Exemple #1
0
def calibrate_pass0(ds, df, etype="e_ftp", write_db=False, test=False):

    print("Calibration on single peak")

    epeaks = sorted(ds.config["cal_peaks"], reverse=True)
    pu = epeaks[0]
    # get initial parameters for this energy estimator
    calpars = ds.get_p1cal_pars("e_ftp")
    pk_thresh = calpars["peakdet_thresh"]
    match_thresh = calpars["match_thresh"]
    xlo, xhi, xpb = calpars["xlims"]
    ene = df[etype]
    nb = int((xhi - xlo) / xpb)
    h, bins = np.histogram(ene, nb, (xlo, xhi))
    b = (bins[:-1] + bins[1:]) / 2.

    # run peakdet to identify the uncalibrated maxima
    maxes, mins = pgu.peakdet(h, pk_thresh, b)
    calVal = maxes[-1][0]
    fcal = pu / calVal
    firstcal = ene * fcal
    h1, bins1 = np.histogram(firstcal, 1600, (1400, 3000))
    b1 = (bins1[:-1] + bins1[1:]) / 2.
    maxes1, mins1 = pgu.peakdet(h1, pk_thresh, b1)
    print(maxes1)
    #    plt.plot(h1)
    #    plt.show()
    iter = 0
    if len(maxes1) == len(epeaks):
        peaks = sorted(maxes1[:, 0], reverse=True)

    else:
        print(
            "found more or less peaks then expected! Have a look at the raw spectrum again..."
        )
        peaks = maxes1[:, 0]

    peaks = np.array(peaks, dtype=float)
    print("Peaks = ", peaks)

    def pol1(x, a, b):
        return a * x + b

    pars1, cov1 = opt.curve_fit(pol1, peaks, epeaks)
    errs1 = np.sqrt(np.diag(cov1))
    print("Calibration curve: ", pars1)

    ecal = firstcal * pars1[0] + pars1[1]
    hcal, bins2 = np.histogram(ecal, 3000, (0, 3000))
    plt.plot(hcal)
    plt.show()
def spectrum_medfilt_peaks():

    with open("runDB.json") as f:
        runDB = json.load(f)
    tier_dir = os.path.expandvars(runDB["tier_dir"])
    meta_dir = os.path.expandvars(runDB["meta_dir"])

    df = pd.read_hdf('{}/t2_run{}.h5'.format(tier_dir, sys.argv[1]))

    m = np.array(df['e_ftp'])

    xlo, xhi, xpb = 0, 10000, 10
    nbins = int((xhi - xlo) / xpb)

    hist, bins = np.histogram(m, nbins, (xlo, xhi))
    #bins = bins + (bins[1] - bins[0])/2
    #bins = bins[0:(len(bins)-1)]
    hist = np.append(hist, 0)

    hmed = medfilt(hist, 5)
    hpks = hist - hmed

    plt.plot(bins,
             hist,
             '-k',
             ls="steps",
             label='uncalibrated energy spectrum, run ' + str(sys.argv[1]))
    plt.plot(bins, hmed, '-r', ls='steps', label="peakless spectrum (medfilt)")
    plt.plot(bins,
             hpks,
             '-b',
             ls='steps',
             label='peaks only (spectrum - medfilt)')

    thresholds = np.arange(5, 10000, 5, dtype=int)

    for i in range(len(thresholds)):
        maxes, mins = pgu.peakdet(hpks, thresholds[i], bins)
        if len(maxes) == 4:
            break

    for pk in maxes:
        plt.plot(pk[0], pk[1], '.m', ms=10)

    plt.xlim(0, 9000)
    plt.ylim(0, plt.ylim()[1])
    #plt.semilogy()
    colors = ['black', 'red', 'blue']
    lines = [Line2D([0], [0], color=c) for c in colors]
    labels = [
        'uncalibrated energy spectrum, run ' + str(sys.argv[1]),
        'peakless spectrum (medfilt)', 'peaks only (spectrum - medfilt)'
    ]
    plt.legend(lines,
               labels,
               frameon=True,
               loc='upper right',
               fontsize='x-small')
    plt.show()
