4
4
# See COPYING and COPYING.LESSER in the root of the repository for full
5
5
# licensing details.
6
6
7
-
7
+ import matplotlib as mpl
8
8
from matplotlib .contour import QuadContourSet
9
9
import matplotlib .path as mpath
10
10
import numpy as np
11
+ import packaging
11
12
12
13
13
14
class GeoContourSet (QuadContourSet ):
@@ -20,66 +21,91 @@ class GeoContourSet(QuadContourSet):
20
21
# fiddling with instance.__class__.
21
22
22
23
def clabel (self , * args , ** kwargs ):
23
- # nb: contour labelling does not work very well for filled
24
- # contours - it is recommended to only label line contours.
25
- # This is especially true when inline=True.
26
-
27
- # This wrapper exist because mpl does not properly transform
28
- # paths. Instead it simply assumes one path represents one polygon
29
- # (not necessarily the case), and it assumes that
30
- # transform(path.verts) is equivalent to transform_path(path).
31
- # Unfortunately there is no way to easily correct this error,
32
- # so we are forced to pre-transform the ContourSet's paths from
33
- # the source coordinate system to the axes' projection.
34
- # The existing mpl code then has a much simpler job of handling
35
- # pre-projected paths (which can now effectively be transformed
36
- # naively).
37
-
38
- for col in self .collections :
39
- # Snaffle the collection's path list. We will change the
40
- # list in-place (as the contour label code does in mpl).
41
- paths = col .get_paths ()
24
+ if packaging .version .parse (mpl .__version__ ).release [:2 ] < (3 , 8 ):
25
+ # nb: contour labelling does not work very well for filled
26
+ # contours - it is recommended to only label line contours.
27
+ # This is especially true when inline=True.
28
+
29
+ # This wrapper exist because mpl does not properly transform
30
+ # paths. Instead it simply assumes one path represents one polygon
31
+ # (not necessarily the case), and it assumes that
32
+ # transform(path.verts) is equivalent to transform_path(path).
33
+ # Unfortunately there is no way to easily correct this error,
34
+ # so we are forced to pre-transform the ContourSet's paths from
35
+ # the source coordinate system to the axes' projection.
36
+ # The existing mpl code then has a much simpler job of handling
37
+ # pre-projected paths (which can now effectively be transformed
38
+ # naively).
39
+
40
+ for col in self .collections :
41
+ # Snaffle the collection's path list. We will change the
42
+ # list in-place (as the contour label code does in mpl).
43
+ paths = col .get_paths ()
44
+
45
+ # Define the transform that will take us from collection
46
+ # coordinates through to axes projection coordinates.
47
+ data_t = self .axes .transData
48
+ col_to_data = col .get_transform () - data_t
49
+
50
+ # Now that we have the transform, project all of this
51
+ # collection's paths.
52
+ new_paths = [col_to_data .transform_path (path )
53
+ for path in paths ]
54
+ new_paths = [path for path in new_paths
55
+ if path .vertices .size >= 1 ]
56
+
57
+ # The collection will now be referenced in axes projection
58
+ # coordinates.
59
+ col .set_transform (data_t )
60
+
61
+ # Clear the now incorrectly referenced paths.
62
+ del paths [:]
63
+
64
+ for path in new_paths :
65
+ if path .vertices .size == 0 :
66
+ # Don't persist empty paths. Let's get rid of them.
67
+ continue
68
+
69
+ # Split the path if it has multiple MOVETO statements.
70
+ codes = np .array (
71
+ path .codes if path .codes is not None else [0 ])
72
+ moveto = codes == mpath .Path .MOVETO
73
+ if moveto .sum () <= 1 :
74
+ # This is only one path, so add it to the collection.
75
+ paths .append (path )
76
+ else :
77
+ # The first MOVETO doesn't need cutting-out.
78
+ moveto [0 ] = False
79
+ split_locs = np .flatnonzero (moveto )
80
+
81
+ split_verts = np .split (path .vertices , split_locs )
82
+ split_codes = np .split (path .codes , split_locs )
83
+
84
+ for verts , codes in zip (split_verts , split_codes ):
85
+ # Add this path to the collection's list of paths.
86
+ paths .append (mpath .Path (verts , codes ))
87
+
88
+ else :
89
+ # Where contour paths exist at the edge of the globe, sometimes a
90
+ # complete path in data space will become multiple paths when
91
+ # transformed into axes or screen space. Matplotlib's contour
92
+ # labelling does not account for this so we need to give it the
93
+ # pre-transformed paths to work with.
42
94
43
95
# Define the transform that will take us from collection
44
96
# coordinates through to axes projection coordinates.
45
97
data_t = self .axes .transData
46
- col_to_data = col .get_transform () - data_t
98
+ col_to_data = self .get_transform () - data_t
47
99
48
100
# Now that we have the transform, project all of this
49
101
# collection's paths.
102
+ paths = self .get_paths ()
50
103
new_paths = [col_to_data .transform_path (path ) for path in paths ]
51
- new_paths = [ path for path in new_paths if path . vertices . size >= 1 ]
104
+ paths [:] = new_paths
52
105
53
106
# The collection will now be referenced in axes projection
54
107
# coordinates.
55
- col .set_transform (data_t )
56
-
57
- # Clear the now incorrectly referenced paths.
58
- del paths [:]
59
-
60
- for path in new_paths :
61
- if path .vertices .size == 0 :
62
- # Don't persist empty paths. Let's get rid of them.
63
- continue
64
-
65
- # Split the path if it has multiple MOVETO statements.
66
- codes = np .array (
67
- path .codes if path .codes is not None else [0 ])
68
- moveto = codes == mpath .Path .MOVETO
69
- if moveto .sum () <= 1 :
70
- # This is only one path, so add it to the collection.
71
- paths .append (path )
72
- else :
73
- # The first MOVETO doesn't need cutting-out.
74
- moveto [0 ] = False
75
- split_locs = np .flatnonzero (moveto )
76
-
77
- split_verts = np .split (path .vertices , split_locs )
78
- split_codes = np .split (path .codes , split_locs )
79
-
80
- for verts , codes in zip (split_verts , split_codes ):
81
- # Add this path to the collection's list of paths.
82
- paths .append (mpath .Path (verts , codes ))
108
+ self .set_transform (data_t )
83
109
84
110
# Now that we have prepared the collection paths, call on
85
111
# through to the underlying implementation.
0 commit comments