Seaborn Scatter Plot

Learn how to create a Seaborn scatter plot using sns.scatterplot(). See examples with hue, style, size, palette, marker size, transparency, labels, legends, and regression lines.

Published

Updated

Read time 6 min read

Reviewed byDeepak Prasad

Seaborn Scatter Plot

A Seaborn scatter plot shows how two numeric variables relate: each point is one observation, with position on the x- and y-axes. The main function is sns.scatterplot(). Use it when you want a clean Matplotlib-based scatter chart that works directly with Pandas DataFrames and optional group styling with hue, style, and size.

Install if needed: pip install seaborn pandas matplotlib. Examples below use Seaborn’s built-in tips dataset and save figures with savefig() so scripts run headless.

Tested on: Python 3.13.3; seaborn 0.13.2; kernel 6.14.0-37-generic.


Seaborn scatter plot quick reference

Task Use
Basic scatter plot sns.scatterplot(data=df, x="x_col", y="y_col")
Color points by group hue="group_col"
Change marker style by group style="group_col"
Change point size by variable size="value_col"
Use a color palette palette="deep" or palette="viridis"
Make points transparent alpha=0.5
Change marker size s=80
Add title and labels ax.set_title(), ax.set_xlabel(), ax.set_ylabel()
Move or edit legend ax.legend() or plt.legend()
Add regression line sns.regplot()
Create multiple scatter plots by category sns.relplot(kind="scatter", col="category")

Basic sns.scatterplot() syntax

python
sns.scatterplot(data=df, x="column_name", y="column_name")
Output
  • data — usually a Pandas DataFrame (long-form: one row per observation).
  • x, y — column names as strings, or array-like values if you omit data.
  • Return value — a Matplotlib Axes object (when plotting on an existing figure) that you can customize further.

Seaborn builds on Matplotlib: titles, labels, figure size, and grids use standard Axes or pyplot calls after plotting.


Create a basic Seaborn scatter plot

python
import matplotlib.pyplot as plt
import seaborn as sns

tips = sns.load_dataset("tips")

fig, ax = plt.subplots(figsize=(8, 5))
sns.scatterplot(data=tips, x="total_bill", y="tip", ax=ax)
ax.set_title("Tip vs total bill")
ax.set_xlabel("Total bill ($)")
ax.set_ylabel("Tip ($)")
fig.savefig("scatter_basic.png", bbox_inches="tight")
plt.show()

You should see points for total_bill vs tip—244 rows in the sample dataset. In a script, call plt.show() only when you want an interactive window; use savefig() for files.


Add color groups with hue

hue colors markers by a column—best for comparing the same x–y relationship across groups (category or numeric; Seaborn scales color differently for each).

python
fig, ax = plt.subplots(figsize=(8, 5))
sns.scatterplot(data=tips, x="total_bill", y="tip", hue="day", ax=ax)
ax.set_title("Tip vs bill by day")
fig.savefig("scatter_hue.png", bbox_inches="tight")

Use hue when group comparison matters, not only for decoration. A legend is added automatically.


Change marker style with style

style maps a column to marker shapes—useful when color alone is not enough (print, accessibility, or black-and-white output).

python
fig, ax = plt.subplots(figsize=(8, 5))
sns.scatterplot(
    data=tips,
    x="total_bill",
    y="tip",
    hue="day",
    style="smoker",
    ax=ax,
)
fig.savefig("scatter_style.png", bbox_inches="tight")

The Seaborn relational plot guide notes that repeating the same variable in hue and style can improve accessibility when chosen deliberately—not by accident with unrelated columns.


Change point size with size

size maps a third numeric variable to marker area—bubble-style scatter plots. Control the range with sizes=(min, max):

python
fig, ax = plt.subplots(figsize=(8, 5))
sns.scatterplot(
    data=tips,
    x="total_bill",
    y="tip",
    hue="day",
    size="size",
    sizes=(40, 200),
    ax=ax,
)
fig.savefig("scatter_size.png", bbox_inches="tight")

Do not stack hue, style, and size on unrelated columns unless the chart stays readable. Too many semantic mappings make plots hard to interpret—Seaborn’s own tutorial warns about this.


Customize colors, palette, markers, and transparency

Parameter Purpose
color Single color for all points (no grouping)
hue + palette Group colors ("deep", "viridis", "Set2", etc.)
alpha Transparency (0–1); helps overlapping points
s Fixed marker size when not using size= mapping
edgecolor, linewidth Marker border color and width
python
fig, ax = plt.subplots(figsize=(8, 5))
sns.scatterplot(
    data=tips,
    x="total_bill",
    y="tip",
    hue="time",
    palette="viridis",
    alpha=0.7,
    s=60,
    edgecolor="white",
    linewidth=0.5,
    ax=ax,
)
fig.savefig("scatter_custom.png", bbox_inches="tight")

palette without hue does not create group colors—pair them when you need categories.


Add title, axis labels, grid, and figure size

Set figure size before plotting when you create the figure yourself:

