def plot_list(
    list_file,
    directory,
    extension=EXTENSION,
    specific=None,
    title="No Title",
    scaling=SCALING,
    text_offset=TEXT_OFFSET,
    axis_offset=AXIS_OFFSET,
):

    file = open(list_file)

    # Formating for thicker figure for readability
    plt.rc("axes", linewidth=2.5)
    ax = plt.gca()
    ax.tick_params(width=2.5, size=5)
    for tick in ax.xaxis.get_major_ticks():
        tick.label1.set_fontsize(19)
        # tick.label1.set_fontweight('bold')
    for tick in ax.yaxis.get_major_ticks():
        tick.label1.set_fontsize(19)
        # tick.label1.set_fontweight('bold')

    obj_red = []
    for line in file:  # Creates a list and appends all the objects with their redshifts as nested lists.
        (object, redshift) = line.split()
        obj_red.append([object, float(redshift)])
    obj_red.sort(key=lambda x: x[1])  # Sorts the object list by the redshift

    full_list = lib_spec(directory, extension)  # Now create the dictionary of spectra objects.
    # The obj_red list acts as the keys to the dictionary to the spectra in the full_list dictionary.
    final = full_list[obj_red[0][0].split(".")[0]]
    first = full_list[obj_red[-1][0].split(".")[0]]

    for spec in obj_red:  # Reassigns all the redshifts to objects in the full_list.
        instance = full_list[spec[0].split(".")[0]]
        instance.redshift(spec[1])  # Assigning redshift

    i = 0  # Keep track of object number
    for spec in obj_red:  # This iteration plots the spectra.

        instance = full_list[spec[0].split(".")[0]]
        instance.plot(i, scaling)  # Plot this with the index number (for y translation) and with scaling coefficient.
        x = (
            first.wavlist[0] / (1 + first.z) - text_offset
        )  # Plots the text relative to the lowest wavelength of the spectra
        y = i
        text = instance.name + ", z = " + str(round(instance.z, 3))
        plt.rc("font", family="serif")
        plt.text(x, y, text, fontsize=13, family="Cambria")
        i += 1

    # Assigns the axis of the plot.
    x_axis_low = first.wavlist[0] / (1 + first.z) - axis_offset
    x_axis_high = final.wavlist[-1] / (1 + final.z) + 200
    y_axis_high = i + 1
    y_axis_low = -1

    # Plot the axis and the line labels.
    plt.axis([x_axis_low, x_axis_high, y_axis_low, y_axis_high])
    plt.xlabel("$\mathrm{Rest \\ Wavelength \\ (\AA)}$", fontsize=25, fontweight="bold")
    plt.ylabel(
        "$\mathrm{Relative \\ Spectral \\ Flux \\ (erg \\ s^{-1} \\ cm^{-2} \\ \AA ^{-1}) \\ + \\ Constant}$",
        fontsize=25,
        fontweight="bold",
    )

    # Will plot a specific spectra if asked to, not main point of the code.
    if specific is None:
        pass
    else:
        plt.clf()

        # Formating for thicker figure for readability
        plt.rc("axes", linewidth=3)
        ax = plt.gca()
        ax.tick_params(width=3, size=5)
        for tick in ax.xaxis.get_major_ticks():
            tick.label1.set_fontsize(22)
            # tick.label1.set_fontweight('bold')
        for tick in ax.yaxis.get_major_ticks():
            tick.label1.set_fontsize(22)
            # tick.label1.set_fontweight('bold')

        plt.xlabel("$\mathrm{Rest \\ Wavelength \\ (\AA)}$", fontsize=30)
        plt.ylabel("$\mathrm{Relative \\ Spectral \\ Flux \\ (erg \\ s^{-1} \\ cm^{-2} \\ \AA ^{-1})}$", fontsize=30)
        full_list[specific].plot(0, scaling)
        y_axis_high = max(full_list[specific].data) * scaling / full_list[specific].norm + 0.9
        plt.axis(
            [
                (full_list[specific].wavlist[0] - 50) / (1 + full_list[specific].z),
                (full_list[specific].wavlist[-1] + 50) / (1 + full_list[specific].z),
                -0.5,
                y_axis_high - 0.3,
            ]
        )
        plt.text(
            (full_list[specific].wavlist[0]) / (1 + full_list[specific].z),
            y_axis_high - 0.5,
            full_list[specific].name + ", $\mathrm{z} = $" + str(round(full_list[specific].z, 3)),
            horizontalalignment="left",
            fontsize=25,
        )

    # Plots the relative lin labels. Some have extra whitespace due to closeness.
    # line_label(1400,"SiIV",y_axis_high)
    # line_label(1549,"CIV",y_axis_high)
    # line_label(1909,"CIII",y_axis_high)
    line_label(2798, "MgII", y_axis_high)
    line_label(3427, "[NeV]", y_axis_high)
    line_label(3729, "[OII]   ", y_axis_high)
    line_label(3870, "     [NeIII]", y_axis_high)
    line_label(4341, "H$\gamma$    ", y_axis_high)
    line_label(4386, "        [OIII]", y_axis_high)
    line_label(4861, "H$\\beta$  ", y_axis_high)
    line_label(4959, "", y_axis_high)
    line_label(5007, "   [OIII]", y_axis_high)
    line_label(6548, "[NII]             ", y_axis_high)
    line_label(6563, "H$\\alpha$", y_axis_high)
    line_label(6584, "            [NII]", y_axis_high)

    plt.subplots_adjust(left=0.1, right=0.9, top=0.9, bottom=0.1)
    plt.show()
    plt.close()
