pg-sui 0.2.3__py3-none-any.whl → 1.6.14.dev9__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 (127) hide show
  1. {pg_sui-0.2.3.dist-info → pg_sui-1.6.14.dev9.dist-info}/METADATA +99 -77
  2. pg_sui-1.6.14.dev9.dist-info/RECORD +81 -0
  3. {pg_sui-0.2.3.dist-info → pg_sui-1.6.14.dev9.dist-info}/WHEEL +1 -1
  4. pg_sui-1.6.14.dev9.dist-info/entry_points.txt +4 -0
  5. {pg_sui-0.2.3.dist-info → pg_sui-1.6.14.dev9.dist-info/licenses}/LICENSE +0 -0
  6. pg_sui-1.6.14.dev9.dist-info/top_level.txt +1 -0
  7. pgsui/__init__.py +35 -54
  8. pgsui/_version.py +34 -0
  9. pgsui/cli.py +909 -0
  10. pgsui/data_processing/__init__.py +0 -0
  11. pgsui/data_processing/config.py +565 -0
  12. pgsui/data_processing/containers.py +1424 -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 +1118 -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 +1285 -0
  65. pgsui/impute/unsupervised/imputers/nlpca.py +1554 -0
  66. pgsui/impute/unsupervised/imputers/ubp.py +1575 -0
  67. pgsui/impute/unsupervised/imputers/vae.py +1228 -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/RECORD +0 -75
  83. pg_sui-0.2.3.dist-info/top_level.txt +0 -3
  84. pgsui/example_data/phylip_files/test_n10.phy +0 -118
  85. pgsui/example_data/phylip_files/test_n100.phy +0 -118
  86. pgsui/example_data/phylip_files/test_n2.phy +0 -118
  87. pgsui/example_data/phylip_files/test_n500.phy +0 -118
  88. pgsui/example_data/structure_files/test.nopops.1row.10sites.str +0 -117
  89. pgsui/example_data/structure_files/test.nopops.2row.100sites.str +0 -234
  90. pgsui/example_data/structure_files/test.nopops.2row.10sites.str +0 -234
  91. pgsui/example_data/structure_files/test.nopops.2row.30sites.str +0 -234
  92. pgsui/example_data/structure_files/test.nopops.2row.allsites.str +0 -234
  93. pgsui/example_data/structure_files/test.pops.1row.10sites.str +0 -117
  94. pgsui/example_data/structure_files/test.pops.2row.10sites.str +0 -234
  95. pgsui/example_data/trees/test.iqtree +0 -376
  96. pgsui/example_data/trees/test.qmat +0 -5
  97. pgsui/example_data/trees/test.rate +0 -2033
  98. pgsui/example_data/trees/test.tre +0 -1
  99. pgsui/example_data/trees/test_n10.rate +0 -19
  100. pgsui/example_data/trees/test_n100.rate +0 -109
  101. pgsui/example_data/trees/test_n500.rate +0 -509
  102. pgsui/example_data/trees/test_siterates.txt +0 -2024
  103. pgsui/example_data/trees/test_siterates_n10.txt +0 -10
  104. pgsui/example_data/trees/test_siterates_n100.txt +0 -100
  105. pgsui/example_data/trees/test_siterates_n500.txt +0 -500
  106. pgsui/example_data/vcf_files/test.vcf +0 -244
  107. pgsui/example_data/vcf_files/test.vcf.gz +0 -0
  108. pgsui/example_data/vcf_files/test.vcf.gz.tbi +0 -0
  109. pgsui/impute/estimators.py +0 -1268
  110. pgsui/impute/impute.py +0 -1463
  111. pgsui/impute/simple_imputers.py +0 -1431
  112. pgsui/impute/supervised/iterative_imputer_fixedparams.py +0 -782
  113. pgsui/impute/supervised/iterative_imputer_gridsearch.py +0 -1024
  114. pgsui/impute/unsupervised/keras_classifiers.py +0 -697
  115. pgsui/impute/unsupervised/models/in_development/cnn_model.py +0 -486
  116. pgsui/impute/unsupervised/neural_network_imputers.py +0 -1440
  117. pgsui/impute/unsupervised/neural_network_methods.py +0 -1395
  118. pgsui/pg_sui.py +0 -261
  119. pgsui/utils/sequence_tools.py +0 -407
  120. simulation/sim_benchmarks.py +0 -333
  121. simulation/sim_treeparams.py +0 -475
  122. test/__init__.py +0 -0
  123. test/pg_sui_simtest.py +0 -215
  124. test/pg_sui_testing.py +0 -523
  125. test/test.py +0 -151
  126. test/test_pgsui.py +0 -374
  127. 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());