Skip to content

Commit 1b0b8d4

Browse files
committed
Don't make VBoxDivider inherit from HBoxDivider.
They share some common calculation helpers, but a VBoxDivider is not a specialization of an HBoxDivider, so just move the helpers out to free functions (they're staticmethods or nearly so anyways). Also rename "equivalent" to "equal" and "appended" to "summed", which I think actually express the constraints better, and are shorter too. Also document their usage, and PEP8-ify a couple of variables.
1 parent 8599919 commit 1b0b8d4

File tree

1 file changed

+74
-77
lines changed

1 file changed

+74
-77
lines changed

lib/mpl_toolkits/axes_grid1/axes_divider.py

+74-77
Original file line numberDiff line numberDiff line change
@@ -581,39 +581,65 @@ def get_subplotspec(self):
581581
return None
582582

583583

584-
class HBoxDivider(SubplotDivider):
584+
def _hvboxdiv_determine_karray(
585+
equal_sizes, summed_sizes, max_equal_size, total_summed_size):
586+
n = len(equal_sizes)
587+
eq_rs, eq_as = np.asarray(equal_sizes).T
588+
sm_rs, sm_as = np.asarray(summed_sizes).T
589+
A = np.zeros((n + 1, n + 1))
590+
B = np.zeros(n + 1)
591+
np.fill_diagonal(A[:n, :n], eq_rs)
592+
A[:n, -1] = -1
593+
A[-1, :-1] = sm_rs
594+
B[:n] = -eq_as
595+
B[-1] = total_summed_size - sum(sm_as)
596+
# A @ K = B: This solves for {k_0, ..., k_{N-1}, H} so that
597+
# eq_r_i * k_i + eq_a_i = H for all i: all axes have the same height
598+
# sum(sm_r_i * k_i + sm_a_i) = total_summed_size: fixed total width
599+
# (foo_r_i * k_i + foo_a_i will end up being the size of foo.)
600+
karray_H = np.linalg.solve(A, B)
601+
karray = karray_H[:-1]
602+
H = karray_H[-1]
603+
if H > max_equal_size: # Additionally, upper-bound the height.
604+
karray = (max_equal_size - eq_as) / eq_rs
605+
return karray
606+
607+
608+
def _hvboxdiv_calc_offsets(summed_sizes, karray):
609+
offsets = [0.]
610+
for (r, a), k in zip(summed_sizes, karray):
611+
offsets.append(offsets[-1] + r*k + a)
612+
return offsets
613+
614+
615+
# The variable names are written for a horizontal layout, but the calculations
616+
# work identically for vertical layouts.
617+
def _hvboxdiv_locate(x, y, w, h, equal_ys, summed_xs, fig_w, fig_h, anchor):
618+
karray = _hvboxdiv_determine_karray(
619+
equal_ys, summed_xs,
620+
max_equal_size=fig_h * h, total_summed_size=fig_w * w)
621+
ox = _hvboxdiv_calc_offsets(summed_xs, karray)
622+
623+
ww = (ox[-1] - ox[0]) / fig_w
624+
ref_h = equal_ys[0]
625+
hh = (karray[0]*ref_h[0] + ref_h[1]) / fig_h
626+
pb = mtransforms.Bbox.from_bounds(x, y, w, h)
627+
pb1 = mtransforms.Bbox.from_bounds(x, y, ww, hh)
628+
pb1_anchored = pb1.anchored(anchor, pb)
629+
x0, y0 = pb1_anchored.x0, pb1_anchored.y0
630+
631+
return x0, y0, ox, hh
585632

586-
@staticmethod
587-
def _determine_karray(equivalent_sizes, appended_sizes,
588-
max_equivalent_size,
589-
total_appended_size):
590-
n = len(equivalent_sizes)
591-
eq_rs, eq_as = np.asarray(equivalent_sizes).T
592-
ap_rs, ap_as = np.asarray(appended_sizes).T
593-
A = np.zeros((n + 1, n + 1))
594-
B = np.zeros(n + 1)
595-
np.fill_diagonal(A[:n, :n], eq_rs)
596-
A[:n, -1] = -1
597-
A[-1, :-1] = ap_rs
598-
B[:n] = -eq_as
599-
B[-1] = total_appended_size - sum(ap_as)
600-
# A @ K = B: This solves for {k_0, ..., k_{N-1}, H} so that
601-
# eq_r_i * k_i + eq_a_i = H for all i: all axes have the same height
602-
# sum(ap_r_i * k_i + ap_a_i) = total_appended_size: fixed total width
603-
# (foo_r_i * k_i + foo_a_i will end up being the size of foo.)
604-
karray_H = np.linalg.solve(A, B)
605-
karray = karray_H[:-1]
606-
H = karray_H[-1]
607-
if H > max_equivalent_size: # Additionally, upper-bound the height.
608-
karray = (max_equivalent_size - eq_as) / eq_rs
609-
return karray
610633

611-
@staticmethod
612-
def _calc_offsets(appended_sizes, karray):
613-
offsets = [0.]
614-
for (r, a), k in zip(appended_sizes, karray):
615-
offsets.append(offsets[-1] + r*k + a)
616-
return offsets
634+
class HBoxDivider(SubplotDivider):
635+
"""
636+
A `SubplotDivider` for laying out axes horizontally, while ensuring that
637+
they have equal heights.
638+
639+
Examples
640+
--------
641+
.. plot:: gallery/axes_grid1/demo_axes_hbox_divider.py
642+
"""
617643

618644
def new_locator(self, nx, nx1=None):
619645
"""
@@ -629,52 +655,26 @@ def new_locator(self, nx, nx1=None):
629655
"""
630656
return AxesLocator(self, nx, 0, nx1, None)
631657

632-
def _locate(self, x, y, w, h,
633-
y_equivalent_sizes, x_appended_sizes,
634-
figW, figH):
635-
equivalent_sizes = y_equivalent_sizes
636-
appended_sizes = x_appended_sizes
637-
638-
max_equivalent_size = figH * h
639-
total_appended_size = figW * w
640-
karray = self._determine_karray(equivalent_sizes, appended_sizes,
641-
max_equivalent_size,
642-
total_appended_size)
643-
644-
ox = self._calc_offsets(appended_sizes, karray)
645-
646-
ww = (ox[-1] - ox[0]) / figW
647-
ref_h = equivalent_sizes[0]
648-
hh = (karray[0]*ref_h[0] + ref_h[1]) / figH
649-
pb = mtransforms.Bbox.from_bounds(x, y, w, h)
650-
pb1 = mtransforms.Bbox.from_bounds(x, y, ww, hh)
651-
pb1_anchored = pb1.anchored(self.get_anchor(), pb)
652-
x0, y0 = pb1_anchored.x0, pb1_anchored.y0
653-
654-
return x0, y0, ox, hh
655-
656658
def locate(self, nx, ny, nx1=None, ny1=None, axes=None, renderer=None):
657659
# docstring inherited
658-
figW, figH = self._fig.get_size_inches()
660+
fig_w, fig_h = self._fig.get_size_inches()
659661
x, y, w, h = self.get_position_runtime(axes, renderer)
660-
661-
y_equivalent_sizes = self.get_vertical_sizes(renderer)
662-
x_appended_sizes = self.get_horizontal_sizes(renderer)
663-
x0, y0, ox, hh = self._locate(x, y, w, h,
664-
y_equivalent_sizes, x_appended_sizes,
665-
figW, figH)
662+
y_equal_sizes = self.get_vertical_sizes(renderer)
663+
x_summed_sizes = self.get_horizontal_sizes(renderer)
664+
x0, y0, ox, hh = _hvboxdiv_locate(
665+
x, y, w, h, y_equal_sizes, x_summed_sizes, fig_w, fig_h,
666+
self.get_anchor())
666667
if nx1 is None:
667668
nx1 = nx + 1
668-
669-
x1, w1 = x0 + ox[nx] / figW, (ox[nx1] - ox[nx]) / figW
669+
x1, w1 = x0 + ox[nx] / fig_w, (ox[nx1] - ox[nx]) / fig_w
670670
y1, h1 = y0, hh
671-
672671
return mtransforms.Bbox.from_bounds(x1, y1, w1, h1)
673672

674673

675-
class VBoxDivider(HBoxDivider):
674+
class VBoxDivider(SubplotDivider):
676675
"""
677-
The Divider class whose rectangle area is specified as a subplot geometry.
676+
A `SubplotDivider` for laying out axes vertically, while ensuring that they
677+
have equal widths.
678678
"""
679679

680680
def new_locator(self, ny, ny1=None):
@@ -693,20 +693,17 @@ def new_locator(self, ny, ny1=None):
693693

694694
def locate(self, nx, ny, nx1=None, ny1=None, axes=None, renderer=None):
695695
# docstring inherited
696-
figW, figH = self._fig.get_size_inches()
696+
fig_w, fig_h = self._fig.get_size_inches()
697697
x, y, w, h = self.get_position_runtime(axes, renderer)
698-
699-
x_equivalent_sizes = self.get_horizontal_sizes(renderer)
700-
y_appended_sizes = self.get_vertical_sizes(renderer)
701-
y0, x0, oy, ww = self._locate(y, x, h, w,
702-
x_equivalent_sizes, y_appended_sizes,
703-
figH, figW)
698+
x_equal_sizes = self.get_horizontal_sizes(renderer)
699+
y_summed_sizes = self.get_vertical_sizes(renderer)
700+
y0, x0, oy, ww = _hvboxdiv_locate(
701+
y, x, h, w, x_equal_sizes, y_summed_sizes, fig_h, fig_w,
702+
self.get_anchor())
704703
if ny1 is None:
705704
ny1 = ny + 1
706-
707705
x1, w1 = x0, ww
708-
y1, h1 = y0 + oy[ny] / figH, (oy[ny1] - oy[ny]) / figH
709-
706+
y1, h1 = y0 + oy[ny] / fig_h, (oy[ny1] - oy[ny]) / fig_h
710707
return mtransforms.Bbox.from_bounds(x1, y1, w1, h1)
711708

712709

0 commit comments

Comments
 (0)