Skip to content

Reintroduce dislocation segmentation & MultiVolumeViewer workflow (rebased after revert after PR 105) #107

Merged
clatlan merged 34 commits into
clatlan:devfrom
Abd-zak:dislo_segmentation
Mar 7, 2026
Merged

Reintroduce dislocation segmentation & MultiVolumeViewer workflow (rebased after revert after PR 105) #107
clatlan merged 34 commits into
clatlan:devfrom
Abd-zak:dislo_segmentation

Conversation

@Abd-zak

@Abd-zak Abd-zak commented Feb 7, 2026

Copy link
Copy Markdown
Collaborator

Reintroduce dislocation segmentation & MultiVolumeViewer workflow (rebased after revert)

This PR reintroduces the dislocation segmentation, analysis, and interactive 3D visualization workflow originally proposed in #105, which was merged and then reverted in #106 to allow for a proper review.

Since the revert, the feature branch has been:

  • reset to the original feature state,
  • cleanly rebased onto the current dev,
  • replayed using --reapply-cherry-picks to correctly handle the merge → revert history.

The feature logic is preserved; no functional content was dropped during the rebase.


Main contributions

1) Dislocation segmentation and analysis

  • New module: src/cdiutils/analysis/dislo.py

  • End-to-end workflow based on strain / phase-gradient features:

    • phase-offset scanning and gradient minimization
    • candidate detection via thresholding + connected components
    • geometric refinement (cylindrical masks, centerline extraction)
    • angular/ring sampling around dislocation cores
    • comparison with analytical dislocation models
  • Includes plotting utilities for experimental vs theoretical phase profiles.

2) MultiVolumeViewer extensions

  • Extended interactive 3D visualization in
    src/cdiutils/interactive/multiviewer_3d.py

  • Key features:

    • multi-layer rendering with independent colorbars
    • slice, plane, and clip layers (ParaView-like behavior)
    • flexible coloring modes (self / other layer / coordinates / constant)
    • robust async animation export
    • support for anisotropic voxel sizes and physical coordinates
  • Public plot="layers" entry point integrated via plotter.py.

3) Documentation and example workflow

  • Reproducible tutorial:

    • src/cdiutils/templates/dislocation_identification.ipynb
    • docs/tutorials/dislocation_identification.rst
  • Demonstrates the full workflow from segmentation to theory comparison.


Notes

  • This PR is intentionally scoped to the core feature files to keep the review focused.
  • The branch is rebased on the latest dev.
  • Large generated documentation artifacts were avoided to limit repository bloat.

Relation to previous PRs

Abd-zak added 20 commits February 3, 2026 18:50
Base updated to latest dev to fully integrate the analysis workflow with the current package version.
This commit significantly extends the MultiVolumeViewer widget into a
ParaView-like interactive 3D visualization tool for Jupyter environments.

Key additions and changes:

- Introduced a unified layer system supporting raw, slice, plane, and clip layers
- Slice layers:
  * Axis-aligned slicing with adjustable position and thickness
  * Independent layers, decoupled from the source after creation
- Plane layers:
  * Arbitrary planes defined by physical-space normal and origin
  * Optional slab thickness and finite spatial extent
  * Robust in-plane basis construction and correct physical sampling
- Clip layers:
  * Half-space clipping of raw volumes using a plane (normal + origin)
  * Selectable side relative to the plane normal (up / down)
  * Geometry extraction via marching cubes with clean planar cuts
  * Coloring sampled from the original (unclipped) source volume

- Flexible coloring:
  * Color by self, other raw layers, spatial coordinates, or constants
  * Independent colorbars per visible layer

- Robust NaN handling:
  * Per-layer NaN policy (none / mean / zero / min / max)
  * For slice and plane layers with NaN policy = "none":
    - NaN regions rendered as true holes (opacity = 0)
    - Behavior consistent with ParaView-style NaN hiding
  * Consistent handling of NaN and ±inf across all layer types

