Plotters

repository·master·Indexed 26 days ago

https://github.com/plotters-rs/plotters

A Rust drawing library focused on data plotting for both WASM and native applications. It includes a high-level plotting API and a modular backend system via the `plotters-backend` crate, with official implementations for bitmap rendering (`plotters-bitmap`) and SVG output (`plotters-svg`). The library supports features such as GIF animations, parallel rendering through backend splitting, and customizable coordinate systems via the `Ranged` and `ReversibleRanged` traits.

Tokens
7.5K
Snippets
8
Records
46
Agent score
88%

What's inside plotters

  1. Install Plotters via Cargo

    master

    To use Plotters in your Rust project, add it to your Cargo.toml dependencies. For the standard version, use:

    [dependencies]
    plotters = "0.3.3"

    If you want to use the latest development version directly from GitHub:

    [dependencies]
    plotters = { git = "https://github.com/plotters-rs/plotters.git" }
    [dependencies]
    plotters = "0.3.3"
  2. Use Plotters with Jupyter (evcxr)

    master

    Plotters supports interactive plotting in Jupyter Notebooks using the evcxr kernel. To use this, you must enable the evcxr feature.

    In your Jupyter cell, include the dependency and use evcxr_figure to wrap your drawing logic:

    :dep plotters = { version = "^0.3.6", default-features = false, features = ["evcxr", "all_series", "all_elements"] }
    extern crate plotters;
    use plotters::prelude::*;
    
    let figure = evcxr_figure((640, 480), |root| {
        root.fill(&WHITE)?;
        let mut chart = ChartBuilder::on(&root)
            .caption("y=x^2", ("Arial", 50).into_font())
            .margin(5)
            .x_label_area_size(30)
            .y_label_area_size(30)
            .build_cartesian_2d(-1f32..1f32, -0.1f32..1f32)?;
    
        chart.configure_mesh().draw()?;
    
        chart.draw_series(LineSeries::new(
                (-50..=50).map(|x| x as f32 / 50.0).map(|x| (x, x * x)),
                &RED,
            )).unwrap()
                .label("y = x^2")
                .legend(|(x,y)| PathElement::new(vec![(x,y), (x + 20,y)], &RED));
    
        chart.configure_series_labels()
                .background_style(&WHITE.mix(0.8))
                .border_style(&BLACK)
                .draw()?;
        Ok(())
    });
    figure
  3. Support animated or realtime rendering in a backend

    master

    To support real-time display (e.g., GTK) or animated formats (e.g., GIF), a backend must correctly manage the frame lifecycle using ensure_prepared and present:

    1. ensure_prepared: Called before every drawing operation. It should initialize the backend for the current frame. If the backend is already prepared for a frame, it should do nothing.
    2. present: Called when the drawing for the current frame is finished. This flushes the changes to the screen or file.

    Lifecycle Summary:

    • Static Drawing: present is called once manually or via the Drop implementation.
    • Dynamic/Animated Drawing: Frames are defined by calls to present. Everything drawn between ensure_prepared and present belongs to a single frame.
  4. Implement the DrawingBackend trait

    master

    To create a new Plotters backend, implement the DrawingBackend trait.

    Minimal Implementation: If your backend only implements draw_pixel, Plotters will use its default CPU rasterizer to handle complex shapes (lines, rectangles, circles, etc.).

    Advanced Implementation: For backends with native support for vector graphics or GPU acceleration, you should override the specific drawing methods (e.g., draw_line, draw_rect, draw_circle) to use the backend's optimized capabilities. If your backend has text rendering, override estimate_text_size to ensure accurate spacing.

    Version Compatibility: It is highly recommended to depend on plotters-backend using a version specification like ^x.y.* to ensure compatibility with the main plotters crate.

  5. Configure Plotters features to reduce dependencies

    master

    Plotters allows you to minimize dependencies and compile time by disabling default features and cherry-picking specific backends or elements.

    To disable default features and only enable the svg backend:

    [dependencies]
    plotters = { git = "https://github.com/plotters-rs/plotters.git", default-features = false, features = ["svg"] }

    Available Features

    Tier 1 Drawing Backends

    NameDescriptionAdditional DependencyDefault?
    bitmap_encoderAllow BitMapBackend to save to bitmap filesimage, rusttype, font-kitYes
    svg_backendEnable SVGBackend SupportNoneYes
    bitmap_gifOpt-in GIF animation for BitMapBackendgifYes

    Font Manipulation

    NameDescriptionAdditional DependencyDefault?
    ttfTrueType font supportfont-kitYes
    ab_glyphSkips system fonts, uses pure Rust implementationab_glyphNo

    Coordinate Support

    NameDescriptionAdditional DependencyDefault?
    datetimeDate and time coordinate supportchronoYes

    Element & Series Support

    NameDescriptionAdditional DependencyDefault?
    errorbarErrorbar element supportNoneYes
    candlestickCandlestick element supportNoneYes
    boxplotBoxplot element supportNoneYes
    area_seriesArea series supportNoneYes
    line_seriesLine series supportNoneYes
    histogramHistogram series supportNoneYes
    point_seriesPoint series supportNoneYes
  6. Handle BitMapBackendError errors

    master

    When using the plotters-bitmap backend, errors are encapsulated in the BitMapBackendError enum. This error type is used to indicate issues during bitmap manipulation or encoding. Common error variants include:

    • InvalidBuffer: The provided pixel buffer is invalid (e.g., incorrect size).
    • IOError: An underlying std::io::Error occurred during bitmap operations.
    • GifEncodingError: An error occurred while encoding a GIF (available when the gif feature is enabled).
    • ImageError: An error from the image crate occurred (available when the image feature is enabled).
  7. Example: Drawing vertical error bars

    master

    This example demonstrates how to create a 2D chart and draw a series of vertical error bars representing minima, maxima, and average values.

    use plotters::prelude::*;
    let data = [(1.0, 3.3), (2., 2.1), (3., 1.5), (4., 1.9), (5., 1.0)];
    let drawing_area = SVGBackend::new("error_bars_vertical.svg", (300, 200)).into_drawing_area();
    drawing_area.fill(&WHITE).unwrap();
    let mut chart_builder = ChartBuilder::on(&drawing_area);
    chart_builder.margin(10).set_left_and_bottom_label_area_size(20);
    let mut chart_context = chart_builder.build_cartesian_2d(0.0..6.0, 0.0..6.0).unwrap();
    chart_context.configure_mesh().draw().unwrap();
    chart_context.draw_series(data.map(|(x, y)| {
        ErrorBar::new_vertical(x, y - 0.4, y, y + 0.3, BLUE.filled(), 10)
    })).unwrap();
    chart_context.draw_series(data.map(|(x, y)| {
        ErrorBar::new_vertical(x, y + 1.0, y + 1.9, y + 2.4, RED, 10)
    })).unwrap();
  8. Quick Start: Draw a Quadratic Function

    master

    This example demonstrates how to initialize a BitMapBackend, create a DrawingArea, build a ChartContext using ChartBuilder, and draw a LineSeries.

    use plotters::prelude::*;
    fn main() -> Result<(), Box<dyn std::error::Error>> {
        let root = BitMapBackend::new("plotters-doc-data/0.png", (640, 480)).into_drawing_area();
        root.fill(&WHITE)?;
        let mut chart = ChartBuilder::on(&root)
            .caption("y=x^2", ("sans-serif", 50).into_font())
            .margin(5)
            .x_label_area_size(30)
            .y_label_area_size(30)
            .build_cartesian_2d(-1f32..1f32, -0.1f32..1f32)?;
    
    chart.configure_mesh().draw()?;
    
    chart
            .draw_series(LineSeries::new(
                (-50..=50).map(|x| x as f32 / 50.0).map(|x| (x, x * x)),
                &RED,
            ))
            .label("y = x^2")
            .legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &RED));
    
    chart
            .configure_series_labels()
            .background_style(&WHITE.mix(0.8))
            .border_style(&BLACK)
            .draw()?;
    
    root.present()?;
    
    Ok(())
    }
  9. Implement ReversibleRanged for pixel-to-value mapping

    master
    If you need to convert pixel-based coordinates back into your logical coordinate values (e.g., for mouse interaction or data picking), implement the ReversibleRanged trait. This requires implementing the unmap method, which takes a pixel coordinate and the pixel limit, returning an Option<Self::ValueType>.
  10. Initialize a BitMapBackend for file output

    master

    Use BitMapBackend::new to create a backend that saves a bitmap image to a file. This requires the image feature to be enabled and is not supported on wasm32 targets.

    Note: You must call .present()? on the backend to ensure the chart is correctly written to the file. While drop attempts a best-effort save, errors during a drop-triggered save are silently ignored.