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
DISTANCE_FROM_MIDDLE = 400.0

The distance in meters from the middle of the skydive to the outer bounding box for the initial view of a new rendered map.

def viewPointBox(data: pandas.core.frame.DataFrame) -> pandas.core.frame.DataFrame:
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

ssscoring.calc.convertFlySight2SSScoring

def speedJumpTrajectory( jumpResult: ssscoring.datatypes.JumpResults, displayScorePoint: bool = True) -> pydeck.bindings.deck.Deck:
 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

def multipleSpeedJumpsTrajectories(jumpResults):
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