2017-08-29 2 views
1

I Patches über ein Bild mit dem (vereinfachten) folgenden Code überlagern:matplotlib: match Legende Farbe patchCollection Farbe

import matplotlib.pyplot as plt 
from scipy.misc import imread 
from matplotlib.collections import PatchCollection 
from matplotlib.patches import Circle, Arrow 
import numpy as np 

def plotFeatures(patches, colours, legends, str_title, colour_scale): 

    fig = plt.figure(); ax = plt.gca() 

    p = PatchCollection(patches, cmap=plt.get_cmap('Spectral_r'), alpha=0.9) 
    p.set_array(np.array(colours)) 
    ax.add_collection(p) 
    p.set_clim(colour_scale) 
    fig.colorbar(p, ax=ax, fraction=0.015) 
    plt.xlabel(str_title) 
    plt.legend(handles=patches, labels=legends, bbox_to_anchor=(0., 1.02, 1., .2), mode='expand', ncol=3, loc="lower left") 
    # ax.set_xticks([]); ax.set_yticks([]) 
    ax.set_xlim([0,100]) 
    ax.set_ylim([0,100]) 


if __name__ == '__main__': 

    my_cmap = plt.get_cmap('Spectral_r') 

    # simplified data structure for example 
    allweights = [ {'name': 'Feature 1', 'mean': 2.1, 'x': 60, 'y':30}, 
        {'name': 'Feature 2', 'mean': 3.0, 'x': 10, 'y':40}, 
        {'name': 'Feature 3', 'mean': 2.5, 'x': 30, 'y':20} ] 

    KPD_patchList = [] 
    KPD_colourList = [] 
    KPD_legendList = [] 

    for w in allweights: 
     KPD_patchList.append(Circle((w['x'], w['y']), w['mean'] + 5)) 
     KPD_colourList.append(w['mean']) 
     KPD_legendList.append('{:s} ({:.2f})'.format(w['name'], w['mean'])) 

    plotFeatures(KPD_patchList, KPD_colourList, KPD_legendList, 'myFeatures', [0, 3]) 

    plt.show() 

dass die Ergebnisse: enter image description here

jedoch die Patches in der Legende nicht tun habe die richtige Farbe.

Das Problem, das ich habe, ist, dass ich die Farbe für die PatchColection p gesetzt habe, aber plt.legend() akzeptiert keine PatchCelection für Handles und ich muss es mit den Patches füttern, die keine Farbdaten enthalten.

Ich versuchte Farbdaten an die Patches direkt mit facecolor=my_cmap(w['mean'] wenn ich Cricle nennen, wie hinzuzufügen:

for w in allweights: 
     KPD_patchList.append(Circle((w['x'], w['y']), w['mean'] + 5, facecolor=my_cmap(w['mean']))) 
     KPD_colourList.append(w['mean']) 
     KPD_legendList.append('{:s} ({:.2f})'.format(w['name'], w['mean'])) 

aber dann die Farben nicht equaly skaliert wie in dem Grundstück:

enter image description here

Antwort

1

Ich denke, Sie waren mit Ihrem zweiten Versuch auf dem richtigen Weg, außer dass Ihre Daten für die Colormap nicht korrekt normalisiert sind. Wenn Sie versuchen, einen Farbwert aus einer Farbpalette zu erhalten, müssen Sie einen Wert im Bereich [0-1] angeben. Um die Dinge einfacher zu machen, verwende ich oft matplotlib.cm.ScalarMappable (link to documentation), die diese Umwandlung automatisch behandelt.

lösen Ihr Problem modifizierte ich die Funktion plotFeatures() wie so:

def plotFeatures(patches, colours, legends, str_title, colour_scale): 

    fig = plt.figure(); ax = plt.gca() 

    p = PatchCollection(patches, cmap=plt.get_cmap('Spectral_r'), alpha=0.9) 
    p.set_array(np.array(colours)) 
    ax.add_collection(p) 
    p.set_clim(colour_scale) 
    fig.colorbar(p, ax=ax, fraction=0.015) 
    plt.xlabel(str_title) 

    # generate legend 
    # create a `ScalarMappable` object with the colormap used, and the right scaling 
    cm = matplotlib.cm.ScalarMappable(cmap=p.get_cmap()) 
    cm.set_clim(colour_scale) 
    # create a list of Patches for the legend 
    l = [Circle((None,None), facecolor=cm.to_rgba(mean_value)) for mean_value in colours] 
    # add legend to plot 
    plt.legend(handles=l, labels=legends, bbox_to_anchor=(0., 1.02, 1., .2), mode='expand', ncol=3, loc="lower left") 


    # ax.set_xticks([]); ax.set_yticks([]) 
    ax.set_xlim([0,100]) 
    ax.set_ylim([0,100]) 

enter image description here

+0

musste ich 'Import matplotlib', und ich änderte die Variable' 'l' für legend_handles', wie pro [PEP8] (https://www.python.org/dev/peps/pep-0008/#names-to-avoid) Namenskonvention. Ansonsten perfekt. – fuyas