Plotting

This notebook can be downloaded here.

# The import will work if the package was installed using pip.
import pyrigi.frameworkDB as frameworks
import pyrigi.graphDB as graphs
from pyrigi import Graph, Framework

Methods Graph.plot() and Framework.plot() offer various plotting options. The default behaviour is the following:

G = Graph([(0,1), (1,2), (2,3), (0,3)])
G.plot()
../../_images/2e71ccf4332597571dd15dda0298ea74ae3a08a48dacb9c560ea93d914fbb709.png
F = Framework(G, {0: (0,0), 1: (1,1), 2: (3,1), 3: (2,0)})
F.plot()
../../_images/c09dcd2599b560705680b0d3e6cf5526dad10b51bf0200ff05b76aa489b86b91.png

Graph layouts

By default, a placement is generated using spring_layout().

G = graphs.ThreePrism()
G.plot()
../../_images/29c5494e55231ba8af78d55ac1002a72aa3a6021f4d315d6c5873c098eebf4e6.png

Other options use random_layout(), circular_layout() or planar_layout():

G.plot(layout="random")
G.plot(layout="circular")
G.plot(layout="planar")
../../_images/7a39500f5437ae4d32399cbf1834851702877f9cf4fde29aa183b8a47024bb44.png ../../_images/73e699ab5b19e45350edeecf1175aac2eba7858b5da0b1987aad193367f39bbf.png ../../_images/12850cc88c4f4c517e1ce2945d539233c5d1645b7f30ddc190b9258863a53ecc.png

One can also specify a placement of the vertices explicitly:

G.plot(placement={0: (0, 0), 1: (0, 2), 2: (2, 1), 3: (6, 0), 4: (6, 2), 5: (4, 1)})
../../_images/2f7ea190bd7416791299b40bf5cbd0023efc05b1a59ebaf89229c2c31b5d3e1b.png

Canvas options

The size of the canvas can be specified.

S = frameworks.Square()
S.plot(canvas_width=2)
../../_images/451898ed5b656dba724a78f3685a792124ffba42881815c49d1ca19684cbd0cf.png
S.plot(canvas_height=2)
../../_images/568a5c741501b469dca6fbb9626e8484d61404c98ef3c4f560daf7eeaf5708de.png
S.plot(canvas_width=2, canvas_height=2)
../../_images/d56d2daa44924635b7c93c49ed668e55bdecbcf429f3669f3f54f6d17b748e0c.png

Also the aspect ratio:

S.plot(aspect_ratio=0.4)
../../_images/3d805e04d866aac3b4dc0b77395c48550fe456c5190b77de1458f0f92e02608c.png

Formatting

There are various options to format a plot.

Vertex color/size or label color/size can be changed.

G = Graph([[0,1]])
formatting = {
    "placement": {0: [0,0], 1: [1,0]},
    "canvas_height": 1,
}
G.plot(vertex_labels=False, vertex_color='green', **formatting)
G.plot(vertex_size=1500, font_size=30, font_color='#FFFFFF', **formatting)
../../_images/74109d030c99ed2e272373994305fe3faf8360e1c09ac762bb34159f946384d9.png ../../_images/d89f2d4db25891e45e2071e44ff9cbe9bf23cdfff790540cd49a5170463219bd.png

There are various styles of vertices and edges.

formatting["vertex_labels"] = False
G.plot(vertex_shape='s', edge_style='-', **formatting)
G.plot(vertex_shape='o', edge_style='--', **formatting)
G.plot(vertex_shape='^', edge_style='-.', **formatting)
G.plot(vertex_shape='>', edge_style=':', **formatting)
G.plot(vertex_shape='v', edge_style='solid', **formatting)
G.plot(vertex_shape='<', edge_style='dashed', **formatting)
G.plot(vertex_shape='d', edge_style='dashdot', **formatting)
G.plot(vertex_shape='p', edge_style='dotted', **formatting)
G.plot(vertex_shape='h', edge_width=3, **formatting)
G.plot(vertex_shape='8', edge_width=5, **formatting)
../../_images/cb73b97abd09b1844f26db6a25a41ab89cd344ee59cd86988884fd05f93b5cd9.png ../../_images/155668ad562c1d3012b529c3f68ae6ec8d3c24beb11cbf8edde3878577dbe80a.png ../../_images/fcfef38372f8efbb92cb83d1473c007a731c1623102847717303cf14ddae3af0.png ../../_images/eb432bdcb7fd4a654850ae832e53d3845da546a35f1eeef6f2f47e23488eaad2.png ../../_images/e3bec6b71e55bef280fa01352e05c5554c487db466518a962c9f7575adc0c13d.png ../../_images/a7df481a0b1e50e40f71996fceb1a071340bf23b795ea15698e9bba5b34d20b1.png ../../_images/1306cb58d8de2d617dd35d791a4f316b4f1b244a0677102adf5208af4e8fee51.png ../../_images/4cf46abd4341e2dcd079034e5fb97f33e97d05e70044676ece8f017c406edb4a.png ../../_images/46cba9b57639767f4c0e755f86001ac4f3f4c7ee7da7c51737543d13b4f35796.png ../../_images/f51451096b7ef608fbcc4039604b8082e0dac1e52201ea8ac580005f9deef4ea.png

