8000 Merge pull request #25138 from anntzer/ask · matplotlib/matplotlib@cb2bdb1 · GitHub
[go: up one dir, main page]

Skip to content

Commit cb2bdb1

Browse files
authored
Merge pull request #25138 from anntzer/ask
Deprecate QuadContourSet.allsegs, .allkinds, .tcolors, .tlinewidths.
2 parents 298aa41 + 78b1fec commit cb2bdb1

File tree

4 files changed

+66
-41
lines changed

4 files changed

+66
-41
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
``allsegs``, ``allkinds``, ``tcolors`` and ``tlinewidths`` attributes of `.ContourSet`
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
These attributes are deprecated; if required, directly retrieve the vertices
4+
and codes of the Path objects in ``QuadContourSet.collections`` and the colors
5+
and the linewidths of these collections.

lib/matplotlib/colorbar.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -774,8 +774,8 @@ def add_lines(self, *args, **kwargs):
774774
# TODO: Make colorbar lines auto-follow changes in contour lines.
775775
return self.add_lines(
776776
CS.levels,
777-
[c[0] for c in CS.tcolors],
778-
[t[0] for t in CS.tlinewidths],
777+
CS.to_rgba(CS.cvalues, CS.alpha),
778+
[coll.get_linewidths()[0] for coll in CS.collections],
779779
erase=erase)
780780
else:
781781
self, levels, colors, linewidths, erase = params.values()

lib/matplotlib/contour.py

Lines changed: 40 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
"""
44

55
import functools
6-
import itertools
76
from numbers import Integral
87

98
import numpy as np
@@ -767,6 +766,10 @@ def __init__(self, ax, *args,
767766
self.negative_linestyles = \
768767
mpl.rcParams['contour.negative_linestyle']
769768

769+
# The base class _process_args will update _allpaths, which gets picked
770+
# up by _get_allpaths below. OTOH the _process_args of subclasses
771+
# leave _allpaths as None and instead set _contour_generator.
772+
self._allpaths = None
770773
kwargs = self._process_args(*args, **kwargs)
771774
self._process_levels()
772775

@@ -820,23 +823,7 @@ def __init__(self, ax, *args,
820823
self.norm.vmax = vmax
821824
self._process_colors()
822825

823-
if getattr(self, 'allsegs', None) is None:
824-
self.allsegs, self.allkinds = self._get_allsegs_and_allkinds()
825-
elif self.allkinds is None:
826-
# allsegs specified in constructor may or may not have allkinds as
827-
# well. Must ensure allkinds can be zipped below.
828-
self.allkinds = [None] * len(self.allsegs)
829-
830-
# Each entry in (allsegs, allkinds) is a list of (segs, kinds) which
831-
# specifies a list of Paths: segs is a list of (N, 2) arrays of xy
832-
# coordinates, kinds is a list of arrays of corresponding pathcodes.
833-
# However, kinds can also be None; in which case all paths in that list
834-
# are codeless.
835-
allpaths = [
836-
[*map(mpath.Path,
837-
segs,
838-
kinds if kinds is not None else itertools.repeat(None))]
839-
for segs, kinds in zip(self.allsegs, self.allkinds)]
826+
allpaths = self._get_allpaths()
840827

841828
if self.filled:
842829
if self.linewidths is not None:
@@ -857,7 +844,7 @@ def __init__(self, ax, *args,
857844
for level, level_upper, paths
858845
in zip(lowers, uppers, allpaths)]
859846
else:
860-
self.tlinewidths = tlinewidths = self._process_linewidths()
847+
tlinewidths = self._process_linewidths()
861848
tlinestyles = self._process_linestyles()
862849
aa = self.antialiased
863850
if aa is not None:
@@ -895,6 +882,15 @@ def __init__(self, ax, *args,
895882
", ".join(map(repr, kwargs))
896883
)
897884

885+
allsegs = _api.deprecated("3.8", pending=True)(property(lambda self: [
886+
p.vertices for c in self.collections for p in c.get_paths()]))
887+
allkinds = _api.deprecated("3.8", pending=True)(property(lambda self: [
888+
p.codes for c in self.collections for p in c.get_paths()]))
889+
tcolors = _api.deprecated("3.8")(property(lambda self: [
890+
(tuple(rgba),) for rgba in self.to_rgba(self.cvalues, self.alpha)]))
891+
tlinewidths = _api.deprecated("3.8")(
892+
property(lambda self: self._process_linewidths()))
893+
898894
def get_transform(self):
899895
"""Return the `.Transform` instance used by this ContourSet."""
900896
if self._transform is None:
@@ -979,51 +975,60 @@ def _process_args(self, *args, **kwargs):
979975
Must set self.levels, self.zmin and self.zmax, and update axes limits.
980976
"""
981977
self.levels = args[0]
982-
self.allsegs = args[1]
983-
self.allkinds = args[2] if len(args) > 2 else None
978+
allsegs = args[1]
979+
allkinds = args[2] if len(args) > 2 else None
984980
self.zmax = np.max(self.levels)
985981
self.zmin = np.min(self.levels)
986982

983+
if allkinds is None:
984+
allkinds = [[None] * len(segs) for segs in allsegs]
985+
987986
# Check lengths of levels and allsegs.
988987
if self.filled:
989-
if len(self.allsegs) != len(self.levels) - 1:
988+
if len(allsegs) != len(self.levels) - 1:
990989
raise ValueError('must be one less number of segments as '
991990
'levels')
992991
else:
993-
if len(self.allsegs) != len(self.levels):
992+
if len(allsegs) != len(self.levels):
994993
raise ValueError('must be same number of segments as levels')
995994

996995
# Check length of allkinds.
997-
if (self.allkinds is not None and
998-
len(self.allkinds) != len(self.allsegs)):
996+
if len(allkinds) != len(allsegs):
999997
raise ValueError('allkinds has different length to allsegs')
1000998

1001999
# Determine x, y bounds and update axes data limits.
1002-
flatseglist = [s for seg in self.allsegs for s in seg]
1000+
flatseglist = [s for seg in allsegs for s in seg]
10031001
points = np.concatenate(flatseglist, axis=0)
10041002
self._mins = points.min(axis=0)
10051003
self._maxs = points.max(axis=0)
10061004

1005+
# Each entry in (allsegs, allkinds) is a list of (segs, kinds) which
1006+
# specifies a list of Paths: segs is a list of (N, 2) arrays of xy
1007+
# coordinates, kinds is a list of arrays of corresponding pathcodes.
1008+
# However, kinds can also be None; in which case all paths in that list
1009+
# are codeless (this case is normalized above).
1010+
self._allpaths = [[*map(mpath.Path, segs, kinds)]
1011+
for segs, kinds in zip(allsegs, allkinds)]
1012+
10071013
return kwargs
10081014

1009-
def _get_allsegs_and_allkinds(self):
1010-
"""Compute ``allsegs`` and ``allkinds`` using C extension."""
1011-
allsegs = []
1012-
allkinds = []
1015+
def _get_allpaths(self):
1016+
"""Compute ``allpaths`` using C extension."""
1017+
if self._allpaths is not None:
1018+
return self._allpaths
1019+
allpaths = []
10131020
if self.filled:
10141021
lowers, uppers = self._get_lowers_and_uppers()
10151022
for level, level_upper in zip(lowers, uppers):
10161023
vertices, kinds = \
10171024
self._contour_generator.create_filled_contour(
10181025
level, level_upper)
1019-
allsegs.append(vertices)
1020-
allkinds.append(kinds)
1026+
allpaths.append([*map(mpath.Path, vertices, kinds)])
10211027
else:
10221028
for level in self.levels:
10231029
vertices, kinds = self._contour_generator.create_contour(level)
1024-
allsegs.append(vertices)
1025-
allkinds.append(kinds)
1026-
return allsegs, allkinds
1030+
allpaths.append([*map(mpath.Path, vertices, kinds)])
1031+
return allpaths
10271032

10281033
def _get_lowers_and_uppers(self):
10291034
"""
@@ -1052,7 +1057,6 @@ def changed(self):
10521057
self.norm.autoscale_None(self.levels)
10531058
tcolors = [(tuple(rgba),)
10541059
for rgba in self.to_rgba(self.cvalues, alpha=self.alpha)]
1055-
self.tcolors = tcolors
10561060
hatches = self.hatches * len(tcolors)
10571061
for color, hatch, collection in zip(tcolors, hatches,
10581062
self.collections):

lib/matplotlib/tests/test_contour.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
import contourpy
66
import numpy as np
77
from numpy.testing import (
8-
assert_array_almost_equal, assert_array_almost_equal_nulp)
8+
assert_array_almost_equal, assert_array_almost_equal_nulp, assert_array_equal)
99
import matplotlib as mpl
10-
from matplotlib.testing.decorators import image_comparison
1110
from matplotlib import pyplot as plt, rc_context, ticker
11+
from matplotlib._api import MatplotlibDeprecationWarning
1212
from matplotlib.colors import LogNorm, same_color
13+
from matplotlib.testing.decorators import image_comparison
1314
import pytest
1415

1516

@@ -365,7 +366,9 @@ def test_contour_linewidth(
365366
fig, ax = plt.subplots()
366367
X = np.arange(4*3).reshape(4, 3)
367368
cs = ax.contour(X, linewidths=call_linewidths)
368-
assert cs.tlinewidths[0][0] == expected
369+
assert cs.collections[0].get_linewidths()[0] == expected
370+
with pytest.warns(MatplotlibDeprecationWarning, match="tlinewidths"):
371+
assert cs.tlinewidths[0][0] == expected
369372

370373

371374
@pytest.mark.backend("pdf")
@@ -722,3 +725,16 @@ def test_all_nan():
722725
assert_array_almost_equal(plt.contour(x).levels,
723726
[-1e-13, -7.5e-14, -5e-14, -2.4e-14, 0.0,
724727
2.4e-14, 5e-14, 7.5e-14, 1e-13])
728+
729+
730+
def test_deprecated_apis():
731+
cs = plt.contour(np.arange(16).reshape((4, 4)))
732+
colls = cs.collections
733+
with pytest.warns(PendingDeprecationWarning, match="allsegs"):
734+
assert cs.allsegs == [p.vertices for c in colls for p in c.get_paths()]
735+
with pytest.warns(PendingDeprecationWarning, match="allkinds"):
736+
assert cs.allkinds == [p.codes for c in colls for p in c.get_paths()]
737+
with pytest.warns(MatplotlibDeprecationWarning, match="tcolors"):
738+
assert_array_equal(cs.tcolors, [c.get_edgecolor() for c in colls])
739+
with pytest.warns(MatplotlibDeprecationWarning, match="tlinewidths"):
740+
assert cs.tlinewidths == [c.get_linewidth() for c in colls]

0 commit comments

Comments
 (0)
0