Skip to content
scipython.com

P4.4.3Creating a set of SVG image files

Write a Python program to create a directory, test in the user's home directory and to populate it with 20 SVG files depicting a small, filled red circle inside a large, black, unfilled circle, for example:

<?xml version="1.0" encoding="utf-8"?>
                 <svg xmlns="http://www.w3.org/2000/svg"
                      xmlns:xlink="http://www.w3.org/1999/xlink"
                      width="500" height="500" style="background: #ffffff">
<circle cx="250.0" cy="250.0" r="200" style="stroke: black; stroke-width: 2px; fill: none;"/>
<circle cx="430.0" cy="250.0" r="20" style="stroke: red; fill: red;"/>
</svg>

Each file should move the red circle around the inside rim of the larger circle so that the 20 files together could form an animation.

One way to achieve this using the free ImageMagick software. Ensure the SVG files are named: fig00.svg, fig01.svg, etc. and issue the following command from your operating system's command line:

$ convert -delay 5 -loop 0 fig*.svg animation.gif

to produce an animated GIF image.

Show solution

Here is one approach.

import os
import math

nfigs = 20
HOME = os.getenv('HOME')
pathdir = os.path.join(HOME, 'test')
if not os.path.exists(pathdir):
    os.mkdir(pathdir)

canvas_height, canvas_width = 500, 500
cx, cy = canvas_height / 2, canvas_width / 2
r1, r2 = 200, 20

# A list of angles to rotate the small red circle through:
alphas = [2*math.pi / nfigs * n for n in range(nfigs)]

for n, alpha in enumerate(alphas):
    filename = os.path.join(pathdir, f'fig{n:02d}.svg')
    with open(filename, 'w') as fo:
        # SVG preamble
        print("""<?xml version="1.0" encoding="utf-8"?>
                 <svg xmlns="http://www.w3.org/2000/svg"
                      xmlns:xlink="http://www.w3.org/1999/xlink"
                      width="{}" height="{}" style="background: {}">""".format(
                        canvas_width, canvas_height, '#ffffff'), file=fo)

        # Large, open black circle
        print(f'<circle cx="{cx}" cy="{cy}" r="{r1}" style="stroke: black;'
              f' stroke-width: 2px; fill: none;"/>', file=fo)

        # Small, filled red circle on the inner rim of the black one,
        # displaced from the x-axis by the angle alpha
        cx2, cy2 = cx+(r1-r2) * math.cos(alpha), cy+(r1-r2) * math.sin(alpha)
        print(f'<circle cx="{cx2}" cy="{cy2}" r="{r2}" style="stroke: red; fill: red;"/>',
                                file=fo)

        print('</svg>', file=fo)

Running these files through ImageMagick's convert program as suggested generates the animated GIF below.

A red circle moving around the circumference on the inside of a larger circle