svgpathtools
svgpathtools is a Python library (version 1.7.2) for manipulating and analyzing SVG Path objects and Bézier curves. It offers functions to read, write, and display SVG files, convert Bézier segments to polynomials, compute tangents, curvature, intersections, and perform various geometric transformations. It is actively maintained with releases as needed.
Common errors
-
could not convert string to float: 's'
cause This error, or similar ones like 'list index out of range', often occurs when `svgpathtools.parse_path()` attempts to parse an SVG path `d` attribute string that is malformed or contains unexpected characters/commands. This can happen with complex SVG exports from graphic design software (e.g., Inkscape) that might use non-standard or subtly incorrect syntax for path commands.fixValidate the SVG `d` string against the official SVG Path Data specification. Simplify the path in the originating software, or manually inspect and correct the `d` attribute string. Ensure all path commands (M, L, C, A, Z, etc.) are correctly capitalized (for absolute coordinates) or lowercase (for relative coordinates) and have the correct number of parameters. -
SVG groups are ignored. Especially transformations acting on the paths inside the group.
cause The `svg2paths()` function processes path elements directly and does not automatically apply transformations defined on parent `<g>` (group) elements in the SVG document structure.fixAfter reading the paths using `svg2paths()`, you need to manually traverse the SVG's DOM (e.g., using `xml.etree.ElementTree`) to identify parent group transformations and apply them to the respective child paths. The `Document` class (experimental) aims to provide a higher-level API that might simplify this in the future.
Warnings
- gotcha The `svg2paths()` function currently ignores SVG group (<g>) transformations when parsing files. Paths inside groups will be read without the parent group's transformations applied.
- gotcha Some functionality within `svgpathtools`, particularly concerning discontinuous `Path` objects, has not been fully tested and might lead to unexpected behavior.
- gotcha The `Path.scaled()` method might produce visual artifacts or unexpected 'cavities' in paths when using very small scaling factors (e.g., below ~0.45). This could be due to internal segmentation or precision issues.
- deprecated The `svg2paths` function's argument signature in older installed versions (e.g., via `pip3`) might not perfectly match the latest documentation or GitHub source, particularly regarding `convert_circles_to_paths` and `convert_ellipses_to_paths` arguments.
Install
-
pip install svgpathtools
Imports
- Path
from svgpathtools import Path
- Line, QuadraticBezier, CubicBezier, Arc
from svgpathtools import Line, QuadraticBezier, CubicBezier, Arc
- svg2paths
from svgpathtools import svg2paths
- wsvg
from svgpathtools import wsvg
- Path
from svg.path import Path
from svgpathtools import Path
Quickstart
from svgpathtools import svg2paths, wsvg, Path, Line, CubicBezier
import os
# Create a dummy SVG file for demonstration
with open('example.svg', 'w') as f:
f.write('<svg width="200" height="200">')
f.write('<path d="M10 10 L100 10 L100 100 L10 100 Z" fill="blue"/>')
f.write('</svg>')
# 1. Read paths from an existing SVG file
paths, attributes = svg2paths('example.svg')
print(f"Read {len(paths)} path(s) from example.svg")
# 2. Manipulate a path (e.g., scale the first path)
if paths:
original_path = paths[0]
# Scale the path by 0.5
scaled_path = original_path.scaled(0.5)
paths[0] = scaled_path
print(f"Scaled the first path. New length: {scaled_path.length():.2f}")
# 3. Create a new path programmatically
new_segment1 = Line(start=10+10j, end=50+100j)
new_segment2 = CubicBezier(start=50+100j, control1=150+50j, control2=50+150j, end=150+100j)
new_path = Path(new_segment1, new_segment2)
# Add the new path to the list and assign attributes
paths.append(new_path)
attributes.append({'fill': 'red', 'stroke': 'black', 'stroke-width': '2'})
# 4. Write the modified and new paths to a new SVG file
wsvg(paths, attributes=attributes, filename='output.svg', openinbrowser=False)
print("Modified paths written to output.svg")
# Clean up dummy file (optional)
os.remove('example.svg')
# os.remove('output.svg') # Uncomment to remove output file after inspection