def plot_xdop_svs(dfDops: pd.DataFrame, colors: tuple, axis, logger: logging.Logger):
    """
    plot_xdop_svs plots the XDOP curves and #SVs on a given axis
    """
    cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored(sys._getframe().f_code.co_name, 'green')

    logger.info('{func:s}: creating XDOP / #SVs vs time plot'.format(func=cFuncName))

    axis.set_ylim([0, 24])
    axis.set_ylabel('#SVs [-]', fontsize='large', color='grey')
    # axis.set_xlabel('Time [sec]', fontsize='large')

    axis.fill_between(dfDops['DT'], 0, dfDops['#SVs'], alpha=0.5, linestyle='-', linewidth=3, color='grey', label='#SVs', interpolate=False)
    # plot PDOP on second y-axis
    axRight = axis.twinx()

    axRight.set_ylim([0, 15])
    axRight.set_ylabel('XDOP [-]', fontsize='large')

    # plot XDOPs (last 4 columns)
    for dop, color in zip(dfDops.columns[-4:], colors):
        axRight.plot(dfDops['DT'], dfDops[dop], linestyle='-', marker='.', markersize=1, color=color, label=dop)

    # add the legend to the plot
    axRight.legend(loc="upper right")

    # set title
    axis.set_title('Visible satellites & XDOP', fontsize='x-large')

    # create the ticks for the time axis
    dtFormat = plot_utils.determine_datetime_ticks(startDT=dfDops['DT'].iloc[0], endDT=dfDops['DT'].iloc[-1])

    if dtFormat['minutes']:
        # axis.xaxis.set_major_locator(dates.MinuteLocator(byminute=range(10, 60, 10), interval=1))
        pass
    else:
        axis.xaxis.set_major_locator(dates.HourLocator(interval=dtFormat['hourInterval']))   # every 4 hours
    axis.xaxis.set_major_formatter(dates.DateFormatter('%H:%M'))  # hours and minutes

    axis.xaxis.set_minor_locator(dates.DayLocator(interval=1))    # every day
    axis.xaxis.set_minor_formatter(dates.DateFormatter('\n%d-%m-%Y'))

    axis.xaxis.set_tick_params(rotation=0)
    for tick in axis.xaxis.get_major_ticks():
        # tick.tick1line.set_markersize(0)
        # tick.tick2line.set_markersize(0)
        tick.label1.set_horizontalalignment('center')
