{"id":50909054,"url":"https://github.com/hyperspy/hyperspy_gui_anywidget","last_synced_at":"2026-06-16T08:02:19.145Z","repository":{"id":360184359,"uuid":"1249038364","full_name":"hyperspy/hyperspy_gui_anywidget","owner":"hyperspy","description":"anywidget GUI elements for the HyperSpy framework","archived":false,"fork":false,"pushed_at":"2026-06-08T18:34:29.000Z","size":190,"stargazers_count":0,"open_issues_count":7,"forks_count":2,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-06-08T20:17:03.513Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://hyperspy-gui-anywidget.readthedocs.io/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hyperspy.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.rst","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":".github/AGENTS.md","dco":null,"cla":null}},"created_at":"2026-05-25T09:37:11.000Z","updated_at":"2026-06-08T18:34:34.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/hyperspy/hyperspy_gui_anywidget","commit_stats":null,"previous_names":["hyperspy/hyperspy_gui_anywidget"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/hyperspy/hyperspy_gui_anywidget","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyperspy%2Fhyperspy_gui_anywidget","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyperspy%2Fhyperspy_gui_anywidget/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyperspy%2Fhyperspy_gui_anywidget/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyperspy%2Fhyperspy_gui_anywidget/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hyperspy","download_url":"https://codeload.github.com/hyperspy/hyperspy_gui_anywidget/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyperspy%2Fhyperspy_gui_anywidget/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34396430,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-16T02:00:06.860Z","response_time":126,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-16T08:02:17.940Z","updated_at":"2026-06-16T08:02:19.136Z","avatar_url":"https://github.com/hyperspy.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# hyperspy_gui_anywidget\n\nanywidget GUI elements for the HyperSpy framework.\n\nThis package provides GUI widgets using [anywidget](https://anywidget.dev/) for the [HyperSpy](https://hyperspy.org/) scientific data analysis library. It is explicitly supported in Jupyter Notebook / JupyterLab and in [Marimo](https://marimo.io/) without any frontend build step or bundler.\n\n## Installation\n\n### With pip\n\n```bash\npip install hyperspy_gui_anywidget\n```\n\n### With optional test dependencies\n\n```bash\npip install \"hyperspy_gui_anywidget[tests]\"\n```\n\n### Development install\n\n```bash\ngit clone https://github.com/hyperspy/hyperspy_gui_anywidget.git\ncd hyperspy_gui_anywidget\npip install -e \".[dev,tests,doc]\"\n```\n\n## Usage\n\n### Jupyter Notebook / JupyterLab\n\nFor modern Jupyter environments, installing `hyperspy_gui_anywidget` is enough. You do not\nneed to manually enable an anywidget extension in current JupyterLab or Notebook releases,\nbecause `anywidget`/`ipywidgets` handle the widget integration.\n\nIn normal use, the default `display=True` behavior is what you want: calling a GUI method\ndisplays the widget inline immediately.\n\nHyperSpy can then use the anywidget toolkit directly:\n\n```python\nimport hyperspy.api as hs\n\n# Open preferences GUI\nhs.preferences.gui(toolkit=\"anywidget\")\n```\n\nWidgets are displayed inline using `IPython.display.display()`:\n\n```python\nroi = hs.roi.SpanROI(left=0, right=10)\nroi.gui(toolkit=\"anywidget\")\n```\n\n### Marimo\n\nMarimo follows the same default behavior: with `display=True` (the default), the widget is\ndisplayed inline for you.\n\nIf you need the raw widget object for manual embedding with `mo.ui.anywidget()`, pass\n`display=False` and use the returned dictionary instead:\n\n```python\nimport marimo as mo\nimport hyperspy.api as hs\n\nroi = hs.roi.SpanROI(left=0, right=10)\nres = roi.gui(toolkit=\"anywidget\", display=False)\nwidget = res[\"anywidget\"][\"widget\"]\nmo.ui.anywidget(widget)\n```\n\nThe `add_display_arg` decorator detects Marimo at runtime (via `sys.modules`) and, when\nneeded, flattens `VBox`/`HBox` containers before displaying them. Use `display=False` only\nwhen you need the raw `{\"widget\": ..., \"wdict\": ...}` dictionary for embedding,\ninspection, or tests.\n\n### Supported environments\n\nThis project is explicitly tested and documented for:\n\n- Jupyter Notebook / JupyterLab\n- Marimo\n\nBecause the leaf widgets are implemented with `anywidget`, they may also work in other\nfrontends that support Jupyter widgets / anywidget. However, this repository does not\nexplicitly test or guarantee behavior in environments such as VS Code notebooks, Google\nColab, JupyterLite, or Voila.\n\n## Architecture\n\nThis package is built on a few key design decisions:\n\n1. **AnyWidget subclasses with inline `_esm` JavaScript** — Every widget is a Python class extending `anywidget.AnyWidget` with an inline JavaScript string. There is no npm, webpack, or build step. The JS renders standard HTML elements (`\u003cinput\u003e`, `\u003cselect\u003e`, `\u003cbutton\u003e`) and syncs state via traitlets.\n\n2. **`link_traits` for bidirectional sync** — Enthought Traits (used by HyperSpy) and traitlets (used by anywidget) are bridged with `link_traits.link()`. Changes in the GUI propagate to the HyperSpy object and vice versa.\n\n3. **ContainerWidget bridges Jupyter and Marimo** — On the Jupyter path, `ContainerWidget` deliberately uses real `ipywidgets` containers such as `VBox`, `HBox`, `Tab`, and `Accordion` so the GUI integrates with the native widget stack. On the Marimo path, those layouts are flattened into `FlatContainer` configs rendered by anywidget.\n\n4. **Environment-aware display** — The `@add_display_arg` decorator handles the difference between Jupyter and Marimo. In Marimo it flattens `VBox`/`HBox` roots before display when needed, and `display=False` always returns the raw `{\"widget\": ..., \"wdict\": ...}` dictionary.\n\n5. **33 widget functions** — All GUI functions return a dictionary with `\"widget\"` (the root AnyWidget) and `\"wdict\"` (a mapping of named sub-widgets). This pattern is consistent across ROI widgets, axis widgets, model widgets, tool widgets, and preference widgets.\n\n## Running the tests\n\npytest is required to run the tests.\n\n```bash\npip install \"hyperspy_gui_anywidget[tests]\"\npytest --pyargs hyperspy_gui_anywidget\n```\n\n## Examples\n\nSee the `examples/` directory:\n\n- `examples/comparison_notebook.ipynb` — clean `ipywidgets` vs `anywidget` side-by-side comparison for representative HyperSpy GUIs ([GitHub](https://github.com/hyperspy/hyperspy_gui_anywidget/blob/main/examples/comparison_notebook.ipynb), [Binder](https://mybinder.org/v2/gh/hyperspy/hyperspy_gui_anywidget/HEAD?filepath=examples%2Fcomparison_notebook.ipynb))\n- `examples/jupyter_anywidget_example.ipynb` — practical Jupyter Notebook / JupyterLab walkthrough using the default `display=True` flow ([GitHub](https://github.com/hyperspy/hyperspy_gui_anywidget/blob/main/examples/jupyter_anywidget_example.ipynb), [Binder](https://mybinder.org/v2/gh/hyperspy/hyperspy_gui_anywidget/HEAD?filepath=examples%2Fjupyter_anywidget_example.ipynb))\n- `examples/marimo_anywidget_example.py` — equivalent Marimo app showing explicit `mo.ui.anywidget(...)` embedding via `display=False` ([GitHub](https://github.com/hyperspy/hyperspy_gui_anywidget/blob/main/examples/marimo_anywidget_example.py))\n\nThe Jupyter notebook examples link to Binder so they open in a live notebook session instead of a\nstatic renderer. The Marimo example is currently linked as source only: this repository does not\nyet publish a verified dynamic Marimo deployment for that example.\n\n## Development\n\nContributions through pull requests are welcome. Start with [CONTRIBUTING.md](CONTRIBUTING.md) for this repository's setup, testing, docs, and changelog workflow, and see the [HyperSpy Developer Guide](http://hyperspy.org/hyperspy-doc/current/dev_guide.html) for the broader project conventions.\n\nWhen adding a new widget:\n\n1. Create an AnyWidget subclass (or reuse one from `custom_widgets.py`)\n2. Use `link_traits.link()` to sync with HyperSpy traits\n3. Wrap everything in a `ContainerWidget`\n4. Apply `@add_display_arg` for environment-aware display\n5. Register the widget in `hyperspy_extension.yaml`\n6. Add tests in `hyperspy_gui_anywidget/tests/`\n\n`ipywidgets` is therefore an explicit runtime dependency by design: anywidget provides the custom leaf widgets, while `ipywidgets` still provides the Jupyter-native container layer that this package bridges to Marimo.\n\nBefore opening a pull request, run:\n\n```bash\npre-commit run --all-files\npytest --pyargs hyperspy_gui_anywidget\nsphinx-build -W -b html docs docs/_build/html\n```\n\nUser-facing changes should also include a short news fragment in `upcoming_changes/`.\n\n## License\n\nThis project is licensed under the GNU General Public License v3 (GPLv3).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhyperspy%2Fhyperspy_gui_anywidget","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhyperspy%2Fhyperspy_gui_anywidget","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhyperspy%2Fhyperspy_gui_anywidget/lists"}