Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit519c1dc

Browse files
committed
DOC: add tutorial explaining imshow *origin* and *extent*
1 parentd9b5b4e commit519c1dc

File tree

1 file changed

+179
-0
lines changed

1 file changed

+179
-0
lines changed
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
"""
2+
*origin* and *extent* in `~.Axes.imshow`
3+
========================================
4+
5+
:meth:`~.Axes.imshow` allows you to render an image (either a 2D array
6+
which will be color-mapped (based on *norm* and *cmap*) or and 3D RGB(A)
7+
array which will be used as-is) to a rectangular region in dataspace.
8+
The orientation of the image in the final rendering is controlled by
9+
the *origin* and *extent* kwargs (and attributes on the resulting
10+
`~.AxesImage` instance) and the data limits of the axes.
11+
12+
The *extent* kwarg controls the bounding box in data coordinates that
13+
the image will fill specified as ``(left, right, bottom, top)`` in
14+
**data coordinates**, the *origin* kwarg controls how the image fills
15+
that bounding box, and the orientation in the final rendered image is
16+
also affected by the axes limits.
17+
"""
18+
importnumpyasnp
19+
importmatplotlib.pyplotasplt
20+
frommatplotlib.gridspecimportGridSpec
21+
22+
23+
defgenerate_imshow_demo_grid(auto_limits,extents):
24+
N=len(extents)
25+
fig=plt.figure(tight_layout=True)
26+
fig.set_size_inches(6,N* (11.25)/5)
27+
gs=GridSpec(N,5,figure=fig)
28+
29+
columns= {'label': [fig.add_subplot(gs[j,0])forjinrange(N)],
30+
'upper': [fig.add_subplot(gs[j,1:3])forjinrange(N)],
31+
'lower': [fig.add_subplot(gs[j,3:5])forjinrange(N)]}
32+
33+
d=np.arange(42).reshape(6,7)
34+
35+
fororiginin ['upper','lower']:
36+
forax,extentinzip(columns[origin],extents):
37+
38+
im=ax.imshow(d,origin=origin,extent=extent)
39+
left,right,bottom,top=im.get_extent()
40+
arrow_style= {'arrowprops': {'arrowstyle':'-|>',
41+
'shrinkA':0,
42+
'color':'0.5',
43+
'linewidth':3}}
44+
ax.annotate('',
45+
(left,bottom+2*np.sign(top-bottom)),
46+
(left,bottom),
47+
**arrow_style)
48+
ax.annotate('',
49+
(left+2*np.sign(right-left),bottom),
50+
(left,bottom),
51+
**arrow_style)
52+
53+
ifauto_limitsortop>bottom:
54+
upper_string,lower_string='top','bottom'
55+
else:
56+
upper_string,lower_string='bottom','top'
57+
58+
ifauto_limitsorleft<right:
59+
port_string,starboard_string='left','right'
60+
else:
61+
port_string,starboard_string='right','left'
62+
63+
bbox_kwargs= {'fc':'w','alpha':.75,'boxstyle':"round4"}
64+
ann_kwargs= {'xycoords':'axes fraction',
65+
'textcoords':'offset points',
66+
'bbox':bbox_kwargs}
67+
68+
ax.annotate(upper_string,xy=(.5,1),xytext=(0,-1),
69+
ha='center',va='top',**ann_kwargs)
70+
ax.annotate(lower_string,xy=(.5,0),xytext=(0,1),
71+
ha='center',va='bottom',**ann_kwargs)
72+
73+
ax.annotate(port_string,xy=(0,.5),xytext=(1,0),
74+
ha='left',va='center',rotation=90,
75+
**ann_kwargs)
76+
ax.annotate(starboard_string,xy=(1,.5),xytext=(-1,0),
77+
ha='right',va='center',rotation=-90,
78+
**ann_kwargs)
79+
80+
ax.set_title(f'origin:{origin}')
81+
82+
ifnotauto_limits:
83+
ax.set_xlim(-1,7)
84+
ax.set_ylim(-1,6)
85+
86+
forax,extentinzip(columns['label'],extents):
87+
text_kwargs= {'ha':'right',
88+
'va':'center',
89+
'xycoords':'axes fraction',
90+
'xy': (1,.5)}
91+
ifextentisNone:
92+
ax.annotate('None',**text_kwargs)
93+
ax.set_title('`extent=`')
94+
else:
95+
left,right,bottom,top=extent
96+
text= ('left: {left:0.1f}\nright: {right:0.1f}\n'+
97+
'bottom: {bottom:0.1f}\ntop: {top:0.1f}\n').format(
98+
left=left,right=right,bottom=bottom,top=top)
99+
100+
ax.annotate(text,**text_kwargs)
101+
ax.axis('off')
102+
103+
104+
extents= (None,
105+
(-0.5,6.5,-0.5,5.5),
106+
(-0.5,6.5,5.5,-0.5),
107+
(6.5,-0.5,-0.5,5.5),
108+
(6.5,-0.5,5.5,-0.5))
109+
110+
###############################################################################
111+
#
112+
#
113+
# First, using *extent* we pick a bounding box in dataspace that the
114+
# image will fill and then interpolate/resample the underlying data to
115+
# fill that box.
116+
#
117+
# - If ``origin='lower'`` than the ``[0, 0]`` entry is closest to the
118+
# ``(left, bottom)`` corner of the bounding box and moving closer to
119+
# ``(left, top)`` moves along the ``[:, 0]`` axis of the array to
120+
# higher indexed rows and moving towards ``(right, bottom)`` moves you
121+
# along the ``[0, :]`` axis of the array to higher indexed columns
122+
#
123+
# - If ``origin='upper'`` then the ``[-1, 0]`` entry is closest to the
124+
# ``(left, bottom)`` corner of the bounding box and moving towards
125+
# ``(left, top)`` moves along the ``[:, 0]`` axis of the array to
126+
# lower index rows and moving towards ``(right, bottom)`` moves you
127+
# along the ``[-1, :]`` axis of the array to higher indexed columns
128+
#
129+
# To demonstrate this we will plot a linear ramp
130+
# ``np.arange(42).reshape(6, 7)`` with varying parameters.
131+
#
132+
133+
generate_imshow_demo_grid(True,extents[:1])
134+
135+
###############################################################################
136+
#
137+
# If we only specify *origin* we can see why it is so named. For
138+
# ``origin='upper'`` the ``[0, 0]`` pixel is on the upper left and for
139+
# ``origin='lower'`` the ``[0, 0]`` pixel is in the lower left [#]_.
140+
# The gray arrows are attached to the ``(left, bottom)`` corner of the
141+
# image. There are two tricky things going on here: first the default
142+
# value of *extent* depends on the value of *origin* and second the x
143+
# and y limits are adjusted to match the extent. The default *extent*
144+
# is ``(-0.5, numcols-0.5, numrows-0.5, -0.5)`` when ``origin ==
145+
# 'upper'`` and ``(-0.5, numcols-0.5, -0.5, numrows-0.5)`` when ``origin
146+
# == 'lower'`` which puts the pixel centers on integer positions and the
147+
# ``[0, 0]`` pixel at ``(0, 0)`` in dataspace.
148+
#
149+
#
150+
# .. [#] The default value of *origin* is set by :rc:`image.origin`
151+
# which defaults to ``'upper'`` to match the matrix indexing
152+
# conventions in math and computer graphics image indexing
153+
# conventions.
154+
155+
generate_imshow_demo_grid(True,extents[1:])
156+
157+
###############################################################################
158+
#
159+
# If the axes is set to autoscale, then view limits of the axes are set
160+
# to match the *extent* which ensures that the coordinate set by
161+
# ``(left, bottom)`` is at the bottom left of the axes! However, this
162+
# may invert the axis so they do not increase in the 'natural' direction.
163+
#
164+
165+
generate_imshow_demo_grid(False,extents)
166+
167+
###############################################################################
168+
#
169+
# If we fix the axes limits so ``(0, 0)`` is at the bottom left and
170+
# increases to up and to the right (from the viewer point of view) then
171+
# we can see that:
172+
#
173+
# - The ``(left, bottom)`` anchors the image which then fills the
174+
# box going towards the ``(right, top)`` point in data space.
175+
# - The first column is always closest to the 'left'.
176+
# - *origin* controls if the first row is closest to 'top' or 'bottom'.
177+
# - The image may be inverted along either direction.
178+
# - The 'left-right' and 'top-bottom' sense of the image is uncoupled from
179+
# the orientation on the screen.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp