def tilt_spec(k, energy, log10jnu, emin=1., emax=10.): """ Tilt the input spectrum between emin and emax by k. The spectrum < emin is unaffected, but is given a constant shift above emax to avoid a discontinuity. Parameters ---------- k : float Tilt parameter. 0 means no tilt, a positive value makes the spectrum shallower, and a negative value makes it steeper. energy : array of shape(n,) Energy in same units as emin, emax (default is Rydbergs) log10jnu : array of shape(n,) log10 of the intensity. emin, emax : floats The start and end energies in Rydbergs of the region to which the tilt is applied. Returns ------- log10jnu_tilted : array of shape (n,) The input spectrum with a tilt applied. """ new = np.array(log10jnu, copy=True) c0 = between(energy, emin, emax) new[c0] = log10jnu[c0] + k * (np.log10(energy[c0]) - np.log10(emin)) c1 = energy > emax new[c1] = log10jnu[c1] + (new[c0][-1] - log10jnu[c0][-1]) return new
def apply_cont_adjustments(self): l = self.opt.f26.lines if self.opt.f26.regions is None: return regions = self.opt.f26.regions isort = regions.wmin.argsort() adjust = l[l.name == '<>'] print 'applying continuum adjustments for', len(adjust), 'regions' for val in adjust: wa = self.opt.atom['<>'].wa[0] * (1 + val['z']) i0 = regions.wmin[isort].searchsorted(wa) i1 = regions.wmax[isort].searchsorted(wa) #print i0, i1 #import pdb; pdb.set_trace() assert i0 - 1 == i1 linterm = val['b'] level = val['logN'] wa0 = regions.wmin[isort[i0 - 1]] - expand_cont_adjustment wa1 = regions.wmax[isort[i1]] + expand_cont_adjustment c0 = between(self.wa, wa0, wa1) mult = level + linterm * (self.wa[c0]/wa - 1) #print mult self.model[c0] = self.model[c0] * mult
def apply_cont_adjustments(self): l = self.opt.f26.lines if self.opt.f26.regions is None: return regions = self.opt.f26.regions isort = regions.wmin.argsort() adjust = l[l.name == '<>'] print 'applying continuum adjustments for', len(adjust), 'regions' for val in adjust: wa = self.opt.atom['<>'].wa[0] * (1 + val['z']) i0 = regions.wmin[isort].searchsorted(wa) i1 = regions.wmax[isort].searchsorted(wa) #print i0, i1 #import pdb; pdb.set_trace() assert i0 - 1 == i1 linterm = val['b'] level = val['logN'] wa0 = regions.wmin[isort[i0 - 1]] - expand_cont_adjustment wa1 = regions.wmax[isort[i1]] + expand_cont_adjustment c0 = between(self.wa, wa0, wa1) mult = level + linterm * (self.wa[c0] / wa - 1) #print mult self.model[c0] = self.model[c0] * mult
def plotregions(ax, wmin, wmax, wa, fl): """ Plot a series of fitting regions on the matplotlib axes `ax`. """ trans = mtransforms.blended_transform_factory(ax.transData, ax.transAxes) regions = [] for w0, w1 in zip(wmin, wmax): r0, = ax.plot([w0, w1], [0.8, 0.8], color='r', lw=3, alpha=0.7, transform=trans) c0 = between(wa, w0, w1) r1, = ax.plot(wa[c0], fl[c0], color='y', lw=3, alpha=0.5, zorder=0, drawstyle='steps-mid') #r = ax.fill_betweenx([0, 0.8], w0, x2=w1, facecolor='b', alpha=0.2, # lw=0, zorder=1, # transform=trans) regions.extend([r0, r1]) return regions
def plot_velocity_regions(wmin, wmax, w0, w1, obswa, ax, offset, vel, nfl): """ wmin, wmax is minimum and maximum wavelengths of the plot. w0 and w1 are the min and max wavelengths of the fitting regions. obswa is the wavelength of the transition for this plot. """ cond = ((w1 >= wmax) & (w0 < wmax)) | \ ((w1 <= wmax) & (w0 >= wmin)) | \ ((w1 > wmin) & (w0 <= wmin)) regions = [] if not cond.any(): return regions vel0 = (w0[cond] / obswa - 1) * c_kms vel1 = (w1[cond] / obswa - 1) * c_kms for v0, v1 in zip(vel0, vel1): yoff = 1.1 + offset R0, = ax.plot([v0, v1], [yoff, yoff], 'r', lw=3, alpha=0.7) cond = between(vel, v0, v1) R1, = ax.plot(vel[cond], nfl[cond] + offset, 'y', lw=4, alpha=0.5, drawstyle='steps-mid', zorder=0) regions.extend([R0, R1]) return regions
def plot_velocity_regions(wmin, wmax, w0, w1, obswa, ax, offset, vel, nfl): """ wmin, wmax is minimum and maximum wavelengths of the plot. w0 and w1 are the min and max wavelengths of the fitting regions. obswa is the wavelength of the transition for this plot. """ cond = ((w1 >= wmax) & (w0 < wmax)) | \ ((w1 <= wmax) & (w0 >= wmin)) | \ ((w1 > wmin) & (w0 <= wmin)) regions = [] if not cond.any(): return regions vel0 = (w0[cond] / obswa - 1) * c_kms vel1 = (w1[cond] / obswa - 1) * c_kms for v0, v1 in zip(vel0, vel1): yoff = 1.1 + offset R0, = ax.plot([v0, v1], [yoff, yoff], 'r', lw=3, alpha=0.7) cond = between(vel, v0, v1) R1, = ax.plot(vel[cond], nfl[cond] + offset, 'y', lw=4, alpha=0.5, drawstyle='steps-mid',zorder=0) regions.extend([R0,R1]) return regions
def on_keypress_navigate(self, event): """ Process a keypress event. Requires attributes self.ax, self.fl, self.wa, self.fig """ # Navigation if event.key == 'i' and event.inaxes: x0,x1 = self.ax.get_xlim() x = event.xdata dx = abs(x1 - x0) self.ax.set_xlim(x - 0.275*dx, x + 0.275*dx) self.fig.canvas.draw() elif event.key == 'o' and event.inaxes: x0,x1 = self.ax.get_xlim() x = event.xdata dx = abs(x1 - x0) self.ax.set_xlim(x - 0.95*dx, x + 0.95*dx) self.fig.canvas.draw() elif event.key == 'Y' and event.inaxes: y0,y1 = self.ax.get_ylim() y = event.ydata dy = abs(y1 - y0) self.ax.set_ylim(y0 - 0.05*dy, y1 + 0.4*dy) self.fig.canvas.draw() elif event.key == 'y' and event.inaxes: x0,x1 = self.ax.get_xlim() y0,y1 = get_flux_plotrange(self.fl[between(self.wa, x0, x1)]) self.ax.set_ylim(y0, y1) self.fig.canvas.draw() elif event.key == ']': x0,x1 = self.ax.get_xlim() dx = abs(x1 - x0) self.ax.set_xlim(x1 - 0.1*dx, x1 + 0.9*dx) self.fig.canvas.draw() elif event.key == '[': x0,x1 = self.ax.get_xlim() dx = abs(x1 - x0) self.ax.set_xlim(x0 - 0.9*dx, x0 + 0.1*dx) self.fig.canvas.draw() elif event.key == 'w': self.ax.set_xlim(self.wa[0], self.wa[-1]) y0,y1 = get_flux_plotrange(self.fl) self.ax.set_ylim(y0, y1) self.fig.canvas.draw() elif event.key == 'b' and event.inaxes: y0, y1 = self.ax.get_ylim() self.ax.set_ylim(event.ydata, y1) self.fig.canvas.draw() elif event.key == 't' and event.inaxes: y0, y1 = self.ax.get_ylim() self.ax.set_ylim(y0, event.ydata) self.fig.canvas.draw() elif event.key == 'l' and event.inaxes: x0, x1 = self.ax.get_xlim() self.ax.set_xlim(event.xdata, x1) self.fig.canvas.draw() elif event.key == 'r' and event.inaxes: x0, x1 = self.ax.get_xlim() self.ax.set_xlim(x0, event.xdata) self.fig.canvas.draw()
def on_keypress_navigate(self, event): """ Process a keypress event. Requires attributes self.ax, self.fl, self.wa, self.fig """ # Navigation if event.key == 'i' and event.inaxes: x0, x1 = self.ax.get_xlim() x = event.xdata dx = abs(x1 - x0) self.ax.set_xlim(x - 0.275 * dx, x + 0.275 * dx) self.fig.canvas.draw() elif event.key == 'o' and event.inaxes: x0, x1 = self.ax.get_xlim() x = event.xdata dx = abs(x1 - x0) self.ax.set_xlim(x - 0.95 * dx, x + 0.95 * dx) self.fig.canvas.draw() elif event.key == 'Y' and event.inaxes: y0, y1 = self.ax.get_ylim() y = event.ydata dy = abs(y1 - y0) self.ax.set_ylim(y0 - 0.05 * dy, y1 + 0.4 * dy) self.fig.canvas.draw() elif event.key == 'y' and event.inaxes: x0, x1 = self.ax.get_xlim() y0, y1 = get_flux_plotrange(self.fl[between(self.wa, x0, x1)]) self.ax.set_ylim(y0, y1) self.fig.canvas.draw() elif event.key == ']': x0, x1 = self.ax.get_xlim() dx = abs(x1 - x0) self.ax.set_xlim(x1 - 0.1 * dx, x1 + 0.9 * dx) self.fig.canvas.draw() elif event.key == '[': x0, x1 = self.ax.get_xlim() dx = abs(x1 - x0) self.ax.set_xlim(x0 - 0.9 * dx, x0 + 0.1 * dx) self.fig.canvas.draw() elif event.key == 'w': self.ax.set_xlim(self.wa[0], self.wa[-1]) y0, y1 = get_flux_plotrange(self.fl) self.ax.set_ylim(y0, y1) self.fig.canvas.draw() elif event.key == 'b' and event.inaxes: y0, y1 = self.ax.get_ylim() self.ax.set_ylim(event.ydata, y1) self.fig.canvas.draw() elif event.key == 't' and event.inaxes: y0, y1 = self.ax.get_ylim() self.ax.set_ylim(y0, event.ydata) self.fig.canvas.draw() elif event.key == 'l' and event.inaxes: x0, x1 = self.ax.get_xlim() self.ax.set_xlim(event.xdata, x1) self.fig.canvas.draw() elif event.key == 'r' and event.inaxes: x0, x1 = self.ax.get_xlim() self.ax.set_xlim(x0, event.xdata) self.fig.canvas.draw()
def main(): if not os.path.lexists('grid.cfg'): print ('./grid.cfg file not found, writing an example grid.cfg to ' 'the current directory') write_example_grid_config() sys.exit() cfg = read_config('grid.cfg') print '' print 'Input values:' for k in sorted(cfg): print ' %s: %s' % (k, cfg[k]) print '' if cfg.table is None: fluxname = cfg.prefix + '_temp_uvb.dat' uvb = calc_uvb(cfg.z, cfg.cuba_name, match_fg=True) writetable('cloudy_jnu_HM.tbl', [uvb['energy'], uvb['logjnu']], overwrite=1, units=['Rydbergs', 'log10(erg/s/cm^2/Hz/ster)'], names=['energy', 'jnu']) if cfg.distance_starburst_kpc is not None: wa, F = read_starburst99('starburst.spectrum1') nu, logjnu = calc_local_jnu(wa, F, cfg.distance_starburst_kpc, cfg.fesc) energy = nu * hplanck / Ryd # use HM uvb energy limits cond = between(uvb['energy'], energy[0], energy[-1]) logjnu1 = np.interp(uvb['energy'][cond], energy, logjnu) uvb['logjnu'][cond] = np.log10(10**uvb['logjnu'][cond] + 10**logjnu1) writetable('cloudy_jnu_total.tbl', [uvb['energy'], uvb['logjnu']], overwrite=1, units=['Rydbergs', 'log10(erg/s/cm^2/Hz/ster)'], names=['energy', 'jnu']) write_uvb(fluxname, uvb['energy'], uvb['logjnu'], cfg.overwrite) # Fnu at 1 Rydberg k = np.argmin(np.abs(uvb['energy'] - 1.)) logfnu912 = np.log10(10**uvb['logjnu'][k] * 4 * pi) else: logfnu912 = cfg.logfnu912 fluxname = None write_grid_input(cfg, fnu912=logfnu912, fluxfilename=fluxname, table=cfg.table, abundances=cfg.abundances) if cfg.run_cloudy: run_grid(nproc=cfg.nproc, overwrite=cfg.overwrite) models = parse_grid2(cfg) filename = cfg.prefix + '_grid.sav.gz' print 'Writing to', filename saveobj(filename, models, overwrite=cfg.overwrite)
def read_redmapper(): #d = fits.getdata(prefix + 'clusters/redmapper/' # 'dr8_run_redmapper_v5.10_lgt5_catalog.fits') d = fits.getdata(prefix + 'clusters/redmapper/DR8/' 'dr8_run_redmapper_v5.10_lgt5_catalog.fit') z = d['Z_LAMBDA'] c0 = d['BCG_SPEC_Z'] != -1 z[c0] = d['BCG_SPEC_Z'][c0] zer = d['Z_LAMBDA_E'] if CLUS_ZERR == 'erphotz': zer[c0] = 0.001 elif isinstance(CLUS_ZERR, float): zer[:] = CLUS_ZERR else: raise ValueError # 0.005 corresponds to a velocity dispersion of 937 km/s at z=0.6 zer = np.where(zer < 0.005, 0.005, zer) if os.path.exists('dc_redmapper.sav'): rlos = loadobj('dc_redmapper.sav') assert len(rlos) == len(d) else: # this takes about 5 min to run print 'calculating comoving distances' rlos = cosmo.comoving_distance(z) saveobj('dc_redmapper.sav', rlos) # in solar masses, conversion from Rykoff 2013 appendix B. m200 = m200_from_richness(d['LAMBDA_CHISQ']) d1 = np.rec.fromarrays([d.RA, d.DEC, z, zer, d.LAMBDA_CHISQ, d.MEM_MATCH_ID, rlos.value, m200], names='ra,dec,z,zer,richness,id,rlos,m200') d2 = d1[between(d1.z, ZMIN_CLUS, ZMAX_CLUS)] d3 = d2[between(np.log10(d2['m200']), log10MINMASS, log10MAXMASS)] iclus_from_id = {idval:i for i,idval in enumerate(d3.id)} return d3, iclus_from_id
def find_dndz_vs_rho(rho, mg2, iMgII_from_id, ewrestmin, ewrestmax): """ Find dNdz as a function of rho for absorbers with rest ew > ewrestmin given a list of results in rho.""" res = [] for irho, r in enumerate(rho): #print 'bin', irho # absorbers in this bin i = np.array([iMgII_from_id[ind] for ind in r['abid']], dtype=int) mg2_ = mg2[i] c0 = between(mg2_['Wr'], ewrestmin, ewrestmax) l = c0.sum() res.append((l / r['zpathtot'], np.sqrt(l) / r['zpathtot'], l)) dNdz, dNdz_err, nabs = map(np.array, zip(*res)) print nabs return dNdz, dNdz_err, nabs
def find_dndz_vs_rho(rho, mg2, iMgII_from_id, ewrestmin, ewrestmax): """ Find dNdz as a function of rho for absorbers with rest ew > ewrestmin given a list of results in rho.""" res = [] for irho,r in enumerate(rho): #print 'bin', irho # absorbers in this bin i = np.array([iMgII_from_id[ind] for ind in r['abid']], dtype=int) mg2_ = mg2[i] c0 = between(mg2_['Wr'], ewrestmin, ewrestmax) l = c0.sum() res.append((l / r['zpathtot'], np.sqrt(l) / r['zpathtot'], l)) dNdz, dNdz_err, nabs = map(np.array, zip(*res)) print nabs return dNdz, dNdz_err, nabs
def apply_zero_offsets(self): l = self.opt.f26.lines if self.opt.f26.regions is None: return regions = self.opt.f26.regions isort = regions.wmin.argsort() zeros = l[l.name == '__'] print 'applying zero offsets for', len(zeros), 'regions' for val in zeros: wa = self.opt.atom['__'].wa[0] * (1 + val['z']) i0 = regions.wmin[isort].searchsorted(wa) i1 = regions.wmax[isort].searchsorted(wa) #print i0, i1 #import pdb; pdb.set_trace() assert i0 - 1 == i1 c0 = between(self.wa, regions.wmin[isort[i0 - 1]], regions.wmax[isort[i1]]) model = self.model[c0] * (1. - val['logN']) + val['logN'] #import pdb; pdb.set_trace() self.model[c0] = model
def read_redmapper(): d = fits.getdata(prefix + 'clusters/redmapper/' 'dr8_run_redmapper_v5.10_lgt5_catalog.fits') #d = fits.getdata(prefix + 'clusters/redmapper/DR8/' # 'dr8_run_redmapper_v5.10_lgt5_catalog.fit') z = d['Z_LAMBDA'] c0 = d['BCG_SPEC_Z'] != -1 z[c0] = d['BCG_SPEC_Z'][c0] zer = d['Z_LAMBDA_E'] if CLUS_ZERR == 'erphotz': zer[c0] = 0.001 elif isinstance(CLUS_ZERR, float): zer[:] = CLUS_ZERR else: raise ValueError # 0.005 corresponds to a velocity dispersion of 937 km/s at z=0.6 zer = np.where(zer < 0.005, 0.005, zer) if os.path.exists('dc_redmapper.sav'): rlos = loadobj('dc_redmapper.sav') assert len(rlos) == len(d) else: # this takes about 5 min to run print 'calculating comoving distances' rlos = cosmo.comoving_distance(z) saveobj('dc_redmapper.sav', rlos) # in solar masses, conversion from Rykoff 2013 appendix B. m200 = m200_from_richness(d['LAMBDA_CHISQ']) d1 = np.rec.fromarrays([ d.RA, d.DEC, z, zer, d.LAMBDA_CHISQ, d.MEM_MATCH_ID, rlos.value, m200 ], names='ra,dec,z,zer,richness,id,rlos,m200') d2 = d1[d1.z > ZMIN_CLUS] d3 = d2[between(np.log10(d2['m200']), log10MINMASS, log10MAXMASS)] iclus_from_id = {idval: i for i, idval in enumerate(d3.id)} return d3, iclus_from_id
def main(): if not os.path.lexists('grid.cfg'): print ('./grid.cfg file not found, writing an example grid.cfg to ' 'the current directory') write_example_grid_config() sys.exit() cfg = read_config('grid.cfg') print '' print 'Input values:' for k in sorted(cfg): print ' %s: %s' % (k, cfg[k]) print '' if cfg.table is None: fluxname = cfg.prefix + '_temp_uvb.dat' if cfg.cuba_name is None: cfg.cuba_name = get_data_path() + 'UVB.out' uvb = calc_uvb(cfg.z, cfg.cuba_name, match_fg=False) writetable('cloudy_jnu_HM.tbl', [uvb['energy'], uvb['logjnu']], overwrite=1, units=['Rydbergs', 'erg/s/cm^2/Hz/ster'], names=['energy', 'log10jnu']) if cfg.uvb_tilt is not None: if cfg.distance_starburst_kpc is not None: raise RuntimeError('Must only specify one of uvb_tilt and\ distance_starburst_kpc!') # remember which bits had 1e-30 clow = uvb['logjnu'] == -30 # tilt the UV background between 1 and 10 Rydbergs logjnu = tilt_spec(cfg.uvb_tilt, uvb['energy'], uvb['logjnu'], emin=1, emax=10) logjnu[clow] = -30 print('Tilting UVB using parameter {}'.format(cfg.uvb_tilt)) # now re-normalise to match the photoionization rate of the # default spectrum. gamma_default = find_gamma(uvb['energy'], 10**uvb['logjnu']) mult = gamma_default / find_gamma(uvb['energy'], 10**logjnu) print 'Scaling tilted Jnu by %.3g to match default gamma' % mult logjnu = logjnu + np.log10(mult) writetable('cloudy_jnu_tilted.tbl', [uvb['energy'], logjnu], overwrite=1, units=['Rydbergs', 'erg/s/cm^2/Hz/ster'], names=['energy', 'log10jnu']) uvb['logjnu'] = logjnu elif cfg.distance_starburst_kpc is not None: wa, F = read_starburst99(get_data_path() + 'starburst.spectrum1') nu, logjnu = calc_local_jnu(wa, F, cfg.distance_starburst_kpc, cfg.fesc) energy = nu * hplanck / Ryd # use HM uvb energy limits cond = between(uvb['energy'], energy[0], energy[-1]) logjnu1 = np.interp(uvb['energy'][cond], energy, logjnu) uvb['logjnu'][cond] = np.log10(10**uvb['logjnu'][cond] + 10**logjnu1) writetable('cloudy_jnu_total.tbl', [uvb['energy'], uvb['logjnu']], overwrite=1, units=['Rydbergs', 'erg/s/cm^2/Hz/ster'], names=['energy', 'log10jnu']) write_uvb(fluxname, uvb['energy'], uvb['logjnu'], cfg.overwrite) # Fnu at 1 Rydberg k = np.argmin(np.abs(uvb['energy'] - 1.)) logfnu912 = np.log10(10**uvb['logjnu'][k] * 4 * pi) else: logfnu912 = cfg.logfnu912 fluxname = None write_grid_input(cfg, fnu912=logfnu912, fluxfilename=fluxname, table=cfg.table, abundances=cfg.abundances) if cfg.run_cloudy: run_grid(nproc=cfg.nproc, overwrite=cfg.overwrite) models = parse_grid(cfg) filename = cfg.prefix + '_grid.sav.gz' print 'Writing to', filename saveobj(filename, models, overwrite=cfg.overwrite) savehdf5(filename.replace('.sav.gz', '.hdf5'), models, overwrite=cfg.overwrite)
def initvelplot(wa, nfl, ner, nco, transitions, z, fig, atom, ncol, vmin=-1000., vmax=1000., nmodels=0, osc=False, residuals=False): """ Vertical stacked plots of expected positions of absorption lines at the given redshift on a velocity scale.""" colours = ('b', 'r', 'g', 'orangered', 'c', 'purple') ions = [tr['name'].split()[0] for tr in transitions] # want an ordered set ionset = [] for ion in ions: if ion not in ionset: ionset.append(ion) colour = dict(zip(ionset, colours * (len(ions) // len(colours) + 1))) zp1 = z + 1 betamin = vmin / c_kms betamax = vmax / c_kms fig.subplots_adjust(wspace=0.0001, left=0.03, right=0.97, top=0.95, bottom=0.07) axes = [] for i in range(ncol): axes.append(pl.subplot(1, ncol, i + 1)) axes = axes[::-1] for ax in axes: ax.set_autoscale_on(0) # plot top down, so we need reversed() offsets = [] artists = dict(fl=[], er=[], co=[], resid=[], text=[], model=[], models={}, ew=None, regions=[], ticklabels=[], ticks=[], aod=[]) num_per_panel = int(ceil(1 / float(ncol) * len(transitions))) for i, trans in enumerate(reversed(transitions)): tr_id = trans['name'], tuple(trans['tr']) iax, ioff = divmod(i, num_per_panel) ax = axes[iax] ion = trans['name'].split()[0] offset = ioff * 1.5 #print i, offset offsets.append(offset) watrans = trans['wa'] obswa = watrans * zp1 wmin = obswa * (1 + 3 * betamin) wmax = obswa * (1 + 3 * betamax) cond = between(wa, wmin, wmax) #good = ~np.isnan(fl) & (er > 0) & ~np.isnan(co) fl = nfl[cond] #er = ner[cond] co = nco[cond] vel = (wa[cond] / obswa - 1) * c_kms #import pdb; pdb.set_trace() ax.axhline(offset, color='gray', lw=0.5) #artists['er'].extend( # ax.plot(vel, er + offset, lw=1, color='orange', alpha=0.5) ) artists['fl'].extend( ax.plot(vel, fl + offset, color=colour[ion], lw=0.5, ls='steps-mid')) artists['co'].extend( ax.plot(vel, co + offset, color='gray', lw=0.5, ls='dashed')) artists['model'].extend(ax.plot(vel, co + offset, 'k', lw=1, zorder=12)) artists['models'][tr_id] = {} if residuals: artists['resid'].extend( ax.plot([], [], '.', ms=3, mew=0, color='forestgreen')) #ax.axhline(offset-0.1, color='k', lw=0.3) ax.axhline(offset - 0.05, color='k', lw=0.3) ax.axhline(offset - 0.15, color='k', lw=0.3) bbox = dict(facecolor='k', edgecolor='None') transf = mtransforms.blended_transform_factory(ax.transAxes, ax.transData) name = trans['name'] #import pdb; pdb.set_trace() if name.startswith('HI'): ind = indexnear(HIwavs, trans['wa']) lynum = len(HIwavs) - ind name = 'Ly' + str(lynum) + ' ' + name[2:] # find Ly transition number if 'tr' in trans and osc: name = name + ' %.3g' % trans['tr']['osc'] artists['text'].append( ax.text( 0.03, offset + 0.5, name, fontsize=15, #bbox=bbox, transform=transf, zorder=20)) for ax in axes: ax.axvline(0, color='k', lw=0.5, zorder=20) ax.set_xlim(vmin, vmax) ax.set_ylim(-0.5, num_per_panel * 1.5) ax.set_yticks([]) ax.set_xlabel(r'$\Delta v\ \mathrm{(km/s)}$', fontsize=16) artists['title'] = pl.suptitle('$z = %.5f$' % z, fontsize=18) artists['sky'] = [] return artists, np.array(offsets[:num_per_panel]), num_per_panel, axes
def update(self, z): if self.opt.f26 is not None: wa, nfl, ner, nco, model, artists, options = (self.wa, self.nfl, self.ner, self.co, self.model, self.artists, self.opt) else: wa, nfl, ner, nco, artists, options = (self.wa, self.nfl, self.ner, self.co, self.artists, self.opt) self.z = z ymult = self.ymult zp1 = z + 1 betamin = self.vmin / c_kms betamax = self.vmax / c_kms for t in artists['ticklabels']: t.remove() for t in artists['ticks']: t.remove() artists['ticklabels'] = [] artists['ticks'] = [] if artists['ew'] is not None: artists['ew'].remove() artists['ew'] = None for r in artists['regions']: r.remove() for s in artists['sky']: s.remove() for s in artists['aod']: s.remove() artists['regions'] = [] artists['sky'] = [] artists['aod'] = [] # want plots to appear from top down, so we need reversed() for i, trans in enumerate(reversed(options.linelist)): atom, ion = split_trans_name(trans['name'].split()[0]) iax, ioff = divmod(i, self.num_per_panel) ax = self.axes[iax] offset = ioff * 1.5 #if i >= self.num_per_panel: # offset = (i - self.num_per_panel) * 1.5 # ax = self.axes[1] watrans = trans['wa'] obswa = watrans * zp1 wmin = obswa * (1 + 3 * betamin) wmax = obswa * (1 + 3 * betamax) if self.opt.showticks and len(self.allticks) > 0: ticks = self.allticks tickwmin = obswa * (1 + betamin) tickwmax = obswa * (1 + betamax) wticks = ticks.wa cond = between(wticks, tickwmin, tickwmax) if cond.any(): vel = (wticks[cond] / obswa - 1) * c_kms for j, t in enumerate(ticks[cond]): T, Tlabels = plot_tick_vel(ax, vel[j], offset, t, tickz=options.tickz) artists['ticklabels'].extend(Tlabels) artists['ticks'].extend(T) cond = between(wa, wmin, wmax) #good = ~np.isnan(fl) & (er > 0) & ~np.isnan(co) # remove ultra-low S/N regions to help plotting cond &= ner < 1.5 cond &= ymult * (nfl - 1) + 1 > -0.1 fl = nfl[cond] co = nco[cond] vel = (wa[cond] / obswa - 1) * c_kms if options.f26 is not None and options.f26.regions is not None: artists['regions'].extend( plot_velocity_regions(wmin, wmax, options.f26.regions.wmin, options.f26.regions.wmax, obswa, ax, offset, vel, ymult * (fl - 1) + 1)) #import pdb; pdb.set_trace() if hasattr(options, 'aod'): # print ranges used for AOD calculation. # find the right transition c0 = ((np.abs(options.aod['wrest'] - trans['wa']) < 0.01) & (options.aod['atom'] == atom)) itrans = np.flatnonzero(c0) for row in options.aod[itrans]: c0 = between(wa[cond], row['wmin'], row['wmax']) if np.any(c0): artists['aod'].append( ax.fill_between(vel[c0], offset, offset + 1.5, facecolor='0.8', lw=0, zorder=0)) vranges = [] for w0, w1 in unrelated: c0 = between(wa[cond], w0, w1) if c0.any(): vranges.append(c0) for w0, w1 in ATMOS: c0 = between(wa[cond], w0, w1) if c0.any(): artists['sky'].append( ax.fill_between(vel[c0], offset, offset + 1.5, facecolor='0.9', lw=0)) if self.smoothby > 1: if len(fl) > 3 * self.smoothby: fl = convolve_psf(fl, self.smoothby) artists['fl'][i].set_xdata(vel) artists['fl'][i].set_ydata(ymult * (fl - 1) + 1 + offset) artists['co'][i].set_xdata(vel) artists['co'][i].set_ydata(ymult * (co - 1) + 1 + offset) #pdb.set_trace() if self.opt.residuals: resid = (fl - model[cond]) / ner[cond] c0 = np.abs(resid) < 5 artists['resid'][i].set_xdata(vel[c0]) artists['resid'][i].set_ydata(resid[c0] * 0.05 + offset - 0.1) if self.opt.f26 is not None: artists['model'][i].set_xdata(vel) artists['model'][i].set_ydata(ymult * (model[cond] - 1) + 1 + offset) tr_id = trans['name'], tuple(trans['tr']) #import pdb; pdb.set_trace() art = self.artists['models'][tr_id] for line in self.models: m = self.models[line] if line not in art: art[line] = ax.plot(vel, ymult * (m[cond] - 1) + 1 + offset, 'k', lw=0.2)[0] else: art[line].set_xdata(vel) art[line].set_ydata(ymult * (m[cond] - 1) + 1 + offset) for ax in self.axes: ax.set_xlim(self.vmin, self.vmax) ax.set_ylim(-0.5, self.num_per_panel * 1.5) self.artists['title'].set_text('$z = %.5f$' % self.z) if not self.opt.ticklabels: for t in artists['ticklabels']: t.set_visible(False) self.fig.canvas.draw() self.artists = artists
import pylab as plt from astropy.io import fits from barak.utilities import between mag = dict(u=26.8, g=26.08, r=25.9) rmg = mag['r'] - mag['g'] gmu = mag['g'] - mag['u'] fh = fits.open('../magphys/daCunha_UDF/UDF_mags_props_forNeil.fits') d = fh[1].data Rmag = 0.5 * (d.Vmag + d.Imag) Gmag = 0.5 * (d.Bmag + d.Vmag) # ~700 satisfy c0 c0 = between(d.z, 2.3, 2.7) # 38 satisfy c0 and c1. c1 = between(Rmag, mag['r'] - 0.4, mag['r'] + 0.4) Rmag0 = Rmag[c0 & c1] Gmag0 = Gmag[c0 & c1] # could also use Vmag cut instead? #c2 = between(Rmag-d.Vmag, rmg -0.2, rmg + 0.4) d0 = d[c0 & c1] # magphys fitted vals 8.817E+000 9.362E+000 9.727E+000 M16, M50, M84 = 8.817, 9.362, 9.727 # #
def update(self, z): if self.opt.f26 is not None: wa, nfl, ner, nco, model, artists, options = ( self.wa, self.nfl, self.ner, self.co, self.model, self.artists, self.opt) else: wa, nfl, ner, nco, artists, options = ( self.wa, self.nfl, self.ner, self.co, self.artists, self.opt) self.z = z ymult = self.ymult zp1 = z + 1 betamin = self.vmin / c_kms betamax = self.vmax / c_kms for t in artists['ticklabels']: t.remove() for t in artists['ticks']: t.remove() artists['ticklabels'] = [] artists['ticks'] = [] if artists['ew'] is not None: artists['ew'].remove() artists['ew'] = None for r in artists['regions']: r.remove() for s in artists['sky']: s.remove() for s in artists['aod']: s.remove() artists['regions'] = [] artists['sky'] = [] artists['aod'] = [] # want plots to appear from top down, so we need reversed() for i, trans in enumerate(reversed(options.linelist)): atom, ion = split_trans_name(trans['name'].split()[0]) iax, ioff = divmod(i, self.num_per_panel) ax = self.axes[iax] offset = ioff * 1.5 #if i >= self.num_per_panel: # offset = (i - self.num_per_panel) * 1.5 # ax = self.axes[1] watrans = trans['wa'] obswa = watrans * zp1 wmin = obswa * (1 + 3*betamin) wmax = obswa * (1 + 3*betamax) if self.opt.showticks and len(self.allticks) > 0: ticks = self.allticks tickwmin = obswa * (1 + betamin) tickwmax = obswa * (1 + betamax) wticks = ticks.wa cond = between(wticks, tickwmin, tickwmax) if cond.any(): vel = (wticks[cond] / obswa - 1) * c_kms for j,t in enumerate(ticks[cond]): T,Tlabels = plot_tick_vel(ax, vel[j], offset, t, tickz=options.tickz) artists['ticklabels'].extend(Tlabels) artists['ticks'].extend(T) cond = between(wa, wmin, wmax) #good = ~np.isnan(fl) & (er > 0) & ~np.isnan(co) # remove ultra-low S/N regions to help plotting cond &= ner < 1.5 cond &= ymult*(nfl-1) + 1 > -0.1 fl = nfl[cond] co = nco[cond] vel = (wa[cond] / obswa - 1) * c_kms if options.f26 is not None and options.f26.regions is not None: artists['regions'].extend(plot_velocity_regions( wmin, wmax, options.f26.regions.wmin, options.f26.regions.wmax, obswa, ax, offset, vel, ymult*(fl-1) + 1)) #import pdb; pdb.set_trace() if hasattr(options, 'aod'): # print ranges used for AOD calculation. # find the right transition c0 = ((np.abs(options.aod['wrest'] - trans['wa']) < 0.01) & (options.aod['atom'] == atom)) itrans = np.flatnonzero(c0) for row in options.aod[itrans]: c0 = between(wa[cond], row['wmin'], row['wmax']) if np.any(c0): artists['aod'].append( ax.fill_between(vel[c0], offset, offset+1.5, facecolor='0.8', lw=0, zorder=0) ) vranges = [] for w0, w1 in unrelated: c0 = between(wa[cond], w0, w1) if c0.any(): vranges.append(c0) for w0, w1 in ATMOS: c0 = between(wa[cond], w0, w1) if c0.any(): artists['sky'].append( ax.fill_between(vel[c0], offset, offset + 1.5, facecolor='0.9', lw=0)) if self.smoothby > 1: if len(fl) > 3 * self.smoothby: fl = convolve_psf(fl, self.smoothby) artists['fl'][i].set_xdata(vel) artists['fl'][i].set_ydata(ymult*(fl-1) + 1 + offset) artists['co'][i].set_xdata(vel) artists['co'][i].set_ydata(ymult*(co-1) + 1 + offset) #pdb.set_trace() if self.opt.residuals: resid = (fl - model[cond]) / ner[cond] c0 = np.abs(resid) < 5 artists['resid'][i].set_xdata(vel[c0]) artists['resid'][i].set_ydata(resid[c0] * 0.05 + offset - 0.1) if self.opt.f26 is not None: artists['model'][i].set_xdata(vel) artists['model'][i].set_ydata(ymult*(model[cond]-1) + 1 + offset) tr_id = trans['name'], tuple(trans['tr']) #import pdb; pdb.set_trace() art = self.artists['models'][tr_id] for line in self.models: m = self.models[line] if line not in art: art[line] = ax.plot(vel, ymult*(m[cond]-1) + 1 + offset, 'k', lw=0.2)[0] else: art[line].set_xdata(vel) art[line].set_ydata(ymult*(m[cond]-1) + 1 + offset) for ax in self.axes: ax.set_xlim(self.vmin, self.vmax) ax.set_ylim(-0.5, self.num_per_panel * 1.5) self.artists['title'].set_text('$z = %.5f$' % self.z) if not self.opt.ticklabels: for t in artists['ticklabels']: t.set_visible(False) self.fig.canvas.draw() self.artists = artists
if DEBUG: print ' pair cluster z %.3f, sep Mpc %.2f' % ( p['cz'], p['sepMpc_prop']) # check MgII detection range overlaps with cluster z # if not, skip to next cluster if cz < zmin_mg2: continue if cz > zmax_mg2: continue # redshift uncertainty in cluster zmin = max(cz - p['cz_er'], zmin_mg2) zmax = min(cz + p['cz_er'], zmax_mg2) #assert zmax > zmin close_z = between(mg2['z'], zmin, zmax) closeids = mg2['abid'][close_z] nabs = len(closeids) if DEBUG: print ' nMgII', nabs print ' MgII close', mg2[close_z]['z'] print ' ic={:i}, zmin={.3f}, zmax={.3f}'.format( p['ic'], zmin, zmax) raw_input('We have a nearby absorber!') if LOGBINS: ibin = int((p['logsepMpc_prop'] - rbin.edges[0]) / rbin.width[0]) else:
import pylab as plt from astropy.io import fits from barak.utilities import between mag =dict(u=26.8, g=26.08, r=25.9) rmg = mag['r'] - mag['g'] gmu = mag['g'] - mag['u'] fh = fits.open('../magphys/daCunha_UDF/UDF_mags_props_forNeil.fits') d = fh[1].data Rmag = 0.5*(d.Vmag + d.Imag) Gmag = 0.5*(d.Bmag + d.Vmag) # ~700 satisfy c0 c0 = between(d.z, 2.3, 2.7) # 38 satisfy c0 and c1. c1 = between(Rmag, mag['r'] -0.4, mag['r'] + 0.4) Rmag0 = Rmag[c0&c1] Gmag0 = Gmag[c0&c1] # could also use Vmag cut instead? #c2 = between(Rmag-d.Vmag, rmg -0.2, rmg + 0.4) d0 = d[c0 & c1] # magphys fitted vals 8.817E+000 9.362E+000 9.727E+000 M16, M50, M84 = 8.817, 9.362, 9.727 #
def match_clus_qso(clus, qso, filename=None, rho=MAX_RHO_PROP_MPC): """find all QSO - cluster pairs with impact params < rho. Need fields: clus['ra'], clus['dec'], clus['z'], clus['id'], clus['rlos'] where rlos is the comoving line of sight distance to each cluster qso['ra'], qso['dec'], qso['zmin_MgII'], qso['zmax_MgII'], qso['qid'] rho is in same units as rlos (default assumes Mpc), and is a proper distance """ print 'Matching' iqso = [] iclus = [] zclus = [] zclus_er = [] seps_deg = [] seps_Mpc = [] for i in xrange(len(clus)): # find impact parameter in degrees corresponding to maximum rho in proper Mpc # note rho is a proper distance scalefac = 1. / (1. + clus['z'][i]) comoving_sep = rho / scalefac if not i % 5000: print i, 'of', len(clus), 'maximum rho comoving',\ comoving_sep, 'Mpc' angsep_deg = comoving_sep / clus['rlos'][i] * 180. / np.pi # throw away everything a long way away c0 = between(qso['dec'], clus['dec'][i] - angsep_deg, clus['dec'][i] + angsep_deg) qra = qso['ra'][c0] qdec = qso['dec'][c0] qzmin = qso['zmin_mg2'][c0] qzmax = qso['zmax_mg2'][c0] seps = ang_sep(clus['ra'][i], clus['dec'][i], qra, qdec) # within rho close_angsep = seps < angsep_deg # with a smaller redshift than the b/g qso but large enough # redshift that we could detect MgII close_z = between(clus['z'][i], qzmin, qzmax) c1 = close_angsep & close_z num = c1.sum() #import pdb; pdb.set_trace() iqso.extend(qso['qid'][c0][c1]) iclus.extend([clus['id'][i]] * num) zclus.extend([clus['z'][i]] * num) zclus_er.extend([clus['zer'][i]] * num) seps_deg.extend(seps[c1]) seps_Mpc.extend(np.pi / 180 * clus['rlos'][i] * seps[c1]) seps_Mpc = np.array(seps_Mpc) seps_Mpc_prop = seps_Mpc / (1 + np.array(zclus)) logsepMpc_prop = np.log10(seps_Mpc_prop) logsepMpc_com = np.log10(seps_Mpc) names = ('qid cid sepdeg sepMpc_com sepMpc_prop ' 'logsepMpc_com logsepMpc_prop cz cz_er').split() qnear = np.rec.fromarrays([ iqso, iclus, seps_deg, seps_Mpc, seps_Mpc_prop, logsepMpc_com, logsepMpc_prop, zclus, zclus_er ], names=names) if filename is not None: Table(qnear).write(filename) return qnear
if DEBUG: print ' pair cluster z %.3f, sep Mpc %.2f' % ( p['cz'], p['sepMpc_prop']) # check MgII detection range overlaps with cluster z # if not, skip to next cluster if cz < zmin_mg2: continue if cz > zmax_mg2: continue # redshift uncertainty in cluster zmin = max(cz - p['cz_er'], zmin_mg2) zmax = min(cz + p['cz_er'], zmax_mg2) #assert zmax > zmin close_z = between(mg2['z'], zmin, zmax) closeids = mg2['abid'][close_z] nabs = len(closeids) if DEBUG: print ' nMgII', nabs print ' MgII close', mg2[close_z]['z'] print ' ic={:i}, zmin={.3f}, zmax={.3f}'.format( p['ic'], zmin, zmax) raw_input('We have a nearby absorber!') if LOGBINS: ibin = int( (p['logsepMpc_prop'] - rbin.edges[0]) / rbin.width[0]) else: ibin = int(p['sepMpc_prop'] / rbin.width[0])
def on_keypress_custom(self, event): if event.key == 'right': if self.i == self.n - 1: print 'At the last spectrum.' return self.artists['zlines'] = [] self.get_new_spec(self.i + 1) self.update() elif event.key == 'left': if self.i == 0: print 'At the first spectrum.' return self.artists['zlines'] = [] self.get_new_spec(self.i - 1) self.update() elif event.key == '?': print help elif event.key == 'T': if self.opt.ticklabels: for t in self.artists['ticklabels']: t.set_visible(False) self.opt.ticklabels = False else: self.opt.ticklabels = True x0, x1 = self.ax.get_xlim() for t in self.artists['ticklabels']: if x0 < t.get_position()[0] < x1: t.set_visible(True) self.fig.canvas.draw() elif event.key == ' ' and event.inaxes is not None: print '%.4f %.4f %i' % ( event.xdata, event.ydata, indexnear(self.spec[self.i].wa, event.xdata)) elif event.key == 'm' and event.inaxes is not None: if self.wlim1 is not None: self.artists['mlines'].append(plt.gca().axvline( event.xdata, color='k', alpha=0.3)) plt.draw() w0, w1 = self.wlim1, event.xdata if w0 > w1: w0, w1 = w1, w0 sp = self.spec[self.i] good = between(sp.wa, w0, w1) & (sp.er > 0) & ~np.isnan(sp.fl) fmt1 = 'Median flux {:.3g}, rms {:.2g}, er {:.2g}. {:.2g} A/pix' fmt2 = ('SNR {:.2g}/pix, {:.2g}/A (RMS), {:.2g}/pix, {:.2g}/A ' '(er)') if good.sum() < 2: print 'Too few good pixels in range' self.wlim1 = None return medfl = np.median(sp.fl[good]) stdfl = sp.fl[good].std() meder = np.median(sp.er[good]) pixwidth = np.mean(sp.wa[good][1:] - sp.wa[good][:-1]) mult = sqrt(1. / pixwidth) snr1 = medfl / stdfl snr2 = medfl / meder print fmt1.format(medfl, stdfl, meder, pixwidth) print fmt2.format(snr1, snr1 * mult, snr2, snr2 * mult) self.wlim1 = None else: for l in self.artists['mlines']: try: l.remove() except ValueError: # plot has been removed pass self.artists['mlines'].append(plt.gca().axvline( event.xdata, color='k', alpha=0.3)) plt.draw() self.wlim1 = event.xdata print "press 'm' again..." elif event.key == 'C': # fit dodgy continuum sp = self.spec[self.i] co = barak.spec.find_cont(sp.fl) temp, = plt.gca().plot(sp.wa, co, 'm') plt.draw() c = raw_input('Accept continuum? (y) ') if (c + ' ').lower()[0] != 'n': print 'Accepted' sp.co = co self.update() else: temp.remove() elif event.key == 'B' and event.inaxes is not None: # print fitting region wa = event.xdata if self.prev_wa != None: wmin = self.prev_wa wmax = wa if wmin > wmax: wmin, wmax = wmax, wmin print '%%%% %s 1 %.3f %.3f vsig=x.x' % (self.filenames[self.i], wmin, wmax) self.prev_wa = None else: self.prev_wa = wa elif event.key == 'h' and event.inaxes is not None: # print HI line wa = event.xdata z = wa / 1215.6701 - 1 print '%-6s %8.6f 0.0 %3.0f 0.0 %4.1f 0.0' % ('HI', z, 20, 14.0) elif event.key == 'E': # overplot a template c = '0' while c not in '1234': c = raw_input("""\ 1: LBG 2: QSO 3: LRG 4: Starburst galaxy """) temp = get_SEDs('LBG', 'lbg_em.dat') temp.redshift_to(self.zp1 - 1) self.twa = temp.wa self.tfl = temp.fl self.update()
def update(self, z): if self.opt.f26 is not None: wa, nfl, ner, nco, model, artists, options = ( self.wa, self.nfl, self.ner, self.co, self.model, self.artists, self.opt) else: wa, nfl, ner, nco, artists, options = ( self.wa, self.nfl, self.ner, self.co, self.artists, self.opt) self.z = z zp1 = z + 1 betamin = self.vmin / c_kms betamax = self.vmax / c_kms for t in artists['ticklabels']: t.remove() for t in artists['ticks']: t.remove() artists['ticklabels'] = [] artists['ticks'] = [] if artists['ew'] is not None: artists['ew'].remove() artists['ew'] = None for r in artists['regions']: r.remove() for s in artists['sky']: s.remove() artists['regions'] = [] artists['sky'] = [] # want plots to appear from top down, so we need reversed() for i, trans in enumerate(reversed(options.linelist)): ax = self.axes[0] offset = i * 1.5 if i >= self.num_per_panel: offset = (i - self.num_per_panel) * 1.5 ax = self.axes[1] watrans = trans['wa'] obswa = watrans * zp1 wmin = obswa * (1 + 3*betamin) wmax = obswa * (1 + 3*betamax) if self.opt.showticks and len(self.allticks) > 0: ticks = self.allticks tickwmin = obswa * (1 + betamin) tickwmax = obswa * (1 + betamax) wticks = ticks.wa cond = between(wticks, tickwmin, tickwmax) if cond.any(): vel = (wticks[cond] / obswa - 1) * c_kms for j,t in enumerate(ticks[cond]): T,Tlabels = plot_tick_vel(ax, vel[j], offset, t, tickz=options.tickz) artists['ticklabels'].extend(Tlabels) artists['ticks'].extend(T) if options.f26 is not None and options.f26.regions is not None: artists['regions'].extend(plot_velocity_regions( wmin, wmax, options.f26.regions.wmin, options.f26.regions.wmax, obswa, ax, offset)) cond = between(wa, wmin, wmax) #good = ~np.isnan(fl) & (er > 0) & ~np.isnan(co) # remove ultra-low S/N regions to help plotting cond &= ner < 1.5 fl = nfl[cond] co = nco[cond] vel = (wa[cond] / obswa - 1) * c_kms vranges = [] for w0, w1 in unrelated: c0 = between(wa[cond], w0, w1) if c0.any(): vranges.append(c0) for w0, w1 in ATMOS: c0 = between(wa[cond], w0, w1) if c0.any(): artists['sky'].append( ax.fill_between(vel[c0], offset, offset + 1.5, facecolor='0.9', lw=0)) if self.smoothby > 1: if len(fl) > 3 * self.smoothby: fl = convolve_psf(fl, self.smoothby) artists['fl'][i].set_xdata(vel) artists['fl'][i].set_ydata(fl + offset) artists['co'][i].set_xdata(vel) artists['co'][i].set_ydata(co + offset) #pdb.set_trace() if self.opt.residuals: resid = (fl - model[cond]) / ner[cond] c0 = np.abs(resid) < 5 artists['resid'][i].set_xdata(vel[c0]) artists['resid'][i].set_ydata(resid[c0] * 0.05 + offset - 0.1) if self.opt.f26 is not None: artists['model'][i].set_xdata(vel) artists['model'][i].set_ydata(model[cond] + offset) for ax in self.axes: ax.set_xlim(self.vmin, self.vmax) ax.set_ylim(-0.5, self.num_per_panel * 1.5) self.artists['title'].set_text('$z = %.5f$' % self.z) if not self.opt.ticklabels: for t in artists['ticklabels']: t.set_visible(False) self.fig.canvas.draw() self.artists = artists
regions = vp.regions isort = regions.wmin.argsort() print 'Applying continuum adjustments for', len(adjust), 'regions' for val in adjust: wav0 = ATOMDAT['<>'].wa[0] * (1 + val['z']) i0 = regions.wmin[isort].searchsorted(wav0) i1 = regions.wmax[isort].searchsorted(wav0) #print i0, i1 #import pdb; pdb.set_trace() assert i0 - 1 == i1 linterm = val['b'] level = val['logN'] wa0 = regions.wmin[isort[i0 - 1]] - expand_cont_adjustment wa1 = regions.wmax[isort[i1]] + expand_cont_adjustment c0 = between(sp.wa, wa0, wa1) mult = level + linterm * (sp.wa[c0] / wav0 - 1) sp.co[c0] = sp.co[c0] * mult if 1: fig, AX = get_fig_axes(10, 2, len(transitions), aspect=0.24, width=6.3) #fig,AX = get_fig_axes(7, 2, len(transitions), aspect=0.26, width=6.3) fig.subplots_adjust(hspace=1e-5, wspace=1e-5, bottom=0.06, right=0.99, left=0.08, top=0.97) label = [] for tr in transitions:
def make_plot(sp, transitions, model, models, ticks, opt, width=None, height=None, aspect=0.5, textloc='lower left', unrelated=[], cols=None, flw=0.5, mlw=0.5, nrows=None, ncols=None, unrelated_alpha=0.5, trans_fontsize='medium', zerovel_lw=0.5, tlw=1): """ Parameters ---------- cols : dict An optional dictionary of colours. The keys 'data', 'resid', 'ticks' and 'model' can be defined. """ if cols is None: cols = {} if 'data' not in cols: cols['data'] = None if 'resid' not in cols: cols['resid'] = 'g' if 'model' not in cols: cols['model'] = 'r' if 'ticks' not in cols: cols['ticks'] = 'b' wa = sp.wa wextra = np.diff(wa)[0] * 2 nfl = sp.fl / sp.co ner = sp.er / sp.co if opt.f26name is not None: resid = (nfl - model) / ner # actual plotting ntrans = len(transitions) if None in (nrows, ncols): nrows, ncols = get_nrows_ncols(ntrans) assert ntrans <= nrows*ncols fig, vplot = get_fig_axes(nrows, ncols, ntrans, width=width, height=height, aspect=aspect) colour = get_colours(transitions) zp1 = opt.redshift + 1 vmax = opt.vmax if opt.vmin is None: vmin = -abs(vmax) else: vmin = opt.vmin betamin = vmin / c_kms betamax = vmax / c_kms fig.subplots_adjust(left=0.05, right=0.99, bottom=0.07, top=0.99, wspace=0.0001, hspace=0.00001) # plot top down, so we need reversed() for i,trans in enumerate(transitions): ax = vplot.axes[i] ion = trans[0].split()[0] watrans = trans[1][0] obswa = watrans * zp1 wmin = obswa * (1 - 3*abs(betamin)) wmax = obswa * (1 + 3*abs(betamax)) cond = between(wa, wmin, wmax) wa1 = wa[cond] fl = nfl[cond] vel = (wa1 / obswa - 1) * c_kms ax.axhline(0, color='gray', lw=0.5) c = cols['data'] if c is None: c = colour[ion] ax.plot(vel, fl, color=c, lw=flw, ls='steps-mid') for w0,w1 in unrelated: c0 = between(wa1, w0, w1) c1 = between(wa1, w0-wextra, w1+wextra) if c0.any(): ax.plot(vel[c0], fl[c0], 'w', lw=flw+2, ls='-', drawstyle='steps-mid') #ax.plot(vel[c0], fl[c0], '--', lw=flw, color=c, # drawstyle='steps-mid') ax.plot(vel[c1], fl[c1], '-', lw=flw, color=c, alpha=unrelated_alpha, drawstyle='steps-mid') ax.axhline(1, color='gray', lw=0.5, ls='dashed', zorder=3) for m in models: ax.plot(vel, m[cond], cols['model'], lw=0.2) if opt.f26name is not None: if opt.modelfill: ax.fill_between(vel, model[cond], 1, lw=0, color=cols['model'], alpha=0.4, zorder=0) else: ax.plot(vel, model[cond], cols['model'], lw=mlw) for w0,w1 in unrelated: c0 = between(wa1, w0, w1) if c0.any(): ax.plot(vel[c0], model[cond][c0], 'w', lw=flw+2, ls=':') if opt.residuals and opt.f26name is not None: mult = 0.05 offset = -0.2 ax.scatter(vel, offset + mult*resid[cond], marker='.', s=5, faceted=False, c=cols['resid']) ax.axhline(offset - mult, color='0.5', lw=0.3) ax.axhline(offset + mult, color='0.5', lw=0.3) if len(ticks) > 0: tickwmin = obswa * (1 + betamin) tickwmax = obswa * (1 + betamax) wticks = ticks.wa cond = between(wticks, tickwmin, tickwmax) if cond.any(): # should really check ion name here too... c0 = np.abs(trans[1][0] - ticks.wa0[cond]) < 1e-2 vel = (wticks[cond][c0] / obswa - 1) * c_kms #import pdb; pdb.set_trace() for j,t in enumerate(ticks[cond][c0]): T = plot_tick_vel(ax, vel[j], 0, t, lw=tlw, col=cols['ticks']) vel = (wticks[cond][~c0] / obswa - 1) * c_kms for j,t in enumerate(ticks[cond][~c0]): T = plot_tick_vel(ax, vel[j], 0, t, lw=tlw, col=cols['ticks'], ls=':') #bbox = dict(facecolor='w', edgecolor='None') transf = mtransforms.blended_transform_factory( ax.transAxes, ax.transData) name = trans[0] if opt.osc: name = name + ' %.3g' % trans[1]['osc'] if textloc == 'lower left': ax.text(0.03, 0.02, name, fontsize=trans_fontsize, transform=transf) # bbox=bbox, elif textloc =='upper right': puttext(0.97, 0.97, name, ax, fontsize=trans_fontsize, va='top', ha='right') # bbox=bbox, #ax.text(0.98, 0.02, name, ha='right', fontsize=13, transform=transf) # bbox=bbox, for i,ax in enumerate(vplot.axes): ax.axvline(0, color='0.7', lw=zerovel_lw, zorder=0) ax.set_xlim(vmin, vmax) ax.set_ylim(-0.49, 1.49) return fig, vplot
def initvelplot(wa, nfl, ner, nco, transitions, z, fig, atom, vmin=-1000., vmax=1000., nmodels=0, osc=False, residuals=False): """ Vertical stacked plots of expected positions of absorption lines at the given redshift on a velocity scale.""" colours = ('b', 'r', 'g', 'orangered', 'c', 'purple') ions = [tr['name'].split()[0] for tr in transitions] # want an ordered set ionset = [] for ion in ions: if ion not in ionset: ionset.append(ion) colour = dict(zip(ionset, colours * (len(ions) // len(colours) + 1))) zp1 = z + 1 betamin = vmin / c_kms betamax = vmax / c_kms fig.subplots_adjust(wspace=0.0001, left=0.03, right=0.97, top=0.95, bottom=0.07) ax1 = pl.subplot(122) ax2 = pl.subplot(121) axes = [ax1, ax2] for ax in axes: ax.set_autoscale_on(0) # plot top down, so we need reversed() offsets = [] artists = dict(fl=[], er=[], co=[], resid=[], text=[], model=[], models=[], ew=None, regions=[], ticklabels=[], ticks=[]) num_per_panel = int(ceil(0.5 * len(transitions))) for i, trans in enumerate(reversed(transitions)): ax = ax1 if i >= num_per_panel: i -= num_per_panel ax = ax2 ion = trans['name'].split()[0] offset = i * 1.5 #print i, offset offsets.append(offset) watrans = trans['wa'] obswa = watrans * zp1 wmin = obswa * (1 + 3 * betamin) wmax = obswa * (1 + 3 * betamax) cond = between(wa, wmin, wmax) #good = ~np.isnan(fl) & (er > 0) & ~np.isnan(co) fl = nfl[cond] #er = ner[cond] co = nco[cond] vel = (wa[cond] / obswa - 1) * c_kms #import pdb; pdb.set_trace() ax.axhline(offset, color='gray', lw=0.5) #artists['er'].extend( # ax.plot(vel, er + offset, lw=1, color='orange', alpha=0.5) ) artists['fl'].extend( ax.plot(vel, fl + offset, color=colour[ion], lw=0.5, ls='steps-mid')) artists['co'].extend( ax.plot(vel, co + offset, color='gray', lw=0.5, ls='dashed')) if nmodels > 0: artists['models'].append([ax.plot(vel, co + offset, 'k', lw=0.2)[0] for j in range(nmodels)]) artists['model'].extend( ax.plot(vel, co + offset, 'k', lw=0.5, zorder=12)) if residuals: artists['resid'].extend( ax.plot([], [], '.', ms=3, mew=0, alpha=0.4, color='forestgreen')) #ax.axhline(offset-0.1, color='k', lw=0.3) ax.axhline(offset - 0.05, color='k', lw=0.3) ax.axhline(offset - 0.15, color='k', lw=0.3) bbox = dict(facecolor='k', edgecolor='None') transf = mtransforms.blended_transform_factory( ax.transAxes, ax.transData) name = trans['name'] if 'tr' in trans and osc: name = name + ' %.3g' % trans['tr']['osc'] artists['text'].append( ax.text(0.03, offset + 0.5, name, fontsize=15, #bbox=bbox, transform=transf, zorder=20)) for ax in axes: ax.axvline(0, color='k', lw=0.5, zorder=20) ax.set_xlim(vmin, vmax) ax.set_ylim(-0.5, num_per_panel * 1.5) ax.set_yticks([]) ax.set_xlabel('Velocity offset (km s$^{-1}$)', fontsize=16) artists['title'] = pl.suptitle('$z = %.5f$' % z, fontsize=18) artists['sky'] = [] return artists, np.array(offsets[:num_per_panel]), num_per_panel, axes
def match_clus_qso(clus, qso, filename=None, rho=MAX_RHO_PROP_MPC): """find all QSO - cluster pairs with impact params < rho. Need fields: clus['ra'], clus['dec'], clus['z'], clus['id'], clus['rlos'] where rlos is the comoving line of sight distance to each cluster qso['ra'], qso['dec'], qso['zmin_MgII'], qso['zmax_MgII'], qso['qid'] rho is in same units as rlos (default assumes Mpc), and is a proper distance """ print 'Matching' iqso = [] iclus = [] zclus = [] zclus_er = [] seps_deg = [] seps_Mpc = [] for i in xrange(len(clus)): # find impact parameter in degrees corresponding to maximum rho in proper Mpc # note rho is a proper distance scalefac = 1. / (1. + clus['z'][i]) comoving_sep = rho / scalefac if not i % 5000: print i, 'of', len(clus), 'maximum rho comoving',\ comoving_sep, 'Mpc' angsep_deg = comoving_sep / clus['rlos'][i] * 180. / np.pi # throw away everything a long way away c0 = between(qso['dec'], clus['dec'][i] - angsep_deg, clus['dec'][i] + angsep_deg) qra = qso['ra'][c0] qdec = qso['dec'][c0] qzmin = qso['zmin_mg2'][c0] qzmax = qso['zmax_mg2'][c0] seps = ang_sep(clus['ra'][i], clus['dec'][i], qra, qdec) # within rho close_angsep = seps < angsep_deg # with a smaller redshift than the b/g qso but large enough # redshift that we could detect MgII close_z = between(clus['z'][i], qzmin, qzmax) c1 = close_angsep & close_z num = c1.sum() #import pdb; pdb.set_trace() iqso.extend(qso['qid'][c0][c1]) iclus.extend([clus['id'][i]] * num) zclus.extend([clus['z'][i]] * num) zclus_er.extend([clus['zer'][i]] * num) seps_deg.extend(seps[c1]) seps_Mpc.extend(np.pi / 180 * clus['rlos'][i] * seps[c1]) seps_Mpc = np.array(seps_Mpc) seps_Mpc_prop = seps_Mpc / (1 + np.array(zclus)) logsepMpc_prop = np.log10(seps_Mpc_prop) logsepMpc_com = np.log10(seps_Mpc) names = ('qid cid sepdeg sepMpc_com sepMpc_prop ' 'logsepMpc_com logsepMpc_prop cz cz_er').split() qnear = np.rec.fromarrays( [iqso, iclus, seps_deg, seps_Mpc, seps_Mpc_prop, logsepMpc_com, logsepMpc_prop, zclus, zclus_er], names=names) if filename is not None: Table(qnear).write(filename) return qnear
regions = vp.regions isort = regions.wmin.argsort() print 'Applying continuum adjustments for', len(adjust), 'regions' for val in adjust: wav0 = ATOMDAT['<>'].wa[0] * (1 + val['z']) i0 = regions.wmin[isort].searchsorted(wav0) i1 = regions.wmax[isort].searchsorted(wav0) #print i0, i1 #import pdb; pdb.set_trace() assert i0 - 1 == i1 linterm = val['b'] level = val['logN'] wa0 = regions.wmin[isort[i0 - 1]] - expand_cont_adjustment wa1 = regions.wmax[isort[i1]] + expand_cont_adjustment c0 = between(sp.wa, wa0, wa1) mult = level + linterm * (sp.wa[c0]/wav0 - 1) sp.co[c0] = sp.co[c0] * mult if 1: fig,AX = get_fig_axes(10, 2, len(transitions), aspect=0.24, width=6.3) #fig,AX = get_fig_axes(7, 2, len(transitions), aspect=0.26, width=6.3) fig.subplots_adjust(hspace=1e-5, wspace=1e-5, bottom=0.06, right=0.99, left=0.08, top=0.97) label = [] for tr in transitions: ion,wa = tr[0].split() atom,stage = split_trans_name(ion) if tr[0] == 'HI 926': label.append('H I')
def find_trace(filename, tol=0.002, findtrace=True): """ Given a HIRES raw filename, find a suitable exposure in the archive to use as a trace. """ path = os.path.split(os.path.abspath(__file__))[0] fh = fits.open(filename) hd = fh[0].header echangl = hd['ECHANGL'] xdangl = hd['XDANGL'] binning = hd['BINNING'] dateobs = hd['DATE-OBS'] xdispers = None if 'XDISPERS' in hd: xdispers = hd['XDISPERS'] #import pdb; pdb.set_trace() print('Reading KOA file') KOAfilename = os.path.join(path, 'koa/KOA_HIRES_20150706.fits') koa = Table.read(KOAfilename) print('Finding possible traces') if findtrace: cond = between(koa['echangl'], echangl - tol, echangl + tol) cond &= between(koa['xdangl'], xdangl - tol, xdangl + tol) cond &= koa['binning'] == binning if xdispers is not None: cond &= koa['xdispers'] == xdispers cond &= koa['elaptime'] < 600 isflat = koa['imagetyp'] == 'flatlamp' # don't want a flat unless it has the pinhole decker cond &= ~isflat | (isflat & (koa['deckname'] == 'D5')) # don't want darks or arcs. isdark = (koa['imagetyp'] == 'dark') | (koa['imagetyp'] == 'dark_lamp_on') cond &= ~isdark cond &= (koa['imagetyp'] != 'arclamp') #import pdb; pdb.set_trace() print('{:d} found'.format(cond.sum())) if not cond.sum(): c0 = koa['binning'] == bytes(binning) # find closest 'distance' in echangl xdangle space. dist = np.hypot(echangl - koa['echangl'], xdangl - koa['xdangl']) ind = np.argmin(dist[c0]) import pdb; pdb.set_trace() s = 'XD {:.3g} ECH {:.3g} Closest match: XD {:.3g} ECH {:.3g}'.format( xdangl, echangl, koa[c0]['xdangl'][ind], koa[c0]['echangl'][ind]) raise RuntimeError('None found!\n' + s) print('Finding exposures with the nearest date') koa1 = koa[cond] dates = np.array([int(d.replace('-', '')) for d in koa1['date_obs']]) datediff = np.abs(dates - int(dateobs.replace('-',''))) isort = datediff.argsort() count = 1 outstr = [] retval = [] for k in koa1[isort]: obj = k['object'].lower() if 'flat' in obj or 'dark' in obj: continue outstr.append('%-20s|%s| %s| %s' %( k['object'][:20], k['koaid'], k['ut'], k['deckname'])) retval.append((k['object'].strip(), k['koaid'].strip())) if count == 10: break count +=1 return retval
def on_keypress_custom(self, event): if event.key == 'pagedown': if self.i == self.n - 1: print('At the last spectrum.') return self.artists['zlines'] = [] self.get_new_spec(self.i + 1) self.update() elif event.key == 'pageup': if self.i == 0: print('At the first spectrum.') return self.artists['zlines'] = [] self.get_new_spec(self.i - 1) self.update() elif event.key == '?': print(help) elif event.key == 'T': if self.opt.ticklabels: for t in self.artists['ticklabels']: t.set_visible(False) self.opt.ticklabels = False else: self.opt.ticklabels = True x0, x1 = self.ax.get_xlim() for t in self.artists['ticklabels']: if x0 < t.get_position()[0] < x1: t.set_visible(True) self.fig.canvas.draw() elif event.key == ' ' and event.inaxes is not None: print('%.4f %.4f %i' % ( event.xdata, event.ydata, indexnear(self.spec[self.i].wa, event.xdata))) elif event.key == 'm' and event.inaxes is not None: if self.wlim1 is not None: self.artists['mlines'].append(plt.gca().axvline( event.xdata, color='k', alpha=0.3)) plt.draw() w0, w1 = self.wlim1, event.xdata if w0 > w1: w0, w1 = w1, w0 sp = self.spec[self.i] good = between(sp.wa, w0, w1) & (sp.er > 0) & ~np.isnan(sp.fl) fmt1 = 'Median flux {:.3g}, rms {:.2g}, er {:.2g}. {:.2g} A/pix' fmt2 = ('SNR {:.3g}/pix, {:.3g}/A (RMS), {:.3g}/pix, {:.3g}/A ' '(er)') if good.sum() < 2: print('Too few good pixels in range') self.wlim1 = None return medfl = np.median(sp.fl[good]) stdfl = sp.fl[good].std() meder = np.median(sp.er[good]) pixwidth = np.mean(sp.wa[good][1:] - sp.wa[good][:-1]) mult = sqrt(1. / pixwidth) snr1 = medfl / stdfl snr2 = medfl / meder print(fmt1.format(medfl, stdfl, meder, pixwidth)) print(fmt2.format(snr1, snr1 * mult, snr2, snr2 * mult)) self.wlim1 = None else: for l in self.artists['mlines']: try: l.remove() except ValueError: # plot has been removed pass self.artists['mlines'].append(plt.gca().axvline( event.xdata, color='k', alpha=0.3)) plt.draw() self.wlim1 = event.xdata print("press 'm' again...") elif event.key == 'C': # fit dodgy continuum sp = self.spec[self.i] co = barak.spec.find_cont(sp.fl) temp, = plt.gca().plot(sp.wa, co, 'm') plt.draw() c = raw_input('Accept continuum? (y) ') if (c + ' ').lower()[0] != 'n': print('Accepted') sp.co = co self.update() else: temp.remove() elif event.key == 'B' and event.inaxes is not None: # print fitting region wa = event.xdata if self.prev_wa != None: wmin = self.prev_wa wmax = wa if wmin > wmax: wmin, wmax = wmax, wmin print('%%%% %s 1 %.3f %.3f vsig=x.x' % ( self.filenames[self.i], wmin, wmax)) self.prev_wa = None else: self.prev_wa = wa elif event.key == 'h' and event.inaxes is not None: # print HI line wa = event.xdata z = wa / 1215.6701 - 1 print('%-6s %8.6f 0.0 %3.0f 0.0 %4.1f 0.0' % ('HI', z, 20, 14.0)) elif event.key == 'E': # overplot a template c = '0' while c not in '1234': c = raw_input("""\ 1: LBG 2: QSO 3: LRG 4: Starburst galaxy """) temp = get_SEDs('LBG', 'lbg_em.dat') temp.redshift_to(self.zp1 - 1) self.twa = temp.wa self.tfl = temp.fl self.update() elif event.key == ')': self.ax.set_xlabel('$\mathrm{Wavelength\ (\AA)}$') self.ax.set_ylabel('$F_\lambda\ \mathrm{(arbitrary)}$') self.update()