示例#1
0
def main(args):
    data = np.genfromtxt(args.data, delimiter=',', names=True)

    mjd = data['mjd']
    mjd0 = int(mjd.min())
    mjd -= mjd0

    fig, axes = plt.subplots(3, 1, sharex=True)

    centre_a = data['psf_A_5']
    centre_b = data['psf_B_5']
    centre_e = eccentricity(centre_a, centre_b)

    for corner_index in [1, 3, 7, 9]:
        a = data['psf_A_{}'.format(corner_index)]
        b = data['psf_B_{}'.format(corner_index)]
        ratio_a = a / centre_a
        ratio_b = b / centre_a

        e = eccentricity(a, b)
        ratio_e = e - centre_e

        axes[0].plot(mjd, ratio_a, '.')
        axes[1].plot(mjd, ratio_b, '.')
        axes[2].plot(mjd, ratio_e, '.')

    labels = [r'$a_{\mathrm{edge}} / a_{\mathrm{centre}}$',
            r'$b_{\mathrm{edge}} / b_{\mathrm{centre}}$',
            r'$e_{\mathrm{edge}} - e_{\mathrm{centre}}$']
    for ax, label in zip(axes, labels):
        ax.grid(True)
        ax.set_ylabel(label)

    fig.tight_layout()
    fig.savefig(args.output)
def main(args):
    logger.info('Reading data')
    with fitsio.FITS(args.filename) as infile:
        imagelist_hdu = infile['imagelist']
        mjd = imagelist_hdu['tmid'].read()
        seeing = imagelist_hdu['seeing'].read()
        frame_sn = imagelist_hdu['frame_sn'].read()

    mjd0 = int(mjd.min())
    mjd -= mjd0


    logger.info('Plotting')
    fig, axes = plt.subplots(2, 1, sharex=True)
    labels = ['"Seeing"', 'Frame S/N']
    for ax, data, label in zip(axes, [seeing, frame_sn], labels):
        ax.plot(mjd, data, marker='.', ls='None')
        ax.set_ylabel(label)
        ax.grid(True, axis='y')
        plot_night_breaks(ax, mjd)

    axes[-1].set_xlabel('MJD - {}'.format(mjd0))

    fig.tight_layout()
    if args.output is not None:
        logger.info('Rendering to %s', args.output)
        fig.savefig(args.output, bbox_inches='tight')
    else:
        plt.show()
def main(args):
    with fitsio.FITS(args.filename) as infile:
        imagelist = infile['imagelist']
        coeffs = imagelist['aj'].read()
        mjd = imagelist['tmid'].read()

    n_coeffs = coeffs.shape[1]

    fig, axes = plt.subplots(n_coeffs, 1, sharex=True, figsize=(11, 8))

    frames = np.arange(mjd.size)

    for i, axis in enumerate(axes):
        data = coeffs[:, i]

        axis.plot(frames, data, 'k.', label="{}".format(i + 1))

        # Detect night boundaries
        d_mjd = np.diff(mjd)
        breaks = np.where(np.diff(mjd) > 0.3)[0]
        for b in breaks:
            axis.axvline(b, ls=':', color='k')

        axis.grid(True, axis='y')

        axis.set_ylabel(r'$a_{}$'.format(i))

    axes[-1].set_xlabel(r'Frame')

    fig.tight_layout()

    if args.output is not None:
        fig.savefig(args.output, bbox_inches='tight')
    else:
        plt.show()
