diff --git a/.vscode/settings.json b/.vscode/settings.json
index 69d0337..ff995d8 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -89,6 +89,8 @@
"TICKRIGHT",
"TICKUP",
"toolkits",
+ "tricontour",
+ "tricontourf",
"triplot",
"trisurf",
"twinx",
diff --git a/examples/README.md b/examples/README.md
index f6a29a0..37da89a 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -78,6 +78,7 @@ Some output of integration tests are shown below.



+
## Curve
diff --git a/figures/integ_contour_draw_tri.svg b/figures/integ_contour_draw_tri.svg
new file mode 100644
index 0000000..76ae2f1
--- /dev/null
+++ b/figures/integ_contour_draw_tri.svg
@@ -0,0 +1,1064 @@
+
+
+
diff --git a/src/constants.rs b/src/constants.rs
index 1a0a030..35754d4 100644
--- a/src/constants.rs
+++ b/src/constants.rs
@@ -34,6 +34,7 @@ import matplotlib.patheffects as pff
import matplotlib.lines as lns
import matplotlib.transforms as tra
import mpl_toolkits.mplot3d
+import matplotlib.tri as plt_tri
# Variable to handle NaN values coming from Rust
NaN = np.nan
@@ -150,6 +151,6 @@ mod tests {
#[test]
fn constants_are_correct() {
- assert_eq!(PYTHON_HEADER.len(), 2886);
+ assert_eq!(PYTHON_HEADER.len(), 2919);
}
}
diff --git a/src/contour.rs b/src/contour.rs
index 1a65e81..35e90c8 100644
--- a/src/contour.rs
+++ b/src/contour.rs
@@ -1,4 +1,5 @@
use super::{generate_list_quoted, matrix_to_array, vector_to_array, AsMatrix, GraphMaker};
+use crate::AsVector;
use num_traits::Num;
use std::fmt::Write;
@@ -47,27 +48,32 @@ use std::fmt::Write;
///
/// 
pub struct Contour {
- colors: Vec, // Colors to be used instead of colormap
- levels: Vec, // Pre-defined levels
- colormap_name: String, // Colormap name
- no_lines: bool, // Skip drawing a lines contour
- no_labels: bool, // Skip adding labels to the lines contour
- no_inline_labels: bool, // Do not draw labels inline
- no_colorbar: bool, // Skip drawing a colorbar
- colorbar_label: String, // Colorbar label
- number_format_cb: String, // Number format for the labels in lines contour
- line_color: String, // Line color for the lines contour
- line_style: String, // Line style for the lines contour
- line_width: f64, // Line width for the lines contour
- fontsize_labels: f64, // Font size for labels
- with_selected: bool, // Draw a line contour with a selected level
- selected_level: f64, // Selected level (e.g., 0.0)
- selected_line_color: String, // Color to mark the selected level
- selected_line_style: String, // Line style for the selected level
- selected_line_width: f64, // Line width for the selected level
- extra_filled: String, // Extra commands (comma separated) for the filled contour
- extra_line: String, // Extra commands (comma separated) for the line contour
- buffer: String, // buffer
+ colors: Vec, // Colors to be used instead of colormap
+ levels: Vec, // Pre-defined levels
+ colormap_name: String, // Colormap name
+ no_fill: bool, // Skip drawing filled contour
+ no_lines: bool, // Skip drawing a lines contour
+ no_labels: bool, // Skip adding labels to the lines contour
+ no_inline_labels: bool, // Do not draw labels inline
+ no_colorbar: bool, // Skip drawing a colorbar
+ colorbar_label: String, // Colorbar label
+ number_format_cb: String, // Number format for the labels in lines contour
+ line_color: String, // Line color for the lines contour
+ line_style: String, // Line style for the lines contour
+ line_width: f64, // Line width for the lines contour
+ fontsize_labels: f64, // Font size for labels
+ with_selected: bool, // Draw a line contour with a selected level
+ selected_level: f64, // Selected level (e.g., 0.0)
+ selected_line_color: String, // Color to mark the selected level
+ selected_line_style: String, // Line style for the selected level
+ selected_line_width: f64, // Line width for the selected level
+ extra_filled: String, // Extra commands (comma separated) for the filled contour
+ extra_line: String, // Extra commands (comma separated) for the line contour
+ tri_show_edges: bool, // Show triangulation edges
+ tri_edges_color: String, // Triangulation edges color
+ tri_edges_line_width: f64, // Triangulation edges line width
+ tri_edges_line_style: String, // Triangulation edges line style
+ buffer: String, // buffer
}
impl Contour {
@@ -77,6 +83,7 @@ impl Contour {
colors: Vec::new(),
levels: Vec::new(),
colormap_name: "bwr".to_string(),
+ no_fill: false,
no_lines: false,
no_labels: false,
no_inline_labels: false,
@@ -94,6 +101,10 @@ impl Contour {
selected_line_width: 2.0,
extra_filled: String::new(),
extra_line: String::new(),
+ tri_show_edges: false,
+ tri_edges_color: "black".to_string(),
+ tri_edges_line_width: 0.5,
+ tri_edges_line_style: "-".to_string(),
buffer: String::new(),
}
}
@@ -110,6 +121,7 @@ impl Contour {
///
/// The following flags control what features are not to be drawn:
///
+ /// * `no_fill` -- skip drawing filled contour
/// * `no_lines` -- skip drawing a lines contour on top of the filled contour
/// * `no_labels` -- skip adding labels to the lines contour (if enabled)
/// * `no_colorbar` -- skip drawing a colorbar
@@ -122,6 +134,53 @@ impl Contour {
matrix_to_array(&mut self.buffer, "x", x);
matrix_to_array(&mut self.buffer, "y", y);
matrix_to_array(&mut self.buffer, "z", z);
+ self.contour_or_tricontour(false);
+ }
+
+ /// Draws a fancy contour using a triangulation: filled contour with a line contour and a colorbar
+ ///
+ /// # Input
+ ///
+ /// * `x` -- list of x coordinates
+ /// * `y` -- list of y coordinates
+ /// * `z` -- list of elevations at each coordinate
+ /// * `connectivity` -- triangulation/connectivity
+ ///
+ /// # Flags
+ ///
+ /// The following flags control what features are not to be drawn:
+ ///
+ /// * `no_fill` -- skip drawing filled contour
+ /// * `no_lines` -- skip drawing a lines contour on top of the filled contour
+ /// * `no_labels` -- skip adding labels to the lines contour (if enabled)
+ /// * `no_colorbar` -- skip drawing a colorbar
+ /// * `with_selected` -- draw a line contour with a selected level (e.g., 0.0) on top of everything
+ pub fn draw_tri<'a, T, U, C>(&mut self, x: &'a T, y: &'a T, z: &'a T, connectivity: &'a C)
+ where
+ T: AsVector<'a, U>,
+ U: 'a + std::fmt::Display + Num,
+ C: AsMatrix<'a, usize>,
+ {
+ vector_to_array(&mut self.buffer, "x", x);
+ vector_to_array(&mut self.buffer, "y", y);
+ vector_to_array(&mut self.buffer, "z", z);
+ matrix_to_array(&mut self.buffer, "con", connectivity);
+ write!(&mut self.buffer, "tri=plt_tri.Triangulation(x,y,triangles=con)\n").unwrap();
+ self.contour_or_tricontour(true);
+ if self.tri_show_edges {
+ write!(
+ &mut self.buffer,
+ "plt.triplot(tri,color='{}',lw={},ls='{}')\n",
+ self.tri_edges_color, self.tri_edges_line_width, self.tri_edges_line_style
+ )
+ .unwrap();
+ }
+ }
+
+ /// Draw contour or tricontour
+ fn contour_or_tricontour(&mut self, tricontour: bool) {
+ let contour = if tricontour { "tricontour(tri" } else { "contour(x,y" };
+ let contourf = if tricontour { "tricontourf(tri" } else { "contourf(x,y" };
if self.colors.len() > 0 {
generate_list_quoted(&mut self.buffer, "colors", &self.colors);
}
@@ -129,16 +188,18 @@ impl Contour {
vector_to_array(&mut self.buffer, "levels", &self.levels);
}
let opt = self.options_filled();
- write!(&mut self.buffer, "cf=plt.contourf(x,y,z{})\n", &opt).unwrap();
+ if !self.no_fill {
+ write!(&mut self.buffer, "cf=plt.{},z{})\n", contourf, &opt).unwrap();
+ }
if !self.no_lines {
let opt_line = self.options_line();
- write!(&mut self.buffer, "cl=plt.contour(x,y,z{})\n", &opt_line).unwrap();
+ write!(&mut self.buffer, "cl=plt.{},z{})\n", contour, &opt_line).unwrap();
if !self.no_labels {
let opt_label = self.options_label();
write!(&mut self.buffer, "plt.clabel(cl{})\n", &opt_label).unwrap();
}
}
- if !self.no_colorbar {
+ if !self.no_colorbar && !self.no_fill {
let opt_colorbar = self.options_colorbar();
write!(&mut self.buffer, "cb=plt.colorbar(cf{})\n", &opt_colorbar).unwrap();
if self.colorbar_label != "" {
@@ -147,7 +208,7 @@ impl Contour {
}
if self.with_selected {
let opt_selected = self.options_selected();
- write!(&mut self.buffer, "plt.contour(x,y,z{})\n", &opt_selected).unwrap();
+ write!(&mut self.buffer, "plt.{},z{})\n", contour, &opt_selected).unwrap();
}
}
@@ -197,6 +258,12 @@ impl Contour {
self
}
+ /// Sets option to skip drawing filled contour
+ pub fn set_no_fill(&mut self, flag: bool) -> &mut Self {
+ self.no_fill = flag;
+ self
+ }
+
/// Sets option to skip drawing a lines contour on top of the filled contour
pub fn set_no_lines(&mut self, flag: bool) -> &mut Self {
self.no_lines = flag;
@@ -320,6 +387,30 @@ impl Contour {
self
}
+ /// Sets option to show triangulation edges (only for draw_tri)
+ pub fn set_tri_show_edges(&mut self, flag: bool) -> &mut Self {
+ self.tri_show_edges = flag;
+ self
+ }
+
+ /// Sets triangulation edges color (only for draw_tri)
+ pub fn set_tri_edges_color(&mut self, color: &str) -> &mut Self {
+ self.tri_edges_color = color.to_string();
+ self
+ }
+
+ /// Sets triangulation edges line width (only for draw_tri)
+ pub fn set_tri_edges_line_width(&mut self, width: f64) -> &mut Self {
+ self.tri_edges_line_width = width;
+ self
+ }
+
+ /// Sets triangulation edges line style (only for draw_tri)
+ pub fn set_tri_edges_line_style(&mut self, style: &str) -> &mut Self {
+ self.tri_edges_line_style = style.to_string();
+ self
+ }
+
/// Returns options for filled contour
fn options_filled(&self) -> String {
let mut opt = String::new();
diff --git a/tests/test_contour.rs b/tests/test_contour.rs
index 526b54c..1e099c8 100644
--- a/tests/test_contour.rs
+++ b/tests/test_contour.rs
@@ -146,3 +146,60 @@ fn test_contour_colormap_name() -> Result<(), StrError> {
}
Ok(())
}
+
+#[test]
+fn test_contour_draw_tri() -> Result<(), StrError> {
+ // point coordinates (two triangles in a square)
+
+ let x = vec![0.0, 1.0, 2.0, 3.0, 0.5, 1.5, 2.5, 1.0, 2.0, 1.5];
+ let y = vec![0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 2.0, 2.0, 3.0];
+ let connectivity = vec![
+ vec![0, 1, 4],
+ vec![1, 5, 4],
+ vec![2, 6, 5],
+ vec![4, 5, 7],
+ vec![5, 8, 7],
+ vec![7, 8, 9],
+ vec![1, 2, 5],
+ vec![2, 3, 6],
+ ];
+
+ // elevations
+ let mut z = vec![0.0; x.len()];
+ for i in 0..x.len() {
+ z[i] = x[i] + y[i];
+ }
+
+ // canvas
+ let mut contour = Contour::new();
+ contour
+ .set_no_fill(false)
+ .set_colors(&vec!["#fcaeae", "#da98d1", "#c45178", "#5594d2", "#e6af69", "#e6d969"])
+ .set_colorbar_label("x + y")
+ .set_line_color("black")
+ .set_line_style("-")
+ .set_line_width(1.5)
+ .set_tri_show_edges(true)
+ .set_tri_edges_color("green")
+ .set_tri_edges_line_width(1.0)
+ .set_tri_edges_line_style("--");
+
+ // draw contour
+ contour.draw_tri(&x, &y, &z, &connectivity);
+
+ // add contour to plot
+ let mut plot = Plot::new();
+ plot.add(&contour);
+
+ // save figure
+ let path = Path::new(OUT_DIR).join("integ_contour_draw_tri.svg");
+ plot.set_equal_axes(true).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();
+ assert!(n > 1030 && n < 1090);
+ Ok(())
+}