pst*_*mps 1 python list matplotlib pandas seaborn
假设我有一个结构如下的数据框:
Name x y
Joe 0,1,5 0,3,8
Sue 0,2,8 1,9,5
...
Harold 0,5,6 0,7,2
Run Code Online (Sandbox Code Playgroud)
我想将 x 轴和 y 轴中的值绘制在基于行的折线图上。实际上,有许多 x 和 y 值,但这些列中的每个 y 值始终对应一个 x 值。绘图的名称将是“名称”中的值。
我尝试通过首先将 x 和 y 转换为各自单独列中的列表来实现此目的,如下所示:
df['xval'] = df.['x'].str.split(',')
df['yval'] = df.['y'].str.split(',')
Run Code Online (Sandbox Code Playgroud)
然后将它们传递给seaborn:
ax = sns.lineplot(x=df['xval'], y=df['yval'], data=df)
Run Code Online (Sandbox Code Playgroud)
但是,这不起作用,因为 1)我收到一个错误,我认为这是由于尝试从数据帧传递列表所致,声称:
TypeError: unhashable type: 'list'
Run Code Online (Sandbox Code Playgroud)
2)我无法为特定线图指定 df['name'] 的值。解决这个问题的最佳方法是什么?
数据和导入:
import pandas as pd
import seaborn as sns
from matplotlib import pyplot as plt
df = pd.DataFrame({
'name': ['joe', 'sue', 'mike'],
'x': ['0,1,5', '0,2,8', '0,4'],
'y': ['0,3,8', '1,9,5', '1,6']
})
Run Code Online (Sandbox Code Playgroud)
我们应该转换df成可用的绘图格式。这使得所有的绘图变得更加容易。我们可以利用这一事实x并y建立一对一的关系。请注意,我添加了第三个名称,其 xy 值为 2(而不是 3),以表明只要每行具有相同数量的 x 和 y 值,此方法就适用于每个名称的不同数量的 x 和 y。
创建plot_df:
# Grab Name Column to Start Plot DF with
plot_df = df.loc[:, ['name']]
# Split X column
plot_df['x'] = df['x'].str.split(',')
# Explode X into Rows
plot_df = plot_df.explode('x').reset_index(drop=True)
# Split and Series Explode y in one step
# This works IF AND ONLY IF a 1-to-1 relationship for x and y
plot_df['y'] = df['y'].str.split(',').explode().reset_index(drop=True)
# These need to be numeric to plot correctly
plot_df.loc[:, ['x', 'y']] = plot_df.loc[:, ['x', 'y']].astype(int)
Run Code Online (Sandbox Code Playgroud)
plot_df:
name x y
0 joe 0 0
1 joe 1 3
2 joe 5 8
3 sue 0 1
4 sue 2 9
5 sue 8 5
6 mike 0 1
7 mike 4 6
Run Code Online (Sandbox Code Playgroud)
创建时使用的方法参考plot_df:
DataFrame.loc对数据框进行子集化Series.str.split将逗号分隔的值拆分为列表DataFrame.explode基于中的可迭代来升级 DataFramexDataFrame.reset_index使索引在爆炸后再次唯一Series.explode升级系列中的列表y。Series.reset_index使索引在爆炸后再次唯一DataFrame.astype因为这些值最初是字符串,仅分裂和爆炸是不够的。需要转换为数字类型才能正确绘制绘图(选项 1)
# Plot with hue set to name.
sns.lineplot(data=plot_df, x='x', y='y', hue='name')
plt.show()
Run Code Online (Sandbox Code Playgroud)
绘制单独线条的参考:
sns.lineplot来策划。请注意hue基于 来创建单独行的参数name。pyplot.show显示。绘制(选项 2.a)子图:
sns.relplot(data=plot_df, x='x', y='y', col='name', kind='line')
plt.tight_layout()
plt.show()
Run Code Online (Sandbox Code Playgroud)
绘图(选项 2.b)子图:
# Use Grouper From plot_df
grouper = plot_df.groupby('name')
# Create Subplots based on the number of groups (ngroups)
fig, axes = plt.subplots(nrows=grouper.ngroups)
# Iterate over axes and groups
for ax, (grp_name, grp) in zip(axes, grouper):
# Plot from each grp DataFrame on ax from axes
sns.lineplot(data=grp, x='x', y='y', ax=ax, label=grp_name)
plt.show()
Run Code Online (Sandbox Code Playgroud)
绘制子图的参考:
2.a
relplot或row参数col可用于以与创建多条线类似的方式创建子图hue。这将返回一个seaborn.FacetGrid所以后处理将不同于lineplot返回matplotlib.axes.Axes2.b
groupby创建可用于绘制子图的迭代。pyplot.subplots创建要绘制的子图。groupby.ngroup计算组数。zip同时迭代轴和组。sns.lineplot来策划。需要注意label的是有图例。grp_name包含当前 DataFrame 中通用的当前键grp。pyplot.show显示。绘图选项 3(单独绘图):
# Plot from each grp DataFrame in it's own plot
for grp_name, grp in plot_df.groupby('name'):
fig, ax = plt.subplots()
sns.lineplot(data=grp, x='x', y='y', ax=ax)
ax.set_title(grp_name)
fig.show()
Run Code Online (Sandbox Code Playgroud)
绘制单独图的参考:
groupby创建可用于单独绘制每个名称的迭代。pyplot.subplots创建单独的绘图来绘制。sns.lineplot来策划。需要注意label的是有图例。grp_name包含当前 DataFrame 中通用的当前键grp。pyplot.show显示。