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

PoC: Sonified layer in flux viewer #3430

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions jdaviz/configs/cubeviz/plugins/sonify_data/sonify_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@ def vue_sonify_cube(self, *args):
self.audfrqmax, self.eln, self.use_pccut)

# Automatically select spectrum-at-spaxel tool
spec_at_spaxel_tool = self.flux_viewer.toolbar.tools['jdaviz:spectrumperspaxel']
self.flux_viewer.toolbar.active_tool = spec_at_spaxel_tool
# spec_at_spaxel_tool = self.flux_viewer.toolbar.tools['jdaviz:spectrumperspaxel']
# self.flux_viewer.toolbar.active_tool = spec_at_spaxel_tool

def vue_start_stop_stream(self, *args):
self.stream_active = not self.stream_active
Expand Down
77 changes: 75 additions & 2 deletions jdaviz/configs/cubeviz/plugins/viewers.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import uuid

from glue.core import BaseData
from glue_jupyter.bqplot.image import BqplotImageView
import numpy as np
from astropy import units as u
from astropy.nddata import CCDData
from astropy.wcs import WCS

from jdaviz.core.registries import viewer_registry
from jdaviz.configs.cubeviz.plugins.mixins import WithSliceIndicator, WithSliceSelection
from jdaviz.configs.default.plugins.viewers import JdavizViewerMixin
from jdaviz.configs.specviz.plugins.viewers import SpecvizProfileView
from jdaviz.core.freezable_state import FreezableBqplotImageViewerState
from jdaviz.configs.cubeviz.plugins.cube_listener import CubeListenerData, MINVOL
import numpy as np
from astropy import units as u


try:
import sounddevice as sd
Expand Down Expand Up @@ -45,6 +50,10 @@
self._subscribe_to_layers_update()
self.state.add_callback('reference_data', self._initial_x_axis)

self.add_event_callback(self._viewer_mouse_event, events=['mousemove',
'mouseleave',
'mouseenter'])

# Hide axes by default
self.state.show_axes = False

Expand All @@ -58,6 +67,11 @@

self.data_menu._obj.dataset.add_filter('is_cube_or_image')

# Dictionary that contains keys with UUIDs for each
# sonified data layer. The value of each key is another dictionary containing
# integers as keys and arrays representing sounds as the value.
self.uuid_lookup = {}

@property
def _default_spectrum_viewer_reference_name(self):
return self.jdaviz_helper._default_spectrum_viewer_reference_name
Expand Down Expand Up @@ -114,6 +128,20 @@
self.sonified_cube.newsig = self.sonified_cube.sigcube[x, y, :]
self.sonified_cube.cbuff = True

def update_sonified_cube_value(self, value):
if (not self.sonified_cube or not hasattr(self.sonified_cube, 'newsig') or

Check warning on line 132 in jdaviz/configs/cubeviz/plugins/viewers.py

View check run for this annotation

Codecov / codecov/patch

jdaviz/configs/cubeviz/plugins/viewers.py#L132

Added line #L132 was not covered by tests
not hasattr(self.sonified_cube, 'sigcube')):
return

Check warning on line 134 in jdaviz/configs/cubeviz/plugins/viewers.py

View check run for this annotation

Codecov / codecov/patch

jdaviz/configs/cubeviz/plugins/viewers.py#L134

Added line #L134 was not covered by tests
# Loop through all sonified layers and
# set newsig to the sound for each layer
# Do we need to change the sonified_cube/sonified_cube.newsig
# code to be compatible with multiple sonified cubes?
for k, v in self.uuid_lookup.items():
if value not in v:
continue
self.sonified_cube.newsig = v[value]
self.sonified_cube.cbuff = True

Check warning on line 143 in jdaviz/configs/cubeviz/plugins/viewers.py

View check run for this annotation

Codecov / codecov/patch

jdaviz/configs/cubeviz/plugins/viewers.py#L139-L143

Added lines #L139 - L143 were not covered by tests

def update_listener_wls(self, wranges, wunit):
self.sonification_wl_ranges = wranges
self.sonification_wl_unit = wunit
Expand Down Expand Up @@ -180,6 +208,51 @@
callback=self.sonified_cube.player_callback)
self.sonified_cube.cbuff = True

x_size = self.sonified_cube.sigcube.shape[0]
y_size = self.sonified_cube.sigcube.shape[1]

Check warning on line 212 in jdaviz/configs/cubeviz/plugins/viewers.py

View check run for this annotation

Codecov / codecov/patch

jdaviz/configs/cubeviz/plugins/viewers.py#L211-L212

