Example #1
0
def process_s(s):

    s.values[s.values == 0] = np.nan
    s.values[np.logical_or(np.isinf(s.values), np.isnan(s.values))] = np.nan
    s, had_outlier = _setnull_s_outliers(s)
    while had_outlier:
        s, had_outlier = _setnull_s_outliers(s)

    has_null = s.isnull().any()

    if has_null:

        try:

            r, c = np.nonzero(np.isfinite(s.values))
            y = s.lat[r].values
            x = s.lon[c].values
            points = (x, y)
            values = s.values[r, c]
            grid_x, grid_y = np.meshgrid(s.lon.values, s.lat.values)

            try:
                sgrid = griddata(points,
                                 values, (grid_x, grid_y),
                                 method='cubic')
            except QhullError:
                sgrid = np.zeros(s.shape)

            try:
                sgrid_l = griddata(points,
                                   values, (grid_x, grid_y),
                                   method='linear')
            except QhullError:
                sgrid_l = np.empty(s.shape)
                sgrid_l.fill(np.nan)

            sgrid_n = griddata(points,
                               values, (grid_x, grid_y),
                               method='nearest')

            mask_zero = sgrid <= 0
            sgrid[mask_zero] = sgrid_l[mask_zero]

            mask_nan = np.isnan(sgrid)
            sgrid[mask_nan] = sgrid_n[mask_nan]

            s = xr.DataArray(sgrid, coords=[s.lat, s.lon])

        except ValueError as e:

            if e.args[0] == 'No points given':
                # No valid scaler factors
                s.values[:] = 1
            else:
                raise

    return s
Example #2
0
def inv_dense_corres(dense_corres_a2b, pre_cache_x2d=None):

    H, W = dense_corres_a2b.shape[:2]
    if pre_cache_x2d is None:
        x_a = x_2d_coords(H, W).reshape((H, W, 2))
    else:
        x_a = pre_cache_x2d.reshape((H, W, 2))

    dense_corres_b2a = griddata(dense_corres_a2b.reshape((H * W, 2)),
                                x_a.reshape((H * W, 2)),
                                x_a.reshape((H * W, 2)),
                                method='linear',
                                fill_value=-1)
    return dense_corres_b2a.reshape((H, W, 2))
    def _extract_h5(self, dm):
        #         cells = []
        tab = dm.get_table('power_map', '/')
        metadata = dict()
        try:
            b = tab._v_attrs['bounds']
        except Exception as e:
            print('exception', e)
            b = 1

        metadata['bounds'] = -float(b), float(b)

        try:
            bd = tab._v_attrs['beam_diameter']
        except Exception as e:
            print('exception', e)
            bd = 0

        try:
            po = tab._v_attrs['power']
        except Exception as e:
            print('exception', e)
            po = 0

        metadata['beam_diameter'] = bd
        metadata['power'] = po

        xs, ys, power = array([(r['x'], r['y'], r['power'])
                               for r in tab.iterrows()]).T

        #        xs, ys, power = array(xs), array(ys), array(power)
        #        n = power.shape[0]
        #        print n
        xi = linspace(min(xs), max(xs), 50)
        yi = linspace(min(ys), max(ys), 50)

        X = xi[None, :]
        Y = yi[:, None]

        power = griddata(
            (xs, ys),
            power,
            (X, Y),
            fill_value=0,
            #                          method='cubic'
        )
        return rot90(power, k=2), metadata
Example #4
0
    def _extract_h5(self, dm):
        #         cells = []
        tab = dm.get_table('power_map', '/')
        metadata = dict()
        try:
            b = tab._v_attrs['bounds']
        except Exception as e:
            print('exception', e)
            b = 1

        metadata['bounds'] = -float(b), float(b)

        try:
            bd = tab._v_attrs['beam_diameter']
        except Exception as e:
            print('exception', e)
            bd = 0

        try:
            po = tab._v_attrs['power']
        except Exception as e:
            print('exception', e)
            po = 0

        metadata['beam_diameter'] = bd
        metadata['power'] = po

        xs, ys, power = array([(r['x'], r['y'], r['power'])
                               for r in tab.iterrows()]).T

        #        xs, ys, power = array(xs), array(ys), array(power)
        #        n = power.shape[0]
        #        print n
        xi = linspace(min(xs), max(xs), 50)
        yi = linspace(min(ys), max(ys), 50)

        X = xi[None, :]
        Y = yi[:, None]

        power = griddata((xs, ys), power, (X, Y),
                         fill_value=0,
                         #                          method='cubic'
                         )
        return rot90(power, k=2), metadata
