def MakeErrorTable(baseGs, baseDs, altGs, altDs, outfile=None):
    if outfile is not None:
        fp = open(outfile, 'a')
    else:
        fp = None

    DataOut(latexHead, fp=fp)

    dElems = np.array(sorted(baseDs.keys()))
    gElems = np.array(sorted(baseGs.keys()))
    # 19 element/ion colums will fit on a sideways table page
    # Note: Assume the giants and dwarfs _should_ have the same number of ions
    halfway = int(round(len(dElems) / 2 + 0.1,
                        0))  # F*ing Python floating points!
    DataOut(r'r' * halfway + '} \n', fp=fp)

    for ionSet, sType, baseAbs, abSet in [(dElems[:halfway], 'Dwarf', baseDs, altDs), \
                                 (gElems[:halfway], 'Giant', baseGs, altGs), \
                                 (dElems[halfway:], 'Dwarf', baseDs, altDs), \
                                 (gElems[halfway:], 'Giant', baseGs, altGs)]:
        # Do the column headers once for the Dwarfs, only
        if sType == 'Dwarf':
            columnHead = r'\multicolumn{1}{l}{Parameter} '
            for ion in ionSet:
                columnHead = columnHead + r'& \multicolumn{{1}}{{c}}{{{0}}} '.format(
                    el.getIonName(ion))
            DataOut(columnHead + r'\\{0}\hline{0}'.format('\n'), fp=fp)

        DataOut(r'\multicolumn{{{0:2d}}}{{|c|}}{{{1}s}}\\{2}\hline{2}'.format(
            len(ionSet) + 1, sType, '\n'),
                fp=fp)

        for parmVar in abSet.keys():
            rowData = r'\multicolumn{{1}}{{|l|}}{{{0}}}'.format(parmVar)
            for ion in ionSet:
                rowData = rowData + r' & \multicolumn{{1}}{{r|}}{{{0:1.2f}}}'.format(
                    abSet[parmVar][ion] - baseAbs[ion])
            DataOut(rowData + r'\\{0}'.format('\n'), fp=fp)

        DataOut(r'\hline {1}\multicolumn{{1}}{{|l|}}{{{0} Totals}}'.format(
            sType, '\n'),
                fp=fp)
        for ion in ionSet:
            subtotal = np.sqrt(sum([max((abSet[RowHeaders[2*i]][ion]-baseAbs[ion])**2, \
                                      (abSet[RowHeaders[2*i+1]][ion]-baseAbs[ion])**2 \
                                      ) for i in [0,1,2]]))
            DataOut(r' & \multicolumn{{1}}{{r|}}{{{0:1.2f}}}'.format(subtotal),
                    fp=fp)
        DataOut(r'\\{0}\hline{0}'.format('\n'), fp=fp)
    DataOut(latexFoot, fp=fp)
    if fp: fp.close()
    return
def MakeOneLogGPlot(logGPts, abPts, starName='', fileTag=''):
    # Draw a logG plot for a single star.
    # We want to use a couple of np.array tricks, so...
    if len(logGPts) < 2 or len(abPts) < 2: return
    Xs = np.array(logGPts)
    Ys = np.array(abPts)

    ax = pyplot.gca()
    pyplot.scatter(Xs, Ys)
    pyplot.axhline(0.0, linestyle=':')
    interpGs = np.interp([0.1, 0., -0.1], -Ys, Xs)
    pyplot.plot(Xs, Ys,
                label=r'${0}({1:4.2f}^{{+{2:4.2f}}}_{{-{3:4.2f}}}$)'.\
                format(el.getIonName(22.0),interpGs[1],\
                       interpGs[1]-interpGs[2],\
                       interpGs[0]-interpGs[1]))
    ax.set_xlabel(r'$Log(G)$')
    ax.set_ylabel('[TiI/TiII]')
    pyplot.legend()
    pyplot.savefig(k.ParmPlotDir + 'Logg/' + starName + fileTag + '_logG.png')
    pyplot.close()
Exemple #3
0
def MakeLineListTable(ions=[], wls=[], outFile=d.TableDir + 'Table2.dat'):
    lines, refs = LL.getLines(elements=ions, wavelengthRange=wls,\
        dataFormat=None)
    unused1, unused2, weights = RC.GetSolarCorrections()

    fp = open(outFile, 'w')
    fmt, db = BuildFormatString(table2Format,
                                DataLabels=table2Labels,
                                DataUnits=table2Units,
                                DataExp=table2Desc,
                                MakeBbBDesc=True)
    fp.write(db)
    allIons = sorted(set(np.array(lines)[:, 1]))
    lineData = []
    for i in allIons:
        ion = np.round(i, decimals=1)
        (elem, state, unused) = el.getIonState(el.getIonName(ion))
        ionLines = np.array(
            sorted([l for l in lines if np.round(l[1], decimals=1) == ion],
                   key=lambda l: l[0]))
        for line in ionLines:
            wl = np.round(line[0], decimals=3)
            xp = line[2]
            gf = line[3]
            if gf < 0:
                gfs = '-'
            else:
                gfs = ''
            gf = abs(gf)
            try:
                qu = int(weights[ion][wl])
            except KeyError:
                qu = 0
            rf = line[5]
            lineData.append([elem, state, wl, xp, gfs, gf, qu, rf])
    for line in lineData:
        fp.write(fmt.format(*line) + '\n')
    fp.close()
def QualityPlot(points,
                starName,
                ion,
                fileTag='',
                plotTitle='',
                pointLabels=None):
    # Plot an [X/H]vs.line strength plot, with the points colored by "quality" -
    # or how well they correspond to the linear fit (along the linear section of
    # the COG) of other measurements with similar excitation potential values.
    # The linear portion of the CoG is modeled by an Orthogonal Data Reduction (ODR)
    # using a linear function (from sp.odr).
    # The quality of a point is measured as an inverse of its distance to the linear
    # fit as measured by the ODR.
    # The passed data, in the array 'points' is of the form:
    # [wl, Ex.Pot., Log(gf), eqw, Log(eqw/wl), [X/H]]
    # For now, just bailing if no points were passed
    nPoints = len(points)
    if nPoints == 0:
        return


#    assert nPoints>0
# This abSTR measure is basically the log10 of the gravity*abundance*temp
    abStrs = np.array(
        [line[5] + line[2] + np.log10(line[0]) for line in points])
    # We're rounding 'cause...Python.
    XPs = np.around(points[:, 1], 4)
    minXP = min(XPs)
    maxXP = max(XPs)
    uniqueXPs = sorted(set(XPs))
    XPDelta = maxXP - minXP
    normedXPs = [(xp - minXP) / XPDelta for xp in XPs]

    # Arrange points to analyze:
    # I just want you to be confused by the different indices
    pointData = np.array(
        zip(abStrs, points[:, 4], XPs, points[:, 5], points[:, 3]))

    # Bin our points by nearby XPs
    XPBins = [uniqueXPs[0]]
    for xp in uniqueXPs:
        if xp > XPBins[-1] + k.evBinSize:
            XPBins.append(xp)

    # We'll weight our linear COG fits by the individual points' [X/H] variance
    # Note: we'll change the median once we 'weed out' measurements outside of
    # the linear portion of the CoG.
    abMed = np.median(points[:, 5])
    #    abVar = np.std(points[:,5])

    linFits = {}
    plotPoints = {}
    minminErr = 10.
    maxmaxErr = 0.
    for xp in XPBins:
        fitPoints = np.array([
            p for p in pointData if p[2] >= xp and p[2] <= xp +
            k.evBinSize and p[1] < k.cogPlotLimit - xp * k.cogCorrFactor
        ])
        #        fitPoints = np.array([p for p in pointData if p[2]>=xp and p[2]<=xp+k.evBinSize])
        if fitPoints.shape[0] < 2:
            linFits[xp] = []
            plotPoints[xp] = []
            continue
        # Weight = distance to group median - max = 100 (ie: 1/sigma <=100)
        deltas = [abs(ab - abMed) for ab in fitPoints[:, 3]]
        pointWeights = u.normalize(
            [1. / (500. * d) if d > 0.002 else 1. for d in deltas])

        # The linfits dictionary entry will now contain:
        # [[Linear fit coefficients], [parameter estimated errors], [covariance matrix],
        #  [estimated error in x], [estimated error in y]]
        linFits[xp], coeffErrs, covariance, xErrs, yErrs = u.odRegress(
            fitPoints[:, 0], fitPoints[:, 1], weights=pointWeights)
        pointErrs = [np.sqrt(p[0]**2 + p[1]**2) for p in zip(xErrs, yErrs)]
        plotPoints[xp] = np.array(
            zip(fitPoints[:, 3], fitPoints[:, 1], pointErrs, fitPoints[:, 2],
                pointWeights))

        minErr = min(pointErrs)
        maxErr = max(pointErrs)
        if maxErr > maxmaxErr: maxmaxErr = maxErr
        if minErr < minminErr: minminErr = minErr

    # Calculate the point 'score' based on priors
    deltaErr = maxmaxErr - minminErr
    for xp in XPBins:
        if len(plotPoints[xp]) == 0:
            continue
        # Normalize the errors for the first prior
        normedErrs = np.array([(pe - minminErr) / deltaErr
                               for pe in plotPoints[xp][:, 2]])
        # Normalized XP for second prior, however, we want 0.0eV to be highest
        # values, and the highest XP to be valued no lower than 0.5
        normedXPs = np.array([
            1. - ((px - minXP) / XPDelta) / 2. for px in plotPoints[xp][:, 3]
        ])

        combPriors = u.normalize(
            np.array([
                (ps[0] * (ps[1]**2) * ps[2])**0.25
                for ps in zip(normedErrs, normedXPs, plotPoints[xp][:, 4])
            ]))
        plotPoints[xp] = np.array(
            zip(plotPoints[xp][:, 0], plotPoints[xp][:, 1], combPriors))

    fig = pyplot.figure()
    axes = pyplot.gca()
    # Y axis is negative
    Ymin = min(pointData[:, 1]) * 1.05
    Ymax = max(pointData[:, 1]) * 0.95
    Xmin = min(pointData[:, 3]) * 0.95
    Xmax = max(pointData[:, 3]) * 1.05

    if len(points) < 200:
        pointSize = 9
        if pointLabels is not None:
            # Must have one label for each point (even if it is '')
            if len(pointLabels) < len(abStrs):
                # Must have labels for all the points
                pointLabels = None
    else:
        pointLabels = None  # Seriously, don't label more than 100 points
        pointSize = 5

    allPlotPts = []  # For median/variance calcs.
    for xp in XPBins:
        if len(plotPoints[xp]) != 0:
            pyplot.scatter(plotPoints[xp][:, 0],
                           plotPoints[xp][:, 1],
                           figure=fig,
                           marker='o',
                           s=pointSize,
                           c=1. - plotPoints[xp][:, 2],
                           cmap=pyplot.get_cmap('CMRmap'),
                           edgecolors='None')
            allPlotPts.extend(plotPoints[xp])

    # It's possible that we've weeded a bit too heavily, in which case,
    # we're done.
    if len(allPlotPts) < 2:
        pyplot.close()
        return

    abMed = np.median(np.array(allPlotPts)[:, 0])
    abVar = np.std(np.array(allPlotPts)[:, 0])
    # Plot the median abundance value
    axes.plot([abMed, abMed], [Ymin, Ymax], linestyle='--', color='r')
    axes.plot([abMed - abVar, abMed - abVar], [Ymin, Ymax],
              linestyle=':',
              color='c')
    axes.plot([abMed + abVar, abMed + abVar], [Ymin, Ymax],
              linestyle=':',
              color='c')

    pyplot.text(0.65,
                0.25,
                r'{0}({1:3d}): {2:1.3f}+/-{3:1.3f}'.format(
                    el.getIonName(ion), nPoints, abMed, abVar),
                transform=axes.transAxes,
                fontsize='smaller')

    cb = pyplot.colorbar()
    cb.set_label('Point \"Quality\" (Score)')
    cb.set_ticks([0., 0.5, 1.0])
    #    cb.set_ticklabels(['{0:1.2f}'.format(minminErr), '{0:1.2f}'.format(minminErr+(maxmaxErr-minminErr)/2.), '{0:1.2f}'.format(maxmaxErr)])
    cb.set_ticklabels(['1.00', '0.50', '0.00'])

    # Write in a (tiny) label next to each point
    if pointLabels is not None:
        for coord in zip(abStrs.tolist(), wls.tolist(), pointLabels):
            # Place the label below and right of the point
            pyplot.text(coord[0] + 0.02 * (Xmax - Xmin),
                        coord[1] - 0.03 * (Ymax - Ymin),
                        coord[2],
                        color='k',
                        fontsize='xx-small')

    # Axes labels and ranges
    axes.set_ylim([Ymin, Ymax])
    axes.set_xlim([Xmin, Xmax])
    axes.set_xlabel('[{0}/H]'.format(el.getIonName(ion)))
    axes.set_ylabel(r'$Log(EQW/\lambda)$')

    if plotTitle is not '':
        axes.set_title(plotTitle)

    saveDirName = dirs.CoGPlotsDir + el.getIonName(ion) + '/'
    try:
        os.stat(saveDirName)
    except:
        os.mkdir(saveDirName[:-1])
    pyplot.savefig('{0}{1}_{2}{3}.png'.format(saveDirName, starName,
                                              el.getIonName(ion), fileTag),
                   figure=fig)
    pyplot.close()
