jdaviz
jdaviz copied to clipboard
[BUG] Mosviz: Model Fitting doesn't work in Mosviz
Describe the bug All attempts to fit a model using the Model Fitting plugin in Mosviz fail, for even the simplest model (Constant1D), to either the full Dataset or a Subset. The following traceback is generated:
IndexError Traceback (most recent call last)
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/ipyvue/VueTemplateWidget.py in _handle_event(self, _, content, buffers)
55 getattr(self, 'vue_' + event)(data, buffers)
56 else:
---> 57 getattr(self, 'vue_' + event)(data)
58
59
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/jdaviz/configs/default/plugins/model_fitting/model_fitting.py in vue_model_fitting(self, *args, **kwargs)
359 self._fitted_spectrum = fitted_spectrum
360
--> 361 self.vue_register_spectrum({"spectrum": fitted_spectrum})
362 self.app.fitted_models[self.model_label] = fitted_model
363
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/jdaviz/configs/default/plugins/model_fitting/model_fitting.py in vue_register_spectrum(self, event)
498 # Remove the actual Glue data object from the data_collection
499 self.data_collection.remove(self.data_collection[label])
--> 500 self.data_collection[label] = spectrum
501
502 self.app.add_data_to_viewer('spectrum-viewer', label)
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue/core/data_collection.py in __setitem__(self, key, data)
391 self.remove(existing_data)
392
--> 393 self.append(data)
394
395 def __iter__(self):
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue/core/data_collection.py in append(self, data)
80 s.register()
81 msg = DataCollectionAddMessage(self, data)
---> 82 self.hub.broadcast(msg)
83
84 self._sync_link_manager()
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue/core/hub.py in broadcast(self, message)
213 logging.getLogger(__name__).info("Broadcasting %s", message)
214 for subscriber, handler in self._find_handlers(message):
--> 215 handler(message)
216
217 def __getstate__(self):
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/jdaviz/app.py in _on_data_added(self, msg)
1022 the new data.
1023 """
-> 1024 self._link_new_data()
1025 data_item = self._create_data_item(msg.data.label)
1026 self.state.data_items.append(data_item)
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/jdaviz/app.py in _link_new_data(self)
257 continue
258 else:
--> 259 self.data_collection.add_link(LinkSame(wc_old[0], wc_new[0]))
260 break
261
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue/core/data_collection.py in add_link(self, links)
160 instances, or a :class:`~glue.core.link_helpers.LinkCollection`
161 """
--> 162 self._link_manager.add_link(links)
163
164 def remove_link(self, links):
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue/core/link_manager.py in add_link(self, link, update_external)
187 self._external_links.append(link)
188 if update_external:
--> 189 self.update_externally_derivable_components()
190
191 @contract(link=ComponentLink)
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue/core/link_manager.py in update_externally_derivable_components(self, data)
240 d = DerivedComponent(data, link)
241 comps[cid] = d
--> 242 data._set_externally_derivable_components(comps)
243
244 # Now update information about pixel-aligned data
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue/core/data.py in _set_externally_derivable_components(self, derivable_components)
1028 if self.hub:
1029 msg = ExternallyDerivableComponentsChangedMessage(self)
-> 1030 self.hub.broadcast(msg)
1031
1032 def _set_pixel_aligned_data(self, pixel_aligned_data):
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue/core/hub.py in broadcast(self, message)
213 logging.getLogger(__name__).info("Broadcasting %s", message)
214 for subscriber, handler in self._find_handlers(message):
--> 215 handler(message)
216
217 def __getstate__(self):
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue/viewers/common/viewer.py in _update_data(self, message)
271 else:
272 if layer_artist.layer is message.data:
--> 273 layer_artist.update()
274
275 def _update_subset(self, message):
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue_jupyter/table/viewer.py in update(self)
157
158 def update(self):
--> 159 self._refresh()
160
161 def clear(self):
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue_jupyter/table/viewer.py in _refresh(self)
151
152 def _refresh(self):
--> 153 self._table_viewer.redraw()
154
155 def redraw(self):
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue_jupyter/table/viewer.py in redraw(self)
204 self.widget_table.selections = [subset.label for subset in subsets]
205 self.widget_table.selection_colors = [subset.style.color for subset in subsets]
--> 206 self.widget_table._update()
207
208 def apply_filter(self):
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue_jupyter/table/viewer.py in _update(self)
29 def _update(self):
30 self._update_columns()
---> 31 self._update_items()
32 self.total_length = len(self)
33 self.options = {**self.options, 'totalItems': self.total_length}
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue_jupyter/table/viewer.py in _update_items(self)
68
69 def _update_items(self):
---> 70 self.items = self._get_items()
71
72 @traitlets.default('items')
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue_jupyter/table/viewer.py in _get_items(self)
127
128 view = slice(i1, i2)
--> 129 masks = {k.label: k.to_mask(view) for k in self.data.subsets}
130
131 items = []
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue_jupyter/table/viewer.py in <dictcomp>(.0)
127
128 view = slice(i1, i2)
--> 129 masks = {k.label: k.to_mask(view) for k in self.data.subsets}
130
131 items = []
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue/core/subset.py in to_mask(self, view)
180
181 """
--> 182 return self.data.get_mask(self.subset_state, view=view)
183
184 @contract(value=bool)
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue/core/data.py in get_mask(self, subset_state, view)
1383 def get_mask(self, subset_state, view=None):
1384 try:
-> 1385 return subset_state.to_mask(self, view=view)
1386 except IncompatibleAttribute:
1387 return get_mask_with_key_joins(self, self._key_joins, subset_state, view=view)
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue/core/subset.py in to_mask(self, data, view)
771 @contract(data='isinstance(Data)', view='array_view')
772 def to_mask(self, data, view=None):
--> 773 x = data[self.att, view]
774 result = (x >= self.lo) & (x <= self.hi)
775 return result
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue/core/data.py in __getitem__(self, key)
569 raise IncompatibleAttribute(_k)
570
--> 571 return self.get_data(key, view=view)
572
573 def _ipython_key_completions_(self):
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue/core/data.py in get_data(self, cid, view)
1362
1363 if view is not None:
-> 1364 result = comp[view]
1365 else:
1366 result = comp.data
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue/core/component.py in __getitem__(self, key)
196
197 def __getitem__(self, key):
--> 198 return self._link.compute(self._data, key)
199
200
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue/core/component_link.py in compute(self, data, view)
164
165 # First we get the values of all the 'from' components.
--> 166 args = [data[join_component_view(f, view)] for f in self._from]
167
168 # We keep track of the original shape of the arguments
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue/core/component_link.py in <listcomp>(.0)
164
165 # First we get the values of all the 'from' components.
--> 166 args = [data[join_component_view(f, view)] for f in self._from]
167
168 # We keep track of the original shape of the arguments
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue/core/data.py in __getitem__(self, key)
569 raise IncompatibleAttribute(_k)
570
--> 571 return self.get_data(key, view=view)
572
573 def _ipython_key_completions_(self):
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue/core/data.py in get_data(self, cid, view)
1362
1363 if view is not None:
-> 1364 result = comp[view]
1365 else:
1366 result = comp.data
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue/core/component.py in __getitem__(self, key)
196
197 def __getitem__(self, key):
--> 198 return self._link.compute(self._data, key)
199
200
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue/core/component_link.py in compute(self, data, view)
164
165 # First we get the values of all the 'from' components.
--> 166 args = [data[join_component_view(f, view)] for f in self._from]
167
168 # We keep track of the original shape of the arguments
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue/core/component_link.py in <listcomp>(.0)
164
165 # First we get the values of all the 'from' components.
--> 166 args = [data[join_component_view(f, view)] for f in self._from]
167
168 # We keep track of the original shape of the arguments
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue/core/data.py in __getitem__(self, key)
569 raise IncompatibleAttribute(_k)
570
--> 571 return self.get_data(key, view=view)
572
573 def _ipython_key_completions_(self):
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue/core/data.py in get_data(self, cid, view)
1362
1363 if view is not None:
-> 1364 result = comp[view]
1365 else:
1366 result = comp.data
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue/core/component.py in __getitem__(self, key)
196
197 def __getitem__(self, key):
--> 198 return self._link.compute(self._data, key)
199
200
~/miniconda3/envs/jwebbinar7/lib/python3.8/site-packages/glue/core/component_link.py in compute(self, data, view)
167
168 # We keep track of the original shape of the arguments
--> 169 original_shape = args[0].shape
170 logger.debug("shape of first argument: %s", original_shape)
171
IndexError: list index out of range
To Reproduce Steps to reproduce the behavior:
- Go to Model Fitting
- Click on 1DSpectrum (or Subset)
- Add a constant model component 'C'
- Enter 'C' in the Model Equation Editor
- Press 'Fit'
Expected behavior The model should be fitted and plotted in the spectrum viewer
Screenshots N/A Desktop (please complete the following information):
- OS: OSX 10.15.7
- Browser: safari
- Jupyter: [run "jupyter --version"] jupyter core : 4.7.1 jupyter-notebook : 6.4.0 qtconsole : 5.1.1 ipython : 7.25.0 ipykernel : 6.0.3 jupyter client : 6.1.12 jupyter lab : not installed nbconvert : 6.1.0 ipywidgets : 7.6.3 nbformat : 5.1.3 traitlets : 5.0.5
Package versions (please complete the following information):
macOS-10.15.7-x86_64-i386-64bit Python 3.8.10 | packaged by conda-forge | (default, May 10 2021, 22:58:09) [Clang 11.1.0 ] Numpy 1.21.1 astropy 4.3 specutils 1.3 spectral-cube 0.5.0 pyyaml 5.4.1 click 8.0.1 asteval 0.9.25 idna 2.10 traitlets 5.0.5 bqplot 0.12.30 bqplot-image-gl 1.4.3 glue-core 1.0.1 glue-jupyter 0.7 glue-astronomy 0.2 echo 0.5 ipyvue 1.5.0 ipyvuetify 1.8.0 ipysplitpanes 0.2.0 ipygoldenlayout 0.4.0 voila 0.2.10 vispy 0.7.3 Jdaviz 1.2.dev365+ge29b827
Additional context (e.g. data files) ERS NIRSpec MOS PRISM dataset with cutouts, jwst 1.1.0-processed
Model fitting works in Specviz and Cubeviz, but has never been attempted for an x1d in Mosviz.
This traceback looks similar to one we caught in #762. We should revisit this issue once that is merged
It looks like this error is because the linking code in app.py attempts to link to the first dataset when new data is loaded, which means it's trying to link the fitted spectrum to an image. @astrofrog pointed out recently that the linking there could cause problems and well, here's a problem!
I don't think this will be solved by #762, will probably require a couple extra lines of code in app.py to do the linking more intelligently. There's a comment that it "Link[s] to the first dataset with compatible coordinates", but it really links to the first dataset with any world coordinates. We should change it to do what the comment says!
Perhaps #811 can shed some light on this as well?
Maybe. I just tested with #762 and auto-link set to False and this still errors, with a (I think) slightly different trace. This looks like the error is cause by the glue-astronomy translator trying to get the mask attribute of the subset I'm fitting, but I haven't delved too deep into it yet.
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
~/opt/anaconda3/envs/viz_dev/lib/python3.9/site-packages/ipyvue/VueTemplateWidget.py in _handle_event(self, _, content, buffers)
55 getattr(self, 'vue_' + event)(data, buffers)
56 else:
---> 57 getattr(self, 'vue_' + event)(data)
58
59
~/projects/jdaviz/jdaviz/configs/default/plugins/model_fitting/model_fitting.py in vue_model_fitting(self, *args, **kwargs)
359 self._fitted_spectrum = fitted_spectrum
360
--> 361 self.vue_register_spectrum({"spectrum": fitted_spectrum})
362 self.app.fitted_models[self.model_label] = fitted_model
363
~/projects/jdaviz/jdaviz/configs/default/plugins/model_fitting/model_fitting.py in vue_register_spectrum(self, event)
500 self.data_collection[label] = spectrum
501
--> 502 self.app.add_data_to_viewer('spectrum-viewer', label)
~/projects/jdaviz/jdaviz/app.py in add_data_to_viewer(self, viewer_reference, data_path, clear_other_data, ext)
677 if data_id is not None:
678 data_ids.append(data_id)
--> 679 self._update_selected_data_items(viewer_item['id'], data_ids)
680 else:
681 raise ValueError(
~/projects/jdaviz/jdaviz/app.py in _update_selected_data_items(self, viewer_id, selected_items)
992 viewer_id=viewer_id,
993 sender=self)
--> 994 self.hub.broadcast(add_data_message)
995
996 # Remove any deselected data objects from viewer
~/projects/glue/glue/core/hub.py in broadcast(self, message)
213 logging.getLogger(__name__).info("Broadcasting %s", message)
214 for subscriber, handler in self._find_handlers(message):
--> 215 handler(message)
216
217 def __getstate__(self):
~/projects/jdaviz/jdaviz/configs/default/plugins/line_lists/line_lists.py in _on_viewer_data_changed(self, msg)
95
96 try:
---> 97 viewer_data = self.app.get_viewer('spectrum-viewer').data()
98 except TypeError:
99 warn_message = SnackbarMessage("Line list plugin could not retrieve data from viewer",
~/projects/jdaviz/jdaviz/configs/specviz/plugins/viewers.py in data(self, cls)
69 handler, _ = data_translator.get_handler_for(_class)
70 try:
---> 71 layer_data = handler.to_object(layer_data,
72 statistic=statistic)
73 except IncompatibleAttribute:
~/opt/anaconda3/envs/viz_dev/lib/python3.9/site-packages/glue_astronomy/translators/spectrum1d.py in to_object(self, data_or_subset, attribute, statistic)
142 return data_kwargs
143
--> 144 data_kwargs = parse_attributes(
145 [attribute] if not hasattr(attribute, '__len__') else attribute)
146
~/opt/anaconda3/envs/viz_dev/lib/python3.9/site-packages/glue_astronomy/translators/spectrum1d.py in parse_attributes(attributes)
109 mask = None
110 else:
--> 111 mask = data.get_mask(subset_state=subset_state)
112 mask = ~mask
113
~/projects/glue/glue/core/data.py in get_mask(self, subset_state, view)
1383 def get_mask(self, subset_state, view=None):
1384 try:
-> 1385 return subset_state.to_mask(self, view=view)
1386 except IncompatibleAttribute:
1387 return get_mask_with_key_joins(self, self._key_joins, subset_state, view=view)
~/projects/glue/glue/core/subset.py in to_mask(self, data, view)
771 @contract(data='isinstance(Data)', view='array_view')
772 def to_mask(self, data, view=None):
--> 773 x = data[self.att, view]
774 result = (x >= self.lo) & (x <= self.hi)
775 return result
~/projects/glue/glue/core/data.py in __getitem__(self, key)
569 raise IncompatibleAttribute(_k)
570
--> 571 return self.get_data(key, view=view)
572
573 def _ipython_key_completions_(self):
~/projects/glue/glue/core/data.py in get_data(self, cid, view)
1364 result = comp[view]
1365 else:
-> 1366 result = comp.data
1367
1368 return result
~/projects/glue/glue/core/component.py in data(self)
188 def data(self):
189 """ Return the numerical data as a numpy array """
--> 190 return self._link.compute(self._data)
191
192 @property
~/projects/glue/glue/core/component_link.py in compute(self, data, view)
164
165 # First we get the values of all the 'from' components.
--> 166 args = [data[join_component_view(f, view)] for f in self._from]
167
168 # We keep track of the original shape of the arguments
~/projects/glue/glue/core/component_link.py in <listcomp>(.0)
164
165 # First we get the values of all the 'from' components.
--> 166 args = [data[join_component_view(f, view)] for f in self._from]
167
168 # We keep track of the original shape of the arguments
~/projects/glue/glue/core/data.py in __getitem__(self, key)
569 raise IncompatibleAttribute(_k)
570
--> 571 return self.get_data(key, view=view)
572
573 def _ipython_key_completions_(self):
~/projects/glue/glue/core/data.py in get_data(self, cid, view)
1364 result = comp[view]
1365 else:
-> 1366 result = comp.data
1367
1368 return result
~/projects/glue/glue/core/component.py in data(self)
188 def data(self):
189 """ Return the numerical data as a numpy array """
--> 190 return self._link.compute(self._data)
191
192 @property
~/projects/glue/glue/core/component_link.py in compute(self, data, view)
167
168 # We keep track of the original shape of the arguments
--> 169 original_shape = args[0].shape
170 logger.debug("shape of first argument: %s", original_shape)
171
IndexError: list index out of range
For future reference, I tried patching glue-astronomy in glue-viz/glue-astronomy#39 (to fix Cubeviz) but Tom said glue-astronomy is doing the right thing by raising exception, so it is up to Jdaviz to catch it.
@PatrickOgle As I mentioned offline, I still see an error with some of the older simulated NIRSPEC data, but with the most recent simulated dataset the model fitting appears to work fine. Are you ok with closing this issue given that it seems to have been a now-fixed problem with the old simulated data?
I will have to see it work in my Jwebbinar notebook to be convinced...