The Ultimate Python
Seaborn Tutorial: Gotta
Catch ‘Em All
MAY 2, 2017
In this step-by-step Seaborn tutorial, you’ll learn how to use one of Python’s
most convenient libraries for data visualization.
For those who’ve tinkered with Matplotlib before, you may have wondered,
“why does it take me 10 lines of code just to make a decent-looking
histogram?”
Introduction to Seaborn
Seaborn provides a high-level interface to Matplotlib, a powerful but
sometimes unwieldy Python visualization library.
On Seaborn’s official website, they state:
If matplotlib “tries to make easy things easy and hard things
possible”, seaborn tries to make a well-defined set of hard
things easy too.
We’ve found this to be a pretty good summary of Seaborn’s strengths. In
practice, the “well-defined set of hard things” includes:
Using default themes that are aesthetically
pleasing.
Setting custom color palettes.
Making attractive statistical plots.
Easily and flexibly displaying distributions.
Visualizing information from matrices and
DataFrames.
Those last three points are why Seaborn is our tool of choice for
Exploratory Analysis. It makes it very easy to “get to know” your data quickly
and efficiently.
However, Seaborn is a complement, not a substitute, for Matplotlib. There are
some tweaks that still require Matplotlib, and we’ll cover how to do that as
well.
How to Learn Seaborn, the Self-Starter Way:
While Seaborn simplifies data visualization in Python, it still has many
features. Therefore, the best way to learn Seaborn is to learn by doing.
1 First, understand the basics and
paradigms of the library.
Each library approaches data visualization differently, so it's
important to understand how Seaborn "thinks about" the problem.
2 Learning in context is the best way to master
a new skill quickly.
3 Finally, refer to galleries to spark ideas
and documentation to customize your
charts.
Since you've already learned the library's paradigms and had some
hands-on practice, you'll easily find what you need.
This process will give you intuition about what you can do with Seaborn,
leaving documentation to serve as further guidance. This is the fastest way to
go from zero to proficient.
A quick tip before we begin:
We tried to make this tutorial as streamlined as possible, which means we
won’t go into too much detail for any one topic. It’s helpful to have
the Seaborn documentation open beside you, in case you want to learn more
about a feature.
Seaborn Tutorial Contents
Instead of just showing you how to make a bunch of plots, we’re going to walk
through the most important paradigms of the Seaborn library. Along the way,
we’ll illustrate each concept with examples.
Here are the steps we’ll cover in this tutorial:
1. Installing Seaborn.
2. Importing libraries and dataset.
3. Seaborn’s plotting functions.
Scatter Plot
4. Customizing with Matplotlib.
5. The role of Pandas.
Box Plot
6. Seaborn themes.
Violin Plot
7. Color palettes.
Swarm Plot
8. Overlaying plots.
9. Putting it all together.
10. Pokédex (mini-gallery).
Heatmap
Histogram
Bar Plot
Factor Plot
Density Plot
Joint Distribution Plot
Step 1: Installing Seaborn.
First, things first: Let’s. Get. Pumped. Up!
(Yes… We totally looped that while writing this tutorial…)
Next, make sure you have the following installed on your computer:
Python 2.7+ or Python 3
Pandas
Matplotlib
Seaborn
Jupyter Notebook (optional, but recommended)
We strongly recommend installing the Anaconda Distribution, which comes
with all of those packages. Simply follow the instructions on that download
page.
Once you have Anaconda installed, simply start Jupyter (either through the
command line or the Navigator app) and open a new notebook:
Step 2: Importing libraries and dataset.
Let's start by importing Pandas, which is a great library for managing relational
(i.e. table-format) datasets:
Pandas
Python
1 # Pandas for managing datasets
2 import pandas as pd
Next, we'll import Matplotlib, which will help us customize our plots further.
Tip: In Jupyter Notebook, you can also
include %matplotlib inline to display your plots
inside your notebook.
Matplotlib
Python
1 # Matplotlib for additional customization
2 from matplotlib import pyplot as plt
3 %matplotlib inline
Then, we'll import the Seaborn library, which is the star of today's show.
Seaborn
Python
1 # Seaborn for plotting and styling
2 import seaborn as sns
Now we're ready to import our dataset.
Tip: we gave each of our imported libraries
an alias. Later, we can invoke Pandas withpd,
Matplotlib with plt, and Seaborn with sns.
Today, we'll be using a cool Pokémon dataset (first generation). Here's the
free download:
[Link]
Dataset for this tutorial.
Once you've downloaded the CSV file, you can import it with Pandas.
Tip: The argument index_col=0 simply means
we'll treat the first column of the dataset as the
ID column.
Import dataset
Python
1 # Read dataset
2 df = pd.read_csv('[Link]', index_col=0)
Here's what the dataset looks like:
Example observations
Python
1 # Display first 5 observations
2 [Link]()
As you can see, we have combat stats data for the original 151 (a.k.a best
151) Pokémon.
Step 3: Seaborn's plotting functions.
One of Seaborn's greatest strengths is its diversity of plotting functions. For
instance, making a scatter plot is just one line of code using
the lmplot() function.
There are two ways you can do so.
The first way (recommended) is to pass your
DataFrame to the data= argument, while
passing column names to the axes
arguments, x= and y=.
The second way is to directly pass in Series of
data to the axes arguments.
For example, let's compare the Attack and Defense stats for our Pokémon:
Default Scatterplot
Python
1 # Recommended way
2 [Link](x='Attack', y='Defense', data=df)
3
4 # Alternative way
5 # [Link](x=[Link], y=[Link])
By the way, Seaborn doesn't have a dedicated scatter plot function, which is
why you see a diagonal line. We actually used Seaborn's function for fitting
and plotting a regression line.
Thankfully, each plotting function has several useful options that you can set.
Here's how we can tweak the lmplot():
First, we'll set fit_reg=False to remove the
regression line, since we only want a scatter
plot.
Then, we'll set hue='Stage' to color our points
by the Pokémon's evolution stage.
This hueargument is very useful because it
allows you to express a third dimension of
information using color.
Scatterplot parameters
Python
1 # Scatterplot arguments
2 [Link](x='Attack', y='Defense', data=df,
3 fit_reg=False, # No regression line
4 hue='Stage') # Color by evolution stage
Looking better, but we can improve this scatter plot further. For example, all of
our Pokémon have positive Attack and Defense values, yet our axes
limits fall below zero. Let's see how we can fix that...
Step 4: Customizing with Matplotlib.
Remember, Seaborn is a high-level interface to Matplotlib. From our
experience, Seaborn will get you most of the way there, but you'll sometimes
need to bring in Matplotlib.
Setting your axes limits is one of those times, but the process is pretty simple:
1. First, invoke your Seaborn plotting function as
normal.
2. Then, invoke Matplotlib's customization
functions. In this case, we'll use
its ylim() andxlim() functions.
Here's our new scatter plot with sensible axes limits:
Customizing with Matplotlib
Python
1 # Plot using Seaborn
2 [Link](x='Attack', y='Defense', data=df,
3 fit_reg=False,
4 hue='Stage')
5
6 # Tweak using Matplotlib
7 [Link](0, None)
8 [Link](0, None)
For more information on Matplotlib's customization functions, check out
its documentation.
Step 5: The role of Pandas.
Even though this is a Seaborn tutorial, Pandas actually plays a very important
role. You see, Seaborn's plotting functions benefit from a base DataFrame
that's reasonably formatted.
For example, let's say we wanted to make a box plot for our Pokémon's
combat stats:
Default boxplot
Python
1 # Boxplot
2 [Link](data=df)
Well, that's a reasonable start, but there are some columns we'd probably like
to remove:
We can remove the Total since we
have individual stats.
We can remove the Stage and Legendary
columns because they aren't combat stats.
In turns out that this isn't easy to do within Seaborn alone. Instead, it's much
simpler to pre-format your DataFrame.
Let's create a new DataFrame called stats_df that only keeps the stats
columns:
Pre-format DataFrame
Python
1 # Pre-format DataFrame
2 stats_df = [Link](['Total', 'Stage', 'Legendary'], axis=1)
3
4 # New boxplot using stats_df
5 [Link](data=stats_df)
It's outside the scope of this tutorial to dive into Pandas, but here's a
handy cheat sheet.
Step 6: Seaborn themes.
Another advantage of Seaborn is that it comes with decent style themes right
out of the box. The default theme is called 'darkgrid'.
Next, we'll change the theme to 'whitegrid' while making a violin plot.
Violin plots are useful alternatives to box plots.
They show the distribution (through the
thickness of the violin) instead of only the
summary statistics.
For example, we can visualize the distribution of Attack by Pokémon's primary
type:
Set theme, then plot violin plot
Python
1 # Set theme
2 sns.set_style('whitegrid')
3
4 # Violin plot
5 [Link](x='Type 1', y='Attack', data=df)
As you can see, Dragon types tend to have higher Attack stats than Ghost
types, but they also have greater variance.
Now, Pokémon fans might find something quite jarring about that plot: The
colors are nonsensical. Why is the Grass type colored pink or the Water
type colored orange? We must fix this!
Step 7: Color palettes.
Fortunately, Seaborn allows us to set custom color palettes. We can simply
create an ordered Python list of color hex values.
Let's use Bulbapedia to help us create a new color palette:
Pokemon color palette
Python
1 pkmn_type_colors = ['#78C850', # Grass
2
3
4
5
'#F08030', # Fire
6
'#6890F0', # Water
7
'#A8B820', # Bug
8
'#A8A878', # Normal
9
'#A040A0', # Poison
1
'#F8D030', # Electric
0
'#E0C068', # Ground
1
'#EE99AC', # Fairy
1
'#C03028', # Fighting
1
'#F85888', # Psychic
2
'#B8A038', # Rock
1
'#705898', # Ghost
3
'#98D8D8', # Ice
1
'#7038F8', # Dragon
4
]
1
5
1
6
Wonderful. Now we can simply use the palette= argument to recolor our
chart.
Custom color palette
Python
1 # Violin plot with Pokemon color palette
2 [Link](x='Type 1', y='Attack', data=df,
3 palette=pkmn_type_colors) # Set color palette
Much better!
Violin plots are great for visualizing distributions. However, since we only have
151 Pokémon in our dataset, we may want to simply display each point.
That's where the swarm plot comes in. This visualization will show each
point, while "stacking" those with similar values:
Swarm plot
Python
1 # Swarm plot with Pokemon color palette
2 [Link](x='Type 1', y='Attack', data=df,
3 palette=pkmn_type_colors)
That's handy, but can't we combine our swarm plot and the violin plot? After
all, they display similar information, right?
Step 8: Overlaying plots.
The answer is yes.
It's pretty straightforward to overlay plots using Seaborn, and it works the
same way as with Matplotlib. Here's what we'll do:
1. First, we'll make our figure larger using
Matplotlib.
2. Then, we'll plot the violin plot. However, we'll
set inner=None to remove the bars inside the
violins.
3. Next, we'll plot the swarm plot. This time, we'll
make the points black so they pop out more.
4. Finally, we'll set a title using Matplotlib.
Overlaying swarm and violin plots
Python
1
2
3
4
5
# Set figure size with matplotlib
6
[Link](figsize=(10,6))
7
8
# Create plot
9
[Link](x='Type 1',
1
y='Attack',
0
data=df,
1
inner=None, # Remove the bars inside the violins
1
palette=pkmn_type_colors)
1
2
[Link](x='Type 1',
1
y='Attack',
3
data=df,
1
color='k', # Make points black
4
alpha=0.7) # and slightly transparent
1
5
# Set title with matplotlib
1
[Link]('Attack by Type')
6
1
7
1
8
Awesome, now we have a pretty chart that tells us how Attack values are
distributed across different Pokémon types. But what it we want to see all of
the other stats as well?
Step 9: Putting it all together.
Well, we could certainly repeat that chart for each stat. But we can also
combine the information into one chart... we just have to do some data
wrangling with Pandas beforehand.
First, here's a reminder of our data format:
First 5 rows of stats_df
Python
1 stats_df.head()
As you can see, all of our stats are in separate columns. Instead, we want to
"melt" them into one column.
To do so, we'll use Pandas's melt() function. It takes 3 arguments:
First, the DataFrame to melt.
Second, ID variables to keep (Pandas will melt
all of the other ones).
Finally, a name for the new, melted variable.
Here's the output:
Melt DataFrame
Python
1 # Melt DataFrame
2 melted_df = [Link](stats_df,
3 id_vars=["Name", "Type 1", "Type 2"], # Variables to keep
4 var_name="Stat") # Name of melted variable
5 melted_df.head()
All 6 of the stat columns have been "melted" into one, and the new Stat
column indicates the original stat (HP, Attack, Defense, Sp. Attack, Sp.
Defense, or Speed). For example, it's hard to see here, but Bulbasaur now
has 6 rows of data.
In fact, if you print the shape of these two DataFrames...
Shape comparison
Python
1 print( stats_df.shape )
2 print( melted_df.shape )
3 # (151, 9)
4 # (906, 5)
...you'll find that melted_df has 6 times the number of rows as stats_df.
Now we can make a swarm plot with melted_df.
But this time, we're going to
set x='Stat' and y='value' so our swarms are
separated by stat.
Then, we'll set hue='Type 1' to color our points
by the Pokémon type.
Swarmplot with melted_df
Python
1 # Swarmplot with melted_df
2 [Link](x='Stat', y='value', data=melted_df,
3 hue='Type 1')
Finally, let's make a few final tweaks for a more readable chart:
1. Enlarge the plot.
2. Separate points by hue using the
argument split=True .
3. Use our custom Pokemon color palette.
4. Adjust the y-axis limits to end at 0.
5. Place the legend to the right.
Customizations
Python
1 # 1. Enlarge the plot
2 [Link](figsize=(10,6))
3
4 [Link](x='Stat',
5 y='value',
6 data=melted_df,
7 hue='Type 1',
8 split=True, # 2. Separate points by hue
9
1
0
1 palette=pkmn_type_colors) # 3. Use Pokemon palette
1
1 # 4. Adjust the y-axis
2 [Link](0, 260)
1
3 # 5. Place legend to the right
1 [Link](bbox_to_anchor=(1, 1), loc=2)
4
1
5
There we go!
Step 10: Pokédex (mini-gallery).
We're going to conclude this tutorial with a few quick-fire data visualizations,
just to give you a sense of what's possible with Seaborn.
10.1 - Heatmap
Heatmaps help you visualize matrix-like data.
Heatmap
Python
1 # Calculate correlations
2 corr = stats_df.corr()
3
4 # Heatmap
5 [Link](corr)
10.2 - Histogram
Histograms allow you to plot the distributions of numeric variables.
Histogram
Python
1 # Distribution Plot (a.k.a. Histogram)
2 [Link]([Link])
10.3 - Bar Plot
Bar plots help you visualize the distributions of categorical variables.
Bar Plot
Python
1 # Count Plot (a.k.a. Bar Plot)
2 [Link](x='Type 1', data=df, palette=pkmn_type_colors)
3
4 # Rotate x-labels
5 [Link](rotation=-45)
10.4 - Factor Plot
Factor plots make it easy to separate plots by categorical classes.
Factor Plot
Python
1 # Factor Plot
2 g = [Link](x='Type 1',
3 y='Attack',
4 data=df,
5 hue='Stage', # Color by stage
6 col='Stage', # Separate by stage
7 kind='swarm') # Swarmplot
8
9 # Rotate x-axis labels
1 g.set_xticklabels(rotation=-45)
0
1 # Doesn't work because only rotates last plot
1
1
2 # [Link](rotation=-45)
1
3
10.5 - Density Plot
Density plots display the distribution between two variables.
Tip: Consider overlaying this with a scatter plot.
Density Plot
Python
1 # Density Plot
2 [Link]([Link], [Link])
10.6 - Joint Distribution Plot
Joint distribution plots combine information from scatter plots and histograms
to give you detailed information for bi-variate distributions.
Joint Distribution Plot
Python
1 # Joint Distribution Plot
2 [Link](x='Attack', y='Defense', data=df)
Congratulations... you've made it to the end of this Python Seaborn tutorial!
We've just concluded a tour of key Seaborn paradigms and showed you many
examples along the way. Feel free to use this page along with the official
Seaborn gallery as references for your projects going forward.