Skip to content

Commit f1b481b

Browse files
committed
DOC: Rewrite parts of imshow origin/extent handling
1 parent 285c8d2 commit f1b481b

File tree

1 file changed

+74
-50
lines changed

1 file changed

+74
-50
lines changed

tutorials/intermediate/imshow_extent.py

+74-50
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
**data coordinates**, the *origin* kwarg controls how the image fills
1515
that bounding box, and the orientation in the final rendered image is
1616
also affected by the axes limits.
17+
18+
.. hint:: For the moment, you may want to skip the code details below and
19+
directly continue with the discussion of the results.
1720
"""
1821
import numpy as np
1922
import matplotlib.pyplot as plt
@@ -80,7 +83,7 @@ def set_extent_None_text(ax):
8083
ha='center', va='center', color='w')
8184

8285

83-
def generate_imshow_demo_grid(extents, auto_limits):
86+
def generate_imshow_demo_grid(extents, xlim=None, ylim=None):
8487
N = len(extents)
8588
fig = plt.figure(tight_layout=True)
8689
fig.set_size_inches(6, N * (11.25) / 5)
@@ -98,12 +101,12 @@ def generate_imshow_demo_grid(extents, auto_limits):
98101
im = ax.imshow(d, origin=origin, extent=extent)
99102
left, right, bottom, top = im.get_extent()
100103

101-
if auto_limits or top > bottom:
104+
if xlim is None or top > bottom:
102105
upper_string, lower_string = 'top', 'bottom'
103106
else:
104107
upper_string, lower_string = 'bottom', 'top'
105108

106-
if auto_limits or left < right:
109+
if ylim is None or left < right:
107110
port_string, starboard_string = 'left', 'right'
108111
inverted_xindex = False
109112
else:
@@ -135,9 +138,10 @@ def generate_imshow_demo_grid(extents, auto_limits):
135138
ax.text(tx, ty, index, color='white', ha=halign, va='center',
136139
bbox={'boxstyle': 'square', 'facecolor': facecolor})
137140

138-
if not auto_limits:
139-
ax.set_xlim(-1, 7)
140-
ax.set_ylim(-1, 6)
141+
if xlim:
142+
ax.set_xlim(*xlim)
143+
if ylim:
144+
ax.set_ylim(*ylim)
141145

142146
for ax, extent in zip(columns['label'], extents):
143147
text_kwargs = {'ha': 'right',
@@ -158,71 +162,92 @@ def generate_imshow_demo_grid(extents, auto_limits):
158162
return columns
159163

160164

161-
extents = (None,
162-
(-0.5, 6.5, -0.5, 5.5),
163-
(-0.5, 6.5, 5.5, -0.5),
164-
(6.5, -0.5, -0.5, 5.5),
165-
(6.5, -0.5, 5.5, -0.5))
166165

166+
###############################################################################
167+
#
168+
# Default extent
169+
# --------------
170+
#
171+
# First, let's have a look at the default `extent=None`
167172

173+
generate_imshow_demo_grid(extents=[None])
168174

169175
###############################################################################
170176
#
177+
# Generally, for an array of shape (N, M), the first index runs along the
178+
# vertical, the second index runs along the horizontal.
179+
# The pixel centers are at integer positions ranging from 0 to `N' = N - 1``
180+
# vertically and from 0 to ``M' = M - 1`` horizontally.
181+
# *origin* determines how to the data is filled in the bounding box.
171182
#
172-
# First, using *extent* we pick a bounding box in dataspace that the
173-
# image will fill and then interpolate/resample the underlying data to
174-
# fill that box.
183+
# For ``origin='lower'``:
175184
#
176-
# - If ``origin='lower'`` than the ``[0, 0]`` entry is closest to the
177-
# ``(left, bottom)`` corner of the bounding box and moving closer to
178-
# ``(left, top)`` moves along the ``[:, 0]`` axis of the array to
179-
# higher indexed rows and moving towards ``(right, bottom)`` moves you
180-
# along the ``[0, :]`` axis of the array to higher indexed columns
185+
# - [0, 0] is at (left, bottom)
186+
# - [N', 0] is at (left, top)
187+
# - [0, M'] is at (right, bottom)
188+
# - [N', M'] is at (right, top)
181189
#
182-
# - If ``origin='upper'`` then the ``[-1, 0]`` entry is closest to the
183-
# ``(left, bottom)`` corner of the bounding box and moving towards
184-
# ``(left, top)`` moves along the ``[:, 0]`` axis of the array to
185-
# lower index rows and moving towards ``(right, bottom)`` moves you
186-
# along the ``[-1, :]`` axis of the array to higher indexed columns
187-
188-
generate_imshow_demo_grid(extents[:1], auto_limits=True)
189-
190-
###############################################################################
190+
# ``origin='upper'`` reverses the vertical axes direction and filling:
191+
#
192+
# - [0, 0] is at (left, top)
193+
# - [N', 0] is at (left, bottom)
194+
# - [0, M'] is at (right, top)
195+
# - [N', M'] is at (right, bottom)
191196
#
192-
# If we only specify *origin* we can see why it is so named. For
193-
# ``origin='upper'`` the ``[0, 0]`` pixel is on the upper left and for
194-
# ``origin='lower'`` the ``[0, 0]`` pixel is in the lower left [#]_.
195-
# The gray arrows are attached to the ``(left, bottom)`` corner of the
196-
# image. There are two tricky things going on here: first the default
197-
# value of *extent* depends on the value of *origin* and second the x
198-
# and y limits are adjusted to match the extent. The default *extent*
199-
# is ``(-0.5, numcols-0.5, numrows-0.5, -0.5)`` when ``origin ==
200-
# 'upper'`` and ``(-0.5, numcols-0.5, -0.5, numrows-0.5)`` when ``origin
201-
# == 'lower'`` which puts the pixel centers on integer positions and the
202-
# ``[0, 0]`` pixel at ``(0, 0)`` in dataspace.
197+
# In summary, the position of the [0, 0] index as well as the extent are
198+
# influenced by *origin*:
203199
#
200+
# ====== =============== ==========================================
201+
# origin [0, 0] position extent
202+
# ====== =============== ==========================================
203+
# upper top left ``(-0.5, numcols-0.5, numrows-0.5, -0.5)``
204+
# lower bottom left ``(-0.5, numcols-0.5, -0.5, numrows-0.5)``
205+
# ====== =============== ==========================================
204206
#
205-
# .. [#] The default value of *origin* is set by :rc:`image.origin`
206-
# which defaults to ``'upper'`` to match the matrix indexing
207-
# conventions in math and computer graphics image indexing
208-
# conventions.
207+
# The default value of *origin* is set by :rc:`image.origin` which defaults
208+
# to ``'upper'`` to match the matrix indexing conventions in math and
209+
# computer graphics image indexing conventions.
210+
#
211+
#
212+
# Explicit extent
213+
# ---------------
214+
#
215+
# By setting *extent* we pick a bounding box in dataspace that the image will
216+
# fill. Then, the underlying data is interpolated/resampled to fill that box.
209217
#
210218
# If the axes is set to autoscale, then view limits of the axes are set
211219
# to match the *extent* which ensures that the coordinate set by
212220
# ``(left, bottom)`` is at the bottom left of the axes! However, this
213221
# may invert the axis so they do not increase in the 'natural' direction.
214222
#
215223

216-
columns = generate_imshow_demo_grid(extents[1:], auto_limits=True)
224+
extents = [(-0.5, 6.5, -0.5, 5.5),
225+
(-0.5, 6.5, 5.5, -0.5),
226+
(6.5, -0.5, -0.5, 5.5),
227+
(6.5, -0.5, 5.5, -0.5)]
228+
229+
columns = generate_imshow_demo_grid(extents)
217230
set_extent_None_text(columns['upper'][1])
218231
set_extent_None_text(columns['lower'][0])
219232

220233

221234
###############################################################################
222235
#
223-
# If we fix the axes limits so ``(0, 0)`` is at the bottom left and
224-
# increases to up and to the right (from the viewer point of view) then
225-
# we can see that:
236+
# Explicit extent and axes limits
237+
# -------------------------------
238+
#
239+
# If we fix the axes limits by explicity setting `set_xlim` / `set_ylim`, we
240+
# force a certain size and orientation of the axes.
241+
# This can decouple the 'left-right' and 'top-bottom' sense of the image from
242+
# the orientation on the screen.
243+
#
244+
# In the example below we have chosen the limits slightly larger than the
245+
# the extent (note the white areas within the Axes.
246+
#
247+
# While we keep the extents as in the examples before, (0, 0) is now
248+
# explicitly put at the bottom left and values
249+
# increase to up and to the right (from the viewer point of view).
250+
# We can see that:
226251
#
227252
# - The ``(left, bottom)`` anchors the image which then fills the
228253
# box going towards the ``(right, top)`` point in data space.
@@ -232,6 +257,5 @@ def generate_imshow_demo_grid(extents, auto_limits):
232257
# - The 'left-right' and 'top-bottom' sense of the image is uncoupled from
233258
# the orientation on the screen.
234259

235-
columns = generate_imshow_demo_grid(extents, auto_limits=False)
236-
set_extent_None_text(columns['upper'][2])
237-
set_extent_None_text(columns['lower'][1])
260+
generate_imshow_demo_grid(extents=[None] + extents,
261+
xlim=(-2, 8), ylim=(-1, 6))

0 commit comments

Comments
 (0)