upxo.viz.ebsdviz module
EBSD visualisation helpers for UPXO.
All functions accept an upxo.interfaces.defdap.ebsd_reader.EBSDReader
instance (or plain NumPy arrays where noted) and produce Matplotlib figures.
Usage
import upxo.viz.ebsdviz as ebsdviz
- upxo.viz.ebsdviz.plot_grain_labels(rdr, show_boundaries: bool = True, boundary_color=(0, 0, 0), cmap: str = 'nipy_spectral', figsize: tuple = (7, 6), dpi: int = 100, title: str = 'Grain label field', ax=None)[source]
Plot the grain label field (lfi_ebsd) with optional boundary overlay.
- Parameters:
rdr (EBSDReader) – Loaded EBSD reader with
lfi_ebsdpopulated.show_boundaries (bool) – Whether to overlay grain boundaries in black.
boundary_color (tuple) – RGB tuple for boundary colour (values 0–1).
cmap (str) – Matplotlib colormap for grain IDs.
title (str) – Axes title.
ax (matplotlib.axes.Axes or None) – If provided, draw onto this axes; otherwise create a new figure.
- Return type:
fig, ax
- upxo.viz.ebsdviz.plot_euler_maps(rdr, show_boundaries: bool = True, boundary_color=(0, 0, 0), cmaps=('hsv', 'viridis', 'hsv'), figsize: tuple = (15, 5), dpi: int = 100, suptitle: str = 'Bunge Euler angle maps')[source]
Plot phi1, Phi, phi2 Euler maps side-by-side.
- Parameters:
rdr (EBSDReader) – Loaded EBSD reader with
euler_ebsdandlfi_ebsdpopulated.show_boundaries (bool) – Overlay grain boundaries on every panel.
cmaps (tuple of str) – One colormap per channel (phi1, Phi, phi2).
- Return type:
fig, axes
- upxo.viz.ebsdviz.build_ipf_rgb(lfi: numpy.ndarray, quats_dict: dict, sample_direction=(0.0, 0.0, 1.0), grey: tuple = (0.75, 0.75, 0.75)) numpy.ndarray[source]
Build a pixel-level IPF RGB image from an integer label field and a grain-quaternion mapping.
- Parameters:
lfi (ndarray (ny, nx), int) – Pixel label field; each value is a grain ID.
quats_dict (dict {int gid -> ndarray (4,)}) – Quaternion
(w, x, y, z)for each oriented grain.sample_direction (array-like (3,)) – Sample reference direction for IPF colouring. Default [001] (ND).
grey (tuple of 3 floats) – RGB colour for pixels whose grain has no assigned orientation.
- Returns:
rgb
- Return type:
- upxo.viz.ebsdviz.plot_grain_size_histogram(rdr, figsize: tuple = (7, 4), dpi: int = 100, bins: int = 40, color: str = 'steelblue')[source]
Plot a grain area histogram in physical units (µm²).
- Parameters:
rdr (EBSDReader) – Loaded EBSD reader with
lfi_ebsdandstep_sizepopulated.- Return type:
fig, ax
- upxo.viz.ebsdviz.plot_grain_structure_with_boundaries(rdr, show_euler_panel: bool = True, euler_channel: int = 0, boundary_color=(0, 0, 0), figsize: tuple = (16, 7), dpi: int = 100, suptitle: str = 'Grain structure with grain boundaries')[source]
Two-panel figure: grain label map + Euler background, both with boundaries.
- Parameters:
rdr (EBSDReader) – Loaded EBSD reader.
show_euler_panel (bool) – If False, only the grain-label panel is shown (single axes).
euler_channel (int) – Which Euler channel (0=phi1, 1=Phi, 2=phi2) to use as orientation background in the right panel.
boundary_color (tuple) – RGB boundary overlay colour (values 0–1).
suptitle (str) – Overall figure title.
- Return type:
fig, axes (axes is a single Axes if show_euler_panel=False)
- upxo.viz.ebsdviz.plot_mdf(mdf: dict, peaks: dict, figsize: tuple[float, float] = (9, 4), angle_max: float = 65.0) tuple[source]
Plot a grain-boundary MDF histogram with KDE overlay, CSL reference lines, and auto-detected peak annotations.
- upxo.viz.ebsdviz.plot_mdf_selected(mdf: dict, peaks: dict, selected_peaks: dict, figsize: tuple[float, float] = (9, 4), angle_max: float = 65.0) tuple[source]
Replot the MDF histogram + KDE with only the user-selected peaks highlighted in colour (unselected bins are greyed out).
- Parameters:
- Return type:
fig, ax
- upxo.viz.ebsdviz.plot_csl_grain_map(lfi: numpy.ndarray, csl_grains: dict, figsize: tuple[float, float] = (10, 5), dpi: int = 130, alpha_bg: float = 0.15, suptitle: str | None = None) tuple[source]
Colour-code the grain label field by CSL boundary participation.
Each CSL type present in csl_grains gets its own colour. Grains that touch boundaries of more than one CSL type have blended colours. Non-CSL grains are shown in semi-transparent light grey.
- Parameters:
lfi (ndarray, shape (ny, nx)) – Integer grain label field (positive = grain ID, ≤0 = unindexed).
csl_grains (dict) – Output of
crystal_orientation.segregate_csl_pairs(). Keys are CSL labels; each value must have'grains_all','n_pairs', and'n_grains'.figsize – Standard figure parameters.
dpi – Standard figure parameters.
alpha_bg – Standard figure parameters.
suptitle – Standard figure parameters.
- Return type:
fig, ax
- upxo.viz.ebsdviz.print_parent_grain_summary(parent_info: dict, csl_grains: dict) None[source]
Print a formatted table of parent / twin / intermediate grain counts for each CSL type.
- upxo.viz.ebsdviz.plot_parent_grain_summary(parent_info: dict, figsize: tuple[float, float] = (8, 4), dpi: int = 120, title: str = 'Parent / twin / intermediate grain counts per CSL type', bar_width: float = 0.25, colors: tuple[str, str, str] = ('steelblue', 'coral', 'mediumseagreen')) tuple[source]
Grouped bar chart of pure-parent, pure-twin, and intermediate grain counts for each CSL type.
- Parameters:
parent_info (dict) – Output of
crystal_orientation.identify_parent_grains().figsize – Standard figure parameters.
dpi – Standard figure parameters.
title – Standard figure parameters.
bar_width (float) – Width of each bar group.
colors (tuple of str) – Three colours for (pure parents, pure twins, intermediates).
- Return type:
fig, ax
- upxo.viz.ebsdviz.plot_parent_twin_map(lfi: numpy.ndarray, parent_info: dict, figsize: tuple[float, float] = (10, 5), dpi: int = 130, alpha_bg: float = 0.12, colors: dict | None = None, suptitle: str | None = None) tuple[source]
Colour-code the grain label field by parent / twin / intermediate role for each CSL type present in parent_info.
One subplot is produced per CSL type. Within each subplot:
Pure parents – solid blue (default)
Pure twins – solid coral / red
Intermediates – solid green
Non-role grains – semi-transparent light grey
- Parameters:
parent_info (dict) – Output of
crystal_orientation.identify_parent_grains().figsize – Figure dimensions per subplot (total width scaled by n_csl).
dpi – Figure dimensions per subplot (total width scaled by n_csl).
alpha_bg (float) – Opacity of non-role background grains.
colors (dict, optional) – Override role colours. Keys:
'pure_parent','pure_twin','intermediate'. Values: any Matplotlib colour spec.suptitle (str, optional) – Figure-level title.
- Return type:
fig, axes
- upxo.viz.ebsdviz.plot_combined_parent_twin_map(lfi: numpy.ndarray, parent_info: dict, figsize: tuple[float, float] = (10, 5), dpi: int = 130, alpha_bg: float = 0.1, color_parent: str = '#4878CF', color_twin: str = '#D65F5F', color_intermediate: str = '#59A14F', color_non_participating: str = '#E8A33D', highlight: str = 'combined', suptitle: str | None = None) tuple[source]
Single map showing pure-parent, pure-twin, intermediate, and/or non-participating grains aggregated across all CSL types in parent_info, depending on highlight.
A grain that is a pure-parent in any CSL type → parent role. A grain that is a pure-twin in any CSL type → twin role. A grain that is intermediate in any CSL type → intermediate role. Priority when a grain appears in multiple roles: intermediate > parent > twin. A grain that is none of the above in any CSL type → non-participating.
- Parameters:
parent_info (dict) – Output of
crystal_orientation.identify_parent_grains().figsize – Figure size and resolution.
dpi – Figure size and resolution.
alpha_bg (float) – Opacity of the dimmed (non-highlighted) grains.
color_parent (str) – Matplotlib colour specs for each role.
color_twin (str) – Matplotlib colour specs for each role.
color_intermediate (str) – Matplotlib colour specs for each role.
color_non_participating (str) – Matplotlib colour specs for each role.
highlight ({'combined', 'parent', 'non_participating'}) –
'combined'(default): parent/twin/intermediate all coloured, non-participating grains dimmed — the original behaviour.'parent': only pure-parent grains coloured; twins, intermediates, and non-participating grains all dimmed alike.'non_participating': only non-participating grains coloured; every role grain (parent/twin/intermediate) is dimmed instead.suptitle (str or None) – Figure title. When
None(default), an auto-generated title matching highlight is used.
- Return type:
fig, ax
- upxo.viz.ebsdviz.compute_pct_interior_grains(lfi: numpy.ndarray, grain_ids) float | None[source]
Percentage of
grain_idsthat are completely interior tolfi– i.e. have no pixel on any of the map’s 4 edges (top/bottom row, left/right column). The EBSD-side equivalent ofTwinnedSimple3DBase.rank_temporal_slices_by_n’s per-slicepct_ng_in_2dcomputation, for direct comparison against a synthetic candidate’s<%.NgIn.2D>.Note this is inherently sensitive to the absolute size of the imaged/simulated region: a bigger map has relatively more grains that safely avoid the edge purely because there’s more area to be interior in, independent of anything about representativeness. Comparing this percentage between an EBSD map and a synthetic RVE of a different physical extent should be done cautiously.
- Parameters:
- Returns:
Percentage (0-100) of
grain_idswith no pixel on any oflfi’s 4 edges.Noneifgrain_idsis empty.- Return type:
float or None
- upxo.viz.ebsdviz.compute_grain_role_property_distributions(lfi: numpy.ndarray, parent_info: dict, prop: dict, neigh_gid: dict, selected_props: list | None = None, selected_groups: list | None = None, step_size: float = 1.0) dict[source]
Extract per-grain-role-group property value arrays – the pure data step of
plot_grain_role_property_stats, with no plotting. Split out so a caller can compute once and plot (or replot) separately, e.g. a GUI’s “Compute” vs “Plot” button pair.- Parameters:
parent_info (dict) – Output of
identify_parent_grains().prop (dict) – Per-grain property dict (grain_id → dict) as from
prop_ebsd, i.e.upxo.interfaces.defdap.ebsd_reader._char_lfi’s output – ALREADY in physical (µm) units, sinceEBSDReader.characterise()calls_char_lfiwith the realstep_size, not px_size=1. Expected keys:'area','aspect_ratio','perimeter','solidity','eq_diameter','major_axis_length','minor_axis_length','eccentricity','euler_number'– used as-is, with NO further step_size scaling here.neigh_gid (dict) – Neighbour-grain dict (grain_id → list of neighbour IDs) as from
neigh_gid_ebsd. Used to deriven_neighboursand every Tier-4 neighbour-role-composition property.selected_props (list of str, optional) – Subset of
GRAIN_ROLE_ALL_PROPS(see that constant’s Tier 1-4 grouping for what each property needs). Defaults to all.selected_groups (list of str, optional) – Subset of
GRAIN_ROLE_ALL_GROUPS. Defaults to all four.step_size (float) – EBSD step size (µm). Used ONLY for Tier 2 properties (circularity/gb_segment_length/n_tjp), which are recomputed fresh from lfi via
compute_slice_metricsrather than read from prop – everything else already carries physical units.
- Returns:
{prop_name: {group_name: ndarray of values}}– pass directly as thedataargument ofplot_grouped_distributions(), or toplot_grain_role_property_stats’s companion plot call.- Return type:
- upxo.viz.ebsdviz.plot_grain_role_property_distributions(data: dict, selected_groups: list | None = None, bins: int = 40, bw_method: str = 'scott', peak_prominence: float = 0.01, figsize_per: tuple[float, float] = (5, 4), dpi: int = 110, suptitle: str = 'Grain morphological & topological statistics by role', ncols: int | None = None, fontsize: float = 9.0) tuple[source]
Plot overlaid histograms + KDE + detected peaks from a pre-computed
datadict (output ofcompute_grain_role_property_distributions).Parameters mirror
plot_grain_role_property_stats’s plotting-related arguments; see that function’s docstring for details.selected_groupsmust match what was passed tocompute_grain_role_property_distributions(defaults to all four groups, same as there).- Return type:
fig, axes
- upxo.viz.ebsdviz.plot_grain_role_property_stats(lfi: numpy.ndarray, parent_info: dict, prop: dict, neigh_gid: dict, selected_props: list | None = None, selected_groups: list | None = None, step_size: float = 1.0, bins: int = 40, bw_method: str = 'scott', peak_prominence: float = 0.01, figsize_per: tuple[float, float] = (5, 4), dpi: int = 110, suptitle: str = 'Grain morphological & topological statistics by role', ncols: int | None = None, fontsize: float = 9.0) tuple[source]
For each selected property, plot overlaid histograms + KDE + detected peaks for each selected grain-role group (pure parents, pure twins, intermediates, non-role). Min / max / mean / std are embedded in the legend labels.
One-shot compute + plot convenience wrapper around
compute_grain_role_property_distributions+plot_grain_role_property_distributions– kept for existing callers (notebooks,repgen2d.see_grain_role_property_stats) that don’t need the compute/plot split.- Parameters:
parent_info (dict) – Output of
identify_parent_grains().prop (dict) – Per-grain property dict (grain_id → dict) as from
prop_ebsd. Expected keys:'area','aspect_ratio','perimeter','solidity'.neigh_gid (dict) – Neighbour-grain dict (grain_id → list of neighbour IDs) as from
neigh_gid_ebsd. Used to deriven_neighbours.selected_props (list of str, optional) – Subset of
['area', 'aspect_ratio', 'perimeter', 'solidity', 'n_neighbours']. Defaults to all five.selected_groups (list of str, optional) – Subset of
['pure_parents', 'pure_twins', 'intermediates', 'non_role']. Defaults to all four.step_size (float) – EBSD step size (µm). Multiplied into area (px² → µm²) and perimeter (px → µm) values.
bins (int) – Number of histogram bins.
bw_method (str) – Bandwidth selector passed to
scipy.stats.gaussian_kde.peak_prominence (float) – Fraction of KDE max used as minimum prominence for peak annotation.
figsize_per (tuple) –
(width, height)in inches for each subplot.dpi (int) – Figure resolution.
suptitle (str) – Figure-level title.
ncols (int or None) – Number of columns in the subplot grid.
None(default) places all subplots in a single row. E.g.ncols=2gives a 2-column grid;ncols=1gives a single column.fontsize (float) – Base font size in points. Axis labels and titles use this size; tick labels use
fontsize - 2; legend text usesfontsize - 2; peak annotations usefontsize - 3; the figure suptitle usesfontsize + 1. Default9.0.
- Return type:
fig, axes
- upxo.viz.ebsdviz.print_grain_role_ratios(ratios: dict) None[source]
Print a formatted table of grain-role counts and ratios produced by
crystal_orientation.compute_grain_role_ratios().- Parameters:
ratios (dict) – Output of
compute_grain_role_ratios().
- upxo.viz.ebsdviz.plot_grain_role_map(lfi: numpy.ndarray, role_sets: dict, figsize: tuple[float, float] = (10, 5), dpi: int = 130, alpha_bg: float = 0.1, color_parent: str = '#4878CF', color_twin: str = '#D65F5F', color_intermediate: str = '#59A14F', suptitle: str | None = None) tuple[source]
Plot a grain role map from pre-computed role sets (output of
crystal_orientation.assign_grain_roles_by_ratio()orcrystal_orientation.compute_grain_role_ratios()).- Parameters:
role_sets (dict) – Dict with keys
'pure_parents','pure_twins','intermediates','non_role'— each value either a set of grain IDs or a sub-dict with a'grain_ids'key (as returned byassign_grain_roles_by_ratio()).figsize – Figure parameters.
dpi – Figure parameters.
alpha_bg – Figure parameters.
color_parent (str) – Matplotlib colour specs for each role.
color_twin (str) – Matplotlib colour specs for each role.
color_intermediate (str) – Matplotlib colour specs for each role.
suptitle (str or None) – Figure title.
- Return type:
fig, ax
- upxo.viz.ebsdviz.plot_twin_introduction_map(lfi_before: numpy.ndarray, twin_result: dict, figsize: tuple = (14, 5), dpi: int = 130, color_parent: str = '#4878CF', color_twin: str = '#D65F5F', color_other: str = '#CCCCCC', alpha_other: float = 0.3, show_cut_lines: bool = True, suptitle=None) tuple[source]
Side-by-side comparison of the grain label field before and after twin introduction, with cut-lines overlaid on the “after” panel.
- Parameters:
lfi_before (ndarray, shape (ny, nx)) – Grain label field before twin introduction.
twin_result (dict) – Output of
crystal_orientation.introduce_twins_by_csl().figsize (tuple) – Total figure size (width, height).
dpi (int) – Figure resolution.
color_parent (str) – Colour for parent grains.
color_twin (str) – Colour for newly introduced twin grains.
color_other (str) – Colour for all other grains.
alpha_other (float) – Opacity for other grains.
show_cut_lines (bool) – If True, overlay the Sline2d cut-lines on the “after” panel.
suptitle (str or None) – Figure-level title.
- Return type:
fig, axes
- upxo.viz.ebsdviz.default_bin_width(data) float[source]
Freedman-Diaconis default histogram bin width for data, with the same fallback chain the EBSD Twin Thickness Statistics page’s inline plot uses: Freedman-Diaconis (2*IQR*n^-1/3) when the IQR is usable, Scott’s rule (3.49*std*n^-1/3) when the IQR is degenerate (e.g. very few points), and range/10 as a last resort when even std is 0 (constant data). Never returns 0 – callers divide by this.
- upxo.viz.ebsdviz.plot_twin_thickness_stats(stats: dict, bins: int | None = None, bin_width: float | None = None, figsize: tuple = (7, 4), dpi: int = 120, color: str = 'steelblue', title: str | None = None, show_kde: bool = False, kde_width: float | None = None, show_iqr: bool = False, extra_curves: dict | None = None, ax=None) tuple[source]
Plot a histogram of twin lamella thickness from the dict returned by
compute_twin_thickness_stats(i.e.compute_mc_twin_thickness’s result).- Parameters:
stats (dict) – Output of
compute_twin_thickness_stats.bins (int or None) – Explicit histogram bin count. Mutually exclusive with
bin_width– if both are None,default_bin_widthpicks a Freedman-Diaconis-based width automatically.bin_width (float or None) – Histogram bin width in the same units as
thick_um(µm). Converted to a bin count via the data’s own range.dpi (int)
color (str) – Bar fill colour for the primary (thickness) histogram.
title (str or None) – Custom figure title; auto-generated when None.
show_kde (bool) – Overlay a Gaussian KDE curve on top of the histogram, for the primary curve and every curve in
extra_curves.kde_width (float or None) – KDE bandwidth in µm (shared by every plotted curve). None: each curve uses scipy’s own default (Scott’s rule) bandwidth.
show_iqr (bool) – Draw vertical dashed lines at the primary thickness distribution’s Q1/Q3 (
stats['thick_q1']/['thick_q3']).extra_curves (dict {label: ndarray} or None) – Additional distributions (already in µm) to overlay as their own histogram + optional KDE curve, alongside the primary thickness curve – e.g. per-axis linear-intercept lengths. Each gets its own colour from a fixed cycle and its own legend entry.
ax (matplotlib.axes.Axes or None) – Draw into this existing Axes instead of creating a new Figure/Axes pair (for embedding into a GUI’s own canvas). When given, the caller owns the Figure and must NOT call
fig.tight_layout()/redraw itself – this function does not callplt.show()either way.
- Return type:
fig, ax
- upxo.viz.ebsdviz.plot_grain_area_comparison(scale_result: dict, bins: int = 50, pct_clip: float = 97.0, figsize: tuple = (8, 4), dpi: int = 120, color_ebsd: str = 'steelblue', color_sim: str = 'tomato') tuple[source]
Plot overlapping grain-area histograms for the EBSD target and the scaled synthetic structure.
- Parameters:
scale_result (dict) – Output of
compute_scale_factor_grain_size. Must contain'areas_ebsd_um2','areas_sim_um2','mean_area_ebsd_um2','scale_factor', and'mean_area_sim_um2'.bins (int) – Number of histogram bins.
pct_clip (float) – Upper percentile used to clip the x-axis range (avoids giant outlier grains dominating the axis).
figsize (figure size and resolution.)
dpi (figure size and resolution.)
color_ebsd (bar fill colours.)
color_sim (bar fill colours.)
- Return type:
fig, ax