def _on_query(self, eruption_jd) -> DataFrame: # Make sure we work with a copy - we don't want to modify the underlying data df = self._data.copy() df = df.query("rate_err == rate_err").query("rate_err > 0") print( f"\tafter filtering out rate_err is NaN or 0, {len(df)} rows left") # We create the standard day and day_err fields, relative to passed eruption jd if "jd" in df.columns: df["day"] = tm.delta_t_from_jd(df["jd"], eruption_jd) df["day_err"] = df["jd_plus_err"] elif "mjd" in df.columns: df["day"] = tm.delta_t_from_jd(tm.jd_from_mjd(df["mjd"]), eruption_jd) df["day_err"] = df["mjd_plus_err"] return df
def _calculate_shift_factor(self, ix: int, spectrum: Spectrum1DEx) -> float: shift_factor = 0 if self.y_shift != 0: if self.y_shift_by_delta_t: mjd = spectrum.mjd delta_t = tm.delta_t_from_jd(tm.jd_from_mjd(mjd), self.eruption_jd) shift_factor = self.y_shift * delta_t else: shift_factor = self.y_shift * ix return shift_factor
def _draw_plot_data(self, ax: Axes, **kwargs): # The payload should be spectral line fitted models containing Gaussian fits to lines. It's a dictionary keyed # on spec_name (b_e_20190828_3 etc.). Each item is an array of astropy CompoundModels for each spectral line. # Each model will have 1+ Gaussian1D models for the line and 1 Polynomial1D for the continuum. # Compound models named H$\\alpha$ etc. Each Gaussian fit$_{1}$ (wide), fit$_{2}$ (narrow) spectra = kwargs["spectra"] all_line_fits = kwargs["line_fits"] reference_jd = self.eruption_jd # The data is in a slightly awkward form, dicts keyed on spectrum with each item an array of line_fits (as we # would generally be interested in one spectrum & associated data at a time). Best to transform into a # more usable form; an array of dictionaries which can be loaded into a DataFrame / tabular data rows = list() columns = ["line", "fit", "delta_t", "velocity", "velocity_err"] for spec_key, line_fits in all_line_fits.items(): mjd = spectra[spec_key].mjd if spec_key in spectra else None delta_t = tm.delta_t_from_jd(tm.jd_from_mjd(mjd), reference_jd=reference_jd) for line_fit in line_fits: if line_fit.name in self.lines: for sub_fit in line_fit: if sub_fit.name in self.lines[line_fit.name] and isinstance(sub_fit, Gaussian1D): lambda_0 = sub_fit.mean.quantity v = fu.calculate_velocity_from_sigma(lambda_0, sub_fit.fwhm).to("km / s") v_err = 0 * v.unit # TODO: uncertainty rows.append({ "line": line_fit.name.replace("\\", "_"), "fit": sub_fit.name.replace("\\", "_"), "delta_t": delta_t, "velocity": v.value, "velocity_err": v_err.value }) df = DataFrame.from_records(rows, columns=columns) # The line name / fit name will be used to look up the corresponding columns for line_name, line in self.lines.items(): line_field = line_name.replace("\\", "_") for fit_name in line: fit_plot_params = line[fit_name] color = fit_plot_params["color"] if "color" in fit_plot_params else "k" label = f"{line_name} {fit_plot_params['label'] if 'label' in fit_plot_params else fit_name}" fit_field = fit_name.replace("\\", "_") df_line = df.query(f"line == '{line_field}' and fit == '{fit_field}'").sort_values(by="delta_t") if len(df_line) > 0: self._plot_points_to_error_bars_on_ax(ax, x_points=df_line["delta_t"], y_points=df_line["velocity"], y_err_points=df_line["velocity_err"], color=color, label=label) self._plot_points_to_lines_on_ax(ax, x_points=df_line["delta_t"], y_points=df_line["velocity"], color=color, line_style="--", alpha=0.3) return
def _on_query(self, eruption_jd: float) -> DataFrame: """ Return standard magnitude fields for use by a magnitude query. """ # Make sure we are working with a copy of the underlying data - we don't want to change the source df = self._data.copy() # Apply any filters; the two on mag_err exclude those rows where mag_err is NaN and 0 (both no use to us) df = df.query("mag_err == mag_err").query("mag_err > 0").query( "is_null_obs == False") print( f"\tafter filtering on mag_err is NaN or 0 and is_null_obs == True, {len(df)} rows left" ) # We create day and log(day) field, relative to passed eruption jd df['day'] = tm.delta_t_from_jd(df['jd'], eruption_jd) df['log_day'] = np.log10(df.query("day>0")['day']) return df
for plot_config in settings["plots"][plot_group_config]: spectra = {} spectral_lines = {} plot_line_fits = {} delta_t = None # Each plot will generally have 2 spectra (blue arm and red arm) for spec_match in plot_config["spectra"]: # Get all the data source whose name start with the key value - mostly each individually specified filtered_data_sources = { k: v for k, v in data_sources.items() if k.startswith(spec_match) } for spec_name, ds in filtered_data_sources.items(): delta_t = tm.delta_t_from_jd(tm.jd_from_mjd(ds.header["MJD"]), eruption_jd) spectrum = ds.query() print( f"\tUsing spectrum '{spec_name}': Delta-t={delta_t:.2f} & max_flux={spectrum.max_flux}" ) spectra[spec_name] = spectrum flux_units = spectrum.flux.unit if "line_fits" in plot_config: # Pick up any fitted spectral lines configured for fit_match in plot_config["line_fits"]: plot_line_fits.update({ k: v for k, v in line_fit_sets.items() if k.startswith(fit_match) })
def _get_spectrum_delta_t(self, spectrum: Spectrum1DEx) -> float: mjd = spectrum.mjd return tm.delta_t_from_jd(tm.jd_from_mjd(mjd), self.eruption_jd)
def get_spectra_epochs(eruption_jd: float) -> Dict[str, float]: """ Gets the timing of the LT Spectra for the 2019 eruption as an epochs dictionary. """ return { "b_e_20190828_11": tm.delta_t_from_jd(2458724.408415, eruption_jd), "b_e_20190828_3": tm.delta_t_from_jd(2458724.358298, eruption_jd), "b_e_20190830_5": tm.delta_t_from_jd(2458726.358392, eruption_jd), "b_e_20190831_11": tm.delta_t_from_jd(2458727.433088, eruption_jd), "b_e_20190831_5": tm.delta_t_from_jd(2458727.354917, eruption_jd), "b_e_20190901_11": tm.delta_t_from_jd(2458728.430003, eruption_jd), "b_e_20190901_5": tm.delta_t_from_jd(2458728.356852, eruption_jd), "b_e_20190902_5": tm.delta_t_from_jd(2458729.353593, eruption_jd), "b_e_20190902_7": tm.delta_t_from_jd(2458729.419832, eruption_jd), "b_e_20190903_5": tm.delta_t_from_jd(2458730.363364, eruption_jd), "b_e_20190903_7": tm.delta_t_from_jd(2458730.42483, eruption_jd), "b_e_20190904_4": tm.delta_t_from_jd(2458731.363214, eruption_jd), "b_e_20190905_5": tm.delta_t_from_jd(2458732.351202, eruption_jd), "b_e_20190905_7": tm.delta_t_from_jd(2458732.431063, eruption_jd), "b_e_20190910_1": tm.delta_t_from_jd(2458737.355612, eruption_jd), "b_e_20190911_5": tm.delta_t_from_jd(2458738.346323, eruption_jd), "b_e_20190911_7": tm.delta_t_from_jd(2458738.410921, eruption_jd), "b_e_20190913_5": tm.delta_t_from_jd(2458740.345966, eruption_jd), "b_e_20190913_7": tm.delta_t_from_jd(2458740.406875, eruption_jd), "b_e_20190915_5": tm.delta_t_from_jd(2458742.344409, eruption_jd), "r_e_20190828_11": tm.delta_t_from_jd(2458724.408344, eruption_jd), "r_e_20190828_3": tm.delta_t_from_jd(2458724.358227, eruption_jd), "r_e_20190830_5": tm.delta_t_from_jd(2458726.358327, eruption_jd), "r_e_20190831_11": tm.delta_t_from_jd(2458727.433159, eruption_jd), "r_e_20190831_5": tm.delta_t_from_jd(2458727.354847, eruption_jd), "r_e_20190901_11": tm.delta_t_from_jd(2458728.430132, eruption_jd), "r_e_20190901_5": tm.delta_t_from_jd(2458728.356769, eruption_jd), "r_e_20190902_5": tm.delta_t_from_jd(2458729.353522, eruption_jd), "r_e_20190902_7": tm.delta_t_from_jd(2458729.419905, eruption_jd), "r_e_20190903_5": tm.delta_t_from_jd(2458730.363294, eruption_jd), "r_e_20190903_7": tm.delta_t_from_jd(2458730.42476, eruption_jd), "r_e_20190904_4": tm.delta_t_from_jd(2458731.363149, eruption_jd), "r_e_20190905_5": tm.delta_t_from_jd(2458732.351137, eruption_jd), "r_e_20190905_7": tm.delta_t_from_jd(2458732.431134, eruption_jd), "r_e_20190910_1": tm.delta_t_from_jd(2458737.355542, eruption_jd), "r_e_20190911_5": tm.delta_t_from_jd(2458738.346253, eruption_jd), "r_e_20190911_7": tm.delta_t_from_jd(2458738.410851, eruption_jd), "r_e_20190913_5": tm.delta_t_from_jd(2458740.345901, eruption_jd), "r_e_20190913_7": tm.delta_t_from_jd(2458740.406804, eruption_jd), "r_e_20190915_5": tm.delta_t_from_jd(2458742.344338, eruption_jd), }