aqi_monitor/backend/flask/app/graph_pm.py

188 lines
5.3 KiB
Python

""" creates the PM 2.5 and pm 10 graphs """
from datetime import datetime
from matplotlib import pyplot as plt
import numpy as np
import pandas as pd
from app.db_connect import db_connect, db_close
def color_colums(y):
""" helper function to color bar columns """
col = []
for val in y:
if val <= 50:
# good
col.append('#85a762')
elif val > 50 and val <= 100:
# moderate
col.append('#d4b93c')
elif val > 100 and val <= 150:
# ufsg
col.append('#e96843')
elif val > 150 and val <= 200:
# unhealthy
col.append('#d03f3b')
elif val > 200 and val <= 300:
# vunhealthy
col.append('#be4173')
else:
# hazardous
col.append('#714261')
return col
def get_pm_data(config):
""" gets last 10 days worth of data"""
now = datetime.now()
day_until = int(now.date().strftime('%s'))
day_from = day_until - 10 * 24 * 60 * 60
conn, cur = db_connect(config)
cur.execute(
f'SELECT epoch_time, pm25, pm10 FROM aqi \
WHERE epoch_time > {day_from} \
AND epoch_time < {day_until} \
ORDER BY epoch_time DESC;'
)
rows = cur.fetchall()
db_close(conn, cur)
return rows
def get_pm_axis(rows):
""" build axis """
# build dataframe
x_timeline = [datetime.fromtimestamp(i[0]) for i in rows]
y_pm25_values = [int(i[1]) for i in rows]
y_pm10_values = [int(i[2]) for i in rows]
data = {
'timestamp': x_timeline,
'pm25': y_pm25_values,
'pm10': y_pm10_values
}
df = pd.DataFrame(data)
indexed = df.set_index('timestamp')
indexed.sort_values(by=['timestamp'], inplace=True, ascending=True)
mean = indexed.resample('1d').mean()
mean.reset_index(level=0, inplace=True)
# axis
mean['pm25'] = mean['pm25'].round()
mean['pm10'] = mean['pm10'].round()
x = mean['timestamp']
y_1 = mean['pm25']
y_2 = mean['pm10']
return x, y_1, y_2
def build_pm_plot(x, y, y_max, thresh, title):
""" write plots to file """
file_name = title.replace('.', '')
# make ticks
x_range = np.arange(10).tolist()
x_date_time = pd.to_datetime(x).dt.date.unique()
x_dates = [i.strftime('%d %b') for i in x_date_time]
# color
col = []
for val in y:
if val < thresh:
col.append('#6ecd65')
else:
col.append('#ff4d4d')
# title
plt_title = f'Daily avg PM {title} exposure'
# plot
plt.style.use('seaborn')
plt.bar(x_dates, y, color=col, width=0.5)
plt.axhline(y=thresh, color='#6ecd65', linestyle=':')
plt.xticks(ticks=x_range, labels=x_dates)
plt.yticks(np.arange(0, y_max, step=25))
plt.title(plt_title, fontsize=20)
plt.tight_layout()
plt.savefig(f'dyn/pm{file_name}.png', dpi=300)
plt.close('all')
plt.figure()
def rebuild_pm_bar(config):
""" main function to rebuild pm2.5 and pm10 values """
# get data
rows = get_pm_data(config)
x, y_1, y_2 = get_pm_axis(rows)
# max
y_max = np.ceil(max(y_1.append(y_2))/25)*25 + 25
# pm 2.5
build_pm_plot(x, y_1, y_max, thresh=25, title='2.5')
# pm 10
build_pm_plot(x, y_2, y_max, thresh=50, title='10')
# done
print('recreated PM 2.5 and PM 10 graphs')
# hour bar chart
def get_hour_data(config):
""" get last three days worth of data from postgres """
# time
now = datetime.now()
day_until = int(now.date().strftime('%s'))
day_from = day_until - 3 * 24 * 60 * 60
# call db
conn, cur = db_connect(config)
cur.execute(
f'SELECT epoch_time, aqi_value FROM aqi \
WHERE epoch_time > {day_from} \
AND epoch_time < {day_until} \
ORDER BY epoch_time DESC;'
)
rows = cur.fetchall()
db_close(conn, cur)
return rows
def get_hour_axis(rows):
""" build x and y from the rows """
x_timeline = [datetime.fromtimestamp(i[0]) for i in rows]
y_aqi_values = [int(i[1]) for i in rows]
# build dataframe
data = {'timestamp': x_timeline, 'aqi': y_aqi_values}
df = pd.DataFrame(data)
indexed = df.set_index('timestamp')
indexed.sort_values(by=['timestamp'], inplace=True)
mean = indexed.resample('1h').mean()
# regroup by hour
mean_hour = mean.groupby([mean.index.hour]).mean()
mean_hour.reset_index(level=0, inplace=True)
# set axis
x = mean_hour['timestamp']
y = mean_hour['aqi'].round()
return x, y
def build_hour_plot(x, y):
""" takes x and y and writes plot to file """
plt_title = 'Last three days average AQI for each hour'
# ticks
x_range = np.arange(0, 24, step=3)
x_hours = [str(i).zfill(2) + ":00" for i in x_range]
y_max = np.ceil(max(y)/50) * 50 + 50
# color columns
col = color_colums(y)
# create plot
plt.style.use('seaborn')
plt.bar(x, y, color=col, width=0.5)
plt.yticks(np.arange(0, y_max, step=50))
plt.xticks(ticks=x_range, labels=x_hours)
plt.title(plt_title, fontsize=20)
plt.tight_layout()
plt.savefig('dyn/hours.png', dpi=300)
plt.close('all')
plt.figure()
def rebuild_hour_bar(config):
""" main function to rebuild houly bar avg """
rows = get_hour_data(config)
x, y = get_hour_axis(rows)
build_hour_plot(x, y)