Exemple #3
0
def find_peaks(hE, xE, var):
    """
    run peakdet routine (use a JSON config file to set thresholds)
    """

    maxes, mins = pu.peakdet(hE, 100, xE[1:])
    umaxes = np.array(sorted([x[0] for x in maxes]))
    print(f"{umaxes}")

    for peak in umaxes:
        plt.axvline(peak, linestyle="--", lw=1)

    plt.semilogy(xE[1:], hE, ls='steps', lw=1, c='r')

    plt.xlabel("Energy (uncal.)", ha='right', x=1)
    plt.ylabel("Counts", ha='right', y=1)
    plt.show()
Exemple #4
0
def calibrate_pass1(ds, df, etype="e_ftp", write_db=False, test=False):
    """
    Run a "first guess" calibration of an arbitrary energy estimator.

    Uses a peak matching algorithm based on finding ratios of uncalibrated
    and "true" (keV) energies.  We run peakdet to find the maxima
    in the spectrum, then compute all ratios e1/e2, u1/u2, ..., u29/u30 etc.
    We find the subset of uncalibrated ratios (u7/u8, ... etc) that
    match the "true" ratios, and compute a calibration constant for each.
    Then for each uncalibrated ratio, we assume it to be true, then loop
    over the expected peak positions.
    We shift the uncalibrated peaks so that the true peak would be very close
    to 0, and calculate its distance from 0.  The "true" calibration constant
    will minimize this value for all ratios, and this is the one we select.

    Writes first-pass calibration results to a database, for access
    by the second pass, and other codes.
    """

    print("Start first Calibration!")
    # get a list of peaks we assume are always present
    epeaks = sorted(ds.config["cal_peaks"], reverse=True)

    # get initial parameters for this energy estimator
    calpars = ds.get_p1cal_pars(etype)
    pk_thresh = calpars["peakdet_thresh"]
    match_thresh = calpars["match_thresh"]
    xlo, xhi, xpb = calpars["xlims"]

    # make energy histogram
    ene = df[etype]
    nb = int((xhi - xlo) / xpb)
    h, bins = np.histogram(ene, nb, (xlo, xhi))
    b = (bins[:-1] + bins[1:]) / 2.
    print(pk_thresh, " / ", b)
    print("")
    print(bins)
    plt.plot(h)
    plt.show()
    # run peakdet to identify the uncalibrated maxima
    maxes, mins = pgu.peakdet(h, pk_thresh, b)
    print(maxes)

    umaxes = np.array(sorted([x[0] for x in maxes], reverse=True))

    # compute all ratios
    ecom = [c for c in it.combinations(epeaks, 2)]
    ucom = [c for c in it.combinations(umaxes, 2)]
    eratios = np.array([x[0] / x[1] for x in ecom])  # assumes x[0] > x[1]
    uratios = np.array([x[0] / x[1] for x in ucom])
    # match peaks to true energies
    cals = {}
    for i, er in enumerate(eratios):

        umatch = np.where(np.isclose(uratios, er, rtol=match_thresh))
        e1, e2 = ecom[i][0], ecom[i][1]
        if test:
            print(f"\nratio {i} -- e1 {e1:.0f}  e2 {e2:.0f} -- {er:.3f}")

        if len(umatch[0]) == 0:
            continue

        caldists = []
        for ij, j in enumerate(umatch[0]):
            u1, u2 = ucom[j][0], ucom[j][1]
            cal = (e2 - e1) / (u2 - u1)
            cal_maxes = cal * umaxes

            # shift peaks by the amount we would expect if this const were true.
            # compute the distance (in "keV") of the peak that minimizes this.
            dist = 0
            for e_true in epeaks:
                idx = np.abs(cal_maxes - e_true).argmin()
                dist += np.abs(cal_maxes[idx] - e_true)
            caldists.append([cal, dist])

            if test:
                dev = er - uratios[j]  # set by match_thresh parameter
                print(
                    f"{ij}  {u1:-5.0f}  {u2:-5.0f}  {dev:-7.3f}  {cal:-5.2f}")

        # get the cal ratio with the smallest total dist
        caldists = np.array(caldists)
        imin = caldists[:, 1].argmin()
        cals[i] = caldists[imin, :]

        if test:
            print(
                f"best: {imin}  {caldists[imin, 0]:.4f}  {caldists[imin, 1]:.4f}"
            )

    if test:
        print("\nSummary:")
        for ipk in cals:
            e1, e2 = ecom[ipk][0], ecom[ipk][1]
            print(f"{ipk}  {e1:-6.1f}  {e2:-6.1f}  cal {cals[ipk][0]:.5f}")

    # get first-pass const for this DataSet
    cal_vals = np.array([c[1][0] for c in cals.items()])
    ds_cal = np.median(cal_vals)
    ds_std = np.std(cal_vals)
    print(f"Pass-1 cal for {etype}: {ds_cal:.5e} pm {ds_std:.5e}")

    if test:
        plt.semilogy(b * ds_cal,
                     h,
                     ls='steps',
                     lw=1.5,
                     c='b',
                     label=f"{etype}, {sum(h)} cts")
        for x, y in maxes:
            plt.plot(x * ds_cal, y, "m.", ms=10)

        pks = ds.config["pks"]
        cmap = plt.cm.get_cmap('jet', len(pks) + 1)
        for i, pk in enumerate(pks):
            plt.axvline(float(pk),
                        c=cmap(i),
                        linestyle="--",
                        lw=1,
                        label=f"{pks[pk]}: {pk} keV")

        plt.xlabel("Energy (keV)", ha='right', x=1)
        plt.ylabel("Counts", ha='right', y=1)
        plt.legend(fontsize=9)

#       plt.show()

    if write_db:
        calDB = ds.calDB
        query = db.Query()
        table = calDB.table("cal_pass1")

        # write an entry for every dataset.  if we've chained together
        # multiple datasets, the values will be the same.
        # use "upsert" to avoid writing duplicate entries.
        for dset in ds.ds_list:
            row = {"ds": dset, "p1cal": ds_cal, "p1std": ds_std}
            table.upsert(row, query.ds == dset)
def linear_calibration():

    with open("runDB.json") as f:
        runDB = json.load(f)
    tier_dir = os.path.expandvars(runDB["tier_dir"])
    meta_dir = os.path.expandvars(runDB["meta_dir"])

    pks_lit = [238.6, 583.2]

    pks_lit = [238.6, 583.2]

    df = pd.read_hdf('{}/t2_run{}.h5'.format(tier_dir, sys.argv[1]))
    # ds = DataSet(runlist=[278, 279], md='./runDB.json', tier_dir=tier_dir)
    # df = ds.get_t2df()
    m = np.array(df['e_ftp'])

    xlo, xhi, xpb = 0, 10000, 1
    nbins = int((xhi - xlo) / xpb)

    hist, bins = np.histogram(m, nbins, (xlo, xhi))
    hist = np.pad(hist, (1, 0), 'constant')
    bins = bins + (bins[1] - bins[0]) / 2

    hmed = medfilt(hist, 51)
    hpks = hist - hmed

    thresholds = np.arange(5, 10000, 5, dtype=int)

    for i in range(len(thresholds)):
        maxes, mins = pgu.peakdet(hpks, thresholds[i], bins)
        if len(maxes) == 5:
            break

    x_maxes = []
    for i in range(len(maxes)):
        x_value = maxes[i][0]
        x_maxes.append(x_value)

    ratios = []
    for i in range(len(maxes)):
        for j in range(len(maxes)):
            ratios.append(x_maxes[i] / x_maxes[j])

    #another way to do the block above
    #import itertools
    #ratios = []
    #for x_i, x_j in itertools.product(x_maxes, x_maxes):
    #ratios.append(x_i/x_j)

    real_ratio = []
    for i in range(len(ratios)):
        real_ratio.append(pks_lit[1] / pks_lit[0])

    ratios_array = np.array(ratios)
    real_ratio_array = np.array(real_ratio)

    closeness = np.absolute(ratios_array - real_ratio_array)

    relevant_entry = int(np.where(closeness == np.amin(closeness))[0])

    adc_2_peak_combinations = []
    for i in range(len(x_maxes)):
        for j in range(len(x_maxes)):
            adc_2_peak_combinations.append([x_maxes[j], x_maxes[i]])

    #ADC Values Corresponding to Energy Peaks 1460.820 keV and 2614.511 keV
    adc_values = adc_2_peak_combinations[relevant_entry]

    #Now we model a linear equation to go from ADC value (e_ftp) to real energy using the points (adc_values[0], 1460.820) and (adc_values[1], 2614.511 keV)
    # E = A(e_ftp) + B
    A = float((pks_lit[1] - pks_lit[0]) / (adc_values[1] - adc_values[0]))
    B = float((pks_lit[1] - adc_values[1] * A))
    #Now we will add a column to df that represents the energy measured (rather than only having the adc (e_ftp) value measured as the df currently does)
    df['e_cal'] = df['e_ftp'] * A + B

    pks_lit_all = [
        238.6, 338.3, 463.0, 511, 0, 583.2, 727.3, 794.9, 860.6, 911.2, 969,
        1460.8, 1592.5, 2103.5, 2614.5
    ]
    plt.axvline(x=238.6,
                ymin=0,
                ymax=30,
                color='red',
                linestyle='--',
                lw=1,
                zorder=1)
    plt.axvline(x=338.3,
                ymin=0,
                ymax=30,
                color='aqua',
                linestyle='--',
                lw=1,
                zorder=1)
    plt.axvline(x=463.0,
                ymin=0,
                ymax=30,
                color='teal',
                linestyle='--',
                lw=1,
                zorder=1)
    plt.axvline(x=511.0,
                ymin=0,
                ymax=30,
                color='darkgreen',
                linestyle='--',
                lw=1,
                zorder=1)
    plt.axvline(x=583.2,
                ymin=0,
                ymax=30,
                color='darkorange',
                linestyle='--',
                lw=1,
                zorder=1)
    plt.axvline(x=727.3,
                ymin=0,
                ymax=30,
                color='gray',
                linestyle='--',
                lw=1,
                zorder=1)
    plt.axvline(x=794.9,
                ymin=0,
                ymax=30,
                color='brown',
                linestyle='--',
                lw=1,
                zorder=1)
    plt.axvline(x=860.6,
                ymin=0,
                ymax=30,
                color='purple',
                linestyle='--',
                lw=1,
                zorder=1)
    plt.axvline(x=911.2,
                ymin=0,
                ymax=30,
                color='fuchsia',
                linestyle='--',
                lw=1,
                zorder=1)
    plt.axvline(x=969.0,
                ymin=0,
                ymax=30,
                color='saddlebrown',
                linestyle='--',
                lw=1,
                zorder=1)
    plt.axvline(x=1460.8,
                ymin=0,
                ymax=30,
                color='navy',
                linestyle='--',
                lw=1,
                zorder=1)
    plt.axvline(x=1592.5,
                ymin=0,
                ymax=30,
                color='limegreen',
                linestyle='--',
                lw=1,
                zorder=1)
    plt.axvline(x=2103.5,
                ymin=0,
                ymax=30,
                color='olive',
                linestyle='--',
                lw=1,
                zorder=1)
    plt.axvline(x=2614.5,
                ymin=0,
                ymax=30,
                color='indigo',
                linestyle='--',
                lw=1,
                zorder=1)
    n = np.array(df['e_cal'])
    plt.hist(n,
             np.arange(0, 9500, 1.5),
             histtype='step',
             color='black',
             zorder=2,
             label='{} entries'.format(len(n)))
    plt.xlim(0, 4000)
    plt.ylim(0, plt.ylim()[1])
    plt.xlabel('Energy (keV)', ha='right', x=1.0)
    plt.ylabel('Counts', ha='right', y=1.0)
    E_cal = 'calibrated energy spectrum, run ' + str(sys.argv[1])
    E_1 = 'E=238.6 keV (212Pb peak)*'
    E_2 = 'E=338.3 keV (228Ac peak)'
    E_3 = 'E=463.0 keV (228Ac peak)'
    E_4 = 'E=511.0 keV (beta+ peak)'
    E_5 = 'E=583.2 keV (208Tl peak)*'
    E_6 = 'E=727.3 keV (212Bi peak)'
    E_7 = 'E=794.9 keV (228Ac peak)'
    E_8 = 'E=860.6 keV (208Tl peak)'
    E_9 = 'E=911.2 keV (228Ac peak)'
    E_10 = 'E=969 keV (228Ac peak)'
    E_11 = 'E=1460.8 keV (40K peak)'
    E_12 = 'E=1592.5 keV (208Tl DE)'
    E_13 = 'E=2103.5 keV (208Tl SE)'
    E_14 = 'E=2614.5 keV (208Tl peak)'
    colors = [
        'black', 'red', 'aqua', 'teal', 'darkgreen', 'darkorange', 'gray',
        'brown', 'purple', 'fuchsia', 'saddlebrown', 'navy', 'limegreen',
        'olive', 'indigo'
    ]
    lines = [Line2D([0], [0], color=c) for c in colors]
    labels = [
        E_cal, E_1, E_2, E_3, E_4, E_5, E_6, E_7, E_8, E_9, E_10, E_11, E_12,
        E_13, E_14
    ]
    plt.legend(lines,
               labels,
               frameon=True,
               loc='upper right',
               fontsize='x-small')
    plt.tight_layout()
    #plt.semilogy()
    plt.show()
