diff --git a/dynetx/classes/dyndigraph.py b/dynetx/classes/dyndigraph.py index 7d820d8..86b0579 100644 --- a/dynetx/classes/dyndigraph.py +++ b/dynetx/classes/dyndigraph.py @@ -117,7 +117,7 @@ def __init__(self, data=None, edge_removal=True, **attr): self.edge_removal = edge_removal self.directed = True - def nodes_iter(self, t=None): + def nodes_iter(self, t=None, data=False): """Return an iterator over the nodes with respect to a given temporal snapshot. Parameters @@ -125,6 +125,8 @@ def nodes_iter(self, t=None): t : snapshot id (default=None). If None the iterator returns all the nodes of the flattened graph. + data: node data(default=False) + Returns ------- niter : iterator @@ -142,8 +144,15 @@ def nodes_iter(self, t=None): [0, 1, 2] """ if t is not None: - return iter([n for n in self.degree(t=t).values() if n > 0]) - return iter(self._node) + if not data: + return [n for n, d in self.degree(t=t).items() if d > 0] + else: + return {n: self._node[n] for n, d in self.degree(t=t).items() if d > 0} + + if not data: + return iter(self._node) + else: + return self._node def nodes(self, t=None, data=False): """Return a list of the nodes in the graph at a given snapshot. @@ -173,7 +182,10 @@ def nodes(self, t=None, data=False): >>> G.nodes(t=0) [0, 1] """ - return list(self.nodes_iter(t=t)) + if data: + return [(k, v) for k, v in self.nodes_iter(t=t, data=data).items()] + else: + return [k for k in self.nodes_iter(t=t, data=data)] def has_node(self, n, t=None): """Return True if the graph, at time t, contains the node n. @@ -1289,8 +1301,49 @@ def time_slice(self, t_from, t_to=None): H.add_interaction(u, v, i_to, b) elif i_to <= a <= f_from <= b: H.add_interaction(u, v, a, f_from) + + for n in H.nodes(): + H._node[n] = self._node[n] + return H + def update_node_attr(self, n, **data): + """Updates the attributes of a specified node. + + Parameters + ---------- + + n : node id + **data : the attributes and their new values + + Examples + -------- + >>> import dynetx as dn + >>> G = dn.DynGraph() + >>> G.add_node(0, Label="A") + >>> G.update_node_attr(0, Label="B") + """ + self._node[n] = data + + def update_node_attr_from(self, nlist, **data): + """Updates the attributes of a specified node. + + Parameters + ---------- + + nlist : list of node ids + **data : the attributes and their new values + + Examples + -------- + >>> import dynetx as dn + >>> G = dn.DynGraph() + >>> G.add_nodes_from([0, 1, 2], Label="A") + >>> G.update_node_attr_from([0, 2], Label="B") + """ + for n in nlist: + self._node[n] = data + def temporal_snapshots_ids(self): """Return the ordered list of snapshot ids present in the dynamic graph. diff --git a/dynetx/classes/dyngraph.py b/dynetx/classes/dyngraph.py index 47f45b1..ba94455 100644 --- a/dynetx/classes/dyngraph.py +++ b/dynetx/classes/dyngraph.py @@ -125,7 +125,7 @@ def __init__(self, data=None, edge_removal=True, **attr): self.edge_removal = edge_removal self.directed = False - def nodes_iter(self, t=None): + def nodes_iter(self, t=None, data=False): """Return an iterator over the nodes with respect to a given temporal snapshot. Parameters @@ -133,6 +133,8 @@ def nodes_iter(self, t=None): t : snapshot id (default=None). If None the iterator returns all the nodes of the flattened graph. + data: node data(default=False) + Returns ------- niter : iterator @@ -149,8 +151,15 @@ def nodes_iter(self, t=None): [0, 1, 2] """ if t is not None: - return iter([n for n in self.degree(t=t).values() if n > 0]) - return iter(self._node) + if not data: + return [n for n, d in self.degree(t=t).items() if d > 0] + else: + return {n: self._node[n] for n, d in self.degree(t=t).items() if d > 0} + + if not data: + return iter(self._node) + else: + return self._node def nodes(self, t=None, data=False): """Return a list of the nodes in the graph at a given snapshot. @@ -180,7 +189,11 @@ def nodes(self, t=None, data=False): >>> G.nodes(t=0) [0, 1, 2] """ - return list(self.nodes_iter(t=t)) + + if data: + return [(k, v) for k, v in self.nodes_iter(t=t, data=data).items()] + else: + return [k for k in self.nodes_iter(t=t, data=data)] def interactions(self, nbunch=None, t=None): """Return the list of interaction present in a given snapshot. @@ -1037,6 +1050,7 @@ def time_slice(self, t_from, t_to=None): f_from = t_from for a, b in ts['t']: + if i_to <= a and b <= f_from: H.add_interaction(u, v, a, b) elif a <= i_to and f_from <= b: @@ -1045,8 +1059,49 @@ def time_slice(self, t_from, t_to=None): H.add_interaction(u, v, i_to, b) elif i_to <= a <= f_from <= b: H.add_interaction(u, v, a, f_from) + + for n in H.nodes(): + H._node[n] = self._node[n] + return H + def update_node_attr(self, n, **data): + """Updates the attributes of a specified node. + + Parameters + ---------- + + n : node id + **data : the attributes and their new values + + Examples + -------- + >>> import dynetx as dn + >>> G = dn.DynGraph() + >>> G.add_node(0, Label="A") + >>> G.update_node_attr(0, Label="B") + """ + self._node[n] = data + + def update_node_attr_from(self, nlist, **data): + """Updates the attributes of a specified node. + + Parameters + ---------- + + nlist : list of node ids + **data : the attributes and their new values + + Examples + -------- + >>> import dynetx as dn + >>> G = dn.DynGraph() + >>> G.add_nodes_from([0, 1, 2], Label="A") + >>> G.update_node_attr_from([0, 2], Label="B") + """ + for n in nlist: + self._node[n] = data + def temporal_snapshots_ids(self): """Return the ordered list of snapshot ids present in the dynamic graph. diff --git a/dynetx/test/test_dyndigraph.py b/dynetx/test/test_dyndigraph.py index 5d10ef7..30760f1 100644 --- a/dynetx/test/test_dyndigraph.py +++ b/dynetx/test/test_dyndigraph.py @@ -210,6 +210,21 @@ def test_in_out_interactions(self): sr = g.out_interactions([0, 1], 7) self.assertEqual(sr, []) + def test_update_node_attr(self): + g = dn.DynDiGraph() + + for n in [0, 1, 2, 3, 4, 5, 6, 7, 8]: + g.add_node(n, Label="A") + + for n in g.nodes(): + g.update_node_attr(n, Label="B") + + for n in g.nodes(data=True): + self.assertEqual(n[1]['Label'], "B") + + g.update_node_attr_from([0, 1, 2], Label="C") + self.assertEqual(g._node[0]['Label'], "C") + def test_neighbors(self): g = dn.DynDiGraph() g.add_interaction(0, 1, 5) @@ -337,7 +352,6 @@ def test_time_slice(self): self.assertEqual(h.number_of_nodes(), 5) self.assertEqual(h.number_of_interactions(), 4) - h = g.time_slice(5, 5) self.assertIsInstance(h, dn.DynDiGraph) self.assertEqual(h.number_of_nodes(), 5) @@ -504,7 +518,6 @@ def test_conversion(self): H = G.to_undirected() self.assertIsInstance(H, dn.DynGraph) self.assertEqual(H.number_of_nodes(), 3) - print(H.edges, H.number_of_edges()) self.assertEqual(H.number_of_edges(), 3) if __name__ == '__main__': diff --git a/dynetx/test/test_dyngraph.py b/dynetx/test/test_dyngraph.py index 42ecfd1..5662626 100644 --- a/dynetx/test/test_dyngraph.py +++ b/dynetx/test/test_dyngraph.py @@ -229,6 +229,61 @@ def test_number_of_nodes(self): avg = g.avg_number_of_nodes() self.assertEqual(avg, 5) + def test_update_node_attr(self): + g = dn.DynGraph() + + for n in [0, 1, 2, 3, 4, 5, 6, 7, 8]: + g.add_node(n, Label="A") + + for n in g.nodes(): + g.update_node_attr(n, Label="B") + + for n in g.nodes(data=True): + self.assertEqual(n[1]['Label'], "B") + + g.update_node_attr_from([0, 1, 2], Label="C") + self.assertEqual(g._node[0]['Label'], "C") + + def test_add_node_attr(self): + g = dn.DynGraph() + + for n in [0, 1, 2, 3, 4, 5, 6, 7, 8]: + g.add_node(n, Label="A") + + g.add_nodes_from([9, 10, 11, 12], Label="A") + + g.add_path([0, 1, 2, 3, 4], t=5) + g.add_path([4, 5, 6, 7, 8], t=6) + + for n in g.nodes(data=True): + self.assertEqual(n[1]['Label'], "A") + + nds5 = [] + for n in g.nodes(data=True, t=5): + nds5.append(n[0]) + self.assertEqual(n[1]['Label'], "A") + + self.assertListEqual(nds5, [0, 1, 2, 3, 4]) + + def test_time_slice_node_attr(self): + g = dn.DynGraph() + + for n in [0, 1, 2, 3, 4, 5, 6, 7, 8]: + g.add_node(n, Label="A") + + g.add_path([0, 1, 2, 3, 4], t=5) + g.add_path([4, 5, 6, 7, 8], t=6) + + h = g.time_slice(5) + for n in h.nodes(data=True): + self.assertEqual(n[1]['Label'], "A") + + self.assertIsInstance(h, dn.DynGraph) + self.assertEqual(h.number_of_nodes(), 5) + self.assertEqual(h.number_of_interactions(), 4) + + + def test_time_slice(self): g = dn.DynGraph() g.add_path([0, 1, 2, 3, 4], t=5)