Element pl-graph: Displaying graphs from data

This question was created to show the graph rendering capabilities of the pl-graph element.

Here's a static graph that was created by hand with DOT markup:

1
2
3
4
5
6
<pl-graph>
digraph G {
  A -> B
  B -> C
}
</pl-graph>
G A A B B A->B C C B->C

Here's a graph with randomly-generated edge weights. Because here the graph is specified in the question.html, parameters can be templated using Mustache.

1
2
3
4
5
6
<pl-graph>
digraph G {
  A -> B [label="{{ params.weight1 }}"]
  B -> C [label="{{ params.weight2 }}"]
}
</pl-graph>
G A A B B A->B  10 C C B->C  1

Here's a graph created from a randomly-generated adjacency matrix. By default, weights will be displayed when they are not 0 or 1. The matrix and labels can be specified with params-name and params-name-labels, respectively.

1
2
3
4
mat = np.random.random((3, 3))
mat = mat / la.norm(mat, 1, axis=0)
data['params']['labels'] = pl.to_json(['A', 'B', 'C'])
data['params']['matrix'] = pl.to_json(mat)
1
2
<pl-matrix-latex params-name="matrix"></pl-matrix-latex>
<pl-graph params-name="matrix" params-name-labels="labels"></pl-graph>
\begin{bmatrix} 0.53 & 0.39 & 0.18\\ 0.17 & 0.22 & 0.55\\ 0.30 & 0.39 & 0.27\\\end{bmatrix}
A A A->A 0.53 B B A->B 0.17 C C A->C 0.30 B->A 0.39 B->B 0.22 B->C 0.39 C->A 0.18 C->B 0.55 C->C 0.27

To force no weights being displayed, the attribute weights can be set to "false". Here is the same graph with no edge weights.

A A A->A B B A->B C C A->C B->A B->B B->C C->A C->B C->C

To force the graph to be undirected, the attribute directed can be set to "false". Here is an undirected graph. The input matrix must be symmetric in this case.

\begin{bmatrix} 0.53 & 0.39 & 0.30\\ 0.39 & 0.22 & 0.55\\ 0.30 & 0.55 & 0.27\\\end{bmatrix}
A A A--A 0.53 B B B--A 0.39 B--B 0.22 C C C--A 0.30 C--B 0.55 C--C 0.27

The formatting of the weight labels can also be changed with the weights-digits and weights-presentation-type attributes. This example has weights-digits="5".

A A A->A 0.53021 B B A->B 0.16863 C C A->C 0.30116 B->A 0.38961 B->B 0.22245 B->C 0.38794 C->A 0.18313 C->B 0.54914 C->C 0.26774

Here is another graph with binary 0 or 1 weights. These weights will not be displayed unless specified with weights="true".

\begin{bmatrix} 0 & 0 & 0\\ 0 & 0 & 0\\ 1 & 0 & 0\\\end{bmatrix}
0 0 2 2 0->2 1 1

Here is a graph with negative weights. These weights will not be displayed unless specified with negative-weights="true". In the input matrix, to hide an edge, simply set the corresponding entry to None.

1
2
3
array([[None, 2, -1.5],
       [-1.1, -1.4, None],
       [None, 4, -2]], dtype=object)
A A B B A->B -1.10 B->A 2.00 B->B -1.40 C C B->C 4.00 C->A -1.50 C->C -2.00

The pl-graph element has the ability to be extended on a course level to create graphs based on custom inputs. This course extension located in elementExtensions/pl-graph/edge-inc-matrix adds the capability of rendering edge-incidence matrices as graphs.

\begin{bmatrix} -1 & 0 & 1 & 0\\ 0 & -1 & 1 & 0\\ 1 & 0 & 0 & -1\\ 0 & 1 & -1 & 0\\\end{bmatrix}
0 0 2 2 0->2 1 1 2->1 1->2 3 3 3->0

For more information on how to create extensions, check the extension documentation and graph element documentation.

