Contents
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
use crate::element::{Circle, DynElement, IntoDynElement, PathElement};
use crate::style::ShapeStyle;
use plotters_backend::DrawingBackend;
use std::marker::PhantomData;
/**
The line series object, which takes an iterator of data points in guest coordinate system
and creates appropriate lines and points with the given style.
# Example
```
use plotters::prelude::*;
let x_values = [0.0f64, 1., 2., 3., 4.];
let drawing_area = SVGBackend::new("line_series_point_size.svg", (300, 200)).into_drawing_area();
drawing_area.fill(&WHITE).unwrap();
let mut chart_builder = ChartBuilder::on(&drawing_area);
chart_builder.margin(10).set_left_and_bottom_label_area_size(20);
let mut chart_context = chart_builder.build_cartesian_2d(0.0..4.0, 0.0..3.0).unwrap();
chart_context.configure_mesh().draw().unwrap();
chart_context.draw_series(LineSeries::new(x_values.map(|x| (x, 0.3 * x)), BLACK)).unwrap();
chart_context.draw_series(LineSeries::new(x_values.map(|x| (x, 2.5 - 0.05 * x * x)), RED)
.point_size(5)).unwrap();
chart_context.draw_series(LineSeries::new(x_values.map(|x| (x, 2. - 0.1 * x * x)), BLUE.filled())
.point_size(4)).unwrap();
```
The result is a chart with three line series; two of them have their data points highlighted:
![](https://cdn.jsdelivr.net/gh/facorread/plotters-doc-data@64e0a28/apidoc/line_series_point_size.svg)
*/
pub struct LineSeries<DB: DrawingBackend, Coord> {
style: ShapeStyle,
data: Vec<Coord>,
point_idx: usize,
point_size: u32,
phantom: PhantomData<DB>,
}
impl<DB: DrawingBackend, Coord: Clone + 'static> Iterator for LineSeries<DB, Coord> {
type Item = DynElement<'static, DB, Coord>;
fn next(&mut self) -> Option<Self::Item> {
if !self.data.is_empty() {
if self.point_size > 0 && self.point_idx < self.data.len() {
let idx = self.point_idx;
self.point_idx += 1;
return Some(
Circle::new(self.data[idx].clone(), self.point_size, self.style.clone())
.into_dyn(),
);
}
let mut data = vec![];
std::mem::swap(&mut self.data, &mut data);
Some(PathElement::new(data, self.style.clone()).into_dyn())
} else {
None
}
}
}
impl<DB: DrawingBackend, Coord> LineSeries<DB, Coord> {
/**
Creates a new line series based on a data iterator and a given style.
See [`LineSeries`] for more information and examples.
*/
pub fn new<I: IntoIterator<Item = Coord>, S: Into<ShapeStyle>>(iter: I, style: S) -> Self {
Self {
style: style.into(),
data: iter.into_iter().collect(),
point_size: 0,
point_idx: 0,
phantom: PhantomData,
}
}
/**
Sets the size of the points in the series, in pixels.
See [`LineSeries`] for more information and examples.
*/
pub fn point_size(mut self, size: u32) -> Self {
self.point_size = size;
self
}
}
#[cfg(test)]
mod test {
use crate::prelude::*;
#[test]
fn test_line_series() {
let drawing_area = create_mocked_drawing_area(200, 200, |m| {
m.check_draw_path(|c, s, path| {
assert_eq!(c, RED.to_rgba());
assert_eq!(s, 3);
for i in 0..100 {
assert_eq!(path[i], (i as i32 * 2, 200 - i as i32 * 2 - 1));
}
});
m.drop_check(|b| {
assert_eq!(b.num_draw_path_call, 1);
assert_eq!(b.draw_count, 1);
});
});
let mut chart = ChartBuilder::on(&drawing_area)
.build_cartesian_2d(0..100, 0..100)
.expect("Build chart error");
chart
.draw_series(LineSeries::new(
(0..100).map(|x| (x, x)),
Into::<ShapeStyle>::into(&RED).stroke_width(3),
))
.expect("Drawing Error");
}
}