Skip to content

Commit

Permalink
WIP: Glue unit conversion in Jdaviz. [ci skip] [rtd skip]
Browse files Browse the repository at this point in the history
Co-authored-by: Jesse Averbukh <javerbukh@gmail.com>
  • Loading branch information
pllim and javerbukh committed Feb 28, 2023
1 parent c29db28 commit b1d9e91
Show file tree
Hide file tree
Showing 11 changed files with 219 additions and 28 deletions.
30 changes: 30 additions & 0 deletions jdaviz/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from ipywidgets import widget_serialization
import ipyvue

from astropy import units as u
from astropy.nddata import CCDData, NDData
from astropy.io import fits

Expand All @@ -32,6 +33,7 @@
SubsetDeleteMessage)
from glue.core.state_objects import State
from glue.core.subset import Subset, RangeSubsetState, RoiSubsetState
from glue.core.units import unit_converter
from glue_astronomy.spectral_coordinates import SpectralCoordinates
from glue_jupyter.app import JupyterApplication
from glue_jupyter.common.toolbar_vuetify import read_icon
Expand Down Expand Up @@ -62,10 +64,38 @@
mask=['mask', 'dq'])


@unit_converter('custom-jdaviz')
class UnitConverterWithSpectral:

def equivalent_units(self, data, cid, units):
if cid.label == "flux":
eqv = u.spectral_density(1 * u.m) # Value does not matter here.
else: # spectral axis
eqv = u.spectral()
return map(str, u.Unit(units).find_equivalent_units(
include_prefix_units=True, equivalencies=eqv))

def to_unit(self, data, cid, values, original_units, target_units):
# Given a glue data object (data), a component ID (cid), the values
# to convert, and the original and target units of the values, this method
# should return the converted values. Note that original_units
# gives the units of the values array, which might not be the same
# as the original native units of the component in the data.
if cid.label == "flux":
spec = data.get_object(cls=Spectrum1D)
eqv = u.spectral_density(spec.spectral_axis)
else: # spectral axis
eqv = u.spectral()
return (values * u.Unit(original_units)).to_value(u.Unit(target_units), equivalencies=eqv)


# Set default opacity for data layers to 1 instead of 0.8 in
# some glue-core versions
glue_settings.DATA_ALPHA = 1

# Enable spectrum unit conversion.
glue_settings.UNIT_CONVERTER = 'custom-jdaviz'

