Galaxy Morphology with SDSS and Astrocut#


Learning Goals#

By the end of this tutorial, you will:

  • Understand how to use astroquery.mast to download the SDSS Legacy Imaging Survey Data from the MAST archive.

  • Utilize astrocut to create colorized cropped images from 12 different galaxies.

  • Construct a Hubble Tuning Fork Diagram from the cropped images to learn about galaxy morphology.

Table of Contents#

  • Introduction

  • Imports

  • Accessing SDSS Legacy Imaging Survey Data from MAST

    • Querying SDSS Legacy Imaging Survey

    • Gathering Galaxies from the SDSS Legacy Imaging Survey

      • Elliptical Galaxies

      • Lenticular Galaxies

      • Spiral Galaxies

      • Barred Spiral Galaxies

      • Irregular Galaxies

    • Downloading Data Products

  • Creating the Cutout Images Using Astrocut

  • Making the Hubble Tuning Fork Diagram

  • End of Tutorial

  • Exercise

  • Exercise Solution

  • Additional Resources

  • Citations

  • About this Notebook

Introduction#

Hubble Tuning Fork Diagram
Hubble Tuning Fork Diagram [1].

In the early 1900s, most astronomers believed objects such as the Andromeda galaxy were nebulous clouds within our galaxy. In 1923, Edwin Hubble proved Andromeda was outside the Milky Way using the period-luminosity relationship with Cepheid variables [2]. Once Hubble discovered most “nebulae” visible in the sky were actually galaxies, he created a classification scheme known as the Hubble Tuning Fork, or the Hubble Sequence. Hubble initially separated galaxies into two main groups: elliptical galaxies and spiral galaxies. Elliptical galaxies lack spiral arms, but are ellipses in shape. Hubble classified them by their ellipticity; the more elongated the galaxy, the higher its classification number (i.e. E0 to E7).

Spiral galaxies, which have prominent spiral arms, were further divided into two types based on the presence of a central bar: barred spirals (with a bar) and normal spirals (without). Both types were then categorized as early, intermediate, or late, depending on how tightly wound their arms were. Galaxies that lacked both a central nucleus and spiral structure were classified as “irregular” [3].

Hubble initially proposed that galaxies evolved from left to right on his tuning fork diagram, starting at E0 ellipticals and ending at late-type spiral/barred spiral galaxies. However, we now know this to be incorrect! Despite this, the Hubble Sequence remains a widely used tool for galaxy morphological classification [1].

In this notebook, we’ll construct our own Hubble Tuning Fork Diagram based on this classification scheme using imaging data from the SDSS Legacy Imaging Survey. We can utilize the Astrocut package to crop selected fields and generate color cutouts of various galaxies for our diagram.

Imports#

The main packages and their use-cases in this tutorial are as follows:

  • numpy to handle array functions

  • matplotlib.pyplot for plotting data

  • matplotlib.image to handle .png images

  • astroquery.mast.Observations to access SDSS data from MAST

  • astrocut.FITSCutout to mosaic images

  • astropy for handling FITS files

  • astropy.table.vstack for combining Astropy tables

  • warnings to suppress FITS warnings

  • bz2 to decompress the data files

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
from astroquery.mast import Observations
from astrocut import FITSCutout
import astropy
from astropy.table import vstack
import warnings
import bz2

If you’re not sure if you have the required versions of packages installed on your device, you can run the following cell:

with open("requirements.txt") as f:
    print(f"Required packages for this notebook:\n{f.read()}")
Required packages for this notebook:
numpy >= 1.26.4
matplotlib >= 3.9.1
astroquery >= 0.4.9
astropy >= 5.3
astrocut >= 1.0.1

To ensure these requirements are installed, you can run the following command in the terminal:

pip install -r requirements.txt

Accessing SDSS Legacy Imaging Survey Data from MAST#

The Mikulski Archive for Space Telescopes (MAST) hosts a large array of data from several telescope missions. In this tutorial, we will be specifically focusing on data from the Sloan Digital Sky Survey’s (SDSS) Imaging Survey.

The SDSS Legacy Imaging Survey was the first SDSS survey completed! Beginning in 1998, the SDSS Legacy Imaging Survey captured around 35,000 square degrees of images until 2009, which covers about one-third of the whole sky. To do this, the survey took millions of 10 by 13 arcminute pictures (called “fields”). Not only does the SDSS Legacy Imaging Survey data at MAST provide users with preview images in .jpg format, but it also has photometric data in all five broad band SDSS filters (u, g, r, i, and z). For more information about the data and products from the SDSS Legacy Imaging Survey, you can check out the SDSS Imaging Archive Manual.

Querying SDSS Legacy Imaging Survey#

You can query data from MAST using the website portal. You can also query MAST data in Python using the module astroquery.mast!

We can query all of the SDSS Legacy Imaging data using the Observations.query_criteria() function with the parameter provenance_name = "SDSS Legacy Imaging". Since there is a large amount of data in the SDSS Legacy Imaging archive, we can display the first 10 results using the pagesize parameter as well as the page parameter.

# Querying SDSS Legacy Imaging
imaging_data = Observations.query_criteria(
    provenance_name="SDSS Legacy Imaging", pagesize=10, page=1
)

