Skip to content

Commit

Permalink
Cleanup suplabel align, move texts.py-->labels.py
Browse files Browse the repository at this point in the history
  • Loading branch information
lukelbd committed Jan 15, 2022
1 parent 4eb15f7 commit 1040ae1
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 45 deletions.
10 changes: 5 additions & 5 deletions proplot/axes/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@
dependencies,
docstring,
guides,
labels,
rcsetup,
texts,
warnings,
)
from ..utils import _fontsize_to_pt, edges, units
Expand Down Expand Up @@ -792,7 +792,7 @@ def __init__(self, *args, **kwargs):
self.yaxis.isDefault_minloc = True

# Various dictionary properties
# NOTE: Critical to use self.text() so they are patched with _update_text
# NOTE: Critical to use self.text() so they are patched with _update_label
self._legend_dict = {}
self._colorbar_dict = {}
d = self._panel_dict = {}
Expand Down Expand Up @@ -1315,7 +1315,7 @@ def _apply_title_above(self):
pax._title_pad = self._title_pad
pax._abc_title_pad = self._abc_title_pad
for name in names:
texts._transfer_text(self._title_dict[name], pax._title_dict[name])
labels._transfer_label(self._title_dict[name], pax._title_dict[name])

def _apply_auto_share(self):
"""
Expand Down Expand Up @@ -2378,7 +2378,7 @@ def _update_title(self, loc, title=None, **kwargs):
loc = rc.find('title.loc', context=True)
loc = self._title_loc = _translate_loc(loc or self._title_loc, 'text')
if loc != old and old is not None:
texts._transfer_text(self._title_dict[old], self._title_dict[loc])
labels._transfer_label(self._title_dict[old], self._title_dict[loc])

# Update the title text. For outer panels, add text to the panel if
# necesssary. For inner panels, use the border and bbox settings.
Expand Down Expand Up @@ -2986,7 +2986,7 @@ def text(

# Update the text object using a monkey patch
obj = func(*args, transform=transform, **kwargs)
obj.update = texts._update_text.__get__(obj)
obj.update = labels._update_label.__get__(obj)
obj.update(
{
'border': border,
Expand Down
6 changes: 3 additions & 3 deletions proplot/axes/cartesian.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from .. import ticker as pticker
from ..config import rc
from ..internals import ic # noqa: F401
from ..internals import _not_none, _pop_rc, dependencies, docstring, texts, warnings
from ..internals import _not_none, _pop_rc, dependencies, docstring, labels, warnings
from . import plot, shared

__all__ = ['CartesianAxes']
Expand Down Expand Up @@ -371,7 +371,7 @@ def _apply_axis_sharing(self):
if self._sharex is not None and axis.get_visible():
level = 3 if self._panel_sharex_group else self.figure._sharex
if level > 0:
texts._transfer_text(axis.label, self._sharex.xaxis.label)
labels._transfer_label(axis.label, self._sharex.xaxis.label)
axis.label.set_visible(False)
if level > 2:
# WARNING: Cannot set NullFormatter because shared axes share the
Expand All @@ -382,7 +382,7 @@ def _apply_axis_sharing(self):
if self._sharey is not None and axis.get_visible():
level = 3 if self._panel_sharey_group else self.figure._sharey
if level > 0:
texts._transfer_text(axis.label, self._sharey.yaxis.label)
labels._transfer_label(axis.label, self._sharey.yaxis.label)
axis.label.set_visible(False)
if level > 2:
axis.set_tick_params(which='both', labelleft=False, labelright=False)
Expand Down
63 changes: 30 additions & 33 deletions proplot/figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
_translate_loc,
context,
docstring,
texts,
labels,
warnings,
)
from .utils import units
Expand Down Expand Up @@ -1199,14 +1199,14 @@ def _align_super_labels(self, side, renderer):
ax._apply_title_above()
if side not in ('left', 'right', 'bottom', 'top'):
raise ValueError(f'Invalid side {side!r}.')
labels = self._suplabel_dict[side]
axs = tuple(ax for ax, label in labels.items() if label.get_text())
labs = self._suplabel_dict[side]
axs = tuple(ax for ax, lab in labs.items() if lab.get_text())
if not axs:
return
c = self._get_offset_coord(side, axs, renderer)
for label in labels.values():
for lab in labs.values():
s = 'x' if side in ('left', 'right') else 'y'
label.update({s: c})
lab.update({s: c})

def _align_super_title(self, renderer):
"""
Expand All @@ -1229,56 +1229,53 @@ def _update_axis_label(self, side, axs):
"""
Update the aligned axis label for the input axes.
"""
# Get the central axis and the spanning label (initialize if it does not exist)
# NOTE: Previously we secretly used matplotlib axis labels for spanning labels,
# offsetting them between two subplots if necessary. Now we track designated
# 'super' labels and replace the actual labels with spaces so they still impact
# the tight bounding box and thus allocate space for the spanning label.
x, y = 'xy' if side in ('bottom', 'top') else 'yx'
labs = getattr(self, f'_sup{x}label_dict') # dict of spanning labels
setpos = getattr(mtext.Text, 'set_' + y)
axislist = [getattr(ax, x + 'axis') for ax in axs]

