Understanding hvPlot’s Statistical Plot Types#

hvPlot provides several statistical plots that go beyond basic charts. Each one answers a different question about your data, and some take a bit of practice to read. For each plot, this guide explains what it shows, when to use it, and how to read it on a concrete example.

Which plot should I use?#

Question

Plot

hvPlot method

What values does a variable take, and how often?

Histogram

df.hvplot.hist()

Same, as smooth curves that compare groups of different sizes?

KDE

df.hvplot.kde()

How do groups compare (median, spread, outliers)?

Box plot

df.hvplot.box()

Same, including the shape of each distribution?

Violin plot

df.hvplot.violin()

How are two variables related?

Scatter plot

df.hvplot.scatter()

Same, with too many points to see them all?

Hexbin plot

df.hvplot.hexbin()

Which combinations of two variables are most common?

Bivariate plot

df.hvplot.bivariate()

Which variables are correlated?

Heatmap

df.corr().hvplot.heatmap()

What do all pairwise relationships look like?

Scatter matrix

hvplot.scatter_matrix(df)

Which variables distinguish groups?

Parallel coordinates

hvplot.parallel_coordinates(df, class_column)

Are groups separated when all variables are combined?

Andrews curves

hvplot.andrews_curves(df, class_column)

Does a time series depend on its past values?

Lag plot

hvplot.lag_plot(df)

Sample data#

Most examples use the Palmer penguins dataset: body measurements of 333 penguins from three species (Adelie, Chinstrap and Gentoo). The time series example uses weekly stock prices, normalized to 1 at the start of 2019.

import hvplot.pandas  # noqa

penguins = hvplot.sampledata.penguins("pandas").dropna()
stocks = hvplot.sampledata.stocks("pandas")

num_cols = ['bill_length_mm', 'bill_depth_mm', 'flipper_length_mm', 'body_mass_g']
penguins_subset = penguins[['species', *num_cols]]

# Standardized copy (mean 0, standard deviation 1) so that all variables share the same scale
penguins_scaled = penguins_subset.copy()
numeric = penguins[num_cols]
penguins_scaled[num_cols] = (numeric - numeric.mean()) / numeric.std()

Distributions#

The distribution of a variable tells you which values it takes and how often. These plots answer questions like: what are the typical values, how spread out are they, is there more than one peak, are there unusual values?

Histograms#

What it shows: How many observations fall into each range (bin) of values.

Strengths:

  • Familiar and easy to read

  • Shows the shape, the spread, multiple peaks and gaps

Best for: A first look at a single variable.

Limitations: The shape depends on the number of bins; more than two or three overlaid groups get hard to read.

penguins.hvplot.hist(y='body_mass_g', by='species', alpha=0.6, bins=20)

How to read it: Each bar’s height is the number of penguins in that range of body mass. Look at where the bars are tallest (the typical values), how wide the spread is, and whether there is more than one peak. Heights are counts, so a smaller group always looks lower.

In this example: Gentoo penguins are clearly heavier (around 5000 g) and barely overlap with the other two species. Adelie and Chinstrap penguins have almost the same body mass (around 3700 g); the Chinstrap bars are lower only because the dataset has fewer of them (68 against 146 Adelie).

See also

See the reference guide for Histograms

KDE (Kernel Density Estimation) Plots#

What it shows: A smooth curve estimating the distribution, like a histogram without bins.

Strengths:

  • Overlaid curves are easier to compare than overlaid bars

  • Each curve encloses an area of 1, so groups of different sizes compare fairly

Best for: Comparing the shapes of a few distributions.

Limitations: The amount of smoothing (bandwidth) can hide real bumps or create fake ones; curves can extend beyond the possible values (e.g. below zero).

penguins.hvplot.kde(y='body_mass_g', by='species', alpha=0.6)

How to read it: The higher the curve, the more common the value. The y-axis shows a density, not a count: its values depend on the units of the x-axis (small numbers like 0.001 are normal here), so focus on the shape. One peak means one typical value; two peaks suggest two subgroups.

In this example: Unlike in the histogram, the Adelie and Chinstrap curves have about the same height, confirming that their body mass distributions are nearly identical. The Gentoo curve has two bumps, around 4700 g and 5500 g, which match the average body mass of females and males (the dataset has a sex column to check this).

