ssscoring.ssscoresingle

  1# See: https://github.com/pr3d4t0r/SSScoring/blob/master/LICENSE.txt
  2
  3"""
  4Streamlit-based application.
  5
  6Issue deploying to Streamlit.io:
  7https://discuss.streamlit.io/t/pythonpath-issue-modulenotfounderror-in-same-package-where-app-is-defined/91170
  8"""
  9
 10from ssscoring.appcommon import displayJumpDataIn
 11from ssscoring.appcommon import displayTrackOnMap
 12from ssscoring.appcommon import initFileUploaderState
 13from ssscoring.appcommon import interpretJumpResult
 14from ssscoring.appcommon import isStreamlitHostedApp
 15from ssscoring.appcommon import plotJumpResult
 16from ssscoring.appcommon import setSideBarAndMain
 17from ssscoring.calc import convertFlySight2SSScoring
 18from ssscoring.calc import dropNonSkydiveDataFrom
 19from ssscoring.calc import getFlySightDataFromCSVBuffer
 20from ssscoring.calc import processJump
 21from ssscoring.constants import M_2_FT
 22from ssscoring.constants import SPEED_ACCURACY_THRESHOLD
 23from ssscoring.datatypes import JumpStatus
 24from ssscoring.datatypes import PerformanceWindow
 25from ssscoring.mapview import speedJumpTrajectory
 26
 27import pandas as pd
 28import streamlit as st
 29
 30
 31# *** implementation ***
 32
 33def _selectDZState(*args, **kwargs):
 34    if st.session_state.elevation:
 35        st.session_state.uploaderKey += 1
 36        st.session_state.trackFile = None
 37
 38
 39def _getJumpDataFrom(trackFileBuffer: str) -> pd.DataFrame:
 40    dropZoneAltMSLMeters = 0.0 if st.session_state.elevation == None else st.session_state.elevation
 41    data = None
 42    tag = None
 43    if dropZoneAltMSLMeters is not None:
 44        rawData, tag = getFlySightDataFromCSVBuffer(trackFileBuffer, st.session_state.trackFile.name)
 45        data = convertFlySight2SSScoring(rawData, altitudeDZMeters=dropZoneAltMSLMeters)
 46    return data, tag
 47
 48
 49def _displayAllJumpDataIn(data: pd.DataFrame):
 50    columns = [ 'plotTime' ] + [ column for column in data.columns if column != 'plotTime' and column != 'timeUnix' ]
 51    st.html('<h3>All rows of jump data</h3>')
 52    st.dataframe(data,
 53        column_order=columns,
 54        column_config={
 55            'plotTime': st.column_config.NumberColumn(format='%.02f'),
 56            'speedAngle': st.column_config.NumberColumn(format='%.02f'),
 57            'speedAccuracyISC': st.column_config.NumberColumn(format='%.02f'),
 58        },
 59        hide_index=True)
 60
 61
 62def _displayScoresIn(rawData: dict):
 63    st.html('<h3>Scores</h3>')
 64    data = pd.DataFrame.from_dict({ 'time': rawData.values(), 'score': rawData.keys(), })
 65    data.time = data.time.apply(lambda x: '%.2f' % x)
 66    st.dataframe(data, hide_index=True)
 67
 68
 69def _displayBadRowsISCAccuracyExceeded(data: pd.DataFrame, window: PerformanceWindow):
 70    badRows = data[data.speedAccuracyISC >= SPEED_ACCURACY_THRESHOLD]
 71    badRows = dropNonSkydiveDataFrom(badRows)
 72    times = pd.to_datetime(badRows.timeUnix, unit='s').dt.strftime('%Y-%m-%d %H:%M:%S.%f').str[:-4]
 73    badRows.insert(0, 'time', times)
 74    badRows.drop(columns = [
 75        'timeUnix',
 76        'altitudeMSL',
 77        'altitudeMSLFt',
 78        'speedAccuracy',
 79        'hMetersPerSecond',
 80        'hKMh',
 81        'speedAngle',
 82        'latitude',
 83        'longitude',
 84        'verticalAccuracy', ], inplace=True)
 85    st.html('<h3>Performance window:<br>start = %.2f m (%.2f ft)<br>end = %.2f m (%.2f ft)<br>validation start = %.2f m (%.2f ft)</h3>' % \
 86                    (window.start, M_2_FT*window.start, window.end, M_2_FT*window.end, window.validationStart, M_2_FT*window.validationStart))
 87    st.html('<h3>%d track rows where the ISC speed accuracy threshold was exceeded during the speed run:</h3>' % len(badRows))
 88    st.dataframe(badRows, hide_index=True)
 89
 90
 91    workData = data.copy()
 92    workData = dropNonSkydiveDataFrom(workData)
 93    times = pd.to_datetime(workData.timeUnix, unit='s').dt.strftime('%Y-%m-%d %H:%M:%S.%f').str[:-4]
 94    workData.insert(0, 'time', times)
 95    st.html('<h3>Full speed run data (%d rows)</h3>' % len(workData))
 96    st.dataframe(workData, hide_index=True)
 97
 98
 99def main():
