Wednesday, October 29, 2008

Applying Filter Effects on SVG files created using Matplotlib

SVG Filter Effects

Using SVG Filter Effects, some fancy effects can be applied relatively easily.

While this can be done using applications like Inkscape, it is also possible to apply a few simple filter effects using python script. For example, using python, you can read in the original svg file as a DOM tree, modify the tree as necessary (adding the definition of filters, setting the filter attributes to the objects in your interest), and save it as a new svg file.

Original matplotlib figure

After applying SVG Filters,

The Python script used

  • Note that the original svg file is generated from the slightly modified version of matplotlib SVG backend, which sets the id attributes of patches with its label names. In this way, you can pick the objects you want by their id after you read in the svg file.

import xml.etree.cElementTree as ET

# filter definition for a dropshadow using a gaussian blur

# and etc
filter = """
  <defs  xmlns='' xmlns:xlink=''>
    <filter id='dropshadow' height='1.2' width='1.2'>
      <feGaussianBlur result='blur' stdDeviation='2'/>
    <filter id='MyFilter' filterUnits='objectBoundingBox' x='0' y='0' width='1' height='1'>
      <feGaussianBlur in='SourceAlpha' stdDeviation='4%' result='blur'/>
      <feOffset in='blur' dx='4%' dy='4%' result='offsetBlur'/>
      <feSpecularLighting in='blur' surfaceScale='5' specularConstant='.75'
           specularExponent='20' lighting-color='#bbbbbb' result='specOut'>
        <fePointLight x='-5000%' y='-10000%' z='20000%'/>
      <feComposite in='specOut' in2='SourceAlpha' operator='in' result='specOut'/>
      <feComposite in='SourceGraphic' in2='specOut' operator='arithmetic'
    k1='0' k2='1' k3='1' k4='0'/>

tree, xmlid = ET.XMLID(open("pie_demo.svg").read())

# insert the filter definition in the svg dom tree.
filters = ET.XML(filter)
tree.insert(0, filters)

for i, pie_name in enumerate(['Frogs', 'Hogs', 'Dogs', 'Logs']):

    pie = xmlid[pie_name]

    pie.set("filter", 'url(#MyFilter)')

    shadow = xmlid[pie_name + "_shadow"]


Other than the filter definition string, the code to modify the SVG DOM tree is quite simple.