#pythonIntermediate

Seaborn Data Visualization Guide: Charts & Techniques

Jun 21, 2026
50 min read

AI Insights

Powered by GPT-4o-mini

Verified Context: seaborn-data-visualization-guide-charts-techniques
Quick Answer

Learn Seaborn with original datasets and practical examples covering scatter plots, line plots, histograms, KDE plots, categorical charts, regression plots, heatmaps, clustermaps, pair plots, facets, themes, and palettes.

Quick Summary

Learn to create stunning visualizations with Seaborn. This guide covers scatter plots, heatmaps, regression, and more for effective data analysis.

Seaborn Plotting: Relational, Distribution, Categorical, Regression, Heatmap, Pair Plot, and Styling

Seaborn is a high-level visualization library built on top of Matplotlib.

Matplotlib gives you detailed control over every part of a figure. Seaborn gives you a faster way to create statistical charts from Pandas DataFrames. It also provides better default themes, easier grouping with hue, and convenient figure-level functions for facets.

This guide teaches Seaborn with original synthetic datasets about online learning sessions. It does not use copied course notebooks, built-in Seaborn datasets, or third-party exercise data.

Files Used In This Guide

Place these CSV files in the same folder as your notebook or script:

  • seaborn_learning_sessions.csv
  • seaborn_monthly_outcomes.csv

If you keep them in a data/ folder, update the paths:

python
sessions = pd.read_csv("data/seaborn_learning_sessions.csv")
monthly = pd.read_csv("data/seaborn_monthly_outcomes.csv")

What You Will Learn

By the end, you should be able to:

  • explain why Seaborn is useful even when you know Matplotlib
  • choose between axes-level and figure-level functions
  • create scatter plots and line plots with scatterplot, lineplot, and relplot
  • use hue, style, size, row, and col
  • inspect distributions with histograms, KDE plots, and rug plots
  • compare categories with count, bar, box, violin, strip, and swarm plots
  • fit simple trend lines with regression plots
  • build heatmaps from pivot tables and correlation matrices
  • create pair plots for quick multivariate exploration
  • control themes, palettes, labels, legends, and figure size
  • avoid common Seaborn mistakes in real analysis

1. Install And Import

Install the libraries if needed:

bash
pip install pandas matplotlib seaborn

Use this standard setup:

python
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

Set a clean theme once near the top of the notebook:

python
sns.set_theme(style="whitegrid", context="notebook")

Load the datasets:

python
sessions = pd.read_csv("seaborn_learning_sessions.csv")
monthly = pd.read_csv("seaborn_monthly_outcomes.csv")

monthly["month"] = pd.to_datetime(monthly["month"])

print(sessions.head())
print(monthly.head())

The sessions table has one row per learner session. The monthly table has one row per course track per month.

2. Understand The Data

Before plotting, inspect the columns:

python
print(sessions.info())
print(sessions.describe(numeric_only=True))
print(sessions["track"].value_counts())

Useful columns in sessions:

  • track: course area such as Python or Machine Learning
  • learner_level: Beginner, Intermediate, or Advanced
  • device: Laptop, Mobile, Tablet, or Desktop
  • study_minutes: time spent in the session
  • practice_questions: number of practice questions attempted
  • quiz_score: score out of 100
  • completion_pct: percentage of the lesson path completed
  • satisfaction: learner rating from 1 to 5
  • mentor_help: number of mentor help requests
  • certificate: whether the learner earned a certificate

Useful columns in monthly:

  • active_learners
  • avg_quiz_score
  • avg_completion_pct
  • projects_submitted
  • support_tickets

3. Axes-Level vs Figure-Level Functions

Seaborn has two common styles of function.

Axes-level functions draw on one Matplotlib axes object:

  • sns.scatterplot
  • sns.lineplot
  • sns.histplot
  • sns.kdeplot
  • sns.boxplot
  • sns.violinplot
  • sns.heatmap
  • sns.regplot

Figure-level functions create an entire figure and can easily build facets:

  • sns.relplot
  • sns.displot
  • sns.catplot
  • sns.lmplot
  • sns.pairplot

Use axes-level functions when you want precise Matplotlib control or subplots. Use figure-level functions when you want easy row, col, and col_wrap behavior.

4. First Scatter Plot

A scatter plot compares two numeric columns.

This chart asks: do learners who spend more time also score higher?

python
sns.scatterplot(
    data=sessions,
    x="study_minutes",
    y="quiz_score",
)

plt.title("Study Time vs Quiz Score")
plt.xlabel("Study Minutes")
plt.ylabel("Quiz Score")
plt.show()

Each point is one learner session.

If the points generally move upward from left to right, longer study time is associated with higher quiz score. Association is not proof of causation, but it is a good starting point for analysis.

5. Add Color, Style, And Size

Seaborn makes grouped scatter plots simple.

python
plt.figure(figsize=(10, 6))

sns.scatterplot(
    data=sessions,
    x="study_minutes",
    y="quiz_score",
    hue="track",
    style="device",
    size="practice_questions",
    sizes=(40, 220),
    alpha=0.85,
)

plt.title("Study Time, Quiz Score, Track, Device, and Practice Volume")
plt.xlabel("Study Minutes")
plt.ylabel("Quiz Score")
plt.legend(bbox_to_anchor=(1.02, 1), loc="upper left")
plt.tight_layout()
plt.show()

Use visual mappings carefully:

  • hue is usually best for categories.
  • style is useful for a small number of categories.
  • size works best for numeric magnitude.
  • Too many mappings can make a chart hard to read.

6. Figure-Level Scatter Plot With Facets

Use relplot when you want the same relationship split into multiple panels.

python
g = sns.relplot(
    data=sessions,
    x="study_minutes",
    y="quiz_score",
    kind="scatter",
    hue="track",
    col="learner_level",
    height=4,
    aspect=1,
)

g.set_axis_labels("Study Minutes", "Quiz Score")
g.fig.suptitle("Study Time vs Quiz Score By Learner Level", y=1.05)
plt.show()

Facets are useful when one crowded chart would hide patterns.

Here, each learner level gets its own panel. You can compare whether the study-time pattern looks similar for beginners, intermediate learners, and advanced learners.

Line plots work well when the x-axis has an order, such as time.

python
plt.figure(figsize=(10, 5))

sns.lineplot(
    data=monthly,
    x="month",
    y="active_learners",
    hue="track",
    marker="o",
)

plt.title("Active Learners By Track")
plt.xlabel("Month")
plt.ylabel("Active Learners")
plt.xticks(rotation=30)
plt.tight_layout()
plt.show()

Use a line plot when the order matters. Do not use a line plot for unordered categories, because the connecting line implies movement from one value to the next.

8. Faceted Line Plot

relplot can also create faceted line charts.

python
g = sns.relplot(
    data=monthly,
    x="month",
    y="avg_completion_pct",
    kind="line",
    hue="track",
    col="track",
    col_wrap=2,
    marker="o",
    height=3.5,
)

g.set_axis_labels("Month", "Average Completion (%)")
g.set_titles("{col_name}")

for ax in g.axes.flat:
    ax.tick_params(axis="x", rotation=30)

g.fig.suptitle("Completion Trend By Track", y=1.04)
plt.show()

Facets help when four lines in one chart would compete for attention.

9. Histogram

A histogram shows the distribution of one numeric column.

python
sns.histplot(
    data=sessions,
    x="quiz_score",
    bins=10,
)

plt.title("Distribution Of Quiz Scores")
plt.xlabel("Quiz Score")
plt.ylabel("Number Of Sessions")
plt.show()

Histograms answer questions like:

  • Are most scores low, medium, or high?
  • Is there one main peak or multiple peaks?
  • Are there unusually low or unusually high values?

10. Histogram With Groups

Add hue to compare distributions.

python
plt.figure(figsize=(9, 5))

sns.histplot(
    data=sessions,
    x="quiz_score",
    hue="certificate",
    bins=10,
    multiple="stack",
)

plt.title("Quiz Score Distribution By Certificate Status")
plt.xlabel("Quiz Score")
plt.ylabel("Number Of Sessions")
plt.show()

multiple="stack" stacks the groups inside each bin. You can also try multiple="layer" or multiple="dodge" depending on the story you want to tell.

11. Figure-Level Distribution Plot

displot is the figure-level distribution function.

python
g = sns.displot(
    data=sessions,
    x="study_minutes",
    hue="learner_level",
    col="certificate",
    bins=8,
    height=4,
    aspect=1.1,
)

