Skip to content

Commit

Permalink
Updated to typst 0.7.0 (Closes #15)
Browse files Browse the repository at this point in the history
Added Boxplot (Closes #9)
  • Loading branch information
Gewi413 committed Aug 8, 2023
1 parent fee5c13 commit 956ea13
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 31 deletions.
Binary file modified docs/Docs.pdf
Binary file not shown.
Binary file modified example/Plotting.pdf
Binary file not shown.
69 changes: 61 additions & 8 deletions example/main.typ
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#import "/lib.typ": *
#import "/lib.typ": * // For local testing
//#import "@preview/plotst:0.1.0": *

#let print(desc: "", content) = {
desc
Expand All @@ -8,29 +9,34 @@
#let scatter_plot_test() = {

let gender_data = (
("w", 1), ("w", 3), ("w", 5), ("w", 4), ("m", 2), ("m", 2), ("m", 4), ("m", 6), ("d", 1), ("d", 9), ("d", 5), ("d", 8), ("d", 3), ("d", 1), (0, 11)
("w", 1), ("w", 3), ("w", 5), ("w", 4), ("m", 2), ("m", 2), ("m", 4), ("m", 6), ("d", 1), ("d", 9), ("d", 5), ("d", 8), ("d", 3), ("d", 1)
)
let y_axis = axis(min: 0, max: 11, step: 1, location: "left", helper_lines: true, invert_markings: false, title: "foo")
let gender_axis_x = axis(values: ("", "m", "w", "d"), location: "bottom", helper_lines: true, invert_markings: false, title: "Gender")
let pl = plot(data: gender_data, axes: (gender_axis_x, y_axis))

let y_axis_right = axis(min: 0, max: 11, step: 1, location: "right", helper_lines: false, invert_markings: false, title: "foo", stroke: 7pt + red, show_arrows: false)
let gender_axis_x = axis(values: ("", "m", "w", "d"), location: "bottom", helper_lines: true, invert_markings: false, title: "Gender", show_arrows: false)
let pl = plot(data: gender_data, axes: (gender_axis_x, y_axis, y_axis_right))
scatter_plot(pl, (100%,50%))
let data = (
(0, 0), (2, 2), (3, 0), (4, 4), (5, 7), (6, 6), (7, 9), (8, 5), (9, 9), (10, 1)
)
let x_axis = axis(min: 0, max: 11, step: 2, location: "bottom")
let y_axis = axis(min: 0, max: 11, step: 2, location: "left", helper_lines: false)
let y_axis = axis(min: 0, max: 11, step: 2, location: "left", helper_lines: false, show_values: false)
let pl = plot(data: data, axes: (x_axis, y_axis))
scatter_plot(pl, (100%, 25%))
}

#let graph_plot_test() = {
let data = (
(0, 0), (2, 2), (3, 0), (4, 4), (5, 7), (6, 6), (7, 9), (8, 5), (9, 9), (10, 1)
(0, 4), (2, 2), (3, 0), (4, 4), (5, 7), (6, 6), (7, 9), (8, 5), (9, 9), (10, 1)
)
let data2 = (
(0, 0), (2, 2), (3, 1), (4, 4), (5, 2), (6, 6), (7, 5), (8, 7), (9, 10), (10, 3)
)
let x_axis = axis(min: 0, max: 11, step: 2, location: "bottom")
let y_axis = axis(min: 0, max: 11, step: 2, location: "left", helper_lines: false)
let pl = plot(data: data, axes: (x_axis, y_axis))
graph_plot(pl, (100%, 25%))
graph_plot(pl, (100%, 25%), markings: [])
graph_plot(pl, (100%, 25%), rounding: 30%, caption: "Graph Plot with caption and rounding", markings: [#emoji.rocket])
}

Expand Down Expand Up @@ -125,7 +131,7 @@

#let radar_test() = {
let data = (
(0,6),(1,7),(2,5),(3,4),(4,4),(5,7),(6,6),(7,1),
(0,6),(1,7),(2,5),(3,4),(4,4),(5,7),(6,6),(7,6),
)
let y_axis = axis(min:0, max: 8, location: "left", helper_lines: true)
let x_axis = axis(min:0, max: 8, location: "bottom")
Expand All @@ -134,6 +140,50 @@
radar_chart(pl, (100%,60%))
}

#let function_test() = {
let data = function_plotter(x => {2*(x*x) + 3*x + 3}, 0, 8.3, precision: 100)
let data2 = function_plotter(x => {1*(x*x) + 3*x + 3}, 0, 11.4, precision: 100)
let x_axis = axis(min: 0, max: 20, step: 1, location: "bottom")
let y_axis = axis(min: 0, max: 151, step: 50, location: "left", helper_lines: true)
let p1 = graph_plot(plot(axes: (x_axis, y_axis), data: data), (100%, 50%), markings: [], stroke: red)
let p2 = graph_plot(plot(axes: (x_axis, y_axis), data: data2), (100%, 50%), markings: [], stroke: green)
overlay((p1, p2), (100%, 50%))
}

