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

Commitf4ac6fb

Browse files
jklymakMeeseeksDev[bot]
authored and
MeeseeksDev[bot]
committed
Backport PR#10947: DOC: add tutorial explaining imshow *origin* and *extent*
1 parentaaf7177 commitf4ac6fb

File tree

2 files changed

+266
-1
lines changed

2 files changed

+266
-1
lines changed

‎doc/_static/mpl.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ div.deprecated span.versionmodified {
416416
font-weight: bold;
417417
}
418418

419-
div.green {
419+
div.green,div.hint {
420420
color:#468847;
421421
background-color:#dff0d8;
422422
border:1px solid#d6e9c6;
Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
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+
.. hint:: Most of the code below is used for adding labels and informative
19+
text to the plots. The described effects of *origin* and *extent* can be
20+
seen in the plots without the need to follow all code details.
21+
22+
For a quick understanding, you may want to skip the code details below and
23+
directly continue with the discussion of the results.
24+
"""
25+
importnumpyasnp
26+
importmatplotlib.pyplotasplt
27+
frommatplotlib.gridspecimportGridSpec
28+
29+
30+
defindex_to_coordinate(index,extent,origin):
31+
"""Return the pixel center of an index."""
32+
left,right,bottom,top=extent
33+
34+
hshift=0.5*np.sign(right-left)
35+
left,right=left+hshift,right-hshift
36+
vshift=0.5*np.sign(top-bottom)
37+
bottom,top=bottom+vshift,top-vshift
38+
39+
iforigin=='upper':
40+
bottom,top=top,bottom
41+
42+
return {
43+
"[0, 0]": (left,bottom),
44+
"[M', 0]": (left,top),
45+
"[0, N']": (right,bottom),
46+
"[M', N']": (right,top),
47+
}[index]
48+
49+
50+
defget_index_label_pos(index,extent,origin,inverted_xindex):
51+
"""
52+
Return the desired position and horizontal alignment of an index label.
53+
"""
54+
ifextentisNone:
55+
extent=lookup_extent(origin)
56+
left,right,bottom,top=extent
57+
x,y=index_to_coordinate(index,extent,origin)
58+
59+
is_x0=index[-2:]=="0]"
60+
halign='left'ifis_x0^inverted_xindexelse'right'
61+
hshift=0.5*np.sign(left-right)
62+
x+=hshift* (1ifis_x0else-1)
63+
returnx,y,halign
64+
65+
66+
defget_color(index,data,cmap):
67+
"""Return the data color of an index."""
68+
val= {
69+
"[0, 0]":data[0,0],
70+
"[0, N']":data[0,-1],
71+
"[M', 0]":data[-1,0],
72+
"[M', N']":data[-1,-1],
73+
}[index]
74+
returncmap(val/data.max())
75+
76+
77+
deflookup_extent(origin):
78+
"""Return extent for label positioning when not given explicitly."""
79+
iforigin=='lower':
80+
return (-0.5,6.5,-0.5,5.5)
81+
else:
82+
return (-0.5,6.5,5.5,-0.5)
83+
84+
85+
defset_extent_None_text(ax):
86+
ax.text(3,2.5,'equals\nextent=None',size='large',
87+
ha='center',va='center',color='w')
88+
89+
90+
defplot_imshow_with_labels(ax,data,extent,origin,xlim,ylim):
91+
"""Actually run ``imshow()`` and add extent and index labels."""
92+
im=ax.imshow(data,origin=origin,extent=extent)
93+
94+
# extent labels (left, right, bottom, top)
95+
left,right,bottom,top=im.get_extent()
96+
ifxlimisNoneortop>bottom:
97+
upper_string,lower_string='top','bottom'
98+
else:
99+
upper_string,lower_string='bottom','top'
100+
ifylimisNoneorleft<right:
101+
port_string,starboard_string='left','right'
102+
inverted_xindex=False
103+
else:
104+
port_string,starboard_string='right','left'
105+
inverted_xindex=True
106+
bbox_kwargs= {'fc':'w','alpha':.75,'boxstyle':"round4"}
107+
ann_kwargs= {'xycoords':'axes fraction',
108+
'textcoords':'offset points',
109+
'bbox':bbox_kwargs}
110+
ax.annotate(upper_string,xy=(.5,1),xytext=(0,-1),
111+
ha='center',va='top',**ann_kwargs)
112+
ax.annotate(lower_string,xy=(.5,0),xytext=(0,1),
113+
ha='center',va='bottom',**ann_kwargs)
114+
ax.annotate(port_string,xy=(0,.5),xytext=(1,0),
115+
ha='left',va='center',rotation=90,
116+
**ann_kwargs)
117+
ax.annotate(starboard_string,xy=(1,.5),xytext=(-1,0),
118+
ha='right',va='center',rotation=-90,
119+
**ann_kwargs)
120+
ax.set_title('origin: {origin}'.format(origin=origin))
121+
122+
# index labels
123+
forindexin ["[0, 0]","[0, N']","[M', 0]","[M', N']"]:
124+
tx,ty,halign=get_index_label_pos(index,extent,origin,
125+
inverted_xindex)
126+
facecolor=get_color(index,data,im.get_cmap())
127+
ax.text(tx,ty,index,color='white',ha=halign,va='center',
128+
bbox={'boxstyle':'square','facecolor':facecolor})
129+
ifxlim:
130+
ax.set_xlim(*xlim)
131+
ifylim:
132+
ax.set_ylim(*ylim)
133+
134+
135+
defgenerate_imshow_demo_grid(extents,xlim=None,ylim=None):
136+
N=len(extents)
137+
fig=plt.figure(tight_layout=True)
138+
fig.set_size_inches(6,N* (11.25)/5)
139+
gs=GridSpec(N,5,figure=fig)
140+
141+
columns= {'label': [fig.add_subplot(gs[j,0])forjinrange(N)],
142+
'upper': [fig.add_subplot(gs[j,1:3])forjinrange(N)],
143+
'lower': [fig.add_subplot(gs[j,3:5])forjinrange(N)]}
144+
x,y=np.ogrid[0:6,0:7]
145+
data=x+y
146+
147+
fororiginin ['upper','lower']:
148+
forax,extentinzip(columns[origin],extents):
149+
plot_imshow_with_labels(ax,data,extent,origin,xlim,ylim)
150+
151+
forax,extentinzip(columns['label'],extents):
152+
text_kwargs= {'ha':'right',
153+
'va':'center',
154+
'xycoords':'axes fraction',
155+
'xy': (1,.5)}
156+
ifextentisNone:
157+
ax.annotate('None',**text_kwargs)
158+
ax.set_title('extent=')
159+
else:
160+
left,right,bottom,top=extent
161+
text= ('left: {left:0.1f}\nright: {right:0.1f}\n'+
162+
'bottom: {bottom:0.1f}\ntop: {top:0.1f}\n').format(
163+
left=left,right=right,bottom=bottom,top=top)
164+
165+
ax.annotate(text,**text_kwargs)
166+
ax.axis('off')
167+
returncolumns
168+
169+
170+
###############################################################################
171+
#
172+
# Default extent
173+
# --------------
174+
#
175+
# First, let's have a look at the default `extent=None`
176+
177+
generate_imshow_demo_grid(extents=[None])
178+
179+
###############################################################################
180+
#
181+
# Generally, for an array of shape (M, N), the first index runs along the
182+
# vertical, the second index runs along the horizontal.
183+
# The pixel centers are at integer positions ranging from 0 to ``N' = N - 1``
184+
# horizontally and from 0 to ``M' = M - 1`` vertically.
185+
# *origin* determines how to the data is filled in the bounding box.
186+
#
187+
# For ``origin='lower'``:
188+
#
189+
# - [0, 0] is at (left, bottom)
190+
# - [M', 0] is at (left, top)
191+
# - [0, N'] is at (right, bottom)
192+
# - [M', N'] is at (right, top)
193+
#
194+
# ``origin='upper'`` reverses the vertical axes direction and filling:
195+
#
196+
# - [0, 0] is at (left, top)
197+
# - [M', 0] is at (left, bottom)
198+
# - [0, N'] is at (right, top)
199+
# - [M', N'] is at (right, bottom)
200+
#
201+
# In summary, the position of the [0, 0] index as well as the extent are
202+
# influenced by *origin*:
203+
#
204+
# ====== =============== ==========================================
205+
# origin [0, 0] position extent
206+
# ====== =============== ==========================================
207+
# upper top left ``(-0.5, numcols-0.5, numrows-0.5, -0.5)``
208+
# lower bottom left ``(-0.5, numcols-0.5, -0.5, numrows-0.5)``
209+
# ====== =============== ==========================================
210+
#
211+
# The default value of *origin* is set by :rc:`image.origin` which defaults
212+
# to ``'upper'`` to match the matrix indexing conventions in math and
213+
# computer graphics image indexing conventions.
214+
#
215+
#
216+
# Explicit extent
217+
# ---------------
218+
#
219+
# By setting *extent* we define the coordinates of the image area. The
220+
# underlying image data is interpolated/resampled to fill that area.
221+
#
222+
# If the axes is set to autoscale, then the view limits of the axes are set
223+
# to match the *extent* which ensures that the coordinate set by
224+
# ``(left, bottom)`` is at the bottom left of the axes! However, this
225+
# may invert the axis so they do not increase in the 'natural' direction.
226+
#
227+
228+
extents= [(-0.5,6.5,-0.5,5.5),
229+
(-0.5,6.5,5.5,-0.5),
230+
(6.5,-0.5,-0.5,5.5),
231+
(6.5,-0.5,5.5,-0.5)]
232+
233+
columns=generate_imshow_demo_grid(extents)
234+
set_extent_None_text(columns['upper'][1])
235+
set_extent_None_text(columns['lower'][0])
236+
237+
238+
###############################################################################
239+
#
240+
# Explicit extent and axes limits
241+
# -------------------------------
242+
#
243+
# If we fix the axes limits by explicity setting `set_xlim` / `set_ylim`, we
244+
# force a certain size and orientation of the axes.
245+
# This can decouple the 'left-right' and 'top-bottom' sense of the image from
246+
# the orientation on the screen.
247+
#
248+
# In the example below we have chosen the limits slightly larger than the
249+
# extent (note the white areas within the Axes).
250+
#
251+
# While we keep the extents as in the examples before, the coordinate (0, 0)
252+
# is now explicitly put at the bottom left and values increase to up and to
253+
# the right (from the viewer point of view).
254+
# We can see that:
255+
#
256+
# - The coordinate ``(left, bottom)`` anchors the image which then fills the
257+
# box going towards the ``(right, top)`` point in data space.
258+
# - The first column is always closest to the 'left'.
259+
# - *origin* controls if the first row is closest to 'top' or 'bottom'.
260+
# - The image may be inverted along either direction.
261+
# - The 'left-right' and 'top-bottom' sense of the image may be uncoupled from
262+
# the orientation on the screen.
263+
264+
generate_imshow_demo_grid(extents=[None]+extents,
265+
xlim=(-2,8),ylim=(-1,6))

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp