+
+
+
+
+
+ {{item.name}} ({{key}}): {{item.description}}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jdaviz/configs/default/plugins/data_quality/dq_utils.py b/jdaviz/configs/default/plugins/data_quality/dq_utils.py
index 019fa603a7..940071295a 100644
--- a/jdaviz/configs/default/plugins/data_quality/dq_utils.py
+++ b/jdaviz/configs/default/plugins/data_quality/dq_utils.py
@@ -45,7 +45,7 @@ def load_flag_map(mission_or_instrument=None, path=None):
flag_mapping = {}
for flag, name, desc in flag_table.iterrows():
- flag_mapping[flag] = dict(name=name, description=desc)
+ flag_mapping[int(flag)] = dict(name=name, description=desc)
return flag_mapping
@@ -77,7 +77,7 @@ def write_flag_map(flag_mapping, csv_path, **kwargs):
table.write(csv_path, format='ascii.csv', **kwargs)
-def generate_listed_colormap(n_flags, seed=42):
+def generate_listed_colormap(n_flags=None, seed=3):
"""
Generate a list of random "light" colors of length ``n_flags``.
@@ -103,14 +103,14 @@ def generate_listed_colormap(n_flags, seed=42):
# Generate random colors that are generally "light", i.e. with
# RGB values in the upper half of the interval (0, 1):
rgba_colors = [
- tuple(rng.uniform(low=0.5, high=1, size=3).tolist() + [default_alpha])
+ tuple(np.insert(rng.uniform(size=2), rng.integers(0, 3), 1).tolist() + [default_alpha])
for _ in range(n_flags)
]
cmap = ListedColormap(rgba_colors)
# setting `bad` alpha=0 will make NaNs transparent:
- cmap.set_bad(alpha=0)
+ cmap.set_bad(color='k', alpha=0)
return cmap, rgba_colors
diff --git a/jdaviz/configs/default/plugins/plot_options/plot_options.py b/jdaviz/configs/default/plugins/plot_options/plot_options.py
index ef78823fdf..77dfa3600e 100644
--- a/jdaviz/configs/default/plugins/plot_options/plot_options.py
+++ b/jdaviz/configs/default/plugins/plot_options/plot_options.py
@@ -115,10 +115,61 @@ def update_knots(self, x, y):
self.spline = PchipInterpolator(self._x, self._y)
+class LookupStretch:
+ """
+ Stretch class specific to DQ arrays.
+
+ Attributes
+ ----------
+ flags : array-like
+ DQ flags.
+ """
+
+ def __init__(self, flags=None):
+ # Default x, y values(0-1) range chosen for a typical initial spline shape.
+ # Can be modified if required.
+ if flags is None:
+ flags = np.linspace(0, 1, 5)
+ self.flags = np.asarray(flags)
+
+ def __call__(self, values, out=None, clip=False):
+ # For our uses, we can ignore `out` and `clip`, but those would need
+ # to be implemented before contributing this class upstream.
+
+ # find closest index in `self.flags` for each value in `values`:
+ if hasattr(values, 'squeeze'):
+ values = values.squeeze()
+
+ # renormalize the flags on range (0, 1):
+ scaled_flags = self.flags / np.max(self.flags)
+
+ # `values` will have already been passed through
+ # astropy.visualization.ManualInterval and normalized on (0, 1)
+ # before they arrive here. Now find the index of the closest entry in
+ # `scaled_flags` for each of `values` using array broadcasting.
+ min_indices = np.argmin(np.abs(
+ np.nan_to_num(values, nan=-10).flatten()[None, :] - scaled_flags[:, None]
+ ), axis=0).reshape(values.shape)
+
+ # normalize by the number of flags, onto interval (0, 1):
+ renormed = min_indices / (len(self.flags) - 1)
+
+ # preserve nans in the result:
+ renormed = np.where(
+ np.isnan(values),
+ np.nan,
+ renormed
+ )
+ return renormed
+
+
# Add the spline stretch to the glue stretch registry if not registered
if "spline" not in stretches:
stretches.add("spline", SplineStretch, display="Spline")
+if "lookup" not in stretches:
+ stretches.add("lookup", LookupStretch, display="DQ")
+
def _round_step(step):
# round the step for a float input
diff --git a/jdaviz/configs/imviz/imviz.yaml b/jdaviz/configs/imviz/imviz.yaml
index 4e7de049bb..2934cebabf 100644
--- a/jdaviz/configs/imviz/imviz.yaml
+++ b/jdaviz/configs/imviz/imviz.yaml
@@ -24,6 +24,7 @@ tray:
- g-plot-options
- g-subset-plugin
- g-markers
+ - g-data-quality
- imviz-compass
- imviz-line-profile-xy
- imviz-aper-phot-simple
diff --git a/jdaviz/core/template_mixin.py b/jdaviz/core/template_mixin.py
index 3a568b9f8e..a34594505f 100644
--- a/jdaviz/core/template_mixin.py
+++ b/jdaviz/core/template_mixin.py
@@ -1329,7 +1329,9 @@ def __init__(self, plugin, items, selected, viewer,
multiselect=None,
default_text=None, manual_options=[],
default_mode='first',
- only_wcs_layers=False):
+ only_wcs_layers=False,
+ is_root=True,
+ is_child_of=None):
"""
Parameters
----------
@@ -1382,11 +1384,24 @@ def __init__(self, plugin, items, selected, viewer,
self._update_layer_items()
self.update_wcs_only_filter(only_wcs_layers)
- # ignore layers that are children in associations:
- def is_parent(data):
- return self.app._get_assoc_data_parent(data.label) is None
+ self.filter_is_root = is_root
+ self.filter_is_child_of = is_child_of
- self.add_filter(is_parent)
+ if self.filter_is_root:
+ # ignore layers that are children in associations:
+ def filter_is_root(data):
+ return self.app._get_assoc_data_parent(data.label) is None
+
+ self.add_filter(filter_is_root)
+
+ elif not self.filter_is_root and self.filter_is_child_of is not None:
+ # only offer layers that are children of the correct parent:
+ def has_correct_parent(data):
+ if self.filter_is_child_of == '':
+ return False
+ return self.app._get_assoc_data_parent(data.label) == self.filter_is_child_of
+
+ self.add_filter(has_correct_parent)
def _get_viewer(self, viewer):
# newer will likely be the viewer name in most cases, but viewer id in the case