1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
//! Definition of the Plot struct
//!
use std::f64;
use failure::Error;
use cairo::Context;
use palette::Rgba;
use ::{canvas, chart, frame, text};
/// ## Plot
///
/// Determines a single plot. A plot is part of a figure, and contains a canvas where things are
/// drawn. By default, there is some space around the canvas, to make space for labels, ticks, and
/// tick labels.
#[derive(Clone, Debug)]
pub struct Plot {
title: text::Text,
color: Rgba,
local_frame: frame::Frame,
canvas: canvas::Canvas,
}
impl Plot {
/// Create and return a plot
pub fn new() -> Plot {
let mut local_frame = frame::Frame::new();
local_frame.display_border(true);
local_frame.set_thickness(0.001);
Plot {
title: text::Text::new(""),
color: Rgba::new(240.0/255.0, 242.0/255.0, 255.0/255.0, 1.0),
local_frame: local_frame,
canvas: canvas::Canvas::new(),
}
}
/// Set plot title
pub fn set_title(mut self, title: &str) -> Self {
self.title.set_content(title);
self
}
/// Set plot background color. **Note**: This is different from the canvas background color.
pub fn set_color(mut self, color: Rgba) -> Self {
self.color = color;
self
}
/// Set the plot background color. **Note**: This is different from the canvas background color.
pub fn set_color_rgb(mut self, red: f32, green: f32, blue: f32) -> Self {
let red = red.max(0.0);
let red = red.min(1.0);
let green = green.max(0.0);
let green = green.min(1.0);
let blue = blue.max(0.0);
let blue = blue.min(1.0);
self.color = Rgba::new(red, green, blue, 1.0);
self
}
/// Set the plot background color. **Note**: This is different from the canvas background color.
pub fn set_color_rgba(mut self, red: f32, green: f32, blue: f32, alpha: f32) -> Self {
let red = red.max(0.0);
let red = red.min(1.0);
let green = green.max(0.0);
let green = green.min(1.0);
let blue = blue.max(0.0);
let blue = blue.min(1.0);
let alpha = alpha.max(0.0);
let alpha = alpha.min(1.0);
self.color = Rgba::new(red, green, blue, alpha);
self
}
/// Set local plot coordinates, relative to the figure it belongs to.
///
/// A value of 0.0 is the minimum figure coordinate, and a value of 1.0 is the maximum figure
/// coordinate.
pub fn set_local_frame(mut self, left: f64, right: f64, bottom: f64, top: f64) -> Self {
self.local_frame.set(left, right, bottom, top);
self
}
/// Set the data range of the plot
///
/// *Note*:
/// This is a soft suggestion, and can be overwritten before the final result for aestethics.
/// See more [here](struct.Canvas.html#method.set_data_range).
pub fn set_data_range(mut self, x_min: f64, x_max: f64, y_min: f64, y_max: f64) -> Self {
self.canvas.set_data_range(x_min, x_max, y_min, y_max);
self
}
/// Set the horisontal data range of the plot
///
/// *Note*:
/// This is a soft suggestion, and can be overwritten before the final result for aestethics.
/// See more [here](struct.Canvas.html#method.set_data_range).
pub fn set_x_range(mut self, x_min: f64, x_max: f64) -> Self {
self.canvas.set_x_range(x_min, x_max);
self
}
/// Set the vertical data range of the plot
///
/// *Note*:
/// This is a soft suggestion, and can be overwritten before the final result for aestethics.
/// See more [here](struct.Canvas.html#method.set_data_range).
pub fn set_y_range(mut self, y_min: f64, y_max: f64) -> Self {
self.canvas.set_y_range(y_min, y_max);
self
}
/// Set the left horisontal data range end of the plot
///
/// *Note*:
/// This is a soft suggestion, and can be overwritten before the final result for aestethics.
/// See more [here](struct.Canvas.html#method.set_data_range).
pub fn set_x_min(mut self, x_min: f64) -> Self {
self.canvas.set_x_min(x_min);
self
}
/// Set the right horisontal data range end of the plot
///
/// *Note*:
/// This is a soft suggestion, and can be overwritten before the final result for aestethics.
/// See more [here](struct.Canvas.html#method.set_data_range).
pub fn set_x_max(mut self, x_max: f64) -> Self {
self.canvas.set_x_max(x_max);
self
}
/// Set the bottom vertical data range end of the plot
///
/// *Note*:
/// This is a soft suggestion, and can be overwritten before the final result for aestethics.
/// See more [here](struct.Canvas.html#method.set_data_range).
pub fn set_y_min(mut self, y_min: f64) -> Self {
self.canvas.set_y_min(y_min);
self
}
/// Set the top vertical data range end of the plot
///
/// *Note*:
/// This is a soft suggestion, and can be overwritten before the final result for aestethics.
/// See more [here](struct.Canvas.html#method.set_data_range).
pub fn set_y_max(mut self, y_max: f64) -> Self {
self.canvas.set_y_max(y_max);
self
}
/// Whether or not to display a border around the plot
pub fn display_border(mut self, val: bool) -> Self {
self.local_frame.display_border(val);
self
}
/// Set the color of the border around the plot
pub fn set_border_color(mut self, color: Rgba) -> Self {
self.local_frame.set_color(color);
self
}
/// Set the line width of the border around the plot
pub fn set_border_thickness(mut self, val: f64) -> Self {
self.local_frame.set_thickness(val);
self
}
/// Add a canvas to the plot
pub fn add(mut self, chart: chart::Chart) -> Self {
self.canvas.add_chart(chart);
self
}
fn scale_size(&mut self, factor: f64) {
self.local_frame.scale_size(factor);
self.title.scale_size(factor);
}
/// This method is called by figure after all plots are added, and all plot adjustment is made.
/// This happend right before the plot is drawn on the figure.
///
/// The function scales various elements within the plot, and calls a similar plot for its
/// canvasses.
pub fn fit(&mut self) -> Result<(), Error> {
let scale_factor = self.local_frame.diag_len() / 2f64.sqrt();
self.scale_size(scale_factor);
self.canvas.fit(&self.local_frame)?;
Ok(())
}
/// Do the actual drawing of the plot
pub fn draw(&self, cr: &Context, fig_rel_height: f64, fig_rel_width: f64) {
// Fill background
cr.set_source_rgba(self.color.red as f64, self.color.green as f64, self.color.blue as f64,
self.color.alpha as f64);
cr.rectangle(self.local_frame.left(), self.local_frame.bottom(),
self.local_frame.width(), self.local_frame.height());
cr.fill();
// Draw frame border
self.local_frame.draw(cr, fig_rel_height, fig_rel_width);
// Draw canvas
self.canvas.draw(cr, fig_rel_height, fig_rel_width);
}
}