Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
4314f9b
Standardize tutorial project save paths
AndrewSazonov Jun 3, 2026
32b3151
Seed and standardize save paths for Bayesian tutorials
AndrewSazonov Jun 3, 2026
eb9ff5e
Regenerate tutorial notebooks
AndrewSazonov Jun 3, 2026
f40054e
Add tutorial-output regression test against fit baseline
AndrewSazonov Jun 3, 2026
0b4ae45
Apply pixi run fix auto-fixes
AndrewSazonov Jun 3, 2026
3d5fe64
Assert persisted result_kind in tutorial-output test
AndrewSazonov Jun 3, 2026
7a02030
Run tutorial-output checks in CI
AndrewSazonov Jun 3, 2026
6be99da
Clean saved tutorial projects before tutorial tests
AndrewSazonov Jun 3, 2026
32a4a07
Skip numeric baseline for platform-sensitive tutorials
AndrewSazonov Jun 3, 2026
ca98158
Set non-zero defaults for TOF profiles
AndrewSazonov Jun 3, 2026
fb764d1
Trim platform-sensitive skip message
AndrewSazonov Jun 3, 2026
06daaf1
Update tutorial Si structure and doc URLs
AndrewSazonov Jun 3, 2026
ff76e4e
Add pattern-display-unification implementation plan
AndrewSazonov Jun 3, 2026
42ad544
Add top margin above structure scene rectangle
AndrewSazonov Jun 3, 2026
ba6a0f8
Match single-panel pattern height and x-range to composite
AndrewSazonov Jun 3, 2026
bb57242
Always render available pattern content; drop include
AndrewSazonov Jun 3, 2026
7572462
Amend display-ux ADR for always-on pattern view
AndrewSazonov Jun 3, 2026
b12e762
Apply formatter to pattern docstring and docs
AndrewSazonov Jun 3, 2026
9d4a80d
Drop include= from tutorials for unified pattern view
AndrewSazonov Jun 3, 2026
b1a952c
Reach Phase 1 review gate
AndrewSazonov Jun 3, 2026
e964aaf
Add Raises section to pattern docstring
AndrewSazonov Jun 3, 2026
ece8f90
Set single-panel height via layout construction
AndrewSazonov Jun 3, 2026
0b1cb28
Update unit tests for unified pattern view
AndrewSazonov Jun 3, 2026
6be57ff
Remove py3Dmol, relax pillow constraint
AndrewSazonov Jun 3, 2026
0b68698
Update integration plotting tests for dropped include
AndrewSazonov Jun 3, 2026
e6f3d49
Mark Phase 2 verification complete
AndrewSazonov Jun 3, 2026
15c7d91
Record pattern unification as a dedicated ADR
AndrewSazonov Jun 3, 2026
2c8c6c7
Show pretty units in parameter repr
AndrewSazonov Jun 4, 2026
6e3a8c9
Omit space_group_Wyckoff loop from IUCr reports
AndrewSazonov Jun 4, 2026
5fb2328
Hide space_group_Wyckoff via _skip_cif_serialization hook
AndrewSazonov Jun 4, 2026
999002d
Make Wyckoff skip-serialization hook a staticmethod
AndrewSazonov Jun 4, 2026
457413a
Update Wyckoff plan for serialization-hook refactor
AndrewSazonov Jun 4, 2026
4271d2d
Apply latest templates
AndrewSazonov Jun 4, 2026
ec4865f
Assert crysfml engine is loaded in switch-calculator test
AndrewSazonov Jun 4, 2026
8ee6f1b
Reformat builtins as multiline list
AndrewSazonov Jun 4, 2026
2929b2e
Increase page max-width to 118em
AndrewSazonov Jun 4, 2026
e25e200
Point report API page at easydiffraction.report package
AndrewSazonov Jun 4, 2026
e2b12be
Track host theme in 3D-view loading box, relabel to plot
AndrewSazonov Jun 4, 2026
0f2e6ea
Size fit-series scatter plot to the pattern top panel
AndrewSazonov Jun 4, 2026
7e6ab31
Increase page and content max-widths
AndrewSazonov Jun 4, 2026
768534b
Hide space_group_Wyckoff from parameter tables
AndrewSazonov Jun 4, 2026
f24875b
Render integer descriptors in parameter table
AndrewSazonov Jun 4, 2026
bbdd0ba
Pre-bin posterior distribution histogram, not raw samples
AndrewSazonov Jun 4, 2026
1e3e573
Move notebook action buttons to top left above title
AndrewSazonov Jun 4, 2026
654ab02
Drop duplicate pair scatter hover layer, halve sample cap
AndrewSazonov Jun 4, 2026
aec8c18
Apply ruff format to distribution histogram test
AndrewSazonov Jun 4, 2026
04937a4
Include integer descriptors in remaining parameter tables
AndrewSazonov Jun 4, 2026
154c769
Add regression tests for parameter table rendering
AndrewSazonov Jun 4, 2026
2879684
Name tutorial projects to match their save directories
AndrewSazonov Jun 4, 2026
271fc1d
Render pandas tables as inline-styled HTML
AndrewSazonov Jun 4, 2026
635738e
Remove dead table theme-sync leftovers
AndrewSazonov Jun 4, 2026
0e35076
Neutralize MkDocs Material table CSS rules
AndrewSazonov Jun 4, 2026
935d833
Rename tutorial projects to match save directories
AndrewSazonov Jun 4, 2026
c2f3bf5
Temporarily mark all structures as nuclear-only
AndrewSazonov Jun 4, 2026
584a878
Match project outputs to save directories
AndrewSazonov Jun 4, 2026
c74cec2
Validate refined tutorial parameters from model and experiment CIFs
AndrewSazonov Jun 4, 2026
02dbfcd
Update tutorial projects and remove structure display
AndrewSazonov Jun 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .copier-answers.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# WARNING: Do not edit this file manually.
# Any changes will be overwritten by Copier.
_commit: v0.11.4
_commit: v0.12.0
_src_path: gh:easyscience/templates
app_docs_url: https://easyscience.github.io/diffraction-app
app_doi: 10.5281/zenodo.18163581
Expand Down
26 changes: 1 addition & 25 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,32 +63,8 @@ jobs:
files: ./coverage-unit.xml
token: ${{ secrets.CODECOV_TOKEN }}

