Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 78b1fec

Browse files
committed
Deprecate QuadContourSet.allsegs, .allkinds, .tcolors, .tlinewidths.
Directly construct the relevant path objects and the collections with the right properties instead of carrying around another copy of the information in raw array form. By having fewer intermediate objects lying around for a long time (as attributes of the QuadContourSet) this makes the logic easier to follow.
1 parent 204ab61 commit 78b1fec

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)