Zopra/Charts
Guide
Getting startedAll chartsWhich chart to use?Domain specific
Base charts7
XY ChartTrendCandlestickHeatmapState TimelineFlame GraphBar Gauge
Derived charts73
Time SeriesHistogramStatus HistoryStatGaugeHoneyCombTracesNode GraphHeikin-AshiRenkoKagiPoint & FigureParetoIshikawaControl ChartBland-AltmanLollipopDumbbellSlopeBumpBack-to-BackWaterfallBulletFunnelMekkoForestBarcodeBeeswarmRidgelineHorizonSpectrogramAttention MapWaffleVennUpSetWarped WaffleWord CloudGanttSankeySankey MatrixTreemap ForceChord DiagramCircosArc DiagramAlluvialSankey FunnelDendrogramIcicleSunburstSpiderNightingale RoseParallel CoordinatesOscilloscopeEfficient FrontierPhase PortraitPoincaré MapBifurcationH-R DiagramRamachandranHarkerRoot LocusRadiation PatternQuiverHodographSmith ChartEye DiagramSequence LogoTernaryTernary ContourPiperStüveTephigramChoropleth

Charts/Core charts

Histogram

<Histogram /> · 13 examples

Counts of values per bucket, so you can see the shape of a whole distribution at once.

Overview

An average is a summary, and summaries are polite. They tell you what the data would like you to believe. A histogram is the data in its own clothes: take every value, drop it into a bucket by size, count the buckets, draw the counts as bars. What comes out is a shape, and the shape tells you things the mean never would. One hump or two. A long tail or a cliff. A suspicious spike at exactly zero.

Karl Pearson gave the histogram its name in the 1890s, and the idea of counting things into bins is of course far older. The chart has outlived most of the fashions that tried to replace it, for the dull reason that it is hard to fool. You cannot hide a bimodal distribution in a histogram, though people have tried.

The one decision that is yours is the bucket size. Too wide and everything merges into one hump. Too narrow and the hump becomes a comb. In zopra-charts the default aims for about thirty buckets and rounds the width to a friendly number, so you get a sensible first picture and can decide whether the buckets mean something afterwards.

Props

API

<Histogram> counts how many values fall into each bucket and draws the counts as bars: how request times, sizes or scores are spread. It is a port of Grafana's Histogram panel; see Coming from Grafana.

use zopra_charts::*;
  • <Histogram>
  • <HistogramSeries>
  • Buckets
  • Pre-counted buckets
  • Coming from Grafana

Not sure which option fits? See the guide.


<Histogram>

<Histogram data={requests}>
    <HistogramSeries name="GET" value={|r: &Request| r.get_ms} />
    <HistogramSeries name="POST" value={|r: &Request| r.post_ms} />
</Histogram>
PropTypeDefault
dataVec<T>, Signal<Vec<T>>, Frame<N>, Signal<Frame<N>>, or your own Datasetrequired
children<HistogramSeries> tagsfor a Frame: every field except xMin / xMax
bucket_countusize: roughly how many buckets to aim for30
bucket_sizef64: the width of every bucketpicked from bucket_count, see Buckets
bucket_offsetf64: shifts where buckets start0.
combinebool: add every series into one Count seriesfalse
x_min / x_maxFn(&T) -> f64: each row's bucket edges, for pre-counted bucketsnone
fill_opacityf32, 0.0–1.00.8
gradientGradientMode: None, Opacity, Hue, SchemeNone
line_widthf32 px1.
stackingStacking: None, Stacking::NORMAL, Stacking::PERCENTNone
hide_fromHideFromnothing hidden
thresholds, schemecolours for gradient={GradientMode::Scheme}your theme's
x_axisAxisConfigdecimals from the bucket size
y_axisAxisConfigstarts at 0
legendLegendLegend::list() at the bottom
tooltipTooltipTooltip::single()
class, key

<HistogramSeries>

<HistogramSeries name="GET" value={|r: &Request| r.get_ms} color={rgb(0x1e66f5)} />
PropTypeDefault
valueFn(&T) -> f64: the value to count, or the count itself for pre-counted bucketsrequired
nametext"Series 1", "Series 2", …
colorany colouryour theme's palette
fill_opacity, line_width, gradient, hide_fromas on the chartthe chart's

Missing values (NaN or infinite) are not counted.

Buckets

  • Size. With bucket_size, every bucket is that wide. Without it, the chart divides the range of all values by bucket_count and picks the next size up from a list of round sizes (1, 2, 2.5, 4 and 5 times a power of ten). It never picks a size smaller than the smallest gap between two values.
  • Edges. A value v falls in the bucket starting at floor((v - offset) / size) * size + offset. Buckets include their start and exclude their end.
  • Series. Every series is counted into the same buckets so their bars line up. Buckets with no values are left out.
  • Hover. The tooltip shows the bucket, such as 120 - 125, and the count of each series.

Pre-counted buckets

If your data is already bucketed, give each row's edges with x_min and x_max; each series' value is then the count:

<Histogram data={buckets} x_min={|b: &Bucket| b.low} x_max={|b: &Bucket| b.high}>
    <HistogramSeries name="requests" value={|b: &Bucket| b.count} />
</Histogram>

Buckets may have different widths. If only x_min or only x_max is given, the other edge is guessed from the gap between the first two rows. A Frame with fields named xMin and xMax is read the same way, as in Grafana.

Coming from Grafana

Grafana optionHere
Bucket count, Bucket size, Bucket offsetbucket_count, bucket_size, bucket_offset
Combine seriescombine
Fill opacity, Gradient mode, Line widthfill_opacity (0.0–1.0), gradient, line_width
Stack seriesstacking
Legend, Tooltiplegend, tooltip
Hide in areahide_from
xMin / xMax framesx_min / x_max, or a Frame with those field names

Not available here: Prometheus le histograms (use <Heatmap> with BucketLayout::Le), units and log-scale bucket axes.

Run them

13 examples

Press Run to load an example into the live render at the top of the page. Open one to read its code.

How to read it

  1. 01Find the tallest bar, the mode, and ask whether it is the only one. A second hump means two populations.
  2. 02Look at the tails. A long right tail means a few large values pull the mean away from the typical one.
  3. 03Check the bucket width before you read anything into the bar heights. Different widths make heights incomparable.
  4. 04Hover a bar for its range and count. With several series, overlap and stacking behave differently, so check which one you are looking at.

When to use it, and when not to

Reach for it when

  • You want the shape of one numeric variable: spread, skew, modes, outliers.
  • You are comparing two groups and want to see whether their shapes differ, not only their means.
  • You are deciding how to summarise. A long tail argues for percentiles. Two humps argue for splitting the data first.
  • You have raw samples (request latency, file sizes, test scores) or counts already in buckets from a metrics system.

Skip it when

  • You want how the distribution changes over time. A Heatmap with calculate stacks one histogram per time bucket.
  • You have very few values. Twelve values in thirty buckets is a drawing of twelve bars.
  • You need to compare each value against another variable. XY Chart.
  • You want precise quantiles. A histogram shows them roughly. Compute them.

The math behind it

Binning

Given values x1,…,xnx_1, \dots, x_nx1​,…,xn​, a bucket width www and an offset ooo (zero by default), the bucket of a value is identified by its lower edge, and the bucket covers the half-open interval from that edge up to the edge plus www. The count of a bucket is the number of values whose lower edge matches it.

Only buckets that contain at least one value are produced, so gaps in the data show as gaps. Lower edges are rounded to nine decimals to keep floating-point crumbs out of the bucket identity, which stops 0.30000000000000004 from becoming a bucket of its own.

ℓ(x)=w⌊x−ow⌋+o,ck=#{ i:ℓ(xi)=ℓk }\ell(x) = w \left\lfloor \frac{x - o}{w} \right\rfloor + o, \qquad c_k = \#\{\, i : \ell(x_i) = \ell_k \,\}ℓ(x)=w⌊wx−o​⌋+o,ck​=#{i:ℓ(xi​)=ℓk​}

Choosing the width

When you give neither bucket_size nor bucket_count, the chart aims for n=30n = 30n=30 buckets. It computes the target width as the range of all values divided by nnn, and then picks the smallest width from a ladder of round numbers (1, 2, 2.5, 4, 5 times a power of ten, from 10−910^{-9}10−9 to 10910^{9}109) that is larger than the target and also no smaller than the smallest gap between distinct values.

The second condition is what keeps integer data tidy: if your values are whole numbers, the bucket will never be narrower than 1, so no bucket is mysteriously empty. bucket_offset set to half the width centres buckets on round numbers.

w=min⁡{ s∈S:s>max⁡x−min⁡xn, s≥δmin⁡ }w = \min\{\, s \in \mathcal{S} : s > \tfrac{\max x - \min x}{n},\ s \ge \delta_{\min} \,\}w=min{s∈S:s>nmaxx−minx​, s≥δmin​}

Several series and pre-counted data

With several series, values from all of them are bucketed with the same width and offset, so bars line up. Each bucket row then has one count per series. stacking stacks them to show the total and the parts, combine={true} merges everything into one count, and an overlay with lower fill_opacity compares shapes.

If your data is already counted, you pass the lower and upper edges and a count. A missing edge is guessed from the spacing of the other one, and non-finite counts are treated as zero.

Real life usage

The exam that had two peaks

Oksana taught introductory statistics at a technical college in Lviv, and every term she graded the final exam, computed the mean, and posted it. Sixty-one out of a hundred, again, which felt right and told her nothing at all.

This term the head of department asked her why a third of the class had still failed, given that the average looked healthy. It was a reasonable question, and she had no answer, because she had never actually looked at the scores. She had looked at their mean, which is a different thing.

She exported the 214 results into a spreadsheet and plotted them with zopra-charts, using <Histogram> with a bucket size of five points and a single series. She expected a hill with a hump at sixty. She wanted to be right, in the same way that everyone wants to be right.

The chart had two humps. One at about 40 and one at about 80, with a valley between them at 60 that was very nearly empty. Sixty-one was the average of two groups, and almost nobody had actually scored sixty-one.

She split the data by which tutorial group the student had attended. The two humps separated cleanly: a section that had been taught by a substitute for the middle four weeks had scored low, and the rest high. The lecturer on leave had covered conditional probability, which is the one topic on the exam that is entirely made of ideas you only get once.

Oksana ran two revision sessions for that section on conditional probability. At the retake, the low hump had moved from 40 to 66 and the valley had filled in.

She now plots the histogram before she computes anything else. The mean, she tells her students, is the number you get when you ask a crowd to stand in the middle of a room, and nobody in the room is standing there.

Pitfalls

  • Bucket width changes the story. Try a coarser and a finer width before you conclude there is a gap or a second hump.
  • Unequal widths. Pre-counted buckets of different sizes make bar heights misleading. Count per unit width or use equal buckets.
  • Overlaying more than two series. Overlapping bars turn to mud. Stack them, or compare two at a time.
  • Integers and half-open buckets. Edges belong to the bucket above, so a value of exactly 10 falls in 10 to 15, not 5 to 10.
  • Treating the histogram as a density. Bars show counts, not probabilities, so the totals depend on how much data you have.

From around the web

Watch and read

YouTubeStatQuest: Histograms, Clearly ExplainedStatQuest with Josh StarmerWell-known, clear explanation of histograms and bin width.

Keep going

Related charts

HeatmapOne histogram per time bucket, drawn as colour, to see how the shape changes.RidgelineSeveral distributions drawn as overlapping curves, one per group.BarcodeEvery value as a tick, when you have few samples and want to see each one.BeeswarmEvery point shown without overlap, per category.
PreviousTime SeriesNextStatus History

On this page

  • Live
  • Overview
  • API
  • Examples
  • How to read it
  • When to use it
  • The math
  • Story
  • Pitfalls
  • Watch and read
  • Related