diff --git a/examples/README.md b/examples/README.md index 5a9f872..03eea59 100644 --- a/examples/README.md +++ b/examples/README.md @@ -108,6 +108,7 @@ Some output of integration tests are shown below. ![inset_axes](https://raw.githubusercontent.com/cpmech/plotpy/main/figures/integ_inset_axes_4.svg) ![inset_axes](https://raw.githubusercontent.com/cpmech/plotpy/main/figures/integ_inset_axes_5.svg) ![inset_axes](https://raw.githubusercontent.com/cpmech/plotpy/main/figures/integ_inset_axes_6.svg) +![inset_axes](https://raw.githubusercontent.com/cpmech/plotpy/main/figures/integ_inset_axes_7.svg) ## Legend diff --git a/figures/integ_inset_axes_7.svg b/figures/integ_inset_axes_7.svg new file mode 100644 index 0000000..a630008 --- /dev/null +++ b/figures/integ_inset_axes_7.svg @@ -0,0 +1,943 @@ + + + + + + + + 2025-02-10T08:15:09.489054 + image/svg+xml + + + Matplotlib v3.6.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/inset_axes.rs b/src/inset_axes.rs index 8c7a92b..3e5cb89 100644 --- a/src/inset_axes.rs +++ b/src/inset_axes.rs @@ -37,10 +37,7 @@ use std::fmt::Write; /// then the inset must be added after the range has been set. Otherwise, the inset will not be displayed correctly. /// Specifically the connector lines will not be drawn if the inset is added before `set_range`. pub struct InsetAxes { - xmin: f64, - xmax: f64, - ymin: f64, - ymax: f64, + range: Option<(f64, f64, f64, f64)>, extra_for_axes: String, extra_for_indicator: String, indicator_line_style: String, @@ -49,6 +46,7 @@ pub struct InsetAxes { indicator_hatch: String, indicator_alpha: Option, axes_visible: bool, + indicator_disabled: bool, title: String, buffer: String, } @@ -77,10 +75,7 @@ impl InsetAxes { /// ``` pub fn new() -> Self { Self { - xmin: 0.0, - xmax: 1.0, - ymin: 0.0, - ymax: 1.0, + range: None, extra_for_axes: String::new(), extra_for_indicator: String::new(), indicator_line_style: String::new(), @@ -89,6 +84,7 @@ impl InsetAxes { indicator_hatch: String::new(), indicator_alpha: None, axes_visible: false, + indicator_disabled: false, title: String::new(), buffer: String::new(), } @@ -197,28 +193,37 @@ impl InsetAxes { pub fn draw(&mut self, u0: f64, v0: f64, width: f64, height: f64) { let opt1 = self.options_for_axes(); let opt2 = self.options_for_indicator(); - self.buffer.insert_str( - 0, - &format!( - "zoom=plt.gca().inset_axes([{},{},{},{}],xlim=({},{}),ylim=({},{}){})\n", - u0, v0, width, height, self.xmin, self.xmax, self.ymin, self.ymax, opt1, - ), - ); + if let Some((xmin, xmax, ymin, ymax)) = self.range { + self.buffer.insert_str( + 0, + &format!( + "zoom=plt.gca().inset_axes([{},{},{},{}],xlim=({},{}),ylim=({},{}){})\n", + u0, v0, width, height, xmin, xmax, ymin, ymax, opt1, + ), + ); + } else { + self.buffer.insert_str( + 0, + &format!( + "zoom=plt.gca().inset_axes([{},{},{},{}]{})\n", + u0, v0, width, height, opt1, + ), + ); + } if !self.axes_visible { write!(&mut self.buffer, "zoom.set_xticks([])\nzoom.set_yticks([])\n").unwrap(); } if !self.title.is_empty() { write!(&mut self.buffer, "zoom.set_title(r'{}')\n", self.title).unwrap(); } - write!(&mut self.buffer, "plt.gca().indicate_inset_zoom(zoom{})\n", opt2,).unwrap(); + if !self.indicator_disabled { + write!(&mut self.buffer, "plt.gca().indicate_inset_zoom(zoom{})\n", opt2,).unwrap(); + } } /// Sets the limits of axes in the inset. pub fn set_range(&mut self, xmin: f64, xmax: f64, ymin: f64, ymax: f64) -> &mut Self { - self.xmin = xmin; - self.xmax = xmax; - self.ymin = ymin; - self.ymax = ymax; + self.range = Some((xmin, xmax, ymin, ymax)); self } @@ -254,6 +259,16 @@ impl InsetAxes { self } + /// Sets whether the indicator lines are disabled + /// + /// # Arguments + /// + /// * `disabled` - If true, hides the indicator lines. If false, shows them. + pub fn set_indicator_disabled(&mut self, disabled: bool) -> &mut Self { + self.indicator_disabled = disabled; + self + } + /// Returns options for the inset Axes fn options_for_axes(&self) -> String { let mut opt = String::new(); @@ -314,10 +329,7 @@ mod tests { #[test] fn test_new() { let inset = InsetAxes::new(); - assert_eq!(inset.xmin, 0.0); - assert_eq!(inset.xmax, 1.0); - assert_eq!(inset.ymin, 0.0); - assert_eq!(inset.ymax, 1.0); + assert_eq!(inset.range, None); assert!(inset.buffer.is_empty()); } @@ -325,10 +337,7 @@ mod tests { fn test_set_range() { let mut inset = InsetAxes::new(); inset.set_range(-1.0, 2.0, -3.0, 4.0); - assert_eq!(inset.xmin, -1.0); - assert_eq!(inset.xmax, 2.0); - assert_eq!(inset.ymin, -3.0); - assert_eq!(inset.ymax, 4.0); + assert_eq!(inset.range, Some((-1.0, 2.0, -3.0, 4.0))); } #[test] @@ -374,6 +383,25 @@ mod tests { assert!(buffer.contains("plt.gca().indicate_inset_zoom(zoom")); } + #[test] + fn test_indicator_disabled() { + let mut inset = InsetAxes::new(); + assert_eq!(inset.indicator_disabled, false); + + inset.set_indicator_disabled(true); + assert_eq!(inset.indicator_disabled, true); + + inset.draw(0.5, 0.5, 0.4, 0.3); + let buffer = inset.get_buffer(); + assert!(!buffer.contains("indicate_inset_zoom")); + + inset.set_indicator_disabled(false); + inset.clear_buffer(); + inset.draw(0.5, 0.5, 0.4, 0.3); + let buffer = inset.get_buffer(); + assert!(buffer.contains("indicate_inset_zoom")); + } + #[test] fn test_clear_buffer() { let mut inset = InsetAxes::new(); diff --git a/tests/test_inset_axes.rs b/tests/test_inset_axes.rs index b6cc590..4eeaf68 100644 --- a/tests/test_inset_axes.rs +++ b/tests/test_inset_axes.rs @@ -252,3 +252,57 @@ fn test_inset_axes_6() -> Result<(), StrError> { assert!(n > 920 && n < 1010); Ok(()) } + +#[test] +fn test_inset_axes_7() -> Result<(), StrError> { + // curve + let mut curve = Curve::new(); + let x = &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]; + let y = &[1.0, 4.0, 9.0, 16.0, 25.0, 36.0, 49.0, 64.0]; + curve.draw(x, y); + + // first inset axes + let mut inset1 = InsetAxes::new(); + inset1 + .set_indicator_line_color("red") + .add(&curve) + .set_range(7.0, 8.2, 55.0, 65.0) + .draw(0.02, 0.78, 0.2, 0.2); + + // second inset axes + let mut inset2 = InsetAxes::new(); + inset2 + .set_indicator_line_color("green") + .add(&curve) + .set_range(0.8, 2.5, 0.0, 13.0) + .draw(0.02, 0.38, 0.3, 0.2); + + // third inset axes + let mut inset3 = InsetAxes::new(); + inset3 + .set_indicator_disabled(true) + .set_visibility(true) + .set_extra_for_axes("title='MINIATURE'") + .add(&curve) + .draw(0.64, 0.08, 0.34, 0.34); + + // add to plot + let mut plot = Plot::new(); + plot.add(&curve); + + // save figure + let path = Path::new(OUT_DIR).join("integ_inset_axes_7.svg"); + plot.add(&inset1) + .add(&inset2) + .add(&inset3) + .set_show_errors(true) + .save(&path)?; + + // check number of lines + let file = File::open(path).map_err(|_| "cannot open file")?; + let buffered = BufReader::new(file); + let lines_iter = buffered.lines(); + let n = lines_iter.count().clone(); + assert!(n > 900 && n < 1000); + Ok(()) +}