new interplot relations, elev_plot hovering position displays blue marker on line_map now

This commit is contained in:
2025-09-15 22:26:43 +02:00
parent 7129df8a79
commit efe3ff4be3

View File

@@ -14,7 +14,7 @@ import datetime
from math import radians, sin, cos, sqrt, asin from math import radians, sin, cos, sqrt, asin
import dash import dash
from dash import dcc, html, Input, Output, Dash from dash import dcc, html, Input, Output, Dash, State
import dash_bootstrap_components as dbc import dash_bootstrap_components as dbc
import pandas as pd import pandas as pd
@@ -340,7 +340,7 @@ def create_info_banner(df):
'justifyContent': 'space-around', 'justifyContent': 'space-around',
'backgroundColor': '#1e1e1e', 'backgroundColor': '#1e1e1e',
'color': 'white', 'color': 'white',
'padding': '20px', 'padding': '5px',
'marginBottom': '5px', 'marginBottom': '5px',
'borderRadius': '10px', 'borderRadius': '10px',
'width': '100%', 'width': '100%',
@@ -355,25 +355,6 @@ def create_info_banner(df):
# START OF THE PLOTS # START OF THE PLOTS
# ============================================================================= # =============================================================================
def create_map_plot(df): def create_map_plot(df):
# fig = px.line_map(
# df,
# lat='lat',
# lon='lon',
# hover_name='time',
# hover_data={
# 'cum_dist_km': ':.2f',
# 'duration_hms': True,
# 'lat': False,
# 'lon': False,
# 'time': False
# },
# labels={
# 'cum_dist_km': 'Distance (km) ',
# 'duration_hms': 'Elapsed Time '
# },
# zoom=13,
# height=800
# )
fig = px.line_map( fig = px.line_map(
df, df,
lat='lat', lat='lat',
@@ -394,9 +375,9 @@ def create_map_plot(df):
customdata=df[['cum_dist_km', 'speed_kmh', 'heart_rate', 'duration_hms']] customdata=df[['cum_dist_km', 'speed_kmh', 'heart_rate', 'duration_hms']]
) )
# Define map style and the line ontop # Define map style and the line ontop
fig.update_layout(map_style="open-street-map") fig.update_layout(map_style="open-street-map") #My-Fav: open-street-map, satellite-streets, dark, white-bg
# The built-in plotly.js styles are: carto-darkmatter, carto-positron, open-street-map, stamen-terrain, stamen-toner, stamen-watercolor, white-bg # Possible Options:
# The built-in Mapbox styles are: basic, streets, outdoors, light, dark, satellite, satellite-streets # 'basic', 'carto-darkmatter', 'carto-darkmatter-nolabels', 'carto-positron', 'carto-positron-nolabels', 'carto-voyager', 'carto-voyager-nolabels', 'dark', 'light', 'open-street-map', 'outdoors', 'satellite', 'satellite-streets', 'streets', 'white-bg'.
fig.update_traces(line=dict(color="#f54269", width=3)) fig.update_traces(line=dict(color="#f54269", width=3))
# Start / Stop marker # Start / Stop marker
@@ -410,17 +391,33 @@ def create_map_plot(df):
lat=[end['lat']], lon=[end['lon']], mode='markers+text', lat=[end['lat']], lon=[end['lon']], mode='markers+text',
marker=dict(size=12, color='#b9fc62'), text=['Stop'], name='Stop', textposition='bottom left' marker=dict(size=12, color='#b9fc62'), text=['Stop'], name='Stop', textposition='bottom left'
)) ))
fig.update_layout(paper_bgcolor='#1e1e1e', font=dict(color='white')) # THIS IS MY ELEVATION-PLOT SHOW POSITION-MARKER IN MAP-PLOT:
fig.add_trace(go.Scattermap(
lat=[],
lon=[],
mode="markers",
marker=dict(size=18, color="#42B1E5", symbol="circle"),
name="Hovered Point"
))
# KOMPAKTE LAYOUT-EINSTELLUNGEN
fig.update_layout( fig.update_layout(
legend=dict( paper_bgcolor='#1e1e1e',
orientation='h', # horizontal layout font=dict(color='white'),
yanchor='top', # Margins reduzieren für kompakteren Plot
y=-0.01, # move legend below the map margin=dict(l=60, r=45, t=10, b=50), # Links, Rechts, Oben, Unten
xanchor='center', # Plotly-Toolbar konfigurieren
x=0.5, showlegend=True,
font=dict(color='white') # Kompakte Legend
legend=dict(
orientation='h', # horizontal layout
yanchor='top',
y=-0.02, # move legend below the map
xanchor='center',
x=0.5,
font=dict(color='white', size=10) # Kleinere Schrift
)
) )
)
return fig return fig
@@ -881,18 +878,20 @@ app.layout = html.Div([
) )
def load_fit_data(path): def load_fit_data(path):
df = process_fit(path) df = process_fit(path)
return df.to_json(date_format='iso', orient='split') return df.to_json(date_format='iso', orient='split')
# Callback 2: Update All Plots # Callback 2: Update All (static) Plots
@app.callback( @app.callback(
Output('info-banner', 'children'), Output('info-banner', 'children'),
Output('fig-map', 'figure'), Output('fig-map', 'figure', allow_duplicate=True),
Output('fig-elevation', 'figure'), Output('fig-elevation', 'figure'),
Output('fig_deviation', 'figure'), Output('fig_deviation', 'figure'),
Output('fig_speed', 'figure'), Output('fig_speed', 'figure'),
Output('fig_hr', 'figure'), Output('fig_hr', 'figure'),
Output('fig_pace_bars', 'figure'), Output('fig_pace_bars', 'figure'),
Input('stored-df', 'data') Input('stored-df', 'data'),
prevent_initial_call=True
) )
def update_all_plots(json_data): def update_all_plots(json_data):
df = pd.read_json(io.StringIO(json_data), orient='split') df = pd.read_json(io.StringIO(json_data), orient='split')
@@ -908,6 +907,27 @@ def update_all_plots(json_data):
return info, fig_map, fig_elev, fig_dev, fig_speed, fig_hr, fig_pace return info, fig_map, fig_elev, fig_dev, fig_speed, fig_hr, fig_pace
# Callback 3: Hover → update only hover (dynamic) marker
@app.callback(
Output('fig-map', 'figure'),
Input('fig-elevation', 'hoverData'),
State('fig-map', 'figure'),
State('stored-df', 'data'),
prevent_initial_call=True
)
def highlight_map(hoverData, fig_map, json_data):
df = pd.read_json(io.StringIO(json_data), orient='split')
if hoverData is not None:
point_index = hoverData['points'][0]['pointIndex']
lat, lon = df.iloc[point_index][['lat', 'lon']]
# update the last trace (the empty Hovered Point trace)
fig_map['data'][-1]['lat'] = [lat]
fig_map['data'][-1]['lon'] = [lon]
return fig_map
# === Run Server === # === Run Server ===
if __name__ == '__main__': if __name__ == '__main__':
app.run(debug=True, port=8051) app.run(debug=True, port=8051)