pl-graph element¶
Using the PyGraphviz library, create Graphviz DOT visualizations.
Sample elements¶

<pl-graph> digraph G { A -> B } </pl-graph>

<pl-graph params-name="matrix" params-name-labels="labels"></pl-graph>
import prairielearn as pl
import numpy as np
def generate(data):
mat = np.random.random((3, 3))
mat = mat / np.linalg.norm(mat, 1, axis=0)
data["params"]["labels"] = pl.to_json(["A", "B", "C"])
data["params"]["matrix"] = pl.to_json(mat)
<pl-graph params-type="networkx" params-name="random-graph"></pl-graph>
import random
import string
import prairielearn as pl
import networkx as nx
def generate(data):
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)
Customizations¶
| Attribute | Type | Default | Description |
|---|---|---|---|
aria-label |
string | — | A short text alternative describing the graph, read by screen readers. See the accessibility section. |
aria-description |
string | — | A longer, more detailed text description of the graph, read by screen readers. Requires aria-label. See the accessibility section. |
directed |
boolean | true | Whether to treat edges in an adjacency matrix as directed or undirected. If set to false, then edges will be rendered as undirected. The input adjacency matrix must be symmetric if this is set to false. |
directory |
string | "." |
Directory where the source file is located. Can be "." (question directory), "clientFilesCourse", or "serverFilesCourse". |
engine |
string | dot | The rendering engine to use; supports "circo", "dot", "fdp", "neato", "osage", and "twopi". |
log-warnings |
boolean | true | Whether to log warnings that occur during Graphviz rendering. |
negative-weights |
boolean | false | Whether to recognize negative weights in an adjacency matrix. If set to false, then all weights at most 0 are ignored (not counted as an edge). If set to true, then all weights that are not None are recognized. |
params-name |
string | — | The name of a parameter containing the data to use as input. Data type to use depends on params-type attribute. |
params-name-labels |
string | — | When using an adjacency matrix, the parameter that contains the labels for each node. |
params-type |
string | "adjacency-matrix" |
Which backend to use for rendering a graph from data. By default, only adjacency-matrix and networkx exist, but custom types can be added through extensions. |
source-file-name |
string | — | Name of the file to load graph content from. If provided, the file content will be used instead of the element's inner HTML. Useful for complex graphs with special characters like angle brackets in record-based nodes. |
weights |
boolean | — | When using an adjacency matrix, whether to show the edge weights. By default, will automatically show weights for stochastic matrices (when they are not binary 0/1). |
weights-digits |
integer | 2 | When using an adjacency matrix, how many digits to show for the weights. |
weights-presentation-type |
string | "f" |
Number display format for the weights when using an adjacency matrix. If weights-presentation-type is "sigfig", each number is formatted using the to_precision module to digits significant figures. Otherwise, each number is formatted as {:.{digits}{presentation-type}}. |
Migrating from deprecated attributes¶
The following deprecated attribute is still supported for backward compatibility:
| Old syntax | New syntax |
|---|---|
params-name-matrix="<name>" |
params-name="<name>" |
Details¶
Note that using networkx for rendering, attributes from the input networkx graph are retained when creating a Graphviz DOT visualization. As a result, it is possible to set node and edge properties such as color, line weight, as part of the input graph and have these reflected in the rendering. These include global properties of the graph, such as the rankdir used in rendering. See the Graphviz documentation on attributes for more information on what attributes are supported. The currently used Graphviz version is 2.44.0.
The source-file-name attribute is particularly useful when working with static graphs that contain special characters like angle brackets (<>), which are used in record-based nodes but can interfere with HTML parsing. By placing the graph content in an external file, you can avoid the need to escape these characters.
Accessibility¶
A pl-graph renders as an SVG. Graphviz adds a <title> to every node and edge, but those are hover tooltips, not a description of the graph as a whole, so a screen reader user gets no meaningful information by default. How you provide an accessible equivalent depends on how the graph is used.
Informational graphs¶
If the graph conveys information (rather than being the thing a student must interpret to answer), give it a text alternative with aria-label. When aria-label is set, the graph is exposed to assistive technologies as a single labeled image, which also hides Graphviz's per-node titles. Use aria-description for additional detail if needed, though the aria-description attribute has inconsistent screen reader support and requires aria-label to also be set.
For a static graph, describe it directly:
<pl-graph aria-label="Directed graph with an edge from A to B and from B to C">
digraph G { A -> B -> C }
</pl-graph>
For a randomly generated graph, a fixed string like "a random graph" tells a screen reader user nothing about what was actually drawn. Generate the description from the same data so it always matches the graph:
import prairielearn as pl
import networkx as nx
def generate(data):
graph = nx.gnm_random_graph(5, 6)
data["params"]["graph"] = pl.to_json(graph)
edges = ", ".join(f"{u} to {v}" for u, v in graph.edges())
data["params"]["graph_alt"] = (
f"Undirected graph with {graph.number_of_nodes()} nodes "
f"and {graph.number_of_edges()} edges: {edges}."
)
<pl-graph params-type="networkx" params-name="graph" aria-label="{{ params.graph_alt }}"></pl-graph>
Presenting the same information in an accessible format¶
Packing a large graph into a single aria-label string produces a long, unstructured announcement that is hard to navigate. Often the better option is to also present the data in a natively accessible format that every student benefits from — for example an adjacency matrix rendered with pl-matrix-latex, or an edge table:
<pl-graph
params-type="networkx"
params-name="graph"
aria-label="Undirected graph; its edges are listed in the table below"
></pl-graph>
<table>
<caption>
Edges of the graph above
</caption>
<thead>
<tr>
<th scope="col">From</th>
<th scope="col">To</th>
</tr>
</thead>
<tbody>
{{#params.edge_rows}}
<tr>
<td>{{from}}</td>
<td>{{to}}</td>
</tr>
{{/params.edge_rows}}
</tbody>
</table>
Graphs that are the question¶
If a student must read the graph to answer (for example, "give the adjacency matrix of the graph below"), a descriptive aria-label is not appropriate. It appears in the page source, so it would reveal the answer, and no text alternative can convey the graph in a form the student is expected to reason about. Such a question is not accessible to screen reader users as-is; provide an alternative version of the question instead.
Example implementations¶
Extension API¶
Custom values for params-type can be added with element extensions. Each custom type is defined as a function that takes as input the element and data values and returns processed DOT syntax as output.
A minimal type function can look something like:
def custom_type(element, data):
return "graph { a -- b; }"
In order to register these custom types, your extension should define the global backends dictionary. This will map a value of params-type to your function above:
backends = {
'my-custom-type': custom_type
}
This will automatically get picked up when the extension gets imported. If your extension needs extra attributes to be defined, you may optionally define the global optional_attribs array that contains a list of attributes that the element may use.
For a full implementation, check out the edge-inc-matrix extension in the exampleCourse.
See also¶
- External: the DOT language reference
pl-figurefor displaying static or dynamically generated graphics.pl-file-downloadfor allowing either static or dynamically generated files to be downloaded.