Here's a graph created from a randomly-generated networkx graph. To specify the use of a networkx graph, set params-type="networkx". The graph can be specified with params-name. To make it accessible to screen readers, set aria-label to a description of the graph; since a static label can't describe a randomly-generated graph, that description is generated in server.py from the graph data.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
random_graph = nx.gnm_random_graph(5, 6)

for in_node, out_node, edge_data in random_graph.edges(data=True):
    edge_data['label'] = random.choice(string.ascii_lowercase)

data['params']['random-graph'] = pl.to_json(random_graph)

edges = ", ".join(
    f"{in_node} to {out_node} (labeled {edge_data['label']})"
    for in_node, out_node, edge_data in random_graph.edges(data=True)
)
data['params']['random_graph_alt'] = (
    f"Undirected graph with {random_graph.number_of_nodes()} nodes "
    f"and {random_graph.number_of_edges()} edges: {edges}."
)
1
<pl-graph params-type="networkx" params-name="random-graph" aria-label="{{ params.random_graph_alt }}"></pl-graph>

Rendering directed graphs and multigraphs is supported natively with networkx. Here, we also set rankdir="LR" in the constructor for the graph.

1 1 2 2 1->2 1->2 3 3 1->3 2->1 2->3 3->2

The color of each node or edge in a networkx graph can be set by assigning the 'color' attribute in the associated data dictionary for each object. In the example below, we've set the color of each edge to 'blue' and used different colors for nodes in different layers.

0 0 5 5 0--5 6 6 0--6 7 7 0--7 8 8 0--8 9 9 0--9 10 10 5--10 11 11 5--11 12 12 5--12 13 13 5--13 6--10 6--11 6--12 6--13 7--10 7--11 7--12 7--13 8--10 8--11 8--12 8--13 9--10 9--11 9--12 9--13 14 14 10--14 15 15 10--15 16 16 10--16 11--14 11--15 11--16 12--14 12--15 12--16 13--14 13--15 13--16 1 1 1--5 1--6 1--7 1--8 1--9 2 2 2--5 2--6 2--7 2--8 2--9 3 3 3--5 3--6 3--7 3--8 3--9 4 4 4--5 4--6 4--7 4--8 4--9 17 17 14--17 18 18 14--18 15--17 15--18 16--17 16--18 19 19 17--19 20 20 17--20 21 21 17--21 22 22 17--22 18--19 18--20 18--21 18--22 23 23 19--23 24 24 19--24 25 25 19--25 26 26 19--26 20--23 20--24 20--25 20--26 21--23 21--24 21--25 21--26 22--23 22--24 22--25 22--26 27 27 23--27 28 28 23--28 29 29 23--29 24--27 24--28 24--29 25--27 25--28 25--29 26--27 26--28 26--29

The source-file-name attribute allows loading graph content from an external file. This is particularly useful for graphs with complex DOT syntax, such as record-based nodes that use angle brackets <>, which can cause issues when embedded directly in HTML.

1
<pl-graph source-file-name="record-graph.dot"></pl-graph>

The file record-graph.dot contains:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// Example of record-based nodes
// Reference: https://graphviz.org/doc/info/shapes.html#record
digraph structs {
    node [shape=record];
    struct1 [label="<f0> left|<f1> middle|<f2> right"];
    struct2 [label="<f0> one|<f1> two"];
    struct3 [label="hello\nworld |{ b |{c|<here> d|e}| f}| g | h"];
    struct1:f1 -> struct2:f0;
    struct1:f2 -> struct3:here;
}
structs struct1 left middle right struct2 one two struct1:f1->struct2:f0 struct3 hello world b c d e f g h struct1:f2->struct3:here

Correct answer

Student view placeholder

In student views this area is used for assessment and score info.
Tools

Staff information

Question

Title:
Element pl-graph: Displaying graphs from data

Variant

Started at:
2026-08-05 00:40:41 (CDT)
Duration:
0s
Show/Hide answer
{}
History
dec frac
rad deg