def get_scale(dataset, variable, depth, timestamp, projection, extent, interp,
              radius, neighbours):
    """
    Calculates and returns the range (min, max values) of a selected variable,
    given the current map extents.
    """
    x = np.linspace(extent[0], extent[2], 50)
    y = np.linspace(extent[1], extent[3], 50)
    xx, yy = np.meshgrid(x, y)
    dest = Proj(init=projection)
    lon, lat = dest(xx, yy, inverse=True)

    variables = variable.split(",")
    config = DatasetConfig(dataset)

    with open_dataset(config, variable=variables, timestamp=timestamp) as ds:

        d = ds.get_area(np.array([lat, lon]), depth, timestamp, variables[0],
                        interp, radius, neighbours)

        if len(variables) > 1:
            d0 = d
            d1 = ds.get_area(np.array([lat, lon]), depth, timestamp,
                             variables[1], interp, radius, neighbours)
            d = __magnitude(d0,
                            d1)  # Use your dot-product instead of exponents

        return normalize_scale(d, config.variable[",".join(variables)])
 def __add_surface_plot(self, axis_divider):
     ax = axis_divider.append_axes("top", size="35%", pad=0.35)
     ax.plot(self.surface_data['distance'],
             self.surface_data['data'], color='r')
     ax.locator_params(nbins=3)
     ax.yaxis.tick_right()
     ax.yaxis.set_label_position("right")
     label = plt.ylabel(utils.mathtext(self.surface_data['unit']))
     title = plt.title(self.surface_data['name'], y=1.1)
     plt.setp(title, size='smaller')
     plt.setp(label, size='smaller')
     plt.setp(ax.get_yticklabels(), size='x-small')
     plt.xlim([0, self.surface_data['distance'][-1]])
     plt.ylim(utils.normalize_scale(self.surface_data['data'],
                                    self.surface_data['config']))
     ax.yaxis.grid(True)
     ax.axes.get_xaxis().set_visible(False)
Example #3
0
def get_scale(dataset, variable, depth, time, projection, extent, interp,
              radius, neighbours):
    x = np.linspace(extent[0], extent[2], 50)
    y = np.linspace(extent[1], extent[3], 50)
    xx, yy = np.meshgrid(x, y)
    dest = Proj(init=projection)
    lon, lat = dest(xx, yy, inverse=True)

    variables = variable.split(",")
    config = DatasetConfig(dataset)

    with open_dataset(config) as ds:
        timestamp = ds.timestamps[time]

        d = ds.get_area(np.array([lat, lon]), depth, time, variables[0],
                        interp, radius, neighbours)

        if len(variables) > 1:
            d0 = d
            d1 = ds.get_area(np.array([lat, lon]), depth, time, variables[1],
                             interp, radius, neighbours)
            d = np.sqrt(d0**2 + d1**2)

        return normalize_scale(d, config.variable[",".join(variables)])
    def plot(self):

        gs, fig, velocity = self.gridSetup()

        # Plot the transect on a map
        if self.showmap:
            plt.subplot(gs[0, 0])
            utils.path_plot(self.transect_data['points'])

        # Args:
        #    subplots: a GridSpec object (gs)
        #    map_subplot: Row number (Note: don't use consecutive rows to allow
        #                 for expanding figure height)
        #    data: Data to be plotted
        #    name: subplot title
        #    cmapLabel: label for colourmap legend
        #    vmin: minimum value for a variable (grabbed from the lowest value of some data)
        #    vmax: maxmimum value for a variable (grabbed from the highest value of some data)onstrate a networked Ope
        #    units: units for variable (PSU, Celsius, etc)
        #    cmap: colormap for variable
        #
        def do_plot(subplots, map_subplot, data, name, cmapLabel, vmin, vmax,
                    units, cmap):

            plt.subplot(subplots[map_subplot[0], map_subplot[1]])

            divider = self._transect_plot(data, self.depth, name, vmin, vmax,
                                          cmapLabel, units, cmap)

            if self.surface:
                self._surface_plot(divider)

        """
        Finds and returns the correct min/max values for the variable scale
        Args:
            scale: scale for the left or Right Map (self.scale or self.compare['scale])
            data: transect_data
        Returns:
            (min, max)
        """

        def find_minmax(scale, data):
            if scale:
                return (scale[0], scale[1])
            else:
                return (np.amin(data), np.amax(data))

        # Creates and places the plots
        def velocity_plot():

            Row = 0
            if self.showmap:
                Col = 1
            else:
                Col = 0

            if self.selected_velocity_plots[0] == 1:
                do_plot(
                    gs, [Row, Col], self.transect_data['magnitude'],
                    gettext("Magnitude") +
                    gettext(" for ") + self.date_formatter(self.timestamp),
                    gettext("Magnitude"), vmin, vmax,
                    self.transect_data['unit'], self.cmap)
                Row += 1
            if self.selected_velocity_plots[1] == 1:
                do_plot(
                    gs, [Row, Col], self.transect_data['parallel'],
                    self.transect_data['name'] + " (" + gettext("Parallel") +
                    ")" +
                    gettext(" for ") + self.date_formatter(self.timestamp),
                    gettext("Parallel"), vmin, vmax,
                    self.transect_data['unit'], self.cmap)
                Row += 1
            if self.selected_velocity_plots[2] == 1:

                do_plot(
                    gs, [Row, Col], self.transect_data['perpendicular'],
                    self.transect_data['name'] + " (" +
                    gettext("Perpendicular") + ")" + gettext(" for ") +
                    self.date_formatter(self.timestamp),
                    gettext("Perpendicular"), vmin, vmax,
                    self.transect_data['unit'], self.cmap)

        # Plot Transects
        # If in compare mode

        Type = ['magnitude', 'parallel', 'perpendicular']

        if self.compare:
            # Velocity has 2 components
            if velocity:
                if self.scale:
                    vmin = self.scale[0]
                    vmax = self.scale[1]
                else:
                    vmin = min(np.amin(self.transect_data['parallel']),
                               np.amin(self.transect_data['perpendicular']))
                    vmax = max(np.amax(self.transect_data['parallel']),
                               np.amin(self.transect_data['perpendicular']))
                    vmin = min(vmin, -vmax)
                    vmax = max(vmax, -vmin)

                # Get colormap for variable
                if self.showmap:
                    Col = 1
                else:
                    Col = 0

                do_plot(
                    gs, [0, Col], self.transect_data['parallel'],
                    self.transect_data['name'] + " (" + gettext("Parallel") +
                    ")" +
                    gettext(" for ") + self.date_formatter(self.timestamp),
                    gettext("Parallel"), vmin, vmax,
                    self.transect_data['unit'], self.cmap)
                Col += 1
                do_plot(
                    gs, [0, Col], self.transect_data['perpendicular'],
                    self.transect_data['name'] + " (" +
                    gettext("Perpendicular") + ")" + gettext(" for ") +
                    self.date_formatter(self.timestamp),
                    gettext("Perpendicular"), vmin, vmax,
                    self.transect_data['unit'], self.cmap)

                if len(self.compare['variables']) == 2:
                    if self.compare['scale']:
                        vmin = self.compare['scale'][0]
                        vmax = self.compare['scale'][1]
                    else:
                        vmin = min(np.amin(self.compare['parallel']),
                                   np.amin(self.compare['perpendicular']))
                        vmax = max(np.amax(self.compare['parallel']),
                                   np.amin(self.compare['perpendicular']))
                        vmin = min(vmin, -vmax)
                        vmax = max(vmax, -vmin)

                    # Get colormap for variable
                    cmap = colormap.find_colormap(self.compare['colormap'])
                    if self.showmap:
                        Col = 1
                    else:
                        Col = 0
                    do_plot(
                        gs, [1, Col], self.compare['parallel'],
                        self.transect_data['name'] + " (" +
                        gettext("Parallel") + ")" + gettext(" for ") +
                        self.date_formatter(self.compare['date']),
                        gettext("Parallel"), vmin, vmax,
                        self.transect_data['unit'], cmap)
                    Col += 1
                    do_plot(
                        gs, [1, Col], self.compare['perpendicular'],
                        self.transect_data['name'] + " (" +
                        gettext("Perpendicular") + ")" + gettext(" for ") +
                        self.date_formatter(self.compare['date']),
                        gettext("Perpendicular"), vmin, vmax,
                        self.transect_data['unit'], cmap)

            else:
                vmin, vmax = utils.normalize_scale(
                    self.transect_data['data'],
                    self.dataset_config.variable[self.variables[0]])

                # Render primary/Left Map
                if self.showmap:
                    Col = 1
                else:
                    Col = 0

                do_plot(
                    gs, [0, Col], self.transect_data['data'],
                    self.transect_data['name'] + gettext(" for ") +
                    self.date_formatter(self.timestamp),
                    self.transect_data['name'], vmin, vmax,
                    self.transect_data['unit'], self.cmap)

                # Render Right Map
                vmin, vmax = utils.normalize_scale(
                    self.transect_data['compare_data'],
                    self.compare_config.variable[",".join(
                        self.compare['variables'])])
                if self.showmap:
                    Col = 1
                else:
                    Col = 0

                do_plot(
                    gs, [1, Col], self.transect_data['compare_data'],
                    self.compare['name'] + gettext(" for ") +
                    self.date_formatter(self.compare['date']),
                    self.compare['name'], vmin, vmax, self.compare['unit'],
                    self.compare['colormap'])

                # Show a difference plot if both variables and datasets are the same
                if self.variables[0] == self.compare['variables'][0]:
                    self.transect_data['difference'] = self.transect_data['data'] - \
                                                       self.transect_data['compare_data']
                    # Calculate variable range
                    if self.compare['scale_diff'] is not None:
                        vmin = self.compare['scale_diff'][0]
                        vmax = self.compare['scale_diff'][1]
                    else:
                        vmin, vmax = find_minmax(
                            self.compare['scale_diff'],
                            self.transect_data['difference'])
                        vmin = min(vmin, -vmax)
                        vmax = max(vmax, -vmin)
                    if self.showmap:
                        Col = 1
                    else:
                        Col = 0
                    do_plot(
                        gs,
                        [2, Col],
                        self.transect_data['difference'],
                        self.transect_data['name'] + gettext(" Difference"),
                        self.transect_data['name'],
                        vmin,
                        vmax,
                        self.transect_data[
                            'unit'],  # Since both variables are the same doesn't matter which view we reference
                        colormap.find_colormap(
                            self.compare['colormap_diff']
                        )  # Colormap for difference graphs
                    )

        # Not comparing
        else:
            # Velocity has 3 possible components
            if velocity:
                if self.scale:
                    vmin = self.scale[0]
                    vmax = self.scale[1]
                else:
                    vmin = min(np.amin(self.transect_data['magnitude']),
                               np.amin(self.transect_data['parallel']),
                               np.amin(self.transect_data['perpendicular']))
                    vmax = max(np.amax(self.transect_data['magnitude']),
                               np.amax(self.transect_data['parallel']),
                               np.amin(self.transect_data['perpendicular']))
                    vmin = min(vmin, -vmax)
                    vmax = max(vmax, -vmin)

                Row = 0

                velocity_plot()

            # All other variables have 1 component
            else:
                if self.showmap:
                    Col = 1
                else:
                    Col = 0
                if self.scale:
                    vmin = self.scale[0]
                    vmax = self.scale[1]
                else:
                    vmin, vmax = utils.normalize_scale(
                        self.transect_data['data'],
                        self.dataset_config.variable[self.variables[0]])

                do_plot(
                    gs, [0, Col], self.transect_data['data'],
                    self.transect_data['name'] + " for " +
                    self.date_formatter(self.timestamp),
                    self.transect_data['name'], vmin, vmax,
                    self.transect_data['unit'], self.cmap)

        # Figure title
        if self.plotTitle is None or self.plotTitle == "":
            fig.suptitle("Transect Data for:\n%s" % (self.name), fontsize=15)
        else:
            fig.suptitle(self.plotTitle, fontsize=15)

        # Subplot padding
        fig.tight_layout(pad=2, w_pad=2, h_pad=2)
        fig.subplots_adjust(top=0.90 if self.compare else 0.85)

        return super(TransectPlotter, self).plot(fig)
    def plot(self):
        if self.scale:
            vmin = self.scale[0]
            vmax = self.scale[1]
        else:
            vmin, vmax = utils.normalize_scale(
                self.data, self.dataset_config.variable[self.variables[0]])

        if self.cmap is None:
            self.cmap = colormap.find_colormap(self.variable_name)

        datenum = matplotlib.dates.date2num(self.times)
        if self.depth == 'all':
            size = list(map(float, self.size.split("x")))
            numpoints = len(self.points)
            figuresize = (size[0], size[1] * numpoints)
            fig, ax = plt.subplots(numpoints,
                                   1,
                                   sharex=True,
                                   figsize=figuresize,
                                   dpi=self.dpi)

            if not isinstance(ax, np.ndarray):
                ax = [ax]

            for idx, p in enumerate(self.points):
                d = self.data[idx, 0, :]
                dlim = np.ma.flatnotmasked_edges(d[0, :])
                maxdepth = self.depths[dlim[1]].max()
                mindepth = self.depths[dlim[0]].min()

                c = ax[idx].pcolormesh(datenum,
                                       self.depths[:dlim[1] + 1],
                                       d[:, :dlim[1] + 1].transpose(),
                                       shading='gouraud',
                                       cmap=self.cmap,
                                       vmin=vmin,
                                       vmax=vmax)
                ax[idx].invert_yaxis()
                if maxdepth > LINEAR:
                    ax[idx].set_yscale('symlog', linthreshy=LINEAR)
                ax[idx].yaxis.set_major_formatter(ScalarFormatter())

                if maxdepth > LINEAR:
                    l = 10**np.floor(np.log10(maxdepth))
                    ax[idx].set_ylim(np.ceil(maxdepth / l) * l, mindepth)
                    ax[idx].set_yticks(
                        list(ax[idx].get_yticks()) + [maxdepth, LINEAR])
                else:
                    ax[idx].set_ylim(maxdepth, mindepth)
                ax[idx].set_ylabel("Depth (%s)" %
                                   utils.mathtext(self.depth_unit))

                ax[idx].xaxis_date()
                ax[idx].set_xlim(datenum[0], datenum[-1])

                divider = make_axes_locatable(ax[idx])
                cax = divider.append_axes("right", size="5%", pad=0.05)
                bar = plt.colorbar(c, cax=cax)
                bar.set_label("%s (%s)" % (self.variable_name.title(),
                                           utils.mathtext(self.variable_unit)))
                ax[idx].set_title("%s%s at %s" %
                                  (self.variable_name.title(),
                                   self.depth_label, self.names[idx]))
                plt.setp(ax[idx].get_xticklabels(), rotation=30)
            fig.autofmt_xdate()
        else:
            # Create base figure
            figure_size = self.figuresize
            figure_size[0] *= 1.5 if self.showmap else 1.0
            fig = plt.figure(figsize=figure_size, dpi=self.dpi)

            # Setup figure layout
            width = 1
            if self.showmap:
                width += 1
                # Horizontally scale the actual plots by 2x the size of
                # the location map
                width_ratios = [1, 2]
            else:
                width_ratios = None

            # Create layout helper
            gs = gridspec.GridSpec(1, width, width_ratios=width_ratios)
            subplot = 0

            # Render point location
            if self.showmap:
                plt.subplot(gs[0, 0])
                subplot += 1
                utils.point_plot(
                    np.array([
                        [x[0] for x in self.points],  # Latitudes
                        [x[1] for x in self.points]
                    ]))  # Longitudes

            plt.subplot(gs[:, subplot])
            plt.plot_date(datenum,
                          np.squeeze(self.data),
                          fmt='-',
                          figure=fig,
                          xdate=True)
            plt.ylabel(
                f"{self.variable_name.title()} ({utils.mathtext(self.variable_unit)})",
                fontsize=14)
            plt.ylim(vmin, vmax)

            # Title
            if self.plotTitle is None or self.plotTitle == "":
                wrapped_title = wrap(
                    "%s%s at %s" % (self.variable_name.title(),
                                    self.depth_label, ", ".join(self.names)),
                    80)
                plt.title("\n".join(wrapped_title), fontsize=15)
            else:
                plt.title(self.plotTitle, fontsize=15)

            plt.gca().grid(True)

            fig.autofmt_xdate()

            self.plot_legend(fig, self.names)

        return super(TimeseriesPlotter, self).plot(fig)
Example #6
0
    def plot(self):
        def get_depth_label(depthValue, depthUnit):
            if depthValue == "bottom":
                return " at Bottom"
            return " at %s %s" % (depthValue, depthUnit)

        # Figure size
        figuresize = list(map(float, self.size.split("x")))
        # Vertical scaling of figure
        figuresize[1] *= 1.5 if self.compare else 1

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

        if self.showmap:
            width = 2  # 2 columns
            width_ratios = [2, 7]
        else:
            width = 1  # 1 column
            width_ratios = [1]

        # Setup grid (rows, columns, column/row ratios) depending on view mode
        if self.compare:
            # Don't show a difference plot if variables are different
            if self.compare["variables"][0] == self.variables[0]:
                gs = gridspec.GridSpec(3,
                                       width,
                                       width_ratios=width_ratios,
                                       height_ratios=[1, 1, 1])
            else:
                gs = gridspec.GridSpec(2,
                                       width,
                                       width_ratios=width_ratios,
                                       height_ratios=[1, 1])
        else:
            gs = gridspec.GridSpec(1, width, width_ratios=width_ratios)

        if self.showmap:
            # Plot the path on a map
            utils.path_plot(self.path_points, gs[:, 0])

        # Calculate variable range
        if self.scale:
            vmin = self.scale[0]
            vmax = self.scale[1]
        else:
            vmin, vmax = utils.normalize_scale(
                self.data, self.dataset_config.variable[self.variables[0]])

            if len(self.variables) > 1:
                vmin = 0

        # Render
        self._hovmoller_plot(
            gs,
            [0, 1],
            [0, 0],
            gettext(self.variable_name),
            vmin,
            vmax,
            self.data,
            self.iso_timestamps,
            self.cmap,
            self.variable_unit,
            gettext(self.variable_name) +
            gettext(get_depth_label(self.depth_value, self.depth_unit)),
        )

        # If in compare mode
        if self.compare:
            # Calculate variable range
            if self.compare["scale"]:
                vmin = self.compare["scale"][0]
                vmax = self.compare["scale"][1]
            else:
                vmin = np.amin(self.compare["data"])
                vmax = np.amax(self.compare["data"])
            if np.any([
                    re.search(x, self.compare["variable_name"], re.IGNORECASE)
                    for x in ["velocity", "surface height", "wind"]
            ]):
                vmin = min(vmin, -vmax)
                vmax = max(vmax, -vmin)

            if len(self.compare["variables"]) > 1:
                vmin = 0

            self._hovmoller_plot(
                gs,
                [1, 1],
                [1, 0],
                gettext(self.compare["variable_name"]),
                vmin,
                vmax,
                self.compare["data"],
                self.compare["times"],
                self.compare["colormap"],
                self.compare["variable_unit"],
                gettext(self.compare["variable_name"]) + gettext(
                    get_depth_label(self.compare["depth"],
                                    self.compare["depth_unit"])),
            )

            # Difference plot
            if self.compare["variables"][0] == self.variables[0]:

                data_difference = self.data - self.compare["data"]
                vmin = np.amin(data_difference)
                vmax = np.amax(data_difference)

                self._hovmoller_plot(
                    gs,
                    [2, 1],
                    [2, 0],
                    gettext(self.compare["variable_name"]),
                    vmin,
                    vmax,
                    data_difference,
                    self.compare["times"],
                    colormap.find_colormap("anomaly"),
                    self.compare["variable_unit"],
                    gettext(self.compare["variable_name"]) +
                    gettext(" Difference") + gettext(
                        get_depth_label(self.compare["depth"],
                                        self.compare["depth_unit"])),
                )

        # Image title
        if self.plotTitle:
            fig.suptitle(gettext("Hovm\xf6ller Diagram(s) for:\n%s") %
                         (self.name),
                         fontsize=15)
        else:
            fig.suptitle(self.plotTitle, fontsize=15)
        # Subplot padding
        fig.tight_layout(pad=0, w_pad=4, h_pad=2)
        fig.subplots_adjust(top=0.9 if self.compare else 0.85)

        return super(HovmollerPlotter, self).plot(fig)
    def plot(self):

        if self.filetype == "geotiff":
            f, fname = tempfile.mkstemp()
            os.close(f)

            driver = gdal.GetDriverByName("GTiff")
            outRaster = driver.Create(
                fname,
                self.latitude.shape[1],
                self.longitude.shape[0],
                1,
                gdal.GDT_Float64,
            )
            x = np.array([self.longitude[0, 0], self.longitude[-1, -1]])
            y = np.array([self.latitude[0, 0], self.latitude[-1, -1]])
            outRasterSRS = osr.SpatialReference()

            pts = self.plot_projection.transform_points(
                self.pc_projection, x, y)
            x = pts[:, 0]
            y = pts[:, 1]
            outRasterSRS.ImportFromProj4(self.plot_projection.proj4_init)

            pixelWidth = (x[-1] - x[0]) / self.longitude.shape[0]
            pixelHeight = (y[-1] - y[0]) / self.latitude.shape[0]
            outRaster.SetGeoTransform(
                (x[0], pixelWidth, 0, y[0], 0, pixelHeight))

            outband = outRaster.GetRasterBand(1)
            d = self.data.astype(np.float64)
            ndv = d.fill_value
            outband.WriteArray(d.filled(ndv))
            outband.SetNoDataValue(ndv)
            outRaster.SetProjection(outRasterSRS.ExportToWkt())
            outband.FlushCache()
            outRaster = None

            with open(fname, "r", encoding="latin-1") as f:
                buf = f.read()
            os.remove(fname)

            return (buf, self.mime, self.filename.replace(".geotiff", ".tif"))
        # Figure size
        figuresize = list(map(float, self.size.split("x")))
        fig, map_plot = basemap.load_map(
            self.plot_projection,
            self.plot_extent,
            figuresize,
            self.dpi,
            self.plot_res,
        )

        ax = plt.gca()

        if self.scale:
            vmin = self.scale[0]
            vmax = self.scale[1]
        else:
            vmin, vmax = utils.normalize_scale(
                self.data,
                self.dataset_config.variable[f"{self.variables[0]}"])

        c = map_plot.imshow(
            self.data,
            vmin=vmin,
            vmax=vmax,
            cmap=self.cmap,
            extent=self.plot_extent,
            transform=self.plot_projection,
            origin="lower",
            zorder=0,
        )

        if len(self.quiver_data) == 2:
            qx, qy = self.quiver_data
            qx, qy = self.plot_projection.transform_vectors(
                self.pc_projection, self.quiver_longitude,
                self.quiver_latitude, qx, qy)
            pts = self.plot_projection.transform_points(
                self.pc_projection, self.quiver_longitude,
                self.quiver_latitude)
            x = pts[:, :, 0]
            y = pts[:, :, 1]

            qx = np.ma.masked_where(np.ma.getmask(self.quiver_data[0]), qx)
            qy = np.ma.masked_where(np.ma.getmask(self.quiver_data[1]), qy)

            if self.quiver["magnitude"] != "length":
                qx = qx / self.quiver_magnitude
                qy = qy / self.quiver_magnitude
                qscale = 50
            else:
                qscale = None

            if self.quiver["magnitude"] == "color":
                if (self.quiver["colormap"] is None
                        or self.quiver["colormap"] == "default"):
                    qcmap = colormap.colormaps.get("speed")
                else:
                    qcmap = colormap.colormaps.get(self.quiver["colormap"])
                q = map_plot.quiver(
                    x,
                    y,
                    qx,
                    qy,
                    self.quiver_magnitude,
                    width=0.0035,
                    headaxislength=4,
                    headlength=4,
                    scale=qscale,
                    pivot="mid",
                    cmap=qcmap,
                    transform=self.plot_projection,
                )
            else:
                q = map_plot.quiver(
                    x,
                    y,
                    qx,
                    qy,
                    width=0.0025,
                    headaxislength=4,
                    headlength=4,
                    scale=qscale,
                    pivot="mid",
                    transform=self.plot_projection,
                    zorder=6,
                )

            if self.quiver["magnitude"] == "length":
                unit_length = np.mean(self.quiver_magnitude) * 2
                unit_length = np.round(unit_length,
                                       -int(np.floor(np.log10(unit_length))))
                if unit_length >= 1:
                    unit_length = int(unit_length)

                plt.quiverkey(
                    q,
                    0.65,
                    0.01,
                    unit_length,
                    self.quiver_name.title() + " " + str(unit_length) + " " +
                    utils.mathtext(self.quiver_unit),
                    coordinates="figure",
                    labelpos="E",
                )

        if self.show_bathymetry:
            # Plot bathymetry on top
            cs = map_plot.contour(
                self.longitude,
                self.latitude,
                self.bathymetry,
                linewidths=0.5,
                norm=FuncNorm((lambda x: np.log10(x), lambda x: 10**x),
                              vmin=1,
                              vmax=6000),
                cmap="Greys",
                levels=[100, 200, 500, 1000, 2000, 3000, 4000, 5000, 6000],
                transform=self.pc_projection,
                zorder=4,
            )
            plt.clabel(cs, fontsize="x-large", fmt="%1.0fm")

        if self.area and self.show_area:
            for a in self.area:
                polys = []
                for co in a["polygons"] + a["innerrings"]:
                    coords = np.array(co).transpose()
                    coords_transform = self.plot_projection.transform_points(
                        self.pc_projection, coords[1], coords[0])
                    mx = coords_transform[:, 0]
                    my = coords_transform[:, 1]
                    map_coords = list(zip(mx, my))
                    polys.append(Polygon(map_coords))

                paths = []
                for poly in polys:
                    paths.append(poly.get_path())
                path = Path.make_compound_path(*paths)

                for ec, lw in zip(["w", "k"], [5, 3]):
                    poly = PathPatch(
                        path,
                        fill=None,
                        edgecolor=ec,
                        linewidth=lw,
                        transform=self.plot_projection,
                        zorder=3,
                    )
                    map_plot.add_patch(poly)

            if self.names is not None and len(self.names) > 1:
                for idx, name in enumerate(self.names):
                    pts = self.plot_projection.transform_points(
                        self.pc_projection, self.centroids[idx].x,
                        self.centroids[idx].y)
                    x = pts[:, 0]
                    y = pts[:, 1]
                    plt.annotate(
                        xy=(x, y),
                        s=name,
                        ha="center",
                        va="center",
                        size=12,
                        # weight='bold'
                    )

        if len(self.contour_data) > 0:
            if self.contour_data[0].min() != self.contour_data[0].max():
                cmin, cmax = utils.normalize_scale(
                    self.contour_data[0],
                    self.dataset_config.variable[self.contour["variable"]],
                )
                levels = None
                if (self.contour.get("levels") is not None
                        and self.contour["levels"] != "auto"
                        and self.contour["levels"] != ""):
                    try:
                        levels = list(
                            set([
                                float(xx)
                                for xx in self.contour["levels"].split(",")
                                if xx.strip()
                            ]))
                        levels.sort()
                    except ValueError:
                        pass

                if levels is None:
                    levels = np.linspace(cmin, cmax, 5)
                cmap = self.contour["colormap"]
                if cmap is not None:
                    cmap = colormap.colormaps.get(cmap)
                    if cmap is None:
                        cmap = colormap.find_colormap(self.contour_name)

                if not self.contour.get("hatch"):
                    contours = map_plot.contour(
                        self.longitude,
                        self.latitude,
                        self.contour_data[0],
                        linewidths=2,
                        levels=levels,
                        cmap=cmap,
                        transform=self.pc_projection,
                        zorder=5,
                    )
                else:
                    hatches = [
                        "//", "xx", "\\\\", "--", "||", "..", "oo", "**"
                    ]
                    if len(levels) + 1 < len(hatches):
                        hatches = hatches[0:len(levels) + 2]
                    map_plot.contour(
                        self.longitude,
                        self.latitude,
                        self.contour_data[0],
                        linewidths=1,
                        levels=levels,
                        colors="k",
                        transform=self.pc_projection,
                        zorder=5,
                    )
                    contours = map_plot.contourf(
                        self.longitude,
                        self.latitude,
                        self.contour_data[0],
                        colors=["none"],
                        levels=levels,
                        hatches=hatches,
                        vmin=cmin,
                        vmax=cmax,
                        extend="both",
                        transform=self.pc_projection,
                        zorder=5,
                    )

                if self.contour["legend"]:
                    handles, l = contours.legend_elements()
                    labels = []
                    for i, lab in enumerate(l):
                        if self.contour.get("hatch"):
                            if self.contour_unit == "fraction":
                                if i == 0:
                                    labels.append(
                                        "$x \\leq {0: .0f}\\%$".format(
                                            levels[i] * 100))
                                elif i == len(levels):
                                    labels.append("$x > {0: .0f}\\%$".format(
                                        levels[i - 1] * 100))
                                else:
                                    labels.append(
                                        "${0:.0f}\\% < x \\leq {1:.0f}\\%$".
                                        format(levels[i - 1] * 100,
                                               levels[i] * 100))
                            else:
                                if i == 0:
                                    labels.append("$x \\leq %.3g$" % levels[i])
                                elif i == len(levels):
                                    labels.append("$x > %.3g$" % levels[i - 1])
                                else:
                                    labels.append("$%.3g < x \\leq %.3g$" %
                                                  (levels[i - 1], levels[i]))
                        else:
                            if self.contour_unit == "fraction":
                                labels.append("{0:.0%}".format(levels[i]))
                            else:
                                labels.append(
                                    "%.3g %s" %
                                    (levels[i],
                                     utils.mathtext(self.contour_unit)))

                    ax = plt.gca()

                    if self.contour_unit != "fraction" and not self.contour.get(
                            "hatch"):
                        contour_title = "%s (%s)" % (
                            self.contour_name,
                            utils.mathtext(self.contour_unit),
                        )
                    else:
                        contour_title = self.contour_name

                    leg = ax.legend(
                        handles[::-1],
                        labels[::-1],
                        loc="lower left",
                        fontsize="medium",
                        frameon=True,
                        framealpha=0.75,
                        title=contour_title,
                    )
                    leg.get_title().set_fontsize("medium")
                    if not self.contour.get("hatch"):
                        for legobj in leg.legendHandles:
                            legobj.set_linewidth(3)

        title = self.plotTitle

        if self.plotTitle is None or self.plotTitle == "":
            area_title = "\n".join(wrap(", ".join(self.names), 60)) + "\n"

            title = "%s %s %s, %s" % (
                area_title,
                self.variable_name.title(),
                self.depth_label,
                self.date_formatter(self.timestamp),
            )
        plt.title(title.strip())
        axpos = map_plot.get_position()
        pos_x = axpos.x0 + axpos.width + 0.01
        pos_y = axpos.y0
        cax = fig.add_axes([pos_x, pos_y, 0.03, axpos.height])
        bar = plt.colorbar(c, cax=cax)
        bar.set_label(
            "%s (%s)" %
            (self.variable_name.title(), utils.mathtext(self.variable_unit)),
            fontsize=14,
        )

        if (self.quiver is not None and self.quiver["variable"] != ""
                and self.quiver["variable"] != "none"
                and self.quiver["magnitude"] == "color"):
            pos_x = axpos.x0
            pos_y = axpos.y0 - 0.05
            bax = fig.add_axes([pos_x, pos_y, axpos.width, 0.03])
            qbar = plt.colorbar(q, orientation="horizontal", cax=bax)
            qbar.set_label(
                self.quiver_name.title() + " " +
                utils.mathtext(self.quiver_unit),
                fontsize=14,
            )

        return super(MapPlotter, self).plot(fig)
