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

Bar Charts in Stata: graph bar and graph hbar

How to build grouped and stacked bar charts in Stata with graph bar and graph hbar: the over() option for categorical breakdowns, asyvars for stacking, and value labels.

Ask about Bar Charts in Stata: graph bar and graph hbar

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

graph bar draws vertical bars and graph hbar draws the identical chart rotated onto its side — every option covered here works the same way in both. By default each bar shows the mean of a variable; over() is the option that turns a single bar into a categorical breakdown, and it is what most of the syntax below revolves around.

This page covers the syntax specifically: choosing graph bar vs. graph hbar, building grouped and stacked variants with over() and asyvars, and adding value labels. For the underlying statistics — means, standard deviations, and how to report them — see CASRAI’s guide to descriptive statistics first if you need that background.

graph bar vs. graph hbar: which one to use

The two commands accept identical syntax; the only difference is orientation. graph bar puts categories on the horizontal axis and bar height encodes the value — the familiar default. graph hbar puts categories on the vertical axis and bar length encodes the value.

Use graph hbar whenever category labels are long or numerous: institution names, survey item text, or more than five or six over() levels all become unreadable as rotated labels under vertical bars, but read cleanly down the left margin of a horizontal chart. Use graph bar for short category labels (year, group, yes/no) where the default vertical orientation is more familiar to readers.

graph bar (mean) score, over(department)
graph hbar (mean) score, over(department)

Basic syntax: plotting means, sums, and other statistics

A bar in graph bar is always a summary statistic of a variable, never a raw value — there is no way to plot one bar per observation. The statistic defaults to the mean if you don’t specify one; write it as a parenthetical immediately before the variable to use something else:

graph bar score
graph bar (mean) score
graph bar (sum) score
graph bar (median) score
graph bar (count) score

The first two lines are equivalent. Common alternatives to (mean): (sum) for totals, (median), (sd), (count) for the number of non-missing observations, and (percent) for the share of observations falling in each category — useful for a distribution chart rather than a summary-statistic chart:

graph bar (percent), over(status)

Note there’s no variable name after (percent) here — percent-of-observations doesn’t need one; Stata is counting rows in each over() category, not summarizing a value.

The over() option: categorical breakdowns

over(groupvar) is what turns a single overall bar into one bar per category. It’s the option that does almost all the real work in a Stata bar chart:

graph bar (mean) score, over(department)

You can stack multiple over() options to nest categories — the first over() becomes the outer grouping (shown as the outer axis labels, spanning several bars), and each subsequent over() nests inside it:

graph bar (mean) score, over(department) over(cohort)

That example produces one cluster of bars per department, with a bar for each cohort inside every department’s cluster. Relabel category values inline instead of recoding the underlying variable with relabel():

graph bar (mean) score, over(status, relabel(1 "Active" 2 "Completed" 3 "Withdrawn"))

over() is not the same as the separate by() option: over() puts multiple categories inside one graph, while by() draws an entirely separate small-multiple graph per level — useful when a breakdown has too many combinations to read as nested bars in a single frame:

graph bar (mean) score, over(department) by(site)

Grouped (clustered) bars from multiple variables

Listing more than one y-variable produces a cluster of side-by-side bars automatically, without needing over() at all — one bar per variable, or one cluster of bars per variable if combined with over():

graph bar (mean) pretest posttest
graph bar (mean) pretest posttest, over(group)

The second line draws one cluster per group level, with a pretest bar and a posttest bar side by side inside each cluster — the standard “grouped bar chart” layout for a before/after or a multi-series comparison.

Stacked bars: asyvars and stack

By default, combining multiple y-variables with over() clusters the bars side by side, as above. To stack them into a single bar per category instead, add stack:

graph bar (mean) pretest posttest, over(group) stack

The harder case is stacking a single variable broken down by an over() group — e.g., one bar per department, each bar internally divided into segments for a status category. stack alone can’t do this, because with a single y-variable and no second series, there’s nothing to stack against. asyvars is the option that fixes this: it tells Stata to treat the levels of the first over() group as if they were separate y-variables, which gives stack something to work with:

graph bar (mean) score, over(status) over(department) asyvars stack

That produces one stacked bar per department, with each bar internally divided by status, and a legend keyed to the status categories — the composition chart most people actually mean when they ask for a “stacked bar chart in Stata.” Without asyvars, the same command draws nested clustered bars instead of stacked segments.

Adding value labels

blabel(bar) prints the value of each bar directly above (or, for graph hbar, beside) the bar itself — useful when exact figures matter and you don’t want a reader estimating them off the axis:

graph bar (mean) score, over(department) blabel(bar)
graph bar (mean) score, over(department) blabel(bar, format(%9.1f))

The format() suboption controls decimal places using a standard Stata display format — %9.1f above rounds to one decimal place. Without it, Stata prints the statistic’s default precision, which for a mean is often more decimal places than a chart needs.

Common mistakes

  • Forgetting the default statistic is the mean, not the count. graph bar score plots average score, not how many observations have each value of score — if you want a frequency count, use (count) explicitly, or use histogram instead if score is continuous.
  • Confusing over() nesting order. The first over() is the outer grouping and the last is the innermost; swapping the order of over(department) over(cohort) to over(cohort) over(department) changes which variable’s labels sit on the outer axis, not just the visual grouping.
  • Adding stack without asyvars and expecting a single-variable breakdown to stack. As above, stack needs either multiple y-variables or asyvars to have separate series to stack — on its own with one variable and one over(), it has no effect.
  • Using graph bar for many long category labels. Vertical bars force rotated or truncated axis text once you’re past a handful of categories; switch to graph hbar rather than fighting label angle options.

Frequently asked questions

What’s the actual difference between graph bar and graph hbar?

Orientation only. Every option — over(), asyvars, stack, blabel() — works identically in both; graph hbar simply draws categories on the vertical axis and values on the horizontal axis instead of the reverse.

How do I plot percentages instead of means?

Use (percent) as the statistic with no variable name: graph bar (percent), over(group) shows what share of observations fall into each level of group, rather than summarizing a separate outcome variable.

Why won’t stack produce a stacked bar for my single variable?

Because stack stacks series, and a single y-variable with one over() group has only one series. Add asyvars so the over() levels are treated as the stackable series.

Can I show two grouping variables side by side instead of nested?

Yes — list the outcome as multiple variables (one per series) combined with a single over(), rather than two over() options, to get clustered rather than nested bars. See the grouped-bars section above.

Related CASRAI guides

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.