From f1d90a7ce598b184a4aba039c5c163a0c89b5d82 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Sun, 10 May 2020 20:05:00 +0200 Subject: [PATCH 1/2] removed time info --- rowers/interactiveplots.py | 2 ++ rowers/templates/history.html | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index f1f79cbe..bc8a4c42 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -285,6 +285,8 @@ def interactive_workouttype_piechart(workouts): data['color'] = ['lightblue'] data['totaltime'] = pd.Series([pretty_timedelta(v) for v in data['value']]) + #print(data) + p = figure(plot_height=350, title="Types", toolbar_location=None, tools="hover,save", tooltips="@type: @totaltime", x_range=(-0.5, 1.0)) diff --git a/rowers/templates/history.html b/rowers/templates/history.html index 16e6984c..0e3af386 100644 --- a/rowers/templates/history.html +++ b/rowers/templates/history.html @@ -30,7 +30,7 @@
  • -

    History for {{ rower.user.first_name }} {{ rower.user.last_name }} from {{ startdate|date:"c" }} to {{ enddate|date:"c"}}

    +

    History for {{ rower.user.first_name }} {{ rower.user.last_name }}

  • Past 7 days From 6c4de553cb6ed3b418eba8bdef0e7bb28367bc43 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Sun, 10 May 2020 21:51:12 +0200 Subject: [PATCH 2/2] legends done --- rowers/interactiveplots.py | 192 +++++++++++++++++++++++++++++++--- rowers/mytypes.py | 6 ++ rowers/views/analysisviews.py | 3 +- 3 files changed, 186 insertions(+), 15 deletions(-) diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index bc8a4c42..d5abd874 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -267,9 +267,10 @@ def interactive_workouttype_piechart(workouts): for w in workouts: try: - label = mytypes.workouttypes_ordered[w.workouttype] + # label = mytypes.workouttypes_ordered[w.workouttype] + label = w.workouttype except KeyError: - labels = w.workouttype + label = w.workouttype try: datadict[label] += 60*(60*w.duration.hour+w.duration.minute)+w.duration.second except KeyError: @@ -277,15 +278,15 @@ def interactive_workouttype_piechart(workouts): data = pd.Series(datadict).reset_index(name='value').rename(columns={'index':'type'}) data['angle'] = data['value']/data['value'].sum() * 2*pi - if len(datadict)>2: - data['color'] = Category10[len(datadict)] - elif len(datadict)==2: - data['color'] = ['orange','lightblue'] - else: - data['color'] = ['lightblue'] - data['totaltime'] = pd.Series([pretty_timedelta(v) for v in data['value']]) - #print(data) + + + + data = pd.DataFrame(data) + data['color'] = data['type'].apply(lambda x:mytypes.color_map[x]) + data['totaltime'] = data['value'].apply(lambda x:pretty_timedelta(x)) + data['type'] = data['type'].apply(lambda x:mytypes.workouttypes_ordered[x]) + p = figure(plot_height=350, title="Types", toolbar_location=None, tools="hover,save", tooltips="@type: @totaltime", x_range=(-0.5, 1.0)) @@ -412,6 +413,7 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type',toolbar_lo durations = [] links = [] + rowersinitials = {} seen = ['seen'] idseen = [] @@ -458,6 +460,7 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type',toolbar_lo ) ) + types.append(w.workouttype) try: rowers.append(rowersinitials[w.user.id]) @@ -488,6 +491,7 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type',toolbar_lo durations.append(0) links.append('') types.append('rower') + try: rowers.append(rowers[0]) except IndexError: @@ -508,24 +512,24 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type',toolbar_lo 'link':links, } - types_ind = list(set(types)) - + dim_expr = hv.dim('type').categorize(mytypes.color_map) df = pd.DataFrame(thedict) source = ColumnDataSource(df) df.sort_values('date_sorting',inplace=True) + #clrs = hv.Cycle(df['colors'].values) hv.extension('bokeh') if stack == 'type': table = hv.Table(df,[('date','Date'),('type','Workout Type')],[('duration','Minutes'),('link','link')]) + else: table = hv.Table(df,[('date','Date'),('rower','Rower')],[('duration','Minutes'),('link','link')]) - bars=table.to.bars(['date',stack],['duration']) bars.opts( opts.Bars(color=hv.Cycle('Category10'), show_legend=True, stacked=True, @@ -550,6 +554,168 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type',toolbar_lo + callback = CustomJS(args={'links':df.link}, code=""" + var index = cb_data.source.selected['1d'].indices[0]; + console.log(links); + console.log(index); + console.log(links[index]); + window.location.href = links[index] + """) + + taptool.callback = callback + + + script,div = components(p) + return script,div + +def interactive_activitychart2(workouts,startdate,enddate,stack='type',toolbar_location=None): + + dates = [] + dates_sorting = [] + types = [] + rowers = [] + durations = [] + links = [] + + + rowersinitials = {} + seen = ['seen'] + idseen = [] + + startdate = datetime.datetime(year=startdate.year,month=startdate.month,day=startdate.day) + enddate = datetime.datetime(year=enddate.year,month=enddate.month,day=enddate.day) + + duration = enddate-startdate + + totaldays = duration.total_seconds()/(24*3600) + + + for w in workouts: + aantal=1 + initials = w.user.user.first_name[0:aantal]+w.user.user.last_name[0:aantal] + if w.user.id not in idseen: + while initials in seen: + aantal += 1 + initials = w.user.user.first_name[0:aantal]+w.user.user.last_name[0:aantal] + + seen.append(initials) + idseen.append(w.user.id) + rowersinitials[w.user.id] = initials + + + + for w in workouts: + dd = w.date.strftime('%m/%d') + dd2 = w.date.strftime('%Y/%m/%d') + dd3 = w.date.strftime('%Y/%m') + du = w.duration.hour*60+w.duration.minute + + if totaldays<30: + dates.append(dd) + dates_sorting.append(dd2) + else: + dates.append(dd3) + dates_sorting.append(dd3) + durations.append(du) + links.append( + "{siteurl}/rowers/workout/{code}/".format( + siteurl = settings.SITE_URL, + code = encoder.encode_hex(w.id) + ) + ) + + + types.append(w.workouttype) + try: + rowers.append(rowersinitials[w.user.id]) + except IndexError: + rowers.append(str(w.user)) + + try: + d = utc.localize(startdate) + except (ValueError,AttributeError): + d = startdate + + try: + enddate = utc.localize(enddate) + except (ValueError,AttributeError): + pass + + # add dates with no activity + while d<=enddate: + dd = d.strftime('%d') + + + if totaldays<30: + dates.append(d.strftime('%m/%d')) + dates_sorting.append(d.strftime('%Y/%m/%d')) + else: + dates.append(d.strftime('%Y/%m')) + dates_sorting.append(d.strftime('%Y/%m')) + durations.append(0) + links.append('') + types.append('rower') + + try: + rowers.append(rowers[0]) + except IndexError: + try: + rowers.append(str(workouts[0].user)) + except IndexError: + rowers.append(' ') + + d += datetime.timedelta(days=1) + + + thedict = { + 'date':dates, + 'date_sorting':dates_sorting, + 'duration':durations, + 'type':types, + 'rower':rowers, + 'link':links, + } + + dim_expr = hv.dim('type').categorize(mytypes.color_map) + + df = pd.DataFrame(thedict) + + + source = ColumnDataSource(df) + + df.sort_values('date_sorting',inplace=True) + #clrs = hv.Cycle(df['colors'].values) + + hv.extension('bokeh') + + + table = hv.Table(df,[('date','Date'),('type','Workout Type')],[('duration','Minutes'),('link','link')]) + + + bars=table.to.bars(['date',stack],['duration']) + bars.opts( + opts.Bars(color=dim_expr, show_legend=True, stacked=True, + tools=['tap','hover'], width=550, xrotation=45,padding=(0,(0,.1)), + legend_position='bottom',show_frame=True)) + + + + p = hv.render(bars) + + p.title.text = 'Activity {d1} to {d2}'.format( + d1 = startdate.strftime("%Y-%m-%d"), + d2 = enddate.strftime("%Y-%m-%d"), + ) + + p.plot_width=550 + p.plot_height=350 + p.toolbar_location = toolbar_location + p.sizing_mode = 'scale_width' + url = "http://rowsandall.com/rowers/workout/@duration/" + taptool = p.select(type=TapTool) + + + callback = CustomJS(args={'links':df.link}, code=""" var index = cb_data.source.selected['1d'].indices[0]; console.log(links); diff --git a/rowers/mytypes.py b/rowers/mytypes.py index e8b7aa9b..817884f4 100644 --- a/rowers/mytypes.py +++ b/rowers/mytypes.py @@ -270,6 +270,12 @@ rowtypes = ( checktypes = [i[0] for i in workouttypes] +from bokeh.palettes import Category10 + + +colors = Category10[9]+Category10[9]+Category10[9]+Category10[9] +color_map = {checktypes[i]:colors[i] for i in range(len(checktypes))} + workoutsources = ( ('strava','strava'), ('concept2','concept2'), diff --git a/rowers/views/analysisviews.py b/rowers/views/analysisviews.py index 4dfdc921..53cad48e 100644 --- a/rowers/views/analysisviews.py +++ b/rowers/views/analysisviews.py @@ -4783,7 +4783,6 @@ def history_view(request,userid=0): if firstmay>today: firstmay = datetime.datetime(year=today.year-1,month=5,day=1) - print(sstartdate,senddate,'history') return render(request,'history.html', { @@ -4923,7 +4922,7 @@ def history_view_data(request,userid=0): totalsdict['nrworkouts'] = g_workouts.count() # activity chart - activity_script, activity_div = interactive_activitychart(g_workouts,startdate,enddate) + activity_script, activity_div = interactive_activitychart2(g_workouts,startdate,enddate) # interactive hr pie chart if typeselect == 'All':