Source code for libertem.common.analysis

from io import BytesIO
from typing import (
    Callable, Optional, Union
)

import numpy as np


[docs] class AnalysisResult: """ This class represents a single 2D image result from an Analysis. Instances of this class are contained in an :class:`AnalysisResultSet`. Attributes ---------- raw_data : numpy.ndarray The raw numerical data of this result visualized : numpy.ndarray Visualized result as :class:`numpy.ndarray` with RGB or RGBA values title : str Title for the GUI desc : str Short description in the GUI key : str Key to identify the result in an :class:`AnalysisResultSet` """ def __init__( self, raw_data: np.ndarray, visualized: np.ndarray, title: str, desc: str, key: str, include_in_download: bool = True, ): self.include_in_download = include_in_download self.raw_data = raw_data self._visualized = visualized self.title = title self.desc = desc self.key = key def __str__(self): result = "" for k in ("title", "desc", "key", "raw_data", "visualized"): result += f"{k}: {getattr(self, k)}\n" return result def __repr__(self): return "<AnalysisResult: %s>" % self.key def __array__(self): return np.array(self.raw_data) def get_image(self, save_kwargs: Optional[dict] = None) -> BytesIO: from libertem.common.viz import encode_image return encode_image(self.visualized, save_kwargs=save_kwargs) @property def visualized(self): if callable(self._visualized): self._visualized = self._visualized() return self._visualized
_ResultsType = Union[list[AnalysisResult], Callable[[], list[AnalysisResult]]]
[docs] class AnalysisResultSet: """ Base class for Analysis result sets. :meth:`libertem.api.Context.run` returns an instance of this class or a subclass. Many of the subclasses are just introduced to document the Analysis-specific results (keys) of the result set and don't introduce new functionality. The contents of an :class:`AnalysisResultSet` can be addressed in four different ways: 1. As a container class with the :attr:`AnalysisResult.key` properties as attributes of type :class:`AnalysisResult`. 2. As a list of :class:`AnalysisResult` objects. 3. As an iterator of :class:`AnalysisResult` objects (since 0.3). 4. As a dictionary of :class:`AnalysisResult` objects with the :attr:`AnalysisResult.key` properties as keys. This allows to implement generic result handling code for an Analysis, for example GUI display, as well as specific code for particular Analysis subclasses. Attributes ---------- raw_results Raw results from the underlying numerical processing, if available, otherwise None. Examples -------- >>> mask_shape = tuple(dataset.shape.sig) >>> def m0(): ... return np.ones(shape=mask_shape) >>> def m1(): ... result = np.zeros(shape=mask_shape) ... result[0,0] = 1 ... return result >>> analysis = ctx.create_mask_analysis( ... dataset=dataset, factories=[m0, m1] ... ) >>> result = ctx.run(analysis) >>> # As an object with attributes >>> print(result.mask_0.title) mask 0 >>> print(result.mask_1.title) mask 1 >>> # As a list >>> print(result[0].title) mask 0 >>> # As an iterator >>> # New since 0.3.0 >>> for m in result: ... print(m.title) mask 0 mask 1 >>> # As a dictionary >>> print(result['mask_1'].title) mask 1 """ def __init__(self, results: _ResultsType, raw_results=None): self._results = results self.raw_results = raw_results def __repr__(self): return repr(self.results) def __getattr__(self, k): for result in self.results: if result.key == k: return result raise AttributeError("result with key '{}' not found, have: {}".format( k, ", ".join([r.key for r in self.results]) )) def __getitem__(self, k): if isinstance(k, str): return self.__getattr__(k) return self.results[k] def __len__(self): return len(self.results) def keys(self): return [r.key for r in self.results] @property def results(self): if callable(self._results): self._results = self._results() return self._results def __iter__(self): return iter(self.results)