Skip to content

ENH: allow changing the Axes sort order for event handling #2986

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
2014-05-03 Added Figure.swap_axes_order() method to exchange the
sort order of two Axes objects.

2014-05-02 Added colorblind-friendly colormap, named 'Wistia'.

2014-04-27 Improved input clean up in Axes.{h|v}lines
Expand Down
5 changes: 5 additions & 0 deletions doc/api/api_changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,11 @@ original location:

* Added clockwise parameter to control sectors direction in `axes.pie`

* Added :func:`~matplotlib.Figure.swap_axes_order` so that when using
:func:`~matplotlib.axes.Axes.twinx`, for example, one can restore
the original Axes as the one receiving mouse and keypress events.


Code removal
------------

Expand Down
12 changes: 9 additions & 3 deletions doc/users/whats_new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ New plotting features
Power-law normalization
```````````````````````
Ben Gamari added a power-law normalization method,
:class:`~matplotlib.colors.PowerNorm`. This class maps a range of
:class:`~matplotlib.colors.PowerNorm`. This class maps a range of
values to the interval [0,1] with power-law scaling with the exponent
provided by the constructor's `gamma` argument. Power law normalization
can be useful for, e.g., emphasizing small populations in a histogram.
Expand Down Expand Up @@ -152,8 +152,8 @@ specifically the Skew-T used in meteorology.

.. plot:: mpl_examples/api/skewt.py

Support for specifying properties of wedge and text in pie charts.
``````````````````````````````````````````````````````````````
Support for specifying properties of wedge and text in pie charts
`````````````````````````````````````````````````````````````````
Added the `kwargs` 'wedgeprops' and 'textprops' to :func:`~matplotlib.Axes.pie`
to accept properties for wedge and text objects in a pie. For example, one can
specify wedgeprops = {'linewidth':3} to specify the width of the borders of
Expand All @@ -166,6 +166,12 @@ Larry Bradley fixed the :func:`~matplotlib.pyplot.errorbar` method such
that the upper and lower limits (*lolims*, *uplims*, *xlolims*,
*xuplims*) now point in the correct direction.

Support for controlling Axes sort order in a Figure
```````````````````````````````````````````````````
Added :func:`~matplotlib.Figure.swap_axes_order` so that when using
:func:`~matplotlib.axes.Axes.twinx`, for example, one can restore
the original Axes as the one receiving mouse and keypress events.

Date handling
-------------

Expand Down
6 changes: 6 additions & 0 deletions examples/api/two_scales.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,11 @@
ax2.set_ylabel('sin', color='r')
for tl in ax2.get_yticklabels():
tl.set_color('r')

# By default, the most recently-added Axes will be the one
# receiving mouse events such as cursor position. To reverse
# this, use the following Figure method:
fig.swap_axes_order(ax1, ax2)

plt.show()

27 changes: 16 additions & 11 deletions examples/pylab_examples/multiple_yaxis_with_spines.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,30 @@
import matplotlib.pyplot as plt

def make_patch_spines_invisible(ax):
ax.set_frame_on(True)
ax.patch.set_visible(False)
for sp in ax.spines.itervalues():
sp.set_visible(False)

fig, host = plt.subplots()

# Leave room for the additional spine:
fig.subplots_adjust(right=0.75)

par1 = host.twinx()
par2 = host.twinx()

# By default, par2 would now be the last Axes to be drawn,
# and the one to receive mouse and keyboard events. If we
# want the host to receive events, we can swap its position
# with par2 in the Axes stack with a Figure method:
fig.swap_axes_order(par2, host)

# Or let par1 receive the events:
#fig.swap_axes_order(par2, par1) # par1 is active

# Offset the right spine of par2. The ticks and label have already been
# placed on the right by twinx above.
par2.spines["right"].set_position(("axes", 1.2))
# Having been created by twinx, par2 has its frame off, so the line of its
# detached spine is invisible. First, activate the frame but make the patch
# and spines invisible.
make_patch_spines_invisible(par2)
# Second, show the right spine.

# Show only the right spine.
for sp in par2.spines.itervalues():
sp.set_visible(False)
par2.spines["right"].set_visible(True)

p1, = host.plot([0, 1, 2], [0, 1, 2], "b-", label="Density")
Expand Down Expand Up @@ -48,6 +53,6 @@ def make_patch_spines_invisible(ax):

lines = [p1, p2, p3]

host.legend(lines, [l.get_label() for l in lines])
host.legend(lines, [l.get_label() for l in lines], loc='upper left')

plt.show()
38 changes: 38 additions & 0 deletions lib/matplotlib/figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,29 @@ def add(self, key, a):
self._ind += 1
return Stack.push(self, (key, (self._ind, a)))

def swap_order(self, ax1, ax2):
"""
Exchange the indices of the specified axes objects.
"""
i1 = None
i2 = None
for i, entry in enumerate(self._elements):
if entry[1][1] == ax1:
i1 = i
entry1 = entry
elif entry[1][1] == ax2:
i2 = i
entry2 = entry

if i1 is None:
raise ValueError("First axes argument is not on the stack.")
if i2 is None:
raise ValueError("Second axes argument is not on the stack.")

seq1 = entry1[1][0]
self._elements[i1] = (entry1[0], (entry2[1][0], entry1[1][1]))
self._elements[i2] = (entry2[0], (seq1, entry2[1][1]))

def current_key_axes(self):
"""
Return a tuple of ``(key, axes)`` for the active axes.
Expand Down Expand Up @@ -877,6 +900,21 @@ def add_axes(self, *args, **kwargs):
self.sca(a)
return a

def swap_axes_order(self, ax1, ax2):
"""
Exchange the sort order of two Axes objects.

If the Axes share an x or y axis, then the visible
attribute of the Axes patch object is also exchanged.
"""
self._axstack.swap_order(ax1, ax2)

if (ax1.get_shared_x_axes().joined(ax1, ax2)
or ax1.get_shared_y_axes().joined(ax1, ax2)):
p1_visible = ax1.patch.get_visible()
ax1.patch.set_visible(ax2.patch.get_visible())
ax2.patch.set_visible(p1_visible)

@docstring.dedent_interpd
def add_subplot(self, *args, **kwargs):
"""
Expand Down
16 changes: 5 additions & 11 deletions lib/matplotlib/tests/test_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2796,13 +2796,6 @@ def test_phase_spectrum_noise():
@image_comparison(baseline_images=['twin_spines'], remove_text=True,
extensions=['png'])
def test_twin_spines():

def make_patch_spines_invisible(ax):
ax.set_frame_on(True)
ax.patch.set_visible(False)
for sp in six.itervalues(ax.spines):
sp.set_visible(False)

fig = plt.figure(figsize=(4, 3))
fig.subplots_adjust(right=0.75)

Expand All @@ -2813,10 +2806,11 @@ def make_patch_spines_invisible(ax):
# Offset the right spine of par2. The ticks and label have already been
# placed on the right by twinx above.
par2.spines["right"].set_position(("axes", 1.2))
# Having been created by twinx, par2 has its frame off, so the line of its
# detached spine is invisible. First, activate the frame but make the patch
# and spines invisible.
make_patch_spines_invisible(par2)

# First, make the par2 spines invisible.
for sp in six.itervalues(par2.spines):
sp.set_visible(False)

# Second, show the right spine.
par2.spines["right"].set_visible(True)

Expand Down