如何根据不同的列绘制具有颜色和线型的宽数据框

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 分别为颜色和线型指定 huestyle。 使用mdates 为x 轴提供良好的格式。如果不需要,请删除。
使用pandas 1.2.4seaborn 0.11.1matplotlib 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】:

虽然这可以通过pyplotmatplotlib 完成,但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)

R:ggplot-根据组绘制具有不同颜色的数据点趋势线

ggvis 彩色折线图和相应的图例

在 seaborn 中绘制不同的组时如何将数据作为一组包含在内

根据节点值为networkx中的节点绘制不同的颜色

Pyspark:如何在不同条件的数据框中创建列