Querying PUNCH Data#

A notebook guide to querying and loading PUNCH data using SunPy.

This notebook provides a guide on how to query PUNCH data from the SDAC / VSO using Python tools, and how to load and display this data. Note that PUNCH provides some bespoke tools to assist Fido in querying the complex range of data products and versions of PUNCH.

Load libraries

from sunpy.net import Fido
from sunpy.net import attrs as a

import punchbowl  # Note that this import is needed to register PUNCH fido tools
from punchbowl.data import punch_io, visualize

With a range of dates and a PUNCH data product in mind, we can begin querying data. Here we’ll search for level 3 clear low-noise mosaics from 1-2 November 2025. We’re looking for CAM data, so a product code of “CA” and a instrument code of “M”. We can construct a query using the Fido tool, specifying search attributes:

result = Fido.search(a.Time('2025/10/30 12:00:00', '2025/10/31 12:00:00'),
                     a.punch.ProductCode.ca, # (ca for clear low-noise), or pa for polarized low-noise, etc.
                     a.Instrument.m, # (m for mosaic), or a.Instrument.nfi_4, etc for earlier levels.
                     a.Level.three,
                     a.punch.DataVersion.newest, # or a.punch.DataVersion.zero_j, etc.
                     a.punch.FileType.fits) # or a.punch.FileType.jp2

result
Results from 1 Provider:

45 Results from the PUNCHClient:
QueryResponse length=45
Start TimeEnd TimeLevelProductCodeInstrumentDataVersionSourceProviderFileType
TimeTimestr1str2str1str2str5str4str4
2025-10-30 12:00:00.0002025-10-30 12:00:00.9993CAM0jPUNCHSwRIfits
2025-10-30 12:32:00.0002025-10-30 12:32:00.9993CAM0jPUNCHSwRIfits
2025-10-30 13:04:00.0002025-10-30 13:04:00.9993CAM0jPUNCHSwRIfits
2025-10-30 13:36:00.0002025-10-30 13:36:00.9993CAM0jPUNCHSwRIfits
2025-10-30 14:08:00.0002025-10-30 14:08:00.9993CAM0jPUNCHSwRIfits
2025-10-30 14:40:00.0002025-10-30 14:40:00.9993CAM0jPUNCHSwRIfits
2025-10-30 15:12:00.0002025-10-30 15:12:00.9993CAM0jPUNCHSwRIfits
2025-10-30 15:44:00.0002025-10-30 15:44:00.9993CAM0jPUNCHSwRIfits
2025-10-30 16:16:00.0002025-10-30 16:16:00.9993CAM0jPUNCHSwRIfits
...........................
2025-10-31 06:40:00.0002025-10-31 06:40:00.9993CAM0jPUNCHSwRIfits
2025-10-31 07:12:00.0002025-10-31 07:12:00.9993CAM0jPUNCHSwRIfits
2025-10-31 07:44:00.0002025-10-31 07:44:00.9993CAM0jPUNCHSwRIfits
2025-10-31 08:16:00.0002025-10-31 08:16:00.9993CAM0jPUNCHSwRIfits
2025-10-31 08:48:00.0002025-10-31 08:48:00.9993CAM0jPUNCHSwRIfits
2025-10-31 09:20:00.0002025-10-31 09:20:00.9993CAM0jPUNCHSwRIfits
2025-10-31 09:52:00.0002025-10-31 09:52:00.9993CAM0jPUNCHSwRIfits
2025-10-31 10:24:00.0002025-10-31 10:24:00.9993CAM0jPUNCHSwRIfits
2025-10-31 11:28:00.0002025-10-31 11:28:00.9993CAM0jPUNCHSwRIfits
2025-10-31 12:00:00.0002025-10-31 12:00:00.9993CAM0jPUNCHSwRIfits



This results in a table of available data products that match the search criteria. Next, let’s download the first file from this list of results:

try:
    files = Fido.fetch(result[0][0])
except IndexError:
    print("Oops no files were found!")
    files = None
Files Downloaded:   0%|          | 0/1 [00:00<?, ?file/s]

PUNCH_L3_CAM_20251030120000_v0j.fits:   0%|          | 0.00/22.7M [00:00<?, ?B/s]

PUNCH_L3_CAM_20251030120000_v0j.fits:   2%|▏         | 448k/22.7M [00:00<00:04, 4.47MB/s]

PUNCH_L3_CAM_20251030120000_v0j.fits:  25%|██▌       | 5.69M/22.7M [00:00<00:00, 32.2MB/s]

PUNCH_L3_CAM_20251030120000_v0j.fits:  73%|███████▎  | 16.5M/22.7M [00:00<00:00, 66.7MB/s]


Files Downloaded: 100%|██████████| 1/1 [00:00<00:00,  2.19file/s]
Files Downloaded: 100%|██████████| 1/1 [00:00<00:00,  2.18file/s]

This returns a list of paths to files that have been downloaded. Note that the Fido.fetch tool can specify a particular download directory for larger data searches. With that file downloaded, we can plot the data:

if files:
    fig, ax = visualize.plot_punch(files[0])
PUNCH CAM 2025/10/30 12:00:00 UT

And that’s it! From here the data is loaded into the PUNCH plotting tool and displayed. Of course this is just one path, you could always load the data using the punchbowl.data.punch_io.load_ndcube_from_fits() function or Astropy fits tools. As an example you could load this file using:

if files:
    datacube = punch_io.load_ndcube_from_fits(files[0])

datacube
<ndcube.ndcube.NDCube object at 0x7cf8eecf5ee0>
NDCube
------
Shape: (4096, 4096)
Physical Types of Axes: [('custom:pos.helioprojective.lon', 'custom:pos.helioprojective.lat'), ('custom:pos.helioprojective.lon', 'custom:pos.helioprojective.lat')]
Unit: ct
Data Type: float64

Total running time of the script: (0 minutes 2.616 seconds)

Gallery generated by Sphinx-Gallery