Edge Attributes

Splines

When connection points are provided, the splines of an SVGEdge default to cubic Bézier curves.

from sp_svg_diagram import SVGDiagram, SVGEdge

diagram = SVGDiagram()
splines_types = [
    SVGEdge.SPLINES_SPLINE,
    SVGEdge.SPLINES_LINE,
]
for i, splines in enumerate(splines_types):
    y = i * 80.0
    tail_id, head_id = f"A{i}", f"B{i}"
    node1 = diagram.add_node(tail_id)
    node1.set_center(0, y)
    node1.set_label("A")
    node2 = diagram.add_node(head_id)
    node2.set_center(150, y)
    node2.set_label("B")
    edge = diagram.add_edge(tail_id, head_id)
    edge.set_splines(splines)
    edge.add_connection_point(50, y - 20)
    edge.add_connection_point(100, y + 20)
    edge.set_label(splines)
svg = diagram.render()
import { SVGDiagram, SVGEdge } from 'sp-svg-diagram';

const diagram = new SVGDiagram();
const splinesTypes = [
    SVGEdge.SPLINES_SPLINE,
    SVGEdge.SPLINES_LINE,
];
for (const [i, splines] of splinesTypes.entries()) {
    const y = i * 80.0;
    const tailID = `A${i}`;
    const headID = `B${i}`;
    const node1 = diagram.addNode(tailID);
    node1.setCenter(0, y);
    node1.setLabel("A");
    const node2 = diagram.addNode(headID);
    node2.setCenter(150, y);
    node2.setLabel("B");
    const edge = diagram.addEdge(tailID, headID);
    edge.setSplines(splines);
    edge.addConnectionPoint(50, y - 20);
    edge.addConnectionPoint(100, y + 20);
    edge.setLabel(splines);
}
const svg = diagram.render();
#include "svg_diagram.h"
#include <vector>
#include <format>
using namespace svg_diagram;

int main() {
    SVGDiagram diagram;
    const auto splinesTypes = std::vector{
        SVGEdge::SPLINES_SPLINE,
        SVGEdge::SPLINES_LINE,
    };
    for (int i = 0; i < static_cast<int>(splinesTypes.size()); i++) {
        const double y = i * 80.0;
        const auto tailNodeID = std::format("A{}", i);
        const auto headNodeID = std::format("B{}", i);
        const auto node1 = diagram.addNode(tailNodeID);
        node1->setCenter(0, y);
        node1->setLabel("A");
        const auto node2 = diagram.addNode(headNodeID);
        node2->setCenter(150, y);
        node2->setLabel("B");
        const auto edge = diagram.addEdge(tailNodeID, headNodeID);
        edge->setSplines(splinesTypes[i]);
        edge->addConnectionPoint(50, y - 20);
        edge->addConnectionPoint(100, y + 20);
        edge->setLabel(std::string(splinesTypes[i]));
    }
    diagram.render("splines.svg");
    return 0;
}

In the figure below, you can see the tangent directions of the curve at the connection points.

Arrow

You can set the arrow styles for the start and end points; by default, no arrows are applied.

from sp_svg_diagram import SVGDiagram, SVGEdge

diagram = SVGDiagram()
arrow_types = [
    SVGEdge.ARROW_NONE,
    SVGEdge.ARROW_NORMAL,
    SVGEdge.ARROW_EMPTY,
]
for i, arrow in enumerate(arrow_types):
    y = i * 60.0
    tail_id, head_id = f"A{i}", f"B{i}"
    node1 = diagram.add_node(tail_id)
    node1.set_center(0, y)
    node1.set_label("A")
    node2 = diagram.add_node(head_id)
    node2.set_center(150, y)
    node2.set_label("B")
    edge = diagram.add_edge(tail_id, head_id)
    edge.set_arrow_tail(SVGEdge.ARROW_NONE)
    edge.set_arrow_head(arrow)
    edge.set_label(arrow)
