A pure Rust visualization library inspired by D3.js

Overview

charts

A pure Rust visualization library inspired by D3.js.

See gallery and examples for code and more charts.

Frequency Of English Letters

Revenue By Music Format

Install

You can add this as a dependency to your project in your Cargo.toml file:

[dependencies]
charts = "0.3.0"

Chart Types

The library supports the following charts (more to be added soon):

  1. Vertical Bar Chart
  2. Vertical Stacked Bar Chart
  3. Horizontal Bar Chart
  4. Horizontal Stacked Bar Chart
  5. Scatter Chart
  6. Line Chart
  7. Area Chart
  8. Histogram (TBD)
  9. Box Plot (TBD)
  10. Other (TBD)

Also, composite charts are supported (see Composite Charts below)

Building Blocks

Here are the components that allow you to create a chart:

  1. Scales
  2. Views
  3. Axes
  4. Size and Margins
  5. Legend

The first two are foundational components that offer a certain degree of flexibility in how data is represented and how it can be combined to achieve the desired outcome when the goal is to visualize data beyond simple forms.

Let's dive into each building block and define its structure and API, or you can go to Examples section and see what you can build using charts.

1. Scales

A scale is an entity that transforms data from one dimension into another. The dimension you are transforming from is called domain and the dimension you are transforming to is called range. Currently, charts has implemented two types of scales:

  1. Linear Scale
  2. Band Scale

Linear Scale

A linear scale is an interpolation function that takes in a domain (e.g. [0, 10]) and a range (e.g. [0, 50]) and is able to transform a value from the domain into a corresponding value in the range (e.g. 5 -> 25).

When using a linear scale to create a chart, the domain represents the range of values that are present in the dataset. For instance, if you have a simple dataset vec![123, 48, 232, 99], the domain is represented by [48, 232] (but it can also be represented by [40, 240] or [0, 1000], more on that in a minute).

Conversely, the range of a scale represents the diapason that is available for rendering. For instance, if you have a chart that is 800px wide and 50px margin on the left and 50px margin on the right (see Margins below), this means that the available range to render data is [0, 700].

Thus, if to combine the domain and the range concepts, a scale with domain[0, 10] and a range[0, 500] will map all points from 0 to 10 onto a range of 0 to 500 pixels.

Band Scale

A band scale takes in a list of distinct domain values (e.g. categories, years) and a continuous range and interpolates the domain onto the range. It is often used in Bar Charts, where you need to map a categorical dataset onto a continuous axis of a specific size.

For instance, a band scale with domain["Apples", "Oranges", "Pears"] and a range[0, 100] will map the "Apples" domain to 0, "Oranges" to 33.33 and "Pears" to 66.66. The actual implementation has an inner_padding value that will leave a gap between the categories, so the real mapped values are going to be a bit different.

2. Views

Since the same dataset can be represented in different forms, there is a concept of a View that denotes a specific representation of the data.

Since a view of the data is a representation of that data along 2 dimensions (in 2D charts), each view requires a scale for its X dimension and a scale for its Y dimension.

Here is the list of views that are available:

  1. VerticalBarView
  2. HorizontalBarView
  3. ScatterView
  4. LineSeriesView
  5. AreaSeriesView

3. Axes

An axis is a representation of the range of the domain that is being visualized. This means that in order to properly display an axis, it should operate with the same scale as a view does.

As a user, you will not explicitly create axes, but rather where to draw the axis (top, right, bottom, left) and what scale to use for that axis.

4. Size and Margins

When creating a chart, you can customize its layout to some degree.

You can set chart width and height as well as the margins (top, right, bottom, left). Chart margins are the padding from the chart borders that define how much space will be left for axes and other elements that are not related to a view of the data.

For instance, a chart with 800px wide and 600px tall and margins of top: 100, right: 40, bottom: 50, left: 60 will leave an area of 700px wide and 450px tall for actual data representation.

      width - 800
