【问题标题】:Global legend for subplots with different content具有不同内容的子图的全局图例
【发布时间】:2017-12-10 21:49:23
【问题描述】:

我通读了以前的解决方案,但无法使它们中的任何一个起作用。我想为各个子图创建一个全球图例。 此子图的 ax 对象由预定义类中的预定义函数“get_plot”生成 “The_predefined_plotting_class”大致是这样的:

该函数返回一个 ax 对象,每个 ax 对象都有多个“绘图”/来自原始“数据文件”的多个列。

在我在这个网站上找到的一个解决方案中,我读到我可以使用:

创造一个全球性的传奇。不幸的是,我不知道如何将单个 ax 对象(或其中的数据)附加到句柄以使其工作。 每个图都包含一些相同的列名和一些不同的列名。如果一个条目/名称存在于许多子图中,它应该只打印一次。

Solution1

Solution2

Solution3

编辑

很抱歉我不得不使用图片,但无论我在网页上做什么,即使它在预览窗口中正确显示(截图来自这个窗口),我也没有让我发布我的代码

EDIT2

如果我这样做:

lines=[]
labels=[]
for idata, datafile in enumerate(datafiles):

    MYData = The_predefined_plotting_class.from_file(datafile) 

    axis[idata] = The_predefined_plotting_class.get_plot( *kwargs)
    h, l = axis[idata].get_legend_handles_labels()

    lines.append(h)
    labels.append(l)


LINES=[]
LABELS=[]
for i in range(0, nrows):
    LINES+=lines[i]
    LABELS+=labels[i]
plt.legend( LINES, LABELS, loc="upper left", bbox_to_anchor=[0, 1],ncol=3, shadow=True, title="Legend", fancybox=True)
plt.show()

然后它显示所有 Data 。一些数据具有相同的行和标签处理程序。我现在剩下的问题是遍历两个列表并只删除一个条目,如果在两个列表中 tuple (LINES[j];LABELS[j]) = (LINES[i] ;LABELS[i]) 存在两次(并且仅在那时)。最好是第一个条目:

EDIT3

labels =[]
lines = []
h=["Cat","Mouse","Dog","Cat","Cat","Kangaroo","Dog"]
l=["black","white","brown","white","black","yellow","brown"]


for handle, label in zip(h, l):
    if label not in labels : 

            lines.append(handle)
            labels.append(label)

print "The disired Output is :"            
print '["Cat","Mouse","Dog","Cat","Kangaroo"]'
print '["black","white","brown","white","yellow"]'

print "currently you get:"               

print lines
print labels  

EDIT4

我添加了一个“最小”工作示例,其中应包含我的真实数据中发生的所有可能情况。

lines=[]
labels=[]
legend_properties = {'weight':'bold','size':10}  
# Example data
x1 = np.linspace(0.0, 5.0)
x2 = np.linspace(0.0, 2.0)

a = np.cos(2 * np.pi * x1) * np.exp(-x1)
b = np.cos(2 * np.pi * x2)
c = np.cos(5 * np.pi * x1) * np.exp(-x1)
c2 = np.cos(5 * np.pi * x1**2) * np.exp(-x1)
d = np.cos(2 * np.pi * x2 )
d2 = np.cos(2 * np.pi * x2-1 )
e = x1*5
e2 = -x1*5
f = np.exp(x1)-e
f2 = (np.exp(x1)-e)/2

nrows = 4
# Plot

fig, axis = plt.subplots(nrows, sharex=True, sharey=False, figsize=(5, 8))
fig.subplots_adjust(hspace=0.0001)
fig.suptitle("Stacked Plots with global Legend wich contains to little elements",fontsize=14,weight='bold')



axis[0].plot(x1, e, 'k--', label='Label1',color="green")
axis[0].plot(x1, e2, 'k--', label='Label2',color="blue")
axis[0].plot(x1, a, 'k--', label='Label3',color="yellow")
axis[1].plot(x1, c, 'k--', label='Label1',color="green")
axis[1].plot(x1, c2, 'k--', label='Label2',color="blue")
axis[1].plot(x1, a, 'k--', label='Label3',color="grey")
axis[2].plot(x2, d, '*', label='Label1',color="green")
axis[2].plot(x2, d2, 'D', label='Label2',color="green")
axis[3].plot(x1, f, 'H', label='Label1',color="green")
axis[3].plot(x1, f2, 'D', label='Label2',color="green")

for i in range(nrows):
    h, l = axis[i].get_legend_handles_labels()
    for handle, label in zip(h, l):
        if label not in labels:
            lines.append(handle)
            labels.append(label)

# only 3 Legend entrys Label1 , Label2 and Label3 are visible .. Differences in cloors and markers are ignored
plt.legend(handles=lines, labels=labels,bbox_to_anchor=(0., nrows+.02, 1., .102), loc=3,ncol=3, prop=legend_properties,mode="expand", borderaxespad=0.,frameon=False,framealpha=0.0) 

plt.show()

EDIT5

这是生成实际绘图的脚本部分。 “列”仅包含要绘制的实际数据的名称。

    # add plots
    ic = 0
    for col in columns:
        if col == "envelope":
            ax.plot(self.data.index, self.data.envelope,
                    linewidth=LINEWIDTH_envelope, c=last_color, label="")
        elif col == "Exp":
            ax.plot(self.data.index, self.data.Exp, c=first_color, linestyle="",
                    label="Exp", marker="o", markersize=MARKERSIZE )
        else:
            color = used_colors[ic % len(used_colors)]
            if fill and "BG" in self.data.columns:
                ax.fill_between(self.data.index, self.data.BG,
                                self.data[col], label=col, alpha=ALPHA,
                                color=color)
            else:
                ax.plot(self.data.index, self.data[col], linewidth=LINEWIDTH,
                        c=color, label=col)
            ic += 1

EDIT6

我试图根据我在这里提出的想法找到解决方案:

Iteration though lists

不幸的是,适用于两个包含字符串的列表的方法似乎不适用于艺术家处理。

import matplotlib.pyplot as plt
import numpy as np
LI=[]
lines=[]
labels=[]
legend_properties = {'weight':'bold','size':10}  
# Example data
x1 = np.linspace(0.0, 5.0)
x2 = np.linspace(0.0, 2.0)

a = np.cos(2 * np.pi * x1) * np.exp(-x1)
b = np.cos(2 * np.pi * x2)
c = np.cos(5 * np.pi * x1) * np.exp(-x1)
c2 = np.cos(5 * np.pi * x1**2) * np.exp(-x1)
d = np.cos(2 * np.pi * x2 )
d2 = np.cos(2 * np.pi * x2-1 )
e = x1*5
e2 = -x1*5
f = np.exp(x1)-e
f2 = (np.exp(x1)-e)/2

nrows = 4
# Plot

fig, axis = plt.subplots(nrows, sharex=True, sharey=False, figsize=(5, 8))
fig.subplots_adjust(hspace=0.0001)
#fig.suptitle("Stacked Plots with global Legend wich contains to little elements",fontsize=14,weight='bold')



axis[0].plot(x1, e, 'k--', label='Label1',color="green")
axis[0].plot(x1, e2, 'k--', label='Label2',color="blue")
axis[0].plot(x1, a, 'k--', label='Label3',color="yellow")
axis[1].plot(x1, c, 'k--', label='Label1',color="green")
axis[1].plot(x1, c2, 'k--', label='Label2',color="blue")
axis[1].plot(x1, a, 'k--', label='Label3',color="grey")
axis[2].plot(x2, d, '*', label='Label1',color="green")
axis[2].plot(x2, d2, 'D', label='Label2',color="green")
axis[3].plot(x1, f, 'H', label='Label1',color="green")
axis[3].plot(x1, f2, 'D', label='Label2',color="green")

for i in range(nrows):
    print i
    h, l = axis[i].get_legend_handles_labels()
    for hl in zip(h,l):

        if hl not in LI:
            LI.append(hl)
            lines.append(LI[-1][0])
            labels.append(LI[-1][1])

print LI            
















# only 3 Legend entrys Label1 , Label2 and Label3 are visible .. Differences in cloors and markers are ignored
plt.legend(handles=lines, labels=labels,bbox_to_anchor=(0., nrows+.02, 1., .102), loc=3,ncol=3, prop=legend_properties,mode="expand", borderaxespad=0.,frameon=False,framealpha=0.0) 


plt.show()

我认为问题是只比较了内存​​地址的字符串

if hl not in LI:

不是“h”的实际内容?

解决方案基于 ImportanceOfBeingErnest 在相关帖子Link7 中给出的解释:

import matplotlib.pyplot as plt
import numpy as np
import matplotlib.mlab as mlab
import math
import matplotlib.collections

def is_inlist(handle, handles):
    for h in handles:
        if isinstance(handle, matplotlib.collections.PolyCollection) and isinstance(h, matplotlib.collections.PolyCollection): 
            if np.all(h.get_facecolor() == handle.get_facecolor()) and \
                np.all(h.get_linestyle() == handle.get_linestyle()) and \
                np.all(h.get_alpha() == handle.get_alpha()):
                return True
        if isinstance(handle, matplotlib.lines.Line2D) and isinstance(h, matplotlib.lines.Line2D):
            if h.get_color() == handle.get_color() and \
                h.get_linestyle() == handle.get_linestyle() and \
                h.get_marker() == handle.get_marker():
                return True        


    return False


lines=[]
labels=[]
legend_properties = {'weight':'bold','size':10}  
# Example data


mu = 0
mu2 = 5
variance = 1
variance2 = 2
sigma = math.sqrt(variance)
sigma2 = math.sqrt(variance2)
x = np.linspace(mu-3*variance,mu+3*variance, 100)
x2 = np.linspace(mu2-3*variance2,mu2+3*variance2, 100)

nrows = 4
# Plot

fig, axis = plt.subplots(nrows, sharex=True, sharey=False, figsize=(5, 8))
fig.subplots_adjust(hspace=0.0001)
#fig.suptitle("Stacked Plots with global Legend wich contains to little elements",fontsize=14,weight='bold')


axis[0].fill_between(x+6,0,mlab.normpdf(x, mu, sigma), color='green',alpha=0.5,label="PEAK1", interpolate=True)
axis[0].fill_between(x+4,0,mlab.normpdf(x, mu, sigma), color='orange',alpha=0.5,label="PEAK2", interpolate=True)
axis[0].fill_between(x+3,0,mlab.normpdf(x, mu, sigma), color='blue',alpha=0.5,label="PEAK3", interpolate=True)
axis[0].fill_between(x+7,0,mlab.normpdf(x, mu, sigma), color='red',alpha=0.5,label="PEAK4", interpolate=True)
axis[0].plot(x2,2.5*mlab.normpdf(x2, mu2, sigma2),color='black',linestyle="",label="Exp", marker="o", markersize=4)

axis[1].fill_between(x+6,0,mlab.normpdf(x, mu, sigma), color='green',alpha=0.5,label="PEAK1", interpolate=True)
axis[1].fill_between(x+4,0,mlab.normpdf(x, mu, sigma), color='purple',alpha=0.5,label="PEAK2", interpolate=True)
axis[1].fill_between(x+3,0,mlab.normpdf(x, mu, sigma), color='blue',alpha=0.5,label="PEAK3", interpolate=True)
axis[1].fill_between(x+7,0,mlab.normpdf(x, mu, sigma), color='red',alpha=0.5,label="PEAK4", interpolate=True)
axis[1].fill_between(x+6.5,0,mlab.normpdf(x, mu, sigma), color='yellow',alpha=0.5,label="PEAK5", interpolate=True)
axis[1].plot(x2,2.5*mlab.normpdf(x2, mu2, sigma2),color='black',linestyle="",label="Exp", marker="o", markersize=4)

axis[2].fill_between(x+6,0,mlab.normpdf(x, mu, sigma), color='green',alpha=0.5,label="PEAK1", interpolate=True)
axis[2].fill_between(x+4,0,mlab.normpdf(x, mu, sigma), color='orange',alpha=0.5,label="PEAK2", interpolate=True)
axis[2].fill_between(x+3,0,mlab.normpdf(x, mu, sigma), color='#73d216',alpha=0.5,label="PEAK3", interpolate=True)
axis[2].fill_between(x+7,0,mlab.normpdf(x, mu, sigma), color='red',alpha=0.5,label="PEAK4", interpolate=True)
axis[2].plot(x2,2.5*mlab.normpdf(x2, mu2, sigma2),color='black',linestyle="",label="Exp", marker="o", markersize=4)


