Display playtime graph on session list
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
Fixes #29
This commit is contained in:
64
src/web/common/util/plots.py
Normal file
64
src/web/common/util/plots.py
Normal file
@ -0,0 +1,64 @@
|
||||
import pandas as pd
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib.dates import date2num
|
||||
import base64
|
||||
from io import BytesIO
|
||||
from tracker.models import Session
|
||||
from django.db.models import Sum, IntegerField, F
|
||||
from django.db.models.functions import TruncDay
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from django.db.models import QuerySet
|
||||
|
||||
|
||||
def key_value_to_value_value(data):
|
||||
return {data["date"]: data["hours"]}
|
||||
|
||||
|
||||
def playtime_over_time_chart(queryset: QuerySet = Session.objects):
|
||||
microsecond_in_second = 1000000
|
||||
result = (
|
||||
queryset.annotate(date=TruncDay("timestamp_start"))
|
||||
.values("date")
|
||||
.annotate(
|
||||
hours=Sum(
|
||||
F("duration_calculated") + F("duration_manual"),
|
||||
output_field=IntegerField(),
|
||||
)
|
||||
)
|
||||
.values("date", "hours")
|
||||
)
|
||||
keys = []
|
||||
values = []
|
||||
running_total = int(0)
|
||||
for item in result:
|
||||
date_value = datetime.strftime(item["date"], "%d-%m-%Y")
|
||||
keys.append(date_value)
|
||||
running_total += int(item["hours"] / (3600 * microsecond_in_second))
|
||||
values.append(running_total)
|
||||
data = [keys, values]
|
||||
return get_chart(data, title="Playtime over time", xlabel="Date", ylabel="Hours")
|
||||
|
||||
|
||||
def get_graph():
|
||||
buffer = BytesIO()
|
||||
plt.savefig(buffer, format="svg", transparent=True)
|
||||
buffer.seek(0)
|
||||
image_png = buffer.getvalue()
|
||||
graph = base64.b64encode(image_png)
|
||||
graph = graph.decode("utf-8")
|
||||
buffer.close()
|
||||
return graph
|
||||
|
||||
|
||||
def get_chart(data, title="", xlabel="", ylabel=""):
|
||||
plt.style.use("dark_background")
|
||||
plt.switch_backend("SVG")
|
||||
fig = plt.figure(figsize=(10, 4))
|
||||
plt.plot(data[0], data[1])
|
||||
plt.title(title)
|
||||
plt.xlabel(xlabel)
|
||||
plt.ylabel(ylabel)
|
||||
plt.tight_layout()
|
||||
chart = get_graph()
|
||||
return chart
|
@ -794,6 +794,10 @@ select {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.mb-5 {
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.ml-1 {
|
||||
margin-left: 0.25rem;
|
||||
}
|
||||
|
@ -5,11 +5,14 @@
|
||||
{% block content %}
|
||||
<div class="text-center text-xl mb-4 dark:text-slate-400">
|
||||
{% if dataset.count >= 2 %}
|
||||
<img src="data:image/svg+xml;base64,{{ chart|safe }}" class="mx-auto mb-5" />
|
||||
<a href="{% url 'start_session' dataset.last.purchase.id %}">
|
||||
<button type="button" title="Track last tracked" class="py-1 px-2 bg-green-600 hover:bg-green-700 focus:ring-green-500 focus:ring-offset-blue-200 text-white transition ease-in duration-200 text-center text-base font-semibold shadow-md focus:outline-none focus:ring-2 focus:ring-offset-2 rounded-lg ">
|
||||
New session of {{ dataset.last.purchase }}
|
||||
</button>
|
||||
</a>
|
||||
{% else %}
|
||||
Playtime chart will be displayed when there are 2 or more sessions.
|
||||
{% endif %}
|
||||
{% if purchase %}
|
||||
<h1>Listing sessions only for purchase "{{ purchase }}"</h1>
|
||||
|
@ -8,6 +8,7 @@ from django.conf import settings
|
||||
from common.util.time import now as now_with_tz, format_duration
|
||||
from django.db.models import Sum
|
||||
import logging
|
||||
from common.util.plots import playtime_over_time_chart
|
||||
|
||||
|
||||
def model_counts(request):
|
||||
@ -68,6 +69,7 @@ def list_sessions(request, purchase_id=None):
|
||||
|
||||
context["total_duration"] = dataset.total_duration()
|
||||
context["dataset"] = dataset
|
||||
context["chart"] = playtime_over_time_chart(dataset)
|
||||
|
||||
return render(request, "list_sessions.html", context)
|
||||
|
||||
|
Reference in New Issue
Block a user