2021-01-11 07:49:08 -05:00
|
|
|
import re
|
|
|
|
|
|
|
|
from sqlalchemy import func
|
|
|
|
|
|
|
|
from communicator import db, app
|
|
|
|
from communicator.models.sample import Sample
|
|
|
|
import random
|
|
|
|
import logging
|
|
|
|
import datetime as dt
|
2021-01-29 09:40:59 -05:00
|
|
|
from sqlalchemy import func, and_, case, or_
|
|
|
|
from communicator.api.admin import add_sample_search_filters
|
2021-01-11 07:49:08 -05:00
|
|
|
|
|
|
|
def dow_count(start, end):
|
2021-01-29 09:40:59 -05:00
|
|
|
# Sunday, Monday, ...
|
2021-01-11 07:49:08 -05:00
|
|
|
counts = [0 for _ in range(7)]
|
2021-01-11 10:43:36 -05:00
|
|
|
curr = start
|
2021-01-11 07:49:08 -05:00
|
|
|
while curr <= end:
|
2021-01-20 18:54:25 -05:00
|
|
|
counts[curr.weekday()] += 1
|
2021-01-11 10:43:36 -05:00
|
|
|
curr += dt.timedelta(1)
|
2021-01-11 07:49:08 -05:00
|
|
|
return counts
|
|
|
|
|
2021-01-11 10:43:36 -05:00
|
|
|
|
2021-01-11 07:49:08 -05:00
|
|
|
def date2datetime(_date):
|
|
|
|
return dt.datetime.combine(_date, dt.datetime.min.time())
|
|
|
|
|
2021-01-11 10:43:36 -05:00
|
|
|
|
|
|
|
def daterange(start, stop, days=1, hours=0):
|
2021-01-11 07:49:08 -05:00
|
|
|
if (type(start) == dt.date):
|
|
|
|
start = date2datetime(start)
|
|
|
|
if (type(stop) == dt.date):
|
|
|
|
stop = date2datetime(stop)
|
|
|
|
time = start
|
|
|
|
date_list = []
|
|
|
|
while time <= stop:
|
|
|
|
date_list.append(time)
|
2021-01-11 10:43:36 -05:00
|
|
|
time += dt.timedelta(days=days, hours=hours)
|
2021-01-11 07:49:08 -05:00
|
|
|
return date_list
|
|
|
|
|
2021-01-11 10:43:36 -05:00
|
|
|
|
2021-01-11 07:49:08 -05:00
|
|
|
class GraphService(object):
|
|
|
|
def __init__(self):
|
|
|
|
self.filters = dict()
|
|
|
|
self.filters["start_date"] = Sample.date >= dt.date.today()
|
2021-01-11 08:03:45 -05:00
|
|
|
self.start_date = dt.date.today()
|
2021-01-11 10:43:36 -05:00
|
|
|
self.filters["end_date"] = Sample.date <= dt.date.today() + \
|
|
|
|
dt.timedelta(1)
|
2021-01-11 07:49:08 -05:00
|
|
|
self.end_date = dt.date.today() + dt.timedelta(1)
|
|
|
|
|
|
|
|
def get_totals_by_hour(self):
|
|
|
|
hourly_charts_data = dict()
|
2021-01-11 08:03:45 -05:00
|
|
|
days_in_search = (self.end_date - self.start_date).days
|
2021-01-11 10:43:36 -05:00
|
|
|
|
|
|
|
cases = []
|
2021-01-11 07:49:08 -05:00
|
|
|
for i in range(24):
|
2021-01-11 10:43:36 -05:00
|
|
|
cases.append(func.count(
|
|
|
|
case([(func.extract('hour', Sample.date) == i, 1)])))
|
|
|
|
|
2021-01-11 07:49:08 -05:00
|
|
|
q = db.session.query(Sample.location, Sample.station,
|
2021-01-11 10:43:36 -05:00
|
|
|
*cases
|
|
|
|
).group_by(Sample.location, Sample.station)
|
2021-01-11 07:49:08 -05:00
|
|
|
|
2021-01-29 09:40:59 -05:00
|
|
|
q = add_sample_search_filters(q, self.filters)
|
2021-01-11 07:49:08 -05:00
|
|
|
for result in q:
|
|
|
|
location, station = result[0], result[1]
|
2021-01-11 10:43:36 -05:00
|
|
|
if location not in hourly_charts_data:
|
|
|
|
hourly_charts_data[location] = dict()
|
|
|
|
# Here I'm accounting for the difference in UTC and GMT time zones
|
|
|
|
# by moving the five results from the start to the end.
|
|
|
|
offset = 6
|
2021-01-11 07:49:08 -05:00
|
|
|
counts = result[2:]
|
|
|
|
counts = counts[offset:] + counts[:offset]
|
2021-01-11 10:43:36 -05:00
|
|
|
hourly_charts_data[location][station] = [
|
|
|
|
round(i/days_in_search + .4) for i in counts]
|
2021-01-11 08:03:45 -05:00
|
|
|
return hourly_charts_data
|
2021-01-11 10:43:36 -05:00
|
|
|
|
2021-01-11 07:49:08 -05:00
|
|
|
def get_totals_by_day(self):
|
2021-01-11 08:03:45 -05:00
|
|
|
daily_charts_data = dict()
|
2021-01-11 07:49:08 -05:00
|
|
|
bounds = daterange(self.start_date, self.end_date, days=1, hours=0)
|
2021-01-11 10:43:36 -05:00
|
|
|
cases = []
|
2021-01-11 07:49:08 -05:00
|
|
|
for i in range(len(bounds) - 1):
|
2021-01-11 10:43:36 -05:00
|
|
|
cases.append(func.count(
|
|
|
|
case([(and_(Sample.date >= bounds[i], Sample.date <= bounds[i+1]), 1)])))
|
|
|
|
|
2021-01-11 07:49:08 -05:00
|
|
|
q = db.session.query(Sample.location, Sample.station,
|
2021-01-11 10:43:36 -05:00
|
|
|
*cases
|
|
|
|
).group_by(Sample.location, Sample.station)
|
2021-01-29 09:40:59 -05:00
|
|
|
|
|
|
|
q = add_sample_search_filters(q, self.filters)
|
2021-01-11 08:03:45 -05:00
|
|
|
|
2021-01-11 07:49:08 -05:00
|
|
|
for result in q:
|
|
|
|
location, station = result[0], result[1]
|
2021-01-11 10:43:36 -05:00
|
|
|
if location not in daily_charts_data:
|
|
|
|
daily_charts_data[location] = dict()
|
2021-01-11 07:49:08 -05:00
|
|
|
daily_charts_data[location][station] = result[2:]
|
2021-01-11 10:43:36 -05:00
|
|
|
|
2021-01-11 07:49:08 -05:00
|
|
|
return daily_charts_data
|
2021-01-11 10:43:36 -05:00
|
|
|
|
2021-01-11 07:49:08 -05:00
|
|
|
def get_totals_by_weekday(self):
|
|
|
|
weekday_charts_data = dict()
|
2021-01-11 10:43:36 -05:00
|
|
|
dow_counts = dow_count(
|
|
|
|
self.start_date, self.end_date - dt.timedelta(1))
|
|
|
|
cases = []
|
2021-01-11 07:49:08 -05:00
|
|
|
for i in range(7):
|
2021-01-11 10:43:36 -05:00
|
|
|
cases.append(func.count(
|
2021-01-26 20:30:22 -05:00
|
|
|
case([(func.extract('isodow', Sample.date) == i + 1, 1)])))
|
2021-01-11 10:43:36 -05:00
|
|
|
|
2021-01-11 07:49:08 -05:00
|
|
|
q = db.session.query(Sample.location, Sample.station,
|
2021-01-11 10:43:36 -05:00
|
|
|
*cases
|
|
|
|
).group_by(Sample.location, Sample.station)
|
2021-01-29 09:40:59 -05:00
|
|
|
q = add_sample_search_filters(q, self.filters)
|
2021-01-11 07:49:08 -05:00
|
|
|
for result in q:
|
2021-01-13 17:03:50 -05:00
|
|
|
location, station = result[0], result[1]
|
2021-01-11 10:43:36 -05:00
|
|
|
if location not in weekday_charts_data:
|
|
|
|
weekday_charts_data[location] = dict()
|
2021-01-11 07:49:08 -05:00
|
|
|
weekday_charts_data[location][station] = []
|
2021-01-11 10:43:36 -05:00
|
|
|
for dow, total in zip(range(7), result[2:]):
|
2021-01-11 07:49:08 -05:00
|
|
|
if dow_counts[dow] > 0:
|
2021-01-11 10:43:36 -05:00
|
|
|
weekday_charts_data[location][station].append(
|
|
|
|
round(total/dow_counts[dow] + .4))
|
2021-01-11 07:49:08 -05:00
|
|
|
else:
|
|
|
|
weekday_charts_data[location][station].append(total)
|
|
|
|
return weekday_charts_data
|
2021-01-11 10:43:36 -05:00
|
|
|
|
2021-01-11 07:49:08 -05:00
|
|
|
def update_search_filters(self, filters):
|
2021-01-29 09:40:59 -05:00
|
|
|
self.filters = filters
|
|
|
|
if "start_date" in filters:
|
|
|
|
self.start_date = filters["start_date"]
|
|
|
|
if "end_date" in filters:
|
|
|
|
self.end_date = filters["end_date"] + dt.timedelta(1)
|
|
|
|
|
|
|
|
|