Friday, August 9, 2024

Embedding an SVG in a graphviz Generated SVG and More DAG Hamilton

Last time I used a previous post's DAG Hamilton graphviz output to generate a series of functionally highlighted DAG Hamilton workflow graphs. The  SVG (scalable vector graphics) versions of these graphs will serve as the input for this post.

I was dissatisfied with the quality of the PNG output, or at least how it rendered, fuzzy and illegible. My thought was that an SVG presentation would provide a more crisp, scalable (hence the name SVG) view of each graph.

Where I ran into problems was the embedded logos. Applications like PowerPoint allowed the inclusion of the logos as SGV "images" within the SVG "image" in PowerPoint, but did not render them; blank spaces remained.

So I set out to embed the SVG of the logos inline as elements within the final SVG file; it turned into quite the journey . . .

So SVG is really just XML, right? No, it is XML; it's just not just XML. There are XML tags and what is inside those tags can contain multiple SVG characteristics, all in their own syntax, most listed as quoted text.

At this point finding a library that allows for programmatic manipulation of SGV by tag or reviewing some open source browser source code may have helped. I did not do either of those things (a brief internet search yielded Python libraries, but they seemed focused more on conversion to and from SVG and other image formats) and set out on my own.

Like most people, I have played with Inkscape and converted images to SVG format. I even blogged about having done this with POVRay rendered pysanky eggs back in the day. Using something with software written by people way smarter than you and actually understanding it are two entirely different animals.

To make matters worse . . . I cannot actually display the SVG images or inline them here on Blogger. Smaller SVG snippets seem to work, but an entire graph with SVG logos is either too much or I am doing something wrong. Another (blurry) PNG example of the output will have to do.

Important concepts with links:

1) viewBox, scale, dimensions - Soueiden (classic, kind of the standard as far as I can tell):

https://www.sarasoueidan.com/blog/mimic-relative-positioning-in-svg/

2) the four quadrants of svg space (but you only see the lower right):

http://dh.obdurodon.org/coordinate-tutorial.xhtml

3) use x, y positioning to place embedded SVG rather than viewBox coordinates:

I have lost the link, but whoever suggested this, thank you.

4) (no link) Allow graphviz to do as much work as possible before editing any svg. For instance, when bolding edges of the graph in SVG, the edges will invariably overlap the nodes. This looks ugly. graphviz handles all that and it is far far simpler than trying to do it on your own.

5) bezier curves - nothing in this post about them, but they were part of my real introduction to SVG, and the most fun part. Recommend.

https://javascript.info/bezier-curve#de-casteljau-s-algorithm

Methodology for putting SVG logos inside the SVG document (not necessarily in order):

1) scale the embedded SVGs with the "width" and "height" attributes (SVG). I made mine proportional relative to the original SVGs' dimensions.

2) Calculate where the SVGs are supposed to go within the graphviz generated SVG coordinate space.

graphviz pushes everything into the upper right SVG space quadrant with an SVG "translate" command with 4 units padding. This needs to be taken into account when positioning the SVG elements relative to graphviz' coordinate space. The elements will be using the lower right SVG space quadrant coordinate space.

3) Leverage the positioning and size of the original PNG logos to place your SVG ones, then pop the old logo image elements and "erase" the boxes around them (yes, quite hacky, but effective).

This is a Python blog. Nutshell: I used xml.etree.ElementTree and rudimentary text processing of the SVG specific parts to get this done.

The whole thing got quite unwieldy and I turned once again to DAG Hamilton to help me organize and visualize things. (Blurry) screenshot below:





Wow, it looks like you just collected every piece of information you could about all the dimensions and smashed it all together in the final SVG document at the end.

Yes.

Hey, why is that one node just hanging out at a dead end not doing anything?

I was not getting the whole coordinate thing and needed it for reference.

The code:

# run.py - the DAG Hamilton control file.

"""
Hamilton wrapper.
"""

# https://hamilton.dagworks.io/en/latest/concepts/driver/#recap

import sys

import pprint

from hamilton import driver

import editsvgs as esvg

OUTPUTFILES = {'data_source_highlighted':'data_source_highlighted_final',
               'web_scraping_functions_highlighted':'web_scraping_functions_highlighted_final',
               'output_functions_highlighted':'output_functions_highlighted_final'}

dr = driver.Builder().with_modules(esvg).build()

dr.display_all_functions('esvg.svg', deduplicate_inputs=True, keep_dot=True, orient='BR')

for keyx in OUTPUTFILES:
    results = dr.execute(['hamilton_logo_root',
                          'company_logo_root',
                          'graph_root',
                          'doc_attrib',
                          'hamilton_logo_tree_indices',
                          'company_logo_tree_indices',
                          'hamilton_logo_png_attrib',
                          'company_logo_png_attrib',
                          'parsed_hamiltonlogo_png_attrib',
                          'parsed_companylogo_png_attrib',
                          'biggerdimension',
                          'dimensionratio',
                          'parsed_graph_dimensions',
                          'hamilton_logo_position',
                          'hamilton_svg_dimensions',
                          'hamilton_logo_dimensions_orig',
                          'biggerdimension_company',
                          'dimensionratio_company',
                          'company_logo_position',
                          'company_svg_dimensions',
                          'company_logo_dimensions_orig',
                          'final_svg_file'],
                          inputs={'hamiltonlogofile':'hamiltonlogolarge.svg',
                                  'companylogofile':'fauxcompanylogo.svg',
                                  'testfile':keyx + '.svg',
                                  'outputfile':OUTPUTFILES[keyx] + '.svg',
                                  'hamiltonlogopng':'hamiltonlogolarge.png',
                                  'companylogopng':'fauxcompanylogo.png'})
    
    print('\ndoc_attrib =\n')
    pprint.pprint(results['doc_attrib'])
    print('\nhamilton_logo_tree_indices =\n')
    pprint.pprint(results['hamilton_logo_tree_indices'])
    print('\ncompany_logo_tree_indices =\n')
    pprint.pprint(results['company_logo_tree_indices'])
    print('\nhamilton_logo_png_attrib =\n')
    pprint.pprint(results['hamilton_logo_png_attrib'])
    print('\nparsed_hamiltonlogo_png_attrib =\n')
    pprint.pprint(results['parsed_hamiltonlogo_png_attrib'])
    print('\ncompany_logo_png_attrib =\n')
    pprint.pprint(results['company_logo_png_attrib'])
    print('\nparsed_companylogo_png_attrib =\n')
    pprint.pprint(results['parsed_companylogo_png_attrib'])
    print('\nbiggerdimension =\n')
    pprint.pprint(results['biggerdimension'])
    print('\ndimensionratio =\n')
    pprint.pprint(results['dimensionratio'])
    print('\nparsed_graph_dimensions =\n')
    pprint.pprint(results['parsed_graph_dimensions'])
    print('\nhamilton_logo_position =\n')
    pprint.pprint(results['hamilton_logo_position'])
    print('\nhamilton_svg_dimensions =\n')
    pprint.pprint(results['hamilton_svg_dimensions'])
    print('\nhamilton_logo_dimensions_orig =\n')
    pprint.pprint(results['hamilton_logo_dimensions_orig'])
    print('\ndimensionratio_company =\n')
    pprint.pprint(results['dimensionratio_company'])
    print('\ncompany_logo_position =\n')
    pprint.pprint(results['company_logo_position'])
    print('\ncompany_svg_dimensions =\n')
    pprint.pprint(results['company_svg_dimensions'])
    print('\ncompany_logo_dimensions_orig =\n')
    pprint.pprint(results['company_logo_dimensions_orig'])
    print('\nfinal_svg_file =\n')
    pprint.pprint(results['final_svg_file'])

# editsvgs.py - DAG Hamilton noun-named functions.

# python 3.12

"""
Attempt to position svg logos and edit
flowchart with svg.
"""

import os

import pprint

import xml.etree.ElementTree as ET

import itertools

import sys

import copy

import reusedfunctions as rf

# Pop this to get rid of png image.
# '{http://www.w3.org/1999/xlink}href': 'hamiltonlogolarge.png'}
PNG_ATTRIB_KEY = '{http://www.w3.org/1999/xlink}href'
# '{http://www.w3.org/1999/xlink}href': 'fauxcompanylogo.png'}

def hamilton_logo_root(hamiltonlogofile:str) -> ET.Element:
    """
    Get root of ElementTree object for Hamilton
    logo svg file.

    hamiltonlogofile is the svg file with the Hamilton logo.
    """
    print('Getting Hamilton logo svg file root Element . . .')
    return rf.getroot(hamiltonlogofile)

def company_logo_root(companylogofile:str) -> ET.Element:
    """
    Get root of ElementTree object for company
    logo svg file.

    companylogofile is the svg file with the company logo.
    """
    print('Getting company logo svg file root Element . . .')
    return rf.getroot(companylogofile)

def graph_root(testfile:str) -> ET.Element:
    """
    Gets root Element of graphviz graph svg.

    testfile is the graphviz svg file.
    """
    print('Getting root Element of main graph svg file . . .')
    return rf.getroot(testfile)

def doc_attrib(graph_root:ET.Element) -> dict:
    """
    Gets graphviz svg document's dimensions and viewBox
    in a dictionary.

    graph_root is the graphviz svg file root Element. 

    Returns dictionary of xml/svg data for doc.
    """
    print('Getting dimensions and viewBox for main graph svg file . . .')
    return graph_root.attrib

def hamilton_logo_tree_indices(graph_root:ET.Element, hamiltonlogopng:str) -> tuple:
    """
    Get tree indices (3 deep) for original png
    Hamilton logo on graph.

    graph_root is the root Element of graphviz graph svg.

    hamiltonlogopng is the name of the png file referenced
    in the image link in the svg file (string).

    Returns 3 tuple of integers.
    """
    print('Getting ElementTree indices for tree for Hamilton png logo Element . . .')
    return rf.gettreeindices(graph_root, hamiltonlogopng)

def company_logo_tree_indices(graph_root:ET.Element, companylogopng:str) -> tuple:
    """
    Get tree indices (3 deep) for original png
    company logo on graph.

    graph_root is the root Element of graphviz graph svg.

    companylogopng is the name of the png file referenced
    in the image link in the svg file (string).

    Returns 3 tuple of integers.
    """
    print('Getting ElementTree indices for tree for company png logo Element . . .')
    return rf.gettreeindices(graph_root, companylogopng)

def hamilton_logo_png_attrib(graph_root:ET.Element, hamilton_logo_tree_indices:tuple) -> dict:
    """
    Get attrib dictionary for original Hamilton png file Element in graph svg.

    graph_root is the root Element of graphviz graph svg.

    hamilton_logo_tree_indices are the lookup indices for the Hamilton
    logo png Element within the xml tree.
    """
    print('Getting attrib dictionary for original Hamilton png file Element in graph svg . . .')
    return rf.getpngattrib(graph_root, hamilton_logo_tree_indices)

def company_logo_png_attrib(graph_root:ET.Element, company_logo_tree_indices:tuple) -> dict:
    """
    Get attrib dictionary for original company png file Element in graph svg.

    graph_root is the root Element of graphviz graph svg.

    company_logo_tree_indices are the lookup indices for the company
    logo png Element within the xml tree.
    """
    print('Getting attrib dictionary for original company png file Element in graph svg . . .')
    return rf.getpngattrib(graph_root, company_logo_tree_indices)

def parsed_hamiltonlogo_png_attrib(hamilton_logo_png_attrib:dict) -> dict:
    """
    Work dictionary that has information on former
    location of png Hamilton logo image in the 
    graphviz svg.

    Basically getting svg text values into float format.

    Returns new dictionary.
    """
    print('Getting svg text values into float format for Hamilton png Element . . .')
    return rf.parsepngattrib(hamilton_logo_png_attrib)

def parsed_companylogo_png_attrib(company_logo_png_attrib:dict) -> dict:
    """
    Work dictionary that has information on former
    location of png company logo image in the 
    graphviz svg.

    Basically getting svg text values into float format.

    Returns new dictionary.
    """
    print('Getting svg text values into float format for company logo png Element . . .')
    return rf.parsepngattrib(company_logo_png_attrib)

def biggerdimension(hamilton_logo_root:ET.Element) -> str:
    """
    hamilton_logo_root is the ElementTree Element
    for the big svg Hamilton logo.

    Returns 'Y' if the y dimension is the 
    bigger one, and 'X' if the x one is.

    Returns None if there is a key error.
    """
    print('Determining bigger dimension for svg Hamilton logo . . .')
    return rf.getbiggerdimension(hamilton_logo_root)

def dimensionratio(biggerdimension:str, hamilton_logo_root:ET.Element) -> float:
    """
    biggerdimension is a string, 'X' or 'Y'.

    hamilton_logo_root is the ElementTree Element
    for the big svg Hamilton logo.

    Returns ratio of bigger dimension
    to smaller one (float).
    """
    print('Calculating dimensions ratio for Hamilton logo svg . . .')
    return rf.getdimensionratio(biggerdimension, hamilton_logo_root)

def parsed_graph_dimensions(graph_root:ET.Element) -> tuple:
    """
    Get translate coordinates from graphviz
    svg root Element.

    Returns two tuple of x, y translation.
    """
    graph0dimensions = graph_root[0].attrib
    coordstr = graph0dimensions['transform']
    coordstr = coordstr[coordstr.index('translate'):]
    coordstr = coordstr[coordstr.index('(') + 1:-1]
    vals = [float(x) for x in coordstr.split(' ')]
    return tuple(vals)

def hamilton_logo_position(parsed_graph_dimensions:tuple,
                           parsed_hamiltonlogo_png_attrib:dict) -> tuple:
    """
    parsed_graph_dimensions is an x, y two tuple.

    parsed_hamiltonlogo_png_attrib is a dictionary.

    Returns x, y position of Hamilton logo svg graphic as a
    two tuple.
    """
    print('Getting position of Hamilton logo . . .')
    return rf.getposition(parsed_graph_dimensions, parsed_hamiltonlogo_png_attrib)

def company_logo_position(parsed_graph_dimensions:tuple,
                          parsed_companylogo_png_attrib:dict) -> tuple:
    """
    parsed_graph_dimensions is an x, y two tuple.

    parsed_hamiltonlogo_png_attrib is a dictionary.

    Returns x, y position of company logo svg graphic as a
    two tuple.
    """
    print('Getting position of company logo . . .')
    # Add 4.
    x = parsed_companylogo_png_attrib['X'] + parsed_graph_dimensions[0]
    # Add negative number with big absolute value.
    # Upper right quadrant translation thing.
    y = parsed_companylogo_png_attrib['Y'] + parsed_graph_dimensions[1] 
    return x, y

def hamilton_svg_dimensions(parsed_hamiltonlogo_png_attrib:dict,
                            biggerdimension:str,
                            dimensionratio:float) -> tuple:
    """
    Get width and height of svg Hamilton logo within
    final document.

    parsed_hamiltonlogo_png_attrib is the dictionary of
    numeric values associated with the original image
    position of the Hamilton png logo within the
    svg document.

    biggerdimension is the 'X' or 'Y' value that
    indicates which dimension is the larger of
    the two.

    dimensionratio is the ratio of the larger
    dimension to the smaller one.

    Returns x, y two tuple of floats.
    """
    print('Getting size of Hamilton logo in final doc . . .')
    return rf.getdimensions(parsed_hamiltonlogo_png_attrib, biggerdimension, dimensionratio)

def hamilton_logo_dimensions_orig(hamilton_logo_root:ET.Element) -> tuple:
    """
    hamilton_logo_root is the ElementTree Element
    for the big svg Hamilton logo.

    Returns two tuple of width, height.
    """
    print('Retrieving dimensions of Hamilton logo svg . . .')
    return rf.getdimensionsorig(hamilton_logo_root)

def final_svg_file(testfile:str,
                   outputfile:str,
                   hamilton_logo_root:ET.Element,
                   hamilton_logo_tree_indices:tuple,
                   hamilton_logo_position:tuple,
                   hamilton_svg_dimensions:tuple,
                   hamilton_logo_dimensions_orig:tuple,
                   company_logo_tree_indices:tuple,
                   parsed_companylogo_png_attrib:dict,
                   company_logo_position:tuple,
                   company_logo_root:ET.Element,
                   company_svg_dimensions:tuple,
                   company_logo_dimensions_orig:tuple,
                   ) -> str:
    """
    Replaces image logos with scaleable
    svg ones.

    testfile is the name of the original svg file.

    outputfile is the name of the intended final
    svg file.

    hamilton_logo_root is the elementree root object
    for the Hamilton logo svg file.

    hamilton_logo_tree_indices are nested indices 
    indicating the location of the original Hamilton
    logo png elementree Element within the input
    svg document.

    hamilton_logo_position - x, y tuple - where to
    put the svg Hamilton logo within the final
    svg document.

    hamilton_svg_dimensions - x, y tuple - width and
    height of Hamilton svg logo within the final
    svg document.

    hamilton_logo_dimensions_orig - two tuple of width, height
    of original svg file Hamilton logo.

    company_logo_tree_indices are nested indices 
    indicating the location of the original company
    logo png elementree Element within the input
    svg document.

    company_logo_position - x, y tuple - where to
    put the svg company logo within the final
    svg document.

    company_logo_root is the elementree root object
    for the company logo svg file.
 
    company_svg_dimensions - x, y tuple - width and
    height of company svg logo within the final
    svg document.

    company_logo_dimensions_orig - two tuple of width, height
    of original svg file company logo.

    Returns string filename.
    """
    print('Making changes to svg . . .')
    hlti = hamilton_logo_tree_indices 
    retval = outputfile
    tree = ET.parse(testfile)
    root = tree.getroot()
    # pop Hamilton png
    print('Popping original Hamilton png logo . . .')
    root[hlti[0]][hlti[1]][hlti[2]].attrib.pop(PNG_ATTRIB_KEY)
    print('Appending Hamilton svg to root Element . . .')
    root.append(hamilton_logo_root)
    print('Adjusting viewBox for Hamilton svg . . .')
    root[-1].attrib['viewBox'] = '0.00 0.00 {0:.3f} {1:.3f}'.format(*hamilton_logo_dimensions_orig)
    print('Adjusting height and width for Hamilton svg . . .')
    root[-1].attrib['height'] = str(hamilton_svg_dimensions[1])
    root[-1].attrib['width'] = str(hamilton_svg_dimensions[0])
    print('Positioning Hamilton logo svg within final svg . . .')
    root[-1].attrib['x'] = str(hamilton_logo_position[0])
    root[-1].attrib['y'] = str(hamilton_logo_position[1])
    print('Erasing Hamilton logo bounding box . . .')
    # After popping png, polygon resides one index unit back.
    root[hlti[0]][hlti[1]][hlti[2] - 1].attrib['stroke'] = 'none'
    clti = company_logo_tree_indices
    # pop company png
    print('Popping original company png logo . . .')
    root[clti[0]][clti[1]][clti[2]].attrib.pop(PNG_ATTRIB_KEY)
    print('Adding company logo svg Element to main svg file . . .')
    root.append(company_logo_root)
    print('Adjusting viewBox for company svg . . .')
    root[-1].attrib['viewBox'] = '0.00 0.00 {0:.3f} {1:.3f}'.format(*company_logo_dimensions_orig)
    print('Adjusting height and width for company svg . . .')
    root[-1].attrib['height'] = str(company_svg_dimensions[1])
    root[-1].attrib['width'] = str(company_svg_dimensions[0])
    print('Moving company logo svg to the correct position in the display . . .')
    # Had to adjust 15 units to get it out of the way of the legend.
    root[-1].attrib['x'] = str(company_logo_position[0] - 15)
    root[-1].attrib['y'] = str(company_logo_position[1])
    print('Erasing company logo bounding box . . .')
    # After popping png, polygon resides one index unit back.
    root[clti[0]][clti[1]][clti[2] - 1].attrib['stroke'] = 'none'
    print('Writing new svg . . .')
    tree.write(retval)
    return retval

def biggerdimension_company(company_logo_root:ET.Element) -> str:
    """
    company_logo_root is the ElementTree Element
    for the big svg company logo.

    Returns 'Y' if the y dimension is the 
    bigger one, and 'X' if the x one is.
    """
    print('Determining bigger dimension for svg company logo . . .')
    return rf.getbiggerdimension(company_logo_root)

def dimensionratio_company(biggerdimension_company:str,
                           company_logo_root:ET.Element) -> float:
    """
    biggerdimension is a string, 'X' or 'Y'.

    company_logo_root is the ElementTree Element
    for the big svg company logo.

    Returns ratio of bigger dimension
    to smaller one (float).
    """
    print('Calculating dimensions ratio for company logo svg . . .')
    return rf.getdimensionratio(biggerdimension_company,
                                company_logo_root)

def company_logo_position(parsed_graph_dimensions:tuple,
                          parsed_companylogo_png_attrib:dict) -> tuple:
    """
    parsed_graph_dimensions is an x, y two tuple.

    parsed_companylogo_png_attrib is a dictionary.

    Returns x, y position of company logo svg graphic as a
    two tuple.
    """
    print('Getting position of company logo . . .')
    return rf.getposition(parsed_graph_dimensions,
                          parsed_companylogo_png_attrib)

def company_svg_dimensions(parsed_companylogo_png_attrib:dict,
                           biggerdimension_company:str,
                           dimensionratio_company:float) -> tuple:
    """
    Get width and height of svg company logo within
    final document.

    parsed_companylogo_png_attrib is the dictionary of
    numeric values associated with the original image
    position of the company png logo within the
    svg document.

    biggerdimension is the 'X' or 'Y' value that
    indicates which dimension is the larger of
    the two.

    dimensionratio_company is the ratio of the larger
    dimension to the smaller one.

    Returns x, y two tuple of floats.
    """
    pprint.pprint(parsed_companylogo_png_attrib)
    print('Getting size of company logo in final doc . . .')
    return rf.getdimensions(parsed_companylogo_png_attrib, 
                            biggerdimension_company,
                            dimensionratio_company)

def company_logo_dimensions_orig(company_logo_root:ET.Element) -> tuple:
    """
    company_logo_root is the ElementTree Element
    for the big svg company logo.

    Returns two tuple of width, height.
    """
    print('Retrieving dimensions of company logo svg . . .')
    return rf.getdimensionsorig(company_logo_root)

# reusedfunctions.py - utility/helper/main functionality
#                      at a granular level.

# python 3.12

"""
Auxiliary module to Hamilton svg script.
"""

import itertools

import xml.etree.ElementTree as ET

# Pop this to get rid of png image.
# '{http://www.w3.org/1999/xlink}href': 'hamiltonlogolarge.png'}
PNG_ATTRIB_KEY = '{http://www.w3.org/1999/xlink}href'

