Skip to main content

astrowidget

Interactive radio astronomy visualization for Jupyter. Renders radio images on a rotatable celestial sphere with SIN projection, reading directly from zarr stores -- no FITS intermediary.

PyPI version License Python DOI

Why astrowidget?

Existing tools like ipyaladin have significant limitations for radio astronomy workflows:

Problem with ipyaladin astrowidget solution
Broken sphere overlay for radio images Correct SIN projection on a rotatable sphere
Requires FITS round-trip (zarr -> HDU -> FITS -> display) Direct binary transfer (zarr -> numpy -> GPU)
GPL-3 license (Aladin Lite) BSD-3, fully owned
No native zarr support open_dataset() reads zarr natively
FITS serialization adds latency Raw float32 transfer, <50 ms per frame
No frequency/time slider controls Built-in time/freq slice navigation

Features

  • Interactive sphere -- Pan, zoom, and rotate the celestial sphere at 60 fps
  • Zarr-native -- Load local, remote (S3/HTTPS), or in-memory zarr stores
  • WCS coordinate grid -- RA/Dec grid overlay with auto-scaling intervals
  • HiPS backgrounds -- Aladin Lite embed for DSS, WISE, Planck survey tiles
  • Click-to-inspect -- Click anywhere on the sphere to extract spectrum and light curve
  • SkyViewer dashboard -- Panel-based dashboard with controls and linked HoloViews plots
  • Box zoom -- Drag a rectangle to zoom into a region of interest
  • Tested -- 63 Python + 15 JS tests with astropy-validated projection vectors

Quick Start

from astrowidget import SkyWidget, open_dataset

# Load zarr data
ds = open_dataset("path/to/observation.zarr")

# Display on the celestial sphere
widget = SkyWidget()
widget.set_dataset(ds)
widget.background_survey = "DSS"  # optional HiPS background
widget

Synthetic data

from astrowidget import SkyWidget
import numpy as np
from astropy.wcs import WCS

data = np.random.randn(256, 256).astype(np.float32)

wcs = WCS(naxis=2)
wcs.wcs.ctype = ["RA---SIN", "DEC--SIN"]
wcs.wcs.crval = [180.0, 45.0]
wcs.wcs.cdelt = [-0.1, 0.1]
wcs.wcs.crpix = [128.5, 128.5]

widget = SkyWidget()
widget.set_image(data, wcs)
widget

Dashboard with linked views

from astrowidget import SkyViewer

viewer = SkyViewer.from_zarr("path/to/observation.zarr")
viewer.panel()

This opens a Panel dashboard with the sky widget, time/frequency sliders, colormap controls, and linked spectrum + light curve plots that update on click.

Installation

From PyPI

pip install astrowidget

Optional extras:

pip install 'astrowidget[dashboard]'  # Panel, HoloViews, Bokeh for SkyViewer
pip install 'astrowidget[remote]'     # S3/fsspec for remote zarr stores
pip install 'astrowidget[ingest]'     # xradio for radio data ingestion

From source (development)

git clone https://github.com/uw-ssec/astrowidget.git
cd astrowidget
pixi install
pixi run test  # verify everything works

As a dependency in another pixi project

Add to your pyproject.toml:

[tool.pixi.feature.visualization.pypi-dependencies]
astrowidget = { path = "../astrowidget", editable = true }

Development

astrowidget uses pixi for reproducible development environments. All tasks are defined in pyproject.toml:

Task Description
pixi run test Run all Python and JS tests
pixi run test-py Run Python tests only
pixi run test-js Run JS tests only
pixi run lint Lint with ruff
pixi run build Build JS bundle with Vite
pixi run dev Watch mode for JS development
pixi run docs-serve Serve docs locally at localhost:8000
pixi run docs-build Build static documentation site
pixi run vectors Regenerate astropy projection test fixtures

Build pipeline

  1. JS: npm run build bundles js/inline_widget.js into src/astrowidget/static/widget.js via Vite
  2. Python: python -m build creates sdist + wheel with the bundled JS
  3. CI/CD: GitHub Actions builds and publishes to PyPI on release via trusted publisher

Architecture

zarr store ──> xarray.Dataset ──> PreloadedCube (LRU cache)
                                       │
                                  float32 slice
                                       │
                              SkyWidget (anywidget)
                                       │
                               ┌───────┴───────┐
                               │  Python ←→ JS  │
                               │   (traitlets)  │
                               └───────┬───────┘
                                       │
                              WebGL2 fragment shader
                              ┌────────────────────┐
                              │ screen pixel        │
                              │   → gnomonic inv.   │
                              │   → RA/Dec          │
                              │   → SIN proj.       │
                              │   → (l, m)          │
                              │   → texture sample  │
                              │   → stretch         │
                              │   → colormap LUT    │
                              │   → RGBA            │
                              └────────────────────┘

Key components

Component File Role
SkyWidget src/astrowidget/widget.py Anywidget class -- bridges Python data to JS renderer
open_dataset src/astrowidget/io.py Unified zarr loader (local, S3, in-memory)
PreloadedCube src/astrowidget/cube.py LRU-cached slice loader with strided downsampling
get_wcs src/astrowidget/wcs.py WCS extraction from zarr metadata (3 fallback locations)
SkyViewer src/astrowidget/viewer.py Panel dashboard with linked spectrum/light curve views
WebGL renderer js/inline_widget.js Raw WebGL2 fragment shader with SIN projection

API Overview

SkyWidget

The core widget for displaying radio images on the celestial sphere.

widget = SkyWidget()

# Load data
widget.set_image(data_2d, wcs)           # numpy array + astropy WCS
widget.set_dataset(ds)                    # xarray Dataset from zarr

# Navigation
widget.goto(SkyCoord(180, 45, unit="deg"), fov=10)

# Display options
widget.colormap = "viridis"               # inferno, viridis, plasma, magma, grayscale
widget.stretch = "sqrt"                   # linear, log, sqrt, asinh
widget.show_grid = True                   # RA/Dec coordinate grid
widget.auto_scale(5, 99.5)               # percentile-based vmin/vmax

# HiPS background
widget.background_survey = "DSS"          # DSS, WISE, Planck, 2MASS, ...
widget.background_opacity = 0.5

# Events
widget.clicked_coord                      # (RA, Dec) of last click

open_dataset

from astrowidget import open_dataset

ds = open_dataset("/local/path.zarr")
ds = open_dataset("s3://bucket/obs.zarr", storage_options={"anon": True})

SkyViewer

from astrowidget import SkyViewer

viewer = SkyViewer.from_zarr("path/to/data.zarr")
viewer.panel()  # returns a Panel layout

Tech Stack

Layer Technology
Widget framework anywidget
Rendering Raw WebGL2 (fragment shader)
Projection SIN (slant orthographic)
Data format zarr v2 via xarray + dask
Coordinates astropy WCS
Dashboard Panel + HoloViews + Bokeh
Build Hatchling (Python) + Vite (JS)
Environment pixi (conda-forge)
Testing pytest + vitest
CI/CD GitHub Actions -> PyPI trusted publisher

Documentation

Full documentation is available at uw-ssec.github.io/astrowidget:

Section Description
Getting Started Installation, first widget, pixi tasks
Architecture Overview System design, data flow, components
Data Pipeline Zarr loading, WCS extraction, caching
WebGL Renderer Fragment shader, SIN projection, colormaps
Design Decisions Why raw WebGL2, inline ESM, uint8 textures
OVRO-LWA Integration Using with ovro-lwa-portal
HiPS Backgrounds Aladin Lite survey configuration
API Reference SkyWidget, open_dataset, SkyViewer

License

BSD 3-Clause -- Copyright (c) 2026, UW Scientific Software Engineering Center

Citation

If you use astrowidget in your research, please cite:

@software{astrowidget,
  title     = {astrowidget: Interactive Radio Astronomy Visualization for Jupyter},
  author    = {{UW Scientific Software Engineering Center}},
  year      = {2026},
  url       = {https://github.com/uw-ssec/astrowidget},
  license   = {BSD-3-Clause}
}

Metadata

Release files for astrowidget 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for astrowidget 0.2.0
File Size Uploaded Provenance Actions
astrowidget-0.2.0.tar.gz 282.9 kB With provenance Details for astrowidget-0.2.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for astrowidget 0.2.0
File Interpreter ABI Platform Actions
astrowidget-0.2.0-py3-none-any.whl Python 3 none any Details for astrowidget-0.2.0-py3-none-any.whl

Total release size: 452.3 kB

Release files / astrowidget-0.2.0.tar.gz

Download URL astrowidget-0.2.0.tar.gz
Size 282.9 kB
Tags Source
SHA-256 checksum
How to use checksums
9242a120634b612284c819e8afcd7da9f88b3c67f12c29ad1f48f47803508648
BLAKE2b-256 checksum
How to use checksums
c6c19650c7188c8fec3ed07746092f70b054812b5544d225f4133d15b3506154
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 11, 2026.

Transparency log

Release files / astrowidget-0.2.0-py3-none-any.whl

Download URL astrowidget-0.2.0-py3-none-any.whl
Size 169.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
183bd003c5022d002bdd1f96b41b147cb085e59c60c5806c2e15416a5702284e
BLAKE2b-256 checksum
How to use checksums
637130a9cd5807ada9d91c2ff64de3285735f20418b95c25f4deedaec19cb22d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 11, 2026.

Transparency log

Security for astrowidget 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for astrowidget-0.2.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 11, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page