g.set_axis_labels("Study Minutes", "Session Count")
g.fig.suptitle("Study Minutes By Learner Level And Certificate Status", y=1.05)
plt.show()

Use displot when faceting is more important than low-level Matplotlib control.

12. KDE Plot

A KDE plot estimates a smooth density curve.

python
sns.kdeplot(
    data=sessions,
    x="completion_pct",
    hue="learner_level",
    fill=True,
    common_norm=False,
    alpha=0.35,
)

plt.title("Completion Percentage Density By Learner Level")
plt.xlabel("Completion (%)")
plt.show()

KDE plots are smooth, but they are estimates. For small datasets, always compare with a histogram before making strong claims.

13. Rug Plot

A rug plot draws small marks for individual observations.

python
sns.kdeplot(data=sessions, x="study_minutes", fill=True, alpha=0.25)
sns.rugplot(data=sessions, x="study_minutes", height=0.08)

plt.title("Study Minutes Density With Individual Session Marks")
plt.xlabel("Study Minutes")
plt.show()

The KDE curve shows the overall shape. The rug marks show where the actual values are located.

14. Count Plot

A count plot is useful for categorical frequency.

python
sns.countplot(
    data=sessions,
    x="track",
    hue="certificate",
)

plt.title("Session Count By Track And Certificate Status")
plt.xlabel("Track")
plt.ylabel("Number Of Sessions")
plt.xticks(rotation=25)
plt.tight_layout()
plt.show()

Use countplot when you want to count rows. Use barplot when you want to summarize a numeric value.

15. Bar Plot

A bar plot summarizes a numeric column for each category.

python
plt.figure(figsize=(9, 5))

sns.barplot(
    data=sessions,
    x="track",
    y="quiz_score",
    hue="learner_level",
    errorbar=None,
)

plt.title("Average Quiz Score By Track And Level")
plt.xlabel("Track")
plt.ylabel("Average Quiz Score")
plt.xticks(rotation=25)
plt.tight_layout()
plt.show()

By default, Seaborn estimates the mean for each group. Here, errorbar=None hides uncertainty bars to keep the teaching example simple.

In serious analysis, keep error bars when you want to show uncertainty or variation.

16. Box Plot

A box plot compares distributions across categories.

python
sns.boxplot(
    data=sessions,
    x="learner_level",
    y="completion_pct",
    hue="certificate",
)

plt.title("Completion Percentage By Learner Level")
plt.xlabel("Learner Level")
plt.ylabel("Completion (%)")
plt.show()

Box plots show median, spread, and possible outliers.

Use them when you need more than a single average.

17. Violin Plot

A violin plot combines category comparison with density shape.

python
plt.figure(figsize=(9, 5))

sns.violinplot(
    data=sessions,
    x="track",
    y="study_minutes",
    hue="certificate",
    split=True,
    inner="quart",
)

plt.title("Study Minutes Distribution By Track")
plt.xlabel("Track")
plt.ylabel("Study Minutes")
plt.xticks(rotation=25)
plt.tight_layout()
plt.show()

Violin plots are helpful when the shape of each distribution matters. They can be harder to read than box plots for beginners, so use them when the audience needs the extra detail.

18. Strip Plot And Swarm Plot

Strip and swarm plots show individual points for categories.

python
plt.figure(figsize=(9, 5))

sns.stripplot(
    data=sessions,
    x="track",
    y="satisfaction",
    hue="learner_level",
    jitter=True,
    alpha=0.75,
)

plt.title("Individual Satisfaction Ratings")
plt.xlabel("Track")
plt.ylabel("Satisfaction")
plt.xticks(rotation=25)
plt.tight_layout()
plt.show()

For small datasets, individual points can be more honest than summary bars.

Try a swarm plot too:

python
plt.figure(figsize=(9, 5))

sns.swarmplot(
    data=sessions,
    x="learner_level",
    y="quiz_score",
    hue="certificate",
)

plt.title("Quiz Scores By Level With Individual Points")
plt.xlabel("Learner Level")
plt.ylabel("Quiz Score")
plt.show()

Swarm plots avoid overlap, but they can become slow or crowded for large datasets.

19. Catplot For Faceted Category Charts

catplot is the figure-level interface for categorical plots.

python
g = sns.catplot(
    data=sessions,
    x="learner_level",
    y="quiz_score",
    hue="certificate",
    col="track",
    col_wrap=2,
    kind="box",
    height=3.5,
)

g.set_axis_labels("Learner Level", "Quiz Score")
g.set_titles("{col_name}")
g.fig.suptitle("Quiz Score Spread By Track And Level", y=1.04)
plt.show()

Use catplot when you want category charts split into panels.

20. Regression Plot

A regression plot adds a trend line.

python
sns.regplot(
    data=sessions,
    x="practice_questions",
    y="quiz_score",
    scatter_kws={"alpha": 0.75},
    line_kws={"color": "red"},
)

plt.title("Practice Questions vs Quiz Score")
plt.xlabel("Practice Questions Attempted")
plt.ylabel("Quiz Score")
plt.show()

The line is a model summary, not a guarantee. Always inspect the points too.

21. Lmplot With Groups

lmplot is the figure-level regression function.

python
g = sns.lmplot(
    data=sessions,
    x="study_minutes",
    y="completion_pct",
    hue="certificate",
    col="learner_level",
    height=4,
    aspect=1,
    scatter_kws={"alpha": 0.75},
)

g.set_axis_labels("Study Minutes", "Completion (%)")
g.fig.suptitle("Study Time And Completion By Level", y=1.05)
plt.show()

This is useful when the relationship may differ by group.

22. Residual Plot

A residual plot helps you inspect whether a simple linear trend is reasonable.

python
sns.residplot(
    data=sessions,
    x="study_minutes",
    y="quiz_score",
    lowess=True,
)

plt.title("Residual Pattern For Study Minutes And Quiz Score")
plt.xlabel("Study Minutes")
plt.ylabel("Residual")
plt.show()

If residuals show a clear curve or pattern, a straight-line model may be too simple.

23. Heatmap From A Pivot Table

Heatmaps are useful for matrix-shaped data.

Create a track-by-month table of average completion:

python
completion_matrix = monthly.pivot_table(
    index="track",
    columns="month_num",
    values="avg_completion_pct",
)

plt.figure(figsize=(9, 4))

sns.heatmap(
    completion_matrix,
    annot=True,
    fmt=".0f",
    cmap="YlGnBu",
    linewidths=0.5,
)

plt.title("Average Completion Percentage By Track And Month")
plt.xlabel("Month Number")
plt.ylabel("Track")
plt.show()

Use annot=True when the exact values matter. Use a color map that matches the meaning of the metric.

24. Correlation Heatmap

A correlation matrix shows how numeric columns move together.

python
numeric_cols = [
    "study_minutes",
    "practice_questions",
    "quiz_score",
    "completion_pct",
    "satisfaction",
    "mentor_help",
]

corr = sessions[numeric_cols].corr()

plt.figure(figsize=(8, 6))

sns.heatmap(
    corr,
    annot=True,
    fmt=".2f",
    cmap="coolwarm",
    center=0,
    linewidths=0.5,
)

plt.title("Correlation Between Learning Session Metrics")
plt.show()

Correlation ranges from -1 to 1.

  • Positive values mean two columns tend to rise together.
  • Negative values mean one tends to fall as the other rises.
  • Values near zero mean there is little linear relationship.

Correlation does not prove causation.

25. Clustermap

A clustermap reorders rows and columns by similarity.

python
sns.clustermap(
    corr,
    cmap="coolwarm",
    center=0,
    annot=True,
    fmt=".2f",
    linewidths=0.5,
    figsize=(8, 8),
)

plt.show()

Clustermaps are useful when you have many metrics and want to see which variables behave similarly.

26. Pair Plot

A pair plot quickly compares several numeric columns.

python
pair_cols = [
    "track",
    "study_minutes",
    "practice_questions",
    "quiz_score",
    "completion_pct",
]

sns.pairplot(
    data=sessions[pair_cols],
    hue="track",
    corner=True,
    plot_kws={"alpha": 0.75},
)

plt.show()

Pair plots are useful for exploration, but they become heavy when you include too many columns.

Use them early, then build focused charts for communication.

27. Theme, Context, And Palette

Seaborn has built-in styling tools.

python
sns.set_theme(style="ticks", context="talk", palette="Set2")

plt.figure(figsize=(9, 5))

