Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit a515fc5

Browse filesBrowse files
authored
Merge pull request #25556 from anntzer/twincursor
Display cursor coordinates for all axes twinned with the current one.
2 parents d0faf22 + c5b2158 commit a515fc5
Copy full SHA for a515fc5

File tree

Expand file treeCollapse file tree

3 files changed

+51
-18
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+51
-18
lines changed

‎lib/matplotlib/axes/_base.py

Copy file name to clipboardExpand all lines: lib/matplotlib/axes/_base.py
+14-4Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3976,10 +3976,20 @@ def format_ydata(self, y):
39763976

39773977
def format_coord(self, x, y):
39783978
"""Return a format string formatting the *x*, *y* coordinates."""
3979-
return "x={} y={}".format(
3980-
"???" if x is None else self.format_xdata(x),
3981-
"???" if y is None else self.format_ydata(y),
3982-
)
3979+
twins = self._twinned_axes.get_siblings(self)
3980+
if len(twins) == 1:
3981+
return "(x, y) = ({}, {})".format(
3982+
"???" if x is None else self.format_xdata(x),
3983+
"???" if y is None else self.format_ydata(y))
3984+
screen_xy = self.transData.transform((x, y))
3985+
xy_strs = []
3986+
# Retrieve twins in the order of self.figure.axes to sort tied zorders (which is
3987+
# the common case) by the order in which they are added to the figure.
3988+
for ax in sorted(twins, key=attrgetter("zorder")):
3989+
data_x, data_y = ax.transData.inverted().transform(screen_xy)
3990+
xy_strs.append(
3991+
"({}, {})".format(ax.format_xdata(data_x), ax.format_ydata(data_y)))
3992+
return "(x, y) = {}".format(" | ".join(xy_strs))
39833993

39843994
def minorticks_on(self):
39853995
"""

‎lib/matplotlib/cbook.py

Copy file name to clipboardExpand all lines: lib/matplotlib/cbook.py
+23-8Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -849,19 +849,26 @@ class Grouper:
849849
def __init__(self, init=()):
850850
self._mapping = weakref.WeakKeyDictionary(
851851
{x: weakref.WeakSet([x]) for x in init})
852+
self._ordering = weakref.WeakKeyDictionary()
853+
for x in init:
854+
if x not in self._ordering:
855+
self._ordering[x] = len(self._ordering)
856+
self._next_order = len(self._ordering) # Plain int to simplify pickling.
852857

853858
def __getstate__(self):
854859
return {
855860
**vars(self),
856861
# Convert weak refs to strong ones.
857862
"_mapping": {k: set(v) for k, v in self._mapping.items()},
863+
"_ordering": {**self._ordering},
858864
}
859865

860866
def __setstate__(self, state):
861867
vars(self).update(state)
862868
# Convert strong refs to weak ones.
863869
self._mapping = weakref.WeakKeyDictionary(
864870
{k: weakref.WeakSet(v) for k, v in self._mapping.items()})
871+
self._ordering = weakref.WeakKeyDictionary(self._ordering)
865872

866873
def __contains__(self, item):
867874
return item in self._mapping
@@ -875,10 +882,19 @@ def join(self, a, *args):
875882
Join given arguments into the same set. Accepts one or more arguments.
876883
"""
877884
mapping = self._mapping
878-
set_a = mapping.setdefault(a, weakref.WeakSet([a]))
879-
885+
try:
886+
set_a = mapping[a]
887+
except KeyError:
888+
set_a = mapping[a] = weakref.WeakSet([a])
889+
self._ordering[a] = self._next_order
890+
self._next_order += 1
880891
for arg in args:
881-
set_b = mapping.get(arg, weakref.WeakSet([arg]))
892+
try:
893+
set_b = mapping[arg]
894+
except KeyError:
895+
set_b = mapping[arg] = weakref.WeakSet([arg])
896+
self._ordering[arg] = self._next_order
897+
self._next_order += 1
882898
if set_b is not set_a:
883899
if len(set_b) > len(set_a):
884900
set_a, set_b = set_b, set_a
@@ -892,9 +908,8 @@ def joined(self, a, b):
892908

893909
def remove(self, a):
894910
"""Remove *a* from the grouper, doing nothing if it is not there."""
895-
set_a = self._mapping.pop(a, None)
896-
if set_a:
897-
set_a.remove(a)
911+
self._mapping.pop(a, {a}).remove(a)
912+
self._ordering.pop(a, None)
898913

899914
def __iter__(self):
900915
"""
@@ -904,12 +919,12 @@ def __iter__(self):
904919
"""
905920
unique_groups = {id(group): group for group in self._mapping.values()}
906921
for group in unique_groups.values():
907-
yield [x for x in group]
922+
yield sorted(group, key=self._ordering.__getitem__)
908923

909924
def get_siblings(self, a):
910925
"""Return all of the items joined with *a*, including itself."""
911926
siblings = self._mapping.get(a, [a])
912-
return [x for x in siblings]
927+
return sorted(siblings, key=self._ordering.get)
913928

914929

915930
class GrouperView:

‎lib/matplotlib/tests/test_backend_bases.py

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/test_backend_bases.py
+14-6Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import re
2-
31
from matplotlib import path, transforms
42
from matplotlib.backend_bases import (
53
FigureCanvasBase, KeyEvent, LocationEvent, MouseButton, MouseEvent,
@@ -123,11 +121,21 @@ def test_location_event_position(x, y):
123121
assert event.y == int(y)
124122
assert isinstance(event.y, int)
125123
if x is not None and y is not None:
126-
assert re.match(
127-
f"x={ax.format_xdata(x)} +y={ax.format_ydata(y)}",
128-
ax.format_coord(x, y))
124+
assert (ax.format_coord(x, y)
125+
== f"(x, y) = ({ax.format_xdata(x)}, {ax.format_ydata(y)})")
129126
ax.fmt_xdata = ax.fmt_ydata = lambda x: "foo"
130-
assert re.match("x=foo +y=foo", ax.format_coord(x, y))
127+
assert ax.format_coord(x, y) == "(x, y) = (foo, foo)"
128+
129+
130+
def test_location_event_position_twin():
131+
fig, ax = plt.subplots()
132+
ax.set(xlim=(0, 10), ylim=(0, 20))
133+
assert ax.format_coord(5., 5.) == "(x, y) = (5.00, 5.00)"
134+
ax.twinx().set(ylim=(0, 40))
135+
assert ax.format_coord(5., 5.) == "(x, y) = (5.00, 5.00) | (5.00, 10.0)"
136+
ax.twiny().set(xlim=(0, 5))
137+
assert (ax.format_coord(5., 5.)
138+
== "(x, y) = (5.00, 5.00) | (5.00, 10.0) | (2.50, 5.00)")
131139

132140

133141
def test_pick():

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.