From 38ab67e21fd38c3889979e2618f7b6048d3501a8 Mon Sep 17 00:00:00 2001 From: Aaron Ayres Date: Mon, 3 May 2021 15:35:46 -0500 Subject: [PATCH 1/5] step1 --- chaco/base_xy_plot.py | 10 +++++++++- chaco/grid_mapper.py | 19 +++++++++++++++++++ chaco/linear_mapper.py | 6 +++--- chaco/lineplot.py | 13 +++++++------ 4 files changed, 38 insertions(+), 10 deletions(-) diff --git a/chaco/base_xy_plot.py b/chaco/base_xy_plot.py index d73571132..7681082fb 100644 --- a/chaco/base_xy_plot.py +++ b/chaco/base_xy_plot.py @@ -342,9 +342,17 @@ def map_screen(self, data_array): an array. Implements the AbstractPlotRenderer interface. + + Parameters + ---------- + data_array: array of shape (N, 2) + + Returns + ------- + array of shape (N, 2) """ # data_array is Nx2 array - if len(data_array) == 0: + if data_array.size == 0: return [] x_ary, y_ary = transpose(data_array) diff --git a/chaco/grid_mapper.py b/chaco/grid_mapper.py index 9a810a03e..361b28692 100644 --- a/chaco/grid_mapper.py +++ b/chaco/grid_mapper.py @@ -115,6 +115,14 @@ def map_screen(self, data_pts): """map_screen(data_pts) -> screen_array Maps values from data space into screen space. + + Parameters + ---------- + data_pts: array of shape (N, 2) + + Returns + ------- + array of shape (N, 2) """ xs, ys = transpose(data_pts) screen_xs = self._xmapper.map_screen(xs) @@ -126,6 +134,14 @@ def map_data(self, screen_pts): """map_data(screen_pts) -> data_vals Maps values from screen space into data space. + + Parameters + ---------- + screen_pts: array of shape (N, 2) + + Returns + ------- + array of shape (N, 2) """ screen_xs, screen_ys = transpose(screen_pts) xs = self._xmapper.map_data(screen_xs) @@ -134,6 +150,9 @@ def map_data(self, screen_pts): return data_pts def map_data_array(self, screen_pts): + """ Since map_data is already vectorized, this is equivalent to + map_data. + """ return self.map_data(screen_pts) # ------------------------------------------------------------------------ diff --git a/chaco/linear_mapper.py b/chaco/linear_mapper.py index 16dd61e46..21d689e79 100644 --- a/chaco/linear_mapper.py +++ b/chaco/linear_mapper.py @@ -49,6 +49,8 @@ def map_screen(self, data_array): else: return array([self.low_pos]) else: + if not isinstance(data_array, ndarray): + data_array = array(data_array, ndmin=1) return (data_array - self.range.low) * self._scale + self.low_pos def map_data(self, screen_val): @@ -57,9 +59,7 @@ def map_data(self, screen_val): Overrides AbstractMapper. Maps values from screen space into data space. """ self._compute_scale() - if self._null_screen_range: - return array([self.range.low]) - elif self._null_data_range: + if self._null_screen_range or self._null_data_range: return array([self.range.low]) else: return (screen_val - self.low_pos) / self._scale + self.range.low diff --git a/chaco/lineplot.py b/chaco/lineplot.py index 6a7861521..bc81d1456 100644 --- a/chaco/lineplot.py +++ b/chaco/lineplot.py @@ -105,21 +105,22 @@ def hittest(self, screen_pt, threshold=7.0, return_distance=False): any data points on the line. If so, then it returns the (x,y) value of a data point near the screen point. If not, then it returns None. """ - # First, check screen_pt is directly on a point in the lineplot ndx = self.map_index(screen_pt, threshold) if ndx is not None: # screen_pt is one of the points in the lineplot - data_pt = (self.index.get_data()[ndx], self.value.get_data()[ndx]) + data_pt = array( + [[self.index.get_data()[ndx], self.value.get_data()[ndx]]] + ) if return_distance: scrn_pt = self.map_screen(data_pt) dist = sqrt( - (screen_pt[0] - scrn_pt[0]) ** 2 - + (screen_pt[1] - scrn_pt[1]) ** 2 + (screen_pt[0] - scrn_pt[0, 0]) ** 2 + + (screen_pt[1] - scrn_pt[0, 1]) ** 2 ) - return (data_pt[0], data_pt[1], dist) + return (data_pt[0, 0], data_pt[0, 1], dist) else: - return data_pt + return (data_pt[0, 0], data_pt[0, 1]) else: # We now must check the lines themselves From 8e4aa1fc4fa3926c44c559220ea11f70d06b75d1 Mon Sep 17 00:00:00 2001 From: Aaron Ayres Date: Mon, 3 May 2021 15:52:03 -0500 Subject: [PATCH 2/5] more docstring and return type changes --- chaco/barplot.py | 10 +++++++++- chaco/base_1d_plot.py | 4 ++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/chaco/barplot.py b/chaco/barplot.py index 5749f5bf9..193314bc0 100644 --- a/chaco/barplot.py +++ b/chaco/barplot.py @@ -165,9 +165,17 @@ def map_screen(self, data_array): an array. Implements the AbstractPlotRenderer interface. + + Parameters + ---------- + data_array: array of shape (N, 2) + + Returns + ------- + array of shape (N, 2) """ # data_array is Nx2 array - if len(data_array) == 0: + if data_array.size == 0: return [] x_ary, y_ary = transpose(data_array) sx = self.index_mapper.map_screen(x_ary) diff --git a/chaco/base_1d_plot.py b/chaco/base_1d_plot.py index 8fbb8f237..54c872bba 100644 --- a/chaco/base_1d_plot.py +++ b/chaco/base_1d_plot.py @@ -110,8 +110,8 @@ def map_screen(self, data_array): """ # data_array is 1D array of length N - if len(data_array) == 0: - return [] + if data_array.size == 0: + return np.empty(shape=(0,)) return asarray(self.index_mapper.map_screen(data_array)) def map_data(self, screen_pts): From bbca2ca3dd49b4b1afa9913bde7ce52e32d329ca Mon Sep 17 00:00:00 2001 From: Aaron Ayres Date: Mon, 3 May 2021 15:57:25 -0500 Subject: [PATCH 3/5] Base2DPlot map_screen should always return an ndarray and be given an array as input --- chaco/base_2d_plot.py | 4 ++-- chaco/image_plot.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/chaco/base_2d_plot.py b/chaco/base_2d_plot.py index 469b3a43c..4e8b5c3b3 100644 --- a/chaco/base_2d_plot.py +++ b/chaco/base_2d_plot.py @@ -110,8 +110,8 @@ def map_screen(self, data_pts): Implements the AbstractPlotRenderer interface. """ # data_pts is Nx2 array - if len(data_pts) == 0: - return [] + if data_pts.shape == 0: + return np.empty(shape=(0,)) return asarray(self.index_mapper.map_screen(data_pts)) def map_data(self, screen_pts): diff --git a/chaco/image_plot.py b/chaco/image_plot.py index 7131d1843..9355ead97 100644 --- a/chaco/image_plot.py +++ b/chaco/image_plot.py @@ -234,8 +234,8 @@ def _calc_virtual_screen_bbox(self): (lower_left, upper_right) = self.index.get_bounds() # ... but if the origin is not 'bottom left', the data-to-screen # mapping will flip min and max values. - x_min, y_min = self.map_screen([lower_left])[0] - x_max, y_max = self.map_screen([upper_right])[0] + x_min, y_min = self.map_screen(np.array([lower_left]))[0] + x_max, y_max = self.map_screen(np.array([upper_right]))[0] if x_min > x_max: x_min, x_max = x_max, x_min if y_min > y_max: From 784e6d9e8ee6ea55ece8032bd927cdaa358d1f3e Mon Sep 17 00:00:00 2001 From: Aaron Ayres Date: Mon, 3 May 2021 16:32:35 -0500 Subject: [PATCH 4/5] pass array into map_screen in cursor_tool --- chaco/tools/cursor_tool.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/chaco/tools/cursor_tool.py b/chaco/tools/cursor_tool.py index 4002861d1..69d1466d5 100644 --- a/chaco/tools/cursor_tool.py +++ b/chaco/tools/cursor_tool.py @@ -16,7 +16,7 @@ # Major library imports -import numpy +import numpy as np # Enthought library imports from enable.api import CircleMarker @@ -190,7 +190,7 @@ def draw(self, gc, view_bounds=None): if plot is None: return - sx, sy = plot.map_screen(self.current_position) + sx, sy = plot.map_screen(np.array([self.current_position]))[0] orientation = plot.orientation if orientation == "h" and sx is not None: @@ -211,10 +211,10 @@ def is_draggable(self, x, y): plot = self.component if plot is not None: orientation = plot.orientation - sx, sy = plot.map_screen(self.current_position) - if orientation == "h" and numpy.abs(sx - x) <= self.threshold: + sx, sy = plot.map_screen(np.array([self.current_position]))[0] + if orientation == "h" and np.abs(sx - x) <= self.threshold: return True - elif orientation == "v" and numpy.abs(sy - y) <= self.threshold: + elif orientation == "v" and np.abs(sy - y) <= self.threshold: return True return False @@ -258,17 +258,17 @@ def is_draggable(self, x, y): plot = self.component if plot is not None: orientation = plot.orientation - sx, sy = plot.map_screen([self.current_position])[0] + sx, sy = plot.map_screen(np.array([self.current_position]))[0] self._dragV = self._dragH = False if orientation == "h": - if numpy.abs(sx - x) <= self.threshold: + if np.abs(sx - x) <= self.threshold: self._dragH = True - if numpy.abs(sy - y) <= self.threshold: + if np.abs(sy - y) <= self.threshold: self._dragV = True else: - if numpy.abs(sx - x) <= self.threshold: + if np.abs(sx - x) <= self.threshold: self._dragV = True - if numpy.abs(sy - y) <= self.threshold: + if np.abs(sy - y) <= self.threshold: self._dragH = True return self._dragV or self._dragH return False @@ -284,7 +284,7 @@ def draw(self, gc, view_bounds=None): plot = self.component if plot is None: return - sx, sy = plot.map_screen([self.current_position])[0] + sx, sy = plot.map_screen(np.array([self.current_position]))[0] orientation = plot.orientation if orientation == "h": From 01d6afdc0c43203adcf451ceedf9121c4aba7106 Mon Sep 17 00:00:00 2001 From: Aaron Ayres Date: Mon, 3 May 2021 16:42:11 -0500 Subject: [PATCH 5/5] more of the same process --- chaco/horizon_plot.py | 4 +++- chaco/tools/data_label_tool.py | 2 +- examples/demo/cursor_tool_demo.py | 28 ++++++++++++++++++++++------ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/chaco/horizon_plot.py b/chaco/horizon_plot.py index 069b04888..c8f784b21 100644 --- a/chaco/horizon_plot.py +++ b/chaco/horizon_plot.py @@ -20,6 +20,8 @@ def map_screen(self, data_array): return array([self.low_pos]) else: # Scale the data by the number of bands + if not isinstance(data_array, ndarray): + data_array = array(data_array, ndmin=1) return ( data_array * self.bands - self.range.low ) * self._scale + self.low_pos @@ -74,7 +76,7 @@ def _render(self, gc, points): if len(points) == 0: return - ox, oy = self.map_screen([[0, 0]])[0] + ox, oy = self.map_screen(np.array([[0, 0]]))[0] ylow, yhigh = self.value_mapper.screen_bounds y_plus_height = yhigh - oy diff --git a/chaco/tools/data_label_tool.py b/chaco/tools/data_label_tool.py index dabf0242f..dce1488a4 100644 --- a/chaco/tools/data_label_tool.py +++ b/chaco/tools/data_label_tool.py @@ -61,7 +61,7 @@ def drag_start(self, event): """ if self.component: label = self.component - pointx, pointy = label.component.map_screen(label.data_point) + pointx, pointy = label.component.map_screen(np.array(label.data_point)) self._original_offset = (label.x - pointx, label.y - pointy) event.window.set_mouse_owner(self, event.net_transform()) event.handled = True diff --git a/examples/demo/cursor_tool_demo.py b/examples/demo/cursor_tool_demo.py index f39ffc856..44a61311a 100644 --- a/examples/demo/cursor_tool_demo.py +++ b/examples/demo/cursor_tool_demo.py @@ -14,6 +14,10 @@ # Enthought library imports from chaco.api import ( + ArrayDataSource, + LinePlot, + LogMapper, + DataRange1D, create_line_plot, OverlayPlotContainer, HPlotContainer, @@ -52,12 +56,24 @@ def __init__(self): value = numpy.sin(index) # create a LinePlot instance and add it to the subcontainer - line = create_line_plot( - [index, value], - add_grid=True, - add_axis=True, - index_sort="ascending", - orientation="h", + #line = create_line_plot( + ## [index, value], + # add_grid=True, + # add_axis=True, + # index_sort="ascending", + # orientation="h", + #) + line = LinePlot( + index=ArrayDataSource(index, sort_order='ascending'), + value=ArrayDataSource(value), + index_mapper=LogMapper(range=DataRange1D()), + value_mapper=LogMapper(range=DataRange1D()), + orientation='h', + color='red', + bgcolor='transparent', + line_width=1.0, + line_style='solid', + border_visible=False, ) subcontainer.add(line)