GALEX Visits

In this tutorial we are going to inspect the GALEX visits table. This is the full list of observations by GALEX available on MAST. During initialization of a GALEXField with given field ID this list is searched for all visits belonging to this field.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.offsetbox import AnchoredText
import pandas as pd
from astropy.table import Table

from vasca.resource_manager import ResourceManager
import vasca.utils as vutils
# Initialize ResourceManager
rm = ResourceManager()
gal_visits = rm.get_path("gal_visits_list", "vasca")
# tt_gal_visits is a table containing info about all GALEX visits
tt_gal_visits = Table.read(gal_visits)
tt_gal_visits.info()
<Table length=100865>
      name        dtype 
---------------- -------
    RATileCenter float64
   DECTileCenter float64
          survey  bytes3
        nexptime float64
        fexptime float64
        imgRunID   int64
  ParentImgRunID   int64
          joinID   int64
         tileNum   int64
     specTileNum   int64
          source  bytes6
   nPhotoObjects   int64
    nPhotoVisits   int64
    PhotoObsDate bytes22
         spectra  bytes5
        nSpectra  bytes4
  nSpectraVisits  bytes4
     SpecObsDate  bytes4
        visitNum   int64
          subvis   int64
 minPhotoObsDate bytes22
 maxPhotoObsDate bytes22
  minSpecObsDate  bytes4
  maxSpecObsDate  bytes4
PhotoObsDate_MJD float64
# Convert astropy Table to pandas DataFrame for better query/aggregation methods
# String columns are bytes in the Table representation and need to decoded in the DataFrame
df_gal_visits = tt_gal_visits.to_pandas().apply(
    lambda x: x.str.decode("utf-8") if x.dtype == "O" else x
)
RATileCenter DECTileCenter nexptime fexptime imgRunID ParentImgRunID joinID tileNum specTileNum nPhotoObjects nPhotoVisits visitNum subvis PhotoObsDate_MJD
Loading ITables v2.2.3 from the init_notebook_mode cell... (need help?)

Surveys

Find more about GALEX surveys on the documentation page AIS : All-Sky Imaging Survey. Exposure time of 100s over 26,000 square degrees of sky reaching a depth of mAB = 20-2 in both bands.

MIS

Medium Sky Imaging Survey. Single orbit exposures (1,500s) of 1000 square degrees in positions that match the Sloan Digital Sky Survey (SDSS) spectroscopic footprint.

DIS

Deep Sky Imaging Survey. Exposure goal of 30,000s over 80 square degrees of sky.

NGS

Nearby Galaxy Survey. Nearby galaxies with a nominal exposure time of 1000s to 1500s.

GII

Guest Investigator Imaging. 33% of observing time per year to peer reviewed proposals from the community.

CAI

Calibration Imaging. White dwarf standards for the purposes of calibration.

Survey Stats

Below are several statistics on the GALEX data set.

Tip

One of the many useful utility functions for visualization is color_palette. It returns a list of colors for given color map and specified number of elements

survey_names = ["AIS", "MIS", "DIS", "NGS", "GII", "CAI"]
n_surveys = len(survey_names)
survey_colors = vutils.color_palette("bright", n_surveys, show_in_notebook=True)
bright
bright colormap
under
bad
over
# Aggregate
df_survey_grpd = df_gal_visits.groupby("survey")
survey_stats = {}
for survey in survey_names:
    df_survey_visits = df_survey_grpd.get_group(survey)
    stats = {}
    stats["n_vis"] = len(df_survey_visits)
    stats["n_fd"] = len(df_survey_visits.ParentImgRunID.unique())
    stats["texp"] = df_survey_visits.nexptime.sum()
    survey_stats[survey] = stats

df_survey_stats = pd.DataFrame().from_dict(survey_stats).T
# df_survey_stats
n_vis n_fd texp
Loading ITables v2.2.3 from the init_notebook_mode cell... (need help?)

Number of visits

Hide code cell source
plot_name = "n_vis"
fig, ax = plt.subplots(num=plot_name, figsize=(3, 3), layout="constrained")

total = df_survey_stats.n_vis.sum()
text = AnchoredText(f"Total: {total:1.0f}", loc="upper right")
ax.add_artist(text)

bars = ax.bar(
    survey_names,
    df_survey_stats.n_vis,
    color=survey_colors,
)
ax.bar_label(bars, labels=[f"{x:1.0%}" for x in df_survey_stats.n_vis / total])
ax.margins(y=0.2)

ax.set_ylabel("Number of visits")
ax.set_xlabel("Survey")
ax.set_yscale("log")
ax.grid(visible=True, linewidth=0.5, color="k", alpha=0.3, zorder=0)
ax.tick_params(axis="y", direction="in", left=True, right=True, which="both")
ax.tick_params(axis="x", direction="in", top=True, bottom=True, which="both")
../_images/75e698163efb9d56ab0513d3a1bee27a78a444712febffe94d2eb19ffe341efe.png

Number of fields

Hide code cell source
plot_name = "n_fields"
fig, ax = plt.subplots(num=plot_name, figsize=(3, 3), layout="constrained")

