Exemple #1
0
    def plot(self, axis=None, **kwargs):
        """Plot centroids scatter points over earth.

        Parameters
        ----------
        axis : matplotlib.axes._subplots.AxesSubplot, optional
            axis to use
        kwargs : optional
            arguments for scatter matplotlib function

        Returns
        -------
        axis : matplotlib.axes._subplots.AxesSubplot
        """
        if self.meta and not self.coord.size:
            self.set_meta_to_lat_lon()
        pad = np.abs(u_coord.get_resolution(self.lat, self.lon)).min()

        proj_data, _ = u_plot.get_transformation(self.crs)
        proj_plot = proj_data
        if isinstance(proj_data, ccrs.PlateCarree):
            # use different projections for plot and data to shift the central lon in the plot
            xmin, ymin, xmax, ymax = u_coord.latlon_bounds(self.lat, self.lon, buffer=pad)
            proj_plot = ccrs.PlateCarree(central_longitude=0.5 * (xmin + xmax))
        else:
            xmin, ymin, xmax, ymax = (self.lon.min() - pad, self.lat.min() - pad,
                                      self.lon.max() + pad, self.lat.max() + pad)

        if not axis:
            _, axis = u_plot.make_map(proj=proj_plot)

        axis.set_extent((xmin, xmax, ymin, ymax), crs=proj_data)
        u_plot.add_shapes(axis)
        axis.scatter(self.lon, self.lat, transform=proj_data, **kwargs)
        return axis
    def test_latlon_bounds(self):
        """Test latlon_bounds function"""
        lat, lon = np.array([0, -2, 5]), np.array([-179, 175, 178])
        bounds = latlon_bounds(lat, lon)
        self.assertEqual(bounds, (175, -2, 181, 5))
        bounds = latlon_bounds(lat, lon, buffer=1)
        self.assertEqual(bounds, (174, -3, 182, 6))

        # buffer exceeding antimeridian
        lat, lon = np.array([0, -2.1, 5]), np.array([-179.5, -175, -178])
        bounds = latlon_bounds(lat, lon, buffer=1)
        self.assertEqual(bounds, (179.5, -3.1, 186, 6))

        # longitude values need to be normalized before they lie between computed bounds:
        lon_mid = 0.5 * (bounds[0] + bounds[2])
        lon = lon_normalize(lon, center=lon_mid)
        self.assertTrue(np.all((bounds[0] <= lon) & (lon <= bounds[2])))

        # data covering almost the whole longitudinal range
        lat, lon = np.linspace(-90, 90, 180), np.linspace(-180.0, 179, 360)
        bounds = latlon_bounds(lat, lon)
        self.assertEqual(bounds, (-179, -90, 180, 90))
        bounds = latlon_bounds(lat, lon, buffer=1)
        self.assertEqual(bounds, (-180, -90, 180, 90))
Exemple #3
0
    def plot_raster(self,
                    res=None,
                    raster_res=None,
                    save_tiff=None,
                    raster_f=lambda x: np.log10((np.fmax(x + 1, 1))),
                    label='value (log10)',
                    scheduler=None,
                    axis=None,
                    **kwargs):
        """Generate raster from points geometry and plot it using log10 scale:
        np.log10((np.fmax(raster+1, 1))).

        Parameters:
            res (float, optional): resolution of current data in units of latitude
                and longitude, approximated if not provided.
            raster_res (float, optional): desired resolution of the raster
            save_tiff (str, optional): file name to save the raster in tiff
                format, if provided
            raster_f (lambda function): transformation to use to data. Default:
                log10 adding 1.
            label (str): colorbar label
            scheduler (str): used for dask map_partitions. “threads”,
                “synchronous” or “processes”
            axis (matplotlib.axes._subplots.AxesSubplot, optional): axis to use
            kwargs (optional): arguments for imshow matplotlib function

        Returns:
            matplotlib.figure.Figure, cartopy.mpl.geoaxes.GeoAxesSubplot
        """
        if self.meta and self.meta.get('height', 0) * self.meta.get(
                'height', 0) == len(self.gdf):
            raster = self.gdf.value.values.reshape(
                (self.meta['height'], self.meta['width']))
            # check raster starts by upper left corner
            if self.gdf.latitude.values[0] < self.gdf.latitude.values[-1]:
                raster = np.flip(raster, axis=0)
            if self.gdf.longitude.values[0] > self.gdf.longitude.values[-1]:
                LOGGER.error(
                    'Points are not ordered according to meta raster.')
                raise ValueError
        else:
            raster, meta = u_coord.points_to_raster(self.gdf, ['value'], res,
                                                    raster_res, scheduler)
            raster = raster.reshape((meta['height'], meta['width']))
        # save tiff
        if save_tiff is not None:
            with rasterio.open(save_tiff,
                               'w',
                               driver='GTiff',
                               height=meta['height'],
                               width=meta['width'],
                               count=1,
                               dtype=np.float32,
                               crs=self.crs,
                               transform=meta['transform']) as ras_tiff:
                ras_tiff.write(raster.astype(np.float32), 1)
        # make plot
        proj_data, _ = u_plot.get_transformation(self.crs)
        proj_plot = proj_data
        if isinstance(proj_data, ccrs.PlateCarree):
            # use different projections for plot and data to shift the central lon in the plot
            xmin, ymin, xmax, ymax = u_coord.latlon_bounds(
                self.gdf.latitude.values, self.gdf.longitude.values)
            proj_plot = ccrs.PlateCarree(central_longitude=0.5 * (xmin + xmax))
        else:
            xmin, ymin, xmax, ymax = (self.gdf.longitude.min(),
                                      self.gdf.latitude.min(),
                                      self.gdf.longitude.max(),
                                      self.gdf.latitude.max())

        if not axis:
            _, axis = u_plot.make_map(proj=proj_plot)

        cbar_ax = make_axes_locatable(axis).append_axes('right',
                                                        size="6.5%",
                                                        pad=0.1,
                                                        axes_class=plt.Axes)
        axis.set_extent((xmin, xmax, ymin, ymax), crs=proj_data)
        u_plot.add_shapes(axis)
        imag = axis.imshow(raster_f(raster),
                           **kwargs,
                           origin='upper',
                           extent=(xmin, xmax, ymin, ymax),
                           transform=proj_data)
        plt.colorbar(imag, cax=cbar_ax, label=label)
        plt.draw()
        return axis
Exemple #4
0
def _plot_scattered_data(method,
                         array_sub,
                         geo_coord,
                         var_name,
                         title,
                         pop_name=False,
                         buffer=BUFFER,
                         extend='neither',
                         proj=ccrs.PlateCarree(),
                         shapes=True,
                         axes=None,
                         figsize=(9, 13),
                         adapt_fontsize=True,
                         **kwargs):
    """Function for internal use in `geo_scatter_from_array` (when called with method="scatter")
    and `geo_bin_from_array` (when called with method="hexbin"). See the docstrings of the
    respective functions for more information on the parameters."""

    # Generate array of values used in each subplot
    num_im, list_arr = _get_collection_arrays(array_sub)
    list_tit = to_list(num_im, title, 'title')
    list_name = to_list(num_im, var_name, 'var_name')
    list_coord = to_list(num_im, geo_coord, 'geo_coord')

    if 'cmap' not in kwargs:
        kwargs['cmap'] = CMAP_EXPOSURES

    if axes is None:
        proj_plot = proj
        if isinstance(proj, ccrs.PlateCarree):
            # use different projections for plot and data to shift the central lon in the plot
            xmin, xmax = u_coord.lon_bounds(
                np.concatenate([c[:, 1] for c in list_coord]))
            proj_plot = ccrs.PlateCarree(central_longitude=0.5 * (xmin + xmax))
        _, axes, fontsize = make_map(num_im,
                                     proj=proj_plot,
                                     figsize=figsize,
                                     adapt_fontsize=adapt_fontsize)
    else:
        fontsize = None
    axes_iter = axes
    if not isinstance(axes, np.ndarray):
        axes_iter = np.array([[axes]])

    # Generate each subplot
    for array_im, axis, tit, name, coord in \
    zip(list_arr, axes_iter.flatten(), list_tit, list_name, list_coord):
        if coord.shape[0] != array_im.size:
            raise ValueError("Size mismatch in input array: %s != %s." %
                             (coord.shape[0], array_im.size))

        # Binned image with coastlines
        if isinstance(proj, ccrs.PlateCarree):
            xmin, ymin, xmax, ymax = u_coord.latlon_bounds(coord[:, 0],
                                                           coord[:, 1],
                                                           buffer=buffer)
            extent = (xmin, xmax, ymin, ymax)
        else:
            extent = _get_borders(coord,
                                  buffer=buffer,
                                  proj_limits=proj.x_limits + proj.y_limits)
        axis.set_extent((extent), proj)

        if shapes:
            add_shapes(axis)
        if pop_name:
            add_populated_places(axis, extent, proj, fontsize)

        if method == "hexbin":
            if 'gridsize' not in kwargs:
                kwargs['gridsize'] = min(int(array_im.size / 2), MAX_BINS)
            mappable = axis.hexbin(coord[:, 1],
                                   coord[:, 0],
                                   C=array_im,
                                   transform=proj,
                                   **kwargs)
        else:
            mappable = axis.scatter(coord[:, 1],
                                    coord[:, 0],
                                    c=array_im,
                                    transform=proj,
                                    **kwargs)

        # Create colorbar in this axis
        cbax = make_axes_locatable(axis).append_axes('right',
                                                     size="6.5%",
                                                     pad=0.1,
                                                     axes_class=plt.Axes)
        cbar = plt.colorbar(mappable,
                            cax=cbax,
                            orientation='vertical',
                            extend=extend)
        cbar.set_label(name)
        axis.set_title("\n".join(wrap(tit)))
        if fontsize:
            cbar.ax.tick_params(labelsize=fontsize)
            cbar.ax.yaxis.get_offset_text().set_fontsize(fontsize)
            for item in [axis.title, cbar.ax.xaxis.label, cbar.ax.yaxis.label]:
                item.set_fontsize(fontsize)
    plt.tight_layout()
    return axes
Exemple #5
0
    def plot_raster(self,
                    res=None,
                    raster_res=None,
                    save_tiff=None,
                    raster_f=lambda x: np.log10((np.fmax(x + 1, 1))),
                    label='value (log10)',
                    scheduler=None,
                    axis=None,
                    figsize=(9, 13),
                    fill=True,
                    adapt_fontsize=True,
                    **kwargs):
        """Generate raster from points geometry and plot it using log10 scale:
        np.log10((np.fmax(raster+1, 1))).

        Parameters
        ----------
        res : float, optional
            resolution of current data in units of latitude
            and longitude, approximated if not provided.
        raster_res : float, optional
            desired resolution of the raster
        save_tiff : str, optional
            file name to save the raster in tiff
            format, if provided
        raster_f : lambda function
            transformation to use to data. Default:
            log10 adding 1.
        label : str
            colorbar label
        scheduler : str
            used for dask map_partitions. “threads”,
            “synchronous” or “processes”
        axis : matplotlib.axes._subplots.AxesSubplot, optional
            axis to use
        figsize : tuple, optional
            figure size for plt.subplots
        fill : bool, optional
            If false, the areas with no data will be plotted
            in white. If True, the areas with missing values are filled as 0s.
            The default is True.
        adapt_fontsize : bool, optional
            If set to true, the size of the fonts will be adapted to the size of the figure.
            Otherwise the default matplotlib font size is used. Default is True.
        kwargs : optional
            arguments for imshow matplotlib function

        Returns
        -------
        matplotlib.figure.Figure, cartopy.mpl.geoaxes.GeoAxesSubplot
        """
        if self.meta and self.meta.get('height', 0) * self.meta.get(
                'height', 0) == len(self.gdf):
            raster = self.gdf.value.values.reshape(
                (self.meta['height'], self.meta['width']))
            # check raster starts by upper left corner
            if self.gdf.latitude.values[0] < self.gdf.latitude.values[-1]:
                raster = np.flip(raster, axis=0)
            if self.gdf.longitude.values[0] > self.gdf.longitude.values[-1]:
                raise ValueError(
                    'Points are not ordered according to meta raster.')
        else:
            raster, meta = u_coord.points_to_raster(self.gdf, ['value'], res,
                                                    raster_res, scheduler)
            raster = raster.reshape((meta['height'], meta['width']))
        # save tiff
        if save_tiff is not None:
            with rasterio.open(save_tiff,
                               'w',
                               driver='GTiff',
                               height=meta['height'],
                               width=meta['width'],
                               count=1,
                               dtype=np.float32,
                               crs=self.crs,
                               transform=meta['transform']) as ras_tiff:
                ras_tiff.write(raster.astype(np.float32), 1)
        # make plot
        proj_data, _ = u_plot.get_transformation(self.crs)
        proj_plot = proj_data
        if isinstance(proj_data, ccrs.PlateCarree):
            # use different projections for plot and data to shift the central lon in the plot
            xmin, ymin, xmax, ymax = u_coord.latlon_bounds(
                self.gdf.latitude.values, self.gdf.longitude.values)
            proj_plot = ccrs.PlateCarree(central_longitude=0.5 * (xmin + xmax))
        else:
            xmin, ymin, xmax, ymax = (self.gdf.longitude.min(),
                                      self.gdf.latitude.min(),
                                      self.gdf.longitude.max(),
                                      self.gdf.latitude.max())

        if not axis:
            _, axis, fontsize = u_plot.make_map(proj=proj_plot,
                                                figsize=figsize,
                                                adapt_fontsize=adapt_fontsize)
        else:
            fontsize = None
        cbar_ax = make_axes_locatable(axis).append_axes('right',
                                                        size="6.5%",
                                                        pad=0.1,
                                                        axes_class=plt.Axes)
        axis.set_extent((xmin, xmax, ymin, ymax), crs=proj_data)
        u_plot.add_shapes(axis)
        if not fill:
            raster = np.where(raster == 0, np.nan, raster)
            raster_f = lambda x: np.log10((np.maximum(x + 1, 1)))
        if 'cmap' not in kwargs:
            kwargs['cmap'] = CMAP_RASTER
        imag = axis.imshow(raster_f(raster),
                           **kwargs,
                           origin='upper',
                           extent=(xmin, xmax, ymin, ymax),
                           transform=proj_data)
        cbar = plt.colorbar(imag, cax=cbar_ax, label=label)
        plt.colorbar(imag, cax=cbar_ax, label=label)
        plt.tight_layout()
        plt.draw()
        if fontsize:
            cbar.ax.tick_params(labelsize=fontsize)
            cbar.ax.yaxis.get_offset_text().set_fontsize(fontsize)
            for item in [axis.title, cbar.ax.xaxis.label, cbar.ax.yaxis.label]:
                item.set_fontsize(fontsize)
        return axis
Exemple #6
0
def geo_bin_from_array(array_sub,
                       geo_coord,
                       var_name,
                       title,
                       pop_name=True,
                       buffer=BUFFER,
                       extend='neither',
                       proj=ccrs.PlateCarree(),
                       axes=None,
                       figsize=(9, 13),
                       **kwargs):
    """Plot array values binned over input coordinates.

    Parameters
    ----------
    array_sub : np.array(1d or 2d) or list(np.array)
        Each array (in a row or in  the list) are values at each point in corresponding
        geo_coord that are binned in one subplot.
    geo_coord : 2d np.array or list(2d np.array)
        (lat, lon) for each point in a row. If one provided, the same grid is used for all
        subplots. Otherwise provide as many as subplots in array_sub.
    var_name : str or list(str)
        label to be shown in the colorbar. If one provided, the same is used for all subplots.
        Otherwise provide as many as subplots in array_sub.
    title : str or list(str)
        subplot title. If one provided, the same is used for all subplots.
        Otherwise provide as many as subplots in array_sub.
    pop_name : bool, optional
        add names of the populated places, by default True
    buffer : float, optional
        border to add to coordinates, by default BUFFER
    extend : str, optional
        extend border colorbar with arrows.
        [ 'neither' | 'both' | 'min' | 'max' ], by default 'neither'
    proj : ccrs, optional
        coordinate reference system of the given data, by default ccrs.PlateCarree()
    axes : Axes or ndarray(Axes), optional
        by default None
    figsize : tuple, optional
        figure size for plt.subplots, by default (9, 13)
    **kwargs
        arbitrary keyword arguments for hexbin matplotlib function

    Returns
    -------
    cartopy.mpl.geoaxes.GeoAxesSubplot

    Raises
    ------
    ValueError
    """

    # Generate array of values used in each subplot
    num_im, list_arr = _get_collection_arrays(array_sub)
    list_tit = to_list(num_im, title, 'title')
    list_name = to_list(num_im, var_name, 'var_name')
    list_coord = to_list(num_im, geo_coord, 'geo_coord')

    if 'cmap' not in kwargs:
        kwargs['cmap'] = 'Wistia'

    if axes is None:
        proj_plot = proj
        if isinstance(proj, ccrs.PlateCarree):
            # use different projections for plot and data to shift the central lon in the plot
            xmin, xmax = u_coord.lon_bounds(
                np.concatenate([c[:, 1] for c in list_coord]))
            proj_plot = ccrs.PlateCarree(central_longitude=0.5 * (xmin + xmax))
        _, axes = make_map(num_im, proj=proj_plot, figsize=figsize)

    if not isinstance(axes, np.ndarray):
        axes_iter = np.array([[axes]])

    # Generate each subplot
    for array_im, axis, tit, name, coord in \
    zip(list_arr, axes_iter.flatten(), list_tit, list_name, list_coord):
        if coord.shape[0] != array_im.size:
            raise ValueError("Size mismatch in input array: %s != %s." %
                             (coord.shape[0], array_im.size))

        # Binned image with coastlines
        if isinstance(proj, ccrs.PlateCarree):
            xmin, ymin, xmax, ymax = u_coord.latlon_bounds(coord[:, 0],
                                                           coord[:, 1],
                                                           buffer=buffer)
            extent = (xmin, xmax, ymin, ymax)
        else:
            extent = _get_borders(coord,
                                  buffer=buffer,
                                  proj_limits=proj.x_limits + proj.y_limits)
        axis.set_extent((extent), proj)
        add_shapes(axis)
        if pop_name:
            add_populated_places(axis, extent, proj)

        if 'gridsize' not in kwargs:
            kwargs['gridsize'] = min(int(array_im.size / 2), MAX_BINS)
        hex_bin = axis.hexbin(coord[:, 1],
                              coord[:, 0],
                              C=array_im,
                              transform=proj,
                              **kwargs)

        # Create colorbar in this axis
        cbax = make_axes_locatable(axis).append_axes('right',
                                                     size="6.5%",
                                                     pad=0.1,
                                                     axes_class=plt.Axes)
        cbar = plt.colorbar(hex_bin,
                            cax=cbax,
                            orientation='vertical',
                            extend=extend)
        cbar.set_label(name)
        axis.set_title(tit)

    return axes