Example #8
0
    def plot(self):
        if self.filetype == 'geotiff':
            f, fname = tempfile.mkstemp()
            os.close(f)

            driver = gdal.GetDriverByName('GTiff')
            outRaster = driver.Create(fname, self.latitude.shape[1],
                                      self.longitude.shape[0], 1,
                                      gdal.GDT_Float64)
            x = [self.longitude[0, 0], self.longitude[-1, -1]]
            y = [self.latitude[0, 0], self.latitude[-1, -1]]
            outRasterSRS = osr.SpatialReference()

            x, y = self.basemap(x, y)
            outRasterSRS.ImportFromProj4(self.basemap.proj4string)

            pixelWidth = (x[-1] - x[0]) / self.longitude.shape[0]
            pixelHeight = (y[-1] - y[0]) / self.latitude.shape[0]
            outRaster.SetGeoTransform(
                (x[0], pixelWidth, 0, y[0], 0, pixelHeight))

            outband = outRaster.GetRasterBand(1)
            d = self.data.astype("Float64")
            ndv = d.fill_value
            outband.WriteArray(d.filled(ndv))
            outband.SetNoDataValue(ndv)
            outRaster.SetProjection(outRasterSRS.ExportToWkt())
            outband.FlushCache()
            outRaster = None

            with open(fname, 'r', encoding="latin-1") as f:
                buf = f.read()
            os.remove(fname)

            return (buf, self.mime, self.filename.replace(".geotiff", ".tif"))
        # Figure size
        figuresize = list(map(float, self.size.split("x")))
        fig = plt.figure(figsize=figuresize, dpi=self.dpi)
        ax = plt.gca()

        if self.scale:
            vmin = self.scale[0]
            vmax = self.scale[1]
        else:
            vmin = np.amin(self.data)
            vmax = np.amax(self.data)
            if self.compare:
                vmax = max(abs(vmax), abs(vmin))
                vmin = -vmax

        c = self.basemap.imshow(self.data,
                                vmin=vmin,
                                vmax=vmax,
                                cmap=self.cmap)

        if len(self.quiver_data) == 2:
            qx, qy = self.quiver_data
            qx, qy, x, y = self.basemap.rotate_vector(qx,
                                                      qy,
                                                      self.quiver_longitude,
                                                      self.quiver_latitude,
                                                      returnxy=True)
            quiver_mag = np.sqrt(qx**2 + qy**2)

            if self.quiver['magnitude'] != 'length':
                qx = qx / quiver_mag
                qy = qy / quiver_mag
                qscale = 50
            else:
                qscale = None

            if self.quiver['magnitude'] == 'color':
                if self.quiver['colormap'] is None or \
                   self.quiver['colormap'] == 'default':
                    qcmap = colormap.colormaps.get('speed')
                else:
                    qcmap = colormap.colormaps.get(self.quiver['colormap'])
                q = self.basemap.quiver(
                    x,
                    y,
                    qx,
                    qy,
                    quiver_mag,
                    width=0.0035,
                    headaxislength=4,
                    headlength=4,
                    scale=qscale,
                    pivot='mid',
                    cmap=qcmap,
                )
            else:
                q = self.basemap.quiver(
                    x,
                    y,
                    qx,
                    qy,
                    width=0.0025,
                    headaxislength=4,
                    headlength=4,
                    scale=qscale,
                    pivot='mid',
                )

            if self.quiver['magnitude'] == 'length':
                unit_length = np.mean(quiver_mag) * 2
                unit_length = np.round(unit_length,
                                       -int(np.floor(np.log10(unit_length))))
                if unit_length >= 1:
                    unit_length = int(unit_length)

                plt.quiverkey(q,
                              .65,
                              .01,
                              unit_length,
                              self.quiver_name.title() + " " +
                              str(unit_length) + " " +
                              utils.mathtext(self.quiver_unit),
                              coordinates='figure',
                              labelpos='E')

        if self.show_bathymetry:
            # Plot bathymetry on top
            cs = self.basemap.contour(
                self.longitude,
                self.latitude,
                self.bathymetry,
                latlon=True,
                linewidths=0.5,
                norm=LogNorm(vmin=1, vmax=6000),
                cmap=mcolors.LinearSegmentedColormap.from_list(
                    'transparent_gray', [(0, 0, 0, 0.5), (0, 0, 0, 0.1)]),
                levels=[100, 200, 500, 1000, 2000, 3000, 4000, 5000, 6000])
            plt.clabel(cs, fontsize='xx-small', fmt='%1.0fm')

        if self.area and self.show_area:
            for a in self.area:
                polys = []
                for co in a['polygons'] + a['innerrings']:
                    coords = np.array(co).transpose()
                    mx, my = self.basemap(coords[1], coords[0])
                    map_coords = list(zip(mx, my))
                    polys.append(Polygon(map_coords))

                paths = []
                for poly in polys:
                    paths.append(poly.get_path())
                path = concatenate_paths(paths)

                poly = PathPatch(path,
                                 fill=None,
                                 edgecolor='#ffffff',
                                 linewidth=5)
                plt.gca().add_patch(poly)
                poly = PathPatch(path, fill=None, edgecolor='k', linewidth=2)
                plt.gca().add_patch(poly)

            if self.names is not None and len(self.names) > 1:
                for idx, name in enumerate(self.names):
                    x, y = self.basemap(self.centroids[idx].y,
                                        self.centroids[idx].x)
                    plt.annotate(
                        xy=(x, y),
                        s=name,
                        ha='center',
                        va='center',
                        size=12,
                        # weight='bold'
                    )

        if len(self.contour_data) > 0:
            if (self.contour_data[0].min() != self.contour_data[0].max()):
                cmin, cmax = utils.normalize_scale(self.contour_data[0],
                                                   self.contour_name,
                                                   self.contour_unit)
                levels = None
                if self.contour.get('levels') is not None and \
                    self.contour['levels'] != 'auto' and \
                        self.contour['levels'] != '':
                    try:
                        levels = list(
                            set([
                                float(xx)
                                for xx in self.contour['levels'].split(",")
                                if xx.strip()
                            ]))
                        levels.sort()
                    except ValueError:
                        pass

                if levels is None:
                    levels = np.linspace(cmin, cmax, 5)
                cmap = self.contour['colormap']
                if cmap is not None:
                    cmap = colormap.colormaps.get(cmap)
                    if cmap is None:
                        cmap = colormap.find_colormap(self.contour_name)

                if not self.contour.get('hatch'):
                    contours = self.basemap.contour(self.longitude,
                                                    self.latitude,
                                                    self.contour_data[0],
                                                    latlon=True,
                                                    linewidths=2,
                                                    levels=levels,
                                                    cmap=cmap)
                else:
                    hatches = [
                        '//', 'xx', '\\\\', '--', '||', '..', 'oo', '**'
                    ]
                    if len(levels) + 1 < len(hatches):
                        hatches = hatches[0:len(levels) + 2]
                    self.basemap.contour(self.longitude,
                                         self.latitude,
                                         self.contour_data[0],
                                         latlon=True,
                                         linewidths=1,
                                         levels=levels,
                                         colors='k')
                    contours = self.basemap.contourf(self.longitude,
                                                     self.latitude,
                                                     self.contour_data[0],
                                                     latlon=True,
                                                     colors=['none'],
                                                     levels=levels,
                                                     hatches=hatches,
                                                     vmin=cmin,
                                                     vmax=cmax,
                                                     extend='both')

                if self.contour['legend']:
                    handles, l = contours.legend_elements()
                    labels = []
                    for i, lab in enumerate(l):
                        if self.contour.get('hatch'):
                            if self.contour_unit == 'fraction':
                                if i == 0:
                                    labels.append(
                                        "$x \\leq {0: .0f}\\%$".format(
                                            levels[i] * 100))
                                elif i == len(levels):
                                    labels.append("$x > {0: .0f}\\%$".format(
                                        levels[i - 1] * 100))
                                else:
                                    labels.append(
                                        "${0:.0f}\\% < x \\leq {1:.0f}\\%$".
                                        format(levels[i - 1] * 100,
                                               levels[i] * 100))
                            else:
                                if i == 0:
                                    labels.append("$x \\leq %.3g$" % levels[i])
                                elif i == len(levels):
                                    labels.append("$x > %.3g$" % levels[i - 1])
                                else:
                                    labels.append("$%.3g < x \\leq %.3g$" %
                                                  (levels[i - 1], levels[i]))
                        else:
                            if self.contour_unit == 'fraction':
                                labels.append("{0:.0%}".format(levels[i]))
                            else:
                                labels.append(
                                    "%.3g %s" %
                                    (levels[i],
                                     utils.mathtext(self.contour_unit)))

                    ax = plt.gca()

                    if self.contour_unit != 'fraction' and not \
                            self.contour.get('hatch'):
                        contour_title = "%s (%s)" % (self.contour_name,
                                                     utils.mathtext(
                                                         self.contour_unit))
                    else:
                        contour_title = self.contour_name

                    leg = ax.legend(handles[::-1],
                                    labels[::-1],
                                    loc='lower left',
                                    fontsize='medium',
                                    frameon=True,
                                    framealpha=0.75,
                                    title=contour_title)
                    leg.get_title().set_fontsize('medium')
                    if not self.contour.get('hatch'):
                        for legobj in leg.legendHandles:
                            legobj.set_linewidth(3)

        # Map Info
        self.basemap.drawmapboundary(fill_color=(0.3, 0.3, 0.3), zorder=-1)
        self.basemap.drawcoastlines(linewidth=0.5)
        self.basemap.fillcontinents(color='grey', lake_color='dimgrey')

        def find_lines(values):
            if np.amax(values) - np.amin(values) < 1:
                return [values.mean()]
            elif np.amax(values) - np.amin(values) < 25:
                return np.round(
                    np.arange(np.amin(values), np.amax(values),
                              round(np.amax(values) - np.amin(values)) / 5))
            else:
                return np.arange(round(np.amin(values), -1),
                                 round(np.amax(values), -1), 5)

        parallels = find_lines(self.latitude)
        meridians = find_lines(self.longitude)
        self.basemap.drawparallels(parallels,
                                   labels=[1, 0, 0, 0],
                                   color=(0, 0, 0, 0.5))
        self.basemap.drawmeridians(meridians,
                                   labels=[0, 0, 0, 1],
                                   color=(0, 0, 0, 0.5),
                                   latmax=85)

        title = self.plotTitle

        if self.plotTitle is None or self.plotTitle == "":
            area_title = "\n".join(wrap(", ".join(self.names), 60)) + "\n"

            title = "%s %s %s, %s" % (area_title, self.variable_name.title(),
                                      self.depth_label,
                                      self.date_formatter(self.timestamp))
        plt.title(title.strip())
        ax = plt.gca()
        divider = make_axes_locatable(ax)
        cax = divider.append_axes("right", size="5%", pad=0.05)
        bar = plt.colorbar(c, cax=cax)
        bar.set_label(
            "%s (%s)" %
            (self.variable_name.title(), utils.mathtext(self.variable_unit)),
            fontsize=14)

        if self.quiver is not None and \
            self.quiver['variable'] != '' and \
            self.quiver['variable'] != 'none' and \
                self.quiver['magnitude'] == 'color':
            bax = divider.append_axes("bottom", size="5%", pad=0.35)
            qbar = plt.colorbar(q, orientation='horizontal', cax=bax)
            qbar.set_label(self.quiver_name.title() + " " +
                           utils.mathtext(self.quiver_unit),
                           fontsize=14)

        fig.tight_layout(pad=3, w_pad=4)

        return super(MapPlotter, self).plot(fig)