feat: add image/plotters
This commit is contained in:
51
__image/plotters/examples/area-chart.rs
Normal file
51
__image/plotters/examples/area-chart.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
use plotters::prelude::*;
|
||||
|
||||
use rand::SeedableRng;
|
||||
use rand_distr::{Distribution, Normal};
|
||||
use rand_xorshift::XorShiftRng;
|
||||
|
||||
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("area-chart.png", (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),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
#[test]
|
||||
fn entry_point() {
|
||||
main().unwrap()
|
||||
}
|
||||
169
__image/plotters/examples/slc-temp.rs
Normal file
169
__image/plotters/examples/slc-temp.rs
Normal file
@@ -0,0 +1,169 @@
|
||||
use plotters::prelude::*;
|
||||
|
||||
use chrono::{TimeZone, Utc};
|
||||
|
||||
use std::error::Error;
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let root =
|
||||
BitMapBackend::new("slc-temp.png", (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)
|
||||
.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())),
|
||||
)?;
|
||||
|
||||
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()
|
||||
}
|
||||
73
__image/plotters/examples/stock.rs
Normal file
73
__image/plotters/examples/stock.rs
Normal file
@@ -0,0 +1,73 @@
|
||||
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()
|
||||
}
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let data = get_data();
|
||||
let root = BitMapBackend::new("stock.png", (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, &RED, 15)),
|
||||
)?;
|
||||
|
||||
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()
|
||||
}
|
||||
Reference in New Issue
Block a user