예제 #1
0
def test_slice_maker_complex_input():
    """Test complex in all positions."""
    for y0, x0, width in product(*(((10, 10j), ) * 3)):
        if np.isrealobj((y0, x0, width)):
            continue
        with pytest.raises(TypeError):
            slice_maker((y0, x0), width)
예제 #2
0
 def plot_blob_grid(self, window=11, **kwargs):
     """Display a grid of blobs."""
     return display_grid(
         {
             i: self.data[slice_maker((y, x), window)]
             for i, (y, x, s, r) in enumerate(self.blobs)
         },
         **kwargs
     )
예제 #3
0
def test_slice_maker_center():
    """Make sure slices center y0, x0 at fft center."""
    for i in range(10):
        data = np.zeros((256, 256))
        center_loc = tuple(rng.integers(64, 256 - 64, 2))
        data[center_loc] = 1
        width = rng.integers(16, 32)
        slices = slice_maker(center_loc, width)
        data_crop = data[slices]
        print(data_crop)
        print(ifftshift(data_crop))
        assert ifftshift(data_crop)[0, 0] == 1, ifftshift(data_crop)
예제 #4
0
    def plot_fits(self, window_width, residuals=False, **kwargs):
        """Generate a plot of the found peaks, individually."""
        # check if the fitting has been performed yet, warn user if it hasn't
        if self._fits is None:
            raise RuntimeError("Blobs have not been fit yet, cannot show fits")
        else:
            fits = self._fits

        # pull the labels and the data from the object
        data = self.data

        # find objects from labelled data
        my_objects = [slice_maker(center, window_width) for center in fits[["y0", "x0"]].values]

        # generate a nice layout
        nb_labels = len(my_objects)

        nrows = int(np.ceil(np.sqrt(nb_labels)))
        ncols = int(np.ceil(nb_labels / nrows))

        fig, axes = plt.subplots(nrows, ncols, figsize=(3 * ncols, 3 * nrows))

        for n, (obj, ax) in enumerate(zip(my_objects, axes.ravel())):
            ex = (obj[1].start, obj[1].stop - 1, obj[0].stop - 1, obj[0].start)
            ax.set_title(n)
            ax.grid("off")

            # generate the model fit to display, from parameters.
            dict_params = dict(fits.loc[n].dropna())

            # recenter
            dict_params["x0"] -= obj[1].start
            dict_params["y0"] -= obj[0].start
            params = Gauss2D.dict_to_params(dict_params)
            fake_data = Gauss2D.gen_model(data[obj], *params)
            if residuals:
                ax.matshow(data[obj] - fake_data, extent=ex, **kwargs)
            else:
                ax.matshow(data[obj], extent=ex, **kwargs)
                ax.contour(fake_data, extent=ex, colors="w", origin="image")

        # # Remove empty plots
        for ax in axes.ravel():
            if not (len(ax.images)) and not (len(ax.lines)):
                fig.delaxes(ax)

        fig.tight_layout()

        # return the fig and axes handles to user for later manipulation.
        return fig, axes
예제 #5
0
    def fit_blobs(self, width=10, poly_coefs_df=None, **kwargs):
        """Fit blobs to Gaussian funtion.

        Parameters
        ----------
        width : int
            The size of the fitting window in pixels

        **kwargs is for Gauss2D optimize_params
        """
        # If we don't have blobs, find them.
        if self._blobs is None:
            self.find_blobs()

        @dask.delayed
        def fitfunc(win, sub_data):
            # fit the data as we should
            if poly_coefs_df is None:
                mypeak = Gauss2D(sub_data)
            else:
                mypeak = Gauss2Dz(sub_data, poly_coefs_df)
            # optimize params
            mypeak.optimize_params(**kwargs)
            fit_coefs = mypeak.all_params_dict()
            # need to place the fit coefs in the right place
            fit_coefs["y0"] += win[0].start
            fit_coefs["x0"] += win[1].start
            # Calc SNR for each peak
            fit_coefs["noise"] = mypeak.noise
            fit_coefs["SNR"] = fit_coefs["amp"] / fit_coefs["noise"]
            return fit_coefs

        # iterate through blobs
        windows = [slice_maker((int(y), int(x)), width) for y, x, s, r in self.blobs]
        data_to_fit = [self.data[win] for win in windows]
        peakfits = dask.delayed(
            [fitfunc(win, sub_data) for win, sub_data in zip(windows, data_to_fit)]
        )
        # construct DataFrame
        peakfits_df = pd.DataFrame(peakfits.compute())
        # internalize DataFrame
        self._fits = peakfits_df
        # Return it to user
        return peakfits_df
예제 #6
0
def test_slice_maker_float_input():
    """Make sure floats are rounded properly."""
    for i in range(10):
        y0, x0, width = rng.random(3) * 100
        slice_list = _turn_slices_into_list(slice_maker((y0, x0), width))
        assert np.issubdtype(slice_list.dtype, int)
예제 #7
0
def test_slice_negative_width():
    """Test negative width input."""
    with pytest.raises(ValueError):
        slice_maker((0, 1), (-1, 1))
예제 #8
0
def test_slice_maker_negative():
    """Make sure slice_maker doesn't return negative indices."""
    slices = _turn_slices_into_list(slice_maker((10, -10), 10))
    assert (slices >= 0).all(), slices
예제 #9
0
def _fitPeaks_sim(fitwidth, blob, stack, **kwargs):
    """Fit peaks in SIM data.

    A sub function that can be dispatched to multiple cores for processing.

    This function is specific to analyzing SIM data and is designed to fit
    substacks _without_ moving the fit window (i.e. it is assumed that
    drift is minimal).

    Parameters
    ----------
    fitwidth : int
        size of fitting window
    blob : list [int]
        a blob as returned by the find peak function

    Returns
    -------
    df : DataFrame
        A pandas DataFrame that contains all the fit parameters for a full
        stack.
    """
    # fix stack
    if stack is None:
        # if stack is None we know we've been decorated
        stack = _fitPeaks_sim.stack
    # pull parameters from the blob
    y, x, w, amp = blob

    # generate a slice
    myslice = slice_maker((y, x), fitwidth)

    # save the upper left coordinates for later use
    ystart = myslice[0].start
    xstart = myslice[1].start

    # insert the equivalent of `:` at the beginning
    myslice = (slice(None, None, None), ) + myslice

    # pull the substack
    substack = stack[myslice]

    # fit the max projection for a good initial guess
    max_z = Gauss2D(substack.max(0))
    max_z.optimize_params(**kwargs)

    # save the initial guess for later use
    guess_params = max_z.opt_params

    # check to see if initial fit was successful, if so proceed
    if np.isfinite(guess_params).all():

        def get_params(myslice):
            """Take a slice and fit a gaussian to it.

            Makes sure to update fit window coordinates to full ROI coordinates
            """
            # set up the fit object
            fit = Gauss2D(myslice)

            # do the fit, using the guess_parameters
            with np.errstate(all="ignore"):
                fit.optimize_params(guess_params=guess_params, **kwargs)

            # get the optimized parameters as a dict
            opt = fit.all_params_dict()

            # update coordinates
            opt["x0"] += xstart
            opt["y0"] += ystart

            # add an estimate of the noise
            opt["noise"] = (myslice - fit.fit_model).std()

            # return updated coordinates
            return opt

        # prep our container
        peakfits = [get_params(myslice) for myslice in substack]

        # turn everything into a data frame for easy manipulation.
        peakfits_df = pd.DataFrame(peakfits)
        # convert sigmas to positive values
        peakfits_df[["sigma_x",
                     "sigma_y"]] = abs(peakfits_df[["sigma_x", "sigma_y"]])
        peakfits_df.index.name = "slice"

        return peakfits_df
    else:
        # initial fit failed, return None
        return None
