Beispiel #1
0
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
Beispiel #2
0
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)
Beispiel #3
0
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)
Beispiel #5
0
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
Beispiel #6
0
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
Beispiel #7
0
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
Beispiel #9
0
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()
Beispiel #11
0
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()
Beispiel #12
0
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)
Beispiel #13
0
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)
Beispiel #14
0
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)
Beispiel #16
0
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
Beispiel #17
0
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)
Beispiel #18
0
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)
Beispiel #19
0
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
Beispiel #20
0
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)
Beispiel #21
0
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