8000 Axis Labels with offset Spines by cimarronm · Pull Request #4134 · matplotlib/matplotlib · GitHub
[go: up one dir, main page]

Skip to content

Axis Labels with offset Spines #4134

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

Merged
merged 9 commits into from
Mar 12, 2015
Merged
74 changes: 46 additions & 28 deletions lib/matplotlib/axis.py
Original file line number Diff line number Diff line change
Expand Up @@ -1569,8 +1569,8 @@ def set_ticks(self, ticks, minor=False):

def _update_label_position(self, bboxes, bboxes2):
"""
Update the label position based on the sequence of bounding
boxes of all the ticklabels
Update the label position based on the the bounding box enclosing
all the ticklabels and axis spine
"""
raise NotImplementedError('Derived must override')

Expand Down Expand Up @@ -1725,28 +1725,38 @@ def set_label_position(self, position):

def _update_label_position(self, bboxes, bboxes2):
"""
Update the label position based on the sequence of bounding
boxes of all the ticklabels
Update the label position based on the the bounding box enclosing
all the ticklabels and axis spine
"""
if not self._autolabelpos:
return
x, y = self.label.get_position()
if self.label_position == 'bottom':
if not len(bboxes):
bottom = self.axes.bbox.ymin
else:
bbox = mtransforms.Bbox.union(bboxes)
bottom = bbox.y0
try:
spine = self.axes.spines['bottom']
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make more sense to just throw the bounding box of the spine and the axes in to the bboxes list and let the union call take care of this logic?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, @tacaswell, I think that makes more sense. I'll update to do just that.

spinebbox = spine.get_transform().transform_path(
spine.get_path()).get_extents()
except KeyError:
# use axes if spine doesn't exist
spinebbox = self.axes.bbox
bbox = mtransforms.Bbox.union(bboxes + [spinebbox])
bottom = bbox.y0

self.label.set_position(
(x, bottom - self.labelpad * self.figure.dpi / 72.0)
)

else:
if not len(bboxes2):
top = self.axes.bbox.ymax
else:
bbox = mtransforms.Bbox.union(bboxes2)
top = bbox.y1
try:
spine = self.axes.spines['top']
spinebbox = spine.get_transform().transform_path(
spine.get_path()).get_extents()
except KeyError:
# use axes if spine doesn't exist
spinebbox = self.axes.bbox
bbox = mtransforms.Bbox.union(bboxes2 + [spinebbox])
top = bbox.y1

self.label.set_position(
(x, top + self.labelpad * self.figure.dpi / 72.0)
)
Expand Down Expand Up @@ -2031,29 +2041,37 @@ def set_label_position(self, position):

def _update_label_position(self, bboxes, bboxes2):
"""
Update the label position based on the sequence of bounding
boxes of all the ticklabels
Update the label position based on the the bounding box enclosing
all the ticklabels and axis spine
"""
if not self._autolabelpos:
return
x, y = self.label.get_position()
if self.label_position == 'left':
if not len(bboxes):
left = self.axes.bbox.xmin
else:
bbox = mtransforms.Bbox.union(bboxes)
left = bbox.x0
try:
spine = self.axes.spines['left']
spinebbox = spine.get_transform().transform_path(
spine.get_path()).get_extents()
except KeyError:
# use axes if spine doesn't exist
spinebbox = self.axes.bbox
bbox = mtransforms.Bbox.union(bboxes + [spinebbox])
left = bbox.x0

self.label.set_position(
(left - self.labelpad * self.figure.dpi / 72.0, y)
)

else:
if not len(bboxes2):
right = self.axes.bbox.xmax
else:
bbox = mtransforms.Bbox.union(bboxes2)
right = bbox.x1
try:
spine = self.axes.spines['right']
spinebbox = spine.get_transform().transform_path(
spine.get_path()).get_extents()
except KeyError:
# use axes if spine doesn't exist
spinebbox = self.axes.bbox
bbox = mtransforms.Bbox.union(bboxes2 + [spinebbox])
right = bbox.x1

self.label.set_position(
(right + self.labelpad * self.figure.dpi / 72.0, y)
Expand Down Expand Up @@ -2146,8 +2164,8 @@ def get_ticks_position(self):
majt = self.majorTicks[0]
mT = self.minorTicks[0]

majorRight = ((not majt.tick1On) and majt.tick2On
and (not majt.label1On) and majt.label2On)
majorRight = ((not majt.tick1On) and majt.tick2On and
(not majt.label1On) and majt.label2On)
minorRight = ((not mT.tick1On) and mT.tick2On and
(not mT.label1On) and mT.label2On)
if majorRight and minorRight:
Expand Down
1 change: 0 additions & 1 deletion lib/matplotlib/tests/test_coding_standards.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,6 @@ def test_pep8_conformance_installed_files():
'tests/test_mathtext.py',
'tests/test_rcparams.py',
'tests/test_simplification.py',
'tests/test_spines.py',
'tests/test_streamplot.py',
'tests/test_subplots.py',
'tests/test_tightlayout.py',
Expand Down
60 changes: 49 additions & 11 deletions lib/matplotlib/tests/test_spines.py
Original file line number Diff line number Diff line change
@@ -1,45 +1,83 @@
from __future_ 8000 _ import (absolute_import, division, print_function,
unicode_literals)

import numpy as np
from nose.tools import assert_true
import six

import numpy as np
import matplotlib
from matplotlib.testing.decorators import image_comparison
import matplotlib.pyplot as plt
import matplotlib.transforms as mtransforms
from matplotlib.testing.decorators import image_comparison, cleanup


@image_comparison(baseline_images=['spines_axes_positions'])
def test_spines_axes_positions():
# SF bug 2852168
fig = plt.figure()
x = np.linspace(0,2*np.pi,100)
x = np.linspace(0, 2*np.pi, 100)
y = 2*np.sin(x)
ax = fig.add_subplot(1,1,1)
ax = fig.add_subplot(1, 1, 1)
ax.set_title('centered spines')
ax.plot(x,y)
ax.spines['right'].set_position(('axes',0.1))
ax.plot(x, y)
ax.spines['right'].set_position(('axes', 0.1))
ax.yaxis.set_ticks_position('right')
ax.spines['top'].set_position(('axes',0.25))
ax.spines['top'].set_position(('axes', 0.25))
ax.xaxis.set_ticks_position('top')
ax.spines['left'].set_color('none')
ax.spines['bottom'].set_color('none')


@image_comparison(baseline_images=['spines_data_positions'])
def test_spines_data_positions():
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax = fig.add_subplot(1, 1, 1)
ax.spines['left'].set_position(('data', -1.5))
ax.spines['top'].set_position(('data', 0.5))
ax.spines['right'].set_position(('data', -0.5))
ax.spines['bottom'].set_position('zero')
ax.set_xlim([-2,2])
ax.set_ylim([-2,2])
ax.set_xlim([-2, 2])
ax.set_ylim([-2, 2])


@image_comparison(baseline_images=['spines_capstyle'])
def test_spines_capstyle():
# issue 2542
plt.rc('axes', linewidth=20)
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax = fig.add_subplot(1, 1, 1)
ax.set_xticks([])
ax.set_yticks([])


@cleanup
def test_label_without_ticks():
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
plt.subplots_adjust(left=0.3, bottom=0.3)
ax.plot(np.arange(10))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('outward', 30))
ax.spines['right'].set_visible(False)
ax.set_ylabel('y label')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('outward', 30))
ax.spines['top'].set_visible(False)
ax.set_xlabel('x label')
ax.xaxis.set_ticks([])
ax.yaxis.set_ticks([])
plt.draw()

spine = ax.spines['left']
spinebbox = spine.get_transform().transform_path(
spine.get_path()).get_extents()
# replace with assert_less if >python2.6
assert_true(ax.yaxis.label.get_position()[0] < spinebbox.xmin,
"Y-Axis label not left of the spine")

spine = ax.spines['bottom']
spinebbox = spine.get_transform().transform_path(
spine.get_path()).get_extents()
# replace with assert_less if >python2.6
assert_true(ax.xaxis.label.get_position()[1] < spinebbox.ymin,
"X-Axis label not below the spine")
0