首页 > 解决方案 > x 轴刻度作为日期

问题描述

我有一些数据要绘制,由两列组成,一列是金额count,另一列是实际记录的日期。绘制此图时,由于我有超过 2000 个日期,因此不将每个日期都显示为 - 轴上的刻度更有意义x,否则它将不可读。但是,我很难让日期x以某种逻辑显示在 - 轴上。我曾尝试使用 matplotlib 的内置刻度定位器,但它无法以某种方式工作。这是数据的预览:

PatientTraffic = pd.DataFrame({'count' : CleanData.groupby("TimeStamp").size()}).reset_index()
display(PatientTraffic.head(3000))

TimeStamp   count
0   2016-03-13 12:20:00 1
1   2016-03-13 13:39:00 1
2   2016-03-13 13:43:00 1
3   2016-03-13 16:00:00 1
4   2016-03-14 13:27:00 1
... ... ...
2088    2020-02-18 16:00:00 8
2089    2020-02-19 16:00:00 8
2090    2020-02-20 16:00:00 8
2091    2020-02-21 16:00:00 8
2092    2020-02-22 16:00:00 8
2093 rows × 2 columns

当我用这些设置来绘制它时:

PatientTrafficPerTimeStamp = PatientTraffic.plot.bar(
        x='TimeStamp', 
        y='count',
        figsize=(20,3),
        title = "Patient Traffic over Time"
        
    )
PatientTrafficPerTimeStamp.xaxis.set_major_locator(plt.MaxNLocator(3))

我希望得到一个条形图,其中x-axis 有三个刻度,一个在开始中间和结束......也许我用错了。此外,似乎出现的刻度只是列中的前 3 个,这不是我想要的。任何帮助,将不胜感激!

在此处输入图像描述

标签: pythonmatplotlib

解决方案


你可能认为你有一个问题,但实际上你有两个 - 两者都是基于你使用便利函数这一事实。您最可能不知道的问题是 pandas 将条形图绘制为分类数据。这在大多数情况下是有意义的,但显然不是,如果您将时间戳数据作为 x 轴。让我们看看我是否没有弥补:

import matplotlib.pyplot as plt
import pandas as pd

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 5))
df = pd.read_csv("test.txt", sep = "\s{2,}", engine="python")
#convert TS from string into datetime objects
df.TS = pd.to_datetime(df.TS, format="%Y-%m-%d %H:%M:%S")

#and plot it as you do directly from pandas that provides the data to matplotlib
df.plot.bar(
        x="TS", 
        y="Val",
        ax=ax1,
        title="pandas version"    
    )

#now plot the same data using matplotlib
ax2.bar(df.TS, df.Val, width=22)
ax2.tick_params(axis="x", labelrotation=90)
ax2.set_title("matplotlib version")    

plt.tight_layout()
plt.show()

样本输出:

在此处输入图像描述

因此,我们应该直接从 matplotlib 中绘制它们,以防止丢失时间戳信息。显然,我们失去了 pandas 提供的一些便利,例如,我们必须调整条的宽度并标记轴。现在,您可以使用 的其他便利功能,MaxNLocator但正如您注意到的那样,它已被编写为在大多数情况下都可以正常工作,但是您放弃了对刻度的精确定位的控制。为什么不使用 编写我们自己的定位器FixedLocator

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from matplotlib.ticker import FixedLocator
import pandas as pd

def myownMaxNLocator(datacol, n):
    datemin = mdates.date2num(datacol.min())
    datemax = mdates.date2num(datacol.max())
    xticks = np.linspace(datemin, datemax, n)
    return xticks


fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 5))
df = pd.read_csv("test.txt", sep = "\s{2,}", engine="python")
df.TS = pd.to_datetime(df.TS, format="%Y-%m-%d %H:%M:%S")
    
df.plot.bar(
        x="TS", 
        y="Val",
        ax=ax1,
        title="pandas version"    
    )

ax2.bar(df.TS, df.Val, width=22)
ax2.set_title("matplotlib version")
dateticks = myownMaxNLocator(df.TS, 5)
ax2.xaxis.set_major_locator(FixedLocator(dateticks))
ax2.tick_params(axis="x", labelrotation=90)

plt.tight_layout()
plt.show()

样本输出: 在此处输入图像描述

在这里,刻度以最低值开始,以最高值结束。或者,您可以使用LinearLocator在整个视图中均匀分布刻度的 :

from matplotlib.ticker import LinearLocator
...
ax2.bar(df.TS, df.Val, width=22)
ax2.set_title("matplotlib version")
ax2.xaxis.set_major_locator(LinearLocator(numticks=5))
ax2.tick_params(axis="x", labelrotation=90)
...

样本输出: 在此处输入图像描述

样本数据存储在具有以下结构的文件中:

        TS                   Val
0       2016-03-13 12:20:00  1
1       2016-04-13 13:39:00  3
2       2016-04-03 13:43:00  5
3       2016-06-17 16:00:00  1
4       2016-09-14 13:27:00  2
2088    2017-02-08 16:00:00  7
2089    2017-02-25 16:00:00  2
2090    2018-02-20 16:00:00  8
2091    2019-02-21 16:00:00  9
2092    2020-02-22 16:00:00  8

推荐阅读