plotters-rs / plotters

A rust drawing library for high quality data plotting for both WASM and native, statically and realtimely 🦀 📈🚀
https://plotters-rs.github.io/home/
MIT License
3.91k stars 280 forks source link

Fix WithKeyPoints for f32 / f64 ranges #653

Closed oldgalileo closed 2 weeks ago

oldgalileo commented 1 month ago

Allow using f32 key point ranges when constructing a Cartesian2d chart:

fn main() -> Result<_> {
    // Chart setup ...
    let mut chart = ChartBuilder::on(&top)
        .x_label_area_size(20)
        .y_label_area_size(40)
        .build_cartesian_2d(
            (0f32..10f32)
                .with_key_points((0f32..10f32)
                    .step(0.5)
                    .values()
                    .map(|x| x * PI).collect()),
            0f32..2.5f32
        ).unwrap();

    chart.configure_mesh()
        .x_labels(5)
        .y_labels(2)
        .draw()?;

    // Draw stuff ...
}

This code fails to compile, and will complain with the following:

error[E0599]: the method `configure_mesh` exists for struct `ChartContext<'_, BitMapBackend<'_>, Cartesian2d<WithKeyPoints<RangedCoordf32>, RangedCoordf32>>`, but its trait bounds were not satisfied
  --> src/bin/plotting.rs:30:11
   |
30 |     chart.configure_mesh()
   |           ^^^^^^^^^^^^^^ method cannot be called due to unsatisfied trait bounds
   |
  ::: $HOME/.cargo/registry/src/index.crates.io-6f17d22bba15001f/plotters-0.3.7/src/coord/ranged1d/combinators/ckps.rs:16:1
   |
16 | pub struct WithKeyPoints<Inner: Ranged> {
   | --------------------------------------- doesn't satisfy `<_ as Ranged>::FormatOption = DefaultFormatting` or `WithKeyPoints<RangedCoordf32>: ValueFormatter<f32>`
   |
   = note: the following trait bounds were not satisfied:
           `<WithKeyPoints<RangedCoordf32> as plotters::prelude::Ranged>::FormatOption = DefaultFormatting`
           which is required by `WithKeyPoints<RangedCoordf32>: ValueFormatter<f32>`

My change addresses the immediate issue, although I suspect there's a more elegant fix here. Couldn't find a quick fix for the issue of a default implementation not existing when T::FormatOption != DefaultFormatting, but it occurred to me that maybe a macro at least would be better? Although conversely it's only for f32 and f64 at the moment so I'm not sure.