Classes

Array

class py4DSTEM.Array(data: ndarray, name: str | None = 'array', units: str | None = '', dims: list | None = None, dim_names: list | None = None, dim_units: list | None = None, slicelabels=None)

A class which stores any N-dimensional array-like data, plus basic metadata: a name and units, as well as calibrations for each axis of the array, and names and units for those axis calibrations.

In the simplest usage, only a data array is passed:

>>> ar = Array(np.ones((20,20,256,256)))

will create an array instance whose data is the numpy array passed, and with automatically populated dimension calibrations in units of pixels.

Additional arguments may be passed to populate the object metadata:

>>> ar = Array(
>>>     np.ones((20,20,256,256)),
>>>     name = 'test_array',
>>>     units = 'intensity',
>>>     dims = [
>>>         [0,5],
>>>         [0,5],
>>>         [0,0.01],
>>>         [0,0.01]
>>>     ],
>>>     dim_units = [
>>>         'nm',
>>>         'nm',
>>>         'A^-1',
>>>         'A^-1'
>>>     ],
>>>     dim_names = [
>>>         'rx',
>>>         'ry',
>>>         'qx',
>>>         'qy'
>>>     ],
>>> )

will create an array with a name and units for its data, where its first two dimensions are in units of nanometers, have pixel sizes of 5nm, and are described by the handles ‘rx’ and ‘ry’, and where its last two dimensions are in units of inverse Angstroms, have pixels sizes of 0.01A^-1, and are described by the handles ‘qx’ and ‘qy’.

Arrays in which the length of each pixel is non-constant are also supported. For instance,

>>> x = np.logspace(0,1,100)
>>> y = np.sin(x)
>>> ar = Array(
>>>     y,
>>>     dims = [
>>>         x
>>>     ]
>>> )

generates an array representing the values of the sine function sampled 100 times along a logarithmic interval from 1 to 10. In this example, this data could then be plotted with, e.g.

>>> plt.scatter(ar.dims[0], ar.data)

If the slicelabels keyword is passed, the first N-1 dimensions of the array are treated normally, while the final dimension is used to represent distinct arrays which share a common shape and set of dim vectors. Thus

>>> ar = Array(
>>>     np.ones((50,50,4)),
>>>     name = 'test_array_stack',
>>>     units = 'intensity',
>>>     dims = [
>>>         [0,2],
>>>         [0,2]
>>>     ],
>>>     dim_units = [
>>>         'nm',
>>>         'nm'
>>>     ],
>>>     dim_names = [
>>>         'rx',
>>>         'ry'
>>>     ],
>>>     slicelabels = [
>>>         'a',
>>>         'b',
>>>         'c',
>>>         'd'
>>>     ]
>>> )

will generate a single Array instance containing 4 arrays which each have a shape (50,50) and a common set of dim vectors [‘rx’,’ry’], and which can be indexed into with the names assigned in slicelabels using

>>> ar.get_slice('a')

which will return a 2D (non-stack-like) Array instance with shape (50,50) and the dims assigned above. The Array attribute .rank is equal to the number of dimensions for a non-stack-like Array, and is equal to N-1 for stack-like arrays.

__init__(data: ndarray, name: str | None = 'array', units: str | None = '', dims: list | None = None, dim_names: list | None = None, dim_units: list | None = None, slicelabels=None)
Accepts:

data (np.ndarray): the data name (str): the name of the Array units (str): units for the pixel values dims (variable): calibration vectors for each of the axes of the data

array. Valid values for each element of the list are None, a number, a 2-element list/array, or an M-element list/array where M is the data array. If None is passed, the dim will be populated with integer values starting at 0 and its units will be set to pixels. If a number is passed, the dim is populated with a vector beginning at zero and increasing linearly by this step size. If a 2-element list/array is passed, the dim is populated with a linear vector with these two numbers as the first two elements. If a list/array of length M is passed, this is used as the dim vector, (and must therefore match this dimension’s length). If dims recieves a list of fewer than N arguments for an N-dimensional data array, the extra dimensions are populated as if None were passed, using integer pixel values. If the dims parameter is not passed, all dim vectors are populated this way.

dim_units (list): the units for the calibration dim vectors. If

nothing is passed, dims vectors which have been populated automatically with integers corresponding to pixel numbers will be assigned units of ‘pixels’, and any other dim vectors will be assigned units of ‘unknown’. If a list with length < the array dimensions, the passed values are assumed to apply to the first N dimensions, and the remaining values are populated with ‘pixels’ or ‘unknown’ as above.

dim_names (list): labels for each axis of the data array. Values

which are not passed, following the same logic as described above, will be autopopulated with the name “dim#” where # is the axis number.

slicelabels (None or True or list): if not None, must be True or a

list of strings, indicating a “stack-like” array. In this case, the first N-1 dimensions of the array are treated normally, in the sense of populating dims, dim_names, and dim_units, while the final dimension is treated distinctly: it indexes into distinct arrays which share a set of dimension attributes, and can be sliced into using the string labels from the slicelabels list, with the syntax array[‘label’] or array.get_slice(‘label’). If slicelabels is True or is a list with length less than the final dimension length, unassigned dimensions are autopopulated with labels array{i}. The flag array.is_stack is set to True and the array.rank attribute is set to N-1.

Returns:

A new Array instance

get_dim(n)

Return the n’th dim vector

dim(n)

Return the n’th dim vector

set_dim(n: int, dim: list | ndarray, units: str | None = None, name: str | None = None)

Sets the n’th dim vector, using dim as described in the Array documentation. If units and/or name are passed, sets these values for the n’th dim vector.

Accepts:

n (int): specifies which dim vector dim (list or array): length must be either 2, or equal to the

length of the n’th axis of the data array

units (Optional, str): name: (Optional, str):

get_dim_units(n)

Return the n’th dim vector units

set_dim_units(n: int, units: str)

Sets the n’th dim vector units to units.

Accepts:

n (int): specifies which dim vector units (str): new units

get_dim_name(n)

Get the n’th dim vector name

set_dim_name(n: int, name: str)

Sets the n’th dim vector name to name.

Accepts:

n (int): specifies which dim vector name (str): new name

to_h5(group)

Takes an h5py Group instance and creates a subgroup containing this Array, tags indicating its EMD type and Python class, and the array’s data and metadata.

Accepts:

group (h5py Group)

Returns:

(h5py Group) the new array’s Group

add_to_tree(node)

Add an unrooted node as a child of the current, rooted node. To move an already rooted node/branch, use .graft(). To create a rooted node, use Root().

cut_from_tree(root_metadata=True)

Removes a branch from an object tree at this node.

A new root node is created under this object with this object’s name. Metadata from the current root is transferred/not transferred to the new root according to the value of root_metadata.

Accepts:
root_metadata (True, False, or ‘copy’): if True adds the old root’s

metadata to the new root; if False adds no metadata to the new root; if ‘copy’ adds copies of all metadata from the old root to the new root.

Returns:

(Node) the new root node

force_add_to_tree(node)

Add node node as a child of the current node, whether or not node is rooted. If it’s unrooted, performs a simple add. If it is rooted, performs a graft, excluding the root metadata from node.

classmethod from_h5(group)

Takes an h5py Group which is open in read mode. Confirms that a a Node of this name exists in this group, and loads and returns it with it’s metadata.

Accepts:

group (h5py Group)

Returns:

(Node)

get_from_tree(name)

Finds and returns an object from an EMD tree using the string key name, with ‘/’ delimiters between ‘parent/child’ nodes. Search from the root node by adding a leading ‘/’; otherwise, searches from the current node.

graft(node, merge_metadata=True)

Moves the branch beginning node onto this tree at this node.

For the reverse (i.e. grafting from this tree onto another tree) either use that tree’s .graft method, or use this tree’s ._graft.

Accepts:

node (Node): merge_metadata (True, False, or ‘copy’): if True adds the old root’s

metadata to the new root; if False adds no metadata to the new root; if ‘copy’ adds copies of all metadata from the old root to the new root.

Returns:

(Node) this tree’s root node

static newnode(method)

Decorator which may be added to node methods which product and return a new node. If such a method is decorated with

>>> @newnode

then the new node is added to the parent node’s tree, and a Metadata instance is added to the new node’s metadata which stores information about how the node was created, namely: method’s name, the parent’s class and name, and all the arguments passed to method.

show_tree(root=False)

Display the object tree. If root is False, displays the branch of the tree downstream from this node. If root is True, displays the full tree from the root node.

tree(arg=None, **kwargs)

Usages -

>>> .tree()             # show tree from current node
>>> .tree(show=True)    # show from root
>>> .tree(show=False)   # show from current node
>>> .tree(add=node)     # add a child node
>>> .tree(get='path')   # return a '/' delimited child node
>>> .tree(get='/path')  # as above, starting at root
>>> .tree(cut=True)     # remove/return a branch, keep root metadata
>>> .tree(cut=False)    # remove/return a branch, discard root md
>>> .tree(cut='copy')   # remove/return a branch, copy root metadata
>>> .tree(graft=node)   # remove/graft a branch, keeping root metadata
>>> .tree(graft=(node,True))    # as above
>>> .tree(graft=(node,False))   # as above, discard root metadata
>>> .tree(graft=(node,'copy'))  # as above, copy root metadata

The show, add, and get methods can be accessed directly with

>>> .tree(arg)

for an arg of the appropriate type (bool, Node, and string).

BraggVectors

class py4DSTEM.BraggVectors(Rshape, Qshape, name='braggvectors', verbose=False, calibration=None)

Stores localized bragg scattering positions and intensities for a 4D-STEM datacube.

Raw (detector coordinate) vectors are accessible as

>>> braggvectors.raw[ scan_x, scan_y ]

and calibrated vectors as

>>> braggvectors.cal[ scan_x, scan_y ]

To set which calibrations are being applied, call

>>> braggvectors.setcal(
>>>     center = bool,
>>>     ellipse = bool,
>>>     pixel = bool,
>>>     rotate = bool
>>> )

If .setcal is not called, calibrations will be automatically selected based based on the contents of the instance’s calibrations property. The calibrations performed in the last call to braggvectors.cal are exposed as

>>> braggvectors.calstate

After grabbing some vectors

>>> vects = braggvectors.raw[ scan_x,scan_y ]

the values themselves are accessible as

>>> vects.qx,vects.qy,vects.I
>>> vects['qx'],vects['qy'],vects['intensity']

Alternatively, you can access the centered vectors in pixel units with

>>> vects.get_vectors(
>>>     scan_x,
>>>     scan_y,
>>>     center = bool,
>>>     ellipse = bool,
>>>     pixel = bool,
>>>     rotate = bool
>>> )

which will return the vectors at scan position (scan_x,scan_y) with the requested calibrations applied.

__init__(Rshape, Qshape, name='braggvectors', verbose=False, calibration=None)
set_raw_vectors(x)

Given some PointListArray x of the correct shape, sets this to the raw vectors

property raw

Calling

>>> raw[ scan_x, scan_y ]

returns those bragg vectors.

property cal

Calling

>>> cal[ scan_x, scan_y ]

retrieves data. Use .setcal to set the calibrations to be applied, or .calstate to see which calibrations are currently set. Calibrations are initially all set to False. Call .setcal() (with no arguments) to automatically detect which calibrations are present and apply those.

setcal(center=None, ellipse=None, pixel=None, rotate=None)

Calling

>>> braggvectors.setcal(
>>>     center = bool,
>>>     ellipse = bool,
>>>     pixel = bool,
>>>     rotate = bool,
>>> )

sets the calibrations that will be applied to vectors subsequently retrieved with

>>> braggvectors.cal[ scan_x, scan_y ]

Any arguments left as None will be automatically set based on the calibration measurements available.

calibrate()

Autoupdate the calstate when relevant calibrations are set

get_vectors(scan_x, scan_y, center, ellipse, pixel, rotate)

Returns the bragg vectors at the specified scan position with the specified calibration state.

Parameters:
  • scan_x (int) –

  • scan_y (int) –

  • center (bool) –

  • ellipse (bool) –

  • pixel (bool) –

  • rotate (bool) –

Returns:

vectors

Return type:

BVects

to_h5(group)

Constructs the group, adds the bragg vector pointlists, and adds metadata describing the shape

add_to_tree(node)

Add an unrooted node as a child of the current, rooted node. To move an already rooted node/branch, use .graft(). To create a rooted node, use Root().

attach(node)

Attach node to the current object’s tree, attaching calibration and detaching calibrations as needed.

cut_from_tree(root_metadata=True)

Removes a branch from an object tree at this node.

A new root node is created under this object with this object’s name. Metadata from the current root is transferred/not transferred to the new root according to the value of root_metadata.

Accepts:
root_metadata (True, False, or ‘copy’): if True adds the old root’s

metadata to the new root; if False adds no metadata to the new root; if ‘copy’ adds copies of all metadata from the old root to the new root.

Returns:

(Node) the new root node

fit_origin(mask=None, fitfunction='plane', robust=False, robust_steps=3, robust_thresh=2, mask_check_data=True, plot=True, plot_range=None, cmap='RdBu_r', returncalc=True, **kwargs)

Fit origin of bragg vectors.

Parameters:
  • mask (2b boolean array, optional) – ignore points where mask=True

  • fitfunction (str, optional) – must be ‘plane’ or ‘parabola’ or ‘bezier_two’

  • robust (bool, optional) – If set to True, fit will be repeated with outliers removed.

  • robust_steps (int, optional) – Optional parameter. Number of robust iterations performed after initial fit.

  • robust_thresh (int, optional) – Threshold for including points, in units of root-mean-square (standard deviations) error of the predicted values after fitting.

  • mask_check_data (bool) – Get mask from origin measurements equal to zero. (TODO - replace)

  • plot (bool, optional) – plot results

  • plot_range (float) – min and max color range for plot (pixels)

  • cmap (colormap) – plotting colormap

Returns:

Return value depends on returnfitp. If returnfitp==False (default), returns a 4-tuple containing:

  • qx0_fit: (ndarray) the fit origin x-position

  • qy0_fit: (ndarray) the fit origin y-position

  • qx0_residuals: (ndarray) the x-position fit residuals

  • qy0_residuals: (ndarray) the y-position fit residuals

Return type:

(variable)

fit_p_ellipse(bvm, center, fitradii, mask=None, returncalc=False, **kwargs)
Parameters:
  • bvm (BraggVectorMap) – a 2D array used for ellipse fitting

  • center (2-tuple of floats) – the center (x0,y0) of the annular fitting region

  • fitradii (2-tuple of floats) – inner and outer radii (ri,ro) of the fit region

  • mask (ar-shaped ndarray of bools) – ignore data wherever mask==True

Returns:

p_ellipse if returncal is True

force_add_to_tree(node)

Add node node as a child of the current node, whether or not node is rooted. If it’s unrooted, performs a simple add. If it is rooted, performs a graft, excluding the root metadata from node.

classmethod from_h5(group)

Takes an h5py Group which is open in read mode. Confirms that a a Node of this name exists in this group, and loads and returns it with it’s metadata.

Accepts:

group (h5py Group)

Returns:

(Node)

get_bragg_vector_map(mode='cal', sampling=1, weights=None, weights_thresh=0.005)

Returns a 2D histogram of Bragg vector intensities in diffraction space, aka a Bragg vector map.

Parameters:
  • mode (str) – Must be ‘cal’ or ‘raw’. Use the calibrated or raw vector positions.

  • sampling (number) – The sampling rate of the histogram, in units of the camera’s sampling. sampling = 2 upsamples and sampling = 0.5 downsamples, each by a factor of 2.

  • weights (None or array) – If None, use all real space scan positions. Otherwise must be a real space shaped array representing a weighting factor applied to vector intensities from each scan position. If weights is boolean uses beam positions where weights is True. If weights is number-like, scales by the values, and skips positions where wieghts<weights_thresh.

  • weights_thresh (number) – If weights is an array of numbers, pixels where weights>weight_thresh are skipped.

Returns:

An Array with .data representing the data, and .dim[0] and .dim[1] representing the sampling grid.

Return type:

BraggVectorHistogram

get_bvm(mode='cal', sampling=1, weights=None, weights_thresh=0.005)

Returns a 2D histogram of Bragg vector intensities in diffraction space, aka a Bragg vector map.

Parameters:
  • mode (str) – Must be ‘cal’ or ‘raw’. Use the calibrated or raw vector positions.

  • sampling (number) – The sampling rate of the histogram, in units of the camera’s sampling. sampling = 2 upsamples and sampling = 0.5 downsamples, each by a factor of 2.

  • weights (None or array) – If None, use all real space scan positions. Otherwise must be a real space shaped array representing a weighting factor applied to vector intensities from each scan position. If weights is boolean uses beam positions where weights is True. If weights is number-like, scales by the values, and skips positions where wieghts<weights_thresh.

  • weights_thresh (number) – If weights is an array of numbers, pixels where weights>weight_thresh are skipped.

Returns:

An Array with .data representing the data, and .dim[0] and .dim[1] representing the sampling grid.

Return type:

BraggVectorHistogram

get_from_tree(name)

Finds and returns an object from an EMD tree using the string key name, with ‘/’ delimiters between ‘parent/child’ nodes. Search from the root node by adding a leading ‘/’; otherwise, searches from the current node.

get_masked_peaks(mask, update_inplace=False, returncalc=True)

Alias for mask_in_Q.

get_virtual_image(mode=None, geometry=None, name='bragg_virtual_image', returncalc=True, center=True, ellipse=True, pixel=True, rotate=True)

Calculates a virtual image based on the values of the Braggvectors integrated over some detector function determined by mode and geometry.

Parameters:
  • mode (str) –

    defines the type of detector used. Options:
    • ’circular’, ‘circle’: uses round detector, like bright field

    • ’annular’, ‘annulus’: uses annular detector, like dark field

  • geometry (variable) –

    expected value depends on the value of mode, as follows:
    • ’circle’, ‘circular’: nested 2-tuple, ((qx,qy),radius)

    • ’annular’ or ‘annulus’: nested 2-tuple, ((qx,qy),(radius_i,radius_o))

    Values can be in pixels or calibrated units. Note that (qx,qy) can be skipped, which assumes peaks centered at (0,0).

  • center (bool) – Apply calibration - center coordinate.

  • ellipse (bool) – Apply calibration - elliptical correction.

  • pixel (bool) – Apply calibration - pixel size.

  • rotate (bool) – Apply calibration - QR rotation.

Returns:

virtual_im

Return type:

VirtualImage

graft(node, merge_metadata=True)

Moves the branch beginning node onto this tree at this node.

For the reverse (i.e. grafting from this tree onto another tree) either use that tree’s .graft method, or use this tree’s ._graft.

Accepts:

node (Node): merge_metadata (True, False, or ‘copy’): if True adds the old root’s

metadata to the new root; if False adds no metadata to the new root; if ‘copy’ adds copies of all metadata from the old root to the new root.

Returns:

(Node) this tree’s root node

histogram(mode='cal', sampling=1, weights=None, weights_thresh=0.005)

Returns a 2D histogram of Bragg vector intensities in diffraction space, aka a Bragg vector map.

Parameters:
  • mode (str) – Must be ‘cal’ or ‘raw’. Use the calibrated or raw vector positions.

  • sampling (number) – The sampling rate of the histogram, in units of the camera’s sampling. sampling = 2 upsamples and sampling = 0.5 downsamples, each by a factor of 2.

  • weights (None or array) – If None, use all real space scan positions. Otherwise must be a real space shaped array representing a weighting factor applied to vector intensities from each scan position. If weights is boolean uses beam positions where weights is True. If weights is number-like, scales by the values, and skips positions where wieghts<weights_thresh.

  • weights_thresh (number) – If weights is an array of numbers, pixels where weights>weight_thresh are skipped.

Returns:

An Array with .data representing the data, and .dim[0] and .dim[1] representing the sampling grid.

Return type:

BraggVectorHistogram

mask_in_Q(mask, update_inplace=False, returncalc=True)

Remove peaks which fall inside the diffraction shaped boolean array mask, in raw (uncalibrated) peak positions.

Parameters:
  • mask (2d boolean array) – The mask. Must be diffraction space shaped

  • update_inplace (bool) – If False (default) copies this BraggVectors instance and removes peaks from the copied instance. If True, removes peaks from this instance.

  • returncalc (bool) – Toggles returning the answer

Returns:

bvects

Return type:

BraggVectors

mask_in_R(mask, update_inplace=False, returncalc=True)

Remove peaks which fall inside the real space shaped boolean array mask.

Parameters:
  • mask (2d boolean array) – The mask. Must be real space shaped

  • update_inplace (bool) – If False (default) copies this BraggVectors instance and removes peaks from the copied instance. If True, removes peaks from this instance.

  • returncalc (bool) – Toggles returning the answer

Returns:

bvects

Return type:

BraggVectors

measure_origin(center_guess=None, score_method=None, findcenter='max')

Finds the diffraction shifts of the center beam using the raw Bragg vector measurements.

If a center guess is not specified, first, a guess at the unscattered beam position is determined, either by taking the CoM of the Bragg vector map, or by taking its maximal pixel. Once a unscattered beam position is determined, the Bragg peak closest to this position is identified. The shifts in these peaks positions from their average are returned as the diffraction shifts.

Parameters:
  • center_guess (2-tuple) – initial guess for the center

  • score_method (str) –

    Method used to find center peak
    • ’intensity’: finds the most intense Bragg peak near the center

    • ’distance’: finds the closest Bragg peak to the center

    • ’intensity weighted distance’: determines center through a combination of weighting distance and intensity

  • (str) (findcenter) – position options: ‘CoM’, or ‘max.’ Only used if center_guess is None. CoM finds the center of mass of bragg ector map, ‘max’ uses its brightest pixel.

  • Returns

    (3-tuple): A 3-tuple comprised of:

    • qx0 ((R_Nx,R_Ny)-shaped array): the origin x-coord

    • qy0 ((R_Nx,R_Ny)-shaped array): the origin y-coord

    • braggvectormap ((R_Nx,R_Ny)-shaped array): the Bragg vector map of only the Bragg peaks identified with the unscattered beam. Useful for diagnostic purposes.

measure_origin_beamstop(center_guess, radii, max_dist=None, max_iter=1, **kwargs)

Find the origin from a set of braggpeaks assuming there is a beamstop, by identifying pairs of conjugate peaks inside an annular region and finding their centers of mass.

Parameters:
  • center_guess (2-tuple) – qx0,qy0

  • radii (2-tuple) – the inner and outer radii of the specified annular region

  • max_dist (number) – the maximum allowed distance between the reflection of two peaks to consider them conjugate pairs

  • max_iter (integer) – for values >1, repeats the algorithm after updating center_guess

Returns:

the origins

Return type:

(2d masked array)

static newnode(method)

Decorator which may be added to node methods which product and return a new node. If such a method is decorated with

>>> @newnode

then the new node is added to the parent node’s tree, and a Metadata instance is added to the new node’s metadata which stores information about how the node was created, namely: method’s name, the parent’s class and name, and all the arguments passed to method.

plot(index: tuple[int, int] | list[int], cal: str = 'cal', returnfig: bool = False, **kwargs)

Plot Bragg vector, from a specified index. Calls py4DSTEM.process.diffraction.plot_diffraction_pattern(braggvectors.<cal/raw>[index], **kwargs). Optionally can return the figure.

Parameters:
  • index (tuple[int,int] | list[int]) – scan position for which Bragg vectors to plot

  • cal (str, optional) – Choice to plot calibrated or raw Bragg vectors must be ‘raw’ or ‘cal’, by default ‘cal’

  • returnfig (bool, optional) – Boolean to return figure or not, by default False

Returns:

matplotlib figure, axes returned if returnfig is True

Return type:

tuple (figure, axes)

show_tree(root=False)

Display the object tree. If root is False, displays the branch of the tree downstream from this node. If root is True, displays the full tree from the root node.

to_strainmap(name: str | None = None)

Generate a StrainMap object from the BraggVectors equivalent to py4DSTEM.StrainMap(braggvectors=braggvectors)

Parameters:

name (str, optional) – The name of the strainmap. Defaults to None which reverts to default name ‘strainmap’.

Returns:

A py4DSTEM StrainMap object generated from the BraggVectors

Return type:

py4DSTEM.StrainMap

tree(arg=None, **kwargs)

Usages -

>>> .tree()             # show tree from current node
>>> .tree(show=True)    # show from root
>>> .tree(show=False)   # show from current node
>>> .tree(add=node)     # add a child node
>>> .tree(get='path')   # return a '/' delimited child node
>>> .tree(get='/path')  # as above, starting at root
>>> .tree(cut=True)     # remove/return a branch, keep root metadata
>>> .tree(cut=False)    # remove/return a branch, discard root md
>>> .tree(cut='copy')   # remove/return a branch, copy root metadata
>>> .tree(graft=node)   # remove/graft a branch, keeping root metadata
>>> .tree(graft=(node,True))    # as above
>>> .tree(graft=(node,False))   # as above, discard root metadata
>>> .tree(graft=(node,'copy'))  # as above, copy root metadata

The show, add, and get methods can be accessed directly with

>>> .tree(arg)

for an arg of the appropriate type (bool, Node, and string).

Calibration

class py4DSTEM.Calibration(name: str | None = 'calibration', root: Root | None = None)

Stores calibration measurements.

Usage

For some calibration instance c

>>> c['x'] = y

will set the value of some calibration item called ‘x’ to y, and

>>> _y = c['x']

will return the value currently stored as ‘x’ and assign it to _y. Additionally, for calibration items in the list l given below, the syntax

>>> c.set_p(p)
>>> p = c.get_p()

is equivalent to

>>> c.p = p
>>> p = c.p

is equivalent to

>>> c['p'] = p
>>> p = c['p']

where in the first line of each couplet the parameter p is set and in the second it’s retrieved, for parameters p in the list

l = [

Q_pixel_size, * R_pixel_size, * Q_pixel_units, * R_pixel_units, * qx0, qy0, qx0_mean, qy0_mean, qx0shift, qy0shift, origin, * origin_meas, origin_meas_mask, origin_shift, a, * b, * theta, * p_ellipse, * ellipse, * QR_rotation_degrees, * QR_flip, * QR_rotflip, * probe_semiangle, probe_param, probe_center, probe_convergence_semiangle_pixels, probe_convergence_semiangle_mrad,

]

There are two advantages to using the getter/setter syntax for parameters in l (e.g. either c.set_p or c.p) instead of the normal dictionary-like getter/setter syntax (i.e. c[‘p’]). These are (1) enabling retrieving parameters by beam scan position, and (2) enabling propagation of any calibration changes to downstream data objects which are affected by the altered calibrations. See below.

Get a parameter by beam scan position

Some parameters support retrieval by beam scan position. In these cases, calling

>>> c.get_p(rx,ry)

will return the value of parameter p at beam position (rx,ry). This works only for the above syntax. Using either of

>>> c.p
>>> c['p']

will return an R-space shaped array.

Trigger downstream calibrations

Some objects store their own internal calibration state, which depends on the calibrations stored here. For example, a DataCube stores dimension vectors which calibrate its 4 dimensions, and which depend on the pixel sizes and the origin position.

Modifying certain parameters therefore can trigger other objects which depend on these parameters to re-calibrate themselves by calling their .calibrate() method, if the object has one. Methods marked with a * in the list l above have this property. Only objects registered with the Calibration instance will have their .calibrate method triggered by changing these parameters. An object data can be registered by calling

>>> c.register_target( data )

and deregistered with

>>> c.deregister_target( data )

If an object without a .calibrate method is registerd when a * method is called, nothing happens.

The .calibrate methods are triggered by setting some parameter p using either

>>> c.set_p( val )

or

>>> c.p = val

syntax. Setting the parameter with

>>> c['p'] = val

will not trigger re-calibrations.

Calibration + Data

Data in py4DSTEM is stored in filetree like representations, and Calibration instances are the top-level objects in these trees, in that they live here:

Root

|–metadata | |*—> calibration <—* | |–some_object(e.g.datacube) | |–another_object(e.g.max_dp) | |–etc. |–etc. :

Every py4DSTEM Data object has a tree with a calibration, and calling

>>> data.calibration

will return the that Calibration instance. See also the docstring for the Data class.

Attaching an object to a different Calibration

To modify the calibration associated with some object data, use

>>> c.attach( data )

where c is the new calibration instance. This (1) moves data into the top level of c’s data tree, which means the new calibration will now be accessible normally at

>>> data.calibration

and (2) if and only if data was registered with its old calibration, de-registers it there and registers it with the new calibration. If data was not registered with the old calibration and it should be registered with the new one, c.register_target( data ) should be called.

To attach data to a different location in the calibration instance’s tree, use node.attach( data ). See the Data.attach docstring.

__init__(name: str | None = 'calibration', root: Root | None = None)
Parameters:

name (optional, str) –

attach(data)

Attach data to this calibration instance, placing it in the top level of the Calibration instance’s tree. If data was in a different data tree, remove it. If data was registered with a different calibration instance, de-register it there and register it here. If data was not previously registerd and it should be, after attaching it run self.register_target(data).

