Exemplo n.º 1
0
def sub_sky_rings(fnlist, medfilelist):
    """Fits for night sky rings in a series of images, then subtracts them off.
    If uncertainty images exist, updates them with better uncertainties.

    The rings are fitted in an interactive way by the user.

    After the ring subtraction, the header keyword "fpdering" is created and
    set to "True."

    Note: A 'median.fits' image must exist for the object or this routine will
    not work.

    Inputs:
    fnlist -> List of strings, each the path to a fits image.
    medfilelist -> List of paths to median images for each image to subtract
                   off (probably all the same, but could be different)

    """

    # This bit takes care of the 's' to save shortcut in matplotlib.
    oldsavekey = plt.rcParams["keymap.save"]
    plt.rcParams["keymap.save"] = ""
    oldfullscreenkey = plt.rcParams['keymap.fullscreen']
    plt.rcParams['keymap.fullscreen'] = ""

    # Open all of the images, median-subtract them, make wavelength arrays
    # make skywavelibs for each, make spectra for each, trim images
    images = [FPImage(fn) for fn in fnlist]
    wavearraylist = []
    skywavelibs = []
    skywavelibs_extended = []
    spectrum_wave = []
    spectrum_inty = []
    minwavelist = []
    maxwavelist = []
    xcenlist = []
    ycenlist = []
    Flist = []
    wave0list = []
    has_been_saved = np.zeros(len(fnlist), dtype="bool")
    for i in range(len(fnlist)):
        # Get a bunch of relevant header values
        medimage = fits.open(medfilelist[i])
        Flist.append(images[i].calf)
        wave0list.append(images[i].wave0)
        xcen = images[i].xcen
        ycen = images[i].ycen
        arad = images[i].arad
        axcen = images[i].axcen
        aycen = images[i].aycen
        # Median subtract it
        images[i].inty -= medimage[0].data
        images[i].inty -= np.median(images[i].inty[images[i].badp != 1])
        # Make wavelength array
        r2grid = images[i].rarray(xcen, ycen)**2
        wavearraylist.append(wave0list[i]/np.sqrt(1+r2grid/Flist[i]**2))
        # Get the sky wave library
        minwavelist.append(np.min(wavearraylist[i][r2grid < arad**2]))
        maxwavelist.append(np.max(wavearraylist[i][r2grid < arad**2]))
        skywaves = get_libraries(images[i].filter)[1]
        skywavelibs.append(skywaves[np.logical_and(skywaves > minwavelist[i],
                                                   skywaves < maxwavelist[i])])
        # Make an "extended" sky wave library
        lowermask = np.logical_and(skywaves < minwavelist[i],
                                   skywaves > minwavelist[i]-5)
        uppermask = np.logical_and(skywaves > maxwavelist[i],
                                   skywaves < maxwavelist[i]+5)
        skywavelibs_extended.append(skywaves[np.logical_or(uppermask,
                                                           lowermask)])
        # Make the spectrum
        minwav = np.min(wavearraylist[i][r2grid < arad**2])
        maxwav = np.max(wavearraylist[i][r2grid < arad**2])
        wavstep = 0.25  # Quarter-angstrom spacing
        spectrum_wave.append(np.linspace(minwav, maxwav,
                                         np.int(((maxwav-minwav)/wavstep))))
        spectrum_inty.append(np.zeros_like(spectrum_wave[i][1:]))
        for j in range(len(spectrum_wave[i])-1):
            uppermask = wavearraylist[i] < spectrum_wave[i][j+1]
            lowermask = wavearraylist[i] > spectrum_wave[i][j]
            mask = np.logical_and(uppermask, lowermask)
            goodmask = np.logical_and(mask, images[i].badp == 0)
            spectrum_inty[i][j] = np.median(images[i].inty[goodmask])
        spectrum_wave[i] = 0.5*(spectrum_wave[i][:-1]+spectrum_wave[i][1:])
        # Trim the images and arrays to the aperture size
        images[i].inty = images[i].inty[aycen-arad:aycen+arad,
                                        axcen-arad:axcen+arad]
        wavearraylist[i] = wavearraylist[i][aycen-arad:aycen+arad,
                                            axcen-arad:axcen+arad]
        xcenlist.append(arad+xcen-axcen)
        ycenlist.append(arad+ycen-aycen)
        # Convert skywavelibs to lists
        skywavelibs[i] = list(skywavelibs[i])
        skywavelibs_extended[i] = list(skywavelibs_extended[i])
        # Close median image
        medimage.close()
        # Try to fix the NaNs
        mask = np.logical_not(np.isnan(spectrum_inty[i]))
        spectrum_wave[i] = spectrum_wave[i][mask]
        spectrum_inty[i] = spectrum_inty[i][mask]

    # Interactive plotting of ring profiles
    addedwaves = []
    final_fitted_waves = []
    final_fitted_intys = []
    final_fitted_sigs = []
    for i in range(len(fnlist)):
        addedwaves.append([])
        final_fitted_waves.append([])
        final_fitted_intys.append([])
        final_fitted_sigs.append([])
    i = 0
    while True:
        # Determine which wavelengths we want to fit
        waves_to_fit = skywavelibs[i]+addedwaves[i]

        # Generate a fitting function from those wavelengths
        func_to_fit = make_sum_gaussians(waves_to_fit)

        # Come up with reasonable guesses for the fitting function parameters
        contguess = [0]
        intyguesses = []
        sigguesses = []
        for j in range(len(waves_to_fit)):
            uppermask = spectrum_wave[i] < waves_to_fit[j]+4
            lowermask = spectrum_wave[i] > waves_to_fit[j]-4
            mask = np.logical_and(uppermask, lowermask)
            # Guess at line intensity via integral
            intyguesses.append(np.sum(spectrum_inty[i][mask] *
                                      (spectrum_wave[i][1] -
                                       spectrum_wave[i][0])))
            # Guess sigma is 2 angstroms
            sigguesses.append(2)
        guess = contguess+intyguesses+sigguesses

        # Fit the spectrum
        fitsuccess = True
        try:
            fit = curve_fit(func_to_fit, spectrum_wave[i],
                            spectrum_inty[i], p0=guess)[0]
        except RuntimeError:
            print ("Warning: Fit did not converge. " +
                   "Maybe remove some erroneous lines from the fit?")
            fit = guess
            fitsuccess = False
        fitcont = fit[0]
        fitintys = np.array(fit[1:len(waves_to_fit)+1])
        fitsigs = np.array(fit[len(waves_to_fit)+1:2*len(waves_to_fit)+1])
        # Flip signs of negative sigma fits (sign degeneracy)
        fitintys[fitsigs < 0] = -1*fitintys[fitsigs < 0]
        fitsigs[fitsigs < 0] = -1*fitsigs[fitsigs < 0]

        # Make the subtracted plot array
        subarray = images[i].inty.copy()
        for j in range(len(waves_to_fit)):
            subarray -= fitintys[j]*nGauss(wavearraylist[i]-waves_to_fit[j],
                                           fitsigs[j])

        # Figure out which radius each wavelength is at
        radiilist = []
        for j in range(len(waves_to_fit)):
            radiilist.append(Flist[i] *
                             np.sqrt((wave0list[i]/waves_to_fit[j])**2-1))

        # Create the subtracted spectrum
        sub_spec_inty = spectrum_inty[i] - fitcont
        for j in range(len(waves_to_fit)):
            sub_spec_inty -= (fitintys[j] *
                              nGauss(spectrum_wave[i]-waves_to_fit[j],
                                     fitsigs[j]))

        # Create the spectrum fit plot
        fit_X = np.linspace(minwavelist[i], maxwavelist[i], 500)
        fit_Y = np.ones_like(fit_X)*fitcont
        for j in range(len(waves_to_fit)):
            fit_Y += fitintys[j]*nGauss(fit_X-waves_to_fit[j], fitsigs[j])

        # Plot the image, spectrum, and fit
        profile_plot = SkyRingPlot(images[i].inty, subarray,
                                   xcenlist[i], ycenlist[i], radiilist,
                                   spectrum_wave[i], spectrum_inty[i],
                                   sub_spec_inty, fit_X, fit_Y,
                                   skywavelibs[i], addedwaves[i],
                                   skywavelibs_extended[i],
                                   repr(i+1)+"/"+repr(len(fnlist)),
                                   has_been_saved[i], fitsuccess)

        # Shifting images and breakout condition
        if profile_plot.key == "a":
            i += -1
        if profile_plot.key == "d":
            i += 1
        quitloop = False
        if (i == -1 or i == len(fnlist) or profile_plot.key == "q"):
            if (np.sum(np.logical_not(has_been_saved)) == 0):