- UI and UX improvements:
  * Contextual “Create layer” workflow
  * Two-column layout for plane and clip normal/origin controls
  * Independent edit panels per selected layer
  * Removal of unused UI components
  * Improved slider range synchronization

- Rendering and consistency:
  * Full support for anisotropic voxel sizes
  * All geometry defined and rendered in physical (x, y, z) space
  * Lighting controls preserved for mesh-based layers

- Code quality:
  * Refactored for clarity and separation of concerns
  * Formatted with ruff (line length 79)
  * All ruff checks pass with no violations

This completes the core functionality of MultiVolumeViewer as a
self-contained, notebook-native 3D visualization tool for scientific
volume data exploration (e.g. BCDI, tomography, FEM fields).
…ogic, and add robust async animation export

This commit introduces a substantial refactor and feature expansion of MultiVolumeViewer, focusing on UI stability,
deterministic color handling, and scalable animation export.

1. Color-range and color_by handling (major behavioral fix)
- Reset range slider bounds when color_by changes instead of only expanding bounds.
- Track the active reference field via _range_ref_color_by to detect color_by transitions.
- On color_by change:
  * Recompute min/max from the newly selected scalar field.
  * Reset the slider window to the full valid range unless the user explicitly overrides it.
- Prevents stale or misleading color scaling when switching between __self__, other layers,
  spatial coordinates (__x__, __y__, __z__), or constants.
- Ensures cmin/cmax always reflect the active coloring source.

Impact: fixes long-standing UI inconsistency and ensures physically meaningful color interpretation.

2. NaN handling consistency for derived layers
- Clear separation between base data (data2d_base, NaNs preserved) and displayed data (policy-applied).
- Slice and plane layers now:
  * Respect nan_policy="none" by producing true transparency holes.
  * Match ParaView-like NaN masking behavior.
- Geometry NaNs and color-intensity NaNs are handled independently and deterministically.

3. Observer lifecycle management (UI performance and correctness)
- Explicit unobserve / re-observe logic for slice and plane panels.
- Observers are stored per panel (_slice_obs, _plane_obs) and safely detached before rebuild.
- Prevents duplicate callbacks, refresh storms, and memory leaks during repeated UI edits.

4. Layer rename UX fix
- Introduced _EDIT_PLACEHOLDER="__choose_layer__" and _suspend_rename_autofill_once flag.
- Rename textbox auto-fills only when appropriate.
- Prevents overwriting user input when switching layers.
- Fixes regression causing confusing rename behavior.

5. Rendering and animation export architecture
- Added configurable rendering backend:
  rendering_mode ∈ {"safe", "fast", "process"}.
- Introduced render_workers and render_in_flight controls.
- Implemented async / parallel animation export:
  * Geometry/materialization remains sequential and UI-safe.
  * PNG rendering may run in a process pool.
  * Frames are streamed and written in order without large in-memory buffers.
- Added _render_fig_json_to_png helper to decouple Plotly rendering from UI state.

Impact: enables stable high-resolution MP4/GIF export without freezing the notebook or breaking widgets.

6. Global rendering safety controls
- Added force_fixed_color_range flag to disable auto-ranging globally.
- Guarantees deterministic color scaling for publications and animations.

7. Miscellaneous UI and layout improvements
- Grid visibility toggle respected during theme updates.
- Camera reset and forced relayout after exports.
- More robust colorbar placement logic.
- Minor cleanup of colormap discovery and option exposure.

Summary:
This refactor upgrades MultiVolumeViewer into a robust, production-grade visualization and export engine
with correct color semantics, stable UI behavior under heavy interaction, and scalable animation export.
- Restrict layers input to dict[str, np.ndarray]
- Forward viewer-specific options via `layers_kwargs`
- Update docstrings to reflect current behavior
- Align arguments with new Plotter and MultiVolumeViewer APIs
- No functional changes
This enables reliable MP4 animation export via imageio on all platforms,
by ensuring the FFmpeg backend required by imageio is available.