svg = diagram.render()
import { SVGDiagram, SVGEdge } from 'sp-svg-diagram';

const diagram = new SVGDiagram();
const arrowTypes = [
    SVGEdge.ARROW_NONE,
    SVGEdge.ARROW_NORMAL,
    SVGEdge.ARROW_EMPTY,
];
for (const [i, arrow] of arrowTypes.entries()) {
    const y = i * 60.0;
    const tailID = `A${i}`;
    const headID = `B${i}`;
    const node1 = diagram.addNode(tailID);
    node1.setCenter(0, y);
    node1.setLabel("A");
    const node2 = diagram.addNode(headID);
    node2.setCenter(150, y);
    node2.setLabel("B");
    const edge = diagram.addEdge(tailID, headID);
    edge.setArrowTail(SVGEdge.ARROW_NONE);
    edge.setArrowHead(arrow);
    edge.setLabel(arrow);
}
const svg = diagram.render();
#include "svg_diagram.h"
#include <vector>
#include <format>
using namespace svg_diagram;

int main() {
    SVGDiagram diagram;
    const auto arrowTypes = std::vector{
        SVGEdge::ARROW_NONE,
        SVGEdge::ARROW_NORMAL,
        SVGEdge::ARROW_EMPTY,
    };
    for (int i = 0; i < static_cast<int>(arrowTypes.size()); i++) {
        const double y = i * 60.0;
        const auto tailNodeID = std::format("A{}", i);
        const auto headNodeID = std::format("B{}", i);
        const auto node1 = diagram.addNode(tailNodeID);
        node1->setCenter(0, y);
        node1->setLabel("A");
        const auto node2 = diagram.addNode(headNodeID);
        node2->setCenter(150, y);
        node2->setLabel("B");
        const auto edge = diagram.addEdge(tailNodeID, headNodeID);
        edge->setArrowTail(SVGEdge::ARROW_NONE);
        edge->setArrowHead(std::string(arrowTypes[i]));
        edge->setLabel(std::string(arrowTypes[i]));
    }
    diagram.render("arrow.svg");
    return 0;
}

Label

By default, the text of an SVGEdge is positioned to the right of the arrow direction and centered along the edge (including the arrow length).

from sp_svg_diagram import SVGDiagram

diagram = SVGDiagram()
node1 = diagram.add_node("A")
node1.set_center(0, 0)
node1.set_label("A")
node2 = diagram.add_node("B")
node2.set_center(150, 0)
node2.set_label("B")
edge1 = diagram.add_edge("A", "B")
edge1.set_arrow_head()
edge1.set_label("A → B")
edge1.add_connection_point(76, 20)
edge2 = diagram.add_edge("B", "A")
edge2.set_arrow_head()
edge2.set_label("A ← B")
edge2.add_connection_point(76, -20)
svg = diagram.render()
import { SVGDiagram } from 'sp-svg-diagram';

const diagram = new SVGDiagram();
const node1 = diagram.addNode("A");
node1.setCenter(0, 0);
node1.setLabel("A");
const node2 = diagram.addNode("B");
node2.setCenter(150, 0);
node2.setLabel("B");
const edge1 = diagram.addEdge("A", "B");
edge1.setArrowHead();
edge1.setLabel("A → B");
edge1.addConnectionPoint(76, 20);
const edge2 = diagram.addEdge("B", "A");
edge2.setArrowHead();
edge2.setLabel("A ← B");
edge2.addConnectionPoint(76, -20);
const svg = diagram.render();
#include "svg_diagram.h"
using namespace svg_diagram;

int main() {
    SVGDiagram diagram;
    const auto node1 = diagram.addNode("A");
    node1->setCenter(0, 0);
    node1->setLabel("A");
    const auto node2 = diagram.addNode("B");
    node2->setCenter(150, 0);
    node2->setLabel("B");
    const auto edge1 = diagram.addEdge("A", "B");
    edge1->setArrowHead();
    edge1->setLabel("A → B");
    edge1->addConnectionPoint(76, 20);
    const auto edge2 = diagram.addEdge("B", "A");
    edge2->setArrowHead();
    edge2->setLabel("A ← B");
    edge2->addConnectionPoint(76, -20);
    diagram.render("label.svg");
    return 0;
}

Self Loop

There are some helper functions for drawing self-loops, which require specifying the height of the loop and the opening angle.

from sp_svg_diagram import SVGDiagram

diagram = SVGDiagram()
loop_height, loop_angle = 30.0, 30.0
node = diagram.add_node("A")
node.set_label("Self Loops")
edge1 = diagram.add_self_loop_to_left("A", loop_height, loop_angle)
edge1.set_label("Left")
edge1.set_arrow_head()
edge2 = diagram.add_self_loop_to_right("A", loop_height, loop_angle)
edge2.set_label("Right")
edge2.set_arrow_head()
edge3 = diagram.add_self_loop_to_top("A", loop_height, loop_angle)
edge3.set_label("Top")
edge3.set_arrow_head()
edge4 = diagram.add_self_loop_to_bottom("A", loop_height, loop_angle)
edge4.set_label("Bottom")
edge4.set_arrow_head()
svg = diagram.render()
import { SVGDiagram } from 'sp-svg-diagram';

const diagram = new SVGDiagram();
const loopHeight = 30.0, loopAngle = 30.0;
const node = diagram.addNode("A");
node.setLabel("Self Loops");
const edge1 = diagram.addSelfLoopToLeft("A", loopHeight, loopAngle);
edge1.setLabel("Left");
edge1.setArrowHead();
const edge2 = diagram.addSelfLoopToRight("A", loopHeight, loopAngle);
edge2.setLabel("Right");
edge2.setArrowHead();
const edge3 = diagram.addSelfLoopToTop("A", loopHeight, loopAngle);
edge3.setLabel("Top");
edge3.setArrowHead();
const edge4 = diagram.addSelfLoopToBottom("A", loopHeight, loopAngle);
edge4.setLabel("Bottom");
edge4.setArrowHead();
const svg = diagram.render();
#include "svg_diagram.h"
using namespace svg_diagram;

int main() {
    SVGDiagram diagram;
    constexpr double loopHeight = 30.0, loopAngle = 30.0;
    const auto node = diagram.addNode("A");
    node->setLabel("Self Loops");
    const auto edge1 = diagram.addSelfLoopToLeft("A", loopHeight, loopAngle);
    edge1->setLabel("Left");
    edge1->setArrowHead();
    const auto edge2 = diagram.addSelfLoopToRight("A", loopHeight, loopAngle);
    edge2->setLabel("Right");
    edge2->setArrowHead();
    const auto edge3 = diagram.addSelfLoopToTop("A", loopHeight, loopAngle);
    edge3->setLabel("Top");
    edge3->setArrowHead();
    const auto edge4 = diagram.addSelfLoopToBottom("A", loopHeight, loopAngle);
    edge4->setLabel("Bottom");
    edge4->setArrowHead();
    diagram.render(OUTPUT_DIR + "self_loop.svg");
    return 0;
}

Color

You can set the color of the line and the font. The arrow color matches the line color and is independent of fill color.

from sp_svg_diagram import SVGDiagram, SVGEdge

diagram = SVGDiagram()
node1 = diagram.add_node("A")
node1.set_center(0, 0)
node1.set_label("A")
node2 = diagram.add_node("B")
node2.set_center(150, 0)
node2.set_label("B")
edge = diagram.add_edge("A", "B")
edge.set_arrow_head(SVGEdge.ARROW_NORMAL)
edge.set_arrow_tail(SVGEdge.ARROW_EMPTY)
edge.set_label("color")
edge.set_color("red")
edge.set_font_color("blue")
svg = diagram.render()
import { SVGDiagram, SVGEdge } from 'sp-svg-diagram';

