From a49fd2530c027bf1595b4e0f7d447873af2a56a2 Mon Sep 17 00:00:00 2001 From: Raphael Date: Tue, 12 Oct 2021 17:10:33 +0200 Subject: [PATCH 01/13] draw the figure after attaching the blit-manager to already cache the background --- eomaps/eomaps.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/eomaps/eomaps.py b/eomaps/eomaps.py index dadfae1fe..7e376a5d0 100644 --- a/eomaps/eomaps.py +++ b/eomaps/eomaps.py @@ -438,6 +438,9 @@ def on_close(event): self.BM = BlitManager(self.figure.f.canvas) + # trigger drawing the figure + self.figure.f.canvas.draw() + def _spatial_plot( self, data, @@ -663,9 +666,6 @@ def picker(artist, event): coll.set_picker(picker) - # trigger drawing the figure - f.canvas.draw() - self.figure = _Maps_plot( f=f, gridspec=gs, From a1ac399c0469febebd30952e79d3134af7fb93e7 Mon Sep 17 00:00:00 2001 From: Raphael Date: Tue, 12 Oct 2021 22:26:49 +0200 Subject: [PATCH 02/13] add "delauney_triangulation" as a possible shape - use try-except for scipy import to avoid it as a required dependency --- eomaps/eomaps.py | 97 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 95 insertions(+), 2 deletions(-) diff --git a/eomaps/eomaps.py b/eomaps/eomaps.py index 7e376a5d0..1dd09d733 100644 --- a/eomaps/eomaps.py +++ b/eomaps/eomaps.py @@ -336,6 +336,14 @@ def set_plot_specs(self, **kwargs): - "trimesh_rectangles": rectangles but drawn with a TriMesh collection so that there are no boundaries between the pixels. (e.g. useful for contourplots) + NOTE: setting edge- and facecolors afterwards is not possible! + - "delauney_triangulation": plot a delauney-triangulation + for the given set of data. (e.g. a dense triangulation of + irregularly spaced points) + NOTE: setting edge- and facecolors afterwards is not possible! + - "delauney_triangulation_flat": same as the normal delauney- + triangulation, but plotted as a polygon-collection so that + edgecolors etc. can be set. The default is "trimesh_rectangles". """ @@ -644,15 +652,33 @@ def _spatial_plot( # ------------- add a picker that will be used by the callbacks # use a cKDTree based picking to speed up picks for large collections tree = cKDTree(np.stack([props["x0"], props["y0"]], axis=1)) - maxdist = np.max([np.max(props["w"]), np.max(props["h"])]) + + if shape.startswith("delauney_triangulation"): + # set an infinite search-distance if triangulations are used + maxdist = np.inf + else: + maxdist = np.max([np.max(props["w"]), np.max(props["h"])]) * 2 def picker(artist, event): + if event.inaxes != self.figure.ax: + return False, None + if event.dblclick: double_click = True else: double_click = False dist, index = tree.query((event.xdata, event.ydata)) + + # always set the point as invalid if it is outside of the bounds + # (for plots like delauney-triangulations that do not require a radius) + bounds = self._bounds + if not ( + (bounds[0] < event.xdata < bounds[2]) + and (bounds[1] < event.ydata < bounds[3]) + ): + dist = np.inf + if dist < maxdist: return True, dict( ind=index, double_click=double_click, mouse_button=event.button @@ -677,6 +703,16 @@ def picker(artist, event): coll=coll, ) + @property + @lru_cache() + def _bounds(self): + return ( + self._props["x0"].min(), + self._props["y0"].min(), + self._props["x0"].max(), + self._props["y0"].max(), + ) + def _set_cpos(self, x, y, radiusx, radiusy, cpos): # use x = x + ... instead of x += to allow casting from int to float if cpos == "c": @@ -905,11 +941,23 @@ def _prepare_data( ) props["tri"] = tri + elif shape.startswith("delauney_triangulation"): + try: + from scipy.spatial import Delaunay + except ImportError: + raise ImportError("'scipy' is required for 'delauney_triangulation'!") + d = Delaunay(np.column_stack((x0, y0)), qhull_options="QJ") + + tri = Triangulation(d.points[:, 0], d.points[:, 1], d.simplices) + props["tri"] = tri else: raise TypeError( f"'{shape}' is not a valid shape, use one of:\n" - + " - 'ellipses'\n - 'rectangles'\n - 'trimesh_rectangles'" + + " - 'ellipses'\n" + + " - 'rectangles'\n" + + " - 'trimesh_rectangles'\n" + + " - 'delauney_triangulation'" ) return props @@ -1146,6 +1194,51 @@ def _add_collection( coll.set_norm(norm) # coll.set_urls(np.repeat(ids, 3, axis=0)) ax.add_collection(coll) + elif shape.startswith("delauney_triangulation"): + if shape.endswith("_flat"): + shading = "flat" + else: + shading = "gouraud" + if shading == "gouraud": + coll = TriMesh(props["tri"]) + + if color is not None: + coll.set_facecolors([color] * (len(props["x0"])) * 6) + else: + z = np.ma.masked_invalid(z_data) + # tri-contour meshes need 3 values for each triangle + z = np.tile(z, 3) + + coll.set_array(z.ravel()) + coll.set_cmap(cmap) + coll.set_clim(vmin, vmax) + coll.set_norm(norm) + + else: + tri = props["tri"] + # Vertices of triangles. + maskedTris = tri.get_masked_triangles() + verts = np.stack((tri.x[maskedTris], tri.y[maskedTris]), axis=-1) + + coll = collections.PolyCollection(verts, transOffset=ax.transData) + if color is not None: + coll.set_color(color) + else: + z = np.ma.masked_invalid(z_data) + # tri-contour meshes need 3 values for each triangle + z = np.tile(z, 3) + z = z[maskedTris].mean(axis=1) + + coll.set_array(z) + coll.set_cmap(cmap) + coll.set_clim(vmin, vmax) + coll.set_norm(norm) + + # add centroid positions (used by the picker in self._spatial_plot) + coll._Maps_positions = list(zip(props["x0"], props["y0"])) + + # coll.set_urls(np.repeat(ids, 3, axis=0)) + ax.add_collection(coll) return coll From b735482ff0aa4d1dd11b2550f2420dce97cc978c Mon Sep 17 00:00:00 2001 From: Raphael Date: Tue, 12 Oct 2021 22:29:07 +0200 Subject: [PATCH 03/13] use flatiters instead of .rave() --- eomaps/eomaps.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/eomaps/eomaps.py b/eomaps/eomaps.py index 7e376a5d0..d15ddb454 100644 --- a/eomaps/eomaps.py +++ b/eomaps/eomaps.py @@ -710,7 +710,6 @@ def _prepare_data( shape=None, buffer=None, ): - # get specifications if data is None: data = self.data @@ -885,17 +884,17 @@ def _prepare_data( verts = np.array(list(zip(*[np.array(i).T for i in (p0, p1, p2, p3)]))) x = np.vstack( [verts[:, 2][:, 0], verts[:, 3][:, 0], verts[:, 1][:, 0]] - ).T.ravel() + ).T.flat y = np.vstack( [verts[:, 2][:, 1], verts[:, 3][:, 1], verts[:, 1][:, 1]] - ).T.ravel() + ).T.flat x2 = np.vstack( [verts[:, 3][:, 0], verts[:, 0][:, 0], verts[:, 1][:, 0]] - ).T.ravel() + ).T.flat y2 = np.vstack( [verts[:, 3][:, 1], verts[:, 0][:, 1], verts[:, 1][:, 1]] - ).T.ravel() + ).T.flat x = np.append(x, x2) y = np.append(y, y2) From 04e83d5f4a7e27d1aa38fdb7895475826bf2d9d6 Mon Sep 17 00:00:00 2001 From: Raphael Date: Wed, 13 Oct 2021 00:24:03 +0200 Subject: [PATCH 04/13] expose cKDTree add masking for Delauney --- eomaps/eomaps.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/eomaps/eomaps.py b/eomaps/eomaps.py index 1dd09d733..241e3d70b 100644 --- a/eomaps/eomaps.py +++ b/eomaps/eomaps.py @@ -650,8 +650,6 @@ def _spatial_plot( f.canvas.draw_idle() # ------------- add a picker that will be used by the callbacks - # use a cKDTree based picking to speed up picks for large collections - tree = cKDTree(np.stack([props["x0"], props["y0"]], axis=1)) if shape.startswith("delauney_triangulation"): # set an infinite search-distance if triangulations are used @@ -668,7 +666,8 @@ def picker(artist, event): else: double_click = False - dist, index = tree.query((event.xdata, event.ydata)) + # use a cKDTree based picking to speed up picks for large collections + dist, index = self.tree.query((event.xdata, event.ydata)) # always set the point as invalid if it is outside of the bounds # (for plots like delauney-triangulations that do not require a radius) @@ -895,6 +894,9 @@ def _prepare_data( # calculate rotation angle based on mid-point theta = np.sign(y3 - y0) * np.rad2deg(np.arcsin(np.abs(y3 - y0) / w)) + # use a cKDTree based picking to speed up picks for large collections + self.tree = cKDTree(np.stack([x0, y0], axis=1)) + props = dict( x0=x0, y0=y0, @@ -951,6 +953,20 @@ def _prepare_data( tri = Triangulation(d.points[:, 0], d.points[:, 1], d.simplices) props["tri"] = tri + + + x = tri.x[tri.triangles] + y = tri.y[tri.triangles] + n = self.tree.query(np.column_stack((x.mean(axis=1), + y.mean(axis=1))), 3)[1] + n2 = self.tree.query(np.column_stack((x.flat, + y.flat)), + 1)[1].reshape(n.shape) + n.sort(axis=1) + n2.sort(axis=1) + mask = ~np.equal(n, n2).all(axis=1) + + tri.set_mask(mask) else: raise TypeError( f"'{shape}' is not a valid shape, use one of:\n" From 03b22329b0738a48d569e23aeac329ab65da5c86 Mon Sep 17 00:00:00 2001 From: Raphael Date: Wed, 13 Oct 2021 12:17:04 +0200 Subject: [PATCH 05/13] add sampling-based masking to Delauney triangulation --- eomaps/eomaps.py | 56 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/eomaps/eomaps.py b/eomaps/eomaps.py index fffb8d391..73c41dad2 100644 --- a/eomaps/eomaps.py +++ b/eomaps/eomaps.py @@ -344,6 +344,15 @@ def set_plot_specs(self, **kwargs): - "delauney_triangulation_flat": same as the normal delauney- triangulation, but plotted as a polygon-collection so that edgecolors etc. can be set. + - "delauney_triangulation_masked" (or "_flat_masked"): + same as "delauney_triangulation" but all triangles that + exhibit side-lengths longer than (2 x radius) are masked + + This is particularly useful to triangulate concave areas + that are densely sampled. + -> you can use the radius as a parameter for the max. + interpolation-distance! + The default is "trimesh_rectangles". """ @@ -677,7 +686,7 @@ def picker(artist, event): and (bounds[1] < event.ydata < bounds[3]) ): dist = np.inf - + print(event.xdata, event.ydata, dist, index) if dist < maxdist: return True, dict( ind=index, double_click=double_click, mouse_button=event.button @@ -894,7 +903,8 @@ def _prepare_data( theta = np.sign(y3 - y0) * np.rad2deg(np.arcsin(np.abs(y3 - y0) / w)) # use a cKDTree based picking to speed up picks for large collections - self.tree = cKDTree(np.stack([x0, y0], axis=1)) + if not hasattr(self, "figure"): + self.tree = cKDTree(np.stack([x0, y0], axis=1)) props = dict( x0=x0, @@ -943,6 +953,16 @@ def _prepare_data( props["tri"] = tri elif shape.startswith("delauney_triangulation"): + assert ( + shape == "delauney_triangulation" + or shape == "delauney_triangulation_masked" + or shape == "delauney_triangulation_flat" + or shape == "delauney_triangulation_flat_masked" + ), ( + f"the provided delauney-shape suffix '{shape}'" + + " is not valid ...use one of" + + " '_masked', '_flat' or ' _flat_masked'" + ) try: from scipy.spatial import Delaunay except ImportError: @@ -953,26 +973,32 @@ def _prepare_data( tri = Triangulation(d.points[:, 0], d.points[:, 1], d.simplices) props["tri"] = tri + if shape.endswith("_masked"): + + if radius_crs == "in": + x = xorig[tri.triangles] + y = yorig[tri.triangles] + elif radius_crs == "out": + x = x0[tri.triangles] + y = y0[tri.triangles] + else: + x = x0r[tri.triangles] + y = y0r[tri.triangles] - x = tri.x[tri.triangles] - y = tri.y[tri.triangles] - n = self.tree.query(np.column_stack((x.mean(axis=1), - y.mean(axis=1))), 3)[1] - n2 = self.tree.query(np.column_stack((x.flat, - y.flat)), - 1)[1].reshape(n.shape) - n.sort(axis=1) - n2.sort(axis=1) - mask = ~np.equal(n, n2).all(axis=1) + maxdist = np.mean(2 * np.sqrt(radiusx ** 2 + radiusy ** 2)) + l0 = np.sqrt((x[:, 0] - x[:, 1]) ** 2 + (y[:, 0] - y[:, 1]) ** 2) + l1 = np.sqrt((x[:, 0] - x[:, 2]) ** 2 + (y[:, 0] - y[:, 2]) ** 2) + l2 = np.sqrt((x[:, 1] - x[:, 2]) ** 2 + (y[:, 1] - y[:, 2]) ** 2) + mask = (l0 > maxdist) | (l1 > maxdist) | (l2 > maxdist) - tri.set_mask(mask) + tri.set_mask(mask) else: raise TypeError( f"'{shape}' is not a valid shape, use one of:\n" + " - 'ellipses'\n" + " - 'rectangles'\n" + " - 'trimesh_rectangles'\n" - + " - 'delauney_triangulation'" + + " - 'delauney_triangulation(_flat)(_masked)'" ) return props @@ -1210,7 +1236,7 @@ def _add_collection( # coll.set_urls(np.repeat(ids, 3, axis=0)) ax.add_collection(coll) elif shape.startswith("delauney_triangulation"): - if shape.endswith("_flat"): + if shape.endswith("_flat") or shape.endswith("_flat_masked"): shading = "flat" else: shading = "gouraud" From d40e968d53398d0190c8b3b974e5b662445a25ce Mon Sep 17 00:00:00 2001 From: Raphael Date: Thu, 14 Oct 2021 19:06:34 +0200 Subject: [PATCH 06/13] implement better masking for Delauney triangulation --- eomaps/eomaps.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/eomaps/eomaps.py b/eomaps/eomaps.py index 73c41dad2..0ccf3319e 100644 --- a/eomaps/eomaps.py +++ b/eomaps/eomaps.py @@ -985,11 +985,12 @@ def _prepare_data( x = x0r[tri.triangles] y = y0r[tri.triangles] - maxdist = np.mean(2 * np.sqrt(radiusx ** 2 + radiusy ** 2)) - l0 = np.sqrt((x[:, 0] - x[:, 1]) ** 2 + (y[:, 0] - y[:, 1]) ** 2) - l1 = np.sqrt((x[:, 0] - x[:, 2]) ** 2 + (y[:, 0] - y[:, 2]) ** 2) - l2 = np.sqrt((x[:, 1] - x[:, 2]) ** 2 + (y[:, 1] - y[:, 2]) ** 2) - mask = (l0 > maxdist) | (l1 > maxdist) | (l2 > maxdist) + maxdist = 2 * np.mean(np.sqrt(radiusx ** 2 + radiusy ** 2)) + + verts = np.stack((x, y), axis=2) + cpos = verts.mean(axis=1)[:, None] + cdist = np.sqrt(np.sum((verts - cpos) ** 2, axis=2)) + mask = np.any(cdist > maxdist, axis=1) tri.set_mask(mask) else: From afeeb203aed151a1ff2d517e90cfd8b00c5a2af4 Mon Sep 17 00:00:00 2001 From: Raphael Date: Thu, 14 Oct 2021 19:07:11 +0200 Subject: [PATCH 07/13] implement "Voroni" diagram as possible plot shape --- eomaps/eomaps.py | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/eomaps/eomaps.py b/eomaps/eomaps.py index 0ccf3319e..877c662c2 100644 --- a/eomaps/eomaps.py +++ b/eomaps/eomaps.py @@ -993,6 +993,45 @@ def _prepare_data( mask = np.any(cdist > maxdist, axis=1) tri.set_mask(mask) + elif shape == "Voroni": + try: + from scipy.spatial import Voronoi + from itertools import zip_longest + except ImportError: + raise ImportError("'scipy' is required for 'Voroni'!") + + maxdist = 2 * np.mean(np.sqrt(radiusx ** 2 + radiusy ** 2)) + + xy = np.column_stack((x0, y0)) + vor = Voronoi(xy) + + rect_regions = np.array(list(zip_longest(*vor.regions, fillvalue=-2))).T + # (use -2 instead of None to make np.take work as expected) + + rect_regions = rect_regions[vor.point_region] + # exclude all points at infinity + mask = np.all(np.not_equal(rect_regions, -1), axis=1) + # get the mask for the artificially added vertices + rect_mask = rect_regions == -2 + + x = np.ma.masked_array( + np.take(vor.vertices[:, 0], rect_regions), mask=rect_mask + ) + y = np.ma.masked_array( + np.take(vor.vertices[:, 1], rect_regions), mask=rect_mask + ) + rect_verts = np.ma.stack((x, y)).swapaxes(0, 1).swapaxes(1, 2) + + # exclude any polygon whose defining point is farther away than maxdist + cdist = np.sqrt(np.sum((rect_verts - vor.points[:, None]) ** 2, axis=2)) + polymask = np.all(cdist < maxdist, axis=1) + mask = np.logical_and(mask, polymask) + + verts = list(i.compressed().reshape(-1, 2) for i in rect_verts[mask]) + props["verts"] = verts + + # remember masked points + self._voroni_mask = mask else: raise TypeError( f"'{shape}' is not a valid shape, use one of:\n" @@ -1215,6 +1254,23 @@ def _add_collection( coll.set_norm(norm) # coll.set_urls(ids) ax.add_collection(coll) + elif shape == "Voroni": + coll = collections.PolyCollection( + verts=props["verts"], + transOffset=ax.transData, + ) + # add centroid positions (used by the picker in self._spatial_plot) + coll._Maps_positions = list(zip(props["x0"], props["y0"])) + + if color is not None: + coll.set_color(color) + else: + coll.set_array(np.ma.masked_invalid(z_data)[self._voroni_mask]) + coll.set_cmap(cmap) + coll.set_clim(vmin, vmax) + coll.set_norm(norm) + # coll.set_urls(ids) + ax.add_collection(coll) elif shape == "trimesh_rectangles": coll = TriMesh(props["tri"]) From bdf7a3983077c41811a192413268b6b72044a671 Mon Sep 17 00:00:00 2001 From: Raphael Date: Thu, 14 Oct 2021 20:03:32 +0200 Subject: [PATCH 08/13] add second mask-condition for delauney add _shapes property (for testing) --- eomaps/eomaps.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/eomaps/eomaps.py b/eomaps/eomaps.py index 877c662c2..633e2d11a 100644 --- a/eomaps/eomaps.py +++ b/eomaps/eomaps.py @@ -98,6 +98,17 @@ class Maps(object): or below the map ("vertical"). The default is "vertical" """ + _shapes = [ + "ellipses", + "rectangles", + "trimesh_rectangles", + "delauney_triangulation", + "delauney_triangulation_flat", + "delauney_triangulation_masked", + "delauney_triangulation_flat_masked", + "Voroni", + ] + def __init__( self, orientation="vertical", @@ -974,7 +985,6 @@ def _prepare_data( props["tri"] = tri if shape.endswith("_masked"): - if radius_crs == "in": x = xorig[tri.triangles] y = yorig[tri.triangles] @@ -985,12 +995,15 @@ def _prepare_data( x = x0r[tri.triangles] y = y0r[tri.triangles] - maxdist = 2 * np.mean(np.sqrt(radiusx ** 2 + radiusy ** 2)) + maxdist = 4 * np.mean(np.sqrt(radiusx ** 2 + radiusy ** 2)) verts = np.stack((x, y), axis=2) cpos = verts.mean(axis=1)[:, None] cdist = np.sqrt(np.sum((verts - cpos) ** 2, axis=2)) - mask = np.any(cdist > maxdist, axis=1) + + mask = np.logical_or( + np.any(cdist > maxdist * 2, axis=1), cdist.mean(axis=1) > maxdist + ) tri.set_mask(mask) elif shape == "Voroni": From 8c5cb3ce45d3bd652af9be6d155448d678231fdd Mon Sep 17 00:00:00 2001 From: Raphael Date: Thu, 14 Oct 2021 20:03:48 +0200 Subject: [PATCH 09/13] test all plot shapes --- tests/test_basic_functions.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/tests/test_basic_functions.py b/tests/test_basic_functions.py index d7e2d727d..1c86f865d 100644 --- a/tests/test_basic_functions.py +++ b/tests/test_basic_functions.py @@ -8,7 +8,7 @@ class TestBasicPlotting(unittest.TestCase): def setUp(self): x, y = np.meshgrid( - np.linspace(-19000000, 19000000, 20), np.linspace(-19000000, 19000000, 20) + np.linspace(-19000000, 19000000, 50), np.linspace(-19000000, 19000000, 50) ) x, y = x.ravel(), y.ravel() @@ -23,12 +23,14 @@ def test_simple_map(self): plt.close(m.figure.f) - def test_simple_rectangles(self): - m = Maps() - m.data = self.data - m.set_data_specs(xcoord="x", ycoord="y", in_crs=3857) - m.set_plot_specs(plot_epsg=4326, shape="rectangles") - m.plot_map() + def test_simple_plot_shapes(self): + usedata = self.data.sample(500) + for shape in Maps._shapes: + m = Maps() + m.data = usedata + m.set_data_specs(xcoord="x", ycoord="y", in_crs=3857) + m.set_plot_specs(plot_epsg=4326, shape=shape) + m.plot_map() plt.close(m.figure.f) From f20662693a2e8000ab9a4c9b0012d59d6c7316db Mon Sep 17 00:00:00 2001 From: Raphael Date: Thu, 14 Oct 2021 20:04:11 +0200 Subject: [PATCH 10/13] close figures in test --- tests/test_basic_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_basic_functions.py b/tests/test_basic_functions.py index 1c86f865d..e5ccad04a 100644 --- a/tests/test_basic_functions.py +++ b/tests/test_basic_functions.py @@ -32,7 +32,7 @@ def test_simple_plot_shapes(self): m.set_plot_specs(plot_epsg=4326, shape=shape) m.plot_map() - plt.close(m.figure.f) + plt.close(m.figure.f) def test_simple_map2(self): m = Maps() From 061fbb9a88385679dadb1c39eac1d880c79cd21a Mon Sep 17 00:00:00 2001 From: Raphael Date: Thu, 14 Oct 2021 20:11:06 +0200 Subject: [PATCH 11/13] fix codecov link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1b1470268..d5ab9c69b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ [![tests](https://github.com/raphaelquast/EOmaps/actions/workflows/testMaps.yml/badge.svg?branch=master)](https://github.com/raphaelquast/EOmaps/actions/workflows/testMaps.yml) -[![codecov](https://codecov.io/gh/raphaelquast/EOmaps/branch/dev/graph/badge.svg?token=25M85P7MJG)](https://codecov.io/gh/raphaelquast/MapIt) +[![codecov](https://codecov.io/gh/raphaelquast/EOmaps/branch/dev/graph/badge.svg?token=25M85P7MJG)](https://codecov.io/gh/raphaelquast/EOmaps) [![pypi](https://img.shields.io/pypi/v/eomaps)](https://pypi.org/project/eomaps/) # EOmaps From 01801a8c60efae7c47b5d8546d68e9e6e58a4132 Mon Sep 17 00:00:00 2001 From: Raphael Date: Fri, 15 Oct 2021 10:19:42 +0200 Subject: [PATCH 12/13] minor re-structuring --- eomaps/eomaps.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/eomaps/eomaps.py b/eomaps/eomaps.py index 633e2d11a..965d53de2 100644 --- a/eomaps/eomaps.py +++ b/eomaps/eomaps.py @@ -669,14 +669,26 @@ def _spatial_plot( f.canvas.draw_idle() - # ------------- add a picker that will be used by the callbacks - if shape.startswith("delauney_triangulation"): # set an infinite search-distance if triangulations are used maxdist = np.inf else: maxdist = np.max([np.max(props["w"]), np.max(props["h"])]) * 2 + # ------------- add a picker that will be used by the callbacks + self._attach_picker(coll, maxdist) + self.figure = _Maps_plot( + f=f, + gridspec=gs, + ax=ax, + ax_cb=cb_ax, + ax_cb_plot=cb_plot_ax, + cb=cb, + cb_gridspec=cbgs, + coll=coll, + ) + + def _attach_picker(self, coll, maxdist): def picker(artist, event): if event.inaxes != self.figure.ax: return False, None @@ -711,17 +723,6 @@ def picker(artist, event): coll.set_picker(picker) - self.figure = _Maps_plot( - f=f, - gridspec=gs, - ax=ax, - ax_cb=cb_ax, - ax_cb_plot=cb_plot_ax, - cb=cb, - cb_gridspec=cbgs, - coll=coll, - ) - @property @lru_cache() def _bounds(self): From c7a37845a21b92f532997d61b65eae65a50594f1 Mon Sep 17 00:00:00 2001 From: Raphael Date: Fri, 15 Oct 2021 10:25:03 +0200 Subject: [PATCH 13/13] remove print-command --- eomaps/eomaps.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eomaps/eomaps.py b/eomaps/eomaps.py index 965d53de2..12c2c4e46 100644 --- a/eomaps/eomaps.py +++ b/eomaps/eomaps.py @@ -709,7 +709,7 @@ def picker(artist, event): and (bounds[1] < event.ydata < bounds[3]) ): dist = np.inf - print(event.xdata, event.ydata, dist, index) + if dist < maxdist: return True, dict( ind=index, double_click=double_click, mouse_button=event.button