Example #5
0
    def _add_data(self, data):

        #        def _refresh_data(v):
        tab, x, y, col, row, mag, sid = data

        #        self.debug('{} {} {} {} {}'.format(*v[1:]))
        self._write_datum(tab, x, y, col, row, mag)
        self.graph.add_datum((x, mag), series=sid)

        self._xs = hstack((self._xs, x))
        self._ys = hstack((self._ys, y))
        self._zs = hstack((self._zs, mag))

        #         xl, xh = self._bounds[:2]
        #         yl, yh = self._bounds[2:]

        if col % 10 == 0 and row:
            cg = self.contour_graph
            xx = self._xs
            yy = self._ys
            z = self._zs

            #             print 'xx-----', xx
            #             print 'yy-----', yy
            zd = griddata(
                (xx, yy),
                z,
                self.area,
                #                        method='cubic',
                fill_value=0)

            zd = rot90(zd, k=2)
            #             zd = zd.T
            #             print zd
            if not cg.plots[0].plots.keys():
                cg.new_series(
                    z=zd,
                    xbounds=(-self._padding, self._padding),
                    ybounds=(-self._padding, self._padding),
                    #                              xbounds=(xl, xh),
                    #                              ybounds=(yl, yh),
                    style='contour')
            else:
                cg.plots[0].data.set_data('z0', zd)
Example #6
0
    def _add_data(self, data):


#        def _refresh_data(v):
        tab, x, y, col, row, mag, sid = data

#        self.debug('{} {} {} {} {}'.format(*v[1:]))
        self._write_datum(tab, x, y, col, row, mag)
        self.graph.add_datum((x, mag), series=sid)

        self._xs = hstack((self._xs, x))
        self._ys = hstack((self._ys, y))
        self._zs = hstack((self._zs, mag))

#         xl, xh = self._bounds[:2]
#         yl, yh = self._bounds[2:]

        if col % 10 == 0 and row:
            cg = self.contour_graph
            xx = self._xs
            yy = self._ys
            z = self._zs

#             print 'xx-----', xx
#             print 'yy-----', yy
            zd = griddata((xx, yy), z, self.area,
#                        method='cubic',
                        fill_value=0)

            zd = rot90(zd, k=2)
#             zd = zd.T
#             print zd
            if not cg.plots[0].plots.keys():
                cg.new_series(z=zd,
                              xbounds=(-self._padding, self._padding),
                              ybounds=(-self._padding, self._padding),
#                              xbounds=(xl, xh),
#                              ybounds=(yl, yh),
                              style='contour')
            else:
                cg.plots[0].data.set_data('z0', zd)
Example #7
0
    def min(self, source_depths, receiver_depths, distances, method='linear'):
        '''
        Returns the minimum (minima) travel time(s) for the point(s) identified by
        (source_depths, receiver_depths, distances) by building a grid and
        interpolating on the points identified by each
        ```
            P[i] = (source_depths[i], receiver_depths[i], distances[i])
        ```
        if the source file has been built with
        receiver depths == [0]. It uses a 2d linear interpolation on a grid. It uses
        scipy griddata
        :param source_depths: numeric or numpy array of length n: the source depth(s), in km
        :param receiver_depths: numeric or numpy array of length n: the receiver depth(s), in km.
        For most applications, this value can be set to zero
        :param distances: numeric or numpy array of length n: the distance(s), in degrees
        :param method: forwarded to `scipy.griddata` function
        :return: a numpy array of length n denoting the minimum travel time(s) of this model for
        each P
        '''
        # Handle the case some arguments are scalars and some arrays:
        source_depths, receiver_depths, distances = \
            np.broadcast_arrays(source_depths, receiver_depths, distances)
        # handle the case all arguments scalars. See
        # https://stackoverflow.com/questions/29318459/python-function-that-handles-scalar-or-arrays
        allscalars = all(_.ndim == 0
                         for _ in (source_depths, receiver_depths, distances))
        if source_depths.ndim == 0:
            source_depths = source_depths[None]  # Makes x 1D
        if receiver_depths.ndim == 0:
            receiver_depths = receiver_depths[None]  # Makes x 1D
        if distances.ndim == 0:
            distances = distances[None]  # Makes x 1D
        # correct source depths and receiver depths
        source_depths[source_depths < 0] = 0
        receiver_depths[receiver_depths < 0] = 0
        # correct distances to be compatible with obpsy traveltimes calculations:
        distances = distances % 360
        # set values symmetric to 180 degrees if greater than 180:
        _mask = distances > 180
        if _mask.any(
        ):  # does this speeds up (allocate mask array once)? FIXME: check
            distances[_mask] = 360 - distances[_mask]
        # set source depths to nan if out of bounds. This prevent method = 'nearest'
        # to return non nan values and be consistent with 'linear' and 'cubic'
        if self._unique_receiver_depth:
            # get values without receiver depth dimension:
            values = np.hstack((self._km2deg(source_depths).reshape(-1, 1),
                                distances.reshape(-1, 1)))
        else:
            values = np.hstack((self._km2deg(source_depths).reshape(-1, 1),
                                self._km2deg(receiver_depths).reshape(-1, 1),
                                distances.reshape(-1, 1)))

        ret = griddata(self._gridpts,
                       self._gridvals,
                       values,
                       method=method,
                       rescale=False,
                       fill_value=np.nan)

        # ret is almost likely a float, so we can set now nans for out of boun values
        # we cannot do it before on any input array cause int arrays do not support nan assignement
        ret[(source_depths > self._sourcedepth_bounds_km[1]) |
            (receiver_depths > self._receiverdepth_bounds_km[1])] = np.nan
        # return scalar if inputs are scalar, array oitherwise
        return np.squeeze(ret) if allscalars else ret