const diagram = new SVGDiagram();
const node1 = diagram.addNode("A");
node1.setCenter(0, 0);
node1.setLabel("A");
const node2 = diagram.addNode("B");
node2.setCenter(150, 0);
node2.setLabel("B");
const edge = diagram.addEdge("A", "B");
edge.setArrowHead(SVGEdge.ARROW_NORMAL);
edge.setArrowTail(SVGEdge.ARROW_EMPTY);
edge.setLabel("color");
edge.setColor("red")
edge.setFontColor("blue")
const svg = diagram.render();
#include "svg_diagram.h"
using namespace svg_diagram;

int main() {
    SVGDiagram diagram;
    const auto node1 = diagram.addNode("A");
    node1->setCenter(0, 0);
    node1->setLabel("A");
    const auto node2 = diagram.addNode("B");
    node2->setCenter(150, 0);
    node2->setLabel("B");
    const auto edge = diagram.addEdge("A", "B");
    edge->setArrowHead(SVGEdge::ARROW_NORMAL);
    edge->setArrowTail(SVGEdge::ARROW_EMPTY);
    edge->setLabel("color");
    edge->setColor("red");
    edge->setFontColor("blue");
    diagram.render("color.svg");
    return 0;
}

Pen Width & Margin

The thickness of the line, which also affects the arrow.

from sp_svg_diagram import SVGDiagram, SVGEdge

diagram = SVGDiagram()
node1 = diagram.add_node("A")
node1.set_center(0, 0)
node1.set_label("A")
node2 = diagram.add_node("B")
node2.set_center(150, 0)
node2.set_label("B")
edge = diagram.add_edge("A", "B")
edge.set_arrow_head(SVGEdge.ARROW_NORMAL)
edge.set_arrow_tail(SVGEdge.ARROW_EMPTY)
edge.set_label("penWidth=3")
edge.set_pen_width(3)
edge.set_margin(4, 4)
svg = diagram.render()
import { SVGDiagram, SVGEdge } from 'sp-svg-diagram';

const diagram = new SVGDiagram();
const node1 = diagram.addNode("A");
node1.setCenter(0, 0);
node1.setLabel("A");
const node2 = diagram.addNode("B");
node2.setCenter(150, 0);
node2.setLabel("B");
const edge = diagram.addEdge("A", "B");
edge.setArrowHead(SVGEdge.ARROW_NORMAL);
edge.setArrowTail(SVGEdge.ARROW_EMPTY);
edge.setLabel("penWidth=3");
edge.setPenWidth(3);
edge.setMargin(4, 4);
const svg = diagram.render();
#include "svg_diagram.h"
using namespace svg_diagram;

int main() {
    SVGDiagram diagram;
    const auto node1 = diagram.addNode("A");
    node1->setCenter(0, 0);
    node1->setLabel("A");
    const auto node2 = diagram.addNode("B");
    node2->setCenter(150, 0);
    node2->setLabel("B");
    const auto edge = diagram.addEdge("A", "B");
    edge->setArrowHead(SVGEdge::ARROW_NORMAL);
    edge->setArrowTail(SVGEdge::ARROW_EMPTY);
    edge->setLabel("penWidth=3");
    edge->setPenWidth(3);
    edge->setMargin(4);
    diagram.render("pen_width.svg");
    return 0;
}

Font

from sp_svg_diagram import SVGDiagram

diagram = SVGDiagram()
    node1 = diagram.add_node("A")
    node1.set_center(0, 0)
    node1.set_label("A")
    node2 = diagram.add_node("B")
    node2.set_center(150, 0)
    node2.set_label("B")
    edge = diagram.add_edge("A", "B")
    edge.set_label("font")
    edge.set_margin(4, 4)
    edge.set_font_name("Consolas")
    edge.set_font_size(16)
    edge.set_font("Consolas,'Courier New',monospace", 16)
    svg = diagram.render()
import { SVGDiagram } from 'sp-svg-diagram';

