Comparing dithered vs non-dithered

Two catalogues were created from the same field where one set of data included dithering at two levels, $3\mathrm{"}$ and $30\mathrm{"}$. The other data set included no dithering. These files are contained in catalogue-matching/topcat-match.fits.


In [278]:
import fitsio
from astropy.coordinates import ICRS
from astropy import units as u
from scipy import stats
from pyslalib import slalib

rc('lines', markersize=2)

In [279]:
def analyse_hdu(hdu):
    data = hdu['RA', 'DEC', 'RAJ2000', 'DEJ2000'].read()
    
    test_point = ICRS(ra=data['RA'], dec=data['DEC'], unit=(u.radian, u.radian))
    ref_point = ICRS(ra=data['RAJ2000'], dec=data['DEJ2000'], unit=(u.degree, u.degree))
    separations = ref_point.separation(test_point)
    return separations.arcsecond

In [280]:
fname = 'catalogue-matching/topcat-match.fits'

with fitsio.FITS(fname) as infile:
    dithered_hdu = infile['dithered_match']
    normal_hdu = infile['normal_match']
    
    dithered_separations = analyse_hdu(dithered_hdu)
    normal_separations = analyse_hdu(normal_hdu)

In [281]:
plt.hist([dithered_separations, normal_separations], 30, label=['Dithered', 'Normal'],
         histtype='step')
plt.legend(loc='best')
plt.xlabel(r'Separation / arcseconds')


Out[281]:
<matplotlib.text.Text at 0x97d33d0>

We can see that overall the dithered data show smaller separations, but the tail is still quite long. What is the source for this long tail? We shall plot a few things:

  • separations vs brightness for the two fields
  • separations vs pixel phase
  • separations vs altitude (for differential refraction)
  • separations spatially over the image

Separations vs brightness


In [282]:
with fitsio.FITS(fname) as infile:
    jmag = infile['dithered_match']['Jmag'].read()

In [283]:
rms = lambda values: np.std(values) / float(values.size)

In [284]:
plt.plot(jmag, dithered_separations, 'k.')
plt.gca().invert_xaxis()
plt.xlabel(r'J magnitude')
plt.ylabel(r'Separation')

med_magnitudes, ledge, _ = stats.binned_statistic(jmag, dithered_separations, statistic='median', bins=20)
errs, _, _ = stats.binned_statistic(jmag, dithered_separations, statistic=rms, bins=ledge)

# plt.errorbar(ledge[:-1] + np.diff(ledge)[0] / 2., med_magnitudes, errs, ls='None', color='r')
plt.plot(ledge[:-1], med_magnitudes, 'r-', drawstyle='steps-post')


Out[284]:
[<matplotlib.lines.Line2D at 0x9895e90>]

So we can see from this that for this case the areas with highest RMS separation are above $\sim J = 8$ and towards the fainter magnitudes. This is not unexpected as brighter than $J=8$ the stars are saturated in NGTS data, and at fainter magnitudes the stars have more uncertainty in their pixel positions.

Separations vs pixel phase

Pixel phase can be computed from position % 1 to get the fractional position in each coordinate. If higher uncertainties are nearer pixel edges we should see a distribution which is high or low towards 0 and 1, and the opposite in between.


In [285]:
with fitsio.FITS(fname) as infile:
    data = infile['dithered_match']['X_coordinate', 'Y_coordinate'].read()
    
x, y = map(np.array, zip(*[(row['X_coordinate'], row['Y_coordinate']) for row in data]))
x_phase = x % 1
y_phase = y % 1

In [290]:
def display_phase_separations(axis, phase, separations):
    med, ledges, _ = stats.binned_statistic(phase, separations, statistic='median', bins=15)    
    errs, _, _ = stats.binned_statistic(phase, separations, statistic=rms, bins=ledges)
    ydata = np.hstack([med, [med[-1]]])
    edata = np.hstack([errs, [errs[-1]]])
    bin_centres = ledges + np.diff(ledges)[0] / 2.    
    
    # Plotting
    axis[0].plot(phase, separations, 'k.', alpha=0.2)
    axis[1].plot(ledges, ydata, 'r-', drawstyle='steps-post')    
    # axis[1].errorbar(bin_centres, ydata, edata, ls='None', color='r')
    

fig, axes = plt.subplots(2, 2)

for (axis, phase) in zip(axes, [x_phase, y_phase]):
    display_phase_separations(axis, phase, dithered_separations)


At a push there is a slight decrease in accuracy when stars are very near a pixel edge (at separation == 0). This is not visible in the raw data (left) but is apparent when binning.

Separations vs pixel coordinates

We already have the x and y coordinates for each matched star, we can display the separations in the third dimension somehow.


In [288]:
plt.scatter(x, y, c=dithered_separations, edgecolor='None', cmap='afmhot')
plt.colorbar()


Out[288]:
<matplotlib.colorbar.Colorbar instance at 0x90c88c0>

This display is not too useful, instead compute the median separation in bins.


In [289]:
stat, xedges, yedges, _ = stats.binned_statistic_2d(x, y, dithered_separations, 
                                                    statistic='median', 
                                                    bins=32)
m_stat = ma.masked_where(stat != stat, stat)
plt.pcolormesh(xedges[:-1], yedges[:-1], m_stat, cmap='afmhot')
plt.colorbar()
plt.axis(aspect='equal', xlim=(0, 2048), ylim=(0, 2048))
plt.xlim(0, 2048)
plt.ylim(0, 2048)


Out[289]:
(0, 2048)

There does seem to be a spatial dependence, at least it's not uniform. It does not seem to be worse in the corners particularly, just at the centre there is a bright spot towards the top right of the centre, and a dark spot at the lower left.

Separations vs altitude

As there seems to be no systematic dependence on chip position, there is probably no dependence on altitude. This would show up in a change in declination.


In [306]:
with fitsio.FITS(fname) as infile:
    dec = np.degrees(infile['dithered_match']['DEC'].read())

plt.plot(dec, dithered_separations, 'k.', alpha=0.3)
binned, ledges, _ = stats.binned_statistic(dec, dithered_separations, statistic='median', bins=30)
plt.plot(ledges[:-1], binned, 'r-', drawstyle='steps-post')


Out[306]:
[<matplotlib.lines.Line2D at 0x7f39c257bdd0>]