register_target(new_target)

Register an object to recieve calls to it calibrate method when certain calibrations get updated

unregister_target(target)

Unlink an object from recieving calls to calibrate when certain calibration values are changed

set_origin_meas(x)
Parameters:

x (2-tuple or 3 uple of 2D R-shaped arrays) – qx0,qy0,[mask]

set_probe_param(x)
Parameters:

x (3-tuple) – (probe size, x0, y0)

to_h5(group)

Saves the metadata dictionary _params to group, then adds the calibration’s target’s list

classmethod from_h5(group)

Takes a valid group for an HDF5 file object which is open in read mode. Determines if it’s a valid Metadata representation, and if so loads and returns it as a Calibration instance. Otherwise, raises an exception.

Accepts:

group (HDF5 group)

Returns:

A Calibration instance

Custom

class py4DSTEM.Custom(name='custom')
__init__(name='custom')
to_h5(group)

Constructs an h5 group, adds metadata, and adds all attributes which point to EMD nodes.

Accepts:

group (h5py Group)

Returns:

(h5py Group) the new node’s Group

add_to_tree(node)

Add an unrooted node as a child of the current, rooted node. To move an already rooted node/branch, use .graft(). To create a rooted node, use Root().

cut_from_tree(root_metadata=True)

Removes a branch from an object tree at this node.

A new root node is created under this object with this object’s name. Metadata from the current root is transferred/not transferred to the new root according to the value of root_metadata.

Accepts:
root_metadata (True, False, or ‘copy’): if True adds the old root’s

metadata to the new root; if False adds no metadata to the new root; if ‘copy’ adds copies of all metadata from the old root to the new root.

Returns:

(Node) the new root node

force_add_to_tree(node)

Add node node as a child of the current node, whether or not node is rooted. If it’s unrooted, performs a simple add. If it is rooted, performs a graft, excluding the root metadata from node.

classmethod from_h5(group)

Takes an h5py Group which is open in read mode. Confirms that a a Node of this name exists in this group, and loads and returns it with it’s metadata.

Accepts:

group (h5py Group)

Returns:

(Node)

get_from_tree(name)

Finds and returns an object from an EMD tree using the string key name, with ‘/’ delimiters between ‘parent/child’ nodes. Search from the root node by adding a leading ‘/’; otherwise, searches from the current node.

graft(node, merge_metadata=True)

Moves the branch beginning node onto this tree at this node.

For the reverse (i.e. grafting from this tree onto another tree) either use that tree’s .graft method, or use this tree’s ._graft.

Accepts:

node (Node): merge_metadata (True, False, or ‘copy’): if True adds the old root’s

metadata to the new root; if False adds no metadata to the new root; if ‘copy’ adds copies of all metadata from the old root to the new root.

Returns:

(Node) this tree’s root node

static newnode(method)

Decorator which may be added to node methods which product and return a new node. If such a method is decorated with

>>> @newnode

then the new node is added to the parent node’s tree, and a Metadata instance is added to the new node’s metadata which stores information about how the node was created, namely: method’s name, the parent’s class and name, and all the arguments passed to method.

show_tree(root=False)

Display the object tree. If root is False, displays the branch of the tree downstream from this node. If root is True, displays the full tree from the root node.

tree(arg=None, **kwargs)

Usages -

>>> .tree()             # show tree from current node
>>> .tree(show=True)    # show from root
>>> .tree(show=False)   # show from current node
>>> .tree(add=node)     # add a child node
>>> .tree(get='path')   # return a '/' delimited child node
>>> .tree(get='/path')  # as above, starting at root
>>> .tree(cut=True)     # remove/return a branch, keep root metadata
>>> .tree(cut=False)    # remove/return a branch, discard root md
>>> .tree(cut='copy')   # remove/return a branch, copy root metadata
>>> .tree(graft=node)   # remove/graft a branch, keeping root metadata
>>> .tree(graft=(node,True))    # as above
>>> .tree(graft=(node,False))   # as above, discard root metadata
>>> .tree(graft=(node,'copy'))  # as above, copy root metadata

The show, add, and get methods can be accessed directly with

>>> .tree(arg)

for an arg of the appropriate type (bool, Node, and string).

Data

class py4DSTEM.Data(calibration=None)

The purpose of the Data class is to ensure calibrations are linked to data containing class instances, while allowing multiple objects to share a single Calibration. The calibrations of a Data instance data is accessible as

>>> data.calibration

In py4DSTEM, Data containing objects are stored internally in filetree like representations, defined by the EMD1.0 and emdfile specifications, e.g.

Root

|–metadata | |–calibration | |–some_object(e.g.datacube) | |–another_object(e.g.max_dp) | |–etc. | |–one_more_object(e.g.crystal) | |–etc. :

Calibrations are metadata which always live in the root of such a tree. Running data.calibration returns the calibrations from the tree root, and therefore the same calibration instance is referred to be all objects in the same tree. The root itself is accessible from any Data instance as

>>> data.root

To examine the tree of a Data instance, in a Python interpreter do

>>> data.tree(True)

to display the whole data tree, and

>>> data.tree()

to display the tree of from the current node on, i.e. the branch downstream of data.

Calling

>>> data.calibration

will raise a warning and return None if no root calibrations are found.

Some objects should be modified when the calibrations change - these objects must have .calibrate() method, which is called any time relevant calibration parameters change if the object has been registered with the calibrations.

To transfer data from it’s current tree to another existing tree, use

>>> data.attach(some_other_data)

which will move the data to the new tree. If the data was registered with it’s old calibrations, this will also de-register it there and register it with the new calibrations such that .calibrate() is called when it should be.

See also the Calibration docstring.

__init__(calibration=None)
attach(node)

Attach node to the current object’s tree, attaching calibration and detaching calibrations as needed.

DataCube

class py4DSTEM.DataCube(data: ndarray, name: str | None = 'datacube', slicelabels: bool | list | None = None, calibration: Calibration | None = None)

Storage and processing methods for 4D-STEM datasets.

__init__(data: ndarray, name: str | None = 'datacube', slicelabels: bool | list | None = None, calibration: Calibration | None = None)
Accepts:

data (np.ndarray): the data name (str): the name of the datacube calibration (None or Calibration or ‘pass’): default (None)

creates and attaches a new Calibration instance to root metadata, or, passing a Calibration instance uses this instead.

slicelabels (None or list): names for slices if this is a

stack of datacubes

Returns:

A new DataCube instance.

calibrate()

Calibrate the coordinate axes of the datacube. Using the calibrations at self.calibration, sets the 4 dim vectors (Qx,Qy,Rx,Ry) according to the pixel size, units and origin positions, then updates the meshgrids representing Q and R space.

copy()

Copys datacube

add(data, name='')

Adds a block of data to the DataCube’s tree. If data is an instance of an EMD/py4DSTEM class, add it to the tree. If it’s a numpy array, turn it into an Array instance, then save to the tree.

set_scan_shape(Rshape)

Reshape the data given the real space scan shape.

Accepts:

Rshape (2-tuple)

swap_RQ()

Swaps the first and last two dimensions of the 4D datacube.

swap_Rxy()

Swaps the real space x and y coordinates.

swap_Qxy()

Swaps the diffraction space x and y coordinates.

crop_Q(ROI)

Crops the data in diffraction space about the region specified by ROI.

Accepts:

ROI (4-tuple): Specifies (Qx_min,Qx_max,Qy_min,Qy_max)

crop_R(ROI)

Crops the data in real space about the region specified by ROI.

Accepts:

ROI (4-tuple): Specifies (Rx_min,Rx_max,Ry_min,Ry_max)

bin_Q(N, dtype=None)

Bins the data in diffraction space by bin factor N

Parameters:
  • N (int) – The binning factor

  • dtype (a datatype (optional)) – Specify the datatype for the output. If not passed, the datatype is left unchanged

Returns:

datacube

Return type:

DataCube

pad_Q(N=None, output_size=None)

Pads the data in diffraction space by pad factor N, or to match output_size.

Accepts:

N (float, or Sequence[float]): the padding factor output_size ((int,int)): the padded output size

resample_Q(N=None, output_size=None, method='bilinear', conserve_array_sums=False)

Resamples the data in diffraction space by resampling factor N, or to match output_size, using either ‘fourier’ or ‘bilinear’ interpolation.

Accepts:

N (float, or Sequence[float]): the resampling factor output_size ((int,int)): the resampled output size method (str): ‘fourier’ or ‘bilinear’ (default)

bin_Q_mmap(N, dtype=<class 'numpy.float32'>)

Bins the data in diffraction space by bin factor N for memory mapped data

Accepts:

N (int): the binning factor dtype: the data type

bin_R(N)

Bins the data in real space by bin factor N

Accepts:

N (int): the binning factor

thin_R(N)

Reduces the data in real space by skipping every N patterns in the x and y directions.

Accepts:

N (int): the thinning factor

filter_hot_pixels(thresh, ind_compare=1, return_mask=False)

This function performs pixel filtering to remove hot / bright pixels. We first compute a moving local ordering filter, applied to the mean diffraction image. This ordering filter will return a single value from the local sorted intensity values, given by ind_compare. ind_compare=0 would be the highest intensity, =1 would be the second hightest, etc. Next, a mask is generated for all pixels which are least a value thresh higher than the local ordering filter output. Finally, we loop through all diffraction images, and any pixels defined by mask are replaced by their 3x3 local median.

Parameters:
  • datacube (DataCube) –

  • thresh (float) – threshold for replacing hot pixels, if pixel value minus local ordering filter exceeds it.

  • ind_compare (int) – which median filter value to compare against. 0 = brightest pixel, 1 = next brightest, etc.

  • return_mask (bool) – if True, returns the filter mask

Returns:

datacube (DataCube) mask (optional, boolean Array) the bad pixel mask

median_filter_masked_pixels(mask, kernel_width: int = 3)

This function fixes a datacube where the same pixels are consistently bad. It requires a mask that identifies all the bad pixels in the dataset. Then for each diffraction pattern, a median kernel is applied around each bad pixel with the specified width.

get_vacuum_probe(ROI=None, align=True, mask=None, threshold=0.0, expansion=12, opening=3, verbose=False, returncalc=True)

Computes a vacuum probe.

Which diffraction patterns are included in the calculation is specified by the ROI parameter. Diffraction patterns are aligned before averaging if align is True (default). A global mask is applied to each diffraction pattern before aligning/averaging if mask is specified. After averaging, a final masking step is applied according to the parameters threshold, expansion, and opening.

Parameters:
  • ROI (optional, boolean array or len 4 list/tuple) – If unspecified, uses the whole datacube. If a boolean array is passed must be real-space shaped, and True pixels are used. If a 4-tuple is passed, uses the region inside the limits (rx_min,rx_max,ry_min,ry_max)

  • align (optional, bool) – if True, aligns the probes before averaging

  • mask (optional, array) – mask applied to each diffraction pattern before alignment and averaging

  • threshold (float) – in the final masking step, values less than max(probe)*threshold are considered outside the probe

  • expansion (int) – number of pixels by which the final mask is expanded after thresholding

  • opening (int) – size of binary opening applied to the final mask to eliminate stray bright pixels

  • verbose (bool) – toggles verbose output

  • returncalc (bool) – if True, returns the answer

Returns:

probe – the vacuum probe

Return type:

Probe, optional

get_probe_size(dp=None, thresh_lower=0.01, thresh_upper=0.99, N=100, plot=False, returncal=True, write_to_cal=True, **kwargs)

Gets the center and radius of the probe in the diffraction plane.

The algorithm is as follows: First, create a series of N binary masks, by thresholding the diffraction pattern DP with a linspace of N thresholds from thresh_lower to thresh_upper, measured relative to the maximum intensity in DP. Using the area of each binary mask, calculate the radius r of a circular probe. Because the central disk is typically very intense relative to the rest of the DP, r should change very little over a wide range of intermediate values of the threshold. The range in which r is trustworthy is found by taking the derivative of r(thresh) and finding identifying where it is small. The radius is taken to be the mean of these r values. Using the threshold corresponding to this r, a mask is created and the CoM of the DP times this mask it taken. This is taken to be the origin x0,y0.

Parameters:
  • dp (str or array) – specifies the diffraction pattern in which to find the central disk. A position averaged, or shift-corrected and averaged, DP works best. If mode is None, the diffraction pattern stored in the tree from ‘get_dp_mean’ is used. If mode is a string it specifies the name of another virtual diffraction pattern in the tree. If mode is an array, the array is used to calculate probe size.

  • thresh_lower (float, 0 to 1) – the lower limit of threshold values

  • thresh_upper (float, 0 to 1) – the upper limit of threshold values

  • N (int) – the number of thresholds / masks to use

  • plot (bool) – if True plots results

  • plot_params (dict) – dictionary to modify defaults in plot

  • return_calc (bool) – if True returns 3-tuple described below

  • write_to_cal (bool) – if True, looks for a Calibration instance and writes the measured probe radius there

Returns:

A 3-tuple containing:

  • r: (float) the central disk radius, in pixels

  • x0: (float) the x position of the central disk center

  • y0: (float) the y position of the central disk center

Return type:

(3-tuple)

find_Bragg_disks(template, data=None, radial_bksb=False, filter_function=None, corrPower=1, sigma=None, sigma_dp=0, sigma_cc=2, subpixel='multicorr', upsample_factor=16, minAbsoluteIntensity=0, minRelativeIntensity=0.005, relativeToPeak=0, minPeakSpacing=60, edgeBoundary=20, maxNumPeaks=70, CUDA=False, CUDA_batched=True, distributed=None, ML=False, ml_model_path=None, ml_num_attempts=1, ml_batch_size=8, name='braggvectors', returncalc=True)

Finds the Bragg disks in the diffraction patterns represented by data by cross/phase correlatin with template.

Behavior depends on data. If it is None (default), runs on the whole DataCube, and stores the output in its tree. Otherwise, nothing is stored in tree, but some value is returned. Valid entries are:

  • a 2-tuple of numbers (rx,ry): run on this diffraction image,

    and return a QPoints instance

  • a 2-tuple of arrays (rx,ry): run on these diffraction images,

    and return a list of QPoints instances

  • an Rspace shapped 2D boolean array: run on the diffraction images

    specified by the True counts and return a list of QPoints instances

For disk detection on a full DataCube, the calculation can be performed on the CPU, GPU or a cluster. By default the CPU is used. If CUDA is set to True, tries to use the GPU. If CUDA_batched is also set to True, batches the FFT/IFFT computations on the GPU. For distribution to a cluster, distributed must be set to a dictionary, with contents describing how distributed processing should be performed - see below for details.

