Change matplotlib backend to speed up plottng time (~0.25 to ~0.03 seconds)
This commit is contained in:
113
app.py
113
app.py
@@ -1,3 +1,11 @@
|
||||
import matplotlib.dates as mdates
|
||||
import matplotlib.pyplot as plt
|
||||
from dateutil.relativedelta import relativedelta
|
||||
import humanize
|
||||
from dateutil.parser import isoparse
|
||||
import sparklines
|
||||
import os
|
||||
import time
|
||||
from sqlalchemy import func
|
||||
from datetime import datetime, timedelta
|
||||
import io
|
||||
@@ -5,13 +13,8 @@ from flask_sqlalchemy import SQLAlchemy
|
||||
from flask import Flask, make_response, render_template, request, jsonify
|
||||
import jinja_partials
|
||||
from flask_htmx import HTMX
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.dates as mdates
|
||||
import os
|
||||
import sparklines
|
||||
from dateutil.parser import isoparse
|
||||
import humanize
|
||||
from dateutil.relativedelta import relativedelta
|
||||
import matplotlib
|
||||
matplotlib.use('Agg')
|
||||
|
||||
|
||||
app = Flask(__name__)
|
||||
@@ -358,63 +361,66 @@ def get_workouts_for_user(user, workouts):
|
||||
return [get_workout_view_data(workout, user) for workout in workouts if get_workout_view_data(workout, user)]
|
||||
|
||||
|
||||
def format_workout_data(workout, user):
|
||||
"""
|
||||
Formats the workout data for view.
|
||||
|
||||
Parameters:
|
||||
- workout: The workout object.
|
||||
- user: The user associated with the workout.
|
||||
|
||||
Returns:
|
||||
- dict: A dictionary with formatted workout data.
|
||||
"""
|
||||
duration = timedelta(seconds=int(workout.duration or 0))
|
||||
|
||||
return {
|
||||
'id': workout.id,
|
||||
'user_id': user.id,
|
||||
'user_name': user.name,
|
||||
'start_time': format_date_with_ordinal(workout.started_at, '%#H:%M %B %dth %Y'),
|
||||
'start_time_date': workout.started_at,
|
||||
'start_time_ago': humanize.naturaltime(workout.started_at),
|
||||
'duration': humanize.naturaldelta(duration),
|
||||
'duration_minutes': duration.total_seconds() / 60,
|
||||
'average_rpm': int(workout.average_rpm or 0),
|
||||
'min_rpm': int(workout.min_rpm or 0),
|
||||
'max_rpm': int(workout.max_rpm or 0),
|
||||
'calories': int(workout.calories or 0),
|
||||
'distance': int(workout.distance or 0),
|
||||
'bike_display_name': workout.bike.display_name,
|
||||
'selected_graph_types': ['speed'] + (['heart_rate'] if workout.is_heart_rate_available else []),
|
||||
'is_heart_rate_available': workout.is_heart_rate_available,
|
||||
'is_cadence_available': workout.is_cadence_available,
|
||||
'average_bpm': int(workout.average_bpm or 0),
|
||||
'min_bpm': int(workout.min_bpm or 0),
|
||||
'max_bpm': int(workout.max_bpm or 0),
|
||||
}
|
||||
|
||||
|
||||
def get_workout_view_data(workout, user):
|
||||
duration = timedelta(
|
||||
seconds=int(workout.duration)) if workout.duration else timedelta(seconds=0)
|
||||
average_rpm = workout.average_rpm if workout.average_rpm else 0
|
||||
min_rpm = workout.min_rpm if workout.min_rpm else 0
|
||||
max_rpm = workout.max_rpm if workout.max_rpm else 0
|
||||
calories = workout.calories if workout.calories else 0
|
||||
distance = workout.distance if workout.distance else 0
|
||||
average_bpm = workout.average_bpm if workout.average_bpm else 0
|
||||
min_bpm = workout.min_bpm if workout.min_bpm else 0
|
||||
max_bpm = workout.max_bpm if workout.max_bpm else 0
|
||||
is_heart_rate_available = workout.is_heart_rate_available
|
||||
is_cadence_available = workout.is_cadence_available
|
||||
start_time = workout.started_at
|
||||
"""
|
||||
Retrieve view data for a single workout.
|
||||
|
||||
selected_graph_types = ['speed']
|
||||
if is_heart_rate_available:
|
||||
selected_graph_types.append('heart_rate')
|
||||
Parameters:
|
||||
- workout: The workout object.
|
||||
- user: The user associated with the workout.
|
||||
|
||||
if is_cadence_available or is_heart_rate_available:
|
||||
return {
|
||||
'id': workout.id,
|
||||
'user_id': user.id,
|
||||
'user_name': user.name,
|
||||
'start_time': format_date_with_ordinal(start_time, '%#H:%M %B %dth %Y'),
|
||||
'start_time_date': start_time,
|
||||
'start_time_ago': humanize.naturaltime(start_time),
|
||||
'duration': humanize.naturaldelta(duration),
|
||||
'duration_minutes': duration.total_seconds() / 60,
|
||||
'average_rpm': int(average_rpm),
|
||||
'min_rpm': int(min_rpm),
|
||||
'max_rpm': int(max_rpm),
|
||||
'calories': int(calories),
|
||||
'distance': int(distance),
|
||||
'bike_display_name': workout.bike.display_name,
|
||||
'selected_graph_types': selected_graph_types,
|
||||
'is_heart_rate_available': is_heart_rate_available,
|
||||
'is_cadence_available': is_cadence_available,
|
||||
'average_bpm': int(average_bpm),
|
||||
'min_bpm': int(min_bpm),
|
||||
'max_bpm': int(max_bpm),
|
||||
}
|
||||
else:
|
||||
return None
|
||||
Returns:
|
||||
- dict or None: A dictionary containing view data if cadence or heart rate is available, otherwise None.
|
||||
"""
|
||||
if workout.is_cadence_available or workout.is_heart_rate_available:
|
||||
return format_workout_data(workout, user)
|
||||
return None
|
||||
|
||||
|
||||
def create_graph(x_values, y_values, y_label, filename, x_label='Time'):
|
||||
# Plotting
|
||||
fig, ax = plt.subplots()
|
||||
ax.plot(x_values, y_values)
|
||||
ax.set_xlabel(x_label)
|
||||
ax.set_ylabel(y_label)
|
||||
|
||||
# ax.set_title(
|
||||
# 'Cadence Readings for Workout {}'.format(workout_id))
|
||||
ax.xaxis.set_major_formatter(mdates.DateFormatter("%H:%M"))
|
||||
|
||||
# set the y-axis limits to start at 0
|
||||
ax.set_ylim(bottom=0)
|
||||
|
||||
# Save the graph to a bytes buffer
|
||||
@@ -422,6 +428,7 @@ def create_graph(x_values, y_values, y_label, filename, x_label='Time'):
|
||||
plt.savefig(buffer, format='png',
|
||||
transparent=True, bbox_inches='tight')
|
||||
buffer.seek(0)
|
||||
|
||||
# Create a response object with the graph image
|
||||
response = make_response(buffer.getvalue())
|
||||
response.headers['Content-Type'] = 'image/png'
|
||||
|
||||
Reference in New Issue
Block a user