1# Plotters - A Rust drawing library focus on data plotting for both WASM and native applications 2 3<a href="https://crates.io/crates/plotters"> 4 <img style="display: inline!important" src="https://img.shields.io/crates/v/plotters.svg"></img> 5</a> 6<a href="https://docs.rs/plotters"> 7 <img style="display: inline!important" src="https://docs.rs/plotters/badge.svg"></img> 8</a> 9<a href="https://plotters-rs.github.io/rustdoc/plotters/"> 10 <img style="display: inline! important" src="https://img.shields.io/badge/docs-development-lightgrey.svg"></img> 11</a> 12<a href="https://travis-ci.org/38/plotters"> 13 <img style="display: inline! important" src="https://travis-ci.org/38/plotters.svg?branch=master"></img> 14</a> 15<a href="https://codecov.io/gh/38/plotters"> 16 <img style="display: inline! important" src="https://codecov.io/gh/38/plotters/branch/master/graph/badge.svg" /> 17</a> 18 19Plotters is drawing library designed for rendering figures, plots, and charts, in pure rust. Plotters supports various types of back-ends, 20including bitmap, vector graph, piston window, GTK/Cairo and WebAssembly. 21 22- A new Plotters Developer's Guide is working in progress. The preview version is available at [here](https://plotters-rs.github.io/book). 23- To try Plotters with interactive Jupyter notebook, or view [here](https://plotters-rs.github.io/plotters-doc-data/evcxr-jupyter-integration.html) for the static HTML version. 24- To view the WASM example, go to this [link](https://plumberserver.com/plotters-wasm-demo/index.html) 25- Currently we have all the internal code ready for console plotting, but a console based backend is still not ready. See [this example](https://github.com/38/plotters/blob/master/examples/console.rs) for how to plotting on Console with a customized backend. 26 27## Gallery 28 29To view the source code for each example, please click on the example image. 30 31<a href="https://github.com/38/plotters/blob/master/examples/chart.rs"> 32 <img src="https://plotters-rs.github.io/plotters-doc-data/sample.png" class="galleryItem" width=200px></img> 33</a> 34 35<a href="https://github.com/38/plotters/blob/master/examples/stock.rs"> 36 <img src="https://plotters-rs.github.io/plotters-doc-data/stock.png" class="galleryItem" width=200px></img> 37</a> 38 39<a href="https://github.com/38/plotters/blob/master/examples/histogram.rs"> 40 <img src="https://plotters-rs.github.io/plotters-doc-data/histogram.png" class="galleryItem" width=200px></img> 41</a> 42 43<a href="https://github.com/38/plotters#quick-start"> 44 <img src="https://plotters-rs.github.io/plotters-doc-data/0.png" class="galleryItem" width=200px></img> 45</a> 46 47<a href="#"> 48 <img src="https://plotters-rs.github.io/plotters-doc-data/console-2.png" class="galleryItem" width=200px></img> 49</a> 50 51<a href="https://github.com/38/plotters/blob/master/examples/mandelbrot.rs"> 52 <img src="https://plotters-rs.github.io/plotters-doc-data/mandelbrot.png" class="galleryItem" width=200px></img> 53</a> 54 55<a href="https://github.com/38/plotters#trying-with-jupyter-evcxr-kernel-interactively"> 56 <img src="https://plotters-rs.github.io/plotters-doc-data/evcxr_animation.gif" class="galleryItem" width=200px></img> 57</a> 58 59 60<a href="https://github.com/38/plotters/tree/master/examples/piston-demo"> 61 <img src="https://plotters-rs.github.io/plotters-doc-data/plotters-piston.gif" class="galleryItem" width=200px></img> 62</a> 63 64<a href="https://github.com/38/plotters/blob/master/examples/normal-dist.rs"> 65 <img src="https://plotters-rs.github.io/plotters-doc-data/normal-dist.png" class="galleryItem" width=200px></img> 66</a> 67 68<a href="https://github.com/38/plotters/blob/master/examples/two-scales.rs"> 69 <img src="https://plotters-rs.github.io/plotters-doc-data/twoscale.png" class="galleryItem" width=200px></img> 70</a> 71 72<a href="https://github.com/38/plotters/blob/master/examples/matshow.rs"> 73 <img src="https://plotters-rs.github.io/plotters-doc-data/matshow.png" class="galleryItem" width=200px></img> 74</a> 75 76<a href="https://github.com/38/plotters/blob/master/examples/sierpinski.rs"> 77 <img src="https://plotters-rs.github.io/plotters-doc-data/sierpinski.png" class="galleryItem" width=200px></img> 78</a> 79 80<a href="https://github.com/38/plotters/blob/master/examples/normal-dist2.rs"> 81 <img src="https://plotters-rs.github.io/plotters-doc-data/normal-dist2.png" class="galleryItem" width=200px></img> 82</a> 83 84<a href="https://github.com/38/plotters/blob/master/examples/errorbar.rs"> 85 <img src="https://plotters-rs.github.io/plotters-doc-data/errorbar.png" class="galleryItem" width=200px></img> 86</a> 87 88<a href="https://github.com/38/plotters/blob/master/examples/slc-temp.rs"> 89 <img src="https://plotters-rs.github.io/plotters-doc-data/slc-temp.png" class="galleryItem" width=200px></img> 90</a> 91 92<a href="https://github.com/38/plotters/blob/master/examples/area-chart.rs"> 93 <img src="https://plotters-rs.github.io/plotters-doc-data/area-chart.png" class="galleryItem" width=200px></img> 94</a> 95 96<a href="https://github.com/38/plotters/blob/master/examples/snowflake.rs"> 97 <img src="https://plotters-rs.github.io/plotters-doc-data/snowflake.png" class="galleryItem" width=200px></img> 98</a> 99 100<a href="https://github.com/38/plotters/blob/master/examples/animation.rs"> 101 <img src="https://plotters-rs.github.io/plotters-doc-data/animation.gif" class="galleryItem" width=200px></img> 102</a> 103 104<a href="https://github.com/38/plotters/blob/master/examples/console.rs"> 105 <img src="https://plotters-rs.github.io/plotters-doc-data/console-example.png" class="galleryItem" width=200px></img> 106</a> 107 108<a href="https://github.com/38/plotters/blob/master/examples/console.rs"> 109 <img src="https://plotters-rs.github.io/plotters-doc-data/console.png" class="galleryItem" width=200px></img> 110</a> 111 112<a href="https://github.com/38/plotters/blob/master/examples/blit-bitmap.rs"> 113 <img src="https://plotters-rs.github.io/plotters-doc-data/blit-bitmap.png" class="galleryItem" width=200px></img> 114</a> 115 116<a href="https://github.com/38/plotters/blob/master/examples/boxplot.rs"> 117 <img src="https://plotters-rs.github.io/plotters-doc-data/boxplot.svg" class="galleryItem" width=200px></img> 118</a> 119 120<a href="https://github.com/38/plotters/blob/master/examples/3d-plot.rs"> 121 <img src="https://plotters-rs.github.io/plotters-doc-data/3d-plot.svg" class="galleryItem" width=200px></img> 122</a> 123 124 125## Table of Contents 126 * [Gallery](#gallery) 127 * [Quick Start](#quick-start) 128 * [Trying with Jupyter evcxr Kernel Interactively](#trying-with-jupyter-evcxr-kernel-interactively) 129 * [Interactive Tutorial with Jupyter Notebook](#interactive-tutorial-with-jupyter-notebook) 130 * [Plotting in Rust](#plotting-in-rust) 131 * [Plotting on HTML5 canvas with WASM Backend](#plotting-on-html5-canvas-with-wasm-backend) 132 * [What types of figure are supported?](#what-types-of-figure-are-supported) 133 * [Concepts by examples](#concepts-by-examples) 134 + [Drawing Back-ends](#drawing-backends) 135 + [Drawing Area](#drawing-area) 136 + [Elements](#elements) 137 + [Composable Elements](#composable-elements) 138 + [Chart Context](#chart-context) 139 * [Misc](#misc) 140 + [Development Version](#development-version) 141 + [Reducing Depending Libraries && Turning Off Backends](#reducing-depending-libraries--turning-off-backends) 142 + [List of Features](#list-of-features) 143 * [FAQ List](#faq-list) 144 145## Quick Start 146 147To use Plotters, you can simply add Plotters into your `Cargo.toml` 148```toml 149[dependencies] 150plotters = "^0.3.0" 151``` 152 153And the following code draws a quadratic function. `src/main.rs`, 154 155```rust 156use plotters::prelude::*; 157fn main() -> Result<(), Box<dyn std::error::Error>> { 158 let root = BitMapBackend::new("plotters-doc-data/0.png", (640, 480)).into_drawing_area(); 159 root.fill(&WHITE)?; 160 let mut chart = ChartBuilder::on(&root) 161 .caption("y=x^2", ("sans-serif", 50).into_font()) 162 .margin(5) 163 .x_label_area_size(30) 164 .y_label_area_size(30) 165 .build_ranged(-1f32..1f32, -0.1f32..1f32)?; 166 167 chart.configure_mesh().draw()?; 168 169 chart 170 .draw_series(LineSeries::new( 171 (-50..=50).map(|x| x as f32 / 50.0).map(|x| (x, x * x)), 172 &RED, 173 ))? 174 .label("y = x^2") 175 .legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &RED)); 176 177 chart 178 .configure_series_labels() 179 .background_style(&WHITE.mix(0.8)) 180 .border_style(&BLACK) 181 .draw()?; 182 183 Ok(()) 184} 185``` 186 187![](https://plotters-rs.github.io/plotters-doc-data/0.png) 188 189 190## Trying with Jupyter evcxr Kernel Interactively 191 192Plotters now supports integrate with `evcxr` and is able to interactively drawing plots in Jupyter Notebook. 193The feature `evcxr` should be enabled when including Plotters to Jupyter Notebook. 194 195The following code shows a minimal example of this. 196 197```text 198:dep plotters = { git = "https://github.com/38/plotters", default_features = false, features = ["evcxr"] } 199extern crate plotters; 200use plotters::prelude::*; 201 202let figure = evcxr_figure((640, 480), |root| { 203 root.fill(&WHITE); 204 let mut chart = ChartBuilder::on(&root) 205 .caption("y=x^2", ("Arial", 50).into_font()) 206 .margin(5) 207 .x_label_area_size(30) 208 .y_label_area_size(30) 209 .build_ranged(-1f32..1f32, -0.1f32..1f32)?; 210 211 chart.configure_mesh().draw()?; 212 213 chart.draw_series(LineSeries::new( 214 (-50..=50).map(|x| x as f32 / 50.0).map(|x| (x, x * x)), 215 &RED, 216 )).unwrap() 217 .label("y = x^2") 218 .legend(|(x,y)| PathElement::new(vec![(x,y), (x + 20,y)], &RED)); 219 220 chart.configure_series_labels() 221 .background_style(&WHITE.mix(0.8)) 222 .border_style(&BLACK) 223 .draw()?; 224 Ok(()) 225}); 226figure 227``` 228 229<img src="https://plotters-rs.github.io/plotters-doc-data/evcxr_animation.gif" width="450px"></img> 230 231## Interactive Tutorial with Jupyter Notebook 232 233*This tutorial is now working in progress and isn't complete* 234 235Thanks to the evcxr, now we have an interactive tutorial for Plotters! 236To use the interactive notebook, you must have Jupyter and evcxr installed on your computer. 237Follow the instruction on [this page](https://github.com/google/evcxr/tree/master/evcxr_jupyter) below to install it. 238 239After that, you should be able to start your Jupyter server locally and load the tutorial! 240 241```bash 242git clone https://github.com/38/plotters-doc-data 243cd plotteres-doc-data 244jupyter notebook 245``` 246 247And select the notebook called `evcxr-jupyter-integration.ipynb`. 248 249Also, there's a static HTML version of this notebook available at the [this location](https://plumberserver.com/plotters-docs/evcxr-jupyter-integration.html) 250 251## Plotting in Rust 252 253Rust is a perfect language for data visualization. Although there are many mature visualization libraries in many different languages. 254But Rust is one of the best languages fits the need. 255 256* **Easy to use** Rust has a very good iterator system built into the standard library. With the help of iterators, 257Plotting in Rust can be as easy as most of the high-level programming languages. The Rust based plotting library 258can be very easy to use. 259 260* **Fast** If you need rendering a figure with trillions of data points, 261Rust is a good choice. Rust's performance allows you to combine data processing step 262and rendering step into a single application. When plotting in high-level programming languages, 263e.g. Javascript or Python, data points must be down-sampled before feeding into the plotting 264program because of the performance considerations. Rust is fast enough to do the data processing and visualization 265within a single program. You can also integrate the 266figure rendering code into your application handling a huge amount of data and visualize it in real-time. 267 268* **WebAssembly Support** Rust is one of few the language with the best WASM support. Plotting in Rust could be 269very useful for visualization on a web page and would have a huge performance improvement comparing to Javascript. 270 271## Plotting on HTML5 canvas with WASM Backend 272 273Plotters currently supports backend that uses the HTML5 canvas. To use the WASM support, you can simply use 274`CanvasBackend` instead of other backend and all other API remains the same! 275 276There's a small demo for Plotters + WASM under `examples/wasm-demo` directory of this repo. 277To play with the deployed version, follow this [link](https://plumberserver.com/plotters-wasm-demo/index.html). 278 279 280## What types of figure are supported? 281 282Plotters is not limited to any specific type of figure. 283You can create your own types of figures easily with the Plotters API. 284 285But Plotters provides some builtin figure types for convenience. 286Currently, we support line series, point series, candlestick series, and histogram. 287And the library is designed to be able to render multiple figure into a single image. 288But Plotter is aimed to be a platform that is fully extendable to support any other types of figure. 289 290## Concepts by examples 291 292### Drawing Back-ends 293Plotters can use different drawing back-ends, including SVG, BitMap, and even real-time rendering. For example, a bitmap drawing backend. 294 295```rust 296use plotters::prelude::*; 297fn main() -> Result<(), Box<dyn std::error::Error>> { 298 // Create a 800*600 bitmap and start drawing 299 let mut backend = BitMapBackend::new("plotters-doc-data/1.png", (300, 200)); 300 // And if we want SVG backend 301 // let backend = SVGBackend::new("output.svg", (800, 600)); 302 backend.draw_rect((50, 50), (200, 150), &RED, true)?; 303 Ok(()) 304} 305``` 306 307![](https://plotters-rs.github.io/plotters-doc-data/1.png) 308 309### Drawing Area 310Plotters uses a concept called drawing area for layout purpose. 311Plotters support multiple integrating into a single image. 312This is done by creating sub-drawing-areas. 313 314Besides that, the drawing area also allows the customized coordinate system, by doing so, the coordinate mapping is done by the drawing area automatically. 315 316```rust 317use plotters::prelude::*; 318fn main() -> Result<(), Box<dyn std::error::Error>> { 319 let root_drawing_area = 320 BitMapBackend::new("plotters-doc-data/2.png", (300, 200)).into_drawing_area(); 321 // And we can split the drawing area into 3x3 grid 322 let child_drawing_areas = root_drawing_area.split_evenly((3, 3)); 323 // Then we fill the drawing area with different color 324 for (area, color) in child_drawing_areas.into_iter().zip(0..) { 325 area.fill(&Palette99::pick(color))?; 326 } 327 Ok(()) 328} 329``` 330 331![](https://plotters-rs.github.io/plotters-doc-data/2.png) 332 333### Elements 334 335In Plotters, elements are build blocks of figures. All elements are able to draw on a drawing area. 336There are different types of built-in elements, like lines, texts, circles, etc. 337You can also define your own element in the application code. 338 339You may also combine existing elements to build a complex element. 340 341To learn more about the element system, please read the [element module documentation](./element/index.html). 342 343```rust 344use plotters::prelude::*; 345fn main() -> Result<(), Box<dyn std::error::Error>> { 346 let root = BitMapBackend::new("plotters-doc-data/3.png", (300, 200)).into_drawing_area(); 347 root.fill(&WHITE)?; 348 // Draw an circle on the drawing area 349 root.draw(&Circle::new( 350 (100, 100), 351 50, 352 Into::<ShapeStyle>::into(&GREEN).filled(), 353 ))?; 354 Ok(()) 355} 356``` 357 358![](https://plotters-rs.github.io/plotters-doc-data/3.png) 359 360### Composable Elements 361 362Besides the built-in elements, elements can be composed into a logic group we called composed elements. 363When composing new elements, the upper-left corner is given in the target coordinate, and a new pixel-based 364coordinate which has the upper-left corner defined as `(0,0)` is used for further element composition purpose. 365 366For example, we can have an element which includes a dot and its coordinate. 367 368```rust 369use plotters::prelude::*; 370use plotters::coord::types::RangedCoordf32; 371 372fn main() -> Result<(), Box<dyn std::error::Error>> { 373 let root = BitMapBackend::new("plotters-doc-data/4.png", (640, 480)).into_drawing_area(); 374 375 root.fill(&RGBColor(240, 200, 200))?; 376 377 let root = root.apply_coord_spec(Cartesian2d::<RangedCoordf32, RangedCoordf32>::new( 378 0f32..1f32, 379 0f32..1f32, 380 (0..640, 0..480), 381 )); 382 383 let dot_and_label = |x: f32, y: f32| { 384 return EmptyElement::at((x, y)) 385 + Circle::new((0, 0), 3, ShapeStyle::from(&BLACK).filled()) 386 + Text::new( 387 format!("({:.2},{:.2})", x, y), 388 (10, 0), 389 ("sans-serif", 15.0).into_font(), 390 ); 391 }; 392 393 root.draw(&dot_and_label(0.5, 0.6))?; 394 root.draw(&dot_and_label(0.25, 0.33))?; 395 root.draw(&dot_and_label(0.8, 0.8))?; 396 Ok(()) 397} 398``` 399 400![](https://plotters-rs.github.io/plotters-doc-data/4.png) 401 402### Chart Context 403 404In order to draw a chart, Plotters need a data object built on top of the drawing area called `ChartContext`. 405The chart context defines even higher level constructs compare to the drawing area. 406For example, you can define the label areas, meshes, and put a data series onto the drawing area with the help 407of the chart context object. 408 409```rust 410use plotters::prelude::*; 411fn main() -> Result<(), Box<dyn std::error::Error>> { 412 let root = BitMapBackend::new("plotters-doc-data/5.png", (640, 480)).into_drawing_area(); 413 root.fill(&WHITE); 414 let root = root.margin(10, 10, 10, 10); 415 // After this point, we should be able to draw construct a chart context 416 let mut chart = ChartBuilder::on(&root) 417 // Set the caption of the chart 418 .caption("This is our first plot", ("sans-serif", 40).into_font()) 419 // Set the size of the label region 420 .x_label_area_size(20) 421 .y_label_area_size(40) 422 // Finally attach a coordinate on the drawing area and make a chart context 423 .build_cartesian_2d(0f32..10f32, 0f32..10f32)?; 424 425 // Then we can draw a mesh 426 chart 427 .configure_mesh() 428 // We can customize the maximum number of labels allowed for each axis 429 .x_labels(5) 430 .y_labels(5) 431 // We can also change the format of the label text 432 .y_label_formatter(&|x| format!("{:.3}", x)) 433 .draw()?; 434 435 // And we can draw something in the drawing area 436 chart.draw_series(LineSeries::new( 437 vec![(0.0, 0.0), (5.0, 5.0), (8.0, 7.0)], 438 &RED, 439 ))?; 440 // Similarly, we can draw point series 441 chart.draw_series(PointSeries::of_element( 442 vec![(0.0, 0.0), (5.0, 5.0), (8.0, 7.0)], 443 5, 444 &RED, 445 &|c, s, st| { 446 return EmptyElement::at(c) // We want to construct a composed element on-the-fly 447 + Circle::new((0,0),s,st.filled()) // At this point, the new pixel coordinate is established 448 + Text::new(format!("{:?}", c), (10, 0), ("sans-serif", 10).into_font()); 449 }, 450 ))?; 451 Ok(()) 452} 453``` 454 455![](https://plotters-rs.github.io/plotters-doc-data/5.png) 456 457## Misc 458 459### Development Version 460 461To use the latest development version, pull https://github.com/38/plotters.git. In `Cargo.toml` 462 463```toml 464[dependencies] 465plotters = { git = "https://github.com/38/plotters.git" } 466``` 467 468### Reducing Depending Libraries && Turning Off Backends 469Plotters now supports use features to control the backend dependencies. By default, `BitMapBackend` and `SVGBackend` are supported, 470use `default_features = false` in the dependency description in `Cargo.toml` and you can cherry-pick the backend implementations. 471 472- `svg` Enable the `SVGBackend` 473- `bitmap` Enable the `BitMapBackend` 474 475For example, the following dependency description would avoid compiling with bitmap support: 476 477```toml 478[dependencies] 479plotters = { git = "https://github.com/38/plotters.git", default_features = false, features = ["svg"] } 480``` 481 482The library also allows consumers to make use of the [`Palette`](https://crates.io/crates/palette/) crate's color types by default. 483This behavior can also be turned off by setting `default_features = false`. 484 485### List of Features 486 487This is the full list of features that is defined by `Plotters` crate. 488Use `default_features = false` to disable those default enabled features, 489and then you should be able to cherry-pick what features you want to include into `Plotters` crate. 490By doing so, you can minimize the number of dependencies down to only `itertools` and compile time is less than 6s. 491 492The following list is a complete list of features that can be opt in and out. 493 494- Tier 1 drawing backends 495 496| Name | Description | Additional Dependency |Default?| 497|---------|--------------|--------|------------| 498| bitmap\_encoder | Allow `BitMapBackend` save the result to bitmap files | image, rusttype, font-kit | Yes | 499| svg\_backend | Enable `SVGBackend` Support | None | Yes | 500| bitmap\_gif| Opt-in GIF animation Rendering support for `BitMapBackend`, implies `bitmap` enabled | gif | Yes | 501 502- Font manipulation features 503 504| Name | Description | Additional Dependency |Default?| 505|---------|--------------|--------|------------| 506| ttf | Allows TrueType font support | rusttype, font-kit | Yes | 507 508- Coordinate features 509 510| Name | Description | Additional Dependency |Default?| 511|---------|--------------|--------|------------| 512| datetime | Eanble the date and time coordinate support | chrono | Yes | 513 514- Element, series and util functions 515 516| Name | Description | Additional Dependency |Default?| 517|---------|--------------|--------|------------| 518| errorbar | The errorbar element support | None | Yes | 519| candlestick | The candlestick element support | None | Yes | 520| boxplot | The boxplot element support | None | Yes | 521| area\_series | The area series support | None | Yes | 522| line\_series | The line series support | None | Yes | 523| histogram | The histogram series support | None | Yes | 524| point\_series| The point series support | None | Yes | 525 526- Misc 527 528| Name | Description | Additional Dependency |Default?| 529|---------|--------------|--------|------------| 530| deprecated\_items | This feature allows use of deprecated items which is going to be removed in the future | None | Yes | 531| debug | Enable the code used for debugging | None | No | 532 533 534## FAQ List 535 536* Why does the WASM example break on my machine ? 537 538 The WASM example requires using `wasm32` target to build. Using `cargo build` is likely to use the default target 539 which in most of the case is any of the x86 target. Thus you need add `--target=wasm32-unknown-unknown` in the cargo 540 parameter list to build it. 541 542* How to draw text/circle/point/rectangle/... on the top of chart ? 543 544 As you may realized, Plotters is a drawing library rather than a traditional data plotting library, 545 you have the freedom to draw anything you want on the drawing area. 546 Use `DrawingArea::draw` to draw any element on the drawing area. 547 548 549