diff --git a/lib/mpl_toolkits/axes_grid1/axes_divider.py b/lib/mpl_toolkits/axes_grid1/axes_divider.py index 2722a3fe507c..680ad9bf3e92 100644 --- a/lib/mpl_toolkits/axes_grid1/axes_divider.py +++ b/lib/mpl_toolkits/axes_grid1/axes_divider.py @@ -583,39 +583,67 @@ def get_subplotspec(self): return None -class HBoxDivider(SubplotDivider): +# Helper for HBoxDivider/VBoxDivider. +# The variable names are written for a horizontal layout, but the calculations +# work identically for vertical layouts (and likewise for the helpers below). +def _determine_karray(summed_widths, equal_heights, total_width, max_height): + n = len(equal_heights) + eq_rs, eq_as = np.asarray(equal_heights).T + sm_rs, sm_as = np.asarray(summed_widths).T + A = np.zeros((n + 1, n + 1)) + B = np.zeros(n + 1) + np.fill_diagonal(A[:n, :n], eq_rs) + A[:n, -1] = -1 + A[-1, :-1] = sm_rs + B[:n] = -eq_as + B[-1] = total_width - sum(sm_as) + # A @ K = B: This solves for {k_0, ..., k_{N-1}, H} so that + # eq_r_i * k_i + eq_a_i = H for all i: all axes have the same height + # sum(sm_r_i * k_i + sm_a_i) = total_summed_width: fixed total width + # (foo_r_i * k_i + foo_a_i will end up being the size of foo.) + karray_and_height = np.linalg.solve(A, B) + karray = karray_and_height[:-1] + height = karray_and_height[-1] + if height > max_height: # Additionally, upper-bound the height. + karray = (max_height - eq_as) / eq_rs + return karray + + +# Helper for HBoxDivider/VBoxDivider (see above re: variable naming). +def _calc_offsets(summed_sizes, karray): + offsets = [0.] + for (r, a), k in zip(summed_sizes, karray): + offsets.append(offsets[-1] + r*k + a) + return offsets + + +# Helper for HBoxDivider/VBoxDivider (see above re: variable naming). +def _locate(x, y, w, h, summed_widths, equal_heights, fig_w, fig_h, anchor): + karray = _determine_karray( + summed_widths, equal_heights, + total_width=fig_w * w, max_height=fig_h * h) + ox = _calc_offsets(summed_widths, karray) + + ww = (ox[-1] - ox[0]) / fig_w + h0_r, h0_a = equal_heights[0] + hh = (karray[0]*h0_r + h0_a) / fig_h + pb = mtransforms.Bbox.from_bounds(x, y, w, h) + pb1 = mtransforms.Bbox.from_bounds(x, y, ww, hh) + pb1_anchored = pb1.anchored(anchor, pb) + x0, y0 = pb1_anchored.x0, pb1_anchored.y0 + + return x0, y0, ox, hh - @staticmethod - def _determine_karray(equivalent_sizes, appended_sizes, - max_equivalent_size, - total_appended_size): - n = len(equivalent_sizes) - eq_rs, eq_as = np.asarray(equivalent_sizes).T - ap_rs, ap_as = np.asarray(appended_sizes).T - A = np.zeros((n + 1, n + 1)) - B = np.zeros(n + 1) - np.fill_diagonal(A[:n, :n], eq_rs) - A[:n, -1] = -1 - A[-1, :-1] = ap_rs - B[:n] = -eq_as - B[-1] = total_appended_size - sum(ap_as) - # A @ K = B: This solves for {k_0, ..., k_{N-1}, H} so that - # eq_r_i * k_i + eq_a_i = H for all i: all axes have the same height - # sum(ap_r_i * k_i + ap_a_i) = total_appended_size: fixed total width - # (foo_r_i * k_i + foo_a_i will end up being the size of foo.) - karray_H = np.linalg.solve(A, B) - karray = karray_H[:-1] - H = karray_H[-1] - if H > max_equivalent_size: # Additionally, upper-bound the height. - karray = (max_equivalent_size - eq_as) / eq_rs - return karray - @staticmethod - def _calc_offsets(appended_sizes, karray): - offsets = [0.] - for (r, a), k in zip(appended_sizes, karray): - offsets.append(offsets[-1] + r*k + a) - return offsets +class HBoxDivider(SubplotDivider): + """ + A `SubplotDivider` for laying out axes horizontally, while ensuring that + they have equal heights. + + Examples + -------- + .. plot:: gallery/axes_grid1/demo_axes_hbox_divider.py + """ def new_locator(self, nx, nx1=None): """ @@ -631,52 +659,25 @@ def new_locator(self, nx, nx1=None): """ return AxesLocator(self, nx, 0, nx1, None) - def _locate(self, x, y, w, h, - y_equivalent_sizes, x_appended_sizes, - figW, figH): - equivalent_sizes = y_equivalent_sizes - appended_sizes = x_appended_sizes - - max_equivalent_size = figH * h - total_appended_size = figW * w - karray = self._determine_karray(equivalent_sizes, appended_sizes, - max_equivalent_size, - total_appended_size) - - ox = self._calc_offsets(appended_sizes, karray) - - ww = (ox[-1] - ox[0]) / figW - ref_h = equivalent_sizes[0] - hh = (karray[0]*ref_h[0] + ref_h[1]) / figH - pb = mtransforms.Bbox.from_bounds(x, y, w, h) - pb1 = mtransforms.Bbox.from_bounds(x, y, ww, hh) - pb1_anchored = pb1.anchored(self.get_anchor(), pb) - x0, y0 = pb1_anchored.x0, pb1_anchored.y0 - - return x0, y0, ox, hh - def locate(self, nx, ny, nx1=None, ny1=None, axes=None, renderer=None): # docstring inherited - figW, figH = self._fig.get_size_inches() + fig_w, fig_h = self._fig.get_size_inches() x, y, w, h = self.get_position_runtime(axes, renderer) - - y_equivalent_sizes = self.get_vertical_sizes(renderer) - x_appended_sizes = self.get_horizontal_sizes(renderer) - x0, y0, ox, hh = self._locate(x, y, w, h, - y_equivalent_sizes, x_appended_sizes, - figW, figH) + summed_ws = self.get_horizontal_sizes(renderer) + equal_hs = self.get_vertical_sizes(renderer) + x0, y0, ox, hh = _locate( + x, y, w, h, summed_ws, equal_hs, fig_w, fig_h, self.get_anchor()) if nx1 is None: nx1 = nx + 1 - - x1, w1 = x0 + ox[nx] / figW, (ox[nx1] - ox[nx]) / figW + x1, w1 = x0 + ox[nx] / fig_w, (ox[nx1] - ox[nx]) / fig_w y1, h1 = y0, hh - return mtransforms.Bbox.from_bounds(x1, y1, w1, h1) -class VBoxDivider(HBoxDivider): +class VBoxDivider(SubplotDivider): """ - The Divider class whose rectangle area is specified as a subplot geometry. + A `SubplotDivider` for laying out axes vertically, while ensuring that they + have equal widths. """ def new_locator(self, ny, ny1=None): @@ -695,20 +696,16 @@ def new_locator(self, ny, ny1=None): def locate(self, nx, ny, nx1=None, ny1=None, axes=None, renderer=None): # docstring inherited - figW, figH = self._fig.get_size_inches() + fig_w, fig_h = self._fig.get_size_inches() x, y, w, h = self.get_position_runtime(axes, renderer) - - x_equivalent_sizes = self.get_horizontal_sizes(renderer) - y_appended_sizes = self.get_vertical_sizes(renderer) - y0, x0, oy, ww = self._locate(y, x, h, w, - x_equivalent_sizes, y_appended_sizes, - figH, figW) + summed_hs = self.get_vertical_sizes(renderer) + equal_ws = self.get_horizontal_sizes(renderer) + y0, x0, oy, ww = _locate( + y, x, h, w, summed_hs, equal_ws, fig_h, fig_w, self.get_anchor()) if ny1 is None: ny1 = ny + 1 - x1, w1 = x0, ww - y1, h1 = y0 + oy[ny] / figH, (oy[ny1] - oy[ny]) / figH - + y1, h1 = y0 + oy[ny] / fig_h, (oy[ny1] - oy[ny]) / fig_h return mtransforms.Bbox.from_bounds(x1, y1, w1, h1)
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: