You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[BUG] Out-of-range data is deformed (line slopes changed) #689
I'm plotting a simple test plot of the equation y = x^2.
// Simple chart setup for testing
let root = SVGBackend::new("test.svg", (640, 480)).into_drawing_area();
root.fill(&WHITE).unwrap();
let mut chart = ChartBuilder::on(&root)
.caption("Test Chart", ("sans-serif", 50).into_font())
.x_label_area_size(30)
.y_label_area_size(30)
.margin(5)
.build_cartesian_2d(0..10, 0..10)
.unwrap();
chart.configure_mesh().draw().unwrap();
chart
.draw_series(LineSeries::new(
(0..10).map(|x| (x, x * x)),
&RED,
))
.unwrap();
root.present().expect("Unable to write result to file");
This produces the following plot:
As you can see, the data goes out of range. What I would expect is that either:
The line crosses outside the chart rectangle.
The line is clipped off at the boundary
The code produces an error/panic
However, with the current implementation, the slope of the line is instead adjusted between x=3 and x=4, and for x > 4, it just goes flat against the top boundary. I consider this a severe deformation of the input data.
Sure, in this example I artificially created some data that goes out-of-bounds, but with datasets in the wild, you might accidentally create artifacts in the plot that may lead to incorrect conclusions being drawn.
The root cause is this:
/// Used for 2d coordinate transformations.
pub struct BackendCoordOnly;
impl CoordMapper for BackendCoordOnly {
type Output = BackendCoord;
fn map<CT: CoordTranslate>(coord_trans: &CT, from: &CT::From, rect: &Rect) -> BackendCoord {
rect.truncate(coord_trans.translate(from))
}
}
Unfortunately, the truncation behavior here is a bit naïve, as this also applies to the endpoints of lines.
Version Information
plotters = { version = "0.3.7", default-features = false, features = ["svg_backend", "all_series","colormaps","full_palette","histogram"] }
Personally, I'd actually prefer to just not truncate the coordinates at all, something like:
/// Used for 2d coordinate transformations.
pub struct BackendCoordOnly;
impl CoordMapper for BackendCoordOnly {
type Output = BackendCoord;
fn map<CT: CoordTranslate>(coord_trans: &CT, from: &CT::From, rect: &Rect) -> BackendCoord {
coord_trans.translate(from) // note removed call to "truncate"
}
}
The whole way I discovered this bug in the first place was because I was trying to draw some text outside the bounds of the chart (underneath the X-axis) and was very confused as to why the text would not go further down. (Only the text anchor is clipped to the rectangle btw, the text itself happily crosses outside.)
Activity
werner291 commentedon Mar 27, 2025
Personally, I'd actually prefer to just not truncate the coordinates at all, something like:
The whole way I discovered this bug in the first place was because I was trying to draw some text outside the bounds of the chart (underneath the X-axis) and was very confused as to why the text would not go further down. (Only the text anchor is clipped to the rectangle btw, the text itself happily crosses outside.)
werner291 commentedon Mar 27, 2025
Alternatively, perhaps consider letting the backend handle clipping?
SVG, for instance, offers the
<clipPath>and<mask>elements