Пример #2
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
Пример #3
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)
Пример #4
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
Пример #5
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)
Пример #6
0
def plot_utm_ellh(dRtk: dict,
                  dfUTM: pd.DataFrame,
                  logger: logging.Logger,
                  showplot: bool = False):
    """
     plots the UTM coordinates

    """
    cFuncName = colored(os.path.basename(__file__),
                        'yellow') + ' - ' + colored(
                            sys._getframe().f_code.co_name, 'green')

    # select colors for position mode
    # colors = []
    # colors.append([51 / 256., 204 / 256., 51 / 256.])
    # colors.append([51 / 256., 51 / 256., 255 / 256.])
    # colors.append([255 / 256., 51 / 256., 51 / 256.])
    colors = [
        'tab:white', 'tab:green', 'tab:olive', 'tab:orange', 'tab:cyan',
        'tab:blue', 'tab:red', 'tab:pink', 'tab:purple', 'tab:brown'
    ]

    # what to plot
    crds2Plot = ['UTM.E', 'UTM.N', 'ellH', 'age']
    stdDev2Plot = ['sde', 'sdn', 'sdu']
    stdDevWAvg = ['sdUTM.E', 'sdUTM.N', 'sdellH']

    # set up the plot
    plt.style.use('ggplot')

    # subplots
    fig, ax = plt.subplots(nrows=len(crds2Plot),
                           ncols=1,
                           sharex=True,
                           figsize=(20.0, 16.0))

    # make title for plot
    ax[0].annotate(
        '{camp:s} - {date:s} - {marker:s} ({pos:s}, quality {mode:s})'.format(
            camp=dRtk['campaign'],
            date=dRtk['obsStart'].strftime('%d %b %Y'),
            marker=dRtk['marker'],
            pos=dRtk['posFile'],
            mode=dRtk['rtkqual'].upper()),
        xy=(0.5, 1),
        xycoords='axes fraction',
        xytext=(0, 0),
        textcoords='offset pixels',
        horizontalalignment='center',
        verticalalignment='bottom',
        weight='strong',
        fontsize='large')

    # copyright this
    ax[-1].annotate(r'$\copyright$ Alain Muls ([email protected])',
                    xy=(1, 1),
                    xycoords='axes fraction',
                    xytext=(0, 0),
                    textcoords='offset pixels',
                    horizontalalignment='right',
                    verticalalignment='bottom',
                    weight='strong',
                    fontsize='large')

    # determine the difference to weighted average or marker position of UTM (N,E), ellH to plot
    dfCrd = pd.DataFrame(columns=crds2Plot[:3])
    originCrds = [float(amc.dRTK['WAVG'][crd]) for crd in crds2Plot[:3]]
    dfCrd = dfUTM[crds2Plot[:3]].sub(originCrds, axis='columns')
    amutils.logHeadTailDataFrame(logger=logger,
                                 callerName=cFuncName,
                                 df=dfCrd,
                                 dfName='dfCrd')

    crdMax = max(dfCrd.max())
    crdMin = min(dfCrd.min())
    crdMax = int(crdMax + (1 if crdMax > 0 else -1))
    crdMin = int(crdMin + (1 if crdMin > 0 else -1))

    # plot the coordinates dN, dE, dU and ns
    for i, crd in enumerate(crds2Plot):
        if i < 3:  # subplots for coordinates display dN, dE, dU
            # plot over the different coordinate offsets using different colors

            # we plot offset to the weighted averga value
            # ax[i].plot(dfUTM['DT'], dCrd[crd], linestyle='', marker='.', markersize=2, color=colors[i], label=crd)
            # ax[i].fill_between(dfUTM['DT'], dCrd[crd]-dfUTM[stdDev2Plot[i]], dCrd[crd]+dfUTM[stdDev2Plot[i]], color=colors[i], alpha=0.15, interpolate=False)

            for key, value in rtkc.dRTKQual.items():
                # get the indices according to the position mode
                idx = dfUTM.index[dfUTM['Q'] == key]
                rgb = mpcolors.colorConverter.to_rgb(colors[key])
                rgb_new = amutils.make_rgb_transparent(rgb, (1, 1, 1), 0.3)

                # plot according to the color list if the length of the index is not 0
                if len(idx) > 0:
                    ax[i].errorbar(x=dfUTM.loc[idx]['DT'],
                                   y=dfCrd.loc[idx][crd],
                                   yerr=dfUTM.loc[idx][stdDev2Plot[i]],
                                   linestyle='None',
                                   fmt='o',
                                   ecolor=rgb_new,
                                   capthick=2,
                                   markersize=2,
                                   color=colors[key],
                                   label=value)

            # set dimensions of y-axis
            ax[i].set_ylim([crdMin, crdMax])
            ax[i].set_ylabel('{crd:s} [m]'.format(crd=crd, fontsize='large'))

            # lcoation of legend
            ax[i].legend(loc='best', markerscale=4)

            # annotate plot
            annotatetxt = r'WAvg: {crd:.3f}m $\pm$ {sdcrd:.3f}m'.format(
                crd=amc.dRTK['WAVG'][crds2Plot[i]],
                sdcrd=amc.dRTK['WAVG'][stdDevWAvg[i]])
            ax[i].annotate(annotatetxt,
                           xy=(1, 1),
                           xycoords='axes fraction',
                           xytext=(0, 0),
                           textcoords='offset pixels',
                           horizontalalignment='right',
                           verticalalignment='bottom',
                           fontweight='bold',
                           fontsize='large')

        else:  # last subplot: age of corrections & #SVs
            # plot #SVs on left axis
            # ax[i].set_ylim([0, 24])

            # plot AGE value
            ax[i].set_ylabel('Age [s]', fontsize='large', color='darkorchid')
            ax[i].set_xlabel('Time [sec]', fontsize='large')
            ax[i].plot(dfUTM['DT'],
                       dfUTM['age'],
                       linestyle='',
                       marker='x',
                       markersize=2,
                       color='darkorchid',
                       label='age')
            ax[i].set_title('#SVs & Age of correction',
                            fontsize='large',
                            fontweight='bold')

            # plot number of SV on second y-axis
            axRight = ax[i].twinx()

            axRight.set_ylim([0, 25])
            axRight.set_ylabel('#SVs [-]', fontsize='large', color='grey')

            ax[i].fill_between(dfUTM['DT'],
                               0,
                               dfUTM['ns'],
                               alpha=0.5,
                               linestyle='-',
                               linewidth=3,
                               color='grey',
                               label='#SVs',
                               interpolate=False)

            # create the ticks for the time axis
            dtFormat = plot_utils.determine_datetime_ticks(
                startDT=dfUTM['DT'].iloc[0], endDT=dfUTM['DT'].iloc[-1])

            if dtFormat['minutes']:
                if dfUTM.shape[0] > 300:
                    ax[i].xaxis.set_major_locator(
                        dates.MinuteLocator(byminute=range(1, 60, 10),
                                            interval=1))
                else:
                    ax[i].xaxis.set_major_locator(
                        dates.MinuteLocator(byminute=range(1, 60), interval=1))

            else:
                ax[i].xaxis.set_major_locator(
                    dates.HourLocator(
                        interval=dtFormat['hourInterval']))  # every 4 hours
            ax[i].xaxis.set_major_formatter(
                dates.DateFormatter('%H:%M'))  # hours and minutes

            ax[i].xaxis.set_minor_locator(
                dates.DayLocator(interval=1))  # every day
            ax[i].xaxis.set_minor_formatter(dates.DateFormatter('\n%d-%m-%Y'))

            ax[i].xaxis.set_tick_params(rotation=0)
            for tick in ax[i].xaxis.get_major_ticks():
                # tick.tick1line.set_markersize(0)
                # tick.tick2line.set_markersize(0)
                tick.label1.set_horizontalalignment('center')

    # save the plot in subdir png of GNSSSystem
    pngName = os.path.join(
        dRtk['posDir'],
        '{name:s}-ENU.png'.format(name=os.path.splitext(dRtk['posFile'])[0]))
    fig.savefig(pngName, dpi=fig.dpi)

    logger.info('{func:s}: created plot {plot:s}'.format(func=cFuncName,
                                                         plot=colored(
                                                             pngName,
                                                             'green')))

    if showplot:
        plt.show(block=True)
    else:
        plt.close(fig)

    return
Пример #7
0
def plotUTMCoords(dStf: dict, dfCrd: pd.DataFrame, logger=logging.Logger):
    """
    plots the UTM coordinates and #SVs on 4 different plots as a function of time
    """
    cFuncName = colored(os.path.basename(__file__),
                        'yellow') + ' - ' + colored(
                            sys._getframe().f_code.co_name, 'green')
    crds = ['UTM.E', 'UTM.N', 'Height[m]', 'dist', 'NrSV']
    # crds = ['dist', 'NrSV']

    logger.info(
        '{func:s}: start plotting UTM coordinates'.format(func=cFuncName))

    amutils.logHeadTailDataFrame(df=dfCrd,
                                 dfName='dfCrd',
                                 callerName=cFuncName,
                                 logger=logger)

    # specify the style
    mpl.style.use('seaborn')

    fig, axes = plt.subplots(nrows=len(crds), ncols=1, sharex=True)
    fig.set_size_inches(18.5, 15)

    # get the index for 2D/3D
    idx3D = dfCrd.index[dfCrd['2D/3D'] == 0]
    idx2D = dfCrd.index[dfCrd['2D/3D'] == 1]

    # get the index for signals used for PNT AND for 3D/2D
    dIdx = {}  # dict with indices corresponding to signals & 3D/2D usage
    for st, lstSTNames in dStf['signals'].items():
        stNames = ",".join(lstSTNames)
        logger.info('{func:s}: st = {st:d}  name = {name!s}'.format(
            st=st, name=stNames, func=cFuncName))
        dIdx[st] = {}
        dIdx[st]['3D'] = dfCrd.index[(dfCrd['SignalInfo'] == st)
                                     & (dfCrd['2D/3D'] == 0)]
        dIdx[st]['2D'] = dfCrd.index[(dfCrd['SignalInfo'] == st)
                                     & (dfCrd['2D/3D'] == 1)]
        logger.info(
            '{func:s}: list of indices dIdx[{st:d}][3D] = {idx!s}'.format(
                st=st, idx=dIdx[st]['3D'], func=cFuncName))
        logger.info(
            '{func:s}: list of indices dIdx[{st:d}][2D] = {idx!s}'.format(
                st=st, idx=dIdx[st]['2D'], func=cFuncName))

    # for setting the time on time-scale
    dtFormat = plot_utils.determine_datetime_ticks(
        startDT=dfCrd['time'].iloc[0], endDT=dfCrd['time'].iloc[-1])

    for crd, ax in zip(crds, axes):
        # print in order UTM.E, UTM.N, height, and NrSV and indicate 2D/3D by alpha
        logger.info('{func:s}: plotting {crd:s}'.format(crd=crd,
                                                        func=cFuncName))

        # x-axis properties
        ax.set_xlim([dfCrd['time'].iloc[0], dfCrd['time'].iloc[-1]])
        if dtFormat['minutes']:
            ax.xaxis.set_major_locator(
                dates.MinuteLocator(byminute=[0, 15, 30, 45], interval=1))
        else:
            ax.xaxis.set_major_locator(
                dates.HourLocator(
                    interval=dtFormat['hourInterval']))  # every 4 hours
        ax.xaxis.set_major_formatter(
            dates.DateFormatter('%H:%M'))  # hours and minutes

        ax.xaxis.set_minor_locator(dates.DayLocator(interval=1))  # every day
        ax.xaxis.set_minor_formatter(dates.DateFormatter('\n%d-%m-%Y'))

        ax.xaxis.set_tick_params(rotation=0)
        for tick in ax.xaxis.get_major_ticks():
            # tick.tick1line.set_markersize(0)
            # tick.tick2line.set_markersize(0)
            tick.label1.set_horizontalalignment('center')

        # (re)set the color iterator
        colorsIter = iter(list(mcolors.TABLEAU_COLORS))

        if crd is not 'NrSV':
            # plot according to signals used and 2D/3D
            for st, lstSTNames in dStf['signals'].items():
                stNames = ",".join(lstSTNames)
                for mode in '3D', '2D':
                    lblTxt = '{st:s} ({mode:s})'.format(st=stNames, mode=mode)
                    logger.debug('{func:s}: plotting {stm:s}'.format(
                        stm=lblTxt, func=cFuncName))

                    # get the index for this sigType & mode
                    idx = dIdx[st][mode]
                    ax.plot(dfCrd['time'].iloc[idx],
                            dfCrd[crd].iloc[idx],
                            color=next(colorsIter),
                            linestyle='',
                            marker='.',
                            label=lblTxt,
                            markersize=2)
        else:
            # plot when 3D posn
            ax.fill_between(dfCrd['time'], dfCrd[crd], color='grey', alpha=.2)

            # plot when 3D posn
            ax.plot(dfCrd['time'].iloc[idx3D],
                    dfCrd[crd].iloc[idx3D],
                    color='green',
                    linestyle='',
                    marker='.',
                    markersize=2,
                    label='3D')
            # plot when 2D posn
            ax.plot(dfCrd['time'].iloc[idx2D],
                    dfCrd[crd].iloc[idx2D],
                    color='red',
                    linestyle='',
                    marker='.',
                    markersize=2,
                    label='2D')

        # name y-axis
        ax.set_ylabel(crd, fontsize=14)

        # add a legend the plot showing 2D/3D positioning displayed
        ax.legend(loc='best', ncol=16, markerscale=5)

    # title of plot
    title = '{syst:s}: UTM Coordinates'.format(syst=dStf['gnss'])
    fig.suptitle(title, fontsize=16)

    # copyright this
    ax.annotate(r'$\copyright$ Alain Muls ([email protected])',
                xy=(1, 0),
                xycoords='axes fraction',
                xytext=(0, -45),
                textcoords='offset pixels',
                horizontalalignment='right',
                verticalalignment='bottom',
                weight='strong',
                fontsize='medium')

    # Save the file in dir png
    pltDir = os.path.join(dStf['dir'], 'png')
    os.makedirs(pltDir, exist_ok=True)
    pltName = '{syst:s}-UTM.png'.format(syst=dStf['gnss'].replace(' ', '-'))
    pltName = os.path.join(pltDir, pltName)
    fig.savefig(pltName, dpi=100)

    logger.info('{func:s}: plot saved as {name:s}'.format(name=pltName,
                                                          func=cFuncName))

    plt.show(block=False)
