10000 Merge pull request #22230 from pratimugale/bugfix-for-issue-22105 · matplotlib/matplotlib@3d6c3da · GitHub
[go: up one dir, main page]

Skip to content

Commit 3d6c3da

Browse files
authored
Merge pull request #22230 from pratimugale/bugfix-for-issue-22105
FIX: add support for imshow extent to have units
2 parents 06c1554 + 90a4899 commit 3d6c3da

File tree

5 files changed

+88
-2
lines changed

5 files changed

+88
-2
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
The *extent* of ``imshow`` can now be expressed with units
2+
----------------------------------------------------------
3+
The *extent* parameter of `~.axes.Axes.imshow` and `~.AxesImage.set_extent`
4+
can now be expressed with units.
5+
6+
.. plot::
7+
:include-source: true
8+
9+
import matplotlib.pyplot as plt
10+
import numpy as np
11+
from matplotlib.dates import HourLocator, DateFormatter
12+
from matplotlib.ticker import AutoMinorLocator
13+
14+
fig, ax = plt.subplots()
15+
date_first = np.datetime64('2020-01-01', 'D')
16+
date_last = np.datetime64('2020-01-11', 'D')
17+
18+
arr = [[i+j for i in range(10)] for j in range(10)]
19+
20+
ax.imshow(arr, origin='lower', extent=[1, 11, date_first, date_last])
21+
22+
ax.yaxis.set_major_formatter(DateFormatter('%d/%m/%y:- %H00hours'))
23+
ax.yaxis.set_major_locator(HourLocator(byhour=[0, 6, 12, 18, 24]))
24+
ax.yaxis.set_minor_locator(AutoMinorLocator())
25+
26+
plt.show()

lib/matplotlib/axes/_axes.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5548,6 +5548,7 @@ def imshow(self, X, cmap=None, norm=None, *, aspect=None,
55485548
55495549
extent : floats (left, right, bottom, top), optional
55505550
The bounding box in data coordinates that the image will fill.
5551+
These values may be unitful and match the units of the Axes.
55515552
The image is stretched individually along x and y to fill the box.
55525553
55535554
The default extent is determined by the following conditions.

lib/matplotlib/image.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -953,7 +953,7 @@ def _check_unsampled_image(self):
953953
"""Return whether the image would be better drawn unsampled."""
954954
return self.get_interpolation() == "none"
955955

956-
def set_extent(self, extent):
956+
def set_extent(self, extent, **kwargs):
957957
"""
958958
Set the image extent.
959959
@@ -962,6 +962,10 @@ def set_extent(self, extent):
962962
extent : 4-tuple of float
963963
The position and size of the image as tuple
964964
``(left, right, bottom, top)`` in data coordinates.
965+
**kwargs
966+
Other parameters from which unit info (i.e., the *xunits*,
967+
*yunits*, *zunits* (for 3D axes), *runits* and *thetaunits* (for
968+
polar axes) entries are applied, if present.
965969
966970
Notes
967971
-----
@@ -970,7 +974,26 @@ def set_extent(self, extent):
970974
state is not changed, so following this with ``ax.autoscale_view()``
971975
will redo the autoscaling in accord with ``dataLim``.
972976
"""
973-
self._extent = xmin, xmax, ymin, ymax = extent
977+
(xmin, xmax), (ymin, ymax) = self.axes._process_unit_info(
978+
[("x", [extent[0], extent[1]]),
979+
("y", [extent[2], extent[3]])],
980+
kwargs)
981+
if len(kwargs):
982+
raise ValueError(
983+
"set_extent did not consume all of the kwargs passed." +
984+
f"{list(kwargs)!r} were unused"
985+
)
986+
xmin = self.axes._validate_converted_limits(
987+
xmin, self.convert_xunits)
988+
xmax = self.axes._validate_converted_limits(
989+
xmax, self.convert_xunits)
990+
ymin = self.axes._validate_converted_limits(
991+
ymin, self.convert_yunits)
992+
ymax = self.axes._validate_converted_limits(
993+
ymax, self.convert_yunits)
994+
extent = [xmin, xmax, ymin, ymax]
995+
996+
self._extent = extent
974997
corners = (xmin, ymin), (xmax, ymax)
975998
self.axes.update_datalim(corners)
976999
self.sticky_edges.x[:] = [xmin, xmax]
Loading

lib/matplotlib/tests/test_axes.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8254,3 +8254,39 @@ def test_bar_all_nan(fig_test, fig_ref):
82548254

82558255
ax_ref.bar([1], [1]).remove()
82568256
ax_ref.bar([1], [1])
8257+
8258+
8259+
@image_comparison(["extent_units.png"], style="mpl20")
8260+
def test_extent_units():
8261+
_, axs = plt.subplots(2, 2)
8262+
date_first = np.datetime64('2020-01-01', 'D')
8263+
date_last = np.datetime64('2020-01-11', 'D')
8264+
arr = [[i+j for i in range(10)] for j in range(10)]
8265+
8266+
axs[0, 0].set_title('Date extents on y axis')
8267+
im = axs[0, 0].imshow(arr, origin='lower',
8268+
extent=[1, 11, date_first, date_last],
8269+
cmap=mpl.colormaps["plasma"])
8270+
8271+
axs[0, 1].set_title('Date extents on x axis (Day of Jan 2020)')
8272+
im = axs[0, 1].imshow(arr, origin='lower',
8273+
extent=[date_first, date_last, 1, 11],
8274+
cmap=mpl.colormaps["plasma"])
8275+
axs[0, 1].xaxis.set_major_formatter(mdates.DateFormatter('%d'))
8276+
8277+
im = axs[1, 0].imshow(arr, origin='lower',
8278+
extent=[date_first, date_last,
8279+
date_first, date_last],
8280+
cmap=mpl.colormaps["plasma"])
8281+
axs[1, 0].xaxis.set_major_formatter(mdates.DateFormatter('%d'))
8282+
axs[1, 0].set(xlabel='Day of Jan 2020')
8283+
8284+
im = axs[1, 1].imshow(arr, origin='lower',
8285+
cmap=mpl.colormaps["plasma"])
8286+
im.set_extent([date_last, date_first, date_last, date_first])
8287+
axs[1, 1].xaxis.set_major_formatter(mdates.DateFormatter('%d'))
8288+
axs[1, 1].set(xlabel='Day of Jan 2020')
8289+
8290+
with pytest.raises(ValueError,
8291+
match="set_extent did not consume all of the kwargs"):
8292+
im.set_extent([2, 12, date_first, date_last], clip=False)

0 commit comments

Comments
 (0)
0