From 4ce5ccc01040ffe26f873a05ed9d2463ee36025f Mon Sep 17 00:00:00 2001 From: Robert Kern Date: Mon, 18 Dec 2017 12:45:51 -0800 Subject: [PATCH 1/8] Merge pull request #394 from enthought/fix/chain BUG: Fix use of itertools.chain() --- chaco/plot.py | 2 +- chaco/tests/plot_test_case.py | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/chaco/plot.py b/chaco/plot.py index 5b17199f1..cb4a690b6 100644 --- a/chaco/plot.py +++ b/chaco/plot.py @@ -1276,7 +1276,7 @@ def _handle_range_changed(self, name, old, new): if new is not None: new.add(datasource) range_name = name + "_range" - for renderer in itertools.chain(six.itervalues(self.plots)): + for renderer in itertools.chain(*six.itervalues(self.plots)): if hasattr(renderer, range_name): setattr(renderer, range_name, new) diff --git a/chaco/tests/plot_test_case.py b/chaco/tests/plot_test_case.py index 3234dcf20..ceb4207a0 100644 --- a/chaco/tests/plot_test_case.py +++ b/chaco/tests/plot_test_case.py @@ -3,7 +3,7 @@ from numpy import arange # Chaco imports -from chaco.api import ArrayPlotData, Plot +from chaco.api import ArrayPlotData, Plot, DataRange1D class PlotTestCase(unittest.TestCase): @@ -18,5 +18,18 @@ def test_plot_from_unsupported_array_shape(self): data.update_data(x=arr, y=arr) self.assertRaises(ValueError, plot.plot, ("x", "y")) + def test_range_change(self): + arr = arange(10) + data = ArrayPlotData(x=arr, y=arr) + plot = Plot(data) + renderer = plot.plot(('x', 'y'))[0] + new_range = DataRange1D() + old_range = plot.index_range + self.assertIsNot(old_range, new_range) + self.assertIs(renderer.index_range, old_range) + plot.index_range = new_range + self.assertIs(plot.index_range, new_range) + self.assertIs(renderer.index_range, new_range) + if __name__ == "__main__": unittest.main() From f8400f1567ca625a18653ca45a28f43eaf1b3c65 Mon Sep 17 00:00:00 2001 From: John Wiggins Date: Fri, 30 Mar 2018 13:21:50 +0200 Subject: [PATCH 2/8] Merge pull request #402 from enthought/fix/legend-highlighter-visibility FIX: Respect visibility in the LegendHighlighter --- chaco/tools/legend_highlighter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chaco/tools/legend_highlighter.py b/chaco/tools/legend_highlighter.py index 0d2bf5469..c0df6cf37 100644 --- a/chaco/tools/legend_highlighter.py +++ b/chaco/tools/legend_highlighter.py @@ -1,6 +1,5 @@ import operator -import six import six.moves as sm # ETS imports @@ -50,7 +49,8 @@ class LegendHighlighter(LegendTool): _selected_renderers = List def normal_left_down(self, event): - if not self.component.is_in(event.x, event.y): + if (not self.component.visible or + not self.component.is_in(event.x, event.y)): return plots = get_hit_plots(self.component, event) From 0113552932a2dfb5b3b72e7f7dc7c9b2966da172 Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Sat, 31 Mar 2018 08:42:31 +0100 Subject: [PATCH 3/8] Merge pull request #401 from enthought/fix/six-moves-import FIX: alias six.moves as sm --- chaco/errorbar_plot.py | 3 +-- chaco/tests/errorbarplot_test_case.py | 36 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 chaco/tests/errorbarplot_test_case.py diff --git a/chaco/errorbar_plot.py b/chaco/errorbar_plot.py index 261729fae..e50c7c59e 100644 --- a/chaco/errorbar_plot.py +++ b/chaco/errorbar_plot.py @@ -2,7 +2,7 @@ from __future__ import with_statement import six -import six.moves +import six.moves as sm # Major library imports from numpy import column_stack, compress, invert, isnan, transpose @@ -159,4 +159,3 @@ def _render_bar_endcap(self, gc, start, end, low, high, axis): def _render_icon(self, gc, x, y, width, height): pass - diff --git a/chaco/tests/errorbarplot_test_case.py b/chaco/tests/errorbarplot_test_case.py new file mode 100644 index 000000000..70a7a0bc5 --- /dev/null +++ b/chaco/tests/errorbarplot_test_case.py @@ -0,0 +1,36 @@ +import unittest + +import numpy as np +from numpy import alltrue + +# Chaco imports +from chaco.api import ( + ArrayDataSource, DataRange1D, ErrorBarPlot, LinearMapper, + PlotGraphicsContext +) + + +class DrawErrorBarPlotCase(unittest.TestCase): + def test_errorbarplot(self): + """ Coverage test to check basic case works """ + size = (50, 50) + x = np.array([1, 2]) + y = np.array([5, 10]) + errors = np.array([1, 2]) + low = ArrayDataSource(y - errors) + high = ArrayDataSource(y + errors) + errorbar_plot = ErrorBarPlot( + index=ArrayDataSource(x), + values=ArrayDataSource(y), + index_mapper=LinearMapper(range=DataRange1D(low=0, high=3)), + value_mapper=LinearMapper(range=DataRange1D(low=0, high=15)), + value_low=low, + value_high=high, + color='blue', + line_width=3.0, + ) + errorbar_plot.outer_bounds = list(size) + gc = PlotGraphicsContext(size) + gc.render_component(errorbar_plot) + actual = gc.bmp_array[:, :, :] + self.assertFalse(alltrue(actual == 255)) From 525a48b45920a6b0801d96dd9216c06eb1c754bb Mon Sep 17 00:00:00 2001 From: John Wiggins Date: Fri, 30 Mar 2018 17:47:40 +0200 Subject: [PATCH 4/8] Merge pull request #403 from enthought/fix/legend-highlighter-multiplot FIX: Handle multiple plots in LegendHighlighter --- chaco/tools/legend_highlighter.py | 57 +++++++++++++++++-------------- examples/demo/multiaxis.py | 5 +-- 2 files changed, 35 insertions(+), 27 deletions(-) diff --git a/chaco/tools/legend_highlighter.py b/chaco/tools/legend_highlighter.py index c0df6cf37..5ad9c3579 100644 --- a/chaco/tools/legend_highlighter.py +++ b/chaco/tools/legend_highlighter.py @@ -1,11 +1,19 @@ -import operator - -import six.moves as sm +from itertools import chain # ETS imports from chaco.tools.api import LegendTool from traits.api import List, Float +concat = chain.from_iterable + + +def _ensure_list(obj): + """ NOTE: The Legend stores plots in a dictionary with either single + renderers as values, or lists of renderers. + This function helps us assume we're always working with lists + """ + return obj if isinstance(obj, list) else [obj] + def get_hit_plots(legend, event): if legend is None or not legend.is_in(event.x, event.y): @@ -26,7 +34,7 @@ def get_hit_plots(legend, event): ndx = legend._cached_labels.index(label) label_name = legend._cached_label_names[ndx] renderers = legend.plots[label_name] - return renderers + return _ensure_list(renderers) except (ValueError, KeyError): return [] @@ -54,35 +62,34 @@ def normal_left_down(self, event): return plots = get_hit_plots(self.component, event) - - if len(plots) > 0: - plot = plots[0] - - if event.shift_down: - # User in multi-select mode by using [shift] key. + if event.shift_down: + # User in multi-select mode by using [shift] key. + for plot in plots: if plot in self._selected_renderers: self._selected_renderers.remove(plot) else: self._selected_renderers.append(plot) - - else: - # User in single-select mode. - add_plot = plot not in self._selected_renderers - self._selected_renderers = [] - if add_plot: - self._selected_renderers.append(plot) - - if self._selected_renderers: - self._set_states(self.component.plots) - else: - self._reset_selects(self.component.plots) - plot.request_redraw() + elif plots: + # User in single-select mode. + add_plot = any(plot not in self._selected_renderers + for plot in plots) + self._selected_renderers = [] + if add_plot: + self._selected_renderers.extend(plots) + + if self._selected_renderers: + self._set_states(self.component.plots) + else: + self._reset_selects(self.component.plots) + + if plots: + plots[0].request_redraw() event.handled = True def _reset_selects(self, plots): """ Set all renderers to their default values. """ - for plot in sm.reduce(operator.add, plots.values()): + for plot in concat(_ensure_list(p) for p in plots.values()): if not hasattr(plot, '_orig_alpha'): plot._orig_alpha = plot.alpha plot._orig_line_width = plot.line_width @@ -92,7 +99,7 @@ def _reset_selects(self, plots): def _set_states(self, plots): """ Decorates a plot to indicate it is selected """ - for plot in sm.reduce(operator.add, plots.values()): + for plot in concat(_ensure_list(p) for p in plots.values()): if not hasattr(plot, '_orig_alpha'): # FIXME: These attributes should be put into the class def. plot._orig_alpha = plot.alpha diff --git a/examples/demo/multiaxis.py b/examples/demo/multiaxis.py index 451a95fbc..f6a4a3c26 100644 --- a/examples/demo/multiaxis.py +++ b/examples/demo/multiaxis.py @@ -25,8 +25,8 @@ from chaco.api import create_line_plot, add_default_axes, \ add_default_grids, OverlayPlotContainer, \ PlotLabel, Legend, PlotAxis -from chaco.tools.api import PanTool, LegendTool, TraitsTool, \ - BroadcasterTool +from chaco.tools.api import (PanTool, LegendTool, LegendHighlighter, + TraitsTool, BroadcasterTool) #=============================================================================== # # Create the Chaco plot. @@ -76,6 +76,7 @@ def _create_plot_component(): legend = Legend(component=container, padding=10, align="ur") legend.tools.append(LegendTool(legend, drag_button="right")) + legend.tools.append(LegendHighlighter(legend)) container.overlays.append(legend) # Set the list of plots on the legend From 0bfc04aa540d64bd1a4ba3df89d6ac7bbf5d89bd Mon Sep 17 00:00:00 2001 From: John Wiggins Date: Mon, 2 Jul 2018 11:04:49 +0200 Subject: [PATCH 5/8] FIX: Pass a C-contiguous array to points_in_polygon (#409) --- chaco/tools/lasso_selection.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/chaco/tools/lasso_selection.py b/chaco/tools/lasso_selection.py index f3c7bc57c..fa2d5b4f9 100644 --- a/chaco/tools/lasso_selection.py +++ b/chaco/tools/lasso_selection.py @@ -2,7 +2,7 @@ """ # Major library imports import numpy -from numpy import array, empty, sometrue, transpose, vstack, zeros +from numpy import array, empty, sometrue, vstack, zeros, ascontiguousarray # Enthought library imports from traits.api import Any, Array, Enum, Event, Bool, Instance, \ @@ -308,8 +308,9 @@ def _map_data(self, point): def _get_data(self): """ Returns the datapoints in the plot, as an Nx2 array of (x,y). """ - return transpose(array((self.plot.index.get_data(), self.plot.value.get_data()))) - + points = array((self.plot.index.get_data(), + self.plot.value.get_data())) + return ascontiguousarray(points.T) #------------------------------------------------------------------------ # Property getter/setters From 6915dce0a4b8b574f51d50a4858accabbef7772b Mon Sep 17 00:00:00 2001 From: John Wiggins Date: Tue, 3 Jul 2018 13:51:52 +0200 Subject: [PATCH 6/8] FIX: Ensure contiguous inputs to points_in_polygon (#410) --- chaco/polygon_plot.py | 2 +- chaco/tools/lasso_selection.py | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/chaco/polygon_plot.py b/chaco/polygon_plot.py index 4234bf667..aec89af41 100644 --- a/chaco/polygon_plot.py +++ b/chaco/polygon_plot.py @@ -134,7 +134,7 @@ def hittest(self, screen_pt, threshold=7.0, return_distance=False): data_pt = self.map_data(screen_pt, all_values=True) index = self.index.get_data() value = self.value.get_data() - poly = np.vstack((index,value)).T + poly = np.column_stack((index, value)) if points_in_polygon([data_pt], poly)[0] == 1: return True else: diff --git a/chaco/tools/lasso_selection.py b/chaco/tools/lasso_selection.py index fa2d5b4f9..053eb863d 100644 --- a/chaco/tools/lasso_selection.py +++ b/chaco/tools/lasso_selection.py @@ -2,7 +2,7 @@ """ # Major library imports import numpy -from numpy import array, empty, sometrue, vstack, zeros, ascontiguousarray +from numpy import array, column_stack, empty, sometrue, vstack, zeros # Enthought library imports from traits.api import Any, Array, Enum, Event, Bool, Instance, \ @@ -308,9 +308,8 @@ def _map_data(self, point): def _get_data(self): """ Returns the datapoints in the plot, as an Nx2 array of (x,y). """ - points = array((self.plot.index.get_data(), - self.plot.value.get_data())) - return ascontiguousarray(points.T) + return column_stack((self.plot.index.get_data(), + self.plot.value.get_data())) #------------------------------------------------------------------------ # Property getter/setters From 7dc3b85247dcfdfb82c9ee476be0fb2aaa5f572f Mon Sep 17 00:00:00 2001 From: John Wiggins Date: Thu, 12 Jul 2018 11:15:39 -0400 Subject: [PATCH 7/8] REL: v4.7.2 --- CHANGES.txt | 12 ++++++++++++ setup.py | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGES.txt b/CHANGES.txt index 76991fe2e..fb6abb18e 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -2,6 +2,18 @@ Chaco CHANGELOG =============== +Release 4.7.2 +------------- + +Fixes + +* FIX: Ensure contiguous inputs to points_in_polygon (#409 & #410) +* FIX: Handle multiple plots in LegendHighlighter (#403) +* FIX: alias six.moves as sm (#401) +* FIX: Respect visibility in the LegendHighlighter (#402) +* BUG: Fix use of itertools.chain() (#394) + + Release 4.7.1 ------------- diff --git a/setup.py b/setup.py index 66a1bf24a..4047e2e47 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ MINOR = 7 MICRO = 2 -IS_RELEASED = False +IS_RELEASED = True VERSION = '%d.%d.%d' % (MAJOR, MINOR, MICRO) From cc15df9bf39127c139674dcf13d1fdec166ca57c Mon Sep 17 00:00:00 2001 From: John Wiggins Date: Thu, 12 Jul 2018 11:16:43 -0400 Subject: [PATCH 8/8] Post-release version bump --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 4047e2e47..29fd20dcf 100644 --- a/setup.py +++ b/setup.py @@ -9,9 +9,9 @@ MAJOR = 4 MINOR = 7 -MICRO = 2 +MICRO = 3 -IS_RELEASED = True +IS_RELEASED = False VERSION = '%d.%d.%d' % (MAJOR, MINOR, MICRO)