示例#1
0
def _get_figure(map_region='default', map_par=None, fig_par=None,
                fig=None, ax=None, m=None, image=None):
    """Returns a matplotlib figure based on the parameters.

    The idea is that I create a :class:`Structure` that contains the figure,
    ax, and m instance. I also add a field for "indices".
    This is so as to be able to reuse figures. This saves a huge amount of
    time, as creating then basemap instance can be time consuming.

    USAGE::
        >>> fig = _get_figure()
        or
        >>> fig = _get_figure(map_region='polarcat')

    Returns
       This will return the "FIG" object, which has attributes: `fig`, `ax`,
       `m`, and `indices`. The indices are used for deleting lines, texts,
       collections, etc. if and when we are reusing the figure instance. The
       indices basically give us a reference to the *empty* map, so we can
       delete lines without losing meridians or parallels for example.

         ============      ======================================
         keys              description
         ============      ======================================
         fig               A pyplot.fig instance, use
                           plt.figure(FIG.fig.number) to make the
                           fig active (for example to use
                           plt.savefig('filename.png')
         m                 The basemap instance so you can do:
                           x,y = FIG.m(lon,lat)
         ax                The axes
         indices           with index for texts, images, lines,
                           and collections
         ============      ======================================

    """
    fig_par = fig_par or {}

    figure = Structure()

    if m is None:
        fig, m = mp.get_base_image(map_region, map_par, fig_par, image=image)

    elif fig is None:
        map_par, fig_par = mp.map_regions(map_region, map_par, fig_par)
        fig = plt.figure(**fig_par)

    figure.fig = fig
    figure.m = m
    figure.ax = ax if ax is not None else fig.gca()

    figure.indices = Structure(
        texts=len(figure.ax.texts),
        images=len(figure.ax.images),
        collections=len(figure.ax.collections),
        lines=len(figure.ax.lines),
    )

    print("Using figure: %s" % figure.fig.number)
    return figure
示例#2
0
def plot_curtain(H, data,
                 nx=None,
                 ny=None,
                 data_range=None,
                 units='ppbv',
                 datainfo_str=None,
                 asl=True,
                 plottitle=None,
                 log=True,
                 figure=None,
                 cax_title=None,
                 method='contourf',
                 fig_par=None):
    """ plot_sensitivity: core function for plotting FLEXPART output.

    Usage::

        > FIG = plot_sensitivity(H,data,*kwargs)

    This returns the FIGURE object, and plots the sensitivity from the data contained in the "D"
    array.

    Inputs
      H = a :class:`Header` instance for a FLEXPART run.
      data = a 2d data array containing the sensitivity values to plot, this can be extracted from a
      grid instance (see :func:`readgridV8` and :func:`get_slabs`)

    Returns
      A "mapping.py" ``FIGURE`` object.

    Arguments

      .. tabularcolumns::  |l|L|

      =============         ================================================
      keyword               Description [default]
      =============         ================================================
      data_range            range of data for scale bars, if None will
                            be taken from min/max of data
      asl                   [True] plot the units in m.a.s.l
      cax_title             string to be passed as colorbar title (units will
                            be passed to the format argument)
      units                 units for the scale bar
      datainfo_str          A string for labeling the scale bar.
      plottitle             Title for the plot.
      rel_i                 Release index to plot from the data array
      map_region                A map_region specified in mapping.py
      projection            [deprecated] use pre-defined map_regions.
      dropm                 Force creation of a new basemap instance
      coords                Used with autofit option. An array of lat,lon
                            values for the mapping module to autofit a
                            basemap instance to.
      autofit               Try to generate map_region automagically (flakey)
      overlay               Force removal of previous figure elements.
      transform             For use with imshow method, if your data is not
                            in same coordinates as projection, try to transform
                            the data to the basemap projection.
      log                   Create a logarithmic color scale.
      figure                A FIGURE instance from mapping module get_FIGURE
      MapPar                A Structure of paramters to be passed to the
                            basemap class when creating an instance.
      method                The method to use for plotting array data. May be
                            one of: [pcolormesh], imshow, or contourf
      lsmask                set to True to draw a grey landseamask [False]
      =============         ================================================

    .. todo::
        A lot!! There are some problems here and it is sensitive to options.
        lsmask = True seems to only work with certain projections (POLARCAT)

    .. note::
        This is the primary main function for creating plots of flexpart output.
        Most the other routines are simply wrappers to this function, passing
        arguments in with some predefined settings. For more information on the
        mechanics of this function, see the mapping.py module and the matplotlib
        basemap toolkit.


    """

    methods = ['imshow', 'pcolormesh', 'contourf', 'contour', 'None']
    assert method in methods, "method keyword must be one of: %s" % methods

    if figure is None:
        fig_par = fig_par or {}
        fig = plt.figure(**fig_par)
        ax = fig.add_subplot(111)
        figure = Structure(fig=fig, ax=ax)
    else:
        fig = figure.fig
        ax = figure.ax

    # Make the figure current
    plt.figure(fig.number)
    plt.axes(ax)

    # Get min/max range
    #data = data.slabs[0]
    if data_range is not None:
        dat_min = data_range[0]
        dat_max = data_range[1]
    else:
        dat_min, dat_max = [data.min(), data.max()]

    if log:
        clevs = _log_clevs(dat_min, dat_max)
    else:
        clevs = [i for i in np.arange(dat_min, dat_max, (dat_max - dat_min) / 100)]

    # # Set up the IMAGE
    # # cmapnames = ['jet', 'hsv', 'gist_ncar', 'gist_rainbow', 'cool', 'spectral']
    colmap = _gen_flexpart_colormap()
    colmap.set_over(color='k', alpha=0.8)
    topodat = data


    if method == 'imshow':
        im = plt.imshow(np.flipud(topodat), cmap=colmap, zorder=-1,
                      norm=mpl.colors.LogNorm(vmin=clevs[0],
                                              vmax=clevs[-1]))

    if method == 'pcolormesh':
        im = plt.pcolormesh(nx, ny, topodat, cmap=colmap,
                          norm=mpl.colors.LogNorm(vmin=clevs[0],
                                                  vmax=clevs[-1]))
    if method == 'contourf':
        print('*******')
        print(nx)
        print(ny)
        print('*******')
        print(topodat)
        print('*******')
        im = plt.contourf(topodat)
