Skip to content

Commit 55a6ada

Browse files
committed
Clean up title padding internals
1 parent 09f2058 commit 55a6ada

File tree

4 files changed

+104
-117
lines changed

4 files changed

+104
-117
lines changed

WHATSNEW.rst

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,19 +91,17 @@ ProPlot v0.7.0 (2021-06-30)
9191
Make the ``Browns1`` map the most colorful/vibrant one, just like ``Greens1`` and
9292
``Blues1``; split up the ``RedPurple`` maps into ``Reds`` and ``Purples``; and add
9393
the ``Yellows`` category from the ``Oranges`` maps (:commit:`8be0473f`).
94+
* Rename `abovetop` keyword for moving title/abc labels above or below top panels,
95+
colorbars, and legends to :rcraw:`title.above` (:commit:`9ceacb7b`).
9496
* Rename seldom-used `Figure` argument `fallback_to_cm` to more understandable
9597
`mathtext_fallback` (:pr:`251`).
96-
* Rename `abovetop` keyword for moving title/abc label above or below top panels to rc
97-
param :rcraw:`axes.titleabove` with alias :rcraw:`title.above` (:commit:`9ceacb7b`).
9898

9999
.. rubric:: Features
100100

101-
* Add :rcraw:`basemap` setting for changing the default backend (:commit:`###`). If
101+
* Add :rcraw:`basemap` setting for changing the default backend (:commit:`c9ca0bdd`). If
102102
users have a cartopy vs. basemap preference, they probably want to use it globally.
103103
* Add :rcraw:`cartopy.circular` setting for optionally disabling the "circular bounds
104-
on polar projections" feature (:commit:`###`).
105-
* Add :rcraw:`abc.pad` and :rcraw:`abc.above` settings for changing a-b-c label
106-
padding separate from titles (:commit:`###`).
104+
on polar projections" feature (:commit:`c9ca0bdd`).
107105
* Add `titlebbox` and `abcbbox` as alternatives to `titleborder` and `abcborder`
108106
for "inner" titles and a-b-c labels (:pr:`240`) by `Pratiman Patel`_.
109107
Default behavior uses borders.

proplot/axes/base.py

Lines changed: 64 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -226,17 +226,17 @@ def __init__(self, *args, number=None, main=False, _subplotspec=None, **kwargs):
226226
self._auto_format = None # manipulated by wrapper functions
227227
self._abc_loc = None
228228
self._abc_text = None
229-
self._abc_border_kwargs = {} # abs border properties
230-
self._title_above = rc['axes.titleabove']
231-
self._title_loc = None # location of main title
232-
self._title_pad = rc['axes.titlepad'] # format() can overwrite
233-
self._title_pad_active = None
229+
self._abc_border_kwargs = {}
230+
self._title_loc = None
234231
self._title_border_kwargs = {} # title border properties
232+
self._title_above = rc['title.above']
233+
self._title_pad = rc['title.pad']
234+
self._title_pad_current = None
235235
self._bottom_panels = []
236236
self._top_panels = []
237237
self._left_panels = []
238238
self._right_panels = []
239-
self._tightbbox = None # bounding boxes are saved
239+
self._tight_bbox = None # bounding boxes are saved
240240
self._panel_hidden = False # True when "filled" with cbar/legend
241241
self._panel_parent = None
242242
self._panel_share = False
@@ -560,7 +560,7 @@ def _range_tightbbox(self, x):
560560
`~Figure.get_tightbbox` is called.
561561
"""
562562
# TODO: Better testing for axes visibility
563-
bbox = self._tightbbox
563+
bbox = self._tight_bbox
564564
if bbox is None:
565565
return np.nan, np.nan
566566
if x == 'x':
@@ -570,30 +570,21 @@ def _range_tightbbox(self, x):
570570

571571
def _reassign_subplot_label(self, side):
572572
"""
573-
Re-assign the column and row labels to the relevant panel if present.
573+
Reassign the column and row labels to the relevant panel if present.
574574
This is called by `~proplot.figure.Figure._align_subplot_figure_labels`.
575575
"""
576-
# Place column and row labels on panels instead of axes -- works when
577-
# this is called on the main axes *or* on the relevant panel itself
578-
# TODO: Mixed figure panels with super labels? How does that work?
579-
if side == self._panel_side:
580-
ax = self._panel_parent
581-
else:
582-
ax = self
583-
paxs = getattr(ax, '_' + side + '_panels')
576+
# NOTE: Since panel axes are "children" main axes is always drawn first.
577+
paxs = getattr(self, '_' + side + '_panels')
584578
if not paxs:
585-
return ax
579+
return self
586580
kw = {}
587-
pax = paxs[-1] # outermost is always list in list
588-
obj = getattr(ax, '_' + side + '_label')
589-
for key in ('color', 'fontproperties'): # TODO: add to this?
590-
kw[key] = getattr(obj, 'get_' + key)()
581+
pax = paxs[-1] # outermost
582+
obj = getattr(self, '_' + side + '_label')
591583
pobj = getattr(pax, '_' + side + '_label')
584+
for key in ('text', 'color', 'fontproperties'):
585+
kw[key] = getattr(obj, 'get_' + key)()
592586
pobj.update(kw)
593-
text = obj.get_text()
594-
if text:
595-
obj.set_text('')
596-
pobj.set_text(text)
587+
obj.set_text('')
597588
return pax
598589

599590
def _reassign_title(self):
@@ -603,30 +594,20 @@ def _reassign_title(self):
603594
be offset but still belong to main axes, which messes up the tight
604595
bounding box.
605596
"""
606-
# Reassign title from main axes to top panel -- works when this is
607-
# called on the main axes *or* on the top panel itself. This is
608-
# critical for bounding box calcs; not always clear whether draw() and
609-
# get_tightbbox() are called on the main axes or panel first
610-
if self._panel_side == 'top' and self._panel_parent:
611-
ax = self._panel_parent
612-
else:
613-
ax = self
614-
taxs = ax._top_panels
615-
if not taxs or not ax._title_above:
616-
tax = ax
617-
else:
618-
tax = taxs[-1]
619-
tax._title_pad = ax._title_pad
620-
for loc in ('abc', 'left', 'center', 'right'):
621-
kw = {}
622-
obj = ax._get_title(loc)
623-
if not obj.get_text():
624-
continue
625-
tobj = tax._get_title(loc)
626-
for key in ('text', 'color', 'fontproperties'): # add to this?
627-
kw[key] = getattr(obj, 'get_' + key)()
628-
tobj.update(kw)
629-
obj.set_text('')
597+
# NOTE: Since panel axes are "children" main axes is always drawn first.
598+
taxs = self._top_panels
599+
if not taxs or not self._title_above:
600+
return
601+
tax = taxs[-1] # outermost
602+
tax._title_pad = self._title_pad
603+
for loc in ('abc', 'left', 'center', 'right'):
604+
kw = {}
605+
obj = self._get_title(loc)
606+
tobj = tax._get_title(loc)
607+
for key in ('text', 'color', 'fontproperties'):
608+
kw[key] = getattr(obj, 'get_' + key)()
609+
tobj.update(kw)
610+
obj.set_text('')
630611

