Advertisement
Guest User

Untitled

a guest
Feb 24th, 2020
703
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.20 KB | None | 0 0
  1. import json
  2. import pandas as pd
  3. from collections import Counter
  4. import datetime
  5. from math import isclose
  6.  
  7. TS0 = datetime.datetime(1,1,1,0,0,0)
  8. def ts_to_time(timestamp):
  9.     return (TS0 + datetime.timedelta(milliseconds=timestamp) + datetime.timedelta(hours=1)).strftime('%H:%M:%S')
  10.  
  11. def lap_in_sec(laptime, as_string=True):
  12.     # for converting 1:23.456 into 83.456 if someone wants to plot them later
  13.     if laptime == '':
  14.         return ''
  15.     else:
  16.         qq1, qq2 = laptime.split(':')
  17.         laptime_float = 60*int(qq1) + float(qq2)
  18.         return '%.3f' % laptime_float if as_string else laptime_float
  19.  
  20. def is_laptime_right(row):
  21.     # for sanity checking s1 + s2 + s3 == laptime
  22.     if row['s1'] != '' and row['s2'] != '' and row['s3'] != '' and row['laptime'] != '':
  23.         laptime_s123 = float(row['s1']) + float(row['s2']) + float(row['s3'])
  24.         laptime_full = lap_in_sec(row['laptime'], as_string=False)
  25.         return 'ok' if isclose(laptime_s123, laptime_full, abs_tol=0.0001) else 'PROBLEM'
  26.     else:
  27.         return 'partial'
  28.    
  29. def find_key_in_json(frame, searchkey='DR'):
  30.     found_entries = []
  31.     def seek_recursively(entry):
  32.         if isinstance(entry, list):
  33.             for element in entry:
  34.                 seek_recursively(element)
  35.         elif isinstance(entry, dict):
  36.             if searchkey in entry:
  37.                 found_entries.append(entry[searchkey])
  38.             else:
  39.                 for entry2 in entry.values():
  40.                     seek_recursively(entry2)
  41.         else:
  42.             return None
  43.     seek_recursively(frame)
  44.     return found_entries
  45.    
  46.  
  47. frames = []
  48. with open('day2-afternoon.json', 'r') as infile:
  49.     frames = json.load(infile)
  50.  
  51.  
  52. drinames = find_key_in_json(frames, 'init')
  53. for driverlist in drinames:
  54.     ts = find_key_in_json(driverlist, 'T')[0]
  55.     print()
  56.     print('driver list at timestamp', ts, ts_to_time(ts))
  57.     drivers = {i: x['Initials'] for i, x in enumerate(driverlist['data']['Drivers'])}
  58.     print(drivers)
  59. print()
  60. print('using last one. If you see more than 1 driver list, make sure to check that they are all equal')
  61. print('otherwise driver IDs at different timestamps will have to be converted to different initials!')
  62.  
  63.  
  64.  
  65. frames2 = []  # cleaning out irrelevant frames.
  66. frames2_thrownout = []
  67. for frame in frames:
  68.     if tuple(frame.keys()) != ('C', 'M'):
  69.         frames2_thrownout.append(frame)
  70.         continue  # all the timing frames seem to have only C and M keys
  71.     multiframes = frame['M']  # usually only one element, but sometimes 2 or 3
  72.     for subframe in multiframes:
  73.         # subframe always has 3 keys: H, M, A. H&M are constant strings, only information is under A.
  74.         # subframe['A'] is a fixed list of 3. First element is SPFeed / ExtrapolatedClock / StreamingStatus (almost all SPFeed)
  75.         # second element is rich data
  76.         # third element is text timestamp
  77.         if subframe['A'][0] == 'SPFeed':
  78.             frames2.append(subframe['A'][1])
  79.            
  80.            
  81. cleaned_dr = []
  82. last_timestamp = 0
  83. for timestamp, drentries in ((find_key_in_json(x, 'T'), find_key_in_json(x, 'DR')) for x in frames2):
  84.     if timestamp:
  85.         ts = timestamp[0]
  86.         last_timestamp = ts
  87.         warning = ''
  88.     else:
  89.         print('no timestamp, adding a fake one based on the previous', drentries)
  90.         ts = last_timestamp + 1
  91.         warning = 'missing_timestamp'
  92.     for drentry in drentries:
  93.         if not isinstance(drentry, dict):  # early initialization frames may be weird, ignore
  94.             continue
  95.         for driverid, data in drentry.items():
  96.             data['DRIVERID'] = int(driverid)
  97.             data['TIMESTAMP'] = ts
  98.             data['WARNING'] = warning
  99.             cleaned_dr.append(data)
  100.  
  101.  
  102.  
  103. todf = []
  104. for frame in cleaned_dr:
  105.     try:
  106.         yy = frame['O'].copy()
  107.         yy['dri'] = frame['DRIVERID']
  108.         yy['ts'] = frame['TIMESTAMP']
  109.         todf.append(yy)
  110.     except:
  111.         pass
  112.    
  113. for frame in cleaned_dr:
  114.     try:
  115.         yy = frame['X'].copy()
  116.         zz = frame['TI']
  117.         zz2 = zz if isinstance(zz, list) else tuple(zz.values())
  118.         zz3 = {'age': str(zz2[2]), 'dri': frame['DRIVERID'], 'ts': frame['TIMESTAMP']}  # 'stint' : zz2[1]
  119.        
  120.         yy['tyrehist'] = yy.pop('9')
  121.         yy['tyre'] = yy['tyrehist'][0]
  122.         yy['dri'] = frame['DRIVERID']
  123.         yy['ts'] = frame['TIMESTAMP']
  124.         todf.append(yy)
  125.         todf.append(zz3)
  126.     except:
  127.         continue  # screw this below.
  128.         # It's redundant information and it always arrives a few seconds after the laptime making,
  129.         # making it a pain to integrate in later steps. They can be calculated from the stint start if someone really wants is
  130.         if 'TI' in frame:
  131.             zz = frame['TI']
  132.             zz2 = zz2 if isinstance(zz, list) else tuple(zz.values())
  133.             if len(zz2) == 2:
  134.                 zz3 = {'stint': '%02d' % zz2[0], 'age': '%02d' % zz2[1], 'dri': frame['DRIVERID'], 'ts': frame['TIMESTAMP']}
  135.                 todf.append(zz3)
  136.             else:
  137.                 print('problem with tyre info', frame)
  138.          
  139.  
  140.  
  141.  
  142. fieldnames = {
  143.     '1': 'laptime',
  144.     '2': 'sections',
  145.     '3': 'dunno1',
  146.     '4': 'dunno2',
  147.     '5': 's1',
  148.     '6': 's2',
  149.     '7': 's3',
  150.     '8': 'dunno3',
  151.     '9': 'dunno4',
  152.     '10': 'sp1',
  153.     '11': 'sp2',
  154.     '12': 'sp3',
  155.     '13': 'sp0',
  156.     '14': 'gap'
  157. }
  158. df = pd.DataFrame(todf).fillna('').rename(columns=fieldnames)
  159. df['driver'] = df['dri'].apply(drivers.get)
  160. df['time'] = df['ts'].apply(ts_to_time)
  161. df.sort_values(['driver', 'ts'], inplace=True)
  162.  
  163. df = df.loc[:, 'driver time s1 s2 s3 laptime sp0 sp1 sp2 sp3 tyre age'.split()]
  164. df2 = df.query('s1!="" | s2!="" | s3!="" | laptime!="" | sp0!="" | sp1!="" | sp2!="" | sp3!="" | tyre!="" | age!=""').reset_index(drop=True)
  165.  
  166.  
  167. # group the sector times into full laps
  168. all_laps = []
  169. for driver, subdf in df2.groupby('driver'):
  170.    
  171.     driver_laps = []
  172.     data_for_lap = []
  173.    
  174.     has_laptime = False
  175.     has_s1 = False
  176.     has_s2 = False
  177.     has_s3 = False
  178.    
  179.     for _, row in subdf.iterrows():
  180.         if row['s1'] != '':
  181.             # if s1 follows any other unprinted sector/laptime info, it's some weird in/out lap
  182.             # so first dump the previous information
  183.             if has_s1 or has_s2 or has_s3 or has_laptime:  # TODO: add has_tyre to get rid of a few stint opening problems. Low priority
  184.                 lapdf = pd.DataFrame(data_for_lap)
  185.                 full_lap = pd.DataFrame(data_for_lap).max(axis=0)
  186.                 driver_laps.append(full_lap)
  187.                 data_for_lap, has_laptime, has_s1, has_s2, has_s3 = [], False, False, False, False
  188.             has_s1 = True
  189.         if row['s2'] != '':
  190.             # if s2 follows any other unprinted s2/s3/laptime info, same thing, dump before continuing
  191.             if has_s2 or has_s3 or has_laptime:
  192.                 lapdf = pd.DataFrame(data_for_lap)
  193.                 full_lap = pd.DataFrame(data_for_lap).max(axis=0)
  194.                 driver_laps.append(full_lap)
  195.                 data_for_lap, has_laptime, has_s1, has_s2, has_s3 = [], False, False, False, False
  196.             has_s2 = True
  197.         if row['s3'] != '':
  198.             has_s3 = True
  199.         if row['laptime'] != '':
  200.             has_laptime = True
  201.        
  202.         data_for_lap.append(row)
  203.        
  204.         if has_laptime and has_s3: # wait until both s3 and laptime is available, whichever comes later
  205.             # finished collecting info for lap, time to save it
  206.             lapdf = pd.DataFrame(data_for_lap)
  207.             full_lap = pd.DataFrame(data_for_lap).max(axis=0)
  208.             driver_laps.append(full_lap)
  209.             data_for_lap, has_laptime, has_s1, has_s2, has_s3 = [], False, False, False, False
  210.            
  211.     driver_all_laps = pd.DataFrame(driver_laps)
  212.     driver_all_laps.insert(1, 'lapno', range(1, driver_all_laps.shape[0] + 1))
  213.     all_laps.append(driver_all_laps)
  214.  
  215. lapdf = pd.concat(all_laps, axis=0, ignore_index=True)
  216. lapdf['lapsecs'] = lapdf['laptime'].apply(lap_in_sec)
  217. lapdf['math'] = lapdf.apply(is_laptime_right, axis=1)
  218.  
  219.  
  220. # df.to_csv('day2-afternoon-raw.tsv', sep='\t', index=False)
  221.  
  222. lapdf.to_csv('day2-afternoon-lapchart.tsv', sep='\t', index=False)
  223.  
  224. print('finished')
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement