ssscoring.mapview
1# See: https://github.com/pr3d4t0r/SSScoring/blob/master/LICENSE.txt 2 3from geopy import distance 4from ssscoring.constants import SAMPLE_RATE 5from ssscoring.constants import SCORING_INTERVAL 6from ssscoring.datatypes import JumpResults 7from ssscoring.notebook import SPEED_COLORS 8from ssscoring.notebook import convertHexColorToRGB 9 10import pandas as pd 11import pydeck as pdk 12 13 14# *** constants *** 15 16DISTANCE_FROM_MIDDLE = 400.0 17""" 18The distance in meters from the middle of the skydive to the outer bounding box 19for the initial view of a new rendered map. 20""" 21 22 23# *** implementation *** 24 25def viewPointBox(data: pd.DataFrame) -> pd.DataFrame: 26 """ 27 Calculate the NW and SE corners of a "box" delimiting the viewport area 28 `DISTANCE_FROM_MIDDLE` meters away from the middle of the speed skydive. 29 30 Arguments 31 --------- 32 data 33 A SSScoring dataframe with jump data. 34 35 Returns 36 ------- 37 The NW and SE corners of the box, as terrestrial coordinates, in a dataframe 38 with these columns: 39 40 - `latitude` 41 - `lontigude` 42 43 See 44 --- 45 `ssscoring.calc.convertFlySight2SSScoring` 46 """ 47 mid = len(data)//2 48 datum = data.iloc[mid] 49 origin = (datum.latitude, datum.longitude) 50 pointNW = distance.distance(meters=DISTANCE_FROM_MIDDLE).destination(origin, bearing=315) 51 pointSE = distance.distance(meters=DISTANCE_FROM_MIDDLE).destination(origin, bearing=135) 52 data = list(zip([ pointNW[0], pointSE[0], ], [ pointNW[1], pointSE[1], ])) 53 result = pd.DataFrame(data, columns=[ 'latitude', 'longitude', ]) 54 return result 55 56 57def _resolveMaxScoreTimeFrom(jumpResult: JumpResults) -> float: 58 scoreTime = jumpResult.scores[jumpResult.score] 59 workData = jumpResult.data.reset_index(drop=True).copy() 60 ref = workData.index[workData.plotTime == scoreTime][0]+round(SCORING_INTERVAL/SAMPLE_RATE/2.0)-1 61 return workData.iloc[ref].plotTime 62 63 64def _resolveMaxSpeedTimeFrom(jumpResult: JumpResults) -> float: 65 rowIndex = jumpResult.data.vKMh.idxmax() 66 plotTime = jumpResult.data.loc[rowIndex, 'plotTime'] 67 return plotTime 68 69 70def speedJumpTrajectory(jumpResult: JumpResults, 71 displayScorePoint: bool=True) -> pdk.Deck: 72 """ 73 Build the layers for a PyDeck map showing a jumper's trajectory. 74 75 Arguments 76 --------- 77 jumpResult 78 A SSScoring `JumpResults` instance with the results of the jump. 79 80 Returns 81 ------- 82 A PyDeck `deck` instance ready for rendering using PyDeck or Streamlit 83 mapping facilities. 84 85 See 86 --- 87 `st.pydeck_chart` 88 `st.map` 89 """ 90 if jumpResult.data is not None and jumpResult.score != None and jumpResult.scores != None: 91 workData = jumpResult.data.copy() 92 scoresData = pd.DataFrame(list(jumpResult.scores.items()), columns=[ 'score', 'plotTime', ]) 93 workData = pd.merge(workData, scoresData, on='plotTime', how='left') 94 workData.vKMh = workData.vKMh.apply(lambda x: round(x, 2)) 95 workData.speedAngle = workData.speedAngle.apply(lambda x: round(x, 2)) 96 if displayScorePoint: 97 maxValueTime = _resolveMaxScoreTimeFrom(jumpResult) 98 maxColorOuter = [ 0, 255, 0, ] 99 maxCollorDot = [ 0, 128, 0, ] 100 else: 101 maxValueTime = _resolveMaxSpeedTimeFrom(jumpResult) 102 maxColorOuter = [ 255, 0, 0, 255, ] # red 103 maxCollorDot = [ 255, 255, 0, 255, ] # yellow 104 layers = [ 105 pdk.Layer( 106 'ScatterplotLayer', 107 data=workData.head(1), 108 get_color=[ 255, 126, 0, 255 ], 109 get_position=[ 'longitude', 'latitude', ], 110 get_radius=8), 111 pdk.Layer( 112 'ScatterplotLayer', 113 data=workData.tail(1), 114 get_color=[ 0, 192, 0, 160 ], 115 get_position=[ 'longitude', 'latitude', ], 116 get_radius=8), 117 pdk.Layer( 118 'ScatterplotLayer', 119 data=workData[workData.plotTime == maxValueTime], 120 get_color=maxColorOuter, 121 get_position=[ 'longitude', 'latitude', ], 122 get_radius=12), 123 pdk.Layer( 124 'ScatterplotLayer', 125 data=workData, 126 get_color=[ 0x64, 0x95, 0xed, 255 ], 127 get_position=[ 'longitude', 'latitude', ], 128 get_radius=2, 129 pickable=True), 130 pdk.Layer( 131 'ScatterplotLayer', 132 data=workData[workData.plotTime == maxValueTime], 133 get_color=maxCollorDot, 134 get_position=[ 'longitude', 'latitude', ], 135 get_radius=4), 136 ] 137 viewBox = viewPointBox(workData) 138 tooltip = { 139 # TODO: Figure out how to plot the score @ plotTime here. 140 # 'html': '<b>plotTime:</b> {plotTime} s<br><b>Score:</b> {score} km/h<br><b>Speed:</b> {vKMh} km/h<br><b>speedAngle:</b> {speedAngle}º', 141 'html': '<b>plotTime:</b> {plotTime} s<br><b>Speed:</b> {vKMh} km/h<br><b>speedAngle:</b> {speedAngle}º', 142 'style': { 143 'backgroundColor': 'steelblue', 144 'color': 'white', 145 }, 146 'cursor': 'default', 147 } 148 deck = pdk.Deck( 149 map_style = None, 150 layers=layers, 151 initial_view_state=pdk.data_utils.compute_view(viewBox[['longitude', 'latitude',]]), 152 tooltip=tooltip, 153 ) 154 return deck 155 156 157def multipleSpeedJumpsTrajectories(jumpResults): 158 """ 159 Build all the layers for a PyDeck map showing the trajectories of every jump 160 in the results set. 161 162 Arguments 163 --------- 164 jumpResults 165 A dictionary of all the jump results after processing. 166 167 Returns 168 ------- 169 A PyDeck `deck` instance ready for rendering using PyDeck or Streamlit 170 mapping facilities. 171 172 See 173 --- 174 `st.pydeck_chart` 175 `st.map` 176 """ 177 mapLayers = list() 178 mixColor = 0 179 for result in jumpResults.values(): 180 if result.scores != None: 181 workData = result.data.copy() 182 maxScoreTime = _resolveMaxScoreTimeFrom(result) 183 mixColor = (mixColor+1)%len(SPEED_COLORS) 184 layers = [ 185 pdk.Layer( 186 'ScatterplotLayer', 187 data=workData.head(1), 188 get_color=[ 255, 126, 0, 255 ], 189 get_position=[ 'longitude', 'latitude', ], 190 get_radius=8), 191 pdk.Layer( 192 'ScatterplotLayer', 193 data=workData.tail(1), 194 get_color=[ 0, 192, 0, 160 ], 195 get_position=[ 'longitude', 'latitude', ], 196 get_radius=8), 197 pdk.Layer( 198 'ScatterplotLayer', 199 data=workData[workData.plotTime == maxScoreTime], 200 get_color=[ 0, 255, 0, ], 201 get_position=[ 'longitude', 'latitude', ], 202 get_radius=12), 203 pdk.Layer( 204 'ScatterplotLayer', 205 data=workData, 206 get_color = convertHexColorToRGB(SPEED_COLORS[mixColor]), 207 get_position=[ 'longitude', 'latitude', ], 208 get_radius=2), 209 pdk.Layer( 210 'ScatterplotLayer', 211 data=workData[workData.plotTime == maxScoreTime], 212 get_color=[ 0, 128, 0, ], 213 get_position=[ 'longitude', 'latitude', ], 214 get_radius=4), 215 ] 216 mapLayers += layers 217 viewBox = viewPointBox(workData) 218 deck = pdk.Deck( 219 map_style = None, 220 initial_view_state=pdk.data_utils.compute_view(viewBox[['longitude', 'latitude',]]), 221 layers=mapLayers 222 ) 223 return deck
The distance in meters from the middle of the skydive to the outer bounding box for the initial view of a new rendered map.
26def viewPointBox(data: pd.DataFrame) -> pd.DataFrame: 27 """ 28 Calculate the NW and SE corners of a "box" delimiting the viewport area 29 `DISTANCE_FROM_MIDDLE` meters away from the middle of the speed skydive. 30 31 Arguments 32 --------- 33 data 34 A SSScoring dataframe with jump data. 35 36 Returns 37 ------- 38 The NW and SE corners of the box, as terrestrial coordinates, in a dataframe 39 with these columns: 40 41 - `latitude` 42 - `lontigude` 43 44 See 45 --- 46 `ssscoring.calc.convertFlySight2SSScoring` 47 """ 48 mid = len(data)//2 49 datum = data.iloc[mid] 50 origin = (datum.latitude, datum.longitude) 51 pointNW = distance.distance(meters=DISTANCE_FROM_MIDDLE).destination(origin, bearing=315) 52 pointSE = distance.distance(meters=DISTANCE_FROM_MIDDLE).destination(origin, bearing=135) 53 data = list(zip([ pointNW[0], pointSE[0], ], [ pointNW[1], pointSE[1], ])) 54 result = pd.DataFrame(data, columns=[ 'latitude', 'longitude', ]) 55 return result
Calculate the NW and SE corners of a "box" delimiting the viewport area
DISTANCE_FROM_MIDDLE
meters away from the middle of the speed skydive.
Arguments
data
A SSScoring dataframe with jump data.
Returns
The NW and SE corners of the box, as terrestrial coordinates, in a dataframe with these columns:
latitude
lontigude
See
71def speedJumpTrajectory(jumpResult: JumpResults, 72 displayScorePoint: bool=True) -> pdk.Deck: 73 """ 74 Build the layers for a PyDeck map showing a jumper's trajectory. 75 76 Arguments 77 --------- 78 jumpResult 79 A SSScoring `JumpResults` instance with the results of the jump. 80 81 Returns 82 ------- 83 A PyDeck `deck` instance ready for rendering using PyDeck or Streamlit 84 mapping facilities. 85 86 See 87 --- 88 `st.pydeck_chart` 89 `st.map` 90 """ 91 if jumpResult.data is not None and jumpResult.score != None and jumpResult.scores != None: 92 workData = jumpResult.data.copy() 93 scoresData = pd.DataFrame(list(jumpResult.scores.items()), columns=[ 'score', 'plotTime', ]) 94 workData = pd.merge(workData, scoresData, on='plotTime', how='left') 95 workData.vKMh = workData.vKMh.apply(lambda x: round(x, 2)) 96 workData.speedAngle = workData.speedAngle.apply(lambda x: round(x, 2)) 97 if displayScorePoint: 98 maxValueTime = _resolveMaxScoreTimeFrom(jumpResult) 99 maxColorOuter = [ 0, 255, 0, ] 100 maxCollorDot = [ 0, 128, 0, ] 101 else: 102 maxValueTime = _resolveMaxSpeedTimeFrom(jumpResult) 103 maxColorOuter = [ 255, 0, 0, 255, ] # red 104 maxCollorDot = [ 255, 255, 0, 255, ] # yellow 105 layers = [ 106 pdk.Layer( 107 'ScatterplotLayer', 108 data=workData.head(1), 109 get_color=[ 255, 126, 0, 255 ], 110 get_position=[ 'longitude', 'latitude', ], 111 get_radius=8), 112 pdk.Layer( 113 'ScatterplotLayer', 114 data=workData.tail(1), 115 get_color=[ 0, 192, 0, 160 ], 116 get_position=[ 'longitude', 'latitude', ], 117 get_radius=8), 118 pdk.Layer( 119 'ScatterplotLayer', 120 data=workData[workData.plotTime == maxValueTime], 121 get_color=maxColorOuter, 122 get_position=[ 'longitude', 'latitude', ], 123 get_radius=12), 124 pdk.Layer( 125 'ScatterplotLayer', 126 data=workData, 127 get_color=[ 0x64, 0x95, 0xed, 255 ], 128 get_position=[ 'longitude', 'latitude', ], 129 get_radius=2, 130 pickable=True), 131 pdk.Layer( 132 'ScatterplotLayer', 133 data=workData[workData.plotTime == maxValueTime], 134 get_color=maxCollorDot, 135 get_position=[ 'longitude', 'latitude', ], 136 get_radius=4), 137 ] 138 viewBox = viewPointBox(workData) 139 tooltip = { 140 # TODO: Figure out how to plot the score @ plotTime here. 141 # 'html': '<b>plotTime:</b> {plotTime} s<br><b>Score:</b> {score} km/h<br><b>Speed:</b> {vKMh} km/h<br><b>speedAngle:</b> {speedAngle}º', 142 'html': '<b>plotTime:</b> {plotTime} s<br><b>Speed:</b> {vKMh} km/h<br><b>speedAngle:</b> {speedAngle}º', 143 'style': { 144 'backgroundColor': 'steelblue', 145 'color': 'white', 146 }, 147 'cursor': 'default', 148 } 149 deck = pdk.Deck( 150 map_style = None, 151 layers=layers, 152 initial_view_state=pdk.data_utils.compute_view(viewBox[['longitude', 'latitude',]]), 153 tooltip=tooltip, 154 ) 155 return deck
Build the layers for a PyDeck map showing a jumper's trajectory.
Arguments
jumpResult
A SSScoring JumpResults
instance with the results of the jump.
Returns
A PyDeck deck
instance ready for rendering using PyDeck or Streamlit
mapping facilities.
See
st.pydeck_chart
st.map
158def multipleSpeedJumpsTrajectories(jumpResults): 159 """ 160 Build all the layers for a PyDeck map showing the trajectories of every jump 161 in the results set. 162 163 Arguments 164 --------- 165 jumpResults 166 A dictionary of all the jump results after processing. 167 168 Returns 169 ------- 170 A PyDeck `deck` instance ready for rendering using PyDeck or Streamlit 171 mapping facilities. 172 173 See 174 --- 175 `st.pydeck_chart` 176 `st.map` 177 """ 178 mapLayers = list() 179 mixColor = 0 180 for result in jumpResults.values(): 181 if result.scores != None: 182 workData = result.data.copy() 183 maxScoreTime = _resolveMaxScoreTimeFrom(result) 184 mixColor = (mixColor+1)%len(SPEED_COLORS) 185 layers = [ 186 pdk.Layer( 187 'ScatterplotLayer', 188 data=workData.head(1), 189 get_color=[ 255, 126, 0, 255 ], 190 get_position=[ 'longitude', 'latitude', ], 191 get_radius=8), 192 pdk.Layer( 193 'ScatterplotLayer', 194 data=workData.tail(1), 195 get_color=[ 0, 192, 0, 160 ], 196 get_position=[ 'longitude', 'latitude', ], 197 get_radius=8), 198 pdk.Layer( 199 'ScatterplotLayer', 200 data=workData[workData.plotTime == maxScoreTime], 201 get_color=[ 0, 255, 0, ], 202 get_position=[ 'longitude', 'latitude', ], 203 get_radius=12), 204 pdk.Layer( 205 'ScatterplotLayer', 206 data=workData, 207 get_color = convertHexColorToRGB(SPEED_COLORS[mixColor]), 208 get_position=[ 'longitude', 'latitude', ], 209 get_radius=2), 210 pdk.Layer( 211 'ScatterplotLayer', 212 data=workData[workData.plotTime == maxScoreTime], 213 get_color=[ 0, 128, 0, ], 214 get_position=[ 'longitude', 'latitude', ], 215 get_radius=4), 216 ] 217 mapLayers += layers 218 viewBox = viewPointBox(workData) 219 deck = pdk.Deck( 220 map_style = None, 221 initial_view_state=pdk.data_utils.compute_view(viewBox[['longitude', 'latitude',]]), 222 layers=mapLayers 223 ) 224 return deck
Build all the layers for a PyDeck map showing the trajectories of every jump in the results set.
Arguments
jumpResults
A dictionary of all the jump results after processing.
Returns
A PyDeck deck
instance ready for rendering using PyDeck or Streamlit
mapping facilities.
See
st.pydeck_chart
st.map