Example #8
0
# imports
import nmafeat
from prody import *
import numpy as np
# %%
nmafeat.computeNMDfile()
(coords, modes) = nmafeat.extractModesCoords()
print(f"Values range from {coords.min()} to {coords.max()}")
# %%
dmin = coords.min() - 2
dmax = coords.max() + 2
a = np.mgrid[dmin:dmax:101j,dmin:dmax:101j,dmin:dmax:101j]
a = a.reshape(3,1030301).transpose()
# %%
import scipy.interpolate.ndgriddata as ndgriddata
mode1_interp = ndgriddata.griddata(coords, modes[0], a)     # interpolate the data onto the grid
# %%
# Eureka! Maybe it worked!: 
# is not nan
mode1_interp[~np.isnan(mode1_interp)].size
# %%
# is nan
mode1_interp[np.isnan(mode1_interp)].size
# %%
δ = np.gradient(mode1_interp)
# %%
δ[0][~np.isnan(δ[0])].size
# %%
m1i_orig = mode1_interp.reshape(3,101,101,101)
# %%
m1i_grad = np.gradient(m1i_orig)
        metadata['power'] = po

        xs, ys, power = array([(r['x'], r['y'], r['power'])
                               for r in tab.iterrows()]).T

        #        xs, ys, power = array(xs), array(ys), array(power)
        #        n = power.shape[0]
        #        print n
        xi = linspace(min(xs), max(xs), 50)
        yi = linspace(min(ys), max(ys), 50)

        X = xi[None, :]
        Y = yi[:, None]

        power = griddata((xs, ys), power, (X, Y),
                         fill_value=0,
                         #                          method='cubic'
        )
        return rot90(power, k=2), metadata

    #        return flipud(fliplr(power)), metadata
    #        for row in tab.iterrows():
    #            x = int(row['col'])
    #            try:
    #                nr = cells[x]
    #            except IndexError:
    #                cells.append([])
    #                nr = cells[x]
    #
    #            # baseline = self._calc_baseline(table, index) if self.correct_baseline else 0.0
    #            baseline = 0
    #            pwr = row['power']
Example #10
0
def scale_anoms(s, obs_anoms):

    vals_d = obs_anoms.copy()
    mask_wet = vals_d.values > 0
    vals_d.values[mask_wet] = vals_d.values[mask_wet] + s.values[mask_wet]
    mask_wet_invalid = np.logical_and(mask_wet, vals_d.values <= 0)

    has_invalid = mask_wet_invalid.any()

    try:

        if has_invalid:

            s.values[np.logical_or(mask_wet_invalid, ~mask_wet)] = np.nan

            r, c = np.nonzero(np.isfinite(s.values))
            y = s.lat[r].values
            x = s.lon[c].values
            points = (x, y)
            values = s.values[r, c]
            grid_x, grid_y = np.meshgrid(s.lon.values, s.lat.values)

            try:
                sgrid = griddata(points,
                                 values, (grid_x, grid_y),
                                 method='cubic')
            except QhullError:
                sgrid = np.empty(s.shape)
                sgrid.fill(np.nan)

            sgrid_n = griddata(points,
                               values, (grid_x, grid_y),
                               method='nearest')

            mask_nan = np.isnan(sgrid)
            sgrid[mask_nan] = sgrid_n[mask_nan]

            s = xr.DataArray(sgrid, coords=[s.lat, s.lon])

            vals_d = obs_anoms.copy()
            mask_wet = vals_d.values > 0
            vals_d.values[
                mask_wet] = vals_d.values[mask_wet] + s.values[mask_wet]
            mask_wet_invalid = np.logical_and(mask_wet, vals_d.values <= 0)

            has_invalid = mask_wet_invalid.any()

            if has_invalid:

                vals_d.values[mask_wet_invalid] = np.nan

                r, c = np.nonzero(vals_d.values > 0)
                y = vals_d.lat[r].values
                x = vals_d.lon[c].values
                points = (x, y)
                values = vals_d.values[r, c]
                grid_x, grid_y = np.meshgrid(vals_d.lon.values,
                                             vals_d.lat.values)

                try:
                    vals_d_grid = griddata(points,
                                           values, (grid_x, grid_y),
                                           method='cubic')
                except QhullError:
                    vals_d_grid = np.zeros(vals_d.shape)

                try:
                    vals_d_grid_l = griddata(points,
                                             values, (grid_x, grid_y),
                                             method='linear')
                except QhullError:
                    vals_d_grid_l = np.empty(vals_d.shape)
                    vals_d_grid_l.fill(np.nan)

                vals_d_grid_n = griddata(points,
                                         values, (grid_x, grid_y),
                                         method='nearest')

                mask_zero = vals_d_grid <= 0
                vals_d_grid[mask_zero] = vals_d_grid_l[mask_zero]

                mask_nan = np.isnan(vals_d_grid)
                vals_d_grid[mask_nan] = vals_d_grid_n[mask_nan]

                vals_d = xr.DataArray(vals_d_grid,
                                      coords=[vals_d.lat, vals_d.lon])
                vals_d.values[obs_anoms.values == 0] = 0

    except ValueError as e:

        if e.args[0] == 'No points given':
            # No valid scaler factors
            vals_d = obs_anoms.copy()
        else:
            raise

    return vals_d
        metadata['power'] = po

        xs, ys, power = array([(r['x'], r['y'], r['power'])
                               for r in tab.iterrows()]).T

        #        xs, ys, power = array(xs), array(ys), array(power)
        #        n = power.shape[0]
        #        print n
        xi = linspace(min(xs), max(xs), 50)
        yi = linspace(min(ys), max(ys), 50)

        X = xi[None, :]
        Y = yi[:, None]

        power = griddata((xs, ys), power, (X, Y),
                         fill_value=0,
                         #                          method='cubic'
                         )
        return rot90(power, k=2), metadata

    #        return flipud(fliplr(power)), metadata
    #        for row in tab.iterrows():
    #            x = int(row['col'])
    #            try:
    #                nr = cells[x]
    #            except IndexError:
    #                cells.append([])
    #                nr = cells[x]
    #
    #            # baseline = self._calc_baseline(table, index) if self.correct_baseline else 0.0
    #            baseline = 0
    #            pwr = row['power']
