{"id":29,"date":"2020-08-04T12:05:45","date_gmt":"2020-08-04T12:05:45","guid":{"rendered":"https:\/\/data-science.gotoauthority.com\/2020\/08\/04\/visualizing-the-similarity-of-two-networks\/"},"modified":"2020-08-04T12:05:45","modified_gmt":"2020-08-04T12:05:45","slug":"visualizing-the-similarity-of-two-networks","status":"publish","type":"post","link":"https:\/\/wealthrevelation.com\/data-science\/2020\/08\/04\/visualizing-the-similarity-of-two-networks\/","title":{"rendered":"Visualizing the similarity of two networks"},"content":{"rendered":"<div id=\"content\">\n<h2>Visualizing the similarity of two networks<\/h2>\n<p>\u00a0<\/p>\n<p>Julia Len (jlen at ucsd.edu)<\/p>\n<h3>Introduction<\/h3>\n<p><span>When working with networks, it is often useful to consider how similar two networks are. \u00a0There are a number of ways of quantifying network similarity however. \u00a0One could simply consider the number of nodes two networks have in common. \u00a0However, this would miss any structural similarity, or lack thereof, between the edges. \u00a0For example, it is possible for two networks to have completely identical node sets, but have completely disjoint edge sets. \u00a0Note however that in order for two networks to share edges, they must share nodes as well (since edges are defined by the nodes they connect). \u00a0<\/span><\/p>\n<p>In this post, we will introduce a network overlap visualization function (draw_graph_union) in the visJS2jupyter package, and explore a few possible scenarios.<\/p>\n<h3>Installation<\/h3>\n<p><span>To install visJS2jupyter, run <\/span><\/p>\n<p><code><span>\u00a0 \u00a0 pip install visJS2jupyter<\/span><\/code><\/p>\n<p><span>in your terminal. To import the visualizations module, use the statement <\/span><\/p>\n<p><code><span>\u00a0 \u00a0 import visJS2jupyter.visualizations as visualizations<\/span><\/code><\/p>\n<p><span>in your jupyter notebook. The source code is also available on github <\/span><a href=\"https:\/\/github.com\/ucsd-ccbb\/visJS_2_jupyter\/blob\/master\/visJS2jupyter\/visualizations.py\"><span>here<\/span><\/a><span>.<\/span><\/p>\n<h3><span>Simple example with default parameters<\/span><\/h3>\n<p><span>We will now go through a simple example using two 10-node networks whose intersection is exactly 5 nodes. We create two small, random networks using the networkx function \u2018<\/span><a href=\"https:\/\/networkx.github.io\/documentation\/networkx-1.10\/reference\/generated\/networkx.generators.random_graphs.connected_watts_strogatz_graph.html\"><span>connected_watts_strogatz_graph<\/span><\/a><span>\u2019. Each network will have 10 nodes, with each node initially connected to its 5 nearest neighbors. These connections are then randomly rewired with probability 0.1. <\/span><\/p>\n<p><code><span>\u00a0 \u00a0 G1 = nx.connected_watts_strogatz_graph(10,5,.1)<\/span><\/code><\/p>\n<p><code><span>\u00a0 \u00a0 G2 = nx.connected_watts_strogatz_graph(10,5,.1)<\/span><\/code><\/p>\n<p><span>This produces two networks who both have nodes labelled from 0 to 9. Their intersection is then all the nodes for each graph. This is an unexciting case, so let\u2019s relabel some nodes, so that they share only 5 nodes in common. We can do this by relabelling the nodes 0 to 9 of the second graph, G2, to 5 to 14 using the networkx function \u2018<\/span><a href=\"https:\/\/networkx.github.io\/documentation\/networkx-1.10\/reference\/generated\/networkx.relabel.relabel_nodes.html?highlight=relabel_nodes#networkx.relabel.relabel_nodes\"><span>relabel_nodes<\/span><\/a><span>\u2019. The code for this is shown below:<\/span><\/p>\n<p><code><span>\u00a0 \u00a0 old_nodes = range(5)<\/span><\/code><\/p>\n<p><code><span>\u00a0 \u00a0 new_nodes = range(10,15)<\/span><\/code><\/p>\n<p><code><span>\u00a0 \u00a0 new_node_labels = dict(zip(old_nodes,new_nodes))<\/span><\/code><\/p>\n<p><code><span>\u00a0 \u00a0 G2 = nx.relabel_nodes(G2,new_node_labels)<\/span><\/code><\/p>\n<p><span>Now nodes 0 to 4 belong to only G1, nodes 5 to 9 belong to G1 and G2, and nodes 10 to 14 belong to only G2. Let\u2019s see what this looks like by using draw_graph_union:<\/span><\/p>\n<p><code><span>\u00a0 \u00a0 visualizations.draw_graph_union(G1,G2)<\/span><\/code><\/p>\n<p><a href=\"https:\/\/bl.ocks.org\/julialen\/raw\/d21c9d378cb09b5a7181497101996727\/\"><img loading=\"lazy\" data-attachment-id=\"351\" data-permalink=\"http:\/\/compbio.ucsd.edu\/visualizing-similarity-two-networks\/simple_overlap\/\" data-orig-file=\"https:\/\/i1.wp.com\/compbio.ucsd.edu\/wp-content\/uploads\/2016\/12\/simple_overlap.png?fit=900%2C800\" data-orig-size=\"900,800\" data-comments-opened=\"1\" data-image-meta='{\"aperture\":\"0\",\"credit\":\"\",\"camera\":\"\",\"caption\":\"\",\"created_timestamp\":\"0\",\"copyright\":\"\",\"focal_length\":\"0\",\"iso\":\"0\",\"shutter_speed\":\"0\",\"title\":\"\",\"orientation\":\"0\"}' data-image-title=\"simple_overlap\" data-image-description=\"\" data-medium-file=\"https:\/\/i1.wp.com\/compbio.ucsd.edu\/wp-content\/uploads\/2016\/12\/simple_overlap.png?fit=300%2C267\" data-large-file=\"https:\/\/i1.wp.com\/compbio.ucsd.edu\/wp-content\/uploads\/2016\/12\/simple_overlap.png?fit=900%2C800\" class=\"alignleft size-full wp-image-351\" src=\"https:\/\/i1.wp.com\/compbio.ucsd.edu\/wp-content\/uploads\/2016\/12\/simple_overlap.png?resize=900%2C800\" alt=\"\" width=\"900\" height=\"800\" data-recalc-dims=\"1\"><\/a><\/p>\n<p><span>And that\u2019s it! We get an interactive graph fairly quickly and easily. Notice that the nodes are color-coded and shaped based on which network they belong to. For instance, nodes in the intersection of G1 and G2 are orange and triangular shapes, while nodes which only belong to G1 are red circles, and nodes which only belong to G2 are yellow squares. Also notice that edges found in both G1 and G2 are colored red while all other edges are colored blue. <\/span><\/p>\n<p><span>You can take a look at the sample notebook <\/span><a href=\"https:\/\/bl.ocks.org\/julialen\/raw\/d21c9d378cb09b5a7181497101996727\/\"><span>here<\/span><\/a><span>. \u00a0Notice that hovering over a node pops up a tooltip with information about the node\u2019s name and graph membership.<\/span><\/p>\n<p>From the previous example, we saw that draw_graph_union not only depicts the intersection of nodes, but it also visualizes the intersection of edges as well. Let\u2019s take a look at how this works with two networks having identical nodes but but only a few overlapping edges.<\/p>\n<h3><span>Identical nodes, some overlapping edges<\/span><\/h3>\n<p><span>We\u2019ll again be using the connected_watts_strogatz_graph to create our two networks, but this time both networks will contain 50 nodes:<\/span><\/p>\n<p><code><span>\u00a0 \u00a0 G1 = nx.connected_watts_strogatz_graph(50,5,.1)<\/span><\/code><\/p>\n<p><code><span>\u00a0 \u00a0 G2 = nx.connected_watts_strogatz_graph(50,5,.1)<\/span><\/code><\/p>\n<p><span>This produces two networks with identical nodes and randomly intersecting edges. We want the sets of edges to only intersect over 5 nodes. Python\u2019s built-in <\/span><a href=\"https:\/\/docs.python.org\/2\/library\/stdtypes.html#set\"><span>set<\/span><\/a><span> object can help with this. We can get the edges for G1 and G2, convert the lists of edges to sets of edges, and then find their intersection using &amp;. We can then subtract out the intersecting edges from each set of edges. <\/span><\/p>\n<p><code><span>\u00a0 \u00a0 edges_1 = set(G1.edges())<\/span><\/code><\/p>\n<p><code><span>\u00a0 \u00a0 edges_2 = set(G2.edges())<\/span><\/code><\/p>\n<p><code><span>\u00a0 \u00a0 intersecting_edges = edges_1 &amp; edges_2<\/span><\/code><\/p>\n<p><code><span>\u00a0 \u00a0 edges_1_disjoint = edges_1 - intersecting_edges<\/span><\/code><\/p>\n<p><code><span>\u00a0 \u00a0 edges_2_disjoint = edges_2 - interesecting_edges<\/span><\/code><\/p>\n<p><span>This produces two disjoint sets of edges. We now want to add back in 5 edges from the intersection into each disjoint set. <\/span><\/p>\n<p><code><span>\u00a0 \u00a0 for i in range(0,5):<\/span><\/code><\/p>\n<p><code><span>\u00a0 \u00a0 \u00a0 \u00a0 new_edge = intersecting_edges.pop()<\/span><\/code><\/p>\n<p><code><span>\u00a0 \u00a0 \u00a0 \u00a0 edges_1_disjoint.add(new_edge)<\/span><\/code><\/p>\n<p><code><span>\u00a0 \u00a0 \u00a0 \u00a0 edges_2_disjoint.add(new_edge)<\/span><\/code><\/p>\n<p><span>We can then remove the current edges from G1 and add back in the desired edges. We do the same for G2.<\/span><\/p>\n<p><code><span>\u00a0 \u00a0 G1.remove_edges_from(edges_1)<\/span><\/code><\/p>\n<p><code><span>\u00a0 \u00a0 G1.add_edges_from(list(edges_1_disjoint))<\/span><\/code><\/p>\n<p><span>Let\u2019s now draw the two graphs using draw_graph_union, but this time let\u2019s customize the graph a bit. The function sets the default color of the nodes to matplotlib\u2019s colormap autumn and the default color of the edges to matplotlib\u2019s colormap coolwarm. However, matplotlib has many wonderful colormaps available that we can choose from (click <\/span><a href=\"http:\/\/matplotlib.org\/examples\/color\/colormaps_reference.html\"><span>here<\/span><\/a><span> for more details). To set the colormap of the nodes and edges, use the arguments node_cmap and edge_cmap. If you decide to change the colormap, make sure to import the matplotlib package:<\/span><\/p>\n<p><code><span>\u00a0 \u00a0 import matplotlib as mpl<\/span><\/code><\/p>\n<p><span>We can add other customizations as well, such as setting edge width and edge shadows. The function allows for any argument available in visJS_module in the visJS2jupyter package. This allows many potential customizing features for the function. Now, let\u2019s see what this looks like overall:<\/span><\/p>\n<p><code><span>\u00a0 \u00a0 visualizations.draw_graph_union(G1,G2,<\/span><\/code><\/p>\n<p><code><span>\u00a0 \u00a0 \u00a0 \u00a0 node_cmap=mpl.cm.cool,<\/span><\/code><\/p>\n<p><code><span>\u00a0 \u00a0 \u00a0 \u00a0 edge_cmap=mpl.cm.winter_r,<\/span><\/code><\/p>\n<p><code><span>\u00a0 \u00a0 \u00a0 \u00a0 edge_width=5,<\/span><\/code><\/p>\n<p><code><span>\u00a0 \u00a0 \u00a0 \u00a0 edge_shadow_enabled=True,<\/span><\/code><\/p>\n<p><code><span>\u00a0 \u00a0 \u00a0 \u00a0 edge_shadow_size=2)<\/span><\/code><\/p>\n<p><a href=\"https:\/\/bl.ocks.org\/julialen\/raw\/23b25c91232c97d61782390c44437e56\/\"><img loading=\"lazy\" data-attachment-id=\"352\" data-permalink=\"http:\/\/compbio.ucsd.edu\/visualizing-similarity-two-networks\/same_nodes_overlap\/\" data-orig-file=\"https:\/\/i1.wp.com\/compbio.ucsd.edu\/wp-content\/uploads\/2016\/12\/same_nodes_overlap.png?fit=900%2C800\" data-orig-size=\"900,800\" data-comments-opened=\"1\" data-image-meta='{\"aperture\":\"0\",\"credit\":\"\",\"camera\":\"\",\"caption\":\"\",\"created_timestamp\":\"0\",\"copyright\":\"\",\"focal_length\":\"0\",\"iso\":\"0\",\"shutter_speed\":\"0\",\"title\":\"\",\"orientation\":\"0\"}' data-image-title=\"same_nodes_overlap\" data-image-description=\"\" data-medium-file=\"https:\/\/i1.wp.com\/compbio.ucsd.edu\/wp-content\/uploads\/2016\/12\/same_nodes_overlap.png?fit=300%2C267\" data-large-file=\"https:\/\/i1.wp.com\/compbio.ucsd.edu\/wp-content\/uploads\/2016\/12\/same_nodes_overlap.png?fit=900%2C800\" class=\"alignleft size-full wp-image-352\" src=\"https:\/\/i1.wp.com\/compbio.ucsd.edu\/wp-content\/uploads\/2016\/12\/same_nodes_overlap.png?resize=900%2C800\" alt=\"\" width=\"900\" height=\"800\" data-recalc-dims=\"1\"><\/a><\/p>\n<p><span>As you can see in the graph above, there is now only one set of nodes, all of which are triangle shaped because all the nodes overlap. The edges are mostly colored in green except for 5 edges in blue: the edges in the intersection. Notice that the edges and nodes are colored differently from before and the edges now have added shadows. You can take a look at the interactive notebook with this example <\/span><a href=\"https:\/\/bl.ocks.org\/julialen\/raw\/23b25c91232c97d61782390c44437e56\/\"><span>here<\/span><\/a><span>.<\/span><\/p>\n<h3><span>One network\u00a0contains the other network<\/span><\/h3>\n<p><span>So far, we\u2019ve seen graphs where there is a small intersection of the nodes and the node sets are equal. What happens if the set of nodes for one graph is a subset of the nodes for the other graph? We\u2019ll take a look at this case now.<\/span><\/p>\n<p><span>We again create two networks using connected_watts_strogatz. Graph 1 will have 50 nodes and graph 2 will have 20 so that all of the second graph\u2019s nodes intersect with graph 1. We will then call draw_graph_union on these two graphs. This time, we use some more features of the function. We can set the name of the nodes for graph 1 and graph 2. Notice that previously when we hovered over a node, the tooltip showed something like \u201cgraph 1 + graph 2\u201d. Using the arguments node_name_1 and node_name_2, we can customize what is shown in the tooltip. Pretty cool!<\/span><\/p>\n<p><span>If you\u2019ve played around with some of the example notebooks, you\u2019ve probably noticed that the nodes move around when dragged as if they have a gravitational field. This is the physics_enabled feature. It is set by default for graphs of less than 100 nodes, while it is turned off for any larger graphs. One nice feature is that you can override this by setting the physics_enabled argument to true or false. Let\u2019s turn off this setting for this example.<\/span><\/p>\n<p><code><span>\u00a0 \u00a0 visualizations.draw_graph_union(G1,G2,edge_width=5<\/span><\/code><\/p>\n<p><code><span>\u00a0 \u00a0 \u00a0 \u00a0 node_name_1=\u201dsuperset\u201d,<\/span><\/code><\/p>\n<p><code><span>\u00a0 \u00a0 \u00a0 \u00a0 node_name_2=\u201dsubset\u201d,<\/span><\/code><\/p>\n<p><code><span>\u00a0 \u00a0 \u00a0 \u00a0 physics_enabled=False)<\/span><\/code><\/p>\n<p><a href=\"https:\/\/bl.ocks.org\/julialen\/raw\/6f6ce4d28c7b6897897d800155f3752c\/\"><img loading=\"lazy\" data-attachment-id=\"353\" data-permalink=\"http:\/\/compbio.ucsd.edu\/visualizing-similarity-two-networks\/network_contains_subnetwork\/\" data-orig-file=\"https:\/\/i2.wp.com\/compbio.ucsd.edu\/wp-content\/uploads\/2016\/12\/network_contains_subnetwork.png?fit=900%2C800\" data-orig-size=\"900,800\" data-comments-opened=\"1\" data-image-meta='{\"aperture\":\"0\",\"credit\":\"\",\"camera\":\"\",\"caption\":\"\",\"created_timestamp\":\"0\",\"copyright\":\"\",\"focal_length\":\"0\",\"iso\":\"0\",\"shutter_speed\":\"0\",\"title\":\"\",\"orientation\":\"0\"}' data-image-title=\"network_contains_subnetwork\" data-image-description=\"\" data-medium-file=\"https:\/\/i2.wp.com\/compbio.ucsd.edu\/wp-content\/uploads\/2016\/12\/network_contains_subnetwork.png?fit=300%2C267\" data-large-file=\"https:\/\/i2.wp.com\/compbio.ucsd.edu\/wp-content\/uploads\/2016\/12\/network_contains_subnetwork.png?fit=900%2C800\" class=\"alignleft size-full wp-image-353\" src=\"https:\/\/i2.wp.com\/compbio.ucsd.edu\/wp-content\/uploads\/2016\/12\/network_contains_subnetwork.png?resize=900%2C800\" alt=\"\" width=\"900\" height=\"800\" data-recalc-dims=\"1\"><\/a><\/p>\n<p><span>In just a couple of lines of code, we have produced an interactive network! Notice that when we hover over a node, it has the name that we set, just like we wanted. You can also see that dragging a node around makes it stay stuck in place, so the physics_enabled setting has been turned off. The example notebook can be found <\/span><a href=\"https:\/\/bl.ocks.org\/julialen\/raw\/6f6ce4d28c7b6897897d800155f3752c\/\"><span>here<\/span><\/a><span>. <\/span><\/p>\n<p><span>Overall, draw_graph_union provides a quick and easy way to create customizable and interactive visualizations for network similarities, enabling visual assessment of what two networks share and what they don\u2019t. \u00a0\u00a0<\/span><\/p>\n<h3 class=\"jp-relatedposts-headline\"><em>Related<\/em><\/h3>\n<p><a href=\"http:\/\/compbio.ucsd.edu\/outreach\/data-science-blog\/\">\u00ab Return<\/a><\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>http:\/\/compbio.ucsd.edu\/visualizing-similarity-two-networks\/<\/p>\n","protected":false},"author":0,"featured_media":30,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[2],"tags":[],"_links":{"self":[{"href":"https:\/\/wealthrevelation.com\/data-science\/wp-json\/wp\/v2\/posts\/29"}],"collection":[{"href":"https:\/\/wealthrevelation.com\/data-science\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wealthrevelation.com\/data-science\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/wealthrevelation.com\/data-science\/wp-json\/wp\/v2\/comments?post=29"}],"version-history":[{"count":0,"href":"https:\/\/wealthrevelation.com\/data-science\/wp-json\/wp\/v2\/posts\/29\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wealthrevelation.com\/data-science\/wp-json\/wp\/v2\/media\/30"}],"wp:attachment":[{"href":"https:\/\/wealthrevelation.com\/data-science\/wp-json\/wp\/v2\/media?parent=29"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wealthrevelation.com\/data-science\/wp-json\/wp\/v2\/categories?post=29"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wealthrevelation.com\/data-science\/wp-json\/wp\/v2\/tags?post=29"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}