Skip to content

Commit

Permalink
first pass at sb -> angle drop down changes
Browse files Browse the repository at this point in the history
  • Loading branch information
gibsongreen committed Jul 23, 2024
1 parent 069dbbc commit a5eaeb7
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 56 deletions.
80 changes: 31 additions & 49 deletions jdaviz/configs/specviz/plugins/unit_conversion/unit_conversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
create_flux_equivalencies_list,
create_sb_equivalencies_list,
check_if_unit_is_per_solid_angle,
units_to_strings)
units_to_strings,
create_angle_equivalencies_list)

__all__ = ['UnitConversion']

Expand Down Expand Up @@ -61,8 +62,10 @@ class UnitConversion(PluginTemplateMixin):
flux_unit_items = List().tag(sync=True)
flux_unit_selected = Unicode().tag(sync=True)

sb_unit_items = List().tag(sync=True)
sb_unit_selected = Unicode().tag(sync=True)
sb_unit = Unicode().tag(sync=True)

angle_unit_items = List().tag(sync=True)
angle_unit_selected = Unicode().tag(sync=True)

flux_or_sb_items = List().tag(sync=True)
flux_or_sb_selected = Unicode().tag(sync=True)
Expand Down Expand Up @@ -107,10 +110,10 @@ def __init__(self, *args, **kwargs):
self.flux_unit = UnitSelectPluginComponent(self,
items='flux_unit_items',
selected='flux_unit_selected')

self.sb_unit = UnitSelectPluginComponent(self,
items='sb_unit_items',
selected='sb_unit_selected')
self.angle_unit = UnitSelectPluginComponent(self,
items='angle_unit_items',
selected='angle_unit_selected')

@property
def user_api(self):
Expand Down Expand Up @@ -140,7 +143,7 @@ def _on_glue_x_display_unit_changed(self, x_unit):
# which would then be appended on to the list of choices going forward
self.spectral_unit._addl_unit_strings = self.spectrum_viewer.state.__class__.x_display_unit.get_choices(self.spectrum_viewer.state) # noqa
self.spectral_unit.selected = x_unit
if not len(self.flux_unit.choices) or not len(self.sb_unit.choices):
if not len(self.flux_unit.choices) or not len(self.angle_unit.choices):
# in case flux_unit was triggered first (but could not be set because there
# as no spectral_unit to determine valid equivalencies)
self._on_glue_y_display_unit_changed(self.spectrum_viewer.state.y_display_unit)
Expand Down Expand Up @@ -171,29 +174,19 @@ def _on_glue_y_display_unit_changed(self, y_unit):
if not np.any([y_u == u.Unit(choice) for choice in flux_choices]):
flux_choices = [y_unit] + flux_choices

if self.app.config == 'cubeviz':
sb_choices = create_sb_equivalencies_list(y_u / u.sr, x_u)
self.sb_unit.choices = sb_choices
if y_unit + ' / sr' in self.sb_unit.choices:
self.sb_unit.selected = y_unit + ' / sr'

self.flux_unit.choices = flux_choices
self.flux_unit.selected = y_unit
self.flux_or_sb.selected = 'Flux'

elif flux_or_sb == 'Surface Brightness' and y_unit != self.sb_unit.selected:
sb_choices = create_sb_equivalencies_list(y_u, x_u)

# ensure that original entry is in the list of choices
if not np.any([y_u == u.Unit(choice) for choice in sb_choices]):
sb_choices = [y_unit] + sb_choices


### TODO
elif flux_or_sb == 'Surface Brightness' and y_unit != (self.flux_unit.selected + ' \ ' + self.angle_unit.selected):
if self.app.config == 'cubeviz':
flux_choices = create_flux_equivalencies_list(y_u * u.sr, x_u)
self.flux_unit.choices = flux_choices

self.sb_unit.choices = sb_choices
self.sb_unit.selected = y_unit
if self.app.data_collection[0]:
self.angle_unit.choices = create_angle_equivalencies_list(self.app.data_collection[0].get_object()._unit)
self.angle_unit.selected = self.angle_unit.choices[0]
self.sb_unit = self.flux_unit.selected + " / " + self.angle_unit.selected

@observe('spectral_unit_selected')
def _on_spectral_unit_changed(self, *args):
Expand All @@ -204,15 +197,14 @@ def _on_spectral_unit_changed(self, *args):
self.spectral_unit.selected,
sender=self))

@observe('flux_or_sb_selected', 'flux_unit_selected', 'sb_unit_selected')
@observe('flux_or_sb_selected', 'flux_unit_selected')
def _on_flux_unit_changed(self, msg):
# may need to be updated if translations in other configs going to be supported
if not hasattr(self, 'flux_unit'):
return
if not self.flux_unit.choices and self.app.config == 'cubeviz':
return
flux_or_sb = None
current_y = self.spectrum_viewer.state.y_display_unit

data_collection_unit = ''
# need to determine the input spectrum units to disable the additional
Expand All @@ -232,6 +224,9 @@ def _on_flux_unit_changed(self, msg):
name = msg.get('name')
# determine if flux or surface brightness unit was changed by user
if name == 'flux_unit_selected':
with open('example.txt', 'a') as file:
if self.app.data_collection and len(self.app.data_collection) > 0:
file.write(f'select flux unit \n')
# when the configuration is Specviz, translation is not currently supported.
# If in Cubeviz, all spectra pass through Spectral Extraction plugin and will
# have a scale factor assigned in the metadata, enabling translation.
Expand All @@ -241,10 +236,6 @@ def _on_flux_unit_changed(self, msg):
f"is not supported in {self.app.config}."
)
flux_or_sb = self.flux_unit.selected
# update flux or surface brightness dropdown if necessary
if check_if_unit_is_per_solid_angle(current_y):
self._translate('Flux')
self.flux_or_sb.selected = 'Flux'
untranslatable_units = self._untranslatable_units
# disable translator if flux unit is untranslatable,
# still can convert flux units, this just disables flux
Expand All @@ -253,22 +244,6 @@ def _on_flux_unit_changed(self, msg):
self.can_translate = False
else:
self.can_translate = True

elif name == 'sb_unit_selected':
if data_collection_unit == 'Flux':
# when the configuration is Specviz, translation is not currently supported.
# If in Cubeviz, all spectra pass through Spectral Xxtraction plugin and will
# have a scale factor assigned in the metadata, enabling translation.
raise ValueError(
"Unit translation between Flux and Surface Brightness "
f"is not supported in {self.app.config}."
)
flux_or_sb = self.sb_unit.selected
self.can_translate = True
# update flux or surface brightness dropdown if necessary
if not check_if_unit_is_per_solid_angle(current_y):
self._translate('Surface Brightness')
self.flux_or_sb.selected = 'Surface Brightness'
elif name == 'flux_or_sb_selected':
self._translate(self.flux_or_sb_selected)
return
Expand All @@ -283,6 +258,10 @@ def _on_flux_unit_changed(self, msg):
flux_or_sb,
sender=self))
self.spectrum_viewer.reset_limits()

with open('example.txt', 'a') as file:
if self.app.data_collection and len(self.app.data_collection) > 0:
file.write(f'post flux unit \n')

if (
len(self.app.data_collection) > 0
Expand All @@ -295,6 +274,9 @@ def _translate(self, flux_or_sb=None):
if self.app.config == 'specviz':
return

with open('example.txt', 'a') as file:
if self.app.data_collection:
file.write(f'{self.flux_or_sb_selected}\n')
# we want to raise an error if a user tries to translate with an
# untranslated Flux unit using the API
untranslatable_units = self._untranslatable_units
Expand All @@ -321,15 +303,15 @@ def _translate(self, flux_or_sb=None):
spec_units *= u.sr
# update display units
self.spectrum_viewer.state.y_display_unit = str(spec_units)
self.flux_or_sb.selected = 'Flux'
#self.flux_or_sb.selected = 'Flux'

# Flux -> Surface Brightness
elif (not check_if_unit_is_per_solid_angle(spec_units)
and flux_or_sb == 'Surface Brightness'):
spec_units /= u.sr
# update display units
self.spectrum_viewer.state.y_display_unit = str(spec_units)
self.flux_or_sb.selected = 'Surface Brightness'
#self.flux_or_sb.selected = 'Surface Brightness'
# entered the translator when we shouldn't translate
else:
return
Expand Down
22 changes: 15 additions & 7 deletions jdaviz/configs/specviz/plugins/unit_conversion/unit_conversion.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,27 @@
persistent-hint
></v-select>
</v-row>

<v-row v-if="flux_or_sb_config_disabler === 'Flux' || config == 'cubeviz'">
<v-row v-if="flux_or_sb_config_disabler === 'Surface Brightness' || config == 'cubeviz'">
<v-select
:menu-props="{ left: true }"
attach
:items="sb_unit_items.map(i => i.label)"
v-model="sb_unit_selected"
:items="angle_unit_items.map(i => i.label)"
v-model="angle_unit_selected"
label="Solid Angle Unit"
hint="Solid angle unit."
persistent-hint
></v-select>
</v-row>

<v-row v-if="flux_or_sb_config_disabler === 'Flux' || config == 'cubeviz'">
<v-text-field
v-model="sb_unit"
label="Surface Brightness Unit"
hint="Global display unit for surface brightness axis."
persistent-hint
:disabled="!can_translate"
></v-select>
<span v-if="!can_translate">Translation is not available due to current unit selection.</span>
:disabled='true'
></v-text-field>
</v-row>

<v-row v-if="config == 'cubeviz'">
Expand Down
20 changes: 20 additions & 0 deletions jdaviz/core/validunits.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,26 @@ def create_sb_equivalencies_list(sb_unit, spectral_axis_unit):
# Concatenate both lists with the local units coming first.
return sorted(units_to_strings(local_units)) + sb_unit_equivalencies_titles

def create_angle_equivalencies_list(unit):
# first, convert string to u.Unit obj.
# this will take care of some formatting consistency like
# turning something like Jy / (degree*degree) to Jy / deg**2
# and erg sr^1 to erg / sr
if isinstance(unit, u.core.Unit) or isinstance(unit, u.core.CompositeUnit):
unit_str = unit.to_string()
elif isinstance(unit, str):
unit = u.Unit(unit)
unit_str = unit.to_string()
else:
raise ValueError('Unit must be u.Unit, or string that can be converted into a u.Unit')

if '/' in unit_str:
# might be comprised of several units in denom.
denom = unit_str.split('/')[-1].split()
return denom
else:
# this could be where force / u.pix
return ['pix']

def check_if_unit_is_per_solid_angle(unit):
"""
Expand Down
3 changes: 3 additions & 0 deletions jdaviz/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,9 @@ def flux_conversion(spec, values, original_units, target_units):
if (('_pixel_scale_factor' in spec.meta) and
(((u.sr in orig_bases) and (u.sr not in targ_bases)) or
((u.sr not in orig_bases) and (u.sr in targ_bases)))):
with open('example.txt', 'a') as file:
file.write(f'utils {original_units}\n')
file.write(f'utils {target_units}\n')
# Data item in data collection does not update from conversion/translation.
# App-wide original data units are used for conversion, original and
# target_units dictate the conversion to take place.
Expand Down

0 comments on commit a5eaeb7

Please sign in to comment.