def plot_lightcurve (self, ccd_id=None, bin_energies=False): # XXX CIAO COPY/PASTE DOES THIS EVEN WORK??? import omega as om from ...bblocks import tt_bblock from ..ciao.data import tight_bounds if ccd_id is None: if len (self.gti) != 1: raise Exception ('must specify ccd_id') ccd_id = list(self.gti.keys())[0] kev = self.events['pi'] * 1e-3 # XXXXXXX vb = om.layout.VBox (2) if kev.size == 0: vb[0] = om.RectPlot() vb[1] = om.RectPlot() tmin = self.gti[ccd_id]['start_dmjd'].min() tmax = self.gti[ccd_id]['stop_dmjd'].max() if np.isnan(tmin): tmin, tmax = -1., 1. emin, emax = -1., 1. rmin, rmax = -1., 1. else: bbinfo = tt_bblock ( self.gti[ccd_id]['start_dmjd'], self.gti[ccd_id]['stop_dmjd'], self.events['dmjd'].sort_values(), intersect_with_bins = True, ) cps = bbinfo.rates / 86400 tmin, tmax = tight_bounds (bbinfo.ledges[0], bbinfo.redges[-1]) emin, emax = tight_bounds (kev.min (), kev.max ()) rmin, rmax = tight_bounds (cps.min (), cps.max ()) vb[0] = om.RectPlot () csp = om.rect.ContinuousSteppedPainter (keyText='%d events' % (self.events.shape[0])) csp.setFloats (np.concatenate ((bbinfo.ledges, bbinfo.redges[-1:])), np.concatenate ((cps, [0]))) vb[0].add (csp) if bin_energies: vb[1] = self._plot_binned_event_energies( bbinfo, energy_scale = 1e-3, dsn = 0 ) else: vb[1] = om.quickXY (self.events['dmjd'], kev, None, lines=0) vb[0].setBounds (tmin, tmax, rmin, rmax) vb[0].setYLabel ('Count rate (ct/s)') vb[0].bpainter.paintLabels = False self._plot_add_gtis (vb[0], ccd_id) vb[1].setBounds (tmin, tmax, emin, emax) vb[1].setLabels ('MJD - %d' % self.mjd0, 'Energy (keV)') self._plot_add_gtis (vb[1], ccd_id) return vb
def demo_divine_figure_2a(): """If I type in the coefficients exactly as printed in the paper, the results at L = 7.2 disagree substantially with what's published in the paper. I've checked my code over and I think everything is working right and typed in correctly, so I suspect that there's a typo in the table of coefficients. If I change the a0 coefficient at L = 7.2 from 6.39 to 5.8, the plot in this figure looks much closer to the original. So that's what I've done. The position of the E > 21 MeV curve at L = 16 is also off compared to the figure in the paper. It is less obvious how to patch up that problem, and it feels less urgent, so I'm not trying to deal with that at the moment. """ import omega as om L = np.array([ 1.09, 1.55, 1.75, 1.90, 2.00, 2.10, 2.40, 2.60, 2.80, 2.85, 3.20, 3.60, 6.2, 7.2, 9.00, 11.0, 12.0, 14.0, 16.0 ]) moment = 4.255 p = om.RectPlot() for E in [0.1, 3., 21]: # Note: ignoring augmented field strength at L > 20 B = moment * L**-3 J = inner_radbelt_e_omnidirectional_integ_flux(moment, L, B, E)[0] ok = np.isfinite(J) p.addXY(L[ok], J[ok], 'E = %.1f' % E) p.setLinLogAxes(False, True) p.setBounds(0, 16, 3e4, 3e9) p.setLabels('McIlwain L', 'Omnidirectional integral flux (cm^-2 s^-1)') return p
def main(): import omega as om from pwkit.ndshow_gtk3 import cycle, view ###xg, yg, grid1 = calculate_dynat(n_pseudo_particles=2048, n_steps=30000) ###xg, yg, grid1 = calculate_fixed(n_pseudo_particles=16384, delta_t=0.00001) ###xg, yg, grid1 = calculate_debug(n_pseudo_particles=4096, n_steps=10000, delta_t=0.00001) ###_, _, grid2 = calculate(delta_t=0.00005) y_bins = 40 y_edges = np.linspace(YMIN, YMAX, y_bins + 1) y_centers = 0.5 * (y_edges[1:] + y_edges[:-1]) yg = y_centers.reshape((-1, 1)) x_bins = 40 x_edges = np.linspace(XMIN, XMAX, x_bins + 1) x_centers = 0.5 * (x_edges[1:] + x_edges[:-1]) xg = x_centers.reshape((1, -1)) rho = np.sqrt(np.log(xg / x0)**2 + np.log(yg / y0)**2) / u0 exact = ((xg * y0 / (x0 * yg))**(1. / (2 * u0 * D0)) * k0(rho * np.sqrt(1 + D0**2 * u0**2) / (np.sqrt(2) * D0)) / (2 * np.pi * D0 * u0**2 * np.sqrt(xg * yg * x0 * y0))) ###grid1 *= np.percentile(exact, 95) / np.percentile(grid1, 95) ###cycle([exact[::-1], grid1[::-1]], yflip=True) view(exact[::-1], yflip=True) p = om.RectPlot() p.addXY(xg, exact[10], 'exact') ###p.addXY(xg, grid1[10], 'mine') p.show()
def plot(self, ispw, amp=True): import omega as om p = om.RectPlot() for iant, ipol in sorted(six.iterkeys(self.antpols)): for this_ispw, isoln in self.antpols[iant, ipol]: if this_ispw != ispw: continue f = self.flags[ipol, :, isoln] w = np.where(~f)[0] if amp: v = np.abs(self.vals[ipol, :, isoln]) else: v = np.angle(self.vals[ipol, :, isoln], deg=True) for s in numutil.slice_around_gaps(w, 1): wsub = w[s] if wsub.size == 0: continue # Should never happen, but eh. lines = (wsub.size > 1) p.addXY(wsub, v[wsub], None, lines=lines, dsn=iant) return p
def summers05_figure_1(): import omega as om alpha_star = 0.16 x_m = 0.35 delta_x = 0.15 R = 8.5e-8 Omega_e = 59941 # = 2 * np.pi * 9540 max_wave_lat = 15 * np.pi / 180 degrees = np.linspace(0.1, 89.9, 100) sinas = np.sin(degrees * np.pi / 180) vb = om.layout.VBox(3) vb[0] = paa = om.RectPlot() vb[1] = pap = om.RectPlot() vb[2] = ppp = om.RectPlot() for kev in 100, 300, 1000, 3000: E = kev / 511. # normalized to mc^2 = 511 keV Daa, Dap, Dpp = compute_local(E, sinas, Omega_e, alpha_star, R, x_m, delta_x, max_wave_lat, 'R', wave_filtering='f', p_scaled=True) paa.addXY(degrees, Daa, str(kev)) pap.addXY(degrees, np.abs(Dap), str(kev)) ppp.addXY(degrees, Dpp, str(kev)) for p in paa, pap, ppp: p.setLinLogAxes(False, True) p.setBounds(0, 90, 1e-8, 0.1) p.setXLabel('Pitch angle (degrees)') paa.setYLabel('D_aa') pap.setYLabel('|D_ap|/p') ppp.setYLabel('D_pp/p^2') return vb
def make_qq_plot(kev, obs, mdl, unit, key_text): """Make a quantile-quantile plot comparing events and a model. *kev* A 1D, sorted array of event energy bins measured in keV. *obs* A 1D array giving the number or rate of events in each bin. *mdl* A 1D array giving the modeled number or rate of events in each bin. *unit* Text describing the unit in which *obs* and *mdl* are measured; will be shown on the plot axes. *key_text* Text describing the quantile-quantile comparison quantity; will be shown on the plot legend. Returns: An :class:`omega.RectPlot` instance. *TODO*: nothing about this is Sherpa-specific. Same goes for some of the plotting routines in :mod:`pkwit.environments.casa.data`; might be reasonable to add a submodule for generic X-ray-y plotting routines. """ import omega as om kev = np.asarray(kev) obs = np.asarray(obs) mdl = np.asarray(mdl) c_obs = np.cumsum(obs) c_mdl = np.cumsum(mdl) mx = max(c_obs[-1], c_mdl[-1]) p = om.RectPlot() p.addXY([0, mx], [0, mx], '1:1') p.addXY(c_mdl, c_obs, key_text) # HACK: this range of numbers is chosen to give reasonable sampling for my # sources, which are typically quite soft. locs = np.array([0, 0.05, 0.08, 0.11, 0.17, 0.3, 0.4, 0.7, 1 ]) * (kev.size - 2) c0 = mx * 1.05 c1 = mx * 1.1 for loc in locs: i0 = int(np.floor(loc)) frac = loc - i0 kevval = (1 - frac) * kev[i0] + frac * kev[i0 + 1] mdlval = (1 - frac) * c_mdl[i0] + frac * c_mdl[i0 + 1] obsval = (1 - frac) * c_obs[i0] + frac * c_obs[i0 + 1] p.addXY([mdlval, mdlval], [c0, c1], '%.2f keV' % kevval, dsn=2) p.addXY([c0, c1], [obsval, obsval], None, dsn=2) p.setLabels('Cumulative model ' + unit, 'Cumulative data ' + unit) p.defaultKeyOverlay.vAlign = 0.3 return p
def phase_plot(df, period, yofs=200, phofs=0., lines=False, errs=True, psf='default', byrot=True): if psf == 'default': psf = om.stamps.Circle elif psf is None: psf = lambda: None df['nrot'] = (df['mjd'] - df['mjd'].min()) / period df['ph'] = (df['nrot'] + phofs) % 1. nmax = int(np.floor(df['nrot'].max())) p = om.RectPlot() nplot = 0 for i in range(nmax + 1): subset = (df['nrot'] >= i) & (df['nrot'] < i + 1) if not subset.any(): continue x = df[subset]['ph'] u = df[subset]['ure'] if byrot: y = df[subset]['re'] + i * yofs else: y = df[subset]['re'] + nplot * yofs if errs: p.addXYErr( x, y, u, None, lines=lines, pointStamp=psf(), ) else: p.addXY( x, y, None, lines=lines, pointStamp=psf(), ) nplot += 1 p.setBounds(-0.05, 1.05) return p
def make_multi_qq_plots(arrays, key_text): """Make a quantile-quantile plot comparing multiple sets of events and models. *arrays* X. *key_text* Text describing the quantile-quantile comparison quantity; will be shown on the plot legend. Returns: An :class:`omega.RectPlot` instance. *TODO*: nothing about this is Sherpa-specific. Same goes for some of the plotting routines in :mod:`pkwit.environments.casa.data`; might be reasonable to add a submodule for generic X-ray-y plotting routines. *TODO*: Some gross code duplication here. """ import omega as om p = om.RectPlot() p.addXY([0, 1.], [0, 1.], '1:1') for index, array in enumerate(arrays): kev, obs, mdl = array c_obs = np.cumsum(obs) c_mdl = np.cumsum(mdl) mx = 0.5 * (c_obs[-1] + c_mdl[-1]) c_obs /= mx c_mdl /= mx p.addXY(c_mdl, c_obs, '%s #%d' % (key_text, index)) # HACK: this range of numbers is chosen to give reasonable sampling for my # sources, which are typically quite soft. # # Note: this reuses the variables from the last loop iteration. locs = np.array([0, 0.05, 0.08, 0.11, 0.17, 0.3, 0.4, 0.7, 1 ]) * (kev.size - 2) c0 = 1.05 c1 = 1.1 for loc in locs: i0 = int(np.floor(loc)) frac = loc - i0 kevval = (1 - frac) * kev[i0] + frac * kev[i0 + 1] mdlval = (1 - frac) * c_mdl[i0] + frac * c_mdl[i0 + 1] obsval = (1 - frac) * c_obs[i0] + frac * c_obs[i0 + 1] p.addXY([mdlval, mdlval], [c0, c1], '%.2f keV' % kevval, dsn=2) p.addXY([c0, c1], [obsval, obsval], None, dsn=2) p.setLabels('Cumulative rescaled model', 'Cumulative rescaled data') p.defaultKeyOverlay.vAlign = 0.3 return p
def snip_plot(df, t0, period, yofs=200, lines=False, errs=True, psf='default', tcol='dmjd', widthfactor=0.5): if psf == 'default': psf = om.stamps.Circle elif psf is None: psf = lambda: None p = om.RectPlot() nplot = 0 tmax = df[tcol].max() width = widthfactor * period tleft = t0 - 0.5 * width while tleft < tmax: subset = (df[tcol] >= tleft) & (df[tcol] < tleft + width) if not subset.any(): tleft += width continue x = df[subset][tcol] - (tleft + 0.5 * width) y = df[subset]['re'] + nplot * yofs u = df[subset]['ure'] if errs: p.addXYErr( x, y, u, None, lines=lines, pointStamp=psf(), ) else: p.addXY( x, y, None, lines=lines, pointStamp=psf(), ) nplot += 1 tleft += width p.setBounds(-0.5 * width, 0.5 * width) return p
def plot_one(plotnum, data, prd): data['n'] = (data['mjd'] - 58404.598) / prd + 0.5 data['ph'] = data['n'] % 1. nmax = int(np.ceil(data['n'].max())) p = om.RectPlot() for i in range(nmax): s = data[(data['n'] >= i) & (data['n'] < i + 1)] # All this junk to avoid connecting over bandpass cal visits t = np.asarray(s.mjd) w = np.where((t[1:] - t[:-1]) > dt_sep_cutoff)[0] if w.size == 0: segments = [s] else: assert w.size == 1 tcut = s.mjd.iloc[w[0]] segments = [s[s.mjd <= tcut], s[s.mjd > tcut]] if colormap is None: for seg in segments: p.addDF(seg[['ph', cmpt, 'u'+cmpt]], None, dsn=i, lines=True, pointStamp=stamp()) else: colormap_value = i / (nmax - 1) color = tuple(colormap(colormap_value)) + (alpha_term,) for seg in segments: p.addDF(seg[['ph', cmpt, 'u'+cmpt]], None, dsn=None, lines=True, pointStamp=stamp(), lineStyle={'color': color}, stampStyle={'color': color}) p.addKeyItem('%.3f hr' % (24 * prd)) for ap in p.bpainter, p.tpainter: ap.everyNthMajor = 2 ap.minorTicks = 2 ap.majorTickScale = 1.7 p.setXLabel('Phase') p.lpainter.majorTickScale = p.rpainter.majorTickScale = 1.7 if plotnum == 0: p.setYLabel('Flux Density(μJy)') else: p.lpainter.paintLabels = False p.defaultKeyOverlay.hAlign = 0.89 p.defaultKeyOverlay.vAlign = 0.04 p.add(TextOverlay(0.05, 0.02, '<span size="xx-large" weight="700">(%s)</span>' % (chr(ord('A') + plotnum)))) p.setBounds(xmin=-0.05, xmax=1.05, ymin=-70, ymax=800) return p
def make_specseq_plot(settings, ii): import omega as om p = om.RectPlot() p.setLinLogAxes(True, False) for icml, cml in enumerate(ii.cmls): spect = ii.spectrum(icml, settings.stokes) p.addXY(ii.freqs, spect, '%.0f' % cml) p.defaultKeyOverlay.hAlign = 0.95 p.setLabels('Frequency (GHz)', 'Flux density (uJy)') return p
def plot(self): import omega as om p = om.RectPlot() dt = (np.asarray(self.times) - self.times[0]) * 24. print 'Base time is', util.jdToFull(self.times[0]) for pol, amps in self.amps.iteritems(): us = self.ampus[pol] p.addXYErr(dt, amps, us, util.polarizationName(pol), lines=False) #p.setBounds (ymin=0) p.setLabels('Relative Time (hr)', 'Flux Density (Jy)') return p
def plot(self, modelx, dlines=False, xmin=None, xmax=None, ymin=None, ymax=None, **kwargs): """Plot the data and model (requires `omega`). This assumes that `data` is 1D and that `mfunc` takes one argument that should be treated as the X variable. """ import omega as om modelx = np.asarray(modelx) if modelx.shape != self.data.shape: raise ValueError('modelx and data arrays must have same shape') modely = self.mfunc(modelx) sigmas = self.invsigma**-1 # TODO: handle invsigma = 0 vb = om.layout.VBox(2) vb.pData = om.quickXYErr(modelx, self.data, sigmas, 'Data', lines=dlines, **kwargs) vb[0] = vb.pData vb[0].addXY(modelx, modely, 'Model') vb[0].setYLabel('Y') vb[0].rebound(False, True) vb[0].setBounds(xmin, xmax, ymin, ymax) vb[1] = vb.pResid = om.RectPlot() vb[1].defaultField.xaxis = vb[1].defaultField.xaxis vb[1].addXYErr(modelx, self.resids, sigmas, None, lines=False) vb[1].setLabels('X', 'Residuals') vb[1].rebound(False, True) # ignore Y values since residuals are on different scale: vb[1].setBounds(xmin, xmax) vb.setWeight(0, 3) return vb
def main(): import time from pwkit.ndshow_gtk3 import view t0 = time.time() x_centers1, grid1 = calculate(delta_t=0.0002) #x_centers2, grid2 = calculate(delta_t=0.00005) elapsed = time.time() - t0 print('Calculated grid(s) in %.1f seconds' % elapsed) xex = np.linspace(0, XMAX, 50) yex = (np.exp(Q) - np.exp(Q * xex)) / (np.exp(Q) - 1) p = om.RectPlot() p.addXY(xex, yex, 'exact') p.addXY(x_centers1, grid1, '0.0002') #p.addXY(x_centers2, grid2, '0.00005') p.defaultKeyOverlay.hAlign = 0.95 p.show()
def _plot_binned_event_energies(self, bbinfo, energy_scale=1., time_key='dmjd', target_max_per_bin=100, **kwargs): import omega as om from scipy.stats.mstats_extras import mjci p = om.RectPlot() time = self.events[time_key] energy = self.events['energy'] * energy_scale for ledge, redge in zip(bbinfo.ledges, bbinfo.redges): subset = self.events[(time >= ledge) & (time < redge)] n = subset.shape[0] if n == 0: continue nbin = max(int(np.floor(n / target_max_per_bin)), 1) subbin_width = (redge - ledge) / nbin for i in range(nbin): t0 = ledge + i * subbin_width t1 = t0 + subbin_width tmid = 0.5 * (t0 + t1) matched = (time >= t0) & (time < t1) subsubset = self.events[matched] if subsubset.shape[0] == 0: continue subsubenergy = energy[matched] med_energy = subsubenergy.median() u_med_energy = mjci(subsubenergy.data, prob=0.5).item() p.addXY([t0, t1], [med_energy, med_energy], None, **kwargs) p.addXY([tmid, tmid], [med_energy - u_med_energy, med_energy + u_med_energy], None, **kwargs) return p
def demo_divine_figure_2b(): import omega as om E = np.logspace(np.log10(0.06), np.log10(35), 64) moment = 4.255 alpha = 0.5 * np.pi p = om.RectPlot() for L in [2, 6.2, 10.5]: # Note: ignoring augmented field strength at L > 20 B = moment * L**-3 p.addXY(E, inner_radbelt_e_integ_intensity(moment, L, B, alpha, E), 'L = %.1f' % L) p.setLinLogAxes(True, True) p.setBounds(0.03, 100., 4000., 3e8) p.defaultKeyOverlay.hAlign = 0.9 p.setLabels('Energy (MeV)', 'Integ. Intensity (cm^-2 s^-1 sr^-1)') return p
def main(): import omega as om xex, yex = exact() #xbvp, ybvp = bvp() xb = np.linspace(0.05, 0.95, 8) yb = np.empty_like(xb) #for i in range(xb.size): # yb[i] = backwards(xb[i]) #xf, yf = forwards_scalar() xf, yf = forwards_vector_fixed_steps() p = om.RectPlot() p.addXY(xex, yex, 'exact') #p.addXY(xbvp, ybvp, 'BVP') #p.addXY(xb, yb, 'backwards', lines=False) p.addXY(xf, yf, 'forwards', lines=False) p.defaultKeyOverlay.hAlign = 0.95 p.show()
def demo_divine_figure_2c(): import omega as om E = 3. # MeV moment = 4.255 alpha = 0.5 * np.pi p = om.RectPlot() for L, lammax in [(2, 40.), (6.2, 65.), (10.5, 70.)]: mlat_deg = np.linspace(0., lammax, 64) mlat_rad = mlat_deg * astutil.D2R # Note: ignoring augmented field strength at L > 20 r = L * np.cos(mlat_rad)**2 B = moment * r**-3 * (1 + 3 * np.sin(mlat_rad)**2)**0.5 p.addXY(mlat_deg, inner_radbelt_e_integ_intensity(moment, L, B, alpha, E), 'L = %.1f' % L) p.setLinLogAxes(False, True) p.setBounds(0, 70, 3e3, 3e7) p.defaultKeyOverlay.hAlign = 0.9 p.setLabels('Mag. Lat (deg)', 'Integ. Intensity (cm^-2 s^-1 sr^-1)') return p
def summarize(): import omega as om alpha_star = 0.16 x_m = 0.35 delta_x = 0.20 R = 8.5e-8 Omega_e = 59941 # = 2 * np.pi * 9540 max_wave_lat = 30 * np.pi / 180 degrees = np.linspace(0.1, 89.9, 100) sinas = np.sin(degrees * np.pi / 180) hb = om.layout.HBox(3) hb[0] = paa = om.RectPlot() hb[1] = pap = om.RectPlot() hb[2] = ppp = om.RectPlot() dmin = dmax = None for kev in 100, 1000, 10000: E = kev / 511. # normalized to mc^2 = 511 keV Daa, Dap, Dpp = compute(E, sinas, Omega_e, alpha_star, R, x_m, delta_x, max_wave_lat, 'R', wave_filtering='f', p_scaled=True, parallel=False) Dap = np.abs(Dap) cmin = min(Daa.min(), Dap.min(), Dpp.min()) cmax = max(Daa.max(), Dap.max(), Dpp.max()) if dmin is None: dmin, dmax = cmin, cmax else: dmin = min(dmin, cmin) dmax = max(dmax, cmax) paa.addXY(degrees, Daa, str(kev)) pap.addXY(degrees, Dap, str(kev)) ppp.addXY(degrees, Dpp, str(kev)) if dmin == 0: dmin = 1e-12 for p in paa, pap, ppp: p.setLinLogAxes(False, True) p.setBounds(0, 90, dmin * 0.8, dmax / 0.8) p.setXLabel('Pitch angle (degrees)') paa.setYLabel('D_aa') pap.setYLabel('|D_ap|/p') ppp.setYLabel('D_pp/p^2') return hb
def plot(): df = photom.load_and_reduce('../target.phot.ll.txt') df['dhr'] = df['dmjd'] * 24 soln = photom.BEST_SOLN toa_nrot, toas = photom.best_toas(df) toa_info = dict(zip(toa_nrot, toas - photom.MJD0)) vb = om.layout.VBox(3) for dday in (0, 1, 2): subset = (df['dmjd'] >= dday) & (df['dmjd'] < (dday + 1)) p = om.RectPlot() # Zero reference line p.addXY( [24 * (DMJD_XMIN + dday), 24 * (DMJD_XMAX + dday)], [0, 0], None, lineStyle = {'dashing': [3, 3], 'color': 'muted'}, dsn = 0 ) # Actual data t = Time(np.median(df[subset]['dmjd']) + photom.MJD0, format='mjd', scale='utc') utdate = t.utc.strftime('%Y %b %d') p.addDF(df[subset][['dhr', 're', 'ure']], f'Day {dday+1} ({utdate} UT)') # Markers for the best-fit pulse ephemeris dmjdmin = DMJD_XMIN + dday nmin = (dmjdmin - soln.t0) / soln.period nmin = int(np.ceil(nmin)) n = nmin while True: dmjd = soln.n_to_mjd(n) - photom.MJD0 if dmjd > DMJD_XMAX + dday: break if n == nmin or n == nmin + PULSES_IN_DAY[dday] - 1: t = f'<span size="larger" weight="700">{n+1}</span>' p.add(XYText(24 * dmjd, 380, t)) toa = toa_info.get(n) if toa is not None: p.addXY( [24 * toa, 24 * toa], [150, 450], None, lineStyle = {'linewidth': 0.5, 'color': (0, 0, 0), 'dashing': [2, 2]}, dsn = 0 ) p.addXY( [24 * dmjd, 24 * dmjd], [250, 350], None, lineStyle = {'linewidth': 3, 'color': (0, 0, 0)}, dsn = 0 ) n += 1 # Labeling etc p.setBounds(24 * (DMJD_XMIN + dday), 24 * (DMJD_XMAX + dday), YMIN, YMAX) p.defaultKeyOverlay.hAlign = 0.97 p.defaultKeyOverlay.vAlign = 0.07 p.bpainter.numFormat = dhr_to_ut p.bpainter.minorTicks = 4 p.add(TextOverlay(0.02, 0.04, '<span size="xx-large" weight="700">(%s)</span>' % (chr(ord('A') + dday))), rebound=False) vb[dday] = p vb[1].setYLabel('Flux density (μJy)') vb[2].setXLabel('Universal Time (UT)') return vb
def snip_page(df, t0, period, lines=False, errs=True, psf='default', tcol='dmjd', widthfactor=0.5): if psf == 'default': psf = om.stamps.Circle elif psf is None: psf = lambda: None pg = om.makeDisplayPager() tmax = df[tcol].max() width = widthfactor * period def gen_data(): tleft = t0 - 0.5 * width while tleft < tmax: subset = (df[tcol] >= tleft) & (df[tcol] < tleft + width) if not subset.any(): tleft += width continue x = df[subset][tcol] - (tleft + 0.5 * width) y = df[subset]['re'] u = df[subset]['ure'] yield x, y, u tleft += width ymin = ymax = None for x, y, u in gen_data(): if ymin is None: ymin = (y - u).min() ymax = (y + u).max() else: ymin = min(ymin, (y - u).min()) ymax = max(ymax, (y + u).max()) height = ymax - ymin if height == 0: height = 0.5 * ymax if height == 0: height = 1 ymax = ymax + 0.05 * height ymin = ymin - 0.05 * height for x, y, u in gen_data(): p = om.RectPlot() if errs: p.addXYErr( x, y, u, None, lines=lines, pointStamp=psf(), ) else: p.addXY( x, y, None, lines=lines, pointStamp=psf(), ) p.setBounds(-0.5 * width, 0.5 * width, ymin, ymax) pg.send(p) pg.done()
def plot_flare_zoom(dphot, plotinfo): from . import data dur = plotinfo.dmjd1 - plotinfo.dmjd0 w = ((dphot.dmjd > plotinfo.dmjd0 - 0.1 * dur) & (dphot.dmjd < plotinfo.dmjd1 + 0.1 * dur)) subset = dphot[w] p = om.RectPlot() med_uncerts = [] max_val = None max_loc = None for icmp, cinfo in enumerate(plotinfo.components): kt1 = cinfo.key if plotinfo.showkey else None med_uncerts.append(subset['u' + cinfo.name].median()) ml = subset[cinfo.name].argmax() if max_val is None or subset[cinfo.name][ml] > max_val: max_val = subset[cinfo.name][ml] max_loc = ml for mask in data.photom_generate_indices(subset): visit = subset.take(mask) venv = om.rect.VEnvelope(kt1) yhi = np.asarray(visit[cinfo.name]) ylo = 0 * yhi w = np.where(ylo > yhi) tmp = ylo[w] ylo[w] = yhi[w] yhi[w] = tmp venv.setFloats(np.asarray(visit.dmjd), ylo, yhi) venv.style = {'color': cinfo.color} p.add(venv) kt1 = None if plotinfo.showkey: p.defaultKeyOverlay.hAlign = 0.05 p.defaultKeyOverlay.vAlign = 0.06 med_uncert = np.median(med_uncerts) p.addXYErr([plotinfo.uncert_loc[0]], [plotinfo.uncert_loc[1]], [med_uncert], None, lineStyle={'color': (0, 0, 0)}, stampStyle={'color': (0, 0, 0)}) p.addHLine(0, None, zheight=-5, lineStyle=plotinfo.refline_style) p.setBounds(plotinfo.dmjd0, plotinfo.dmjd1, *plotinfo.ybounds) tp = om.TextPainter('<big><b>%s</b></big>' % plotinfo.desc) co = p.add(om.rect.AbsoluteFieldOverlay(tp), rebound=False) co.hAlign = 0.95 co.vAlign = 0.05 if plotinfo.paintleft: p.lpainter.everyNthMajor = 3 else: p.lpainter.paintLabels = False for ap in p.bpainter, p.tpainter: ap.autoBumpThreshold = 0 ap.minorTicks = 10 p.bpainter.labelMinorTicks = True p.bpainter.everyNthMinor = 5 for ap in p.lpainter, p.rpainter: ap.minorTicks = 2 if plotinfo.labelleft: p.setYLabel('Flux density(μJy)') if plotinfo.labelbot: mjd0 = np.floor(dphot.mjd.min()) p.setXLabel('MJD - %.0f(day)' % mjd0) # time away from peak top-axis label dmjdpeak = subset.dmjd[max_loc] ds0 = 86400 * (plotinfo.dmjd0 - dmjdpeak) ds1 = 86400 * (plotinfo.dmjd1 - dmjdpeak) p.tpainter.axis = om.rect.LinearAxis(ds0, ds1) p.tpainter.paintLabels = True p.tpainter.autoBumpThreshold = 10. p.tpainter.minorTicks = 4 p.tpainter.everyNthMajor = 2 p.setSideLabel(p.SIDE_TOP, pangosub('t – t{peak}(sec)')) return p
def report(self, cfg): import omega as om import omega.gtk3 from pwkit import ndshow_gtk3 self.all_aps = np.sort(list(self.all_aps)) self.all_bps = sorted(self.all_bps) self.all_times = np.sort(list(self.all_times)) # Antpols by DDID, time: data = [] descs = [] for ddid, stats in self.ap_time_stats_by_ddid.items(): mean, scat = postproc(stats.finish(self.all_times, self.all_aps)) data.append(mean / scat) descs.append('DDID %d' % ddid) print( 'Viewing X axis: antpol; Y axis: time; iteration: DDID (~= spwid) ...' ) ndshow_gtk3.cycle(data, descs, run_main=True) # Antpols by DDID, freq: data = [] descs = [] for ddid, stats in self.ap_spec_stats_by_ddid.items(): mean, scat = postproc(stats.finish(self.all_aps)) data.append(mean / scat) descs.append('DDID %d' % ddid) print('Viewing X axis: frequency; Y axis: antpol; iteration: DDID ...') ndshow_gtk3.cycle(data, descs, run_main=True) # Antpols by DDID p = om.RectPlot() for ddid, stats in self.ap_stats_by_ddid.items(): ok, mean, scat = postproc_mask(stats.finish(self.all_aps)) p.addXYErr( np.arange(len(self.all_aps))[ok], mean, scat, 'DDID %d' % ddid) p.setBounds(-0.5, len(self.all_aps) - 0.5) p.setLabels('Antpol number', 'Mean closure phase (rad)') p.addHLine(0, keyText=None, zheight=-1) print('Viewing everything grouped by antpol ...') p.show() # Basepols by DDID data = [] descs = [] tostatuses = [] def bpgrid_status(pol1, pol2, ants, yx): i, j = [int(_) for _ in np.floor(yx + 0.5)] if i < 0 or j < 0 or i >= ants.size or j >= ants.size: return '' ni = self._getname(ants[i]) nj = self._getname(ants[j]) if i <= j: return '%s-%s %s' % (ni, nj, util.pol_names[pol1]) return '%s-%s %s' % (nj, ni, util.pol_names[pol2]) for ddid, stats in self.bp_stats_by_ddid.items(): mean, scat = postproc(stats.finish(self.all_bps)) nmean = mean / scat pol1, pol2, ants, grid = grid_bp_data(self.all_bps, zip(self.all_bps, nmean)) data.append(grid) descs.append('DDID %d' % ddid) tostatuses.append(lambda yx: bpgrid_status(pol1, pol2, ants, yx)) print('Viewing X axis: antpol1; Y axis: antpol2; iteration: DDID ...') ndshow_gtk3.cycle(data, descs, tostatuses=tostatuses, run_main=True) # Everything by time ok, mean, scat = postproc_mask( self.global_stats_by_time.finish(self.all_times)) stimes = self.all_times[ok] / 86400 st0 = int(np.floor(stimes.min())) stimes -= st0 p = om.quickXYErr(stimes, mean, scat) p.addHLine(0, keyText=None, zheight=-1) p.setLabels('MJD - %d' % st0, 'Mean closure phase (rad)') print('Viewing everything grouped by time ...') p.show()
def debug_toa_analysis( soln, df, toas, weights, nrots=NROT_ALL, widthfactor=0.7, sort='seq', yrange=None, ): # Solve for the period so that we can figure out how to convert the # weights into uncertainties. from pwkit.lsqmdl import PolynomialModel invsigma = weights**0.5 mtoa = toas.mean() ephem = PolynomialModel(1, nrots, toas - mtoa, invsigma).solve() ephem.print_soln() print('T0:', ephem.params[0] + mtoa - MJD0) print('RMS residual:', (ephem.resids**2).mean()**0.5) wtscale = np.sqrt(ephem.rchisq) uncerts = wtscale * weights**-0.5 pg = om.makeDisplayPager() half_inner_width = 0.25 * soln.period * widthfactor if sort == 'seq': sort_idx = np.arange(nrots.size) elif sort == 'resid': sort_idx = np.argsort(ephem.resids) else: raise ValueError(f'unhandled sort {sort!r}') for i in sort_idx: n = nrots[i] sl = soln.slice(df, n, widthfactor=widthfactor) sl['invsigma'] = 1. / sl['ure'] toa = toas[i] mjd = soln.n_to_mjd(n) # Repeat the solution of the baseline flux used to determine # the excess. is_inner = np.abs(sl['dmjd']) < half_inner_width outer = sl[~is_inner] baseline = PolynomialModel( BASELINE_MODEL_POLYNOMIAL_ORDER, outer['dmjd'].values, outer['re'].values, outer['invsigma'].values, ).solve() p = om.RectPlot() # The TOA for this slice with its uncertainty, as determined from its # weight and the RMS of the residuals to the period fit. p.add(om.rect.XBand(toa - uncerts[i], toa + uncerts[i], keyText=None), dsn=0) p.addVLine(toa, keyText='n=%d Centroid TOA' % n, dsn=0) # The actual data. p.addDF(sl[['mjd', 're', 'ure']], dsn=1) # The definitions of the inner/outer windows used for the baseline fit and # excess flux computation. p.addVLine(mjd - half_inner_width, dsn=2, lineStyle={'dashing': [3, 3]}, keyText=None) p.addVLine(mjd + half_inner_width, dsn=2, lineStyle={'dashing': [3, 3]}, keyText=None) # The baseline flux fit bl_dmjd = np.linspace(-2 * half_inner_width, 2 * half_inner_width, 3) p.addXY(bl_dmjd + mjd, baseline.mfunc(bl_dmjd), None, dsn=2) # The new ephemeris fit label = 'New ephem (resid = %.5f = %.1fσ)' % ( ephem.resids[i], ephem.resids[i] / uncerts[i]) mjd_ephem = ephem.mfunc(n) + mtoa p.addVLine(mjd_ephem, dsn=3, keyText=label) if yrange is not None: p.setBounds(ymin=yrange[0], ymax=yrange[1]) p.bpainter.numFormat = '%.8g' pg.send(p) pg.done() return ephem
def plot (self): if isinstance (self.cfg.out, omega.render.Pager): # This is for non-CLI invocation. pager = self.cfg.out elif self.cfg.out is None: from omega import gtk3 pager = om.makeDisplayPager () else: pager = om.makePager (self.cfg.out, dims=self.cfg.dims, margins=self.cfg.margins, style=om.styles.ColorOnWhiteVector ()) # Collect the data as loaded skeys = sorted (six.viewkeys (self.results)) normalized = {} spws = set () polns = set () for antnum, antname in enumerate (self.antnames): for key in skeys: spw, poln, time = key gc = self.results[key] idx = gc.ant_to_antidx.get (antnum) if idx is None: continue samps, otherant = gc.get_normalized (idx) bysp = normalized.setdefault (antname, {}) bytime = bysp.setdefault ((spw, poln), {}) bytime[time] = (samps, otherant) polns.add (poln) spws.add (spw) spws = sorted (spws) polns = sorted (polns) spwseq = dict ((s, i) for (i, s) in enumerate (spws)) polnseq = dict ((p, i) for (i, p) in enumerate (polns)) # Group by time and get dims rmin = rmax = imin = imax = amin = amax = None for antname, bysp in six.viewitems (normalized): for spwpol in list (six.viewkeys (bysp)): bytime = bysp[spwpol] times = sorted (six.viewkeys (bytime)) samps = np.concatenate (tuple (bytime[t][0] for t in times)) otherants = np.concatenate (tuple (bytime[t][1] for t in times)) logamps = np.log10 (np.abs (samps)) bysp[spwpol] = samps, otherants, logamps if rmin is None: rmin = samps.real.min () rmax = samps.real.max () imin = samps.imag.min () imax = samps.imag.max () amin = logamps.min () amax = logamps.max () else: rmin = min (rmin, samps.real.min ()) rmax = max (rmax, samps.real.max ()) imin = min (imin, samps.imag.min ()) imax = max (imax, samps.imag.max ()) amin = min (amin, logamps.min ()) amax = max (amax, logamps.max ()) # Square things up in the real/imag plot and add little margins rrange = rmax - rmin irange = imax - imin arange = amax - amin if rrange < irange: delta = 0.5 * (irange - rrange) rmax += delta rmin -= delta rrange = irange else: delta = 0.5 * (rrange - irange) imax += delta imin -= delta irange = rrange rmax += 0.05 * rrange rmin -= 0.05 * rrange imax += 0.05 * irange imin -= 0.05 * irange amax += 0.05 * arange amin -= 0.05 * arange # Info for overplotted cumulative histogram of log-ampls def getlogamps (): for bysp in six.viewvalues (normalized): for samps, otherant, logamp in six.viewvalues (bysp): yield logamp all_log_amps = np.concatenate (tuple (getlogamps ())) all_log_amps.sort () all_log_amps_x = np.linspace (0., len (self.antnames), all_log_amps.size) all_log_amps_bounds = scoreatpercentile (all_log_amps, [2.5, 97.5]) # Actually plot for antname in self.antnames: bysp = normalized.get (antname) if bysp is None: continue # no data reim = om.RectPlot () reim.addKeyItem (antname) reim.addHLine (0, keyText=None, zheight=-2, dsn=0, lineStyle={'color': (0,0,0), 'dashing': (2, 2)}) reim.addVLine (1, keyText=None, zheight=-2, dsn=0, lineStyle={'color': (0,0,0), 'dashing': (2, 2)}) loga = om.RectPlot () loga.addHLine (0, keyText=None, zheight=-2, dsn=0, lineStyle={'color': (0,0,0), 'dashing': (2, 2)}) loga.addXY (all_log_amps_x, all_log_amps, None, lineStyle={'color': (0,0,0)}) for a in all_log_amps_bounds: loga.addHLine (a, keyText=None, zheight=-2, dsn=0, lineStyle={'color': (0,0,0), 'dashing': (1, 3)}) for (spw, poln), (samps, otherant, logamp) in six.viewitems (bysp): # Real/imag plot ms = om.stamps.MultiStamp ('cnum', 'shape', 'tlines') ms.fixedsize = 4 ms.fixedlinestyle = {'color': 'muted'} cnum = np.zeros (samps.size, dtype=np.int) cnum.fill (spwseq[spw]) shape = np.zeros_like (cnum) shape.fill (polnseq[poln]) dp = om.rect.XYDataPainter (lines=False, pointStamp=ms, keyText=None) dp.setInts (cnum, shape, otherant + 1) dp.setFloats (samps.real, samps.imag) reim.add (dp) # Log-amplitudes plot ms = om.stamps.MultiStamp ('cnum', 'shape', 'tlines') ms.fixedsize = 4 ms.fixedlinestyle = {'color': 'muted'} cnum = np.zeros (samps.size, dtype=np.int) cnum.fill (spwseq[spw]) shape = np.zeros_like (cnum) shape.fill (polnseq[poln]) dp = om.rect.XYDataPainter (lines=False, pointStamp=ms, keyText=None) dp.setInts (cnum, shape, otherant + 1) dp.setFloats (otherant, np.log10 (np.abs (samps))) loga.add (dp) for spw in spws: for poln in polns: s = EmulatedMultiStamp (polnseq[poln], spwseq[spw], 4) reim.addKeyItem (ManualStampKeyPainter ('spw#%d %s' % (spw, poln), s)) reim.setLabels ('Normalized real part', 'Normalized imaginary part') reim.setBounds (rmin, rmax, imin, imax) # Unfortunately this is not compatible with VBox layout right now. #reim.fieldAspect = 1. loga.setLabels ('Paired antenna number', 'Log10 amplitude ratio') loga.setBounds (-0.5, len (self.antnames) + 0.5, amin, amax) vb = om.layout.VBox (2) vb[0] = reim vb[1] = loga vb.setWeight (0, 3) pager.send (vb) pager.done ()
def make_spectrum_plot(model_plot, data_plot, desc, xmin_clamp=0.01, min_valid_x=None, max_valid_x=None): """Make a plot of a spectral model and data. *model_plot* A model plot object returned by Sherpa from a call like `ui.get_model_plot()` or `ui.get_bkg_model_plot()`. *data_plot* A data plot object returned by Sherpa from a call like `ui.get_source_plot()` or `ui.get_bkg_plot()`. *desc* Text describing the origin of the data; will be shown in the plot legend (with "Model" and "Data" appended). *xmin_clamp* The smallest "x" (energy axis) value that will be plotted; default is 0.01. This is needed to allow the plot to be shown on a logarithmic scale if the energy axes of the model go all the way to 0. *min_valid_x* Either None, or the smallest "x" (energy axis) value in which the model and data are valid; this could correspond to a range specified in the "notice" command during analysis. If specified, a gray band will be added to the plot showing the invalidated regions. *max_valid_x* Like *min_valid_x* but for the largest "x" (energy axis) value in which the model and data are valid. Returns: A tuple ``(plot, xlow, xhigh)``, where *plot* an OmegaPlot RectPlot instance, *xlow* is the left edge of the plot bounds, and *xhigh* is the right edge of the plot bounds. """ import omega as om model_x = np.concatenate((model_plot.xlo, [model_plot.xhi[-1]])) model_x[0] = max(model_x[0], xmin_clamp) model_y = np.concatenate((model_plot.y, [0.])) # Sigh, sometimes Sherpa gives us bad values. is_bad = ~np.isfinite(model_y) if is_bad.sum(): from .cli import warn warn('bad Sherpa model Y value(s) at: %r', np.where(is_bad)[0]) model_y[is_bad] = 0 data_left_edges = data_plot.x - 0.5 * data_plot.xerr data_left_edges[0] = max(data_left_edges[0], xmin_clamp) data_hist_x = np.concatenate( (data_left_edges, [data_plot.x[-1] + 0.5 * data_plot.xerr[-1]])) data_hist_y = np.concatenate((data_plot.y, [0.])) log_bounds_pad_factor = 0.9 xlow = model_x[0] * log_bounds_pad_factor xhigh = model_x[-1] / log_bounds_pad_factor p = om.RectPlot() if min_valid_x is not None: p.add(om.rect.XBand(1e-3 * xlow, min_valid_x, keyText=None), zheight=-1, dsn=1) if max_valid_x is not None: p.add(om.rect.XBand(max_valid_x, xhigh * 1e3, keyText=None), zheight=-1, dsn=1) csp = om.rect.ContinuousSteppedPainter(keyText=desc + ' Model') csp.setFloats(model_x, model_y) p.add(csp) csp = om.rect.ContinuousSteppedPainter(keyText=None) csp.setFloats(data_hist_x, data_hist_y) p.add(csp) p.addXYErr(data_plot.x, data_plot.y, data_plot.yerr, desc + ' Data', lines=0, dsn=1) p.setLabels(data_plot.xlabel, data_plot.ylabel) p.setLinLogAxes(True, False) p.setBounds(xlow, xhigh) return p, xlow, xhigh
def make_multi_spectrum_plots(model_plot, plotids, data_getter, desc, xmin_clamp=0.01, min_valid_x=None, max_valid_x=None): """Make a plot of multiple spectral models and data. *model_plot* A model plot object returned by Sherpa from a call like ``ui.get_model_plot()`` or ``ui.get_bkg_model_plot()``. *data_plots* An iterable of data plot objects returned by Sherpa from calls like ``ui.get_source_plot(id)`` or ``ui.get_bkg_plot(id)``. *desc* Text describing the origin of the data; will be shown in the plot legend (with "Model" and "Data #<number>" appended). *xmin_clamp* The smallest "x" (energy axis) value that will be plotted; default is 0.01. This is needed to allow the plot to be shown on a logarithmic scale if the energy axes of the model go all the way to 0. *min_valid_x* Either None, or the smallest "x" (energy axis) value in which the model and data are valid; this could correspond to a range specified in the "notice" command during analysis. If specified, a gray band will be added to the plot showing the invalidated regions. *max_valid_x* Like *min_valid_x* but for the largest "x" (energy axis) value in which the model and data are valid. Returns: A tuple ``(plot, xlow, xhigh)``, where *plot* an OmegaPlot RectPlot instance, *xlow* is the left edge of the plot bounds, and *xhigh* is the right edge of the plot bounds. TODO: not happy about the code duplication with :func:`make_spectrum_plot` but here we are. """ import omega as om from omega.stamps import DataThemedStamp, WithYErrorBars model_x = np.concatenate((model_plot.xlo, [model_plot.xhi[-1]])) model_x[0] = max(model_x[0], xmin_clamp) model_y = np.concatenate((model_plot.y, [0.])) # Sigh, sometimes Sherpa gives us bad values. is_bad = ~np.isfinite(model_y) if is_bad.sum(): from .cli import warn warn('bad Sherpa model Y value(s) at: %r', np.where(is_bad)[0]) model_y[is_bad] = 0 p = om.RectPlot() data_csps = [] data_lines = [] xlow = xhigh = None for index, plotid in enumerate(plotids): data_plot = data_getter(plotid) data_left_edges = data_plot.x - 0.5 * data_plot.xerr data_left_edges[0] = max(data_left_edges[0], xmin_clamp) data_hist_x = np.concatenate( (data_left_edges, [data_plot.x[-1] + 0.5 * data_plot.xerr[-1]])) data_hist_y = np.concatenate((data_plot.y, [0.])) if xlow is None: xlow = model_x[0] xhigh = model_x[-1] else: xlow = min(xlow, model_x[0]) xhigh = max(xhigh, model_x[-1]) csp = om.rect.ContinuousSteppedPainter(keyText=None) csp.setFloats(data_hist_x, data_hist_y) data_csps.append(csp) inner_stamp = DataThemedStamp(None) stamp = WithYErrorBars(inner_stamp) lines = om.rect.XYDataPainter(lines=False, pointStamp=stamp, keyText='%s Data #%d' % (desc, index)) lines.setFloats(data_plot.x, data_plot.y, data_plot.y + data_plot.yerr, data_plot.y - data_plot.yerr) inner_stamp.setHolder(lines) data_lines.append(lines) log_bounds_pad_factor = 0.9 xlow *= log_bounds_pad_factor xhigh /= log_bounds_pad_factor if min_valid_x is not None: p.add(om.rect.XBand(1e-3 * xlow, min_valid_x, keyText=None), zheight=-1, dsn=1) if max_valid_x is not None: p.add(om.rect.XBand(max_valid_x, xhigh * 1e3, keyText=None), zheight=-1, dsn=1) model_csp = om.rect.ContinuousSteppedPainter(keyText=desc + ' Model') model_csp.setFloats(model_x, model_y) p.add(model_csp) for index, (data_csp, lines) in enumerate(zip(data_csps, data_lines)): p.add(data_csp, dsn=index + 1) p.add(lines, dsn=index + 1) p.setLabels(data_plot.xlabel, data_plot.ylabel) # data_plot = last one from the for loop p.setLinLogAxes(True, False) p.setBounds(xlow, xhigh) return p, xlow, xhigh
def plot_long_term_photom(dsrc, dref, dpdm, plotinfo): add_unbinned = plotinfo.get('add_unbinned', True) add_refsrc = plotinfo.get('add_refsrc', True) from . import data ssrc = data.photom_bin_by_visits(dsrc, half_scans=True) if add_refsrc: sref = data.photom_bin_by_visits(dref, half_scans=True) print('# typical integration time:', np.median(ssrc.inttime)) mjd0 = dsrc.mjd.min() - dsrc.dmjd.min() prd = dpdm.both_prd / 24. c0 = plotinfo.comp0 c1 = plotinfo.comp1 dsn0 = plotinfo.dsn_base if not plotinfo.has('group_sep1'): groups = [slice(None)] else: groups = [(ssrc.dmjd < plotinfo.group_sep1), (ssrc.dmjd > plotinfo.group_sep1) & (ssrc.dmjd < plotinfo.group_sep2), (ssrc.dmjd > plotinfo.group_sep2)] p = om.RectPlot() # Un-binned source data if add_unbinned: p.addXY(dsrc.dmjd, dsrc[c0], None, lines=0, pointStamp=om.stamps.Circle(fill=1, size=2), stampStyle={ 'color': (1, plotinfo.unavg_intens, plotinfo.unavg_intens) }) p.addXY(dsrc.dmjd, dsrc[c1], None, lines=0, pointStamp=om.stamps.Circle(fill=1, size=2), stampStyle={ 'color': (plotinfo.unavg_intens, plotinfo.unavg_intens, 1) }) # Horizontal zero lines(source and reference) p.addHLine(0, keyText=None, lineStyle={'color': (0, 0, 0), 'linewidth': 3}) if add_refsrc: p.addHLine(plotinfo.ref_offset, keyText=None, lineStyle=plotinfo.ref_style) # Binned source and reference data kt1 = plotinfo.src_kt0 kt2 = plotinfo.src_kt1 if add_refsrc: kt3 = plotinfo.ref_kt0 kt4 = plotinfo.ref_kt1 sref['plot_' + c0] = sref[c0] + plotinfo.ref_offset sref['plot_' + c1] = sref[c1] + plotinfo.ref_offset for g in groups: p.addDF(ssrc[g][['dmjd', c0, 'u' + c0]], kt1, lines=1, pointStamp=om.stamps.Circle(fill=1, size=3), lineStyle={'linewidth': 2}, dsn=dsn0 + 0, zheight=5) p.addDF(ssrc[g][['dmjd', c1, 'u' + c1]], kt2, lines=1, pointStamp=om.stamps.Circle(fill=1, size=3), lineStyle={'linewidth': 2}, dsn=dsn0 + 1, zheight=5) if add_refsrc: p.addDF(sref[g][['dmjd', 'plot_' + c0, 'u' + c0]], kt3, lines=1, pointStamp=om.stamps.Circle(fill=1, size=3), lineStyle={'linewidth': 2}, dsn=2) p.addDF(sref[g][['dmjd', 'plot_' + c1, 'u' + c1]], kt4, lines=1, pointStamp=om.stamps.Circle(fill=1, size=3), lineStyle={'linewidth': 2}, dsn=3) kt1 = kt2 = kt3 = kt4 = None # Single-period PDM phasing, potentially with boxes identifying flare # zoom-ins. if plotinfo.has('zoom_ybounds'): for i in xrange(plotinfo.zoom_n_lines): t = (plotinfo.zoom_mjd0 - mjd0) + i * prd p.add(Rectangle(t - 0.5 * plotinfo.zoom_window_dur, t + 0.5 * plotinfo.zoom_window_dur, *plotinfo.zoom_ybounds, style={ 'color': 'muted', 'dashing': [7, 3] }), zheight=-5, rebound=False) if plotinfo.zoom_desc is not None: p.add(XYText(t, plotinfo.zoom_ybounds[1], '<big><b>%s%d</b></big>' % (plotinfo.zoom_desc, i + 1), vAnchor=-0.03), rebound=False) p.defaultKeyOverlay.hAlign = plotinfo.key_halign p.defaultKeyOverlay.vAlign = plotinfo.key_valign p.setBounds(*plotinfo.bounds) p.setYLabel('Flux density(μJy)') if plotinfo.label_bot: p.setXLabel('MJD - %.0f(day)' % mjd0) else: p.bpainter.paintLabels = False if plotinfo.add_dhr_top_axis: add_dhr_top_axis(p, dsrc) p.lpainter.everyNthMajor = 2 return p
def demo_divine_figure_7l(): """Lower panel of figure 7. """ import omega as om d4 = JupiterD4Field() KM_IFY = 1e30 # cm^-6 => km^-6 EV_IFY = 1e6 # MeV => eV blat = 0. blon = -110 * astutil.D2R # sign? br = 6. # R_J mlat, mlon, L = d4(blat, blon, br) B = d4.bmag(blat, blon, br) p = om.RectPlot() p.setLinLogAxes(True, True) # Energetic electron distribution E = np.array([0.07, 0.2, 0.5, 1.1, 3]) # MeV E_cgs = E * cgs.ergperev * 1e6 j_energetic = radbelt_e_omnidirectional_diff_flux( blat, blon, br, E, d4, ) j_energetic *= 1e-6 * cgs.evpererg # per MeV to per erg f_energetic = cgs.me**2 * j_energetic / (8 * np.pi * E_cgs) * KM_IFY p.addXY(E * EV_IFY, f_energetic, 'Energetic') # Warm Maxwellian E = np.logspace(1., 4.15, 40) # eV N_ew = warm_e_reference_density(blat, blon, br) print('DG83 warm density: 7.81; mine: %.2f' % N_ew) kT_cgs = 1e3 * cgs.ergperev prefactor = (cgs.me / (2 * np.pi * kT_cgs))**1.5 f_ew_m = N_ew * prefactor * np.exp(-(E * cgs.ergperev) / kT_cgs) * KM_IFY p.addXY(E, f_ew_m, 'Warm Maxwellian') # Fitted Warm kappa distribution kappa_model = warm_e_psd_model(blat, blon, br, d4) print('DG83 warm N_0: 8.5 cm^-3; mine: %.2f' % kappa_model.params[0]) print('DG83 warm E0: 933 eV; mine: %.0f' % (kappa_model.params[1] * 1e6)) print('DG83 warm kappa: 2.32; mine: %.2f' % kappa_model.params[2]) E = np.logspace(1., 6.5, 60) # eV f_ew_k = kappa_model.mfunc(E * 1e-6) * KM_IFY p.addXY(E, f_ew_k, 'Warm kappa') # Cold electrons. The "2070 cm^-3" reported here seems to be the value for # the interpolated "N" from Table 7, not the N_k value corrected for the # fact that we're slightly off the disk. The figure caption seems pretty # clear about which location we're looking at, i.e. it seems unlikely that # the equations are supposed to be evaluated at the disk equator rather # than the rotational equator. So I think the discrepancy is just an # oversight / inclarity. N, kT_mev = cold_e_maxwellian_parameters(blat, blon, br) print('DG83 cold N_0: 2070 cm^-3; mine: %.0f' % N) print('DG83 cold kT: 36.1 eV; mine: %.1f' % (kT_mev * 1e6)) E = np.logspace(1., 3., 30) # eV f_ec_k = cold_e_psd(blat, blon, br, E * 1e-6) * KM_IFY p.addXY(E, f_ec_k, 'Cold') p.setBounds(1e1, 8e6, 1.2e-8, 9e6) p.defaultKeyOverlay.hAlign = 0.9 p.setLabels('Energy (eV)', 'Elec distrib func (s^3/km^6)') return p