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

Skip to content

Commit 6e5e401

Browse files
committed
DOC: manually placing images example
1 parent 3a0bc88 commit 6e5e401

File tree

1 file changed

+127
-0
lines changed

1 file changed

+127
-0
lines changed
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
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 mages 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+
We can preserve the relative sizes of two images by using either the `width_ratio` or
19+
`height_ratio` of the subplots. Which one you use depends on the shape of the image and
20+
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 in a
82+
# final product by ``bbox_inches="tight"`), and is not very general. For instance, if
83+
# the axes had been arrayed vertically instead of horizontally, setting the height
84+
# aspect ratio would not have helped because the axes are wider than they are tall.
85+
# For more complicated situations it is necessary to place the axes manually.
86+
#
87+
# Manual placement
88+
# ================
89+
#
90+
# We can manually place axes when they are created by passing a position to
91+
# `~.Figure.add_axes`. This position takes the form ``[left bottom width height]`` and
92+
# is in units that are a fraction of the figure width and height. Here we decide how
93+
# large to make the axes based on the size of the images, and add a small buffer of
94+
# 0.35 inches. We do all this at 100 dpi.
95+
96+
dpi = 100 # 100 pixels is one inch
97+
buffer = 0.35 * dpi # inches
98+
left = buffer
99+
bottom = buffer
100+
ny, nx = np.shape(A)
101+
posA = [left, bottom, nx, ny]
102+
# we know this is tallest, so we can get the fig height:
103+
figh = bottom + ny + buffer
104+
105+
# place the B axes
106+
left = left + nx + buffer
107+
ny, nx = np.shape(B)
108+
posB = [left, figh - buffer - ny, nx, ny]
109+
110+
# get the fig width
111+
figw = left + nx + buffer
112+
113+
fig = plt.figure(figsize=(figw / dpi, figh / dpi), facecolor='aliceblue')
114+
115+
ax = fig.add_axes([posA[0] / figw, posA[1] / figh, posA[2] / figw, posA[3] / figh])
116+
ax.imshow(A, vmin=-1, vmax=1)
117+
rect = mpatches.Rectangle((0, 0), 200, 40, linewidth=1, edgecolor='r', facecolor='none')
118+
ax.add_patch(rect)
119+
120+
ax = fig.add_axes([posB[0] / figw, posB[1] / figh, posB[2] / figw, posB[3] / figh])
121+
ax.imshow(B, vmin=-1, vmax=1)
122+
123+
# %%
124+
# Inspection of the image will show that it is exactly 3* 35 + 300 + 200 = 605 pixels
125+
# wide, and 2 * 35 + 100 = 170 pixels high (or twice that if the 2x version is
126+
# used instead). The images should be rendered with exactly 1 pixel per data point
127+
# (or two, if 2x).

0 commit comments

Comments
 (0)