Пример #8
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)
Пример #9
0
def plotAGC(dStf: dict, dfAgc: pd.DataFrame, logger=logging.Logger):
    """
    plots the UTM coordinates and #SVs on 4 different plots as a function of time
    """
    cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored(sys._getframe().f_code.co_name, 'green')

    logger.info('{func:s}: start plotting AGC values'.format(func=cFuncName))

    amutils.logHeadTailDataFrame(df=dfAgc, dfName='dfAgc', callerName=cFuncName, logger=logger)

    # specify the style
    mpl.style.use('seaborn')
    colors = ['tab:green', 'tab:olive', 'tab:orange', 'tab:cyan', 'tab:blue', 'tab:red', 'tab:pink', 'tab:purple', 'tab:brown', 'tab:white']
    # (re)set the color iterator
    # colorsIter = iter(list(mcolors.TABLEAU_COLORS))
    colorsIter = iter(list(colors))

    fig, ax = plt.subplots(nrows=1, ncols=1, sharex=True)
    fig.set_size_inches(14, 10)

    # for setting the time on time-scale
    dtFormat = plot_utils.determine_datetime_ticks(startDT=dfAgc['time'].iloc[0], endDT=dfAgc['time'].iloc[-1])

    # x-axis properties
    ax.set_xlim([dfAgc['time'].iloc[0], dfAgc['time'].iloc[-1]])
    if dtFormat['minutes']:
        ax.xaxis.set_major_locator(dates.MinuteLocator(byminute=[0, 15, 30, 45], interval=1))
    else:
        ax.xaxis.set_major_locator(dates.HourLocator(interval=dtFormat['hourInterval']))   # every 4 hours
    ax.xaxis.set_major_formatter(dates.DateFormatter('%H:%M'))  # hours and minutes

    ax.xaxis.set_minor_locator(dates.DayLocator(interval=1))    # every day
    ax.xaxis.set_minor_formatter(dates.DateFormatter('\n%d-%m-%Y'))

    ax.xaxis.set_tick_params(rotation=0)
    for tick in ax.xaxis.get_major_ticks():
        # tick.tick1line.set_markersize(0)
        # tick.tick2line.set_markersize(0)
        tick.label1.set_horizontalalignment('center')

    # get the index for the different frontends
    dIdx = {}  # dict with indices
    for i, fe in enumerate(dStf['frontend']):
        logger.info('{func:s}: ... plotting frontend[{nr:d}], SSNID = {ssnid:d}, name = {name:s}'.format(nr=i, ssnid=fe, name=dStf['frontend'][fe]['name'], func=cFuncName))

        idx = dfAgc.index[dfAgc['FrontEnd'] == fe]
        logger.info('{func:s}:    ... indices found {idx!s} (#{len:d})'.format(idx=idx, len=len(idx), func=cFuncName))

        # plot the AGC for this frontend
        ax.plot(dfAgc['time'].loc[idx], dfAgc['AGCGain[dB]'].loc[idx], color=next(colorsIter), linestyle='', marker='.', label=dStf['frontend'][fe]['name'], markersize=3)

    # name y-axis
    ax.set_ylabel('AGC Gain [dB]', fontsize=14)

    # add a legend the plot showing 2D/3D positioning displayed
    ax.legend(loc='best', ncol=16, markerscale=6)

    # title of plot
    title = '{syst:s}: AGC Gain [dB]'.format(syst=dStf['gnss'])
    fig.suptitle(title, fontsize=16)

    # copyright this
    ax.annotate(r'$\copyright$ Alain Muls ([email protected])', xy=(1, 0), xycoords='axes fraction', xytext=(0, -45), textcoords='offset pixels', horizontalalignment='right', verticalalignment='bottom', weight='strong', fontsize='medium')

    # Save the file in dir png
    pltDir = os.path.join(dStf['dir'], 'png')
    os.makedirs(pltDir, exist_ok=True)
    pltName = '{syst:s}-AGC.png'.format(syst=dStf['gnss'].replace(' ', '-'))
    pltName = os.path.join(pltDir, pltName)
    fig.savefig(pltName, dpi=100)

    logger.info('{func:s}: plot saved as {name:s}'.format(name=pltName, func=cFuncName))

    plt.show(block=True)
