1use plotters::prelude::*;
2
3use chrono::{TimeZone, Utc};
4
5use std::error::Error;
6
7const OUT_FILE_NAME: &'static str = "plotters-doc-data/slc-temp.png";
8fn 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
61const 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]
172fn entry_point() {
173 main().unwrap()
174}
175