Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6d8fc4c

Browse files
committed
Subplot titles with shared axes
-Fix subplot titles so they work with plots with shared axes -Add tests
1 parent 43b421e commit 6d8fc4c

File tree

2 files changed

+347
-16
lines changed

2 files changed

+347
-16
lines changed

plotly/tests/test_core/test_tools/test_make_subplots.py

Lines changed: 319 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,10 +1210,10 @@ def test_specs_padding_bottom_left():
12101210
)
12111211

12121212
fig = tls.make_subplots(rows=2, cols=2,
1213-
horizontal_spacing=0, vertical_spacing=0,
1214-
specs=[[{'l': 0.1}, {'b': 0.2}],
1215-
[{'t': 0.2}, {'r': 0.1}]],
1216-
start_cell='bottom-left')
1213+
horizontal_spacing=0, vertical_spacing=0,
1214+
specs=[[{'l': 0.1}, {'b': 0.2}],
1215+
[{'t': 0.2}, {'r': 0.1}]],
1216+
start_cell='bottom-left')
12171217
assert fig == expected
12181218

12191219
def test_shared_xaxes():
@@ -1926,3 +1926,318 @@ def test_insets_multiple_bottom_left():
19261926
{'cell': (2,1), 'l':0.8}],
19271927
start_cell='bottom-left')
19281928
assert fig == expected
1929+
1930+
1931+
def test_subplot_titles_2x1():
1932+
# make a title for each subplot when the layout is 2 rows and 1 column
1933+
expected = Figure(
1934+
data=Data(),
1935+
layout=Layout(
1936+
annotations=Annotations([
1937+
Annotation(
1938+
x=0.5,
1939+
y=1.0,
1940+
xref='paper',
1941+
yref='paper',
1942+
text='Title 1',
1943+
showarrow=False,
1944+
font=Font(size=18),
1945+
xanchor='center',
1946+
yanchor='bottom'
1947+
),
1948+
Annotation(
1949+
x=0.5,
1950+
y=0.425,
1951+
xref='paper',
1952+
yref='paper',
1953+
text='Title 2',
1954+
showarrow=False,
1955+
font=Font(size=18),
1956+
xanchor='center',
1957+
yanchor='bottom'
1958+
)
1959+
]),
1960+
xaxis1=XAxis(
1961+
domain=[0.0, 1.0],
1962+
anchor='y1'
1963+
),
1964+
xaxis2=XAxis(
1965+
domain=[0.0, 1.0],
1966+
anchor='y2'
1967+
),
1968+
yaxis1=YAxis(
1969+
domain=[0.575, 1.0],
1970+
anchor='x1'
1971+
),
1972+
yaxis2=YAxis(
1973+
domain=[0.0, 0.425],
1974+
anchor='x2'
1975+
)
1976+
)
1977+
)
1978+
fig = tls.make_subplots(rows=2, subplot_titles=('Title 1', 'Title 2'))
1979+
assert fig == expected
1980+
1981+
1982+
def test_subplot_titles_1x3():
1983+
# make a title for each subplot when the layout is 1 row and 3 columns
1984+
expected = Figure(
1985+
data=Data(),
1986+
layout=Layout(
1987+
annotations=Annotations([
1988+
Annotation(
1989+
x=0.14444444444444446,
1990+
y=1.0,
1991+
xref='paper',
1992+
yref='paper',
1993+
text='Title 1',
1994+
showarrow=False,
1995+
font=Font(size=18),
1996+
xanchor='center',
1997+
yanchor='bottom'
1998+
),
1999+
Annotation(
2000+
x=0.5,
2001+
y=1.0,
2002+
xref='paper',
2003+
yref='paper',
2004+
text='Title 2',
2005+
showarrow=False,
2006+
font=Font(size=18),
2007+
xanchor='center',
2008+
yanchor='bottom'
2009+
),
2010+
Annotation(
2011+
x=0.8555555555555556,
2012+
y=1.0,
2013+
xref='paper',
2014+
yref='paper',
2015+
text='Title 3',
2016+
showarrow=False,
2017+
font=Font(size=18),
2018+
xanchor='center',
2019+
yanchor='bottom'
2020+
)
2021+
]),
2022+
xaxis1=XAxis(
2023+
domain=[0.0, 0.2888888888888889],
2024+
anchor='y1'
2025+
),
2026+
xaxis2=XAxis(
2027+
domain=[0.35555555555555557, 0.6444444444444445],
2028+
anchor='y2'
2029+
),
2030+
xaxis3=XAxis(
2031+
domain=[0.7111111111111111, 1.0],
2032+
anchor='y3'
2033+
),
2034+
yaxis1=YAxis(
2035+
domain=[0.0, 1.0],
2036+
anchor='x1'
2037+
),
2038+
yaxis2=YAxis(
2039+
domain=[0.0, 1.0],
2040+
anchor='x2'
2041+
),
2042+
yaxis3=YAxis(
2043+
domain=[0.0, 1.0],
2044+
anchor='x3'
2045+
)
2046+
)
2047+
)
2048+
fig = tls.make_subplots(cols=3,
2049+
subplot_titles=('Title 1', 'Title 2', 'Title 3'))
2050+
assert fig == expected
2051+
2052+
2053+
def test_subplot_titles_shared_axes():
2054+
# make a title for each subplot when the layout is 1 row and 3 columns
2055+
expected = Figure(
2056+
data=Data(),
2057+
layout=Layout(
2058+
annotations=Annotations([
2059+
Annotation(
2060+
x=0.22499999999999998,
2061+
y=1.0,
2062+
xref='paper',
2063+
yref='paper',
2064+
text='Title 1',
2065+
showarrow=False,
2066+
font=Font(size=18),
2067+
xanchor='center',
2068+
yanchor='bottom'
2069+
),
2070+
Annotation(
2071+
x=0.7749999999999999,
2072+
y=1.0,
2073+
xref='paper',
2074+
yref='paper',
2075+
text='Title 2',
2076+
showarrow=False,
2077+
font=Font(size=18),
2078+
xanchor='center',
2079+
yanchor='bottom'
2080+
),
2081+
Annotation(
2082+
x=0.22499999999999998,
2083+
y=0.42500000000000004,
2084+
xref='paper',
2085+
yref='paper',
2086+
text='Title 3',
2087+
showarrow=False,
2088+
font=Font(size=18),
2089+
xanchor='center',
2090+
yanchor='bottom'
2091+
),
2092+
Annotation(
2093+
x=0.7749999999999999,
2094+
y=0.42500000000000004,
2095+
xref='paper',
2096+
yref='paper',
2097+
text='Title 4',
2098+
showarrow=False,
2099+
font=Font(size=18),
2100+
xanchor='center',
2101+
yanchor='bottom'
2102+
)
2103+
]),
2104+
xaxis1=XAxis(
2105+
domain=[0.0, 0.45],
2106+
anchor='y2'
2107+
),
2108+
xaxis2=XAxis(
2109+
domain=[0.55, 1.0],
2110+
anchor='free',
2111+
position=0.0
2112+
),
2113+
yaxis1=YAxis(
2114+
domain=[0.575, 1.0],
2115+
anchor='free',
2116+
position=0.0
2117+
),
2118+
yaxis2=YAxis(
2119+
domain=[0.0, 0.425],
2120+
anchor='x1'
2121+
)
2122+
)
2123+
)
2124+
fig = tls.make_subplots(rows=2, cols=2,
2125+
subplot_titles=('Title 1', 'Title 2',
2126+
'Title 3', 'Title 4'),
2127+
shared_xaxes=True, shared_yaxes=True)
2128+
2129+
assert fig == expected
2130+
2131+
2132+
def test_subplot_titles_irregular_layout():
2133+
# make a title for each subplot when the layout is irregular:
2134+
expected = Figure(
2135+
data=Data(),
2136+
layout=Layout(
2137+
annotations=Annotations([
2138+
Annotation(
2139+
x=0.225,
2140+
y=1.0,
2141+
xref='paper',
2142+
yref='paper',
2143+
text='Title 1',
2144+
showarrow=False,
2145+
font=Font(size=18),
2146+
xanchor='center',
2147+
yanchor='bottom'
2148+
),
2149+
Annotation(
2150+
x=0.775,
2151+
y=1.0,
2152+
xref='paper',
2153+
yref='paper',
2154+
text='Title 2',
2155+
showarrow=False,
2156+
font=Font(size=18),
2157+
xanchor='center',
2158+
yanchor='bottom'
2159+
),
2160+
Annotation(
2161+
x=0.5,
2162+
y=0.425,
2163+
xref='paper',
2164+
yref='paper',
2165+
text='Title 3',
2166+
showarrow=False,
2167+
font=Font(size=18),
2168+
xanchor='center',
2169+
yanchor='bottom'
2170+
)
2171+
]),
2172+
xaxis1=XAxis(
2173+
domain=[0.0, 0.45],
2174+
anchor='y1'
2175+
),
2176+
xaxis2=XAxis(
2177+
domain=[0.55, 1.0],
2178+
anchor='y2'
2179+
),
2180+
xaxis3=XAxis(
2181+
domain=[0.0, 1.0],
2182+
anchor='y3'
2183+
),
2184+
yaxis1=YAxis(
2185+
domain=[0.575, 1.0],
2186+
anchor='x1'
2187+
),
2188+
yaxis2=YAxis(
2189+
domain=[0.575, 1.0],
2190+
anchor='x2'
2191+
),
2192+
yaxis3=YAxis(
2193+
domain=[0.0, 0.425],
2194+
anchor='x3'
2195+
)
2196+
)
2197+
)
2198+
fig = tls.make_subplots(rows=2, cols=2,
2199+
subplot_titles=('Title 1', 'Title 2', 'Title 3'),
2200+
specs=[[{}, {}], [{'colspan': 2}, None]])
2201+
assert fig == expected
2202+
2203+
2204+
def test_subplot_titles_insets():
2205+
# This should make a title for the inset plot
2206+
# and no title for the main plot.
2207+
expected = Figure(
2208+
data=Data(),
2209+
layout=Layout(
2210+
annotations=Annotations([
2211+
Annotation(
2212+
x=0.85,
2213+
y=1.0,
2214+
xref='paper',
2215+
yref='paper',
2216+
text='Inset',
2217+
showarrow=False,
2218+
font=Font(size=18),
2219+
xanchor='center',
2220+
yanchor='bottom'
2221+
)
2222+
]),
2223+
xaxis1=XAxis(
2224+
domain=[0.0, 1.0],
2225+
anchor='y1'
2226+
),
2227+
xaxis2=XAxis(
2228+
domain=[0.7, 1.0],
2229+
anchor='y2'
2230+
),
2231+
yaxis1=YAxis(
2232+
domain=[0.0, 1.0],
2233+
anchor='x1'
2234+
),
2235+
yaxis2=YAxis(
2236+
domain=[0.3, 1.0],
2237+
anchor='x2'
2238+
)
2239+
)
2240+
)
2241+
fig = tls.make_subplots(insets=[{'cell': (1, 1), 'l': 0.7, 'b': 0.3}],
2242+
subplot_titles=("", 'Inset'))
2243+
assert fig == expected

plotly/tools.py

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,17 +1169,33 @@ def _pad(s, cell_len=cell_len):
11691169
)
11701170

11711171
# Add subplot titles
1172-
x_dom = list_of_domains[::2]
1173-
y_dom = list_of_domains[1::2]
11741172

1175-
subtitle_pos_x = []
1176-
for index in range(len(x_dom)):
1177-
subtitle_pos_x.append(((x_dom[index][1]) - (x_dom[index][0])) / 2 +
1178-
x_dom[index][0])
1179-
1180-
subtitle_pos_y = []
1181-
for index in range(len(y_dom)):
1182-
subtitle_pos_y.append(y_dom[index][1])
1173+
# If shared_axes is False (default) use list_of_domains
1174+
# This is used for insets and irregular layouts
1175+
if not shared_xaxes and not shared_yaxes:
1176+
x_dom = list_of_domains[::2]
1177+
y_dom = list_of_domains[1::2]
1178+
subtitle_pos_x = []
1179+
subtitle_pos_y = []
1180+
for index in range(len(x_dom)):
1181+
subtitle_pos_x.append(((x_dom[index][1]) - (x_dom[index][0])) / 2 +
1182+
x_dom[index][0])
1183+
for index in range(len(y_dom)):
1184+
subtitle_pos_y.append(y_dom[index][1])
1185+
# If shared_axes is True the domin of each subplot is not returned so the
1186+
# title position must be calculated for each subplot
1187+
else:
1188+
subtitle_pos_x = [None] * cols
1189+
subtitle_pos_y = [None] * rows
1190+
delt_x = (x_e - x_s)
1191+
for index in range(cols):
1192+
subtitle_pos_x[index] = ((delt_x / 2) +
1193+
((delt_x + horizontal_spacing) * index))
1194+
subtitle_pos_x *= rows
1195+
for index in range(rows):
1196+
subtitle_pos_y[index] = (1 - ((y_e + vertical_spacing) * index))
1197+
subtitle_pos_y *= cols
1198+
subtitle_pos_y = sorted(subtitle_pos_y, reverse=True)
11831199

11841200
plot_titles = []
11851201
for index in range(len(subplot_titles)):
@@ -1192,12 +1208,12 @@ def _pad(s, cell_len=cell_len):
11921208
'yref': 'paper',
11931209
'text': subplot_titles[index],
11941210
'showarrow': False,
1195-
'font': Font(size=18),
1211+
'font': graph_objs.Font(size=18),
11961212
'xanchor': 'center',
11971213
'yanchor': 'bottom'
11981214
})
11991215

1200-
layout['annotations'] = plot_titles
1216+
layout['annotations'] = plot_titles
12011217

12021218
if print_grid:
12031219
print(grid_str)

0 commit comments

Comments
 (0)