#let box_plot_test() = {
box_plot(box_width: 70%, pre_calculated: false, plot(axes: (
axis(values: ("", "(a)", "(b)", "(c)"), location: "bottom", show_markings: false),
axis(min: 0, max: 10, step: 1, location: "left", helper_lines: true),
),
data:((1, 3, 4, 4, 5, 6, 7, 8), (1, 3, 4, 4, 5, 7, 8), (1, 3, 4, 5, 7))
), (100%, 40%), caption: none)
}

#let cumsum_test() = {
datetime(year: 2023, month: 1, day: 20) - datetime.today()
let data = range(1,31).map(i=> (datetime(year: 2023, month: 1, day: i),2))
let dates = data.map(it => it.at(0))
let newdata = ()
let sum = 0
for d in data {
sum += d.at(1)
newdata.push((d.at(0).display(), sum))
}
let _ = newdata.remove(0)
let x_axis = axis(values: dates.map(it=> it.display()), location: "bottom")
let y_axis = axis(min: 0, max: sum, step: 10, location: "left")
graph_plot(plot(axes: (x_axis, y_axis), data: newdata), (100%, 50%))
}

#let box_plot_test() = {
box_plot(box_width: 70%, pre_calculated: false, plot(axes: (
axis(values: ("", "(a)", "(b)", "(c)"), location: "bottom", show_markings: false),
axis(min: -5, max: 100, step: 10, location: "left"),
),
data:((10, 20, 30, 50, 60), (5, 20, 25, 30, 45), (6, 19, 23, 37, 98))
), (100%, 40%), caption: none)
}

#let paper_test() = {
set par(justify: true)
pagebreak()
Expand Down Expand Up @@ -218,6 +268,9 @@
bar_chart_test()
overlay_test()
radar_test()
function_test()
box_plot_test()
//cumsum_test()

paper_test()
}
Expand Down
55 changes: 40 additions & 15 deletions plotst/axis.typ
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// DONT COMMIT ME
#import "util/util.typ": *

//------------------
Expand Down Expand Up @@ -107,19 +108,15 @@
let inversion = if axis.invert_markings == -1 {dist * 2 + size.width} else {0pt}

let title_extra = measure(axis.title, style).height

