Box Plot
Distribution at a glance: one box-and-whisker (quartiles, median, Tukey
outliers) or violin (kernel density body) per category. Push raw samples
and the phone does the statistics — quartiles, 1.5 × IQR fences, gaussian KDE —
or push precomputed stats when the server already reduced them. Tapping a
distribution reads its median into the header and fires boxAction with the
full five-number summary, so a latency plot doubles as a drill-down picker.
Type
"boxPlot"
Recommended Size
Wide like Chart: [3, 4]. In a flow grid it auto-sizes to a 16:10 cell.
Relevant Fields
Inherits all shared fields. Key fields:
| Field | Type | Default | Description |
|---|---|---|---|
label |
string | — | Header label (selection readout appears beside it) |
boxStyle |
string | "box" |
"box" or "violin" |
boxPlotConfig |
BoxPlotConfig | — | Full configuration object (all optional) |
tint |
string | "#667eea" |
First-category color / palette seed |
formatValue |
string | — | Formatter for axis + readout numbers |
action |
ActionDefinition | — | Fallback for boxAction |
BoxPlotConfig
| Field | Type | Default | Description |
|---|---|---|---|
showXAxis |
bool | true |
Category labels along the bottom |
showYAxis |
bool | true |
Value labels down the left gutter |
showGrid |
bool | true |
Horizontal grid lines |
yMin / yMax |
number | data range | Pin the value axis |
whiskers |
string | "tukey" |
"tukey" (1.5 × IQR fences + outlier dots) or "minmax" (full range) |
showOutliers |
bool | true |
Outlier dots beyond the whiskers |
showMean |
bool | false |
Hollow dot at the mean |
boxWidth |
number | 0.55 |
Box width as a fraction of the category slot |
colors |
string[] | built-in palette | Per-category color cycle |
boxAction |
ActionDefinition | — | Fired on tap; {{value}} = the stats as JSON |
scrub |
bool | false |
Drag sweeps the selection across categories with haptic ticks (readout only — the action still fires on tap) |
Sync Payload Structure
Raw samples (the app computes the statistics) — natural JSON or an encoded string:
{
"categories": ["us-east", "eu-west", "ap-south"],
"samples": [
[42, 51, 38, 66, 47, 130, 44],
[61, 72, 58, 66, 70, 64, 69],
[88, 95, 91, 180, 86, 90, 84]
]
}
Shorthand: a bare 2-D array [[…], […]] is samples with numbered categories.
Or precomputed stats (wins over samples if both are present):
{
"categories": ["us-east"],
"stats": [
{ "min": 38, "q1": 43, "median": 47, "q3": 58, "max": 66, "outliers": [130] }
]
}
Note: boxStyle: "violin" needs raw samples for the density body; with only
stats it falls back to the skeleton bar.
Examples
Latency by region (tap to inspect)
{
"type": "boxPlot",
"id": "latency",
"position": [0, 0],
"span": [3, 4],
"label": "Latency (ms)",
"boxPlotConfig": {
"boxAction": { "method": "meshsocket", "mode": "broadcast", "event": "broadcast", "payload": { "msg_type": "inspect_region", "stats": "{{value}}" } }
},
"sync": [{ "method": "meshsocket", "type": "listen", "event": "broadcast", "filter": { "msg_type": "latency_samples" }, "valuePath": "regions" }]
}
Violin comparison
{
"type": "boxPlot",
"id": "spread",
"position": [0, 0],
"span": [3, 4],
"label": "Sensor spread",
"boxStyle": "violin",
"boxPlotConfig": { "showMean": true },
"defaultValue": "{\"categories\":[\"A\",\"B\"],\"samples\":[[5,6,6,7,7,7,8,9],[4,5,7,9,10,11,11,12]]}"
}
Behavior
- Dataset pushes animate via the control's
animationprofile - Tap a category to select it (header shows
name ~median); tap again or tap empty space to clear scrub: truelets a drag sweep the selection fluidly across categories with a tick per change- Quartiles use type-7 linear interpolation (same as Numbers/NumPy); violin bandwidth is Silverman's rule
- The value axis pads 6% beyond the extremes so caps and outlier dots never clip
Notes
- 2–6 categories read best; past ~8 the boxes get skinny on a phone
- The control's value is the dataset JSON — selection never overwrites it
- For a single streaming series use Sparkline; for binned frequency shape use a Chart
histogramseries