Skip to content

Commit 5c64e4b

Browse files
authored
Merge pull request #56 from petercorke/doc/vertex-details
docs: what a vertex holds (edge lists, with example and figure)
2 parents b965468 + f0ad331 commit 5c64e4b

1 file changed

Lines changed: 136 additions & 0 deletions

File tree

‎docs/source/edges_vertices.rst‎

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,142 @@ For the directed case, each vertex maintains two edge lists: a list of outgoing
1515
The graph class provides methods for adding and removing vertices and edges (see :doc:`modification`)
1616
and for querying its structure (see :doc:`analysis`).
1717

18+
What a vertex holds
19+
~~~~~~~~~~~~~~~~~~~~
20+
21+
22+
Each vertex has **two** private edge lists, plus a back-pointer to its graph.
23+
24+
.. list-table::
25+
:header-rows: 1
26+
:widths: 15 55 30
27+
28+
* - Attribute
29+
- For undirected graphs
30+
- For directed graphs
31+
* - ``_edgelist``
32+
- the edges *incident on* it
33+
- the edges *leaving* it
34+
* - ``_inlist``
35+
- empty
36+
- the edges *entering* it
37+
* - ``_graph``
38+
- the graph it belongs to (``None`` if standalone)
39+
- the graph it belongs to (``None`` if standalone)
40+
41+
Every list entry is a reference to the same :class:`~pgraph.PGraph.Edge` class object, and
42+
there is exactly one edge object for each edge in the graph.
43+
44+
* **Undirected:** one list does everything, since an undirected edge is both "out"
45+
and "in". That is also why a loop is stored twice, once for each end, and why it
46+
counts 2 towards ``degree``.
47+
* **Directed:** the two lists are the out-list and the in-list. A loop sits once in
48+
each, so ``degree`` (in + out) is 2 there too.
49+
50+
An example, as lists
51+
~~~~~~~~~~~~~~~~~~~~~~
52+
53+
For these simple graphs
54+
55+
.. plot::
56+
:include-source: no
57+
:alt: the example graph drawn as an undirected and as a directed graph: two parallel edges e1 and e2 from a to b, e3 from b to c and a loop e4 on c
58+
59+
import matplotlib.pyplot as plt
60+
from matplotlib.patches import Circle, FancyArrowPatch
61+
62+
pos = {"a": (0.0, 0.0), "b": (2.0, 0.0), "c": (4.0, 0.0)}
63+
# (name, from, to, curvature, label offset): e1 and e2 are parallel, drawn
64+
# as two arcs curving to either side
65+
edges = [("e1", "a", "b", 0.3, (0, 0.5)), ("e2", "a", "b", -0.3, (0, -0.5)),
66+
("e3", "b", "c", 0, (0, 0.18))]
67+
68+
fig, axs = plt.subplots(1, 2, figsize=(9, 2.3))
69+
for ax, is_directed, title in zip(axs, (False, True), ("UGraph", "DGraph")):
70+
style = "-|>" if is_directed else "-"
71+
for name, p, q, rad, (dx, dy) in edges:
72+
ax.add_patch(FancyArrowPatch(pos[p], pos[q], arrowstyle=style, mutation_scale=16,
73+
connectionstyle=f"arc3,rad={rad}", shrinkA=15, shrinkB=15,
74+
color="0.15", lw=1.6))
75+
mx = (pos[p][0] + pos[q][0]) / 2 + dx
76+
my = (pos[p][1] + pos[q][1]) / 2 + dy
77+
ax.text(mx, my, name, ha="center", va="center", fontsize=10, color="0.15")
78+
x, y = pos["c"] # e4: a loop, an edge from c to itself
79+
ax.add_patch(FancyArrowPatch((x - 0.15, y + 0.15), (x + 0.15, y + 0.15), arrowstyle=style,
80+
mutation_scale=16, connectionstyle="arc3,rad=-1.8",
81+
color="0.15", lw=1.6))
82+
ax.text(x, y + 0.62, "e4", ha="center", va="center", fontsize=10, color="0.15")
83+
for name, (x, y) in pos.items():
84+
ax.add_patch(Circle((x, y), 0.2, fc="#1f77b4", ec="none", zorder=3))
85+
ax.text(x, y, name, ha="center", va="center", color="white", fontsize=11, zorder=4)
86+
ax.set_xlim(-0.6, 4.6)
87+
ax.set_ylim(-0.8, 0.95)
88+
ax.set_aspect("equal")
89+
ax.axis("off")
90+
ax.set_title(title, fontsize=11)
91+
fig.tight_layout()
92+
93+
The vertices ``a``, ``b`` and ``c`` and edges ``e1`` and ``e2`` are added in that order.
94+
The resulting vertex lists are
95+
96+
.. list-table::
97+
:header-rows: 1
98+
:widths: 10 30 30 30
99+
100+
* - Vertex name
101+
- ``UGraph`` ``_edgelist``
102+
- ``DGraph`` ``_edgelist``
103+
- ``DGraph`` ``_inlist``
104+
* - ``a``
105+
- ``[e1, e2]``
106+
- ``[e1, e2]``
107+
- ``[]``
108+
* - ``b``
109+
- ``[e1, e2, e3]``
110+
- ``[e3]``
111+
- ``[e1, e2]``
112+
* - ``c``
113+
- ``[e3, e4, e4]``
114+
- ``[e4]``
115+
- ``[e3, e4]``
116+
117+
The graph also keeps **every edge once** in ``graph._edges`` (an insertion-ordered
118+
dict, so ``[e1, e2, e3, e4]``).
119+
120+
The public view of those lists
121+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
122+
123+
.. list-table::
124+
:header-rows: 1
125+
:widths: 30 35 35
126+
127+
* - Method
128+
- Returns for ``UGraph``
129+
- Returns for ``DGraph``
130+
* - ``edges()``, ``out_edges()``
131+
- a copy of ``_edgelist``
132+
- a copy of ``_edgelist``
133+
* - ``in_edges()``
134+
- a copy of ``_edgelist``
135+
- a copy of ``_inlist``
136+
* - ``degree``
137+
- ``len(_edgelist)``
138+
- ``len(_edgelist) + len(_inlist)``
139+
* - ``in_degree``
140+
- ``len(_edgelist)``
141+
- ``len(_inlist)``
142+
* - ``out_degree``
143+
- ``len(_edgelist)``
144+
- ``len(_edgelist)``
145+
* - ``adjacent()``
146+
- the far end of each edge in ``_edgelist``
147+
- the far end of each edge in ``_edgelist``
148+
* - ``incidences()``
149+
- ``adjacent()`` paired with ``out_edges()``
150+
- ``adjacent()`` paired with ``out_edges()``
151+
152+
All are returned in the order the edges were connected.
153+
18154

19155
Working with vertices and edges directly
20156
-----------------------------------------

0 commit comments

Comments
 (0)