Esempio n. 1
0
def plot_polar_comparison(config,
                          Lons,
                          Lats,
                          modelArray,
                          refArray,
                          diffArray,
                          colorMapSectionName,
                          fileout,
                          title=None,
                          plotProjection='npstere',
                          latmin=50.0,
                          lon0=0,
                          modelTitle='Model',
                          refTitle='Observations',
                          diffTitle='Model-Observations',
                          cbarlabel='units',
                          titleFontSize=None,
                          figsize=None,
                          dpi=None,
                          vertical=False):
    """
    Plots a data set around either the north or south pole.

    Parameters
    ----------
    config : instance of ConfigParser
        the configuration, containing a [plot] section with options that
        control plotting

    Lons, Lats : float arrays
        longitude and latitude arrays

    modelArray, refArray : float arrays
        model and observational or control run data sets

    diffArray : float array
        difference between modelArray and refArray

    colorMapSectionName : str
        section name in ``config`` where color map info can be found.

    fileout : str
        the file name to be written

    title : str, optional
        the subtitle of the plot

    plotProjection : str, optional
        Basemap projection for the plot

    modelTitle : str, optional
        title of the model panel

    refTitle : str, optional
        title of the observations or control run panel

    diffTitle : str, optional
        title of the difference (bias) panel

    cbarlabel : str, optional
        label on the colorbar

    titleFontSize : int, optional
        size of the title font

    figsize : tuple of float, optional
        the size of the figure in inches.  If ``None``, the figure size is
        ``(8, 22)`` if ``vertical == True`` and ``(22, 8)`` otherwise.

    dpi : int, optional
        the number of dots per inch of the figure, taken from section ``plot``
        option ``dpi`` in the config file by default

    vertical : bool, optional
        whether the subplots should be stacked vertically rather than
        horizontally
    """

    # Authors
    # -------
    # Xylar Asay-Davis, Milena Veneziani

    def do_subplot(ax, field, title, colormap, norm, levels, ticks, contours,
                   lineWidth, lineColor):
        """
        Make a subplot within the figure.
        """

        m = Basemap(projection=plotProjection,
                    boundinglat=latmin,
                    lon_0=lon0,
                    resolution='l',
                    ax=ax)

        fieldPeriodic, LatsPeriodic, LonsPeriodic = addcyclic(
            field, Lats, Lons)

        x, y = m(LonsPeriodic, LatsPeriodic)  # compute map proj coordinates

        ax.set_title(title, y=1.06, **plottitle_font)

        m.drawcoastlines()
        m.fillcontinents(color='grey', lake_color='white')
        m.drawparallels(np.arange(-80., 81., 10.))
        m.drawmeridians(np.arange(-180., 181., 20.),
                        labels=[True, False, True, True])

        if levels is None:
            plotHandle = m.pcolormesh(x,
                                      y,
                                      fieldPeriodic,
                                      cmap=colormap,
                                      norm=norm)
        else:
            plotHandle = m.contourf(x,
                                    y,
                                    fieldPeriodic,
                                    cmap=colormap,
                                    norm=norm,
                                    levels=levels)

        if contours is not None:
            matplotlib.rcParams['contour.negative_linestyle'] = 'solid'
            m.contour(x,
                      y,
                      field,
                      levels=contours,
                      colors=lineColor,
                      linewidths=lineWidth)

        cbar = m.colorbar(plotHandle,
                          location='right',
                          pad="3%",
                          spacing='uniform',
                          ticks=ticks,
                          boundaries=levels)
        cbar.set_label(cbarlabel)

    if dpi is None:
        dpi = config.getint('plot', 'dpi')

    dictModelRef = setup_colormap(config, colorMapSectionName, suffix='Result')
    dictDiff = setup_colormap(config, colorMapSectionName, suffix='Difference')

    if refArray is None:
        if figsize is None:
            figsize = (8, 8.5)
        subplots = [111]
    elif vertical:
        if figsize is None:
            figsize = (8, 22)
        subplots = [311, 312, 313]
    else:
        if figsize is None:
            figsize = (22, 8.5)
        subplots = [131, 132, 133]

    fig = plt.figure(figsize=figsize, dpi=dpi)

    if (title is not None):
        if titleFontSize is None:
            titleFontSize = config.get('plot', 'titleFontSize')
        title_font = {
            'size': titleFontSize,
            'color': config.get('plot', 'titleFontColor'),
            'weight': config.get('plot', 'titleFontWeight')
        }
        fig.suptitle(title, y=0.95, **title_font)

    plottitle_font = {
        'size': config.get('plot', 'threePanelPlotTitleFontSize')
    }

    ax = plt.subplot(subplots[0])
    do_subplot(ax=ax, field=modelArray, title=modelTitle, **dictModelRef)

    if refArray is not None:
        ax = plt.subplot(subplots[1])
        do_subplot(ax=ax, field=refArray, title=refTitle, **dictModelRef)

        ax = plt.subplot(subplots[2])
        do_subplot(ax=ax, field=diffArray, title=diffTitle, **dictDiff)

    plt.tight_layout(pad=4.)
    if vertical:
        plt.subplots_adjust(top=0.9)

    if (fileout is not None):
        plt.savefig(fileout, dpi=dpi, bbox_inches='tight', pad_inches=0.1)

    plt.close()
