mgbam commited on
Commit
937ad52
·
verified ·
1 Parent(s): adad416

Update genesis/visualization.py

Browse files
Files changed (1) hide show
  1. genesis/visualization.py +147 -54
genesis/visualization.py CHANGED
@@ -1,62 +1,155 @@
1
  # genesis/visualization.py
2
- import networkx as nx
3
- import matplotlib.pyplot as plt
4
- import io
5
- import base64
6
-
7
- def _graph_to_image_bytes(G, layout_func=nx.spring_layout):
8
- """Helper: Convert NetworkX graph to PNG bytes."""
9
- plt.figure(figsize=(8, 6))
10
- pos = layout_func(G)
11
- nx.draw_networkx_nodes(G, pos, node_size=1500, node_color="#34d399", alpha=0.9)
12
- nx.draw_networkx_edges(G, pos, width=2, alpha=0.5, edge_color="#6b7280")
13
- nx.draw_networkx_labels(G, pos, font_size=10, font_family="sans-serif", font_color="white")
14
- plt.axis("off")
15
-
16
- buf = io.BytesIO()
17
- plt.savefig(buf, format="png", bbox_inches="tight")
18
- plt.close()
19
- buf.seek(0)
20
- return buf
21
-
22
- def generate_pathway_graph(entities, relationships):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  """
24
- Create a pathway relationship graph for synthetic biology concepts.
25
- entities: list of strings
26
- relationships: list of dicts {source, target, type}
27
- Returns: file path to PNG
28
  """
29
- G = nx.DiGraph()
30
- for entity in entities:
31
- G.add_node(entity)
 
32
 
33
- for rel in relationships:
34
- G.add_edge(rel["source"], rel["target"], label=rel["type"])
 
 
 
 
35
 
36
- buf = _graph_to_image_bytes(G)
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
- def generate_funding_network(companies):
 
 
 
43
  """
44
- Create a funding network graph.
45
- companies: list of dicts {name, investors}
46
- Returns: file path to PNG
47
  """
48
- G = nx.Graph()
49
- for comp in companies:
50
- company_node = f"🏢 {comp['name']}"
51
- G.add_node(company_node)
52
- investors = [i.strip() for i in comp["investors"].split(",")]
53
- for inv in investors:
54
- inv_node = f"💰 {inv}"
55
- G.add_node(inv_node)
56
- G.add_edge(company_node, inv_node)
57
-
58
- buf = _graph_to_image_bytes(G, layout_func=nx.kamada_kawai_layout)
59
- file_path = "/tmp/funding_network.png"
60
- with open(file_path, "wb") as f:
61
- f.write(buf.read())
62
- return file_path
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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()