From e311cdfaa28da7376d436d36dba21f6ae27ff4c0 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Wed, 30 Oct 2013 12:08:46 -0500 Subject: [PATCH 1/2] Fix plotting and zooming in image plots with vertical orientation --- chaco/image_plot.py | 53 +++++++++++++++++++------------------- chaco/tools/better_zoom.py | 7 ++++- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/chaco/image_plot.py b/chaco/image_plot.py index d1df84072..982e1a7a1 100644 --- a/chaco/image_plot.py +++ b/chaco/image_plot.py @@ -36,7 +36,7 @@ class ImagePlot(Base2DPlot): # The interpolation method to use when rendering an image onto the GC. interpolation = Enum("nearest", "bilinear", "bicubic") - + #------------------------------------------------------------------------ # Private traits #------------------------------------------------------------------------ @@ -129,7 +129,7 @@ def _compute_cached_image(self, data=None, mapper=None): The parameter *data* is for subclasses that might not store an RGB(A) image as the value, but need to compute one to display (colormaps, etc.). - + The parameter *mapper* is also for subclasses that might not store an RGB(A) image as their value, and gives an opportunity to produce the values only for the visible region, rather than for the whole plot, @@ -142,16 +142,15 @@ def _compute_cached_image(self, data=None, mapper=None): (lpt, upt) = self.index.get_bounds() ll_x, ll_y = self.map_screen([lpt])[0] ur_x, ur_y = self.map_screen([upt])[0] - if "right" in self.origin: + if ll_x > ur_x: ll_x, ur_x = ur_x, ll_x - if "top" in self.origin: + if ll_y > ur_y: ll_y, ur_y = ur_y, ll_y virtual_width = ur_x - ll_x virtual_height = ur_y - ll_y - args = self.position \ - + self.bounds \ - + [ll_x, ll_y, virtual_width, virtual_height] + virtual_rect = [ll_x, ll_y, virtual_width, virtual_height] + args = self.position + self.bounds + virtual_rect img_pixels, gc_rect = self._calc_zoom_coords(*args) # Grab the appropriate sub-image, if necessary @@ -161,18 +160,19 @@ def _compute_cached_image(self, data=None, mapper=None): y_length = self.value.get_array_bounds()[1][1] j1 = y_length - j1 j2 = y_length - j2 - # swap so that j1 < j2 - j1, j2 = j2, j1 if "right" in self.origin: x_length = self.value.get_array_bounds()[0][1] i1 = x_length - i1 i2 = x_length - i2 - # swap so that i1 < i2 + + if j1 > j2: + j1, j2 = j2, j1 + if i1 > i2: i1, i2 = i2, i1 # Since data is row-major, j1 and j2 go first data = data[j1:j2, i1:i2] - + if mapper is not None: data = mapper(data) @@ -189,12 +189,11 @@ def _compute_cached_image(self, data=None, mapper=None): raise RuntimeError, "Unknown colormap depth value: %i" \ % data.value_depth - self._cached_image = GraphicsContextArray(data, pix_format=kiva_depth) if gc_rect is not None: self._cached_dest_rect = gc_rect else: - self._cached_dest_rect = (ll_x, ll_y, virtual_width, virtual_height) + self._cached_dest_rect = virtual_rect self._image_cache_valid = True def _calc_zoom_coords(self, px, py, plot_width, plot_height, @@ -248,23 +247,23 @@ def _calc_zoom_coords(self, px, py, plot_width, plot_height, # x2,y2 refers to the upper-right corner. # 1. screen space -> pixel offsets - if self.orientation == "h": - x1 = px - ix - x2 = (px + plot_width) - ix - y1 = py - iy - y2 = (py + plot_height) - iy - else: - x1 = px - ix - x2 = (px + plot_height) - ix - y1 = py - iy - y2 = (py + plot_width) - iy + if self.orientation == "v": + plot_width, plot_height = plot_height, plot_width + x1 = px - ix + x2 = (px + plot_width) - ix + y1 = py - iy + y2 = (py + plot_height) - iy + + if x1 > x2: + x1, x2 = x2, x1 + if y1 > y2: + y1, y2 = y2, y1 # 2. pixel offsets -> data array indices # X and Y are transposed because for image plot data - pixel_bounds = self.value.get_array_bounds() - xpixels = pixel_bounds[0][1] - pixel_bounds[0][0] - ypixels = pixel_bounds[1][1] - pixel_bounds[1][0] + xpixels = self.value.get_width() + ypixels = self.value.get_height() i1 = max(floor(float(x1) / image_width * xpixels), 0) i2 = min(ceil(float(x2) / image_width * xpixels), xpixels) j1 = max(floor(float(y1) / image_height * ypixels), 0) @@ -327,4 +326,4 @@ def _index_mapper_changed_fired(self): def _value_data_changed_fired(self): self._image_cache_valid = False self.request_redraw() - + diff --git a/chaco/tools/better_zoom.py b/chaco/tools/better_zoom.py index 9a60b3bdd..7c42c31b8 100644 --- a/chaco/tools/better_zoom.py +++ b/chaco/tools/better_zoom.py @@ -83,7 +83,11 @@ def _do_zoom(self, new_index_factor, new_value_factor): y = y_map.map_data(location[1]) nexty = y + (cy - y)*(self._value_factor/new_value_factor) - pan_state = PanState((cx,cy), (nextx, nexty)) + if self.component.orientation == 'v': + cx, cy = cy, cx + nextx, nexty = nexty, nextx + + pan_state = PanState((cx, cy), (nextx, nexty)) zoom_state = ZoomState((self._index_factor, self._value_factor), (new_index_factor, new_value_factor)) @@ -125,6 +129,7 @@ def zoom_in(self, factor=0): return if self._zoom_limit_reached(new_value_factor, 'x'): return + self._do_zoom(new_index_factor, new_value_factor) def zoom_out(self, factor=0): From 12afd04a437d273065786100cda659f778b9ed64 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Wed, 30 Oct 2013 13:04:44 -0500 Subject: [PATCH 2/2] Revert changes to image_plot --- chaco/image_plot.py | 53 +++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/chaco/image_plot.py b/chaco/image_plot.py index 982e1a7a1..d1df84072 100644 --- a/chaco/image_plot.py +++ b/chaco/image_plot.py @@ -36,7 +36,7 @@ class ImagePlot(Base2DPlot): # The interpolation method to use when rendering an image onto the GC. interpolation = Enum("nearest", "bilinear", "bicubic") - + #------------------------------------------------------------------------ # Private traits #------------------------------------------------------------------------ @@ -129,7 +129,7 @@ def _compute_cached_image(self, data=None, mapper=None): The parameter *data* is for subclasses that might not store an RGB(A) image as the value, but need to compute one to display (colormaps, etc.). - + The parameter *mapper* is also for subclasses that might not store an RGB(A) image as their value, and gives an opportunity to produce the values only for the visible region, rather than for the whole plot, @@ -142,15 +142,16 @@ def _compute_cached_image(self, data=None, mapper=None): (lpt, upt) = self.index.get_bounds() ll_x, ll_y = self.map_screen([lpt])[0] ur_x, ur_y = self.map_screen([upt])[0] - if ll_x > ur_x: + if "right" in self.origin: ll_x, ur_x = ur_x, ll_x - if ll_y > ur_y: + if "top" in self.origin: ll_y, ur_y = ur_y, ll_y virtual_width = ur_x - ll_x virtual_height = ur_y - ll_y - virtual_rect = [ll_x, ll_y, virtual_width, virtual_height] - args = self.position + self.bounds + virtual_rect + args = self.position \ + + self.bounds \ + + [ll_x, ll_y, virtual_width, virtual_height] img_pixels, gc_rect = self._calc_zoom_coords(*args) # Grab the appropriate sub-image, if necessary @@ -160,19 +161,18 @@ def _compute_cached_image(self, data=None, mapper=None): y_length = self.value.get_array_bounds()[1][1] j1 = y_length - j1 j2 = y_length - j2 + # swap so that j1 < j2 + j1, j2 = j2, j1 if "right" in self.origin: x_length = self.value.get_array_bounds()[0][1] i1 = x_length - i1 i2 = x_length - i2 - - if j1 > j2: - j1, j2 = j2, j1 - if i1 > i2: + # swap so that i1 < i2 i1, i2 = i2, i1 # Since data is row-major, j1 and j2 go first data = data[j1:j2, i1:i2] - + if mapper is not None: data = mapper(data) @@ -189,11 +189,12 @@ def _compute_cached_image(self, data=None, mapper=None): raise RuntimeError, "Unknown colormap depth value: %i" \ % data.value_depth + self._cached_image = GraphicsContextArray(data, pix_format=kiva_depth) if gc_rect is not None: self._cached_dest_rect = gc_rect else: - self._cached_dest_rect = virtual_rect + self._cached_dest_rect = (ll_x, ll_y, virtual_width, virtual_height) self._image_cache_valid = True def _calc_zoom_coords(self, px, py, plot_width, plot_height, @@ -247,23 +248,23 @@ def _calc_zoom_coords(self, px, py, plot_width, plot_height, # x2,y2 refers to the upper-right corner. # 1. screen space -> pixel offsets - if self.orientation == "v": - plot_width, plot_height = plot_height, plot_width - - x1 = px - ix - x2 = (px + plot_width) - ix - y1 = py - iy - y2 = (py + plot_height) - iy + if self.orientation == "h": + x1 = px - ix + x2 = (px + plot_width) - ix + y1 = py - iy + y2 = (py + plot_height) - iy + else: + x1 = px - ix + x2 = (px + plot_height) - ix + y1 = py - iy + y2 = (py + plot_width) - iy - if x1 > x2: - x1, x2 = x2, x1 - if y1 > y2: - y1, y2 = y2, y1 # 2. pixel offsets -> data array indices # X and Y are transposed because for image plot data - xpixels = self.value.get_width() - ypixels = self.value.get_height() + pixel_bounds = self.value.get_array_bounds() + xpixels = pixel_bounds[0][1] - pixel_bounds[0][0] + ypixels = pixel_bounds[1][1] - pixel_bounds[1][0] i1 = max(floor(float(x1) / image_width * xpixels), 0) i2 = min(ceil(float(x2) / image_width * xpixels), xpixels) j1 = max(floor(float(y1) / image_height * ypixels), 0) @@ -326,4 +327,4 @@ def _index_mapper_changed_fired(self): def _value_data_changed_fired(self): self._image_cache_valid = False self.request_redraw() - +