Exemple #6
0
def calibrate_pass2(ds, test=False):
    """
    load first-pass constants from the calDB for this DataSet,
    and the list of peaks we want to fit from the runDB, and
    fit the radford peak to each one.
    make a new table in the calDB, "cal_pass2" that holds all
    the important results, like mu, sigma, errors, etc.
    """
    """
    This function is mainly being used to estimate the FWHM of the calibration
    peaks
    """
    epeaks = sorted(ds.config["expected_peaks"])
    calpars = ds.get_p1cal_pars("e_ftp")
    xlo, xhi, xpb = calpars["xlims"]
    pk_thresh = calpars["width_thresh"]
    width_lo, width_hi, wlo1, whi1, wlo2, whi2 = calpars["width_lims"]

    calDB = ds.calDB
    query = db.Query()
    table = calDB.table("cal_pass1")
    vals = table.all()
    df_cal = pd.DataFrame(vals)  # <<---- omg awesome
    df_cal = df_cal.loc[df_cal.ds.isin(ds.ds_list)]
    p1cal = df_cal.iloc[0]["p1cal"]

    t2 = ds.get_t2df()
    ene = t2["e_ftp"] * p1cal

    for i in range(len(epeaks)):
        ehi = epeaks[i] + width_hi
        elo = epeaks[i] + width_lo
        xpb = 1
        nb = int((ehi - elo) / xpb)
        h, bins = np.histogram(ene, nb, (elo, ehi))
        b = (bins[:-1] + bins[1:]) / 2

        # subract background
        mean_upper = np.mean(np.array(h[wlo1:whi1]))
        mean_lower = np.mean(np.array(h[wlo2:whi2]))
        h = h - (mean_upper + mean_lower) / 2

        max, min = peakdet(h, pk_thresh, b)
        print(max)

        binr = np.where(b == max[0][0])
        binl = np.where(b == max[0][0])
        binr, binl = binr[0], binl[0]
        peakh = max[0][1]
        fwhmr = h[binr]
        fwhml = h[binl]

        while fwhmr > 0.5 * peakh or fwhml > 0.5 * peakh:
            binr += 1
            binl += -1
            fwhmr = h[binr]
            fwhml = h[binl]

        print("FWHM is kind of in the ball park of: ", (b[binr] - b[binl]))

        if test:
            plt.plot(b, h, ls="steps", linewidth=1.5)
            plt.axvline(float(max[0][0]), c='red', linestyle="--", lw=1)
            plt.axvline(float(b[binr]), c='black', linestyle="--", lw=1)
            plt.axvline(float(b[binl]), c='green', linestyle="--", lw=1)
            plt.title("Peak: {}".format(epeaks[i]))
            plt.xlabel("keV")
            plt.ylabel("Counts/keV")
            plt.show()
    exit()