示例#4
0
文件: pixel-com.py 项目: NGTS/zlp-qa
def main(args):
    logger.info('Reading data from %s', args.fname)
    with fitsio.FITS(args.fname) as infile:
        ccdx = infile['ccdx'].read()
        ccdy = infile['ccdy'].read()
        mjd = infile['imagelist']['tmid'].read()

    mjd0 = int(mjd.min())
    mjd -= mjd0
    fn = np.median

    logger.info('Plotting')
    fig, axis = plt.subplots()
    mappable_x = axis.plot(mjd, fn(ccdx, axis=0), 'b.')[0]
    axis2 = axis.twinx()
    mappable_y = axis2.plot(mjd, fn(ccdy, axis=0), 'g.')[0]

    axis2.legend([mappable_x, mappable_y], ['X', 'Y'], loc='best')
    axis.set_ylabel(r'X')
    axis2.set_ylabel(r'Y')
    axis.set_xlabel('MJD - {}'.format(mjd0))

    plot_night_breaks(axis, mjd)

    fig.tight_layout()
    if args.output is not None:
        logger.info('Rendering to %s', args.output)
        fig.savefig(args.output, bbox_inches='tight')
    else:
        plt.show()
示例#5
0
def main(args):
    with fitsio.FITS(args.catalogue) as infile:
        hdu = infile[1]
        ra1 = hdu['RA_1'][:]
        dec1 = hdu['DEC_1'][:]

        ra2 = hdu['ra_2'][:]
        dec2 = hdu['dec_2'][:]


    coords1 = ICRS(ra=ra1, dec=dec1, unit=(u.radian, u.radian))
    coords2 = ICRS(ra=ra2, dec=dec2, unit=(u.degree, u.degree))

    separations = coords1.separation(coords2).degree * 3600.

    fig, axes = plt.subplots(figsize=(11, 8))

    axes.hist(separations, 30, histtype='step')
    axes.set_xlabel(r'Separation / arcseconds')
    axes.grid(True)

    fig.tight_layout()

    if args.output is not None:
        fig.savefig(args.output, bbox_inches='tight')
    else:
        plt.show()
def main(args):
    with fitsio.FITS(args.catalogue) as infile:
        hdu = infile[1]
        ra1 = hdu['RA_1'][:]
        dec1 = hdu['DEC_1'][:]

        ra2 = hdu['ra_2'][:]
        dec2 = hdu['dec_2'][:]

        x = hdu['X_coordinate'][:]
        y = hdu['Y_coordinate'][:]


    coords1 = ICRS(ra=ra1, dec=dec1, unit=(u.radian, u.radian))
    coords2 = ICRS(ra=ra2, dec=dec2, unit=(u.degree, u.degree))

    separations = coords1.separation(coords2).degree * 3600.

    fig, axes = plt.subplots(2, 2, sharex=True, figsize=(11, 8))
    [(x_axis, y_axis), (x_zoomed, y_zoomed)] = axes

    nsigma = 5
    nbins = 2048 / 128
    print('Using {} bins'.format(nbins))
    x_axis.plot(x, separations, 'k.', color='0.4')
    x_axis.set_ylabel(r'X')

    ledges, x_binned = compute_binned(x, separations, nbins)
    _, x_binned_error = compute_binned_errors(x, separations, ledges)
    bin_centres = compute_bin_centres(ledges)

    for ax in [x_axis, x_zoomed]:
        ax.errorbar(bin_centres[:-1], x_binned[:-1], x_binned_error[:-1],
                color='r', ls='None')
        ax.plot(ledges, x_binned, color='r', drawstyle='steps-post')

    y_axis.plot(y, separations, 'k.', color='0.4')
    y_axis.set_ylabel(r'y')

    ledges, y_binned = compute_binned(y, separations, nbins)
    _, y_binned_error = compute_binned_errors(y, separations, ledges)

    for ax in [y_axis, y_zoomed]:
        ax.errorbar(bin_centres[:-1], y_binned[:-1], x_binned_error[:-1],
                color='r', ls='None')
        ax.plot(ledges, y_binned, color='r', drawstyle='steps-post')

    link_y_limits(x_zoomed, y_zoomed)

    for ax in axes.flatten():
        ax.grid(True)

    fig.tight_layout()

    if args.output is not None:
        fig.savefig(args.output, bbox_inches='tight')
    else:
        plt.show()
