- ds
- Data display
- Scatter plot
Scatter plot
Two measures per point, with a highlighted outlier.
Two measures per item, to find a relationship and the items that break it. Points are HTML circles positioned in a plot, so they stay round, take hover and focus, and can carry a label.
Query cost, last 24 hours
Each point is a query. The dashed line is the typical 0.11 s per GB.
seconds
0100200300400
GB scanned
Show code
<figure class="chart boxed">
<figcaption class="ch-head">
<div><p class="ch-title">Query cost, last 24 hours</p><p class="ch-sub">Each point is a query. The dashed line is the typical 0.11 s per GB.</p></div>
</figcaption>
<div class="plot" style="--h:15rem" role="img" aria-label="Warehouse queries by data scanned and duration. Most fall on a line of about 0.1 seconds per GB; orders_by_region took 51 seconds for 82 GB.">
<div class="ch-grid dashed"><i style="--at:0" data-v="0"></i><i style="--at:0.25" data-v="15"></i><i style="--at:0.5" data-v="30"></i><i style="--at:0.75" data-v="45"></i><i style="--at:1" data-v="60"></i></div>
<span class="ch-yt">seconds</span>
<svg viewBox="0 0 100 100" preserveAspectRatio="none" aria-hidden="true"><path class="ch-line dash muted" d="M0 99.16666666666667L100 26.66666666666667"/></svg>
<i class="ch-pt s1" style="--x:0.472;--y:0.302"></i><i class="ch-pt s1" style="--x:0.045;--y:0.053"></i><i class="ch-pt s1" style="--x:0.235;--y:0.188"></i><i class="ch-pt s1" style="--x:0.087;--y:0.066"></i><i class="ch-pt s1" style="--x:0.258;--y:0.181"></i><i class="ch-pt s1" style="--x:0.297;--y:0.238"></i><i class="ch-pt s1" style="--x:0.163;--y:0.070"></i><i class="ch-pt s1" style="--x:0.557;--y:0.448"></i><i class="ch-pt s1" style="--x:0.147;--y:0.055"></i><i class="ch-pt s1" style="--x:0.420;--y:0.365"></i><i class="ch-pt s1" style="--x:0.750;--y:0.584"></i><i class="ch-pt s1" style="--x:0.253;--y:0.119"></i><i class="ch-pt s1" style="--x:0.207;--y:0.181"></i><i class="ch-pt s1" style="--x:0.075;--y:0.074"></i><i class="ch-pt s1" style="--x:0.068;--y:0.008"></i><i class="ch-pt s1" style="--x:0.333;--y:0.289"></i><i class="ch-pt s1" style="--x:0.015;--y:0.008"></i><i class="ch-pt s1" style="--x:0.345;--y:0.245"></i><i class="ch-pt s1" style="--x:0.072;--y:0.075"></i><i class="ch-pt s1" style="--x:0.207;--y:0.140"></i><i class="ch-pt s1" style="--x:0.083;--y:0.080"></i><i class="ch-pt s1" style="--x:0.705;--y:0.474"></i><i class="ch-pt s1" style="--x:0.025;--y:0.076"></i><i class="ch-pt s1" style="--x:0.193;--y:0.212"></i><i class="ch-pt s1" style="--x:0.630;--y:0.525"></i><i class="ch-pt s1" style="--x:0.098;--y:0.139"></i><i class="ch-pt s1" style="--x:0.015;--y:0.036"></i><i class="ch-pt s1" style="--x:0.350;--y:0.210"></i><i class="ch-pt s1" style="--x:0.122;--y:0.023"></i><i class="ch-pt s1" style="--x:0.340;--y:0.308"></i><i class="ch-pt s1" style="--x:0.220;--y:0.145"></i><i class="ch-pt s1" style="--x:0.665;--y:0.430"></i><i class="ch-pt s1" style="--x:0.092;--y:0.132"></i><i class="ch-pt s1" style="--x:0.170;--y:0.158"></i><i class="ch-pt s1" style="--x:0.203;--y:0.108"></i><i class="ch-pt s1" style="--x:0.362;--y:0.196"></i><i class="ch-pt s1" style="--x:0.022;--y:0.008"></i><i class="ch-pt s1" style="--x:0.158;--y:0.125"></i><i class="ch-pt s1" style="--x:0.603;--y:0.397"></i><i class="ch-pt s1" style="--x:0.432;--y:0.296"></i><i class="ch-pt s1" style="--x:0.100;--y:0.089"></i><i class="ch-pt s1" style="--x:0.048;--y:0.008"></i><i class="ch-pt s1" style="--x:0.725;--y:0.566"></i><i class="ch-pt s1" style="--x:0.410;--y:0.331"></i><i class="ch-pt s1" style="--x:0.400;--y:0.360"></i><i class="ch-pt s1" style="--x:0.310;--y:0.206"></i><i class="ch-pt s1" style="--x:0.138;--y:0.037"></i><i class="ch-pt s1" style="--x:0.135;--y:0.141"></i><i class="ch-pt s1" style="--x:0.070;--y:0.056"></i><i class="ch-pt s1" style="--x:0.623;--y:0.424"></i><i class="ch-pt s1" style="--x:0.040;--y:0.061"></i><i class="ch-pt s1" style="--x:0.015;--y:0.008"></i><i class="ch-pt s1" style="--x:0.223;--y:0.143"></i><i class="ch-pt s1" style="--x:0.642;--y:0.413"></i><i class="ch-pt s1" style="--x:0.693;--y:0.553"></i><i class="ch-pt s1" style="--x:0.422;--y:0.259"></i><i class="ch-pt s1" style="--x:0.375;--y:0.285"></i><i class="ch-pt s1" style="--x:0.412;--y:0.262"></i><i class="ch-pt s1" style="--x:0.390;--y:0.218"></i><i class="ch-pt s1" style="--x:0.258;--y:0.212"></i><i class="ch-pt s1" style="--x:0.077;--y:0.083"></i><i class="ch-pt s1" style="--x:0.015;--y:0.084"></i><i class="ch-pt s1" style="--x:0.318;--y:0.173"></i><i class="ch-pt s1" style="--x:0.665;--y:0.452"></i><i class="ch-pt s1" style="--x:0.102;--y:0.141"></i><i class="ch-pt s1" style="--x:0.268;--y:0.256"></i><i class="ch-pt s1" style="--x:0.075;--y:0.126"></i><i class="ch-pt s1" style="--x:0.600;--y:0.509"></i><i class="ch-pt s1" style="--x:0.058;--y:0.104"></i><i class="ch-pt s1" style="--x:0.680;--y:0.435"></i>
<i class="ch-pt c-down hl" style="--x:0.205;--y:0.850" data-v="orders_by_region, no partition filter"></i><i class="ch-pt c-down" style="--x:0.850;--y:0.367"></i><i class="ch-pt c-down" style="--x:0.300;--y:0.683"></i>
<div class="ch-x"><span style="--at:0">0</span><span style="--at:0.25">100</span><span style="--at:0.5">200</span><span style="--at:0.75">300</span><span style="--at:1">400</span></div>
<span class="ch-xt">GB scanned</span>
</div>
</figure>Points are filled at 40% with a solid edge, so overlaps show density. The outliers are red and the worst one is labelled from data-v; the rest are context. Axis titles go above the y labels and under the x labels, never rotated.
Bubbles
Services
Traffic against error rate. Size is monthly cost.
error rate
02k rpm4k rpm6k rpm
Show code
<figure class="chart boxed">
<figcaption class="ch-head">
<div><p class="ch-title">Services</p><p class="ch-sub">Traffic against error rate. Size is monthly cost.</p></div>
</figcaption>
<div class="plot" style="--h:13rem" role="img" aria-label="Services by requests per minute and error rate, sized by monthly cost. exports and notifications have the highest error rates.">
<div class="ch-grid dashed"><i style="--at:0" data-v="0%"></i><i style="--at:0.3333" data-v="1%"></i><i style="--at:0.6667" data-v="2%"></i><i style="--at:1" data-v="3%"></i></div>
<span class="ch-yt">error rate</span>
<i class="ch-pt s1" style="--x:0.700;--y:0.300;--r:3.84" data-v="checkout-api"></i><i class="ch-pt s1" style="--x:0.500;--y:0.067;--r:2.8800000000000003" data-v="search"></i><i class="ch-pt s1" style="--x:0.107;--y:0.017;--r:1.7600000000000002" data-v="ledger-writer"></i><i class="ch-pt s2 hl" style="--x:0.300;--y:0.533;--r:1.92" data-v="notifications"></i><i class="ch-pt s1" style="--x:0.867;--y:0.033;--r:2.4000000000000004" data-v="auth"></i><i class="ch-pt s2 hl" style="--x:0.035;--y:0.800;--r:4.4799999999999995" data-v="exports"></i><i class="ch-pt s1" style="--x:0.400;--y:0.133;--r:2.08" data-v="catalog"></i><i class="ch-pt s1" style="--x:0.063;--y:0.233;--r:1.6" data-v="billing-sync"></i>
<div class="ch-x"><span style="--at:0">0</span><span style="--at:0.3333">2k rpm</span><span style="--at:0.6667">4k rpm</span><span style="--at:1">6k rpm</span></div>
</div>
</figure>--r scales a point; 1 is 8px. Size by area reads better than by radius, so take the square root of the value before setting --r.
| Class | On | What it does |
|---|---|---|
.ch-pt | i, button | A point at --x, --y, scaled by --r. Colour from a series or status class. .hl fills it solid, .muted greys it, data-v labels it on the right. |
.ch-yt / .ch-xt | span | Axis titles: above the y labels, under the x labels. The plot makes room for them. |
.ch-grid.dashed | div | Dashed gridlines, quieter for dense charts. |
Do
- Label the two or three points the chart is about.
- A reference line for what "normal" looks like.
- Buttons for points that open something, so they can be focused.
Don't
- Labels on every point.
- A third and fourth encoding at once: size and colour and shape.
- Scatter plots for time series.
Accessibility
- The plot's label names the relationship and the outliers. Offer the points as a sortable table for anything beyond a glance.