use super::GraphMaker;
use std::fmt::Write;
pub struct InsetAxes {
range: Option<(f64, f64, f64, f64)>,
extra_for_axes: String,
extra_for_indicator: String,
indicator_line_style: String,
indicator_line_color: String,
indicator_line_width: f64,
indicator_hatch: String,
indicator_alpha: Option<f64>,
axes_visible: bool,
indicator_disabled: bool,
title: String,
buffer: String,
}
impl InsetAxes {
pub fn new() -> Self {
Self {
range: None,
extra_for_axes: String::new(),
extra_for_indicator: String::new(),
indicator_line_style: String::new(),
indicator_line_color: String::new(),
indicator_line_width: 0.0,
indicator_hatch: String::new(),
indicator_alpha: None,
axes_visible: false,
indicator_disabled: false,
title: String::new(),
buffer: String::new(),
}
}
pub fn set_indicator_line_style(&mut self, style: &str) -> &mut Self {
self.indicator_line_style = style.to_string();
self
}
pub fn set_indicator_line_color(&mut self, color: &str) -> &mut Self {
self.indicator_line_color = color.to_string();
self
}
pub fn set_indicator_line_width(&mut self, width: f64) -> &mut Self {
self.indicator_line_width = width;
self
}
pub fn set_indicator_alpha(&mut self, alpha: f64) -> &mut Self {
self.indicator_alpha = Some(alpha);
self
}
pub fn set_indicator_hatch(&mut self, hatch: &str) -> &mut Self {
self.indicator_hatch = hatch.to_string();
self
}
pub fn add(&mut self, graph: &dyn GraphMaker) -> &mut Self {
let buf = graph
.get_buffer()
.replace("plt.gca()", "zoom")
.replace("plt.barh", "zoom.barh")
.replace("plt.bar", "zoom.bar")
.replace("plt.boxplot", "zoom.boxplot")
.replace("plt.contourf", "zoom.contourf")
.replace("plt.contour", "zoom.contour")
.replace("plt.clabel", "zoom.clabel")
.replace("plt.colorbar", "ignore_this")
.replace("cb.ax.set_ylabel", "ignore_this")
.replace("plt.fill_between", "zoom.fill_between")
.replace("plt.imshow", "zoom.imshow")
.replace("plt.legend", "zoom.legend")
.replace("plt.hist", "zoom.hist")
.replace("plt.plot", "zoom.plot")
.replace("plt.quiver", "zoom.quiver")
.replace("plt.text", "zoom.text")
.replace("plt.streamplot", "zoom.streamplot")
.replace("plt.tricontour", "zoom.tricontour")
.replace("plt.tricontourf", "zoom.tricontourf")
.replace("plt.triplot", "zoom.triplot");
self.buffer.push_str(&buf);
self
}
pub fn draw(&mut self, u0: f64, v0: f64, width: f64, height: f64) {
let opt1 = self.options_for_axes();
let opt2 = self.options_for_indicator();
if let Some((xmin, xmax, ymin, ymax)) = self.range {
self.buffer.insert_str(
0,
&format!(
"zoom=plt.gca().inset_axes([{},{},{},{}],xlim=({},{}),ylim=({},{}){})\n",
u0, v0, width, height, xmin, xmax, ymin, ymax, opt1,
),
);
} else {
self.buffer.insert_str(
0,
&format!(
"zoom=plt.gca().inset_axes([{},{},{},{}]{})\n",
u0, v0, width, height, opt1,
),
);
}
if !self.axes_visible {
write!(&mut self.buffer, "zoom.set_xticks([])\nzoom.set_yticks([])\n").unwrap();
}
if !self.title.is_empty() {
write!(&mut self.buffer, "zoom.set_title(r'{}')\n", self.title).unwrap();
}
if !self.indicator_disabled {
write!(&mut self.buffer, "plt.gca().indicate_inset_zoom(zoom{})\n", opt2,).unwrap();
}
}
pub fn set_range(&mut self, xmin: f64, xmax: f64, ymin: f64, ymax: f64) -> &mut Self {
self.range = Some((xmin, xmax, ymin, ymax));
self
}
pub fn set_extra_for_axes(&mut self, extra: &str) -> &mut Self {
self.extra_for_axes = extra.to_string();
self
}
pub fn set_extra_for_indicator(&mut self, extra: &str) -> &mut Self {
self.extra_for_indicator = extra.to_string();
self
}
pub fn set_visibility(&mut self, visible: bool) -> &mut Self {
self.axes_visible = visible;
self
}
pub fn set_title(&mut self, title: &str) -> &mut Self {
self.title = title.to_string();
self
}
pub fn set_indicator_disabled(&mut self, disabled: bool) -> &mut Self {
self.indicator_disabled = disabled;
self
}
fn options_for_axes(&self) -> String {
let mut opt = String::new();
if !self.extra_for_axes.is_empty() {
write!(&mut opt, ",{}", self.extra_for_axes).unwrap();
}
opt
}
fn options_for_indicator(&self) -> String {
let mut opt = String::new();
if !self.indicator_line_style.is_empty() {
write!(&mut opt, ",linestyle='{}'", self.indicator_line_style).unwrap();
}
if !self.indicator_line_color.is_empty() {
write!(&mut opt, ",edgecolor='{}'", self.indicator_line_color).unwrap();
}
if self.indicator_line_width > 0.0 {
write!(&mut opt, ",linewidth={}", self.indicator_line_width).unwrap();
}
if !self.indicator_hatch.is_empty() {
write!(&mut opt, ",hatch='{}'", self.indicator_hatch).unwrap();
}
if let Some(alpha) = self.indicator_alpha {
write!(&mut opt, ",alpha={}", alpha).unwrap();
}
if !self.extra_for_indicator.is_empty() {
write!(&mut opt, ",{}", self.extra_for_indicator).unwrap();
}
opt
}
}
impl GraphMaker for InsetAxes {
fn get_buffer<'a>(&'a self) -> &'a String {
&self.buffer
}
fn clear_buffer(&mut self) {
self.buffer.clear();
}
}
#[cfg(test)]
mod tests {
use super::InsetAxes;
use crate::GraphMaker;
#[test]
fn test_new() {
let inset = InsetAxes::new();
assert_eq!(inset.range, None);
assert!(inset.buffer.is_empty());
}
#[test]
fn test_set_range() {
let mut inset = InsetAxes::new();
inset.set_range(-1.0, 2.0, -3.0, 4.0);
assert_eq!(inset.range, Some((-1.0, 2.0, -3.0, 4.0)));
}
#[test]
fn test_set_title() {
let mut inset = InsetAxes::new();
inset.set_title("Test Title");
assert_eq!(inset.title, "Test Title");
}
#[test]
fn test_set_visibility() {
let mut inset = InsetAxes::new();
inset.set_visibility(true);
assert!(inset.axes_visible);
inset.set_visibility(false);
assert!(!inset.axes_visible);
}
#[test]
fn test_indicator_options() {
let mut inset = InsetAxes::new();
inset
.set_indicator_line_style("--")
.set_indicator_line_color("red")
.set_indicator_line_width(2.0)
.set_indicator_hatch("/")
.set_indicator_alpha(0.5);
let options = inset.options_for_indicator();
assert!(options.contains("linestyle='--'"));
assert!(options.contains("edgecolor='red'"));
assert!(options.contains("linewidth=2"));
assert!(options.contains("hatch='/'"));
assert!(options.contains("alpha=0.5"));
}
#[test]
fn test_draw_basic() {
let mut inset = InsetAxes::new();
inset.draw(0.5, 0.5, 0.4, 0.3);
let buffer = inset.get_buffer();
assert!(buffer.contains("zoom=plt.gca().inset_axes([0.5,0.5,0.4,0.3]"));
assert!(buffer.contains("plt.gca().indicate_inset_zoom(zoom"));
}
#[test]
fn test_indicator_disabled() {
let mut inset = InsetAxes::new();
assert_eq!(inset.indicator_disabled, false);
inset.set_indicator_disabled(true);
assert_eq!(inset.indicator_disabled, true);
inset.draw(0.5, 0.5, 0.4, 0.3);
let buffer = inset.get_buffer();
assert!(!buffer.contains("indicate_inset_zoom"));
inset.set_indicator_disabled(false);
inset.clear_buffer();
inset.draw(0.5, 0.5, 0.4, 0.3);
let buffer = inset.get_buffer();
assert!(buffer.contains("indicate_inset_zoom"));
}
#[test]
fn test_clear_buffer() {
let mut inset = InsetAxes::new();
inset.draw(0.5, 0.5, 0.4, 0.3);
assert!(!inset.buffer.is_empty());
inset.clear_buffer();
assert!(inset.buffer.is_empty());
}
}