Lesson 2 · Full-Length Courses
Data Visualization for Beginners, with Seaborn
Seaborn is a Python charting library built on top of matplotlib, specialized for statistical charts like bar plots, box plots, violin plots, and correlation…
- CourseFull-Length Courses
- Lesson2 of 7
- Video45 min
- FormatJupyter notebook · 38 code cells
- Data1 dataset
What you'll learn
Datasets used in this lesson
Save these next to the notebook. In Google Colab, upload them with the 📁 icon on the left first.
- tips.csv7.9 KB
📓 Full notebook
Download .ipynbData Visualization for Beginners, with Seaborn#
- Seaborn is a Python charting library built on top of matplotlib, specialized for statistical charts like bar plots, box plots, violin plots, and correlation heatmaps.
- This lesson runs entirely inside a Jupyter Notebook in VS Code, one cell at a time.
- No prior seaborn experience is required, only basic Python, pandas, and ideally the matplotlib basics from the previous lesson.
- We will reuse the same real-world restaurant tips dataset from the matplotlib lesson, so you can compare how each library approaches the same questions.
Before You Start#
- Open a new Jupyter Notebook in VS Code and select your Python interpreter as the kernel.
- If seaborn, pandas, or matplotlib are not installed yet, open a terminal in VS Code and run: pip install seaborn pandas matplotlib
- Place tips.csv in the same folder as your notebook so pandas can find it with just its file name.
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
print('Seaborn version:', sns.__version__)
Why Seaborn, If We Already Have Matplotlib?#
- Matplotlib gives you full control, but statistical charts like box plots or correlation heatmaps take many lines of code to build from scratch.
- Seaborn adds ready-made chart types that understand pandas DataFrames directly, plus attractive default styling, in far fewer lines.
- Under the hood, seaborn is still drawing on matplotlib figures, so everything you learned about plt.xlabel, plt.title, and plt.show still applies.
tips = pd.read_csv('tips.csv')
tips.head()
Bar Plots: Averages by Category#
- seaborn's barplot draws one bar per category, showing a summary statistic, the mean by default, along with a small error bar.
sns.barplot(data=tips, x='sex', y='total_bill', hue='sex', palette='Set1', legend=False)
plt.xlabel('Sex')
plt.ylabel('Mean Total Bill ($)')
plt.title('Average Total Bill by Sex')
plt.show()
tips.groupby('sex', observed=True)['total_bill'].mean()
sns.barplot(data=tips, x='sex', y='total_bill', hue='sex', estimator='median', palette='hls', legend=False)
plt.xlabel('Sex')
plt.ylabel('Median Total Bill ($)')
plt.title('Median Total Bill by Sex')
plt.show()
Countplot: How Many Rows per Category#
- countplot is barplot's simpler cousin: instead of averaging a number, it just counts how many rows fall into each category.
sns.countplot(data=tips, x='day')
plt.xlabel('Day')
plt.ylabel('Number of Bills')
plt.title('Number of Bills by Day')
plt.show()
A Quick Look at Color Palettes#
- Seaborn ships with several built-in color palettes you can preview before using them in a real chart.
sns.color_palette('colorblind')
sns.countplot(data=tips, x='day', hue='day', palette='colorblind', legend=False)
plt.xlabel('Day')
plt.ylabel('Number of Bills')
plt.title('Number of Bills by Day (Colorblind Palette)')
plt.show()
Distribution Plots: histplot and jointplot#
- histplot is seaborn's own histogram, and can overlay a smooth density curve on top with a single argument.
- jointplot goes a step further, combining a scatter plot with a histogram for each axis, all in one figure.
sns.histplot(data=tips, x='total_bill', kde=True)
plt.xlabel('Total Bill ($)')
plt.ylabel('Count')
plt.title('Distribution of Total Bill, With Density Curve')
plt.show()
sns.jointplot(data=tips, x='total_bill', y='tip')
plt.show()
Box Plots: Distribution Summaries by Category#
- A box plot summarizes a number's spread using five landmarks: minimum, 25th percentile, median, 75th percentile, and maximum, plus outlier points.
sns.boxplot(data=tips, x='day', y='total_bill', hue='day', palette='hls', legend=False)
plt.xlabel('Day')
plt.ylabel('Total Bill ($)')
plt.title('Total Bill Distribution by Day')
plt.show()
sns.boxplot(data=tips, x='day', y='total_bill', hue='smoker', palette='hls')
plt.xlabel('Day')
plt.ylabel('Total Bill ($)')
plt.title('Total Bill Distribution by Day and Smoker Status')
plt.show()
Violin Plots: Box Plots With Shape#
- A violin plot shows the same summary information as a box plot, but also draws the full smoothed shape of the distribution, so you can see if it is lumpy or has more than one peak.
sns.violinplot(data=tips, x='day', y='total_bill', hue='day', palette='Set2', legend=False)
plt.xlabel('Day')
plt.ylabel('Total Bill ($)')
plt.title('Total Bill Distribution by Day (Violin Plot)')
plt.show()
sns.violinplot(data=tips, x='day', y='total_bill', hue='sex', split=True, palette='muted')
plt.xlabel('Day')
plt.ylabel('Total Bill ($)')
plt.title('Total Bill Distribution by Day and Sex (Split Violin)')
plt.show()
Strip Plots: Every Individual Point#
- A strip plot plots one dot per row along a category, so instead of a summary shape, you see every single observation.
sns.stripplot(data=tips, x='day', y='total_bill', hue='day', palette='husl', legend=False)
plt.xlabel('Day')
plt.ylabel('Total Bill ($)')
plt.title('Individual Bills by Day')
plt.show()
sns.stripplot(data=tips, x='day', y='total_bill', hue='sex', dodge=True, palette='Set2')
plt.xlabel('Day')
plt.ylabel('Total Bill ($)')
plt.title('Individual Bills by Day and Sex')
plt.show()
Swarm Plots: Points That Never Overlap#
- swarmplot works like stripplot, but instead of random jitter, it nudges points apart using an algorithm that guarantees no two points ever overlap.
sns.swarmplot(data=tips, x='day', y='total_bill', hue='day', palette='Set2', legend=False)
plt.xlabel('Day')
plt.ylabel('Total Bill ($)')
plt.title('Individual Bills by Day (Swarm Plot)')
plt.show()
Combining Plots: Violin Plus Strip#
sns.violinplot(data=tips, x='day', y='tip', hue='day', palette='rainbow', legend=False, inner=None)
sns.stripplot(data=tips, x='day', y='tip', color='black', size=3, alpha=0.5)
plt.xlabel('Day')
plt.ylabel('Tip ($)')
plt.title('Tip Distribution and Individual Bills by Day')
plt.show()
catplot: One Function, Many Chart Types#
- catplot is a flexible wrapper: change its kind argument, and it draws a completely different chart type using the exact same data and column arguments.
sns.catplot(data=tips, x='sex', y='total_bill', kind='bar', height=4)
plt.show()
sns.catplot(data=tips, x='day', y='total_bill', hue='sex', kind='violin', height=5, aspect=1.2)
plt.show()
Small Multiples: Faceting With col#
sns.catplot(data=tips, x='sex', y='total_bill', col='time', kind='bar', height=4)
plt.show()
relplot and lineplot: Relationships Between Numbers#
- relplot is scatter and line plots' equivalent of catplot: one flexible, figure-level function covering both.
- lineplot is especially powerful because it automatically summarizes repeated x-values, drawing both an average line and a shaded confidence band.
sns.relplot(data=tips, x='total_bill', y='tip', hue='time', height=4)
plt.show()
sns.lineplot(data=tips, x='size', y='tip')
plt.xlabel('Party Size')
plt.ylabel('Tip ($)')
plt.title('Average Tip by Party Size, With Confidence Band')
plt.show()
Pairplot: Every Numeric Column Against Every Other#
- pairplot automatically builds a grid comparing every numeric column in your data against every other numeric column, all in one call.
sns.pairplot(tips[['total_bill', 'tip', 'size']])
plt.show()
sns.pairplot(tips[['total_bill', 'tip', 'size', 'sex']], hue='sex', palette='Set2')
plt.show()
Regression Plots: Adding a Trend Line#
- regplot draws a scatter plot plus a best-fit straight line through the points, summarizing the overall trend in a single line of code.
sns.regplot(data=tips, x='total_bill', y='tip')
plt.xlabel('Total Bill ($)')
plt.ylabel('Tip ($)')
plt.title('Total Bill vs. Tip, With Trend Line')
plt.show()
sns.lmplot(data=tips, x='total_bill', y='tip', hue='sex', height=4, aspect=1.2)
plt.show()
Correlation Heatmaps#
- A correlation coefficient measures how strongly two numbers move together, from -1, a perfect opposite relationship, through 0, no relationship, to 1, a perfect matching relationship.
- A heatmap turns a whole table of correlations into a single, easy-to-scan, color-coded grid.
tips.corr(numeric_only=True)
sns.heatmap(tips.corr(numeric_only=True), annot=True, cmap='BuGn')
plt.title('Correlation Between Numeric Columns')
plt.show()
Pivot Tables and Heatmaps Together#
tips.pivot_table(values='tip', index='day', columns='time', observed=True).round(2)
pivot_tips = tips.pivot_table(values='tip', index='day', columns='time', observed=True)
sns.heatmap(pivot_tips, annot=True, cmap='coolwarm', linewidths=1, linecolor='white')
plt.title('Average Tip by Day and Time')
plt.show()
A Finishing Touch: despine#
- Many charts look cleaner with the top and right border lines removed, since they rarely carry any information.
sns.boxplot(data=tips, x='day', y='total_bill', hue='day', palette='Set2', legend=False)
plt.xlabel('Day')
plt.ylabel('Total Bill ($)')
plt.title('Total Bill by Day (Despined)')
sns.despine()
plt.show()
A Real Gotcha: Seaborn's API Changes Over Time#
- Older seaborn tutorials online often use a function called factorplot. It was renamed years ago, and calling it today raises an error.
- The next cell deliberately triggers this exact error on purpose, so you instantly recognize it if you ever run into an old tutorial or old code.
sns.factorplot(data=tips, x='sex', y='total_bill', kind='bar')
The Fix: Use catplot Instead#
- Whenever you see factorplot in an old tutorial, mentally replace it with catplot, and the rest of the code usually still works unchanged.
Catching Errors Gracefully#
- Sometimes you want to detect a problem and handle it in your code, rather than letting the whole notebook stop.
- Python's try and except lets you catch a specific error type and respond to it instead of crashing.
try:
sns.barplot(data=tips, x='not_a_real_column', y='total_bill')
except ValueError as e:
print('ValueError:', e)
Best Practice: A Reusable Category Explorer#
- If you find yourself building the same box-plot-by-category chart for many different columns, wrap the pattern in a function.
def explore_by_category(df, category_col, value_col):
sns.boxplot(data=df, x=category_col, y=value_col, hue=category_col, legend=False)
plt.xlabel(category_col.title())
plt.ylabel(value_col.replace('_', ' ').title())
plt.title(f'{value_col.title()} by {category_col.title()}')
plt.show()
explore_by_category(tips, 'time', 'tip')
End-to-End Mini Project: When Do People Tip the Most?#
- Let's combine grouping, a pivot table, and a heatmap to answer a real question: does the average tip percentage change by day and by meal time?
tips['tip_pct'] = tips['tip'] / tips['total_bill'] * 100
tips[['total_bill', 'tip', 'tip_pct']].head()
tip_pct_pivot = tips.pivot_table(values='tip_pct', index='day', columns='time', observed=True).round(1)
tip_pct_pivot
sns.heatmap(tip_pct_pivot, annot=True, fmt='.1f', cmap='YlGnBu', linewidths=1, linecolor='white')
plt.title('Average Tip Percentage by Day and Time')
plt.xlabel('Time')
plt.ylabel('Day')
plt.show()
Wrap-Up: What You Learned#
- Bar plots and count plots for comparing averages and counts across categories.
- Color palettes, including accessible, colorblind-friendly options.
- Distribution plots, histplot and jointplot, for seeing shape and relationship together.
- Box plots, violin plots, strip plots, and swarm plots for comparing distributions and individual points, including splitting them by a second category.
- catplot for one flexible function covering many chart kinds at once, including faceting a grid of small multiples with col.
- relplot and lineplot for relationships between numbers, including automatic confidence bands.
- pairplot for a fast overview of every numeric column against every other.
- Regression plots, regplot and lmplot, for adding trend lines and faceting by category.
- Correlation heatmaps and pivot-table heatmaps for spotting patterns in a full table of numbers at a glance.
- Small finishing touches, like despine, that make any chart look more polished.
- Practice prompt: pick a dataset of your own and try rebuilding this lesson's end-to-end mini project a pivot table turned into a heatmap to answer your own question.
- If this lesson helped, consider subscribing for more hands-on data tutorials and drop a comment with which chart type you want to see covered next!
Found this useful?
All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.



