Skip to content

Commit

Permalink
Merge branch 'dev' of github.com:saezlab/networkcommons into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
deeenes committed Jul 2, 2024
2 parents 5d24b0c + 42a420f commit 9509c80
Show file tree
Hide file tree
Showing 11 changed files with 1,261 additions and 385 deletions.
3 changes: 2 additions & 1 deletion networkcommons/_visual/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@
Visualization methods for networks and analyses.
"""

from . import networkx as networkx
from . import vis_networkx as vis_networkx
from . import yfiles as vis_yfiles
11 changes: 11 additions & 0 deletions networkcommons/_visual/_aux.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

def wrap_node_name(node_name):
if ":" in node_name:
node_name = node_name.replace(":", "_")
if node_name.startswith("COMPLEX"):
# remove the word COMPLEX with a separator (:/-, etc)
return node_name[8:]
else:
return node_name


91 changes: 91 additions & 0 deletions networkcommons/_visual/_network_mock.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
from graphviz import Digraph
from IPython.display import display
from yfiles_jupyter_graphs import GraphWidget
from typing import Dict, List
import networkx as nx
import pandas as pd
import matplotlib.pyplot as plt
import datetime
import os
from pypath.utils import mapping

from _aux import wrap_node_name
import yfiles

class NetworkMock:

def __init__(self):
self.network = nx.DiGraph()
self.color_map = {}

def init_from_sif(self, filepath):
"""
Initialize the network from a SIF file
"""
with open(filepath, 'r') as f:
for line in f:
source, target = line.strip().split()
self.network.add_edge(source, target)
return self.network

def add_nodes(self, nodes):
# add nodes to networkx
self.network.add_nodes_from(nodes)
return self.network

def set_initial_nodes(self, initial_nodes):
self.update_node_property(initial_nodes, type="initial_node")

def set_nodes_of_interest(self, nodes):
self.update_node_property(nodes, type="noi", value="1")

def add_edges(self, edges):
self.network.add_edges_from(edges)

def update_node_property(self, node, type="color", value="blue"):
# add color to the node in networkx
if type == "color":
self.color_map[node] = value
elif type == "initial_node":
self.network.nodes[node]["initial_node"] = True
return self.color_map

def update_edge_property(self, edge, type="color", color="blue"):
# add color to the edge in networkx
if type == "color":
self.color_map[edge] = color
return self.color_map

def draw(self, filepath=None, render=False):
networkx_vis = yfiles.NetworkXVisualizer()
networkx_vis.visualise(render=render)

def mapping_node_identifier(self, node: str) -> List[str]:
complex_string = None
gene_symbol = None
uniprot = None

if mapping.id_from_label0(node):
uniprot = mapping.id_from_label0(node)
gene_symbol = mapping.label(uniprot)
elif node.startswith("COMPLEX"):
node = node[8:] #TODO change to wrap
node_list = node.split("_")
translated_node_list = [mapping.label(mapping.id_from_label0(item)) for item in node_list]
complex_string = "COMPLEX:" + "_".join(translated_node_list)
elif mapping.label(node):
gene_symbol = mapping.label(node)
uniprot = mapping.id_from_label0(gene_symbol)
else:
print("Error during translation, check syntax for ", node)

return [complex_string, gene_symbol, uniprot]

def convert_edges_into_genesymbol(self, edges: pd.DataFrame) -> pd.DataFrame:
def convert_identifier(x):
identifiers = self.mapping_node_identifier(x)
return identifiers[1] # Using GeneSymbol
edges["source"] = edges["source"].apply(convert_identifier)
edges["target"] = edges["target"].apply(convert_identifier)
return edges

128 changes: 128 additions & 0 deletions networkcommons/_visual/network_stats.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import pandas as pd
import matplotlib.pyplot as plt
import networkx as nx
from typing import List, Dict


def plot_n_nodes_edges(
networks: Dict[str, nx.DiGraph],
filepath=None,
render=False,
orientation='vertical',
color_palette='Set2',
size=10,
linewidth=2,
marker='o',
show_nodes=True,
show_edges=True
):
"""
Plot the number of nodes and edges in the networks using a lollipop plot.
Args:
networks (Dict[str, nx.DiGraph]): A dictionary of network names and their corresponding graphs.
filepath (str): Path to save the plot. Default is None.
render (bool): Whether to display the plot. Default is False.
orientation (str): 'vertical' or 'horizontal'. Default is 'vertical'.
color_palette (str): Matplotlib color palette. Default is 'Set2'.
size (int): Size of the markers. Default is 10.
linewidth (int): Line width of the lollipops. Default is 2.
marker (str): Marker style for the lollipops. Default is 'o'.
show_nodes (bool): Whether to show nodes count. Default is True.
show_edges (bool): Whether to show edges count. Default is True.
"""
if not show_nodes and not show_edges:
raise ValueError("At least one of 'show_nodes' or 'show_edges' must be True.")

# Set the color palette
palette = plt.get_cmap(color_palette)
colors = palette.colors if hasattr(palette, 'colors') else palette(range(len(networks)))

fig, ax = plt.subplots(figsize=(12, 8))

for idx, (network_name, network) in enumerate(networks.items()):
# Get the number of nodes and edges
n_nodes = len(network.nodes)
n_edges = len(network.edges)
categories = []
values = []

if show_nodes:
categories.append('Nodes')
values.append(n_nodes)
if show_edges:
categories.append('Edges')
values.append(n_edges)

color = colors[idx % len(colors)]

if orientation == 'vertical':
positions = [f"{network_name} {cat}" for cat in categories]
ax.vlines(x=positions, ymin=0, ymax=values, color=color, linewidth=linewidth, label=network_name)
ax.scatter(positions, values, color=color, s=size ** 2, marker=marker, zorder=3)

# Annotate the values
for i, value in enumerate(values):
offset = size * 0.1 if value < 10 else size * 0.2
ax.text(positions[i], value + offset, str(value), ha='center', va='bottom', fontsize=size)
else:
positions = [f"{network_name} {cat}" for cat in categories]
ax.hlines(y=positions, xmin=0, xmax=values, color=color, linewidth=linewidth, label=network_name)
ax.scatter(values, positions, color=color, s=size ** 2, marker=marker, zorder=3)

# Annotate the values
for i, value in enumerate(values):
offset = size * 0.1 if value < 10 else size * 0.2
ax.text(value + offset, positions[i], str(value), va='center', ha='left', fontsize=size)

# Set the axis labels
if orientation == 'vertical':
ax.set_xlabel("Network and Type")
ax.set_ylabel("Count")
else:
ax.set_ylabel("Network and Type")
ax.set_xlabel("Count")

# Set the title depending on the categories
title = "Number of Nodes and Edges"
if show_nodes and not show_edges:
title = "Number of Nodes"
elif show_edges and not show_nodes:
title = "Number of Edges"
ax.set_title(title)

# Add a legend
ax.legend()

# Save the plot
if filepath is not None:
plt.savefig(filepath)

# Render the plot
if render:
plt.show()


# Test the function with sample networks
# if __name__ == "__main__":
# # Create sample directed graphs
# G1 = nx.DiGraph()
# G1.add_nodes_from(range(10)) # Adding 10 nodes
# G1.add_edges_from([(i, i + 1) for i in range(9)]) # Adding 9 edges
#
# G2 = nx.DiGraph()
# G2.add_nodes_from(range(15)) # Adding 15 nodes
# G2.add_edges_from([(i, i + 1) for i in range(14)]) # Adding 14 edges
#
# G3 = nx.DiGraph()
# G3.add_nodes_from(range(5)) # Adding 5 nodes
# G3.add_edges_from([(i, (i + 1) % 5) for i in range(5)]) # Adding 5 edges
#
# G4 = nx.DiGraph()
# G4.add_nodes_from(range(20)) # Adding 20 nodes
# G4.add_edges_from([(i, i + 1) for i in range(19)]) # Adding 19 edges
#
# networks = {'Network1': G1, 'Network2': G2, 'Network3': G3, 'Network4': G4}
#
# plot_n_nodes_edges(networks, filepath="nodes_edges_plot.png", render=True, orientation='horizontal',
# color_palette='Set2', size=12, linewidth=2, marker='o', show_nodes=True, show_edges=True)
Loading

0 comments on commit 9509c80

Please sign in to comment.