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

Seaborn Histogram: sns.histplot Syntax, Bins, KDE and Hue

How to draw a seaborn histogram with sns.histplot: bins, stat options, KDE, hue overlays and the common_norm trap when comparing groups.

Written and maintained by CASRAI Editorial Board

Last updated

A seaborn histogram is drawn with seaborn.histplot(): pass a DataFrame and a column name, and it bins the values and draws bars whose heights follow the stat option you choose (count by default). This guide is for researchers who need a defensible distribution figure in Python: choose bins, pick the right normalisation, overlay groups without misleading the reader, and report the choices.

What it is used for in research

A histogram shows how the values of one numeric variable are distributed: where they cluster, how spread out they are, and whether there is more than one mode. In seaborn, histograms are the default plot type for both histplot() and the figure-level displot(). The seaborn tutorial on visualizing distributions advises: “It is always advisable to check that your impressions of the distribution are consistent across different bin sizes.” For the general concept, see CASRAI’s histogram guide; for the matplotlib route (ax.hist), see histogram in matplotlib.

Install or access

The seaborn installation page (read 2026-11-07) gives these commands:

  • pip install seaborn
  • pip install seaborn[stats] for the optional statistical dependencies
  • conda install seaborn, or conda install seaborn -c conda-forge

The mandatory dependencies are numpy, pandas and matplotlib. The page stated Python 3.8 or later when read; the install page carries the current requirement.

Step-by-step: draw and tune a histogram

The signature, from the official seaborn.histplot reference, begins seaborn.histplot(data=None, *, x=None, y=None, hue=None, weights=None, stat='count', bins='auto', binwidth=None, binrange=None, discrete=None, cumulative=False, common_bins=True, common_norm=True, multiple='layer', element='bars', fill=True, shrink=1, kde=False, ...).

  1. Import and prepare data. Put the variable in a pandas DataFrame column. The data below are generated only to make the example runnable.
    import numpy as np
    import pandas as pd
    import seaborn as sns
    import matplotlib.pyplot as plt
    
    rng = np.random.default_rng(1)
    df = pd.DataFrame({
        "score": rng.normal(50, 10, 300),
        "group": rng.choice(["A", "B"], 300),
    })
  2. Draw the basic histogram. sns.histplot(data=df, x="score"), then plt.show(). The default is bins='auto', which is passed to numpy.histogram_bin_edges().
  3. Set the bins. bins=30 sets a number of bins, binwidth=3 sets a fixed width and overrides bins, and binrange=(20, 80) limits the range (the default is the data extremes). bins can also be a rule name or explicit edges.
  4. Add a density curve. sns.histplot(data=df, x="score", kde=True) overlays a kernel density estimate (univariate plots only). Smoothness is controlled through kde_kws, for example bw_adjust.
  5. Split by group. sns.histplot(data=df, x="score", hue="group"). See the comparing-groups section below for the layering options.
  6. Change the vertical scale. Set stat="density", "percent" and so on (table below).
  7. Bivariate version. Passing both x and y draws a two-dimensional histogram; cbar=True adds a colour bar, and thresh, pthresh and pmax control which cells are shaded.

Output and how to read it

The stat options

The default stat='count' shows the number of observations per bin. The documented alternatives:

stat What the bars show
count (default) Number of observations in each bin
frequency Observations divided by bin width
probability or proportion Heights sum to 1
percent Heights sum to 100
density Total area of the bars equals 1

The seaborn tutorial notes that stat="probability" suits discrete data, while stat="density" normalises so areas sum to 1. Because both are normalised, they let you compare samples of different sizes; raw counts make a larger sample look taller.

Comparing groups: layer, step, stack, dodge

With hue, the default multiple="layer" overlays translucent bars, which the tutorial says can be hard to read. Documented alternatives:

  • element="step" draws outlines instead of filled bars, easing comparison.
  • multiple="stack" shows part-to-whole composition but can hide modes within groups.
  • multiple="dodge" places bars side by side and suits only a few levels.
  • multiple="fill" is the remaining documented option for univariate plots.

The normalisation trap. By default common_norm=True, so normalisation is applied over the whole dataset: with stat="density", each group keeps its share of the total, so a smaller group’s histogram is lower. To compare the shape of each group on its own, set common_norm=False, which normalises each subset separately. The official example is sns.histplot(data=penguins, x="bill_length_mm", hue="island", element="step", stat="density", common_norm=False). Bins are shared across groups by default (common_bins=True).

Integer and Likert data

Integer-valued data can leave gaps between bars when bins do not align with the values. Use explicit bin edges or discrete=True, which centres bars on the data points and defaults binwidth to 1. Categorical variables get discrete bins automatically. Example: sns.histplot(data=df, x="rating", stat="percent", discrete=True).

Reporting for a paper

The documentation notes that bins that are too large erase features and bins that are too small show noise. State your bin rule, width or count, and the stat in the figure caption, and check that the conclusion survives a different bin choice. A log-scaled axis is available through log_scale=True. Colour choices are covered in seaborn color palettes.

Troubleshooting

Symptom Documented cause and fix
Gaps between bars in integer data Bins do not align with integer values. Use discrete=True or explicit bin edges.
Features vanish, or the plot looks jagged Bins too large or too small. Try several bins or binwidth values.
Overlaid groups are unreadable Use element="step", multiple="stack", or multiple="dodge" for few levels.
A smaller group looks low under stat="density" common_norm=True is the default. Set common_norm=False.

Free alternatives

Option Notes
seaborn.displot() Figure-level interface in seaborn; histograms are its default plot type (seaborn tutorial).
matplotlib Axes.hist The lower-level route; see histogram in matplotlib.
numpy.histogram_bin_edges() The function histplot uses to compute bins when you pass a rule name.

For a grid of pairwise distributions, see pairplot in seaborn.

FAQ

How do I make a histogram in seaborn?

Call sns.histplot(data=df, x="column"), then plt.show(). Bins default to 'auto'.

How do I change the number or width of bins?

Use bins= for a count, rule or edges, or binwidth= for a fixed width, which overrides bins.

How do I show percentages instead of counts?

Set stat="percent" so heights sum to 100, or stat="probability" so they sum to 1.

How do I add a density curve?

Set kde=True; adjust smoothness with kde_kws.

What is the difference between histplot and displot?

histplot() draws a histogram on a single axes; displot() is the figure-level distribution function. Histograms are the default for both.

Sources

Follow CASRAI

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

Ask CASRAI · free to try

Ask about Seaborn Histogram: sns.histplot Syntax, Bins, KDE and Hue

Ask your first 2 questions free below. Subscribers get 150 a day for $29 a month.

An AI assistant specialized in research administration. It cites the sources behind every answer, labels web answers and says when it can't answer.

Answers draw on CASRAI's guides and dictionary plus the federal and funder documents we index: Federal Register, Grants.gov, Regulations.gov and UKRI.

Works on this site and inside Claude, Cursor and the AI tools you already use.

Everything CASRAI publishes — this page, the dictionary, the guides and the news — stays free to read, with no account and no card.

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 →