Skip to content

Commit

Permalink
Improve behavior of PV slicing tool, and fix implementation of PVSlic…
Browse files Browse the repository at this point in the history
…edData.compute.fixed_resolution_buffer to ensure that multiple sliced datasets can be shown at the same time
  • Loading branch information
astrofrog committed Oct 28, 2021
1 parent a907fe4 commit 0273542
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 26 deletions.
69 changes: 66 additions & 3 deletions glue/plugins/tools/pv_slicer/pv_sliced_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,70 @@ def compute_statistic(self, *args, view=None, **kwargs):
def compute_histogram(self, *args, **kwargs):
return self.original_data.compute_histogram(*args, **kwargs)

def compute_fixed_resolution_buffer(self, *args, **kwargs):
def compute_fixed_resolution_buffer(self, bounds, target_data=None, target_cid=None,
subset_state=None, broadcast=True, cache_id=None):

from glue.core.fixed_resolution_buffer import compute_fixed_resolution_buffer
print(args, kwargs)
return compute_fixed_resolution_buffer(self, *args, **kwargs)

# First check that the target data is also a PVSlicedData
# TODO: also check it's actually for the same path

if not isinstance(target_data, PVSlicedData):
raise TypeError('target_data has to be a PVSlicedData')

if len(bounds) != len(self.shape):
raise ValueError('bounds should have {0} elements'.format(len(self.shape)))

# Now translate the bounds so that we replace the path with the
# pixel coordinates in the target dataset


# The last item of bounds is the pixel offset in the target PV slice
path_pixel_offset_target = np.linspace(*bounds[-1])

# Translate this to a relative offset along the path
path_pixel_offset_target_relative = path_pixel_offset_target / self.shape[-1]

# Find the pixel coordinates in the current dataset
x = np.interp(path_pixel_offset_target_relative,
np.linspace(0., 1., len(self.x)),
self.x)
y = np.interp(path_pixel_offset_target_relative,
np.linspace(0., 1., len(self.y)),
self.y)

# Create new bouds list

new_bounds = []
idim_current = 0

slices = []

for idim in range(self.original_data.ndim):

if idim == self.cid_x.axis:
ixmax = np.ceil(np.max(x))
bound = (0, ixmax, ixmax + 1)
slices.append(np.round(x).astype(int))
elif idim == self.cid_y.axis:
iymax = np.ceil(np.max(y))
bound = (0, iymax, iymax + 1)
slices.append(np.round(x).astype(int))
else:
bound = bounds[idim_current]
idim_current += 1
slices.append(slice(None))

new_bounds.append(bound)

# TODO: For now we extract a cube and then slice it, but it would be
# more efficient if bounds could include 1-d arrays.

# Now compute the fixed resolution buffer using the original datasets
result = compute_fixed_resolution_buffer(self.original_data, new_bounds,
target_data=target_data.original_data,
target_cid=target_cid)

result = result[slices]

return result
57 changes: 34 additions & 23 deletions glue/plugins/tools/pv_slicer/qt/pv_slicer.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def __init__(self, viewer, **kwargs):
self._roi_callback = self._extract_callback
self._slice_widget = None
self.viewer.state.add_callback('reference_data', self._on_reference_data_change)
# self._sliced_data = []

def _on_reference_data_change(self, reference_data):
if reference_data is not None:
Expand All @@ -47,31 +48,41 @@ def _extract_callback(self, mode):

selected = self.viewer.session.application.selected_layers()

if len(selected) == 1 and isinstance(selected[0], PVSlicedData):
data = selected[0]
data.original_data = self.viewer.state.reference_data
data.x_att = self.viewer.state.x_att
data.y_att = self.viewer.state.y_att
data.set_xy(vx, vy)
open_viewer = True
for tab in self.viewer.session.application.viewers:
for viewer in tab:
if data in viewer._layer_artist_container:
open_viewer = False
break
if not open_viewer:
break
else:
data = PVSlicedData(self.viewer.state.reference_data,
self.viewer.state.x_att, vx,
self.viewer.state.y_att, vy,
label=self.viewer.state.reference_data.label + " [slice]")
data.parent_viewer = self.viewer
self.viewer.session.data_collection.append(data)
open_viewer = True
open_viewer = False

all_pvdata = []

for data in self.viewer.state.layers_data:
if isinstance(data, Data):

for pvdata in self.viewer.session.data_collection:
if isinstance(pvdata, PVSlicedData):
if pvdata.original_data is data:
break
else:
pvdata = None

if pvdata is None:
pvdata = PVSlicedData(data,
self.viewer.state.x_att, vx,
self.viewer.state.y_att, vy,
label=data.label + " [slice]")
data.parent_viewer = self.viewer
self.viewer.session.data_collection.append(pvdata)
open_viewer = True
else:
data = pvdata
data.original_data = self.viewer.state.reference_data
data.x_att = self.viewer.state.x_att
data.y_att = self.viewer.state.y_att
data.set_xy(vx, vy)

all_pvdata.append(pvdata)

if open_viewer:
viewer = self.viewer.session.application.new_data_viewer(ImageViewer, data=data)
viewer = self.viewer.session.application.new_data_viewer(ImageViewer)
for pvdata in all_pvdata:
viewer.add_data(pvdata)

viewer.state.aspect = 'auto'
viewer.state.reset_limits()
Expand Down
48 changes: 48 additions & 0 deletions glue/plugins/tools/pv_slicer/tests/test_pv_sliced_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import numpy as np
from glue.core import Data, DataCollection
from glue.core.coordinates import AffineCoordinates, IdentityCoordinates
from glue.plugins.tools.pv_slicer.pv_sliced_data import PVSlicedData
from glue.core.link_helpers import LinkSame


class TestPVSlicedData:

def setup_method(self, method):
matrix = np.array([[2, 0, 0, 0], [0, 2, 0, 0], [0, 0, 2, 0], [0, 0, 0, 1]])

self.data1 = Data(x=np.arange(120).reshape((6, 5, 4)), coords=AffineCoordinates(matrix))
self.data2 = Data(y=np.arange(120).reshape((6, 5, 4)), coords=IdentityCoordinates(n_dim=3))

self.dc = DataCollection([self.data1, self.data2])

self.dc.add_link(LinkSame(self.data1.world_component_ids[0],
self.data2.world_component_ids[0]))

self.dc.add_link(LinkSame(self.data1.world_component_ids[1],
self.data2.world_component_ids[1]))

self.dc.add_link(LinkSame(self.data1.world_component_ids[2],
self.data2.world_component_ids[2]))

# TODO: the paths in the next two PVSlicedData objects are meant to
# be the same conceptually. We should make sure we formalize this with
# a UUID. Also should use proper links.

x1 = [0, 2, 5]
y1 = [1, 2, 3]

self.pvdata1 = PVSlicedData(self.data1,
self.data1.pixel_component_ids[1], y1,
self.data1.pixel_component_ids[2], x1)

x2, y2, _ = self.data2.coords.world_to_pixel_values(*self.data1.coords.pixel_to_world_values(x1, y1, 0))

self.pvdata2 = PVSlicedData(self.data2,
self.data2.pixel_component_ids[1], y2,
self.data2.pixel_component_ids[2], x2)

def test_fixed_resolution_buffer_linked(self):
result = self.pvdata1.compute_fixed_resolution_buffer(bounds=[(0, 5, 15), (0, 6, 20)],
target_data=self.pvdata2,
target_cid=self.data1.id['x'])
assert result.shape == (15, 20)

0 comments on commit 0273542

Please sign in to comment.