def store_to_cvs(df: pd.DataFrame, ext: str, logger: logging.Logger, index: bool = True) -> str: """ store the dataframe to a CSV file """ cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored( sys._getframe().f_code.co_name, 'green') csv_name = amc.dRTK['glab_out'].split('.')[0] + '.' + ext # make dir if not exist dir_glabng = os.path.join(amc.dRTK['dir_root'], amc.dRTK['dgLABng']['dir_glab']) amutils.mkdir_p(dir_glabng) df.to_csv(os.path.join(dir_glabng, csv_name), index=index, header=True) # amutils.logHeadTailDataFrame(logger=logger, callerName=cFuncName, df=df, dfName=csv_name) logger.info('{func:s}: stored dataframe as csv file {csv:s}'.format( csv=colored(csv_name, 'yellow'), func=cFuncName)) return csv_name
def doNcFTPDownload(logger: logging.Logger): """ doNcFTPDownload downloads remote files using 'ncftget' program """ cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored(sys._getframe().f_code.co_name, 'green') # locate 'ncftpget' program exeNCFTPGET = location.locateProg('ncftpget', logger) # create and change to download directory amc.dRTK['local']['YYDOY'] = '{YY:s}{DOY:s}'.format(YY=amc.dRTK['date']['YY'], DOY=amc.dRTK['date']['DoY']) amc.dRTK['local']['dir'] = os.path.join(amc.dRTK['local']['root'], amc.dRTK['local']['YYDOY']) amutils.mkdir_p(amc.dRTK['local']['dir']) amutils.changeDir(amc.dRTK['local']['dir']) logger.info('{func:s}: changed to local directory {dir:s}'.format(dir=amc.dRTK['local']['dir'], func=cFuncName)) for gnss in amc.dRTK['remote'].keys(): logger.info('{func:s}: downloading for {gnss:s} RINEX Nav {nav:s}'.format(gnss=gnss, nav=amc.dRTK['remote'][gnss]['rfile'], func=cFuncName)) cmdNCFTPGET = '{prog:s} -u {user:s} -p {passwd:s} -v ftp://{host:s}/{rpath}/{rfile:s}'.format(prog=exeNCFTPGET, user=amc.dRTK['ftp']['user'], passwd=amc.dRTK['ftp']['passwd'], host=amc.dRTK['ftp']['server'], rpath=amc.dRTK['remote'][gnss]['rpath'], rfile=amc.dRTK['remote'][gnss]['rfile']) logger.info('{func:s}: ... running {cmd:s}'.format(cmd=cmdNCFTPGET, func=cFuncName)) # run the program exeprogram.subProcessDisplayStdErr(cmd=cmdNCFTPGET, verbose=True)
def checkValidityArgs(logger: logging.Logger) -> bool: """ checks for existence of dirs/files """ cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored( sys._getframe().f_code.co_name, 'green') # change to baseDir, everything is relative to this directory logger.info('{func:s}: check existence of rootDir {root:s}'.format( func=cFuncName, root=amc.dRTK['rootDir'])) amc.dRTK['rootDir'] = os.path.expanduser(amc.dRTK['rootDir']) if not os.path.exists(amc.dRTK['rootDir']): logger.error('{func:s} !!! Dir {basedir:s} does not exist.'.format( func=cFuncName, basedir=amc.dRTK['rootDir'])) return amc.E_INVALID_ARGS # make the coplete filename by adding to rootdir and check existence of binary file to convert amc.dRTK['binFile'] = os.path.join(amc.dRTK['rootDir'], amc.dRTK['binFile']) logger.info( '{func:s}: check existence of binary file {bin:s} to convert'.format( func=cFuncName, bin=amc.dRTK['binFile'])) if not os.access(amc.dRTK['binFile'], os.R_OK): logger.error( '{func:s} !!! binary observation file {bin:s} not accessible.'. format(func=cFuncName, bin=amc.dRTK['binFile'])) return amc.E_FILE_NOT_EXIST # check existence of rinexdir and create if needed logger.info( '{func:s}: check existence of rinexdir {rinex:s} and create if needed'. format(func=cFuncName, rinex=amc.dRTK['rinexDir'])) # amc.dRTK['rinexDir'] = os.path.join(amc.dRTK['rootDir'], amc.dRTK['rinexDir']) amutils.mkdir_p(amc.dRTK['rinexDir']) # check whether the rinexNaming arguments are correctly formatted amc.dRTK['marker'] = amc.dRTK['rinexNaming'][0] amc.dRTK['doy'] = amc.dRTK['rinexNaming'][1] amc.dRTK['yy'] = amc.dRTK['rinexNaming'][2] if (len(amc.dRTK['marker']) < 4) or (len(amc.dRTK['doy']) != 3) or (len( amc.dRTK['yy']) != 2): logger.error('{func:s}: Please enter rinexNaming as follows'.format( func=cFuncName)) logger.error('{func:s}: ... marker {marker:s} at least 4 chars'.format( func=cFuncName, marker=amc.dRTK['marker'])) logger.error('{func:s}: ... doy {doy:s} exact 3 chars'.format( func=cFuncName, doy=amc.dRTK['doy'])) logger.error('{func:s}: ... yy {yy:s} exact 2 chars'.format( func=cFuncName, yy=amc.dRTK['yy'])) return amc.E_INVALID_ARGS return amc.E_SUCCESS
def plot_xdop_distribution(dRtk: dict, dfXDOP: pd.DataFrame, dfXDOPdisp: pd.DataFrame, logger: logging.Logger, showplot: bool = False): """ plot_xdop_distribution plots the XDOP values and the distribution XDOPs """ cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored(sys._getframe().f_code.co_name, 'green') logger.info('{func:s}: creating XDOP distribution plot'.format(func=cFuncName)) # select colors for xDOP coordinate difference colors = ('blue', 'green', 'cyan', 'red') # set up the plot plt.style.use('ggplot') # subplots fig = plt.figure(figsize=(14.0, 9.0), tight_layout=False) fig.suptitle('{syst:s} - {posf:s} - {date:s}: XDOP'.format(posf=dRtk['info']['rtkPosFile'], syst=dRtk['syst'], date=dRtk['Time']['date'])) # create a grid for lotting the XDOP line plots and 6 XDOP distribution plots gs = GridSpec(2, 4) # plot the XDOPs and #SVs on the first axis ax = fig.add_subplot(gs[0, :]) # first row, span all columns plot_xdop_svs(dfDops=dfXDOP, colors=colors, axis=ax, logger=logger) # add the xDOP distributions axisShare = None for col, xdop, color in zip((0, 1, 2, 3), dfXDOPdisp.columns[-4:], colors): # create exis for this figure if axisShare is None: ax = fig.add_subplot(gs[1, col]) axisShare = ax else: ax = fig.add_subplot(gs[1, col], sharey=axisShare) # ax.get_yaxis().set_ticklabels([]) ax.tick_params(labelleft=False) # plot distribution for a DOP value plot_xdop_histogram(dfDopsDist=dfXDOPdisp, xdop=xdop, color=color, axis=ax, logger=logger) # 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] + '-XDOP.png') fig.savefig(pngName, dpi=fig.dpi) if showplot: plt.show(block=True) else: plt.close(fig)
def checkValidityArgs(logger: logging.Logger) -> bool: """ checks for existence of dirs/files and also for presence of base station observation when posmode > 0 (single) """ cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored(sys._getframe().f_code.co_name, 'green') # change to baseDir, everything is relative to this directory amc.dRTK['rootDir'] = os.path.expanduser(amc.dRTK['rootDir']) if not amutils.changeDir(amc.dRTK['rootDir']): logger.error('{func:s}: could not change to {basedir:s}.\n'.format(func=cFuncName, basedir=amc.dRTK['rootDir'])) return amc.E_INVALID_ARGS logger.info('{func:s}: changed to directory {basedir:s}'.format(func=cFuncName, basedir=colored(amc.dRTK['rootDir'], 'green'))) # create the rtkp directory for storing the result files according to the GNSS system processed amc.dRTK['rtkDir'] = os.path.join(amc.dRTK['rootDir'], 'rtkp', amc.dRTK['GNSS']) amutils.mkdir_p(amc.dRTK['rtkDir']) # check existence of rover observation file if not os.access(amc.dRTK['roverObs'], os.R_OK): logger.error('{func:s}: rover observation file {rover:s} not accessible.\n'.format(func=cFuncName, rover=amc.dRTK['roverObs'])) return amc.E_FILE_NOT_EXIST else: amc.dRTK['filePos'] = '{rover:s}.pos'.format(rover=os.path.join('rtkp', amc.dRTK['GNSS'], amc.dRTK['basename2use'])) amc.dRTK['fileStat'] = '{pos:s}.stat'.format(pos=amc.dRTK['filePos']) # check existence of ephemeris file for _, ephemFile in enumerate(amc.dRTK['ephems']): if not os.access(ephemFile, os.R_OK): logger.error('{func:s}: ephemeris file {ephem:s} not accessible.\n'.format(func=cFuncName, ephem=ephemFile)) return amc.E_FILE_NOT_EXIST # check existence of template file amc.dRTK['template'] = os.path.join(amc.dRTK['rootDir'], os.path.expanduser(amc.dRTK['template'])) if not os.access(os.path.abspath(amc.dRTK['template']), os.R_OK): logger.error('{func:s}: rnx2rtkp (rtkpos) template file {tmpl:s} not accessible.\n'.format(func=cFuncName, tmpl=amc.dRTK['template'])) return amc.E_FILE_NOT_EXIST # check if base station observation file is present when the positioning mode is not single (=0) if amc.dRTK['posMode'] != 'single': if not os.access(amc.dRTK['baseObs'], os.R_OK): logger.error('{func:s}: reference station observation file {base:s} not accessible.\n'.format(func=cFuncName, base=amc.dRTK['baseObs'])) return amc.E_FILE_NOT_EXIST return amc.E_SUCCESS
def rnxobs_statistics_file(dTmpRnx: dict, logger: logging.Logger): """ rnxobs_statistics_file creates the observation statistics per satellite system """ cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored(sys._getframe().f_code.co_name, 'green') # create the satsys option for extracting the observation statistics for only Galileo & GPS (if both present) satsystems = ''.join(amc.dRTK['rnx']['gnss']['select']).replace('M', '') # create the CLI command for getting observation statistics in a temporary file dTmpRnx['obsstat'] = dTmpRnx['obs'] + '.obsstat' args4GFZRNX = [amc.dRTK['bin']['GFZRNX'], '-finp', dTmpRnx['obs'], '-stk_obs', '-satsys', satsystems, '-fout', dTmpRnx['obsstat'], '-f'] logger.info('{func:s}: extracting RINEX observation statistics'.format(func=cFuncName)) amutils.run_subprocess(sub_proc=args4GFZRNX, logger=logger) # open the obsstat file for reading line by line finp = open(dTmpRnx['obsstat'], 'r') # read in the obsstat file per satellite system for _, satsys in enumerate(satsystems): # reset to start of file finp.seek(0, os.SEEK_SET) # create the directory under gfzrnx for this marker marker_dir = os.path.join(amc.dRTK['gfzrnxDir'], amc.dRTK['rnx']['gnss'][satsys]['marker']) amutils.mkdir_p(marker_dir) amc.dRTK['rnx']['gnss'][satsys]['obsstat'] = '{marker:s}{doy:03d}0-{yy:02d}O.obsstat'.format(marker=amc.dRTK['rnx']['gnss'][satsys]['marker'], doy=amc.dRTK['rnx']['times']['DoY'], yy=amc.dRTK['rnx']['times']['yy']) # create the file with the observation statistics for satsys logger.info('{func:s}: creating observation statistics {stat:s}'.format(stat=colored(amc.dRTK['rnx']['gnss'][satsys]['obsstat'], 'green'), func=cFuncName)) with open(os.path.join(marker_dir, amc.dRTK['rnx']['gnss'][satsys]['obsstat']), "w") as fout: for line in finp.readlines(): try: if satsys == line[10]: # found a line belonging to this satsys, replace the original marker name fout.write('{line:s}'.format(line=line[1:].replace(amc.dRTK['rnx']['marker'], amc.dRTK['rnx']['gnss'][satsys]['marker']))) except IndexError: # skip empty lines pass # close the obsstat file finp.close() pass
def checkValidityArgs(logger: logging.Logger) -> bool: """ checks for existence of dirs/files """ cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored( sys._getframe().f_code.co_name, 'green') # change to baseDir, everything is relative to this directory logger.info('{func:s}: check existence of rootDir {root:s}'.format( func=cFuncName, root=amc.dRTK['rootDir'])) amc.dRTK['rootDir'] = os.path.expanduser(amc.dRTK['rootDir']) if not os.path.exists(amc.dRTK['rootDir']): logger.error('{func:s} !!! Dir {basedir:s} does not exist.'.format( func=cFuncName, basedir=amc.dRTK['rootDir'])) return amc.E_INVALID_ARGS # make the coplete filename by adding to rootdir and check existence of binary file to convert logger.info( '{func:s}: check existence of binary file {bin:s} to convert'.format( func=cFuncName, bin=os.path.join(amc.dRTK['rootDir'], amc.dRTK['binFile']))) if not os.access(os.path.join(amc.dRTK['rootDir'], amc.dRTK['binFile']), os.R_OK): logger.error( '{func:s} !!! binary observation file {bin:s} not accessible.'. format(func=cFuncName, bin=amc.dRTK['binFile'])) return amc.E_FILE_NOT_EXIST # check existence of rinexdir and create if needed logger.info( '{func:s}: check existence of rinexdir {rinex:s} and create if needed'. format(func=cFuncName, rinex=amc.dRTK['rinexDir'])) amutils.mkdir_p(amc.dRTK['rinexDir']) # check existence of rinexdir and create if needed logger.info( '{func:s}: check existence of gfzrnxdir {gfzrnx:s} and create if needed' .format(func=cFuncName, gfzrnx=amc.dRTK['gfzrnxDir'])) amutils.mkdir_p(amc.dRTK['gfzrnxDir']) return amc.E_SUCCESS
def process_rover(dRover, dProj, logger: logging.Logger, overwrite=False): """ process_rover processes the rover according to the settings file :params dRover: information of the rover station :type dRover: dictionary :params dProj: information about project :type dProj: dictionary """ cFuncName = amc.cBaseName + ': ' + colored(sys._getframe().f_code.co_name, 'green') # create RNX2RTKP command line options amc.dSettings['PROGS']['rnx2rtkp'] = location.locateProg('rnx2rtkp') # convert directory for the specified positioning mode and rover dRover['rtkp_dir'] = os.path.join(amc.dSettings['PROJECT']['out_dir'], dProj['posmode'], dRover['name']) amutils.mkdir_p(dRover['rtkp_dir']) dRover['rtkp_pos'] = os.path.join(dRover['rtkp_dir'], '{stat:s}-{yy:d}{doy:d}.pos'.format(stat=dRover['name'], yy=amc.dSettings['PROJECT']['iYY'], doy=amc.dSettings['PROJECT']['iDOY'])) # dRover['posfile'] = dRover script = '{cmd:s} -k {conf:s} '.format(cmd=amc.dSettings['PROGS']['rnx2rtkp'], conf=amc.dSettings['RNX2RTKP']['rtkpconf']) if dProj['posmode'].lower() == 'single': logger.info('{func:s}\n... {mode:s} processing station {stat:s}'.format(func=cFuncName, mode=colored(amc.dSettings['PROJECT']['posmode'], 'yellow'), stat=colored(dRover['name'], 'yellow'))) script += '-o {out:s} {obs:s} {nav:s}'.format(out=dRover['rtkp_pos'], obs=dRover['rinex_name'], nav=amc.dSettings['NAV']['com']) else: logger.info('{func:s}\n... {mode:s} processing station {rvr:s}, reference {base:s}'.format(func=cFuncName, mode=colored(amc.dSettings['PROJECT']['posmode'], 'yellow'), rvr=colored(dRover['name'], 'yellow'), base=colored(amc.dSettings['BASE']['site'], 'yellow'))) if dProj['posmode'].lower() in ['dgps', 'static']: script += '-o {out:s} -r {xyz:s} {obs:s} {ref:s} {nav:s}'.format(out=dRover['rtkp_pos'], obs=dRover['rinex_name'], ref=amc.dSettings['BASE']['rinex'], nav=amc.dSettings['NAV']['com_rnx3'], xyz=amc.dSettings['BASE']['cart']) else: sys.stderr.write('{func:s}\n ... wrong positioning mode for RNX2RTKP: {mode:s}'.format(func=cFuncName, mode=dProj['posmode'])) logger.info('{func:s}: executing = {script!s}'.format(script=script, func=cfunc)) sys.exit(6) # execute script exeprogram.subProcessLogStdErr(command=script, logger=logger) pass
def create_tabular_observation(satsys: str, rnx_type: str, logger: logging.Logger) -> dict: """ create_tabular_observation creates a tabular view of all observables for all SVs in RINEX obs file """ cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored(sys._getframe().f_code.co_name, 'green') # create a tabular output file containing the observables for this satsys amutils.mkdir_p(os.path.join(amc.dRTK['gfzrnxDir'], amc.dRTK['rnx']['gnss'][satsys]['marker'])) dobs_tab = {} if satsys != 'M': dobs_tab[satsys] = amc.dRTK['rnx']['gnss'][satsys][rnx_type].replace('.', '-') + '.obstab' args4GFZRNX = [amc.dRTK['bin']['GFZRNX'], '-f', '-finp', os.path.join(amc.dRTK['rinexDir'], amc.dRTK['rnx']['gnss'][satsys][rnx_type]), '-fout', os.path.join(amc.dRTK['gfzrnxDir'], amc.dRTK['rnx']['gnss'][satsys]['marker'], dobs_tab[satsys]), '-tab_obs', '-satsys', satsys] logger.info('{func:s}: Creating observation tabular output {obstab:s}'.format(obstab=colored(dobs_tab[satsys], 'green'), func=cFuncName)) # run the program # gfzrnx -finp GALI1340.19O -tab_obs -satsys E 2> /dev/null -fout /tmp/E-ALL.t amutils.run_subprocess(sub_proc=args4GFZRNX, logger=logger) else: # create a file for GALI and one for GPSN from COMB RNX OBS file for sat_syst, sat_syst_name in zip(['E', 'G'], ['GALI', 'GPSN']): dobs_tab[sat_syst] = sat_syst_name + amc.dRTK['rnx']['gnss'][satsys][rnx_type].replace('.', '-')[4:] + '.obstab' print('dobs_tab[sat_syst] = {!s}'.format(dobs_tab[sat_syst])) args4GFZRNX = [amc.dRTK['bin']['GFZRNX'], '-f', '-finp', os.path.join(amc.dRTK['rinexDir'], amc.dRTK['rnx']['gnss'][satsys][rnx_type]), '-fout', os.path.join(amc.dRTK['gfzrnxDir'], amc.dRTK['rnx']['gnss'][satsys]['marker'], dobs_tab[sat_syst]), '-tab_obs', '-satsys', sat_syst] logger.info('{func:s}: Creating observation tabular output {obstab:s}'.format(obstab=colored(dobs_tab[sat_syst], 'green'), func=cFuncName)) # run the program # gfzrnx -finp GALI1340.19O -tab_obs -satsys E 2> /dev/null -fout /tmp/E-ALL.t amutils.run_subprocess(sub_proc=args4GFZRNX, logger=logger) # return the created files name return dobs_tab
def plot_glab_statistics(df_dopenu: pd.DataFrame, scale: float, logger: logging.Logger, showplot: bool = False): """ plot_glab_statistics plots the position statitictics according to COP bins """ cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored( sys._getframe().f_code.co_name, 'green') logger.info( '{func:s}: plotting position statistics'.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) # create additional column assigning the values of crd diffs to the correct PDOP bin dop_bins = [] for dop_min, dop_max in zip(amc.dRTK['dop_bins'][:-1], amc.dRTK['dop_bins'][1:]): bin_interval = 'bin{:d}-{:.0f}'.format(dop_min, dop_max) dop_bins.append(bin_interval) logger.info('{func:s}: setting for PDOP bin = {bin!s}'.format( bin=bin_interval, func=cFuncName)) # add column 'bin' for grouping the results during plotting df_dopenu.loc[(df_dopenu['PDOP'] > dop_min) & (df_dopenu['PDOP'] <= dop_max), 'bin'] = bin_interval # amutils.printHeadTailDataFrame(df=df_dopenu, name='df_dopenu', index=False) fig, axes = plt.subplots(nrows=4, ncols=len(dop_bins), sharex=True, sharey='row', figsize=(18, 8), gridspec_kw={ 'height_ratios': (.065, .065, .065, .805), 'wspace': 0.02, 'hspace': 0.02 }) # define the axis used for the boxplots and histogram ax_box = axes[:3] ax_hist = axes[-1] for axis in ax_hist: axis.set_xlim([-1.5 * scale, +1.5 * scale]) # go over the coordinate differences for i, (crd, enu_color) in enumerate(zip(['dN0', 'dE0', 'dU0'], glc.enu_colors)): # create the plot holding for each DOP bin the histogram and bixplot combined in a subfigure for j, bin in enumerate(dop_bins): # boxplot in above 3xj subplots sns.boxplot(df_dopenu.loc[df_dopenu['bin'] == bin][crd], ax=ax_box[i][j], orient='h', color=enu_color, width=0.9, linewidth=1) cur_xaxis = ax_box[i][j].axes.get_xaxis() cur_xaxis.set_visible(False) # cur_yaxis = ax_box[i][j].axes.get_yaxis() if j == 0: ax_box[i][j].set_ylabel(crd, color=enu_color) else: cur_yaxis = ax_box[i][j].axes.get_yaxis() cur_yaxis.set_visible(False) # distplot in last subplot for column j sns.distplot(df_dopenu.loc[df_dopenu['bin'] == bin][crd], ax=ax_hist[j], color=glc.enu_colors[i]) ax_hist[j].set_xlabel('PDOP[{bin:s}]'.format(bin=bin[3:])) # global title fig.suptitle('{title:s}'.format(title=plot_title), **glc.title_font) # plot annotations ax_box[0][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_box[0][-1].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_hist[-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') # 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}-boxhist.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 scatter plot {plot:s}'.format( func=cFuncName, plot=colored(png_filename, 'green'))) plt.show()
def plot_rise_set_stats(gnss: str, df_arcs: pd.DataFrame, nr_arcs: int, logger: logging.Logger, showplot: bool = False): """ plot_rise_set_stats plots the rise/set statistics per SVs """ cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored(sys._getframe().f_code.co_name, 'green') logger.info('{func:s}: plotting observation statistics'.format(func=cFuncName)) # amutils.logHeadTailDataFrame(logger=logger, callerName=cFuncName, df=df_dt, dfName='df_dt') # set up the plot plt.style.use('ggplot') # plt.style.use('seaborn-darkgrid') dx_obs, dx_tle, arc_width = bars_info(nr_arcs=nr_arcs, logger=logger) # create colormap with 36 discrete colors arc_colors, title_font = amutils.create_colormap_font(nrcolors=nr_arcs, font_size=12) x = np.arange(df_arcs.shape[0]) # the label locations # subplots fig, (ax1, ax2) = plt.subplots(figsize=(14.0, 9.0), nrows=2) fig.suptitle('Rise/Set for {gnss:s} - {marker:s} - {date:s}'.format(gnss=amc.dRTK['rnx']['gnss'][gnss]['name'], marker=amc.dRTK['rnx']['gnss'][gnss]['marker'], date='{date:s} ({yy:02d}/{doy:03d})'.format(date=amc.dRTK['rnx']['times']['DT'][:10], yy=amc.dRTK['rnx']['times']['yy'], doy=amc.dRTK['rnx']['times']['DoY'])), fontdict=title_font, fontsize=24) # creating bar plots for absolute values for i_arc, (obs_dx, tle_dx) in enumerate(zip(dx_obs, dx_tle)): ax1.bar(x + tle_dx, df_arcs['Arc{arc:d}_tle'.format(arc=i_arc)], width=arc_width, color=arc_colors[i_arc], alpha=0.35, edgecolor='black', hatch='//', label='TLE Arc {arc:d}'.format(arc=i_arc)) ax1.bar(x + obs_dx, df_arcs['Arc{arc:d}_obs'.format(arc=i_arc)], width=arc_width, color=arc_colors[i_arc], label='Obs Arc {arc:d}'.format(arc=i_arc)) # beautify plot ax1.xaxis.grid() ax1.legend(loc='center left', bbox_to_anchor=(1, 0.5)) # ax1.set_xlabel('PRN', fontdict=title_font) ax1.set_ylabel('#Observed / #Predicted', fontdict=title_font) # setticks on X axis to represent the PRN ax1.xaxis.set_ticks(np.arange(0, df_arcs.shape[0], 1)) ax1.xaxis.set_major_formatter(ticker.FormatStrFormatter('%0.0f')) ax1.set_xticklabels(df_arcs['PRN'], rotation=90) # # creating bar plots for relative values for i_arc, (obs_dx, tle_dx) in enumerate(zip(dx_obs, dx_tle)): ax2.bar(x + tle_dx, (df_arcs['Arc{arc:d}_%'.format(arc=i_arc)] * 100), width=arc_width, color=arc_colors[i_arc], label='Perc Arc {arc:d}'.format(arc=i_arc)) # write the percentage in the bars for i, patch in enumerate(ax2.patches[i_arc * df_arcs.shape[0]:]): if not np.isnan(df_arcs.iloc[i]['Arc{arc:d}_%'.format(arc=i_arc)]): ax2.text(patch.get_x(), patch.get_y() + 2, '{rnd:.1f}%'.format(rnd=(df_arcs.iloc[i]['Arc{arc:d}_%'.format(arc=i_arc)] * 100)), fontsize=8, rotation=90, color='black', verticalalignment='bottom') # beautify plot ax2.xaxis.grid() ax2.legend(loc='center left', bbox_to_anchor=(1, 0.5)) ax2.set_xlabel('PRN', fontdict=title_font) ax2.set_ylabel('Percentage', fontdict=title_font) # setticks on X axis to represent the PRN ax2.xaxis.set_ticks(np.arange(0, df_arcs.shape[0], 1)) ax2.xaxis.set_major_formatter(ticker.FormatStrFormatter('%0.0f')) ax2.set_xticklabels(df_arcs['PRN'], rotation=90) # save the plot in subdir png of GNSSSystem png_dir = os.path.join(amc.dRTK['gfzrnxDir'], amc.dRTK['rnx']['gnss'][gnss]['marker'], 'png') amutils.mkdir_p(png_dir) pngName = os.path.join(png_dir, os.path.splitext(amc.dRTK['rnx']['gnss'][gnss]['obstab'])[0] + '-obs.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) plt.show()
def plotUTMScatterBin(dRtk: dict, dfPos: pd.DataFrame, dfCrd: dict, dCrdLim: dict, logger: logging.Logger, showplot: bool = False): """ plotUTMScatter plots scatter plot (per DOPbin) """ 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.]) # set up the plot plt.style.use('ggplot') # subplots fig, ax = plt.subplots(nrows=2, ncols=3, figsize=(16.0, 11.0)) print('ax = {!s}'.format(ax)) # make title for plot fig.suptitle('UTM Scatter {syst:s} - {posf:s} - {date:s}'.format(syst=dRtk['syst'], posf=dRtk['info']['rtkPosFile'], date=dRtk['Time']['date']), weight='strong', fontsize='xx-large') # copyright this ax[1][2].annotate(r'$\copyright$ Alain Muls ([email protected])', xy=(1, 0), xycoords='axes fraction', xytext=(0, -90), textcoords='offset pixels', horizontalalignment='right', verticalalignment='bottom', weight='strong', fontsize='medium') # annotate with reference position if [amc.dRTK['marker']['UTM.E'], amc.dRTK['marker']['UTM.N'], amc.dRTK['marker']['ellH']] == [np.NaN, np.NaN, np.NaN]: annotatePosRef = 'E = {east:.3f}, N = {north:.3f}'.format(east=amc.dRTK['WAvg']['UTM.E'], north=amc.dRTK['WAvg']['UTM.N']) else: annotatePosRef = 'E = {east:.3f}, N = {north:.3f}'.format(east=amc.dRTK['marker']['UTM.E'], north=amc.dRTK['marker']['UTM.N']) ax[1][0].annotate(annotatePosRef, xy=(0, 0), xycoords='axes fraction', xytext=(0, -90), textcoords='offset pixels', horizontalalignment='left', verticalalignment='bottom', weight='strong', fontsize='medium') # get the marker styles markerBins = predefinedMarkerStyles() # go over all PDOP bins and plot according to the markersBin defined for i in range(0, len(dRtk['PDOP']['bins']) - 1): binInterval = 'bin{:d}-{:.0f}'.format(dRtk['PDOP']['bins'][i], dRtk['PDOP']['bins'][i + 1]) index4Bin = (dfPos['PDOP'] > dRtk['PDOP']['bins'][i]) & (dfPos['PDOP'] <= dRtk['PDOP']['bins'][i + 1]) # print('index4Bin = {!s}'.format(np.sum(index4Bin))) lblBin = r'{!s} $\leq$ PDOP $<$ {!s} ({:.1f}%, #{:d})'.format(dRtk['PDOP']['bins'][i], dRtk['PDOP']['bins'][i + 1], dRtk['PDOP'][binInterval]['perc'] * 100, np.sum(index4Bin)) logger.info('{func:s}: {bin:s}'.format(func=cFuncName, bin=lblBin)) # get the axis axis = ax[i // 3][i % 3] # plot per dopBin axis.plot(dfCrd.loc[index4Bin, 'UTM.E'], dfCrd.loc[index4Bin, 'UTM.N'], label=lblBin, **markerBins[i + 1]) # draw circles for distancd evaluation on plot for radius in range(1, 15, 1): newCircle = plt.Circle((0, 0), radius, color='blue', fill=False, clip_on=True, alpha=0.4) axis.add_artist(newCircle) # annotate the radius for 1, 2, 5 and 10 meter # if radius in [1, 2, 3, 4, 5, 10]: axis.annotate('{radius:d}m'.format(radius=radius), xy=(np.pi / 4, radius), xytext=(np.pi / 4, radius), textcoords='polar', xycoords='polar', clip_on=True, color='blue', alpha=0.4) # lcoation of legend axis.legend(loc='best', markerscale=6) # add titles to axes axis.set_xlim([-7.5, +7.5]) axis.set_ylim([-7.5, +7.5]) axis.set_aspect(aspect='equal', adjustable='box') # nema the axis axis.set_xlabel('UTM East [m]', fontsize='large') axis.set_ylabel('UTM North [m]', 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] + '-scatter-bin.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)
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 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 plot_elev_distribution(dRtk: dict, df: pd.DataFrame, ds: pd.Series, obs_name: str, logger: logging.Logger, showplot: bool = False): """ plot_elev_distribution plots the distribution of CN0 or PRres as function of elevation bins """ cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored( sys._getframe().f_code.co_name, 'green') logger.info('{func:s}: creating {obs:s} distribution plot'.format( obs=obs_name, func=cFuncName)) amutils.logHeadTailDataFrame(logger=logger, callerName=cFuncName, df=df, dfName=obs_name) # set up the plot plt.style.use('ggplot') # possible GNSS systems in df gnss_names = ('GAL', 'GPS') colors = ('blue', 'red') dgnss_avail = {} col_width = 0.25 for gnss_name in gnss_names: dgnss_avail[gnss_name] = any( [True for col in df if col.startswith(gnss_name)]) nrCols = 3 col_move = 0 if all(dgnss_avail.values()): tmpValue = divmod(len(df.columns) / 2, nrCols) col_move = 0.125 else: tmpValue = divmod(len(df.columns), nrCols) syst_names = ' + '.join([k for k, v in dgnss_avail.items() if v == True]) if (tmpValue[1] == 0): nrRows = int(tmpValue[0]) else: nrRows = int(tmpValue[0]) + 1 # get the elevation bins used elev_bins = list(set([col[3:] for col in df.columns])) elev_bins.sort() logger.info('{func:s}: elevation bins {bins!s}'.format(bins=elev_bins, func=cFuncName)) logger.info('{func:s}: elevation bins sorted {bins!s}'.format( bins=elev_bins.sort(), func=cFuncName)) fig, ax = plt.subplots(nrows=nrRows, ncols=nrCols, sharex=True, sharey=True, figsize=(20.0, 12.0)) fig.suptitle('{syst:s} - {posf:s} - {date:s}: {obs:s} Statistics'.format( posf=dRtk['info']['rtkPosFile'], syst=syst_names, date=dRtk['Time']['date'], obs=obs_name), fontsize='xx-large') for i, elev_bin, gnss, color in zip((-1, +1), elev_bins, dgnss_avail, colors): # plot if the gnss is avaiable if dgnss_avail[gnss]: logger.info('{func:s}: plotting for system {gnss:s}'.format( gnss=gnss, func=cFuncName)) # the indexes on the x-axis ind = np.arange(len(df.index)) logger.info('{func:s}: ind = {ind!s}'.format(ind=ind, func=cFuncName)) # columns of this system gnss_cols = [ '{gnss:s}{bin:s}'.format(gnss=gnss, bin=elev_bin) for elev_bin in elev_bins ] # calculate the total number of observations per system obs_per_bin = df.loc[:, gnss_cols].sum() logger.info('{func:s}: obs_per_bin = {nrobs!s}'.format( nrobs=obs_per_bin, func=cFuncName)) if obs_name == 'PRres': # get index numbers for PRres between -2 and +2 tmpValue = divmod(df.shape[0], 2) if tmpValue[1] == 0: mid_prres = tmpValue[0] - 0.5 else: mid_prres = tmpValue for axis, col in zip(ax.flat, gnss_cols): # create a filled area for domain [-1, 1] if PRres plot if obs_name == 'PRres': axis.axvspan(mid_prres - 2, mid_prres + 2, alpha=0.1, color='green') # draw a bar plot axis.bar(ind + (i * col_move), df[col] / obs_per_bin.sum() * 100, alpha=0.5, color=color, edgecolor='none') # rotate the ticks on this axis idx = np.asarray([i for i in range(len(df.index))]) axis.set_xticks(idx) axis.set_xticklabels(df.index.tolist(), rotation='vertical') axis.annotate('# = {:.0f} ({:.2f}%)'.format( ds[col], ds[col] / ds.sum() * 100), xy=(1, 1), xycoords='axes fraction', xytext=(0, -25), textcoords='offset pixels', horizontalalignment='right', verticalalignment='bottom', weight='strong', fontsize='large') # set the title for sub-plot axis.set_title( label='Elevation bin {bin:s}'.format(bin=col[3:]), fontsize='x-large') # set the title for the Y axis axis.set_ylabel( '{obs:s} statistics in [%]'.format(obs=obs_name)) # 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] + '-{syst:s}-{obs:s}-dist.png'.format(syst=syst_names.replace(" ", ""), obs=obs_name)) fig.savefig(pngName, dpi=fig.dpi) 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 plot_rise_set_times(gnss: str, df_rs: pd.DataFrame, logger: logging.Logger, showplot: bool = False): """ plot_rise_set_times plots the rise/set times vs time per SVs as observed / predicted """ cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored(sys._getframe().f_code.co_name, 'green') logger.info('{func:s}: plotting rise/set times'.format(func=cFuncName)) # amutils.logHeadTailDataFrame(logger=logger, callerName=cFuncName, df=df_dt, dfName='df_dt') # set up the plot plt.style.use('ggplot') # plt.style.use('seaborn-darkgrid') # create colormap with 36 discrete colors max_prn = 36 prn_colors, title_font = amutils.create_colormap_font(nrcolors=max_prn, font_size=12) # subplots fig, ax = plt.subplots(figsize=(16.0, 10.0)) fig.suptitle('Rise/Set for {gnss:s} - {marker:s} - {date:s}'.format(gnss=amc.dRTK['rnx']['gnss'][gnss]['name'], marker=amc.dRTK['rnx']['gnss'][gnss]['marker'], date='{date:s} ({yy:02d}/{doy:03d})'.format(date=amc.dRTK['rnx']['times']['DT'][:10], yy=amc.dRTK['rnx']['times']['yy'], doy=amc.dRTK['rnx']['times']['DoY'])), fontdict=title_font, fontsize=24) # draw the rise to set lines per PRN for prn in df_rs.index: y_prn = int(prn[1:]) - 1 # get the lists with rise / set times as observed for dt_obs_rise, dt_obs_set in zip(df_rs.loc[prn]['obs_rise'], df_rs.loc[prn]['obs_set']): ax.plot_date([dt_obs_rise, dt_obs_set], [y_prn, y_prn], linestyle='solid', color=prn_colors[y_prn], linewidth=2, marker='v', markersize=4, alpha=1) # get the lists with rise / set times by TLEs for dt_tle_rise, dt_tle_set, dt_tle_cul in zip(df_rs.loc[prn]['tle_rise'], df_rs.loc[prn]['tle_set'], df_rs.loc[prn]['tle_cul']): ax.plot_date([dt_tle_rise, dt_tle_set], [y_prn - 0.25, y_prn - 0.25], linestyle='--', color=prn_colors[y_prn], linewidth=2, marker='^', markersize=4, alpha=0.5) # add a indicator for the culmination time of PRN ax.plot(dt_tle_cul, y_prn - 0.25, marker='d', markersize=4, alpha=0.5, color=prn_colors[y_prn]) # format the date time ticks ax.xaxis.set_major_locator(dates.DayLocator(interval=1)) ax.xaxis.set_major_formatter(dates.DateFormatter('\n%d-%m-%Y')) ax.xaxis.set_minor_locator(dates.HourLocator(interval=3)) ax.xaxis.set_minor_formatter(dates.DateFormatter('%H:%M')) plt.xticks() # format the y-ticks to represent the PRN number plt.yticks(np.arange(0, max_prn)) prn_ticks = [''] * max_prn # get list of observed PRN numbers (without satsyst letter) prn_nrs = [int(prn[1:]) for prn in df_rs.index] # and the corresponding ticks for prn_nr, prn_txt in zip(prn_nrs, df_rs.index): prn_ticks[prn_nr - 1] = prn_txt # adjust color for y ticks for color, tick in zip(prn_colors, ax.yaxis.get_major_ticks()): tick.label1.set_color(color) # set the color property tick.label1.set_fontweight('bold') ax.set_yticklabels(prn_ticks) # set the axis labels ax.set_xlabel('Time', fontdict=title_font) ax.set_ylabel('PRN', fontdict=title_font) # save the plot in subdir png of GNSSSystem png_dir = os.path.join(amc.dRTK['gfzrnxDir'], amc.dRTK['rnx']['gnss'][gnss]['marker'], 'png') amutils.mkdir_p(png_dir) pngName = os.path.join(png_dir, os.path.splitext(amc.dRTK['rnx']['gnss'][gnss]['obstab'])[0] + '-RS.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)
def plot_glab_scatter_bin(dfCrd: pd.DataFrame, scale: float, center: str, logger: logging.Logger, showplot: bool = False): """ plot_glab_scatter plots the horizontal 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 EN scattering'.format(func=cFuncName)) # # select colors for E, N, U coordinate difference # colors = [] # colors.append([51 / 256., 204 / 256., 51 / 256.]) # 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=2, ncols=3, figsize=(16.0, 11.0)) # figure title fig.suptitle('{title:s}'.format(title=plot_title), **glc.title_font) # plot annotations ax[0][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][2].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][2].annotate(r'$\copyright$ Alain Muls ([email protected])', xy=(1, 0), xycoords='axes fraction', xytext=(0, -70), textcoords='offset pixels', horizontalalignment='right', verticalalignment='bottom', weight='ultrabold', fontsize='x-small') # annotate with reference position txt_rx_posn = r'$\varphi = ${lat:.8f}, $\lambda = ${lon:.8f}'.format( lat=rx_geod[0], lon=rx_geod[1]) ax[1][0].annotate(txt_rx_posn, xy=(0, 0), xycoords='axes fraction', xytext=(0, -70), textcoords='offset pixels', horizontalalignment='left', verticalalignment='bottom', weight='strong', fontsize='medium') # get the marker styles markerBins = glc.predefined_marker_styles() # go over all PDOP bins and plot according to the markersBin defined for i in range(0, len(amc.dRTK['dop_bins']) - 1): binInterval = 'bin{:d}-{:.0f}'.format(amc.dRTK['dop_bins'][i], amc.dRTK['dop_bins'][i + 1]) logger.info('{func:s}: binInterval = {bin!s}'.format(bin=binInterval, func=cFuncName)) index4Bin = (dfCrd['PDOP'] > amc.dRTK['dop_bins'][i]) & ( dfCrd['PDOP'] <= amc.dRTK['dop_bins'][i + 1]) # get the axis axis = ax[i // 3][i % 3] # get th epercentage of observations within this dop_bin bin_percentage = '{perc:.1f}'.format( perc=amc.dRTK['dgLABng']['stats']['dop_bin'][binInterval]['perc'] * 100) lblBin = r'{!s} $\leq$ PDOP $<$ {!s} ({:s}%, #{:d})'.format( amc.dRTK['dop_bins'][i], amc.dRTK['dop_bins'][i + 1], bin_percentage, amc.dRTK['dgLABng']['stats']['dop_bin'][binInterval]['count']) logger.info('{func:s}: {bin:s}'.format(func=cFuncName, bin=lblBin)) # define center position if center == 'origin': wavg_E = wavg_N = 0 else: wavg_E = amc.dRTK['dgLABng']['stats']['crd']['dE0']['wavg'] wavg_N = amc.dRTK['dgLABng']['stats']['crd']['dN0']['wavg'] circle_center = (wavg_E, wavg_N) # draw circles for distancd evaluation on plot for radius in np.linspace(scale / 5, scale * 2, num=10): newCircle = plt.Circle(circle_center, radius, color='blue', fill=False, clip_on=True, alpha=0.4) axis.add_artist(newCircle) # annotate the radius for 1, 2, 5 and 10 meter # if radius in [1, 2, 3, 4, 5, 10]: # axis.annotate('{radius:.2f}m'.format(radius=radius), xy=(np.pi / 4, radius), xytext=(np.pi / 4, radius), textcoords='polar', xycoords='polar', clip_on=True, color='blue', alpha=0.4) axis.annotate('{radius:.2f}m'.format(radius=radius), xy=(wavg_E + np.cos(np.pi / 4) * radius, wavg_N + np.sin(np.pi / 4) * radius), xytext=(wavg_E + np.cos(np.pi / 4) * radius, wavg_N + np.sin(np.pi / 4) * radius), clip_on=True, color='blue', alpha=0.4) # plot the coordinates for each bin axis.plot(dfCrd.loc[index4Bin, 'dE0'], dfCrd.loc[index4Bin, 'dN0'], label=r'{!s} $\leq$ PDOP $<$ {!s} ({:s}%)'.format( amc.dRTK['dop_bins'][i], amc.dRTK['dop_bins'][i + 1], bin_percentage), **markerBins[(i)]) # lcoation of legend axis.legend(loc='best', markerscale=6, fontsize='x-small') # add titles to axes axis.set_xlim([wavg_E - scale, wavg_E + scale]) axis.set_ylim([wavg_N - scale, wavg_N + scale]) axis.set_aspect(aspect='equal', adjustable='box') # nema the axis if i > 2: axis.set_xlabel('East [m]', fontsize='large') axis.set_ylabel('North [m]', fontsize='large') # 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}-scatter-bins.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 scatter plot {plot:s}'.format( func=cFuncName, plot=colored(png_filename, 'green'))) if showplot: plt.show(block=True) else: plt.close(fig)
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 rnx_prsobs_plot(dArgs: dict, prn: str, stobs: list, dfPrn: pd.DataFrame, rawobs: list, logger: logging.Logger, showplot: bool = False): """ rnx_prsobs_plot plots the observations for PRN contained in dfPRN for a specific systyp """ cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored( sys._getframe().f_code.co_name, 'green') # deterimine text for the sigtyp plotted if stobs[0][0] == 'C': str_obs = 'Pseudo Range [m]' elif stobs[0][0] == 'S': str_obs = 'Signal strength [dbHz]' elif stobs[0][0] == 'L': str_obs = 'Carrier waves [-]' elif stobs[0][0] == 'D': str_obs = 'Doppler frequency [Hz]' # set up the plot plt.style.use('ggplot') # determine the discrete colors for all observables colormap = plt.cm.tab20 # I suggest to use nipy_spectral, Set1, Paired colors = [colormap(i) for i in np.linspace(0, 1, len(stobs) * 2)] # print('colors = {!s}'.format(colors)) fig, ax = plt.subplots(figsize=(18.0, 12.0)) # print the raw observables on first y axis count = 0 lstlabels = [] # store the label info for i, obs in enumerate([obs for obs in stobs if obs in rawobs]): txt_label = ax.plot(dfPrn['DT'], dfPrn[obs], color=colors[i], marker='.', linestyle='-', markersize=3, label=obs, alpha=max(0.9 - 0.075 * i, 0.25)) lstlabels += txt_label count += 1 ax.set_ylabel('Signal Type: {:s}'.format(str_obs), fontsize='large') ax.set_xlabel('Date time', fontsize='large') # print the difference in observables on second y axis ax2 = ax.twinx() for j, obs in enumerate([obs for obs in stobs if obs not in rawobs]): txt_label = ax2.plot(dfPrn['DT'], dfPrn[obs], color=colors[count + j], marker='x', linestyle='-', markersize=3, label=obs, alpha=max(0.9 - 0.075 * j, 0.25)) lstlabels += txt_label ax2.set_ylabel('Difference of Signal Type: {:s}'.format(str_obs), fontsize='large') # show combined label information labs = [l.get_label() for l in lstlabels] ax.legend(lstlabels, labs, loc='upper center', bbox_to_anchor=(0.5, 1.025), ncol=10, fancybox=True, shadow=True, facecolor='white', framealpha=1, fontsize='large', markerscale=6) # # get the individual lines inside legend and set line width # leg = ax.legend() # for line in leg.get_lines(): # line.set_linewidth(4) # # get label texts inside legend and set font size # for text in leg.get_texts(): # text.set_fontsize('x-large') # set the title of plot fig.suptitle('File: {name:s} | PRN: {prn:s} | Type: {obs:s}'.format( name=dArgs['obs_name'], obs=str_obs, prn=prn), fontsize='x-large') # save the plot in subdir png of GNSSSystem amutils.mkdir_p('png') pngName = os.path.join( 'png', '{name:s}-{prn:s}-{obs:s}.png'.format(name=dArgs['obs_name'].replace( '.', '-'), prn=prn, obs=stobs[0][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)
def plot_enu_distribution(dRtk: dict, dfENUdist: pd.DataFrame, dfENUstat: pd.DataFrame, logger: logging.Logger, showplot: bool = False): """ plot_enu_distribution plots the distribution for the ENU coordinates """ cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored(sys._getframe().f_code.co_name, 'green') logger.info('{func:s}: creating ENU distribution plot'.format(func=cFuncName)) # 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.]) # set up the plot plt.style.use('ggplot') # subplots fig, ax = plt.subplots(nrows=1, ncols=4, sharex=True, sharey=True, figsize=(24.0, 10.0)) fig.suptitle('{syst:s} - {posf:s} - {date:s}: ENU Statistics'.format(posf=dRtk['info']['rtkPosFile'], syst=dRtk['syst'], date=dRtk['Time']['date'])) # the indexes on the x-axis ind = np.arange(len(dfENUdist.index)) for axis, crd, color in zip(ax[:3], ('dUTM.E', 'dUTM.N', 'dEllH'), colors): axis.bar(ind, dfENUdist[crd], alpha=0.5, color=color, edgecolor='none') # rotate the ticks on this axis axis.set_xticklabels(dfENUdist.index.tolist(), rotation='vertical') # set the title for sub-plot axis.set_title(label=crd, color=color, fontsize='large') # annotate the plot with the statistics calculated axis.annotate(r'Mean = {:.3f}'.format(dfENUstat.loc['mean', crd]), xy=(1, 1), xycoords='axes fraction', xytext=(0, -25), textcoords='offset pixels', horizontalalignment='right', verticalalignment='bottom', weight='strong', fontsize='medium') axis.annotate(r'$\sigma$ = {:.3f}'.format(dfENUstat.loc['std', crd]), xy=(1, 1), xycoords='axes fraction', xytext=(0, -45), textcoords='offset pixels', horizontalalignment='right', verticalalignment='bottom', weight='strong', fontsize='medium') # add the 3 distributions on 1 subplot for comparing width = .25 for i, crd, color in zip((-1, 0, +1), ('dUTM.E', 'dUTM.N', 'dEllH'), colors): ax[-1].bar(ind + (i * width), dfENUdist[crd], width=width, alpha=0.5, color=color, edgecolor='none') # rotate the ticks on this axis ax[-1].set_xticklabels(dfENUdist.index.tolist(), rotation='vertical') # set the ticks on the x-axis ax[0].set_xlim([ind[0], ind[-1]]) ax[0].xaxis.set_major_locator(FixedLocator(ind)) # copyright this ax[-1].annotate(r'$\copyright$ Alain Muls ([email protected])', xy=(1, 1), xycoords='axes fraction', xytext=(0, +25), textcoords='offset pixels', horizontalalignment='right', verticalalignment='bottom', weight='strong', fontsize='medium') # 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-dist.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