def gettreeindices(graph_root, png):
    """
    Get tree indices (3 deep) for png on graph.

    graph_root is the root Element of graphviz graph svg.

    png is the name of the png file referenced
    in the image link in the svg file (string).

    Returns 3 tuple of integers.
    """
    countergeneratorx = itertools.count()
    counterx = next(countergeneratorx)
    for nodex in graph_root:
        countergeneratory = itertools.count()
        countery = next(countergeneratory)
        for nodey in nodex:
            countergeneratorz = itertools.count()
            counterz = next(countergeneratorz)
            for nodez in nodey:
                if PNG_ATTRIB_KEY in nodez.attrib:
                    if nodez.attrib[PNG_ATTRIB_KEY] == png:
                        return counterx, countery, counterz
                counterz = next(countergeneratorz)
            countery = next(countergeneratory)
        counterx = next(countergeneratorx)

def getroot(filename):
    """
    Get root of ElementTree object for svg file.

    filename is the svg file string.
    """
    return ET.parse(filename).getroot()

def getpngattrib(graph_root, indices):
    """
    Get attrib dictionary for png file Element in graph svg.

    graph_root is the root Element of graphviz graph svg.

    indices are the lookup indices for the 
    png Element within the xml tree.
    """
    return graph_root[indices[0]][indices[1]][indices[2]].attrib

def parsepngattrib(attrib):
    """
    Work dictionary that has information on
    location of png image in the 
    graphviz svg.

    Basically getting svg text values into float format.

    Returns new dictionary.
    """
    retval = {}
    retval['X'] = float(attrib['x'])
    retval['Y'] = float(attrib['y'])
    retval['height'] = float(attrib['height'][:attrib['height'].index('px')])
    retval['width'] = float(attrib['width'][:attrib['width'].index('px')])
    return retval

def getbiggerdimension(root):
    """
    root is the ElementTree Element
    for the svg file element to be
    embedded into the main svg file.

    Returns 'Y' if the y dimension is the 
    bigger one, and 'X' if the x one is.

    Returns None if there is a key error.
    """
    dimensions = root.attrib
    try:
        if float(dimensions['height']) > float(dimensions['width']):
            return 'Y'
        else:
            # X bigger or equal
            return 'X'
    except ValueError:
        pass
    return None

def getdimensionratio(biggerdimension, root):
    """
    biggerdimension is a string, 'X' or 'Y'.

    root is the etree Element for the
    svg Element that is to be embedded
    into the final svg file

    Returns ratio of bigger dimension
    to smaller one (float).
    """
    dimensions = root.attrib
    if biggerdimension == 'Y':
        return float(dimensions['height']) / float(dimensions['width'])
    else:
        return float(dimensions['width']) / float(dimensions['height'])

def getposition(dimensions, attrib):
    """
    dimensions is an x, y two tuple.

    attrib is a dictionary.

    Returns x, y position of svg graphic as a
    two tuple.
    """
    # Add 4.
    x = attrib['X'] + dimensions[0]
    # Add negative number with big absolute value.
    # Upper right quadrant translation thing.
    y = attrib['Y'] + dimensions[1] 
    return x, y

def getdimensions(attrib, biggerdimension, dimensionratio):
    """
    Get width and height of svg within
    final document.

    attrib is the dictionary of numeric values
    associated with the original image
    position of the png within the
    svg document.

    biggerdimension is the 'X' or 'Y' value that
    indicates which dimension is the larger of
    the two.

    dimensionratio is the ratio of the larger
    dimension to the smaller one.

    Returns x, y two tuple of floats.
    """
    if biggerdimension == 'Y':
        return (attrib['width'],  dimensionratio * attrib['width'])
    else:
        return (dimensionratio * attrib['height'], attrib['height'])

def getdimensionsorig(root):
    """
    root is the ElementTree Element
    for the svg Element to be embedded 
    in the main svg file.

    Returns two tuple of width, height.
    """
    return float(root.attrib['width']), float(root.attrib['height'])

# OUTPUT (stdout)