Esempio n. 2
0
def plot_polar_projection_comparison(config,
                                     x,
                                     y,
                                     landMask,
                                     modelArray,
                                     refArray,
                                     diffArray,
                                     fileout,
                                     colorMapSectionName,
                                     title=None,
                                     modelTitle='Model',
                                     refTitle='Observations',
                                     diffTitle='Model-Observations',
                                     cbarlabel='units',
                                     titleFontSize=None,
                                     figsize=None,
                                     dpi=None,
                                     lineWidth=0.5,
                                     lineColor='black',
                                     vertical=False):
    """
    Plots a data set as a longitude/latitude map.

    Parameters
    ----------
    config : instance of ConfigParser
        the configuration, containing a [plot] section with options that
        control plotting

    x, y : numpy ndarrays
        1D x and y arrays defining the projection grid

    landMask : numpy ndarrays
        model and observational or control run data sets

    modelArray, refArray : numpy ndarrays
        model and observational or control run data sets

    diffArray : float array
        difference between modelArray and refArray

    fileout : str
        the file name to be written

    colorMapSectionName : str
        section name in ``config`` where color map info can be found.

    title : str, optional
        the subtitle of the plot

    modelTitle : str, optional
        title of the model panel

    refTitle : str, optional
        title of the observations or control run panel

    diffTitle : str, optional
        title of the difference (bias) panel

    cbarlabel : str, optional
        label on the colorbar

    titleFontSize : int, optional
        size of the title font

    figsize : tuple of float, optional
        the size of the figure in inches.  If ``None``, the figure size is
        ``(8, 22)`` if ``vertical == True`` and ``(22, 8)`` otherwise.

    dpi : int, optional
        the number of dots per inch of the figure, taken from section ``plot``
        option ``dpi`` in the config file by default

    lineWidth : int, optional
        the line width of contour lines (if specified)

    lineColor : str, optional
        the color of contour lines (if specified)

    vertical : bool, optional
        whether the subplots should be stacked vertically rather than
        horizontally
    """

    # Authors
    # -------
    # Xylar Asay-Davis

    def plot_panel(ax, title, array, colormap, norm, levels, ticks, contours,
                   lineWidth, lineColor):

        plt.title(title, y=1.06, **plottitle_font)

        if levels is None:
            plotHandle = plt.pcolormesh(x, y, array, cmap=colormap, norm=norm)
        else:
            plotHandle = plt.contourf(xCenter,
                                      yCenter,
                                      array,
                                      cmap=colormap,
                                      norm=norm,
                                      levels=levels,
                                      extend='both')

        plt.pcolormesh(x, y, landMask, cmap=landColorMap)
        plt.contour(xCenter,
                    yCenter,
                    landMask.mask, (0.5, ),
                    colors='k',
                    linewidths=0.5)

        if contours is not None:
            matplotlib.rcParams['contour.negative_linestyle'] = 'solid'
            plt.contour(x,
                        y,
                        array,
                        levels=contours,
                        colors=lineColor,
                        linewidths=lineWidth)

        # create an axes on the right side of ax. The width of cax will be 5%
        # of ax and the padding between cax and ax will be fixed at 0.05 inch.
        divider = make_axes_locatable(ax)
        cax = divider.append_axes("right", size="5%", pad=0.05)

        cbar = plt.colorbar(plotHandle, cax=cax)
        cbar.set_label(cbarlabel)
        if ticks is not None:
            cbar.set_ticks(ticks)
            cbar.set_ticklabels(['{}'.format(tick) for tick in ticks])

        ax.axis('off')
        ax.set_aspect('equal')
        ax.autoscale(tight=True)

    # set up figure
    if dpi is None:
        dpi = config.getint('plot', 'dpi')

    if refArray is None:
        if figsize is None:
            figsize = (8, 7.5)
        subplots = [111]
    elif vertical:
        if figsize is None:
            figsize = (8, 22)
        subplots = [311, 312, 313]
    else:
        if figsize is None:
            figsize = (22, 7.5)
        subplots = [131, 132, 133]

    dictModelRef = setup_colormap(config, colorMapSectionName, suffix='Result')
    dictDiff = setup_colormap(config, colorMapSectionName, suffix='Difference')

    fig = plt.figure(figsize=figsize, dpi=dpi)

    if (title is not None):
        if titleFontSize is None:
            titleFontSize = config.get('plot', 'titleFontSize')
        title_font = {
            'size': titleFontSize,
            'color': config.get('plot', 'titleFontColor'),
            'weight': config.get('plot', 'titleFontWeight')
        }
        fig.suptitle(title, y=0.95, **title_font)

    plottitle_font = {
        'size': config.get('plot', 'threePanelPlotTitleFontSize')
    }

    # set up land colormap
    colorList = [(0.8, 0.8, 0.8), (0.8, 0.8, 0.8)]
    landColorMap = cols.LinearSegmentedColormap.from_list('land', colorList)

    # locations of centers for contour plots
    xCenter = 0.5 * (x[1:] + x[0:-1])
    yCenter = 0.5 * (y[1:] + y[0:-1])

    ax = plt.subplot(subplots[0])
    plot_panel(ax, modelTitle, modelArray, **dictModelRef)

    if refArray is not None:
        ax = plt.subplot(subplots[1])
        plot_panel(ax, refTitle, refArray, **dictModelRef)

        ax = plt.subplot(subplots[2])
        plot_panel(ax, diffTitle, diffArray, **dictDiff)

    if (fileout is not None):
        plt.savefig(fileout, dpi=dpi, bbox_inches='tight', pad_inches=0.1)

    plt.close()
Esempio n. 3
0
def plot_global_comparison(config,
                           Lons,
                           Lats,
                           modelArray,
                           refArray,
                           diffArray,
                           colorMapSectionName,
                           fileout,
                           title=None,
                           modelTitle='Model',
                           refTitle='Observations',
                           diffTitle='Model-Observations',
                           cbarlabel='units',
                           titleFontSize=None,
                           figsize=None,
                           dpi=None,
                           lineWidth=1,
                           lineColor='black'):
    """
    Plots a data set as a longitude/latitude map.

    Parameters
    ----------
    config : instance of ConfigParser
        the configuration, containing a [plot] section with options that
        control plotting

    Lons, Lats : float arrays
        longitude and latitude arrays

    modelArray, refArray : float arrays
        model and observational or control run data sets

    diffArray : float array
        difference between modelArray and refArray

    colorMapSectionName : str
        section name in ``config`` where color map info can be found.

    fileout : str
        the file name to be written

    title : str, optional
        the subtitle of the plot

    modelTitle : str, optional
        title of the model panel

    refTitle : str, optional
        title of the observations or control run panel

    diffTitle : str, optional
        title of the difference (bias) panel

    cbarlabel : str, optional
        label on the colorbar

    titleFontSize : int, optional
        size of the title font

    figsize : tuple of float, optional
        the size of the figure in inches

    dpi : int, optional
        the number of dots per inch of the figure, taken from section ``plot``
        option ``dpi`` in the config file by default

    lineWidth : int, optional
        the line width of contour lines (if specified)

    lineColor : str, optional
        the color of contour lines (if specified)
    """

    # Authors
    # -------
    # Xylar Asay-Davis, Milena Veneziani

    def plot_panel(title, array, colormap, norm, levels, ticks, contours,
                   lineWidth, lineColor):

        plt.title(title, y=1.06, **plottitle_font)

        m.drawcoastlines()
        m.fillcontinents(color='grey', lake_color='white')
        m.drawparallels(np.arange(-80., 80., 20.),
                        labels=[True, False, False, False])
        m.drawmeridians(np.arange(-180., 180., 60.),
                        labels=[False, False, False, True])

        if levels is None:
            plotHandle = m.pcolormesh(x, y, array, cmap=colormap, norm=norm)
        else:
            plotHandle = m.contourf(x,
                                    y,
                                    array,
                                    cmap=colormap,
                                    norm=norm,
                                    levels=levels,
                                    extend='both')

        if contours is not None:
            matplotlib.rcParams['contour.negative_linestyle'] = 'solid'
            m.contour(x,
                      y,
                      array,
                      levels=contours,
                      colors=lineColor,
                      linewidths=lineWidth)

        cbar = m.colorbar(plotHandle,
                          location='right',
                          pad="5%",
                          spacing='uniform',
                          ticks=ticks,
                          boundaries=ticks)
        cbar.set_label(cbarlabel)

    # set up figure
    if dpi is None:
        dpi = config.getint('plot', 'dpi')
    if figsize is None:
        # set the defaults, depending on if we have 1 or 3 panels
        if refArray is None:
            figsize = (8, 5)
        else:
            figsize = (8, 13)
    fig = plt.figure(figsize=figsize, dpi=dpi)
    if (title is not None):
        if titleFontSize is None:
            titleFontSize = config.get('plot', 'titleFontSize')
        title_font = {
            'size': titleFontSize,
            'color': config.get('plot', 'titleFontColor'),
            'weight': config.get('plot', 'titleFontWeight')
        }
        fig.suptitle(title, y=0.95, **title_font)

    plottitle_font = {
        'size': config.get('plot', 'threePanelPlotTitleFontSize')
    }

    m = Basemap(projection='cyl',
                llcrnrlat=-85,
                urcrnrlat=86,
                llcrnrlon=-180,
                urcrnrlon=181,
                resolution='l')
    x, y = m(Lons, Lats)  # compute map proj coordinates

    dictModelRef = setup_colormap(config, colorMapSectionName, suffix='Result')
    dictDiff = setup_colormap(config, colorMapSectionName, suffix='Difference')

    if refArray is not None:
        plt.subplot(3, 1, 1)

    plot_panel(modelTitle, modelArray, **dictModelRef)

    if refArray is not None:
        plt.subplot(3, 1, 2)
        plot_panel(refTitle, refArray, **dictModelRef)

        plt.subplot(3, 1, 3)
        plot_panel(diffTitle, diffArray, **dictDiff)

    if (fileout is not None):
        plt.savefig(fileout, dpi=dpi, bbox_inches='tight', pad_inches=0.1)

    plt.close()
Esempio n. 4
0
def plot_vertical_section(
        config,
        xArray,
        depthArray,
        fieldArray,
        colorMapSectionName,
        suffix='',
        colorbarLabel=None,
        title=None,
        xlabel=None,
        ylabel=None,
        figsize=(10, 4),
        dpi=None,
        titleFontSize=None,
        titleY=None,
        axisFontSize=None,
        xLim=None,
        yLim=None,
        lineWidth=2,
        lineStyle='solid',
        lineColor='black',
        backgroundColor='grey',
        secondXAxisData=None,
        secondXAxisLabel=None,
        thirdXAxisData=None,
        thirdXAxisLabel=None,
        numUpperTicks=None,
        upperXAxisTickLabelPrecision=None,
        invertYAxis=True,
        xArrayIsTime=False,
        movingAveragePoints=None,
        firstYearXTicks=None,
        yearStrideXTicks=None,
        maxXTicks=20,
        calendar='gregorian',
        plotAsContours=False,
        contourComparisonFieldArray=None,
        comparisonFieldName=None,
        originalFieldName=None,
        comparisonContourLineStyle=None,
        comparisonContourLineColor=None,
        labelContours=False,
        contourLabelPrecision=1,
        maxTitleLength=70):  # {{{
    """
    Plots a data set as a x distance (latitude, longitude,
    or spherical distance) vs depth map (vertical section).

    Or, if xArrayIsTime is True, plots data set on a vertical
    Hovmoller plot (depth vs. time).

    Typically, the fieldArray data are plotted using a heatmap, but if
    contourComparisonFieldArray is not None, then contours of both
    fieldArray and contourComparisonFieldArray are plotted instead.

    Parameters
    ----------
    config : instance of ConfigParser
        the configuration, containing a [plot] section with options that
        control plotting

    xArray : float array
        x array (latitude, longitude, or spherical distance; or, time for a
        Hovmoller plot)

    depthArray : float array
        depth array [m]

    fieldArray : float array
        field array to plot

    colorMapSectionName : str
        section name in ``config`` where color map info can be found.

    suffix : str, optional
        the suffix used for colorbar config options

    colorbarLabel : str, optional
        the label for the colorbar.  If plotAsContours and labelContours are
        both True, colorbarLabel is used as follows (typically in order to
        indicate the units that are associated with the contour labels):
        if contourComparisonFieldArray is None, the colorbarLabel string is
        parenthetically appended to the plot title;  if
        contourComparisonFieldArray is not None, it is parenthetically appended
        to the legend entries of the contour comparison plot.

    title : str, optional
        title of plot

    xlabel, ylabel : str, optional
        label of x- and y-axis

    figsize : tuple of float, optional
        size of the figure in inches, or None if the current figure should
        be used (e.g. if this is a subplot)

    dpi : int, optional
        the number of dots per inch of the figure, taken from section ``plot``
        option ``dpi`` in the config file by default

    titleFontSize : int, optional
        size of the title font

    titleY : float, optional
        the y value to use for placing the plot title

    axisFontSize : int, optional
        size of the axis font

    xLim : float array, optional
        x range of plot

    yLim : float array, optional
        y range of plot

    lineWidth : int, optional
        the line width of contour lines (if specified)

    lineStyle : str, optional
        the line style of contour lines (if specified); this applies to the
        style of contour lines of fieldArray (the style of the contour lines
        of contourComparisonFieldArray is set using
        contourComparisonLineStyle).

    lineColor : str, optional
        the color of contour lines (if specified); this applies to the
        contour lines of fieldArray (the color of the contour lines of
        contourComparisonFieldArray is set using contourComparisonLineColor

    backgroundColor : str, optional
        the background color for the plot (NaNs will be shown in this color)

    secondXAxisData : the data to use to display a second x axis (which will be
        placed above the plot).  This array must have the same number of values
        as xArray, and it is assumed that the values in this array define
        locations along the x axis that are the same as those defined by the
        corresponding values in xArray, but in some different unit system.

    secondXAxisLabel : the label for the second x axis, if requested

    thirdXAxisData : the data to use to display a third x axis (which will be
        placed above the plot and above the second x axis, which must be
        specified if a third x axis is to be specified).  This array must have
        the same number of values as xArray, and it is assumed that the values
        in this array define locations along the x axis that are the same as
        those defined by the corresponding values in xArray, but in some
        different unit system (which is presumably also different from the unit
        system used for the values in the secondXAxisData array).  The typical
        use for this third axis is for transects, for which the primary x axis
        represents distance along a transect, and the second and third x axes
        are used to display the corresponding latitudes and longitudes.

    thirdXAxisLabel : the label for the third x axis, if requested

    numUpperTicks : the approximate number of ticks to use on the upper x axis
        or axes (these are the second and third x axes, which are placed above
        the plot if they have been requested by specifying the secondXAxisData
        or thirdXAxisData arrays above)

    upperXAxisTickLabelPrecision : the number of decimal places (to the right
        of the decimal point) to use for values at upper axis ticks.  This
        value can be adjusted (in concert with numUpperTicks) to avoid problems
        with overlapping numbers along the upper axis.

    invertYAxis : logical, optional
        if True, invert Y axis

    xArrayIsTime : logical, optional
        if True, format the x axis for time (this applies only to the primary
        x axis, not to the optional second or third x axes)

    movingAveragePoints : int, optional
        the number of points over which to perform a moving average
        NOTE: this option is mostly intended for use when xArrayIsTime is True,
        although it will work with other data as well.  Also, the moving
        average calculation is based on number of points, not actual x axis
        values, so for best results, the values in the xArray should be equally
        spaced.

    firstYearXTicks : int, optional
        The year of the first tick on the x axis.  By default, the first time
        entry is the first tick.

    yearStrideXTicks : int, optional
        The number of years between x ticks. By default, the stride is chosen
        automatically to have ``maxXTicks`` tick marks or fewer.

    maxXTicks : int, optional
        the maximum number of tick marks that will be allowed along the primary
        x axis.  This may need to be adjusted depending on the figure size and
        aspect ratio.  NOTE:  maxXTicks is only used if xArrayIsTime is True

    calendar : str, optional
        the calendar to use for formatting the time axis
        NOTE:  calendar is only used if xArrayIsTime is True

    plotAsContours : bool, optional
        if plotAsContours is True, instead of plotting fieldArray as a
        heatmap, the function will plot only the contours of fieldArray.  In
        addition, if contourComparisonFieldArray is not None, the contours
        of this field will be plotted on the same plot.  The selection of
        contour levels is still determined as for the contours on the heatmap
        plots, via the 'contours' entry in colorMapSectionName.

    contourComparisonFieldArray : float array, optional
        a comparison field array (typically observational data or results from
        another simulation run), assumed to be of the same shape as fieldArray,
        and related to xArray and depthArray in the same way fieldArray is.
        If contourComparisonFieldArray is None, then fieldArray will be plotted
        as a heatmap.  However, if countourComparisonFieldArray is not None,
        then contours of both fieldArray and contourComparisonFieldArray will
        be plotted in order to enable a comparison of the two fields on the
        same plot.  If plotAsContours is False, this parameter is ignored.

    comparisonFieldName : str, optional
       the name for the comparison field.  If contourComparisonFieldArray is
       None, this parameter is ignored.

    originalFieldName : str, optional
       the name for the fieldArray field (for the purposes of labeling the
       contours on a contour comparison plot).  If contourComparisonFieldArray
       is None, this parameter is ignored.

    comparisonContourLineStyle : str, optional
        the line style of contour lines of the comparisonFieldName field on
        a contour comparison plot

    comparisonContourLineColor : str, optional
        the line color of contour lines of the comparisonFieldName field on
        a contour comparison plot

    labelContours : bool, optional
        whether or not to label contour lines (if specified) with their values

    contourLabelPrecision : int, optional
        the precision (in terms of number of figures to the right of the
        decimal point) of contour labels

    maxTitleLength : int, optional
        the maximum number of characters in the title, beyond which it is
        truncated with a trailing ellipsis

    Returns
    -------
    fig : ``matplotlib.figure.Figure``
        The figure that was plotted

    ax : ``matplotlib.axes.Axes``
        The subplot
    """
    # Authors
    # -------
    # Milena Veneziani, Mark Petersen, Xylar Asay-Davis, Greg Streletz

    # compute moving averages with respect to the x dimension
    if movingAveragePoints is not None and movingAveragePoints != 1:
        N = movingAveragePoints
        movingAverageDepthSlices = []
        for nVertLevel in range(len(depthArray)):
            depthSlice = fieldArray[[nVertLevel]][0]
            # in case it's not an xarray already
            depthSlice = xr.DataArray(depthSlice)
            mean = pd.Series.rolling(depthSlice.to_series(), N,
                                     center=True).mean()
            mean = xr.DataArray.from_series(mean)
            mean = mean[int(N / 2.0):-int(round(N / 2.0) - 1)]
            movingAverageDepthSlices.append(mean)
        xArray = xArray[int(N / 2.0):-int(round(N / 2.0) - 1)]
        fieldArray = xr.DataArray(movingAverageDepthSlices)

    dimX = xArray.shape
    dimZ = depthArray.shape
    dimF = fieldArray.shape
    if contourComparisonFieldArray is not None:
        dimC = contourComparisonFieldArray.shape

    if len(dimX) != 1 and len(dimX) != 2:
        raise ValueError('xArray must have either one or two dimensions '
                         '(has %d)' % dimX)

    if len(dimZ) != 1 and len(dimZ) != 2:
        raise ValueError('depthArray must have either one or two dimensions '
                         '(has %d)' % dimZ)

    if len(dimF) != 2:
        raise ValueError('fieldArray must have two dimensions (has %d)' % dimF)

    if contourComparisonFieldArray is not None:
        if len(dimC) != 2:
            raise ValueError('contourComparisonFieldArray must have two '
                             'dimensions (has %d)' % dimC)
        elif (fieldArray.shape[0] != contourComparisonFieldArray.shape[0]) or \
             (fieldArray.shape[1] != contourComparisonFieldArray.shape[1]):
            raise ValueError('size mismatch between fieldArray (%d x %d) and '
                             'contourComparisonFieldArray (%d x %d)' %
                             (fieldArray.shape[0], fieldArray.shape[1],
                              contourComparisonFieldArray.shape[0],
                              contourComparisonFieldArray.shape[1]))

    # verify that the dimensions of fieldArray are consistent with those of
    # xArray and depthArray
    if len(dimX) == 1 and len(dimZ) == 1:
        num_x = dimX[0]
        num_z = dimZ[0]
        if num_x != fieldArray.shape[1] or num_z != fieldArray.shape[0]:
            raise ValueError('size mismatch between xArray (%d), '
                             'depthArray (%d), and fieldArray (%d x %d)' %
                             (num_x, num_z, fieldArray.shape[0],
                              fieldArray.shape[1]))
    elif len(dimX) == 1:
        num_x = dimX[0]
        num_x_Z = dimZ[1]
        num_z = dimZ[0]
        if num_x != fieldArray.shape[1] or num_z != fieldArray.shape[0] or \
                num_x != num_x_Z:
            raise ValueError('size mismatch between xArray (%d), '
                             'depthArray (%d x %d), and fieldArray (%d x %d)' %
                             (num_x, num_z, num_x_Z,
                              fieldArray.shape[0],
                              fieldArray.shape[1]))
    elif len(dimZ) == 1:
        num_x = dimX[1]
        num_z_X = dimX[0]
        num_z = dimZ[0]
        if num_x != fieldArray.shape[1] or num_z != fieldArray.shape[0] or \
                num_z != num_z_X:
            raise ValueError('size mismatch between xArray (%d x %d), '
                             'depthArray (%d), and fieldArray (%d x %d)' %
                             (num_z_X, num_x, num_z,
                              fieldArray.shape[0],
                              fieldArray.shape[1]))
    else:
        num_x = dimX[1]
        num_z_X = dimX[0]
        num_x_Z = dimZ[1]
        num_z = dimZ[0]
        if num_x != fieldArray.shape[1] or num_z != fieldArray.shape[0] \
                or num_x != num_x_Z or num_z != num_z_X:
            raise ValueError('size mismatch between xArray (%d x %d), '
                             'depthArray (%d x %d), and fieldArray (%d x %d)' %
                             (num_z_X, num_x, num_z, num_x_Z,
                              fieldArray.shape[0],
                              fieldArray.shape[1]))

    # Verify that the upper x-axis parameters are consistent with each other
    # and with xArray
    if secondXAxisData is None and thirdXAxisData is not None:
        raise ValueError('secondXAxisData cannot be None if thirdXAxisData '
                         'is not None')
    if secondXAxisData is not None:
        arrayShape = secondXAxisData.shape
        if len(arrayShape) == 1 and arrayShape[0] != num_x:
            raise ValueError('secondXAxisData has %d x values, '
                             'but should have num_x = %d x values' %
                             (arrayShape[0], num_x))
        elif len(arrayShape) == 2 and arrayShape[1] != num_x:
            raise ValueError('secondXAxisData has %d x values, '
                             'but should have num_x = %d x values' %
                             (arrayShape[1], num_x))
        elif len(arrayShape) > 2:
            raise ValueError('secondXAxisData must be a 1D or 2D array, '
                             'but is of dimension %d' %
                             (len(arrayShape)))
    if thirdXAxisData is not None:
        arrayShape = thirdXAxisData.shape
        if len(arrayShape) == 1 and arrayShape[0] != num_x:
            raise ValueError('thirdXAxisData has %d x values, '
                             'but should have num_x = %d x values' %
                             (arrayShape[0], num_x))
        elif len(arrayShape) == 2 and arrayShape[1] != num_x:
            raise ValueError('thirdXAxisData has %d x values, '
                             'but should have num_x = %d x values' %
                             (arrayShape[1], num_x))
        elif len(arrayShape) > 2:
            raise ValueError('thirdXAxisData must be a 1D or 2D array, '
                             'but is of dimension %d' %
                             (len(arrayShape)))

    # define x and y as the appropriate 2D arrays for plotting
    if len(dimX) == 1 and len(dimZ) == 1:
        x, y = np.meshgrid(xArray, depthArray)
    elif len(dimX) == 1:
        x, y = np.meshgrid(xArray, np.zeros(num_z))
        y = depthArray
    elif len(dimZ) == 1:
        x, y = np.meshgrid(np.zeros(num_x), depthArray)
        x = xArray
    else:
        x = xArray
        y = depthArray

    # set up figure
    if dpi is None:
        dpi = config.getint('plot', 'dpi')
    if figsize is not None:
        fig = plt.figure(figsize=figsize, dpi=dpi)
    else:
        fig = plt.gcf()

    colormapDict = setup_colormap(config, colorMapSectionName, suffix=suffix)

    if not plotAsContours:    # display a heatmap of fieldArray

        if colormapDict['levels'] is None:
            # interpFieldArray contains the values at centers of grid cells,
            # for pcolormesh plots (using bilinear interpolation)
            interpFieldArray = \
                0.5 * (0.5 * (fieldArray[1:, 1:] + fieldArray[0:-1, 1:]) +
                       0.5 * (fieldArray[1:, 0:-1] + fieldArray[0:-1, 0:-1]))

            plotHandle = plt.pcolormesh(x, y, interpFieldArray,
                                        cmap=colormapDict['colormap'],
                                        norm=colormapDict['norm'])
        else:
            plotHandle = plt.contourf(x, y, fieldArray,
                                      cmap=colormapDict['colormap'],
                                      norm=colormapDict['norm'],
                                      levels=colormapDict['levels'],
                                      extend='both')

        cbar = plt.colorbar(plotHandle,
                            orientation='vertical',
                            spacing='uniform',
                            aspect=9,
                            ticks=colormapDict['ticks'],
                            boundaries=colormapDict['ticks'])

        if colorbarLabel is not None:
            cbar.set_label(colorbarLabel)

    else:     # display a white heatmap to get a white background for non-land
        zeroArray = np.ma.where(fieldArray != np.nan, 0.0, fieldArray)
        plt.contourf(x, y, zeroArray, colors='white')

    # set the color for NaN or masked regions, and draw a black
    # outline around them; technically, the contour level used should
    # be 1.0, but the contours don't show up when using 1.0, so 0.999
    # is used instead
    ax = plt.gca()
    ax.set_facecolor(backgroundColor)
    landArray = np.ma.where(fieldArray != np.nan, 1.0, fieldArray)
    landArray = np.ma.masked_where(landArray == np.nan, landArray, copy=True)
    landArray = landArray.filled(0.0)
    plt.contour(x, y, landArray, levels=[0.999], colors='black', linewidths=1)

    # plot contours, if they were requested
    contourLevels = colormapDict['contours']
    if contourLevels is not None:
        if len(contourLevels) == 0:
            # automatic calculation of contour levels
            contourLevels = None
        cs1 = plt.contour(x, y, fieldArray,
                          levels=contourLevels,
                          colors=lineColor,
                          linestyles=lineStyle,
                          linewidths=lineWidth)
        if labelContours:
            fmt_string = "%%1.%df" % int(contourLabelPrecision)
            plt.clabel(cs1, fmt=fmt_string)
        if plotAsContours and contourComparisonFieldArray is not None:
            cs2 = plt.contour(x, y, contourComparisonFieldArray,
                              levels=contourLevels,
                              colors=comparisonContourLineColor,
                              linestyles=comparisonContourLineStyle,
                              linewidths=lineWidth)
            if labelContours:
                plt.clabel(cs2, fmt=fmt_string)

    if plotAsContours and contourComparisonFieldArray is not None:
        h1, _ = cs1.legend_elements()
        h2, _ = cs2.legend_elements()
        if labelContours:
            originalFieldName = originalFieldName + " (" + colorbarLabel + ")"
            comparisonFieldName = comparisonFieldName + " (" + \
                colorbarLabel + ")"
        ax.legend([h1[0], h2[0]], [originalFieldName, comparisonFieldName],
                  loc='upper center', bbox_to_anchor=(0.5, -0.25), ncol=1)

    if title is not None:
        if plotAsContours and labelContours \
           and contourComparisonFieldArray is None:
            title = limit_title(title, maxTitleLength-(3+len(colorbarLabel)))
            title = title + " (" + colorbarLabel + ")"
        else:
            title = limit_title(title, maxTitleLength)
        if titleFontSize is None:
            titleFontSize = config.get('plot', 'titleFontSize')
        title_font = {'size': titleFontSize,
                      'color': config.get('plot', 'titleFontColor'),
                      'weight': config.get('plot', 'titleFontWeight')}
        if titleY is not None:
            plt.title(title, y=titleY, **title_font)
        else:
            plt.title(title, **title_font)

    if (xlabel is not None) or (ylabel is not None):
        if axisFontSize is None:
            axisFontSize = config.get('plot', 'axisFontSize')
        axis_font = {'size': axisFontSize}

    if xlabel is not None:
        plt.xlabel(xlabel, **axis_font)
    if ylabel is not None:
        plt.ylabel(ylabel, **axis_font)

    if invertYAxis:
        ax.invert_yaxis()

    if xLim:
        ax.set_xlim(xLim)
    if yLim:
        ax.set_ylim(yLim)

    if xArrayIsTime:
        if firstYearXTicks is None:
            minDays = [xArray[0]]
        else:
            minDays = date_to_days(year=firstYearXTicks, calendar=calendar)
        maxDays = [xArray[-1]]

        plot_xtick_format(calendar, minDays, maxDays, maxXTicks,
                          yearStride=yearStrideXTicks)

    # add a second x-axis scale, if it was requested
    if secondXAxisData is not None:
        ax2 = ax.twiny()
        ax2.set_facecolor(backgroundColor)
        ax2.set_xlabel(secondXAxisLabel, **axis_font)
        xlimits = ax.get_xlim()
        ax2.set_xlim(xlimits)
        xticks = np.linspace(xlimits[0], xlimits[1], numUpperTicks)
        tickValues = np.interp(xticks, x.flatten()[:num_x], secondXAxisData)
        ax2.set_xticks(xticks)
        formatString = "{{0:.{:d}f}}{}".format(
            upperXAxisTickLabelPrecision, r'$\degree$')
        ax2.set_xticklabels([formatString.format(member)
                             for member in tickValues])

        # add a third x-axis scale, if it was requested
        if thirdXAxisData is not None:
            ax3 = ax.twiny()
            ax3.set_facecolor(backgroundColor)
            ax3.set_xlabel(thirdXAxisLabel, **axis_font)
            ax3.set_xlim(xlimits)
            ax3.set_xticks(xticks)
            tickValues = np.interp(xticks, x.flatten()[:num_x], thirdXAxisData)
            ax3.set_xticklabels([formatString.format(member)
                                 for member in tickValues])
            ax3.spines['top'].set_position(('outward', 36))

    return fig, ax  # }}}
Esempio n. 5
0
def plot_polar_comparison(config,
                          lon,
                          lat,
                          modelArray,
                          refArray,
                          diffArray,
                          colorMapSectionName,
                          fileout,
                          title=None,
                          plotProjection='npstere',
                          latmin=50.0,
                          lon0=0,
                          modelTitle='Model',
                          refTitle='Observations',
                          diffTitle='Model-Observations',
                          cbarlabel='units',
                          titleFontSize=None,
                          figsize=None,
                          dpi=None,
                          vertical=False):
    """
    Plots a data set around either the north or south pole.

    Parameters
    ----------
    config : instance of ConfigParser
        the configuration, containing a [plot] section with options that
        control plotting

    Lons, Lats : float arrays
        longitude and latitude arrays

    modelArray, refArray : float arrays
        model and observational or control run data sets

    diffArray : float array
        difference between modelArray and refArray

    colorMapSectionName : str
        section name in ``config`` where color map info can be found.

    fileout : str
        the file name to be written

    title : str, optional
        the subtitle of the plot

    plotProjection : 'npstere' or 'spstere', optional
        projection for the plot (north or south pole)

    modelTitle : str, optional
        title of the model panel

    refTitle : str, optional
        title of the observations or control run panel

    diffTitle : str, optional
        title of the difference (bias) panel

    cbarlabel : str, optional
        label on the colorbar

    titleFontSize : int, optional
        size of the title font

    figsize : tuple of float, optional
        the size of the figure in inches.  If ``None``, the figure size is
        ``(8, 22)`` if ``vertical == True`` and ``(22, 8)`` otherwise.

    dpi : int, optional
        the number of dots per inch of the figure, taken from section ``plot``
        option ``dpi`` in the config file by default

    vertical : bool, optional
        whether the subplots should be stacked vertically rather than
        horizontally
    """

    # Authors
    # -------
    # Xylar Asay-Davis, Milena Veneziani

    def do_subplot(ax, field, title, colormap, norm, levels, ticks, contours,
                   lineWidth, lineColor):
        """
        Make a subplot within the figure.
        """

        data_crs = cartopy.crs.PlateCarree()
        ax.set_extent(extent, crs=data_crs)

        ax.set_title(title, y=1.06, **plottitle_font)

        gl = ax.gridlines(crs=data_crs,
                          color='k',
                          linestyle=':',
                          zorder=5,
                          draw_labels=True)
        gl.xlocator = mticker.FixedLocator(np.arange(-180., 181., 20.))
        gl.ylocator = mticker.FixedLocator(np.arange(-80., 81., 10.))
        gl.n_steps = 100
        gl.right_labels = False
        gl.xformatter = cartopy.mpl.gridliner.LONGITUDE_FORMATTER
        gl.yformatter = cartopy.mpl.gridliner.LATITUDE_FORMATTER

        fieldPeriodic, lonPeriodic = add_cyclic_point(field, lon)

        LonsPeriodic, LatsPeriodic = np.meshgrid(lonPeriodic, lat)

        if levels is None:
            plotHandle = ax.pcolormesh(LonsPeriodic,
                                       LatsPeriodic,
                                       fieldPeriodic,
                                       cmap=colormap,
                                       norm=norm,
                                       transform=data_crs,
                                       zorder=1)
        else:
            plotHandle = ax.contourf(LonsPeriodic,
                                     LatsPeriodic,
                                     fieldPeriodic,
                                     cmap=colormap,
                                     norm=norm,
                                     levels=levels,
                                     transform=data_crs,
                                     zorder=1)

        _add_land_lakes_coastline(ax)

        if contours is not None:
            matplotlib.rcParams['contour.negative_linestyle'] = 'solid'
            ax.contour(LonsPeriodic,
                       LatsPeriodic,
                       fieldPeriodic,
                       levels=contours,
                       colors=lineColor,
                       linewidths=lineWidth,
                       transform=data_crs)

        divider = make_axes_locatable(ax)
        cax = divider.append_axes("right",
                                  size="5%",
                                  pad=0.1,
                                  axes_class=plt.Axes)
        cbar = plt.colorbar(plotHandle, cax=cax, boundaries=levels)
        cbar.set_label(cbarlabel)
        if ticks is not None:
            cbar.set_ticks(ticks)
            cbar.set_ticklabels(['{}'.format(tick) for tick in ticks])

    if dpi is None:
        dpi = config.getint('plot', 'dpi')

    dictModelRef = setup_colormap(config, colorMapSectionName, suffix='Result')
    dictDiff = setup_colormap(config, colorMapSectionName, suffix='Difference')

    if refArray is None:
        if figsize is None:
            figsize = (8, 8.5)
        subplots = [111]
    elif vertical:
        if figsize is None:
            figsize = (8, 22)
        subplots = [311, 312, 313]
    else:
        if figsize is None:
            figsize = (22, 8.5)
        subplots = [131, 132, 133]

    fig = plt.figure(figsize=figsize, dpi=dpi)

    if (title is not None):
        if titleFontSize is None:
            titleFontSize = config.get('plot', 'titleFontSize')
        title_font = {
            'size': titleFontSize,
            'color': config.get('plot', 'titleFontColor'),
            'weight': config.get('plot', 'titleFontWeight')
        }
        fig.suptitle(title, y=0.95, **title_font)

    plottitle_font = {
        'size': config.get('plot', 'threePanelPlotTitleFontSize')
    }

    if plotProjection == 'npstere':
        projection = cartopy.crs.NorthPolarStereo()
        extent = [-180, 180, latmin, 90]
    elif plotProjection == 'spstere':
        projection = cartopy.crs.SouthPolarStereo()
        extent = [-180, 180, -90, latmin]
    else:
        raise ValueError(
            'Unexpected plot projection {}'.format(plotProjection))

    ax = plt.subplot(subplots[0], projection=projection)
    do_subplot(ax=ax, field=modelArray, title=modelTitle, **dictModelRef)

    if refArray is not None:
        ax = plt.subplot(subplots[1], projection=projection)
        do_subplot(ax=ax, field=refArray, title=refTitle, **dictModelRef)

        ax = plt.subplot(subplots[2], projection=projection)
        do_subplot(ax=ax, field=diffArray, title=diffTitle, **dictDiff)

    fig.canvas.draw()
    plt.tight_layout(pad=4.)
    if vertical:
        plt.subplots_adjust(top=0.9)

    if (fileout is not None):
        plt.savefig(fileout, dpi=dpi, bbox_inches='tight', pad_inches=0.1)

    plt.close()
Esempio n. 6
0
def plot_global_comparison(config,
                           Lons,
                           Lats,
                           modelArray,
                           refArray,
                           diffArray,
                           colorMapSectionName,
                           fileout,
                           title=None,
                           modelTitle='Model',
                           refTitle='Observations',
                           diffTitle='Model-Observations',
                           cbarlabel='units',
                           titleFontSize=None,
                           figsize=None,
                           dpi=None,
                           lineWidth=1,
                           lineColor='black'):
    """
    Plots a data set as a longitude/latitude map.

    Parameters
    ----------
    config : instance of ConfigParser
        the configuration, containing a [plot] section with options that
        control plotting

    Lons, Lats : float arrays
        longitude and latitude arrays

    modelArray, refArray : float arrays
        model and observational or control run data sets

    diffArray : float array
        difference between modelArray and refArray

    colorMapSectionName : str
        section name in ``config`` where color map info can be found.

    fileout : str
        the file name to be written

    title : str, optional
        the subtitle of the plot

    modelTitle : str, optional
        title of the model panel

    refTitle : str, optional
        title of the observations or control run panel

    diffTitle : str, optional
        title of the difference (bias) panel

    cbarlabel : str, optional
        label on the colorbar

    titleFontSize : int, optional
        size of the title font

    figsize : tuple of float, optional
        the size of the figure in inches

    dpi : int, optional
        the number of dots per inch of the figure, taken from section ``plot``
        option ``dpi`` in the config file by default

    lineWidth : int, optional
        the line width of contour lines (if specified)

    lineColor : str, optional
        the color of contour lines (if specified)
    """

    # Authors
    # -------
    # Xylar Asay-Davis, Milena Veneziani

    def plot_panel(ax, title, array, colormap, norm, levels, ticks, contours,
                   lineWidth, lineColor):

        ax.set_extent(extent, crs=projection)

        ax.set_title(title, y=1.06, **plottitle_font)

        gl = ax.gridlines(crs=projection,
                          color='k',
                          linestyle=':',
                          zorder=5,
                          draw_labels=True)
        gl.right_labels = False
        gl.top_labels = False
        gl.xlocator = mticker.FixedLocator(np.arange(-180., 181., 60.))
        gl.ylocator = mticker.FixedLocator(np.arange(-80., 81., 20.))
        gl.xformatter = cartopy.mpl.gridliner.LONGITUDE_FORMATTER
        gl.yformatter = cartopy.mpl.gridliner.LATITUDE_FORMATTER

        if levels is None:
            plotHandle = ax.pcolormesh(Lons,
                                       Lats,
                                       array,
                                       cmap=colormap,
                                       norm=norm,
                                       transform=projection,
                                       zorder=1)
        else:
            plotHandle = ax.contourf(Lons,
                                     Lats,
                                     array,
                                     cmap=colormap,
                                     norm=norm,
                                     levels=levels,
                                     extend='both',
                                     transform=projection,
                                     zorder=1)

        _add_land_lakes_coastline(ax)

        if contours is not None:
            matplotlib.rcParams['contour.negative_linestyle'] = 'solid'
            ax.contour(Lons,
                       Lats,
                       array,
                       levels=contours,
                       colors=lineColor,
                       linewidths=lineWidth,
                       transform=projection)

        divider = make_axes_locatable(ax)
        cax = divider.append_axes("right",
                                  size="5%",
                                  pad=0.1,
                                  axes_class=plt.Axes)
        cbar = plt.colorbar(plotHandle, cax=cax, ticks=ticks, boundaries=ticks)
        cbar.set_label(cbarlabel)

    # set up figure
    if dpi is None:
        dpi = config.getint('plot', 'dpi')
    if figsize is None:
        # set the defaults, depending on if we have 1 or 3 panels
        if refArray is None:
            figsize = (8, 5)
        else:
            figsize = (8, 13)
    fig = plt.figure(figsize=figsize, dpi=dpi)
    if (title is not None):
        if titleFontSize is None:
            titleFontSize = config.get('plot', 'titleFontSize')
        title_font = {
            'size': titleFontSize,
            'color': config.get('plot', 'titleFontColor'),
            'weight': config.get('plot', 'titleFontWeight')
        }
        fig.suptitle(title, y=0.95, **title_font)

    plottitle_font = {
        'size': config.get('plot', 'threePanelPlotTitleFontSize')
    }

    if refArray is None:
        subplots = [111]
    else:
        subplots = [311, 312, 313]

    projection = cartopy.crs.PlateCarree()

    extent = [-180, 180, -85, 85]

    dictModelRef = setup_colormap(config, colorMapSectionName, suffix='Result')
    dictDiff = setup_colormap(config, colorMapSectionName, suffix='Difference')

    ax = plt.subplot(subplots[0], projection=projection)
    plot_panel(ax, modelTitle, modelArray, **dictModelRef)

    if refArray is not None:
        ax = plt.subplot(subplots[1], projection=projection)
        plot_panel(ax, refTitle, refArray, **dictModelRef)

        ax = plt.subplot(subplots[2], projection=projection)
        plot_panel(ax, diffTitle, diffArray, **dictDiff)

    if (fileout is not None):
        plt.savefig(fileout, dpi=dpi, bbox_inches='tight', pad_inches=0.1)

    plt.close()