# Get the central label and "super" label for parallel alignment.
# Initialize the super label if one does not already exist.
c, ax = self._get_align_coord(side, axs, includepanels=self._includepanels)
axis = getattr(ax, x + 'axis') # use the central axis
label = labs.get(ax, None)
if label is None and not axis.label.get_text().strip():
axlab = getattr(ax, x + 'axis').label # the central label
suplabs = getattr(self, '_sup' + x + 'label_dict') # dict of spanning labels
suplab = suplabs.get(ax, None)
if suplab is None and not axlab.get_text().strip():
return # nothing to transfer from the normal label
if label is not None and not label.get_text().strip():
if suplab is not None and not suplab.get_text().strip():
return # nothing to update on the super label
if label is None:
if suplab is None:
props = ('ha', 'va', 'rotation', 'rotation_mode')
label = labs[ax] = self.text(0, 0, '')
label.update({p: getattr(axis.label, 'get_' + p)() for p in props})
suplab = suplabs[ax] = self.text(0, 0, '')
suplab.update({prop: getattr(axlab, 'get_' + prop)() for prop in props})

# Copy text from central label to spanning label
# Copy text from the central label to the spanning label
# NOTE: Must use spaces rather than newlines, otherwise tight layout
# won't make room. Reason is Text implementation (see Text._get_layout())
texts._transfer_text(axis.label, label) # text, color, and font properties
space = '\n'.join(' ' * (1 + label.get_text().count('\n')))
for axis in axislist: # should include original 'axis'
labels._transfer_label(axlab, suplab) # text, color, and font properties
count = 1 + suplab.get_text().count('\n')
space = '\n'.join(' ' * count)
for ax in axs: # includes original 'axis'
axis = getattr(ax, x + 'axis')
axis.label.set_text(space)

# Update spanning label position
# Update spanning label position then add simple monkey patch
# NOTE: Simply using axis._update_label_position() when this is
# called is not sufficient. Fails with e.g. inline backend.
t = mtransforms.IdentityTransform() # set in pixels
cx, cy = axis.label.get_position()
cx, cy = axlab.get_position()
if x == 'x':
trans = mtransforms.blended_transform_factory(self.transFigure, t)
coord = (c, cy)
else:
trans = mtransforms.blended_transform_factory(t, self.transFigure)
coord = (cx, c)
label.set_transform(trans)
label.set_position(coord)

# Add simple monkey patch to ensure positions stay in sync
# NOTE: Simply using axis._update_label_position() when this is called
# is not sufficient. Fails with e.g. inline backend.
def _set_coord(self, *args, **kwargs):
suplab.set_transform(trans)
suplab.set_position(coord)
setpos = getattr(mtext.Text, 'set_' + y)
def _set_coord(self, *args, **kwargs): # noqa: E306
setpos(self, *args, **kwargs)
setpos(label, *args, **kwargs)
setattr(axis.label, 'set_' + y, _set_coord.__get__(axis.label))
setpos(suplab, *args, **kwargs)
setattr(axlab, 'set_' + y, _set_coord.__get__(axlab))

def _update_super_labels(self, side, labels, **kwargs):
"""
Expand Down
2 changes: 1 addition & 1 deletion proplot/internals/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ def _not_none(*args, default=None, **kwargs):
docstring,
guides,
inputs,
labels,
rcsetup,
texts,
warnings
)

Expand Down
6 changes: 3 additions & 3 deletions proplot/internals/texts.py → proplot/internals/labels.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#!/usr/bin/env python3
"""
Utilities related to matplotlib text objects.
Utilities related to matplotlib text labels.
"""
import matplotlib.patheffects as mpatheffects
import matplotlib.text as mtext

from . import ic # noqa: F401


def _transfer_text(src, dest):
def _transfer_label(src, dest):
"""
Transfer the input text object properties and content to the destination
text object. Then clear the input object text.
Expand All @@ -22,7 +22,7 @@ def _transfer_text(src, dest):
src.set_text('')


def _update_text(text, props=None, **kwargs):
def _update_label(text, props=None, **kwargs):
"""
Add a monkey patch for ``Text.update`` with pseudo "border" and "bbox"
properties without wrapping the entire class. This facillitates inset titles.
Expand Down

0 comments on commit 1040ae1

Please sign in to comment.