const diagram = new SVGDiagram();
const node1 = diagram.addNode("A");
node1.setCenter(0, 0);
node1.setLabel("A");
const node2 = diagram.addNode("B");
node2.setCenter(150, 0);
node2.setLabel("B");
const edge = diagram.addEdge("A", "B");
edge.setLabel("font");
edge.setMargin(4, 4);
edge.setFontName("Consolas");
edge.setFontSize(16);
edge.setFont("Consolas,'Courier New',monospace", 16);
const svg = diagram.render();
#include "svg_diagram.h"
using namespace svg_diagram;

int main() {
    SVGDiagram diagram;
    const auto node1 = diagram.addNode("A");
    node1->setCenter(0, 0);
    node1->setLabel("A");
    const auto node2 = diagram.addNode("B");
    node2->setCenter(150, 0);
    node2->setLabel("B");
    const auto edge = diagram.addEdge("A", "B");
    edge->setLabel("font");
    edge->setMargin(4);
    edge->setFontName("Consolas");
    edge->setFontSize(16);
    edge->setFont("Consolas,'Courier New',monospace", 16);
    diagram.render("font.svg");
    return 0;
}

Stroke Style

The default edge style is solid, rendered as solid lines. Two dashed styles are also available: dashed and dotted. These three styles are mutually exclusive, and the one specified last takes precedence.

from sp_svg_diagram import SVGDiagram

diagram = SVGDiagram()
labels = ["solid", "dashed", "dotted"]
for i, label in enumerate(labels):
    y = i * 60.0
    tail_id, head_id = f"A{i}", f"B{i}"
    node1 = diagram.add_node(tail_id)
    node1.set_center(0, y)
    node1.set_label("A")
    node2 = diagram.add_node(head_id)
    node2.set_center(150, y)
    node2.set_label("B")
    edge = diagram.add_edge(tail_id, head_id)
    edge.set_arrow_head()
    edge.set_label(label)
    if i == 1:
        edge.append_style_dashed()
    elif i == 2:
        edge.append_style_dotted()
svg = diagram.render()
import { SVGDiagram } from 'sp-svg-diagram';

const diagram = new SVGDiagram();
const labels = ["solid", "dashed", "dotted"];
for (const [i, label] of labels.entries()) {
    const y = i * 60.0;
    const tailID = `A${i}`;
    const headID = `B${i}`;
    const node1 = diagram.addNode(tailID);
    node1.setCenter(0, y);
    node1.setLabel("A");
    const node2 = diagram.addNode(headID);
    node2.setCenter(150, y);
    node2.setLabel("B");
    const edge = diagram.addEdge(tailID, headID);
    edge.setArrowHead();
    edge.setLabel(label);
    if (i === 1) {
        edge.appendStyleDashed();
    } else if (i === 2) {
        edge.appendStyleDotted();
    }
}
const svg = diagram.render();
#include "svg_diagram.h"
#include <format>
#include <vector>
#include <string>
using namespace svg_diagram;

int main() {
    SVGDiagram diagram;
    const auto labels = std::vector<std::string>({"solid", "dashed", "dotted"});
    for (int i = 0; i < static_cast<int>(labels.size()); i++) {
        const double y = i * 60.0;
        const auto tailNodeID = std::format("A{}", i);
        const auto headNodeID = std::format("B{}", i);
        const auto node1 = diagram.addNode(tailNodeID);
        node1->setCenter(0, y);
        node1->setLabel("A");
        const auto node2 = diagram.addNode(headNodeID);
        node2->setCenter(150, y);
        node2->setLabel("B");
        const auto edge = diagram.addEdge(tailNodeID, headNodeID);
        edge->setArrowHead();
        edge->setLabel(labels[i]);
        if (i == 1) {
            edge->appendStyleDashed();
        } else if (i == 2) {
            edge->appendStyleDotted();
        }
    }
    diagram.render("stroke_style.svg");
    return 0;
}