DrawIo Module

N2G Drawio Module supports producing XML structured text files that can be opened by Diagrams DrawIO desktop or DrawIO web applications

Quick start

Nodes and links can be added one by one using add_node and add_link methods

from N2G import drawio_diagram

diagram = drawio_diagram()
diagram.add_diagram("Page-1")
diagram.add_node(id="R1")
diagram.add_node(id="R2")
diagram.add_link("R1", "R2", label="DF", src_label="Gi1/1", trgt_label="GE23")
diagram.layout(algo="kk")
diagram.dump_file(filename="Sample_graph.drawio", folder="./Output/")

After opening and editing diagram, it might look like this:

R1
R1
R2
R2
DFGi1/1GE23
Viewer does not support full SVG 1.1

Working with drawio module should be started with adding new diagram, after that nodes and links can be added. It is possible to switch between diagrams to edit using go_to_diagram method.

Note

link src_label and trgt_label attributes supported starting with 0.2.0 version

Adding styles

Styles used to change the way how things look and can be applied to nodes or links. Styles attributes in DrawIO encoded using strings similar to this one:

shape=mxgraph.cisco.misc.asr_1000_series;html=1;pointerEvents=1;dashed=0;fillColor=#036897;strokeColor=#ffffff;strokeWidth=2;verticalLabelPosition=bottom;verticalAlign=top;align=center;outlineConnect=0;

above strings can be found in node and link settings:

_images/where_styles.png

and can be used to reference by node and links style attribute, additionally, style string can be saved in text file and style attribute can reference that file OS path location.

from N2G import drawio_diagram

new_link_style="endArrow=classic;fillColor=#f8cecc;strokeColor=#FF3399;dashed=1;edgeStyle=entityRelationEdgeStyle;startArrow=diamondThin;startFill=1;endFill=0;strokeWidth=5;"
building_style="shape=mxgraph.cisco.buildings.generic_building;html=1;pointerEvents=1;dashed=0;fillColor=#036897;strokeColor=#ffffff;strokeWidth=2;verticalLabelPosition=bottom;verticalAlign=top;align=center;outlineConnect=0;"

diagram = drawio_diagram()
diagram.add_diagram("Page-1")
diagram.add_node(id="HQ", style=building_style, width=90, height=136)
diagram.add_node(id="R1", style="./styles/router.txt")
diagram.add_link("R1", "HQ", label="DF", style=new_link_style)

where ./styles/router.txt content is:

shape=mxgraph.cisco.routers.atm_router;html=1;pointerEvents=1;dashed=0;fillColor=#036897;strokeColor=#ffffff;strokeWidth=2;verticalLabelPosition=bottom;verticalAlign=top;align=center;outlineConnect=0;

After opening and editing diagram, it might look like this:

HQ
HQ
R1
R1
DF
Viewer does not support full SVG 1.1

Note

DrawIO does not encode node width and height attributes in style string, as a result width and height should be provided separately or will be set to default values: 120 and 60 pixels

Loading graph from dictionary

Diagram elements can be loaded from dictionary structure. That dictionary may contain nodes, links and edges keys, these keys should contain list of dictionaries where each dictionary item will contain element attributes such as id, labels, data, url etc.

from N2G import drawio_diagram

diagram = drawio_diagram()
sample_graph={
'nodes': [
    {'id': 'a', 'style': './styles/router.txt', 'label': 'R1', 'width': 78, 'height': 53},
    {'id': 'R2', 'label':'CE12800'},
    {'id': 'c', 'label': 'R3', 'data': {'role': 'access', 'make': 'VendorX'}}
],
'links': [
    {'source': 'a', 'label': 'DF', 'target': 'R2', 'data': {'role': 'uplink'}},
    {'source': 'R2', 'label': 'Copper', 'target': 'c'},
    {'source': 'c', 'label': 'ZR', 'target': 'a'}
]}
diagram.from_dict(sample_graph, width=300, height=200, diagram_name="Page-2")
diagram.layout(algo="kk")
diagram.dump_file(filename="Sample_graph.drawio", folder="./Output/")

After opening and editing diagram, it might look like this:

R1
R1
CE12800
CE12800
R3
R3
DFCopperZR
Viewer does not support full SVG 1.1

