This is a interactive tutorial forPlotters
drawing library. If you are looking at the static HTML version and want to try the interactive version. Please follow the steps:
# Install Jupyter notebooksudo apt install libzmq3-dev jupyter-notebookcargo install evcxr_jupyterevcxr_jupyter --install# Get the notebookgit clone https://github.com/38/plotters-doc-datacd plotteres-doc-datajupyter notebook
# Install Jupyter notebookbrew install zeromq pkg-configcargo install evcxr_jupyterevcxr_jupyter --install# Get the notebookgit clone https://github.com/38/plotters-doc-datacd plotteres-doc-datajupyter notebook
You can also download the latest notebook fromhttps://raw.githubusercontent.com/38/plotters-doc-data/master/evcxr-jupyter-integration.ipynb, thus you don't have to clone the entire data repo.
In order to usePlotters
injupyter-evcxr
, you need both Jupyter and evcxr installed.Checkhttps://github.com/google/evcxr for the instructions.
To use Plotters withjupyter-evcxr
, you need to import it using the following code:
:depplotters={version="^0.3.0",default_features=false,features=["evcxr","all_series"]}
Becauseevcxr
uses only SVG images and all types of series, so we don't need other types of backend. So we should put
default_features = false, features = ["evcxr", "all_series"]
Make the compilation faster. Sinceevcxr
shares all the artifacts among cells, after the first time we haveplotters
compiled, it should be faster after.
To use plotters, the most convenient way is importing everything defined in theprelude
module.It will importevcxr_figure
function forevcxr
integration.
Note: Currently evcxr doesn't work with nightly rust, so please make sure you are using a stable rust
:depplotters={version="^0.3.0",default_features=false,features=["evcxr","all_series"]}externcrateplotters;// Import all the plotters prelude functionsuseplotters::prelude::*;// To create a figure that can be displayed in Jupyter notebook, use evcxr_figure function.// The first param is the resolution of the figure.// The second param is the closure that performes the drawing.evcxr_figure((300,100),|root|{// Do the drawingsroot.fill(&BLUE)?;// Tell plotters that everything is okOk(())})
:depplotters={version="^0.3.0",default_features=false,features=["evcxr","all_series"]}externcrateplotters;useplotters::prelude::*;evcxr_figure((320,50),|root|{root.fill(&GREEN)?;root.draw(&Text::new("Hello World from Plotters!",(15,15),("Arial",20).into_font()))?;Ok(())})
One of the very important features is,Plotters
allows drawing multiple charts in a single figure. And this is done by having sub-drawing-areas. The root drawing area is able to be splitted into smaller drawing areas, and you can always do more fine-grained splits as well.
:depplotters={version="^0.3.0",default_features=false,features=["evcxr","all_series"]}externcrateplotters;useplotters::prelude::*;useplotters::coord::Shift;pubfnsierpinski_carpet(depth:u32,drawing_area:&DrawingArea<SVGBackend,Shift>)->Result<(),Box<dynstd::error::Error>>{ifdepth>0{letsub_areas=drawing_area.split_evenly((3,3));for(idx,sub_area)in(0..).zip(sub_areas.iter()){ifidx==4{sub_area.fill(&WHITE)?;}else{sierpinski_carpet(depth-1,sub_area)?;}}}Ok(())}evcxr_figure((4800,4800),|root|{root.fill(&BLACK)?;sierpinski_carpet(5,&root)}).style("width: 200px")/* You can add CSS style to the result */
Plotters
is designed for drawing charts, plots, etc. This example demonstrate how to usePlotters
chart specific APIs to draw a chart, including, labels, axis, meshes, etc. To draw a chart on the drawin area, you need to create a chart context and do some configuration.
:depplotters={version="^0.3.0",default_features=false,features=["evcxr","all_series"]}externcrateplotters;useplotters::prelude::*;evcxr_figure((640,240),|root|{// The following code will create a chart contextletmutchart=ChartBuilder::on(&root).caption("Hello Plotters Chart Context!",("Arial",20).into_font()).build_cartesian_2d(0f32..1f32,0f32..1f32)?;// Then we can draw a series on it!chart.draw_series((1..10).map(|x|{letx=xasf32/10.0;Circle::new((x,x),5,&RED)}))?;Ok(())}).style("width:60%")
We can also makePlotters
draws common components for us, such as, meshes, axis, legend. In this section, we demonstrate how to do that.
The following code shows how we add mesh to the chart.
:depplotters={version="^0.3.0",default_features=false,features=["evcxr","all_series"]}externcrateplotters;useplotters::prelude::*;evcxr_figure((640,480),|root|{// The following code will create a chart contextletmutchart=ChartBuilder::on(&root).caption("Chart Context with Mesh",("Arial",20).into_font()).build_cartesian_2d(0f32..1f32,0f32..1f32)?;chart.configure_mesh().draw()?;Ok(())}).style("width: 60%")
Then we can add axis to the chart.
:depplotters={version="^0.3.0",default_features=false,features=["evcxr","all_series"]}externcrateplotters;useplotters::prelude::*;evcxr_figure((640,480),|root|{// The following code will create a chart contextletmutchart=ChartBuilder::on(&root).caption("Chart Context with Mesh and Axis",("Arial",20).into_font()).x_label_area_size(40).y_label_area_size(40).build_cartesian_2d(0f32..1f32,0f32..1f32)?;chart.configure_mesh().draw()?;Ok(())}).style("width: 60%")
In addition to that, we can put label text to the axis.
:depplotters={version="^0.3.0",default_features=false,features=["evcxr","all_series"]}externcrateplotters;useplotters::prelude::*;evcxr_figure((640,480),|root|{// The following code will create a chart contextletmutchart=ChartBuilder::on(&root).caption("Chart with Axis Label",("Arial",20).into_font()).x_label_area_size(40).y_label_area_size(40).build_cartesian_2d(0f32..1f32,0f32..1f32)?;chart.configure_mesh().x_desc("Here's the label for X").y_desc("Here's the label for Y").draw()?;Ok(())}).style("width: 60%")
Then let's disable mesh lines for the X axis
:depplotters={version="^0.3.0",default_features=false,features=["evcxr","all_series"]}externcrateplotters;useplotters::prelude::*;evcxr_figure((640,480),|root|{// The following code will create a chart contextletmutchart=ChartBuilder::on(&root).caption("Chart Context with Mesh and Axis",("Arial",20).into_font()).x_label_area_size(40).y_label_area_size(40).build_cartesian_2d(0f32..1f32,0f32..1f32)?;chart.configure_mesh().y_labels(10).light_line_style(&TRANSPARENT).disable_x_mesh().draw()?;Ok(())}).style("width: 60%")
To create multiple charts in a single figure, you can just split the drawing area and create multiple chart context.
:depplotters={version="^0.3.0",default_features=false,features=["evcxr","all_series"]}externcrateplotters;useplotters::prelude::*;evcxr_figure((640,480),|root|{letsub_areas=root.split_evenly((2,2));for(idx,area)in(1..).zip(sub_areas.iter()){// The following code will create a chart contextletmutchart=ChartBuilder::on(&area).caption(format!("Subchart #{}",idx),("Arial",15).into_font()).x_label_area_size(40).y_label_area_size(40).build_cartesian_2d(0f32..1f32,0f32..1f32)?;chart.configure_mesh().y_labels(10).light_line_style(&TRANSPARENT).disable_x_mesh().draw()?;}Ok(())}).style("width: 60%")
Unlike most of the plotting libraries,Plotters
doesn't actually define any types of chart. All the chart is abstracted to a concept of series. By doing so, you can put a histgoram series and a line plot series into the same chart context.The series is actually defined as an iterator of elements, just this.
This givesPlotters
a huge flexibility on drawing charts. You can implement you own types of series and uses the coordinate translation and chart elements.
There are few types of predefined series, just for convenience:
First of all, let's generate some random numbers.
:deprand={version="0.6.5"}externcraterand;userand::distributions::Normal;userand::distributions::Distribution;userand::thread_rng;letsd=0.13;letrandom_points:Vec<(f64,f64)>={letmutnorm_dist=Normal::new(0.5,sd);let(mutx_rand,muty_rand)=(thread_rng(),thread_rng());letx_iter=norm_dist.sample_iter(&mutx_rand);lety_iter=norm_dist.sample_iter(&muty_rand);x_iter.zip(y_iter).take(1000).collect()};random_points.len()
1000
It's trivial to draw a scatter plot withPlotters
. The only need is, provide a iterator of the elements as series.The following example shows how to make a 2D normal distribution figure. The red rectangle is the two sigma area and the red cross is the mean.
:depplotters={version="^0.3.0",default_features=false,features=["evcxr","all_series"]}externcrateplotters;useplotters::prelude::*;evcxr_figure((640,480),|root|{// The following code will create a chart contextletmutchart=ChartBuilder::on(&root).caption("Normal Distribution",("Arial",20).into_font()).x_label_area_size(40).y_label_area_size(40).build_ranged(0f64..1f64,0f64..1f64)?;chart.configure_mesh().disable_x_mesh().disable_y_mesh().draw()?;chart.draw_series(random_points.iter().map(|(x,y)|Circle::new((*x,*y),3,GREEN.filled())));// You can alawys freely draw on the drawing backendletarea=chart.plotting_area();lettwo_sigma=sd*2.0;area.draw(&Rectangle::new([(0.5-two_sigma,0.5-two_sigma),(0.5+two_sigma,0.5+two_sigma)],RED.mix(0.3).filled()))?;area.draw(&Cross::new((0.5,0.5),5,&RED))?;Ok(())}).style("width:60%")
We can also have histograms. For histograms, we can use the predefined histogram series struct to build the histogram easily. The following code demonstrate how to create both histogram for X and Y value ofrandom_points
.
:depplotters={version="^0.3.0",default_features=false,features=["evcxr","all_series","all_elements"]}externcrateplotters;useplotters::prelude::*;evcxr_figure((640,480),|root|{letareas=root.split_evenly((2,1));letmutcharts=vec![];// The following code will create a chart contextfor(area,name)inareas.iter().zip(["X","Y"].into_iter()){letmutchart=ChartBuilder::on(&area).caption(format!("Histogram for {}",name),("Arial",20).into_font()).x_label_area_size(40).y_label_area_size(40).build_cartesian_2d(0u32..100u32,0f64..0.5f64)?;chart.configure_mesh().disable_x_mesh().disable_y_mesh().y_labels(5).x_label_formatter(&|x|format!("{:.1}",*xasf64/100.0)).y_label_formatter(&|y|format!("{}%",(*y*100.0)asu32)).draw()?;charts.push(chart);}lethist_x=Histogram::vertical(&charts[0]).style(RED.filled()).margin(0).data(random_points.iter().map(|(x,_)|((x*100.0)asu32,0.01)));lethist_y=Histogram::vertical(&charts[0]).style(GREEN.filled()).margin(0).data(random_points.iter().map(|(_,y)|((y*100.0)asu32,0.01)));charts[0].draw_series(hist_x);charts[1].draw_series(hist_y);Ok(())}).style("width:60%")
:depplotters={version="^0.3.0",default_features=false,features=["evcxr","all_series","all_elements"]}useplotters::prelude::*;evcxr_figure((640,480),|root|{letroot=root.titled("Scatter with Histogram Example",("Arial",20).into_font())?;letareas=root.split_by_breakpoints([560],[80]);letmutx_hist_ctx=ChartBuilder::on(&areas[0]).y_label_area_size(40).build_cartesian_2d(0u32..100u32,0f64..0.5f64)?;letmuty_hist_ctx=ChartBuilder::on(&areas[3]).x_label_area_size(40).build_cartesian_2d(0f64..0.5f64,0..100u32)?;letmutscatter_ctx=ChartBuilder::on(&areas[2]).x_label_area_size(40).y_label_area_size(40).build_cartesian_2d(0f64..1f64,0f64..1f64)?;scatter_ctx.configure_mesh().disable_x_mesh().disable_y_mesh().draw()?;scatter_ctx.draw_series(random_points.iter().map(|(x,y)|Circle::new((*x,*y),3,GREEN.filled())))?;letx_hist=Histogram::vertical(&x_hist_ctx).style(RED.filled()).margin(0).data(random_points.iter().map(|(x,_)|((x*100.0)asu32,0.01)));lety_hist=Histogram::horizontal(&y_hist_ctx).style(GREEN.filled()).margin(0).data(random_points.iter().map(|(_,y)|((y*100.0)asu32,0.01)));x_hist_ctx.draw_series(x_hist)?;y_hist_ctx.draw_series(y_hist)?;Ok(())}).style("width:60%")
Plotters also support 3D plotting since 0.3. To plotting a 3D chart, it's quite simple: when constructing theChartContext
, instead ofbuild_cartesian_2d
, usebuild_cartesian_3d
instead. Then you should get a plotting environment that supports accepts 3-dimensional coordinates.
:depplotters={version="^0.3.0",default_features=false,features=["evcxr","all_series","all_elements"]}useplotters::prelude::*;evcxr_figure((640,480),|root|{letroot=root.titled("3D Plotting",("Arial",20).into_font())?;letmutchart=ChartBuilder::on(&root).build_cartesian_3d(-10.0..10.0,-10.0..10.0,-10.0..10.0)?;// Draw a red circle parallel to XOZ panelchart.draw_series(LineSeries::new((-314..314).map(|a|aasf64/100.0).map(|a|(8.0*a.cos(),0.0,8.0*a.sin())),&RED,))?;// Draw a green circle parallel to YOZ panelchart.draw_series(LineSeries::new((-314..314).map(|a|aasf64/100.0).map(|a|(0.0,8.0*a.cos(),8.0*a.sin())),&GREEN,))?;Ok(())})
Just like the 2D plots, we are able to draw the axis and axis panel easily. Unlike the 2D plots, 3D plots use the functionconfigure_axes
to configure the chart components.
:depplotters={version="^0.3.0",default_features=false,features=["evcxr","all_series","all_elements"]}useplotters::prelude::*;evcxr_figure((640,480),|root|{letroot=root.titled("3D Plotting",("Arial",20).into_font())?;letmutchart=ChartBuilder::on(&root).build_cartesian_3d(-10.0..10.0,-10.0..10.0,-10.0..10.0)?;chart.configure_axes().draw()?;// Draw a red circle parallel to XOZ panelchart.draw_series(LineSeries::new((-314..314).map(|a|aasf64/100.0).map(|a|(8.0*a.cos(),0.0,8.0*a.sin())),&RED,))?;// Draw a green circle parallel to YOZ panelchart.draw_series(LineSeries::new((-314..314).map(|a|aasf64/100.0).map(|a|(0.0,8.0*a.cos(),8.0*a.sin())),&GREEN,))?;Ok(())})
Unlike the 2D plot, 3D plot allows you to change the point of view. For example, rotate the plot or scale the plot, etc. This is done by the projection matrix, Plotters allows you override the default projection matrix, so that you can customize your view point of the 3D Plot. The following example shows how to look at the plot from top to bottom in the plot we have previously created.
:depplotters={version="^0.3.0",default_features=false,features=["evcxr","all_series","all_elements"]}useplotters::prelude::*;evcxr_figure((640,480),|root|{letroot=root.titled("3D Plotting",("Arial",20).into_font())?;letmutchart=ChartBuilder::on(&root).build_cartesian_3d(-10.0..10.0,-10.0..10.0,-10.0..10.0)?;chart.with_projection(|mutp|{p.pitch=1.5707;// 90 degreen pitch, thus we are looking the plot from topp.yaw=0.0;// Make plot's X axis parallel to screen's X axisp.into_matrix()// build the projection matrix});chart.configure_axes().draw()?;// Draw a red circle parallel to XOZ panelchart.draw_series(LineSeries::new((-314..314).map(|a|aasf64/100.0).map(|a|(8.0*a.cos(),0.0,8.0*a.sin())),&RED,))?;// Draw a green circle parallel to YOZ panelchart.draw_series(LineSeries::new((-314..314).map(|a|aasf64/100.0).map(|a|(0.0,8.0*a.cos(),8.0*a.sin())),&GREEN,))?;Ok(())})
:depplotters={version="^0.3.0",default_features=false,features=["evcxr","all_series","all_elements"]}useplotters::prelude::*;evcxr_figure((640,480),|root|{letroot=root.titled("3D Plotting",("Arial",20).into_font())?;letmutchart=ChartBuilder::on(&root).build_cartesian_3d(-10.0..10.0,-10.0..10.0,-10.0..10.0)?;chart.with_projection(|mutp|{p.pitch=0.7;p.yaw=0.7;p.scale=0.5;p.into_matrix()// build the projection matrix});chart.configure_axes().draw()?;// Draw a red circle parallel to XOZ panelchart.draw_series(LineSeries::new((-314..314).map(|a|aasf64/100.0).map(|a|(8.0*a.cos(),0.0,8.0*a.sin())),&RED,))?;// Draw a green circle parallel to YOZ panelchart.draw_series(LineSeries::new((-314..314).map(|a|aasf64/100.0).map(|a|(0.0,8.0*a.cos(),8.0*a.sin())),&GREEN,))?;Ok(())})
:depplotters={version="^0.3.0",default_features=false,features=["evcxr","all_series","all_elements"]}useplotters::prelude::*;fnpdf(x:f64,y:f64)->f64{constSDX:f64=0.1;constSDY:f64=0.1;constA:f64=5.0;letx=xasf64/10.0;lety=yasf64/10.0;A*(-x*x/2.0/SDX/SDX-y*y/2.0/SDY/SDY).exp()}evcxr_figure((640*2,480),|root|{letroot=root.titled("2D Guassian PDF",("Arial",20).into_font())?;let(left,right)=root.split_horizontally(640);for(pitch,yaw,area)invec![(0.6,0.3,left),(1.5707,0.0,right)]{letmutchart=ChartBuilder::on(&area).build_cartesian_3d(-3.0..3.0,0.0..6.0,-3.0..3.0)?;chart.with_projection(|mutp|{p.pitch=pitch;p.yaw=yaw;p.scale=0.7;p.into_matrix()// build the projection matrix});chart.configure_axes().draw()?;letseries=(-15..15).map(|x|std::iter::repeat(x).zip(-15..15)).flatten().map(|(x,z)|{letx=xasf64/5.0;letz=zasf64/5.0;Polygon::new(vec![(x,pdf(x,z),z),(x+0.2,pdf(x+0.2,z),z),(x+0.2,pdf(x+0.2,z+0.2),z+0.2),(x,pdf(x,z+0.2),z+0.2),],&HSLColor(240.0/360.0-240.0/360.0*pdf(x,z)/5.0,1.0,0.7))});chart.draw_series(series);}Ok(())})