Pandas / Pyplot中的散点图:如何按类别绘制[重复]
Posted
技术标签:
【中文标题】Pandas / Pyplot中的散点图:如何按类别绘制[重复]【英文标题】:Scatter plots in Pandas/Pyplot: How to plot by category [duplicate] 【发布时间】:2014-03-06 10:50:46 【问题描述】:我正在尝试使用 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()
【问题讨论】:
【参考方案1】:使用Seaborn (pip install seaborn
) 作为单行者很简单
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")
这是供参考的数据框:
由于您的数据中有三个变量列,您可能希望绘制所有成对维度:
sns.pairplot(vars=["one","two","three"], data=df, hue="key1")
https://rasbt.github.io/mlxtend/user_guide/plotting/category_scatter/ 是另一种选择。
【讨论】:
【参考方案2】:seaborn 有一个包装函数 scatterplot
,它可以更有效地执行此操作。
sns.scatterplot(data = df, x = 'one', y = 'two', data = 'key1'])
【讨论】:
【参考方案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())
@NandishPatel 检查这个答案的第一句话。还要确保不要混淆legends_elements
和legend_elements
。
好的,谢谢。那是一个错字(传说/传说)。自从过去 6 个小时以来,我一直在做一些事情,所以我没有想到 Matplotlib 版本。我以为我用的是最新的。我很困惑文档说有这样的方法,但代码给出了错误。再次感谢你。我现在可以睡觉了。【参考方案4】:
这很 hacky,但您可以使用 one1
作为 Float64Index
一次性完成所有操作:
df.set_index('one').sort_index().groupby('key1')['two'].plot(style='--o', legend=True)
请注意,从 0.20.3 开始,sorting the index is necessary,图例为 a bit wonky。
【讨论】:
【参考方案5】:您可以使用 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()
【讨论】:
【参考方案6】:您也可以尝试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))
Altair 代码
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()
【讨论】:
【参考方案7】:有了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)
结果是:
【讨论】:
【参考方案8】:您可以为此使用 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
样式,那么只需使用 pandas 样式表更新 rcParams
并使用它的颜色生成器。 (我也在稍微调整一下图例):
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 示例中,符号在图例中显示了两次?如何只显示一次? @SteveSchulist - 使用ax.legend(numpoints=1)
仅显示一个标记。有两个,就像Line2D
,通常有一条线连接两个标记。
此代码仅在ax.plot()
命令后添加plt.hold(True)
后对我有效。知道为什么吗?
set_color_cycle()
在 matplotlib 1.5 中已弃用。现在有set_prop_cycle()
。
非常违反直觉,但谢谢!以上是关于Pandas / Pyplot中的散点图:如何按类别绘制[重复]的主要内容,如果未能解决你的问题,请参考以下文章
来自颜色字典的 matplotlib.pyplot 散点图图例
带有分类标记的行/列的散点图 Pandas DataFrame
数据可视化实例: 带线性回归最佳拟合线的散点图(matplotlib,pandas)