Loading graph from list

From list method allows to load graph from list of dictionaries, generally containing link details like source, target, label. Additionally source and target can be defined using dictionaries as well, containing nodes details.

Note

Non-existing node will be automatically added on first encounter, by default later occurrences of same node will not lead to node attributes change, that behavior can be changed setting node_duplicates drawio_diagram attribute equal to update value.

from N2G import drawio_diagram

diagram = drawio_diagram()
sample_list_graph = [
    {'source': {'id': 'SW1'}, 'target': 'R1', 'label': 'Gig0/1--Gi2'},
    {'source': 'R2', 'target': 'SW1', "data": {"speed": "1G", "media": "10G-LR"}},
    {'source': {'id':'a', 'label': 'R3'}, 'target': 'SW1'},
    {'source': 'SW1', 'target': 'R4'}
]
diagram.from_list(sample_list_graph, width=300, height=200, diagram_name="Page-2")
diagram.layout(algo="kk")
diagram.dump_file(filename="Sample_graph.drawio", folder="./Output/")

After opening and editing diagram, it might look like this:

SW1
SW1
R1
R1
Gig0/1--Gi2
R2
R2
R3
R3
R4
R4
Viewer does not support full SVG 1.1

Loading graph from csv

Similar to from_dict or from_list, from_csv method can take csv data with elements details and add them to diagram. Two types of csv table should be provided - one for nodes, another for links.

from N2G import drawio_diagram

diagram = drawio_diagram()
csv_links_data = """"source","label","target"
"a","DF","b"
"b","Copper","c"
"b","Copper","e"
d,FW,e
"""
csv_nodes_data=""""id","label","style","width","height"
a,"R12","./styles/router.txt",78,53
"b","R2",,,
"c","R3",,,
"d","SW22",,,
"e","R1",,,
"""
diagram.from_csv(csv_nodes_data)
diagram.from_csv(csv_links_data)
diagram.layout(algo="kk")
diagram.dump_file(filename="Sample_graph.drawio", folder="./Output/")

After opening and editing diagram, it might look like this:

R12
R12
R2
R2
R3
R3
SW22
SW22
R1
R1
DFCopperCopperFW
Viewer does not support full SVG 1.1

Loading existing diagrams

N2G DrawIO module provides from_file and from_text methods to load existing diagram content, to load diagram from file one can use this as example:

from N2G import drawio_diagram

diagram = drawio_diagram()
drawing.from_file("./source/old_office_diagram.drawio")

After diagram loaded it can be modified or updated using add_x, from_x, delete_x or compare methods.

Diagram layout

To arrange diagram nodes in certain way one can use layout method that relies on igraph library to calculate node coordinates in accordance with certain algorithm. List of supported layout algorithms and their details can be found here together with brief description in API Reference section.

Sample code to layout diagram:

from N2G import drawio_diagram

diagram = drawio_diagram()
diagram.from_file("./source/old_office_diagram.graphml")
diagram.layout(algo="drl")
diagram.dump_file(filename="updated_office_diagram.graphml", folder="./Output/")

Comparing diagrams

Comparing diagrams can help to spot changes in your system. N2G compare method allow to calculate differences between old and new graphs and produce resulting diagram highlighting changes.

from N2G import drawio_diagram

diagram = drawio_diagram()
old_graph = {
'nodes': [
    {'id': 'R1'}, {'id': 'R2'}, {'id': 'R3'},
    ],
'edges': [
    {'source': 'R1', 'target': 'R2'},
    {'source': 'R2', 'target': 'R3'},
    {'source': 'R3', 'target': 'R1'}
]}
new_graph = {
'nodes': [
    {'id': 'R1'}, {'id': 'R2'}, {'id': 'R4'},
    ],
'edges': [
    {'source': 'R1', 'target': 'R2'},
    {'source': 'R2', 'target': 'R4'}
]}
diagram.add_diagram("Page-1", width=500, height=500)
diagram.from_dict(old_graph)
diagram.compare(new_graph)
diagram.layout(algo="kk")
diagram.dump_file(filename="Sample_graph.drawio", folder="./Output/")

Original and after diagrams combined:

R1
R1
R2
R2
R3
R3
R4
R4
Viewer does not support full SVG 1.1

R3 and its links are missing - highlighted in gray, but R4 and its link is new - highlighted in green.

API reference

API reference for N2G DrawIO module.

class N2G.drawio_diagram(node_duplicates='skip', link_duplicates='skip')

N2G DrawIO module allows to produce diagrams compatible with DrawIO XML format.

Parameters

  • node_duplicates (str) can be of value skip, log, update
  • link_duplicates (str) can be of value skip, log, update
add_diagram(id, name='', width=1360, height=864)

Method to add new diagram tab and switch to it.

Warning

This method must be called to create at list one diagram tab to work with prior to nodes and links can be added to the drawing calling add_link or add_node methods.

Parameters

  • id (str) id of the diagram, should be unique across other diagrams
  • name (str) tab name
  • width (int) width of diagram in pixels
  • height (int) height of diagram in pixels

Method to add link between nodes to the diagram.

Parameters

  • source (str) mandatory, source node id
  • source (str) mandatory, target node id
  • label (str) link label to display at the centre of the link
  • data (dict) dictionary of key value pairs to add as link data
  • url (str) url string to save as link url attribute
  • style (str) string or OS path to text file with style to apply to the link
  • src_label (str) link label to display next to source node
  • trgt_label (str) link label to display next to target node
  • src_label_style (str) source label style string
  • trgt_label_style (str) target label style string

Sample DrawIO style string for the link:

endArrow=classic;fillColor=#f8cecc;strokeColor=#FF3399;dashed=1;
edgeStyle=entityRelationEdgeStyle;startArrow=diamondThin;startFill=1;
endFill=0;strokeWidth=5;

Note

If source or target nodes does not exists, they will be automatically created

All labels are optional and substituted with empty values to calculate link id.

add_node(id, label='', data={}, url='', style='', width=120, height=60, x_pos=200, y_pos=150, **kwargs)

Method to add node to the diagram.

Parameters

  • id (str) mandatory, unique node identifier, usually equal to node name
  • label (str) node label, if not provided, set equal to id
  • data (dict) dictionary of key value pairs to add as node data
  • url (str) url string to save as node url attribute
  • width (int) node width in pixels
  • height (int) node height in pixels
  • x_pos (int) node position on x axis
  • y_pos (int) node position on y axis
  • style (str) string containing DrawIO style parameters to apply to the node

Sample DrawIO style string for the node:

shape=mxgraph.cisco.misc.asr_1000_series;html=1;pointerEvents=1;
dashed=0;fillColor=#036897;strokeColor=#ffffff;strokeWidth=2;
verticalLabelPosition=bottom;verticalAlign=top;align=center;
outlineConnect=0;
compare(data, diagram_name=None, missing_colour='#C0C0C0', new_colour='#00FF00')

Method to combine two graphs - existing and new - and produce resulting graph following these rules:

  • nodes and links present in new graph but not in existing graph considered as new and will be updated with new_colour style attribute by default highlighting them in green
  • nodes and links missing from new graph but present in existing graph considered as missing and will be updated with missing_colour style attribute by default highlighting them in gray
  • nodes and links present in both graphs will remain unchanged

Parameters

  • data (dict) dictionary containing new graph data, dictionary format should be the same as for from_dict method.
  • missing_colour (str) colour to apply to missing elements
  • new_colour (str) colour to apply to new elements

Sample usage:

from N2G import drawio_diagram
existing_graph = {
    "nodes": [
        {"id": "node-1"},
        {"id": "node-2"},
        {"id": "node-3"}
],
    "links": [
        {"source": "node-1", "target": "node-2", "label": "bla1"},
        {"source": "node-2", "target": "node-3", "label": "bla2"},
    ]
}
new_graph = {
    "nodes": [
        {"id": "node-99"},
        {"id": "node-100", "style": "./Pics/router_1.txt", "width": 78, "height": 53},
    ],
    "links": [
        {"source": "node-2", "target": "node-3", "label": "bla2"},
        {"source": "node-99", "target": "node-3", "label": "bla99"},
        {"source": "node-100", "target": "node-99", "label": "bla10099"},
    ]
}
drawing = drawio_diagram()
drawing.from_dict(data=existing_graph)
drawing.compare(new_graph)
drawing.layout(algo="kk")
drawing.dump_file(filename="compared_graph.drawio")