Пример #10
0
def plotRinexObservables(dPlot: dict,
                         obsData: xarray.Dataset,
                         logger=logging.Logger):
    """
    plots the observales according to the selection made
    each plot combines separate plots for each signalType selected for all satellites
    """
    cFuncName = colored(os.path.basename(__file__),
                        'yellow') + ' - ' + colored(
                            sys._getframe().f_code.co_name, 'green')

    logger.info('{func:s}: start plotting\n{plt!s}'.format(plt=dPlot,
                                                           func=cFuncName))

    # deterimne layout of subplots according to number of signals we have to plot
    dSubPlotsLayout = {
        1: [1, 1],
        2: [2, 1],
        3: [3, 1],
        4: [2, 2],
        5: [3, 2],
        6: [3, 3],
        7: [4, 3],
        8: [4, 4]
    }

    # specify the style
    mpl.style.use('seaborn')

    # find the signalType to which each signal belongs
    sigTypes = []
    for signal in dPlot['Signals']:
        sigType = list(
            set(
                rnxobs.findKeyOfSignal(signal, dict(rnxobs.dGAL,
                                                    **rnxobs.dGPS))))
        logger.info(
            '{func:s}: signal = {sign!s}   signal type = {sigt!s}'.format(
                sign=signal, sigt=sigType, func=cFuncName))
        sigTypes.append(sigType)

    # get rid of list of lists to get 1 list
    flatSigTypes = [item for sublist in sigTypes for item in sublist]
    # get the unique signal types out of this list
    uniqSigTypes = list(set(flatSigTypes))
    logger.info('{func:s}: plot signal types (all)  = {sigt!s}'.format(
        sigt=flatSigTypes, func=cFuncName))
    logger.info('{func:s}: plot signal types (uniq) = {sigt!s}'.format(
        sigt=uniqSigTypes, func=cFuncName))

    # the x-axis is a time axis, set its limits
    tLim = [dPlot['Time']['start'], dPlot['Time']['end']]
    logger.info('{func:s}: time limits = {tlim!s}'.format(tlim=tLim,
                                                          func=cFuncName))

    # create 1 plot for each uniq signalType with subplots for each signal of that sigType we have
    for i, sigType in enumerate(uniqSigTypes):
        logger.info('{func:s}: ----------------------'.format(func=cFuncName))
        logger.info(
            '{func:s}: making plot for signal type {name!s} ({sigt:s})'.format(
                sigt=sigType,
                name=rnxobs.dSignalTypesNames[sigType]['name'],
                func=cFuncName))

        # count the number of signals of this type to determine # of subplots
        nrSubPlotsSigType = len([v for v in flatSigTypes if v == sigType])
        logger.info('{func:s}: sub plots created = {nrplt!s}'.format(
            nrplt=nrSubPlotsSigType, func=cFuncName))

        # generate the subplots and its axes
        nrRows = dSubPlotsLayout[nrSubPlotsSigType][0]
        nrCols = dSubPlotsLayout[nrSubPlotsSigType][1]
        logger.info(
            '{func:s}: plot layout - rows={row:d} columns={col:d}'.format(
                row=nrRows, col=nrCols, func=cFuncName))

        fig, axes = plt.subplots(nrows=nrRows,
                                 ncols=nrCols,
                                 sharex='col',
                                 sharey='row')
        fig.set_size_inches(18.5, 10.5)

        logger.debug('{func:s}: axes = {ax!s}'.format(ax=axes, func=cFuncName))
        # axes_list = [item for sublist in axes for item in sublist]

        # find indices for signals of this signalType
        indexSigType = [
            index for index, st in enumerate(flatSigTypes) if st == sigType
        ]
        logger.info('{func:s}: index for signal type = {ist!s}'.format(
            ist=indexSigType, func=cFuncName))

        # determine the discrete colors for SVs
        colormap = plt.cm.nipy_spectral  # I suggest to use nipy_spectral, Set1,Paired
        # colormap = plt.cm.Spectral  #I  suggest to use nipy_spectral, Set1,Paired
        colors = [colormap(i) for i in np.linspace(0, 1, dPlot['#SVs'])]
        logger.debug('{func:s}: colors = {colors!s}'.format(colors=colors,
                                                            func=cFuncName))

        # create the subplots for each signal of this sigType
        for indexAxes, indexSignal in enumerate(indexSigType):
            # get the axes to plot onto
            logger.info(
                '\n{func:s}: index axis = {iax:d}  index signal = {isg:d}'.
                format(iax=indexAxes, isg=indexSignal, func=cFuncName))
            axRow, axCol = divmod(indexAxes, nrCols)
            logger.info(
                '{func:s}: axis #row = {row:d} #column = {col:d}'.format(
                    row=axRow, col=axCol, func=cFuncName))
            try:
                ax = axes[axRow, axCol]
            except IndexError as e:
                logger.info('{func:s}: {err!s}'.format(err=colored(e, 'red'),
                                                       func=cFuncName))
                ax = axes[axRow]
            except TypeError as e:
                logger.info('{func:s}: {err!s}'.format(err=colored(e, 'red'),
                                                       func=cFuncName))
                ax = axes

            # add a UE RESTREINT
            if (axCol == 0 and axRow == 0) or (axCol == nrCols - 1
                                               and axRow == nrRows - 1):
                ax.annotate(
                    r'$\copyright$ Alain Muls - RESTREINT UE/EU RESTRICTED',
                    xy=(1, 1),
                    xycoords='axes fraction',
                    xytext=(0, 0),
                    textcoords='offset pixels',
                    horizontalalignment='right',
                    verticalalignment='bottom',
                    fontsize='large',
                    color='red')

            # get the name of the signal to plot on this axis
            signal = dPlot['Signals'][indexSignal]
            # get time interval
            timeInterval = [
                datetime.datetime.strptime(dPlot['Time']['start'],
                                           "%Y-%m-%dT%H:%M:%S"),
                datetime.datetime.strptime(dPlot['Time']['end'],
                                           "%Y-%m-%dT%H:%M:%S")
            ]
            logger.info(
                '{func:s}: Plotting signal {!s} over interval {time!s}'.format(
                    signal, time=timeInterval, func=cFuncName))
            logger.info('{func:s}: for satellites {svs!s} (#{nr:d})'.format(
                svs=dPlot['SVs'], nr=len(dPlot['SVs']), func=cFuncName))

            for iSV, sv in enumerate(dPlot['SVs']):
                obsData_time = obsData.sel(
                    time=slice(timeInterval[0], timeInterval[1]))
                logger.info('{func:s} ... plotting satellite {sv:s}'.format(
                    sv=sv, func=cFuncName))

                # determine color for this SV by taking the color with th eindex of SV in AllSVs list
                colorSV = colors[dPlot['AllSVs'].index(sv)]

                ax.plot(obsData_time.time,
                        obsData_time[signal].sel(sv=sv),
                        label='{sv:s}'.format(sv=sv),
                        color=colorSV,
                        marker='.',
                        markersize=3,
                        linestyle='')

            # add a legend the plot showing the satellites displayed
            ax.legend(loc='best', ncol=16, markerscale=6)

            # find name of the signal in each constellation and use this for subplot title
            subTitle = 'Datafile {name:s}: '.format(
                name=os.path.basename(dPlot['name']))
            if any([sv for sv in dPlot['SVs'] if sv.startswith('E')]):
                subTitle += subTitleGNSS(dGNSS=rnxobs.dGAL,
                                         signal=signal,
                                         logger=logger)
            if any([sv for sv in dPlot['SVs'] if sv.startswith('G')]):
                subTitle += subTitleGNSS(dGNSS=rnxobs.dGPS,
                                         signal=signal,
                                         logger=logger)
            logger.info('{func:s}: plot subtitle {sub:s}'.format(
                sub=subTitle, func=cFuncName))

            # adjust the titles for the subplots
            ax.set_title(subTitle, fontsize=11)
            # ax.set_xlabel('Time')
            if axCol == 0:
                ax.set_ylabel('{name:s} {unit:s}'.format(
                    name=rnxobs.dSignalTypesNames[sigType]['name'],
                    unit=rnxobs.dSignalTypesNames[sigType]['unit']),
                              fontsize=11)

            if signal.startswith('S'):
                ax.set_ylim([20, 60])

            # create the ticks for the time axis
            dtFormat = plot_utils.determine_datetime_ticks(
                startDT=timeInterval[0], endDT=timeInterval[1])

            if dtFormat['minutes']:
                ax.xaxis.set_major_locator(
                    dates.MinuteLocator(byminute=[0, 15, 30, 45], interval=1))
            else:
                ax.xaxis.set_major_locator(
                    dates.HourLocator(
                        interval=dtFormat['hourInterval']))  # every 4 hours
            ax.xaxis.set_major_formatter(
                dates.DateFormatter('%H:%M'))  # hours and minutes

            ax.xaxis.set_minor_locator(
                dates.DayLocator(interval=1))  # every day
            ax.xaxis.set_minor_formatter(dates.DateFormatter('\n%d-%m-%Y'))

            ax.xaxis.set_tick_params(rotation=0)
            for tick in ax.xaxis.get_major_ticks():
                # tick.tick1line.set_markersize(0)
                # tick.tick2line.set_markersize(0)
                tick.label1.set_horizontalalignment('center')

        # set title
        fig.suptitle(rnxobs.dSignalTypesNames[sigType]['name'], fontsize=16)

        # fig.tight_layout()
        fig.subplots_adjust(top=0.925)

        # save the figure (add satellite number is total satellites in plot is < 3)
        baseName = os.path.basename(dPlot['name'])
        dirName = os.path.dirname(dPlot['name'])
        os.makedirs(os.path.join(dirName, 'png'), exist_ok=True)
        if len(dPlot['SVs']) < 4:
            listSVs = '-'.join(dPlot['SVs'])
            figName = os.path.join(
                dirName, 'png', '{base:s}-{name:s}-{list:s}'.format(
                    base=baseName,
                    name=rnxobs.dSignalTypesNames[sigType]['name'],
                    list=listSVs))
        elif dPlot['#SVs'] == len(dPlot['SVs']):
            listSVs = 'ALL'
            figName = os.path.join(
                dirName, 'png', '{base:s}-{name:s}-{list:s}'.format(
                    base=baseName,
                    name=rnxobs.dSignalTypesNames[sigType]['name'],
                    list=listSVs))
        else:
            figName = os.path.join(
                dirName, 'png', '{base:s}-{name:s}'.format(
                    base=baseName,
                    name=rnxobs.dSignalTypesNames[sigType]['name']))

        # figName += '{start:s}'.format(start=datetime.datetime.strptime(dPlot['Time']['start'], "%Y-%m-%dT%H:%M:%S"))
        # figName += '{end:s}'.format(end=datetime.datetime.strptime(dPlot['Time']['end'], "%Y-%m-%dT%H:%M:%S"))
        tmpName = figName.replace(' ', '-')
        tmp2Name = tmpName.replace('.', '-')
        tmpName = tmp2Name.replace('_', '')
        figName = tmpName + '.png'
        fig.savefig(figName, dpi=100)

        logger.info('{func:s}: plot saved as {name:s}'.format(name=figName,
                                                              func=cFuncName))

        plt.show()