custom_components = {'j-tooltip': 'components/tooltip.vue',
'j-external-link': 'components/external_link.vue',
'j-docs-link': 'components/docs_link.vue',
Expand Down
2 changes: 0 additions & 2 deletions jdaviz/configs/default/plugins/viewers.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,6 @@ def _get_layer_info(layer):
return "mdi-chart-bell-curve", ""
return "", suffix

return '', ''

visible_layers = {}
for layer in self.state.layers[::-1]:
if layer.visible:
Expand Down
5 changes: 4 additions & 1 deletion jdaviz/configs/imviz/plugins/coords_info/coords_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,10 @@ def _spectrum_viewer_update(self, viewer, x, y):
self.row3_title = 'Flux'
self.row3_text = f'{closest_flux.value:10.5e} {closest_flux.unit.to_string()}'

self.icon = closest_icon
if closest_icon is not None:
self.icon = closest_icon
else:
self.icon = ""

self.marks[viewer._reference_id].update_xy([closest_wave.value], [closest_flux.value]) # noqa
self.marks[viewer._reference_id].visible = True
12 changes: 0 additions & 12 deletions jdaviz/configs/specviz/plugins/parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,6 @@ def specviz_spectrum1d_parser(app, data, data_label=None, format=None, show_in_v
raise ValueError(f"Length of data labels list ({len(data_label)}) is different"
f" than length of list of data ({len(data)})")

# If there's already data in the viewer, convert units if needed
current_unit = None
if spectrum_viewer_reference_name in app.get_viewer_reference_names():
current_spec = app.get_data_from_viewer(spectrum_viewer_reference_name)
if current_spec != {} and current_spec is not None:
spec_key = list(current_spec.keys())[0]
current_unit = current_spec[spec_key].spectral_axis.unit

with app.data_collection.delay_link_manager_update():
# these are used to build a combined spectrum with all
# input spectra included (taken from https://github.com/spacetelescope/
Expand All @@ -98,10 +90,6 @@ def specviz_spectrum1d_parser(app, data, data_label=None, format=None, show_in_v
wave_units = spec.spectral_axis.unit
flux_units = spec.flux.unit

if current_unit is not None and spec.spectral_axis.unit != current_unit:
spec = Spectrum1D(flux=spec.flux,
spectral_axis=spec.spectral_axis.to(current_unit))

# Make metadata layout conform with other viz.
spec.meta = standardize_metadata(spec.meta)

Expand Down
17 changes: 11 additions & 6 deletions jdaviz/configs/specviz/plugins/unit_conversion/unit_conversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,18 @@ def update_ui(self, event=None):
if spectrum is None:
return

# Set UI label to show current flux and spectral axis units.
self.current_flux_unit = spectrum.flux.unit.to_string()
self.current_spectral_axis_unit = spectrum.spectral_axis.unit.to_string()
viewer = self.app.get_viewer(self._default_spectrum_viewer_reference_name)

# Populate drop down with all valid options for unit conversion.
self.spectral_axis_unit_equivalencies = create_spectral_equivalencies_list(spectrum)
self.flux_unit_equivalencies = create_flux_equivalencies_list(spectrum)
# 1. Set UI label to show current flux and spectral axis units.
# 2. Populate drop down with all valid options for unit conversion.

if viewer.state.y_display_unit is not None:
self.current_flux_unit = viewer.state.y_display_unit
self.flux_unit_equivalencies = create_flux_equivalencies_list(spectrum)

if viewer.state.x_display_unit is not None:
self.current_spectral_axis_unit = viewer.state.x_display_unit
self.spectral_axis_unit_equivalencies = create_spectral_equivalencies_list(spectrum)

def vue_unit_conversion(self, *args, **kwargs):
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<j-tray-plugin
description='Convert the spectral flux density and spectral axis units.'
:link="'https://jdaviz.readthedocs.io/en/'+vdocs+'/'+config+'/plugins.html#unit-conversion'"
disabled_msg="This plugin is temporarily disabled. Effort to improve it is being tracked at GitHub Issue 1972."
:disabled_msg="disabled_msg"
:popout_button="popout_button">

<!-- for mosviz, the entries change on row change, so we want to always show the dropdown
Expand Down
11 changes: 8 additions & 3 deletions jdaviz/configs/specviz/plugins/viewers.py
Original file line number Diff line number Diff line change
Expand Up @@ -479,20 +479,25 @@ def set_plot_axes(self):

# Set axes labels for the spectrum viewer
spectral_axis_unit_type = str(data.spectral_axis.unit.physical_type).title()
# flux_unit_type = data.flux.unit.physical_type.title()
spectral_axis_unit_str = data.spectral_axis.unit.to_string()
flux_unit_type = "Flux density"
flux_unit_str = data.flux.unit.to_string()

if data.spectral_axis.unit.is_equivalent(u.m):
spectral_axis_unit_type = "Wavelength"
elif data.spectral_axis.unit.is_equivalent(u.pixel):
spectral_axis_unit_type = "pixel"

label_0 = f"{spectral_axis_unit_type} [{data.spectral_axis.unit.to_string()}]"
label_0 = f"{spectral_axis_unit_type} [{spectral_axis_unit_str}]"
self.figure.axes[0].label = label_0
self.figure.axes[1].label = f"{flux_unit_type} [{data.flux.unit.to_string()}]"
self.figure.axes[1].label = f"{flux_unit_type} [{flux_unit_str}]"

# Make it so y axis label is not covering tick numbers.
self.figure.axes[1].label_offset = "-50"

# Set Y-axis to scientific notation
self.figure.axes[1].tick_format = '0.1e'

# Register display units for Glue unit conversion.
self.state.y_display_unit = flux_unit_str
self.state.x_display_unit = spectral_axis_unit_str
2 changes: 1 addition & 1 deletion jdaviz/configs/specviz/specviz.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ tray:
- g-subset-plugin
- g-gaussian-smooth
- g-model-fitting
- g-unit-conversion
#- g-unit-conversion
- g-line-list
- specviz-line-analysis
- g-export-plot
Expand Down
2 changes: 1 addition & 1 deletion jdaviz/core/freezable_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
__all__ = ['FreezableState', 'FreezableProfileViewerState', 'FreezableBqplotImageViewerState']


class FreezableState():
class FreezableState:
_frozen_state = []

def __setattr__(self, k, v):
Expand Down
1 change: 0 additions & 1 deletion jdaviz/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from collections import deque

import matplotlib.pyplot as plt

from astropy.io import fits
from ipyvue import watch
from glue.config import settings
Expand Down
163 changes: 163 additions & 0 deletions notebooks/concepts/specviz_glue_unit_conversion.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "57c41ae5",
"metadata": {},
"source": [
"This is a concept notebook to investigate Glue unit conversion behavior integrated into Jdaviz spectrum viewer."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2b3bbfb1",
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"from astropy import units as u\n",
"from specutils import Spectrum1D\n",
"\n",
"from jdaviz import Specviz"
]
},
{
"cell_type": "markdown",
"id": "0d253733",
"metadata": {},
"source": [
"First spectrum."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "cba69bb7",
"metadata": {},
"outputs": [],
"source": [
"wave1 = np.linspace(2, 5, 10) * u.um\n",
"flux1 = [1, 2, 3, 4, 5, 5, 4, 3, 2, 1] * u.Jy\n",
"spec1 = Spectrum1D(flux=flux1, spectral_axis=wave1)\n",
"\n",
"print(wave1)\n",
"print(flux1)"
]
},
{
"cell_type": "markdown",
"id": "1e0e7dc5",
"metadata": {},
"source": [
"Second spectrum in different units and with slight offsets in spectral axis."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "26bc794d",
"metadata": {},
"outputs": [],
"source": [
"wave2 = (wave1 + (0.1 * u.um)).to(u.GHz, u.spectral())\n",
"flux2 = flux1.to(u.mJy)\n",
"spec2 = Spectrum1D(flux=flux2, spectral_axis=wave2)\n",
"\n",
"print(wave2)\n",
"print(wave2.to(u.um, u.spectral()))\n",
"print(flux2)"
]
},
{
"cell_type": "markdown",
"id": "2bb4f4ea",
"metadata": {},
"source": [
"Fire up Specviz."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "74692a02",
"metadata": {},
"outputs": [],
"source": [
"specviz = Specviz()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "efdba701",
"metadata": {},
"outputs": [],
"source": [
"specviz.show()"
]
},
{
"cell_type": "markdown",
"id": "642fbae1",
"metadata": {},
"source": [
"Load the data into Specviz. Desired behavior:\n",
"\n",
"1. \"Jy_um\" would load with Jy in Y-axis and um in X-axis.\n",
"2. \"mJy_GHz\" would load with data automatically converted to Jy and um in the plot. You would see the same shape but slightly offset in X-axis, just slightly."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5ee09160",
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"specviz.load_data(spec1, data_label=\"Jy_um\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9655292b",
"metadata": {},
"outputs": [],
"source": [
"specviz.load_data(spec2, data_label=\"mJy_GHz\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ed8974c9",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.8"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

0 comments on commit b1d9e91

Please sign in to comment.