Added lines #L211 - L212 were not covered by tests

# Create a new entry for the sonified layer in uuid_lookup. The value is a dictionary
# containing x_size * y_size keys with values being arrays that represent sounds
data_name = str(uuid.uuid4())
self.uuid_lookup[data_name] = {x*y: self.sonified_cube.sigcube[x-1, y-1, :]

Check warning on line 217 in jdaviz/configs/cubeviz/plugins/viewers.py

View check run for this annotation

Codecov / codecov/patch

jdaviz/configs/cubeviz/plugins/viewers.py#L216-L217

Added lines #L216 - L217 were not covered by tests
for x in range(1, x_size + 1)
for y in range(1, y_size + 1)}

# Create a 2D array with integers starting at 1 and going until x_size * y_size
# TODO: instead of a dictionary inside another dictionary, we could continue the numbering
# for subsequent layers and use a dictionary to map ints to sound arrays
a = np.arange(1, x_size * y_size + 1).reshape((x_size, y_size))

Check warning on line 224 in jdaviz/configs/cubeviz/plugins/viewers.py

View check run for this annotation

Codecov / codecov/patch

jdaviz/configs/cubeviz/plugins/viewers.py#L224

Added line #L224 was not covered by tests

wcs = WCS({'CTYPE1': 'RA---TAN', 'CUNIT1': 'deg', 'CDELT1': -0.0002777777778,

Check warning on line 226 in jdaviz/configs/cubeviz/plugins/viewers.py

View check run for this annotation

Codecov / codecov/patch

jdaviz/configs/cubeviz/plugins/viewers.py#L226

Added line #L226 was not covered by tests
'CRPIX1': 1, 'CRVAL1': 337.5202808,
'CTYPE2': 'DEC--TAN', 'CUNIT2': 'deg', 'CDELT2': 0.0002777777778,
'CRPIX2': 1, 'CRVAL2': -20.833333059999998})

# Create add data with name data_name to data collection and then add it to the flux viewer
test = CCDData(a * u.Unit('m'), wcs=wcs)
self.jdaviz_app.data_collection[data_name] = test
self.jdaviz_app.add_data_to_viewer('flux-viewer', data_name)

Check warning on line 234 in jdaviz/configs/cubeviz/plugins/viewers.py

View check run for this annotation

Codecov / codecov/patch

jdaviz/configs/cubeviz/plugins/viewers.py#L232-L234

Added lines #L232 - L234 were not covered by tests

# Set opacity to 0 and start the stream to hear sound when mousing over the flux viewer
self.state.layers[-1].alpha = 0
self.start_stream()

Check warning on line 238 in jdaviz/configs/cubeviz/plugins/viewers.py

View check run for this annotation

Codecov / codecov/patch

jdaviz/configs/cubeviz/plugins/viewers.py#L237-L238

Added lines #L237 - L238 were not covered by tests

def _viewer_mouse_event(self, data):
if data['event'] in ('mouseleave', 'mouseenter'):
return

Check warning on line 242 in jdaviz/configs/cubeviz/plugins/viewers.py

View check run for this annotation

Codecov / codecov/patch

jdaviz/configs/cubeviz/plugins/viewers.py#L241-L242

Added lines #L241 - L242 were not covered by tests

if len(self.jdaviz_app.data_collection) < 1:
return

Check warning on line 245 in jdaviz/configs/cubeviz/plugins/viewers.py

View check run for this annotation

Codecov / codecov/patch

jdaviz/configs/cubeviz/plugins/viewers.py#L244-L245

Added lines #L244 - L245 were not covered by tests

# Extract data coordinates - these are pixels in the reference image
x = data['domain']['x']
y = data['domain']['y']

Check warning on line 249 in jdaviz/configs/cubeviz/plugins/viewers.py

View check run for this annotation

Codecov / codecov/patch

jdaviz/configs/cubeviz/plugins/viewers.py#L248-L249

Added lines #L248 - L249 were not covered by tests

if x is None or y is None or int(x) < 0 or int(y) < 0: # Out of bounds
return
index = (int(x)+1) * (int(y)+1)
self.update_sonified_cube_value(index)

Check warning on line 254 in jdaviz/configs/cubeviz/plugins/viewers.py

View check run for this annotation

Codecov / codecov/patch

jdaviz/configs/cubeviz/plugins/viewers.py#L251-L254

Added lines #L251 - L254 were not covered by tests


@viewer_registry("cubeviz-profile-viewer", label="Profile 1D (Cubeviz)")
class CubevizProfileView(SpecvizProfileView, WithSliceIndicator):
Expand Down
Loading