

.. _sphx_glr_gallery_misc_demo_agg_filter.py:


===============
Demo Agg Filter
===============





.. image:: /gallery/misc/images/sphx_glr_demo_agg_filter_001.png
    :align: center





.. code-block:: python

    import matplotlib.pyplot as plt

    import numpy as np
    import matplotlib.cm as cm
    import matplotlib.mlab as mlab
    import matplotlib.transforms as mtransforms
    from matplotlib.colors import LightSource
    from matplotlib.artist import Artist


    def smooth1d(x, window_len):
        # copied from http://www.scipy.org/Cookbook/SignalSmooth

        s = np.r_[2*x[0] - x[window_len:1:-1], x, 2*x[-1] - x[-1:-window_len:-1]]
        w = np.hanning(window_len)
        y = np.convolve(w/w.sum(), s, mode='same')
        return y[window_len-1:-window_len+1]


    def smooth2d(A, sigma=3):

        window_len = max(int(sigma), 3)*2 + 1
        A1 = np.array([smooth1d(x, window_len) for x in np.asarray(A)])
        A2 = np.transpose(A1)
        A3 = np.array([smooth1d(x, window_len) for x in A2])
        A4 = np.transpose(A3)

        return A4


    class BaseFilter(object):
        def prepare_image(self, src_image, dpi, pad):
            ny, nx, depth = src_image.shape
            # tgt_image = np.zeros([pad*2+ny, pad*2+nx, depth], dtype="d")
            padded_src = np.zeros([pad*2 + ny, pad*2 + nx, depth], dtype="d")
            padded_src[pad:-pad, pad:-pad, :] = src_image[:, :, :]

            return padded_src  # , tgt_image

        def get_pad(self, dpi):
            return 0

        def __call__(self, im, dpi):
            pad = self.get_pad(dpi)
            padded_src = self.prepare_image(im, dpi, pad)
            tgt_image = self.process_image(padded_src, dpi)
            return tgt_image, -pad, -pad


    class OffsetFilter(BaseFilter):
        def __init__(self, offsets=None):
            if offsets is None:
                self.offsets = (0, 0)
            else:
                self.offsets = offsets

        def get_pad(self, dpi):
            return int(max(*self.offsets)/72.*dpi)

        def process_image(self, padded_src, dpi):
            ox, oy = self.offsets
            a1 = np.roll(padded_src, int(ox/72.*dpi), axis=1)
            a2 = np.roll(a1, -int(oy/72.*dpi), axis=0)
            return a2


    class GaussianFilter(BaseFilter):
        "simple gauss filter"

        def __init__(self, sigma, alpha=0.5, color=None):
            self.sigma = sigma
            self.alpha = alpha
            if color is None:
                self.color = (0, 0, 0)
            else:
                self.color = color

        def get_pad(self, dpi):
            return int(self.sigma*3/72.*dpi)

        def process_image(self, padded_src, dpi):
            # offsetx, offsety = int(self.offsets[0]), int(self.offsets[1])
            tgt_image = np.zeros_like(padded_src)
            aa = smooth2d(padded_src[:, :, -1]*self.alpha,
                          self.sigma/72.*dpi)
            tgt_image[:, :, -1] = aa
            tgt_image[:, :, :-1] = self.color
            return tgt_image


    class DropShadowFilter(BaseFilter):
        def __init__(self, sigma, alpha=0.3, color=None, offsets=None):
            self.gauss_filter = GaussianFilter(sigma, alpha, color)
            self.offset_filter = OffsetFilter(offsets)

        def get_pad(self, dpi):
            return max(self.gauss_filter.get_pad(dpi),
                       self.offset_filter.get_pad(dpi))

        def process_image(self, padded_src, dpi):
            t1 = self.gauss_filter.process_image(padded_src, dpi)
            t2 = self.offset_filter.process_image(t1, dpi)
            return t2


    class LightFilter(BaseFilter):
        "simple gauss filter"

        def __init__(self, sigma, fraction=0.5):
            self.gauss_filter = GaussianFilter(sigma, alpha=1)
            self.light_source = LightSource()
            self.fraction = fraction

        def get_pad(self, dpi):
            return self.gauss_filter.get_pad(dpi)

        def process_image(self, padded_src, dpi):
            t1 = self.gauss_filter.process_image(padded_src, dpi)
            elevation = t1[:, :, 3]
            rgb = padded_src[:, :, :3]

            rgb2 = self.light_source.shade_rgb(rgb, elevation,
                                               fraction=self.fraction)

            tgt = np.empty_like(padded_src)
            tgt[:, :, :3] = rgb2
            tgt[:, :, 3] = padded_src[:, :, 3]

            return tgt


    class GrowFilter(BaseFilter):
        "enlarge the area"

        def __init__(self, pixels, color=None):
            self.pixels = pixels
            if color is None:
                self.color = (1, 1, 1)
            else:
                self.color = color

        def __call__(self, im, dpi):
            pad = self.pixels
            ny, nx, depth = im.shape
            new_im = np.empty([pad*2 + ny, pad*2 + nx, depth], dtype="d")
            alpha = new_im[:, :, 3]
            alpha.fill(0)
            alpha[pad:-pad, pad:-pad] = im[:, :, -1]
            alpha2 = np.clip(smooth2d(alpha, self.pixels/72.*dpi) * 5, 0, 1)
            new_im[:, :, -1] = alpha2
            new_im[:, :, :-1] = self.color
            offsetx, offsety = -pad, -pad

            return new_im, offsetx, offsety


    class FilteredArtistList(Artist):
        """
        A simple container to draw filtered artist.
        """

        def __init__(self, artist_list, filter):
            self._artist_list = artist_list
            self._filter = filter
            Artist.__init__(self)

        def draw(self, renderer):
            renderer.start_rasterizing()
            renderer.start_filter()
            for a in self._artist_list:
                a.draw(renderer)
            renderer.stop_filter(self._filter)
            renderer.stop_rasterizing()


    def filtered_text(ax):
        # mostly copied from contour_demo.py

        # prepare image
        delta = 0.025
        x = np.arange(-3.0, 3.0, delta)
        y = np.arange(-2.0, 2.0, delta)
        X, Y = np.meshgrid(x, y)
        Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
        Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
        # difference of Gaussians
        Z = 10.0 * (Z2 - Z1)

        # draw
        im = ax.imshow(Z, interpolation='bilinear', origin='lower',
                       cmap=cm.gray, extent=(-3, 3, -2, 2))
        levels = np.arange(-1.2, 1.6, 0.2)
        CS = ax.contour(Z, levels,
                        origin='lower',
                        linewidths=2,
                        extent=(-3, 3, -2, 2))

        ax.set_aspect("auto")

        # contour label
        cl = ax.clabel(CS, levels[1::2],  # label every second level
                       inline=1,
                       fmt='%1.1f',
                       fontsize=11)

        # change clable color to black
        from matplotlib.patheffects import Normal
        for t in cl:
            t.set_color("k")
            # to force TextPath (i.e., same font in all backends)
            t.set_path_effects([Normal()])

        # Add white glows to improve visibility of labels.
        white_glows = FilteredArtistList(cl, GrowFilter(3))
        ax.add_artist(white_glows)
        white_glows.set_zorder(cl[0].get_zorder() - 0.1)

        ax.xaxis.set_visible(False)
        ax.yaxis.set_visible(False)


    def drop_shadow_line(ax):
        # copied from examples/misc/svg_filter_line.py

        # draw lines
        l1, = ax.plot([0.1, 0.5, 0.9], [0.1, 0.9, 0.5], "bo-",
                      mec="b", mfc="w", lw=5, mew=3, ms=10, label="Line 1")
        l2, = ax.plot([0.1, 0.5, 0.9], [0.5, 0.2, 0.7], "ro-",
                      mec="r", mfc="w", lw=5, mew=3, ms=10, label="Line 1")

        gauss = DropShadowFilter(4)

        for l in [l1, l2]:

            # draw shadows with same lines with slight offset.

            xx = l.get_xdata()
            yy = l.get_ydata()
            shadow, = ax.plot(xx, yy)
            shadow.update_from(l)

            # offset transform
            ot = mtransforms.offset_copy(l.get_transform(), ax.figure,
                                         x=4.0, y=-6.0, units='points')

            shadow.set_transform(ot)

            # adjust zorder of the shadow lines so that it is drawn below the
            # original lines
            shadow.set_zorder(l.get_zorder() - 0.5)
            shadow.set_agg_filter(gauss)
            shadow.set_rasterized(True)  # to support mixed-mode renderers

        ax.set_xlim(0., 1.)
        ax.set_ylim(0., 1.)

        ax.xaxis.set_visible(False)
        ax.yaxis.set_visible(False)


    def drop_shadow_patches(ax):
        # Copied from barchart_demo.py
        N = 5
        menMeans = (20, 35, 30, 35, 27)

        ind = np.arange(N)  # the x locations for the groups
        width = 0.35       # the width of the bars

        rects1 = ax.bar(ind, menMeans, width, color='r', ec="w", lw=2)

        womenMeans = (25, 32, 34, 20, 25)
        rects2 = ax.bar(ind + width + 0.1, womenMeans, width,
                        color='y', ec="w", lw=2)

        # gauss = GaussianFilter(1.5, offsets=(1,1), )
        gauss = DropShadowFilter(5, offsets=(1, 1), )
        shadow = FilteredArtistList(rects1 + rects2, gauss)
        ax.add_artist(shadow)
        shadow.set_zorder(rects1[0].get_zorder() - 0.1)

        ax.set_ylim(0, 40)

        ax.xaxis.set_visible(False)
        ax.yaxis.set_visible(False)


    def light_filter_pie(ax):
        fracs = [15, 30, 45, 10]
        explode = (0, 0.05, 0, 0)
        pies = ax.pie(fracs, explode=explode)
        ax.patch.set_visible(True)

        light_filter = LightFilter(9)
        for p in pies[0]:
            p.set_agg_filter(light_filter)
            p.set_rasterized(True)  # to support mixed-mode renderers
            p.set(ec="none",
                  lw=2)

        gauss = DropShadowFilter(9, offsets=(3, 4), alpha=0.7)
        shadow = FilteredArtistList(pies[0], gauss)
        ax.add_artist(shadow)
        shadow.set_zorder(pies[0][0].get_zorder() - 0.1)


    if 1:

        plt.figure(1, figsize=(6, 6))
        plt.subplots_adjust(left=0.05, right=0.95)

        ax = plt.subplot(221)
        filtered_text(ax)

        ax = plt.subplot(222)
        drop_shadow_line(ax)

        ax = plt.subplot(223)
        drop_shadow_patches(ax)

        ax = plt.subplot(224)
        ax.set_aspect(1)
        light_filter_pie(ax)
        ax.set_frame_on(True)

        plt.show()

**Total running time of the script:** ( 0 minutes  0.318 seconds)



.. only :: html

 .. container:: sphx-glr-footer


  .. container:: sphx-glr-download

     :download:`Download Python source code: demo_agg_filter.py <demo_agg_filter.py>`



  .. container:: sphx-glr-download

     :download:`Download Jupyter notebook: demo_agg_filter.ipynb <demo_agg_filter.ipynb>`


.. only:: html

 .. rst-class:: sphx-glr-signature

    `Gallery generated by Sphinx-Gallery <https://sphinx-gallery.readthedocs.io>`_