# Display first 10 entries
imaging_data
Table masked=True length=10
intentTypeobs_collectionprovenance_nameinstrument_nameprojectfilterswavelength_regiontarget_nametarget_classificationobs_ids_ras_decdataproduct_typeproposal_picalib_levelt_mint_maxt_exptimeem_minem_maxobs_titlet_obs_releaseproposal_idproposal_typesequence_numbers_regionjpegURLdataURLdataRightsmtFlagsrcDenobsidobjID
str7str4str19str11str4str9str7str13str5str24float64float64str5str18int64float64float64float64float64float64str51float64str3str1int64str198str61str61str6boolfloat64str9str9
scienceSDSSSDSS Legacy ImagingSDSS CameraSDSSu;g;r;i;zOPTICAL005973-4-0047FIELDsdss_image_005973-4-0047174.229442517-3.71090674527imageSDSS Collaboration353741.4770736111153741.4810145538953.907456304.799999999999951083.3000000000002Sloan Digital Sky Survey (SDSS) Legacy Imaging Data55571.0N/A----POLYGON 174.2883643778937 -3.8370902845458192 174.09108107630817 -3.7279354542798657 174.17063384071784 -3.584772619524905 174.3678949976759 -3.6939097621482793 174.2883643778937 -3.8370902845458192mast:SDSS/sdss/imaging/5973/4/47/frame-irg-005973-4-0047.jpgmast:SDSS/sdss/imaging/5973/4/47/photoObj-005973-4-0047.fitsPUBLICFalsenan295513881874391015
scienceSDSSSDSS Legacy ImagingSDSS CameraSDSSu;g;r;i;zOPTICAL001462-1-0126FIELDsdss_image_001462-1-0126144.2752095140.741253271781imageSDSS Collaboration351669.1867204861151669.1906617761153.907456304.799999999999951083.3000000000002Sloan Digital Sky Survey (SDSS) Legacy Imaging Data55571.0N/A----POLYGON 144.19658829938143 0.6263566454578132 144.19021788017662 0.8513235009682893 144.35383791652822 0.8560386018700294 144.36020003080324 0.6310715111882993 144.19658829938143 0.6263566454578132mast:SDSS/sdss/imaging/1462/1/126/frame-irg-001462-1-0126.jpgmast:SDSS/sdss/imaging/1462/1/126/photoObj-001462-1-0126.fitsPUBLICFalsenan295513901874391051
scienceSDSSSDSS Legacy ImagingSDSS CameraSDSSu;g;r;i;zOPTICAL002589-1-0103FIELDsdss_image_002589-1-010330.6386361561-0.944229797667imageSDSS Collaboration352173.3171418981552173.32108260944453.907456304.799999999999951083.3000000000002Sloan Digital Sky Survey (SDSS) Legacy Imaging Data55571.0N/A----POLYGON 30.556815019164613 -1.0568566677447302 30.5567540900602 -0.831785879001948 30.720452026468934 -0.8317109537235243 30.7205235541735 -1.0567817393486545 30.556815019164613 -1.0568566677447302mast:SDSS/sdss/imaging/2589/1/103/frame-irg-002589-1-0103.jpgmast:SDSS/sdss/imaging/2589/1/103/photoObj-002589-1-0103.fitsPUBLICFalsenan295513908874391076
scienceSDSSSDSS Legacy ImagingSDSS CameraSDSSu;g;r;i;zOPTICAL001013-1-0095FIELDsdss_image_001013-1-009570.7719214022-1.04767931483imageSDSS Collaboration351459.48009930555451459.48404047981653.907456304.799999999999951083.3000000000002Sloan Digital Sky Survey (SDSS) Legacy Imaging Data55571.0N/A----POLYGON 70.69004600918034 -1.1602654120268343 70.69010156512687 -0.9351905477520949 70.85379088960994 -0.9352010321171098 70.85374709332649 -1.1602758989866386 70.69004600918034 -1.1602654120268343mast:SDSS/sdss/imaging/1013/1/95/frame-irg-001013-1-0095.jpgmast:SDSS/sdss/imaging/1013/1/95/photoObj-001013-1-0095.fitsPUBLICFalsenan295513946874391138
scienceSDSSSDSS Legacy ImagingSDSS CameraSDSSu;g;r;i;zOPTICAL005973-5-0037FIELDsdss_image_005973-5-0037173.132629482-4.816058996imageSDSS Collaboration353741.47292766203553741.4768687205653.907456304.799999999999951083.3000000000002Sloan Digital Sky Survey (SDSS) Legacy Imaging Data55571.0N/A----POLYGON 173.1914427566512 -4.942374860882622 172.9940314742844 -4.832827572791295 173.07393446271988 -4.689791600591029 173.27131708934695 -4.799315862787537 173.1914427566512 -4.942374860882622mast:SDSS/sdss/imaging/5973/5/37/frame-irg-005973-5-0037.jpgmast:SDSS/sdss/imaging/5973/5/37/photoObj-005973-5-0037.fitsPUBLICFalsenan295513976874391191
scienceSDSSSDSS Legacy ImagingSDSS CameraSDSSu;g;r;i;zOPTICAL001462-1-0139FIELDsdss_image_001462-1-0139146.2206404860.795511046803imageSDSS Collaboration351669.1921113425951669.1960526325953.907456304.799999999999951083.3000000000002Sloan Digital Sky Survey (SDSS) Legacy Imaging Data55571.0N/A----POLYGON 146.1419152529625 0.6807520127105144 146.13577886376785 0.9056991046172137 146.29937309153925 0.9101586882084078 146.3055005693894 0.6852113532500438 146.1419152529625 0.6807520127105144mast:SDSS/sdss/imaging/1462/1/139/frame-irg-001462-1-0139.jpgmast:SDSS/sdss/imaging/1462/1/139/photoObj-001462-1-0139.fitsPUBLICFalsenan295513995874391224
scienceSDSSSDSS Legacy ImagingSDSS CameraSDSSu;g;r;i;zOPTICAL002589-1-0228FIELDsdss_image_002589-1-022849.3537096163-0.944154233102imageSDSS Collaboration352173.3689715277852173.37291270203453.907456304.799999999999951083.3000000000002Sloan Digital Sky Survey (SDSS) Legacy Imaging Data55571.0N/A----POLYGON 49.27187518653335 -1.0567348956152853 49.271824453431414 -0.8316600492747049 49.43553877625802 -0.8316815982341773 49.43560010836548 -1.0567564419363762 49.27187518653335 -1.0567348956152853mast:SDSS/sdss/imaging/2589/1/228/frame-irg-002589-1-0228.jpgmast:SDSS/sdss/imaging/2589/1/228/photoObj-002589-1-0228.fitsPUBLICFalsenan295514006874391254
scienceSDSSSDSS Legacy ImagingSDSS CameraSDSSu;g;r;i;zOPTICAL001013-1-0092FIELDsdss_image_001013-1-009270.3228432592-1.04763839962imageSDSS Collaboration351459.4788553240751459.4827966140753.907456304.799999999999951083.3000000000002Sloan Digital Sky Survey (SDSS) Legacy Imaging Data55571.0N/A----POLYGON 70.24097683204889 -1.1601976036920532 70.24102714799464 -0.9351305230571858 70.40470378557966 -0.9351870067813087 70.4046652275189 -1.1602540897366753 70.24097683204889 -1.1601976036920532mast:SDSS/sdss/imaging/1013/1/92/frame-irg-001013-1-0092.jpgmast:SDSS/sdss/imaging/1013/1/92/photoObj-001013-1-0092.fitsPUBLICFalsenan295514045874391306
scienceSDSSSDSS Legacy ImagingSDSS CameraSDSSu;g;r;i;zOPTICAL005973-5-0131FIELDsdss_image_005973-5-0131179.9693526787.4943606014imageSDSS Collaboration353741.5119034722253741.5158445307453.907456304.799999999999951083.3000000000002Sloan Digital Sky Survey (SDSS) Legacy Imaging Data55571.0N/A----POLYGON 180.0283952399242 7.368044789069491 179.8300551327669 7.477623018461708 179.91037279910233 7.620615014737597 180.1087578061914 7.511000816926455 180.0283952399242 7.368044789069491mast:SDSS/sdss/imaging/5973/5/131/frame-irg-005973-5-0131.jpgmast:SDSS/sdss/imaging/5973/5/131/photoObj-005973-5-0131.fitsPUBLICFalsenan295514071874391355
scienceSDSSSDSS Legacy ImagingSDSS CameraSDSSu;g;r;i;zOPTICAL001462-1-0075FIELDsdss_image_001462-1-0075136.6444046540.507734474462imageSDSS Collaboration351669.1655743055551669.169515711353.907456304.799999999999951083.3000000000002Sloan Digital Sky Survey (SDSS) Legacy Imaging Data55571.0N/A----POLYGON 136.5662754766541 0.39254266058524295 136.55897977522113 0.6174606423234328 136.72254017681908 0.6228154675656018 136.72983019447588 0.3978973013522048 136.5662754766541 0.39254266058524295mast:SDSS/sdss/imaging/1462/1/75/frame-irg-001462-1-0075.jpgmast:SDSS/sdss/imaging/1462/1/75/photoObj-001462-1-0075.fitsPUBLICFalsenan295514096874391392

The table above provides some basic information for each object:

  • instrument_name: SDSS Camera indicates that the imaging data were collected using the SDSS camera.

  • filters: Indicates the SDSS filters used in the survey (u, g, r, i, and z).

  • wavelength_region: Indicates the region of the electromagnetic spectrum observed. This should be OPTICAL, since the SDSS Legacy Imaging Survey observed in the optical wavelength range.

  • target_classification: FIELD indicates the survey captured images of the sky.

  • obs_id: Observation ID associated with the image.

  • s_ra and s_dec: Right ascension and declination.

  • dataproduct_type: This should be image since we’re focusing on an imaging survey.

  • t_min and t_max: The modified Julian dates indicating the start and end times of the exposures.

  • em_min and em_max: The minimum and maximum wavelengths observed by the survey. For the SDSS Legacy Imaging survey, this range is approximately 304.8 - 1083.3 nanometers (optical).

Gathering Galaxies from the SDSS Legacy Imaging Survey#

In this tutorial, we’ll be gathering a variety of galaxies to make a Hubble Tuning Fork Diagram. We’ll select the following galaxies:

  • Elliptical:

    • M89 (E0)

    • NGC 5982 (E3)

    • NGC 4697 (E6)

  • Lenticular:

    • NGC 3384 (S0)

  • Spiral:

    • NGC 488 (Sa)

    • M88 (Sb)

    • M99 (Sc)

  • Barred Spiral:

    • NGC 109 (SBa)

    • M91 (SBb)

    • NGC 5068 (SBc)

  • Irregular:

    • IC 3583

    • NGC 7292

These galaxies were selected based on their NED classification as well as how they fit in an SDSS field using the MAST Portal Astroview.

We can query MAST using the target name directly! We’ll use M89 as an example:

# Querying MAST for M89 using search radius of 0
m89 = Observations.query_criteria(
    objectname="M89", radius=0, provenance_name="SDSS Legacy Imaging"
)
# Displaying the results
m89
Table masked=True length=3
intentTypeobs_collectionprovenance_nameinstrument_nameprojectfilterswavelength_regiontarget_nametarget_classificationobs_ids_ras_decdataproduct_typeproposal_picalib_levelt_mint_maxt_exptimeem_minem_maxobs_titlet_obs_releaseproposal_idproposal_typesequence_numbers_regionjpegURLdataURLdataRightsmtFlagsrcDenobsidobjIDobjID1distance
str7str4str19str11str4str9str7str13str5str24float64float64str5str18int64float64float64float64float64float64str51float64str3str1int64str194str61str61str6boolfloat64str9str9str9float64
scienceSDSSSDSS Legacy ImagingSDSS CameraSDSSu;g;r;i;zOPTICAL003805-4-0012FIELDsdss_image_003805-4-0012188.89870144112.5764587394imageSDSS Collaboration352721.2294822916752721.2334228872253.907456304.799999999999951083.3000000000002Sloan Digital Sky Survey (SDSS) Legacy Imaging Data55571.0N/A----POLYGON 188.8132288137322 12.46506119358693 188.81649298124918 12.690134070168584 188.98424657174562 12.687719213107714 188.9808354852855 12.462648412357575 188.8132288137322 12.46506119358693mast:SDSS/sdss/imaging/3805/4/12/frame-irg-003805-4-0012.jpgmast:SDSS/sdss/imaging/3805/4/12/photoObj-003805-4-0012.fitsPUBLICFalsenan2970849708771108068771108060.0
scienceSDSSSDSS Legacy ImagingSDSS CameraSDSSu;g;r;i;zOPTICAL003064-4-0048FIELDsdss_image_003064-4-0048188.88805859412.5775588961imageSDSS Collaboration352356.4342923611152356.4382334196353.907456304.799999999999951083.3000000000002Sloan Digital Sky Survey (SDSS) Legacy Imaging Data55571.0N/A----POLYGON 188.80250968110988 12.46618524586542 188.80590815690954 12.69122285024466 188.97368000165366 12.688795440850217 188.97013460213253 12.463759996247843 188.80250968110988 12.46618524586542mast:SDSS/sdss/imaging/3064/4/48/frame-irg-003064-4-0048.jpgmast:SDSS/sdss/imaging/3064/4/48/photoObj-003064-4-0048.fitsPUBLICFalsenan2974859688780091488780091480.0
scienceSDSSSDSS Legacy ImagingSDSS CameraSDSSu;g;r;i;zOPTICAL003804-4-0207FIELDsdss_image_003804-4-0207188.8976296112.5766093494imageSDSS Collaboration352721.2160975694452721.22003874370453.907456304.799999999999951083.3000000000002Sloan Digital Sky Survey (SDSS) Legacy Imaging Data55571.0N/A----POLYGON 188.81217294825396 12.46522271055066 188.81545014737785 12.690283256904873 188.98315874867606 12.687858932000672 188.97973467649607 12.46280046903323 188.81217294825396 12.46522271055066mast:SDSS/sdss/imaging/3804/4/207/frame-irg-003804-4-0207.jpgmast:SDSS/sdss/imaging/3804/4/207/photoObj-003804-4-0207.fitsPUBLICFalsenan2978682458808400698808400690.0

There are three fields available for M89, but we’ll be using the field with target_name=003804-4-0207 since it completely captures the galaxy. For the rest of the tutorial, we’ll be querying by target name (field) as we preselected these from the MAST Portal depending on how the galaxy fit into each field.

Elliptical Galaxies#

Elliptical galaxies have a distinct nucleus, but do not have a disk or spiral arms. Due to the minimal dust and gas present, these galaxies are mostly made up of population II stars. Elliptical galaxies are categorized by number, with E0 being the most round in shape, and E7 being the most elliptical in shape. The elliptical galaxy classification numbers are derived from the equation:

\[ n = 10(\frac{b}{a}) \]

where \(n\) is the classification number, \(b\) is the projected length of the semi-minor axis on the sky, and \(a\) is the projected length of the semi-major axis on the sky [4]. However, this system is sensitive to the angle at which we observe the galaxy. A galaxy that appears highly elliptical when viewed edge-on may be more circular when viewed face-on. Although this classification scheme remains in use, it’s important to remember the limitations imposed by our viewing perspective.

We’ll use the following fields for each galaxy:

  • M89 field: 003804-4-0207

  • NGC 5982 field: 004679-1-0034

  • NGC 4697 field: 006121-1-0124

