|
| 1 | +# ADR: Unified Pattern View |
| 2 | + |
| 3 | +## Status |
| 4 | + |
| 5 | +Accepted and implemented. |
| 6 | + |
| 7 | +## Date |
| 8 | + |
| 9 | +2026-06-04 |
| 10 | + |
| 11 | +## Context |
| 12 | + |
| 13 | +`project.display.pattern()` was originally specified by the |
| 14 | +[Display UX Facade](display-ux.md) ADR with an `include=` argument that |
| 15 | +assembled a view from named layers (`measured`, `calculated`, |
| 16 | +`background`, `residual`, `bragg`, `excluded`, `uncertainty`), plus a |
| 17 | +`show_pattern_options()` discovery table. `include='auto'` already chose |
| 18 | +the most informative combination from project state. |
| 19 | + |
| 20 | +In practice this surfaced several problems: |
| 21 | + |
| 22 | +- The single-panel path (`plot_meas`/`plot_calc` → `plot_powder`) and |
| 23 | + the composite path (`build_powder_meas_vs_calc_figure`) computed |
| 24 | + figure height and x-range independently, so they drifted. A |
| 25 | + measured-only view rendered at the full three-panel height in the lazy |
| 26 | + docs runtime — the |
| 27 | + [Plotting & Docs Performance](plotting-docs-performance.md) skeleton |
| 28 | + fell back to `DEFAULT_HEIGHT * PLOTLY_HEIGHT_PER_UNIT` — and gained |
| 29 | + stray left/right autoscale padding the composite did not have. |
| 30 | +- `'excluded'` was an opt-in overlay, but excluded regions are a |
| 31 | + property of the experiment, not a viewing choice; `include='measured'` |
| 32 | + and `include=('measured', 'excluded')` produced different plots of the |
| 33 | + same data, which read as redundant. |
| 34 | +- For a scientist audience, choosing layers is friction. The project |
| 35 | + state already determines what is meaningful to show, which is exactly |
| 36 | + what `include='auto'` computed. |
| 37 | + |
| 38 | +## Decision |
| 39 | + |
| 40 | +`pattern(expt_name, x_min=None, x_max=None, *, x=None)` always renders |
| 41 | +every kind of data the project state supports — the former |
| 42 | +`include='auto'` behaviour is now the only behaviour. The `include` |
| 43 | +parameter, the `show_pattern_options()` method, and the option-status |
| 44 | +discovery table are removed. Strict-subset views (for example |
| 45 | +measured-only once a calculation exists) are intentionally no longer |
| 46 | +offered; zooming (`x_min`/`x_max`) and the x-axis variable (`x`) remain. |
| 47 | + |
| 48 | +Excluded regions are always shaded when defined on the experiment, |
| 49 | +skipped only when a custom `x` axis variable is selected, because the |
| 50 | +overlay cannot be mapped onto an arbitrary axis. |
| 51 | + |
| 52 | +Single-panel and composite charts share one figure-sizing and x-range |
| 53 | +core. `plot_powder` builds its layout with the same |
| 54 | +`_single_main_panel_height_pixels(...)` height and tight |
| 55 | +`_composite_x_range(...)` as the composite main row, and `_get_layout` |
| 56 | +already applies the composite margins. A one-row chart is therefore the |
| 57 | +top row of the multi-row chart pixel for pixel, by construction, so the |
| 58 | +two paths cannot diverge again. |
| 59 | + |
| 60 | +This supersedes the `include`-based pattern design in the |
| 61 | +[Display UX Facade](display-ux.md) ADR. The remainder of that ADR — the |
| 62 | +facade grouping, renderer categories, and naming rules — still stands. |
| 63 | + |
| 64 | +## Consequences |
| 65 | + |
| 66 | +- `pattern(expt_name=...)` is the whole pattern API surface; tutorials, |
| 67 | + docs, and tests no longer pass `include=`. |
| 68 | +- The project is in beta, so this replaces the previous API with no |
| 69 | + compatibility shim; tutorials and tests are updated to the current |
| 70 | + API. |
| 71 | +- Sizing and range differences between one- and three-panel views are |
| 72 | + prevented structurally, not patched per call. |
| 73 | +- `structure(include=...)` and `show_structure_options()` are |
| 74 | + unaffected: choosing which 3D features to draw remains a genuine |
| 75 | + viewing choice (see |
| 76 | + [Crystal Structure 3D Visualization](crysview-structure-visualization.md)). |
| 77 | + |
| 78 | +## Alternatives Considered |
| 79 | + |
| 80 | +Keeping `include` as the view-selection vocabulary (the original |
| 81 | +design). `include` had been chosen over `layers`, `components`, |
| 82 | +`content`, `view`, `series`, and boolean flags because it read as user |
| 83 | +intent and fit residual rows and Bragg ticks. It is removed now because |
| 84 | +the only combination users reached for in practice was the automatic |
| 85 | +"show everything available" view; the subset combinations added API |
| 86 | +surface and a discovery table without a matching workflow, and the |
| 87 | +parallel single-panel rendering path was the source of the sizing and |
| 88 | +range divergence. |
| 89 | + |
| 90 | +Keeping `'excluded'` as an opt-in overlay, or as a redundant no-op |
| 91 | +token, was rejected: excluded regions belong to the experiment, so |
| 92 | +shading them is automatic whenever they are present. |
0 commit comments