8000 FIX: add support for imshow extent to have units · matplotlib/matplotlib@615c7f6 · GitHub
[go: up one dir, main page]

Skip to content

Commit 615c7f6

Browse files
committed
FIX: add support for imshow extent to have units
1 parent f393802 commit 615c7f6

File tree

5 files changed

+64
-4
lines changed

5 files changed

+64
-4
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
The extent parameter of imshow and set_extent functions can now be expressed with Units
2+
---------------------------------------------------------------------------------------
3+
The extent parameter of `~axes.Axes.imshow` can now be expressed
4+
with Units. It internally uses the `~AxesImage.set_extent` which contains
5+
the implemenation that enables extent being expressed with Units.
6+
If extent[0] is expressed in units, then so must extent[1].
7+
Similarly, this applies to extent[2] and extent[3] as well. The user is
8+
responsible to ensure that the units are lined up.
9+
10+
.. plot::
11+
:include-source: true
12+
13+
import matplotlib.pyplot as plt
14+
import numpy as np
15+
from matplotlib.dates import HourLocator, DateFormatter
16+
from matplotlib.ticker import (AutoMinorLocator)
17+
18+
19+
fig, ax = plt.subplots()
20+
dates = np.arange("2020-01-01","2020-01-13", dtype='datetime64[h]')
21+
22+
arr = [[i+j for i in range(10)] for j in range(10)]
23+
24+
ax.imshow(arr, origin='lower', extent=[dates[0], dates[10], dates[10], dates[0]])
25+
26+
ax.xaxis.set_major_formatter(DateFormatter('%d/%m:%H'))
27+
ax.xaxis.set_major_locator(HourLocator(byhour=[0, 2, 4, 6, 8, 10]))
28+
ax.xaxis.set_minor_locator(AutoMinorLocator())
29+
30+
plt.show()

lib/matplotlib/axes/_axes.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5409,7 +5409,7 @@ def imshow(self, X, cmap=None, norm=None, aspect=None,
54095409
See the :doc:`/tutorials/intermediate/imshow_extent` tutorial for
54105410
examples and a more detailed description.
54115411
5412-
extent : floats (left, right, bottom, top), optional
5412+
extent : floats or units (left, right, bottom, top), optional
54135413
The bounding box in data coordinates that the image will fill.
54145414
The image is stretched individually along x and y to fill the box.
54155415
@@ -5486,6 +5486,7 @@ def imshow(self, X, cmap=None, norm=None, aspect=None,
54865486
if aspect is None:
54875487
aspect = rcParams['image.aspect']
54885488
self.set_aspect(aspect)
5489+
54895490
im = mimage.AxesImage(self, cmap, norm, interpolation,
54905491
origin, extent, filternorm=filternorm,
54915492
filterrad=filterrad, resample=resample,
@@ -5502,7 +5503,7 @@ def imshow(self, X, cmap=None, norm=None, aspect=None,
55025503

55035504
# update ax.dataLim, and, if autoscaling, set viewLim
55045505
# to tightly fit the image, regardless of dataLim.
5505-
im.set_extent(im.get_extent())
5506+
im.set_extent(im.get_extent(), **kwargs)
55065507

55075508
self.add_image(im)
55085509
return im

lib/matplotlib/image.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -933,7 +933,7 @@ def _check_unsampled_image(self):
933933
"""Return whether the image would be better drawn unsampled."""
934934
return self.get_interpolation() == "none"
935935

936-
def set_extent(self, extent):
936+
def set_extent(self, extent, **kwargs):
937937
"""
938938
Set the image extent.
939939
@@ -942,6 +942,11 @@ def set_extent(self, extent):
942942
extent : 4-tuple of float
943943
The position and size of the image as tuple
944944
``(left, right, bottom, top)`` in data coordinates.
945+
kwargs : dict
946+
Other parameters from which unit info (i.e., the *xunits*,
947+
*yunits*, *zunits* (for 3D axes), *runits* and *thetaunits* (for
948+
polar axes) entries) is popped, if present. Note that this dict is
949+
mutated in-place!
945950
946951
Notes
947952
-----
@@ -950,7 +955,21 @@ def set_extent(self, extent):
950955
state is not changed, so following this with ``ax.autoscale_view()``
951956
will redo the autoscaling in accord with ``dataLim``.
952957
"""
953-
self._extent = xmin, xmax, ymin, ymax = extent
958+
(xmin, xmax), = self.axes._process_unit_info(
959+
[("x", [extent[0], extent[1]])], kwargs)
960+
(ymin, ymax), = self.axes._process_unit_info(
961+
[("y", [extent[2], extent[3]])], kwargs)
962+
xmin = self.axes._validate_converted_limits(
963+
xmin, self.convert_xunits)
964+
xmax = self.axes._validate_converted_limits(
965+
xmax, self.convert_xunits)
966+
ymin = self.axes._validate_converted_limits(
967+
ymin, self.convert_yunits)
968+
ymax = self.axes._validate_converted_limits(
969+
ymax, self.convert_yunits)
970+
extent = [xmin, xmax, ymin, ymax]
971+
972+
self._extent = extent
954973
corners = (xmin, ymin), (xmax, ymax)
955974
self.axes.update_datalim(corners)
956975
self.sticky_edges.x[:] = [xmin, xmax]
Binary file not shown.

lib/matplotlib/tests/test_axes.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7387,3 +7387,13 @@ def test_clim():
73877387
clim = (7, 8)
73887388
norm = plot_method(clim=clim).norm
73897389
assert (norm.vmin, norm.vmax) == clim
7390+
7391+
7392+
@image_comparison(["extent_units.pdf"])
7393+
def test_extent_units():
7394+
mpl.style.use("mpl20")
7395+
fig, ax = plt.subplots()
7396+
dates = np.arange("2020-01-01", "2020-01-13", dtype='datetime64')
7397+
arr = [[i+j for i in range(10)] for j in range(10)]
7398+
ax.imshow(arr, origin='lower', extent=[0, 10,
7399+
dates[10], dates[0]])

0 commit comments

Comments
 (0)
0