def plot_xdop_svs(dfDops: pd.DataFrame, colors: tuple, axis, logger: logging.Logger): """ plot_xdop_svs plots the XDOP curves and #SVs on a given axis """ cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored(sys._getframe().f_code.co_name, 'green') logger.info('{func:s}: creating XDOP / #SVs vs time plot'.format(func=cFuncName)) axis.set_ylim([0, 24]) axis.set_ylabel('#SVs [-]', fontsize='large', color='grey') # axis.set_xlabel('Time [sec]', fontsize='large') axis.fill_between(dfDops['DT'], 0, dfDops['#SVs'], alpha=0.5, linestyle='-', linewidth=3, color='grey', label='#SVs', interpolate=False) # plot PDOP on second y-axis axRight = axis.twinx() axRight.set_ylim([0, 15]) axRight.set_ylabel('XDOP [-]', fontsize='large') # plot XDOPs (last 4 columns) for dop, color in zip(dfDops.columns[-4:], colors): axRight.plot(dfDops['DT'], dfDops[dop], linestyle='-', marker='.', markersize=1, color=color, label=dop) # add the legend to the plot axRight.legend(loc="upper right") # set title axis.set_title('Visible satellites & XDOP', fontsize='x-large') # create the ticks for the time axis dtFormat = plot_utils.determine_datetime_ticks(startDT=dfDops['DT'].iloc[0], endDT=dfDops['DT'].iloc[-1]) if dtFormat['minutes']: # axis.xaxis.set_major_locator(dates.MinuteLocator(byminute=range(10, 60, 10), interval=1)) pass else: axis.xaxis.set_major_locator(dates.HourLocator(interval=dtFormat['hourInterval'])) # every 4 hours axis.xaxis.set_major_formatter(dates.DateFormatter('%H:%M')) # hours and minutes axis.xaxis.set_minor_locator(dates.DayLocator(interval=1)) # every day axis.xaxis.set_minor_formatter(dates.DateFormatter('\n%d-%m-%Y')) axis.xaxis.set_tick_params(rotation=0) for tick in axis.xaxis.get_major_ticks(): # tick.tick1line.set_markersize(0) # tick.tick2line.set_markersize(0) tick.label1.set_horizontalalignment('center')
def plotUTMOffset(dRtk: dict, dfPos: pd.DataFrame, dfCrd: pd.DataFrame, dCrdLim: dict, logger: logging.Logger, showplot: bool = False): """ plotUTMOffset plots the offset NEU wrt to reference point """ cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored(sys._getframe().f_code.co_name, 'green') # select colors for E, N, U coordinate difference colors = [] colors.append([51 / 256., 204 / 256., 51 / 256.]) colors.append([51 / 256., 51 / 256., 255 / 256.]) colors.append([255 / 256., 51 / 256., 51 / 256.]) # what to plot crds2Plot = ['UTM.E', 'UTM.N', 'ellH', 'ns'] stdDev2Plot = ['sde', 'sdn', 'sdu'] annotateList = ['east', 'north', 'ellh', '#SV'] # find gaps in the data by comparing to mean value of difference in time dfPos['tDiff'] = dfPos['DT'].diff(1) dtMean = dfPos['tDiff'].mean() # look for it using location indexing dfPos.loc[dfPos['tDiff'] > dtMean, 'ns'] = np.nan amc.logDataframeInfo(df=dfPos, dfName='dfPos', callerName=cFuncName, logger=logger) # set up the plot plt.style.use('ggplot') # subplots fig, ax = plt.subplots(nrows=len(crds2Plot), ncols=1, sharex=True, figsize=(20.0, 16.0)) fig.suptitle('{syst:s} - {posf:s} - {date:s}'.format(posf=dRtk['info']['rtkPosFile'], syst=dRtk['syst'], date=dRtk['Time']['date'])) # make title for plot ax[0].annotate('{syst:s} - {date:s}'.format(syst=dRtk['syst'], date=dfPos['DT'].iloc[0].strftime('%d %b %Y')), xy=(0, 1), xycoords='axes fraction', xytext=(0, 0), textcoords='offset pixels', horizontalalignment='left', verticalalignment='bottom', weight='strong', fontsize='large') # copyright this ax[-1].annotate(r'$\copyright$ Alain Muls ([email protected])', xy=(1, 1), xycoords='axes fraction', xytext=(0, 0), textcoords='offset pixels', horizontalalignment='right', verticalalignment='bottom', weight='strong', fontsize='large') # subplots for coordinates display delta NEU for i, crd in enumerate(crds2Plot[:3]): axis = ax[i] # color for markers and alpha colors for error bars rgb = mpcolors.colorConverter.to_rgb(colors[i]) rgb_new = amutils.make_rgb_transparent(rgb, (1, 1, 1), 0.3) # plot coordinate differences and error bars axis.errorbar(x=dfPos['DT'], y=dfCrd[crd], yerr=dfPos[stdDev2Plot[i]], linestyle='None', fmt='o', ecolor=rgb_new, capthick=1, markersize=1, color=colors[i]) # set dimensions of y-axis axis.set_ylim([dCrdLim['min'], dCrdLim['max']]) axis.set_ylabel('{crd:s} [m]'.format(crd=crd, fontsize='large'), color=colors[i]) # # annotate each subplot with its reference position # if [dRtk['marker']['UTM.E'], dRtk['marker']['UTM.N'], dRtk['marker']['ellH']] == [np.NaN, np.NaN, np.NaN]: # # use the mean UTM/ellH position for the reference point # crdRef = dRtk['WAvg'][crd] # crdSD = dRtk['WAvg'][stdDev2Plot[i]] # annotatetxt = r'Mean: {refcrd:.3f}m ($\pm${stddev:.2f}m)'.format(refcrd=crdRef, stddev=crdSD) # else: # # we have a reference point # crdRef = dRtk['marker'][crd] # crdOffset = dRtk['marker'][crd] - dRtk['WAvg'][crd] # crdSD = dRtk['WAvg'][stdDev2Plot[i]] # annotatetxt = r'Ref: {crd:s} = {refcrd:.3f}m ({offset:.3f}m $\pm${stddev:.2f}m)'.format(crd=crd, refcrd=crdRef, stddev=crdSD, offset=crdOffset) annotatetxt = markerAnnotation(crd, stdDev2Plot[i]) # put annotation text axis.annotate(annotatetxt, xy=(1, 1), xycoords='axes fraction', xytext=(0, 0), textcoords='offset pixels', horizontalalignment='right', verticalalignment='bottom', weight='strong', fontsize='large') # title of sub-plot axis.set_title('{crd:s} offset'.format(crd=str.capitalize(annotateList[i]), fontsize='large')) # last subplot: number of satellites & PDOP for _, crd in enumerate(crds2Plot[3:4]): # plot #SVs on left axis axis = ax[-1] axis.set_ylim([0, 24]) axis.set_ylabel('#SVs [-]', fontsize='large', color='grey') # axis.set_xlabel('Time [sec]', fontsize='large') axis.fill_between(dfPos['DT'], 0, dfPos['ns'], alpha=0.5, linestyle='-', linewidth=3, color='grey', label='#SVs', interpolate=False) # plot PDOP on second y-axis axRight = axis.twinx() axRight.set_ylim([0, 15]) axRight.set_ylabel('PDOP [-]', fontsize='large', color='darkorchid') # plot PDOP value axRight.plot(dfPos['DT'], dfPos['PDOP'], linestyle='-', marker='.', markersize=1, color='darkorchid', label='PDOP') # set title axis.set_title('Visible satellites & PDOP', fontsize='large') # create the ticks for the time axis dtFormat = plot_utils.determine_datetime_ticks(startDT=dfPos['DT'].iloc[0], endDT=dfPos['DT'].iloc[-1]) if dtFormat['minutes']: axis.xaxis.set_major_locator(dates.MinuteLocator(byminute=range[1, 60, 5], interval=1)) else: axis.xaxis.set_major_locator(dates.HourLocator(interval=dtFormat['hourInterval'])) # every 4 hours axis.xaxis.set_major_formatter(dates.DateFormatter('%H:%M')) # hours and minutes axis.xaxis.set_minor_locator(dates.DayLocator(interval=1)) # every day axis.xaxis.set_minor_formatter(dates.DateFormatter('\n%d-%m-%Y')) axis.xaxis.set_tick_params(rotation=0) for tick in axis.xaxis.get_major_ticks(): # tick.tick1line.set_markersize(0) # tick.tick2line.set_markersize(0) tick.label1.set_horizontalalignment('center') # save the plot in subdir png of GNSSSystem amutils.mkdir_p(os.path.join(dRtk['info']['dir'], 'png')) pngName = os.path.join(dRtk['info']['dir'], 'png', os.path.splitext(dRtk['info']['rtkPosFile'])[0] + '-ENU.png') fig.savefig(pngName, dpi=fig.dpi) logger.info('{func:s}: created plot {plot:s}'.format(func=cFuncName, plot=colored(pngName, 'green'))) if showplot: plt.show(block=True) else: plt.close(fig) return
def plot_glab_xdop(dfCrd: pd.DataFrame, logger: logging.Logger, showplot: bool = False): """ plot_xdop plot the DOP values vs time """ cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored( sys._getframe().f_code.co_name, 'green') logger.info('{func:s}: plotting xDOP'.format(func=cFuncName)) # set up the plot plt.style.use('ggplot') # get info for the plot titles plot_title, proc_options, rx_geod = amc.get_title_info(logger=logger) # subplots fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(12.0, 8.0)) # figure title fig.suptitle('{title:s}'.format(title=plot_title), **glc.title_font) # plot annotations ax.annotate('{conf:s}'.format(conf=amc.dRTK['glab_out']), xy=(0, 1), xycoords='axes fraction', xytext=(0, 0), textcoords='offset pixels', horizontalalignment='left', verticalalignment='bottom', weight='ultrabold', fontsize='small') ax.annotate(proc_options, xy=(1, 1), xycoords='axes fraction', xytext=(0, 0), textcoords='offset pixels', horizontalalignment='right', verticalalignment='bottom', weight='ultrabold', fontsize='small') # copyright this ax.annotate(r'$\copyright$ Alain Muls ([email protected])', xy=(1, 0), xycoords='axes fraction', xytext=(0, -50), textcoords='offset pixels', horizontalalignment='right', verticalalignment='bottom', weight='ultrabold', fontsize='x-small') # plot the xDOP values vs time for (xdop, dop_color) in zip(dfCrd[glc.dgLab['OUTPUT']['XDOP']], glc.dop_colors): if xdop == 'PDOP': ax.fill_between(x=dfCrd['DT'], y1=0, y2=dfCrd[xdop], color=dop_color, linestyle='-', linewidth=0, interpolate=False, alpha=0.15) ax.plot(dfCrd['DT'], dfCrd[xdop], color=dop_color, linestyle='', marker='.', markersize=1, label=xdop) # lcoation of legend ax.legend(loc='best', markerscale=6, fontsize='x-small') # add titles to axes ax.set_ylim([0, 10]) # name the axis ax.set_ylabel('DOP [-]', fontsize='large') # set limits for the x-axis ax.set_xlim([dfCrd['DT'].iloc[0], dfCrd['DT'].iloc[-1]]) # create the ticks for the time axis dtFormat = plot_utils.determine_datetime_ticks(startDT=dfCrd['DT'].iloc[0], endDT=dfCrd['DT'].iloc[-1]) if not dtFormat['minutes']: # # ax.xaxis.set_major_locator(dates.MinuteLocator(byminute=range(10, 60, 10), interval=1)) # pass # else: ax.xaxis.set_major_locator( dates.HourLocator(interval=dtFormat['hourInterval'])) # every ax.xaxis.set_minor_locator(dates.DayLocator(interval=1)) # every day ax.xaxis.set_minor_formatter(dates.DateFormatter('\n%d-%m-%Y')) ax.xaxis.set_major_formatter( dates.DateFormatter('%H:%M')) # hours and minutes ax.xaxis.set_tick_params(rotation=0) for tick in ax.xaxis.get_major_ticks(): tick.label1.set_horizontalalignment('center') # save the plot in subdir png of GNSSSystem dir_png = os.path.join(amc.dRTK['dir_root'], amc.dRTK['dgLABng']['dir_glab'], 'png') png_filename = os.path.join( dir_png, '{out:s}-DOP.png'.format(out=amc.dRTK['glab_out'].replace('.', '-'))) amutils.mkdir_p(dir_png) fig.savefig(png_filename, dpi=fig.dpi) logger.info('{func:s}: created plot {plot:s}'.format(func=cFuncName, plot=colored( png_filename, 'green'))) if showplot: plt.show(block=True) else: plt.close(fig)
def plot_glab_position(dfCrd: pd.DataFrame, scale: float, logger: logging.Logger, showplot: bool = False): """ plot_glab_position plots the position difference wrt to Nominal a priori position """ cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored( sys._getframe().f_code.co_name, 'green') logger.info('{func:s}: plotting position offset'.format(func=cFuncName)) # set up the plot plt.style.use('ggplot') # get info for the plot titles plot_title, proc_options, rx_geod = amc.get_title_info(logger=logger) # subplots fig, ax = plt.subplots(nrows=4, ncols=1, sharex=True, figsize=(16.0, 12.0)) fig.suptitle('{title:s}'.format(title=plot_title), **glc.title_font) # plot annotations ax[0].annotate('{conf:s}'.format(conf=amc.dRTK['glab_out']), xy=(0, 1), xycoords='axes fraction', xytext=(0, 0), textcoords='offset pixels', horizontalalignment='left', verticalalignment='bottom', weight='ultrabold', fontsize='small') ax[0].annotate(proc_options, xy=(1, 1), xycoords='axes fraction', xytext=(0, 0), textcoords='offset pixels', horizontalalignment='right', verticalalignment='bottom', weight='ultrabold', fontsize='small') # copyright this ax[-1].annotate(r'$\copyright$ Alain Muls ([email protected])', xy=(1, 0), xycoords='axes fraction', xytext=(0, -50), textcoords='offset pixels', horizontalalignment='right', verticalalignment='bottom', weight='ultrabold', fontsize='x-small') # plot the ENU difference xwrt nominal initial position and display the standard deviation, xDOP for i, (crd, sdCrd) in enumerate( zip(glc.dgLab['OUTPUT']['dENU'], glc.dgLab['OUTPUT']['sdENU'])): # select the axis to use for this coordinate axis = ax[i] # get the statistics for this coordinate crd_stats = amc.dRTK['dgLABng']['stats']['crd'][crd] # color for markers and alpha colors for error bars rgb = mpcolors.colorConverter.to_rgb(glc.enu_colors[i]) rgb_error = amutils.make_rgb_transparent(rgb, (1, 1, 1), 0.4) # plot coordinate differences and error bars axis.errorbar(x=dfCrd['DT'].values, y=dfCrd[crd], yerr=dfCrd[sdCrd], linestyle='none', fmt='.', ecolor=rgb_error, capthick=1, markersize=1, color=glc.enu_colors[i]) # set dimensions of y-axis (double for UP scale) if crd == 'dU0': axis.set_ylim( [crd_stats['wavg'] - scale * 2, crd_stats['wavg'] + scale * 2]) else: axis.set_ylim( [crd_stats['wavg'] - scale, crd_stats['wavg'] + scale]) axis.set_ylabel('{crd:s} [m]'.format(crd=crd, fontsize='large'), color=glc.enu_colors[i], weight='ultrabold') # annotate each subplot with its reference position stat_str = '\n'.join( (r'gLab={:.3f} ($\pm${:.3f})'.format(crd_stats['kf'], crd_stats['sdkf']), r'', r'WAvg={:.3f} ($\pm${:.3f})'.format(crd_stats['wavg'], crd_stats['sdwavg']), r'', r'Range=[{:.2f}..{:.2f}]'.format(crd_stats['max'], crd_stats['min']))) # place a text box in upper left in axes coords axis.text(1.01, 0.95, stat_str, transform=axis.transAxes, fontsize='small', verticalalignment='top', color=glc.enu_colors[i], weight='strong') # annotatetxt = markerAnnotation(crd, sdCrd) # axis.annotate(annotatetxt, xy=(1, 1), xycoords='axes fraction', xytext=(0, 0), textcoords='offset pixels', horizontalalignment='right', verticalalignment='bottom', weight='ultrabold', fontsize='large') # title of sub-plot # axis.set_title('{crd:s} offset'.format(crd=str.capitalize(crd), fontsize='large')) axis.set_xlabel('') # last subplot: number of satellites & PDOP # plot #SVs on left axis axis = ax[-1] axis.set_ylim([0, 24]) axis.set_ylabel('#SVs [-]', fontsize='large', color='grey', weight='ultrabold') # axis.set_xlabel('Time [sec]', fontsize='large') # plot the number of SVs and color as function of the GNSSs used for (i_gnss, gnss, gnss_color) in zip([1, 1, 2], ['GAL', 'GPS', ''], ['blue', 'red', 'grey']): if i_gnss == 2: axis.fill_between(dfCrd['DT'].values, 0, dfCrd['#SVs'], where=(dfCrd['#GNSSs'] == i_gnss), alpha=0.25, linestyle='-', linewidth=2, color=gnss_color, interpolate=False) else: axis.fill_between(dfCrd['DT'].values, 0, dfCrd['#SVs'], where=((dfCrd['#GNSSs'] == i_gnss) & (gnss == dfCrd['GNSSs'])), alpha=0.25, linestyle='-', linewidth=2, color=gnss_color, interpolate=False) # plot PDOP on second y-axis axis_right = axis.twinx() axis_right.set_ylim([0, 10]) axis_right.set_ylabel('PDOP [-]', fontsize='large', color='darkorchid', weight='ultrabold') # plot PDOP value axis_right.plot(dfCrd['DT'], dfCrd['PDOP'], linestyle='', marker='.', markersize=1, color='darkorchid', label='PDOP') # set limits for the x-axis axis.set_xlim([dfCrd['DT'].iloc[0], dfCrd['DT'].iloc[-1]]) # create the ticks for the time axis dtFormat = plot_utils.determine_datetime_ticks(startDT=dfCrd['DT'].iloc[0], endDT=dfCrd['DT'].iloc[-1]) if dtFormat['minutes']: axis.xaxis.set_major_locator( dates.MinuteLocator(byminute=range(10, 60, 10), interval=1)) else: axis.xaxis.set_major_locator( dates.HourLocator(interval=dtFormat['hourInterval'])) # every axis.xaxis.set_minor_locator(dates.DayLocator(interval=1)) # every day axis.xaxis.set_minor_formatter(dates.DateFormatter('\n%d-%m-%Y')) axis.xaxis.set_major_formatter( dates.DateFormatter('%H:%M')) # hours and minutes axis.xaxis.set_tick_params(rotation=0) for tick in axis.xaxis.get_major_ticks(): tick.label1.set_horizontalalignment('center') # save the plot in subdir png of GNSSSystem dir_png = os.path.join(amc.dRTK['dir_root'], amc.dRTK['dgLABng']['dir_glab'], 'png') png_filename = os.path.join( dir_png, '{out:s}-ENU.png'.format(out=amc.dRTK['glab_out'].replace('.', '-'))) amutils.mkdir_p(dir_png) fig.savefig(png_filename, dpi=fig.dpi) logger.info('{func:s}: created plot {plot:s}'.format(func=cFuncName, plot=colored( png_filename, 'green'))) if showplot: plt.show(block=True) else: plt.close(fig) return
def plotRTKLibSatsColumn(dCol: dict, dRtk: dict, dfSVs: pd.DataFrame, logger: logging.Logger, showplot: bool = False): """ plotRTKLibSatsColumn plots a data columln from the stas dataframe """ cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored(sys._getframe().f_code.co_name, 'green') # set up the plot plt.style.use('ggplot') # create a dataframe dfMerged with columns DT and the columns we want (PRres, CN0, Elev) selected by dCol # check for which GNSS we have data to display GNSSSysts = [] if dRtk['PRres']['#GAL'] > 0: GNSSSysts.append('GAL') if dRtk['PRres']['#GPS'] > 0: GNSSSysts.append('GPS') if dRtk['PRres']['#GAL'] > 0 and dRtk['PRres']['#GPS'] > 0: GNSSSysts.append('COM') logger.info('{func:s}: processing GNSS Systems = {systs!s}'.format(func=cFuncName, systs=GNSSSysts)) for _, GNSSSyst in enumerate(GNSSSysts): logger.info('{func:s}: working on GNSS = {syst:s}'.format(func=cFuncName, syst=GNSSSyst)) # start with create a dataframe containing the DTs (unique values) and per column the value of column 'col' dfSatsCol = pd.DataFrame(dfSVs.DT.unique(), columns=['DT']) logger.debug('{func:s}: dfSatsCol.columns = {cols!s}'.format(func=cFuncName, cols=dfSatsCol.columns)) # logger.debug('{func:s}: final dRtk =\n{settings!s}'.format(func=cFuncName, settings=json.dumps(dRtk, sort_keys=False, indent=4))) if GNSSSyst == 'COM': curSVsList = dRtk['PRres']['GALList'] + dRtk['PRres']['GPSList'] else: curSVsList = dRtk['PRres']['%sList' % GNSSSyst] logger.debug('{func:s} #{line:d}: curSVsList of system {syst:s} = {list!s} {count:d}'.format(func=cFuncName, list=curSVsList, count=len(curSVsList), syst=GNSSSyst, line=amc.lineno())) # add column to this dataframe for each SV and for its selected value 'col' for i, sv in enumerate(curSVsList): dfSVCol = pd.DataFrame(dfSVs[['DT', dCol['name']]][dfSVs['SV'] == sv]) dfSVCol.rename(columns={dCol['name']: sv}, inplace=True) # logger.debug('{func:s}: dfSVCol = {df!s} (#{size!s})'.format(df=dfSVCol, size=dfSVCol.size, func=cFuncName)) # merge together dfMerged = pd.merge(dfSatsCol, dfSVCol, on=['DT'], how='outer') dfSatsCol = dfMerged # add a count of the number of residuals we have dfMerged['#{name:s}'.format(name=dCol['name'])] = dfMerged.apply(lambda x: x.count() - 1, axis=1) # -1 else DT is counted as well amc.logDataframeInfo(df=dfMerged, dfName='dfMerged', callerName=cFuncName, logger=logger) # only processing dCol['name'] of current system, plot both vs DT and statistics if dCol['name'] in ['CN0', 'PRres']: fig, axis = plt.subplots(nrows=3, ncols=1, figsize=(24.0, 20.0)) else: fig, axis = plt.subplots(nrows=2, ncols=1, figsize=(24.0, 16.0)) # determine the discrete colors for SVs colormap = plt.cm.nipy_spectral # I suggest to use nipy_spectral, Set1, Paired colors = [colormap(i) for i in np.linspace(0, 1, len(dfMerged.columns) - 1)] # print('colors = {!s}'.format(colors)) # Plot first the dCol['name'] versus DT ax1 = axis[0] # color white background between [-2 and +2] if dCol['name'] == 'PRres': ax1.fill_between(dfMerged['DT'], -2, +2, color='lightgreen', alpha=0.2) # plot the selected 'col' values excluding last column dfMerged[dfMerged.columns[:-1]].set_index('DT').plot(ax=ax1, color=colors, marker='.', markersize=1, linestyle='', alpha=1) # name the ax1 and set limits ax1.set_ylabel('{title:s} [{unit:s}]'.format(title=dCol['title'], unit=dCol['unit']), fontsize='large') if not dCol['yrange'][0] is np.nan: ax1.set_ylim(dCol['yrange']) # title for plot ax1.set_title('{title:s} {syst:s} - {date:s}'.format(title=dCol['title'], syst=GNSSSyst, date=dRtk['Time']['date']), fontsize='large') # add legend ax1.legend(bbox_to_anchor=(0.5, 0.025), loc='lower center', ncol=min(np.size(curSVsList), 15), fontsize='small', markerscale=10) # create the ticks for the time axis dtFormat = plot_utils.determine_datetime_ticks(startDT=dfMerged['DT'].iloc[0], endDT=dfMerged['DT'].iloc[-1]) if dtFormat['minutes']: ax1.xaxis.set_major_locator(dates.MinuteLocator(byminute=[0, 15, 30, 45], interval=1)) else: ax1.xaxis.set_major_locator(dates.HourLocator(interval=dtFormat['hourInterval'])) # every 4 hours ax1.xaxis.set_major_formatter(dates.DateFormatter('%H:%M')) # hours and minutes ax1.xaxis.set_minor_locator(dates.DayLocator(interval=1)) # every day ax1.xaxis.set_minor_formatter(dates.DateFormatter('\n%d-%m-%Y')) ax1.xaxis.set_tick_params(rotation=0) for tick in ax1.xaxis.get_major_ticks(): # tick.tick1line.set_markersize(0) # tick.tick2line.set_markersize(0) tick.label1.set_horizontalalignment('center') ax1.annotate(r'$\copyright$ Alain Muls ([email protected])', xy=(1, 1), xycoords='axes fraction', xytext=(0, 0), textcoords='offset pixels', horizontalalignment='right', verticalalignment='bottom', weight='strong', fontsize='large') # SECOND: PLOT THE STATISTICS FOR DCOL['NAME'] FOR ALL SVS logger.info('{func:s}: {gnss:s} statistics {name:s}\n{stat!s}'.format(func=cFuncName, name=dCol['name'], gnss=GNSSSyst, stat=dfMerged.describe())) ax2 = axis[1] plotTitle = '{title:s} {gnss:s} statistics - {date:s}'.format(title=dCol['title'], gnss=GNSSSyst, date=dRtk['Time']['date']) # leave out the column DT and the count column (eg '#PRres') selectCols = [x for x in dfMerged.columns if x not in ['DT', '#{name:s}'.format(name=dCol['name'])]] # print('selectCols = {!s}'.format(selectCols)) boxPlot = dfMerged[selectCols].plot(ax=ax2, kind='box', title=plotTitle, legend=True, fontsize='large', colormap='jet', return_type='dict', ylim=dCol['yrange'], rot=90, notch=True, patch_artist=True) # name the ax1 and set limits ax2.set_ylabel('%s [%s]' % (dCol['title'], dCol['unit']), fontsize='large') if not dCol['yrange'][0] is np.nan: ax2.set_ylim(dCol['yrange']) # beautify the boxplots svColors = [] if GNSSSyst == 'GAL' or GNSSSyst == 'GPS': # for i, color in enumerate(colors): svColors = colors else: for _, SV in enumerate(curSVsList): if SV.startswith('E'): svColors.append('blue') else: svColors.append('red') for item in ['boxes', 'fliers', 'medians']: # , 'whiskers', 'fliers', 'medians', 'caps']: for patch, color in zip(boxPlot[item], svColors): patch.set(color=color, linewidth=2) if item in ['boxes', 'fliers']: # make transparent background fill patch.set_alpha(0.15) # double the colors because whiskers exist at both sides doubleSVColors = [] for i, svColor in enumerate(svColors): doubleSVColors.append(svColor) doubleSVColors.append(svColor) # color elements that are twice available for item in ['whiskers', 'caps']: # , 'whiskers', 'fliers', 'medians', 'caps']: for patch, color in zip(boxPlot[item], doubleSVColors): patch.set(color=color, linewidth=2) # THIRD: FOR CN0 WE ALSO PLOT THE TIMEWISE DIFFERENCE dfMergedDiff = pd.DataFrame() if dCol['name'] == 'CN0': dfMergedDiff = dfMerged[dfMerged.columns[1:]].diff() dfMergedDiff = dfMergedDiff.mask(dfMergedDiff.abs() <= 1) dfMergedDiff.insert(loc=0, column='DT', value=dfMerged['DT']) dfMergedDiff.dropna(axis=0, how='all', subset=dfMerged.columns[1:], inplace=True) dfMergedDiff.dropna(axis=1, how='all', inplace=True) logger.debug('{func:s}: SVs observed (CN0 value) dfMerged.columns = {cols!s}'.format(func=cFuncName, cols=dfMerged.columns)) logger.debug('{func:s}: SVs with SN0 diff > 1 dfMergedDiff.columns = {cols!s}'.format(func=cFuncName, cols=dfMergedDiff.columns)) # THIRD: create the CN0 difference plot on the 3rd axis ax3 = axis[2] ax3.set_xlim([dfMerged['DT'].iat[0], dfMerged['DT'].iat[-1]]) # plot the selected 'col' values for sv in dfMergedDiff.columns[1:-1]: logger.debug('{func:s}: {syst:s} {sv:s}'.format(func=cFuncName, syst=GNSSSyst, sv=sv)) svcolor = svColors[curSVsList.index(sv)] # print('sv = {!s} {!s}'.format(sv, svcolor)) markerline, stemlines, baseline = ax3.stem(dfMergedDiff['DT'], dfMergedDiff[sv], label=sv) plt.setp(stemlines, color=svcolor, linewidth=2) plt.setp(markerline, color=svcolor, markersize=4) ax3.set_ylabel('Diff %s [%s]' % (dCol['title'], dCol['unit']), fontsize='large') # create the ticks for the time axis dtFormat = plot_utils.determine_datetime_ticks(startDT=dfMerged['DT'].iloc[0], endDT=dfMerged['DT'].iloc[-1]) if dtFormat['minutes']: ax3.xaxis.set_major_locator(dates.MinuteLocator(byminute=[0, 15, 30, 45], interval=1)) else: ax3.xaxis.set_major_locator(dates.HourLocator(interval=dtFormat['hourInterval'])) # every 4 hours ax3.xaxis.set_major_formatter(dates.DateFormatter('%H:%M')) # hours and minutes ax3.xaxis.set_minor_locator(dates.DayLocator(interval=1)) # every day ax3.xaxis.set_minor_formatter(dates.DateFormatter('\n%d-%m-%Y')) ax3.xaxis.set_tick_params(rotation=0) for tick in ax3.xaxis.get_major_ticks(): tick.label1.set_horizontalalignment('center') elif dCol['name'] == 'PRres': # THIRD: FOR PRRES WE ALSO PLOT THE PERCENTAGE OF PRRES WITHIN [-2, +2] ax3 = axis[2] ax3bis = ax3.twinx() # get the list of SVs for this GNSS if GNSSSyst == 'COM': curSVsList = dRtk['PRres']['GALList'] + dRtk['PRres']['GPSList'] else: curSVsList = dRtk['PRres']['%sList' % GNSSSyst] logger.debug('{func:s} #{line:d}: curSVsList = {list!s} {count:d}'.format(func=cFuncName, list=curSVsList, count=len(curSVsList), line=amc.lineno())) # create a dataframe indexed by SVID and which holds the #PR, #PRreslt2, %PRreslt2 dfSVPR = pd.DataFrame(curSVsList, columns=['SV']).set_index('SV', drop=False) # add dummy columns for holding the residu info dfSVPR = dfSVPR.reindex(columns=['SV', '#res', '#reslt2', '#pcreslt2']) if GNSSSyst == 'COM': curSVsPRRes = {k: v for d in (dRtk['PRres']['GALSVs'], dRtk['PRres']['GPSSVs']) for k, v in d.items()} else: curSVsPRRes = dRtk['PRres']['%sSVs' % GNSSSyst] logger.debug('{func:s} #{line:d}: curSVsPRRes = {list!s} {count:d}'.format(func=cFuncName, list=curSVsPRRes, count=len(curSVsPRRes), line=amc.lineno())) for i, sv in enumerate(curSVsList): dfSVPR.loc[dfSVPR['SV'] == sv, '#res'] = curSVsPRRes[sv]['count'] dfSVPR.loc[dfSVPR['SV'] == sv, '#reslt2'] = curSVsPRRes[sv]['PRlt2'] dfSVPR.loc[dfSVPR['SV'] == sv, '#pcreslt2'] = curSVsPRRes[sv]['PRlt2%'] amc.logDataframeInfo(df=dfSVPR, dfName='dfSVPR', callerName=cFuncName, logger=logger) # plot the bars for PRres and PRReslt2 dfSVPR.plot(kind='bar', ax=ax3, x='SV', y=['#res', '#reslt2'], edgecolor='white', fontsize='large', alpha=0.5) ax3.legend(labels=[r'#PRres', r'#PRres $\leq$ 2'], fontsize='medium') start, end = ax3.get_xlim() # print('start = {!s}'.format(start)) # print('end = {!s}'.format(end)) # ax3.set_xlim(left=start-1, right=end+1) # plot line for representing the percentage dfSVPR.plot(kind='line', ax=ax3bis, x='SV', y=['#pcreslt2'], fontsize='large', color='green', marker='o', markersize=5, linestyle='') ax3bis.legend(labels=[r'% PRres $\leq$ 2'], fontsize='medium') ax3bis.set_ylim([94.5, 100.5]) ax3bis.tick_params(axis='y', colors='green') # start, end = ax3bis.get_xlim() # print('start = {!s}'.format(start)) # print('end = {!s}'.format(end)) ax3bis.set_xlim(left=start, right=end) svRects = [] for i, rect in enumerate(ax3.patches): # print('i = {:d} rect = {!s}'.format(i, rect)) if i < len(curSVsList): svRects.append(rect) for i, rect in enumerate(ax3.patches): # print('i = {:d} len = {:d}'.format(i, len(curSVsList))) if i % 2: # 2 bars per SV # get_width pulls left or right; get_y pushes up or down sv = curSVsList[int(i / 2)] # print('SV = {:s} rect = {!s}'.format(sv, rect)) svRect = svRects[int(i / 2)] ax3.text(svRect.get_x() + svRect.get_width(), svRect.get_y() + svRect.get_height(), '{:.2f}%'.format(dfSVPR.loc[sv]['#pcreslt2']), fontsize='medium', color='green', horizontalalignment='center') # name the y axis ax3.set_ylabel('# of {:s}'.format(dCol['name']), fontsize='large') ax3bis.set_ylabel(r'% $\in$ [-2, +2]'.format(dCol['name']), fontsize='large', color='green') # save the plot in subdir png of GNSSSystem amutils.mkdir_p(os.path.join(dRtk['info']['dir'], 'png')) pngName = os.path.join(dRtk['info']['dir'], 'png', os.path.splitext(dRtk['info']['rtkPosFile'])[0] + '-{col:s}.png'.format(col=dCol['name'])) fig.savefig(pngName, dpi=fig.dpi) logger.info('{func:s}: created plot {plot:s}'.format(func=cFuncName, plot=colored(pngName, 'green'))) if showplot: plt.show(block=True) else: plt.close(fig)
def plot_utm_ellh(dRtk: dict, dfUTM: pd.DataFrame, logger: logging.Logger, showplot: bool = False): """ plots the UTM coordinates """ cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored( sys._getframe().f_code.co_name, 'green') # select colors for position mode # colors = [] # colors.append([51 / 256., 204 / 256., 51 / 256.]) # colors.append([51 / 256., 51 / 256., 255 / 256.]) # colors.append([255 / 256., 51 / 256., 51 / 256.]) colors = [ 'tab:white', 'tab:green', 'tab:olive', 'tab:orange', 'tab:cyan', 'tab:blue', 'tab:red', 'tab:pink', 'tab:purple', 'tab:brown' ] # what to plot crds2Plot = ['UTM.E', 'UTM.N', 'ellH', 'age'] stdDev2Plot = ['sde', 'sdn', 'sdu'] stdDevWAvg = ['sdUTM.E', 'sdUTM.N', 'sdellH'] # set up the plot plt.style.use('ggplot') # subplots fig, ax = plt.subplots(nrows=len(crds2Plot), ncols=1, sharex=True, figsize=(20.0, 16.0)) # make title for plot ax[0].annotate( '{camp:s} - {date:s} - {marker:s} ({pos:s}, quality {mode:s})'.format( camp=dRtk['campaign'], date=dRtk['obsStart'].strftime('%d %b %Y'), marker=dRtk['marker'], pos=dRtk['posFile'], mode=dRtk['rtkqual'].upper()), xy=(0.5, 1), xycoords='axes fraction', xytext=(0, 0), textcoords='offset pixels', horizontalalignment='center', verticalalignment='bottom', weight='strong', fontsize='large') # copyright this ax[-1].annotate(r'$\copyright$ Alain Muls ([email protected])', xy=(1, 1), xycoords='axes fraction', xytext=(0, 0), textcoords='offset pixels', horizontalalignment='right', verticalalignment='bottom', weight='strong', fontsize='large') # determine the difference to weighted average or marker position of UTM (N,E), ellH to plot dfCrd = pd.DataFrame(columns=crds2Plot[:3]) originCrds = [float(amc.dRTK['WAVG'][crd]) for crd in crds2Plot[:3]] dfCrd = dfUTM[crds2Plot[:3]].sub(originCrds, axis='columns') amutils.logHeadTailDataFrame(logger=logger, callerName=cFuncName, df=dfCrd, dfName='dfCrd') crdMax = max(dfCrd.max()) crdMin = min(dfCrd.min()) crdMax = int(crdMax + (1 if crdMax > 0 else -1)) crdMin = int(crdMin + (1 if crdMin > 0 else -1)) # plot the coordinates dN, dE, dU and ns for i, crd in enumerate(crds2Plot): if i < 3: # subplots for coordinates display dN, dE, dU # plot over the different coordinate offsets using different colors # we plot offset to the weighted averga value # ax[i].plot(dfUTM['DT'], dCrd[crd], linestyle='', marker='.', markersize=2, color=colors[i], label=crd) # ax[i].fill_between(dfUTM['DT'], dCrd[crd]-dfUTM[stdDev2Plot[i]], dCrd[crd]+dfUTM[stdDev2Plot[i]], color=colors[i], alpha=0.15, interpolate=False) for key, value in rtkc.dRTKQual.items(): # get the indices according to the position mode idx = dfUTM.index[dfUTM['Q'] == key] rgb = mpcolors.colorConverter.to_rgb(colors[key]) rgb_new = amutils.make_rgb_transparent(rgb, (1, 1, 1), 0.3) # plot according to the color list if the length of the index is not 0 if len(idx) > 0: ax[i].errorbar(x=dfUTM.loc[idx]['DT'], y=dfCrd.loc[idx][crd], yerr=dfUTM.loc[idx][stdDev2Plot[i]], linestyle='None', fmt='o', ecolor=rgb_new, capthick=2, markersize=2, color=colors[key], label=value) # set dimensions of y-axis ax[i].set_ylim([crdMin, crdMax]) ax[i].set_ylabel('{crd:s} [m]'.format(crd=crd, fontsize='large')) # lcoation of legend ax[i].legend(loc='best', markerscale=4) # annotate plot annotatetxt = r'WAvg: {crd:.3f}m $\pm$ {sdcrd:.3f}m'.format( crd=amc.dRTK['WAVG'][crds2Plot[i]], sdcrd=amc.dRTK['WAVG'][stdDevWAvg[i]]) ax[i].annotate(annotatetxt, xy=(1, 1), xycoords='axes fraction', xytext=(0, 0), textcoords='offset pixels', horizontalalignment='right', verticalalignment='bottom', fontweight='bold', fontsize='large') else: # last subplot: age of corrections & #SVs # plot #SVs on left axis # ax[i].set_ylim([0, 24]) # plot AGE value ax[i].set_ylabel('Age [s]', fontsize='large', color='darkorchid') ax[i].set_xlabel('Time [sec]', fontsize='large') ax[i].plot(dfUTM['DT'], dfUTM['age'], linestyle='', marker='x', markersize=2, color='darkorchid', label='age') ax[i].set_title('#SVs & Age of correction', fontsize='large', fontweight='bold') # plot number of SV on second y-axis axRight = ax[i].twinx() axRight.set_ylim([0, 25]) axRight.set_ylabel('#SVs [-]', fontsize='large', color='grey') ax[i].fill_between(dfUTM['DT'], 0, dfUTM['ns'], alpha=0.5, linestyle='-', linewidth=3, color='grey', label='#SVs', interpolate=False) # create the ticks for the time axis dtFormat = plot_utils.determine_datetime_ticks( startDT=dfUTM['DT'].iloc[0], endDT=dfUTM['DT'].iloc[-1]) if dtFormat['minutes']: if dfUTM.shape[0] > 300: ax[i].xaxis.set_major_locator( dates.MinuteLocator(byminute=range(1, 60, 10), interval=1)) else: ax[i].xaxis.set_major_locator( dates.MinuteLocator(byminute=range(1, 60), interval=1)) else: ax[i].xaxis.set_major_locator( dates.HourLocator( interval=dtFormat['hourInterval'])) # every 4 hours ax[i].xaxis.set_major_formatter( dates.DateFormatter('%H:%M')) # hours and minutes ax[i].xaxis.set_minor_locator( dates.DayLocator(interval=1)) # every day ax[i].xaxis.set_minor_formatter(dates.DateFormatter('\n%d-%m-%Y')) ax[i].xaxis.set_tick_params(rotation=0) for tick in ax[i].xaxis.get_major_ticks(): # tick.tick1line.set_markersize(0) # tick.tick2line.set_markersize(0) tick.label1.set_horizontalalignment('center') # save the plot in subdir png of GNSSSystem pngName = os.path.join( dRtk['posDir'], '{name:s}-ENU.png'.format(name=os.path.splitext(dRtk['posFile'])[0])) fig.savefig(pngName, dpi=fig.dpi) logger.info('{func:s}: created plot {plot:s}'.format(func=cFuncName, plot=colored( pngName, 'green'))) if showplot: plt.show(block=True) else: plt.close(fig) return
def plotUTMCoords(dStf: dict, dfCrd: pd.DataFrame, logger=logging.Logger): """ plots the UTM coordinates and #SVs on 4 different plots as a function of time """ cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored( sys._getframe().f_code.co_name, 'green') crds = ['UTM.E', 'UTM.N', 'Height[m]', 'dist', 'NrSV'] # crds = ['dist', 'NrSV'] logger.info( '{func:s}: start plotting UTM coordinates'.format(func=cFuncName)) amutils.logHeadTailDataFrame(df=dfCrd, dfName='dfCrd', callerName=cFuncName, logger=logger) # specify the style mpl.style.use('seaborn') fig, axes = plt.subplots(nrows=len(crds), ncols=1, sharex=True) fig.set_size_inches(18.5, 15) # get the index for 2D/3D idx3D = dfCrd.index[dfCrd['2D/3D'] == 0] idx2D = dfCrd.index[dfCrd['2D/3D'] == 1] # get the index for signals used for PNT AND for 3D/2D dIdx = {} # dict with indices corresponding to signals & 3D/2D usage for st, lstSTNames in dStf['signals'].items(): stNames = ",".join(lstSTNames) logger.info('{func:s}: st = {st:d} name = {name!s}'.format( st=st, name=stNames, func=cFuncName)) dIdx[st] = {} dIdx[st]['3D'] = dfCrd.index[(dfCrd['SignalInfo'] == st) & (dfCrd['2D/3D'] == 0)] dIdx[st]['2D'] = dfCrd.index[(dfCrd['SignalInfo'] == st) & (dfCrd['2D/3D'] == 1)] logger.info( '{func:s}: list of indices dIdx[{st:d}][3D] = {idx!s}'.format( st=st, idx=dIdx[st]['3D'], func=cFuncName)) logger.info( '{func:s}: list of indices dIdx[{st:d}][2D] = {idx!s}'.format( st=st, idx=dIdx[st]['2D'], func=cFuncName)) # for setting the time on time-scale dtFormat = plot_utils.determine_datetime_ticks( startDT=dfCrd['time'].iloc[0], endDT=dfCrd['time'].iloc[-1]) for crd, ax in zip(crds, axes): # print in order UTM.E, UTM.N, height, and NrSV and indicate 2D/3D by alpha logger.info('{func:s}: plotting {crd:s}'.format(crd=crd, func=cFuncName)) # x-axis properties ax.set_xlim([dfCrd['time'].iloc[0], dfCrd['time'].iloc[-1]]) if dtFormat['minutes']: ax.xaxis.set_major_locator( dates.MinuteLocator(byminute=[0, 15, 30, 45], interval=1)) else: ax.xaxis.set_major_locator( dates.HourLocator( interval=dtFormat['hourInterval'])) # every 4 hours ax.xaxis.set_major_formatter( dates.DateFormatter('%H:%M')) # hours and minutes ax.xaxis.set_minor_locator(dates.DayLocator(interval=1)) # every day ax.xaxis.set_minor_formatter(dates.DateFormatter('\n%d-%m-%Y')) ax.xaxis.set_tick_params(rotation=0) for tick in ax.xaxis.get_major_ticks(): # tick.tick1line.set_markersize(0) # tick.tick2line.set_markersize(0) tick.label1.set_horizontalalignment('center') # (re)set the color iterator colorsIter = iter(list(mcolors.TABLEAU_COLORS)) if crd is not 'NrSV': # plot according to signals used and 2D/3D for st, lstSTNames in dStf['signals'].items(): stNames = ",".join(lstSTNames) for mode in '3D', '2D': lblTxt = '{st:s} ({mode:s})'.format(st=stNames, mode=mode) logger.debug('{func:s}: plotting {stm:s}'.format( stm=lblTxt, func=cFuncName)) # get the index for this sigType & mode idx = dIdx[st][mode] ax.plot(dfCrd['time'].iloc[idx], dfCrd[crd].iloc[idx], color=next(colorsIter), linestyle='', marker='.', label=lblTxt, markersize=2) else: # plot when 3D posn ax.fill_between(dfCrd['time'], dfCrd[crd], color='grey', alpha=.2) # plot when 3D posn ax.plot(dfCrd['time'].iloc[idx3D], dfCrd[crd].iloc[idx3D], color='green', linestyle='', marker='.', markersize=2, label='3D') # plot when 2D posn ax.plot(dfCrd['time'].iloc[idx2D], dfCrd[crd].iloc[idx2D], color='red', linestyle='', marker='.', markersize=2, label='2D') # name y-axis ax.set_ylabel(crd, fontsize=14) # add a legend the plot showing 2D/3D positioning displayed ax.legend(loc='best', ncol=16, markerscale=5) # title of plot title = '{syst:s}: UTM Coordinates'.format(syst=dStf['gnss']) fig.suptitle(title, fontsize=16) # copyright this ax.annotate(r'$\copyright$ Alain Muls ([email protected])', xy=(1, 0), xycoords='axes fraction', xytext=(0, -45), textcoords='offset pixels', horizontalalignment='right', verticalalignment='bottom', weight='strong', fontsize='medium') # Save the file in dir png pltDir = os.path.join(dStf['dir'], 'png') os.makedirs(pltDir, exist_ok=True) pltName = '{syst:s}-UTM.png'.format(syst=dStf['gnss'].replace(' ', '-')) pltName = os.path.join(pltDir, pltName) fig.savefig(pltName, dpi=100) logger.info('{func:s}: plot saved as {name:s}'.format(name=pltName, func=cFuncName)) plt.show(block=False)
def plotClock(dfClk: pd.DataFrame, dRtk: dict, logger: logging.Logger, showplot: bool = False): """ plotClock plots athe clock for all systems """ cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored( sys._getframe().f_code.co_name, 'green') # set up the plot plt.style.use('ggplot') colors = ['blue', 'red', 'green', 'black'] amc.logDataframeInfo(df=dfClk, dfName='dfClk', callerName=cFuncName, logger=logger) # find out for which system we have clk offset values GNSSSysts = [] for gnss in ['GAL', 'GPS', 'OTH', 'GLO']: if dfClk[gnss].any(): GNSSSysts.append(gnss) logger.info('{func:s}: Clock available for GNSS systems {syst:s}'.format( func=cFuncName, syst=' '.join(GNSSSysts))) # create the plot araea fig, axis = plt.subplots(nrows=len(GNSSSysts), ncols=1, figsize=(24.0, 20.0)) for i, GNSSsyst in enumerate(GNSSSysts): logger.info('{func:s}: plotting clock offset for {syst:s}'.format( func=cFuncName, syst=GNSSsyst)) # get the axis to draw to if len(GNSSSysts) == 1: ax = axis else: ax = axis[i] # create the plot for this GNSS system dfClk.plot(ax=ax, x='DT', y=GNSSsyst, marker='.', linestyle='', color=colors[i]) # create the ticks for the time axis dtFormat = plot_utils.determine_datetime_ticks( startDT=dfClk['DT'].iloc[0], endDT=dfClk['DT'].iloc[-1]) if dtFormat['minutes']: ax.xaxis.set_major_locator( dates.MinuteLocator(byminute=[0, 15, 30, 45], interval=1)) else: ax.xaxis.set_major_locator( dates.HourLocator( interval=dtFormat['hourInterval'])) # every 4 hours ax.xaxis.set_major_formatter( dates.DateFormatter('%H:%M')) # hours and minutes ax.xaxis.set_minor_locator(dates.DayLocator(interval=1)) # every day ax.xaxis.set_minor_formatter(dates.DateFormatter('\n%d-%m-%Y')) ax.xaxis.set_tick_params(rotation=0) for tick in ax.xaxis.get_major_ticks(): # tick.tick1line.set_markersize(0) # tick.tick2line.set_markersize(0) tick.label1.set_horizontalalignment('center') # name the axis ax.set_ylabel('{syst:s} Clock Offset [ns]'.format(syst=GNSSsyst), fontsize='large', color=colors[i]) ax.set_xlabel('Time', fontsize='large') # title of sub-plot ax.set_title('Clock offset relative to {syst:s} @ {date:s}'.format( syst=GNSSsyst, date=dfClk['DT'].iloc[0].strftime('%d %b %Y'), fontsize='large')) # save the plot in subdir png of GNSSSystem amutils.mkdir_p(os.path.join(dRtk['info']['dir'], 'png')) pngName = os.path.join( dRtk['info']['dir'], 'png', os.path.splitext(dRtk['info']['rtkPosFile'])[0] + '-CLK.png') # print('pngName = {:s}'.format(pngName)) fig.savefig(pngName, dpi=fig.dpi) logger.info('{func:s}: created plot {plot:s}'.format(func=cFuncName, plot=colored( pngName, 'green'))) if showplot: plt.show(block=True) else: plt.close(fig)
def plotAGC(dStf: dict, dfAgc: pd.DataFrame, logger=logging.Logger): """ plots the UTM coordinates and #SVs on 4 different plots as a function of time """ cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored(sys._getframe().f_code.co_name, 'green') logger.info('{func:s}: start plotting AGC values'.format(func=cFuncName)) amutils.logHeadTailDataFrame(df=dfAgc, dfName='dfAgc', callerName=cFuncName, logger=logger) # specify the style mpl.style.use('seaborn') colors = ['tab:green', 'tab:olive', 'tab:orange', 'tab:cyan', 'tab:blue', 'tab:red', 'tab:pink', 'tab:purple', 'tab:brown', 'tab:white'] # (re)set the color iterator # colorsIter = iter(list(mcolors.TABLEAU_COLORS)) colorsIter = iter(list(colors)) fig, ax = plt.subplots(nrows=1, ncols=1, sharex=True) fig.set_size_inches(14, 10) # for setting the time on time-scale dtFormat = plot_utils.determine_datetime_ticks(startDT=dfAgc['time'].iloc[0], endDT=dfAgc['time'].iloc[-1]) # x-axis properties ax.set_xlim([dfAgc['time'].iloc[0], dfAgc['time'].iloc[-1]]) if dtFormat['minutes']: ax.xaxis.set_major_locator(dates.MinuteLocator(byminute=[0, 15, 30, 45], interval=1)) else: ax.xaxis.set_major_locator(dates.HourLocator(interval=dtFormat['hourInterval'])) # every 4 hours ax.xaxis.set_major_formatter(dates.DateFormatter('%H:%M')) # hours and minutes ax.xaxis.set_minor_locator(dates.DayLocator(interval=1)) # every day ax.xaxis.set_minor_formatter(dates.DateFormatter('\n%d-%m-%Y')) ax.xaxis.set_tick_params(rotation=0) for tick in ax.xaxis.get_major_ticks(): # tick.tick1line.set_markersize(0) # tick.tick2line.set_markersize(0) tick.label1.set_horizontalalignment('center') # get the index for the different frontends dIdx = {} # dict with indices for i, fe in enumerate(dStf['frontend']): logger.info('{func:s}: ... plotting frontend[{nr:d}], SSNID = {ssnid:d}, name = {name:s}'.format(nr=i, ssnid=fe, name=dStf['frontend'][fe]['name'], func=cFuncName)) idx = dfAgc.index[dfAgc['FrontEnd'] == fe] logger.info('{func:s}: ... indices found {idx!s} (#{len:d})'.format(idx=idx, len=len(idx), func=cFuncName)) # plot the AGC for this frontend ax.plot(dfAgc['time'].loc[idx], dfAgc['AGCGain[dB]'].loc[idx], color=next(colorsIter), linestyle='', marker='.', label=dStf['frontend'][fe]['name'], markersize=3) # name y-axis ax.set_ylabel('AGC Gain [dB]', fontsize=14) # add a legend the plot showing 2D/3D positioning displayed ax.legend(loc='best', ncol=16, markerscale=6) # title of plot title = '{syst:s}: AGC Gain [dB]'.format(syst=dStf['gnss']) fig.suptitle(title, fontsize=16) # copyright this ax.annotate(r'$\copyright$ Alain Muls ([email protected])', xy=(1, 0), xycoords='axes fraction', xytext=(0, -45), textcoords='offset pixels', horizontalalignment='right', verticalalignment='bottom', weight='strong', fontsize='medium') # Save the file in dir png pltDir = os.path.join(dStf['dir'], 'png') os.makedirs(pltDir, exist_ok=True) pltName = '{syst:s}-AGC.png'.format(syst=dStf['gnss'].replace(' ', '-')) pltName = os.path.join(pltDir, pltName) fig.savefig(pltName, dpi=100) logger.info('{func:s}: plot saved as {name:s}'.format(name=pltName, func=cFuncName)) plt.show(block=True)
def plotRinexObservables(dPlot: dict, obsData: xarray.Dataset, logger=logging.Logger): """ plots the observales according to the selection made each plot combines separate plots for each signalType selected for all satellites """ cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored( sys._getframe().f_code.co_name, 'green') logger.info('{func:s}: start plotting\n{plt!s}'.format(plt=dPlot, func=cFuncName)) # deterimne layout of subplots according to number of signals we have to plot dSubPlotsLayout = { 1: [1, 1], 2: [2, 1], 3: [3, 1], 4: [2, 2], 5: [3, 2], 6: [3, 3], 7: [4, 3], 8: [4, 4] } # specify the style mpl.style.use('seaborn') # find the signalType to which each signal belongs sigTypes = [] for signal in dPlot['Signals']: sigType = list( set( rnxobs.findKeyOfSignal(signal, dict(rnxobs.dGAL, **rnxobs.dGPS)))) logger.info( '{func:s}: signal = {sign!s} signal type = {sigt!s}'.format( sign=signal, sigt=sigType, func=cFuncName)) sigTypes.append(sigType) # get rid of list of lists to get 1 list flatSigTypes = [item for sublist in sigTypes for item in sublist] # get the unique signal types out of this list uniqSigTypes = list(set(flatSigTypes)) logger.info('{func:s}: plot signal types (all) = {sigt!s}'.format( sigt=flatSigTypes, func=cFuncName)) logger.info('{func:s}: plot signal types (uniq) = {sigt!s}'.format( sigt=uniqSigTypes, func=cFuncName)) # the x-axis is a time axis, set its limits tLim = [dPlot['Time']['start'], dPlot['Time']['end']] logger.info('{func:s}: time limits = {tlim!s}'.format(tlim=tLim, func=cFuncName)) # create 1 plot for each uniq signalType with subplots for each signal of that sigType we have for i, sigType in enumerate(uniqSigTypes): logger.info('{func:s}: ----------------------'.format(func=cFuncName)) logger.info( '{func:s}: making plot for signal type {name!s} ({sigt:s})'.format( sigt=sigType, name=rnxobs.dSignalTypesNames[sigType]['name'], func=cFuncName)) # count the number of signals of this type to determine # of subplots nrSubPlotsSigType = len([v for v in flatSigTypes if v == sigType]) logger.info('{func:s}: sub plots created = {nrplt!s}'.format( nrplt=nrSubPlotsSigType, func=cFuncName)) # generate the subplots and its axes nrRows = dSubPlotsLayout[nrSubPlotsSigType][0] nrCols = dSubPlotsLayout[nrSubPlotsSigType][1] logger.info( '{func:s}: plot layout - rows={row:d} columns={col:d}'.format( row=nrRows, col=nrCols, func=cFuncName)) fig, axes = plt.subplots(nrows=nrRows, ncols=nrCols, sharex='col', sharey='row') fig.set_size_inches(18.5, 10.5) logger.debug('{func:s}: axes = {ax!s}'.format(ax=axes, func=cFuncName)) # axes_list = [item for sublist in axes for item in sublist] # find indices for signals of this signalType indexSigType = [ index for index, st in enumerate(flatSigTypes) if st == sigType ] logger.info('{func:s}: index for signal type = {ist!s}'.format( ist=indexSigType, func=cFuncName)) # determine the discrete colors for SVs colormap = plt.cm.nipy_spectral # I suggest to use nipy_spectral, Set1,Paired # colormap = plt.cm.Spectral #I suggest to use nipy_spectral, Set1,Paired colors = [colormap(i) for i in np.linspace(0, 1, dPlot['#SVs'])] logger.debug('{func:s}: colors = {colors!s}'.format(colors=colors, func=cFuncName)) # create the subplots for each signal of this sigType for indexAxes, indexSignal in enumerate(indexSigType): # get the axes to plot onto logger.info( '\n{func:s}: index axis = {iax:d} index signal = {isg:d}'. format(iax=indexAxes, isg=indexSignal, func=cFuncName)) axRow, axCol = divmod(indexAxes, nrCols) logger.info( '{func:s}: axis #row = {row:d} #column = {col:d}'.format( row=axRow, col=axCol, func=cFuncName)) try: ax = axes[axRow, axCol] except IndexError as e: logger.info('{func:s}: {err!s}'.format(err=colored(e, 'red'), func=cFuncName)) ax = axes[axRow] except TypeError as e: logger.info('{func:s}: {err!s}'.format(err=colored(e, 'red'), func=cFuncName)) ax = axes # add a UE RESTREINT if (axCol == 0 and axRow == 0) or (axCol == nrCols - 1 and axRow == nrRows - 1): ax.annotate( r'$\copyright$ Alain Muls - RESTREINT UE/EU RESTRICTED', xy=(1, 1), xycoords='axes fraction', xytext=(0, 0), textcoords='offset pixels', horizontalalignment='right', verticalalignment='bottom', fontsize='large', color='red') # get the name of the signal to plot on this axis signal = dPlot['Signals'][indexSignal] # get time interval timeInterval = [ datetime.datetime.strptime(dPlot['Time']['start'], "%Y-%m-%dT%H:%M:%S"), datetime.datetime.strptime(dPlot['Time']['end'], "%Y-%m-%dT%H:%M:%S") ] logger.info( '{func:s}: Plotting signal {!s} over interval {time!s}'.format( signal, time=timeInterval, func=cFuncName)) logger.info('{func:s}: for satellites {svs!s} (#{nr:d})'.format( svs=dPlot['SVs'], nr=len(dPlot['SVs']), func=cFuncName)) for iSV, sv in enumerate(dPlot['SVs']): obsData_time = obsData.sel( time=slice(timeInterval[0], timeInterval[1])) logger.info('{func:s} ... plotting satellite {sv:s}'.format( sv=sv, func=cFuncName)) # determine color for this SV by taking the color with th eindex of SV in AllSVs list colorSV = colors[dPlot['AllSVs'].index(sv)] ax.plot(obsData_time.time, obsData_time[signal].sel(sv=sv), label='{sv:s}'.format(sv=sv), color=colorSV, marker='.', markersize=3, linestyle='') # add a legend the plot showing the satellites displayed ax.legend(loc='best', ncol=16, markerscale=6) # find name of the signal in each constellation and use this for subplot title subTitle = 'Datafile {name:s}: '.format( name=os.path.basename(dPlot['name'])) if any([sv for sv in dPlot['SVs'] if sv.startswith('E')]): subTitle += subTitleGNSS(dGNSS=rnxobs.dGAL, signal=signal, logger=logger) if any([sv for sv in dPlot['SVs'] if sv.startswith('G')]): subTitle += subTitleGNSS(dGNSS=rnxobs.dGPS, signal=signal, logger=logger) logger.info('{func:s}: plot subtitle {sub:s}'.format( sub=subTitle, func=cFuncName)) # adjust the titles for the subplots ax.set_title(subTitle, fontsize=11) # ax.set_xlabel('Time') if axCol == 0: ax.set_ylabel('{name:s} {unit:s}'.format( name=rnxobs.dSignalTypesNames[sigType]['name'], unit=rnxobs.dSignalTypesNames[sigType]['unit']), fontsize=11) if signal.startswith('S'): ax.set_ylim([20, 60]) # create the ticks for the time axis dtFormat = plot_utils.determine_datetime_ticks( startDT=timeInterval[0], endDT=timeInterval[1]) if dtFormat['minutes']: ax.xaxis.set_major_locator( dates.MinuteLocator(byminute=[0, 15, 30, 45], interval=1)) else: ax.xaxis.set_major_locator( dates.HourLocator( interval=dtFormat['hourInterval'])) # every 4 hours ax.xaxis.set_major_formatter( dates.DateFormatter('%H:%M')) # hours and minutes ax.xaxis.set_minor_locator( dates.DayLocator(interval=1)) # every day ax.xaxis.set_minor_formatter(dates.DateFormatter('\n%d-%m-%Y')) ax.xaxis.set_tick_params(rotation=0) for tick in ax.xaxis.get_major_ticks(): # tick.tick1line.set_markersize(0) # tick.tick2line.set_markersize(0) tick.label1.set_horizontalalignment('center') # set title fig.suptitle(rnxobs.dSignalTypesNames[sigType]['name'], fontsize=16) # fig.tight_layout() fig.subplots_adjust(top=0.925) # save the figure (add satellite number is total satellites in plot is < 3) baseName = os.path.basename(dPlot['name']) dirName = os.path.dirname(dPlot['name']) os.makedirs(os.path.join(dirName, 'png'), exist_ok=True) if len(dPlot['SVs']) < 4: listSVs = '-'.join(dPlot['SVs']) figName = os.path.join( dirName, 'png', '{base:s}-{name:s}-{list:s}'.format( base=baseName, name=rnxobs.dSignalTypesNames[sigType]['name'], list=listSVs)) elif dPlot['#SVs'] == len(dPlot['SVs']): listSVs = 'ALL' figName = os.path.join( dirName, 'png', '{base:s}-{name:s}-{list:s}'.format( base=baseName, name=rnxobs.dSignalTypesNames[sigType]['name'], list=listSVs)) else: figName = os.path.join( dirName, 'png', '{base:s}-{name:s}'.format( base=baseName, name=rnxobs.dSignalTypesNames[sigType]['name'])) # figName += '{start:s}'.format(start=datetime.datetime.strptime(dPlot['Time']['start'], "%Y-%m-%dT%H:%M:%S")) # figName += '{end:s}'.format(end=datetime.datetime.strptime(dPlot['Time']['end'], "%Y-%m-%dT%H:%M:%S")) tmpName = figName.replace(' ', '-') tmp2Name = tmpName.replace('.', '-') tmpName = tmp2Name.replace('_', '') figName = tmpName + '.png' fig.savefig(figName, dpi=100) logger.info('{func:s}: plot saved as {name:s}'.format(name=figName, func=cFuncName)) plt.show()
def plotSignalDiff(dCsv: dict, dfSig: pd.DataFrame, logger=logging.Logger): """ Plot the signals and their difference per observed PRN """ cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored( sys._getframe().f_code.co_name, 'green') logger.info( '{func:s}: start plotting for signal difference {st0:s}-{st1:s}\n'. format(st0=dCsv[0]['signal'], st1=dCsv[1]['signal'], func=cFuncName)) # specify the style mpl.style.use('seaborn') # determine the discrete colors for SVs colormap = plt.cm.nipy_spectral # I suggest to use nipy_spectral, Set1,Paired # colormap = plt.cm.Spectral # I suggest to use nipy_spectral, Set1,Paired colors = [colormap(i) for i in np.linspace(0, 1, dCsv['#SVs'] * 3)] logger.debug('{func:s}: colors = {colors!s}'.format(colors=colors, func=cFuncName)) # max for signals itself y1Max = max(dCsv[0]['max'], dCsv[1]['max']) + 5 y1Min = min(dCsv[0]['min'], dCsv[1]['min']) - 5 # for formatting date time x axis dtFormat = plot_utils.determine_datetime_ticks( startDT=dfSig['time'].iloc[0], endDT=dfSig['time'].iloc[-1]) # go over all PRNs for i, prn in enumerate(dCsv['SVs']): logger.info('{func:s}: plotting for PRN {prn:s}'.format( prn=prn, func=cFuncName)) # create the figure and axes fig, ax1 = plt.subplots(figsize=(15, 10)) # x-axis properties ax1.set_xlim([dfSig['time'].iloc[0], dfSig['time'].iloc[-1]]) if dtFormat['minutes']: ax1.xaxis.set_major_locator( dates.MinuteLocator(byminute=[0, 15, 30, 45], interval=1)) else: ax1.xaxis.set_major_locator( dates.HourLocator( interval=dtFormat['hourInterval'])) # every 4 hours ax1.xaxis.set_major_formatter( dates.DateFormatter('%H:%M')) # hours and minutes ax1.xaxis.set_minor_locator(dates.DayLocator(interval=1)) # every day ax1.xaxis.set_minor_formatter(dates.DateFormatter('\n%d-%m-%Y')) ax1.xaxis.set_tick_params(rotation=0) for tick in ax1.xaxis.get_major_ticks(): # tick.tick1line.set_markersize(0) # tick.tick2line.set_markersize(0) tick.label1.set_horizontalalignment('center') # plot both signals in color for prn ax1.set_ylim([y1Min, y1Max]) prnst = '{prn:s}-{st:s}'.format(prn=prn, st=dCsv[0]['signal']) ax1.plot(dfSig['time'], dfSig[prnst], linestyle='-', marker='.', markersize=1, color='blue', label=prnst, alpha=0.5) prnst = '{prn:s}-{st:s}'.format(prn=prn, st=dCsv[1]['signal']) ax1.plot(dfSig['time'], dfSig[prnst], linestyle='-', marker='.', markersize=1, color='green', label=prnst, alpha=0.5) # add a legend the plot showing the satellites displayed ax1.legend(loc='upper left', ncol=16, markerscale=4) # plot the difference on second y-axis ax2 = ax1.twinx() if dCsv[0]['signal'].startswith('C'): ax2.set_ylim([0, 15]) elif dCsv[0]['signal'].startswith('S'): ax2.set_ylim([-15, 15]) else: ax2.set_ylim([dCsv['dMin'], dCsv['dMax']]) prnstdiff = '{prn:s}: {st0:s}-{st1:s}'.format(prn=prn, st0=dCsv[0]['signal'], st1=dCsv[1]['signal']) ax2.fill_between(dfSig['time'], dfSig[prn], linestyle='-', color='red', label=prnstdiff, alpha=0.5) # plot the moving average for this prn prnMA = '{prn:s}-MA'.format(prn=prn) movAvgTxt = 'MovAvg ({time:d}s: #{count:d}, mean={mean:.1f}, max={max:.1f}, min={min:.1f})'.format( time=dCsv['movavg'], count=dCsv['stats'][prn]['count'], max=dCsv['stats'][prn]['max'], min=dCsv['stats'][prn]['min'], mean=dCsv['stats'][prn]['mean']) ax2.plot(dfSig['time'], dfSig[prnMA], linestyle='-', marker='.', markersize=1, color='yellow', label=movAvgTxt) # add a legend the plot showing the satellites displayed ax2.legend(loc='upper right', ncol=16, markerscale=4) # title of plot shortName = dCsv[0]['file'].split('-')[0] title = '{file:s}: {syst:s} {prn:s} Signal difference {st0:s}-{st1:s}'.format( file=shortName, syst=dCsv['gnss'], prn=prn, st0=dCsv[0]['signal'], st1=dCsv[1]['signal']) fig.suptitle(title, fontsize=16) # Save the file in dir png pltDir = os.path.join(dCsv['dir'], 'png') os.makedirs(pltDir, exist_ok=True) pltName = '{file:s}-{syst:s}-{prn:s}-{st0:s}-{st1:s}.png'.format( file=shortName, syst=dCsv['gnss'], prn=prn, st0=dCsv[0]['signal'], st1=dCsv[1]['signal']) tmpName = pltName.replace(' ', '-') pltName = os.path.join(pltDir, tmpName) fig.savefig(pltName, dpi=100) logger.info('{func:s}: plot saved as {name:s}'.format(name=pltName, func=cFuncName)) plt.show(block=True)