From 92c133bbd528d03010f74c6dbb1719298c208e46 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 6 Mar 2024 17:20:29 +0100 Subject: [PATCH] adding video charts --- rowers/interactiveplots.py | 546 ++----------------- rowers/templates/course_edit_view.html | 5 +- rowers/templates/course_replace.html | 5 +- rowers/templates/course_replace_confirm.html | 4 +- rowers/templates/course_view.html | 5 +- rowers/templates/coursemap.html | 4 +- rowers/templates/map_view.html | 5 +- rowers/templates/mapcompare.html | 4 +- rowers/templates/multicompare.html | 4 +- rowers/templates/panel_map.html | 5 +- rowers/templates/windedit.html | 4 +- rowers/templates/workout_form.html | 4 +- rowers/templates/workout_view.html | 5 +- rowers/views/workoutviews.py | 17 +- 14 files changed, 74 insertions(+), 543 deletions(-) diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index 73b041c5..ad456ad2 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -2211,8 +2211,13 @@ def course_map(course): def leaflet_chart(lat, lon, name="", raceresult=0): - if lat.empty or lon.empty: # pragma: no cover - return [0, "invalid coordinate data"] + try: + if lat.empty or lon.empty: # pragma: no cover + return [0, "invalid coordinate data"] + except AttributeError: + if not len(lat) or not len(lon): # pragma: no cover + return [0, "invalid coordinate data"] + # Throw out 0,0 df = pd.DataFrame({ @@ -2286,56 +2291,9 @@ def leaflet_chart_compare(course, workoutids, labeldict={}, startenddict={}): except ValueError: # pragma: no cover df = pd.DataFrame() - mapdata = { - 'trajectories': df.reset_index().to_json() - } - 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 += """ - ]""" + course_dict = GeoCourseSerializer(course).data # Throw out 0,0 df = df.replace(0, np.nan) @@ -2357,89 +2315,7 @@ def leaflet_chart_compare(course, workoutids, labeldict={}, startenddict={}): except AttributeError: items = zip(workoutids, colors) - script = """ - - """ - - div = """ -

 

- """ + mapdata = { + 'course': course_dict, + 'latmean': latmean, + 'lonmean': lonmean, + 'trajectories': trajectories, + } + + script, div = get_chart("/mapcompare", mapdata) return script, div -def leaflet_chart2(lat, lon, name=""): - if lat.empty or lon.empty: # pragma: no cover - return [0, "invalid coordinate data"] - # Throw out 0,0 - df = pd.DataFrame({ - 'lat': lat, - 'lon': lon - }) - - df = df.replace(0, np.nan) - 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: # pragma: no cover - return [0, "invalid coordinate data"] - - latmean = lat.mean() - lonmean = lon.mean() - latbegin = lat[lat.index[0]] - longbegin = lon[lon.index[0]] - latend = lat[lat.index[-1]] - longend = lon[lon.index[-1]] - - 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, - latbegin=latbegin, - latend=latend, - longbegin=longbegin, - longend=longend, - scoordinates=scoordinates, - ) - - div = """ -

 

- """ - - return script, div - - -def leaflet_chart_video(lat, lon, name=""): - if not len(lat) or not len(lon): # pragma: no cover - return [0, "invalid coordinate data"] - - # Throw out 0,0 - df = pd.DataFrame({ - 'lat': lat, - 'lon': lon - }) - - df = df.replace(0, np.nan) - 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: # pragma: no cover - return [0, "invalid coordinate data"] - - latmean = lat.mean() - lonmean = lon.mean() - latbegin = lat[lat.index[0]] - longbegin = lon[lon.index[0]] - - coordinates = zip(lat, lon) - - scoordinates = "[" - - for x, y in coordinates: - scoordinates += """[{x},{y}], - """.format( - x=x, - y=y - ) - - scoordinates += "]" - - script = """ - - - var streets = L.tileLayer( - 'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{ - attribution: '© Mapbox © OpenStreetMap Improve this map', - tileSize: 512, - maxZoom: 18, - zoomOffset: -1, - id: 'mapbox/streets-v11', - accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA' -}} - ), - - satellite = L.tileLayer( - 'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{ - attribution: '© Mapbox © OpenStreetMap Improve this map', - tileSize: 512, - maxZoom: 18, - zoomOffset: -1, - id: 'mapbox/satellite-v9', - accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA' -}} - ), - - outdoors = L.tileLayer( - 'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{ - attribution: '© Mapbox © OpenStreetMap Improve this map', - tileSize: 512, - maxZoom: 18, - zoomOffset: -1, - id: 'mapbox/outdoors-v11', - accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA' -}} - ); - - - - var mymap = L.map('map_canvas', {{ - center: [{latmean}, {lonmean}], - zoom: 13, - layers: [streets, satellite] - }}).setView([{latmean},{lonmean}], 13); - - var navionics = new JNC.Leaflet.NavionicsOverlay({{ - navKey: 'Navionics_webapi_03205', - chartType: JNC.NAVIONICS_CHARTS.NAUTICAL, - isTransparent: true, - zIndex: 1 - }}); - - - var osmUrl2='http://tiles.openseamap.org/seamark/{{z}}/{{x}}/{{y}}.png'; - var osmUrl='http://{{s}}.tile.openstreetmap.org/{{z}}/{{x}}/{{y}}.png'; - - - //create two TileLayer - var nautical=new L.TileLayer(osmUrl,{{ - maxZoom:18}}); - - - L.control.layers({{ - "Streets": streets, - "Satellite": satellite, - "Outdoors": outdoors, - "Nautical": nautical, - }},{{ - "Navionics":navionics, - }}, - {{ - position:'topleft' - }}).addTo(mymap); - - var marker = L.marker([{latbegin}, {longbegin}]).addTo(mymap); - marker.bindPopup("Start"); - - var latlongs = {scoordinates} - var polyline = L.polyline(latlongs, {{color:'red'}}).addTo(mymap) - mymap.fitBounds(polyline.getBounds()) - - """.format( - latmean=latmean, - lonmean=lonmean, - latbegin=latbegin, - longbegin=longbegin, - scoordinates=scoordinates, - ) - - div = """ -

 

- """ - - return script, div def interactive_agegroupcpchart(age, normalized=False): @@ -4272,12 +3866,10 @@ def interactive_chart_video(videodata): data = zip(time, spm) - data2 = "[" + data2 = [] for t, s in data: - data2 += "{x: %s, y: %s}, " % (t, s) - - data2 = data2[:-2] + "]" + data2.append( {'x': t, 'y': s}) markerpoint = { 'x': time[0], @@ -4285,89 +3877,13 @@ def interactive_chart_video(videodata): 'r': 10, } - div = """ - - - """ - - script = """ - var ctx = document.getElementById("myChart").getContext('2d'); - var data = %s - - var myChart = new Chart(ctx, { - type: 'scatter', - label: 'SPM', - animationSteps: 10, - options: { - legend: { - display: false, - }, - animation: { - duration: 100, - }, - scales: { - yAxes: [{ - scaleLabel: { - display: true, - labelString: 'Stroke Rate' - } - }], - xAxes: [{ - scaleLabel: { - type: 'linear', - display: true, - labelString: 'Time (seconds)' - } - }], - } - }, - data: - { - datasets: [ - { - type: 'bubble', - label: 'now', - data: [ %s ], - backgroundColor: '#36a2eb', - }, - { - label: 'spm', - data: data, - backgroundColor: "#ff0000", - borderColor: "#ff0000", - fill: false, - borderDash: [0, 0], - pointRadius: 1, - pointHoverRadius: 1, - showLine: true, - tension: 0, - }, - - ] - }, - - }); - - var marker = { - datapoint: %s , - setLatLng: function (LatLng) { - var lat = LatLng.lat; - var lng = LatLng.lng; - this.datapoint = { - 'x': lat, - 'y': lng, - 'r': 10, - } - myChart.data.datasets[0].data[0] = this.datapoint; - myChart.update(); + chart_data = { + 'data': data2, + 'markerpoint': markerpoint, } - } - marker.setLatLng({ - 'lat': data[0]['x'], - 'lng': data[0]['y'] - }) - """ % (data2, markerpoint, markerpoint) + + script, div = get_chart("/videochart", chart_data) return [script, div] diff --git a/rowers/templates/course_edit_view.html b/rowers/templates/course_edit_view.html index 58b2cb64..29be3f99 100644 --- a/rowers/templates/course_edit_view.html +++ b/rowers/templates/course_edit_view.html @@ -32,8 +32,9 @@
{{ mapdiv|safe }} - - {{ mapscript|safe }} +
diff --git a/rowers/templates/course_replace.html b/rowers/templates/course_replace.html index 53569c1f..067c90ff 100644 --- a/rowers/templates/course_replace.html +++ b/rowers/templates/course_replace.html @@ -37,8 +37,9 @@
{{ mapdiv|safe }} - - {{ mapscript|safe }} +
diff --git a/rowers/templates/course_replace_confirm.html b/rowers/templates/course_replace_confirm.html index 965b9180..c057f2c1 100644 --- a/rowers/templates/course_replace_confirm.html +++ b/rowers/templates/course_replace_confirm.html @@ -45,7 +45,9 @@
  • {{ mapdiv|safe }} - {{ mapscript|safe }} +
  • diff --git a/rowers/templates/course_view.html b/rowers/templates/course_view.html index 37cb41d9..e3f2db0b 100644 --- a/rowers/templates/course_view.html +++ b/rowers/templates/course_view.html @@ -39,8 +39,9 @@
    {{ mapdiv|safe }} - - {{ mapscript|safe }} +
    {% if records %} diff --git a/rowers/templates/coursemap.html b/rowers/templates/coursemap.html index d926f731..196ce47f 100644 --- a/rowers/templates/coursemap.html +++ b/rowers/templates/coursemap.html @@ -19,7 +19,9 @@

    {{ course.name }}

    {{ mapdiv|safe }} - {{ mapscript|safe }} +
    {% endblock %} diff --git a/rowers/templates/map_view.html b/rowers/templates/map_view.html index 17eedd47..7938fe02 100644 --- a/rowers/templates/map_view.html +++ b/rowers/templates/map_view.html @@ -26,8 +26,9 @@
    {{ mapdiv|safe }} - - {{ mapscript|safe }} + diff --git a/rowers/templates/mapcompare.html b/rowers/templates/mapcompare.html index a00044a6..52b582b4 100644 --- a/rowers/templates/mapcompare.html +++ b/rowers/templates/mapcompare.html @@ -25,7 +25,9 @@
    {{ mapdiv|safe }} - {{ mapscript|safe }} +
    diff --git a/rowers/templates/multicompare.html b/rowers/templates/multicompare.html index 59ddd994..7b5a8415 100644 --- a/rowers/templates/multicompare.html +++ b/rowers/templates/multicompare.html @@ -11,8 +11,10 @@ Bokeh.set_log_level("info"); + +

    Interactive Comparison

    diff --git a/rowers/templates/panel_map.html b/rowers/templates/panel_map.html index 8e45af39..25941388 100644 --- a/rowers/templates/panel_map.html +++ b/rowers/templates/panel_map.html @@ -3,8 +3,9 @@
    {{ mapdiv|safe }} - - {{ mapscript|safe }} +
    diff --git a/rowers/templates/windedit.html b/rowers/templates/windedit.html index 25e4e74e..26322e6e 100644 --- a/rowers/templates/windedit.html +++ b/rowers/templates/windedit.html @@ -67,7 +67,9 @@
    {{ gmapdiv |safe }} - {{ gmap |safe }} +
    diff --git a/rowers/templates/workout_form.html b/rowers/templates/workout_form.html index a95424f6..f3d6c3f0 100644 --- a/rowers/templates/workout_form.html +++ b/rowers/templates/workout_form.html @@ -217,9 +217,9 @@
    {{ mapdiv|safe }}
    - + {% endif %} {% for graph in graphs %} diff --git a/rowers/templates/workout_view.html b/rowers/templates/workout_view.html index bfb12fe2..af45ac7e 100644 --- a/rowers/templates/workout_view.html +++ b/rowers/templates/workout_view.html @@ -131,8 +131,9 @@ {{ mapdiv|safe }} - - {{ mapscript|safe }} +
    {% endif %} diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index b22a7da4..61e3b86d 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -126,8 +126,7 @@ def workout_video_view_mini(request, id=''): hascoordinates = pd.Series(data['latitude']).std() > 0 # create map if hascoordinates and mode == 'water': - mapscript, mapdiv = leaflet_chart_video(data['latitude'], data['longitude'], - w.name) + mapscript, mapdiv = leaflet_chart(data['latitude'], data['longitude']) else: mapscript, mapdiv = interactive_chart_video(data) data['longitude'] = data['spm'] @@ -237,8 +236,7 @@ def workout_video_view(request, id=''): hascoordinates = pd.Series(data['latitude']).std() > 0 # create map if hascoordinates and mode == 'water': - mapscript, mapdiv = leaflet_chart_video(data['latitude'], data['longitude'], - w.name) + mapscript, mapdiv = leaflet_chart(data['latitude'], data['longitude']) else: mapscript, mapdiv = interactive_chart_video(data) data['longitude'] = data['spm'] @@ -353,8 +351,7 @@ def workout_video_create_view(request, id=0): # create map if hascoordinates and mode == 'water': - mapscript, mapdiv = leaflet_chart_video(data['latitude'], data['longitude'], - w.name) + mapscript, mapdiv = leaflet_chart(data['latitude'], data['longitude']) else: mapscript, mapdiv = interactive_chart_video(data) data['longitude'] = data['spm'] @@ -4141,7 +4138,7 @@ def workout_workflow_view(request, id): if 'panel_map.html' in r.workflowmiddlepanel and rowhascoordinates(row): rowdata = rdata(csvfile=row.csvfilename) - mapscript, mapdiv = leaflet_chart2(rowdata.df[' latitude'], + mapscript, mapdiv = leaflet_chart(rowdata.df[' latitude'], rowdata.df[' longitude'], row.name) else: @@ -4182,6 +4179,8 @@ def workout_workflow_view(request, id): ] + print(middleTemplates) + return render(request, 'workflow.html', { @@ -5063,7 +5062,7 @@ def workout_map_view(request, id=0): hascoordinates = 0 if hascoordinates: - mapscript, mapdiv = leaflet_chart2(rowdata.df[' latitude'], + mapscript, mapdiv = leaflet_chart(rowdata.df[' latitude'], rowdata.df[' longitude'], w.name) else: @@ -5188,7 +5187,7 @@ def workout_uploadimage_view(request, id): # pragma: no cover # Generic chart creation @permission_required('workout.change_workout', fn=get_workout_by_opaqueid, raise_exception=True) def workout_add_chart_view(request, id, plotnr=1): - + w = get_workoutuser(id, request) r = getrower(request.user)