2020import matplotlib .ticker as mticker
2121import polars as pl
2222
23+ from .utils import (
24+ NODE_TYPE_LABELS ,
25+ PALETTE ,
26+ THEMES ,
27+ load_polled_edges ,
28+ normalize_relation_types ,
29+ )
30+
2331logger = logging .getLogger ("cli" )
2432
25- # Human-readable labels for compact node-type codes
26- NODE_TYPE_LABELS : dict [str , str ] = {
27- "ANA" : "Anatomy" ,
28- "BPO" : "Biological process" ,
29- "CCO" : "Cellular component" ,
30- "DIS" : "Disease" ,
31- "DRG" : "Drug" ,
32- "EXP" : "Exposure" ,
33- "GEN" : "Gene" ,
34- "MFN" : "Molecular function" ,
35- "PHE" : "Phenotype" ,
36- "PWY" : "Pathway" ,
37- }
38-
39- _PALETTE = [
40- "#516FD9" , # Royal Blue
41- "#7EACF5" , # Sky Blue
42- "#69C39C" , # Mint
43- "#6FA430" , # Green
44- "#E7C454" , # Yellow
45- "#EDB453" , # Amber
46- "#ED9353" , # Orange
47- "#DA3546" , # Red
48- "#9B7DF1" , # Purple
49- "#838E9F" , # Gray
50- ]
33+ _PALETTE = PALETTE
34+ _THEMES = THEMES
5135
5236_FALSE_GRAY = "#D0D0D0"
5337_ALL_RATINGS = [1 , 2 , 3 , 4 , 5 ]
5438_RATING_LABELS = ["No evidence" , "Weak" , "Moderate" , "Strong" , "Very strong" ]
55-
56- # Per-panel SVG themes. Data colors (palette, gray for false edges) stay the same;
57- # only axes/text/spines flip between light and dark.
58- _THEMES : dict [str , dict [str , str ]] = {
59- "light" : {"ink" : "#26251e" , "muted" : "#57534e" },
60- "dark" : {"ink" : "#ebebeb" , "muted" : "#a8a29e" },
61- }
6239_RATING_NO_EVIDENCE = _ALL_RATINGS [0 ]
6340_RATING_WEAK = _ALL_RATINGS [1 ]
6441_RATING_MODERATE = _ALL_RATINGS [2 ]
@@ -72,41 +49,6 @@ def _run_id_from_path(path: Path) -> str:
7249 return path .stem
7350
7451
75- def _load_df (input_path : Path ) -> pl .DataFrame :
76- if not input_path .exists ():
77- raise FileNotFoundError (f"Input file not found: { input_path } " )
78-
79- df = pl .read_csv (input_path , infer_schema_length = 100000 )
80-
81- required = {"seed_node_type" , "is_true_edge" , "rating" }
82- missing = required - set (df .columns )
83- if missing :
84- raise ValueError (f"Input CSV is missing required columns: { missing } " )
85-
86- return df .with_columns (
87- pl .col ("rating" ).cast (pl .Int32 , strict = False ),
88- pl .col ("is_true_edge" ).cast (pl .Boolean , strict = False ),
89- ).filter (pl .col ("rating" ).is_not_null () & pl .col ("is_true_edge" ).is_not_null ())
90-
91-
92- # Whole-token PRO → GEN (Unicode word boundaries: hyphens/pipes/ends ok; not "PROGRAM")
93- _RELATION_PRO_TO_GEN_PATTERN = r"\bPRO\b"
94-
95-
96- def _relation_type_pro_to_gen (df : pl .DataFrame ) -> pl .DataFrame :
97- """Replace whole-token ``PRO`` with ``GEN`` in ``relation_type`` (pipes, hyphens, etc.)."""
98- if "relation_type" not in df .columns :
99- return df
100- return df .with_columns (
101- pl .when (pl .col ("relation_type" ).is_null ())
102- .then (None )
103- .otherwise (
104- pl .col ("relation_type" ).str .replace_all (_RELATION_PRO_TO_GEN_PATTERN , "GEN" )
105- )
106- .alias ("relation_type" ),
107- )
108-
109-
11052def _by_prevalence (df : pl .DataFrame , col : str ) -> list [str ]:
11153 """Return unique values of `col` ordered by descending row count."""
11254 return (
@@ -643,12 +585,12 @@ def run(
643585 out_dir = out_dir or input_path .parent
644586 out_dir .mkdir (parents = True , exist_ok = True )
645587
646- df = _load_df (input_path )
588+ df = load_polled_edges (input_path )
647589 if df .is_empty ():
648590 logger .warning ("No rows with valid rating + is_true_edge; nothing to plot." )
649591 return
650592
651- df = _relation_type_pro_to_gen (df )
593+ df = normalize_relation_types (df )
652594
653595 run_id = _run_id_from_path (input_path )
654596
0 commit comments