Combine two Pyplot patches for legend

2019-01-09 13:40发布

I am trying to plot some data with confidence bands. I am doing this with two plots for each data stream: plot, and fill_between. I would like the legend to look similar to the plots, where each entry has a box (the color of the confidence region) with a darker, solid line passing through the center. So far I have been able to use patches to create the rectangle legend key, but I don't know how to achieve the centerline. I tried using hatch, but there is no control over the placement, thickness, or color.

My original idea was to try and combine two patches (Patch and 2DLine); however, it hasn't worked yet. Is there a better approach? My MWE and current figure are shown below.

import matplotlib.patches as mpatches
import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0,1,11)
y = np.linspace(0,1,11)

plt.plot(x, y, c='r')
plt.fill_between(x, y-0.2, y+0.2, color='r', alpha=0.5)
p = mpatches.Patch(color='r', alpha=0.5, linewidth=0)

plt.legend((p,), ('Entry',))

Figure

3条回答
smile是对你的礼貌
2楼-- · 2019-01-09 14:13

The solution is borrowed from the comment by CrazyArm, found here: Matplotlib, legend with multiple different markers with one label. Apparently you can make a list of handles and assign only one label and it magically combines the two handles/artists.

import matplotlib.patches as mpatches
import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0,1,11)
y = np.linspace(0,1,11)

p1, = plt.plot(x, y, c='r')  # notice the comma!
plt.fill_between(x, y-0.2, y+0.2, color='r', alpha=0.5)
p2 = mpatches.Patch(color='r', alpha=0.5, linewidth=0)

plt.legend(((p1,p2),), ('Entry',))

Figure

查看更多
你好瞎i
3楼-- · 2019-01-09 14:24

I am having 'similar' issues. I was able to achieve the following thanks to this question.

fig = pylab.figure()
figlegend = pylab.figure(figsize=(3,2))
ax = fig.add_subplot(111)
point1 = ax.scatter(range(3), range(1,4), 250, marker=ur'$\u2640$', label = 'S', edgecolor = 'green')
point2 = ax.scatter(range(3), range(2,5), 250, marker=ur'$\u2640$', label = 'I', edgecolor = 'red')
point3 = ax.scatter(range(1,4), range(3),  250, marker=ur'$\u2642$', label = 'S', edgecolor = 'green')
point4 = ax.scatter(range(2,5), range(3), 250, marker=ur'$\u2642$', label = 'I', edgecolor = 'red')
figlegend.legend(((point1, point3), (point2, point4)), ('S','I'), 'center',  scatterpoints = 1, handlelength = 1)
figlegend.show()
pylab.show()

However, my two (venus and mars) markers overlap in the legend. I tried playing with handlelength, but that doesn't seem to help. Any suggestions or comments would be helpful.

查看更多
Deceive 欺骗
4楼-- · 2019-01-09 14:25

starting with your code,

this is the closest i can get you. there may be a way to create the patch in a way you want but i am a bit new to this as well and all i can do is build the proper legend:

import matplotlib.patches as mpatches
import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0,1,11)
y = np.linspace(0,1,11)

fig = plt.figure()
ax = fig.add_subplot(111)
plt.plot(x, y, c='r',label='Entry')
plt.fill_between(x, y-0.2, y+0.2, color='r', alpha=0.5)
p_handle = [mpatches.Patch(color='r', alpha=0.5, linewidth=0)]
p_label = [u'Entry Confidence Interval']
handle, label = ax.get_legend_handles_labels()
handles=handle+p_handle
labels=label+p_label
plt.legend(handles,labels,bbox_to_anchor=(0. ,1.02 ,1.,0.3),loc=8,
           ncol=5,mode='expand',borderaxespad=0,prop={'size':9},numpoints=1)

plt.show()

enter image description here

From what i can tell you would have to create ans "artist" object that fits the design you are looking for which i cannot find a method of doing. some examples of something similar can be found in this thread: Custom Legend Thread

Hope that helps good luck, I am interested if there are more in depth ways as well.

查看更多
登录 后发表回答