631612
def _sharex_setup(self, sharex):
632613
"""
@@ -683,7 +664,8 @@ def _update_title_position(self, renderer):
683664
Update the position of proplot inset titles and builtin matplotlib
684665
titles. This is called by matplotlib at drawtime.
685666
"""
686-
# Custom inset titles
667+
# Update custom inset titles
668+
pad = self._title_pad
687669
width, height = self.get_size_inches()
688670
for loc in (
689671
'abc',
@@ -695,26 +677,25 @@ def _update_title_position(self, renderer):
695677
loc = self._abc_loc
696678
if loc in ('left', 'right', 'center'):
697679
continue
698-
pad = self._title_pad / (72 * width)
680+
x_pad = pad / (72 * width)
699681
if loc in ('upper center', 'lower center'):
700682
x = 0.5
701683
elif loc in ('upper left', 'lower left'):
702-
x = pad
684+
x = x_pad
703685
elif loc in ('upper right', 'lower right'):
704-
x = 1 - pad
705-
pad = self._title_pad / (72 * height)
686+
x = 1 - x_pad
687+
y_pad = pad / (72 * height)
706688
if loc in ('upper left', 'upper right', 'upper center'):
707-
y = 1 - pad
689+
y = 1 - y_pad
708690
elif loc in ('lower left', 'lower right', 'lower center'):
709-
y = pad
691+
y = y_pad
710692
obj.set_position((x, y))
711693

712694
# Push title above tick marks, since builtin algorithm used to offset
713695
# the title seems to ignore them. This is known matplotlib problem but
714696
# especially annoying with top panels.
715697
# TODO: Make sure this is robust. Seems 'default' is returned usually
716698
# when tick sides is actually *both*.
717-
pad = self._title_pad
718699
pos = self.xaxis.get_ticks_position()
719700
fmt = self.xaxis.get_major_formatter()
720701
if self.xaxis.get_visible() and (
@@ -727,11 +708,12 @@ def _update_title_position(self, renderer):
727708
)
728709
):
729710
pad += self.xaxis.get_tick_padding()
730-
pad_active = self._title_pad_active
731-
if pad_active is None or not np.isclose(pad_active, pad):
732-
# Avoid doing this on every draw in case it is expensive to change
733-
# the title Text transforms every time.
734-
self._title_pad_active = pad
711+
712+
# Avoid applying padding on every draw in case it is expensive to change
713+
# the title Text transforms every time.
714+
pad_current = self._title_pad_current
715+
if pad_current is None or not np.isclose(pad, pad_current):
716+
self._title_pad_current = pad
735717
self._set_title_offset_trans(pad)
736718

737719
# Adjust the title positions with builtin algorithm and match
@@ -740,9 +722,7 @@ def _update_title_position(self, renderer):
740722
if self._abc_loc in ('left', 'center', 'right'):
741723
title = self._get_title(self._abc_loc)
742724
self._abc_label.set_position(title.get_position())
743-
self._abc_label.set_transform(
744-
self.transAxes + self.titleOffsetTrans
745-
)
725+
self._abc_label.set_transform(self.transAxes + self.titleOffsetTrans)
746726

