Programmatically generate SVG (vector) images, animations, and interactive Jupyter widgets
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add examples to README, add dependencies for video, bump version to 1.2

+99 -180
-167
DESCRIPTION.rst
··· 1 - Most common SVG tags are supported and others can easily be added by 2 - writing a small subclass of ``DrawableBasicElement`` or 3 - ``DrawableParentElement``. 4 - 5 - Install 6 - ======= 7 - 8 - drawSvg is available on PyPI: 9 - 10 - :: 11 - 12 - $ pip3 install drawSvg 13 - 14 - Examples 15 - ======== 16 - 17 - Basic drawing elements 18 - ~~~~~~~~~~~~~~~~~~~~~~ 19 - 20 - .. code:: python 21 - 22 - d = draw.Drawing(200, 100, origin='center') 23 - 24 - d.append(draw.Lines(-80, -45, 25 - 70, -49, 26 - 95, 49, 27 - -90, 40, 28 - close=False, 29 - fill='#eeee00', 30 - stroke='black')) 31 - 32 - d.append(draw.Rectangle(0,0,40,50, fill='#1248ff')) 33 - d.append(draw.Circle(-40, -10, 30, 34 - fill='red', stroke_width=2, stroke='black')) 35 - 36 - p = draw.Path(stroke_width=2, stroke='green', 37 - fill='black', fill_opacity=0.5) 38 - p.M(-30,5) # Start path at point (-30, 5) 39 - p.l(60,30) # Draw line to (60, 30) 40 - p.h(-70) # Draw horizontal line to x=-70 41 - p.Z() # Draw line to start 42 - d.append(p) 43 - 44 - d.append(draw.ArcLine(60,-20,20,60,270, 45 - stroke='red', stroke_width=5, fill='red', fill_opacity=0.2)) 46 - d.append(draw.Arc(60,-20,20,60,270,cw=False, 47 - stroke='green', stroke_width=3, fill='none')) 48 - d.append(draw.Arc(60,-20,20,270,60,cw=True, 49 - stroke='blue', stroke_width=1, fill='black', fill_opacity=0.3)) 50 - 51 - d.setPixelScale(2) # Set number of pixels per geometry unit 52 - #d.setRenderSize(400,200) # Alternative to setPixelScale 53 - d.saveSvg('example.svg') 54 - d.savePng('example.png') 55 - 56 - # Display in iPython notebook 57 - d.rasterize() # Display as PNG 58 - d # Display as SVG 59 - 60 - .. image:: https://github.com/cduck/drawSvg/raw/master/example1.png 61 - :alt: Example output image 62 - 63 - Gradients 64 - ~~~~~~~~~ 65 - 66 - .. code:: python 67 - 68 - d = draw.Drawing(1.5, 0.8, origin='center') 69 - 70 - d.draw(draw.Rectangle(-0.75,-0.5,1.5,1, fill='#ddd')) 71 - 72 - # Create gradient 73 - gradient = draw.RadialGradient(0,-0.35,0.7*10) 74 - gradient.addStop(0.5/0.7/10, 'green', 1) 75 - gradient.addStop(1/10, 'red', 0) 76 - 77 - # Draw a shape to fill with the gradient 78 - p = draw.Path(fill=gradient, stroke='black', stroke_width=0.002) 79 - p.arc(0,-0.35,0.7,30,120) 80 - p.arc(0,-0.35,0.5,120,30,cw=True, includeL=True) 81 - p.Z() 82 - d.append(p) 83 - 84 - # Draw another shape to fill with the same gradient 85 - p = draw.Path(fill=gradient, stroke='red', stroke_width=0.002) 86 - p.arc(0,-0.35,0.75,130,160) 87 - p.arc(0,-0.35,0,160,130,cw=True, includeL=True) 88 - p.Z() 89 - d.append(p) 90 - 91 - # Another gradient 92 - gradient2 = draw.LinearGradient(0.1,-0.35,0.1+0.6,-0.35+0.2) 93 - gradient2.addStop(0, 'green', 1) 94 - gradient2.addStop(1, 'red', 0) 95 - d.append(draw.Rectangle(0.1,-0.35,0.6,0.2, 96 - stroke='black', stroke_width=0.002, 97 - fill=gradient2)) 98 - 99 - # Display 100 - d.setRenderSize(w=600) 101 - d 102 - 103 - .. image:: https://github.com/cduck/drawSvg/raw/master/example2.png 104 - :alt: Example output image 105 - 106 - Duplicate geometry and clip paths 107 - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 108 - 109 - .. code:: python 110 - 111 - d = draw.Drawing(1.4, 1.4, origin='center') 112 - 113 - # Define clip path 114 - clip = draw.ClipPath() 115 - clip.append(draw.Rectangle(-.25,.25-1,1,1)) 116 - 117 - # Draw a cropped circle 118 - c = draw.Circle(0,0,0.5, stroke_width='0.01', stroke='black', 119 - fill_opacity=0.3, clip_path=clip, 120 - id='circle') 121 - d.append(c) 122 - 123 - # Make a transparent copy, cropped again 124 - g = draw.Group(opacity=0.5, clip_path=clip) 125 - g.append(draw.Use('circle', 0.25,0.1)) 126 - d.append(g) 127 - 128 - # Display 129 - d.setRenderSize(400) 130 - d.rasterize() 131 - 132 - .. image:: https://github.com/cduck/drawSvg/raw/master/example3.png 133 - :alt: Example output image 134 - 135 - Implementing other SVG tags 136 - ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 137 - 138 - .. code:: python 139 - 140 - # Subclass DrawingBasicElement if it cannot have child nodes 141 - # Subclass DrawingParentElement otherwise 142 - # Subclass DrawingDef if it must go between <def></def> tags in an SVG 143 - class Hyperlink(draw.DrawingParentElement): 144 - TAG_NAME = 'a' 145 - def __init__(self, href, target=None, **kwargs): 146 - # Other init logic... 147 - # Keyword arguments to super().__init__() correspond to SVG node 148 - # arguments: stroke_width=5 -> stroke-width="5" 149 - super().__init__(href=href, target=target, **kwargs) 150 - 151 - d = draw.Drawing(1, 1.2, origin='center') 152 - 153 - # Create hyperlink 154 - hlink = Hyperlink('https://www.python.org', target='_blank', 155 - transform='skewY(-30)') 156 - # Add child elements 157 - hlink.append(draw.Circle(0,0,0.5, fill='green')) 158 - hlink.append(draw.Text('Hyperlink',0.2, 0,0, center=0.6, fill='white')) 159 - 160 - # Draw and display 161 - d.append(hlink) 162 - d.setRenderSize(200) 163 - d 164 - 165 - .. image:: https://github.com/cduck/drawSvg/raw/master/example4.png 166 - :alt: Example output image 167 -
+86 -5
README.md
··· 1 1 # drawSvg 2 2 3 - This is a Python 3 library for programmatically generating SVG images (vector drawings) and rendering them or displaying them in an iPython notebook. 3 + A Python 3 library for programmatically generating SVG images (vector drawings) and rendering them or displaying them in an iPython notebook. 4 4 5 5 Most common SVG tags are supported and others can easily be added by writing a small subclass of `DrawableBasicElement` or `DrawableParentElement`. 6 + 7 + An interactive Jupyter widget, `drawSvg.widgets.DrawingWidget`, is included that can update drawings based on mouse events. 6 8 7 9 # Install 8 10 drawSvg is available on PyPI: ··· 56 58 d # Display as SVG 57 59 ``` 58 60 59 - ![Example output image](https://github.com/cduck/drawSvg/raw/master/example1.png) 61 + ![Example output image](https://raw.githubusercontent.com/cduck/drawSvg/master/examples/example1.png) 60 62 61 63 ### Gradients 62 64 ```python ··· 98 100 d 99 101 ``` 100 102 101 - ![Example output image](https://github.com/cduck/drawSvg/raw/master/example2.png) 103 + ![Example output image](https://raw.githubusercontent.com/cduck/drawSvg/master/examples/example2.png) 102 104 103 105 ### Duplicate geometry and clip paths 104 106 ```python ··· 126 128 d.rasterize() 127 129 ``` 128 130 129 - ![Example output image](https://github.com/cduck/drawSvg/raw/master/example3.png) 131 + ![Example output image](https://raw.githubusercontent.com/cduck/drawSvg/master/examples/example3.png) 130 132 131 133 ### Implementing other SVG tags 132 134 ```python ··· 158 160 d 159 161 ``` 160 162 161 - ![Example output image](https://github.com/cduck/drawSvg/blob/master/example4.svg) 163 + ![Example output image](https://github.com/cduck/drawSvg/blob/master/examples/example4.svg) 164 + 165 + ### Interactive Widget 166 + ```python 167 + import drawSvg as draw 168 + from drawSvg.widgets import DrawingWidget 169 + import hyperbolic.poincare.shapes as hyper # pip3 install hyperbolic 170 + 171 + # Create drawing 172 + d = draw.Drawing(2, 2, origin='center') 173 + d.setRenderSize(500) 174 + d.append(draw.Circle(0, 0, 1, fill='orange')) 175 + group = draw.Group() 176 + d.append(group) 177 + 178 + # Update the drawing based on user input 179 + click_list = [] 180 + def redraw(points): 181 + group.children.clear() 182 + for x1, y1 in points: 183 + for x2, y2 in points: 184 + if (x1, y1) == (x2, y2): continue 185 + p1 = hyper.Point.fromEuclid(x1, y1) 186 + p2 = hyper.Point.fromEuclid(x2, y2) 187 + if p1.distanceTo(p2) <= 2: 188 + line = hyper.Line.fromPoints(*p1, *p2, segment=True) 189 + group.draw(line, hwidth=0.2, fill='white') 190 + for x, y in points: 191 + p = hyper.Point.fromEuclid(x, y) 192 + group.draw(hyper.Circle.fromCenterRadius(p, 0.1), 193 + fill='green') 194 + redraw(click_list) 195 + 196 + # Create interactive widget and register mouse events 197 + widget = DrawingWidget(d) 198 + @widget.mousedown 199 + def mousedown(widget, x, y, info): 200 + if (x**2 + y**2) ** 0.5 + 1e-5 < 1: 201 + click_list.append((x, y)) 202 + redraw(click_list) 203 + widget.refresh() 204 + @widget.mousemove 205 + def mousemove(widget, x, y, info): 206 + if (x**2 + y**2) ** 0.5 + 1e-5 < 1: 207 + redraw(click_list + [(x, y)]) 208 + widget.refresh() 209 + widget 210 + ``` 211 + 212 + ![Example output image](https://raw.githubusercontent.com/cduck/drawSvg/master/examples/example5.gif) 213 + 214 + ### Animation 215 + ```python 216 + import drawSvg as draw 217 + 218 + # Draw a frame of the animation 219 + def draw_frame(t): 220 + d = draw.Drawing(2, 6.05, origin=(-1,-1.05)) 221 + d.setRenderSize(h=300) 222 + d.append(draw.Rectangle(-2, -2, 4, 8, fill='white')) 223 + d.append(draw.Rectangle(-1, -1.05, 2, 0.05, fill='brown')) 224 + t = (t + 1) % 2 - 1 225 + y = 4 - t**2 * 4 226 + d.append(draw.Circle(0, y, 1, fill='lime')) 227 + return d 228 + 229 + with draw.animate_jupyter(draw_frame, delay=0.05) as anim: 230 + # Or: 231 + #with draw.animate_video('example6.gif', draw_frame, duration=0.05 232 + # ) as anim: 233 + # Add each frame to the animation 234 + for i in range(20): 235 + anim.draw_frame(i/10) 236 + for i in range(20): 237 + anim.draw_frame(i/10) 238 + for i in range(20): 239 + anim.draw_frame(i/10) 240 + ``` 241 + 242 + ![Example output image](https://raw.githubusercontent.com/cduck/drawSvg/master/examples/example6.gif) 162 243
example1.png examples/example1.png
example1.svg examples/example1.svg
example2.png examples/example2.png
example2.svg examples/example2.svg
example3.png examples/example3.png
example3.svg examples/example3.svg
example4.png examples/example4.png
example4.svg examples/example4.svg
examples/example5.gif

This is a binary file and will not be displayed.

examples/example6.gif

This is a binary file and will not be displayed.

+13 -8
setup.py
··· 1 1 from setuptools import setup, find_packages 2 + import logging 3 + logger = logging.getLogger(__name__) 2 4 3 - version = '1.1.0' 5 + version = '1.2.0' 4 6 5 7 try: 6 - with open('DESCRIPTION.rst', 'r') as f: 7 - longDesc = f.read() 8 + with open('README.md', 'r') as f: 9 + long_desc = f.read() 8 10 except: 9 - print('Warning: Could not open DESCRIPTION.rst. long_description will be set to None.') 10 - longDesc = None 11 + logger.warning('Could not open README.md. long_description will be set to None.') 12 + long_desc = None 11 13 12 14 setup( 13 15 name = 'drawSvg', 14 16 packages = find_packages(), 15 17 version = version, 16 - description = 'This is a Python 3 library for programmatically generating SVG images (vector drawings) and rendering them or displaying them in an iPython notebook.', 17 - long_description = longDesc, 18 + description = 'A Python 3 library for programmatically generating SVG images (vector drawings) and rendering them or displaying them in an iPython notebook.', 19 + long_description = long_desc, 20 + long_description_content_type = 'text/markdown', 18 21 author = 'Casey Duckering', 19 22 #author_email = '', 20 23 url = 'https://github.com/cduck/drawSvg', 21 24 download_url = 'https://github.com/cduck/drawSvg/archive/{}.tar.gz'.format(version), 22 - keywords = ['SVG', 'draw', 'graphics', 'iPython', 'Jupyter'], 25 + keywords = ['SVG', 'draw', 'graphics', 'iPython', 'Jupyter', 'widget'], 23 26 classifiers = [ 24 27 'License :: OSI Approved :: MIT License', 25 28 'Programming Language :: Python :: 3', ··· 28 31 ], 29 32 install_requires = [ 30 33 'cairoSVG', 34 + 'numpy', 35 + 'imageio', 31 36 ], 32 37 ) 33 38