Example #12
0
    def plot_images(self, figure, centroid, labels, density=200, smooth=0.5):
        """
            Generate the parameter space plots
        """

        try:

            def extraxt_points_from_grid(grid2D, parx=None, pary=None):
                """ Helper function that extract x,y(,z) points from all the data """
                grid2D = grid2D.flatten()
                if parx is not None and pary is not None:
                    points_x = np.array([
                        item["point"][parx] for item in grid2D
                        if item["point"] is not None
                    ])
                    points_y = np.array([
                        item["point"][pary] for item in grid2D
                        if item["point"] is not None
                    ])
                    points_z = np.array([
                        item["value"] for item in grid2D
                        if item["point"] is not None
                    ])
                    return points_x, points_y, points_z
                else:
                    points_x = np.array([
                        item["point"] for item in grid2D
                        if item["point"] is not None
                    ])
                    points_y = np.array([
                        item["value"] for item in grid2D
                        if item["point"] is not None
                    ])
                    points_x = points_x.flatten()
                    points_y = points_y.flatten()
                    xy = np.array(list(zip(points_x, points_y)),
                                  dtype=[('x', float), ('y', float)])
                    xy.sort(order=['x'], axis=0)
                    points_x = xy['x']
                    points_y = xy['y']
                    return points_x, points_y

            if self.num_params == 1:
                # Only one parameter refined:
                points_x, points_y = extraxt_points_from_grid(self.grid)
                ax = figure.add_subplot(1, 1, 1)
                ax.plot(points_x, points_y)
                ax.set_ylabel("Residual error")
                ax.set_xlabel(get_plot_safe(labels[0]))

            else:
                # Multi-parameter space:
                image_grid, divider, get_grid = self._setup_image_grid(
                    figure, self.num_params)

                # Keep a reference to the images created,
                # so we can add a scale bar for all images (and they have the same range)
                ims = []
                tvmin, tvmax = None, None

                for index, (parx, pary) in enumerate(
                        itertools.combinations(list(range(self.num_params)),
                                               2)):
                    # Get the data for this cross section:
                    grid2D = self.grid[index, ...]
                    points_x, points_y, points_z = extraxt_points_from_grid(
                        grid2D, parx, pary)

                    # Setup axis:
                    ax = get_grid(parx, pary)
                    extent = (self.minima[parx], self.maxima[parx],
                              self.minima[pary], self.maxima[pary])
                    aspect = 'auto'

                    # Try to interpolate the data:
                    xi = np.linspace(self.minima[parx], self.maxima[parx],
                                     density)
                    yi = np.linspace(self.minima[pary], self.maxima[pary],
                                     density)
                    zi = griddata((points_x, points_y),
                                  points_z, (xi[None, :], yi[:, None]),
                                  method='cubic')

                    # Plot it:
                    im = ax.imshow(zi,
                                   origin='lower',
                                   aspect=aspect,
                                   extent=extent,
                                   alpha=0.75)
                    ims.append(im)
                    im.set_cmap('gray_r')

                    # Get visual limits:
                    vmin, vmax = im.get_clim()
                    if index == 0:
                        tvmin, tvmax = vmin, vmax
                    else:
                        tvmin, tvmax = min(tvmin, vmin), max(tvmax, vmax)

                    # Try to add a contour & labels:
                    try:
                        ct = ax.contour(xi,
                                        yi,
                                        zi,
                                        colors='k',
                                        aspect=aspect,
                                        extent=extent,
                                        origin='lower')
                        ax.clabel(ct, colors='k', fontsize=10, format="%1.2f")
                    except ValueError:
                        pass  #ignore the "zero-size array" error for now.

                    # Add a red cross where the 'best' solution is:
                    ax.plot((centroid[parx], ), (centroid[pary], ), 'r+')

                    # Rotate x labels
                    for lbl in ax.get_xticklabels():
                        lbl.set_rotation(90)

                    # Reduce number of ticks:
                    ax.locator_params(axis='both', nbins=5)

                    # Set limits:
                    ax.set_xlim(extent[0:2])
                    ax.set_ylim(extent[2:4])

                    # Add labels to the axes so the user knows which is which:
                    # TODO add some flags/color/... indicating which phase & component each parameter belongs to...
                    if parx == 0:
                        ax.set_ylabel(
                            str("#%d " % (pary + 1)) +
                            get_plot_safe(labels[pary]))
                    if pary == (self.num_params - 1):
                        ax.set_xlabel(
                            str("#%d " % (parx + 1)) +
                            get_plot_safe(labels[parx]))

                # Set the data limits:
                for im in ims:
                    im.set_clim(tvmin, tvmax)

                # Make it look PRO:
                if im is not None:
                    cbar_ax = image_grid.cbar_axes[0]
                    nx = 1 + (self.num_params - 1) * 2
                    ny1 = (self.num_params - 1) * 2
                    cbar_ax.set_axes_locator(
                        divider.new_locator(nx=nx, ny=1, ny1=ny1))
                    cb = cbar_ax.colorbar(im)  # @UnusedVariable

        except:
            print(
                "Unhandled exception while generating parameter space images:")
            print(format_exc())
            # ignore error, tell the user via the plot and return
            self.clear_image(figure)
            return