For each diffraction pattern, the algorithm works in 4 steps:

  1. any pre-processing is performed to the diffraction image. This is accomplished by passing a callable function to the argument filter_function, a bool to the argument radial_bksb, or a value >0 to sigma_dp. If none of these are passed, this step is skipped.

  2. the diffraction image is cross correlated with the template. Phase/hybrid correlations can be used instead by setting the corrPower argument. Cross correlation can be skipped entirely, and the subsequent steps performed directly on the diffraction image instead of the cross correlation, by passing None to template.

  3. the maxima of the cross correlation are located and their positions and intensities stored. The cross correlation may be passed through a gaussian filter first by passing the sigma_cc argument. The method for maximum detection can be set with the subpixel parameter. Options, from something like fastest/least precise to slowest/most precise are ‘pixel’, ‘poly’, and ‘multicorr’.

  4. filtering is applied to remove untrusted or undesired positive counts, based on their intensity (minRelativeIntensity,`relativeToPeak`, minAbsoluteIntensity) their proximity to one another or the image edge (minPeakSpacing, edgeBoundary), and the total number of peaks per pattern (maxNumPeaks).

Parameters:
  • template (2D array) – the vacuum probe template, in real space. For Probe instances, this is probe.kernel. If None, does not perform a cross correlation.

  • data (variable) – see above

  • radial_bksb (bool) – if True, computes a radial background given by the median of the (circular) polar transform of each each diffraction pattern, and subtracts this background from the pattern before applying any filter function and computing the cross correlation. The origin position must be set in the datacube’s calibrations. Currently only supported for full datacubes on the CPU.

  • filter_function (callable) – filtering function to apply to each diffraction pattern before peak finding. Must be a function of only one argument (the diffraction pattern) and return the filtered diffraction pattern. The shape of the returned DP must match the shape of the probe kernel (but does not need to match the shape of the input diffraction pattern, e.g. the filter can be used to bin the diffraction pattern). If using distributed disk detection, the function must be able to be pickled with by dill.

  • corrPower (float between 0 and 1, inclusive) – the cross correlation power. A value of 1 corresponds to a cross correlation, 0 corresponds to a phase correlation, and intermediate values correspond to hybrid correlations.

  • sigma (float) – alias for sigma_cc

  • sigma_dp (float) – if >0, a gaussian smoothing filter with this standard deviation is applied to the diffraction pattern before maxima are detected

  • sigma_cc (float) – if >0, a gaussian smoothing filter with this standard deviation is applied to the cross correlation before maxima are detected

  • subpixel (str) –

    Whether to use subpixel fitting, and which algorithm to use. Must be in (‘none’,’poly’,’multicorr’).

    • ’none’: performs no subpixel fitting

    • ’poly’: polynomial interpolation of correlogram peaks (default)

    • ’multicorr’: uses the multicorr algorithm with DFT upsampling

  • upsample_factor (int) – upsampling factor for subpixel fitting (only used when subpixel=’multicorr’)

  • minAbsoluteIntensity (float) – the minimum acceptable correlation peak intensity, on an absolute scale

  • minRelativeIntensity (float) – the minimum acceptable correlation peak intensity, relative to the intensity of the brightest peak

  • relativeToPeak (int) – specifies the peak against which the minimum relative intensity is measured – 0=brightest maximum. 1=next brightest, etc.

  • minPeakSpacing (float) – the minimum acceptable spacing between detected peaks

  • (int) (edgeBoundary) – the diffraction image edge, in pixels.

  • maxNumPeaks (int) – the maximum number of peaks to return

  • CUDA (bool) – If True, import cupy and use an NVIDIA GPU to perform disk detection

  • CUDA_batched (bool) – If True, and CUDA is selected, the FFT and IFFT steps of disk detection are performed in batches to better utilize GPU resources.

  • distributed (dict) –

    contains information for parallel processing using an IPyParallel or Dask distributed cluster. Valid keys are:

    • ipyparallel (dict):

    • client_file (str): path to client json for connecting to your

      existing IPyParallel cluster

    • dask (dict): client (object): a dask client that connects to

      your existing Dask cluster

    • data_file (str): the absolute path to your original data

      file containing the datacube

    • cluster_path (str): defaults to the working directory during

      processing

    if distributed is None, which is the default, processing will be in serial

  • name (str) – name for the output BraggVectors

  • returncalc (bool) – if True, returns the answer

Returns:

See above.

Return type:

variable

get_beamstop_mask(threshold=0.25, distance_edge=2.0, include_edges=True, sigma=0, use_max_dp=False, scale_radial=None, name='mask_beamstop', returncalc=True)

This function uses the mean diffraction pattern plus a threshold to create a beamstop mask.

Parameters:
  • threshold (float) – Value from 0 to 1 defining initial threshold for beamstop mask, taken from the sorted intensity values - 0 is the dimmest pixel, while 1 uses the brighted pixels.

  • distance_edge (float) – How many pixels to expand the mask.

  • include_edges (bool) – If set to True, edge pixels will be included in the mask.

  • sigma (float) – Gaussain blur std to apply to image before thresholding.

  • use_max_dp (bool) – Use the max DP instead of the mean DP.

  • scale_radial (float) – Scale from center of image by this factor (can help with edge)

  • name (string) – Name of the output array.

  • returncalc (bool) – Set to true to return the result.

Returns:

if returncalc is True, returns the beamstop mask

Return type:

(Optional)

get_radial_bkgrnd(rx, ry, sigma=2)

Computes and returns a background image for the diffraction pattern at (rx,ry), populated by radial rings of constant intensity about the origin, with the value of each ring given by the median value of the diffraction pattern at that radial distance.

Parameters:
  • rx (int) – The x-coord of the beam position

  • ry (int) – The y-coord of the beam position

  • sigma (number) – If >0, applying a gaussian smoothing in the radial direction before returning

Returns:

background – The radial background

Return type:

ndarray

get_radial_bksb_dp(rx, ry, sigma=2)

Computes and returns the diffraction pattern at beam position (rx,ry) with a radial background subtracted. See the docstring for datacube.get_radial_background for more info.

Parameters:
  • rx (int) – The x-coord of the beam position

  • ry (int) – The y-coord of the beam position

  • sigma (number) – If >0, applying a gaussian smoothing in the radial direction before returning

Returns:

data – The radial background subtracted diffraction image

Return type:

ndarray

get_local_ave_dp(rx, ry, radial_bksb=False, sigma=2, braggmask=False, braggvectors=None, braggmask_radius=None)

Computes and returns the diffraction pattern at beam position (rx,ry) after weighted local averaging with its nearest-neighbor patterns, using a 3x3 gaussian kernel for the weightings.

Parameters:
  • rx (int) – The x-coord of the beam position

  • ry (int) – The y-coord of the beam position

  • radial_bksb (bool) – It True, apply a radial background subtraction to each pattern before averaging

  • sigma (number) – If radial_bksb is True, use this sigma for radial smoothing of the background

  • braggmask (bool) – If True, masks bragg scattering at each scan position before averaging. braggvectors and braggmask_radius must be specified.

  • braggvectors (BraggVectors) – The Bragg vectors to use for masking

  • braggmask_radius (number) – The radius about each Bragg point to mask

Returns:

data – The radial background subtracted diffraction image

Return type:

ndarray

get_braggmask(braggvectors, rx, ry, radius)

Returns a boolean mask which is False in a radius of radius around each bragg scattering vector at scan position (rx,ry).

Parameters:
  • braggvectors (BraggVectors) – The bragg vectors

  • rx (int) – The x-coord of the beam position

  • ry (int) – The y-coord of the beam position

  • radius (number) – mask pixels about each bragg vector to this radial distance

Returns:

mask

Return type:

boolean ndarray

add_to_tree(node)

Add an unrooted node as a child of the current, rooted node. To move an already rooted node/branch, use .graft(). To create a rooted node, use Root().

attach(node)

Attach node to the current object’s tree, attaching calibration and detaching calibrations as needed.

cut_from_tree(root_metadata=True)

Removes a branch from an object tree at this node.

A new root node is created under this object with this object’s name. Metadata from the current root is transferred/not transferred to the new root according to the value of root_metadata.

Accepts:
root_metadata (True, False, or ‘copy’): if True adds the old root’s

metadata to the new root; if False adds no metadata to the new root; if ‘copy’ adds copies of all metadata from the old root to the new root.

Returns:

(Node) the new root node

dim(n)

Return the n’th dim vector

force_add_to_tree(node)

Add node node as a child of the current node, whether or not node is rooted. If it’s unrooted, performs a simple add. If it is rooted, performs a graft, excluding the root metadata from node.

classmethod from_h5(group)

Takes an h5py Group which is open in read mode. Confirms that a a Node of this name exists in this group, and loads and returns it with it’s metadata.

Accepts:

group (h5py Group)

Returns:

(Node)

static get_calibrated_detector_geometry(calibration, mode, geometry, centered, calibrated)

Determine the detector geometry in pixels, given some mode and geometry in calibrated units, where the calibration state is specified by { centered, calibrated}

Parameters:
  • calibration (Calibration) – Used to retrieve the center positions. If None, confirms that centered and calibrated are False then passes, otherwise raises an exception

  • mode (str) – see the DataCube.get_virtual_image docstring

  • geometry (variable) – see the DataCube.get_virtual_image docstring

  • centered (bool) – see the DataCube.get_virtual_image docstring

  • calibrated (bool) – see the DataCube.get_virtual_image docstring

Returns:

geo – the geometry in detector pixels

Return type:

tuple

get_dim(n)

Return the n’th dim vector

get_dim_name(n)

Get the n’th dim vector name

get_dim_units(n)

Return the n’th dim vector units

get_dp_max(returncalc=True)

Calculates the max diffraction pattern.

Calls DataCube.get_virtual_diffraction - see that method’s docstring for more custimizable virtual diffraction.

Parameters:

returncalc (bool) – toggles returning the answer

Returns:

max_dp

Return type:

VirtualDiffraction

get_dp_mean(returncalc=True)

Calculates the mean diffraction pattern.

Calls DataCube.get_virtual_diffraction - see that method’s docstring for more custimizable virtual diffraction.

Parameters:

returncalc (bool) – toggles returning the answer

Returns:

mean_dp

Return type:

VirtualDiffraction

get_dp_median(returncalc=True)

Calculates the max diffraction pattern.

Calls DataCube.get_virtual_diffraction - see that method’s docstring for more custimizable virtual diffraction.

Parameters:

returncalc (bool) – toggles returning the answer

Returns:

max_dp

Return type:

VirtualDiffraction

get_from_tree(name)

Finds and returns an object from an EMD tree using the string key name, with ‘/’ delimiters between ‘parent/child’ nodes. Search from the root node by adding a leading ‘/’; otherwise, searches from the current node.

get_virtual_diffraction(method, mask=None, shift_center=False, subpixel=False, verbose=True, name='virtual_diffraction', returncalc=True)

Function to calculate virtual diffraction images.

Parameters:
  • method (str) – defines method used for averaging/combining diffraction patterns. Options are (‘mean’, ‘median’, ‘max’)

  • mask (None or 2D array) – if None (default), all pixels are used. Otherwise, must be a boolean or floating point or complex array with the same shape as real space. For bool arrays, only True pixels are used in the computation. Otherwise a weighted average is performed.

  • shift_center (bool) – toggles shifting the diffraction patterns to account for beam shift. Currently only supported for ‘max’ and ‘mean’ modes. Default is False.

  • subpixel (bool) – if shift_center is True, toggles subpixel shifts via Fourier interpolation. Ignored if shift_center is False.

  • verbose (bool) – toggles progress bar

  • name (string) – name for the output DiffractionImage instance

  • returncalc (bool) – toggles returning the output

Returns:

diff_im

Return type:

DiffractionImage

get_virtual_image(mode, geometry, centered=False, calibrated=False, shift_center=False, subpixel=False, verbose=True, dask=False, return_mask=False, name='virtual_image', returncalc=True, test_config=False)

Calculate a virtual image.

The detector is determined by the combination of the mode and geometry arguments, supporting point, circular, rectangular, annular, and custom mask detectors. The values passed to geometry may be given with respect to an origin at the corner of the detector array or with respect to the calibrated center position, and in units of pixels or real calibrated units, depending on the values of the centered and calibrated arguments, respectively. The mask may be shifted pattern-by-pattern to account for diffraction scan shifts using the shift_center argument.

The computed virtual image is stored in the datacube’s tree, and is also returned by default.

Parameters:
  • mode (str) –

    defines geometry mode for calculating virtual image, and the expected input for the geometry argument. options:

    • ’point’: uses a single pixel detector

    • ’circle’, ‘circular’: uses a round detector, like bright field

    • ’annular’, ‘annulus’: uses an annular detector, like dark field

    • ’rectangle’, ‘square’, ‘rectangular’: uses rectangular detector

    • ’mask’: any diffraction-space shaped 2D array, representing a flexible detector

  • geometry (variable) –

    the expected value of this argument is determined by mode as follows:

    • ’point’: 2-tuple, (qx,qy), ints

    • ’circle’, ‘circular’: nested 2-tuple, ((qx,qy),radius),

    • ’annular’, ‘annulus’: nested 2-tuple, ((qx,qy),(radius_i,radius_o)),

    • ’rectangle’, ‘square’, ‘rectangular’: 4-tuple, (xmin,xmax,ymin,ymax)

    • mask: any boolean or floating point 2D array with the same

      size as datacube.Qshape

  • centered (bool) – if False, the origin is in the upper left corner. If True, the origin is set to the mean origin in the datacube calibrations, so that a bright-field image could be specified with, e.g., geometry=((0,0),R). The origin can set with datacube.calibration.set_origin(). For mode=”mask”, has no effect. Default is False.

  • calibrated (bool) – if True, geometry is specified in units of ‘A^-1’ instead of pixels. The datacube’s calibrations must have its “Q_pixel_units” parameter set to “A^-1”. For mode=”mask”, has no effect. Default is False.

  • shift_center (bool) – if True, the mask is shifted at each real space position to account for any shifting of the origin of the diffraction images. The datacube’s calibration[‘origin’] parameter must be set. The shift applied to each pattern is the difference between the local origin position and the mean origin position over all patterns, rounded to the nearest integer for speed. Default is False. If shift_center is True, centered is automatically set to True.

  • subpixel (bool) – if True, applies subpixel shifts to virtual image

  • verbose (bool) – toggles a progress bar

  • dask (bool) – if True, use dask to distribute the calculation

  • return_mask (bool) – if False (default) returns a virtual image as usual. Otherwise does not compute or return a virtual image, instead finding and returning the mask that will be used in subsequent calls to this function using these same parameters. In this case, must be either True or a 2-tuple of integers corresponding to (rx,ry). If True is passed, returns the mask used if shift_center is set to False. If a 2-tuple is passed, returns the mask used at scan position (rx,ry) if shift_center is set to True. Nothing is added to the datacube’s tree.

  • name (str) – the output object’s name

  • returncalc (bool) – if True, returns the output

  • test_config (bool) – if True, prints the Boolean values of (centered,`calibrated`,`shift_center`). Does not compute the virtual image.

