演示Agg过滤器

演示Agg过滤器示例

  1. import matplotlib.pyplot as plt
  2. import numpy as np
  3. import matplotlib.cm as cm
  4. import matplotlib.transforms as mtransforms
  5. from matplotlib.colors import LightSource
  6. from matplotlib.artist import Artist
  7. def smooth1d(x, window_len):
  8. # copied from http://www.scipy.org/Cookbook/SignalSmooth
  9. s = np.r_[2*x[0] - x[window_len:1:-1], x, 2*x[-1] - x[-1:-window_len:-1]]
  10. w = np.hanning(window_len)
  11. y = np.convolve(w/w.sum(), s, mode='same')
  12. return y[window_len-1:-window_len+1]
  13. def smooth2d(A, sigma=3):
  14. window_len = max(int(sigma), 3)*2 + 1
  15. A1 = np.array([smooth1d(x, window_len) for x in np.asarray(A)])
  16. A2 = np.transpose(A1)
  17. A3 = np.array([smooth1d(x, window_len) for x in A2])
  18. A4 = np.transpose(A3)
  19. return A4
  20. class BaseFilter(object):
  21. def prepare_image(self, src_image, dpi, pad):
  22. ny, nx, depth = src_image.shape
  23. # tgt_image = np.zeros([pad*2+ny, pad*2+nx, depth], dtype="d")
  24. padded_src = np.zeros([pad*2 + ny, pad*2 + nx, depth], dtype="d")
  25. padded_src[pad:-pad, pad:-pad, :] = src_image[:, :, :]
  26. return padded_src # , tgt_image
  27. def get_pad(self, dpi):
  28. return 0
  29. def __call__(self, im, dpi):
  30. pad = self.get_pad(dpi)
  31. padded_src = self.prepare_image(im, dpi, pad)
  32. tgt_image = self.process_image(padded_src, dpi)
  33. return tgt_image, -pad, -pad
  34. class OffsetFilter(BaseFilter):
  35. def __init__(self, offsets=None):
  36. if offsets is None:
  37. self.offsets = (0, 0)
  38. else:
  39. self.offsets = offsets
  40. def get_pad(self, dpi):
  41. return int(max(*self.offsets)/72.*dpi)
  42. def process_image(self, padded_src, dpi):
  43. ox, oy = self.offsets
  44. a1 = np.roll(padded_src, int(ox/72.*dpi), axis=1)
  45. a2 = np.roll(a1, -int(oy/72.*dpi), axis=0)
  46. return a2
  47. class GaussianFilter(BaseFilter):
  48. "simple gauss filter"
  49. def __init__(self, sigma, alpha=0.5, color=None):
  50. self.sigma = sigma
  51. self.alpha = alpha
  52. if color is None:
  53. self.color = (0, 0, 0)
  54. else:
  55. self.color = color
  56. def get_pad(self, dpi):
  57. return int(self.sigma*3/72.*dpi)
  58. def process_image(self, padded_src, dpi):
  59. # offsetx, offsety = int(self.offsets[0]), int(self.offsets[1])
  60. tgt_image = np.zeros_like(padded_src)
  61. aa = smooth2d(padded_src[:, :, -1]*self.alpha,
  62. self.sigma/72.*dpi)
  63. tgt_image[:, :, -1] = aa
  64. tgt_image[:, :, :-1] = self.color
  65. return tgt_image
  66. class DropShadowFilter(BaseFilter):
  67. def __init__(self, sigma, alpha=0.3, color=None, offsets=None):
  68. self.gauss_filter = GaussianFilter(sigma, alpha, color)
  69. self.offset_filter = OffsetFilter(offsets)
  70. def get_pad(self, dpi):
  71. return max(self.gauss_filter.get_pad(dpi),
  72. self.offset_filter.get_pad(dpi))
  73. def process_image(self, padded_src, dpi):
  74. t1 = self.gauss_filter.process_image(padded_src, dpi)
  75. t2 = self.offset_filter.process_image(t1, dpi)
  76. return t2
  77. class LightFilter(BaseFilter):
  78. "simple gauss filter"
  79. def __init__(self, sigma, fraction=0.5):
  80. self.gauss_filter = GaussianFilter(sigma, alpha=1)
  81. self.light_source = LightSource()
  82. self.fraction = fraction
  83. def get_pad(self, dpi):
  84. return self.gauss_filter.get_pad(dpi)
  85. def process_image(self, padded_src, dpi):
  86. t1 = self.gauss_filter.process_image(padded_src, dpi)
  87. elevation = t1[:, :, 3]
  88. rgb = padded_src[:, :, :3]
  89. rgb2 = self.light_source.shade_rgb(rgb, elevation,
  90. fraction=self.fraction)
  91. tgt = np.empty_like(padded_src)
  92. tgt[:, :, :3] = rgb2
  93. tgt[:, :, 3] = padded_src[:, :, 3]
  94. return tgt
  95. class GrowFilter(BaseFilter):
  96. "enlarge the area"
  97. def __init__(self, pixels, color=None):
  98. self.pixels = pixels
  99. if color is None:
  100. self.color = (1, 1, 1)
  101. else:
  102. self.color = color
  103. def __call__(self, im, dpi):
  104. pad = self.pixels
  105. ny, nx, depth = im.shape
  106. new_im = np.empty([pad*2 + ny, pad*2 + nx, depth], dtype="d")
  107. alpha = new_im[:, :, 3]
  108. alpha.fill(0)
  109. alpha[pad:-pad, pad:-pad] = im[:, :, -1]
  110. alpha2 = np.clip(smooth2d(alpha, self.pixels/72.*dpi) * 5, 0, 1)
  111. new_im[:, :, -1] = alpha2
  112. new_im[:, :, :-1] = self.color
  113. offsetx, offsety = -pad, -pad
  114. return new_im, offsetx, offsety
  115. class FilteredArtistList(Artist):
  116. """
  117. A simple container to draw filtered artist.
  118. """
  119. def __init__(self, artist_list, filter):
  120. self._artist_list = artist_list
  121. self._filter = filter
  122. Artist.__init__(self)
  123. def draw(self, renderer):
  124. renderer.start_rasterizing()
  125. renderer.start_filter()
  126. for a in self._artist_list:
  127. a.draw(renderer)
  128. renderer.stop_filter(self._filter)
  129. renderer.stop_rasterizing()
  130. def filtered_text(ax):
  131. # mostly copied from contour_demo.py
  132. # prepare image
  133. delta = 0.025
  134. x = np.arange(-3.0, 3.0, delta)
  135. y = np.arange(-2.0, 2.0, delta)
  136. X, Y = np.meshgrid(x, y)
  137. Z1 = np.exp(-X**2 - Y**2)
  138. Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2)
  139. Z = (Z1 - Z2) * 2
  140. # draw
  141. im = ax.imshow(Z, interpolation='bilinear', origin='lower',
  142. cmap=cm.gray, extent=(-3, 3, -2, 2))
  143. levels = np.arange(-1.2, 1.6, 0.2)
  144. CS = ax.contour(Z, levels,
  145. origin='lower',
  146. linewidths=2,
  147. extent=(-3, 3, -2, 2))
  148. ax.set_aspect("auto")
  149. # contour label
  150. cl = ax.clabel(CS, levels[1::2], # label every second level
  151. inline=1,
  152. fmt='%1.1f',
  153. fontsize=11)
  154. # change clable color to black
  155. from matplotlib.patheffects import Normal
  156. for t in cl:
  157. t.set_color("k")
  158. # to force TextPath (i.e., same font in all backends)
  159. t.set_path_effects([Normal()])
  160. # Add white glows to improve visibility of labels.
  161. white_glows = FilteredArtistList(cl, GrowFilter(3))
  162. ax.add_artist(white_glows)
  163. white_glows.set_zorder(cl[0].get_zorder() - 0.1)
  164. ax.xaxis.set_visible(False)
  165. ax.yaxis.set_visible(False)
  166. def drop_shadow_line(ax):
  167. # copied from examples/misc/svg_filter_line.py
  168. # draw lines
  169. l1, = ax.plot([0.1, 0.5, 0.9], [0.1, 0.9, 0.5], "bo-",
  170. mec="b", mfc="w", lw=5, mew=3, ms=10, label="Line 1")
  171. l2, = ax.plot([0.1, 0.5, 0.9], [0.5, 0.2, 0.7], "ro-",
  172. mec="r", mfc="w", lw=5, mew=3, ms=10, label="Line 1")
  173. gauss = DropShadowFilter(4)
  174. for l in [l1, l2]:
  175. # draw shadows with same lines with slight offset.
  176. xx = l.get_xdata()
  177. yy = l.get_ydata()
  178. shadow, = ax.plot(xx, yy)
  179. shadow.update_from(l)
  180. # offset transform
  181. ot = mtransforms.offset_copy(l.get_transform(), ax.figure,
  182. x=4.0, y=-6.0, units='points')
  183. shadow.set_transform(ot)
  184. # adjust zorder of the shadow lines so that it is drawn below the
  185. # original lines
  186. shadow.set_zorder(l.get_zorder() - 0.5)
  187. shadow.set_agg_filter(gauss)
  188. shadow.set_rasterized(True) # to support mixed-mode renderers
  189. ax.set_xlim(0., 1.)
  190. ax.set_ylim(0., 1.)
  191. ax.xaxis.set_visible(False)
  192. ax.yaxis.set_visible(False)
  193. def drop_shadow_patches(ax):
  194. # Copied from barchart_demo.py
  195. N = 5
  196. menMeans = (20, 35, 30, 35, 27)
  197. ind = np.arange(N) # the x locations for the groups
  198. width = 0.35 # the width of the bars
  199. rects1 = ax.bar(ind, menMeans, width, color='r', ec="w", lw=2)
  200. womenMeans = (25, 32, 34, 20, 25)
  201. rects2 = ax.bar(ind + width + 0.1, womenMeans, width,
  202. color='y', ec="w", lw=2)
  203. # gauss = GaussianFilter(1.5, offsets=(1,1), )
  204. gauss = DropShadowFilter(5, offsets=(1, 1), )
  205. shadow = FilteredArtistList(rects1 + rects2, gauss)
  206. ax.add_artist(shadow)
  207. shadow.set_zorder(rects1[0].get_zorder() - 0.1)
  208. ax.set_ylim(0, 40)
  209. ax.xaxis.set_visible(False)
  210. ax.yaxis.set_visible(False)
  211. def light_filter_pie(ax):
  212. fracs = [15, 30, 45, 10]
  213. explode = (0, 0.05, 0, 0)
  214. pies = ax.pie(fracs, explode=explode)
  215. ax.patch.set_visible(True)
  216. light_filter = LightFilter(9)
  217. for p in pies[0]:
  218. p.set_agg_filter(light_filter)
  219. p.set_rasterized(True) # to support mixed-mode renderers
  220. p.set(ec="none",
  221. lw=2)
  222. gauss = DropShadowFilter(9, offsets=(3, 4), alpha=0.7)
  223. shadow = FilteredArtistList(pies[0], gauss)
  224. ax.add_artist(shadow)
  225. shadow.set_zorder(pies[0][0].get_zorder() - 0.1)
  226. if 1:
  227. plt.figure(1, figsize=(6, 6))
  228. plt.subplots_adjust(left=0.05, right=0.95)
  229. ax = plt.subplot(221)
  230. filtered_text(ax)
  231. ax = plt.subplot(222)
  232. drop_shadow_line(ax)
  233. ax = plt.subplot(223)
  234. drop_shadow_patches(ax)
  235. ax = plt.subplot(224)
  236. ax.set_aspect(1)
  237. light_filter_pie(ax)
  238. ax.set_frame_on(True)
  239. plt.show()

下载这个示例