Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 54a4755

Browse filesBrowse files
authored
Merge pull request plotly#885 from plotly/subplot_proportions
Subplot proportions
2 parents 2b3de41 + 6498770 commit 54a4755
Copy full SHA for 54a4755

File tree

Expand file treeCollapse file tree

3 files changed

+130
-41
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+130
-41
lines changed

‎CHANGELOG.md

Copy file name to clipboardExpand all lines: CHANGELOG.md
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
All notable changes to this project will be documented in this file.
33
This project adheres to [Semantic Versioning](http://semver.org/).
44

5+
## [Unreleased] - TBA
6+
### Added
7+
-`column_width` and `row_width` parameters for `plotly.tools.make_subplots`. Call `help(plotly.tools.make_subplots)` for documentation.
8+
59
## [2.2.2] - 2017-11-23
610
### Added
711
- bullet chart figure factory. Call `help(plotly.figure_factory.create_bullet)` for examples and how to get started making bullet charts with the API.

‎plotly/tests/test_core/test_tools/test_make_subplots.py

Copy file name to clipboardExpand all lines: plotly/tests/test_core/test_tools/test_make_subplots.py
+40-24Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,22 @@ def test_insets_wrong_cell_col(self):
8383
with self.assertRaises(Exception):
8484
tls.make_subplots(insets=([{'cell': (1, 0)}]))
8585

86+
def test_column_width_not_list(self):
87+
with self.assertRaises(Exception):
88+
tls.make_subplots(rows=2, cols=2, column_width='not gonna work')
89+
90+
def test_column_width_not_list_of_correct_numbers(self):
91+
with self.assertRaises(Exception):
92+
tls.make_subplots(rows=2, cols=2, column_width=[0])
93+
94+
def test_row_width_not_list(self):
95+
with self.assertRaises(Exception):
96+
tls.make_subplots(rows=2, cols=2, row_width='not gonna work')
97+
98+
def test_row_width_not_list_of_correct_numbers(self):
99+
with self.assertRaises(Exception):
100+
tls.make_subplots(rows=2, cols=2, row_width=[1])
101+
86102
def test_single_plot(self):
87103
expected = Figure(
88104
data=Data(),
@@ -193,7 +209,7 @@ def test_a_lot(self):
193209
anchor='y12'
194210
),
195211
xaxis13=XAxis(
196-
domain=[0.7346938775510203, 0.8530612244897958],
212+
domain=[0.7346938775510204, 0.8530612244897959],
197213
anchor='y13'
198214
),
199215
xaxis14=XAxis(
@@ -225,7 +241,7 @@ def test_a_lot(self):
225241
anchor='y2'
226242
),
227243
xaxis20=XAxis(
228-
domain=[0.7346938775510203, 0.8530612244897958],
244+
domain=[0.7346938775510204, 0.8530612244897959],
229245
anchor='y20'
230246
),
231247
xaxis21=XAxis(
@@ -253,7 +269,7 @@ def test_a_lot(self):
253269
anchor='y26'
254270
),
255271
xaxis27=XAxis(
256-
domain=[0.7346938775510203, 0.8530612244897958],
272+
domain=[0.7346938775510204, 0.8530612244897959],
257273
anchor='y27'
258274
),
259275
xaxis28=XAxis(
@@ -273,7 +289,7 @@ def test_a_lot(self):
273289
anchor='y5'
274290
),
275291
xaxis6=XAxis(
276-
domain=[0.7346938775510203, 0.8530612244897958],
292+
domain=[0.7346938775510204, 0.8530612244897959],
277293
anchor='y6'
278294
),
279295
xaxis7=XAxis(
@@ -289,7 +305,7 @@ def test_a_lot(self):
289305
anchor='y9'
290306
),
291307
yaxis1=YAxis(
292-
domain=[0.8062499999999999, 0.9999999999999999],
308+
domain=[0.80625, 1.0],
293309
anchor='x1'
294310
),
295311
yaxis10=YAxis(
@@ -333,7 +349,7 @@ def test_a_lot(self):
333349
anchor='x19'
334350
),
335351
yaxis2=YAxis(
336-
domain=[0.8062499999999999, 0.9999999999999999],
352+
domain=[0.80625, 1.0],
337353
anchor='x2'
338354
),
339355
yaxis20=YAxis(
@@ -373,23 +389,23 @@ def test_a_lot(self):
373389
anchor='x28'
374390
),
375391
yaxis3=YAxis(
376-
domain=[0.8062499999999999, 0.9999999999999999],
392+
domain=[0.80625, 1.0],
377393
anchor='x3'
378394
),
379395
yaxis4=YAxis(
380-
domain=[0.8062499999999999, 0.9999999999999999],
396+
domain=[0.80625, 1.0],
381397
anchor='x4'
382398
),
383399
yaxis5=YAxis(
384-
domain=[0.8062499999999999, 0.9999999999999999],
400+
domain=[0.80625, 1.0],
385401
anchor='x5'
386402
),
387403
yaxis6=YAxis(
388-
domain=[0.8062499999999999, 0.9999999999999999],
404+
domain=[0.80625, 1.0],
389405
anchor='x6'
390406
),
391407
yaxis7=YAxis(
392-
domain=[0.8062499999999999, 0.9999999999999999],
408+
domain=[0.80625, 1.0],
393409
anchor='x7'
394410
),
395411
yaxis8=YAxis(
@@ -426,7 +442,7 @@ def test_a_lot_bottom_left(self):
426442
anchor='y12'
427443
),
428444
xaxis13=XAxis(
429-
domain=[0.7346938775510203, 0.8530612244897958],
445+
domain=[0.7346938775510204, 0.8530612244897959],
430446
anchor='y13'
431447
),
432448
xaxis14=XAxis(
@@ -458,7 +474,7 @@ def test_a_lot_bottom_left(self):
458474
anchor='y2'
459475
),
460476
xaxis20=XAxis(
461-
domain=[0.7346938775510203, 0.8530612244897958],
477+
domain=[0.7346938775510204, 0.8530612244897959],
462478
anchor='y20'
463479
),
464480
xaxis21=XAxis(
@@ -486,7 +502,7 @@ def test_a_lot_bottom_left(self):
486502
anchor='y26'
487503
),
488504
xaxis27=XAxis(
489-
domain=[0.7346938775510203, 0.8530612244897958],
505+
domain=[0.7346938775510204, 0.8530612244897959],
490506
anchor='y27'
491507
),
492508
xaxis28=XAxis(
@@ -506,7 +522,7 @@ def test_a_lot_bottom_left(self):
506522
anchor='y5'
507523
),
508524
xaxis6=XAxis(
509-
domain=[0.7346938775510203, 0.8530612244897958],
525+
domain=[0.7346938775510204, 0.8530612244897959],
510526
anchor='y6'
511527
),
512528
xaxis7=XAxis(
@@ -578,31 +594,31 @@ def test_a_lot_bottom_left(self):
578594
anchor='x21'
579595
),
580596
yaxis22=YAxis(
581-
domain=[0.8062499999999999, 0.9999999999999999],
597+
domain=[0.80625, 1.0],
582598
anchor='x22'
583599
),
584600
yaxis23=YAxis(
585-
domain=[0.8062499999999999, 0.9999999999999999],
601+
domain=[0.80625, 1.0],
586602
anchor='x23'
587603
),
588604
yaxis24=YAxis(
589-
domain=[0.8062499999999999, 0.9999999999999999],
605+
domain=[0.80625, 1.0],
590606
anchor='x24'
591607
),
592608
yaxis25=YAxis(
593-
domain=[0.8062499999999999, 0.9999999999999999],
609+
domain=[0.80625, 1.0],
594610
anchor='x25'
595611
),
596612
yaxis26=YAxis(
597-
domain=[0.8062499999999999, 0.9999999999999999],
613+
domain=[0.80625, 1.0],
598614
anchor='x26'
599615
),
600616
yaxis27=YAxis(
601-
domain=[0.8062499999999999, 0.9999999999999999],
617+
domain=[0.80625, 1.0],
602618
anchor='x27'
603619
),
604620
yaxis28=YAxis(
605-
domain=[0.8062499999999999, 0.9999999999999999],
621+
domain=[0.80625, 1.0],
606622
anchor='x28'
607623
),
608624
yaxis3=YAxis(
@@ -1308,7 +1324,7 @@ def test_shared_yaxes(self):
13081324
xaxis4=XAxis(
13091325
domain=[0.55, 1.0],
13101326
anchor='free',
1311-
position=0.636
1327+
position=0.6359999999999999
13121328
),
13131329
xaxis5=XAxis(
13141330
domain=[0.0, 0.45],
@@ -1337,7 +1353,7 @@ def test_shared_yaxes(self):
13371353
anchor='x1'
13381354
),
13391355
yaxis2=YAxis(
1340-
domain=[0.636, 0.788],
1356+
domain=[0.6359999999999999, 0.7879999999999999],
13411357
anchor='x3'
13421358
),
13431359
yaxis3=YAxis(

‎plotly/tools.py

Copy file name to clipboardExpand all lines: plotly/tools.py
+86-17Lines changed: 86 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,32 @@ def make_subplots(rows=1, cols=1,
772772
in fraction of cell height
773773
* h (float or 'to_end', default='to_end') inset height
774774
in fraction of cell height ('to_end': to cell top edge)
775+
776+
column_width (kwarg, list of numbers)
777+
Column_width specifications
778+
779+
- Functions similarly to `column_width` of `plotly.graph_objs.Table`.
780+
Specify a list that contains numbers where the amount of numbers in
781+
the list is equal to `cols`.
782+
783+
- The numbers in the list indicate the proportions that each column
784+
domains take across the full horizontal domain excluding padding.
785+
786+
- For example, if columns_width=[3, 1], horizontal_spacing=0, and
787+
cols=2, the domains for each column would be [0. 0.75] and [0.75, 1]
788+
789+
row_width (kwargs, list of numbers)
790+
Row_width specifications
791+
792+
- Functions similarly to `column_width`. Specify a list that contains
793+
numbers where the amount of numbers in the list is equal to `rows`.
794+
795+
- The numbers in the list indicate the proportions that each row
796+
domains take along the full vertical domain excluding padding.
797+
798+
- For example, if row_width=[3, 1], vertical_spacing=0, and
799+
cols=2, the domains for each row from top to botton would be
800+
[0. 0.75] and [0.75, 1]
775801
"""
776802
# TODO: protected until #282
777803
from plotly.graph_objs import graph_objs
@@ -807,7 +833,8 @@ def make_subplots(rows=1, cols=1,
807833

808834
# Throw exception if non-valid kwarg is sent
809835
VALID_KWARGS = ['horizontal_spacing', 'vertical_spacing',
810-
'specs', 'insets', 'subplot_titles']
836+
'specs', 'insets', 'subplot_titles', 'column_width',
837+
'row_width']
811838
for key in kwargs.keys():
812839
if key not in VALID_KWARGS:
813840
raise Exception("Invalid keyword argument: '{0}'".format(key))
@@ -907,9 +934,47 @@ def _checks(item, defaults):
907934
)
908935
_check_keys_and_fill('insets', insets, INSET_defaults)
909936

910-
# Set width & height of each subplot cell (excluding padding)
911-
width = (1. - horizontal_spacing * (cols - 1)) / cols
912-
height = (1. - vertical_spacing * (rows - 1)) / rows
937+
# set heights (with 'column_width')
938+
try:
939+
column_width = kwargs['column_width']
940+
if not isinstance(column_width, list) or len(column_width) != cols:
941+
raise Exception(
942+
"Keyword argument 'column_width' must be a list with {} "
943+
"numbers in it, the number of subplot cols.".format(cols)
944+
)
945+
except KeyError:
946+
column_width = None
947+
948+
if column_width:
949+
cum_sum = float(sum(column_width))
950+
widths = []
951+
for w in column_width:
952+
widths.append(
953+
(1. - horizontal_spacing * (cols - 1)) * (w / cum_sum)
954+
)
955+
else:
956+
widths = [(1. - horizontal_spacing * (cols - 1)) / cols] * cols
957+
958+
# set widths (with 'row_width')
959+
try:
960+
row_width = kwargs['row_width']
961+
if not isinstance(row_width, list) or len(row_width) != rows:
962+
raise Exception(
963+
"Keyword argument 'row_width' must be a list with {} "
964+
"numbers in it, the number of subplot rows.".format(rows)
965+
)
966+
except KeyError:
967+
row_width = None
968+
969+
if row_width:
970+
cum_sum = float(sum(row_width))
971+
heights = []
972+
for h in row_width:
973+
heights.append(
974+
(1. - vertical_spacing * (rows - 1)) * (h / cum_sum)
975+
)
976+
else:
977+
heights = [(1. - vertical_spacing * (rows - 1)) / rows] * rows
913978

914979
# Built row/col sequence using 'row_dir' and 'col_dir'
915980
COL_DIR = START_CELL['col_dir']
@@ -918,10 +983,14 @@ def _checks(item, defaults):
918983
row_seq = range(rows)[::ROW_DIR]
919984

920985
# [grid] Build subplot grid (coord tuple of cell)
921-
grid = [[((width + horizontal_spacing) * c,
922-
(height + vertical_spacing) * r)
923-
for c in col_seq]
924-
for r in row_seq]
986+
grid = [
987+
[
988+
(
989+
(sum(widths[:c]) + c * horizontal_spacing),
990+
(sum(heights[:r]) + r * vertical_spacing)
991+
) for c in col_seq
992+
] for r in row_seq
993+
]
925994

926995
# [grid_ref] Initialize the grid and insets' axis-reference lists
927996
grid_ref = [[None for c in range(cols)] for r in range(rows)]
@@ -1040,16 +1109,16 @@ def _add_domain_is_3d(layout, s_label, x_domain, y_domain):
10401109

10411110
# Get x domain using grid and colspan
10421111
x_s = grid[r][c][0] + spec['l']
1043-
x_e = grid[r][c_spanned][0] + width - spec['r']
1112+
x_e = grid[r][c_spanned][0] + widths[c] - spec['r']
10441113
x_domain = [x_s, x_e]
10451114

10461115
# Get y domain (dep. on row_dir) using grid & r_spanned
10471116
if ROW_DIR > 0:
10481117
y_s = grid[r][c][1] + spec['b']
1049-
y_e = grid[r_spanned][c][1] + height - spec['t']
1118+
y_e = grid[r_spanned][c][1] + heights[-1 - r] - spec['t']
10501119
else:
10511120
y_s = grid[r_spanned][c][1] + spec['b']
1052-
y_e = grid[r][c][1] + height - spec['t']
1121+
y_e = grid[r][c][1] + heights[-1 - r] - spec['t']
10531122
y_domain = [y_s, y_e]
10541123

10551124
if spec['is_3d']:
@@ -1108,19 +1177,19 @@ def _add_domain_is_3d(layout, s_label, x_domain, y_domain):
11081177
"Note: the starting cell is (1, 1)")
11091178

11101179
# Get inset x domain using grid
1111-
x_s = grid[r][c][0] + inset['l'] * width
1180+
x_s = grid[r][c][0] + inset['l'] * widths[c]
11121181
if inset['w'] == 'to_end':
1113-
x_e = grid[r][c][0] + width
1182+
x_e = grid[r][c][0] + widths[c]
11141183
else:
1115-
x_e = x_s + inset['w'] * width
1184+
x_e = x_s + inset['w'] * widths[c]
11161185
x_domain = [x_s, x_e]
11171186

11181187
# Get inset y domain using grid
1119-
y_s = grid[r][c][1] + inset['b'] * height
1188+
y_s = grid[r][c][1] + inset['b'] * heights[-1 - r]
11201189
if inset['h'] == 'to_end':
1121-
y_e = grid[r][c][1] + height
1190+
y_e = grid[r][c][1] + heights[-1 - r]
11221191
else:
1123-
y_e = y_s + inset['h'] * height
1192+
y_e = y_s + inset['h'] * heights[-1 - r]
11241193
y_domain = [y_s, y_e]
11251194

11261195
if inset['is_3d']:

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.