示例#7
0
def main(args):
    filename = args.filename
    data_dict = load_data(filename, hdu=args.hdu)

    left_edges = 10 ** np.linspace(2, 5, 10)[:-1]
    right_edges = 10 ** (np.log10(left_edges) + 3. / 9.)

    values = range(0, len(left_edges) + 1)

    mymap = cm = plt.get_cmap('autumn')
    cNorm = colors.Normalize(vmin=0, vmax=values[-1])
    scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=mymap)

    levels = np.array([left_edges[0]] + list(right_edges))

    if args.serial:
        pool_class = NullPool
    else:
        pool_class = mp.Pool

    fig, axis = plt.subplots()

    flux_limits = [(left_edges[i], right_edges[i]) for i in
                   xrange(len(left_edges))]
    fn = partial(noisecharacterise, datadict=data_dict,
                 flux_limits=flux_limits,
                 ax=axis)

    pool = pool_class()
    plot_data = pool.map(fn, range(0, len(left_edges)))

    for i, r in enumerate(plot_data):
        colorVal = scalarMap.to_rgba(values[i])
        axis.plot(r.x, r.y, color=colorVal, linewidth=2.0)
        # axis.errorbar(r.x, r.y, r.yerr, color=colorVal, linewidth=2.0)
        axis.plot(r.x, r.white, '--', color='grey', alpha=0.8)

    cbar = create_colourbar(fig, values, mymap, cNorm)
    nicelist = [int(left_edges[0])] + [int(x) for x in right_edges]
    cbar.ax.set_yticklabels(nicelist[::-1])  # vertically oriented colorbar

    axis.set(yscale='log',
            xscale='log',
            xlabel="Bin size (Minutes)",
            ylabel="Fractional RMS (millimags)",
            title=':'.join([os.path.basename(args.filename), args.hdu]),
            yticks=(0.5, 1, 2, 5, 10, 20, 50, 100),
            yticklabels=('0.5', '1', '2', '5', '10', '20', '50', '100'),
            xticks=(1, 5, 10, 60),
            xticklabels=('1', '5', '10', '60'))
    axis.set(xlim=(0.1, 150), ylim=(0.1, 100))

    fig.tight_layout()
    if args.output is not None:
        plt.savefig(args.output, bbox_inches='tight')
    else:
        plt.show()
示例#8
0
def main(args):
    logger.info('Reading data from %s', args.extracted)
    data = qa_common.CSVContainer(args.extracted,
            key_type_map={'roof_open': qa_common.CSVContainer.bool_converter})

    mjd0 = int(data.mjd.min())
    data['mjd'] = data['mjd'] - mjd0
    roof_closed = ~data['roof_open']

    logger.info('Plotting')
    fig, axes = plt.subplots(6, 1, figsize=(11, 16), sharex=True)
    ind = data['exposure'] > 0.
    axes[0].semilogy(data['mjd'][ind], data['exposure'][ind], 'k.')
    axes[0].set_ylabel(r'Exposure time / s')
    axes[0].yaxis.set_major_formatter(plt.LogFormatter())

    axes[1].plot(data['mjd'], data.right - data.left, 'k.')
    axes[1].set_ylabel(r'Left - Right')

    axes[2].plot(data['mjd'], data.left, 'r.', label='left')
    axes[2].plot(data['mjd'], data.right, 'g.', label='right')
    axes[2].set_ylabel(r'Overscan level / counts')

    axes[3].plot(data['mjd'], data.chstemp, 'r.')
    axes[3].set_ylabel(r'Chassis temp')

    axes[4].plot(data['mjd'], data.ccdtemp, 'r.')
    axes[4].set_ylabel(r'CCD temp')

    axes[5].plot(data['mjd'], data.airmass, 'r.')
    axes[5].set_ylabel(r'Airmass')

    axes[-1].set_xlabel('MJD - {}'.format(mjd0))

    for ax in axes:
        highlight_roof_closed_sections(ax, data['mjd'], roof_closed)
        ax.grid(True, axis='y')

    fig.tight_layout()

    if args.output is not None:
        logger.info('Rendering to %s', args.output)
        fig.savefig(args.output, bbox_inches='tight')
    else:
        plt.show()
示例#9
0
def main(args):
    logger.info('Loading flux data from %s', args.filename)
    extracted = extract_flux_data(args.filename, hdu=args.hdu)

    fig, ax = plt.subplots(figsize=(11, 8))
    plot_summary(extracted, 'r', ax=ax)
    ax.set(xlabel='Kepler magnitude', ylabel='FRMS', yscale='log',
            title='{}:{}'.format(os.path.basename(args.filename), args.hdu),
            xlim=(5, 20), ylim=(1E-3, 10))
    ax.yaxis.set_major_formatter(plt.ScalarFormatter())
    ax.grid(True)
    fig.tight_layout()

    logger.info('Saving to %s', args.output)
    if args.output is not None:
        fig.savefig(args.output, bbox_inches='tight')
    else:
        plt.show()
示例#10
0
def main(args):
    fig, axes = plt.subplots(2, 1, figsize=(11, 11))
    m_casu = list(missing_from_casu(args))
    _, ra, dec, _, ngts_mag = zip(*m_casu)

    axes[1].plot(ra, dec, 'r.', zorder=10)

    m_2mass = missing_from_2mass(args)
    ra, dec, mag_2mass = [], [], []
    for row in m_2mass:
        ra.append(float(row['ra']))
        dec.append(float(row['dec']))
        mag_2mass.append(float(row['jmag']))

    height, xedges, yedges = np.histogram2d(ra, dec, bins=30)

    mappable = axes[1].pcolormesh(xedges[:-1], yedges[:-1], height.T,
                       cmap=plt.cm.binary, zorder=-10)
    fig.colorbar(mappable, ax=axes[1])

    axes[0].hist([ngts_mag, mag_2mass], bins=15, normed=True, histtype='step',
                 label=['ngts', '2mass'])
    axes[0].legend(loc='best')
    axes[1].set_aspect('equal')

    for ax in axes:
        ax.grid(True)

    axes[0].set_xlabel(r'Magnitude')
    axes[0].set_ylabel(r'Normalised density')
    axes[1].set_xlabel(r'$\alpha$')
    axes[1].set_ylabel(r'$\delta$')


    axes[0].set_title(r'CASU misses: {}, 2MASS misses: {}'.format(
        len(ngts_mag), len(mag_2mass)))

    fig.tight_layout()
    
    if args.output is not None:
        fig.savefig(args.output, bbox_inches='tight')
    else:
        plt.show()
示例#11
0
def main(args):
    with fitsio.FITS(args.catalogue) as infile:
        hdu = infile[1]

        ra1 = np.degrees(hdu['RA_1'][:])
        dec1 = np.degrees(hdu['DEC_1'][:])

        ra2 = hdu['ra_2'][:]
        dec2 = hdu['dec_2'][:]

        x = hdu['X_Coordinate'][:]
        y = hdu['Y_Coordinate'][:]


    centres = [2048 / 4, 2048 / 2, 3 * 2048 / 4]
    fig, axes = plt.subplots(3, 3, figsize=(11, 8))

    # Get the axes in the correct order
    axes = axes[::-1].T
    zipped = itertools.izip(
        itertools.product(centres, centres),
        axes.flatten())

    margin = 128
    for (x_centre, y_centre), axis in zipped:
        ind = ((x >= x_centre - margin) & (x <= x_centre + margin) &
               (y >= y_centre - margin) & (y <= y_centre + margin))

        axis.scatter(ra2[ind], dec2[ind], marker='o', edgecolor='b', color='None',
                    label='2MASS')
        axis.scatter(ra1[ind], dec1[ind], marker='s', edgecolor='r', color='None',
                    label='CASU')

        hide_labels(axis)

    padding = 0.5
    fig.tight_layout(h_pad=padding, w_pad=padding)

    if args.output is not None:
        fig.savefig(args.output, bbox_inches='tight')
    else:
        plt.show()