def COGPlot(points,
            starName,
            ion,
            fileTag='',
            plotTitle='',
            pointLabels=None,
            fitXPLines=False):
    # Plot a curve of growth (COG)
    # The linear portion of the CoG is modeled by least squares (numpy polyfid for
    # a 1-d polynomial.
    # The passed data, in the array 'points' is of the form:
    # [wl, Ex.Pot., Log(gf), eqw, Log(eqw/wl), [X/H]]

    # For now, just bailing if no points were passed
    if len(points) == 0:
        return

    assert len(points) > 0

    # We'll weight our linear COG fits by the individual points' [X/H] variance
    abMed = np.median(points[:, 5])
    #    abVar = np.std(points[:,5])

    ## Quick experiment - what does the plot look like if we use the median abundance
    ## instead of the measured?
    ## We'll color the points with ex.pot. for this one.
    #    abStrs = np.array([abMed+line[2]+np.log10(line[0]) for line in points])
    abStrs = np.array(
        [line[5] + line[2] + np.log10(line[0]) for line in points])

    # We're rounding 'cause...Python.
    XPs = np.around(points[:, 1], 4)
    minXP = min(XPs)
    maxXP = max(XPs)
    uniqueXPs = sorted(set(XPs))
    deltaXP = maxXP - minXP

    # Arrange points to analyze:
    # I just want you to be confused by the different indices
    pointData = np.array(
        zip(abStrs, points[:, 4], XPs, points[:, 5], points[:, 3], points[:,
                                                                          0]))

    linFits = {}
    plotPoints = {}

    XPBins = [uniqueXPs[0]]
    for xp in uniqueXPs:
        if xp > XPBins[-1] + k.evBinSize:
            XPBins.append(xp)

    minminErr = 10.
    maxmaxErr = 0.
    for xp in XPBins:
        fitPoints = np.array(
            [p for p in pointData if p[2] >= xp and p[2] <= xp + k.evBinSize])
        if fitPoints.shape[0] < 3:
            linFits[xp] = None
            plotPoints[xp] = None
            continue
        # Weight = distance to group median - max = 100 (ie: 1/sigma <=100)
        deltas = [(abs(ab - abMed))**2 for ab in fitPoints[:, 3]]
        pointWeights = [1. / (500. * d) if d > 0.002 else 1. for d in deltas]

        # The linfits dictionary entry will now contain:
        # [[Linear fit coefficients], [parameter estimated errors], [covariance matrix],
        #  [estimated error in x], [estimated error in y]]
        linFits[xp], coeffErrs, covariance, xErrs, yErrs = u.odRegress(
            fitPoints[:, 0], fitPoints[:, 1], weights=pointWeights)
        pointErrs = [np.sqrt(p[0]**2 + p[1]**2) for p in zip(xErrs, yErrs)]
        plotPoints[xp] = np.array(
            zip(fitPoints[:, 0], fitPoints[:, 1], pointErrs, fitPoints[:, 5]))

        minErr = min(pointErrs)
        maxErr = max(pointErrs)
        if maxErr > maxmaxErr: maxmaxErr = maxErr
        if minErr < minminErr: minminErr = minErr

    # Normalize the errors for plotting
    deltaErr = maxmaxErr - minminErr
    for xp in XPBins:
        if plotPoints[xp] == None:
            continue
        pointErrs = plotPoints[xp][:, 2]
        normedErrs = np.array([(pe - minminErr) / deltaErr
                               for pe in pointErrs])
        plotPoints[xp] = np.array(
            zip(plotPoints[xp][:, 0], plotPoints[xp][:, 1], normedErrs,
                plotPoints[xp][:, 3]))

    fig = pyplot.figure()
    axes = pyplot.gca()
    # Y axis is negative
    Xmin = min(pointData[:, 0]) * 1.1
    Xmax = max(pointData[:, 0]) * 0.9
    Xmed = np.median(pointData[:, 0])
    Ymin = min(pointData[:, 1]) * 0.9
    Ymax = max(pointData[:, 1]) * 1.1

    legendCount = 0
    #    fp =open('/home/mikelum/Dropbox/CodeCloud/MyTools/ClusterAnalysis/Plots/slopes.txt','a')
    for xp in XPBins:
        if plotPoints[xp] is None:
            continue
#        fp.write('---------------\n{0} {1:1.2f}eV ({2:2d}): {3:2.3f}\n    '.format(el.getIonName(ion), xp, len(plotPoints[xp]), linFits[xp][0]))
# Plot the fit
        minX = min(plotPoints[xp][:, 0])
        minY = linFits[xp][0] * minX + linFits[xp][1]
        maxX = max(plotPoints[xp][:, 0])
        maxY = linFits[xp][0] * maxX + linFits[xp][1]
        normedXP = ((xp - minXP) / deltaXP)
        plt = axes.plot([minX, maxX], [minY, maxY],
                        color=pyplot.get_cmap('CMRmap')(normedXP))

        # Plot the points:
        # Color by distance to fit:
        #        axes.scatter(plotPoints[xp][:,0], plotPoints[xp][:,1], figure=fig, marker='o', s=8, c=plotPoints[xp][:,2], cmap=pyplot.get_cmap('CMRmap'), edgecolors='None')
        # Color by Ex. Pot.
        axes.scatter(plotPoints[xp][:, 0],
                     plotPoints[xp][:, 1],
                     figure=fig,
                     marker='o',
                     s=8,
                     color=pyplot.get_cmap('CMRmap')(normedXP),
                     edgecolors='None')
        # Legend Key
        axes.text(0.75,
                  0.35 - legendCount * 0.05,
                  r'{0:1.2f}eV: {1:2.3f}'.format(xp, linFits[xp][0]),
                  transform=axes.transAxes,
                  color=pyplot.get_cmap('CMRmap')(normedXP),
                  fontsize='smaller')
        legendCount += 1


#        slopes = np.array([[(p[3],(p[1]-a[1])/(p[0]-a[0])) if (p[0]-a[0]) != 0. else (p[3],float('nan')) for p in plotPoints[xp]] for a in plotPoints[xp]])

#        diagIndex = 0
#        for p in slopes:
#            var = abs(linFits[xp][0]/np.nanmean(p[:,1]))
#            if var > 2. or var< 0.5:
#                fp.write(' -**')
#            fp.write('{0:4.3f}:{1:2.3f}'.format(p[diagIndex,0], np.nanmean(p[:,1])))
#            if var > 2. or var< 0.5:
#                fp.write('**- ')
#            else:
#                fp.write('   ')
#            diagIndex += 1
#        fp.write('\n')
#    fp.close()
# Plot the linear CoG limit
    axes.plot([4, 14], [k.cogPlotLimit, k.cogPlotLimit], linestyle=':')

    #    cb = pyplot.colorbar()
    #    cb.set_label('Excitation Potential (eV)')
    #    cb.set_ticks([0., 0.5, 1.0])
    #    cb.set_ticklabels(['{0:1.2f}'.format(minXP), '{0:1.2f}'.format(minXP+(maxXP-minXP)/2.), '{0:1.2f}'.format(maxXP)])

    # Write in a (tiny) label next to each point
    if pointLabels is not None:
        for coord in zip(abStrs.tolist(), XPs.tolist(), pointLabels):
            # Place the label below and right of the point
            axes.text(coord[0] + 0.02 * (Xmax - Xmin),
                      coord[1] - 0.03 * (Ymax - Ymin),
                      coord[2],
                      color='k',
                      fontsize='xx-small')

    # Axes labels and ranges
    axes.set_ylim([Ymin, Ymax])
    axes.set_xlim([Xmin, Xmax])
    axes.set_xlabel(r'$Log(A*gf*\lambda)$')
    axes.set_ylabel(r'$Log(EQW/\lambda)$')

    if plotTitle is not '':
        axes.set_title(plotTitle)

    saveDirName = dirs.CoGPlotsDir + el.getIonName(ion) + '/'
    try:
        os.stat(saveDirName)
    except:
        os.mkdir(saveDirName[:-1])
    pyplot.savefig('{0}{1}_{2}{3}.png'.format(saveDirName, starName,
                                              el.getIonName(ion), fileTag),
                   figure=fig)
    pyplot.close()
def AbSTRPlot(starName,
              ion,
              points,
              redSet=np.array([]),
              greenSet=np.array([]),
              blueSet=np.array([]),
              lowLimit=None,
              hiLimit=None,
              fileTag='',
              plotTitle='',
              labelPoints=None):
    # For now, just bailing if no points were passed
    if len(points) == 0:
        return

    assert len(points) > 0

    # Labels?
    blackLabels = []
    redLabels = []
    greenLabels = []
    blueLabels = []
    # Plot the passed (np.array) point array in an external file
    abundances = points[:, 0]
    STRs = points[:, 1]
    #    Xmax = max(abundances)
    #    Xmin = min(abundances)
    Ymin = min(STRs)
    Ymax = max(STRs)

    #    # Use an arbitrary Solar+1.0/-1.5 in [X/H] space for the plot limits
    #    solarAB = el.atnoLU(int(ion))[3]
    #    pyplot.axis([np.round(solarAB-0.5,1), np.round(solarAB+1.0,1), np.round(Ymin,1)-0.5, np.round(Ymax,1)+0.5])

    axes = pyplot.gca()

    if len(points) < 500:
        pointSize = 5
        if labelPoints is not None:
            # Must have one label for each point (even if it is '')
            if len(labelPoints) < len(abundances):
                # Must have labels for all the "black" (data) points
                labelPoints = None
            else:
                # Note that array slicing will automatically return empty members
                # for indices beyond the sliced array length
                blackLabels = labelPoints[:len(abundances)]
                redLabels = labelPoints[len(abundances):len(abundances) +
                                        len(redSet)]
                greenLabels = labelPoints[len(abundances) +
                                          len(redSet):len(abundances) +
                                          len(redSet) + len(greenSet)]
                blueLabels = labelPoints[len(abundances) + len(redSet) +
                                         len(greenSet):len(abundances) +
                                         len(redSet) + len(greenSet) +
                                         len(blueSet)]
    else:
        labelPoints = None  # Seriously, don't label more than 30 points
        pointSize = 3
    pyplot.scatter(abundances, STRs, marker='.', s=pointSize + 2)

    # Write in a (tiny) wavelength reference next to each point
    if len(blackLabels) > 0:
        for coord in zip(abundances.tolist(), STRs.tolist(), blackLabels):
            # Place the label below and right of the point
            pyplot.text(coord[0] + 0.02,
                        coord[1] - 0.03,
                        coord[2],
                        color='k',
                        fontsize='xx-small')

    if len(redSet) > 0:
        if len(redSet) < 30:
            pointSize = 5
        else:
            pointSize = 3
        redAbs = redSet[:, 0]
        redSTRs = redSet[:, 1]
        Ymin = min(Ymin, min(redAbs))
        Ymax = max(Ymax, max(redSTRs))
        pyplot.scatter(redAbs, redSTRs, marker='x', color='red', s=pointSize)
        for i in range(len(redLabels)):
            pyplot.text(redSet[i, 0] + 0.02,
                        redSet[i, 1] - 0.03,
                        redLabels[i],
                        color='r',
                        fontsize='xx-small')

    if len(greenSet) > 0:
        if len(greenSet) < 30:
            pointSize = 5
        else:
            pointSize = 3
        greenAbs = greenSet[:, 0]
        greenSTRs = greenSet[:, 1]
        Ymin = min(Ymin, min(greenAbs))
        Ymax = max(Ymax, max(greenSTRs))
        pyplot.scatter(greenAbs,
                       greenSTRs,
                       marker='x',
                       color='green',
                       s=pointSize)
        for i in range(len(greenLabels)):
            pyplot.text(greenSet[i, 0] + 0.02,
                        greenSet[i, 1] - 0.03,
                        greenLabels[i],
                        color='g',
                        fontsize='xx-small')
    if len(blueSet) > 0:
        if len(blueSet) < 30:
            pointSize = 5
        else:
            pointSize = 3
        blueAbs = blueSet[:, 0]
        blueSTRs = blueSet[:, 1]
        Ymin = min(Ymin, min(blueAbs))
        Ymax = max(Ymax, max(blueSTRs))
        pyplot.scatter(blueAbs,
                       blueSTRs,
                       marker='x',
                       color='blue',
                       s=pointSize)
        for i in range(len(blueLabels)):
            pyplot.text(blueSet[i, 0] + 0.02,
                        blueSet[i, 1] - 0.03,
                        blueLabels[i],
                        color='b',
                        fontsize='xx-small')

# DEBUGGING
#    axes.set_ylim([min(STRs)-0.1, max(STRs)+0.1])
    axes.set_xlim([min(abundances) - 0.1, max(abundances) + 0.1])
    axes.set_ylim([np.round(Ymin, 1) - 0.2, np.round(Ymax, 1) + 0.2])
    axes.set_xlabel('[{0}/H]'.format(el.getIonName(ion)))
    axes.set_ylabel('STR. value')
    if plotTitle is not '':
        axes.set_title(plotTitle)

    # Detection Limit?
    if lowLimit is not None:
        detXs = np.array([min(abundances) - 1.0, max(abundances) + 1.0])
        detYs = lowLimit[0] * detXs + lowLimit[1]
        pyplot.plot(detXs.tolist(), detYs.tolist(), 'k--')

    # CoG Limit?
    if hiLimit is not None:
        detYs = hiLimit[0] * detXs + hiLimit[1]
        pyplot.plot(detXs.tolist(), detYs.tolist(), 'k-.')

    # Plot the best-fit abundance line
    # Note: We're trying to fit a (hopefully) vertical line, which is ummmm...
    # ...bad for typical linear regression methods. So, we swap X and Y, and
    # pretend we're fitting a horizontal line (which also give us the ability to
    # use p-values to claim "vertical-ness"
    allPoints = zip(STRs.tolist(), abundances.tolist())
    #    abFitPoints = np.array([point for point in allPoints if point[0]>(lowLimit[0]*point[1] + lowLimit[1])])
    abFitPoints = np.array(allPoints)
    #    avgExPot = np.mean(abFitPoints[:,0])

    # Red = Low corrections
    #    weightArray = [10.0*(4.0-abs(avgExPot-x)) for x in abFitPoints[:,0]]
    #    abSlope, abIntercept = sp.polyfit(abFitPoints[:,0], abFitPoints[:,1], 1, w=weightArray)
    #    pyplot.text(0.80, 0.9, 'slope={0:5.1f}\n[{1}/H]={2:1.2f}+/-{3:1.2f}'.format(1./abSlope, el.getIonName(ion), np.mean(abundances), np.std(abundances)), transform=axes.transAxes, color='r', fontsize='smaller')
    #    detYs = np.array([np.round(Ymin,1)-0.5, np.round(Ymax,1)+0.5])
    #    detXs = abSlope*detYs + abIntercept
    #    pyplot.plot(detXs.tolist(), detYs.tolist(), 'r:')

    # Green = unweighted fit
    #    abSlope, abIntercept, rv, pv, err = sp.stats.linregress(abFitPoints[:,0], abFitPoints[:,1])
    #    pyplot.text(0.80, 0.9, 'slope={0:5.1f}\nR^2-value={1:1.4f}\n[{2}/H]={3:1.2f}+/-{4:1.2f}({5:3d})'.format(1./abSlope, rv**2, el.getIonName(ion), np.mean(abundances), np.std(abundances),len(abundances)), transform=axes.transAxes, color='g', fontsize='smaller')
    if len(redSet) > 0:
        pyplot.text(0.75,
                    0.95,
                    '[{0}/H]={1:1.2f}+/-{2:1.2f}({3:3d})'.format(
                        el.getIonName(ion), np.mean(redAbs), np.std(redAbs),
                        len(redSet)),
                    transform=axes.transAxes,
                    color='r',
                    fontsize='smaller')
#    else:
#        pyplot.text(0.75, 0.95, '(No data)', transform=axes.transAxes, color='r', fontsize='smaller')

    if len(greenSet) > 0:
        pyplot.text(0.75,
                    0.90,
                    '[{0}/H]={1:1.2f}+/-{2:1.2f}({3:3d})'.format(
                        el.getIonName(ion), np.mean(greenAbs),
                        np.std(greenAbs), len(greenSet)),
                    transform=axes.transAxes,
                    color='g',
                    fontsize='smaller')
#    else:
#        pyplot.text(0.75, 0.90, '(No data)', transform=axes.transAxes, color='g', fontsize='smaller')

    if len(blueSet) > 0:
        pyplot.text(0.75,
                    0.85,
                    '[{0}/H]={1:1.2f}+/-{2:1.2f}({3:3d})'.format(
                        el.getIonName(ion), np.mean(blueAbs), np.std(blueAbs),
                        len(blueSet)),
                    transform=axes.transAxes,
                    color='b',
                    fontsize='smaller')


#    else:
#        pyplot.text(0.75, 0.85, '(No Data)', transform=axes.transAxes, color='b', fontsize='smaller')

    pyplot.text(0.75,
                0.80,
                '[{0}/H]={1:1.2f}+/-{2:1.2f}({3:3d})'.format(
                    el.getIonName(ion), np.mean(abundances),
                    np.std(abundances), len(abundances)),
                transform=axes.transAxes,
                color='k',
                fontsize='smaller')

    #    detYs = np.array([np.round(Ymin,1)-0.5, np.round(Ymax,1)+0.5])
    #    detXs = abSlope*detYs + abIntercept
    #    pyplot.plot(detXs.tolist(), detYs.tolist(), 'g:')

    # Do the same for just the points in the linear region of the CoG
    #    linearPoints = np.array([point for point in allPoints if point[0]<(hiLimit[0]*point[1] + hiLimit[1])])
    #    abSlope, abIntercept, rv, pv, err = sp.stats.linregress(linearPoints[:,0], linearPoints[:,1])

    #    pyplot.text(0.50, 0.9, 'slope={0:5.1f}\nR^2-value={1:1.4f}\[email protected]={2:1.2f}'.format(1./abSlope, rv**2, abIntercept), transform=axes.transAxes, color='g', fontsize='smaller')
    #    detXs = abSlope*detYs + abIntercept
    #    pyplot.plot(detXs.tolist(), detYs.tolist(), 'g:')

    #    pyplot.xlabel('[{0}/H]'.format(el.getIonName(ion)))
    #    pyplot.ylabel('Ex.Pot.')
    saveDirName = dirs.XPAbPlotsDir + el.getIonName(ion) + '/'
    try:
        os.stat(saveDirName)
    except:
        os.mkdir(saveDirName[:-1])
    pyplot.savefig('{0}{1}_{2}{3}.png'.format(saveDirName, starName,
                                              el.getIonName(ion), fileTag))
    pyplot.close()
def PlotXPAbs(starData,
              clusterName='NGC-0752',
              ionList=kAllIonList,
              fileTag='',
              labelPlot=True,
              labelPoints=False,
              showTrendLine=False,
              modelAtms=None,
              pradks=None,
              referenceCorrect=False):
    # Make XP vs. Ab for the passed star
    # One element per plot.
    starName = starData[0]
    starParmTuple = tuple(starData[1:])

    isGiant = RC.isGiantStar(starParmTuple)
    if isGiant:
        modelPath = k.GiantModelPath
    else:
        modelPath = k.DwarfModelPath

    if modelAtms == None or pradks == None:
        modelFiles = mk.findDataFiles(modelPath)
        modelAtms, pradks = mk.LoadModels(modelFiles)

    abdict, uncorrLines, unusedMin, unusedMax = \
                AB.CalcAbsAndLines(clusterName+' '+starName,
                                   tuple(starData[1:6]), ionList=ionList,
                                   modelAtms=modelAtms, pradks=pradks)
    # uncorrLines:
    # # {elem.ion:[[Wavelength, Ex.Pot., logGf, eqw, logRW, abund],...]}

    if referenceCorrect:
        if isGiant:  # Obligatory comment on bad Giant corrections, and using
            # Solar instead.
            correctDict, referenceLines, lineWeights = \
            RC.GetSolarCorrections(ionList=ionList,
                                modelAtms=modelAtms,
                                pradks=pradks)
        else:
            correctDict, referenceLines, lineWeights = \
            RC.GetDwarfCorrections(ionList=ionList,
                                modelAtms=modelAtms,
                                pradks=pradks)

    correctionsAvailable = False
    if len(correctDict) > 0 and len(referenceLines) > 0:
        correctionsAvailable = True

    for ion in ionList:
        if ion not in uncorrLines.keys():
            continue
        # Does this element have NLTE corrections available? Note: we do
        # this BEFORE Solar corrections, which assumes that the same
        # NLTE corrections are already applied to any Solar corrections
        # we use.
        if ion in NLTEIons:
            LTELines = AB.CorrectNLTEAbs(ion, uncorrLines[ion],
                                         tuple(starData[1:6]))
        else:
            if ion in uncorrLines.keys():
                LTELines = uncorrLines[ion]
            else:
                # Either synthesized lines, or none available
                LTELines = np.array([])

        # Do we want the "reference corrected" abundances?
        if referenceCorrect and correctionsAvailable:
            tempAdj,tempAll = \
                    RC.SortAndFilterLines(LTELines,
                                       ion,
                                       tuple(starData[1:6]),
                                       solarCorrect=referenceCorrect,
                                       solarLines=referenceLines[ion],
                                       solarCorrs=correctDict[ion],
                                       lineWeights=lineWeights[ion])

            # correctedLines:
            #           [[ab, line STR score, wl, "quality"], ...]
            # allLines:
            #           [[ab, line STR score, wl],...]
            # We want to use np.arrays, so...
            allLines = np.array(tempAll)
            correctedLines = np.array(tempAdj)
            if len(allLines) == 0 or len(correctedLines) == 0:
                correctionsAvailable = False
            elif len(allLines) == 1 or len(correctedLines) == 1:
                print('Single Line determination:{0}'.format(starData[0]))
                print(allLines, correctedLines)
        # One plot per ion.
        if labelPlot:
            plotLabel = 'XP vs Ab for [{2}/H] in {0} {1}.'.\
                        format(clusterName, starName, el.getIonName(ion))
        else:
            plotLabel = ''

        if referenceCorrect and correctionsAvailable:
            tempPoints = []
            for line in uncorrLines[ion]:
                correctedAbs = [l[0] for l in correctedLines if \
                                u.in_range(l[2],line[0]-0.05, line[0]+0.05)]
                if len(correctedAbs) > 0:
                    tempPoints.append(
                        [line[1],
                         np.mean(correctedAbs), line[3], line[0]])
                else:
                    tempPoints.append([line[1], line[5], line[3], line[0]])
            XPAbPoints = np.array(tempPoints)
        else:
            XPAbPoints = np.array([[line[1],line[5],line[3],line[0]]\
                                for line in uncorrLines[ion]])
        if labelPoints:
            # Label the points with the wavelength
            pointLabels = ['{0:2.3f}'.format(point[3]) \
                           for point in XPAbPoints]
        else:
            pointLabels = None

        ps.XPAbPlot(XPAbPoints,
                    starName,
                    ion,
                    fileTag=fileTag + 'XPAb',
                    plotTitle=plotLabel,
                    pointLabels=pointLabels,
                    showTrendLine=showTrendLine)
def PlotClusterAbs(clusterName='NGC-0752',
                   ionList=kAllIonList,
                   fileTag='',
                   mass=1.2,
                   metallicity=0.0,
                   solarRelative=False,
                   referenceCorrect=False):
    giantParms = GetGiantStarParms(clusterName=clusterName,\
                                   mass=mass, metallicity=metallicity)
    modelFiles = mk.findDataFiles(k.GiantModelPath)
    gAtms, gPradks = mk.LoadModels(modelFiles)
    modelFiles = mk.findDataFiles(k.DwarfModelPath)
    dAtms, dPradks = mk.LoadModels(modelFiles)

    gAbs = GetAbsForStars(giantParms,\
                          gModelAtms=gAtms, gPradks=gPradks,\
                          dModelAtms=dAtms, dPradks=dPradks,\
                          referenceCorrect=referenceCorrect)

    gIons = sorted([ion for ion in gAbs.keys() if ion in ionList])
    if solarRelative:
        gElems = [gAbs[i][0] for i in gIons]
    else:
        solarFeH = PA.ptoe[25][PA.abIdx]
        starIons = gAbs.keys()
        starFeH = GetStarFeH(gAbs)

        gElems = [
            gAbs[i][0] - PA.ptoe[int(i) - 1][PA.abIdx] - starFeH for i in gIons
        ]

    gVar = [gAbs[i][1] for i in gIons]

    dwarfParms = GetDwarfStarParms(clusterName=clusterName,\
                                   mass=mass, metallicity=metallicity)

    dAbs = GetAbsForStars(dwarfParms,\
                          gModelAtms=gAtms, gPradks=gPradks,\
                          dModelAtms=dAtms, dPradks=dPradks,\
                          referenceCorrect=referenceCorrect)

    dIons = sorted([ion for ion in dAbs.keys() if ion in ionList])
    if solarRelative:
        dElems = [dAbs[i][0] for i in dIons]
    else:
        #        solarFeH = PA.ptoe[25][PA.abIdx] - calculated in giants, above
        starIons = dAbs.keys()
        starFeH = GetStarFeH(dAbs)

        dElems = [
            dAbs[i][0] - PA.ptoe[int(i) - 1][PA.abIdx] - starFeH for i in dIons
        ]

    dVar = [dAbs[i][1] for i in dIons]

    ionLUT = {}

    for num, ion in enumerate(sorted(set(dIons + gIons))):
        ionLUT[ion] = num

    ionLabels = [' -', ' ']
    for ion in sorted(ionLUT.keys()):
        ionLabels.append(el.getIonName(ion))
    ionLabels.append(' ')

    fig = pyplot.figure()
    ax = fig.gca()

    ax.errorbar([ionLUT[ion] for ion in gIons], gElems, yerr=gVar, fmt='rs',\
                label=clusterName+' giants')
    ax.errorbar([ionLUT[ion] for ion in dIons], dElems, yerr=dVar, fmt='bo',\
                label=clusterName+' dwarfs')

    ax.xaxis.set_major_locator(pyplot.MultipleLocator(1))
    ax.set_xticklabels(ionLabels, rotation='vertical')
    ax.set_xlabel('Ion')
    ax.set_xlim(left=-1, right=len(ionLUT.keys()))
    if solarRelative:
        ax.set_ylabel('[X/H]')
    else:
        ax.set_ylabel('[X/Fe]')
