1+ import micropip
2+
3+ await micropip .install ("pango-collapse" , deps = False )
4+
5+ from pango_collapse import Collapsor
6+ from pango_collapse .utils import load_potential_parents_from_file
7+ from pyodide .http import open_url
8+ import csv
9+ from pyscript import when , document , window
10+
11+ print ("✅ Required packages loaded." )
12+ btn = document .querySelector ("#myfile" )
13+ btn .style .display = 'block'
14+ loading = document .querySelector ("#loading" )
15+ loading .style .display = 'none'
16+
17+ # At this point PyScript has already applied pyscript.json configuration,
18+ btn .disabled = False
19+
20+ def build_table (data , headers ):
21+ table = document .createElement ('table' )
22+ table .id = "table"
23+ header = table .createTHead ()
24+ header_row = header .insertRow (0 )
25+ for i , col_name in enumerate (headers ):
26+ cell = header_row .insertCell (i )
27+ cell .innerHTML = f"<b>{ col_name } </b>"
28+ tbody = table .createTBody ()
29+ for row_data in data :
30+ row = tbody .insertRow ()
31+ for i , col_name in enumerate (headers ):
32+ cell = row .insertCell (i )
33+ cell .innerHTML = row_data .get (col_name , "" )
34+ document .body .appendChild (table )
35+
36+
37+ def download_table_as_csv (table_id ):
38+ table = document .getElementById (table_id )
39+ rows = table .getElementsByTagName ('tr' )
40+ csv_content = []
41+ for row in rows :
42+ cells = row .getElementsByTagName ('td' )
43+ if cells .length == 0 :
44+ cells = row .getElementsByTagName ('th' )
45+ row_data = []
46+ for cell in cells :
47+ row_data .append (cell .innerText )
48+ csv_content .append (',' .join (row_data ))
49+ csv_string = '\n ' .join (csv_content )
50+ blob = window .Blob .new ([csv_string ], { "type" : "text/csv" })
51+ url = window .URL .createObjectURL (blob )
52+ a = document .createElement ('a' )
53+ a .href = url
54+ a .download = 'collapsed_lineages.csv'
55+ document .body .appendChild (a )
56+ a .click ()
57+ document .body .removeChild (a )
58+ window .URL .revokeObjectURL (url )
59+
60+ def copy_file_to_local (url ):
61+ filename = url .split ('/' )[- 1 ]
62+ with open (filename , 'w' ) as file :
63+ file .writelines (open_url ((url )).readlines ())
64+
65+ def collapse (data , lineage_col , collapse_col , expanded_col = 'Lineage_expanded' ):
66+
67+ copy_file_to_local ('https://raw.githubusercontent.com/cov-lineages/pango-designation/master/pango_designation/alias_key.json' )
68+ collapsor = Collapsor (alias_file = "alias_key.json" )
69+ collapse_file_url = document .getElementById ("collapse_file" ).value
70+ copy_file_to_local (collapse_file_url )
71+ potential_parents = load_potential_parents_from_file ("collapse.txt" )
72+ collapsed_data = []
73+ for row in data :
74+ row [collapse_col ] = collapsor .collapse (row [lineage_col ], potential_parents )
75+ row [expanded_col ] = collapsor .expand (row [lineage_col ])
76+ collapsed_data .append (row )
77+ return collapsed_data
78+
79+
80+ @when ("change" , "#myfile" )
81+ async def process_file (event ):
82+ print ("🚀 process_file called - file input detected!" )
83+ table_el = document .getElementById ("table" )
84+ if table_el :
85+ print ("📊 Removing existing table" )
86+ table_el .remove ()
87+ e = document .getElementById ("loading" )
88+ e .style .display = 'block'
89+ print ("⏳ Loading spinner displayed" )
90+
91+ lineage_col = document .getElementById ("lineage_col" ).value
92+ collapse_col = 'Lineage_family'
93+ expanded_col = 'Lineage_expanded'
94+ print (f"📝 Configuration - Lineage column: { lineage_col } " )
95+
96+ fileList = event .target .files .to_py ()
97+ print (f"📁 Number of files selected: { len (fileList )} " )
98+ for f in fileList :
99+ print (f"📄 Processing file: { f .name } " )
100+ delimiter = ','
101+ if f .name .endswith ('.tsv' ):
102+ delimiter = '\t '
103+ file = await f .text ()
104+ lines = file .split ("\n " )
105+ data = csv .DictReader (lines , delimiter = delimiter )
106+ collapsed_data = collapse (data , lineage_col , collapse_col , expanded_col = expanded_col )
107+ headers = data .fieldnames
108+ if collapse_col not in headers :
109+ headers += [collapse_col ]
110+ if expanded_col not in headers :
111+ headers += [expanded_col ]
112+ build_table (collapsed_data , headers = headers )
113+ download_table_as_csv ('table' )
114+ e .style .display = 'none'
0 commit comments