1""" 2=============== 3Demo Agg Filter 4=============== 5 6""" 7import matplotlib.pyplot as plt 8 9import numpy as np 10import matplotlib.cm as cm 11import matplotlib.transforms as mtransforms 12from matplotlib.colors import LightSource 13from matplotlib.artist import Artist 14 15 16def smooth1d(x, window_len): 17 # copied from http://www.scipy.org/Cookbook/SignalSmooth 18 19 s = np.r_[2*x[0] - x[window_len:1:-1], x, 2*x[-1] - x[-1:-window_len:-1]] 20 w = np.hanning(window_len) 21 y = np.convolve(w/w.sum(), s, mode='same') 22 return y[window_len-1:-window_len+1] 23 24 25def 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 34 35 36class BaseFilter(object): 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 45 def get_pad(self, dpi): 46 return 0 47 48 def __call__(self, im, dpi): 49 pad = self.get_pad(dpi) 50 padded_src = self.prepare_image(im, dpi, pad) 51 tgt_image = self.process_image(padded_src, dpi) 52 return tgt_image, -pad, -pad 53 54 55class OffsetFilter(BaseFilter): 56 def __init__(self, offsets=None): 57 if offsets is None: 58 self.offsets = (0, 0) 59 else: 60 self.offsets = offsets 61 62 def get_pad(self, dpi): 63 return int(max(*self.offsets)/72.*dpi) 64 65 def process_image(self, padded_src, dpi): 66 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) 69 return a2 70 71 72class GaussianFilter(BaseFilter): 73 "simple gauss filter" 74 75 def __init__(self, sigma, alpha=0.5, color=None): 76 self.sigma = sigma 77 self.alpha = alpha 78 if color is None: 79 self.color = (0, 0, 0) 80 else: 81 self.color = color 82 83 def get_pad(self, dpi): 84 return int(self.sigma*3/72.*dpi) 85 86 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 93 return tgt_image 94 95 96class DropShadowFilter(BaseFilter): 97 def __init__(self, sigma, alpha=0.3, color=None, offsets=None): 98 self.gauss_filter = GaussianFilter(sigma, alpha, color) 99 self.offset_filter = OffsetFilter(offsets) 100 101 def get_pad(self, dpi): 102 return max(self.gauss_filter.get_pad(dpi), 103 self.offset_filter.get_pad(dpi)) 104 105 def process_image(self, padded_src, dpi): 106 t1 = self.gauss_filter.process_image(padded_src, dpi) 107 t2 = self.offset_filter.process_image(t1, dpi) 108 return t2 109 110 111class LightFilter(BaseFilter): 112 "simple gauss filter" 113 114 def __init__(self, sigma, fraction=0.5): 115 self.gauss_filter = GaussianFilter(sigma, alpha=1) 116 self.light_source = LightSource() 117 self.fraction = fraction 118 119 def get_pad(self, dpi): 120 return self.gauss_filter.get_pad(dpi) 121 122 def process_image(self, padded_src, dpi): 123 t1 = self.gauss_filter.process_image(padded_src, dpi) 124 elevation = t1[:, :, 3] 125 rgb = padded_src[:, :, :3] 126 127 rgb2 = self.light_source.shade_rgb(rgb, elevation, 128 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 135 136 137class GrowFilter(BaseFilter): 138 "enlarge the area" 139 140 def __init__(self, pixels, color=None): 141 self.pixels = pixels 142 if color is None: 143 self.color = (1, 1, 1) 144 else: 145 self.color = color 146 147 def __call__(self, im, dpi): 148 pad = self.pixels 149 ny, nx, depth = im.shape 150 new_im = np.empty([pad*2 + ny, pad*2 + nx, depth], dtype="d") 151 alpha = new_im[:, :, 3] 152 alpha.fill(0) 153 alpha[pad:-pad, pad:-pad] = im[:, :, -1] 154 alpha2 = np.clip(smooth2d(alpha, self.pixels/72.*dpi) * 5, 0, 1) 155 new_im[:, :, -1] = alpha2 156 new_im[:, :, :-1] = self.color 157 offsetx, offsety = -pad, -pad 158 159 return new_im, offsetx, offsety 160 161 162class FilteredArtistList(Artist): 163 """ 164 A simple container to draw filtered artist. 165 """ 166 167 def __init__(self, artist_list, filter): 168 self._artist_list = artist_list 169 self._filter = filter 170 Artist.__init__(self) 171 172 def draw(self, renderer): 173 renderer.start_rasterizing() 174 renderer.start_filter() 175 for a in self._artist_list: 176 a.draw(renderer) 177 renderer.stop_filter(self._filter) 178 renderer.stop_rasterizing() 179 180 181def filtered_text(ax): 182 # mostly copied from contour_demo.py 183 184 # prepare image 185 delta = 0.025 186 x = np.arange(-3.0, 3.0, delta) 187 y = np.arange(-2.0, 2.0, delta) 188 X, Y = np.meshgrid(x, y) 189 Z1 = np.exp(-X**2 - Y**2) 190 Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2) 191 Z = (Z1 - Z2) * 2 192 193 # draw 194 im = ax.imshow(Z, interpolation='bilinear', origin='lower', 195 cmap=cm.gray, extent=(-3, 3, -2, 2)) 196 levels = np.arange(-1.2, 1.6, 0.2) 197 CS = ax.contour(Z, levels, 198 origin='lower', 199 linewidths=2, 200 extent=(-3, 3, -2, 2)) 201 202 ax.set_aspect("auto") 203 204 # contour label 205 cl = ax.clabel(CS, levels[1::2], # label every second level 206 inline=1, 207 fmt='%1.1f', 208 fontsize=11) 209 210 # change clable color to black 211 from matplotlib.patheffects import Normal 212 for t in cl: 213 t.set_color("k") 214 # to force TextPath (i.e., same font in all backends) 215 t.set_path_effects([Normal()]) 216 217 # Add white glows to improve visibility of labels. 218 white_glows = FilteredArtistList(cl, GrowFilter(3)) 219 ax.add_artist(white_glows) 220 white_glows.set_zorder(cl[0].get_zorder() - 0.1) 221 222 ax.xaxis.set_visible(False) 223 ax.yaxis.set_visible(False) 224 225 226def drop_shadow_line(ax): 227 # copied from examples/misc/svg_filter_line.py 228 229 # draw lines 230 l1, = ax.plot([0.1, 0.5, 0.9], [0.1, 0.9, 0.5], "bo-", 231 mec="b", mfc="w", lw=5, mew=3, ms=10, label="Line 1") 232 l2, = ax.plot([0.1, 0.5, 0.9], [0.5, 0.2, 0.7], "ro-", 233 mec="r", mfc="w", lw=5, mew=3, ms=10, label="Line 1") 234 235 gauss = DropShadowFilter(4) 236 237 for l in [l1, l2]: 238 239 # draw shadows with same lines with slight offset. 240 241 xx = l.get_xdata() 242 yy = l.get_ydata() 243 shadow, = ax.plot(xx, yy) 244 shadow.update_from(l) 245 246 # offset transform 247 ot = mtransforms.offset_copy(l.get_transform(), ax.figure, 248 x=4.0, y=-6.0, units='points') 249 250 shadow.set_transform(ot) 251 252 # adjust zorder of the shadow lines so that it is drawn below the 253 # original lines 254 shadow.set_zorder(l.get_zorder() - 0.5) 255 shadow.set_agg_filter(gauss) 256 shadow.set_rasterized(True) # to support mixed-mode renderers 257 258 ax.set_xlim(0., 1.) 259 ax.set_ylim(0., 1.) 260 261 ax.xaxis.set_visible(False) 262 ax.yaxis.set_visible(False) 263 264 265def drop_shadow_patches(ax): 266 # Copied from barchart_demo.py 267 N = 5 268 menMeans = (20, 35, 30, 35, 27) 269 270 ind = np.arange(N) # the x locations for the groups 271 width = 0.35 # the width of the bars 272 273 rects1 = ax.bar(ind, menMeans, width, color='r', ec="w", lw=2) 274 275 womenMeans = (25, 32, 34, 20, 25) 276 rects2 = ax.bar(ind + width + 0.1, womenMeans, width, 277 color='y', ec="w", lw=2) 278 279 # gauss = GaussianFilter(1.5, offsets=(1,1), ) 280 gauss = DropShadowFilter(5, offsets=(1, 1), ) 281 shadow = FilteredArtistList(rects1 + rects2, gauss) 282 ax.add_artist(shadow) 283 shadow.set_zorder(rects1[0].get_zorder() - 0.1) 284 285 ax.set_ylim(0, 40) 286 287 ax.xaxis.set_visible(False) 288 ax.yaxis.set_visible(False) 289 290 291def light_filter_pie(ax): 292 fracs = [15, 30, 45, 10] 293 explode = (0, 0.05, 0, 0) 294 pies = ax.pie(fracs, explode=explode) 295 ax.patch.set_visible(True) 296 297 light_filter = LightFilter(9) 298 for p in pies[0]: 299 p.set_agg_filter(light_filter) 300 p.set_rasterized(True) # to support mixed-mode renderers 301 p.set(ec="none", 302 lw=2) 303 304 gauss = DropShadowFilter(9, offsets=(3, 4), alpha=0.7) 305 shadow = FilteredArtistList(pies[0], gauss) 306 ax.add_artist(shadow) 307 shadow.set_zorder(pies[0][0].get_zorder() - 0.1) 308 309 310if 1: 311 312 plt.figure(1, figsize=(6, 6)) 313 plt.subplots_adjust(left=0.05, right=0.95) 314 315 ax = plt.subplot(221) 316 filtered_text(ax) 317 318 ax = plt.subplot(222) 319 drop_shadow_line(ax) 320 321 ax = plt.subplot(223) 322 drop_shadow_patches(ax) 323 324 ax = plt.subplot(224) 325 ax.set_aspect(1) 326 light_filter_pie(ax) 327 ax.set_frame_on(True) 328 329 plt.show() 330