2017-07-06 3 views
1

Ich habe frühere Lösungen gelesen, konnte sie aber nicht funktionieren lassen. Ich möchte eine globale Legende für einzelne Subplots haben. Die ax-Objekte von subplot sind durch eine vordefinierte Funktion „get_plot“ aus einer vordefinierten Klasse „The_predefined_plotting_class“ grob wie folgt generiert:Globale Legende für Subplots mit unterschiedlichem Inhalt

My code

Die Funktion gibt ein ax Objekt und jede Objekte ax haben mehr "plots"/aus mehreren Spalten der ursprünglichen "Datendateien".

In einer der Lösungen i auf dieser Seite finden, las ich, dass ich verwenden könnte:

enter image description here

zu einer globalen Legende zu machen. Leider habe ich keine Ahnung, wie man die einzelnen Ax-Objekte (oder die darin enthaltenen Daten) an Handles anhängt, damit dies funktioniert. Jede Zeichnung enthält einige identische Spaltennamen und einige, die sich unterscheiden. Wenn ein Eintrag/Name in vielen Unterplots vorhanden ist, sollte er nur einmal gedruckt werden.

Solution1

Solution2

Solution3

EDIT

Ich bin wirklich leid, dass ich Bilder verwenden musste, aber was auch immer ich die Webside tat habe ich meinen Code nicht zulassen veröffentlichen selbst wenn es im Vorschaufenster richtig angezeigt wurde (die Screenshots stammen aus diesem Fenster)

EDIT2

Wenn ich tue es wie folgt aus:

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

Dann zeigt sie alle Daten. Einige der Daten haben den gleichen Zeilen- und Label-Handler. Ich habe jetzt das Problem, beide Listen zu durchlaufen und nur einen Eintrag zu löschen, wenn in beiden Listen das Tupel(LINES [j]; LABELS [j]) = (LINES [i]; Etiketten [i]) existieren zweimal (und nur dann). Vorzugsweise ist der erste Eintrag:

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

Ich füge ein "Minimum" Arbeitsbeispiel, das alle möglichen Situationen enthalten soll, die in meinen realen Daten auftreten.

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

dies ist der betreffende Teil des Skripts bilden, wo die tatsächlichen Plots erzeugt werden. "columns" enthält nur die Namen der zu plottenden Daten.

# 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

Ich habe versucht, eine Lösung zu finden, basierend auf der Idee, die ich hier vorgestellt:

Iteration though lists

Leider, was für zwei Listen arbeitet Strings enthält, die für die nicht funktioniert Künstler handels scheint es.

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

denke ich das Problem, dass für die Speicheradresse in

nur die Zeichenfolge im Vergleich
if hl not in LI: 

nicht der eigentliche Inhalt von „h“?

Lösung auf der Grundlage der Erklärung von ImportanceOfBeingErnest gab in einem verwandten Beitrag 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() 

Hier meine realen Daten besser widerspiegelt, wie ich beide matplotlib.collections.PolyCollection) und matplotlib.lines.Line2D haben Objekte, die verglichen werden müssen.

+0

Keine der Lösungen in den Fragen für Sie linked gearbeitet? Ich würde vorschlagen, eine einfache 'ax.legend (bbox_to_anchor = (1.05, 0), loc = 'lower center', borderaxespad = 0.)' –

+0

Sie müssen den Code manuell eingeben, irgendwie fügen Sie in Screenshots von der Code. – ngoldbaum

+0

Wenn ich das mache, was Sie vorschlagen, bekomme ich: AttributeError: 'numpy.darray' Objekt hat kein Attribut 'legende'! Ich habe oben eine Frage hinzugefügt. – NorrinRadd

Antwort

1

Der Edit2 sieht vielversprechend aus. Sie können dann überprüfen, ob das Etikett bereits in der Etikettenliste enthalten ist. Wenn nicht, hängen Sie es an. Natürlich kann ich folgendes nicht testen, aber es sollte zumindest das Konzept zeigen.

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

Wenn Sie diplicate Griffe aviod möchten, können Sie die Eigenschaften verwenden, die sie gleich erscheinen zu lassen und sehen, ob ein ähnlicher Künstler in der Griffe Liste bereits vorhanden ist.

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) 

enter image description here

+0

@NorrinRadd beim nächsten Mal bitte eine [MCVE]. Sonst ist es wirklich schwer, Hilfe zu leisten. – ImportanceOfBeingErnest

+0

Zu früh .... wenn ein Handle mit zwei Labels "verbunden" ist, löscht die obige Lösung es trotzdem ... Dies bedeutet, wenn ein Subplot ein Element hat und ein Element rot ist und ein anderes Cublot ein Element a, das farbig ist grün erscheint nur der erste in der Legende. Aber das sollte nicht der Fall sein. Hast du irgendeine Idee? – NorrinRadd

+0

Wie kann ein Griff mit zwei Etiketten verbunden werden? In jedem Fall ist, wie ich schon sagte, ein [mcve] notwendig, um Ihnen eine gute Lösung anbieten zu können. Beachten Sie, dass Sie 'The_predefined_plotting_class' oder so für solch ein Beispiel nicht benötigen. Sie benötigen nur den Arbeitscode, der das Problem anzeigt, und wenn Sie das Problem behoben haben, können Sie Ihr Problem lösen. – ImportanceOfBeingErnest

Verwandte Themen