use plotpy::{linspace, Curve, Plot, SlopeIcon, StrError};
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::Path;
const OUT_DIR: &str = "/tmp/plotpy/integ_tests";
#[test]
fn test_slope_icon_below() -> Result<(), StrError> {
let mut curve1 = Curve::new();
let mut curve2 = Curve::new();
let slope = 1.0 / 3.0;
let x = [-10.0, 10.0];
let dx = x[1] - x[0];
let y1 = [5.0, 5.0 + slope * dx];
let y2 = [5.0 + slope * dx, 5.0];
curve1.draw(&x, &y1);
curve2.draw(&x, &y2);
let mut icon1 = SlopeIcon::new();
let mut icon2 = SlopeIcon::new();
let mut icon3 = SlopeIcon::new();
let mut icon4 = SlopeIcon::new();
icon1
.set_precision(3)
.set_offset_v(1.0)
.set_line_style("--")
.set_face_color("gold")
.set_length(0.25)
.set_no_text(true);
icon2
.set_precision(3)
.set_offset_v(1.0)
.set_fontsize(14.0)
.set_text_h("")
.set_text_v("$\\mathrm{\\lambda}$")
.set_text_color("blue");
icon3
.set_precision(3)
.set_offset_v(1.0)
.set_text_offset_h(1.0)
.set_text_offset_v(1.0);
icon4.set_precision(3).set_offset_v(1.0).set_line_width(2.0);
let xc = x[0] + dx / 4.0;
let yc = y1[0] + slope * dx / 4.0;
icon1.draw(slope, xc, yc);
let xc = x[0] + 3.0 * dx / 4.0;
let yc = y1[0] + slope * 3.0 * dx / 4.0;
icon2.draw(slope, xc, yc);
let xc = x[0] + dx / 4.0;
let yc = y2[0] - slope * dx / 4.0;
icon3.draw(-slope, xc, yc);
let xc = x[0] + 3.0 * dx / 4.0;
let yc = y2[0] - slope * 3.0 * dx / 4.0;
icon4.draw(-slope, xc, yc);
let mut plot = Plot::new();
plot.add(&curve1)
.add(&curve2)
.add(&icon1)
.add(&icon2)
.add(&icon3)
.add(&icon4);
let path = Path::new(OUT_DIR).join("integ_slope_icon_below.svg");
plot.set_equal_axes(true).grid_and_labels("x", "y").save(&path)?;
let file = File::open(path).map_err(|_| "cannot open file")?;
let buffered = BufReader::new(file);
let lines_iter = buffered.lines();
assert!(lines_iter.count() > 680);
Ok(())
}
#[test]
fn test_slope_icon_above() -> Result<(), StrError> {
let mut curve1 = Curve::new();
let mut curve2 = Curve::new();
let slope = 1.0 / 3.0;
let x = [-10.0, 10.0];
let dx = x[1] - x[0];
let y1 = [5.0, 5.0 + slope * dx];
let y2 = [5.0 + slope * dx, 5.0];
curve1.draw(&x, &y1);
curve2.draw(&x, &y2);
let mut icon1 = SlopeIcon::new();
let mut icon2 = SlopeIcon::new();
let mut icon3 = SlopeIcon::new();
let mut icon4 = SlopeIcon::new();
icon1.set_precision(3).set_offset_v(1.0).set_above(true);
icon2.set_precision(3).set_offset_v(1.0).set_above(true);
icon3.set_precision(3).set_offset_v(1.0).set_above(true);
icon4.set_precision(3).set_offset_v(1.0).set_above(true);
let xc = x[0] + dx / 4.0;
let yc = y1[0] + slope * dx / 4.0;
icon1.draw(slope, xc, yc);
let xc = x[0] + 3.0 * dx / 4.0;
let yc = y1[0] + slope * 3.0 * dx / 4.0;
icon2.draw(slope, xc, yc);
let xc = x[0] + dx / 4.0;
let yc = y2[0] - slope * dx / 4.0;
icon3.draw(-slope, xc, yc);
let xc = x[0] + 3.0 * dx / 4.0;
let yc = y2[0] - slope * 3.0 * dx / 4.0;
icon4.draw(-slope, xc, yc);
let mut plot = Plot::new();
plot.add(&curve1)
.add(&curve2)
.add(&icon1)
.add(&icon2)
.add(&icon3)
.add(&icon4);
let path = Path::new(OUT_DIR).join("integ_slope_icon_above.svg");
plot.set_equal_axes(true).grid_and_labels("x", "y").save(&path)?;
let file = File::open(path).map_err(|_| "cannot open file")?;
let buffered = BufReader::new(file);
let lines_iter = buffered.lines();
assert!(lines_iter.count() > 680);
Ok(())
}
#[test]
fn test_slope_icon_linx_liny() -> Result<(), StrError> {
let mut curve1 = Curve::new();
let mut curve2 = Curve::new();
let slope = 1.0 / 3.0;
let x = [-10.0, 10.0];
let dx = x[1] - x[0];
let y1 = [5.0, 5.0 + slope * dx];
let y2 = [5.0 + slope * dx, 5.0];
curve1.draw(&x, &y1);
curve2.draw(&x, &y2);
let mut icon1 = SlopeIcon::new();
let mut icon2 = SlopeIcon::new();
let mut icon3 = SlopeIcon::new();
let mut icon4 = SlopeIcon::new();
let mut icon5 = SlopeIcon::new();
let mut icon6 = SlopeIcon::new();
let mut icon7 = SlopeIcon::new();
let mut icon8 = SlopeIcon::new();
icon1.set_precision(3).set_offset_v(1.0);
icon2.set_precision(3).set_offset_v(1.0).set_above(true);
icon3.set_precision(3).set_offset_v(1.0);
icon4.set_precision(3).set_offset_v(1.0).set_above(true);
icon5.set_precision(3).set_offset_v(1.0);
icon6.set_precision(3).set_offset_v(1.0).set_above(true);
icon7.set_precision(3).set_offset_v(1.0);
icon8.set_precision(3).set_offset_v(1.0).set_above(true);
let xc = x[0] + dx / 4.0;
let yc = y1[0] + slope * dx / 4.0;
icon1.draw(slope, xc, yc);
icon2.draw(slope, xc, yc);
let xc = x[0] + 3.0 * dx / 4.0;
let yc = y1[0] + slope * 3.0 * dx / 4.0;
icon3.draw(slope, xc, yc);
icon4.draw(slope, xc, yc);
let xc = x[0] + dx / 4.0;
let yc = y2[0] - slope * dx / 4.0;
icon5.draw(-slope, xc, yc);
icon6.draw(-slope, xc, yc);
let xc = x[0] + 3.0 * dx / 4.0;
let yc = y2[0] - slope * 3.0 * dx / 4.0;
icon7.draw(-slope, xc, yc);
icon8.draw(-slope, xc, yc);
let mut plot = Plot::new();
plot.add(&curve1)
.add(&curve2)
.add(&icon1)
.add(&icon2)
.add(&icon3)
.add(&icon4)
.add(&icon5)
.add(&icon6)
.add(&icon7)
.add(&icon8);
let path = Path::new(OUT_DIR).join("integ_slope_icon_linx_liny.svg");
plot.set_equal_axes(true).grid_and_labels("x", "y").save(&path)?;
let file = File::open(path).map_err(|_| "cannot open file")?;
let buffered = BufReader::new(file);
let lines_iter = buffered.lines();
assert!(lines_iter.count() > 770);
Ok(())
}
#[test]
fn test_slope_icon_logx_liny() -> Result<(), StrError> {
let (p, slope) = (5.0, 0.5);
let (x0, y0) = (10.0, 0.0);
let f1 = |x: f64| y0 + slope * (f64::log10(x / x0));
let xmax = x0 + f64::powf(10.0, p);
let ymax = f1(xmax);
let f2 = |x: f64| ymax - slope * (f64::log10(x / x0));
let mut curve1 = Curve::new();
let mut curve2 = Curve::new();
curve1.set_marker_style("o");
curve2.set_marker_style("*");
let x = linspace(x0, xmax, 5);
let y1: Vec<_> = x.iter().map(|x| f1(*x)).collect();
let y2: Vec<_> = x.iter().map(|x| f2(*x)).collect();
curve1.draw(&x, &y1);
curve2.draw(&x, &y2);
let mut icon1 = SlopeIcon::new();
let mut icon2 = SlopeIcon::new();
let mut icon3 = SlopeIcon::new();
let mut icon4 = SlopeIcon::new();
let mut icon5 = SlopeIcon::new();
let mut icon6 = SlopeIcon::new();
let mut icon7 = SlopeIcon::new();
let mut icon8 = SlopeIcon::new();
let offset = 1.5;
icon1.set_offset_v(offset);
icon2.set_offset_v(offset).set_above(true);
icon3.set_offset_v(offset);
icon4.set_offset_v(offset).set_above(true);
icon5.set_offset_v(offset);
icon6.set_offset_v(offset).set_above(true);
icon7.set_offset_v(offset);
icon8.set_offset_v(offset).set_above(true);
icon1.draw(slope, 1e2, f1(1e2));
icon2.draw(slope, 1e2, f1(1e2));
icon3.draw(slope, 1e4, f1(1e4));
icon4.draw(slope, 1e4, f1(1e4));
icon5.draw(-slope, 1e2, f2(1e2));
icon6.draw(-slope, 1e2, f2(1e2));
icon7.draw(-slope, 1e4, f2(1e4));
icon8.draw(-slope, 1e4, f2(1e4));
let mut plot = Plot::new();
plot.set_log_x(true)
.add(&curve1)
.add(&curve2)
.add(&icon1)
.add(&icon2)
.add(&icon3)
.add(&icon4)
.add(&icon5)
.add(&icon6)
.add(&icon7)
.add(&icon8);
let path = Path::new(OUT_DIR).join("integ_slope_icon_logx_liny.svg");
plot.grid_and_labels("x", "y").save(&path)?;
let file = File::open(path).map_err(|_| "cannot open file")?;
let buffered = BufReader::new(file);
let lines_iter = buffered.lines();
assert!(lines_iter.count() > 1030);
Ok(())
}
#[test]
fn test_slope_icon_linx_logy() -> Result<(), StrError> {
let (p, slope) = (5.0, 1.5);
let (x0, y0) = (0.0, 10.0);
let f1 = |x: f64| y0 * f64::powf(10.0, slope * (x - x0));
let g1 = |y: f64| x0 + (1.0 / slope) * f64::log10(y / y0);
let ymax = y0 + f64::powf(10.0, p);
let xmax = x0 + f64::log10(ymax / y0) / slope;
let f2 = |x: f64| ymax * f64::powf(10.0, -slope * (x - x0));
let g2 = |y: f64| x0 - (1.0 / slope) * f64::log10(y / ymax);
let mut curve1 = Curve::new();
let mut curve2 = Curve::new();
curve1.set_marker_style("o");
curve2.set_marker_style("*");
let x = linspace(x0, xmax, 5);
let y1: Vec<_> = x.iter().map(|x| f1(*x)).collect();
let y2: Vec<_> = x.iter().map(|x| f2(*x)).collect();
curve1.draw(&x, &y1);
curve2.draw(&x, &y2);
let mut icon1 = SlopeIcon::new();
let mut icon2 = SlopeIcon::new();
let mut icon3 = SlopeIcon::new();
let mut icon4 = SlopeIcon::new();
let mut icon5 = SlopeIcon::new();
let mut icon6 = SlopeIcon::new();
let mut icon7 = SlopeIcon::new();
let mut icon8 = SlopeIcon::new();
icon1.set_offset_v(2.0);
icon2.set_offset_v(2.0).set_above(true);
icon3.set_offset_v(2.0);
icon4.set_offset_v(2.0).set_above(true);
icon5.set_offset_v(2.0);
icon6.set_offset_v(2.0).set_above(true);
icon7.set_offset_v(2.0);
icon8.set_offset_v(2.0).set_above(true);
icon1.draw(slope, g1(1e2), 1e2);
icon2.draw(slope, g1(1e2), 1e2);
icon3.draw(slope, g1(1e4), 1e4);
icon4.draw(slope, g1(1e4), 1e4);
icon5.draw(-slope, g2(1e2), 1e2);
icon6.draw(-slope, g2(1e2), 1e2);
icon7.draw(-slope, g2(1e4), 1e4);
icon8.draw(-slope, g2(1e4), 1e4);
let mut plot = Plot::new();
plot.set_log_y(true)
.add(&curve1)
.add(&curve2)
.add(&icon1)
.add(&icon2)
.add(&icon3)
.add(&icon4)
.add(&icon5)
.add(&icon6)
.add(&icon7)
.add(&icon8);
let path = Path::new(OUT_DIR).join("integ_slope_icon_linx_logy.svg");
plot.grid_and_labels("x", "y").save(&path)?;
let file = File::open(path).map_err(|_| "cannot open file")?;
let buffered = BufReader::new(file);
let lines_iter = buffered.lines();
assert!(lines_iter.count() > 950);
Ok(())
}
#[test]
fn test_slope_icon_logx_logy() -> Result<(), StrError> {
let (p, slope) = (5.0, 2.0);
let (x0, y0) = (10.0, 100.0);
let f1 = |x: f64| y0 * f64::powf(x / x0, slope);
let xmax = x0 + f64::powf(10.0, p);
let ymax = f1(xmax);
let f2 = |x: f64| ymax * f64::powf(x / x0, -slope);
let mut curve1 = Curve::new();
let mut curve2 = Curve::new();
curve1.set_marker_style("o");
curve2.set_marker_style("*");
let x = linspace(x0, xmax, 5);
let y1: Vec<_> = x.iter().map(|x| f1(*x)).collect();
let y2: Vec<_> = x.iter().map(|x| f2(*x)).collect();
curve1.draw(&x, &y1);
curve2.draw(&x, &y2);
let mut icon1 = SlopeIcon::new();
let mut icon2 = SlopeIcon::new();
let mut icon3 = SlopeIcon::new();
let mut icon4 = SlopeIcon::new();
let mut icon5 = SlopeIcon::new();
let mut icon6 = SlopeIcon::new();
let mut icon7 = SlopeIcon::new();
let mut icon8 = SlopeIcon::new();
let offset = 2.0;
icon1.set_offset_v(offset);
icon2.set_offset_v(offset).set_above(true);
icon3.set_offset_v(offset);
icon4.set_offset_v(offset).set_above(true);
icon5.set_offset_v(offset);
icon6.set_offset_v(offset).set_above(true);
icon7.set_offset_v(offset);
icon8.set_offset_v(offset).set_above(true);
icon1.draw(slope, 1e2, f1(1e2));
icon2.draw(slope, 1e2, f1(1e2));
icon3.draw(slope, 1e4, f1(1e4));
icon4.draw(slope, 1e4, f1(1e4));
icon5.draw(-slope, 1e2, f2(1e2));
icon6.draw(-slope, 1e2, f2(1e2));
icon7.draw(-slope, 1e4, f2(1e4));
icon8.draw(-slope, 1e4, f2(1e4));
let mut plot = Plot::new();
plot.set_log_x(true)
.set_log_y(true)
.add(&curve1)
.add(&curve2)
.add(&icon1)
.add(&icon2)
.add(&icon3)
.add(&icon4)
.add(&icon5)
.add(&icon6)
.add(&icon7)
.add(&icon8);
let path = Path::new(OUT_DIR).join("integ_slope_icon_logx_logy.svg");
plot.set_equal_axes(true).grid_and_labels("x", "y").save(&path)?;
let file = File::open(path).map_err(|_| "cannot open file")?;
let buffered = BufReader::new(file);
let lines_iter = buffered.lines();
assert!(lines_iter.count() > 610);
Ok(())
}
#[test]
fn test_slope_icon_example() -> Result<(), StrError> {
let slope1 = 0.5;
let (x1i, x1f, y1i) = (2.0, 12.0, 3.0);
let f1a = |x: f64| y1i + slope1 * (x - x1i);
let f1b = |x: f64| f1a(x1f) - slope1 * (x - x1i);
let mut curve1a = Curve::new();
let mut curve1b = Curve::new();
let x1 = linspace(x1i, x1f, 3);
let y1a: Vec<_> = x1.iter().map(|x| f1a(*x)).collect();
let y1b: Vec<_> = x1.iter().map(|x| f1b(*x)).collect();
curve1a.set_marker_style("o").draw(&x1, &y1a);
curve1b.set_marker_style("*").draw(&x1, &y1b);
let mut icon1a = SlopeIcon::new();
let mut icon1b = SlopeIcon::new();
icon1a.set_offset_v(0.0);
icon1b.set_offset_v(0.0);
icon1a.draw(slope1, 5.0, f1a(5.0));
icon1b.draw(-slope1, 5.0, f1b(5.0));
let mut plot = Plot::new();
plot.set_horizontal_gap(0.2);
plot.set_subplot(2, 2, 1)
.add(&curve1a)
.add(&curve1b)
.set_equal_axes(true)
.add(&icon1a)
.add(&icon1b)
.grid_and_labels("x", "y");
let slope2 = 0.75;
let (x2i, x2f, y2i) = (1.0, 1e6, 0.0);
let f2a = |x: f64| y2i + slope2 * f64::log10(x / x2i);
let f2b = |x: f64| f2a(x2f) - slope2 * f64::log10(x / x2i);
let mut curve2a = Curve::new();
let mut curve2b = Curve::new();
let x2 = linspace(x2i, x2f, 3);
let y2a: Vec<_> = x2.iter().map(|x| f2a(*x)).collect();
let y2b: Vec<_> = x2.iter().map(|x| f2b(*x)).collect();
curve2a.set_marker_style("o").draw(&x2, &y2a);
curve2b.set_marker_style("*").draw(&x2, &y2b);
let mut icon2a = SlopeIcon::new();
let mut icon2b = SlopeIcon::new();
icon2a.set_offset_v(0.0);
icon2b.set_offset_v(0.0);
icon2a.draw(slope2, 2e1, f2a(2e1));
icon2b.draw(-slope2, 2e1, f2b(2e1));
plot.set_subplot(2, 2, 2)
.add(&curve2a)
.add(&curve2b)
.set_log_x(true) .add(&icon2a)
.add(&icon2b)
.grid_and_labels("x", "y");
let slope3 = 1.25;
let (x3i, x3f, y3i) = (2.0, 12.0, 1.0);
let f3a = |x: f64| y3i * f64::powf(10.0, slope3 * (x - x3i));
let f3b = |x: f64| f3a(x3f) * f64::powf(10.0, -slope3 * (x - x3i));
let mut curve3a = Curve::new();
let mut curve3b = Curve::new();
let x3 = linspace(x3i, x3f, 3);
let y3a: Vec<_> = x3.iter().map(|x| f3a(*x)).collect();
let y3b: Vec<_> = x3.iter().map(|x| f3b(*x)).collect();
curve3a.set_marker_style("o").draw(&x3, &y3a);
curve3b.set_marker_style("*").draw(&x3, &y3b);
let mut icon3a = SlopeIcon::new();
let mut icon3b = SlopeIcon::new();
icon3a.set_offset_v(0.0);
icon3b.set_offset_v(0.0);
icon3a.draw(slope3, 5.0, f3a(5.0));
icon3b.draw(-slope3, 5.0, f3b(5.0));
plot.set_subplot(2, 2, 3)
.add(&curve3a)
.add(&curve3b)
.set_log_y(true) .add(&icon3a)
.add(&icon3b)
.grid_and_labels("x", "y");
let slope4 = 1.5;
let (x4i, x4f, y4i) = (1.0, 1e6, 1.0);
let f4a = |x: f64| y4i * f64::powf(x / x4i, slope4);
let f4b = |x: f64| f4a(x4f) * f64::powf(x / x4i, -slope4);
let mut curve4a = Curve::new();
let mut curve4b = Curve::new();
let x4 = linspace(x4i, x4f, 4);
let y4a: Vec<_> = x4.iter().map(|x| f4a(*x)).collect();
let y4b: Vec<_> = x4.iter().map(|x| f4b(*x)).collect();
curve4a.set_marker_style("o").draw(&x4, &y4a);
curve4b.set_marker_style("*").draw(&x4, &y4b);
let mut icon4a = SlopeIcon::new();
let mut icon4b = SlopeIcon::new();
icon4a.set_offset_v(0.0);
icon4b.set_offset_v(0.0).set_above(true);
icon4a.draw(slope4, 2e1, f4a(2e1));
icon4b.draw(-slope4, 2e1, f4b(2e1));
plot.set_subplot(2, 2, 4)
.add(&curve4a)
.add(&curve4b)
.set_log_x(true) .set_log_y(true) .set_equal_axes(true)
.add(&icon4a)
.add(&icon4b)
.grid_and_labels("x", "y");
let path = Path::new(OUT_DIR).join("integ_slope_icon_example.svg");
plot.save(&path)?;
let file = File::open(path).map_err(|_| "cannot open file")?;
let buffered = BufReader::new(file);
let lines_iter = buffered.lines();
assert!(lines_iter.count() > 1400);
Ok(())
}