total = df_survey_stats.n_fd.sum()
text = AnchoredText(f"Total: {total:1.0f}", loc="upper right")
ax.add_artist(text)

bars = ax.bar(
    survey_names,
    df_survey_stats.n_fd,
    color=survey_colors,
)
ax.bar_label(bars, labels=[f"{x:1.1%}" for x in df_survey_stats.n_fd / total])
ax.margins(y=0.2)
ax.margins(x=0.1)

ax.set_ylabel("Number of fields")
ax.set_xlabel("Survey")
ax.set_yscale("log")
ax.grid(visible=True, linewidth=0.5, color="k", alpha=0.3, zorder=0)
ax.tick_params(axis="y", direction="in", left=True, right=True, which="both")
ax.tick_params(axis="x", direction="in", top=True, bottom=True, which="both")
../_images/5cb848b4a433a8dee7d96bff521349d45ea51b4ff49d73db6a66f897875b15a6.png

Total exposure time

Hide code cell source
plot_name = "texp"
fig, ax = plt.subplots(num=plot_name, figsize=(3, 3), layout="constrained")

total = df_survey_stats.texp.sum()
text = AnchoredText(f"Total: {total:1.0f}", loc="upper right")
ax.add_artist(text)

bars = ax.bar(
    survey_names,
    df_survey_stats.texp,
    color=survey_colors,
)
ax.bar_label(bars, labels=[f"{x:1.0%}" for x in df_survey_stats.texp / total])
ax.margins(y=0.2)

ax.set_ylabel("Total exposure time [s]")
ax.set_xlabel("Survey")
ax.set_yscale("log")
ax.grid(visible=True, linewidth=0.5, color="k", alpha=0.3, zorder=0)
ax.tick_params(axis="y", direction="in", left=True, right=True, which="both")
ax.tick_params(axis="x", direction="in", top=True, bottom=True, which="both")
../_images/fb6d5f2f24ccefea15c5ca099bcfbe8232216b171e7bd517777e7276c625afab.png

Number of visits per field distribution

Tip

Another useful utility for visualization is the get_hist_bins function which returns the bin edges for given bin size and a list of non-uniform 1-D data sets.

Hide code cell source
survey_nvis = {}
for survey in survey_names:
    df_survey_visits = df_gal_visits.query("survey==@survey")
    df_fd_grpd = df_survey_visits.groupby("ParentImgRunID")
    survey_nvis[survey] = [len(df_grp) for _, df_grp in df_fd_grpd]
bins = vutils.get_hist_bins(list(survey_nvis.values()), bin_size=1)

plot_name = "nvis_dist"
fig, axs = plt.subplot_mosaic(
    [[x] for x in survey_names],
    num=plot_name,
    figsize=(3, 5),
    layout="constrained",
    sharey=False,
    sharex=True,
)

for i, survey in enumerate(survey_names):
    ax = axs[survey]

    ax.hist(survey_nvis[survey], bins=bins, color=survey_colors[i])

    text = AnchoredText(
        f"{survey}, med. = {np.asarray(survey_nvis[survey]).mean():1.0f}",
        loc="upper right",
        prop={"fontsize": 7},
    )
    ax.add_artist(text)

    ax.set_ylim((0.7, 1e5))
    ax.set_xscale("log")
    ax.set_yscale("log")

    ax.grid(visible=True, linewidth=0.5, color="k", alpha=0.3, zorder=0)
    ax.tick_params(axis="y", direction="in", left=True, right=True, which="both")
    ax.tick_params(axis="x", direction="in", top=True, bottom=True, which="both")

fig.supylabel("Number of fields")
_ = fig.supxlabel("Number of visits")
../_images/b86970e480a1d1b7c9b6db8f631d106a665c64b09c75fe341e201545e5edb63a.png

Exposure time distribution

Hide code cell source
bins = vutils.get_hist_bins(
    [df_gal_visits.query("survey==@x").nexptime.tolist() for x in survey_names],
    bin_size=10,  # Seconds
)

plot_name = "texp_dist"
fig, axs = plt.subplot_mosaic(
    [[x] for x in survey_names],
    num=plot_name,
    figsize=(3, 5),
    layout="constrained",
    sharey=True,
    sharex=True,
)

for i, survey in enumerate(survey_names):
    ax = axs[survey]
    data = df_gal_visits.query("survey==@survey").nexptime
    ax.hist(data, color=survey_colors[i], bins=bins, label=survey)

    text = AnchoredText(
        f"{survey}, med. = {np.median(data):1.0f} s",
        loc="upper right",
        prop={"fontsize": 7},
    )
    ax.add_artist(text)

    ax.set_ylim((10, 5e4))
    ax.set_xscale("log")
    ax.set_yscale("log")

    ax.grid(visible=True, linewidth=0.5, color="k", alpha=0.3, zorder=0)
    ax.tick_params(axis="y", direction="in", left=True, right=True, which="both")
    ax.tick_params(axis="x", direction="in", top=True, bottom=True, which="both")

fig.supylabel("Number of visits")
_ = fig.supxlabel("Exposure time [s]")
../_images/4cd6a9b65bfdd89f0e475cf5fb88c3d1b21750b29e6c6aaa1fdc9206a652580d.png