Быстрый в изучении - мощный в программировании
>> Telegram ЧАТ для Python Программистов

Свободное общение и помощь советом и решением проблем с кодом! Заходите в наш TELEGRAM ЧАТ!

>> Python Форум Помощи!

Мы создали форум где отвечаем на все вопросы связанные с языком программирования Python. Ждем вас там!

>> Python Канал в Telegram

Обучающие статьи, видео и новости из мира Python. Подпишитесь на наш TELEGRAM КАНАЛ!

Строим «график счастья» на Python

Строим «график счастья» на Python

Зима – это очень красивое время года. Однако многие из нас замечают, что в эту пору уходить на работу приходится, когда еще темно, а приходить домой, когда уже темно. Поэтому, в этой статье мы попытаемся визуализировать данные о восходе-заходе солнца и соотнести их с привычным для большинства людей режимом дня (работа и бодрствование). Работу мы будем выполнять на Python (pandas + matplotib). Посмотрим, что получится.

Вообще, это скорее просто из интереса, чем необходимости, на самом деле на Python можно делать куда более серьезные вещи, например развернуть полноценный callcenter для компании. Хотя, для колл-центров лучше использовать готовые программные решения, это эффективнее и надежные. Современные сервисы позволяют организовать работу контакт-центров с 3-300 операторами, чего будет достаточно практически для любого бизнеса.

Итак, сначала мы должны подготовить данные, которые будем визуализировать. В интернете есть уже готовые наборы, а при желании можно собрать и свой. По сути, нам нужны таблицы, в которых собраны сведения о дате, восходе и заходе солнца, продолжительности светового дня, зените. Также нужны данные о астрономических, навигационных и гражданских сумерках.

Чтобы было удобнее создадим папку для проекта /sumerki, в которой папку /input, а также скрипт sumerki.py. А в папке input нам нужно разместить файлики 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()

В результате имеем наш график. Таким образом можно сделать графики для различных городов, и на основе этого определить, какой город будет наиболее приемлемым в плане восхода-захода солнца лично для вас.