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.87k stars 281 forks source link

[BUG] Invalid Coordinate Range hangs program #358

Closed cavemanloverboy closed 2 years ago

cavemanloverboy commented 2 years ago

I was plotting a line with

let mut chart = ChartBuilder::on(&root)
            .caption("Dark Energy Only", ("sans-serif", 50).into_font())
            .margin(5_u32)
            .x_label_area_size(30_u32)
            .y_label_area_size(30_u32)
            .build_cartesian_2d(age_of_universe * a0.powi(2)..0.0, 0.0_f64..1.0).unwrap();

and the program hung. Took me a few minutes and some println! debugging to realize that I had range going from a positive f64 to 0.0_f64 in age_of_universe * a0.powi(2)..0.0.

I haven't been using plotters very long so I don't know where else this may be relevant, but I think there should be some sort of check + panic/err if an invalid range is provided to a function.

facorread commented 2 years ago

I'll be happy to help with his bug.

facorread commented 2 years ago

The program compiled and ran alright when using the latest stable version of plotters, 0.3.1. Here is the source code:

use plotters::prelude::*;

fn main() {
    let root = BitMapBackend::new("example.png", (1920, 1080)).into_drawing_area();
    let mut _chart = ChartBuilder::on(&root)
            .caption("Dark Energy Only", ("sans-serif", 50).into_font())
            .margin(5_u32)
            .x_label_area_size(30_u32)
            .y_label_area_size(30_u32)
            .build_cartesian_2d(0.0..0.0, 0.0_f64..1.0).unwrap();
}
facorread commented 2 years ago

Hey! I was wondering if you are still experiencing this issue. Please let me know if there is anything I can do to help. If not, we can go ahead and close this issue.

FlareFlo commented 2 years ago

I can also report this issue, specifically with coordinates exceeding a dimension of 1000 on the Y-axis.

38 commented 2 years ago

I can also report this issue, specifically with coordinates exceeding a dimension of 1000 on the Y-axis.

Hi, would you please share the range you guys use to build the coordinate? I can't reproduce the issue - Thanks

38 commented 2 years ago

r

I was plotting a line with

let mut chart = ChartBuilder::on(&root)
            .caption("Dark Energy Only", ("sans-serif", 50).into_font())
            .margin(5_u32)
            .x_label_area_size(30_u32)
            .y_label_area_size(30_u32)
            .build_cartesian_2d(age_of_universe * a0.powi(2)..0.0, 0.0_f64..1.0).unwrap();

and the program hung. Took me a few minutes and some println! debugging to realize that I had range going from a positive f64 to 0.0_f64 in age_of_universe * a0.powi(2)..0.0.

I haven't been using plotters very long so I don't know where else this may be relevant, but I think there should be some sort of check + panic/err if an invalid range is provided to a function.

Hi there, I just reproduced the issue with 0.3.1 but not the latest commit of master branch.

I believe this is dup to #253 and get fixed by commit 1291fa0ee

Would you mind try to use the latest development version of plotters from this repository, see if the bug is fixed?

Thanks!

FlareFlo commented 2 years ago

Using

plotters = { git = "https://github.com/plotters-rs/plotters"}
plotters-canvas = { git = "https://github.com/plotters-rs/plotters-canvas"}

plotters: git+https://github.com/plotters-rs/plotters#082ad5896623562d54d05c5f4e0f3ae3072baf6e plotters-canvas: git+https://github.com/plotters-rs/plotters-canvas#f7bea4184893b933cd67d7b7f8a8c74fbc8a0c13

Following dimensions seemingly ran into an endless loop / never returned

Left X-spec, right Y-spec

The only pattern I'm seeing here is the Y-spec range absolute sum of bounds exceeding 1000.

38 commented 2 years ago

Using

plotters = { git = "https://github.com/plotters-rs/plotters"}
plotters-canvas = { git = "https://github.com/plotters-rs/plotters-canvas"}

plotters: git+https://github.com/plotters-rs/plotters#082ad5896623562d54d05c5f4e0f3ae3072baf6e plotters-canvas: git+https://github.com/plotters-rs/plotters-canvas#f7bea4184893b933cd67d7b7f8a8c74fbc8a0c13

Following dimensions seemingly ran into an endless loop / never returned

Left X-spec, right Y-spec

* 0.0..495.0 -129.0..898.0

* 0.0..495.0 -128.0..921.0

* 0.0..594.0 -195.0..968.0

Following dimensions did run and return properly

* 0.0..330.0 -190.0..770.0

* 0.0..1100.0 -120.0..735.0

The only pattern I'm seeing here is the Y-spec range absolute sum of bounds exceeding 1000.

Hi I can't reproduce the bug, I am using the following code.

use plotters::prelude::*;

fn main() {
    let root_area = SVGBackend::new("out.svg", (1024, 768)).into_drawing_area();
    let mut chart = ChartBuilder::on(&root_area)
            .caption("Dark Energy Only", ("sans-serif", 50).into_font())
            .margin(5_u32)
            .x_label_area_size(30_u32)
            .y_label_area_size(30_u32)
            .build_cartesian_2d(0.0f64..495.0, -129.0f64..898.0)
            .unwrap();
    chart
            .configure_mesh()
            .x_desc("Time [Myr]")
            .y_desc("Scale Factor")
            .draw()
            .unwrap();
}

Could you please share a minimal reproduce code? Thanks in advance!

FlareFlo commented 2 years ago

Quick mention: The function does eventually terminate with following stacktrace: panicked at 'capacity overflow', ....rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\alloc\src\raw_vec.rs:517:5