Getting Hamilton logo svg file root Element . . .
Getting company logo svg file root Element . . .
Getting root Element of main graph svg file . . .
Getting dimensions and viewBox for main graph svg file . . .
Getting ElementTree indices for tree for Hamilton png logo Element . . .
Getting ElementTree indices for tree for png Element . . .
Getting ElementTree indices for tree for company png logo Element . . .
Getting ElementTree indices for tree for png Element . . .
Getting attrib dictionary for original Hamilton png file Element in graph svg . . .
Getting attrib dictionary for original company png file Element in graph svg . . .
Getting svg text values into float format for Hamilton png Element . . .
Getting svg text values into float format for company logo png Element . . .
Determining bigger dimension for svg Hamilton logo . . .
Calculating dimensions ratio for Hamilton logo svg . . .
Getting position of Hamilton logo . . .
Getting size of Hamilton logo in final doc . . .
Retrieving dimensions of Hamilton logo svg . . .
Determining bigger dimension for svg company logo . . .
Calculating dimensions ratio for company logo svg . . .
Getting position of company logo . . .
Getting size of company logo in final doc . . .
Retrieving dimensions of company logo svg . . .
Making changes to svg . . .
Popping original Hamilton png logo . . .
Appending Hamilton svg to root Element . . .
Adjusting viewBox for Hamilton svg . . .
Adjusting height and width for Hamilton svg . . .
Positioning Hamilton logo svg within final svg . . .
Erasing Hamilton logo bounding box . . .
Popping original company png logo . . .
Adding company logo svg Element to main svg file . . .
Adjusting viewBox for company svg . . .
Adjusting height and width for company svg . . .
Moving company logo svg to the correct position in the display . . .
Erasing company logo bounding box . . .
Writing new svg . . .

doc_attrib =

{'height': '825pt', 'viewBox': '0.00 0.00 936.00 824.60', 'width': '936pt'}

hamilton_logo_tree_indices =

(0, 4, 2)

company_logo_tree_indices =

(0, 5, 2)

hamilton_logo_png_attrib =

{'height': '43.2px',
 'preserveAspectRatio': 'xMinYMin meet',
 'width': '43.2px',
 'x': '218.3',
 'y': '-673.9',
 '{http://www.w3.org/1999/xlink}href': 'hamiltonlogolarge.png'}

parsed_hamiltonlogo_png_attrib =

{'X': 218.3, 'Y': -673.9, 'height': 43.2, 'width': 43.2}

company_logo_png_attrib =

{'height': '43.2px',
 'preserveAspectRatio': 'xMinYMin meet',
 'width': '367.2px',
 'x': '279.3',
 'y': '-673.9',
 '{http://www.w3.org/1999/xlink}href': 'fauxcompanylogo.png'}

parsed_companylogo_png_attrib =

{'X': 279.3, 'Y': -673.9, 'height': 43.2, 'width': 367.2}

biggerdimension =

'X'

dimensionratio =

1.0421153385977506

parsed_graph_dimensions =

(4.0, 820.6)

hamilton_logo_position =

(222.3, 146.70000000000005)

hamilton_svg_dimensions =

(45.01938262742283, 43.2)

hamilton_logo_dimensions_orig =

(8710.0, 8358.0)

dimensionratio_company =

9.047619047619047

company_logo_position =

(283.3, 146.70000000000005)

company_svg_dimensions =

(390.8571428571429, 43.2)

company_logo_dimensions_orig =

(712.5, 78.75)

final_svg_file =

'data_source_highlighted_final.svg'

# . . . etc. 2 more times.

Note on DAG Hamilton: my use case for this tool is very rudimentary and somewhat pedestrian. That said, it is becoming essential to my workflows.

The DAG Hamilton project is still at its relatively early stages with some very exciting active development ongoing. It seems like every week some amazing new decorator feature gets released.

I am not much of one for decorators use - grateful for their existence and use in the 3rd party modules I use. Truthfully, 3/4 of the work I do could probably be accomplished with a relatively recent version of Python and dictionaries.

Where DAG Hamilton helps me out a lot is in corralling and organizing code. I tend to get a bit undisciplined and have trouble "seeing" the execution path. DAG Hamilton helps there.

Thanks for stopping by.

No comments:

Post a Comment