1 use plotters::prelude::*;
2
3 use chrono::{TimeZone, Utc};
4
5 use std::error::Error;
6
7 const OUT_FILE_NAME: &'static str = "plotters-doc-data/slc-temp.png";
main() -> Result<(), Box<dyn Error>>8 fn main() -> Result<(), Box<dyn Error>> {
9 let root = BitMapBackend::new(OUT_FILE_NAME, (1024, 768)).into_drawing_area();
10
11 root.fill(&WHITE)?;
12
13 let mut chart = ChartBuilder::on(&root)
14 .margin(10)
15 .caption(
16 "Monthly Average Temperate in Salt Lake City, UT",
17 ("sans-serif", 40),
18 )
19 .set_label_area_size(LabelAreaPosition::Left, 60)
20 .set_label_area_size(LabelAreaPosition::Right, 60)
21 .set_label_area_size(LabelAreaPosition::Bottom, 40)
22 .build_cartesian_2d(
23 (Utc.ymd(2010, 1, 1)..Utc.ymd(2018, 12, 1)).monthly(),
24 14.0..104.0,
25 )?
26 .set_secondary_coord(
27 (Utc.ymd(2010, 1, 1)..Utc.ymd(2018, 12, 1)).monthly(),
28 -10.0..40.0,
29 );
30
31 chart
32 .configure_mesh()
33 .disable_x_mesh()
34 .disable_y_mesh()
35 .x_labels(30)
36 .max_light_lines(4)
37 .y_desc("Average Temp (F)")
38 .draw()?;
39 chart
40 .configure_secondary_axes()
41 .y_desc("Average Temp (C)")
42 .draw()?;
43
44 chart.draw_series(LineSeries::new(
45 DATA.iter().map(|(y, m, t)| (Utc.ymd(*y, *m, 1), *t)),
46 &BLUE,
47 ))?;
48
49 chart.draw_series(
50 DATA.iter()
51 .map(|(y, m, t)| Circle::new((Utc.ymd(*y, *m, 1), *t), 3, BLUE.filled())),
52 )?;
53
54 // To avoid the IO failure being ignored silently, we manually call the present function
55 root.present().expect("Unable to write result to file, please make sure 'plotters-doc-data' dir exists under current dir");
56 println!("Result has been saved to {}", OUT_FILE_NAME);
57
58 Ok(())
59 }
60
61 const DATA: [(i32, u32, f64); 12 * 9] = [
62 (2010, 1, 32.4),
63 (2010, 2, 37.5),
64 (2010, 3, 44.5),
65 (2010, 4, 50.3),
66 (2010, 5, 55.0),
67 (2010, 6, 70.0),
68 (2010, 7, 78.7),
69 (2010, 8, 76.5),
70 (2010, 9, 68.9),
71 (2010, 10, 56.3),
72 (2010, 11, 40.3),
73 (2010, 12, 36.5),
74 (2011, 1, 28.8),
75 (2011, 2, 35.1),
76 (2011, 3, 45.5),
77 (2011, 4, 48.9),
78 (2011, 5, 55.1),
79 (2011, 6, 68.8),
80 (2011, 7, 77.9),
81 (2011, 8, 78.4),
82 (2011, 9, 68.2),
83 (2011, 10, 55.0),
84 (2011, 11, 41.5),
85 (2011, 12, 31.0),
86 (2012, 1, 35.6),
87 (2012, 2, 38.1),
88 (2012, 3, 49.1),
89 (2012, 4, 56.1),
90 (2012, 5, 63.4),
91 (2012, 6, 73.0),
92 (2012, 7, 79.0),
93 (2012, 8, 79.0),
94 (2012, 9, 68.8),
95 (2012, 10, 54.9),
96 (2012, 11, 45.2),
97 (2012, 12, 34.9),
98 (2013, 1, 19.7),
99 (2013, 2, 31.1),
100 (2013, 3, 46.2),
101 (2013, 4, 49.8),
102 (2013, 5, 61.3),
103 (2013, 6, 73.3),
104 (2013, 7, 80.3),
105 (2013, 8, 77.2),
106 (2013, 9, 68.3),
107 (2013, 10, 52.0),
108 (2013, 11, 43.2),
109 (2013, 12, 25.7),
110 (2014, 1, 31.5),
111 (2014, 2, 39.3),
112 (2014, 3, 46.4),
113 (2014, 4, 52.5),
114 (2014, 5, 63.0),
115 (2014, 6, 71.3),
116 (2014, 7, 81.0),
117 (2014, 8, 75.3),
118 (2014, 9, 70.0),
119 (2014, 10, 58.6),
120 (2014, 11, 42.1),
121 (2014, 12, 38.0),
122 (2015, 1, 35.3),
123 (2015, 2, 45.2),
124 (2015, 3, 50.9),
125 (2015, 4, 54.3),
126 (2015, 5, 60.5),
127 (2015, 6, 77.1),
128 (2015, 7, 76.2),
129 (2015, 8, 77.3),
130 (2015, 9, 70.4),
131 (2015, 10, 60.6),
132 (2015, 11, 40.9),
133 (2015, 12, 32.4),
134 (2016, 1, 31.5),
135 (2016, 2, 35.1),
136 (2016, 3, 49.1),
137 (2016, 4, 55.1),
138 (2016, 5, 60.9),
139 (2016, 6, 76.9),
140 (2016, 7, 80.0),
141 (2016, 8, 77.0),
142 (2016, 9, 67.1),
143 (2016, 10, 59.1),
144 (2016, 11, 47.4),
145 (2016, 12, 31.8),
146 (2017, 1, 29.4),
147 (2017, 2, 42.4),
148 (2017, 3, 51.7),
149 (2017, 4, 51.7),
150 (2017, 5, 62.5),
151 (2017, 6, 74.8),
152 (2017, 7, 81.3),
153 (2017, 8, 78.1),
154 (2017, 9, 65.7),
155 (2017, 10, 52.5),
156 (2017, 11, 49.0),
157 (2017, 12, 34.4),
158 (2018, 1, 38.1),
159 (2018, 2, 37.5),
160 (2018, 3, 45.4),
161 (2018, 4, 54.6),
162 (2018, 5, 64.0),
163 (2018, 6, 74.9),
164 (2018, 7, 82.5),
165 (2018, 8, 78.1),
166 (2018, 9, 71.9),
167 (2018, 10, 53.2),
168 (2018, 11, 39.7),
169 (2018, 12, 33.6),
170 ];
171 #[test]
entry_point()172 fn entry_point() {
173 main().unwrap()
174 }
175