from functools import cached_property
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import xarray as xr
from tqdm.auto import tqdm, trange
import holoviews as hv
import hvplot.xarray # noqa: F401
import panel as pn
from panel import widgets
from planetarypy.datetime_format_converters import (
fromdoyformat,
doyformat, # replaces removed iso_to_nasa_date
)
from pyuvis import UVPDS, UVISObs, CatalogFilter
from pyuvis.calib.greg import filter_spica_for_date
from pyuvis.calib.steffl import (
steffl_spica_dates,
steffl_spica_doy_dates,
Row2Row,
create_detector_stack,
)
# `param` was used for class definitions in the original; the
# implementation now lives in src/pyuvis/calib/steffl.py — only
# import param here if you're prototyping new classes interactively.
# import param
# `find_mixed_type_cols` is no longer exposed by planetarypy.pds.indexes;
# any cell below that referenced it is left as #| eval: false.Calibration: Steffl method
Recreating Steffl’s Flatfields
Based on his thesis appendix
⚠️ Demo cells below are marked
#| eval: false— they require live PDS index fetches, cached data products, or interactive plotting backends that are unavailable during a clean docs render. Open this notebook in JupyterLab to step through it cell-by-cell against your local data.
hv.extension("bokeh", logo=False)missing = [] there = [] for id in obsids: try: data = UVPDS(id, skip_download=True) except FileNotFoundError: print(id, “not there.”) missing.append(id) else: print(“Got”, id) there.append(id)
cat = CatalogFilter(steffl_spica_dates[2])pids = list(cat.get_euv_date().query("OBSERVATION_TYPE=='CALIB'").index)pidscat.set_next_day()pids.extend(list(cat.get_euv_date().query("OBSERVATION_TYPE=='CALIB'").index))pidskwargs = {"x": "nx", "y": "ny", "cmap": "viridis", "clim": (0, 50)}Row2Row correction
pidsr2r = Row2Row(pids[0])r2r.plot_setr2r.plot_averagedr2r.plot_ffr2r.plot_integratedr2r.plot_column_stdr2r.ffCol2Col sensitivity variation.
Universal detector stack xarray creator
This function allows to create detector-shaped stacks of data for different purposes, like: * along_slit scans * across_slit scans * sets of corrections for the Steffl flatfield
c2c = Col2Col(pids)c2c.calculate_simple_correction()c2c.plot_all_Fm()- It is neat to see how the grid has a weaker signal in the last array, where only 2 columns could be combined
c2c.plot_simple_correction()Row2Row flats
Every across_slit scan comes with an inner along_slit scan that can be used to create a row2row flatfield correction.
So we have 14 of them in this case, that can be averaged.
c2c.plot_r2r_flats()c2c.r2r_flat_average_plot()- Nice to see how the SNR below 155 nm has improved drastically from having the average of the 14 FF corrections.
c2c.simple_both_plot()c2c.i=100
c2c.m=0c2c.plot_triplet()c2c.plot_triplet(corrected=True)def compare_before_after(i=0):
p1 = (
c2c.arr.where(c2c.arr > 0, np.nan)
.isel(across_slit=i, drop=True)
.hvplot(
x="spectral",
y="spatial",
cmap="viridis",
logz=True,
label="Original",
# widget_type="scrubber",
widget_location="bottom",
)
)
p2 = (
c2c.corrected_arr.where(c2c.corrected_arr > 0, np.nan)
.isel(across_slit=i, drop=True)
.hvplot.image(
x="spectral",
y="spatial",
cmap="viridis",
logz=True,
label="Corrected",
# widget_type="scrubber",
widget_location="bottom",
)
)
return pn.Column(p1) + pn.Column(p2)slider = pn.widgets.IntSlider(end=14)pn.interact(compare_before_after, i=(0, 14))p2 = c2c.corrected_arr.where(c2c.corrected_arr > 0, np.nan).isel(across_slit=i, drop=True).hvplot.image(
x="spectral",
y="spatial",
cmap="viridis",
logz=True,
label="Corrected",
# widget_type="scrubber",
widget_location="bottom",
)import panel as pnpn.Column(p1) + pn.Column(p2)(p1+p2)Mean of inner area is 1:
c2c.simple_both.isel(spectral=slice(15, 998), spatial=slice(3,61)).mean().dataiarr = c2c.arr.interactive()### import panel as pn
from panel import widgetsival = widgets.IntSlider(start=0, end=1024)
mval = widgets.IntSlider()iarr.isel(spectral=ival, drop=True).hvplot().layout()c2c.calculate_simple_correction()c2c.simple_correctionc2c.i = 200
c2c.m = 0c2c.column_set_mean() / c2c.column_set()[0]c2c.column_set()[0]c2c.i = 200c2c.m = 3c2c.plot_averaged_triplet()c2c.plot_triplet(corrected=False, i=300)c2c.plot_simple_correction()c2c.simple_correction.shapec2c.plot_Fm(0)c2c.plot_triplet()c2c.column_set_mean()c2c.plot()archive_df.loc["EUV2001_093_08_35_28"]p = obsdir / "index_repaired.tab"df = pd.read_csv(p, quotechar='"', skipinitialspace=True)from planetarypy.pds.indexes import find_mixed_type_colsfind_mixed_type_cols(df, fix=False)df.columnsindex.columnsindex[index.filename.str.startswith("EUV")].iloc[0]obs.head()cols = ["index start_time stop_time detector target obsid_time unknown type comment "]