Beispiel #1
0
    def hysteresis(self, mask=None):
        """Make a hysteresis loop of the average intensity in the given images

        Keyword Argument:
            mask(ndarray or list):
                boolean array of same size as an image or imarray or list of
                masks for each image. If True then don't include that area in
                the intensity averaging.

        Returns
        -------
        hyst(Data):
            'Field', 'Intensity', 2 column array
        """
        hyst = np.column_stack((self.fields, np.zeros(len(self))))
        for i, im in enumerate(self):
            if isinstance(mask, np.ndarray) and len(mask.shape) == 2:
                hyst[i, 1] = np.average(im[np.invert(mask.astype(bool))])
            elif isinstance(mask, np.ndarray) and len(mask.shape) == 3:
                hyst[i, 1] = np.average(im[np.invert(mask[i, :, :].astype(bool))])
            elif isinstance(mask, (tuple, list)):
                hyst[i, 1] = np.average(im[np.invert(mask[i])])
            else:
                hyst[i, 1] = np.average(im)
        d = make_Data(hyst, setas="xy")
        d.column_headers = ["Field", "Intensity"]
        return d
Beispiel #2
0
 def __init__(self, *args, **kargs):
     """Additional constructor for DiskBasedFolderMixins."""
     _ = self.defaults  # Force the default store to be populated.
     if "directory" in self._default_store and self._default_store[
             "directory"] is None:
         self._default_store["directory"] = os.getcwd()
     if "type" in self._default_store and self._default_store[
             "type"] is None and self._type == metadataObject:
         self._default_store["type"] = make_Data(None)
     elif self._type != metadataObject:  # Looks like we've already set our type in a subbclass
         self._default_store.pop("type")
     flat = kargs.pop("flat", self._default_store.get("flat", False))
     prefetch = kargs.pop("prefetch",
                          self._default_store.get("prefetch", False))
     super(DiskBasedFolderMixin, self).__init__(
         *args, **kargs)  # initialise before __clone__ is called in getlist
     if self.readlist and len(args) > 0 and isinstance(
             args[0], string_types):
         self.getlist(directory=args[0])
     if flat:
         self.flatten()
     if prefetch:
         self.fetch()
     if self.pruned:
         self.prune()
Beispiel #3
0
def hist(im, *args, **kargs):
    """Pass through to :py:func:`matplotlib.pyplot.hist` function."""
    counts, edges = np.histogram(im.ravel(), *args, **kargs)
    centres = (edges[1:] + edges[:-1]) / 2
    new = make_Data(np.column_stack((centres, counts)))
    new.column_headers = ["Intensity", "Frequency"]
    new.setas = "xy"
    return new
Beispiel #4
0
def _fmt_as_Data(results):
    """Format the results as a Data() object."""
    ret = make_Data(_fmt_as_dataframe(results))
    mask = np.zeros(ret.shape, dtype=bool)
    for ix, col in enumerate(ret.data.T):
        try:
            mask[:, ix] = np.isnan(col)
        except TypeError:
            pass
    ret.mask = mask
    return ret
Beispiel #5
0
    def __init__(self, *args, **kargs):

        self.type = kargs.pop("type", make_Data(None))
        super(DataFolder, self).__init__(*args, **kargs)
Beispiel #6
0
    def plot(self, *args, **kargs):
        """Call the plot method for each metadataObject, but switching to a subplot each time.

        Args:
            args: Positional arguments to pass through to the :py:meth:`Stoner.plot.PlotMixin.plot` call.
            kargs: Keyword arguments to pass through to the :py:meth:`Stoner.plot.PlotMixin.plot` call.

        Keyword Arguments:
            extra (callable(i,j,d)):
                A callable that can carry out additional processing per plot after the plot is done
            figsize(tuple(x,y)):
                Size of the figure to create
            dpi(float):
                dots per inch on the figure
            edgecolor,facecolor(matplotlib colour):
                figure edge and frame colours.
            frameon (bool):
                Turns figure frames on or off
            FigureClass(class):
                Passed to matplotlib figure call.
            plots_per_page(int):
                maximum number of plots per figure.
            tight_layout(dict or False):
                If not False, arguments to pass to a call of :py:func:`matplotlib.pyplot.tight_layout`. Defaults to {}

        Returns:
            A list of :py:class:`matplotlib.pyplot.Axes` instances.

        Notes:
            If the underlying type of the :py:class:`Stoner.Core.metadataObject` instances in the
            :py:class:`PlotFolder` lacks a **plot** method, then the instances are converted to
            :py:class:`Stoner.Core.Data`.

            Each plot is generated as sub-plot on a page. The number of rows and columns of subplots is computed
            from the aspect ratio of the figure and the number of files in the :py:class:`PlotFolder`.
        """
        plts = kargs.pop("plots_per_page",
                         getattr(self, "plots_per_page", len(self)))
        plts = min(plts, len(self))

        if not hasattr(
                self.type,
                "plot"):  # switch the objects to being Stoner.Data instances
            for i, d in enumerate(self):
                self[i] = make_Data(d)

        extra = kargs.pop("extra", lambda i, j, d: None)
        tight = kargs.pop("tight_layout", {})

        fig_num = kargs.pop("figure", getattr(self, "_figure", None))
        if isinstance(fig_num, Figure):
            fig_num = fig_num.number
        fig_args = getattr(self, "_fig_args", [])
        fig_kargs = getattr(self, "_fig_kargs", {})
        for arg in ("figsize", "dpi", "facecolor", "edgecolor", "frameon",
                    "FigureClass"):
            if arg in kargs:
                fig_kargs[arg] = kargs.pop(arg)
        if fig_num is None:
            fig = figure(*fig_args, **fig_kargs)
        else:
            fig = figure(fig_num, **fig_kargs)
        w, h = fig.get_size_inches()
        plt_x = int(floor(sqrt(plts * w / h)))
        plt_y = int(ceil(plts / plt_x))

        kargs["figure"] = fig
        ret = []
        j = 0
        fignum = fig.number
        for i, d in enumerate(self):
            if i % plts == 0 and i != 0:
                if isinstance(tight, dict):
                    tight_layout(**tight)
                fig = figure(*fig_args, **fig_kargs)
                fignum = fig.number
                j = 1
            else:
                j += 1
            fig = figure(fignum)
            ax = subplot(plt_y, plt_x, j)
            kargs["fig"] = fig
            kargs["ax"] = ax
            ret.append(d.plot(*args, **kargs))
            extra(i, j, d)
        tight_layout()
        return ret
