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

Photometric Extraction plugin #115

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
3 changes: 2 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

* Prevent duplicate sub-intervals (quarter/sector/campaign) in data labels. [#120]

* Photometric extraction plugin. [#115]

* Add feature to query the NASA Exoplanet Archive for exoplanet ephemerides. [#127]

0.4.3 (09.05.2024)
Expand Down Expand Up @@ -41,7 +43,6 @@
* Default data labels no longer include flux-origin, but do include quarter/campaign/sector. [#111]

* Basic stitch plugin to combine light curves into a single entry. [#107]

* Metadata plugin: show undefined entries as empty string instead of object repr. [#108]

* Raise error when parser can't identify file_obj [#106]
Expand Down
33 changes: 33 additions & 0 deletions docs/plugins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,39 @@ The time selector plugin allows defining the time indicated in all light curve v
Jdaviz documentation on the Slice plugin.


.. _photometric-extraction:

Photometric Extraction
======================

Note that this plugin is only available if TPF data is loaded into the app.

.. admonition:: User API Example
:class: dropdown

See the :class:`~lcviz.plugins.stitch.stitch.Stitch` user API documentation for more details.

.. code-block:: python

from lcviz import LCviz
from lightkurve import search_targetpixelfile
tpf = search_targetpixelfile("KIC 001429092",
mission="Kepler",
cadence="long",
quarter=10).download()
lcviz = LCviz()
lcviz.load_data(tpf)
lcviz.show()

ext = lcviz.plugins['Photometric Extraction']
ext.open_in_tray()


.. seealso::

This plugin uses the following ``lightkurve`` implementations:

* :meth:`lightkurve.KeplerTargetPixelFile.extract_aperture_photometry`

.. _stitch:

Expand Down
3 changes: 3 additions & 0 deletions docs/reference/api_plugins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ Plugins API
.. automodapi:: lcviz.plugins.metadata_viewer.metadata_viewer
:no-inheritance-diagram:

.. automodapi:: lcviz.plugins.photometric_extraction.photometric_extraction
:no-inheritance-diagram:

.. automodapi:: lcviz.plugins.plot_options.plot_options
:no-inheritance-diagram:

Expand Down
2 changes: 1 addition & 1 deletion lcviz/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ class LCviz(ConfigHelper):
'toolbar': ['g-data-tools', 'g-subset-tools', 'g-viewer-creator', 'lcviz-coords-info'],
'tray': ['lcviz-metadata-viewer', 'flux-column',
'lcviz-plot-options', 'lcviz-subset-plugin',
'lcviz-markers', 'time-selector',
'lcviz-markers', 'time-selector', 'photometric-extraction',
'stitch', 'flatten', 'frequency-analysis', 'ephemeris',
'binning', 'lcviz-export'],
'viewer_area': [{'container': 'col',
Expand Down
1 change: 1 addition & 0 deletions lcviz/plugins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from .markers.markers import * # noqa
from .time_selector.time_selector import * # noqa
from .metadata_viewer.metadata_viewer import * # noqa
from .photometric_extraction.photometric_extraction import * # noqa
from .plot_options.plot_options import * # noqa
from .stitch.stitch import * # noqa
from .subset_plugin.subset_plugin import * # noqa
1 change: 1 addition & 0 deletions lcviz/plugins/photometric_extraction/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .photometric_extraction import * # noqa
98 changes: 98 additions & 0 deletions lcviz/plugins/photometric_extraction/photometric_extraction.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
from astropy import units as u
from traitlets import Bool, Unicode, observe
from lightkurve import LightCurve

from jdaviz.core.registries import tray_registry
from jdaviz.configs.cubeviz.plugins import SpectralExtraction
from jdaviz.core.user_api import PluginUserApi


__all__ = ['PhotometricExtraction']


@tray_registry('photometric-extraction', label="Photometric Extraction")
class PhotometricExtraction(SpectralExtraction):
"""
See the :ref:`Photometric Extraction Plugin Documentation <photometric-extraction>`
for more details.

Only the following attributes and methods are available through the
:ref:`public plugin API <plugin-apis>`:

* :meth:`~jdaviz.core.template_mixin.PluginTemplateMixin.show`
* :meth:`~jdaviz.core.template_mixin.PluginTemplateMixin.open_in_tray`
* :meth:`~jdaviz.core.template_mixin.PluginTemplateMixin.close_in_tray`
* ``dataset`` (:class:`~jdaviz.core.template_mixin.DatasetSelect`):
Dataset to extract.
* ``add_results`` (:class:`~jdaviz.core.template_mixin.AddResults`)
* :meth:`extract`
"""
resulting_product_name = Unicode("light curve").tag(sync=True)
do_auto_extraction = False
wavelength_dependent_available = Bool(False).tag(sync=True)
bg_export_available = Bool(False).tag(sync=True)

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.docs_link = f"https://lcviz.readthedocs.io/en/{self.vdocs}/plugins.html#photometric-extraction" # noqa
self.docs_description = "Extract light curve from target pixel file cube." # noqa

def is_tpf(data):
return len(data.shape) == 3
self.dataset.filters = [is_tpf]

# only allow for Sum
self.function._manual_options = ['Sum']
self.function.items = [{"label": "Sum"}]

self._set_relevant() # move upstream?

@property
def user_api(self):
expose = ['dataset', 'aperture',
'background',
'add_results', 'extract',
'aperture_method']

return PluginUserApi(self, expose=expose)

@observe('dataset_items')
def _set_relevant(self, *args):
# NOTE: upstream will set disabled_msg to something similar, but mentioning
if len(self.dataset_items) < 1:
self.irrelevant_msg = 'Requires at least one TPF cube to be loaded'
else:
self.irrelevant_msg = ''

def _on_global_display_unit_changed(self, msg=None):
if msg is None:
self.flux_units = str(self.app._get_display_unit('flux'))
self.time_units = str(self.app._get_display_unit('time'))
elif msg.axis == 'flux':
self.flux_units = str(msg.unit)
elif msg.axis == 'time':
self.time_units = str(msg.unit)
else:
# ignore
return
# update results_units based on flux_units, sb_units, and currently selected function
self._update_results_units()

@property
def slice_display_unit_name(self):
return 'time'

@property
def spatial_axes(self):
return (1, 2)

def _return_extracted(self, cube, wcs, collapsed_nddata):
lc = LightCurve(time=cube.get_object(LightCurve).time, flux=collapsed_nddata.data)
return lc

def _preview_x_from_extracted(self, extracted):
return extracted.time.value - self.dataset.selected_obj.meta.get('reference_time',
0.0 * u.d).value

def _preview_y_from_extracted(self, extracted):
return extracted.flux.value
55 changes: 55 additions & 0 deletions lcviz/plugins/photometric_extraction/photometric_extraction.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<template>
<j-tray-plugin
description='Extract light curve from TPF data.'
:link="'https://lcviz.readthedocs.io/en/'+vdocs+'/plugins.html#photometric-extraction'"
:uses_active_status="uses_active_status"
@plugin-ping="plugin_ping($event)"
:keep_active.sync="keep_active"
:popout_button="popout_button">

<v-row>
<v-expansion-panels popout>
<v-expansion-panel>
<v-expansion-panel-header v-slot="{ open }">
<span style="padding: 6px">Settings</span>
</v-expansion-panel-header>
<v-expansion-panel-content>
<v-row>
<v-switch
v-model="show_live_preview"
label="Show live preview"
hint="Whether to show live preview of binning options."
persistent-hint
></v-switch>
</v-row>
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
</v-row>

<plugin-dataset-select
:items="dataset_items"
:selected.sync="dataset_selected"
:show_if_single_entry="false"
label="Data"
hint="Select the TPF as input."
/>

<plugin-add-results
:label.sync="results_label"
:label_default="results_label_default"
:label_auto.sync="results_label_auto"
:label_invalid_msg="results_label_invalid_msg"
:label_overwrite="results_label_overwrite"
label_hint="Label for the extracted light curve."
:add_to_viewer_items="add_to_viewer_items"
:add_to_viewer_selected.sync="add_to_viewer_selected"
action_label="Extract"
action_tooltip="Extract photometry"
:action_disabled="!apply_enabled"
:action_spinner="spinner"
@click:action="apply"
></plugin-add-results>

</j-tray-plugin>
</template>
14 changes: 14 additions & 0 deletions lcviz/plugins/plot_options/plot_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
from traitlets import observe
from jdaviz.configs.default.plugins import PlotOptions
from jdaviz.core.registries import tray_registry
from jdaviz.utils import get_subset_type

from lcviz.viewers import CubeView

__all__ = ['PlotOptions']

Expand Down Expand Up @@ -33,6 +36,17 @@ class PlotOptions(PlotOptions):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

def not_spatial_subset_in_scatter_viewer(lyr):
# note: have to check the classname instead of isinstance to avoid circular import
if np.any([isinstance(viewer, CubeView)
for viewer in self.layer.viewer_objs]):
return True
# at this point, NO selected viewers are TPF Cube viewers,
# so we want to exclude spatial subsets
return get_subset_type(lyr) != 'spatial'

self.layer.add_filter(not_spatial_subset_in_scatter_viewer)

@observe('vdocs')
def _update_docs_link(self, *args):
self.docs_link = f"https://lcviz.readthedocs.io/en/{self.vdocs}/plugins.html#plot-options"
Expand Down
3 changes: 2 additions & 1 deletion lcviz/plugins/stitch/stitch.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,15 @@ def __init__(self, *args, **kwargs):
self.dataset.add_filter(data_not_folded, is_not_tpf)

self.results_label_default = 'stitched'
self._set_relevant()

@property
def user_api(self):
expose = ['dataset', 'stitch', 'remove_input_datasets', 'add_results']
return PluginUserApi(self, expose=expose)

@observe('dataset_items')
def _set_relevent(self, *args):
def _set_relevant(self, *args):
if len(self.dataset_items) < 2:
self.irrelevant_msg = 'Requires at least two datasets loaded into viewers'
else:
Expand Down
2 changes: 1 addition & 1 deletion lcviz/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ def to_data(self, obj, reference_time=None, unit=u.d):
data[cid] = component_data
if hasattr(component_data, 'unit'):
try:
data.get_component(cid).units = str(component_data.unit)
data.get_component(cid).units = str(component_data.unit/u.pix**2)
except KeyError: # pragma: no cover
continue

Expand Down
14 changes: 14 additions & 0 deletions lcviz/viewers.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,13 @@ def _apply_layer_defaults(self, layer_state):
layer_state.size = 5
layer_state.points_mode = 'markers'

def _layer_included_in_legend(self, layer, subset_type):
print("***", layer.layer.label, subset_type)
if subset_type == 'spatial':
# do not show spatial subsets in time or phase viewers
return False
return super()._layer_included_in_legend(layer, subset_type)

def set_plot_axes(self):
# set which components should be plotted
dc = self.jdaviz_app.data_collection
Expand Down Expand Up @@ -361,6 +368,13 @@ def _on_layers_update(self, layers=None):
if hasattr(layer, 'attribute') and layer.attribute != flux_comp:
layer.attribute = flux_comp

def _layer_included_in_legend(self, layer, subset_type):
print("***", layer.layer.label, subset_type)
if subset_type == 'spectral': # NOTE: spectral here means xrange (i.e. not spatial)
# ONLY show spatial subsets in image/cube viewer
return False
return super()._layer_included_in_legend(layer, subset_type)

def data(self, cls=None):
# TODO: generalize upstream in jdaviz.
# This method is generalized from
Expand Down
Loading