Customize Matplotlib Scatter Plot Legend Facecolor in Python

A real-estate client wanted the Matplotlib scatter plot legend facecolor solid so it stood out from the colored points. The answer is ax.legend(facecolor=..., framealpha=1).

Their first try only passed facecolor, and the box still looked washed out. That’s because Matplotlib draws it at 80% opacity.

Quick answer: set color and opacity together:

ax.legend(facecolor="lightyellow", edgecolor="black", framealpha=1)

In this tutorial, I’ll color the legend box, fix the faded look, restyle an existing legend, match a dark theme and set a default.

Set the scatter plot legend facecolor with legend()

My sample is Riverbend Realty’s 2026 Austin listings: 60 homes each in Hyde Park, Mueller and Zilker, run on Python 3.12.5 and Matplotlib 3.11.2. You pass facecolor to legend(), not scatter():

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(7)
areas = {"Hyde Park": (1650, 640), "Mueller": (1900, 590),
         "Zilker": (2200, 910)}           # mean sq ft, mean price $K

fig, ax = plt.subplots(figsize=(8, 5))
for name, (sqft, price) in areas.items():
    x = rng.normal(sqft, 420, 60)
    y = price + (x - sqft) * 0.32 + rng.normal(0, 70, 60)
    ax.scatter(x, y, s=28, alpha=0.8, label=name)
ax.set_xlabel("Living area (sq ft)")
ax.set_ylabel("List price (thousand USD)")

ax.set_title("Riverbend Realty - Austin listings, 2026")
ax.legend(loc="upper left", facecolor="lightyellow",
          edgecolor="black", title="Neighborhood")
plt.tight_layout()
plt.show()
Matplotlib scatter plot of Austin home listings with a light yellow legend facecolor and black edge
The legend box is light yellow with a black edge and a Neighborhood title.

Any color format works. If you still need the legend itself, start with adding a legend to a Matplotlib scatter plot.

Why does my legend facecolor look faded?

Same listings, two panels: default opacity on the left, framealpha=1 on the right:

import matplotlib.pyplot as plt
import numpy as np

# rng and areas from example 1

fig, axes = plt.subplots(1, 2, figsize=(11, 4.5), sharey=True)
for ax, alpha in zip(axes, (None, 1.0)):
    rng = np.random.default_rng(7)
    for name, (sqft, price) in areas.items():
        x = rng.normal(sqft, 420, 60)
        y = price + (x - sqft) * 0.32 + rng.normal(0, 70, 60)
        ax.scatter(x, y, s=28, alpha=0.8, label=name)
    leg = ax.legend(loc="upper left", facecolor="navy",
                    labelcolor="white", framealpha=alpha)
    ax.set_title(f"framealpha={alpha} -> {leg.get_frame().get_alpha()}")
plt.tight_layout()
plt.show()
Two Matplotlib scatter plots side by side, a faded navy legend with default framealpha and a solid navy legend with framealpha 1
The left box is a faded navy; the right one is solid.

The titles show it: None falls back to 0.8, so the white plot tints the navy. Want a see-through box on purpose? See transparent plot backgrounds and legend styling.

Change the legend facecolor after the legend exists

When a helper builds the legend, get_frame() hands you its background patch:

import matplotlib.pyplot as plt
import numpy as np

# rng and areas from example 1

fig, ax = plt.subplots(figsize=(8, 5))
for name, (sqft, price) in areas.items():
    x = rng.normal(sqft, 420, 60)
    y = price + (x - sqft) * 0.32 + rng.normal(0, 70, 60)
    ax.scatter(x, y, s=28, alpha=0.8, label=name)
ax.set_xlabel("Living area (sq ft)")
ax.set_ylabel("List price (thousand USD)")

leg = ax.legend(loc="upper left")
frame = leg.get_frame()
frame.set_facecolor("#e8f4ea")        # mint green
frame.set_edgecolor("#2e7d32")
frame.set_boxstyle("round", pad=0.4)
print(frame.get_facecolor())
plt.tight_layout()
plt.show()

Output:

(0.9098039215686274, 0.9568627450980393, 0.9176470588235294, 0.8)
Matplotlib scatter plot legend restyled with get_frame set_facecolor to mint green with a rounded green border
The frame turns mint green with a dark green border and rounded corners.

The printed RGBA tuple ends in 0.8, so the default opacity still applies. To grow the labels inside the box, see changing the Matplotlib legend font size.

Match the legend to a dark background

On a dark chart, facecolor="inherit" copies the axes color so the legend doesn’t glow white:

import matplotlib.pyplot as plt
import numpy as np
plt.style.use("dark_background")
print("legend.facecolor:", plt.rcParams["legend.facecolor"])

# rng and areas from example 1

fig, ax = plt.subplots(figsize=(8, 5))
for name, (sqft, price) in areas.items():
    x = rng.normal(sqft, 420, 60)
    y = price + (x - sqft) * 0.32 + rng.normal(0, 70, 60)
    ax.scatter(x, y, s=28, alpha=0.8, label=name)
ax.set_xlabel("Living area (sq ft)")
ax.set_ylabel("List price (thousand USD)")

ax.set_facecolor("#1b2631")
ax.legend(loc="upper left", facecolor="inherit",
          edgecolor="gold", framealpha=1)
plt.tight_layout()
plt.show()

Output:

legend.facecolor: inherit
Matplotlib dark background scatter plot with the legend facecolor inherited from the dark axes and a gold border
The legend takes the slate axes color; the gold edge keeps it visible.

inherit reads axes.facecolor, so set the axes color first. If the box still covers points, putting the legend outside the plot is the cleaner fix.

Set a default legend facecolor with rcParams

For a whole report, change the defaults once:

import matplotlib.pyplot as plt
print("default:", plt.rcParams["legend.facecolor"])

plt.rcParams.update({"legend.facecolor": "whitesmoke",
                     "legend.framealpha": 1})
fig, ax = plt.subplots()
ax.scatter([1, 2], [3, 4], label="Mueller")
leg = ax.legend()
print("now:", leg.get_frame().get_facecolor())

Output:

default: inherit
now: (0.9607843137254902, 0.9607843137254902, 0.9607843137254902, 1.0)

The stock value is inherit; new legends now get whitesmoke at full opacity. With several panels, legends in Matplotlib subplots shows where to place each one.

Common errors and how to fix them with legend colors

  • Facecolor does nothing: frameon=False hides the box. Remove it.
  • Markers changed, not the legend: move facecolor from scatter() to legend().
  • Color looks lighter than the hex code: add framealpha=1.
  • Faded legend markers: that’s scatter(alpha=...); see transparent scatter plots.

For more scatter styling, try these:

Frequently asked questions

How do I change the legend background color in Matplotlib?

Pass it to legend(): ax.legend(facecolor="lightyellow").

Why is my legend color lighter than I set?

The default framealpha is 0.8. Add framealpha=1.

Can I change the facecolor after creating the legend?

Yes: ax.get_legend().get_frame().set_facecolor(c).

How do I make the legend match the plot background?

Use facecolor="inherit", which takes the axes facecolor.

How do I set a legend facecolor for all charts?

Set plt.rcParams["legend.facecolor"] once.

Where is the legend facecolor option documented?

See Axes.legend() in the Matplotlib docs.