如何根据不同的列绘制具有颜色和线型的宽数据框
Posted
技术标签:
【中文标题】如何根据不同的列绘制具有颜色和线型的宽数据框【英文标题】:How to plot a wide dataframe with colors and linestyles based on different columns 【发布时间】:2021-06-03 16:26:20 【问题描述】:这是我的一个数据框:
d = 'year': [2020,2020,2020,2021,2020,2020,2021],
'month': [10, 11,12,1,11,12,1],
'class':['A','A','A','A','B','B','B'],
'val1':[2,3,4,5,1,1,1],
'val2':[3,3,3,3,2,3,5]
df = pd.DataFrame(data=d)
输出:
year month class val1 val2
0 2020 10 A 2 3
1 2020 11 A 3 3
2 2020 12 A 4 3
3 2021 1 A 5 3
4 2020 11 B 1 2
5 2020 12 B 1 3
6 2021 1 B 1 5
我需要随着时间的推移以不同的颜色(比如绿色和红色)绘制 val1 和 val2。还有两个类 A 和 B,我想用不同的线型(实线和虚线)绘制这两个类。所以如果类是 A,那么 val1 在图中可能是纯绿色,如果类是 B,那么 val1 在图中可能是绿色虚线。如果 class 是 B,那么 val2 在图中可能是纯红色,如果 class 是 B,那么 val2 在图中可能是红色虚线。
但是我遇到了需要解决的时间(x 轴)问题。首先,时间在不同的列(年和月)中,并且两个类的行数不同。在上面的数据中,B 类直到 2020 年 11 月才开始。
我尝试解决这个问题是使用年份和月份创建新索引:
df.index=df['year']+df['month']/12
df.groupby('class')['val1'].plot(legend='True')
plt.show()
但这会在 x 轴上创建不理想的刻度标签(我想我可以稍后重命名)。虽然它区分了这两个类,但它并没有按照我想要的方式进行。我也不知道如何在图中添加更多列。请指教。谢谢
【问题讨论】:
【参考方案1】:-
组合
'year'
和'month'
列以创建一个带有datetime dtype
的列。
pandas.DataFrame.melt
用于将 DataFrame 从宽格式转换为长格式
使用seaborn.relplot
绘图,这是一个图形级别的绘图,以简化设置图形的高度和宽度。
类似于seaborn.lineplot
分别为颜色和线型指定 hue
和 style
。
使用mdates
为x 轴提供良好的格式。如果不需要,请删除。
pandas 1.2.4
、seaborn 0.11.1
和matplotlib 3.4.2
测试。
导入和转换 DataFrame
import pandas as pd
import seaborn as sns
import matplotlib.dates as mdates # required for formatting the x-axis dates
import matplotlib.pyplot as plt # required for creating the figure when using sns.lineplot; not required for sns.relplot
# combine year and month to create a date column
df['date'] = pd.to_datetime(df.year.astype(str) + df.month.astype(str), format='%Y%m')
# melt the dataframe into a tidy format
df = df.melt(id_vars=['date', 'class'], value_vars=['val1', 'val2'])
seaborn.relplot
# plot with seaborn
p = sns.relplot(data=df, kind='line', x='date', y='value', hue='variable', style='class', height=4, aspect=2, marker='o')
# format the x-axis - use as needed
# xfmt = mdates.DateFormatter('%Y-%m')
# p.axes[0, 0].xaxis.set_major_formatter(xfmt)
seaborn.lineplot
# set the figure height and width
fig, ax = plt.subplots(figsize=(8, 4))
# plot with seaborn
sns.lineplot(data=df, x='date', y='value', hue='variable', style='class', marker='o', ax=ax)
# format the x-axis
xfmt = mdates.DateFormatter('%Y-%m')
ax.xaxis.set_major_formatter(xfmt)
# move the legend
ax.legend(bbox_to_anchor=(1.04, 0.5), loc="center left")
融化df
date class variable value
0 2020-10-01 A val1 2
1 2020-11-01 A val1 3
2 2020-12-01 A val1 4
3 2021-01-01 A val1 5
4 2020-11-01 B val1 1
5 2020-12-01 B val1 1
6 2021-01-01 B val1 1
7 2020-10-01 A val2 3
8 2020-11-01 A val2 3
9 2020-12-01 A val2 3
10 2021-01-01 A val2 3
11 2020-11-01 B val2 2
12 2020-12-01 B val2 3
13 2021-01-01 B val2 5
【讨论】:
【参考方案2】:虽然这可以通过pyplot
和matplotlib
完成,但seaborn
等更高级别的界面将大大改善您绘制多个维度的体验。请参阅docs,了解使用 seaborn 标记数据的所有各种方式
试试:
import pandas as pd
import seaborn as sns
df['time'] = df.year + df.month/12
df1 = pd.wide_to_long(df, stubnames='val', i=['year', 'month', 'class'], j='val_number').reset_index()
sns.lineplot(x='time', y='val', hue='class', size='val_number', data=df1)
数据框现在将采用“长”形式,以允许每个“时间”点的唯一“vals”,以及您可以使用的相关标识符标签。
情节看起来有点混乱,但那是因为你试图用线图表示多少
【讨论】:
以上是关于如何根据不同的列绘制具有颜色和线型的宽数据框的主要内容,如果未能解决你的问题,请参考以下文章
如何根据第三列绘制具有不同颜色的线图? (KeyError:0)