Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/preview/riesketcher/0.4.0/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.pdf
!manual.pdf
21 changes: 21 additions & 0 deletions packages/preview/riesketcher/0.4.0/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2023-2024 Kainoa Kanter

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
15 changes: 15 additions & 0 deletions packages/preview/riesketcher/0.4.0/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# riesketcher

A package to draw Riemann sums (and their plots) of a function with CeTZ.

Usage example and docs: [manual.pdf](https://github.com/ThatOneCalculator/riesketcher/blob/main/manual.pdf)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I first assumed that the functions would immediately draw the plot. Maybe you can add somewhere that the return value needs to be passed to cetz.canvas.


```typst
#import "@preview/riesketcher:0.4.0": riesketcher
```

![Demo](https://github.com/ThatOneCalculator/riesketcher/assets/44733677/4f87b750-e4be-4698-b650-74f4fe56789d)

![Demo for custom partitions](https://github.com/VincentTam/riesketcher/assets/5748535/3b830cb8-c017-4ed4-9410-7f3bad79edab)

![Demo for trapezoidal rule](https://github.com/user-attachments/assets/f72b6a96-2c8e-4b95-a4d1-cad89fbb75e0)
2 changes: 2 additions & 0 deletions packages/preview/riesketcher/0.4.0/lib.typ
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#import "riesketcher.typ": riesketcher
#import "trapezoidal.typ": trapezoidal
Binary file added packages/preview/riesketcher/0.4.0/manual.pdf
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file will be very hard to find on typst universe, could you either remove it, or link it in the readme like this [manual.pdf](manual.pdf)

Binary file not shown.
125 changes: 125 additions & 0 deletions packages/preview/riesketcher/0.4.0/manual.typ
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#import "@preview/tidy:0.1.0"

Check warning on line 1 in packages/preview/riesketcher/0.4.0/manual.typ

View check run for this annotation

Typst package check / @preview/riesketcher:0.4.0

packages/preview/riesketcher/0.4.0/manual.typ#L1

This import seems to use an older version of the package.
#import "@preview/cetz:0.4.1": canvas

Check warning on line 2 in packages/preview/riesketcher/0.4.0/manual.typ

View check run for this annotation

Typst package check / @preview/riesketcher:0.4.0

packages/preview/riesketcher/0.4.0/manual.typ#L2

This import seems to use an older version of the package.
#import "lib.typ": riesketcher, trapezoidal

Check warning on line 3 in packages/preview/riesketcher/0.4.0/manual.typ

View check run for this annotation

Typst package check / @preview/riesketcher:0.4.0

packages/preview/riesketcher/0.4.0/manual.typ#L3

This import should use the package specification, not a relative path.
// #import "@preview/riesketcher:0.4.0": riesketcher, trapezoidal

#set text(size: 10.5pt)

= Riesketcher
A package to draw Riemann sums (left, right, midpoint, and trapezoidal) and their plots for functions using CeTZ; supports tagged and untagged partitions.
```typst
#import "@preview/riesketcher:0.4.0": riesketcher, trapezoidal
```

#show raw.where(lang: "example"): it => block({
table(columns: (50%, 50%), stroke: none, align: (center + horizon, left),
align(left, raw(lang: "typc", it.text)),
eval("canvas({" + it.text + "})", scope: (canvas: canvas, riesketcher: riesketcher, trapezoidal: trapezoidal))
)
})

== Examples
=== Left-Hand Riemann sum

```example
riesketcher(
x => calc.pow(x, 3) + 4,
method: "left",
start: -3.1,
end: 3.5,
n: 10,
plot-x-tick-step: 1,
)
```

=== Midpoint Riemann sum

```example
riesketcher(
x => -calc.pow(x, 2) + 9,
method: "mid",
domain: (-4, 4),
start: -3,
end: 3,
n: 6,
plot-x-tick-step: 1,
)
```

=== Right-method Riemann sum

```example
riesketcher(
x => 16 - x * x,
method: "right",
end: 6,
n: 6,
domain: (-1, auto),
plot-x-tick-step: 1,
)
```

=== Custom untagged partition (midpoint method)

```example
riesketcher(
x => 0.17 * calc.pow(x, 3)
+ 1.5 * calc.sin(calc.cos(x)),
method: "mid",
partition: (-3, -1.5, -0.75, -0.2, 0.8, 1.5,
2.3, 3.4),
plot-x-tick-step: 2,
)
```

=== Tagged partition

```example
riesketcher(
x => 0.5 * calc.pow(x, 3)
- 0.9 * calc.cos(x),
partition: (-3.2, -2.1, -1.1, 0.4, 0.9, 1.7,
2.4, 3.5),
tags: (-2.5, -1.9, -0.35, 0.63, 1.38, 2.06, 3.14),
plot-x-tick-step: 2,
)
```

#pagebreak()

=== Trapezoidal Rule (uniform grid)

```example
trapezoidal(
x => calc.pow(x, 3) + 4,
start: -3,
end: 3.5,
n: 7,
plot-x-tick-step: 1,
positive-color: rgb("#210aa4")
)
```

=== Trapezoidal Rule (non-uniform grid)

```example
trapezoidal(
x => -calc.pow(x, 3) - 4,
partition: (-3, -0.4, 2, 3.1, 3.5),
plot-x-tick-step: 1,
positive-color: rgb("#210aa4")
)
```

#pagebreak()
#set align(left)

== Method parameters

#let riesketcher-tidy = tidy.parse-module(read("riesketcher.typ"), name: "riesketcher")
#tidy.show-module(riesketcher-tidy)

#pagebreak()

#let trapezoidal-tidy = tidy.parse-module(read("trapezoidal.typ"), name: "trapezoidal")
#tidy.show-module(trapezoidal-tidy)
160 changes: 160 additions & 0 deletions packages/preview/riesketcher/0.4.0/riesketcher.typ
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
#import "@preview/cetz-plot:0.1.2"
#import "util.typ": _validate-partition, _validate-tagged-partition

/// Draw a Riemann sum of a function, and optionally plot the function.
///
/// - fn (function): The function to draw a Riemann sum of.
/// - domain (array): Tuple of the domain of `fn`. If a tuple value is `auto`, that
/// value is set to `start`/`end`.
/// - start (number): The starting point for the bars. Used only if `partition`
/// is not a valid array; otherwise, the first value of `partition` is used.
/// - end (number): The ending point for the bars. Used only if `partition` is
/// not a valid array; otherwise, the last value of `partition` is used.
/// - n (number): Number of bars. Used only if `partition` is not a valid array;
/// otherwise, the number of bars is determined by the length of `partition`.
/// - method (string): Determines where the sample points for bar heights are
/// taken (`left`, `mid`/`midpoint`, or `right`). Used only if `tags` is not a
/// valid array; otherwise, bar heights are taken from `tags`.
/// - partition (array, none): (optional) Array of partition points. If valid, it
/// overrides `start`, `end`, and `n`; otherwise, equal partitions are
/// generated from `start`, `end`, and `n`.
/// - tags (array, none): (optional) Array of sample points for bar heights. If
/// valid, it overrides `method`; otherwise, sample points are determined by
/// `method`.
/// - transparency (number): Transparency fill of bars.
/// - dot-radius (number): Radius of dots.
/// - plot (boolean): Whether to add plot of the function.
/// - plot-grid (boolean): Show grid on plot.
/// - plot-x-tick-step (number): X tick step of plot.
/// - plot-y-tick-step (number): Y tick step of plot.
/// - positive-color (color): Color of positive bars.
/// - negative-color (color): Color of negative bars.
/// - plot-line-color (color): Color of plotted line.
/// - size (tuple): The width and height of the plot area, given as a tuple
/// `(width, height)`. Controls the overall size of the rendered Riemann sum
/// and function plot.
#let riesketcher(
fn,
start: 0,
end: 10,
domain: (auto, auto),
n: 10,
partition: none,
tags: none,
method: "left",
transparency: 40%,
dot-radius: 0.15,
plot: true,
plot-grid: false,
plot-x-tick-step: auto,
plot-y-tick-step: auto,
positive-color: color.green,
negative-color: color.red,
plot-line-color: color.blue,
size: (5, 5),
) = {
let delta-x = 0 // store fallback bar width if partition is invalid

// check if partition is valid
let is-valid-partition = _validate-partition(partition)
if is-valid-partition {
start = partition.at(0)
end = partition.at(-1)
n = partition.len() - 1
} else {
delta-x = (end - start) / n
partition = range(0, n + 1).map(k => start + delta-x * k)
}

// Adjust the function domain if set to auto
if domain.at(0) == auto { domain.at(0) = start }
if domain.at(1) == auto { domain.at(1) = end }

// calculate bar widths
let bar-widths = if is-valid-partition {
range(0, partition.len() - 1).map(k => partition.at(k + 1) - partition.at(k))
} else {
range(0, n).map(x => delta-x)
}

// check if tags are valid
let is-valid-tags = _validate-tagged-partition(partition, tags)

// calculate bar heights
let bar-y = none
if is-valid-tags {
bar-y = tags.zip(tags.map(fn))
} else {
let horizontal-hand-offset = 0%
if method == "right" {
horizontal-hand-offset = 100%
}
else if method == "mid" or method == "midpoint" {
horizontal-hand-offset = 50%
}
bar-y = range(0, n).map(k => {
let x = partition.at(k) + bar-widths.at(k) * horizontal-hand-offset / 100%
(x, fn(x))
})
}

let col-trans(color, opacity) = {
let space = color.space()
space(..color.components(alpha: false), opacity)
}

let positive-bar-style = (
fill: col-trans(positive-color.lighten(70%).darken(8%), transparency),
stroke: col-trans(positive-color.darken(30%), 90%) + 1.1pt
)
let negative-bar-style = (
: ..positive-bar-style,
fill: col-trans(negative-color.lighten(70%).darken(8%), transparency),
stroke: col-trans(negative-color.darken(30%), 90%) + 1.1pt
)
let positive-dot-style = (
stroke: black,
fill: positive-color
)
let negative-dot-style = (
: ..positive-dot-style,
fill: negative-color,
)

cetz-plot.plot.plot(
size: size,
x-grid: plot-grid,
y-grid: plot-grid,
x-label: $x$,
y-label: $y$,
axis-style: if plot { "school-book" } else { none },
x-tick-step: plot-x-tick-step,
y-tick-step: plot-y-tick-step,
{
for k in range(0, n) {
let x = partition.at(k)
let y = bar-y.at(k).at(1)
cetz-plot.plot.add-bar(((x, y),),
bar-width: bar-widths.at(k),
bar-position: "start",
style: if y >= 0 { positive-bar-style } else { negative-bar-style })
}

if plot {
cetz-plot.plot.add(
domain: domain,
x => fn(x),
style: (stroke: plot-line-color + 1.5pt))
}

for k in range(0, n) {
let (x, y) = bar-y.at(k)
cetz-plot.plot.add(((x, y),),
mark: "o",
style: (stroke: none),
mark-size: dot-radius,
mark-style: if y >= 0 { positive-dot-style } else { negative-dot-style })
}
}
)
}
Loading