Written and maintained by CASRAI Editorial Board
Last updated
A strip plot (also called a strip chart or jitter plot) is a scatterplot in which one variable is categorical: every observation is drawn as its own point, and the points in each category are spread slightly sideways so they do not sit on top of each other. It is used to show all the raw data for each group, alone or beside a box plot or violin plot. This guide covers what the chart shows, how to build it in Python (seaborn and Plotly Express) and R (ggplot2), and how to read it.
What is a strip plot? (strip chart meaning)
The seaborn documentation describes stripplot as a categorical scatterplot that uses jitter to reduce overplotting. It can be drawn on its own or alongside a box or violin plot to show each observation together with a summary of the underlying distribution. Plotly’s documentation calls a strip chart a box plot with the points showing and no box.
What is a chart strip?
“Chart strip” is a loose search phrase for the same thing: the strip chart. Each category gets a narrow vertical (or horizontal) band, and each data value in that category is one marker within the band. The value axis carries the data; the position across the band is random jitter and carries no information.
Jitter plot
“Jitter plot” names the technique rather than a different chart. Jitter is a small random displacement applied to each point to handle overplotting caused by discrete positions (ggplot2 documents geom_jitter in exactly these terms). In seaborn, jitter is applied along the categorical axis only.
When to use a strip plot
- You want every observation visible. Unlike a box plot, nothing is summarised away, so sample size, gaps and outliers are all apparent.
- You are comparing a numeric outcome across a few groups (for example, one numeric measurement per condition).
- You want to annotate a summary plot with the raw data. Seaborn’s documentation presents the strip plot as a companion to violin plots and box plots; see also box plots in R.
If both axes are numeric and continuous, use an ordinary scatterplot instead (see scatterplots in R); jitter is meant for a categorical axis.
Strip plot vs swarm plot
Seaborn offers two related categorical scatterplots. stripplot jitters points randomly. swarmplot instead adjusts points, only along the categorical axis, so that they do not overlap. The swarmplot documentation notes that it does not scale well to large numbers of observations; when space runs out, points are forced to overlap in the “gutters” of each swarm and a warning is issued suggesting smaller markers or stripplot.
| Question | Strip plot | Swarm plot |
|---|---|---|
| How points are separated | Random jitter along the categorical axis | Adjustment along the categorical axis so points do not overlap |
| Large numbers of observations | Points may still overlap | Does not scale well; may warn that points cannot be placed |
Install or access
All three libraries are free, open-source packages from their own projects: seaborn (built on matplotlib), Plotly for Python and ggplot2 (part of the tidyverse). For base R, see stripchart() in R.
How to make a strip plot in Python
Seaborn
- Import the library and load an example dataset:
import seaborn as sns, thentips = sns.load_dataset("tips"). - Draw the plot:
sns.stripplot(data=tips, x="day", y="total_bill"). - To split by a second variable, add
hueanddodge=True:sns.stripplot(data=tips, x="total_bill", y="day", hue="sex", dodge=True). - To turn jitter off, pass
jitter=False. - To facet, use
sns.catplot(data=tips, x="time", y="total_bill", hue="sex", col="day", aspect=.5)rather than a FacetGrid.
How do I create a strip chart in Python with Plotly?
import plotly.express as pxdf = px.data.tips()fig = px.strip(df, x='day', y='tip')fig.show()
How to make a strip plot in R
In ggplot2, a jittered strip plot is a geom_point with jittered position. geom_jitter() is documented as a shortcut for geom_point(position = "jitter"). The signature is geom_jitter(mapping = NULL, data = NULL, stat = "identity", position = "jitter", ..., width = NULL, height = NULL, na.rm = FALSE, show.legend = NA, inherit.aes = TRUE). The documentation’s example is:
library(ggplot2)
ggplot(mpg, aes(cyl, hwy)) + geom_jitter(width = 0.25)
Jitter is added in both directions, so the total spread is twice the width or height value; the default is 40% of the data resolution. For the base R function, with its jitter, overplot and stack methods, see stripchart() in R.
Equivalent calls across tools
| Tool | Call | Separation method |
|---|---|---|
| seaborn | sns.stripplot(data=tips, x="day", y="total_bill") |
Random jitter (default jitter=True) |
| Plotly Express | px.strip(df, x='day', y='tip') |
Strip chart of points without a box |
| ggplot2 | geom_jitter(width = 0.25) |
Random jitter via position = "jitter" |
| Base R | stripchart() |
See the stripchart guide |
Output and how to read it
- Read the value axis only. Position within a strip, across the category axis, is random jitter, so two points side by side are not “closer” in any data sense.
- Density shows as crowding. Dense stretches of a strip mean many observations at those values; with heavy overlap, reduce marker size or pair the plot with a violin or box plot.
- Jitter is random. Two runs can differ in point positions.
geom_jitterhas no seed argument, so set a random seed in your own code if you need identical figures each run.
Troubleshooting
- Points have no outline in seaborn. The
linewidthdefault is 0, so marker edges are invisible; setlinewidthandedgecolorto see them. - Legend duplicates the axis when
huerepeats the category. Uselegend=False, as insns.stripplot(data=tips, x="total_bill", y="day", hue="day", legend=False). - Numeric categories are evenly spaced. By default, seaborn places categorical values at ordinal positions 0..n. Set
native_scale=Trueto keep numeric or datetime values on their original scale (this parameter, withlog_scale,formatterandlegend, arrived in seaborn 0.13.0; the documentation read is 0.13.2). - Orientation.
orientaccepts “v”, “h”, “x” or “y” (“x”/”y” added in 0.13.0). - Points overlap too much. Lower
size(marker radius in points, default 5) or, in ggplot2, adjustwidth.
Free alternatives and companions
| Chart | What it adds or changes | Source |
|---|---|---|
| Swarm plot | Points adjusted so they do not overlap; does not scale well to large samples | seaborn swarmplot docs |
| Box plot | Plotly describes a strip chart as a box plot with points and no box | Plotly box plot docs |
| Violin plot | Documented as a companion to strip points | seaborn stripplot docs; seaborn violin plots |
| Scatterplot | For two numeric variables, no categorical axis | scatterplots in R |
FAQ
When to use a strip plot?
Use it when you have a numeric measurement across a small number of categories and want every observation visible, either alone or on top of a box or violin plot.
What is a chart strip?
It is usually a strip chart: a categorical scatterplot where each category is a narrow band containing one point per observation.
How to make a strip plot in R?
With ggplot2, use geom_jitter() (a shortcut for geom_point(position = "jitter")), for example ggplot(mpg, aes(cyl, hwy)) + geom_jitter(width = 0.25). In base R, use stripchart().
How do I create a strip chart in Python?
Use sns.stripplot(data=tips, x="day", y="total_bill") in seaborn or px.strip(df, x='day', y='tip') in Plotly Express.
Strip plot vs swarm plot: which should I use?
Swarm plots avoid overlap but do not scale well to large samples; strip plots use random jitter and can overlap.
Sources
- seaborn.stripplot, seaborn 0.13.2 documentation (read 2026-11-07)
- seaborn.swarmplot documentation (read 2026-11-07)
- Plotly, Box plots in Python (box plot with only points) (read 2026-11-07)
- ggplot2 reference: geom_jitter (read 2026-11-07)