sns.barplot(
    data=sessions,
    x="track",
    y="completion_pct",
    hue="certificate",
    errorbar=None,
)

plt.title("Completion Percentage By Track")
plt.xlabel("Track")
plt.ylabel("Average Completion (%)")
plt.xticks(rotation=25)
sns.despine()
plt.tight_layout()
plt.show()

Common style options:

  • whitegrid
  • darkgrid
  • white
  • dark
  • ticks

Common context options:

  • paper
  • notebook
  • talk
  • poster

After experimenting, reset to a simple default:

python
sns.set_theme(style="whitegrid", context="notebook")

28. Palette Choices

Choose palettes based on meaning.

python
palette = {
    "Beginner": "#60a5fa",
    "Intermediate": "#34d399",
    "Advanced": "#f97316",
}

sns.boxplot(
    data=sessions,
    x="learner_level",
    y="quiz_score",
    palette=palette,
)

plt.title("Quiz Score By Learner Level")
plt.xlabel("Learner Level")
plt.ylabel("Quiz Score")
plt.show()

Good palette habits:

  • Use distinct colors for categories.
  • Use sequential palettes for low-to-high numeric values.
  • Use diverging palettes when values have a meaningful center, such as zero.
  • Avoid using too many colors in one chart.

29. Combine Seaborn With Matplotlib Control

Seaborn returns Matplotlib axes, so you can still customize details.

python
fig, ax = plt.subplots(figsize=(10, 5))

sns.lineplot(
    data=monthly,
    x="month",
    y="projects_submitted",
    hue="track",
    marker="o",
    ax=ax,
)

ax.set_title("Projects Submitted By Month")
ax.set_xlabel("Month")
ax.set_ylabel("Projects Submitted")
ax.tick_params(axis="x", rotation=30)
ax.grid(True, alpha=0.25)
ax.legend(title="Track", bbox_to_anchor=(1.02, 1), loc="upper left")

plt.tight_layout()
plt.show()

This is the common professional pattern:

  1. Use Seaborn to draw the statistical chart.
  2. Use Matplotlib to polish labels, legend, axes, and layout.

30. Save A Seaborn Figure

Use savefig after creating the chart.

python
fig, ax = plt.subplots(figsize=(9, 5))

sns.scatterplot(
    data=sessions,
    x="study_minutes",
    y="quiz_score",
    hue="track",
    ax=ax,
)

ax.set_title("Study Time vs Quiz Score")
ax.set_xlabel("Study Minutes")
ax.set_ylabel("Quiz Score")

fig.tight_layout()
fig.savefig("seaborn_study_vs_score.png", dpi=150, bbox_inches="tight")
plt.close(fig)

plt.close(fig) is useful in scripts that generate many charts.

31. Chart Selection Cheat Sheet

QuestionGood Seaborn Function
Do two numeric columns move together?scatterplot, relplot
How does a metric change over time?lineplot, relplot(kind="line")
What is the shape of one numeric column?histplot, displot, kdeplot
How many rows exist in each category?countplot
What is the average value by category?barplot
How does a distribution differ by category?boxplot, violinplot, stripplot, swarmplot
Is there a linear trend?regplot, lmplot
How do matrix values compare?heatmap
Which variables are similar?clustermap, correlation heatmap
How do several numeric columns relate?pairplot

32. Common Mistakes

Passing columns without data

Prefer this:

python
sns.scatterplot(data=sessions, x="study_minutes", y="quiz_score")

Explanation

  • This code generates a scatter plot using seaborn to display the correlation between two variables: study minutes and quiz scores
  • The x-axis represents study minutes while the y-axis shows quiz scores, allowing visualization of how study time relates to academic performance
  • Each point on the plot corresponds to an individual session record from the sessions dataset
  • The scatter plot helps identify patterns such as positive correlation, negative correlation, or no clear relationship between studying time and test results
  • This visualization technique is commonly used in exploratory data analysis to understand variable relationships before applying statistical models

This makes the chart easier to read and less error-prone.

Using too many colors

If hue has many unique values, the chart may become unreadable. Group rare categories or create smaller facets.

Treating categorical x-axis as time

Use line plots for ordered values. Use bar, box, or strip plots for unordered categories.

Forgetting figure size

If labels overlap, set the figure size:

python
plt.figure(figsize=(10, 5))

