mgbam commited on
Commit
7c64f21
Β·
verified Β·
1 Parent(s): 990dd86

Update mcp/graph_metrics.py

Browse files
Files changed (1) hide show
  1. mcp/graph_metrics.py +11 -81
mcp/graph_metrics.py CHANGED
@@ -1,97 +1,27 @@
1
  # mcp/graph_metrics.py
2
- """
3
- Tiny NetworkX helpers for MedGenesis graphs.
4
-
5
- ✨ 2025-06-25 REVAMP
6
- ────────────────────
7
- β€’ Accepts edge-dicts that use either
8
- {'source': 'n1', 'target': 'n2'} ← agraph / d3.js
9
- or {'from' : 'n1', 'to' : 'n2'} ← PyVis
10
-
11
- β€’ Silently skips malformed edges (no more KeyError).
12
-
13
- β€’ Works whether you pass plain dicts or streamlit-agraph Node/Edge objects.
14
- """
15
-
16
- from __future__ import annotations
17
-
18
  import networkx as nx
19
- from typing import List, Dict, Tuple, Union
20
 
21
-
22
- # ── helpers -----------------------------------------------------------------
23
- def _edge_ends(e: Dict) -> Tuple[str, str] | None:
24
- """
25
- Normalise edge formats.
26
-
27
- Returns
28
- -------
29
- (src, dst) tuple – or None if either endpoint is missing.
30
- """
31
  src = e.get("source") or e.get("from")
32
  dst = e.get("target") or e.get("to")
33
- if src and dst:
34
- return str(src), str(dst)
35
- return None
36
-
37
-
38
- def _node_id(n: Union[Dict, object]) -> str:
39
- """
40
- Accept either a dict *or* a streamlit_agraph.Node and return its id.
41
- """
42
- if isinstance(n, dict):
43
- return str(n.get("id"))
44
- # fallback for Node dataclass
45
- return str(getattr(n, "id", ""))
46
 
47
-
48
- def _node_label(n: Union[Dict, object]) -> str:
49
- """
50
- Extract label safely from dict or Node.
51
- """
52
- if isinstance(n, dict):
53
- return str(n.get("label", n.get("id")))
54
- return str(getattr(n, "label", getattr(n, "id", "")))
55
-
56
-
57
- # ── public API --------------------------------------------------------------
58
- def build_nx(
59
- nodes: List[Dict | object],
60
- edges: List[Dict | object],
61
- ) -> nx.Graph:
62
- """
63
- Convert generic node/edge payloads into a NetworkX graph.
64
- """
65
  G = nx.Graph()
66
-
67
- # add nodes
68
  for n in nodes:
69
- nid = _node_id(n)
70
- if not nid:
71
- continue
72
- G.add_node(nid, label=_node_label(n))
73
-
74
- # add edges
75
  for e in edges:
76
- if not isinstance(e, dict):
77
- e = e.__dict__ # Edge dataclass β†’ dict
78
- ends = _edge_ends(e)
79
- if ends:
80
- G.add_edge(*ends)
81
-
82
  return G
83
 
84
-
85
- def get_top_hubs(G: nx.Graph, k: int = 5) -> List[Tuple[str, float]]:
86
- """
87
- Return top-k nodes by **degree centrality**.
88
- """
89
  dc = nx.degree_centrality(G)
90
  return sorted(dc.items(), key=lambda x: x[1], reverse=True)[:k]
91
 
92
-
93
  def get_density(G: nx.Graph) -> float:
94
- """
95
- Graph density in [0, 1].
96
- """
97
  return nx.density(G)
 
1
  # mcp/graph_metrics.py
2
+ from typing import List, Dict, Tuple
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  import networkx as nx
 
4
 
5
+ def _edge_endpoints(e: Dict) -> Tuple[str,str] | None:
 
 
 
 
 
 
 
 
 
6
  src = e.get("source") or e.get("from")
7
  dst = e.get("target") or e.get("to")
8
+ return (src,dst) if src and dst else None
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
+ def build_nx(nodes: List[Dict], edges: List[Dict]) -> nx.Graph:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  G = nx.Graph()
 
 
12
  for n in nodes:
13
+ nid = n.get("id")
14
+ if nid:
15
+ G.add_node(nid, label=n.get("label", nid))
 
 
 
16
  for e in edges:
17
+ pts = _edge_endpoints(e)
18
+ if pts:
19
+ G.add_edge(*pts)
 
 
 
20
  return G
21
 
22
+ def get_top_hubs(G: nx.Graph, k: int = 5):
 
 
 
 
23
  dc = nx.degree_centrality(G)
24
  return sorted(dc.items(), key=lambda x: x[1], reverse=True)[:k]
25
 
 
26
  def get_density(G: nx.Graph) -> float:
 
 
 
27
  return nx.density(G)