Draw diagrams of graphs.

## Project description

WARNING: This is work in progress. There is no guarantee as to the stability and reliability of this program.

Orthogram is a command line program and Python library that lets you draw diagrams of graphs. It reads a YAML file and produces a SVG file like this one:

Orthogram does not aim to be a fully-featured graph layout solution. Actually, it offers just a single layout: grid. More than that, you have to arrange the nodes (i.e. graph vertices) manually in the grid and they stay fixed in place; the program will not attempt to move them around trying to optimize any aspect of the diagram. Styling is also rather basic at the moment. It does however try to do a decent job arranging the links (i.e. graph edges) around the nodes to produce a tidy, readable drawing.

When used as a command line tool, Orthogram reads a diagram definition file and produces a Scalable Vector Graphics file. The definition file is written in YAML.

## Installation

You must have Python 3.8 or newer installed in your system. Run the following command to install package orthogram from PyPi:

python -m pip install orthogram

Note however that some of Orthogram’s dependencies rely on C/C++ libraries that you may have to install on your system:

Python Package

Library

python-igraph

igraph

pyyaml

LibYAML

shapely

GEOS

## Command line interface

The orthogram module is designed to be used from the command line. To generate a drawing of a diagram defined in a diagram definition file named diagram.yaml, enter the following command:

python -m orthogram diagram.yaml

This will create a diagram.svg file in the same directory. If you wish to create a file with a different name or in a different directory, pass the path as a second argument.

The program creates Scalable Vector Graphics (SVG) files. Use your web browser to view the drawing. Use Inkscape to convert it to PNG or other supported formats.

## Hello world

Start the text editor of your choice and type in the following lines of YAML:

nodes:
a:
label: Hello
b:
label: world
rows:
- nodes: [a]
- nodes: ["", b]
- start: a
end: b

Save it as hello.yaml and run:

python -m orthogram hello.yaml

This should create a hello.svg file in the same directory.

## Diagram definition file

Orthogram uses YAML for its input file format. Of course, YAML being a superset of JSON, you can use JSON if you prefer so. The top-level structure must be a YAML mapping; the following keys are recognized, each one containing a different category of definitions:

• diagram

• nodes

• rows

• styles

• groups

### diagram

The diagram section contains the attributes of the diagram itself. It is entirely optional; you do not need one if you do not intend to customize your diagram. Here is an example of a diagram section:

diagram:
label: This is my diagram!
font_weight: bold

The following diagram attributes are of particular significance:

If you set this to true, collinear segments of links belonging to the same group will collapse into a single segment. This may help reduce the clutter, though it depends on the application. Try it out and see.

stretch

By default, the diagram resizes itself to fill the element that contains it. Set this attribute to false to make the browser render the diagram in its original dimensions.

### nodes

The nodes section contains mappings between node names and node definitions. You must have at least a couple of nodes to produce a meaningful diagram. Here is an example:

nodes:
a:
label: A node
b:
label: Another node
stroke: blue

If you want a label with more than one line of text, use the newline character in the string. Even better, you can use the YAML literal style:

nodes:

single-line:
label: A single line label

multi-with-newlines:
label: Two lines separated by\na newline character

multi-with-newlines-again:
label: |-
You can also use
YAML literal style

Note that if the label of a node is not defined, the name of the node is used as a label instead.

### rows

The rows section of the diagram definition file is used to arrange the nodes in the layout grid. It is essential; nodes that have not been placed in the grid are not drawn at all.

The rows structure is a sequence of row definitions. Each row definition contains a sequence of node names. You can use an empty string between the node names to leave an empty spot in the row. Here is an example:

nodes:
a:
b:
c:
rows:
- nodes: [a]
- nodes: [b, "", c]

Note that the nodes key is necessary. Row definitions do not have any attributes, though this may change in the future.

### styles

You can add style definitions to the styles section to create named styles that can be referred to by the nodes and links. Each style definition consists of attribute key-value pairs. For example, the following two nodes are drawn in the same color:

nodes:
a:
style: reddish
b:
style: reddish
rows:
- nodes: [a, b]
styles:
reddish:
stroke: "#880000"
stroke_width: 3.0
fill: "#FFDDDD"

Attributes defined in the element itself override the attributes inherited by the linked named style.

There are two special style names, default_node and default_link, which are used to set default values for all the nodes and links in the diagram respectively.

### groups

The groups section may be used to attach attributes to link groups. Since links in the same group may collapse on one another, it is usually desirable for all the links in one group to share the same attributes. In the example that follows, all links are drawn in blue:

groups:
water:
stroke: blue
stroke_width: 4.0
- start: a
end: b
group: water
- start: c
end: d
group: water

A group definition may contain a reference to a named style if needed. Note that creating an entry in the groups section is not necessary for the grouping of the links; a common group name in each link definition is sufficient.

## Attributes

The following table summarizes the attributes available to the diagram and its components. Where an attribute is applicable, it shows the default value:

Attribute

Diagram

Node

arrow_aspect

1.5

arrow_back

False

arrow_base

3.0

arrow_forward

True

buffer_fill

“none”

buffer_width

0.0

False

column_margin

24.0

drawing_priority

0

end_bias

None

fill

“none”

“none”

font_family

None

None

None

font_size

14.0

10.0

font_style

None

None

None

font_weight

None

None

None

group

None

label_distance

6.0

label_position

“top”

label

None

None

4.0

min_height

300.0

48.0

min_width

300.0

96.0

24.0

row_margin

24.0

start_bias

None

stretch

True

stroke_dasharray

None

None

None

stroke_width

0.0

2.0

2.0

stroke

“none”

“black”

“black”

text_fill

“black”

“black”

text_line_height

1.25

1.25

The options for the enumerated attributes are:

• label_position:

• bottom

• top

• start_bias and end_bias:

• horizontal

• vertical

## API

### Using the Diagram class

If you want to create a diagram using Python, you can start by creating an empty Diagram object:

from orthogram import Diagram, write_svg

diagram = Diagram(label="A hand-made diagram", text_fill="blue")

You can pass any diagram attributes to the constructor as key-value pairs.

You can now add nodes to the diagram:

diagram.add_node("a", label="Hello")
diagram.add_node("c", label="World")

Again, you can provide attributes for the node as key-value pairs.

In order to use the nodes, you must first place them in the grid:

diagram.add_row(["a"])
diagram.add_row(["b", "", "c"])

The add_row method takes a list of node names. Note that you must have added the nodes to the diagram before placing them in the grid. Use an empty string or None to leave an empty space between nodes.

After placing the nodes, you can connect them via links like this:

diagram.add_link("a", "b", stroke="red")

Note that the Diagram class offers an add_links method as well, which lets you create links en masse (all having the same attributes).

After you have finished building your diagram, use the write_svg() function to write the SVG file:

write_svg(diagram, "hello.svg")

### Using the Builder class

The Builder class lets you create Diagram objects from Python dictionaries like the ones you load from a YAML file. The add() method imports a complete diagram definition into the builder:

import yaml
from orthogram import Builder, write_svg

builder = Builder()
with open("diagram.yaml") as f:
write_svg(builder.diagram, "diagram.svg")

If you have to be more specific, Builder provides the following methods:

Do one

Do many

configure_diagram()

For example:

node_def = {
'label': "Hello",
'fill': "yellow",
'stroke': "none",
}
builder.add_node('hello', node_def)

Use the help() Python function to read the documentation of each method. Note that you have to do the imports in a logical order: you must import the styles before using them, place the nodes before linking them etc.

The diagram property of a Builder object holds the diagram which is being built. If you want to use the Diagram API on it, as described in the previous section, after or while using the builder, you can certainly do so.

### Convenience functions

The load_ddf() and translate() functions are provided as shortcuts:

from orthogram import load_ddf, translate, write_svg

# You can do this:
write_svg(diagram, "diagram.svg")

# or just this:
translate("diagram.yaml", "diagram.svg")

## Project details

Uploaded source
Uploaded py3