Returns:

virt_im

Return type:

VirtualImage (optional, if returncalc is True)

graft(node, merge_metadata=True)

Moves the branch beginning node onto this tree at this node.

For the reverse (i.e. grafting from this tree onto another tree) either use that tree’s .graft method, or use this tree’s ._graft.

Accepts:

node (Node): merge_metadata (True, False, or ‘copy’): if True adds the old root’s

metadata to the new root; if False adds no metadata to the new root; if ‘copy’ adds copies of all metadata from the old root to the new root.

Returns:

(Node) this tree’s root node

make_bragg_mask(Qshape, g1, g2, radius, origin, max_q, return_sum=True, include_origin=True, rotation_deg=0, **kwargs)

Creates and returns a mask consisting of circular disks about the points of a 2D lattice.

Parameters:
  • Qshape (2 tuple) – the shape of diffraction space

  • g1 (len 2 array or tuple) – the lattice vectors

  • g2 (len 2 array or tuple) – the lattice vectors

  • radius (number) – the disk radius

  • origin (len 2 array or tuple) – the origin

  • max_q (nuumber) – the maxima distance to tile to

  • return_sum (bool) – if False, return a 3D array, where each slice contains a single disk; if False, return a single 2D masks of all disks

  • include_origin (bool) – if False, removes origin disk

  • rotation_deg (float) – rotate g1 and g2 vectors

Returns:

(2 or 3D array) the mask

static make_detector(shape, mode, geometry)

Generate a 2D mask representing a detector function.

Parameters:
  • shape (2-tuple) – defines shape of mask. Should be the shape of diffraction space.

  • mode (str) – defines geometry mode for calculating virtual image. See the docstring for DataCube.get_virtual_image

  • geometry (variable) – defines geometry for calculating virtual image. See the docstring for DataCube.get_virtual_image

Returns:

detector_mask

Return type:

2d array

static newnode(method)

Decorator which may be added to node methods which product and return a new node. If such a method is decorated with

>>> @newnode

then the new node is added to the parent node’s tree, and a Metadata instance is added to the new node’s metadata which stores information about how the node was created, namely: method’s name, the parent’s class and name, and all the arguments passed to method.

position_detector(mode, geometry, data=None, centered=None, calibrated=None, shift_center=False, subpixel=True, scan_position=None, invert=False, color='r', alpha=0.7, **kwargs)

Position a virtual detector by displaying a mask over a diffraction space image. Calling .get_virtual_image() using the same mode and geometry parameters will compute a virtual image using this detector.

Parameters:
  • mode (str) – see the DataCube.get_virtual_image docstring

  • geometry (variable) – see the DataCube.get_virtual_image docstring

  • data (None or 2d-array or 2-tuple of ints) – The diffraction image to overlay the mask on. If None (default), looks for a max or mean or median diffraction image in this order and if found, uses it, otherwise, uses the diffraction pattern at scan position (0,0). If a 2d array is passed, must be diffraction space shaped array. If a 2-tuple is passed, uses the diffraction pattern at scan position (rx,ry).

  • centered (bool) – see the DataCube.get_virtual_image docstring

  • calibrated (bool) – see the DataCube.get_virtual_image docstring

  • shift_center (None or bool or 2-tuple of ints) – If None (default) and data is either None or an array, the mask is not shifted. If None and data is a 2-tuple, shifts the mask according to the origin at the scan position (rx,ry) specified in data. If False, does not shift the mask. If True and data is a 2-tuple, shifts the mask accordingly, and if True and data is any other value, raises an error. If shift_center is a 2-tuple, shifts the mask according to the origin value at this 2-tuple regardless of the value of data (enabling e.g. overlaying the mask for a specific scan position on a max or mean diffraction image.)

  • subpixel (bool) – if True, applies subpixel shifts to virtual image

  • invert (bool) – if True, invert the masked pixel (i.e. pixels outside the detector are overlaid with a mask)

  • color (any matplotlib color specification) – the mask color

  • alpha (number) – the mask transparency

  • kwargs (dict) – Any additional arguments are passed on to the show() function

set_dim(n: int, dim: list | ndarray, units: str | None = None, name: str | None = None)

Sets the n’th dim vector, using dim as described in the Array documentation. If units and/or name are passed, sets these values for the n’th dim vector.

Accepts:

n (int): specifies which dim vector dim (list or array): length must be either 2, or equal to the

length of the n’th axis of the data array

units (Optional, str): name: (Optional, str):

set_dim_name(n: int, name: str)

Sets the n’th dim vector name to name.

Accepts:

n (int): specifies which dim vector name (str): new name

set_dim_units(n: int, units: str)

Sets the n’th dim vector units to units.

Accepts:

n (int): specifies which dim vector units (str): new units

show_tree(root=False)

Display the object tree. If root is False, displays the branch of the tree downstream from this node. If root is True, displays the full tree from the root node.

to_h5(group)

Takes an h5py Group instance and creates a subgroup containing this Array, tags indicating its EMD type and Python class, and the array’s data and metadata.

Accepts:

group (h5py Group)

Returns:

(h5py Group) the new array’s Group

tree(arg=None, **kwargs)

Usages -

>>> .tree()             # show tree from current node
>>> .tree(show=True)    # show from root
>>> .tree(show=False)   # show from current node
>>> .tree(add=node)     # add a child node
>>> .tree(get='path')   # return a '/' delimited child node
>>> .tree(get='/path')  # as above, starting at root
>>> .tree(cut=True)     # remove/return a branch, keep root metadata
>>> .tree(cut=False)    # remove/return a branch, discard root md
>>> .tree(cut='copy')   # remove/return a branch, copy root metadata
>>> .tree(graft=node)   # remove/graft a branch, keeping root metadata
>>> .tree(graft=(node,True))    # as above
>>> .tree(graft=(node,False))   # as above, discard root metadata
>>> .tree(graft=(node,'copy'))  # as above, copy root metadata

The show, add, and get methods can be accessed directly with

>>> .tree(arg)

for an arg of the appropriate type (bool, Node, and string).

DiffractionSlice

class py4DSTEM.DiffractionSlice(data: ndarray, name: str | None = 'diffractionslice', units: str | None = 'intensity', slicelabels: bool | list | None = None, calibration=None)

Stores a diffraction-space shaped 2D data array.

__init__(data: ndarray, name: str | None = 'diffractionslice', units: str | None = 'intensity', slicelabels: bool | list | None = None, calibration=None)
Accepts:

data (np.ndarray): the data name (str): the name of the diffslice units (str): units of the pixel values slicelabels(None or list): names for slices if this is a 3D stack

Returns:

(DiffractionSlice instance)

add_to_tree(node)

Add an unrooted node as a child of the current, rooted node. To move an already rooted node/branch, use .graft(). To create a rooted node, use Root().

attach(node)

Attach node to the current object’s tree, attaching calibration and detaching calibrations as needed.

cut_from_tree(root_metadata=True)

Removes a branch from an object tree at this node.

A new root node is created under this object with this object’s name. Metadata from the current root is transferred/not transferred to the new root according to the value of root_metadata.

Accepts:
root_metadata (True, False, or ‘copy’): if True adds the old root’s

metadata to the new root; if False adds no metadata to the new root; if ‘copy’ adds copies of all metadata from the old root to the new root.

Returns:

(Node) the new root node

dim(n)

Return the n’th dim vector

force_add_to_tree(node)

Add node node as a child of the current node, whether or not node is rooted. If it’s unrooted, performs a simple add. If it is rooted, performs a graft, excluding the root metadata from node.

classmethod from_h5(group)

Takes an h5py Group which is open in read mode. Confirms that a a Node of this name exists in this group, and loads and returns it with it’s metadata.

Accepts:

group (h5py Group)

Returns:

(Node)

get_dim(n)

Return the n’th dim vector

get_dim_name(n)

Get the n’th dim vector name

get_dim_units(n)

Return the n’th dim vector units

get_from_tree(name)

Finds and returns an object from an EMD tree using the string key name, with ‘/’ delimiters between ‘parent/child’ nodes. Search from the root node by adding a leading ‘/’; otherwise, searches from the current node.

graft(node, merge_metadata=True)

Moves the branch beginning node onto this tree at this node.

For the reverse (i.e. grafting from this tree onto another tree) either use that tree’s .graft method, or use this tree’s ._graft.

Accepts:

node (Node): merge_metadata (True, False, or ‘copy’): if True adds the old root’s

metadata to the new root; if False adds no metadata to the new root; if ‘copy’ adds copies of all metadata from the old root to the new root.

Returns:

(Node) this tree’s root node

static newnode(method)

Decorator which may be added to node methods which product and return a new node. If such a method is decorated with

>>> @newnode

then the new node is added to the parent node’s tree, and a Metadata instance is added to the new node’s metadata which stores information about how the node was created, namely: method’s name, the parent’s class and name, and all the arguments passed to method.

set_dim(n: int, dim: list | ndarray, units: str | None = None, name: str | None = None)

Sets the n’th dim vector, using dim as described in the Array documentation. If units and/or name are passed, sets these values for the n’th dim vector.

Accepts:

n (int): specifies which dim vector dim (list or array): length must be either 2, or equal to the

length of the n’th axis of the data array

units (Optional, str): name: (Optional, str):

set_dim_name(n: int, name: str)

Sets the n’th dim vector name to name.

Accepts:

n (int): specifies which dim vector name (str): new name

set_dim_units(n: int, units: str)

Sets the n’th dim vector units to units.

Accepts:

n (int): specifies which dim vector units (str): new units

show_tree(root=False)

Display the object tree. If root is False, displays the branch of the tree downstream from this node. If root is True, displays the full tree from the root node.

to_h5(group)

Takes an h5py Group instance and creates a subgroup containing this Array, tags indicating its EMD type and Python class, and the array’s data and metadata.

Accepts:

group (h5py Group)

Returns:

(h5py Group) the new array’s Group

tree(arg=None, **kwargs)

Usages -

>>> .tree()             # show tree from current node
>>> .tree(show=True)    # show from root
>>> .tree(show=False)   # show from current node
>>> .tree(add=node)     # add a child node
>>> .tree(get='path')   # return a '/' delimited child node
>>> .tree(get='/path')  # as above, starting at root
>>> .tree(cut=True)     # remove/return a branch, keep root metadata
>>> .tree(cut=False)    # remove/return a branch, discard root md
>>> .tree(cut='copy')   # remove/return a branch, copy root metadata
>>> .tree(graft=node)   # remove/graft a branch, keeping root metadata
>>> .tree(graft=(node,True))    # as above
>>> .tree(graft=(node,False))   # as above, discard root metadata
>>> .tree(graft=(node,'copy'))  # as above, copy root metadata

The show, add, and get methods can be accessed directly with

>>> .tree(arg)

for an arg of the appropriate type (bool, Node, and string).

Metadata

class py4DSTEM.Metadata(name: str | None = 'metadata', data: dict | None = None)

Stores metadata in the form of a flat (non-nested) dictionary. Keys are arbitrary strings. Values may be strings, numbers, arrays, or lists of the above types.

Usage:

>>> meta = Metadata()
>>> meta['param'] = value
>>> val = meta['param']

If the parameter has not been set, the getter methods return None.

__init__(name: str | None = 'metadata', data: dict | None = None)
Parameters:

name (Optional, string) –

copy(name=None)
to_h5(group)

Accepts an h5py Group which is open in write or append mode. Writes a new group with this object’s name and saves its metadata in it.

Accepts:

group (h5py Group)

classmethod from_h5(group)

Accepts an h5py Group which is open in read mode, confirms that it represents an EMD MetadataDict group, then loads and returns it as a Metadata instance.

Accepts:

group (HDF5 group)

Returns:

(Metadata)

Node

class py4DSTEM.Node(name: str | None = 'node')

Nodes contain attributes and methods paralleling the EMD 1.0 file specification in Python runtime objects.

EMD 1.0 is a singly-rooted file format. That is to say: An EMD data object can and must exist in one and only one EMD tree. An EMD file can contain any number of EMD trees, each containing data and metadata which is, within the limits of the EMD group specifications, of some arbitrary complexity. An EMD 1.0 file thus represents, stores, and enables access to some arbitrary data in long term storage on a file system in the form of an HDF5 file. The Node class provides machinery for building trees of data and metadata which mirror the EMD tree format but which exist in a live Python instance, rather than on the file system. This facilitates ease of transfer between Python and the file system.

Nodes are intended to be used a base class on which other, more complex classes can be biult. Nodes themselves contain the machinery for managing a tree heirarchy of other Nodes and Metadata instances, and for reading and writing those trees. They do not contain any particular data. Classes storing data and analysis methods which inherit from Node will inherit its tree management and EMD i/o functionality.

Below, the 4 elements of the node class are each described in turn: roots, trees, metadata, and i/o.

ROOTS

EMD data objects can and must exist in one and only one EMD tree, each of which must have a single, named root node. To parallel this in our runtime objects, each Node has a root property, which can be found by calling self.root.

By default new nodes have their root set to None. If a node with .root == None is saved to file, it is placed inside a new root with the same name as the object itself, and this is then saved to the file as a new (minimal) EMD tree.

A new root node can be instantiated by calling

>>> rootnode = Root(name=some_name).

Objects added to an existing rooted tree (including a new root node) automatically have their root assigned to the root of that tree. Adding objects to trees is discussed below.

TREES

The tree associated with a node can be manipulated with the .tree method. If we have some rooted node node1 and some unrooted node node2, the unrooted node can be added to the existing tree as a child of the rooted node with

>>> node1.tree(node2)

If we have a rooted node node1 and another rooted node node2, we can’t simply add node2 with the code above, as this would create a conflict between the two roots. In this case, we can move node2 from its current tree to the new tree using

>>> node1.tree(graft=node2)

The .tree method has various additional functionalities, including printing the tree, retrieving objects from the tree, and cutting branches from the tree. These are summarized below:

