The solution will depend on whether you already have texts in the axes that should appear in the legend as well, or whether those are independent on anything you have in the axes.
A. Existing texts or annotation
If you already have texts or annotations in the axes, you can provide them as handles to the legend. A new TextHandlerA
that is registered to the Legend
class takes those Text
s as input. The respective label is taken from the artist as usual, via the label
argument.
import numpy as np
import matplotlib.pyplot as plt
import string
from matplotlib.legend_handler import HandlerBase
from matplotlib.text import Text, Annotation
from matplotlib.legend import Legend
class TextHandlerA(HandlerBase):
def create_artists(self, legend, artist ,xdescent, ydescent,
width, height, fontsize, trans):
tx = Text(width/2.,height/2, artist.get_text(), fontsize=fontsize,
ha="center", va="center", fontweight="bold")
return [tx]
Legend.update_default_handler_map({Text : TextHandlerA()})
N = 7
x = np.random.rand(N)*.7
y = np.random.rand(N)*.7
colors = np.random.rand(N)
handles = list(string.ascii_uppercase)
labels = [f"Model Name {c}" for c in handles]
fig, ax = plt.subplots()
ax.scatter(x, y, s=100, c=colors, alpha=0.5)
for i, xy in enumerate(zip(x, y)):
ax.annotate(handles[i], xy=xy, label= labels[i])
ax.legend(handles=ax.texts)
plt.show()
B. Legend from list of strings.
If you want legend entries that are not themselves texts in the axes, you can create them from a list of strings. In this case the TextHandlerB
takes the string as input. In that case the legend needs to be called with two lists of strings, one for the handles, and one for the labels.
import numpy as np
import matplotlib.pyplot as plt
import string
from matplotlib.legend_handler import HandlerBase
from matplotlib.text import Text
from matplotlib.legend import Legend
class TextHandlerB(HandlerBase):
def create_artists(self, legend, text ,xdescent, ydescent,
width, height, fontsize, trans):
tx = Text(width/2.,height/2, text, fontsize=fontsize,
ha="center", va="center", fontweight="bold")
return [tx]
Legend.update_default_handler_map({str : TextHandlerB()})
N = 7
x = np.random.rand(N)*.7
y = np.random.rand(N)*.7
colors = np.random.rand(N)
handles = list(string.ascii_uppercase)[:N]
labels = [f"Model Name {c}" for c in handles]
fig, ax = plt.subplots()
ax.scatter(x, y, s=100, c=colors, alpha=0.5)
for i, xy in enumerate(zip(x, y)):
ax.annotate(handles[i], xy=xy)
ax.legend(handles=handles, labels=labels)
plt.show()
In both cases the output is