#    ax.set_ylim(bottom=-0.4, top=0.5)
    if not solarRelative:
        ax.set_ylim(bottom=np.average(gElems + dElems) - 0.5,
                    top=np.average(gElems + dElems) + 0.5)
    else:
        ax.set_ylim(bottom=0, top=9)
    ax.legend(numpoints=1)
    ax.axhline(y=0.0,
               xmin=-1,
               xmax=len(ionLUT.keys()),
               color='g',
               linestyle='--')
    #    pyplot.show()
    pyplot.savefig(dirs.PlotDir + clusterName + 'Abs' + fileTag + '.png')
    pyplot.close()
    return
def MakeAbTable(clusterName='NGC-0752',
                starDataList=None,
                ions=kAllIonList,
                outFilename=k.TempAbOutFilename,
                filterBlends=False,
                referenceCorrect=False,
                useDAOSpec=False,
                headerLeft='',
                headerRight=''):

    if starDataList == None:
        starDataList = GetAllStarParms(clusterName=clusterName)

    # Lookup the abundance(s) for the passed star(s), and create a LaTeX chart

    tableDict = GetAbTable(clusterName, starDataList, ions, filterBlends,
                           referenceCorrect, useDAOSpec)

    giantNames = np.array([s[0] for s in starDataList \
        if RC.isGiantStar(s[1:5])])
    #    dwarfNames = np.array([s[0] for s in starDataList
    #        if not RC.isGiantStar(s[1],s[2])])

    # Iron abundance is listed as [Fe/H], all others will be [X/Fe].

    # Compile a cluster/dwarfs/giants average table entry.
    # Entries are of the form:
    # {Ion:[[star ab, star line quality], ...], ...}
    clusterDict = {}
    dwarfDict = {}
    giantDict = {}
    for star in tableDict.keys():
        # Place this stars measures into the proper category dictionary
        if star in giantNames:
            catDict = giantDict
        else:
            catDict = dwarfDict

        starFe = GetStarFeH(tableDict[star])

        for ion in tableDict[star].keys():
            solarIonH = PA.ptoe[int(ion) - 1][PA.abIdx]
            if tableDict[star][ion][0] == 0.:
                continue

            if ion not in [26.0, 26.1]:
                # Adjust values for [X/Fe]
                tableDict[star][ion][0] = tableDict[star][ion][0]\
                                          - solarIonH\
                                          - starFe

            if ion in clusterDict.keys():
                clusterDict[ion].append([tableDict[star][ion][0],\
                                         tableDict[star][ion][3]])
            else:
                clusterDict[ion] = [[tableDict[star][ion][0],\
                                     tableDict[star][ion][3]]]

            if ion in catDict.keys():
                catDict[ion].append([tableDict[star][ion][0],\
                                     tableDict[star][ion][3]])
            else:
                catDict[ion] = [[tableDict[star][ion][0],\
                                 tableDict[star][ion][3]]]

    idxName = clusterName + ' (all)'
    tableDict[idxName] = {}
    for ion in clusterDict.keys():
        # If each star's ab measurement for are "independent measures" of the
        # cluster abundance, we should divide the stdev by sqrt(num_measures)...
        # Calcs broken into separate lines for readability.
        cMean = np.mean([l[0] for l in clusterDict[ion]])
        cStd = np.std([l[0] for l in clusterDict[ion]])
        cScoreMean = np.mean([l[1] for l in clusterDict[ion]])
        tableDict[idxName][ion] = \
                        [cMean, cStd, len(clusterDict[ion]), cScoreMean]

    idxName = clusterName + ' (dwarfs)'
    tableDict[idxName] = {}
    for ion in dwarfDict.keys():
        dMean = np.mean([l[0] for l in dwarfDict[ion]])
        dStd = np.std([l[0] for l in dwarfDict[ion]])
        dScoreMean = np.mean([l[1] for l in dwarfDict[ion]])
        tableDict[idxName][ion] = \
                    [dMean, dStd, len(dwarfDict[ion]), dScoreMean]

    idxName = clusterName + ' (giants)'
    tableDict[idxName] = {}
    for ion in giantDict.keys():
        gMean = np.mean([l[0] for l in giantDict[ion]])
        gStd = np.std([l[0] for l in giantDict[ion]])
        gScoreMean = np.mean([l[1] for l in giantDict[ion]])
        tableDict[idxName][ion] = \
                    [gMean, gStd, len(giantDict[ion]), gScoreMean]

    ions = sorted(list(set(ions)))
    # The cluster name starts with "N", so it will be first in the list
    nameList = sorted(tableDict.keys())

    outfile = open(outFilename, 'w')

    latexHeader = kLaTexHeader1 + '\\rhead{\\textbf{' + headerRight\
                  + '}}\n\\lhead{\\textbf{' + headerLeft\
                  + '}}\n\\begin{document}\n'
    outfile.write(latexHeader)
    # New page/table:
    for tableCount in range(int(len(nameList) / 6) + 1):
        outfile.write('\\begin{landscape}\n'\
                      + '\\hspace*{-5cm}\n'\
                      + '\\begin{tabular}{|l|l|l|l|l|l|l|')
        outfile.write('}\n\\multicolumn{1}{l}{Ion}')
        for name in nameList[tableCount * 6:(tableCount + 1) * 6]:
            outfile.write(' & \\multicolumn{{1}}{{l}}{{{0}}}'.format(name))
        outfile.write('\\\\\n\\hline\n')

        # A little bit of stupidity to put FeI and FeII at the top of the table:
        printIons = sorted(ions)
        printIons.remove(26.)
        printIons.remove(26.1)
        printIons = [26.0, 26.1] + printIons

        for ion in printIons:
            if int(ion) == 26:
                outfile.write('[{0}/H]'.format(el.getIonName(ion)))
            else:
                outfile.write('[{0}/Fe]'.format(el.getIonName(ion)))

            for star in nameList[tableCount * 6:(tableCount + 1) * 6]:
                if ion in tableDict[star].keys(
                ) and tableDict[star][ion][2] > 0:
                    outfile.write(' & {0:3.2f}$\pm${1:3.2f} ({2:d}, {3:1.1f})'.\
                                  format(tableDict[star][ion][0],
                                         tableDict[star][ion][1],
                                         tableDict[star][ion][2],
                                         tableDict[star][ion][3]))
                else:
                    outfile.write(' & \multicolumn{1}{c|}{---}')

            outfile.write('\\\\\n\\hline\n')
            # Place a double line after the Fe/H measures
            if ion == 26.1:
                outfile.write('\\hline\n')

        outfile.write('\\label{{tab:752Abs-{0}}}\n'.format(tableCount + 1) +
                      '\\end{tabular}\n\\end{landscape}\n' + '\\clearpage\n')

    outfile.write('\\end{document}\n')
    outfile.close()
def MakeTAbPlots(clusterName='NGC-0752',
                 starDataList=None,
                 ionList=STP.kAllIonList,
                 fileTag='',
                 useSubfigures=False,
                 referenceCorrect=False):
    # Create a bunch of .ps plots with the star's effective temperature vs. [X/Fe]
    # for all ions in the optional passed list. One ion per plot

    if starDataList == None:
        starDataList = STP.GetAllStarParms(clusterName=clusterName)

    abTable = STP.GetAbTable(clusterName=clusterName,
                             starDataList=starDataList,
                             ions=ionList,
                             referenceCorrect=referenceCorrect)

    solarFeH = PA.ptoe[25][PA.abIdx]

    clusterFeH = \
        0.75*np.mean([abTable[star][26.0][0] for star in abTable.keys()])+\
        0.25*np.mean([abTable[star][26.1][0] for star in abTable.keys() \
            if 26.1 in abTable[star].keys()])

    for ion in ionList:

        solarIonH = PA.ptoe[int(ion) - 1][PA.abIdx]

        fig = pyplot.figure()
        ax = pyplot.gca()

        redGPoints = []
        magGPoints = []
        bluDPoints = []
        cyaDPoints = []
        for star in starDataList:
            starName = star[0]
            if starName not in abTable.keys():
                continue
            starIons = sorted(abTable[starName].keys())
            if ion not in starIons:
                continue

            starParms = star[1:]

            # Get the Fe/H for this star. Note: We don't do Fe/Fe comps.
            if int(ion) != 26:
                # If both ions are measured, weight 75/25 for FeI/FeII
                if 26.0 in starIons and 26.1 in starIons:
                    starFe = 0.75*abTable[starName][26.0][0]\
                             + 0.25*abTable[starName][26.1][0]\
                             - solarFeH
                else:
                    starFe = abTable[starName][26.0][0] - solarFeH
            else:
                starFe = 0.

            if RC.isGiantStar(starParms):
                #                if starParms[5] < 50:
                #                    magGPoints.append([starParms[0],
                #                                   abTable[starName][ion][0]-solarIonH-starFe,
                #                                   abTable[starName][ion][1]])
                #                else:
                redGPoints.append([
                    starParms[0],
                    abTable[starName][ion][0] - solarIonH - starFe,
                    abTable[starName][ion][1]
                ])
            else:
                #                if starParms[5] < 25:
                #                    cyaDPoints.append([starParms[0],
                #                                   abTable[starName][ion][0]-solarIonH-starFe,
                #                                   abTable[starName][ion][1]])
                #                else:
                bluDPoints.append([
                    starParms[0],
                    abTable[starName][ion][0] - solarIonH - starFe,
                    abTable[starName][ion][1]
                ])

        dMean = np.mean([l[1] for l in cyaDPoints + bluDPoints])
        dStd = np.std([l[1] for l in cyaDPoints + bluDPoints])
        ax.axhline(y=dMean, ls='dashed', color='b',
                   label=r'Dwarf Avg. (${0:4.2f}\pm{1:4.2f}$)'.\
                   format(dMean,dStd))
        ax.axhline(y=dMean - dStd, ls='dotted', color='b')
        ax.axhline(y=dMean + dStd, ls='dotted', color='b')

        gMean = np.mean([l[1] for l in redGPoints + magGPoints])
        gStd = np.std([l[1] for l in redGPoints + magGPoints])
        ax.axhline(y=gMean, ls='dashed', color='r',
                   label=r'Giant Avg. (${0:4.2f}\pm{1:4.2f}$)'.\
                   format(gMean,gStd))
        ax.axhline(y=gMean - gStd, ls='dotted', color='r')
        ax.axhline(y=gMean + gStd, ls='dotted', color='r')

        ax.axhline(y=0., ls='dashed', color='g', linewidth=1.0,\
                   label='Solar (${0:4.2f}$)'.\
                   format(PA.ptoe[int(ion)-1][PA.abIdx]))

        pyplot.rcParams.update({'legend.fontsize': 10})
        ax.legend()

        if dMean > 0. and gMean > 0.:
            ax.set_ylim([
                min([dMean - 0.5, gMean - 0.5]),
                max([dMean + 0.5, gMean + 0.5])
            ])
        elif dMean > 0.:
            ax.set_ylim([dMean - 0.5, dMean + 0.5])
        elif gMean > 0:
            ax.set_ylim([gMean - 0.5, gMean + 0.5])

        Xs = [l[0] for l in bluDPoints]
        Ys = [l[1] for l in bluDPoints]
        Es = [l[2] for l in bluDPoints]
        eb = ax.errorbar(Xs, Ys, yerr=Es, fmt='o', color='b')
        if len(eb) > 0 and len(eb[-1]) > 0: eb[-1][0].set_linestyle('--')

        #        Xs = [l[0] for l in cyaDPoints]
        #        Ys = [l[1] for l in cyaDPoints]
        #        Es = [l[2] for l in cyaDPoints]
        #        eb=ax.errorbar(Xs, Ys, yerr=Es, fmt='s', color='c')
        #        if len(eb)>0 and len(eb[-1])>0: eb[-1][0].set_linestyle('--')

        Xs = [l[0] for l in redGPoints]
        Ys = [l[1] for l in redGPoints]
        Es = [l[2] for l in redGPoints]
        eb = ax.errorbar(Xs, Ys, yerr=Es, fmt='o', color='r')
        if len(eb) > 0 and len(eb[-1]) > 0: eb[-1][0].set_linestyle('--')

        #        Xs = [l[0] for l in magGPoints]
        #        Ys = [l[1] for l in magGPoints]
        #        Es = [l[2] for l in magGPoints]
        #        eb=ax.errorbar(Xs, Ys, yerr=Es, fmt='s', color='m')
        #        if len(eb)>0 and len(eb[-1])>0: eb[-1][0].set_linestyle('--')

        ionStr = el.getIonName(ion)

        if int(ion) != 26:
            ax.set_ylim((-0.5, 0.5))
        else:
            ax.set_ylim((-0.3, 0.3))

        ax.set_xlabel(r'$T_{eff}$ (K)')
        if int(ion) != 26:
            ax.set_ylabel(r'$[{0}/Fe]$'.format(ionStr))
        else:
            ax.set_ylabel(r'$[{0}]$'.format(ionStr))

        pyplot.savefig('{0}{1}{2}.png'.format(k.PlotDir + 'Elems/', ionStr,
                                              fileTag),
                       figure=fig)
        #        pyplot.show()
        pyplot.close(fig)
def PlotFeXx(clusterName='NGC-0752', starDataList=None, fileTag='', groupErrors=False,\
             ionList=STP.kAllIonList, filterBlends=False, referenceCorrect=False):


    # abTable = {starID:element/ion:[X/H, sigma, #, quality score]}
    abTable=STP.GetAbTable(clusterName=clusterName, starDataList=starDataList,\
             ions=ionList, filterBlends=filterBlends, referenceCorrect=referenceCorrect)

    SolarFe = PA.ptoe[25][PA.abIdx]

    for ion in ionList:
        Xs = []
        Ys = []
        XErrs = []
        YErrs = []
        colors = []
        allPts = []
        SolarY = float(PA.ptoe[int(ion)-1][PA.abIdx])
        for star in abTable.keys():
            starAbs = abTable[star]
            starFe = float(STP.GetStarFeH(starAbs))
            if ion in starAbs.keys():
                if not(u.is_number(starAbs[ion][0]) and \
                    u.is_number(starAbs[26.0][1]) and \
                    u.is_number(starAbs[ion][1])):
                    continue
                adj = SolarY
                if ion != 26.0:
                    adj+=starFe
                allPts.append([float(starFe), float(starAbs[ion][0])-adj, float(starAbs[26.0][1]), float(starAbs[ion][1]), ColorLookup(star)])
                
        yElem = EL.getIonName(ion)
        fig = pyplot.figure()
        axes = fig.gca()
        allPts = np.array(allPts)
#        allPts = np.array(zip(Xs, Ys, XErrs, YErrs, colors))

        gAbs = np.array([p[1] for p in allPts if p[4]=='r']).astype(np.float)
        gAvg = np.mean(gAbs)
        gStd = np.std(gAbs)
        gFeAbs = np.array([p[0] for p in allPts if p[4]=='r']).astype(np.float)
        gFeAvg = np.mean(gFeAbs)
        gFeStd = np.std(gFeAbs)
        dAbs = np.array([p[1] for p in allPts if p[4]=='b']).astype(np.float)
        dAvg = np.mean(dAbs)
        dStd = np.std(dAbs)
        dFeAbs = np.array([p[0] for p in allPts if p[4]=='b']).astype(np.float)
        dFeAvg = np.mean(dFeAbs)
        dFeStd = np.std(dFeAbs)
        
        axes.axhline(y=gAvg, ls='dashed', color='r', 
             label=r'Giant Avg. (${0:4.2f}\pm{1:4.2f}$)'.\
                     format(gAvg,gStd))
        axes.axhline(y=gAvg+gStd, ls='dotted', color='r')
        axes.axhline(y=gAvg-gStd, ls='dotted', color='r')
        
        axes.axhline(y=dAvg, ls='dashed', color='b', 
             label=r'Dwarf Avg. (${0:4.2f}\pm{1:4.2f}$)'.\
                     format(dAvg,dStd))
        axes.axhline(y=dAvg+dStd, ls='dotted', color='b')
        axes.axhline(y=dAvg-dStd, ls='dotted', color='b')

#        axes.axhline(y=SolarY, ls='dashed', color='g', 
#             label=r'Solar ({0:4.2f})'.format(SolarY))
        axes.axhline(y=0., ls='dashed', color='g', 
             label=r'Solar ({0:4.2f})'.format(SolarY))
        Xs = np.array(allPts[:,0]).astype(np.float)
        XErrs = np.array(allPts[:,2]).astype(np.float)
        xMin = max(np.median(Xs)-0.3, min(Xs)-0.1)
        xMax = min(np.median(Xs)+0.3, max(Xs)+0.1)
        axes.set_xlim(xMin, xMax)
        Ys = np.array(allPts[:,1]).astype(np.float)
        YErrs = np.array(allPts[:,3]).astype(np.float)
        yMin = min(np.median(Ys)-0.3, min(Ys))
        yMax = max(np.median(Ys)+0.3, max(Ys))
        axes.set_ylim(yMin, yMax)
        axes.set_xlabel('[Fe/H]', fontsize=18)
        if ion != 26.0:
            axes.set_ylabel('['+yElem+'/Fe]', fontsize=18)
        else:
            axes.set_ylabel('['+yElem+'/H]', fontsize=18)
        
        if groupErrors:
            axes.scatter(gFeAbs, gAbs, marker='o', color='r')
            eb = axes.errorbar(gFeAvg, gAvg, xerr=gFeStd,\
                linestyle='None', markersize=12.,  marker='H', color='r', ecolor='r', \
                label='Giant Mean', capsize=10., elinewidth=2, markerfacecolor='None')
            eb[-1][0].set_linestyle('--')
#            eb[-1][1].set_linestyle('--')
            eb[-1][0].set_linewidth(2.)
#            eb[-1][1].set_linewidth(2.)
            axes.scatter(dFeAbs, dAbs, marker='o', color='b')
            eb = axes.errorbar(dFeAvg, dAvg, xerr=dFeStd,\
                linestyle='None', markersize=12., marker='H', color='b', ecolor='b', \
                label='Dwarf Mean', capsize=10., elinewidth=2, markerfacecolor='None')
            eb[-1][0].set_linestyle('--')
#            eb[-1][1].set_linestyle('--')
            eb[-1][0].set_linewidth(2.)
#            eb[-1][1].set_linewidth(2.)
        else:
            eb = axes.errorbar(Xs, Ys, yerr=YErrs, xerr=XErrs,\
                linestyle='None', marker='o', ecolor=allPts[:,4])
            eb[-1][0].set_linestyle(':')
            eb[-1][1].set_linestyle(':')
            eb[-1][0].set_linewidth(0.5)
            eb[-1][1].set_linewidth(0.5)

        axes.legend()
        pyplot.savefig(dirs.RelAbsDir+'Fe_'+yElem+fileTag+'.png')
        pyplot.close()
def PlotAllCombos():
    abTable=STP.GetAbTable()
    
    ionsToCombine=[6.0,7.0,8.0,11.0,12.0,13.0,14.0,20.0,22.0,26.0,63.1]
    allCombos = u.Cartesian(ionsToCombine,ionsToCombine)
#    allCombos = u.Cartesian(STP.kAllIonList, STP.kAllIonList)
    elemCombos = np.array([i for i in allCombos if i[0]<i[1]])

    SolarFe = PA.ptoe[25][PA.abIdx]

    for combo in elemCombos:
        Xs = []
        Ys = []
        XErrs = []
        YErrs = []
        colors = []
        for star in abTable.keys():
            starAbs = abTable[star]
            if combo[0] in starAbs.keys() and combo[1] in starAbs.keys():
                starFe = 0.75*starAbs[26.0][0] + 0.25*starAbs[26.1][0] - SolarFe
                
                SolarX = PA.ptoe[int(combo[0])-1][PA.abIdx]
                Xs.append(starAbs[combo[0]][0] - starFe - SolarX)
                XErrs.append(starAbs[combo[0]][1])
                
                SolarY = PA.ptoe[int(combo[1])-1][PA.abIdx]
                Ys.append(starAbs[combo[1]][0] - starFe - SolarY)
                YErrs.append(starAbs[combo[1]][1])

                colors.append(ColorLookup(star))
                
        slope, intercept, rVal, pVal, stderr = linregress(Xs, Ys)
        xElem = EL.getIonName(combo[0])
        yElem = EL.getIonName(combo[1])
        fig = pyplot.figure()
        ax = fig.gca()
        
        for pt in zip(Xs, Ys, XErrs, YErrs, colors):
            if pt[4] == 'm' or pt[4]=='c':
                shape='s'
            else:
                shape='o'
            eb = pyplot.errorbar(pt[0], pt[1], yerr=pt[3], xerr=pt[2],\
                linestyle='None', marker=shape, color=pt[4])
            eb[-1][0].set_linestyle('--')
            eb[-1][1].set_linestyle('--')

        minX = min(Xs)
        maxX = max(Xs)
        pyplot.plot([minX,maxX],[intercept+slope*minX, intercept+slope*maxX], 'k:')
        xMin = min(np.median(Xs)-0.5, minX)
        xMax = max(np.median(Xs)+0.5, maxX)
        ax.set_xlim(xMin, xMax)
        
        yMin = min(np.median(Ys)-0.5, min(Ys))
        yMax = max(np.median(Ys)+0.5, max(Ys))
        ax.set_ylim(yMin, yMax)
        
        pyplot.xlabel('['+xElem+'/Fe]')
        pyplot.ylabel('['+yElem+'/Fe]')
        ax.text(0.95, 0.01, 'Slope:{0:4.2f}, R-squared:{1:4.2f}, P-val:{2:4.2f}'.format(slope,rVal**2,pVal), fontsize=10, verticalalignment='bottom', horizontalalignment='right', transform=ax.transAxes,)
        pyplot.savefig(dirs.RelAbsDir+xElem+'_'+yElem+'.png')
        pyplot.close()
def MakeVPlots(clusterName='NGC-0752',
               starDataList=None,
               fileTag='',
               filterBlends=False,
               referenceCorrect=False,
               useDAOSpec=False,
               ions=[20.0]):
    # Function plots V_turb vs. sigma [Ca/H] (sigma is the line-to-line
    # standard deviation of the measured Ca lines), for a range of V_turb values.
    # Intended to provide a spectroscopic confirmation/adjustment
    # for photometrically-determined parameters.
    if starDataList is None:
        starDataList = STP.GetAllStarParms(clusterName=clusterName)

    dModelFiles = mk.findDataFiles(k.DwarfModelPath)
    dModelAtms, dPradks = mk.LoadModels(dModelFiles)
    dCorrectDict, dReferenceLines, dLineWeights = \
            RC.GetDwarfCorrections(ionList=ions,
                                modelAtms=dModelAtms,
                                pradks=dPradks)

    gModelFiles = mk.findDataFiles(k.GiantModelPath)
    gModelAtms, gPradks = mk.LoadModels(gModelFiles)
    # Note: We're using dwarf corrections for giant stars...
    # because they're better than giant corrections for the
    # giant stars. This needs to be fixed. :(
    gCorrectDict, gReferenceLines, gLineWeights = \
            RC.GetSolarCorrections(ionList=ions,
                                modelAtms=dModelAtms,
                                pradks=dPradks)
    # For now, CaI appears to work best for all stars.
    # VI, Ti I/II, Fe I/II, Cr I/II also work, but not as well - (See Reddy, et al. 2012).
    #    ions = [20.0]
    abDict = {}

    colorArray=['r','orange','gold','darkgreen','navy',\
                'm','saddlebrown','skyblue','hotpink']

    for starParms in starDataList:
        if RC.isGiantStar(starParms[1:]):
            modelAtms = gModelAtms
            pradks = gPradks
            refLines = gReferenceLines
            refDict = gCorrectDict
            lineWeights = gLineWeights
        else:
            modelAtms = dModelAtms
            pradks = dPradks
            refLines = dReferenceLines
            refDict = dCorrectDict
            lineWeights = dLineWeights

        starPoints = {}
        for v in np.linspace(0.5, 3.0, 26):
            parmTuple = (starParms[0], starParms[1], starParms[2], v, \
                         starParms[4], starParms[5], starParms[6])

            abDict[v] = STP.GetAbsForStar(parmTuple, ions=ions,\
                filterBlends=filterBlends, refCorrect=referenceCorrect,\
                refDict=refDict, refLines=refLines, lineWeights=lineWeights,\
                useDAOSpec=useDAOSpec, modelAtms=modelAtms, pradks=pradks)

            for ion in abDict[v].keys():
                if ion not in starPoints.keys():
                    starPoints[ion] = {}
                if abDict[v][ion][0] == 0.:
                    continue
                starPoints[ion][v] = abDict[v][ion][1]

        colorIdx = 0

        ymaxes = []
        for ion in starPoints.keys():
            Xs = sorted(np.array(list(starPoints[ion].keys())))
            if len(Xs) == 0 or ion in STP.SynthAbsDict.keys():
                continue
            Ys = np.array([starPoints[ion][x] for x in Xs])
            if len(Xs) < 2 or len(Ys) < 2:
                continue
            Ys = Ys / min(Ys)
            ymaxes.append(max(Ys))
            try:
                minV = Xs[np.where(Ys == min(Ys))[0][0]]
            except IndexError:
                continue
            pyplot.plot(Xs,
                        Ys,
                        label=r'$({1}) V_{{turb}}={0:3.1f}km/sec$'.format(
                            minV, el.getIonName(ion)),
                        color=colorArray[colorIdx])
            pyplot.scatter(Xs, Ys, color=colorArray[colorIdx])
            pyplot.axvline(minV, linestyle=':', color=colorArray[colorIdx])
            colorIdx += 1
            if colorIdx == len(colorArray): colorIdx = 0
        ax = pyplot.gca()
        ax.set_xlabel(r'$V_{{turb}} km/s$')
        ax.set_ylabel('Normalized [X/H] variance')
        ax.set_ylim((0., min(5.0, max(ymaxes))))
        pyplot.legend(fontsize=8)
        pyplot.savefig(k.ParmPlotDir + 'Vturb/' + starParms[0] + fileTag +
                       '.png')
        pyplot.close()
def MakeTeffIonPlots(clusterName='NGC-0752',
                     starDataList=None,
                     fileTag='',
                     filterBlends=False,
                     referenceCorrect=False,
                     useDAOSpec=False):
    # Function plots Teff vs. [TiI/TiII] for a range of temperatures.
    # Intended to provide a spectroscopic confirmation/adjustment
    # for photometrically-determined parameters.

    if starDataList is None:
        starDataList = STP.GetAllStarParms(clusterName=clusterName)

    dModelFiles = mk.findDataFiles(k.DwarfModelPath)
    dModelAtms, dPradks = mk.LoadModels(dModelFiles)
    gModelFiles = mk.findDataFiles(k.GiantModelPath)
    gModelAtms, gPradks = mk.LoadModels(gModelFiles)
    # Want to watch TiI/TiII
    ions = [22.0, 22.1]
    abDict = {}
    dTeffRange = np.linspace(4500, 7000, 101)
    gTeffRange = np.linspace(3500, 6000, 101)

    for TeffIdx in range(len(dTeffRange)):
        tempParmList = []
        for s in starDataList:
            if s[1] < k.giantTeffLimit and s[2] < k.giantLogGLimit:
                Teff = gTeffRange[TeffIdx]
            else:
                Teff = dTeffRange[TeffIdx]
            tempParmList.append((s[0], Teff, s[2], s[3], s[4], s[5], s[6]))
        abDict[Teff] = STP.GetAbTable(clusterName=clusterName,
                                      starDataList=tempParmList,
                                      ions=ions,
                                      filterBlends=filterBlends,
                                      referenceCorrect=referenceCorrect,
                                      useDAOSpec=useDAOSpec,
                                      gModelAtms=gModelAtms,
                                      gPradks=gPradks,
                                      dPradks=dPradks,
                                      dModelAtms=dModelAtms)
    starPoints = {}
    for Teff in abDict.keys():
        for star in abDict[Teff].keys():
            if star not in starPoints.keys():
                starPoints[star] = {}
            # TiI/TiII points:
            if 22.0 in abDict[Teff][star].keys() and \
               22.1 in abDict[Teff][star].keys():
                if 22.0 not in starPoints[star].keys():
                    starPoints[star][22.0] = {}
                starPoints[star][22.0][Teff] =\
                    abDict[Teff][star][22.0][0] - abDict[Teff][star][22.1][0]

    for star in starPoints.keys():
        fig = pyplot.figure()

        starData = [s for s in starDataList if s[0] == star]
        isGiant = False
        if len(starData) > 0: isGiant = STP.isGiantStar(starData[0][1:])
        for ion in starPoints[star].keys():

            Xs = np.array(sorted(starPoints[star][ion].keys()))
            Ys = np.array([starPoints[star][ion][x] for x in Xs])
            if isGiant:
                Xs = Xs - 1000.

            interpTs = np.interp([-0.1, 0., 0.1], Ys, Xs)
            pyplot.scatter(Xs, Ys,
                        label=r'${0}({1:4.0f}^{{+{2:3.0f}}}_{{-{3:3.0f}}}$)'.\
                        format(el.getIonName(ion),interpTs[1],\
                               interpTs[1]-interpTs[0],\
                               interpTs[2]-interpTs[1]), marker='.')
            pyplot.axhline(0.0, linestyle=':')
        ax = pyplot.gca()
        ax.set_xlabel(r'$T_{{eff}}$')
        ax.set_ylabel('[TiI/TiII]')
        pyplot.legend()
        pyplot.savefig(k.ParmPlotDir + 'Teff/' + star + fileTag + '_TiRel.png')
        pyplot.close()
def XPAbPlot(points,
             starName,
             ion,
             fileTag='',
             plotTitle='',
             pointLabels=None,
             showTrendLine=False):
    # Plot the Excitation potential vs abundance for the passed points.
    # The passed data, in the array 'points' is of the form:
    # [[Ex. Pot, [X/H], EQW (mA), wl](A), ...]
    # For now, just bailing if no points were passed
    if len(points) == 0:
        return
    assert len(points) > 0

    # We're rounding 'cause...Python.
    XPs = np.around(points[:, 0], 4)
    Abs = points[:, 1]

    fig = pyplot.figure()
    axes = pyplot.gca()

    Xmin = min(XPs) * 0.9
    if Xmin == 0.:
        Xmin = -0.25
    Xmax = max(XPs) + 0.25

    Ymin = min(Abs) - 0.2
    Ymax = max(Abs) + 0.2

    pyplot.scatter(XPs, Abs, figure=fig, marker='o', s=9)

    # Write in a (tiny) label next to each point
    if pointLabels is not None:
        for coord in zip(XPs.tolist(), Abs.tolist(), pointLabels):
            # Place the label below and right of the point
            pyplot.text(coord[0] + np.random.random() * 0.04 * (Xmax - Xmin),
                        coord[1] - np.random.random() * 0.06 * (Ymax - Ymin),
                        coord[2],
                        color='k',
                        fontsize='xx-small')

    # Fit a line, if desired
    if showTrendLine:
        slope, intercept, rVal, pVal, err = sp.stats.linregress(XPs, Abs)
        pyplot.plot([Xmin, Xmax],
                    [intercept + slope * Xmin, intercept + slope * Xmax], 'g:')
        axes.text(0.95, 0.01, 'Slope:{0:4.2f}, R-squared:{1:4.2f}'.format\
                (slope,rVal**2), fontsize=9, verticalalignment='bottom',\
                horizontalalignment='right', transform=axes.transAxes,)
    # Show mean and standard deviation range:
    mean = np.mean(Abs)
    std = np.std(Abs)
    axes.axhline(y=mean,
                 ls='dashed',
                 color='r',
                 label=r'$[{0}/H]:{1:4.2f}\pm{2:4.2f}$'.format(
                     el.getIonName(ion), mean, std))
    axes.axhline(y=mean - std, ls='dotted', color='r')
    axes.axhline(y=mean + std, ls='dotted', color='r')
    pyplot.plot([Xmin, Xmax],
                [intercept + slope * Xmin, intercept + slope * Xmax], 'g:')
    pyplot.plot([Xmin, Xmax],
                [intercept + slope * Xmin, intercept + slope * Xmax], 'g:')

    # Axes labels and ranges
    axes.set_ylim([Ymin, Ymax])
    axes.set_xlim([Xmin, Xmax])
    axes.set_xlabel('Excitation Potential (eV)')
    axes.set_ylabel('Abundance [X/H]')
    axes.legend()

    if plotTitle is not '':
        axes.set_title(plotTitle)

    saveDirName = dirs.XPAbPlotsDir + el.getIonName(ion) + '/'
    try:
        os.stat(saveDirName)
    except:
        os.mkdir(saveDirName[:-1])
    pyplot.savefig('{0}{1}_{2}{3}.png'.format(saveDirName, starName,
                                              el.getIonName(ion), fileTag),
                   figure=fig)
    pyplot.close()
Exemple #16
0
def MakeSolarCompTable(outFilename=k.TempAbOutFilename,
                       headerLeft='',
                       headerRight=''):
    # Function creates a LaTeX table with elemental abundances as calculated from
    # our Solar reference spectrum, based on a "quality" measurement of each line.
    # Each column of the table represents a measurement using lines of a particular
    # quality or better. The final column is represents all of the measured lines.
    corrections, lines, weights = RC.GetSolarCorrections()

    # We're going to create one column for each "quality" setting from the
    # returned weights list. Basically, each weight is a quality level.
    # The columnDict contains:
    # {weight:{ion:[ab,std,#lines],...},...}
    columnDict = {}
    for wt in k.AbWeights:
        columnDict[wt] = {}

    allIonList = sorted(lines.keys())
    for ion in allIonList:
        ionLines = lines[ion]
        # A single line will not show up as a list of one item. Rather, the
        # entire list will be that one line's parameters...grrr.
        if not u.is_list(ionLines[0]):
            ionLines = [ionLines]
        for wt in k.AbWeights:
            wtLines = np.array([line for line in ionLines \
                        if line[0] in weights[ion] and weights[ion][line[0]] >= wt])
            if len(wtLines) > 0:
                asplundCorr = PA.ptoe[int(ion) - 1][PA.abIdx]
                columnDict[wt][ion] = [
                    np.mean(wtLines[:, 5]) + asplundCorr,
                    np.std(wtLines[:, 5]),
                    len(wtLines)
                ]

    # Create a nice column title for each quality type:
    nameList = [
        r'$\Delta\leq{0:1.2f}$'.format(r[1]) for r in k.AbWeightRanges[:-1]
    ]
    nameList.append('All lines')

    outfile = open(outFilename, 'w')

    latexHeader = STP.kLaTexHeader1 + '\\rhead{\\textbf{' + headerRight\
                  + '}}\n\\lhead{\\textbf{' + headerLeft\
                  + '}}\n\\begin{document}\n'
    outfile.write(latexHeader)

    outfile.write('\\begin{landscape}\n'\
                  + '\\hspace*{-5cm}\n'\
                  + '\\begin{tabular}{|l|l|l|l|l|l|l|l|l|l|')
    outfile.write(
        '}\n\\multicolumn{1}{l}{Ion} & \\multicolumn{1}{l}{Asplund (2009)}')

    for name in nameList:
        outfile.write(' & \\multicolumn{{1}}{{l}}{{{0}}}'.format(name))
    outfile.write('\\\\\n\\hline\n')

    for ion in allIonList:
        outfile.write('{0} & {1:1.2f}$\pm${2:1.2f}'.format(el.getIonName(ion),\
                                          PA.ptoe[int(ion)-1][PA.abIdx],\
                                          PA.ptoe[int(ion)-1][PA.solarErrIdx]))

        for wt in k.AbWeights:
            if ion in columnDict[wt].keys() and columnDict[wt][ion][2] > 0:
                outfile.write(' & {0:1.2f}$\pm${1:1.2f} ({2:d})'.\
                  format(columnDict[wt][ion][0]-PA.ptoe[int(ion)-1][PA.abIdx],
                         columnDict[wt][ion][1],
                         columnDict[wt][ion][2]))
            else:
                outfile.write(' & \\multicolumn{1}{c|}{---} ')

        outfile.write('\\\\\n\\hline\n')

    outfile.write('\\label{{tab:SolarAbs}}\n' +
                  '\\end{tabular}\n\\end{landscape}\n' + '\\clearpage\n')

    outfile.write('\\end{document}\n')
    outfile.close()
def COGPlot(clusterName,
            starData,
            ions,
            fileTag='',
            labelPlot=True,
            labelPoints=False,
            modelAtms=None,
            pradks=None,
            makeQualityPlot=False):
    # Make Curve of Growth (COG) plots for the passed star
    # One element per plot.
    # If the makeQualityPlot flag is set, a second plot will be made, with the
    # points shaded relative to how well they correspond to the linear fit of
    # measurements with similar excitation potentials.
    starName = starData[0]
    starParmTuple = tuple(starData[1:])

    isGiant = RC.isGiantStar(starParmTuple)
    if isGiant:
        modelPath = k.GiantModelPath
    else:
        modelPath = k.DwarfModelPath

    if modelAtms == None or pradks == None:
        modelFiles = mk.findDataFiles(modelPath)
        modelAtms, pradks = mk.LoadModels(modelFiles)

    abdict, uncorrLines, unusedMin, unusedMax = \
                AB.CalcAbsAndLines(clusterName+' '+starName,
                                   tuple(starData[1:6]), ionList=ions,
                                   modelAtms=modelAtms, pradks=pradks)

    for ion in ions:
        # One plot per ion.

        if ion not in uncorrLines.keys():
            print('No {0:2.1f} lines for {1}.'.format(ion, starName))
            continue

        if labelPlot:
            plotLabel = 'Curve of Growth for [{2}/H] in {0} {1}.'.\
                        format(clusterName, starName, el.getIonName(ion))
        else:
            plotLabel = ''

        if labelPoints:
            # Label the points with the excitation potential
            pointLabels = ['{0:2.3f}'.format(point[1]) \
                           for point in np.array(uncorrLines[ion])]
        else:
            pointLabels = None

        ps.COGPlot(np.array(uncorrLines[ion]),
                   starName,
                   ion,
                   fileTag=fileTag,
                   plotTitle=plotLabel,
                   pointLabels=pointLabels)

        if makeQualityPlot:
            if labelPlot:
                plotLabel = 'Measurement quality for [{2}/H] in {0} {1}.'.\
                            format(clusterName, starName, el.getIonName(ion))
            else:
                plotLabel = ''
            ps.QualityPlot(np.array(uncorrLines[ion]),
                           starName,
                           ion,
                           fileTag=fileTag + 'QP',
                           plotTitle=plotLabel,
                           pointLabels=pointLabels)