| """Visualization payload — formats the patient subgraph for react-force-graph. |
| |
| The raras-app /grafo page renders nodes/links via react-force-graph-3d. |
| This module produces the exact JSON shape that component expects, so the |
| front-end can drop in `<ForceGraph data={twin.viz_data} />`. |
| |
| Color map is consistent with raras-app conventions: |
| Patient #00d4ff |
| Phenotype #f59e0b |
| Disease #ef4444 |
| Gene #10b981 |
| Drug #8b5cf6 |
| Lab #6366f1 |
| """ |
| from __future__ import annotations |
| from typing import Optional |
|
|
| from .types import VizData, Subgraph |
|
|
| _COLOR = { |
| "Patient": "#00d4ff", |
| "Phenotype": "#f59e0b", |
| "Disease": "#ef4444", |
| "Gene": "#10b981", |
| "Drug": "#8b5cf6", |
| "Lab": "#6366f1", |
| "Snapshot": "#a78bfa", |
| } |
|
|
| _GROUP = { |
| "Patient": 0, "Phenotype": 1, "Disease": 2, "Gene": 3, |
| "Drug": 4, "Lab": 5, "Snapshot": 6, |
| } |
|
|
| _VAL = { |
| "Patient": 30, "Disease": 18, "Gene": 12, "Phenotype": 10, |
| "Drug": 14, "Lab": 8, "Snapshot": 9, |
| } |
|
|
|
|
| def from_subgraph(sg: Subgraph, *, center_id: Optional[str] = None) -> VizData: |
| """Convert a `Subgraph` into a force-graph-friendly payload.""" |
| nodes = [] |
| for n in sg.nodes: |
| nodes.append({ |
| "id": n.id, |
| "name": n.name, |
| "group": _GROUP.get(n.label, 9), |
| "label": n.label, |
| "val": _VAL.get(n.label, 8) * (0.5 + n.weight), |
| "color": _COLOR.get(n.label, "#94a3b8"), |
| "hpo": n.code if n.label == "Phenotype" else None, |
| "orpha": n.code if n.label == "Disease" else None, |
| "symbol": n.code if n.label == "Gene" else None, |
| "rxcui": n.code if n.label == "Drug" else None, |
| "weight": n.weight, |
| **(n.extra or {}), |
| }) |
| links = [] |
| for e in sg.edges: |
| links.append({ |
| "source": e.source, |
| "target": e.target, |
| "label": e.rel, |
| "value": max(0.5, e.weight), |
| "evidence": e.evidence, |
| }) |
|
|
| legend = {label: {"color": color, "group": _GROUP.get(label, 9)} for label, color in _COLOR.items()} |
|
|
| return VizData( |
| nodes=nodes, |
| links=links, |
| center_id=center_id, |
| legend=legend, |
| ) |
|
|