diff --git a/figures/integ_plot_handles_quotes.svg b/figures/integ_plot_handles_quotes.svg new file mode 100644 index 0000000..b41a4ea --- /dev/null +++ b/figures/integ_plot_handles_quotes.svg @@ -0,0 +1,942 @@ + + + + + + + + 2024-07-01T13:47:08.206327 + image/svg+xml + + + Matplotlib v3.6.3, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/figures/integ_plot_subplots.svg b/figures/integ_plot_subplots.svg index 5f25906..90acda7 100644 --- a/figures/integ_plot_subplots.svg +++ b/figures/integ_plot_subplots.svg @@ -1,12 +1,12 @@ - + - 2023-10-09T17:39:41.478020 + 2024-07-01T13:50:41.838715 image/svg+xml @@ -21,8 +21,8 @@ - - @@ -41,17 +41,17 @@ z - - + - + - + - + - + - + - + - + - - + - + - + - + @@ -275,12 +275,12 @@ z - + - + @@ -289,12 +289,12 @@ z - + - + @@ -302,43 +302,264 @@ z - + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - @@ -346,12 +567,12 @@ z - + - + - + @@ -359,12 +580,12 @@ z - + - + - + @@ -372,12 +593,12 @@ z - + - + - + @@ -385,12 +606,12 @@ z - + - + - + @@ -400,12 +621,12 @@ z - + - + - + @@ -413,12 +634,12 @@ z - + - + - + @@ -427,12 +648,12 @@ z - + - + - + @@ -441,12 +662,12 @@ z - + - + - + @@ -454,43 +675,167 @@ z - + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - @@ -498,12 +843,12 @@ z - + - + - + @@ -511,12 +856,12 @@ z - + - + - + @@ -524,12 +869,12 @@ z - + - + - + @@ -537,12 +882,12 @@ z - + - + - + @@ -552,12 +897,12 @@ z - + - + - + @@ -565,12 +910,12 @@ z - + - + - + @@ -579,12 +924,12 @@ z - + - + - + @@ -593,12 +938,12 @@ z - + - + - + @@ -606,43 +951,97 @@ z - + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - @@ -650,12 +1049,12 @@ z - + - + - + @@ -663,12 +1062,12 @@ z - + - + - + @@ -676,12 +1075,12 @@ z - + - + - + @@ -689,12 +1088,12 @@ z - + - + - + @@ -704,12 +1103,12 @@ z - + - + - + @@ -717,12 +1116,12 @@ z - + - + - + @@ -731,12 +1130,12 @@ z - + - + - + @@ -745,12 +1144,12 @@ z - + - + - + @@ -758,41 +1157,116 @@ z - + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - + + - - + + - - + + diff --git a/src/constants.rs b/src/constants.rs index 7e8bbb0..5ce5df9 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -36,7 +36,7 @@ import matplotlib.transforms as tra import mpl_toolkits.mplot3d # Variable to handle NaN values coming from Rust -NaN = np.NaN +NaN = np.nan # List of additional objects to calculate bounding boxes EXTRA_ARTISTS = [] diff --git a/src/plot.rs b/src/plot.rs index 72039e4..f8951e1 100644 --- a/src/plot.rs +++ b/src/plot.rs @@ -307,17 +307,18 @@ impl Plot { /// Adds a title to the plot or sub-plot pub fn set_title(&mut self, title: &str) -> &mut Self { - write!(&mut self.buffer, "plt.title(r'{}')\n", title).unwrap(); + // we need the extra space in case the user passes a double-quoted string + write!(&mut self.buffer, r#"plt.title(""" {} """){}"#, title, "\n").unwrap(); self } /// Adds a title to all sub-plots pub fn set_super_title(&mut self, title: &str, params: Option) -> &mut Self { match params { - Some(p) => write!(&mut self.buffer, "st=plt.suptitle('{}'{})\n", title, p.options()).unwrap(), - None => write!(&mut self.buffer, "st=plt.suptitle('{}')\n", title).unwrap(), + Some(p) => write!(&mut self.buffer, r#"st=plt.suptitle(""" {} """{})"#, title, p.options(),).unwrap(), + None => write!(&mut self.buffer, r#"st=plt.suptitle(""" {} """)"#, title).unwrap(), } - write!(&mut self.buffer, "add_to_ea(st)\n").unwrap(); + write!(&mut self.buffer, "\nadd_to_ea(st)\n").unwrap(); self } @@ -956,7 +957,7 @@ mod tests { .set_horizontal_gap(0.1) .set_vertical_gap(0.2) .set_gaps(0.3, 0.4); - let b: &str = "st=plt.suptitle('all subplots')\n\ + let b: &str = "st=plt.suptitle(\"\"\" all subplots \"\"\")\n\ add_to_ea(st)\n\ \nplt.subplot(2,2,1)\n\ plt.subplots_adjust(wspace=0.1)\n\ @@ -978,7 +979,7 @@ mod tests { let mut plot = Plot::new(); plot.set_super_title("all subplots", Some(params)); let b: &str = - "st=plt.suptitle('all subplots',x=123.3,y=456.7,ha='left',va='bottom',fontsize=12,fontweight=10)\n\ + "st=plt.suptitle(\"\"\" all subplots \"\"\",x=123.3,y=456.7,ha='left',va='bottom',fontsize=12,fontweight=10)\n\ add_to_ea(st)\n"; assert_eq!(plot.buffer, b); } @@ -1006,11 +1007,34 @@ mod tests { assert_eq!(plot.buffer, b); } + #[test] + fn set_title_and_super_title_handle_quotes() { + let mut p1 = Plot::new(); + p1.set_title("Without Quotes").set_super_title("Hi", None); + let b: &str = "plt.title(\"\"\" Without Quotes \"\"\")\n\ + st=plt.suptitle(\"\"\" Hi \"\"\")\n\ + add_to_ea(st)\n"; + assert_eq!(p1.buffer, b); + + let mut p2 = Plot::new(); + p2.set_title("Developer's Plot").set_super_title("Dev's", None); + let b: &str = "plt.title(\"\"\" Developer's Plot \"\"\")\n\ + st=plt.suptitle(\"\"\" Dev's \"\"\")\n\ + add_to_ea(st)\n"; + assert_eq!(p2.buffer, b); + + let mut p3 = Plot::new(); + p3.set_title("\"Look at This\"").set_super_title("\"Dev's\"", None); + let b: &str = "plt.title(\"\"\" \"Look at This\" \"\"\")\n\ + st=plt.suptitle(\"\"\" \"Dev's\" \"\"\")\n\ + add_to_ea(st)\n"; + assert_eq!(p3.buffer, b); + } + #[test] fn set_functions_work() { let mut plot = Plot::new(); plot.set_show_errors(true) - .set_title("my plot") .set_equal_axes(true) .set_equal_axes(false) .set_hide_axes(true) @@ -1044,8 +1068,7 @@ mod tests { .set_figure_size_points(7227.0, 7227.0) .clear_current_axes() .clear_current_figure(); - let b: &str = "plt.title(r'my plot')\n\ - set_equal_axes()\n\ + let b: &str = "set_equal_axes()\n\ plt.gca().axes.set_aspect('auto')\n\ plt.axis('off')\n\ plt.gca().set_xlim(-1,1)\n\ diff --git a/tests/test_plot.rs b/tests/test_plot.rs index 518c2d8..ab18196 100644 --- a/tests/test_plot.rs +++ b/tests/test_plot.rs @@ -42,7 +42,7 @@ fn test_plot() -> Result<(), StrError> { .set_labels("x", "y") .clear_current_axes(); plot.clear_current_figure(); - plot.set_title("my plot") + plot.set_title("my plot'") // the extra "'" should be sanitized .set_frame_borders(false) .set_frame_borders(true) .set_frame_borders(false) @@ -160,6 +160,25 @@ fn test_plot_error() { assert_eq!(plot.save(&path).err(), Some("python3 failed; please see the log file")); } +#[test] +fn test_plot_handles_quotes() -> Result<(), StrError> { + let mut plot = Plot::new(); + plot.set_title("\"$\\int$ \"The Plot of the Developer\" $versus$ \"Developer's Plot\" $\\mathrm{d}\\sigma$\""); + + // save figure + let path = Path::new(OUT_DIR).join("integ_plot_handles_quotes.svg"); + plot.set_figure_size_points(250.0, 250.0 * 0.75); + plot.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 count = lines_iter.count(); + assert!(count > 920 && count < 980); + Ok(()) +} + #[test] fn test_plot_subplots() -> Result<(), StrError> { // curve object and options @@ -176,20 +195,16 @@ fn test_plot_subplots() -> Result<(), StrError> { // configure plot let mut plot = Plot::new(); - plot.set_super_title("This is the \"super title\", \\n followed by a very long text to see \\n if this whole thing will be wrapped or not \\n we hope that it gets wrapped and beautifully formatted.", Some(params)) + plot.set_super_title("\"Plot's Owner Says: This is the \"super title\", \\n followed by a very long text to see \\n if this whole thing will be wrapped or not \\n we hope that it gets wrapped and beautifully formatted.\"", Some(params)) .set_horizontal_gap(0.5) .set_vertical_gap(0.5) - .set_gaps(0.3, 0.2); + .set_gaps(0.3, 0.3); // add curve to subplots - plot.set_subplot(2, 2, 1); - plot.add(&curve); - plot.set_subplot(2, 2, 2); - plot.add(&curve); - plot.set_subplot(2, 2, 3); - plot.add(&curve); - plot.set_subplot(2, 2, 4); - plot.add(&curve); + plot.set_subplot(2, 2, 1).set_title("\"Owner's First\"").add(&curve); + plot.set_subplot(2, 2, 2).set_title("\"Owner's Second\"").add(&curve); + plot.set_subplot(2, 2, 3).set_title("\"Owner's Third\"").add(&curve); + plot.set_subplot(2, 2, 4).set_title("\"Owner's Fourth\"").add(&curve); // save figure let path = Path::new(OUT_DIR).join("integ_plot_subplots.svg");