2014-06-11 14 views
8

Bu temel örnekte olduğu gibi, başka bir değişkenle ilgili olabileceğinden, dağılım grafiğinde noktaların boyutunu açıklayan bir (matplotlib) lejantı eklemenin bir yolunu arıyorum:matplotlib scatter legend boyutu oluşturma

(esinlenerek: http://matplotlib.org/examples/shapes_and_collections/scatter_demo.html)
import numpy as np 
import matplotlib.pyplot as plt 

N = 50 
x = np.random.rand(N) 
y = np.random.rand(N) 
a2 = 400*np.random.rand(N) 

plt.scatter(x, y, s=a2, alpha=0.5) 
plt.show() 

çok açıklamasında scatter içinde s tanımlayıcısı göre boyutları 0-400 (a2 değişken) karşılık gelen ideal birkaç noktalar olacaktır.

cevap

6

Aşağıdaki çözüm, boyutları birlikte kümelere (groupby ile) gruplandırmak için pandas kullanılır. Her bir grubu çizer ve işaretçiler için bir etiket ve bir boyut atar. this question'dan binning reçetesini kullandım. Aynı binning içindedir olarak

Not bu binned olan işaretleyici boyutları, bu a2 iki element, 36 ve 38 say demektir olarak belirtilen probleme biraz farklıdır, aynı boyutta olacaktır. Her zaman sizin için daha iyi olmasını sağlamak için kutu sayısını artırabilirsiniz.

Bu yöntemi kullanarak, işaretçi şekli veya rengi gibi her bölme için diğer parametreleri de değiştirebilirsiniz.

import numpy as np 
import matplotlib.pyplot as plt 
import pandas as pd 

N = 50 
M = 5 # Number of bins 

x = np.random.rand(N) 
y = np.random.rand(N) 
a2 = 400*np.random.rand(N) 

# Create the DataFrame from your randomised data and bin it using groupby. 
df = pd.DataFrame(data=dict(x=x, y=y, a2=a2)) 
bins = np.linspace(df.a2.min(), df.a2.max(), M) 
grouped = df.groupby(np.digitize(df.a2, bins)) 

# Create some sizes and some labels. 
sizes = [50*(i+1.) for i in range(M)] 
labels = ['Tiny', 'Small', 'Medium', 'Large', 'Huge'] 

for i, (name, group) in enumerate(grouped): 
    plt.scatter(group.x, group.y, s=sizes[i], alpha=0.5, label=labels[i]) 

plt.legend() 
plt.show() 

Plot

+0

sayesinde; Bu, her bir bölme için bir etikete sahip olan sınırlamalara sahiptir, yani etiketlerin çoğu daha sonra – gluuke

+1

göstergesine eklenmedikçe, daha fazla bidon daha fazla efsane çizgisi anlamına gelir. Eğer bazı noktaları, göstergede bir yer atamadan çizmek isterseniz daha sonra, efsaneye eklenmedikleri anlamına gelen "" _ "etiketini atayabilirsiniz. Örneğin "Küçük" ve "Büyük" yi "_" ile değiştirebilirim ve sonra da efsane ["Minik", "Orta", "Büyük"] olur. – Ffisegydd

4

Bu aynı zamanda çalışacağız ve bunu biraz daha basit olduğunu düşünüyorum:

msizes = np.array([3, 4, 5, 6, 7, 8]) 

l1, = plt.plot([],[], 'or', markersize=msizes[0]) 
l2, = plt.plot([],[], 'or', markersize=msizes[1]) 
l3, = plt.plot([],[], 'or', markersize=msizes[2]) 
l4, = plt.plot([],[], 'or', markersize=msizes[3]) 

labels = ['M3', 'M4', 'M5', 'M6'] 

leg = plt.legend([l1, l2, l3, l4], labels, ncol=1, frameon=True, fontsize=12, 
handlelength=2, loc = 8, borderpad = 1.8, 
handletextpad=1, title='My Title', scatterpoints = 1) 

Alındığı: Point size legends in matplotlib and basemap plots

+0

Bu benim için gittiğim şey. Çok nokta efsanesi biraz çirkin ve çok yayın kalitesi değil. – ryanjdillon

2

Neredeyse MJP yanıt gibi, ama o değil Oldukça çalışmak çünkü plt.plot'un 'işareti' argümanı plt.scatter'in 'argümanı' ile aynı anlama gelmez. Boyutlarınız plt.plot kullanılarak yanlış olacaktır.

yerine kullanın:

marker1 = plt.scatter([],[], s=a2.min()) 
    marker2 = plt.scatter([],[], s=a2.max()) 
    legend_markers = [marker1, marker2] 

    labels = [ 
     str(round(a2.min(),2)), 
     str(round(a2.max(),2)) 
     ] 

    fig.legend(handles=legend_markers, labels=labels, loc='upper_right', 
     scatterpoints=1)