See also

See the reference guide for KDE plots

Box Plots#

What it shows: A summary of each distribution: median, quartiles, range and outliers.

Strengths:

  • Compact, so many groups fit side by side

  • Shows outliers explicitly

Best for: Comparing the center and spread of several groups.

Limitations: Hides the shape: a distribution with two peaks can look exactly like one with a single peak.

penguins.hvplot.box(y='flipper_length_mm', by='species')

How to read it: The line inside the box is the median: half of the values are below it, half above. The box contains the middle 50% of the values (from the first to the third quartile), so a taller box means a wider spread. The whiskers extend to the most extreme values within 1.5 box heights of the box, and any value beyond them is drawn as a point, as a potential outlier.

In this example: Gentoo penguins have the longest flippers (median 216 mm) and their box doesn’t overlap with the others, so flipper length alone tells most Gentoo apart. The three boxes have about the same height, so the spread is similar across species. Adelie has two outliers, one short (172 mm) and one long (210 mm).

See also

See the reference guide for Box plots

Violin Plots#

What it shows: A box plot surrounded by a mirrored KDE curve.

Strengths:

  • Shows the shape of the distribution, including multiple peaks

  • Still compact enough to compare several groups

Best for: Comparing groups when the shape matters, not just the median and the spread.

Limitations: Same smoothing caveats as the KDE; less familiar to many audiences.

penguins.hvplot.violin(y='bill_length_mm', by='species')

How to read it: The width of the violin at a given value shows how common that value is. Inside, the white dot is the median, the thick black bar is the box of the box plot (the middle 50% of values), and the thin line plays the role of the whiskers.

In this example: Adelie penguins have shorter bills (median 39 mm) than Chinstrap and Gentoo penguins, whose bills are similar in length. The Chinstrap violin has two bulges, around 46 mm and 51 mm, which match the average bill length of females and males; a box plot would hide this. The long thin tip at the top of the Gentoo violin comes from a single penguin with a 59.6 mm bill.

See also

See the reference guide for Violin plots

Relationships Between Two Variables#

To see how two variables relate, for example whether longer bills go with longer flippers, plot one against the other. The three plots below show the same two variables in different ways.

Scatter Plots#

What it shows: One point per observation, placed at its x and y values.

Strengths:

  • The simplest and most direct view of a relationship

  • Shows individual points and outliers, and can color them by group

Best for: Small to medium datasets, and as a first step before any other plot.

Limitations: With many points, they overlap and dense areas turn into a blob.

penguins.hvplot.scatter(x='bill_length_mm', y='flipper_length_mm', by='species', alpha=0.6)

How to read it: A cloud going up to the right means the two variables increase together (positive relationship); going down means one decreases when the other increases (negative relationship); no direction means no clear relationship. Separate clouds indicate distinct groups.

In this example: Coloring by species reveals three groups: Adelie penguins have short bills and short flippers, Gentoo penguins long bills and long flippers, and Chinstrap penguins long bills but short flippers. Within each species, longer bills tend to go with longer flippers.

See also

See the reference guide for Scatter plots

Hexbin Plots#

What it shows: The plot area divided into hexagonal cells, each colored by the number of points it contains.

Strengths:

  • Works with any number of points, from thousands to millions

  • Reveals where points concentrate, which overlapping points hide in a scatter plot

Best for: Large datasets where a scatter plot is overcrowded.

Limitations: Individual points and outliers are lost; the result depends on the cell size (gridsize).

# The hexagons stretch with the plot shape, aspect=1 keeps them regular
penguins.hvplot.hexbin(x='bill_length_mm', y='flipper_length_mm', gridsize=15, aspect=1)

How to read it: Darker cells contain more points; the color bar gives the counts. Empty areas have no data.

In this example: With only 333 penguins the scatter plot is still readable, but the hexbin makes it easier to see where penguins concentrate. The darkest cells are around 36 to 41 mm bill length with 190 mm flippers (Adelie), and around 46 mm with 215 mm (Gentoo). A hexbin can’t color points by group, so on its own it doesn’t tell which species is which.

See also

See the reference guide for Hexbin plots

Bivariate Plots#

What it shows: A 2D KDE: the density of two variables drawn as contour lines.

Strengths:

  • Smooth view of where the data concentrates

  • Shows peaks clearly, even when many points overlap

Best for: Finding the most common combinations of values and spotting subgroups.

Limitations: Same smoothing caveats as the KDE; small groups can almost disappear; individual points aren’t shown.

penguins.hvplot.bivariate(x='bill_length_mm', y='flipper_length_mm')

How to read it: Read it like the contour lines of a hiking map: each line connects points of equal density, and darker, tightly packed lines climb towards a peak. Peaks are the most common combinations of values.

In this example: There are two clear peaks, around 38 mm bill length with 190 mm flippers and around 47 mm with 215 mm. The scatter plot above shows that these are the Adelie and Gentoo penguins. The Chinstrap penguins (around 49 mm and 196 mm) only make a small bump, because there are fewer of them. Looking at this plot alone, you could easily conclude that the data contains only two groups. Also, unlike the scatter plot, this plot doesn’t use the species column, so it can’t tell you which species each peak is.

See also

See the reference guide for Bivariate plots

Many Variables#

With more than two variables, everything can’t fit on two axes. These plots offer different ways to look at all the numeric variables at once.

Heatmaps#

What it shows: A grid of colored cells; here, the correlation between each pair of variables.

Strengths:

  • Summarizes every pair of variables in one compact view

  • Scales well to many variables

Best for: Correlation matrices, and any data shaped like a table of values (e.g. counts per day and hour).

Limitations: A correlation is a single number per pair: it only captures straight-line relationships and can mislead when the data mixes groups (see below).

correlation_matrix = penguins[num_cols].corr()
# clim=(-1, 1) keeps the color scale centered, so that white means no correlation
correlation_matrix.hvplot.heatmap(cmap='coolwarm', clim=(-1, 1))

How to read it: A correlation goes from -1 to 1. Red cells mean the two variables increase together, blue cells mean one decreases when the other increases, and pale cells (close to 0) mean no linear relationship. The diagonal is always 1, since each variable is perfectly correlated with itself. Hover over a cell to see its value.

In this example: Flipper length and body mass are strongly correlated (0.87): heavier penguins have longer flippers. Bill depth is negatively correlated with the other variables, which suggests that penguins with deeper bills are smaller. This is misleading: within each species, bill depth is positively correlated with the other measurements. The negative correlation only appears when the species are mixed, because Gentoo penguins are large but have shallow bills. The scatter matrix below makes this visible.

See also

See the reference guide for Heatmaps

Scatter Matrix#

What it shows: A grid of scatter plots, one for every pair of numeric variables, with the distribution of each variable on the diagonal.

Strengths:

  • Shows every pairwise relationship, including groups and non-linear patterns

  • Axes are linked, so zooming in one plot updates the others

Best for: Exploring a dataset with a handful of numeric variables.

Limitations: The number of plots grows quickly (10 variables make 100 plots); only shows pairs, not combinations of three or more variables.

hvplot.scatter_matrix(penguins_subset, c='species', alpha=0.6)

How to read it: Each plot shows the variable of its column (x-axis) against the variable of its row (y-axis), so plots on either side of the diagonal are mirror images. Each diagonal plot is a histogram of a single variable.

In this example: Gentoo penguins form a separate cluster in every plot involving bill depth: they are large but have shallow bills. Inside each cluster, the points go up to the right, confirming that bill depth increases with the other measurements within each species, contrary to what the overall correlation suggested. Adelie and Chinstrap penguins overlap, except in the plots involving bill length.

See also

See the reference guide for Scatter Matrix

Parallel Coordinates#

What it shows: Each observation drawn as a line crossing one vertical axis per variable, colored by group.

Strengths:

  • Shows all variables at once

  • Reveals which variables separate groups

Best for: Finding the variables that distinguish groups.

Limitations: Needs standardized data; cluttered with many observations; only neighboring axes are easy to compare, so the order of the variables matters.

hvplot.parallel_coordinates(penguins_scaled, 'species', alpha=0.2)

How to read it: Follow the lines of one color from axis to axis. Where the colors are vertically apart on an axis, that variable distinguishes the groups. Lines that cross between two axes (forming an X) indicate a negative relationship between the two variables; roughly parallel lines indicate a positive one. The values are standardized: 0 is the average and 1 is one standard deviation above it.

In this example: The Gentoo lines go from a low bill depth to a high flipper length and body mass, forming a band of their own. The Adelie lines are lowest on bill length, the only variable that clearly separates them from the Chinstrap lines: on the other three axes, both species overlap.

See also

See the reference guide for Parallel Coordinates

Andrews Curves#

What it shows: Each observation drawn as a curve that combines all its variables, colored by group.

Strengths:

  • Similar observations produce similar curves, so groups appear as bands and outliers stand out

  • Combines all variables, so it can reveal separations that no single variable shows

Best for: Checking how well groups separate overall, and spotting outliers.

Limitations: Needs standardized data; the curves depend on the order of the variables; hard to tell which variable drives a difference.

hvplot.andrews_curves(penguins_scaled, 'species', alpha=0.2)

How to read it: An observation with the values \(x_1, x_2, x_3, x_4\) (here bill length, bill depth, flipper length and body mass) becomes the curve:

\[f(t) = \frac{x_1}{\sqrt{2}} + x_2 \sin(t) + x_3 \cos(t) + x_4 \sin(2t)\]

for t going from -π to π. You don’t need the formula to read the plot: at each value of t, the curve is a different weighted mix of the variables. Look for the values of t where the bands of different colors are well apart: there, that mix of variables separates the groups. A curve far from the band of its group is an outlier.

In this example:

  • Around t = 0, the curves mostly add up bill length and flipper length: the three species form three separate bands, Gentoo on top and Adelie at the bottom.

  • At t = ±π, the curves mostly measure bill length minus flipper length: Chinstrap penguins, with long bills but short flippers, rise above the others.

  • Around t = 2.4, the curves add bill length and depth and subtract flipper length and body mass: Gentoo penguins, with shallow bills and large bodies, drop far below the others.

All three species are well separated at some values of t, which no single variable achieves.

See also

See the reference guide for Andrews Curves

Note

Both parallel coordinates and Andrews curves require standardized data. Without it, variables with large values (body mass, around 3000 to 6000 g) would dominate those with small values (bill depth, around 13 to 22 mm) and hide the patterns.

Time Series#

Lag Plots#

What it shows: Each value of a time series plotted against the value a fixed number of steps later (the lag).

Strengths:

  • Shows whether past values help predict future ones (autocorrelation)

  • Reveals trends and randomness without any modeling

Best for: Checking whether a time series has structure or behaves randomly, before modeling it.

Limitations: Only looks at one lag at a time; series with a trend, like prices, always look strongly autocorrelated.

# First 200 weeks, from 2019 to late 2022
stock_subset = stocks[['Apple', 'Microsoft']].iloc[:200]
hvplot.lag_plot(stock_subset, lag=30, alpha=0.6, aspect=1)

How to read it: Each point compares a value (x-axis) with the value lag steps later (y-axis). Points on the diagonal (y = x, not drawn) mean the value didn’t change; points above it mean it increased, points below mean it decreased. Points lining up along a line or a curve mean the series depends on its past; a shapeless cloud means it behaves randomly.

In this example: The data is weekly, so the lag is 30 weeks (about 7 months). Both stocks form a band rising from the bottom left: a price is a good predictor of the price 30 weeks later. Most points are above the diagonal since both stocks grew over the period, Apple points more so, meaning larger gains. Points below the diagonal, on the right of each band, show the 2022 decline.

Prices mostly reflect a trend. To check whether this week’s change says something about next week’s, plot the weekly returns (the percentage change from one week to the next) with a lag of 1 instead:

hvplot.lag_plot(stock_subset.pct_change().dropna(), lag=1, alpha=0.6, aspect=1)

The returns form a shapeless cloud centered on zero: a good or bad week doesn’t predict the next one. The width of the cloud reflects the volatility, how large the weekly changes typically are.

See also

See the reference guide for Lag plots

See also

This web page was generated from a Jupyter notebook and not all interactivity will work on this website.