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

Skip to content

Commit 7c450a2

Browse files
turnipseasontacaswell
authored andcommitted
Added an initial example and amended _do_layout.
1 parent 3a70c5a commit 7c450a2

File tree

5 files changed

+410
-25
lines changed

5 files changed

+410
-25
lines changed
Lines changed: 399 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,399 @@
1+
"""
2+
=================
3+
Subfigure mosaic
4+
=================
5+
6+
This example is inspired by the `subplot_mosaic()
7+
<https://matplotlib.org/devdocs/users/explain/axes/mosaic.html>`__
8+
and `subfigures()
9+
<https://matplotlib.org/devdocs/gallery/subplots_axes_and_figures/subfigures.html>`__
10+
examples. It especially aims to mimic the former. Most of the API
11+
that is going to be described below is analogous to the `.Figure.subplot_mosaic` API.
12+
13+
`.Figure.subfigure_mosaic` provides a simple way of constructing
14+
complex layouts, such as SubFigures that span multiple columns / rows
15+
of the layout or leave some areas of the Figure blank. The layouts are
16+
constructed either through ASCII art or nested lists.
17+
18+
This interface naturally supports naming your SubFigures. `.Figure.subfigure_mosaic`
19+
returns a dictionary keyed on the labels used to lay out the Figure.
20+
"""
21+
import matplotlib.pyplot as plt
22+
import numpy as np
23+
24+
25+
# Let's define a function to help visualize
26+
def identify_subfigs(subfig_dict, fontsize=36):
27+
"""
28+
Helper to identify the SubFigures in the examples below.
29+
30+
Draws the label in a large font in the center of the SubFigure.
31+
32+
Parameters
33+
----------
34+
subfig_dict : dict[str, SubFigure]
35+
Mapping between the title / label and the SubFigures.
36+
fontsize : int, optional
37+
How big the label should be.
38+
"""
39+
kw = dict(ha="center", va="center", fontsize=fontsize, color="darkgrey")
40+
for k, subfig in subfig_dict.items():
41+
subfig.text(0.5, 0.5, k, **kw)
42+
43+
44+
# %%
45+
# If we want a 2x2 grid we can use `.Figure.subfigures` which returns a 2D array
46+
# of `.figure.SubFigure` which we can index.
47+
48+
fig = plt.figure()
49+
subfigs = fig.subfigures(2, 2)
50+
51+
subfigs[0, 0].set_edgecolor('black')
52+
subfigs[0, 0].set_linewidth(2.1)
53+
subfigs[1, 1].set_edgecolor('yellow')
54+
subfigs[1, 1].set_linewidth(2.1)
55+
subfigs[0, 1].set_facecolor('green')
56+
57+
identify_subfigs(
58+
{(j, k): a for j, r in enumerate(subfigs) for k, a in enumerate(r)},
59+
)
60+
61+
# %%
62+
# Using `.Figure.subfigure_mosaic` we can produce the same mosaic but give the
63+
# SubFigures names
64+
65+
fig = plt.figure()
66+
subfigs = fig.subfigure_mosaic(
67+
[
68+
["First", "Second"],
69+
["Third", "Fourth"],
70+
],
71+
)
72+
subfigs["First"].set_edgecolor('black')
73+
subfigs["First"].set_linewidth(2.1)
74+
subfigs["Second"].set_facecolor('green')
75+
subfigs["Fourth"].set_edgecolor('yellow')
76+
subfigs["Fourth"].set_linewidth(2.1)
77+
78+
identify_subfigs(subfigs)
79+
80+
# %%
81+
# A key difference between `.Figure.subfigures` and
82+
# `.Figure.subfigure_mosaic` is the return value. While the former
83+
# returns an array for index access, the latter returns a dictionary
84+
# mapping the labels to the `.figure.SubFigure` instances created
85+
86+
print(subfigs)
87+
88+
# %%
89+
# String short-hand
90+
# =================
91+
#
92+
# By restricting our labels to single characters we can
93+
# "draw" the SubFigures we want as "ASCII art". The following
94+
95+
96+
mosaic = """
97+
AB
98+
CD
99+
"""
100+
101+
# %%
102+
# will give us 4 SubFigures laid out in a 2x2 grid and generate the same
103+
# subfigure mosaic as above (but now labeled with ``{"A", "B", "C",
104+
# "D"}`` rather than ``{"First", "Second", "Third", "Fourth"}``).
105+
# Bear in mind that subfigures do not come 'visible' the way subplots do.
106+
# In case you want them to be clearly visible - you will need to set certain
107+
# keyword arguments (such as edge/face color). This is discussed at length in the
108+
# :ref:`controlling-creation` part of this example.
109+
110+
fig = plt.figure()
111+
subfigs = fig.subfigure_mosaic(mosaic)
112+
identify_subfigs(subfigs)
113+
114+
# %%
115+
# Alternatively, you can use the more compact string notation:
116+
mosaic = "AB;CD"
117+
118+
# %%
119+
# will give you the same composition, where the ``";"`` is used
120+
# as the row separator instead of newline.
121+
122+
fig = plt.figure()
123+
subfigs = fig.subfigure_mosaic(mosaic)
124+
identify_subfigs(subfigs)
125+
126+
# %%
127+
# SubFigures spanning multiple rows/columns
128+
# =========================================
129+
#
130+
# Something we can do with `.Figure.subfigure_mosaic`, that we cannot
131+
# do with `.Figure.subfigures`, is to specify that a SubFigure should span
132+
# several rows or columns.
133+
134+
135+
# %%
136+
# If we want to re-arrange our four SubFigures to have ``"C"`` be a horizontal
137+
# span on the bottom and ``"D"`` be a vertical span on the right we would do:
138+
139+
subfigs = plt.figure().subfigure_mosaic(
140+
"""
141+
ABD
142+
CCD
143+
"""
144+
)
145+
146+
# setting edges for clarity
147+
for sf in subfigs.values():
148+
sf.set_edgecolor('black')
149+
sf.set_linewidth(2.1)
150+
151+
identify_subfigs(subfigs)
152+
153+
# %%
154+
# If we do not want to fill in all the spaces in the Figure with SubFigures,
155+
# we can specify some spaces in the grid to be blank, like so:
156+
157+
subfigs = plt.figure().subfigure_mosaic(
158+
"""
159+
A.C
160+
BBB
161+
.D.
162+
"""
163+
)
164+
165+
# setting edges for clarity
166+
for sf in subfigs.values():
167+
sf.set_edgecolor('black')
168+
sf.set_linewidth(2.1)
169+
170+
identify_subfigs(subfigs)
171+
172+
# %%
173+
# If we prefer to use another character (rather than a period ``"."``)
174+
# to mark the empty space, we can use *empty_sentinel* to specify the
175+
# character to use.
176+
177+
subfigs = plt.figure().subfigure_mosaic(
178+
"""
179+
aX
180+
Xb
181+
""",
182+
empty_sentinel="X",
183+
)
184+
185+
# setting edges for clarity
186+
for sf in subfigs.values():
187+
sf.set_edgecolor('black')
188+
sf.set_linewidth(2.1)
189+
identify_subfigs(subfigs)
190+
191+
# %%
192+
#
193+
# Internally there is no meaning attached to the letters we use, any
194+
# Unicode code point is valid!
195+
196+
subfigs = plt.figure().subfigure_mosaic(
197+
"""αя
198+
ℝ☢"""
199+
)
200+
201+
# setting edges for clarity
202+
for sf in subfigs.values():
203+
sf.set_edgecolor('black')
204+
sf.set_linewidth(2.1)
205+
identify_subfigs(subfigs)
206+
207+
# %%
208+
# It is not recommended to use white space as either a label or an
209+
# empty sentinel with the string shorthand because it may be stripped
210+
# while processing the input.
211+
#
212+
# Controlling mosaic creation
213+
# ===========================
214+
#
215+
# This feature is built on top of `.gridspec` and you can pass the
216+
# keyword arguments through to the underlying `.gridspec.GridSpec`
217+
# (the same as `.Figure.subfigures`).
218+
#
219+
# In this case we want to use the input to specify the arrangement,
220+
# but set the relative widths of the rows / columns. For convenience,
221+
# `.gridspec.GridSpec`'s *height_ratios* and *width_ratios* are exposed in the
222+
# `.Figure.subfigure_mosaic` calling sequence.
223+
224+
subfigs = plt.figure().subfigure_mosaic(
225+
"""
226+
.a.
227+
bAc
228+
.d.
229+
""",
230+
# set the height ratios between the rows
231+
height_ratios=[1, 3.5, 1],
232+
# set the width ratios between the columns
233+
width_ratios=[1, 3.5, 1],
234+
)
235+
236+
# setting edges for clarity
237+
for sf in subfigs.values():
238+
sf.set_edgecolor('black')
239+
sf.set_linewidth(2.1)
240+
identify_subfigs(subfigs)
241+
242+
# %%
243+
# You can also use the `.Figure.subfigures` functionality to
244+
# position the overall mosaic to put multiple versions of the same
245+
# mosaic in a figure.
246+
247+
mosaic = """AA
248+
BC"""
249+
fig = plt.figure()
250+
251+
left, right = fig.subfigures(nrows=1, ncols=2)
252+
253+
subfigs = left.subfigure_mosaic(mosaic)
254+
for subfig in subfigs.values():
255+
subfig.set_edgecolor('black')
256+
subfig.set_linewidth(2.1)
257+
identify_subfigs(subfigs)
258+
259+
subfigs = right.subfigure_mosaic(mosaic)
260+
for subfig in subfigs.values():
261+
subfig.set_edgecolor('black')
262+
subfig.set_linewidth(2.1)
263+
identify_subfigs(subfigs)
264+
265+
# %%
266+
# .. _controlling-creation:
267+
# Controlling subfigure creation
268+
# ==============================
269+
#
270+
# We can also pass through arguments used to create the subfigures
271+
# which will apply to all of the SubFigures created. So instead of iterating like so:
272+
273+
for sf in subfigs.values():
274+
sf.set_edgecolor('black')
275+
sf.set_linewidth(2.1)
276+
277+
# %%
278+
# we would write:
279+
280+
subfigs = plt.figure().subfigure_mosaic(
281+
"A.B;A.C", subfigure_kw={"edgecolor": "black", "linewidth": 2.1}
282+
)
283+
identify_subfigs(subfigs)
284+
285+
# %%
286+
# Per-SubFigure keyword arguments
287+
# ----------------------------------
288+
#
289+
# If you need to control the parameters passed to each subfigure individually use
290+
# *per_subfigure_kw* to pass a mapping between the SubFigure identifiers (or
291+
# tuples of SubFigure identifiers) to dictionaries of keywords to be passed.
292+
#
293+
294+
fig, subfigs = plt.subfigure_mosaic(
295+
"AB;CD",
296+
per_subfigure_kw={
297+
"A": {"facecolor": "green"},
298+
("C", "D"): {"edgecolor": "black", "linewidth": 1.1, }
299+
},
300+
)
301+
identify_subfigs(subfigs)
302+
303+
# %%
304+
# If the layout is specified with the string short-hand, then we know the
305+
# SubFigure labels will be one character and can unambiguously interpret longer
306+
# strings in *per_subfigure_kw* to specify a set of SubFigures to apply the
307+
# keywords to:
308+
309+
fig, subfigs = plt.subfigure_mosaic(
310+
"AB;CD",
311+
per_subfigure_kw={
312+
"AD": {"facecolor": ".3"},
313+
"BC": {"edgecolor": "black", "linewidth": 2.1, }
314+
},
315+
)
316+
identify_subfigs(subfigs)
317+
318+
# %%
319+
# If *subfigure_kw* and *per_subfigure_kw* are used together, then they are
320+
# merged with *per_subfigure_kw* taking priority:
321+
322+
subfigs = plt.figure().subfigure_mosaic(
323+
"AB;CD",
324+
subfigure_kw={"facecolor": "xkcd:tangerine", "linewidth": 2},
325+
per_subfigure_kw={
326+
"B": {"facecolor": "xkcd:water blue"},
327+
"D": {"edgecolor": "yellow", "linewidth": 2.2, "facecolor": "g"},
328+
}
329+
)
330+
identify_subfigs(subfigs)
331+
332+
# %%
333+
# Nested list input
334+
# =================
335+
#
336+
# Everything we can do with the string shorthand we can also do when
337+
# passing in a list (internally we convert the string shorthand to a nested
338+
# list), for example using spans and blanks:
339+
340+
subfigs = plt.figure().subfigure_mosaic(
341+
[
342+
["main", "zoom"],
343+
["main", "BLANK"],
344+
],
345+
empty_sentinel="BLANK",
346+
width_ratios=[2, 1],
347+
subfigure_kw={"facecolor": "xkcd:sea green", "linewidth": 2},
348+
)
349+
identify_subfigs(subfigs)
350+
351+
# %%
352+
# In addition, using the list input we can specify nested mosaics. Any element
353+
# of the inner list can be another set of nested lists:
354+
355+
inner = [
356+
["inner A"],
357+
["inner B"],
358+
]
359+
inner_three = [
360+
["inner Q"],
361+
["inner Z"],
362+
]
363+
inner_two = [
364+
["inner C"],
365+
[inner_three],
366+
]
367+
368+
layout = [["A", [[inner_two, "C"],
369+
["D", "E"]]
370+
],
371+
["F", "G"],
372+
[".", [["H", [["I"],
373+
["."]
374+
]
375+
]
376+
]
377+
]
378+
]
379+
fig, subfigs = plt.subfigure_mosaic(layout, subfigure_kw={'edgecolor': 'black',
380+
'linewidth': 1.5},
381+
per_subfigure_kw={"E": {'edgecolor': 'xkcd:red'},
382+
"G": {'facecolor': 'yellow'},
383+
"H": {'edgecolor': 'blue',
384+
'facecolor': 'xkcd:azure'}}
385+
)
386+
387+
identify_subfigs(subfigs, fontsize=12)
388+
389+
# %%
390+
# We can also pass in a 2D NumPy array to do things like:
391+
mosaic = np.zeros((4, 4), dtype=int)
392+
for j in range(4):
393+
mosaic[j, j] = j + 1
394+
subfigs = plt.figure().subfigure_mosaic(
395+
mosaic,
396+
subfigure_kw={'edgecolor': 'black', 'linewidth': 1.5},
397+
empty_sentinel=0,
398+
)
399+
identify_subfigs(subfigs, fontsize=12)

0 commit comments

Comments
 (0)