示例#12
0
def main(args):
    data = qa_common.CSVContainer(args.extracted)

    mjd0 = int(data.mjd.min())
    data['mjd'] = data.mjd - mjd0

    fig, axes = plt.subplots(6, 1, figsize=(11, 20), sharex=True)

    axes[0].plot(data['mjd'], data.dark, 'k.')
    axes[0].set_ylabel(r'Dark current / $\mathrm{e}^- s^{-1}$')
    axes[0].set_ylim(1, 7)

    axes[1].plot(data['mjd'], data.right - data.left, 'k.')
    axes[1].set_ylabel(r'Left - Right')

    axes[2].plot(data['mjd'], data.left, 'r.', label='left')
    axes[2].plot(data['mjd'], data.right, 'g.', label='right')
    axes[2].set_ylabel(r'Overscan level / counts')

    axes[3].plot(data['mjd'], data.chstemp, 'r.')
    axes[3].set_ylabel(r'Chassis temp')

    axes[4].plot(data['mjd'], data.ccdtemp, 'r.')
    axes[4].set_ylabel(r'CCD temp')

    axes[5].plot(data['mjd'], data.airmass, 'r.')
    axes[5].set_ylabel(r'Airmass')

    axes[-1].set_xlabel('MJD - {}'.format(mjd0))

    for ax in axes:
        ax.grid(True, axis='y')
        plot_night_breaks(ax, data.mjd)

    fig.tight_layout()

    if args.output is not None:
        logger.info('Rendering to %s', args.output)
        fig.savefig(args.output, bbox_inches='tight')
    else:
        plt.show()
示例#13
0
def main(args):
    reader = csv.DictReader(args.data)
    mjd, nsources = map(np.array, zip(*[(float(row['mjd']), float(row['nsources']))
                                        for row in reader]))
    logger.info('Read point source data')
    error = np.sqrt(nsources)

    mjd0 = int(mjd.min())
    mjd -= mjd0

    logger.info('Plotting to %s', args.output)
    fig, axis = plt.subplots()
    axis.errorbar(mjd, nsources, error, ls='', marker='', capsize=0., lw=1.,
            alpha=0.5, color='k')
    axis.plot(mjd, nsources, 'k.')
    axis.set_xlabel(r'MJD - {}'.format(mjd0))
    axis.set_ylabel(r'Number of point sources')
    axis.grid(True)
    fig.tight_layout()

    fig.savefig(args.output, bbox_inches='tight')
def main(args):
    data = qa_common.CSVContainer(args.extracted)
    logger.info('Data read from %s', args.extracted)

    offset_value = 0.1
    offset = np.random.uniform(-offset_value, offset_value, data.chstemp.size)
    
    fig, axis = plt.subplots()

    axis.plot(data.chstemp + offset, data.dark, 'k.')
    axis.grid(True)
    axis.set_xlabel(r'Chassis temperature / C')
    axis.set_ylabel(r'Dark current / $\mathrm{e}^- s^{-1}$')
    
    fig.tight_layout()

    if args.output is not None:
        logger.info('Rendering file to %s', args.output)
        fig.savefig(args.output, bbox_inches='tight')
    else:
        plt.show()
示例#15
0
def main(args):
    with fitsio.FITS(args.catalogue) as infile:
        hdu = infile[1]
        ra1 = hdu['RA_1'][:]
        dec1 = hdu['DEC_1'][:]

        ra2 = hdu['ra_2'][:]
        dec2 = hdu['dec_2'][:]

        jmag = hdu['jmag'][:]


    coords1 = ICRS(ra=ra1, dec=dec1, unit=(u.radian, u.radian))
    coords2 = ICRS(ra=ra2, dec=dec2, unit=(u.degree, u.degree))

    separations = coords1.separation(coords2).degree * 3600.

    nbins = 30
    height, xedges, yedges = np.histogram2d(jmag, separations, nbins)

    fig, axis = plt.subplots(figsize=(11, 8))

    mappable = axis.pcolormesh(xedges[:-1], yedges[:-1], np.log10(height.T + 1), 
            cmap=plt.cm.binary)
    axis.plot(jmag, separations, 'k.', alpha=0.2)

    stat, ledges, _ = stats.binned_statistic(jmag, separations, statistic='median',
            bins=nbins)
    axis.plot(ledges[:-1], stat, drawstyle='steps-post', color='r')

    axis.set_xlabel(r'2MASS J Magnitude')
    axis.set_ylabel(r'Separation / arcseconds')
    axis.grid(True)

    fig.tight_layout()

    if args.output is not None:
        fig.savefig(args.output, bbox_inches='tight')
    else:
        plt.show()
示例#16
0
def main(args):
    data = np.genfromtxt(args.data, delimiter=',', names=True)

    mjd = data['mjd']
    mjd0 = int(mjd.min())
    mjd -= mjd0

    fig, axes = plt.subplots(5, 1, sharex=True)
    render(axes[1], mjd, data, key_type='A')
    render(axes[2], mjd, data, key_type='B')
    render(axes[3], mjd, data, key_type='T')

    stack = []
    for i in psf_indices:
        A = data['psf_A_{}'.format(i)]
        B = data['psf_B_{}'.format(i)]
        fwhm = (A + B) / 2.
        for (x, y, zorder) in random_zorder(mjd, fwhm, len(psf_indices)):
            axes[0].plot(x, y, '.', zorder=zorder, color=colours[i],
                    markersize=markersize)
        e = np.sqrt(1. - (B / A) ** 2)
        stack.append(e)
        for (x, y, zorder) in random_zorder(mjd, e, len(psf_indices)):
            axes[4].plot(x, y, '.', color=colours[i],
                    zorder=zorder, label='Ecc. {}'.format(i),
                    markersize=markersize)
    low, med, high = compute_stats(stack)
    # _errorbar(axes[4], mjd, med, low, high)

    labels = [r'$\mathrm{fwhm}$', r'$a$', r'$b$', r'$\theta$', r'$e$']
    for (ax, label) in zip(axes, labels):
        ax.grid(True)
        ax.set_ylabel(label)

    axes[-2].set_ylim(-360, 360)
    axes[-1].set_xlabel(r'MJD - {}'.format(mjd0))

    fig.tight_layout()
    fig.savefig(args.output)
示例#17
0
def main(args):
    if not args.width % 2 == 0:
        raise RuntimeError("Width must be a multiple of 2")


    logger.debug('Reading data from %s', args.filename)
    with fitsio.FITS(args.filename) as infile:
        image_data = infile[0].read()
        header = infile[0].read_header()

    nfiles = header['nfiles']
    logger.info('Number of files in master flat: %s', nfiles)

    logger.debug('Region: %s', dict(x=args.x, y=args.y, width=args.width))
    region = image_data[
        args.y - args.width / 2: args.y + args.width / 2,
        args.x - args.width / 2: args.x + args.width / 2
    ]

    med_region = np.median(region)
    std_region = np.std(region)
    logger.info('values: %s', dict(median=med_region, std=std_region))

    fig, axis = plt.subplots()
    colour_cycle = axis._get_lines.color_cycle
    axis.hist(region.flatten(), bins=args.nbins, histtype='step', normed=True)
    axis.axvline(med_region, color=next(colour_cycle))

    axis.set_xlabel(r'Total counts / ADU')
    axis.set_ylabel(r'Probability density')
    axis.set_title('Median: {:.1f}, std: {:.3f}, nfiles: {}'.format(
        med_region, std_region, nfiles))

    fig.tight_layout()
    logger.debug('Saving image to %s', args.output)
    if args.output is not None:
        fig.savefig(args.output, bbox_inches='tight')
    else:
        plt.show()
示例#18
0
def main(args):
    fig, ax = plt.subplots(figsize=(11, 8))

    flux_data = extract_flux_data(args.filename, hdu=args.hdu,
            chosen_exptime=args.exptime)
    plot_summary(flux_data, 'b', title=args.hdu, ax=ax)

    ax.legend(loc='best')

    ax.axhline(0, ls='--', color='k')
    ax.axhline(-1E-3, ls=':', color='k')
    ax.axhline(1E-3, ls=':', color='k')

    ax.set_xlabel(r'$\Delta \mathrm{mjd}$')
    ax.set_ylabel(r'FRMS')

    fig.tight_layout()

    if args.output is not None:
        logger.info('Rendering to %s', args.output)
        fig.savefig(args.output, bbox_inches='tight')
    else:
        plt.show()
