Raincloud plot
Each group's distribution three ways at once: a half violin for its shape, a slim box plot for its quartiles, and every observation jittered beside them. Standing up or lying down.
Page load time by region
Last week's checkout page loads: the shape, the quartiles and every visit.
| Group | Value |
|---|---|
| Europe | 553 ms |
| Europe | 1382 ms |
| Europe | 892 ms |
| Europe | 1408 ms |
| Europe | 495 ms |
| Europe | 1273 ms |
| Europe | 631 ms |
| Europe | 495 ms |
| Europe | 497 ms |
| Europe | 1524 ms |
| Europe | 1501 ms |
| Europe | 793 ms |
| Europe | 710 ms |
| Europe | 812 ms |
| Europe | 882 ms |
| Europe | 1136 ms |
| Europe | 1140 ms |
| Europe | 678 ms |
| Europe | 732 ms |
| Europe | 1266 ms |
| Europe | 632 ms |
| Europe | 739 ms |
| Europe | 501 ms |
| Europe | 1090 ms |
| Europe | 1234 ms |
| Europe | 629 ms |
| Europe | 526 ms |
| Europe | 1519 ms |
| Europe | 508 ms |
| Europe | 712 ms |
| Europe | 714 ms |
| Europe | 504 ms |
| Europe | 506 ms |
| Europe | 904 ms |
| Europe | 1129 ms |
| Europe | 500 ms |
| Europe | 883 ms |
| Europe | 1407 ms |
| Europe | 567 ms |
| Europe | 864 ms |
| Europe | 625 ms |
| Europe | 596 ms |
| Europe | 772 ms |
| Europe | 1032 ms |
| Europe | 594 ms |
| Europe | 519 ms |
| Europe | 1307 ms |
| Europe | 909 ms |
| Europe | 645 ms |
| Europe | 1550 ms |
| Europe | 742 ms |
| Europe | 526 ms |
| Europe | 561 ms |
| Europe | 1396 ms |
| Europe | 861 ms |
| Europe | 751 ms |
| Europe | 525 ms |
| Europe | 693 ms |
| Europe | 526 ms |
| Europe | 492 ms |
| North America | 513 ms |
| North America | 531 ms |
| North America | 578 ms |
| North America | 462 ms |
| North America | 961 ms |
| North America | 1164 ms |
| North America | 463 ms |
| North America | 965 ms |
| North America | 467 ms |
| North America | 501 ms |
| North America | 1069 ms |
| North America | 528 ms |
| North America | 584 ms |
| North America | 581 ms |
| North America | 721 ms |
| North America | 863 ms |
| North America | 608 ms |
| North America | 683 ms |
| North America | 897 ms |
| North America | 614 ms |
| North America | 472 ms |
| North America | 987 ms |
| North America | 1046 ms |
| North America | 457 ms |
| North America | 547 ms |
| North America | 472 ms |
| North America | 784 ms |
| North America | 458 ms |
| North America | 585 ms |
| North America | 1300 ms |
| North America | 1099 ms |
| North America | 980 ms |
| North America | 1380 ms |
| North America | 458 ms |
| North America | 586 ms |
| North America | 1050 ms |
| North America | 457 ms |
| North America | 501 ms |
| North America | 1186 ms |
| North America | 487 ms |
| North America | 535 ms |
| North America | 1206 ms |
| North America | 1013 ms |
| North America | 1325 ms |
| North America | 976 ms |
| North America | 480 ms |
| North America | 667 ms |
| North America | 804 ms |
| North America | 778 ms |
| North America | 624 ms |
| North America | 520 ms |
| North America | 833 ms |
| North America | 661 ms |
| North America | 458 ms |
| North America | 1025 ms |
| North America | 475 ms |
| North America | 457 ms |
| North America | 929 ms |
| North America | 615 ms |
| North America | 791 ms |
| Asia Pacific | 732 ms |
| Asia Pacific | 835 ms |
| Asia Pacific | 1101 ms |
| Asia Pacific | 1027 ms |
| Asia Pacific | 1361 ms |
| Asia Pacific | 1590 ms |
| Asia Pacific | 741 ms |
| Asia Pacific | 1359 ms |
| Asia Pacific | 709 ms |
| Asia Pacific | 1793 ms |
| Asia Pacific | 724 ms |
| Asia Pacific | 983 ms |
| Asia Pacific | 657 ms |
| Asia Pacific | 1495 ms |
| Asia Pacific | 742 ms |
| Asia Pacific | 725 ms |
| Asia Pacific | 722 ms |
| Asia Pacific | 1262 ms |
| Asia Pacific | 737 ms |
| Asia Pacific | 650 ms |
| Asia Pacific | 895 ms |
| Asia Pacific | 981 ms |
| Asia Pacific | 1582 ms |
| Asia Pacific | 1776 ms |
| Asia Pacific | 1361 ms |
| Asia Pacific | 904 ms |
| Asia Pacific | 1476 ms |
| Asia Pacific | 739 ms |
| Asia Pacific | 657 ms |
| Asia Pacific | 803 ms |
| Asia Pacific | 1682 ms |
| Asia Pacific | 1137 ms |
| Asia Pacific | 1038 ms |
| Asia Pacific | 795 ms |
| Asia Pacific | 672 ms |
| Asia Pacific | 1659 ms |
| Asia Pacific | 784 ms |
| Asia Pacific | 657 ms |
| Asia Pacific | 1225 ms |
| Asia Pacific | 1875 ms |
| Asia Pacific | 655 ms |
| Asia Pacific | 1068 ms |
| Asia Pacific | 953 ms |
| Asia Pacific | 1182 ms |
| Asia Pacific | 1976 ms |
| Asia Pacific | 677 ms |
| Asia Pacific | 720 ms |
| Asia Pacific | 994 ms |
| South America | 880 ms |
| South America | 2442 ms |
| South America | 2110 ms |
| South America | 832 ms |
| South America | 1617 ms |
| South America | 904 ms |
| South America | 774 ms |
| South America | 843 ms |
| South America | 998 ms |
| South America | 2247 ms |
| South America | 1042 ms |
| South America | 1888 ms |
| South America | 1516 ms |
| South America | 2162 ms |
| South America | 1001 ms |
| South America | 1428 ms |
| South America | 2408 ms |
| South America | 2240 ms |
| South America | 1431 ms |
| South America | 774 ms |
| South America | 2013 ms |
| South America | 1414 ms |
| South America | 2072 ms |
| South America | 833 ms |
| South America | 1917 ms |
| South America | 1016 ms |
| South America | 1292 ms |
| South America | 781 ms |
| South America | 1498 ms |
| South America | 1104 ms |
| South America | 1091 ms |
| South America | 1019 ms |
| South America | 2034 ms |
| South America | 870 ms |
| South America | 909 ms |
| South America | 1126 ms |
Usage
use hydroxy_leptos::chart_frame::ChartFrame;
use hydroxy_leptos::raincloud_chart::*;
use leptos::prelude::*;
/// `n` page load times in ms around `median`, skewed right like real loads. A fixed
/// generator, so the sample is the same on every render.
fn loads(seed: u32, n: usize, median: f64) -> Vec<f64> {
let mut s = seed;
(0..n)
.map(|_| {
s = s.wrapping_mul(1_664_525).wrapping_add(1_013_904_223);
let u = f64::from(s >> 8) / f64::from(1u32 << 24);
(median * (0.6 + 1.3 * u * u)).round()
})
.collect()
}
fn regions() -> Vec<Group> {
vec![
Group::new("Europe", loads(7, 60, 820.0)),
Group::new("North America", loads(11, 60, 760.0)),
Group::new("Asia Pacific", loads(23, 48, 1080.0)),
Group::new("South America", loads(41, 36, 1290.0)),
]
}
pub fn demo() -> AnyView {
view! {
<ChartFrame title="Page load time by region" description="Last week's checkout page loads: the shape, the quartiles and every visit.">
<RaincloudChart
groups=regions()
orientation=Orientation::Horizontal
label="Checkout page load time by region"
annotations=vec![Annotation::x_line(1000.0, "1 s budget")]
format=|v: f64| format!("{v:.0} ms")
/>
</ChartFrame>
}
.into_any()
}use dioxus::prelude::*;
use hydroxy_dioxus::chart_frame::ChartFrame;
use hydroxy_dioxus::raincloud_chart::{Annotation, Group, Orientation, RaincloudChart};
/// `n` page load times in ms around `median`, skewed right like real loads. A fixed
/// generator, so the sample is the same on every render.
fn loads(seed: u32, n: usize, median: f64) -> Vec<f64> {
let mut s = seed;
(0..n)
.map(|_| {
s = s.wrapping_mul(1_664_525).wrapping_add(1_013_904_223);
let u = f64::from(s >> 8) / f64::from(1u32 << 24);
(median * (0.6 + 1.3 * u * u)).round()
})
.collect()
}
fn regions() -> Vec<Group> {
vec![
Group::new("Europe", loads(7, 60, 820.0)),
Group::new("North America", loads(11, 60, 760.0)),
Group::new("Asia Pacific", loads(23, 48, 1080.0)),
Group::new("South America", loads(41, 36, 1290.0)),
]
}
#[component]
pub fn RaincloudChartDemo() -> Element {
rsx! {
ChartFrame { title: "Page load time by region", description: "Last week's checkout page loads: the shape, the quartiles and every visit.",
RaincloudChart {
groups: regions(),
orientation: Orientation::Horizontal,
label: "Checkout page load time by region",
annotations: vec![Annotation::x_line(1000.0, "1 s budget")],
format: |v: f64| format!("{v:.0} ms"),
}
}
}
}
Anatomy
| Component | data-part | Renders |
|---|---|---|
RaincloudChart | root | figure |
| rain | All the marks; `data-orientation` is vertical or horizontal, `data-active` while a group is picked out |
| cloud | Half violin: kernel density trimmed to the data, revealed from its baseline |
| box-plot | Whisker, box and median for one group; opens out from the median |
| dot | One observation, jittered across a strip; a canvas past 2,000 observations |
| overlay | Focusable layer that reads the pointer and keys |
| tooltip | Count and quartiles of the active group |
| legend | Group names, for two to six groups |
| sr-table | Every observation (up to 1,000 rows; CSV export gets them all) |
Keyboard
| Key | Does |
|---|---|
Arrow keys | Move between groups |
Home / End | First or last group |
Escape | Clear the active group |
Props
| Prop | Type | Notes |
|---|---|---|
groups | Vec<Group> | Required. Group::new(label, values) |
label | String | Required. What the chart shows; the accessible name |
orientation | Orientation | Vertical (default): groups along the bottom. Horizontal: stacked rows |
bandwidth | f64 | Kernel bandwidth in data units. Default: Silverman's rule per group |
annotations | Vec<Annotation> | Reference lines and bands along the value axis |
height | u16 | Plot height in px. Default 280 |
format | Fn(f64) -> String | Formats values on the axis, tooltip and table |
Events
| Prop | Type | Notes |
|---|---|---|
on_hover | Callback<Option<Datum>> | The mark under the pointer or keyboard focus changes, or is left. Fires only on a change |
on_select | Callback<Datum> | Click, tap or Enter on a mark |