Displaying FITS Images#

This notebook shows how to display FITS images in Firefly and how to modify the image display (pan/zoom/stretch/align).

Setup#

First, we create a FireflyClient instance and open a Firefly viewer. See Initializing a FireflyClient instance for more details.

[1]:
from firefly_client import FireflyClient

# Following imports are just for example data fetching and processing (not needed always)
from astropy.utils.data import download_file
from astropy.io import fits
from astropy.convolution import convolve, Gaussian2DKernel
import io

# Initialize a FireflyClient instance
fc = FireflyClient.make_client(url="https://irsa.ipac.caltech.edu/irsaviewer")

Show FITS Image in Firefly#

Use the show_fits_image method of the FireflyClient object to display a FITS image. It can take a local file path, URL, or a file-like object as input via the file_input parameter.

It is recommended to explicitly specify the plot_id parameter for later use in modifying the image display.

From a URL#

You can specify url of any FITS image. Here we use cutout of a WISE all-sky image of M51 galaxy in W2 band:

[2]:
cutout_image_url = 'https://irsa.ipac.caltech.edu/ibe/data/wise/allsky/4band_p1bm_frm/9a/05379a/141/05379a141-w2-int-1b.fits?center=202.4841667,47.23055556&size=400pix'
[3]:
cutout_image_plot_id = 'wise-cutout'
fc.show_fits_image(file_input=cutout_image_url,
                   plot_id=cutout_image_plot_id,
                   title='WISE Cutout')
[3]:
{'success': True}

From a local file#

You can specify path of any local FITS file. Here we download the full WISE all-sky image of M51 in W2 and use its file path:

[4]:
full_image_url = 'https://irsa.ipac.caltech.edu/ibe/data/wise/allsky/4band_p1bm_frm/9a/05379a/141/05379a141-w2-int-1b.fits'
full_image_fpath = download_file(full_image_url, cache=True, timeout=120)
full_image_fpath
[4]:
'/Users/jsinghal/.astropy/cache/download/url/ef686a664b2c17e3d8590b511be8a400/contents'
[5]:
full_image_plot_id = 'wise-fullimage'
fc.show_fits_image(file_input=full_image_fpath,
                   plot_id=full_image_plot_id, # using a different plot id to not overwrite previous plot
                   title='WISE Full Image')
[5]:
{'success': True}

From an in-memory file-like object#

You can also use a file-like object (e.g. BytesIO stream) instead of a local file path or URL. This is useful when you are working with a FITS file in memory and don’t want to write it to disk.

[6]:
processed_fits = io.BytesIO()

with fits.open(cutout_image_url) as hdul:
    # Do some processing on FITS image data (like simple Gaussian smoothing here)
    img_data = hdul[0].data
    gaussian_kernel = Gaussian2DKernel(x_stddev=2)
    img_data = convolve(img_data, gaussian_kernel)

    new_hdu = fits.PrimaryHDU(data=img_data, header=hdul[0].header)
    new_hdu.writeto(processed_fits, overwrite=True)
    processed_fits.seek(0) # to bring reading pointer to the beginning of file
[7]:
fc.show_fits_image(file_input=processed_fits,
                   plot_id='wise-processed',
                   title='Processed WISE Cutout')
[7]:
{'success': True}

Modify the displayed image(s)#

Zooming, panning, and changing the stretch is accomplished by following methods, passing in the plot_id as the first argument.

Panning to a coordinate#

To pan the full image to center on the M51 cutout’s center:

[8]:
fc.set_pan(plot_id=full_image_plot_id, # note we use the plot id we defined above
           x=202.4841667, y=47.23055556, coord='j2000')
[8]:
{'success': True}

Zooming#

To zoom into the full image by a factor of 2:

[9]:
fc.set_zoom(plot_id=full_image_plot_id, factor=2)
[9]:
{'success': True}

Changing the color stretch#

Set the stretch for the full image based on IRAF zscale interval with a linear algorithm:

[10]:
fc.set_stretch(plot_id=full_image_plot_id, stype='zscale', algorithm='linear')

# Or for a log stretch with sigma limits:
# fc.set_stretch(plot_id=full_image_plot_id, stype='sigma', algorithm='log', lower_value=-2, upper_value=30)
[10]:
{'success': True,
 'rv_string': '91,1.000000,91,1.000000,NaN,2.000000,44,25,600,120,0,NaN,1.000000'}

Aligning multiple images#

You can align mutliple images covering the same sky location by target, WCS, pixels, etc. Optionally, you can also lock the alignment so that panning/zooming one image will pan/zoom the other images in sync.

To align both full image and cutout image by WCS and to lock the WCS matching:

[11]:
fc.align_images(lock_match=True)
[11]:
{'success': True}

Advanced Usage (Low-level, Unstable API)#

In most cases, you do not need the low-level API to create or modify image displays, since the higher-level methods shown above cover common workflows and you can always directly use the UI controls in Firefly. For completeness, the sections below document low-level operations that may be useful to advanced users. Note that the low-level API is unstable and may change, so examples here might not work in all cases.

Changing the color map#