Пример #11
0
def plotSignalDiff(dCsv: dict, dfSig: pd.DataFrame, logger=logging.Logger):
    """
    Plot the signals and their difference per observed PRN
    """
    cFuncName = colored(os.path.basename(__file__),
                        'yellow') + ' - ' + colored(
                            sys._getframe().f_code.co_name, 'green')

    logger.info(
        '{func:s}: start plotting for signal difference {st0:s}-{st1:s}\n'.
        format(st0=dCsv[0]['signal'], st1=dCsv[1]['signal'], func=cFuncName))

    # specify the style
    mpl.style.use('seaborn')

    # determine the discrete colors for SVs
    colormap = plt.cm.nipy_spectral  # I suggest to use nipy_spectral, Set1,Paired
    # colormap = plt.cm.Spectral  # I suggest to use nipy_spectral, Set1,Paired
    colors = [colormap(i) for i in np.linspace(0, 1, dCsv['#SVs'] * 3)]
    logger.debug('{func:s}: colors = {colors!s}'.format(colors=colors,
                                                        func=cFuncName))

    # max for signals itself
    y1Max = max(dCsv[0]['max'], dCsv[1]['max']) + 5
    y1Min = min(dCsv[0]['min'], dCsv[1]['min']) - 5

    # for formatting date time x axis
    dtFormat = plot_utils.determine_datetime_ticks(
        startDT=dfSig['time'].iloc[0], endDT=dfSig['time'].iloc[-1])

    # go over all PRNs
    for i, prn in enumerate(dCsv['SVs']):
        logger.info('{func:s}: plotting for PRN {prn:s}'.format(
            prn=prn, func=cFuncName))

        # create the figure and axes
        fig, ax1 = plt.subplots(figsize=(15, 10))

        # x-axis properties
        ax1.set_xlim([dfSig['time'].iloc[0], dfSig['time'].iloc[-1]])
        if dtFormat['minutes']:
            ax1.xaxis.set_major_locator(
                dates.MinuteLocator(byminute=[0, 15, 30, 45], interval=1))
        else:
            ax1.xaxis.set_major_locator(
                dates.HourLocator(
                    interval=dtFormat['hourInterval']))  # every 4 hours
        ax1.xaxis.set_major_formatter(
            dates.DateFormatter('%H:%M'))  # hours and minutes

        ax1.xaxis.set_minor_locator(dates.DayLocator(interval=1))  # every day
        ax1.xaxis.set_minor_formatter(dates.DateFormatter('\n%d-%m-%Y'))

        ax1.xaxis.set_tick_params(rotation=0)
        for tick in ax1.xaxis.get_major_ticks():
            # tick.tick1line.set_markersize(0)
            # tick.tick2line.set_markersize(0)
            tick.label1.set_horizontalalignment('center')

        # plot both signals in color for prn
        ax1.set_ylim([y1Min, y1Max])

        prnst = '{prn:s}-{st:s}'.format(prn=prn, st=dCsv[0]['signal'])
        ax1.plot(dfSig['time'],
                 dfSig[prnst],
                 linestyle='-',
                 marker='.',
                 markersize=1,
                 color='blue',
                 label=prnst,
                 alpha=0.5)
        prnst = '{prn:s}-{st:s}'.format(prn=prn, st=dCsv[1]['signal'])
        ax1.plot(dfSig['time'],
                 dfSig[prnst],
                 linestyle='-',
                 marker='.',
                 markersize=1,
                 color='green',
                 label=prnst,
                 alpha=0.5)

        # add a legend the plot showing the satellites displayed
        ax1.legend(loc='upper left', ncol=16, markerscale=4)

        # plot the difference on second y-axis
        ax2 = ax1.twinx()
        if dCsv[0]['signal'].startswith('C'):
            ax2.set_ylim([0, 15])
        elif dCsv[0]['signal'].startswith('S'):
            ax2.set_ylim([-15, 15])
        else:
            ax2.set_ylim([dCsv['dMin'], dCsv['dMax']])
        prnstdiff = '{prn:s}: {st0:s}-{st1:s}'.format(prn=prn,
                                                      st0=dCsv[0]['signal'],
                                                      st1=dCsv[1]['signal'])
        ax2.fill_between(dfSig['time'],
                         dfSig[prn],
                         linestyle='-',
                         color='red',
                         label=prnstdiff,
                         alpha=0.5)
        # plot the moving average for this prn
        prnMA = '{prn:s}-MA'.format(prn=prn)
        movAvgTxt = 'MovAvg ({time:d}s: #{count:d}, mean={mean:.1f}, max={max:.1f}, min={min:.1f})'.format(
            time=dCsv['movavg'],
            count=dCsv['stats'][prn]['count'],
            max=dCsv['stats'][prn]['max'],
            min=dCsv['stats'][prn]['min'],
            mean=dCsv['stats'][prn]['mean'])
        ax2.plot(dfSig['time'],
                 dfSig[prnMA],
                 linestyle='-',
                 marker='.',
                 markersize=1,
                 color='yellow',
                 label=movAvgTxt)
        # add a legend the plot showing the satellites displayed
        ax2.legend(loc='upper right', ncol=16, markerscale=4)

        # title of plot
        shortName = dCsv[0]['file'].split('-')[0]
        title = '{file:s}: {syst:s} {prn:s} Signal difference {st0:s}-{st1:s}'.format(
            file=shortName,
            syst=dCsv['gnss'],
            prn=prn,
            st0=dCsv[0]['signal'],
            st1=dCsv[1]['signal'])
        fig.suptitle(title, fontsize=16)

        # Save the file in dir png
        pltDir = os.path.join(dCsv['dir'], 'png')
        os.makedirs(pltDir, exist_ok=True)
        pltName = '{file:s}-{syst:s}-{prn:s}-{st0:s}-{st1:s}.png'.format(
            file=shortName,
            syst=dCsv['gnss'],
            prn=prn,
            st0=dCsv[0]['signal'],
            st1=dCsv[1]['signal'])
        tmpName = pltName.replace(' ', '-')
        pltName = os.path.join(pltDir, tmpName)
        fig.savefig(pltName, dpi=100)

        logger.info('{func:s}: plot saved as {name:s}'.format(name=pltName,
                                                              func=cFuncName))

        plt.show(block=True)