# How to Create a Graph Like Criterion?

I'm wanting to create my own graph like this one that criterion created, but based on my own list of numbers. I'm using the plotters library ( which is amazing, thank you @381  ), but I don't know how to do the math to get the density value used for the y axis. Does anybody know of an easy crate or else just a code snippet that would give me that density value for a slice of `f64`s?

Not sure what you mean by "density" value? Do you mean the frequency of a value in a given set? Since these are `f64`s, you can have rounding errors, hence I cast to integers so that it additionally satisfies `Eq`:

``````use std::collections::HashMap;

const SCALE: f64 = 1.0;

fn main() {
let given_slice: &[f64] = &[1., 2., 3.];

let mut hashmap = HashMap::<i128, usize>::new();

given_slice
.iter()
.for_each(
|x| {
let rounded = (x * SCALE) as i128;
*hashmap
.entry(rounded)
.or_insert(0)
+= 1;
}
);
}
``````

If you mean something more like calculating the values between the ticks on the Y-axis, then something like this would work:

``````const NUM_TICKS: f64 = 10.0;

fn main() {
let given_slice: &[f64] = &[1., 2., 3.];

let mut max = f64::MIN;
let mut min = f64::MAX;

given_slice
.iter()
.copied()
.for_each(|x| {
if x > max {
max = x;
}
if x < min {
min = x;
}
});

let size = max - min;
let distance_ticks = size / NUM_TICKS;

println!("{}", distance_ticks);
}
``````

I mean what it calls "Density" on the Y axis in that graph. It's also called PDF ( I can't remember what that stands for ). I just found this `statrs::distribution::Normal` struct that should calculate it for me I think ( assuming I give it the standard distribution which I also have to figure out how to calculate ). But there are a bunch of different distributions and I don't know which one to use so I just guessed `Normal` seemed pretty, "normal" .

I'm looking to render that shaded blue area which somehow represents the probability that a value will fall within that range. Does that make any sense? I have no background in statistics. Ah, alright.

Unfortunately I'm not knowledgeable in statistics beyond basic number processing, so I can't help you choose a good distribution or an accurate one. Sorry for the let down.

No problem, thanks for trying.  1 Like

It looks like criterion's logic for calculating those densities (PDF = probability density function) is in this module:

https://github.com/bheisler/criterion.rs/blob/master/src/plot/plotters_backend/pdf.rs

The actual smoothing seems to be done by calling out to `criterion::kde::sweep_and_estimate`:

https://github.com/bheisler/criterion.rs/blob/89593658643f9a12949f99f35a6bf906cb4e43c0/src/kde.rs#L14

That in turn uses some functionality from `criterion::stats::univariate::kde`. Ultimately this is performing kernel density estimation using a gaussian kernel, which is standard enough that you may be able to find a crate to do it for you. (Unfortunately the `stats` and `plot` modules are private so you can't just import from criterion.)

2 Likes

Hey, actually I just found the `criterion_stats` library, which had what I needed in it:

It's not all fancy interpolated, but I don't really care. It gets the message across.

``````let dist = criterion_stats::Distribution::from(frame_avgs.clone().into_boxed_slice());
let points: Vec<(f64, f64)> = frame_avgs
.iter()
.map(|&x| (x, dist.p_value(x, &Tails::Two)))
.collect();
``````

Not sure what `Tails::Two` is compared to the alternative `Tails::One`, but oh well. 2 Likes

Haha! Now I've got some more neat graphs.

Plotters is awesome. Adding the text to the graph for the percentage difference and the average line was super easy.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.