Skip to content

Commit c5e3449

Browse files
author
James Trayford
committed
Patches:
- Fix sigcube alignment with other cubes [get rid of transpose] - Add percentile cut option that enables some rough feature isolation without full continuum subtraction - Protect against cubes w/NaNs
1 parent 11c73a9 commit c5e3449

File tree

4 files changed

+38
-15
lines changed

4 files changed

+38
-15
lines changed

jdaviz/configs/cubeviz/plugins/cube_listener.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,30 +74,30 @@ def __init__(self, cube, wlens, samplerate=44100, duration=1, overlap=0.05, buff
7474
if self.cursig.nbytes * pow(1024,-3) > 2:
7575
raise Exception("Cube projected to be > 2Gb!")
7676

77-
self.sigcube = np.zeros((self.siglen, *self.cube.shape[1:]), dtype='int16')
77+
self.sigcube = np.zeros((*self.cube.shape[:2], self.siglen), dtype='int16')
7878

7979
def audify_cube(self, fmin=50, fmax=1500):
8080
"""
8181
Iterate through the cube, convert each spectrum to a signal, and store
8282
in class attributes
8383
"""
8484
lo2hi = self.wlens.argsort()[::-1]
85-
for i in tqdm(range(self.cube.shape[1])):
86-
for j in range(self.cube.shape[2]):
85+
for i in tqdm(range(self.cube.shape[0])):
86+
for j in range(self.cube.shape[1]):
8787
with suppress_stderr():
88-
sig = audify_spectrum(self.cube[lo2hi,i,j], self.dur,
88+
sig = audify_spectrum(self.cube[i,j,lo2hi], self.dur,
8989
srate=self.srate,
9090
fmin=fmin, fmax=fmax)
9191
sig = (sig*self.maxval).astype('int16')
92-
self.sigcube[:,i,j] = sig
93-
self.cursig[:] = self.sigcube[:,self.idx1,self.idx2]
92+
self.sigcube[i,j,:] = sig
93+
self.cursig[:] = self.sigcube[self.idx1,self.idx2, :]
9494
self.newsig[:] = self.cursig[:]
9595

9696
def player_callback(self, outdata, frames, time, status):
9797
cur = self.cursig
9898
new = self.newsig
9999
sdx = int(time.outputBufferDacTime*self.srate)
100-
dxs = np.arange(sdx, sdx+frames).astype(int) % self.sigcube.shape[0]
100+
dxs = np.arange(sdx, sdx+frames).astype(int) % self.sigcube.shape[-1]
101101
if self.cbuff:
102102
outdata[:,0] = (cur[dxs] * self.ofade).astype('int16')
103103
outdata[:,0] += (new[dxs] * self.ifade).astype('int16')

jdaviz/configs/cubeviz/plugins/sonify_data/sonify_data.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ class SonifyData(PluginTemplateMixin, DatasetSelectMixin):
1616
ssvidx = FloatHandleEmpty(0.65).tag(sync=True)
1717
wavemin = FloatHandleEmpty(15800).tag(sync=True)
1818
wavemax = FloatHandleEmpty(16000).tag(sync=True)
19-
19+
pccut = IntHandleEmpty(20).tag(sync=True)
20+
2021
def __init__(self, *args, **kwargs):
2122
super().__init__(*args, **kwargs)
2223

2324
def vue_sonify_cube(self, *args):
2425
viewer = self.app.get_viewer('flux-viewer')
25-
viewer.get_sonified_cube(self.sample_rate, self.buffer_size, self.assidx, self.ssvidx)
26+
viewer.get_sonified_cube(self.sample_rate, self.buffer_size, self.assidx, self.ssvidx, self.pccut)

jdaviz/configs/cubeviz/plugins/sonify_data/sonify_data.vue

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
persistent-hint
7272
></v-text-field>
7373
</v-row>
74-
<v-row>
74+
<v-row>
7575
<v-text-field
7676
ref="wavemax"
7777
type="number"
@@ -81,6 +81,17 @@
8181
persistent-hint
8282
></v-text-field>
8383
</v-row>
84+
<v-row>
85+
<v-text-field
86+
ref="pccut"
87+
type="number"
88+
label="Flux Percentile Cut"
89+
v-model.number="pccut"
90+
hint="The minimum flux percentile to be heard."
91+
persistent-hint
92+
></v-text-field>
93+
</v-row>
94+
8495
<v-row>
8596
<plugin-action-button
8697
@click="sonify_cube"

jdaviz/configs/cubeviz/plugins/viewers.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -242,18 +242,29 @@ def stop_stream(self):
242242
def update_cube(self, x, y):
243243
if not self.audified_cube or not hasattr(self.audified_cube, 'newsig') or not hasattr(self.audified_cube, 'sigcube'):
244244
return
245-
self.audified_cube.newsig = self.audified_cube.sigcube[:, x, y]
245+
self.audified_cube.newsig = self.audified_cube.sigcube[x, y, :]
246246
self.audified_cube.cbuff = True
247247

248-
def get_sonified_cube(self, sample_rate, buffer_size, assidx, ssvidx):
248+
def get_sonified_cube(self, sample_rate, buffer_size, assidx, ssvidx, pccut):
249249
spectrum = self.active_image_layer.layer.get_object(statistic=None)
250+
pc_cube = np.percentile(np.nan_to_num(spectrum.flux.value), np.clip(pccut,0,99), axis=-1)
250251

251-
clipped_arr = np.clip(spectrum.flux.value.T, 0, np.inf)
252-
# arr = spectrum[wavemin:wavemax].flux.value.T
252+
# clip zeros and remove NaNs
253+
clipped_arr = np.nan_to_num(np.clip(spectrum.flux.value, 0, np.inf), copy=False)
254+
255+
# make a rough white-light image from the clipped array
256+
whitelight = np.expand_dims(clipped_arr.sum(-1), axis=2)
257+
258+
# subtract any percentile cut
259+
clipped_arr -= np.expand_dims(pc_cube, axis=2)
260+
261+
# and re-clip
262+
clipped_arr = np.clip(clipped_arr, 0, np.inf)
263+
253264
self.audified_cube = CubeListenerData(clipped_arr ** assidx, spectrum.wavelength.value, duration=0.8,
254265
samplerate=sample_rate, buffsize=buffer_size)
255266
self.audified_cube.audify_cube()
256-
self.audified_cube.sigcube = (self.audified_cube.sigcube * pow(clipped_arr.sum(0) / clipped_arr.sum(0).max(), ssvidx)).astype('int16')
267+
self.audified_cube.sigcube = (self.audified_cube.sigcube * pow(whitelight / whitelight.max(), ssvidx)).astype('int16')
257268
self.stream = sd.OutputStream(samplerate=sample_rate, blocksize=buffer_size, channels=1, dtype='int16', latency='low',
258269
callback=self.audified_cube.player_callback)
259270
self.audified_cube.cbuff = True

0 commit comments

Comments
 (0)