Method to delete link by its id. Bulk delete operation supported by providing list of link ids to delete.

If link id or ids not provided, id calculated based on - label, source, target - attributes using this algorithm:

  1. Edge tuple produced: tuple(sorted([label, source, target]))
  2. MD5 hash derived from tuple: hashlib.md5(",".join(edge_tup).encode()).hexdigest()

Parameters

  • id (str) id of single link to delete
  • ids (list) list of link ids to delete
  • label (str) link label to calculate id of single link to delete
  • source (str) link source to calculate id of single link to delete
  • target (str) link target to calculate id of single link to delete
delete_node(id=None, ids=[])

Method to delete node by its id. Bulk delete operation supported by providing list of node ids to delete.

Parameters

  • id (str) id of single node to delete
  • ids (list) list of node ids to delete
dump_file(filename=None, folder='./Output/')

Method to save current diagram in .drawio file.

Parameters

  • filename (str) name of the file to save diagram into
  • folder (str) OS path to folder where to save diagram file

If no filename provided, timestamped format will be used to produce filename, e.g.: Sun Jun 28 20-30-57 2020_output.drawio

dump_xml()

Method to return current diagram XML text

from_csv(text_data)

Method to build graph from CSV tables

Parameters

  • text_data (str) CSV text with links or nodes details

This method supports loading CSV text data that contains nodes or links information. If id in headers, from_dict method will be called for CSV processing, from_list method will be used otherwise.

CSV data with nodes details should have headers matching add_node method arguments and rules.

CSV data with links details should have headers matching add_link method arguments and rules.

Sample CSV table with links details:

"source","label","target","src_label","trgt_label"
"a","DF","b","Gi1/1","Gi2/2"
"b","Copper","c","Te2/1",
"b","Copper","e","","GE3"
"d","FW","e",,

Sample CSV table with nodes details:

"id","label","style","width","height"
a,"R1,2","./Pics/cisco_router.txt",78,53
"b","some",,,
"c","somelabel",,,
"d","somelabel1",,,
"e","R1",,,
from_dict(data, diagram_name='Page-1', width=1360, height=864)

Method to build graph from dictionary.

Parameters

  • diagram_name (str) name of the diagram tab where to add links and nodes. Diagram tab will be created if it does not exists

  • width (int) diagram width in pixels

  • height (int) diagram height in pixels

  • data (dict) dictionary with nodes and link/edges details, example:

    sample_graph = {
        'nodes': [
            {
                'id': 'a',
                'label': 'R1'
            },
            {
                'id': 'b',
                'label': 'somelabel',
                'data': {'description': 'some node description'}
            },
            {
                'id': 'e',
                'label': 'E'
            }
        ],
        'edges': [
            {
                'source': 'a',
                'label': 'DF',
                'src_label': 'Gi1/1',
                'trgt_label': 'Gi2/2',
                'target': 'b',
                'url': 'google.com'
            }
        ],
        'links': [
            {
                'source': 'a',
                'target': 'e'
            }
        ]
    }
    

Dictionary Content Rules

  • dictionary may contain nodes key with a list of nodes dictionaries
  • each node dictionary must contain unique id attribute, other attributes are optional
  • dictionary may contain edges or links key with a list of edges dictionaries
  • each link dictionary must contain source and target attributes, other attributes are optional
from_file(filename, file_load='xml')

Method to load nodes and links from Drawio diagram file for further processing

Args

  • filename - OS path to .drawio file to load
from_list(data, diagram_name='Page-1', width=1360, height=864)

Method to build graph from list.

Parameters

  • diagram_name (str) name of the diagram tab where to add links and nodes. Diagram tab will be created if it does not exists

  • width (int) diagram width in pixels

  • height (int) diagram height in pixels

  • data (list) list of link dictionaries, example:

    sample_graph = [
        {
            'source': 'a',
            'label': 'DF',
            'src_label': 'Gi1/1',
            'trgt_label': 'Gi2/2',
            'target': 'b',
            'data': {'vlans': 'vlans_trunked: 1,2,3\nstate: up'}
        },
        {
            'source': 'a',
            'target': {
                    'id': 'e',
                    'label': 'somelabel',
                    'data': {'description': 'some node description'}
                }
            }
        }
    ]
    