def plot_polar_projection_comparison(config,
                                     x,
                                     y,
                                     landMask,
                                     modelArray,
                                     refArray,
                                     diffArray,
                                     fileout,
                                     colorMapSectionName,
                                     title=None,
                                     modelTitle='Model',
                                     refTitle='Observations',
                                     diffTitle='Model-Observations',
                                     cbarlabel='units',
                                     titleFontSize=None,
                                     figsize=None,
                                     dpi=None,
                                     lineWidth=0.5,
                                     lineColor='black',
                                     vertical=False,
                                     hemisphere='north',
                                     maxTitleLength=55):
    """
    Plots a data set as a longitude/latitude map.

    Parameters
    ----------
    config : instance of ConfigParser
        the configuration, containing a [plot] section with options that
        control plotting

    x, y : numpy ndarrays
        1D x and y arrays defining the projection grid

    landMask : numpy ndarrays
        model and observational or control run data sets

    modelArray, refArray : numpy ndarrays
        model and observational or control run data sets

    diffArray : float array
        difference between modelArray and refArray

    fileout : str
        the file name to be written

    colorMapSectionName : str
        section name in ``config`` where color map info can be found.

    title : str, optional
        the subtitle of the plot

    modelTitle : str, optional
        title of the model panel

    refTitle : str, optional
        title of the observations or control run panel

    diffTitle : str, optional
        title of the difference (bias) panel

    cbarlabel : str, optional
        label on the colorbar

    titleFontSize : int, optional
        size of the title font

    figsize : tuple of float, optional
        the size of the figure in inches.  If ``None``, the figure size is
        ``(8, 22)`` if ``vertical == True`` and ``(22, 8)`` otherwise.

    dpi : int, optional
        the number of dots per inch of the figure, taken from section ``plot``
        option ``dpi`` in the config file by default

    lineWidth : int, optional
        the line width of contour lines (if specified)

    lineColor : str, optional
        the color of contour lines (if specified)

    vertical : bool, optional
        whether the subplots should be stacked vertically rather than
        horizontally

    hemisphere : {'north', 'south'}, optional
        the hemisphere to plot

    maxTitleLength : int, optional
        the maximum number of characters in the title, beyond which it is
        truncated with a trailing ellipsis
    """

    # Authors
    # -------
    # Xylar Asay-Davis

    def plot_panel(ax, title, array, colormap, norm, levels, ticks, contours,
                   lineWidth, lineColor):

        title = limit_title(title, maxTitleLength)
        ax.set_title(title, y=1.06, **plottitle_font)

        ax.set_extent(extent, crs=projection)

        gl = ax.gridlines(crs=cartopy.crs.PlateCarree(),
                          color='k',
                          linestyle=':',
                          zorder=5,
                          draw_labels=True)
        gl.xlocator = mticker.FixedLocator(np.arange(-180., 181., 60.))
        gl.ylocator = mticker.FixedLocator(np.arange(-80., 81., 10.))
        gl.n_steps = 100
        gl.right_labels = False
        gl.xformatter = cartopy.mpl.gridliner.LONGITUDE_FORMATTER
        gl.yformatter = cartopy.mpl.gridliner.LATITUDE_FORMATTER

        if levels is None:
            plotHandle = ax.pcolormesh(x, y, array, cmap=colormap, norm=norm)
        else:
            plotHandle = ax.contourf(xCenter,
                                     yCenter,
                                     array,
                                     cmap=colormap,
                                     norm=norm,
                                     levels=levels,
                                     extend='both')

        if useCartopyCoastline:
            _add_land_lakes_coastline(ax, ice_shelves=False)
        else:
            # add the model coastline
            plt.pcolormesh(x, y, landMask, cmap=landColorMap)
            plt.contour(xCenter,
                        yCenter,
                        landMask.mask, (0.5, ),
                        colors='k',
                        linewidths=0.5)

        if contours is not None:
            matplotlib.rcParams['contour.negative_linestyle'] = 'solid'
            ax.contour(x,
                       y,
                       array,
                       levels=contours,
                       colors=lineColor,
                       linewidths=lineWidth)

        # create an axes on the right side of ax. The width of cax will be 5%
        # of ax and the padding between cax and ax will be fixed at 0.05 inch.
        divider = make_axes_locatable(ax)
        cax = divider.append_axes("right",
                                  size="5%",
                                  pad=0.05,
                                  axes_class=plt.Axes)

        cbar = plt.colorbar(plotHandle, cax=cax)
        cbar.set_label(cbarlabel)
        if ticks is not None:
            cbar.set_ticks(ticks)
            cbar.set_ticklabels(['{}'.format(tick) for tick in ticks])

    useCartopyCoastline = config.getboolean('polarProjection',
                                            'useCartopyCoastline')
    # set up figure
    if dpi is None:
        dpi = config.getint('plot', 'dpi')

    if refArray is None:
        if figsize is None:
            figsize = (8, 7.5)
        subplots = [111]
    elif vertical:
        if figsize is None:
            figsize = (8, 22)
        subplots = [311, 312, 313]
    else:
        if figsize is None:
            figsize = (22, 7.5)
        subplots = [131, 132, 133]

    dictModelRef = setup_colormap(config, colorMapSectionName, suffix='Result')
    dictDiff = setup_colormap(config, colorMapSectionName, suffix='Difference')

    fig = plt.figure(figsize=figsize, dpi=dpi)

    if title is not None:
        if titleFontSize is None:
            titleFontSize = config.get('plot', 'titleFontSize')
        title_font = {
            'size': titleFontSize,
            'color': config.get('plot', 'titleFontColor'),
            'weight': config.get('plot', 'titleFontWeight')
        }
        fig.suptitle(title, y=0.95, **title_font)

    plottitle_font = {
        'size': config.get('plot', 'threePanelPlotTitleFontSize')
    }

    # set up land colormap
    if not useCartopyCoastline:
        colorList = [(0.8, 0.8, 0.8), (0.8, 0.8, 0.8)]
        landColorMap = cols.LinearSegmentedColormap.from_list(
            'land', colorList)

    # locations of centers for contour plots
    xCenter = 0.5 * (x[1:] + x[0:-1])
    yCenter = 0.5 * (y[1:] + y[0:-1])

    if hemisphere == 'north':
        projection = cartopy.crs.Stereographic(central_latitude=90.,
                                               central_longitude=0.0,
                                               true_scale_latitude=75.0)
    elif hemisphere == 'south':
        projection = cartopy.crs.Stereographic(central_latitude=-90.,
                                               central_longitude=0.0,
                                               true_scale_latitude=-71.0)
    else:
        raise ValueError('Unexpected hemisphere {}'.format(hemisphere))
    extent = [x[0], x[-1], y[0], y[-1]]

    ax = plt.subplot(subplots[0], projection=projection)
    plot_panel(ax, modelTitle, modelArray, **dictModelRef)

    if refArray is not None:
        ax = plt.subplot(subplots[1], projection=projection)
        plot_panel(ax, refTitle, refArray, **dictModelRef)

        ax = plt.subplot(subplots[2], projection=projection)
        plot_panel(ax, diffTitle, diffArray, **dictDiff)

    if fileout is not None:
        plt.savefig(fileout, dpi=dpi, bbox_inches='tight', pad_inches=0.1)

    plt.close()