+-------------------------------------------------------+
|                        top                            |  h
|                        100                            |  e
|     +-------------------------------------------+     |  i
|     |                                           |     |  g
|left |                  Actual                   |right|  h
| 60  |                   Data                    | 40  |  t
|     |                   View                    |     |  
|     |                700 x 450                  |     |  6
|     |                                           |     |  0
|     |                                           |     |  0
|     +-------------------------------------------+     |
|                      bottom - 50                      |
+-------------------------------------------------------+

5. Legend

The legend is automatically populated with entries present in each view attached to a chart. In order to add a legend to a chart, use the add_legend_at(position: AxisPosition) method on a chart instance (don't forget to leave sufficient margin at the bottom for the legend to show up).

The dataset's key values are used as legend entry labels. In case the dataset doesn't have any key values (i.e. when the dataset represents a single type of data), you can specify a custom label on a View via the .set_custom_data_label(label: String) method. Check out the Chart Composition section example of scatter plot with two datasets.

Examples

Below you can find examples of charts that are currently supported.

Vertical Bar Chart

Here is the sample code:

use charts::{Chart, VerticalBarView, ScaleBand, ScaleLinear};

fn main() {
    // Define chart related sizes.
    let width = 800;
    let height = 600;
    let (top, right, bottom, left) = (90, 40, 50, 60);

    // Create a band scale that maps ["A", "B", "C"] categories to values in the [0, availableWidth]
    // range (the width of the chart without the margins).
    let x = ScaleBand::new()
        .set_domain(vec![String::from("A"), String::from("B"), String::from("C")])
        .set_range(vec![0, width - left - right])
        .set_inner_padding(0.1)
        .set_outer_padding(0.1);

    // Create a linear scale that will interpolate values in [0, 100] range to corresponding
    // values in [availableHeight, 0] range (the height of the chart without the margins).
    // The [availableHeight, 0] range is inverted because SVGs coordinate system's origin is
    // in top left corner, while chart's origin is in bottom left corner, hence we need to invert
    // the range on Y axis for the chart to display as though its origin is at bottom left.
    let y = ScaleLinear::new()
        .set_domain(vec![0, 100])
        .set_range(vec![height - top - bottom, 0]);

    // You can use your own iterable as data as long as its items implement the `BarDatum` trait.
    let data = vec![("A", 90), ("B", 10), ("C", 30)];

    // Create VerticalBar view that is going to represent the data as vertical bars.
    let view = VerticalBarView::new()
        .set_x_scale(&x)
        .set_y_scale(&y)
        .load_data(&data).unwrap();

    // Generate and save the chart.
    Chart::new()
        .set_width(width)
        .set_height(height)
        .set_margins(top, right, bottom, left)
        .add_title(String::from("Bar Chart"))
        .add_view(&view)
        .add_axis_bottom(&x)
        .add_axis_left(&y)
        .add_left_axis_label("Units of Measurement")
        .add_bottom_axis_label("Categories")
        .save("vertical-bar-chart.svg").unwrap();
}

Here is the result:

Vertical Bar Chart

The display order of categories is defined by the vector passed to set_domain() of a ScaleBand. If you'll switch that order to "A", "C", "B", the resulting order will adjust as well.

Vertical Bar Chart with changed domain order

You can play with set_inner_padding() and set_outer_padding() values to customize the appearance of the chart.

Vertical Stacked Bar Chart

A simple bar chart (as the one above) is a specific instance of a stacked bar chart where there is only one type of values. Under the hood, charts treats both types pretty much the same, that's why the code is almost identical, except the input data must provide a key by which to group and stack values.

<-- uncomment this line to hide bar value labels .set_label_position(BarLabelPosition::Center) .load_data(&data).unwrap(); // Generate and save the chart. Chart::new() .set_width(width) .set_height(height) .set_margins(top, right, bottom, left) .add_title(String::from("Stacked Bar Chart")) .add_view(&view) .add_axis_bottom(&x) .add_axis_left(&y) .add_left_axis_label("Units of Measurement") .add_bottom_axis_label("Categories") .save("stacked-vertical-bar-chart.svg").unwrap(); }">
use charts::{Chart, VerticalBarView, ScaleBand, ScaleLinear, BarLabelPosition};

fn main() {
    // Define chart related sizes.
    let width = 800;
    let height = 600;
    let (top, right, bottom, left) = (90, 40, 50, 60);

    // Create a band scale that maps ["A", "B", "C"] categories to values in [0, availableWidth]
    // range (the width of the chart without the margins).
    let x = ScaleBand::new()
        .set_domain(vec![String::from("A"), String::from("B"), String::from("C")])
        .set_range(vec![0, width - left - right]);

    // Create a linear scale that will interpolate values in [0, 100] range to corresponding
    // values in [availableHeight, 0] range (the height of the chart without the margins).
    // The [availableHeight, 0] range is inverted because SVGs coordinate system's origin is
    // in the top left corner, while chart's origin is in bottom left corner, hence we need to
    // invert the range on Y axis for the chart to display as though its origin is at bottom left.
    let y = ScaleLinear::new()
        .set_domain(vec![0, 100])
        .set_range(vec![height - top - bottom, 0]);

    // You can use your own iterable as data as long as its items implement the `BarDatum` trait.
    let data = vec![("A", 70, "foo"), ("B", 10, "foo"), ("C", 30, "foo"), ("A", 20, "bar"), ("A", 5, "baz")];

    // Create VerticalBar view that is going to represent the data as vertical bars.
    let view = VerticalBarView::new()
        .set_x_scale(&x)
        .set_y_scale(&y)
        // .set_label_visibility(false)  // <-- uncomment this line to hide bar value labels
        .set_label_position(BarLabelPosition::Center)
        .load_data(&data).unwrap();

    // Generate and save the chart.
    Chart::new()
        .set_width(width)
        .set_height(height)
        .set_margins(top, right, bottom, left)
        .add_title(String::from("Stacked Bar Chart"))
        .add_view(&view)
        .add_axis_bottom(&x)
        .add_axis_left(&y)
        .add_left_axis_label("Units of Measurement")
        .add_bottom_axis_label("Categories")
        .save("stacked-vertical-bar-chart.svg").unwrap();
}

The result:

Vertical Stacked Bar Chart

By default, the order of the keys in the input data dictates the stacking order. You can, however, adjust that by specifying a different order using the set_keys() method on the VerticalBarDataset struct before calling load_data():

<-- uncomment this line to hide bar value labels .set_label_position(BarLabelPosition::Center) .load_data(&data).unwrap();">
// Create VerticalBar view that is going to represent the data as vertical bars.
let view = VerticalBarView::new()
    .set_x_scale(&x)
    .set_y_scale(&y)
    .set_keys(vec![String::from("foo"), String::from("baz"), String::from("bar")])
    // .set_label_visibility(false)  // <-- uncomment this line to hide bar value labels
    .set_label_position(BarLabelPosition::Center)
    .load_data(&data).unwrap();

The result of that is as follows (notice the order in the first bar has changed):

Vertical Stacked Bar Chart with custom keys order

Scatter Plot

use charts::{Chart, ScaleLinear, ScatterView, MarkerType, PointLabelPosition};

fn main() {
    // Define chart related sizes.
    let width = 800;
    let height = 600;
    let (top, right, bottom, left) = (90, 40, 50, 60);

    // Create a band scale that will interpolate values in [0, 200] to values in the
    // [0, availableWidth] range (the width of the chart without the margins).
    let x = ScaleLinear::new()
        .set_domain(vec![0, 200])
        .set_range(vec![0, width - left - right]);

    // Create a linear scale that will interpolate values in [0, 100] range to corresponding
    // values in [availableHeight, 0] range (the height of the chart without the margins).
    // The [availableHeight, 0] range is inverted because SVGs coordinate system's origin is
    // in top left corner, while chart's origin is in bottom left corner, hence we need to invert
    // the range on Y axis for the chart to display as though its origin is at bottom left.
    let y = ScaleLinear::new()
        .set_domain(vec![0, 100])
        .set_range(vec![height - top - bottom, 0]);

    // You can use your own iterable as data as long as its items implement the `PointDatum` trait.
    let scatter_data = vec![(120, 90), (12, 54), (100, 40), (180, 10)];

    // Create Scatter view that is going to represent the data as points.
    let scatter_view = ScatterView::new()
        .set_x_scale(&x)
        .set_y_scale(&y)
        .set_label_position(PointLabelPosition::E)
        .set_marker_type(MarkerType::Square)
        .load_data(&scatter_data).unwrap();

    // Generate and save the chart.
    Chart::new()
        .set_width(width)
        .set_height(height)
        .set_margins(top, right, bottom, left)
        .add_title(String::from("Scatter Chart"))
        .add_view(&scatter_view)
        .add_axis_bottom(&x)
        .add_axis_left(&y)
        .add_left_axis_label("Custom X Axis Label")
        .add_bottom_axis_label("Custom Y Axis Label")
        .save("scatter-chart.svg").unwrap();
}

The result:

Scatter plot

You can customize the appearance and layout as follows:

Choose how labels should display relative to the mark. Available options: N, NE, E, SE, S, SW, W, NW

Choose the mark type for the points. Available options: Square, Circle, X

If the dataset has a key which differentiates the points you can also use a ScatterView to display it.

use charts::{Chart, ScaleLinear, ScatterView, MarkerType, Color, PointLabelPosition};

fn main() {
    // Define chart related sizes.
    let width = 800;
    let height = 600;
    let (top, right, bottom, left) = (90, 40, 50, 60);

    // Create a band scale that will interpolate values in [0, 200] to values in the
    // [0, availableWidth] range (the width of the chart without the margins).
    let x = ScaleLinear::new()
        .set_domain(vec![0, 200])
        .set_range(vec![0, width - left - right]);

    // Create a linear scale that will interpolate values in [0, 100] range to corresponding
    // values in [availableHeight, 0] range (the height of the chart without the margins).
    // The [availableHeight, 0] range is inverted because SVGs coordinate system's origin is
    // in top left corner, while chart's origin is in bottom left corner, hence we need to invert
    // the range on Y axis for the chart to display as though its origin is at bottom left.
    let y = ScaleLinear::new()
        .set_domain(vec![0, 100])
        .set_range(vec![height - top - bottom, 0]);

    // You can use your own iterable as data as long as its items implement the `PointDatum` trait.
    let scatter_data = vec![(120, 90, "foo"), (12, 54, "foo"), (100, 40, "bar"), (180, 10, "baz")];

    // Create Scatter view that is going to represent the data as points.
    let scatter_view = ScatterView::new()
        .set_x_scale(&x)
        .set_y_scale(&y)
        .set_label_position(PointLabelPosition::E)
        .set_marker_type(MarkerType::Circle)
        .set_colors(Color::color_scheme_dark())
        .load_data(&scatter_data).unwrap();

    // Generate and save the chart.
    Chart::new()
        .set_width(width)
        .set_height(height)
        .set_margins(top, right, bottom, left)
        .add_title(String::from("Scatter Chart"))
        .add_view(&scatter_view)
        .add_axis_bottom(&x)
        .add_axis_left(&y)
        .add_left_axis_label("Custom X Axis Label")
        .add_bottom_axis_label("Custom Y Axis Label")
        .save("scatter-chart-multiple-keys.svg").unwrap();
}

Scatter Chart with data with different keys

Line Series

Line series supports the same functionality os a Scatter plot.

use charts::{Chart, ScaleLinear, MarkerType, PointLabelPosition, LineSeriesView};

fn main() {
    // Define chart related sizes.
    let width = 800;
    let height = 600;
    let (top, right, bottom, left) = (90, 40, 50, 60);

    // Create a band scale that will interpolate values in [0, 200] to values in the
    // [0, availableWidth] range (the width of the chart without the margins).
    let x = ScaleLinear::new()
        .set_domain(vec![0_f32, 200_f32])
        .set_range(vec![0, width - left - right]);

    // Create a linear scale that will interpolate values in [0, 100] range to corresponding
    // values in [availableHeight, 0] range (the height of the chart without the margins).
    // The [availableHeight, 0] range is inverted because SVGs coordinate system's origin is
    // in top left corner, while chart's origin is in bottom left corner, hence we need to invert
    // the range on Y axis for the chart to display as though its origin is at bottom left.
    let y = ScaleLinear::new()
        .set_domain(vec![0_f32, 100_f32])
        .set_range(vec![height - top - bottom, 0]);

    // You can use your own iterable as data as long as its items implement the `PointDatum` trait.
    let line_data = vec![(12, 54), (100, 40), (120, 50), (180, 70)];

    // Create Line series view that is going to represent the data.
    let line_view = LineSeriesView::new()
        .set_x_scale(&x)
        .set_y_scale(&y)
        .set_marker_type(MarkerType::Circle)
        .set_label_position(PointLabelPosition::N)
        .load_data(&line_data).unwrap();

    // Generate and save the chart.
    Chart::new()
        .set_width(width)
        .set_height(height)
        .set_margins(top, right, bottom, left)
        .add_title(String::from("Line Chart"))
        .add_view(&line_view)
        .add_axis_bottom(&x)
        .add_axis_left(&y)
        .add_left_axis_label("Custom Y Axis Label")
        .add_bottom_axis_label("Custom X Axis Label")
        .save("line-chart.svg").unwrap();
}

Line Series

Area Series

Currently, AreaSeriesView doesn't support datasets with multiple keys, thus it cannot display a stacked area chart.

use charts::{Chart, ScaleLinear, MarkerType, PointLabelPosition, AreaSeriesView};

fn main() {
    // Define chart related sizes.
    let width = 800;
    let height = 600;
    let (top, right, bottom, left) = (90, 40, 50, 60);

    // Create a band scale that will interpolate values in [0, 200] to values in the
    // [0, availableWidth] range (the width of the chart without the margins).
    let x = ScaleLinear::new()
        .set_domain(vec![12_f32, 180_f32])
        .set_range(vec![0, width - left - right]);

    // Create a linear scale that will interpolate values in [0, 100] range to corresponding
    // values in [availableHeight, 0] range (the height of the chart without the margins).
    // The [availableHeight, 0] range is inverted because SVGs coordinate system's origin is
    // in top left corner, while chart's origin is in bottom left corner, hence we need to invert
    // the range on Y axis for the chart to display as though its origin is at bottom left.
    let y = ScaleLinear::new()
        .set_domain(vec![0_f32, 100_f32])
        .set_range(vec![height - top - bottom, 0]);

    // You can use your own iterable as data as long as its items implement the `PointDatum` trait.
    let area_data = vec![(12, 54), (100, 40), (120, 50), (180, 70)];

    // Create Area series view that is going to represent the data.
    let area_view = AreaSeriesView::new()
        .set_x_scale(&x)
        .set_y_scale(&y)
        .set_marker_type(MarkerType::Circle)
        .set_label_position(PointLabelPosition::N)
        .load_data(&area_data).unwrap();

    // Generate and save the chart.
    Chart::new()
        .set_width(width)
        .set_height(height)
        .set_margins(top, right, bottom, left)
        .add_title(String::from("Area Chart"))
        .add_view(&area_view)
        .add_axis_bottom(&x)
        .add_axis_left(&y)
        .add_left_axis_label("Custom Y Axis Label")
        .add_bottom_axis_label("Custom X Axis Label")
        .save("area-chart.svg").unwrap();
}

Area Series Chart

Chart Composition

Once you understand the basic building blocks (mainly Scales and Views), the sky is the limit (and available implemented views, for now (: ) on what you can achieve using charts.

The main idea is to use common scale instances that serve as a common context between different datasets and views.

One example is combining a bar chart and a scatter plot:

<-- add bar view .add_view(&scatter_view) // <-- add scatter view .add_axis_bottom(&x) .add_axis_left(&y) .add_left_axis_label("Units of Measurement") .add_bottom_axis_label("Categories") .save("composite-bar-and-scatter-chart.svg").unwrap(); }">
use charts::{Chart, VerticalBarView, ScaleBand, ScaleLinear, ScatterView, MarkerType, Color, PointLabelPosition};

fn main() {
    // Define chart related sizes.
    let width = 800;
    let height = 600;
    let (top, right, bottom, left) = (90, 40, 50, 60);

    // Create a band scale that maps ["A", "B", "C"] categories to values in the [0, availableWidth]
    // range (the width of the chart without the margins).
    let x = ScaleBand::new()
        .set_domain(vec![String::from("A"), String::from("B"), String::from("C")])
        .set_range(vec![0, width - left - right]);

    // Create a linear scale that will interpolate values in [0, 100] range to corresponding
    // values in [availableHeight, 0] range (the height of the chart without the margins).
    // The [availableHeight, 0] range is inverted because SVGs coordinate system's origin is
    // in top left corner, while chart's origin is in bottom left corner, hence we need to invert
    // the range on Y axis for the chart to display as though its origin is at bottom left.
    let y = ScaleLinear::new()
        .set_domain(vec![0, 100])
        .set_range(vec![height - top - bottom, 0]);

    // You can use your own iterable as data as long as its items implement the `BarDatum` trait.
    let bar_data = vec![("A", 70), ("B", 10), ("C", 30)];

    // You can use your own iterable as data as long as its items implement the `PointDatum` trait.
    let scatter_data = vec![(String::from("A"), 90.3), (String::from("B"), 20.1), (String::from("C"), 10.8)];

    // Create VerticalBar view that is going to represent the data as vertical bars.
    let bar_view = VerticalBarView::new()
        .set_x_scale(&x)
        .set_y_scale(&y)
        .load_data(&bar_data).unwrap();

    // Create Scatter view that is going to represent the data as points.
    let scatter_view = ScatterView::new()
        .set_x_scale(&x)
        .set_y_scale(&y)
        .set_label_position(PointLabelPosition::NE)
        .set_marker_type(MarkerType::Circle)
        .set_colors(Color::from_vec_of_hex_strings(vec!["#FF4700"]))
        .load_data(&scatter_data).unwrap();

    // Generate and save the chart.
    Chart::new()
        .set_width(width)
        .set_height(height)
        .set_margins(top, right, bottom, left)
        .add_title(String::from("Composite Bar + Scatter Chart"))
        .add_view(&bar_view)                            // <-- add bar view
        .add_view(&scatter_view)                        // <-- add scatter view
        .add_axis_bottom(&x)
        .add_axis_left(&y)
        .add_left_axis_label("Units of Measurement")
        .add_bottom_axis_label("Categories")
        .save("composite-bar-and-scatter-chart.svg").unwrap();
}

The result looks as follows:

Composite Bar and Scatter Chart

Another example is combining different datasets. For instance, we can define scales that cover the domain from both datasets and see how they relate to each other.

use charts::{Chart, ScaleLinear, ScatterView, MarkerType, PointLabelPosition, Color, AxisPosition};

fn main() {
    // Define chart related sizes.
    let width = 800;
    let height = 600;
    let (top, right, bottom, left) = (90, 40, 80, 60);

    // Create a band scale that will interpolate values in [0, 200] to values in the
    // [0, availableWidth] range (the width of the chart without the margins).
    let x = ScaleLinear::new()
        .set_domain(vec![0_f32, 200_f32])
        .set_range(vec![0, width - left - right]);

    // Create a linear scale that will interpolate values in [0, 100] range to corresponding
    // values in [availableHeight, 0] range (the height of the chart without the margins).
    // The [availableHeight, 0] range is inverted because SVGs coordinate system's origin is
    // in top left corner, while chart's origin is in bottom left corner, hence we need to invert
    // the range on Y axis for the chart to display as though its origin is at bottom left.
    let y = ScaleLinear::new()
        .set_domain(vec![0_f32, 100_f32])
        .set_range(vec![height - top - bottom, 0]);

    // You can use your own iterable as data as long as its items implement the `PointDatum` trait.
    let scatter_data_1 = vec![(20, 90), (12, 54), (25, 70), (33, 40)];
    let scatter_data_2 = vec![(120, 10), (143, 34), (170, 14), (190, 13)];

    // Create Scatter view that is going to represent the data as points.
    let scatter_view_1 = ScatterView::new()
        .set_x_scale(&x)
        .set_y_scale(&y)
        .set_marker_type(MarkerType::Circle)
        .set_label_position(PointLabelPosition::N)
        .set_custom_data_label("Apples".to_owned())
        .load_data(&scatter_data_1).unwrap();

    // Create Scatter view that is going to represent the data as points.
    let scatter_view_2 = ScatterView::new()
        .set_x_scale(&x)
        .set_y_scale(&y)
        .set_marker_type(MarkerType::Square)
        .set_label_position(PointLabelPosition::N)
        .set_custom_data_label("Oranges".to_owned())
        .set_colors(Color::from_vec_of_hex_strings(vec!["#aa0000"]))
        .load_data(&scatter_data_2).unwrap();

    // Generate and save the chart.
    Chart::new()
        .set_width(width)
        .set_height(height)
        .set_margins(top, right, bottom, left)
        .add_title(String::from("Scatter Chart"))
        .add_view(&scatter_view_1)
        .add_view(&scatter_view_2)
        .add_axis_bottom(&x)
        .add_axis_left(&y)
        .add_left_axis_label("Custom X Axis Label")
        .add_bottom_axis_label("Custom Y Axis Label")
        .add_legend_at(AxisPosition::Bottom)
        .save("scatter-chart-two-datasets.svg").unwrap();
}

Scatter Plot With Two Datasets

Next Steps

This is still a work in progress, so the next steps are going to be implementing more views and improving on existing functionality.

You might also like...
A simple 2D plotting library that outputs graphs to SVG that can be styled using CSS.

Poloto graphs can be stylized using css either directly in the SVG, or from inside of html with an embedded svg. The latter allows the user to dynamically match the svg to their website's theme.

RustViz is a tool that generates interactive visualizations from simple Rust programs to assist users in better understanding the Rust Lifetime and Borrowing mechanism.
Plotly for Rust

Plotly.rs Plotly for Rust Getting Started | Recipes | API Docs | Changelog | | | A plotting library for Rust powered by Plotly.js. Usage Add this to y

This is a Rust implementation of a boid flocking simulation using the ggez graphics crate.
This is a Rust implementation of a boid flocking simulation using the ggez graphics crate.

Boidflock This is a Rust implementation of a boid flocking simulation using the ggez graphics crate. The CLI for this program is built using the struc

Render farm simulator & plotting for optimisation written in Rust.
Render farm simulator & plotting for optimisation written in Rust.

Farm Usage Simulator Given a few basic charasteristics of a render farm and render jobs this app runs a few randomized farm usage scenarios and plots

Rust crate for creating beautiful interactive Chord Diagrams
Rust crate for creating beautiful interactive Chord Diagrams

Chord PRO Released Chord PRO is the full-featured chord visualization API, producing beautiful interactive visualizations, e.g. those featured on the

A Rust API for Vega-Lite V4 to build chart with a rusty API.
A Rust API for Vega-Lite V4 to build chart with a rusty API.

Vega-Lite V4 for Rust A Rust API for Vega-Lite V4 to build chart with a rusty API. Similar to the Altair project in python, this crate build upon Vega

Externalize easily the plotting process from Rust to gnuplot.
Externalize easily the plotting process from Rust to gnuplot.

preexplorer Easy plotter and saver of simple data. Handy tool for development stage or small computational projects. Save data, have a quick view and

Graphical Rust program that uses a fractal algorithm to draw a tree of sorts

rusty-vegetation Graphical Rust program that uses a fractal algorithm to draw a "tree" of sorts. To Build and Run On Linux: Install build-essentials o

Comments
  • Multiple charts in the same SVG

    Multiple charts in the same SVG

    I see that Charts can have multiple views in it. And it looks like the views effectively overlap each other. I'm wondering if the views could be made separate (visually), all within the same SVG. Is this possible today?

    opened by kvark 0
  • Allow users to specify the background colour of charts

    Allow users to specify the background colour of charts

    Hello, I hope this finds you well.

    Please could you add a method to allow people to specify a background colour (or transparency) for Chart instances? I am making SVG charts at the moment, and their transparent backgrounds makes them very difficult to read/see.

    Thank you for your time and consideration.

    opened by taeh98 0
  • Clarify License Agreement

    Clarify License Agreement

    Hi! I'm interesting in using this library in a project I'm working on, but am hesitant to do so because of a lack of a license agreement. In the cargo.toml https://github.com/askanium/rustplotlib/blob/master/Cargo.toml, it specifies the license as "MIT OR Apache 2.0". It would be great to clarify what this means and add a LICENSE.md to the root of the project.

    opened by FermiDirak 0
  • Configure font size for labels

    Configure font size for labels

    I have found that the default font sizes for labels is not suitable in all cases . In a my particular case I needed a larger font size for the tick on the horizontal axis than the default 12px.

    I have forked the repo and can provide a pull request with configuration for all font sizes if you are interested.

    Regards,

    Jerry.

    opened by jerusdp 0
Releases(v.0.2.0)
Owner
Iulian Gulea
Iulian Gulea
🔵🟠 Portal Explorer — web visualization of mind-blowing portals using ray-tracing.

In Portal Explorer you can view how interesting portals are constructed, and visually explore their properties by moving and rotating them. This program doesn't work well on mobile, better opened from PC.

ilya sheprut 99 Dec 7, 2022
📝 Web-based, reactive Datalog notebooks for data analysis and visualization

?? Web-based, reactive Datalog notebooks for data analysis and visualization

Eric Zhang 486 Dec 28, 2022
A color-coded visualization tool for the instructions of an anchor program

anchor-viz A color-coded visualization tool for the instructions of an anchor program. (This is a schematic of basic-2 from anchor's examples/tutorial

cavemanloverboy 5 Oct 15, 2022
A better visualization of clang's -ftime-trace output

crofiler: Easier C++ build profiling Understanding why C++ builds get slow has become a lot easier since clang introduced their -ftime-trace build tra

Hadrien G. 7 Nov 15, 2022
Swash is a pure Rust, cross-platform crate that provides font introspection, complex text shaping and glyph rendering.

Swash is a pure Rust, cross-platform crate that provides font introspection, complex text shaping and glyph rendering. Goals This crate aims to

Chad Brokaw 398 Dec 14, 2022
Data plotting library for Rust

plotlib plotlib is a generic data visualisation and plotting library for Rust. It is currently in the very early stages of development. It can current

Matt Williams 417 Dec 31, 2022
A rust drawing library for high quality data plotting for both WASM and native, statically and realtimely 🦀 📈🚀

Plotters - A Rust drawing library focus on data plotting for both WASM and native applications ?? ?? ?? Plotters is drawing library designed for rende

Hao Hou 2.7k Jan 4, 2023
A Rust library for drawing plots, powered by Gnuplot.

RustGnuplot A Gnuplot controller written in Rust. Documentation See here Examples A simple example: let mut fg = Figure::new(); fg.axes2d() .set_titl

null 353 Dec 26, 2022
A library to generate syntax diagrams for Rust macros.

Live demo (code) A browser add-on for Firefox, Chrome and Edge A library to generate syntax ("railroad") diagrams for Rust's macro_rules!(). Diagrams

null 468 Jan 6, 2023
A library of to show data (in browser, evcxr_jupyter) as table, chart...

showata A library of to show data (in browser, evcxr_jupyter) as table, chart.... The crate provides display for: image vector and slice (as table) nd

Procyon 20 Dec 12, 2022