eval | @ | index_bg.js:544
-- | -- | --
  | logError | @ | index_bg.js:510
  | __wbg_error_09919627ac0992f5 | @ | index_bg.js:542
  | $console_error_panic_hook::error::hfd7d66c6231d40a8 | @ | a26529e……odule.wasm:0x1b01fc
  | $console_error_panic_hook::hook_impl::h28eac0596e12d818 | @ | a26529e……odule.wasm:0x139e3e
  | $console_error_panic_hook::hook::hb09534e39e99a695 | @ | a26529e……odule.wasm:0x227638
  | $core::ops::function::Fn::call::he9dd08968036f9d5 | @ | a26529e……odule.wasm:0x2146fd
  | $std::panicking::rust_panic_with_hook::heaaf23a2375ea2ad | @ | a26529e….module.wasm:0x76eee
  | $std::panicking::begin_panic_handler::{{closure}}::hfde4fad9dbeb54c3 | @ | a26529e……odule.wasm:0x13d0b7
  | $std::sys_common::backtrace::__rust_end_short_backtrace::he3814d3c8a9951c2 | @ | a26529e……odule.wasm:0x1daff4
  | $rust_begin_unwind | @ | a26529e……odule.wasm:0x1c9f17
  | $core::panicking::panic_fmt::h51e842c42a6d2741 | @ | a26529e……odule.wasm:0x1dd4a1
  | $alloc::raw_vec::capacity_overflow::h728d5834553dd3a1 | @ | a26529e……odule.wasm:0x1db45a
  | $alloc::raw_vec::handle_reserve::ha821457ae5996c67 | @ | a26529e……odule.wasm:0x1a5e15
  | $alloc::raw_vec::RawVec<T,A>::reserve_for_push::hf9db6c1ff2df026e | @ | a26529e……odule.wasm:0x1f6b24
  | $alloc::vec::Vec<T,A>::push::hf9b29c354e9f80a8 | @ | a26529e……odule.wasm:0x15d2ce
  | $plotters::coord::ranged1d::types::numeric::compute_f64_key_points::hc26c8cc794898a1f | @ | a26529e….module.wasm:0x86171
  | $<plotters::coord::ranged1d::types::numeric::RangedCoordf64 as plotters::coord::ranged1d::Ranged>::key_points::hd2d1d501a1740acf | @ | a26529e……odule.wasm:0x1d0c8a
  | $plotters::coord::ranged2d::cartesian::Cartesian2d<X,Y>::draw_mesh::h1f1389112b3fd8b3 | @ | a26529e….module.wasm:0x780fb
  | $plotters::drawing::area::DrawingArea<DB,plotters::coord::ranged2d::cartesian::Cartesian2d<X,Y>>::draw_mesh::{{closure}}::h4240395101ba3aa8 | @ | a26529e……odule.wasm:0x1c441f
  | $plotters::drawing::area::DrawingArea<DB,CT>::backend_ops::he5e9646e2df5fd0c | @ | a26529e….module.wasm:0xc658a
  | $plotters::drawing::area::DrawingArea<DB,plotters::coord::ranged2d::cartesian::Cartesian2d<X,Y>>::draw_mesh::hcf85a93d903989b1 | @ | a26529e……odule.wasm:0x16d1dc
  | $plotters::chart::context::cartesian2d::draw_impl::<impl plotters::chart::context::ChartContext<DB,plotters::coord::ranged2d::cartesian::Cartesian2d<X,Y>>>::draw_mesh_lines::hc00a4eb2fcb36c13 | @ | a26529e….module.wasm:0xcd222
  | $plotters::chart::context::cartesian2d::draw_impl::<impl plotters::chart::context::ChartContext<DB,plotters::coord::ranged2d::cartesian::Cartesian2d<X,Y>>>::draw_mesh::hb831c8796932992f | @ | a26529e….module.wasm:0x69dc3
  | $plotters::chart::mesh::MeshStyle<X,Y,DB>::draw::h987259603b4f150d | @ | a26529e….module.wasm:0x6df75
  | $wt_data_sheets_wasm::missile_ballistics::plot::h78ce089ba1ad2180 | @ | a26529e….module.wasm:0x40346
  | $plot | @ | a26529e……odule.wasm:0x17148b
  | plot | @ | index_bg.js:371
  | eval

I will soon follow up with my attempt at reproducing the issue in a sandbox.

38 commented 2 years ago

Sure, but that's odd - Conceptually compute_f64_key_points shouldn't return items more than asked. If this happened, this is definitely a bug. It would be very interesting if you can print the parameters used to invoke compute_f64_key_points.

This can be done by adding printing statement for range and max_points at https://github.com/plotters-rs/plotters/blob/082ad5896623562d54d05c5f4e0f3ae3072baf6e/plotters/src/coord/ranged1d/types/numeric.rs#L108

And it would be very helpful for us if you can share the parameter that triggers the infinite loop. Thanks!

FlareFlo commented 2 years ago

Sandbox which can recreate the issue reliably

Edit: Specific attention to the lines 23 and 28 which point out the two bounds that work or dont

38 commented 2 years ago

Thanks @FlareFlo

I confirm that this reproduces the bug - And I got this fixed with the latest commit. Please let me know if the fix works on your side.

Thanks!

FlareFlo commented 2 years ago

Everything works now, very well done! Edit: Can confirm that the Wasm32 cases work too.

38 commented 2 years ago

Great, closing the issue for now.

I believe the original issue is also fixed by earlier commit.

Feel free to reopen the issue if the problem isn't solved.

Thanks everyone!