Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Spatial Collapsed Spectrum selection to Line Analysis #1583

Merged
merged 20 commits into from
Sep 8, 2022
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ Cubeviz

- Image viewers now have linked pan/zoom and linked box zoom. [#1596]

- Added ability to select spatial subset collasped spectrum for Line Analysis [#1583]
duytnguyendtn marked this conversation as resolved.
Show resolved Hide resolved

Imviz
^^^^^

Expand Down
30 changes: 27 additions & 3 deletions jdaviz/configs/specviz/plugins/line_analysis/line_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ class LineAnalysis(PluginTemplateMixin, DatasetSelectMixin, SpectralSubsetSelect
dialog = Bool(False).tag(sync=True)
template_file = __file__, "line_analysis.vue"

spatial_subset_items = List().tag(sync=True)
collapsed_spectrum_selected = Unicode().tag(sync=True)

continuum_subset_items = List().tag(sync=True)
continuum_subset_selected = Unicode().tag(sync=True)

Expand Down Expand Up @@ -97,6 +100,15 @@ def __init__(self, *args, **kwargs):
# require entries to be in spectrum-viewer (not other cubeviz images, etc)
self.dataset.add_filter('layer_in_spectrum_viewer')

if self.app.state.settings.get("configuration") == "cubeviz":
self.spatial_subset = SubsetSelect(self,
'spatial_subset_items',
'collapsed_spectrum_selected',
default_text='Entire Cube Spectrum',
allowed_type='spatial')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd advocate for using the same traitlet names and default text as in model fitting so there is a consistent UX and API for the user between the two. If there are subtle differences that we want to capture in the UI, then the hint might be the easiest place to make that distinction. (Or we can always change model fitting to match if there is a good reason to make changes).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd still like to see this addressed/discussed before approving/merging!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was going to address this in my "review phase" now that the CI is passing. I think I've mellowed on my original intent, so I'm happy to switch it back! Let me do that first and I'll rerequest review

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not familiar with model fitting, so maybe @rosteen or @javerbukh would have opinions.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Effectively the distinction I tried to make is between selecting the spatial subset itself, or the spectrum generated from the spatial subset. Effectively, it looks identical on the front end, but it's slightly different here in the backend

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kecnry I've reverted those changes so they should match; let me know if it's sufficient, or if I missed something!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do see your point, but just really want to strive for self-consistency across plugins, especially with attribute names and options since we're looking to expose these directly in #1401. This still differs from model fittings spatial dropdown (which is the same use-case: acting on the spectrum corresponding to the referenced spatial subset), in that model fitting has "Entire Cube" and this has "Entire Cube Spectrum". I definitely think they should be the same, and personally would vote for "Entire Cube" and add any clarification to the user in the dropdown hint and/or docs. But if others prefer being more verbose, then let's also make the change to model fitting.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, I misinterpreted your concern to be about the actual traitlets, not realizing you were also concerned about the labeling. I can understand your concern; I'll revert the labeling as well and we can defer this discussion to another day

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I changed the default text/labeling as well. I reworked the hint to try and make it explicit. How does that look @kecnry ?

else:
self.spatial_subset = None

self.hub.subscribe(self, AddDataMessage,
handler=self._on_viewer_data_changed)
self.hub.subscribe(self, RemoveDataMessage,
Expand Down Expand Up @@ -139,7 +151,9 @@ def _on_viewer_subsets_changed(self, msg):
msg : `glue.core.Message`
The glue message passed to this callback method.
"""
if (msg.subset.label in [self.spectral_subset_selected, self.continuum_subset_selected]
if (msg.subset.label in [self.spectral_subset_selected,
self.collapsed_spectrum_selected,
self.continuum_subset_selected]
and self.plugin_opened):
self._calculate_statistics()

Expand Down Expand Up @@ -210,7 +224,8 @@ def _on_identified_line_changed(self, msg):
# in which case we'll default to the identified line
self.selected_line = self.identified_line

@observe("spectral_subset_selected", "dataset_selected", "continuum_subset_selected", "width")
@observe("collapsed_spectrum_selected", "spectral_subset_selected", "dataset_selected",
"continuum_subset_selected", "width")
def _calculate_statistics(self, *args, **kwargs):
"""
Run the line analysis functions on the selected data/subset and
Expand All @@ -222,7 +237,16 @@ def _calculate_statistics(self, *args, **kwargs):
# show spinner with overlay
self.results_computing = True

full_spectrum = self.dataset.selected_obj
if self.config == 'cubeviz' and self.collapsed_spectrum_selected != 'Entire Cube Spectrum':
# then we're acting on the auto-collapsed data in the spectrum-viewer
# of a spatial subset. In the future, we may want to expose on-the-fly
# collapse options... but right now these will follow the settings of the
# spectrum-viewer itself
full_spectrum = self.app.get_data_from_viewer('spectrum-viewer',
self.collapsed_spectrum_selected)
else:
full_spectrum = self.dataset.selected_obj

if full_spectrum is None or self.width == "" or not self.plugin_opened:
# this can happen DURING a unit conversion change
self.update_results(None)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@
hint="Select the data set to be analysed."
/>

<plugin-subset-select
v-if="config=='cubeviz'"
:items="spatial_subset_items"
:selected.sync="collapsed_spectrum_selected"
:show_if_single_entry="true"
label="Collapsed Spectrum"
hint="Select collapsed spectrum to analyze."
/>

<plugin-subset-select
:items="spectral_subset_items"
:selected.sync="spectral_subset_selected"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import astropy.units as u
from astropy.table import QTable
import numpy as np
from glue.core.roi import XRangeROI
from astropy.wcs import WCS
from glue.core.roi import XRangeROI, RectangularROI
from glue.core.edit_subset_mode import NewMode
import numpy as np
import pytest
from specutils import Spectrum1D

from jdaviz.configs.specviz.plugins.line_analysis.line_analysis import _coerce_unit
from jdaviz.core.events import LineIdentifyMessage
Expand Down Expand Up @@ -41,6 +44,50 @@ def test_plugin(specviz_helper, spectrum1d):
assert len(result_dict.get('uncertainty')) > 0


@pytest.mark.filterwarnings('ignore:No observer defined on WCS')
def test_spatial_subset(cubeviz_helper):
"""
Tests that the spatial selection returns any valid result, DOES NOT VALIDATE THE VALUE
Not checking the value attempts to circumvent the issue we ran into here:
https://github.com/spacetelescope/jdaviz/pull/1564#discussion_r949427663
"""

flux = np.arange(250).reshape((5, 5, 10)) * u.Jy
wcs_dict = {"CTYPE1": "RA---TAN", "CTYPE2": "DEC--TAN", "CTYPE3": "WAVE-LOG",
"CRVAL1": 205, "CRVAL2": 27, "CRVAL3": 4.622e-7,
"CDELT1": -0.0001, "CDELT2": 0.0001, "CDELT3": 8e-11,
"CRPIX1": 0, "CRPIX2": 0, "CRPIX3": 0}
w = WCS(wcs_dict)
large_cube = Spectrum1D(flux=flux, wcs=w)
pllim marked this conversation as resolved.
Show resolved Hide resolved

label = "Test Cube"
cubeviz_helper.load_data(large_cube, data_label=label)

# add a region and rerun stats for that region
cubeviz_helper.app.get_viewer('flux-viewer').apply_roi(RectangularROI(-0.5, 0.5, 0.5, 2.5))
cubeviz_helper.app.get_viewer('flux-viewer').session.edit_subset_mode._mode = NewMode
# The cube only has one slice, so we have to grab the entire viewer's range to create a region
cubeviz_helper.app.get_viewer('spectrum-viewer').apply_roi(
XRangeROI(cubeviz_helper.app.get_viewer('spectrum-viewer').state.x_min,
cubeviz_helper.app.get_viewer('spectrum-viewer').state.x_max))

cubeviz_helper.app.state.drawer = True

plugin = cubeviz_helper.app.get_tray_item_from_name('specviz-line-analysis')
plugin.open_in_tray()
pllim marked this conversation as resolved.
Show resolved Hide resolved

plugin.collapsed_spectrum_selected = "Subset 1"
plugin.spectral_subset_selected = 'Subset 2'
plugin.continuum_subset_selected = 'Surrounding'
plugin.width = 3

for result in plugin.results:
# Check that there exists a value
assert not np.isnan(float(result['result']))
# Check the unit is not dimensionless
assert u.Unit(result['unit']) != u.dimensionless_unscaled


def test_line_identify(specviz_helper, spectrum1d):
label = "Test 1D Spectrum"
specviz_helper.load_spectrum(spectrum1d, data_label=label)
Expand Down