# Job 2: Run integration tests with coverage and upload to Codecov
integration-tests-coverage:
runs-on: ubuntu-latest

steps:
- name: Check-out repository
uses: actions/checkout@v6

- name: Set up pixi
uses: ./.github/actions/setup-pixi

- name: Run integration tests with coverage
run:
pixi run integration-tests-coverage --cov-report=xml:coverage-integration.xml

- name: Upload integration tests coverage to Codecov
if: ${{ !cancelled() }}
uses: ./.github/actions/upload-codecov
with:
name: integration-tests-job
flags: integration
files: ./coverage-integration.xml
token: ${{ secrets.CODECOV_TOKEN }}

# Job 4: Build and publish dashboard (reusable workflow)
run-reusable-workflows:
needs: [docstring-coverage, unit-tests-coverage, integration-tests-coverage] # depend on the previous jobs
needs: [docstring-coverage, unit-tests-coverage] # depend on the previous jobs
uses: ./.github/workflows/dashboard.yml
secrets: inherit
4 changes: 2 additions & 2 deletions .github/workflows/tutorial-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,15 @@ jobs:

- name: Test tutorials as python scripts
shell: bash
run: pixi run script-tests
run: pixi run script-tests-checked

- name: Prepare notebooks
shell: bash
run: pixi run notebook-prepare

- name: Test tutorials as notebooks
shell: bash
run: pixi run notebook-tests
run: pixi run notebook-tests-checked

# Job 2: Build and publish dashboard (reusable workflow)
run-reusable-workflows:
Expand Down
3 changes: 3 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ src/easydiffraction/report/templates/html/vendor/
src/easydiffraction/report/templates/tex/styles/
src/easydiffraction/utils/_vendored/jupyter_dark_detect/

# Tox
.tox

# Misc
.benchmarks
.cache
Expand Down
23 changes: 10 additions & 13 deletions docs/dev/adrs/accepted/crysview-structure-visualization.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,7 @@ representation); like the HTML report it can also write a standalone
HTML file to a path. The exact return and save signature is left to the
implementation plan.

Content selection mirrors `pattern(include=...)` rather than inventing a
new vocabulary:
Content selection uses an `include=` argument:

```python
project.display.structure(struct_name='lbco')
Expand All @@ -181,13 +180,11 @@ toggles the same features after the initial view is drawn, so `include`
sets the starting state and the modebar refines it.

A companion `project.display.show_structure_options(struct_name=...)`
mirrors the existing `show_pattern_options(expt_name=...)`: it lists
each `include=` option with whether the active engine and the current
structure state support it, and the reason when they do not — for
example `moments` is unavailable until the structure model carries
lists each `include=` option with whether the active engine and the
current structure state support it, and the reason when they do not —
for example `moments` is unavailable until the structure model carries
moment fields, and the `ascii` engine reports the features only the 3D
engines draw. This gives the structure view the same per-option
discoverability the pattern view already offers.
engines draw. This gives the structure view per-option discoverability.

The view also has a spatial extent: which symmetry-equivalent atoms the
scene contains. The scene builder takes the unique (asymmetric-unit)
Expand Down Expand Up @@ -613,11 +610,11 @@ a per-call request behave predictably:
## Consequences

- `project.display` gains a spatial view (`structure()`) that
complements the 1D `pattern()` view and reuses the `include=`
vocabulary.
- `project.display` also gains `show_structure_options()`, parallel to
`show_pattern_options()`, so the supported content for a given
structure and engine is discoverable with reasons.
complements the 1D `pattern()` view with an `include=` feature
selector.
- `project.display` also gains `show_structure_options()`, so the
supported content for a given structure and engine is discoverable
with reasons.
- Keeping crystallography in the scene builder and out of renderers lets
several front-ends (Three.js now, Qt Quick 3D later) share one model.
- A switchable `rendering_structure` category
Expand Down
86 changes: 11 additions & 75 deletions docs/dev/adrs/accepted/display-ux.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,6 @@ project.display.fit.series(param, versus='diffrn.ambient_temperature')
project.display.posterior.pairs()
project.display.posterior.distribution(param)
project.display.posterior.predictive(expt_name='hrpt')

project.display.show_pattern_options(expt_name='hrpt')
```

`project.analysis.display` is removed from the primary public API. Its
Expand Down Expand Up @@ -116,77 +114,14 @@ project.display.pattern(expt_name='hrpt')
project.display.pattern(expt_name='hrpt', x_min=40, x_max=55)
```

By default, `pattern()` uses `include='auto'` and displays as much
useful information as the project state supports:

- measured data if present
- calculated data if linked structure state and calculated intensities
are available
- background if powder Bragg measured and calculated data plus defined
background points are available
- Bragg ticks if powder Bragg measured and calculated data plus
reflection rows are available
- residual if both measured and calculated data are available and the
experiment type supports a residual panel
- excluded regions if available on the experiment
- uncertainty bands where posterior predictive data exists and the chart
engine supports them

Specific subsets are selected with `include`:

```python
project.display.pattern(expt_name='hrpt', include='auto')
project.display.pattern(expt_name='hrpt', include='measured')
project.display.pattern(expt_name='hrpt', include='calculated')
project.display.pattern(
expt_name='hrpt',
include=('measured', 'calculated', 'background', 'residual', 'bragg'),
)
```

`include` was chosen over alternatives:

| Name | Reason not selected |
| ------------- | ----------------------------------------------- |
| `layers` | Sounds graphical rather than user intent. |
| `components` | Precise, but longer. |
| `content` | Too broad. |
| `view` | Better for presets than arbitrary combinations. |
| `series` | Does not fit residual rows or Bragg ticks well. |
| boolean flags | Explicit, but scales poorly. |

Add discovery for supported pattern content:

```python
project.display.show_pattern_options(expt_name='hrpt')
```

The table shows option name, description, availability for the
experiment, whether `include='auto'` includes it, and the reason an
option is unavailable.

Pattern option names:

- `auto`
- `measured`
- `calculated`
- `background`
- `residual`
- `bragg`
- `excluded`
- `uncertainty`

`uncertainty` is available where posterior predictive data exists for a
supported experiment and the active chart engine can render bands. It is
unavailable, with a clear reason, when no posterior predictive data is
present.

Explicit combinations are validated against the same project state used
by `include='auto'`. `background`, `bragg`, and `residual` require both
measured and calculated data in the same view. `excluded` requires
measured, calculated, or uncertainty content in the same view, and
excluded-region overlays currently require the experiment's default
x-axis.
`pattern()` renders every kind of data the project state supports —
measured, calculated, residual, Bragg ticks, background, excluded
regions, and posterior predictive uncertainty, each shown when
available. It takes no view-selection argument. The content rules, the
removed `include` / `show_pattern_options` design, and the shared
single- and multi-panel figure sizing are recorded in the
[Unified Pattern View](pattern-display-unification.md) ADR, which
supersedes the `include`-based pattern design once described here.

## Deterministic And Bayesian Consistency

Expand Down Expand Up @@ -230,8 +165,9 @@ users should not need to decide the output type before asking for
information. Some outputs may render as a chart or a table depending on
backend and state.

Separate `measured()` and `calculated()` methods were rejected because
they duplicate `pattern(..., include=...)`.
Separate `measured()` and `calculated()` methods are unnecessary:
`pattern()` shows every available kind of data directly, so there is no
subset for them to select.

## Consequences

Expand Down
92 changes: 92 additions & 0 deletions docs/dev/adrs/accepted/pattern-display-unification.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# ADR: Unified Pattern View

## Status

Accepted and implemented.

## Date

2026-06-04

## Context

`project.display.pattern()` was originally specified by the
[Display UX Facade](display-ux.md) ADR with an `include=` argument that
assembled a view from named layers (`measured`, `calculated`,
`background`, `residual`, `bragg`, `excluded`, `uncertainty`), plus a
`show_pattern_options()` discovery table. `include='auto'` already chose
the most informative combination from project state.

In practice this surfaced several problems:

- The single-panel path (`plot_meas`/`plot_calc` → `plot_powder`) and
the composite path (`build_powder_meas_vs_calc_figure`) computed
figure height and x-range independently, so they drifted. A
measured-only view rendered at the full three-panel height in the lazy
docs runtime — the
[Plotting & Docs Performance](plotting-docs-performance.md) skeleton
fell back to `DEFAULT_HEIGHT * PLOTLY_HEIGHT_PER_UNIT` — and gained
stray left/right autoscale padding the composite did not have.
- `'excluded'` was an opt-in overlay, but excluded regions are a
property of the experiment, not a viewing choice; `include='measured'`
and `include=('measured', 'excluded')` produced different plots of the
same data, which read as redundant.
- For a scientist audience, choosing layers is friction. The project
state already determines what is meaningful to show, which is exactly
what `include='auto'` computed.

## Decision

`pattern(expt_name, x_min=None, x_max=None, *, x=None)` always renders
every kind of data the project state supports — the former
`include='auto'` behaviour is now the only behaviour. The `include`
parameter, the `show_pattern_options()` method, and the option-status
discovery table are removed. Strict-subset views (for example
measured-only once a calculation exists) are intentionally no longer
offered; zooming (`x_min`/`x_max`) and the x-axis variable (`x`) remain.

Excluded regions are always shaded when defined on the experiment,
skipped only when a custom `x` axis variable is selected, because the
overlay cannot be mapped onto an arbitrary axis.

Single-panel and composite charts share one figure-sizing and x-range
core. `plot_powder` builds its layout with the same
`_single_main_panel_height_pixels(...)` height and tight
`_composite_x_range(...)` as the composite main row, and `_get_layout`
already applies the composite margins. A one-row chart is therefore the
top row of the multi-row chart pixel for pixel, by construction, so the
two paths cannot diverge again.

This supersedes the `include`-based pattern design in the
[Display UX Facade](display-ux.md) ADR. The remainder of that ADR — the
facade grouping, renderer categories, and naming rules — still stands.

## Consequences

- `pattern(expt_name=...)` is the whole pattern API surface; tutorials,
docs, and tests no longer pass `include=`.
- The project is in beta, so this replaces the previous API with no
compatibility shim; tutorials and tests are updated to the current
API.
- Sizing and range differences between one- and three-panel views are
prevented structurally, not patched per call.
- `structure(include=...)` and `show_structure_options()` are
unaffected: choosing which 3D features to draw remains a genuine
viewing choice (see
[Crystal Structure 3D Visualization](crysview-structure-visualization.md)).

## Alternatives Considered

Keeping `include` as the view-selection vocabulary (the original
design). `include` had been chosen over `layers`, `components`,
`content`, `view`, `series`, and boolean flags because it read as user
intent and fit residual rows and Bragg ticks. It is removed now because
the only combination users reached for in practice was the automatic
"show everything available" view; the subset combinations added API
surface and a discovery table without a matching workflow, and the
parallel single-panel rendering path was the source of the sizing and
range divergence.

Keeping `'excluded'` as an opt-in overlay, or as a redundant no-op
token, was rejected: excluded regions belong to the experiment, so
shading them is automatic whenever they are present.
30 changes: 21 additions & 9 deletions docs/dev/adrs/accepted/wyckoff-letter-detection.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

**Status:** Accepted **Date:** 2026-06-01

> **Amendment (2026-06-04):** the derived `space_group_Wyckoff` loop is
> now **code-only** — it is excluded from IUCr/report output as well as
> from project CIF. Wording below that calls the loop "report-facing" or
> says the report writer "emits" it (the §"`space_group_Wyckoff` loop"
> decision and the matching Consequences bullet) is superseded: the
> table is reachable in code via `structure.space_group_wyckoff` but is
> never serialized.

## Group

Structure model.
Expand Down Expand Up @@ -447,13 +455,17 @@ which fall out naturally below.
already emits the resolved `Wyckoff_symbol` for every atom and now
also emits `_atom_site.site_symmetry_multiplicity`.
- **`space_group_Wyckoff` loop.** The derived category is model-owned
and report-facing, but it is not persisted in project CIF. `Structure`
explicitly excludes it from project-save serialization via
`_serializable_categories()`, overriding `CategoryOwner`'s default of
serializing all owned categories. The IUCr/report writer emits the
`_space_group_Wyckoff.*` loop from the derived category because that
loop is useful report output even though it is redundant persisted
state.
and code-facing only; it is not serialized. The collection suppresses
its own output through `_skip_cif_serialization()` returning `True`,
the same collection-owned hook `atom_site_aniso` uses (conditionally);
every serialization path that consults it honours the suppression —
`category_collection_to_cif` (project CIF) and the report data context
— so the `_space_group_Wyckoff.*` loop never appears in project CIF or
HTML/TeX reports, and the hand-rolled IUCr writer does not emit it
either. The decision lives on the category, so `Structure` needs no
`_serializable_categories()` override. The table is redundant derived
state, reachable in code via `structure.space_group_wyckoff` (amended
2026-06-04).
- **Derived values on read.** Multiplicity is recomputed from the
letter, so any incoming `_atom_site.site_symmetry_multiplicity` is
ignored rather than trusted; the `space_group_Wyckoff` category is
Expand Down Expand Up @@ -677,8 +689,8 @@ may miss:
structure's space group (each entry's letter / multiplicity /
site_symmetry / coords match `SPACE_GROUPS`), rebuilds when the space
group changes, refuses all public mutation paths, is empty for an
absent group, is omitted from project CIF, and is emitted in
IUCr/report output;
absent group, and is omitted from both project CIF and IUCr/report
output (code-only, reachable via `structure.space_group_wyckoff`);
- CIF round-trip stability — a written letter reloads verbatim, an
omitted one re-derives to the same value, and an unsupported-group row
keeps `None` multiplicity whether its letter is empty, explicitly
Expand Down
1 change: 1 addition & 0 deletions docs/dev/adrs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,5 @@ folders.
| User-facing API | Accepted | String Paths and Live Descriptors | Separates persisted field selectors from references to live model parameters. | [`string-paths-and-live-descriptors.md`](accepted/string-paths-and-live-descriptors.md) |
| User-facing API | Accepted | Switchable Category API | Places multi-type category selectors on the owner and omits public selectors for fixed or single-type categories. | [`switchable-category-api.md`](accepted/switchable-category-api.md) |
| User-facing API | Accepted | Switchable Category Owned Selectors | Moves the writable `type` selector and `show_supported()` onto the category itself; collapses the CIF duplication. | [`switchable-category-owned-selectors.md`](accepted/switchable-category-owned-selectors.md) |
| User-facing API | Accepted | Unified Pattern View | `pattern()` always renders available data, drops `include`, and unifies single- and three-panel figure sizing. | [`pattern-display-unification.md`](accepted/pattern-display-unification.md) |
| User-facing API | Accepted | Value-Selector Discovery | Gives enumerated value fields a per-descriptor `show_supported()`, beside the three category-level selector families. | [`value-selector-discovery.md`](accepted/value-selector-discovery.md) |
Loading
Loading