List Content Rules

  • each list item must have target and source attributes defined
  • target/source attributes can be either a string or a dictionary
  • dictionary target/source node must contain id attribute and other supported node attributes

Note

By default drawio_diagram object node_duplicates action set to ‘skip’ meaning that node will be added on first occurrence and ignored after that. Set node_duplicates to ‘update’ if node with given id need to be updated by later occurrences in the list.

from_xml(text_data)

Method to load graph from .drawio XML text produced by DrawIO

Args

  • text_data - text data to load
go_to_diagram(diagram_name=None, diagram_index=None)

DrawIO supports adding multiple diagram tabs within single document. This method allows to switch between diarams in different tabs. That way each tab can be updated separately.

Parameters

  • diagram_name (str) name of diagram tab to switch to
  • diagram_index (int) index of diagram tab to switch to, will change to last tab if index is out of range. Index can be positive or negative number and follows Python list index behaviour. For instance, index equal to “-1” we go to last tab, “0” will go to first tab
layout(algo='kk', **kwargs)

Method to calculate graph layout using Python igraph library

Parameters

  • algo (str) name of layout algorithm to use, default is ‘kk’. Reference Layout algorithms table below for valid algo names
  • kwargs any additional kwargs to pass to igraph Graph.layout method

Layout algorithms

algo name description
circle, circular Deterministic layout that places the vertices on a circle
drl The Distributed Recursive Layout algorithm for large graphs
fr Fruchterman-Reingold force-directed algorithm
fr3d, fr_3d Fruchterman-Reingold force-directed algorithm in three dimensions
grid_fr Fruchterman-Reingold force-directed algorithm with grid heuristics for large graphs
kk Kamada-Kawai force-directed algorithm
kk3d, kk_3d Kamada-Kawai force-directed algorithm in three dimensions
large, lgl, large_graph The Large Graph Layout algorithm for large graphs
random Places the vertices completely randomly
random_3d Places the vertices completely randomly in 3D
rt, tree Reingold-Tilford tree layout, useful for (almost) tree-like graphs
rt_circular, tree Reingold-Tilford tree layout with a polar coordinate post-transformation, useful for (almost) tree-like graphs
sphere, spherical, circular_3d Deterministic layout that places the vertices evenly on the surface of a sphere

Method to update edge/link details.

Parameters

  • edge_id (str) - md5 hash edge id, if not provided, will be generated based on link attributes
  • label (str) - existing edge label
  • src_label (str) - existing edge source label
  • trgt_label (str) - existing edge target label
  • source (str) - existing edge source node id
  • target (str) - existing edge target node id
  • new_label (str) - new edge label
  • data (str) - edge new data attributes
  • url (str) - edge new url attribute
  • style (str) - OS path to file or sting containing style to apply to edge
  • new_src_label (str) - new edge source label`
  • new_trgt_label (str) - new edge target label
  • src_label_style (str) - string with style to apply to source label
  • trgt_label_style (str) - strung with style to apply to target label

Either of these must be provided to find link element to update:

  • edge_id MD5 hash or
  • label, source, target, src_label, trgt_label existing link attributes to calculate edge_id

edge_id calculated based on - label, source, target, src_label, trgt_label - attributes following this algorithm:

  1. Edge tuple produced: tuple(sorted([label, source, target, src_label, trgt_label]))
  2. MD5 hash derived from tuple: hashlib.md5(",".join(edge_tup).encode()).hexdigest()

If no label, src_label, trgt_label provided, they substituted with empty values in assumption that values for existing link are empty as well.

This method will replace existing or add new labels to the link.

Existing data attribute will be amended with new values using dictionary like update method.

New style will replace existing style.

update_node(id, label=None, data={}, url=None, style='', width='', height='', **kwargs)

Method to update node details. Uses node id to search for node to update

Parameters

  • id (str) mandatory, unique node identifier
  • label (str) label at the center of the node
  • data (dict) dictionary of data items to add to the node
  • width (int) node width in pixels
  • height (int) node height in pixels
  • url (str) url string to save as node url attribute
  • style (str) string containing DrawIO style parameters to apply to the node