Pandas绘图:周末使用不同颜色,美化x轴上的时间显示

10

我创建了一个看起来像这样的图表enter image description here

我有几个问题:

  1. 如何具体显示周末。我考虑的一些方法是获取对应于周末的索引,然后在xlims之间绘制透明条形图。也可以为此绘制矩形。如果可以在Pandas中简单地完成,那就最好了。
  2. 日期格式不太好看

以下是用于生成此图的代码

ax4=df4.plot(kind='bar',stacked=True,title='Mains 1 Breakdown');
ax4.set_ylabel('Power (W)');
idx_weekend=df4.index[df4.index.dayofweek>=5]
ax.bar(idx_weekend.to_datetime(),[1800 for x in range(10)])

ax.bar是专门用于突出周末的,但它不会产生任何可见的输出。(问题1) 对于问题2,我尝试使用Major Formatter和Locators,代码如下:

ax4=df4.plot(kind='bar',stacked=True,title='Mains 1 Breakdown');
ax4.set_ylabel('Power (W)');
formatter=matplotlib.dates.DateFormatter('%d-%b');
locator=matplotlib.dates.DayLocator(interval=1);
ax4.xaxis.set_major_formatter(formatter);
ax4.xaxis.set_major_locator(locator);
输出结果如下: enter image description here 了解DataFrame的外观可能会有所帮助。
In [122]:df4

Out[122]:
<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 36 entries, 2011-04-19 00:00:00 to 2011-05-24 00:00:00
Data columns:
(0 to 6 AM) Dawn          19  non-null values
(12 to 6 PM) Dusk         19  non-null values
(6 to 12 Noon) Morning    19  non-null values
(6PM to 12 Noon) Night    20  non-null values
dtypes: float64(4)

如果例如将周末的刻度标签标记为另一种颜色是一种可接受的解决方案,那么在matplotlib中实现这一点并不是很复杂。要过滤掉周末,只需使用matplotlib的“WeekdayLocator”。就个人而言,我认为如果图形是在matplotlib中绘制而不是在pandas中绘制,那么自定义图形会更容易些。 - sodd
@nordev:我已将此内容添加到下面的解决方案中,现在已经是社区维基了。 - Nipun Batra
2个回答

13

我尝试了很多方法,目前这些小技巧可以解决问题。期待更符合Python语言风格和更一致的解决方案。 标签问题的解决方案:

def correct_labels(ax):
    labels = [item.get_text() for item in ax.get_xticklabels()]
    days=[label.split(" ")[0] for label in labels]
    months=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]
    final_labels=[]
    for i in range(len(days)):
        a=days[i].split("-")
        final_labels.append(a[2]+"\n"+months[int(a[1])-1])
    ax.set_xticklabels(final_labels)

在绘图时我做了以下更改

ax=df.plot(kind='bar',rot=0)

这将使标签旋转为0。

为了找到周末并突出显示它们,我编写了以下两个函数:

def find_weekend_indices(datetime_array):
    indices=[]
    for i in range(len(datetime_array)):
        if datetime_array[i].weekday()>=5:
            indices.append(i)
    return indices

def highlight_weekend(weekend_indices,ax):
    i=0
    while i<len(weekend_indices):
         ax.axvspan(weekend_indices[i], weekend_indices[i]+2, facecolor='green', edgecolor='none', alpha=.2)
         i+=2

现在,情节看起来更有用并覆盖了这些用例。enter image description here


1
我建议使用ax.axvspan(weekend_indices[i], weekend_indices[i]+2, facecolor='green', edgecolor='none', alpha=.2)来创建绿色“填充”,因为不需要显式指定ymax - sodd
仅当将indices.append(i)替换为indices.append(datetime_array[i])时,才适用于时间序列对象的替换。 - Martin

6
现在Pandas在每个系列上都支持强大的.dt命名空间,因此可以在没有任何显式Python循环的情况下识别每个周末的开始和结束。只需使用t.dt.dayofweek >= 5筛选您的时间值,以仅选择落在周末的时间,然后按一个每周不同的虚构值进行分组 - 在这里我使用year * 100 + weekofyear,因为结果看起来像201603这样的格式,对于调试而言相当方便。
生成的函数如下:
def highlight_weekends(ax, timeseries):
    d = timeseries.dt
    ranges = timeseries[d.dayofweek >= 5].groupby(d.year * 100 + d.weekofyear).agg(['min', 'max'])
    for i, tmin, tmax in ranges.itertuples():
        ax.axvspan(tmin, tmax, facecolor='orange', edgecolor='none', alpha=0.1)

只需将轴和作为您的 x 轴的时间序列传递给它,它就会为您突出显示周末!


我可以建议不要使用 dt 作为变量名,因为它常用于 import datetime as dt,这会导致混淆。 - yeliabsalohcin
1
@yeliabsalohcin 有趣的想法——我已经重命名了变量。我们会看看是否有关于可读性的任何投诉。 - Brandon Rhodes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接