diff --git a/examples/README.md b/examples/README.md
index 7bafeb6..9d4f905 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -174,6 +174,7 @@ Some output of integration tests are shown below.
[test_stream.rs](https://github.com/cpmech/plotpy/tree/main/tests/test_stream.rs)

+
## Surface and wireframe
diff --git a/figures/integ_stream_arrows_2.svg b/figures/integ_stream_arrows_2.svg
new file mode 100644
index 0000000..fcd149c
--- /dev/null
+++ b/figures/integ_stream_arrows_2.svg
@@ -0,0 +1,3639 @@
+
+
+
diff --git a/src/stream.rs b/src/stream.rs
index 6ea9a61..f42c1d8 100644
--- a/src/stream.rs
+++ b/src/stream.rs
@@ -1,6 +1,6 @@
use super::GraphMaker;
-use crate::conversions::matrix_to_array;
-use crate::AsMatrix;
+use crate::conversions::{matrix_to_array, vector_to_array};
+use crate::{AsMatrix, AsVector};
use num_traits::Num;
use std::fmt::Write;
@@ -13,11 +13,13 @@ pub struct Stream {
streamplot_linewidth: f64,
streamplot_arrow_style: String,
streamplot_density: f64,
+ streamplot_zorder: usize,
streamplot_extra: String,
// quiver options
quiver_scale: f64,
quiver_pivot: String,
+ quiver_zorder: usize,
quiver_extra: String,
// buffer
@@ -34,10 +36,12 @@ impl Stream {
streamplot_linewidth: 0.0,
streamplot_arrow_style: String::new(),
streamplot_density: 0.0,
+ streamplot_zorder: 0,
streamplot_extra: String::new(),
// quiver options
quiver_scale: 0.0,
quiver_pivot: String::new(),
+ quiver_zorder: 0,
quiver_extra: String::new(),
// extra options
// buffer
@@ -45,32 +49,85 @@ impl Stream {
}
}
- /// Draws streamlines (stream plot)
- pub fn draw<'a, T, U>(&mut self, xx: &'a T, yy: &'a T, dx: &'a T, dy: &'a T)
+ /// Draws streamlines (stream plot) given x,y matrices and u,v matrices
+ ///
+ /// From [Matplotlib's documentation](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.streamplot.html):
+ ///
+ /// * xx, yy -- 2D arrays. Evenly spaced strictly increasing arrays to make a grid.
+ /// All rows of *x* must be equal and all columns of *y* must be equal; i.e.,
+ /// they must be as if generated by `np.meshgrid(x, y)`.
+ /// * uu, vv -- 2D arrays. *x* and *y*-velocities. The number of rows and columns
+ /// must match the length of *y* and *x*, respectively.
+ pub fn draw<'a, T, U>(&mut self, xx: &'a T, yy: &'a T, uu: &'a T, vv: &'a T)
where
T: AsMatrix<'a, U>,
U: 'a + std::fmt::Display + Num,
{
matrix_to_array(&mut self.buffer, "xx", xx);
matrix_to_array(&mut self.buffer, "yy", yy);
- matrix_to_array(&mut self.buffer, "dx", dx);
- matrix_to_array(&mut self.buffer, "dy", dy);
+ matrix_to_array(&mut self.buffer, "uu", uu);
+ matrix_to_array(&mut self.buffer, "vv", vv);
+ let opt = self.options_streamplot();
+ write!(&mut self.buffer, "plt.streamplot(xx,yy,uu,vv{})\n", &opt).unwrap();
+ }
+
+ /// Draws streamlines (stream plot) given x,y vectors and u,v matrices
+ ///
+ /// From [Matplotlib's documentation](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.streamplot.html):
+ ///
+ /// * x, y -- 1D arrays. Evenly spaced strictly increasing arrays to make a grid.
+ /// * u, v -- 2D arrays. *x* and *y*-velocities. The number of rows and columns
+ /// must match the length of *y* and *x*, respectively.
+ pub fn draw_alt<'a, V, M, U>(&mut self, x: &'a V, y: &'a V, uu: &'a M, vv: &'a M)
+ where
+ V: AsVector<'a, U>,
+ M: AsMatrix<'a, U>,
+ U: 'a + std::fmt::Display + Num,
+ {
+ vector_to_array(&mut self.buffer, "x", x);
+ vector_to_array(&mut self.buffer, "y", y);
+ matrix_to_array(&mut self.buffer, "uu", uu);
+ matrix_to_array(&mut self.buffer, "vv", vv);
let opt = self.options_streamplot();
- write!(&mut self.buffer, "plt.streamplot(xx,yy,dx,dy{})\n", &opt).unwrap();
+ write!(&mut self.buffer, "plt.streamplot(x,y,uu,vv{})\n", &opt).unwrap();
}
- /// Draws arrows (quiver plot)
- pub fn draw_arrows<'a, T, U>(&mut self, xx: &'a T, yy: &'a T, dx: &'a T, dy: &'a T)
+ /// Draws arrows (quiver plot) given matrices
+ ///
+ /// From [Matplotlib's documentation](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.quiver.html):
+ ///
+ /// * xx, yy -- 2D arrays. The x and y coordinates of the arrow locations.
+ /// * uu, vv -- 2D arrays. The x and y direction components of the arrow vectors.
+ pub fn draw_arrows<'a, T, U>(&mut self, xx: &'a T, yy: &'a T, uu: &'a T, vv: &'a T)
where
T: AsMatrix<'a, U>,
U: 'a + std::fmt::Display + Num,
{
matrix_to_array(&mut self.buffer, "xx", xx);
matrix_to_array(&mut self.buffer, "yy", yy);
- matrix_to_array(&mut self.buffer, "dx", dx);
- matrix_to_array(&mut self.buffer, "dy", dy);
+ matrix_to_array(&mut self.buffer, "uu", uu);
+ matrix_to_array(&mut self.buffer, "vv", vv);
+ let opt = self.options_quiver();
+ write!(&mut self.buffer, "plt.quiver(xx,yy,uu,vv{})\n", &opt).unwrap();
+ }
+
+ /// Draws arrows (quiver plot) given vectors
+ ///
+ /// From [Matplotlib's documentation](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.quiver.html):
+ ///
+ /// * x, y -- 1D arrays. The x and y coordinates of the arrow locations.
+ /// * u, v -- 1D arrays. The x and y direction components of the arrow vectors.
+ pub fn draw_arrows_alt<'a, T, U>(&mut self, x: &'a T, y: &'a T, u: &'a T, v: &'a T)
+ where
+ T: AsVector<'a, U>,
+ U: 'a + std::fmt::Display + Num,
+ {
+ vector_to_array(&mut self.buffer, "x", x);
+ vector_to_array(&mut self.buffer, "y", y);
+ vector_to_array(&mut self.buffer, "u", u);
+ vector_to_array(&mut self.buffer, "v", v);
let opt = self.options_quiver();
- write!(&mut self.buffer, "plt.quiver(xx,yy,dx,dy{})\n", &opt).unwrap();
+ write!(&mut self.buffer, "plt.quiver(x,y,u,v{})\n", &opt).unwrap();
}
/// Sets the line color (quiver or streamlines)
@@ -115,6 +172,12 @@ impl Stream {
self
}
+ /// Sets the z-order of streamlines
+ pub fn set_streamline_zorder(&mut self, zorder: usize) -> &mut Self {
+ self.streamplot_zorder = zorder;
+ self
+ }
+
/// Sets extra options for streamlines
///
/// See
@@ -139,6 +202,12 @@ impl Stream {
self
}
+ /// Sets the quiver z-order
+ pub fn set_quiver_zorder(&mut self, zorder: usize) -> &mut Self {
+ self.quiver_zorder = zorder;
+ self
+ }
+
/// Sets extra options for quiver
///
/// See
@@ -162,6 +231,9 @@ impl Stream {
if self.streamplot_density > 0.0 {
write!(&mut opt, ",density={}", self.streamplot_density).unwrap();
}
+ if self.streamplot_zorder > 0 {
+ write!(&mut opt, ",zorder={}", self.streamplot_zorder).unwrap();
+ }
if self.streamplot_extra != "" {
write!(&mut opt, ",{}", self.streamplot_extra).unwrap();
}
@@ -180,6 +252,9 @@ impl Stream {
if self.quiver_pivot != "" {
write!(&mut opt, ",pivot='{}'", self.quiver_pivot).unwrap();
}
+ if self.quiver_zorder > 0 {
+ write!(&mut opt, ",zorder={}", self.quiver_zorder).unwrap();
+ }
if self.quiver_extra != "" {
write!(&mut opt, ",{}", self.quiver_extra).unwrap();
}
diff --git a/tests/test_stream.rs b/tests/test_stream.rs
index 0b7944d..fc10d4d 100644
--- a/tests/test_stream.rs
+++ b/tests/test_stream.rs
@@ -1,4 +1,4 @@
-use plotpy::{generate2d, Plot, StrError, Stream};
+use plotpy::{generate2d, linspace, Plot, StrError, Stream};
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::Path;
@@ -14,13 +14,13 @@ fn test_stream_arrows_1() -> Result<(), StrError> {
// data
let (nx, ny) = (10, 10);
let (xx, yy) = generate2d(-2.0, 2.0, -2.0, 2.0, nx, ny);
- let (mut dx, mut dy) = generate2d(0.0, 1.0, 0.0, 1.0, nx, ny);
+ let (mut uu, mut vv) = generate2d(0.0, 1.0, 0.0, 1.0, nx, ny);
for j in 0..ny {
for i in 0..nx {
let x = xx[j][i];
let y = yy[j][i];
- dx[j][i] = -y;
- dy[j][i] = x;
+ uu[j][i] = -y;
+ vv[j][i] = x;
}
}
@@ -31,12 +31,12 @@ fn test_stream_arrows_1() -> Result<(), StrError> {
.set_streamplot_arrow_style("fancy")
.set_streamplot_density(0.8)
.set_streamplot_extra("broken_streamlines=False")
- .draw(&xx, &yy, &dx, &dy);
+ .draw(&xx, &yy, &uu, &vv);
quiver
.set_color("#4752c7ff")
.set_quiver_inv_scale(15.0)
.set_quiver_pivot("mid")
- .draw_arrows(&xx, &yy, &dx, &dy);
+ .draw_arrows(&xx, &yy, &uu, &vv);
// add contour to plot
let mut plot = Plot::new();
@@ -54,3 +54,42 @@ fn test_stream_arrows_1() -> Result<(), StrError> {
assert!(n > 8650 && n < 8730);
Ok(())
}
+
+#[test]
+fn test_stream_arrows_2() -> Result<(), StrError> {
+ // object and options
+ let mut stream = Stream::new();
+ let mut quiver = Stream::new();
+
+ // data
+ let n = 10;
+ let x = linspace(1.0, 2.0, n);
+ let y = x.clone();
+ let u = linspace(1.0, 2.0, n);
+ let v = u.clone();
+ let (uu, vv) = generate2d(1.0, 2.0, 1.0, 2.0, n, n);
+
+ // draw arrows
+ stream.set_streamline_zorder(1).draw_alt(&x, &y, &uu, &vv);
+ quiver
+ .set_quiver_zorder(2)
+ .set_color("red")
+ .set_quiver_inv_scale(20.0)
+ .draw_arrows_alt(&x, &y, &u, &v);
+
+ // add contour to plot
+ let mut plot = Plot::new();
+ plot.add(&stream).add(&quiver);
+
+ // save figure
+ let path = Path::new(OUT_DIR).join("integ_stream_arrows_2.svg");
+ plot.set_equal_axes(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();
+ assert!(n > 3600 && n < 3680);
+ Ok(())
+}