【问题标题】:Re-order x-axis for timestamps after midnight - Matplotlib为午夜后的时间戳重新排序 x 轴 - Matplotlib
【发布时间】:2019-07-24 20:00:23
【问题描述】:

我正在尝试 plot 来自 pandas df 的一系列值。这些值取自Columns,它显示了在任何时间点出现的值的总数。

我的尝试如下。我遇到的问题是x-axis 的格式不正确,因为值超过了午夜。与午夜之后的时间戳相关的值是plotted first 而不是 last。 (请看下图)

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from scipy.interpolate import griddata

d = ({
    'Time1' : ['8:00:00','10:30:00','12:40:00','16:25:00','22:30:00','1:31:00','2:15:00','2:20:00','2:30:00'],
    'Occurring1' : ['1','2','3','4','5','4','3','2','1'],
    'Time2' : ['8:10:00','10:10:00','13:40:00','16:05:00','21:30:00','1:11:00','3:00:00','3:01:00','6:00:00'],
    'Occurring2' : ['1','2','3','4','5','4','3','2','0'],
    'Time3' : ['8:05:00','11:30:00','15:40:00','17:25:00','23:30:00','1:01:00','6:00:00','6:00:00','6:00:00'],
    'Occurring3' : ['1','2','2','3','2','1','0','0','0'],
    'Time4' : ['9:50:00','10:30:00','14:40:00','18:25:00','20:30:00','0:31:00','2:35:00','6:00:00','6:00:00'],
    'Occurring4' : ['1','2','3','4','4','3','2','0','0'],
    'Time5' : ['9:00:00','11:30:00','13:40:00','17:25:00','00:30:00','2:31:00','6:00:00','6:00:00','6:00:00'],
    'Occurring5' : ['1','2','3','3','2','1','0','0','0'],                   
     })

df = pd.DataFrame(data=d)

df = df.astype({
    "Time1": np.datetime64,
    "Occurring1": np.int,
    "Time2": np.datetime64,
    "Occurring2": np.int,
    "Time3": np.datetime64,
    "Occurring3": np.int,
    "Time4": np.datetime64,
    "Occurring4": np.int,
    "Time5": np.datetime64,
    "Occurring5": np.int,    
})

all_times = df[["Time1", "Time2", "Time3",'Time4','Time5']].values

t_min = np.timedelta64(int(60*1e9), "ns")

time_grid = np.arange(all_times.min(), all_times.max(), 10*t_min, dtype="datetime64")
X = pd.Series(time_grid).dt.time.values
occurrences_grid = np.zeros((5, len(time_grid)))

for i in range(5):
    occurrences_grid[i] = griddata(
        points=df["Time%i" % (i+1)].values.astype("float"),
        values=df["Occurring%i" % (i+1)],
        xi=time_grid.astype("float"),
        method="linear"
    )

occ_min = np.min(occurrences_grid, axis=0)
occ_max = np.max(occurrences_grid, axis=0)
occ_mean = np.mean(occurrences_grid, axis=0)

plt.style.use('ggplot')
plt.fill_between(X, occ_min, occ_max, color="blue")
plt.plot(X, occ_mean, c="white")
plt.tight_layout()
plt.show()

输出:

【问题讨论】:

  • 如果这些时间表示两个不同日子的时刻,他们应该随身携带一个日期。
  • @ImportanceOfBeingErnest,我只想plot timestamps。没有date 有可能吗?
  • 那么如果您不指定各个时间的日期,您如何想象轴知道02:00 应该在10:30 之后?这就是我已经表达的第一条评论,所以我猜你想实现它,然后可能会询问你在这样做时遇到的任何问题。
  • 我不期望它知道。我正在考虑用日期时间绘制它,以便正确格式化轴,然后考虑使用 xticks。你认为反对票真的有必要吗?
  • 我没有投反对票,所以我无法对此发表评论。但我的直觉是,如果你应用第一条评论并在问题中说明为什么这没有帮助,人们会更好地理解问题的要求,因此不会投反对票。

标签: python pandas datetime matplotlib plot


【解决方案1】:

df = df.astype({
    "Time1": np.datetime64,
    "Occurring1": np.int})

每个时间标记都有相同的日期(2019-03-05 只是今天的日期)。 all_times 的所有元素也具有相同的日期。从这里你可以使用time_grid = np.arange(all_times.min(), all_times.max(), 10*t_min, dtype="datetime64")“得到错误的曲线”。

有两种策略可以规避这个问题:

策略 A

如果您对看到的数据感到满意,但只是因为午夜后的数据不存在而感到不满意,那么您可以移动/滚动数据。这种方法不会改变您提取数据以绘制图形的方式。我插入了以下步骤:

  1. Time_i 确定最早的时间标记(= 时间序列应该开始的时间)。这是t_start
  2. 找出time_grid t_start 的索引。这给了index
  3. 就在绘制移位/滚动数组之前。但是,如果您也滚动 X,它将无法正常工作!所以使用 X 的替代时间轴
  4. 未显示:使用 matplotlib 替换 x 轴的标签 (Example here)

这给出了(代码如下)

策略 B

由于没有日期的时间标记是周期性的,因此您遇到了您提到的问题。对于插值,时间轴应该单调增加。所以方法是:当使用scipy.interpolate.griddata(points, values, xi) 进行插值时,使用单调增加的pointsx1 代理项。为此,您必须调整您确定的程序occurrences_grid

这里是策略 A 的代码。

d = ({
    'Time1' : ['8:00:00','10:30:00','12:40:00','16:25:00','22:30:00','1:31:00','2:15:00','2:20:00','2:30:00'],
    'Occurring1' : ['1','2','3','4','5','4','3','2','1'],
    'Time2' : ['8:10:00','10:10:00','13:40:00','16:05:00','21:30:00','1:11:00','3:00:00','3:01:00','6:00:00'],
    'Occurring2' : ['1','2','3','4','5','4','3','2','0'],
    'Time3' : ['8:05:00','11:30:00','15:40:00','17:25:00','23:30:00','1:01:00','6:00:00','6:00:00','6:00:00'],
    'Occurring3' : ['1','2','2','3','2','1','0','0','0'],
    'Time4' : ['9:50:00','10:30:00','14:40:00','18:25:00','20:30:00','0:31:00','2:35:00','6:00:00','6:00:00'],
    'Occurring4' : ['1','2','3','4','4','3','2','0','0'],
    'Time5' : ['9:00:00','11:30:00','13:40:00','17:25:00','00:30:00','2:31:00','6:00:00','6:00:00','6:00:00'],
    'Occurring5' : ['1','2','3','3','2','1','0','0','0'],                   
     })

df = pd.DataFrame(data=d)

df = df.astype({
    "Time1": np.datetime64,
    "Occurring1": np.int,
    "Time2": np.datetime64,
    "Occurring2": np.int,
    "Time3": np.datetime64,
    "Occurring3": np.int,
    "Time4": np.datetime64,
    "Occurring4": np.int,
    "Time5": np.datetime64,
    "Occurring5": np.int,    
})

all_times = df[["Time1", "Time2", "Time3",'Time4','Time5']].values
t_start = min(df["Time1"].iloc[0], df["Time2"].iloc[0], df["Time3"].iloc[0], 
              df["Time4"].iloc[0], df["Time5"].iloc[0])                                  # new: t_start
t_start = np.datetime64(t_start)                                                         # conversion pandas/numpy
t_min = np.timedelta64(int(60*1e9), "ns")
time_grid = np.arange(all_times.min(), all_times.max(), 10*t_min, dtype="datetime64")
index = np.argmax(time_grid>=t_start)                                                    # new: index to start the graphics
print('index');print(index,time_grid[index])
X = pd.Series(time_grid).dt.time.values
occurrences_grid = np.zeros((5, len(time_grid)))

for i in range(5):
    occurrences_grid[i] = griddata(
        points=df["Time%i" % (i+1)].values.astype("float"),
        values=df["Occurring%i" % (i+1)],
        xi=time_grid.astype("float"),
        method="linear"
    )

occ_min = np.min(occurrences_grid, axis=0)
occ_max = np.max(occurrences_grid, axis=0)
occ_mean = np.mean(occurrences_grid, axis=0)

def roll(X,occ_min,occ_max,occ_mean):                                                   # new: shift/roll the values
    return np.arange(len(X)), np.roll(occ_min,-index), np.roll(occ_max,-index), np.roll(occ_mean,-index)
                                                                                       # do not shift X but use a surrogate time axis

X,occ_min,occ_max,occ_mean = roll(X,occ_min,occ_max,occ_mean) 

fig, ax0 = plt.subplots(figsize=(9,4))
plt.style.use('ggplot')
plt.fill_between(X, occ_min, occ_max, color="blue")
plt.plot(X, occ_mean, c="white")
plt.tight_layout()
plt.show()
fig.savefig('plot_model_2.png', transparency=True) 

【讨论】:

  • 添加:由于 Time_ialle_times 包含日期,因此策略 B 最简单的方法可能是:(i) 使用日期进行插值,(ii) 删除日期只是为了最终的绘图。
猜你喜欢
  • 2012-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-19
相关资源
最近更新 更多