Skip to content

Commit

Permalink
store ephemeris information in viewer instead of relying on name
Browse files Browse the repository at this point in the history
  • Loading branch information
kecnry committed Mar 7, 2024
1 parent f9e1d8f commit 3277d4d
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 81 deletions.
25 changes: 25 additions & 0 deletions lcviz/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,31 @@ def get_data(self, data_label=None, cls=LightCurve, subset=None):
"""
return super()._get_data(data_label=data_label, mask_subset=subset, cls=cls)

@property
def _tray_tools(self):
"""
Access API objects for plugins in the app toolbar.
Returns
-------
plugins : dict
dict of plugin objects
"""
# TODO: provide user-friendly labels, user API, and move upstream to be public
# for now this is just useful for dev-debugging access to toolbar entries
from ipywidgets.widgets import widget_serialization
return {item['name']: widget_serialization['from_json'](item['widget'], None)
for item in self.app.state.tool_items}

def _get_clone_viewer_reference(self, reference):
base_name = reference.split("[")[0]
name = base_name
ind = 0
while name in self.viewers.keys():
ind += 1
name = f"{base_name}[{ind}]"
return name

def _phase_comp_lbl(self, component):
return f'phase:{component}'

Expand Down
10 changes: 6 additions & 4 deletions lcviz/parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from jdaviz.core.registries import data_parser_registry
import lightkurve

from lcviz.viewers import PhaseScatterView

__all__ = ["light_curve_parser"]


Expand Down Expand Up @@ -45,10 +47,10 @@ def light_curve_parser(app, file_obj, data_label=None, show_in_viewer=True, **kw
app.add_data_to_viewer(time_viewer_reference_name, new_data_label)

# add to any known phase viewers
ephem_plugin = app._jdaviz_helper.plugins.get('Ephemeris', None)
if ephem_plugin is not None:
for viewer_id in ephem_plugin._obj.phase_viewer_ids:
app.add_data_to_viewer(viewer_id, new_data_label)
for viewer_id, viewer in app._viewer_store.items():
if not isinstance(viewer, PhaseScatterView):
continue
app.add_data_to_viewer(viewer_id, new_data_label)


def _data_with_reftime(app, light_curve):
Expand Down
79 changes: 42 additions & 37 deletions lcviz/plugins/ephemeris/ephemeris.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,20 +143,17 @@ def _phase_comp_lbl(self, component=None):
def phase_comp_lbl(self):
return self._phase_comp_lbl()

def _phase_viewer_id(self, component=None):
def _generate_phase_viewer_id(self, component=None):
if component is None:
component = self.component_selected
return f'flux-vs-phase:{component}'
return self.app._jdaviz_helper._get_clone_viewer_reference(f'flux-vs-phase:{component}')

@property
def phase_viewer_ids(self):
viewer_ids = self.app.get_viewer_ids()
return [self._phase_viewer_id(component) for component in self.component.choices
if self._phase_viewer_id(component) in viewer_ids]

@property
def phase_viewer_id(self):
return self._phase_viewer_id()
def _get_phase_viewers(self, lbl=None):
if lbl is None:
lbl = self.component_selected
return [viewer for vid, viewer in self.app._viewer_store.items()
if isinstance(viewer, PhaseScatterView)
and viewer._ephemeris_component == lbl]

@property
def default_phase_viewer(self):
Expand All @@ -166,13 +163,6 @@ def default_phase_viewer(self):
# ephemeris component
return self._get_phase_viewers()[0]

def _get_phase_viewers(self, lbl=None):
if lbl is None:
lbl = self.component_selected
return [viewer for vid, viewer in self.app._viewer_store.items()
if isinstance(viewer, PhaseScatterView)
and viewer.ephemeris_component == lbl]

@property
def ephemerides(self):
return self._ephemerides
Expand Down Expand Up @@ -290,7 +280,8 @@ def create_phase_viewer(self, ephem_component=None):
ephem_component : str, optional
label of the component. If not provided or ``None``, will default to plugin value.
"""
phase_viewer_id = self._phase_viewer_id(ephem_component)
if ephem_component is None:
ephem_component = self.component_selected
phase_comp_lbl = self._phase_comp_lbl(ephem_component)
dc = self.app.data_collection

Expand All @@ -300,26 +291,37 @@ def create_phase_viewer(self, ephem_component=None):
if phase_comp_lbl not in [comp.label for comp in dc[0].components]:
self.update_ephemeris() # calls _update_all_phase_arrays

create_phase_viewer = len(self._get_phase_viewers(ephem_component)) == 0
if create_phase_viewer:
# TODO: stack horizontally by default?
self.app._on_new_viewer(NewViewerMessage(PhaseScatterView, data=None, sender=self.app),
vid=phase_viewer_id, name=phase_viewer_id)

time_viewer_item = self.app._get_viewer_item(self.app._jdaviz_helper._default_time_viewer_reference_name) # noqa
for data in dc:
data_id = self.app._data_id_from_label(data.label)
visible = time_viewer_item['selected_data_items'].get(data_id, 'hidden')
self.app.set_data_visibility(phase_viewer_id, data.label, visible == 'visible')
phase_viewer_id = self._generate_phase_viewer_id(ephem_component)
# TODO: stack horizontally by default?
self.app._on_new_viewer(NewViewerMessage(PhaseScatterView, data=None, sender=self.app),
vid=phase_viewer_id, name=phase_viewer_id)

# access new viewer, set bookkeeping for ephemeris component
pv = self.app.get_viewer(phase_viewer_id)
if create_phase_viewer:
pv.state.x_min, pv.state.x_max = (self.wrap_at-1, self.wrap_at)
pv.state.x_att = self.app._jdaviz_helper._component_ids[phase_comp_lbl]
pv._ephemeris_component = ephem_component
# since we couldn't set ephemeris_component right away, _check_if_phase_viewer_exists
# might be out-of-date
self._check_if_phase_viewer_exists()

# set default data visibility
time_viewer_item = self.app._get_viewer_item(self.app._jdaviz_helper._default_time_viewer_reference_name) # noqa
for data in dc:
data_id = self.app._data_id_from_label(data.label)
visible = time_viewer_item['selected_data_items'].get(data_id, 'hidden')
self.app.set_data_visibility(phase_viewer_id, data.label, visible == 'visible')

# set x_att
phase_comp = self.app._jdaviz_helper._component_ids[phase_comp_lbl]
pv.state.x_att = phase_comp

# set viewer limits
pv.state.x_min, pv.state.x_max = (self.wrap_at-1, self.wrap_at)

return pv.user_api

def vue_create_phase_viewer(self, *args):
self.create_phase_viewer()
if not self.phase_viewer_exists:
self.create_phase_viewer()

def vue_period_halve(self, *args):
self.period /= 2
Expand Down Expand Up @@ -350,6 +352,7 @@ def _on_component_rename(self, old_lbl, new_lbl):
viewer._ref_or_id.replace(old_lbl, new_lbl),
update_id=True
)
viewer._ephemeris_component = new_lbl

# update metadata entries so that they can be used for filtering applicable entries in
# data menus
Expand Down Expand Up @@ -465,7 +468,8 @@ def round_to_1(x):
return round(x, -int(np.floor(np.log10(abs(x)))))

# if phase-viewer doesn't yet exist in the app, create it now
self.create_phase_viewer()
if not self.phase_viewer_exists:
self.create_phase_viewer()

# update value in the dictionary (to support multi-ephems)
if event:
Expand All @@ -478,9 +482,10 @@ def round_to_1(x):
if event.get('name') == 'wrap_at':
old = event.get('old') if event.get('old') != '' else self._prev_wrap_at
if event.get('new') != '':
pvs = self.default_phase_viewer.state
delta_phase = event.get('new') - old
pvs.x_min, pvs.x_max = pvs.x_min + delta_phase, pvs.x_max + delta_phase
for pv in self._get_phase_viewers():
pvs = pv.state
pvs.x_min, pvs.x_max = pvs.x_min + delta_phase, pvs.x_max + delta_phase
# we need to cache the old value since it could become a string
# if the widget is cleared
self._prev_wrap_at = event.get('new')
Expand Down
27 changes: 8 additions & 19 deletions lcviz/plugins/viewer_creator/viewer_creator.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from jdaviz.configs.default.plugins import ViewerCreator
from jdaviz.core.registries import tool_registry, viewer_registry
from lcviz.events import EphemerisComponentChangedMessage
from lcviz.viewers import ephem_component_from_phase_viewer_name

__all__ = ['ViewerCreator']

Expand All @@ -21,33 +20,23 @@ def _rebuild_available_viewers(self, *args):
# and label (what appears in dropdown and the default label of the viewer)

if self.app._jdaviz_helper is not None:
phase_viewers = [{'name': 'lcviz-phase-viewer', 'label': f'flux-vs-phase:{e}'}
phase_viewers = [{'name': f'lcviz-phase-viewer:{e}', 'label': f'flux-vs-phase:{e}'}
for e in self.app._jdaviz_helper.plugins['Ephemeris'].component.choices] # noqa
else:
phase_viewers = []

self.viewer_types = [v for v in self.viewer_types if v['name'].startswith('lcviz')
and v['label'] != 'flux-vs-phase'] + phase_viewers
and not v['label'].startswith('flux-vs-phase')] + phase_viewers
self.send_state('viewer_types')

def vue_create_viewer(self, name):
for viewer_item in self.viewer_types:
if viewer_item['name'] == name:
label = viewer_item['label']
break
else:
label = viewer_registry.members[name]['label']

if label in self.app._jdaviz_helper.viewers:
# clone whenever possible
# TODO: update this to not rely directly on the label for phase-viewers, but rather
# checking for the same ephemeris
self.app._jdaviz_helper.viewers[label]._obj.clone_viewer()
return

if name == 'lcviz-phase-viewer':
ephem_comp = ephem_component_from_phase_viewer_name(label)
if name.startswith('lcviz-phase-viewer') or name.startswith('flux-vs-phase'):
ephem_comp = name.split(':')[1]
ephem_plg = self.app._jdaviz_helper.plugins['Ephemeris']
ephem_plg.create_phase_viewer(ephem_comp)
return
if name == 'flux-vs-time':
# allow passing label and map to the name for upstream support
name = 'lcviz-time-viewer'

super().vue_create_viewer(name)
31 changes: 10 additions & 21 deletions lcviz/viewers.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,7 @@
from lightkurve import LightCurve


__all__ = ['TimeScatterView', 'PhaseScatterView', 'ephem_component_from_phase_viewer_name']


def ephem_component_from_phase_viewer_name(label):
return label.split('[')[0].split(':')[-1]
__all__ = ['TimeScatterView', 'PhaseScatterView']


@viewer_registry("lcviz-time-viewer", label="flux-vs-time")
Expand Down Expand Up @@ -214,17 +210,8 @@ 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()
name = self.jdaviz_helper._get_clone_viewer_reference(self.reference)

self.jdaviz_app._on_new_viewer(NewViewerMessage(self.__class__,
data=None,
Expand All @@ -240,7 +227,9 @@ def clone_viewer(self):
# 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
new_viewer = self.jdaviz_app.get_viewer(name)
if hasattr(self, 'ephemeris_component'):
new_viewer._ephemeris_component = self._ephemeris_component
for k, v in this_state.items():
if k in ('layers',):
continue
Expand All @@ -251,13 +240,13 @@ def clone_viewer(self):

@viewer_registry("lcviz-phase-viewer", label="flux-vs-phase")
class PhaseScatterView(TimeScatterView):
@property
def ephemeris_component(self):
return ephem_component_from_phase_viewer_name(self.reference)
def __init__(self, *args, **kwargs):
self._ephemeris_component = 'default'
super().__init__(*args, **kwargs)

def _set_plot_x_axes(self, dc, component_labels, light_curve):
# setting of y_att will be handled by ephemeris plugin
self.state.x_att = dc[0].components[component_labels.index(f'phase:{self.ephemeris_component}')] # noqa
self.state.x_att = dc[0].components[component_labels.index(f'phase:{self._ephemeris_component}')] # noqa
self.figure.axes[0].label = 'phase'
self.figure.axes[0].num_ticks = 5

Expand All @@ -266,4 +255,4 @@ def times_to_phases(self, times):
if ephem is None:
raise ValueError("must have ephemeris plugin loaded to convert")

return ephem.times_to_phases(times, ephem_component=self.ephemeris_component)
return ephem.times_to_phases(times, ephem_component=self._ephemeris_component)

0 comments on commit 3277d4d

Please sign in to comment.