Aperture Photometry#

ztfimg images (quadrant, ccd or focalplane) have a get_aperture() method that is based on sep.

This method expects aperture centroids (x,y) and radius (potentially a list of). You can provide specific data, mask, and error images. It also includes tools like background annulus subtractions etc.


Star aperture photometry#

[1]:
import ztfimg
qimg = ztfimg.ScienceQuadrant.from_filename("ztf_20200924431759_000655_zr_c13_o_q3_sciimg.fits",
                                   as_path=False)

let’s get the gaia catalog associated to this quadrant

[2]:
cat = qimg.get_catalog("gaia", in_fov=True)

let’s see:

[4]:
%matplotlib notebook
fig = qimg.show()
ax = fig.axes[0]

ax.scatter(*cat[["x","y"]].values.T, marker="x", color="tab:orange")

ax.set_xlim(400,800)
ax.set_ylim(300,700)
[4]:
(300.0, 700.0)

Get the aperture photometry, using data masked for bad pixels.

We will use a 5-pixel radius aperture and a background annulus between 5 and 6 to estimate their background

[5]:
%%time
mask = qimg.get_mask()
flux, error, flag = qimg.get_aperture(*cat[["x","y"]].values.T, 5,
                                      mask=mask, bkgann=[5,6])
CPU times: user 235 ms, sys: 30.6 ms, total: 266 ms
Wall time: 264 ms

and let’s compare the observed magnitude with the gaia magnitude

[11]:
import numpy as np
magztf = -2.5*np.log10(flux) # some flux are negative; this will lead to nans
/var/folders/kt/dnsb_cyx445cbz2ht_3l2m6w00029p/T/ipykernel_25071/3743219432.py:2: RuntimeWarning: invalid value encountered in log10
  magztf = -2.5*np.log10(flux) # some flux are negative; this will lead to nans
[17]:
import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(111)

ax.scatter(cat["RPmag"], cat["RPmag"]-magztf, s=1, color="C0")
#ax.set_ylim(26,27)
ax.axhline(np.nanmedian(cat["RPmag"]-magztf), color="C1")

ax.set_xlabel("gaia r-band magnitude")
ax.set_ylabel("gaia-ztf “r-band“ magnitude")
[17]:
Text(0, 0.5, 'gaia-ztf “r-band“ magnitude')

In that figure, the orange band shows the median delta_magnitude. It is not centered at 0 because the image’s zp is not calibrated. The tail toward brightert magnitude at agai-rmag<11 is the ztf camera saturation.


Isolated stars#

To avoid cross-contamination, between stars one may want to only focus on isolated stars. Let’s get the “isolated” stars froml the gaia catalog by comparing it to itself.

[19]:
from ztfimg import catalog
[20]:
isolated = catalog.get_isolated(cat)
isolated
[20]:
1800      True
1807      True
1808      True
1812      True
1815     False
         ...
26296     True
26298    False
26299     True
26300     True
26311     True
Name: isolated, Length: 13899, dtype: bool

and let’s also take the stars that are between 12 and 20 gaia magnitude

[22]:
cat_good = cat[isolated & (cat["RPmag"].between(12,20))]
[25]:
%matplotlib notebook
fig = qimg.show()
ax = fig.axes[0]

ax.scatter(*cat[["x","y"]].values.T, marker="x", color="tab:blue") # blue means all
ax.scatter(*cat_good[["x","y"]].values.T, marker="x", color="tab:orange")# orange good isolated

ax.set_xlim(400,800)
ax.set_ylim(300,700)
[25]:
(300.0, 700.0)
[27]:
%%time
mask = qimg.get_mask()
flux, error, flag = qimg.get_aperture(*cat_good[["x","y"]].values.T, 5,
                                      mask=mask, bkgann=[5,6])

magztf_good = -2.5*np.log10(flux)
CPU times: user 225 ms, sys: 38.2 ms, total: 264 ms
Wall time: 262 ms
<timed exec>:5: RuntimeWarning: invalid value encountered in log10
[31]:
import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(111)

ax.scatter(cat["RPmag"], cat["RPmag"]-magztf, s=1, color="C0")
ax.scatter(cat_good["RPmag"], cat_good["RPmag"]-magztf_good, s=1, color="C1")
#ax.set_ylim(26,27)
ax.axhline(np.nanmedian(cat["RPmag"]-magztf), color="k")

ax.set_xlabel("gaia r-band magnitude")
ax.set_ylabel("gaia-ztf “r-band“ magnitude")
[31]:
Text(0, 0.5, 'gaia-ztf “r-band“ magnitude')

use cleaned image#

let’s change the data on which the aperture photometry is ran, adding, this time, no background annulus correction

[33]:
data_clean = qimg.get_data(apply_mask=True, rm_bkgd=True) # cleaned image
[34]:
%%time
mask = qimg.get_mask()
flux, error, flag = qimg.get_aperture(*cat_good[["x","y"]].values.T, 5,
                                      data=data_clean,
                                      mask=mask)

magztf_good_clean = -2.5*np.log10(flux)
CPU times: user 213 ms, sys: 21.2 ms, total: 234 ms
Wall time: 235 ms
<timed exec>:6: RuntimeWarning: invalid value encountered in log10
[38]:
import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(111)

ax.scatter(cat["RPmag"], cat["RPmag"]-magztf, s=1, color="C0")
ax.scatter(cat_good["RPmag"], cat_good["RPmag"]-magztf_good, s=1, color="C1")
ax.scatter(cat_good["RPmag"], cat_good["RPmag"]-magztf_good_clean, s=0.5, color="C2")
#ax.set_ylim(26,27)
ax.axhline(np.nanmedian(cat["RPmag"]-magztf), color="k")

ax.set_xlabel("gaia r-band magnitude")
ax.set_ylabel("gaia-ztf “r-band“ magnitude")
[38]:
Text(0, 0.5, 'gaia-ztf “r-band“ magnitude')

multiple radius at once#

The code is vectorized so you gain a lot by providing multiple radius at once if that is what you want.

Let’s say we want 10 radii between 1 and 8-pixels

[45]:
%%time
mask = qimg.get_mask()
radii = np.linspace(1, 8, 10)[:,None] # don't forget the broadcast !

flux, error, flag = qimg.get_aperture(*cat_good[["x","y"]].values.T,
                                      radii,
                                      data=data_clean,
                                      mask=mask)
CPU times: user 326 ms, sys: 25.2 ms, total: 351 ms
Wall time: 349 ms
[40]:
flux.shape
[40]:
(10, 8062)

Aperture photometry correction#

[48]:
flux_normed = flux/flux[-1]
[69]:
fig = plt.figure()
ax = fig.add_subplot(111)

median = np.nanmedian(flux_normed, axis=1)

ax.plot(radii, median)
ax.set_xlabel("radius in pixels")
ax.set_ylabel("median star flux")
[69]:
Text(0, 0.5, 'median star flux')