Edge coloring

The color of all edges can be changed.

P = graphs.Path(6)
formatting = {
    "placement": {v: [v, 0] for v in P.vertex_list()},
    "canvas_height": 2,
    "edge_width": 5,
}
P.plot(edge_color='red', **formatting)
../../_images/1c8661fca759653436b71929f4570e499ebd5035b8ae664c4f161c20a8b92ce5.png

If a partition of the edges is specified, then each part is colored differently.

P.plot(edge_color=[[[0, 1], [2, 3]], [[1, 2]], [[5, 4], [4, 3]]], **formatting)
../../_images/052a384fe9bae6f329a3931afb1b3449c9acdf7a8ec6b50d64bd57c955fee21f.png

If the partition is incomplete, the missing edges are black.

P.plot(edge_color=[[[0, 1], [2, 3]], [[5, 4], [4, 3]]], **formatting)
../../_images/ae7eeed8b8b665a13a91b405d7ff0f4c56d215909d97e44f8a5bab0b0cd520b4.png

Visually distinct colors are generated using the package distinctipy.

P30 = graphs.Path(30)
P30.plot(
    vertex_size=15,
    vertex_labels=False,
    edge_color=[[e] for e in P30.edge_list()],
    edge_width=3
)
../../_images/dbfa07e54b51ed13d6140c09308558aac754ad3b9090012009231bb7f9fa6f8b.png

Another possibility is to provide a dictionary assigning to a color a list of edges. Missing edges are again black.

P.plot(
    edge_color={
        "yellow": [[0, 1], [2, 3]],
        "#ABCDEF": [[5, 4], [4, 3]]
    },
    **formatting
)
../../_images/ff0d70948973236a9b06f09a9a2cec76a80d366785d6161d10cc32ab5a29564d.png

Framework plotting

Currently, only plots of frameworks in the plane are implemented.

F = frameworks.Complete(9)
F.plot()
../../_images/7a4b0b2235019484395e265f021681f3bf566785fc5d0f4c83c111d15a1a553d.png

The same formatting options as for graphs are available for frameworks.

F = frameworks.Complete(9)
F.plot(
    vertex_labels=False,
    vertex_color='#A2B4C6',
    edge_style='dashed',
    edge_width=2,
    edge_color={"pink": [[0,1],[3,6]], "lightgreen": [[2, 3], [3, 5]]}
)
../../_images/1703d2ab75038b68c453682a9014dd8d1e710aaf4f3ac3c387cc9da2e425a162.png

Infinitesimal Flexes

It is possible to include infinitesimal flexes in the plot. With the keyword inf_flex=n, we can pick the n-th nontrivial infinitesimal flex from a basis of the rigidity matrix’s kernel. There are several keywords that allow us to alter the style of the drawn arrows.

G = Graph([[0, 1], [0, 2], [1, 2], [2, 3], [2, 4], [3, 4]])
p = {0: [6, 8], 1: [6, -14], 2: [0, 0], 3: [-4, 4], 4: [-4, -4]}
F = Framework(G, p)
F.plot(
    inf_flex=0,
    flex_width=4,
    flex_length=0.25,
    flex_color="darkgrey",
    flex_style="-",
    flex_arrowsize=15
)
../../_images/f6ece9bebfc51eb3cba6afb47fe4de2cb792bc415696eeb14b4e34359df68f86.png

It is also possible to provide a specific infinitesimal flex with the following chain of commands:

F = frameworks.ThreePrism(realization="flexible")
flex = F.nontrivial_inf_flexes()[0]
F.plot(inf_flex=flex)
../../_images/6c0442fc6deb67beb3a1b64e37c79dffeb5859729a0dd9dc02b36b54f3ae2e65.png

It is important to use the same order of the vertices of F as Graph.vertex_list() when providing the infinitesimal flex as a Matrix. To circumvent that, we also support adding an infinitesimal flex as a dict[Vertex, Vector]:

F = frameworks.Square()
flex = {0: (1, -1), 1: (1, 1), 2: (-1, 1), 3: (-1, -1)}
F.plot(inf_flex=flex)
../../_images/85261f1e8d90b1497a61cff6ee2e3221a337020dd18360053eda1092ff6b33ca.png