@@ -574,39 +574,67 @@ def get_subplotspec(self):
574574 return None
575575
576576
577- class HBoxDivider (SubplotDivider ):
577+ # Helper for HBoxDivider/VBoxDivider.
578+ # The variable names are written for a horizontal layout, but the calculations
579+ # work identically for vertical layouts (and likewise for the helpers below).
580+ def _determine_karray (summed_widths , equal_heights , total_width , max_height ):
581+ n = len (equal_heights )
582+ eq_rs , eq_as = np .asarray (equal_heights ).T
583+ sm_rs , sm_as = np .asarray (summed_widths ).T
584+ A = np .zeros ((n + 1 , n + 1 ))
585+ B = np .zeros (n + 1 )
586+ np .fill_diagonal (A [:n , :n ], eq_rs )
587+ A [:n , - 1 ] = - 1
588+ A [- 1 , :- 1 ] = sm_rs
589+ B [:n ] = - eq_as
590+ B [- 1 ] = total_width - sum (sm_as )
591+ # A @ K = B: This solves for {k_0, ..., k_{N-1}, H} so that
592+ # eq_r_i * k_i + eq_a_i = H for all i: all axes have the same height
593+ # sum(sm_r_i * k_i + sm_a_i) = total_summed_width: fixed total width
594+ # (foo_r_i * k_i + foo_a_i will end up being the size of foo.)
595+ karray_and_height = np .linalg .solve (A , B )
596+ karray = karray_and_height [:- 1 ]
597+ height = karray_and_height [- 1 ]
598+ if height > max_height : # Additionally, upper-bound the height.
599+ karray = (max_height - eq_as ) / eq_rs
600+ return karray
601+
602+
603+ # Helper for HBoxDivider/VBoxDivider (see above re: variable naming).
604+ def _calc_offsets (summed_sizes , karray ):
605+ offsets = [0. ]
606+ for (r , a ), k in zip (summed_sizes , karray ):
607+ offsets .append (offsets [- 1 ] + r * k + a )
608+ return offsets
609+
610+
611+ # Helper for HBoxDivider/VBoxDivider (see above re: variable naming).
612+ def _locate (x , y , w , h , summed_widths , equal_heights , fig_w , fig_h , anchor ):
613+ karray = _determine_karray (
614+ summed_widths , equal_heights ,
615+ total_width = fig_w * w , max_height = fig_h * h )
616+ ox = _calc_offsets (summed_widths , karray )
617+
618+ ww = (ox [- 1 ] - ox [0 ]) / fig_w
619+ h0_r , h0_a = equal_heights [0 ]
620+ hh = (karray [0 ]* h0_r + h0_a ) / fig_h
621+ pb = mtransforms .Bbox .from_bounds (x , y , w , h )
622+ pb1 = mtransforms .Bbox .from_bounds (x , y , ww , hh )
623+ pb1_anchored = pb1 .anchored (anchor , pb )
624+ x0 , y0 = pb1_anchored .x0 , pb1_anchored .y0
625+
626+ return x0 , y0 , ox , hh
578627
579- @staticmethod
580- def _determine_karray (equivalent_sizes , appended_sizes ,
581- max_equivalent_size ,
582- total_appended_size ):
583- n = len (equivalent_sizes )
584- eq_rs , eq_as = np .asarray (equivalent_sizes ).T
585- ap_rs , ap_as = np .asarray (appended_sizes ).T
586- A = np .zeros ((n + 1 , n + 1 ))
587- B = np .zeros (n + 1 )
588- np .fill_diagonal (A [:n , :n ], eq_rs )
589- A [:n , - 1 ] = - 1
590- A [- 1 , :- 1 ] = ap_rs
591- B [:n ] = - eq_as
592- B [- 1 ] = total_appended_size - sum (ap_as )
593- # A @ K = B: This solves for {k_0, ..., k_{N-1}, H} so that
594- # eq_r_i * k_i + eq_a_i = H for all i: all axes have the same height
595- # sum(ap_r_i * k_i + ap_a_i) = total_appended_size: fixed total width
596- # (foo_r_i * k_i + foo_a_i will end up being the size of foo.)
597- karray_H = np .linalg .solve (A , B )
598- karray = karray_H [:- 1 ]
599- H = karray_H [- 1 ]
600- if H > max_equivalent_size : # Additionally, upper-bound the height.
601- karray = (max_equivalent_size - eq_as ) / eq_rs
602- return karray
603628
604- @staticmethod
605- def _calc_offsets (appended_sizes , karray ):
606- offsets = [0. ]
607- for (r , a ), k in zip (appended_sizes , karray ):
608- offsets .append (offsets [- 1 ] + r * k + a )
609- return offsets
629+ class HBoxDivider (SubplotDivider ):
630+ """
631+ A `SubplotDivider` for laying out axes horizontally, while ensuring that
632+ they have equal heights.
633+
634+ Examples
635+ --------
636+ .. plot:: gallery/axes_grid1/demo_axes_hbox_divider.py
637+ """
610638
611639 def new_locator (self , nx , nx1 = None ):
612640 """
@@ -622,52 +650,25 @@ def new_locator(self, nx, nx1=None):
622650 """
623651 return AxesLocator (self , nx , 0 , nx1 , None )
624652
625- def _locate (self , x , y , w , h ,
626- y_equivalent_sizes , x_appended_sizes ,
627- figW , figH ):
628- equivalent_sizes = y_equivalent_sizes
629- appended_sizes = x_appended_sizes
630-
631- max_equivalent_size = figH * h
632- total_appended_size = figW * w
633- karray = self ._determine_karray (equivalent_sizes , appended_sizes ,
634- max_equivalent_size ,
635- total_appended_size )
636-
637- ox = self ._calc_offsets (appended_sizes , karray )
638-
639- ww = (ox [- 1 ] - ox [0 ]) / figW
640- ref_h = equivalent_sizes [0 ]
641- hh = (karray [0 ]* ref_h [0 ] + ref_h [1 ]) / figH
642- pb = mtransforms .Bbox .from_bounds (x , y , w , h )
643- pb1 = mtransforms .Bbox .from_bounds (x , y , ww , hh )
644- pb1_anchored = pb1 .anchored (self .get_anchor (), pb )
645- x0 , y0 = pb1_anchored .x0 , pb1_anchored .y0
646-
647- return x0 , y0 , ox , hh
648-
649653 def locate (self , nx , ny , nx1 = None , ny1 = None , axes = None , renderer = None ):
650654 # docstring inherited
651- figW , figH = self ._fig .get_size_inches ()
655+ fig_w , fig_h = self ._fig .get_size_inches ()
652656 x , y , w , h = self .get_position_runtime (axes , renderer )
653-
654- y_equivalent_sizes = self .get_vertical_sizes (renderer )
655- x_appended_sizes = self .get_horizontal_sizes (renderer )
656- x0 , y0 , ox , hh = self ._locate (x , y , w , h ,
657- y_equivalent_sizes , x_appended_sizes ,
658- figW , figH )
657+ summed_ws = self .get_horizontal_sizes (renderer )
658+ equal_hs = self .get_vertical_sizes (renderer )
659+ x0 , y0 , ox , hh = _locate (
660+ x , y , w , h , summed_ws , equal_hs , fig_w , fig_h , self .get_anchor ())
659661 if nx1 is None :
660662 nx1 = nx + 1
661-
662- x1 , w1 = x0 + ox [nx ] / figW , (ox [nx1 ] - ox [nx ]) / figW
663+ x1 , w1 = x0 + ox [nx ] / fig_w , (ox [nx1 ] - ox [nx ]) / fig_w
663664 y1 , h1 = y0 , hh
664-
665665 return mtransforms .Bbox .from_bounds (x1 , y1 , w1 , h1 )
666666
667667
668- class VBoxDivider (HBoxDivider ):
668+ class VBoxDivider (SubplotDivider ):
669669 """
670- The Divider class whose rectangle area is specified as a subplot geometry.
670+ A `SubplotDivider` for laying out axes vertically, while ensuring that they
671+ have equal widths.
671672 """
672673
673674 def new_locator (self , ny , ny1 = None ):
@@ -686,20 +687,16 @@ def new_locator(self, ny, ny1=None):
686687
687688 def locate (self , nx , ny , nx1 = None , ny1 = None , axes = None , renderer = None ):
688689 # docstring inherited
689- figW , figH = self ._fig .get_size_inches ()
690+ fig_w , fig_h = self ._fig .get_size_inches ()
690691 x , y , w , h = self .get_position_runtime (axes , renderer )
691-
692- x_equivalent_sizes = self .get_horizontal_sizes (renderer )
693- y_appended_sizes = self .get_vertical_sizes (renderer )
694- y0 , x0 , oy , ww = self ._locate (y , x , h , w ,
695- x_equivalent_sizes , y_appended_sizes ,
696- figH , figW )
692+ summed_hs = self .get_vertical_sizes (renderer )
693+ equal_ws = self .get_horizontal_sizes (renderer )
694+ y0 , x0 , oy , ww = _locate (
695+ y , x , h , w , summed_hs , equal_ws , fig_h , fig_w , self .get_anchor ())
697696 if ny1 is None :
698697 ny1 = ny + 1
699-
700698 x1 , w1 = x0 , ww
701- y1 , h1 = y0 + oy [ny ] / figH , (oy [ny1 ] - oy [ny ]) / figH
702-
699+ y1 , h1 = y0 + oy [ny ] / fig_h , (oy [ny1 ] - oy [ny ]) / fig_h
703700 return mtransforms .Bbox .from_bounds (x1 , y1 , w1 , h1 )
704701
705702
0 commit comments