NoIdeaHowToFixThis
NoIdeaHowToFixThis

Reputation: 4564

Plot and Scatter legend on subplot

My code looks like this:

pos = 0
x = [1,2,3]
y = [2,3,4]
y2 = [3,5,3]
fig, axs = plt.subplots(1,2)
for pos in [0,1]:
    h1 = axs[pos].scatter(x,y,c='black',label='scttr')
    h2 = axs[pos].plot(x,y2,c='red',label='line')
    axs[pos].legend([h1, h2])
plt.show()

which produces the right legend without text (it shows the object name in the handle). If I try to produce some text for the labels:

pos = 0
x = [1,2,3]
y = [2,3,4]
y2 = [3,5,3]
fig, axs = plt.subplots(1,2)
for pos in [0,1]:
    h1 = axs[pos].scatter(x,y,c='black',label='scttr')
    h2 = axs[pos].plot(x,y2,c='red',label='line')
    axs[pos].legend([h1, h2],['smtng', 'smtng2')
plt.show()

the code crashes with the following:

A proxy artist may be used instead. See: http://matplotlib.org/users/legend_guide.html#using-proxy-artist
"#using-proxy-artist".format(orig_handle))

I did not really understand what proxy artists are and why I would need one for such a basic thing.

Upvotes: 2

Views: 2849

Answers (2)

hitzg
hitzg

Reputation: 12701

At least in your simple example, it is way simpler if you don't pass any handles to legend:

...
axs[pos].legend()
...

Result:

enter image description here

You can overwrite the labels like this:

...
axs[pos].legend(['smtng', 'smtng2'])
...

Result: enter image description here

If you want to use the handles, you can. However, you have to consider that plot returns a list of Line objects. Thus you have to pass it to legend like this:

...
axs[pos].legend([h1, h2[0]],['smtng', 'smtng2'])
...

You only need to use proxy artists if you want to add something to the legend which does not exist in you plot or if you want (for some reason) make it look different in the legend than in the plot.

Upvotes: 1

Ffisegydd
Ffisegydd

Reputation: 53678

The issue is that you can't pass the Line objects directly to the legend call. What you can do, instead, is create some different objects (known as proxy artists) to fill the gap, so to speak.

Below are two proxy objects, scatter_proxy and line_proxy, for the scatter plot and line plot, respectively. You create both using matplotlib.lines.Line2D but the one for the scatter plot has a white line (so isn't effectively seen) and has markers added to it. I realise making the line color white is a bit hacky, but it was the best way I could find.

import matplotlib.pyplot as plt
import matplotlib.lines as mlines

pos = 0
x = [1,2,3]
y = [2,3,4]
y2 = [3,5,3]

fig, axs = plt.subplots(1,2)

scatter_color = 'black'
line_color='red'

for pos in [0,1]:
    h1 = axs[pos].scatter(x, y, c=scatter_color, label='scttr')
    h2 = axs[pos].plot(x, y2, c=line_color, label='line')

    scatter_proxy = mlines.Line2D([], [], color='white', marker='o', markerfacecolor=scatter_color)
    line_proxy = mlines.Line2D([], [], color=line_color)

    axs[pos].legend([scatter_proxy, line_proxy],['smtng', 'smtng2'])

plt.show()

enter image description here

Upvotes: 2

Related Questions