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
use std;
use std::f64;
use svg;
use svg::Node;
use representation::Representation;
use axis;
use svg_render;
use text_render;
#[derive(Default)]
pub struct View<'a> {
pub representations: Vec<&'a Representation>,
x_range: Option<axis::Range>,
y_range: Option<axis::Range>,
x_label: Option<String>,
y_label: Option<String>,
}
impl<'a> View<'a> {
pub fn new() -> View<'a> {
View {
representations: vec![],
x_range: None,
y_range: None,
x_label: None,
y_label: None,
}
}
pub fn add(mut self, repr: &'a Representation) -> Self {
self.representations.push(repr);
self
}
pub fn x_range(mut self, min: f64, max: f64) -> Self {
self.x_range = Some(axis::Range::new(min, max));
self
}
pub fn y_range(mut self, min: f64, max: f64) -> Self {
self.y_range = Some(axis::Range::new(min, max));
self
}
pub fn x_label<T>(mut self, value: T) -> Self
where
T: Into<String>,
{
self.x_label = Some(value.into());
self
}
pub fn y_label<T>(mut self, value: T) -> Self
where
T: Into<String>,
{
self.y_label = Some(value.into());
self
}
fn default_x_range(&self) -> axis::Range {
let mut x_min = f64::INFINITY;
let mut x_max = f64::NEG_INFINITY;
for repr in &self.representations {
let (this_x_min, this_x_max) = repr.range(0);
x_min = x_min.min(this_x_min);
x_max = x_max.max(this_x_max);
}
axis::Range::new(x_min, x_max)
}
fn default_y_range(&self) -> axis::Range {
let mut y_min = f64::INFINITY;
let mut y_max = f64::NEG_INFINITY;
for repr in &self.representations {
let (this_y_min, this_y_max) = repr.range(1);
y_min = y_min.min(this_y_min);
y_max = y_max.max(this_y_max);
}
axis::Range::new(y_min, y_max)
}
fn create_axes(&self) -> (axis::Axis, axis::Axis) {
let default_x_range = self.default_x_range();
let x_range = self.x_range.as_ref().unwrap_or(&default_x_range);
let default_y_range = self.default_y_range();
let y_range = self.y_range.as_ref().unwrap_or(&default_y_range);
let default_x_label = "".to_string();
let x_label: String = self.x_label.clone().unwrap_or(default_x_label);
let default_y_label = "".to_string();
let y_label: String = self.y_label.clone().unwrap_or(default_y_label);
let x_axis = axis::Axis::new(x_range.lower, x_range.upper).label(x_label);
let y_axis = axis::Axis::new(y_range.lower, y_range.upper).label(y_label);
(x_axis, y_axis)
}
pub fn to_svg(&self, face_width: f64, face_height: f64) -> svg::node::element::Group {
let mut view_group = svg::node::element::Group::new();
let (x_axis, y_axis) = self.create_axes();
for repr in &self.representations {
let repr_group = repr.to_svg(&x_axis, &y_axis, face_width, face_height);
view_group.append(repr_group);
}
view_group.append(svg_render::draw_x_axis(&x_axis, face_width));
view_group.append(svg_render::draw_y_axis(&y_axis, face_height));
view_group
}
pub fn to_text(&self, face_width: u32, face_height: u32) -> String {
let (x_axis, y_axis) = self.create_axes();
let (y_axis_string, longest_y_label_width) =
text_render::render_y_axis_strings(&y_axis, face_height);
let (x_axis_string, start_offset) = text_render::render_x_axis_strings(&x_axis, face_width);
let left_gutter_width = std::cmp::max(
longest_y_label_width as i32 + 3,
start_offset.wrapping_neg(),
) as u32;
let view_width = face_width + 1 + left_gutter_width + 1;
let view_height = face_height + 4;
let blank: Vec<String> = (0..view_height)
.map(|_| (0..view_width).map(|_| ' ').collect())
.collect();
let mut view_string = blank.join("\n");
for repr in &self.representations {
let face_string = repr.to_text(&x_axis, &y_axis, face_width, face_height);
view_string =
text_render::overlay(&view_string, &face_string, left_gutter_width as i32 + 1, 0);
}
let view_string = text_render::overlay(
&view_string,
&y_axis_string,
left_gutter_width as i32 - 2 - longest_y_label_width,
0,
);
let view_string = text_render::overlay(
&view_string,
&x_axis_string,
left_gutter_width as i32,
face_height as i32,
);
view_string
}
}