Reputation: 1368
I am using Matplotlib to basically draw a 'picture', not for plotting data.
In the 'picture' I use plt.annotate
to label certain parts of the picture.
I now want to make a completely custom legend to indicate the meaning of the symbols.
Is there a way to define custom handles
and labels
, where the handles
must be alphanumeric letters instead of the normal markers like '*'
or 'o'
.
Is this possible or must I construct the legend manually using plt.annotation
?
Upvotes: 7
Views: 11753
Reputation: 20674
In most cases you probably also want to illustrate elements on the graphic with color in your custom legend. In this case I would simply use matplotlib's own functions, than you also do not need to write your own complex function.
import matplotlib
red_line = matplotlib.lines.Line2D([], [], color='red',markersize=100, label='Blue line')
blue_line = matplotlib.lines.Line2D([], [], color='blue', markersize=100, label='Green line')
purple_line = matplotlib.lines.Line2D([], [], color='purple', markersize=100, label='Green line')
handles = [blue_line,red_line, purple_line]
labels = [h.get_label() for h in handles]
ax.legend(handles=handles, labels=labels)
plt.show()
Upvotes: 2
Reputation: 284582
There are a lot of ways to do it, but it's probably easiest to use a proxy artist in this case. You can use arbitrary text as a marker, so it's fairly easy to have fake Line2D
's show labels instead of lines.
As an example (the bulk of this is the relatively "fancy" call to annotate
):
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
def main():
labels = ['A', 'B', 'C']
positions = [(2, 5), (1, 1), (4, 8)]
descriptions = ['Happy Cow', 'Sad Horse', 'Drooling Dog']
# Plot the data, similar to what you described...
fig, ax = plt.subplots()
ax.imshow(np.random.random((10, 10)), interpolation='none')
for label, xy in zip(labels, positions):
ax.annotate(label, xy, xytext=(20, 20), size=15,
textcoords='offset points',
bbox={'facecolor':'white'},
arrowprops={'arrowstyle':'->'})
# Create a legend with only labels
proxies = [create_proxy(item) for item in labels]
ax.legend(proxies, descriptions, numpoints=1, markerscale=2)
plt.show()
def create_proxy(label):
line = matplotlib.lines.Line2D([0], [0], linestyle='none', mfc='black',
mec='none', marker=r'$\mathregular{{{}}}$'.format(label))
return line
main()
Upvotes: 17