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

Skip to content

Commit 6119c12

Browse files
authored
DOC: manually placing images example (#28775)
1 parent ac366ae commit 6119c12

File tree

1 file changed

+165
-0
lines changed

1 file changed

+165
-0
lines changed
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
"""
2+
=========================================
3+
Placing images, preserving relative sizes
4+
=========================================
5+
6+
By default Matplotlib resamples images created with `~.Axes.imshow` to
7+
fit inside the parent `~.axes.Axes`. This can mean that images that have very
8+
different original sizes can end up appearing similar in size.
9+
10+
This example shows how to keep the images the same relative size, or
11+
how to make the images keep exactly the same pixels as the original data.
12+
13+
Preserving relative sizes
14+
=========================
15+
16+
By default the two images are made a similar size, despite one being 1.5 times the width
17+
of the other:
18+
"""
19+
20+
# sphinx_gallery_thumbnail_number = -1
21+
22+
import matplotlib.pyplot as plt
23+
import numpy as np
24+
25+
import matplotlib.patches as mpatches
26+
27+
# make the data:
28+
N = 450
29+
x = np.arange(N) / N
30+
y = np.arange(N) / N
31+
32+
X, Y = np.meshgrid(x, y)
33+
R = np.sqrt(X**2 + Y**2)
34+
f0 = 5
35+
k = 100
36+
a = np.sin(np.pi * 2 * (f0 * R + k * R**2 / 2))
37+
A = a[:100, :300]
38+
B = A[:40, :200]
39+
40+
# default layout: both axes have the same size
41+
fig, axs = plt.subplots(1, 2, facecolor='aliceblue')
42+
43+
axs[0].imshow(A, vmin=-1, vmax=1)
44+
axs[1].imshow(B, vmin=-1, vmax=1)
45+
46+
47+
def annotate_rect(ax):
48+
# add a rectangle that is the size of the B matrix
49+
rect = mpatches.Rectangle((0, 0), 200, 40, linewidth=1,
50+
edgecolor='r', facecolor='none')
51+
ax.add_patch(rect)
52+
return rect
53+
54+
annotate_rect(axs[0])
55+
56+
# %%
57+
# Note that both images have an aspect ratio of 1 (i.e. pixels are square), but
58+
# pixels sizes differ because the images are scaled to the same width.
59+
#
60+
# If the size of the images are amenable, we can preserve the relative sizes of two
61+
# images by using either the *width_ratio* or *height_ratio* of the subplots. Which
62+
# one you use depends on the shape of the image and the size of the figure.
63+
# We can control the relative sizes using the *width_ratios* argument *if* the images
64+
# are wider than they are tall and shown side by side, as is the case here.
65+
#
66+
# While we are making changes, let us also make the aspect ratio of the figure closer
67+
# to the aspect ratio of the axes using *figsize* so that the figure does not have so
68+
# much white space. Note that you could alternatively trim extra blank space when
69+
# saving a figure by passing ``bbox_inches="tight"`` to `~.Figure.savefig`.
70+
71+
fig, axs = plt.subplots(1, 2, width_ratios=[300/200, 1],
72+
figsize=(6.4, 2), facecolor='aliceblue')
73+
74+
axs[0].imshow(A, vmin=-1, vmax=1)
75+
annotate_rect(axs[0])
76+
77+
axs[1].imshow(B, vmin=-1, vmax=1)
78+
# %%
79+
# Given that the data subsample is in the upper left of the larger image,
80+
# it might make sense if the top of the smaller Axes aligned with the top of the larger.
81+
# This can be done manually by using `~.Axes.set_anchor`, and using "NW" (for
82+
# northwest).
83+
84+
fig, axs = plt.subplots(1, 2, width_ratios=[300/200, 1],
85+
figsize=(6.4, 2), facecolor='aliceblue')
86+
87+
axs[0].imshow(A, vmin=-1, vmax=1)
88+
annotate_rect(axs[0])
89+
90+
axs[0].set_anchor('NW')
91+
axs[1].imshow(B, vmin=-1, vmax=1)
92+
axs[1].set_anchor('NW')
93+
94+
# %%
95+
# Explicit placement
96+
# ==================
97+
# The above approach with adjusting ``figsize`` and ``width_ratios`` does
98+
# not generalize well, because it needs manual parameter tuning, and
99+
# possibly even code changes to using ``height_ratios`` instead of
100+
# ``width_ratios`` depending on the aspects and layout of the images.
101+
#
102+
# We can alternative calculate positions explicitly and place Axes at absolute
103+
# coordinates using `~.Figure.add_axes`. This takes the position in the form
104+
# ``[left bottom width height]`` and is in
105+
# :ref:`figure coordinates <transforms_tutorial>`. In the following, we
106+
# determine figure size and Axes positions so that one image data point
107+
# is rendered exactly to one figure pixel.
108+
109+
dpi = 100 # 100 pixels is one inch
110+
111+
# All variables from here are in pixels:
112+
buffer = 0.35 * dpi # pixels
113+
114+
# Get the position of A axes
115+
left = buffer
116+
bottom = buffer
117+
ny, nx = np.shape(A)
118+
posA = [left, bottom, nx, ny]
119+
# we know this is tallest, so we can already get the fig height (in pixels)
120+
fig_height = bottom + ny + buffer
121+
122+
# place the B axes to the right of the A axes
123+
left = left + nx + buffer
124+
125+
ny, nx = np.shape(B)
126+
# align the bottom so that the top lines up with the top of the A axes:
127+
bottom = fig_height - buffer - ny
128+
posB = [left, bottom, nx, ny]
129+
130+
# now we can get the fig width (in pixels)
131+
fig_width = left + nx + buffer
132+
133+
# figsize must be in inches:
134+
fig = plt.figure(figsize=(fig_width / dpi, fig_height / dpi), facecolor='aliceblue')
135+
136+
# the position posA must be normalized by the figure width and height:
137+
ax = fig.add_axes([posA[0] / fig_width, posA[1] / fig_height,
138+
posA[2] / fig_width, posA[3] / fig_height])
139+
ax.imshow(A, vmin=-1, vmax=1)
140+
annotate_rect(ax)
141+
142+
ax = fig.add_axes([posB[0] / fig_width, posB[1] / fig_height,
143+
posB[2] / fig_width, posB[3] / fig_height])
144+
ax.imshow(B, vmin=-1, vmax=1)
145+
plt.show()
146+
# %%
147+
# Inspection of the image will show that it is exactly 3* 35 + 300 + 200 = 605
148+
# pixels wide, and 2 * 35 + 100 = 170 pixels high (or twice that if the 2x
149+
# version is used by the browser instead). The images should be rendered with
150+
# exactly 1 pixel per data point (or four, if 2x).
151+
#
152+
# .. admonition:: References
153+
#
154+
# The use of the following functions, methods, classes and modules is shown
155+
# in this example:
156+
#
157+
# - `matplotlib.axes.Axes.imshow`
158+
# - `matplotlib.figure.Figure.add_axes`
159+
#
160+
# .. tags::
161+
#
162+
# component: figure
163+
# component: axes
164+
# styling: position
165+
# plot-type: image

0 commit comments

Comments
 (0)