#                 while True:
#                     yn = raw_input("Finished fitting ring profiles? (y/n) ")
#                     if "n" in yn or "N" in yn:
#                         break
#                     if "y" in yn or "Y" in yn:
#                         quitloop = True
#                         break
                quitloop = True
            else:
                print ("Error: Ring fits have not yet been " +
                       "saved for the following images:")
                imagenumbers = np.arange(len(fnlist))+1
                print imagenumbers[np.logical_not(has_been_saved)]
        if quitloop:
            break
        if i == -1:
            i = 0
        if i == len(fnlist):
            i = len(fnlist)-1

        # Delete ring option
        if profile_plot.key == "s":
            nearest_wave = None
            if profile_plot.axis in [1, 3] and len(waves_to_fit) != 0:
                # The keypress was made in an image plot
                clicked_radius = np.sqrt((profile_plot.xcoo - xcenlist[i])**2 +
                                         (profile_plot.ycoo - ycenlist[i])**2)
                near_index = np.argmin(np.abs((np.array(radiilist) -
                                               clicked_radius)))
                nearest_wave = waves_to_fit[near_index]
            elif profile_plot.axis in [2, 4] and len(waves_to_fit) != 0:
                # The keypress was in a spectrum plot
                clicked_wave = profile_plot.xcoo
                near_index = np.argmin(np.abs(np.array(waves_to_fit) -
                                              clicked_wave))
                nearest_wave = waves_to_fit[near_index]
            if nearest_wave is not None:
                # Remove the nearest wavelength from the sky_wave_lib or
                # added waves, add it to extra waves
                if nearest_wave in skywavelibs[i]:
                    skywavelibs[i].remove(nearest_wave)
                    skywavelibs_extended[i].append(nearest_wave)
                if nearest_wave in addedwaves[i]:
                    addedwaves[i].remove(nearest_wave)

        # Add ring option
        if profile_plot.key == "w":
            clicked_wave = None
            if profile_plot.axis in [1, 3]:
                # The keypress was made in an image plot
                clicked_radius = np.sqrt((profile_plot.xcoo - xcenlist[i])**2 +
                                         (profile_plot.ycoo - ycenlist[i])**2)
                # Convert radius to wavelength
                clicked_wave = (wave0list[i] /
                                (1+clicked_radius**2/Flist[i]**2)**0.5)
            elif profile_plot.axis in [2, 4]:
                # The keypress was in a spectrum plot
                clicked_wave = profile_plot.xcoo
            if clicked_wave is not None:
                # Find the nearest wavelength in the extended list
                if len(np.array(skywavelibs_extended[i])-clicked_wave) > 0:
                    near = np.argmin(np.abs(np.array(skywavelibs_extended[i]) -
                                            clicked_wave))
                    wave_to_add = skywavelibs_extended[i][near]
                    # Add that wave to skywavelibs, remove it from extended
                    skywavelibs[i].append(wave_to_add)
                    skywavelibs_extended[i].remove(wave_to_add)

        # Force add ring option
        if profile_plot.key == "e":
            clicked_wave = None
            if profile_plot.axis in [1, 3]:
                # The click was made in an image plot
                clicked_radius = np.sqrt((profile_plot.xcoo - xcenlist[i])**2 +
                                         (profile_plot.ycoo - ycenlist[i])**2)
                # Convert radius to wavelength
                clicked_wave = (wave0list[i] /
                                (1+clicked_radius**2/Flist[i]**2)**0.5)
            elif profile_plot.axis in [2, 4]:
                # The click was in a spectrum plot
                clicked_wave = profile_plot.xcoo
            if clicked_wave is not None:
                # Add this wavelength to the added array
                addedwaves[i].append(clicked_wave)

        # Save option
        if profile_plot.key == "r":
            final_fitted_waves[i] = waves_to_fit[:]
            final_fitted_intys[i] = fitintys[:]
            final_fitted_sigs[i] = fitsigs[:]
            has_been_saved[i] = True

        # Manual Mode Option
        if profile_plot.key == "x":

            # Initialize the manual mode lists
            man_waves = list(waves_to_fit)
            man_intys = list(fitintys)
            man_sigs = list(fitsigs)
            man_cont = fitcont
            man_real = []
            for wave in man_waves:
                if wave in skywavelibs[i] or wave in skywavelibs_extended[i]:
                    man_real.append(True)
                else:
                    man_real.append(False)

            # Initialize refinement level and selected line
            selected_line = 0
            refine = 1
            inty_refine = 0.25*(np.max(spectrum_inty[i]) -
                                np.min(spectrum_inty[i]))
            sig_refine = 0.5
            cont_refine = inty_refine

            # Loop until completion
            while True:

                # Make the subtracted plot array
                subarray = images[i].inty.copy()
                for j in range(len(man_waves)):
                    subarray -= man_intys[j]*nGauss((wavearraylist[i] -
                                                     man_waves[j]),
                                                    man_sigs[j])

                # Figure out which radius each wavelength is at
                radiilist = []
                for j in range(len(man_waves)):
                    radiilist.append(Flist[i] *
                                     np.sqrt((wave0list[i]/man_waves[j])**2-1))
                for skywav in skywavelibs_extended[i]:
                    radiilist.append(Flist[i] *
                                     np.sqrt((wave0list[i] / skywav)**2-1))

                # Create the subtracted spectrum
                sub_spec_inty = spectrum_inty[i] - man_cont
                for j in range(len(man_waves)):
                    sub_spec_inty -= (man_intys[j] *
                                      nGauss(spectrum_wave[i]-man_waves[j],
                                             man_sigs[j]))

                # Create the spectrum fit plot
                fit_X = np.linspace(minwavelist[i], maxwavelist[i], 500)
                fit_Y = np.ones_like(fit_X)*man_cont
                for j in range(len(man_waves)):
                    fit_Y += man_intys[j]*nGauss(fit_X-man_waves[j],
                                                 man_sigs[j])

                # What colors are we using?
                colors = []
                for k in range(len(man_waves)):
                    if selected_line == k:
                        colors.append('purple')
                    elif not man_real[k]:
                        colors.append('green')
                    elif man_real[k]:
                        colors.append('blue')
                for _w in skywavelibs_extended[i]:
                    colors.append('red')

                # Plot the spectrum and fit, get user input
                man_plot = ManualPlot(images[i].inty, subarray,
                                      xcenlist[i], ycenlist[i],
                                      spectrum_wave[i], spectrum_inty[i],
                                      sub_spec_inty,
                                      fit_X, fit_Y,
                                      has_been_saved[i], (repr(i+1)+"/" +
                                                          repr(len(fnlist))),
                                      radiilist,
                                      man_waves+skywavelibs_extended[i],
                                      colors)

                # Cycle selected line
                if man_plot.key == "z":
                    selected_line += 1
                    if selected_line >= len(man_waves):
                        selected_line = 0
                    refine = 1

                # Save fit
                if man_plot.key == "r":
                    final_fitted_waves[i] = man_waves[:]
                    final_fitted_intys[i] = man_intys[:]
                    final_fitted_sigs[i] = man_sigs[:]
                    has_been_saved[i] = True
                    break

                # Refinement levels
                if man_plot.key == "c":
                    refine *= 0.5
                if man_plot.key == "v":
                    refine *= 2

                # Increase/decrease inty
                if len(man_waves) != 0:
                    if man_plot.key == "w":
                        man_intys[selected_line] += refine*inty_refine
                    if man_plot.key == "s":
                        man_intys[selected_line] -= refine*inty_refine

                # Increase/decrease line width
                if len(man_waves) != 0:
                    if man_plot.key == "q":
                        man_sigs[selected_line] += refine*sig_refine
                    if man_plot.key == "a":
                        man_sigs[selected_line] -= refine*sig_refine

                # Increase/decrease continuum
                if man_plot.key == "t":
                    man_cont += refine*cont_refine
                if man_plot.key == "g":
                    man_cont -= refine*cont_refine

                # Add the known line nearest the keypress
                if man_plot.key == "e":
                    clicked_wave = None
                    if man_plot.axis in [1, 3]:
                        # The keypress was made in an image plot
                        clicked_radius = np.sqrt((man_plot.xcoo -
                                                  xcenlist[i])**2 +
                                                 (man_plot.ycoo -
                                                  ycenlist[i])**2)
                        # Convert radius to wavelength
                        clicked_wave = (wave0list[i] /
                                        (1+clicked_radius**2/Flist[i]**2)**0.5)
                    elif man_plot.axis in [2, 4]:
                        # The keypress was in a spectrum plot
                        clicked_wave = man_plot.xcoo
                    if clicked_wave is not None:
                        # Find the nearest wavelength in the extended list
                        if len(np.array(skywavelibs_extended[i]) -
                               clicked_wave) > 0:
                            sky = np.array(skywavelibs_extended[i])
                            near = np.argmin(np.abs(sky-clicked_wave))
                            wave_to_add = skywavelibs_extended[i][near]
                            # Add that wave to manwaves,
                            # remove from extended list
                            man_waves.append(wave_to_add)
                            man_intys.append(0)
                            man_sigs.append(1)
                            man_real.append(True)
                            skywavelibs_extended[i].remove(wave_to_add)
                            selected_line = len(man_waves)-1

                # Remove line nearest the keypress
                if man_plot.key == "d":
                    nearest_wave = None
                    if man_plot.axis in [1, 3] and len(man_waves) != 0:
                        # The keypress was made in an image plot
                        clicked_radius = np.sqrt((man_plot.xcoo -
                                                  xcenlist[i])**2 +
                                                 (man_plot.ycoo -
                                                  ycenlist[i])**2)
                        near_index = np.argmin(np.abs((np.array(radiilist) -
                                                       clicked_radius)))
                        nearest_wave = man_waves[near_index]
                    elif man_plot.axis in [2, 4] and len(man_waves) != 0:
                        # The keypress was in a spectrum plot
                        clicked_wave = man_plot.xcoo
                        near_index = np.argmin(np.abs(np.array(man_waves) -
                                                      clicked_wave))
                        nearest_wave = man_waves[near_index]
                    if nearest_wave is not None:
                        # Remove the nearest wavelength
                        # re-add to extended list
                        # if it was real
                        wave_index = np.where(np.array(man_waves) ==
                                              nearest_wave)[0][0]
                        man_waves.pop(wave_index)
                        man_intys.pop(wave_index)
                        man_sigs.pop(wave_index)
                        if man_real[wave_index]:
                            skywavelibs_extended[i].append(nearest_wave)
                        man_real.pop(wave_index)
                        if wave_index == selected_line:
                            selected_line = 0

                # Force-add
                if man_plot.key == "f":
                    clicked_wave = None
                    if profile_plot.axis in [1, 3]:
                        # The click was made in an image plot
                        clicked_radius = np.sqrt((man_plot.xcoo -
                                                  xcenlist[i])**2 +
                                                 (man_plot.ycoo -
                                                  ycenlist[i])**2)
                        # Convert radius to wavelength
                        clicked_wave = (wave0list[i] /
                                        (1+clicked_radius**2 /
                                         Flist[i]**2)**0.5)
                    elif profile_plot.axis in [2, 4]:
                        # The click was in a spectrum plot
                        clicked_wave = man_plot.xcoo
                    if clicked_wave is not None:
                        # Add this wavelength to the added array
                        man_waves.append(clicked_wave)
                        man_intys.append(0)
                        man_sigs.append(1)
                        man_real.append(False)
                        selected_line = len(man_waves)-1

                # Switch back to automatic
                if man_plot.key == "x":
                    break

    # Close all of the images
    for image in images:
        image.close()

    # Subtract the ring profiles and update headers
    for i in range(len(fnlist)):
        image = FPImage(fnlist[i], update=True)
        arad = image.arad
        axcen = image.axcen
        aycen = image.aycen
        mask = image.inty == 0  # For re-correcting chip gaps
        for j in range(len(final_fitted_waves[i])):
            image.header['subwave'+repr(j)] = final_fitted_waves[i][j]
            image.header['subinty'+repr(j)] = final_fitted_intys[i][j]
            image.header['subsig'+repr(j)] = final_fitted_sigs[i][j]
            ringimg = (final_fitted_intys[i][j] *
                       nGauss(wavearraylist[i]-final_fitted_waves[i][j],
                              final_fitted_sigs[i][j]))
            image.inty[aycen-arad:aycen+arad, axcen-arad:axcen+arad] -= ringimg
            image.ringtog = "True"
        image.inty[mask] = 0  # For re-correcting chip gaps
        image.close()

    # Restore the old keyword shortcut
    plt.rcParams["keymap.save"] = oldsavekey
    plt.rcParams['keymap.fullscreen'] = oldfullscreenkey

    return