def compspectra(list_file, directory, cutoffs, regions, extension=EXTENSION):

    file = open(list_file)

    obj_red = []
    for line in file:  # Creates a list and appends all the objects with their redshifts as nested lists.
        (object, redshift) = line.split()
        obj_red.append([object, float(redshift)])
    obj_red.sort(key=lambda x: x[1])  # Sorts the object list by the redshift

    full_list = lib_spec(directory, extension)  # Now create the dictionary of spectra objects.
    # The obj_red list acts as the keys to the dictionary to the spectra in the full_list dictionary.

    for spec in obj_red:  # Reassigns all the redshifts to objects in the full_list.
        instance = full_list[spec[0].split(".")[0]]
        instance.redshift(spec[1])  # Assigning redshift

    final = full_list[obj_red[0][0].split(".")[0]].wavlist[-1] / (1 + full_list[obj_red[0][0].split(".")[0]].z)
    first = full_list[obj_red[-1][0].split(".")[0]].wavlist[0] / (1 + full_list[obj_red[-1][0].split(".")[0]].z)

    interpgrid = arange(
        math.floor(first), math.ceil(final) - 0.5, 0.5
    )  # Make the grid we are going to interpolate over.

    regiondat = []
    regionsigma = []
    regioncount = []
    regionspectralists = []

    # Creating composite spectra components
    for j in range(len(regions)):

        comp_spectras = []

        for spec in obj_red:
            instance = full_list[spec[0].split(".")[0]]
            if j == 0:
                if instance.z > cutoffs[0]:
                    comp_spectras.append(
                        CompSpecCpnt(instance.wavlist, instance.data, interpgrid, instance.z, instance.name, regions[0])
                    )
                else:
                    pass
            elif j == len(regions) - 1:
                if instance.z < cutoffs[j - 1]:
                    comp_spectras.append(
                        CompSpecCpnt(instance.wavlist, instance.data, interpgrid, instance.z, instance.name, regions[j])
                    )
                else:
                    pass
            else:
                if (instance.z < cutoffs[j - 1]) and (instance.z > cutoffs[j]):
                    comp_spectras.append(
                        CompSpecCpnt(instance.wavlist, instance.data, interpgrid, instance.z, instance.name, regions[j])
                    )
                else:
                    pass

        compdat = []  # Flux Data
        compsigma = []  # Sigma Data
        countdat = []  # Number Data

        # Creating Composite Spectra
        for i in range(len(interpgrid)):
            candidates = []
            for spec in comp_spectras:
                if not (spec.fluxlist[i] == 0):
                    candidates.append(spec.fluxlist[i])

            if len(candidates) > 1:
                nooutliers = stats.sigmaclip(candidates)[0]
            else:
                nooutliers = candidates

            if len(nooutliers) > 0:
                compdat.append(sum(nooutliers) / len(nooutliers))
                compsigma.append(std(nooutliers))
            else:
                compdat.append(0)
                compsigma.append(0)

            countdat.append(len(nooutliers))

        regiondat.append(compdat)
        regionsigma.append(compsigma)
        regioncount.append(countdat)
        regionspectralists.append(comp_spectras)

    centerregion = regions[int(math.floor(len(regions) / 2))]
    comp_spectras = []

    for i in range(len(regiondat)):
        for j in range(len(regionspectralists[i])):
            regionspectralists[i][j].fluxlist = regionspectralists[i][j].fluxlist / sum(
                regiondat[i][centerregion[0] : centerregion[1]]
            )
        comp_spectras = comp_spectras + regionspectralists[i]

    compdat = []  # Flux Data
    compsigma = []  # Sigma Data
    countdat = []  # Number Data

    # Creating Composite Spectra
    for i in range(len(interpgrid)):
        candidates = []
        for spec in comp_spectras:
            if not (spec.fluxlist[i] == 0):
                candidates.append(spec.fluxlist[i])

        if len(candidates) > 1:
            nooutliers = stats.sigmaclip(candidates)[0]
        else:
            nooutliers = candidates

        if len(nooutliers) > 0:
            compdat.append(sum(nooutliers) / len(nooutliers))
            compsigma.append(std(nooutliers) / math.sqrt(len(nooutliers)))
        else:
            compdat.append(0)
            compsigma.append(0)

        countdat.append(len(nooutliers))

    return [interpgrid, compdat, compsigma, countdat]