Вот подход, который должен дать вам то, что вы ищете.
import datetime as dt
import matplotlib.pyplot as plt
import numpy as np
Вручную создайте время, которое мы хотим построить.В вашем наборе данных указанное время соответствует концу предыдущего бара.Чтобы учесть случаи, когда бар проходит более полуночи, может быть легче, чтобы время соответствовало началу бара.В приведенном ниже коде я изменил ваш исходный набор данных, чтобы использовать этот подход.В первый раз в списке будет первый раз, указанный на оси X графика.
times = [dt.time(0,30,0),
dt.time(6,0,0),
dt.time(7,0,0),
dt.time(9,10,0),
dt.time(15,30,0),
dt.time(18,0,0),
dt.time(19,0,0)]
Вместо того, чтобы наносить dt.time()
на оси X, может быть проще построить графикколичество секунд, прошедших за день.Ниже мы используем понимание списка, чтобы преобразовать times
в число прошедших секунд.
seconds = [(x.hour * 3600 + x.minute * 60 + x.second)
for x in times]
Примечание: я удалил NaN
в начале values
и добавил вымышленный 5.5
до конца, чтобы можно было увидеть пример бара, идущего с 19:00 до 0:30.
# manually add the y-axis values
values = [13.5,
25.5,
50.5,
55.5,
20.5,
38.5,
5.5]
Теперь мы создадим два списка, которые будут использоваться, чтобы указать, где на оси x находитсяТики должны быть размещены, и какой ярлык назначить каждому из этих тиков.Если количество прошедших секунд делится на 1800 (30 минут), это число будет использоваться в качестве одного из тиков.start_time
будет количеством секунд, прошедших для первого элемента в times
.Это где начнется ось X.
start_time = (times[0].hour * 3600 + times[0].minute * 60 + times[0].second)
xticks = [x + start_time for x in range(60 * 60 * 24) if x % 1800 == 0]
Чтобы отобразить время, а не количество прошедших секунд, мы должны использовать dt.timedelta()
для преобразования целого числа в dt.time
.Если значение start_time
больше 0
, то будет xticks
со значениями не менее 86400
.Мы должны вычесть 86400
из этих значений, чтобы xticklabels
не выглядел как one day, 0:30
.
def label_format(seconds):
if seconds >= 86400:
seconds -= 86400
return str(dt.timedelta(seconds=seconds))
xticklabels = [label_format(x) for x in xticks]
Теперь мы можем создать график.Поскольку мы создаем диаграмму стиля гистограммы с неравной шириной полосы, нам нужен способ указать ширину полосы.bar_traits()
может использоваться для определения начальной точки и ширины полосы на основе начальной точки оси x и начальной точки следующего бара.
def bar_traits(ix, second, seconds, start_time):
if ix < len(seconds) - 1:
if seconds[ix + 1] < second:
width = 86400 + seconds[ix + 1] - second
else:
width = seconds[ix + 1] - second
else:
if start_time < second:
width = 86400 + start_time - second
else:
width = start_time - second
if start_time > second:
second += 86400
return second, width
Код для создания графика с использованиемbar_traits()
для обработки графиков в полночь.
fig, ax = plt.subplots(figsize=(16,8))
for ix, (second, value) in enumerate(zip(seconds, values)):
second, width = bar_traits(ix, second, seconds, start_time)
ax.bar(second, value, width=width, align='edge', color='C0')
ax.set_xticks(xticks)
ax.set_xticklabels(xticklabels, rotation=90)
plt.show()