Skip to content

Commit 241f4ca

Browse files
committed
Merge pull request #170 from plotly/revamp-get_subplots
Revamp tls.get_subplots
2 parents 6638801 + 5536194 commit 241f4ca

File tree

8 files changed

+3153
-25
lines changed

8 files changed

+3153
-25
lines changed

Diff for: plotly/graph_objs/graph_objs.py

+81
Original file line numberDiff line numberDiff line change
@@ -919,6 +919,87 @@ def __init__(self, *args, **kwargs):
919919
kwargs['layout'] = Layout()
920920
super(Figure, self).__init__(*args, **kwargs)
921921
Figure.__init__ = __init__ # override method!
922+
923+
def print_grid(self):
924+
"""Print a visual layout of the figure's axes arrangement.
925+
926+
This is only valid for figures that are created
927+
with plotly.tools.make_subplots.
928+
"""
929+
try:
930+
grid_str = self._grid_str
931+
except KeyError:
932+
raise Exception("Use plotly.tools.make_subplots "
933+
"to create a subplot grid.")
934+
print(grid_str)
935+
Figure.print_grid = print_grid
936+
937+
def append_trace(self, trace, row, col):
938+
""" Helper function to add a data traces to your figure
939+
that is bound to axes at the row, col index.
940+
941+
The row, col index is generated from figures created with
942+
plotly.tools.make_subplots and can be viewed with Figure.print_grid.
943+
944+
Example:
945+
# stack two subplots vertically
946+
fig = tools.make_subplots(rows=2)
947+
948+
This is the format of your plot grid:
949+
[ (1,1) x1,y1 ]
950+
[ (2,1) x2,y2 ]
951+
952+
fig.append_trace(Scatter(x=[1,2,3], y=[2,1,2]), 1, 1)
953+
fig.append_trace(Scatter(x=[1,2,3], y=[2,1,2]), 2, 1)
954+
955+
Arguments:
956+
957+
trace (plotly trace object):
958+
The data trace to be bound.
959+
960+
row (int):
961+
Subplot row index on the subplot grid (see Figure.print_grid)
962+
963+
col (int):
964+
Subplot column index on the subplot grid (see Figure.print_grid)
965+
966+
"""
967+
try:
968+
grid_ref = self._grid_ref
969+
except KeyError:
970+
raise Exception("In order to use Figure.append_trace, "
971+
"you must first use plotly.tools.make_subplots "
972+
"to create a subplot grid.")
973+
if row <= 0:
974+
raise Exception("Row value is out of range. "
975+
"Note: the starting cell is (1, 1)")
976+
if col <= 0:
977+
raise Exception("Col value is out of range. "
978+
"Note: the starting cell is (1, 1)")
979+
try:
980+
ref = grid_ref[row-1][col-1]
981+
except IndexError:
982+
raise Exception("The (row, col) pair sent is out of range. "
983+
"Use Figure.print_grid to view the subplot grid. ")
984+
if 'scene' in ref[0]:
985+
trace['scene'] = ref[0]
986+
if ref[0] not in self['layout']:
987+
raise Exception("Something went wrong. "
988+
"The scene object for ({r},{c}) subplot cell "
989+
"got deleted.".format(r=row, c=col))
990+
else:
991+
xaxis_key = "xaxis{ref}".format(ref=ref[0][1:])
992+
yaxis_key = "yaxis{ref}".format(ref=ref[1][1:])
993+
if (xaxis_key not in self['layout']
994+
or yaxis_key not in self['layout']):
995+
raise Exception("Something went wrong. "
996+
"An axis object for ({r},{c}) subplot cell "
997+
"got deleted.".format(r=row, c=col))
998+
trace['xaxis'] = ref[0]
999+
trace['yaxis'] = ref[1]
1000+
self['data'] += [trace]
1001+
Figure.append_trace = append_trace
1002+
9221003
return Figure
9231004

9241005
Figure = get_patched_figure_class(Figure)

Diff for: plotly/graph_reference/graph_objs_meta.json

+14-4
Original file line numberDiff line numberDiff line change
@@ -1586,9 +1586,9 @@
15861586
},
15871587
"scene": {
15881588
"key_type": "plot_info",
1589-
"val_types": "'s1' | 's2' | 's3' | etc.",
1589+
"val_types": "'scene1' | 'scene2' | 'scene3' | etc.",
15901590
"required": false,
1591-
"description": "This key determines the scene on which this trace will be plotted in. More info coming soon."
1591+
"description": "This key determines the scene on which this trace will be plotted in."
15921592
},
15931593
"stream": {
15941594
"key_type": "object",
@@ -1657,9 +1657,9 @@
16571657
},
16581658
"scene": {
16591659
"key_type": "plot_info",
1660-
"val_types": "'s1' | 's2' | 's3' | etc.",
1660+
"val_types": "'scene1' | 'scene2' | 'scene3' | etc.",
16611661
"required": false,
1662-
"description": "This key determines the scene on which this trace will be plotted in. More info coming soon."
1662+
"description": "This key determines the scene on which this trace will be plotted in."
16631663
},
16641664
"stream": {
16651665
"key_type": "object",
@@ -3317,6 +3317,16 @@
33173317
],
33183318
"description": "Sets the camera position with respect to the scene. The first entry (a list or 1d numpy array of length 4) sets the angular position of the camera. The second entry (a list or 1d numpy array of length 3) sets the (x,y,z) translation of the camera. The third entry (a scalar) sets zoom of the camera."
33193319
},
3320+
"domain": {
3321+
"key_type": "plot_info",
3322+
"val_types": "domain dictionary",
3323+
"required": false,
3324+
"examples": [
3325+
"{'x': [0, 0.4], 'y': [0.6, 1]}",
3326+
"dict(x=[0, 0.4], y=[0.6, 1])"
3327+
],
3328+
"description": "Sets the x-y domain of this scene on the plotting surface."
3329+
},
33203330
"bgcolor": {
33213331
"key_type": "style",
33223332
"val_types": "a string describing color",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
import plotly
2+
from plotly.graph_objs import *
3+
import plotly.tools as tls
4+
from nose.tools import raises
5+
6+
7+
@raises(Exception)
8+
def test_print_grid_before_make_subplots():
9+
fig.print_grid()
10+
11+
@raises(Exception)
12+
def test_append_trace_before_make_subplots():
13+
trace = Scatter(
14+
x=[1,2,3],
15+
y=[2,3,4]
16+
)
17+
fig.append_trace(trace, 2, 2)
18+
19+
@raises(Exception)
20+
def test_append_trace_row_out_of_range():
21+
trace = Scatter(
22+
x=[1,2,3],
23+
y=[2,3,4]
24+
)
25+
fig = tls.make_subplots(rows=2, cols=3)
26+
fig.append_trace(trace, 10, 2)
27+
28+
@raises(Exception)
29+
def test_append_trace_col_out_of_range():
30+
trace = Scatter(
31+
x=[1,2,3],
32+
y=[2,3,4]
33+
)
34+
fig = tls.make_subplots(rows=2, cols=3)
35+
fig.append_trace(trace, 2, 0)
36+
37+
def test_append_scatter():
38+
expected = Figure(
39+
data=Data([
40+
Scatter(
41+
x=[1, 2, 3],
42+
y=[2, 3, 4],
43+
xaxis='x5',
44+
yaxis='y5'
45+
)
46+
]),
47+
layout=Layout(
48+
xaxis1=XAxis(
49+
domain=[0.0, 0.2888888888888889],
50+
anchor='y1'
51+
),
52+
xaxis2=XAxis(
53+
domain=[0.35555555555555557, 0.6444444444444445],
54+
anchor='y2'
55+
),
56+
xaxis3=XAxis(
57+
domain=[0.7111111111111111, 1.0],
58+
anchor='y3'
59+
),
60+
xaxis4=XAxis(
61+
domain=[0.0, 0.2888888888888889],
62+
anchor='y4'
63+
),
64+
xaxis5=XAxis(
65+
domain=[0.35555555555555557, 0.6444444444444445],
66+
anchor='y5'
67+
),
68+
xaxis6=XAxis(
69+
domain=[0.7111111111111111, 1.0],
70+
anchor='y6'
71+
),
72+
yaxis1=YAxis(
73+
domain=[0.575, 1.0],
74+
anchor='x1'
75+
),
76+
yaxis2=YAxis(
77+
domain=[0.575, 1.0],
78+
anchor='x2'
79+
),
80+
yaxis3=YAxis(
81+
domain=[0.575, 1.0],
82+
anchor='x3'
83+
),
84+
yaxis4=YAxis(
85+
domain=[0.0, 0.425],
86+
anchor='x4'
87+
),
88+
yaxis5=YAxis(
89+
domain=[0.0, 0.425],
90+
anchor='x5'
91+
),
92+
yaxis6=YAxis(
93+
domain=[0.0, 0.425],
94+
anchor='x6'
95+
)
96+
)
97+
)
98+
99+
trace = Scatter(
100+
x=[1,2,3],
101+
y=[2,3,4]
102+
)
103+
fig = tls.make_subplots(rows=2, cols=3)
104+
fig.append_trace(trace, 2, 2)
105+
assert fig == expected
106+
107+
@raises(Exception)
108+
def test_append_scatter_after_deleting_xaxis():
109+
trace = Scatter(
110+
x=[1,2,3],
111+
y=[2,3,4]
112+
)
113+
fig = tls.make_subplots(rows=2, cols=3)
114+
fig['layout'].pop('xaxis5', None)
115+
fig.append_trace(trace, 2, 2)
116+
117+
@raises(Exception)
118+
def test_append_scatter_after_deleting_yaxis():
119+
trace = Scatter(
120+
x=[1,2,3],
121+
y=[2,3,4]
122+
)
123+
fig = tls.make_subplots(rows=2, cols=3)
124+
fig['layout'].pop('yaxis5', None)
125+
fig.append_trace(trace, 2, 2)
126+
127+
def test_append_scatter3d():
128+
expected = Figure(
129+
data=Data([
130+
Scatter3d(
131+
x=[1, 2, 3],
132+
y=[2, 3, 4],
133+
z=[1, 2, 3],
134+
scene='scene2'
135+
),
136+
Scatter3d(
137+
x=[1, 2, 3],
138+
y=[2, 3, 4],
139+
z=[1, 2, 3],
140+
scene='scene2'
141+
)
142+
]),
143+
layout=Layout(
144+
scene1=Scene(
145+
domain={'y': [0.575, 1.0], 'x': [0.0, 1.0]}
146+
),
147+
scene2=Scene(
148+
domain={'y': [0.0, 0.425], 'x': [0.0, 1.0]}
149+
)
150+
)
151+
)
152+
153+
fig = tls.make_subplots(rows=2, cols=1,
154+
specs=[[{'is_3d': True}],
155+
[{'is_3d': True}]])
156+
trace = Scatter3d(
157+
x=[1,2,3],
158+
y=[2,3,4],
159+
z=[1,2,3]
160+
)
161+
fig.append_trace(trace, 1, 1)
162+
fig.append_trace(trace, 2, 1)
163+
assert fig == expected
164+
165+
@raises(Exception)
166+
def test_append_scatter3d_after_deleting_scene():
167+
fig = tls.make_subplots(rows=2, cols=1,
168+
specs=[[{'is_3d': True}],
169+
[{'is_3d': True}]])
170+
trace = Scatter3d(
171+
x=[1,2,3],
172+
y=[2,3,4],
173+
z=[1,2,3]
174+
)
175+
fig['layout'].pop('scene1', None)
176+
fig.append_trace(trace, 1, 1)

0 commit comments

Comments
 (0)