#plot #drawing #wasm

plotters-unstable

一个专注于WASM和原生应用数据绘图的Rust绘图库

2个版本

0.2.1 2020年9月3日
0.2.0 2020年9月3日

#328 in 可视化

MIT许可证

3.5MB
10K SLoC

Plotters - 一个专注于WASM和原生应用数据绘图的Rust绘图库 🦀📈🚀

Plotters是一个专为纯Rust渲染图形、图表和绘图的库。Plotters支持多种后端类型,包括位图、矢量图形、piston窗口、GTK/Cairo和WebAssembly。

  • 新的Plotters开发者指南正在制作中。预览版本可在此处找到。
  • 要尝试使用交互式Jupyter笔记本的Plotters,或查看此处的静态HTML版本。
  • 要查看WASM示例,请访问此链接
  • 目前我们已准备好所有内部代码以用于控制台绘图,但基于控制台的后端仍未准备就绪。有关如何使用自定义后端在控制台上进行绘图的示例,请参阅此示例

要查看每个示例的源代码,请点击示例图片。

目录

快速入门

要使用Plotters,您可以将Plotters添加到您的Cargo.toml

[dependencies]
plotters = "^0.2.15"

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

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_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)| PathElement::new(vec![(x, y), (x + 20, y)], &RED));

    chart
        .configure_series_labels()
        .background_style(&WHITE.mix(0.8))
        .border_style(&BLACK)
        .draw()?;

    Ok(())
}

交互式尝试Jupyter evcxr内核

Plotters现在支持与evcxr集成,并能够在Jupyter Notebook中交互式地绘制图形。在将Plotters包含到Jupyter Notebook时,应启用evcxr功能。

以下代码显示了此功能的简化示例。

:dep plotters = { git = "https://github.com/38/plotters", default_features = false, features = ["evcxr"] }
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_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,
    )).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

使用Jupyter Notebook的交互式教程

本教程目前正在制作中,尚不完整

感谢evcxr,我们现在有Plotters的交互式教程!要使用交互式笔记本,您必须在计算机上安装Jupyter和evcxr。按照此页面下的说明进行安装。

之后,您应该能够在本地上启动Jupyter服务器并加载教程!

git clone https://github.com/38/plotters-doc-data
cd plotteres-doc-data
jupyter notebook

请选择名为 evcxr-jupyter-integration.ipynb 的笔记本。

此外,该笔记本的静态HTML版本可在以下位置获取:此位置

Rust中的绘图

Rust 是数据可视化的理想语言。尽管许多不同语言中都有许多成熟的可视化库。但 Rust 是最适合这一需求的最佳语言之一。

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

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

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

使用WASM后端在HTML5 canvas上绘图

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

在当前存储库的 examples/wasm-demo 目录下有一个 Plotters + WASM 的小型演示。要玩部署版本,请点击此 链接

支持哪些类型的图形?

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

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

通过示例讲解概念

绘图后端

Plotters 可以使用不同的绘图后端,包括 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("plotters-doc-data/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(())
}

绘图区域

Plotters 使用一个称为绘图区域的概念进行布局。Plotters 支持将多个图形集成到单个图像中。这是通过创建子绘图区域来完成的。

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

use plotters::prelude::*;
fn main() -> Result<(), Box<dyn std::error::Error>> {
    let root_drawing_area =
        BitMapBackend::new("plotters-doc-data/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(())
}

元素

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

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

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

use plotters::prelude::*;
fn main() -> Result<(), Box<dyn std::error::Error>> {
    let root = BitMapBackend::new("plotters-doc-data/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::*;
use plotters::coord::types::RangedCoordf32;

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

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

    let root = root.apply_coord_spec(Cartesian2d::<RangedCoordf32, RangedCoordf32>::new(
        0f32..1f32,
        0f32..1f32,
        (0..640, 0..480),
    ));

    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),
                ("sans-serif", 15.0).into_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("plotters-doc-data/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 mut chart = ChartBuilder::on(&root)
        // Set the caption of the chart
        .caption("This is our first plot", ("sans-serif", 40).into_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
    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), ("sans-serif", 10).into_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"] }

该库还允许消费者默认使用 Palette crate 的颜色类型。此行为也可以通过设置 default_features = false 来关闭。

功能列表

这是由 Plotters crate 定义的功能的完整列表。使用 default_features = false 来禁用默认启用的功能,然后您应该能够选择性地将您想要包含到 Plotters crate 中的功能。通过这样做,您可以最小化依赖项的数量,仅包含 itertools,编译时间少于 6 秒。

以下列表是可以选择启用或禁用的功能的完整列表。

  • 绘图后端相关功能
名称 描述 附加依赖 默认值?
image_encoder 允许 BitMapBackend 将结果保存到位图文件 image, rusttype, font-kit
svg 启用 SVGBackend 支持
gif_backend 选择启用 GIF 动画渲染支持 BitMapBackend,意味着启用 bitmap gif
piston 启用 PistonWindowBackend piston_window, rusttype, font-kit
cairo 启用 CairoBackend cairo-rs, rusttype, font-kit
  • 字体操作功能
名称 描述 附加依赖 默认值?
ttf 允许 TrueType 字体支持 rusttype, font-kit
  • 坐标功能
名称 描述 附加依赖 默认值?
datetime 启用日期和时间坐标支持 chrono
  • 元素、系列和实用函数
名称 描述 附加依赖 默认值?
errorbar 支持误差条元素
candlestick 支持蜡烛图元素
boxplot 支持箱线图元素
area_series 支持面积系列
line_series 支持折线系列
histogram 支持直方图系列
point_series 支持点系列
  • 其他
名称 描述 附加依赖 默认值?
deprecated_items 此功能允许使用即将在将来被删除的已弃用项
debug 启用用于调试的代码

常见问题列表

  • 为什么我的机器上的 WASM 示例会崩溃?

    WASM 示例需要使用 wasm32 目标来构建。使用 cargo build 可能会使用默认目标,在大多数情况下是任何 x86 目标。因此,您需要在 cargo 参数列表中添加 --target=wasm32-unknown-unknown 以构建它。

  • 如何在图表顶部绘制文本/圆形/点/矩形/...?

    如您所意识到的那样,Plotters 是一个绘图库,而不是传统的数据绘图库,您可以在绘图区域绘制任何想要的元素。使用 DrawingArea::draw 在绘图区域绘制任何元素。

依赖项

~1-15MB
~147K SLoC