Beispiel #7
0
 def __init__(self, *args, **kargs):
     """Set the default type before creating the DataFolder."""
     self.type = kargs.pop("type", make_Data(None))
     super(DataFolder, self).__init__(*args, **kargs)
Beispiel #8
0
def profile_line(img,
                 src=None,
                 dst=None,
                 linewidth=1,
                 order=1,
                 mode="constant",
                 cval=0.0,
                 constrain=True,
                 **kargs):
    """Wrapper for sckit-image method of the same name to get a line_profile.

    Parameters:
        img(ImageArray): Image data to take line section of
        src, dst (2-tuple of int or float): start and end of line profile. If the co-ordinates
            are given as intergers then they are assumed to be pxiel co-ordinates, floats are
            assumed to be real-space co-ordinates using the embedded metadata.
        linewidth (int): the wideth of the profile to be taken.
        order (int 1-3): Order of interpolation used to find image data when not aligned to a point
        mode (str): How to handle data outside of the image.
        cval (float): The constant value to assume for data outside of the image is mode is "constant"
        constrain (bool): Ensure the src and dst are within the image (default True).

    Returns:
        A :py:class:`Stoner.Data` object containing the line profile data and the metadata from the image.
    """
    scale = img.get("MicronsPerPixel", 1.0)
    r, c = img.shape
    if src is None and dst is None:
        if "x" in kargs:
            src = (kargs["x"], 0)
            dst = (kargs["x"], r)
        if "y" in kargs:
            src = (0, kargs["y"])
            dst = (c, kargs["y"])
    if isinstance(src, float):
        src = (src, src)
    if isinstance(dst, float):
        dst = (dst, dst)
    dst = _scale(dst, scale)
    src = _scale(src, scale)
    if not isTuple(src, int, int):
        raise ValueError("src co-ordinates are not a 2-tuple of ints.")
    if not isTuple(dst, int, int):
        raise ValueError("dst co-ordinates are not a 2-tuple of ints.")

    if constrain:
        fix = lambda x, mx: int(round(sorted([0, x, mx])[1]))
        r, c = img.shape
        src = list(src)
        src = (fix(src[0], r), fix(src[1], c))
        dst = (fix(dst[0], r), fix(dst[1], c))

    result = measure.profile_line(img, src, dst, linewidth, order, mode, cval)
    points = measure.profile._line_profile_coordinates(src, dst,
                                                       linewidth)[:, :, 0]
    ret = make_Data()
    ret.data = points.T
    ret.setas = "xy"
    ret &= np.sqrt(ret.x**2 + ret.y**2) * scale
    ret &= result
    ret.column_headers = ["X", "Y", "Distance", "Intensity"]
    ret.setas = "..xy"
    ret.metadata = img.metadata.copy()
    return ret
Beispiel #9
0
def cfg_data_from_ini(inifile, filename=None, **kargs):
    """Read an inifile and load and configure a DataFile from it.

    Args:
        inifile (str or file):
            Path to the ini file to be read.

    Keyword Arguments:
        filename (strig,boolean or None):
            File to load that contains the data.
        **kargs:
            All other keywords are passed to the Data constructor

    Returns:
        An instance of :py:class:`Stoner.Core.Data` with data loaded and columns configured.

    The inifile should contain a [Data] section that contains the following keys:
        -  **type (str):** optional name of DataFile subclass to import.
        -  **filename (str or boolean):** optionally used if *filename* parameter is None.
        - **xcol (column index):** defines the x-column data for fitting.
        - **ycol (column index):** defines the y-column data for fitting.
        - **yerr (column index):** Optional column with uncertainity values for the data
    """
    if SafeConfigParser is None:
        raise RuntimeError("Need to have ConfigParser module installed for this to work.")
    config = SafeConfigParser()
    if isinstance(inifile, string_types):
        config.read(inifile)
    elif isinstance(inifile, IOBase):
        config.readfp(inifile)
    if not config.has_section("Data"):
        raise RuntimeError("Configuration file lacks a [Data] section to describe data.")

    if config.has_option("Data", "type"):
        typ = config.get("Data", "type").split(".")
        typ_mod = ".".join(typ[:-1])
        typ = typ[-1]
        typ = __import__(typ_mod, fromlist=[typ]).__getattribute__(typ)
    else:
        typ = None
    data = make_Data(**kargs)
    if filename is None:
        if not config.has_option("Data", "filename"):
            filename = False
        else:
            filename = config.get("Data", "filename")
            if filename in ["False", "True"]:
                filename = bool(filename)
    data.load(filename, auto_load=False, filetype=typ)
    cols = {"x": 0, "y": 1, "e": None}  # Defaults

    for c in ["x", "y", "e"]:
        if not config.has_option("Data", c):
            pass
        else:
            try:
                cols[c] = config.get("Data", c)
                cols[c] = int(cols[c])
            except ValueError:
                pass
        if cols[c] is None:
            del cols[c]

    data.setas(**cols)  # pylint: disable=not-callable
    return data