44===============
55
66"""
7- import matplotlib .pyplot as plt
87
9- import numpy as np
108import matplotlib .cm as cm
9+ import matplotlib .pyplot as plt
1110import matplotlib .transforms as mtransforms
1211from matplotlib .colors import LightSource
1312from matplotlib .artist import Artist
13+ import numpy as np
1414
1515
1616def smooth1d (x , window_len ):
1717 # copied from http://www.scipy.org/Cookbook/SignalSmooth
18-
1918 s = np .r_ [2 * x [0 ] - x [window_len :1 :- 1 ], x , 2 * x [- 1 ] - x [- 1 :- window_len :- 1 ]]
2019 w = np .hanning (window_len )
2120 y = np .convolve (w / w .sum (), s , mode = 'same' )
2221 return y [window_len - 1 :- window_len + 1 ]
2322
2423
2524def 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
3429
3530
3631class 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
4432
4533 def get_pad (self , dpi ):
4634 return 0
4735
36+ def process_image (padded_src , dpi ):
37+ raise NotImplementedError ("Should be overridden by subclasses" )
38+
4839 def __call__ (self , im , dpi ):
4940 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" )
5142 tgt_image = self .process_image (padded_src , dpi )
5243 return tgt_image , - pad , - pad
5344
5445
5546class 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
6150
6251 def get_pad (self , dpi ):
63- return int (max (* self .offsets )/ 72. * dpi )
52+ return int (max (self .offsets ) / 72 * dpi )
6453
6554 def process_image (self , padded_src , dpi ):
6655 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 )
6958 return a2
7059
7160
7261class GaussianFilter (BaseFilter ):
73- "simple gauss filter"
62+ """Simple Gaussian filter."" "
7463
75- def __init__ (self , sigma , alpha = 0.5 , color = None ):
64+ def __init__ (self , sigma , alpha = 0.5 , color = ( 0 , 0 , 0 ) ):
7665 self .sigma = sigma
7766 self .alpha = alpha
78- if color is None :
79- self .color = (0 , 0 , 0 )
80- else :
81- self .color = color
67+ self .color = color
8268
8369 def get_pad (self , dpi ):
84- return int (self .sigma * 3 / 72. * dpi )
70+ return int (self .sigma * 3 / 72 * dpi )
8571
8672 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 )
9377 return tgt_image
9478
9579
9680class 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 )):
9883 self .gauss_filter = GaussianFilter (sigma , alpha , color )
9984 self .offset_filter = OffsetFilter (offsets )
10085
@@ -109,7 +94,6 @@ def process_image(self, padded_src, dpi):
10994
11095
11196class LightFilter (BaseFilter ):
112- "simple gauss filter"
11397
11498 def __init__ (self , sigma , fraction = 0.5 ):
11599 self .gauss_filter = GaussianFilter (sigma , alpha = 1 )
@@ -123,47 +107,36 @@ def process_image(self, padded_src, dpi):
123107 t1 = self .gauss_filter .process_image (padded_src , dpi )
124108 elevation = t1 [:, :, 3 ]
125109 rgb = padded_src [:, :, :3 ]
126-
110+ alpha = padded_src [:, :, 3 :]
127111 rgb2 = self .light_source .shade_rgb (rgb , elevation ,
128112 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 )
135114
136115
137116class GrowFilter (BaseFilter ):
138- "enlarge the area"
117+ """Enlarge the area."" "
139118
140- def __init__ (self , pixels , color = None ):
119+ def __init__ (self , pixels , color = ( 1 , 1 , 1 ) ):
141120 self .pixels = pixels
142- if color is None :
143- self .color = (1 , 1 , 1 )
144- else :
145- self .color = color
121+ self .color = color
146122
147123 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 )
151126 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
154129 offsetx , offsety = - self .pixels , - self .pixels
155130 return new_im , offsetx , offsety
156131
157132
158133class FilteredArtistList (Artist ):
159- """
160- A simple container to draw filtered artist.
161- """
134+ """A simple container to filter multiple artists at once."""
162135
163136 def __init__ (self , artist_list , filter ):
137+ super ().__init__ ()
164138 self ._artist_list = artist_list
165139 self ._filter = filter
166- Artist .__init__ (self )
167140
168141 def draw (self , renderer ):
169142 renderer .start_rasterizing ()
@@ -188,15 +161,13 @@ def filtered_text(ax):
188161
189162 # draw
190163 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' )
192165 levels = np .arange (- 1.2 , 1.6 , 0.2 )
193166 CS = ax .contour (Z , levels ,
194167 origin = 'lower' ,
195168 linewidths = 2 ,
196169 extent = (- 3 , 3 , - 2 , 2 ))
197170
198- ax .set_aspect ("auto" )
199-
200171 # contour label
201172 cl = ax .clabel (CS , levels [1 ::2 ], # label every second level
202173 inline = 1 ,
@@ -223,17 +194,14 @@ def drop_shadow_line(ax):
223194 # copied from examples/misc/svg_filter_line.py
224195
225196 # 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-" )
230199
231200 gauss = DropShadowFilter (4 )
232201
233202 for l in [l1 , l2 ]:
234203
235204 # draw shadows with same lines with slight offset.
236-
237205 xx = l .get_xdata ()
238206 yy = l .get_ydata ()
239207 shadow , = ax .plot (xx , yy )
@@ -288,7 +256,6 @@ def light_filter_pie(ax):
288256 fracs = [15 , 30 , 45 , 10 ]
289257 explode = (0 , 0.05 , 0 , 0 )
290258 pies = ax .pie (fracs , explode = explode )
291- ax .patch .set_visible (True )
292259
293260 light_filter = LightFilter (9 )
294261 for p in pies [0 ]:
@@ -305,21 +272,12 @@ def light_filter_pie(ax):
305272
306273if __name__ == "__main__" :
307274
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 )
319276
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 )
324282
325283 plt .show ()
0 commit comments