Exemplo n.º 2
0
def sub_sky_rings(fnlist,medfilelist):
    """Fits for night sky rings in a series of images, then subtracts them off.
    If uncertainty images exist, updates them with better uncertainties.
    
    The rings are fitted in an interactive way by the user.
    
    After the ring subtraction, the header keyword "fpdering" is created and
    set to "True."
    
    Note: A 'median.fits' image must exist for the object or this routine will
    not work.
    
    Inputs:
    fnlist -> List of strings, each the path to a fits image.
    medfilelist -> List of paths to median images for each image to subtract off
                   (probably all the same, but generally could be different)
    
    """
    
    #This bit takes care of the 's' to save shortcut in matplotlib.
    oldsavekey = plt.rcParams["keymap.save"]
    plt.rcParams["keymap.save"] = ""
    
    #Open all of the images, median-subtract them, make wavelength arrays
    # make skywavelibs for each, make spectra for each, trim images
    imagelist = []
    wavearraylist = []
    skywavelibs = []
    skywavelibs_extended = []
    spectrum_wave = []
    spectrum_inty = []
    minwavelist = []
    maxwavelist = []
    xcenlist = []
    ycenlist = []
    Flist = []
    wave0list = []
    has_been_saved = np.zeros(len(fnlist),dtype="bool")
    for i in range(len(fnlist)):
        #Open image
        imagelist.append(openfits(fnlist[i]))
        medimage = openfits(medfilelist[i])
        #Get a bunch of relevant header values
        Flist.append(imagelist[i][0].header["fpcalf"])
        wave0list.append(imagelist[i][0].header["fpwave0"])
        xcen = imagelist[i][0].header["fpxcen"]
        ycen = imagelist[i][0].header["fpycen"]
        arad = imagelist[i][0].header["fparad"]
        axcen = imagelist[i][0].header["fpaxcen"]
        aycen = imagelist[i][0].header["fpaycen"]
        #Median subtract it
        imagelist[i][0].data += -medimage[0].data
        #Make wavelength array
        xgrid, ygrid = np.meshgrid(np.arange(imagelist[i][0].data.shape[1]),np.arange(imagelist[i][0].data.shape[0]))
        r2grid = (xgrid-xcen)**2+(ygrid-ycen)**2
        wavearraylist.append(wave0list[i]/np.sqrt(1+r2grid/Flist[i]**2))
        #Get the sky wave library
        minwavelist.append(np.min(wavearraylist[i][r2grid<arad**2]))
        maxwavelist.append(np.max(wavearraylist[i][r2grid<arad**2]))
        skywaves = get_libraries(imagelist[i][0].header["FILTER"])[1]
        skywavelibs.append(skywaves[np.logical_and(skywaves>minwavelist[i],skywaves<maxwavelist[i])])
        #Make an "extended" sky wave library
        skywavelibs_extended.append(skywaves[np.logical_or(np.logical_and(skywaves<minwavelist[i],skywaves>minwavelist[i]-5),np.logical_and(skywaves>maxwavelist[i],skywaves<maxwavelist[i]+5))])
        #Make the spectrum
        spectrum_wave.append(np.linspace(np.min(wavearraylist[i][r2grid<arad**2]),np.max(wavearraylist[i][r2grid<arad**2]),np.int(((np.max(wavearraylist[i][r2grid<arad**2])-np.min(wavearraylist[i][r2grid<arad**2]))/0.25))))
        spectrum_inty.append(np.zeros_like(spectrum_wave[i][1:]))
        for j in range(len(spectrum_wave[i])-1):
            spectrum_inty[i][j] = np.median(imagelist[i][0].data[np.logical_and(np.logical_and(imagelist[i][0].data!=0,wavearraylist[i]>spectrum_wave[i][j]),wavearraylist[i]<spectrum_wave[i][j+1])])
        spectrum_wave[i] = 0.5*(spectrum_wave[i][:-1]+spectrum_wave[i][1:])
        #Trim the images and arrays to the aperture size
        imagelist[i][0].data = imagelist[i][0].data[aycen-arad:aycen+arad,axcen-arad:axcen+arad]
        wavearraylist[i] = wavearraylist[i][aycen-arad:aycen+arad,axcen-arad:axcen+arad]
        xcenlist.append(arad+xcen-axcen)
        ycenlist.append(arad+ycen-aycen)
        #Convert skywavelibs to lists
        skywavelibs[i] = list(skywavelibs[i])
        skywavelibs_extended[i] = list(skywavelibs_extended[i])
        #Close median image
        medimage.close()
    
    #Interactive plotting of ring profiles
    addedwaves = []
    final_fitted_waves = []
    final_fitted_intys = []
    final_fitted_sigs = []
    for i in range(len(fnlist)):
        addedwaves.append([])
        final_fitted_waves.append([])
        final_fitted_intys.append([])
        final_fitted_sigs.append([])
    i = 0
    while True:
        #Determine which wavelengths we want to fit
        waves_to_fit = skywavelibs[i]+addedwaves[i]
        
        #Generate a fitting function from those wavelengths
        func_to_fit = make_sum_gaussians(waves_to_fit)
        
        #Come up with reasonable guesses for the fitting function parameters
        contguess = [0]
        intyguesses = []
        sigguesses = []
        for j in range(len(waves_to_fit)):
            intyguesses.append(np.sum(spectrum_inty[i][np.logical_and(spectrum_wave[i]<waves_to_fit[j]+4,spectrum_wave[i]>waves_to_fit[j]-4)]*(spectrum_wave[i][1]-spectrum_wave[i][0])))
            sigguesses.append(2)
        guess = contguess+intyguesses+sigguesses
        
        #Fit the spectrum
        fitsuccess = True
        try:
            fit = curve_fit(func_to_fit,spectrum_wave[i],spectrum_inty[i],p0=guess)[0]
        except RuntimeError:
            print "Warning: Fit did not converge. Maybe remove some erroneous lines from the fit?"
            fit = guess
            fitsuccess = False
        fitcont = fit[0]
        fitintys = np.array(fit[1:len(waves_to_fit)+1])
        fitsigs = np.array(fit[len(waves_to_fit)+1:2*len(waves_to_fit)+1])
        
        #Make the subtracted plot array
        subarray = imagelist[i][0].data.copy()
        for j in range(len(waves_to_fit)): subarray += -fitintys[j]*nGauss(wavearraylist[i]-waves_to_fit[j],fitsigs[j])
        
        #Figure out which radius each wavelength is at
        radiilist = []
        for j in range(len(waves_to_fit)): radiilist.append(Flist[i]*np.sqrt((wave0list[i]/waves_to_fit[j])**2-1))
        
        #Create the subtracted spectrum
        sub_spec_inty = spectrum_inty[i] - fitcont
        for j in range(len(waves_to_fit)): sub_spec_inty += -fitintys[j]*nGauss(spectrum_wave[i]-waves_to_fit[j],fitsigs[j])
        
        #Create the spectrum fit plot
        fit_X = np.linspace(minwavelist[i],maxwavelist[i],500)
        fit_Y = np.ones_like(fit_X)*fitcont
        for j in range(len(waves_to_fit)): fit_Y += fitintys[j]*nGauss(fit_X-waves_to_fit[j], fitsigs[j])
        
        #Plot the image, spectrum, and fit
        profile_plot = SkyRingPlot(imagelist[i][0].data, subarray,
                                   xcenlist[i], ycenlist[i], radiilist,
                                   spectrum_wave[i], spectrum_inty[i], sub_spec_inty,
                                   fit_X, fit_Y,
                                   skywavelibs[i], addedwaves[i], skywavelibs_extended[i],
                                   repr(i+1)+"/"+repr(len(fnlist)), has_been_saved[i], fitsuccess)
        
        #Shifting images and breakout condition
        if profile_plot.key == "a": i+=-1
        if profile_plot.key == "d": i+=1
        quitloop = False
        if (i==-1 or i==len(fnlist) or profile_plot.key=="q"):
            if (np.sum(np.logical_not(has_been_saved))==0):
                while True:
                    yn = raw_input("Finished fitting ring profiles? (y/n) ")
                    if "n" in yn or "N" in yn:
                        break
                    if "y" in yn or "Y" in yn:
                        quitloop=True
                        break
            else:
                print "Error: Ring fits have not yet been saved for the following images:"
                print (np.arange(len(fnlist))+1)[np.logical_not(has_been_saved)]
        if quitloop: break
        if i == -1: i=0
        if i == len(fnlist): i=len(fnlist)-1
        
        #Delete ring option
        if profile_plot.key == "s":
            nearest_wave = None
            if profile_plot.axis in [1,3]:
                #The click was made in an image plot
                clicked_radius = np.sqrt((profile_plot.xcoo - xcenlist[i])**2 + (profile_plot.ycoo - ycenlist[i])**2)
                nearest_wave = waves_to_fit[np.argmin(np.abs((np.array(radiilist)-clicked_radius)))]
            elif profile_plot.axis in [2,4]:
                #The click was in a spectrum plot
                clicked_wave = profile_plot.xcoo
                nearest_wave = waves_to_fit[np.argmin(np.abs(np.array(waves_to_fit)-clicked_wave))]
            if nearest_wave != None:
                #Remove the nearest wavelength from the sky_wave_lib or added waves, add it to extra waves
                if nearest_wave in skywavelibs[i]:
                    skywavelibs[i].remove(nearest_wave)
                    skywavelibs_extended[i].append(nearest_wave)
                if nearest_wave in addedwaves[i]: addedwaves[i].remove(nearest_wave)
                
        #Add ring option
        if profile_plot.key == "w":
            clicked_wave = None
            if profile_plot.axis in [1,3]:
                #The click was made in an image plot
                clicked_radius = np.sqrt((profile_plot.xcoo - xcenlist[i])**2 + (profile_plot.ycoo - ycenlist[i])**2)
                #Convert radius to wavelength
                clicked_wave = wave0list[i] / (1+clicked_radius**2/Flist[i]**2)**0.5
            elif profile_plot.axis in [2,4]:
                #The click was in a spectrum plot
                clicked_wave = profile_plot.xcoo
            if clicked_wave != None:
                #Find the nearest wavelength in the extended list (if there are any)
                if len(np.abs(np.array(skywavelibs_extended[i])-clicked_wave))>0:
                    wave_to_add = skywavelibs_extended[i][np.argmin(np.abs(np.array(skywavelibs_extended[i])-clicked_wave))]
                    #Add that wave to skywavelibs, remove it from extended
                    skywavelibs[i].append(wave_to_add)
                    skywavelibs_extended[i].remove(wave_to_add)
        
        #Force add ring option
        if profile_plot.key == "e":
            clicked_wave = None
            if profile_plot.axis in [1,3]:
                #The click was made in an image plot
                clicked_radius = np.sqrt((profile_plot.xcoo - xcenlist[i])**2 + (profile_plot.ycoo - ycenlist[i])**2)
                #Convert radius to wavelength
                clicked_wave = wave0list[i] / (1+clicked_radius**2/Flist[i]**2)**0.5
            elif profile_plot.axis in [2,4]:
                #The click was in a spectrum plot
                clicked_wave = profile_plot.xcoo
            if clicked_wave != None:
                #Add this wavelength to the added array
                addedwaves[i].append(clicked_wave)
                
        #Save option
        if profile_plot.key == "r":
            final_fitted_waves[i] = waves_to_fit[:]
            final_fitted_intys[i] = fitintys[:]
            final_fitted_sigs[i] = fitsigs[:]
            has_been_saved[i] = True
        
    #Close all of the images
    medimage.close()
    for i in range(len(fnlist)):
        imagelist[i].close()
    
    #Subtract the ring profiles and update headers
    for i in range(len(fnlist)):
        image = openfits(fnlist[i], mode="update")
        arad = image[0].header["fparad"]
        axcen = image[0].header["fpaxcen"]
        aycen = image[0].header["fpaycen"]
        mask = image[0].data == 0 #For re-correcting chip gaps
        for j in range(len(final_fitted_waves[i])):
            image[0].data[aycen-arad:aycen+arad,axcen-arad:axcen+arad] += -final_fitted_intys[i][j]*nGauss(wavearraylist[i]-final_fitted_waves[i][j], final_fitted_sigs[i][j])
            image[0].header["fpdering"] = "True"
        image[0].data[mask]=0 #For re-correcting chip gaps
        image.close()
    
    #Restore the old keyword shortcut
    plt.rcParams["keymap.save"] = oldsavekey
    
    return