def fit_spline(x, y, bins=4, estimator=np.median): """ Find a smooth function that approximates `x`, `y`. `bins` is the number of bins into which the sample is split. Returns a function f(x) that approximates y from min(x) to max(x). Notes ----- The sample is split into bins number of sub-samples with evenly spaced x values. The median x and y value within each subsample is measured, and a cubic spline is drawn through these subsample median points. `x` must be sorted lowest -> highest, but need not be evenly spaced. """ x,y = map(np.asarray, (x,y)) good = ~np.isnan(x) good &= ~np.isnan(y) x = x[good] y = y[good] binedges = np.linspace(x.min(), x.max(), bins+1) medvals = [] cbins = [] for x0,x1 in zip(binedges[:-1], binedges[1:]): cond = between(x, x0, x1) if not cond.any(): continue cbins.append(estimator(x[cond])) medvals.append(estimator(y[cond])) if len(cbins) < 3: raise RuntimeError('Too few bins') return AkimaSpline(cbins, medvals)
def editRow(row): gotChoice = False while not gotChoice: utilities.clearScreen() #print(row); input(); quit() print('1) Solution Type: %s' % row[2][1][1]) print('2) Distance: %s' % row[0]) interval = utilities.format_time_string(row[1]) if interval[0] == 'interval': print('3) Time: %s' % interval[1]) else: pass #-> there should be no error from this function # call - the time is guaranteed to be a float. choice = input('Which line do you wish to edit ([r] to return)? ') if choice.lower() == 'r': gotChoice = True elif utilities.isInt(choice) and utilities.between(int(choice), 1, 3): gotChoice = True else: input('%s is not a valid choice: press [ENTER] to continue' % choice) if choice == 'r': return if choice == '3': row[1] = get_time() editRow(row) elif choice == '2': row[0] = get_distance() editRow(row) elif choice == '1': input('rutwro')
def get_row(): choice = input('Which leg? ') if choice == 'q': return(0) if len(choice) > 0 and utilities.isInt(choice): if utilities.between(int(choice), 1, len(result_set)): return(result_set[int(choice) - 1]) else: input('%s is not a valid choice. Press [Enter] to continue (or [q] to quit)' % choice) else: input('You must choose a leg between %d through %d. Press [Enter] to continue (or [q] to quit)' % (1, len(result_set)))
def plotlines(z, ax, atmos=None, lines=None, labels=False, ls="dotted", color="k", trim=False, fontsize=10, **kwargs): """ Draw vertical dotted lines showing expected positions of absorption and emission lines, given a redshift. Parameters ---------- atmos : list of float pairs, or True (None) Regions of atmospheric absorption to plot. If True, it uses an internal list of regions. lines : stuctured array, optional If given, it must be a record array with fields 'name' and 'wa'. Returns the mpl artists representing the lines. """ if lines is None: lines = readtxt(DATAPATH + "linelists/galaxy_lines", names="wa,name,select") else: lines = np.rec.fromrecords([(l["name"], l["wa"]) for l in lines], names="name,wa") autoscale = ax.get_autoscale_on() if autoscale: ax.set_autoscale_on(False) artists = [] w0, w1 = ax.get_xlim() wa = lines.wa * (z + 1) if trim: c0 = between(wa, w0, w1) wa = wa[c0] lines = lines[c0] artists.append(axvlines(wa, ax=ax, ls=ls, color=color, **kwargs)) if labels: for i in range(3): for w, l in zip(wa[i::3], lines[i::3]): if not (w0 < w < w1) and trim: continue # name = l.name + '%.2f' % l.wa name = l.name artists.append( puttext( w, 0.7 + i * 0.08, name, ax, xcoord="data", alpha=1, fontsize=fontsize, rotation=90, ha="right", color=color, ) ) if atmos: if atmos == True: atmos = None artists.append(plotatmos(ax, atmos=atmos)) if autoscale: ax.set_autoscale_on(True) return artists
def update(self): """ Calculates the new continuum, residuals and updates the plots. Updates the following attributes: self.markers self.continuum """ wa,fl,er = (self.spec[key] for key in 'wa fl er'.split()) co = np.empty(len(wa)) co.fill(np.nan) for b0,b1 in zip(self.breaks[:-1], self.breaks[1:]): cpts = [(x,y) for x,y in self.contpoints if b0 <= x <= b1] if len(cpts) == 0: continue spline = AkimaSpline(*zip(*cpts)) i,j = wa.searchsorted([b0,b1]) co[i:j] = spline(wa[i:j]) resid = (fl - co) / er # histogram bins = np.arange(0, 5+0.1, 0.2) w0,w1 = self.fig.axes[1].get_xlim() x,_ = np.histogram(resid[between(wa, w0, w1)], bins=bins) b = np.repeat(bins, 2) X = np.concatenate([[0], np.repeat(x,2), [0]]) Xmax = X.max() X = 0.05 * X / Xmax self.markers['hist_left'].set_data(X, b) self.markers['contpoints'].set_data(zip(*self.contpoints)) nbin = self.nbin self.markers['cont'].set_data(wa[::nbin], co[::nbin]) self.markers['resid'].set_data(wa[::nbin], resid[::nbin]) if self.smoothby is not None: sfl = convolve_psf(fl, self.smoothby) self.art_fl.set_data(wa, sfl) else: self.art_fl.set_data(wa, fl) self.continuum = co saveobj('_knots.sav', self.contpoints, overwrite=True) self.fig.canvas.draw()
def calc_iontau(wa, ion, zp1, logN, b, debug=False, ticks=False, maxdv=1000., label_tau_threshold=0.01, vpad=500., verbose=True): """ Returns tau values at each wavelength for transitions in ion. Parameters ---------- wa : array of floats wavelength array ion : atom.data entry ion entry from readatom output dictionary zp1 : float redshift + 1 logN : float log10(column density in cm**-2) b : float b parameter (km/s). Assumes thermal broadening. maxdv : float (default 1000) For performance reasons, only calculate the Voigt profile for a single line to +/- maxdv. Increase this if you expect DLA-type extended wings. None for no maximum. vpad : float (default 500) Include transitions that are within vpad km/s of either edge of the wavelength array. Returns ------- tau : array of floats Array of optical depth values. """ z = zp1 - 1 if debug: i = int(len(wa)/2) psize = c_kms * (wa[i] - wa[i-1]) / wa[i] print 'approx pixel width %.1f km/s at %.1f Ang' % (psize, wa[i]) #select only ions with redshifted central wavelengths inside wa, #+/- the padding velocity range vpad. obswavs = ion.wa * zp1 wmin = wa[0] * (1 - vpad / c_kms) wmax = wa[-1] * (1 + vpad / c_kms) trans = ion[between(obswavs, wmin, wmax)] if debug: if len(trans) == 0: print 'No transitions found overlapping with wavelength array' tickmarks = [] sumtau = np.zeros_like(wa) i0 = i1 = None for i,(wav0,osc,gam) in enumerate(trans): refwav = wav0 * zp1 dv = (wa - refwav) / refwav * c_kms if maxdv is not None: i0,i1 = dv.searchsorted([-maxdv, maxdv]) tau = calctau(dv[i0:i1], wav0, osc, gam, logN, btemp=b, debug=debug, verbose=verbose) if ticks and tau.max() > label_tau_threshold: tickmarks.append((refwav, z, wav0, i)) sumtau[i0:i1] += tau if ticks: return sumtau, tickmarks else: return sumtau