milliams / plotlib

@@ -98,11 +98,20 @@
Loading
98 98
    where
99 99
        P: AsRef<Path>,
100 100
    {
101 -
        match path.as_ref().extension().and_then(OsStr::to_str) {
102 -
            Some("svg") => match svg::save(path, &self.to_svg()?) {
101 +
        let path = path.as_ref();
102 +
        match path.extension().and_then(OsStr::to_str) {
103 +
            Some("svg") => {
104 +
                if let Some(parent) = path.parent() {
105 +
                    if !parent.exists() {
106 +
                        std::fs::create_dir_all(parent)?;
107 +
                    }
108 +
                }
109 +
110 +
                match svg::save(&path, &self.to_svg()?) {
103 111
                    Ok(ok) => Ok(ok),
104 112
                    Err(error) => Err(errors::Error::FailedToSave(error))
105 113
                }
114 +
            },
106 115
            _ => Ok(()),
107 116
        }
108 117
    }

@@ -167,7 +167,7 @@
Loading
167 167
168 168
        let (x_axis, y_axis) = self.create_axes()?;
169 169
170 -
        let (legend_x, mut legend_y) = (face_width - 100., -face_height);
170 +
        let (legend_x, mut legend_y) = (face_width - 100., -23.);
171 171
        if let Some(grid) = &self.grid {
172 172
            view_group.append(svg_render::draw_grid(
173 173
                GridType::Both(grid),
@@ -186,7 +186,7 @@
Loading
186 186
                    "transform",
187 187
                    format!("translate({}, {})", legend_x, legend_y),
188 188
                ));
189 -
                legend_y += 18.;
189 +
                legend_y -= 18.;
190 190
            }
191 191
        }
192 192

@@ -162,19 +162,25 @@
Loading
162 162
        ticks.append(tick_mark);
163 163
164 164
        let tick_label = node::element::Text::new()
165 -
            .set("x", tick_pos)
166 -
            .set("y", 20)
167 165
            .set("text-anchor", "middle")
168 -
            .set("font-size", 12)
166 +
            .set("x", 0)
167 +
            .set("y", 0)
168 +
            .set("font-size", 9)
169 +
            .set("transform", "rotate(10)")
169 170
            .add(node::Text::new(tick.to_owned()));
170 -
        labels.append(tick_label);
171 +
172 +
        let tick_g = node::element::Group::new()
173 +
            .set("transform", format!("translate({}, {})", tick_pos, 20))
174 +
            .add(tick_label);
175 +
176 +
        labels.append(tick_g);
171 177
    }
172 178
173 179
    let label = node::element::Text::new()
174 180
        .set("x", face_width / 2.)
175 181
        .set("y", 30)
176 182
        .set("text-anchor", "middle")
177 -
        .set("font-size", 12)
183 +
        .set("font-size", 9)
178 184
        .add(node::Text::new(a.get_label()));
179 185
180 186
    node::element::Group::new()
@@ -197,48 +203,168 @@
Loading
197 203
    for &(x, y) in s {
198 204
        let x_pos = value_to_face_offset(x, x_axis, face_width);
199 205
        let y_pos = -value_to_face_offset(y, y_axis, face_height);
200 -
        let radius = f64::from(style.get_size());
201 -
        match style.get_marker() {
202 -
            style::PointMarker::Circle => {
203 -
                group.append(
204 -
                    node::element::Circle::new()
205 -
                        .set("cx", x_pos)
206 -
                        .set("cy", y_pos)
207 -
                        .set("r", radius)
208 -
                        .set("fill", style.get_colour()),
209 -
                );
210 -
            }
211 -
            style::PointMarker::Square => {
212 -
                group.append(
213 -
                    node::element::Rectangle::new()
214 -
                        .set("x", x_pos - radius)
215 -
                        .set("y", y_pos - radius)
216 -
                        .set("width", 2. * radius)
217 -
                        .set("height", 2. * radius)
218 -
                        .set("fill", style.get_colour()),
219 -
                );
220 -
            }
221 -
            style::PointMarker::Cross => {
222 -
                let path = node::element::path::Data::new()
223 -
                    .move_to((x_pos - radius, y_pos - radius))
224 -
                    .line_by((radius * 2., radius * 2.))
225 -
                    .move_by((-radius * 2., 0))
226 -
                    .line_by((radius * 2., -radius * 2.))
227 -
                    .close();
228 -
                group.append(
229 -
                    node::element::Path::new()
230 -
                        .set("fill", "none")
231 -
                        .set("stroke", style.get_colour())
232 -
                        .set("stroke-width", 2)
233 -
                        .set("d", path),
234 -
                );
235 -
            }
236 -
        };
206 +
        let mark = draw_marker(x_pos, y_pos, style);
207 +
        group.append(mark);
237 208
    }
