Skip to content

Commit

Permalink
Merge pull request #227 from enthought/fix/stretch-data-false
Browse files Browse the repository at this point in the history
Fix stretch_data=False
  • Loading branch information
Jonathan Rocher committed Oct 23, 2014
2 parents 0a151d9 + b12e7e5 commit 9a628ab
Show file tree
Hide file tree
Showing 3 changed files with 295 additions and 17 deletions.
1 change: 1 addition & 0 deletions CHANGES.txt
Expand Up @@ -27,6 +27,7 @@ Fixes
(PR#215).
* Fix white gap between image border and image (PR#219).
* Fix redraw color mapped image plot when color mapper updates (PR#221)
* Fix behaviour of mappers when stretch_data trait is False (PR#227)

Release 4.4.1
-------------
Expand Down
39 changes: 25 additions & 14 deletions chaco/base_1d_mapper.py
Expand Up @@ -41,21 +41,26 @@ class Base1DMapper(AbstractMapper):

# Indicates whether or not the bounds have been set at all, or if they
# are at their initial default values.
_bounds_initialized = Bool(False)
_low_bound_initialized = Bool(False)
_high_bound_initialized = Bool(False)

#------------------------------------------------------------------------
# Event handlers
#------------------------------------------------------------------------

def _low_pos_changed(self):
def _low_pos_changed(self, old, new):
self._cache_valid = False
if not self.stretch_data:
self._adjust_range((old, self.high_pos), (new, self.high_pos))
self._low_bound_initialized = True
self.updated = True
return

def _high_pos_changed(self):
def _high_pos_changed(self, old, new):
self._cache_valid = False
if not self.stretch_data:
self._adjust_range((self.low_pos, old), (self.low_pos, new))
self._high_bound_initialized = True
self.updated = True
return

def _range_changed(self, old, new):
if old is not None:
Expand Down Expand Up @@ -90,18 +95,24 @@ def _get_sign(self):
def _set_screen_bounds(self, new_bounds):
if new_bounds[0] == self.low_pos and new_bounds[1] == self.high_pos:
return
if not self.stretch_data and self.range is not None and self._bounds_initialized:
rangelow = self.range.low
rangehigh = self.range.high
d_data = rangehigh - rangelow
d_screen = self.high_pos - self.low_pos
if d_data != 0 and d_screen != 0:
new_data_extent = d_data / d_screen * abs(new_bounds[1] - new_bounds[0])
self.range.set_bounds(rangelow, rangelow + new_data_extent)
if not self.stretch_data:
self._adjust_range((self.low_pos, self.high_pos), new_bounds)
self.set(low_pos = new_bounds[0], trait_change_notify=False)
self.set(high_pos = new_bounds[1], trait_change_notify=False)
self._cache_valid = False
self._bounds_initialized = True
self._low_bound_initialized = True
self._high_bound_initialized = True
self.updated = True
return

def _adjust_range(self, old_bounds, new_bounds):
initialized = self._low_bound_initialized and \
self._high_bound_initialized
if self.range is not None and initialized:
rangelow = self.range.low
rangehigh = self.range.high
d_data = rangehigh - rangelow
old_d_screen = old_bounds[1] - old_bounds[0]
if d_data != 0 and old_d_screen != 0:
new_data_extent = d_data / old_d_screen * (new_bounds[1] - new_bounds[0])
self.range.set_bounds(rangelow, rangelow + new_data_extent)
272 changes: 269 additions & 3 deletions chaco/tests/linearmapper_test_case.py
@@ -1,7 +1,7 @@

import unittest
from numpy import array
from numpy.testing import assert_equal
from numpy.testing import assert_array_almost_equal, assert_equal


from chaco.api import ArrayDataSource, DataRange1D, LinearMapper
Expand All @@ -12,7 +12,13 @@ def test_basic(self):
ary = array([5.0, 6.0, 7.0, 8.0, 9.0, 10.0])
ds = ArrayDataSource(ary)
r = DataRange1D(ds)
mapper = LinearMapper(range=r, low_pos=50, high_pos=100)
mapper = LinearMapper(range=r)
self.assertFalse(mapper._low_bound_initialized)
self.assertFalse(mapper._high_bound_initialized)
mapper.low_pos=50
self.assertTrue(mapper._low_bound_initialized)
mapper.high_pos=100
self.assertTrue(mapper._high_bound_initialized)
result = mapper.map_screen(ary)
assert_equal(result , array([50, 60, 70, 80, 90, 100]))
return
Expand All @@ -21,11 +27,271 @@ def test_reversed(self):
ary = array([5.0, 6.0, 7.0, 8.0, 9.0, 10.0])
ds = ArrayDataSource(ary)
r = DataRange1D(ds)
mapper = LinearMapper(range=r, low_pos=100, high_pos=0)
mapper = LinearMapper(range=r)
self.assertFalse(mapper._low_bound_initialized)
self.assertFalse(mapper._high_bound_initialized)
mapper.low_pos=100
self.assertTrue(mapper._low_bound_initialized)
mapper.high_pos=0
self.assertTrue(mapper._high_bound_initialized)
result = mapper.map_screen(ary)
assert_equal(result , array([100, 80, 60, 40, 20, 0]))
return

def test_set_screen_bounds(self):
ary = array([5.0, 6.0, 7.0, 8.0, 9.0, 10.0])
ds = ArrayDataSource(ary)
r = DataRange1D(ds)
mapper = LinearMapper(range=r)
self.assertFalse(mapper._low_bound_initialized)
self.assertFalse(mapper._high_bound_initialized)
mapper.screen_bounds = (50.0, 100.0)
self.assertTrue(mapper._low_bound_initialized)
self.assertTrue(mapper._high_bound_initialized)
result = mapper.map_screen(ary)
assert_equal(result , array([50, 60, 70, 80, 90, 100]))
return

def test_reversed_set_screen_bounds(self):
ary = array([5.0, 6.0, 7.0, 8.0, 9.0, 10.0])
ds = ArrayDataSource(ary)
r = DataRange1D(ds)
mapper = LinearMapper(range=r)
self.assertFalse(mapper._low_bound_initialized)
self.assertFalse(mapper._high_bound_initialized)
mapper.screen_bounds = (100.0, 0.0)
self.assertTrue(mapper._low_bound_initialized)
self.assertTrue(mapper._high_bound_initialized)
result = mapper.map_screen(ary)
assert_equal(result , array([100, 80, 60, 40, 20, 0]))
return

def test_update_screen_bounds_stretch_data(self):
ary = array([5.0, 6.0, 7.0, 8.0, 9.0, 10.0])
ds = ArrayDataSource(ary)
r = DataRange1D(ds)
mapper = LinearMapper(range=r, stretch_data=True)
# Initialize the bounds, then modify them.
mapper.screen_bounds = (50.0, 100.0)
mapper.screen_bounds = (40.0, 120.0)
result = mapper.map_screen(ary)
assert_array_almost_equal(
result, array([40.0, 56.0, 72.0, 88.0, 104.0, 120.0]))

def test_update_screen_bounds_dont_stretch_data(self):
ary = array([5.0, 6.0, 7.0, 8.0, 9.0, 10.0])
ds = ArrayDataSource(ary)
r = DataRange1D(ds)
mapper = LinearMapper(range=r, stretch_data=False)
# Initialize the bounds, then modify them.
mapper.screen_bounds = (50.0, 100.0)
mapper.screen_bounds = (40.0, 120.0)
result = mapper.map_screen(ary)
assert_array_almost_equal(
result, array([40.0, 50.0, 60.0, 70.0, 80.0, 90.0]))

def test_reversed_update_screen_bounds_stretch_data(self):
ary = array([5.0, 6.0, 7.0, 8.0, 9.0, 10.0])
ds = ArrayDataSource(ary)
r = DataRange1D(ds)
mapper = LinearMapper(range=r, stretch_data=True)
# Initialize the bounds, then modify them.
mapper.screen_bounds = (100.0, 0.0)
mapper.screen_bounds = (120.0, -10.0)
result = mapper.map_screen(ary)
assert_array_almost_equal(
result, array([120.0, 94.0, 68.0, 42.0, 16.0, -10.0]))

def test_reversed_update_screen_bounds_dont_stretch_data(self):
ary = array([5.0, 6.0, 7.0, 8.0, 9.0, 10.0])
ds = ArrayDataSource(ary)
r = DataRange1D(ds)
mapper = LinearMapper(range=r, stretch_data=False)
# Initialize the bounds, then modify them.
mapper.screen_bounds = (100.0, 0.0)
mapper.screen_bounds = (120.0, -10.0)
result = mapper.map_screen(ary)
assert_array_almost_equal(
result, array([120.0, 100.0, 80.0, 60.0, 40.0, 20.0]))

def test_update_low_pos_stretch_data(self):
ary = array([5.0, 6.0, 7.0, 8.0, 9.0, 10.0])
ds = ArrayDataSource(ary)
r = DataRange1D(ds)
mapper = LinearMapper(range=r, stretch_data=True)
# Initialize the bounds, then modify them.
mapper.screen_bounds = (50.0, 100.0)
mapper.low_pos = 40.0
result = mapper.map_screen(ary)
assert_array_almost_equal(result, array([40, 52, 64, 76, 88, 100]))

def test_update_low_pos_dont_stretch_data(self):
ary = array([5.0, 6.0, 7.0, 8.0, 9.0, 10.0])
ds = ArrayDataSource(ary)
r = DataRange1D(ds)
mapper = LinearMapper(range=r, stretch_data=False)
# Initialize the bounds, then modify them.
mapper.screen_bounds = (50.0, 100.0)
mapper.low_pos = 40.0
result = mapper.map_screen(ary)
assert_array_almost_equal(result, array([40, 50, 60, 70, 80, 90]))

def test_reversed_update_low_pos_stretch_data(self):
ary = array([5.0, 6.0, 7.0, 8.0, 9.0, 10.0])
ds = ArrayDataSource(ary)
r = DataRange1D(ds)
mapper = LinearMapper(range=r, stretch_data=True)
# Initialize the bounds, then modify them.
mapper.screen_bounds = (100.0, 50.0)
mapper.low_pos = 110.0
result = mapper.map_screen(ary)
assert_array_almost_equal(result, array([110, 98, 86, 74, 62, 50]))

def test_reversed_update_low_pos_dont_stretch_data(self):
ary = array([5.0, 6.0, 7.0, 8.0, 9.0, 10.0])
ds = ArrayDataSource(ary)
r = DataRange1D(ds)
mapper = LinearMapper(range=r, stretch_data=False)
# Initialize the bounds, then modify them.
mapper.screen_bounds = (100.0, 50.0)
mapper.low_pos = 110.0
result = mapper.map_screen(ary)
assert_array_almost_equal(result, array([110, 100, 90, 80, 70, 60]))

def test_update_high_pos_stretch_data(self):
ary = array([5.0, 6.0, 7.0, 8.0, 9.0, 10.0])
ds = ArrayDataSource(ary)
r = DataRange1D(ds)
mapper = LinearMapper(range=r, stretch_data=True)
# Initialize the bounds, then modify them.
mapper.screen_bounds = (50.0, 100.0)
mapper.high_pos = 110.0
result = mapper.map_screen(ary)
assert_array_almost_equal(result, array([50, 62, 74, 86, 98, 110]))

def test_update_high_pos_dont_stretch_data(self):
ary = array([5.0, 6.0, 7.0, 8.0, 9.0, 10.0])
ds = ArrayDataSource(ary)
r = DataRange1D(ds)
mapper = LinearMapper(range=r, stretch_data=False)
# Initialize the bounds, then modify them.
mapper.screen_bounds = (50.0, 100.0)
mapper.high_pos = 110.0
result = mapper.map_screen(ary)
assert_array_almost_equal(result, array([50, 60, 70, 80, 90, 100]))

def test_reversed_update_high_pos_stretch_data(self):
ary = array([5.0, 6.0, 7.0, 8.0, 9.0, 10.0])
ds = ArrayDataSource(ary)
r = DataRange1D(ds)
mapper = LinearMapper(range=r, stretch_data=True)
# Initialize the bounds, then modify them.
mapper.screen_bounds = (100.0, 50.0)
mapper.high_pos = 40.0
result = mapper.map_screen(ary)
assert_array_almost_equal(result, array([100, 88, 76, 64, 52, 40]))

def test_reversed_update_high_pos_dont_stretch_data(self):
ary = array([5.0, 6.0, 7.0, 8.0, 9.0, 10.0])
ds = ArrayDataSource(ary)
r = DataRange1D(ds)
mapper = LinearMapper(range=r, stretch_data=False)
# Initialize the bounds, then modify them.
mapper.screen_bounds = (100.0, 50.0)
mapper.high_pos = 40.0
result = mapper.map_screen(ary)
assert_array_almost_equal(result, array([100, 90, 80, 70, 60, 50]))

def test_update_low_pos_stretch_data_with_reverse(self):
ary = array([5.0, 6.0, 7.0, 8.0, 9.0, 10.0])
ds = ArrayDataSource(ary)
r = DataRange1D(ds)
mapper = LinearMapper(range=r, stretch_data=True)
# Initialize the bounds, then modify them.
mapper.screen_bounds = (50.0, 100.0)
mapper.low_pos = 150.0
result = mapper.map_screen(ary)
assert_array_almost_equal(result, array([150, 140, 130, 120, 110, 100]))

def test_update_low_pos_dont_stretch_data_with_reverse(self):
ary = array([5.0, 6.0, 7.0, 8.0, 9.0, 10.0])
ds = ArrayDataSource(ary)
r = DataRange1D(ds)
mapper = LinearMapper(range=r, stretch_data=False)
# Initialize the bounds, then modify them.
mapper.screen_bounds = (50.0, 100.0)
mapper.low_pos = 150.0
result = mapper.map_screen(ary)
assert_array_almost_equal(result, array([150, 160, 170, 180, 190, 200]))

def test_update_high_pos_stretch_data_with_reverse(self):
ary = array([5.0, 6.0, 7.0, 8.0, 9.0, 10.0])
ds = ArrayDataSource(ary)
r = DataRange1D(ds)
mapper = LinearMapper(range=r, stretch_data=True)
# Initialize the bounds, then modify them.
mapper.screen_bounds = (50.0, 100.0)
mapper.high_pos = 0.0
result = mapper.map_screen(ary)
assert_array_almost_equal(result, array([50, 40, 30, 20, 10, 0]))

def test_update_high_pos_dont_stretch_data_with_reverse(self):
ary = array([5.0, 6.0, 7.0, 8.0, 9.0, 10.0])
ds = ArrayDataSource(ary)
r = DataRange1D(ds)
mapper = LinearMapper(range=r, stretch_data=False)
# Initialize the bounds, then modify them.
mapper.screen_bounds = (50.0, 100.0)
mapper.high_pos = 0.0
result = mapper.map_screen(ary)
assert_array_almost_equal(result, array([50, 60, 70, 80, 90, 100]))

def test_update_low_pos_stretch_data_with_zero(self):
ary = array([5.0, 6.0, 7.0, 8.0, 9.0, 10.0])
ds = ArrayDataSource(ary)
r = DataRange1D(ds)
mapper = LinearMapper(range=r, stretch_data=True)
# Initialize the bounds, then modify them.
mapper.screen_bounds = (50.0, 100.0)
mapper.low_pos = 100.0
result = mapper.map_screen(ary)
assert_array_almost_equal(result, array([100, 100, 100, 100, 100, 100]))

def test_update_low_pos_dont_stretch_data_with_zero(self):
ary = array([5.0, 6.0, 7.0, 8.0, 9.0, 10.0])
ds = ArrayDataSource(ary)
r = DataRange1D(ds)
mapper = LinearMapper(range=r, stretch_data=False)
# Initialize the bounds, then modify them.
mapper.screen_bounds = (50.0, 100.0)
mapper.low_pos = 100.0
result = mapper.map_screen(ary)
assert_array_almost_equal(result, array([100, 100, 100, 100, 100, 100]))

def test_update_high_pos_stretch_data_with_zero(self):
ary = array([5.0, 6.0, 7.0, 8.0, 9.0, 10.0])
ds = ArrayDataSource(ary)
r = DataRange1D(ds)
mapper = LinearMapper(range=r, stretch_data=True)
# Initialize the bounds, then modify them.
mapper.screen_bounds = (50.0, 100.0)
mapper.high_pos = 50.0
result = mapper.map_screen(ary)
assert_array_almost_equal(result, array([50, 50, 50, 50, 50, 50]))

def test_update_high_pos_dont_stretch_data_with_zero(self):
ary = array([5.0, 6.0, 7.0, 8.0, 9.0, 10.0])
ds = ArrayDataSource(ary)
r = DataRange1D(ds)
mapper = LinearMapper(range=r, stretch_data=False)
# Initialize the bounds, then modify them.
mapper.screen_bounds = (50.0, 100.0)
mapper.high_pos = 100.0
result = mapper.map_screen(ary)
assert_array_almost_equal(result, array([50, 60, 70, 80, 90, 100]))



if __name__ == '__main__':
import nose
nose.run()

0 comments on commit 9a628ab

Please sign in to comment.