Exemple #7
0
def linear_calibration():

    if (len(sys.argv) != 2):
        print('Usage: campaign.py [run number]')
        sys.exit()

    pks_lit = [609.3, 1460.8]

    with open("runDB.json") as f:
        runDB = json.load(f)
    tier_dir = os.path.expandvars(runDB["tier_dir"])
    meta_dir = os.path.expandvars(runDB["meta_dir"])

    df = pd.read_hdf('{}/t2_run{}.h5'.format(tier_dir, sys.argv[1]))
    print(df.keys())
    exit()
    m = np.array(df['e_ftp'])

    xlo, xhi, xpb = 0, 10000, 10
    nbins = int((xhi - xlo) / xpb)

    hist, bins = np.histogram(m, nbins, (xlo, xhi))
    bins = bins + (bins[1] - bins[0]) / 2
    bins = bins[0:(len(bins) - 1)]

    hmed = medfilt(hist, 5)
    hpks = hist - hmed

    thresholds = np.arange(50, 1000000, 10, dtype=int)

    for i in range(len(thresholds)):
        maxes, mins = pgu.peakdet(hpks, thresholds[i], bins)
        if len(maxes) == 4:
            break

    x_maxes = []
    for i in range(len(maxes)):
        x_value = maxes[i][0]
        x_maxes.append(x_value)

    y_maxes = []
    for i in range(len(maxes)):
        y_value = maxes[i][1]
        y_maxes.append(y_value)

    ## if for whatever reason the background calibration does not seem to work, these values seem to work more often than not.
    #x_maxes = [15.0, 345.0, 585.0, 725.0, 835.0, 865.0, 1255.0, 1435.0, 1495.0, 1785.0, 2235.0, 2375.0, 2755.0, 3595.0, 4335.0, 6425.0]

    ratios = []
    for i in range(len(x_maxes)):
        for j in range(len(x_maxes)):
            ratios.append(x_maxes[i] / x_maxes[j])

    #another way to do the block above
    #import itertools
    #ratios = []
    #for x_i, x_j in itertools.product(x_maxes, x_maxes):
    #ratios.append(x_i/x_j)

    real_ratio = []
    for i in range(len(ratios)):
        real_ratio.append(pks_lit[1] / pks_lit[0])

    ratios_array = np.array(ratios)
    real_ratio_array = np.array(real_ratio)

    closeness = np.absolute(ratios_array - real_ratio_array)

    relevant_entry = np.where(closeness == np.amin(closeness))[0]
    relevant_entry = int(relevant_entry[len(relevant_entry) - 1])

    adc_2_peak_combinations = []
    for i in range(len(x_maxes)):
        for j in range(len(x_maxes)):
            adc_2_peak_combinations.append([x_maxes[j], x_maxes[i]])

    #ADC Values Corresponding to Energy Peaks 1460.820 keV and 2614.511 keV
    adc_values = adc_2_peak_combinations[relevant_entry]

    #Now we model a linear equation to go from ADC value (e_ftp) to real energy using the points (adc_values[0], 1460.820) and (adc_values[1], 2614.511 keV)
    # E = A(e_ftp) + B
    A = float((pks_lit[1] - pks_lit[0]) / (adc_values[1] - adc_values[0]))
    B = float((pks_lit[1] - adc_values[1] * A))
    #Now we will add a column to df that represents the energy measured (rather than only having the adc (e_ftp) value measured as the df currently does)

    df["e_cal"] = A * df['e_ftp'] + B

    df.to_hdf('{}/Spectrum_{}.hdf5'.format(meta_dir, sys.argv[1]),
              key='df',
              mode='w')

    pks_lit_all = [
        238.6, 351.9, 511.0, 583.2, 609.3, 911.2, 969, 1120.3, 1460.8, 1764.5,
        2614.5
    ]
    plt.axvline(x=238.6,
                ymin=0,
                ymax=30,
                color='red',
                linestyle='--',
                lw=1,
                zorder=1)
    plt.axvline(x=351.9,
                ymin=0,
                ymax=30,
                color='aqua',
                linestyle='--',
                lw=1,
                zorder=1)
    plt.axvline(x=511.0,
                ymin=0,
                ymax=30,
                color='darkgreen',
                linestyle='--',
                lw=1,
                zorder=1)
    plt.axvline(x=583.2,
                ymin=0,
                ymax=30,
                color='darkorange',
                linestyle='--',
                lw=1,
                zorder=1)
    plt.axvline(x=609.3,
                ymin=0,
                ymax=30,
                color='gray',
                linestyle='--',
                lw=1,
                zorder=1)
    plt.axvline(x=911.2,
                ymin=0,
                ymax=30,
                color='brown',
                linestyle='--',
                lw=1,
                zorder=1)
    plt.axvline(x=969.0,
                ymin=0,
                ymax=30,
                color='saddlebrown',
                linestyle='--',
                lw=1,
                zorder=1)
    plt.axvline(x=1120.3,
                ymin=0,
                ymax=30,
                color='navy',
                linestyle='--',
                lw=1,
                zorder=1)
    plt.axvline(x=1460.8,
                ymin=0,
                ymax=30,
                color='olive',
                linestyle='--',
                lw=1,
                zorder=1)
    plt.axvline(x=1764.5,
                ymin=0,
                ymax=30,
                color='indigo',
                linestyle='--',
                lw=1,
                zorder=1)
    plt.axvline(x=2614.5,
                ymin=0,
                ymax=30,
                color='limegreen',
                linestyle='--',
                lw=1,
                zorder=1)
    n = np.array(df['e_cal'])
    plt.hist(n,
             np.arange(0, 9500, 0.75),
             histtype='step',
             color='black',
             zorder=2,
             label='{} entries'.format(len(n)))
    plt.xlim(0, 4000)
    plt.ylim(0, plt.ylim()[1])
    plt.xlabel('Energy (keV)', ha='right', x=1.0)
    plt.ylabel('Counts', ha='right', y=1.0)
    E_cal = 'calibrated energy spectrum, run ' + str(sys.argv[1])
    E_1 = 'E=238.6 keV (212Pb peak)'
    E_2 = 'E=351.93 keV (214Pb peak)'
    E_3 = 'E=511.0 keV (beta+ peak)'
    E_4 = 'E=583.19 keV (208Tl peak)'
    E_5 = 'E=609.32 keV (214Bi peak)*'
    E_6 = 'E=911.2 keV (228Ac peak)'
    E_7 = 'E=969 keV (228Ac peak)'
    E_8 = 'E=1120.3 keV (214Bi peak)'
    E_9 = 'E=1460.82 keV (40K peak)*'
    E_10 = 'E=1764.49 keV (214Bi peak)'
    E_11 = 'E=2614.51 keV (208Tl peak)'
    colors = [
        'black', 'red', 'aqua', 'darkgreen', 'darkorange', 'gray', 'brown',
        'saddlebrown', 'navy', 'olive', 'indigo', 'limegreen'
    ]
    lines = [Line2D([0], [0], color=c) for c in colors]
    labels = [E_cal, E_1, E_2, E_3, E_4, E_5, E_6, E_7, E_8, E_9, E_10, E_11]
    #plt.title('Energy Spectrum')
    plt.legend(lines,
               labels,
               frameon=True,
               loc='upper right',
               fontsize='x-small')
    plt.tight_layout()
    #plt.semilogy()
    plt.show()