238 209
239 210
    group
240 211
}
241 212
213 +
pub fn draw_marker(x_pos: f64, y_pos: f64, style: &style::PointStyle) -> node::element::Group  {
214 +
    let radius = f64::from(style.get_size());
215 +
    let mut group = node::element::Group::new();
216 +
    match style.get_marker() {
217 +
        style::PointMarker::Circle => {
218 +
            group.append(
219 +
                node::element::Circle::new()
220 +
                    .set("cx", x_pos)
221 +
                    .set("cy", y_pos)
222 +
                    .set("r", radius)
223 +
                    .set("fill", style.get_colour()),
224 +
            );
225 +
        }
226 +
        style::PointMarker::Square => {
227 +
            group.append(
228 +
                node::element::Rectangle::new()
229 +
                    .set("x", x_pos - radius)
230 +
                    .set("y", y_pos - radius)
231 +
                    .set("width", 2. * radius)
232 +
                    .set("height", 2. * radius)
233 +
                    .set("fill", style.get_colour()),
234 +
            );
235 +
        }
236 +
        style::PointMarker::Cross => {
237 +
            let data = node::element::path::Data::new()
238 +
                .move_to((-radius, -radius))
239 +
                .line_to(( radius,  radius))
240 +
                .move_to((-radius,  radius))
241 +
                .line_to(( radius, -radius))
242 +
                .close();
243 +
244 +
            let path = node::element::Path::new()
245 +
                .set("fill", "none")
246 +
                .set("stroke", style.get_colour())
247 +
                .set("stroke-width", 1)
248 +
                .set("d", data);
249 +
250 +
            let mut translation = node::element::Group::new()
251 +
                .set("transform", format!("translate({},{})", x_pos, y_pos));
252 +
            translation.append(path);
253 +
254 +
            let mut wrap = node::element::Group::new();
255 +
            wrap.append(translation);
256 +
257 +
            group.append(wrap);
258 +
        }
259 +
        style::PointMarker::Plus => {
260 +
            let data = node::element::path::Data::new()
261 +
                .move_to((-radius, 0))
262 +
                .horizontal_line_to(radius)
263 +
                .move_to((0, - radius))
264 +
                .vertical_line_to(radius)
265 +
                .close();
266 +
267 +
            let path = node::element::Path::new()
268 +
                .set("fill", "none")
269 +
                .set("stroke", style.get_colour())
270 +
                .set("stroke-width", 1)
271 +
                .set("d", data);
272 +
273 +
            let mut translation = node::element::Group::new()
274 +
                .set("transform", format!("translate({},{})", x_pos, y_pos));
275 +
            translation.append(path);
276 +
277 +
            let mut wrap = node::element::Group::new();
278 +
            wrap.append(translation);
279 +
280 +
            group.append(wrap);
281 +
        }
282 +
        style::PointMarker::Star => {
283 +
            let data = node::element::path::Data::new()
284 +
                .move_to((-radius, 0))
285 +
                .horizontal_line_to(radius)
286 +
                .move_to((0, - radius))
287 +
                .vertical_line_to(radius)
288 +
                .move_to((-radius, -radius))
289 +
                .line_to(( radius,  radius))
290 +
                .move_to((-radius,  radius))
291 +
                .line_to(( radius, -radius))
292 +
                .close();
293 +
294 +
            let path = node::element::Path::new()
295 +
                .set("fill", "none")
296 +
                .set("stroke", style.get_colour())
297 +
                .set("stroke-width", 1)
298 +
                .set("d", data);
299 +
300 +
            let mut translation = node::element::Group::new()
301 +
                .set("transform", format!("translate({},{})", x_pos, y_pos));
302 +
            translation.append(path);
303 +
304 +
            let mut wrap = node::element::Group::new();
305 +
            wrap.append(translation);
306 +
307 +
            group.append(wrap);
308 +
        }
309 +
        style::PointMarker::Triangle => {
310 +
            let left = (-radius, 0.);
311 +
            let right= ( radius, 0.);
312 +
            let top  = (     0.,  -2.*radius);
313 +
314 +
            let points = format!("{},{} {},{} {},{}",
315 +
                                 left.0 ,left.1,
316 +
                                 right.0,right.1,
317 +
                                 top.0, top.1);
318 +
319 +
            let polygon= node::element::Polygon::new()
320 +
                .set("points", points)
321 +
                .set("fill", style.get_colour())
322 +
                .set("transform", format!("translate({},{})", x_pos, y_pos +radius));
323 +
324 +
            let mut translation = node::element::Group::new();
325 +
            translation.append(polygon);
326 +
327 +
            group.append(translation);
328 +
        },
329 +
        style::PointMarker::TriangleDown => {
330 +
            let left = (-radius, 0.);
331 +
            let right= ( radius, 0.);
332 +
            let top  = (     0.,  2.*radius);
333 +
334 +
            let points = format!("{},{} {},{} {},{}",
335 +
                                 left.0 ,left.1,
336 +
                                 right.0,right.1,
337 +
                                 top.0, top.1);
338 +
339 +
            let polygon= node::element::Polygon::new()
340 +
                .set("points", points)
341 +
                .set("fill", style.get_colour())
342 +
                .set("transform", format!("translate({},{})", x_pos, y_pos -radius));
343 +
344 +
            let mut translation = node::element::Group::new();
345 +
            translation.append(polygon);
346 +
347 +
            group.append(translation);
348 +
        },
349 +
        style::PointMarker::Diamond => {
350 +
            let r = radius;
351 +
            let points = format!("{},{} {},{} {},{} {},{}", -r,0, 0,r, r,0, 0,-r);
352 +
            let polygon= node::element::Polygon::new()
353 +
                .set("x", x_pos - radius)
354 +
                .set("y", y_pos - radius)
355 +
                .set("points", points)
356 +
                .set("fill", style.get_colour())
357 +
                .set("transform", format!("translate({},{})", x_pos, y_pos));
358 +
359 +
            let mut translation = node::element::Group::new();
360 +
            translation.append(polygon);
361 +
362 +
            group.append(translation);
363 +
        },
364 +
    };
365 +
    group
366 +
}
367 +
242 368
pub fn draw_face_bars(
243 369
    h: &repr::Histogram,
244 370
    x_axis: &axis::ContinuousAxis,

@@ -60,7 +60,7 @@
Loading
60 60
        self
61 61
    }
62 62
    pub fn get_width(&self) -> f32 {
63 -
        self.width.unwrap_or(2.0)
63 +
        self.width.unwrap_or(1.0)
64 64
    }
65 65
66 66
    pub fn linejoin<T>(mut self, value: T) -> Self
@@ -81,6 +81,11 @@
Loading
81 81
    Circle,
82 82
    Square,
83 83
    Cross,
84 +
    Plus,
85 +
    Star,
86 +
    Triangle,
87 +
    TriangleDown,
88 +
    Diamond
84 89
}
85 90
86 91
#[derive(Debug, Default, Clone)]
@@ -141,7 +146,7 @@
Loading
141 146
        self
142 147
    }
143 148
    pub fn get_size(&self) -> f32 {
144 -
        self.size.unwrap_or(5.0)
149 +
        self.size.unwrap_or(3.0)
145 150
    }
146 151
}
147 152

@@ -370,6 +370,11 @@
Loading
370 370
        style::PointMarker::Circle => '●',
371 371
        style::PointMarker::Square => '■',
372 372
        style::PointMarker::Cross => '×',
373 +
        style::PointMarker::Plus => '+',
374 +
        style::PointMarker::Star => '*',
375 +
        style::PointMarker::Triangle => '▲',
376 +
        style::PointMarker::TriangleDown => '▼',
377 +
        style::PointMarker::Diamond => '♦',
373 378
    };
374 379
375 380
    let mut face_strings: Vec<String> = vec![];

@@ -21,6 +21,7 @@
Loading
21 21
use crate::style::*;
22 22
use crate::svg_render;
23 23
use crate::text_render;
24 +
use crate::svg_render::draw_marker;
24 25
25 26
/// Representation of any plot with points in the XY plane, visualized as points and/or with lines
26 27
/// in-between.
@@ -146,7 +147,7 @@
Loading
146 147
            let legend = legend.clone();
147 148
148 149
            let mut group = node::element::Group::new();
149 -
            const FONT_SIZE: f32 = 12.0;
150 +
            const FONT_SIZE: f32 = 9.0;
150 151
151 152
            // Draw legend text
152 153
            let legend_text = node::element::Text::new()
@@ -159,7 +160,7 @@
Loading
159 160
160 161
            if let Some(ref style) = self.line_style {
161 162
                let line = node::element::Line::new()
162 -
                    .set("x1", -10)
163 +
                    .set("x1", -23)
163 164
                    .set("y1", -FONT_SIZE / 2. + 2.)
164 165
                    .set("x2", -3)
165 166
                    .set("y2", -FONT_SIZE / 2. + 2.)
@@ -168,6 +169,11 @@
Loading
168 169
                group.append(line);
169 170
            }
170 171
172 +
            if let Some(ref style) = self.point_style {
173 +
                let mark = draw_marker(-13., (-FONT_SIZE / 2. + 2.) as f64, style);
174 +
                group.append(mark);
175 +
            }
176 +
171 177
            group
172 178
        })
173 179
    }
Files Coverage
src 61.16%
tests/test_no_data.rs 100.00%
Project Totals (13 files) 61.82%

No yaml found.

Create your codecov.yml to customize your Codecov experience

Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading