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

Skip to content

Commit ea6cad9

Browse files
committed
DOC: manually placing images example
1 parent d8ff960 commit ea6cad9

File tree

1 file changed

+163
-0
lines changed

1 file changed

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

0 commit comments

Comments
 (0)