Need help with drawSvg?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

230 Stars 40 Forks MIT License 78 Commits 15 Opened issues


A Python 3 library for programmatically generating SVG images (vector drawings) and rendering them or displaying them in a Jupyter notebook

Services available


Need anything else?

Contributors list

# 95,628
67 commits
# 101,513
1 commit
# 439,763
1 commit
# 91,892
1 commit
# 546,316
Data vi...
1 commit
# 493,738
1 commit
# 273,575
1 commit


A Python 3 library for programmatically generating SVG images (vector drawings) and rendering them or displaying them in a Jupyter notebook.

Most common SVG tags are supported and others can easily be added by writing a small subclass of


An interactive Jupyter notebook widget,

, is included that can update drawings based on mouse events.


drawSvg is available on PyPI:

$ pip3 install drawSvg


Cairo needs to be installed separately. When Cairo is installed, drawSvg can output PNG or other image formats in addition to SVG. See platform-specific instructions for Linux, Windows, and macOS from Cairo. Below are some examples for installing Cairo on Linux distributions and macOS.


$ sudo apt-get install libcairo2


Using homebrew:

$ brew install cairo


Basic drawing elements

import drawSvg as draw

d = draw.Drawing(200, 100, origin='center', displayInline=False)

Draw an irregular polygon

d.append(draw.Lines(-80, -45, 70, -49, 95, 49, -90, 40, close=False, fill='#eeee00', stroke='black'))

Draw a rectangle

r = draw.Rectangle(-80,0,40,50, fill='#1248ff') r.appendTitle("Our first rectangle") # Add a tooltip d.append(r)

Draw a circle

d.append(draw.Circle(-40, -10, 30, fill='red', stroke_width=2, stroke='black'))

Draw an arbitrary path (a triangle in this case)

p = draw.Path(stroke_width=2, stroke='lime', fill='black', fill_opacity=0.2) p.M(-10, 20) # Start path at point (-10, 20) p.C(30, -10, 30, 50, 70, 20) # Draw a curve to (70, 20) d.append(p)

Draw text

d.append(draw.Text('Basic text', 8, -10, 35, fill='blue')) # Text with font size 8 d.append(draw.Text('Path text', 8, path=p, text_anchor='start', valign='middle')) d.append(draw.Text(['Multi-line', 'text'], 8, path=p, text_anchor='end'))

Draw multiple circular arcs

d.append(draw.ArcLine(60,-20,20,60,270, stroke='red', stroke_width=5, fill='red', fill_opacity=0.2)) d.append(draw.Arc(60,-20,20,60,270,cw=False, stroke='green', stroke_width=3, fill='none')) d.append(draw.Arc(60,-20,20,270,60,cw=True, stroke='blue', stroke_width=1, fill='black', fill_opacity=0.3))

Draw arrows

arrow = draw.Marker(-0.1, -0.5, 0.9, 0.5, scale=4, orient='auto') arrow.append(draw.Lines(-0.1, -0.5, -0.1, 0.5, 0.9, 0, fill='red', close=True)) p = draw.Path(stroke='red', stroke_width=2, fill='none', marker_end=arrow) # Add an arrow to the end of a path p.M(20, -40).L(20, -27).L(0, -20) # Chain multiple path operations d.append(p) d.append(draw.Line(30, -20, 0, -10, stroke='red', stroke_width=2, fill='none', marker_end=arrow)) # Add an arrow to the end of a line

d.setPixelScale(2) # Set number of pixels per geometry unit #d.setRenderSize(400,200) # Alternative to setPixelScale d.saveSvg('example.svg') d.savePng('example.png')

Display in Jupyter notebook

d.rasterize() # Display as PNG d # Display as SVG

Example output image


import drawSvg as draw

d = draw.Drawing(1.5, 0.8, origin='center')

d.draw(draw.Rectangle(-0.75,-0.5,1.5,1, fill='#ddd'))

Create gradient

gradient = draw.RadialGradient(0,-0.35,0.7*10) gradient.addStop(0.5/0.7/10, 'green', 1) gradient.addStop(1/10, 'red', 0)

Draw a shape to fill with the gradient

p = draw.Path(fill=gradient, stroke='black', stroke_width=0.002) p.arc(0,-0.35,0.7,30,120) p.arc(0,-0.35,0.5,120,30,cw=True, includeL=True) p.Z() d.append(p)

Draw another shape to fill with the same gradient

p = draw.Path(fill=gradient, stroke='red', stroke_width=0.002) p.arc(0,-0.35,0.75,130,160) p.arc(0,-0.35,0,160,130,cw=True, includeL=True) p.Z() d.append(p)

Another gradient

gradient2 = draw.LinearGradient(0.1,-0.35,0.1+0.6,-0.35+0.2) gradient2.addStop(0, 'green', 1) gradient2.addStop(1, 'red', 0) d.append(draw.Rectangle(0.1,-0.35,0.6,0.2, stroke='black', stroke_width=0.002, fill=gradient2))


d.setRenderSize(w=600) d

Example output image

Duplicate geometry and clip paths

import drawSvg as draw

d = draw.Drawing(1.4, 1.4, origin='center')

Define clip path

clip = draw.ClipPath() clip.append(draw.Rectangle(-.25,.25-1,1,1))

Draw a cropped circle

c = draw.Circle(0,0,0.5, stroke_width='0.01', stroke='black', fill_opacity=0.3, clip_path=clip, id='circle') d.append(c)

