diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index faa5c3c0..aa884ea1 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -2049,21 +2049,70 @@ def leaflet_chart(lat,lon,name=""): return script,div -def leaflet_chart_compare(workoutids,labeldict={},startenddict={}): +def leaflet_chart_compare(course,workoutids,labeldict={},startenddict={}): data = [] for id in workoutids: w = Workout.objects.get(id=id) rowdata = rdata(w.csvfilename) + time = rowdata.df['TimeStamp (sec)'] df = pd.DataFrame({ - 'id':id, + 'workoutid':id, 'lat':rowdata.df[' latitude'], - 'lon':rowdata.df[' longitude'] + 'lon':rowdata.df[' longitude'], + 'time':time-time[0], }) - data.append(f) + data.append(df) df = pd.concat(data,axis=0) + latmean,lonmean,coordinates = course_coord_center(course) + lat_min, lat_max, long_min, long_max = course_coord_maxmin(course) + + coordinates = course_spline(coordinates) + + + + polygons = GeoPolygon.objects.filter(course=course).order_by("order_in_course") + + plabels = '' + + for p in polygons: + coords = polygon_coord_center(p) + + plabels += """ + var marker = L.marker([{latbegin}, {longbegin}]).addTo(mymap); + marker.bindPopup("{name}"); + + """.format( + latbegin = coords[0], + longbegin = coords[1], + name = p.name + ) + + pcoordinates = """[ + """ + + for p in polygons: + pcoordinates += """[ + [""" + + points = GeoPoint.objects.filter(polygon=p).order_by("order_in_poly") + + for pt in points: + pcoordinates += "[{x},{y}],".format( + x = pt.latitude, + y = pt.longitude + ) + + # remove last comma + pcoordinates = pcoordinates[:-1] + pcoordinates += """] + ], + """ + + pcoordinates += """ + ]""" # Throw out 0,0 @@ -2071,25 +2120,26 @@ def leaflet_chart_compare(workoutids,labeldict={},startenddict={}): df = df.loc[(df!=0).any(axis=1)] df.fillna(method='bfill',axis=0,inplace=True) df.fillna(method='ffill',axis=0,inplace=True) + + + lat = df['lat'] lon = df['lon'] if lat.empty or lon.empty: return [0,"invalid coordinate data"] + latbegin = lat.values[0] + longbegin = lon.values[0] + latend = lat.values[-1] + longend = lon.values[-1] + + colors = itertools.cycle(palette) + try: + items = itertools.izip(workoutids,colors) + except AttributeError: + items = zip(workoutids,colors) - coordinates = zip(lat,lon) - - scoordinates = "[" - - for x,y in coordinates: - scoordinates += """[{x},{y}], - """.format( - x=x, - y=y - ) - - scoordinates += "]" script = """ """.format( latmean=latmean, lonmean=lonmean, @@ -2179,9 +2225,69 @@ def leaflet_chart_compare(workoutids,labeldict={},startenddict={}): latend=latend, longbegin=longbegin, longend=longend, - scoordinates=scoordinates, + pcoordinates=pcoordinates, + plabels=plabels, ) + for id,color in items: + group = df[df['workoutid']==int(id)].copy() + try: + startsecond,endsecond = startenddict[id] + except KeyError: + startsecond = 0 + endsecond = 0 + + try: + label = labeldict[id] + except KeyError: + label = str(id) + + group.sort_values(by='time',ascending=True,inplace=True) + group.dropna(axis=0,how='any',inplace=True) + if endsecond > 0: + group['time'] = group['time'] - startsecond + mask = group['time'] < 0 + group.mask(mask,inplace=True) + mask = group['time'] > (endsecond-startsecond) + group.mask(mask,inplace=True) + + lat = group['lat'].dropna() + lon = group['lon'].dropna() + + coordinates = zip(lat,lon) + + scoordinates = "[" + for x,y in coordinates: + scoordinates += """[{x},{y}], + """.format(x=x,y=y) + scoordinates += "]" + + script += """ + var latlongs = {scoordinates} + var polyline = L.polyline(latlongs, {{color:'{color}'}}).addTo(mymap) + polyline.bindPopup("{label}",{{ autoPan: false, autoClose: false }}).openPopup() + polyline.on('mouseover',function(ev) {{ + ev.target.openPopup(); + }}); + polyline.on('dblclick', function (e) {{ + mymap.removeLayer(this); + }}); + mymap.fitBounds(polyline.getBounds()) + """.format( + scoordinates=scoordinates, + color=color, + label=label, + id=id, + ) + + script += """ + + + """ + + + + div = """

 

