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
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()
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
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
def __init__(self, *args, **kargs): self.type = kargs.pop("type", make_Data(None)) super(DataFolder, self).__init__(*args, **kargs)
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
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)
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
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