Pandalar / Pyplot'ta dağılım grafikleri: Kategoriye göre nasıl çizim yapılır


90

Bir Pandas DataFrame nesnesi kullanarak pyplot'ta basit bir dağılım grafiği yapmaya çalışıyorum, ancak iki değişkeni çizmenin etkili bir yolunu istiyorum, ancak sembollerin üçüncü bir sütun (anahtar) tarafından dikte edilmesini istiyorum. Df.groupby kullanarak çeşitli yollar denedim, ancak başarılı olamadım. Örnek bir df komut dosyası aşağıdadır. Bu, işaretçileri "key1" e göre renklendirir, ancak Id, "key1" kategorilerine sahip bir efsane görmek ister. Yakın mıyım Teşekkürler.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame(np.random.normal(10,1,30).reshape(10,3), index = pd.date_range('2010-01-01', freq = 'M', periods = 10), columns = ('one', 'two', 'three'))
df['key1'] = (4,4,4,6,6,6,8,8,8,8)
fig1 = plt.figure(1)
ax1 = fig1.add_subplot(111)
ax1.scatter(df['one'], df['two'], marker = 'o', c = df['key1'], alpha = 0.8)
plt.show()

Yanıtlar:


120

Bunun için kullanabilirsiniz scatter, ancak bu sizin için sayısal değerlere sahip olmayı gerektirir key1ve fark ettiğiniz gibi bir efsaneye sahip olmayacaksınız.

Bunun plotgibi ayrı kategoriler için kullanmak daha iyidir . Örneğin:

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
np.random.seed(1974)

# Generate Data
num = 20
x, y = np.random.random((2, num))
labels = np.random.choice(['a', 'b', 'c'], num)
df = pd.DataFrame(dict(x=x, y=y, label=labels))

groups = df.groupby('label')

# Plot
fig, ax = plt.subplots()
ax.margins(0.05) # Optional, just adds 5% padding to the autoscaling
for name, group in groups:
    ax.plot(group.x, group.y, marker='o', linestyle='', ms=12, label=name)
ax.legend()

plt.show()

görüntü açıklamasını buraya girin

Her şeyin varsayılan pandasstile benzemesini istiyorsanız rcParams, pandalar stil sayfasını güncelleyin ve renk oluşturucuyu kullanın. (Ayrıca efsaneyi biraz değiştiriyorum):

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
np.random.seed(1974)

# Generate Data
num = 20
x, y = np.random.random((2, num))
labels = np.random.choice(['a', 'b', 'c'], num)
df = pd.DataFrame(dict(x=x, y=y, label=labels))

groups = df.groupby('label')

# Plot
plt.rcParams.update(pd.tools.plotting.mpl_stylesheet)
colors = pd.tools.plotting._get_standard_colors(len(groups), color_type='random')

fig, ax = plt.subplots()
ax.set_color_cycle(colors)
ax.margins(0.05)
for name, group in groups:
    ax.plot(group.x, group.y, marker='o', linestyle='', ms=12, label=name)
ax.legend(numpoints=1, loc='upper left')

plt.show()

görüntü açıklamasını buraya girin


Neden yukarıdaki RGB örneğinde sembol açıklamada iki kez gösteriliyor? Yalnızca bir kez nasıl gösterilir?
Steve Schulist

1
@SteveSchulist - ax.legend(numpoints=1)Yalnızca bir işaretçi göstermek için kullanın . İki tane var, a'da olduğu gibi Line2D, genellikle iki işaretleyiciyi birbirine bağlayan bir çizgi var.
Joe Kington

Bu kod sadece komuttan sonra ekledikten plt.hold(True)sonra benim için çalıştı ax.plot(). Herhangi bir fikrin neden?
Yuval Atzmon

set_color_cycle() matplotlib 1.5'te kullanımdan kaldırıldı. Orada set_prop_cycle()şimdi.
ale

52

Bu, bir oneliner olarak Seaborn ( pip install seaborn) ile yapmak kolaydır

sns.scatterplot(x_vars="one", y_vars="two", data=df, hue="key1") :

import seaborn as sns
import pandas as pd
import numpy as np
np.random.seed(1974)

df = pd.DataFrame(
    np.random.normal(10, 1, 30).reshape(10, 3),
    index=pd.date_range('2010-01-01', freq='M', periods=10),
    columns=('one', 'two', 'three'))
df['key1'] = (4, 4, 4, 6, 6, 6, 8, 8, 8, 8)

sns.scatterplot(x="one", y="two", data=df, hue="key1")

görüntü açıklamasını buraya girin

İşte referans için veri çerçevesi:

görüntü açıklamasını buraya girin

Verilerinizde üç değişken sütun bulunduğundan, tüm ikili boyutları aşağıdakilerle çizmek isteyebilirsiniz:

sns.pairplot(vars=["one","two","three"], data=df, hue="key1")

görüntü açıklamasını buraya girin

https://rasbt.github.io/mlxtend/user_guide/plotting/category_scatter/ başka bir seçenektir.


19

İle plt.scatter, aklıma sadece bir tane: proxy sanatçı kullanmak için:

df = pd.DataFrame(np.random.normal(10,1,30).reshape(10,3), index = pd.date_range('2010-01-01', freq = 'M', periods = 10), columns = ('one', 'two', 'three'))
df['key1'] = (4,4,4,6,6,6,8,8,8,8)
fig1 = plt.figure(1)
ax1 = fig1.add_subplot(111)
x=ax1.scatter(df['one'], df['two'], marker = 'o', c = df['key1'], alpha = 0.8)

ccm=x.get_cmap()
circles=[Line2D(range(1), range(1), color='w', marker='o', markersize=10, markerfacecolor=item) for item in ccm((array([4,6,8])-4.0)/4)]
leg = plt.legend(circles, ['4','6','8'], loc = "center left", bbox_to_anchor = (1, 0.5), numpoints = 1)

Ve sonuç:

görüntü açıklamasını buraya girin


10

Df.plot.scatter'ı kullanabilir ve her noktanın rengini tanımlayan c = argümanına bir dizi geçirebilirsiniz:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame(np.random.normal(10,1,30).reshape(10,3), index = pd.date_range('2010-01-01', freq = 'M', periods = 10), columns = ('one', 'two', 'three'))
df['key1'] = (4,4,4,6,6,6,8,8,8,8)
colors = np.where(df["key1"]==4,'r','-')
colors[df["key1"]==6] = 'g'
colors[df["key1"]==8] = 'b'
print(colors)
df.plot.scatter(x="one",y="two",c=colors)
plt.show()

görüntü açıklamasını buraya girin


4

Bildirime dayalı görselleştirmelere odaklanan Altair veya ggpot'u da deneyebilirsiniz .

import numpy as np
import pandas as pd
np.random.seed(1974)

# Generate Data
num = 20
x, y = np.random.random((2, num))
labels = np.random.choice(['a', 'b', 'c'], num)
df = pd.DataFrame(dict(x=x, y=y, label=labels))

Altair kodu

from altair import Chart
c = Chart(df)
c.mark_circle().encode(x='x', y='y', color='label')

görüntü açıklamasını buraya girin

ggplot kodu

from ggplot import *
ggplot(aes(x='x', y='y', color='label'), data=df) +\
geom_point(size=50) +\
theme_bw()

görüntü açıklamasını buraya girin


4

Matplotlib 3.1'den itibaren kullanabilirsiniz .legend_elements(). Otomatik açıklama oluşturmada bir örnek gösterilmektedir . Avantajı, tek bir dağılım çağrısının kullanılabilmesidir.

Bu durumda:

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

df = pd.DataFrame(np.random.normal(10,1,30).reshape(10,3), 
                  index = pd.date_range('2010-01-01', freq = 'M', periods = 10), 
                  columns = ('one', 'two', 'three'))
df['key1'] = (4,4,4,6,6,6,8,8,8,8)


fig, ax = plt.subplots()
sc = ax.scatter(df['one'], df['two'], marker = 'o', c = df['key1'], alpha = 0.8)
ax.legend(*sc.legend_elements())
plt.show()

görüntü açıklamasını buraya girin

Anahtarların doğrudan sayı olarak verilmemesi durumunda,

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

df = pd.DataFrame(np.random.normal(10,1,30).reshape(10,3), 
                  index = pd.date_range('2010-01-01', freq = 'M', periods = 10), 
                  columns = ('one', 'two', 'three'))
df['key1'] = list("AAABBBCCCC")

labels, index = np.unique(df["key1"], return_inverse=True)

fig, ax = plt.subplots()
sc = ax.scatter(df['one'], df['two'], marker = 'o', c = index, alpha = 0.8)
ax.legend(sc.legend_elements()[0], labels)
plt.show()

görüntü açıklamasını buraya girin


"PathCollection" nesnesinin "legends_elements" niteliği olmadığını söyleyen bir hata aldım. Kodum aşağıdaki gibidir. fig, ax = plt.subplots(1, 1, figsize = (4,4)) scat = ax.scatter(rand_jitter(important_dataframe["workout_type_int"], jitter = 0.04), important_dataframe["distance"], c = color_list, marker = 'o', alpha = 0.9) print(scat.legends_elements()) #ax.legend(*scat.legend_elements())
Nandish Patel

1
@NandishPatel Bu cevabın ilk cümlesini kontrol edin. Ayrıca karıştırmamaya dikkat edin legends_elementsve legend_elements.
ImportanceOfBeingErnest

Evet teşekkür ederim. Bu bir yazım hatasıydı (efsaneler / efsaneler). Son 6 saattir bir şey üzerinde çalıştığım için Matplotlib versiyonu aklıma gelmedi. En sonuncuyu kullandığımı sanıyordum. Belgelerin böyle bir yöntem olduğunu söylediği, ancak kodun hata verdiği konusunda kafam karıştı. Tekrar teşekkürler. Şimdi uyuyabilirim
Nandish Patel


1

seaborn, scatterplotbunu daha verimli yapan bir sarmalayıcı işlevine sahiptir.

sns.scatterplot(data = df, x = 'one', y = 'two', data =  'key1'])
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.