I have this wrapper object, which is doing its job:
use std::error::Error;
use std::time::Duration;
use plotters::backend::BitMapBackend;
use plotters::chart::ChartContext;
use plotters::coord::types::RangedCoordu64;
use plotters::element::EmptyElement;
use plotters::prelude::{Cartesian2d, Circle, LineSeries, PointSeries, RGBColor, Text, BLUE, RED};
use plotters::style::IntoFont;
use crate::BrightTemp;
pub struct Plotter<'a> {
inner: ChartContext<'a, BitMapBackend<'a>, Cartesian2d<RangedCoordu64, RangedCoordu64>>,
}
impl Plotter<'_> {
pub fn plot(&mut self, items: &[(Duration, BrightTemp)]) -> Result<(), Box<dyn Error>> {
self.plot_series_and_dots(
items
.iter()
.filter_map(|(t, b)| {
b.brightness()
.map(|brightness| (u64::from(brightness), t.as_secs()))
})
.collect(),
RED,
"Brightness",
)?;
self.plot_series_and_dots(
items
.iter()
.filter_map(|(t, b)| {
b.color_temperature()
.map(|color_temperature| (u64::from(color_temperature), t.as_secs()))
})
.collect(),
BLUE,
"Color temperature",
)?;
Ok(())
}
fn plot_series_and_dots(
&mut self,
items: Vec<(u64, u64)>,
style: RGBColor,
label: &str,
) -> Result<(), Box<dyn Error>> {
self.plot_series(items.clone(), style, label)?;
self.plot_dots(items, style)
}
/// Draw a line series.
fn plot_series(
&mut self,
items: Vec<(u64, u64)>,
style: RGBColor,
label: &str,
) -> Result<(), Box<dyn Error>> {
self.inner
.draw_series(LineSeries::new(items, style))?
.label(label);
Ok(())
}
/// Draw a point series.
fn plot_dots(&mut self, items: Vec<(u64, u64)>, style: RGBColor) -> Result<(), Box<dyn Error>> {
self.inner
.draw_series(PointSeries::of_element(items, 5, style, &|c, s, st| {
EmptyElement::at(c) // We want to construct a composed element on-the-fly
+ Circle::new((0, 0), s, st.filled()) // At this point, the new pixel coordinate is established
+ Text::new(format!("{c:?}"), (10, 0), ("sans-serif", 10).into_font())
}))?;
Ok(())
}
}
impl<'a> From<ChartContext<'a, BitMapBackend<'a>, Cartesian2d<RangedCoordu64, RangedCoordu64>>>
for Plotter<'a>
{
fn from(
inner: ChartContext<'a, BitMapBackend<'a>, Cartesian2d<RangedCoordu64, RangedCoordu64>>,
) -> Self {
Self { inner }
}
}
impl<'a> From<Plotter<'a>>
for ChartContext<'a, BitMapBackend<'a>, Cartesian2d<RangedCoordu64, RangedCoordu64>>
{
fn from(plotter: Plotter<'a>) -> Self {
plotter.inner
}
}
However, I'd prefer implementing the respective methods on an extension trait of ChartContext<'_, DB, CT>
instead.
However, I cannot find out, how to resolve the required trait bounds for plot_dots()
:
use plotters::element::{Circle, EmptyElement, PointCollection, Text};
use plotters::prelude::{
ChartContext, CoordTranslate, DrawingBackend, DynElement, IntoFont, LineSeries, PointSeries,
RGBColor,
};
use std::error::Error;
pub trait ChartContextExt {
fn plot_series_and_dots(
&mut self,
items: Vec<(u64, u64)>,
style: RGBColor,
label: &str,
) -> Result<(), Box<dyn Error>> {
self.plot_series(items.clone(), style, label)?;
self.plot_dots(items, style)
}
/// Draw a line series.
fn plot_series(
&mut self,
items: Vec<(u64, u64)>,
style: RGBColor,
label: &str,
) -> Result<(), Box<dyn Error>>;
/// Draw a point series.
fn plot_dots(&mut self, items: Vec<(u64, u64)>, style: RGBColor) -> Result<(), Box<dyn Error>>;
}
impl<DB, CT> ChartContextExt for ChartContext<'_, DB, CT>
where
DB: DrawingBackend,
CT: CoordTranslate,
<DB as DrawingBackend>::ErrorType: 'static,
for<'b> &'b DynElement<'static, DB, (u64, u64)>:
PointCollection<'b, <CT as CoordTranslate>::From>,
{
/// Draw a line series.
fn plot_series(
&mut self,
items: Vec<(u64, u64)>,
style: RGBColor,
label: &str,
) -> Result<(), Box<dyn Error>> {
self.draw_series(LineSeries::new(items, style))?
.label(label);
Ok(())
}
/// Draw a point series.
fn plot_dots(&mut self, items: Vec<(u64, u64)>, style: RGBColor) -> Result<(), Box<dyn Error>> {
self.draw_series(PointSeries::of_element(items, 5, style, &|c, s, st| {
EmptyElement::at(c) // We want to construct a composed element on-the-fly
+ Circle::new((0, 0), s, st.filled()) // At this point, the new pixel coordinate is established
+ Text::new(format!("{c:?}"), (10, 0), ("sans-serif", 10).into_font())
}))?;
Ok(())
}
}
I cannot get rid of the error:
~/RustroverProjects/smik-testsuite> cargo build 2024-12-05T15:43:38
Compiling smik-testsuite v0.1.0 (/home/neumann/RustroverProjects/smik-testsuite)
error[E0277]: the trait bound `ComposedElement<(u64, u64), _, Circle<(i32, i32), {integer}>, Text<'_, (i32, i32), String>>: Borrow<DynElement<'static, DB, (u64, u64)>>` is not satisfied
--> src/plotting/chart_context_ext.rs:53:14
|
53 | self.draw_series(PointSeries::of_element(items, 5, style, &|c, s, st| {
| ^^^^^^^^^^^ the trait `Borrow<DynElement<'static, DB, (u64, u64)>>` is not implemented for `ComposedElement<(u64, u64), _, Circle<(i32, i32), {integer}>, Text<'_, (i32, i32), String>>`
|
note: required by a bound in `ChartContext::<'a, DB, CT>::draw_series`
--> /home/neumann/.cargo/registry/src/index.crates.io-6f17d22bba15001f/plotters-0.3.7/src/chart/context.rs:128:12
|
120 | pub fn draw_series<B, E, R, S>(
| ----------- required by a bound in this associated function
...
128 | R: Borrow<E>,
| ^^^^^^^^^ required by this bound in `ChartContext::<'a, DB, CT>::draw_series`
For more information about this error, try `rustc --explain E0277`.
error: could not compile `smik-testsuite` (lib) due to 1 previous error
~/RustroverProjects/smik-testsuite>
Can somebody help me out here?