График счастья с python, pandas и matplotlib

от автора

image

Зима — это по истине прекрасное время года. Но именно зимой я всегда задумываюсь о том, что встаю и ухожу на работу, а затем и возвращаюсь с работы, не видя солнечного света. Сегодня мне захотелось визуализировать данные о восходе и заходе солнца и соотнести их со столь привычным для многих распорядком дня (рабочие часы и время бодрствования). Для работы мы будем использовать Python (pandas + matplotlib). Посмотрим, что из этого получилось.

Для начала нам понадобятся данные, которые можно визуализировать. Я нашел подходящий набор здесь. На странице мы видим две таблицы, содержащие данные о дате, восходе и заходе солнца, зените и продолжительности светового дня, а также данные о гражданских, навигационных и астрономических сумерках. Для работы нам понадобится время восхода и захода солнца, информация о гражданских сумерках, и, само собой дата, которую мы сможем представить на таймлайне.

Для удобства создадим папку проекта /sumerki, внутри неё создадим папку /input и скрипт приложения sumerki.py. В папку input мы положим 2 файла sumerki_1.txt и sumerki_2.txt, куда просто скопируем таблицы с сайта. Первые строки таблиц выглядят так:

1 января	09:00:39	12:33:54	16:07:09	07:06:29	+1:16 08:14:08	07:25:39	06:40:27	18:27:20	17:42:09	16:53:40

Данных из внешних источников нам вполне достаточно, теперь осталось обозначить время бодрствования и рабочее время. Не мудрствуя лукаво я решил взять следующие временные интервалы: 07:00:00 — 20:00:00 для бодрствования и 09:00:00 — 18:00:00 рабочий день.

Со структурой всё понятно. Давайте теперь немного кода на Python.

Сначала сделаем все необходимые импорты и осуществим небольшие настройки.

import os import datetime import pandas as pd import matplotlib.pyplot as plt import matplotlib.dates as mdates from matplotlib import rc   # Создадим небольшую служебную функцию для преобразования строкового времени с число def stn(dstr):     return mdates.datestr2num(dstr.tolist())   # Простой рецепт для решения проблемы отображения кириллицы в matplotlib font = {'family': 'Verdana', 'weight': 'normal'} rc('font', **font)  DIR = os.path.dirname('__File__') 

Сформируем данные в pandas (на выходе получим 2 датафрейма, с которыми будем работать — S, W):

# Считаем данные из текстовых файлов и сохраним их в датафрейм с заранее известными столбцами s1 = open(os.path.join(DIR, 'input', 'sumerki_1.txt'), 'r').read().split('\n') s2 = open(os.path.join(DIR, 'input', 'sumerki_2.txt'), 'r').read().split('\n') oday = datetime.datetime.strptime('01.01.2016', '%d.%m.%Y') dates = [oday + datetime.timedelta(days=dt) for dt in range(len(s1))]  # От себя мы добавим столбцы с временем начала и окончания дня (0, 24) s = [[dates[i[0]]] + s1[i[0]].split('\t') + s2[i[0]].split('\t') + ['00:00:01', '23:59:59'] for i in enumerate(s1)] columns = ['datetime', 'date', 'voshod', 'zenit', 'zahod', 'dolgota', 'cng',            'sum1_from', 'sum2_from', 'sum3_from', 'sum3_to', 'sum2_to', 'sum1_to',            '0', '24'] S = pd.DataFrame(s, columns=columns)  # Сформироуем датафрейм, содержащий данные о дне и начале/конце рабочего дня (бодрствования) w = [[dt, '07:00:00', '09:00:00', '18:00:00', '20:00:00'] for dt in dates] columns = ['datetime', 'life_from', 'work_from', 'work_to', 'life_to'] W = pd.DataFrame(w, columns=columns) 

Теперь нам остаётся только отобразить все полученные данные на графике. Для удобства, я постарался подобрать цвета — желтый для светового дня, оранжевый для сумерек, а голубоватый со звёздами для темного времени суток.

# Ну а теперь построим график fig, ax = plt.subplots()  plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m')) plt.gca().xaxis.set_major_locator(mdates.MonthLocator()) plt.gcf().autofmt_xdate()  # Отобразим нужные данные на графике l1, = ax.plot(S['datetime'], stn(S['voshod']), 'r-', label='восход') l2, = ax.plot(S['datetime'], stn(S['zahod']), 'b-', label='заход') l3, = ax.plot(S['datetime'], stn(S['sum1_from']), 'g-', label='сумерки (от)') l4, = ax.plot(S['datetime'], stn(S['sum1_to']), 'm-', label='сумерки (до)') l5, = ax.plot(W['datetime'], stn(W['work_from']), 'k-', label='рабочее время') l6, = ax.plot(S['datetime'], stn(W['work_to']), 'k-', label='рабочее время') l7, = ax.plot(S['datetime'], stn(W['life_from']), 'k-', label='время бодрствования') l8, = ax.plot(S['datetime'], stn(W['life_to']), 'k-', label='время бодрствования')   # Заполним пространство между # Восход-заход plt.fill_between(S['datetime'].tolist(), stn(S['voshod']), stn(S['zahod']), alpha=0.4, color='yellow', hatch='.') # Cумерки plt.fill_between(S['datetime'].tolist(), stn(S['sum1_from']), stn(S['voshod']), alpha=0.4, color='orange', hatch='.') plt.fill_between(S['datetime'].tolist(), stn(S['zahod']), stn(S['sum1_to']), alpha=0.4, color='orange', hatch='.') # Ночь plt.fill_between(S['datetime'].tolist(),  stn(S['0']), stn(S['sum1_from']), alpha=0.4, color='blue', hatch='*') plt.fill_between(S['datetime'].tolist(), stn(S['sum1_to']),  stn(S['24']), alpha=0.4, color='blue', hatch='*') # Рабочее время и время бодрствования plt.fill_between(W['datetime'].tolist(), stn(W['work_from']), stn(W['work_to']), alpha=0.1, color='blue', hatch='/') plt.fill_between(W['datetime'].tolist(), stn(W['life_from']), stn(W['life_to']), alpha=0.1, color='blue', hatch='/')  # Форматирование, заголовок и легенда ax.yaxis_date() ax.xaxis_date() ax.set_xlabel("Дата") ax.set_ylabel("Время") plt.title('График зависимости рабочего времени (времени бодрствования) от светового дня.') plt.legend(handles=[l1, l2, l3, l4, l6, l8], loc=1, fontsize=11) fig.autofmt_xdate()  # Ну и покажем график уже наконец plt.show() 

Спасибо за внимание!

ссылка на оригинал статьи http://habrahabr.ru/post/274927/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *