Repository: holoviz/holoviews

Issue:
Unpin matplotlib 3.8
In https://github.com/holoviz/holoviews/pull/5895 I pinned matplotlib 3.8, this should be removed before the next release. 


Discussion:

Resolving patch:
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -33,7 +33,7 @@
     'pytest-cov',
     'pytest-xdist',
     'flaky',
-    'matplotlib >=3, <3.8',  # 3.8 breaks tests
+    'matplotlib >=3',
     'nbconvert',
     'bokeh >=3.1',
     'pillow',


Test patch:
diff --git a/holoviews/tests/plotting/matplotlib/test_heatmapplot.py b/holoviews/tests/plotting/matplotlib/test_heatmapplot.py
--- a/holoviews/tests/plotting/matplotlib/test_heatmapplot.py
+++ b/holoviews/tests/plotting/matplotlib/test_heatmapplot.py
@@ -2,7 +2,7 @@
 
 from holoviews.element import HeatMap, Image
 
-from .test_plot import TestMPLPlot, mpl_renderer
+from .test_plot import TestMPLPlot, mpl38, mpl_renderer
 
 
 class TestHeatMapPlot(TestMPLPlot):
@@ -12,25 +12,35 @@ def test_heatmap_invert_axes(self):
         hm = HeatMap(Image(arr)).opts(invert_axes=True)
         plot = mpl_renderer.get_plot(hm)
         artist = plot.handles['artist']
-        self.assertEqual(artist.get_array().data, arr.T[::-1].flatten())
+        if mpl38:
+            np.testing.assert_equal(artist.get_array().data, arr.T[::-1])
+        else:
+            np.testing.assert_equal(artist.get_array().data, arr.T[::-1].flatten())
 
     def test_heatmap_extents(self):
         hmap = HeatMap([('A', 50, 1), ('B', 2, 2), ('C', 50, 1)])
         plot = mpl_renderer.get_plot(hmap)
-        self.assertEqual(plot.get_extents(hmap, {}), (-.5, -22, 2.5, 74))
+        assert plot.get_extents(hmap, {}) == (-.5, -22, 2.5, 74)
 
     def test_heatmap_invert_xaxis(self):
         hmap = HeatMap([('A',1, 1), ('B', 2, 2)]).opts(invert_xaxis=True)
         plot = mpl_renderer.get_plot(hmap)
         array = plot.handles['artist'].get_array()
-        expected = np.array([1, np.inf, np.inf, 2])
+        if mpl38:
+            expected = np.array([[1, np.inf], [np.inf, 2]])
+        else:
+            expected = np.array([1, np.inf, np.inf, 2])
         masked = np.ma.array(expected, mask=np.logical_not(np.isfinite(expected)))
-        self.assertEqual(array, masked)
+        np.testing.assert_equal(array, masked)
 
     def test_heatmap_invert_yaxis(self):
         hmap = HeatMap([('A',1, 1), ('B', 2, 2)]).opts(invert_yaxis=True)
         plot = mpl_renderer.get_plot(hmap)
         array = plot.handles['artist'].get_array()
         expected = np.array([1, np.inf, np.inf, 2])
+        if mpl38:
+            expected = np.array([[1, np.inf], [np.inf, 2]])
+        else:
+            expected = np.array([1, np.inf, np.inf, 2])
         masked = np.ma.array(expected, mask=np.logical_not(np.isfinite(expected)))
-        self.assertEqual(array, masked)
+        np.testing.assert_equal(array, masked)
diff --git a/holoviews/tests/plotting/matplotlib/test_plot.py b/holoviews/tests/plotting/matplotlib/test_plot.py
--- a/holoviews/tests/plotting/matplotlib/test_plot.py
+++ b/holoviews/tests/plotting/matplotlib/test_plot.py
@@ -1,14 +1,17 @@
 import matplotlib.pyplot as plt
 import pyviz_comms as comms
+from packaging.version import Version
 from param import concrete_descendents
 
 from holoviews.core.options import Store
 from holoviews.element.comparison import ComparisonTestCase
+from holoviews.plotting.mpl import mpl_version
 from holoviews.plotting.mpl.element import ElementPlot
 
 from .. import option_intersections
 
 mpl_renderer = Store.renderers['matplotlib']
+mpl38 = mpl_version >= Version("3.8")
 
 
 class TestPlotDefinitions(ComparisonTestCase):
diff --git a/holoviews/tests/plotting/matplotlib/test_quadmeshplot.py b/holoviews/tests/plotting/matplotlib/test_quadmeshplot.py
--- a/holoviews/tests/plotting/matplotlib/test_quadmeshplot.py
+++ b/holoviews/tests/plotting/matplotlib/test_quadmeshplot.py
@@ -2,49 +2,53 @@
 
 from holoviews.element import Dataset, Image, QuadMesh
 
-from .test_plot import TestMPLPlot, mpl_renderer
+from .test_plot import TestMPLPlot, mpl38, mpl_renderer
 
 
 class TestQuadMeshPlot(TestMPLPlot):
 
     def test_quadmesh_invert_axes(self):
-        arr = np.array([[0, 1, 2], [3, 4,  5]])
+        arr = np.array([[0, 1, 2], [3, 4, 5]])
         qmesh = QuadMesh(Image(arr)).opts(invert_axes=True)
         plot = mpl_renderer.get_plot(qmesh)
         artist = plot.handles['artist']
-        self.assertEqual(artist.get_array().data, arr.T[:, ::-1].flatten())
+        if mpl38:
+            np.testing.assert_equal(artist.get_array().data, arr[::-1].T)
+        else:
+            np.testing.assert_equal(artist.get_array().data, arr.T[::-1].flatten())
 
     def test_quadmesh_nodata(self):
-        arr = np.array([[0, 1, 2], [3, 4,  5]])
+        arr = np.array([[0, 1, 2], [3, 4, 5]])
         qmesh = QuadMesh(Image(arr)).opts(nodata=0)
         plot = mpl_renderer.get_plot(qmesh)
         artist = plot.handles['artist']
-        self.assertEqual(artist.get_array().data,
-                         np.array([3, 4, 5, np.nan, 1, 2]))
+        if mpl38:
+            expected = np.array([[3, 4, 5], [np.nan, 1, 2]])
+        else:
+            expected = np.array([3, 4, 5, np.nan, 1, 2])
+
+        np.testing.assert_equal(artist.get_array().data, expected)
 
     def test_quadmesh_nodata_uint(self):
-        arr = np.array([[0, 1, 2], [3, 4,  5]], dtype='uint32')
+        arr = np.array([[0, 1, 2], [3, 4, 5]], dtype='uint32')
         qmesh = QuadMesh(Image(arr)).opts(nodata=0)
         plot = mpl_renderer.get_plot(qmesh)
         artist = plot.handles['artist']
-        self.assertEqual(artist.get_array().data,
-                         np.array([3, 4, 5, np.nan, 1, 2]))
+        if mpl38:
+            expected = np.array([[3, 4, 5], [np.nan, 1, 2]])
+        else:
+            expected = np.array([3, 4, 5, np.nan, 1, 2])
+        np.testing.assert_equal(artist.get_array().data, expected)
 
     def test_quadmesh_update_cbar(self):
         xs = ys = np.linspace(0, 6, 10)
         zs = np.linspace(1, 2, 5)
-        XS, YS, ZS = np.meshgrid(xs, ys, zs)
+        XS, _YS, ZS = np.meshgrid(xs, ys, zs)
         values = np.sin(XS) * ZS
         ds = Dataset((xs, ys, zs, values.T), ['x', 'y', 'z'], 'values')
         hmap = ds.to(QuadMesh).opts(colorbar=True, framewise=True)
         plot = mpl_renderer.get_plot(hmap)
         cbar = plot.handles['cbar']
-        self.assertEqual(
-            np.allclose([cbar.vmin, cbar.vmax], [-0.9989549170979283, 0.9719379013633128]),
-            True
-        )
+        np.testing.assert_allclose([cbar.vmin, cbar.vmax], [-0.9989549170979283, 0.9719379013633128])
         plot.update(3)
-        self.assertEqual(
-            np.allclose([cbar.vmin, cbar.vmax], [-1.7481711049213744, 1.7008913273857975]),
-            True
-        )
+        np.testing.assert_allclose([cbar.vmin, cbar.vmax], [-1.7481711049213744, 1.7008913273857975])