use plotters::prelude::*;
use num::Complex;
use std::f64::consts::PI;
pub struct RealPlot {
x_values: Vec<Vec<f64>>,
y_values: Vec<Vec<f64>>,
x_scale_log: bool,
y_scale_log: bool,
}
pub struct ComplexPlot {
x_values: Vec<Vec<f64>>,
y_values: Vec<Vec<Complex<f64>>>,
x_scale_log: bool,
y_scale_log: bool,
}
impl RealPlot {
pub fn new() -> Self {
RealPlot{
x_values: Vec::new(),
y_values: Vec::new(),
x_scale_log: false,
y_scale_log: false,
}
}
pub fn get_size(&self) -> Vec<usize> {
let mut output: Vec<usize> = Vec::new();
for x in self.x_values.iter() {
output.push(x.len());
}
output
}
pub fn add_data_vector(&mut self, x: Vec<f64>, y: Vec<f64>) {
assert_eq!(x.len(), y.len());
self.x_values.push(x);
self.y_values.push(y);
}
pub fn set_x_scale_to_log(&mut self, x_log: bool) {
self.x_scale_log = x_log;
}
pub fn set_y_scale_to_log(&mut self, y_log: bool) {
self.y_scale_log = y_log;
}
pub fn draw(self, name: &str) {
let (mut xmin, mut xmax): (f64, f64) = (f64::MAX, f64::MIN);
for x_vec in self.x_values.iter() {
let (temp_min, temp_max) = (x_vec[0], x_vec[x_vec.len()-1]);
if temp_min < xmin { xmin = temp_min; }
if temp_max > xmax { xmax = temp_max; }
}
let (mut ymin, mut ymax): (f64, f64) = (f64::MAX, f64::MIN);
for y_vec in self.y_values.iter() {
for y in y_vec.iter() {
if *y < ymin { ymin = *y; }
if *y > ymax { ymax = *y; }
}
}
let drawing_area = SVGBackend::new(name, (1365, 768)).into_drawing_area();
drawing_area.fill(&WHITE).unwrap();
let size: Vec<usize> = self.get_size();
if self.x_scale_log & self.y_scale_log {
let mut ctx = ChartBuilder::on(&drawing_area)
.margin(20)
.set_left_and_bottom_label_area_size(64)
.build_cartesian_2d((xmin..xmax).log_scale(), (ymin..ymax).log_scale())
.unwrap();
ctx.configure_mesh().draw().unwrap();
for i in 0..self.y_values.len() {
ctx.draw_series(LineSeries::new( (0..size[i]).map( |index| (
self.x_values[i][index], self.y_values[i][index]
)), &Palette99::pick(i) )).unwrap();
}
} else if self.x_scale_log & !self.y_scale_log {
let mut ctx = ChartBuilder::on(&drawing_area)
.margin(20)
.set_left_and_bottom_label_area_size(64)
.build_cartesian_2d((xmin..xmax).log_scale(), ymin..ymax)
.unwrap();
ctx.configure_mesh().draw().unwrap();
for i in 0..self.y_values.len() {
ctx.draw_series(LineSeries::new( (0..size[i]).map( |index| (
self.x_values[i][index], self.y_values[i][index]
)), &Palette99::pick(i) )).unwrap();
}
} else if !self.x_scale_log & self.y_scale_log {
let mut ctx = ChartBuilder::on(&drawing_area)
.margin(20)
.set_left_and_bottom_label_area_size(64)
.build_cartesian_2d(xmin..xmax, (ymin..ymax).log_scale())
.unwrap();
ctx.configure_mesh().draw().unwrap();
for i in 0..self.y_values.len() {
ctx.draw_series(LineSeries::new( (0..size[i]).map( |index| (
self.x_values[i][index], self.y_values[i][index]
)), &Palette99::pick(i) )).unwrap();
}
} else {
let mut ctx = ChartBuilder::on(&drawing_area)
.margin(20)
.set_left_and_bottom_label_area_size(64)
.build_cartesian_2d(xmin..xmax, ymin..ymax)
.unwrap();
ctx.configure_mesh().draw().unwrap();
for i in 0..self.y_values.len() {
ctx.draw_series(LineSeries::new( (0..size[i]).map( |index| (
self.x_values[i][index], self.y_values[i][index]
)), &Palette99::pick(i) )).unwrap();
}
}
}
}
impl ComplexPlot {
pub fn new() -> Self {
ComplexPlot{
x_values: Vec::new(),
y_values: Vec::new(),
x_scale_log: false,
y_scale_log: false,
}
}
pub fn get_size(&self) -> Vec<usize> {
let mut output: Vec<usize> = Vec::new();
for x in self.x_values.iter() {
output.push(x.len());
}
output
}
pub fn add_data_vector(&mut self, x: Vec<f64>, y: Vec<Complex<f64>>) {
assert_eq!(x.len(), y.len());
self.x_values.push(x);
self.y_values.push(y);
}
pub fn set_x_scale_to_log(&mut self, x_log: bool) {
self.x_scale_log = x_log;
}
pub fn set_y_scale_to_log(&mut self, y_log: bool) {
self.y_scale_log = y_log;
}
pub fn draw(self, name: &str) {
let (mut xmin, mut xmax): (f64, f64) = (f64::MAX, f64::MIN);
for x_vec in self.x_values.iter() {
let (temp_min, temp_max) = (x_vec[0], x_vec[x_vec.len()-1]);
if temp_min < xmin { xmin = temp_min; }
if temp_max > xmax { xmax = temp_max; }
}
let (mut ymin, mut ymax): (f64, f64) = (f64::MAX, f64::MIN);
for y_vec in self.y_values.iter() {
for y in y_vec.iter() {
if y.norm() < ymin { ymin = y.norm(); }
if y.norm() > ymax { ymax = y.norm(); }
}
}
let drawing_area = SVGBackend::new(name, (1365, 768)).into_drawing_area();
drawing_area.fill(&WHITE).unwrap();
let (top, bottom) = drawing_area.split_vertically(384);
let size: Vec<usize> = self.get_size();
if self.x_scale_log & self.y_scale_log {
let mut ctx = ChartBuilder::on(&top)
.margin(20)
.set_left_and_bottom_label_area_size(64)
.build_cartesian_2d((xmin..xmax).log_scale(), (ymin..ymax).log_scale())
.unwrap();
ctx.configure_mesh().draw().unwrap();
for i in 0..self.y_values.len() {
ctx.draw_series(LineSeries::new( (0..size[i]).map( |index| (
self.x_values[i][index], self.y_values[i][index].norm()
)), &Palette99::pick(i) )).unwrap();
}
} else if self.x_scale_log & !self.y_scale_log {
let mut ctx = ChartBuilder::on(&top)
.margin(20)
.set_left_and_bottom_label_area_size(64)
.build_cartesian_2d((xmin..xmax).log_scale(), ymin..ymax)
.unwrap();
ctx.configure_mesh().draw().unwrap();
for i in 0..self.y_values.len() {
ctx.draw_series(LineSeries::new( (0..size[i]).map( |index| (
self.x_values[i][index], self.y_values[i][index].norm()
)), &Palette99::pick(i) )).unwrap();
}
} else if !self.x_scale_log & self.y_scale_log {
let mut ctx = ChartBuilder::on(&top)
.margin(20)
.set_left_and_bottom_label_area_size(64)
.build_cartesian_2d(xmin..xmax, (ymin..ymax).log_scale())
.unwrap();
ctx.configure_mesh().draw().unwrap();
for i in 0..self.y_values.len() {
ctx.draw_series(LineSeries::new( (0..size[i]).map( |index| (
self.x_values[i][index], self.y_values[i][index].norm()
)), &Palette99::pick(i) )).unwrap();
}
} else {
let mut ctx = ChartBuilder::on(&top)
.margin(20)
.set_left_and_bottom_label_area_size(64)
.build_cartesian_2d(xmin..xmax, ymin..ymax)
.unwrap();
ctx.configure_mesh().draw().unwrap();
for i in 0..self.y_values.len() {
ctx.draw_series(LineSeries::new( (0..size[i]).map( |index| (
self.x_values[i][index], self.y_values[i][index].norm()
)), &Palette99::pick(i) )).unwrap();
}
}
(ymin, ymax) = (-PI, PI);
if self.x_scale_log {
let mut ctx = ChartBuilder::on(&bottom)
.margin(20)
.set_left_and_bottom_label_area_size(64)
.build_cartesian_2d((xmin..xmax).log_scale(), ymin..ymax)
.unwrap();
ctx.configure_mesh().draw().unwrap();
for i in 0..self.y_values.len() {
ctx.draw_series(LineSeries::new( (0..size[i]).map( |index| (
self.x_values[i][index], self.y_values[i][index].arg()
)), &Palette99::pick(i) )).unwrap();
}
} else {
let mut ctx = ChartBuilder::on(&bottom)
.margin(20)
.set_left_and_bottom_label_area_size(64)
.build_cartesian_2d(xmin..xmax, ymin..ymax)
.unwrap();
ctx.configure_mesh().draw().unwrap();
for i in 0..self.y_values.len() {
ctx.draw_series(LineSeries::new( (0..size[i]).map( |index| (
self.x_values[i][index], self.y_values[i][index].arg()
)), &Palette99::pick(i) )).unwrap();
}
}
}
}