pg-sui 0.2.3__py3-none-any.whl → 1.6.16a3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. pg_sui-1.6.16a3.dist-info/METADATA +292 -0
  2. pg_sui-1.6.16a3.dist-info/RECORD +81 -0
  3. {pg_sui-0.2.3.dist-info → pg_sui-1.6.16a3.dist-info}/WHEEL +1 -1
  4. pg_sui-1.6.16a3.dist-info/entry_points.txt +4 -0
  5. {pg_sui-0.2.3.dist-info → pg_sui-1.6.16a3.dist-info/licenses}/LICENSE +0 -0
  6. pg_sui-1.6.16a3.dist-info/top_level.txt +1 -0
  7. pgsui/__init__.py +35 -54
  8. pgsui/_version.py +34 -0
  9. pgsui/cli.py +922 -0
  10. pgsui/data_processing/__init__.py +0 -0
  11. pgsui/data_processing/config.py +565 -0
  12. pgsui/data_processing/containers.py +1436 -0
  13. pgsui/data_processing/transformers.py +557 -907
  14. pgsui/{example_data/trees → electron/app}/__init__.py +0 -0
  15. pgsui/electron/app/__main__.py +5 -0
  16. pgsui/electron/app/extra-resources/.gitkeep +1 -0
  17. pgsui/electron/app/icons/icons/1024x1024.png +0 -0
  18. pgsui/electron/app/icons/icons/128x128.png +0 -0
  19. pgsui/electron/app/icons/icons/16x16.png +0 -0
  20. pgsui/electron/app/icons/icons/24x24.png +0 -0
  21. pgsui/electron/app/icons/icons/256x256.png +0 -0
  22. pgsui/electron/app/icons/icons/32x32.png +0 -0
  23. pgsui/electron/app/icons/icons/48x48.png +0 -0
  24. pgsui/electron/app/icons/icons/512x512.png +0 -0
  25. pgsui/electron/app/icons/icons/64x64.png +0 -0
  26. pgsui/electron/app/icons/icons/icon.icns +0 -0
  27. pgsui/electron/app/icons/icons/icon.ico +0 -0
  28. pgsui/electron/app/main.js +227 -0
  29. pgsui/electron/app/package-lock.json +6894 -0
  30. pgsui/electron/app/package.json +51 -0
  31. pgsui/electron/app/preload.js +15 -0
  32. pgsui/electron/app/server.py +157 -0
  33. pgsui/electron/app/ui/logo.png +0 -0
  34. pgsui/electron/app/ui/renderer.js +131 -0
  35. pgsui/electron/app/ui/styles.css +59 -0
  36. pgsui/electron/app/ui/ui_shim.js +72 -0
  37. pgsui/electron/bootstrap.py +43 -0
  38. pgsui/electron/launch.py +57 -0
  39. pgsui/electron/package.json +14 -0
  40. pgsui/example_data/__init__.py +0 -0
  41. pgsui/example_data/phylip_files/__init__.py +0 -0
  42. pgsui/example_data/phylip_files/test.phy +0 -0
  43. pgsui/example_data/popmaps/__init__.py +0 -0
  44. pgsui/example_data/popmaps/{test.popmap → phylogen_nomx.popmap} +185 -99
  45. pgsui/example_data/structure_files/__init__.py +0 -0
  46. pgsui/example_data/structure_files/test.pops.2row.allsites.str +0 -0
  47. pgsui/example_data/vcf_files/phylogen_subset14K.vcf.gz +0 -0
  48. pgsui/example_data/vcf_files/phylogen_subset14K.vcf.gz.tbi +0 -0
  49. pgsui/impute/__init__.py +0 -0
  50. pgsui/impute/deterministic/imputers/allele_freq.py +725 -0
  51. pgsui/impute/deterministic/imputers/mode.py +844 -0
  52. pgsui/impute/deterministic/imputers/nmf.py +221 -0
  53. pgsui/impute/deterministic/imputers/phylo.py +973 -0
  54. pgsui/impute/deterministic/imputers/ref_allele.py +669 -0
  55. pgsui/impute/supervised/__init__.py +0 -0
  56. pgsui/impute/supervised/base.py +343 -0
  57. pgsui/impute/{unsupervised/models/in_development → supervised/imputers}/__init__.py +0 -0
  58. pgsui/impute/supervised/imputers/hist_gradient_boosting.py +317 -0
  59. pgsui/impute/supervised/imputers/random_forest.py +291 -0
  60. pgsui/impute/unsupervised/__init__.py +0 -0
  61. pgsui/impute/unsupervised/base.py +1121 -0
  62. pgsui/impute/unsupervised/callbacks.py +92 -262
  63. {simulation → pgsui/impute/unsupervised/imputers}/__init__.py +0 -0
  64. pgsui/impute/unsupervised/imputers/autoencoder.py +1361 -0
  65. pgsui/impute/unsupervised/imputers/nlpca.py +1666 -0
  66. pgsui/impute/unsupervised/imputers/ubp.py +1660 -0
  67. pgsui/impute/unsupervised/imputers/vae.py +1316 -0
  68. pgsui/impute/unsupervised/loss_functions.py +261 -0
  69. pgsui/impute/unsupervised/models/__init__.py +0 -0
  70. pgsui/impute/unsupervised/models/autoencoder_model.py +215 -567
  71. pgsui/impute/unsupervised/models/nlpca_model.py +155 -394
  72. pgsui/impute/unsupervised/models/ubp_model.py +180 -1106
  73. pgsui/impute/unsupervised/models/vae_model.py +269 -630
  74. pgsui/impute/unsupervised/nn_scorers.py +255 -0
  75. pgsui/utils/__init__.py +0 -0
  76. pgsui/utils/classification_viz.py +608 -0
  77. pgsui/utils/logging_utils.py +22 -0
  78. pgsui/utils/misc.py +35 -480
  79. pgsui/utils/plotting.py +996 -829
  80. pgsui/utils/pretty_metrics.py +290 -0
  81. pgsui/utils/scorers.py +213 -666
  82. pg_sui-0.2.3.dist-info/METADATA +0 -322
  83. pg_sui-0.2.3.dist-info/RECORD +0 -75
  84. pg_sui-0.2.3.dist-info/top_level.txt +0 -3
  85. pgsui/example_data/phylip_files/test_n10.phy +0 -118
  86. pgsui/example_data/phylip_files/test_n100.phy +0 -118
  87. pgsui/example_data/phylip_files/test_n2.phy +0 -118
  88. pgsui/example_data/phylip_files/test_n500.phy +0 -118
  89. pgsui/example_data/structure_files/test.nopops.1row.10sites.str +0 -117
  90. pgsui/example_data/structure_files/test.nopops.2row.100sites.str +0 -234
  91. pgsui/example_data/structure_files/test.nopops.2row.10sites.str +0 -234
  92. pgsui/example_data/structure_files/test.nopops.2row.30sites.str +0 -234
  93. pgsui/example_data/structure_files/test.nopops.2row.allsites.str +0 -234
  94. pgsui/example_data/structure_files/test.pops.1row.10sites.str +0 -117
  95. pgsui/example_data/structure_files/test.pops.2row.10sites.str +0 -234
  96. pgsui/example_data/trees/test.iqtree +0 -376
  97. pgsui/example_data/trees/test.qmat +0 -5
  98. pgsui/example_data/trees/test.rate +0 -2033
  99. pgsui/example_data/trees/test.tre +0 -1
  100. pgsui/example_data/trees/test_n10.rate +0 -19
  101. pgsui/example_data/trees/test_n100.rate +0 -109
  102. pgsui/example_data/trees/test_n500.rate +0 -509
  103. pgsui/example_data/trees/test_siterates.txt +0 -2024
  104. pgsui/example_data/trees/test_siterates_n10.txt +0 -10
  105. pgsui/example_data/trees/test_siterates_n100.txt +0 -100
  106. pgsui/example_data/trees/test_siterates_n500.txt +0 -500
  107. pgsui/example_data/vcf_files/test.vcf +0 -244
  108. pgsui/example_data/vcf_files/test.vcf.gz +0 -0
  109. pgsui/example_data/vcf_files/test.vcf.gz.tbi +0 -0
  110. pgsui/impute/estimators.py +0 -1268
  111. pgsui/impute/impute.py +0 -1463
  112. pgsui/impute/simple_imputers.py +0 -1431
  113. pgsui/impute/supervised/iterative_imputer_fixedparams.py +0 -782
  114. pgsui/impute/supervised/iterative_imputer_gridsearch.py +0 -1024
  115. pgsui/impute/unsupervised/keras_classifiers.py +0 -697
  116. pgsui/impute/unsupervised/models/in_development/cnn_model.py +0 -486
  117. pgsui/impute/unsupervised/neural_network_imputers.py +0 -1440
  118. pgsui/impute/unsupervised/neural_network_methods.py +0 -1395
  119. pgsui/pg_sui.py +0 -261
  120. pgsui/utils/sequence_tools.py +0 -407
  121. simulation/sim_benchmarks.py +0 -333
  122. simulation/sim_treeparams.py +0 -475
  123. test/__init__.py +0 -0
  124. test/pg_sui_simtest.py +0 -215
  125. test/pg_sui_testing.py +0 -523
  126. test/test.py +0 -151
  127. test/test_pgsui.py +0 -374
  128. test/test_tkc.py +0 -185
File without changes
@@ -0,0 +1,5 @@
1
+ import uvicorn
2
+
3
+ from .server import app
4
+
5
+ uvicorn.run(app, host="0.0.0.0", port=8765, log_level="info")
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,227 @@
1
+ const { app, BrowserWindow, ipcMain, dialog } = require('electron');
2
+ const path = require('path');
3
+ const fs = require('fs');
4
+ const { spawn, spawnSync } = require('child_process');
5
+ const readline = require('readline');
6
+
7
+ app.disableHardwareAcceleration();
8
+ app.commandLine.appendSwitch('disable-gpu');
9
+
10
+ let win = null;
11
+ let currentChild = null;
12
+
13
+ function resolveBundledPython() {
14
+ const candidates = [
15
+ path.join(process.resourcesPath || '', 'extras', 'venv', 'bin', 'python3'),
16
+ path.join(process.resourcesPath || '', 'extras', 'venv', 'bin', 'python'),
17
+ path.join(process.resourcesPath || '', 'extras', 'venv', 'Scripts', 'python.exe'),
18
+ path.resolve(__dirname, 'extras', 'venv', 'bin', 'python3'),
19
+ path.resolve(__dirname, 'extras', 'venv', 'bin', 'python'),
20
+ path.resolve(__dirname, 'extras', 'venv', 'Scripts', 'python.exe'),
21
+ ];
22
+ for (const pth of candidates) {
23
+ if (pth && fs.existsSync(pth)) return pth;
24
+ }
25
+ return null;
26
+ }
27
+
28
+ function pickFirstWorkingPython(candidates) {
29
+ for (const exe of candidates) {
30
+ if (!exe) continue;
31
+ try {
32
+ const res = spawnSync(exe, ['--version'], { env: process.env });
33
+ if (res.status === 0 || res.stdout.length || res.stderr.length) return exe;
34
+ } catch { /* try next */ }
35
+ }
36
+ return 'python3';
37
+ }
38
+
39
+ function createWindow() {
40
+ win = new BrowserWindow({
41
+ width: 1200,
42
+ height: 880,
43
+ backgroundColor: '#0b0f14',
44
+ titleBarStyle: process.platform === 'darwin' ? 'hiddenInset' : 'default',
45
+ webPreferences: {
46
+ preload: path.join(__dirname, 'preload.js'),
47
+ contextIsolation: true,
48
+ sandbox: true,
49
+ nodeIntegration: false,
50
+ webSecurity: true,
51
+ backgroundThrottling: false
52
+ }
53
+ });
54
+ win.loadFile(path.join(__dirname, 'ui', 'index.html'));
55
+ }
56
+
57
+ const gotLock = app.requestSingleInstanceLock();
58
+ if (!gotLock) app.quit();
59
+ else {
60
+ app.whenReady().then(() => {
61
+ createWindow();
62
+ app.on('activate', () => {
63
+ if (BrowserWindow.getAllWindows().length === 0) createWindow();
64
+ });
65
+ });
66
+ }
67
+ app.on('window-all-closed', () => { if (process.platform !== 'darwin') app.quit(); });
68
+
69
+ function buildArgs(p) {
70
+ const a = [];
71
+ const kv = (f, v) => { if (v !== undefined && v !== null && String(v).trim() !== '') a.push(f, String(v)); };
72
+ const fl = (f, c) => { if (c) a.push(f); };
73
+ kv('--input', p.inputPath);
74
+ kv('--format', p.format);
75
+ kv('--popmap', p.popmapPath);
76
+ kv('--prefix', p.prefix);
77
+ kv('--config', p.yamlPath);
78
+ kv('--dump-config', p.dumpConfigPath);
79
+ kv('--preset', p.preset || 'fast');
80
+ kv('--sim-strategy', p.simStrategy);
81
+ if (Array.isArray(p.models) && p.models.length) a.push('--models', ...p.models);
82
+ if (Array.isArray(p.includePops) && p.includePops.length) a.push('--include-pops', ...p.includePops);
83
+ fl('--tune', !!p.tune);
84
+ if (p.tuneNTrials) kv('--tune-n-trials', p.tuneNTrials);
85
+ kv('--batch-size', p.batchSize ?? 64);
86
+ if (['cpu','cuda','mps'].includes(p.device || '')) kv('--device', p.device);
87
+ if (p.nJobs) kv('--n-jobs', p.nJobs);
88
+ if (['png','pdf','svg'].includes(p.plotFormat || '')) kv('--plot-format', p.plotFormat);
89
+ if (p.seed) kv('--seed', p.seed);
90
+ fl('--verbose', !!p.verbose);
91
+ if (p.logFile) kv('--log-file', p.logFile);
92
+ fl('--force-popmap', !!p.forcePopmap);
93
+ fl('--dry-run', !!p.dryRun);
94
+ (p.setPairs || []).forEach(s => { if (s && s.includes('=')) a.push('--set', s); });
95
+ return a;
96
+ }
97
+
98
+ function checkCmd(cmd, args = ['--version']) {
99
+ return new Promise((resolve) => {
100
+ try {
101
+ const p = spawn(cmd, args, { env: process.env });
102
+ let seen = false;
103
+ p.stdout.on('data', () => { seen = true; });
104
+ p.stderr.on('data', () => { seen = true; });
105
+ p.on('error', () => resolve(false));
106
+ p.on('close', () => resolve(seen));
107
+ } catch { resolve(false); }
108
+ });
109
+ }
110
+
111
+ // ---- IPC: always reply using event.sender; never use win.webContents ----
112
+ ipcMain.handle('detect:pgsui', async () => ({ ok: await checkCmd('pg-sui') }));
113
+
114
+ ipcMain.handle('pgsui:start', async (evt, payload) => {
115
+ const send = (ch, m) => { try { evt?.sender?.send(ch, m); } catch {} };
116
+
117
+ if (currentChild) return { ok: false, error: 'Process already running.' };
118
+ if (!payload?.cwd || !String(payload.cwd).trim()) return { ok: false, error: 'Working directory is required.' };
119
+
120
+ const args = buildArgs(payload);
121
+ const cwd = payload.cwd;
122
+
123
+ let fullArgv;
124
+ if (payload.usePgSui === true) { // you likely removed this path; keeping for safety
125
+ const cmd = 'pg-sui';
126
+ fullArgv = [cmd, ...args];
127
+ currentChild = spawn(cmd, args, { cwd, env: process.env });
128
+ } else {
129
+ const pythonExe = pickFirstWorkingPython([
130
+ resolveBundledPython(),
131
+ payload.pythonPath,
132
+ process.env.PGSUI_PYTHON,
133
+ '/opt/homebrew/bin/python3.12',
134
+ '/usr/local/bin/python3.12',
135
+ 'python3.12',
136
+ 'python3',
137
+ 'python',
138
+ ]);
139
+ let cliPath = payload.cliPath;
140
+ if (!cliPath) {
141
+ const r = await resolveDefaultCli();
142
+ if (r.ok) cliPath = r.path;
143
+ }
144
+ if (!cliPath || !fs.existsSync(cliPath)) return { ok: false, error: `cli.py not found at ${cliPath || '<auto>'}` };
145
+ fullArgv = [pythonExe, cliPath, ...args];
146
+ currentChild = spawn(pythonExe, [cliPath, ...args], { cwd, env: process.env });
147
+ }
148
+
149
+ // wire streams BEFORE returning
150
+ const rlOut = readline.createInterface({ input: currentChild.stdout });
151
+ rlOut.on('line', line => send('pgsui:log', { stream: 'stdout', line }));
152
+ const rlErr = readline.createInterface({ input: currentChild.stderr });
153
+ rlErr.on('line', line => send('pgsui:log', { stream: 'stderr', line }));
154
+
155
+ currentChild.on('close', code => { send('pgsui:exit', { code }); currentChild = null; });
156
+ currentChild.on('error', err => { send('pgsui:error', { message: String(err) }); currentChild = null; });
157
+
158
+ send('pgsui:started', { argv: fullArgv, cwd });
159
+ return { ok: true };
160
+ });
161
+
162
+ ipcMain.handle('pgsui:stop', async () => {
163
+ if (!currentChild) return { ok: false, error: 'No process running.' };
164
+ return new Promise((resolve) => {
165
+ const child = currentChild; currentChild = null;
166
+ const done = (ok, error) => resolve(ok ? { ok: true } : { ok: false, error });
167
+ try {
168
+ if (process.platform === 'win32') {
169
+ const killer = spawn('taskkill', ['/PID', String(child.pid), '/T', '/F']);
170
+ killer.on('close', (code) => done(code === 0));
171
+ } else {
172
+ child.once('close', () => done(true));
173
+ child.kill('SIGTERM');
174
+ setTimeout(() => { try { child.kill('SIGKILL'); } catch {} }, 5000);
175
+ }
176
+ } catch (e) { done(false, String(e)); }
177
+ });
178
+ });
179
+
180
+ function resolveDefaultCliPathCandidates() {
181
+ const pkgRoot = path.resolve(__dirname, '..', '..'); // <repo>/pgsui
182
+ const repoRoot = path.resolve(pkgRoot, '..'); // <repo>
183
+ return [
184
+ path.join(pkgRoot, 'cli.py'),
185
+ path.join(repoRoot, 'pgsui', 'cli.py'),
186
+ path.join(process.resourcesPath, 'pgsui', 'cli.py'),
187
+ ];
188
+ }
189
+
190
+ async function resolveDefaultCli() {
191
+ const envp = process.env.PGSUI_CLI_DEFAULT;
192
+ if (envp && fs.existsSync(envp)) return { ok: true, path: envp };
193
+ for (const pth of resolveDefaultCliPathCandidates()) {
194
+ if (fs.existsSync(pth)) return { ok: true, path: pth };
195
+ }
196
+ return { ok: false };
197
+ }
198
+
199
+
200
+ // simple single-flight guard
201
+ let dialogBusy = false;
202
+ async function withDialogMutex(fn) {
203
+ if (dialogBusy) return null;
204
+ dialogBusy = true;
205
+ try { return await fn(); }
206
+ finally { dialogBusy = false; }
207
+ }
208
+
209
+ ipcMain.handle('pick:dir', async () => withDialogMutex(async () => {
210
+ const res = await dialog.showOpenDialog({ properties: ['openDirectory'] });
211
+ return (!res.canceled && res.filePaths[0]) ? res.filePaths[0] : null;
212
+ }));
213
+
214
+ ipcMain.handle('pick:file', async (_evt, { filters }) => withDialogMutex(async () => {
215
+ const res = await dialog.showOpenDialog({
216
+ properties: ['openFile'],
217
+ filters: Array.isArray(filters) && filters.length ? filters : [{ name: 'All Files', extensions: ['*'] }],
218
+ });
219
+ return (!res.canceled && res.filePaths[0]) ? res.filePaths[0] : null;
220
+ }));
221
+
222
+ ipcMain.handle('pick:save', async (_evt, { defaultPath }) => withDialogMutex(async () => {
223
+ const res = await dialog.showSaveDialog({ defaultPath });
224
+ return (!res.canceled && res.filePath) ? res.filePath : null;
225
+ }));
226
+
227
+ ipcMain.handle('default:cli', async () => resolveDefaultCli());