100    if not isStreamlitHostedApp():
101        st.set_page_config(layout = 'wide')
102    initFileUploaderState('trackFile')
103    setSideBarAndMain('1️⃣ ', True, _selectDZState)
104
105    col0, col1 = st.columns([ 0.4, 0.6, ])
106    if st.session_state.trackFile:
107        data, tag = _getJumpDataFrom(st.session_state.trackFile.getvalue())
108        jumpResult = processJump(data)
109        jumpStatusInfo, \
110        scoringInfo, \
111        badJumpLegend, \
112        jumpStatus = interpretJumpResult(tag, jumpResult, st.session_state.processBadJump)
113        if jumpStatus != JumpStatus.OK:
114            st.toast('#### %s - %s' % (tag, str(jumpStatus)), icon='⚠️')
115        with col0:
116            st.html('<h3>'+jumpStatusInfo+scoringInfo+(badJumpLegend if badJumpLegend else '')+'</h3>')
117        if (st.session_state.processBadJump and jumpStatus != JumpStatus.OK and jumpStatus != JumpStatus.WARM_UP_FILE) or jumpStatus == JumpStatus.OK:
118            with col0:
119                displayJumpDataIn(jumpResult.table)
120                _displayAllJumpDataIn(jumpResult.data)
121                _displayScoresIn(jumpResult.scores)
122            with col1:
123                plotJumpResult(tag, jumpResult)
124                displayTrackOnMap(speedJumpTrajectory(jumpResult))
125        elif jumpStatus == JumpStatus.SPEED_ACCURACY_EXCEEDS_LIMIT:
126            with col0:
127                _displayBadRowsISCAccuracyExceeded(data, jumpResult.window)
128
129
130if '__main__' == __name__:
131    main()
def main():
100def main():
101    if not isStreamlitHostedApp():
102        st.set_page_config(layout = 'wide')
103    initFileUploaderState('trackFile')
104    setSideBarAndMain('1️⃣ ', True, _selectDZState)
105
106    col0, col1 = st.columns([ 0.4, 0.6, ])
107    if st.session_state.trackFile:
108        data, tag = _getJumpDataFrom(st.session_state.trackFile.getvalue())
109        jumpResult = processJump(data)
110        jumpStatusInfo, \
111        scoringInfo, \
112        badJumpLegend, \
113        jumpStatus = interpretJumpResult(tag, jumpResult, st.session_state.processBadJump)
114        if jumpStatus != JumpStatus.OK:
115            st.toast('#### %s - %s' % (tag, str(jumpStatus)), icon='⚠️')
116        with col0:
117            st.html('<h3>'+jumpStatusInfo+scoringInfo+(badJumpLegend if badJumpLegend else '')+'</h3>')
118        if (st.session_state.processBadJump and jumpStatus != JumpStatus.OK and jumpStatus != JumpStatus.WARM_UP_FILE) or jumpStatus == JumpStatus.OK:
119            with col0:
120                displayJumpDataIn(jumpResult.table)
121                _displayAllJumpDataIn(jumpResult.data)
122                _displayScoresIn(jumpResult.scores)
123            with col1:
124                plotJumpResult(tag, jumpResult)
125                displayTrackOnMap(speedJumpTrajectory(jumpResult))
126        elif jumpStatus == JumpStatus.SPEED_ACCURACY_EXCEEDS_LIMIT:
127            with col0:
128                _displayBadRowsISCAccuracyExceeded(data, jumpResult.window)