2014-07-11 15 views
13

Sto creando alcuni grafici a dispersione e desidero impostare la dimensione dei punti nella legenda su un valore fisso e uguale.Impostazione di una dimensione fissa per i punti nella legenda

momento ho questo:

import matplotlib.pyplot as plt 
import numpy as np 

def rand_data(): 
    return np.random.uniform(low=0., high=1., size=(100,)) 

# Generate data. 
x1, y1 = [rand_data() for i in range(2)] 
x2, y2 = [rand_data() for i in range(2)] 


plt.figure() 
plt.scatter(x1, y1, marker='o', label='first', s=20., c='b') 
plt.scatter(x2, y2, marker='o', label='second', s=35., c='r') 
# Plot legend. 
plt.legend(loc="lower left", markerscale=2., scatterpoints=1, fontsize=10) 
plt.show() 

che produce questo:

enter image description here

Le dimensioni dei punti nella legenda sono scalate ma non la stessa. Come posso fissare le dimensioni dei punti della legenda a un valore uguale senza influire sulle dimensioni nel grafico scatter?

risposta

26

Ho dato un'occhiata al codice sorgente di matplotlib. La cattiva notizia è che non sembra esserci un modo semplice per impostare le dimensioni uguali dei punti nella legenda. È particolarmente difficile con i grafici a dispersione (errati: vedere l'aggiornamento sotto). Ci sono essenzialmente due alternative:

  1. modificare il codice
  2. maplotlib Aggiungi una trasformazione nelle PathCollection oggetti che rappresentano i punti nell'immagine. La trasformazione (ridimensionamento) deve tenere conto della dimensione originale.

Nessuno di questi è molto divertente, anche se il primo sembra più semplice. I diagrammisono particolarmente difficili da questo punto di vista.

Tuttavia, ho un hack che fa probabilmente quello che si vuole:

import matplotlib.pyplot as plt 
import numpy as np 

def rand_data(): 
    return np.random.uniform(low=0., high=1., size=(100,)) 

# Generate data. 
x1, y1 = [rand_data() for i in range(2)] 
x2, y2 = [rand_data() for i in range(2)] 

plt.figure() 
plt.plot(x1, y1, 'o', label='first', markersize=np.sqrt(20.), c='b') 
plt.plot(x2, y2, 'o', label='second', markersize=np.sqrt(35.), c='r') 
# Plot legend. 
lgnd = plt.legend(loc="lower left", numpoints=1, fontsize=10) 

#change the marker size manually for both lines 
lgnd.legendHandles[0]._legmarker.set_markersize(6) 
lgnd.legendHandles[1]._legmarker.set_markersize(6) 
plt.show() 

Questo dà:

enter image description here

che sembra essere quello che si voleva.

I cambiamenti:

  • scatter cambiato in un plot, che cambia la scala marcatore (da qui il sqrt) e rende impossibile usare cambiare dimensioni marcatore (se era destinato)
  • la dimensione marcatore modificata manualmente per essere 6 punti per entrambi i marcatori nella leggenda

Come si può vedere, questo utilizza le proprietà di sottolineatura nascosti (_legmarker) ed è bug-brutto. Potrebbe subentrare a qualsiasi aggiornamento in matplotlib.

Aggiornamento

Haa, ho trovato. Una migliore trucco:

import matplotlib.pyplot as plt 
import numpy as np 

def rand_data(): 
    return np.random.uniform(low=0., high=1., size=(100,)) 

# Generate data. 
x1, y1 = [rand_data() for i in range(2)] 
x2, y2 = [rand_data() for i in range(2)] 

plt.figure() 
plt.scatter(x1, y1, marker='o', label='first', s=20., c='b') 
plt.scatter(x2, y2, marker='o', label='second', s=35., c='r') 
# Plot legend. 
lgnd = plt.legend(loc="lower left", scatterpoints=1, fontsize=10) 
lgnd.legendHandles[0]._sizes = [30] 
lgnd.legendHandles[1]._sizes = [30] 
plt.show() 

Ora il _sizes (un altro sottolineano proprietà) fa il trucco. Non c'è bisogno di toccare la fonte, anche se questo è piuttosto un trucco. Ma ora puoi utilizzare tutte le offerte scatter.

enter image description here

+0

blu si suppone che sia più piccolo, ma dovrebbe essere semplice da risolvere , +1 – Aprillion

+0

Sorprendente risposta DrV! Scusa se non ho commentato prima, pensavo di averlo ma a quanto pare non ho mai inviato il cmmt. – Gabriel

+0

Volevo solo sottolineare che il secondo hack non funziona più, almeno per me ('python 3.5',' matplotlib 1.5.1'). Forse hanno cambiato qualcosa nel codice di 'matplotlib'. Il primo però funziona, grazie mille per quello. –

4

non ho avuto molto successo usando @ La soluzione di DRV anche se forse il mio caso d'uso è unico. A causa della densità dei punti, sto utilizzando la più piccola dimensione dell'indicatore, ad esempio plt.plot(x, y, '.', ms=1, ...), e desidero ingrandire i simboli della legenda.

ho seguito la raccomandazione che ho trovato sul matplotlib forums:

  1. plot i dati (senza etichette)
  2. record di assi limite (xlimits = plt.xlim())
  3. tracciare i dati falsi lontano da dati reali con si racconta appropriati colori dei simboli e dimensioni
  4. ripristino assi limiti (plt.xlim(xlimits))
  5. creare legenda

Ecco come si è scoperto (per questo i punti sono in realtà meno importante che le linee): enter image description here

Spero che questo aiuti qualcun altro.

4

Analogamente alla risposta, supponendo che si desidera tutti i marcatori con la stessa dimensione:

lgnd = plt.legend(loc="lower left", scatterpoints=1, fontsize=10) 
for handle in lgnd.legendHandles: 
    handle.set_sizes([6.0]) 

Con matplotlib 2.0.0