Skip to content

Add widget state export helpers and harden projected DOS tests#340

Merged
janosh merged 7 commits intomainfrom
widget-display-to-dict-methods
Feb 23, 2026
Merged

Add widget state export helpers and harden projected DOS tests#340
janosh merged 7 commits intomainfrom
widget-display-to-dict-methods

Conversation

@janosh
Copy link
Owner

@janosh janosh commented Feb 23, 2026

Summary

  • add MatterVizWidget.display() and MatterVizWidget.to_dict() with an explicit public state_fields contract
  • strengthen widget and phonon tests, including regression checks for projected DOS stacking isolation and unstacked total overlays
  • simplify projected DOS stack-group bookkeeping and improve phonopy example diagnostics with dedicated missing-DOS error types

Test plan

  • pytest tests/widgets/test_matterviz.py tests/phonons/test_phonon_plotly.py -q
  • mutation checks on to_dict() key export and projected DOS stacking/total-overlay behavior
  • pre-commit hooks run during commit (ruff, ty, docs/link checks, formatting/lint hooks)

Summary by CodeRabbit

  • New Features

    • Notebook-friendly widget display() and to_dict(), plus explicit synced state fields.
  • Improvements

    • DOS plotting: model-aware stacking while keeping total DOS as an overlay.
    • XRD normalization: stricter dict/schema validation and consistent hkls handling.
    • Trajectory handling: richer validation and preserved metadata.
    • Various typing/clarity cleanups across plotting utilities.
  • Bug Fixes

    • More specific errors for missing DOS (distinct missing-total vs missing-projected).
  • Documentation

    • Updated phonons anchors.
  • Tests

    • Expanded tests for DOS stacking, XRD, trajectory, and widget state.
  • Chores

    • Bumped toolchain hook versions.

- add `display()` convenience method to `MatterVizWidget` for notebook usage
- add `to_dict()` to export stable public widget state fields
- add parameterized tests to verify exported keys and runtime state updates
@janosh janosh added phonons Phonon bands and DOS plots testing Test all the things dx Developer experience labels Feb 23, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 23, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Bumps pre-commit hook versions; adds two specific Phonopy DOS-missing exceptions; updates phonon DOS plotting to track per-trace stack groups and adjust stacking fill behavior; exposes MatterVizWidget public state via state_fields, display(), and to_dict(); tightens XRD normalization and FermiSurfaceWidget validation; assorted typing cleanups and expanded tests.

Changes

Cohort / File(s) Summary
Toolchain / pre-commit
./.pre-commit-config.yaml
Minor version bumps for multiple hooks (ruff, nbstripout, mirrors-eslint, python-jsonschema). No new hooks or behavioral changes.
Phonon DOS exceptions
assets/scripts/phonons/phonon_dos.py
Added PhonopyTotalDosMissingError and PhonopyProjectedDosMissingError; specific exceptions raised where total or projected DOS are absent.
Phonon DOS plotting / stacking
pymatviz/phonons/figures.py
Added stack_group_by_trace and _stack_group() helper; assemble DOS traces per project/label and adjust stacking fill modes (tozeroy/tonexty) per group.
MatterViz widget API
pymatviz/widgets/matterviz.py
Added public state_fields attribute and methods display() and to_dict() to expose and render widget state.
Widgets: normalization & validation
pymatviz/widgets/_normalize.py, pymatviz/widgets/fermi_surface.py, pymatviz/widgets/xrd.py
Introduced strict dict-schema validation for XRD (canonical vs Ferrox schemas) and Ferrox HKL normalization; FermiSurfaceWidget now requires exactly one of fermi_data or band_data; XrdWidget docstring updated.
Trajectory validation & normalization
pymatviz/widgets/trajectory.py, tests/widgets/test_trajectory_widget.py
Added _validate_trajectory_dict and is_structure_like helpers; _normalize_trajectory now supports and validates dict-shaped trajectories and preserves top-level metadata; added regression tests for many invalid inputs and edge cases.
Widgets tests & state behavior
tests/widgets/test_new_widgets.py, tests/widgets/test_matterviz.py, tests/widgets/*
Expanded and parameterized widget tests: normalization, input validation, state export (to_dict), ASE skip checks, and FermiSurface invalid-combo tests; updated MatterViz tests to assert exported public state only.
Phonons tests
tests/phonons/test_phonon_plotly.py
Parametrized DOS stacking tests per model label; ensures per-model stacking resets, "Total" overlay stays unstacked, and stacked traces use expected fill modes.
XRD & normalization helpers
pymatviz/widgets/_normalize.py
New internal helper _normalize_ferrox_hkls; stricter dict validation and clearer ValueError messages on schema mismatches.
Type/typing cleanup & small refactors
pymatviz/*, assets/scripts/cluster/..., examples/..., tests/...
Removed inline type-ignore comments, added/used cast and explicit callable casts in several modules, small signature change in example (return type → `float
Figure/structure minor cleanups
pymatviz/structure/figures.py, pymatviz/structure/helpers.py, pymatviz/brillouin.py, pymatviz/rdf/figures.py
Removed in-line type-ignore comments and simplified small lattice/access assignments; no behavioral change.
Docs anchor update
readme.md
Updated Phonons table anchors to new line-number targets.

Sequence Diagram(s)

(omitted — changes do not introduce multi-component sequential control flow warranting a diagram)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

widgets

Poem

🐰 A hop, a nibble, code lines neat and spry,
DOS now asks clearly when totals go awry,
Widgets display their state with a flourish and grin,
Trajectories vetted before they’re let in,
Tests clap their paws — the garden’s tidy and spry.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the two main changes: adding widget state export helpers (display/to_dict methods on MatterVizWidget) and hardening projected DOS tests with better error types and stacking isolation.
Docstring Coverage ✅ Passed Docstring coverage is 97.73% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch widget-display-to-dict-methods

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
examples/ward_metallic_glasses/formula_features.py (1)

122-134: ⚠️ Potential issue | 🟡 Minor

Fix docstring default for on_key_err.

The docstring still says “Defaults to 'raise'” while the function default is "set-none" (Line 113). This is misleading for users.

🔧 Suggested docstring fix
-            Defaults to "raise".
+            Defaults to "set-none".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/ward_metallic_glasses/formula_features.py` around lines 122 - 134,
The docstring for the parameter on_key_err is incorrect: update the default
description to match the function signature (change "Defaults to 'raise'" to
"Defaults to 'set-none'") in the docstring in
examples/ward_metallic_glasses/formula_features.py so the documented default
matches the actual default value of the on_key_err parameter (refer to the
on_key_err parameter in the function signature).
pymatviz/phonons/figures.py (1)

517-523: ⚠️ Potential issue | 🟠 Major

Reset fill baseline when a new stack group starts.

When stack=True and project is set, traces are grouped by their label (e.g., "Label1", "Label2"). The current code always uses fill="tonexty", which fills between the current trace and the previous trace in the figure. This causes misalignment when a new group starts: the first trace of group 2 fills to the last trace of group 1 instead of to the y=0 baseline. The first trace of each group should use fill="tozeroy", with subsequent traces in that group using fill="tonexty".

🔧 Suggested fix
         if stack:
             stack_group = _stack_group(dos_name)
-            densities = densities + cumulative_density_by_group.get(
-                stack_group, np.zeros_like(densities)
-            )
-            cumulative_density_by_group[stack_group] = densities
-            scatter_kwargs["fill"] = "tonexty"
+            prev = cumulative_density_by_group.get(stack_group)
+            base = prev if prev is not None else np.zeros_like(densities)
+            densities = densities + base
+            cumulative_density_by_group[stack_group] = densities
+            scatter_kwargs["fill"] = "tonexty" if prev is not None else "tozeroy"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pymatviz/phonons/figures.py` around lines 517 - 523, The current code always
sets scatter_kwargs["fill"] = "tonexty", causing the first trace of a new stack
group to fill to the previous group's last trace; update the logic around
stack_group/_stack_group and cumulative_density_by_group so that when a
stack_group is seen for the first time (i.e., stack_group not in
cumulative_density_by_group) you set scatter_kwargs["fill"] = "tozeroy" and
initialize cumulative_density_by_group[stack_group] to an appropriate zero
baseline (e.g., np.zeros_like(densities)) before adding densities, otherwise for
subsequent traces keep scatter_kwargs["fill"] = "tonexty". Ensure this check
occurs where densities are combined and before fig.add_scatter is called.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@examples/ward_metallic_glasses/formula_features.py`:
- Around line 338-345: The print loop assumes numeric feature values and uses
f"{...:.2f}", which will TypeError when calc_liu_features returns
Optional[float]; update the printing for both the Pt50P50 and test_comp2 loops
to guard each value (e.g., check if features[feature].get(test_comp) is None)
and print a safe fallback like "N/A" (or format the float with :.2f only when
not None) so that missing binary systems don't crash the print routine;
references: calc_liu_features, features dict, test_comp and test_comp2 loops.

---

Outside diff comments:
In `@examples/ward_metallic_glasses/formula_features.py`:
- Around line 122-134: The docstring for the parameter on_key_err is incorrect:
update the default description to match the function signature (change "Defaults
to 'raise'" to "Defaults to 'set-none'") in the docstring in
examples/ward_metallic_glasses/formula_features.py so the documented default
matches the actual default value of the on_key_err parameter (refer to the
on_key_err parameter in the function signature).

In `@pymatviz/phonons/figures.py`:
- Around line 517-523: The current code always sets scatter_kwargs["fill"] =
"tonexty", causing the first trace of a new stack group to fill to the previous
group's last trace; update the logic around stack_group/_stack_group and
cumulative_density_by_group so that when a stack_group is seen for the first
time (i.e., stack_group not in cumulative_density_by_group) you set
scatter_kwargs["fill"] = "tozeroy" and initialize
cumulative_density_by_group[stack_group] to an appropriate zero baseline (e.g.,
np.zeros_like(densities)) before adding densities, otherwise for subsequent
traces keep scatter_kwargs["fill"] = "tonexty". Ensure this check occurs where
densities are combined and before fig.add_scatter is called.
ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 957b22f and 8137cec.

📒 Files selected for processing (13)
  • assets/scripts/cluster/composition/cluster_compositions_matbench.py
  • examples/ward_metallic_glasses/formula_features.py
  • pymatviz/brillouin.py
  • pymatviz/classify/confusion_matrix.py
  • pymatviz/cluster/composition/plot.py
  • pymatviz/phonons/figures.py
  • pymatviz/powerups.py
  • pymatviz/rdf/figures.py
  • pymatviz/structure/figures.py
  • pymatviz/structure/helpers.py
  • readme.md
  • tests/test_brillouin.py
  • tests/widgets/test_new_widgets.py
✅ Files skipped from review due to trivial changes (4)
  • pymatviz/brillouin.py
  • pymatviz/structure/figures.py
  • tests/test_brillouin.py
  • pymatviz/rdf/figures.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • readme.md

- add strict XRD normalization support for canonical and Ferrox dict schemas with validation and hkls normalization
- enforce exactly one Fermi surface data source and strengthen widget tests by asserting meaningful normalized state
- fix projected DOS stacked fill baseline per model group and update metallic-glass example docs/output formatting for optional values
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
tests/phonons/test_phonon_plotly.py (1)

402-414: Minor redundancy: same trace lookup performed twice.

first_group_trace (lines 409-413) performs the identical lookup as lines 403-407, finding the same trace. Consider reusing the result:

♻️ Suggested simplification
     for model_label in model_labels:
-        trace_name = next(
-            trace.name
+        first_group_trace = next(
+            trace
             for trace in fig_stacked.data
             if trace.name.startswith(f"{model_label} - ")
         )
-        assert np.allclose(stacked_by_name[trace_name], unstacked_by_name[trace_name])
-        first_group_trace = next(
-            trace
-            for trace in fig_stacked.data
-            if trace.name.startswith(f"{model_label} - ")
-        )
+        assert np.allclose(
+            stacked_by_name[first_group_trace.name],
+            unstacked_by_name[first_group_trace.name],
+        )
         assert first_group_trace.fill == "tozeroy"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/phonons/test_phonon_plotly.py` around lines 402 - 414, The test
redundantly looks up the same trace twice; compute the trace once by replacing
the first generator that finds trace_name/trace with a single variable (e.g.,
found_trace = next(trace for trace in fig_stacked.data if
trace.name.startswith(f"{model_label} - "))), use found_trace.name for the
stacked_by_name/unstacked_by_name comparison and then assert found_trace.fill ==
"tozeroy", and remove the duplicate generator expressions that create
trace_name/first_group_trace separately.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@tests/phonons/test_phonon_plotly.py`:
- Around line 402-414: The test redundantly looks up the same trace twice;
compute the trace once by replacing the first generator that finds
trace_name/trace with a single variable (e.g., found_trace = next(trace for
trace in fig_stacked.data if trace.name.startswith(f"{model_label} - "))), use
found_trace.name for the stacked_by_name/unstacked_by_name comparison and then
assert found_trace.fill == "tozeroy", and remove the duplicate generator
expressions that create trace_name/first_group_trace separately.
ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8137cec and 9994010.

📒 Files selected for processing (9)
  • examples/ward_metallic_glasses/formula_features.py
  • pymatviz/phonons/figures.py
  • pymatviz/widgets/_normalize.py
  • pymatviz/widgets/fermi_surface.py
  • pymatviz/widgets/xrd.py
  • readme.md
  • tests/phonons/test_phonon_plotly.py
  • tests/widgets/test_matterviz.py
  • tests/widgets/test_new_widgets.py
✅ Files skipped from review due to trivial changes (1)
  • pymatviz/widgets/xrd.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • readme.md
  • tests/widgets/test_matterviz.py

- detect canonical and Ferrox schemas only when all required keys are present, and keep targeted errors for partial schemas
- add regression coverage for mixed-key XRD dicts that should resolve through complete Ferrox schema
- simplify projected DOS stack reset test by reusing one located trace per model label
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
pymatviz/widgets/_normalize.py (1)

133-156: hkls normalization logic is correct but could benefit from helper extraction.

The nested conditional checks for different hkls formats work correctly, but the deep nesting and repeated structure validation make this harder to maintain. Consider extracting a helper function like _normalize_ferrox_hkls(hkls_data) if this grows more complex.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pymatviz/widgets/_normalize.py` around lines 133 - 156, Extract the nested
hkls validation/normalization logic into a helper function (e.g.,
_normalize_ferrox_hkls(hkls_data)) and replace the current inlined checks inside
the block that reads hkls_data = obj.get("hkls") with a call to that helper; the
helper should accept hkls_data, perform the two validation branches (single hkl
entries as [h,k,l] and grouped entries where first element is [h,k,l]) and
return the normalized list or the original hkls_data fallback, so update the
assignment to normalized["hkls"] = _normalize_ferrox_hkls(hkls_data).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@pymatviz/widgets/_normalize.py`:
- Around line 133-156: Extract the nested hkls validation/normalization logic
into a helper function (e.g., _normalize_ferrox_hkls(hkls_data)) and replace the
current inlined checks inside the block that reads hkls_data = obj.get("hkls")
with a call to that helper; the helper should accept hkls_data, perform the two
validation branches (single hkl entries as [h,k,l] and grouped entries where
first element is [h,k,l]) and return the normalized list or the original
hkls_data fallback, so update the assignment to normalized["hkls"] =
_normalize_ferrox_hkls(hkls_data).
ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9994010 and 65031d6.

📒 Files selected for processing (3)
  • pymatviz/widgets/_normalize.py
  • tests/phonons/test_phonon_plotly.py
  • tests/widgets/test_new_widgets.py

- extract Ferrox HKL normalization into a helper for cleaner XRD input handling
- validate trajectory dict schemas with clearer type/key errors while preserving legacy structure-frame dicts
- add and refine trajectory widget regression tests for invalid schemas and restored lifecycle state
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
tests/widgets/test_trajectory_widget.py (1)

423-496: Comprehensive schema validation test coverage.

The parameterized test cases effectively exercise the validation error paths in _validate_trajectory_dict. The test at lines 466-488 correctly expects the "coordinate key" error since the validation checks species before abc/xyz.

Consider adding test cases for the remaining validation branches if full coverage is desired:

  • Missing label key
  • Missing properties dict
  • Missing lattice derived keys (a, b, c, alpha, beta, gamma)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/widgets/test_trajectory_widget.py` around lines 423 - 496, The test
suite misses cases exercising some branches in _validate_trajectory_dict; add
parameterized cases to
test_trajectory_widget_invalid_dict_schema_raises_helpful_error that trigger
missing 'label' in a site, missing 'properties' dict on a frame/trajectory, and
missing lattice-derived keys ('a','b','c','alpha','beta','gamma') so the
TrajectoryWidget(trajectory=...) validation raises the expected
ValueError/TypeError with the correct messages; reference the existing test
function name test_trajectory_widget_invalid_dict_schema_raises_helpful_error
and the validator _validate_trajectory_dict to locate where to extend the
parameter list and expected error messages.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pymatviz/widgets/trajectory.py`:
- Around line 255-259: Remove the duplicate local is_structure_like function and
import the canonical implementation from process_data (from
pymatviz.process_data import is_structure_like); replace usages of the local
function with the imported one so the code relies on the global isinstance
checks against STRUCTURE_CLASSES (which will properly recognize PhonopyAtoms and
other supported types) instead of the weaker attribute-based duck-typing.

---

Nitpick comments:
In `@tests/widgets/test_trajectory_widget.py`:
- Around line 423-496: The test suite misses cases exercising some branches in
_validate_trajectory_dict; add parameterized cases to
test_trajectory_widget_invalid_dict_schema_raises_helpful_error that trigger
missing 'label' in a site, missing 'properties' dict on a frame/trajectory, and
missing lattice-derived keys ('a','b','c','alpha','beta','gamma') so the
TrajectoryWidget(trajectory=...) validation raises the expected
ValueError/TypeError with the correct messages; reference the existing test
function name test_trajectory_widget_invalid_dict_schema_raises_helpful_error
and the validator _validate_trajectory_dict to locate where to extend the
parameter list and expected error messages.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 65031d6 and afdc0b6.

📒 Files selected for processing (3)
  • pymatviz/widgets/_normalize.py
  • pymatviz/widgets/trajectory.py
  • tests/widgets/test_trajectory_widget.py

- validate and complete trajectory dict inputs more robustly, including per-site coordinate checks and safer species handling
- simplify widget tests by removing tautological/perf-brittle assertions and replacing them with stronger behavioral checks
@janosh janosh merged commit 3ffbf98 into main Feb 23, 2026
47 checks passed
@janosh janosh deleted the widget-display-to-dict-methods branch February 23, 2026 19:51
janosh added a commit that referenced this pull request Feb 25, 2026
* Add widget display and state export helpers

- add `display()` convenience method to `MatterVizWidget` for notebook usage
- add `to_dict()` to export stable public widget state fields
- add parameterized tests to verify exported keys and runtime state updates

* fix ty errors

* Improve widget normalization and projected DOS stacking behavior

- add strict XRD normalization support for canonical and Ferrox dict schemas with validation and hkls normalization
- enforce exactly one Fermi surface data source and strengthen widget tests by asserting meaningful normalized state
- fix projected DOS stacked fill baseline per model group and update metallic-glass example docs/output formatting for optional values

* Refine XRD schema precedence and test readability

- detect canonical and Ferrox schemas only when all required keys are present, and keep targeted errors for partial schemas
- add regression coverage for mixed-key XRD dicts that should resolve through complete Ferrox schema
- simplify projected DOS stack reset test by reusing one located trace per model label

* Harden trajectory dict handling and normalize Ferrox HKLs

- extract Ferrox HKL normalization into a helper for cleaner XRD input handling
- validate trajectory dict schemas with clearer type/key errors while preserving legacy structure-frame dicts
- add and refine trajectory widget regression tests for invalid schemas and restored lifecycle state

* Harden trajectory normalization tests

- validate and complete trajectory dict inputs more robustly, including per-site coordinate checks and safer species handling
- simplify widget tests by removing tautological/perf-brittle assertions and replacing them with stronger behavioral checks

* fix ty
janosh added a commit that referenced this pull request Feb 25, 2026
* Add widget display and state export helpers

- add `display()` convenience method to `MatterVizWidget` for notebook usage
- add `to_dict()` to export stable public widget state fields
- add parameterized tests to verify exported keys and runtime state updates

* fix ty errors

* Improve widget normalization and projected DOS stacking behavior

- add strict XRD normalization support for canonical and Ferrox dict schemas with validation and hkls normalization
- enforce exactly one Fermi surface data source and strengthen widget tests by asserting meaningful normalized state
- fix projected DOS stacked fill baseline per model group and update metallic-glass example docs/output formatting for optional values

* Refine XRD schema precedence and test readability

- detect canonical and Ferrox schemas only when all required keys are present, and keep targeted errors for partial schemas
- add regression coverage for mixed-key XRD dicts that should resolve through complete Ferrox schema
- simplify projected DOS stack reset test by reusing one located trace per model label

* Harden trajectory dict handling and normalize Ferrox HKLs

- extract Ferrox HKL normalization into a helper for cleaner XRD input handling
- validate trajectory dict schemas with clearer type/key errors while preserving legacy structure-frame dicts
- add and refine trajectory widget regression tests for invalid schemas and restored lifecycle state

* Harden trajectory normalization tests

- validate and complete trajectory dict inputs more robustly, including per-site coordinate checks and safer species handling
- simplify widget tests by removing tautological/perf-brittle assertions and replacing them with stronger behavioral checks

* fix ty + update readme citations
@coderabbitai coderabbitai bot mentioned this pull request Mar 1, 2026
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dx Developer experience phonons Phonon bands and DOS plots testing Test all the things

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant