Pandas / Pyplot의 산점도 : 범주별로 플로팅하는 방법


89

Pandas DataFrame 개체를 사용하여 pyplot에서 간단한 산점도를 만들려고하지만 두 개의 변수를 그리는 효율적인 방법을 원하지만 기호는 세 번째 열 (키)로 지정됩니다. df.groupby를 사용하여 다양한 방법을 시도했지만 성공적으로 수행하지 못했습니다. 샘플 df 스크립트는 다음과 같습니다. 이렇게하면 'key1'에 따라 마커의 색상이 지정되지만 'key1'카테고리의 범례를보고 싶습니다. 가까워요? 감사.

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

답변:


118

scatter이를 위해 사용할 수 있지만,에 대한 숫자 값이 필요하며 key1눈치 채셨 듯이 범례가 없습니다.

plot이와 같은 개별 범주 에만 사용 하는 것이 좋습니다 . 예를 들면 :

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

여기에 이미지 설명 입력

기본 pandas스타일 처럼 보이게 rcParams하려면 pandas 스타일 시트로를 업데이트 하고 색상 생성기를 사용하면됩니다. (저는 또한 전설을 약간 수정하고 있습니다) :

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

여기에 이미지 설명 입력


위의 RGB 예에서 기호가 범례에 두 번 표시되는 이유는 무엇입니까? 한 번만 표시하는 방법?
Steve Schulist

1
@SteveSchulist- ax.legend(numpoints=1)하나의 마커 만 표시하는 데 사용 합니다. 는 두 가지가 있으며 Line2D, 두 마커를 연결하는 선이있는 경우가 많습니다.
Joe Kington

이 코드 plt.hold(True)ax.plot()명령 뒤에 추가 한 후에 만 저에게 효과적이었습니다 . 왜 그런지 아세요?
Yuval Atzmon 2016

set_color_cycle() matplotlib 1.5에서는 더 이상 사용되지 않습니다. 이 set_prop_cycle()지금.
ale

52

이것은 Seaborn ( pip install seaborn)을 oneliner로 사용하면 간단합니다.

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

여기에 이미지 설명 입력

다음은 참조 용 데이터 프레임입니다.

여기에 이미지 설명 입력

데이터에 3 개의 변수 열이 있으므로 다음을 사용하여 모든 쌍별 차원을 플로팅 할 수 있습니다.

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

여기에 이미지 설명 입력

https://rasbt.github.io/mlxtend/user_guide/plotting/category_scatter/ 는 또 다른 옵션입니다.


19

을 사용하면 다음 plt.scatter중 하나만 생각할 수 있습니다. 프록시 아티스트를 사용하는 것 :

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)

결과는 다음과 같습니다.

여기에 이미지 설명 입력


10

df.plot.scatter를 사용하고 각 포인트의 색상을 정의하는 c = 인수에 배열을 전달할 수 있습니다.

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

여기에 이미지 설명 입력


4

선언적 시각화에 중점을 둔 Altair 또는 ggpot 을 사용해 볼 수도 있습니다 .

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

알테어 코드

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

여기에 이미지 설명 입력

ggplot 코드

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

여기에 이미지 설명 입력


3

matplotlib 3.1부터는 .legend_elements(). Automated legend creation 에 예가 나와 있습니다. 장점은 단일 분산 호출을 사용할 수 있다는 것입니다.

이 경우 :

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

여기에 이미지 설명 입력

키가 숫자로 직접 주어지지 않은 경우 다음과 같이 보일 것입니다.

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

여기에 이미지 설명 입력


'PathCollection'개체에 'legends_elements'속성이 없다는 오류가 발생했습니다. 내 코드는 다음과 같습니다. 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이 답변의 첫 번째 문장을 확인하십시오. 또한 혼동하지 있는지 확인 legends_elements하고 legend_elements.
ImportanceOfBeingErnest

네 감사합니다. 오타 (범례 / 범례)였습니다. 지난 6 시간 이후로 작업 중이었기 때문에 Matplotlib 버전이 나에게 발생하지 않았습니다. 최신 버전을 사용하고 있다고 생각했습니다. 나는 문서에 그러한 방법이 있다고 말했지만 코드가 오류를 일으킨다는 것이 혼란 스럽습니다. 다시 감사합니다. 이제 잘 수 있습니다.
Nandish Patel

2

다소 해키하지만 한 번에 모든 작업을 수행 one1하는 Float64Index데 사용할 수 있습니다 .

df.set_index('one').sort_index().groupby('key1')['two'].plot(style='--o', legend=True)

여기에 이미지 설명 입력

0.20.3부터는 색인 정렬이 필요 하며 범례는 약간 불안정 합니다.


1

seaborn에는 scatterplot이를보다 효율적으로 수행 하는 래퍼 기능 이 있습니다.

sns.scatterplot(data = df, x = 'one', y = 'two', data =  'key1'])
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.