>>> .tree()             # show tree from current node
>>> .tree(show=True)    # show from root
>>> .tree(show=False)   # show from current node
>>> .tree(add=node)     # add a child node
>>> .tree(get='path')   # return a '/' delimited child node
>>> .tree(get='/path')  # as above, starting at root
>>> .tree(cut=True)     # remove/return a branch, keep root metadata
>>> .tree(cut=False)    # remove/return a branch, discard root md
>>> .tree(cut='copy')   # remove/return a branch, copy root metadata
>>> .tree(graft=node)   # remove/graft a branch, keep root metadata
>>> .tree(graft=(node,True))    # as above
>>> .tree(graft=(node,False))   # as above, discard root metadata
>>> .tree(graft=(node,'copy'))  # as above, copy root metadata

The show, add, and get methods can be accessed directly with

>>> .tree(arg)

for an arg of the appropriate type (bool, Node, and string), i.e. in most cases, the keyword can be dropped. So

>>> .tree()
>>> .tree(node)
>>> .tree(True)
>>> .tree('some/node')

will, respectively, print the tree from the current node to screen, add the node node to the tree, pring the tree from the root node to screen, and return the node at the emdpath ‘some/node’.

If a node needs to be added to a tree and it may or may not already have its own root, calling

>>> .tree(add=node, force=True)

or

>>> .tree(node, force=True)

will add the node to the tree, using a simple add if node has no root, and grafting it if it does have a root.

METADATA

Nodes can contain any number of Metadata instances, each of which wraps a Python dictionary of some arbitrary complexity (to within the limits of the Metadata group EMD specification, which limits permissible values somewhat).

The code:

>>> md1 = Metadata(name='md1')
>>> md2 = Metadata(name='md2')
>>> <<<  some code populating md1 + md2 >>>
>>> node.metadata = md1
>>> node.metadata = md2

will create two Metadata objects, populate them with data, then add them to the node. Note that Node.metadata is not a Python attribute, it is specially defined property, such that the last line of code does not overwrite the line before it - rather, assigning to the .metadata property adds the new metadata object to a running dictionary of arbitrarily many metadata objects. Both of these two metadata instances can therefore still be retrieved, using:

>>> x = node.metadata['md1']
>>> y = node.metadata['md2']

Note, however, that if the second metadata instance has an identical name to the first instance, then in will overwrite the old instance.

I/O

# TODO

__init__(name: str | None = 'node')
show_tree(root=False)

Display the object tree. If root is False, displays the branch of the tree downstream from this node. If root is True, displays the full tree from the root node.

add_to_tree(node)

Add an unrooted node as a child of the current, rooted node. To move an already rooted node/branch, use .graft(). To create a rooted node, use Root().

force_add_to_tree(node)

Add node node as a child of the current node, whether or not node is rooted. If it’s unrooted, performs a simple add. If it is rooted, performs a graft, excluding the root metadata from node.

get_from_tree(name)

Finds and returns an object from an EMD tree using the string key name, with ‘/’ delimiters between ‘parent/child’ nodes. Search from the root node by adding a leading ‘/’; otherwise, searches from the current node.

graft(node, merge_metadata=True)

Moves the branch beginning node onto this tree at this node.

For the reverse (i.e. grafting from this tree onto another tree) either use that tree’s .graft method, or use this tree’s ._graft.

Accepts:

node (Node): merge_metadata (True, False, or ‘copy’): if True adds the old root’s

metadata to the new root; if False adds no metadata to the new root; if ‘copy’ adds copies of all metadata from the old root to the new root.

Returns:

(Node) this tree’s root node

cut_from_tree(root_metadata=True)

Removes a branch from an object tree at this node.

A new root node is created under this object with this object’s name. Metadata from the current root is transferred/not transferred to the new root according to the value of root_metadata.

Accepts:
root_metadata (True, False, or ‘copy’): if True adds the old root’s

metadata to the new root; if False adds no metadata to the new root; if ‘copy’ adds copies of all metadata from the old root to the new root.

Returns:

(Node) the new root node

tree(arg=None, **kwargs)

Usages -

>>> .tree()             # show tree from current node
>>> .tree(show=True)    # show from root
>>> .tree(show=False)   # show from current node
>>> .tree(add=node)     # add a child node
>>> .tree(get='path')   # return a '/' delimited child node
>>> .tree(get='/path')  # as above, starting at root
>>> .tree(cut=True)     # remove/return a branch, keep root metadata
>>> .tree(cut=False)    # remove/return a branch, discard root md
>>> .tree(cut='copy')   # remove/return a branch, copy root metadata
>>> .tree(graft=node)   # remove/graft a branch, keeping root metadata
>>> .tree(graft=(node,True))    # as above
>>> .tree(graft=(node,False))   # as above, discard root metadata
>>> .tree(graft=(node,'copy'))  # as above, copy root metadata

The show, add, and get methods can be accessed directly with

>>> .tree(arg)

for an arg of the appropriate type (bool, Node, and string).

static newnode(method)

Decorator which may be added to node methods which product and return a new node. If such a method is decorated with

>>> @newnode

then the new node is added to the parent node’s tree, and a Metadata instance is added to the new node’s metadata which stores information about how the node was created, namely: method’s name, the parent’s class and name, and all the arguments passed to method.

classmethod from_h5(group)

Takes an h5py Group which is open in read mode. Confirms that a a Node of this name exists in this group, and loads and returns it with it’s metadata.

Accepts:

group (h5py Group)

Returns:

(Node)

to_h5(group)

Takes an h5py Group instance and creates a subgroup containing this node, tags indicating the groups EMD type and Python class, and any metadata in this node.

Accepts:

group (h5py Group)

Returns:

(h5py Group) the new node’s Group

PointList

class py4DSTEM.PointList(data: ndarray, name: str | None = 'pointlist')

A wrapper around structured numpy arrays, with read/write functionality in/out of EMD formatted HDF5 files.

__init__(data: ndarray, name: str | None = 'pointlist')

Instantiate a PointList.

Parameters:
  • data (structured numpy ndarray) – the data; the dtype of this array will specify the fields of the PointList.

  • name (str) – name for the PointList

Returns:

a PointList instance

add(data)

Appends a numpy structured array. Its dtypes must agree with the existing data.

remove(mask)

Removes points wherever mask==True

sort(field, order='ascending')

Sorts the point list according to field, which must be a field in self.dtype. order should be ‘descending’ or ‘ascending’.

copy(name=None)

Returns a copy of the PointList. If name=None, sets to {name}_copy

add_fields(new_fields, name='')

Creates a copy of the PointList, but with additional fields given by new_fields.

Parameters:
  • new_fields – a list of 2-tuples, (‘name’, dtype)

  • name – a name for the new pointlist

add_data_by_field(data, fields=None)

Add a list of data arrays to the PointList, in the fields given by fields. If fields is not specified, assumes the data arrays are in the same order as self.fields

Parameters:

data (list) – arrays of data to add to each field

add_to_tree(node)

Add an unrooted node as a child of the current, rooted node. To move an already rooted node/branch, use .graft(). To create a rooted node, use Root().

cut_from_tree(root_metadata=True)

Removes a branch from an object tree at this node.

A new root node is created under this object with this object’s name. Metadata from the current root is transferred/not transferred to the new root according to the value of root_metadata.

Accepts:
root_metadata (True, False, or ‘copy’): if True adds the old root’s

metadata to the new root; if False adds no metadata to the new root; if ‘copy’ adds copies of all metadata from the old root to the new root.

Returns:

(Node) the new root node

force_add_to_tree(node)

Add node node as a child of the current node, whether or not node is rooted. If it’s unrooted, performs a simple add. If it is rooted, performs a graft, excluding the root metadata from node.

classmethod from_h5(group)

Takes an h5py Group which is open in read mode. Confirms that a a Node of this name exists in this group, and loads and returns it with it’s metadata.

Accepts:

group (h5py Group)

Returns:

(Node)

get_from_tree(name)

Finds and returns an object from an EMD tree using the string key name, with ‘/’ delimiters between ‘parent/child’ nodes. Search from the root node by adding a leading ‘/’; otherwise, searches from the current node.

graft(node, merge_metadata=True)

Moves the branch beginning node onto this tree at this node.

For the reverse (i.e. grafting from this tree onto another tree) either use that tree’s .graft method, or use this tree’s ._graft.

Accepts:

node (Node): merge_metadata (True, False, or ‘copy’): if True adds the old root’s

metadata to the new root; if False adds no metadata to the new root; if ‘copy’ adds copies of all metadata from the old root to the new root.

Returns:

(Node) this tree’s root node

static newnode(method)

Decorator which may be added to node methods which product and return a new node. If such a method is decorated with

>>> @newnode

then the new node is added to the parent node’s tree, and a Metadata instance is added to the new node’s metadata which stores information about how the node was created, namely: method’s name, the parent’s class and name, and all the arguments passed to method.

show_tree(root=False)

Display the object tree. If root is False, displays the branch of the tree downstream from this node. If root is True, displays the full tree from the root node.

tree(arg=None, **kwargs)

Usages -

>>> .tree()             # show tree from current node
>>> .tree(show=True)    # show from root
>>> .tree(show=False)   # show from current node
>>> .tree(add=node)     # add a child node
>>> .tree(get='path')   # return a '/' delimited child node
>>> .tree(get='/path')  # as above, starting at root
>>> .tree(cut=True)     # remove/return a branch, keep root metadata
>>> .tree(cut=False)    # remove/return a branch, discard root md
>>> .tree(cut='copy')   # remove/return a branch, copy root metadata
>>> .tree(graft=node)   # remove/graft a branch, keeping root metadata
>>> .tree(graft=(node,True))    # as above
>>> .tree(graft=(node,False))   # as above, discard root metadata
>>> .tree(graft=(node,'copy'))  # as above, copy root metadata

The show, add, and get methods can be accessed directly with

>>> .tree(arg)

for an arg of the appropriate type (bool, Node, and string).

to_h5(group)

Takes an h5py Group instance and creates a subgroup containing this PointList, tags indicating its EMD type and Python class, and the pointlist’s data and metadata.

Accepts:

group (h5py Group)

Returns:

(h5py Group) the new pointlist’s group

PointListArray

class py4DSTEM.PointListArray(dtype, shape, name: str | None = 'pointlistarray')

An 2D array of PointLists which share common coordinates.

__init__(dtype, shape, name: str | None = 'pointlistarray')

Creates an empty PointListArray.

Parameters:
  • dtype – the dtype of the numpy structured arrays which will comprise the data of each PointList

  • shape (2-tuple of ints) – the shape of the array of PointLists

  • name (str) – a name for the PointListArray

Returns:

a PointListArray instance

get_pointlist(i, j, name=None)

Returns the pointlist at i,j

copy(name='')

Returns a copy of itself.

add_fields(new_fields, name='')

Creates a copy of the PointListArray, but with additional fields given by new_fields.

Parameters:
  • new_fields – a list of 2-tuples, (‘name’, dtype)

  • name – a name for the new pointlist

to_h5(group)

Takes an h5py Group instance and creates a subgroup containing this PointListArray, tags indicating its EMD type and Python class, and the pointlistarray’s data and metadata.

Accepts:

group (h5py Group)

Returns:

(h5py Group) the new pointlistarray’s group

add_to_tree(node)

Add an unrooted node as a child of the current, rooted node. To move an already rooted node/branch, use .graft(). To create a rooted node, use Root().

cut_from_tree(root_metadata=True)

Removes a branch from an object tree at this node.

A new root node is created under this object with this object’s name. Metadata from the current root is transferred/not transferred to the new root according to the value of root_metadata.

Accepts:
root_metadata (True, False, or ‘copy’): if True adds the old root’s

metadata to the new root; if False adds no metadata to the new root; if ‘copy’ adds copies of all metadata from the old root to the new root.

Returns:

(Node) the new root node

force_add_to_tree(node)

Add node node as a child of the current node, whether or not node is rooted. If it’s unrooted, performs a simple add. If it is rooted, performs a graft, excluding the root metadata from node.

classmethod from_h5(group)

Takes an h5py Group which is open in read mode. Confirms that a a Node of this name exists in this group, and loads and returns it with it’s metadata.

Accepts:

group (h5py Group)

Returns:

(Node)

get_from_tree(name)

Finds and returns an object from an EMD tree using the string key name, with ‘/’ delimiters between ‘parent/child’ nodes. Search from the root node by adding a leading ‘/’; otherwise, searches from the current node.

graft(node, merge_metadata=True)

Moves the branch beginning node onto this tree at this node.

For the reverse (i.e. grafting from this tree onto another tree) either use that tree’s .graft method, or use this tree’s ._graft.

Accepts:

node (Node): merge_metadata (True, False, or ‘copy’): if True adds the old root’s

metadata to the new root; if False adds no metadata to the new root; if ‘copy’ adds copies of all metadata from the old root to the new root.

Returns:

(Node) this tree’s root node

static newnode(method)

Decorator which may be added to node methods which product and return a new node. If such a method is decorated with

>>> @newnode

then the new node is added to the parent node’s tree, and a Metadata instance is added to the new node’s metadata which stores information about how the node was created, namely: method’s name, the parent’s class and name, and all the arguments passed to method.

show_tree(root=False)

Display the object tree. If root is False, displays the branch of the tree downstream from this node. If root is True, displays the full tree from the root node.

tree(arg=None, **kwargs)

Usages -

>>> .tree()             # show tree from current node
>>> .tree(show=True)    # show from root
>>> .tree(show=False)   # show from current node
>>> .tree(add=node)     # add a child node
>>> .tree(get='path')   # return a '/' delimited child node
>>> .tree(get='/path')  # as above, starting at root
>>> .tree(cut=True)     # remove/return a branch, keep root metadata
>>> .tree(cut=False)    # remove/return a branch, discard root md
>>> .tree(cut='copy')   # remove/return a branch, copy root metadata
>>> .tree(graft=node)   # remove/graft a branch, keeping root metadata
>>> .tree(graft=(node,True))    # as above
>>> .tree(graft=(node,False))   # as above, discard root metadata
>>> .tree(graft=(node,'copy'))  # as above, copy root metadata

The show, add, and get methods can be accessed directly with

>>> .tree(arg)

for an arg of the appropriate type (bool, Node, and string).

Probe

class py4DSTEM.Probe(data: ndarray, name: str | None = 'probe')

Stores a vacuum probe.

Both a vacuum probe and a kernel for cross-correlative template matching derived from that probe are stored and can be accessed at

>>> p.probe
>>> p.kernel

respectively, for some Probe instance p. If a kernel has not been computed the latter expression returns None.

__init__(data: ndarray, name: str | None = 'probe')
Accepts:
data (2D or 3D np.ndarray): the vacuum probe, or

the vacuum probe + kernel

name (str): a name

Returns:

(Probe)

classmethod from_vacuum_data(data, mask=None, threshold=0.2, expansion=12, opening=3)