Explanation

  • Initializes a new figure object using matplotlib's pyplot interface
  • Sets the figure size to 10 inches width and 5 inches height for optimal display
  • Creates a canvas where subsequent plotting commands will be rendered
  • Allows for proper scaling and layout of visual elements within the specified dimensions
  • Commonly used as the first step in creating organized data visualizations with matplotlib

For figure-level functions, use height and aspect.

Reading too much into a trend line

Regression lines summarize patterns. They do not prove cause and effect.

33. Practice Tasks

Try these tasks with the included CSV files:

  1. Create a scatter plot of completion_pct vs quiz_score, colored by learner_level.
  2. Build a faceted scatter plot with one panel per track.
  3. Draw a histogram of study_minutes with separate colors for certificate.
  4. Create a KDE plot of quiz_score by learner_level.
  5. Build a count plot of device usage by track.
  6. Create a box plot of satisfaction by track.
  7. Create a violin plot of study_minutes by learner_level.
  8. Draw a line chart of avg_quiz_score over time for each track.
  9. Create a heatmap of projects_submitted by track and month_num.
  10. Build a pair plot using study_minutes, practice_questions, quiz_score, and completion_pct.

34. Interview-Style Questions

Why use Seaborn instead of only Matplotlib?

Seaborn provides higher-level statistical plots, better default styling, and easier grouping from DataFrame columns. Matplotlib is still useful for final customization.

What is the difference between axes-level and figure-level functions?

Axes-level functions draw on one axes object. Figure-level functions create a full figure and are better for facets.

What does hue do?

hue maps a column to color, usually to compare groups.

What is the difference between histplot and kdeplot?

histplot counts observations inside bins. kdeplot estimates a smooth density curve.

When should you use boxplot instead of barplot?

Use boxplot when you need to compare the spread, median, and possible outliers. Use barplot when a single summary value is enough.

What is a heatmap good for?

A heatmap is useful for matrix-shaped data such as pivot tables and correlation matrices.

Why can pair plots become slow?

Pair plots create many charts at once. The number of panels grows quickly as you add more numeric columns.

Does a regression line prove causation?

No. It only summarizes a relationship in the observed data.

35. Final Checklist

Before moving on, make sure you can:

  • load CSV files with Pandas
  • choose a chart based on the question
  • use data, x, and y consistently
  • add hue, style, and size when they clarify the chart
  • create facets with relplot, displot, catplot, and lmplot
  • compare distributions with histograms, KDE plots, box plots, and violin plots
  • build heatmaps from pivot tables and correlations
  • style charts with themes, contexts, and palettes
  • combine Seaborn with Matplotlib labels and layout tools
  • save a figure as a PNG file

Seaborn becomes easier when you stop memorizing chart names and start from the analysis question:

  • What relationship am I checking?
  • What distribution am I inspecting?
  • Which groups should I compare?
  • Does the chart need facets?
  • Is this for exploration or communication?

Pick the simplest chart that answers the question clearly.


Next in this series: Mastering Seaborn: Categorical and Regression Plots Explained →

Frequently Asked Questions

Why is Seaborn useful even if you know Matplotlib?
Seaborn provides a faster way to create statistical charts from Pandas DataFrames and offers better default themes, easier grouping with hue, and convenient figure-level functions for facets.
What types of plots can you create with Seaborn?
You can create scatter plots, line plots, histograms, KDE plots, rug plots, count plots, bar plots, box plots, violin plots, strip plots, swarm plots, regression plots, heatmaps, and pair plots.
What datasets are used in this Seaborn guide?
The guide uses original synthetic datasets about online learning sessions, specifically 'seabornlearningsessions.csv' and 'seabornmonthlyoutcomes.csv'.
How should you set up your environment to use Seaborn?
Install the necessary libraries using pip and set up your environment with 'import pandas as pd', 'import matplotlib.pyplot as plt', and 'import seaborn as sns'. Set a clean theme using 'sns.set_theme(style="whitegrid", context="notebook")'.
What are some useful columns in the 'sessions' dataset?
Useful columns in the 'sessions' dataset include 'track', 'learnerlevel', 'device', 'studyminutes', 'practicequestions', 'quizscore', 'completionpct', 'satisfaction', 'mentorhelp', and 'certificate'.

Related Work

See how this thinking shows up in shipped systems.