{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Demo Notebook\n",
    "\n",
    "# Photometry example using DS9 and Photutils"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This notebook shows an example of some quick photometry investigation using imexam the photutils package.\n",
    "\n",
    "**In order to run you must install photutils, an astropy affiliated photometry package.**\n",
    "\n",
    "You can install the latest stable version using: \" pip install --no-deps photutils \""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#The nbAgg backend allows for nice plotting control inside the notebook,qt5agg should also work  \n",
    "#%matplotlib notebook"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Import the required modules.\n",
    "import os\n",
    "from astropy.io import ascii, fits\n",
    "import matplotlib.pyplot as plt\n",
    "import matplotlib.image as mpimage\n",
    "import numpy as np\n",
    "import photutils\n",
    "from photutils.detection import DAOStarFinder"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Read in Data\n",
    "you can choose an example image of your own, if so replace the image name below"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Load the image we are going to use in read-only mode\n",
    "# \n",
    "hdulist = fits.open('iacs01t4q_flt.fits')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Similar to catfits in iraf\n",
    "hdulist.info()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(f'Instrument: {hdulist[0].header[\"instrume\"]}')\n",
    "print(f'Detector: {hdulist[0].header[\"detector\"]}')\n",
    "print(f'Target Name: {hdulist[0].header[\"targname\"]}')\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Let's Science!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We're going to show you two different ways to do this. \n",
    "The first example is just a quick way to look at your image"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#display a quick image to see what we are working with, you can even use matplotlib here\n",
    "image = hdulist[1].data\n",
    "plt.imshow(image, vmin=-1.5, vmax=1.5, cmap=plt.cm.gray, origin='lower')\n",
    "plt.colorbar() #for reference       "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#how about displaying our image in DS9 so we can interact with it a bit more?\n",
    "#Here I'll import imexam and open a connection to ds9 on my desktop\n",
    "import imexam\n",
    "a=imexam.connect() #let ds9 start before starting the next cell"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a.load_fits('iacs01t4q_flt.fits')\n",
    "a.scale()\n",
    "a.zoomtofit()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Extract keyword values that we will need.\n",
    "# Note: Keyword names and units may vary for other instruments. Consult DHB.\n",
    "\n",
    "header = hdulist[0].header\n",
    "exptime   = header['EXPTIME']   # seconds\n",
    "photflam  = header[\"PHOTFLAM\"]  # ergs cm^-2 ang^-1 s^-1\n",
    "photplam  = header[\"PHOTPLAM\"]  # erg cm^-2 s^-1 Hz^-1\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "stzpt = -2.5 * np.log10(photflam* 1.0) - 21.1\n",
    "abmag = -2.5 * np.log10(photflam*1.0) - 21.1 -  5 * np.log10(photplam) + 18.692"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print('Exposure time: {0}'.format(exptime))\n",
    "print('STMAG zeropoint: {0}'.format(stzpt))\n",
    "print('ABMAG zeropoint: {0}'.format(abmag))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Finding Sources - using photutils"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "image = hdulist[1].data  # Input will be EXT 1, same as above"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#now we subtract a median background from the image, consider what you are doing here,'\n",
    "#taking the straight median might not be the best way in such a crowded field. We will\n",
    "#Use the background subtracted image for the rest of the example\n",
    "skybkg=np.median(image)\n",
    "print(skybkg)\n",
    "image -= skybkg"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#let's also get the background deviation\n",
    "from astropy.stats import median_absolute_deviation as mad\n",
    "bkg_sigma = 1.4826 * mad(image)\n",
    "print(bkg_sigma)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#now we'll use the daofind method in photutils to find out sources\n",
    "sources = DAOStarFinder(fwhm=2.5, threshold=3.*bkg_sigma)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# See just a few lines of output, with no print it uses a pretty print in the notebook\n",
    "source_cat=sources.find_stars(image)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "source_cat"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Visualizing the Sources\n",
    "<p align=\"left\">... and taking advantage of astropy tables </p>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# what does daofind return?\n",
    "print(type(sources))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# extract xcenter values\n",
    "xcen=source_cat['xcentroid']\n",
    "print(xcen)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Plot of the sharpness versus the mag as blue pluses\n",
    "plt.plot(source_cat['sharpness'], source_cat['mag'], 'b+')\n",
    "plt.title('Mag vs. Sharpness from photutils')\n",
    "plt.ylabel('Mag')\n",
    "plt.xlabel('Sharpness')\n",
    "\n",
    "# Save the plot as a PDF.\n",
    "# Matplotlib automatically determines format from given extension.\n",
    "#plt.savefig('sharp_v_mag_photutil.pdf')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Select stars with sharpness greater than 0.9\n",
    "# use boolean arrays\n",
    "\n",
    "#Want to save a table of just the sharper sources? You can do this:\n",
    "sharp_sources = source_cat[source_cat['sharpness'] >0.95]\n",
    "sharp_sources\n",
    "\n",
    "print('Number of sharp stars: {0}'.format(len(sharp_sources)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Plot the image again in a different color using matplotlib, just as an example\n",
    "plt.imshow(image, vmin=-3., vmax=3., cmap=plt.cm.jet)\n",
    "\n",
    "# Only show the high sharpness stars as black circles.\n",
    "plt.plot(sharp_sources['xcentroid'], sharp_sources['ycentroid'], 'ko', mfc='None')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#now lets do the same thing in DS9\n",
    "stars = zip(sharp_sources['xcentroid'],sharp_sources['ycentroid'],sharp_sources['id'])\n",
    "stars"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a.mark_region_from_array(stars)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Aperture Photometry"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#photutils takes an aperture specfication along with the image as input:\n",
    "#You can do a local background subtraction by specifying the apertures for the background in a similar manner\n",
    "from photutils import aperture_photometry, CircularAperture\n",
    "positions = [(x,y) for x,y in zip(sharp_sources['xcentroid'], sharp_sources['ycentroid'])]   \n",
    "apertures = CircularAperture(positions, r=4.)    \n",
    "phot_table = aperture_photometry(image, apertures)    \n",
    "phot_table"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Analyze Photometry Results"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's make a histogram of the recovered instrumental magnitudes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "mags=phot_table['aperture_sum']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#wfc3 ir data is already in countrate, but no aperture correction has been applied here yet\n",
    "goodmags=-2.5 *np.log10(mags[mags>0.] * photflam) - 21.1 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Nifty, right? Now lets plot a histogram of our values\n",
    "plt.hist(goodmags, bins=20)\n",
    "plt.xlabel('Mag')\n",
    "plt.ylabel('N')\n",
    "plt.title('Recovered Valid Magnitudes')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note: The mags above are different from the mags in the iraf example mostly because a different zeropoint was used (as input to the phot task in the pars parameter set)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Closing Time"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# It is a good practice to close any open file pointers.\n",
    "# You might also want to check out the notes on  using the \"with open as\" clause\n",
    "hdulist.close()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a.close() #close the ds9 window"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
