Skip to content

Commit c739a08

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).
1 parent 178b46e commit c739a08

File tree

1 file changed

+68
-69
lines changed

1 file changed

+68
-69
lines changed

lib/mpl_toolkits/axes_grid1/axes_divider.py

Lines changed: 68 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -583,39 +583,67 @@ def get_subplotspec(self):
583583
return None
584584

585585

586-
class HBoxDivider(SubplotDivider):
586+
# Helper for HBoxDivider/VBoxDivider.
587+
def _determine_karray(equivalent_sizes, appended_sizes,
588+
max_equivalent_size, total_appended_size):
589+
n = len(equivalent_sizes)
590+
eq_rs, eq_as = np.asarray(equivalent_sizes).T
591+
ap_rs, ap_as = np.asarray(appended_sizes).T
592+
A = np.zeros((n + 1, n + 1))
593+
B = np.zeros(n + 1)
594+
np.fill_diagonal(A[:n, :n], eq_rs)
595+
A[:n, -1] = -1
596+
A[-1, :-1] = ap_rs
597+
B[:n] = -eq_as
598+
B[-1] = total_appended_size - sum(ap_as)
599+
# A @ K = B: This solves for {k_0, ..., k_{N-1}, H} so that
600+
# eq_r_i * k_i + eq_a_i = H for all i: all axes have the same height
601+
# sum(ap_r_i * k_i + ap_a_i) = total_summed_width: fixed total width
602+
# (foo_r_i * k_i + foo_a_i will end up being the size of foo.)
603+
karray_H = np.linalg.solve(A, B)
604+
karray = karray_H[:-1]
605+
H = karray_H[-1]
606+
if H > max_equivalent_size: # Additionally, upper-bound the height.
607+
karray = (max_equivalent_size - eq_as) / eq_rs
608+
return karray
609+
610+
611+
# Helper for HBoxDivider/VBoxDivider.
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
617+
618+
619+
# Helper for HBoxDivider/VBoxDivider.
620+
def _locate(
621+
x, y, w, h, equivalent_sizes, appended_sizes, fig_w, fig_h, anchor):
622+
karray = _determine_karray(
623+
equivalent_sizes, appended_sizes,
624+
max_equivalent_size=fig_h * h, total_appended_size=fig_w * w)
625+
ox = _calc_offsets(appended_sizes, karray)
626+
627+
ww = (ox[-1] - ox[0]) / fig_w
628+
h0_r, h0_a = equivalent_sizes[0]
629+
hh = (karray[0]*h0_r + h0_a) / fig_h
630+
pb = mtransforms.Bbox.from_bounds(x, y, w, h)
631+
pb1 = mtransforms.Bbox.from_bounds(x, y, ww, hh)
632+
pb1_anchored = pb1.anchored(anchor, pb)
633+
x0, y0 = pb1_anchored.x0, pb1_anchored.y0
634+
635+
return x0, y0, ox, hh
587636

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

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

620648
def new_locator(self, nx, nx1=None):
621649
"""
@@ -631,52 +659,26 @@ def new_locator(self, nx, nx1=None):
631659
"""
632660
return AxesLocator(self, nx, 0, nx1, None)
633661

634-
def _locate(self, x, y, w, h,
635-
y_equivalent_sizes, x_appended_sizes,
636-
figW, figH):
637-
equivalent_sizes = y_equivalent_sizes
638-
appended_sizes = x_appended_sizes
639-
640-
max_equivalent_size = figH * h
641-
total_appended_size = figW * w
642-
karray = self._determine_karray(equivalent_sizes, appended_sizes,
643-
max_equivalent_size,
644-
total_appended_size)
645-
646-
ox = self._calc_offsets(appended_sizes, karray)
647-
648-
ww = (ox[-1] - ox[0]) / figW
649-
ref_h = equivalent_sizes[0]
650-
hh = (karray[0]*ref_h[0] + ref_h[1]) / figH
651-
pb = mtransforms.Bbox.from_bounds(x, y, w, h)
652-
pb1 = mtransforms.Bbox.from_bounds(x, y, ww, hh)
653-
pb1_anchored = pb1.anchored(self.get_anchor(), pb)
654-
x0, y0 = pb1_anchored.x0, pb1_anchored.y0
655-
656-
return x0, y0, ox, hh
657-
658662
def locate(self, nx, ny, nx1=None, ny1=None, axes=None, renderer=None):
659663
# docstring inherited
660664
figW, figH = self._fig.get_size_inches()
661665
x, y, w, h = self.get_position_runtime(axes, renderer)
662-
663666
y_equivalent_sizes = self.get_vertical_sizes(renderer)
664667
x_appended_sizes = self.get_horizontal_sizes(renderer)
665-
x0, y0, ox, hh = self._locate(x, y, w, h,
666-
y_equivalent_sizes, x_appended_sizes,
667-
figW, figH)
668+
x0, y0, ox, hh = _locate(x, y, w, h,
669+
y_equivalent_sizes, x_appended_sizes,
670+
figW, figH, self.get_anchor())
668671
if nx1 is None:
669672
nx1 = nx + 1
670-
671673
x1, w1 = x0 + ox[nx] / figW, (ox[nx1] - ox[nx]) / figW
672674
y1, h1 = y0, hh
673-
674675
return mtransforms.Bbox.from_bounds(x1, y1, w1, h1)
675676

676677

677-
class VBoxDivider(HBoxDivider):
678+
class VBoxDivider(SubplotDivider):
678679
"""
679-
The Divider class whose rectangle area is specified as a subplot geometry.
680+
A `SubplotDivider` for laying out axes vertically, while ensuring that they
681+
have equal widths.
680682
"""
681683

682684
def new_locator(self, ny, ny1=None):
@@ -697,18 +699,15 @@ def locate(self, nx, ny, nx1=None, ny1=None, axes=None, renderer=None):
697699
# docstring inherited
698700
figW, figH = self._fig.get_size_inches()
699701
x, y, w, h = self.get_position_runtime(axes, renderer)
700-
701702
x_equivalent_sizes = self.get_horizontal_sizes(renderer)
702703
y_appended_sizes = self.get_vertical_sizes(renderer)
703-
y0, x0, oy, ww = self._locate(y, x, h, w,
704-
x_equivalent_sizes, y_appended_sizes,
705-
figH, figW)
704+
y0, x0, oy, ww = _locate(y, x, h, w,
705+
x_equivalent_sizes, y_appended_sizes,
706+
figH, figW, self.get_anchor())
706707
if ny1 is None:
707708
ny1 = ny + 1
708-
709709
x1, w1 = x0, ww
710710
y1, h1 = y0 + oy[ny] / figH, (oy[ny1] - oy[ny]) / figH
711-
712711
return mtransforms.Bbox.from_bounds(x1, y1, w1, h1)
713712

714713

0 commit comments

Comments
 (0)