""" diff --git a/rowers/templates/mapcompare.html b/rowers/templates/mapcompare.html index e9ca1e92..88a1db29 100644 --- a/rowers/templates/mapcompare.html +++ b/rowers/templates/mapcompare.html @@ -1,6 +1,12 @@ {% extends "newbase.html" %} {% load staticfiles %} {% load rowerfilters %} +{% load leaflet_tags %} + +{% block meta %} +{% leaflet_js %} +{% leaflet_css %} +{% endblock %} {% block title %}View Comparison {% endblock %} @@ -11,32 +17,17 @@ Bokeh.set_log_level("info"); -{{ interactiveplot |safe }} +

Course Map Comparison

-

Interactive Comparison

+

Click on a line to see the label. Double click on a line to remove it. Reload to get back all lines.

+

We show your original GPS coordinates on the course. For course time, we use a finer interpolation, to get + the exact time when you crossed the line.

- -
    -
  • -
    - {{ the_div|safe }} +
    + {{ mapdiv|safe }} + {{ mapscript|safe }}
    -
  • -
  • -
    - {% csrf_token %} - - {{ chartform.as_table }} -
    - -

    - -

    -
    -
  • -
- {% endblock %} diff --git a/rowers/templates/virtualevent.html b/rowers/templates/virtualevent.html index 86e61402..3b8c6c57 100644 --- a/rowers/templates/virtualevent.html +++ b/rowers/templates/virtualevent.html @@ -377,6 +377,10 @@

Compare Results + {% if race.sessiontype == 'race' %} + Compare Course + {% endif %}

{% if race.manager == request.user %} \b[0-9A-Fa-f]+\b)/wind/$',views.workout_wind_view,name='workout_wind_view'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/image/$',views.workout_uploadimage_view,name='workout_uploadimage_view'), re_path(r'^virtualevent/(?P\d+)/compare/$',views.virtualevent_compare_view,name='virtualevent_compare_view'), + re_path(r'^virtualevent/(?P\d+)/mapcompare/$',views.virtualevent_mapcompare_view, + name='virtualevent_mapcompare_view'), re_path(r'^virtualevent/(?P\d+)/image/$', views.virtualevent_uploadimage_view,name='virtualevent_uploadimage_view'), re_path(r'^virtualevent/(?P\d+)/setimage/(?P\d+)/$', diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index 40be42c1..88d75939 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -1491,6 +1491,97 @@ def team_comparison_select(request, 'teams':get_my_teams(request.user), }) +def virtualevent_mapcompare_view(request,id=0): + results = [] + + r = None + if not request.user.is_anonymous: + r = getrower(request.user) + + try: + race = VirtualRace.objects.get(id=id) + except VirtualRace.DoesNotExist: + raise Http404("Virtual Challenge does not exist") + + if race.sessiontype != 'race': + url = reverse(virtualevent_view,kwargs={'id':id}) + messages.error(request,"This challenge doesn't have map data") + return HttpResponseRedirect(request) + + results = VirtualRaceResult.objects.filter( + race=race, + workoutid__isnull=False, + coursecompleted=True, + ).order_by("distance","duration") + + workoutids = [result.workoutid for result in results] + + startenddict = {} + if race.sessiontype == 'race': + for result in results: + startenddict[result.workoutid] = (result.startsecond,result.endsecond) + + if len(workoutids) == 0: + url = reverse('virtualevent_view', + kwargs={ + 'id':race.id, + }) + + messages.info(request,'There are no results to display') + + return HttpResponseRedirect(url) + + workouts = [] + for id in workoutids: + try: + workouts.append(Workout.objects.get(id=id)) + except Workout.DoesNotExist: + pass + + labeldict = { + int(w.id): w.__str__() for w in workouts + } + + script,div = leaflet_chart_compare(race.course,workoutids, + labeldict=labeldict, + startenddict=startenddict) + + breadcrumbs = [ + { + 'url': reverse('virtualevents_view'), + 'name': 'Racing' + }, + { + 'url':reverse('virtualevent_view', + kwargs={ + 'id':race.id, + } + ), + 'name': race.name + }, + { + 'url':reverse('virtualevent_mapcompare_view', + kwargs={ + 'id':race.id, + } + ), + 'name': 'Course Compare' + } + ] + + + return render(request,'mapcompare.html', + {'mapscript':script, + 'mapdiv':div, + 'breadcrumbs':breadcrumbs, + 'rower':r, + 'race':race, + 'results':results, + 'active':'nav-racing', + 'teamid':0, + 'teams':[] + }) + def virtualevent_compare_view(request,id=0): results = [] @@ -1506,7 +1597,7 @@ def virtualevent_compare_view(request,id=0): try: race = VirtualRace.objects.get(id=id) except VirtualRace.DoesNotExist: - raise Http404("Virtual Race does not exist") + raise Http404("Virtual Challenge does not exist") if race.sessiontype == 'race': script,div = course_map(race.course) @@ -1531,6 +1622,8 @@ def virtualevent_compare_view(request,id=0): + + if len(workoutids) == 0: url = reverse('virtualevent_view', kwargs={