Skip to content

Boxplot element and category coordinate have been added. #83

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Nov 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .cargo/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[target.wasm32-unknown-unknown]
runner = 'wasm-bindgen-test-runner'
53 changes: 52 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,61 @@ fn foo(param_1: u32, param_2: u32) -> u32{ 0 }d

## Top Level Documentation and Readme

Please notice we put almost same content for top level rustdoc and `README.md`. Thus the both part are gennerated by script.
Please notice we put almost same content for top level rustdoc and `README.md`. Thus the both part are generated by script.
If you need to modify the readme and documentation, please change the template at [doc-template/readme.template.md](https://github.com/38/plotters/blob/master/doc-template/readme.template.md) and
use the following command to synchronize the doc to both `src/lib.rs` and `README.md`.

```bash
bash doc-template/update-readme.sh
```

## Testing Notes

As the project is intended to work in various environments, it's important to test its all features. The notes below may help you with that task.

### Native

Testing all features:

```bash
cargo test --all-features
```

### WebAssembly

Wasm target is not tested by default, and you may want to use [wasm-bindgen](https://rustwasm.github.io/docs/wasm-bindgen/wasm-bindgen-test/usage.html) CLI tool.

Installation:

```bash
rustup target add wasm32-unknown-unknown
cargo install wasm-bindgen-cli
```

Additionally, the web browser and its driver should be available, please see [Configuring Which Browser is Used](https://rustwasm.github.io/wasm-bindgen/wasm-bindgen-test/browsers.html#configuring-which-browser-is-used-1). For example, to use Firefox, its binary (`firefox`) and [geckodriver](https://github.com/mozilla/geckodriver/releases) must be on your `$PATH`.

Usage (only library tests are supported for now):

```bash
cargo test --lib --target wasm32-unknown-unknown
```

For the debugging you could set the `NO_HEADLESS=1` environment variable to run the tests using the local server instead of the headless browser.

### Code Coverage

For for the code coverage information you may want to use [cargo-tarpaulin](https://crates.io/crates/cargo-tarpaulin). Please note that it works with x86_64 GNU/Linux only, and the doc tests coverage require nightly Rust.

Installation ([pycobertura](https://pypi.python.org/pypi/pycobertura) is used to get the detailed report about the coverage):

```bash
cargo install cargo-tarpaulin
pip install pycobertura
```

Usage:

```bash
cargo tarpaulin --all-features --run-types Tests Doctests -o Xml --output-dir target/test
pycobertura show target/test/cobertura.xml
```
9 changes: 8 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ chrono = { version = "0.4.9", optional = true }
svg = { version = "0.6.0", optional = true }
palette = { version = "^0.4", default-features = false, optional = true }
gif = { version = "^0.10.3", optional = true }
cairo-rs = { version = "0.7.1", optional = true }

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
rusttype = "0.8.1"
Expand All @@ -31,6 +30,11 @@ optional = true
default_features = false
features = ["jpeg", "png_codec", "bmp"]

[target.'cfg(not(target_arch = "wasm32"))'.dependencies.cairo-rs]
version = "0.7.1"
optional = true
features = ["ps"]

[target.'cfg(target_arch = "wasm32")'.dependencies]
js-sys= "0.3.29"
wasm-bindgen = "0.2.52"
Expand Down Expand Up @@ -59,6 +63,9 @@ criterion = "0.3.0"
rayon = "1.2.0"
rand_xorshift = "0.2.0"

[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
wasm-bindgen-test = "0.3.4"

[[bench]]
name = "benchmark"
harness = false
Expand Down
1 change: 1 addition & 0 deletions benches/benches/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod data;
pub mod parallel;
pub mod rasterizer;
3 changes: 2 additions & 1 deletion benches/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ mod benches;

criterion_main! {
benches::parallel::parallel_group,
benches::rasterizer::rasterizer_group
benches::rasterizer::rasterizer_group,
benches::data::quartiles_group
}
219 changes: 219 additions & 0 deletions examples/boxplot.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
use itertools::Itertools;
use plotters::data::fitting_range;
use plotters::prelude::*;
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::env;
use std::fs;
use std::io::{self, prelude::*, BufReader};

fn read_data<BR: BufRead>(reader: BR) -> HashMap<(String, String), Vec<f64>> {
let mut ds = HashMap::new();
for l in reader.lines() {
let line = l.unwrap();
let tuple: Vec<&str> = line.split('\t').collect();
if tuple.len() == 3 {
let key = (String::from(tuple[0]), String::from(tuple[1]));
let entry = ds.entry(key).or_insert_with(Vec::new);
entry.push(tuple[2].parse::<f64>().unwrap());
}
}
ds
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
let root = SVGBackend::new("plotters-doc-data/boxplot.svg", (1024, 768)).into_drawing_area();
root.fill(&WHITE)?;

let (upper, lower) = root.split_vertically(512);

let args: Vec<String> = env::args().collect();

let ds = if args.len() < 2 {
read_data(io::Cursor::new(get_data()))
} else {
let file = fs::File::open(&args[1])?;
read_data(BufReader::new(file))
};
let dataset: Vec<(String, String, Quartiles)> = ds
.iter()
.map(|(k, v)| (k.0.clone(), k.1.clone(), Quartiles::new(&v)))
.collect();

let category = Category::new(
"Host",
dataset
.iter()
.unique_by(|x| x.0.clone())
.sorted_by(|a, b| b.2.median().partial_cmp(&a.2.median()).unwrap())
.map(|x| x.0.clone())
.collect(),
);

let mut colors = (0..).map(Palette99::pick);
let mut offsets = (-12..).step_by(24);
let mut series = BTreeMap::new();
for x in dataset.iter() {
let entry = series
.entry(x.1.clone())
.or_insert_with(|| (Vec::new(), colors.next().unwrap(), offsets.next().unwrap()));
entry.0.push((x.0.clone(), &x.2));
}

let values: Vec<f32> = dataset
.iter()
.map(|x| x.2.values().to_vec())
.flatten()
.collect();
let values_range = fitting_range(values.iter());

let mut chart = ChartBuilder::on(&upper)
.x_label_area_size(40)
.y_label_area_size(120)
.caption("Ping Boxplot", ("sans-serif", 20).into_font())
.build_ranged(
values_range.start - 1.0..values_range.end + 1.0,
category.range(),
)?;

chart
.configure_mesh()
.x_desc("Ping, ms")
.y_desc(category.name())
.y_labels(category.len())
.line_style_2(&WHITE)
.draw()?;

for (label, (values, style, offset)) in &series {
chart
.draw_series(values.iter().map(|x| {
Boxplot::new_horizontal(category.get(&x.0).unwrap(), &x.1)
.width(20)
.whisker_width(0.5)
.style(style)
.offset(*offset)
}))?
.label(label)
.legend(move |(x, y)| Rectangle::new([(x - 5, y - 5), (x + 5, y + 5)], style.filled()));
}
chart
.configure_series_labels()
.position(SeriesLabelPosition::UpperRight)
.background_style(WHITE.filled())
.border_style(&BLACK.mix(0.5))
.draw()?;

let drawing_areas = lower.split_evenly((1, 2));
let (left, right) = (&drawing_areas[0], &drawing_areas[1]);

let quartiles_a = Quartiles::new(&[
6.0, 7.0, 15.9, 36.9, 39.0, 40.0, 41.0, 42.0, 43.0, 47.0, 49.0,
]);
let quartiles_b = Quartiles::new(&[16.0, 17.0, 50.0, 60.0, 40.2, 41.3, 42.7, 43.3, 47.0]);
let category_ab = Category::new("", vec!["a", "b"]);
let values_range = fitting_range(
quartiles_a
.values()
.iter()
.chain(quartiles_b.values().iter()),
);
let mut chart = ChartBuilder::on(&left)
.x_label_area_size(40)
.y_label_area_size(40)
.caption("Vertical Boxplot", ("sans-serif", 20).into_font())
.build_ranged(
category_ab.get(&"a").unwrap()..category_ab.get(&"b").unwrap(),
values_range.start - 10.0..values_range.end + 10.0,
)?;

chart.configure_mesh().line_style_2(&WHITE).draw()?;
chart.draw_series(vec![
Boxplot::new_vertical(category_ab.get(&"a").unwrap(), &quartiles_a),
Boxplot::new_vertical(category_ab.get(&"b").unwrap(), &quartiles_b),
])?;

let mut chart = ChartBuilder::on(&right)
.x_label_area_size(40)
.y_label_area_size(40)
.caption("Horizontal Boxplot", ("sans-serif", 20).into_font())
.build_ranged(-30f32..90f32, 0..3)?;

chart.configure_mesh().line_style_2(&WHITE).draw()?;
chart.draw_series(vec![
Boxplot::new_horizontal(1, &quartiles_a),
Boxplot::new_horizontal(2, &Quartiles::new(&[30])),
])?;

Ok(())
}

fn get_data() -> String {
String::from(
"
1.1.1.1 wireless 41.6
1.1.1.1 wireless 32.5
1.1.1.1 wireless 33.1
1.1.1.1 wireless 32.3
1.1.1.1 wireless 36.7
1.1.1.1 wireless 32.0
1.1.1.1 wireless 33.1
1.1.1.1 wireless 32.0
1.1.1.1 wireless 32.9
1.1.1.1 wireless 32.7
1.1.1.1 wireless 34.5
1.1.1.1 wireless 36.5
1.1.1.1 wireless 31.9
1.1.1.1 wireless 33.7
1.1.1.1 wireless 32.6
1.1.1.1 wireless 35.1
8.8.8.8 wireless 42.3
8.8.8.8 wireless 32.9
8.8.8.8 wireless 32.9
8.8.8.8 wireless 34.3
8.8.8.8 wireless 32.0
8.8.8.8 wireless 33.3
8.8.8.8 wireless 31.5
8.8.8.8 wireless 33.1
8.8.8.8 wireless 33.2
8.8.8.8 wireless 35.9
8.8.8.8 wireless 42.3
8.8.8.8 wireless 34.1
8.8.8.8 wireless 34.2
8.8.8.8 wireless 34.2
8.8.8.8 wireless 32.4
8.8.8.8 wireless 33.0
1.1.1.1 wired 31.8
1.1.1.1 wired 28.6
1.1.1.1 wired 29.4
1.1.1.1 wired 28.8
1.1.1.1 wired 28.2
1.1.1.1 wired 28.8
1.1.1.1 wired 28.4
1.1.1.1 wired 28.6
1.1.1.1 wired 28.3
1.1.1.1 wired 28.5
1.1.1.1 wired 28.5
1.1.1.1 wired 28.5
1.1.1.1 wired 28.4
1.1.1.1 wired 28.6
1.1.1.1 wired 28.4
1.1.1.1 wired 28.9
8.8.8.8 wired 33.3
8.8.8.8 wired 28.4
8.8.8.8 wired 28.7
8.8.8.8 wired 29.1
8.8.8.8 wired 29.6
8.8.8.8 wired 28.9
8.8.8.8 wired 28.6
8.8.8.8 wired 29.3
8.8.8.8 wired 28.6
8.8.8.8 wired 29.1
8.8.8.8 wired 28.7
8.8.8.8 wired 28.3
8.8.8.8 wired 28.3
8.8.8.8 wired 28.6
8.8.8.8 wired 29.4
8.8.8.8 wired 33.1
",
)
}
14 changes: 7 additions & 7 deletions examples/console.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,24 @@ enum PixelState {
}

impl PixelState {
fn to_char(&self) -> char {
fn to_char(self) -> char {
match self {
Self::Empty => ' ',
Self::HLine => '-',
Self::VLine => '|',
Self::Cross => '+',
Self::Pixel => '.',
Self::Text(c) => *c,
Self::Text(c) => c,
Self::Circle(filled) => {
if *filled {
if filled {
'@'
} else {
'O'
}
}
}
}

fn update(&mut self, new_state: PixelState) {
let next_state = match (*self, new_state) {
(Self::HLine, Self::VLine) => Self::Cross,
Expand Down Expand Up @@ -123,12 +124,11 @@ impl DrawingBackend for TextDrawingBackend {
Ok((text.len() as u32, 1))
}

fn draw_text<'a>(
fn draw_text(
&mut self,
text: &str,
_font: &FontDesc<'a>,
_style: &TextStyle,
pos: (i32, i32),
_color: &RGBAColor,
) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
let offset = pos.1.max(0) * 100 + pos.0.max(0);
for (idx, chr) in (offset..).zip(text.chars()) {
Expand All @@ -150,7 +150,7 @@ where
.set_label_area_size(LabelAreaPosition::Left, (5i32).percent_width())
.set_label_area_size(LabelAreaPosition::Bottom, (10i32).percent_height())
.set_label_area_size(LabelAreaPosition::Bottom, (10i32).percent_height())
.build_ranged(-3.14..3.14, -1.2..1.2)?;
.build_ranged(-std::f64::consts::PI..std::f64::consts::PI, -1.2..1.2)?;

chart
.configure_mesh()
Expand Down
2 changes: 1 addition & 1 deletion examples/piston-demo/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Realtime CPU Usage by Plotters + Piston

This is a demo that demonstrate using Plotters along with Piston for dynmaic rendering.
This is a demo that demonstrate using Plotters along with Piston for dynamic rendering.

To try the demo use

Expand Down
2 changes: 1 addition & 1 deletion examples/wasm-demo/www/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"wasm",
"rust",
"webpack",
"visualization"
"visualization"
],
"author": "Plotters Developers",
"license": "MIT",
Expand Down
Loading