use super::{call_python3, Legend, StrError, SuperTitleParams};
use std::ffi::OsStr;
use std::fmt::Write;
use std::fs::File;
use std::io::Write as IoWrite;
use std::path::Path;
pub trait GraphMaker {
fn get_buffer<'a>(&'a self) -> &'a String;
fn clear_buffer(&mut self);
}
pub struct Plot {
show_errors: bool, buffer: String, save_tight: bool, save_pad_inches: Option<f64>, save_transparent: Option<bool>, }
impl Plot {
pub fn new() -> Self {
Plot {
show_errors: false,
buffer: String::new(),
save_tight: true,
save_pad_inches: None,
save_transparent: None,
}
}
pub fn add(&mut self, graph: &dyn GraphMaker) -> &mut Self {
self.buffer.push_str(graph.get_buffer());
self
}
pub fn set_save_tight(&mut self, tight: bool) -> &mut Self {
self.save_tight = tight;
self
}
pub fn set_save_pad_inches(&mut self, pad_inches: f64) -> &mut Self {
self.save_pad_inches = Some(pad_inches);
self
}
pub fn set_save_transparent(&mut self, transparent: bool) -> &mut Self {
self.save_transparent = Some(transparent);
self
}
pub fn save<S>(&self, figure_path: &S) -> Result<(), StrError>
where
S: AsRef<OsStr> + ?Sized,
{
self.run(figure_path, false)
}
pub fn save_and_show<S>(&self, figure_path: &S) -> Result<(), StrError>
where
S: AsRef<OsStr> + ?Sized,
{
self.run(figure_path, true)
}
pub fn clear_current_axes(&mut self) -> &mut Self {
self.buffer.push_str("plt.gca().cla()\n");
self
}
pub fn clear_current_figure(&mut self) -> &mut Self {
self.buffer.push_str("plt.clf()\n");
self
}
pub fn legend(&mut self) -> &mut Self {
let mut legend = Legend::new();
legend.draw();
self.add(&legend)
}
pub fn grid_and_labels(&mut self, xlabel: &str, ylabel: &str) -> &mut Self {
write!(
&mut self.buffer,
"plt.gca().set_axisbelow(True)\n\
plt.grid(linestyle='--',color='grey',zorder=-1000)\n\
plt.gca().set_xlabel(r'{}')\n\
plt.gca().set_ylabel(r'{}')\n",
xlabel, ylabel
)
.unwrap();
self
}
pub fn grid_labels_legend(&mut self, xlabel: &str, ylabel: &str) -> &mut Self {
write!(
&mut self.buffer,
"plt.gca().set_axisbelow(True)\n\
plt.grid(linestyle='--',color='grey',zorder=-1000)\n\
plt.gca().set_xlabel(r'{}')\n\
plt.gca().set_ylabel(r'{}')\n",
xlabel, ylabel
)
.unwrap();
self.legend()
}
pub fn set_show_errors(&mut self, option: bool) -> &mut Self {
self.show_errors = option;
self
}
pub fn set_subplot_3d(&mut self, row: usize, col: usize, index: usize) -> &mut Self {
write!(&mut self.buffer, "\nsubplot_3d({},{},{})\n", row, col, index).unwrap();
self
}
pub fn set_subplot(&mut self, row: usize, col: usize, index: usize) -> &mut Self {
write!(&mut self.buffer, "\nplt.subplot({},{},{})\n", row, col, index).unwrap();
self
}
pub fn set_gridspec(&mut self, grid_handle: &str, row: usize, col: usize, options: &str) -> &mut Self {
write!(
&mut self.buffer,
"grid_{}=plt.GridSpec({},{},{})\n",
grid_handle, row, col, options
)
.unwrap();
self
}
pub fn set_subplot_grid(&mut self, grid_handle: &str, i_range: &str, j_range: &str) -> &mut Self {
write!(
&mut self.buffer,
"\nplt.subplot(grid_{}[{},{}])\n",
grid_handle, i_range, j_range
)
.unwrap();
self
}
pub fn set_rotation_ticks_x(&mut self, rotation: f64) -> &mut Self {
write!(
&mut self.buffer,
"plt.gca().tick_params(axis='x',rotation={})\n",
rotation
)
.unwrap();
self
}
pub fn set_rotation_ticks_y(&mut self, rotation: f64) -> &mut Self {
write!(
&mut self.buffer,
"plt.gca().tick_params(axis='y',rotation={})\n",
rotation
)
.unwrap();
self
}
pub fn set_align_labels(&mut self) -> &mut Self {
write!(&mut self.buffer, "plt.gcf().align_labels()\n").unwrap();
self
}
pub fn set_title(&mut self, title: &str) -> &mut Self {
write!(&mut self.buffer, "plt.title(r'{}')\n", title).unwrap();
self
}
pub fn set_super_title(&mut self, title: &str, params: Option<SuperTitleParams>) -> &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(),
}
write!(&mut self.buffer, "add_to_ea(st)\n").unwrap();
self
}
pub fn set_horizontal_gap(&mut self, value: f64) -> &mut Self {
write!(&mut self.buffer, "plt.subplots_adjust(wspace={})\n", value).unwrap();
self
}
pub fn set_vertical_gap(&mut self, value: f64) -> &mut Self {
write!(&mut self.buffer, "plt.subplots_adjust(hspace={})\n", value).unwrap();
self
}
pub fn set_gaps(&mut self, horizontal: f64, vertical: f64) -> &mut Self {
write!(
&mut self.buffer,
"plt.subplots_adjust(wspace={},hspace={})\n",
horizontal, vertical
)
.unwrap();
self
}
pub fn set_equal_axes(&mut self, equal: bool) -> &mut Self {
if equal {
self.buffer.push_str("set_equal_axes()\n");
} else {
self.buffer.push_str("plt.gca().axes.set_aspect('auto')\n");
}
self
}
pub fn set_figure_size_inches(&mut self, width: f64, height: f64) -> &mut Self {
write!(&mut self.buffer, "plt.gcf().set_size_inches({},{})\n", width, height).unwrap();
self
}
#[rustfmt::skip]
pub fn set_figure_size_points(&mut self, width: f64, height: f64) -> &mut Self {
const FACTOR: f64 = 72.27;
write!(&mut self.buffer, "plt.gcf().set_size_inches({},{})\n", width / FACTOR, height / FACTOR).unwrap();
self
}
pub fn set_hide_xticks(&mut self) -> &mut Self {
write!(&mut self.buffer, "plt.gca().set_xticklabels([])\n").unwrap();
self
}
pub fn set_hide_yticks(&mut self) -> &mut Self {
write!(&mut self.buffer, "plt.gca().set_yticklabels([])\n").unwrap();
self
}
pub fn set_hide_zticks(&mut self) -> &mut Self {
write!(&mut self.buffer, "plt.gca().set_zticklabels([])\n").unwrap();
self
}
pub fn set_hide_axes(&mut self, hide: bool) -> &mut Self {
let option = if hide { "off" } else { "on" };
write!(&mut self.buffer, "plt.axis('{}')\n", option).unwrap();
self
}
pub fn set_range_3d(&mut self, xmin: f64, xmax: f64, ymin: f64, ymax: f64, zmin: f64, zmax: f64) -> &mut Self {
write!(
&mut self.buffer,
"plt.gca().set_xlim({},{})\n\
plt.gca().set_ylim({},{})\n\
plt.gca().set_zlim({},{})\n",
xmin, xmax, ymin, ymax, zmin, zmax,
)
.unwrap();
self
}
pub fn set_range(&mut self, xmin: f64, xmax: f64, ymin: f64, ymax: f64) -> &mut Self {
write!(&mut self.buffer, "plt.axis([{},{},{},{}])\n", xmin, xmax, ymin, ymax).unwrap();
self
}
pub fn set_range_from_vec(&mut self, limits: &[f64]) -> &mut Self {
write!(
&mut self.buffer,
"plt.axis([{},{},{},{}])\n",
limits[0], limits[1], limits[2], limits[3]
)
.unwrap();
self
}
pub fn set_xmin(&mut self, xmin: f64) -> &mut Self {
write!(&mut self.buffer, "plt.gca().set_xlim([{},None])\n", xmin).unwrap();
self
}
pub fn set_xmax(&mut self, xmax: f64) -> &mut Self {
write!(&mut self.buffer, "plt.gca().set_xlim([None,{}])\n", xmax).unwrap();
self
}
pub fn set_ymin(&mut self, ymin: f64) -> &mut Self {
write!(&mut self.buffer, "plt.gca().set_ylim([{},None])\n", ymin).unwrap();
self
}
pub fn set_ymax(&mut self, ymax: f64) -> &mut Self {
write!(&mut self.buffer, "plt.gca().set_ylim([None,{}])\n", ymax).unwrap();
self
}
pub fn set_zmin(&mut self, zmin: f64) -> &mut Self {
write!(&mut self.buffer, "plt.gca().set_zlim([{},None])\n", zmin).unwrap();
self
}
pub fn set_zmax(&mut self, zmax: f64) -> &mut Self {
write!(&mut self.buffer, "plt.gca().set_zlim([None,{}])\n", zmax).unwrap();
self
}
pub fn set_xrange(&mut self, xmin: f64, xmax: f64) -> &mut Self {
write!(&mut self.buffer, "plt.gca().set_xlim([{},{}])\n", xmin, xmax).unwrap();
self
}
pub fn set_yrange(&mut self, ymin: f64, ymax: f64) -> &mut Self {
write!(&mut self.buffer, "plt.gca().set_ylim([{},{}])\n", ymin, ymax).unwrap();
self
}
pub fn set_zrange(&mut self, zmin: f64, zmax: f64) -> &mut Self {
write!(&mut self.buffer, "plt.gca().set_zlim([{},{}])\n", zmin, zmax).unwrap();
self
}
pub fn set_num_ticks_x(&mut self, num: usize) -> &mut Self {
if num == 0 {
self.buffer.push_str("plt.gca().get_xaxis().set_ticks([])\n");
} else {
write!(
&mut self.buffer,
"plt.gca().get_xaxis().set_major_locator(tck.MaxNLocator({}))\n",
num
)
.unwrap();
}
self
}
pub fn set_num_ticks_y(&mut self, num: usize) -> &mut Self {
if num == 0 {
self.buffer.push_str("plt.gca().get_yaxis().set_ticks([])\n");
} else {
write!(
&mut self.buffer,
"plt.gca().get_yaxis().set_major_locator(tck.MaxNLocator({}))\n",
num
)
.unwrap();
}
self
}
pub fn set_num_ticks_z(&mut self, num: usize) -> &mut Self {
if num == 0 {
self.buffer.push_str("plt.gca().get_zaxis().set_ticks([])\n");
} else {
write!(
&mut self.buffer,
"plt.gca().get_zaxis().set_major_locator(tck.MaxNLocator({}))\n",
num
)
.unwrap();
}
self
}
#[rustfmt::skip]
pub fn set_ticks_x(&mut self, major_every: f64, minor_every: f64, major_number_format: &str) -> &mut Self {
if major_every > 0.0 {
write!(&mut self.buffer, "major_locator = tck.MultipleLocator({})\n", major_every).unwrap();
write!(&mut self.buffer, "n_ticks = (plt.gca().axis()[1] - plt.gca().axis()[0]) / {}\n", major_every).unwrap();
write!(&mut self.buffer, "if n_ticks < major_locator.MAXTICKS * 0.9:\n").unwrap();
write!(&mut self.buffer, " plt.gca().xaxis.set_major_locator(major_locator)\n").unwrap();
}
if minor_every > 0.0 {
write!(&mut self.buffer, "minor_locator = tck.MultipleLocator({})\n", minor_every).unwrap();
write!(&mut self.buffer, "n_ticks = (plt.gca().axis()[1] - plt.gca().axis()[0]) / {}\n", minor_every).unwrap();
write!(&mut self.buffer, "if n_ticks < minor_locator.MAXTICKS * 0.9:\n").unwrap();
write!(&mut self.buffer, " plt.gca().xaxis.set_minor_locator(minor_locator)\n").unwrap();
}
if major_number_format != "" {
write!(&mut self.buffer, "major_formatter = tck.FormatStrFormatter(r'{}')\n", major_number_format).unwrap();
write!(&mut self.buffer, "plt.gca().xaxis.set_major_formatter(major_formatter)\n").unwrap();
}
self
}
#[rustfmt::skip]
pub fn set_ticks_y(&mut self, major_every: f64, minor_every: f64, major_number_format: &str) -> &mut Self {
if major_every > 0.0 {
write!(&mut self.buffer, "major_locator = tck.MultipleLocator({})\n", major_every).unwrap();
write!(&mut self.buffer, "n_ticks = (plt.gca().axis()[3] - plt.gca().axis()[2]) / {}\n", major_every).unwrap();
write!(&mut self.buffer, "if n_ticks < major_locator.MAXTICKS * 0.9:\n").unwrap();
write!(&mut self.buffer, " plt.gca().yaxis.set_major_locator(major_locator)\n").unwrap();
}
if minor_every > 0.0 {
write!(&mut self.buffer, "minor_locator = tck.MultipleLocator({})\n", minor_every).unwrap();
write!(&mut self.buffer, "n_ticks = (plt.gca().axis()[3] - plt.gca().axis()[2]) / {}\n", minor_every).unwrap();
write!(&mut self.buffer, "if n_ticks < minor_locator.MAXTICKS * 0.9:\n").unwrap();
write!(&mut self.buffer, " plt.gca().yaxis.set_minor_locator(minor_locator)\n").unwrap();
}
if major_number_format != "" {
write!(&mut self.buffer, "major_formatter = tck.FormatStrFormatter(r'{}')\n", major_number_format).unwrap();
write!(&mut self.buffer, "plt.gca().yaxis.set_major_formatter(major_formatter)\n").unwrap();
}
self
}
#[inline]
fn write_multiple_of_pi_formatter(&mut self) {
write!(
&mut self.buffer,
"def multiple_of_pi_formatter(x, pos):\n\
\x20\x20\x20\x20den = 2\n\
\x20\x20\x20\x20num = int(np.rint(den*x/np.pi))\n\
\x20\x20\x20\x20com = np.gcd(num,den)\n\
\x20\x20\x20\x20(num,den) = (int(num/com),int(den/com))\n\
\x20\x20\x20\x20if den==1:\n\
\x20\x20\x20\x20\x20\x20\x20\x20if num==0: return r'$0$'\n\
\x20\x20\x20\x20\x20\x20\x20\x20if num==1: return r'$\\pi$'\n\
\x20\x20\x20\x20\x20\x20\x20\x20elif num==-1: return r'$-\\pi$'\n\
\x20\x20\x20\x20\x20\x20\x20\x20else: return r'$%s\\pi$'%num\n\
\x20\x20\x20\x20else:\n\
\x20\x20\x20\x20\x20\x20\x20\x20if num==1: return r'$\\frac{{\\pi}}{{%s}}$'%den\n\
\x20\x20\x20\x20\x20\x20\x20\x20elif num==-1: return r'$\\frac{{-\\pi}}{{%s}}$'%den\n\
\x20\x20\x20\x20\x20\x20\x20\x20else: return r'$\\frac{{%s\\pi}}{{%s}}$'%(num,den)\n"
)
.unwrap();
}
#[rustfmt::skip]
pub fn set_ticks_x_multiple_of_pi(&mut self, minor_every: f64) -> &mut Self {
write!(&mut self.buffer, "major_locator = tck.MultipleLocator(np.pi/2.0)\n").unwrap();
write!(&mut self.buffer, "n_ticks = (plt.gca().axis()[1] - plt.gca().axis()[0]) / (np.pi/2.0)\n").unwrap();
write!(&mut self.buffer, "if n_ticks < major_locator.MAXTICKS * 0.9:\n").unwrap();
write!(&mut self.buffer, " plt.gca().xaxis.set_major_locator(major_locator)\n").unwrap();
if minor_every > 0.0 {
write!(&mut self.buffer, "minor_locator = tck.MultipleLocator({})\n", minor_every).unwrap();
write!(&mut self.buffer, "n_ticks = (plt.gca().axis()[1] - plt.gca().axis()[0]) / {}\n", minor_every).unwrap();
write!(&mut self.buffer, "if n_ticks < minor_locator.MAXTICKS * 0.9:\n").unwrap();
write!(&mut self.buffer, " plt.gca().xaxis.set_minor_locator(minor_locator)\n").unwrap();
}
self.write_multiple_of_pi_formatter();
write!(&mut self.buffer, "major_formatter = tck.FuncFormatter(multiple_of_pi_formatter)\n").unwrap();
write!(&mut self.buffer, "plt.gca().xaxis.set_major_formatter(major_formatter)\n").unwrap();
self
}
#[rustfmt::skip]
pub fn set_ticks_y_multiple_of_pi(&mut self, minor_every: f64) -> &mut Self {
write!(&mut self.buffer, "major_locator = tck.MultipleLocator(np.pi/2.0)\n").unwrap();
write!(&mut self.buffer, "n_ticks = (plt.gca().axis()[3] - plt.gca().axis()[2]) / (np.pi/2.0)\n").unwrap();
write!(&mut self.buffer, "if n_ticks < major_locator.MAXTICKS * 0.9:\n").unwrap();
write!(&mut self.buffer, " plt.gca().yaxis.set_major_locator(major_locator)\n").unwrap();
if minor_every > 0.0 {
write!(&mut self.buffer, "minor_locator = tck.MultipleLocator({})\n", minor_every).unwrap();
write!(&mut self.buffer, "n_ticks = (plt.gca().axis()[3] - plt.gca().axis()[2]) / {}\n", minor_every).unwrap();
write!(&mut self.buffer, "if n_ticks < minor_locator.MAXTICKS * 0.9:\n").unwrap();
write!(&mut self.buffer, " plt.gca().yaxis.set_minor_locator(minor_locator)\n").unwrap();
}
self.write_multiple_of_pi_formatter();
write!(&mut self.buffer, "major_formatter = tck.FuncFormatter(multiple_of_pi_formatter)\n").unwrap();
write!(&mut self.buffer, "plt.gca().yaxis.set_major_formatter(major_formatter)\n").unwrap();
self
}
pub fn set_log_x(&mut self, log: bool) -> &mut Self {
if log {
self.buffer.push_str("plt.gca().set_xscale('log')\n");
} else {
self.buffer.push_str("plt.gca().set_xscale('linear')\n");
}
self
}
pub fn set_log_y(&mut self, log: bool) -> &mut Self {
if log {
self.buffer.push_str("plt.gca().set_yscale('log')\n");
} else {
self.buffer.push_str("plt.gca().set_yscale('linear')\n");
}
self
}
pub fn set_label_x(&mut self, label: &str) -> &mut Self {
write!(&mut self.buffer, "plt.gca().set_xlabel(r'{}')\n", label).unwrap();
self
}
pub fn set_label_y(&mut self, label: &str) -> &mut Self {
write!(&mut self.buffer, "plt.gca().set_ylabel(r'{}')\n", label).unwrap();
self
}
pub fn set_label_z(&mut self, label: &str) -> &mut Self {
write!(&mut self.buffer, "plt.gca().set_zlabel(r'{}')\n", label).unwrap();
self
}
pub fn set_label_x_and_pad(&mut self, label: &str, pad: f64) -> &mut Self {
write!(
&mut self.buffer,
"plt.gca().set_xlabel(r'{}',labelpad={})\n",
label, pad
)
.unwrap();
self
}
pub fn set_label_y_and_pad(&mut self, label: &str, pad: f64) -> &mut Self {
write!(
&mut self.buffer,
"plt.gca().set_ylabel(r'{}',labelpad={})\n",
label, pad
)
.unwrap();
self
}
pub fn set_label_z_and_pad(&mut self, label: &str, pad: f64) -> &mut Self {
write!(
&mut self.buffer,
"plt.gca().set_zlabel(r'{}',labelpad={})\n",
label, pad
)
.unwrap();
self
}
pub fn set_labels(&mut self, xlabel: &str, ylabel: &str) -> &mut Self {
write!(
&mut self.buffer,
"plt.gca().set_xlabel(r'{}')\nplt.gca().set_ylabel(r'{}')\n",
xlabel, ylabel
)
.unwrap();
self
}
pub fn set_labels_3d(&mut self, xlabel: &str, ylabel: &str, zlabel: &str) -> &mut Self {
write!(
&mut self.buffer,
"plt.gca().set_xlabel(r'{}')\nplt.gca().set_ylabel(r'{}')\nplt.gca().set_zlabel(r'{}')\n",
xlabel, ylabel, zlabel
)
.unwrap();
self
}
pub fn set_inv_x(&mut self) -> &mut Self {
write!(&mut self.buffer, "plt.gca().invert_xaxis()\n").unwrap();
self
}
pub fn set_inv_y(&mut self) -> &mut Self {
write!(&mut self.buffer, "plt.gca().invert_yaxis()\n").unwrap();
self
}
pub fn set_camera(&mut self, elev: f64, azimuth: f64) -> &mut Self {
write!(
&mut self.buffer,
"plt.gca().view_init(elev={},azim={})\n",
elev, azimuth
)
.unwrap();
self
}
pub fn set_frame_border(&mut self, left: bool, right: bool, bottom: bool, top: bool) -> &mut Self {
if left {
self.buffer.push_str("plt.gca().spines['left'].set_visible(True)\n");
} else {
self.buffer.push_str("plt.gca().spines['left'].set_visible(False)\n");
}
if right {
self.buffer.push_str("plt.gca().spines['right'].set_visible(True)\n");
} else {
self.buffer.push_str("plt.gca().spines['right'].set_visible(False)\n");
}
if bottom {
self.buffer.push_str("plt.gca().spines['bottom'].set_visible(True)\n");
} else {
self.buffer.push_str("plt.gca().spines['bottom'].set_visible(False)\n");
}
if top {
self.buffer.push_str("plt.gca().spines['top'].set_visible(True)\n");
} else {
self.buffer.push_str("plt.gca().spines['top'].set_visible(False)\n");
}
self
}
pub fn set_frame_borders(&mut self, show_all: bool) -> &mut Self {
self.set_frame_border(show_all, show_all, show_all, show_all)
}
pub fn extra(&mut self, commands: &str) -> &mut Self {
self.buffer.write_str(commands).unwrap();
self
}
fn run<S>(&self, figure_path: &S, show: bool) -> Result<(), StrError>
where
S: AsRef<OsStr> + ?Sized,
{
let fig_path = Path::new(figure_path);
let mut txt = "plt.savefig(fn".to_string();
if self.save_tight {
txt.push_str(",bbox_inches='tight',bbox_extra_artists=EXTRA_ARTISTS");
}
if let Some(pad) = self.save_pad_inches {
txt.push_str(format!(",pad_inches={}", pad).as_str());
}
if let Some(transparent) = self.save_transparent {
if transparent {
txt.push_str(",transparent=True");
}
}
txt.push_str(")\n");
if show {
txt.push_str("\nplt.show()\n");
};
let commands = format!("{}\nfn=r'{}'\n{}", self.buffer, fig_path.to_string_lossy(), txt);
let mut path = Path::new(figure_path).to_path_buf();
path.set_extension("py");
let output = call_python3(&commands, &path)?;
if output != "" {
let mut log_path = Path::new(figure_path).to_path_buf();
log_path.set_extension("log");
let mut log_file = File::create(log_path).map_err(|_| "cannot create log file")?;
log_file
.write_all(output.as_bytes())
.map_err(|_| "cannot write to log file")?;
if self.show_errors {
println!("{}", output);
}
return Err("python3 failed; please see the log file");
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::SuperTitleParams;
use super::Plot;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::Path;
const OUT_DIR: &str = "/tmp/plotpy/unit_tests";
#[test]
fn new_plot_works() {
let plot = Plot::new();
assert_eq!(plot.buffer.len(), 0);
}
#[test]
fn save_works() {
let plot = Plot::new();
assert_eq!(plot.buffer.len(), 0);
let path = Path::new(OUT_DIR).join("save_works.svg");
plot.save(&path).unwrap();
let file = File::open(&path).map_err(|_| "cannot open file").unwrap();
let buffered = BufReader::new(file);
let lines_iter = buffered.lines();
assert!(lines_iter.count() > 20);
}
#[test]
fn save_str_works() {
let plot = Plot::new();
assert_eq!(plot.buffer.len(), 0);
let path = "/tmp/plotpy/unit_tests/save_str_works.svg";
plot.save(&path).unwrap();
let file = File::open(&path).map_err(|_| "cannot open file").unwrap();
let buffered = BufReader::new(file);
let lines_iter = buffered.lines();
assert!(lines_iter.count() > 20);
}
#[test]
fn show_errors_works() {
const WRONG: usize = 0;
let mut plot = Plot::new();
plot.set_show_errors(true);
plot.set_subplot(1, 1, WRONG);
let path = Path::new(OUT_DIR).join("show_errors_works.svg");
assert_eq!(plot.save(&path).err(), Some("python3 failed; please see the log file"));
}
#[test]
fn subplot_3d_works() {
let mut plot = Plot::new();
plot.set_subplot_3d(3, 2, 1);
let b: &str = "\nsubplot_3d(3,2,1)\n";
assert_eq!(plot.buffer, b);
}
#[test]
fn subplot_functions_work() {
let mut plot = Plot::new();
plot.set_super_title("all subplots", None)
.set_subplot(2, 2, 1)
.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\
add_to_ea(st)\n\
\nplt.subplot(2,2,1)\n\
plt.subplots_adjust(wspace=0.1)\n\
plt.subplots_adjust(hspace=0.2)\n\
plt.subplots_adjust(wspace=0.3,hspace=0.4)\n";
assert_eq!(plot.buffer, b);
}
#[test]
fn super_title_works() {
let mut params = SuperTitleParams::new();
params
.set_x(123.3)
.set_y(456.7)
.set_align_horizontal("left")
.set_align_vertical("bottom")
.set_fontsize(12.0)
.set_fontweight(10.0);
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\
add_to_ea(st)\n";
assert_eq!(plot.buffer, b);
}
#[test]
fn grid_functions_work() {
let mut plot = Plot::new();
plot.grid_and_labels("xx", "yy").grid_labels_legend("xx", "yy").legend();
let b: &str = "plt.gca().set_axisbelow(True)\n\
plt.grid(linestyle='--',color='grey',zorder=-1000)\n\
plt.gca().set_xlabel(r'xx')\n\
plt.gca().set_ylabel(r'yy')\n\
plt.gca().set_axisbelow(True)\n\
plt.grid(linestyle='--',color='grey',zorder=-1000)\n\
plt.gca().set_xlabel(r'xx')\n\
plt.gca().set_ylabel(r'yy')\n\
h,l=plt.gca().get_legend_handles_labels()\n\
if len(h)>0 and len(l)>0:\n\
\x20\x20\x20\x20leg=plt.legend(handlelength=3,ncol=1,loc='best')\n\
\x20\x20\x20\x20add_to_ea(leg)\n\
h,l=plt.gca().get_legend_handles_labels()\n\
if len(h)>0 and len(l)>0:\n\
\x20\x20\x20\x20leg=plt.legend(handlelength=3,ncol=1,loc='best')\n\
\x20\x20\x20\x20add_to_ea(leg)\n";
assert_eq!(plot.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)
.set_range_3d(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0)
.set_range(-1.0, 1.0, -1.0, 1.0)
.set_range_from_vec(&[0.0, 1.0, 0.0, 1.0])
.set_xrange(-80.0, 800.0)
.set_yrange(13.0, 130.0)
.set_zrange(44.0, 444.0)
.set_xmin(-3.0)
.set_xmax(8.0)
.set_ymin(-7.0)
.set_ymax(33.0)
.set_zmin(12.0)
.set_zmax(34.0)
.set_num_ticks_x(0)
.set_num_ticks_x(8)
.set_num_ticks_y(0)
.set_num_ticks_y(5)
.set_log_x(true)
.set_log_y(true)
.set_log_x(false)
.set_log_y(false)
.set_label_x("x-label")
.set_label_y("y-label")
.set_labels("x", "y")
.set_camera(1.0, 10.0)
.set_ticks_x(1.5, 0.5, "%.2f")
.set_ticks_y(0.5, 0.1, "%g")
.set_figure_size_inches(2.0, 2.0)
.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\
plt.gca().axes.set_aspect('auto')\n\
plt.axis('off')\n\
plt.gca().set_xlim(-1,1)\n\
plt.gca().set_ylim(-1,1)\n\
plt.gca().set_zlim(-1,1)\n\
plt.axis([-1,1,-1,1])\n\
plt.axis([0,1,0,1])\n\
plt.gca().set_xlim([-80,800])\n\
plt.gca().set_ylim([13,130])\n\
plt.gca().set_zlim([44,444])\n\
plt.gca().set_xlim([-3,None])\n\
plt.gca().set_xlim([None,8])\n\
plt.gca().set_ylim([-7,None])\n\
plt.gca().set_ylim([None,33])\n\
plt.gca().set_zlim([12,None])\n\
plt.gca().set_zlim([None,34])\n\
plt.gca().get_xaxis().set_ticks([])\n\
plt.gca().get_xaxis().set_major_locator(tck.MaxNLocator(8))\n\
plt.gca().get_yaxis().set_ticks([])\n\
plt.gca().get_yaxis().set_major_locator(tck.MaxNLocator(5))\n\
plt.gca().set_xscale('log')\n\
plt.gca().set_yscale('log')\n\
plt.gca().set_xscale('linear')\n\
plt.gca().set_yscale('linear')\n\
plt.gca().set_xlabel(r'x-label')\n\
plt.gca().set_ylabel(r'y-label')\n\
plt.gca().set_xlabel(r'x')\n\
plt.gca().set_ylabel(r'y')\n\
plt.gca().view_init(elev=1,azim=10)\n\
major_locator = tck.MultipleLocator(1.5)\n\
n_ticks = (plt.gca().axis()[1] - plt.gca().axis()[0]) / 1.5\n\
if n_ticks < major_locator.MAXTICKS * 0.9:\n\
\x20\x20\x20\x20plt.gca().xaxis.set_major_locator(major_locator)\n\
minor_locator = tck.MultipleLocator(0.5)\n\
n_ticks = (plt.gca().axis()[1] - plt.gca().axis()[0]) / 0.5\n\
if n_ticks < minor_locator.MAXTICKS * 0.9:\n\
\x20\x20\x20\x20plt.gca().xaxis.set_minor_locator(minor_locator)\n\
major_formatter = tck.FormatStrFormatter(r'%.2f')\n\
plt.gca().xaxis.set_major_formatter(major_formatter)\n\
major_locator = tck.MultipleLocator(0.5)\n\
n_ticks = (plt.gca().axis()[3] - plt.gca().axis()[2]) / 0.5\n\
if n_ticks < major_locator.MAXTICKS * 0.9:\n\
\x20\x20\x20\x20plt.gca().yaxis.set_major_locator(major_locator)\n\
minor_locator = tck.MultipleLocator(0.1)\n\
n_ticks = (plt.gca().axis()[3] - plt.gca().axis()[2]) / 0.1\n\
if n_ticks < minor_locator.MAXTICKS * 0.9:\n\
\x20\x20\x20\x20plt.gca().yaxis.set_minor_locator(minor_locator)\n\
major_formatter = tck.FormatStrFormatter(r'%g')\n\
plt.gca().yaxis.set_major_formatter(major_formatter)\n\
plt.gcf().set_size_inches(2,2)\n\
plt.gcf().set_size_inches(100,100)\n\
plt.gca().cla()\n\
plt.clf()\n";
assert_eq!(plot.buffer, b);
assert_eq!(plot.show_errors, true);
}
#[test]
fn set_functions_work_2() {
let mut plot = Plot::new();
plot.set_ticks_x_multiple_of_pi(0.0);
let b: &str = "major_locator = tck.MultipleLocator(np.pi/2.0)\n\
n_ticks = (plt.gca().axis()[1] - plt.gca().axis()[0]) / (np.pi/2.0)\n\
if n_ticks < major_locator.MAXTICKS * 0.9:\n\
\x20\x20\x20\x20plt.gca().xaxis.set_major_locator(major_locator)\n\
def multiple_of_pi_formatter(x, pos):\n\
\x20\x20\x20\x20den = 2\n\
\x20\x20\x20\x20num = int(np.rint(den*x/np.pi))\n\
\x20\x20\x20\x20com = np.gcd(num,den)\n\
\x20\x20\x20\x20(num,den) = (int(num/com),int(den/com))\n\
\x20\x20\x20\x20if den==1:\n\
\x20\x20\x20\x20\x20\x20\x20\x20if num==0: return r'$0$'\n\
\x20\x20\x20\x20\x20\x20\x20\x20if num==1: return r'$\\pi$'\n\
\x20\x20\x20\x20\x20\x20\x20\x20elif num==-1: return r'$-\\pi$'\n\
\x20\x20\x20\x20\x20\x20\x20\x20else: return r'$%s\\pi$'%num\n\
\x20\x20\x20\x20else:\n\
\x20\x20\x20\x20\x20\x20\x20\x20if num==1: return r'$\\frac{\\pi}{%s}$'%den\n\
\x20\x20\x20\x20\x20\x20\x20\x20elif num==-1: return r'$\\frac{-\\pi}{%s}$'%den\n\
\x20\x20\x20\x20\x20\x20\x20\x20else: return r'$\\frac{%s\\pi}{%s}$'%(num,den)\n\
major_formatter = tck.FuncFormatter(multiple_of_pi_formatter)\n\
plt.gca().xaxis.set_major_formatter(major_formatter)\n";
assert_eq!(plot.buffer, b);
let mut plot = Plot::new();
plot.set_ticks_y_multiple_of_pi(0.0);
let b: &str = "major_locator = tck.MultipleLocator(np.pi/2.0)\n\
n_ticks = (plt.gca().axis()[3] - plt.gca().axis()[2]) / (np.pi/2.0)\n\
if n_ticks < major_locator.MAXTICKS * 0.9:\n\
\x20\x20\x20\x20plt.gca().yaxis.set_major_locator(major_locator)\n\
def multiple_of_pi_formatter(x, pos):\n\
\x20\x20\x20\x20den = 2\n\
\x20\x20\x20\x20num = int(np.rint(den*x/np.pi))\n\
\x20\x20\x20\x20com = np.gcd(num,den)\n\
\x20\x20\x20\x20(num,den) = (int(num/com),int(den/com))\n\
\x20\x20\x20\x20if den==1:\n\
\x20\x20\x20\x20\x20\x20\x20\x20if num==0: return r'$0$'\n\
\x20\x20\x20\x20\x20\x20\x20\x20if num==1: return r'$\\pi$'\n\
\x20\x20\x20\x20\x20\x20\x20\x20elif num==-1: return r'$-\\pi$'\n\
\x20\x20\x20\x20\x20\x20\x20\x20else: return r'$%s\\pi$'%num\n\
\x20\x20\x20\x20else:\n\
\x20\x20\x20\x20\x20\x20\x20\x20if num==1: return r'$\\frac{\\pi}{%s}$'%den\n\
\x20\x20\x20\x20\x20\x20\x20\x20elif num==-1: return r'$\\frac{-\\pi}{%s}$'%den\n\
\x20\x20\x20\x20\x20\x20\x20\x20else: return r'$\\frac{%s\\pi}{%s}$'%(num,den)\n\
major_formatter = tck.FuncFormatter(multiple_of_pi_formatter)\n\
plt.gca().yaxis.set_major_formatter(major_formatter)\n";
assert_eq!(plot.buffer, b);
let mut plot = Plot::new();
plot.set_ticks_x_multiple_of_pi(1.0);
let b: &str = "major_locator = tck.MultipleLocator(np.pi/2.0)\n\
n_ticks = (plt.gca().axis()[1] - plt.gca().axis()[0]) / (np.pi/2.0)\n\
if n_ticks < major_locator.MAXTICKS * 0.9:\n\
\x20\x20\x20\x20plt.gca().xaxis.set_major_locator(major_locator)\n\
minor_locator = tck.MultipleLocator(1)\n\
n_ticks = (plt.gca().axis()[1] - plt.gca().axis()[0]) / 1\n\
if n_ticks < minor_locator.MAXTICKS * 0.9:\n\
\x20\x20\x20\x20plt.gca().xaxis.set_minor_locator(minor_locator)\n\
def multiple_of_pi_formatter(x, pos):\n\
\x20\x20\x20\x20den = 2\n\
\x20\x20\x20\x20num = int(np.rint(den*x/np.pi))\n\
\x20\x20\x20\x20com = np.gcd(num,den)\n\
\x20\x20\x20\x20(num,den) = (int(num/com),int(den/com))\n\
\x20\x20\x20\x20if den==1:\n\
\x20\x20\x20\x20\x20\x20\x20\x20if num==0: return r'$0$'\n\
\x20\x20\x20\x20\x20\x20\x20\x20if num==1: return r'$\\pi$'\n\
\x20\x20\x20\x20\x20\x20\x20\x20elif num==-1: return r'$-\\pi$'\n\
\x20\x20\x20\x20\x20\x20\x20\x20else: return r'$%s\\pi$'%num\n\
\x20\x20\x20\x20else:\n\
\x20\x20\x20\x20\x20\x20\x20\x20if num==1: return r'$\\frac{\\pi}{%s}$'%den\n\
\x20\x20\x20\x20\x20\x20\x20\x20elif num==-1: return r'$\\frac{-\\pi}{%s}$'%den\n\
\x20\x20\x20\x20\x20\x20\x20\x20else: return r'$\\frac{%s\\pi}{%s}$'%(num,den)\n\
major_formatter = tck.FuncFormatter(multiple_of_pi_formatter)\n\
plt.gca().xaxis.set_major_formatter(major_formatter)\n";
assert_eq!(plot.buffer, b);
let mut plot = Plot::new();
plot.set_ticks_y_multiple_of_pi(1.0);
let b: &str = "major_locator = tck.MultipleLocator(np.pi/2.0)\n\
n_ticks = (plt.gca().axis()[3] - plt.gca().axis()[2]) / (np.pi/2.0)\n\
if n_ticks < major_locator.MAXTICKS * 0.9:\n\
\x20\x20\x20\x20plt.gca().yaxis.set_major_locator(major_locator)\n\
minor_locator = tck.MultipleLocator(1)\n\
n_ticks = (plt.gca().axis()[3] - plt.gca().axis()[2]) / 1\n\
if n_ticks < minor_locator.MAXTICKS * 0.9:\n\
\x20\x20\x20\x20plt.gca().yaxis.set_minor_locator(minor_locator)\n\
def multiple_of_pi_formatter(x, pos):\n\
\x20\x20\x20\x20den = 2\n\
\x20\x20\x20\x20num = int(np.rint(den*x/np.pi))\n\
\x20\x20\x20\x20com = np.gcd(num,den)\n\
\x20\x20\x20\x20(num,den) = (int(num/com),int(den/com))\n\
\x20\x20\x20\x20if den==1:\n\
\x20\x20\x20\x20\x20\x20\x20\x20if num==0: return r'$0$'\n\
\x20\x20\x20\x20\x20\x20\x20\x20if num==1: return r'$\\pi$'\n\
\x20\x20\x20\x20\x20\x20\x20\x20elif num==-1: return r'$-\\pi$'\n\
\x20\x20\x20\x20\x20\x20\x20\x20else: return r'$%s\\pi$'%num\n\
\x20\x20\x20\x20else:\n\
\x20\x20\x20\x20\x20\x20\x20\x20if num==1: return r'$\\frac{\\pi}{%s}$'%den\n\
\x20\x20\x20\x20\x20\x20\x20\x20elif num==-1: return r'$\\frac{-\\pi}{%s}$'%den\n\
\x20\x20\x20\x20\x20\x20\x20\x20else: return r'$\\frac{%s\\pi}{%s}$'%(num,den)\n\
major_formatter = tck.FuncFormatter(multiple_of_pi_formatter)\n\
plt.gca().yaxis.set_major_formatter(major_formatter)\n";
assert_eq!(plot.buffer, b);
}
#[test]
fn set_frame_functions_work() {
let mut plot = Plot::new();
plot.set_frame_border(false, false, false, false)
.set_frame_border(true, true, true, true)
.set_frame_borders(false);
let b: &str = "plt.gca().spines['left'].set_visible(False)\n\
plt.gca().spines['right'].set_visible(False)\n\
plt.gca().spines['bottom'].set_visible(False)\n\
plt.gca().spines['top'].set_visible(False)\n\
plt.gca().spines['left'].set_visible(True)\n\
plt.gca().spines['right'].set_visible(True)\n\
plt.gca().spines['bottom'].set_visible(True)\n\
plt.gca().spines['top'].set_visible(True)\n\
plt.gca().spines['left'].set_visible(False)\n\
plt.gca().spines['right'].set_visible(False)\n\
plt.gca().spines['bottom'].set_visible(False)\n\
plt.gca().spines['top'].set_visible(False)\n";
assert_eq!(plot.buffer, b);
}
#[test]
fn additional_features_work() {
let mut plot = Plot::new();
plot.set_inv_x()
.set_inv_y()
.set_hide_xticks()
.set_hide_yticks()
.set_hide_zticks()
.set_label_x_and_pad("X IS CLOSER NOW", -15.0)
.set_label_y_and_pad("Y IS CLOSER NOW", -25.0)
.set_label_z_and_pad("Z IS CLOSER NOW", -35.0)
.extra("plt.show()\n");
let b: &str = "plt.gca().invert_xaxis()\n\
plt.gca().invert_yaxis()\n\
plt.gca().set_xticklabels([])\n\
plt.gca().set_yticklabels([])\n\
plt.gca().set_zticklabels([])\n\
plt.gca().set_xlabel(r'X IS CLOSER NOW',labelpad=-15)\n\
plt.gca().set_ylabel(r'Y IS CLOSER NOW',labelpad=-25)\n\
plt.gca().set_zlabel(r'Z IS CLOSER NOW',labelpad=-35)\n\
plt.show()\n";
assert_eq!(plot.buffer, b);
}
#[test]
fn gridspec_functions_work() {
let mut plot = Plot::new();
plot.set_gridspec("the_grid", 2, 2, "wspace=0.1,hspace=0.2")
.set_subplot_grid("the_grid", "0:2", "0")
.set_rotation_ticks_x(55.0)
.set_rotation_ticks_y(45.0)
.set_align_labels();
let b: &str = "grid_the_grid=plt.GridSpec(2,2,wspace=0.1,hspace=0.2)\n\
\nplt.subplot(grid_the_grid[0:2,0])\n\
plt.gca().tick_params(axis='x',rotation=55)\n\
plt.gca().tick_params(axis='y',rotation=45)\n\
plt.gcf().align_labels()\n";
assert_eq!(plot.buffer, b);
}
#[test]
fn set_labels_3d_works() {
let mut plot = Plot::new();
plot.set_label_z("Z").set_labels_3d("X", "Y", "Z");
let b: &str = "plt.gca().set_zlabel(r'Z')\n\
plt.gca().set_xlabel(r'X')\n\
plt.gca().set_ylabel(r'Y')\n\
plt.gca().set_zlabel(r'Z')\n";
assert_eq!(plot.buffer, b);
}
}