def make_cand_plot(d, im, data, loclabel, outname=''): """ Builds candidate plot. Expects phased, dedispersed data (cut out in time, dual-pol), image, and metadata loclabel is used to label the plot with (scan, segment, candint, dmind, dtind, beamnum). """ # given d, im, data, make plot logger.info('Plotting...') logger.debug('(image, data) shape: (%s, %s)' % (str(im.shape), str(data.shape))) assert len( loclabel ) == 6, 'loclabel should have (scan, segment, candint, dmind, dtind, beamnum)' scan, segment, candint, dmind, dtind, beamnum = loclabel # calc source location snrmin = im.min() / im.std() snrmax = im.max() / im.std() if snrmax > -1 * snrmin: l1, m1 = rt.calc_lm(d, im, minmax='max') snrobs = snrmax else: l1, m1 = rt.calc_lm(d, im, minmax='min') snrobs = snrmin pt_ra, pt_dec = d['radec'] src_ra, src_dec = source_location(pt_ra, pt_dec, l1, m1) logger.info('Peak (RA, Dec): %s, %s' % (src_ra, src_dec)) # build plot fig = plt.Figure(figsize=(8.5, 8)) ax = fig.add_subplot(221, axisbg='white') # add annotating info ax.text(0.1, 0.9, d['fileroot'], fontname='sans-serif', transform=ax.transAxes) ax.text(0.1, 0.8, 'sc %d, seg %d, int %d, DM %.1f, dt %d' % (scan, segment, candint, d['dmarr'][dmind], d['dtarr'][dtind]), fontname='sans-serif', transform=ax.transAxes) ax.text(0.1, 0.7, 'Peak: (' + str(np.round(l1, 3)) + ' ,' + str(np.round(m1, 3)) + '), SNR: ' + str(np.round(snrobs, 1)), fontname='sans-serif', transform=ax.transAxes) # plot dynamic spectra left, width = 0.6, 0.2 bottom, height = 0.2, 0.7 rect_dynsp = [left, bottom, width, height] rect_lc = [left, bottom - 0.1, width, 0.1] rect_sp = [left + width, bottom, 0.1, height] ax_dynsp = fig.add_axes(rect_dynsp) ax_lc = fig.add_axes(rect_lc) ax_sp = fig.add_axes(rect_sp) spectra = np.swapaxes( data.real, 0, 1 ) # seems that latest pickle actually contains complex values in spectra... dd = np.concatenate( (spectra[..., 0], np.zeros_like(spectra[..., 0]), spectra[..., 1]), axis=1) # make array for display with white space between two pols impl = ax_dynsp.imshow(dd, origin='lower', interpolation='nearest', aspect='auto', cmap=plt.get_cmap('Greys')) ax_dynsp.text(0.5, 0.95, 'RR LL', horizontalalignment='center', verticalalignment='center', fontsize=16, color='w', transform=ax_dynsp.transAxes) ax_dynsp.set_yticks(range(0, len(d['freq']), 30)) ax_dynsp.set_yticklabels(d['freq'][::30]) ax_dynsp.set_ylabel('Freq (GHz)') ax_dynsp.set_xlabel('Integration (rel)') spectrum = spectra[:, len(spectra[0]) / 2].mean( axis=1 ) # assume pulse in middle bin. get stokes I spectrum. **this is wrong in a minority of cases.** ax_sp.plot(spectrum, range(len(spectrum)), 'k.') ax_sp.plot(np.zeros(len(spectrum)), range(len(spectrum)), 'k:') ax_sp.set_ylim(0, len(spectrum)) ax_sp.set_yticklabels([]) xmin, xmax = ax_sp.get_xlim() ax_sp.set_xticks(np.linspace(xmin, xmax, 3).round(2)) ax_sp.set_xlabel('Flux (Jy)') lc = dd.mean(axis=0) lenlc = len(data) # old (stupid) way: lenlc = np.where(lc == 0)[0][0] ax_lc.plot( range(0, lenlc) + range(2 * lenlc, 3 * lenlc), list(lc)[:lenlc] + list(lc)[-lenlc:], 'k.') ax_lc.plot( range(0, lenlc) + range(2 * lenlc, 3 * lenlc), list(np.zeros(lenlc)) + list(np.zeros(lenlc)), 'k:') ax_lc.set_xlabel('Integration') ax_lc.set_ylabel('Flux (Jy)') ax_lc.set_xticks([ 0, 0.5 * lenlc, lenlc, 1.5 * lenlc, 2 * lenlc, 2.5 * lenlc, 3 * lenlc ]) ax_lc.set_xticklabels( ['0', str(lenlc / 2), str(lenlc), '', '0', str(lenlc / 2), str(lenlc)]) ymin, ymax = ax_lc.get_ylim() ax_lc.set_yticks(np.linspace(ymin, ymax, 3).round(2)) # image ax = fig.add_subplot(223) fov = np.degrees(1. / d['uvres']) * 60. impl = ax.imshow(im.transpose(), aspect='equal', origin='upper', interpolation='nearest', extent=[fov / 2, -fov / 2, -fov / 2, fov / 2], cmap=plt.get_cmap('Greys'), vmin=0, vmax=0.5 * im.max()) ax.set_xlabel('RA Offset (arcmin)') ax.set_ylabel('Dec Offset (arcmin)') if not outname: outname = os.path.join( d['workdir'], 'cands_{}_sc{}-seg{}-i{}-dm{}-dt{}.png'.format( d['fileroot'], scan, segment, candint, dmind, dtind)) try: canvas = FigureCanvasAgg(fig) canvas.print_figure(outname) except ValueError: logger.warn('Could not write figure to %s' % outname)
def make_cand_plot(d, im, data, loclabel, outname=''): """ Builds candidate plot. Expects phased, dedispersed data (cut out in time, dual-pol), image, and metadata loclabel is used to label the plot with (scan, segment, candint, dmind, dtind, beamnum). """ # given d, im, data, make plot logger.info('Plotting...') logger.debug('(image, data) shape: (%s, %s)' % (str(im.shape), str(data.shape))) assert len(loclabel) == 6, 'loclabel should have (scan, segment, candint, dmind, dtind, beamnum)' scan, segment, candint, dmind, dtind, beamnum = loclabel # calc source location snrmin = im.min()/im.std() snrmax = im.max()/im.std() if snrmax > -1*snrmin: l1, m1 = rt.calc_lm(d, im, minmax='max') snrobs = snrmax else: l1, m1 = rt.calc_lm(d, im, minmax='min') snrobs = snrmin pt_ra, pt_dec = d['radec'] src_ra, src_dec = source_location(pt_ra, pt_dec, l1, m1) logger.info('Peak (RA, Dec): %s, %s' % (src_ra, src_dec)) # build plot fig = plt.Figure(figsize=(8.5,8)) ax = fig.add_subplot(221, axisbg='white') # add annotating info ax.text(0.1, 0.9, d['fileroot'], fontname='sans-serif', transform = ax.transAxes) ax.text(0.1, 0.8, 'sc %d, seg %d, int %d, DM %.1f, dt %d' % (scan, segment, candint, d['dmarr'][dmind], d['dtarr'][dtind]), fontname='sans-serif', transform = ax.transAxes) ax.text(0.1, 0.7, 'Peak: (' + str(np.round(l1, 3)) + ' ,' + str(np.round(m1, 3)) + '), SNR: ' + str(np.round(snrobs, 1)), fontname='sans-serif', transform = ax.transAxes) # plot dynamic spectra left, width = 0.6, 0.2 bottom, height = 0.2, 0.7 rect_dynsp = [left, bottom, width, height] rect_lc = [left, bottom-0.1, width, 0.1] rect_sp = [left+width, bottom, 0.1, height] ax_dynsp = fig.add_axes(rect_dynsp) ax_lc = fig.add_axes(rect_lc) ax_sp = fig.add_axes(rect_sp) spectra = np.swapaxes(data.real,0,1) # seems that latest pickle actually contains complex values in spectra... dd = np.concatenate( (spectra[...,0], np.zeros_like(spectra[...,0]), spectra[...,1]), axis=1) # make array for display with white space between two pols impl = ax_dynsp.imshow(dd, origin='lower', interpolation='nearest', aspect='auto', cmap=plt.get_cmap('Greys')) ax_dynsp.text(0.5, 0.95, 'RR LL', horizontalalignment='center', verticalalignment='center', fontsize=16, color='w', transform = ax_dynsp.transAxes) ax_dynsp.set_yticks(range(0,len(d['freq']),30)) ax_dynsp.set_yticklabels(d['freq'][::30]) ax_dynsp.set_ylabel('Freq (GHz)') ax_dynsp.set_xlabel('Integration (rel)') spectrum = spectra[:,len(spectra[0])/2].mean(axis=1) # assume pulse in middle bin. get stokes I spectrum. **this is wrong in a minority of cases.** ax_sp.plot(spectrum, range(len(spectrum)), 'k.') ax_sp.plot(np.zeros(len(spectrum)), range(len(spectrum)), 'k:') ax_sp.set_ylim(0, len(spectrum)) ax_sp.set_yticklabels([]) xmin,xmax = ax_sp.get_xlim() ax_sp.set_xticks(np.linspace(xmin,xmax,3).round(2)) ax_sp.set_xlabel('Flux (Jy)') lc = dd.mean(axis=0) lenlc = len(data) # old (stupid) way: lenlc = np.where(lc == 0)[0][0] ax_lc.plot(range(0,lenlc)+range(2*lenlc,3*lenlc), list(lc)[:lenlc] + list(lc)[-lenlc:], 'k.') ax_lc.plot(range(0,lenlc)+range(2*lenlc,3*lenlc), list(np.zeros(lenlc)) + list(np.zeros(lenlc)), 'k:') ax_lc.set_xlabel('Integration') ax_lc.set_ylabel('Flux (Jy)') ax_lc.set_xticks([0,0.5*lenlc,lenlc,1.5*lenlc,2*lenlc,2.5*lenlc,3*lenlc]) ax_lc.set_xticklabels(['0',str(lenlc/2),str(lenlc),'','0',str(lenlc/2),str(lenlc)]) ymin,ymax = ax_lc.get_ylim() ax_lc.set_yticks(np.linspace(ymin,ymax,3).round(2)) # image ax = fig.add_subplot(223) fov = np.degrees(1./d['uvres'])*60. impl = ax.imshow(im.transpose(), aspect='equal', origin='upper', interpolation='nearest', extent=[fov/2, -fov/2, -fov/2, fov/2], cmap=plt.get_cmap('Greys'), vmin=0, vmax=0.5*im.max()) ax.set_xlabel('RA Offset (arcmin)') ax.set_ylabel('Dec Offset (arcmin)') if not outname: outname = os.path.join(d['workdir'], 'cands_{}_sc{}-seg{}-i{}-dm{}-dt{}.png'.format(d['fileroot'], scan, segment, candint, dmind, dtind)) try: canvas = FigureCanvasAgg(fig) canvas.print_figure(outname) except ValueError: logger.warn('Could not write figure to %s' % outname)
def make_cand_plot(d, im, data, loclabel, version=2, snrs=[], outname=''): """ Builds a new candidate plot, distinct from the original plots produced by make_cand_plot. Expects phased, dedispersed data (cut out in time, dual-pol), image, and metadata version 2 is the new one (thanks to bridget andersen). version 1 is the initial one. loclabel is used to label the plot with (scan, segment, candint, dmind, dtind, beamnum). snrs is array for an (optional) SNR histogram plot. d are used to label the plots with useful information. """ # given d, im, data, make plot logger.info('Plotting...') logger.debug('(image, data) shape: (%s, %s)' % (str(im.shape), str(data.shape))) assert len( loclabel ) == 6, 'loclabel should have (scan, segment, candint, dmind, dtind, beamnum)' scan, segment, candint, dmind, dtind, beamnum = loclabel # calc source location snrmin = im.min() / im.std() snrmax = im.max() / im.std() if snrmax > -1 * snrmin: l1, m1 = rt.calc_lm(d, im, minmax='max') snrobs = snrmax else: l1, m1 = rt.calc_lm(d, im, minmax='min') snrobs = snrmin pt_ra, pt_dec = d['radec'] src_ra, src_dec = source_location(pt_ra, pt_dec, l1, m1) logger.info('Peak (RA, Dec): %s, %s' % (src_ra, src_dec)) # convert l1 and m1 from radians to arcminutes l1arcm = l1 * 180. * 60. / np.pi m1arcm = m1 * 180. * 60. / np.pi if version == 1: # build plot fig = plt.Figure(figsize=(8.5, 8)) ax = fig.add_subplot(221, axisbg='white') # add annotating info ax.text(0.1, 0.9, d['fileroot'], fontname='sans-serif', transform=ax.transAxes) ax.text(0.1, 0.8, 'sc %d, seg %d, int %d, DM %.1f, dt %d' % (scan, segment, candint, d['dmarr'][dmind], d['dtarr'][dtind]), fontname='sans-serif', transform=ax.transAxes) ax.text(0.1, 0.7, 'Peak: (' + str(np.round(l1, 3)) + ' ,' + str(np.round(m1, 3)) + '), SNR: ' + str(np.round(snrobs, 1)), fontname='sans-serif', transform=ax.transAxes) # plot dynamic spectra left, width = 0.6, 0.2 bottom, height = 0.2, 0.7 rect_dynsp = [left, bottom, width, height] rect_lc = [left, bottom - 0.1, width, 0.1] rect_sp = [left + width, bottom, 0.1, height] ax_dynsp = fig.add_axes(rect_dynsp) ax_lc = fig.add_axes(rect_lc) ax_sp = fig.add_axes(rect_sp) spectra = np.swapaxes( data.real, 0, 1 ) # seems that latest pickle actually contains complex values in spectra... dd = np.concatenate( (spectra[..., 0], np.zeros_like(spectra[..., 0]), spectra[..., 1]), axis=1) # make array for display with white space between two pols logger.debug('{0}'.format(dd.shape)) impl = ax_dynsp.imshow(dd, origin='lower', interpolation='nearest', aspect='auto', cmap=plt.get_cmap('Greys')) ax_dynsp.text(0.5, 0.95, 'RR LL', horizontalalignment='center', verticalalignment='center', fontsize=16, color='w', transform=ax_dynsp.transAxes) ax_dynsp.set_yticks(range(0, len(d['freq']), 30)) ax_dynsp.set_yticklabels(d['freq'][::30]) ax_dynsp.set_ylabel('Freq (GHz)') ax_dynsp.set_xlabel('Integration (rel)') spectrum = spectra[:, len(spectra[0]) / 2].mean( axis=1 ) # assume pulse in middle bin. get stokes I spectrum. **this is wrong in a minority of cases.** ax_sp.plot(spectrum, range(len(spectrum)), 'k.') ax_sp.plot(np.zeros(len(spectrum)), range(len(spectrum)), 'k:') ax_sp.set_ylim(0, len(spectrum)) ax_sp.set_yticklabels([]) xmin, xmax = ax_sp.get_xlim() ax_sp.set_xticks(np.linspace(xmin, xmax, 3).round(2)) ax_sp.set_xlabel('Flux (Jy)') lc = dd.mean(axis=0) lenlc = len(data) # old (stupid) way: lenlc = np.where(lc == 0)[0][0] ax_lc.plot( range(0, lenlc) + range(2 * lenlc, 3 * lenlc), list(lc)[:lenlc] + list(lc)[-lenlc:], 'k.') ax_lc.plot( range(0, lenlc) + range(2 * lenlc, 3 * lenlc), list(np.zeros(lenlc)) + list(np.zeros(lenlc)), 'k:') ax_lc.set_xlabel('Integration') ax_lc.set_ylabel('Flux (Jy)') ax_lc.set_xticks([ 0, 0.5 * lenlc, lenlc, 1.5 * lenlc, 2 * lenlc, 2.5 * lenlc, 3 * lenlc ]) ax_lc.set_xticklabels([ '0', str(lenlc / 2), str(lenlc), '', '0', str(lenlc / 2), str(lenlc) ]) ymin, ymax = ax_lc.get_ylim() ax_lc.set_yticks(np.linspace(ymin, ymax, 3).round(2)) # image ax = fig.add_subplot(223) fov = np.degrees(1. / d['uvres']) * 60. logger.debug('{0}'.format(im.shape)) impl = ax.imshow(im.transpose(), aspect='equal', origin='upper', interpolation='nearest', extent=[fov / 2, -fov / 2, -fov / 2, fov / 2], cmap=plt.get_cmap('Greys'), vmin=0, vmax=0.5 * im.max()) ax.set_xlabel('RA Offset (arcmin)') ax.set_ylabel('Dec Offset (arcmin)') elif version == 2: # build overall plot fig = plt.Figure(figsize=(12.75, 8)) # add metadata in subfigure ax = fig.add_subplot(2, 3, 1, axisbg='white') # calculate the overall dispersion delay: dd f1 = d['freq_orig'][0] f2 = d['freq_orig'][len(d['freq_orig']) - 1] dd = 4.15 * d['dmarr'][dmind] * (f1**(-2) - f2**(-2)) # add annotating info start = 1.1 # these values determine the spacing and location of the annotating information space = 0.07 left = 0.0 ax.text(left, start, d['fileroot'], fontname='sans-serif', transform=ax.transAxes, fontsize='small') ax.text(left, start - space, 'Peak (arcmin): (' + str(np.round(l1arcm, 3)) + ', ' + str(np.round(m1arcm, 3)) + ')', fontname='sans-serif', transform=ax.transAxes, fontsize='small') # split the RA and Dec and display in a nice format ra = src_ra.split() dec = src_dec.split() ax.text(left, start - 2 * space, 'Peak (RA, Dec): (' + ra[0] + ':' + ra[1] + ':' + ra[2][0:4] + ', ' + dec[0] + ':' + dec[1] + ':' + dec[2][0:4] + ')', fontname='sans-serif', transform=ax.transAxes, fontsize='small') ax.text(left, start - 3 * space, 'Source: ' + str(d['source']), fontname='sans-serif', transform=ax.transAxes, fontsize='small') ax.text(left, start - 4 * space, 'scan: ' + str(scan), fontname='sans-serif', transform=ax.transAxes, fontsize='small') ax.text(left, start - 5 * space, 'segment: ' + str(segment), fontname='sans-serif', transform=ax.transAxes, fontsize='small') ax.text(left, start - 6 * space, 'integration: ' + str(candint), fontname='sans-serif', transform=ax.transAxes, fontsize='small') ax.text(left, start - 7 * space, 'DM = ' + str(d['dmarr'][dmind]) + ' (index ' + str(dmind) + ')', fontname='sans-serif', transform=ax.transAxes, fontsize='small') ax.text(left, start - 8 * space, 'dt = ' + str(np.round(d['inttime'] * d['dtarr'][dtind], 3) * 1e3) + ' ms' + ' (index ' + str(dtind) + ')', fontname='sans-serif', transform=ax.transAxes, fontsize='small') ax.text(left, start - 9 * space, 'disp delay = ' + str(np.round(dd, 1)) + ' ms', fontname='sans-serif', transform=ax.transAxes, fontsize='small') ax.text(left, start - 10 * space, 'SNR: ' + str(np.round(snrobs, 1)), fontname='sans-serif', transform=ax.transAxes, fontsize='small') # set the plot invisible so that it doesn't interfere with annotations ax.get_xaxis().set_visible(False) ax.get_yaxis().set_visible(False) ax.spines['bottom'].set_color('white') ax.spines['top'].set_color('white') ax.spines['right'].set_color('white') ax.spines['left'].set_color('white') # plot full dynamic spectra left, width = 0.75, 0.2 * 2. / 3. bottom, height = 0.2, 0.7 rect_dynsp1 = [ left, bottom, width / 3., height ] # three rectangles for each panel of the spectrum (RR, RR+LL, LL) rect_dynsp2 = [left + width / 3., bottom, width / 3., height] rect_dynsp3 = [left + 2. * width / 3., bottom, width / 3., height] rect_lc1 = [left, bottom - 0.1, width / 3., 0.1] rect_lc2 = [left + width / 3., bottom - 0.1, width / 3., 0.1] rect_lc3 = [left + 2. * width / 3., bottom - 0.1, width / 3., 0.1] rect_sp = [left + width, bottom, 0.1 * 2. / 3., height] ax_dynsp1 = fig.add_axes(rect_dynsp1) ax_dynsp2 = fig.add_axes( rect_dynsp2, sharey=ax_dynsp1) # sharey so that axes line up ax_dynsp3 = fig.add_axes(rect_dynsp3, sharey=ax_dynsp1) # make RR+LL and LL dynamic spectra y labels invisible so they don't interfere with the plots [label.set_visible(False) for label in ax_dynsp2.get_yticklabels()] [label.set_visible(False) for label in ax_dynsp3.get_yticklabels()] ax_sp = fig.add_axes(rect_sp, sharey=ax_dynsp3) [label.set_visible(False) for label in ax_sp.get_yticklabels()] ax_lc1 = fig.add_axes(rect_lc1) ax_lc2 = fig.add_axes(rect_lc2, sharey=ax_lc1) ax_lc3 = fig.add_axes(rect_lc3, sharey=ax_lc1) [label.set_visible(False) for label in ax_lc2.get_yticklabels()] [label.set_visible(False) for label in ax_lc3.get_yticklabels()] # now actually plot the data spectra = np.swapaxes(data.real, 0, 1) dd1 = spectra[..., 0] dd2 = spectra[..., 0] + spectra[..., 1] dd3 = spectra[..., 1] colormap = 'viridis' logger.debug('{0}'.format(dd1.shape)) logger.debug('{0}'.format(dd2.shape)) logger.debug('{0}'.format(dd3.shape)) impl1 = ax_dynsp1.imshow(dd1, origin='lower', interpolation='nearest', aspect='auto', cmap=plt.get_cmap(colormap)) impl2 = ax_dynsp2.imshow(dd2, origin='lower', interpolation='nearest', aspect='auto', cmap=plt.get_cmap(colormap)) impl3 = ax_dynsp3.imshow(dd3, origin='lower', interpolation='nearest', aspect='auto', cmap=plt.get_cmap(colormap)) ax_dynsp1.set_yticks(range(0, len(d['freq']), 30)) ax_dynsp1.set_yticklabels(d['freq'][::30]) ax_dynsp1.set_ylabel('Freq (GHz)') ax_dynsp1.set_xlabel('RR') ax_dynsp1.xaxis.set_label_position('top') ax_dynsp2.set_xlabel('RR+LL') ax_dynsp2.xaxis.set_label_position('top') ax_dynsp3.set_xlabel('LL') ax_dynsp3.xaxis.set_label_position('top') [label.set_visible(False) for label in ax_dynsp1.get_xticklabels() ] # set xlabels invisible so that they don't interefere with lc plots ax_dynsp1.get_yticklabels()[0].set_visible( False) # This one y label was getting in the way # plot stokes I spectrum of the candidate pulse (assume middle bin) spectrum = spectra[:, len(spectra[0]) / 2].mean( axis=1) # select stokes I middle bin ax_sp.plot(spectrum, range(len(spectrum)), 'k.') ax_sp.plot(np.zeros(len(spectrum)), range(len(spectrum)), 'r:') # plot 0 Jy dotted line xmin, xmax = ax_sp.get_xlim() ax_sp.set_xticks(np.linspace(xmin, xmax, 3).round(2)) ax_sp.set_xlabel('Flux (Jy)') # plot mean flux values for each time bin lc1 = dd1.mean(axis=0) lc2 = dd2.mean(axis=0) lc3 = dd3.mean(axis=0) lenlc = len(data) ax_lc1.plot(range(0, lenlc), list(lc1)[:lenlc], 'k.') ax_lc2.plot(range(0, lenlc), list(lc2)[:lenlc], 'k.') ax_lc3.plot(range(0, lenlc), list(lc3)[:lenlc], 'k.') ax_lc1.plot(range(0, lenlc), list(np.zeros(lenlc)), 'r:') # plot 0 Jy dotted line for each plot ax_lc2.plot(range(0, lenlc), list(np.zeros(lenlc)), 'r:') ax_lc3.plot(range(0, lenlc), list(np.zeros(lenlc)), 'r:') ax_lc2.set_xlabel('Integration (rel)') ax_lc1.set_ylabel('Flux (Jy)') ax_lc1.set_xticks([0, 0.5 * lenlc, lenlc]) ax_lc1.set_xticklabels( ['0', str(lenlc / 2), str(lenlc)] ) # note I chose to only show the '0' label for one of the plots to avoid messy overlap ax_lc2.set_xticks([0, 0.5 * lenlc, lenlc]) ax_lc2.set_xticklabels(['', str(lenlc / 2), str(lenlc)]) ax_lc3.set_xticks([0, 0.5 * lenlc, lenlc]) ax_lc3.set_xticklabels(['', str(lenlc / 2), str(lenlc)]) ymin, ymax = ax_lc1.get_ylim() ax_lc1.set_yticks(np.linspace(ymin, ymax, 3).round(2)) # readjust the x tick marks on the dynamic spectra so that they line up with the lc plots ax_dynsp1.set_xticks([0, 0.5 * lenlc, lenlc]) ax_dynsp2.set_xticks([0, 0.5 * lenlc, lenlc]) ax_dynsp3.set_xticks([0, 0.5 * lenlc, lenlc]) # plot second set of dynamic spectra (averaged across frequency bins to get SNR=2 for the detected candidate) left, width = 0.45, 0.1333 bottom, height = 0.1, 0.4 rect_dynsp1 = [left, bottom, width / 3., height] rect_dynsp2 = [left + width / 3., bottom, width / 3., height] rect_dynsp3 = [left + 2. * width / 3., bottom, width / 3., height] rect_sp = [left + width, bottom, 0.1 * 2. / 3., height] ax_dynsp1 = fig.add_axes(rect_dynsp1) ax_dynsp2 = fig.add_axes(rect_dynsp2, sharey=ax_dynsp1) ax_dynsp3 = fig.add_axes(rect_dynsp3, sharey=ax_dynsp1) # make RR+LL and LL dynamic spectra y labels invisible so they don't interfere with the plots [label.set_visible(False) for label in ax_dynsp2.get_yticklabels()] [label.set_visible(False) for label in ax_dynsp3.get_yticklabels()] ax_sp = fig.add_axes(rect_sp, sharey=ax_dynsp3) [label.set_visible(False) for label in ax_sp.get_yticklabels()] # calculate the number of frequency rows to average together (make the plot have an SNR of 2) n = int((2. * (len(spectra))**0.5 / snrobs)**2) if n == 0: # if n==0 then don't average any (avoids errors for modding and dividing by 0) dd1avg = dd1 dd3avg = dd3 else: # otherwise, add zeros onto the data so that it's length is cleanly divisible by n (makes it easier to average over) dd1zerotemp = np.concatenate( (np.zeros((n - len(spectra) % n, len(spectra[0])), dtype=dd1.dtype), dd1), axis=0) dd3zerotemp = np.concatenate( (np.zeros((n - len(spectra) % n, len(spectra[0])), dtype=dd3.dtype), dd3), axis=0) # make them masked arrays so that the appended zeros do not affect average calculation zeros = np.zeros((len(dd1), len(dd1[0]))) ones = np.ones((n - len(spectra) % n, len(dd1[0]))) masktemp = np.concatenate((ones, zeros), axis=0) dd1zero = ma.masked_array(dd1zerotemp, mask=masktemp) dd3zero = ma.masked_array(dd3zerotemp, mask=masktemp) # average together the data dd1avg = np.array([], dtype=dd1.dtype) for i in range(len(spectra[0])): temp = dd1zero[:, i].reshape(-1, n) tempavg = np.reshape(np.mean(temp, axis=1), (len(temp), 1)) temprep = np.repeat( tempavg, n, axis=0 ) # repeats the mean values to create more pixels (easier to properly crop when it is finally displayed) if i == 0: dd1avg = temprep else: dd1avg = np.concatenate((dd1avg, temprep), axis=1) dd3avg = np.array([], dtype=dd3.dtype) for i in range(len(spectra[0])): temp = dd3zero[:, i].reshape(-1, n) tempavg = np.reshape(np.mean(temp, axis=1), (len(temp), 1)) temprep = np.repeat(tempavg, n, axis=0) if i == 0: dd3avg = temprep else: dd3avg = np.concatenate((dd3avg, temprep), axis=1) dd2avg = dd1avg + dd3avg # add together to get averaged RR+LL spectrum colormap = 'viridis' if n == 0: # again, if n==0 then don't crop the spectra because no zeroes were appended dd1avgcrop = dd1avg dd2avgcrop = dd2avg dd3avgcrop = dd3avg else: # otherwise, crop off the appended zeroes dd1avgcrop = dd1avg[len(ones):len(dd1avg), :] dd2avgcrop = dd2avg[len(ones):len(dd2avg), :] dd3avgcrop = dd3avg[len(ones):len(dd3avg), :] logger.debug('{0}'.format(dd1avgcrop.shape)) logger.debug('{0}'.format(dd2avgcrop.shape)) logger.debug('{0}'.format(dd3avgcrop.shape)) impl1 = ax_dynsp1.imshow(dd1avgcrop, origin='lower', interpolation='nearest', aspect='auto', cmap=plt.get_cmap(colormap)) impl2 = ax_dynsp2.imshow(dd2avgcrop, origin='lower', interpolation='nearest', aspect='auto', cmap=plt.get_cmap(colormap)) impl3 = ax_dynsp3.imshow(dd3avgcrop, origin='lower', interpolation='nearest', aspect='auto', cmap=plt.get_cmap(colormap)) ax_dynsp1.set_yticks(range(0, len(d['freq']), 30)) ax_dynsp1.set_yticklabels(d['freq'][::30]) ax_dynsp1.set_ylabel('Freq (GHz)') ax_dynsp1.set_xlabel('RR') ax_dynsp1.xaxis.set_label_position('top') ax_dynsp2.set_xlabel('Integration (rel)') ax2 = ax_dynsp2.twiny() ax2.set_xlabel('RR+LL') [label.set_visible(False) for label in ax2.get_xticklabels()] ax_dynsp3.set_xlabel('LL') ax_dynsp3.xaxis.set_label_position('top') # plot stokes I spectrum of the candidate pulse in the averaged data (assume middle bin) ax_sp.plot(dd2avgcrop[:, len(dd2avgcrop[0]) / 2] / 2., range(len(dd2avgcrop)), 'k.') ax_sp.plot(np.zeros(len(dd2avgcrop)), range(len(dd2avgcrop)), 'r:') xmin, xmax = ax_sp.get_xlim() ax_sp.set_xticks(np.linspace(xmin, xmax, 3).round(2)) ax_sp.get_xticklabels()[0].set_visible(False) ax_sp.set_xlabel('Flux (Jy)') # readjust the x tick marks on the dynamic spectra ax_dynsp1.set_xticks([0, 0.5 * lenlc, lenlc]) ax_dynsp1.set_xticklabels(['0', str(lenlc / 2), str(lenlc)]) ax_dynsp2.set_xticks([0, 0.5 * lenlc, lenlc]) ax_dynsp2.set_xticklabels(['', str(lenlc / 2), str(lenlc)]) ax_dynsp3.set_xticks([0, 0.5 * lenlc, lenlc]) ax_dynsp3.set_xticklabels(['', str(lenlc / 2), str(lenlc)]) # plot the image and zoomed cutout ax = fig.add_subplot(2, 3, 4) fov = np.degrees(1. / d['uvres']) * 60. impl = ax.imshow(im.transpose(), aspect='equal', origin='upper', interpolation='nearest', extent=[fov / 2, -fov / 2, -fov / 2, fov / 2], cmap=plt.get_cmap('viridis'), vmin=0, vmax=0.5 * im.max()) ax.set_xlabel('RA Offset (arcmin)') ax.set_ylabel('Dec Offset (arcmin)') ax.autoscale( False ) # to stop the plot from autoscaling when we plot the triangles that label the location # add markers on the axes to indicate the measured position of the candidate ax.scatter(x=[l1arcm], y=[-fov / 2], c='#ffff00', s=60, marker='^', clip_on=False) ax.scatter(x=[fov / 2], y=[m1arcm], c='#ffff00', s=60, marker='>', clip_on=False) ax.set_frame_on( False ) # makes it so the axis does not intersect the location triangles (for cosmetic reasons) # add a zoomed cutout image of the candidate (set width at 5*synthesized beam) key = d['vrange'].keys()[0] umax = d['urange'][key] vmax = d['vrange'][key] uvdist = (umax**2 + vmax**2)**0.5 sbeam = np.degrees( d['uvoversample'] / uvdist) * 60. # calculate synthesized beam in arcminutes # figure out the location to center the zoomed image on xratio = len(im[0]) / fov # pix/arcmin yratio = len(im) / fov # pix/arcmin mult = 5 # sets how many times the synthesized beam the zoomed FOV is xmin = max(0, int(len(im[0]) / 2 - (m1arcm + sbeam * mult) * xratio)) xmax = int(len(im[0]) / 2 - (m1arcm - sbeam * mult) * xratio) ymin = max(0, int(len(im) / 2 - (l1arcm + sbeam * mult) * yratio)) ymax = int(len(im) / 2 - (l1arcm - sbeam * mult) * yratio) left, width = 0.231, 0.15 bottom, height = 0.465, 0.15 rect_imcrop = [left, bottom, width, height] ax_imcrop = fig.add_axes(rect_imcrop) logger.debug('{0}'.format(im.transpose()[xmin:xmax, ymin:ymax].shape)) logger.debug('{0} {1} {2} {3}'.format(xmin, xmax, ymin, ymax)) impl = ax_imcrop.imshow(im.transpose()[xmin:xmax, ymin:ymax], aspect=1, origin='upper', interpolation='nearest', extent=[-1, 1, -1, 1], cmap=plt.get_cmap('viridis'), vmin=0, vmax=0.5 * im.max()) # setup the axes ax_imcrop.set_ylabel('Dec (arcmin)') ax_imcrop.set_xlabel('RA (arcmin)') ax_imcrop.xaxis.set_label_position('top') ax_imcrop.xaxis.tick_top() xlabels = [ str(np.round(l1arcm + sbeam * mult / 2, 1)), '', str(np.round(l1arcm, 1)), '', str(np.round(l1arcm - sbeam * mult / 2, 1)) ] ylabels = [ str(np.round(m1arcm - sbeam * mult / 2, 1)), '', str(np.round(m1arcm, 1)), '', str(np.round(m1arcm + sbeam * mult / 2, 1)) ] ax_imcrop.set_xticklabels(xlabels) ax_imcrop.set_yticklabels(ylabels) # change axis label location of inset so it doesn't interfere with the full picture ax_imcrop.get_yticklabels()[0].set_verticalalignment('bottom') # create SNR versus N histogram for the whole observation (properties for each candidate in the observation given by prop) if len(snrs): left, width = 0.45, 0.2 bottom, height = 0.6, 0.3 rect_snr = [left, bottom, width, height] ax_snr = fig.add_axes(rect_snr) pos_snrs = snrs[snrs >= 0] neg_snrs = snrs[snrs < 0] if not len( neg_snrs): # if working with subset and only positive snrs neg_snrs = pos_snrs nonegs = True else: nonegs = False minval = 5.5 maxval = 8.0 # determine the min and max values of the x axis if min(pos_snrs) < min(np.abs(neg_snrs)): minval = min(pos_snrs) else: minval = min(np.abs(neg_snrs)) if max(pos_snrs) > max(np.abs(neg_snrs)): maxval = max(pos_snrs) else: maxval = max(np.abs(neg_snrs)) # positive SNR bins are in blue # absolute values of negative SNR bins are taken and plotted as red x's on top of positive blue bins for compactness n, b, patches = ax_snr.hist(pos_snrs, 50, (minval, maxval), facecolor='blue', zorder=1) vals, bin_edges = np.histogram(np.abs(neg_snrs), 50, (minval, maxval)) bins = np.array([(bin_edges[i] + bin_edges[i + 1]) / 2. for i in range(len(vals))]) vals = np.array(vals) if not nonegs: ax_snr.scatter(bins[vals > 0], vals[vals > 0], marker='x', c='orangered', alpha=1.0, zorder=2) ax_snr.set_xlabel('SNR') ax_snr.set_xlim(left=minval - 0.2) ax_snr.set_xlim(right=maxval + 0.2) ax_snr.set_ylabel('N') ax_snr.set_yscale('log') # draw vertical line where the candidate SNR is ax_snr.axvline(x=np.abs(snrobs), linewidth=1, color='y', alpha=0.7) else: logger.warn('make_cand_plot version not recognized.') if not outname: outname = os.path.join( d['workdir'], 'cands_{}_sc{}-seg{}-i{}-dm{}-dt{}.png'.format( d['fileroot'], scan, segment, candint, dmind, dtind)) try: canvas = FigureCanvasAgg(fig) canvas.print_figure(outname) except ValueError: logger.warn('Could not write figure to %s' % outname)
def plot_cand(mergepkl, candnum=-1, outname='', threshold=0, **kwargs): """ Create detailed plot of a single candidate. threshold is min of sbs(SNR) used to filter candidates to select with candnum. kwargs passed to rt.set_pipeline """ d = pickle.load(open(mergepkl, 'r')) loc, prop = read_candidates(mergepkl) if not os.path.dirname(d['filename']): d['filename'] = os.path.join(d['workdir'], d['filename']) # feature columns if 'snr2' in d['features']: snrcol = d['features'].index('snr2') elif 'snr1' in d['features']: snrcol = d['features'].index('snr1') if 'l2' in d['features']: lcol = d['features'].index('l2') elif 'l1' in d['features']: lcol = d['features'].index('l1') if 'm2' in d['features']: mcol = d['features'].index('m2') elif 'm1' in d['features']: mcol = d['features'].index('m1') scancol = d['featureind'].index('scan') segmentcol = d['featureind'].index('segment') intcol = d['featureind'].index('int') dtindcol = d['featureind'].index('dtind') dmindcol = d['featureind'].index('dmind') # sort and prep candidate list snrs = n.array([prop[i][snrcol] for i in range(len(prop))]) select = n.where(n.abs(snrs) > threshold)[0] loc = loc[select] prop = [prop[i] for i in select] if candnum < 0: logger.info('Getting candidates...') for i in range(len(loc)): logger.info("%d %s %s" % (i, str(loc[i]), str(prop[i][snrcol]))) return (loc, n.array([prop[i][snrcol] for i in range(len(prop))])) else: logger.info('Reproducing and visualizing candidate %d at %s with properties %s.' % (candnum, loc[candnum], prop[candnum])) # get cand info scan = loc[candnum, scancol] segment = loc[candnum, segmentcol] dmind = loc[candnum, dmindcol] dtind = loc[candnum, dtindcol] candint = loc[candnum, intcol] dmarrorig = d['dmarr'] dtarrorig = d['dtarr'] # set up state dict d['starttime_mjd'] = d['starttime_mjddict'][scan] d['scan'] = scan d['nsegments'] = len(d['segmenttimesdict'][scan]) # d2 = rt.set_pipeline(d['filename'], scan, fileroot=d['fileroot'], savecands=False, savenoise=False, nsegments=nsegments, **kwargs) d['segmenttimes'] = d['segmenttimesdict'][scan] d['savecands'] = False; d['savenoise'] = False for key in kwargs.keys(): logger.info('Setting %s to %s' % (key, kwargs[key])) d[key] = kwargs[key] # reproduce im, data = rt.pipeline_reproduce(d, segment, (candint, dmind, dtind)) # with candnum, pipeline will return cand image and data # calc source location snrmin = im.min()/im.std() snrmax = im.max()/im.std() if snrmax > -1*snrmin: l1, m1 = rt.calc_lm(d, im, minmax='max') else: l1, m1 = rt.calc_lm(d, im, minmax='min') pt_ra, pt_dec = d['radec'] src_ra, src_dec = source_location(pt_ra, pt_dec, l1, m1) logger.info('Peak (RA, Dec): %s, %s' % (src_ra, src_dec)) # plot it logger.info('Plotting...') fig = plt.Figure(figsize=(8.5,8)) ax = fig.add_subplot(221, axisbg='white') # # first plot dm-t distribution beneath times0 = int2mjd(d, loc) times0 = times0 - times0[0] times = times0[candnum] dms0 = n.array(dmarrorig)[list(loc[:,dmindcol])] dms = dmarrorig[loc[candnum,dmindcol]] snr0 = [prop[i][snrcol] for i in range(len(prop))] snr = snr0[candnum] snrmin = 0.8 * min(d['sigma_image1'], d['sigma_image2']) # plot positive good = n.where(snr0 > 0)[0] ax.scatter(times0[good], dms0[good], s=(snr0[good]-snrmin)**5, facecolor='none', linewidth=0.2, clip_on=False) ax.scatter(times, dms, s=(snr-snrmin)**5, facecolor='none', linewidth=2, clip_on=False) # plot negative good = n.where(snr0 < 0) ax.scatter(times0[good], dms0[good], s=(n.abs(snr0)[good]-snrmin)**5, marker='x', edgecolors='k', linewidth=0.2, clip_on=False) ax.set_ylim(dmarrorig[0], dmarrorig[-1]) ax.set_xlim(times0.min(), times0.max()) ax.set_xlabel('Time (s)') ax.set_ylabel('DM (pc/cm3)') # # then add annotating info ax.text(0.1, 0.9, d['fileroot']+'_sc'+str(scan), fontname='sans-serif', transform = ax.transAxes) ax.text(0.1, 0.8, 'seg %d, int %d, DM %.1f, dt %d' % (segment, loc[candnum, intcol], dmarrorig[loc[candnum, dmindcol]], dtarrorig[loc[candnum,dtindcol]]), fontname='sans-serif', transform = ax.transAxes) ax.text(0.1, 0.7, 'Peak: (' + str(n.round(l1, 3)) + '\' ,' + str(n.round(m1, 3)) + '\'), SNR: ' + str(n.round(snr, 1)), fontname='sans-serif', transform = ax.transAxes) # plot dynamic spectra left, width = 0.6, 0.2 bottom, height = 0.2, 0.7 rect_dynsp = [left, bottom, width, height] rect_lc = [left, bottom-0.1, width, 0.1] rect_sp = [left+width, bottom, 0.1, height] ax_dynsp = fig.add_axes(rect_dynsp) ax_lc = fig.add_axes(rect_lc) ax_sp = fig.add_axes(rect_sp) spectra = n.swapaxes(data.real,0,1) # seems that latest pickle actually contains complex values in spectra... dd = n.concatenate( (spectra[...,0], n.zeros_like(spectra[...,0]), spectra[...,1]), axis=1) # make array for display with white space between two pols impl = ax_dynsp.imshow(dd, origin='lower', interpolation='nearest', aspect='auto', cmap=plt.get_cmap('Greys')) ax_dynsp.text(0.5, 0.95, 'RR LL', horizontalalignment='center', verticalalignment='center', fontsize=16, color='w', transform = ax_dynsp.transAxes) ax_dynsp.set_yticks(range(0,len(d['freq']),30)) ax_dynsp.set_yticklabels(d['freq'][::30]) ax_dynsp.set_ylabel('Freq (GHz)') ax_dynsp.set_xlabel('Integration (rel)') spectrum = spectra[:,len(spectra[0])/2].mean(axis=1) # assume pulse in middle bin. get stokes I spectrum. **this is wrong in a minority of cases.** ax_sp.plot(spectrum, range(len(spectrum)), 'k.') ax_sp.plot(n.zeros(len(spectrum)), range(len(spectrum)), 'k:') ax_sp.set_ylim(0, len(spectrum)) ax_sp.set_yticklabels([]) xmin,xmax = ax_sp.get_xlim() ax_sp.set_xticks(n.linspace(xmin,xmax,3).round(2)) ax_sp.set_xlabel('Flux (Jy)') lc = dd.mean(axis=0) lenlc = n.where(lc == 0)[0][0] ax_lc.plot(range(0,lenlc)+range(2*lenlc,3*lenlc), list(lc)[:lenlc] + list(lc)[-lenlc:], 'k.') ax_lc.plot(range(0,lenlc)+range(2*lenlc,3*lenlc), list(n.zeros(lenlc)) + list(n.zeros(lenlc)), 'k:') ax_lc.set_xlabel('Integration') ax_lc.set_ylabel('Flux (Jy)') ax_lc.set_xticks([0,0.5*lenlc,lenlc,1.5*lenlc,2*lenlc,2.5*lenlc,3*lenlc]) ax_lc.set_xticklabels(['0',str(lenlc/2),str(lenlc),'','0',str(lenlc/2),str(lenlc)]) ymin,ymax = ax_lc.get_ylim() ax_lc.set_yticks(n.linspace(ymin,ymax,3).round(2)) # image ax = fig.add_subplot(223) fov = n.degrees(1./d['uvres'])*60. # ax.scatter(((xpix/2-srcra[0])-0.05*xpix)*fov/xpix, (ypix/2-srcdec[0])*fov/ypix, s=80, marker='<', facecolor='none') # ax.scatter(((xpix/2-srcra[0])+0.05*xpix)*fov/xpix, (ypix/2-srcdec[0])*fov/ypix, s=80, marker='>', facecolor='none') impl = ax.imshow(im.transpose(), aspect='equal', origin='upper', interpolation='nearest', extent=[fov/2, -fov/2, -fov/2, fov/2], cmap=plt.get_cmap('Greys'), vmin=0, vmax=0.5*im.max()) ax.set_xlabel('RA Offset (arcmin)') ax.set_ylabel('Dec Offset (arcmin)') if not outname: outname = os.path.join(d['workdir'], 'cands_%s_sc%dseg%di%ddm%ddt%d.png' % (d['fileroot'], scan, segment, loc[candnum, intcol], dmind, dtind)) canvas = FigureCanvasAgg(fig) canvas.print_figure(outname) return ([],[])