use super::{matrix_to_array, vector_to_array, vector_to_strings, AsMatrix, GraphMaker};
use std::fmt::Write;
pub struct Contour {
colors: Vec<String>, levels: Vec<f64>, colormap_name: String, no_lines: bool, no_labels: bool, no_inline_labels: bool, no_colorbar: bool, colorbar_label: String, number_format_cb: String, line_color: String, line_style: String, line_width: f64, fontsize_labels: f64, with_selected: bool, selected_level: f64, selected_line_color: String, selected_line_style: String, selected_line_width: f64, buffer: String, }
impl Contour {
pub fn new() -> Self {
Contour {
colors: Vec::new(),
levels: Vec::new(),
colormap_name: "bwr".to_string(),
no_lines: false,
no_labels: false,
no_inline_labels: false,
no_colorbar: false,
colorbar_label: String::new(),
number_format_cb: String::new(),
line_color: "black".to_string(),
line_style: String::new(),
line_width: 0.0,
fontsize_labels: 0.0,
with_selected: false,
selected_level: 0.0,
selected_line_color: "yellow".to_string(),
selected_line_style: "-".to_string(),
selected_line_width: 2.0,
buffer: String::new(),
}
}
pub fn draw<'a, T, U>(&mut self, x: &'a T, y: &'a T, z: &'a T)
where
T: AsMatrix<'a, U>,
U: 'a + std::fmt::Display,
{
matrix_to_array(&mut self.buffer, "x", x);
matrix_to_array(&mut self.buffer, "y", y);
matrix_to_array(&mut self.buffer, "z", z);
if self.colors.len() > 0 {
vector_to_strings(&mut self.buffer, "colors", &self.colors);
}
if self.levels.len() > 0 {
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_lines {
let opt_line = self.options_line();
write!(&mut self.buffer, "cl=plt.contour(x,y,z{})\n", &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 {
let opt_colorbar = self.options_colorbar();
write!(&mut self.buffer, "cb=plt.colorbar(cf{})\n", &opt_colorbar).unwrap();
if self.colorbar_label != "" {
write!(&mut self.buffer, "cb.ax.set_ylabel(r'{}')\n", self.colorbar_label).unwrap();
}
}
if self.with_selected {
let opt_selected = self.options_selected();
write!(&mut self.buffer, "plt.contour(x,y,z{})\n", &opt_selected).unwrap();
}
}
pub fn set_colors(&mut self, colors: &[&str]) -> &mut Self {
self.colors = colors.iter().map(|color| color.to_string()).collect();
self
}
pub fn set_levels(&mut self, levels: &[f64]) -> &mut Self {
self.levels = levels.to_vec();
self
}
pub fn set_colormap_index(&mut self, index: usize) -> &mut Self {
const CMAP: [&str; 7] = ["bwr", "RdBu", "hsv", "jet", "terrain", "pink", "Greys"];
self.colormap_name = CMAP[index % 7].to_string();
self.colors = Vec::new();
self
}
pub fn set_colormap_name(&mut self, name: &str) -> &mut Self {
self.colormap_name = String::from(name);
self.colors = Vec::new();
self
}
pub fn set_no_lines(&mut self, flag: bool) -> &mut Self {
self.no_lines = flag;
self
}
pub fn set_no_labels(&mut self, flag: bool) -> &mut Self {
self.no_labels = flag;
self
}
pub fn set_no_inline_labels(&mut self, flag: bool) -> &mut Self {
self.no_inline_labels = flag;
self
}
pub fn set_no_colorbar(&mut self, flag: bool) -> &mut Self {
self.no_colorbar = flag;
self
}
pub fn set_colorbar_label(&mut self, label: &str) -> &mut Self {
self.colorbar_label = String::from(label);
self
}
pub fn set_number_format_cb(&mut self, format: &str) -> &mut Self {
self.number_format_cb = String::from(format);
self
}
pub fn set_line_color(&mut self, color: &str) -> &mut Self {
self.line_color = String::from(color);
self
}
pub fn set_line_style(&mut self, style: &str) -> &mut Self {
self.line_style = String::from(style);
self
}
pub fn set_line_width(&mut self, width: f64) -> &mut Self {
self.line_width = width;
self
}
pub fn set_fontsize_labels(&mut self, fontsize: f64) -> &mut Self {
self.fontsize_labels = fontsize;
self
}
pub fn set_selected_level(&mut self, level: f64, enabled: bool) -> &mut Self {
self.selected_level = level;
self.with_selected = enabled;
self
}
pub fn set_selected_line_color(&mut self, color: &str) -> &mut Self {
self.selected_line_color = String::from(color);
self
}
pub fn set_selected_line_style(&mut self, style: &str) -> &mut Self {
self.selected_line_style = String::from(style);
self
}
pub fn set_selected_line_width(&mut self, width: f64) -> &mut Self {
self.selected_line_width = width;
self
}
fn options_filled(&self) -> String {
let mut opt = String::new();
if self.colors.len() > 0 {
write!(&mut opt, ",colors=colors",).unwrap();
} else {
if self.colormap_name != "" {
write!(&mut opt, ",cmap=plt.get_cmap('{}')", self.colormap_name).unwrap();
}
}
if self.levels.len() > 0 {
write!(&mut opt, ",levels=levels").unwrap();
}
opt
}
fn options_line(&self) -> String {
let mut opt = String::new();
if self.line_color != "" {
write!(&mut opt, ",colors=['{}']", self.line_color).unwrap();
}
if self.levels.len() > 0 {
write!(&mut opt, ",levels=levels").unwrap();
}
if self.line_style != "" {
write!(&mut opt, ",linestyles=['{}']", self.line_style).unwrap();
}
if self.line_width > 0.0 {
write!(&mut opt, ",linewidths=[{}]", self.line_width).unwrap();
}
opt
}
fn options_label(&self) -> String {
let mut opt = String::new();
if self.no_inline_labels {
write!(&mut opt, ",inline=False").unwrap();
} else {
write!(&mut opt, ",inline=True").unwrap();
}
if self.fontsize_labels > 0.0 {
write!(&mut opt, ",fontsize={}", self.fontsize_labels).unwrap();
}
opt
}
fn options_colorbar(&self) -> String {
let mut opt = String::new();
if self.number_format_cb != "" {
write!(&mut opt, ",format='{}'", self.number_format_cb).unwrap();
}
opt
}
fn options_selected(&self) -> String {
let mut opt = String::new();
if self.selected_line_color != "" {
write!(&mut opt, ",colors=['{}']", self.selected_line_color).unwrap();
}
write!(&mut opt, ",levels=[{}]", self.selected_level).unwrap();
if self.selected_line_style != "" {
write!(&mut opt, ",linestyles=['{}']", self.selected_line_style).unwrap();
}
if self.selected_line_width > 0.0 {
write!(&mut opt, ",linewidths=[{}]", self.selected_line_width).unwrap();
}
opt
}
}
impl GraphMaker for Contour {
fn get_buffer<'a>(&'a self) -> &'a String {
&self.buffer
}
fn clear_buffer(&mut self) {
self.buffer.clear();
}
}
#[cfg(test)]
mod tests {
use super::Contour;
use crate::GraphMaker;
#[test]
fn new_works() {
let contour = Contour::new();
assert_eq!(contour.colors.len(), 0);
assert_eq!(contour.levels.len(), 0);
assert_eq!(contour.colormap_name, "bwr");
assert_eq!(contour.no_lines, false);
assert_eq!(contour.no_labels, false);
assert_eq!(contour.no_inline_labels, false);
assert_eq!(contour.no_colorbar, false);
assert_eq!(contour.colorbar_label.len(), 0);
assert_eq!(contour.number_format_cb.len(), 0);
assert_eq!(contour.line_color, "black".to_string());
assert_eq!(contour.line_style.len(), 0);
assert_eq!(contour.line_width, 0.0);
assert_eq!(contour.fontsize_labels, 0.0);
assert_eq!(contour.with_selected, false);
assert_eq!(contour.selected_level, 0.0);
assert_eq!(contour.selected_line_color, "yellow".to_string());
assert_eq!(contour.selected_line_style, "-".to_string());
assert_eq!(contour.selected_line_width, 2.0);
assert_eq!(contour.buffer.len(), 0);
}
#[test]
fn options_filled_works() {
let mut contour = Contour::new();
contour
.set_colors(&vec!["#f00", "#0f0", "#00f"])
.set_levels(&vec![0.25, 0.5, 1.0]);
let opt = contour.options_filled();
assert_eq!(
opt,
",colors=colors\
,levels=levels"
);
contour.set_colormap_index(4);
let opt = contour.options_filled();
assert_eq!(
opt,
",cmap=plt.get_cmap('terrain')\
,levels=levels"
);
}
#[test]
fn options_line_works() {
let mut contour = Contour::new();
contour
.set_levels(&vec![0.25, 0.5, 1.0])
.set_line_color("red")
.set_line_style(":")
.set_line_width(3.0);
let opt = contour.options_line();
assert_eq!(
opt,
",colors=['red']\
,levels=levels\
,linestyles=[':']\
,linewidths=[3]"
);
}
#[test]
fn options_label_works() {
let mut contour = Contour::new();
contour.set_no_inline_labels(false).set_fontsize_labels(5.0);
let opt = contour.options_label();
assert_eq!(
opt,
",inline=True\
,fontsize=5"
);
contour.set_no_inline_labels(true);
let opt = contour.options_label();
assert_eq!(
opt,
",inline=False\
,fontsize=5"
);
}
#[test]
fn options_colorbar_works() {
let mut contour = Contour::new();
contour.set_number_format_cb("%.4f");
let opt = contour.options_colorbar();
assert_eq!(opt, ",format='%.4f'");
}
#[test]
fn options_selected_works() {
let mut contour = Contour::new();
contour
.set_selected_level(0.75, true)
.set_selected_line_color("blue")
.set_selected_line_style("--")
.set_selected_line_width(2.5);
let opt = contour.options_selected();
assert_eq!(
opt,
",colors=['blue']\
,levels=[0.75]\
,linestyles=['--']\
,linewidths=[2.5]"
);
}
#[test]
fn draw_works() {
let mut contour = Contour::new();
contour
.set_colors(&vec!["#f00", "#0f0", "#00f"])
.set_levels(&vec![0.25, 0.5, 1.0])
.set_colorbar_label("temperature")
.set_selected_level(0.0, true);
let x = vec![vec![-0.5, 0.0, 0.5], vec![-0.5, 0.0, 0.5], vec![-0.5, 0.0, 0.5]];
let y = vec![vec![-0.5, -0.5, -0.5], vec![0.0, 0.0, 0.0], vec![0.5, 0.5, 0.5]];
let z = vec![vec![0.50, 0.25, 0.50], vec![0.25, 0.00, 0.25], vec![0.50, 0.25, 0.50]];
contour.draw(&x, &y, &z);
let b: &str = "x=np.array([[-0.5,0,0.5,],[-0.5,0,0.5,],[-0.5,0,0.5,],],dtype=float)\n\
y=np.array([[-0.5,-0.5,-0.5,],[0,0,0,],[0.5,0.5,0.5,],],dtype=float)\n\
z=np.array([[0.5,0.25,0.5,],[0.25,0,0.25,],[0.5,0.25,0.5,],],dtype=float)\n\
colors=['#f00','#0f0','#00f',]\n\
levels=np.array([0.25,0.5,1,],dtype=float)\n\
cf=plt.contourf(x,y,z,colors=colors,levels=levels)\n\
cl=plt.contour(x,y,z,colors=['black'],levels=levels)\n\
plt.clabel(cl,inline=True)\n\
cb=plt.colorbar(cf)\n\
cb.ax.set_ylabel(r'temperature')\n\
plt.contour(x,y,z,colors=['yellow'],levels=[0],linestyles=['-'],linewidths=[2])\n";
assert_eq!(contour.buffer, b);
contour.clear_buffer();
assert_eq!(contour.buffer, "");
}
}