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

Skip to content

Commit 141f811

Browse files
committed
DOC: manually placing images example
1 parent 3a0bc88 commit 141f811

File tree

1 file changed

+128
-0
lines changed

1 file changed

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

0 commit comments

Comments
 (0)