
# ShowSVG.py
# Andrew Davison, ad@coe.psu.ac.th, April 2025
'''
Load an SVG file containing multiple paths, and 
display in matplotlib as a PathCollection resized
to be a unit square with the origin at the bottom left.

Based on code at
  https://nbviewer.org/github/nvictus/svgpath2mpl/blob/master/examples/homer.ipynb

'''
import math
import xml.etree.ElementTree as ET
import re

import matplotlib as mpl
from matplotlib import pyplot as plt
from matplotlib.transforms import Affine2D

from svgpath2mpl import parse_path
  
fnm = input("SVG filename (no extension): ")
SVGtext = open(fnm+'.svg', 'r', encoding='utf-8').read()

# parse XML
tree = ET.ElementTree(ET.fromstring(SVGtext))
root = tree.getroot()
width = int(re.match(r'\d+', root.attrib['width']).group())
height = int(re.match(r'\d+', root.attrib['height']).group())
path_elems = root.findall('.//{http://www.w3.org/2000/svg}path')

# extract SVG info from the paths
paths = [parse_path(elem.attrib['d']) for elem in path_elems]
facecolors = [elem.attrib.get('fill', 'none') for elem in path_elems]
edgecolors = [elem.attrib.get('stroke', 'none') for elem in path_elems]
linewidths = [elem.attrib.get('stroke_width', 1) for elem in path_elems]

# build a Matplotlib paths collection
pc = mpl.collections.PathCollection(paths, 
                                  edgecolors=edgecolors, 
                                  linewidths=linewidths,
                                  facecolors=facecolors)
# display in a 1 x 1 grid
fig = plt.figure(figsize=(5,5))
ax = fig.add_subplot(111)
ax.set_xlim([0, 1])
ax.set_ylim([0, 1])

# scale and reflect in x-axis, then move up
trans = Affine2D().scale(1/width, -1/height).translate(0, 1)
                 #.rotate_deg(30)

pc.set_transform(trans + ax.transData)
ax.add_artist(pc)

plt.title(fnm)
plt.show()