Notes:
- This does NOT install a system ffmpeg binary.
- GIF export continues to rely on an external ffmpeg executable and
  is handled separately in code with explicit runtime checks.
@Abd-zak Abd-zak requested a review from clatlan February 10, 2026 19:26
@Abd-zak Abd-zak self-assigned this Feb 20, 2026
@clatlan

clatlan commented Feb 22, 2026

Copy link
Copy Markdown
Owner

I had a quick look at the PR which is nice as in introduces new features. Can you address the following points:

  • the dislo.py is a bit long and seems rather complex and could be easily broken down in several files. Perhaps we should consider a dislocation sub-package within cdiutils.analysis. Then make the function available directly at the disclocation sub-package so it does not change the usage. I would opt for dislocation instead of dislo.
  • An important remark is the import of libraries within functions, can you please make sure all imports are handled at module level, not hidden in packages, that might mess up a few things and is not considered as pythonic. This will come with handling of the new dependencies. With perhaps a try: import as you can see in the interactive module. You can then create a new error class in the __init__.py of the dislocation module.
  • I would add some unit test to make this PR complete. That would be awesome.

@clatlan clatlan marked this pull request as ready for review February 22, 2026 15:56
@Abd-zak

Abd-zak commented Feb 22, 2026

Copy link
Copy Markdown
Collaborator Author

ok. i agree with the sub package for dislocation.
I will work on some new features in multiviewer and handle properly the import. I will add a translation and rotation handler which i think are important also title and unit.

Abd-zak added 5 commits March 5, 2026 11:33
- create cdiutils.analysis.dislocation subpackage
- split large dislo.py into modular modules:
  _strain_map, _clustering, _geometry, _ring, _theory, _phase_decomp, _plotting
- expose public API via dislocation.__init__
- improve maintainability and readability
Abd-zak added 7 commits March 5, 2026 12:07
…e UI

This commit introduces several improvements to the MultiVolumeViewer interactive
3D viewer, focusing on better spatial control of layers, clearer axis
representation, and improved UI structure.

1. Per-layer rigid transformations
----------------------------------
A new transform system allows each layer to be visually manipulated independently.

New capabilities:
- Rotation controls: Rx, Ry, Rz
- Translation controls: Tx, Ty, Tz
- Transformations are applied only at the rendering stage, meaning:
  * the underlying voxel data remain unchanged
  * transformations affect only the displayed geometry

Implementation details:
- Transform state stored per layer (self._layer_transform)
- Applied in the rendering pipeline before plotting
- Default transform state initialized when layers are created
- New layers start with zero transform

This enables spatial comparison of volumes and derived layers without modifying
the original data.

2. Axis unit support
--------------------
An optional 'unit' parameter was added to allow axis labeling with physical units.

Example:
X (nm), Y (nm), Z (nm)

Behavior:
- unit=None -> axis labels remain X, Y, Z
- unit="nm" -> axis labels become X (nm), Y (nm), Z (nm)

Implementation:
- new argument in MultiVolumeViewer
- helper method used when configuring Plotly scene axes
- forwarded via layers_kwargs in Plotter

3. Expanded transform ranges
----------------------------
Translation sliders (Tx, Ty, Tz) now scale with the physical extent of the dataset.

Range is derived from the dataset physical size based on voxel_size and
volume dimensions. This allows moving layers significantly outside the
volume if needed.

4. Slice panel improvements
---------------------------
The slice UI logic was corrected to ensure consistent behavior.

Key fixes:
- Slice position handled consistently
- Prevents empty slices caused by invalid position values
- Axis change correctly updates slider limits
- Center button restores the mid-slice position

These fixes restore robust slice rendering while maintaining compatibility
with the interpolation pipeline.

5. Improved edit panel structure
--------------------------------
The right-side editing panel was reorganized.

Changes:
- Lighting and Transform controls moved into collapsible sections
- Implemented via a collapsible UI helper
- Improves readability of the layer editor
- Reduces vertical clutter when editing multiple parameters

6. Documentation updates
------------------------
Module documentation was updated to reflect new functionality:

- Added description of the transform system
- Documented axis unit feature
- Updated feature list
- Updated Plotter documentation for layers_kwargs

Result
------
The viewer now supports:
- independent spatial manipulation of layers
- clearer axis labeling with physical units
- improved UI organization
- more robust slice handling

while maintaining compatibility with the existing rendering and animation
export system.
…e new files appear to be foramtted after updatting the ruff version from 0.1.14 to 0.15.4
…nd fix traitlets deprecation

This commit introduces unit test coverage for the dislocation analysis module and the MultiVolumeViewer 3D interface,
and fixes a traitlets/ipywidgets deprecation warning related to ButtonStyle usage.

1. Dislocation module testing
   Added a comprehensive pytest suite for the dislocation analysis module.

New test file:
tests/test_dislocation.py

Covered functionality includes:

* Geometry utilities

  * extract_structure
  * fit_line_3d
  * generate_filled_cylinder
  * circular mask generation
  * phase extraction around dislocations

* Ring analysis utilities

  * center angle computation
  * removal of large angular jumps
  * phase ring processing pipeline

* Phase decomposition

  * validation of cos² / sin² phase recovery

* Strain map utilities

  * map_min_gradient behavior
  * shape and range validation

* Clustering pipeline

  * clusters_dislo_strain_map smoke test

* Theory utilities

  * vector operations
  * rotation matrix correctness
  * dislocation phase model properties

These tests ensure that the main computational routines of the dislocation module execute correctly and return outputs with expected structure and physical properties.

2. MultiVolumeViewer 3D testing
   Added a test suite for the interactive 3D multi-volume visualization system.

New test file:
tests/test_multiviewer_3d.py

Covered functionality includes:

* Input validation for dict_data
* Raw layer registration and management
* NaN handling policies

  * preserve
  * mean
  * zero
  * min
  * max
* Mesh trace generation for volumetric layers
* Slice layer creation and registration
* Basic rendering pipeline smoke tests

These tests validate the internal logic of the viewer without requiring a graphical interface.

3. Traitlets / ipywidgets deprecation fix
   Resolved a DeprecationWarning triggered by passing an unsupported argument to ButtonStyle.

Previous pattern:
widgets.Button(
...,
style={"description_width": "60px"}
)

This caused the warning:
DeprecationWarning: Passing unrecognized arguments to
super(ButtonStyle).**init**(description_width='60px')

Resolution:

* Removed description_width from ButtonStyle usage
* When sizing was required, replaced with Layout-based sizing

Example fix:
widgets.Button(
...,
layout=widgets.Layout(width="60px")
)

This ensures compatibility with newer versions of:
traitlets
ipywidgets

4. Test robustness improvements
   All tests were verified under strict deprecation enforcement:

   pytest -W error::DeprecationWarning

This confirms the codebase no longer triggers traitlets deprecation warnings.

Dislocation tests:
pytest tests/test_dislocation.py
→ all tests passed

MultiVolumeViewer tests:
pytest tests/test_multiviewer_3d.py
→ all tests passed

Strict warning mode:
pytest -W error::DeprecationWarning
→ all tests passed

* Improves reliability and maintainability of the dislocation analysis code.
* Adds regression protection for interactive visualization logic.
* Ensures forward compatibility with modern traitlets and ipywidgets versions.
* Provides a foundation for future extension of visualization and analysis features.
@Abd-zak

Abd-zak commented Mar 5, 2026

Copy link
Copy Markdown
Collaborator Author

Done all features and test units.

self.title = title
self.layers_kwargs = layers_kwargs or {}

# 🔒 STRICT: MultiVolumeViewer only accepts dict

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the lock please !

@clatlan clatlan left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good PR, thank you very much @Abd-zak

@clatlan clatlan merged commit 06e5d90 into clatlan:dev Mar 7, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants