diff --git a/.copier-answers.yml b/.copier-answers.yml index 009e6acc4..32c8c49a5 100644 --- a/.copier-answers.yml +++ b/.copier-answers.yml @@ -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 diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index d96e5b87d..5208a3333 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -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 diff --git a/.github/workflows/tutorial-tests.yml b/.github/workflows/tutorial-tests.yml index f924a31d3..4e93a6383 100644 --- a/.github/workflows/tutorial-tests.yml +++ b/.github/workflows/tutorial-tests.yml @@ -47,7 +47,7 @@ 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 @@ -55,7 +55,7 @@ jobs: - 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: diff --git a/.prettierignore b/.prettierignore index b894e10fb..32b5970dc 100644 --- a/.prettierignore +++ b/.prettierignore @@ -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 diff --git a/docs/dev/adrs/accepted/crysview-structure-visualization.md b/docs/dev/adrs/accepted/crysview-structure-visualization.md index b5fc2281a..0852726f3 100644 --- a/docs/dev/adrs/accepted/crysview-structure-visualization.md +++ b/docs/dev/adrs/accepted/crysview-structure-visualization.md @@ -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') @@ -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) @@ -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 diff --git a/docs/dev/adrs/accepted/display-ux.md b/docs/dev/adrs/accepted/display-ux.md index 40ee2c0d1..edd55f3b3 100644 --- a/docs/dev/adrs/accepted/display-ux.md +++ b/docs/dev/adrs/accepted/display-ux.md @@ -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 @@ -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 @@ -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 diff --git a/docs/dev/adrs/accepted/pattern-display-unification.md b/docs/dev/adrs/accepted/pattern-display-unification.md new file mode 100644 index 000000000..e4f057a00 --- /dev/null +++ b/docs/dev/adrs/accepted/pattern-display-unification.md @@ -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. diff --git a/docs/dev/adrs/accepted/wyckoff-letter-detection.md b/docs/dev/adrs/accepted/wyckoff-letter-detection.md index 47df620bc..c8b4340bb 100644 --- a/docs/dev/adrs/accepted/wyckoff-letter-detection.md +++ b/docs/dev/adrs/accepted/wyckoff-letter-detection.md @@ -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. @@ -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 @@ -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 diff --git a/docs/dev/adrs/index.md b/docs/dev/adrs/index.md index eea0d1af1..4156a5eb0 100644 --- a/docs/dev/adrs/index.md +++ b/docs/dev/adrs/index.md @@ -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) | diff --git a/docs/dev/plans/pattern-display-unification.md b/docs/dev/plans/pattern-display-unification.md new file mode 100644 index 000000000..35c3f2f08 --- /dev/null +++ b/docs/dev/plans/pattern-display-unification.md @@ -0,0 +1,151 @@ +# Plan: Pattern Display Unification + +Follows [`AGENTS.md`](../../../AGENTS.md). No deliberate exceptions. + +## ADR + +Recorded as the +[`pattern-display-unification`](../adrs/accepted/pattern-display-unification.md) +ADR (Accepted), which supersedes the `include`-based pattern design in +[`display-ux.md`](../adrs/accepted/display-ux.md). Relates to +[`plotting-docs-performance.md`](../adrs/accepted/plotting-docs-performance.md) +(the lazy figure skeleton that exposed the height bug) and open issue +#93 (future of `show_residual`). + +## Branch / PR + +Feature slug `pattern-display-unification`. PR targets `develop`. +**Open:** confirm whether to branch off the current +`tutorial-project-outputs` working branch or start a fresh +`pattern-display-unification` branch before committing. + +## Background + +Four user-reported issues, all rooted in the split between the +single-panel path (`plot_meas`/`plot_calc` → `plot_powder`) and the +composite path (`build_powder_meas_vs_calc_figure`): + +1. **HTML height** — the single-panel Plotly figure sets no explicit + height, so the docs' lazy skeleton falls back to + `DEFAULT_HEIGHT * PLOTLY_HEIGHT_PER_UNIT = 600px` (the full 3-panel + height) instead of the ~458px main panel. +2. **X-axis offsets** — the single-panel path sets no x-range, so Plotly + auto-pads; the composite pins `(min, max)`. +3. **`include=('measured','excluded')` redundancy** — excluded regions + are a property of the experiment, not a viewing choice. +4. **Structure top margin** — the 3D scene sits flush under its header + line. + +## Decisions + +- **Drop `include` entirely.** + `pattern(expt_name, x_min=None, x_max=None, *, x=None)` always renders + all available content (the former `include='auto'` behaviour, which is + already proven). The cost — losing strict-subset views such as + measured-only once a calc exists — is accepted; `x_min`/`x_max` and + `x` still work. Can be re-added later only on a concrete need. +- **Excluded regions always shade** when defined on the experiment, in + every view; skipped only when a custom `x` axis is selected (the + overlay can't be mapped). The `'excluded'` token is removed. +- **Common rendering base via shared primitives.** The single-panel + `plot_powder` derives its figure height from + `_single_main_panel_height_pixels(...)` and its x-range from + `_composite_x_range(...)` — the same helpers the composite uses. + Because `_get_layout` already uses the composite margins + (`r:30, t:40, b:45`), a 1-panel view becomes the composite's main row + pixel-for-pixel. No builder merge (the composite hard-requires + `y_calc`); the shared helpers are the single source of truth. +- **Keep the internal availability engine** (`_pattern_option_statuses`, + `_auto_include`, `PatternOptionStatus`); only the user-facing + selection/validation/discovery layer is removed. +- The residual-fraction default moves to `plotters/base.py` so both the + facade (`plotting.py`) and backend (`plotly.py`) can import it without + a circular dependency. + +## Open questions + +- Branch choice (above). +- Should `pattern()` keep accepting a custom `x` axis variable? Assumed + **yes** (separate from `include`). + +## Concrete files likely to change + +- `src/easydiffraction/display/plotters/base.py` — add + `DEFAULT_RESIDUAL_HEIGHT_FRACTION`. +- `src/easydiffraction/display/plotters/plotly.py` — `plot_powder` + explicit height + tight x-range. +- `src/easydiffraction/display/plotting.py` — import the moved constant. +- `src/easydiffraction/project/display.py` — rewrite `pattern()`; remove + `include`, `_normalize_include`, `_validate_requested_include`, + `show_pattern_options`; simplify `_show_point_estimate_pattern`. +- `src/easydiffraction/display/structure/templates/structure.html.j2` — + scene top margin (done). +- `docs/dev/adrs/accepted/display-ux.md` — amend Pattern Display. +- `docs/dev/adrs/accepted/crysview-structure-visualization.md`, + `docs/docs/quick-reference/index.md` — drop stale + `show_pattern_options` references. +- `docs/docs/tutorials/ed-3.py`, `ed-9.py`, `ed-11.py`, `ed-13.py` (+ + regenerated `.ipynb`) — remove `include=`. +- Phase 2: `tests/unit/easydiffraction/project/test_display.py`, + `tests/integration/fitting/test_plotting.py`. + +## Implementation steps (Phase 1) + +- [x] **P1.1 — Unify single-panel sizing/x-range.** Move + `DEFAULT_RESIDUAL_HEIGHT_FRACTION` to `base.py`; `plot_powder` + sets explicit main-panel height and tight `(min,max)` x-range. + Fixes issues #1 and #2. Commit: + `Match single-panel pattern height and x-range to composite` +- [x] **P1.2 — Drop `include`; always render available content.** + Rewrite `pattern()`; remove the selection/validation/discovery + layer; always-shade excluded. Fixes issue #3. Commit: + `Always render available pattern content; drop include` +- [x] **P1.3 — Structure scene top margin.** Fixes issue #4. Commit: + `Add top margin above structure scene rectangle` +- [x] **P1.4 — Amend ADR and docs.** Update `display-ux.md`; drop stale + `show_pattern_options` references. Commit: + `Amend display-ux ADR for always-on pattern view` +- [x] **P1.5 — Update tutorials.** Remove `include=` from tutorial + sources; `pixi run notebook-prepare`. Commit: + `Drop include= from tutorials for unified pattern view` +- [x] **P1.6 — Phase 1 review gate.** Commit: + `Reach Phase 1 review gate` + +Each completed P1 step is staged with explicit paths and committed +locally before the next step (per `AGENTS.md` Commits). Stop after Phase +1 for review before Phase 2. + +## Phase 2 — Verification + +```bash +pixi run fix +pixi run check > /tmp/easydiffraction-check.log 2>&1; check_exit_code=$?; tail -n 200 /tmp/easydiffraction-check.log; exit $check_exit_code +pixi run unit-tests > /tmp/easydiffraction-unit.log 2>&1; unit_tests_exit_code=$?; tail -n 200 /tmp/easydiffraction-unit.log; exit $unit_tests_exit_code +pixi run integration-tests +pixi run script-tests +``` + +Test updates: remove `include=`/`show_pattern_options` tests; add +coverage for always-shown excluded regions, single-panel height + tight +x-range matching the composite main row, and the nothing-to-plot error. + +## Status checklist + +- [x] Phase 1 implementation complete +- [ ] Phase 1 reviewed +- [x] Phase 2 verification complete + +## Suggested Pull Request + +**Title:** Simplify and unify the experiment pattern view + +**Description:** `project.display.pattern()` now always shows everything +the data supports — measured and calculated curves, the residual, Bragg +ticks, background, excluded regions, and uncertainty bands — so you no +longer pass `include=...` to assemble a view; just call +`pattern(expt_name=...)` and zoom with `x_min`/`x_max`. Excluded regions +are always shaded when defined. Single-panel and full three-panel charts +now share one layout, so a measured-only plot is exactly the top panel +of the full view — fixing the oversized height in the HTML docs and the +stray left/right margins. The 3D structure view also gains a little +breathing room below its title. diff --git a/docs/dev/plans/wyckoff-letter-detection.md b/docs/dev/plans/wyckoff-letter-detection.md index 2bfcb4bc5..094111680 100644 --- a/docs/dev/plans/wyckoff-letter-detection.md +++ b/docs/dev/plans/wyckoff-letter-detection.md @@ -11,6 +11,18 @@ ADR. No deliberate exception to `AGENTS.md` is taken. - [x] Phase 1 review gate - [x] Phase 2 — Verification (tests + `pixi` checks) +> **Post-implementation amendment (2026-06-04).** Two follow-up changes +> landed after this plan completed: (1) the `_space_group_Wyckoff.*` +> loop is no longer emitted in IUCr/HTML/TeX report output — the derived +> table is code-only; and (2) its exclusion from every serialization +> path now comes from the collection's own `_skip_cif_serialization()` +> hook (returning `True`), not from a +> `Structure._serializable_categories()` override, which was removed. +> References to `_serializable_categories()` and to "report-facing" / +> "emits the loop" below describe the original implementation and are +> superseded by this note and by the +> [ADR amendment](../adrs/accepted/wyckoff-letter-detection.md). + ## ADR This plan implements the @@ -105,13 +117,15 @@ rotation/translation parser. `_replace_from_space_group()` path rebuilds the derived collection through internal adoption. 10. **`space_group_Wyckoff` serialization policy.** The category is - model-owned and report-facing, but not persisted in project CIF. - `Structure._serializable_categories()` excludes it from - `structure.as_cif` / project saves, the IUCr/report writer emits the - `_space_group_Wyckoff.*` loop from the derived category, and - incoming `_space_group_Wyckoff.*` values are ignored/overwritten on - project load because the category is re-derived from the space - group. + model-owned and code-only: it is excluded from every serialization + path. The collection's own `_skip_cif_serialization()` hook (returns + `True`) suppresses its output in `structure.as_cif` / project saves + and in the report data context alike, and the IUCr writer does not + emit the `_space_group_Wyckoff.*` loop; incoming + `_space_group_Wyckoff.*` values are ignored/overwritten on project + load because the category is re-derived from the space group. + (Superseded the original `_serializable_categories()` + + report-emission design; see the Post-implementation amendment.) 11. **Allowed letters come from the current space group.** `_wyckoff_letter_allowed_values` returns `['', *tabulated_letters]` for supported groups and `[]` for absent groups. @@ -196,8 +210,9 @@ Phase 1 (implementation): - `src/easydiffraction/datablocks/structure/item/base.py` — add the `space_group_wyckoff` sibling category, expose it read-only, rebuild it from the current `space_group` before ordinary category update - hooks, and exclude it from project CIF through - `_serializable_categories()`. + hooks. (Project-CIF exclusion originally lived here via + `_serializable_categories()`; it now lives on the collection through + `_skip_cif_serialization()` — see the Post-implementation amendment.) - `src/easydiffraction/analysis/calculators/cryspy.py` — `_update_atom_multiplicity` reads `atom_site.multiplicity.value`. - `src/easydiffraction/io/cif/serialize.py` — only if atom-site CIF read @@ -288,7 +303,9 @@ The ADR commit + design-phase review/reply cleanup are handled by a read-only sibling category on `Structure`, rebuild it when structure categories update so it tracks the current space group, keep it empty for absent groups, and exclude it from project CIF - by overriding `_serializable_categories()`. Rebuild it from + by overriding `_serializable_categories()` (later replaced by the + collection's `_skip_cif_serialization()` hook; see the + Post-implementation amendment). Rebuild it from `Structure._update_categories()` before ordinary category update hooks, with no special `_update_priority`; atom-site detection reads `SPACE_GROUPS` through the crystallography helpers rather @@ -391,9 +408,11 @@ The ADR commit + design-phase review/reply cleanup are handled by is already automatic: P1.4 added the `multiplicity` descriptor with that CIF handler, and it is part of `AtomSite.parameters`, so the atom-site loop emits it (value `?` for untabulated - sites). The `_space_group_Wyckoff` loop exclusion is already - provided by P1.3's `Structure._serializable_categories` - override. No new write-side code was needed in P1.8. + sites). The `_space_group_Wyckoff` loop exclusion was originally + provided by P1.3's `Structure._serializable_categories` override + (later moved to the collection's `_skip_cif_serialization()` + hook; see the Post-implementation amendment). No new write-side + code was needed in P1.8. - **Read ignore of incoming `_space_group_Wyckoff.*`** is done by a no-op `SpaceGroupWyckoffCollection.from_cif` override (the structure read loop iterates *all* categories, including the diff --git a/docs/docs/api-reference/report.md b/docs/docs/api-reference/report.md index c33824c37..7a3ae20f9 100644 --- a/docs/docs/api-reference/report.md +++ b/docs/docs/api-reference/report.md @@ -1 +1 @@ -::: easydiffraction.project.categories.report.default.Report +::: easydiffraction.report diff --git a/docs/docs/assets/javascripts/extra.js b/docs/docs/assets/javascripts/extra.js index 6cf2caa6a..00894bb0f 100644 --- a/docs/docs/assets/javascripts/extra.js +++ b/docs/docs/assets/javascripts/extra.js @@ -194,14 +194,6 @@ }) } - function syncPandasTableTheme() { - const colors = themeColors() - document.querySelectorAll('.ed-themed-table').forEach((table) => { - // TABLE_AXIS_FRAME_CSS_VAR - table.style.setProperty('--ed-axis-frame-color', colors.axisFrame) - }) - } - function syncCrysviewTheme() { const next = themeName() document.querySelectorAll('.crysview').forEach((viewer) => { @@ -215,7 +207,6 @@ function syncThemeAwareOutputs() { syncPlotlyTheme() - syncPandasTableTheme() syncCrysviewTheme() } diff --git a/docs/docs/assets/stylesheets/extra.css b/docs/docs/assets/stylesheets/extra.css index 59e5b0929..ae3c9bccd 100644 --- a/docs/docs/assets/stylesheets/extra.css +++ b/docs/docs/assets/stylesheets/extra.css @@ -202,12 +202,33 @@ label.md-nav__title[for="__drawer"] { /* Change the overall width of the page */ .md-grid { - max-width: 1280px; + max-width: 125em; } -/* Needed for mkdocs-jupyter to show download and other buttons on top of the notebook */ -.md-content__button { - position: relative !important; +/* Keep prose line length stable when sidebars are hidden at narrower widths */ +.md-main .md-content > .md-content__inner { + width: min(100%, 45em); + margin-left: auto !important; + margin-right: auto !important; +} + +/* Notebook action buttons (Open in Colab, Download). The page title is the + notebook's own H1 rendered just below, so lay the buttons out as a + left-aligned row above it instead of the theme's default right float, + which overlapped long titles. */ +.md-content__nb-actions { + display: flex; + gap: 0.4rem; + /* Empty line of separation between the button row and the title */ + margin-bottom: 1.2em; + /* Keep the row above the notebook, which is pulled up via margin-top */ + position: relative; + z-index: 1; +} + +.md-content__nb-actions .md-content__button { + float: none; + margin: 0; } /* Background color of the search input field */ @@ -241,7 +262,9 @@ body[data-md-color-scheme="slate"] .jupyter-wrapper { .jp-Notebook { padding: 0 !important; - margin-top: -3em !important; + /* Pull the notebook up to absorb the jupyter wrapper's intrinsic top + whitespace while leaving a small gap below the action-button row. */ + margin-top: -0.5em !important; /* Ensure notebook content stretches across the page */ width: 100% !important; diff --git a/docs/docs/quick-reference/index.md b/docs/docs/quick-reference/index.md index 6fee6b1f5..b246586d1 100644 --- a/docs/docs/quick-reference/index.md +++ b/docs/docs/quick-reference/index.md @@ -136,7 +136,7 @@ experiment.linked_phases.create(id='lbco', scale=10.0) ## Inspect the Project -Show names, CIF text, and plotting options: +Show names and CIF text: ```python project.structures.show_names() @@ -144,8 +144,6 @@ project.experiments.show_names() structure.show_as_cif() experiment.show_as_cif() - -project.display.show_pattern_options(expt_name='hrpt') ``` Open the main display views: diff --git a/docs/docs/tutorials/ed-1.ipynb b/docs/docs/tutorials/ed-1.ipynb index 39de4d787..0ca03392d 100644 --- a/docs/docs/tutorials/ed-1.ipynb +++ b/docs/docs/tutorials/ed-1.ipynb @@ -75,8 +75,8 @@ "metadata": {}, "outputs": [], "source": [ - "# Create minimal project without name and description\n", - "project = ed.Project()" + "# Create a minimal project with a short name\n", + "project = ed.Project(name='lbco_hrpt')" ] }, { @@ -288,6 +288,24 @@ "# Plot measured vs. calculated diffraction patterns\n", "project.display.pattern(expt_name='hrpt')" ] + }, + { + "cell_type": "markdown", + "id": "25", + "metadata": {}, + "source": [ + "## 💾 Save Project" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "26", + "metadata": {}, + "outputs": [], + "source": [ + "project.save_as(dir_path='projects/ed_1_lbco_hrpt')" + ] } ], "metadata": { diff --git a/docs/docs/tutorials/ed-1.py b/docs/docs/tutorials/ed-1.py index 07e1830b3..59a574582 100644 --- a/docs/docs/tutorials/ed-1.py +++ b/docs/docs/tutorials/ed-1.py @@ -26,8 +26,8 @@ # ## 📦 Define Project # %% -# Create minimal project without name and description -project = ed.Project() +# Create a minimal project with a short name +project = ed.Project(name='lbco_hrpt') # %% [markdown] # ## 🧩 Define Structure @@ -115,3 +115,9 @@ # %% # Plot measured vs. calculated diffraction patterns project.display.pattern(expt_name='hrpt') + +# %% [markdown] +# ## 💾 Save Project + +# %% +project.save_as(dir_path='projects/ed_1_lbco_hrpt') diff --git a/docs/docs/tutorials/ed-10.ipynb b/docs/docs/tutorials/ed-10.ipynb index 3815f24ea..0b309da49 100644 --- a/docs/docs/tutorials/ed-10.ipynb +++ b/docs/docs/tutorials/ed-10.ipynb @@ -75,7 +75,7 @@ "metadata": {}, "outputs": [], "source": [ - "project = ed.Project()" + "project = ed.Project(name='ni_pdf')" ] }, { @@ -261,6 +261,24 @@ "source": [ "project.display.pattern(expt_name='pdf')" ] + }, + { + "cell_type": "markdown", + "id": "24", + "metadata": {}, + "source": [ + "## 💾 Save Project" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "25", + "metadata": {}, + "outputs": [], + "source": [ + "project.save_as(dir_path='projects/ed_10_ni_pdf')" + ] } ], "metadata": { diff --git a/docs/docs/tutorials/ed-10.py b/docs/docs/tutorials/ed-10.py index 751831508..46f54c02e 100644 --- a/docs/docs/tutorials/ed-10.py +++ b/docs/docs/tutorials/ed-10.py @@ -21,7 +21,7 @@ # ### Create Project # %% -project = ed.Project() +project = ed.Project(name='ni_pdf') # %% [markdown] # ### Add Structure @@ -101,3 +101,9 @@ # %% project.display.pattern(expt_name='pdf') + +# %% [markdown] +# ## 💾 Save Project + +# %% +project.save_as(dir_path='projects/ed_10_ni_pdf') diff --git a/docs/docs/tutorials/ed-11.ipynb b/docs/docs/tutorials/ed-11.ipynb index b5d03cf56..65a861672 100644 --- a/docs/docs/tutorials/ed-11.ipynb +++ b/docs/docs/tutorials/ed-11.ipynb @@ -72,7 +72,7 @@ "metadata": {}, "outputs": [], "source": [ - "project = ed.Project()" + "project = ed.Project(name='si_nomad_pdf')" ] }, { @@ -289,7 +289,25 @@ "metadata": {}, "outputs": [], "source": [ - "project.display.pattern(expt_name='nomad', include=('measured', 'calculated'))" + "project.display.pattern(expt_name='nomad')" + ] + }, + { + "cell_type": "markdown", + "id": "27", + "metadata": {}, + "source": [ + "## 💾 Save Project" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "28", + "metadata": {}, + "outputs": [], + "source": [ + "project.save_as(dir_path='projects/ed_11_si_nomad_pdf')" ] } ], diff --git a/docs/docs/tutorials/ed-11.py b/docs/docs/tutorials/ed-11.py index e08e81d63..a11f1b233 100644 --- a/docs/docs/tutorials/ed-11.py +++ b/docs/docs/tutorials/ed-11.py @@ -18,7 +18,7 @@ # ### Create Project # %% -project = ed.Project() +project = ed.Project(name='si_nomad_pdf') # %% [markdown] # ### Set Plotting Engine @@ -111,4 +111,10 @@ # ### Display Pattern # %% -project.display.pattern(expt_name='nomad', include=('measured', 'calculated')) +project.display.pattern(expt_name='nomad') + +# %% [markdown] +# ## 💾 Save Project + +# %% +project.save_as(dir_path='projects/ed_11_si_nomad_pdf') diff --git a/docs/docs/tutorials/ed-12.ipynb b/docs/docs/tutorials/ed-12.ipynb index ed2c0a0b5..2499a1981 100644 --- a/docs/docs/tutorials/ed-12.ipynb +++ b/docs/docs/tutorials/ed-12.ipynb @@ -75,7 +75,7 @@ "metadata": {}, "outputs": [], "source": [ - "project = ed.Project()" + "project = ed.Project(name='nacl_xray_pdf')" ] }, { @@ -331,6 +331,24 @@ "source": [ "project.display.pattern(expt_name='xray_pdf')" ] + }, + { + "cell_type": "markdown", + "id": "30", + "metadata": {}, + "source": [ + "## 💾 Save Project" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "31", + "metadata": {}, + "outputs": [], + "source": [ + "project.save_as(dir_path='projects/ed_12_nacl_xray_pdf')" + ] } ], "metadata": { diff --git a/docs/docs/tutorials/ed-12.py b/docs/docs/tutorials/ed-12.py index 3add79927..8b8f31617 100644 --- a/docs/docs/tutorials/ed-12.py +++ b/docs/docs/tutorials/ed-12.py @@ -21,7 +21,7 @@ # ### Create Project # %% -project = ed.Project() +project = ed.Project(name='nacl_xray_pdf') # %% [markdown] # ### Set Plotting Engine @@ -131,3 +131,9 @@ # %% project.display.pattern(expt_name='xray_pdf') + +# %% [markdown] +# ## 💾 Save Project + +# %% +project.save_as(dir_path='projects/ed_12_nacl_xray_pdf') diff --git a/docs/docs/tutorials/ed-13.ipynb b/docs/docs/tutorials/ed-13.ipynb index 9a84c90cd..4a13675e3 100644 --- a/docs/docs/tutorials/ed-13.ipynb +++ b/docs/docs/tutorials/ed-13.ipynb @@ -59,7 +59,7 @@ "metadata": {}, "source": [ "📖 See\n", - "[documentation](https://docs.easydiffraction.org/lib/user-guide/first-steps/#importing-easydiffraction)\n", + "[documentation](https://docs.easydiffraction.org/lib/latest/user-guide/first-steps/#importing-easydiffraction)\n", "for more details about importing the EasyDiffraction library and its\n", "components." ] @@ -107,7 +107,7 @@ "metadata": {}, "source": [ "📖 See\n", - "[documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/project/)\n", + "[documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/project/)\n", "for more details about creating a project and its purpose in the\n", "analysis workflow." ] @@ -163,7 +163,7 @@ "metadata": {}, "source": [ "📖 See\n", - "[documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/experiment/)\n", + "[documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/experiment/)\n", "for more details about experiments and their purpose in the analysis\n", "workflow." ] @@ -221,7 +221,7 @@ "metadata": {}, "source": [ "📖 See\n", - "[documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/experiment/#defining-an-experiment-manually)\n", + "[documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/experiment/#defining-an-experiment-manually)\n", "for more details about different types of experiments." ] }, @@ -263,11 +263,11 @@ "metadata": {}, "source": [ "📖 See\n", - "[documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/experiment/#measured-data-category)\n", + "[documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/experiment/#measured-data-category)\n", "for more details about the measured data and its format.\n", "\n", "To visualize the measured data, we can use the `pattern` method of\n", - "the project's `display` facade with `include='measured'`." + "the project's `display` facade." ] }, { @@ -277,7 +277,7 @@ "metadata": {}, "outputs": [], "source": [ - "project_1.display.pattern(expt_name='sim_si', include='measured')" + "project_1.display.pattern(expt_name='sim_si')" ] }, { @@ -309,7 +309,7 @@ "metadata": {}, "source": [ "📖 See\n", - "[documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/experiment/#excluded-regions-category)\n", + "[documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/experiment/#excluded-regions-category)\n", "for more details about excluding regions from the measured data." ] }, @@ -341,7 +341,7 @@ "metadata": {}, "outputs": [], "source": [ - "project_1.display.pattern(expt_name='sim_si', include=('measured', 'excluded'))" + "project_1.display.pattern(expt_name='sim_si')" ] }, { @@ -373,7 +373,7 @@ "metadata": {}, "source": [ "📖 See\n", - "[documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/experiment/#instrument-category)\n", + "[documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/experiment/#instrument-category)\n", "for more details about the instrument parameters." ] }, @@ -460,7 +460,7 @@ "metadata": {}, "source": [ "📖 See\n", - "[documentation](https://docs.easydiffraction.org/lib/user-guide/parameters/)\n", + "[documentation](https://docs.easydiffraction.org/lib/latest/user-guide/parameters/)\n", "for more details about parameters in EasyDiffraction and their\n", "attributes." ] @@ -527,7 +527,7 @@ "metadata": {}, "source": [ "📖 See\n", - "[documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/experiment/#peak-category)\n", + "[documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/experiment/#peak-category)\n", "for more details about the peak profile types." ] }, @@ -598,7 +598,7 @@ "metadata": {}, "source": [ "📖 See\n", - "[documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/experiment/#background-category)\n", + "[documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/experiment/#background-category)\n", "for more details about the background and its types." ] }, @@ -655,15 +655,16 @@ "which is the length of the unit cell edge. The Si crystal structure\n", "has a single atom in the unit cell, which is located at the origin (0,\n", "0, 0) of the unit cell. The symmetry of this site is defined by the\n", - "Wyckoff letter 'a'. The atomic displacement parameter defines the\n", - "thermal vibrations of the atoms in the unit cell and is presented as\n", - "an isotropic parameter (B_iso).\n", + "Wyckoff letter 'a', which is assigned automatically based on the space\n", + "group and the atomic coordinates. The atomic displacement parameter\n", + "defines the thermal vibrations of the atoms in the unit cell and is\n", + "presented as an isotropic parameter (B_iso).\n", "\n", "Sometimes, the initial crystal structure parameters can be obtained\n", "from one of the crystallographic databases, like for example the\n", "Crystallography Open Database (COD). In this case, we use the COD\n", "entry for silicon as a reference for the initial crystal structure\n", - "model: https://www.crystallography.net/cod/4507226.html\n", + "model: https://www.crystallography.net/cod/9008565.html\n", "\n", "Usually, the crystal structure parameters are provided in a CIF file\n", "format, which is a standard format for crystallographic data. An\n", @@ -678,7 +679,7 @@ "metadata": {}, "source": [ "📖 See\n", - "[documentation](https://docs.easydiffraction.org/lib/user-guide/data-format/)\n", + "[documentation](https://docs.easydiffraction.org/lib/latest/user-guide/data-format/)\n", "for more details about the CIF format and its use in EasyDiffraction." ] }, @@ -691,7 +692,7 @@ "data_si\n", "\n", "_space_group.name_H-M_alt \"F d -3 m\"\n", - "_space_group.IT_coordinate_system_code 2\n", + "_space_group.IT_coordinate_system_code 1\n", "\n", "_cell.length_a 5.43\n", "_cell.length_b 5.43\n", @@ -706,11 +707,10 @@ "_atom_site.fract_x\n", "_atom_site.fract_y\n", "_atom_site.fract_z\n", - "_atom_site.wyckoff_letter\n", "_atom_site.occupancy\n", "_atom_site.ADP_type\n", "_atom_site.B_iso_or_equiv\n", - "Si Si 0.125 0.125 0.125 a 1.0 Biso 0.89\n", + "Si Si 0 0 0 1.0 Biso 0.89\n", "```" ] }, @@ -730,7 +730,7 @@ "metadata": {}, "source": [ "📖 See\n", - "[documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/structure/)\n", + "[documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/structure/)\n", "for more details about structures and their purpose in the data\n", "analysis workflow." ] @@ -767,7 +767,7 @@ "metadata": {}, "source": [ "📖 See\n", - "[documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/structure/#space-group-category)\n", + "[documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/structure/#space-group-category)\n", "for more details about the space group." ] }, @@ -779,7 +779,7 @@ "outputs": [], "source": [ "project_1.structures['si'].space_group.name_h_m = 'F d -3 m'\n", - "project_1.structures['si'].space_group.it_coordinate_system_code = '2'" + "project_1.structures['si'].space_group.it_coordinate_system_code = '1'" ] }, { @@ -796,7 +796,7 @@ "metadata": {}, "source": [ "📖 See\n", - "[documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/structure/#cell-category)\n", + "[documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/structure/#cell-category)\n", "for more details about the unit cell parameters." ] }, @@ -824,7 +824,7 @@ "metadata": {}, "source": [ "📖 See\n", - "[documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/structure/#atom-sites-category)\n", + "[documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/structure/#atom-sites-category)\n", "for more details about the atom sites category." ] }, @@ -838,9 +838,10 @@ "project_1.structures['si'].atom_sites.create(\n", " label='Si',\n", " type_symbol='Si',\n", - " fract_x=0.125,\n", - " fract_y=0.125,\n", - " fract_z=0.125,\n", + " fract_x=0.0,\n", + " fract_y=0.0,\n", + " fract_z=0.0,\n", + " adp_type='Biso',\n", " adp_iso=0.89,\n", ")" ] @@ -885,7 +886,7 @@ "metadata": {}, "source": [ "📖 See\n", - "[documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/experiment/#linked-phases-category)\n", + "[documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/experiment/#linked-phases-category)\n", "for more details about linking a structure to an experiment." ] }, @@ -944,7 +945,7 @@ "metadata": {}, "source": [ "📖 See\n", - "[documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/analysis/#minimization-optimization)\n", + "[documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/analysis/#minimization-optimization)\n", "for more details about the fitting process in EasyDiffraction." ] }, @@ -1067,7 +1068,7 @@ "metadata": {}, "source": [ "📖 See\n", - "[documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/analysis/#perform-fit)\n", + "[documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/analysis/#perform-fit)\n", "for more details about the fitting process." ] }, @@ -1199,7 +1200,7 @@ "metadata": {}, "outputs": [], "source": [ - "project_1.save_as(dir_path='data/powder_diffraction_Si')" + "project_1.save_as(dir_path='projects/ed_13_reference')" ] }, { @@ -1368,12 +1369,12 @@ "metadata": {}, "outputs": [], "source": [ - "project_2.display.pattern(expt_name='sim_lbco', include='measured')\n", + "project_2.display.pattern(expt_name='sim_lbco')\n", "\n", "project_2.experiments['sim_lbco'].excluded_regions.create(id='1', start=0, end=55000)\n", "project_2.experiments['sim_lbco'].excluded_regions.create(id='2', start=105500, end=200000)\n", "\n", - "project_2.display.pattern(expt_name='sim_lbco', include=('measured', 'excluded'))" + "project_2.display.pattern(expt_name='sim_lbco')" ] }, { @@ -1578,14 +1579,13 @@ "_atom_site.fract_x\n", "_atom_site.fract_y\n", "_atom_site.fract_z\n", - "_atom_site.wyckoff_letter\n", "_atom_site.occupancy\n", "_atom_site.ADP_type\n", "_atom_site.B_iso_or_equiv\n", - "La La 0.0 0.0 0.0 a 0.5 Biso 0.95\n", - "Ba Ba 0.0 0.0 0.0 a 0.5 Biso 0.95\n", - "Co Co 0.5 0.5 0.5 b 1.0 Biso 0.80\n", - "O O 0.0 0.5 0.5 c 1.0 Biso 1.66\n", + "La La 0.0 0.0 0.0 0.5 Biso 0.95\n", + "Ba Ba 0.0 0.0 0.0 0.5 Biso 0.95\n", + "Co Co 0.5 0.5 0.5 1.0 Biso 0.80\n", + "O O 0.0 0.5 0.5 1.0 Biso 1.66\n", "```" ] }, @@ -1804,8 +1804,9 @@ " fract_x=0,\n", " fract_y=0,\n", " fract_z=0,\n", - " adp_iso=0.95,\n", " occupancy=0.5,\n", + " adp_type='Biso',\n", + " adp_iso=0.95,\n", ")\n", "project_2.structures['lbco'].atom_sites.create(\n", " label='Ba',\n", @@ -1813,8 +1814,9 @@ " fract_x=0,\n", " fract_y=0,\n", " fract_z=0,\n", - " adp_iso=0.95,\n", " occupancy=0.5,\n", + " adp_type='Biso',\n", + " adp_iso=0.95,\n", ")\n", "project_2.structures['lbco'].atom_sites.create(\n", " label='Co',\n", @@ -1822,6 +1824,7 @@ " fract_x=0.5,\n", " fract_y=0.5,\n", " fract_z=0.5,\n", + " adp_type='Biso',\n", " adp_iso=0.80,\n", ")\n", "project_2.structures['lbco'].atom_sites.create(\n", @@ -1830,6 +1833,7 @@ " fract_x=0,\n", " fract_y=0.5,\n", " fract_z=0.5,\n", + " adp_type='Biso',\n", " adp_iso=1.66,\n", ")" ] @@ -2631,7 +2635,7 @@ "metadata": {}, "outputs": [], "source": [ - "project_2.save_as(dir_path='data/powder_diffraction_LBCO_Si')" + "project_2.save_as(dir_path='projects/ed_13_main')" ] }, { diff --git a/docs/docs/tutorials/ed-13.py b/docs/docs/tutorials/ed-13.py index 82970780f..d30af7865 100644 --- a/docs/docs/tutorials/ed-13.py +++ b/docs/docs/tutorials/ed-13.py @@ -29,7 +29,7 @@ # %% [markdown] tags=["doc-link"] # 📖 See -# [documentation](https://docs.easydiffraction.org/lib/user-guide/first-steps/#importing-easydiffraction) +# [documentation](https://docs.easydiffraction.org/lib/latest/user-guide/first-steps/#importing-easydiffraction) # for more details about importing the EasyDiffraction library and its # components. @@ -60,7 +60,7 @@ # %% [markdown] tags=["doc-link"] # 📖 See -# [documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/project/) +# [documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/project/) # for more details about creating a project and its purpose in the # analysis workflow. @@ -87,7 +87,7 @@ # %% [markdown] tags=["doc-link"] # 📖 See -# [documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/experiment/) +# [documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/experiment/) # for more details about experiments and their purpose in the analysis # workflow. @@ -116,7 +116,7 @@ # %% [markdown] tags=["doc-link"] # 📖 See -# [documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/experiment/#defining-an-experiment-manually) +# [documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/experiment/#defining-an-experiment-manually) # for more details about different types of experiments. # %% @@ -141,14 +141,14 @@ # %% [markdown] tags=["doc-link"] # 📖 See -# [documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/experiment/#measured-data-category) +# [documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/experiment/#measured-data-category) # for more details about the measured data and its format. # # To visualize the measured data, we can use the `pattern` method of -# the project's `display` facade with `include='measured'`. +# the project's `display` facade. # %% -project_1.display.pattern(expt_name='sim_si', include='measured') +project_1.display.pattern(expt_name='sim_si') # %% [markdown] # If you zoom in on the highest TOF peak (around 120,000 μs), you will @@ -170,7 +170,7 @@ # %% [markdown] tags=["doc-link"] # 📖 See -# [documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/experiment/#excluded-regions-category) +# [documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/experiment/#excluded-regions-category) # for more details about excluding regions from the measured data. # %% @@ -183,7 +183,7 @@ # the plot and is not used in the fitting process. # %% -project_1.display.pattern(expt_name='sim_si', include=('measured', 'excluded')) +project_1.display.pattern(expt_name='sim_si') # %% [markdown] # #### Set Instrument @@ -205,7 +205,7 @@ # %% [markdown] tags=["doc-link"] # 📖 See -# [documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/experiment/#instrument-category) +# [documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/experiment/#instrument-category) # for more details about the instrument parameters. # %% @@ -251,7 +251,7 @@ # %% [markdown] tags=["doc-link"] # 📖 See -# [documentation](https://docs.easydiffraction.org/lib/user-guide/parameters/) +# [documentation](https://docs.easydiffraction.org/lib/latest/user-guide/parameters/) # for more details about parameters in EasyDiffraction and their # attributes. @@ -308,7 +308,7 @@ # %% [markdown] tags=["doc-link"] # 📖 See -# [documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/experiment/#peak-category) +# [documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/experiment/#peak-category) # for more details about the peak profile types. # %% @@ -355,7 +355,7 @@ # %% [markdown] tags=["doc-link"] # 📖 See -# [documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/experiment/#background-category) +# [documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/experiment/#background-category) # for more details about the background and its types. # %% @@ -393,15 +393,16 @@ # which is the length of the unit cell edge. The Si crystal structure # has a single atom in the unit cell, which is located at the origin (0, # 0, 0) of the unit cell. The symmetry of this site is defined by the -# Wyckoff letter 'a'. The atomic displacement parameter defines the -# thermal vibrations of the atoms in the unit cell and is presented as -# an isotropic parameter (B_iso). +# Wyckoff letter 'a', which is assigned automatically based on the space +# group and the atomic coordinates. The atomic displacement parameter +# defines the thermal vibrations of the atoms in the unit cell and is +# presented as an isotropic parameter (B_iso). # # Sometimes, the initial crystal structure parameters can be obtained # from one of the crystallographic databases, like for example the # Crystallography Open Database (COD). In this case, we use the COD # entry for silicon as a reference for the initial crystal structure -# model: https://www.crystallography.net/cod/4507226.html +# model: https://www.crystallography.net/cod/9008565.html # # Usually, the crystal structure parameters are provided in a CIF file # format, which is a standard format for crystallographic data. An @@ -411,7 +412,7 @@ # %% [markdown] tags=["doc-link"] # 📖 See -# [documentation](https://docs.easydiffraction.org/lib/user-guide/data-format/) +# [documentation](https://docs.easydiffraction.org/lib/latest/user-guide/data-format/) # for more details about the CIF format and its use in EasyDiffraction. # %% [markdown] @@ -419,7 +420,7 @@ # data_si # # _space_group.name_H-M_alt "F d -3 m" -# _space_group.IT_coordinate_system_code 2 +# _space_group.IT_coordinate_system_code 1 # # _cell.length_a 5.43 # _cell.length_b 5.43 @@ -434,11 +435,10 @@ # _atom_site.fract_x # _atom_site.fract_y # _atom_site.fract_z -# _atom_site.wyckoff_letter # _atom_site.occupancy # _atom_site.ADP_type # _atom_site.B_iso_or_equiv -# Si Si 0.125 0.125 0.125 a 1.0 Biso 0.89 +# Si Si 0 0 0 1.0 Biso 0.89 # ``` # %% [markdown] @@ -448,7 +448,7 @@ # %% [markdown] tags=["doc-link"] # 📖 See -# [documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/structure/) +# [documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/structure/) # for more details about structures and their purpose in the data # analysis workflow. @@ -463,19 +463,19 @@ # %% [markdown] tags=["doc-link"] # 📖 See -# [documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/structure/#space-group-category) +# [documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/structure/#space-group-category) # for more details about the space group. # %% project_1.structures['si'].space_group.name_h_m = 'F d -3 m' -project_1.structures['si'].space_group.it_coordinate_system_code = '2' +project_1.structures['si'].space_group.it_coordinate_system_code = '1' # %% [markdown] # #### Set Unit Cell # %% [markdown] tags=["doc-link"] # 📖 See -# [documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/structure/#cell-category) +# [documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/structure/#cell-category) # for more details about the unit cell parameters. # %% @@ -486,16 +486,17 @@ # %% [markdown] tags=["doc-link"] # 📖 See -# [documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/structure/#atom-sites-category) +# [documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/structure/#atom-sites-category) # for more details about the atom sites category. # %% project_1.structures['si'].atom_sites.create( label='Si', type_symbol='Si', - fract_x=0.125, - fract_y=0.125, - fract_z=0.125, + fract_x=0.0, + fract_y=0.0, + fract_z=0.0, + adp_type='Biso', adp_iso=0.89, ) @@ -518,7 +519,7 @@ # %% [markdown] tags=["doc-link"] # 📖 See -# [documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/experiment/#linked-phases-category) +# [documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/experiment/#linked-phases-category) # for more details about linking a structure to an experiment. # %% @@ -553,7 +554,7 @@ # %% [markdown] tags=["doc-link"] # 📖 See -# [documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/analysis/#minimization-optimization) +# [documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/analysis/#minimization-optimization) # for more details about the fitting process in EasyDiffraction. # %% [markdown] @@ -625,7 +626,7 @@ # %% [markdown] tags=["doc-link"] # 📖 See -# [documentation](https://docs.easydiffraction.org/lib/user-guide/analysis-workflow/analysis/#perform-fit) +# [documentation](https://docs.easydiffraction.org/lib/latest/user-guide/analysis-workflow/analysis/#perform-fit) # for more details about the fitting process. # %% @@ -709,7 +710,7 @@ # directory specified by the `dir_path` attribute of the project object. # %% -project_1.save_as(dir_path='data/powder_diffraction_Si') +project_1.save_as(dir_path='projects/ed_13_reference') # %% [markdown] # ## 💪 Exercise: Complex Fit – LBCO @@ -797,12 +798,12 @@ # **Solution:** # %% tags=["solution", "hide-input"] -project_2.display.pattern(expt_name='sim_lbco', include='measured') +project_2.display.pattern(expt_name='sim_lbco') project_2.experiments['sim_lbco'].excluded_regions.create(id='1', start=0, end=55000) project_2.experiments['sim_lbco'].excluded_regions.create(id='2', start=105500, end=200000) -project_2.display.pattern(expt_name='sim_lbco', include=('measured', 'excluded')) +project_2.display.pattern(expt_name='sim_lbco') # %% [markdown] # #### Exercise 2.2: Set Instrument @@ -916,14 +917,13 @@ # _atom_site.fract_x # _atom_site.fract_y # _atom_site.fract_z -# _atom_site.wyckoff_letter # _atom_site.occupancy # _atom_site.ADP_type # _atom_site.B_iso_or_equiv -# La La 0.0 0.0 0.0 a 0.5 Biso 0.95 -# Ba Ba 0.0 0.0 0.0 a 0.5 Biso 0.95 -# Co Co 0.5 0.5 0.5 b 1.0 Biso 0.80 -# O O 0.0 0.5 0.5 c 1.0 Biso 1.66 +# La La 0.0 0.0 0.0 0.5 Biso 0.95 +# Ba Ba 0.0 0.0 0.0 0.5 Biso 0.95 +# Co Co 0.5 0.5 0.5 1.0 Biso 0.80 +# O O 0.0 0.5 0.5 1.0 Biso 1.66 # ``` # %% [markdown] @@ -1029,8 +1029,9 @@ fract_x=0, fract_y=0, fract_z=0, - adp_iso=0.95, occupancy=0.5, + adp_type='Biso', + adp_iso=0.95, ) project_2.structures['lbco'].atom_sites.create( label='Ba', @@ -1038,8 +1039,9 @@ fract_x=0, fract_y=0, fract_z=0, - adp_iso=0.95, occupancy=0.5, + adp_type='Biso', + adp_iso=0.95, ) project_2.structures['lbco'].atom_sites.create( label='Co', @@ -1047,6 +1049,7 @@ fract_x=0.5, fract_y=0.5, fract_z=0.5, + adp_type='Biso', adp_iso=0.80, ) project_2.structures['lbco'].atom_sites.create( @@ -1055,6 +1058,7 @@ fract_x=0, fract_y=0.5, fract_z=0.5, + adp_type='Biso', adp_iso=1.66, ) @@ -1478,7 +1482,7 @@ # the analysis. # %% -project_2.save_as(dir_path='data/powder_diffraction_LBCO_Si') +project_2.save_as(dir_path='projects/ed_13_main') # %% [markdown] # #### Final Remarks diff --git a/docs/docs/tutorials/ed-14.ipynb b/docs/docs/tutorials/ed-14.ipynb index 2c744b0da..9488915db 100644 --- a/docs/docs/tutorials/ed-14.ipynb +++ b/docs/docs/tutorials/ed-14.ipynb @@ -63,14 +63,14 @@ "metadata": {}, "outputs": [], "source": [ - "# Create minimal project without name and description\n", + "# Create a minimal project with a short name\n", "project = ed.Project(name='tbti_heidi')\n", "project.info.title = 'Tb2Ti2O7 at HEiDi@FRMII'\n", "project.info.description = \"\"\"This project demonstrates a standard\n", "refinement of the crystal structure of Tb2Ti2O7 using single crystal \n", "neutron diffraction data from HEiDi at FRM II.\"\"\"\n", "\n", - "project.save_as('projects/tbti_heidi')" + "project.save_as(dir_path='projects/ed_14_tbti_heidi')" ] }, { diff --git a/docs/docs/tutorials/ed-14.py b/docs/docs/tutorials/ed-14.py index f0b214526..03a2b329d 100644 --- a/docs/docs/tutorials/ed-14.py +++ b/docs/docs/tutorials/ed-14.py @@ -14,14 +14,14 @@ # ## 📦 Define Project # %% -# Create minimal project without name and description +# Create a minimal project with a short name project = ed.Project(name='tbti_heidi') project.info.title = 'Tb2Ti2O7 at HEiDi@FRMII' project.info.description = """This project demonstrates a standard refinement of the crystal structure of Tb2Ti2O7 using single crystal neutron diffraction data from HEiDi at FRM II.""" -project.save_as('projects/tbti_heidi') +project.save_as(dir_path='projects/ed_14_tbti_heidi') # %% [markdown] # ## 🧩 Define Structure diff --git a/docs/docs/tutorials/ed-15.ipynb b/docs/docs/tutorials/ed-15.ipynb index 821429bd9..2fcc797fa 100644 --- a/docs/docs/tutorials/ed-15.ipynb +++ b/docs/docs/tutorials/ed-15.ipynb @@ -63,8 +63,8 @@ "metadata": {}, "outputs": [], "source": [ - "# Create minimal project without name and description\n", - "project = ed.Project()" + "# Create a minimal project with a short name\n", + "project = ed.Project(name='taurine_senju')" ] }, { @@ -425,6 +425,24 @@ "source": [ "structure.show_as_cif()" ] + }, + { + "cell_type": "markdown", + "id": "41", + "metadata": {}, + "source": [ + "## 💾 Save Project" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "42", + "metadata": {}, + "outputs": [], + "source": [ + "project.save_as(dir_path='projects/ed_15_taurine_senju')" + ] } ], "metadata": { diff --git a/docs/docs/tutorials/ed-15.py b/docs/docs/tutorials/ed-15.py index 2fcf91934..c8d799405 100644 --- a/docs/docs/tutorials/ed-15.py +++ b/docs/docs/tutorials/ed-15.py @@ -14,8 +14,8 @@ # ## 📦 Define Project # %% -# Create minimal project without name and description -project = ed.Project() +# Create a minimal project with a short name +project = ed.Project(name='taurine_senju') # %% [markdown] # ## 🧩 Define Structure @@ -140,3 +140,9 @@ # %% structure.show_as_cif() + +# %% [markdown] +# ## 💾 Save Project + +# %% +project.save_as(dir_path='projects/ed_15_taurine_senju') diff --git a/docs/docs/tutorials/ed-16.ipynb b/docs/docs/tutorials/ed-16.ipynb index 09c816f05..0e26f35e7 100644 --- a/docs/docs/tutorials/ed-16.ipynb +++ b/docs/docs/tutorials/ed-16.ipynb @@ -374,7 +374,7 @@ "metadata": {}, "outputs": [], "source": [ - "project = Project()" + "project = Project(name='si_bragg_pdf')" ] }, { @@ -618,6 +618,24 @@ "source": [ "project.display.pattern(expt_name='nomad')" ] + }, + { + "cell_type": "markdown", + "id": "58", + "metadata": {}, + "source": [ + "## 💾 Save Project" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "59", + "metadata": {}, + "outputs": [], + "source": [ + "project.save_as(dir_path='projects/ed_16_si_bragg_pdf')" + ] } ], "metadata": { diff --git a/docs/docs/tutorials/ed-16.py b/docs/docs/tutorials/ed-16.py index 89e60625f..1a811a2a8 100644 --- a/docs/docs/tutorials/ed-16.py +++ b/docs/docs/tutorials/ed-16.py @@ -157,7 +157,7 @@ # ### Create Project # %% -project = Project() +project = Project(name='si_bragg_pdf') # %% [markdown] # ### Add Structure @@ -254,3 +254,9 @@ # %% project.display.pattern(expt_name='nomad') + +# %% [markdown] +# ## 💾 Save Project + +# %% +project.save_as(dir_path='projects/ed_16_si_bragg_pdf') diff --git a/docs/docs/tutorials/ed-17.ipynb b/docs/docs/tutorials/ed-17.ipynb index 351290746..81bce1da7 100644 --- a/docs/docs/tutorials/ed-17.ipynb +++ b/docs/docs/tutorials/ed-17.ipynb @@ -69,7 +69,7 @@ "metadata": {}, "outputs": [], "source": [ - "project = ed.Project(name='cosio_d20')\n", + "project = ed.Project(name='cosio_d20_scan')\n", "analysis = project.analysis\n", "display = project.display" ] @@ -90,7 +90,7 @@ "metadata": {}, "outputs": [], "source": [ - "project.save_as(dir_path='projects/cosio_d20_scan')" + "project.save_as(dir_path='projects/ed_17_cosio_d20_scan')" ] }, { diff --git a/docs/docs/tutorials/ed-17.py b/docs/docs/tutorials/ed-17.py index eb3605e9d..7391e1582 100644 --- a/docs/docs/tutorials/ed-17.py +++ b/docs/docs/tutorials/ed-17.py @@ -20,7 +20,7 @@ # and other related components. # %% -project = ed.Project(name='cosio_d20') +project = ed.Project(name='cosio_d20_scan') analysis = project.analysis display = project.display @@ -29,7 +29,7 @@ # results can be written to `analysis/results.csv`. # %% -project.save_as(dir_path='projects/cosio_d20_scan') +project.save_as(dir_path='projects/ed_17_cosio_d20_scan') # %% [markdown] # ## 🧩 Define Structure diff --git a/docs/docs/tutorials/ed-18.ipynb b/docs/docs/tutorials/ed-18.ipynb index 86d6cb69d..0299b4487 100644 --- a/docs/docs/tutorials/ed-18.ipynb +++ b/docs/docs/tutorials/ed-18.ipynb @@ -181,6 +181,24 @@ "source": [ "project.display.pattern(expt_name='hrpt')" ] + }, + { + "cell_type": "markdown", + "id": "18", + "metadata": {}, + "source": [ + "## 💾 Save Project" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "19", + "metadata": {}, + "outputs": [], + "source": [ + "project.save_as(dir_path='projects/ed_18_lbco_hrpt')" + ] } ], "metadata": { diff --git a/docs/docs/tutorials/ed-18.py b/docs/docs/tutorials/ed-18.py index f3caa2e09..c65c0243f 100644 --- a/docs/docs/tutorials/ed-18.py +++ b/docs/docs/tutorials/ed-18.py @@ -59,3 +59,9 @@ # %% project.display.pattern(expt_name='hrpt') + +# %% [markdown] +# ## 💾 Save Project + +# %% +project.save_as(dir_path='projects/ed_18_lbco_hrpt') diff --git a/docs/docs/tutorials/ed-2.ipynb b/docs/docs/tutorials/ed-2.ipynb index 9b1872b5b..60ba1b82c 100644 --- a/docs/docs/tutorials/ed-2.ipynb +++ b/docs/docs/tutorials/ed-2.ipynb @@ -80,7 +80,7 @@ "metadata": {}, "outputs": [], "source": [ - "project = ed.Project()" + "project = ed.Project(name='lbco_hrpt')" ] }, { @@ -549,7 +549,7 @@ "metadata": {}, "outputs": [], "source": [ - "project.save_as('projects/lbco_hrpt')" + "project.save_as(dir_path='projects/ed_2_lbco_hrpt')" ] } ], diff --git a/docs/docs/tutorials/ed-2.py b/docs/docs/tutorials/ed-2.py index 008ca5d0f..e2207a8b2 100644 --- a/docs/docs/tutorials/ed-2.py +++ b/docs/docs/tutorials/ed-2.py @@ -31,7 +31,7 @@ # ## 📦 Define Project # %% -project = ed.Project() +project = ed.Project(name='lbco_hrpt') # %% [markdown] # ## 🧩 Define Structure @@ -234,4 +234,4 @@ # ## 💾 Save Project # %% -project.save_as('projects/lbco_hrpt') +project.save_as(dir_path='projects/ed_2_lbco_hrpt') diff --git a/docs/docs/tutorials/ed-20.ipynb b/docs/docs/tutorials/ed-20.ipynb index 6dc22803e..98d9572a7 100644 --- a/docs/docs/tutorials/ed-20.ipynb +++ b/docs/docs/tutorials/ed-20.ipynb @@ -456,8 +456,8 @@ "metadata": {}, "outputs": [], "source": [ - "project = Project(name='beer')\n", - "project.save_as(dir_path='projects/beer_mcstas')" + "project = Project(name='beer_mcstas')\n", + "project.save_as(dir_path='projects/ed_20_beer_mcstas')" ] }, { diff --git a/docs/docs/tutorials/ed-20.py b/docs/docs/tutorials/ed-20.py index 5b4b6fe03..bc5b1e644 100644 --- a/docs/docs/tutorials/ed-20.py +++ b/docs/docs/tutorials/ed-20.py @@ -222,8 +222,8 @@ # ### Create Project # %% -project = Project(name='beer') -project.save_as(dir_path='projects/beer_mcstas') +project = Project(name='beer_mcstas') +project.save_as(dir_path='projects/ed_20_beer_mcstas') # %% [markdown] # ### Add Structures diff --git a/docs/docs/tutorials/ed-21.ipynb b/docs/docs/tutorials/ed-21.ipynb index 697851df6..0b4ab246e 100644 --- a/docs/docs/tutorials/ed-21.ipynb +++ b/docs/docs/tutorials/ed-21.ipynb @@ -87,7 +87,7 @@ "metadata": {}, "outputs": [], "source": [ - "project = ed.Project()" + "project = ed.Project(name='lbco_hrpt_bumps_dream')" ] }, { @@ -97,7 +97,7 @@ "metadata": {}, "outputs": [], "source": [ - "project.save_as('projects/lbco_hrpt_bumps-dream')" + "project.save_as(dir_path='projects/ed_21_lbco_hrpt_bumps_dream')" ] }, { @@ -637,7 +637,8 @@ "outputs": [], "source": [ "project.analysis.minimizer.sampling_steps = 100 # lower than the default 3000\n", - "project.analysis.minimizer.burn_in_steps = 20 # lower than the default 600" + "project.analysis.minimizer.burn_in_steps = 20 # lower than the default 600\n", + "project.analysis.minimizer.random_seed = 42 # fixed seed for reproducible output" ] }, { diff --git a/docs/docs/tutorials/ed-21.py b/docs/docs/tutorials/ed-21.py index efce4cacd..002f3ba4d 100644 --- a/docs/docs/tutorials/ed-21.py +++ b/docs/docs/tutorials/ed-21.py @@ -38,10 +38,10 @@ # it later if needed. # %% -project = ed.Project() +project = ed.Project(name='lbco_hrpt_bumps_dream') # %% -project.save_as('projects/lbco_hrpt_bumps-dream') +project.save_as(dir_path='projects/ed_21_lbco_hrpt_bumps_dream') # %% [markdown] # ## 🧩 Define Structure @@ -306,6 +306,7 @@ # %% project.analysis.minimizer.sampling_steps = 100 # lower than the default 3000 project.analysis.minimizer.burn_in_steps = 20 # lower than the default 600 +project.analysis.minimizer.random_seed = 42 # fixed seed for reproducible output # %% project.analysis.fit() diff --git a/docs/docs/tutorials/ed-22.ipynb b/docs/docs/tutorials/ed-22.ipynb index 1a70e189e..d7f559090 100644 --- a/docs/docs/tutorials/ed-22.ipynb +++ b/docs/docs/tutorials/ed-22.ipynb @@ -84,7 +84,7 @@ "metadata": {}, "outputs": [], "source": [ - "project = ed.Project()" + "project = ed.Project(name='tbti_heidi_emcee')" ] }, { @@ -94,7 +94,7 @@ "metadata": {}, "outputs": [], "source": [ - "project.save_as('projects/tbti_heidi_emcee')" + "project.save_as(dir_path='projects/ed_22_tbti_heidi_emcee')" ] }, { @@ -510,7 +510,8 @@ "source": [ "project.analysis.minimizer.sampling_steps = 500 # lower than the default 3000\n", "project.analysis.minimizer.burn_in_steps = 100 # lower than the default 600\n", - "project.analysis.minimizer.population_size = 16 # lower than the default 32" + "project.analysis.minimizer.population_size = 16 # lower than the default 32\n", + "project.analysis.minimizer.random_seed = 42 # fixed seed for reproducible output" ] }, { diff --git a/docs/docs/tutorials/ed-22.py b/docs/docs/tutorials/ed-22.py index e1b3f8abe..d9dcad9ca 100644 --- a/docs/docs/tutorials/ed-22.py +++ b/docs/docs/tutorials/ed-22.py @@ -35,10 +35,10 @@ # workflow inside this object. # %% -project = ed.Project() +project = ed.Project(name='tbti_heidi_emcee') # %% -project.save_as('projects/tbti_heidi_emcee') +project.save_as(dir_path='projects/ed_22_tbti_heidi_emcee') # %% [markdown] # ## 🧩 Define Structure @@ -229,6 +229,7 @@ project.analysis.minimizer.sampling_steps = 500 # lower than the default 3000 project.analysis.minimizer.burn_in_steps = 100 # lower than the default 600 project.analysis.minimizer.population_size = 16 # lower than the default 32 +project.analysis.minimizer.random_seed = 42 # fixed seed for reproducible output # %% project.analysis.fit() diff --git a/docs/docs/tutorials/ed-23.ipynb b/docs/docs/tutorials/ed-23.ipynb index 368150181..fcca74451 100644 --- a/docs/docs/tutorials/ed-23.ipynb +++ b/docs/docs/tutorials/ed-23.ipynb @@ -258,6 +258,24 @@ "source": [ "project.display.fit.series(versus=temperature)" ] + }, + { + "cell_type": "markdown", + "id": "24", + "metadata": {}, + "source": [ + "## 💾 Save Project" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "25", + "metadata": {}, + "outputs": [], + "source": [ + "project.save_as(dir_path='projects/ed_23_cosio_d20_scan')" + ] } ], "metadata": { diff --git a/docs/docs/tutorials/ed-23.py b/docs/docs/tutorials/ed-23.py index f7e01bc66..59ee1c6ef 100644 --- a/docs/docs/tutorials/ed-23.py +++ b/docs/docs/tutorials/ed-23.py @@ -102,3 +102,9 @@ # %% project.display.fit.series(versus=temperature) + +# %% [markdown] +# ## 💾 Save Project + +# %% +project.save_as(dir_path='projects/ed_23_cosio_d20_scan') diff --git a/docs/docs/tutorials/ed-24.ipynb b/docs/docs/tutorials/ed-24.ipynb index e21fd7ed6..b4dbb1fee 100644 --- a/docs/docs/tutorials/ed-24.ipynb +++ b/docs/docs/tutorials/ed-24.ipynb @@ -245,6 +245,24 @@ "source": [ "project.display.posterior.predictive(expt_name='hrpt', x_min=92, x_max=93)" ] + }, + { + "cell_type": "markdown", + "id": "23", + "metadata": {}, + "source": [ + "## 💾 Save Project" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "24", + "metadata": {}, + "outputs": [], + "source": [ + "project.save_as(dir_path='projects/ed_24_lbco_hrpt_bumps_dream')" + ] } ], "metadata": { diff --git a/docs/docs/tutorials/ed-24.py b/docs/docs/tutorials/ed-24.py index 95cfff7d7..984706474 100644 --- a/docs/docs/tutorials/ed-24.py +++ b/docs/docs/tutorials/ed-24.py @@ -94,3 +94,9 @@ # %% project.display.posterior.predictive(expt_name='hrpt', x_min=92, x_max=93) + +# %% [markdown] +# ## 💾 Save Project + +# %% +project.save_as(dir_path='projects/ed_24_lbco_hrpt_bumps_dream') diff --git a/docs/docs/tutorials/ed-25.ipynb b/docs/docs/tutorials/ed-25.ipynb index 7f94ff8d9..b7757aa2f 100644 --- a/docs/docs/tutorials/ed-25.ipynb +++ b/docs/docs/tutorials/ed-25.ipynb @@ -87,7 +87,7 @@ "metadata": {}, "outputs": [], "source": [ - "project = ed.Project()" + "project = ed.Project(name='lbco_hrpt_emcee')" ] }, { @@ -97,7 +97,7 @@ "metadata": {}, "outputs": [], "source": [ - "project.save_as('projects/lbco_hrpt_emcee')" + "project.save_as(dir_path='projects/ed_25_lbco_hrpt_emcee')" ] }, { @@ -623,7 +623,8 @@ "source": [ "project.analysis.minimizer.sampling_steps = 100 # lower than the default 5000\n", "project.analysis.minimizer.burn_in_steps = 20 # lower than the default 1000\n", - "project.analysis.minimizer.population_size = 16 # lower than the default 32" + "project.analysis.minimizer.population_size = 16 # lower than the default 32\n", + "project.analysis.minimizer.random_seed = 42 # fixed seed for reproducible output" ] }, { diff --git a/docs/docs/tutorials/ed-25.py b/docs/docs/tutorials/ed-25.py index 8806d05cc..662615def 100644 --- a/docs/docs/tutorials/ed-25.py +++ b/docs/docs/tutorials/ed-25.py @@ -38,10 +38,10 @@ # it later if needed. # %% -project = ed.Project() +project = ed.Project(name='lbco_hrpt_emcee') # %% -project.save_as('projects/lbco_hrpt_emcee') +project.save_as(dir_path='projects/ed_25_lbco_hrpt_emcee') # %% [markdown] # ## 🧩 Define Structure @@ -299,6 +299,7 @@ project.analysis.minimizer.sampling_steps = 100 # lower than the default 5000 project.analysis.minimizer.burn_in_steps = 20 # lower than the default 1000 project.analysis.minimizer.population_size = 16 # lower than the default 32 +project.analysis.minimizer.random_seed = 42 # fixed seed for reproducible output # %% project.analysis.fit() diff --git a/docs/docs/tutorials/ed-26.ipynb b/docs/docs/tutorials/ed-26.ipynb index f9a778aa3..1e4460336 100644 --- a/docs/docs/tutorials/ed-26.ipynb +++ b/docs/docs/tutorials/ed-26.ipynb @@ -291,6 +291,7 @@ "metadata": {}, "outputs": [], "source": [ + "project.analysis.minimizer.random_seed = 42 # fixed seed for reproducible output\n", "project.analysis.fit(resume=True, extra_steps=100)" ] }, @@ -343,6 +344,24 @@ "source": [ "project.display.posterior.predictive(expt_name='hrpt', x_min=92, x_max=93)" ] + }, + { + "cell_type": "markdown", + "id": "31", + "metadata": {}, + "source": [ + "## 💾 Save Project" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "32", + "metadata": {}, + "outputs": [], + "source": [ + "project.save_as(dir_path='projects/ed_26_lbco_hrpt_emcee')" + ] } ], "metadata": { diff --git a/docs/docs/tutorials/ed-26.py b/docs/docs/tutorials/ed-26.py index c3d994d62..d3d9be817 100644 --- a/docs/docs/tutorials/ed-26.py +++ b/docs/docs/tutorials/ed-26.py @@ -124,6 +124,7 @@ # convergence and better posterior resolution. # %% +project.analysis.minimizer.random_seed = 42 # fixed seed for reproducible output project.analysis.fit(resume=True, extra_steps=100) # %% @@ -142,3 +143,9 @@ # %% project.display.posterior.predictive(expt_name='hrpt', x_min=92, x_max=93) + +# %% [markdown] +# ## 💾 Save Project + +# %% +project.save_as(dir_path='projects/ed_26_lbco_hrpt_emcee') diff --git a/docs/docs/tutorials/ed-3.ipynb b/docs/docs/tutorials/ed-3.ipynb index cce439297..2ed3d57e0 100644 --- a/docs/docs/tutorials/ed-3.ipynb +++ b/docs/docs/tutorials/ed-3.ipynb @@ -148,7 +148,7 @@ "metadata": {}, "outputs": [], "source": [ - "project.save_as(dir_path='projects/lbco_hrpt')" + "project.save_as(dir_path='projects/ed_3_lbco_hrpt')" ] }, { @@ -594,7 +594,7 @@ "metadata": {}, "outputs": [], "source": [ - "project.display.pattern(expt_name='hrpt', include='measured')" + "project.display.pattern(expt_name='hrpt')" ] }, { @@ -907,24 +907,6 @@ "cell_type": "markdown", "id": "85", "metadata": {}, - "source": [ - "### Show Calculated Data" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "86", - "metadata": {}, - "outputs": [], - "source": [ - "project.display.pattern(expt_name='hrpt', include='calculated')" - ] - }, - { - "cell_type": "markdown", - "id": "87", - "metadata": {}, "source": [ "### Display Pattern" ] @@ -932,7 +914,7 @@ { "cell_type": "code", "execution_count": null, - "id": "88", + "id": "86", "metadata": {}, "outputs": [], "source": [ @@ -942,7 +924,7 @@ { "cell_type": "code", "execution_count": null, - "id": "89", + "id": "87", "metadata": {}, "outputs": [], "source": [ @@ -951,7 +933,7 @@ }, { "cell_type": "markdown", - "id": "90", + "id": "88", "metadata": {}, "source": [ "### Display Parameters\n", @@ -962,7 +944,7 @@ { "cell_type": "code", "execution_count": null, - "id": "91", + "id": "89", "metadata": {}, "outputs": [], "source": [ @@ -971,7 +953,7 @@ }, { "cell_type": "markdown", - "id": "92", + "id": "90", "metadata": {}, "source": [ "Show all fittable parameters." @@ -980,7 +962,7 @@ { "cell_type": "code", "execution_count": null, - "id": "93", + "id": "91", "metadata": {}, "outputs": [], "source": [ @@ -989,7 +971,7 @@ }, { "cell_type": "markdown", - "id": "94", + "id": "92", "metadata": {}, "source": [ "Show only free parameters." @@ -998,7 +980,7 @@ { "cell_type": "code", "execution_count": null, - "id": "95", + "id": "93", "metadata": {}, "outputs": [], "source": [ @@ -1007,7 +989,7 @@ }, { "cell_type": "markdown", - "id": "96", + "id": "94", "metadata": {}, "source": [ "Show how to access parameters in the code." @@ -1016,7 +998,7 @@ { "cell_type": "code", "execution_count": null, - "id": "97", + "id": "95", "metadata": {}, "outputs": [], "source": [ @@ -1025,7 +1007,7 @@ }, { "cell_type": "markdown", - "id": "98", + "id": "96", "metadata": {}, "source": [ "### Set Fit Mode\n", @@ -1036,7 +1018,7 @@ { "cell_type": "code", "execution_count": null, - "id": "99", + "id": "97", "metadata": {}, "outputs": [], "source": [ @@ -1045,7 +1027,7 @@ }, { "cell_type": "markdown", - "id": "100", + "id": "98", "metadata": {}, "source": [ "Select desired fit mode." @@ -1054,7 +1036,7 @@ { "cell_type": "code", "execution_count": null, - "id": "101", + "id": "99", "metadata": {}, "outputs": [], "source": [ @@ -1063,7 +1045,7 @@ }, { "cell_type": "markdown", - "id": "102", + "id": "100", "metadata": {}, "source": [ "### Set Minimizer\n", @@ -1074,7 +1056,7 @@ { "cell_type": "code", "execution_count": null, - "id": "103", + "id": "101", "metadata": {}, "outputs": [], "source": [ @@ -1083,7 +1065,7 @@ }, { "cell_type": "markdown", - "id": "104", + "id": "102", "metadata": {}, "source": [ "Select desired fitting engine." @@ -1092,7 +1074,7 @@ { "cell_type": "code", "execution_count": null, - "id": "105", + "id": "103", "metadata": {}, "outputs": [], "source": [ @@ -1101,7 +1083,7 @@ }, { "cell_type": "markdown", - "id": "106", + "id": "104", "metadata": {}, "source": [ "### Perform Fit 1/5\n", @@ -1112,7 +1094,7 @@ { "cell_type": "code", "execution_count": null, - "id": "107", + "id": "105", "metadata": {}, "outputs": [], "source": [ @@ -1121,7 +1103,7 @@ }, { "cell_type": "markdown", - "id": "108", + "id": "106", "metadata": {}, "source": [ "Set experiment parameters to be refined." @@ -1130,7 +1112,7 @@ { "cell_type": "code", "execution_count": null, - "id": "109", + "id": "107", "metadata": {}, "outputs": [], "source": [ @@ -1145,7 +1127,7 @@ }, { "cell_type": "markdown", - "id": "110", + "id": "108", "metadata": {}, "source": [ "Show free parameters after selection." @@ -1154,7 +1136,7 @@ { "cell_type": "code", "execution_count": null, - "id": "111", + "id": "109", "metadata": {}, "outputs": [], "source": [ @@ -1163,7 +1145,7 @@ }, { "cell_type": "markdown", - "id": "112", + "id": "110", "metadata": {}, "source": [ "#### Run Fitting" @@ -1172,7 +1154,7 @@ { "cell_type": "code", "execution_count": null, - "id": "113", + "id": "111", "metadata": {}, "outputs": [], "source": [ @@ -1182,7 +1164,7 @@ }, { "cell_type": "markdown", - "id": "114", + "id": "112", "metadata": {}, "source": [ "#### Display Pattern" @@ -1191,7 +1173,7 @@ { "cell_type": "code", "execution_count": null, - "id": "115", + "id": "113", "metadata": {}, "outputs": [], "source": [ @@ -1201,7 +1183,7 @@ { "cell_type": "code", "execution_count": null, - "id": "116", + "id": "114", "metadata": {}, "outputs": [], "source": [ @@ -1210,7 +1192,7 @@ }, { "cell_type": "markdown", - "id": "117", + "id": "115", "metadata": {}, "source": [ "### Perform Fit 2/5\n", @@ -1221,7 +1203,7 @@ { "cell_type": "code", "execution_count": null, - "id": "118", + "id": "116", "metadata": {}, "outputs": [], "source": [ @@ -1233,7 +1215,7 @@ }, { "cell_type": "markdown", - "id": "119", + "id": "117", "metadata": {}, "source": [ "Show free parameters after selection." @@ -1242,7 +1224,7 @@ { "cell_type": "code", "execution_count": null, - "id": "120", + "id": "118", "metadata": {}, "outputs": [], "source": [ @@ -1251,7 +1233,7 @@ }, { "cell_type": "markdown", - "id": "121", + "id": "119", "metadata": {}, "source": [ "#### Run Fitting" @@ -1260,7 +1242,7 @@ { "cell_type": "code", "execution_count": null, - "id": "122", + "id": "120", "metadata": {}, "outputs": [], "source": [ @@ -1270,7 +1252,7 @@ }, { "cell_type": "markdown", - "id": "123", + "id": "121", "metadata": {}, "source": [ "#### Display Pattern" @@ -1279,7 +1261,7 @@ { "cell_type": "code", "execution_count": null, - "id": "124", + "id": "122", "metadata": {}, "outputs": [], "source": [ @@ -1289,7 +1271,7 @@ { "cell_type": "code", "execution_count": null, - "id": "125", + "id": "123", "metadata": {}, "outputs": [], "source": [ @@ -1298,7 +1280,7 @@ }, { "cell_type": "markdown", - "id": "126", + "id": "124", "metadata": {}, "source": [ "#### Save Project State" @@ -1307,7 +1289,7 @@ { "cell_type": "code", "execution_count": null, - "id": "127", + "id": "125", "metadata": {}, "outputs": [], "source": [ @@ -1316,7 +1298,7 @@ }, { "cell_type": "markdown", - "id": "128", + "id": "126", "metadata": {}, "source": [ "### Perform Fit 3/5\n", @@ -1327,7 +1309,7 @@ { "cell_type": "code", "execution_count": null, - "id": "129", + "id": "127", "metadata": {}, "outputs": [], "source": [ @@ -1339,7 +1321,7 @@ }, { "cell_type": "markdown", - "id": "130", + "id": "128", "metadata": {}, "source": [ "Show free parameters after selection." @@ -1348,7 +1330,7 @@ { "cell_type": "code", "execution_count": null, - "id": "131", + "id": "129", "metadata": {}, "outputs": [], "source": [ @@ -1357,7 +1339,7 @@ }, { "cell_type": "markdown", - "id": "132", + "id": "130", "metadata": {}, "source": [ "#### Run Fitting" @@ -1366,7 +1348,7 @@ { "cell_type": "code", "execution_count": null, - "id": "133", + "id": "131", "metadata": {}, "outputs": [], "source": [ @@ -1376,7 +1358,7 @@ }, { "cell_type": "markdown", - "id": "134", + "id": "132", "metadata": {}, "source": [ "#### Display Pattern" @@ -1385,7 +1367,7 @@ { "cell_type": "code", "execution_count": null, - "id": "135", + "id": "133", "metadata": {}, "outputs": [], "source": [ @@ -1395,7 +1377,7 @@ { "cell_type": "code", "execution_count": null, - "id": "136", + "id": "134", "metadata": {}, "outputs": [], "source": [ @@ -1404,7 +1386,7 @@ }, { "cell_type": "markdown", - "id": "137", + "id": "135", "metadata": {}, "source": [ "### Perform Fit 4/5\n", @@ -1417,7 +1399,7 @@ { "cell_type": "code", "execution_count": null, - "id": "138", + "id": "136", "metadata": {}, "outputs": [], "source": [ @@ -1433,7 +1415,7 @@ }, { "cell_type": "markdown", - "id": "139", + "id": "137", "metadata": {}, "source": [ "Set constraints." @@ -1442,7 +1424,7 @@ { "cell_type": "code", "execution_count": null, - "id": "140", + "id": "138", "metadata": {}, "outputs": [], "source": [ @@ -1451,7 +1433,7 @@ }, { "cell_type": "markdown", - "id": "141", + "id": "139", "metadata": {}, "source": [ "Show defined constraints." @@ -1460,7 +1442,7 @@ { "cell_type": "code", "execution_count": null, - "id": "142", + "id": "140", "metadata": {}, "outputs": [], "source": [ @@ -1469,7 +1451,7 @@ }, { "cell_type": "markdown", - "id": "143", + "id": "141", "metadata": {}, "source": [ "Show free parameters." @@ -1478,7 +1460,7 @@ { "cell_type": "code", "execution_count": null, - "id": "144", + "id": "142", "metadata": {}, "outputs": [], "source": [ @@ -1487,7 +1469,7 @@ }, { "cell_type": "markdown", - "id": "145", + "id": "143", "metadata": {}, "source": [ "#### Run Fitting" @@ -1496,7 +1478,7 @@ { "cell_type": "code", "execution_count": null, - "id": "146", + "id": "144", "metadata": {}, "outputs": [], "source": [ @@ -1506,7 +1488,7 @@ }, { "cell_type": "markdown", - "id": "147", + "id": "145", "metadata": {}, "source": [ "#### Display Pattern" @@ -1515,7 +1497,7 @@ { "cell_type": "code", "execution_count": null, - "id": "148", + "id": "146", "metadata": {}, "outputs": [], "source": [ @@ -1525,7 +1507,7 @@ { "cell_type": "code", "execution_count": null, - "id": "149", + "id": "147", "metadata": {}, "outputs": [], "source": [ @@ -1534,7 +1516,7 @@ }, { "cell_type": "markdown", - "id": "150", + "id": "148", "metadata": {}, "source": [ "### Perform Fit 5/5\n", @@ -1547,7 +1529,7 @@ { "cell_type": "code", "execution_count": null, - "id": "151", + "id": "149", "metadata": {}, "outputs": [], "source": [ @@ -1563,7 +1545,7 @@ }, { "cell_type": "markdown", - "id": "152", + "id": "150", "metadata": {}, "source": [ "Set more constraints." @@ -1572,7 +1554,7 @@ { "cell_type": "code", "execution_count": null, - "id": "153", + "id": "151", "metadata": {}, "outputs": [], "source": [ @@ -1583,7 +1565,7 @@ }, { "cell_type": "markdown", - "id": "154", + "id": "152", "metadata": {}, "source": [ "Show defined constraints." @@ -1592,7 +1574,7 @@ { "cell_type": "code", "execution_count": null, - "id": "155", + "id": "153", "metadata": { "lines_to_next_cell": 2 }, @@ -1603,7 +1585,7 @@ }, { "cell_type": "markdown", - "id": "156", + "id": "154", "metadata": {}, "source": [ "Set structure parameters to be refined." @@ -1612,7 +1594,7 @@ { "cell_type": "code", "execution_count": null, - "id": "157", + "id": "155", "metadata": {}, "outputs": [], "source": [ @@ -1621,7 +1603,7 @@ }, { "cell_type": "markdown", - "id": "158", + "id": "156", "metadata": {}, "source": [ "Show free parameters after selection." @@ -1630,7 +1612,7 @@ { "cell_type": "code", "execution_count": null, - "id": "159", + "id": "157", "metadata": {}, "outputs": [], "source": [ @@ -1639,7 +1621,7 @@ }, { "cell_type": "markdown", - "id": "160", + "id": "158", "metadata": {}, "source": [ "#### Run Fitting" @@ -1648,7 +1630,7 @@ { "cell_type": "code", "execution_count": null, - "id": "161", + "id": "159", "metadata": {}, "outputs": [], "source": [ @@ -1659,7 +1641,7 @@ }, { "cell_type": "markdown", - "id": "162", + "id": "160", "metadata": {}, "source": [ "#### Display Pattern" @@ -1668,7 +1650,7 @@ { "cell_type": "code", "execution_count": null, - "id": "163", + "id": "161", "metadata": {}, "outputs": [], "source": [ @@ -1678,26 +1660,16 @@ { "cell_type": "code", "execution_count": null, - "id": "164", + "id": "162", "metadata": {}, "outputs": [], "source": [ "project.display.pattern(expt_name='hrpt', x_min=38, x_max=41)" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "165", - "metadata": {}, - "outputs": [], - "source": [ - "project.display.structure(struct_name='lbco')" - ] - }, { "cell_type": "markdown", - "id": "166", + "id": "163", "metadata": {}, "source": [ "#### Display Structure" @@ -1706,7 +1678,7 @@ { "cell_type": "code", "execution_count": null, - "id": "167", + "id": "164", "metadata": {}, "outputs": [], "source": [ @@ -1715,7 +1687,7 @@ }, { "cell_type": "markdown", - "id": "168", + "id": "165", "metadata": {}, "source": [ "## 📊 Report\n", @@ -1735,7 +1707,7 @@ { "cell_type": "code", "execution_count": null, - "id": "169", + "id": "166", "metadata": {}, "outputs": [], "source": [ diff --git a/docs/docs/tutorials/ed-3.py b/docs/docs/tutorials/ed-3.py index 6b1c06dc1..16af51f1c 100644 --- a/docs/docs/tutorials/ed-3.py +++ b/docs/docs/tutorials/ed-3.py @@ -58,7 +58,7 @@ # directory path. # %% -project.save_as(dir_path='projects/lbco_hrpt') +project.save_as(dir_path='projects/ed_3_lbco_hrpt') # %% [markdown] # ## 🧩 Define Structure @@ -257,7 +257,7 @@ # ### Show Measured Data # %% -project.display.pattern(expt_name='hrpt', include='measured') +project.display.pattern(expt_name='hrpt') # %% [markdown] # ### Set Instrument @@ -380,12 +380,6 @@ # %% project.rendering_plot.help() -# %% [markdown] -# ### Show Calculated Data - -# %% -project.display.pattern(expt_name='hrpt', include='calculated') - # %% [markdown] # ### Display Pattern @@ -675,9 +669,6 @@ # %% project.display.pattern(expt_name='hrpt', x_min=38, x_max=41) -# %% -project.display.structure(struct_name='lbco') - # %% [markdown] # #### Display Structure diff --git a/docs/docs/tutorials/ed-4.ipynb b/docs/docs/tutorials/ed-4.ipynb index c45ed29cf..8f7797640 100644 --- a/docs/docs/tutorials/ed-4.ipynb +++ b/docs/docs/tutorials/ed-4.ipynb @@ -511,7 +511,7 @@ "metadata": {}, "outputs": [], "source": [ - "project = Project()" + "project = Project(name='pbso4_joint')" ] }, { @@ -712,6 +712,24 @@ "source": [ "project.display.pattern(expt_name='xrd', x_min=29.0, x_max=30.4)" ] + }, + { + "cell_type": "markdown", + "id": "63", + "metadata": {}, + "source": [ + "## 💾 Save Project" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "64", + "metadata": {}, + "outputs": [], + "source": [ + "project.save_as(dir_path='projects/ed_4_pbso4_joint')" + ] } ], "metadata": { diff --git a/docs/docs/tutorials/ed-4.py b/docs/docs/tutorials/ed-4.py index 0e974893a..1ab7a4416 100644 --- a/docs/docs/tutorials/ed-4.py +++ b/docs/docs/tutorials/ed-4.py @@ -235,7 +235,7 @@ # ### Create Project # %% -project = Project() +project = Project(name='pbso4_joint') # %% [markdown] # ### Add Structure @@ -320,3 +320,9 @@ # %% project.display.pattern(expt_name='xrd', x_min=29.0, x_max=30.4) + +# %% [markdown] +# ## 💾 Save Project + +# %% +project.save_as(dir_path='projects/ed_4_pbso4_joint') diff --git a/docs/docs/tutorials/ed-5.ipynb b/docs/docs/tutorials/ed-5.ipynb index 391ca3651..a57352ba9 100644 --- a/docs/docs/tutorials/ed-5.ipynb +++ b/docs/docs/tutorials/ed-5.ipynb @@ -361,7 +361,7 @@ "metadata": {}, "outputs": [], "source": [ - "project = Project()" + "project = Project(name='cosio_d20')" ] }, { @@ -371,7 +371,7 @@ "metadata": {}, "outputs": [], "source": [ - "project.save_as('projects/cosio_d20')" + "project.save_as(dir_path='projects/ed_5_cosio_d20')" ] }, { diff --git a/docs/docs/tutorials/ed-5.py b/docs/docs/tutorials/ed-5.py index 942444d25..23a091d6e 100644 --- a/docs/docs/tutorials/ed-5.py +++ b/docs/docs/tutorials/ed-5.py @@ -171,10 +171,10 @@ # ### Create Project # %% -project = Project() +project = Project(name='cosio_d20') # %% -project.save_as('projects/cosio_d20') +project.save_as(dir_path='projects/ed_5_cosio_d20') # %% [markdown] # ### Add Structure diff --git a/docs/docs/tutorials/ed-6.ipynb b/docs/docs/tutorials/ed-6.ipynb index 561afb750..e38f74ef4 100644 --- a/docs/docs/tutorials/ed-6.ipynb +++ b/docs/docs/tutorials/ed-6.ipynb @@ -320,7 +320,7 @@ "metadata": {}, "outputs": [], "source": [ - "project = Project()" + "project = Project(name='hs_hrpt')" ] }, { @@ -830,6 +830,24 @@ "The HTML report is written automatically when the project is saved;\n", "enable `project.report.pdf` as well for a PDF version." ] + }, + { + "cell_type": "markdown", + "id": "77", + "metadata": {}, + "source": [ + "## 💾 Save Project" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "78", + "metadata": {}, + "outputs": [], + "source": [ + "project.save_as(dir_path='projects/ed_6_hs_hrpt')" + ] } ], "metadata": { diff --git a/docs/docs/tutorials/ed-6.py b/docs/docs/tutorials/ed-6.py index f2968b774..50a3ab363 100644 --- a/docs/docs/tutorials/ed-6.py +++ b/docs/docs/tutorials/ed-6.py @@ -150,7 +150,7 @@ # ### Create Project # %% -project = Project() +project = Project(name='hs_hrpt') # %% [markdown] # ### Add Structure @@ -344,3 +344,9 @@ # # The HTML report is written automatically when the project is saved; # enable `project.report.pdf` as well for a PDF version. + +# %% [markdown] +# ## 💾 Save Project + +# %% +project.save_as(dir_path='projects/ed_6_hs_hrpt') diff --git a/docs/docs/tutorials/ed-7.ipynb b/docs/docs/tutorials/ed-7.ipynb index e0902a8e7..5f5ae0b00 100644 --- a/docs/docs/tutorials/ed-7.ipynb +++ b/docs/docs/tutorials/ed-7.ipynb @@ -286,7 +286,7 @@ "metadata": {}, "outputs": [], "source": [ - "project = Project()" + "project = Project(name='si_sepd')" ] }, { @@ -926,6 +926,24 @@ "source": [ "project.display.pattern(expt_name='sepd', x='d_spacing')" ] + }, + { + "cell_type": "markdown", + "id": "91", + "metadata": {}, + "source": [ + "## 💾 Save Project" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92", + "metadata": {}, + "outputs": [], + "source": [ + "project.save_as(dir_path='projects/ed_7_si_sepd')" + ] } ], "metadata": { diff --git a/docs/docs/tutorials/ed-7.py b/docs/docs/tutorials/ed-7.py index a8d568805..09e51da4f 100644 --- a/docs/docs/tutorials/ed-7.py +++ b/docs/docs/tutorials/ed-7.py @@ -117,7 +117,7 @@ # ### Create Project # %% -project = Project() +project = Project(name='si_sepd') # %% [markdown] # ### Add Structure @@ -356,3 +356,9 @@ # %% project.display.pattern(expt_name='sepd', x='d_spacing') + +# %% [markdown] +# ## 💾 Save Project + +# %% +project.save_as(dir_path='projects/ed_7_si_sepd') diff --git a/docs/docs/tutorials/ed-8.ipynb b/docs/docs/tutorials/ed-8.ipynb index 7e02e5770..097ac6f57 100644 --- a/docs/docs/tutorials/ed-8.ipynb +++ b/docs/docs/tutorials/ed-8.ipynb @@ -498,7 +498,7 @@ "metadata": {}, "outputs": [], "source": [ - "project = Project()" + "project = Project(name='ncaf_wish')" ] }, { @@ -713,6 +713,24 @@ "The HTML report is written automatically when the project is saved;\n", "enable `project.report.pdf` as well for a PDF version." ] + }, + { + "cell_type": "markdown", + "id": "55", + "metadata": {}, + "source": [ + "## 💾 Save Project" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "56", + "metadata": {}, + "outputs": [], + "source": [ + "project.save_as(dir_path='projects/ed_8_ncaf_wish')" + ] } ], "metadata": { diff --git a/docs/docs/tutorials/ed-8.py b/docs/docs/tutorials/ed-8.py index d875c3998..94c0a89d5 100644 --- a/docs/docs/tutorials/ed-8.py +++ b/docs/docs/tutorials/ed-8.py @@ -268,7 +268,7 @@ # ### Create Project # %% -project = Project() +project = Project(name='ncaf_wish') # %% [markdown] # ### Add Structure @@ -360,3 +360,9 @@ # # The HTML report is written automatically when the project is saved; # enable `project.report.pdf` as well for a PDF version. + +# %% [markdown] +# ## 💾 Save Project + +# %% +project.save_as(dir_path='projects/ed_8_ncaf_wish') diff --git a/docs/docs/tutorials/ed-9.ipynb b/docs/docs/tutorials/ed-9.ipynb index 8d1ecdfee..613268b88 100644 --- a/docs/docs/tutorials/ed-9.ipynb +++ b/docs/docs/tutorials/ed-9.ipynb @@ -429,7 +429,7 @@ "metadata": {}, "outputs": [], "source": [ - "project = Project()" + "project = Project(name='lbco_si_mcstas')" ] }, { @@ -523,7 +523,7 @@ "metadata": {}, "outputs": [], "source": [ - "project.display.pattern(expt_name='mcstas', include='measured')" + "project.display.pattern(expt_name='mcstas')" ] }, { @@ -578,7 +578,7 @@ "metadata": {}, "outputs": [], "source": [ - "project.display.pattern(expt_name='mcstas', include=('measured', 'excluded'))" + "project.display.pattern(expt_name='mcstas')" ] }, { @@ -695,6 +695,24 @@ "source": [ "project.display.pattern(expt_name='mcstas')" ] + }, + { + "cell_type": "markdown", + "id": "63", + "metadata": {}, + "source": [ + "## 💾 Save Project" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "64", + "metadata": {}, + "outputs": [], + "source": [ + "project.save_as(dir_path='projects/ed_9_lbco_si_mcstas')" + ] } ], "metadata": { diff --git a/docs/docs/tutorials/ed-9.py b/docs/docs/tutorials/ed-9.py index 4fe451af2..a869b2583 100644 --- a/docs/docs/tutorials/ed-9.py +++ b/docs/docs/tutorials/ed-9.py @@ -195,7 +195,7 @@ # ### Create Project # %% -project = Project() +project = Project(name='lbco_si_mcstas') # %% [markdown] # ### Add Structures @@ -229,7 +229,7 @@ # Show measured data as loaded from the file. # %% -project.display.pattern(expt_name='mcstas', include='measured') +project.display.pattern(expt_name='mcstas') # %% [markdown] # Add excluded regions. @@ -248,7 +248,7 @@ # Show measured data after adding excluded regions. # %% -project.display.pattern(expt_name='mcstas', include=('measured', 'excluded')) +project.display.pattern(expt_name='mcstas') # %% [markdown] # Show experiment as CIF. @@ -304,3 +304,9 @@ # %% project.display.pattern(expt_name='mcstas') + +# %% [markdown] +# ## 💾 Save Project + +# %% +project.save_as(dir_path='projects/ed_9_lbco_si_mcstas') diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 8dba57ab1..b7b7786fd 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -161,7 +161,18 @@ plugins: show_root_heading: true show_root_full_path: false show_submodules: true - show_source: true + show_source: false + show_bases: false + # Uncomment when the project depends on `easyscience` and inherited + # EasyScience base-class members should be shown in the API docs. + # preload_modules: + # - easyscience + inherited_members: true + show_category_heading: true + merge_init_into_class: true + docstring_options: + ignore_init_summary: true + summary: true - search # Determines additional directories to watch when running mkdocs serve diff --git a/docs/overrides/main.html b/docs/overrides/main.html index 07acc6194..e0010f85f 100644 --- a/docs/overrides/main.html +++ b/docs/overrides/main.html @@ -37,20 +37,24 @@ {# Download link: relative to the current page #} {% set file_url = filename %} - {# Open in Colab (absolute GitHub URL; works anywhere) #} - - {% include ".icons/google-colab.svg" %} - - - {# Download: use a RELATIVE link to the file next to this page #} - - {% include ".icons/material/download.svg" %} - + {# Action buttons as a left-aligned row above the notebook title; see + .md-content__nb-actions in extra.css #} +
+ {# Open in Colab (absolute GitHub URL; works anywhere) #} + + {% include ".icons/google-colab.svg" %} + + + {# Download: use a RELATIVE link to the file next to this page #} + + {% include ".icons/material/download.svg" %} + +
{% endif %} {{ super() }} diff --git a/pixi.lock b/pixi.lock index 96e17870c..d4ab13b04 100644 --- a/pixi.lock +++ b/pixi.lock @@ -274,7 +274,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/89/1d/8eff589b45bb8190a9d12c49cfad0f176a5cbd1534908a6b5125e2886239/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/8e/5a/7fd1b784a87e96e0078f49a0a13a98b4c5f644ba5597a4a3b70a2ba3e613/py3dmol-2.5.5-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/ad/cba91b3bcf04073e4d1655a5c1710ef3f457f56f7d1b79dcc3d72f4dd912/plotly-6.7.0-py3-none-any.whl @@ -598,7 +597,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/88/29/744136411e785c4b0b744d5413e56555265939ab3a104c6a4b719dad33fd/mkdocs_get_deps-0.2.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/8e/5a/7fd1b784a87e96e0078f49a0a13a98b4c5f644ba5597a4a3b70a2ba3e613/py3dmol-2.5.5-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/ad/cba91b3bcf04073e4d1655a5c1710ef3f457f56f7d1b79dcc3d72f4dd912/plotly-6.7.0-py3-none-any.whl @@ -915,7 +913,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8a/bd/e11a108317485075e68af9d23039619b86b28130c3b50d227d42edece64b/greenlet-3.5.1-cp314-cp314-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/8e/5a/7fd1b784a87e96e0078f49a0a13a98b4c5f644ba5597a4a3b70a2ba3e613/py3dmol-2.5.5-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/ad/cba91b3bcf04073e4d1655a5c1710ef3f457f56f7d1b79dcc3d72f4dd912/plotly-6.7.0-py3-none-any.whl @@ -1259,7 +1256,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8a/2b/514fce8a7df81cf5bad7ff7865de7ac0c5776a38cc043475c4703eb7fe8b/sqlalchemy-2.0.50-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/8e/5a/7fd1b784a87e96e0078f49a0a13a98b4c5f644ba5597a4a3b70a2ba3e613/py3dmol-2.5.5-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/ad/cba91b3bcf04073e4d1655a5c1710ef3f457f56f7d1b79dcc3d72f4dd912/plotly-6.7.0-py3-none-any.whl @@ -1581,7 +1577,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/88/29/744136411e785c4b0b744d5413e56555265939ab3a104c6a4b719dad33fd/mkdocs_get_deps-0.2.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/8e/5a/7fd1b784a87e96e0078f49a0a13a98b4c5f644ba5597a4a3b70a2ba3e613/py3dmol-2.5.5-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/ad/cba91b3bcf04073e4d1655a5c1710ef3f457f56f7d1b79dcc3d72f4dd912/plotly-6.7.0-py3-none-any.whl @@ -1899,7 +1894,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8c/ec/d431eb7941fb55a31dd6ca3404d41fbb52d99172df2e7707754488390910/msgpack-1.1.2-cp312-cp312-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/8e/5a/7fd1b784a87e96e0078f49a0a13a98b4c5f644ba5597a4a3b70a2ba3e613/py3dmol-2.5.5-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/ad/cba91b3bcf04073e4d1655a5c1710ef3f457f56f7d1b79dcc3d72f4dd912/plotly-6.7.0-py3-none-any.whl @@ -2239,7 +2233,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/89/1d/8eff589b45bb8190a9d12c49cfad0f176a5cbd1534908a6b5125e2886239/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/8e/5a/7fd1b784a87e96e0078f49a0a13a98b4c5f644ba5597a4a3b70a2ba3e613/py3dmol-2.5.5-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/ad/cba91b3bcf04073e4d1655a5c1710ef3f457f56f7d1b79dcc3d72f4dd912/plotly-6.7.0-py3-none-any.whl @@ -2563,7 +2556,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/88/29/744136411e785c4b0b744d5413e56555265939ab3a104c6a4b719dad33fd/mkdocs_get_deps-0.2.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/8e/5a/7fd1b784a87e96e0078f49a0a13a98b4c5f644ba5597a4a3b70a2ba3e613/py3dmol-2.5.5-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/ad/cba91b3bcf04073e4d1655a5c1710ef3f457f56f7d1b79dcc3d72f4dd912/plotly-6.7.0-py3-none-any.whl @@ -2880,7 +2872,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8a/bd/e11a108317485075e68af9d23039619b86b28130c3b50d227d42edece64b/greenlet-3.5.1-cp314-cp314-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/8e/5a/7fd1b784a87e96e0078f49a0a13a98b4c5f644ba5597a4a3b70a2ba3e613/py3dmol-2.5.5-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/ad/cba91b3bcf04073e4d1655a5c1710ef3f457f56f7d1b79dcc3d72f4dd912/plotly-6.7.0-py3-none-any.whl @@ -8763,10 +8754,9 @@ packages: - lmfit - numpy - pandas - - pillow>=10.1 + - pillow - plotly - pooch - - py3dmol - rich - scipy - sympy diff --git a/pixi.toml b/pixi.toml index bb0f0b629..928c8bb22 100644 --- a/pixi.toml +++ b/pixi.toml @@ -106,8 +106,30 @@ user = { features = ['py-max', 'user'] } unit-tests = 'python -m pytest tests/unit/ --color=yes -v' functional-tests = 'python -m pytest tests/functional/ --color=yes -v' integration-tests = 'python -m pytest tests/integration/ --color=yes -n auto -v' -script-tests = { cmd = 'python -m pytest tools/test_scripts.py --color=yes -n auto -v', env = { EASYDIFFRACTION_ARTIFACT_ROOT = 'tmp/tutorials' } } -notebook-tests = { cmd = 'python -m pytest --nbmake docs/docs/tutorials/ --nbmake-timeout=1200 --color=yes -n auto -v', env = { EASYDIFFRACTION_ARTIFACT_ROOT = 'tmp/tutorials' } } + +# Remove previously saved tutorial output projects (projects/ed_*) so the +# tutorial-output checks cannot pass against a stale artifact from an earlier +# run. Downloaded input projects (projects/ed-NN) are preserved. +clean-tutorial-projects = { cmd = 'python tools/clean_tutorial_projects.py', env = { EASYDIFFRACTION_ARTIFACT_ROOT = 'tmp/tutorials' } } +script-tests = { cmd = 'python -m pytest tools/test_scripts.py --color=yes -n auto -v', depends-on = [ + 'clean-tutorial-projects', +], env = { EASYDIFFRACTION_ARTIFACT_ROOT = 'tmp/tutorials' } } +notebook-tests = { cmd = 'python -m pytest --nbmake docs/docs/tutorials/ --nbmake-timeout=1200 --color=yes -n auto -v', depends-on = [ + 'clean-tutorial-projects', +], env = { EASYDIFFRACTION_ARTIFACT_ROOT = 'tmp/tutorials' } } + +# Parse the analysis.cif of every saved tutorial project and assert its +# refined fit results against tests/tutorials/baseline.json. Run only after +# the tutorials have been executed (script-tests or notebook-tests), so the +# saved projects exist under tmp/tutorials/projects/. +tutorial-output-tests = { cmd = 'python -m pytest tests/tutorials/ --color=yes -v', env = { EASYDIFFRACTION_ARTIFACT_ROOT = 'tmp/tutorials' } } +# Run the tutorials and then verify their saved outputs in a single step. +script-tests-checked = { cmd = 'python -m pytest tests/tutorials/ --color=yes -v', depends-on = [ + 'script-tests', +], env = { EASYDIFFRACTION_ARTIFACT_ROOT = 'tmp/tutorials' } } +notebook-tests-checked = { cmd = 'python -m pytest tests/tutorials/ --color=yes -v', depends-on = [ + 'notebook-tests', +], env = { EASYDIFFRACTION_ARTIFACT_ROOT = 'tmp/tutorials' } } test = { depends-on = ['unit-tests', 'functional-tests'] } test-all = { depends-on = [ diff --git a/pyproject.toml b/pyproject.toml index c8d57b976..6e5b27250 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,8 +47,7 @@ dependencies = [ 'darkdetect', # Detecting dark mode (system-level) 'pandas', # Displaying tables in Jupyter notebooks 'plotly', # Interactive plots - 'py3Dmol', # Visualisation of crystal structures - 'pillow>=10.1', # Rendering structure figures (labels, legend) for reports + 'pillow', # Rendering structure figures (labels, legend) for reports ] [project.optional-dependencies] @@ -225,7 +224,9 @@ exclude = [ indent-width = 4 line-length = 99 # See also `max-line-length` in [tool.ruff.lint.pycodestyle] preview = true # Enable new rules that are not yet stable, like DOC - +builtins = [ + 'display', +] # Clutch-fix/patch to https://github.com/nbQA-dev/nbQA/issues/882 # Formatting options for Ruff [tool.ruff.format] @@ -358,6 +359,9 @@ ignore = [ 'D', 'W', ] +'docs/docs/tutorials/**' = [ + 'E402', # https://docs.astral.sh/ruff/rules/module-import-not-at-top-of-file/ +] # Specific options for certain rules diff --git a/src/easydiffraction/analysis/analysis.py b/src/easydiffraction/analysis/analysis.py index 41ffc5443..38afe0f39 100644 --- a/src/easydiffraction/analysis/analysis.py +++ b/src/easydiffraction/analysis/analysis.py @@ -51,9 +51,8 @@ from easydiffraction.core.category_owner import CategoryOwner from easydiffraction.core.guard import _apply_help_filter from easydiffraction.core.singleton import ConstraintsHandler -from easydiffraction.core.variable import NumericDescriptor +from easydiffraction.core.variable import GenericNumericDescriptor from easydiffraction.core.variable import Parameter -from easydiffraction.core.variable import StringDescriptor from easydiffraction.datablocks.experiment.item.base import intensity_category_for from easydiffraction.datablocks.experiment.item.enums import SampleFormEnum from easydiffraction.display.progress import make_display_handle @@ -75,8 +74,17 @@ from easydiffraction.analysis.categories.fit_result import FitResultBase from easydiffraction.analysis.categories.minimizer.base import MinimizerCategoryBase from easydiffraction.core.posterior import PosteriorParameterSummary - -_SUMMARY_HIDDEN_PARAMETER_CATEGORIES = frozenset({'pd_data', 'total_data', 'refln'}) + from easydiffraction.core.variable import GenericDescriptorBase + +# Categories hidden from the parameter summary tables: bulky measured +# data and derived, read-only tables that would only add noise. The +# space_group_Wyckoff table also carries unreadably long coords_xyz. +_SUMMARY_HIDDEN_PARAMETER_CATEGORIES = frozenset({ + 'pd_data', + 'total_data', + 'refln', + 'space_group_Wyckoff', +}) _POSTERIOR_SAMPLE_NDIM = 3 @@ -175,8 +183,8 @@ def _flush_structure_categories(self) -> None: @staticmethod def _summary_parameters( - params: list[StringDescriptor | NumericDescriptor | Parameter], - ) -> list[StringDescriptor | NumericDescriptor | Parameter]: + params: list[GenericDescriptorBase], + ) -> list[GenericDescriptorBase]: """Return parameters suitable for compact summary displays.""" return [ param @@ -328,25 +336,23 @@ def how_to_access_parameters(self) -> None: project_varname = project._varname for datablock_code, params in all_params.items(): for param in params: - if isinstance(param, (StringDescriptor, NumericDescriptor, Parameter)): - datablock_entry_name = param._identity.datablock_entry_name - category_code = param._identity.category_code - category_entry_name = param._identity.category_entry_name or '' - param_key = param.name - code_variable = ( - f'{project_varname}.{datablock_code}' - f"['{datablock_entry_name}'].{category_code}" - ) - if category_entry_name: - code_variable += f"['{category_entry_name}']" - code_variable += f'.{param_key}' - columns_data.append([ - datablock_entry_name, - category_code, - category_entry_name, - param_key, - code_variable, - ]) + datablock_entry_name = param._identity.datablock_entry_name + category_code = param._identity.category_code + category_entry_name = param._identity.category_entry_name or '' + param_key = param.name + code_variable = ( + f"{project_varname}.{datablock_code}['{datablock_entry_name}'].{category_code}" + ) + if category_entry_name: + code_variable += f"['{category_entry_name}']" + code_variable += f'.{param_key}' + columns_data.append([ + datablock_entry_name, + category_code, + category_entry_name, + param_key, + code_variable, + ]) console.paragraph('How to access parameters') render_table( @@ -393,19 +399,18 @@ def parameter_cif_uids(self) -> None: columns_data = [] for params in all_params.values(): for param in params: - if isinstance(param, (StringDescriptor, NumericDescriptor, Parameter)): - datablock_entry_name = param._identity.datablock_entry_name - category_code = param._identity.category_code - category_entry_name = param._identity.category_entry_name or '' - param_key = param.name - cif_uid = param._cif_handler.uid - columns_data.append([ - datablock_entry_name, - category_code, - category_entry_name, - param_key, - cif_uid, - ]) + datablock_entry_name = param._identity.datablock_entry_name + category_code = param._identity.category_code + category_entry_name = param._identity.category_entry_name or '' + param_key = param.name + cif_uid = param._cif_handler.uid + columns_data.append([ + datablock_entry_name, + category_code, + category_entry_name, + param_key, + cif_uid, + ]) console.paragraph('Show parameter CIF unique identifiers') render_table( @@ -1200,15 +1205,15 @@ def _has_software_provenance(self) -> bool: @staticmethod def _get_params_as_dataframe( - params: list[NumericDescriptor | Parameter], + params: list[GenericDescriptorBase], ) -> pd.DataFrame: """ Convert a list of parameters to a DataFrame. Parameters ---------- - params : list[NumericDescriptor | Parameter] - List of DescriptorFloat or Parameter objects. + params : list[GenericDescriptorBase] + List of descriptor or parameter objects. Returns ------- @@ -1217,19 +1222,17 @@ def _get_params_as_dataframe( """ records = [] for param in params: - record = {} # TODO: Merge into one. Add field if attr exists # TODO: f'{param.value!r}' for StringDescriptor? - if isinstance(param, (StringDescriptor, NumericDescriptor, Parameter)): - record = { - ('fittable', 'left'): False, - ('datablock', 'left'): param._identity.datablock_entry_name, - ('category', 'left'): param._identity.category_code, - ('entry', 'left'): param._identity.category_entry_name or '', - ('parameter', 'left'): param.name, - ('value', 'right'): param.value, - } - if isinstance(param, (NumericDescriptor, Parameter)): + record = { + ('fittable', 'left'): False, + ('datablock', 'left'): param._identity.datablock_entry_name, + ('category', 'left'): param._identity.category_code, + ('entry', 'left'): param._identity.category_entry_name or '', + ('parameter', 'left'): param.name, + ('value', 'right'): '' if param.value is None else param.value, + } + if isinstance(param, GenericNumericDescriptor): record |= { ('units', 'left'): _parameter_display_units(param), } diff --git a/src/easydiffraction/analysis/calculators/cryspy.py b/src/easydiffraction/analysis/calculators/cryspy.py index 16fcd818b..fdd4bda46 100644 --- a/src/easydiffraction/analysis/calculators/cryspy.py +++ b/src/easydiffraction/analysis/calculators/cryspy.py @@ -140,6 +140,11 @@ def calculate_structure_factors( cryspy_in_out_dict: dict[str, Any] = {} + # TODO: This is temporary solution to mark all structures as + # nuclear-only. Once magnetic structure is implemented, we + # would need to auto-detect it. + cryspy_dict[f'crystal_{structure.name}']['flag_only_nuclear'] = True + # Calculate the pattern using Cryspy # TODO: Redirect stderr to suppress Cryspy warnings. # This is a temporary solution to avoid cluttering the output. @@ -223,6 +228,11 @@ def calculate_pattern( cryspy_in_out_dict: dict[str, Any] = {} + # TODO: This is temporary solution to mark all structures as + # nuclear-only. Once magnetic structure is implemented, we + # would need to auto-detect it. + cryspy_dict[f'crystal_{structure.name}']['flag_only_nuclear'] = True + # Calculate the pattern using Cryspy # TODO: Redirect stderr to suppress Cryspy warnings. # This is a temporary solution to avoid cluttering the output. diff --git a/src/easydiffraction/core/variable.py b/src/easydiffraction/core/variable.py index 03dac6b1f..8bcffb872 100644 --- a/src/easydiffraction/core/variable.py +++ b/src/easydiffraction/core/variable.py @@ -329,8 +329,9 @@ def __str__(self) -> str: """Return the string representation including units.""" s: str = super().__str__() s = s[1:-1] # strip <> - if self.units != 'none': - s += f' {self.units}' + units = self.resolve_display_units('gui') + if units: + s += f' {units}' return f'<{s}>' @property @@ -412,8 +413,9 @@ def __str__(self) -> str: s = s[1:-1] # strip <> if self.uncertainty is not None: s += f' ± {self.uncertainty}' - if self.units != 'none': - s += f' {self.units}' + units = self.resolve_display_units('gui') + if units: + s += f' {units}' s += f' (free={self.free})' return f'<{s}>' diff --git a/src/easydiffraction/datablocks/experiment/categories/peak/tof_mixins.py b/src/easydiffraction/datablocks/experiment/categories/peak/tof_mixins.py index d540d6bb2..0ebd66b16 100644 --- a/src/easydiffraction/datablocks/experiment/categories/peak/tof_mixins.py +++ b/src/easydiffraction/datablocks/experiment/categories/peak/tof_mixins.py @@ -23,7 +23,12 @@ class TofGaussianBroadeningMixin: - """TOF Gaussian broadening parameters σ₀, σ₁, σ₂.""" + """ + TOF Gaussian broadening parameters σ₀, σ₁, σ₂. + + The constant term σ₀ defaults nonzero so every TOF profile has a + finite peak width out of the box; σ₁ and σ₂ default to 0. + """ def __init__(self) -> None: super().__init__() @@ -37,7 +42,7 @@ def __init__(self) -> None: latex_units=r'$\mu\mathrm{s}^2$', ), value_spec=AttributeSpec( - default=0.0, + default=7.0, validator=RangeValidator(), ), cif_handler=CifHandler( @@ -230,6 +235,9 @@ class TofBackToBackExponentialMixin: Rise parameters α₀, α₁ and decay parameters β₀, β₁ follow Von Dreele, Jorgensen & Windsor, J. Appl. Cryst. 15, 581 (1982). + + The rise α₁ and decay β₀ default nonzero so the profile is + normalisable and the peak is visible; refine per instrument. """ def __init__(self) -> None: @@ -244,7 +252,7 @@ def __init__(self) -> None: latex_units=r'$\mu\mathrm{s}$', ), value_spec=AttributeSpec( - default=0.01, + default=0.0, validator=RangeValidator(), ), cif_handler=CifHandler( @@ -261,7 +269,7 @@ def __init__(self) -> None: latex_units=r'$\mu\mathrm{s}/\mathrm{\AA}$', ), value_spec=AttributeSpec( - default=0.02, + default=0.2, validator=RangeValidator(), ), cif_handler=CifHandler( @@ -278,7 +286,7 @@ def __init__(self) -> None: latex_units=r'$\mu\mathrm{s}$', ), value_spec=AttributeSpec( - default=0.0, + default=0.04, validator=RangeValidator(), ), cif_handler=CifHandler( @@ -368,6 +376,9 @@ class TofDoubleExponentialMixin: Rise parameters α₁, α₂, decay parameters β₀₀, β₀₁, β₁₀ for two exponential regimes, and switching-function parameters r₀₁, r₀₂, r₀₃. + + α₁, β₀₀, β₁₀ and r₀₁ default nonzero so both regimes stay finite and + blended; an all-zero set produces NaN. Refine per instrument. """ def __init__(self) -> None: @@ -382,7 +393,7 @@ def __init__(self) -> None: latex_units=r'$\mu\mathrm{s}$', ), value_spec=AttributeSpec( - default=0.0, + default=0.25, validator=RangeValidator(), ), cif_handler=CifHandler( @@ -416,7 +427,7 @@ def __init__(self) -> None: latex_units=r'$\mu\mathrm{s}$', ), value_spec=AttributeSpec( - default=0.0, + default=4.0, validator=RangeValidator(), ), cif_handler=CifHandler( @@ -450,7 +461,7 @@ def __init__(self) -> None: latex_units=r'$\mu\mathrm{s}$', ), value_spec=AttributeSpec( - default=0.0, + default=2.0, validator=RangeValidator(), ), cif_handler=CifHandler( @@ -463,7 +474,7 @@ def __init__(self) -> None: description='Double-exp switching function r₀₁', units='none', value_spec=AttributeSpec( - default=0.0, + default=0.5, validator=RangeValidator(), ), cif_handler=CifHandler( diff --git a/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py b/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py index 3c6256567..0478cfe02 100644 --- a/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py +++ b/src/easydiffraction/datablocks/structure/categories/space_group_wyckoff/default.py @@ -125,6 +125,26 @@ def __init__(self) -> None: """Initialise an empty derived Wyckoff collection.""" super().__init__(item_type=SpaceGroupWyckoff) + @staticmethod + def _skip_cif_serialization() -> bool: + """ + Suppress all serialized output for this derived category. + + The Wyckoff table is rebuilt from the structure's space group on + every update, so it is code-only: reachable via + ``structure.space_group_wyckoff`` but never written to project + CIF, the IUCr export, or HTML/TeX reports. Every serialization + path that consults this hook (``category_collection_to_cif`` and + the report data context) honours the suppression, so no + owner-level category filtering is required. + + Returns + ------- + bool + Always ``True``. + """ + return True + @override def add(self, item: object) -> None: """ diff --git a/src/easydiffraction/datablocks/structure/item/base.py b/src/easydiffraction/datablocks/structure/item/base.py index 704a98c9c..addc8552d 100644 --- a/src/easydiffraction/datablocks/structure/item/base.py +++ b/src/easydiffraction/datablocks/structure/item/base.py @@ -253,16 +253,6 @@ def _update_categories( self._need_categories_update = False - def _serializable_categories(self) -> list: - """ - Project-CIF categories (excludes the derived Wyckoff table). - """ - return [ - category - for category in self.categories - if not isinstance(category, SpaceGroupWyckoffCollection) - ] - # ------------------------------------------------------------------ # Public methods # ------------------------------------------------------------------ diff --git a/src/easydiffraction/display/plotters/base.py b/src/easydiffraction/display/plotters/base.py index 5a02c37b8..5e2d38eca 100644 --- a/src/easydiffraction/display/plotters/base.py +++ b/src/easydiffraction/display/plotters/base.py @@ -16,6 +16,9 @@ from easydiffraction.datablocks.experiment.item.enums import ScatteringTypeEnum DEFAULT_HEIGHT = 25 +# Residual-to-main row height ratio shared by the composite figure and +# the single-panel figure so both derive the same main-panel height. +DEFAULT_RESIDUAL_HEIGHT_FRACTION = 0.25 DEFAULT_MIN = -np.inf DEFAULT_MAX = np.inf diff --git a/src/easydiffraction/display/plotters/plotly.py b/src/easydiffraction/display/plotters/plotly.py index 8bfed31a4..a20a8dd82 100644 --- a/src/easydiffraction/display/plotters/plotly.py +++ b/src/easydiffraction/display/plotters/plotly.py @@ -30,6 +30,7 @@ HTML = None from easydiffraction.display.plotters.base import DEFAULT_HEIGHT +from easydiffraction.display.plotters.base import DEFAULT_RESIDUAL_HEIGHT_FRACTION from easydiffraction.display.plotters.base import SERIES_CONFIG from easydiffraction.display.plotters.base import BraggTickSet from easydiffraction.display.plotters.base import PlotterBase @@ -1998,6 +1999,7 @@ def _get_layout( *, axis_range: tuple[float, float] | None = None, axis_dtick: float | None = None, + height: int | None = None, ) -> object: """ Create a Plotly layout configuration. @@ -2015,6 +2017,8 @@ def _get_layout( axis_dtick : float | None, default=None When given, the same tick step applied to both axes, so the x and y ticks match. + height : int | None, default=None + Explicit figure height in pixels; ``None`` auto-sizes. Returns ------- @@ -2076,6 +2080,7 @@ def _get_layout( 'yanchor': 'top', 'y': 0.99, }, + height=height, xaxis=xaxis, yaxis=yaxis, shapes=shapes, @@ -2114,7 +2119,8 @@ def plot_powder( excluded_ranges : tuple[tuple[float, float], ...], default=() Excluded x-ranges to shade on the figure. """ - # Intentionally unused; accepted for API compatibility + # The passed height is an ASCII row count; the Plotly single + # panel is sized to the composite main row below instead. del height data = [] @@ -2123,12 +2129,22 @@ def plot_powder( trace = self._get_powder_trace(x, y, label) data.append(trace) + # Share the composite's sizing and range primitives so a single + # panel is its main row by construction: the same explicit + # height (otherwise the docs skeleton falls back to the full + # three-panel height) and the same tight x-range with no + # autoscale padding. ``_get_layout`` already uses the composite + # margins, so the drawable area matches pixel-for-pixel. layout = self._get_layout( title, axes_labels, + height=self._single_main_panel_height_pixels(DEFAULT_RESIDUAL_HEIGHT_FRACTION), ) fig = self._get_figure(data, layout) + x_min, x_max = self._composite_x_range(np.asarray(x)) + if x_min is not None and x_max is not None: + fig.update_xaxes(range=[x_min, x_max]) self._add_excluded_region_vrects(fig=fig, excluded_ranges=excluded_ranges) self._show_figure(fig) @@ -2978,7 +2994,10 @@ def plot_scatter( height: int | None = None, ) -> None: """Render a scatter plot with error bars via Plotly.""" - _ = height # not used by Plotly backend + # The passed height is an ASCII row count; the Plotly scatter + # panel is sized to the composite main row instead, so it + # matches the pattern plot's top panel. + del height trace = go.Scatter( x=x, @@ -3005,6 +3024,7 @@ def plot_scatter( layout = self._get_layout( title, axes_labels, + height=self._single_main_panel_height_pixels(DEFAULT_RESIDUAL_HEIGHT_FRACTION), ) fig = self._get_figure(trace, layout) diff --git a/src/easydiffraction/display/plotting.py b/src/easydiffraction/display/plotting.py index 90b0c8aca..2688711e9 100644 --- a/src/easydiffraction/display/plotting.py +++ b/src/easydiffraction/display/plotting.py @@ -30,6 +30,7 @@ from easydiffraction.display.plotters.base import DEFAULT_HEIGHT from easydiffraction.display.plotters.base import DEFAULT_MAX from easydiffraction.display.plotters.base import DEFAULT_MIN +from easydiffraction.display.plotters.base import DEFAULT_RESIDUAL_HEIGHT_FRACTION from easydiffraction.display.plotters.base import DEFAULT_X_AXIS from easydiffraction.display.plotters.base import BraggTickSet from easydiffraction.display.plotters.base import PowderMeasVsCalcSpec @@ -82,7 +83,6 @@ class PosteriorPairPlotStyleEnum(StrEnum): DEFAULT_CORRELATION_THRESHOLD: float | None = None DEFAULT_CORRELATION_MAX_PARAMETERS = 6 EXPECTED_COVAR_NDIM = 2 -DEFAULT_RESIDUAL_HEIGHT_FRACTION = 0.25 DEFAULT_BRAGG_PEAKS_HEIGHT_FRACTION = 0.10 DEFAULT_RESID_HEIGHT = DEFAULT_RESIDUAL_HEIGHT_FRACTION DEFAULT_BRAGG_ROW = DEFAULT_BRAGG_PEAKS_HEIGHT_FRACTION @@ -142,7 +142,7 @@ class PosteriorPairPlotStyleEnum(StrEnum): [0.82, 'rgba(215, 48, 39, 0.98)'], [1.0, 'rgba(215, 48, 39, 0.98)'], ] -POSTERIOR_PAIR_SCATTER_MAX_POINTS = 1500 +POSTERIOR_PAIR_SCATTER_MAX_POINTS = 750 # keep embedded pair scatter small POSTERIOR_PAIR_MAX_DENSITY_SAMPLES = 4000 POSTERIOR_PAIR_MIN_DENSITY_SAMPLES = 800 POSTERIOR_PAIR_TARGET_DENSITY_SAMPLE_BUDGET = 24000 @@ -177,7 +177,6 @@ class PosteriorPairPlotStyleEnum(StrEnum): CORRELATION_CELL_LABEL_CHAR_COUNT = 16 CORRELATION_LABEL_CHAR_WIDTH_FACTOR = 0.6 POSTERIOR_PAIR_SAMPLE_MARKER_SIZE = 6 -POSTERIOR_PAIR_SAMPLE_HOVER_MARKER_SIZE = 6 @dataclass(frozen=True) @@ -2096,7 +2095,7 @@ def _add_posterior_pair_off_diagonal( name='Posterior samples', legendgroup='posterior-samples', showlegend=legend_state.show_scatter, - hoverinfo='skip', + hovertemplate=sample_hovertemplate, zorder=0, ), row=row, @@ -2112,22 +2111,6 @@ def _add_posterior_pair_off_diagonal( fig.add_trace(contour_traces[0], row=row, col=col) fig.add_trace(contour_traces[1], row=row, col=col) legend_state.show_contour = False - fig.add_trace( - go.Scatter( - x=x_scatter_values, - y=y_scatter_values, - mode='markers', - marker={ - 'color': 'rgba(0, 0, 0, 0)', - 'size': POSTERIOR_PAIR_SAMPLE_HOVER_MARKER_SIZE, - }, - showlegend=False, - hovertemplate=sample_hovertemplate, - zorder=3, - ), - row=row, - col=col, - ) @staticmethod def _configure_posterior_pair_panel_axes( @@ -3043,29 +3026,46 @@ def _add_posterior_distribution_histogram( histogram_bin_edges: np.ndarray | None, ) -> None: """Add the histogram trace for a posterior distribution plot.""" - histogram_kwargs: dict[str, object] = {} - if ( - histogram_bin_edges is not None - and histogram_bin_edges.size >= MIN_POSTERIOR_SAMPLE_COUNT - ): - histogram_kwargs['xbins'] = { - 'start': float(histogram_bin_edges[0]), - 'end': float(histogram_bin_edges[-1]), - 'size': float(histogram_bin_edges[1] - histogram_bin_edges[0]), - } + marker = { + 'color': POSTERIOR_HISTOGRAM_FILL_COLOR, + 'line': {'color': POSTERIOR_HISTOGRAM_LINE_COLOR, 'width': 1}, + } + densities = Plotter._posterior_distribution_histogram_density( + values, + histogram_bin_edges, + ) + if densities is None or histogram_bin_edges is None: + # Degenerate sample (no usable bins): let Plotly bin the few + # raw values client-side; the embedded payload stays tiny. + fig.add_trace( + go.Histogram( + x=values, + histnorm='probability density', + marker=marker, + opacity=0.82, + name='Posterior histogram', + hovertemplate='sample=%{x:.4f}
density: %{y:.2f}', + ) + ) + return + # Pre-bin server-side and emit a Bar trace so only the per-bin + # densities ride in the page, not every raw posterior sample. + # ``go.Histogram(x=values)`` serializes the full sample array + # (hundreds of thousands of values per parameter), bloating the + # docs page and stalling the "Loading plot…" skeleton paint. + edges = np.asarray(histogram_bin_edges, dtype=float) + bin_centers = (edges[:-1] + edges[1:]) / 2.0 + bin_widths = np.diff(edges) fig.add_trace( - go.Histogram( - x=values, - histnorm='probability density', - marker={ - 'color': POSTERIOR_HISTOGRAM_FILL_COLOR, - 'line': {'color': POSTERIOR_HISTOGRAM_LINE_COLOR, 'width': 1}, - }, + go.Bar( + x=bin_centers, + y=densities, + width=bin_widths, + marker=marker, opacity=0.82, name='Posterior histogram', hovertemplate='sample=%{x:.4f}
density: %{y:.2f}', - **histogram_kwargs, ) ) diff --git a/src/easydiffraction/display/structure/templates/structure.html.j2 b/src/easydiffraction/display/structure/templates/structure.html.j2 index 51e8b9aa5..752cb018f 100644 --- a/src/easydiffraction/display/structure/templates/structure.html.j2 +++ b/src/easydiffraction/display/structure/templates/structure.html.j2 @@ -1,9 +1,9 @@ -
-
Loading 3D view…
+
Loading plot…
diff --git a/src/easydiffraction/display/tablers/pandas.py b/src/easydiffraction/display/tablers/pandas.py index 25a013902..38ff2590e 100644 --- a/src/easydiffraction/display/tablers/pandas.py +++ b/src/easydiffraction/display/tablers/pandas.py @@ -1,9 +1,14 @@ # SPDX-FileCopyrightText: 2025 EasyScience contributors # SPDX-License-Identifier: BSD-3-Clause -"""Pandas-based table renderer for notebooks using DataFrame Styler.""" +""" +Pandas-input table renderer emitting inline-styled HTML for notebooks. +""" from __future__ import annotations +import html +import re + try: from IPython.display import HTML from IPython.display import display @@ -11,225 +16,148 @@ HTML = None display = None -import re - from easydiffraction.display.tablers.base import TableBackendBase -from easydiffraction.display.theme import DARK_AXIS_FRAME_COLOR -from easydiffraction.display.theme import LIGHT_AXIS_FRAME_COLOR -from easydiffraction.display.theme import TABLE_AXIS_FRAME_CSS_VAR from easydiffraction.utils.environment import can_use_ipython_display from easydiffraction.utils.logging import log +# Rich-style inline colour markup, e.g. ``[red]text[/red]``. _RICH_COLOR_RE = re.compile(r'\[(\w+)\](.*?)\[/\1\]') -PANDAS_TABLE_THEME_CLASS = 'ed-themed-table' -PANDAS_AXIS_FRAME_COLOR = f'var({TABLE_AXIS_FRAME_CSS_VAR}, {LIGHT_AXIS_FRAME_COLOR})' + +# Theme-neutral translucent greys. Both read correctly on light and dark +# backgrounds, so the table needs no theme-sync script -- which matters +# because JupyterLab strips ``