FireflyClient doesn’t provide a high-level method to change the color map but you can do so by using the lower-level API: dispatch the relevant JavaScript action with the required parameters in the payload.

[12]:
fc.dispatch(action_type='ImagePlotCntlr.ColorChange',
            payload={
                'plotId': full_image_plot_id,
                'cbarId': 24 # veridis color map
                })
[12]:
{'success': True}

Specifying Zoom and Stretch Values When First Displaying an Image#

It can be advantageous to specify the zoom, stretch, and color table parameters in the same command that displays the image, to avoid problems with the later commands being ignored when the image display has not completed.

To specify the stretch as part of the image display, you can generate a range values string. This example is for an asinh stretch with a Q value of 6 and an upper level of 98 percent:

[13]:
from firefly_client import RangeValues
rvstring = RangeValues.create_rv_standard(algorithm='asinh',
                                          asinh_q_value=6,
                                          upper_value=98.0)

The zoom value can be specified in several different ways. When displaying images with different pixel scales, the best practice is to specify ZoomType='ARCSEC_PER_SCREEN_PIX' and then the numerical value, e.g. ZoomArcsecPerScreenPix=0.3.

These parameters use the key names defined in FITS Plotting Parameters for the Firefly JavaScript. They can be passed to the show_fits_image method as additional keyword arguments:

[14]:
fc.show_fits_image(file_input=cutout_image_url,
                   plot_id=cutout_image_plot_id, # same plot id to replace the previous image
                   title='WISE Cutout',
                   # additional keyword arguments
                   ColorTable=4,
                   ZoomType='ARCSEC_PER_SCREEN_PIX',
                   ZoomArcsecPerScreenPix=0.3,
                   RangeValues=rvstring
                   )
[14]:
{'success': True}

Retrieving Images Using IRSA-Specific Searches#

Instead of providing FITS image file (as a local file path, URL, or file-like object), you can also retrieve images by utilizing Firefly’s image search processors that powers the IRSA archives.

A table of available projects for image searches is maintained in the Firefly code base. The information can be retrieved into an Astropy table:

[15]:
from astropy.table import Table
surveys = Table.read('https://raw.githubusercontent.com/Caltech-IPAC/firefly/dev/src/firefly/java/edu/caltech/ipac/firefly/resources/irsa-image-master-table.csv',
                    format='csv')

To select images available for the WISE AllSky project:

[16]:
wise_surveys = surveys[surveys['missionId'] == 'WISE']
wise_surveys[['AllSky' in project for project in wise_surveys['project']]]
[16]:
Table length=4
missionIdprojectsubProjectsurveyKeyacronymwavebandIdimageIdtitlewavelengthwavelengthDescwaveTypeprojectTypeKeyprojectTypeDescminRangeDegmaxRangeDeghelpUrltooltipapiTypefilterdataTypedefaultRgbColor
str8str115str8str33str25str11str2str42float64str15str7str13str13float64float64str74str46str7str80str5str5
WISEWISE AllSky Atlas--1bWISE AllSky W11--W1 (3.4 microns)3.43.4 micronsmid-IRall-skyall-sky0.010.2https://irsa.ipac.caltech.edu/docs/irsaviewer_datasets.html#WISEAll-SkyWISE AllSky SIngle Exposure W1 3.4 micronsWISE--image--
WISEWISE AllSky Atlas--1bWISE AllSky W22--W2 (4.6 microns)4.64.6 micronsmid-IRall-skyall-sky0.010.2https://irsa.ipac.caltech.edu/docs/irsaviewer_datasets.html#WISEAll-SkyWISE AllSky SIngle Exposure W2WISE--image--
WISEWISE AllSky Atlas--1bWISE AllSky W33--W3 (12 microns)12.012 micronsmid-IRall-skyall-sky0.010.2https://irsa.ipac.caltech.edu/docs/irsaviewer_datasets.html#WISEAll-SkyWISE AllSky SIngle Exposure W3WISE--image--
WISEWISE AllSky Atlas--1bWISE AllSky W44--W4 (22 microns)22.022 micronsmid-IRall-skyall-sky0.010.2https://irsa.ipac.caltech.edu/docs/irsaviewer_datasets.html#WISEAll-SkyWISE AllSky SIngle Exposure W4WISE--image--

To search the WISE AllSky survey in W1 band:

[17]:
size_in_arcsec = 600
ra = 202.4841667
dec = 47.23055556
target = f'{ra};{dec};EQ_J2000'
fc.show_fits_image(plot_id='IRAC1',
                    Title='WISE AllSky W1 Search',
                    Type='SERVICE',
                    Service='WISE', # apiType
                    SurveyKey='1b', # surveyKey
                    SurveyKeyBand='1', # wavebandId
                    WorldPt=target,
                    SizeInDeg=size_in_arcsec/3600,
                    ColorTable=1,
                    ZoomType='ARCSEC_PER_SCREEN_PIX',
                    ZoomArcsecPerScreenPix=0.3,
                    RangeValues=rvstring)
[17]:
{'success': True}

Since we added additional images to the viewer, we re-align and lock them by WCS so panning/zooming stays in sync:

[18]:
fc.align_images(lock_match=True)
[18]:
{'success': True}