# Elliptical Galaxies
ellipticals = Observations.query_criteria(
    provenance_name="SDSS Legacy Imaging",
    target_name=[
        "003804-4-0207",  # M89
        "004679-1-0034",  # NGC 5982
        "006121-1-0124",  # NGC 4697
    ],
)
ellipticals
Table masked=True length=3
intentTypeobs_collectionprovenance_nameinstrument_nameprojectfilterswavelength_regiontarget_nametarget_classificationobs_ids_ras_decdataproduct_typeproposal_picalib_levelt_mint_maxt_exptimeem_minem_maxobs_titlet_obs_releaseproposal_idproposal_typesequence_numbers_regionjpegURLdataURLdataRightsmtFlagsrcDenobsidobjID
str7str4str19str11str4str9str7str13str5str24float64float64str5str18int64float64float64float64float64float64str51float64str3str1int64str196str61str61str6boolfloat64str9str9
scienceSDSSSDSS Legacy ImagingSDSS CameraSDSSu;g;r;i;zOPTICAL003804-4-0207FIELDsdss_image_003804-4-0207188.8976296112.5766093494imageSDSS Collaboration352721.2160975694452721.22003874370453.907456304.799999999999951083.3000000000002Sloan Digital Sky Survey (SDSS) Legacy Imaging Data55571.0N/A----POLYGON 188.81217294825396 12.46522271055066 188.81545014737785 12.690283256904873 188.98315874867606 12.687858932000672 188.97973467649607 12.46280046903323 188.81217294825396 12.46522271055066mast:SDSS/sdss/imaging/3804/4/207/frame-irg-003804-4-0207.jpgmast:SDSS/sdss/imaging/3804/4/207/photoObj-003804-4-0207.fitsPUBLICFalsenan297868245880840069
scienceSDSSSDSS Legacy ImagingSDSS CameraSDSSu;g;r;i;zOPTICAL004679-1-0034FIELDsdss_image_004679-1-0034234.57454877659.3448234453imageSDSS Collaboration353170.3060050925953170.30994626685453.907456304.799999999999951083.3000000000002Sloan Digital Sky Survey (SDSS) Legacy Imaging Data55571.0N/A----POLYGON 234.3046197895768 59.32444261506588 234.62038966365222 59.481940250855786 234.84464256375884 59.36456934478688 234.52892307987 59.20761382067637 234.3046197895768 59.32444261506588mast:SDSS/sdss/imaging/4679/1/34/frame-irg-004679-1-0034.jpgmast:SDSS/sdss/imaging/4679/1/34/photoObj-004679-1-0034.fitsPUBLICFalsenan298084026883250573
scienceSDSSSDSS Legacy ImagingSDSS CameraSDSSu;g;r;i;zOPTICAL006121-1-0124FIELDsdss_image_006121-1-0124192.206354543-5.7765959424imageSDSS Collaboration353856.2820930555553856.2860341140853.907456304.799999999999951083.3000000000002Sloan Digital Sky Survey (SDSS) Legacy Imaging Data55571.0N/A----POLYGON 192.31583595794746 -5.863292886582556 192.08978940731004 -5.853419106917138 192.0970170390151 -5.689882899407467 192.32299845386115 -5.699753837522322 192.31583595794746 -5.863292886582556mast:SDSS/sdss/imaging/6121/1/124/frame-irg-006121-1-0124.jpgmast:SDSS/sdss/imaging/6121/1/124/photoObj-006121-1-0124.fitsPUBLICFalsenan297963442881902351

Lenticular Galaxies#

Lenticular galaxies are in-between elliptical and spiral galaxies. They have a central bulge and a disk similar to a spiral galaxy, but lack the spiral arm structure. These galaxies are thought to be former spiral galaxies that lost their interstellar material, likely due to interactions with other galaxies or their environments [5] [6].

We’ll use the field 003631-1-0302 for NGC 3384.

# Lenticular Galaxy
lenticular = Observations.query_criteria(
    provenance_name="SDSS Legacy Imaging",
    target_name="003631-1-0302",  # NGC 3384
)
lenticular
Table masked=True length=1
intentTypeobs_collectionprovenance_nameinstrument_nameprojectfilterswavelength_regiontarget_nametarget_classificationobs_ids_ras_decdataproduct_typeproposal_picalib_levelt_mint_maxt_exptimeem_minem_maxobs_titlet_obs_releaseproposal_idproposal_typesequence_numbers_regionjpegURLdataURLdataRightsmtFlagsrcDenobsidobjID
str7str4str19str11str4str9str7str13str5str24float64float64str5str18int64float64float64float64float64float64str51float64str3str1int64str194str61str61str6boolfloat64str9str9
scienceSDSSSDSS Legacy ImagingSDSS CameraSDSSu;g;r;i;zOPTICAL003631-1-0302FIELDsdss_image_003631-1-0302162.0049591712.6948375209imageSDSS Collaboration352667.43149745370552667.4354380492653.907456304.799999999999951083.3000000000002Sloan Digital Sky Survey (SDSS) Legacy Imaging Data55571.0N/A----POLYGON 161.9332351533888 12.574530580964552 161.90978380682168 12.798441361659597 162.0767624598467 12.815015802635779 162.10006839174622 12.591090421528067 161.9332351533888 12.574530580964552mast:SDSS/sdss/imaging/3631/1/302/frame-irg-003631-1-0302.jpgmast:SDSS/sdss/imaging/3631/1/302/photoObj-003631-1-0302.fitsPUBLICFalsenan298398508885964246

Spiral Galaxies#

Spiral galaxies have distinct spiral arms that protrude from a central bulge of older stars. Within the spiral arms lie stellar “nurseries” of gas and dust that fuel young star formation. Spiral galaxies are classified into Sa, Sb, or Sc groups based on how tightly wound their spirals are, the thickness of the spiral arms, and the size of the central bulge. Sa spirals have large bulges and faint, small spiral arms whereas Sc spirals have smaller bulges, but larger, loose spiral arms [7].

We’ll use the following fields for each galaxy:

  • NGC 488 field: 007727-5-0202

  • M88 field: 004381-2-0114

  • M99 field: 004381-2-0093

# Spiral Galaxies
spirals = Observations.query_criteria(
    provenance_name="SDSS Legacy Imaging",
    target_name=[
        "007727-5-0202",  # NGC 488
        "004381-2-0114",  # M88
        "004381-2-0093",  # M99
    ],
)
spirals
Table masked=True length=3
intentTypeobs_collectionprovenance_nameinstrument_nameprojectfilterswavelength_regiontarget_nametarget_classificationobs_ids_ras_decdataproduct_typeproposal_picalib_levelt_mint_maxt_exptimeem_minem_maxobs_titlet_obs_releaseproposal_idproposal_typesequence_numbers_regionjpegURLdataURLdataRightsmtFlagsrcDenobsidobjID
str7str4str19str11str4str9str7str13str5str24float64float64str5str18int64float64float64float64float64float64str51float64str3str1int64str195str61str61str6boolfloat64str9str9
scienceSDSSSDSS Legacy ImagingSDSS CameraSDSSu;g;r;i;zOPTICAL004381-2-0093FIELDsdss_image_004381-2-0093184.71913604914.4769892626imageSDSS Collaboration353032.3977682870453032.40170922981653.907456304.799999999999951083.3000000000002Sloan Digital Sky Survey (SDSS) Legacy Imaging Data55571.0N/A----POLYGON 184.63484872415157 14.364236748218197 184.6343524567763 14.58938512819659 184.80350921612668 14.589601743912382 184.80383394846027 14.364453070729992 184.63484872415157 14.364236748218197mast:SDSS/sdss/imaging/4381/2/93/frame-irg-004381-2-0093.jpgmast:SDSS/sdss/imaging/4381/2/93/photoObj-004381-2-0093.fitsPUBLICFalsenan298352265885500811
scienceSDSSSDSS Legacy ImagingSDSS CameraSDSSu;g;r;i;zOPTICAL004381-2-0114FIELDsdss_image_004381-2-0114187.96614133214.457917178imageSDSS Collaboration353032.4064753472253032.4104164057453.907456304.799999999999951083.3000000000002Sloan Digital Sky Survey (SDSS) Legacy Imaging Data55571.0N/A----POLYGON 187.88016114963244 14.346363232959801 187.8830848748545 14.571503687912221 188.05220635612855 14.569329914111023 188.0491114033052 14.344191605583559 187.88016114963244 14.346363232959801mast:SDSS/sdss/imaging/4381/2/114/frame-irg-004381-2-0114.jpgmast:SDSS/sdss/imaging/4381/2/114/photoObj-004381-2-0114.fitsPUBLICFalsenan298351741885496458
scienceSDSSSDSS Legacy ImagingSDSS CameraSDSSu;g;r;i;zOPTICAL007727-5-0202FIELDsdss_image_007727-5-020220.4068040765.3457659483imageSDSS Collaboration354747.4088667824154747.4128078409353.907456304.799999999999951083.3000000000002Sloan Digital Sky Survey (SDSS) Legacy Imaging Data55571.0N/A----POLYGON 20.321964096341954 5.235060749739203 20.32725877200831 5.460113241855058 20.49167212052815 5.4563495479137645 20.48631705941364 5.231298472919874 20.321964096341954 5.235060749739203mast:SDSS/sdss/imaging/7727/5/202/frame-irg-007727-5-0202.jpgmast:SDSS/sdss/imaging/7727/5/202/photoObj-007727-5-0202.fitsPUBLICFalsenan298036044882777689