#       im = plt.contourf(nx, ny, topodat, cmap=colmap, levels=clevs,
#                       norm=mpl.colors.LogNorm(vmin=clevs[0],
#                                               vmax=clevs[-1]))

    if method == 'contour':
        im = plt.contour(nx, ny, topodat, cmap=colmap,
                        norm=mpl.colors.LogNorm(vmin=clevs[0],
                                                vmax=clevs[-1]))

    # # Get the current axes, and properties for use later
    pos = ax.get_position()
    l, b, w, h = pos.bounds

    # # CREATE COLORBAR
    # # Note, with upgrades to matplotlib and basemap had to make some
    # # changes here... no more 'ghost' axes
    # # does a colorbar already exist?
    try:
        cb = figure.cb
        cax = figure.cax
        cb.update_normal(im)
    except:
    # # make a copy of the image object, change
    # # colormap to linear version of the precip colormap.
    # # create new axis for colorbar.
        h = 0.8 * h
        l = l + w + .02
        b = 0.5 - (h / 2)
        w = 0.025
        cax = plt.axes([l, b, w, h])
    # # using im2, not im (hack to prevent colors from being
    # # too compressed at the low end on the colorbar - results
    # # from highly nonuniform colormap)
        cb = fig.colorbar(im, cax=cax)  # , format='%3.2g') # draw colorbar
        figure.cax = cax
        figure.cb = cb

    # # set colorbar label and ticks
    p_cax = mpl.font_manager.FontProperties(size='6')
    clabels = list(clevs[::10])  # #clevs, by 10 steps
    clabels.append(clevs[-1])  # # add the last label
    # cax.set_yticks(np.linspace(clabels[0],clabels[-1],len(clabels)))
    cax.set_yticks(np.linspace(0, 1, len(clabels)))
    cax.set_yticklabels(['%3.2g' % cl for cl in clabels])
                        # fontproperties=p_cax)

    if cax_title:
        cax.set_title(cax_title.format(units), fontproperties=p_cax)
    else:
        cax.set_title('sensitivity\n({0})'.format(units),
                          fontproperties=p_cax)

    # # make the original axes current again
    plt.axes(ax)
    plt.grid(True)
    figure.ax = ax
    figure.fig = fig

    if plottitle != None:
        figure.ax.set_title(plottitle, fontsize=10)

    return figure
示例#3
0
def map_regions(map_region='default', map_par=None, fig_par=None):
    """Given a `map_region`, return the associated parameters in mapping DB.

    USAGE::
        map_par, fig_par = map_regions(map_region="polarcat")

    The list of regions know by reflexible by default is located in the
    package file named 'mapping_db.yml'.  If you want to create a new region,
    or override an existing one in reflexible itself, you can create it in
    your own YAML file.  For example, suppose that you have the next
    'myregions.yml' file::

      northern_hemisphere:
        descr: Northern Hemisphere
        alias: my_own_nh
        map_par:
            projection: cyl
            llcrnrlat: 0.5
            urcrnrlat: 90
            llcrnrlon: -180.7
            urcrnrlon: 180
            resolution: c
            # anchor: W
        fig_par:
            figsize: [8, 3]  # w,h tuple
            axlocs: [0.1, 0.1, .7, .8]

    For informing reflexible on where your mapping file is located, you just
    create the REFLEXIBLE_MAPDB environment variable with its path::

      $ export REFLEXIBLE_MAPDB = $HOME/my_analysis/myregions.yml

    Since this moment on, the definitions in your file will be used (with
    highest priority) for finding the regions specified in `map_region`.

    Returns
      Two dictionaries, first a map_par dictionary with keywords that are the
      same as what is need to create a basemap instance of matplotlib:

      ============      ==========================
      keys              description
      ============      ==========================
      llcrnrlat         lower left latitude
      llcrnrlon         lower left longitude
      urcrnrlat         upper right latitude
      urcrnrlon         upper right longitude
      area_thresh       area threshold
      resolution        resolution
      projection        projection
      lat_1             lat_1
      lon_0             lon_0
      rsphere           (6378137.00,6356752.3142)
      m                 you can pass an m object
                        which is needed for some
                        regions
      ============      ==========================

      Second, a fig_par dictionary that contains options that may be passed to
      the :mod:`matplotlib.pyplot` :func:`figure` function:

      ============      ==========================
      keys              description
      ============      ==========================
      figsize           size of the figure
      axlocs            locations of the axes
      ============      ==========================

      .. note::
          You can override the returned map_par and fig_par dicts by passing
          dicts through the optional `map_par` and `fig_par` parameters.
    """
    # Set some default values
    map_par_ = Structure(anchor='C')
    fig_par_ = Structure(
        figsize=[8, 7],  # w,h tuple
        axlocs=[0.05, 0.01, .8, .9],  # rect = l,b,w,h
    )

    # Get the database out of the system YAML file
    mapdb_file = os.path.join(os.path.dirname(__file__), 'mapping_db.yml')
    with open(mapdb_file) as mapdb:
        mapping_db = yaml.safe_load(mapdb)

    # and merge it with a possible one pointed by REFLEXIBLE_MAPDB env var
    if 'REFLEXIBLE_MAPDB' in os.environ:
        user_mapdb_file = os.environ['REFLEXIBLE_MAPDB']
        with open(user_mapdb_file) as mapdb:
            mapping_db.update(yaml.safe_load(mapdb))

    # Lookup the region and its aliases
    try:
        region = mapping_db[map_region]
    except KeyError:
        # Lookup aliases
        for key in mapping_db:
            if 'alias' in mapping_db[key]:
                alias = mapping_db[key]['alias']
                if map_region in re.split(r',\s*', alias):
                    region = mapping_db[key]
                    break
        else:
            raise KeyError("region {} not found".format(map_region))

    # Get the params
    map_par_.update(region['map_par'])  # map_par should be always there
    fig_par_.update(region.get('fig_par', {}))  # fig_par not always present

    # Override params if `map_par` or `fig_par` are passed
    map_par_.update(map_par or {})
    fig_par_.update(fig_par or {})

    # Just in case
    map_par_.pop('m', None)

    return map_par_, fig_par_
示例#4
0
def _get_figure(map_region='default', map_par=None, fig_par=None,
                fig=None, ax=None, m=None, image=None):
    """Returns a matplotlib figure based on the parameters.

    The idea is that I create a :class:`Structure` that contains the figure,
    ax, and m instance. I also add a field for "indices".
    This is so as to be able to reuse figures. This saves a huge amount of
    time, as creating then basemap instance can be time consuming.

    USAGE::
        >>> fig = _get_figure()
        or
        >>> fig = _get_figure(map_region='polarcat')

    Returns
       This will return the "FIG" object, which has attributes: `fig`, `ax`,
       `m`, and `indices`. The indices are used for deleting lines, texts,
       collections, etc. if and when we are reusing the figure instance. The
       indices basically give us a reference to the *empty* map, so we can
       delete lines without losing meridians or parallels for example.

         ============      ======================================
         keys              description
         ============      ======================================
         fig               A pyplot.fig instance, use
                           plt.figure(FIG.fig.number) to make the
                           fig active (for example to use
                           plt.savefig('filename.png')
         m                 The basemap instance so you can do:
                           x,y = FIG.m(lon,lat)
         ax                The axes
         indices           with index for texts, images, lines,
                           and collections
         ============      ======================================

    """
    fig_par = fig_par or {}

    figure = Structure()

    if m is None:
        if image:
            fig, m = mp.get_base_image(image, map_region, map_par, fig_par)
        else:
            fig, m = mp.get_base1(map_region, map_par, fig_par, fig=fig)

    if fig is None:
        map_par, fig_par = mp.map_regions(map_region, map_par, fig_par)
        fig = plt.figure(**fig_par)

    figure.fig = fig
    figure.m = m
    figure.ax = ax if ax is not None else fig.gca()

    figure.indices = Structure(
        texts=len(figure.ax.texts),
        images=len(figure.ax.images),
        collections=len(figure.ax.collections),
        lines=len(figure.ax.lines),
    )

    print("Using figure: %s" % figure.fig.number)
    return figure
示例#5
0
def plot_curtain(H, data, data_range=None,
                 nx=None,
                 ny=None,
                 units='ppbv',
                 datainfo_str=None,
                 asl=True,
                 plottitle=None,
                 log=True,
                 figure=None,
                 cax_title=None,
                 method='contourf',
                 fig_par=None):
    """ plot_sensitivity: core function for plotting FLEXPART output.

    Usage::

        > FIG = plot_sensitivity(H,data,*kwargs)

    This returns the FIGURE object, and plots the sensitivity from the data contained in the "D"
    array.

    Inputs
      H = a :class:`Header` instance for a FLEXPART run.
      data = a 2d data array containing the sensitivity values to plot, this can be extracted from a
      grid instance (see :func:`readgridV8` and :func:`get_slabs`)

    Returns
      A "mapping.py" ``FIGURE`` object.

    Arguments

      .. tabularcolumns::  |l|L|

      =============         ================================================
      keyword               Description [default]
      =============         ================================================
      data_range            range of data for scale bars, if None will
                            be taken from min/max of data
      asl                   [True] plot the units in m.a.s.l
      cax_title             string to be passed as colorbar title (units will
                            be passed to the format argument)
      units                 units for the scale bar
      datainfo_str          A string for labeling the scale bar.
      plottitle             Title for the plot.
      rel_i                 Release index to plot from the data array
      map_region                A map_region specified in mapping.py
      projection            [deprecated] use pre-defined map_regions.
      dropm                 Force creation of a new basemap instance
      coords                Used with autofit option. An array of lat,lon
                            values for the mapping module to autofit a
                            basemap instance to.
      autofit               Try to generate map_region automagically (flakey)
      overlay               Force removal of previous figure elements.
      transform             For use with imshow method, if your data is not
                            in same coordinates as projection, try to transform
                            the data to the basemap projection.
      log                   Create a logarithmic color scale.
      figure                A FIGURE instance from mapping module get_FIGURE
      MapPar                A Structure of paramters to be passed to the
                            basemap class when creating an instance.
      method                The method to use for plotting array data. May be
                            one of: [pcolormesh], imshow, or contourf
      lsmask                set to True to draw a grey landseamask [False]
      =============         ================================================

    .. todo::
        A lot!! There are some problems here and it is sensitive to options.
        lsmask = True seems to only work with certain projections (POLARCAT)

    .. note::
        This is the primary main function for creating plots of flexpart output.
        Most the other routines are simply wrappers to this function, passing
        arguments in with some predefined settings. For more information on the
        mechanics of this function, see the mapping.py module and the matplotlib
        basemap toolkit.


    """

    methods = ['imshow', 'pcolormesh', 'contourf', 'contour', 'None']
    assert method in methods, "method keyword must be one of: %s" % methods

    if figure is None:
        fig_par = fig_par or {}
        fig = plt.figure(**fig_par)
        ax = fig.add_subplot(111)
        figure = Structure(fig=fig, ax=ax)
    else:
        fig = figure.fig
        ax = figure.ax

    # Make the figure current
    plt.figure(fig.number)
    plt.axes(ax)

    # Get min/max range
    #data = data.slabs[0]
    if data_range is not None:
        dat_min = data_range[0]
        dat_max = data_range[1]
    else:
        dat_min, dat_max = [data.min(), data.max()]

    if log:
        clevs = _log_clevs(dat_min, dat_max)
    else:
        clevs = [i for i in np.arange(dat_min, dat_max, (dat_max - dat_min) / 100)]

    # # Set up the IMAGE
    # # cmapnames = ['jet', 'hsv', 'gist_ncar', 'gist_rainbow', 'cool', 'spectral']
    colmap = _gen_flexpart_colormap()
    colmap.set_over(color='k', alpha=0.8)
    topodat = data


    if method == 'imshow':
        im = plt.imshow(np.flipud(topodat), cmap=colmap, zorder=-1,
                      norm=mpl.colors.LogNorm(vmin=clevs[0],
                                              vmax=clevs[-1]))

    if method == 'pcolormesh':
        im = plt.pcolormesh(nx, ny, topodat, cmap=colmap,
                          norm=mpl.colors.LogNorm(vmin=clevs[0],
                                                  vmax=clevs[-1]))
    if method == 'contourf':
        im = plt.contourf(topodat)
