Skip to main content
v2026.11,610 entries · CC-BY 4.0

Histograms in Stata: histogram and twoway histogram

How to build a histogram in Stata: bin() and width() control, density vs. frequency vs. percent scaling, the normal overlay, by-group panels, and when to switch to twoway histogram to combine a histogram with another plot type.

Ask about Histograms in Stata: histogram and twoway histogram

Answers are drawn from this guide and the rest of the CASRAI corpus, with a link to every source.

Answers are AI-generated from CASRAI’s own published pages and can be wrong, so check the linked sources before relying on one; your question is logged without personal data — never sold, never used to train a third-party model — to show us what CASRAI is missing, so please do not type personal or confidential details. How we use this

Written and maintained by CASRAI Editorial Board

Last updated

Stata has two ways to draw a histogram: the standalone histogram command, which is fast to type and covers bin control, scaling, a normal-curve overlay, and by-group panels on its own, and twoway histogram, the plottype form used inside a graph twoway call when you need to combine a histogram with another plot — a second overlaid histogram, a kernel density curve, a fitted function — in one coordinate space. Most single-histogram jobs only need the standalone command. Reach for twoway histogram specifically when you’re layering more than one plot together.

The histogram command: basic syntax

The minimal call needs only a variable name:

histogram varname

For example, plotting the distribution of grant review turnaround times (variable days):

histogram days

By default Stata treats the variable as continuous, chooses a bin count automatically (an algorithm based on the data’s range and sample size), and scales the y-axis to density — bar heights such that the total area sums to 1, not raw counts. That default surprises people used to counts-based histograms elsewhere; see the scaling section below to change it.

Controlling bins: bin(), width(), and start()

Three options control how the data is binned, and only one of the first two can be used at a time:

  • bin(#) — sets the number of bins directly. Stata divides the observed range into that many equal-width bins.
  • width(#) — sets the bin width directly instead of the count. Use this when the width itself is the meaningful unit (e.g., one bin per 5-point score band) rather than an arbitrary bin count.
  • start(#) — sets the left edge of the first bin. Combine with either option above to control exactly where bin boundaries fall, which matters when a natural boundary (a 0 point, a passing threshold) should sit exactly on a bin edge rather than splitting across two.
histogram days, bin(20)
histogram days, width(5) start(0)

bin() and width() cannot both be specified — Stata computes one from the other and rejects the command if you supply both.

For a variable that’s genuinely discrete — a count, a small set of integer values, a Likert item — add the discrete option instead of binning at all. It puts one bar on each distinct observed value rather than grouping values into ranges, which avoids the misleading gaps and merges a continuous-style bin width can create on count data:

histogram num_coauthors, discrete

Density, frequency, fraction, and percent: the y-axis scale

Four mutually exclusive options control what the y-axis represents:

  • density — the default. Bar heights scale so total bar area equals 1; this is what makes a normal overlay (below) comparable to the bars, since a normal density curve is also scaled to unit area.
  • frequency — raw observation counts per bin. The most intuitive reading for a general audience, but not on the same scale as a normal curve overlay.
  • fraction — each bar’s share of the total sample, as a proportion (0 to 1).
  • percent — the same as fraction, expressed as a percentage (0 to 100).
histogram days, frequency
histogram days, percent

If you plan to overlay a normal curve, leave the default density scale in place (or add normal, which forces it) — frequency/fraction/percent scaling with normal added will still run, but the curve and bars are no longer on a comparable footing.

Overlaying a normal curve: the normal option

Add normal to draw a normal density curve, fit to the variable’s own mean and standard deviation, over the histogram — a quick visual check of how far the data departs from normality:

histogram days, normal

Style the overlay line with normopts(), which accepts standard line options:

histogram days, normal normopts(lcolor(red) lwidth(medthick))

A normal overlay is a visual aid, not a formal test — a curve that looks close by eye can still fail a formal normality test on a large sample, and a curve that looks off by eye can still be fine for tests that are robust to mild non-normality. For a fuller treatment of checking the normality assumption itself, see CASRAI’s guide to normality of distribution, and for reading skew direction off the shape, left-skewed vs. right-skewed distributions.

By-group panels: the by() option

Add by(groupvar) to produce one histogram panel per distinct value of a grouping variable, laid out as small multiples on shared axes rather than overlaid in one plot area:

histogram days, by(department)

The standard by() layout controls apply, so you can adjust the panel grid and add a shared title:

histogram days, by(department, rows(2) title("Review turnaround by department"))

This is the right tool when you want to compare distributions side by side, each with its own clean, uncluttered bars. It is the wrong tool when you want the groups overlapping in a single plot area for a direct visual comparison of overlap — for that, use twoway histogram with transparency, covered next.

twoway histogram: combining a histogram with other plot types

The standalone histogram command draws one complete graph and accepts only histogram-specific options. twoway histogram is the same underlying plot, but used as one layer inside a graph twoway call, which lets you combine it with any other twoway plottype — another histogram, a kernel density estimate, a fitted line, an arbitrary function — in one shared coordinate space:

twoway (histogram days, percent) (kdensity days), legend(off)

That overlays a smoothed kernel density curve on top of the histogram bars, both on the same percent-equivalent scale. It’s a more flexible alternative to histogram‘s own normal option when you want a nonparametric density estimate rather than a normal curve fit, or when you want to layer more than one addition at once.

The case twoway histogram genuinely enables that the standalone command cannot is overlaying two histograms in the same plot area — comparing two groups’ distributions directly, not as separate panels:

twoway (histogram days if department == 1, color(blue%40)) ///
       (histogram days if department == 2, color(red%40)), ///
       legend(order(1 "Department A" 2 "Department B"))

Each parenthesized piece is a full if-restricted histogram call with its own styling; the %40 suffix on color() sets partial transparency, so overlapping bars from both groups stay visible instead of one occluding the other. by() gives you the same two distributions side by side in separate panels; twoway histogram with two layers gives you them overlapping in one panel — pick based on whether the comparison you want to show is “same axes, different panels” or “same panel, direct overlap.”

One shortcut worth knowing before reaching for full twoway syntax: the standalone histogram command has its own addplot() option, which adds a single extra twoway-plot layer without writing out the parenthesized twoway (...) (...) form at all:

histogram days, normal addplot(kdensity days)

addplot() is the simpler path for “one histogram plus one extra layer.” Write the full twoway (histogram ...) (...) syntax when you need more than one histogram layer, precise control over each layer’s draw order and styling, or a second y-axis (yaxis(2)) for a layer on a different scale.

Common mistakes

  • Combining bin() and width(). Stata rejects the command — pick one. If you need a specific width, use width() directly rather than trying to reverse-engineer the matching bin() count.
  • Reading density bars as counts. The default y-axis is density (area = 1), not frequency. If a reviewer or a reader expects raw counts, add frequency explicitly — don’t leave the default in place and relabel the axis by hand.
  • Binning genuinely discrete data. Running the default continuous binning on integer count data (number of publications, number of coauthors) can split or merge values in a way that misrepresents the distribution. Use discrete for count-like variables instead of tuning bin()/width() to approximate it.
  • Expecting by() to overlay groups. by() produces separate panels, not one overlapping plot — a common source of “I wanted them on the same axes” confusion. Use two twoway histogram layers with transparency instead.
  • Opaque overlapping bars. Two twoway histogram layers without a transparency setting (the %NN suffix on color()) will have the second layer’s bars simply cover the first’s wherever they overlap, hiding real overlap in the data.

Frequently asked questions

What’s the difference between histogram and twoway histogram in Stata?

The histogram command draws one complete, standalone histogram and only accepts histogram-specific options. twoway histogram is the same plot used as one layer inside a graph twoway call, so it can be combined with other twoway plottypes — another histogram, a kernel density curve, a fitted line — in the same coordinate space. For a single histogram with no combination, they produce the same bars; the distinction only matters once you’re layering plots.

How do I control bin width in Stata’s histogram command?

Use bin(#) to set the number of bins, or width(#) to set the bin width directly — not both at once. Add start(#) to fix where the first bin begins if a natural boundary needs to land exactly on a bin edge.

How do I overlay a normal curve on a Stata histogram?

Add the normal option: histogram varname, normal. Stata fits the curve to the variable’s own mean and standard deviation and draws it on the same density scale as the bars. Style the line itself with normopts().

How do I make separate histograms for each group in Stata?

Add by(groupvar) to the histogram command for one panel per group value on shared axes. If you want the groups overlapping in a single plot area instead of separate panels, use two twoway histogram layers with a transparent color() setting.

Does a Stata histogram show counts or density by default?

Density — bar heights are scaled so the total area sums to 1, not raw observation counts. Add frequency to show counts, fraction for proportion of the total, or percent for percentage.

For the broader statistical logic behind histograms and how to read one regardless of software, see CASRAI’s guide to histograms. For related descriptive-statistics groundwork in Stata, see descriptive statistics and standard deviation. For other Stata procedures, see running a t-test in Stata and the collapse command in Stata, and for choosing Stata over another package, CASRAI’s comparisons of SPSS vs. Stata and R vs. Stata.

Follow CASRAI

Research-administration guidance, standards updates and independent tool reviews.

Referenced across the research world

University of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logoUniversity of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logo
  • University of Cambridge logo
  • Columbia University logo
  • Crossref logo
  • University of Edinburgh logo
  • Harvard University logo
  • University of Oxford logo
  • Princeton University logo
  • Stanford School of Medicine logo
  • University College London logo
  • ORCID logo

View CASRAI adoption →

Regulatory Radar

Stop finding out after the fact

$29/month, cancel anytime. Daily digest updates from our analysis, a dashboard holding the same items, and a cited assistant for everything they raise.

  • Federal Register, Federal Register+, Grants.gov, Regulations.gov, NSF News, UKRI, plus CASRAI’s own published content.
  • 44,322 indexed passages, and every answer cites the ones it drew on.