Generates and returns a vacuum probe Probe instance from either a 2D vacuum image or a 3D stack of vacuum diffraction patterns.

The probe is multiplied by mask, if it’s passed. An additional masking step zeros values outside of a mask determined by threshold, expansion, and opening, generated by first computing the binary image probe < max(probe)*threshold, then applying a binary expansion and then opening to this image. No alignment is performed - i.e. it is assumed that the beam was stationary during acquisition of the stack. To align the images, use the DataCube .get_vacuum_probe method.

Parameters:
  • data (2D or 3D array) – the vacuum diffraction data. For 3D stacks, use shape (N,Q_Nx,Q_Ny)

  • mask (boolean array, optional) – mask applied to the probe

  • threshold (float) – threshold determining mask which zeros values outside of probe

  • expansion (int) – number of pixels by which the zeroing mask is expanded to capture the full probe

  • opening (int) – size of binary opening used to eliminate stray bright pixels

Returns:

probe – the vacuum probe

Return type:

Probe

classmethod generate_synthetic_probe(radius, width, Qshape)

Makes a synthetic probe, with the functional form of a disk blurred by a sigmoid (a logistic function).

Parameters:
  • radius (float) – the probe radius

  • width (float) – the blurring of the probe edge. width represents the full width of the blur, with x=-w/2 to x=+w/2 about the edge spanning values of ~0.12 to 0.88

  • Qshape (2 tuple) – the diffraction plane dimensions

Returns:

probe – the probe

Return type:

Probe

measure_disk(thresh_lower=0.01, thresh_upper=0.99, N=100, returncalc=True, data=None)

Finds the center and radius of an average probe image.

A naive algorithm. Creates a series of N binary masks by thresholding the probe image a linspace of N thresholds from thresh_lower to thresh_upper, relative to the image max/min. For each mask, we find the square root of the number of True valued pixels divided by pi to estimate a radius. Because the central disk is intense relative to the remainder of the image, the computed radii are expected to vary very little over a wider range threshold values. A range of r values considered trustworthy is estimated by taking the derivative r(thresh)/dthresh identifying where it is small, and the mean of this range is returned as the radius. A center is estimated using a binary thresholded image in combination with the center of mass operator.

Parameters:
  • thresh_lower (float, 0 to 1) – the lower limit of threshold values

  • thresh_upper (float, 0 to 1)) – the upper limit of threshold values

  • N (int) – the number of thresholds / masks to use

  • returncalc (True) – toggles returning the answer

  • data (2d array, optional) – if passed, uses this 2D array in place of the probe image when performing the computation. This also supresses storing the results in the Probe’s calibration metadata

Returns:

r, x0, y0 – the radius and origin

Return type:

(3-tuple)

get_kernel(mode='flat', origin=None, data=None, returncalc=True, **kwargs)

Creates a cross-correlation kernel from the vacuum probe.

Specific behavior and valid keyword arguments depend on the mode specified. In each case, the center of the probe is shifted to the origin and the kernel normalized such that it sums to 1. This is the only processing performed if mode is ‘flat’. Otherwise, a centrosymmetric region of negative intensity is added around the probe intended to promote edge-filtering-like behavior during cross correlation, with the functional form of the subtracted region defined by mode and the relevant **kwargs. For normalization, flat probes integrate to 1, and the remaining probes integrate to 1 before subtraction and 0 after. Required keyword arguments are:

  • ‘flat’: No required arguments. This mode is recommended for bullseye or other structured probes

  • ‘gaussian’: Required arg sigma (number), the width (standard deviation) of a centered gaussian to be subtracted.

  • ‘sigmoid’: Required arg radii (2-tuple), the inner and outer radii (ri,ro) of an annular region with a sine-squared sigmoidal radial profile to be subtracted.

  • ‘sigmoid_log’: Required arg radii (2-tuple), the inner and outer radii (ri,ro) of an annular region with a logistic sigmoidal radial profile to be subtracted.

Parameters:
  • mode (str) – must be in ‘flat’,’gaussian’,’sigmoid’,’sigmoid_log’

  • origin (2-tuple, optional) – specify the origin. If not passed, looks for a value for the probe origin in metadata. If not found there, calls .measure_disk.

  • data (2d array, optional) – if specified, uses this array instead of the probe image to compute the kernel

  • **kwargs – see descriptions above

Returns:

kernel

Return type:

2D array

static get_probe_kernel_flat(probe, origin=None, bilinear=False)

Creates a cross-correlation kernel from the vacuum probe by normalizing and shifting the center.

Parameters:
  • probe (2d array) – the vacuum probe

  • origin (2-tuple (optional)) – the origin of diffraction space. If not specified, finds the origin using get_probe_radius.

  • bilinear (bool (optional)) – By default probe is shifted via a Fourier transform. Setting this to True overrides it and uses bilinear shifting. Not recommended!

Returns:

kernel – the cross-correlation kernel corresponding to the probe, in real space

Return type:

ndarray

static get_probe_kernel_edge_gaussian(probe, sigma, origin=None, bilinear=True)

Creates a cross-correlation kernel from the probe, subtracting a gaussian from the normalized probe such that the kernel integrates to zero, then shifting the center of the probe to the array corners.

Parameters:
  • probe (ndarray) – the diffraction pattern corresponding to the probe over vacuum

  • sigma (float) – the width of the gaussian to subtract, relative to the standard deviation of the probe

  • origin (2-tuple (optional)) – the origin of diffraction space. If not specified, finds the origin using get_probe_radius.

  • bilinear (bool) – By default probe is shifted via a Fourier transform. Setting this to True overrides it and uses bilinear shifting. Not recommended!

Returns:

kernel – the cross-correlation kernel

Return type:

ndarray

static get_probe_kernel_edge_sigmoid(probe, radii, origin=None, type='sine_squared', bilinear=True)

Creates a convolution kernel from an average probe, subtracting an annular trench about the probe such that the kernel integrates to zero, then shifting the center of the probe to the array corners.

Parameters:
  • probe (ndarray) – the diffraction pattern corresponding to the probe over vacuum

  • radii (2-tuple) – the sigmoid inner and outer radii

  • origin (2-tuple (optional)) – the origin of diffraction space. If not specified, finds the origin using get_probe_radius.

  • type (string) – must be ‘logistic’ or ‘sine_squared’

  • bilinear (bool) – By default probe is shifted via a Fourier transform. Setting this to True overrides it and uses bilinear shifting. Not recommended!

Returns:

kernel – the cross-correlation kernel

Return type:

2d array

add_to_tree(node)

Add an unrooted node as a child of the current, rooted node. To move an already rooted node/branch, use .graft(). To create a rooted node, use Root().

attach(node)

Attach node to the current object’s tree, attaching calibration and detaching calibrations as needed.

cut_from_tree(root_metadata=True)

Removes a branch from an object tree at this node.

A new root node is created under this object with this object’s name. Metadata from the current root is transferred/not transferred to the new root according to the value of root_metadata.

Accepts:
root_metadata (True, False, or ‘copy’): if True adds the old root’s

metadata to the new root; if False adds no metadata to the new root; if ‘copy’ adds copies of all metadata from the old root to the new root.

Returns:

(Node) the new root node

dim(n)

Return the n’th dim vector

force_add_to_tree(node)

Add node node as a child of the current node, whether or not node is rooted. If it’s unrooted, performs a simple add. If it is rooted, performs a graft, excluding the root metadata from node.

classmethod from_h5(group)

Takes an h5py Group which is open in read mode. Confirms that a a Node of this name exists in this group, and loads and returns it with it’s metadata.

Accepts:

group (h5py Group)

Returns:

(Node)

get_dim(n)

Return the n’th dim vector

get_dim_name(n)

Get the n’th dim vector name

get_dim_units(n)

Return the n’th dim vector units

get_from_tree(name)

Finds and returns an object from an EMD tree using the string key name, with ‘/’ delimiters between ‘parent/child’ nodes. Search from the root node by adding a leading ‘/’; otherwise, searches from the current node.

graft(node, merge_metadata=True)

Moves the branch beginning node onto this tree at this node.

For the reverse (i.e. grafting from this tree onto another tree) either use that tree’s .graft method, or use this tree’s ._graft.

Accepts:

node (Node): merge_metadata (True, False, or ‘copy’): if True adds the old root’s

metadata to the new root; if False adds no metadata to the new root; if ‘copy’ adds copies of all metadata from the old root to the new root.

Returns:

(Node) this tree’s root node

static newnode(method)

Decorator which may be added to node methods which product and return a new node. If such a method is decorated with

>>> @newnode

then the new node is added to the parent node’s tree, and a Metadata instance is added to the new node’s metadata which stores information about how the node was created, namely: method’s name, the parent’s class and name, and all the arguments passed to method.

set_dim(n: int, dim: list | ndarray, units: str | None = None, name: str | None = None)

Sets the n’th dim vector, using dim as described in the Array documentation. If units and/or name are passed, sets these values for the n’th dim vector.

Accepts:

n (int): specifies which dim vector dim (list or array): length must be either 2, or equal to the

length of the n’th axis of the data array

units (Optional, str): name: (Optional, str):

set_dim_name(n: int, name: str)

Sets the n’th dim vector name to name.

Accepts:

n (int): specifies which dim vector name (str): new name

set_dim_units(n: int, units: str)

Sets the n’th dim vector units to units.

Accepts:

n (int): specifies which dim vector units (str): new units

show_tree(root=False)

Display the object tree. If root is False, displays the branch of the tree downstream from this node. If root is True, displays the full tree from the root node.

to_h5(group)

Takes an h5py Group instance and creates a subgroup containing this Array, tags indicating its EMD type and Python class, and the array’s data and metadata.

Accepts:

group (h5py Group)

Returns:

(h5py Group) the new array’s Group

tree(arg=None, **kwargs)

Usages -

>>> .tree()             # show tree from current node
>>> .tree(show=True)    # show from root
>>> .tree(show=False)   # show from current node
>>> .tree(add=node)     # add a child node
>>> .tree(get='path')   # return a '/' delimited child node
>>> .tree(get='/path')  # as above, starting at root
>>> .tree(cut=True)     # remove/return a branch, keep root metadata
>>> .tree(cut=False)    # remove/return a branch, discard root md
>>> .tree(cut='copy')   # remove/return a branch, copy root metadata
>>> .tree(graft=node)   # remove/graft a branch, keeping root metadata
>>> .tree(graft=(node,True))    # as above
>>> .tree(graft=(node,False))   # as above, discard root metadata
>>> .tree(graft=(node,'copy'))  # as above, copy root metadata

The show, add, and get methods can be accessed directly with

>>> .tree(arg)

for an arg of the appropriate type (bool, Node, and string).

QPoints

class py4DSTEM.QPoints(data: ndarray, name: str | None = 'qpoints')

Stores a set of diffraction space points, with fields ‘qx’, ‘qy’ and ‘intensity’

__init__(data: ndarray, name: str | None = 'qpoints')
Accepts:
data (structured numpy ndarray): should have three fields, which

will be renamed ‘qx’,’qy’,’intensity’

name (str): the name of the QPoints instance

Returns:

A new QPoints instance

add(data)

Appends a numpy structured array. Its dtypes must agree with the existing data.

add_data_by_field(data, fields=None)

Add a list of data arrays to the PointList, in the fields given by fields. If fields is not specified, assumes the data arrays are in the same order as self.fields

Parameters:

data (list) – arrays of data to add to each field

add_fields(new_fields, name='')

Creates a copy of the PointList, but with additional fields given by new_fields.

Parameters:
  • new_fields – a list of 2-tuples, (‘name’, dtype)

  • name – a name for the new pointlist

add_to_tree(node)

Add an unrooted node as a child of the current, rooted node. To move an already rooted node/branch, use .graft(). To create a rooted node, use Root().

attach(node)

Attach node to the current object’s tree, attaching calibration and detaching calibrations as needed.

copy(name=None)

Returns a copy of the PointList. If name=None, sets to {name}_copy

cut_from_tree(root_metadata=True)

Removes a branch from an object tree at this node.

A new root node is created under this object with this object’s name. Metadata from the current root is transferred/not transferred to the new root according to the value of root_metadata.

Accepts:
root_metadata (True, False, or ‘copy’): if True adds the old root’s

metadata to the new root; if False adds no metadata to the new root; if ‘copy’ adds copies of all metadata from the old root to the new root.

Returns:

(Node) the new root node

force_add_to_tree(node)

Add node node as a child of the current node, whether or not node is rooted. If it’s unrooted, performs a simple add. If it is rooted, performs a graft, excluding the root metadata from node.

classmethod from_h5(group)

Takes an h5py Group which is open in read mode. Confirms that a a Node of this name exists in this group, and loads and returns it with it’s metadata.

Accepts:

group (h5py Group)

Returns:

(Node)

get_from_tree(name)

Finds and returns an object from an EMD tree using the string key name, with ‘/’ delimiters between ‘parent/child’ nodes. Search from the root node by adding a leading ‘/’; otherwise, searches from the current node.

graft(node, merge_metadata=True)

Moves the branch beginning node onto this tree at this node.

For the reverse (i.e. grafting from this tree onto another tree) either use that tree’s .graft method, or use this tree’s ._graft.

Accepts:

node (Node): merge_metadata (True, False, or ‘copy’): if True adds the old root’s

metadata to the new root; if False adds no metadata to the new root; if ‘copy’ adds copies of all metadata from the old root to the new root.

Returns:

(Node) this tree’s root node

static newnode(method)

Decorator which may be added to node methods which product and return a new node. If such a method is decorated with

>>> @newnode

then the new node is added to the parent node’s tree, and a Metadata instance is added to the new node’s metadata which stores information about how the node was created, namely: method’s name, the parent’s class and name, and all the arguments passed to method.

remove(mask)

Removes points wherever mask==True

show_tree(root=False)

Display the object tree. If root is False, displays the branch of the tree downstream from this node. If root is True, displays the full tree from the root node.

sort(field, order='ascending')

Sorts the point list according to field, which must be a field in self.dtype. order should be ‘descending’ or ‘ascending’.

to_h5(group)

Takes an h5py Group instance and creates a subgroup containing this PointList, tags indicating its EMD type and Python class, and the pointlist’s data and metadata.

Accepts:

group (h5py Group)

Returns:

(h5py Group) the new pointlist’s group

tree(arg=None, **kwargs)

Usages -

>>> .tree()             # show tree from current node
>>> .tree(show=True)    # show from root
>>> .tree(show=False)   # show from current node
>>> .tree(add=node)     # add a child node
>>> .tree(get='path')   # return a '/' delimited child node
>>> .tree(get='/path')  # as above, starting at root
>>> .tree(cut=True)     # remove/return a branch, keep root metadata
>>> .tree(cut=False)    # remove/return a branch, discard root md
>>> .tree(cut='copy')   # remove/return a branch, copy root metadata
>>> .tree(graft=node)   # remove/graft a branch, keeping root metadata
>>> .tree(graft=(node,True))    # as above
>>> .tree(graft=(node,False))   # as above, discard root metadata
>>> .tree(graft=(node,'copy'))  # as above, copy root metadata

The show, add, and get methods can be accessed directly with

>>> .tree(arg)

for an arg of the appropriate type (bool, Node, and string).

RealSlice

class py4DSTEM.RealSlice(data: ndarray, name: str | None = 'realslice', units: str | None = 'intensity', slicelabels: bool | list | None = None, calibration=None)

Stores a real-space shaped 2D data array.

__init__(data: ndarray, name: str | None = 'realslice', units: str | None = 'intensity', slicelabels: bool | list | None = None, calibration=None)
Accepts:

data (np.ndarray): the data name (str): the name of the realslice slicelabels(None or list): names for slices if this is a stack of

realslices

Returns:

A new RealSlice instance

add_to_tree(node)

Add an unrooted node as a child of the current, rooted node. To move an already rooted node/branch, use .graft(). To create a rooted node, use Root().

attach(node)

Attach node to the current object’s tree, attaching calibration and detaching calibrations as needed.

cut_from_tree(root_metadata=True)

Removes a branch from an object tree at this node.

A new root node is created under this object with this object’s name. Metadata from the current root is transferred/not transferred to the new root according to the value of root_metadata.

Accepts:
root_metadata (True, False, or ‘copy’): if True adds the old root’s

metadata to the new root; if False adds no metadata to the new root; if ‘copy’ adds copies of all metadata from the old root to the new root.

Returns:

(Node) the new root node

dim(n)

Return the n’th dim vector

force_add_to_tree(node)

Add node node as a child of the current node, whether or not node is rooted. If it’s unrooted, performs a simple add. If it is rooted, performs a graft, excluding the root metadata from node.

classmethod from_h5(group)

Takes an h5py Group which is open in read mode. Confirms that a a Node of this name exists in this group, and loads and returns it with it’s metadata.

Accepts:

group (h5py Group)

Returns:

(Node)

get_dim(n)

Return the n’th dim vector

get_dim_name(n)

Get the n’th dim vector name

get_dim_units(n)

Return the n’th dim vector units

get_from_tree(name)

Finds and returns an object from an EMD tree using the string key name, with ‘/’ delimiters between ‘parent/child’ nodes. Search from the root node by adding a leading ‘/’; otherwise, searches from the current node.

graft(node, merge_metadata=True)

Moves the branch beginning node onto this tree at this node.

For the reverse (i.e. grafting from this tree onto another tree) either use that tree’s .graft method, or use this tree’s ._graft.

Accepts:

node (Node): merge_metadata (True, False, or ‘copy’): if True adds the old root’s

metadata to the new root; if False adds no metadata to the new root; if ‘copy’ adds copies of all metadata from the old root to the new root.

Returns:

(Node) this tree’s root node

static newnode(method)

Decorator which may be added to node methods which product and return a new node. If such a method is decorated with

>>> @newnode

then the new node is added to the parent node’s tree, and a Metadata instance is added to the new node’s metadata which stores information about how the node was created, namely: method’s name, the parent’s class and name, and all the arguments passed to method.

set_dim(n: int, dim: list | ndarray, units: str | None = None, name: str | None = None)

Sets the n’th dim vector, using dim as described in the Array documentation. If units and/or name are passed, sets these values for the n’th dim vector.

Accepts:

n (int): specifies which dim vector dim (list or array): length must be either 2, or equal to the

length of the n’th axis of the data array

units (Optional, str): name: (Optional, str):

set_dim_name(n: int, name: str)

Sets the n’th dim vector name to name.

Accepts:

n (int): specifies which dim vector name (str): new name

set_dim_units(n: int, units: str)

Sets the n’th dim vector units to units.

Accepts:

n (int): specifies which dim vector units (str): new units

show_tree(root=False)

Display the object tree. If root is False, displays the branch of the tree downstream from this node. If root is True, displays the full tree from the root node.

to_h5(group)

Takes an h5py Group instance and creates a subgroup containing this Array, tags indicating its EMD type and Python class, and the array’s data and metadata.

Accepts:

group (h5py Group)

Returns:

(h5py Group) the new array’s Group

tree(arg=None, **kwargs)

Usages -

>>> .tree()             # show tree from current node
>>> .tree(show=True)    # show from root
>>> .tree(show=False)   # show from current node
>>> .tree(add=node)     # add a child node
>>> .tree(get='path')   # return a '/' delimited child node
>>> .tree(get='/path')  # as above, starting at root
>>> .tree(cut=True)     # remove/return a branch, keep root metadata
>>> .tree(cut=False)    # remove/return a branch, discard root md
>>> .tree(cut='copy')   # remove/return a branch, copy root metadata
>>> .tree(graft=node)   # remove/graft a branch, keeping root metadata
>>> .tree(graft=(node,True))    # as above
>>> .tree(graft=(node,False))   # as above, discard root metadata
>>> .tree(graft=(node,'copy'))  # as above, copy root metadata

The show, add, and get methods can be accessed directly with

>>> .tree(arg)

for an arg of the appropriate type (bool, Node, and string).

VirtualDiffraction

class py4DSTEM.VirtualDiffraction(data: ndarray, name: str | None = 'virtualdiffraction')

Stores a diffraction-space shaped 2D image with metadata indicating how this image was generated from a self.

__init__(data: ndarray, name: str | None = 'virtualdiffraction')
Parameters:
  • data (np.ndarray) – the 2D data

  • name (str) – the name

Returns:

A new VirtualDiffraction instance

add_to_tree(node)

Add an unrooted node as a child of the current, rooted node. To move an already rooted node/branch, use .graft(). To create a rooted node, use Root().

attach(node)

Attach node to the current object’s tree, attaching calibration and detaching calibrations as needed.

cut_from_tree(root_metadata=True)

Removes a branch from an object tree at this node.

A new root node is created under this object with this object’s name. Metadata from the current root is transferred/not transferred to the new root according to the value of root_metadata.

Accepts:
root_metadata (True, False, or ‘copy’): if True adds the old root’s

metadata to the new root; if False adds no metadata to the new root; if ‘copy’ adds copies of all metadata from the old root to the new root.

Returns:

(Node) the new root node

dim(n)

Return the n’th dim vector

force_add_to_tree(node)

Add node node as a child of the current node, whether or not node is rooted. If it’s unrooted, performs a simple add. If it is rooted, performs a graft, excluding the root metadata from node.

classmethod from_h5(group)

Takes an h5py Group which is open in read mode. Confirms that a a Node of this name exists in this group, and loads and returns it with it’s metadata.

Accepts:

group (h5py Group)

Returns:

(Node)

get_dim(n)

Return the n’th dim vector

get_dim_name(n)

Get the n’th dim vector name

get_dim_units(n)

Return the n’th dim vector units

get_from_tree(name)

Finds and returns an object from an EMD tree using the string key name, with ‘/’ delimiters between ‘parent/child’ nodes. Search from the root node by adding a leading ‘/’; otherwise, searches from the current node.

graft(node, merge_metadata=True)

Moves the branch beginning node onto this tree at this node.

For the reverse (i.e. grafting from this tree onto another tree) either use that tree’s .graft method, or use this tree’s ._graft.

Accepts:

node (Node): merge_metadata (True, False, or ‘copy’): if True adds the old root’s

metadata to the new root; if False adds no metadata to the new root; if ‘copy’ adds copies of all metadata from the old root to the new root.

Returns:

(Node) this tree’s root node

static newnode(method)

Decorator which may be added to node methods which product and return a new node. If such a method is decorated with

>>> @newnode

then the new node is added to the parent node’s tree, and a Metadata instance is added to the new node’s metadata which stores information about how the node was created, namely: method’s name, the parent’s class and name, and all the arguments passed to method.

set_dim(n: int, dim: list | ndarray, units: str | None = None, name: str | None = None)

Sets the n’th dim vector, using dim as described in the Array documentation. If units and/or name are passed, sets these values for the n’th dim vector.

Accepts:

n (int): specifies which dim vector dim (list or array): length must be either 2, or equal to the

length of the n’th axis of the data array

units (Optional, str): name: (Optional, str):

set_dim_name(n: int, name: str)

Sets the n’th dim vector name to name.

Accepts:

n (int): specifies which dim vector name (str): new name

set_dim_units(n: int, units: str)

Sets the n’th dim vector units to units.

Accepts:

n (int): specifies which dim vector units (str): new units

show_tree(root=False)

Display the object tree. If root is False, displays the branch of the tree downstream from this node. If root is True, displays the full tree from the root node.

to_h5(group)

Takes an h5py Group instance and creates a subgroup containing this Array, tags indicating its EMD type and Python class, and the array’s data and metadata.

Accepts:

group (h5py Group)

Returns:

(h5py Group) the new array’s Group

tree(arg=None, **kwargs)

Usages -

>>> .tree()             # show tree from current node
>>> .tree(show=True)    # show from root
>>> .tree(show=False)   # show from current node
>>> .tree(add=node)     # add a child node
>>> .tree(get='path')   # return a '/' delimited child node
>>> .tree(get='/path')  # as above, starting at root
>>> .tree(cut=True)     # remove/return a branch, keep root metadata
>>> .tree(cut=False)    # remove/return a branch, discard root md
>>> .tree(cut='copy')   # remove/return a branch, copy root metadata
>>> .tree(graft=node)   # remove/graft a branch, keeping root metadata
>>> .tree(graft=(node,True))    # as above
>>> .tree(graft=(node,False))   # as above, discard root metadata
>>> .tree(graft=(node,'copy'))  # as above, copy root metadata

The show, add, and get methods can be accessed directly with

>>> .tree(arg)

for an arg of the appropriate type (bool, Node, and string).

VirtualImage

class py4DSTEM.VirtualImage(data: ndarray, name: str | None = 'virtualimage')

A container for storing virtual image data and metadata, including the real-space shaped 2D image and metadata indicating how this image was generated from a datacube.

__init__(data: ndarray, name: str | None = 'virtualimage')
Parameters:
  • data (np.ndarray) – the 2D data

  • name (str) – the name

add_to_tree(node)

Add an unrooted node as a child of the current, rooted node. To move an already rooted node/branch, use .graft(). To create a rooted node, use Root().

attach(node)

Attach node to the current object’s tree, attaching calibration and detaching calibrations as needed.

cut_from_tree(root_metadata=True)

Removes a branch from an object tree at this node.

A new root node is created under this object with this object’s name. Metadata from the current root is transferred/not transferred to the new root according to the value of root_metadata.

Accepts:
root_metadata (True, False, or ‘copy’): if True adds the old root’s

metadata to the new root; if False adds no metadata to the new root; if ‘copy’ adds copies of all metadata from the old root to the new root.

Returns:

(Node) the new root node

dim(n)

Return the n’th dim vector

force_add_to_tree(node)

Add node node as a child of the current node, whether or not node is rooted. If it’s unrooted, performs a simple add. If it is rooted, performs a graft, excluding the root metadata from node.

classmethod from_h5(group)

Takes an h5py Group which is open in read mode. Confirms that a a Node of this name exists in this group, and loads and returns it with it’s metadata.

Accepts:

group (h5py Group)

Returns:

(Node)

get_dim(n)

Return the n’th dim vector

get_dim_name(n)

Get the n’th dim vector name

get_dim_units(n)

Return the n’th dim vector units

get_from_tree(name)

Finds and returns an object from an EMD tree using the string key name, with ‘/’ delimiters between ‘parent/child’ nodes. Search from the root node by adding a leading ‘/’; otherwise, searches from the current node.

graft(node, merge_metadata=True)

Moves the branch beginning node onto this tree at this node.

For the reverse (i.e. grafting from this tree onto another tree) either use that tree’s .graft method, or use this tree’s ._graft.

Accepts:

node (Node): merge_metadata (True, False, or ‘copy’): if True adds the old root’s

metadata to the new root; if False adds no metadata to the new root; if ‘copy’ adds copies of all metadata from the old root to the new root.

Returns:

(Node) this tree’s root node

static newnode(method)

Decorator which may be added to node methods which product and return a new node. If such a method is decorated with

>>> @newnode

then the new node is added to the parent node’s tree, and a Metadata instance is added to the new node’s metadata which stores information about how the node was created, namely: method’s name, the parent’s class and name, and all the arguments passed to method.

set_dim(n: int, dim: list | ndarray, units: str | None = None, name: str | None = None)

Sets the n’th dim vector, using dim as described in the Array documentation. If units and/or name are passed, sets these values for the n’th dim vector.

Accepts:

n (int): specifies which dim vector dim (list or array): length must be either 2, or equal to the

length of the n’th axis of the data array

units (Optional, str): name: (Optional, str):

set_dim_name(n: int, name: str)

Sets the n’th dim vector name to name.

Accepts:

n (int): specifies which dim vector name (str): new name

set_dim_units(n: int, units: str)

Sets the n’th dim vector units to units.

Accepts:

n (int): specifies which dim vector units (str): new units

show_tree(root=False)

Display the object tree. If root is False, displays the branch of the tree downstream from this node. If root is True, displays the full tree from the root node.

to_h5(group)

Takes an h5py Group instance and creates a subgroup containing this Array, tags indicating its EMD type and Python class, and the array’s data and metadata.

Accepts:

group (h5py Group)

Returns:

(h5py Group) the new array’s Group

tree(arg=None, **kwargs)

Usages -

>>> .tree()             # show tree from current node
>>> .tree(show=True)    # show from root
>>> .tree(show=False)   # show from current node
>>> .tree(add=node)     # add a child node
>>> .tree(get='path')   # return a '/' delimited child node
>>> .tree(get='/path')  # as above, starting at root
>>> .tree(cut=True)     # remove/return a branch, keep root metadata
>>> .tree(cut=False)    # remove/return a branch, discard root md
>>> .tree(cut='copy')   # remove/return a branch, copy root metadata
>>> .tree(graft=node)   # remove/graft a branch, keeping root metadata
>>> .tree(graft=(node,True))    # as above
>>> .tree(graft=(node,False))   # as above, discard root metadata
>>> .tree(graft=(node,'copy'))  # as above, copy root metadata

The show, add, and get methods can be accessed directly with

>>> .tree(arg)

for an arg of the appropriate type (bool, Node, and string).