Как построить график времени ночью с осью в диапазоне от 20 (8 вечера) до 12 (утра) python

#python #pandas #dataframe #datetime #matplotlib

Вопрос:

Я пытаюсь определить время дня, когда я ложился спать каждый день.

Мне было интересно, существует ли элегантное решение, чтобы моя ось y (время суток) менялась с 20 ч (или 10 вечера) до 12 ч или (12 вечера)

По сути, мои галочки были бы [20, 21, 22, 23, 00, 01, 02, …, 09, 10, 11, 12]

Вот часть моей базы данных :

Дата Начать Конец
2019-09-21 23:26:01 05:40:01
2019-09-22 22:45:42 05:58:04
2019-09-23 22:56:40 05:55:23
2019-09-24 22:35:47 06:05:07
2019-09-25 00:23:13 06:03:08

Вот что я хотел бы сделать :

введите описание изображения здесь

И вот что я попробовал :

 import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import dates as mdates

data = pd.read_csv("sleepdata.csv", sep=";")

plt.plot(mdates.date2num(data.Date), mdates.datestr2num(data.Start))
 

Выход

Ответ №1:

Я полагаю, у вас есть данные, хранящиеся в csv файле, который можно прочитать с помощью pandas:

 df = pd.read_csv(r'data/data.csv')
 
          Date     Start       End
0  2019-09-21  23:26:01  05:40:01
1  2019-09-22  22:45:42  05:58:04
2  2019-09-23  22:56:40  05:55:23
3  2019-09-24  22:35:47  06:05:07
4  2019-09-25  00:23:13  06:03:08
 

Прежде всего, вы должны внести некоторые изменения в фрейм данных.
По оси y вам нужно время из двух разных дней: вечера того дня, когда вы начинаете спать, и утра следующего дня. Однако 'Start' 'End' столбцы и не содержат информации о дате, только время.
Кроме того, вы хотите построить график времени в разные дни. Итак, если я выведу дату из 'Date' столбца, по оси y у вас будут данные от 2019-09-21 20:00:00 до 2019-09-25 12:00:00 (или последняя дата в ваших данных), и вы не сможете сравнивать только время, потому что каждое время относится к другому дню. Таким образом, вы должны назначить свидание 'Start' и 'End' столбцы, и вы должны выбрать всегда одну и ту же дату, чтобы иметь возможность сравнивать только время, независимо от даты. Это причина, по которой я вменяю даты 2000-01-01 или 2000-01-02 в 'Start' и 'End' столбцы через start и end функции.
Затем вам нужно преобразовать 'Date' тип столбца из str в datetime .
На данный момент у вас есть этот фрейм данных:

         Date               Start                 End
0 2019-09-21 2000-01-01 23:26:01 2000-01-02 05:40:01
1 2019-09-22 2000-01-01 22:45:42 2000-01-02 05:58:04
2 2019-09-23 2000-01-01 22:56:40 2000-01-02 05:55:23
3 2019-09-24 2000-01-01 22:35:47 2000-01-02 06:05:07
4 2019-09-25 2000-01-02 00:23:13 2000-01-02 06:03:08
 

Обратите внимание на дату 'Start' и 'End' столбцы: если 'Start' час позже полудня, значит, вы легли спать 1-го числа , вкл 2000-01-01 ., в противном случае на следующий день, вкл 2000-01-02 . В любом случае вы всегда просыпаетесь на 2-й день, вкл 2000-01-02 .
Теперь вы можете строить кадр данных изо дня в день. Я использую df.iterrows цикл, который не самый лучший, я открыт для предложений по улучшению процесса построения графика.
Наконец, вам нужно настроить формат и метки по осям x и y.

Полный Код

 import pandas as pd
import matplotlib.pyplot as plt
from datetime import datetime, timedelta
import matplotlib.dates as md


df = pd.read_csv(r'data/data.csv')


def start(x):
    H, M, S = list(map(int, x['Start'].split(':')))
    Y, m, d = 2000, 1, 1
    if H > 12:
        return datetime(year = Y, month = m, day = d, hour = H, minute = M, second = S)
    else:
        return datetime(year = Y, month = m, day = d, hour = H, minute = M, second = S)   timedelta(days = 1)

def end(x):
    H, M, S = list(map(int, x['End'].split(':')))
    Y, m, d = 2000, 1, 1
    return datetime(year = Y, month = m, day = d, hour = H, minute = M, second = S)   timedelta(days = 1)


df['Start'] = df.apply(start, axis = 1)
df['End'] = df.apply(end, axis = 1)
df['Date'] = pd.to_datetime(df['Date'], format = '%Y-%m-%d')


fig, ax = plt.subplots()

for i, row in df.iterrows():
    ax.plot([row['Date'], row['Date']], [row['Start'], row['End']], linewidth = 10, color = 'blue')

ax.xaxis.set_major_locator(md.DayLocator(interval = 1))
ax.xaxis.set_major_formatter(md.DateFormatter('%Y-%m-%d'))
plt.setp(ax.xaxis.get_majorticklabels(), rotation = 90)


ax.yaxis.set_major_locator(md.HourLocator(interval = 1))
ax.yaxis.set_major_formatter(md.DateFormatter('%H:%M'))
ax.set_ylim(datetime(year = 2000, month = 1, day = 1, hour = 20, minute = 0, second = 0),
            datetime(year = 2000, month = 1, day = 2, hour = 12, minute = 0, second = 0))

plt.show()
 

введите описание изображения здесь