/usr/lib/python2.7/dist-packages/chaco/data_range_2d.py is in python-chaco 4.5.0-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 | """
Defines the DataRange2D class.
"""
from numpy import compress, inf, transpose
# Enthought library imports
from traits.api import Any, Bool, CFloat, Instance, Property, Trait, \
Tuple, on_trait_change
# Local relative imports
from base_data_range import BaseDataRange
from data_range_1d import DataRange1D
class DataRange2D(BaseDataRange):
""" A range on (2-D) image data.
In a mathematically general sense, a 2-D range is an arbitrary region in
the plane. Arbitrary regions are difficult to implement well, so this
class supports only rectangular regions for now.
"""
# The actual value of the lower bound of this range. To set it, use
# **low_setting**.
low = Property # (2,) array of lower-left x,y
# The actual value of the upper bound of this range. To set it, use
# **high_setting**.
high = Property # (2,) array of upper-right x,y
# Property for the lower bound of this range (overrides AbstractDataRange).
low_setting = Property
# Property for the upper bound of this range (overrides AbstractDataRange).
high_setting = Property
# The 2-D grid range is actually implemented as two 1-D ranges, which can
# be accessed individually. They can also be set to new DataRange1D
# instances; in that case, the DataRange2D's sources are removed from
# its old 1-D dataranges and added to the new one.
# Property for the range in the x-dimension.
x_range = Property
# Property for the range in the y-dimension.
y_range = Property
# Do "auto" bounds imply an exact fit to the data? (One Boolean per
# dimension) If False, the bounds pad a little bit of margin on either
# side.
tight_bounds = Tuple(Bool(True), Bool(True))
# The minimum percentage difference between low and high for each
# dimension. That is, (high-low) >= epsilon * low.
epsilon = Tuple(CFloat(1.0e-4), CFloat(1.0e-4))
#------------------------------------------------------------------------
# Private traits
#------------------------------------------------------------------------
# DataRange1D for the x-dimension.
_xrange = Instance(DataRange1D, args=())
# DataRange1D for the y-dimension.
_yrange = Instance(DataRange1D, args=())
#------------------------------------------------------------------------
# AbstractRange interface
#------------------------------------------------------------------------
def clip_data(self, data):
""" Returns a list of data values that are within the range.
Implements AbstractDataRange.
"""
return compress(self.mask_data(data), data, axis=0)
def mask_data(self, data):
""" Returns a mask array, indicating whether values in the given array
are inside the range.
Implements AbstractDataRange.
"""
x_points, y_points = transpose(data)
x_mask = (x_points >= self.low[0]) & (x_points <= self.high[0])
y_mask = (y_points >= self.low[1]) & (y_points <= self.high[1])
return x_mask & y_mask
def bound_data(self, data):
""" Not implemented for this class.
"""
raise NotImplementedError("bound_data() has not been implemented "
"for 2d pointsets.")
def set_bounds(self, low, high):
""" Sets all the bounds of the range simultaneously.
Implements AbstractDataRange.
Parameters
----------
low : (x,y)
Lower-left corner of the range.
high : (x,y)
Upper right corner of the range.
"""
self._do_set_low_setting(low, fire_event=False)
self._do_set_high_setting(high)
#------------------------------------------------------------------------
# Public methods
#------------------------------------------------------------------------
def __init__(self, *args, **kwargs):
super(DataRange2D, self).__init__(*args, **kwargs)
def reset(self):
""" Resets the bounds of this range.
"""
self.high_setting = ('auto', 'auto')
self.low_setting = ('auto', 'auto')
self.refresh()
def refresh(self):
""" If any of the bounds is 'auto', this method refreshes the actual
low and high values from the set of the view filters' data sources.
"""
if 'auto' not in self.low_setting and \
'auto' not in self.high_setting:
# If the user has hard-coded bounds, then refresh() doesn't do
# anything.
return
else:
self._refresh_bounds()
#------------------------------------------------------------------------
# Private methods
#------------------------------------------------------------------------
def _refresh_bounds(self):
self._xrange.refresh()
self._yrange.refresh()
#------------------------------------------------------------------------
# Property getters and setters
#------------------------------------------------------------------------
def _get_low(self):
return (self._xrange.low, self._yrange.low)
def _set_low(self, val):
return self._set_low_setting(val)
def _get_low_setting(self):
return (self._xrange.low_setting, self._yrange.low_setting)
def _set_low_setting(self, val):
self._do_set_low_setting(val)
def _do_set_low_setting(self, val, fire_event=True):
self._xrange.low_setting = val[0]
self._yrange.low_setting = val[1]
def _get_high(self):
return (self._xrange.high, self._yrange.high)
def _set_high(self, val):
return self._set_high_setting(val)
def _get_high_setting(self):
return (self._xrange.high_setting, self._yrange.high_setting)
def _set_high_setting(self, val):
self._do_set_high_setting(val)
def _do_set_high_setting(self, val, fire_event=True):
self._xrange.high_setting = val[0]
self._yrange.high_setting = val[1]
def _get_x_range(self):
return self._xrange
def _set_x_range(self, newrange):
self._set_1d_range("_xdata", self._xrange, newrange)
self._xrange = newrange
def _get_y_range(self):
return self._yrange
def _set_y_range(self, newrange):
self._set_1d_range("_ydata", self._yrange, newrange)
self._yrange = newrange
def _set_1d_range(self, dataname, oldrange, newrange):
# dataname is the name of the underlying 1d data source of the
# ImageData instances in self.sources, e.g. "_xdata" or "_ydata"
for source in self.sources:
source1d = getattr(source, dataname, None)
if source1d:
if oldrange:
oldrange.remove(source1d)
if newrange:
newrange.add(source1d)
return
#------------------------------------------------------------------------
# Event handlers
#------------------------------------------------------------------------
def _sources_items_changed(self, event):
for source in event.removed:
source.on_trait_change(self.refresh, "data_changed", remove=True)
for source in event.added:
source.on_trait_change(self.refresh, "data_changed")
# the _xdata and _ydata of the sources may be created anew on every
# access, so we can't just add/delete from _xrange and _yrange sources
# based on object identity. So recreate lists each time:
self._xrange.sources = [s._xdata for s in self.sources]
self._yrange.sources = [s._ydata for s in self.sources]
self.refresh()
def _sources_changed(self, old, new):
for source in old:
source.on_trait_change(self.refresh, "data_changed", remove=True)
for source in new:
source.on_trait_change(self.refresh, "data_changed")
# the _xdata and _ydata of the sources may be created anew on every
# access, so we can't just add/delete from _xrange and _yrange sources
# based on object identity. So recreate lists each time:
self._xrange.sources = [s._xdata for s in self.sources]
self._yrange.sources = [s._ydata for s in self.sources]
self.refresh()
@on_trait_change("_xrange.updated,_yrange.updated")
def _subranges_updated(self):
self.updated = True
|