Skip to main content
MahiDev — Learn. Build. Become AI-ready.

Lesson 16

Customising and Saving Seaborn Charts

Finish Seaborn charts with Matplotlib: draw into subplots with ax=, set titles and limits with ax.set, move the legend, and save figure-level grids.

Intermediate25 min
Customising and Saving Seaborn Charts hero Module 26 Lesson 16Customising and Saving Seaborn Charts hero Module 26 Lesson 16

Seaborn draws the chart; Matplotlib finishes it. Axes-level functions hand back an Axes, so every Matplotlib method you know still works. Figure-level functions hand back a grid with its own methods for labels, titles, and saving.

Five steps from drawing a Seaborn chart to finishing and saving itFive steps from drawing a Seaborn chart to finishing and saving it

Everything in one ax.set call

ax.set takes any Axes property as a keyword: title, xlabel, ylabel, xlim, ylim, and more. It replaces a run of separate plt.title, plt.xlabel, and plt.ylim calls.

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

rng = np.random.default_rng(26)
study = pd.DataFrame({
    "track": rng.choice(["Python", "Data", "Web"], 120),
    "mode": rng.choice(["online", "classroom"], 120),
    "week": rng.integers(1, 7, 120),
})
study["hours"] = (rng.uniform(1, 6, 120) + study["week"] * 0.8).round(1)
study["score"] = (35 + study["hours"] * 4.5 + rng.normal(0, 7, 120)).clip(0, 100).round()

ax = sns.boxplot(data=study, x="track", y="score")
ax.set(title="Quiz scores by track", xlabel="", ylabel="score out of 100", ylim=(30, 95))
plt.show()

print(ax.get_title(), ax.get_ylim())

Output:

text
Quiz scores by track (30.0, 95.0)

Seaborn inside subplots

Create the grid with plt.subplots, then pass each Axes as ax=. Seaborn charts, plain Matplotlib charts, and text can share one figure.

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

rng = np.random.default_rng(26)
study = pd.DataFrame({
    "track": rng.choice(["Python", "Data", "Web"], 120),
    "mode": rng.choice(["online", "classroom"], 120),
    "week": rng.integers(1, 7, 120),
})
study["hours"] = (rng.uniform(1, 6, 120) + study["week"] * 0.8).round(1)
study["score"] = (35 + study["hours"] * 4.5 + rng.normal(0, 7, 120)).clip(0, 100).round()

fig, (left, right) = plt.subplots(1, 2, figsize=(11, 4))
sns.histplot(data=study, x="hours", binwidth=1, ax=left)
sns.scatterplot(data=study, x="hours", y="score", hue="track", ax=right)
left.set_title("How long learners study")
right.set_title("And what it is worth")
fig.suptitle("Study hours", fontsize=16)
plt.tight_layout()
plt.show()

print(len(fig.axes), "axes")

Output:

text
2 axes

Move the legend

sns.move_legend rebuilds the legend in a new place and keeps its handles. bbox_to_anchor=(1, 1) with "upper left" sits it just outside the right edge, and title renames it.

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

rng = np.random.default_rng(26)
study = pd.DataFrame({
    "track": rng.choice(["Python", "Data", "Web"], 120),
    "mode": rng.choice(["online", "classroom"], 120),
    "week": rng.integers(1, 7, 120),
})
study["hours"] = (rng.uniform(1, 6, 120) + study["week"] * 0.8).round(1)
study["score"] = (35 + study["hours"] * 4.5 + rng.normal(0, 7, 120)).clip(0, 100).round()

ax = sns.scatterplot(data=study, x="hours", y="score", hue="track")
sns.move_legend(ax, "upper left", bbox_to_anchor=(1, 1), title="Track", frameon=False)
plt.show()

print(ax.get_legend().get_title().get_text())

Output:

text
Track

Finishing a figure-level grid

A FacetGrid has set for every panel, set_axis_labels, set_titles, and figure for the whole Matplotlib figure. Size comes from height and aspect when you create it, not from figsize.

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

rng = np.random.default_rng(26)
study = pd.DataFrame({
    "track": rng.choice(["Python", "Data", "Web"], 120),
    "mode": rng.choice(["online", "classroom"], 120),
    "week": rng.integers(1, 7, 120),
})
study["hours"] = (rng.uniform(1, 6, 120) + study["week"] * 0.8).round(1)
study["score"] = (35 + study["hours"] * 4.5 + rng.normal(0, 7, 120)).clip(0, 100).round()

g = sns.catplot(data=study, x="track", y="score", col="mode", kind="violin",
                height=3.2, aspect=1.1, inner="quart")
g.set_axis_labels("", "score")
g.set_titles("{col_name}")
g.set(ylim=(30, 95))
g.figure.suptitle("Scores by track and mode", y=1.04)
plt.show()

print(g.figure.get_size_inches().round(2))

Output:

text
[7.15 3.2 ]

Save the result

Axes-level charts save with plt.savefig like any Matplotlib figure. Grids have g.savefig, which trims the margins by default so outside legends and titles are not cut off.

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

rng = np.random.default_rng(26)
study = pd.DataFrame({
    "track": rng.choice(["Python", "Data", "Web"], 120),
    "mode": rng.choice(["online", "classroom"], 120),
    "week": rng.integers(1, 7, 120),
})
study["hours"] = (rng.uniform(1, 6, 120) + study["week"] * 0.8).round(1)
study["score"] = (35 + study["hours"] * 4.5 + rng.normal(0, 7, 120)).clip(0, 100).round()

import os

ax = sns.barplot(data=study, x="track", y="score", errorbar=None)
plt.savefig("means.png", dpi=120, bbox_inches="tight")
plt.close()

g = sns.relplot(data=study, x="hours", y="score", col="mode", height=3)
g.savefig("grid.png", dpi=120)
plt.close("all")

print(os.path.exists("means.png"), os.path.exists("grid.png"))

Output:

text
True True

In this page's playground the files go to a temporary folder in your browser's memory and disappear when you reload.

Key takeaways

  • Axes-level functions return an Axes; finish it with ax.set(...)

  • Pass ax= to place Seaborn charts inside plt.subplots

  • sns.move_legend relocates and retitles a legend

  • Grids use set_axis_labels, set_titles, figure.suptitle, and g.savefig

  • Next: What Is Scikit-learn

  • Previous: Themes, Contexts, and Palettes

Loading playground…

Check your understanding

Customising and Saving Seaborn Charts Quiz

What do axes-level Seaborn functions return?

1 / 10