-
Notifications
You must be signed in to change notification settings - Fork 10
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
TPF viewer #81
TPF viewer #81
Changes from 8 commits
408b89b
5391845
761961f
e2bc30a
0df19b2
4711c6e
8a703ae
fb656fa
35de766
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,19 +12,55 @@ | |
|
||
from jdaviz.core.events import NewViewerMessage | ||
from jdaviz.core.registries import viewer_registry | ||
from jdaviz.configs.cubeviz.plugins.viewers import CubevizImageView | ||
from jdaviz.configs.default.plugins.viewers import JdavizViewerMixin | ||
from jdaviz.configs.specviz.plugins.viewers import SpecvizProfileView | ||
|
||
from lcviz.state import ScatterViewerState | ||
|
||
from lightkurve import LightCurve | ||
from lightkurve import LightCurve, KeplerTargetPixelFile | ||
|
||
__all__ = ['TimeScatterView', 'PhaseScatterView', 'CubeView'] | ||
|
||
__all__ = ['TimeScatterView', 'PhaseScatterView'] | ||
|
||
class CloneViewerMixin: | ||
def _get_clone_viewer_reference(self): | ||
base_name = self.reference.split("[")[0] | ||
name = base_name | ||
ind = 0 | ||
while name in self.jdaviz_helper.viewers.keys(): | ||
ind += 1 | ||
name = f"{base_name}[{ind}]" | ||
return name | ||
|
||
def clone_viewer(self): | ||
name = self._get_clone_viewer_reference() | ||
|
||
self.jdaviz_app._on_new_viewer(NewViewerMessage(self.__class__, | ||
data=None, | ||
sender=self.jdaviz_app), | ||
vid=name, name=name) | ||
|
||
this_viewer_item = self.jdaviz_app._get_viewer_item(self.reference) | ||
this_state = self.state.as_dict() | ||
for data in self.jdaviz_app.data_collection: | ||
data_id = self.jdaviz_app._data_id_from_label(data.label) | ||
visible = this_viewer_item['selected_data_items'].get(data_id, 'hidden') | ||
self.jdaviz_app.set_data_visibility(name, data.label, visible == 'visible') | ||
# TODO: don't revert color when adding same data to a new viewer | ||
# (same happens when creating a phase-viewer from ephemeris plugin) | ||
|
||
new_viewer = self.jdaviz_helper.viewers[name]._obj | ||
for k, v in this_state.items(): | ||
if k in ('layers',): | ||
continue | ||
setattr(new_viewer.state, k, v) | ||
|
||
return new_viewer.user_api | ||
|
||
|
||
@viewer_registry("lcviz-time-viewer", label="flux-vs-time") | ||
class TimeScatterView(JdavizViewerMixin, BqplotScatterView): | ||
class TimeScatterView(JdavizViewerMixin, CloneViewerMixin, BqplotScatterView): | ||
# categories: zoom resets, zoom, pan, subset, select tools, shortcuts | ||
tools_nested = [ | ||
['jdaviz:homezoom', 'jdaviz:prevzoom'], | ||
|
@@ -43,7 +79,6 @@ def __init__(self, *args, **kwargs): | |
|
||
self.display_mask = False | ||
self.time_unit = kwargs.get('time_unit', u.d) | ||
self._subscribe_to_layers_update() | ||
self.initialize_toolbar() | ||
self._subscribe_to_layers_update() | ||
# hack to inherit a small subset of methods from SpecvizProfileView | ||
|
@@ -210,40 +245,6 @@ def apply_roi(self, roi, use_current=False): | |
|
||
super().apply_roi(roi, use_current=use_current) | ||
|
||
def _get_clone_viewer_reference(self): | ||
base_name = self.reference.split("[")[0] | ||
name = base_name | ||
ind = 0 | ||
while name in self.jdaviz_helper.viewers.keys(): | ||
ind += 1 | ||
name = f"{base_name}[{ind}]" | ||
return name | ||
|
||
def clone_viewer(self): | ||
name = self._get_clone_viewer_reference() | ||
|
||
self.jdaviz_app._on_new_viewer(NewViewerMessage(self.__class__, | ||
data=None, | ||
sender=self.jdaviz_app), | ||
vid=name, name=name) | ||
|
||
this_viewer_item = self.jdaviz_app._get_viewer_item(self.reference) | ||
this_state = self.state.as_dict() | ||
for data in self.jdaviz_app.data_collection: | ||
data_id = self.jdaviz_app._data_id_from_label(data.label) | ||
visible = this_viewer_item['selected_data_items'].get(data_id, 'hidden') | ||
self.jdaviz_app.set_data_visibility(name, data.label, visible == 'visible') | ||
# TODO: don't revert color when adding same data to a new viewer | ||
# (same happens when creating a phase-viewer from ephemeris plugin) | ||
|
||
new_viewer = self.jdaviz_helper.viewers[name]._obj | ||
for k, v in this_state.items(): | ||
if k in ('layers',): | ||
continue | ||
setattr(new_viewer.state, k, v) | ||
|
||
return new_viewer.user_api | ||
|
||
|
||
@viewer_registry("lcviz-phase-viewer", label="phase-vs-time") | ||
class PhaseScatterView(TimeScatterView): | ||
|
@@ -263,3 +264,61 @@ def times_to_phases(self, times): | |
raise ValueError("must have ephemeris plugin loaded to convert") | ||
|
||
return ephem.times_to_phases(times, ephem_component=self.ephemeris_component) | ||
|
||
|
||
@viewer_registry("lcviz-cube-viewer", label="cube") | ||
class CubeView(CloneViewerMixin, CubevizImageView): | ||
# categories: zoom resets, zoom, pan, subset, select tools, shortcuts | ||
tools_nested = [ | ||
['jdaviz:homezoom', 'jdaviz:prevzoom'], | ||
['jdaviz:boxzoom'], | ||
['jdaviz:panzoom'], | ||
['bqplot:rectangle'], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there anything stopping us from allowing other ROI shapes at this point? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not really, but we'll have to see what we want to support for actual photometric extraction (and if we want sub-pixel support or not). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed, but even rectangle ROIs aren't required to have 100% overlap with the pixel grid. I don't see a difference with other shapes in that sense. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. right, we might decide to just do pixel-by-pixel masking if we don't want sub-pixel at all. Let's consider this when we write the extraction plugin - as of now the subsets don't do anything but I just wanted at least something to show up in the menu to test that they are created succesfully. |
||
['jdaviz:sidebar_plot', 'jdaviz:sidebar_export'] | ||
] | ||
# TODO: can we vary this default_class based on Kepler vs TESS, etc? | ||
default_class = KeplerTargetPixelFile | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Curious to check in on this. Does the mission specificity matter in the viewer class? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah, I wasn't sure what to do with this 🤔 . Ultimately this is just for the default and the user can override, but maybe its better to just have as None and require the user to pass a class? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done and linked a comment back here if we ever want to revisit. |
||
|
||
def __init__(self, *args, **kwargs): | ||
super().__init__(*args, **kwargs) | ||
|
||
self.display_mask = False | ||
self.time_unit = kwargs.get('time_unit', u.d) | ||
self.initialize_toolbar() | ||
self._subscribe_to_layers_update() | ||
|
||
# Hide axes by default | ||
self.state.show_axes = False | ||
Comment on lines
+291
to
+292
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just commenting that I like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ah, yes, that was mostly for debugging and confirming the mouseover information, I don't think we'd want that in any public-facing example. |
||
|
||
# TODO: refactor upstream so lcviz can inherit cubeviewer methods/setup with jdaviz-specific | ||
# logic: | ||
# * _default_spectrum_viewer_reference_name | ||
# * _default_flux_viewer_reference_name | ||
# * _default_uncert_viewer_reference_name | ||
|
||
def _initial_x_axis(self, *args): | ||
# Make sure that the x_att/y_att is correct on data load | ||
# called via a callback set upstream in CubevizImageView when reference_data is changed | ||
ref_data = self.state.reference_data | ||
if ref_data is not None: | ||
self.state.x_att = ref_data.id['Pixel Axis 2 [x]'] | ||
self.state.y_att = ref_data.id['Pixel Axis 1 [y]'] | ||
|
||
def _on_layers_update(self, layers=None): | ||
super()._on_layers_update(layers=layers) | ||
ref_data = self.state.reference_data | ||
if ref_data is None: | ||
return | ||
flux_comp = ref_data.id['flux'] | ||
for layer in self.state.layers: | ||
if hasattr(layer, 'attribute') and layer.attribute != flux_comp: | ||
layer.attribute = flux_comp | ||
|
||
def data(self, cls=None): | ||
# TODO: generalize upstream in jdaviz. | ||
# This method is generalized from | ||
# jdaviz/configs/cubeviz/plugins/viewers.py | ||
return [layer_state.layer | ||
for layer_state in self.state.layers | ||
if hasattr(layer_state, 'layer') and | ||
isinstance(layer_state.layer, BaseData)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good name. 😊