如何从 Pandas 数据框中绘制多个折线图

Posted

技术标签:

【中文标题】如何从 Pandas 数据框中绘制多个折线图【英文标题】:How to plot multiple line charts from a Pandas data frames 【发布时间】:2018-07-28 21:18:24 【问题描述】:

我正在尝试从这样的数据框中制作一组折线图

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

df = pd.DataFrame( 'CITY' : np.random.choice(['PHOENIX','ATLANTA','CHICAGO', 'MIAMI', 'DENVER'], 10000),
                    'DAY': np.random.choice(['Monday','Tuesday','Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'], 10000),
                    'TIME_BIN': np.random.randint(1, 86400, size=10000),
                    'COUNT': np.random.randint(1, 700, size=10000))

df['TIME_BIN'] = pd.to_datetime(df['TIME_BIN'], unit='s').dt.round('10min').dt.strftime('%H:%M:%S')
print(df)

         CITY  COUNT        DAY  TIME_BIN
0     ATLANTA    270  Wednesday  10:50:00
1     CHICAGO    375  Wednesday  12:20:00
2       MIAMI    490   Thursday  11:30:00
3       MIAMI    571     Sunday  23:30:00
4      DENVER    379   Saturday  07:30:00
...       ...    ...        ...       ...
9995  ATLANTA    107   Saturday  21:10:00
9996   DENVER    127    Tuesday  15:00:00
9997   DENVER    330     Friday  06:20:00
9998  PHOENIX    379   Saturday  19:50:00
9999  CHICAGO    628   Saturday  01:30:00

这就是我现在拥有的:

piv = df.pivot(columns="DAY").plot(x='TIME_BIN', kind="Line", subplots=True)
plt.show()

但是 x 轴格式混乱了,我需要每个城市都有自己的线。我该如何解决?我在想我需要遍历一周中的每一天,而不是尝试在一行中创建一个数组。我试过seaborn没有运气。总而言之,这就是我想要实现的目标:

x 轴上的 TIME_BIN Y 轴计数 每个城市都有不同的颜色线 每天一张图表

【问题讨论】:

在我看来,在 for 循环中执行此操作并将每个框放在单独的子图中会很有帮助 - 然后您可以在第一次运行时轻松修复轴格式(只需正确格式化每个在创建子图时使用sharex=True)。 【参考方案1】:

我看不出数据透视在这里有什么帮助,因为最后您需要将数据划分两次,一次用于一周中的几天,应将其放入多个子图中,另一次用于城市,其中应有他们自己的彩色线。在这一点上,我们已经到了 pandas 可以用它的绘图包装器做的极限。

Matplotlib

使用 matplotlib 可以循环遍历日期和城市这两个类别并绘制数据。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates

df = pd.DataFrame( 
    'CITY' : np.random.choice(['PHOENIX','ATLANTA','CHICAGO', 'MIAMI', 'DENVER'], 10000),
    'DAY': np.random.choice(['Monday','Tuesday','Wednesday', 'Thursday', 
                             'Friday', 'Saturday', 'Sunday'], 10000),
    'TIME_BIN': np.random.randint(1, 86400, size=10000),
    'COUNT': np.random.randint(1, 700, size=10000))

df['TIME_BIN'] = pd.to_datetime(df['TIME_BIN'], unit='s').dt.round('10min')


days = ['Monday','Tuesday','Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
cities = np.unique(df["CITY"])
fig, axes = plt.subplots(nrows=len(days), figsize=(13,8), sharex=True)

# loop over days (one could use groupby here, but that would lead to days unsorted)
for i, day in enumerate(days):
    ddf = df[df["DAY"] == day].sort_values("TIME_BIN")
    # loop over cities
    for city in cities:
        dddf = ddf[ddf["CITY"] == city]
        axes[i].plot(dddf["TIME_BIN"], dddf["COUNT"], label=city)
    axes[i].margins(x=0)
    axes[i].set_title(day)


fmt = matplotlib.dates.DateFormatter("%H:%M") 
axes[-1].xaxis.set_major_formatter(fmt)   
axes[0].legend(bbox_to_anchor=(1.02,1))
fig.subplots_adjust(left=0.05,bottom=0.05, top=0.95,right=0.85, hspace=0.8)    
plt.show()

Seaborn

使用 seaborn FacetGrid 可以实现大致相同的效果。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates
import seaborn as sns

df = pd.DataFrame( 
    'CITY' : np.random.choice(['PHOENIX','ATLANTA','CHICAGO', 'MIAMI', 'DENVER'], 10000),
    'DAY': np.random.choice(['Monday','Tuesday','Wednesday', 'Thursday', 
                             'Friday', 'Saturday', 'Sunday'], 10000),
    'TIME_BIN': np.random.randint(1, 86400, size=10000),
    'COUNT': np.random.randint(1, 700, size=10000))

df['TIME_BIN'] = pd.to_datetime(df['TIME_BIN'], unit='s').dt.round('10min')

days = ['Monday','Tuesday','Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
cities = np.unique(df["CITY"])

g = sns.FacetGrid(data=df.sort_values('TIME_BIN'), 
                  row="DAY", row_order=days, 
                  hue="CITY", hue_order=cities, sharex=True, aspect=5)
g.map(plt.plot, "TIME_BIN", "COUNT")

g.add_legend()
g.fig.subplots_adjust(left=0.05,bottom=0.05, top=0.95,hspace=0.8)
fmt = matplotlib.dates.DateFormatter("%H:%M")
g.axes[-1,-1].xaxis.set_major_formatter(fmt)
plt.show()

【讨论】:

我收到此错误,DateFormatter 发现 x=0 的值,这是一个非法日期。这通常是因为您没有通知轴它正在绘制日期,例如使用 ax .xaxis_date()。我尝试使用 g.axes[-1, -1].xaxis_date() 投射 TIME_BIN,但没有成功。你知道如何解决这个错误吗? 您是否在按原样运行答案中的代码时遇到此错误? Nvm,我明白了,简单修复,df['TIME_BIN'] = pd.to_datetime(df['TIME_BIN']) 我没有对此发表评论,但与您的代码相比,我更改了 df['TIME_BIN'] = ... 行,以便数据框包含实际日期而不是日期。

以上是关于如何从 Pandas 数据框中绘制多个折线图的主要内容,如果未能解决你的问题,请参考以下文章

从数据的数据组中分别绘制折线图[重复]

如何使用Python的Pandas库绘制折线图

pandas之折线图(plot)

如何绘制具有不同数据比例的多个折线图

Python图形绘制:如何用Matplotlib和pandas绘图?

python多个折线图合并到一个三维图