@@ -574,39 +574,67 @@ def get_subplotspec(self):
574
574
return None
575
575
576
576
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
578
627
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
603
628
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
+ """
610
638
611
639
def new_locator (self , nx , nx1 = None ):
612
640
"""
@@ -622,52 +650,25 @@ def new_locator(self, nx, nx1=None):
622
650
"""
623
651
return AxesLocator (self , nx , 0 , nx1 , None )
624
652
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
-
649
653
def locate (self , nx , ny , nx1 = None , ny1 = None , axes = None , renderer = None ):
650
654
# docstring inherited
651
- figW , figH = self ._fig .get_size_inches ()
655
+ fig_w , fig_h = self ._fig .get_size_inches ()
652
656
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 ())
659
661
if nx1 is None :
660
662
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
663
664
y1 , h1 = y0 , hh
664
-
665
665
return mtransforms .Bbox .from_bounds (x1 , y1 , w1 , h1 )
666
666
667
667
668
- class VBoxDivider (HBoxDivider ):
668
+ class VBoxDivider (SubplotDivider ):
669
669
"""
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.
671
672
"""
672
673
673
674
def new_locator (self , ny , ny1 = None ):
@@ -686,20 +687,16 @@ def new_locator(self, ny, ny1=None):
686
687
687
688
def locate (self , nx , ny , nx1 = None , ny1 = None , axes = None , renderer = None ):
688
689
# docstring inherited
689
- figW , figH = self ._fig .get_size_inches ()
690
+ fig_w , fig_h = self ._fig .get_size_inches ()
690
691
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 ())
697
696
if ny1 is None :
698
697
ny1 = ny + 1
699
-
700
698
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
703
700
return mtransforms .Bbox .from_bounds (x1 , y1 , w1 , h1 )
704
701
705
702
0 commit comments