Open mlange-42 opened 4 years ago
Hmm, this is something unsupported yet. You just spotted the root cause of this.
The cc
variable doesn't have a valid type, since it can not be ChartContext<RangedCoord<_, :RangedCoordf64>>
and ChartContext<'_, _, RangedCoord<_, LogCoord<f64>>>
at the same time.
One way to address that (not only in Rust but also other programming languages) is using dynamic dispatch, which is, in Rust term, a trait object. However, Plotters doesn't have a trait for those two types, so the compiler don't know how to do that.
One work around is to use static dispatch instead (use template function).
Hope this is helpful, and dynamic dispatch on charts with same data type should be supported. Thanks again to come up with this problem, hopefully Plotters will support dynamic dispatch i the future release.
Thanks for trying Plotters and hope you enjoy both the crate and Rust language.
I am changing this issue to a feature request if you don't mind.
Cheers!
Many thanks for the reply!
My solution so far was complete doubling of the plotting code, as you can see here: https://github.com/mlange-42/easy_graph/blob/master/src/ui/chart.rs#L406
Not really nice, but good to know that my limited Rust experience was not the sole reason.
And yes, I really enjoy Rust as well as plotters.
doubling of the plotting code
Yep, you got that. To make it nicer, you can make duplicated code reusable with a template function.
That is very often used trick in both Rust and C++ I believe. Since in C++ it's also not recommended to frequently use dynamic dispatch, or AKA virtual method functions.
For anyone else running into this issue, the trait bounds I ended up with to get a linear or logarithmic Y-axis were:
use std::convert::identity;
use std::ops::Range;
use std::fmt::Debug;
use plotters::chart::ChartBuilder;
use plotters::coord::combinators::IntoLogRange;
use plotters::coord::ranged1d::AsRangedCoord;
use plotters::coord::ranged1d::DefaultFormatting;
use plotters::coord::ranged1d::Ranged;
use plotters::coord::ranged1d::ValueFormatter;
pub fn plot_linear() {
plot(identity);
}
pub fn plot_logarithmic() {
plot(IntoLogRange::log_scale);
}
fn plot<S>(
scale: fn(Range<u64>) -> S,
)
where
S: AsRangedCoord<Value = u64>,
S::CoordDescType: ValueFormatter<u64> + Ranged<FormatOption = DefaultFormatting>,
S::Value: Debug,
{
ChartBuilder::on(...)
.build_cartesian_2d(..., scale(0u64..100u64))?;
}
If the chart is defined to accept same data type, even though the axis is using different types of decorator, those chart types should be cvt into a trait object.
==== Original issue (one of valid use case)
First, many thanks for providing this great library!
Learning Rust for 2 weeks now and not really grasping the type system yet, this may be more of a Rust question than a plotters question.
I try to create a chart context with optional log-scaled y axis:
Now, my problem is that this doesn't compile due to:
When I use the condition in
build_ranged
I get a type mismatch between
std::ops::Range
andplotters::coord::logarithmic::LogRange
.I understand that I probably have to specify an explicit type for
cc
, probably with somedyn Trait
in ChartContext's generics. However, due to my still very limited Rust experience, I can't get it to work.Many thanks for your help!