示例#19
0
def main(args):
    nbins = 256
    logger.debug('Reading data from %s, nbins: %s', args.filename, nbins)
    with fitsio.FITS(args.filename) as infile:
        image = infile[0].read()

    normalised = histogram_equalise(image, nbins=nbins)

    suffixes = ['.{}'.format(args.ext), '_smoothed.{}'.format(args.ext)]
    interpolation_methods = ['none', 'gaussian']

    for (suffix, interpolation_method) in zip(suffixes, interpolation_methods):
        output_filename = '{}{}'.format(args.stub, suffix)
        logger.info('Plotting to %s', output_filename)
        fig, axis = plt.subplots()
        mappable = axis.imshow(normalised, origin='lower', cmap=plt.cm.afmhot,
                               interpolation=interpolation_method)

        for dimension in ['xaxis', 'yaxis']:
            getattr(axis, dimension).set_visible(False)
        axis.set_title(os.path.basename(args.filename))
        fig.tight_layout()
        fig.savefig(output_filename, bbox_inches='tight')
        plt.close(fig)
示例#20
0
def main(args):
    global MJD0
    ledges, redges = build_bins()

    assert all(os.path.isfile(f) for f in args.reduced_files)
    metadata = extract_metadata(args.reduced_files)

    logger.info('Reading data from %s', args.filename)
    with fitsio.FITS(args.filename) as infile:
        flux = infile[args.hdu].read()
        fluxerr = infile['fluxerr'].read()
        imagelist = infile['imagelist']
        airmass = imagelist['airmass'].read()
        exposure = imagelist['exposure'].read()
        tmid = imagelist['tmid'].read()

    unique_exposure_times = sorted(list(set(exposure)))
    logger.info('Found %s exposure times: %s', len(unique_exposure_times),
                unique_exposure_times)

    logger.info('Normalising by exposure time')
    flux /= exposure
    fluxerr /= exposure
    logger.info('Removing extinction')

    MJD0 = int(tmid.min())
    tmid -= MJD0

    flux_mean = np.average(flux, axis=1, weights=1. / fluxerr ** 2)

    fig, axes = plt.subplots(len(ledges) + len(PLOT_KEYS), 1, sharex=True,
                             figsize=(8, 15))

    colours = ['r', 'g', 'b', 'c', 'm', 'k', 'y']
    plot_border = 0.02
    for (ledge, redge, axis) in zip(ledges, redges, axes[len(PLOT_KEYS):]):
        for exptime, colour in zip(unique_exposure_times, colours):
            ind = (flux_mean >= ledge) & (flux_mean < redge)
            exptime_ind = exposure == exptime
            chosen_flux = flux[ind][:, exptime_ind]

            chosen_fluxerr = fluxerr[ind][:, exptime_ind]
            try:
                binned_lc = np.average(chosen_flux, axis=0,
                                   weights=1. / chosen_fluxerr ** 2)
            except ZeroDivisionError:
                binned_lc = np.average(chosen_flux, axis=0)

            axis.plot(tmid[exptime_ind], binned_lc, '.', zorder=2,
                      color=colour)

        axis.yaxis.set_major_locator(plt.MaxNLocator(5))
        axis.set_xlim(tmid.min() - 0.005,
                      tmid.max() + 0.005)

    for (key, axis) in zip(PLOT_KEYS, axes):
        plot_metadata_series(axis, metadata, key, ls='None', marker='.')

    axes[-1].set_xlabel(r'MJD - {}'.format(MJD0))
    axes[0].set_title(args.hdu)

    fig.tight_layout()

    if args.output is not None:
        logger.info('Rendering to %s', args.output)
        fig.savefig(args.output, bbox_inches='tight')
    else:
        plt.show()