Barred Spiral Galaxies#

Barred spiral galaxies have a distinct, luminous bar/stripe across their center. This bar is thought to form either from internal dynamical instabilities or from gravitational interactions with neighboring galaxies. Like regular spiral galaxies, they are classified into SBa, SBb, and SBc types: SBa galaxies have tightly wound spiral arms and a larger central bulge, while SBc galaxies have loosely wound arms and a smaller bulge. [8].

We’ll use the following fields for each galaxy:

  • NGC 109 field: 007932-2-0051

  • M91 field: 004381-2-0120

  • NGC 5068 field: 001449-5-0093

# Barred Spirals
barred_spirals = Observations.query_criteria(
    provenance_name="SDSS Legacy Imaging",
    target_name=[
        "007932-2-0051",  # NGC 109
        "004381-2-0120",  # M91
        "001449-5-0093",  # NGC 5068
    ],
)
barred_spirals
Table masked=True length=3
intentTypeobs_collectionprovenance_nameinstrument_nameprojectfilterswavelength_regiontarget_nametarget_classificationobs_ids_ras_decdataproduct_typeproposal_picalib_levelt_mint_maxt_exptimeem_minem_maxobs_titlet_obs_releaseproposal_idproposal_typesequence_numbers_regionjpegURLdataURLdataRightsmtFlagsrcDenobsidobjID
str7str4str19str11str4str9str7str13str5str24float64float64str5str18int64float64float64float64float64float64str51float64str3str1int64str198str61str61str6boolfloat64str9str9
scienceSDSSSDSS Legacy ImagingSDSS CameraSDSSu;g;r;i;zOPTICAL001449-5-0093FIELDsdss_image_001449-5-0093199.759449788-21.0895968268imageSDSS Collaboration351667.20852372685551667.2124647853753.907456304.799999999999951083.3000000000002Sloan Digital Sky Survey (SDSS) Legacy Imaging Data55571.0N/A----POLYGON 199.68382220371453 -21.209641458700236 199.6605346260022 -20.98555578244084 199.83496672259864 -20.969628194410113 199.8585150712067 -21.19368991756911 199.68382220371453 -21.209641458700236mast:SDSS/sdss/imaging/1449/5/93/frame-irg-001449-5-0093.jpgmast:SDSS/sdss/imaging/1449/5/93/photoObj-001449-5-0093.fitsPUBLICFalsenan298381053885786836
scienceSDSSSDSS Legacy ImagingSDSS CameraSDSSu;g;r;i;zOPTICAL004381-2-0120FIELDsdss_image_004381-2-0120188.89366000914.4440133289imageSDSS Collaboration353032.40896319444453032.41290436870653.907456304.799999999999951083.3000000000002Sloan Digital Sky Survey (SDSS) Legacy Imaging Data55571.0N/A----POLYGON 188.8072050207449 14.332814743629992 188.81110366536907 14.557938939364815 188.98019947543165 14.55507039558893 188.97612983550505 14.329949038635592 188.8072050207449 14.332814743629992mast:SDSS/sdss/imaging/4381/2/120/frame-irg-004381-2-0120.jpgmast:SDSS/sdss/imaging/4381/2/120/photoObj-004381-2-0120.fitsPUBLICFalsenan298353167885509568
scienceSDSSSDSS Legacy ImagingSDSS CameraSDSSu;g;r;i;zOPTICAL007932-2-0051FIELDsdss_image_007932-2-00516.5284008943621.7582967467imageSDSS Collaboration354857.1467420138954857.1506830724153.907456304.799999999999951083.3000000000002Sloan Digital Sky Survey (SDSS) Legacy Imaging Data55571.0N/A----POLYGON 6.439077306737359 21.646492711571536 6.441505431337264 21.87164565721037 6.617862374334172 21.869942774151156 6.615157893982057 21.644792545902753 6.439077306737359 21.646492711571536mast:SDSS/sdss/imaging/7932/2/51/frame-irg-007932-2-0051.jpgmast:SDSS/sdss/imaging/7932/2/51/photoObj-007932-2-0051.fitsPUBLICFalsenan298320511885204258

Irregular Galaxies#

Irregular galaxies are galaxies that do not fit into the elliptical or spiral/barred spiral categories. They typically have chaotic or asymmetric structures, often resulting from violent interactions with other galaxies, collisions, or internal processes. Well-known examples include the Large and Small Magellanic Clouds [9].

We’ll use the following fields for each galaxy:

  • IC 3583 field: 003836-5-0268

  • NGC 7292 field: 008115-6-0118

# Irregular galaxies
irregulars = Observations.query_criteria(
    provenance_name="SDSS Legacy Imaging",
    target_name=[
        "003836-5-0268",  # IC 3583
        "008115-6-0118",  # NGC 7292
    ],
)
irregulars
Table masked=True length=2
intentTypeobs_collectionprovenance_nameinstrument_nameprojectfilterswavelength_regiontarget_nametarget_classificationobs_ids_ras_decdataproduct_typeproposal_picalib_levelt_mint_maxt_exptimeem_minem_maxobs_titlet_obs_releaseproposal_idproposal_typesequence_numbers_regionjpegURLdataURLdataRightsmtFlagsrcDenobsidobjID
str7str4str19str11str4str9str7str13str5str24float64float64str5str18int64float64float64float64float64float64str51float64str3str1int64str197str61str61str6boolfloat64str9str9
scienceSDSSSDSS Legacy ImagingSDSS CameraSDSSu;g;r;i;zOPTICAL003836-5-0268FIELDsdss_image_003836-5-0268189.17505973513.1998869096imageSDSS Collaboration352729.24177372685552729.2457149011153.907456304.799999999999951083.3000000000002Sloan Digital Sky Survey (SDSS) Legacy Imaging Data55571.0N/A----POLYGON 189.08925682499807 13.088602004029513 189.09279407361726 13.313649665325844 189.26093904132443 13.311033284196608 189.25724699913016 13.085987980105468 189.08925682499807 13.088602004029513mast:SDSS/sdss/imaging/3836/5/268/frame-irg-003836-5-0268.jpgmast:SDSS/sdss/imaging/3836/5/268/photoObj-003836-5-0268.fitsPUBLICFalsenan297915282881405426
scienceSDSSSDSS Legacy ImagingSDSS CameraSDSSu;g;r;i;zOPTICAL008115-6-0118FIELDsdss_image_008115-6-0118337.06316540130.3475793355imageSDSS Collaboration355122.1094153935255122.113356336353.907456304.799999999999951083.3000000000002Sloan Digital Sky Survey (SDSS) Legacy Imaging Data55571.0N/A----POLYGON 337.0043270910967 30.21800053821113 336.9384683229479 30.435781036316044 337.12219177360197 30.47702529132038 337.18766967475585 30.259153076577768 337.0043270910967 30.21800053821113mast:SDSS/sdss/imaging/8115/6/118/frame-irg-008115-6-0118.jpgmast:SDSS/sdss/imaging/8115/6/118/photoObj-008115-6-0118.fitsPUBLICFalsenan297726821879149237

Downloading SDSS Legacy Imaging Survey Data Products#

For each image, there are 7 available products: The preview .jpg image, the FITS files in each respective SDSS filter (u, g, r, i, and z), and a catalog file containing photometric measurements from all five filters combined. The catalog file is listed as SDSS Imaging Catalogs for the productSubGroupDescription parameter.

For more information about products available at MAST, you can check out the SDSS Legacy Imaging Survey Documentation.

# Combining the Astropy tables for all galaxies
all_galaxies = vstack(
    [ellipticals, lenticular, spirals, barred_spirals, irregulars]
)

# Viewing available products (first 7)
galaxy_products = Observations.get_product_list(all_galaxies)
galaxy_products[:7]
Table masked=True length=7
obsIDobs_collectiondataproduct_typeobs_iddescriptiontypedataURIproductTypeproductGroupDescriptionproductSubGroupDescriptionproductDocumentationURLprojectprvversionproposal_idproductFilenamesizeparent_obsiddataRightscalib_levelfilters
str9str4str12str28str246str1str64str7str28str21str48str19str3str3str30int64str9str6int64str9
297726821SDSSimagesdss_image_008115-6-0118Preview-FullSmast:SDSS/sdss/imaging/8115/6/118/frame-irg-008115-6-0118.jpgPREVIEW------SDSS Legacy ImagingDR8N/Aframe-irg-008115-6-0118.jpg1041251297726821PUBLIC3u;g;r;i;z
297726821SDSSimagesdss_image_008115-6-0118SDSS calibrated, sky-subtracted corrected photometry frame and associated calibration metadata for each run number, camera column, and field name within SDSS.Smast:SDSS/sdss/imaging/8115/6/118/frame-g-008115-6-0118.fits.bz2SCIENCEMinimum Recommended ProductsIMAGEhttps://archive.stsci.edu/missions-and-data/sdssSDSS Legacy ImagingDR8N/Aframe-g-008115-6-0118.fits.bz23077536297726821PUBLIC2g
297726821SDSSimagesdss_image_008115-6-0118SDSS calibrated, sky-subtracted corrected photometry frame and associated calibration metadata for each run number, camera column, and field name within SDSS.Smast:SDSS/sdss/imaging/8115/6/118/frame-i-008115-6-0118.fits.bz2SCIENCEMinimum Recommended ProductsIMAGEhttps://archive.stsci.edu/missions-and-data/sdssSDSS Legacy ImagingDR8N/Aframe-i-008115-6-0118.fits.bz23876498297726821PUBLIC2i
297726821SDSSimagesdss_image_008115-6-0118SDSS calibrated, sky-subtracted corrected photometry frame and associated calibration metadata for each run number, camera column, and field name within SDSS.Smast:SDSS/sdss/imaging/8115/6/118/frame-r-008115-6-0118.fits.bz2SCIENCEMinimum Recommended ProductsIMAGEhttps://archive.stsci.edu/missions-and-data/sdssSDSS Legacy ImagingDR8N/Aframe-r-008115-6-0118.fits.bz23661286297726821PUBLIC2r
297726821SDSSimagesdss_image_008115-6-0118SDSS calibrated, sky-subtracted corrected photometry frame and associated calibration metadata for each run number, camera column, and field name within SDSS.Smast:SDSS/sdss/imaging/8115/6/118/frame-u-008115-6-0118.fits.bz2SCIENCEMinimum Recommended ProductsIMAGEhttps://archive.stsci.edu/missions-and-data/sdssSDSS Legacy ImagingDR8N/Aframe-u-008115-6-0118.fits.bz23537982297726821PUBLIC2u
297726821SDSSimagesdss_image_008115-6-0118SDSS calibrated, sky-subtracted corrected photometry frame and associated calibration metadata for each run number, camera column, and field name within SDSS.Smast:SDSS/sdss/imaging/8115/6/118/frame-z-008115-6-0118.fits.bz2SCIENCEMinimum Recommended ProductsIMAGEhttps://archive.stsci.edu/missions-and-data/sdssSDSS Legacy ImagingDR8N/Aframe-z-008115-6-0118.fits.bz23897222297726821PUBLIC2z
297726821SDSSimagesdss_image_008115-6-0118SDSS Legacy Imaging photoObj catalog. This contains the full, calibrated outputs of the SDSS Imaging Pipeline including source detection, classification, magnitude measurements, and quality flags for each field and all five filters in that field.Smast:SDSS/sdss/imaging/8115/6/118/photoObj-008115-6-0118.fitsSCIENCEMinimum Recommended ProductsSDSS Imaging Catalogshttps://archive.stsci.edu/missions-and-data/sdssSDSS Legacy ImagingDR8N/AphotoObj-008115-6-0118.fits5705280297726821PUBLIC3u;g;r;i;z

We’ll now download all FITS files, specifically focusing on the files in specific ugriz filters. For this tutorial, we’ll be using the g, r, and i filters only, so we can filter those out using the filters parameter.

# Downloading products
manifest = Observations.download_products(
    galaxy_products, mrp_only=True, verbose=False, filters=["g", "r", "i"]
)

Each FITS file follows the following naming scheme: frame-{filter}-{RUN}-{CAMCOL}-{FIELD} where RUN is the zero-padded, six-digit identification number for that photometric run, CAMCOL is the camera column identifying the scanline within the run, and FIELD is field number for that observation.

While we won’t be using the photoObj files in this tutorial, these contain the fully calibrated outputs from the SDSS Imaging Pipeline and other respective measurements such as photometry in all five SDSS filters (u, g, r, i, and z), source classification, and quality flags. There is one photoObj file for each run-camcol-field combination.

Creating the Cutout Images Using Astrocut#

Now that we downloaded the FITS files for each galaxy, we can use Astrocut to trim the images and create cutouts!

Astrocut uses FITS files and specified center coordinates to create a trimmed image. We’ll create a dictionary of galaxy names, their target names, and center coordinates. For more information about Astrocut, you can view the documentation.

We’ll use warnings.filterwarnings to suppress FITS warnings due to the change in keyword names since SDSS data was created.

Each Astrocut image cell takes a few seconds to run!

# Suppressing FITS warnings
warnings.filterwarnings("ignore", category=astropy.wcs.FITSFixedWarning)

In order to center the galaxy in our cutout, we need to know the center coordinates! We can use astroquery to resolve the coordinates for each galaxy using Observations.resolve_object. We’ll now make a dictionary to code in the field ID and coordinates per galaxy.

# Making a dictionary for galaxy names with MAST target names and coordinates
galaxies = {
    "m89": {
        "id": "003804-4-0207",
        "coord": Observations.resolve_object("m89"),
    },
    "ngc5982": {
        "id": "004679-1-0034",
        "coord": Observations.resolve_object("ngc5982"),
    },
    "ngc4697": {
        "id": "006121-1-0124",
        "coord": Observations.resolve_object("ngc4697"),
    },
    "ngc3384": {
        "id": "003631-1-0302",
        "coord": Observations.resolve_object("ngc3384"),
    },
    "ngc488": {
        "id": "007727-5-0202",
        "coord": Observations.resolve_object("ngc488"),
    },
    "m88": {
        "id": "004381-2-0114",
        "coord": Observations.resolve_object("m88"),
    },
    "m99": {
        "id": "004381-2-0093",
        "coord": Observations.resolve_object("m99"),
    },
    "ngc109": {
        "id": "007932-2-0051",
        "coord": Observations.resolve_object("ngc109"),
    },
    "m91": {
        "id": "004381-2-0120",
        "coord": Observations.resolve_object("m91"),
    },
    "ngc5068": {
        "id": "001449-5-0093",
        "coord": Observations.resolve_object("ngc5068"),
    },
    "ic3583": {
        "id": "003836-5-0268",
        "coord": Observations.resolve_object("ic3583"),
    },
    "ngc7292": {
        "id": "008115-6-0118",
        "coord": Observations.resolve_object("ngc7292"),
    },
}
# Creating a function to locate files from download, find the r, g, and i files
def get_files_for_galaxy(galaxy_name):
    """
    Finds the files based on galaxy name and returns their r, g, and i FITS files
    """

    # Finding the file by galaxy name
    galaxy_mask = (
        np.char.find(
            manifest["Local Path"].astype(str), galaxies[galaxy_name]["id"]
        )
        >= 0
    )
    files = np.array(manifest["Local Path"][galaxy_mask], dtype=str)

    # Decompressing the files
    fits_files = np.array([], dtype=str)
    for file in files:
        fits_filename = file.replace('.bz2', '')
        fits_files = np.append(fits_files, fits_filename)
        with bz2.open(file, 'rb') as compressed_file:
            with open(fits_filename, 'wb') as decompressed_file:
                decompressed_file.write(compressed_file.read())

    # Finding the r, g, and i files
    rmask = np.char.find(fits_files, "frame-r") >= 0
    gmask = np.char.find(fits_files, "frame-g") >= 0
    imask = np.char.find(fits_files, "frame-i") >= 0

    r_file = fits_files[rmask]
    g_file = fits_files[gmask]
    i_file = fits_files[imask]

    return i_file[0], r_file[0], g_file[0]
# Helper function for creating cutout images
def create_cutouts(galaxy_name, cutout_size):
    """
    This function takes the name of the galaxy and size of the cutout,
    creates cutout using Astrocut, then plots the image using matplotlib
    """

    # Using previous function to get the r, g, and i files
    galaxy_input = get_files_for_galaxy(galaxy_name)

    # Creating the cutouts
    galaxy_colorimage = FITSCutout(
        galaxy_input, galaxies[galaxy_name]["coord"], cutout_size
    ).get_image_cutouts(colorize=True)[0]
    galaxy_colorimage.save(f"{galaxy_name}_cutout.png")

    # Capitalizing the title
    title_name = np.char.upper(galaxy_name)

    # Displaying the cutouts
    plt.figure(figsize=(5, 5))
    plt.imshow(galaxy_colorimage)
    plt.title(f"Cutout of {title_name}")
    plt.show()
# M89
# Creating and displaying the cutout image of M89!
m89_img = create_cutouts("m89", [200, 200])
../../../_images/adfdb33fd5b827ea01b13d9779a789ef66bee9b83aa2a059a5eac96e5d501b69.png
# NGC 5982
# Creating and displaying the cutout image of NGC 5982!
ngc5982_img = create_cutouts("ngc5982", [200, 200])
../../../_images/f26915a4bba2c5e5e0ecfcf87968ce148996bfdb802f783f0c9033e8b2e6b6b2.png
# NGC 4697
# Creating and displaying the cutout image of NGC 4697!
ngc4697_img = create_cutouts("ngc4697", [300, 200])
../../../_images/5e6684438674f7210d9594b8c6cec48e4da1b57c73ea1739d2d847c8affe54de.png
# NGC 3384
# Creating and displaying the cutout image of NGC 3384!
ngc3384_img = create_cutouts("ngc3384", [175, 175])
../../../_images/8c616fedaa690ca903d5f5d5f1fd36480826e2eba851ad1aba91c6ed43610f94.png
# NGC 488
# Creating and displaying the cutout image of NGC 488!
ngc488_img = create_cutouts("ngc488", [440, 500])
../../../_images/049761b31aa22b8c72d01161cb637c2fca9269b104f8945b4d25f63a593ae887.png
# M88
# Creating and displaying the cutout image of M88!
m88_img = create_cutouts("m88", [700, 600])
../../../_images/0c5ef70d311c9e99603509164d5009d68db36c97d0c8a958b9bfa7caf0865a78.png
# M99
# Creating and displaying the cutout image of M99!
m99_img = create_cutouts("m99", [600, 600])
../../../_images/5800b2a327af6d1b19ce608be8aa043fe5c1a0495efa500a9915d6801d4c744d.png
# NGC 109
# Creating and displaying the cutout image of NGC 109!
ngc109_img = create_cutouts("ngc109", [200, 200])
../../../_images/d26a81e375b9176c1e4154498e5a640aea36bb41afe9ebdc32426fe7624fe557.png
# M91
# Creating and displaying the cutout image of M91!
m91_img = create_cutouts("m91", [275, 425])
../../../_images/8ebbbc57adfb9efac4849d37a802b483914baaf3f8881ec3a3a041f8e5ad3380.png
# NGC 5068
# Creating and displaying the cutout image of NGC 5068!
ngc5068_img = create_cutouts("ngc5068", [800, 800])
../../../_images/71a47ddd1e15aed91858c30f19aec67d90471606a7cd9bd2746f2d57638c4e3b.png
# IC 3583
# Creating and displaying the cutout image of IC 3583!
ic3583_img = create_cutouts("ic3583", [300, 150])
../../../_images/17970a72f03b073e3121b8d9c32885f089f0ef87add8a619e40dbd4cadecb4d2.png
# NGC 7292
# Creating and displaying the cutout image of NGC 7292!
ngc7292_img = create_cutouts("ngc7292", [250, 300])
../../../_images/fd30edee48d7c334aee5107df82ee24760e9c17d871b45a3fef432ac2afcfa19.png

Making the Hubble Tuning Fork Diagram#

Now that we have our cutouts saved as .png files, we can create our Hubble Tuning Fork Diagram using matplotlib.image and a series of subplots!

# Creating subplots
fig, ax = plt.subplots(nrows=5, ncols=9, figsize=(15, 10), facecolor="black")
for row in ax:
    for a in row:
        a.axis("off")

