From 28571576fe35a2edcb4964c15780fe21776273cc Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Fri, 14 Feb 2025 17:51:48 +0000 Subject: [PATCH 01/34] Initial implementation of color architecture. RBG fully implmented --- gnuplot/Cargo.toml | 6 +++ gnuplot/examples/color.rs | 68 ++++++++++++++++++++++++++++ gnuplot/examples/inverse_api.rs | 2 +- gnuplot/src/axes2d.rs | 5 ++- gnuplot/src/axes_common.rs | 11 ++--- gnuplot/src/color.rs | 79 +++++++++++++++++++++++++++++++++ gnuplot/src/lib.rs | 2 + gnuplot/src/options.rs | 12 +++-- 8 files changed, 174 insertions(+), 11 deletions(-) create mode 100644 gnuplot/examples/color.rs create mode 100644 gnuplot/src/color.rs diff --git a/gnuplot/Cargo.toml b/gnuplot/Cargo.toml index d28184be..4e57472f 100644 --- a/gnuplot/Cargo.toml +++ b/gnuplot/Cargo.toml @@ -60,6 +60,12 @@ path = "examples/box_and_whisker.rs" name = "box_xy_error" path = "examples/box_xy_error.rs" +[[example]] + +name = "color" +path = "examples/color.rs" + + [[example]] name = "lines_3d" diff --git a/gnuplot/examples/color.rs b/gnuplot/examples/color.rs new file mode 100644 index 00000000..f9ea6886 --- /dev/null +++ b/gnuplot/examples/color.rs @@ -0,0 +1,68 @@ +// This file is released into Public Domain. +use crate::common::*; +use gnuplot::*; + +mod common; + +fn example(c: Common) { + let x = 0..10; + + let mut fg = Figure::new(); + + let ax = fg.axes2d(); + ax.set_title("Color cycling", &[]); + ax.set_legend(Graph(0.5), Graph(0.9), &[], &[]); + let colors = [ + Color("black"), + ColorOpt(ColorType::RGBColor("black")), + Color("red"), + ColorOpt(ColorType::RGBColor("#ff0000")), // red using Hex coded RRGGBB + ColorOpt(ColorType::RGBColor("#ff8888")), // pink using Hex coded RRGGBB + ColorOpt(ColorType::RGBColor("#88ff0000")), // pink using Hex coded AARRGGBB + ColorOpt(ColorType::RGBColor("#ff0000")), // red using Hex coded RRGGBB + ]; + + for (i, color) in colors.into_iter().enumerate() { + ax.lines_points( + x.clone(), + x.clone().map(|v| v * 2 + i), + &[Caption(&format!("{}: {:?}", i, color)), color], + ); + } + + c.show(&mut fg, "color_cycling"); + + // 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/examples/inverse_api.rs b/gnuplot/examples/inverse_api.rs index f333ff54..a0c5a8e7 100644 --- a/gnuplot/examples/inverse_api.rs +++ b/gnuplot/examples/inverse_api.rs @@ -32,7 +32,7 @@ impl PlotElement for Lines PointSize(v) => PointSize(*v), Caption(v) => Caption(&v), LineWidth(v) => LineWidth(*v), - Color(v) => Color(&v), + ColorOpt(v) => ColorOpt(v.to_ref()), BorderColor(v) => BorderColor(&v), LineStyle(v) => LineStyle(*v), FillAlpha(v) => FillAlpha(*v), diff --git a/gnuplot/src/axes2d.rs b/gnuplot/src/axes2d.rs index 83d11a10..cbb0328f 100644 --- a/gnuplot/src/axes2d.rs +++ b/gnuplot/src/axes2d.rs @@ -8,6 +8,7 @@ use crate::datatype::*; use crate::options::*; use crate::util::{escape, OneWayOwned}; use crate::writer::Writer; +use crate::ColorType; struct LegendData { @@ -188,7 +189,7 @@ impl ArrowData } w.write_str(",12"); - AxesCommonData::write_color_options(w, &self.plot_options, Some("black")); + AxesCommonData::write_color_options(w, &self.plot_options, Some(ColorType::Black)); AxesCommonData::write_line_options( w, &self.plot_options, @@ -233,7 +234,7 @@ impl BorderOptions write!(writer, "{}", f); writer.write_str(if self.front { " front " } else { " back " }); - AxesCommonData::write_color_options(writer, &self.options, Some("black")); + AxesCommonData::write_color_options(writer, &self.options, Some(ColorType::Black)); AxesCommonData::write_line_options(writer, &self.options, version); writer.write_str("\n"); diff --git a/gnuplot/src/axes_common.rs b/gnuplot/src/axes_common.rs index 5b88cb2e..a907222e 100644 --- a/gnuplot/src/axes_common.rs +++ b/gnuplot/src/axes_common.rs @@ -12,6 +12,7 @@ use crate::datatype::*; use crate::options::*; use crate::util::{escape, OneWayOwned}; use crate::writer::*; +use crate::ColorType; use std::borrow::Borrow; use std::fs; use std::path; @@ -859,7 +860,7 @@ impl AxisData w.write_str(self.axis.get_axis_str()); w.write_str("zeroaxis "); - AxesCommonData::write_color_options(w, &self.options, Some("black")); + AxesCommonData::write_color_options(w, &self.options, Some(ColorType::RGBColor("black".into()))); AxesCommonData::write_line_options(w, &self.options, version); } else @@ -1365,19 +1366,19 @@ impl AxesCommonData } pub fn write_color_options( - c: &mut dyn Writer, options: &[PlotOption], default: Option<&str>, + c: &mut dyn Writer, options: &[PlotOption], default: Option, ) { - let mut col = default; + let mut col = default.as_ref(); first_opt! {options, - Color(ref s) => + ColorOpt(ref s) => { col = Some(s) } } if let Some(s) = col { - write!(c, r#" lc rgb "{}""#, s); + write!(c, "lc {}", s.command()); } } diff --git a/gnuplot/src/color.rs b/gnuplot/src/color.rs new file mode 100644 index 00000000..66dbe0b0 --- /dev/null +++ b/gnuplot/src/color.rs @@ -0,0 +1,79 @@ +pub use self::ColorType::*; + +pub trait IntoColor: Into + Clone {} +impl + Clone> IntoColor for T {} + +#[derive(Debug, Clone, PartialEq, PartialOrd)] +pub enum ColorType { + RGBColor(T), + RGBIntegerColor(u16), + RGBVariableColor, + PaletteFracColor(f32), + PaletteCBColor(f32), + PaletteZColor, + PaletteColorMap(T), + VariableColor, + BackgroundColor, + IndexColor, + Black, +} + +impl ColorType { + pub fn command(&self) -> String { + match self { + RGBColor(s) => format!(r#"rgb "{}""#, s), + RGBIntegerColor(_) => todo!(), + RGBVariableColor => todo!(), + PaletteFracColor(_) => todo!(), + PaletteCBColor(_) => todo!(), + PaletteZColor => todo!(), + PaletteColorMap(_) => todo!(), + VariableColor => todo!(), + BackgroundColor => todo!(), + IndexColor => todo!(), + Black => String::from("black"), + } + } +} + +impl <'l> Into> for &'l str { + fn into(self) -> ColorType<&'l str> { + ColorType::RGBColor(self) + } +} + +impl ColorType{ + pub fn to_one_way_owned(&self) -> ColorType { + match self { + RGBColor(s)=>RGBColor(s.to_string()), + RGBIntegerColor(c) => RGBIntegerColor(*c), + RGBVariableColor => todo!(), + PaletteFracColor(_) => todo!(), + PaletteCBColor(_) => todo!(), + PaletteZColor => todo!(), + PaletteColorMap(_) => todo!(), + VariableColor => todo!(), + BackgroundColor => todo!(), + IndexColor => todo!(), + Black => todo!(), + // x=>x, + } + } +} +impl ColorType { + pub fn to_ref(&self) -> ColorType<&str> { + match self { + RGBColor(s)=>RGBColor(&s), + RGBIntegerColor(_) => todo!(), + RGBVariableColor => todo!(), + PaletteFracColor(_) => todo!(), + PaletteCBColor(_) => todo!(), + PaletteZColor => todo!(), + PaletteColorMap(_) => todo!(), + VariableColor => todo!(), + BackgroundColor => todo!(), + IndexColor => todo!(), + Black => todo!(), + } + } +} diff --git a/gnuplot/src/lib.rs b/gnuplot/src/lib.rs index b7f89105..6f9dc791 100644 --- a/gnuplot/src/lib.rs +++ b/gnuplot/src/lib.rs @@ -31,6 +31,7 @@ pub use crate::datatype::*; pub use crate::error_types::*; pub use crate::figure::*; pub use crate::options::*; +pub use crate::color::*; #[macro_use] mod util; @@ -45,3 +46,4 @@ mod figure; mod options; pub mod palettes; mod writer; +mod color; \ No newline at end of file diff --git a/gnuplot/src/options.rs b/gnuplot/src/options.rs index d3334016..a2da6467 100644 --- a/gnuplot/src/options.rs +++ b/gnuplot/src/options.rs @@ -20,10 +20,11 @@ pub use self::TickOption::*; pub use self::XAxis::*; pub use self::YAxis::*; use crate::util::OneWayOwned; +use crate::ColorType; /// An enumeration of plot options you can supply to plotting commands, governing /// things like line width, color and others -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Clone, Debug, PartialOrd, PartialEq)] pub enum PlotOption { /// Sets the symbol used for points. The valid characters are as follows: @@ -51,7 +52,7 @@ pub enum PlotOption LineWidth(f64), /// Sets the color of the plot element. The passed string can be a color name /// (e.g. "black" works), or an HTML color specifier (e.g. "#FFFFFF" is white). This specifies the fill color of a filled plot. - Color(T), + ColorOpt(ColorType), /// Sets the color of the border of a filled plot (if it has one). The passed string can be a color name /// (e.g. "black" works), or an HTML color specifier (e.g. "#FFFFFF" is white). BorderColor(T), @@ -74,6 +75,11 @@ pub enum PlotOption Axes(XAxis, YAxis), } +#[allow(non_snake_case)] +pub fn Color<'l>(c:&'l str)->PlotOption<&'l str>{ + ColorOpt(c.into()) +} + impl<'l> OneWayOwned for PlotOption<&'l str> { type Output = PlotOption; @@ -85,7 +91,7 @@ impl<'l> OneWayOwned for PlotOption<&'l str> PointSize(v) => PointSize(v), Caption(v) => Caption(v.into()), LineWidth(v) => LineWidth(v), - Color(v) => Color(v.into()), + ColorOpt(ref v) => ColorOpt(v.to_one_way_owned()), BorderColor(v) => BorderColor(v.into()), LineStyle(v) => LineStyle(v), FillAlpha(v) => FillAlpha(v), From 203b8ce1b5498cc4f65b8be5a37f5c11f0e27fdf Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Sun, 16 Feb 2025 18:10:53 +0000 Subject: [PATCH 02/34] Implement variable index color -requires new plot architecture --- gnuplot/examples/color.rs | 73 +++++++++++++++++++++++++-- gnuplot/examples/example1.rs | 2 +- gnuplot/src/axes2d.rs | 96 +++++++++++++++++++++++------------- gnuplot/src/axes_common.rs | 19 ++++++- gnuplot/src/color.rs | 86 ++++++++++++++++++++++++++------ gnuplot/src/lib.rs | 2 +- gnuplot/src/options.rs | 9 ++-- gnuplot/src/util.rs | 82 ++++++++++++++++++++++++++++++ 8 files changed, 308 insertions(+), 61 deletions(-) diff --git a/gnuplot/examples/color.rs b/gnuplot/examples/color.rs index f9ea6886..43b8fec4 100644 --- a/gnuplot/examples/color.rs +++ b/gnuplot/examples/color.rs @@ -1,16 +1,29 @@ +use std::iter; + // This file is released into Public Domain. use crate::common::*; use gnuplot::*; mod common; +// https://github.com/gnuplot/gnuplot/blob/master/demo/candlesticks.dat +static CANDLESTICKS_STR: &str = "1 1.5 2 2.4 4 6. +2 1.5 3 3.5 4 5.5 +3 4.5 5 5.5 6 6.5 +4 3.7 4.5 5.0 5.5 6.1 +5 3.1 3.5 4.2 5 6.1 +6 1 4 5.0 6 9 +7 4 4 4.8 6 6.1 +8 4 5 5.1 6 6.1 +9 1.5 2 2.4 3 3.5 +10 2.7 3 3.5 4 4.3"; + fn example(c: Common) { let x = 0..10; let mut fg = Figure::new(); - let ax = fg.axes2d(); - ax.set_title("Color cycling", &[]); + ax.set_title("Demo of RGBColor in various forms", &[]); ax.set_legend(Graph(0.5), Graph(0.9), &[], &[]); let colors = [ Color("black"), @@ -30,7 +43,61 @@ fn example(c: Common) { ); } - c.show(&mut fg, "color_cycling"); + c.show(&mut fg, "rgb_color"); + + + let data:Vec> = CANDLESTICKS_STR.split("\n").map(|line| line.split("\t").map(|v| v.trim().parse::().unwrap()).collect()).collect(); + let extract_col = |i| data.iter().map(|l| l[i]).collect::>(); + + let d1 = extract_col(0); + let d2 = extract_col(1); + let d3 = extract_col(2); + // let d4 = extract_col(3); + let d5 = extract_col(4); + let d6 = extract_col(5); + let row_index:Vec<_> = (0..d1.len() as u32).collect(); + + // Demo/test of variable color in many different plot styles + // derived from plot 1 in https://gnuplot.sourceforge.net/demo_6.0/varcolor.html + // this demonstrates usage of variableColor with indcies to use gnuplots dfefalt color styles, + // but make them align for multiple plot items on the same axis. + // i.e. evertything at x = 1 uses the first gnuplot color, everything at x = 2 uses the second and so on. + let mut fg = Figure::new(); + let ax = fg.axes2d(); + ax.set_title("variable color points, candlesticks, boxes, and boxxyerror", &[]); + ax.set_y_range(Fix(-4.0), Fix(10.0)); + ax.set_x_range(Fix(0.0), Fix(11.0)); + + let by3 = |x| (((x%3.0)+1.0)/6.0); + let by4 = |x| (((x%4.0)+1.0)/7.0); + + // let ax.financebars(...) + // points replaces circles (as circles not implemented) + ax.points(&d1, &d2, &[ColorOpt(VariableColor(row_index.clone())), PointSymbol('O'), PointSize(3.0)]); + ax.box_xy_error_delta( + &d1, + iter::repeat(8), + d1.iter().map(by3), + d1.iter().map(by4), + &[ColorOpt(VariableColor(row_index.clone()))]); + ax.boxes_set_width( + &d1, + d2.iter().map(|v| -v/2.0), + iter::repeat(0.2), + &[ColorOpt(VariableColor(row_index.clone()))]); + // box_and_whisker is rust gnuplot's name for candlestick + ax.box_and_whisker_set_width( + &d1, + d3, + d2, + d6, + d5, + iter::repeat(0.3), + &[ColorOpt(VariableColor(row_index.clone()))]); + // set boxwidth 0.2 abs + // set bars front + // rgbfudge(x) = x*51*32768 + (11-x)*51*128 + int(abs(5.5-x)*510/9.) + c.show(&mut fg, "variable_color"); // let mut fg = Figure::new(); diff --git a/gnuplot/examples/example1.rs b/gnuplot/examples/example1.rs index f5a28d6e..96e260b7 100644 --- a/gnuplot/examples/example1.rs +++ b/gnuplot/examples/example1.rs @@ -307,7 +307,7 @@ fn example(c: Common) MarkerSymbol('*'), TextAlign(AlignCenter), TextOffset(0.0, -1.0), - MarkerColor("red"), + MarkerColor(RGBColor("red")), MarkerSize(2.0), ], ); diff --git a/gnuplot/src/axes2d.rs b/gnuplot/src/axes2d.rs index cbb0328f..bbadb34a 100644 --- a/gnuplot/src/axes2d.rs +++ b/gnuplot/src/axes2d.rs @@ -405,12 +405,16 @@ impl Axes2D &'l mut self, x: X, y: Y, options: &[PlotOption<&str>], ) -> &'l mut Self { - self.common.elems.push(PlotElement::new_plot2( - Points, - x, - y, - options.to_one_way_owned(), - )); + let (data, num_rows, num_cols) = generate_data!(options, x, y); + self.common.elems.push( + PlotElement::new_plot( + Points, + data, + num_rows, + num_cols, + options, + ) + ); self } @@ -660,12 +664,16 @@ impl Axes2D &'l mut self, x: X, y: Y, options: &[PlotOption<&str>], ) -> &'l mut Self { - self.common.elems.push(PlotElement::new_plot2( - Boxes, - x, - y, - options.to_one_way_owned(), - )); + let (data, num_rows, num_cols) = generate_data!(options, x, y); + self.common.elems.push( + PlotElement::new_plot( + Boxes, + data, + num_rows, + num_cols, + options, + ) + ); self } @@ -694,13 +702,16 @@ impl Axes2D &'l mut self, x: X, y: Y, w: W, options: &[PlotOption<&str>], ) -> &'l mut Self { - self.common.elems.push(PlotElement::new_plot3( - Boxes, - x, - y, - w, - options.to_one_way_owned(), - )); + let (data, num_rows, num_cols) = generate_data!(options, x, y, w); + self.common.elems.push( + PlotElement::new_plot( + Boxes, + data, + num_rows, + num_cols, + options, + ) + ); self } @@ -737,14 +748,20 @@ impl Axes2D box_max: BoxMax, options: &[PlotOption<&str>], ) -> &'l mut Self { - self.common.elems.push(PlotElement::new_plot5( - BoxAndWhisker, + let (data, num_rows, num_cols) = generate_data!( + options, x, box_min, whisker_min, whisker_max, - box_max, - options.to_one_way_owned(), + box_max); + self.common.elems.push( + PlotElement::new_plot( + BoxAndWhisker, + data, + num_rows, + num_cols, + options, )); self } @@ -785,15 +802,22 @@ impl Axes2D box_max: BoxMax, box_width: BoxWidth, options: &[PlotOption<&str>], ) -> &'l mut Self { - self.common.elems.push(PlotElement::new_plot6( - BoxAndWhisker, + let (data, num_rows, num_cols) = generate_data!( + options, x, box_min, whisker_min, whisker_max, box_max, - box_width, - options.to_one_way_owned(), + box_width + ); + self.common.elems.push( + PlotElement::new_plot( + BoxAndWhisker, + data, + num_rows, + num_cols, + options, )); self } @@ -826,14 +850,16 @@ impl Axes2D &'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(), - )); + let (data, num_rows, num_cols) = generate_data!(options, x, y, x_delta, y_delta); + self.common.elems.push( + PlotElement::new_plot( + BoxXYError, + data, + num_rows, + num_cols, + options, + ) + ); self } diff --git a/gnuplot/src/axes_common.rs b/gnuplot/src/axes_common.rs index a907222e..a22244a4 100644 --- a/gnuplot/src/axes_common.rs +++ b/gnuplot/src/axes_common.rs @@ -30,6 +30,21 @@ pub struct PlotElement impl PlotElement { + pub fn new_plot<'l>( + plot_type: PlotType, data: Vec, num_rows: usize, num_cols: usize, options: &[PlotOption<&str>], + ) -> PlotElement{ + PlotElement { + data, + num_rows, + num_cols, + plot_type, + source_type: Record, + is_3d: false, + options: options.to_one_way_owned(), + } + } + + pub fn new_plot2( plot_type: PlotType, x1: X1, x2: X2, options: Vec>, ) -> PlotElement @@ -661,7 +676,7 @@ pub fn write_out_label_options( first_opt! {options, MarkerColor(ref s) => { - write!(w, r#" lc rgb "{}""#, s); + write!(w, r#" lc rgb "{}""#, s.command()); } } @@ -1378,7 +1393,7 @@ impl AxesCommonData } if let Some(s) = col { - write!(c, "lc {}", s.command()); + write!(c, " lc {}", s.command()); } } diff --git a/gnuplot/src/color.rs b/gnuplot/src/color.rs index 66dbe0b0..1ae88eb6 100644 --- a/gnuplot/src/color.rs +++ b/gnuplot/src/color.rs @@ -1,62 +1,117 @@ +//! TODO + pub use self::ColorType::*; pub trait IntoColor: Into + Clone {} impl + Clone> IntoColor for T {} +/// Option type (for lines, axes, and text) that allows the various different gnuplot +/// color formats. The gnuplot [colorspec reference](http://gnuplot.info/docs_6.0/loc3640.html) +/// also explains these +/// +/// There are equivalent many ways of specifying colors, and this allows the user to chose the most convenient. +/// for example, all the following will produce the same blue color: +/// `RGBColor("blue")`, `RGBColor("0x0000ff")`, `RGBColor("#0000ff")`, `RGBColor("0x000000ff")`, +/// `RGBColor("#000000ff")`, `RGBIntegerColor(0, 0, 255)`, `ARGBColor(0, 0, 0, 255)`, +/// +/// See example usage of this in `color.rs` in the +/// [Examples folder](https://github.com/SiegeLord/RustGnuplot/tree/master/gnuplot/examples) on Github #[derive(Debug, Clone, PartialEq, PartialOrd)] pub enum ColorType { + /// string (`&str` or `String`, but usually created with `&str`) in one of the following gnuplot-supported formats + /// - colorname --- e.g. "blue" [See the gnuplot + /// [list of colornames](http://gnuplot.info/docs_6.0/loc11229.html)] + /// - 0xRRGGBB --- string containing hexadecimal constant + /// - 0xAARRGGBB --- string containing hexadecimal constant + /// - #RRGGBB --- string containing hexadecimal in x11 format + /// - #AARRGGBB --- string containing hexadecimal in x11 format + /// + /// "#AARRGGBB" represents an RGB color with an alpha channel (transparency) value in the high bits. + /// An alpha value of 0 represents a fully opaque color; i.e., "#00RRGGBB" is the same as "#RRGGBB". + /// An alpha value of 255 (FF) represents full transparency. RGBColor(T), - RGBIntegerColor(u16), - RGBVariableColor, + /// tuple of u8 representing red, green and blue values as 0-255 + RGBIntegerColor(u8, u8, u8), + /// tuple of u8 representing alpha, red, green and blue values as 0-255. + /// As with `RGBColor`, an alpha value of 0 represents a fully opaque color; + /// an alpha value of 255 (FF) represents full transparency. + ARGBIntegerColor(u8,u8,u8,u8), + RGBVariableColor(Vec), PaletteFracColor(f32), PaletteCBColor(f32), PaletteZColor, PaletteColorMap(T), - VariableColor, + VariableColor(Vec), BackgroundColor, IndexColor, Black, } impl ColorType { + /// Returns the gnuplot string that will produce the requested color pub fn command(&self) -> String { match self { RGBColor(s) => format!(r#"rgb "{}""#, s), - RGBIntegerColor(_) => todo!(), - RGBVariableColor => todo!(), + RGBIntegerColor(r, g, b) => format!(r#"rgb {}"#, from_argb(0, *r, *g, *b)), + ARGBIntegerColor(a, r, g, b) => format!(r#"rgb {}"#, from_argb(*a, *r, *g, *b)), + RGBVariableColor(_) => String::from("rgb variable"), PaletteFracColor(_) => todo!(), PaletteCBColor(_) => todo!(), PaletteZColor => todo!(), PaletteColorMap(_) => todo!(), - VariableColor => todo!(), + VariableColor(_) => String::from("variable"), BackgroundColor => todo!(), IndexColor => todo!(), Black => String::from("black"), + } } } +pub fn from_argb(a:u8, r:u8, g:u8, b:u8) -> u32{ + (a as u32) << 24 + (r as u32) << 16 + (g as u32) << 8 + (b as u32) +} + +impl <'l> Into> for &'l str { + fn into(self) -> ColorType { + ColorType::RGBColor(String::from(self)) + } +} + +impl <'l> Into> for String { + fn into(self) -> ColorType { + ColorType::RGBColor(self) + } +} + impl <'l> Into> for &'l str { fn into(self) -> ColorType<&'l str> { ColorType::RGBColor(self) } } +// impl <'l> Into> for String { +// fn into(self) -> ColorType<&'l str> { +// ColorType::RGBColor(&self) +// } +// } + + impl ColorType{ pub fn to_one_way_owned(&self) -> ColorType { match self { RGBColor(s)=>RGBColor(s.to_string()), - RGBIntegerColor(c) => RGBIntegerColor(*c), - RGBVariableColor => todo!(), + RGBIntegerColor(r, g,b) => RGBIntegerColor(*r, *g, *b), + RGBVariableColor(_) => todo!(), PaletteFracColor(_) => todo!(), PaletteCBColor(_) => todo!(), PaletteZColor => todo!(), PaletteColorMap(_) => todo!(), - VariableColor => todo!(), + VariableColor(d) => VariableColor(d.clone()), BackgroundColor => todo!(), IndexColor => todo!(), - Black => todo!(), - // x=>x, + Black => Black, + ARGBIntegerColor(a, r, g, b) => ARGBIntegerColor(*a, *r,*g, *b), } } } @@ -64,16 +119,17 @@ impl ColorType { pub fn to_ref(&self) -> ColorType<&str> { match self { RGBColor(s)=>RGBColor(&s), - RGBIntegerColor(_) => todo!(), - RGBVariableColor => todo!(), + RGBIntegerColor(r,g,b) => RGBIntegerColor(*r, *g, *b), + RGBVariableColor(_) => todo!(), PaletteFracColor(_) => todo!(), PaletteCBColor(_) => todo!(), PaletteZColor => todo!(), PaletteColorMap(_) => todo!(), - VariableColor => todo!(), + VariableColor(_) => todo!(), BackgroundColor => todo!(), IndexColor => todo!(), - Black => todo!(), + Black => Black, + ARGBIntegerColor(a, r, g, b) => ARGBIntegerColor(*a, *r,*g, *b), } } } diff --git a/gnuplot/src/lib.rs b/gnuplot/src/lib.rs index 6f9dc791..5da7b93a 100644 --- a/gnuplot/src/lib.rs +++ b/gnuplot/src/lib.rs @@ -27,11 +27,11 @@ pub use crate::axes2d::Axes2D; pub use crate::axes3d::Axes3D; pub use crate::axes_common::AxesCommon; pub use crate::coordinates::*; +pub use crate::color::*; pub use crate::datatype::*; pub use crate::error_types::*; pub use crate::figure::*; pub use crate::options::*; -pub use crate::color::*; #[macro_use] mod util; diff --git a/gnuplot/src/options.rs b/gnuplot/src/options.rs index a2da6467..751bf058 100644 --- a/gnuplot/src/options.rs +++ b/gnuplot/src/options.rs @@ -76,6 +76,7 @@ pub enum PlotOption } #[allow(non_snake_case)] +/// TODO pub fn Color<'l>(c:&'l str)->PlotOption<&'l str>{ ColorOpt(c.into()) } @@ -221,7 +222,7 @@ impl OneWayOwned for AutoOption } /// An enumeration of label options that control label attributes -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Clone, Debug, PartialOrd, PartialEq)] pub enum LabelOption { /// Sets the offset of the label in characters @@ -254,7 +255,7 @@ pub enum LabelOption MarkerSymbol(char), /// Sets the color of the marker. The passed string can be a color name /// (e.g. "black" works), or an HTML color specifier (e.g. "#FFFFFF" is white) - MarkerColor(T), + MarkerColor(ColorType), /// Sets the size of the marker. The size acts as a multiplier, with 1.0 being the default. MarkerSize(f64), } @@ -264,7 +265,7 @@ impl<'l> OneWayOwned for LabelOption<&'l str> type Output = LabelOption; fn to_one_way_owned(&self) -> Self::Output { - match *self + match self.clone() { TextOffset(v1, v2) => TextOffset(v1, v2), Font(v1, v2) => Font(v1.into(), v2), @@ -272,7 +273,7 @@ impl<'l> OneWayOwned for LabelOption<&'l str> Rotate(v) => Rotate(v), TextAlign(v) => TextAlign(v), MarkerSymbol(v) => MarkerSymbol(v), - MarkerColor(v) => MarkerColor(v.into()), + MarkerColor(v) => MarkerColor(v.to_one_way_owned()), MarkerSize(v) => MarkerSize(v), } } diff --git a/gnuplot/src/util.rs b/gnuplot/src/util.rs index 6294d593..ce5008c8 100644 --- a/gnuplot/src/util.rs +++ b/gnuplot/src/util.rs @@ -48,6 +48,88 @@ macro_rules! first_opt_default ) } +// returns (data, num_rows, num_cols) +macro_rules! generate_data { + ($options: ident, $( $d:ident ),*) => { + {let mut c_data = None; + + first_opt! {$options, + ColorOpt(ref color) => + { + match color + { + ColorType::VariableColor(values)| ColorType::RGBVariableColor(values) => { + c_data = Some(values); + }, + _ => (), + } + } + } + if let Some(c_values) = c_data { + generate_data_inner!( + $( + $d, + )* + c_values + ) + } else{ + generate_data_inner!( + $( + $d, + )* + ) + } + } + }; +} + +// returns (data, num_rows, num_cols) +macro_rules! generate_data_inner { + ($( $d:ident ),* $(,)?) => { + { + let mut num_rows = 0; + let num_cols = count_data!($($d )*); + let mut data = vec![]; + // TODO: Reserve. + for nested_tuples!($($d,)*) in multizip!($($d, )*) //macro + { + $( data.push($d.get()); )* + num_rows += 1; + } + (data, num_rows, num_cols) + } + } +} + +macro_rules! nested_tuples { + ($last: ident $(,)?)=> + { + $last + }; + ($first: ident, $( $tail:ident ),* $(,)? ) => { + ($first, nested_tuples!($($tail, )*)) + }; +} + +macro_rules! multizip { + ($last: ident $(,)?)=> + { + ($last.into_iter()) + }; + ($first: ident, $( $tail:ident ),* , ) => { + $first.into_iter().zip(multizip!($($tail, )*)) + }; +} + + +macro_rules! replace_expr { + ($_t:tt $sub:expr) => {$sub}; +} + +macro_rules! count_data { + ($($data:tt)*) => {0usize $(+ replace_expr!($data 1usize))*}; +} + pub(crate) trait OneWayOwned { type Output; From 9be2ab08db9d0285e0e79450156779aafed0fb25 Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Sun, 16 Feb 2025 22:04:50 +0000 Subject: [PATCH 03/34] Implement no-show option in inverse_api example --- gnuplot/examples/inverse_api.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/gnuplot/examples/inverse_api.rs b/gnuplot/examples/inverse_api.rs index a0c5a8e7..932a4d05 100644 --- a/gnuplot/examples/inverse_api.rs +++ b/gnuplot/examples/inverse_api.rs @@ -176,11 +176,14 @@ fn example(c: Common) //~ lines(z.clone(), y.clone()).show(); - (lines(z.clone(), y.clone()), lines(z.clone(), x.clone())) - .to_axes2d() - .title("Test") - .x(axis().log_scale(Some(10.))) - .show(); + let mut axes = (lines(z.clone(), y.clone()), lines(z.clone(), x.clone())) + .to_axes2d(); + axes.title("Test"); + axes.x(axis().log_scale(Some(10.))); + + if !c.no_show { + axes.show(); + } } fn main() From 01b0be1943d8cca9a4f6cec04c6e28f23eaa021a Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Sun, 16 Feb 2025 22:12:10 +0000 Subject: [PATCH 04/34] Finish architecture updates for generate_data/new_plot --- gnuplot/src/axes2d.rs | 152 +++++++++++++++++----------- gnuplot/src/axes3d.rs | 34 ++++--- gnuplot/src/axes_common.rs | 198 ------------------------------------- 3 files changed, 112 insertions(+), 272 deletions(-) diff --git a/gnuplot/src/axes2d.rs b/gnuplot/src/axes2d.rs index bbadb34a..a6e49455 100644 --- a/gnuplot/src/axes2d.rs +++ b/gnuplot/src/axes2d.rs @@ -377,12 +377,16 @@ impl Axes2D &'l mut self, x: X, y: Y, options: &[PlotOption<&str>], ) -> &'l mut Self { - self.common.elems.push(PlotElement::new_plot2( - Lines, - x, - y, - options.to_one_way_owned(), - )); + let (data, num_rows, num_cols) = generate_data!(options, x, y); + self.common.elems.push( + PlotElement::new_plot( + Lines, + data, + num_rows, + num_cols, + options, + ) + ); self } @@ -433,12 +437,16 @@ impl Axes2D &'l mut self, x: X, y: Y, options: &[PlotOption<&str>], ) -> &'l mut Self { - self.common.elems.push(PlotElement::new_plot2( - LinesPoints, - x, - y, - options.to_one_way_owned(), - )); + let (data, num_rows, num_cols) = generate_data!(options, x, y); + self.common.elems.push( + PlotElement::new_plot( + LinesPoints, + data, + num_rows, + num_cols, + options, + ) + ); self } @@ -465,13 +473,16 @@ impl Axes2D &'l mut self, x: X, y: Y, x_error: XE, options: &[PlotOption<&str>], ) -> &'l mut Self { - self.common.elems.push(PlotElement::new_plot3( - XErrorBars, - x, - y, - x_error, - options.to_one_way_owned(), - )); + let (data, num_rows, num_cols) = generate_data!(options, x, y, x_error); + self.common.elems.push( + PlotElement::new_plot( + XErrorBars, + data, + num_rows, + num_cols, + options, + ) + ); self } @@ -498,13 +509,16 @@ impl Axes2D &'l mut self, x: X, y: Y, y_error: YE, options: &[PlotOption<&str>], ) -> &'l mut Self { - self.common.elems.push(PlotElement::new_plot3( - YErrorBars, - x, - y, - y_error, - options.to_one_way_owned(), - )); + let (data, num_rows, num_cols) = generate_data!(options, x, y, y_error); + self.common.elems.push( + PlotElement::new_plot( + YErrorBars, + data, + num_rows, + num_cols, + options, + ) + ); self } @@ -533,13 +547,16 @@ impl Axes2D &'l mut self, x: X, y: Y, x_error: XE, options: &[PlotOption<&str>], ) -> &'l mut Self { - self.common.elems.push(PlotElement::new_plot3( - XErrorLines, - x, - y, - x_error, - options.to_one_way_owned(), - )); + let (data, num_rows, num_cols) = generate_data!(options, x, y, x_error); + self.common.elems.push( + PlotElement::new_plot( + XErrorLines, + data, + num_rows, + num_cols, + options, + ) + ); self } @@ -568,14 +585,16 @@ impl Axes2D &'l mut self, x: X, y: Y, y_error: YE, options: &[PlotOption<&str>], ) -> &'l mut Self { - self.common.elems.push(PlotElement::new_plot3( - YErrorLines, - x, - y, - y_error, - options.to_one_way_owned(), - )); - self + let (data, num_rows, num_cols) = generate_data!(options, x, y, y_error); + self.common.elems.push( + PlotElement::new_plot( + YErrorLines, + data, + num_rows, + num_cols, + options, + ) + );self } /// Plot a 2D scatter-plot of two curves (bound by `y_lo` and `y_hi`) with a filled region between them. @@ -602,13 +621,16 @@ impl Axes2D &'l mut self, x: X, y_lo: YL, y_hi: YH, options: &[PlotOption<&str>], ) -> &'l mut Self { - self.common.elems.push(PlotElement::new_plot3( - FillBetween, - x, - y_lo, - y_hi, - options.to_one_way_owned(), - )); + let (data, num_rows, num_cols) = generate_data!(options, x, y_lo, y_hi); + self.common.elems.push( + PlotElement::new_plot( + FillBetween, + data, + num_rows, + num_cols, + options, + ) + ); self } @@ -633,12 +655,16 @@ impl Axes2D &'l mut self, x: X, y: Y, options: &[PlotOption<&str>], ) -> &'l mut Self { - self.common.elems.push(PlotElement::new_plot2( - Polygons, - x, - y, - options.to_one_way_owned(), - )); + let (data, num_rows, num_cols) = generate_data!(options, x, y); + self.common.elems.push( + PlotElement::new_plot( + FillBetween, + data, + num_rows, + num_cols, + options, + ) + ); self } @@ -898,16 +924,24 @@ impl Axes2D options: &[PlotOption<&str>], ) -> &'l mut Self { - self.common.elems.push(PlotElement::new_plot6( - BoxXYError, + let (data, num_rows, num_cols) = generate_data!( + options, x, y, x_low, x_high, y_low, - y_high, - options.to_one_way_owned(), - )); + y_high + ); + self.common.elems.push( + PlotElement::new_plot( + BoxXYError, + data, + num_rows, + num_cols, + options, + ) + ); self } diff --git a/gnuplot/src/axes3d.rs b/gnuplot/src/axes3d.rs index b76d0548..3707d551 100644 --- a/gnuplot/src/axes3d.rs +++ b/gnuplot/src/axes3d.rs @@ -8,6 +8,7 @@ use crate::options::*; use crate::util::OneWayOwned; use crate::writer::Writer; use std::borrow::Borrow; +use crate::ColorType; enum View { @@ -119,12 +120,13 @@ impl Axes3D &'l mut self, x: X, y: Y, z: Z, options: &[PlotOption<&str>], ) -> &'l mut Self { - self.common.elems.push(PlotElement::new_plot3( + let (data, num_rows, num_cols) = generate_data!(options, x, y, z); + self.common.elems.push(PlotElement::new_plot( Points, - x, - y, - z, - options.to_one_way_owned(), + data, + num_rows, + num_cols, + options, )); self } @@ -151,12 +153,13 @@ impl Axes3D &'l mut self, x: X, y: Y, z: Z, options: &[PlotOption<&str>], ) -> &'l mut Self { - self.common.elems.push(PlotElement::new_plot3( + let (data, num_rows, num_cols) = generate_data!(options, x, y, z); + self.common.elems.push(PlotElement::new_plot( Lines, - x, - y, - z, - options.to_one_way_owned(), + data, + num_rows, + num_cols, + options, )); self } @@ -179,12 +182,13 @@ impl Axes3D &'l mut self, x: X, y: Y, z: Z, options: &[PlotOption<&str>], ) -> &'l mut Self { - self.common.elems.push(PlotElement::new_plot3( + let (data, num_rows, num_cols) = generate_data!(options, x, y, z); + self.common.elems.push(PlotElement::new_plot( LinesPoints, - x, - y, - z, - options.to_one_way_owned(), + data, + num_rows, + num_cols, + options, )); self } diff --git a/gnuplot/src/axes_common.rs b/gnuplot/src/axes_common.rs index a22244a4..791ad5be 100644 --- a/gnuplot/src/axes_common.rs +++ b/gnuplot/src/axes_common.rs @@ -44,204 +44,6 @@ impl PlotElement } } - - pub fn new_plot2( - plot_type: PlotType, x1: X1, x2: X2, options: Vec>, - ) -> PlotElement - where - T1: DataType, - X1: IntoIterator, - T2: DataType, - X2: IntoIterator, - { - let mut num_rows = 0; - let mut data = vec![]; - // TODO: Reserve. - for (x1, x2) in x1.into_iter().zip(x2.into_iter()) - { - data.push(x1.get()); - data.push(x2.get()); - num_rows += 1; - } - - PlotElement { - data, - num_rows, - num_cols: 2, - plot_type, - source_type: Record, - is_3d: false, - options, - } - } - - pub fn new_plot3( - plot_type: PlotType, x1: X1, x2: X2, x3: X3, options: Vec>, - ) -> PlotElement - where - T1: DataType, - X1: IntoIterator, - T2: DataType, - X2: IntoIterator, - T3: DataType, - X3: IntoIterator, - { - let mut num_rows = 0; - let mut data = vec![]; - // TODO: Reserve. - for ((x1, x2), x3) in x1.into_iter().zip(x2.into_iter()).zip(x3.into_iter()) - { - data.push(x1.get()); - data.push(x2.get()); - data.push(x3.get()); - num_rows += 1; - } - - PlotElement { - data, - num_rows, - num_cols: 3, - plot_type, - source_type: Record, - is_3d: false, - options, - } - } - - 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>, - ) -> PlotElement - where - T1: DataType, - X1: IntoIterator, - T2: DataType, - X2: IntoIterator, - T3: DataType, - X3: IntoIterator, - T4: DataType, - X4: IntoIterator, - T5: DataType, - X5: IntoIterator, - { - let mut num_rows = 0; - let mut data = vec![]; - // TODO: Reserve. - for ((((x1, x2), x3), x4), x5) in x1 - .into_iter() - .zip(x2.into_iter()) - .zip(x3.into_iter()) - .zip(x4.into_iter()) - .zip(x5.into_iter()) - { - data.push(x1.get()); - data.push(x2.get()); - data.push(x3.get()); - data.push(x4.get()); - data.push(x5.get()); - num_rows += 1; - } - - PlotElement { - data, - num_rows, - num_cols: 5, - plot_type, - source_type: Record, - is_3d: false, - options, - } - } - - pub fn new_plot6( - plot_type: PlotType, x1: X1, x2: X2, x3: X3, x4: X4, x5: X5, x6: X6, - options: Vec>, - ) -> PlotElement - where - T1: DataType, - X1: IntoIterator, - T2: DataType, - X2: IntoIterator, - T3: DataType, - X3: IntoIterator, - T4: DataType, - X4: IntoIterator, - T5: DataType, - X5: IntoIterator, - T6: DataType, - X6: IntoIterator, - { - let mut num_rows = 0; - let mut data = vec![]; - // TODO: Reserve. - for (((((x1, x2), x3), x4), x5), x6) in x1 - .into_iter() - .zip(x2.into_iter()) - .zip(x3.into_iter()) - .zip(x4.into_iter()) - .zip(x5.into_iter()) - .zip(x6.into_iter()) - { - data.push(x1.get()); - data.push(x2.get()); - data.push(x3.get()); - data.push(x4.get()); - data.push(x5.get()); - data.push(x6.get()); - num_rows += 1; - } - - PlotElement { - data, - num_rows, - num_cols: 6, - plot_type, - source_type: Record, - is_3d: false, - options, - } - } - pub fn new_plot_matrix>( plot_type: PlotType, is_3d: bool, mat: X, num_rows: usize, num_cols: usize, dimensions: Option<(f64, f64, f64, f64)>, options: Vec>, From b3ed31225305d5b74a8adfe13f9e4f8bb5213ca7 Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Sun, 16 Feb 2025 22:40:28 +0000 Subject: [PATCH 05/34] Tidy macro formatting --- gnuplot/src/util.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gnuplot/src/util.rs b/gnuplot/src/util.rs index ce5008c8..82d844c3 100644 --- a/gnuplot/src/util.rs +++ b/gnuplot/src/util.rs @@ -121,9 +121,10 @@ macro_rules! multizip { }; } - macro_rules! replace_expr { - ($_t:tt $sub:expr) => {$sub}; + ($_t:tt $sub:expr) => { + $sub + }; } macro_rules! count_data { From bf72c4b849a430a542c5ba22b7a534dec4024198 Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Tue, 18 Feb 2025 10:14:55 +0000 Subject: [PATCH 06/34] Improve and simplify architecture for more consistency --- gnuplot/examples/color.rs | 51 +++++--------------- gnuplot/src/axes3d.rs | 1 - gnuplot/src/color.rs | 97 ++++++++++++++++++++++++++++++--------- gnuplot/src/options.rs | 3 +- gnuplot/src/util.rs | 45 +++++++++--------- 5 files changed, 109 insertions(+), 88 deletions(-) diff --git a/gnuplot/examples/color.rs b/gnuplot/examples/color.rs index 43b8fec4..cc02ced1 100644 --- a/gnuplot/examples/color.rs +++ b/gnuplot/examples/color.rs @@ -27,12 +27,12 @@ fn example(c: Common) { ax.set_legend(Graph(0.5), Graph(0.9), &[], &[]); let colors = [ Color("black"), - ColorOpt(ColorType::RGBColor("black")), + Color(ColorType::RGBColor("black")), Color("red"), - ColorOpt(ColorType::RGBColor("#ff0000")), // red using Hex coded RRGGBB - ColorOpt(ColorType::RGBColor("#ff8888")), // pink using Hex coded RRGGBB - ColorOpt(ColorType::RGBColor("#88ff0000")), // pink using Hex coded AARRGGBB - ColorOpt(ColorType::RGBColor("#ff0000")), // red using Hex coded RRGGBB + Color(ColorType::RGBColor("#ff0000")), // red using Hex coded RRGGBB + Color(ColorType::RGBColor("#ff8888")), // pink using Hex coded RRGGBB + Color(ColorType::RGBColor("#88ff0000")), // pink using Hex coded AARRGGBB + Color(ColorType::RGBColor("#ff0000")), // red using Hex coded RRGGBB ]; for (i, color) in colors.into_iter().enumerate() { @@ -55,11 +55,11 @@ fn example(c: Common) { // let d4 = extract_col(3); let d5 = extract_col(4); let d6 = extract_col(5); - let row_index:Vec<_> = (0..d1.len() as u32).collect(); + let row_index:Vec<_> = (1..=d1.len() as u8).collect(); // Demo/test of variable color in many different plot styles // derived from plot 1 in https://gnuplot.sourceforge.net/demo_6.0/varcolor.html - // this demonstrates usage of variableColor with indcies to use gnuplots dfefalt color styles, + // this demonstrates usage of VariableIndexColor with indcies to use gnuplots dfefalt color styles, // but make them align for multiple plot items on the same axis. // i.e. evertything at x = 1 uses the first gnuplot color, everything at x = 2 uses the second and so on. let mut fg = Figure::new(); @@ -73,18 +73,18 @@ fn example(c: Common) { // let ax.financebars(...) // points replaces circles (as circles not implemented) - ax.points(&d1, &d2, &[ColorOpt(VariableColor(row_index.clone())), PointSymbol('O'), PointSize(3.0)]); + ax.points(&d1, &d2, &[Color(VariableIndexColor(row_index.clone())), PointSymbol('O'), PointSize(3.0)]); ax.box_xy_error_delta( &d1, iter::repeat(8), d1.iter().map(by3), d1.iter().map(by4), - &[ColorOpt(VariableColor(row_index.clone()))]); + &[Color(VariableIndexColor(row_index.clone()))]); ax.boxes_set_width( &d1, d2.iter().map(|v| -v/2.0), iter::repeat(0.2), - &[ColorOpt(VariableColor(row_index.clone()))]); + &[Color(VariableIndexColor(row_index.clone()))]); // box_and_whisker is rust gnuplot's name for candlestick ax.box_and_whisker_set_width( &d1, @@ -93,41 +93,12 @@ fn example(c: Common) { d6, d5, iter::repeat(0.3), - &[ColorOpt(VariableColor(row_index.clone()))]); + &[Color(VariableIndexColor(row_index.clone()))]); // set boxwidth 0.2 abs // set bars front // rgbfudge(x) = x*51*32768 + (11-x)*51*128 + int(abs(5.5-x)*510/9.) c.show(&mut fg, "variable_color"); - // 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() { diff --git a/gnuplot/src/axes3d.rs b/gnuplot/src/axes3d.rs index 3707d551..c47567fc 100644 --- a/gnuplot/src/axes3d.rs +++ b/gnuplot/src/axes3d.rs @@ -8,7 +8,6 @@ use crate::options::*; use crate::util::OneWayOwned; use crate::writer::Writer; use std::borrow::Borrow; -use crate::ColorType; enum View { diff --git a/gnuplot/src/color.rs b/gnuplot/src/color.rs index 1ae88eb6..dcb01f8f 100644 --- a/gnuplot/src/color.rs +++ b/gnuplot/src/color.rs @@ -1,9 +1,15 @@ //! TODO +use std::fmt::Display; +use crate::util::OneWayOwned; pub use self::ColorType::*; -pub trait IntoColor: Into + Clone {} -impl + Clone> IntoColor for T {} +pub trait IntoColor: Into> + Clone {} +impl> + Clone> IntoColor for T {} + +pub type ColorIndex = u8; +pub type ColorComponent = u8; +pub type ColorInt = u32; /// Option type (for lines, axes, and text) that allows the various different gnuplot /// color formats. The gnuplot [colorspec reference](http://gnuplot.info/docs_6.0/loc3640.html) @@ -36,36 +42,77 @@ pub enum ColorType { /// As with `RGBColor`, an alpha value of 0 represents a fully opaque color; /// an alpha value of 255 (FF) represents full transparency. ARGBIntegerColor(u8,u8,u8,u8), - RGBVariableColor(Vec), + VariableRGBColor(Vec<(u8, u8, u8)>), + VariableARGBColor(Vec<(u8, u8, u8, u8)>), PaletteFracColor(f32), PaletteCBColor(f32), PaletteZColor, PaletteColorMap(T), - VariableColor(Vec), + /// Set the color of all elements of the plot to the `n`th color in the current gnuplot color cycle. + IndexColor(u8), + /// A color type that sets the color per element using a index `n` which represents the `n`th + /// color in the current gnuplot color scheme. In gnuplot this is the last element in the plot command, + /// in Rust gnuplot, the color type takes a vector of u32, where each index is treated the same as the + /// fixed `IndexColor`. + /// This is useful for setting bars/boxes etc to be + /// the same color from multiple plot commands. The `color.rs` example has examples of this usage + VariableIndexColor(Vec), + /// BackgroundColor, - IndexColor, + + /// Fixed black color Black, } -impl ColorType { +impl ColorType { /// Returns the gnuplot string that will produce the requested color pub fn command(&self) -> String { match self { - RGBColor(s) => format!(r#"rgb "{}""#, s), + RGBColor(s) => format!(r#"rgb "{}""#, s), RGBIntegerColor(r, g, b) => format!(r#"rgb {}"#, from_argb(0, *r, *g, *b)), ARGBIntegerColor(a, r, g, b) => format!(r#"rgb {}"#, from_argb(*a, *r, *g, *b)), - RGBVariableColor(_) => String::from("rgb variable"), + VariableRGBColor(_) => String::from("rgb variable"), + VariableARGBColor(_) => String::from("rgb variable"), PaletteFracColor(_) => todo!(), PaletteCBColor(_) => todo!(), PaletteZColor => todo!(), PaletteColorMap(_) => todo!(), - VariableColor(_) => String::from("variable"), + VariableIndexColor(_) => String::from("variable"), BackgroundColor => todo!(), - IndexColor => todo!(), + IndexColor(n) => format!("{}", n), Black => String::from("black"), } } + + pub fn data(&self) -> Vec { + match self { + RGBColor(_) => panic!("data() called on non-variable color type."), + RGBIntegerColor(_, _, _) => panic!("data() called on non-variable color type."), + ARGBIntegerColor(_, _, _, _) => panic!("data() called on non-variable color type."), + VariableRGBColor(items) => { + items.iter().map(|(r, g, b)| from_argb(0, *r, *g, *b)).collect() + }, + VariableARGBColor(items) => { + items.into_iter().map(|(a, r, g, b)| from_argb(*a, *r, *g, *b)).collect() + }, + PaletteFracColor(_) => panic!("data() called on non-variable color type."), + PaletteCBColor(_) => panic!("data() called on non-variable color type."), + PaletteZColor => panic!("data() called on non-variable color type."), + PaletteColorMap(_) => panic!("data() called on non-variable color type."), + IndexColor(_) => panic!("data() called on non-variable color type."), + VariableIndexColor(items) => items.into_iter().map(|v| *v as ColorInt).collect(), + BackgroundColor => panic!("data() called on non-variable color type."), + Black => panic!("data() called on non-variable color type."), + } + } + + pub fn is_variable(&self) -> bool { + match self { + VariableRGBColor(_) | VariableARGBColor(_) | VariableIndexColor(_) => true, + _ => false, + } + } } pub fn from_argb(a:u8, r:u8, g:u8, b:u8) -> u32{ @@ -97,37 +144,43 @@ impl <'l> Into> for &'l str { // } -impl ColorType{ - pub fn to_one_way_owned(&self) -> ColorType { +impl OneWayOwned for ColorType +{ + type Output = ColorType; + + fn to_one_way_owned(&self) -> ColorType { match self { RGBColor(s)=>RGBColor(s.to_string()), RGBIntegerColor(r, g,b) => RGBIntegerColor(*r, *g, *b), - RGBVariableColor(_) => todo!(), + VariableRGBColor(d) => VariableRGBColor(d.clone()), PaletteFracColor(_) => todo!(), PaletteCBColor(_) => todo!(), - PaletteZColor => todo!(), + PaletteZColor => PaletteZColor, PaletteColorMap(_) => todo!(), - VariableColor(d) => VariableColor(d.clone()), - BackgroundColor => todo!(), - IndexColor => todo!(), + VariableIndexColor(d) => VariableIndexColor(d.clone()), + BackgroundColor => BackgroundColor, + IndexColor(n) => IndexColor(*n), Black => Black, ARGBIntegerColor(a, r, g, b) => ARGBIntegerColor(*a, *r,*g, *b), + VariableARGBColor(d) => VariableARGBColor(d.clone()), } } } -impl ColorType { + +impl ColorType { pub fn to_ref(&self) -> ColorType<&str> { match self { - RGBColor(s)=>RGBColor(&s), + RGBColor(s)=>RGBColor(s), RGBIntegerColor(r,g,b) => RGBIntegerColor(*r, *g, *b), - RGBVariableColor(_) => todo!(), + VariableRGBColor(d) => VariableRGBColor(d.to_vec()), + VariableARGBColor(d) => VariableARGBColor(d.to_vec()), PaletteFracColor(_) => todo!(), PaletteCBColor(_) => todo!(), PaletteZColor => todo!(), PaletteColorMap(_) => todo!(), - VariableColor(_) => todo!(), + VariableIndexColor(d) => VariableIndexColor(d.to_vec()), BackgroundColor => todo!(), - IndexColor => todo!(), + IndexColor(n) => IndexColor(*n), Black => Black, ARGBIntegerColor(a, r, g, b) => ARGBIntegerColor(*a, *r,*g, *b), } diff --git a/gnuplot/src/options.rs b/gnuplot/src/options.rs index 751bf058..73c42c7f 100644 --- a/gnuplot/src/options.rs +++ b/gnuplot/src/options.rs @@ -21,6 +21,7 @@ pub use self::XAxis::*; pub use self::YAxis::*; use crate::util::OneWayOwned; use crate::ColorType; +use crate::IntoColor; /// An enumeration of plot options you can supply to plotting commands, governing /// things like line width, color and others @@ -77,7 +78,7 @@ pub enum PlotOption #[allow(non_snake_case)] /// TODO -pub fn Color<'l>(c:&'l str)->PlotOption<&'l str>{ +pub fn Color<'l, T: IntoColor<&'l str>>(c: T)->PlotOption<&'l str>{ ColorOpt(c.into()) } diff --git a/gnuplot/src/util.rs b/gnuplot/src/util.rs index 82d844c3..29e71a1e 100644 --- a/gnuplot/src/util.rs +++ b/gnuplot/src/util.rs @@ -51,35 +51,32 @@ macro_rules! first_opt_default // returns (data, num_rows, num_cols) macro_rules! generate_data { ($options: ident, $( $d:ident ),*) => { - {let mut c_data = None; + { + let mut c_data = None; - first_opt! {$options, - ColorOpt(ref color) => - { - match color + first_opt! {$options, + ColorOpt(ref color) => { - ColorType::VariableColor(values)| ColorType::RGBVariableColor(values) => { - c_data = Some(values); - }, - _ => (), + if color.is_variable() { + c_data = Some(color.data()); + } } } + if let Some(c_values) = c_data { + generate_data_inner!( + $( + $d, + )* + c_values + ) + } else { + generate_data_inner!( + $( + $d, + )* + ) + } } - if let Some(c_values) = c_data { - generate_data_inner!( - $( - $d, - )* - c_values - ) - } else{ - generate_data_inner!( - $( - $d, - )* - ) - } - } }; } From e07682ad83556d9428141eb8e2ae4283f033327b Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Sat, 22 Feb 2025 22:10:18 +0000 Subject: [PATCH 07/34] Add XY Error Bars plot type --- gnuplot/src/axes2d.rs | 39 ++++++++++++++++++++++++++++++++++++++ gnuplot/src/axes_common.rs | 4 +++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/gnuplot/src/axes2d.rs b/gnuplot/src/axes2d.rs index a6e49455..3e8e8fad 100644 --- a/gnuplot/src/axes2d.rs +++ b/gnuplot/src/axes2d.rs @@ -522,6 +522,45 @@ impl Axes2D self } + /// Plot a 2D scatter-plot with a point standing in for each data point. + /// Additionally, error bars are attached to each data point in the X and Y directions. + /// # Arguments + /// * `x` - x values + /// * `y` - y values + /// * `x_error` - Errors associated with the x value + /// * `options` - Array of PlotOption 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). + /// * `PointSymbol` - Sets symbol for each point + /// * `PointSize` - Sets the size of each point + /// * `Color` - Sets the color + pub fn xy_error_bars< + 'l, + Tx: DataType, + X: IntoIterator, + Ty: DataType, + Y: IntoIterator, + Txe: DataType, + XE: IntoIterator, + Tye: DataType, + YE: IntoIterator, + >( + &'l mut self, x: X, y: Y, x_error: XE, y_error: YE, options: &[PlotOption<&str>], + ) -> &'l mut Self + { + let (data, num_rows, num_cols) = generate_data!(options, x, y, x_error, y_error); + self.common.elems.push( + PlotElement::new_plot( + XYErrorBars, + data, + num_rows, + num_cols, + options, + ) + ); + self + } + + /// Plot a 2D scatter-plot with a point standing in for each data point and lines connecting each data point. /// Additionally, error bars are attached to each data point in the X direction. /// # Arguments diff --git a/gnuplot/src/axes_common.rs b/gnuplot/src/axes_common.rs index 791ad5be..b9323d9b 100644 --- a/gnuplot/src/axes_common.rs +++ b/gnuplot/src/axes_common.rs @@ -161,6 +161,7 @@ impl PlotElement YErrorLines => "yerrorlines", XErrorBars => "xerrorbars", YErrorBars => "yerrorbars", + XYErrorBars => "xyerrorbars", FillBetween => "filledcurves", Polygons => "polygons", Boxes => "boxes", @@ -578,6 +579,7 @@ pub enum PlotType XErrorLines, YErrorLines, XErrorBars, + XYErrorBars, YErrorBars, FillBetween, Polygons, @@ -607,7 +609,7 @@ impl PlotType { matches!( *self, - Points | LinesPoints | XErrorLines | YErrorLines | XErrorBars | YErrorBars + Points | LinesPoints | XErrorLines | YErrorLines | XErrorBars | YErrorBars | XYErrorBars ) } From e99e0550ee30fc9026130ae440dfd6e6cbbc1291 Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Sat, 22 Feb 2025 22:11:53 +0000 Subject: [PATCH 08/34] Convert BorderColor to new color style --- gnuplot/examples/inverse_api.rs | 2 +- gnuplot/src/axes_common.rs | 5 ++--- gnuplot/src/options.rs | 11 +++++++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/gnuplot/examples/inverse_api.rs b/gnuplot/examples/inverse_api.rs index 932a4d05..e857bef9 100644 --- a/gnuplot/examples/inverse_api.rs +++ b/gnuplot/examples/inverse_api.rs @@ -33,7 +33,7 @@ impl PlotElement for Lines Caption(v) => Caption(&v), LineWidth(v) => LineWidth(*v), ColorOpt(v) => ColorOpt(v.to_ref()), - BorderColor(v) => BorderColor(&v), + BorderColorOpt(v) => BorderColorOpt(v.to_ref()), LineStyle(v) => LineStyle(*v), FillAlpha(v) => FillAlpha(*v), FillRegion(v) => FillRegion(*v), diff --git a/gnuplot/src/axes_common.rs b/gnuplot/src/axes_common.rs index b9323d9b..9eadcb33 100644 --- a/gnuplot/src/axes_common.rs +++ b/gnuplot/src/axes_common.rs @@ -219,11 +219,10 @@ impl PlotElement if self.plot_type.is_line() { - writer.write_str(" border"); first_opt! {self.options, - BorderColor(ref s) => + BorderColorOpt(ref s) => { - write!(writer, r#" rgb "{}""#, s); + write!(writer, " border {}", s.command()); } } } diff --git a/gnuplot/src/options.rs b/gnuplot/src/options.rs index 73c42c7f..6f91f006 100644 --- a/gnuplot/src/options.rs +++ b/gnuplot/src/options.rs @@ -56,7 +56,7 @@ pub enum PlotOption ColorOpt(ColorType), /// Sets the color of the border of a filled plot (if it has one). The passed string can be a color name /// (e.g. "black" works), or an HTML color specifier (e.g. "#FFFFFF" is white). - BorderColor(T), + BorderColorOpt(ColorType), /// Sets the style of the line. Note that not all gnuplot terminals support dashed lines. See DashType for the available styles. LineStyle(DashType), /// Sets the transparency of a filled plot. `0.0` - fully transparent, `1.0` - fully opaque. Cannot be used with `FillPattern`. @@ -82,6 +82,13 @@ pub fn Color<'l, T: IntoColor<&'l str>>(c: T)->PlotOption<&'l str>{ ColorOpt(c.into()) } +#[allow(non_snake_case)] +/// TODO +pub fn BorderColor<'l, T: IntoColor<&'l str>>(c: T)->PlotOption<&'l str>{ + BorderColorOpt(c.into()) +} + + impl<'l> OneWayOwned for PlotOption<&'l str> { type Output = PlotOption; @@ -94,7 +101,7 @@ impl<'l> OneWayOwned for PlotOption<&'l str> Caption(v) => Caption(v.into()), LineWidth(v) => LineWidth(v), ColorOpt(ref v) => ColorOpt(v.to_one_way_owned()), - BorderColor(v) => BorderColor(v.into()), + BorderColorOpt(ref v) => BorderColorOpt(v.to_one_way_owned()), LineStyle(v) => LineStyle(v), FillAlpha(v) => FillAlpha(v), FillRegion(v) => FillRegion(v), From 75f6e970c0e10da8b82f1b1600e699f8260e036d Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Sat, 22 Feb 2025 22:14:06 +0000 Subject: [PATCH 09/34] Improve internal color API, and add more Into options --- gnuplot/src/color.rs | 345 ++++++++++++++++++++++++++----------------- 1 file changed, 211 insertions(+), 134 deletions(-) diff --git a/gnuplot/src/color.rs b/gnuplot/src/color.rs index dcb01f8f..af5b74c1 100644 --- a/gnuplot/src/color.rs +++ b/gnuplot/src/color.rs @@ -1,8 +1,8 @@ //! TODO -use std::fmt::Display; -use crate::util::OneWayOwned; pub use self::ColorType::*; +use crate::util::OneWayOwned; +use std::fmt::Display; pub trait IntoColor: Into> + Clone {} impl> + Clone> IntoColor for T {} @@ -10,6 +10,13 @@ impl> + Clone> IntoColor for T {} pub type ColorIndex = u8; pub type ColorComponent = u8; pub type ColorInt = u32; +pub type RGBInts = (ColorComponent, ColorComponent, ColorComponent); +pub type ARGBInts = ( + ColorComponent, + ColorComponent, + ColorComponent, + ColorComponent, +); /// Option type (for lines, axes, and text) that allows the various different gnuplot /// color formats. The gnuplot [colorspec reference](http://gnuplot.info/docs_6.0/loc3640.html) @@ -24,165 +31,235 @@ pub type ColorInt = u32; /// [Examples folder](https://github.com/SiegeLord/RustGnuplot/tree/master/gnuplot/examples) on Github #[derive(Debug, Clone, PartialEq, PartialOrd)] pub enum ColorType { - /// string (`&str` or `String`, but usually created with `&str`) in one of the following gnuplot-supported formats - /// - colorname --- e.g. "blue" [See the gnuplot - /// [list of colornames](http://gnuplot.info/docs_6.0/loc11229.html)] - /// - 0xRRGGBB --- string containing hexadecimal constant - /// - 0xAARRGGBB --- string containing hexadecimal constant - /// - #RRGGBB --- string containing hexadecimal in x11 format - /// - #AARRGGBB --- string containing hexadecimal in x11 format - /// - /// "#AARRGGBB" represents an RGB color with an alpha channel (transparency) value in the high bits. - /// An alpha value of 0 represents a fully opaque color; i.e., "#00RRGGBB" is the same as "#RRGGBB". - /// An alpha value of 255 (FF) represents full transparency. + /// string (`&str` or `String`, but usually created with `&str`) in one of the following gnuplot-supported formats + /// - colorname --- e.g. "blue" [See the gnuplot + /// [list of colornames](http://gnuplot.info/docs_6.0/loc11229.html)] + /// - 0xRRGGBB --- string containing hexadecimal constant + /// - 0xAARRGGBB --- string containing hexadecimal constant + /// - #RRGGBB --- string containing hexadecimal in x11 format + /// - #AARRGGBB --- string containing hexadecimal in x11 format + /// + /// "#AARRGGBB" represents an RGB color with an alpha channel (transparency) value in the high bits. + /// An alpha value of 0 represents a fully opaque color; i.e., "#00RRGGBB" is the same as "#RRGGBB". + /// An alpha value of 255 (FF) represents full transparency. RGBColor(T), - /// tuple of u8 representing red, green and blue values as 0-255 - RGBIntegerColor(u8, u8, u8), - /// tuple of u8 representing alpha, red, green and blue values as 0-255. - /// As with `RGBColor`, an alpha value of 0 represents a fully opaque color; - /// an alpha value of 255 (FF) represents full transparency. - ARGBIntegerColor(u8,u8,u8,u8), - VariableRGBColor(Vec<(u8, u8, u8)>), - VariableARGBColor(Vec<(u8, u8, u8, u8)>), - PaletteFracColor(f32), - PaletteCBColor(f32), - PaletteZColor, - PaletteColorMap(T), - /// Set the color of all elements of the plot to the `n`th color in the current gnuplot color cycle. - IndexColor(u8), - /// A color type that sets the color per element using a index `n` which represents the `n`th - /// color in the current gnuplot color scheme. In gnuplot this is the last element in the plot command, - /// in Rust gnuplot, the color type takes a vector of u32, where each index is treated the same as the - /// fixed `IndexColor`. - /// This is useful for setting bars/boxes etc to be - /// the same color from multiple plot commands. The `color.rs` example has examples of this usage - VariableIndexColor(Vec), - /// - BackgroundColor, - - /// Fixed black color - Black, -} - -impl ColorType { - /// Returns the gnuplot string that will produce the requested color + /// tuple of u8 representing red, green and blue values as 0-255 + RGBIntegerColor(ColorComponent, ColorComponent, ColorComponent), + /// tuple of u8 representing alpha, red, green and blue values as 0-255. + /// As with `RGBColor`, an alpha value of 0 represents a fully opaque color; + /// an alpha value of 255 (FF) represents full transparency. + ARGBIntegerColor( + ColorComponent, + ColorComponent, + ColorComponent, + ColorComponent, + ), + VariableRGBColor(Vec), + VariableARGBColor(Vec), + PaletteFracColor(f32), + PaletteCBColor(f32), + PaletteZColor, + PaletteColorMap(T), + /// Set the color of all elements of the plot to the `n`th color in the current gnuplot color cycle. + IndexColor(ColorIndex), + /// A color type that sets the color per element using a index `n` which represents the `n`th + /// color in the current gnuplot color scheme. In gnuplot this is the last element in the plot command, + /// in Rust gnuplot, the color type takes a vector of u8, where each index is treated the same as the + /// fixed `IndexColor`. + /// This is useful for setting bars/boxes etc to be + /// the same color from multiple plot commands. The `color.rs` example has examples of this usage + VariableIndexColor(Vec), + /// + BackgroundColor, + /// Fixed black color + Black, +} + +impl ColorType { + /// Returns the gnuplot string that will produce the requested color pub fn command(&self) -> String { match self { - RGBColor(s) => format!(r#"rgb "{}""#, s), - RGBIntegerColor(r, g, b) => format!(r#"rgb {}"#, from_argb(0, *r, *g, *b)), - ARGBIntegerColor(a, r, g, b) => format!(r#"rgb {}"#, from_argb(*a, *r, *g, *b)), - VariableRGBColor(_) => String::from("rgb variable"), - VariableARGBColor(_) => String::from("rgb variable"), - PaletteFracColor(_) => todo!(), - PaletteCBColor(_) => todo!(), - PaletteZColor => todo!(), - PaletteColorMap(_) => todo!(), - VariableIndexColor(_) => String::from("variable"), - BackgroundColor => todo!(), - IndexColor(n) => format!("{}", n), - Black => String::from("black"), + RGBColor(s) => format!(r#"rgb "{}""#, s), + RGBIntegerColor(r, g, b) => format!(r#"rgb {}"#, from_argb(0, *r, *g, *b)), + ARGBIntegerColor(a, r, g, b) => format!(r#"rgb {}"#, from_argb(*a, *r, *g, *b)), + VariableRGBColor(_) => String::from("rgb variable"), + VariableARGBColor(_) => String::from("rgb variable"), + PaletteFracColor(_) => todo!(), + PaletteCBColor(_) => todo!(), + PaletteZColor => todo!(), + PaletteColorMap(_) => todo!(), + VariableIndexColor(_) => String::from("variable"), + BackgroundColor => todo!(), + IndexColor(n) => format!("{}", n), + Black => String::from("black"), + } + } + + pub fn data(&self) -> Vec { + match self { + RGBColor(_) => panic!("data() called on non-variable color type."), + RGBIntegerColor(_, _, _) => panic!("data() called on non-variable color type."), + ARGBIntegerColor(_, _, _, _) => panic!("data() called on non-variable color type."), + VariableRGBColor(items) => items + .iter() + .map(|(r, g, b)| from_argb(0, *r, *g, *b)) + .collect(), + VariableARGBColor(items) => items + .into_iter() + .map(|(a, r, g, b)| from_argb(*a, *r, *g, *b)) + .collect(), + PaletteFracColor(_) => panic!("data() called on non-variable color type."), + PaletteCBColor(_) => panic!("data() called on non-variable color type."), + PaletteZColor => panic!("data() called on non-variable color type."), + PaletteColorMap(_) => panic!("data() called on non-variable color type."), + IndexColor(_) => panic!("data() called on non-variable color type."), + VariableIndexColor(items) => items.into_iter().map(|v| *v as ColorInt).collect(), + BackgroundColor => panic!("data() called on non-variable color type."), + Black => panic!("data() called on non-variable color type."), + } + } + pub fn is_variable(&self) -> bool { + match self { + VariableRGBColor(_) | VariableARGBColor(_) | VariableIndexColor(_) => true, + _ => false, } } +} + +fn from_argb( + a: ColorComponent, r: ColorComponent, g: ColorComponent, b: ColorComponent, +) -> ColorInt { + (a as ColorInt) << 24 + (r as ColorInt) << 16 + (g as ColorInt) << 8 + (b as ColorInt) +} + +fn float_color_to_int(v: f64) -> u8 { + if v < 0.0 || v > 1.0 { + panic!( + "Float value must be greater than zero and less than one. Actual value: {}", + v + ); + } + ((v * 255.0).round()) as u8 +} + +fn from_rgb_floats(r: f64, g: f64, b: f64) -> RGBInts { + ( + float_color_to_int(r), + float_color_to_int(g), + float_color_to_int(b), + ) +} - pub fn data(&self) -> Vec { - match self { - RGBColor(_) => panic!("data() called on non-variable color type."), - RGBIntegerColor(_, _, _) => panic!("data() called on non-variable color type."), - ARGBIntegerColor(_, _, _, _) => panic!("data() called on non-variable color type."), - VariableRGBColor(items) => { - items.iter().map(|(r, g, b)| from_argb(0, *r, *g, *b)).collect() - }, - VariableARGBColor(items) => { - items.into_iter().map(|(a, r, g, b)| from_argb(*a, *r, *g, *b)).collect() - }, - PaletteFracColor(_) => panic!("data() called on non-variable color type."), - PaletteCBColor(_) => panic!("data() called on non-variable color type."), - PaletteZColor => panic!("data() called on non-variable color type."), - PaletteColorMap(_) => panic!("data() called on non-variable color type."), - IndexColor(_) => panic!("data() called on non-variable color type."), - VariableIndexColor(items) => items.into_iter().map(|v| *v as ColorInt).collect(), - BackgroundColor => panic!("data() called on non-variable color type."), - Black => panic!("data() called on non-variable color type."), - } - } - - pub fn is_variable(&self) -> bool { - match self { - VariableRGBColor(_) | VariableARGBColor(_) | VariableIndexColor(_) => true, - _ => false, - } - } -} - -pub fn from_argb(a:u8, r:u8, g:u8, b:u8) -> u32{ - (a as u32) << 24 + (r as u32) << 16 + (g as u32) << 8 + (b as u32) -} - -impl <'l> Into> for &'l str { +fn from_argb_floats(a: f64, r: f64, g: f64, b: f64) -> ARGBInts { + ( + float_color_to_int(a), + float_color_to_int(r), + float_color_to_int(g), + float_color_to_int(b), + ) +} + +impl<'l> Into> for &'l str { fn into(self) -> ColorType { ColorType::RGBColor(String::from(self)) } } -impl <'l> Into> for String { +impl<'l> Into> for String { fn into(self) -> ColorType { ColorType::RGBColor(self) } } -impl <'l> Into> for &'l str { +impl<'l> Into> for &'l str { fn into(self) -> ColorType<&'l str> { ColorType::RGBColor(self) } } -// impl <'l> Into> for String { -// fn into(self) -> ColorType<&'l str> { -// ColorType::RGBColor(&self) -// } -// } +impl Into> for ARGBInts { + fn into(self) -> ColorType { + ColorType::ARGBIntegerColor(self.0, self.1, self.2, self.3) + } +} + +impl Into> for RGBInts { + fn into(self) -> ColorType { + ColorType::RGBIntegerColor(self.0, self.1, self.2) + } +} + +impl Into> for (f64, f64, f64) { + fn into(self) -> ColorType { + let ints = from_rgb_floats(self.0, self.1, self.2); + ColorType::RGBIntegerColor(ints.0, ints.1, ints.2) + } +} + +impl Into> for (f64, f64, f64, f64) { + fn into(self) -> ColorType { + let ints = from_argb_floats(self.0, self.1, self.2, self.3); + ColorType::ARGBIntegerColor(ints.0, ints.1, ints.2, ints.3) + } +} + +impl Into> for Vec { + fn into(self) -> ColorType { + ColorType::VariableRGBColor(self) + } +} + +impl Into> for Vec { + fn into(self) -> ColorType { + ColorType::VariableARGBColor(self) + } +} +impl Into> for Vec { + fn into(self) -> ColorType { + ColorType::VariableIndexColor(self) + } +} -impl OneWayOwned for ColorType -{ +impl OneWayOwned for ColorType { type Output = ColorType; - fn to_one_way_owned(&self) -> ColorType { - match self { - RGBColor(s)=>RGBColor(s.to_string()), - RGBIntegerColor(r, g,b) => RGBIntegerColor(*r, *g, *b), - VariableRGBColor(d) => VariableRGBColor(d.clone()), - PaletteFracColor(_) => todo!(), - PaletteCBColor(_) => todo!(), - PaletteZColor => PaletteZColor, - PaletteColorMap(_) => todo!(), - VariableIndexColor(d) => VariableIndexColor(d.clone()), - BackgroundColor => BackgroundColor, - IndexColor(n) => IndexColor(*n), - Black => Black, - ARGBIntegerColor(a, r, g, b) => ARGBIntegerColor(*a, *r,*g, *b), - VariableARGBColor(d) => VariableARGBColor(d.clone()), - } - } + fn to_one_way_owned(&self) -> ColorType { + match self { + RGBColor(s) => RGBColor(s.to_string()), + RGBIntegerColor(r, g, b) => RGBIntegerColor(*r, *g, *b), + VariableRGBColor(d) => VariableRGBColor(d.clone()), + PaletteFracColor(_) => todo!(), + PaletteCBColor(_) => todo!(), + PaletteZColor => PaletteZColor, + PaletteColorMap(_) => todo!(), + VariableIndexColor(d) => VariableIndexColor(d.clone()), + BackgroundColor => BackgroundColor, + IndexColor(n) => IndexColor(*n), + Black => Black, + ARGBIntegerColor(a, r, g, b) => ARGBIntegerColor(*a, *r, *g, *b), + VariableARGBColor(d) => VariableARGBColor(d.clone()), + } + } } impl ColorType { - pub fn to_ref(&self) -> ColorType<&str> { - match self { - RGBColor(s)=>RGBColor(s), - RGBIntegerColor(r,g,b) => RGBIntegerColor(*r, *g, *b), - VariableRGBColor(d) => VariableRGBColor(d.to_vec()), - VariableARGBColor(d) => VariableARGBColor(d.to_vec()), - PaletteFracColor(_) => todo!(), - PaletteCBColor(_) => todo!(), - PaletteZColor => todo!(), - PaletteColorMap(_) => todo!(), - VariableIndexColor(d) => VariableIndexColor(d.to_vec()), - BackgroundColor => todo!(), - IndexColor(n) => IndexColor(*n), - Black => Black, - ARGBIntegerColor(a, r, g, b) => ARGBIntegerColor(*a, *r,*g, *b), - } - } + pub fn to_ref(&self) -> ColorType<&str> { + match self { + RGBColor(s) => RGBColor(s), + RGBIntegerColor(r, g, b) => RGBIntegerColor(*r, *g, *b), + VariableRGBColor(d) => VariableRGBColor(d.to_vec()), + VariableARGBColor(d) => VariableARGBColor(d.to_vec()), + PaletteFracColor(_) => todo!(), + PaletteCBColor(_) => todo!(), + PaletteZColor => todo!(), + PaletteColorMap(_) => todo!(), + VariableIndexColor(d) => VariableIndexColor(d.to_vec()), + BackgroundColor => todo!(), + IndexColor(n) => IndexColor(*n), + Black => Black, + ARGBIntegerColor(a, r, g, b) => ARGBIntegerColor(*a, *r, *g, *b), + } + } } From 889e55def467ff790492a441caf9198cc0fdec69 Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Sat, 22 Feb 2025 22:37:20 +0000 Subject: [PATCH 10/34] Add box error bars plots --- gnuplot/src/axes2d.rs | 177 +++++++++++++++++++++++++++++++++++++ gnuplot/src/axes_common.rs | 6 +- 2 files changed, 181 insertions(+), 2 deletions(-) diff --git a/gnuplot/src/axes2d.rs b/gnuplot/src/axes2d.rs index 3e8e8fad..559dde85 100644 --- a/gnuplot/src/axes2d.rs +++ b/gnuplot/src/axes2d.rs @@ -2,6 +2,8 @@ // // All rights reserved. Distributed under LGPL 3.0. For full terms see the file LICENSE. +use std::iter; + use crate::axes_common::*; use crate::coordinates::*; use crate::datatype::*; @@ -780,6 +782,181 @@ impl Axes2D self } + /// Plot a 2D box-plot with error bars using boxes of automatic width. + /// Box widths are set so that there are no gaps between successive boxes (i.e. each box may have a different width). + /// Boxes start at the x-axis and go towards the y value of the datapoint. + /// Each box has an error bar from y - y_delta to y + y_delta. + /// # Arguments + /// * `x` - x values (center of the box) + /// * `y` - y values + /// * `y_delta` - errors in y (error bars are plotted from y - y_delta to y + y_delta) + /// * `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_error_delta< + 'l, + Tx: DataType, + X: IntoIterator, + Ty: DataType, + Y: IntoIterator, + Tye: DataType, + YE: IntoIterator, + >( + &'l mut self, x: X, y: Y, y_error: YE, options: &[PlotOption<&str>], + ) -> &'l mut Self + { + let (data, num_rows, num_cols) = generate_data!(options, x, y, y_error); + self.common.elems.push( + PlotElement::new_plot( + BoxErrorBars, + data, + num_rows, + num_cols, + options, + ) + ); + self + } + + /// Plot a 2D box-plot with error bars using boxes of specified width. + /// Box widths are set so that there are no gaps between successive boxes (i.e. each box may have a different width). + /// Boxes start at the x-axis and go towards the y value of the datapoint. + /// Each box has an error bar from y - y_delta to y + y_delta. + /// # Arguments + /// * `x` - x values (center of the box) + /// * `y` - y values + /// * `y_delta` - errors in y (error bars are plotted from y - y_delta to y + y_delta) + /// * `x_delta` - errors in x (interpreted as box width) + /// * `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_error_delta_set_width< + 'l, + Tx: DataType, + X: IntoIterator, + Ty: DataType, + Y: IntoIterator, + Tye: DataType, + YE: IntoIterator, + Tw: DataType, + W: IntoIterator, + >( + &'l mut self, x: X, y: Y, y_error: YE, x_delta: W, options: &[PlotOption<&str>], + ) -> &'l mut Self + { + let (data, num_rows, num_cols) = generate_data!(options, x, y, y_error, x_delta); + self.common.elems.push( + PlotElement::new_plot( + BoxErrorBars, + data, + num_rows, + num_cols, + options, + ) + ); + self + } + + /// Plot a 2D box-plot with error bars using boxes of automatic width. + /// Box widths are set so that there are no gaps between successive boxes (i.e. each box may have a different width). + /// Boxes start at the x-axis and go towards the y value of the datapoint. + /// Each box has an error bar from y - y_low to y + y_high. + /// # Arguments + /// * `x` - x values (center of the box) + /// * `y` - y values + /// * `y_low` - minimum of error bar + /// * `y_high` - maximum of error bar + /// * `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_error_low_high< + 'l, + Tx: DataType, + X: IntoIterator, + Ty: DataType, + Y: IntoIterator, + Tyl: DataType, + YL: IntoIterator, + Tyh: DataType, + YH: IntoIterator, + >( + &'l mut self, x: X, y: Y, y_low: YL, y_high: YH, options: &[PlotOption<&str>], + ) -> &'l mut Self + { + // The way to get boxerrorbars to interpret low and high y values is to use a dummy negative value for + // xdelta (box width). If you supply four values rather than five, the fourth is interpreted as width. + let dummy_width = iter::repeat(-1.0); + let (data, num_rows, num_cols) = generate_data!(options, x, y, y_low, y_high, dummy_width); + self.common.elems.push( + PlotElement::new_plot( + BoxErrorBars, + data, + num_rows, + num_cols, + options, + ) + ); + self + } + + /// Plot a 2D box-plot with error bars using boxes of specified width. + /// Box widths are set so that there are no gaps between successive boxes (i.e. each box may have a different width). + /// Boxes start at the x-axis and go towards the y value of the datapoint. + /// Each box has an error bar from y - y_low to y + y_high. + /// # Arguments + /// * `x` - x values (center of the box) + /// * `y` - y values + /// * `y_low` - minimum of error bar + /// * `y_high` - maximum of error bar + /// * `x_delta` - errors in x (interpreted as box width) + /// * `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_error_low_high_set_width< + 'l, + Tx: DataType, + X: IntoIterator, + Ty: DataType, + Y: IntoIterator, + Tyl: DataType, + YL: IntoIterator, + Tyh: DataType, + YH: IntoIterator, + Tw: DataType, + W: IntoIterator, + >( + &'l mut self, x: X, y: Y, y_low: YL, y_high: YH, x_delta: W, options: &[PlotOption<&str>], + ) -> &'l mut Self + { + let (data, num_rows, num_cols) = generate_data!(options, x, y, y_low, y_high, x_delta); + self.common.elems.push( + PlotElement::new_plot( + BoxErrorBars, + data, + num_rows, + num_cols, + options, + ) + ); + self + } + /// Plot a 2D box-and-whisker plot using boxes of automatic width. /// /// # Arguments diff --git a/gnuplot/src/axes_common.rs b/gnuplot/src/axes_common.rs index 9eadcb33..c85de44a 100644 --- a/gnuplot/src/axes_common.rs +++ b/gnuplot/src/axes_common.rs @@ -167,6 +167,7 @@ impl PlotElement Boxes => "boxes", BoxAndWhisker => "candlestick", BoxXYError => "boxxyerror", + BoxErrorBars => "boxerrorbars", Pm3D => "pm3d", Image => "image", }; @@ -583,6 +584,7 @@ pub enum PlotType FillBetween, Polygons, Boxes, + BoxErrorBars, BoxAndWhisker, BoxXYError, Pm3D, @@ -600,7 +602,7 @@ impl PlotType | XErrorLines | Boxes | YErrorLines | BoxAndWhisker - | BoxXYError | Polygons + | BoxXYError | BoxErrorBars | Polygons ) } @@ -616,7 +618,7 @@ impl PlotType { matches!( *self, - Boxes | FillBetween | BoxAndWhisker | BoxXYError | Polygons + Boxes | FillBetween | BoxAndWhisker | BoxXYError | BoxErrorBars | Polygons ) } } From ff99e959fa54a69edafe4c44367be3668da29a5e Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Sun, 23 Feb 2025 13:07:45 +0000 Subject: [PATCH 11/34] Finish first color example and put in a loop --- gnuplot/examples/color.rs | 117 +++++++++++++++++++++++--------------- 1 file changed, 70 insertions(+), 47 deletions(-) diff --git a/gnuplot/examples/color.rs b/gnuplot/examples/color.rs index cc02ced1..40f79a19 100644 --- a/gnuplot/examples/color.rs +++ b/gnuplot/examples/color.rs @@ -29,10 +29,10 @@ fn example(c: Common) { Color("black"), Color(ColorType::RGBColor("black")), Color("red"), - Color(ColorType::RGBColor("#ff0000")), // red using Hex coded RRGGBB - Color(ColorType::RGBColor("#ff8888")), // pink using Hex coded RRGGBB + Color(ColorType::RGBColor("#ff0000")), // red using Hex coded RRGGBB + Color(ColorType::RGBColor("#ff8888")), // pink using Hex coded RRGGBB Color(ColorType::RGBColor("#88ff0000")), // pink using Hex coded AARRGGBB - Color(ColorType::RGBColor("#ff0000")), // red using Hex coded RRGGBB + Color(ColorType::RGBColor("#ff0000")), // red using Hex coded RRGGBB ]; for (i, color) in colors.into_iter().enumerate() { @@ -45,60 +45,83 @@ fn example(c: Common) { c.show(&mut fg, "rgb_color"); - - let data:Vec> = CANDLESTICKS_STR.split("\n").map(|line| line.split("\t").map(|v| v.trim().parse::().unwrap()).collect()).collect(); + let data: Vec> = CANDLESTICKS_STR + .split("\n") + .map(|line| { + line.split("\t") + .map(|v| v.trim().parse::().unwrap()) + .collect() + }) + .collect(); let extract_col = |i| data.iter().map(|l| l[i]).collect::>(); let d1 = extract_col(0); let d2 = extract_col(1); - let d3 = extract_col(2); + // let d3 = extract_col(2); // let d4 = extract_col(3); let d5 = extract_col(4); let d6 = extract_col(5); - let row_index:Vec<_> = (1..=d1.len() as u8).collect(); + let row_index: Vec<_> = (1..=d1.len() as u8).collect(); + let by3 = |x| (((x % 3.0) + 1.0) / 6.0); + let by4 = |x| (((x % 4.0) + 1.0) / 7.0); // Demo/test of variable color in many different plot styles - // derived from plot 1 in https://gnuplot.sourceforge.net/demo_6.0/varcolor.html - // this demonstrates usage of VariableIndexColor with indcies to use gnuplots dfefalt color styles, - // but make them align for multiple plot items on the same axis. - // i.e. evertything at x = 1 uses the first gnuplot color, everything at x = 2 uses the second and so on. - let mut fg = Figure::new(); - let ax = fg.axes2d(); - ax.set_title("variable color points, candlesticks, boxes, and boxxyerror", &[]); - ax.set_y_range(Fix(-4.0), Fix(10.0)); - ax.set_x_range(Fix(0.0), Fix(11.0)); - - let by3 = |x| (((x%3.0)+1.0)/6.0); - let by4 = |x| (((x%4.0)+1.0)/7.0); - - // let ax.financebars(...) - // points replaces circles (as circles not implemented) - ax.points(&d1, &d2, &[Color(VariableIndexColor(row_index.clone())), PointSymbol('O'), PointSize(3.0)]); - ax.box_xy_error_delta( - &d1, - iter::repeat(8), - d1.iter().map(by3), - d1.iter().map(by4), - &[Color(VariableIndexColor(row_index.clone()))]); - ax.boxes_set_width( - &d1, - d2.iter().map(|v| -v/2.0), - iter::repeat(0.2), - &[Color(VariableIndexColor(row_index.clone()))]); - // box_and_whisker is rust gnuplot's name for candlestick - ax.box_and_whisker_set_width( - &d1, - d3, - d2, - d6, - d5, - iter::repeat(0.3), - &[Color(VariableIndexColor(row_index.clone()))]); - // set boxwidth 0.2 abs - // set bars front - // rgbfudge(x) = x*51*32768 + (11-x)*51*128 + int(abs(5.5-x)*510/9.) - c.show(&mut fg, "variable_color"); + // derived from https://gnuplot.sourceforge.net/demo_6.0/varcolor.html + // + // The loop is run four times with different color sets: each one sets all the elements of a given + // plot to a different color, while making sure the colors align by x position: i.e. everything at x = 1 + // uses the first color, everything at x = 2 uses the second and so on. + // + // + // The first color loop demonstrates usage of VariableIndexColor with indices to use gnuplot's default color styles, + // but make them align for multiple plot items on the same axis. This is implicity constructed from a Vec using + // the `Color` function but could equivalently be created explicitly using `ColorType::VariableIndexColor(row_index.clone())` + // + // The second color loop ... + for color in [Color(row_index.clone())] { + let mut fg = Figure::new(); + let ax = fg.axes2d(); + ax.set_title( + "variable color boxerror, xyerrorbars, impulses, vectors, and labels", + &[], + ); + ax.set_y_range(Fix(-4.0), Fix(11.5)); + // unset colorbox + ax.box_error_low_high_set_width( + &d1, + &d5, + &d2, + &d6, + iter::repeat(0.2), + &[ + color.clone(), + FillAlpha(0.5), + BorderColor(RGBColor("black")), + ], + ); + ax.points(&d1, iter::repeat(1), &[color.clone(), PointSymbol('D')]); + ax.xy_error_bars( + &d1, + iter::repeat(8), + d1.iter().map(by3), + d1.iter().map(by4), + &[color.clone()], + ); + ax.points( + &d1, + d2.iter().map(|v| -v / 2.0), + &[color.clone(), PointSymbol('O'), PointSize(3.0)], + ); + ax.box_xy_error_delta( + &d1, + iter::repeat(10), + d1.iter().map(by3), + d1.iter().map(by4), + &[color.clone()], + ); + c.show(&mut fg, "variable_color"); + } } fn main() { From c5b0046e3a7f8735c5c7090af49df751b7bd1af0 Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Sun, 23 Feb 2025 13:26:24 +0000 Subject: [PATCH 12/34] Add VariablePaletteColor with example --- gnuplot/examples/color.rs | 14 +++++++++++--- gnuplot/src/color.rs | 23 +++++++++++++---------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/gnuplot/examples/color.rs b/gnuplot/examples/color.rs index 40f79a19..fddb9b61 100644 --- a/gnuplot/examples/color.rs +++ b/gnuplot/examples/color.rs @@ -77,12 +77,20 @@ fn example(c: Common) { // but make them align for multiple plot items on the same axis. This is implicity constructed from a Vec using // the `Color` function but could equivalently be created explicitly using `ColorType::VariableIndexColor(row_index.clone())` // - // The second color loop ... - for color in [Color(row_index.clone())] { + // The second color loop use a VariablePaletteColor: this selects the color based on the current color palette and the + // input value for each data point. The palette is scaled to the maximum value in the vector of `f64`s passed + // to the VariablePaletteColor + for (color, label) in [ + (Color(row_index.clone()), "VariableIndexColor"), + ( + ColorOpt(VariablePaletteColor(row_index.iter().map(|v| *v as f64).collect())), + "VariablePaletteColor", + ), + ] { let mut fg = Figure::new(); let ax = fg.axes2d(); ax.set_title( - "variable color boxerror, xyerrorbars, impulses, vectors, and labels", + &format!("variable color boxerror, points, xyerrorbars, and boxxyerror.\nColor used is a {label}"), &[], ); ax.set_y_range(Fix(-4.0), Fix(11.5)); diff --git a/gnuplot/src/color.rs b/gnuplot/src/color.rs index af5b74c1..dfdff47a 100644 --- a/gnuplot/src/color.rs +++ b/gnuplot/src/color.rs @@ -58,7 +58,7 @@ pub enum ColorType { VariableARGBColor(Vec), PaletteFracColor(f32), PaletteCBColor(f32), - PaletteZColor, + VariablePaletteColor(Vec), PaletteColorMap(T), /// Set the color of all elements of the plot to the `n`th color in the current gnuplot color cycle. IndexColor(ColorIndex), @@ -86,7 +86,7 @@ impl ColorType { VariableARGBColor(_) => String::from("rgb variable"), PaletteFracColor(_) => todo!(), PaletteCBColor(_) => todo!(), - PaletteZColor => todo!(), + VariablePaletteColor(_) => String::from("palette z"), PaletteColorMap(_) => todo!(), VariableIndexColor(_) => String::from("variable"), BackgroundColor => todo!(), @@ -95,25 +95,25 @@ impl ColorType { } } - pub fn data(&self) -> Vec { + pub fn data(&self) -> Vec { match self { RGBColor(_) => panic!("data() called on non-variable color type."), RGBIntegerColor(_, _, _) => panic!("data() called on non-variable color type."), ARGBIntegerColor(_, _, _, _) => panic!("data() called on non-variable color type."), VariableRGBColor(items) => items .iter() - .map(|(r, g, b)| from_argb(0, *r, *g, *b)) + .map(|(r, g, b)| from_argb(0, *r, *g, *b) as f64) .collect(), VariableARGBColor(items) => items .into_iter() - .map(|(a, r, g, b)| from_argb(*a, *r, *g, *b)) + .map(|(a, r, g, b)| from_argb(*a, *r, *g, *b) as f64) .collect(), PaletteFracColor(_) => panic!("data() called on non-variable color type."), PaletteCBColor(_) => panic!("data() called on non-variable color type."), - PaletteZColor => panic!("data() called on non-variable color type."), + VariablePaletteColor(items) => items.clone(), PaletteColorMap(_) => panic!("data() called on non-variable color type."), IndexColor(_) => panic!("data() called on non-variable color type."), - VariableIndexColor(items) => items.into_iter().map(|v| *v as ColorInt).collect(), + VariableIndexColor(items) => items.into_iter().map(|v| *v as f64).collect(), BackgroundColor => panic!("data() called on non-variable color type."), Black => panic!("data() called on non-variable color type."), } @@ -121,7 +121,10 @@ impl ColorType { pub fn is_variable(&self) -> bool { match self { - VariableRGBColor(_) | VariableARGBColor(_) | VariableIndexColor(_) => true, + VariableRGBColor(_) + | VariableARGBColor(_) + | VariableIndexColor(_) + | VariablePaletteColor(_) => true, _ => false, } } @@ -232,7 +235,7 @@ impl OneWayOwned for ColorType { VariableRGBColor(d) => VariableRGBColor(d.clone()), PaletteFracColor(_) => todo!(), PaletteCBColor(_) => todo!(), - PaletteZColor => PaletteZColor, + VariablePaletteColor(d) => VariablePaletteColor(d.clone()), PaletteColorMap(_) => todo!(), VariableIndexColor(d) => VariableIndexColor(d.clone()), BackgroundColor => BackgroundColor, @@ -253,7 +256,7 @@ impl ColorType { VariableARGBColor(d) => VariableARGBColor(d.to_vec()), PaletteFracColor(_) => todo!(), PaletteCBColor(_) => todo!(), - PaletteZColor => todo!(), + VariablePaletteColor(d) => VariablePaletteColor(d.to_vec()), PaletteColorMap(_) => todo!(), VariableIndexColor(d) => VariableIndexColor(d.to_vec()), BackgroundColor => todo!(), From d12009791d4185722e428047eaad79fb71aca40a Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Mon, 24 Feb 2025 15:37:59 +0000 Subject: [PATCH 13/34] Fix parentheses in from_argb --- gnuplot/src/color.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gnuplot/src/color.rs b/gnuplot/src/color.rs index dfdff47a..52394cc2 100644 --- a/gnuplot/src/color.rs +++ b/gnuplot/src/color.rs @@ -133,7 +133,7 @@ impl ColorType { fn from_argb( a: ColorComponent, r: ColorComponent, g: ColorComponent, b: ColorComponent, ) -> ColorInt { - (a as ColorInt) << 24 + (r as ColorInt) << 16 + (g as ColorInt) << 8 + (b as ColorInt) + ((a as ColorInt) << 24) + ((r as ColorInt) << 16) + ((g as ColorInt) << 8) + (b as ColorInt) } fn float_color_to_int(v: f64) -> u8 { From adcd232a9103265bda1a4ff010fb681b01a51520 Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Mon, 24 Feb 2025 15:40:13 +0000 Subject: [PATCH 14/34] Add VariableARGBColor example --- gnuplot/examples/color.rs | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/gnuplot/examples/color.rs b/gnuplot/examples/color.rs index fddb9b61..c0d9a23f 100644 --- a/gnuplot/examples/color.rs +++ b/gnuplot/examples/color.rs @@ -65,8 +65,15 @@ fn example(c: Common) { let by3 = |x| (((x % 3.0) + 1.0) / 6.0); let by4 = |x| (((x % 4.0) + 1.0) / 7.0); + let argb_formula = |x: &f64| { + let a = 255.0 * (x - 5.5).abs() / 5.5; + let r = x * 51.0 / 2.0; + let g = (11.0 - x) * 51.0 / 2.0; + let b = ((5.5 - x).abs() * 2.0 * 510.0 / 9.0).round(); + (a as u8, r as u8, g as u8, b as u8) + }; // Demo/test of variable color in many different plot styles - // derived from https://gnuplot.sourceforge.net/demo_6.0/varcolor.html + // Inspired by https://gnuplot.sourceforge.net/demo_6.0/varcolor.html // // The loop is run four times with different color sets: each one sets all the elements of a given // plot to a different color, while making sure the colors align by x position: i.e. everything at x = 1 @@ -75,17 +82,28 @@ fn example(c: Common) { // // The first color loop demonstrates usage of VariableIndexColor with indices to use gnuplot's default color styles, // but make them align for multiple plot items on the same axis. This is implicity constructed from a Vec using - // the `Color` function but could equivalently be created explicitly using `ColorType::VariableIndexColor(row_index.clone())` + // the `Color` function but could equivalently be created explicitly using `ColorOpt(ColorType::VariableIndexColor(row_index.clone()))` // - // The second color loop use a VariablePaletteColor: this selects the color based on the current color palette and the + // The second color loop uses a VariablePaletteColor: this selects the color based on the current color palette and the // input value for each data point. The palette is scaled to the maximum value in the vector of `f64`s passed - // to the VariablePaletteColor + // to the VariablePaletteColor. + // + // The third color loop uses an (implicit) VariableARGBColor. The `Vec<(u8, u8, u8, u8)>` needed to constcruct the color + // is calculated in this case by the `argb_formula()` closure. An explicit VariableARGBColor could also be constructed using + // `ColorOpt(ColorType::VariableARGBColor(data)``. A VariableRGBColor is also defined that takes a 3-tuple of u8, rather than + // a 4 tuple. for (color, label) in [ (Color(row_index.clone()), "VariableIndexColor"), ( - ColorOpt(VariablePaletteColor(row_index.iter().map(|v| *v as f64).collect())), + ColorOpt(VariablePaletteColor( + row_index.iter().map(|v| *v as f64).collect(), + )), "VariablePaletteColor", ), + ( + Color(d1.iter().map(argb_formula).collect::>()), + "VariableARGBColor", + ), ] { let mut fg = Figure::new(); let ax = fg.axes2d(); @@ -94,7 +112,6 @@ fn example(c: Common) { &[], ); ax.set_y_range(Fix(-4.0), Fix(11.5)); - // unset colorbox ax.box_error_low_high_set_width( &d1, &d5, From 91c20df9cbc5650dc9f27afa6f3074726ac33178 Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Mon, 24 Feb 2025 18:10:06 +0000 Subject: [PATCH 15/34] Add SavedColorMap implementation and example --- gnuplot/examples/color.rs | 86 +++++++++++++++++++++++++++++++++++++- gnuplot/src/axes_common.rs | 81 ++++++++++++----------------------- gnuplot/src/color.rs | 13 +++--- gnuplot/src/options.rs | 61 +++++++++++++++++++++++++++ 4 files changed, 179 insertions(+), 62 deletions(-) diff --git a/gnuplot/examples/color.rs b/gnuplot/examples/color.rs index c0d9a23f..6e5b12ff 100644 --- a/gnuplot/examples/color.rs +++ b/gnuplot/examples/color.rs @@ -2,7 +2,7 @@ use std::iter; // This file is released into Public Domain. use crate::common::*; -use gnuplot::*; +use gnuplot::{palettes::MAGMA, *}; mod common; @@ -142,11 +142,93 @@ fn example(c: Common) { iter::repeat(10), d1.iter().map(by3), d1.iter().map(by4), - &[color.clone()], + &[color.clone(), BorderColor(RGBColor("black"))], ); c.show(&mut fg, "variable_color"); } + + // ##################################################################### + // The example below shows the same graphs as in the loop, but using a set of saved colormaps + // similar to palette in gnuplot terms, but the current palette is applied to all plots by default, and + // multiple named colormaps can be created). + // + // As with VariablePaletteColor, this Color takes a vector of f64 that says which point in the colormap to use, + // but it also takes a the name of the colormap from which to draw the colors. + // + // Note that the Color range appears to be shared across plots: i.e. if one plot has + // color data (the Vec) in the range 0-1, and another in the range 1-100, all the + // colors in the first plot will be right at the bottom end of it's colormap, even if that's + // a different colormap to the one used in the second plot. + let mut fg = Figure::new(); + let ax = fg.axes2d(); + + // First create the colormaps we will later refer to + // MAGMA is one of the colormaps provide with rust gnuplot + ax.create_colormap("magma", MAGMA); + // HOT is one of the colormaps provide with rust gnuplot + ax.create_colormap("hot", HOT); + // ocean (green-blue-white) as per the gnuplot documentation + ax.create_colormap("ocean", PaletteType::Formula(23, 28, 3)); + + let color_values: Vec = row_index.iter().map(|v| *v as f64).collect(); + + ax.set_title( + &format!("variable color boxerror, points, xyerrorbars, and boxxyerror.\nColor used is a SavedColormap"), + &[], + ); + ax.set_y_range(Fix(-4.0), Fix(11.5)); + ax.box_error_low_high_set_width( + &d1, + &d5, + &d2, + &d6, + iter::repeat(0.2), + &[ + Color(SavedColorMap("magma", color_values.clone())), + FillAlpha(0.5), + BorderColor(RGBColor("black")), + ], + ); + ax.points( + &d1, + iter::repeat(1), + &[ + Color(SavedColorMap( + "hot", + color_values.iter().map(|v| 11.0 - *v).collect(), + )), + PointSymbol('D'), + ], + ); + ax.xy_error_bars( + &d1, + iter::repeat(8), + d1.iter().map(by3), + d1.iter().map(by4), + &[Color(SavedColorMap("ocean", color_values.clone()))], + ); + ax.points( + &d1, + d2.iter().map(|v| -v / 2.0), + &[ + Color(SavedColorMap("magma", color_values.clone())), + PointSymbol('O'), + PointSize(3.0), + ], + ); + ax.box_xy_error_delta( + &d1, + iter::repeat(10), + d1.iter().map(by3), + d1.iter().map(by4), + &[ + Color(SavedColorMap("hot", color_values.clone())), + BorderColor(RGBColor("black")), + ], + ); + + c.show(&mut fg, "variable_palette"); } fn main() { diff --git a/gnuplot/src/axes_common.rs b/gnuplot/src/axes_common.rs index c85de44a..481c473b 100644 --- a/gnuplot/src/axes_common.rs +++ b/gnuplot/src/axes_common.rs @@ -479,7 +479,7 @@ pub fn write_out_label_options( first_opt! {options, MarkerColor(ref s) => { - write!(w, r#" lc rgb "{}""#, s.command()); + write!(w, r#" lc "{}""#, s.command()); } } @@ -1081,6 +1081,7 @@ pub struct AxesCommonData pub aspect_ratio: AutoOption, pub margins: Margins, pub palette: PaletteType>, + pub colormaps: Vec<(String, PaletteType>)> } impl AxesCommonData @@ -1104,6 +1105,7 @@ impl AxesCommonData aspect_ratio: Auto, margins: Margins::new(), palette: COLOR.to_one_way_owned(), + colormaps: Vec::new(), }; ret.x2_axis.tick_type = TickType::None; ret.y2_axis.tick_type = TickType::None; @@ -1236,60 +1238,19 @@ impl AxesCommonData } } self.margins.write_out_commands(w); - - match self.palette - { - Gray(gamma) => - { - assert!(gamma > 0.0, "Gamma must be positive"); - writeln!(w, "set palette gray gamma {:.12e}", gamma); - } - Formula(r, g, b) => - { - assert!(r >= -36 && r <= 36, "Invalid r formula!"); - assert!(g >= -36 && g <= 36, "Invalid g formula!"); - assert!(b >= -36 && b <= 36, "Invalid b formula!"); - writeln!(w, "set palette rgbformulae {},{},{}", r, g, b); - } - CubeHelix(start, rev, sat, gamma) => - { - assert!(sat >= 0.0, "Saturation must be non-negative"); - assert!(gamma > 0.0, "Gamma must be positive"); - writeln!( - w, - "set palette cubehelix start {:.12e} cycles {:.12e} saturation {:.12e} gamma {:.12e}", - start, rev, sat, gamma - ); - } - Custom(ref entries) => - { - if entries.len() < 2 - { - panic!("Need at least 2 elements in a custom palette"); - } - write!(w, "set palette defined ("); - - let mut first = true; - let mut old_x = 0.0; - for &(x, r, g, b) in entries - { - if first - { - old_x = x; - first = false; - } - else - { - write!(w, ","); - } - assert!(x >= old_x, "The gray levels must be non-decreasing!"); - old_x = x; - - write!(w, "{:.12e} {:.12e} {:.12e} {:.12e}", x, r, g, b); - } - - writeln!(w, ")"); + self.palette.write_out_commands(w); + + if !self.colormaps.is_empty(){ + // save previous palette + writeln!(w, "set colormap new __ORIGINAL_COLORMAP__"); + for (name, map) in &self.colormaps { + // set palette to the requested map + map.write_out_commands(w); + // save current palette to colormap with the requested name + writeln!(w, "set colormap new {name}"); } + // reload previous palette from saved colormap + writeln!(w, "set palette colormap __ORIGINAL_COLORMAP__"); } self.x_axis.write_out_commands(w, version); @@ -2093,4 +2054,16 @@ pub trait AxesCommon: AxesCommonPrivate self.get_common_data_mut().palette = palette.to_one_way_owned(); self } + + /// Creates and saves a colormap in the gnuplot environment that can be used for + /// later plots (see examples/color_variable.rs for example usage) + /// + /// /// # Arguments + /// * `name` - The name with which to save the colormap + /// * `palette` - What palette type to use + fn create_colormap(&mut self, name: &str, palette: PaletteType<&[(f32, f32, f32, f32)]>) -> &mut Self + { + self.get_common_data_mut().colormaps.push((name.to_owned(), palette.to_one_way_owned())); + self + } } diff --git a/gnuplot/src/color.rs b/gnuplot/src/color.rs index 52394cc2..17a15f31 100644 --- a/gnuplot/src/color.rs +++ b/gnuplot/src/color.rs @@ -59,7 +59,7 @@ pub enum ColorType { PaletteFracColor(f32), PaletteCBColor(f32), VariablePaletteColor(Vec), - PaletteColorMap(T), + SavedColorMap(T, Vec), /// Set the color of all elements of the plot to the `n`th color in the current gnuplot color cycle. IndexColor(ColorIndex), /// A color type that sets the color per element using a index `n` which represents the `n`th @@ -87,7 +87,7 @@ impl ColorType { PaletteFracColor(_) => todo!(), PaletteCBColor(_) => todo!(), VariablePaletteColor(_) => String::from("palette z"), - PaletteColorMap(_) => todo!(), + SavedColorMap(s, _) => format!("palette {s}"), VariableIndexColor(_) => String::from("variable"), BackgroundColor => todo!(), IndexColor(n) => format!("{}", n), @@ -111,7 +111,7 @@ impl ColorType { PaletteFracColor(_) => panic!("data() called on non-variable color type."), PaletteCBColor(_) => panic!("data() called on non-variable color type."), VariablePaletteColor(items) => items.clone(), - PaletteColorMap(_) => panic!("data() called on non-variable color type."), + SavedColorMap(_, items) => items.clone(), IndexColor(_) => panic!("data() called on non-variable color type."), VariableIndexColor(items) => items.into_iter().map(|v| *v as f64).collect(), BackgroundColor => panic!("data() called on non-variable color type."), @@ -124,7 +124,8 @@ impl ColorType { VariableRGBColor(_) | VariableARGBColor(_) | VariableIndexColor(_) - | VariablePaletteColor(_) => true, + | VariablePaletteColor(_) + | SavedColorMap(_, _) => true, _ => false, } } @@ -236,7 +237,7 @@ impl OneWayOwned for ColorType { PaletteFracColor(_) => todo!(), PaletteCBColor(_) => todo!(), VariablePaletteColor(d) => VariablePaletteColor(d.clone()), - PaletteColorMap(_) => todo!(), + SavedColorMap(s, d) => SavedColorMap(s.to_string(), d.clone()), VariableIndexColor(d) => VariableIndexColor(d.clone()), BackgroundColor => BackgroundColor, IndexColor(n) => IndexColor(*n), @@ -257,7 +258,7 @@ impl ColorType { PaletteFracColor(_) => todo!(), PaletteCBColor(_) => todo!(), VariablePaletteColor(d) => VariablePaletteColor(d.to_vec()), - PaletteColorMap(_) => todo!(), + SavedColorMap(s, d) => SavedColorMap(s, d.to_vec()), VariableIndexColor(d) => VariableIndexColor(d.to_vec()), BackgroundColor => todo!(), IndexColor(n) => IndexColor(*n), diff --git a/gnuplot/src/options.rs b/gnuplot/src/options.rs index 6f91f006..e3c6c229 100644 --- a/gnuplot/src/options.rs +++ b/gnuplot/src/options.rs @@ -20,6 +20,7 @@ pub use self::TickOption::*; pub use self::XAxis::*; pub use self::YAxis::*; use crate::util::OneWayOwned; +use crate::writer::Writer; use crate::ColorType; use crate::IntoColor; @@ -469,6 +470,66 @@ pub const HOT: PaletteType<&'static [(f32, f32, f32, f32)]> = Formula(34, 35, 36 /// A nice default for a cube helix pub const HELIX: PaletteType<&'static [(f32, f32, f32, f32)]> = CubeHelix(0.5, -0.8, 2.0, 1.0); +impl PaletteType>{ + pub fn write_out_commands(&self, w: &mut dyn Writer) + { + match *self + { + Gray(gamma) => + { + assert!(gamma > 0.0, "Gamma must be positive"); + writeln!(w, "set palette gray gamma {:.12e}", gamma); + } + Formula(r, g, b) => + { + assert!(r >= -36 && r <= 36, "Invalid r formula!"); + assert!(g >= -36 && g <= 36, "Invalid g formula!"); + assert!(b >= -36 && b <= 36, "Invalid b formula!"); + writeln!(w, "set palette rgbformulae {},{},{}", r, g, b); + } + CubeHelix(start, rev, sat, gamma) => + { + assert!(sat >= 0.0, "Saturation must be non-negative"); + assert!(gamma > 0.0, "Gamma must be positive"); + writeln!( + w, + "set palette cubehelix start {:.12e} cycles {:.12e} saturation {:.12e} gamma {:.12e}", + start, rev, sat, gamma + ); + } + Custom(ref entries) => + { + if entries.len() < 2 + { + panic!("Need at least 2 elements in a custom palette"); + } + write!(w, "set palette defined ("); + + let mut first = true; + let mut old_x = 0.0; + for &(x, r, g, b) in entries + { + if first + { + old_x = x; + first = false; + } + else + { + write!(w, ","); + } + assert!(x >= old_x, "The gray levels must be non-decreasing!"); + old_x = x; + + write!(w, "{:.12e} {:.12e} {:.12e} {:.12e}", x, r, g, b); + } + + writeln!(w, ")"); + } + } + } +} + /// Gnuplot version identifier. This is used to handle version-specific /// features. #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] From 235163a52e497ae0edb87b9d4e7f0a053f335b71 Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Mon, 24 Feb 2025 18:13:35 +0000 Subject: [PATCH 16/34] Move variable color example to separate file --- gnuplot/Cargo.toml | 4 + gnuplot/examples/color.rs | 200 +-------------------------- gnuplot/examples/variable_color.rs | 211 +++++++++++++++++++++++++++++ 3 files changed, 216 insertions(+), 199 deletions(-) create mode 100644 gnuplot/examples/variable_color.rs diff --git a/gnuplot/Cargo.toml b/gnuplot/Cargo.toml index 4e57472f..ecb11ff6 100644 --- a/gnuplot/Cargo.toml +++ b/gnuplot/Cargo.toml @@ -65,6 +65,10 @@ path = "examples/box_xy_error.rs" name = "color" path = "examples/color.rs" +[[example]] + +name = "variable_color" +path = "examples/variable_color.rs" [[example]] diff --git a/gnuplot/examples/color.rs b/gnuplot/examples/color.rs index 6e5b12ff..c6cce425 100644 --- a/gnuplot/examples/color.rs +++ b/gnuplot/examples/color.rs @@ -1,23 +1,9 @@ -use std::iter; - // This file is released into Public Domain. use crate::common::*; -use gnuplot::{palettes::MAGMA, *}; +use gnuplot::*; mod common; -// https://github.com/gnuplot/gnuplot/blob/master/demo/candlesticks.dat -static CANDLESTICKS_STR: &str = "1 1.5 2 2.4 4 6. -2 1.5 3 3.5 4 5.5 -3 4.5 5 5.5 6 6.5 -4 3.7 4.5 5.0 5.5 6.1 -5 3.1 3.5 4.2 5 6.1 -6 1 4 5.0 6 9 -7 4 4 4.8 6 6.1 -8 4 5 5.1 6 6.1 -9 1.5 2 2.4 3 3.5 -10 2.7 3 3.5 4 4.3"; - fn example(c: Common) { let x = 0..10; @@ -45,190 +31,6 @@ fn example(c: Common) { c.show(&mut fg, "rgb_color"); - let data: Vec> = CANDLESTICKS_STR - .split("\n") - .map(|line| { - line.split("\t") - .map(|v| v.trim().parse::().unwrap()) - .collect() - }) - .collect(); - let extract_col = |i| data.iter().map(|l| l[i]).collect::>(); - - let d1 = extract_col(0); - let d2 = extract_col(1); - // let d3 = extract_col(2); - // let d4 = extract_col(3); - let d5 = extract_col(4); - let d6 = extract_col(5); - let row_index: Vec<_> = (1..=d1.len() as u8).collect(); - let by3 = |x| (((x % 3.0) + 1.0) / 6.0); - let by4 = |x| (((x % 4.0) + 1.0) / 7.0); - - let argb_formula = |x: &f64| { - let a = 255.0 * (x - 5.5).abs() / 5.5; - let r = x * 51.0 / 2.0; - let g = (11.0 - x) * 51.0 / 2.0; - let b = ((5.5 - x).abs() * 2.0 * 510.0 / 9.0).round(); - (a as u8, r as u8, g as u8, b as u8) - }; - // Demo/test of variable color in many different plot styles - // Inspired by https://gnuplot.sourceforge.net/demo_6.0/varcolor.html - // - // The loop is run four times with different color sets: each one sets all the elements of a given - // plot to a different color, while making sure the colors align by x position: i.e. everything at x = 1 - // uses the first color, everything at x = 2 uses the second and so on. - // - // - // The first color loop demonstrates usage of VariableIndexColor with indices to use gnuplot's default color styles, - // but make them align for multiple plot items on the same axis. This is implicity constructed from a Vec using - // the `Color` function but could equivalently be created explicitly using `ColorOpt(ColorType::VariableIndexColor(row_index.clone()))` - // - // The second color loop uses a VariablePaletteColor: this selects the color based on the current color palette and the - // input value for each data point. The palette is scaled to the maximum value in the vector of `f64`s passed - // to the VariablePaletteColor. - // - // The third color loop uses an (implicit) VariableARGBColor. The `Vec<(u8, u8, u8, u8)>` needed to constcruct the color - // is calculated in this case by the `argb_formula()` closure. An explicit VariableARGBColor could also be constructed using - // `ColorOpt(ColorType::VariableARGBColor(data)``. A VariableRGBColor is also defined that takes a 3-tuple of u8, rather than - // a 4 tuple. - for (color, label) in [ - (Color(row_index.clone()), "VariableIndexColor"), - ( - ColorOpt(VariablePaletteColor( - row_index.iter().map(|v| *v as f64).collect(), - )), - "VariablePaletteColor", - ), - ( - Color(d1.iter().map(argb_formula).collect::>()), - "VariableARGBColor", - ), - ] { - let mut fg = Figure::new(); - let ax = fg.axes2d(); - ax.set_title( - &format!("variable color boxerror, points, xyerrorbars, and boxxyerror.\nColor used is a {label}"), - &[], - ); - ax.set_y_range(Fix(-4.0), Fix(11.5)); - ax.box_error_low_high_set_width( - &d1, - &d5, - &d2, - &d6, - iter::repeat(0.2), - &[ - color.clone(), - FillAlpha(0.5), - BorderColor(RGBColor("black")), - ], - ); - ax.points(&d1, iter::repeat(1), &[color.clone(), PointSymbol('D')]); - ax.xy_error_bars( - &d1, - iter::repeat(8), - d1.iter().map(by3), - d1.iter().map(by4), - &[color.clone()], - ); - ax.points( - &d1, - d2.iter().map(|v| -v / 2.0), - &[color.clone(), PointSymbol('O'), PointSize(3.0)], - ); - ax.box_xy_error_delta( - &d1, - iter::repeat(10), - d1.iter().map(by3), - d1.iter().map(by4), - &[color.clone(), BorderColor(RGBColor("black"))], - ); - - c.show(&mut fg, "variable_color"); - } - - // ##################################################################### - // The example below shows the same graphs as in the loop, but using a set of saved colormaps - // similar to palette in gnuplot terms, but the current palette is applied to all plots by default, and - // multiple named colormaps can be created). - // - // As with VariablePaletteColor, this Color takes a vector of f64 that says which point in the colormap to use, - // but it also takes a the name of the colormap from which to draw the colors. - // - // Note that the Color range appears to be shared across plots: i.e. if one plot has - // color data (the Vec) in the range 0-1, and another in the range 1-100, all the - // colors in the first plot will be right at the bottom end of it's colormap, even if that's - // a different colormap to the one used in the second plot. - let mut fg = Figure::new(); - let ax = fg.axes2d(); - - // First create the colormaps we will later refer to - // MAGMA is one of the colormaps provide with rust gnuplot - ax.create_colormap("magma", MAGMA); - // HOT is one of the colormaps provide with rust gnuplot - ax.create_colormap("hot", HOT); - // ocean (green-blue-white) as per the gnuplot documentation - ax.create_colormap("ocean", PaletteType::Formula(23, 28, 3)); - - let color_values: Vec = row_index.iter().map(|v| *v as f64).collect(); - - ax.set_title( - &format!("variable color boxerror, points, xyerrorbars, and boxxyerror.\nColor used is a SavedColormap"), - &[], - ); - ax.set_y_range(Fix(-4.0), Fix(11.5)); - ax.box_error_low_high_set_width( - &d1, - &d5, - &d2, - &d6, - iter::repeat(0.2), - &[ - Color(SavedColorMap("magma", color_values.clone())), - FillAlpha(0.5), - BorderColor(RGBColor("black")), - ], - ); - ax.points( - &d1, - iter::repeat(1), - &[ - Color(SavedColorMap( - "hot", - color_values.iter().map(|v| 11.0 - *v).collect(), - )), - PointSymbol('D'), - ], - ); - ax.xy_error_bars( - &d1, - iter::repeat(8), - d1.iter().map(by3), - d1.iter().map(by4), - &[Color(SavedColorMap("ocean", color_values.clone()))], - ); - ax.points( - &d1, - d2.iter().map(|v| -v / 2.0), - &[ - Color(SavedColorMap("magma", color_values.clone())), - PointSymbol('O'), - PointSize(3.0), - ], - ); - ax.box_xy_error_delta( - &d1, - iter::repeat(10), - d1.iter().map(by3), - d1.iter().map(by4), - &[ - Color(SavedColorMap("hot", color_values.clone())), - BorderColor(RGBColor("black")), - ], - ); - - c.show(&mut fg, "variable_palette"); } fn main() { diff --git a/gnuplot/examples/variable_color.rs b/gnuplot/examples/variable_color.rs new file mode 100644 index 00000000..826ad795 --- /dev/null +++ b/gnuplot/examples/variable_color.rs @@ -0,0 +1,211 @@ +use std::iter; + +// This file is released into Public Domain. +use crate::common::*; +use gnuplot::{palettes::MAGMA, *}; + +mod common; + +// https://github.com/gnuplot/gnuplot/blob/master/demo/candlesticks.dat +static CANDLESTICKS_STR: &str = "1 1.5 2 2.4 4 6. +2 1.5 3 3.5 4 5.5 +3 4.5 5 5.5 6 6.5 +4 3.7 4.5 5.0 5.5 6.1 +5 3.1 3.5 4.2 5 6.1 +6 1 4 5.0 6 9 +7 4 4 4.8 6 6.1 +8 4 5 5.1 6 6.1 +9 1.5 2 2.4 3 3.5 +10 2.7 3 3.5 4 4.3"; + +fn example(c: Common) { + + let data: Vec> = CANDLESTICKS_STR + .split("\n") + .map(|line| { + line.split("\t") + .map(|v| v.trim().parse::().unwrap()) + .collect() + }) + .collect(); + let extract_col = |i| data.iter().map(|l| l[i]).collect::>(); + + let d1 = extract_col(0); + let d2 = extract_col(1); + // let d3 = extract_col(2); + // let d4 = extract_col(3); + let d5 = extract_col(4); + let d6 = extract_col(5); + let row_index: Vec<_> = (1..=d1.len() as u8).collect(); + let by3 = |x| (((x % 3.0) + 1.0) / 6.0); + let by4 = |x| (((x % 4.0) + 1.0) / 7.0); + + let argb_formula = |x: &f64| { + let a = 255.0 * (x - 5.5).abs() / 5.5; + let r = x * 51.0 / 2.0; + let g = (11.0 - x) * 51.0 / 2.0; + let b = ((5.5 - x).abs() * 2.0 * 510.0 / 9.0).round(); + (a as u8, r as u8, g as u8, b as u8) + }; + // Demo/test of variable color in many different plot styles + // Inspired by https://gnuplot.sourceforge.net/demo_6.0/varcolor.html + // + // The loop is run four times with different color sets: each one sets all the elements of a given + // plot to a different color, while making sure the colors align by x position: i.e. everything at x = 1 + // uses the first color, everything at x = 2 uses the second and so on. + // + // + // The first color loop demonstrates usage of VariableIndexColor with indices to use gnuplot's default color styles, + // but make them align for multiple plot items on the same axis. This is implicity constructed from a Vec using + // the `Color` function but could equivalently be created explicitly using `ColorOpt(ColorType::VariableIndexColor(row_index.clone()))` + // + // The second color loop uses a VariablePaletteColor: this selects the color based on the current color palette and the + // input value for each data point. The palette is scaled to the maximum value in the vector of `f64`s passed + // to the VariablePaletteColor. + // + // The third color loop uses an (implicit) VariableARGBColor. The `Vec<(u8, u8, u8, u8)>` needed to constcruct the color + // is calculated in this case by the `argb_formula()` closure. An explicit VariableARGBColor could also be constructed using + // `ColorOpt(ColorType::VariableARGBColor(data)``. A VariableRGBColor is also defined that takes a 3-tuple of u8, rather than + // a 4 tuple. + for (color, label) in [ + (Color(row_index.clone()), "VariableIndexColor"), + ( + ColorOpt(VariablePaletteColor( + row_index.iter().map(|v| *v as f64).collect(), + )), + "VariablePaletteColor", + ), + ( + Color(d1.iter().map(argb_formula).collect::>()), + "VariableARGBColor", + ), + ] { + let mut fg = Figure::new(); + let ax = fg.axes2d(); + ax.set_title( + &format!("variable color boxerror, points, xyerrorbars, and boxxyerror.\nColor used is a {label}"), + &[], + ); + ax.set_y_range(Fix(-4.0), Fix(11.5)); + ax.box_error_low_high_set_width( + &d1, + &d5, + &d2, + &d6, + iter::repeat(0.2), + &[ + color.clone(), + FillAlpha(0.5), + BorderColor(RGBColor("black")), + ], + ); + ax.points(&d1, iter::repeat(1), &[color.clone(), PointSymbol('D')]); + ax.xy_error_bars( + &d1, + iter::repeat(8), + d1.iter().map(by3), + d1.iter().map(by4), + &[color.clone()], + ); + ax.points( + &d1, + d2.iter().map(|v| -v / 2.0), + &[color.clone(), PointSymbol('O'), PointSize(3.0)], + ); + ax.box_xy_error_delta( + &d1, + iter::repeat(10), + d1.iter().map(by3), + d1.iter().map(by4), + &[color.clone(), BorderColor(RGBColor("black"))], + ); + + c.show(&mut fg, "variable_color"); + } + + // ##################################################################### + // The example below shows the same graphs as in the loop, but using a set of saved colormaps + // similar to palette in gnuplot terms, but the current palette is applied to all plots by default, and + // multiple named colormaps can be created). + // + // As with VariablePaletteColor, this Color takes a vector of f64 that says which point in the colormap to use, + // but it also takes a the name of the colormap from which to draw the colors. + // + // Note that the Color range appears to be shared across plots: i.e. if one plot has + // color data (the Vec) in the range 0-1, and another in the range 1-100, all the + // colors in the first plot will be right at the bottom end of it's colormap, even if that's + // a different colormap to the one used in the second plot. + let mut fg = Figure::new(); + let ax = fg.axes2d(); + + // First create the colormaps we will later refer to + // MAGMA is one of the colormaps provide with rust gnuplot + ax.create_colormap("magma", MAGMA); + // HOT is one of the colormaps provide with rust gnuplot + ax.create_colormap("hot", HOT); + // ocean (green-blue-white) as per the gnuplot documentation + ax.create_colormap("ocean", PaletteType::Formula(23, 28, 3)); + + let color_values: Vec = row_index.iter().map(|v| *v as f64).collect(); + + ax.set_title( + &format!("variable color boxerror, points, xyerrorbars, and boxxyerror.\nColor used is a SavedColormap"), + &[], + ); + ax.set_y_range(Fix(-4.0), Fix(11.5)); + ax.box_error_low_high_set_width( + &d1, + &d5, + &d2, + &d6, + iter::repeat(0.2), + &[ + Color(SavedColorMap("magma", color_values.clone())), + FillAlpha(0.5), + BorderColor(RGBColor("black")), + ], + ); + ax.points( + &d1, + iter::repeat(1), + &[ + Color(SavedColorMap( + "hot", + color_values.iter().map(|v| 11.0 - *v).collect(), + )), + PointSymbol('D'), + ], + ); + ax.xy_error_bars( + &d1, + iter::repeat(8), + d1.iter().map(by3), + d1.iter().map(by4), + &[Color(SavedColorMap("ocean", color_values.clone()))], + ); + ax.points( + &d1, + d2.iter().map(|v| -v / 2.0), + &[ + Color(SavedColorMap("magma", color_values.clone())), + PointSymbol('O'), + PointSize(3.0), + ], + ); + ax.box_xy_error_delta( + &d1, + iter::repeat(10), + d1.iter().map(by3), + d1.iter().map(by4), + &[ + Color(SavedColorMap("hot", color_values.clone())), + BorderColor(RGBColor("black")), + ], + ); + + c.show(&mut fg, "variable_palette"); +} + +fn main() { + Common::new().map(|c| example(c)); +} From 14a05b2f3f94cf30a5b5b13eed82ed105e972e2f Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Mon, 24 Feb 2025 19:44:49 +0000 Subject: [PATCH 17/34] Rename colors to reduce redundancy and add more documentation --- gnuplot/examples/color.rs | 13 ++- gnuplot/examples/example1.rs | 2 +- gnuplot/examples/variable_color.rs | 17 ++-- gnuplot/src/axes_common.rs | 2 +- gnuplot/src/color.rs | 126 ++++++++++++++++------------- 5 files changed, 85 insertions(+), 75 deletions(-) diff --git a/gnuplot/examples/color.rs b/gnuplot/examples/color.rs index c6cce425..9d34a9e8 100644 --- a/gnuplot/examples/color.rs +++ b/gnuplot/examples/color.rs @@ -9,16 +9,16 @@ fn example(c: Common) { let mut fg = Figure::new(); let ax = fg.axes2d(); - ax.set_title("Demo of RGBColor in various forms", &[]); + ax.set_title("Demo of RGBString in various forms", &[]); ax.set_legend(Graph(0.5), Graph(0.9), &[], &[]); let colors = [ Color("black"), - Color(ColorType::RGBColor("black")), + Color(ColorType::RGBString("black")), Color("red"), - Color(ColorType::RGBColor("#ff0000")), // red using Hex coded RRGGBB - Color(ColorType::RGBColor("#ff8888")), // pink using Hex coded RRGGBB - Color(ColorType::RGBColor("#88ff0000")), // pink using Hex coded AARRGGBB - Color(ColorType::RGBColor("#ff0000")), // red using Hex coded RRGGBB + Color(ColorType::RGBString("#ff0000")), // red using Hex coded RRGGBB + Color(ColorType::RGBString("#ff8888")), // pink using Hex coded RRGGBB + Color(ColorType::RGBString("#88ff0000")), // pink using Hex coded AARRGGBB + Color(ColorType::RGBString("#ff0000")), // red using Hex coded RRGGBB ]; for (i, color) in colors.into_iter().enumerate() { @@ -30,7 +30,6 @@ fn example(c: Common) { } c.show(&mut fg, "rgb_color"); - } fn main() { diff --git a/gnuplot/examples/example1.rs b/gnuplot/examples/example1.rs index 96e260b7..df795997 100644 --- a/gnuplot/examples/example1.rs +++ b/gnuplot/examples/example1.rs @@ -307,7 +307,7 @@ fn example(c: Common) MarkerSymbol('*'), TextAlign(AlignCenter), TextOffset(0.0, -1.0), - MarkerColor(RGBColor("red")), + MarkerColor(RGBString("red")), MarkerSize(2.0), ], ); diff --git a/gnuplot/examples/variable_color.rs b/gnuplot/examples/variable_color.rs index 826ad795..8ce89555 100644 --- a/gnuplot/examples/variable_color.rs +++ b/gnuplot/examples/variable_color.rs @@ -19,7 +19,6 @@ static CANDLESTICKS_STR: &str = "1 1.5 2 2.4 4 6. 10 2.7 3 3.5 4 4.3"; fn example(c: Common) { - let data: Vec> = CANDLESTICKS_STR .split("\n") .map(|line| { @@ -63,9 +62,9 @@ fn example(c: Common) { // input value for each data point. The palette is scaled to the maximum value in the vector of `f64`s passed // to the VariablePaletteColor. // - // The third color loop uses an (implicit) VariableARGBColor. The `Vec<(u8, u8, u8, u8)>` needed to constcruct the color - // is calculated in this case by the `argb_formula()` closure. An explicit VariableARGBColor could also be constructed using - // `ColorOpt(ColorType::VariableARGBColor(data)``. A VariableRGBColor is also defined that takes a 3-tuple of u8, rather than + // The third color loop uses an (implicit) VariableARGBString. The `Vec<(u8, u8, u8, u8)>` needed to constcruct the color + // is calculated in this case by the `argb_formula()` closure. An explicit VariableARGBString could also be constructed using + // `ColorOpt(ColorType::VariableARGBString(data)``. A VariableRGBString is also defined that takes a 3-tuple of u8, rather than // a 4 tuple. for (color, label) in [ (Color(row_index.clone()), "VariableIndexColor"), @@ -77,7 +76,7 @@ fn example(c: Common) { ), ( Color(d1.iter().map(argb_formula).collect::>()), - "VariableARGBColor", + "VariableARGBString", ), ] { let mut fg = Figure::new(); @@ -96,7 +95,7 @@ fn example(c: Common) { &[ color.clone(), FillAlpha(0.5), - BorderColor(RGBColor("black")), + BorderColor(RGBString("black")), ], ); ax.points(&d1, iter::repeat(1), &[color.clone(), PointSymbol('D')]); @@ -117,7 +116,7 @@ fn example(c: Common) { iter::repeat(10), d1.iter().map(by3), d1.iter().map(by4), - &[color.clone(), BorderColor(RGBColor("black"))], + &[color.clone(), BorderColor(RGBString("black"))], ); c.show(&mut fg, "variable_color"); @@ -162,7 +161,7 @@ fn example(c: Common) { &[ Color(SavedColorMap("magma", color_values.clone())), FillAlpha(0.5), - BorderColor(RGBColor("black")), + BorderColor(RGBString("black")), ], ); ax.points( @@ -199,7 +198,7 @@ fn example(c: Common) { d1.iter().map(by4), &[ Color(SavedColorMap("hot", color_values.clone())), - BorderColor(RGBColor("black")), + BorderColor(RGBString("black")), ], ); diff --git a/gnuplot/src/axes_common.rs b/gnuplot/src/axes_common.rs index 481c473b..6e3a1f56 100644 --- a/gnuplot/src/axes_common.rs +++ b/gnuplot/src/axes_common.rs @@ -680,7 +680,7 @@ impl AxisData w.write_str(self.axis.get_axis_str()); w.write_str("zeroaxis "); - AxesCommonData::write_color_options(w, &self.options, Some(ColorType::RGBColor("black".into()))); + AxesCommonData::write_color_options(w, &self.options, Some(ColorType::RGBString("black".into()))); AxesCommonData::write_line_options(w, &self.options, version); } else diff --git a/gnuplot/src/color.rs b/gnuplot/src/color.rs index 17a15f31..90b271a0 100644 --- a/gnuplot/src/color.rs +++ b/gnuplot/src/color.rs @@ -20,14 +20,14 @@ pub type ARGBInts = ( /// Option type (for lines, axes, and text) that allows the various different gnuplot /// color formats. The gnuplot [colorspec reference](http://gnuplot.info/docs_6.0/loc3640.html) -/// also explains these +/// also explains these. /// /// There are equivalent many ways of specifying colors, and this allows the user to chose the most convenient. /// for example, all the following will produce the same blue color: /// `RGBColor("blue")`, `RGBColor("0x0000ff")`, `RGBColor("#0000ff")`, `RGBColor("0x000000ff")`, /// `RGBColor("#000000ff")`, `RGBIntegerColor(0, 0, 255)`, `ARGBColor(0, 0, 0, 255)`, /// -/// See example usage of this in `color.rs` in the +/// See example usages of these colors in `color.rs`, `variable_color.rs` in the /// [Examples folder](https://github.com/SiegeLord/RustGnuplot/tree/master/gnuplot/examples) on Github #[derive(Debug, Clone, PartialEq, PartialOrd)] pub enum ColorType { @@ -42,35 +42,47 @@ pub enum ColorType { /// "#AARRGGBB" represents an RGB color with an alpha channel (transparency) value in the high bits. /// An alpha value of 0 represents a fully opaque color; i.e., "#00RRGGBB" is the same as "#RRGGBB". /// An alpha value of 255 (FF) represents full transparency. - RGBColor(T), + RGBString(T), /// tuple of u8 representing red, green and blue values as 0-255 - RGBIntegerColor(ColorComponent, ColorComponent, ColorComponent), + RGBInteger(ColorComponent, ColorComponent, ColorComponent), /// tuple of u8 representing alpha, red, green and blue values as 0-255. /// As with `RGBColor`, an alpha value of 0 represents a fully opaque color; /// an alpha value of 255 (FF) represents full transparency. - ARGBIntegerColor( + ARGBInteger( ColorComponent, ColorComponent, ColorComponent, ColorComponent, ), - VariableRGBColor(Vec), - VariableARGBColor(Vec), + /// Vector of tuples of `u8` (as per `RGBColor`), but instead of a single color for the whole + /// plot, the vector should contain a separte color for each data point. + VariableRGBIntegers(Vec), + /// Vector of tuples of `u8` (as per `ARGBColor`), but as with `VariableRGBColor`, a separate + /// color value is given for each data point. + VariableARGBIntegers(Vec), + /// TODO PaletteFracColor(f32), + /// TODO PaletteCBColor(f32), + /// Vector of `f64` values which act as indexes into the current palette to set the color of + /// each data point VariablePaletteColor(Vec), + /// Similar to `VariablePaletteColor` in that it takes a `Vec` to set the indexes into the + /// color map for each data point, but in addition to the color data it takes a string hold the name + /// of the color map to use. This should have been previously created in the workspace using the + /// `axes.create_colormap()` function. SavedColorMap(T, Vec), /// Set the color of all elements of the plot to the `n`th color in the current gnuplot color cycle. - IndexColor(ColorIndex), + Index(ColorIndex), /// A color type that sets the color per element using a index `n` which represents the `n`th /// color in the current gnuplot color scheme. In gnuplot this is the last element in the plot command, /// in Rust gnuplot, the color type takes a vector of u8, where each index is treated the same as the /// fixed `IndexColor`. /// This is useful for setting bars/boxes etc to be - /// the same color from multiple plot commands. The `color.rs` example has examples of this usage - VariableIndexColor(Vec), - /// - BackgroundColor, + /// the same color from multiple plot commands. The `color.rs` example has examples of this usage. + VariableIndex(Vec), + /// Set the color of the plot to the current background color. + Background, /// Fixed black color Black, } @@ -79,32 +91,32 @@ impl ColorType { /// Returns the gnuplot string that will produce the requested color pub fn command(&self) -> String { match self { - RGBColor(s) => format!(r#"rgb "{}""#, s), - RGBIntegerColor(r, g, b) => format!(r#"rgb {}"#, from_argb(0, *r, *g, *b)), - ARGBIntegerColor(a, r, g, b) => format!(r#"rgb {}"#, from_argb(*a, *r, *g, *b)), - VariableRGBColor(_) => String::from("rgb variable"), - VariableARGBColor(_) => String::from("rgb variable"), + RGBString(s) => format!(r#"rgb "{}""#, s), + RGBInteger(r, g, b) => format!(r#"rgb {}"#, from_argb(0, *r, *g, *b)), + ARGBInteger(a, r, g, b) => format!(r#"rgb {}"#, from_argb(*a, *r, *g, *b)), + VariableRGBIntegers(_) => String::from("rgb variable"), + VariableARGBIntegers(_) => String::from("rgb variable"), PaletteFracColor(_) => todo!(), PaletteCBColor(_) => todo!(), VariablePaletteColor(_) => String::from("palette z"), SavedColorMap(s, _) => format!("palette {s}"), - VariableIndexColor(_) => String::from("variable"), - BackgroundColor => todo!(), - IndexColor(n) => format!("{}", n), + VariableIndex(_) => String::from("variable"), + Background => todo!(), + Index(n) => format!("{}", n), Black => String::from("black"), } } pub fn data(&self) -> Vec { match self { - RGBColor(_) => panic!("data() called on non-variable color type."), - RGBIntegerColor(_, _, _) => panic!("data() called on non-variable color type."), - ARGBIntegerColor(_, _, _, _) => panic!("data() called on non-variable color type."), - VariableRGBColor(items) => items + RGBString(_) => panic!("data() called on non-variable color type."), + RGBInteger(_, _, _) => panic!("data() called on non-variable color type."), + ARGBInteger(_, _, _, _) => panic!("data() called on non-variable color type."), + VariableRGBIntegers(items) => items .iter() .map(|(r, g, b)| from_argb(0, *r, *g, *b) as f64) .collect(), - VariableARGBColor(items) => items + VariableARGBIntegers(items) => items .into_iter() .map(|(a, r, g, b)| from_argb(*a, *r, *g, *b) as f64) .collect(), @@ -112,18 +124,18 @@ impl ColorType { PaletteCBColor(_) => panic!("data() called on non-variable color type."), VariablePaletteColor(items) => items.clone(), SavedColorMap(_, items) => items.clone(), - IndexColor(_) => panic!("data() called on non-variable color type."), - VariableIndexColor(items) => items.into_iter().map(|v| *v as f64).collect(), - BackgroundColor => panic!("data() called on non-variable color type."), + Index(_) => panic!("data() called on non-variable color type."), + VariableIndex(items) => items.into_iter().map(|v| *v as f64).collect(), + Background => panic!("data() called on non-variable color type."), Black => panic!("data() called on non-variable color type."), } } pub fn is_variable(&self) -> bool { match self { - VariableRGBColor(_) - | VariableARGBColor(_) - | VariableIndexColor(_) + VariableRGBIntegers(_) + | VariableARGBIntegers(_) + | VariableIndex(_) | VariablePaletteColor(_) | SavedColorMap(_, _) => true, _ => false, @@ -166,63 +178,63 @@ fn from_argb_floats(a: f64, r: f64, g: f64, b: f64) -> ARGBInts { impl<'l> Into> for &'l str { fn into(self) -> ColorType { - ColorType::RGBColor(String::from(self)) + ColorType::RGBString(String::from(self)) } } impl<'l> Into> for String { fn into(self) -> ColorType { - ColorType::RGBColor(self) + ColorType::RGBString(self) } } impl<'l> Into> for &'l str { fn into(self) -> ColorType<&'l str> { - ColorType::RGBColor(self) + ColorType::RGBString(self) } } impl Into> for ARGBInts { fn into(self) -> ColorType { - ColorType::ARGBIntegerColor(self.0, self.1, self.2, self.3) + ColorType::ARGBInteger(self.0, self.1, self.2, self.3) } } impl Into> for RGBInts { fn into(self) -> ColorType { - ColorType::RGBIntegerColor(self.0, self.1, self.2) + ColorType::RGBInteger(self.0, self.1, self.2) } } impl Into> for (f64, f64, f64) { fn into(self) -> ColorType { let ints = from_rgb_floats(self.0, self.1, self.2); - ColorType::RGBIntegerColor(ints.0, ints.1, ints.2) + ColorType::RGBInteger(ints.0, ints.1, ints.2) } } impl Into> for (f64, f64, f64, f64) { fn into(self) -> ColorType { let ints = from_argb_floats(self.0, self.1, self.2, self.3); - ColorType::ARGBIntegerColor(ints.0, ints.1, ints.2, ints.3) + ColorType::ARGBInteger(ints.0, ints.1, ints.2, ints.3) } } impl Into> for Vec { fn into(self) -> ColorType { - ColorType::VariableRGBColor(self) + ColorType::VariableRGBIntegers(self) } } impl Into> for Vec { fn into(self) -> ColorType { - ColorType::VariableARGBColor(self) + ColorType::VariableARGBIntegers(self) } } impl Into> for Vec { fn into(self) -> ColorType { - ColorType::VariableIndexColor(self) + ColorType::VariableIndex(self) } } @@ -231,19 +243,19 @@ impl OneWayOwned for ColorType { fn to_one_way_owned(&self) -> ColorType { match self { - RGBColor(s) => RGBColor(s.to_string()), - RGBIntegerColor(r, g, b) => RGBIntegerColor(*r, *g, *b), - VariableRGBColor(d) => VariableRGBColor(d.clone()), + RGBString(s) => RGBString(s.to_string()), + RGBInteger(r, g, b) => RGBInteger(*r, *g, *b), + VariableRGBIntegers(d) => VariableRGBIntegers(d.clone()), PaletteFracColor(_) => todo!(), PaletteCBColor(_) => todo!(), VariablePaletteColor(d) => VariablePaletteColor(d.clone()), SavedColorMap(s, d) => SavedColorMap(s.to_string(), d.clone()), - VariableIndexColor(d) => VariableIndexColor(d.clone()), - BackgroundColor => BackgroundColor, - IndexColor(n) => IndexColor(*n), + VariableIndex(d) => VariableIndex(d.clone()), + Background => Background, + Index(n) => Index(*n), Black => Black, - ARGBIntegerColor(a, r, g, b) => ARGBIntegerColor(*a, *r, *g, *b), - VariableARGBColor(d) => VariableARGBColor(d.clone()), + ARGBInteger(a, r, g, b) => ARGBInteger(*a, *r, *g, *b), + VariableARGBIntegers(d) => VariableARGBIntegers(d.clone()), } } } @@ -251,19 +263,19 @@ impl OneWayOwned for ColorType { impl ColorType { pub fn to_ref(&self) -> ColorType<&str> { match self { - RGBColor(s) => RGBColor(s), - RGBIntegerColor(r, g, b) => RGBIntegerColor(*r, *g, *b), - VariableRGBColor(d) => VariableRGBColor(d.to_vec()), - VariableARGBColor(d) => VariableARGBColor(d.to_vec()), + RGBString(s) => RGBString(s), + RGBInteger(r, g, b) => RGBInteger(*r, *g, *b), + VariableRGBIntegers(d) => VariableRGBIntegers(d.to_vec()), + VariableARGBIntegers(d) => VariableARGBIntegers(d.to_vec()), PaletteFracColor(_) => todo!(), PaletteCBColor(_) => todo!(), VariablePaletteColor(d) => VariablePaletteColor(d.to_vec()), SavedColorMap(s, d) => SavedColorMap(s, d.to_vec()), - VariableIndexColor(d) => VariableIndexColor(d.to_vec()), - BackgroundColor => todo!(), - IndexColor(n) => IndexColor(*n), + VariableIndex(d) => VariableIndex(d.to_vec()), + Background => todo!(), + Index(n) => Index(*n), Black => Black, - ARGBIntegerColor(a, r, g, b) => ARGBIntegerColor(*a, *r, *g, *b), + ARGBInteger(a, r, g, b) => ARGBInteger(*a, *r, *g, *b), } } } From 9be40641d00460ea9f203ce661458fec5aa121dd Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Mon, 24 Feb 2025 22:06:54 +0000 Subject: [PATCH 18/34] Complete color example and modify common code to allow transpareny to work --- gnuplot/examples/color.rs | 83 +++++++++++++++++++++++++++++++------- gnuplot/src/axes2d.rs | 4 +- gnuplot/src/axes_common.rs | 23 +++++++---- gnuplot/src/color.rs | 27 ++++++++++--- 4 files changed, 108 insertions(+), 29 deletions(-) diff --git a/gnuplot/examples/color.rs b/gnuplot/examples/color.rs index 9d34a9e8..549de2e9 100644 --- a/gnuplot/examples/color.rs +++ b/gnuplot/examples/color.rs @@ -1,34 +1,87 @@ +use std::{fmt::Debug, iter}; + // This file is released into Public Domain. use crate::common::*; use gnuplot::*; mod common; +fn color_name(color: &PlotOption) -> String{ + let s = format!("{:?}", color).replace("ColorOpt(", ""); + let mut chars = s.chars(); + chars.next_back(); + chars.as_str().to_string() +} + fn example(c: Common) { - let x = 0..10; + let x = 0..5; - let mut fg = Figure::new(); - let ax = fg.axes2d(); - ax.set_title("Demo of RGBString in various forms", &[]); - ax.set_legend(Graph(0.5), Graph(0.9), &[], &[]); let colors = [ - Color("black"), - Color(ColorType::RGBString("black")), - Color("red"), - Color(ColorType::RGBString("#ff0000")), // red using Hex coded RRGGBB - Color(ColorType::RGBString("#ff8888")), // pink using Hex coded RRGGBB - Color(ColorType::RGBString("#88ff0000")), // pink using Hex coded AARRGGBB - Color(ColorType::RGBString("#ff0000")), // red using Hex coded RRGGBB + Color("black"), // Conversion to RGBString is implicit + Color(ColorType::RGBString("black")), // Explicit use of RGBString + Color("red"), // Conversion to RGBString is implicit + Color(RGBString("#ff0000")), // red using Hex coded RRGGBB + Color(RGBString("#00ff0000")), // red using Hex coded AARRGGBB + Color("#ff8888"), // pink using Hex coded RRGGBB. Conversion to RGBString is implict + Color("#88ff0000"), // pink using Hex coded AARRGGBB. Conversion to RGBString is implict + Color(ColorType::RGBString("#ffff0000")), // transparent using Hex coded AARRGGBB + Color((128, 0, 255)), // purple using implict RGBInteger + Color(RGBInteger(128, 0, 255)), // purple using explict RGBInteger + Color((0.5, 0.0, 1.0)), // purple using implict float to int conversion + Color(floats_to_rgb(0.5, 0.0, 1.0)), // purple using explicit float to int conversion + Color((128, 128, 0, 255)), // pale purple using implict ARGBInteger + Color(ARGBInteger(128, 128, 0, 255)), // pale purple using explict ARGBInteger + Color((0.5, 0.5, 0.0, 1.0)), // pale purple using implict float to int conversion + Color(floats_to_argb(0.5, 0.5, 0.0, 1.0)), // pale purple using explicit float to int conversion ]; + let mut fg = Figure::new(); + let ax = fg.axes2d(); + ax.set_title( + "Demo of RGBString in various forms\nSee code comments for how to construct the colors", + &[], + ); + ax.set_x_range(Fix(-10.0), Auto); + ax.set_legend(Graph(0.6), Graph(0.8), &[], &[Font("Arial", 14.0)]); + + + let n_colors = colors.len(); for (i, color) in colors.into_iter().enumerate() { - ax.lines_points( + ax.box_xy_error_delta( x.clone(), - x.clone().map(|v| v * 2 + i), - &[Caption(&format!("{}: {:?}", i, color)), color], + iter::repeat((n_colors - 1) - i), + iter::repeat(0.4), + iter::repeat(0.2), //x.clone().map(|x| (((3 + x) as f64) / 3.0).rem(0.8)), + &[ + Caption(&color_name(&color)), + LineWidth(1.0), + BorderColor("black"), + color, + ], ); } + // Draw line across the boxes in fixed black and background colors + ax.lines( + [0, 0], + [0, n_colors - 1], + &[ + LineWidth(7.0), + Color(Black), + Caption(&color_name(&Color(Black))), + ], + ); + + ax.lines( + [4, 4], + [0, n_colors - 1], + &[ + LineWidth(7.0), + Color(Background), + Caption(&color_name(&Color(Background))), + ], + ); + c.show(&mut fg, "rgb_color"); } diff --git a/gnuplot/src/axes2d.rs b/gnuplot/src/axes2d.rs index 559dde85..5f76b4dc 100644 --- a/gnuplot/src/axes2d.rs +++ b/gnuplot/src/axes2d.rs @@ -191,7 +191,7 @@ impl ArrowData } w.write_str(",12"); - AxesCommonData::write_color_options(w, &self.plot_options, Some(ColorType::Black)); + AxesCommonData::write_color_options(w, &self.plot_options, false, Some(ColorType::Black)); AxesCommonData::write_line_options( w, &self.plot_options, @@ -236,7 +236,7 @@ impl BorderOptions write!(writer, "{}", f); writer.write_str(if self.front { " front " } else { " back " }); - AxesCommonData::write_color_options(writer, &self.options, Some(ColorType::Black)); + AxesCommonData::write_color_options(writer, &self.options, false, Some(ColorType::Black)); AxesCommonData::write_line_options(writer, &self.options, version); writer.write_str("\n"); diff --git a/gnuplot/src/axes_common.rs b/gnuplot/src/axes_common.rs index 6e3a1f56..2c9691aa 100644 --- a/gnuplot/src/axes_common.rs +++ b/gnuplot/src/axes_common.rs @@ -207,7 +207,16 @@ impl PlotElement if !is_pattern { - writer.write_str("transparent solid"); + let mut color_has_alpha = false; + first_opt! {self.options, + ColorOpt(ref c) => { + color_has_alpha = c.has_alpha() + } + } + if !color_has_alpha{ + writer.write_str("transparent "); + } + writer.write_str("solid"); let mut alpha = 1.; first_opt! {self.options, FillAlpha(a) => @@ -255,7 +264,7 @@ impl PlotElement } } - AxesCommonData::write_color_options(writer, &self.options, None); + AxesCommonData::write_color_options(writer, &self.options, self.plot_type.is_fill(), None); writer.write_str(" t \""); first_opt! {self.options, @@ -680,7 +689,7 @@ impl AxisData w.write_str(self.axis.get_axis_str()); w.write_str("zeroaxis "); - AxesCommonData::write_color_options(w, &self.options, Some(ColorType::RGBString("black".into()))); + AxesCommonData::write_color_options(w, &self.options, false, Some(ColorType::RGBString("black".into()))); AxesCommonData::write_line_options(w, &self.options, version); } else @@ -1141,10 +1150,10 @@ impl AxesCommonData } AxesCommonData::write_line_options(c, &self.grid_options, version); - AxesCommonData::write_color_options(c, &self.grid_options, None); + AxesCommonData::write_color_options(c, &self.grid_options, false, None); c.write_str(", "); AxesCommonData::write_line_options(c, &self.minor_grid_options, version); - AxesCommonData::write_color_options(c, &self.minor_grid_options, None); + AxesCommonData::write_color_options(c, &self.minor_grid_options, false, None); c.write_str("\n"); } } @@ -1188,7 +1197,7 @@ impl AxesCommonData } pub fn write_color_options( - c: &mut dyn Writer, options: &[PlotOption], default: Option, + c: &mut dyn Writer, options: &[PlotOption], is_fill: bool, default: Option, ) { let mut col = default.as_ref(); @@ -1200,7 +1209,7 @@ impl AxesCommonData } if let Some(s) = col { - write!(c, " lc {}", s.command()); + write!(c, " {main_type} {}", s.command()); } } diff --git a/gnuplot/src/color.rs b/gnuplot/src/color.rs index 90b271a0..fab86470 100644 --- a/gnuplot/src/color.rs +++ b/gnuplot/src/color.rs @@ -101,7 +101,7 @@ impl ColorType { VariablePaletteColor(_) => String::from("palette z"), SavedColorMap(s, _) => format!("palette {s}"), VariableIndex(_) => String::from("variable"), - Background => todo!(), + Background => String::from("background"), Index(n) => format!("{}", n), Black => String::from("black"), } @@ -141,6 +141,23 @@ impl ColorType { _ => false, } } + + pub fn has_alpha(&self) -> bool { + match self { + RGBString(s) => { + let s = s.to_string(); + if s.starts_with("0x") && s.chars().count() == 10 { + true + } else if s.starts_with("#") && s.chars().count() == 9 { + true + } else { + false + } + } + ARGBInteger(_, _, _, _) | VariableARGBIntegers(_) => true, + _ => false, + } + } } fn from_argb( @@ -159,7 +176,7 @@ fn float_color_to_int(v: f64) -> u8 { ((v * 255.0).round()) as u8 } -fn from_rgb_floats(r: f64, g: f64, b: f64) -> RGBInts { +pub fn floats_to_rgb(r: f64, g: f64, b: f64) -> RGBInts { ( float_color_to_int(r), float_color_to_int(g), @@ -167,7 +184,7 @@ fn from_rgb_floats(r: f64, g: f64, b: f64) -> RGBInts { ) } -fn from_argb_floats(a: f64, r: f64, g: f64, b: f64) -> ARGBInts { +pub fn floats_to_argb(a: f64, r: f64, g: f64, b: f64) -> ARGBInts { ( float_color_to_int(a), float_color_to_int(r), @@ -208,14 +225,14 @@ impl Into> for RGBInts { impl Into> for (f64, f64, f64) { fn into(self) -> ColorType { - let ints = from_rgb_floats(self.0, self.1, self.2); + let ints = floats_to_rgb(self.0, self.1, self.2); ColorType::RGBInteger(ints.0, ints.1, ints.2) } } impl Into> for (f64, f64, f64, f64) { fn into(self) -> ColorType { - let ints = from_argb_floats(self.0, self.1, self.2, self.3); + let ints = floats_to_argb(self.0, self.1, self.2, self.3); ColorType::ARGBInteger(ints.0, ints.1, ints.2, ints.3) } } From eca6c4fd37829b31f4fcaeaf56977d3f761593bb Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Mon, 24 Feb 2025 23:05:51 +0000 Subject: [PATCH 19/34] Conform to nightly formatting rules --- gnuplot/examples/color.rs | 13 +- gnuplot/examples/inverse_api.rs | 6 +- gnuplot/examples/variable_color.rs | 9 +- gnuplot/src/axes2d.rs | 302 +++++++++++------------------ gnuplot/src/axes3d.rs | 12 +- gnuplot/src/axes_common.rs | 47 +++-- gnuplot/src/color.rs | 140 ++++++++----- gnuplot/src/lib.rs | 4 +- gnuplot/src/options.rs | 88 ++++----- 9 files changed, 303 insertions(+), 318 deletions(-) diff --git a/gnuplot/examples/color.rs b/gnuplot/examples/color.rs index 549de2e9..e0a5ac3e 100644 --- a/gnuplot/examples/color.rs +++ b/gnuplot/examples/color.rs @@ -6,14 +6,16 @@ use gnuplot::*; mod common; -fn color_name(color: &PlotOption) -> String{ +fn color_name(color: &PlotOption) -> String +{ let s = format!("{:?}", color).replace("ColorOpt(", ""); let mut chars = s.chars(); chars.next_back(); chars.as_str().to_string() } -fn example(c: Common) { +fn example(c: Common) +{ let x = 0..5; let colors = [ @@ -44,9 +46,9 @@ fn example(c: Common) { ax.set_x_range(Fix(-10.0), Auto); ax.set_legend(Graph(0.6), Graph(0.8), &[], &[Font("Arial", 14.0)]); - let n_colors = colors.len(); - for (i, color) in colors.into_iter().enumerate() { + for (i, color) in colors.into_iter().enumerate() + { ax.box_xy_error_delta( x.clone(), iter::repeat((n_colors - 1) - i), @@ -85,6 +87,7 @@ fn example(c: Common) { c.show(&mut fg, "rgb_color"); } -fn main() { +fn main() +{ Common::new().map(|c| example(c)); } diff --git a/gnuplot/examples/inverse_api.rs b/gnuplot/examples/inverse_api.rs index e857bef9..a02957f7 100644 --- a/gnuplot/examples/inverse_api.rs +++ b/gnuplot/examples/inverse_api.rs @@ -176,12 +176,12 @@ fn example(c: Common) //~ lines(z.clone(), y.clone()).show(); - let mut axes = (lines(z.clone(), y.clone()), lines(z.clone(), x.clone())) - .to_axes2d(); + let mut axes = (lines(z.clone(), y.clone()), lines(z.clone(), x.clone())).to_axes2d(); axes.title("Test"); axes.x(axis().log_scale(Some(10.))); - if !c.no_show { + if !c.no_show + { axes.show(); } } diff --git a/gnuplot/examples/variable_color.rs b/gnuplot/examples/variable_color.rs index 8ce89555..14cdd544 100644 --- a/gnuplot/examples/variable_color.rs +++ b/gnuplot/examples/variable_color.rs @@ -18,7 +18,8 @@ static CANDLESTICKS_STR: &str = "1 1.5 2 2.4 4 6. 9 1.5 2 2.4 3 3.5 10 2.7 3 3.5 4 4.3"; -fn example(c: Common) { +fn example(c: Common) +{ let data: Vec> = CANDLESTICKS_STR .split("\n") .map(|line| { @@ -78,7 +79,8 @@ fn example(c: Common) { Color(d1.iter().map(argb_formula).collect::>()), "VariableARGBString", ), - ] { + ] + { let mut fg = Figure::new(); let ax = fg.axes2d(); ax.set_title( @@ -205,6 +207,7 @@ fn example(c: Common) { c.show(&mut fg, "variable_palette"); } -fn main() { +fn main() +{ Common::new().map(|c| example(c)); } diff --git a/gnuplot/src/axes2d.rs b/gnuplot/src/axes2d.rs index 5f76b4dc..a42f923b 100644 --- a/gnuplot/src/axes2d.rs +++ b/gnuplot/src/axes2d.rs @@ -380,15 +380,9 @@ impl Axes2D ) -> &'l mut Self { let (data, num_rows, num_cols) = generate_data!(options, x, y); - self.common.elems.push( - PlotElement::new_plot( - Lines, - data, - num_rows, - num_cols, - options, - ) - ); + self.common.elems.push(PlotElement::new_plot( + Lines, data, num_rows, num_cols, options, + )); self } @@ -412,15 +406,9 @@ impl Axes2D ) -> &'l mut Self { let (data, num_rows, num_cols) = generate_data!(options, x, y); - self.common.elems.push( - PlotElement::new_plot( - Points, - data, - num_rows, - num_cols, - options, - ) - ); + self.common.elems.push(PlotElement::new_plot( + Points, data, num_rows, num_cols, options, + )); self } @@ -440,15 +428,13 @@ impl Axes2D ) -> &'l mut Self { let (data, num_rows, num_cols) = generate_data!(options, x, y); - self.common.elems.push( - PlotElement::new_plot( - LinesPoints, - data, - num_rows, - num_cols, - options, - ) - ); + self.common.elems.push(PlotElement::new_plot( + LinesPoints, + data, + num_rows, + num_cols, + options, + )); self } @@ -476,15 +462,9 @@ impl Axes2D ) -> &'l mut Self { let (data, num_rows, num_cols) = generate_data!(options, x, y, x_error); - self.common.elems.push( - PlotElement::new_plot( - XErrorBars, - data, - num_rows, - num_cols, - options, - ) - ); + self.common.elems.push(PlotElement::new_plot( + XErrorBars, data, num_rows, num_cols, options, + )); self } @@ -512,15 +492,9 @@ impl Axes2D ) -> &'l mut Self { let (data, num_rows, num_cols) = generate_data!(options, x, y, y_error); - self.common.elems.push( - PlotElement::new_plot( - YErrorBars, - data, - num_rows, - num_cols, - options, - ) - ); + self.common.elems.push(PlotElement::new_plot( + YErrorBars, data, num_rows, num_cols, options, + )); self } @@ -550,19 +524,16 @@ impl Axes2D ) -> &'l mut Self { let (data, num_rows, num_cols) = generate_data!(options, x, y, x_error, y_error); - self.common.elems.push( - PlotElement::new_plot( - XYErrorBars, - data, - num_rows, - num_cols, - options, - ) - ); + self.common.elems.push(PlotElement::new_plot( + XYErrorBars, + data, + num_rows, + num_cols, + options, + )); self } - /// Plot a 2D scatter-plot with a point standing in for each data point and lines connecting each data point. /// Additionally, error bars are attached to each data point in the X direction. /// # Arguments @@ -589,15 +560,13 @@ impl Axes2D ) -> &'l mut Self { let (data, num_rows, num_cols) = generate_data!(options, x, y, x_error); - self.common.elems.push( - PlotElement::new_plot( - XErrorLines, - data, - num_rows, - num_cols, - options, - ) - ); + self.common.elems.push(PlotElement::new_plot( + XErrorLines, + data, + num_rows, + num_cols, + options, + )); self } @@ -627,15 +596,14 @@ impl Axes2D ) -> &'l mut Self { let (data, num_rows, num_cols) = generate_data!(options, x, y, y_error); - self.common.elems.push( - PlotElement::new_plot( - YErrorLines, - data, - num_rows, - num_cols, - options, - ) - );self + self.common.elems.push(PlotElement::new_plot( + YErrorLines, + data, + num_rows, + num_cols, + options, + )); + self } /// Plot a 2D scatter-plot of two curves (bound by `y_lo` and `y_hi`) with a filled region between them. @@ -663,15 +631,13 @@ impl Axes2D ) -> &'l mut Self { let (data, num_rows, num_cols) = generate_data!(options, x, y_lo, y_hi); - self.common.elems.push( - PlotElement::new_plot( - FillBetween, - data, - num_rows, - num_cols, - options, - ) - ); + self.common.elems.push(PlotElement::new_plot( + FillBetween, + data, + num_rows, + num_cols, + options, + )); self } @@ -697,15 +663,13 @@ impl Axes2D ) -> &'l mut Self { let (data, num_rows, num_cols) = generate_data!(options, x, y); - self.common.elems.push( - PlotElement::new_plot( - FillBetween, - data, - num_rows, - num_cols, - options, - ) - ); + self.common.elems.push(PlotElement::new_plot( + FillBetween, + data, + num_rows, + num_cols, + options, + )); self } @@ -732,15 +696,9 @@ impl Axes2D ) -> &'l mut Self { let (data, num_rows, num_cols) = generate_data!(options, x, y); - self.common.elems.push( - PlotElement::new_plot( - Boxes, - data, - num_rows, - num_cols, - options, - ) - ); + self.common.elems.push(PlotElement::new_plot( + Boxes, data, num_rows, num_cols, options, + )); self } @@ -770,15 +728,9 @@ impl Axes2D ) -> &'l mut Self { let (data, num_rows, num_cols) = generate_data!(options, x, y, w); - self.common.elems.push( - PlotElement::new_plot( - Boxes, - data, - num_rows, - num_cols, - options, - ) - ); + self.common.elems.push(PlotElement::new_plot( + Boxes, data, num_rows, num_cols, options, + )); self } @@ -810,15 +762,13 @@ impl Axes2D ) -> &'l mut Self { let (data, num_rows, num_cols) = generate_data!(options, x, y, y_error); - self.common.elems.push( - PlotElement::new_plot( - BoxErrorBars, - data, - num_rows, - num_cols, - options, - ) - ); + self.common.elems.push(PlotElement::new_plot( + BoxErrorBars, + data, + num_rows, + num_cols, + options, + )); self } @@ -853,15 +803,13 @@ impl Axes2D ) -> &'l mut Self { let (data, num_rows, num_cols) = generate_data!(options, x, y, y_error, x_delta); - self.common.elems.push( - PlotElement::new_plot( - BoxErrorBars, - data, - num_rows, - num_cols, - options, - ) - ); + self.common.elems.push(PlotElement::new_plot( + BoxErrorBars, + data, + num_rows, + num_cols, + options, + )); self } @@ -899,15 +847,13 @@ impl Axes2D // xdelta (box width). If you supply four values rather than five, the fourth is interpreted as width. let dummy_width = iter::repeat(-1.0); let (data, num_rows, num_cols) = generate_data!(options, x, y, y_low, y_high, dummy_width); - self.common.elems.push( - PlotElement::new_plot( - BoxErrorBars, - data, - num_rows, - num_cols, - options, - ) - ); + self.common.elems.push(PlotElement::new_plot( + BoxErrorBars, + data, + num_rows, + num_cols, + options, + )); self } @@ -945,15 +891,13 @@ impl Axes2D ) -> &'l mut Self { let (data, num_rows, num_cols) = generate_data!(options, x, y, y_low, y_high, x_delta); - self.common.elems.push( - PlotElement::new_plot( - BoxErrorBars, - data, - num_rows, - num_cols, - options, - ) - ); + self.common.elems.push(PlotElement::new_plot( + BoxErrorBars, + data, + num_rows, + num_cols, + options, + )); self } @@ -990,20 +934,14 @@ impl Axes2D box_max: BoxMax, options: &[PlotOption<&str>], ) -> &'l mut Self { - let (data, num_rows, num_cols) = generate_data!( + let (data, num_rows, num_cols) = + generate_data!(options, x, box_min, whisker_min, whisker_max, box_max); + self.common.elems.push(PlotElement::new_plot( + BoxAndWhisker, + data, + num_rows, + num_cols, options, - x, - box_min, - whisker_min, - whisker_max, - box_max); - self.common.elems.push( - PlotElement::new_plot( - BoxAndWhisker, - data, - num_rows, - num_cols, - options, )); self } @@ -1053,13 +991,12 @@ impl Axes2D box_max, box_width ); - self.common.elems.push( - PlotElement::new_plot( - BoxAndWhisker, - data, - num_rows, - num_cols, - options, + self.common.elems.push(PlotElement::new_plot( + BoxAndWhisker, + data, + num_rows, + num_cols, + options, )); self } @@ -1093,15 +1030,9 @@ impl Axes2D ) -> &'l mut Self { let (data, num_rows, num_cols) = generate_data!(options, x, y, x_delta, y_delta); - self.common.elems.push( - PlotElement::new_plot( - BoxXYError, - data, - num_rows, - num_cols, - options, - ) - ); + self.common.elems.push(PlotElement::new_plot( + BoxXYError, data, num_rows, num_cols, options, + )); self } @@ -1140,24 +1071,11 @@ impl Axes2D options: &[PlotOption<&str>], ) -> &'l mut Self { - let (data, num_rows, num_cols) = generate_data!( - options, - x, - y, - x_low, - x_high, - y_low, - y_high - ); - self.common.elems.push( - PlotElement::new_plot( - BoxXYError, - data, - num_rows, - num_cols, - options, - ) - ); + let (data, num_rows, num_cols) = + generate_data!(options, x, y, x_low, x_high, y_low, y_high); + self.common.elems.push(PlotElement::new_plot( + BoxXYError, data, num_rows, num_cols, options, + )); self } diff --git a/gnuplot/src/axes3d.rs b/gnuplot/src/axes3d.rs index c47567fc..4f4e9476 100644 --- a/gnuplot/src/axes3d.rs +++ b/gnuplot/src/axes3d.rs @@ -121,11 +121,7 @@ impl Axes3D { let (data, num_rows, num_cols) = generate_data!(options, x, y, z); self.common.elems.push(PlotElement::new_plot( - Points, - data, - num_rows, - num_cols, - options, + Points, data, num_rows, num_cols, options, )); self } @@ -154,11 +150,7 @@ impl Axes3D { let (data, num_rows, num_cols) = generate_data!(options, x, y, z); self.common.elems.push(PlotElement::new_plot( - Lines, - data, - num_rows, - num_cols, - options, + Lines, data, num_rows, num_cols, options, )); self } diff --git a/gnuplot/src/axes_common.rs b/gnuplot/src/axes_common.rs index 2c9691aa..3ef05f6d 100644 --- a/gnuplot/src/axes_common.rs +++ b/gnuplot/src/axes_common.rs @@ -31,8 +31,10 @@ pub struct PlotElement impl PlotElement { pub fn new_plot<'l>( - plot_type: PlotType, data: Vec, num_rows: usize, num_cols: usize, options: &[PlotOption<&str>], - ) -> PlotElement{ + plot_type: PlotType, data: Vec, num_rows: usize, num_cols: usize, + options: &[PlotOption<&str>], + ) -> PlotElement + { PlotElement { data, num_rows, @@ -213,7 +215,8 @@ impl PlotElement color_has_alpha = c.has_alpha() } } - if !color_has_alpha{ + if !color_has_alpha + { writer.write_str("transparent "); } writer.write_str("solid"); @@ -611,7 +614,8 @@ impl PlotType | XErrorLines | Boxes | YErrorLines | BoxAndWhisker - | BoxXYError | BoxErrorBars | Polygons + | BoxXYError | BoxErrorBars + | Polygons ) } @@ -619,7 +623,12 @@ impl PlotType { matches!( *self, - Points | LinesPoints | XErrorLines | YErrorLines | XErrorBars | YErrorBars | XYErrorBars + Points + | LinesPoints + | XErrorLines + | YErrorLines + | XErrorBars | YErrorBars + | XYErrorBars ) } @@ -689,7 +698,12 @@ impl AxisData w.write_str(self.axis.get_axis_str()); w.write_str("zeroaxis "); - AxesCommonData::write_color_options(w, &self.options, false, Some(ColorType::RGBString("black".into()))); + AxesCommonData::write_color_options( + w, + &self.options, + false, + Some(ColorType::RGBString("black".into())), + ); AxesCommonData::write_line_options(w, &self.options, version); } else @@ -1090,7 +1104,7 @@ pub struct AxesCommonData pub aspect_ratio: AutoOption, pub margins: Margins, pub palette: PaletteType>, - pub colormaps: Vec<(String, PaletteType>)> + pub colormaps: Vec<(String, PaletteType>)>, } impl AxesCommonData @@ -1197,9 +1211,12 @@ impl AxesCommonData } pub fn write_color_options( - c: &mut dyn Writer, options: &[PlotOption], is_fill: bool, default: Option, + c: &mut dyn Writer, options: &[PlotOption], is_fill: bool, + default: Option, ) { + let main_type = if is_fill { "fillcolor" } else { "linecolor" }; + let mut col = default.as_ref(); first_opt! {options, ColorOpt(ref s) => @@ -1249,10 +1266,12 @@ impl AxesCommonData self.margins.write_out_commands(w); self.palette.write_out_commands(w); - if !self.colormaps.is_empty(){ + if !self.colormaps.is_empty() + { // save previous palette writeln!(w, "set colormap new __ORIGINAL_COLORMAP__"); - for (name, map) in &self.colormaps { + for (name, map) in &self.colormaps + { // set palette to the requested map map.write_out_commands(w); // save current palette to colormap with the requested name @@ -2070,9 +2089,13 @@ pub trait AxesCommon: AxesCommonPrivate /// /// # Arguments /// * `name` - The name with which to save the colormap /// * `palette` - What palette type to use - fn create_colormap(&mut self, name: &str, palette: PaletteType<&[(f32, f32, f32, f32)]>) -> &mut Self + fn create_colormap( + &mut self, name: &str, palette: PaletteType<&[(f32, f32, f32, f32)]>, + ) -> &mut Self { - self.get_common_data_mut().colormaps.push((name.to_owned(), palette.to_one_way_owned())); + self.get_common_data_mut() + .colormaps + .push((name.to_owned(), palette.to_one_way_owned())); self } } diff --git a/gnuplot/src/color.rs b/gnuplot/src/color.rs index fab86470..2daf444c 100644 --- a/gnuplot/src/color.rs +++ b/gnuplot/src/color.rs @@ -30,7 +30,8 @@ pub type ARGBInts = ( /// See example usages of these colors in `color.rs`, `variable_color.rs` in the /// [Examples folder](https://github.com/SiegeLord/RustGnuplot/tree/master/gnuplot/examples) on Github #[derive(Debug, Clone, PartialEq, PartialOrd)] -pub enum ColorType { +pub enum ColorType +{ /// string (`&str` or `String`, but usually created with `&str`) in one of the following gnuplot-supported formats /// - colorname --- e.g. "blue" [See the gnuplot /// [list of colornames](http://gnuplot.info/docs_6.0/loc11229.html)] @@ -87,10 +88,13 @@ pub enum ColorType { Black, } -impl ColorType { +impl ColorType +{ /// Returns the gnuplot string that will produce the requested color - pub fn command(&self) -> String { - match self { + pub fn command(&self) -> String + { + match self + { RGBString(s) => format!(r#"rgb "{}""#, s), RGBInteger(r, g, b) => format!(r#"rgb {}"#, from_argb(0, *r, *g, *b)), ARGBInteger(a, r, g, b) => format!(r#"rgb {}"#, from_argb(*a, *r, *g, *b)), @@ -107,8 +111,10 @@ impl ColorType { } } - pub fn data(&self) -> Vec { - match self { + pub fn data(&self) -> Vec + { + match self + { RGBString(_) => panic!("data() called on non-variable color type."), RGBInteger(_, _, _) => panic!("data() called on non-variable color type."), ARGBInteger(_, _, _, _) => panic!("data() called on non-variable color type."), @@ -131,8 +137,10 @@ impl ColorType { } } - pub fn is_variable(&self) -> bool { - match self { + pub fn is_variable(&self) -> bool + { + match self + { VariableRGBIntegers(_) | VariableARGBIntegers(_) | VariableIndex(_) @@ -142,15 +150,23 @@ impl ColorType { } } - pub fn has_alpha(&self) -> bool { - match self { - RGBString(s) => { + pub fn has_alpha(&self) -> bool + { + match self + { + RGBString(s) => + { let s = s.to_string(); - if s.starts_with("0x") && s.chars().count() == 10 { + if s.starts_with("0x") && s.chars().count() == 10 + { true - } else if s.starts_with("#") && s.chars().count() == 9 { + } + else if s.starts_with("#") && s.chars().count() == 9 + { true - } else { + } + else + { false } } @@ -160,14 +176,16 @@ impl ColorType { } } -fn from_argb( - a: ColorComponent, r: ColorComponent, g: ColorComponent, b: ColorComponent, -) -> ColorInt { +fn from_argb(a: ColorComponent, r: ColorComponent, g: ColorComponent, b: ColorComponent) + -> ColorInt +{ ((a as ColorInt) << 24) + ((r as ColorInt) << 16) + ((g as ColorInt) << 8) + (b as ColorInt) } -fn float_color_to_int(v: f64) -> u8 { - if v < 0.0 || v > 1.0 { +fn float_color_to_int(v: f64) -> u8 +{ + if v < 0.0 || v > 1.0 + { panic!( "Float value must be greater than zero and less than one. Actual value: {}", v @@ -176,7 +194,8 @@ fn float_color_to_int(v: f64) -> u8 { ((v * 255.0).round()) as u8 } -pub fn floats_to_rgb(r: f64, g: f64, b: f64) -> RGBInts { +pub fn floats_to_rgb(r: f64, g: f64, b: f64) -> RGBInts +{ ( float_color_to_int(r), float_color_to_int(g), @@ -184,7 +203,8 @@ pub fn floats_to_rgb(r: f64, g: f64, b: f64) -> RGBInts { ) } -pub fn floats_to_argb(a: f64, r: f64, g: f64, b: f64) -> ARGBInts { +pub fn floats_to_argb(a: f64, r: f64, g: f64, b: f64) -> ARGBInts +{ ( float_color_to_int(a), float_color_to_int(r), @@ -193,73 +213,96 @@ pub fn floats_to_argb(a: f64, r: f64, g: f64, b: f64) -> ARGBInts { ) } -impl<'l> Into> for &'l str { - fn into(self) -> ColorType { +impl<'l> Into> for &'l str +{ + fn into(self) -> ColorType + { ColorType::RGBString(String::from(self)) } } -impl<'l> Into> for String { - fn into(self) -> ColorType { +impl<'l> Into> for String +{ + fn into(self) -> ColorType + { ColorType::RGBString(self) } } -impl<'l> Into> for &'l str { - fn into(self) -> ColorType<&'l str> { +impl<'l> Into> for &'l str +{ + fn into(self) -> ColorType<&'l str> + { ColorType::RGBString(self) } } -impl Into> for ARGBInts { - fn into(self) -> ColorType { +impl Into> for ARGBInts +{ + fn into(self) -> ColorType + { ColorType::ARGBInteger(self.0, self.1, self.2, self.3) } } -impl Into> for RGBInts { - fn into(self) -> ColorType { +impl Into> for RGBInts +{ + fn into(self) -> ColorType + { ColorType::RGBInteger(self.0, self.1, self.2) } } -impl Into> for (f64, f64, f64) { - fn into(self) -> ColorType { +impl Into> for (f64, f64, f64) +{ + fn into(self) -> ColorType + { let ints = floats_to_rgb(self.0, self.1, self.2); ColorType::RGBInteger(ints.0, ints.1, ints.2) } } -impl Into> for (f64, f64, f64, f64) { - fn into(self) -> ColorType { +impl Into> for (f64, f64, f64, f64) +{ + fn into(self) -> ColorType + { let ints = floats_to_argb(self.0, self.1, self.2, self.3); ColorType::ARGBInteger(ints.0, ints.1, ints.2, ints.3) } } -impl Into> for Vec { - fn into(self) -> ColorType { +impl Into> for Vec +{ + fn into(self) -> ColorType + { ColorType::VariableRGBIntegers(self) } } -impl Into> for Vec { - fn into(self) -> ColorType { +impl Into> for Vec +{ + fn into(self) -> ColorType + { ColorType::VariableARGBIntegers(self) } } -impl Into> for Vec { - fn into(self) -> ColorType { +impl Into> for Vec +{ + fn into(self) -> ColorType + { ColorType::VariableIndex(self) } } -impl OneWayOwned for ColorType { +impl OneWayOwned for ColorType +{ type Output = ColorType; - fn to_one_way_owned(&self) -> ColorType { - match self { + fn to_one_way_owned(&self) -> ColorType + { + match self + { RGBString(s) => RGBString(s.to_string()), RGBInteger(r, g, b) => RGBInteger(*r, *g, *b), VariableRGBIntegers(d) => VariableRGBIntegers(d.clone()), @@ -277,9 +320,12 @@ impl OneWayOwned for ColorType { } } -impl ColorType { - pub fn to_ref(&self) -> ColorType<&str> { - match self { +impl ColorType +{ + pub fn to_ref(&self) -> ColorType<&str> + { + match self + { RGBString(s) => RGBString(s), RGBInteger(r, g, b) => RGBInteger(*r, *g, *b), VariableRGBIntegers(d) => VariableRGBIntegers(d.to_vec()), diff --git a/gnuplot/src/lib.rs b/gnuplot/src/lib.rs index 5da7b93a..345f544b 100644 --- a/gnuplot/src/lib.rs +++ b/gnuplot/src/lib.rs @@ -26,8 +26,8 @@ fg.show(); pub use crate::axes2d::Axes2D; pub use crate::axes3d::Axes3D; pub use crate::axes_common::AxesCommon; -pub use crate::coordinates::*; pub use crate::color::*; +pub use crate::coordinates::*; pub use crate::datatype::*; pub use crate::error_types::*; pub use crate::figure::*; @@ -39,6 +39,7 @@ mod util; mod axes2d; mod axes3d; mod axes_common; +mod color; mod coordinates; mod datatype; mod error_types; @@ -46,4 +47,3 @@ mod figure; mod options; pub mod palettes; mod writer; -mod color; \ No newline at end of file diff --git a/gnuplot/src/options.rs b/gnuplot/src/options.rs index e3c6c229..b682dce4 100644 --- a/gnuplot/src/options.rs +++ b/gnuplot/src/options.rs @@ -79,17 +79,17 @@ pub enum PlotOption #[allow(non_snake_case)] /// TODO -pub fn Color<'l, T: IntoColor<&'l str>>(c: T)->PlotOption<&'l str>{ +pub fn Color<'l, T: IntoColor<&'l str>>(c: T) -> PlotOption<&'l str> +{ ColorOpt(c.into()) } #[allow(non_snake_case)] -/// TODO -pub fn BorderColor<'l, T: IntoColor<&'l str>>(c: T)->PlotOption<&'l str>{ +pub fn BorderColor<'l, T: IntoColor<&'l str>>(c: T) -> PlotOption<&'l str> +{ BorderColorOpt(c.into()) } - impl<'l> OneWayOwned for PlotOption<&'l str> { type Output = PlotOption; @@ -470,64 +470,64 @@ pub const HOT: PaletteType<&'static [(f32, f32, f32, f32)]> = Formula(34, 35, 36 /// A nice default for a cube helix pub const HELIX: PaletteType<&'static [(f32, f32, f32, f32)]> = CubeHelix(0.5, -0.8, 2.0, 1.0); -impl PaletteType>{ +impl PaletteType> +{ pub fn write_out_commands(&self, w: &mut dyn Writer) { match *self + { + Gray(gamma) => { - Gray(gamma) => - { - assert!(gamma > 0.0, "Gamma must be positive"); - writeln!(w, "set palette gray gamma {:.12e}", gamma); - } - Formula(r, g, b) => - { - assert!(r >= -36 && r <= 36, "Invalid r formula!"); - assert!(g >= -36 && g <= 36, "Invalid g formula!"); - assert!(b >= -36 && b <= 36, "Invalid b formula!"); - writeln!(w, "set palette rgbformulae {},{},{}", r, g, b); - } - CubeHelix(start, rev, sat, gamma) => - { - assert!(sat >= 0.0, "Saturation must be non-negative"); - assert!(gamma > 0.0, "Gamma must be positive"); - writeln!( + assert!(gamma > 0.0, "Gamma must be positive"); + writeln!(w, "set palette gray gamma {:.12e}", gamma); + } + Formula(r, g, b) => + { + assert!(r >= -36 && r <= 36, "Invalid r formula!"); + assert!(g >= -36 && g <= 36, "Invalid g formula!"); + assert!(b >= -36 && b <= 36, "Invalid b formula!"); + writeln!(w, "set palette rgbformulae {},{},{}", r, g, b); + } + CubeHelix(start, rev, sat, gamma) => + { + assert!(sat >= 0.0, "Saturation must be non-negative"); + assert!(gamma > 0.0, "Gamma must be positive"); + writeln!( w, "set palette cubehelix start {:.12e} cycles {:.12e} saturation {:.12e} gamma {:.12e}", start, rev, sat, gamma ); + } + Custom(ref entries) => + { + if entries.len() < 2 + { + panic!("Need at least 2 elements in a custom palette"); } - Custom(ref entries) => + write!(w, "set palette defined ("); + + let mut first = true; + let mut old_x = 0.0; + for &(x, r, g, b) in entries { - if entries.len() < 2 + if first { - panic!("Need at least 2 elements in a custom palette"); + old_x = x; + first = false; } - write!(w, "set palette defined ("); - - let mut first = true; - let mut old_x = 0.0; - for &(x, r, g, b) in entries + else { - if first - { - old_x = x; - first = false; - } - else - { - write!(w, ","); - } - assert!(x >= old_x, "The gray levels must be non-decreasing!"); - old_x = x; - - write!(w, "{:.12e} {:.12e} {:.12e} {:.12e}", x, r, g, b); + write!(w, ","); } + assert!(x >= old_x, "The gray levels must be non-decreasing!"); + old_x = x; - writeln!(w, ")"); + write!(w, "{:.12e} {:.12e} {:.12e} {:.12e}", x, r, g, b); } + writeln!(w, ")"); } } + } } /// Gnuplot version identifier. This is used to handle version-specific From 3d1f2134e2bb90de56f058b0ae3816424eb409ec Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Tue, 25 Feb 2025 18:34:30 +0000 Subject: [PATCH 20/34] Add TextColor functions --- gnuplot/examples/color.rs | 8 +++++++- gnuplot/examples/multiple_axes.rs | 8 ++++---- gnuplot/src/axes2d.rs | 6 ++---- gnuplot/src/axes_common.rs | 4 ++-- gnuplot/src/options.rs | 11 +++++++++-- 5 files changed, 24 insertions(+), 13 deletions(-) diff --git a/gnuplot/examples/color.rs b/gnuplot/examples/color.rs index e0a5ac3e..f482bc07 100644 --- a/gnuplot/examples/color.rs +++ b/gnuplot/examples/color.rs @@ -53,7 +53,7 @@ fn example(c: Common) x.clone(), iter::repeat((n_colors - 1) - i), iter::repeat(0.4), - iter::repeat(0.2), //x.clone().map(|x| (((3 + x) as f64) / 3.0).rem(0.8)), + iter::repeat(0.2), &[ Caption(&color_name(&color)), LineWidth(1.0), @@ -84,6 +84,12 @@ fn example(c: Common) ], ); + // any of the forms used for Color can also be used with TextColor and BorderColor + ax.set_x_label( + "Labels can be colored using the TextColor function", + &[TextColor((128, 0, 255))], + ); + c.show(&mut fg, "rgb_color"); } diff --git a/gnuplot/examples/multiple_axes.rs b/gnuplot/examples/multiple_axes.rs index 905f40f3..1f83ec9d 100644 --- a/gnuplot/examples/multiple_axes.rs +++ b/gnuplot/examples/multiple_axes.rs @@ -20,10 +20,10 @@ fn example(c: Common) [-5.0f32, 0.0, 5.0].iter(), &[Axes(X1, Y2), Color("red")], ) - .set_y_ticks(Some((Auto, 0)), &[Mirror(false)], &[]) // Make Y1 not mirror. - .set_y2_ticks(Some((Auto, 0)), &[Mirror(false)], &[]) // Make Y2 not mirror, and visible. - .set_y_label("Blue", &[]) - .set_y2_label("Red", &[]) + .set_y_ticks(Some((Auto, 0)), &[Mirror(false)], &[TextColor("blue")]) // Make Y1 not mirror. + .set_y2_ticks(Some((Auto, 0)), &[Mirror(false)], &[TextColor("red")]) // Make Y2 not mirror, and visible. + .set_y_label("Blue", &[TextColor("blue")]) + .set_y2_label("Red", &[TextColor("red")]) .label("Blue Label", Axis(1.), Axis(0.), &[TextColor("blue"), TextAlign(AlignRight)]) .label("Red Label", Axis(2.0), Axis2(2.5), &[TextColor("red")]); diff --git a/gnuplot/src/axes2d.rs b/gnuplot/src/axes2d.rs index a42f923b..acc2481d 100644 --- a/gnuplot/src/axes2d.rs +++ b/gnuplot/src/axes2d.rs @@ -102,11 +102,9 @@ impl LegendData } } first_opt! {self.text_options, - TextColor(ref s) => + TextColorOpt(ref s) => { - w.write_str(" textcolor rgb \""); - w.write_str(&escape(s)); - w.write_str("\""); + write!(w, " textcolor {} ", s.command()); } } first_opt! {self.text_options, diff --git a/gnuplot/src/axes_common.rs b/gnuplot/src/axes_common.rs index 3ef05f6d..de251f0c 100644 --- a/gnuplot/src/axes_common.rs +++ b/gnuplot/src/axes_common.rs @@ -455,9 +455,9 @@ pub fn write_out_label_options( } first_opt! {options, - TextColor(ref s) => + TextColorOpt(ref s) => { - write!(w, r#" tc rgb "{}""#, s); + write!(w, r#" tc {}"#, s.command()); } } diff --git a/gnuplot/src/options.rs b/gnuplot/src/options.rs index b682dce4..97a442c1 100644 --- a/gnuplot/src/options.rs +++ b/gnuplot/src/options.rs @@ -240,7 +240,7 @@ pub enum LabelOption Font(T, f64), /// Sets the color of the label text. The passed string can be a color name /// (e.g. "black" works), or an HTML color specifier (e.g. "#FFFFFF" is white) - TextColor(T), + TextColorOpt(ColorType), /// Rotates the label by a certain number of degrees Rotate(f64), /// Sets the horizontal alignment of the label text (default is left alignment). See AlignType. @@ -278,7 +278,7 @@ impl<'l> OneWayOwned for LabelOption<&'l str> { TextOffset(v1, v2) => TextOffset(v1, v2), Font(v1, v2) => Font(v1.into(), v2), - TextColor(v) => TextColor(v.into()), + TextColorOpt(v) => TextColorOpt(v.to_one_way_owned()), Rotate(v) => Rotate(v), TextAlign(v) => TextAlign(v), MarkerSymbol(v) => MarkerSymbol(v), @@ -288,6 +288,13 @@ impl<'l> OneWayOwned for LabelOption<&'l str> } } +#[allow(non_snake_case)] +/// TODO +pub fn TextColor<'l, T: IntoColor<&'l str>>(c: T) -> LabelOption<&'l str> +{ + TextColorOpt(c.into()) +} + /// An enumeration of axis tick options #[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] pub enum TickOption From 102dd896165d1c0007d47ec2815921cfe7aa4747 Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Tue, 25 Feb 2025 18:53:31 +0000 Subject: [PATCH 21/34] Add documentation to convenience functions --- gnuplot/src/color.rs | 40 ++++++++++++++++++++++++---------------- gnuplot/src/options.rs | 17 +++++++++++++++-- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/gnuplot/src/color.rs b/gnuplot/src/color.rs index 2daf444c..83382fc1 100644 --- a/gnuplot/src/color.rs +++ b/gnuplot/src/color.rs @@ -57,10 +57,10 @@ pub enum ColorType ), /// Vector of tuples of `u8` (as per `RGBColor`), but instead of a single color for the whole /// plot, the vector should contain a separte color for each data point. - VariableRGBIntegers(Vec), + VariableRGBInteger(Vec), /// Vector of tuples of `u8` (as per `ARGBColor`), but as with `VariableRGBColor`, a separate /// color value is given for each data point. - VariableARGBIntegers(Vec), + VariableARGBInteger(Vec), /// TODO PaletteFracColor(f32), /// TODO @@ -98,8 +98,8 @@ impl ColorType RGBString(s) => format!(r#"rgb "{}""#, s), RGBInteger(r, g, b) => format!(r#"rgb {}"#, from_argb(0, *r, *g, *b)), ARGBInteger(a, r, g, b) => format!(r#"rgb {}"#, from_argb(*a, *r, *g, *b)), - VariableRGBIntegers(_) => String::from("rgb variable"), - VariableARGBIntegers(_) => String::from("rgb variable"), + VariableRGBInteger(_) => String::from("rgb variable"), + VariableARGBInteger(_) => String::from("rgb variable"), PaletteFracColor(_) => todo!(), PaletteCBColor(_) => todo!(), VariablePaletteColor(_) => String::from("palette z"), @@ -118,11 +118,11 @@ impl ColorType RGBString(_) => panic!("data() called on non-variable color type."), RGBInteger(_, _, _) => panic!("data() called on non-variable color type."), ARGBInteger(_, _, _, _) => panic!("data() called on non-variable color type."), - VariableRGBIntegers(items) => items + VariableRGBInteger(items) => items .iter() .map(|(r, g, b)| from_argb(0, *r, *g, *b) as f64) .collect(), - VariableARGBIntegers(items) => items + VariableARGBInteger(items) => items .into_iter() .map(|(a, r, g, b)| from_argb(*a, *r, *g, *b) as f64) .collect(), @@ -141,8 +141,8 @@ impl ColorType { match self { - VariableRGBIntegers(_) - | VariableARGBIntegers(_) + VariableRGBInteger(_) + | VariableARGBInteger(_) | VariableIndex(_) | VariablePaletteColor(_) | SavedColorMap(_, _) => true, @@ -170,7 +170,7 @@ impl ColorType false } } - ARGBInteger(_, _, _, _) | VariableARGBIntegers(_) => true, + ARGBInteger(_, _, _, _) | VariableARGBInteger(_) => true, _ => false, } } @@ -275,7 +275,7 @@ impl Into> for Vec { fn into(self) -> ColorType { - ColorType::VariableRGBIntegers(self) + ColorType::VariableRGBInteger(self) } } @@ -283,7 +283,15 @@ impl Into> for Vec { fn into(self) -> ColorType { - ColorType::VariableARGBIntegers(self) + ColorType::VariableARGBInteger(self) + } +} + +impl Into> for ColorIndex +{ + fn into(self) -> ColorType + { + ColorType::Index(self) } } @@ -305,7 +313,7 @@ impl OneWayOwned for ColorType { RGBString(s) => RGBString(s.to_string()), RGBInteger(r, g, b) => RGBInteger(*r, *g, *b), - VariableRGBIntegers(d) => VariableRGBIntegers(d.clone()), + VariableRGBInteger(d) => VariableRGBInteger(d.clone()), PaletteFracColor(_) => todo!(), PaletteCBColor(_) => todo!(), VariablePaletteColor(d) => VariablePaletteColor(d.clone()), @@ -315,7 +323,7 @@ impl OneWayOwned for ColorType Index(n) => Index(*n), Black => Black, ARGBInteger(a, r, g, b) => ARGBInteger(*a, *r, *g, *b), - VariableARGBIntegers(d) => VariableARGBIntegers(d.clone()), + VariableARGBInteger(d) => VariableARGBInteger(d.clone()), } } } @@ -328,14 +336,14 @@ impl ColorType { RGBString(s) => RGBString(s), RGBInteger(r, g, b) => RGBInteger(*r, *g, *b), - VariableRGBIntegers(d) => VariableRGBIntegers(d.to_vec()), - VariableARGBIntegers(d) => VariableARGBIntegers(d.to_vec()), + VariableRGBInteger(d) => VariableRGBInteger(d.to_vec()), + VariableARGBInteger(d) => VariableARGBInteger(d.to_vec()), PaletteFracColor(_) => todo!(), PaletteCBColor(_) => todo!(), VariablePaletteColor(d) => VariablePaletteColor(d.to_vec()), SavedColorMap(s, d) => SavedColorMap(s, d.to_vec()), VariableIndex(d) => VariableIndex(d.to_vec()), - Background => todo!(), + Background => Background, Index(n) => Index(*n), Black => Black, ARGBInteger(a, r, g, b) => ARGBInteger(*a, *r, *g, *b), diff --git a/gnuplot/src/options.rs b/gnuplot/src/options.rs index 97a442c1..f5c8e235 100644 --- a/gnuplot/src/options.rs +++ b/gnuplot/src/options.rs @@ -78,13 +78,25 @@ pub enum PlotOption } #[allow(non_snake_case)] -/// TODO +/// Convience function to allow construction of color options implicitly from a wide range of inputs. +/// +/// Currently these are: +/// * `String` or `&str` - produces a [ColorType::RGBString] +/// * `(u8, u8, u8)` - produces a [ColorType::RGBInteger] +/// * `(u8, u8, u8, u8)` - produces a [ColorType::ARGBInteger] +/// * `Vec<((u8, u8, u8))>` or `Vec<(u8, u8, u8, u8)>` - produces a +/// [ColorType::VariableRGBInteger] or [ColorType::VariableARGBInteger] respectively +/// * `u8` or `Vec` produces a [ColorType::Index] or [ColorType::VariableIndex] respectively +/// +/// See `examples/color.rs` for usage of this function pub fn Color<'l, T: IntoColor<&'l str>>(c: T) -> PlotOption<&'l str> { ColorOpt(c.into()) } #[allow(non_snake_case)] +/// Convience function to allow construction of border color options implicitly from a wide range of inputs. +/// Format and possible inputs are the same as [Color] pub fn BorderColor<'l, T: IntoColor<&'l str>>(c: T) -> PlotOption<&'l str> { BorderColorOpt(c.into()) @@ -289,7 +301,8 @@ impl<'l> OneWayOwned for LabelOption<&'l str> } #[allow(non_snake_case)] -/// TODO +/// Convience function to allow construction of text color options implicitly from a wide range of inputs. +/// Format and possible inputs are the same as [Color] pub fn TextColor<'l, T: IntoColor<&'l str>>(c: T) -> LabelOption<&'l str> { TextColorOpt(c.into()) From da45b285a414359497b0967edbb47098265701cd Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Tue, 25 Feb 2025 20:34:30 +0000 Subject: [PATCH 22/34] Improve documentation --- gnuplot/examples/variable_color.rs | 27 ++++++++-------- gnuplot/src/axes_common.rs | 2 +- gnuplot/src/color.rs | 50 +++++++++++++++++++++++++----- 3 files changed, 57 insertions(+), 22 deletions(-) diff --git a/gnuplot/examples/variable_color.rs b/gnuplot/examples/variable_color.rs index 14cdd544..4c46626e 100644 --- a/gnuplot/examples/variable_color.rs +++ b/gnuplot/examples/variable_color.rs @@ -59,13 +59,14 @@ fn example(c: Common) // but make them align for multiple plot items on the same axis. This is implicity constructed from a Vec using // the `Color` function but could equivalently be created explicitly using `ColorOpt(ColorType::VariableIndexColor(row_index.clone()))` // - // The second color loop uses a VariablePaletteColor: this selects the color based on the current color palette and the - // input value for each data point. The palette is scaled to the maximum value in the vector of `f64`s passed - // to the VariablePaletteColor. + // The second color loop uses a `VariablePaletteColor`: this selects the color based on the current color palette and the + // input value for each data point. The palette is scaled to the maximum value in the `Vec` passed + // to the `VariablePaletteColor`. // - // The third color loop uses an (implicit) VariableARGBString. The `Vec<(u8, u8, u8, u8)>` needed to constcruct the color - // is calculated in this case by the `argb_formula()` closure. An explicit VariableARGBString could also be constructed using - // `ColorOpt(ColorType::VariableARGBString(data)``. A VariableRGBString is also defined that takes a 3-tuple of u8, rather than + // The third color loop uses an (implicit) `VariableARGBString`. The `Vec<(u8, u8, u8, u8)>` needed to construct the color + // is calculated in this case by the `argb_formula()` closure. An explicit `VariableARGBString` could also be constructed using + // `ColorOpt(ColorType::VariableARGBString(data)`. + // As an alternative, `VariableRGBString` is also defined that takes a 3-tuple of u8, rather than // a 4 tuple. for (color, label) in [ (Color(row_index.clone()), "VariableIndexColor"), @@ -126,23 +127,23 @@ fn example(c: Common) // ##################################################################### // The example below shows the same graphs as in the loop, but using a set of saved colormaps - // similar to palette in gnuplot terms, but the current palette is applied to all plots by default, and - // multiple named colormaps can be created). + // similar to palette in gnuplot terms, but the a single (current) palette is applied to all plots by default. + // By contrast, you can create multiple named colormaps. // - // As with VariablePaletteColor, this Color takes a vector of f64 that says which point in the colormap to use, + // As with `VariablePaletteColor``, this Color takes a `Vec` that says which point in the colormap to use, // but it also takes a the name of the colormap from which to draw the colors. // // Note that the Color range appears to be shared across plots: i.e. if one plot has - // color data (the Vec) in the range 0-1, and another in the range 1-100, all the - // colors in the first plot will be right at the bottom end of it's colormap, even if that's + // color data (the `Vec`) in the range 0-1, and another in the range 1-100, all the + // colors in the first plot will be right at the bottom end of its colormap, even if that's // a different colormap to the one used in the second plot. let mut fg = Figure::new(); let ax = fg.axes2d(); // First create the colormaps we will later refer to - // MAGMA is one of the colormaps provide with rust gnuplot + // MAGMA is one of the colormaps provided with rust gnuplot ax.create_colormap("magma", MAGMA); - // HOT is one of the colormaps provide with rust gnuplot + // HOT is one of the colormaps provided with rust gnuplot ax.create_colormap("hot", HOT); // ocean (green-blue-white) as per the gnuplot documentation ax.create_colormap("ocean", PaletteType::Formula(23, 28, 3)); diff --git a/gnuplot/src/axes_common.rs b/gnuplot/src/axes_common.rs index de251f0c..c038d88c 100644 --- a/gnuplot/src/axes_common.rs +++ b/gnuplot/src/axes_common.rs @@ -2086,7 +2086,7 @@ pub trait AxesCommon: AxesCommonPrivate /// Creates and saves a colormap in the gnuplot environment that can be used for /// later plots (see examples/color_variable.rs for example usage) /// - /// /// # Arguments + /// # Arguments /// * `name` - The name with which to save the colormap /// * `palette` - What palette type to use fn create_colormap( diff --git a/gnuplot/src/color.rs b/gnuplot/src/color.rs index 83382fc1..dc4c2629 100644 --- a/gnuplot/src/color.rs +++ b/gnuplot/src/color.rs @@ -1,5 +1,3 @@ -//! TODO - pub use self::ColorType::*; use crate::util::OneWayOwned; use std::fmt::Display; @@ -18,16 +16,16 @@ pub type ARGBInts = ( ColorComponent, ); -/// Option type (for lines, axes, and text) that allows the various different gnuplot +/// Option type (for plots, borders, and text) that allows the various different gnuplot /// color formats. The gnuplot [colorspec reference](http://gnuplot.info/docs_6.0/loc3640.html) /// also explains these. /// -/// There are equivalent many ways of specifying colors, and this allows the user to chose the most convenient. -/// for example, all the following will produce the same blue color: +/// There are many equivalent ways of specifying colors, and this allows the user to chose the most convenient. +/// For example, all the following will produce the same blue color: /// `RGBColor("blue")`, `RGBColor("0x0000ff")`, `RGBColor("#0000ff")`, `RGBColor("0x000000ff")`, /// `RGBColor("#000000ff")`, `RGBIntegerColor(0, 0, 255)`, `ARGBColor(0, 0, 0, 255)`, /// -/// See example usages of these colors in `color.rs`, `variable_color.rs` in the +/// See example usages of these colors in `color.rs` and `variable_color.rs` in the /// [Examples folder](https://github.com/SiegeLord/RustGnuplot/tree/master/gnuplot/examples) on Github #[derive(Debug, Clone, PartialEq, PartialOrd)] pub enum ColorType @@ -71,7 +69,7 @@ pub enum ColorType /// Similar to `VariablePaletteColor` in that it takes a `Vec` to set the indexes into the /// color map for each data point, but in addition to the color data it takes a string hold the name /// of the color map to use. This should have been previously created in the workspace using the - /// `axes.create_colormap()` function. + /// (create_colormap())[crate::AxesCommon::create_colormap()] function. SavedColorMap(T, Vec), /// Set the color of all elements of the plot to the `n`th color in the current gnuplot color cycle. Index(ColorIndex), @@ -80,7 +78,7 @@ pub enum ColorType /// in Rust gnuplot, the color type takes a vector of u8, where each index is treated the same as the /// fixed `IndexColor`. /// This is useful for setting bars/boxes etc to be - /// the same color from multiple plot commands. The `color.rs` example has examples of this usage. + /// the same color from multiple plot commands. The `variable_color` example has examples of this usage. VariableIndex(Vec), /// Set the color of the plot to the current background color. Background, @@ -194,6 +192,17 @@ fn float_color_to_int(v: f64) -> u8 ((v * 255.0).round()) as u8 } +/// Converts a set of `f64` red, green and blue values in the range `0 <= x <= 1` to a 3-tuple of `u8` suitable for use as +/// an [RGBInteger] +/// +/// Panics if any of the arguments are not in the range `0 <= x <= 1` +/// +/// Ses also [floats_to_argb] +/// +/// # Arguments +/// * r - red. 0: no red, 1: fully red +/// * g - green. 0: no green, 1: fully green +/// * b - blue. 0: no blue, 1: fully blue pub fn floats_to_rgb(r: f64, g: f64, b: f64) -> RGBInts { ( @@ -203,6 +212,18 @@ pub fn floats_to_rgb(r: f64, g: f64, b: f64) -> RGBInts ) } +/// Converts a set of `f64` red, green and blue values in the range `0 <= x <= 1` to a 3-tuple of `u8` suitable for use as +/// an [ARGBInteger] +/// +/// Panics if any of the arguments are not in the range `0 <= x <= 1` +/// +/// Ses also [floats_to_rgb] +/// +/// # Arguments +/// * a - alpha (transparency) value. 0: completely opaque, 1: completely transparent. +/// * r - red. 0: no red, 1: fully red +/// * g - green. 0: no green, 1: fully green +/// * b - blue. 0: no blue, 1: fully blue pub fn floats_to_argb(a: f64, r: f64, g: f64, b: f64) -> ARGBInts { ( @@ -215,6 +236,7 @@ pub fn floats_to_argb(a: f64, r: f64, g: f64, b: f64) -> ARGBInts impl<'l> Into> for &'l str { + /// Converts `&str` into [RGBString] fn into(self) -> ColorType { ColorType::RGBString(String::from(self)) @@ -223,6 +245,7 @@ impl<'l> Into> for &'l str impl<'l> Into> for String { + /// Converts `String` into [RGBString] fn into(self) -> ColorType { ColorType::RGBString(self) @@ -231,6 +254,7 @@ impl<'l> Into> for String impl<'l> Into> for &'l str { + /// Converts `&str` into [RGBString] fn into(self) -> ColorType<&'l str> { ColorType::RGBString(self) @@ -239,6 +263,7 @@ impl<'l> Into> for &'l str impl Into> for ARGBInts { + /// Converts `(u8, u8, u8, u8)` into [ARGBInteger] fn into(self) -> ColorType { ColorType::ARGBInteger(self.0, self.1, self.2, self.3) @@ -247,6 +272,7 @@ impl Into> for ARGBInts impl Into> for RGBInts { + /// Converts `(u8, u8, u8)` into [RGBInteger] fn into(self) -> ColorType { ColorType::RGBInteger(self.0, self.1, self.2) @@ -255,6 +281,8 @@ impl Into> for RGBInts impl Into> for (f64, f64, f64) { + /// Converts `(f64, f64, f64)` into [RGBInteger]. + /// All values must be in the range 0-1, or the function will panic. fn into(self) -> ColorType { let ints = floats_to_rgb(self.0, self.1, self.2); @@ -264,6 +292,8 @@ impl Into> for (f64, f64, f64) impl Into> for (f64, f64, f64, f64) { + /// Converts `(f64, f64, f64, f64)` into [ARGBInteger]. + /// All values must be in the range 0-1, or the function will panic. fn into(self) -> ColorType { let ints = floats_to_argb(self.0, self.1, self.2, self.3); @@ -273,6 +303,7 @@ impl Into> for (f64, f64, f64, f64) impl Into> for Vec { + /// Converts `Vec<(u8, u8, u8)>` into [VariableRGBInteger] fn into(self) -> ColorType { ColorType::VariableRGBInteger(self) @@ -281,6 +312,7 @@ impl Into> for Vec impl Into> for Vec { + /// Converts `Vec<(u8, u8, u8, u8)>` into [VariableARGBInteger] fn into(self) -> ColorType { ColorType::VariableARGBInteger(self) @@ -289,6 +321,7 @@ impl Into> for Vec impl Into> for ColorIndex { + /// Converts `u8` into [Index] fn into(self) -> ColorType { ColorType::Index(self) @@ -297,6 +330,7 @@ impl Into> for ColorIndex impl Into> for Vec { + /// Converts `Vec` into [VariableIndex] fn into(self) -> ColorType { ColorType::VariableIndex(self) From f75f7488bcb97fcfe676871cbf8c94e1f6fbd980 Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Tue, 25 Feb 2025 22:13:45 +0000 Subject: [PATCH 23/34] Implement palette fixed colors --- gnuplot/examples/color.rs | 48 +++++++++++++++++++++++-- gnuplot/src/axes_common.rs | 3 +- gnuplot/src/color.rs | 74 +++++++++++++++++++++++++------------- gnuplot/src/options.rs | 2 +- 4 files changed, 98 insertions(+), 29 deletions(-) diff --git a/gnuplot/examples/color.rs b/gnuplot/examples/color.rs index f482bc07..48bde239 100644 --- a/gnuplot/examples/color.rs +++ b/gnuplot/examples/color.rs @@ -42,9 +42,9 @@ fn example(c: Common) ax.set_title( "Demo of RGBString in various forms\nSee code comments for how to construct the colors", &[], - ); - ax.set_x_range(Fix(-10.0), Auto); - ax.set_legend(Graph(0.6), Graph(0.8), &[], &[Font("Arial", 14.0)]); + ) + .set_x_range(Fix(-9.0), Auto) + .set_legend(Graph(0.5), Graph(0.9), &[], &[Font("", 14.0)]); let n_colors = colors.len(); for (i, color) in colors.into_iter().enumerate() @@ -91,6 +91,48 @@ fn example(c: Common) ); c.show(&mut fg, "rgb_color"); + + // ######################################################################## + + let mut fg = Figure::new(); + let ax = fg.axes2d(); + let max_cb = 10.0; + ax.set_cb_range(Fix(0.0), Fix(max_cb)); + for color_value in 0..=10 + { + let color_float = color_value as f64; + let frac_color = Color(PaletteFracColor(color_float / max_cb)); + let cb_range_color = Color(PaletteCBColor(color_float)); + + ax.box_xy_error_delta( + [color_value], + [0], + [0.4], + [0.4], + &[ + Caption(&color_name(&frac_color)), + LineWidth(1.0), + BorderColor("black"), + frac_color, + ], + ) + .box_xy_error_delta( + [color_value], + [1], + [0.4], + [0.4], + &[ + Caption(&color_name(&cb_range_color)), + LineWidth(1.0), + BorderColor("black"), + cb_range_color, + ], + ); + } + ax.set_x_range(Fix(-10.0), Fix(11.0)) + .set_y_range(Fix(-0.5), Fix(1.5)) + .set_legend(Graph(0.45), Graph(0.9), &[], &[Font("", 14.0)]); + c.show(&mut fg, "palette_colors"); } fn main() diff --git a/gnuplot/src/axes_common.rs b/gnuplot/src/axes_common.rs index c038d88c..14e03df2 100644 --- a/gnuplot/src/axes_common.rs +++ b/gnuplot/src/axes_common.rs @@ -2073,7 +2073,8 @@ pub trait AxesCommon: AxesCommonPrivate self } - /// Sets the palette used for 3D surface and image plots + /// Sets the palette used for 3D surface and image plots. See the [palettes][crate::palettes] + /// module for a list of predefined palettes. /// /// # Arguments /// * `palette` - What palette type to use diff --git a/gnuplot/src/color.rs b/gnuplot/src/color.rs index dc4c2629..a897f4a7 100644 --- a/gnuplot/src/color.rs +++ b/gnuplot/src/color.rs @@ -59,12 +59,37 @@ pub enum ColorType /// Vector of tuples of `u8` (as per `ARGBColor`), but as with `VariableRGBColor`, a separate /// color value is given for each data point. VariableARGBInteger(Vec), - /// TODO - PaletteFracColor(f32), - /// TODO - PaletteCBColor(f32), + /// Sets the color of the plot element to a value picked from the current palette (see + /// [set_palette()](crate::AxesCommon::set_palette())). The value supplied to this color type + /// selects the color within the color range of the palette: i.e. it if the color bar range had been + /// set with `ax.set_cb_range(Fix(min), Fix(max))`, the value would be expected to be between + /// `min` and `max`. + /// + /// Example of usage is give in the `color` example. + /// + /// Compare with [PaletteFracColor] + PaletteFracColor(f64), + /// Sets the color of the plot element to a value picked from the current palette (see + /// [set_palette()](crate::AxesCommon::set_palette()) . The value supplied to this color type + /// selects the color as a fraction of the current color range i.e. it is expected to be + /// between `0` and `1`. + /// + /// Example of usage is give in the `color` example. + /// + /// Comparing with [PaletteCBColor]: given the following code + /// ``` + /// assert!(frac <= 0.0) + /// assert!(frac >= 1.0) + /// ax.set_cb_range(Fix(min), Fix(max)) + /// let col1 = PalleteFracColor(frac) + /// let cb_range = max - min; + /// let col2 = PaletteCBColor(min + (frac * cb_range)) + /// ``` + /// `col1` and `col2` should give the same color. + PaletteCBColor(f64), /// Vector of `f64` values which act as indexes into the current palette to set the color of - /// each data point + /// each data point. These variable values work in the same was as the single fixed value supplied + /// to a [PaletteCBColor] VariablePaletteColor(Vec), /// Similar to `VariablePaletteColor` in that it takes a `Vec` to set the indexes into the /// color map for each data point, but in addition to the color data it takes a string hold the name @@ -91,22 +116,23 @@ impl ColorType /// Returns the gnuplot string that will produce the requested color pub fn command(&self) -> String { - match self + let str = match self { - RGBString(s) => format!(r#"rgb "{}""#, s), - RGBInteger(r, g, b) => format!(r#"rgb {}"#, from_argb(0, *r, *g, *b)), - ARGBInteger(a, r, g, b) => format!(r#"rgb {}"#, from_argb(*a, *r, *g, *b)), - VariableRGBInteger(_) => String::from("rgb variable"), - VariableARGBInteger(_) => String::from("rgb variable"), - PaletteFracColor(_) => todo!(), - PaletteCBColor(_) => todo!(), - VariablePaletteColor(_) => String::from("palette z"), - SavedColorMap(s, _) => format!("palette {s}"), - VariableIndex(_) => String::from("variable"), - Background => String::from("background"), - Index(n) => format!("{}", n), - Black => String::from("black"), - } + RGBString(s) => &format!(r#"rgb "{}""#, s), + RGBInteger(r, g, b) => &format!(r#"rgb {}"#, from_argb(0, *r, *g, *b)), + ARGBInteger(a, r, g, b) => &format!(r#"rgb {}"#, from_argb(*a, *r, *g, *b)), + VariableRGBInteger(_) => "rgb variable", + VariableARGBInteger(_) => "rgb variable", + PaletteFracColor(v) => &format!("palette frac {v}"), + PaletteCBColor(v) => &format!("palette cb {v}"), + VariablePaletteColor(_) => "palette z", + SavedColorMap(s, _) => &format!("palette {s}"), + VariableIndex(_) => "variable", + Background => "background", + Index(n) => &format!("{}", n), + Black => "black", + }; + String::from(str) } pub fn data(&self) -> Vec @@ -348,8 +374,8 @@ impl OneWayOwned for ColorType RGBString(s) => RGBString(s.to_string()), RGBInteger(r, g, b) => RGBInteger(*r, *g, *b), VariableRGBInteger(d) => VariableRGBInteger(d.clone()), - PaletteFracColor(_) => todo!(), - PaletteCBColor(_) => todo!(), + PaletteFracColor(v) => PaletteFracColor(*v), + PaletteCBColor(v) => PaletteCBColor(*v), VariablePaletteColor(d) => VariablePaletteColor(d.clone()), SavedColorMap(s, d) => SavedColorMap(s.to_string(), d.clone()), VariableIndex(d) => VariableIndex(d.clone()), @@ -372,8 +398,8 @@ impl ColorType RGBInteger(r, g, b) => RGBInteger(*r, *g, *b), VariableRGBInteger(d) => VariableRGBInteger(d.to_vec()), VariableARGBInteger(d) => VariableARGBInteger(d.to_vec()), - PaletteFracColor(_) => todo!(), - PaletteCBColor(_) => todo!(), + PaletteFracColor(v) => PaletteFracColor(*v), + PaletteCBColor(v) => PaletteCBColor(*v), VariablePaletteColor(d) => VariablePaletteColor(d.to_vec()), SavedColorMap(s, d) => SavedColorMap(s, d.to_vec()), VariableIndex(d) => VariableIndex(d.to_vec()), diff --git a/gnuplot/src/options.rs b/gnuplot/src/options.rs index f5c8e235..912c95ff 100644 --- a/gnuplot/src/options.rs +++ b/gnuplot/src/options.rs @@ -88,7 +88,7 @@ pub enum PlotOption /// [ColorType::VariableRGBInteger] or [ColorType::VariableARGBInteger] respectively /// * `u8` or `Vec` produces a [ColorType::Index] or [ColorType::VariableIndex] respectively /// -/// See `examples/color.rs` for usage of this function +/// See `examples/color.rs` for usage of this function pub fn Color<'l, T: IntoColor<&'l str>>(c: T) -> PlotOption<&'l str> { ColorOpt(c.into()) From 359b4037c917de9c584cd81325fc4b915d697605 Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Tue, 25 Feb 2025 22:27:52 +0000 Subject: [PATCH 24/34] Fix clippy suggestions --- gnuplot/src/axes_common.rs | 2 +- gnuplot/src/color.rs | 103 +++++++++++++++++-------------------- gnuplot/src/options.rs | 2 +- 3 files changed, 48 insertions(+), 59 deletions(-) diff --git a/gnuplot/src/axes_common.rs b/gnuplot/src/axes_common.rs index 14e03df2..5a6ef8b7 100644 --- a/gnuplot/src/axes_common.rs +++ b/gnuplot/src/axes_common.rs @@ -30,7 +30,7 @@ pub struct PlotElement impl PlotElement { - pub fn new_plot<'l>( + pub fn new_plot( plot_type: PlotType, data: Vec, num_rows: usize, num_cols: usize, options: &[PlotOption<&str>], ) -> PlotElement diff --git a/gnuplot/src/color.rs b/gnuplot/src/color.rs index a897f4a7..ca3cb702 100644 --- a/gnuplot/src/color.rs +++ b/gnuplot/src/color.rs @@ -3,7 +3,7 @@ use crate::util::OneWayOwned; use std::fmt::Display; pub trait IntoColor: Into> + Clone {} -impl> + Clone> IntoColor for T {} +impl> + Clone> IntoColor for T {} pub type ColorIndex = u8; pub type ColorComponent = u8; @@ -147,7 +147,7 @@ impl ColorType .map(|(r, g, b)| from_argb(0, *r, *g, *b) as f64) .collect(), VariableARGBInteger(items) => items - .into_iter() + .iter() .map(|(a, r, g, b)| from_argb(*a, *r, *g, *b) as f64) .collect(), PaletteFracColor(_) => panic!("data() called on non-variable color type."), @@ -155,7 +155,7 @@ impl ColorType VariablePaletteColor(items) => items.clone(), SavedColorMap(_, items) => items.clone(), Index(_) => panic!("data() called on non-variable color type."), - VariableIndex(items) => items.into_iter().map(|v| *v as f64).collect(), + VariableIndex(items) => items.iter().map(|v| *v as f64).collect(), Background => panic!("data() called on non-variable color type."), Black => panic!("data() called on non-variable color type."), } @@ -163,15 +163,14 @@ impl ColorType pub fn is_variable(&self) -> bool { - match self - { + matches!( + self, VariableRGBInteger(_) - | VariableARGBInteger(_) - | VariableIndex(_) - | VariablePaletteColor(_) - | SavedColorMap(_, _) => true, - _ => false, - } + | VariableARGBInteger(_) + | VariableIndex(_) + | VariablePaletteColor(_) + | SavedColorMap(_, _) + ) } pub fn has_alpha(&self) -> bool @@ -181,18 +180,8 @@ impl ColorType RGBString(s) => { let s = s.to_string(); - if s.starts_with("0x") && s.chars().count() == 10 - { - true - } - else if s.starts_with("#") && s.chars().count() == 9 - { - true - } - else - { - false - } + s.starts_with("0x") && s.chars().count() == 10 + || s.starts_with("#") && s.chars().count() == 9 } ARGBInteger(_, _, _, _) | VariableARGBInteger(_) => true, _ => false, @@ -208,7 +197,7 @@ fn from_argb(a: ColorComponent, r: ColorComponent, g: ColorComponent, b: ColorCo fn float_color_to_int(v: f64) -> u8 { - if v < 0.0 || v > 1.0 + if !(0.0..=1.0).contains(&v) { panic!( "Float value must be greater than zero and less than one. Actual value: {}", @@ -260,106 +249,106 @@ pub fn floats_to_argb(a: f64, r: f64, g: f64, b: f64) -> ARGBInts ) } -impl<'l> Into> for &'l str +impl<'l> From<&'l str> for ColorType { /// Converts `&str` into [RGBString] - fn into(self) -> ColorType + fn from(value: &'l str) -> Self { - ColorType::RGBString(String::from(self)) + ColorType::RGBString(String::from(value)) } } -impl<'l> Into> for String +impl<'l> From for ColorType { /// Converts `String` into [RGBString] - fn into(self) -> ColorType + fn from(value: String) -> Self { - ColorType::RGBString(self) + ColorType::RGBString(value) } } -impl<'l> Into> for &'l str +impl<'l> From<&'l str> for ColorType<&'l str> { /// Converts `&str` into [RGBString] - fn into(self) -> ColorType<&'l str> + fn from(value: &'l str) -> Self { - ColorType::RGBString(self) + ColorType::RGBString(value) } } -impl Into> for ARGBInts +impl From for ColorType { /// Converts `(u8, u8, u8, u8)` into [ARGBInteger] - fn into(self) -> ColorType + fn from(value: ARGBInts) -> Self { - ColorType::ARGBInteger(self.0, self.1, self.2, self.3) + ColorType::ARGBInteger(value.0, value.1, value.2, value.3) } } -impl Into> for RGBInts +impl From for ColorType { /// Converts `(u8, u8, u8)` into [RGBInteger] - fn into(self) -> ColorType + fn from(value: RGBInts) -> Self { - ColorType::RGBInteger(self.0, self.1, self.2) + ColorType::RGBInteger(value.0, value.1, value.2) } } -impl Into> for (f64, f64, f64) +impl From<(f64, f64, f64)> for ColorType { /// Converts `(f64, f64, f64)` into [RGBInteger]. /// All values must be in the range 0-1, or the function will panic. - fn into(self) -> ColorType + fn from(value: (f64, f64, f64)) -> Self { - let ints = floats_to_rgb(self.0, self.1, self.2); + let ints = floats_to_rgb(value.0, value.1, value.2); ColorType::RGBInteger(ints.0, ints.1, ints.2) } } -impl Into> for (f64, f64, f64, f64) +impl From<(f64, f64, f64, f64)> for ColorType { /// Converts `(f64, f64, f64, f64)` into [ARGBInteger]. /// All values must be in the range 0-1, or the function will panic. - fn into(self) -> ColorType + fn from(value: (f64, f64, f64, f64)) -> Self { - let ints = floats_to_argb(self.0, self.1, self.2, self.3); + let ints = floats_to_argb(value.0, value.1, value.2, value.3); ColorType::ARGBInteger(ints.0, ints.1, ints.2, ints.3) } } -impl Into> for Vec +impl From> for ColorType { /// Converts `Vec<(u8, u8, u8)>` into [VariableRGBInteger] - fn into(self) -> ColorType + fn from(value: Vec) -> Self { - ColorType::VariableRGBInteger(self) + ColorType::VariableRGBInteger(value) } } -impl Into> for Vec +impl From> for ColorType { /// Converts `Vec<(u8, u8, u8, u8)>` into [VariableARGBInteger] - fn into(self) -> ColorType + fn from(value: Vec) -> Self { - ColorType::VariableARGBInteger(self) + ColorType::VariableARGBInteger(value) } } -impl Into> for ColorIndex +impl From for ColorType { /// Converts `u8` into [Index] - fn into(self) -> ColorType + fn from(value: ColorIndex) -> Self { - ColorType::Index(self) + ColorType::Index(value) } } -impl Into> for Vec +impl From> for ColorType { /// Converts `Vec` into [VariableIndex] - fn into(self) -> ColorType + fn from(value: Vec) -> Self { - ColorType::VariableIndex(self) + ColorType::VariableIndex(value) } } diff --git a/gnuplot/src/options.rs b/gnuplot/src/options.rs index 912c95ff..5a10753b 100644 --- a/gnuplot/src/options.rs +++ b/gnuplot/src/options.rs @@ -85,7 +85,7 @@ pub enum PlotOption /// * `(u8, u8, u8)` - produces a [ColorType::RGBInteger] /// * `(u8, u8, u8, u8)` - produces a [ColorType::ARGBInteger] /// * `Vec<((u8, u8, u8))>` or `Vec<(u8, u8, u8, u8)>` - produces a -/// [ColorType::VariableRGBInteger] or [ColorType::VariableARGBInteger] respectively +/// [ColorType::VariableRGBInteger] or [ColorType::VariableARGBInteger] respectively /// * `u8` or `Vec` produces a [ColorType::Index] or [ColorType::VariableIndex] respectively /// /// See `examples/color.rs` for usage of this function From 76029b4244413dc0e802df9bf446c827f60f117d Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Mon, 3 Mar 2025 08:31:40 +0000 Subject: [PATCH 25/34] FIx sample code in docs --- gnuplot/src/color.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/gnuplot/src/color.rs b/gnuplot/src/color.rs index ca3cb702..e027b2e8 100644 --- a/gnuplot/src/color.rs +++ b/gnuplot/src/color.rs @@ -78,12 +78,20 @@ pub enum ColorType /// /// Comparing with [PaletteCBColor]: given the following code /// ``` - /// assert!(frac <= 0.0) - /// assert!(frac >= 1.0) - /// ax.set_cb_range(Fix(min), Fix(max)) - /// let col1 = PalleteFracColor(frac) + /// use gnuplot::{PaletteCBColor, PaletteFracColor, Fix, Figure, AxesCommon, Color}; + /// let min = -5.0; // or any value + /// let max = 12.0; // or any value + /// + /// let frac = 0.5; // or any value 0.0 <= frac <= 1.0 + /// assert!(frac >= 0.0); + /// assert!(frac <= 1.0); + /// + /// let mut fg = Figure::new(); + /// let ax = fg.axes2d(); + /// ax.set_cb_range(Fix(min), Fix(max)); + /// let col1 = Color(PaletteFracColor(frac)); /// let cb_range = max - min; - /// let col2 = PaletteCBColor(min + (frac * cb_range)) + /// let col2 = Color(PaletteCBColor(min + (frac * cb_range))); /// ``` /// `col1` and `col2` should give the same color. PaletteCBColor(f64), From f2612e9e64eee0289a5d2496eefa63a36a0cc807 Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Sun, 16 Mar 2025 16:10:46 +0000 Subject: [PATCH 26/34] Improve color docs --- gnuplot/src/color.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gnuplot/src/color.rs b/gnuplot/src/color.rs index e027b2e8..acbd44df 100644 --- a/gnuplot/src/color.rs +++ b/gnuplot/src/color.rs @@ -79,10 +79,10 @@ pub enum ColorType /// Comparing with [PaletteCBColor]: given the following code /// ``` /// use gnuplot::{PaletteCBColor, PaletteFracColor, Fix, Figure, AxesCommon, Color}; - /// let min = -5.0; // or any value - /// let max = 12.0; // or any value + ///# let min = -5.0; // or any value + ///# let max = 12.0; // or any value /// - /// let frac = 0.5; // or any value 0.0 <= frac <= 1.0 + ///# let frac = 0.5; // or any value 0.0 <= frac <= 1.0 /// assert!(frac >= 0.0); /// assert!(frac <= 1.0); /// @@ -93,7 +93,7 @@ pub enum ColorType /// let cb_range = max - min; /// let col2 = Color(PaletteCBColor(min + (frac * cb_range))); /// ``` - /// `col1` and `col2` should give the same color. + /// `col1` and `col2` should give the same color for any values of `max` and `min`, and `0 <= frac <= 1`. PaletteCBColor(f64), /// Vector of `f64` values which act as indexes into the current palette to set the color of /// each data point. These variable values work in the same was as the single fixed value supplied @@ -102,7 +102,7 @@ pub enum ColorType /// Similar to `VariablePaletteColor` in that it takes a `Vec` to set the indexes into the /// color map for each data point, but in addition to the color data it takes a string hold the name /// of the color map to use. This should have been previously created in the workspace using the - /// (create_colormap())[crate::AxesCommon::create_colormap()] function. + /// [create_colormap()](crate::AxesCommon::create_colormap) function. SavedColorMap(T, Vec), /// Set the color of all elements of the plot to the `n`th color in the current gnuplot color cycle. Index(ColorIndex), From d407f42c14b2196b55d59c838302f3a50e83f58d Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Sun, 16 Mar 2025 16:42:41 +0000 Subject: [PATCH 27/34] Remove (hacky) convenience functions in favour of clear explicit .into() calls --- gnuplot/examples/box_and_whisker.rs | 2 +- gnuplot/examples/box_xy_error.rs | 2 +- gnuplot/examples/color.rs | 40 +++++++------- gnuplot/examples/dash_type.rs | 2 +- gnuplot/examples/example1.rs | 81 ++++++++++++++++++++--------- gnuplot/examples/example2.rs | 34 +++++++----- gnuplot/examples/gif.rs | 4 +- gnuplot/examples/inverse_api.rs | 6 +-- gnuplot/examples/lines_3d.rs | 2 +- gnuplot/examples/lines_points_3d.rs | 2 +- gnuplot/examples/multiple_axes.rs | 16 +++--- gnuplot/examples/points_3d.rs | 2 +- gnuplot/examples/polygons.rs | 12 +++-- gnuplot/examples/variable_color.rs | 10 ++-- gnuplot/src/axes2d.rs | 2 +- gnuplot/src/axes_common.rs | 8 +-- gnuplot/src/color.rs | 10 ++-- gnuplot/src/lib.rs | 2 +- gnuplot/src/options.rs | 46 +++------------- gnuplot/src/util.rs | 2 +- 20 files changed, 149 insertions(+), 136 deletions(-) diff --git a/gnuplot/examples/box_and_whisker.rs b/gnuplot/examples/box_and_whisker.rs index a1017ea3..747a3eed 100644 --- a/gnuplot/examples/box_and_whisker.rs +++ b/gnuplot/examples/box_and_whisker.rs @@ -27,7 +27,7 @@ fn example(c: Common) [0.5f32, 0.25, 0.125].iter(), &[ WhiskerBars(0.5), - Color("blue"), + Color("blue".into()), LineWidth(2.0), LineStyle(SmallDot), FillAlpha(0.5), diff --git a/gnuplot/examples/box_xy_error.rs b/gnuplot/examples/box_xy_error.rs index 1ffc6731..bee507f6 100644 --- a/gnuplot/examples/box_xy_error.rs +++ b/gnuplot/examples/box_xy_error.rs @@ -25,7 +25,7 @@ fn example(c: Common) [-1.5f32, 4.5, 3.0].iter(), [0.5f32, 4.75, 0.125].iter(), &[ - Color("blue"), + Color("blue".into()), LineWidth(2.0), LineStyle(SmallDot), FillAlpha(0.5), diff --git a/gnuplot/examples/color.rs b/gnuplot/examples/color.rs index 48bde239..a00f8399 100644 --- a/gnuplot/examples/color.rs +++ b/gnuplot/examples/color.rs @@ -8,7 +8,7 @@ mod common; fn color_name(color: &PlotOption) -> String { - let s = format!("{:?}", color).replace("ColorOpt(", ""); + let s = format!("{:?}", color).replace("Color(", ""); let mut chars = s.chars(); chars.next_back(); chars.as_str().to_string() @@ -19,22 +19,22 @@ fn example(c: Common) let x = 0..5; let colors = [ - Color("black"), // Conversion to RGBString is implicit - Color(ColorType::RGBString("black")), // Explicit use of RGBString - Color("red"), // Conversion to RGBString is implicit - Color(RGBString("#ff0000")), // red using Hex coded RRGGBB - Color(RGBString("#00ff0000")), // red using Hex coded AARRGGBB - Color("#ff8888"), // pink using Hex coded RRGGBB. Conversion to RGBString is implict - Color("#88ff0000"), // pink using Hex coded AARRGGBB. Conversion to RGBString is implict + Color("black".into()), // Conversion to RGBString is implicit + Color(ColorType::RGBString("black")), // Explicit use of RGBString + Color("red".into()), // Conversion to RGBString is implicit + Color(RGBString("#ff0000")), // red using Hex coded RRGGBB + Color(RGBString("#00ff0000")), // red using Hex coded AARRGGBB + Color("#ff8888".into()), // pink using Hex coded RRGGBB. Conversion to RGBString is implict + Color("#88ff0000".into()), // pink using Hex coded AARRGGBB. Conversion to RGBString is implict Color(ColorType::RGBString("#ffff0000")), // transparent using Hex coded AARRGGBB - Color((128, 0, 255)), // purple using implict RGBInteger + Color((128, 0, 255).into()), // purple using implict RGBInteger Color(RGBInteger(128, 0, 255)), // purple using explict RGBInteger - Color((0.5, 0.0, 1.0)), // purple using implict float to int conversion - Color(floats_to_rgb(0.5, 0.0, 1.0)), // purple using explicit float to int conversion - Color((128, 128, 0, 255)), // pale purple using implict ARGBInteger + Color((0.5, 0.0, 1.0).into()), // purple using implict float to int conversion + Color(floats_to_rgb(0.5, 0.0, 1.0).into()), // purple using explicit float to int conversion + Color((128, 128, 0, 255).into()), // pale purple using implict ARGBInteger Color(ARGBInteger(128, 128, 0, 255)), // pale purple using explict ARGBInteger - Color((0.5, 0.5, 0.0, 1.0)), // pale purple using implict float to int conversion - Color(floats_to_argb(0.5, 0.5, 0.0, 1.0)), // pale purple using explicit float to int conversion + Color((0.5, 0.5, 0.0, 1.0).into()), // pale purple using implict float to int conversion + Color(floats_to_argb(0.5, 0.5, 0.0, 1.0).into()), // pale purple using explicit float to int conversion ]; let mut fg = Figure::new(); @@ -57,7 +57,7 @@ fn example(c: Common) &[ Caption(&color_name(&color)), LineWidth(1.0), - BorderColor("black"), + BorderColor("black".into()), color, ], ); @@ -70,7 +70,7 @@ fn example(c: Common) &[ LineWidth(7.0), Color(Black), - Caption(&color_name(&Color(Black))), + Caption(&color_name::(&Color(Black))), ], ); @@ -80,14 +80,14 @@ fn example(c: Common) &[ LineWidth(7.0), Color(Background), - Caption(&color_name(&Color(Background))), + Caption(&color_name::(&Color(Background))), ], ); // any of the forms used for Color can also be used with TextColor and BorderColor ax.set_x_label( "Labels can be colored using the TextColor function", - &[TextColor((128, 0, 255))], + &[TextColor((128, 0, 255).into())], ); c.show(&mut fg, "rgb_color"); @@ -112,7 +112,7 @@ fn example(c: Common) &[ Caption(&color_name(&frac_color)), LineWidth(1.0), - BorderColor("black"), + BorderColor("black".into()), frac_color, ], ) @@ -124,7 +124,7 @@ fn example(c: Common) &[ Caption(&color_name(&cb_range_color)), LineWidth(1.0), - BorderColor("black"), + BorderColor("black".into()), cb_range_color, ], ); diff --git a/gnuplot/examples/dash_type.rs b/gnuplot/examples/dash_type.rs index c8928173..99c2556f 100644 --- a/gnuplot/examples/dash_type.rs +++ b/gnuplot/examples/dash_type.rs @@ -22,7 +22,7 @@ fn example(c: Common) x.clone().map(|v| v * 2 + 2 * i), &[ LineWidth(2.), - Color("black"), + Color("black".into()), LineStyle(dt), Caption(&format!("{:?}", dt)), ], diff --git a/gnuplot/examples/example1.rs b/gnuplot/examples/example1.rs index df795997..674df498 100644 --- a/gnuplot/examples/example1.rs +++ b/gnuplot/examples/example1.rs @@ -56,7 +56,7 @@ fn example(c: Common) ArrowType(Closed), ArrowSize(0.1), LineWidth(2.0), - Color("black"), + Color("black".into()), ], ) .label("Here", Axis(5.7912), Axis(3.1), &[TextAlign(AlignCenter)]) @@ -64,18 +64,26 @@ fn example(c: Common) x, y1.map(|&y| y * 0.85 - 1.0), y1.map(|&y| y * 1.15 + 1.0), - &[Color("#aaaaff")], + &[Color("#aaaaff".into())], ) .lines( x, y1, - &[Caption("(x - 4)^2 - 5"), LineWidth(1.5), Color("black")], + &[ + Caption("(x - 4)^2 - 5"), + LineWidth(1.5), + Color("black".into()), + ], ) .y_error_lines( x, y2, repeat(1.0f32), - &[Caption("-(x - 4)^2 + 5"), LineWidth(1.5), Color("red")], + &[ + Caption("-(x - 4)^2 + 5"), + LineWidth(1.5), + Color("red".into()), + ], ) .lines_points( x, @@ -85,7 +93,7 @@ fn example(c: Common) PointSymbol('t'), LineWidth(1.5), LineStyle(Dash), - Color("#11ff11"), + Color("#11ff11".into()), ], ); @@ -95,7 +103,11 @@ fn example(c: Common) fg.axes2d() .set_pos_grid(2, 2, 0) - .lines(x, y1, &[Caption("Lines"), LineWidth(3.0), Color("violet")]) + .lines( + x, + y1, + &[Caption("Lines"), LineWidth(3.0), Color("violet".into())], + ) .set_title("Plot1 fg1.2", &[]); fg.axes2d() @@ -106,7 +118,7 @@ fn example(c: Common) &[ Caption("Points"), PointSymbol('D'), - Color("#ffaa77"), + Color("#ffaa77".into()), PointSize(2.0), ], ) @@ -116,8 +128,11 @@ fn example(c: Common) let mut fg = Figure::new(); - fg.axes2d() - .lines(x, y1, &[Caption("Lines"), LineWidth(3.0), Color("violet")]); + fg.axes2d().lines( + x, + y1, + &[Caption("Lines"), LineWidth(3.0), Color("violet".into())], + ); fg.axes2d() .set_pos(0.2, 0.4) @@ -126,7 +141,7 @@ fn example(c: Common) .points( x, y2, - &[Caption("Points"), PointSymbol('T'), Color("#ffaa77")], + &[Caption("Points"), PointSymbol('T'), Color("#ffaa77".into())], ) .set_title("Inset fg1.3", &[]); @@ -135,7 +150,11 @@ fn example(c: Common) let mut fg = Figure::new(); fg.axes2d() - .lines(x, y1, &[Caption("Lines"), LineWidth(3.0), Color("violet")]) + .lines( + x, + y1, + &[Caption("Lines"), LineWidth(3.0), Color("violet".into())], + ) .set_y_range(Fix(-30.0), Auto) .set_y_label("This axis is manually scaled on the low end", &[]) .set_title("Range fg1.4", &[]); @@ -153,7 +172,7 @@ fn example(c: Common) Caption(r"x\_error\_lines"), LineWidth(2.0), PointSymbol('O'), - Color("red"), + Color("red".into()), ], ) .y_error_lines( @@ -164,20 +183,28 @@ fn example(c: Common) Caption(r"y\_error\_lines"), LineWidth(2.0), PointSymbol('S'), - Color("blue"), + Color("blue".into()), ], ) .x_error_bars( x, y3, x_err, - &[Caption(r"x\_error\_bars"), PointSymbol('T'), Color("cyan")], + &[ + Caption(r"x\_error\_bars"), + PointSymbol('T'), + Color("cyan".into()), + ], ) .y_error_bars( x, y4, y_err, - &[Caption(r"y\_error\_bars"), PointSymbol('R'), Color("green")], + &[ + Caption(r"y\_error\_bars"), + PointSymbol('R'), + Color("green".into()), + ], ) .set_title("Error fg1.5", &[]); @@ -193,7 +220,7 @@ fn example(c: Common) y1, y3, &[ - Color("red"), + Color("red".into()), FillAlpha(0.5), FillRegion(Above), Caption("A > B"), @@ -204,7 +231,7 @@ fn example(c: Common) y1, y3, &[ - Color("green"), + Color("green".into()), FillAlpha(0.5), FillRegion(Below), Caption("A < B"), @@ -215,7 +242,7 @@ fn example(c: Common) y2, y3, &[ - Color("blue"), + Color("blue".into()), FillAlpha(0.5), FillRegion(Between), Caption("Between C and B"), @@ -225,18 +252,22 @@ fn example(c: Common) x, y1, &[ - Color("black"), + Color("black".into()), LineWidth(2.0), LineStyle(Dash), Caption("A"), ], ) - .lines(x, y2, &[Color("black"), LineWidth(2.0), Caption("C")]) + .lines( + x, + y2, + &[Color("black".into()), LineWidth(2.0), Caption("C")], + ) .lines( x, y3, &[ - Color("black"), + Color("black".into()), LineWidth(2.0), LineStyle(DotDotDash), Caption("B"), @@ -267,7 +298,7 @@ fn example(c: Common) &[ Caption("(x - 4)^2 - 5"), LineWidth(3.0), - Color("violet"), + Color("violet".into()), LineStyle(DotDash), ], ) @@ -277,7 +308,7 @@ fn example(c: Common) &[ Caption("-(x - 4)^2 + 5"), PointSymbol('S'), - Color("#ffaa77"), + Color("#ffaa77".into()), ], ) .lines_points( @@ -286,13 +317,13 @@ fn example(c: Common) &[ Caption("x - 4"), PointSymbol('O'), - Color("black"), + Color("black".into()), LineStyle(SmallDot), ], ) .set_x_label( "X Label", - &[Font("Arial", 24.0), TextColor("red"), Rotate(45.0)], + &[Font("Arial", 24.0), TextColor("red".into()), Rotate(45.0)], ) .set_y_label("Y Label", &[Rotate(0.0)]) .set_title( diff --git a/gnuplot/examples/example2.rs b/gnuplot/examples/example2.rs index 3d29ccc3..a30d6037 100644 --- a/gnuplot/examples/example2.rs +++ b/gnuplot/examples/example2.rs @@ -41,7 +41,11 @@ fn example(c: Common) fg.axes2d() .set_title("Arrows fg2.1", &[]) - .lines(x, y1, &[LineWidth(3.0), Color("brown"), LineStyle(DotDash)]) + .lines( + x, + y1, + &[LineWidth(3.0), Color("brown".into()), LineStyle(DotDash)], + ) .arrow( Graph(0.5), Graph(1.0), @@ -52,7 +56,7 @@ fn example(c: Common) ArrowSize(0.1), LineStyle(DotDotDash), LineWidth(2.0), - Color("red"), + Color("red".into()), ], ) .arrow( @@ -60,7 +64,7 @@ fn example(c: Common) Graph(1.0), Axis(3.0), Axis(9.0), - &[ArrowType(Open), Color("green")], + &[ArrowType(Open), Color("green".into())], ); c.show(&mut fg, "example2_1"); @@ -74,8 +78,8 @@ fn example(c: Common) y2, &[ LineWidth(2.0), - Color("cyan"), - BorderColor("blue"), + Color("cyan".into()), + BorderColor("blue".into()), LineStyle(DotDash), ], ) @@ -83,7 +87,11 @@ fn example(c: Common) x, y1, w, - &[LineWidth(2.0), Color("gray"), BorderColor("black")], + &[ + LineWidth(2.0), + Color("gray".into()), + BorderColor("black".into()), + ], ); c.show(&mut fg, "example2_2"); @@ -92,12 +100,12 @@ fn example(c: Common) fg.axes2d() .set_title("Axis Ticks fg2.3", &[]) - .lines(x3, y3, &[LineWidth(2.0), Color("blue")]) + .lines(x3, y3, &[LineWidth(2.0), Color("blue".into())]) .set_x_ticks_custom( x3.map(|&x| Major(x as f32, Fix("%.2f ms".to_string()))) .chain(x3.map(|&i| i as f32 + 0.5).map(|x| Minor(x))), &[MajorScale(2.0), MinorScale(0.5), OnAxis(true)], - &[TextColor("blue"), TextAlign(AlignCenter)], + &[TextColor("blue".into()), TextAlign(AlignCenter)], ) .set_x_log(Some(10.0)) .set_y_ticks( @@ -115,9 +123,9 @@ fn example(c: Common) .set_border(true, &[Left, Bottom], &[LineWidth(2.0)]) .set_x_ticks(Some((Fix(1.0), 1)), &[Mirror(false)], &[]) .set_y_ticks(Some((Fix(50.0), 0)), &[Mirror(false)], &[]) - .lines(x3, y3, &[LineWidth(2.0), Color("blue")]) + .lines(x3, y3, &[LineWidth(2.0), Color("blue".into())]) .set_x_axis(true, &[LineWidth(2.0), LineStyle(DotDotDash)]) - .set_y_axis(true, &[LineWidth(2.0), Color("red")]); + .set_y_axis(true, &[LineWidth(2.0), Color("red".into())]); c.show(&mut fg, "example2_4"); @@ -163,10 +171,10 @@ fn example(c: Common) fg.axes2d() .set_title("Axis Grid fg2.8", &[]) - .lines(x3, y3, &[LineWidth(2.0), Color("blue")]) + .lines(x3, y3, &[LineWidth(2.0), Color("blue".into())]) .set_y_ticks(Some((Auto, 2)), &[], &[]) - .set_grid_options(true, &[LineStyle(DotDotDash), Color("black")]) - .set_minor_grid_options(&[LineStyle(SmallDot), Color("red")]) + .set_grid_options(true, &[LineStyle(DotDotDash), Color("black".into())]) + .set_minor_grid_options(&[LineStyle(SmallDot), Color("red".into())]) .set_x_grid(true) .set_y_grid(true) .set_y_minor_grid(true); diff --git a/gnuplot/examples/gif.rs b/gnuplot/examples/gif.rs index 6a511e64..20fa2713 100644 --- a/gnuplot/examples/gif.rs +++ b/gnuplot/examples/gif.rs @@ -24,13 +24,13 @@ fn main() x.iter(), x.iter() .map(|&x| (x + t as f32 * 0.1 * 2. * f32::consts::PI).sin()), - &[Color("blue")], + &[Color("blue".into())], ); ax.lines( x.iter(), x.iter() .map(|&x| (x + t as f32 * 0.1 * 2. * f32::consts::PI).cos()), - &[Color("red")], + &[Color("red".into())], ); t += 0.1; } diff --git a/gnuplot/examples/inverse_api.rs b/gnuplot/examples/inverse_api.rs index a02957f7..235fffec 100644 --- a/gnuplot/examples/inverse_api.rs +++ b/gnuplot/examples/inverse_api.rs @@ -32,8 +32,8 @@ impl PlotElement for Lines PointSize(v) => PointSize(*v), Caption(v) => Caption(&v), LineWidth(v) => LineWidth(*v), - ColorOpt(v) => ColorOpt(v.to_ref()), - BorderColorOpt(v) => BorderColorOpt(v.to_ref()), + Color(v) => Color(v.to_ref()), + BorderColor(v) => BorderColor(v.to_ref()), LineStyle(v) => LineStyle(*v), FillAlpha(v) => FillAlpha(*v), FillRegion(v) => FillRegion(*v), @@ -165,7 +165,7 @@ fn example(c: Common) //~ fg.axes2d().set_title("Old API", &[]).lines( //~ z.clone(), //~ y.clone(), - //~ &[LineWidth(2.), Color("#ffaa77")], + //~ &[LineWidth(2.), Color("#ffaa77".into())], //~ ).lines( //~ z.clone(), //~ x.clone(), diff --git a/gnuplot/examples/lines_3d.rs b/gnuplot/examples/lines_3d.rs index ed515d3d..f0e936db 100644 --- a/gnuplot/examples/lines_3d.rs +++ b/gnuplot/examples/lines_3d.rs @@ -16,7 +16,7 @@ fn example(c: Common) x, y, z, - &[PointSymbol('o'), Color("#ffaa77"), PointSize(2.0)], + &[PointSymbol('o'), Color("#ffaa77".into()), PointSize(2.0)], ); c.show(&mut fg, "lines_3d"); diff --git a/gnuplot/examples/lines_points_3d.rs b/gnuplot/examples/lines_points_3d.rs index 286260be..b91fc0eb 100644 --- a/gnuplot/examples/lines_points_3d.rs +++ b/gnuplot/examples/lines_points_3d.rs @@ -18,7 +18,7 @@ fn example(c: Common) x, y, z, - &[PointSymbol('o'), Color("#ffaa77"), PointSize(2.0)], + &[PointSymbol('o'), Color("#ffaa77".into()), PointSize(2.0)], ); c.show(&mut fg, "lines_points_3d"); diff --git a/gnuplot/examples/multiple_axes.rs b/gnuplot/examples/multiple_axes.rs index 1f83ec9d..9c070ecf 100644 --- a/gnuplot/examples/multiple_axes.rs +++ b/gnuplot/examples/multiple_axes.rs @@ -13,19 +13,19 @@ fn example(c: Common) .lines_points( [0.0f32, 1.0, 2.0].iter(), [-1.0f32, 0.0, 1.0].iter(), - &[Axes(X1, Y1), Color("blue")], + &[Axes(X1, Y1), Color("blue".into())], ) .lines_points( [-0.6f32, 1.5, 2.5].iter(), [-5.0f32, 0.0, 5.0].iter(), - &[Axes(X1, Y2), Color("red")], + &[Axes(X1, Y2), Color("red".into())], ) - .set_y_ticks(Some((Auto, 0)), &[Mirror(false)], &[TextColor("blue")]) // Make Y1 not mirror. - .set_y2_ticks(Some((Auto, 0)), &[Mirror(false)], &[TextColor("red")]) // Make Y2 not mirror, and visible. - .set_y_label("Blue", &[TextColor("blue")]) - .set_y2_label("Red", &[TextColor("red")]) - .label("Blue Label", Axis(1.), Axis(0.), &[TextColor("blue"), TextAlign(AlignRight)]) - .label("Red Label", Axis(2.0), Axis2(2.5), &[TextColor("red")]); + .set_y_ticks(Some((Auto, 0)), &[Mirror(false)], &[TextColor("blue".into())]) // Make Y1 not mirror. + .set_y2_ticks(Some((Auto, 0)), &[Mirror(false)], &[TextColor("red".into())]) // Make Y2 not mirror, and visible. + .set_y_label("Blue", &[TextColor("blue".into())]) + .set_y2_label("Red", &[TextColor("red".into())]) + .label("Blue Label", Axis(1.), Axis(0.), &[TextColor("blue".into()), TextAlign(AlignRight)]) + .label("Red Label", Axis(2.0), Axis2(2.5), &[TextColor("red".into())]); c.show(&mut fg, "multiple_axes"); } diff --git a/gnuplot/examples/points_3d.rs b/gnuplot/examples/points_3d.rs index 91b4b48c..34deb01f 100644 --- a/gnuplot/examples/points_3d.rs +++ b/gnuplot/examples/points_3d.rs @@ -16,7 +16,7 @@ fn example(c: Common) x, y, z, - &[PointSymbol('o'), Color("#ffaa77"), PointSize(2.0)], + &[PointSymbol('o'), Color("#ffaa77".into()), PointSize(2.0)], ); c.show(&mut fg, "points_3d"); diff --git a/gnuplot/examples/polygons.rs b/gnuplot/examples/polygons.rs index 2a5c43bd..32534311 100644 --- a/gnuplot/examples/polygons.rs +++ b/gnuplot/examples/polygons.rs @@ -21,20 +21,24 @@ fn example(c: Common) ax.polygon( coords.iter().map(|x| x[0] + 2.), coords.iter().map(|x| x[1]), - &[FillAlpha(0.), BorderColor("black"), LineWidth(4.)], + &[FillAlpha(0.), BorderColor("black".into()), LineWidth(4.)], ); ax.polygon( coords.iter().map(|x| x[0]), coords.iter().map(|x| x[1] + 2.), - &[Color("#FF0000"), BorderColor("black"), LineWidth(4.)], + &[ + Color("#FF0000".into()), + BorderColor("black".into()), + LineWidth(4.), + ], ); ax.polygon( coords.iter().map(|x| x[0] + 2.), coords.iter().map(|x| x[1] + 2.), &[ FillPattern(Fix(BigCrosses)), - Color("#FF0000"), - BorderColor("black"), + Color("#FF0000".into()), + BorderColor("black".into()), LineWidth(4.), LineStyle(Dash), ], diff --git a/gnuplot/examples/variable_color.rs b/gnuplot/examples/variable_color.rs index 4c46626e..5f4e3a5a 100644 --- a/gnuplot/examples/variable_color.rs +++ b/gnuplot/examples/variable_color.rs @@ -57,7 +57,7 @@ fn example(c: Common) // // The first color loop demonstrates usage of VariableIndexColor with indices to use gnuplot's default color styles, // but make them align for multiple plot items on the same axis. This is implicity constructed from a Vec using - // the `Color` function but could equivalently be created explicitly using `ColorOpt(ColorType::VariableIndexColor(row_index.clone()))` + // the `IntoColor` trait but could equivalently be created explicitly using `Color(ColorType::VariableIndexColor(row_index.clone()))` // // The second color loop uses a `VariablePaletteColor`: this selects the color based on the current color palette and the // input value for each data point. The palette is scaled to the maximum value in the `Vec` passed @@ -65,19 +65,19 @@ fn example(c: Common) // // The third color loop uses an (implicit) `VariableARGBString`. The `Vec<(u8, u8, u8, u8)>` needed to construct the color // is calculated in this case by the `argb_formula()` closure. An explicit `VariableARGBString` could also be constructed using - // `ColorOpt(ColorType::VariableARGBString(data)`. + // `Color(ColorType::VariableARGBString(data)`. // As an alternative, `VariableRGBString` is also defined that takes a 3-tuple of u8, rather than // a 4 tuple. for (color, label) in [ - (Color(row_index.clone()), "VariableIndexColor"), + (Color(row_index.clone().into()), "VariableIndexColor"), ( - ColorOpt(VariablePaletteColor( + Color(VariablePaletteColor( row_index.iter().map(|v| *v as f64).collect(), )), "VariablePaletteColor", ), ( - Color(d1.iter().map(argb_formula).collect::>()), + Color(d1.iter().map(argb_formula).collect::>().into()), "VariableARGBString", ), ] diff --git a/gnuplot/src/axes2d.rs b/gnuplot/src/axes2d.rs index acc2481d..b73d30d4 100644 --- a/gnuplot/src/axes2d.rs +++ b/gnuplot/src/axes2d.rs @@ -102,7 +102,7 @@ impl LegendData } } first_opt! {self.text_options, - TextColorOpt(ref s) => + TextColor(ref s) => { write!(w, " textcolor {} ", s.command()); } diff --git a/gnuplot/src/axes_common.rs b/gnuplot/src/axes_common.rs index 5a6ef8b7..d2525e5d 100644 --- a/gnuplot/src/axes_common.rs +++ b/gnuplot/src/axes_common.rs @@ -211,7 +211,7 @@ impl PlotElement { let mut color_has_alpha = false; first_opt! {self.options, - ColorOpt(ref c) => { + Color(ref c) => { color_has_alpha = c.has_alpha() } } @@ -233,7 +233,7 @@ impl PlotElement if self.plot_type.is_line() { first_opt! {self.options, - BorderColorOpt(ref s) => + BorderColor(ref s) => { write!(writer, " border {}", s.command()); } @@ -455,7 +455,7 @@ pub fn write_out_label_options( } first_opt! {options, - TextColorOpt(ref s) => + TextColor(ref s) => { write!(w, r#" tc {}"#, s.command()); } @@ -1219,7 +1219,7 @@ impl AxesCommonData let mut col = default.as_ref(); first_opt! {options, - ColorOpt(ref s) => + Color(ref s) => { col = Some(s) } diff --git a/gnuplot/src/color.rs b/gnuplot/src/color.rs index acbd44df..5830b538 100644 --- a/gnuplot/src/color.rs +++ b/gnuplot/src/color.rs @@ -22,8 +22,8 @@ pub type ARGBInts = ( /// /// There are many equivalent ways of specifying colors, and this allows the user to chose the most convenient. /// For example, all the following will produce the same blue color: -/// `RGBColor("blue")`, `RGBColor("0x0000ff")`, `RGBColor("#0000ff")`, `RGBColor("0x000000ff")`, -/// `RGBColor("#000000ff")`, `RGBIntegerColor(0, 0, 255)`, `ARGBColor(0, 0, 0, 255)`, +/// `RGBColor("blue".into())`, `RGBColor("0x0000ff".into())`, `RGBColor("#0000ff".into())`, `RGBColor("0x000000ff".into())`, +/// `RGBColor("#000000ff".into())`, `RGBIntegerColor(0, 0, 255)`, `ARGBColor(0, 0, 0, 255)`, /// /// See example usages of these colors in `color.rs` and `variable_color.rs` in the /// [Examples folder](https://github.com/SiegeLord/RustGnuplot/tree/master/gnuplot/examples) on Github @@ -83,6 +83,8 @@ pub enum ColorType ///# let max = 12.0; // or any value /// ///# let frac = 0.5; // or any value 0.0 <= frac <= 1.0 + ///# let x = [1,2,3]; + ///# let y = [4,5,6]; /// assert!(frac >= 0.0); /// assert!(frac <= 1.0); /// @@ -92,8 +94,10 @@ pub enum ColorType /// let col1 = Color(PaletteFracColor(frac)); /// let cb_range = max - min; /// let col2 = Color(PaletteCBColor(min + (frac * cb_range))); + /// ax.lines(x, y, &[col1]); + /// ax.lines(x, y, &[col2]); /// ``` - /// `col1` and `col2` should give the same color for any values of `max` and `min`, and `0 <= frac <= 1`. + /// the two lines should give the same color for any values of `max` and `min`, and `0 <= frac <= 1`. PaletteCBColor(f64), /// Vector of `f64` values which act as indexes into the current palette to set the color of /// each data point. These variable values work in the same was as the single fixed value supplied diff --git a/gnuplot/src/lib.rs b/gnuplot/src/lib.rs index 345f544b..907f029b 100644 --- a/gnuplot/src/lib.rs +++ b/gnuplot/src/lib.rs @@ -18,7 +18,7 @@ let x = [0u32, 1, 2]; let y = [3u32, 4, 5]; let mut fg = Figure::new(); fg.axes2d() -.lines(&x, &y, &[Caption("A line"), Color("black")]); +.lines(&x, &y, &[Caption("A line"), Color("black".into())]); fg.show(); # } ~~~ diff --git a/gnuplot/src/options.rs b/gnuplot/src/options.rs index 5a10753b..7bf77dae 100644 --- a/gnuplot/src/options.rs +++ b/gnuplot/src/options.rs @@ -22,7 +22,6 @@ pub use self::YAxis::*; use crate::util::OneWayOwned; use crate::writer::Writer; use crate::ColorType; -use crate::IntoColor; /// An enumeration of plot options you can supply to plotting commands, governing /// things like line width, color and others @@ -54,10 +53,10 @@ pub enum PlotOption LineWidth(f64), /// Sets the color of the plot element. The passed string can be a color name /// (e.g. "black" works), or an HTML color specifier (e.g. "#FFFFFF" is white). This specifies the fill color of a filled plot. - ColorOpt(ColorType), + Color(ColorType), /// Sets the color of the border of a filled plot (if it has one). The passed string can be a color name /// (e.g. "black" works), or an HTML color specifier (e.g. "#FFFFFF" is white). - BorderColorOpt(ColorType), + BorderColor(ColorType), /// Sets the style of the line. Note that not all gnuplot terminals support dashed lines. See DashType for the available styles. LineStyle(DashType), /// Sets the transparency of a filled plot. `0.0` - fully transparent, `1.0` - fully opaque. Cannot be used with `FillPattern`. @@ -77,31 +76,6 @@ pub enum PlotOption Axes(XAxis, YAxis), } -#[allow(non_snake_case)] -/// Convience function to allow construction of color options implicitly from a wide range of inputs. -/// -/// Currently these are: -/// * `String` or `&str` - produces a [ColorType::RGBString] -/// * `(u8, u8, u8)` - produces a [ColorType::RGBInteger] -/// * `(u8, u8, u8, u8)` - produces a [ColorType::ARGBInteger] -/// * `Vec<((u8, u8, u8))>` or `Vec<(u8, u8, u8, u8)>` - produces a -/// [ColorType::VariableRGBInteger] or [ColorType::VariableARGBInteger] respectively -/// * `u8` or `Vec` produces a [ColorType::Index] or [ColorType::VariableIndex] respectively -/// -/// See `examples/color.rs` for usage of this function -pub fn Color<'l, T: IntoColor<&'l str>>(c: T) -> PlotOption<&'l str> -{ - ColorOpt(c.into()) -} - -#[allow(non_snake_case)] -/// Convience function to allow construction of border color options implicitly from a wide range of inputs. -/// Format and possible inputs are the same as [Color] -pub fn BorderColor<'l, T: IntoColor<&'l str>>(c: T) -> PlotOption<&'l str> -{ - BorderColorOpt(c.into()) -} - impl<'l> OneWayOwned for PlotOption<&'l str> { type Output = PlotOption; @@ -113,8 +87,8 @@ impl<'l> OneWayOwned for PlotOption<&'l str> PointSize(v) => PointSize(v), Caption(v) => Caption(v.into()), LineWidth(v) => LineWidth(v), - ColorOpt(ref v) => ColorOpt(v.to_one_way_owned()), - BorderColorOpt(ref v) => BorderColorOpt(v.to_one_way_owned()), + Color(ref v) => Color(v.to_one_way_owned()), + BorderColor(ref v) => BorderColor(v.to_one_way_owned()), LineStyle(v) => LineStyle(v), FillAlpha(v) => FillAlpha(v), FillRegion(v) => FillRegion(v), @@ -252,7 +226,7 @@ pub enum LabelOption Font(T, f64), /// Sets the color of the label text. The passed string can be a color name /// (e.g. "black" works), or an HTML color specifier (e.g. "#FFFFFF" is white) - TextColorOpt(ColorType), + TextColor(ColorType), /// Rotates the label by a certain number of degrees Rotate(f64), /// Sets the horizontal alignment of the label text (default is left alignment). See AlignType. @@ -290,7 +264,7 @@ impl<'l> OneWayOwned for LabelOption<&'l str> { TextOffset(v1, v2) => TextOffset(v1, v2), Font(v1, v2) => Font(v1.into(), v2), - TextColorOpt(v) => TextColorOpt(v.to_one_way_owned()), + TextColor(v) => TextColor(v.to_one_way_owned()), Rotate(v) => Rotate(v), TextAlign(v) => TextAlign(v), MarkerSymbol(v) => MarkerSymbol(v), @@ -300,14 +274,6 @@ impl<'l> OneWayOwned for LabelOption<&'l str> } } -#[allow(non_snake_case)] -/// Convience function to allow construction of text color options implicitly from a wide range of inputs. -/// Format and possible inputs are the same as [Color] -pub fn TextColor<'l, T: IntoColor<&'l str>>(c: T) -> LabelOption<&'l str> -{ - TextColorOpt(c.into()) -} - /// An enumeration of axis tick options #[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] pub enum TickOption diff --git a/gnuplot/src/util.rs b/gnuplot/src/util.rs index 29e71a1e..4858402f 100644 --- a/gnuplot/src/util.rs +++ b/gnuplot/src/util.rs @@ -55,7 +55,7 @@ macro_rules! generate_data { let mut c_data = None; first_opt! {$options, - ColorOpt(ref color) => + Color(ref color) => { if color.is_variable() { c_data = Some(color.data()); From 0af1a9603dcbf88c281f04de836d1a0d742b8ca0 Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Mon, 17 Mar 2025 17:51:52 +0000 Subject: [PATCH 28/34] Improve clarity of color_name function --- gnuplot/examples/color.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/gnuplot/examples/color.rs b/gnuplot/examples/color.rs index a00f8399..4fa6f95d 100644 --- a/gnuplot/examples/color.rs +++ b/gnuplot/examples/color.rs @@ -8,10 +8,11 @@ mod common; fn color_name(color: &PlotOption) -> String { - let s = format!("{:?}", color).replace("Color(", ""); - let mut chars = s.chars(); - chars.next_back(); - chars.as_str().to_string() + match color + { + Color(color_type) => format!("{:?}", color_type), + _ => panic!(), + } } fn example(c: Common) From 211709b5662bd35b8cc0b3bf977cec0701e6bd88 Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Mon, 17 Mar 2025 17:52:13 +0000 Subject: [PATCH 29/34] Remove unused IntoColor trait --- gnuplot/src/color.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/gnuplot/src/color.rs b/gnuplot/src/color.rs index 5830b538..74ca4677 100644 --- a/gnuplot/src/color.rs +++ b/gnuplot/src/color.rs @@ -2,9 +2,6 @@ pub use self::ColorType::*; use crate::util::OneWayOwned; use std::fmt::Display; -pub trait IntoColor: Into> + Clone {} -impl> + Clone> IntoColor for T {} - pub type ColorIndex = u8; pub type ColorComponent = u8; pub type ColorInt = u32; From bac4a1293fcdfef12f928cdd42f6e614817b03ba Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Mon, 17 Mar 2025 17:52:41 +0000 Subject: [PATCH 30/34] Change background color command for backward compatability --- gnuplot/src/color.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gnuplot/src/color.rs b/gnuplot/src/color.rs index 74ca4677..fd4ae03f 100644 --- a/gnuplot/src/color.rs +++ b/gnuplot/src/color.rs @@ -137,7 +137,7 @@ impl ColorType VariablePaletteColor(_) => "palette z", SavedColorMap(s, _) => &format!("palette {s}"), VariableIndex(_) => "variable", - Background => "background", + Background => "bgnd", Index(n) => &format!("{}", n), Black => "black", }; From fc8536459f044b1499dc92c48318b12e5ee33d65 Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Mon, 17 Mar 2025 17:53:24 +0000 Subject: [PATCH 31/34] Use wildcard for clarity in ColorType::data --- gnuplot/src/color.rs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/gnuplot/src/color.rs b/gnuplot/src/color.rs index fd4ae03f..4581a04c 100644 --- a/gnuplot/src/color.rs +++ b/gnuplot/src/color.rs @@ -1,6 +1,6 @@ pub use self::ColorType::*; use crate::util::OneWayOwned; -use std::fmt::Display; +use std::fmt::{Debug, Display}; pub type ColorIndex = u8; pub type ColorComponent = u8; @@ -120,7 +120,7 @@ pub enum ColorType Black, } -impl ColorType +impl ColorType { /// Returns the gnuplot string that will produce the requested color pub fn command(&self) -> String @@ -148,9 +148,6 @@ impl ColorType { match self { - RGBString(_) => panic!("data() called on non-variable color type."), - RGBInteger(_, _, _) => panic!("data() called on non-variable color type."), - ARGBInteger(_, _, _, _) => panic!("data() called on non-variable color type."), VariableRGBInteger(items) => items .iter() .map(|(r, g, b)| from_argb(0, *r, *g, *b) as f64) @@ -159,14 +156,10 @@ impl ColorType .iter() .map(|(a, r, g, b)| from_argb(*a, *r, *g, *b) as f64) .collect(), - PaletteFracColor(_) => panic!("data() called on non-variable color type."), - PaletteCBColor(_) => panic!("data() called on non-variable color type."), VariablePaletteColor(items) => items.clone(), SavedColorMap(_, items) => items.clone(), - Index(_) => panic!("data() called on non-variable color type."), VariableIndex(items) => items.iter().map(|v| *v as f64).collect(), - Background => panic!("data() called on non-variable color type."), - Black => panic!("data() called on non-variable color type."), + c => panic!("data() called on non-variable color type: {:?}", *c), } } From ab7eb962134440aa5217cb6531775374e4d2a2db Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Mon, 17 Mar 2025 21:40:39 +0000 Subject: [PATCH 32/34] Convert fallible ColorType conversions to TryFrom and remove float covnersion from public API --- gnuplot/examples/color.rs | 6 ++-- gnuplot/src/color.rs | 63 +++++++++++++++++++++------------------ 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/gnuplot/examples/color.rs b/gnuplot/examples/color.rs index 4fa6f95d..9a734aa2 100644 --- a/gnuplot/examples/color.rs +++ b/gnuplot/examples/color.rs @@ -30,12 +30,10 @@ fn example(c: Common) Color(ColorType::RGBString("#ffff0000")), // transparent using Hex coded AARRGGBB Color((128, 0, 255).into()), // purple using implict RGBInteger Color(RGBInteger(128, 0, 255)), // purple using explict RGBInteger - Color((0.5, 0.0, 1.0).into()), // purple using implict float to int conversion - Color(floats_to_rgb(0.5, 0.0, 1.0).into()), // purple using explicit float to int conversion + Color((0.5, 0.0, 1.0).try_into().unwrap()), // purple using implict float to int conversion Color((128, 128, 0, 255).into()), // pale purple using implict ARGBInteger Color(ARGBInteger(128, 128, 0, 255)), // pale purple using explict ARGBInteger - Color((0.5, 0.5, 0.0, 1.0).into()), // pale purple using implict float to int conversion - Color(floats_to_argb(0.5, 0.5, 0.0, 1.0).into()), // pale purple using explicit float to int conversion + Color((0.5, 0.5, 0.0, 1.0).try_into().unwrap()), // pale purple using implict float to int conversion ]; let mut fg = Figure::new(); diff --git a/gnuplot/src/color.rs b/gnuplot/src/color.rs index 4581a04c..d30f1e28 100644 --- a/gnuplot/src/color.rs +++ b/gnuplot/src/color.rs @@ -197,22 +197,25 @@ fn from_argb(a: ColorComponent, r: ColorComponent, g: ColorComponent, b: ColorCo ((a as ColorInt) << 24) + ((r as ColorInt) << 16) + ((g as ColorInt) << 8) + (b as ColorInt) } -fn float_color_to_int(v: f64) -> u8 +fn float_color_to_int(v: f64) -> Result { if !(0.0..=1.0).contains(&v) { - panic!( + Err(format!( "Float value must be greater than zero and less than one. Actual value: {}", v - ); + )) + } + else + { + Ok(((v * 255.0).round()) as u8) } - ((v * 255.0).round()) as u8 } /// Converts a set of `f64` red, green and blue values in the range `0 <= x <= 1` to a 3-tuple of `u8` suitable for use as /// an [RGBInteger] /// -/// Panics if any of the arguments are not in the range `0 <= x <= 1` +/// Returns an error String if any of the arguments are not in the range `0 <= x <= 1` /// /// Ses also [floats_to_argb] /// @@ -220,19 +223,19 @@ fn float_color_to_int(v: f64) -> u8 /// * r - red. 0: no red, 1: fully red /// * g - green. 0: no green, 1: fully green /// * b - blue. 0: no blue, 1: fully blue -pub fn floats_to_rgb(r: f64, g: f64, b: f64) -> RGBInts +fn floats_to_rgb(r: f64, g: f64, b: f64) -> Result { - ( - float_color_to_int(r), - float_color_to_int(g), - float_color_to_int(b), - ) + Ok(( + float_color_to_int(r)?, + float_color_to_int(g)?, + float_color_to_int(b)?, + )) } /// Converts a set of `f64` red, green and blue values in the range `0 <= x <= 1` to a 3-tuple of `u8` suitable for use as /// an [ARGBInteger] /// -/// Panics if any of the arguments are not in the range `0 <= x <= 1` +/// Returns an error String if any of the arguments are not in the range `0 <= x <= 1` /// /// Ses also [floats_to_rgb] /// @@ -241,14 +244,14 @@ pub fn floats_to_rgb(r: f64, g: f64, b: f64) -> RGBInts /// * r - red. 0: no red, 1: fully red /// * g - green. 0: no green, 1: fully green /// * b - blue. 0: no blue, 1: fully blue -pub fn floats_to_argb(a: f64, r: f64, g: f64, b: f64) -> ARGBInts +fn floats_to_argb(a: f64, r: f64, g: f64, b: f64) -> Result { - ( - float_color_to_int(a), - float_color_to_int(r), - float_color_to_int(g), - float_color_to_int(b), - ) + Ok(( + float_color_to_int(a)?, + float_color_to_int(r)?, + float_color_to_int(g)?, + float_color_to_int(b)?, + )) } impl<'l> From<&'l str> for ColorType @@ -296,25 +299,27 @@ impl From for ColorType } } -impl From<(f64, f64, f64)> for ColorType +impl TryFrom<(f64, f64, f64)> for ColorType { + type Error = String; /// Converts `(f64, f64, f64)` into [RGBInteger]. - /// All values must be in the range 0-1, or the function will panic. - fn from(value: (f64, f64, f64)) -> Self + /// Returns an error unless all values are in the range `0 <= v <= 1`. + fn try_from(value: (f64, f64, f64)) -> Result { - let ints = floats_to_rgb(value.0, value.1, value.2); - ColorType::RGBInteger(ints.0, ints.1, ints.2) + let ints = floats_to_rgb(value.0, value.1, value.2)?; + Ok(ColorType::RGBInteger(ints.0, ints.1, ints.2)) } } -impl From<(f64, f64, f64, f64)> for ColorType +impl TryFrom<(f64, f64, f64, f64)> for ColorType { + type Error = String; /// Converts `(f64, f64, f64, f64)` into [ARGBInteger]. - /// All values must be in the range 0-1, or the function will panic. - fn from(value: (f64, f64, f64, f64)) -> Self + /// Returns an error unless all values are in the range `0 <= v <= 1`. + fn try_from(value: (f64, f64, f64, f64)) -> Result { - let ints = floats_to_argb(value.0, value.1, value.2, value.3); - ColorType::ARGBInteger(ints.0, ints.1, ints.2, ints.3) + let ints = floats_to_argb(value.0, value.1, value.2, value.3)?; + Ok(ColorType::ARGBInteger(ints.0, ints.1, ints.2, ints.3)) } } From 4a4ff1555ae1f6ae1b71d5b99b3c2a5830827125 Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Tue, 18 Mar 2025 21:33:01 +0000 Subject: [PATCH 33/34] Convert chars().count() to simpler len(), as string must be ASCII --- gnuplot/src/color.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gnuplot/src/color.rs b/gnuplot/src/color.rs index d30f1e28..6cd546a3 100644 --- a/gnuplot/src/color.rs +++ b/gnuplot/src/color.rs @@ -182,8 +182,7 @@ impl ColorType RGBString(s) => { let s = s.to_string(); - s.starts_with("0x") && s.chars().count() == 10 - || s.starts_with("#") && s.chars().count() == 9 + s.starts_with("0x") && s.len() == 10 || s.starts_with("#") && s.len() == 9 } ARGBInteger(_, _, _, _) | VariableARGBInteger(_) => true, _ => false, From 14873499bef75cef229a949e689e4cc3b05bc1ac Mon Sep 17 00:00:00 2001 From: Ed Rogers Date: Tue, 18 Mar 2025 21:38:21 +0000 Subject: [PATCH 34/34] Simplify string creation in command() --- gnuplot/src/color.rs | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/gnuplot/src/color.rs b/gnuplot/src/color.rs index 6cd546a3..f35eb818 100644 --- a/gnuplot/src/color.rs +++ b/gnuplot/src/color.rs @@ -125,23 +125,22 @@ impl ColorType /// Returns the gnuplot string that will produce the requested color pub fn command(&self) -> String { - let str = match self + match self { - RGBString(s) => &format!(r#"rgb "{}""#, s), - RGBInteger(r, g, b) => &format!(r#"rgb {}"#, from_argb(0, *r, *g, *b)), - ARGBInteger(a, r, g, b) => &format!(r#"rgb {}"#, from_argb(*a, *r, *g, *b)), - VariableRGBInteger(_) => "rgb variable", - VariableARGBInteger(_) => "rgb variable", - PaletteFracColor(v) => &format!("palette frac {v}"), - PaletteCBColor(v) => &format!("palette cb {v}"), - VariablePaletteColor(_) => "palette z", - SavedColorMap(s, _) => &format!("palette {s}"), - VariableIndex(_) => "variable", - Background => "bgnd", - Index(n) => &format!("{}", n), - Black => "black", - }; - String::from(str) + RGBString(s) => format!(r#"rgb "{}""#, s), + RGBInteger(r, g, b) => format!(r#"rgb {}"#, from_argb(0, *r, *g, *b)), + ARGBInteger(a, r, g, b) => format!(r#"rgb {}"#, from_argb(*a, *r, *g, *b)), + VariableRGBInteger(_) => "rgb variable".into(), + VariableARGBInteger(_) => "rgb variable".into(), + PaletteFracColor(v) => format!("palette frac {v}"), + PaletteCBColor(v) => format!("palette cb {v}"), + VariablePaletteColor(_) => "palette z".into(), + SavedColorMap(s, _) => format!("palette {s}"), + VariableIndex(_) => "variable".into(), + Background => "bgnd".into(), + Index(n) => format!("{}", n), + Black => "black".into(), + } } pub fn data(&self) -> Vec