Skip to content

Commit

Permalink
Merge pull request #1344 from astrofrog/fix-standalone-image-widget
Browse files Browse the repository at this point in the history
Fixes to standalone image widget
  • Loading branch information
astrofrog authored Jul 13, 2017
2 parents 75bfd13 + 5379fd5 commit 0924f1a
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 9 deletions.
13 changes: 9 additions & 4 deletions glue/plugins/tools/pv_slicer/qt/pv_slicer.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,18 @@ class PVSlicerMode(PathMode):
tool_tip = ('Extract a slice from an arbitrary path\n'
' ENTER accepts the path\n'
' ESCAPE clears the path')
status_tip = 'Draw a path then press ENTER to extract slice, or press ESC to cancel'
shortcut = 'P'

def __init__(self, viewer, **kwargs):
super(PVSlicerMode, self).__init__(viewer, **kwargs)
self._roi_callback = self._extract_callback
self._slice_widget = None
self.viewer.state.add_callback('reference_data', self._on_reference_data_change)

def _on_reference_data_change(self, reference_data):
if reference_data is not None:
self.enabled = reference_data.ndim == 3

def _clear_path(self):
self.clear()
Expand Down Expand Up @@ -125,9 +131,8 @@ def _sync_slice(self, event):

@defer_draw
def _draw_crosshairs(self, event):
pass
# x, y, _ = self._pos_in_parent(event)
# self._parent.show_crosshairs(x, y)
x, y, _ = self._pos_in_parent(event)
self._parent.show_crosshairs(x, y)

@defer_draw
def _on_move(self, event):
Expand All @@ -147,7 +152,7 @@ def _pos_in_parent(self, event=None, xdata=None, ydata=None):
ydata = event.ydata

# Find position slice where cursor is
ind = np.clip(xdata, 0, self._im_array.shape[1] - 1)
ind = int(round(np.clip(xdata, 0, self._im_array.shape[1] - 1)))

# Find pixel coordinate in input image for this slice
x = self._x[ind]
Expand Down
9 changes: 5 additions & 4 deletions glue/utils/qt/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ def update_combobox(combo, labeldata, default_index=0):
combo.addItem(label, userData=data)
if data is current or data == current:
index = i
combo.blockSignals(False)

if default_index < 0:
default_index = combo.count() + default_index
Expand All @@ -62,11 +61,13 @@ def update_combobox(combo, labeldata, default_index=0):
index = min(default_index, combo.count() - 1)
combo.setCurrentIndex(index)

combo.blockSignals(False)

# We need to force emit this, otherwise if the index happens to be the
# same as before, even if the data is different, callbacks won't be
# called.
if idx == index or idx == -1:
combo.currentIndexChanged.emit(index)
# called. So we block the signals until just before now then always call
# callback manually.
combo.currentIndexChanged.emit(index)


class GlueTabBar(QtWidgets.QTabBar):
Expand Down
12 changes: 12 additions & 0 deletions glue/viewers/image/qt/data_viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,15 @@ def _subset_artist_cls(self, axes, state, layer=None):
@staticmethod
def update_viewer_state(rec, context):
return update_image_viewer_state(rec, context)

@defer_draw
def show_crosshairs(self, x, y):

if getattr(self, '_crosshairs', None) is not None:
self._crosshairs.remove()

self._crosshairs, = self.axes.plot([x], [y], '+', ms=12,
mfc='none', mec='#d32d26',
mew=1, zorder=100)

self.axes.figure.canvas.draw()
2 changes: 1 addition & 1 deletion glue/viewers/image/qt/slice_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def _clear(self):
for s in self._sliders:
s.close()

self._slices = []
self._sliders = []

@avoid_circular
def sync_state_from_sliders(self, *args):
Expand Down
20 changes: 20 additions & 0 deletions glue/viewers/image/qt/standalone_image_viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,22 @@ def set_image(self, image=None, wcs=None, **kwargs):
self._im = imshow(self._axes, image, cmap='gray', **kwargs)
self._im_array = image
self._wcs = wcs

if 'extent' in kwargs:
self.axes.set_xlim(kwargs['extent'][:2])
self.axes.set_ylim(kwargs['extent'][2:])
else:
ny, nx = image.shape
self.axes.set_xlim(-0.5, nx - 0.5)
self.axes.set_ylim(-0.5, ny - 0.5)
# FIXME: for a reason I don't quite understand, dataLim doesn't
# get updated immediately here, which means that there are then
# issues in the first draw of the image (the limits are such that
# only part of the image is shown). We just set dataLim manually
# to avoid this issue. This is also done in ImageViewer.
self.axes.dataLim.intervalx = self.axes.get_xlim()
self.axes.dataLim.intervaly = self.axes.get_ylim()

self._redraw()

@property
Expand Down Expand Up @@ -139,3 +155,7 @@ def initialize_toolbar(self):
self.toolbar.add_tool(mode)

self.addToolBar(self.toolbar)

def set_status(self, message):
sb = self.statusBar()
sb.showMessage(message)
57 changes: 57 additions & 0 deletions glue/viewers/image/qt/tests/test_viewer_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ def setup_method(self, method):
self.catalog = Data(label='catalog', c=[1, 3, 2], d=[4, 3, 3])
self.hypercube = Data(label='hypercube', x=np.arange(120).reshape((2, 3, 4, 5)))

# Create data versions with WCS coordinates
self.image1_wcs = Data(label='image1_wcs', x=self.image1['x'],
coords=WCSCoordinates(wcs=WCS(naxis=2)))
self.hypercube_wcs = Data(label='hypercube_wcs', x=self.hypercube['x'],
coords=WCSCoordinates(wcs=WCS(naxis=4)))

self.session = simple_session()
self.hub = self.session.hub

Expand All @@ -79,6 +85,8 @@ def setup_method(self, method):
self.data_collection.append(self.image2)
self.data_collection.append(self.catalog)
self.data_collection.append(self.hypercube)
self.data_collection.append(self.image1_wcs)
self.data_collection.append(self.hypercube_wcs)

self.viewer = ImageViewer(self.session)

Expand Down Expand Up @@ -404,6 +412,55 @@ def test_change_reference_data(self, capsys):
assert out.strip() == ""
assert err.strip() == ""

@pytest.mark.parametrize('wcs', [False, True])
def test_change_reference_data_dimensionality(self, capsys, wcs):

if wcs:
pytest.xfail()

# Regression test for a bug that caused an exception when changing
# the dimensionality of the reference data

if wcs:
first = self.image1_wcs
second = self.hypercube_wcs
else:
first = self.image1
second = self.hypercube

self.viewer.add_data(first)
self.viewer.add_data(second)

assert self.viewer.state.reference_data is first
assert self.viewer.state.x_att_world is first.world_component_ids[-1]
assert self.viewer.state.y_att_world is first.world_component_ids[-2]
assert self.viewer.state.x_att is first.pixel_component_ids[-1]
assert self.viewer.state.y_att is first.pixel_component_ids[-2]

self.viewer.state.reference_data = second

assert self.viewer.state.reference_data is second
assert self.viewer.state.x_att_world is second.world_component_ids[-1]
assert self.viewer.state.y_att_world is second.world_component_ids[-2]
assert self.viewer.state.x_att is second.pixel_component_ids[-1]
assert self.viewer.state.y_att is second.pixel_component_ids[-2]

self.viewer.state.reference_data = first

assert self.viewer.state.reference_data is first
assert self.viewer.state.x_att_world is first.world_component_ids[-1]
assert self.viewer.state.y_att_world is first.world_component_ids[-2]
assert self.viewer.state.x_att is first.pixel_component_ids[-1]
assert self.viewer.state.y_att is first.pixel_component_ids[-2]

# Some exceptions used to happen during callbacks, and these show up
# in stderr but don't interrupt the code, so we make sure here that
# nothing was printed to stdout nor stderr.

out, err = capsys.readouterr()

assert out.strip() == ""
assert err.strip() == ""

class TestSessions(object):

Expand Down

0 comments on commit 0924f1a

Please sign in to comment.