# Reading the cutout images
images = {}
for galaxy in galaxies.keys():
    images[galaxy] = mpimg.imread(f"{galaxy}_cutout.png")

# Ading connecting lines
# Straight line
x = np.linspace(0, 10, 11)
y1 = 5 * np.ones(11)


# Plotting the images and lines
# Plotting the elliptical galaxies in the center left
ax[2, 0].imshow(images["m89"])
ax[2, 0].set_title("M89\nE0", y=-0.5, color="white", fontsize=14)
ax[2, 1].imshow(images["ngc5982"])
ax[2, 1].set_title("NGC 5982\nE3", y=-0.5, color="white", fontsize=14)
ax[2, 2].imshow(images["ngc4697"])
ax[2, 2].set_title("NGC 4697\nE6", y=-0.98, color="white", fontsize=14)

# Plotting the connecting straight line
ax[2, 3].plot(x, y1, color="white", lw=4)

# Plotting the lenticular galaxy between the ellipticals and spirals
ax[2, 4].imshow(images["ngc3384"])
ax[2, 4].set_title("NGC 3384\nS0", y=-0.5, color="white", fontsize=14)

# Plotting the connecting v line
ax[2, 5].plot((lambda x: np.abs(x - 5))(x), x, color="white", lw=4)
ax[2, 5].set_xlim(0, 5)

# Plotting the spiral galaxies in the top right
ax[1, 6].imshow(images["ngc488"])
ax[1, 6].set_title("NGC 488\nSa", y=-0.5, color="white", fontsize=14)
ax[1, 7].imshow(images["m88"])
ax[1, 7].set_title("M88\nSb", y=-0.82, color="white", fontsize=14)
ax[1, 8].imshow(images["m99"])
ax[1, 8].set_title("M99\nSc", y=-0.63, color="white", fontsize=14)

# Plotting the barred spirals in the bottom right
ax[3, 6].imshow(images["ngc109"])
ax[3, 6].set_title("NGC 109\nSBa", y=-0.68, color="white", fontsize=14)
ax[3, 7].imshow(images["m91"])
ax[3, 7].set_title("M91\nSBb", y=-0.45, color="white", fontsize=14)
ax[3, 8].imshow(images["ngc5068"])
ax[3, 8].set_title("NGC5068\nSBc", y=-0.68, color="white", fontsize=14)

# Plotting the irregular galaxies in the bottom left
ax[4, 0].imshow(images["ic3583"])
ax[4, 0].set_title("IC 3583", y=-1.43, color="white", fontsize=14)
ax[4, 1].imshow(images["ngc7292"])
ax[4, 1].set_title("NGC 7292", y=-0.3, color="white", fontsize=14)

# Adding labels
fig.text(
    0.3,
    0.815,
    "Hubble Tuning Fork Diagram",
    fontsize=30,
    fontstyle="oblique",
    fontweight="bold",
    color="white",
)
fig.text(
    0.35,
    0.78,
    "Made using SDSS Legacy Imaging Data at MAST",
    fontsize=15,
    fontstyle="oblique",
    # fontweight="bold",
    color="white",
)
fig.text(
    0.22, 0.57, "Elliptical", color="white", fontsize=16, fontweight="bold"
)
fig.text(
    0.475, 0.57, "Lenticular", color="white", fontsize=16, fontweight="bold"
)
fig.text(0.75, 0.74, "Spiral", color="white", fontsize=16, fontweight="bold")
fig.text(
    0.725,
    0.425,
    "Barred Spiral",
    color="white",
    fontsize=16,
    fontweight="bold",
)
fig.text(
    0.172, 0.27, "Irregular", color="white", fontsize=16, fontweight="bold"
)

plt.show()
../../../_images/b0ce6dd2ab17250c5cc91c9dc17129763688b2837672279083cee58594f8fbe5.png

End of Tutorial#

Congratulations, you’ve reached the end of this notebook! You’ve learned how to use astroquery.mast and astrocut to create a Hubble Tuning Fork Diagram!


Exercise#

Can you classify these three galaxies referencing the Hubble Tuning Fork Diagram you constructed above?:

  • M95

  • NGC 4125

  • M74

To choose the right field, you can look at the AstroView on the MAST Portal.

(Hint: You can download just the preview image by using Observations.filter_products and adding the argument productType="PREVIEW")

# Query and download data from MAST
# View preview images

Exercise Solution#

# Query and download data from MAST
# Querying MAST
exercise_galaxies = Observations.query_criteria(
    provenance_name="SDSS Legacy Imaging",
    target_name=["003836-4-0084", "006118-3-0168", "007845-2-0104"],
)
# Get product list for query
exercise_products = Observations.get_product_list(exercise_galaxies)
# Filter products to get preview jpgs only
filtered_products = Observations.filter_products(
    exercise_products,
    # Selecting preview jpgs
    productType="PREVIEW",
)
# Download products
Observations.download_products(filtered_products, flat=True, verbose=False)
Table length=3
Local PathStatusMessageURL
str29str8objectobject
./frame-irg-003836-4-0084.jpgCOMPLETENoneNone
./frame-irg-006118-3-0168.jpgCOMPLETENoneNone
./frame-irg-007845-2-0104.jpgCOMPLETENoneNone
# Viewing the previews side-by-side
fig2, ax2 = plt.subplots(nrows=1, ncols=3, figsize=(15, 10), facecolor="black")
for a in ax2:
    a.axis("off")

# Reading images
img1 = mpimg.imread("frame-irg-003836-4-0084.jpg")
img2 = mpimg.imread("frame-irg-006118-3-0168.jpg")
img3 = mpimg.imread("frame-irg-007845-2-0104.jpg")

# Plotting images
ax2[0].imshow(img1)
ax2[0].set_title("M95", color="white", y=-0.2, fontsize=14, fontweight="bold")
ax2[1].imshow(img2)
ax2[1].set_title(
    "NGC 4125", color="white", y=-0.2, fontsize=14, fontweight="bold"
)
ax2[2].imshow(img3)
ax2[2].set_title("M74", color="white", y=-0.2, fontsize=14, fontweight="bold")

plt.show()
../../../_images/3fe6bcb55e7e67b4fed9e354d018f786f08da6aacfb0380a0d847ef0f64cc10f.png

Assumptions:

  • It appears that M95 is fairly similar to NGC 109 and M91; this must be a barred spiral galaxy! While the spiral arms are somewhat tight, M95 is most likely between an SBa and an SBb.

  • NGC 4125 does not have spiral arms or dust lanes, so it must be elliptical. Since elliptical galaxies are classified by their ellipticity, NGC 4125 is likely between an E3 and an E6.

  • M74 has distinct spiral arms, but no visible bar. The spiral arms are fairly loose, but not as loose as M99. M74 is likely between an Sb and an Sc galaxy.

Results from NED:

  • M95: SBb

  • NGC 4125: E6

  • M74: Sc


Additional Resources#

Additional resources are linked below:

Citations#

If you use data from MAST for published research, please see the following links for information on which citations to include in your paper:

About this Notebook#

Author(s): Natalie Haugen (nhaugen@terpmail.umd.edu) and Julie Imig (jimig@stsci.edu)
Keyword(s): Tutorial, SDSS, SDSS Legacy Imaging Survey, galaxies, galaxy morphology
First published: July 2025
Last updated: July 2025


Top of Page Space Telescope Logo