#       im = plt.contourf(nx, ny, topodat, cmap=colmap, levels=clevs,
#                       norm=mpl.colors.LogNorm(vmin=clevs[0],
#                                               vmax=clevs[-1]))

    if method == 'contour':
        im = plt.contour(nx, ny, topodat, cmap=colmap,
                        norm=mpl.colors.LogNorm(vmin=clevs[0],
                                                vmax=clevs[-1]))

    # # Get the current axes, and properties for use later
    pos = ax.get_position()
    l, b, w, h = pos.bounds

    # # CREATE COLORBAR
    # # Note, with upgrades to matplotlib and basemap had to make some
    # # changes here... no more 'ghost' axes
    # # does a colorbar already exist?
    try:
        cb = figure.cb
        cax = figure.cax
        cb.update_normal(im)
    except:
    # # make a copy of the image object, change
    # # colormap to linear version of the precip colormap.
    # # create new axis for colorbar.
        h = 0.8 * h
        l = l + w + .02
        b = 0.5 - (h / 2)
        w = 0.025
        cax = plt.axes([l, b, w, h])
    # # using im2, not im (hack to prevent colors from being
    # # too compressed at the low end on the colorbar - results
    # # from highly nonuniform colormap)
        cb = fig.colorbar(im, cax=cax)  # , format='%3.2g') # draw colorbar
        figure.cax = cax
        figure.cb = cb

    # # set colorbar label and ticks
    p_cax = mpl.font_manager.FontProperties(size='6')
    clabels = list(clevs[::10])  # #clevs, by 10 steps
    clabels.append(clevs[-1])  # # add the last label
    # cax.set_yticks(np.linspace(clabels[0],clabels[-1],len(clabels)))
    cax.set_yticks(np.linspace(0, 1, len(clabels)))
    cax.set_yticklabels(['%3.2g' % cl for cl in clabels])
                        # fontproperties=p_cax)

    if cax_title:
        cax.set_title(cax_title.format(units), fontproperties=p_cax)
    else:
        cax.set_title('sensitivity\n({0})'.format(units),
                          fontproperties=p_cax)

    # # make the original axes current again
    plt.axes(ax)
    plt.grid(True)
    figure.ax = ax
    figure.fig = fig

    if plottitle != None:
        figure.ax.set_title(plottitle, fontsize=10)

    return figure