747727
@staticmethod
748728
@warnings._rename_kwargs('0.6', mode='rc_mode')
@@ -829,10 +809,10 @@ def format(
829809
:rc:`abc.bbox` and :rc:`title.bbox`
830810
titlepad : float, optional
831811
The padding for the inner and outer titles and a-b-c labels in
832-
arbitrary units (default is points). Default is :rc:`axes.titlepad`.
812+
arbitrary units (default is points). Default is :rc:`title.pad`.
833813
titleabove : bool, optional
834-
Whether to try to put outer titles and a-b-c labels above the top panel
835-
(if it exists). Default is :rc:`axes.titleabove`.
814+
Whether to try to put outer titles and a-b-c labels above panels,
815+
colorbars, or legends that are above the axes. Default is :rc:`title.above`.
836816
leftlabels, toplabels, rightlabels, bottomlabels : list of str, \
837817
optional
838818
Labels for the subplots lying along the left, top, right, and
@@ -863,31 +843,32 @@ def format(
863843
proplot.axes.PolarAxes.format
864844
proplot.axes.GeoAxes.format
865845
"""
866-
# Figure patch (needs to be re-asserted even if declared before figure is drawn)
846+
# Figure patch
847+
# TODO: Work out awkward situation where "figure" settings applied on axes
867848
kw = rc.fill({'facecolor': 'figure.facecolor'}, context=True)
868849
self.figure.patch.update(kw)
869850

870-
# Axes settings (TODO: add more settings?)
851+
# Axes settings
871852
cycle = rc.get('axes.prop_cycle', context=True)
872853
if cycle is not None:
873854
self.set_prop_cycle(cycle)
874855

875-
# Text positioning
876-
above = rc.get('axes.titleabove', context=True)
856+
# Text positioning equivalent
857+
above = rc.get('title.above', context=True)
877858
if above is not None:
878859
self._title_above = above
879-
pad = rc.get('axes.titlepad', context=True)
860+
pad = rc.get('title.pad', context=True)
880861
if pad is not None:
881862
self._set_title_offset_trans(pad)
882863
self._title_pad = pad
883864

884865
# Super title
885-
# NOTE: These are actually *figure-wide* settings, but that line
886-
# gets blurred where we have shared axes, spanning labels, and
887-
# whatnot. May result in redundant assignments if formatting more than
888-
# one axes, but operations are fast so some redundancy is nbd.
889-
# NOTE: Below kludge prevents changed *figure-wide* settings
890-
# from getting overwritten when user makes a new axes.
866+
# NOTE: These are actually *figure-wide* settings, but that line gets
867+
# blurred where we have shared axes, spanning labels, and whatnot. May result
868+
# in redundant assignments if formatting more than one axes, but operations
869+
# are fast so some redundancy is nbd.
870+
# NOTE: Below kludge prevents changed *figure-wide* settings from getting
871+
# overwritten when user makes a new axes.
891872
fig = self.figure
892873
suptitle = _not_none(figtitle=figtitle, suptitle=suptitle)
893874
if len(fig._axes_main) > 1 and rc._context and rc._context[-1].mode == 1:
@@ -933,6 +914,7 @@ def sanitize_kw(kw, loc):
933914
kw.pop('border', None)
934915
kw.pop('borderwidth', None)
935916
kw.pop('bbox', None)
917+
kw.pop('bboxpad', None)
936918
kw.pop('bboxcolor', None)
937919
kw.pop('bboxstyle', None)
938920
kw.pop('bboxalpha', None)
@@ -959,6 +941,7 @@ def sanitize_kw(kw, loc):
959941
'border': 'abc.border',
960942
'borderwidth': 'abc.borderwidth',
961943
'bbox': 'abc.bbox',
944+
'bboxpad': 'abc.bboxpad',
962945
'bboxcolor': 'abc.bboxcolor',
963946
'bboxstyle': 'abc.bboxstyle',
964947
'bboxalpha': 'abc.bboxalpha',
@@ -1025,6 +1008,7 @@ def sanitize_kw(kw, loc):
10251008
'border': 'title.border',
10261009
'borderwidth': 'title.borderwidth',
10271010
'bbox': 'title.bbox',
1011+
'bboxpad': 'title.bboxpad',
10281012
'bboxcolor': 'title.bboxcolor',
10291013
'bboxstyle': 'title.bboxstyle',
10301014
'bboxalpha': 'title.bboxalpha',
@@ -1452,7 +1436,7 @@ def get_tightbbox(self, renderer, *args, **kwargs):
14521436
# box as an attribute.
14531437
self._reassign_title()
14541438
bbox = super().get_tightbbox(renderer, *args, **kwargs)
1455-
self._tightbbox = bbox
1439+
self._tight_bbox = bbox
14561440
return bbox
14571441

14581442
def heatmap(self, *args, aspect=None, **kwargs):

proplot/axes/plot.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2205,6 +2205,8 @@ def _update_text(self, props):
22052205
})
22062206

22072207
# Update bounding box
2208+
# NOTE: We use '_title_pad' and '_title_above' for both titles and a-b-c labels
2209+
# because always want to keep them aligned.
22082210
# NOTE: For some reason using pad / 10 results in perfect alignment. Matplotlib
22092211
# docs are vague about bounding box units, maybe they are tens of points?
22102212
bbox = props.pop('bbox', None)
@@ -2270,15 +2272,15 @@ def text_wrapper(
22702272
borderinvert : bool, optional
22712273
If ``True``, the text and border colors are swapped.
22722274
bbox : bool, optional
2273-
Whether to draw a bouning box around text.
2275+
Whether to draw a bounding box around text.
22742276
bboxcolor : color-spec, optional
2275-
The color of the text bouning box. Default is ``'w'``.
2277+
The color of the text bounding box. Default is ``'w'``.
22762278
bboxstyle : boxstyle, optional
2277-
The style of the bouning box. Default is ``'round'``.
2279+
The style of the bounding box. Default is ``'round'``.
22782280
bboxalpha : float, optional
22792281
The alpha for the bounding box. Default is ``'0.5'``.
22802282
bboxpad : float, optional
2281-
The padding of the bounding box. Default is :rc:`title.pad` / 10.
2283+
The padding for the bounding box. Default is :rc:`title.bboxpad`.
22822284
22832285
Other parameters
22842286
----------------

0 commit comments

Comments
 (0)