diff --git a/Cargo.toml b/Cargo.toml index 3c8eb143..c4fc2ce9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "peroxide" -version = "0.34.7" +version = "0.35.0" authors = ["axect "] edition = "2018" description = "Rust comprehensive scientific computation library contains linear algebra, numerical analysis, statistics and machine learning tools with farmiliar syntax" @@ -30,7 +30,7 @@ peroxide-ad = "0.3" peroxide-num = "0.1" #num-complex = "0.3" netcdf = { version = "0.7", optional = true, default_features = false } -pyo3 = { version = "0.20", optional = true, features = ["auto-initialize"] } +pyo3 = { version = "0.21", optional = true, features = ["auto-initialize", "gil-refs"] } blas = { version = "0.22", optional = true } lapack = { version = "0.19", optional = true } serde = { version = "1.0", features = ["derive"], optional = true } diff --git a/RELEASES.md b/RELEASES.md index 6a909e33..60693bc3 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,13 @@ +# Release 0.35.0 (2024-03-29) + +## Change some plot functions + +- Now you can set marker, line style, color, alpha option for specific element. + - `set_marker(vec![(usize, Marker)])` : `usize` is index of element (image or pair) + - `set_line_style(vec![(usize, LineStyle)])` + - `set_color(vec![(usize, String)])` + - `set_alpha(vec![(usize, f64)])` + # Release 0.34.7 (2024-03-11) ## More updates for `plot` feature diff --git a/example_data/test_plot.png b/example_data/test_plot.png index a4475760..d3d1344f 100644 Binary files a/example_data/test_plot.png and b/example_data/test_plot.png differ diff --git a/src/structure/matrix.rs b/src/structure/matrix.rs index baf7bbdd..b0cbb4f4 100644 --- a/src/structure/matrix.rs +++ b/src/structure/matrix.rs @@ -614,7 +614,6 @@ use self::csv::{ReaderBuilder, StringRecord, WriterBuilder}; extern crate blas; #[cfg(feature = "O3")] extern crate lapack; -use ::matrixmultiply; #[cfg(feature = "O3")] use blas::{daxpy, dgemm, dgemv}; #[cfg(feature = "O3")] diff --git a/src/util/plot.rs b/src/util/plot.rs index ee0ba40b..6208b1d0 100644 --- a/src/util/plot.rs +++ b/src/util/plot.rs @@ -3,83 +3,44 @@ //! For Rust, there are some plot libraries but, still difficult to use. //! Practically, using python is best choice to plot. And there is awesome crate - [pyo3](https://crates.io/crates/pyo3). //! -//! Let's see next ordinary code file. +//! # Prerequisite //! -//! ```no-run -//! #[macro_use] -//! extern crate peroxide; -//! use peroxide::fuga::*; -//! -//! fn main() { -//! let init_state = State::::new(0f64, c!(1), c!(0)); -//! -//! let mut ode_solver = ExplicitODE::new(test_fn); +//! - python 3 +//! - matplotlib +//! - scienceplots (Optional) //! -//! ode_solver -//! .set_method(ExMethod::RK4) -//! .set_initial_condition(init_state) -//! .set_step_size(0.01) -//! .set_times(1000); +//! # Usage //! -//! let result = ode_solver.integrate(); -//! result.write("example_data/test.csv"); -//! } +//! To use this module, you should enable `plot` feature in `Cargo.toml` //! -//! fn test_fn(st: &mut State, _: &NoEnv) { -//! let x = st.param; -//! let y = &st.value; -//! let dy = &mut st.deriv; -//! dy[0] = (5f64*x.powi(2) - y[0]) / (x + y[0]).exp(); -//! } //! ``` -//! -//! Now, let's modify this code to below. Then it works surprisingly! -//! -//! ```rust -//! #[macro_use] -//! extern crate peroxide; //! use peroxide::fuga::*; //! //! fn main() { -//! let init_state = State::::new(0f64, c!(1), c!(0)); -//! -//! let mut ode_solver = ExplicitODE::new(test_fn); -//! -//! ode_solver -//! .set_method(ExMethod::RK4) -//! .set_initial_condition(init_state) -//! .set_step_size(0.01) -//! .set_times(1000); -//! -//! let result = ode_solver.integrate(); -//! -//! let x = result.col(0); -//! let y = result.col(1); -//! -//! // Remove below comments to execute -//! //let mut plt = Plot2D::new(); -//! //plt.set_domain(x) -//! // .insert_image(y) -//! // .set_title("Test Figure") -//! // .set_fig_size((10, 6)) -//! // .set_dpi(300) -//! // .set_legend(vec!["RK4"]) -//! // .set_path("example_data/test_plot.png"); -//! -//! //plt.savefig(); -//! } +//! let x = linspace(0, 1, 100); +//! let y1 = x.fmap(|t| t.powi(2)); +//! let y2 = x.fmap(|t| t.powi(3)); //! -//! fn test_fn(st: &mut State, _: &NoEnv) { -//! let x = st.param; -//! let y = &st.value; -//! let dy = &mut st.deriv; -//! dy[0] = (5f64 * x.powi(2) - y[0]) / (x + y[0]).exp(); +//! let mut plt = Plot2D::new(); +//! plt.set_domain(x) +//! .insert_image(y1) +//! .insert_image(y2) +//! .set_legend(vec![r"$y=x^2$", r"$y=x^3$"]) +//! .set_line_style(vec![(0, LineStyle::Dashed), (1, LineStyle::Dotted)]) +//! .set_color(vec![(0, "red"), (1, "darkblue")]) +//! .set_xlabel(r"$x$") +//! .set_ylabel(r"$y$") +//! .set_style(PlotStyle::Nature) // if you want to use scienceplots +//! .set_dpi(600) +//! .tight_layout() +//! .set_path("example_data/test_plot.png") +//! .savefig().unwrap(); //! } //! ``` //! -//! It draws next image +//! This code will generate below plot //! -//! ![test_plot](https://raw.githubusercontent.com/Axect/Peroxide/master/example_data/test_plot.png) +//! ![test_plot](https://github.com/Axect/Peroxide/blob/master/example_data/test_plot.png?raw=true) //! //! # Available Plot Options //! - `set_domain` : Set x data @@ -128,7 +89,6 @@ pub enum PlotOptions { #[derive(Debug, Copy, Clone, Hash, PartialOrd, PartialEq, Eq)] pub enum Markers { Point, - Line, Circle, Pixel, TriangleDown, @@ -152,7 +112,6 @@ impl Display for Markers { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let str = match self { Markers::Point => ".".to_string(), - Markers::Line => "-".to_string(), Markers::Circle => "o".to_string(), Markers::Pixel => ",".to_string(), Markers::TriangleDown => "v".to_string(), @@ -238,12 +197,12 @@ pub trait Plot { fn set_fig_size(&mut self, fig_size: (usize, usize)) -> &mut Self; fn set_dpi(&mut self, dpi: usize) -> &mut Self; fn grid(&mut self, grid: Grid) -> &mut Self; - fn set_marker(&mut self, styles: Vec) -> &mut Self; + fn set_marker(&mut self, styles: Vec<(usize, Markers)>) -> &mut Self; fn set_style(&mut self, style: PlotStyle) -> &mut Self; fn tight_layout(&mut self) -> &mut Self; - fn set_line_style(&mut self, style: Vec) -> &mut Self; - fn set_color(&mut self, color: Vec<&str>) -> &mut Self; - fn set_alpha(&mut self, alpha: Vec) -> &mut Self; + fn set_line_style(&mut self, style: Vec<(usize, LineStyle)>) -> &mut Self; + fn set_color(&mut self, color: Vec<(usize, &str)>) -> &mut Self; + fn set_alpha(&mut self, alpha: Vec<(usize, f64)>) -> &mut Self; fn savefig(&self) -> PyResult<()>; } @@ -260,10 +219,10 @@ pub struct Plot2D { xlim: Option<(f64, f64)>, ylim: Option<(f64, f64)>, legends: Vec, - markers: Vec, - line_style: Vec, - color: Vec, - alpha: Vec, + markers: Vec<(usize, Markers)>, + line_style: Vec<(usize, LineStyle)>, + color: Vec<(usize, String)>, + alpha: Vec<(usize, f64)>, path: String, fig_size: Option<(usize, usize)>, dpi: usize, @@ -403,7 +362,7 @@ impl Plot for Plot2D { self } - fn set_marker(&mut self, styles: Vec) -> &mut Self { + fn set_marker(&mut self, styles: Vec<(usize, Markers)>) -> &mut Self { self.markers = styles; self } @@ -418,17 +377,17 @@ impl Plot for Plot2D { self } - fn set_line_style(&mut self, style: Vec) -> &mut Self { + fn set_line_style(&mut self, style: Vec<(usize, LineStyle)>) -> &mut Self { self.line_style = style; self } - fn set_color(&mut self, color: Vec<&str>) -> &mut Self { - self.color = color.into_iter().map(|x| x.to_owned()).collect(); + fn set_color(&mut self, color: Vec<(usize, &str)>) -> &mut Self { + self.color = color.into_iter().map(|(i, x)| (i, x.to_owned())).collect(); self } - fn set_alpha(&mut self, alpha: Vec) -> &mut Self { + fn set_alpha(&mut self, alpha: Vec<(usize, f64)>) -> &mut Self { self.alpha = alpha; self } @@ -493,8 +452,8 @@ impl Plot for Plot2D { let ylabel = self.ylabel.clone(); let legends = self.legends.clone(); let path = self.path.clone(); - let markers = self.markers.iter().map(|x| format!("{}", x)).collect::>(); - let line_style = self.line_style.iter().map(|x| format!("{}", x)).collect::>(); + let markers = self.markers.iter().map(|(i, x)| (i, format!("{}", x))).collect::>(); + let line_style = self.line_style.iter().map(|(i, x)| (i, format!("{}", x))).collect::>(); let color = self.color.clone(); let alpha = self.alpha.clone(); @@ -571,39 +530,55 @@ impl Plot for Plot2D { for i in 0..y_length { let mut inner_string = format!("x,y[{}]", i); - if !markers.is_empty() { - inner_string.push_str(&format!(",marker=\"{}\"", markers[i])[..]); + let is_corresponding_marker = !markers.is_empty() && (markers.iter().any(|(&j, _)| j == i)); + if is_corresponding_marker { + let marker = markers.iter().find(|(&j, _)| j == i).unwrap().1.as_str(); + inner_string.push_str(&format!(",marker=\"{}\"", marker)[..]); } - if !line_style.is_empty() { - inner_string.push_str(&format!(",linestyle=\"{}\"", line_style[i])[..]); + let is_corresponding_line_style = !line_style.is_empty() && (line_style.iter().any(|(&j, _)| j == i)); + if is_corresponding_line_style { + let style = line_style.iter().find(|(&j, _)| j == i).unwrap().1.as_str(); + inner_string.push_str(&format!(",linestyle=\"{}\"", style)[..]); } - if !color.is_empty() { - inner_string.push_str(&format!(",color=\"{}\"", color[i])[..]); + let is_corresponding_color = !color.is_empty() && (color.iter().any(|(j, _)| j == &i)); + if is_corresponding_color { + let color = color.iter().find(|(j, _)| j == &i).unwrap().1.as_str(); + inner_string.push_str(&format!(",color=\"{}\"", color)[..]); } if !legends.is_empty() { inner_string.push_str(&format!(",label=r\"{}\"", legends[i])[..]); } - if !alpha.is_empty() { - inner_string.push_str(&format!(",alpha={}", alpha[i])[..]); + let is_corresponding_alpha = !alpha.is_empty() && (alpha.iter().any(|(j, _)| j == &i)); + if is_corresponding_alpha { + let alpha = alpha.iter().find(|(j, _)| j == &i).unwrap().1; + inner_string.push_str(&format!(",alpha={}", alpha)[..]); } plot_string.push_str(&format!("plt.plot({})\n", inner_string)[..]); } for i in 0..pair_length { let mut inner_string = format!("pair[{}][0],pair[{}][1]", i, i); - if !markers.is_empty() { - inner_string.push_str(&format!(",marker=\"{}\"", markers[i + y_length])[..]); + let is_corresponding_marker = !markers.is_empty() && (markers.iter().any(|(&j, _)| j == (i + y_length))); + if is_corresponding_marker { + let marker = markers.iter().find(|(&j, _)| j == (i + y_length)).unwrap().1.as_str(); + inner_string.push_str(&format!(",marker=\"{}\"", marker)[..]); } - if !line_style.is_empty() { - inner_string.push_str(&format!(",linestyle=\"{}\"", line_style[i + y_length])[..]); + let is_corresponding_line_style = !line_style.is_empty() && (line_style.iter().any(|(&j, _)| j == (i + y_length))); + if is_corresponding_line_style { + let style = line_style.iter().find(|(&j, _)| j == (i + y_length)).unwrap().1.as_str(); + inner_string.push_str(&format!(",linestyle=\"{}\"", style)[..]); } - if !color.is_empty() { - inner_string.push_str(&format!(",color=\"{}\"", color[i + y_length])[..]); + let is_corresponding_color = !color.is_empty() && (color.iter().any(|(j, _)| j == &(i + y_length))); + if is_corresponding_color { + let color = color.iter().find(|(j, _)| j == &(i + y_length)).unwrap().1.as_str(); + inner_string.push_str(&format!(",color=\"{}\"", color)[..]); } if !legends.is_empty() { inner_string.push_str(&format!(",label=r\"{}\"", legends[i + y_length])[..]); } - if !alpha.is_empty() { - inner_string.push_str(&format!(",alpha={}", alpha[i + y_length])[..]); + let is_corresponding_alpha = !alpha.is_empty() && (alpha.iter().any(|(j, _)| j == &(i + y_length))); + if is_corresponding_alpha { + let alpha = alpha.iter().find(|(j, _)| j == &(i + y_length)).unwrap().1; + inner_string.push_str(&format!(",alpha={}", alpha)[..]); } plot_string.push_str(&format!("plt.plot({})\n", inner_string)[..]); }