diff --git a/CHANGELOG b/CHANGELOG index 9f1b2c86ca5b..7ed8c210b415 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -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 diff --git a/doc/api/api_changes.rst b/doc/api/api_changes.rst index c34115269255..c3096caee6e0 100644 --- a/doc/api/api_changes.rst +++ b/doc/api/api_changes.rst @@ -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 ------------ diff --git a/doc/users/whats_new.rst b/doc/users/whats_new.rst index 3b46a2f8376d..072685ce96b0 100644 --- a/doc/users/whats_new.rst +++ b/doc/users/whats_new.rst @@ -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. @@ -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 @@ -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 ------------- diff --git a/examples/api/two_scales.py b/examples/api/two_scales.py index 356c81336905..50fd3410e102 100644 --- a/examples/api/two_scales.py +++ b/examples/api/two_scales.py @@ -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() diff --git a/examples/pylab_examples/multiple_yaxis_with_spines.py b/examples/pylab_examples/multiple_yaxis_with_spines.py index 3b13b770feff..e471f13a3f76 100644 --- a/examples/pylab_examples/multiple_yaxis_with_spines.py +++ b/examples/pylab_examples/multiple_yaxis_with_spines.py @@ -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") @@ -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() diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index b334ca4edf88..2aec60f4b79e 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -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. @@ -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): """ diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 5b2aa4fbfea6..094a0342c936 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -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) @@ -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)