From e6be2633bfc1c55c52e1574be4818ceb2a30f890 Mon Sep 17 00:00:00 2001 From: Johannes Wolf Date: Thu, 31 Oct 2024 21:50:21 +0100 Subject: [PATCH 1/5] plot: Do not draw marks outside axis intervals --- src/plot.typ | 2 +- src/plot/mark.typ | 15 +++++++++------ src/plot/util.typ | 15 +++++++++++++++ tests/plot/marks/ref/1.png | Bin 28490 -> 41532 bytes tests/plot/marks/test.typ | 8 ++++++++ 5 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/plot.typ b/src/plot.typ index 1436f70..b72f180 100644 --- a/src/plot.typ +++ b/src/plot.typ @@ -459,7 +459,7 @@ } draw.set-style(..d.style, ..d.mark-style) - mark.draw-mark(d.data, x, y, d.mark, d.mark-size, size) + mark.draw-mark(d.data, (x, y), d.mark, d.mark-size, size) }) } } diff --git a/src/plot/mark.typ b/src/plot/mark.typ index 9450d21..97e0986 100644 --- a/src/plot/mark.typ +++ b/src/plot/mark.typ @@ -1,5 +1,6 @@ #import "/src/cetz.typ": draw #import "/src/axes.typ" +#import "/src/plot/util.typ" // Draw mark at point with size #let draw-mark-shape(pt, size, mark, style) = { @@ -34,12 +35,14 @@ } } -#let draw-mark(pts, x, y, mark, mark-size, plot-size) = { - let pts = pts.map(pt => { - axes.transform-vec(plot-size, x, y, none, pt) - }).filter(pt => pt != none) - +/// Draw mark shapes for each point in pts +/// - pts (list): Points +/// - all-axes (list): List of axes, order must match pts value order! +#let draw-mark(pts, all-axes, mark, mark-size, plot-size) = { for pt in pts { - draw-mark-shape(pt, mark-size, mark, (:)) + if util.point-in-range(pt, all-axes) { + pt = axes.transform-vec(plot-size, all-axes.at(0), all-axes.at(1), none, pt) + draw-mark-shape(pt, mark-size, mark, (:)) + } } } diff --git a/src/plot/util.typ b/src/plot/util.typ index 5c59c80..9ca5e25 100644 --- a/src/plot/util.typ +++ b/src/plot/util.typ @@ -370,3 +370,18 @@ return axis-dict } + +/// Tests if point pt is contained in the +/// axis interval of each axis in axes +/// - pt (list): Data array +/// - axes (list): List of axes +#let point-in-range(pt, axes) = { + for i in range(0, axes.len()) { + let a = axes.at(i) + let v = pt.at(i) + if v < a.min or v > a.max { + return false + } + } + return true +} diff --git a/tests/plot/marks/ref/1.png b/tests/plot/marks/ref/1.png index ad6e3341343607d76f5fc6b360a7e2188856abd2..45732edf4f08652c817f16704e4b5d32b5b714ee 100644 GIT binary patch literal 41532 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 ncas0tJ1O>2>9Al&mSw literal 28490 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 diff --git a/tests/plot/marks/test.typ b/tests/plot/marks/test.typ index aa584f0..b6677d4 100644 --- a/tests/plot/marks/test.typ +++ b/tests/plot/marks/test.typ @@ -24,3 +24,11 @@ } ) }) + +#test-case({ + import cetz-plot: plot + + plot.plot(size: (5,5), x-min: 1, y-min: 1, x-max: 9, y-max: 9, { + plot.add(domain: (0, 10), samples: 11, x => x, mark: "square") + }) +}) From 32abfcab07c204abc3a435b92a103e972fde0ccd Mon Sep 17 00:00:00 2001 From: James R Swift Date: Thu, 31 Oct 2024 20:53:13 +0000 Subject: [PATCH 2/5] checkpoint --- src/plot.typ | 1 + src/plot/comb.typ | 123 +++++++++++++++++++++++++++++++++ tests/plot/annotation/test.typ | 2 +- tests/plot/comb/ref.typ | 122 ++++++++++++++++++++++++++++++++ tests/plot/comb/testdata.csv | 57 +++++++++++++++ 5 files changed, 304 insertions(+), 1 deletion(-) create mode 100644 src/plot/comb.typ create mode 100644 tests/plot/comb/ref.typ create mode 100644 tests/plot/comb/testdata.csv diff --git a/src/plot.typ b/src/plot.typ index 1aad373..01f20d8 100644 --- a/src/plot.typ +++ b/src/plot.typ @@ -13,6 +13,7 @@ #import "/src/plot/errorbar.typ": add-errorbar #import "/src/plot/mark.typ" #import "/src/plot/violin.typ": add-violin +#import "/src/plot/comb.typ": add-comb #import "/src/plot/formats.typ" #import plot-legend: add-legend diff --git a/src/plot/comb.typ b/src/plot/comb.typ new file mode 100644 index 0000000..0b64977 --- /dev/null +++ b/src/plot/comb.typ @@ -0,0 +1,123 @@ +#import "/src/cetz.typ": draw, vector +#import "util.typ" +#import "line.typ" +#import "annotation.typ" + +#let _prepare(self, ctx) = { + let (x-axis, y-axis) = (ctx.x, ctx.y) + self.stroke-paths = self.line-data + .map(((x, y, s, ..)) => { + ( + lines: util.compute-stroke-paths( + ((x, 0), (x,y)), + x-axis, + y-axis + ), + style: s, + ) + + }) + self +} + +#let _fill(self, ctx) = {} + +#let _stroke(self, ctx) = { + for (lines, style) in self.stroke-paths { + for p in lines { + draw.line(..p, fill: none, ..self.style, ..style) + } + // if (line) == none {continue} + // let ((ax, ay),(bx, by)) = line + // if (ay == by) {continue} + // if (ax < ctx.x.min){continue} + // if (bx < ctx.x.min){continue} + // if (ax < ctx.x.min){continue} + // if (ax < ctx.x.min){continue} + // draw.line((ax, ay),(bx, by), fill: none, ..self.style, ..style) + } +} + +#let _legend-preview(self) = { + draw.line((0,.5), (1,.5), ..self.style) +} + +#let add-comb( + domain: auto, + mz-key: 0, + intensity-key: 1, + label-key: none, + style-key: none, + style: (:), + mark: none, + mark-size: 0.05, + mark-style: (:), + axes: ("x", "y"), + label: none, + label-padding: none, + annotations: auto, + data +) = { + + let line-data = data.map(d=>( + d.at(mz-key), + d.at(intensity-key), + if style-key != none {d.at(style-key, default: none)} else {style} + )) + + let x-domain = ( + calc.min(..line-data.map(t => t.at(0))), + calc.max(..line-data.map(t => t.at(0))) + ) + + let y-domain = if line-data != none {( + calc.min(..line-data.map(t => t.at(1))), + calc.max(..line-data.map(t => t.at(1))) + )} + + let annotations = if annotations == auto { + if (label-key == none) { + () + } else { + data.filter(it=>it.at(label-key, default: none) != none) + } + } else if annotations == none { + () + } else { + annotations + } + + ((: + type: "comb", + label: label, + data: data, /* Raw data */ + line-data: line-data, /* Transformed data */ + axes: axes, + x-domain: x-domain, + y-domain: y-domain, + style: style, + mark: mark, + mark-size: mark-size, + mark-style: mark-style, + plot-prepare: _prepare, + plot-fill: _fill, + plot-stroke: _stroke, + plot-legend-preview: _legend-preview, + mz-key: mz-key, + intensity-key: intensity-key, + label-key: label-key, + width: 0.5, + ),) + + for (x, y, a) in annotations { + annotation.annotate( + draw.content((x,y), [#a], anchor: "south"), + axes: ("x", "y"), + resize: true, + padding: none, + background: false + ) + } + +} + diff --git a/tests/plot/annotation/test.typ b/tests/plot/annotation/test.typ index efb04a7..aee5200 100644 --- a/tests/plot/annotation/test.typ +++ b/tests/plot/annotation/test.typ @@ -49,7 +49,7 @@ import draw: * set-style(rect: (stroke: none)) - plot.plot(size: (6, 4), x-tick-step: 1, { + plot.plot(size: (6, 4), x-tick-step: 0.5, { plot.add(domain: (100, 101), calc.sin) plot.annotate(padding: .1, { content( (101.5, 0), [A]) diff --git a/tests/plot/comb/ref.typ b/tests/plot/comb/ref.typ new file mode 100644 index 0000000..944d1ef --- /dev/null +++ b/tests/plot/comb/ref.typ @@ -0,0 +1,122 @@ +#set page(width: auto, height: auto) +#import "/src/cetz.typ": * +#import "/src/lib.typ": * +#import "/tests/helper.typ": * + +#let data = csv("testdata.csv").map( + ((x, y,..))=>{ + ( + float(x), + float(y), + if x in ("41",) { + (stroke: (paint: red)) + } else if x in ("93",){ + (stroke: (paint: blue)) + }, + ) + } +) + += General case +- Input data is an array of the form (mz, int, ..) +- keys are not explicitly set. +- X, Y ranges not set + +#test-case({ + plot.plot( + size: (10,6), + // y-max: 100, + // x-min: 0, x-max: 175, + { + plot.add-comb( + label: "Linalool, 70eV", + // style-key: 2, + // style: (stroke: (paint: black)), + data + ) + } + ) +}) + + += With domain set +- General case, but X Y domains are defined explicitly and without mistake + +#table( + columns: 3, + ..(for i in range(0, 9) { + let (x,y) = (calc.div-euclid(i, 3),calc.rem-euclid(i, 3)) + (table.cell( x: x, y: 3-y, test-case({ + plot.plot( + x-tick-step: none, y-tick-step: none, + size: (3,3), + x-min: x * 50, x-max: (x+1) * 50, + y-min: y * 33, y-max: (y+1) * 33, + { + plot.add-comb( + data + ) + } + ) + })),) + }) +) + += With uniform style +Applying the same style to the whole series + +#test-case({ + plot.plot( + size: (10,6), + // y-max: 100, + // x-min: 0, x-max: 175, + { + plot.add-comb( + label: "Linalool, 70eV", + // style-key: 2, + style: (stroke: (paint: black, dash: "dashed")), + data + ) + } + ) +}) + += With uniform style and individual style +Applying the same style across a whole series, except for some for which it is defined explicitly\ as a field set by `style-key` + +#test-case({ + plot.plot( + size: (10,6), + // y-max: 100, + // x-min: 0, x-max: 175, + { + plot.add-comb( + label: "Linalool, 70eV", + style-key: 2, + style: (stroke: (paint: black, dash: "dashed")), + data + ) + } + ) +}) + += With Marks +Uniform marks across the series + +#test-case({ + plot.plot( + size: (10,6), + // y-max: 100, + x-min: 35, x-max: 45, + { + // plot.add-comb( + // label: "Linalool, 70eV", + // mark: "x", + // mark-size: 0.1, + + // data + // ) + plot.add(domain: (0, 100), x=>x, mark: "x") + } + ) +}) \ No newline at end of file diff --git a/tests/plot/comb/testdata.csv b/tests/plot/comb/testdata.csv new file mode 100644 index 0000000..8ca2f60 --- /dev/null +++ b/tests/plot/comb/testdata.csv @@ -0,0 +1,57 @@ +15,2,20 +18,1.15,12 +26,1.04,10 +27,21.16,212 +28,3.01,30 +29,10.19,102 +31,2.24,22 +39,22.09,221 +40,4.97,50 +41,63.43,634 +42,5.86,59 +43,58.84,588 +44,1.63,16 +45,1.58,16 +51,3.62,36 +52,1.45,15 +53,13.41,134 +54,2.5,25 +55,46.66,467 +56,9.02,90 +57,3.48,35 +58,2.51,25 +59,3.42,34 +65,3.06,31 +66,1.17,12 +67,15.88,159 +68,12.86,129 +69,40.64,406 +70,5,50 +71,99.99,999 +72,7.53,75 +77,4.19,42 +79,8.08,81 +80,26.17,262 +81,10.85,109 +82,5.73,57 +83,16.15,162 +84,4.3,43 +85,1.36,14 +86,1.62,16 +91,4.76,48 +92,11.35,114 +93,61.4,614 +94,8.79,88 +95,2.72,27 +96,7.47,75 +97,1.96,20 +105,3.07,31 +107,5.78,58 +108,1.34,13 +109,5.02,50 +111,2.96,30 +121,19.93,199 +122,1.59,16 +136,8.77,88 +137,1.04,10 +139,2.18,22 From 5539b791b4357b1c8eb3dd9d3043b71c16b6e157 Mon Sep 17 00:00:00 2001 From: James R Swift Date: Mon, 28 Oct 2024 20:34:19 +0000 Subject: [PATCH 3/5] fix domain for annotation --- src/plot.typ | 4 ++-- tests/plot/annotation/test.typ | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/plot.typ b/src/plot.typ index b72f180..0de9168 100644 --- a/src/plot.typ +++ b/src/plot.typ @@ -275,9 +275,9 @@ let axis = axis-dict.at(name) let domain = if i == 0 { - d.at("x-domain", default: (0, 0)) + d.at("x-domain", default: (none, none)) } else { - d.at("y-domain", default: (0, 0)) + d.at("y-domain", default: (none, none)) } if domain != (none, none) { axis.min = util.min(axis.min, ..domain) diff --git a/tests/plot/annotation/test.typ b/tests/plot/annotation/test.typ index cd74c2e..efb04a7 100644 --- a/tests/plot/annotation/test.typ +++ b/tests/plot/annotation/test.typ @@ -44,3 +44,15 @@ }) }) }) + +#test-case({ + import draw: * + set-style(rect: (stroke: none)) + + plot.plot(size: (6, 4), x-tick-step: 1, { + plot.add(domain: (100, 101), calc.sin) + plot.annotate(padding: .1, { + content( (101.5, 0), [A]) + }) + }) +}) \ No newline at end of file From 147a77f4b1cbd3bac983a3c9f268327f61f86157 Mon Sep 17 00:00:00 2001 From: James R Swift Date: Thu, 31 Oct 2024 20:53:13 +0000 Subject: [PATCH 4/5] checkpoint --- src/plot.typ | 1 + src/plot/comb.typ | 123 +++++++++++++++++++++++++++++++++ tests/plot/annotation/test.typ | 2 +- tests/plot/comb/ref.typ | 122 ++++++++++++++++++++++++++++++++ tests/plot/comb/testdata.csv | 57 +++++++++++++++ 5 files changed, 304 insertions(+), 1 deletion(-) create mode 100644 src/plot/comb.typ create mode 100644 tests/plot/comb/ref.typ create mode 100644 tests/plot/comb/testdata.csv diff --git a/src/plot.typ b/src/plot.typ index 0de9168..9f1550c 100644 --- a/src/plot.typ +++ b/src/plot.typ @@ -13,6 +13,7 @@ #import "/src/plot/errorbar.typ": add-errorbar #import "/src/plot/mark.typ" #import "/src/plot/violin.typ": add-violin +#import "/src/plot/comb.typ": add-comb #import "/src/plot/formats.typ" #import plot-legend: add-legend diff --git a/src/plot/comb.typ b/src/plot/comb.typ new file mode 100644 index 0000000..0b64977 --- /dev/null +++ b/src/plot/comb.typ @@ -0,0 +1,123 @@ +#import "/src/cetz.typ": draw, vector +#import "util.typ" +#import "line.typ" +#import "annotation.typ" + +#let _prepare(self, ctx) = { + let (x-axis, y-axis) = (ctx.x, ctx.y) + self.stroke-paths = self.line-data + .map(((x, y, s, ..)) => { + ( + lines: util.compute-stroke-paths( + ((x, 0), (x,y)), + x-axis, + y-axis + ), + style: s, + ) + + }) + self +} + +#let _fill(self, ctx) = {} + +#let _stroke(self, ctx) = { + for (lines, style) in self.stroke-paths { + for p in lines { + draw.line(..p, fill: none, ..self.style, ..style) + } + // if (line) == none {continue} + // let ((ax, ay),(bx, by)) = line + // if (ay == by) {continue} + // if (ax < ctx.x.min){continue} + // if (bx < ctx.x.min){continue} + // if (ax < ctx.x.min){continue} + // if (ax < ctx.x.min){continue} + // draw.line((ax, ay),(bx, by), fill: none, ..self.style, ..style) + } +} + +#let _legend-preview(self) = { + draw.line((0,.5), (1,.5), ..self.style) +} + +#let add-comb( + domain: auto, + mz-key: 0, + intensity-key: 1, + label-key: none, + style-key: none, + style: (:), + mark: none, + mark-size: 0.05, + mark-style: (:), + axes: ("x", "y"), + label: none, + label-padding: none, + annotations: auto, + data +) = { + + let line-data = data.map(d=>( + d.at(mz-key), + d.at(intensity-key), + if style-key != none {d.at(style-key, default: none)} else {style} + )) + + let x-domain = ( + calc.min(..line-data.map(t => t.at(0))), + calc.max(..line-data.map(t => t.at(0))) + ) + + let y-domain = if line-data != none {( + calc.min(..line-data.map(t => t.at(1))), + calc.max(..line-data.map(t => t.at(1))) + )} + + let annotations = if annotations == auto { + if (label-key == none) { + () + } else { + data.filter(it=>it.at(label-key, default: none) != none) + } + } else if annotations == none { + () + } else { + annotations + } + + ((: + type: "comb", + label: label, + data: data, /* Raw data */ + line-data: line-data, /* Transformed data */ + axes: axes, + x-domain: x-domain, + y-domain: y-domain, + style: style, + mark: mark, + mark-size: mark-size, + mark-style: mark-style, + plot-prepare: _prepare, + plot-fill: _fill, + plot-stroke: _stroke, + plot-legend-preview: _legend-preview, + mz-key: mz-key, + intensity-key: intensity-key, + label-key: label-key, + width: 0.5, + ),) + + for (x, y, a) in annotations { + annotation.annotate( + draw.content((x,y), [#a], anchor: "south"), + axes: ("x", "y"), + resize: true, + padding: none, + background: false + ) + } + +} + diff --git a/tests/plot/annotation/test.typ b/tests/plot/annotation/test.typ index efb04a7..aee5200 100644 --- a/tests/plot/annotation/test.typ +++ b/tests/plot/annotation/test.typ @@ -49,7 +49,7 @@ import draw: * set-style(rect: (stroke: none)) - plot.plot(size: (6, 4), x-tick-step: 1, { + plot.plot(size: (6, 4), x-tick-step: 0.5, { plot.add(domain: (100, 101), calc.sin) plot.annotate(padding: .1, { content( (101.5, 0), [A]) diff --git a/tests/plot/comb/ref.typ b/tests/plot/comb/ref.typ new file mode 100644 index 0000000..944d1ef --- /dev/null +++ b/tests/plot/comb/ref.typ @@ -0,0 +1,122 @@ +#set page(width: auto, height: auto) +#import "/src/cetz.typ": * +#import "/src/lib.typ": * +#import "/tests/helper.typ": * + +#let data = csv("testdata.csv").map( + ((x, y,..))=>{ + ( + float(x), + float(y), + if x in ("41",) { + (stroke: (paint: red)) + } else if x in ("93",){ + (stroke: (paint: blue)) + }, + ) + } +) + += General case +- Input data is an array of the form (mz, int, ..) +- keys are not explicitly set. +- X, Y ranges not set + +#test-case({ + plot.plot( + size: (10,6), + // y-max: 100, + // x-min: 0, x-max: 175, + { + plot.add-comb( + label: "Linalool, 70eV", + // style-key: 2, + // style: (stroke: (paint: black)), + data + ) + } + ) +}) + + += With domain set +- General case, but X Y domains are defined explicitly and without mistake + +#table( + columns: 3, + ..(for i in range(0, 9) { + let (x,y) = (calc.div-euclid(i, 3),calc.rem-euclid(i, 3)) + (table.cell( x: x, y: 3-y, test-case({ + plot.plot( + x-tick-step: none, y-tick-step: none, + size: (3,3), + x-min: x * 50, x-max: (x+1) * 50, + y-min: y * 33, y-max: (y+1) * 33, + { + plot.add-comb( + data + ) + } + ) + })),) + }) +) + += With uniform style +Applying the same style to the whole series + +#test-case({ + plot.plot( + size: (10,6), + // y-max: 100, + // x-min: 0, x-max: 175, + { + plot.add-comb( + label: "Linalool, 70eV", + // style-key: 2, + style: (stroke: (paint: black, dash: "dashed")), + data + ) + } + ) +}) + += With uniform style and individual style +Applying the same style across a whole series, except for some for which it is defined explicitly\ as a field set by `style-key` + +#test-case({ + plot.plot( + size: (10,6), + // y-max: 100, + // x-min: 0, x-max: 175, + { + plot.add-comb( + label: "Linalool, 70eV", + style-key: 2, + style: (stroke: (paint: black, dash: "dashed")), + data + ) + } + ) +}) + += With Marks +Uniform marks across the series + +#test-case({ + plot.plot( + size: (10,6), + // y-max: 100, + x-min: 35, x-max: 45, + { + // plot.add-comb( + // label: "Linalool, 70eV", + // mark: "x", + // mark-size: 0.1, + + // data + // ) + plot.add(domain: (0, 100), x=>x, mark: "x") + } + ) +}) \ No newline at end of file diff --git a/tests/plot/comb/testdata.csv b/tests/plot/comb/testdata.csv new file mode 100644 index 0000000..8ca2f60 --- /dev/null +++ b/tests/plot/comb/testdata.csv @@ -0,0 +1,57 @@ +15,2,20 +18,1.15,12 +26,1.04,10 +27,21.16,212 +28,3.01,30 +29,10.19,102 +31,2.24,22 +39,22.09,221 +40,4.97,50 +41,63.43,634 +42,5.86,59 +43,58.84,588 +44,1.63,16 +45,1.58,16 +51,3.62,36 +52,1.45,15 +53,13.41,134 +54,2.5,25 +55,46.66,467 +56,9.02,90 +57,3.48,35 +58,2.51,25 +59,3.42,34 +65,3.06,31 +66,1.17,12 +67,15.88,159 +68,12.86,129 +69,40.64,406 +70,5,50 +71,99.99,999 +72,7.53,75 +77,4.19,42 +79,8.08,81 +80,26.17,262 +81,10.85,109 +82,5.73,57 +83,16.15,162 +84,4.3,43 +85,1.36,14 +86,1.62,16 +91,4.76,48 +92,11.35,114 +93,61.4,614 +94,8.79,88 +95,2.72,27 +96,7.47,75 +97,1.96,20 +105,3.07,31 +107,5.78,58 +108,1.34,13 +109,5.02,50 +111,2.96,30 +121,19.93,199 +122,1.59,16 +136,8.77,88 +137,1.04,10 +139,2.18,22 From c1590e94c46c01c307c1d86bef80db52752d7567 Mon Sep 17 00:00:00 2001 From: James R Swift Date: Thu, 31 Oct 2024 22:23:10 +0000 Subject: [PATCH 5/5] finish off --- src/plot/comb.typ | 10 +------ tests/plot/comb/ref.typ | 58 ++++++++++++++++++++++++++++++++++------- 2 files changed, 50 insertions(+), 18 deletions(-) diff --git a/src/plot/comb.typ b/src/plot/comb.typ index 0b64977..3054208 100644 --- a/src/plot/comb.typ +++ b/src/plot/comb.typ @@ -27,14 +27,6 @@ for p in lines { draw.line(..p, fill: none, ..self.style, ..style) } - // if (line) == none {continue} - // let ((ax, ay),(bx, by)) = line - // if (ay == by) {continue} - // if (ax < ctx.x.min){continue} - // if (bx < ctx.x.min){continue} - // if (ax < ctx.x.min){continue} - // if (ax < ctx.x.min){continue} - // draw.line((ax, ay),(bx, by), fill: none, ..self.style, ..style) } } @@ -102,7 +94,7 @@ plot-prepare: _prepare, plot-fill: _fill, plot-stroke: _stroke, - plot-legend-preview: _legend-preview, + // plot-legend-preview: _legend-preview, mz-key: mz-key, intensity-key: intensity-key, label-key: label-key, diff --git a/tests/plot/comb/ref.typ b/tests/plot/comb/ref.typ index 944d1ef..91f7951 100644 --- a/tests/plot/comb/ref.typ +++ b/tests/plot/comb/ref.typ @@ -48,6 +48,7 @@ let (x,y) = (calc.div-euclid(i, 3),calc.rem-euclid(i, 3)) (table.cell( x: x, y: 3-y, test-case({ plot.plot( + x-label: none, y-label: none, x-tick-step: none, y-tick-step: none, size: (3,3), x-min: x * 50, x-max: (x+1) * 50, @@ -109,14 +110,53 @@ Uniform marks across the series // y-max: 100, x-min: 35, x-max: 45, { - // plot.add-comb( - // label: "Linalool, 70eV", - // mark: "x", - // mark-size: 0.1, - - // data - // ) - plot.add(domain: (0, 100), x=>x, mark: "x") + plot.add-comb( + label: "Linalool, 70eV", + mark: "-", + mark-size: 0.2, + data + ) + // plot.add(domain: (0, 100), x=>x, mark: "x") } ) -}) \ No newline at end of file +}) + += Axis swap +// Test pending upstream +#test-case({ + plot.plot( + size: (10,6), + y-max: 0, y-min: 180, + // x-min: 35, x-max: 45, + { + plot.add-comb( + axes: ("y", "x"), + label: "Linalool, 70eV", + // mark: "-", + mark-size: 0.2, + data + ) + // plot.add(domain: (0, 100), x=>x, mark: "x") + } + ) +}) + += Logarithym +// Test pending upstream +#test-case({ + plot.plot( + size: (10,6), + // x-min: 35, x-max: 45, + y-max: 100, + y-mode: "log", y-tick-step: 1, y-base: 10, y-format: "sci", y-minor-tick-step: 1, + { + plot.add-comb( + label: "Linalool, 70eV", + // mark: "-", + mark-size: 0.2, + data + ) + // plot.add(domain: (0, 100), x=>x, mark: "x") + } + ) +})