Skip to content

[BUG] Out-of-range data is deformed (line slopes changed) #689

Open

Description

@werner291

Describe the bug

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:

Image

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"] }

Activity

  1. werner291 commented on Mar 27, 2025

    @werner291
    Author

    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.)

  2. werner291 commented on Mar 27, 2025

    @werner291
    Author

    Alternatively, perhaps consider letting the backend handle clipping?

    SVG, for instance, offers the <clipPath> and <mask> elements

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions