If not already installed, you can **install the prerequisites** usingpip.

.. code:: bash

$ pip install numpy

.. code:: bash

$ pip install svgwrite

Then **install svgpathtools**:

.. code:: bash

$ pip install svgpathtools

Alternative Setup~~~~~~~~~~~~~~~~~

You can download the source from Github and install by using the command(from inside the folder containing setup.py):

.. code:: bash

$ python setup.py install

Credit where credit's due-------------------------

Much of the core of this module was taken from `the svg.path (v2.0)module <https://github.com/regebro/svg.path>`__. Interested svg.pathusers should see the compatibility notes at bottom of this readme.

See the relevant docstrings in *path.py* or the `official SVGspecifications <http://www.w3.org/TR/SVG/paths.html>`__ for moreinformation on what each parameter means.

1 Warning: Some of the functionality in this library has not been testedon discontinuous Path objects. A simple workaround is provided, however,by the ``Path.continuous_subpaths()`` method. `↩ <#a1>`__

.. code:: ipython2

from __future__ import division, print_function

.. code:: ipython2

# Coordinates are given as points in the complex plane from svgpathtools import Path, Line, QuadraticBezier, CubicBezier, Arc seg1 = CubicBezier(300+100j, 100+100j, 200+200j, 200+300j) # A cubic beginning at (300, 100) and ending at (200, 300) seg2 = Line(200+300j, 250+350j) # A line beginning at (200, 300) and ending at (250, 350) path = Path(seg1, seg2) # A path traversing the cubic and then the line

# If we want, we can smooth these out (Experimental and only for line/cubic paths) # Note: smoothing will always works (except on 180 degree turns), but you may want # to play with the maxjointsize and tightness parameters to get pleasing results # Note also: smoothing will increase the number of segments in a path spath = smoothed_path(path) print("spath contains non-differentiable points? ", len(kinks(spath)) > 0) print(spath)

# Let's take a quick look at the path and its smoothed relative # The following commands will open two browser windows to display path and spaths from svgpathtools import disvg from time import sleep disvg(path) sleep(1) # needed when not giving the SVGs unique names (or not using timestamp) disvg(spath) print("Notice that path contains {} segments and spath contains {} segments." "".format(len(path), len(spath)))

| The **svg2paths()** function converts an svgfile to a list of Path objects and a separate list of dictionaries containing the attributes of each said path.| Note: Line, Polyline, Polygon, and Path SVG elements can all be converted to Path objects using this function.

# Update: You can now also extract the svg-attributes by setting # return_svg_attributes=True, or with the convenience function svg2paths2 from svgpathtools import svg2paths2 paths, attributes, svg_attributes = svg2paths2('test.svg')

# Let's print out the first path object and the color it was in the SVG # We'll see it is composed of two CubicBezier objects and, in the SVG file it # came from, it was red redpath = paths[0] redpath_attribs = attributes[0] print(redpath) print(redpath_attribs['stroke'])

The **wsvg()** function creates an SVG file from a list of path. Thisfunction can do many things (see docstring in *paths2svg.py* for moreinformation) and is meant to be quick and easy to use. Note: Use theconvenience function **disvg()** (or set 'openinbrowser=True') toautomatically attempt to open the created svg file in your default SVGviewer.

.. code:: ipython2

# Let's make a new SVG that's identical to the first wsvg(paths, attributes=attributes, svg_attributes=svg_attributes, filename='output1.svg')

There will be many more examples of writing and displaying path databelow.

The .point() method and transitioning between path and path segment parameterizations~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

SVG Path elements and their segments have official parameterizations.These parameterizations can be accessed using the ``Path.point()``,``Line.point()``, ``QuadraticBezier.point()``, ``CubicBezier.point()``,and ``Arc.point()`` methods. All these parameterizations are definedover the domain 0 <= t <= 1.

| **Note:** In this document and in inline documentation and doctrings, I use a capital ``T`` when referring to the parameterization of a Path object and a lower case ``t`` when referring speaking about path segment objects (i.e. Line, QaudraticBezier, CubicBezier, and Arc objects).| Given a ``T`` value, the ``Path.T2t()`` method can be used to find the corresponding segment index, ``k``, and segment parameter, ``t``, such that ``path.point(T)=path[k].point(t)``.| There is also a ``Path.t2T()`` method to solve the inverse problem.

.. code:: ipython2

# Example:

# Let's check that the first segment of redpath starts # at the same point as redpath firstseg = redpath[0] print(redpath.point(0) == firstseg.point(0) == redpath.start == firstseg.start)

# Let's check that the last segment of redpath ends on the same point as redpath lastseg = redpath[-1] print(redpath.point(1) == lastseg.point(1) == redpath.end == lastseg.end)

# This next boolean should return False as redpath is composed multiple segments print(redpath.point(0.5) == firstseg.point(0.5))

# If we want to figure out which segment of redpoint the # point redpath.point(0.5) lands on, we can use the path.T2t() method k, t = redpath.T2t(0.5) print(redpath[k].point(t) == redpath.point(0.5))

| Another great way to work with the parameterizations for ``Line``, ``QuadraticBezier``, and ``CubicBezier`` objects is to convert them to ``numpy.poly1d`` objects. This is done easily using the ``Line.poly()``, ``QuadraticBezier.poly()`` and ``CubicBezier.poly()`` methods.| There's also a ``polynomial2bezier()`` function in the pathtools.py submodule to convert polynomials back to Bezier curves.

where :math:`P_0`, :math:`P_1`, :math:`P_2`, and :math:`P_3` are thecontrol points ``start``, ``control1``, ``control2``, and ``end``,respectively, that svgpathtools uses to define a CubicBezier object. The``CubicBezier.poly()`` method expands this polynomial to its standardform

To further illustrate the power of being able to convert our Beziercurve objects to numpy.poly1d objects and back, lets compute the unittangent vector of the above CubicBezier object, b, at t=0.5 in fourdifferent ways.

# and let's reverse the orientation of b! # the tangent and normal lines should be sent to their opposites br = b.reversed()

# Let's also shift b_r over a bit to the right so we can view it next to b # The simplest way to do this is br = br.translated(3*mag), but let's use # the .bpoints() instead, which returns a Bezier's control points br.start, br.control1, br.control2, br.end = [3*mag + bpt for bpt in br.bpoints()] #

# Now let's add the decorations for k in range(12): decorated_ellipse.append(midline.rotated(30*k))

# Let's move it over so we can see the original Line and Arc object next # to the final product decorated_ellipse = decorated_ellipse.translated(4+0j) wsvg([top_half, midline, decorated_ellipse], filename='decorated_ellipse.svg')

Here we'll create an SVG that shows off the parametric and geometricmidpoints of the paths from ``test.svg``. We'll need to compute use the``Path.length()``, ``Line.length()``, ``QuadraticBezier.length()``,``CubicBezier.length()``, and ``Arc.length()`` methods, as well as therelated inverse arc length methods ``.ilength()`` function to do this.