From ae7f7697b264d204850e08a06e36eb53dccfd637 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Tue, 2 Apr 2024 14:06:46 +0200 Subject: [PATCH 1/2] Make Grouper return siblings in the order in which they have been seen. --- lib/matplotlib/cbook.py | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/lib/matplotlib/cbook.py b/lib/matplotlib/cbook.py index ee043f351dbb..a41bfe56744f 100644 --- a/lib/matplotlib/cbook.py +++ b/lib/matplotlib/cbook.py @@ -849,12 +849,18 @@ class Grouper: def __init__(self, init=()): self._mapping = weakref.WeakKeyDictionary( {x: weakref.WeakSet([x]) for x in init}) + self._ordering = weakref.WeakKeyDictionary() + for x in init: + if x not in self._ordering: + self._ordering[x] = len(self._ordering) + self._next_order = len(self._ordering) # Plain int to simplify pickling. def __getstate__(self): return { **vars(self), # Convert weak refs to strong ones. "_mapping": {k: set(v) for k, v in self._mapping.items()}, + "_ordering": {**self._ordering}, } def __setstate__(self, state): @@ -862,6 +868,7 @@ def __setstate__(self, state): # Convert strong refs to weak ones. self._mapping = weakref.WeakKeyDictionary( {k: weakref.WeakSet(v) for k, v in self._mapping.items()}) + self._ordering = weakref.WeakKeyDictionary(self._ordering) def __contains__(self, item): return item in self._mapping @@ -875,10 +882,19 @@ def join(self, a, *args): Join given arguments into the same set. Accepts one or more arguments. """ mapping = self._mapping - set_a = mapping.setdefault(a, weakref.WeakSet([a])) - + try: + set_a = mapping[a] + except KeyError: + set_a = mapping[a] = weakref.WeakSet([a]) + self._ordering[a] = self._next_order + self._next_order += 1 for arg in args: - set_b = mapping.get(arg, weakref.WeakSet([arg])) + try: + set_b = mapping[arg] + except KeyError: + set_b = mapping[arg] = weakref.WeakSet([arg]) + self._ordering[arg] = self._next_order + self._next_order += 1 if set_b is not set_a: if len(set_b) > len(set_a): set_a, set_b = set_b, set_a @@ -892,9 +908,8 @@ def joined(self, a, b): def remove(self, a): """Remove *a* from the grouper, doing nothing if it is not there.""" - set_a = self._mapping.pop(a, None) - if set_a: - set_a.remove(a) + self._mapping.pop(a, {a}).remove(a) + self._ordering.pop(a, None) def __iter__(self): """ @@ -904,12 +919,12 @@ def __iter__(self): """ unique_groups = {id(group): group for group in self._mapping.values()} for group in unique_groups.values(): - yield [x for x in group] + yield sorted(group, key=self._ordering.__getitem__) def get_siblings(self, a): """Return all of the items joined with *a*, including itself.""" siblings = self._mapping.get(a, [a]) - return [x for x in siblings] + return sorted(siblings, key=self._ordering.get) class GrouperView: From c5b2158e0d354b632d9ec4158cf25153fb267811 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Sun, 26 Mar 2023 23:45:00 +0200 Subject: [PATCH 2/2] Display cursor coordinates for all axes twinned with the current one. --- lib/matplotlib/axes/_base.py | 18 ++++++++++++++---- lib/matplotlib/tests/test_backend_bases.py | 20 ++++++++++++++------ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index 36baff85fa66..23cc1c869c07 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -3976,10 +3976,20 @@ def format_ydata(self, y): def format_coord(self, x, y): """Return a format string formatting the *x*, *y* coordinates.""" - return "x={} y={}".format( - "???" if x is None else self.format_xdata(x), - "???" if y is None else self.format_ydata(y), - ) + twins = self._twinned_axes.get_siblings(self) + if len(twins) == 1: + return "(x, y) = ({}, {})".format( + "???" if x is None else self.format_xdata(x), + "???" if y is None else self.format_ydata(y)) + screen_xy = self.transData.transform((x, y)) + xy_strs = [] + # Retrieve twins in the order of self.figure.axes to sort tied zorders (which is + # the common case) by the order in which they are added to the figure. + for ax in sorted(twins, key=attrgetter("zorder")): + data_x, data_y = ax.transData.inverted().transform(screen_xy) + xy_strs.append( + "({}, {})".format(ax.format_xdata(data_x), ax.format_ydata(data_y))) + return "(x, y) = {}".format(" | ".join(xy_strs)) def minorticks_on(self): """ diff --git a/lib/matplotlib/tests/test_backend_bases.py b/lib/matplotlib/tests/test_backend_bases.py index 399949c93bef..c264f01acdb2 100644 --- a/lib/matplotlib/tests/test_backend_bases.py +++ b/lib/matplotlib/tests/test_backend_bases.py @@ -1,5 +1,3 @@ -import re - from matplotlib import path, transforms from matplotlib.backend_bases import ( FigureCanvasBase, KeyEvent, LocationEvent, MouseButton, MouseEvent, @@ -123,11 +121,21 @@ def test_location_event_position(x, y): assert event.y == int(y) assert isinstance(event.y, int) if x is not None and y is not None: - assert re.match( - f"x={ax.format_xdata(x)} +y={ax.format_ydata(y)}", - ax.format_coord(x, y)) + assert (ax.format_coord(x, y) + == f"(x, y) = ({ax.format_xdata(x)}, {ax.format_ydata(y)})") ax.fmt_xdata = ax.fmt_ydata = lambda x: "foo" - assert re.match("x=foo +y=foo", ax.format_coord(x, y)) + assert ax.format_coord(x, y) == "(x, y) = (foo, foo)" + + +def test_location_event_position_twin(): + fig, ax = plt.subplots() + ax.set(xlim=(0, 10), ylim=(0, 20)) + assert ax.format_coord(5., 5.) == "(x, y) = (5.00, 5.00)" + ax.twinx().set(ylim=(0, 40)) + assert ax.format_coord(5., 5.) == "(x, y) = (5.00, 5.00) | (5.00, 10.0)" + ax.twiny().set(xlim=(0, 5)) + assert (ax.format_coord(5., 5.) + == "(x, y) = (5.00, 5.00) | (5.00, 10.0) | (2.50, 5.00)") def test_pick(): pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy