Spaces:
Sleeping
Sleeping
Update genesis/visualization.py
Browse files- genesis/visualization.py +147 -54
genesis/visualization.py
CHANGED
@@ -1,62 +1,155 @@
|
|
1 |
# genesis/visualization.py
|
2 |
-
import
|
3 |
-
|
4 |
-
import
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
"""
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
Returns: file path to PNG
|
28 |
"""
|
29 |
-
|
30 |
-
|
31 |
-
|
|
|
32 |
|
33 |
-
|
34 |
-
|
|
|
|
|
|
|
|
|
35 |
|
36 |
-
|
37 |
-
file_path = "/tmp/pathway_graph.png"
|
38 |
-
with open(file_path, "wb") as f:
|
39 |
-
f.write(buf.read())
|
40 |
-
return file_path
|
41 |
|
42 |
-
|
|
|
|
|
|
|
43 |
"""
|
44 |
-
|
45 |
-
companies: list of dicts {name, investors}
|
46 |
-
Returns: file path to PNG
|
47 |
"""
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
# genesis/visualization.py
|
2 |
+
import os
|
3 |
+
from neo4j import GraphDatabase
|
4 |
+
import plotly.graph_objects as go
|
5 |
+
|
6 |
+
# =========================
|
7 |
+
# CONFIGURATION
|
8 |
+
# =========================
|
9 |
+
NEO4J_URI = os.getenv("NEO4J_URI")
|
10 |
+
NEO4J_USER = os.getenv("NEO4J_USER")
|
11 |
+
NEO4J_PASSWORD = os.getenv("NEO4J_PASSWORD")
|
12 |
+
|
13 |
+
COLOR_PATHWAY_NODE = "#00FF99" # Biotech green
|
14 |
+
COLOR_FUNDING_NODE = "#FF9900" # Orange
|
15 |
+
COLOR_EDGE = "#AAAAAA"
|
16 |
+
|
17 |
+
# =========================
|
18 |
+
# NEO4J CONNECTION
|
19 |
+
# =========================
|
20 |
+
driver = GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD))
|
21 |
+
|
22 |
+
def run_neo4j_query(query, params=None):
|
23 |
+
"""Run a Cypher query and return results."""
|
24 |
+
with driver.session() as session:
|
25 |
+
return list(session.run(query, params or {}))
|
26 |
+
|
27 |
+
# =========================
|
28 |
+
# GRAPH UTILS
|
29 |
+
# =========================
|
30 |
+
def create_plotly_graph(nodes, edges, title):
|
31 |
+
"""Creates an interactive Plotly network graph."""
|
32 |
+
node_x, node_y, node_text, node_color = [], [], [], []
|
33 |
+
edge_x, edge_y = [], []
|
34 |
+
|
35 |
+
# Layout algorithm (spring layout for better spacing)
|
36 |
+
import networkx as nx
|
37 |
+
G = nx.Graph()
|
38 |
+
for node_id, label, color in nodes:
|
39 |
+
G.add_node(node_id, label=label, color=color)
|
40 |
+
for src, dst in edges:
|
41 |
+
G.add_edge(src, dst)
|
42 |
+
|
43 |
+
pos = nx.spring_layout(G, seed=42, k=0.5)
|
44 |
+
|
45 |
+
for src, dst in edges:
|
46 |
+
x0, y0 = pos[src]
|
47 |
+
x1, y1 = pos[dst]
|
48 |
+
edge_x.extend([x0, x1, None])
|
49 |
+
edge_y.extend([y0, y1, None])
|
50 |
+
|
51 |
+
for node_id, label, color in nodes:
|
52 |
+
x, y = pos[node_id]
|
53 |
+
node_x.append(x)
|
54 |
+
node_y.append(y)
|
55 |
+
node_text.append(label)
|
56 |
+
node_color.append(color)
|
57 |
+
|
58 |
+
edge_trace = go.Scatter(
|
59 |
+
x=edge_x, y=edge_y,
|
60 |
+
line=dict(width=1, color=COLOR_EDGE),
|
61 |
+
hoverinfo='none',
|
62 |
+
mode='lines'
|
63 |
+
)
|
64 |
+
|
65 |
+
node_trace = go.Scatter(
|
66 |
+
x=node_x, y=node_y,
|
67 |
+
mode='markers+text',
|
68 |
+
text=node_text,
|
69 |
+
textposition="top center",
|
70 |
+
hoverinfo="text",
|
71 |
+
marker=dict(
|
72 |
+
color=node_color,
|
73 |
+
size=18,
|
74 |
+
line=dict(width=2, color='#000000')
|
75 |
+
)
|
76 |
+
)
|
77 |
+
|
78 |
+
fig = go.Figure(data=[edge_trace, node_trace])
|
79 |
+
fig.update_layout(
|
80 |
+
title=title,
|
81 |
+
title_x=0.5,
|
82 |
+
plot_bgcolor="#111111",
|
83 |
+
paper_bgcolor="#111111",
|
84 |
+
font=dict(color="#FFFFFF"),
|
85 |
+
showlegend=False,
|
86 |
+
margin=dict(l=10, r=10, t=40, b=10)
|
87 |
+
)
|
88 |
+
return fig
|
89 |
+
|
90 |
+
# =========================
|
91 |
+
# PATHWAY GRAPH
|
92 |
+
# =========================
|
93 |
+
def generate_pathway_graph(pathway_name):
|
94 |
+
"""
|
95 |
+
Generate an interactive graph for a given metabolic pathway.
|
96 |
"""
|
97 |
+
query = """
|
98 |
+
MATCH (p:Pathway {name: $name})-[r:INVOLVES]->(m:Molecule)
|
99 |
+
RETURN p.name AS pathway, m.name AS molecule
|
|
|
100 |
"""
|
101 |
+
results = run_neo4j_query(query, {"name": pathway_name})
|
102 |
+
|
103 |
+
if not results:
|
104 |
+
return None
|
105 |
|
106 |
+
nodes = [(pathway_name, pathway_name, COLOR_PATHWAY_NODE)]
|
107 |
+
edges = []
|
108 |
+
for record in results:
|
109 |
+
mol_name = record["molecule"]
|
110 |
+
nodes.append((mol_name, mol_name, "#00BFFF")) # Blue for molecules
|
111 |
+
edges.append((pathway_name, mol_name))
|
112 |
|
113 |
+
return create_plotly_graph(nodes, edges, f"Metabolic Pathway: {pathway_name}")
|
|
|
|
|
|
|
|
|
114 |
|
115 |
+
# =========================
|
116 |
+
# FUNDING NETWORK
|
117 |
+
# =========================
|
118 |
+
def generate_funding_network(industry_keyword):
|
119 |
"""
|
120 |
+
Generate an interactive funding network graph for companies in a given biotech domain.
|
|
|
|
|
121 |
"""
|
122 |
+
query = """
|
123 |
+
MATCH (c:Company)-[f:FUNDED_BY]->(i:Investor)
|
124 |
+
WHERE toLower(c.industry) CONTAINS toLower($keyword)
|
125 |
+
RETURN c.name AS company, i.name AS investor
|
126 |
+
"""
|
127 |
+
results = run_neo4j_query(query, {"keyword": industry_keyword})
|
128 |
+
|
129 |
+
if not results:
|
130 |
+
return None
|
131 |
+
|
132 |
+
nodes = []
|
133 |
+
edges = []
|
134 |
+
seen_nodes = set()
|
135 |
+
|
136 |
+
for record in results:
|
137 |
+
comp = record["company"]
|
138 |
+
inv = record["investor"]
|
139 |
+
|
140 |
+
if comp not in seen_nodes:
|
141 |
+
nodes.append((comp, comp, COLOR_FUNDING_NODE))
|
142 |
+
seen_nodes.add(comp)
|
143 |
+
if inv not in seen_nodes:
|
144 |
+
nodes.append((inv, inv, "#FFD700")) # Gold for investors
|
145 |
+
seen_nodes.add(inv)
|
146 |
+
|
147 |
+
edges.append((comp, inv))
|
148 |
+
|
149 |
+
return create_plotly_graph(nodes, edges, f"Funding Network: {industry_keyword}")
|
150 |
+
|
151 |
+
# =========================
|
152 |
+
# CLEANUP
|
153 |
+
# =========================
|
154 |
+
def close_driver():
|
155 |
+
driver.close()
|