Lesson 02
Tidy Data for Seaborn
See why Seaborn wants long-form data, one row per observation and one column per variable, and reshape wide tables with pandas melt before you plot.
Seaborn works best with long-form, or tidy, data: each row is one observation and each column is one variable. Spreadsheets are often wide instead, with one column per group. A single melt call turns wide into long, and then every column is something you can hand to x, y, or hue.
Wide and long
This table records practice minutes per week, with a column for each track. It is easy to read, but the track name lives in the column headers, so there is no track column to colour by.
import pandas as pd
wide = pd.DataFrame({
"week": [1, 2, 3],
"Python": [40, 55, 62],
"Data": [35, 48, 58],
"Web": [50, 46, 60],
})
print(wide)
print(list(wide.columns))Output:
week Python Data Web
0 1 40 35 50
1 2 55 48 46
2 3 62 58 60
['week', 'Python', 'Data', 'Web']melt turns columns into rows
melt keeps the id_vars columns as they are and stacks the others. var_name names the new column that holds the old headers, and value_name names the column that holds the numbers. Three rows by three tracks become nine rows.
import pandas as pd
wide = pd.DataFrame({
"week": [1, 2, 3],
"Python": [40, 55, 62],
"Data": [35, 48, 58],
"Web": [50, 46, 60],
})
long = wide.melt(id_vars="week", var_name="track", value_name="minutes")
print(long)
print(long.shape)Output:
week track minutes
0 1 Python 40
1 2 Python 55
2 3 Python 62
3 1 Data 35
4 2 Data 48
5 3 Data 58
6 1 Web 50
7 2 Web 46
8 3 Web 60
(9, 3)Plot the long table
Now each idea has its own column, so the chart is just a matter of naming them: week on x, minutes on y, and track as the colour.
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
wide = pd.DataFrame({
"week": [1, 2, 3],
"Python": [40, 55, 62],
"Data": [35, 48, 58],
"Web": [50, 46, 60],
})
long = wide.melt(id_vars="week", var_name="track", value_name="minutes")
sns.lineplot(data=long, x="week", y="minutes", hue="track", marker="o")
plt.show()
print(long.groupby("track")["minutes"].max())Output:
track
Data 58
Python 62
Web 60
Name: minutes, dtype: int64Wide data works, with less control
Pass a wide table on its own and Seaborn draws one line per numeric column, using the index as x. It is quick, but you cannot choose which column drives colour or style, and the legend has no title.
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
wide = pd.DataFrame({
"week": [1, 2, 3],
"Python": [40, 55, 62],
"Data": [35, 48, 58],
"Web": [50, 46, 60],
}).set_index("week")
ax = sns.lineplot(data=wide)
plt.show()
print([text.get_text() for text in ax.get_legend().get_texts()])
print(repr(ax.get_legend().get_title().get_text()))Output:
['Python', 'Data', 'Web']
''Back to wide with pivot
Some charts, such as heatmaps, want a grid instead. pivot is the opposite of melt: one column becomes the index, one becomes the headers, and one fills the cells.
import pandas as pd
long = pd.DataFrame({
"week": [1, 2, 1, 2],
"track": ["Python", "Python", "Data", "Data"],
"minutes": [40, 55, 35, 48],
})
grid = long.pivot(index="week", columns="track", values="minutes")
print(grid)Output:
track Data Python
week
1 35 40
2 48 55Key takeaways
-
Long-form data has one row per observation and one column per variable
-
melt stacks wide columns into rows; id_vars stay as they are
-
Once data is long, every column can drive x, y, or hue
-
pivot turns long data back into a grid, which heatmaps need
-
Previous: What Is Seaborn
Loading playground…
Check your understanding
Tidy Data for Seaborn Quiz
What is long-form data?
1 / 10