axis[3].fill_between(x+6,0,mlab.normpdf(x, mu, sigma), color='green',alpha=0.5,label="PEAK1", interpolate=True)
axis[3].fill_between(x+4,0,mlab.normpdf(x, mu, sigma), color='purple',alpha=0.5,label="PEAK2", interpolate=True)
axis[3].fill_between(x+3,0,mlab.normpdf(x, mu, sigma), color='blue',alpha=0.5,label="PEAK3", interpolate=True)
axis[3].fill_between(x+7,0,mlab.normpdf(x, mu, sigma), color='red',alpha=0.5,label="PEAK4", interpolate=True)
axis[3].fill_between(x+6.5,0,mlab.normpdf(x, mu, sigma), color='#73d216',alpha=0.5,label="PEAK5", interpolate=True)
axis[3].fill_between(x+5.5,0,mlab.normpdf(x, mu, sigma), color='violet',alpha=0.5,label="PEAK6", interpolate=True)
axis[3].plot(x2,2.5*mlab.normpdf(x2, mu2, sigma2),color='black',linestyle="",label="Exp", marker="o", markersize=4)



for i in range(nrows):
    h, l = axis[i].get_legend_handles_labels()
    for hi, li in zip(h,l):
        if not is_inlist(hi, lines):
            lines.append(hi)
            labels.append(li)






# only 3 Legend entrys Label1 , Label2 and Label3 are visible .. Differences in cloors and markers are ignored
plt.legend(handles=lines, labels=labels,bbox_to_anchor=(0., nrows-1+.02, 1., .102), loc=3,ncol=3, prop=legend_properties,mode="expand", borderaxespad=0.,frameon=False,framealpha=0.0) 


plt.show()

这里我的真实数据得到了更好的反映,因为我有 matplotlib.collections.PolyCollection) 和 matplotlib.lines.Line2D 对象需要比较。

【问题讨论】:

  • 所链接问题中的解决方案都不适合您?我建议一个简单的ax.legend(bbox_to_anchor=(1.05, 0), loc='lower center', borderaxespad=0.)
  • 您需要手动输入代码,不知何故您粘贴了代码的屏幕截图。
  • 如果我按照你的建议去做,我会得到:AttributeError: 'numpy.ndarray' object has no attribute 'legend' !我在上面添加了一个问题。

标签: python list matplotlib legend


【解决方案1】:

Edit2 看起来很有希望。然后,您可以检查标签是否已经在标签列表中,如果没有,请附加它。当然,我无法测试以下内容,但它至少应该显示这个概念。

lines=[]
labels=[]
for idata, datafile in enumerate(datafiles):

    MYData = The_predefined_plotting_class.from_file(datafile) 

    axis[idata] = The_predefined_plotting_class.get_plot( *kwargs)
    h, l = axis[idata].get_legend_handles_labels()

    for handle, label in zip(h, l):
        if label not in labels:
            lines.append(handle)
            labels.append(label)

plt.legend(handles=lines, labels=labels, loc="upper left", bbox_to_anchor=[0, 1],ncol=3, shadow=True, title="Legend", fancybox=True)
plt.show()

如果您想避免重复句柄,您可以使用使它们看起来相等的属性,并查看句柄列表中是否已经存在类似的艺术家。

def is_inlist(handle, handles):
    for h in handles:
        if h.get_color() == handle.get_color() and \
            h.get_linestyle() == handle.get_linestyle() and \
            h.get_marker() == handle.get_marker():
            return True
    return False

lines=[]
labels=[]
for i in range(nrows):
    h, l = axis[i].get_legend_handles_labels()
    for hi, li in zip(h,l):
        if not is_inlist(hi, lines):
            lines.append(hi)
            labels.append(li)

plt.legend(handles=lines, labels=labels) 

【讨论】:

  • @NorrinRadd 下次请提供minimal reproducible example。否则真的很难提供任何帮助。
  • 早......有一个元素 a 是绿色的,只有第一个出现在图例中。但事实并非如此。你有什么想法吗?
  • 一个手柄如何连接两个标签?无论如何,正如我已经说过的,minimal reproducible example 是必要的,以便能够为您提供一个好的解决方案。请注意,对于这样的示例,您不需要 The_predefined_plotting_class 左右。您只需要显示问题的工作代码,如果得到纠正,您就可以解决问题。
  • 如果你在不同的子图中用两种不同的颜色绘制相同的组件......“猫”可能比“黑色”和“白色”...... MWE 的问题在于不幸的是,我没有找到一种方法来模拟 The_predefined_plotting_class 的功能
  • 我为列表排序问题添加了一个 MWE
猜你喜欢
  • 2017-01-03
  • 1970-01-01
  • 2020-11-24
  • 2011-11-23
  • 2011-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-09
相关资源
最近更新 更多