绘制带有两个 x 标签索引的图 - 日期和时间

时间:2021-04-06 13:57:40

标签: python pandas matplotlib

我有很多每季度的数据(消耗与时间)。我必须对这些数据求平均值,我希望根据一周中的天数 + 时间来显示平均值。

所以我希望在同一时间放置日期和时间的图形。预期的结果在 Excel 中是可能的,但我希望在 python 中使用 matplotlib(并使用数据帧)来实现。

如果您有任何想法,非常感谢! 纪尧姆

这是一个显示不错结果的代码,但我想要更好的。 很抱歉,因为我是论坛的新手,所以无法直接附加图片。

import pandas as pd
import datetime
import matplotlib.pyplot as plts

columns = ["Date/Time","Value"]
new_df = pd.DataFrame(columns = columns)
Jour1 = pd.to_datetime('02/01/2021')
value = np.random.randint(100, 150, size=(672,))

for x in range(672):
    TimeStamp = Jour1
    Jour1 = Jour1 + datetime.timedelta(minutes=15)  
    new_df = new_df.append(pd.Series([TimeStamp,value[x]],  index = columns) ,ignore_index=True) 

new_df['Day of week Name'] = new_df['Date/Time'].dt.dayofweek.astype(str) + ' - '+ new_df['Date/Time'].dt.day_name()
new_df["Time"] = new_df['Date/Time'].dt.time
new_df = new_df.groupby(['Day of week Name','Time'])['Value'].sum().reset_index()
new_df['TimeShow'] = new_df['Day of week Name'] +' '+ new_df['Time'].astype(str)

fig = plt.figure(figsize=(18,10))
ax=fig.add_subplot(111)

ax.plot(new_df['TimeShow'], new_df['Value'], label="Test", linewidth = 2)
plt.xticks(['0 - Monday 00:00:00','1 - Tuesday 00:00:00','2 - Wednesday 00:00:00','3 - Thursday 00:00:00','4 - Friday 00:00:00','5 - Saturday 00:00:00','6 - Sunday 00:00:00'])
plt.show()

Image in python

Image in excel - day not in order

编辑: 感谢您的帮助,我终于找到了适合我的东西。我不知道代码是否经过优化,但它有效。如果需要,这里是代码:

fig = plt.figure(figsize=(18,10))
ax=fig.add_subplot(111)

date_rng = pd.date_range('2021-01-01 00:00:00','2021-01-08 00:00:00', freq='6h')
xlabels = pd.DataFrame(index=date_rng)
xlabels = xlabels.index.strftime('%H:%M').tolist()

liste_saisons =  df['Saison'].unique().tolist()
for saisons in liste_saisons :

    df_show = df.loc[(df['Saison'] == saisons)]
    df_show = df_show.groupby(['Jour Semaine Nom','Time'],as_index=False)['SUM(CORR_VALUE)'].mean()
    df_show['TimeShow'] = df_show['Jour Semaine Nom'] +' '+ df_show['Time'].astype(str)
    ax.plot(df_show.index, df_show['SUM(CORR_VALUE)'], label=saisons, linewidth = 3)
    
fig.suptitle('Evolution de la charge BT quart-horaire moyenne semaine', fontsize=20)
plt.xlabel('Jour de la semaine + Heure', fontsize=20)
plt.ylabel('Charge BT quart-horaire moyenne [MW]', fontsize = 20)
plt.rc('legend', fontsize=16)
ax.legend(loc='upper left')
plt.grid(color='k', linestyle='-.', linewidth=1)


ax.set_xticklabels(xlabels)
plt.xticks(np.arange(0, 96*7, 4*6))
plt.ylim(50,350)

xdays = df_show["Jour Semaine Nom"].tolist()
graph_pos = plt.gca().get_position()
points = np.arange(48, len(xdays), 96)
day_points = np.arange(0, len(xdays), 96)
offset = -65.0
trans = ax.get_xaxis_transform()
for i,d in enumerate(xdays):
    if i in points:
         ax.text(i, graph_pos.y0 - offset, d, ha='center',bbox=dict(facecolor='cyan', edgecolor='black', boxstyle='round'), fontsize=12)

plt.show()

Result

1 个答案:

答案 0 :(得分:0)

这种任务有很多可能的方法,但我使用了 text 和 plot 函数来处理它。为了添加第一个日期,我取了图形的大小并从 y0 值中减去偏移值来确定位置。为了添加第一个日期,我取图形的大小并从 y0 值中减去一个偏移值,对于每个日期,我手动设置 y1 值以定位垂直线。

PS:为了更快的回答,即使有未完成的代码,我也会呈现出来。附上图片而不是链接。在文本中附加玩具数据。这是必要的。

import pandas as pd
import numpy as np

date_rng = pd.date_range('2021-01-01','2021-03-01', freq='1h')
value = np.random.randint(100, 150, size=(1417,))
df = pd.DataFrame({'date':pd.to_datetime(date_rng),'value':value})

import matplotlib.pyplot as plt

w = 0.7
fig,ax = plt.subplots(figsize=(20,4))

ax.bar(df.date[:100].apply(lambda x:x.strftime('%Y-%m-%d %H:%M:%S')), df.value[:100], color='C0', width=w, align="center")

xlabels = df.date[:100].apply(lambda x:x.strftime('%H:%M:%S')).tolist()
xdays = df.date[:100].apply(lambda x:x.strftime('%d-%b')).tolist()
ax.set_xticklabels(xlabels, rotation=90)

graph_pos = plt.gca().get_position()
points = np.arange(12, len(xlabels), 24)
day_points = np.arange(0, len(xlabels), 24)
offset = 50.0
trans = ax.get_xaxis_transform()
for i,d in enumerate(xdays):
    if i in points:
        ax.text(i, graph_pos.y0 - offset, d, ha='center')
    if i in day_points:
        ax.plot([i, i], [0, -0.3], color='gray', transform=trans, clip_on=False)
ax.set_xlim(-1, len(xlabels))
plt.show()

enter image description here