From 13c18b1597551ff8023482074c35ccddb18335c8 Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Sun, 9 Feb 2025 21:53:17 +0000 Subject: [PATCH] Add boxxyerror interface --- gnuplot/Cargo.toml | 5 ++ gnuplot/examples/box_xy_error.rs | 43 ++++++++++++++++ gnuplot/src/axes2d.rs | 85 ++++++++++++++++++++++++++++++++ gnuplot/src/axes_common.rs | 46 ++++++++++++++++- 4 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 gnuplot/examples/box_xy_error.rs diff --git a/gnuplot/Cargo.toml b/gnuplot/Cargo.toml index 7909dcd4..3b069822 100644 --- a/gnuplot/Cargo.toml +++ b/gnuplot/Cargo.toml @@ -57,6 +57,11 @@ path = "examples/box_and_whisker.rs" [[example]] +name = "box_xy_error" +path = "examples/box_xy_error.rs" + +[[example]] + name = "lines_3d" path = "examples/lines_3d.rs" diff --git a/gnuplot/examples/box_xy_error.rs b/gnuplot/examples/box_xy_error.rs new file mode 100644 index 00000000..1ffc6731 --- /dev/null +++ b/gnuplot/examples/box_xy_error.rs @@ -0,0 +1,43 @@ +// This file is released into Public Domain. +use crate::common::*; +use gnuplot::*; + +mod common; + +fn example(c: Common) +{ + let mut fg = Figure::new(); + + fg.axes2d() + .set_title("Box XY Error", &[]) + .box_xy_error_delta( + [0.0f32, 1.0, 2.0].iter(), + [-1.0f32, 0.0, 1.0].iter(), + [0.25f32, 0.375, 0.15].iter(), + [2.0f32, 3.0, 4.0].iter(), + &[], + ) + .box_xy_error_low_high( + [-0.6f32, 1.5, 2.5].iter(), + [-1.0f32, 0.0, 1.0].iter(), + [-0.9f32, -1.0, 2.2].iter(), + [-0.45f32, 3.0, 2.95].iter(), + [-1.5f32, 4.5, 3.0].iter(), + [0.5f32, 4.75, 0.125].iter(), + &[ + Color("blue"), + LineWidth(2.0), + LineStyle(SmallDot), + FillAlpha(0.5), + ], + ) + .set_x_range(Fix(-1.0), Fix(3.0)) + .set_y_range(Fix(-3.0), Fix(5.0)); + + c.show(&mut fg, "box_xy_error"); +} + +fn main() +{ + Common::new().map(|c| example(c)); +} diff --git a/gnuplot/src/axes2d.rs b/gnuplot/src/axes2d.rs index a874426d..8c4535cc 100644 --- a/gnuplot/src/axes2d.rs +++ b/gnuplot/src/axes2d.rs @@ -797,6 +797,91 @@ impl Axes2D self } + /// Plot 2D rectangular boxes - usually used for error bars - using specified by width (x_delta) and height (y_delta). + /// + /// # Arguments + /// * `x` - x values (horizontal center of the box) + /// * `y` - y values (vertical center of the box) + /// * `x_delta` - Error in x (horizontal half-width of the box) + /// * `y_delta` - Error in y (vertical half-width of the box) + /// * `options` - Array of PlotOption<&str> controlling the appearance of the plot element. The relevant options are: + /// * `Caption` - Specifies the caption for this dataset. Use an empty string to hide it (default). + /// * `LineWidth` - Sets the width of the border + /// * `LineStyle` - Sets the style of the border + /// * `BorderColor` - Sets the color of the border + /// * `Color` - Sets the color of the box fill + /// * `FillAlpha` - Sets the transparency of the box fill + pub fn box_xy_error_delta< + 'l, + Tx: DataType, + X: IntoIterator, + Ty: DataType, + Y: IntoIterator, + TXDelta: DataType, + XDelta: IntoIterator, + TYDelta: DataType, + YDelta: IntoIterator, + >( + &'l mut self, x: X, y: Y, x_delta: XDelta, y_delta: YDelta, options: &[PlotOption<&str>], + ) -> &'l mut Self { + self.common.elems.push(PlotElement::new_plot4( + BoxXYError, + x, + y, + x_delta, + y_delta, + options.to_one_way_owned(), + )); + self + } + + /// Plot 2D rectangular boxes - usually used for error bars - using specified low and high limits for x and y. + /// + /// # Arguments + /// * `x` - x values (horizontal center of the box) + /// * `y` - y values (vertical center of the box) + /// * `x_low` - Horizontal lower limit of the box + /// * `x_high` - Horizontal upper limit of the box + /// * `y_low` - Vertical lower limit of the box + /// * `y_high` - Vertical upper limit of the box + /// * `options` - Array of PlotOption<&str> controlling the appearance of the plot element. The relevant options are: + /// * `Caption` - Specifies the caption for this dataset. Use an empty string to hide it (default). + /// * `LineWidth` - Sets the width of the border + /// * `LineStyle` - Sets the style of the border + /// * `BorderColor` - Sets the color of the border + /// * `Color` - Sets the color of the box fill + /// * `FillAlpha` - Sets the transparency of the box fill + pub fn box_xy_error_low_high< + 'l, + Tx: DataType, + X: IntoIterator, + Ty: DataType, + Y: IntoIterator, + TXLow: DataType, + XLow: IntoIterator, + TXHigh: DataType, + XHigh: IntoIterator, + TYLow: DataType, + YLow: IntoIterator, + TYHigh: DataType, + YHigh: IntoIterator, + >( + &'l mut self, x: X, y: Y, x_low: XLow, x_high: XHigh,y_low: YLow, y_high: YHigh,options: &[PlotOption<&str>], + ) -> &'l mut Self { + self.common.elems.push(PlotElement::new_plot6( + BoxXYError, + x, + y, + x_low, + x_high, + y_low, + y_high, + options.to_one_way_owned(), + )); + self + } + + /// Draws an image from a rectangular array of data by connecting the individual datapoints with polygons. /// /// #Arguments: diff --git a/gnuplot/src/axes_common.rs b/gnuplot/src/axes_common.rs index 88d73b91..5881f93d 100644 --- a/gnuplot/src/axes_common.rs +++ b/gnuplot/src/axes_common.rs @@ -92,6 +92,46 @@ impl PlotElement } } + pub fn new_plot4( + plot_type: PlotType, x1: X1, x2: X2, x3: X3, x4: X4, options: Vec>, + ) -> PlotElement + where + T1: DataType, + X1: IntoIterator, + T2: DataType, + X2: IntoIterator, + T3: DataType, + X3: IntoIterator, + T4: DataType, + X4: IntoIterator, + { + let mut num_rows = 0; + let mut data = vec![]; + // TODO: Reserve. + for (((x1, x2), x3), x4) in x1 + .into_iter() + .zip(x2.into_iter()) + .zip(x3.into_iter()) + .zip(x4.into_iter()) + { + data.push(x1.get()); + data.push(x2.get()); + data.push(x3.get()); + data.push(x4.get()); + num_rows += 1; + } + + PlotElement { + data, + num_rows, + num_cols: 4, + plot_type, + source_type: Record, + is_3d: false, + options, + } + } + pub fn new_plot5( plot_type: PlotType, x1: X1, x2: X2, x3: X3, x4: X4, x5: X5, options: Vec>, @@ -307,6 +347,7 @@ impl PlotElement Polygons => "polygons", Boxes => "boxes", BoxAndWhisker => "candlestick", + BoxXYError => "boxxyerror", Pm3D => "pm3d", Image => "image", }; @@ -724,6 +765,7 @@ pub enum PlotType Polygons, Boxes, BoxAndWhisker, + BoxXYError, Pm3D, Image, } @@ -734,7 +776,7 @@ impl PlotType { matches!( *self, - Lines | LinesPoints | XErrorLines | Boxes | YErrorLines | BoxAndWhisker | Polygons + Lines | LinesPoints | XErrorLines | Boxes | YErrorLines | BoxAndWhisker | BoxXYError | Polygons ) } @@ -748,7 +790,7 @@ impl PlotType fn is_fill(&self) -> bool { - matches!(*self, Boxes | FillBetween | BoxAndWhisker | Polygons) + matches!(*self, Boxes | FillBetween | BoxAndWhisker | BoxXYError | Polygons) } }