added activity chart
This commit is contained in:
@@ -12,7 +12,7 @@ from bokeh.palettes import Dark2_8 as palette
|
|||||||
import itertools
|
import itertools
|
||||||
from bokeh.plotting import figure, ColumnDataSource, Figure,curdoc
|
from bokeh.plotting import figure, ColumnDataSource, Figure,curdoc
|
||||||
from bokeh.models import CustomJS,Slider, TextInput,BoxAnnotation
|
from bokeh.models import CustomJS,Slider, TextInput,BoxAnnotation
|
||||||
from bokeh.charts import Histogram,HeatMap,Area,BoxPlot
|
from bokeh.charts import Histogram,HeatMap,Area,BoxPlot,Bar
|
||||||
from bokeh.resources import CDN,INLINE
|
from bokeh.resources import CDN,INLINE
|
||||||
from bokeh.embed import components
|
from bokeh.embed import components
|
||||||
from bokeh.layouts import layout,widgetbox
|
from bokeh.layouts import layout,widgetbox
|
||||||
@@ -219,6 +219,63 @@ def interactive_boxchart(datadf,fieldname,extratitle=''):
|
|||||||
return script,div
|
return script,div
|
||||||
|
|
||||||
|
|
||||||
|
def interactive_activitychart(workouts,startdate,enddate):
|
||||||
|
if len(workouts) == 0:
|
||||||
|
return "",""
|
||||||
|
|
||||||
|
dates = []
|
||||||
|
types = []
|
||||||
|
durations = []
|
||||||
|
|
||||||
|
for w in workouts:
|
||||||
|
if w.privacy == 'visible':
|
||||||
|
dd = w.date.strftime('%m/%d')
|
||||||
|
du = w.duration.hour*60+w.duration.minute
|
||||||
|
dates.append(dd)
|
||||||
|
durations.append(du)
|
||||||
|
types.append(w.workouttype)
|
||||||
|
|
||||||
|
d = startdate
|
||||||
|
|
||||||
|
while d<=enddate:
|
||||||
|
dates.append(d.strftime('%m/%d'))
|
||||||
|
durations.append(0)
|
||||||
|
types.append('rower')
|
||||||
|
d += datetime.timedelta(days=1)
|
||||||
|
|
||||||
|
|
||||||
|
df = pd.DataFrame({
|
||||||
|
'date':dates,
|
||||||
|
'duration':durations,
|
||||||
|
'type':types,
|
||||||
|
})
|
||||||
|
|
||||||
|
p = Bar(df,'date',values='duration',title='Activity',
|
||||||
|
stack='type',
|
||||||
|
plot_width=350,
|
||||||
|
plot_height=250,
|
||||||
|
toolbar_location = None,
|
||||||
|
)
|
||||||
|
|
||||||
|
for legend in p.legend:
|
||||||
|
new_items = []
|
||||||
|
for legend_item in legend.items:
|
||||||
|
it = legend_item.label['value']
|
||||||
|
tot = df[df['type']==it].duration.sum()
|
||||||
|
if tot != 0:
|
||||||
|
new_items.append(legend_item)
|
||||||
|
legend.items = new_items
|
||||||
|
|
||||||
|
|
||||||
|
p.legend.location = "top_left"
|
||||||
|
p.legend.background_fill_alpha = 0.7
|
||||||
|
|
||||||
|
p.yaxis.axis_label = 'Minutes'
|
||||||
|
|
||||||
|
script, div = components(p)
|
||||||
|
|
||||||
|
return script,div
|
||||||
|
|
||||||
def interactive_forcecurve(theworkouts,workstrokesonly=False):
|
def interactive_forcecurve(theworkouts,workstrokesonly=False):
|
||||||
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
|
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
|
||||||
|
|
||||||
|
|||||||
@@ -135,6 +135,35 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<div class="grid_4" id="interactiveplot">
|
||||||
|
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||||
|
<script async="true" type="text/javascript">
|
||||||
|
Bokeh.set_log_level("info");
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{ interactiveplot |safe }}
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Set things up to resize the plot on a window resize. You can play with
|
||||||
|
// the arguments of resize_width_height() to change the plot's behavior.
|
||||||
|
var plot_resize_setup = function () {
|
||||||
|
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
|
||||||
|
var plot = Bokeh.index[plotid];
|
||||||
|
var plotresizer = function() {
|
||||||
|
// arguments: use width, use height, maintain aspect ratio
|
||||||
|
plot.resize_width_height(true, true, true);
|
||||||
|
};
|
||||||
|
window.addEventListener('resize', plotresizer);
|
||||||
|
plotresizer();
|
||||||
|
};
|
||||||
|
window.addEventListener('load', plot_resize_setup);
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
|
||||||
|
html, body {height: 100%; margin:5px;}
|
||||||
|
</style>
|
||||||
|
{{ the_div |safe }}
|
||||||
|
</div>
|
||||||
<div class="grid_4" id="announcements">
|
<div class="grid_4" id="announcements">
|
||||||
{% if announcements %}
|
{% if announcements %}
|
||||||
<h3>What's New?</h3>
|
<h3>What's New?</h3>
|
||||||
|
|||||||
@@ -4015,7 +4015,7 @@ def workouts_view(request,message='',successmessage='',
|
|||||||
startdate = s
|
startdate = s
|
||||||
|
|
||||||
# start date for the small graph
|
# start date for the small graph
|
||||||
activity_startdate = enddate-datetime.timedelta(days=30)
|
activity_startdate = enddate-datetime.timedelta(days=15)
|
||||||
|
|
||||||
if teamid:
|
if teamid:
|
||||||
try:
|
try:
|
||||||
@@ -4076,6 +4076,10 @@ def workouts_view(request,message='',successmessage='',
|
|||||||
"-id"
|
"-id"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
script,div = interactive_activitychart(g_workouts,
|
||||||
|
activity_startdate,
|
||||||
|
enddate)
|
||||||
|
|
||||||
messages.info(request,successmessage)
|
messages.info(request,successmessage)
|
||||||
messages.error(request,message)
|
messages.error(request,message)
|
||||||
|
|
||||||
@@ -4087,6 +4091,8 @@ def workouts_view(request,message='',successmessage='',
|
|||||||
'announcements':announcements[0:4],
|
'announcements':announcements[0:4],
|
||||||
'team':theteam,
|
'team':theteam,
|
||||||
'teams':get_my_teams(request.user),
|
'teams':get_my_teams(request.user),
|
||||||
|
'interactiveplot':script,
|
||||||
|
'the_div':div,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user