import os import tempfile import pandas as pd import plotly from plotly.subplots import make_subplots from plotly.graph_objs import Scatter, Layout, Bar, Figure try: from gc_wrapper.GC_Wrapper import GC_wrapper as GC except ImportError: pass BASELINE_DAYS = 7 NORMALRANGE_DAYS = 60 TRAINING_STRESS = 'BikeStress' HRV = 'RECOVERY_POINTS' HR = 'HR' HRV_BASE = 'HrvBaseline' HR_BASE = 'HrBaseline' HRV_NORMAL = 'HrvNormal' HRV_STD = 'HrvStdDev' HRV_CEILING = 'HrvNormalCeiling' HRV_FLOOR = 'HrvNormalFloor' HRV_CV = 'HrvCv' HRV_VAR_BASE = 'HrvVarBase' def get_hrv_measures(): history = pd.DataFrame(GC.seasonMeasures( all=True, group='Hrv')).query(f'{HRV} != 0.0') selection = pd.DataFrame(GC.seasonMeasures( all=False, group='Hrv')).query(f'{HRV} != 0.0') return history, selection def compute_hrv_trends(df: pd.DataFrame): df[HRV_BASE] = df[HRV].rolling(window=BASELINE_DAYS, min_periods=BASELINE_DAYS // 2).mean() df[HRV_NORMAL] = df[HRV].rolling(window=NORMALRANGE_DAYS, min_periods=NORMALRANGE_DAYS // 2).mean() df[HRV_STD] = df[HRV].rolling(window=NORMALRANGE_DAYS, min_periods=NORMALRANGE_DAYS // 2).std() df[HRV_CEILING] = df[HRV_NORMAL] + 0.75 * df[HRV_STD] df[HRV_FLOOR] = df[HRV_NORMAL] - 0.75 * df[HRV_STD] df[HR_BASE] = df[HR].rolling(window=BASELINE_DAYS, min_periods=BASELINE_DAYS // 2).mean() df[HRV_VAR_BASE] = df[HRV].rolling(window=BASELINE_DAYS, min_periods=BASELINE_DAYS // 2).std() df[HRV_CV] = df[HRV_VAR_BASE] / df[HRV_BASE] * 100.0 return df def get_pmc_data(t1): df = pd.DataFrame(GC.seasonPmc(all=True, metric=TRAINING_STRESS)) tmp = pd.DataFrame(GC.seasonPmc(all=False, metric=TRAINING_STRESS)) t0 = tmp.iloc[0]['date'] return crop(df, t0, t1) def get_stress(): df = pd.DataFrame(GC.seasonMetrics())[['date', TRAINING_STRESS]] data = df.groupby('date')[TRAINING_STRESS].sum() df = pd.DataFrame({'date': data.index, TRAINING_STRESS: data.values}) return df def get_rpe(): df = pd.DataFrame(GC.seasonMetrics())[['date', 'RPE']] # df = df.loc[df['RPE'].dtype.kind in 'iufc'] # df = df.query('RPE != 0.0') df['RPE'] = df['RPE'].replace('', '0').astype(int) data = df.groupby('date', as_index=False).mean() return data def crop(df: pd.DataFrame, t0, t1): df = df.loc[df['date'] >= t0] return df.loc[df['date'] <= t1] try: os.remove(tempfile.gettempdir() + "/hrv_trends.html") except: pass history, selection = get_hrv_measures() compute_hrv_trends(history) t0 = selection.iloc[0]['date'] t1 = selection.iloc[-1]['date'] hrv_data = crop(history, t0, t1) rpe = get_rpe() stress = get_stress() pmc_data = get_pmc_data(stress.iloc[-1]['date']) lts_trace = Scatter(x=pmc_data['date'], y=pmc_data['lts'], name='Fitness (LTS)', fill='tozeroy', line=dict(color='#1f77b4')) sts_trace = Scatter(x=pmc_data['date'], y=pmc_data['sts'], name='Fatigue (STS)', fill='tozeroy') sb_trace = Scatter(x=pmc_data['date'], y=pmc_data['sb'], name='Form (TSB)') hr_trace = Scatter(x=hrv_data['date'], y=hrv_data[HR_BASE], mode='lines', name=f'{BASELINE_DAYS}-day HR Baseline') hrv_ceiling_trace = Scatter(x=hrv_data['date'], y=hrv_data[HRV_CEILING], fill=None, mode='lines', name=f"{NORMALRANGE_DAYS}-day Top Normal", line=dict(color='#b3f6d1', )) hrv_floor_trace = Scatter(x=hrv_data['date'], y=hrv_data[HRV_FLOOR], fill='tonexty', mode='lines', name=f'{NORMALRANGE_DAYS}-day Bottom Normal', line=dict(color='#b3f6d1', )) hrv_base_trace = Scatter(x=hrv_data['date'], y=hrv_data[HRV_BASE], mode='lines', name=f"{BASELINE_DAYS}-day Baseline", line=dict(color='red', )) hrv_trace = Bar(x=hrv_data['date'], y=hrv_data[HRV], name="Recovery Points", marker=dict(color='lightgray', )) hrv_cv_trace = Scatter(x=hrv_data['date'], y=hrv_data[HRV_CV], name='CV', mode='lines', line=dict(color='black')) # session_rpe_trace = Bar(x=rpe['date'], # y=rpe['Session_RPE'], # name='RPE', # marker=dict(color='lightgray', )) rpe_trace = Bar(x=rpe['date'], y=rpe['RPE'], name='RPE', marker=dict(color='red', )) layout = Layout(template='none', paper_bgcolor='rgba(0,0,0,0)', plot_bgcolor='rgba(0,0,0,0)', yaxis=dict(title="HRV Recovery Points", range=[5.5, 10]), yaxis2=dict(title="Coeffient of Variation", range=[0, 20]), yaxis3=dict(title=f'{TRAINING_STRESS}'), yaxis4=dict(title='HRV (ln(RMSSD)'), yaxis5=dict(title='HR (BPM)'), legend=dict(orientation="h")) fig = make_subplots( 4, 1, subplot_titles=[ 'HRV', 'Stress', 'HRV vs. HR', 'RPE', ], specs=[ [dict(secondary_y=False)], [dict(secondary_y=False)], [dict(secondary_y=False)], [dict(secondary_y=True)], # [dict(secondary_y=True)], ], # horizontal_spacing=0.2, # vertical_spacing=0.2 ) fig.add_trace(hrv_trace, 1, 1) fig.add_trace(hrv_ceiling_trace, 1, 1) fig.add_trace(hrv_floor_trace, 1, 1) fig.add_trace(hrv_base_trace, 1, 1) # fig.add_trace(sb_trace, 1, 1, secondary_y=True) fig.add_trace(hrv_cv_trace, 2, 1) fig.add_trace(sts_trace, 3, 1) fig.add_trace(lts_trace, 3, 1) fig.add_trace(hr_trace, 4, 1, secondary_y=True) fig.add_trace(hrv_base_trace, 4, 1) # fig.add_trace(session_rpe_trace, 2, 2) # fig.add_trace(rpe_trace, 5, 1) fig.update_layout(layout) fig.update_layout( dict( yaxis=dict(showline=True, mirror=True, ticks='inside'), yaxis2=dict(showline=True, mirror=True, ticks='inside'), yaxis3=dict(showline=True, mirror=True, ticks='inside'), yaxis4=dict(showline=True, mirror=True, ticks='inside'), yaxis5=dict(showline=True, mirror=True, ticks='inside'), yaxis6=dict(showline=True, mirror=True, ticks='inside'), yaxis7=dict(showline=True, mirror=True, ticks='inside'), yaxis8=dict(showline=True, mirror=True, ticks='inside'), xaxis=dict(showline=True, mirror=True, ticks='inside'), xaxis2=dict(showline=True, mirror=True, ticks='inside'), xaxis3=dict(showline=True, mirror=True, ticks='inside'), xaxis4=dict(showline=True, mirror=True, ticks='inside'), xaxis5=dict(showline=True, mirror=True, ticks='inside'), xaxis6=dict(showline=True, mirror=True, ticks='inside'), xaxis7=dict(showline=True, mirror=True, ticks='inside'), xaxis8=dict(showline=True, mirror=True, ticks='inside'), )) fig.update_xaxes(showline=True, linewidth=1, linecolor='black', mirror=True) fig.update_yaxes(showline=True, linewidth=1, linecolor='black', mirror=True) f = plotly.offline.plot(fig, auto_open=False, filename=tempfile.gettempdir() + "/temp-plot.html") GC.webpage("file://" + f)