4
4
===============
5
5
6
6
"""
7
- import matplotlib .pyplot as plt
8
7
9
- import numpy as np
10
8
import matplotlib .cm as cm
9
+ import matplotlib .pyplot as plt
11
10
import matplotlib .transforms as mtransforms
12
11
from matplotlib .colors import LightSource
13
12
from matplotlib .artist import Artist
13
+ import numpy as np
14
14
15
15
16
16
def smooth1d (x , window_len ):
17
17
# copied from http://www.scipy.org/Cookbook/SignalSmooth
18
-
19
18
s = np .r_ [2 * x [0 ] - x [window_len :1 :- 1 ], x , 2 * x [- 1 ] - x [- 1 :- window_len :- 1 ]]
20
19
w = np .hanning (window_len )
21
20
y = np .convolve (w / w .sum (), s , mode = 'same' )
22
21
return y [window_len - 1 :- window_len + 1 ]
23
22
24
23
25
24
def smooth2d (A , sigma = 3 ):
26
-
27
- window_len = max (int (sigma ), 3 )* 2 + 1
28
- A1 = np .array ([smooth1d (x , window_len ) for x in np .asarray (A )])
29
- A2 = np .transpose (A1 )
30
- A3 = np .array ([smooth1d (x , window_len ) for x in A2 ])
31
- A4 = np .transpose (A3 )
32
-
33
- return A4
25
+ window_len = max (int (sigma ), 3 ) * 2 + 1
26
+ A = np .apply_along_axis (smooth1d , 0 , A , window_len )
27
+ A = np .apply_along_axis (smooth1d , 1 , A , window_len )
28
+ return A
34
29
35
30
36
31
class BaseFilter :
37
- def prepare_image (self , src_image , dpi , pad ):
38
- ny , nx , depth = src_image .shape
39
- # tgt_image = np.zeros([pad*2+ny, pad*2+nx, depth], dtype="d")
40
- padded_src = np .zeros ([pad * 2 + ny , pad * 2 + nx , depth ], dtype = "d" )
41
- padded_src [pad :- pad , pad :- pad , :] = src_image [:, :, :]
42
-
43
- return padded_src # , tgt_image
44
32
45
33
def get_pad (self , dpi ):
46
34
return 0
47
35
36
+ def process_image (padded_src , dpi ):
37
+ raise NotImplementedError ("Should be overridden by subclasses" )
38
+
48
39
def __call__ (self , im , dpi ):
49
40
pad = self .get_pad (dpi )
50
- padded_src = self . prepare_image (im , dpi , pad )
41
+ padded_src = np . pad (im , [( pad , pad ), ( pad , pad ), ( 0 , 0 )], "constant" )
51
42
tgt_image = self .process_image (padded_src , dpi )
52
43
return tgt_image , - pad , - pad
53
44
54
45
55
46
class OffsetFilter (BaseFilter ):
56
- def __init__ (self , offsets = None ):
57
- if offsets is None :
58
- self .offsets = (0 , 0 )
59
- else :
60
- self .offsets = offsets
47
+
48
+ def __init__ (self , offsets = (0 , 0 )):
49
+ self .offsets = offsets
61
50
62
51
def get_pad (self , dpi ):
63
- return int (max (* self .offsets )/ 72. * dpi )
52
+ return int (max (self .offsets ) / 72 * dpi )
64
53
65
54
def process_image (self , padded_src , dpi ):
66
55
ox , oy = self .offsets
67
- a1 = np .roll (padded_src , int (ox / 72. * dpi ), axis = 1 )
68
- a2 = np .roll (a1 , - int (oy / 72. * dpi ), axis = 0 )
56
+ a1 = np .roll (padded_src , int (ox / 72 * dpi ), axis = 1 )
57
+ a2 = np .roll (a1 , - int (oy / 72 * dpi ), axis = 0 )
69
58
return a2
70
59
71
60
72
61
class GaussianFilter (BaseFilter ):
73
- "simple gauss filter"
62
+ """Simple Gaussian filter."" "
74
63
75
- def __init__ (self , sigma , alpha = 0.5 , color = None ):
64
+ def __init__ (self , sigma , alpha = 0.5 , color = ( 0 , 0 , 0 ) ):
76
65
self .sigma = sigma
77
66
self .alpha = alpha
78
- if color is None :
79
- self .color = (0 , 0 , 0 )
80
- else :
81
- self .color = color
67
+ self .color = color
82
68
83
69
def get_pad (self , dpi ):
84
- return int (self .sigma * 3 / 72. * dpi )
70
+ return int (self .sigma * 3 / 72 * dpi )
85
71
86
72
def process_image (self , padded_src , dpi ):
87
- # offsetx, offsety = int(self.offsets[0]), int(self.offsets[1])
88
- tgt_image = np .zeros_like (padded_src )
89
- aa = smooth2d (padded_src [:, :, - 1 ]* self .alpha ,
90
- self .sigma / 72. * dpi )
91
- tgt_image [:, :, - 1 ] = aa
92
- tgt_image [:, :, :- 1 ] = self .color
73
+ tgt_image = np .empty_like (padded_src )
74
+ tgt_image [:, :, :3 ] = self .color
75
+ tgt_image [:, :, 3 ] = smooth2d (padded_src [:, :, 3 ] * self .alpha ,
76
+ self .sigma / 72 * dpi )
93
77
return tgt_image
94
78
95
79
96
80
class DropShadowFilter (BaseFilter ):
97
- def __init__ (self , sigma , alpha = 0.3 , color = None , offsets = None ):
81
+
82
+ def __init__ (self , sigma , alpha = 0.3 , color = (0 , 0 , 0 ), offsets = (0 , 0 )):
98
83
self .gauss_filter = GaussianFilter (sigma , alpha , color )
99
84
self .offset_filter = OffsetFilter (offsets )
100
85
@@ -109,7 +94,6 @@ def process_image(self, padded_src, dpi):
109
94
110
95
111
96
class LightFilter (BaseFilter ):
112
- "simple gauss filter"
113
97
114
98
def __init__ (self , sigma , fraction = 0.5 ):
115
99
self .gauss_filter = GaussianFilter (sigma , alpha = 1 )
@@ -123,47 +107,36 @@ def process_image(self, padded_src, dpi):
123
107
t1 = self .gauss_filter .process_image (padded_src , dpi )
124
108
elevation = t1 [:, :, 3 ]
125
109
rgb = padded_src [:, :, :3 ]
126
-
110
+ alpha = padded_src [:, :, 3 :]
127
111
rgb2 = self .light_source .shade_rgb (rgb , elevation ,
128
112
fraction = self .fraction )
129
-
130
- tgt = np .empty_like (padded_src )
131
- tgt [:, :, :3 ] = rgb2
132
- tgt [:, :, 3 ] = padded_src [:, :, 3 ]
133
-
134
- return tgt
113
+ return np .concatenate ([rgb2 , alpha ], - 1 )
135
114
136
115
137
116
class GrowFilter (BaseFilter ):
138
- "enlarge the area"
117
+ """Enlarge the area."" "
139
118
140
- def __init__ (self , pixels , color = None ):
119
+ def __init__ (self , pixels , color = ( 1 , 1 , 1 ) ):
141
120
self .pixels = pixels
142
- if color is None :
143
- self .color = (1 , 1 , 1 )
144
- else :
145
- self .color = color
121
+ self .color = color
146
122
147
123
def __call__ (self , im , dpi ):
148
- ny , nx , depth = im .shape
149
- alpha = np .pad (im [..., - 1 ], self .pixels , "constant" )
150
- alpha2 = np .clip (smooth2d (alpha , self .pixels / 72. * dpi ) * 5 , 0 , 1 )
124
+ alpha = np .pad (im [..., 3 ], self .pixels , "constant" )
125
+ alpha2 = np .clip (smooth2d (alpha , self .pixels / 72 * dpi ) * 5 , 0 , 1 )
151
126
new_im = np .empty ((* alpha2 .shape , 4 ))
152
- new_im [:, :, - 1 ] = alpha2
153
- new_im [:, :, : - 1 ] = self . color
127
+ new_im [:, :, : 3 ] = self . color
128
+ new_im [:, :, 3 ] = alpha2
154
129
offsetx , offsety = - self .pixels , - self .pixels
155
130
return new_im , offsetx , offsety
156
131
157
132
158
133
class FilteredArtistList (Artist ):
159
- """
160
- A simple container to draw filtered artist.
161
- """
134
+ """A simple container to filter multiple artists at once."""
162
135
163
136
def __init__ (self , artist_list , filter ):
137
+ super ().__init__ ()
164
138
self ._artist_list = artist_list
165
139
self ._filter = filter
166
- Artist .__init__ (self )
167
140
168
141
def draw (self , renderer ):
169
142
renderer .start_rasterizing ()
@@ -188,15 +161,13 @@ def filtered_text(ax):
188
161
189
162
# draw
190
163
ax .imshow (Z , interpolation = 'bilinear' , origin = 'lower' ,
191
- cmap = cm .gray , extent = (- 3 , 3 , - 2 , 2 ))
164
+ cmap = cm .gray , extent = (- 3 , 3 , - 2 , 2 ), aspect = 'auto' )
192
165
levels = np .arange (- 1.2 , 1.6 , 0.2 )
193
166
CS = ax .contour (Z , levels ,
194
167
origin = 'lower' ,
195
168
linewidths = 2 ,
196
169
extent = (- 3 , 3 , - 2 , 2 ))
197
170
198
- ax .set_aspect ("auto" )
199
-
200
171
# contour label
201
172
cl = ax .clabel (CS , levels [1 ::2 ], # label every second level
202
173
inline = 1 ,
@@ -223,17 +194,14 @@ def drop_shadow_line(ax):
223
194
# copied from examples/misc/svg_filter_line.py
224
195
225
196
# draw lines
226
- l1 , = ax .plot ([0.1 , 0.5 , 0.9 ], [0.1 , 0.9 , 0.5 ], "bo-" ,
227
- mec = "b" , mfc = "w" , lw = 5 , mew = 3 , ms = 10 , label = "Line 1" )
228
- l2 , = ax .plot ([0.1 , 0.5 , 0.9 ], [0.5 , 0.2 , 0.7 ], "ro-" ,
229
- mec = "r" , mfc = "w" , lw = 5 , mew = 3 , ms = 10 , label = "Line 1" )
197
+ l1 , = ax .plot ([0.1 , 0.5 , 0.9 ], [0.1 , 0.9 , 0.5 ], "bo-" )
198
+ l2 , = ax .plot ([0.1 , 0.5 , 0.9 ], [0.5 , 0.2 , 0.7 ], "ro-" )
230
199
231
200
gauss = DropShadowFilter (4 )
232
201
233
202
for l in [l1 , l2 ]:
234
203
235
204
# draw shadows with same lines with slight offset.
236
-
237
205
xx = l .get_xdata ()
238
206
yy = l .get_ydata ()
239
207
shadow , = ax .plot (xx , yy )
@@ -288,7 +256,6 @@ def light_filter_pie(ax):
288
256
fracs = [15 , 30 , 45 , 10 ]
289
257
explode = (0 , 0.05 , 0 , 0 )
290
258
pies = ax .pie (fracs , explode = explode )
291
- ax .patch .set_visible (True )
292
259
293
260
light_filter = LightFilter (9 )
294
261
for p in pies [0 ]:
@@ -305,21 +272,12 @@ def light_filter_pie(ax):
305
272
306
273
if __name__ == "__main__" :
307
274
308
- plt .figure (figsize = (6 , 6 ))
309
- plt .subplots_adjust (left = 0.05 , right = 0.95 )
310
-
311
- ax = plt .subplot (221 )
312
- filtered_text (ax )
313
-
314
- ax = plt .subplot (222 )
315
- drop_shadow_line (ax )
316
-
317
- ax = plt .subplot (223 )
318
- drop_shadow_patches (ax )
275
+ fix , axs = plt .subplots (2 , 2 )
319
276
320
- ax = plt .subplot (224 )
321
- ax .set_aspect (1 )
322
- light_filter_pie (ax )
323
- ax .set_frame_on (True )
277
+ filtered_text (axs [0 , 0 ])
278
+ drop_shadow_line (axs [0 , 1 ])
279
+ drop_shadow_patches (axs [1 , 0 ])
280
+ light_filter_pie (axs [1 , 1 ])
281
+ axs [1 , 1 ].set_frame_on (True )
324
282
325
283
plt .show ()
0 commit comments