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

Skip to content

Commit 94da849

Browse files
committed
DOC: manually placing images example
1 parent 3a0bc88 commit 94da849

File tree

1 file changed

+131
-0
lines changed

1 file changed

+131
-0
lines changed
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
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+
Sometimes, however, it is desirable to keep the images the same relative size, or
11+
even to make the images keep exactly the same pixels as the original data.
12+
Matplotlib does not automatically make either of these things happen,
13+
but it is possible with some manual manipulation.
14+
15+
Preserving relative sizes
16+
=========================
17+
18+
If the size of the images are amenable, we can preserve the relative sizes of two
19+
images by using either the *width_ratio* or *height_ratio* of the subplots. Which
20+
one you use depends on the shape of the image and the size of the figure.
21+
22+
By default the two images are made a similar size, despite one being 1.5 times the width
23+
of the other:
24+
"""
25+
26+
# sphinx_gallery_thumbnail_number = -1
27+
28+
import matplotlib.pyplot as plt
29+
import numpy as np
30+
31+
import matplotlib.patches as mpatches
32+
33+
# make the data:
34+
N = 450
35+
x = np.arange(N) / N
36+
y = np.arange(N) / N
37+
38+
X, Y = np.meshgrid(x, y)
39+
R = np.sqrt(X**2 + Y**2)
40+
f0 = 5
41+
k = 100
42+
a = np.sin(np.pi * 2 * (f0 * R + k * R**2 / 2))
43+
A = a[:100, :300]
44+
B = A[:40, :200]
45+
46+
# plot with default axes handling:
47+
fig, axs = plt.subplots(1, 2, facecolor='aliceblue')
48+
49+
axs[0].imshow(A, vmin=-1, vmax=1)
50+
axs[1].imshow(B, vmin=-1, vmax=1)
51+
rect = mpatches.Rectangle((0, 0), 200, 40, linewidth=1, edgecolor='r', facecolor='none')
52+
axs[0].add_patch(rect)
53+
54+
# %%
55+
# Note that both images are rendered at a 1:1 ratio, but are made to look almost the
56+
# same width, despite image B being smaller than image A.
57+
#
58+
# We can control the relative sizes using the *width_ratios* argument *if* the images
59+
# are wider than they are tall and shown side by side, as is the case here.
60+
61+
fig, axs = plt.subplots(1, 2, width_ratios=[300/200, 1], facecolor='aliceblue')
62+
63+
axs[0].imshow(A, vmin=-1, vmax=1)
64+
rect = mpatches.Rectangle((0, 0), 200, 40, linewidth=1, edgecolor='r', facecolor='none')
65+
axs[0].add_patch(rect)
66+
axs[1].imshow(B, vmin=-1, vmax=1)
67+
68+
# %%
69+
# Given that the data subsample is in the upper left of the larger image,
70+
# it might make sense if the top of the smaller Axes aligned with the top of the larger.
71+
# This can be done manually by using `~.Axes.set_anchor`, and using "NW" (for
72+
# northwest).
73+
74+
fig, axs = plt.subplots(1, 2, width_ratios=[300/200, 1], facecolor='aliceblue')
75+
76+
axs[0].imshow(A, vmin=-1, vmax=1)
77+
rect = mpatches.Rectangle((0, 0), 200, 40, linewidth=1, edgecolor='r', facecolor='none')
78+
axs[0].add_patch(rect)
79+
axs[0].set_anchor('NW')
80+
axs[1].imshow(B, vmin=-1, vmax=1)
81+
axs[1].set_anchor('NW')
82+
83+
# %%
84+
# Note that this procedure still leaves large white spaces (that can be trimmed
85+
# in a final product by ``bbox_inches="tight"`` in `~.Figure.savefig`), and is
86+
# not very general. For instance, if the axes had been arranged vertically
87+
# instead of horizontally, setting the height aspect ratio would not have
88+
# helped because the axes are wider than they are tall. For more complicated
89+
# situations it is necessary to place the axes manually.
90+
#
91+
# Manual placement
92+
# ================
93+
#
94+
# We can manually place axes when they are created by passing a position to
95+
# `~.Figure.add_axes`. This position takes the form ``[left bottom width height]`` and
96+
# is in units that are a fraction of the figure width and height. Here we decide how
97+
# large to make the axes based on the size of the images, and add a small buffer of
98+
# 0.35 inches. We do all this at 100 dpi.
99+
100+
dpi = 100 # 100 pixels is one inch
101+
buffer = 0.35 * dpi # pixels
102+
left = buffer
103+
bottom = buffer
104+
ny, nx = np.shape(A)
105+
posA = [left, bottom, nx, ny]
106+
# we know this is tallest, so we can get the fig height:
107+
figh = bottom + ny + buffer
108+
109+
# place the B axes
110+
left = left + nx + buffer
111+
ny, nx = np.shape(B)
112+
posB = [left, figh - buffer - ny, nx, ny]
113+
114+
# get the fig width
115+
figw = left + nx + buffer
116+
117+
fig = plt.figure(figsize=(figw / dpi, figh / dpi), facecolor='aliceblue')
118+
119+
ax = fig.add_axes([posA[0] / figw, posA[1] / figh, posA[2] / figw, posA[3] / figh])
120+
ax.imshow(A, vmin=-1, vmax=1)
121+
rect = mpatches.Rectangle((0, 0), 200, 40, linewidth=1, edgecolor='r', facecolor='none')
122+
ax.add_patch(rect)
123+
124+
ax = fig.add_axes([posB[0] / figw, posB[1] / figh, posB[2] / figw, posB[3] / figh])
125+
ax.imshow(B, vmin=-1, vmax=1)
126+
127+
# %%
128+
# Inspection of the image will show that it is exactly 3* 35 + 300 + 200 = 605
129+
# pixels wide, and 2 * 35 + 100 = 170 pixels high (or twice that if the 2x
130+
# version is used by the browser instead). The images should be rendered with
131+
# exactly 1 pixel per data point (or four, if 2x).

0 commit comments

Comments
 (0)