7

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?

Jonny
  • 1,270
  • 5
  • 19
  • 31
  • You can define you own legend keys. Take a look at [this answer](http://stackoverflow.com/a/27841028/2043505). – Schorsch Feb 26 '15 at 14:41
  • Thanks, but that answer explains how to use different shapes as legend keys. I am not sure how to implement alphanumeric letters using that answer. – Jonny Feb 26 '15 at 14:57

2 Answers2

16

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()

enter image description here

Joe Kington
  • 275,208
  • 71
  • 604
  • 463
2

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()
Philipp Schwarz
  • 18,050
  • 5
  • 32
  • 36