50

I currently generate my legend with matplotlib this way:

if t==25:
    l1,l2 = ax2.plot(x320,vTemp320,'or',x320,vAnaTemp320,'-r')
elif t==50:
    l3,l4 = ax2.plot(x320,vTemp320,'ob',x320,vAnaTemp320,'-b')
else:
    l5,l6 = ax2.plot(x320,vTemp320,'og',x320,vAnaTemp320,'-g')
plt.legend((l1,l2,l3,l4,l5,l6), ('t=25 Simulation', 't=25 Analytical','t=50 Simulation', 't=50 Analytical','t=500 Simulation', 't=500 Analytical'),
   bbox_to_anchor=(-.25, 1), loc=2, borderaxespad=0.,prop={'size':12})

Which somehow works see below. But I have duplicated information in my legend.

I would prefer to separate the legend so that I have different colored lines corresponding to each time t, and a normal line as my Analytical solution and dots for the results of my simulation.

Something like that

--(red line)   t = 25
--(blue line)  t = 50
--(green line) t = 500
o              Simulaton
--             Analytical Solution

Does anyone know how I could achieve this with matplotlib?

The current image

2 Answers 2

92

You can chose the artists and labels to display in the legend as follows. You'll need to create custom artists for the elements in the legend that are not actually plotted.

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0,10,31)

fig = plt.figure()
ax = fig.add_subplot(1,1,1)

#Plot analytic solution
ax.plot(x,1*x**2, color='r', label="t = 25")
ax.plot(x,2*x**2, color='b', label="t = 50")
ax.plot(x,3*x**2, color='g', label="t = 500")

#Plot simulation
ax.plot(x,1*x**2, color='r', linestyle='', marker='o')
ax.plot(x,2*x**2, color='b', linestyle='', marker='o')
ax.plot(x,3*x**2, color='g', linestyle='', marker='o')

#Get artists and labels for legend and chose which ones to display
handles, labels = ax.get_legend_handles_labels()
display = (0,1,2)

#Create custom artists
simArtist = plt.Line2D((0,1),(0,0), color='k', marker='o', linestyle='')
anyArtist = plt.Line2D((0,1),(0,0), color='k')

#Create legend from custom artist/label lists
ax.legend([handle for i,handle in enumerate(handles) if i in display]+[simArtist,anyArtist],
          [label for i,label in enumerate(labels) if i in display]+['Simulation', 'Analytic'])

plt.show()

Example plot

Sign up to request clarification or add additional context in comments.

3 Comments

This may be an English language question, but what do you mean by "artist"?
@Mr.Squig. Module artist, class Artist.
This does not work anymore to create multiple dots for a legend entry. One solution is to group multiple Line2D artists via brackets (Line2D((0),(0)...), Line2D((1),(0),... ) and then use handler_map={tuple: HandlerTuple(ndivide=None)} . More info here: matplotlib.org/stable/gallery/text_labels_and_annotations/…
2

You can pass handles and labels to a legend() call to create a custom legend; you can pass any Line2D, PathCollection etc objects and pass them as handles and label them whatever you like. These handles don't even have to refer to the original subplots either, so it can be creates from scratch.

A working example is as follows:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D

x = np.linspace(0,10,31)

fig, ax = plt.subplots()
ax.plot(x, 1*x**2, 'ro-')
ax.plot(x, 2*x**2, 'bo-')
ax.plot(x, 3*x**2, 'go-')

# list of proxy artists
handles = [Line2D([0], [0], c='r'), Line2D([0], [0], c='b'), Line2D([0], [0], c='g'), 
           Line2D([0], [0], c='k'), Line2D([0], [0], c='k', marker='o', linestyle='')]
# its labels
labels = ["t = 25", "t = 50", "t = 500", 'Simulation', 'Analytic']
ax.legend(handles, labels);

result

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.