예제 #10
0
def _fitPeaks_psf(fitwidth, blob, stack, **kwargs):
    """Fitting subfunction for PSFStackAnalyzer."""
    # check if we're being dispatched from the multiprocessing pool
    if stack is None:
        stack = _fitPeaks_psf.stack
    # unpack peak variables
    y, x, w, amp = blob
    # make the slice around the blob
    myslice = slice_maker((y, x), fitwidth)
    # find the start
    ystart = myslice[0].start
    xstart = myslice[1].start
    # insert the equivalent of `:` at the beginning
    myslice = (slice(None, None, None), ) + myslice
    # make the substack
    substack = stack[myslice]
    # we could do median filtering on the substack before attempting to
    # find the max slice!
    # this could still get messed up by salt and pepper noise.
    # my_max = np.unravel_index(substack.argmax(), substack.shape)
    # use the range of each z-slice as an indication of intensity
    my_max = (substack.max((1, 2)) - substack.min((1, 2))).argmax()
    # now change my slice to be that zslice
    myslice = (my_max, ) + myslice[1:]
    substack = stack[myslice]
    # prep our container
    peakfits = []
    # initial fit
    max_z = Gauss2D(substack)
    max_z.optimize_params(**kwargs)

    if np.isfinite(max_z.opt_params).all():

        # recenter the coordinates and add a slice variable
        opt_params = max_z.all_params_dict()
        opt_params["slice"] = my_max
        opt_params["x0"] += xstart
        opt_params["y0"] += ystart

        # append to our list
        peakfits.append(opt_params.copy())

        # pop the slice parameters
        opt_params.pop("slice")

        forwardrange = range(my_max + 1, stack.shape[0])
        backwardrange = reversed(range(0, my_max))

        peakfits += fitPeak(stack,
                            forwardrange,
                            fitwidth,
                            opt_params.copy(),
                            quiet=True)

        peakfits += fitPeak(stack,
                            backwardrange,
                            fitwidth,
                            opt_params.copy(),
                            quiet=True)

        # turn everything into a data frame for easy manipulation.
        peakfits_df = pd.DataFrame(peakfits)
        # convert sigmas to positive values
        try:
            peakfits_df[["sigma_x",
                         "sigma_y"]] = abs(peakfits_df[["sigma_x", "sigma_y"]])
        except KeyError:
            peakfits_df["sigma_x"] = abs(peakfits_df["sigma_x"])

        return peakfits_df.set_index("slice").sort_index()
    else:
        logger.debug(f"blob {blob} is unfittable")
        return None
예제 #11
0
def fitPeak(stack, slices, width, startingfit, **kwargs):
    """Fit a peak through the stack.

    The method will track the peak through the stack, assuming that moves
    are relatively small from one slice to the next

    Parameters
    ----------
    slices : iterator
        an iterator which dictates which slices to fit, should yeild
        integers only

    width : integer
        width of fitting window

    startingfit : dict
        fit coefficients

    Returns
    -------
    list : list of dicts
        A list of dictionaries containing the best fits. Easy to turn into
        a DataFrame

    """
    # set up our variable to return
    toreturn = []

    # grab the starting fit parameters
    popt_d = startingfit.copy()

    y0 = int(round(popt_d["y0"]))
    x0 = int(round(popt_d["x0"]))

    if len(popt_d) == 6 * 2:
        modeltype = "norot"
    elif len(popt_d) == 5 * 2:
        modeltype = "sym"
    elif len(popt_d) == 7 * 2:
        modeltype = "full"
    else:
        raise ValueError("Dictionary is too big {}".format(popt_d))

    for s in slices:

        # make the slice
        try:
            myslice = slice_maker((y0, x0), width)
        except RuntimeError as e:
            logger.warning("Fit window moved to edge of ROI")
            break
        else:
            # pull the starting values from it
            ystart = myslice[0].start
            xstart = myslice[1].start

            # insert the z-slice number
            myslice = (s, ) + myslice

            # set up the fit and perform it using last best params
            sub_stack = stack[myslice]
            if sub_stack.size == 0:
                # the fir window has moved to the edge, break
                logger.warning("Fit window moved to edge of ROI")
                break
            fit = Gauss2D(sub_stack)

            # move our guess coefs back into the window
            popt_d["x0"] -= xstart
            popt_d["y0"] -= ystart
            # leave this in for now for easier debugging in future.
            try:
                fit.optimize_params(popt_d, **kwargs)
            except TypeError as e:
                print(repr(myslice))
                raise e

            # if there was an error performing the fit, try again without
            # a guess
            if fit.error:
                fit.optimize_params(modeltype=modeltype, **kwargs)

            # if there's not an error update center of fitting window and
            # move on to the next fit
            if not fit.error:
                popt_d = fit.all_params_dict()
                popt_d["x0"] += xstart
                popt_d["y0"] += ystart

                popt_d["slice"] = s
                # calculate the apparent noise as the standard deviation
                # of what's the residuals of the fit
                popt_d["noise"] = (sub_stack - fit.fit_model).std()
                toreturn.append(popt_d.copy())

                y0 = int(round(popt_d["y0"]))
                x0 = int(round(popt_d["x0"]))
            else:
                # if the fit fails, make sure to _not_ update positions.
                bad_fit = fit.all_params_dict()
                bad_fit["slice"] = s
                # noise of a failed fit is not really useful
                popt_d["noise"] = np.nan

                toreturn.append(bad_fit.copy())

    return toreturn