python
fig, ax = plt.subplots(figsize=(10, 6))
sns.scatterplot(data=tips, x="total_bill", y="tip", hue="day", ax=ax)
ax.set_title("Restaurant tips")
ax.set_xlabel("Total bill ($)")
ax.set_ylabel("Tip ($)")
ax.grid(True, alpha=0.3)
fig.savefig("scatter_labels.png", bbox_inches="tight")

Prefer ax.set_* on the Axes returned by scatterplot() so you target the correct subplot.


Control legend in Seaborn scatter plot

Legends appear automatically when you use hue, style, or size. Hide or move them when they cover data:

python
fig, ax = plt.subplots(figsize=(8, 5))
sns.scatterplot(data=tips, x="total_bill", y="tip", hue="day", ax=ax)
ax.legend(title="Day", bbox_to_anchor=(1.02, 1), loc="upper left")
fig.savefig("scatter_legend.png", bbox_inches="tight")

Use legend=False on scatterplot() to suppress the legend. For fine control, grab ax.get_legend() or call ax.legend(...) with bbox_to_anchor to place the legend outside the plot area.


Add regression line to a Seaborn scatter plot

sns.scatterplot() does not fit a trend line. Options:

Option 1 — regplot() (scatter + line in one call):

python
fig, ax = plt.subplots(figsize=(8, 5))
sns.regplot(data=tips, x="total_bill", y="tip", ax=ax)
fig.savefig("regplot_basic.png", bbox_inches="tight")

Option 2 — custom scatter styling + line:

python
fig, ax = plt.subplots(figsize=(8, 5))
sns.scatterplot(data=tips, x="total_bill", y="tip", alpha=0.5, ax=ax)
sns.regplot(data=tips, x="total_bill", y="tip", scatter=False, ax=ax)
fig.savefig("scatter_plus_line.png", bbox_inches="tight")

regplot(scatter=False) draws only the regression line on the same Axes.


Create multiple scatter plots with relplot()

For figure-level faceting, use sns.relplot(kind="scatter") with col= or row=:

python
import seaborn as sns

tips = sns.load_dataset("tips")
g = sns.relplot(
    data=tips,
    kind="scatter",
    x="total_bill",
    y="tip",
    hue="smoker",
    col="time",
    height=4,
    aspect=1.1,
)
g.savefig("relplot_scatter.png", bbox_inches="tight")

relplot() wraps scatterplot() with a FacetGrid and keeps semantic mappings consistent across facets—safer than wiring FacetGrid manually for simple split charts.


Handle overplotting in scatter plots

When many points overlap, the chart looks like a solid blob.

  • Lower alpha (for example 0.30.6).
  • Reduce marker size with s or smaller sizes in a size mapping.
  • Sample very large datasets before plotting.
  • For dense numeric clouds, consider sns.kdeplot(), plt.hexbin(), sns.jointplot(), or histplot instead of a raw scatter.
  • For discrete categories on one axis, stripplot() or swarmplot() may read better than a scatter.

Seaborn scatterplot vs regplot vs relplot vs pairplot

Function Use when
sns.scatterplot() One scatter plot on one Axes
sns.regplot() Scatter with a regression line
sns.relplot(kind="scatter") Same scatter mapping split into rows/columns
sns.pairplot() Scatter matrix for many numeric column pairs

Mistakes to avoid

  • Passing x="col" and y="col" without data=df (or pass Series/arrays directly).
  • Mapping hue, style, and size on three unrelated columns—chart becomes unreadable.
  • Expecting scatterplot() to draw a regression line—use regplot().
  • Putting categorical data on both axes when a bar or strip plot would be clearer.
  • Forgetting plt.show() in local scripts (not needed for savefig()-only workflows).
  • Plotting hundreds of thousands of points with full opacity and large markers.
  • Setting palette without hue and expecting grouped colors.
  • Confusing sns.scatterplot() with plt.scatter()—the Seaborn API is DataFrame-oriented and semantic mappings differ.

Summary

Use sns.scatterplot() for Seaborn scatter plots: x and y for the two main variables, data= for a DataFrame. Add hue, style, and size to show groups or extra numeric information— sparingly. Customize with Matplotlib ax.set_title(), labels, figure size, and legend placement. Use sns.regplot() for trend lines and sns.relplot(kind="scatter") for faceted scatter plots. See the official scatterplot API for every parameter.


Frequently Asked Questions

1. How do you make a scatter plot in Seaborn?

Call sns.scatterplot(data=df, x="col_x", y="col_y") with a Pandas DataFrame and column names; add hue, style, or size to map extra variables.

2. Does sns.scatterplot() add a regression line?

No—use sns.regplot() for a fitted line, or layer regplot(scatter=False) on the same Axes after scatterplot() for custom point styling plus a trend line.

3. What is the difference between sns.scatterplot() and plt.scatter()?

scatterplot() understands DataFrame column names and semantic mappings (hue, style, size); plt.scatter() takes raw x/y arrays and manual styling.

4. When should I use relplot instead of scatterplot?

Use sns.relplot(kind="scatter", col=...) or row=... when you want the same scatter mapping split into faceted subplots with synchronized legends.

5. How do I avoid KeyError with column names?

Pass data=df and use string column names for x, y, hue, and size—or pass Series/array values directly without the data= parameter.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive …