Skip to content

Commit

Permalink
Merge pull request #431 from enthought/ENH/image_inspector_overlay
Browse files Browse the repository at this point in the history
Enh: Simplify controlling text of ImageInspectorOverlay
  • Loading branch information
jonathanrocher authored Jun 10, 2019
2 parents 3cf73a0 + 20ace01 commit 36d5792
Show file tree
Hide file tree
Showing 3 changed files with 244 additions and 19 deletions.
52 changes: 34 additions & 18 deletions chaco/tools/image_inspector_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,15 @@ def normal_mouse_move(self, event):
if hasattr(plot, "_cached_mapped_image") and \
plot._cached_mapped_image is not None:
self.new_value = \
dict(indices=ndx,
data_value=image_data.data[y_index, x_index],
color_value=plot._cached_mapped_image[y_index,
x_index])
{"indices": ndx,
"data_value": image_data.data[y_index, x_index],
"color_value": plot._cached_mapped_image[y_index,
x_index]}

else:
self.new_value = \
dict(indices=ndx,
color_value=image_data.data[y_index, x_index])
{"indices": ndx,
"color_value": image_data.data[y_index, x_index]}

self.last_mouse_position = (event.x, event.y)
return
Expand All @@ -100,10 +100,35 @@ class ImageInspectorOverlay(TextBoxOverlay):
#: tool's location, or whether it should be forced to be hidden or visible.
visibility = Enum("auto", True, False)

# Private interface -------------------------------------------------------

def _build_text_from_event(self, event):
""" Create a formatted string to display from the mouse event data.
"""
newstring = ""
if 'indices' in event:
newstring += '(%d, %d)' % event['indices']
if 'color_value' in event:
try:
newstring += "\n(%d, %d, %d)" % tuple(
map(int, event['color_value'][:3]))
except IndexError:
# color value is an integer, for example if gray scale image
newstring += "\n%d" % event['color_value']

if 'data_value' in event:
newstring += "\n{}".format(event['data_value'])

return newstring

# Traits listeners --------------------------------------------------------

def _image_inspector_changed(self, old, new):
if old:
old.on_trait_event(self._new_value_updated, 'new_value', remove=True)
old.on_trait_change(self._tool_visible_changed, "visible", remove=True)
old.on_trait_event(self._new_value_updated, 'new_value',
remove=True)
old.on_trait_change(self._tool_visible_changed, "visible",
remove=True)
if new:
new.on_trait_event(self._new_value_updated, 'new_value')
new.on_trait_change(self._tool_visible_changed, "visible")
Expand All @@ -123,16 +148,7 @@ def _new_value_updated(self, event):
else:
self.alternate_position = None

d = event
newstring = ""
if 'indices' in d:
newstring += '(%d, %d)' % d['indices'] + '\n'
if 'color_value' in d:
newstring += "(%d, %d, %d)" % tuple(map(int,d['color_value'][:3])) + "\n"
if 'data_value' in d:
newstring += str(d['data_value'])

self.text = newstring
self.text = self._build_text_from_event(event)
self.component.request_redraw()

def _visible_changed(self):
Expand Down
209 changes: 209 additions & 0 deletions chaco/tools/tests/test_image_inspector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
""" Tests for the ImageInspectorTool and ImageInspectorOverlay tools.
"""

from unittest import TestCase
import numpy as np
from numpy.testing import assert_array_equal

from chaco.api import ArrayPlotData, Plot
from chaco.tools.api import ImageInspectorTool, ImageInspectorOverlay
from enable.testing import EnableTestAssistant
from traits.testing.unittest_tools import UnittestTools


def create_image_plot(img_values, **kwargs):
data = ArrayPlotData(img=img_values)
plot = Plot(data)
plot.img_plot("img", **kwargs)
return plot


class CustomImageInspectorOverlay(ImageInspectorOverlay):
def _build_text_from_event(self, event):
return 'Position: ({}, {})'.format(*event['indices'])


class BaseImageInspectorTool(EnableTestAssistant, UnittestTools):
def setUp(self):
# Control the pixel size of the plot to know where the tiles are:
self.plot.bounds = [100, 100]
self.plot._window = self.create_mock_window()
renderer = self.plot.plots["plot0"][0]
self.tool = ImageInspectorTool(component=renderer)
self.overlay = ImageInspectorOverlay(component=renderer,
image_inspector=self.tool)
self.overlay2 = CustomImageInspectorOverlay(component=renderer,
image_inspector=self.tool)
self.plot.active_tool = self.tool
self.plot.do_layout()

self.insp_event = None

def test_mouse_move_records_last_position(self):
tool = self.tool

self.assertEqual(tool.last_mouse_position, ())

self.mouse_move(tool, 0, 0)
self.assertEqual(tool.last_mouse_position, (0, 0))

self.mouse_move(tool, 10, 10)
self.assertEqual(tool.last_mouse_position, (10, 10))

self.mouse_leave(tool, 1000, 1000)
self.assertEqual(tool.last_mouse_position, (10, 10))

def test_mouse_move_custom_overlay(self):
tool = self.tool

# Add a listener to catch the emitted event:
tool.on_trait_change(self.store_inspector_event, "new_value")
try:
self.assertIsNone(self.insp_event)

with self.assertTraitChanges(tool, "new_value", 1):
with self.assertTraitChanges(self.overlay2, "text", 1):
self.mouse_move(tool, 0, 0)

self.assertEqual(self.overlay2.text, 'Position: (0, 0)')
finally:
tool.on_trait_change(self.store_inspector_event, "new_value",
remove=True)

# Helper methods ----------------------------------------------------------

def store_inspector_event(self, event):
self.insp_event = event


class TestImageInspectorToolGray(BaseImageInspectorTool, TestCase):
""" Tests for the ImageInspector tool with a gray scale image
"""

def setUp(self):
values = np.arange(4).reshape(2, 2)
self.plot = create_image_plot(values)
super(TestImageInspectorToolGray, self).setUp()

def test_mouse_move_collect_image_info(self):
tool = self.tool

# Add a listener to catch the emitted event:
tool.on_trait_change(self.store_inspector_event, "new_value")
try:
self.assertIsNone(self.insp_event)

with self.assertTraitChanges(tool, "new_value", 1):
with self.assertTraitChanges(self.overlay, "text", 1):
self.mouse_move(tool, 0, 0)
self.assertEqual(self.insp_event["color_value"], 0)
self.assertEqual(self.insp_event["indices"], (0, 0))

self.assertEqual(self.overlay.text, '(0, 0)\n0')

with self.assertTraitChanges(tool, "new_value", 1):
with self.assertTraitChanges(self.overlay, "text", 1):
# Move within the same tile:
self.mouse_move(tool, 90, 0)
self.assertEqual(self.insp_event["color_value"], 1)
self.assertEqual(self.insp_event["indices"], (1, 0))

self.assertEqual(self.overlay.text, '(1, 0)\n1')

with self.assertTraitChanges(tool, "new_value", 1):
with self.assertTraitDoesNotChange(self.overlay, "text"):
# Move within the same tile:
self.mouse_move(tool, 91, 0)
self.assertEqual(self.insp_event["color_value"], 1)
self.assertEqual(self.insp_event["indices"], (1, 0))

with self.assertTraitChanges(tool, "new_value", 1):
with self.assertTraitChanges(self.overlay, "text", 1):
# Move to another value in the image:
self.mouse_move(tool, 0, 90)
self.assertEqual(self.insp_event["color_value"], 2)
self.assertEqual(self.insp_event["indices"], (0, 1))

self.assertEqual(self.overlay.text, '(0, 1)\n2')

with self.assertTraitChanges(tool, "new_value", 1):
with self.assertTraitChanges(self.overlay, "text", 1):
# Move within the same tile:
self.mouse_move(tool, 90, 90)
self.assertEqual(self.insp_event["color_value"], 3)
self.assertEqual(self.insp_event["indices"], (1, 1))

self.assertEqual(self.overlay.text, '(1, 1)\n3')

finally:
tool.on_trait_change(self.store_inspector_event, "new_value",
remove=True)


class TestImageInspectorToolRGB(BaseImageInspectorTool, TestCase):
""" Tests for the ImageInspector tool with an RGB image.
"""

def setUp(self):
values = np.arange(12).reshape(2, 2, 3)
self.plot = create_image_plot(values)
super(TestImageInspectorToolRGB, self).setUp()

def test_mouse_move_collect_image_info(self):
tool = self.tool

# Add a listener to catch the emitted event:
tool.on_trait_change(self.store_inspector_event, "new_value")
try:
self.assertIsNone(self.insp_event)

with self.assertTraitChanges(tool, "new_value", 1):
with self.assertTraitChanges(self.overlay, "text", 1):
self.mouse_move(tool, 0, 0)
assert_array_equal(self.insp_event["color_value"],
np.array([0, 1, 2]))
self.assertEqual(self.insp_event["indices"], (0, 0))

self.assertEqual(self.overlay.text, '(0, 0)\n(0, 1, 2)')

with self.assertTraitChanges(tool, "new_value", 1):
with self.assertTraitChanges(self.overlay, "text", 1):
# Move within the same tile:
self.mouse_move(tool, 90, 0)
assert_array_equal(self.insp_event["color_value"],
np.array([3, 4, 5]))
self.assertEqual(self.insp_event["indices"], (1, 0))

self.assertEqual(self.overlay.text, '(1, 0)\n(3, 4, 5)')

with self.assertTraitChanges(tool, "new_value", 1):
with self.assertTraitDoesNotChange(self.overlay, "text"):
# Move within the same tile:
self.mouse_move(tool, 91, 0)
assert_array_equal(self.insp_event["color_value"],
np.array([3, 4, 5]))
self.assertEqual(self.insp_event["indices"], (1, 0))

with self.assertTraitChanges(tool, "new_value", 1):
with self.assertTraitChanges(self.overlay, "text", 1):
# Move to another value in the image:
self.mouse_move(tool, 0, 90)
assert_array_equal(self.insp_event["color_value"],
np.array([6, 7, 8]))
self.assertEqual(self.insp_event["indices"], (0, 1))

self.assertEqual(self.overlay.text, '(0, 1)\n(6, 7, 8)')

with self.assertTraitChanges(tool, "new_value", 1):
with self.assertTraitChanges(self.overlay, "text", 1):
# Move within the same tile:
self.mouse_move(tool, 90, 90)
assert_array_equal(self.insp_event["color_value"],
np.array([9, 10, 11]))
self.assertEqual(self.insp_event["indices"], (1, 1))

self.assertEqual(self.overlay.text, '(1, 1)\n(9, 10, 11)')

finally:
tool.on_trait_change(self.store_inspector_event, "new_value",
remove=True)
2 changes: 1 addition & 1 deletion examples/demo/basic/image_inspector.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def _create_plot_component():# Create a scalar field to colormap
plot.tools.append(PanTool(plot))
zoom = ZoomTool(component=plot, tool_mode="box", always_on=False)
plot.overlays.append(zoom)
imgtool = ImageInspectorTool(img_plot)
imgtool = ImageInspectorTool(component=img_plot)
img_plot.tools.append(imgtool)
overlay = ImageInspectorOverlay(component=img_plot, image_inspector=imgtool,
bgcolor="white", border_visible=True)
Expand Down

0 comments on commit 36d5792

Please sign in to comment.