Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -276,13 +276,22 @@ The source tutorial notebooks live in [`docs/tutorials`](docs/tutorials). They
can be opened directly in Colab. To make a GitHub-readable preview copy, see
[`docs/github-preview.md`](docs/github-preview.md).

## Citing quantem.widget

If the quantEM interactive framework—including `quantem.widget`, GPU-accelerated
I/O, analysis, or reconstruction workflows on MPS or CUDA—contributed to your
research, please consider citing Lee et al., *Interactive Framework for
Real-Time 4DSTEM Analysis and Reconstruction*, *Microscopy and Microanalysis*
32 (Supplement 1), ozag053.941 (2026),
https://doi.org/10.1093/mam/ozag053.941.

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md) for setup, checks, widget export
expectations, agent signoff, and release-candidate guidance.

This repository follows the
[scikit-package](https://scikit-package.github.io/scikit-package/) standards
Pull request workflows follow the
[scikit-package](https://scikit-package.github.io/scikit-package/) procedures
for reproducible scientific software: issue-first development (a PR closes a
GitHub issue that states the problem), one small themed PR per issue,
Conventional Commit-style messages, NumPy-style docstrings, self-reviewed
Expand All @@ -293,11 +302,7 @@ we squash-merge, so branch tidiness costs nothing). Human contributors
and coding agents/LLMs alike should apply these standards when writing code,
commits, issues, and PRs. This README is the canonical policy source; the
[pull request template](.github/PULL_REQUEST_TEMPLATE.md) turns the policy
into an operational checklist. Reference: S. Lee, C. Myers, A. Yang,
T. Zhang, Y. Xiao, and
S. J. L. Billinge, *Digital Discovery*, 2026,
[doi:10.1039/d6dd00121a](https://doi.org/10.1039/d6dd00121a). For Git/GitHub
tutorials and workflow onboarding, see
into an operational checklist. For Git/GitHub tutorials and workflow onboarding, see
[ophusgroup/dev](https://github.com/ophusgroup/dev).

### Policy map
Expand Down
9 changes: 9 additions & 0 deletions docs/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,15 @@ full-resolution data would be too large for public sharing.

See [Installation](install) to get started.

## Citing quantem.widget

If the quantEM interactive framework—including `quantem.widget`, GPU-accelerated
I/O, analysis, or reconstruction workflows on MPS or CUDA—contributed to your
research, please consider citing Lee et al., *Interactive Framework for
Real-Time 4DSTEM Analysis and Reconstruction*, *Microscopy and Microanalysis*
32 (Supplement 1), ozag053.941 (2026),
https://doi.org/10.1093/mam/ozag053.941.

## Getting help

- **Questions or bugs:** open an issue at
Expand Down
14 changes: 13 additions & 1 deletion js/show3d/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3129,7 +3129,19 @@ function Show3D() {
u8: Uint8Array;
} | null>(null);
const [sidecarRamReady, setSidecarRamReady] = React.useState(false);
const [offlineStackFetchStatus, setOfflineStackFetchStatus] = React.useState<string>("");
const [offlineStackFetchStatus, setOfflineStackFetchStatusVisible] = React.useState<string>("");
// A display cache is an internal playback optimization, not report UI. In
// particular, updating a visible cache counter during its build causes extra
// React work precisely while the browser is preparing a smooth scrub/play
// path. Keep genuine sidecar-load messages and errors, but make all cache
// work silent and clear any preceding load message as it begins.
const setOfflineStackFetchStatus = React.useCallback((status: string) => {
if (/(?:display|playback) cache/i.test(status)) {
setOfflineStackFetchStatusVisible("");
return;
}
setOfflineStackFetchStatusVisible(status);
}, []);
const sidecarMode = Boolean(
(offlineStackUrl || "").trim()
&& !(offlineStackTrait && offlineStackTrait.byteLength > 0),
Expand Down
2 changes: 2 additions & 0 deletions src/quantem/widget/show3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -4167,6 +4167,8 @@ def state_dict(self) -> dict:
"debug": self.debug,
"show_controls": self.show_controls,
"controls_collapsed": self.controls_collapsed,
"hideable": self.hideable,
"hidden_indices": list(self.hidden_indices),
"max_cols": self.max_cols,
"panel_gap": self.panel_gap,
"inter_panel_gap_px": int(self.inter_panel_gap_px),
Expand Down
16 changes: 16 additions & 0 deletions tests/test_show3d_pages.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,22 @@ def test_show3d_paged_state_and_html_roundtrip(tmp_path: pathlib.Path) -> None:
assert "data-show3d-tool-controls" in html


def test_show3d_html_export_preserves_frame_hide_actions(tmp_path: pathlib.Path) -> None:
"""A portable report keeps the scrubber's hide-frame affordance."""
widget = Show3D(
np.zeros((4, 8, 8), dtype=np.float32),
hideable=True,
verbose=False,
)
widget.hide(2)

out = widget.export_html(tmp_path / "hideable.html", encoding="uint8")
html = out.read_text().replace(" ", "").replace("\n", "")

assert '"hideable":true' in html
assert '"hidden_indices":[2]' in html


def test_show3d_paged_to_show2d_uses_current_visible_page() -> None:
widget = Show3D(
_paged_stack(),
Expand Down