Make a transparent copy, cropped again

g = draw.Group(opacity=0.5, clip_path=clip) g.append(draw.Use('circle', 0.25,0.1)) d.append(g)


d.setRenderSize(400) d.rasterize()

Example output image

Implementing other SVG tags

import drawSvg as draw

Subclass DrawingBasicElement if it cannot have child nodes

Subclass DrawingParentElement otherwise

Subclass DrawingDef if it must go between tags in an SVG

class Hyperlink(draw.DrawingParentElement): TAG_NAME = 'a' def init(self, href, target=None, **kwargs): # Other init logic... # Keyword arguments to super().init() correspond to SVG node # arguments: stroke_width=5 -> stroke-width="5" super().init(href=href, target=target, **kwargs)

d = draw.Drawing(1, 1.2, origin='center')

Create hyperlink

hlink = Hyperlink('', target='_blank', transform='skewY(-30)')

Add child elements

hlink.append(draw.Circle(0,0,0.5, fill='green')) hlink.append(draw.Text('Hyperlink',0.2, 0,0, center=0.6, fill='white'))

Draw and display

d.append(hlink) d.setRenderSize(200) d

Example output image

Animation with the SVG Animate Tag

import drawSvg as draw

d = draw.Drawing(200, 200, origin='center')

Animate the position and color of circle

c = draw.Circle(0, 0, 20, fill='red')

See for supported attributes:

c.appendAnim(draw.Animate('cy', '6s', '-80;80;-80', repeatCount='indefinite')) c.appendAnim(draw.Animate('cx', '6s', '0;80;0;-80;0', repeatCount='indefinite')) c.appendAnim(draw.Animate('fill', '6s', 'red;green;blue;yellow', calcMode='discrete', repeatCount='indefinite')) d.append(c)

Animate a black circle around an ellipse

ellipse = draw.Path() ellipse.M(-90, 0) ellipse.A(90, 40, 360, True, True, 90, 0) # Ellipse path ellipse.A(90, 40, 360, True, True, -90, 0) ellipse.Z() c2 = draw.Circle(0, 0, 10)

See for supported attributes:

c2.appendAnim(draw.AnimateMotion(ellipse, '3s', repeatCount='indefinite'))

See for supported attributes:

c2.appendAnim(draw.AnimateTransform('scale', '3s', '1,2;2,1;1,2;2,1;1,2', repeatCount='indefinite')) d.append(c2)

d.saveSvg('animated.svg') # Save to file d # Display in Jupyter notebook

Example output image

Interactive Widget

import drawSvg as draw
from drawSvg.widgets import DrawingWidget
import hyperbolic.poincare.shapes as hyper  # pip3 install hyperbolic

Create drawing

d = draw.Drawing(2, 2, origin='center') d.setRenderSize(500) d.append(draw.Circle(0, 0, 1, fill='orange')) group = draw.Group() d.append(group)

Update the drawing based on user input

click_list = [] def redraw(points): group.children.clear() for x1, y1 in points: for x2, y2 in points: if (x1, y1) == (x2, y2): continue p1 = hyper.Point.fromEuclid(x1, y1) p2 = hyper.Point.fromEuclid(x2, y2) if p1.distanceTo(p2) <= 2: line = hyper.Line.fromPoints(*p1, *p2, segment=True) group.draw(line, hwidth=0.2, fill='white') for x, y in points: p = hyper.Point.fromEuclid(x, y) group.draw(hyper.Circle.fromCenterRadius(p, 0.1), fill='green') redraw(click_list)

Create interactive widget and register mouse events

widget = DrawingWidget(d) @widget.mousedown def mousedown(widget, x, y, info): if (x2 + y2) ** 0.5 + 1e-5 < 1: click_list.append((x, y)) redraw(click_list) widget.refresh() @widget.mousemove def mousemove(widget, x, y, info): if (x2 + y2) ** 0.5 + 1e-5 < 1: redraw(click_list + [(x, y)]) widget.refresh() widget

Example output image

Animation with Python

import drawSvg as draw

Draw a frame of the animation

def draw_frame(t): d = draw.Drawing(2, 6.05, origin=(-1,-1.05)) d.setRenderSize(h=300) d.append(draw.Rectangle(-2, -2, 4, 8, fill='white')) d.append(draw.Rectangle(-1, -1.05, 2, 0.05, fill='brown')) t = (t + 1) % 2 - 1 y = 4 - t**2 * 4 d.append(draw.Circle(0, y, 1, fill='lime')) return d

with draw.animate_jupyter(draw_frame, delay=0.05) as anim:


#with draw.animate_video('example6.gif', draw_frame, duration=0.05

) as anim:

# Add each frame to the animation
for i in range(20):
for i in range(20):
for i in range(20):

Example output image

Asynchronous Animation in Jupyter

# Jupyter cell 1:
import drawSvg as draw
from drawSvg.widgets import AsyncAnimation
widget = AsyncAnimation(fps=10)
# [Animation is displayed here (click to pause)]

Jupyter cell 2:

global_variable = 'a' @widget.set_draw_frame # Animation above is automatically updated def draw_frame(secs=0): # Draw something... d = draw.Drawing(100, 40) d.append(draw.Text(global_variable, 20, 0, 10)) d.append(draw.Text('{:0.1f}'.format(secs), 20, 30, 10)) return d

Jupyter cell 3:

global_variable = 'b' # Animation above now displays 'b'

Example output image

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.