let sizes = (0pt,)
if axis.show_values {
sizes = axis.values.map(it => {
let size = measure([#it], style)
if is_vertical(axis) {
return size.width
} else {
return size.height
}
})
}


let sizes = axis.values.map(it => {
let size = measure([#it], style)
if is_vertical(axis) {
return size.width
} else {
return size.height
}
})
let size = calc.max(..sizes) + inversion + 2 * dist + title_extra
if is_vertical(axis) {
return (size, 0pt)
Expand Down Expand Up @@ -179,7 +176,7 @@
for step in range(axis.marking_offset_left, axis.values.len() - axis.marking_offset_right) {
// Draw helper lines:
if axis.helper_lines {
place(dx: pos.at(0), dy: pos.at(1) - step_length * step, line(angle: 0deg, length: length * invert_markings, stroke: (paint: axis.helper_line_color, dash: axis.helper_line_style)))
//place(dx: pos.at(0), dy: pos.at(1) - step_length * step, line(angle: 0deg, length: length * invert_markings, stroke: (paint: axis.helper_line_color, dash: axis.helper_line_style)))
}

// Draw markings
Expand Down Expand Up @@ -224,7 +221,7 @@
for step in range(axis.marking_offset_left, axis.values.len() - axis.marking_offset_right) {
// Draw helper lines:
if axis.helper_lines {
place(dx: pos.at(0) + step_length * step, dy: pos.at(1), line(angle: 90deg, length: length * -invert_markings, stroke: (paint: axis.helper_line_color, dash: axis.helper_line_style)))
//place(dx: pos.at(0) + step_length * step, dy: pos.at(1), line(angle: 90deg, length: length * -invert_markings, stroke: (paint: axis.helper_line_color, dash: axis.helper_line_style)))
}

// Draw markings
Expand All @@ -246,4 +243,32 @@
}
}

// Draws the helper lines for an axis. Needs to be seperated for rendering order reasons
#let draw_helper_lines(axis, length: 100%, pos: (0pt, 0pt)) = {
let step_length = length / axis.values.len()
let invert_markings = 1
// Changes point of reference if top or right is chosen
if axis.location == "right" {
pos.at(0) = length - pos.at(0)
invert_markings = -1
}
if axis.location == "top" {
pos.at(1) = -length + pos.at(1)
invert_markings = -1
}
if is_vertical(axis) {
// Draw helper lines:
for step in range(axis.marking_offset_left, axis.values.len() - axis.marking_offset_right) {
if axis.helper_lines {
place(dx: pos.at(0), dy: pos.at(1) - step_length * step, line(angle: 0deg, length: length * invert_markings, stroke: (paint: axis.helper_line_color, dash: axis.helper_line_style)))
}
}
} else {
for step in range(axis.marking_offset_left, axis.values.len() - axis.marking_offset_right) {
if axis.helper_lines {
place(dx: pos.at(0) + step_length * step, dy: pos.at(1), line(angle: 90deg, length: length * -invert_markings, stroke: (paint: axis.helper_line_color, dash: axis.helper_line_style)))
}
}
}
}
// ------------------------
85 changes: 77 additions & 8 deletions plotst/plotting.typ
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#import calc: *

// hackyish solution to split axis and content
#let render(plot, plot_code, render_axis) = style(style => {
#let render(plot, plot_code, render_axis, helper_line) = style(style => {
let widths = 0pt
let heights = 0pt
let offset_left = 0pt
Expand Down Expand Up @@ -33,14 +33,19 @@
if y_axis.location == "left" {
offset_x = offset_left
}
place(dx: offset_x, dy: -100% + heights+offset_y, box(width: 100% - widths, height: 100% - heights, fill: none, {
place(dx: offset_x, dy: 100% - offset_bottom, box(width: 100% - widths, height: 100% - heights, fill: none, {
if helper_line {
for axis in plot.axes {
draw_helper_lines(axis)
}
}
if render_axis {
for axis in plot.axes {
draw_axis(axis)
}
} else {
plot_code()
}
plot_code()
}
}))
})

Expand All @@ -61,8 +66,8 @@
// Graph box
set align(left + bottom)
box(width: width, height: height, fill: none, if plot == () { plot_code() } else {
if render_axis { render(plot, plot_code, true) }
render(plot, plot_code, false)
if render_axis { render(plot, plot_code, true, true) }
render(plot, plot_code, false, false)
})
})
}
Expand Down Expand Up @@ -103,9 +108,9 @@
// loop over every plots
for (idx, plot) in plots.enumerate() {
if idx == 0 {
place(dx: 0pt, dy: -100%, box(width: 100%, height: 100%, plot.body.child.body))
place(dx: 0pt, dy: 0pt, box(width: 100%, height: 100%, plot.body.child.body))
} else {
place(dx: 0pt, dy: -100%,box(width: 100%, height: 100%, plot.body.child.body.children.at(1)))
place(dx: 0pt, dy: 0pt, box(width: 100%, height: 100%, plot.body.child.body.children.at(1)))
}
}
})
Expand Down Expand Up @@ -604,3 +609,67 @@

prepare_plot(size, caption, plot_code, plot: plot, render_axis: false)
}


/// This function will display a boxplot based on the provided `plot` object.
#let box_plot(plot, size, caption: "Box plot", stroke: black, fill: none, whisker_stroke: black, box_width: 100%, pre_calculated: true, render_axes: true) = {
// Get the relevant axes:
let x_axis = plot.axes.at(0)
let y_axis = plot.axes.at(1)

let plot_code() = {
// get step sizes
let step_size_x = calc_step_size(100%, x_axis)
let step_size_y = calc_step_size(100%, y_axis)
// only data containing (minimum, first_quartile, median, third_quartile, maximum)
// get correct data
let calc_data = plot.data.map(dataset => transform_data_full(dataset).sorted())
let data = calc_data.map(dataset => (
dataset.at(0),
if calc.rem(dataset.len() * 0.25, 1) != 0 {
dataset.at(int(dataset.len() * 0.25))}
else {
(dataset.at(int(dataset.len() * 0.25) - 1) + dataset.at(int(dataset.len() * 0.25))) / 2},
if calc.rem(dataset.len() * 0.25, 1) != 0 {
dataset.at(int(dataset.len() * 0.5))}
else {
(dataset.at(int(dataset.len() * 0.5) - 1) + dataset.at(int(dataset.len() * 0.5))) / 2},
if calc.rem(dataset.len() * 0.25, 1) != 0 {
dataset.at(int(dataset.len() * 0.75))}
else {
(dataset.at(int(dataset.len() * 0.75) - 1) + dataset.at(int(dataset.len() * 0.75))) / 2},
dataset.at(dataset.len() - 1)
))
data = if pre_calculated {plot.data} else {data}

// let data = transform_data_count(plot.data)
let array_stroke = type(stroke) == "array"
let array_fill = type(fill) == "array"
// draw the boxes
data = if type(data.at(0)) == "array" {
data
} else {
(data,)
}
for (idx, data_set) in data.enumerate() {
let q(i) = (data_set.at(i) - y_axis.min) * step_size_y
let x_data = data_set.at(5, default: idx + 1)
if type(x_data) == "string" {
x_data = x_axis.values.position(c => c == x_data)
}
let box_width = step_size_x * box_width
let whisk_width = box_width * 50%
let x_pos = x_data * step_size_x - box_width / 2
place(dx: x_pos, dy: -q(3),
rect(width: box_width, height: q(3) - q(1),
fill: if array_fill {fill.at(idx)} else {fill},
stroke: if array_stroke {stroke.at(idx)} else {stroke}))
place(dx: x_pos, dy: -q(2), line(length: box_width))
place(dx: x_pos + (box_width - whisk_width) * .5, dy: -q(0), line(length: whisk_width))
place(dx: x_pos + box_width * .5, dy: -q(0), line(end: (0pt, q(0)-q(1)), stroke: whisker_stroke))
place(dx: x_pos + (box_width - whisk_width) * .5, dy: -q(4), line(length: whisk_width))
place(dx: x_pos + box_width * .5, dy: -q(3), line(end: (0pt, q(3)-q(4)), stroke: whisker_stroke))
}
}
prepare_plot(size, caption, plot_code, plot: plot, render_axis: render_axes)
}

0 comments on commit 956ea13

Please sign in to comment.