From f6d28e9f8fe02f3c6cf270cb8bf2ac6ca9de7959 Mon Sep 17 00:00:00 2001 From: yanirmr Date: Mon, 24 Oct 2022 16:44:47 +0300 Subject: [PATCH 1/2] support edges options in add_edges methods. --- pyvis/network.py | 48 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/pyvis/network.py b/pyvis/network.py index b3d6a2f..2473506 100644 --- a/pyvis/network.py +++ b/pyvis/network.py @@ -269,7 +269,7 @@ def add_nodes(self, nodes, **kwargs): :type nodes: list """ valid_args = ["size", "value", "title", - "x", "y", "label", "color", "shape"] + "x", "y", "label", "color", "shape"] for k in kwargs: assert k in valid_args, "invalid arg '" + k + "'" @@ -385,7 +385,7 @@ def add_edge(self, source, to, **options): e = Edge(source, to, self.directed, **options) self.edges.append(e.options) - def add_edges(self, edges): + def add_edges(self, edges, **kwargs): """ This method serves to add multiple edges between existing nodes in the network instance. Adding of the edges is done based off @@ -393,16 +393,32 @@ def add_edges(self, edges): directed graph. :param edges: A list of tuples, each tuple consists of source of edge, - edge destination and and optional width. + edge destination and optional width. :type arrowStrikethrough: list of tuples """ + valid_args = ["arrowStrikethrough", "hidden", "physics", "title", "from", "to", "value", "width"] + + for k in kwargs: + assert k in valid_args, "invalid arg '" + k + "'" + + ed = defaultdict(dict) + for i in range(len(edges)): + for k, v in kwargs.items(): + assert ( + len(v) == len(edges) + ), "keyword arg %s [length %s] does not match" \ + "[length %s] of nodes" % \ + ( + k, len(v), len(edges) + ) + ed[edges[i]].update({k: v[i]}) + for edge in edges: - # if incoming tuple contains a weight - if len(edge) == 3: - self.add_edge(edge[0], edge[1], width=edge[2]) - else: - self.add_edge(edge[0], edge[1]) + try: + self.add_edge(edge[0], edge[1], **ed[edge]) + except: + raise Exception("Invalid edge: %s" % str(edge)) def get_network_data(self): """ @@ -651,7 +667,7 @@ def neighbors(self, node): return self.get_adj_list()[node] def from_nx(self, nx_graph, node_size_transf=(lambda x: x), edge_weight_transf=(lambda x: x), - default_node_size =10, default_edge_weight=1, show_edge_weights=True, edge_scaling=False): + default_node_size=10, default_edge_weight=1, show_edge_weights=True, edge_scaling=False): """ This method takes an exisitng Networkx graph and translates it to a PyVis graph format that can be accepted by the VisJs @@ -679,18 +695,18 @@ def from_nx(self, nx_graph, node_size_transf=(lambda x: x), edge_weight_transf=( >>> nt.from_nx(nx_graph) >>> nt.show("nx.html") """ - assert(isinstance(nx_graph, nx.Graph)) - edges=nx_graph.edges(data = True) - nodes=nx_graph.nodes(data = True) + assert (isinstance(nx_graph, nx.Graph)) + edges = nx_graph.edges(data=True) + nodes = nx_graph.nodes(data=True) if len(edges) > 0: for e in edges: if 'size' not in nodes[e[0]].keys(): - nodes[e[0]]['size']=default_node_size - nodes[e[0]]['size']=int(node_size_transf(nodes[e[0]]['size'])) + nodes[e[0]]['size'] = default_node_size + nodes[e[0]]['size'] = int(node_size_transf(nodes[e[0]]['size'])) if 'size' not in nodes[e[1]].keys(): - nodes[e[1]]['size']=default_node_size - nodes[e[1]]['size']=int(node_size_transf(nodes[e[1]]['size'])) + nodes[e[1]]['size'] = default_node_size + nodes[e[1]]['size'] = int(node_size_transf(nodes[e[1]]['size'])) self.add_node(e[0], **nodes[e[0]]) self.add_node(e[1], **nodes[e[1]]) From 6db937c4c794240e0cfe126214876df127fc4deb Mon Sep 17 00:00:00 2001 From: yanirmr Date: Mon, 24 Oct 2022 20:01:55 +0300 Subject: [PATCH 2/2] add test and fix minor bug --- pyvis/network.py | 7 ++++--- pyvis/tests/test_graph.py | 36 +++++++++++++++++++++++++----------- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/pyvis/network.py b/pyvis/network.py index 2473506..066d527 100644 --- a/pyvis/network.py +++ b/pyvis/network.py @@ -415,10 +415,11 @@ def add_edges(self, edges, **kwargs): ed[edges[i]].update({k: v[i]}) for edge in edges: - try: + # if incoming tuple contains a weight + if len(edge) == 3: + self.add_edge(edge[0], edge[1], width=edge[2], **ed[edge]) + else: self.add_edge(edge[0], edge[1], **ed[edge]) - except: - raise Exception("Invalid edge: %s" % str(edge)) def get_network_data(self): """ diff --git a/pyvis/tests/test_graph.py b/pyvis/tests/test_graph.py index 3fb54a8..a931bed 100644 --- a/pyvis/tests/test_graph.py +++ b/pyvis/tests/test_graph.py @@ -193,6 +193,24 @@ def test_add_edges_mixed_weights(self): list([1, None, 3, None, 5, None]), list(map(lambda x: x.get("width", None), self.g.edges))) + def test_add_edges_with_options(self): + self.g.add_edges( + [ + (0, 1), (0, 2), (0, 3), + (1, 2), (1, 3), (2, 3) + ], width=[1, 2, 3, 4, 5, 6] + ) + self.assertEqual(self.g.num_edges(), 6) + self.assertEqual(self.g.neighbors(0), set([1, 2, 3])) + self.assertEqual(self.g.neighbors(1), set([0, 2, 3])) + self.assertEqual(self.g.neighbors(2), set([0, 1, 3])) + self.assertEqual(self.g.neighbors(3), set([0, 1, 2])) + for edges in self.g.edges: + self.assertTrue("width" in edges) + self.assertEqual( + list([1, 2, 3, 4, 5, 6]), + list(map(lambda x: x["width"], self.g.edges))) + def test_add_edge_directed(self): self.g.directed = True self.g.add_edge(0, 1) @@ -308,23 +326,23 @@ def setUp(self): def test_can_enable_init(self): self.assertTrue(self.g.options['layout']) - + def test_layout_disabled(self): self.g = Network() self.assertRaises(KeyError, lambda: self.g.options['layout']) - + def test_levelSeparation(self): self.assertTrue(self.g.options.layout.hierarchical.levelSeparation) - + def test_treeSpacing(self): self.assertTrue(self.g.options.layout.hierarchical.treeSpacing) - + def test_blockShifting(self): self.assertTrue(self.g.options.layout.hierarchical.blockShifting) - + def test_edgeMinimization(self): self.assertTrue(self.g.options.layout.hierarchical.edgeMinimization) - + def test_parentCentralization(self): self.assertTrue(self.g.options.layout.hierarchical.parentCentralization) @@ -334,7 +352,7 @@ def test_sortMethod(self): def test_set_edge_minimization(self): self.g.options.layout.set_separation(10) self.assertTrue(self.g.options.layout.hierarchical.levelSeparation == 10) - + def test_set_tree_spacing(self): self.g.options.layout.set_tree_spacing(10) self.assertTrue(self.g.options.layout.hierarchical.treeSpacing == 10) @@ -344,7 +362,3 @@ def test_set_edge_minimization(self): self.assertTrue(self.g.options.layout.hierarchical.edgeMinimization == True) self.g.options.layout.set_edge_minimization(False) self.assertTrue(self.g.options.layout.hierarchical.edgeMinimization == False) - - - -