mountainbikel.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. import pandas as pd
  2. import numpy as np
  3. import datetime
  4. import json
  5. import math
  6. import os
  7. import plotly
  8. import plotly.graph_objs as go
  9. import plotly.express as px
  10. def round_float(s):
  11. '''1. if s is float, round it to 0 decimals
  12. 2. else return s as is
  13. '''
  14. import re
  15. m = re.match("(\d+\.\d+)",s.__str__())
  16. try:
  17. r = round(float(m.groups(0)[0]),0)
  18. except:
  19. r = s
  20. # r = 0
  21. return r
  22. def safe_round(number, ndigits=None):
  23. if math.isnan(number):
  24. return number
  25. return round(number, ndigits)
  26. # https://stackoverflow.com/questions/775049/how-do-i-convert-seconds-to-hours-minutes-and-seconds
  27. def sec2time(sec, n_msec=3):
  28. ''' Convert seconds to 'D days, HH:MM:SS.FFF' '''
  29. if hasattr(sec,'__len__'):
  30. return [sec2time(s) for s in sec]
  31. m, s = divmod(sec, 60)
  32. h, m = divmod(m, 60)
  33. # d, h = divmod(h, 24)
  34. d, h = divmod(h, 72)
  35. if n_msec > 0:
  36. pattern = '%%02d:%%02d:%%0%d.%df' % (n_msec+3, n_msec)
  37. else:
  38. pattern = r'%02d:%02d:%02d'
  39. # if d == 0:
  40. if d < 3:
  41. return pattern % (h, m, s)
  42. return ('%d Tage, ' + pattern) % (d, h, m, s)
  43. def read_data(csv_file):
  44. df = pd.read_csv(csv_file, index_col='startTimeLocal', parse_dates=['startTimeLocal'])
  45. df.drop( 'activityId'.split() , axis=1, inplace=True)
  46. df.drop( 'Unnamed: 0', axis=1, inplace=True)
  47. df['distance'] = round(df['distance'] / 1000, 3)
  48. df['maxSpeed'] = round(df['maxSpeed'], 2)
  49. df['averageSpeed'] = round(df['averageSpeed']*3.6, 2)
  50. df['elevationGain'] = df['elevationGain'].astype(int)
  51. df['maxElevation'] = round(df['maxElevation'],0)
  52. df['intensityMinutes'] = df['moderateIntensityMinutes'] + df['vigorousIntensityMinutes']*2
  53. # print(df.index)
  54. df['startzeit'] = df.index
  55. # print(df.keys())
  56. return(df)
  57. def render_weekly_sum_barchart (datafield, factor):
  58. df2 = read_data()
  59. df2['startzeit'] = df2.index
  60. df = df2.sort_values(by="startzeit",ascending=True).set_index("startzeit").last("3M")
  61. df['startTimeLocal'] = df.index
  62. chart_data = pd.concat([
  63. pd.Series(df.set_index('startTimeLocal').index.to_period('W').to_timestamp(how='start').values, index=df.index, name='startTimeLocal|W'),
  64. df[f'{datafield}'] / factor,], axis=1)
  65. chart_data = chart_data.sort_values(['startTimeLocal|W'])
  66. chart_data = chart_data.rename(columns={'startTimeLocal|W': 'x'})
  67. chart_data_sum = chart_data.groupby(['x'], dropna=True)[[f'{datafield}']].sum()
  68. chart_data_sum.columns = [f'{datafield}|sum']
  69. chart_data = chart_data_sum.reset_index()
  70. chart_data = chart_data.dropna()
  71. charts = []
  72. charts.append(go.Bar(
  73. x=chart_data['x'],
  74. y=chart_data[f'{datafield}|sum']
  75. ))
  76. fig = go.Figure(data=charts, layout=go.Layout({
  77. 'barmode': 'stack',
  78. 'legend': {'orientation': 'h', 'y': -0.3},
  79. 'title': {'text': f'Sum of {datafield} by startTimeLocal (Weekly)'},
  80. 'xaxis': {'title': {'text': 'startzeit (Weekly)'}},
  81. 'yaxis': {'title': {'text': f'Sum of {datafield}'}, 'type': 'linear'}
  82. }))
  83. return(fig)
  84. def monthly_sum_barchart (datafield, factor, heading, y_axis, x_axis):
  85. df = read_data()
  86. df = df.reset_index().drop('index', axis=1, errors='ignore')
  87. chart_data = pd.concat([
  88. pd.Series(df.set_index('startTimeLocal').index.to_period('M').to_timestamp(how='start').values, index=df.index, name='startTimeLocal|M'),
  89. df[f'{datafield}'],], axis=1)
  90. chart_data = chart_data.sort_values(['startTimeLocal|M'])
  91. chart_data = chart_data.rename(columns={'startTimeLocal|M': 'x'})
  92. chart_data_sum = chart_data.groupby(['x'], dropna=True)[[f'{datafield}']].sum()
  93. chart_data_sum.columns = [f'{datafield}|sum']
  94. print(chartdata.info())
  95. chart_data = chart_data_sum.reset_index()
  96. chart_data = chart_data.dropna()
  97. charts = []
  98. charts.append(go.Bar(
  99. x=chart_data['x'],
  100. y=chart_data[f'{datafield}|sum']
  101. ))
  102. fig = go.Figure(data=charts, layout=go.Layout({
  103. 'barmode': 'stack',
  104. 'legend': {'orientation': 'h', 'y': -0.3},
  105. 'title': {'text': heading},
  106. 'xaxis': {'title': {'text': x_axis}},
  107. 'yaxis': {'title': {'text': y_axis}}
  108. }))
  109. return(fig)
  110. def monthly_sum_barchart_concurrent2 (csv_file, datafield, factor, heading, y_axis, x_axis, grouptitle):
  111. df = read_data(csv_file)
  112. df = df.reset_index().drop('index', axis=1, errors='ignore')
  113. df['month'] = df['startTimeLocal'].dt.month
  114. df['year'] = df['startTimeLocal'].dt.year
  115. df['movingDuration'] = df['movingDuration'].map(lambda x: round(x/3600,2))
  116. # print(df.head())
  117. df = df.reset_index().drop('index', axis=1, errors='ignore')
  118. grouped_df = df.groupby(by=["month", "year"], as_index=False).agg( {f"{datafield}": "sum"} )
  119. grouped_df.year = grouped_df['year'].apply(str)
  120. grouped_df.sort_values(by=['year'], inplace=True)
  121. fig = px.bar(
  122. data_frame = grouped_df,
  123. x = "month",
  124. y = f"{datafield}",
  125. color = "year",
  126. barmode = "group",
  127. labels = { "year" : x_axis,
  128. f"{datafield}" : y_axis },
  129. title = heading,
  130. )
  131. fig.update_layout(
  132. font_family="Courier New",
  133. font_color="black",
  134. xaxis_title="Monat",
  135. )
  136. fig.update_xaxes( labelalias = { 1:'Jan',2:'Feb',3:'Mar',4:'Apr',5:'Mai',6:'Jun',7:'Jul',8:'"Aug"',9:'Sep',10:'Okt',11:'Nov',12:'Dez' } )
  137. # fig.update_xaxes( labelalias = dict( 2="Saturday", Sun="Sunday") )
  138. # fig.update_xaxes(
  139. # tickangle = 90,
  140. # title_text = "Month",
  141. # title_font = {"size": 20},
  142. # title_standoff = 25)
  143. return(fig)
  144. def monthly_sum_barchart_concurrent (datafield, factor, heading, y_axis, x_axis):
  145. df = read_data()
  146. df = df.reset_index().drop('index', axis=1, errors='ignore')
  147. df['month'] = df['startTimeLocal'].dt.month
  148. df['year'] = df['startTimeLocal'].dt.year
  149. df = df.reset_index().drop('index', axis=1, errors='ignore')
  150. #df.columns = [str(c) for c in df.columns] # update columns to strings in case they are numbers
  151. grouped_df = df.groupby(by=["month", "year"], as_index=False).agg( {"elevationGain": "sum"} )
  152. grouped_df.year = grouped_df['year'].apply(str)
  153. grouped_df.sort_values(by=['year'], inplace=True)
  154. # print(data.head())
  155. fig = px.bar(
  156. data_frame=grouped_df,
  157. x="month",
  158. y="elevationGain",
  159. color="year",
  160. barmode="group",
  161. )
  162. return(fig)
  163. def homepage_data (csv_file):
  164. df2 = read_data(csv_file)
  165. df2['startzeit'] = df2.index
  166. df = df2.sort_values(by="startzeit",ascending=True).set_index("startzeit")
  167. df['startzeit'] = df.index
  168. df['startTimeLocal'] = df.index
  169. wf = df.groupby([pd.Grouper(key='startTimeLocal', freq='W')]).aggregate({
  170. 'elevationGain': sum,
  171. 'distance': sum,
  172. 'averageHR':np.mean,
  173. 'maxHR':np.max,
  174. 'movingDuration': sum,
  175. 'intensityMinutes': sum
  176. })
  177. mf = df.groupby([pd.Grouper(key='startzeit', freq='MS')]).aggregate({
  178. 'elevationGain': sum,
  179. 'distance': sum,
  180. 'averageHR':np.mean,
  181. 'maxHR':np.max,
  182. 'movingDuration': sum,
  183. 'intensityMinutes': sum
  184. })
  185. yf = df.groupby([pd.Grouper(key='startzeit', freq='YS')]).aggregate({
  186. 'elevationGain': sum,
  187. 'distance': sum,
  188. 'averageHR':np.mean,
  189. 'maxHR':np.max,
  190. 'movingDuration': sum,
  191. 'intensityMinutes': sum
  192. })
  193. d = { 'elevationtotal' : df['elevationGain'].sum(),
  194. 'elevation0y' : yf['elevationGain'].take([-1])[0],
  195. 'elevation1y' : yf['elevationGain'].take([-2])[0],
  196. 'elevation1m' : mf['elevationGain'].take([-2])[0],
  197. 'elevation0m' : mf['elevationGain'].take([-1])[0],
  198. 'elevation1w' : wf['elevationGain'].take([-2])[0],
  199. 'elevation0w' : wf['elevationGain'].take([-1])[0],
  200. # '0w' : wf.take([-1]).keys,
  201. 'distancetotal' : round(df['distance'].sum(), 1),
  202. 'distance0y' : round(yf['distance'].take([-1])[0], 1),
  203. 'distance1y' : round(yf['distance'].take([-2])[0], 1),
  204. 'distance1m' : round(mf['distance'].take([-2])[0], 1),
  205. 'distance0m' : round(mf['distance'].take([-1])[0], 1),
  206. 'distance1w' : round(wf['distance'].take([-2])[0], 1),
  207. 'distance0w' : round(wf['distance'].take([-1])[0], 1),
  208. 'durationtotal' : sec2time(df['movingDuration'].sum(), 0),
  209. 'duration0y' : sec2time(yf['movingDuration'].take([-1])[0], 0),
  210. 'duration1y' : sec2time(yf['movingDuration'].take([-2])[0], 0),
  211. 'duration1m' : sec2time(mf['movingDuration'].take([-2])[0], 0),
  212. 'duration0m' : sec2time(mf['movingDuration'].take([-1])[0], 0),
  213. 'duration1w' : sec2time(wf['movingDuration'].take([-2])[0], 0),
  214. 'duration0w' : sec2time(wf['movingDuration'].take([-1])[0], 0),
  215. 'averageHRtotal' : round(df['averageHR'].mean()),
  216. 'averageHR0y' : safe_round(df['averageHR'].take([-1])[0]),
  217. 'averageHR1y' : safe_round(df['averageHR'].take([-2])[0]),
  218. 'averageHR1m' : safe_round(mf['averageHR'].take([-2])[0]),
  219. 'averageHR0m' : safe_round(mf['averageHR'].take([-1])[0]),
  220. 'averageHR1w' : round_float(wf['averageHR'].take([-2])[0]),
  221. 'averageHR0w' : round_float(wf['averageHR'].take([-1])[0]),
  222. 'maxHRtotal' : round(df['maxHR'].max()),
  223. 'maxHR0y' : safe_round(df['maxHR'].take([-1])[0]),
  224. 'maxHR1y' : safe_round(df['maxHR'].take([-2])[0]),
  225. 'maxHR1m' : safe_round(mf['maxHR'].take([-2])[0]),
  226. 'maxHR0m' : safe_round(mf['maxHR'].take([-1])[0]),
  227. 'maxHR1w' : round_float(wf['maxHR'].take([-2])[0]),
  228. 'maxHR0w' : round_float(wf['maxHR'].take([-1])[0]),
  229. 'intensityMinutestotal' : round(df['intensityMinutes'].sum()),
  230. 'intensityMinutes0y' : round(yf['intensityMinutes'].take([-1])[0]),
  231. 'intensityMinutes1y' : round(yf['intensityMinutes'].take([-2])[0]),
  232. 'intensityMinutes1m' : round(mf['intensityMinutes'].take([-2])[0]),
  233. 'intensityMinutes0m' : round(mf['intensityMinutes'].take([-1])[0]),
  234. 'intensityMinutes1w' : round(wf['intensityMinutes'].take([-2])[0]),
  235. 'intensityMinutes0w' : round(wf['intensityMinutes'].take([-1])[0]),
  236. }
  237. return(d)
  238. if __name__ == "__main__":
  239. # render_monthly_sum_barchart ('elevationGain')
  240. #print(render_homepage_data())
  241. print(monthly_sum_barchart_concurrent2('elevationGain', 1, 'Höhenmeter pro Monat', '(m)', 'Monat', 'grouptitle'))