Example #13
0
    def plot_images(self, figure, centroid, labels, density=200, smooth=0.5):
        """
            Generate the parameter space plots
        """

        try:

            def extraxt_points_from_grid(grid2D, parx=None, pary=None):
                """ Helper function that extract x,y(,z) points from all the data """
                grid2D = grid2D.flatten()
                if parx is not None and pary is not None:
                    points_x = np.array([item["point"][parx] for item in grid2D if item["point"] is not None])
                    points_y = np.array([item["point"][pary] for item in grid2D if item["point"] is not None])
                    points_z = np.array([item["value"] for item in grid2D if item["point"] is not None])
                    return points_x, points_y, points_z
                else:
                    points_x = np.array([item["point"] for item in grid2D if item["point"] is not None])
                    points_y = np.array([item["value"] for item in grid2D if item["point"] is not None])
                    points_x = points_x.flatten()
                    points_y = points_y.flatten()
                    xy = np.array(list(zip(points_x, points_y)), dtype=[('x', float), ('y', float)])
                    xy.sort(order=['x'], axis=0)
                    points_x = xy['x']
                    points_y = xy['y']
                    return points_x, points_y

            if self.num_params == 1:
                # Only one parameter refined:
                points_x, points_y = extraxt_points_from_grid(self.grid)
                ax = figure.add_subplot(1, 1, 1)
                ax.plot(points_x, points_y)
                ax.set_ylabel("Residual error")
                ax.set_xlabel(get_plot_safe(labels[0]))

            else:
                # Multi-parameter space:
                image_grid, divider, get_grid = self._setup_image_grid(figure, self.num_params)

                # Keep a reference to the images created,
                # so we can add a scale bar for all images (and they have the same range)
                ims = []
                tvmin, tvmax = None, None

                for index, (parx, pary) in enumerate(itertools.combinations(list(range(self.num_params)), 2)):
                    # Get the data for this cross section:
                    grid2D = self.grid[index, ...]
                    points_x, points_y, points_z = extraxt_points_from_grid(grid2D, parx, pary)

                    # Setup axis:
                    ax = get_grid(parx, pary)
                    extent = (
                        self.minima[parx], self.maxima[parx],
                        self.minima[pary], self.maxima[pary]
                    )
                    aspect = 'auto'

                    # Try to interpolate the data:
                    xi = np.linspace(self.minima[parx], self.maxima[parx], density)
                    yi = np.linspace(self.minima[pary], self.maxima[pary], density)
                    zi = griddata((points_x, points_y), points_z, (xi[None, :], yi[:, None]), method='cubic')

                    # Plot it:
                    im = ax.imshow(zi, origin='lower', aspect=aspect, extent=extent, alpha=0.75)
                    ims.append(im)
                    im.set_cmap('gray_r')

                    # Get visual limits:
                    vmin, vmax = im.get_clim()
                    if index == 0:
                        tvmin, tvmax = vmin, vmax
                    else:
                        tvmin, tvmax = min(tvmin, vmin), max(tvmax, vmax)

                    # Try to add a contour & labels:
                    try:
                        ct = ax.contour(xi, yi, zi, colors='k', aspect=aspect, extent=extent, origin='lower')
                        ax.clabel(ct, colors='k', fontsize=10, format="%1.2f")
                    except ValueError:
                        pass #ignore the "zero-size array" error for now.

                    # Add a red cross where the 'best' solution is:
                    ax.plot((centroid[parx],), (centroid[pary],), 'r+')

                    # Rotate x labels
                    for lbl in ax.get_xticklabels():
                        lbl.set_rotation(90)

                    # Reduce number of ticks:
                    ax.locator_params(axis='both', nbins=5)

                    # Set limits:
                    ax.set_xlim(extent[0:2])
                    ax.set_ylim(extent[2:4])

                    # Add labels to the axes so the user knows which is which:
                    # TODO add some flags/color/... indicating which phase & component each parameter belongs to...
                    if parx == 0:
                        ax.set_ylabel(str("#%d " % (pary + 1)) + get_plot_safe(labels[pary]))
                    if pary == (self.num_params - 1):
                        ax.set_xlabel(str("#%d " % (parx + 1)) + get_plot_safe(labels[parx]))

                # Set the data limits:
                for im in ims:
                    im.set_clim(tvmin, tvmax)

                # Make it look PRO:
                if im is not None:
                    cbar_ax = image_grid.cbar_axes[0]
                    nx = 1 + (self.num_params - 1) * 2
                    ny1 = (self.num_params - 1) * 2
                    cbar_ax.set_axes_locator(divider.new_locator(nx=nx, ny=1, ny1=ny1))
                    cb = cbar_ax.colorbar(im) # @UnusedVariable

        except:
            print("Unhandled exception while generating parameter space images:")
            print(format_exc())
            # ignore error, tell the user via the plot and return
            self.clear_image(figure)
            return