1"""Generators of x-y pairs of node data."""
2
3import networkx as nx
4
5__all__ = ["node_attribute_xy", "node_degree_xy"]
6
7
8@nx._dispatchable(node_attrs="attribute")
9def node_attribute_xy(G, attribute, nodes=None):
10 """Yields 2-tuples of node attribute values for all edges in `G`.
11
12 This generator yields, for each edge in `G` incident to a node in `nodes`,
13 a 2-tuple of form ``(attribute value, attribute value)`` for the parameter
14 specified node-attribute.
15
16 Parameters
17 ----------
18 G: NetworkX graph
19
20 attribute: key
21 The node attribute key.
22
23 nodes: list or iterable (optional)
24 Use only edges that are incident to specified nodes.
25 The default is all nodes.
26
27 Yields
28 ------
29 (x, y): 2-tuple
30 Generates 2-tuple of (attribute, attribute) values.
31
32 Examples
33 --------
34 >>> G = nx.DiGraph()
35 >>> G.add_node(1, color="red")
36 >>> G.add_node(2, color="blue")
37 >>> G.add_node(3, color="green")
38 >>> G.add_edge(1, 2)
39 >>> list(nx.node_attribute_xy(G, "color"))
40 [('red', 'blue')]
41
42 Notes
43 -----
44 For undirected graphs, each edge is produced twice, once for each edge
45 representation (u, v) and (v, u), with the exception of self-loop edges
46 which only appear once.
47 """
48 if nodes is None:
49 nodes = set(G)
50 else:
51 nodes = set(nodes)
52 Gnodes = G.nodes
53 for u, nbrsdict in G.adjacency():
54 if u not in nodes:
55 continue
56 uattr = Gnodes[u].get(attribute, None)
57 if G.is_multigraph():
58 for v, keys in nbrsdict.items():
59 vattr = Gnodes[v].get(attribute, None)
60 for _ in keys:
61 yield (uattr, vattr)
62 else:
63 for v in nbrsdict:
64 vattr = Gnodes[v].get(attribute, None)
65 yield (uattr, vattr)
66
67
68@nx._dispatchable(edge_attrs="weight")
69def node_degree_xy(G, x="out", y="in", weight=None, nodes=None):
70 """Yields 2-tuples of ``(degree, degree)`` values for edges in `G`.
71
72 This generator yields, for each edge in `G` incident to a node in `nodes`,
73 a 2-tuple of form ``(degree, degree)``. The node degrees are weighted
74 when a `weight` attribute is specified.
75
76 Parameters
77 ----------
78 G: NetworkX graph
79
80 x: string ('in','out')
81 The degree type for source node (directed graphs only).
82
83 y: string ('in','out')
84 The degree type for target node (directed graphs only).
85
86 weight: string or None, optional (default=None)
87 The edge attribute that holds the numerical value used
88 as a weight. If None, then each edge has weight 1.
89 The degree is the sum of the edge weights adjacent to the node.
90
91 nodes: list or iterable (optional)
92 Use only edges that are adjacency to specified nodes.
93 The default is all nodes.
94
95 Yields
96 ------
97 (x, y): 2-tuple
98 Generates 2-tuple of (degree, degree) values.
99
100 Examples
101 --------
102 >>> G = nx.DiGraph()
103 >>> G.add_edge(1, 2)
104 >>> list(nx.node_degree_xy(G, x="out", y="in"))
105 [(1, 1)]
106 >>> list(nx.node_degree_xy(G, x="in", y="out"))
107 [(0, 0)]
108
109 Notes
110 -----
111 For undirected graphs, each edge is produced twice, once for each edge
112 representation (u, v) and (v, u), with the exception of self-loop edges
113 which only appear once.
114 """
115 nodes = set(G) if nodes is None else set(nodes)
116 if G.is_directed():
117 direction = {"out": G.out_degree, "in": G.in_degree}
118 xdeg = direction[x]
119 ydeg = direction[y]
120 else:
121 xdeg = ydeg = G.degree
122
123 for u, degu in xdeg(nodes, weight=weight):
124 # use G.edges to treat multigraphs correctly
125 neighbors = (nbr for _, nbr in G.edges(u) if nbr in nodes)
126 for _, degv in ydeg(neighbors, weight=weight):
127 yield degu, degv