Updated the bgcolor settings for the Pixel=Plots area.

This commit is contained in:
2026-05-07 15:56:14 +02:00
parent bbf99a59f2
commit e82f756b4f
2 changed files with 27 additions and 12 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 2.1 MiB

View File

@@ -460,7 +460,7 @@ def safe_add_column_to_dataframe(df, column_name, values):
# ── Biometrics (kalibriert gegen Strava) ───────────────────────────────────── # ── Biometrics (kalibriert gegen Strava) ─────────────────────────────────────
_WEIGHT_KG = 75.0 _WEIGHT_KG = 75.0
_HEIGHT_CM = 178.0 _HEIGHT_CM = 178.0
_AGE_YEARS = 35 _AGE_YEARS = 36
_IS_MALE = True _IS_MALE = True
_HR_REST = 64.5 # Ruhepuls in bpm kalibriert gegen Strava 550 kcal _HR_REST = 64.5 # Ruhepuls in bpm kalibriert gegen Strava 550 kcal
# ───────────────────────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────────────────────
@@ -488,30 +488,45 @@ def calculate_calories_burned(df):
# Kein fixer HR_REST — nutze den tatsächlichen Minimum-HR aus dem Lauf # Kein fixer HR_REST — nutze den tatsächlichen Minimum-HR aus dem Lauf
# als Annäherung an den Ruhepuls # als Annäherung an den Ruhepuls
hr_max = 220 - _AGE_YEARS hr_max = 220 - _AGE_YEARS
hr_rest = _HR_REST # 64.5 bpm
# Check, ob genug Herzfrequenz-Daten vorhanden sind
use_hr = ('heart_rate' in df.columns and use_hr = ('heart_rate' in df.columns and
df['heart_rate'].notna().sum() > len(df) * 0.5) df['heart_rate'].notna().sum() > len(df) * 0.5)
if not use_hr: if not use_hr:
return 0 return 0
# Datenvorbereitung
hr = df['heart_rate'].ffill().fillna(df['heart_rate'].bfill()).values hr = df['heart_rate'].ffill().fillna(df['heart_rate'].bfill()).values
ts = df['time_diff_sec'].values ts = df['time_diff_sec'].values
# Ruhepuls aus dem Lauf selbst schätzen: 5. Perzentile der HR-Werte # 2. VO2max Schätzung basierend auf deinem echten Ruhepuls
hr_rest = float(df['heart_rate'].quantile(0.05)) # Die Formel 15 * (HR_max / HR_rest) ist ein Standard-Approximationswert
hr_rest = max(45.0, min(hr_rest, 80.0)) # Plausibilitätsgrenze
vo2max = 15.0 * (hr_max / hr_rest) vo2max = 15.0 * (hr_max / hr_rest)
# Zeitdifferenzen berechnen
dt = np.diff(ts, prepend=ts[0]) dt = np.diff(ts, prepend=ts[0])
mask = (dt > 0) & (dt <= 10) mask = (dt > 0) & (dt <= 10) # Filtert Pausen oder Sprünge in der Aufzeichnung
# 3. Berechnung der Intensität (Karvonen-Prinzip)
# Anteil der Herzfrequenzreserve (HRR)
frac = np.clip((hr - hr_rest) / (hr_max - hr_rest), 0, None) frac = np.clip((hr - hr_rest) / (hr_max - hr_rest), 0, None)
# Umrechnung in MET (Metabolic Equivalent of Task)
# Ein MET = 3.5 ml VO2/kg/min
met = np.clip((frac * vo2max) / 3.5, 1.0, 18.0) met = np.clip((frac * vo2max) / 3.5, 1.0, 18.0)
# 4. Umrechnung in kcal pro Sekunde
# Formel: (MET * 3.5 * Gewicht_kg) / (200 * 60) -> 12000
kcal_per_s = met * _WEIGHT_KG * 3.5 / 12000.0 kcal_per_s = met * _WEIGHT_KG * 3.5 / 12000.0
# Summation über den gesamten Lauf
cumulative = float(np.sum(kcal_per_s[mask] * dt[mask])) cumulative = float(np.sum(kcal_per_s[mask] * dt[mask]))
print(f"DEBUG calories: rows={len(df)}, hr_valid={df['heart_rate'].notna().sum()}, duration={df['time_diff_sec'].iloc[-1]:.0f}s, hr_mean={df['heart_rate'].mean():.1f}") print(f"DEBUG calories: HR_REST_USED={hr_rest}, VO2MAX_EST={vo2max:.1f}, "
f"DURATION={df['time_diff_sec'].iloc[-1]/60:.1f}min, TOTAL_KCAL={cumulative:.1f}")
return int(round(cumulative)) return int(round(cumulative))
@@ -2408,7 +2423,7 @@ app.layout = html.Div([
# START !!!!!!!!!!!!!!! # START !!!!!!!!!!!!!!!
# Pixel-Map Überschrift # Pixel-Map Überschrift
html.Hr(style={'borderColor': '#333', 'margin': '10px 20px'}), html.Hr(style={'borderColor': '#111111', 'margin': '10px 20px'}), #'#333'
html.Div([ html.Div([
html.H3("Pixel-Maps", style={ html.H3("Pixel-Maps", style={
'color': '#aaaaaa', 'margin': '10px 0 0 0', 'fontSize': '16px' 'color': '#aaaaaa', 'margin': '10px 0 0 0', 'fontSize': '16px'
@@ -2416,7 +2431,7 @@ app.layout = html.Div([
html.P( html.P(
"Plot 1) Heatmap: Einzellauf oder alle Läufe der Region umschalten.\n" "Plot 1) Heatmap: Einzellauf oder alle Läufe der Region umschalten.\n"
"Plot 2), 3) & 4) Elevation-, Pace- & HR-Map: des aktuell gewählten Laufs.", "Plot 2), 3) & 4) Elevation-, Pace- & HR-Map: des aktuell gewählten Laufs.",
style={'color': '#666', 'margin': '2px 0 8px 0', 'fontSize': '12px'} style={'color': '#aaaaaa', 'margin': '2px 0 8px 0', 'fontSize': '12px'}
), ),
], style={'padding': '0 20px'}), ], style={'padding': '0 20px'}),
@@ -2488,7 +2503,7 @@ app.layout = html.Div([
'backgroundColor': '#111111' 'backgroundColor': '#111111'
}), }),
html.Hr(style={'borderColor': '#333', 'margin': '10px 20px'}), html.Hr(style={'borderColor': '#111111', 'margin': '10px 20px'}),
# ENDE !!!!!!!!!!!!!!!! # ENDE !!!!!!!!!!!!!!!!
dcc.Graph(id='fig-elevation'), dcc.Graph(id='fig-elevation'),