【问题标题】:Grouped Bar-Chart with customized DateTime Index using pandas and Matplotlib使用 pandas 和 Matplotlib 自定义日期时间索引的分组条形图
【发布时间】:2020-02-08 08:43:36
【问题描述】:

我想创建一个显示自定义日期时间索引的分组条形图 - 仅显示月份和年份,而不是完整日期。我希望条形图被分组而不是堆叠。

我认为 pandas 可以轻松处理这个问题,使用:

import pandas as pd
import matplotlib.pylab as plt
import matplotlib.dates as mdates

testdata = pd.DataFrame({"A": [1, 2, 3]
                       ,"B": [2, 3, 1]
                       , "C": [2, 3, 1]}  
                       ,index=pd.to_datetime(pd.DatetimeIndex(
                            data=["2019-03-02", "2019-04-01","2019-05-01"])))
ax = testdata.plot.bar()

这会创建我想要的情节,我只想将日期更改为更简单的内容,例如 2019 年 3 月、2019 年 4 月、2019 年 5 月。

我认为使用自定义日期格式化程序会起作用,因此我尝试了

ax.xaxis.set_major_locator(mdates.MonthLocator())
ax.xaxis.set_major_formatter(mdates.DateFormatter('%b %Y'))

但是我的标签已经完全消失了。而this question 暗示 pandas 和 DateFormatter 的关系有点困难。因此我尝试使用 Matplotlib 基础知识:

fig, ax = plt.subplots()
width = 0.8
ax.bar(testdata.index, testdata["A"]) 
ax.bar(testdata.index, testdata["B"])
ax.bar(testdata.index, testdata["C"])
ax.xaxis.set_major_locator(mdates.MonthLocator())
ax.xaxis.set_major_formatter(mdates.DateFormatter('%b %Y'))
plt.show()

现在日期表示符合预期(尽管可以减少空格),但数据重叠,这无济于事。

由于我使用的 DateTime-Index,定义宽度并从 x 值中减去它(如通常建议的那样)将无济于事。我收到一个错误,即不支持减去 DatetimeIndes 和 float。

fig, ax = plt.subplots()
width = 0.8
ax.bar(testdata.index-width, testdata["A"]) 
ax.bar(testdata.index, testdata["B"])
ax.bar(testdata.index+width, testdata["C"])
ax.xaxis.set_major_locator(mdates.MonthLocator())
ax.xaxis.set_major_formatter(mdates.DateFormatter('%b %Y'))
plt.show()

所以现在我的想法已经不多了,希望得到输入

【问题讨论】:

    标签: python pandas matplotlib


    【解决方案1】:

    Pandas 条形图是分类的。所以也许你想多了,只是想用你想看到的字符串作为轴上的类别标签作为索引?

    import pandas as pd
    import matplotlib.pyplot as plt
    
    df = pd.DataFrame({"A": [1, 2, 3]
                           ,"B": [2, 3, 1]
                           , "C": [2, 3, 1]}  
                           ,index=pd.to_datetime(pd.DatetimeIndex(
                                data=["2019-03-02", "2019-04-01","2019-05-01"])))
    
    df.index = [d.strftime("%b %Y") for d in df.index]
    ax = df.plot.bar()
    plt.show()
    

    【讨论】:

      【解决方案2】:

      ax.xaxis.set_major_locator(mdates.MonthLocator()) 失败的原因是,在后台,pandas 会根据range(len(df)) 绘制条形图,然后相应地重命名刻度。

      您可以在绘制后抓取 xticklabels,然后重新格式化:

      ax = testdata.plot.bar()
      
      ticks = [tick.get_text() for tick in ax.get_xticklabels()]
      ticks = pd.to_datetime(ticks).strftime('%b %Y')
      ax.set_xticklabels(ticks)
      

      它给出的结果与 ImpotanceOfBeingErnest 的结果相同:

      另一种可能更好的方法是移动每列的条形。当您有很多列并希望减少 xticks 的数量时,这会更好。

      fig, ax = plt.subplots()
      
      # define the shift
      shift = pd.to_timedelta('1D')
      
      # modify the base of each columns, can do with a for loop
      ax.bar(testdata.index + shift, testdata["A"]) 
      ax.bar(testdata.index, testdata["B"])
      ax.bar(testdata.index - shift, testdata["C"])
      ax.xaxis.set_major_locator(mdates.MonthLocator())
      ax.xaxis.set_major_formatter(mdates.DateFormatter('%b %Y'))
      plt.show()
      

      输出:

      【讨论】:

      • 很高兴知道 pandas 在内部会忽略索引的值并直接绘图。我会记住这一点,以备将来参考。是否有一些关于 pandas 如何处理内部绘图的文档?
      • 我没有这方面的参考,只是根据我的经验。
      猜你喜欢
      • 1970-01-01
      • 2020-04-29
      • 2017-01-03
      • 2020-07-08
      • 2015-06-20
      • 1970-01-01
      • 2021-02-18
      • 2013-10-20
      • 1970-01-01
      相关资源
      最近更新 更多