#plot #drawing #wasm

plotters-unsable

适用于原生和WASM应用程序的纯Rust绘图库

1个不稳定版本

0.1.13-5c709bb2019年6月6日

#plotting中排名10

MIT许可证

275KB
4K SLoC

Plotters - Rust可视化绘图库 🦀 📈🚀

请注意:此库处于非常早期阶段。我正在尽最大努力稳定API并提高整体质量。API可能会在此期间更改。

Plotters是一个专为绘制图形、图表而设计的绘图库,采用纯Rust编写。Plotters支持多种后端,包括位图、矢量图和WebAssembly。

快速入门

要使用Plotters,您只需将Plotters添加到您的Cargo.toml

[depedencies]
plotters = "^0.1.13"

以下代码绘制了一个二次函数。 src/main.rs,

use plotters::prelude::*;
fn main() -> Result<(), Box<dyn std::error::Error>> {
    let root = BitMapBackend::new("examples/outputs/0.png", (640, 480)).into_drawing_area();
    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_ranged(-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)| Path::new(vec![(x,y), (x + 20,y)], &Red));

    chart.configure_series_labels()
        .background_style(&White.mix(0.8))
        .border_style(&Black)
        .draw()?;

    Ok(())
}

Rust中绘图的动力

Rust是进行数据可视化的完美语言。尽管有各种不同语言的许多成熟的可视化库。但Rust是适合这一需求的最佳语言之一。

  • 易于使用 Rust在标准库中内置了一个非常好的迭代器系统。借助迭代器的帮助,Rust中的绘图可以像大多数高级编程语言一样简单。基于Rust的绘图库非常易于使用。

  • 快速 如果您需要渲染具有数万亿数据点的图形,Rust是一个很好的选择。Rust的性能允许您将数据处理步骤和渲染步骤合并到单个应用程序中。在高级编程语言中进行绘图时,例如JavaScript或Python,由于性能考虑,必须在将数据点馈入绘图程序之前进行下采样。Rust足够快,可以在单个程序中进行数据处理和可视化。您还可以将图形渲染代码集成到处理大量数据的应用程序中,并实时进行可视化。

  • WebAssembly支持 Rust是少数具有最佳WASM支持的编程语言之一。在Rust中进行绘图对于网页上的可视化非常有用,与JavaScript相比,性能将得到巨大提升。

支持哪些类型的图形?

Plotters不受任何特定类型图形的限制。您可以使用Plotters API轻松创建自己的图形类型。

但Plotters提供了一些内置图形类型以方便使用。目前,我们支持线系列、点系列、蜡烛图系列和直方图。该库设计为能够将多个图形渲染到单个图像中。但Plotters旨在成为一个完全可扩展的平台,以支持任何其他类型的图形。

在HTML5画布上绘图

Plotters目前支持使用HTML5画布的后端。要使用WASM支持,您只需使用CanvasBackend而不是其他后端,所有其他API保持不变!

在repo的examples/wasm-demo目录下有一个Plotters + WASM的小型演示。要尝试部署的版本,请点击此链接

通过示例说明概念

绘图后端

绘图器可以使用不同的绘图后端,包括SVG、位图,甚至是实时渲染。例如,一个位图绘图后端。

use plotters::prelude::*;
fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create a 800*600 bitmap and start drawing
    let mut backend = BitMapBackend::new("examples/outputs/1.png", (300, 200));
    // And if we want SVG backend
    // let backend = SVGBackend::new("output.svg", (800, 600));
    backend.draw_rect((50, 50), (200, 150), &Red, true)?;
    Ok(())
}

绘图区域

绘图器使用了一个称为绘图区域的概念用于布局。绘图器支持将多个绘图区域集成到一个单独的图像中。这是通过创建子绘图区域来实现的。

除此之外,绘图区域还允许自定义坐标系,通过这样做,坐标映射将由绘图区域自动完成。

use plotters::prelude::*;
fn main() -> Result<(), Box<dyn std::error::Error>> {
    let root_drawing_area =
        BitMapBackend::new("examples/outputs/2.png", (300, 200)).into_drawing_area();
    // And we can split the drawing area into 3x3 grid
    let child_drawing_areas = root_drawing_area.split_evenly((3, 3));
    // Then we fill the drawing area with different color
    for (area, color) in child_drawing_areas.into_iter().zip(0..) {
        area.fill(&Palette99::pick(color))?;
    }
    Ok(())
}

元素

在绘图器中,元素是图形的构建块。所有元素都可以在绘图区域上绘制。存在不同类型的内置元素,如线条、文本、圆等。您也可以在应用程序代码中定义自己的元素。

您还可以将现有的元素组合起来构建一个复杂的元素。

要了解更多关于元素系统的信息,请阅读元素模块文档

use plotters::prelude::*;
fn main() -> Result<(), Box<dyn std::error::Error>> {
    let root = BitMapBackend::new("examples/outputs/3.png", (300, 200)).into_drawing_area();
    root.fill(&White)?;
    // Draw an circle on the drawing area
    root.draw(&Circle::new(
        (100, 100),
        50,
        Into::<ShapeStyle>::into(&Green).filled(),
    ))?;
    Ok(())
}

可组合元素

除了内置元素外,元素还可以组合成我们称为组合元素的逻辑组。在组合新元素时,目标坐标中给出了左上角的位置,并使用一个新的基于像素的坐标作为进一步元素组合的目的,该坐标的左上角被定义为(0,0)

例如,我们可以有一个包含点和其坐标的元素。

use plotters::prelude::*;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let root = BitMapBackend::new("examples/outputs/4.png", (640, 480)).into_drawing_area();

    root.fill(&RGBColor(240, 200, 200))?;

    let root = root.apply_coord_spec(RangedCoord::<RangedCoordf32, RangedCoordf32>::new(
        0f32..1f32,
        0f32..1f32,
        (0..640, 0..480),
    ));
    let font = ("Arial", 15.0).into_font();

    let dot_and_label = |x: f32, y: f32| {
        return EmptyElement::at((x, y))
            + Circle::new((0, 0), 3, ShapeStyle::from(&Black).filled())
            + Text::new(format!("({:.2},{:.2})", x, y), (10, 0), &font);
    };

    root.draw(&dot_and_label(0.5, 0.6))?;
    root.draw(&dot_and_label(0.25, 0.33))?;
    root.draw(&dot_and_label(0.8, 0.8))?;
    Ok(())
}

图表上下文

为了绘制图表,绘图器需要在绘图区域之上构建一个名为ChartContext的数据对象。图表上下文相对于绘图区域定义了更高层次的构建。例如,您可以使用图表上下文对象定义标签区域、网格,并使用图表上下文对象将数据系列放置在绘图区域上。

use plotters::prelude::*;
fn main() -> Result<(), Box<dyn std::error::Error>> {
    let root = BitMapBackend::new("examples/outputs/5.png", (640, 480)).into_drawing_area();
    root.fill(&White);
    let root = root.margin(10, 10, 10, 10);
    // After this point, we should be able to draw construct a chart context
    let font: FontDesc = ("Arial", 40.0).into();
    // Create the chart object
    let mut chart = ChartBuilder::on(&root)
        // Set the caption of the chart
        .caption("This is our first plot", &font)
        // Set the size of the label region
        .x_label_area_size(20)
        .y_label_area_size(40)
        // Finally attach a coordinate on the drawing area and make a chart context
        .build_ranged(0f32..10f32, 0f32..10f32)?;

    // Then we can draw a mesh
    chart
        .configure_mesh()
        // We can customize the maximum number of labels allowed for each axis
        .x_labels(5)
        .y_labels(5)
        // We can also change the format of the label text
        .y_label_formatter(&|x| format!("{:.3}", x))
        .draw()?;

    // And we can draw something in the drawing area
    let smaller_font = font.resize(10.0);
    chart.draw_series(LineSeries::new(
        vec![(0.0, 0.0), (5.0, 5.0), (8.0, 7.0)],
        &Red,
    ))?;
    // Similarly, we can draw point series
    chart.draw_series(PointSeries::of_element(
        vec![(0.0, 0.0), (5.0, 5.0), (8.0, 7.0)],
        5,
        &Red,
        &|c, s, st| {
            return EmptyElement::at(c)    // We want to construct a composed element on-the-fly
            + Circle::new((0,0),s,st.filled()) // At this point, the new pixel coordinate is established
            + Text::new(format!("{:?}", c), (10, 0), &smaller_font);
        },
    ))?;
    Ok(())
}

其他

要使用最新开发版本,请拉取https://github.com/38/plotters.git。在Cargo.toml

[dependencies]
plotters = { git = "https://github.com/38/plotters.git" }

绘图器现在支持使用功能来控制后端依赖。默认情况下,支持BitMapBackendSVGBackend,在Cargo.toml的依赖描述中使用default_features = false,您可以选择性地选择后端实现。

  • svg 启用SVGBackend
  • bitmap 启用BitMapBackend

例如,以下依赖描述将避免使用位图支持进行编译

[dependencies]
plotters = { git = "https://github.com/38/plotters.git", default_features = false, features = ["svg"] }

依赖

~1–7.5MB
~101K SLoC