summaryrefslogtreecommitdiffstats
path: root/vendor/plotters/examples
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
commit9835e2ae736235810b4ea1c162ca5e65c547e770 (patch)
tree3fcebf40ed70e581d776a8a4c65923e8ec20e026 /vendor/plotters/examples
parentReleasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff)
downloadrustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz
rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/plotters/examples')
-rw-r--r--vendor/plotters/examples/3d-plot.rs62
-rw-r--r--vendor/plotters/examples/3d-plot2.rs56
-rw-r--r--vendor/plotters/examples/README.md19
-rw-r--r--vendor/plotters/examples/animation.rs65
-rw-r--r--vendor/plotters/examples/area-chart.rs54
-rw-r--r--vendor/plotters/examples/blit-bitmap.rs45
-rw-r--r--vendor/plotters/examples/boxplot.rs229
-rw-r--r--vendor/plotters/examples/chart.rs94
-rw-r--r--vendor/plotters/examples/console.rs200
-rw-r--r--vendor/plotters/examples/customized_coord.rs54
-rw-r--r--vendor/plotters/examples/errorbar.rs98
-rw-r--r--vendor/plotters/examples/full_palette.rs548
-rw-r--r--vendor/plotters/examples/histogram.rs43
-rw-r--r--vendor/plotters/examples/mandelbrot.rs71
-rw-r--r--vendor/plotters/examples/matshow.rs62
-rw-r--r--vendor/plotters/examples/nested_coord.rs47
-rw-r--r--vendor/plotters/examples/normal-dist.rs66
-rw-r--r--vendor/plotters/examples/normal-dist2.rs83
-rw-r--r--vendor/plotters/examples/pie.rs25
-rw-r--r--vendor/plotters/examples/relative_size.rs57
-rw-r--r--vendor/plotters/examples/sierpinski.rs43
-rw-r--r--vendor/plotters/examples/slc-temp.rs174
-rw-r--r--vendor/plotters/examples/snowflake.rs57
-rw-r--r--vendor/plotters/examples/stock.rs79
-rw-r--r--vendor/plotters/examples/tick_control.rs89
-rw-r--r--vendor/plotters/examples/two-scales.rs60
26 files changed, 2480 insertions, 0 deletions
diff --git a/vendor/plotters/examples/3d-plot.rs b/vendor/plotters/examples/3d-plot.rs
new file mode 100644
index 000000000..af40cc29e
--- /dev/null
+++ b/vendor/plotters/examples/3d-plot.rs
@@ -0,0 +1,62 @@
+use plotters::prelude::*;
+const OUT_FILE_NAME: &'static str = "plotters-doc-data/3d-plot.svg";
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let area = SVGBackend::new(OUT_FILE_NAME, (1024, 760)).into_drawing_area();
+
+ area.fill(&WHITE)?;
+
+ let x_axis = (-3.0..3.0).step(0.1);
+ let z_axis = (-3.0..3.0).step(0.1);
+
+ let mut chart = ChartBuilder::on(&area)
+ .caption(format!("3D Plot Test"), ("sans", 20))
+ .build_cartesian_3d(x_axis.clone(), -3.0..3.0, z_axis.clone())?;
+
+ chart.with_projection(|mut pb| {
+ pb.yaw = 0.5;
+ pb.scale = 0.9;
+ pb.into_matrix()
+ });
+
+ chart
+ .configure_axes()
+ .light_grid_style(BLACK.mix(0.15))
+ .max_light_lines(3)
+ .draw()?;
+
+ chart
+ .draw_series(
+ SurfaceSeries::xoz(
+ (-30..30).map(|f| f as f64 / 10.0),
+ (-30..30).map(|f| f as f64 / 10.0),
+ |x, z| (x * x + z * z).cos(),
+ )
+ .style(BLUE.mix(0.2).filled()),
+ )?
+ .label("Surface")
+ .legend(|(x, y)| Rectangle::new([(x + 5, y - 5), (x + 15, y + 5)], BLUE.mix(0.5).filled()));
+
+ chart
+ .draw_series(LineSeries::new(
+ (-100..100)
+ .map(|y| y as f64 / 40.0)
+ .map(|y| ((y * 10.0).sin(), y, (y * 10.0).cos())),
+ &BLACK,
+ ))?
+ .label("Line")
+ .legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &BLACK));
+
+ chart
+ .configure_series_labels()
+ .border_style(&BLACK)
+ .draw()?;
+
+ // To avoid the IO failure being ignored silently, we manually call the present function
+ area.present().expect("Unable to write result to file, please make sure 'plotters-doc-data' dir exists under current dir");
+ println!("Result has been saved to {}", OUT_FILE_NAME);
+ Ok(())
+}
+#[test]
+fn entry_point() {
+ main().unwrap()
+}
diff --git a/vendor/plotters/examples/3d-plot2.rs b/vendor/plotters/examples/3d-plot2.rs
new file mode 100644
index 000000000..0b5ca2131
--- /dev/null
+++ b/vendor/plotters/examples/3d-plot2.rs
@@ -0,0 +1,56 @@
+use plotters::prelude::*;
+fn pdf(x: f64, y: f64) -> f64 {
+ const SDX: f64 = 0.1;
+ const SDY: f64 = 0.1;
+ const A: f64 = 5.0;
+ let x = x as f64 / 10.0;
+ let y = y as f64 / 10.0;
+ A * (-x * x / 2.0 / SDX / SDX - y * y / 2.0 / SDY / SDY).exp()
+}
+
+const OUT_FILE_NAME: &'static str = "plotters-doc-data/3d-plot2.gif";
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let root = BitMapBackend::gif(OUT_FILE_NAME, (600, 400), 100)?.into_drawing_area();
+
+ for pitch in 0..157 {
+ root.fill(&WHITE)?;
+
+ let mut chart = ChartBuilder::on(&root)
+ .caption("2D Gaussian PDF", ("sans-serif", 20))
+ .build_cartesian_3d(-3.0..3.0, 0.0..6.0, -3.0..3.0)?;
+ chart.with_projection(|mut p| {
+ p.pitch = 1.57 - (1.57 - pitch as f64 / 50.0).abs();
+ p.scale = 0.7;
+ p.into_matrix() // build the projection matrix
+ });
+
+ chart
+ .configure_axes()
+ .light_grid_style(BLACK.mix(0.15))
+ .max_light_lines(3)
+ .draw()?;
+
+ chart.draw_series(
+ SurfaceSeries::xoz(
+ (-15..=15).map(|x| x as f64 / 5.0),
+ (-15..=15).map(|x| x as f64 / 5.0),
+ pdf,
+ )
+ .style_func(&|&v| {
+ (&HSLColor(240.0 / 360.0 - 240.0 / 360.0 * v / 5.0, 1.0, 0.7)).into()
+ }),
+ )?;
+
+ root.present()?;
+ }
+
+ // To avoid the IO failure being ignored silently, we manually call the present function
+ root.present().expect("Unable to write result to file, please make sure 'plotters-doc-data' dir exists under current dir");
+ println!("Result has been saved to {}", OUT_FILE_NAME);
+
+ Ok(())
+}
+#[test]
+fn entry_point() {
+ main().unwrap()
+}
diff --git a/vendor/plotters/examples/README.md b/vendor/plotters/examples/README.md
new file mode 100644
index 000000000..b6dd1666a
--- /dev/null
+++ b/vendor/plotters/examples/README.md
@@ -0,0 +1,19 @@
+# plotters examples
+
+* The example projects have been moved to independent git repository under plotters-rs organization, please check the [Example Project](#example-project) section for the links.
+
+To run any example, from within the repo, run `cargo run --example <example_name>` where `<example name>` is the name of the file without the `.rs` extension.
+
+All the examples assumes the directory [plotters-doc-data](https://github.com/38/plotters-doc-data) exists, otherwise those example crashs.
+
+The output of these example files are used to generate the [plotters-doc-data](https://github.com/38/plotters-doc-data) repo that populates the sample images in the main README.
+We also rely on the output of examples to detect potential layout changes.
+For that reason, **they must be run with `cargo` from within the repo, or you must change the output filename in the example code to a directory that exists.**
+
+The examples that have their own directories and `Cargo.toml` files work differently. They are run the same way you would a standalone project.
+
+## Example Projects
+
+- For WebAssembly sample project, check [plotters-wasm-demo](https://github.com/plotters-rs/plotters-wasm-demo)
+- For Frame Buffer, Realtime Readering example, check [plotters-minifb-demo](https://github.com/plotters-rs/plotters-minifb-demo)
+- For GTK integration, check [plotters-gtk-demo](https://github.com/plotters-rs/plotters-gtk-demo)
diff --git a/vendor/plotters/examples/animation.rs b/vendor/plotters/examples/animation.rs
new file mode 100644
index 000000000..dab7d451d
--- /dev/null
+++ b/vendor/plotters/examples/animation.rs
@@ -0,0 +1,65 @@
+use plotters::prelude::*;
+
+fn snowflake_iter(points: &[(f64, f64)]) -> Vec<(f64, f64)> {
+ let mut ret = vec![];
+ for i in 0..points.len() {
+ let (start, end) = (points[i], points[(i + 1) % points.len()]);
+ let t = ((end.0 - start.0) / 3.0, (end.1 - start.1) / 3.0);
+ let s = (
+ t.0 * 0.5 - t.1 * (0.75f64).sqrt(),
+ t.1 * 0.5 + (0.75f64).sqrt() * t.0,
+ );
+ ret.push(start);
+ ret.push((start.0 + t.0, start.1 + t.1));
+ ret.push((start.0 + t.0 + s.0, start.1 + t.1 + s.1));
+ ret.push((start.0 + t.0 * 2.0, start.1 + t.1 * 2.0));
+ }
+ ret
+}
+
+const OUT_FILE_NAME: &'static str = "plotters-doc-data/animation.gif";
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let root = BitMapBackend::gif(OUT_FILE_NAME, (800, 600), 1_000)?.into_drawing_area();
+
+ for i in 0..8 {
+ root.fill(&WHITE)?;
+
+ let mut chart = ChartBuilder::on(&root)
+ .caption(
+ format!("Koch's Snowflake (n_iter = {})", i),
+ ("sans-serif", 50),
+ )
+ .build_cartesian_2d(-2.0..2.0, -1.5..1.5)?;
+
+ let mut snowflake_vertices = {
+ let mut current: Vec<(f64, f64)> = vec![
+ (0.0, 1.0),
+ ((3.0f64).sqrt() / 2.0, -0.5),
+ (-(3.0f64).sqrt() / 2.0, -0.5),
+ ];
+ for _ in 0..i {
+ current = snowflake_iter(&current[..]);
+ }
+ current
+ };
+
+ chart.draw_series(std::iter::once(Polygon::new(
+ snowflake_vertices.clone(),
+ &RED.mix(0.2),
+ )))?;
+
+ snowflake_vertices.push(snowflake_vertices[0]);
+ chart.draw_series(std::iter::once(PathElement::new(snowflake_vertices, &RED)))?;
+
+ root.present()?;
+ }
+
+ println!("Result has been saved to {}", OUT_FILE_NAME);
+
+ Ok(())
+}
+
+#[test]
+fn entry_point() {
+ main().unwrap()
+}
diff --git a/vendor/plotters/examples/area-chart.rs b/vendor/plotters/examples/area-chart.rs
new file mode 100644
index 000000000..5b1a7a5a5
--- /dev/null
+++ b/vendor/plotters/examples/area-chart.rs
@@ -0,0 +1,54 @@
+use plotters::prelude::*;
+
+use rand::SeedableRng;
+use rand_distr::{Distribution, Normal};
+use rand_xorshift::XorShiftRng;
+
+const OUT_FILE_NAME: &'static str = "plotters-doc-data/area-chart.png";
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let data: Vec<_> = {
+ let norm_dist = Normal::new(500.0, 100.0).unwrap();
+ let mut x_rand = XorShiftRng::from_seed(*b"MyFragileSeed123");
+ let x_iter = norm_dist.sample_iter(&mut x_rand);
+ x_iter
+ .filter(|x| *x < 1500.0)
+ .take(100)
+ .zip(0..)
+ .map(|(x, b)| x + (b as f64).powf(1.2))
+ .collect()
+ };
+
+ let root = BitMapBackend::new(OUT_FILE_NAME, (1024, 768)).into_drawing_area();
+
+ root.fill(&WHITE)?;
+
+ let mut chart = ChartBuilder::on(&root)
+ .set_label_area_size(LabelAreaPosition::Left, 60)
+ .set_label_area_size(LabelAreaPosition::Bottom, 60)
+ .caption("Area Chart Demo", ("sans-serif", 40))
+ .build_cartesian_2d(0..(data.len() - 1), 0.0..1500.0)?;
+
+ chart
+ .configure_mesh()
+ .disable_x_mesh()
+ .disable_y_mesh()
+ .draw()?;
+
+ chart.draw_series(
+ AreaSeries::new(
+ (0..).zip(data.iter()).map(|(x, y)| (x, *y)),
+ 0.0,
+ &RED.mix(0.2),
+ )
+ .border_style(&RED),
+ )?;
+
+ // To avoid the IO failure being ignored silently, we manually call the present function
+ root.present().expect("Unable to write result to file, please make sure 'plotters-doc-data' dir exists under current dir");
+ println!("Result has been saved to {}", OUT_FILE_NAME);
+ Ok(())
+}
+#[test]
+fn entry_point() {
+ main().unwrap()
+}
diff --git a/vendor/plotters/examples/blit-bitmap.rs b/vendor/plotters/examples/blit-bitmap.rs
new file mode 100644
index 000000000..990b25645
--- /dev/null
+++ b/vendor/plotters/examples/blit-bitmap.rs
@@ -0,0 +1,45 @@
+use plotters::prelude::*;
+
+use image::{imageops::FilterType, ImageFormat};
+
+use std::fs::File;
+use std::io::BufReader;
+
+const OUT_FILE_NAME: &'static str = "plotters-doc-data/blit-bitmap.png";
+
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let root = BitMapBackend::new(OUT_FILE_NAME, (1024, 768)).into_drawing_area();
+ root.fill(&WHITE)?;
+
+ let mut chart = ChartBuilder::on(&root)
+ .caption("Bitmap Example", ("sans-serif", 30))
+ .margin(5)
+ .set_label_area_size(LabelAreaPosition::Left, 40)
+ .set_label_area_size(LabelAreaPosition::Bottom, 40)
+ .build_cartesian_2d(0.0..1.0, 0.0..1.0)?;
+
+ chart.configure_mesh().disable_mesh().draw()?;
+
+ let (w, h) = chart.plotting_area().dim_in_pixel();
+ let image = image::load(
+ BufReader::new(
+ File::open("plotters-doc-data/cat.png").map_err(|e| {
+ eprintln!("Unable to open file plotters-doc-data.png, please make sure you have clone this repo with --recursive");
+ e
+ })?),
+ ImageFormat::Png,
+ )?
+ .resize_exact(w - w / 10, h - h / 10, FilterType::Nearest);
+
+ let elem: BitMapElement<_> = ((0.05, 0.95), image).into();
+
+ chart.draw_series(std::iter::once(elem))?;
+ // To avoid the IO failure being ignored silently, we manually call the present function
+ root.present().expect("Unable to write result to file, please make sure 'plotters-doc-data' dir exists under current dir");
+ println!("Result has been saved to {}", OUT_FILE_NAME);
+ Ok(())
+}
+#[test]
+fn entry_point() {
+ main().unwrap()
+}
diff --git a/vendor/plotters/examples/boxplot.rs b/vendor/plotters/examples/boxplot.rs
new file mode 100644
index 000000000..6e46db40a
--- /dev/null
+++ b/vendor/plotters/examples/boxplot.rs
@@ -0,0 +1,229 @@
+use itertools::Itertools;
+use plotters::data::fitting_range;
+use plotters::prelude::*;
+use std::collections::BTreeMap;
+use std::collections::HashMap;
+use std::env;
+use std::fs;
+use std::io::{self, prelude::*, BufReader};
+
+fn read_data<BR: BufRead>(reader: BR) -> HashMap<(String, String), Vec<f64>> {
+ let mut ds = HashMap::new();
+ for l in reader.lines() {
+ let line = l.unwrap();
+ let tuple: Vec<&str> = line.split('\t').collect();
+ if tuple.len() == 3 {
+ let key = (String::from(tuple[0]), String::from(tuple[1]));
+ let entry = ds.entry(key).or_insert_with(Vec::new);
+ entry.push(tuple[2].parse::<f64>().unwrap());
+ }
+ }
+ ds
+}
+
+const OUT_FILE_NAME: &'static str = "plotters-doc-data/boxplot.svg";
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let root = SVGBackend::new(OUT_FILE_NAME, (1024, 768)).into_drawing_area();
+ root.fill(&WHITE)?;
+
+ let root = root.margin(5, 5, 5, 5);
+
+ let (upper, lower) = root.split_vertically(512);
+
+ let args: Vec<String> = env::args().collect();
+
+ let ds = if args.len() < 2 {
+ read_data(io::Cursor::new(get_data()))
+ } else {
+ let file = fs::File::open(&args[1])?;
+ read_data(BufReader::new(file))
+ };
+ let dataset: Vec<(String, String, Quartiles)> = ds
+ .iter()
+ .map(|(k, v)| (k.0.clone(), k.1.clone(), Quartiles::new(&v)))
+ .collect();
+
+ let host_list: Vec<_> = dataset
+ .iter()
+ .unique_by(|x| x.0.clone())
+ .sorted_by(|a, b| b.2.median().partial_cmp(&a.2.median()).unwrap())
+ .map(|x| x.0.clone())
+ .collect();
+
+ let mut colors = (0..).map(Palette99::pick);
+ let mut offsets = (-12..).step_by(24);
+ let mut series = BTreeMap::new();
+ for x in dataset.iter() {
+ let entry = series
+ .entry(x.1.clone())
+ .or_insert_with(|| (Vec::new(), colors.next().unwrap(), offsets.next().unwrap()));
+ entry.0.push((x.0.clone(), &x.2));
+ }
+
+ let values: Vec<f32> = dataset
+ .iter()
+ .map(|x| x.2.values().to_vec())
+ .flatten()
+ .collect();
+ let values_range = fitting_range(values.iter());
+
+ let mut chart = ChartBuilder::on(&upper)
+ .x_label_area_size(40)
+ .y_label_area_size(80)
+ .caption("Ping Boxplot", ("sans-serif", 20))
+ .build_cartesian_2d(
+ values_range.start - 1.0..values_range.end + 1.0,
+ host_list[..].into_segmented(),
+ )?;
+
+ chart
+ .configure_mesh()
+ .x_desc("Ping, ms")
+ .y_desc("Host")
+ .y_labels(host_list.len())
+ .light_line_style(&WHITE)
+ .draw()?;
+
+ for (label, (values, style, offset)) in &series {
+ chart
+ .draw_series(values.iter().map(|x| {
+ Boxplot::new_horizontal(SegmentValue::CenterOf(&x.0), &x.1)
+ .width(20)
+ .whisker_width(0.5)
+ .style(style)
+ .offset(*offset)
+ }))?
+ .label(label)
+ .legend(move |(x, y)| Rectangle::new([(x, y - 6), (x + 12, y + 6)], style.filled()));
+ }
+ chart
+ .configure_series_labels()
+ .position(SeriesLabelPosition::UpperRight)
+ .background_style(WHITE.filled())
+ .border_style(&BLACK.mix(0.5))
+ .legend_area_size(22)
+ .draw()?;
+
+ let drawing_areas = lower.split_evenly((1, 2));
+ let (left, right) = (&drawing_areas[0], &drawing_areas[1]);
+
+ let quartiles_a = Quartiles::new(&[
+ 6.0, 7.0, 15.9, 36.9, 39.0, 40.0, 41.0, 42.0, 43.0, 47.0, 49.0,
+ ]);
+ let quartiles_b = Quartiles::new(&[16.0, 17.0, 50.0, 60.0, 40.2, 41.3, 42.7, 43.3, 47.0]);
+
+ let ab_axis = ["a", "b"];
+
+ let values_range = fitting_range(
+ quartiles_a
+ .values()
+ .iter()
+ .chain(quartiles_b.values().iter()),
+ );
+ let mut chart = ChartBuilder::on(&left)
+ .x_label_area_size(40)
+ .y_label_area_size(40)
+ .caption("Vertical Boxplot", ("sans-serif", 20))
+ .build_cartesian_2d(
+ ab_axis[..].into_segmented(),
+ values_range.start - 10.0..values_range.end + 10.0,
+ )?;
+
+ chart.configure_mesh().light_line_style(&WHITE).draw()?;
+ chart.draw_series(vec![
+ Boxplot::new_vertical(SegmentValue::CenterOf(&"a"), &quartiles_a),
+ Boxplot::new_vertical(SegmentValue::CenterOf(&"b"), &quartiles_b),
+ ])?;
+
+ let mut chart = ChartBuilder::on(&right)
+ .x_label_area_size(40)
+ .y_label_area_size(40)
+ .caption("Horizontal Boxplot", ("sans-serif", 20))
+ .build_cartesian_2d(-30f32..90f32, 0..3)?;
+
+ chart.configure_mesh().light_line_style(&WHITE).draw()?;
+ chart.draw_series(vec![
+ Boxplot::new_horizontal(1, &quartiles_a),
+ Boxplot::new_horizontal(2, &Quartiles::new(&[30])),
+ ])?;
+
+ // To avoid the IO failure being ignored silently, we manually call the present function
+ root.present().expect("Unable to write result to file, please make sure 'plotters-doc-data' dir exists under current dir");
+ println!("Result has been saved to {}", OUT_FILE_NAME);
+ Ok(())
+}
+
+fn get_data() -> String {
+ String::from(
+ "
+ 1.1.1.1 wireless 41.6
+ 1.1.1.1 wireless 32.5
+ 1.1.1.1 wireless 33.1
+ 1.1.1.1 wireless 32.3
+ 1.1.1.1 wireless 36.7
+ 1.1.1.1 wireless 32.0
+ 1.1.1.1 wireless 33.1
+ 1.1.1.1 wireless 32.0
+ 1.1.1.1 wireless 32.9
+ 1.1.1.1 wireless 32.7
+ 1.1.1.1 wireless 34.5
+ 1.1.1.1 wireless 36.5
+ 1.1.1.1 wireless 31.9
+ 1.1.1.1 wireless 33.7
+ 1.1.1.1 wireless 32.6
+ 1.1.1.1 wireless 35.1
+ 8.8.8.8 wireless 42.3
+ 8.8.8.8 wireless 32.9
+ 8.8.8.8 wireless 32.9
+ 8.8.8.8 wireless 34.3
+ 8.8.8.8 wireless 32.0
+ 8.8.8.8 wireless 33.3
+ 8.8.8.8 wireless 31.5
+ 8.8.8.8 wireless 33.1
+ 8.8.8.8 wireless 33.2
+ 8.8.8.8 wireless 35.9
+ 8.8.8.8 wireless 42.3
+ 8.8.8.8 wireless 34.1
+ 8.8.8.8 wireless 34.2
+ 8.8.8.8 wireless 34.2
+ 8.8.8.8 wireless 32.4
+ 8.8.8.8 wireless 33.0
+ 1.1.1.1 wired 31.8
+ 1.1.1.1 wired 28.6
+ 1.1.1.1 wired 29.4
+ 1.1.1.1 wired 28.8
+ 1.1.1.1 wired 28.2
+ 1.1.1.1 wired 28.8
+ 1.1.1.1 wired 28.4
+ 1.1.1.1 wired 28.6
+ 1.1.1.1 wired 28.3
+ 1.1.1.1 wired 28.5
+ 1.1.1.1 wired 28.5
+ 1.1.1.1 wired 28.5
+ 1.1.1.1 wired 28.4
+ 1.1.1.1 wired 28.6
+ 1.1.1.1 wired 28.4
+ 1.1.1.1 wired 28.9
+ 8.8.8.8 wired 33.3
+ 8.8.8.8 wired 28.4
+ 8.8.8.8 wired 28.7
+ 8.8.8.8 wired 29.1
+ 8.8.8.8 wired 29.6
+ 8.8.8.8 wired 28.9
+ 8.8.8.8 wired 28.6
+ 8.8.8.8 wired 29.3
+ 8.8.8.8 wired 28.6
+ 8.8.8.8 wired 29.1
+ 8.8.8.8 wired 28.7
+ 8.8.8.8 wired 28.3
+ 8.8.8.8 wired 28.3
+ 8.8.8.8 wired 28.6
+ 8.8.8.8 wired 29.4
+ 8.8.8.8 wired 33.1
+",
+ )
+}
+#[test]
+fn entry_point() {
+ main().unwrap()
+}
diff --git a/vendor/plotters/examples/chart.rs b/vendor/plotters/examples/chart.rs
new file mode 100644
index 000000000..acdddc3c1
--- /dev/null
+++ b/vendor/plotters/examples/chart.rs
@@ -0,0 +1,94 @@
+use plotters::prelude::*;
+
+const OUT_FILE_NAME: &'static str = "plotters-doc-data/sample.png";
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let root_area = BitMapBackend::new(OUT_FILE_NAME, (1024, 768)).into_drawing_area();
+
+ root_area.fill(&WHITE)?;
+
+ let root_area = root_area.titled("Image Title", ("sans-serif", 60))?;
+
+ let (upper, lower) = root_area.split_vertically(512);
+
+ let x_axis = (-3.4f32..3.4).step(0.1);
+
+ let mut cc = ChartBuilder::on(&upper)
+ .margin(5)
+ .set_all_label_area_size(50)
+ .caption("Sine and Cosine", ("sans-serif", 40))
+ .build_cartesian_2d(-3.4f32..3.4, -1.2f32..1.2f32)?;
+
+ cc.configure_mesh()
+ .x_labels(20)
+ .y_labels(10)
+ .disable_mesh()
+ .x_label_formatter(&|v| format!("{:.1}", v))
+ .y_label_formatter(&|v| format!("{:.1}", v))
+ .draw()?;
+
+ cc.draw_series(LineSeries::new(x_axis.values().map(|x| (x, x.sin())), &RED))?
+ .label("Sine")
+ .legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &RED));
+
+ cc.draw_series(LineSeries::new(
+ x_axis.values().map(|x| (x, x.cos())),
+ &BLUE,
+ ))?
+ .label("Cosine")
+ .legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &BLUE));
+
+ cc.configure_series_labels().border_style(&BLACK).draw()?;
+
+ /*
+ // It's possible to use a existing pointing element
+ cc.draw_series(PointSeries::<_, _, Circle<_>>::new(
+ (-3.0f32..2.1f32).step(1.0).values().map(|x| (x, x.sin())),
+ 5,
+ Into::<ShapeStyle>::into(&RGBColor(255,0,0)).filled(),
+ ))?;*/
+
+ // Otherwise you can use a function to construct your pointing element yourself
+ cc.draw_series(PointSeries::of_element(
+ (-3.0f32..2.1f32).step(1.0).values().map(|x| (x, x.sin())),
+ 5,
+ ShapeStyle::from(&RED).filled(),
+ &|coord, size, style| {
+ EmptyElement::at(coord)
+ + Circle::new((0, 0), size, style)
+ + Text::new(format!("{:?}", coord), (0, 15), ("sans-serif", 15))
+ },
+ ))?;
+
+ let drawing_areas = lower.split_evenly((1, 2));
+
+ for (drawing_area, idx) in drawing_areas.iter().zip(1..) {
+ let mut cc = ChartBuilder::on(&drawing_area)
+ .x_label_area_size(30)
+ .y_label_area_size(30)
+ .margin_right(20)
+ .caption(format!("y = x^{}", 1 + 2 * idx), ("sans-serif", 40))
+ .build_cartesian_2d(-1f32..1f32, -1f32..1f32)?;
+ cc.configure_mesh()
+ .x_labels(5)
+ .y_labels(3)
+ .max_light_lines(4)
+ .draw()?;
+
+ cc.draw_series(LineSeries::new(
+ (-1f32..1f32)
+ .step(0.01)
+ .values()
+ .map(|x| (x, x.powf(idx as f32 * 2.0 + 1.0))),
+ &BLUE,
+ ))?;
+ }
+
+ // To avoid the IO failure being ignored silently, we manually call the present function
+ root_area.present().expect("Unable to write result to file, please make sure 'plotters-doc-data' dir exists under current dir");
+ println!("Result has been saved to {}", OUT_FILE_NAME);
+ Ok(())
+}
+#[test]
+fn entry_point() {
+ main().unwrap()
+}
diff --git a/vendor/plotters/examples/console.rs b/vendor/plotters/examples/console.rs
new file mode 100644
index 000000000..feba0956b
--- /dev/null
+++ b/vendor/plotters/examples/console.rs
@@ -0,0 +1,200 @@
+use plotters::prelude::*;
+use plotters::style::text_anchor::{HPos, VPos};
+use plotters_backend::{
+ BackendColor, BackendStyle, BackendTextStyle, DrawingBackend, DrawingErrorKind,
+};
+use std::error::Error;
+
+#[derive(Copy, Clone)]
+enum PixelState {
+ Empty,
+ HLine,
+ VLine,
+ Cross,
+ Pixel,
+ Text(char),
+ Circle(bool),
+}
+
+impl PixelState {
+ fn to_char(self) -> char {
+ match self {
+ Self::Empty => ' ',
+ Self::HLine => '-',
+ Self::VLine => '|',
+ Self::Cross => '+',
+ Self::Pixel => '.',
+ Self::Text(c) => c,
+ Self::Circle(filled) => {
+ if filled {
+ '@'
+ } else {
+ 'O'
+ }
+ }
+ }
+ }
+
+ fn update(&mut self, new_state: PixelState) {
+ let next_state = match (*self, new_state) {
+ (Self::HLine, Self::VLine) => Self::Cross,
+ (Self::VLine, Self::HLine) => Self::Cross,
+ (_, Self::Circle(what)) => Self::Circle(what),
+ (Self::Circle(what), _) => Self::Circle(what),
+ (_, Self::Pixel) => Self::Pixel,
+ (Self::Pixel, _) => Self::Pixel,
+ (_, new) => new,
+ };
+
+ *self = next_state;
+ }
+}
+
+pub struct TextDrawingBackend(Vec<PixelState>);
+
+impl DrawingBackend for TextDrawingBackend {
+ type ErrorType = std::io::Error;
+
+ fn get_size(&self) -> (u32, u32) {
+ (100, 30)
+ }
+
+ fn ensure_prepared(&mut self) -> Result<(), DrawingErrorKind<std::io::Error>> {
+ Ok(())
+ }
+
+ fn present(&mut self) -> Result<(), DrawingErrorKind<std::io::Error>> {
+ for r in 0..30 {
+ let mut buf = String::new();
+ for c in 0..100 {
+ buf.push(self.0[r * 100 + c].to_char());
+ }
+ println!("{}", buf);
+ }
+
+ Ok(())
+ }
+
+ fn draw_pixel(
+ &mut self,
+ pos: (i32, i32),
+ color: BackendColor,
+ ) -> Result<(), DrawingErrorKind<std::io::Error>> {
+ if color.alpha > 0.3 {
+ self.0[(pos.1 * 100 + pos.0) as usize].update(PixelState::Pixel);
+ }
+ Ok(())
+ }
+
+ fn draw_line<S: BackendStyle>(
+ &mut self,
+ from: (i32, i32),
+ to: (i32, i32),
+ style: &S,
+ ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
+ if from.0 == to.0 {
+ let x = from.0;
+ let y0 = from.1.min(to.1);
+ let y1 = from.1.max(to.1);
+ for y in y0..y1 {
+ self.0[(y * 100 + x) as usize].update(PixelState::VLine);
+ }
+ return Ok(());
+ }
+
+ if from.1 == to.1 {
+ let y = from.1;
+ let x0 = from.0.min(to.0);
+ let x1 = from.0.max(to.0);
+ for x in x0..x1 {
+ self.0[(y * 100 + x) as usize].update(PixelState::HLine);
+ }
+ return Ok(());
+ }
+
+ plotters_backend::rasterizer::draw_line(self, from, to, style)
+ }
+
+ fn estimate_text_size<S: BackendTextStyle>(
+ &self,
+ text: &str,
+ _: &S,
+ ) -> Result<(u32, u32), DrawingErrorKind<Self::ErrorType>> {
+ Ok((text.len() as u32, 1))
+ }
+
+ fn draw_text<S: BackendTextStyle>(
+ &mut self,
+ text: &str,
+ style: &S,
+ pos: (i32, i32),
+ ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
+ let (width, height) = self.estimate_text_size(text, style)?;
+ let (width, height) = (width as i32, height as i32);
+ let dx = match style.anchor().h_pos {
+ HPos::Left => 0,
+ HPos::Right => -width,
+ HPos::Center => -width / 2,
+ };
+ let dy = match style.anchor().v_pos {
+ VPos::Top => 0,
+ VPos::Center => -height / 2,
+ VPos::Bottom => -height,
+ };
+ let offset = (pos.1 + dy).max(0) * 100 + (pos.0 + dx).max(0);
+ for (idx, chr) in (offset..).zip(text.chars()) {
+ self.0[idx as usize].update(PixelState::Text(chr));
+ }
+ Ok(())
+ }
+}
+
+fn draw_chart<DB: DrawingBackend>(
+ b: DrawingArea<DB, plotters::coord::Shift>,
+) -> Result<(), Box<dyn Error>>
+where
+ DB::ErrorType: 'static,
+{
+ let mut chart = ChartBuilder::on(&b)
+ .margin(1)
+ .caption("Sine and Cosine", ("sans-serif", (10).percent_height()))
+ .set_label_area_size(LabelAreaPosition::Left, (5i32).percent_width())
+ .set_label_area_size(LabelAreaPosition::Bottom, (10i32).percent_height())
+ .build_cartesian_2d(-std::f64::consts::PI..std::f64::consts::PI, -1.2..1.2)?;
+
+ chart
+ .configure_mesh()
+ .disable_x_mesh()
+ .disable_y_mesh()
+ .draw()?;
+
+ chart.draw_series(LineSeries::new(
+ (-314..314).map(|x| x as f64 / 100.0).map(|x| (x, x.sin())),
+ &RED,
+ ))?;
+
+ chart.draw_series(LineSeries::new(
+ (-314..314).map(|x| x as f64 / 100.0).map(|x| (x, x.cos())),
+ &RED,
+ ))?;
+
+ b.present()?;
+
+ Ok(())
+}
+
+const OUT_FILE_NAME: &'static str = "plotters-doc-data/console-example.png";
+fn main() -> Result<(), Box<dyn Error>> {
+ draw_chart(TextDrawingBackend(vec![PixelState::Empty; 5000]).into_drawing_area())?;
+ let b = BitMapBackend::new(OUT_FILE_NAME, (1024, 768)).into_drawing_area();
+ b.fill(&WHITE)?;
+ draw_chart(b)?;
+
+ println!("Image result has been saved to {}", OUT_FILE_NAME);
+
+ Ok(())
+}
+#[test]
+fn entry_point() {
+ main().unwrap()
+}
diff --git a/vendor/plotters/examples/customized_coord.rs b/vendor/plotters/examples/customized_coord.rs
new file mode 100644
index 000000000..cb3a18f03
--- /dev/null
+++ b/vendor/plotters/examples/customized_coord.rs
@@ -0,0 +1,54 @@
+use plotters::{
+ coord::ranged1d::{KeyPointHint, NoDefaultFormatting, ValueFormatter},
+ prelude::*,
+};
+const OUT_FILE_NAME: &'static str = "plotters-doc-data/customized_coord.svg";
+
+struct CustomizedX(u32);
+
+impl Ranged for CustomizedX {
+ type ValueType = u32;
+ type FormatOption = NoDefaultFormatting;
+ fn map(&self, value: &Self::ValueType, limit: (i32, i32)) -> i32 {
+ let size = limit.1 - limit.0;
+ ((*value as f64 / self.0 as f64) * size as f64) as i32 + limit.0
+ }
+
+ fn range(&self) -> std::ops::Range<Self::ValueType> {
+ 0..self.0
+ }
+
+ fn key_points<Hint: KeyPointHint>(&self, hint: Hint) -> Vec<Self::ValueType> {
+ if hint.max_num_points() < (self.0 as usize) {
+ return vec![];
+ }
+
+ (0..self.0).collect()
+ }
+}
+
+impl ValueFormatter<u32> for CustomizedX {
+ fn format_ext(&self, value: &u32) -> String {
+ format!("{} of {}", value, self.0)
+ }
+}
+
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let area = SVGBackend::new(OUT_FILE_NAME, (1024, 760)).into_drawing_area();
+ area.fill(&WHITE)?;
+
+ let mut chart = ChartBuilder::on(&area)
+ .set_all_label_area_size(50)
+ .build_cartesian_2d(CustomizedX(7), 0.0..10.0)?;
+
+ chart.configure_mesh().draw()?;
+
+ area.present().expect("Unable to write result to file, please make sure 'plotters-doc-data' dir exists under current dir");
+ println!("Result has been saved to {}", OUT_FILE_NAME);
+ Ok(())
+}
+
+#[test]
+fn entry_point() {
+ main().unwrap()
+}
diff --git a/vendor/plotters/examples/errorbar.rs b/vendor/plotters/examples/errorbar.rs
new file mode 100644
index 000000000..75c5dbea0
--- /dev/null
+++ b/vendor/plotters/examples/errorbar.rs
@@ -0,0 +1,98 @@
+use plotters::prelude::*;
+
+use rand::SeedableRng;
+use rand_distr::{Distribution, Normal};
+use rand_xorshift::XorShiftRng;
+
+use itertools::Itertools;
+
+use num_traits::sign::Signed;
+
+const OUT_FILE_NAME: &'static str = "plotters-doc-data/errorbar.png";
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let data = generate_random_data();
+ let down_sampled = down_sample(&data[..]);
+
+ let root = BitMapBackend::new(OUT_FILE_NAME, (1024, 768)).into_drawing_area();
+
+ root.fill(&WHITE)?;
+
+ let mut chart = ChartBuilder::on(&root)
+ .caption("Linear Function with Noise", ("sans-serif", 60))
+ .margin(10)
+ .set_label_area_size(LabelAreaPosition::Left, 40)
+ .set_label_area_size(LabelAreaPosition::Bottom, 40)
+ .build_cartesian_2d(-10f64..10f64, -10f64..10f64)?;
+
+ chart.configure_mesh().draw()?;
+
+ chart
+ .draw_series(LineSeries::new(data, &GREEN.mix(0.3)))?
+ .label("Raw Data")
+ .legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &GREEN));
+
+ chart.draw_series(LineSeries::new(
+ down_sampled.iter().map(|(x, _, y, _)| (*x, *y)),
+ &BLUE,
+ ))?;
+
+ chart
+ .draw_series(
+ down_sampled.iter().map(|(x, yl, ym, yh)| {
+ ErrorBar::new_vertical(*x, *yl, *ym, *yh, BLUE.filled(), 20)
+ }),
+ )?
+ .label("Down-sampled")
+ .legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &BLUE));
+
+ chart
+ .configure_series_labels()
+ .background_style(WHITE.filled())
+ .draw()?;
+
+ // To avoid the IO failure being ignored silently, we manually call the present function
+ root.present().expect("Unable to write result to file, please make sure 'plotters-doc-data' dir exists under current dir");
+ println!("Result has been saved to {}", OUT_FILE_NAME);
+
+ Ok(())
+}
+
+fn generate_random_data() -> Vec<(f64, f64)> {
+ let norm_dist = Normal::new(0.0, 1.0).unwrap();
+ let mut x_rand = XorShiftRng::from_seed(*b"MyFragileSeed123");
+ let x_iter = norm_dist.sample_iter(&mut x_rand);
+ x_iter
+ .take(20000)
+ .filter(|x| x.abs() <= 4.0)
+ .zip(-10000..10000)
+ .map(|(yn, x)| {
+ (
+ x as f64 / 1000.0,
+ x as f64 / 1000.0 + yn * x as f64 / 10000.0,
+ )
+ })
+ .collect()
+}
+
+fn down_sample(data: &[(f64, f64)]) -> Vec<(f64, f64, f64, f64)> {
+ let down_sampled: Vec<_> = data
+ .iter()
+ .group_by(|x| (x.0 * 1.0).round() / 1.0)
+ .into_iter()
+ .map(|(x, g)| {
+ let mut g: Vec<_> = g.map(|(_, y)| *y).collect();
+ g.sort_by(|a, b| a.partial_cmp(b).unwrap());
+ (
+ x,
+ g[0],
+ g.iter().sum::<f64>() / g.len() as f64,
+ g[g.len() - 1],
+ )
+ })
+ .collect();
+ down_sampled
+}
+#[test]
+fn entry_point() {
+ main().unwrap()
+}
diff --git a/vendor/plotters/examples/full_palette.rs b/vendor/plotters/examples/full_palette.rs
new file mode 100644
index 000000000..dbd0d4290
--- /dev/null
+++ b/vendor/plotters/examples/full_palette.rs
@@ -0,0 +1,548 @@
+use plotters::prelude::*;
+
+const OUT_FILE_NAME: &'static str = "plotters-doc-data/full_palette.png";
+
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let root = BitMapBackend::new(OUT_FILE_NAME, (2000, 850)).into_drawing_area();
+
+ root.fill(&WHITE)?;
+
+ let mut chart = ChartBuilder::on(&root)
+ .caption("Demonstration of full_palette Colors", ("sans-serif", 50))
+ .build_cartesian_2d(-0.5f32..19f32, -1f32..15f32)?;
+
+ use full_palette::*;
+ let colors = [
+ [
+ RED, RED_50, RED_100, RED_200, RED_300, RED_400, RED_500, RED_600, RED_700, RED_800,
+ RED_900, RED_A100, RED_A200, RED_A400, RED_A700,
+ ],
+ [
+ PINK, PINK_50, PINK_100, PINK_200, PINK_300, PINK_400, PINK_500, PINK_600, PINK_700,
+ PINK_800, PINK_900, PINK_A100, PINK_A200, PINK_A400, PINK_A700,
+ ],
+ [
+ PURPLE,
+ PURPLE_50,
+ PURPLE_100,
+ PURPLE_200,
+ PURPLE_300,
+ PURPLE_400,
+ PURPLE_500,
+ PURPLE_600,
+ PURPLE_700,
+ PURPLE_800,
+ PURPLE_900,
+ PURPLE_A100,
+ PURPLE_A200,
+ PURPLE_A400,
+ PURPLE_A700,
+ ],
+ [
+ DEEPPURPLE,
+ DEEPPURPLE_50,
+ DEEPPURPLE_100,
+ DEEPPURPLE_200,
+ DEEPPURPLE_300,
+ DEEPPURPLE_400,
+ DEEPPURPLE_500,
+ DEEPPURPLE_600,
+ DEEPPURPLE_700,
+ DEEPPURPLE_800,
+ DEEPPURPLE_900,
+ DEEPPURPLE_A100,
+ DEEPPURPLE_A200,
+ DEEPPURPLE_A400,
+ DEEPPURPLE_A700,
+ ],
+ [
+ INDIGO,
+ INDIGO_50,
+ INDIGO_100,
+ INDIGO_200,
+ INDIGO_300,
+ INDIGO_400,
+ INDIGO_500,
+ INDIGO_600,
+ INDIGO_700,
+ INDIGO_800,
+ INDIGO_900,
+ INDIGO_A100,
+ INDIGO_A200,
+ INDIGO_A400,
+ INDIGO_A700,
+ ],
+ [
+ BLUE, BLUE_50, BLUE_100, BLUE_200, BLUE_300, BLUE_400, BLUE_500, BLUE_600, BLUE_700,
+ BLUE_800, BLUE_900, BLUE_A100, BLUE_A200, BLUE_A400, BLUE_A700,
+ ],
+ [
+ LIGHTBLUE,
+ LIGHTBLUE_50,
+ LIGHTBLUE_100,
+ LIGHTBLUE_200,
+ LIGHTBLUE_300,
+ LIGHTBLUE_400,
+ LIGHTBLUE_500,
+ LIGHTBLUE_600,
+ LIGHTBLUE_700,
+ LIGHTBLUE_800,
+ LIGHTBLUE_900,
+ LIGHTBLUE_A100,
+ LIGHTBLUE_A200,
+ LIGHTBLUE_A400,
+ LIGHTBLUE_A700,
+ ],
+ [
+ CYAN, CYAN_50, CYAN_100, CYAN_200, CYAN_300, CYAN_400, CYAN_500, CYAN_600, CYAN_700,
+ CYAN_800, CYAN_900, CYAN_A100, CYAN_A200, CYAN_A400, CYAN_A700,
+ ],
+ [
+ TEAL, TEAL_50, TEAL_100, TEAL_200, TEAL_300, TEAL_400, TEAL_500, TEAL_600, TEAL_700,
+ TEAL_800, TEAL_900, TEAL_A100, TEAL_A200, TEAL_A400, TEAL_A700,
+ ],
+ [
+ GREEN, GREEN_50, GREEN_100, GREEN_200, GREEN_300, GREEN_400, GREEN_500, GREEN_600,
+ GREEN_700, GREEN_800, GREEN_900, GREEN_A100, GREEN_A200, GREEN_A400, GREEN_A700,
+ ],
+ [
+ LIGHTGREEN,
+ LIGHTGREEN_50,
+ LIGHTGREEN_100,
+ LIGHTGREEN_200,
+ LIGHTGREEN_300,
+ LIGHTGREEN_400,
+ LIGHTGREEN_500,
+ LIGHTGREEN_600,
+ LIGHTGREEN_700,
+ LIGHTGREEN_800,
+ LIGHTGREEN_900,
+ LIGHTGREEN_A100,
+ LIGHTGREEN_A200,
+ LIGHTGREEN_A400,
+ LIGHTGREEN_A700,
+ ],
+ [
+ LIME, LIME_50, LIME_100, LIME_200, LIME_300, LIME_400, LIME_500, LIME_600, LIME_700,
+ LIME_800, LIME_900, LIME_A100, LIME_A200, LIME_A400, LIME_A700,
+ ],
+ [
+ YELLOW,
+ YELLOW_50,
+ YELLOW_100,
+ YELLOW_200,
+ YELLOW_300,
+ YELLOW_400,
+ YELLOW_500,
+ YELLOW_600,
+ YELLOW_700,
+ YELLOW_800,
+ YELLOW_900,
+ YELLOW_A100,
+ YELLOW_A200,
+ YELLOW_A400,
+ YELLOW_A700,
+ ],
+ [
+ AMBER, AMBER_50, AMBER_100, AMBER_200, AMBER_300, AMBER_400, AMBER_500, AMBER_600,
+ AMBER_700, AMBER_800, AMBER_900, AMBER_A100, AMBER_A200, AMBER_A400, AMBER_A700,
+ ],
+ [
+ ORANGE,
+ ORANGE_50,
+ ORANGE_100,
+ ORANGE_200,
+ ORANGE_300,
+ ORANGE_400,
+ ORANGE_500,
+ ORANGE_600,
+ ORANGE_700,
+ ORANGE_800,
+ ORANGE_900,
+ ORANGE_A100,
+ ORANGE_A200,
+ ORANGE_A400,
+ ORANGE_A700,
+ ],
+ [
+ DEEPORANGE,
+ DEEPORANGE_50,
+ DEEPORANGE_100,
+ DEEPORANGE_200,
+ DEEPORANGE_300,
+ DEEPORANGE_400,
+ DEEPORANGE_500,
+ DEEPORANGE_600,
+ DEEPORANGE_700,
+ DEEPORANGE_800,
+ DEEPORANGE_900,
+ DEEPORANGE_A100,
+ DEEPORANGE_A200,
+ DEEPORANGE_A400,
+ DEEPORANGE_A700,
+ ],
+ [
+ BROWN, BROWN_50, BROWN_100, BROWN_200, BROWN_300, BROWN_400, BROWN_500, BROWN_600,
+ BROWN_700, BROWN_800, BROWN_900, BROWN_A100, BROWN_A200, BROWN_A400, BROWN_A700,
+ ],
+ [
+ GREY, GREY_50, GREY_100, GREY_200, GREY_300, GREY_400, GREY_500, GREY_600, GREY_700,
+ GREY_800, GREY_900, GREY_A100, GREY_A200, GREY_A400, GREY_A700,
+ ],
+ [
+ BLUEGREY,
+ BLUEGREY_50,
+ BLUEGREY_100,
+ BLUEGREY_200,
+ BLUEGREY_300,
+ BLUEGREY_400,
+ BLUEGREY_500,
+ BLUEGREY_600,
+ BLUEGREY_700,
+ BLUEGREY_800,
+ BLUEGREY_900,
+ BLUEGREY_A100,
+ BLUEGREY_A200,
+ BLUEGREY_A400,
+ BLUEGREY_A700,
+ ],
+ ];
+ let color_names = [
+ [
+ "RED", "RED_50", "RED_100", "RED_200", "RED_300", "RED_400", "RED_500", "RED_600",
+ "RED_700", "RED_800", "RED_900", "RED_A100", "RED_A200", "RED_A400", "RED_A700",
+ ],
+ [
+ "PINK",
+ "PINK_50",
+ "PINK_100",
+ "PINK_200",
+ "PINK_300",
+ "PINK_400",
+ "PINK_500",
+ "PINK_600",
+ "PINK_700",
+ "PINK_800",
+ "PINK_900",
+ "PINK_A100",
+ "PINK_A200",
+ "PINK_A400",
+ "PINK_A700",
+ ],
+ [
+ "PURPLE",
+ "PURPLE_50",
+ "PURPLE_100",
+ "PURPLE_200",
+ "PURPLE_300",
+ "PURPLE_400",
+ "PURPLE_500",
+ "PURPLE_600",
+ "PURPLE_700",
+ "PURPLE_800",
+ "PURPLE_900",
+ "PURPLE_A100",
+ "PURPLE_A200",
+ "PURPLE_A400",
+ "PURPLE_A700",
+ ],
+ [
+ "DEEPPURPLE",
+ "DEEPPURPLE_50",
+ "DEEPPURPLE_100",
+ "DEEPPURPLE_200",
+ "DEEPPURPLE_300",
+ "DEEPPURPLE_400",
+ "DEEPPURPLE_500",
+ "DEEPPURPLE_600",
+ "DEEPPURPLE_700",
+ "DEEPPURPLE_800",
+ "DEEPPURPLE_900",
+ "DEEPPURPLE_A100",
+ "DEEPPURPLE_A200",
+ "DEEPPURPLE_A400",
+ "DEEPPURPLE_A700",
+ ],
+ [
+ "INDIGO",
+ "INDIGO_50",
+ "INDIGO_100",
+ "INDIGO_200",
+ "INDIGO_300",
+ "INDIGO_400",
+ "INDIGO_500",
+ "INDIGO_600",
+ "INDIGO_700",
+ "INDIGO_800",
+ "INDIGO_900",
+ "INDIGO_A100",
+ "INDIGO_A200",
+ "INDIGO_A400",
+ "INDIGO_A700",
+ ],
+ [
+ "BLUE",
+ "BLUE_50",
+ "BLUE_100",
+ "BLUE_200",
+ "BLUE_300",
+ "BLUE_400",
+ "BLUE_500",
+ "BLUE_600",
+ "BLUE_700",
+ "BLUE_800",
+ "BLUE_900",
+ "BLUE_A100",
+ "BLUE_A200",
+ "BLUE_A400",
+ "BLUE_A700",
+ ],
+ [
+ "LIGHTBLUE",
+ "LIGHTBLUE_50",
+ "LIGHTBLUE_100",
+ "LIGHTBLUE_200",
+ "LIGHTBLUE_300",
+ "LIGHTBLUE_400",
+ "LIGHTBLUE_500",
+ "LIGHTBLUE_600",
+ "LIGHTBLUE_700",
+ "LIGHTBLUE_800",
+ "LIGHTBLUE_900",
+ "LIGHTBLUE_A100",
+ "LIGHTBLUE_A200",
+ "LIGHTBLUE_A400",
+ "LIGHTBLUE_A700",
+ ],
+ [
+ "CYAN",
+ "CYAN_50",
+ "CYAN_100",
+ "CYAN_200",
+ "CYAN_300",
+ "CYAN_400",
+ "CYAN_500",
+ "CYAN_600",
+ "CYAN_700",
+ "CYAN_800",
+ "CYAN_900",
+ "CYAN_A100",
+ "CYAN_A200",
+ "CYAN_A400",
+ "CYAN_A700",
+ ],
+ [
+ "TEAL",
+ "TEAL_50",
+ "TEAL_100",
+ "TEAL_200",
+ "TEAL_300",
+ "TEAL_400",
+ "TEAL_500",
+ "TEAL_600",
+ "TEAL_700",
+ "TEAL_800",
+ "TEAL_900",
+ "TEAL_A100",
+ "TEAL_A200",
+ "TEAL_A400",
+ "TEAL_A700",
+ ],
+ [
+ "GREEN",
+ "GREEN_50",
+ "GREEN_100",
+ "GREEN_200",
+ "GREEN_300",
+ "GREEN_400",
+ "GREEN_500",
+ "GREEN_600",
+ "GREEN_700",
+ "GREEN_800",
+ "GREEN_900",
+ "GREEN_A100",
+ "GREEN_A200",
+ "GREEN_A400",
+ "GREEN_A700",
+ ],
+ [
+ "LIGHTGREEN",
+ "LIGHTGREEN_50",
+ "LIGHTGREEN_100",
+ "LIGHTGREEN_200",
+ "LIGHTGREEN_300",
+ "LIGHTGREEN_400",
+ "LIGHTGREEN_500",
+ "LIGHTGREEN_600",
+ "LIGHTGREEN_700",
+ "LIGHTGREEN_800",
+ "LIGHTGREEN_900",
+ "LIGHTGREEN_A100",
+ "LIGHTGREEN_A200",
+ "LIGHTGREEN_A400",
+ "LIGHTGREEN_A700",
+ ],
+ [
+ "LIME",
+ "LIME_50",
+ "LIME_100",
+ "LIME_200",
+ "LIME_300",
+ "LIME_400",
+ "LIME_500",
+ "LIME_600",
+ "LIME_700",
+ "LIME_800",
+ "LIME_900",
+ "LIME_A100",
+ "LIME_A200",
+ "LIME_A400",
+ "LIME_A700",
+ ],
+ [
+ "YELLOW",
+ "YELLOW_50",
+ "YELLOW_100",
+ "YELLOW_200",
+ "YELLOW_300",
+ "YELLOW_400",
+ "YELLOW_500",
+ "YELLOW_600",
+ "YELLOW_700",
+ "YELLOW_800",
+ "YELLOW_900",
+ "YELLOW_A100",
+ "YELLOW_A200",
+ "YELLOW_A400",
+ "YELLOW_A700",
+ ],
+ [
+ "AMBER",
+ "AMBER_50",
+ "AMBER_100",
+ "AMBER_200",
+ "AMBER_300",
+ "AMBER_400",
+ "AMBER_500",
+ "AMBER_600",
+ "AMBER_700",
+ "AMBER_800",
+ "AMBER_900",
+ "AMBER_A100",
+ "AMBER_A200",
+ "AMBER_A400",
+ "AMBER_A700",
+ ],
+ [
+ "ORANGE",
+ "ORANGE_50",
+ "ORANGE_100",
+ "ORANGE_200",
+ "ORANGE_300",
+ "ORANGE_400",
+ "ORANGE_500",
+ "ORANGE_600",
+ "ORANGE_700",
+ "ORANGE_800",
+ "ORANGE_900",
+ "ORANGE_A100",
+ "ORANGE_A200",
+ "ORANGE_A400",
+ "ORANGE_A700",
+ ],
+ [
+ "DEEPORANGE",
+ "DEEPORANGE_50",
+ "DEEPORANGE_100",
+ "DEEPORANGE_200",
+ "DEEPORANGE_300",
+ "DEEPORANGE_400",
+ "DEEPORANGE_500",
+ "DEEPORANGE_600",
+ "DEEPORANGE_700",
+ "DEEPORANGE_800",
+ "DEEPORANGE_900",
+ "DEEPORANGE_A100",
+ "DEEPORANGE_A200",
+ "DEEPORANGE_A400",
+ "DEEPORANGE_A700",
+ ],
+ [
+ "BROWN",
+ "BROWN_50",
+ "BROWN_100",
+ "BROWN_200",
+ "BROWN_300",
+ "BROWN_400",
+ "BROWN_500",
+ "BROWN_600",
+ "BROWN_700",
+ "BROWN_800",
+ "BROWN_900",
+ "BROWN_A100",
+ "BROWN_A200",
+ "BROWN_A400",
+ "BROWN_A700",
+ ],
+ [
+ "GREY",
+ "GREY_50",
+ "GREY_100",
+ "GREY_200",
+ "GREY_300",
+ "GREY_400",
+ "GREY_500",
+ "GREY_600",
+ "GREY_700",
+ "GREY_800",
+ "GREY_900",
+ "GREY_A100",
+ "GREY_A200",
+ "GREY_A400",
+ "GREY_A700",
+ ],
+ [
+ "BLUEGREY",
+ "BLUEGREY_50",
+ "BLUEGREY_100",
+ "BLUEGREY_200",
+ "BLUEGREY_300",
+ "BLUEGREY_400",
+ "BLUEGREY_500",
+ "BLUEGREY_600",
+ "BLUEGREY_700",
+ "BLUEGREY_800",
+ "BLUEGREY_900",
+ "BLUEGREY_A100",
+ "BLUEGREY_A200",
+ "BLUEGREY_A400",
+ "BLUEGREY_A700",
+ ],
+ ];
+
+ use plotters::style::text_anchor::*;
+ let centered = Pos::new(HPos::Center, VPos::Top);
+ let label_style = TextStyle::from(("monospace", 14.0).into_font()).pos(centered);
+
+ for (col, colors) in colors.iter().enumerate() {
+ chart.draw_series(colors.iter().zip(color_names[col].iter()).enumerate().map(
+ |(row, (color, &name))| {
+ let row = row as f32;
+ let col = col as f32;
+ EmptyElement::at((col, row))
+ + Circle::new((0, 0), 15, color.filled())
+ + Text::new(name, (0, 16), &label_style)
+ },
+ ))?;
+ }
+
+ // To avoid the IO failure being ignored silently, we manually call the present function
+ root.present().expect("Unable to write result to file, please make sure 'plotters-doc-data' dir exists under current dir");
+ println!("Result has been saved to {}", OUT_FILE_NAME);
+
+ Ok(())
+}
+#[test]
+fn entry_point() {
+ main().unwrap()
+}
diff --git a/vendor/plotters/examples/histogram.rs b/vendor/plotters/examples/histogram.rs
new file mode 100644
index 000000000..5cda05dbe
--- /dev/null
+++ b/vendor/plotters/examples/histogram.rs
@@ -0,0 +1,43 @@
+use plotters::prelude::*;
+const OUT_FILE_NAME: &'static str = "plotters-doc-data/histogram.png";
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let root = BitMapBackend::new(OUT_FILE_NAME, (640, 480)).into_drawing_area();
+
+ root.fill(&WHITE)?;
+
+ let mut chart = ChartBuilder::on(&root)
+ .x_label_area_size(35)
+ .y_label_area_size(40)
+ .margin(5)
+ .caption("Histogram Test", ("sans-serif", 50.0))
+ .build_cartesian_2d((0u32..10u32).into_segmented(), 0u32..10u32)?;
+
+ chart
+ .configure_mesh()
+ .disable_x_mesh()
+ .bold_line_style(&WHITE.mix(0.3))
+ .y_desc("Count")
+ .x_desc("Bucket")
+ .axis_desc_style(("sans-serif", 15))
+ .draw()?;
+
+ let data = [
+ 0u32, 1, 1, 1, 4, 2, 5, 7, 8, 6, 4, 2, 1, 8, 3, 3, 3, 4, 4, 3, 3, 3,
+ ];
+
+ chart.draw_series(
+ Histogram::vertical(&chart)
+ .style(RED.mix(0.5).filled())
+ .data(data.iter().map(|x: &u32| (*x, 1))),
+ )?;
+
+ // To avoid the IO failure being ignored silently, we manually call the present function
+ root.present().expect("Unable to write result to file, please make sure 'plotters-doc-data' dir exists under current dir");
+ println!("Result has been saved to {}", OUT_FILE_NAME);
+
+ Ok(())
+}
+#[test]
+fn entry_point() {
+ main().unwrap()
+}
diff --git a/vendor/plotters/examples/mandelbrot.rs b/vendor/plotters/examples/mandelbrot.rs
new file mode 100644
index 000000000..413c319c6
--- /dev/null
+++ b/vendor/plotters/examples/mandelbrot.rs
@@ -0,0 +1,71 @@
+use plotters::prelude::*;
+use std::ops::Range;
+
+const OUT_FILE_NAME: &'static str = "plotters-doc-data/mandelbrot.png";
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let root = BitMapBackend::new(OUT_FILE_NAME, (800, 600)).into_drawing_area();
+
+ root.fill(&WHITE)?;
+
+ let mut chart = ChartBuilder::on(&root)
+ .margin(20)
+ .x_label_area_size(10)
+ .y_label_area_size(10)
+ .build_cartesian_2d(-2.1f64..0.6f64, -1.2f64..1.2f64)?;
+
+ chart
+ .configure_mesh()
+ .disable_x_mesh()
+ .disable_y_mesh()
+ .draw()?;
+
+ let plotting_area = chart.plotting_area();
+
+ let range = plotting_area.get_pixel_range();
+
+ let (pw, ph) = (range.0.end - range.0.start, range.1.end - range.1.start);
+ let (xr, yr) = (chart.x_range(), chart.y_range());
+
+ for (x, y, c) in mandelbrot_set(xr, yr, (pw as usize, ph as usize), 100) {
+ if c != 100 {
+ plotting_area.draw_pixel((x, y), &HSLColor(c as f64 / 100.0, 1.0, 0.5))?;
+ } else {
+ plotting_area.draw_pixel((x, y), &BLACK)?;
+ }
+ }
+
+ // To avoid the IO failure being ignored silently, we manually call the present function
+ root.present().expect("Unable to write result to file, please make sure 'plotters-doc-data' dir exists under current dir");
+ println!("Result has been saved to {}", OUT_FILE_NAME);
+
+ Ok(())
+}
+
+fn mandelbrot_set(
+ real: Range<f64>,
+ complex: Range<f64>,
+ samples: (usize, usize),
+ max_iter: usize,
+) -> impl Iterator<Item = (f64, f64, usize)> {
+ let step = (
+ (real.end - real.start) / samples.0 as f64,
+ (complex.end - complex.start) / samples.1 as f64,
+ );
+ return (0..(samples.0 * samples.1)).map(move |k| {
+ let c = (
+ real.start + step.0 * (k % samples.0) as f64,
+ complex.start + step.1 * (k / samples.0) as f64,
+ );
+ let mut z = (0.0, 0.0);
+ let mut cnt = 0;
+ while cnt < max_iter && z.0 * z.0 + z.1 * z.1 <= 1e10 {
+ z = (z.0 * z.0 - z.1 * z.1 + c.0, 2.0 * z.0 * z.1 + c.1);
+ cnt += 1;
+ }
+ return (c.0, c.1, cnt);
+ });
+}
+#[test]
+fn entry_point() {
+ main().unwrap()
+}
diff --git a/vendor/plotters/examples/matshow.rs b/vendor/plotters/examples/matshow.rs
new file mode 100644
index 000000000..30c71a745
--- /dev/null
+++ b/vendor/plotters/examples/matshow.rs
@@ -0,0 +1,62 @@
+use plotters::prelude::*;
+
+const OUT_FILE_NAME: &'static str = "plotters-doc-data/matshow.png";
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let root = BitMapBackend::new(OUT_FILE_NAME, (1024, 768)).into_drawing_area();
+
+ root.fill(&WHITE)?;
+
+ let mut chart = ChartBuilder::on(&root)
+ .caption("Matshow Example", ("sans-serif", 80))
+ .margin(5)
+ .top_x_label_area_size(40)
+ .y_label_area_size(40)
+ .build_cartesian_2d(0i32..15i32, 15i32..0i32)?;
+
+ chart
+ .configure_mesh()
+ .x_labels(15)
+ .y_labels(15)
+ .max_light_lines(4)
+ .x_label_offset(35)
+ .y_label_offset(25)
+ .disable_x_mesh()
+ .disable_y_mesh()
+ .label_style(("sans-serif", 20))
+ .draw()?;
+
+ let mut matrix = [[0; 15]; 15];
+
+ for i in 0..15 {
+ matrix[i][i] = i + 4;
+ }
+
+ chart.draw_series(
+ matrix
+ .iter()
+ .zip(0..)
+ .map(|(l, y)| l.iter().zip(0..).map(move |(v, x)| (x as i32, y as i32, v)))
+ .flatten()
+ .map(|(x, y, v)| {
+ Rectangle::new(
+ [(x, y), (x + 1, y + 1)],
+ HSLColor(
+ 240.0 / 360.0 - 240.0 / 360.0 * (*v as f64 / 20.0),
+ 0.7,
+ 0.1 + 0.4 * *v as f64 / 20.0,
+ )
+ .filled(),
+ )
+ }),
+ )?;
+
+ // To avoid the IO failure being ignored silently, we manually call the present function
+ root.present().expect("Unable to write result to file, please make sure 'plotters-doc-data' dir exists under current dir");
+ println!("Result has been saved to {}", OUT_FILE_NAME);
+
+ Ok(())
+}
+#[test]
+fn entry_point() {
+ main().unwrap()
+}
diff --git a/vendor/plotters/examples/nested_coord.rs b/vendor/plotters/examples/nested_coord.rs
new file mode 100644
index 000000000..b70010148
--- /dev/null
+++ b/vendor/plotters/examples/nested_coord.rs
@@ -0,0 +1,47 @@
+use plotters::prelude::*;
+const OUT_FILE_NAME: &'static str = "plotters-doc-data/nested_coord.png";
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let root = BitMapBackend::new(OUT_FILE_NAME, (640, 480)).into_drawing_area();
+
+ root.fill(&WHITE)?;
+
+ let mut chart = ChartBuilder::on(&root)
+ .x_label_area_size(35)
+ .y_label_area_size(40)
+ .margin(5)
+ .caption("Nested Coord", ("sans-serif", 50.0))
+ .build_cartesian_2d(
+ ["Linear", "Quadratic"].nested_coord(|_| 0.0..10.0),
+ 0.0..10.0,
+ )?;
+
+ chart
+ .configure_mesh()
+ .disable_mesh()
+ .axis_desc_style(("sans-serif", 15))
+ .draw()?;
+
+ chart.draw_series(LineSeries::new(
+ (0..10)
+ .map(|x| x as f64 / 1.0)
+ .map(|x| ((&"Linear", x).into(), x)),
+ &RED,
+ ))?;
+
+ chart.draw_series(LineSeries::new(
+ (0..10)
+ .map(|x| x as f64 / 1.0)
+ .map(|x| ((&"Quadratic", x).into(), x * x / 10.0)),
+ &RED,
+ ))?;
+
+ // To avoid the IO failure being ignored silently, we manually call the present function
+ root.present().expect("Unable to write result to file, please make sure 'plotters-doc-data' dir exists under current dir");
+ println!("Result has been saved to {}", OUT_FILE_NAME);
+
+ Ok(())
+}
+#[test]
+fn entry_point() {
+ main().unwrap()
+}
diff --git a/vendor/plotters/examples/normal-dist.rs b/vendor/plotters/examples/normal-dist.rs
new file mode 100644
index 000000000..be4878630
--- /dev/null
+++ b/vendor/plotters/examples/normal-dist.rs
@@ -0,0 +1,66 @@
+use plotters::prelude::*;
+
+use rand::SeedableRng;
+use rand_distr::{Distribution, Normal};
+use rand_xorshift::XorShiftRng;
+
+const OUT_FILE_NAME: &'static str = "plotters-doc-data/normal-dist.png";
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let root = BitMapBackend::new(OUT_FILE_NAME, (1024, 768)).into_drawing_area();
+
+ root.fill(&WHITE)?;
+
+ let sd = 0.13;
+
+ let random_points: Vec<(f64, f64)> = {
+ let norm_dist = Normal::new(0.5, sd).unwrap();
+ let mut x_rand = XorShiftRng::from_seed(*b"MyFragileSeed123");
+ let mut y_rand = XorShiftRng::from_seed(*b"MyFragileSeed321");
+ let x_iter = norm_dist.sample_iter(&mut x_rand);
+ let y_iter = norm_dist.sample_iter(&mut y_rand);
+ x_iter.zip(y_iter).take(5000).collect()
+ };
+
+ let areas = root.split_by_breakpoints([944], [80]);
+
+ let mut x_hist_ctx = ChartBuilder::on(&areas[0])
+ .y_label_area_size(40)
+ .build_cartesian_2d((0.0..1.0).step(0.01).use_round().into_segmented(), 0..250)?;
+ let mut y_hist_ctx = ChartBuilder::on(&areas[3])
+ .x_label_area_size(40)
+ .build_cartesian_2d(0..250, (0.0..1.0).step(0.01).use_round())?;
+ let mut scatter_ctx = ChartBuilder::on(&areas[2])
+ .x_label_area_size(40)
+ .y_label_area_size(40)
+ .build_cartesian_2d(0f64..1f64, 0f64..1f64)?;
+ scatter_ctx
+ .configure_mesh()
+ .disable_x_mesh()
+ .disable_y_mesh()
+ .draw()?;
+ scatter_ctx.draw_series(
+ random_points
+ .iter()
+ .map(|(x, y)| Circle::new((*x, *y), 2, GREEN.filled())),
+ )?;
+ let x_hist = Histogram::vertical(&x_hist_ctx)
+ .style(GREEN.filled())
+ .margin(0)
+ .data(random_points.iter().map(|(x, _)| (*x, 1)));
+ let y_hist = Histogram::horizontal(&y_hist_ctx)
+ .style(GREEN.filled())
+ .margin(0)
+ .data(random_points.iter().map(|(_, y)| (*y, 1)));
+ x_hist_ctx.draw_series(x_hist)?;
+ y_hist_ctx.draw_series(y_hist)?;
+
+ // To avoid the IO failure being ignored silently, we manually call the present function
+ root.present().expect("Unable to write result to file, please make sure 'plotters-doc-data' dir exists under current dir");
+ println!("Result has been saved to {}", OUT_FILE_NAME);
+
+ Ok(())
+}
+#[test]
+fn entry_point() {
+ main().unwrap()
+}
diff --git a/vendor/plotters/examples/normal-dist2.rs b/vendor/plotters/examples/normal-dist2.rs
new file mode 100644
index 000000000..6c84ab3ab
--- /dev/null
+++ b/vendor/plotters/examples/normal-dist2.rs
@@ -0,0 +1,83 @@
+use plotters::prelude::*;
+
+use rand::SeedableRng;
+use rand_distr::{Distribution, Normal};
+use rand_xorshift::XorShiftRng;
+
+use num_traits::sign::Signed;
+
+const OUT_FILE_NAME: &'static str = "plotters-doc-data/normal-dist2.png";
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let sd = 0.60;
+
+ let random_points: Vec<f64> = {
+ let norm_dist = Normal::new(0.0, sd).unwrap();
+ let mut x_rand = XorShiftRng::from_seed(*b"MyFragileSeed123");
+ let x_iter = norm_dist.sample_iter(&mut x_rand);
+ x_iter.take(5000).filter(|x| x.abs() <= 4.0).collect()
+ };
+
+ let root = BitMapBackend::new(OUT_FILE_NAME, (1024, 768)).into_drawing_area();
+
+ root.fill(&WHITE)?;
+
+ let mut chart = ChartBuilder::on(&root)
+ .margin(5)
+ .caption("1D Gaussian Distribution Demo", ("sans-serif", 30))
+ .set_label_area_size(LabelAreaPosition::Left, 60)
+ .set_label_area_size(LabelAreaPosition::Bottom, 60)
+ .set_label_area_size(LabelAreaPosition::Right, 60)
+ .build_cartesian_2d(-4f64..4f64, 0f64..0.1)?
+ .set_secondary_coord(
+ (-4f64..4f64).step(0.1).use_round().into_segmented(),
+ 0u32..500u32,
+ );
+
+ chart
+ .configure_mesh()
+ .disable_x_mesh()
+ .disable_y_mesh()
+ .y_label_formatter(&|y| format!("{:.0}%", *y * 100.0))
+ .y_desc("Percentage")
+ .draw()?;
+
+ chart.configure_secondary_axes().y_desc("Count").draw()?;
+
+ let actual = Histogram::vertical(chart.borrow_secondary())
+ .style(GREEN.filled())
+ .margin(3)
+ .data(random_points.iter().map(|x| (*x, 1)));
+
+ chart
+ .draw_secondary_series(actual)?
+ .label("Observed")
+ .legend(|(x, y)| Rectangle::new([(x, y - 5), (x + 10, y + 5)], GREEN.filled()));
+
+ let pdf = LineSeries::new(
+ (-400..400).map(|x| x as f64 / 100.0).map(|x| {
+ (
+ x,
+ (-x * x / 2.0 / sd / sd).exp() / (2.0 * std::f64::consts::PI * sd * sd).sqrt()
+ * 0.1,
+ )
+ }),
+ &RED,
+ );
+
+ chart
+ .draw_series(pdf)?
+ .label("PDF")
+ .legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], RED.filled()));
+
+ chart.configure_series_labels().draw()?;
+
+ // To avoid the IO failure being ignored silently, we manually call the present function
+ root.present().expect("Unable to write result to file, please make sure 'plotters-doc-data' dir exists under current dir");
+ println!("Result has been saved to {}", OUT_FILE_NAME);
+
+ Ok(())
+}
+#[test]
+fn entry_point() {
+ main().unwrap()
+}
diff --git a/vendor/plotters/examples/pie.rs b/vendor/plotters/examples/pie.rs
new file mode 100644
index 000000000..a950c0218
--- /dev/null
+++ b/vendor/plotters/examples/pie.rs
@@ -0,0 +1,25 @@
+use plotters::{prelude::*, style::full_palette::ORANGE};
+
+const OUT_FILE_NAME: &'static str = "plotters-doc-data/pie-chart.png";
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let root_area = BitMapBackend::new(&OUT_FILE_NAME, (950, 700)).into_drawing_area();
+ root_area.fill(&WHITE).unwrap();
+ let title_style = TextStyle::from(("sans-serif", 30).into_font()).color(&(BLACK));
+ root_area.titled("BEST CIRCLES", title_style).unwrap();
+
+ let dims = root_area.dim_in_pixel();
+ let center = (dims.0 as i32 / 2, dims.1 as i32 / 2);
+ let radius = 300.0;
+ let sizes = vec![66.0, 33.0];
+ let _rgba = RGBAColor(0, 50, 255, 1.0);
+ let colors = vec![RGBColor(0, 50, 255), CYAN];
+ let labels = vec!["Pizza", "Pacman"];
+
+ let mut pie = Pie::new(&center, &radius, &sizes, &colors, &labels);
+ pie.start_angle(66.0);
+ pie.label_style((("sans-serif", 50).into_font()).color(&(ORANGE)));
+ pie.percentages((("sans-serif", radius * 0.08).into_font()).color(&BLACK));
+ root_area.draw(&pie)?;
+
+ Ok(())
+}
diff --git a/vendor/plotters/examples/relative_size.rs b/vendor/plotters/examples/relative_size.rs
new file mode 100644
index 000000000..66eaec130
--- /dev/null
+++ b/vendor/plotters/examples/relative_size.rs
@@ -0,0 +1,57 @@
+use plotters::coord::Shift;
+use plotters::prelude::*;
+
+fn draw_chart<B: DrawingBackend>(root: &DrawingArea<B, Shift>) -> DrawResult<(), B> {
+ let mut chart = ChartBuilder::on(root)
+ .caption(
+ "Relative Size Example",
+ ("sans-serif", (5).percent_height()),
+ )
+ .x_label_area_size((10).percent_height())
+ .y_label_area_size((10).percent_width())
+ .margin(5)
+ .build_cartesian_2d(-5.0..5.0, -1.0..1.0)?;
+
+ chart
+ .configure_mesh()
+ .disable_x_mesh()
+ .disable_y_mesh()
+ .label_style(("sans-serif", (3).percent_height()))
+ .draw()?;
+
+ chart.draw_series(LineSeries::new(
+ (0..1000)
+ .map(|x| x as f64 / 100.0 - 5.0)
+ .map(|x| (x, x.sin())),
+ &RED,
+ ))?;
+ Ok(())
+}
+
+const OUT_FILE_NAME: &'static str = "plotters-doc-data/relative_size.png";
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let root = BitMapBackend::new(OUT_FILE_NAME, (1024, 768)).into_drawing_area();
+
+ root.fill(&WHITE)?;
+
+ let (left, right) = root.split_horizontally((70).percent_width());
+
+ draw_chart(&left)?;
+
+ let (upper, lower) = right.split_vertically(300);
+
+ draw_chart(&upper)?;
+ draw_chart(&lower)?;
+ let root = root.shrink((200, 200), (150, 100));
+ draw_chart(&root)?;
+
+ // To avoid the IO failure being ignored silently, we manually call the present function
+ root.present().expect("Unable to write result to file, please make sure 'plotters-doc-data' dir exists under current dir");
+ println!("Result has been saved to {}", OUT_FILE_NAME);
+
+ Ok(())
+}
+#[test]
+fn entry_point() {
+ main().unwrap()
+}
diff --git a/vendor/plotters/examples/sierpinski.rs b/vendor/plotters/examples/sierpinski.rs
new file mode 100644
index 000000000..b9655bf94
--- /dev/null
+++ b/vendor/plotters/examples/sierpinski.rs
@@ -0,0 +1,43 @@
+use plotters::coord::Shift;
+use plotters::prelude::*;
+
+pub fn sierpinski_carpet(
+ depth: u32,
+ drawing_area: &DrawingArea<BitMapBackend, Shift>,
+) -> Result<(), Box<dyn std::error::Error>> {
+ if depth > 0 {
+ let sub_areas = drawing_area.split_evenly((3, 3));
+ for (idx, sub_area) in (0..).zip(sub_areas.iter()) {
+ if idx != 4 {
+ sub_area.fill(&BLUE)?;
+ sierpinski_carpet(depth - 1, sub_area)?;
+ } else {
+ sub_area.fill(&WHITE)?;
+ }
+ }
+ }
+ Ok(())
+}
+
+const OUT_FILE_NAME: &'static str = "plotters-doc-data/sierpinski.png";
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let root = BitMapBackend::new(OUT_FILE_NAME, (1024, 768)).into_drawing_area();
+
+ root.fill(&WHITE)?;
+
+ let root = root
+ .titled("Sierpinski Carpet Demo", ("sans-serif", 60))?
+ .shrink(((1024 - 700) / 2, 0), (700, 700));
+
+ sierpinski_carpet(5, &root)?;
+
+ // To avoid the IO failure being ignored silently, we manually call the present function
+ root.present().expect("Unable to write result to file, please make sure 'plotters-doc-data' dir exists under current dir");
+ println!("Result has been saved to {}", OUT_FILE_NAME);
+
+ Ok(())
+}
+#[test]
+fn entry_point() {
+ main().unwrap()
+}
diff --git a/vendor/plotters/examples/slc-temp.rs b/vendor/plotters/examples/slc-temp.rs
new file mode 100644
index 000000000..9d6e47313
--- /dev/null
+++ b/vendor/plotters/examples/slc-temp.rs
@@ -0,0 +1,174 @@
+use plotters::prelude::*;
+
+use chrono::{TimeZone, Utc};
+
+use std::error::Error;
+
+const OUT_FILE_NAME: &'static str = "plotters-doc-data/slc-temp.png";
+fn main() -> Result<(), Box<dyn Error>> {
+ let root = BitMapBackend::new(OUT_FILE_NAME, (1024, 768)).into_drawing_area();
+
+ root.fill(&WHITE)?;
+
+ let mut chart = ChartBuilder::on(&root)
+ .margin(10)
+ .caption(
+ "Monthly Average Temperate in Salt Lake City, UT",
+ ("sans-serif", 40),
+ )
+ .set_label_area_size(LabelAreaPosition::Left, 60)
+ .set_label_area_size(LabelAreaPosition::Right, 60)
+ .set_label_area_size(LabelAreaPosition::Bottom, 40)
+ .build_cartesian_2d(
+ (Utc.ymd(2010, 1, 1)..Utc.ymd(2018, 12, 1)).monthly(),
+ 14.0..104.0,
+ )?
+ .set_secondary_coord(
+ (Utc.ymd(2010, 1, 1)..Utc.ymd(2018, 12, 1)).monthly(),
+ -10.0..40.0,
+ );
+
+ chart
+ .configure_mesh()
+ .disable_x_mesh()
+ .disable_y_mesh()
+ .x_labels(30)
+ .max_light_lines(4)
+ .y_desc("Average Temp (F)")
+ .draw()?;
+ chart
+ .configure_secondary_axes()
+ .y_desc("Average Temp (C)")
+ .draw()?;
+
+ chart.draw_series(LineSeries::new(
+ DATA.iter().map(|(y, m, t)| (Utc.ymd(*y, *m, 1), *t)),
+ &BLUE,
+ ))?;
+
+ chart.draw_series(
+ DATA.iter()
+ .map(|(y, m, t)| Circle::new((Utc.ymd(*y, *m, 1), *t), 3, BLUE.filled())),
+ )?;
+
+ // To avoid the IO failure being ignored silently, we manually call the present function
+ root.present().expect("Unable to write result to file, please make sure 'plotters-doc-data' dir exists under current dir");
+ println!("Result has been saved to {}", OUT_FILE_NAME);
+
+ Ok(())
+}
+
+const DATA: [(i32, u32, f64); 12 * 9] = [
+ (2010, 1, 32.4),
+ (2010, 2, 37.5),
+ (2010, 3, 44.5),
+ (2010, 4, 50.3),
+ (2010, 5, 55.0),
+ (2010, 6, 70.0),
+ (2010, 7, 78.7),
+ (2010, 8, 76.5),
+ (2010, 9, 68.9),
+ (2010, 10, 56.3),
+ (2010, 11, 40.3),
+ (2010, 12, 36.5),
+ (2011, 1, 28.8),
+ (2011, 2, 35.1),
+ (2011, 3, 45.5),
+ (2011, 4, 48.9),
+ (2011, 5, 55.1),
+ (2011, 6, 68.8),
+ (2011, 7, 77.9),
+ (2011, 8, 78.4),
+ (2011, 9, 68.2),
+ (2011, 10, 55.0),
+ (2011, 11, 41.5),
+ (2011, 12, 31.0),
+ (2012, 1, 35.6),
+ (2012, 2, 38.1),
+ (2012, 3, 49.1),
+ (2012, 4, 56.1),
+ (2012, 5, 63.4),
+ (2012, 6, 73.0),
+ (2012, 7, 79.0),
+ (2012, 8, 79.0),
+ (2012, 9, 68.8),
+ (2012, 10, 54.9),
+ (2012, 11, 45.2),
+ (2012, 12, 34.9),
+ (2013, 1, 19.7),
+ (2013, 2, 31.1),
+ (2013, 3, 46.2),
+ (2013, 4, 49.8),
+ (2013, 5, 61.3),
+ (2013, 6, 73.3),
+ (2013, 7, 80.3),
+ (2013, 8, 77.2),
+ (2013, 9, 68.3),
+ (2013, 10, 52.0),
+ (2013, 11, 43.2),
+ (2013, 12, 25.7),
+ (2014, 1, 31.5),
+ (2014, 2, 39.3),
+ (2014, 3, 46.4),
+ (2014, 4, 52.5),
+ (2014, 5, 63.0),
+ (2014, 6, 71.3),
+ (2014, 7, 81.0),
+ (2014, 8, 75.3),
+ (2014, 9, 70.0),
+ (2014, 10, 58.6),
+ (2014, 11, 42.1),
+ (2014, 12, 38.0),
+ (2015, 1, 35.3),
+ (2015, 2, 45.2),
+ (2015, 3, 50.9),
+ (2015, 4, 54.3),
+ (2015, 5, 60.5),
+ (2015, 6, 77.1),
+ (2015, 7, 76.2),
+ (2015, 8, 77.3),
+ (2015, 9, 70.4),
+ (2015, 10, 60.6),
+ (2015, 11, 40.9),
+ (2015, 12, 32.4),
+ (2016, 1, 31.5),
+ (2016, 2, 35.1),
+ (2016, 3, 49.1),
+ (2016, 4, 55.1),
+ (2016, 5, 60.9),
+ (2016, 6, 76.9),
+ (2016, 7, 80.0),
+ (2016, 8, 77.0),
+ (2016, 9, 67.1),
+ (2016, 10, 59.1),
+ (2016, 11, 47.4),
+ (2016, 12, 31.8),
+ (2017, 1, 29.4),
+ (2017, 2, 42.4),
+ (2017, 3, 51.7),
+ (2017, 4, 51.7),
+ (2017, 5, 62.5),
+ (2017, 6, 74.8),
+ (2017, 7, 81.3),
+ (2017, 8, 78.1),
+ (2017, 9, 65.7),
+ (2017, 10, 52.5),
+ (2017, 11, 49.0),
+ (2017, 12, 34.4),
+ (2018, 1, 38.1),
+ (2018, 2, 37.5),
+ (2018, 3, 45.4),
+ (2018, 4, 54.6),
+ (2018, 5, 64.0),
+ (2018, 6, 74.9),
+ (2018, 7, 82.5),
+ (2018, 8, 78.1),
+ (2018, 9, 71.9),
+ (2018, 10, 53.2),
+ (2018, 11, 39.7),
+ (2018, 12, 33.6),
+];
+#[test]
+fn entry_point() {
+ main().unwrap()
+}
diff --git a/vendor/plotters/examples/snowflake.rs b/vendor/plotters/examples/snowflake.rs
new file mode 100644
index 000000000..6e52f25b6
--- /dev/null
+++ b/vendor/plotters/examples/snowflake.rs
@@ -0,0 +1,57 @@
+use plotters::prelude::*;
+
+fn snowflake_iter(points: &[(f64, f64)]) -> Vec<(f64, f64)> {
+ let mut ret = vec![];
+ for i in 0..points.len() {
+ let (start, end) = (points[i], points[(i + 1) % points.len()]);
+ let t = ((end.0 - start.0) / 3.0, (end.1 - start.1) / 3.0);
+ let s = (
+ t.0 * 0.5 - t.1 * (0.75f64).sqrt(),
+ t.1 * 0.5 + (0.75f64).sqrt() * t.0,
+ );
+ ret.push(start);
+ ret.push((start.0 + t.0, start.1 + t.1));
+ ret.push((start.0 + t.0 + s.0, start.1 + t.1 + s.1));
+ ret.push((start.0 + t.0 * 2.0, start.1 + t.1 * 2.0));
+ }
+ ret
+}
+
+const OUT_FILE_NAME: &'static str = "plotters-doc-data/snowflake.png";
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let root = BitMapBackend::new(OUT_FILE_NAME, (1024, 768)).into_drawing_area();
+
+ root.fill(&WHITE)?;
+
+ let mut chart = ChartBuilder::on(&root)
+ .caption("Koch's Snowflake", ("sans-serif", 50))
+ .build_cartesian_2d(-2.0..2.0, -1.5..1.5)?;
+
+ let mut snowflake_vertices = {
+ let mut current: Vec<(f64, f64)> = vec![
+ (0.0, 1.0),
+ ((3.0f64).sqrt() / 2.0, -0.5),
+ (-(3.0f64).sqrt() / 2.0, -0.5),
+ ];
+ for _ in 0..6 {
+ current = snowflake_iter(&current[..]);
+ }
+ current
+ };
+
+ chart.draw_series(std::iter::once(Polygon::new(
+ snowflake_vertices.clone(),
+ &RED.mix(0.2),
+ )))?;
+ snowflake_vertices.push(snowflake_vertices[0]);
+ chart.draw_series(std::iter::once(PathElement::new(snowflake_vertices, &RED)))?;
+
+ // To avoid the IO failure being ignored silently, we manually call the present function
+ root.present().expect("Unable to write result to file, please make sure 'plotters-doc-data' dir exists under current dir");
+ println!("Result has been saved to {}", OUT_FILE_NAME);
+ Ok(())
+}
+#[test]
+fn entry_point() {
+ main().unwrap()
+}
diff --git a/vendor/plotters/examples/stock.rs b/vendor/plotters/examples/stock.rs
new file mode 100644
index 000000000..8e9416f6d
--- /dev/null
+++ b/vendor/plotters/examples/stock.rs
@@ -0,0 +1,79 @@
+use chrono::offset::{Local, TimeZone};
+use chrono::{Date, Duration};
+use plotters::prelude::*;
+fn parse_time(t: &str) -> Date<Local> {
+ Local
+ .datetime_from_str(&format!("{} 0:0", t), "%Y-%m-%d %H:%M")
+ .unwrap()
+ .date()
+}
+const OUT_FILE_NAME: &'static str = "plotters-doc-data/stock.png";
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let data = get_data();
+ let root = BitMapBackend::new(OUT_FILE_NAME, (1024, 768)).into_drawing_area();
+ root.fill(&WHITE)?;
+
+ let (to_date, from_date) = (
+ parse_time(&data[0].0) + Duration::days(1),
+ parse_time(&data[29].0) - Duration::days(1),
+ );
+
+ let mut chart = ChartBuilder::on(&root)
+ .x_label_area_size(40)
+ .y_label_area_size(40)
+ .caption("MSFT Stock Price", ("sans-serif", 50.0).into_font())
+ .build_cartesian_2d(from_date..to_date, 110f32..135f32)?;
+
+ chart.configure_mesh().light_line_style(&WHITE).draw()?;
+
+ chart.draw_series(
+ data.iter().map(|x| {
+ CandleStick::new(parse_time(x.0), x.1, x.2, x.3, x.4, GREEN.filled(), RED, 15)
+ }),
+ )?;
+
+ // To avoid the IO failure being ignored silently, we manually call the present function
+ root.present().expect("Unable to write result to file, please make sure 'plotters-doc-data' dir exists under current dir");
+ println!("Result has been saved to {}", OUT_FILE_NAME);
+
+ Ok(())
+}
+
+fn get_data() -> Vec<(&'static str, f32, f32, f32, f32)> {
+ return vec![
+ ("2019-04-25", 130.0600, 131.3700, 128.8300, 129.1500),
+ ("2019-04-24", 125.7900, 125.8500, 124.5200, 125.0100),
+ ("2019-04-23", 124.1000, 125.5800, 123.8300, 125.4400),
+ ("2019-04-22", 122.6200, 124.0000, 122.5700, 123.7600),
+ ("2019-04-18", 122.1900, 123.5200, 121.3018, 123.3700),
+ ("2019-04-17", 121.2400, 121.8500, 120.5400, 121.7700),
+ ("2019-04-16", 121.6400, 121.6500, 120.1000, 120.7700),
+ ("2019-04-15", 120.9400, 121.5800, 120.5700, 121.0500),
+ ("2019-04-12", 120.6400, 120.9800, 120.3700, 120.9500),
+ ("2019-04-11", 120.5400, 120.8500, 119.9200, 120.3300),
+ ("2019-04-10", 119.7600, 120.3500, 119.5400, 120.1900),
+ ("2019-04-09", 118.6300, 119.5400, 118.5800, 119.2800),
+ ("2019-04-08", 119.8100, 120.0200, 118.6400, 119.9300),
+ ("2019-04-05", 119.3900, 120.2300, 119.3700, 119.8900),
+ ("2019-04-04", 120.1000, 120.2300, 118.3800, 119.3600),
+ ("2019-04-03", 119.8600, 120.4300, 119.1500, 119.9700),
+ ("2019-04-02", 119.0600, 119.4800, 118.5200, 119.1900),
+ ("2019-04-01", 118.9500, 119.1085, 118.1000, 119.0200),
+ ("2019-03-29", 118.0700, 118.3200, 116.9600, 117.9400),
+ ("2019-03-28", 117.4400, 117.5800, 116.1300, 116.9300),
+ ("2019-03-27", 117.8750, 118.2100, 115.5215, 116.7700),
+ ("2019-03-26", 118.6200, 118.7050, 116.8500, 117.9100),
+ ("2019-03-25", 116.5600, 118.0100, 116.3224, 117.6600),
+ ("2019-03-22", 119.5000, 119.5900, 117.0400, 117.0500),
+ ("2019-03-21", 117.1350, 120.8200, 117.0900, 120.2200),
+ ("2019-03-20", 117.3900, 118.7500, 116.7100, 117.5200),
+ ("2019-03-19", 118.0900, 118.4400, 116.9900, 117.6500),
+ ("2019-03-18", 116.1700, 117.6100, 116.0500, 117.5700),
+ ("2019-03-15", 115.3400, 117.2500, 114.5900, 115.9100),
+ ("2019-03-14", 114.5400, 115.2000, 114.3300, 114.5900),
+ ];
+}
+#[test]
+fn entry_point() {
+ main().unwrap()
+}
diff --git a/vendor/plotters/examples/tick_control.rs b/vendor/plotters/examples/tick_control.rs
new file mode 100644
index 000000000..b34fc88c1
--- /dev/null
+++ b/vendor/plotters/examples/tick_control.rs
@@ -0,0 +1,89 @@
+// Data is pulled from https://covid.ourworldindata.org/data/owid-covid-data.json
+use plotters::prelude::*;
+use std::fs::File;
+use std::io::BufReader;
+
+#[derive(serde_derive::Deserialize)]
+struct DailyData {
+ #[serde(default)]
+ new_cases: f64,
+ #[serde(default)]
+ total_cases: f64,
+}
+
+#[derive(serde_derive::Deserialize)]
+struct CountryData {
+ data: Vec<DailyData>,
+}
+
+const OUT_FILE_NAME: &'static str = "plotters-doc-data/tick_control.svg";
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let root = SVGBackend::new(OUT_FILE_NAME, (1024, 768)).into_drawing_area();
+ root.fill(&WHITE)?;
+
+ let (upper, lower) = root.split_vertically(750);
+
+ lower.titled(
+ "Data Source: https://covid.ourworldindata.org/data/owid-covid-data.json",
+ ("sans-serif", 10).into_font().color(&BLACK.mix(0.5)),
+ )?;
+
+ let mut chart = ChartBuilder::on(&upper)
+ .caption("World COVID-19 Cases", ("sans-serif", (5).percent_height()))
+ .set_label_area_size(LabelAreaPosition::Left, (8).percent())
+ .set_label_area_size(LabelAreaPosition::Bottom, (4).percent())
+ .margin((1).percent())
+ .build_cartesian_2d(
+ (20u32..5000_0000u32)
+ .log_scale()
+ .with_key_points(vec![50, 100, 1000, 10000, 100000, 1000000, 10000000]),
+ (0u32..50_0000u32)
+ .log_scale()
+ .with_key_points(vec![10, 50, 100, 1000, 10000, 100000, 200000]),
+ )?;
+
+ chart
+ .configure_mesh()
+ .x_desc("Total Cases")
+ .y_desc("New Cases")
+ .draw()?;
+
+ let data: std::collections::HashMap<String, CountryData> = serde_json::from_reader(
+ BufReader::new(File::open("plotters-doc-data/covid-data.json")?),
+ )?;
+
+ for (idx, &series) in ["CHN", "USA", "RUS", "JPN", "DEU", "IND", "OWID_WRL"]
+ .iter()
+ .enumerate()
+ {
+ let color = Palette99::pick(idx).mix(0.9);
+ chart
+ .draw_series(LineSeries::new(
+ data[series].data.iter().map(
+ |&DailyData {
+ new_cases,
+ total_cases,
+ ..
+ }| (total_cases as u32, new_cases as u32),
+ ),
+ color.stroke_width(3),
+ ))?
+ .label(series)
+ .legend(move |(x, y)| Rectangle::new([(x, y - 5), (x + 10, y + 5)], color.filled()));
+ }
+
+ chart
+ .configure_series_labels()
+ .border_style(&BLACK)
+ .draw()?;
+
+ // To avoid the IO failure being ignored silently, we manually call the present function
+ root.present().expect("Unable to write result to file, please make sure 'plotters-doc-data' dir exists under current dir");
+ println!("Result has been saved to {}", OUT_FILE_NAME);
+
+ Ok(())
+}
+#[test]
+fn entry_point() {
+ main().unwrap()
+}
diff --git a/vendor/plotters/examples/two-scales.rs b/vendor/plotters/examples/two-scales.rs
new file mode 100644
index 000000000..6e1dfa4c2
--- /dev/null
+++ b/vendor/plotters/examples/two-scales.rs
@@ -0,0 +1,60 @@
+use plotters::prelude::*;
+
+const OUT_FILE_NAME: &'static str = "plotters-doc-data/twoscale.png";
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let root = BitMapBackend::new(OUT_FILE_NAME, (1024, 768)).into_drawing_area();
+ root.fill(&WHITE)?;
+
+ let mut chart = ChartBuilder::on(&root)
+ .x_label_area_size(35)
+ .y_label_area_size(40)
+ .right_y_label_area_size(40)
+ .margin(5)
+ .caption("Dual Y-Axis Example", ("sans-serif", 50.0).into_font())
+ .build_cartesian_2d(0f32..10f32, (0.1f32..1e10f32).log_scale())?
+ .set_secondary_coord(0f32..10f32, -1.0f32..1.0f32);
+
+ chart
+ .configure_mesh()
+ .disable_x_mesh()
+ .disable_y_mesh()
+ .y_desc("Log Scale")
+ .y_label_formatter(&|x| format!("{:e}", x))
+ .draw()?;
+
+ chart
+ .configure_secondary_axes()
+ .y_desc("Linear Scale")
+ .draw()?;
+
+ chart
+ .draw_series(LineSeries::new(
+ (0..=100).map(|x| (x as f32 / 10.0, (1.02f32).powf(x as f32 * x as f32 / 10.0))),
+ &BLUE,
+ ))?
+ .label("y = 1.02^x^2")
+ .legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &BLUE));
+
+ chart
+ .draw_secondary_series(LineSeries::new(
+ (0..=100).map(|x| (x as f32 / 10.0, (x as f32 / 5.0).sin())),
+ &RED,
+ ))?
+ .label("y = sin(2x)")
+ .legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &RED));
+
+ chart
+ .configure_series_labels()
+ .background_style(&RGBColor(128, 128, 128))
+ .draw()?;
+
+ // To avoid the IO failure being ignored silently, we manually call the present function
+ root.present().expect("Unable to write result to file, please make sure 'plotters-doc-data' dir exists under current dir");
+ println!("Result has been saved to {}", OUT_FILE_NAME);
+
+ Ok(())
+}
+#[test]
+fn entry_point() {
+ main().unwrap()
+}