'''Interactive HTML network visualization with PyVis''' # Reference: pyvis 0.3+, networkx 3.2+ | Verify API if version differs import networkx as nx import numpy as np from pyvis.network import Network from networkx.algorithms.community import greedy_modularity_communities # --- ALTERNATIVE: Load real interaction data --- # import pandas as pd # interactions = pd.read_csv('string_interactions.csv') # G = nx.Graph() # for _, row in interactions.iterrows(): # G.add_edge(row['gene_a'], row['gene_b'], weight=row['score'] / 1000) np.random.seed(42) genes = [f'Gene{i}' for i in range(1, 41)] G = nx.barabasi_albert_graph(40, 2, seed=42) G = nx.relabel_nodes(G, {i: genes[i] for i in range(40)}) for u, v in G.edges(): G[u][v]['weight'] = np.random.uniform(0.4, 1.0) G[u][v]['score'] = int(G[u][v]['weight'] * 1000) def create_interactive_network(G, output='network.html', title='Biological Network'): '''Basic interactive network with PyVis''' net = Network(height='700px', width='100%', bgcolor='white', font_color='black', heading=title) net.from_nx(G) net.toggle_physics(True) net.show_buttons(filter_=['physics']) net.save_graph(output) return output def create_styled_network(G, output='styled_network.html', title='Styled Network'): '''Interactive network with degree sizing and community coloring''' net = Network(height='700px', width='100%', bgcolor='white', font_color='black', heading=title) communities = list(greedy_modularity_communities(G)) node_to_community = {} for i, comm in enumerate(communities): for node in comm: node_to_community[node] = i # Nature-style color palette, colorblind-friendly for up to 8 communities palette = ['#E64B35', '#4DBBD5', '#00A087', '#3C5488', '#F39B7F', '#8491B4', '#91D1C2', '#DC0000'] degrees = dict(G.degree()) for node in G.nodes(): comm_idx = node_to_community.get(node, 0) color = palette[comm_idx % len(palette)] size = 10 + degrees[node] * 5 tooltip = f'{node}\nDegree: {degrees[node]}\nCommunity: {comm_idx + 1}' net.add_node(node, size=size, color=color, title=tooltip, label=node) for u, v, data in G.edges(data=True): weight = data.get('weight', 0.5) score = data.get('score', 500) tooltip = f'{u} -- {v}\nScore: {score}' net.add_edge(u, v, width=weight * 3, title=tooltip) options = { 'physics': { 'forceAtlas2Based': {'gravitationalConstant': -50, 'centralGravity': 0.01, 'springLength': 100, 'springConstant': 0.08}, 'solver': 'forceAtlas2Based', 'stabilization': {'iterations': 150} }, 'interaction': {'hover': True, 'navigationButtons': True, 'keyboard': True} } import json net.set_options(json.dumps(options)) net.save_graph(output) return output # --- Create basic interactive network --- basic_file = create_interactive_network(G, output='network_basic.html', title='Basic Interactive Network') print(f'Basic network saved: {basic_file}') # --- Create styled network with communities --- styled_file = create_styled_network(G, output='network_styled.html', title='PPI Network with Communities') print(f'Styled network saved: {styled_file}') # --- Summary --- communities = list(greedy_modularity_communities(G)) print(f'\nNetwork: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges') print(f'Communities detected: {len(communities)}') for i, comm in enumerate(communities): print(f' Community {i+1}: {len(comm)} nodes') print('\nOpen the HTML files in a browser to interact with the networks.')