102.2. How to get started with PyVO using SIA#
For the API Aspect of the Rubin Science Platform at data.lsst.cloud.
Data Release: DP1
Last verified to run: 2026-02-18
Learning objective: Query Rubin DP1 images using the Simple Image Access (SIA) protocol with PyVO from a Python environment.
LSST data products: DP1 images accessed via the Rubin Science Platform SIA service.
Credit: Developed by Andrés A. Plazas Malagón and the Rubin Community Science Team (CST), and based on tutorials developed by the CST. Please consider acknowledging them if this tutorial is used for the preparation of journal articles, software releases, or other tutorials.
Get Support: Everyone is encouraged to ask questions or raise issues in the Support Category of the Rubin Community Forum. Rubin staff will respond to all questions posted there.
Introduction#
This tutorial demonstrates how to access Rubin DP1 image data programmatically using the API Aspect of the Rubin Science Platform. The tutorial uses the Python Virtual Observatory (PyVO) package to authenticate with the Rubin Simple Image Access (SIA) service and query for images.
Simple Image Access (SIA) is a protocol of the International Virtual Observatory Alliance (IVOA). It provides a standardized model for image metadata, and the capability to query and retrieve image datasets. Learn more in the IVOA SIA documentation.
This workflow is suitable for users who prefer scripted or automated access to Rubin data from a local Python environment or from cloud-based environments such as Google Colab. Familiarity with basic Python syntax is assumed.
Related tutorials describe image access via the Notebook Aspect of the Rubin Science Platform, such as 103.2. Simple Image Access (SIA).
1. Create an RSP access token#
Create an RSP access token following the instructions on the Creating user tokens webpage
Configure the token with the following properties:
Include
pyvoorsiain the token name.Select the
read:imagescope.No expiration date.
Copy the token to a secure location. The token will not be shown again.
Important
Treat tokens like passwords. Do not share them and do not store them in version-controlled files.
2. Install and import the Python packages#
Install the required Python packages, PyVO and requests, in the chosen environment (for example, in a local computer or in a Google Colab notebook).
See the PyVO homepage and the “requests” documentation for download and install instructions.
Note that in certain environments like Google Colab you may have to re-install these packages for each session.
Import the required packages.
import pyvo
import requests
from pyvo.dal.adhoc import DatalinkResults
3. Store the access token#
Store the access token in a Python variable or environment variable.
Read the token from an environment variable (recommended):
import os
token = os.environ["RSP_TOKEN"]
Alternatively, assign the token directly:
token = "YOUR_TOKEN"
4. Create an authenticated HTTP session#
Create a persistent HTTP session and attach the access token using the Authorization header.
session = requests.Session()
session.headers["Authorization"] = f"Bearer {token}"
This session ensures that all SIA requests are authenticated using the provided token.
5. Connect to the Rubin SIA service#
Define the Rubin SIA service endpoint and initialize a PyVO SIA2Service object.
The endpoint for the DP1 SIA service is https://data.lsst.cloud/api/sia/dp1/query.
rsp_sia_url = "https://data.lsst.cloud/api/sia/dp1/query"
sia_service = pyvo.dal.SIA2Service(
rsp_sia_url, session=session, check_baseurl=False
)
The SIA service object represents the remote image service and manages query submission and result retrieval.
Note that check_baseurl=False is required because the SIA endpoint includes the query path.
6. Define the search parameters#
Define a spatial region to search for images. For this example, search for images in a circular region centered at RA, Dec = 53.076, -28.110 degrees with a radius of 0.05 degrees.
circle = (53.076, -28.110, 0.05)
The position is specified as a tuple of (RA, Dec, radius) in decimal degrees.
7. Query for images#
Execute a search query to retrieve images that overlap the specified region. Limit the results to calibrated images (calib_level=2) and restrict the number of results to 5.
results = sia_service.search(pos=circle, calib_level=2, maxrec=5)
The calib_level parameter filters images by calibration level:
calib_level=1: Raw or partially calibrated imagescalib_level=2: Fully calibrated images (recommended for scientific analysis)calib_level=3: Derived data products (e.g., coadds)
See the SIA2Query documentation for a complete list of query parameters.
8. Inspect the results#
The results object contains a table of image metadata. Convert the results to an Astropy table for easier manipulation.
table = results.to_table()
Print the number of results and inspect the columns.
print(f"Found {len(results)} images")
print(table.colnames)
Display the first few rows to see the available metadata:
table[:5]
The results table includes metadata such as:
s_ra,s_dec: Image center positiont_exptime: Exposure timeem_filter_name: Filter/band namedataproduct_subtype: Type of image (e.g., lsst.deepCoadd)access_url: URL to access the image data
9. Download an image file#
To download a FITS file that can be opened locally with tools like DS9, use the DataLink service to obtain the direct download URL.
First, retrieve the access_url from the results table. This URL points to a DataLink endpoint that provides various access methods for the image.
datalink_url = table["access_url"][0]
print("DataLink URL:\n", datalink_url)
Fetch and parse the DataLink response as a VOTable.
dl = DatalinkResults.from_result_url(datalink_url, session=session)
Inspect the available links.
dl_table = dl.to_table()
print("DataLink records:", len(dl_table))
dl_table[:10]
Extract the direct download URL for the first record.
image_url = dl.getrecord(0).get("access_url")
print("Chosen file URL:\n", image_url)
Download the FITS file to your local system.
r = session.get(image_url, stream=True)
r.raise_for_status()
out_path = "dp1_image.fits"
with open(out_path, "wb") as f:
for chunk in r.iter_content(chunk_size=1024 * 1024):
if chunk:
f.write(chunk)
print("Saved:", out_path)
The downloaded FITS file can now be opened with FITS viewers such as DS9 or analyzed using Python libraries like astropy.io.fits.
For catalog queries using TAP, see the companion tutorial 102.1. How to get started with PyVO using TAP.