Skip to content
Folio

Charts

Histogram

The shape of one distribution.

Usage

When to reach for it

A single distribution has to be understood — two clusters, a hard floor, a pile-up at a timeout. Several distributions side by side want a BoxPlot.

Ships from@misoto22/design/charts

TSX
import { Histogram } from '@misoto22/design/charts'

Notes

The shape of one distribution — where the mass sits, how it leans, whether there is more than one hump in it.

The form that answers what a <BoxPlot> structurally cannot: two clusters, a hard floor, a pile-up at a timeout value. Reach for the box plot when several distributions have to be compared side by side, and for this one when a single distribution has to be understood.

A histogram's shape is a property of its bin width, not only of its data. The same numbers cut into eight buckets and into eighty are two different pictures, and a gap between two humps can be created or erased by moving a bin edge. That is not a defect to be fixed, it is what binning IS, and the defence is to say which rule drew the picture — the default here is Freedman–Diaconis — and to look at more than one width before believing a feature. Uneven buckets add a second trap: under frequency a bucket twice as wide stands twice as tall at the same underlying rate, which is what mode="density" exists to correct.

Recharts earns its place here for the axes, the grid and the tooltip, but not for the bars: a bar chart's bars are positioned by CATEGORY and a histogram's are positioned and SIZED by a continuous measurement. So the x axis is numeric and each bar is drawn from its own two edges — which is what lets an uneven bucket be as wide as it really is instead of being flattened into an equal slot beside its neighbours.

Anatomy

Histogram anatomy
ElementDescription
Figure framerequiredChartFigure’s <figure>, with an empty state when no bucket survives binning — which is what zero finite observations produces.
Barsrequired<Histogram.Bars>, each drawn from its bucket’s own two edges rather than placed in an equal category slot, which is what lets an uneven bucket be as wide as it really is. radius is 0 by default, unlike BarChart’s: a rounded corner draws a gap between two buckets that touch.
Measured axisrequired<Histogram.XAxis>, numeric, running from the first bucket’s lower edge to the last one’s upper edge.
Count axis<Histogram.YAxis>. Under mode="frequency" it is a count; under mode="density" it is count over n times width, and the bars then enclose an area of one.
Binning ruleNot a mark on screen and the most consequential part of the figure: bins takes a bucket count or the explicit edges, and the default is Freedman-Diaconis capped at 200 buckets, falling back to Sturges when the interquartile range is zero. Explicit edges are also a RANGE — an observation outside the first and last has no bucket, and is counted into the tooltip’s share and into a Below or Above row of the table rather than dropped.
Hidden data tableThe sr-only table prints each bucket’s two edges as its row header and its count beside them — the only exact reading a binned chart can offer, since every bar stands for a range rather than for a value. Observations outside explicit edges get their own Below and Above rows, because they have no bar anywhere.

Best practices

Do

  • Name the binning rule on the page. The same numbers cut into eight buckets and into eighty are two different pictures, and a gap between two humps can be created or erased by moving one edge — so look at more than one width before believing a feature.
  • Set mode="density" whenever the buckets are uneven. Under frequency a bucket twice as wide stands twice as tall at the same underlying rate, which is the trap pre-counted buckets from a metrics backend walk straight into.
  • Give values or data, never both. data wins when both arrive, so the values array is then binned by nothing and drawn by nothing, with no warning anywhere.

Don’t

  • Do not read the tooltip’s share as a share of the bars. It is a share of the SAMPLE, so a set of buckets summing to 96% is telling you the other 4% fell outside your own edges — which is the one reading a share taken over the drawn buckets could never give, because it always sums to 100.
  • Do not use it to compare several distributions. Two histograms overlaid occlude each other and six side by side do not fit; that is a BoxPlot, which spends a tenth of the ink per distribution.
  • Do not assume the automatic rule kept the resolution you asked for. Freedman-Diaconis divides by the interquartile range, so a tight middle with a long tail asks for tens of thousands of sub-pixel bars — the 200-bucket cap turns that into a coarse histogram rather than a hung tab, and a coarse histogram is a different picture.
  • Do not read a single-value distribution as a shape. Every observation on one number still draws: the edges become that value plus and minus a half, and the result is one honest bar that is not a distribution.

Examples

default

The shape of one distribution, which is what a box plot structurally cannot show: these 75 samples have two humps in them — a warm cache path and a cold one — and the same numbers draw a single tidy box that says nothing about either. Left to itself the chart bins by Freedman–Diaconis, 2 times IQR times n to the power of minus a third, which reads the interquartile range rather than the range, so one far outlier cannot stretch the picture into one tall bar and forty empty ones. Say which rule drew the histogram, as the description does here, because the shape is a property of the bin width as much as of the data.

Request durationBinned by Freedman–Diaconis
Request duration
labelCount
62 – 10337
103 – 1446
144 – 18522
185 – 2265
226 – 2673
267 – 3082

bin width

The same numbers, four times. bins takes a count of equal-width buckets, and moving it moves the picture: at five the two humps merge into one, at forty the shape dissolves into a row of one-count bars, and auto hands the choice back to Freedman–Diaconis. That is not a defect to be tuned away — binning IS this — so the defences are to name the rule that drew the picture, as the title does, and to look at more than one width before believing a feature such as the gap between two humps.

Request duration — Freedman–Diaconis
Request duration — Freedman–Diaconis
labelCount
62 – 10337
103 – 1446
144 – 18522
185 – 2265
226 – 2673
267 – 3082

density

Buckets that arrived already counted, at the widths a metrics backend chose, getting wider as the values grow. Under frequency the 100 to 250 bucket reads as a real shoulder, and it is only there because that bucket is fifteen times as wide as the first one — a wider bucket collects more observations at the same underlying rate. density divides each count by n times the bucket width, so the bars enclose an area of one and the tail flattens into what the data actually says. Reach for it whenever the buckets are uneven, and whenever two histograms of different sample sizes have to be compared.

Request duration — frequency
Request duration — frequency
labelCount
0 – 10480
10 – 25610
25 – 50540
50 – 100420
100 – 250310
250 – 500120
500 – 1,00040

Types

TSX
export type HistogramMode = 'frequency' | 'density'

Accessibility

  • The shape is a property of the bin width, not only of the data: the same numbers cut into eight buckets and into eighty are two different pictures. The rule that drew it — Freedman–Diaconis by default — is named on the page.
  • The x axis is numeric and every bar is drawn from its own two edges, so an uneven bucket is as wide as it really is rather than flattened into an equal slot.
  • mode="density" corrects the trap uneven buckets create: under frequency a bucket twice as wide stands twice as tall at the same underlying rate.
  • The hidden data table prints each bucket’s two edges and its count, which is the only exact reading a binned chart can offer.