Kumi
c7295829fc
Standardized the parameter name for setting chart height across all chart creation functions in statistics.py. Replaced `plot_height` with `height` to align with the latest visualization library conventions. This change enhances code consistency and adheres to the updated library API, ensuring future compatibility and easier maintenance.
268 lines
No EOL
9.3 KiB
Python
268 lines
No EOL
9.3 KiB
Python
import holoviews as hv
|
|
import pandas as pd
|
|
|
|
from django.utils import timezone
|
|
|
|
from math import pi
|
|
|
|
from bokeh.models import HoverTool
|
|
from bokeh.io import output_file, show
|
|
from bokeh.plotting import figure
|
|
from bokeh.transform import cumsum
|
|
from bokeh.layouts import row, column
|
|
from holoviews.operation import timeseries
|
|
from dateutil.relativedelta import relativedelta
|
|
|
|
from .models import Status, Mood, StatusActivity
|
|
|
|
def moodstats(user):
|
|
hv.extension('bokeh')
|
|
|
|
tooltips = [
|
|
('Date', '@date{%F %H:%M}'),
|
|
('Mood', '@name (@value)')
|
|
]
|
|
|
|
formatters = {
|
|
'@date': 'datetime'
|
|
}
|
|
|
|
hover = HoverTool(tooltips=tooltips, formatters=formatters)
|
|
|
|
pointdict = {"date": [], "value": [], "color": [], "name": []}
|
|
|
|
|
|
for status in Status.objects.filter(user=user):
|
|
if status.mood:
|
|
pointdict["date"].append(status.timestamp)
|
|
pointdict["value"].append(status.mood.value)
|
|
pointdict["color"].append(status.mood.color)
|
|
pointdict["name"].append(status.mood.name)
|
|
|
|
pointframe = pd.DataFrame.from_dict(pointdict)
|
|
|
|
points = hv.Points(pointframe)
|
|
|
|
points.opts(
|
|
tools=[hover], color='color', cmap='Category20',
|
|
line_color='black', size=25,
|
|
width=600, height=400, show_grid=True)
|
|
|
|
pointtuples = [(pointdict["date"][i], pointdict["value"][i]) for i in range(len(pointdict["date"]))]
|
|
|
|
line = hv.Curve(pointtuples)
|
|
|
|
maxval = Mood.objects.filter(user=user).latest("value").value
|
|
maxy = maxval + max(maxval * 0.1, 1)
|
|
|
|
maxx = timezone.now().timestamp() * 1000
|
|
minx = maxx - (60*60*24*7) * 1000
|
|
|
|
output = points * line * timeseries.rolling(line, rolling_window=7)
|
|
output.opts(ylim=(0, maxy), xlim=(minx, maxx))
|
|
|
|
return output
|
|
|
|
def activitystats(user):
|
|
output = {}
|
|
|
|
for status in Status.objects.filter(user=user):
|
|
for activity in status.activity_set:
|
|
if not activity in output.keys():
|
|
output[activity] = {
|
|
"alltime": 0,
|
|
"yearly": 0,
|
|
"monthly": 0,
|
|
"weekly": 0
|
|
}
|
|
|
|
output[activity]["alltime"] += 1
|
|
|
|
if status.timestamp > timezone.now() - relativedelta(years=1):
|
|
output[activity]["yearly"] += 1
|
|
|
|
if status.timestamp > timezone.now() - relativedelta(months=1):
|
|
output[activity]["monthly"] += 1
|
|
|
|
if status.timestamp > timezone.now() - relativedelta(weeks=1):
|
|
output[activity]["weekly"] += 1
|
|
|
|
return output
|
|
|
|
def moodpies(user):
|
|
hv.extension('bokeh')
|
|
|
|
maxdate = timezone.now()
|
|
|
|
weekly_moods = Status.objects.filter(user=user, timestamp__lte=maxdate, timestamp__gte=maxdate - relativedelta(weeks=1))
|
|
monthly_moods = Status.objects.filter(user=user, timestamp__lte=maxdate, timestamp__gte=maxdate - relativedelta(months=1))
|
|
yearly_moods = Status.objects.filter(user=user, timestamp__lte=maxdate, timestamp__gte=maxdate - relativedelta(years=1))
|
|
|
|
weekly = dict()
|
|
colors = []
|
|
|
|
for mood in Mood.objects.filter(user=user):
|
|
weekly[mood.name] = 0
|
|
colors.append(mood.color)
|
|
|
|
monthly, yearly = weekly.copy(), weekly.copy()
|
|
|
|
for status in weekly_moods:
|
|
if status.mood:
|
|
weekly[status.mood.name] += 1
|
|
|
|
for status in monthly_moods:
|
|
if status.mood:
|
|
monthly[status.mood.name] += 1
|
|
|
|
for status in yearly_moods:
|
|
if status.mood:
|
|
yearly[status.mood.name] += 1
|
|
|
|
weekly_data = pd.Series(weekly).reset_index(name='value').rename(columns={'index':'mood'})
|
|
weekly_data['angle'] = weekly_data['value']/weekly_data['value'].sum() * 2*pi
|
|
weekly_data['color'] = colors
|
|
|
|
weekly_chart = figure(height=350, title="Weekly", toolbar_location=None,
|
|
tools="hover", tooltips="@mood: @value")
|
|
weekly_chart.axis.visible = False
|
|
|
|
weekly_chart.wedge(x=0, y=1, radius=0.4,
|
|
start_angle=cumsum('angle', include_zero=True), end_angle=cumsum('angle'),
|
|
line_color="white", fill_color='color', legend='mood', source=weekly_data)
|
|
|
|
monthly_data = pd.Series(monthly).reset_index(name='value').rename(columns={'index':'mood'})
|
|
monthly_data['angle'] = monthly_data['value']/monthly_data['value'].sum() * 2*pi
|
|
monthly_data['color'] = colors
|
|
|
|
monthly_chart = figure(height=350, title="Monthly", toolbar_location=None,
|
|
tools="hover", tooltips="@mood: @value")
|
|
monthly_chart.axis.visible = False
|
|
|
|
monthly_chart.wedge(x=0, y=1, radius=0.4,
|
|
start_angle=cumsum('angle', include_zero=True), end_angle=cumsum('angle'),
|
|
line_color="white", fill_color='color', legend='mood', source=monthly_data)
|
|
|
|
yearly_data = pd.Series(yearly).reset_index(name='value').rename(columns={'index':'mood'})
|
|
yearly_data['angle'] = yearly_data['value']/yearly_data['value'].sum() * 2*pi
|
|
yearly_data['color'] = colors
|
|
|
|
yearly_chart = figure(height=350, title="Yearly", toolbar_location=None,
|
|
tools="hover", tooltips="@mood: @value")
|
|
yearly_chart.axis.visible = False
|
|
|
|
yearly_chart.wedge(x=0, y=1, radius=0.4,
|
|
start_angle=cumsum('angle', include_zero=True), end_angle=cumsum('angle'),
|
|
line_color="white", fill_color='color', legend='mood', source=yearly_data)
|
|
|
|
return column(weekly_chart, monthly_chart, yearly_chart)
|
|
|
|
def activitymood(activity):
|
|
hv.extension('bokeh')
|
|
|
|
tooltips = [
|
|
('Date', '@date{%F %H:%M}'),
|
|
('Mood', '@name (@value)')
|
|
]
|
|
|
|
formatters = {
|
|
'@date': 'datetime'
|
|
}
|
|
|
|
hover = HoverTool(tooltips=tooltips, formatters=formatters)
|
|
|
|
pointdict = {"date": [], "value": [], "color": [], "name": []}
|
|
|
|
for statusactivity in StatusActivity.objects.filter(activity=activity):
|
|
if statusactivity.status.mood:
|
|
pointdict["date"].append(statusactivity.status.timestamp)
|
|
pointdict["value"].append(statusactivity.status.mood.value)
|
|
pointdict["color"].append(statusactivity.status.mood.color)
|
|
pointdict["name"].append(statusactivity.status.mood.name)
|
|
|
|
pointframe = pd.DataFrame.from_dict(pointdict)
|
|
|
|
points = hv.Points(pointframe)
|
|
|
|
points.opts(
|
|
tools=[hover], color='color', cmap='Category20',
|
|
line_color='black', size=25,
|
|
width=600, height=400, show_grid=True)
|
|
|
|
pointtuples = [(pointdict["date"][i], pointdict["value"][i]) for i in range(len(pointdict["date"]))]
|
|
|
|
line = hv.Curve(pointtuples)
|
|
|
|
maxval = Mood.objects.filter(user=activity.user).latest("value").value
|
|
maxy = maxval + max(maxval * 0.1, 1)
|
|
|
|
maxx = timezone.now().timestamp() * 1000
|
|
minx = maxx - (60*60*24*7) * 1000
|
|
|
|
output = points * line * timeseries.rolling(line, rolling_window=7)
|
|
output.opts(ylim=(0, maxy), xlim=(minx, maxx))
|
|
|
|
return output
|
|
|
|
def activitypies(activity):
|
|
hv.extension('bokeh')
|
|
|
|
maxdate = timezone.now()
|
|
|
|
sa = StatusActivity.objects.filter(activity=activity)
|
|
|
|
weekly = dict()
|
|
colors = []
|
|
|
|
for mood in Mood.objects.filter(user=activity.user):
|
|
weekly[mood.name] = 0
|
|
colors.append(mood.color)
|
|
|
|
monthly, yearly = weekly.copy(), weekly.copy()
|
|
|
|
for single in sa:
|
|
if single.status.mood:
|
|
if single.status.timestamp > timezone.now() - relativedelta(weeks=1):
|
|
weekly[single.status.mood.name] += 1
|
|
if single.status.timestamp > timezone.now() - relativedelta(months=1):
|
|
monthly[single.status.mood.name] += 1
|
|
if single.status.timestamp > timezone.now() - relativedelta(years=1):
|
|
yearly[single.status.mood.name] += 1
|
|
|
|
weekly_data = pd.Series(weekly).reset_index(name='value').rename(columns={'index':'mood'})
|
|
weekly_data['angle'] = weekly_data['value']/weekly_data['value'].sum() * 2*pi
|
|
weekly_data['color'] = colors
|
|
|
|
weekly_chart = figure(height=350, title="Weekly", toolbar_location=None,
|
|
tools="hover", tooltips="@mood: @value")
|
|
weekly_chart.axis.visible = False
|
|
|
|
weekly_chart.wedge(x=0, y=1, radius=0.4,
|
|
start_angle=cumsum('angle', include_zero=True), end_angle=cumsum('angle'),
|
|
line_color="white", fill_color='color', legend='mood', source=weekly_data)
|
|
|
|
monthly_data = pd.Series(monthly).reset_index(name='value').rename(columns={'index':'mood'})
|
|
monthly_data['angle'] = monthly_data['value']/monthly_data['value'].sum() * 2*pi
|
|
monthly_data['color'] = colors
|
|
|
|
monthly_chart = figure(height=350, title="Monthly", toolbar_location=None,
|
|
tools="hover", tooltips="@mood: @value")
|
|
monthly_chart.axis.visible = False
|
|
|
|
monthly_chart.wedge(x=0, y=1, radius=0.4,
|
|
start_angle=cumsum('angle', include_zero=True), end_angle=cumsum('angle'),
|
|
line_color="white", fill_color='color', legend='mood', source=monthly_data)
|
|
|
|
yearly_data = pd.Series(yearly).reset_index(name='value').rename(columns={'index':'mood'})
|
|
yearly_data['angle'] = yearly_data['value']/yearly_data['value'].sum() * 2*pi
|
|
yearly_data['color'] = colors
|
|
|
|
yearly_chart = figure(height=350, title="Yearly", toolbar_location=None,
|
|
tools="hover", tooltips="@mood: @value")
|
|
yearly_chart.axis.visible = False
|
|
|
|
yearly_chart.wedge(x=0, y=1, radius=0.4,
|
|
start_angle=cumsum('angle', include_zero=True), end_angle=cumsum('angle'),
|
|
line_color="white", fill_color='color', legend='mood', source=yearly_data)
|
|
|
|
return column(weekly_chart, monthly_chart, yearly_chart) |