M3Drop 0.4.58__py3-none-any.whl → 0.4.60__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.
- m3Drop/CoreCPU.py +26 -7
- m3Drop/CoreGPU.py +21 -4
- m3Drop/DiagnosticsCPU.py +39 -5
- m3Drop/DiagnosticsGPU.py +40 -8
- m3Drop/NormalizationCPU.py +13 -2
- m3Drop/NormalizationGPU.py +5 -4
- {m3drop-0.4.58.dist-info → m3drop-0.4.60.dist-info}/METADATA +1 -1
- m3drop-0.4.60.dist-info/RECORD +14 -0
- m3drop-0.4.58.dist-info/RECORD +0 -14
- {m3drop-0.4.58.dist-info → m3drop-0.4.60.dist-info}/WHEEL +0 -0
- {m3drop-0.4.58.dist-info → m3drop-0.4.60.dist-info}/licenses/LICENSE +0 -0
- {m3drop-0.4.58.dist-info → m3drop-0.4.60.dist-info}/top_level.txt +0 -0
m3Drop/CoreCPU.py
CHANGED
|
@@ -22,10 +22,19 @@ from scipy.stats import norm
|
|
|
22
22
|
from scipy import sparse
|
|
23
23
|
from statsmodels.stats.multitest import multipletests
|
|
24
24
|
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
|
|
25
|
+
# ==========================================
|
|
26
|
+
# HYBRID IMPORT (PACKAGE VS LOCAL)
|
|
27
|
+
# ==========================================
|
|
28
|
+
try:
|
|
29
|
+
# Case 1: Running as an installed package
|
|
30
|
+
from .ControlDeviceCPU import ControlDevice
|
|
31
|
+
except ImportError:
|
|
32
|
+
# Case 2: Running locally
|
|
33
|
+
try:
|
|
34
|
+
from ControlDeviceCPU import ControlDevice
|
|
35
|
+
except ImportError:
|
|
36
|
+
print("CRITICAL ERROR: 'ControlDeviceCPU.py' not found.")
|
|
37
|
+
sys.exit(1)
|
|
29
38
|
|
|
30
39
|
# ==========================================
|
|
31
40
|
# NUMBA KERNELS (CPU OPTIMIZED)
|
|
@@ -323,9 +332,17 @@ def NBumiFitDispVsMeanCPU(fit: dict, suppress_plot=True):
|
|
|
323
332
|
tjs = vals['tjs'].values
|
|
324
333
|
mean_expression = tjs / vals['nc']
|
|
325
334
|
|
|
326
|
-
|
|
335
|
+
# [FIX] Filter out the 10,000 imputation values.
|
|
336
|
+
# We treat 10,000 as an error code for "Under-Dispersed/Poissonian".
|
|
337
|
+
# Masking these prevents artificial gravity from pulling the regression line up.
|
|
338
|
+
forfit = (np.isfinite(size_g)) & \
|
|
339
|
+
(size_g < 9999.0) & \
|
|
340
|
+
(mean_expression > 1e-3) & \
|
|
341
|
+
(size_g > 0)
|
|
342
|
+
|
|
327
343
|
log2_mean_expr = np.log2(mean_expression, where=(mean_expression > 0))
|
|
328
344
|
|
|
345
|
+
# Heuristic: If we have enough high-expression genes, focus fit there
|
|
329
346
|
higher = log2_mean_expr > 4
|
|
330
347
|
if np.sum(higher & forfit) > 2000:
|
|
331
348
|
forfit = higher & forfit
|
|
@@ -338,8 +355,10 @@ def NBumiFitDispVsMeanCPU(fit: dict, suppress_plot=True):
|
|
|
338
355
|
|
|
339
356
|
if not suppress_plot:
|
|
340
357
|
plt.figure(figsize=(7, 6))
|
|
341
|
-
|
|
342
|
-
plt.
|
|
358
|
+
# Plot ALL points (grey) vs FITTED points (blue)
|
|
359
|
+
plt.scatter(np.log(mean_expression), np.log(size_g), alpha=0.3, s=1, c='grey', label='All Genes')
|
|
360
|
+
plt.scatter(x, y, alpha=0.5, s=1, c='blue', label='Used for Fit')
|
|
361
|
+
plt.plot(x, model.fittedvalues, color='red', label='Regression Fit')
|
|
343
362
|
plt.show()
|
|
344
363
|
|
|
345
364
|
return model.params
|
m3Drop/CoreGPU.py
CHANGED
|
@@ -22,8 +22,19 @@ import matplotlib.pyplot as plt
|
|
|
22
22
|
from scipy.stats import norm
|
|
23
23
|
from statsmodels.stats.multitest import multipletests
|
|
24
24
|
|
|
25
|
-
#
|
|
26
|
-
|
|
25
|
+
# ==========================================
|
|
26
|
+
# HYBRID IMPORT (PACKAGE VS LOCAL)
|
|
27
|
+
# ==========================================
|
|
28
|
+
try:
|
|
29
|
+
# Case 1: Running as an installed package (e.g. import m3drop.CoreGPU)
|
|
30
|
+
from .ControlDeviceGPU import ControlDevice
|
|
31
|
+
except ImportError:
|
|
32
|
+
# Case 2: Running locally (e.g. python CoreGPU.py)
|
|
33
|
+
try:
|
|
34
|
+
from ControlDeviceGPU import ControlDevice
|
|
35
|
+
except ImportError:
|
|
36
|
+
print("CRITICAL ERROR: 'ControlDeviceGPU.py' not found.")
|
|
37
|
+
sys.exit(1)
|
|
27
38
|
|
|
28
39
|
# ==========================================
|
|
29
40
|
# FUSED KERNELS
|
|
@@ -313,9 +324,14 @@ def NBumiFitDispVsMeanGPU(fit: dict, suppress_plot=True):
|
|
|
313
324
|
tjs = vals['tjs'].values
|
|
314
325
|
mean_expression = tjs / vals['nc']
|
|
315
326
|
|
|
316
|
-
forfit = (np.isfinite(size_g)) &
|
|
327
|
+
forfit = (np.isfinite(size_g)) & \
|
|
328
|
+
(size_g < 9999.0) & \
|
|
329
|
+
(mean_expression > 1e-3) & \
|
|
330
|
+
(size_g > 0)
|
|
331
|
+
|
|
317
332
|
log2_mean_expr = np.log2(mean_expression, where=(mean_expression > 0))
|
|
318
333
|
|
|
334
|
+
# Heuristic: If we have enough high-expression genes, focus fit there
|
|
319
335
|
higher = log2_mean_expr > 4
|
|
320
336
|
if np.sum(higher & forfit) > 2000:
|
|
321
337
|
forfit = higher & forfit
|
|
@@ -328,7 +344,8 @@ def NBumiFitDispVsMeanGPU(fit: dict, suppress_plot=True):
|
|
|
328
344
|
|
|
329
345
|
if not suppress_plot:
|
|
330
346
|
plt.figure(figsize=(7, 6))
|
|
331
|
-
|
|
347
|
+
# Visual check only - code below handles the production plot
|
|
348
|
+
plt.scatter(x, y, alpha=0.5, s=1, c='blue')
|
|
332
349
|
plt.plot(x, model.fittedvalues, color='red')
|
|
333
350
|
plt.show()
|
|
334
351
|
|
m3Drop/DiagnosticsCPU.py
CHANGED
|
@@ -4,6 +4,7 @@ import matplotlib.pyplot as plt
|
|
|
4
4
|
import h5py
|
|
5
5
|
import os
|
|
6
6
|
import time
|
|
7
|
+
import sys
|
|
7
8
|
import pickle
|
|
8
9
|
import gc
|
|
9
10
|
from scipy import sparse
|
|
@@ -14,9 +15,29 @@ import statsmodels.api as sm
|
|
|
14
15
|
from scipy.stats import norm
|
|
15
16
|
from statsmodels.stats.multitest import multipletests
|
|
16
17
|
|
|
17
|
-
#
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
# ==========================================
|
|
19
|
+
# HYBRID IMPORT (PACKAGE VS LOCAL)
|
|
20
|
+
# ==========================================
|
|
21
|
+
|
|
22
|
+
# [FIX] Hybrid Import: ControlDeviceCPU
|
|
23
|
+
try:
|
|
24
|
+
from .ControlDeviceCPU import ControlDevice
|
|
25
|
+
except ImportError:
|
|
26
|
+
try:
|
|
27
|
+
from ControlDeviceCPU import ControlDevice
|
|
28
|
+
except ImportError:
|
|
29
|
+
print("CRITICAL ERROR: 'ControlDeviceCPU.py' not found.")
|
|
30
|
+
sys.exit(1)
|
|
31
|
+
|
|
32
|
+
# [FIX] Hybrid Import: CoreCPU
|
|
33
|
+
try:
|
|
34
|
+
from .CoreCPU import hidden_calc_valsCPU, NBumiFitModelCPU, NBumiFitDispVsMeanCPU, dropout_prob_kernel_cpu
|
|
35
|
+
except ImportError:
|
|
36
|
+
try:
|
|
37
|
+
from CoreCPU import hidden_calc_valsCPU, NBumiFitModelCPU, NBumiFitDispVsMeanCPU, dropout_prob_kernel_cpu
|
|
38
|
+
except ImportError:
|
|
39
|
+
print("CRITICAL ERROR: 'CoreCPU.py' not found.")
|
|
40
|
+
sys.exit(1)
|
|
20
41
|
|
|
21
42
|
# ==========================================
|
|
22
43
|
# DIAGNOSTICS & COMPARISON (CPU)
|
|
@@ -244,7 +265,7 @@ def NBumiCompareModelsCPU(
|
|
|
244
265
|
stats: dict,
|
|
245
266
|
fit_adjust: dict,
|
|
246
267
|
mask_filename: str = None,
|
|
247
|
-
mode: str = "auto",
|
|
268
|
+
mode: str = "auto",
|
|
248
269
|
manual_target: int = 3000,
|
|
249
270
|
suppress_plot=False,
|
|
250
271
|
plot_filename=None
|
|
@@ -365,9 +386,11 @@ def NBumiPlotDispVsMeanCPU(
|
|
|
365
386
|
mean_expression = fit['vals']['tjs'].values / fit['vals']['nc']
|
|
366
387
|
sizes = fit['sizes'].values
|
|
367
388
|
|
|
389
|
+
# 1. Get calibrated coefficients (using the fixed CoreCPU logic)
|
|
368
390
|
coeffs = NBumiFitDispVsMeanCPU(fit, suppress_plot=True)
|
|
369
391
|
intercept, slope = coeffs[0], coeffs[1]
|
|
370
392
|
|
|
393
|
+
# 2. Calculate the regression line
|
|
371
394
|
log_mean_expr_range = np.linspace(
|
|
372
395
|
np.log(mean_expression[mean_expression > 0].min()),
|
|
373
396
|
np.log(mean_expression.max()),
|
|
@@ -376,8 +399,19 @@ def NBumiPlotDispVsMeanCPU(
|
|
|
376
399
|
log_fitted_sizes = intercept + slope * log_mean_expr_range
|
|
377
400
|
fitted_sizes = np.exp(log_fitted_sizes)
|
|
378
401
|
|
|
402
|
+
# 3. [FIX] Mask the 10k outliers for the SCATTER PLOT
|
|
403
|
+
# We create a visualization mask to hide the distracting "roof" at y=10000
|
|
404
|
+
mask_viz = (sizes < 9999.0) & (sizes > 0)
|
|
405
|
+
|
|
406
|
+
mean_expr_clean = mean_expression[mask_viz]
|
|
407
|
+
sizes_clean = sizes[mask_viz]
|
|
408
|
+
|
|
379
409
|
plt.figure(figsize=(8, 6))
|
|
380
|
-
|
|
410
|
+
|
|
411
|
+
# Plot only the clean data
|
|
412
|
+
plt.scatter(mean_expr_clean, sizes_clean, label='Observed Dispersion', alpha=0.5, s=8)
|
|
413
|
+
|
|
414
|
+
# Plot the regression line (calculated correctly via CoreCPU)
|
|
381
415
|
plt.plot(np.exp(log_mean_expr_range), fitted_sizes, color='red', label='Regression Fit', linewidth=2)
|
|
382
416
|
|
|
383
417
|
plt.xscale('log')
|
m3Drop/DiagnosticsGPU.py
CHANGED
|
@@ -9,17 +9,36 @@ import time
|
|
|
9
9
|
import pickle
|
|
10
10
|
import psutil
|
|
11
11
|
import gc
|
|
12
|
+
import sys
|
|
12
13
|
from scipy import sparse
|
|
13
14
|
from scipy import stats
|
|
14
15
|
import anndata
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
# ==========================================
|
|
18
|
+
# HYBRID IMPORT (PACKAGE VS LOCAL)
|
|
19
|
+
# ==========================================
|
|
20
|
+
try:
|
|
21
|
+
# Case 1: Package
|
|
22
|
+
from .ControlDeviceGPU import ControlDevice
|
|
23
|
+
from .CoreGPU import (
|
|
24
|
+
hidden_calc_valsGPU,
|
|
25
|
+
NBumiFitModelGPU,
|
|
26
|
+
NBumiFitDispVsMeanGPU,
|
|
27
|
+
dropout_prob_kernel
|
|
28
|
+
)
|
|
29
|
+
except ImportError:
|
|
30
|
+
# Case 2: Local
|
|
31
|
+
try:
|
|
32
|
+
from ControlDeviceGPU import ControlDevice
|
|
33
|
+
from CoreGPU import (
|
|
34
|
+
hidden_calc_valsGPU,
|
|
35
|
+
NBumiFitModelGPU,
|
|
36
|
+
NBumiFitDispVsMeanGPU,
|
|
37
|
+
dropout_prob_kernel
|
|
38
|
+
)
|
|
39
|
+
except ImportError:
|
|
40
|
+
print("CRITICAL ERROR: Dependencies (ControlDeviceGPU, CoreGPU) not found.")
|
|
41
|
+
sys.exit(1)
|
|
23
42
|
|
|
24
43
|
from cupy.sparse import csr_matrix as cp_csr_matrix
|
|
25
44
|
import scipy.sparse as sp
|
|
@@ -385,9 +404,11 @@ def NBumiPlotDispVsMeanGPU(
|
|
|
385
404
|
mean_expression = fit['vals']['tjs'].values / fit['vals']['nc']
|
|
386
405
|
sizes = fit['sizes'].values
|
|
387
406
|
|
|
407
|
+
# 1. Get calibrated coefficients (using the fixed CoreGPU logic)
|
|
388
408
|
coeffs = NBumiFitDispVsMeanGPU(fit, suppress_plot=True)
|
|
389
409
|
intercept, slope = coeffs[0], coeffs[1]
|
|
390
410
|
|
|
411
|
+
# 2. Calculate the regression line
|
|
391
412
|
log_mean_expr_range = np.linspace(
|
|
392
413
|
np.log(mean_expression[mean_expression > 0].min()),
|
|
393
414
|
np.log(mean_expression.max()),
|
|
@@ -396,8 +417,19 @@ def NBumiPlotDispVsMeanGPU(
|
|
|
396
417
|
log_fitted_sizes = intercept + slope * log_mean_expr_range
|
|
397
418
|
fitted_sizes = np.exp(log_fitted_sizes)
|
|
398
419
|
|
|
420
|
+
# 3. [FIX] Mask the 10k outliers for the SCATTER PLOT
|
|
421
|
+
# We create a visualization mask to hide the distracting "roof" at y=10000
|
|
422
|
+
mask_viz = (sizes < 9999.0) & (sizes > 0)
|
|
423
|
+
|
|
424
|
+
mean_expr_clean = mean_expression[mask_viz]
|
|
425
|
+
sizes_clean = sizes[mask_viz]
|
|
426
|
+
|
|
399
427
|
plt.figure(figsize=(8, 6))
|
|
400
|
-
|
|
428
|
+
|
|
429
|
+
# Plot only the clean data
|
|
430
|
+
plt.scatter(mean_expr_clean, sizes_clean, label='Observed Dispersion', alpha=0.5, s=8)
|
|
431
|
+
|
|
432
|
+
# Plot the regression line (which was calculated correctly via CoreGPU)
|
|
401
433
|
plt.plot(np.exp(log_mean_expr_range), fitted_sizes, color='red', label='Regression Fit', linewidth=2)
|
|
402
434
|
|
|
403
435
|
plt.xscale('log')
|
m3Drop/NormalizationCPU.py
CHANGED
|
@@ -16,8 +16,19 @@ except ImportError:
|
|
|
16
16
|
print("CRITICAL ERROR: 'numba' not found. Please install it (pip install numba).")
|
|
17
17
|
sys.exit(1)
|
|
18
18
|
|
|
19
|
-
#
|
|
20
|
-
|
|
19
|
+
# ==========================================
|
|
20
|
+
# HYBRID IMPORT (PACKAGE VS LOCAL)
|
|
21
|
+
# ==========================================
|
|
22
|
+
try:
|
|
23
|
+
# Case 1: Running as an installed package
|
|
24
|
+
from .ControlDeviceCPU import ControlDevice
|
|
25
|
+
except ImportError:
|
|
26
|
+
# Case 2: Running locally
|
|
27
|
+
try:
|
|
28
|
+
from ControlDeviceCPU import ControlDevice
|
|
29
|
+
except ImportError:
|
|
30
|
+
print("CRITICAL ERROR: 'ControlDeviceCPU.py' not found.")
|
|
31
|
+
sys.exit(1)
|
|
21
32
|
|
|
22
33
|
# ==========================================
|
|
23
34
|
# NUMBA KERNELS (CPU)
|
m3Drop/NormalizationGPU.py
CHANGED
|
@@ -18,10 +18,14 @@ except ImportError:
|
|
|
18
18
|
cupy = None
|
|
19
19
|
HAS_GPU = False
|
|
20
20
|
|
|
21
|
-
#
|
|
21
|
+
# ==========================================
|
|
22
|
+
# HYBRID IMPORT (PACKAGE VS LOCAL)
|
|
23
|
+
# ==========================================
|
|
22
24
|
try:
|
|
25
|
+
# Case 1: Package
|
|
23
26
|
from .ControlDeviceGPU import ControlDevice
|
|
24
27
|
except ImportError:
|
|
28
|
+
# Case 2: Local
|
|
25
29
|
try:
|
|
26
30
|
from ControlDeviceGPU import ControlDevice
|
|
27
31
|
except ImportError:
|
|
@@ -367,6 +371,3 @@ def NBumiPearsonResidualsCombinedGPU(
|
|
|
367
371
|
|
|
368
372
|
if hasattr(adata_in, "file") and adata_in.file is not None: adata_in.file.close()
|
|
369
373
|
print(f"Total time: {time.perf_counter() - start_time:.2f} seconds.\n")
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
m3Drop/ControlDeviceCPU.py,sha256=8P-hxd4thc2wSeon73b9rz3clIGkE3x0cEE82RiGFds,8880
|
|
2
|
+
m3Drop/ControlDeviceGPU.py,sha256=4nzPtgyV0RsEOeezwCVJ7oyDOsp9-dRVLczlduUocpU,9143
|
|
3
|
+
m3Drop/CoreCPU.py,sha256=EVGh6JFka-PlUHF034z6UOjKsmMdjWJxP0a4Sg1mq4M,19475
|
|
4
|
+
m3Drop/CoreGPU.py,sha256=e-dZhtQgRmOdy6Ill_X9YaLEM7GXOWu4R8VO7SNkr8E,20439
|
|
5
|
+
m3Drop/DiagnosticsCPU.py,sha256=CjuP773llDZuvll3xl0Yjl1BAxMx5vDZY9P4tM-kHyE,14072
|
|
6
|
+
m3Drop/DiagnosticsGPU.py,sha256=qWtH0lGaWwTxaY-7c5oDA2gJff_y0-r18-RqarWZz7E,15521
|
|
7
|
+
m3Drop/NormalizationCPU.py,sha256=Qfj2IRMQyxkvJaAlbH9_H6SMFIWs_UCw3LhY2mOTFSA,13038
|
|
8
|
+
m3Drop/NormalizationGPU.py,sha256=FJLzfYdEB96v9OXld64FZO7r5_M9AU00OSuSlaM0ThY,15541
|
|
9
|
+
m3Drop/__init__.py,sha256=W_TQ9P8_7Tdsa6kDZ6IJKT0FMkX_JFvBqiP821CZIrk,2180
|
|
10
|
+
m3drop-0.4.60.dist-info/licenses/LICENSE,sha256=44Iqpp8Fc10Xzd5T7cT9UhO31Qftk3gBiCjtpwilP_k,1074
|
|
11
|
+
m3drop-0.4.60.dist-info/METADATA,sha256=FDFnoP0RnBjbl0gLkJNsEWcdIUkJwDLtIv9kYQbW9gA,5248
|
|
12
|
+
m3drop-0.4.60.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
13
|
+
m3drop-0.4.60.dist-info/top_level.txt,sha256=AEULFEFIgFtAwS-KBlIFoYXrqczX_rwqrEcdK46GIrA,7
|
|
14
|
+
m3drop-0.4.60.dist-info/RECORD,,
|
m3drop-0.4.58.dist-info/RECORD
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
m3Drop/ControlDeviceCPU.py,sha256=8P-hxd4thc2wSeon73b9rz3clIGkE3x0cEE82RiGFds,8880
|
|
2
|
-
m3Drop/ControlDeviceGPU.py,sha256=4nzPtgyV0RsEOeezwCVJ7oyDOsp9-dRVLczlduUocpU,9143
|
|
3
|
-
m3Drop/CoreCPU.py,sha256=csRg5TLQx1Sup7k3lDJm9OO5Oe5-1aC3u_6ldE_GIX8,18679
|
|
4
|
-
m3Drop/CoreGPU.py,sha256=6LToLuWyHxX_7sC2z0Xnvy_qqgmpew5DmnCV0PxmTZQ,19785
|
|
5
|
-
m3Drop/DiagnosticsCPU.py,sha256=l0Imkh3F3zo4ovihUjx7cYWYgzPdztWCN1hcBFO43nY,12943
|
|
6
|
-
m3Drop/DiagnosticsGPU.py,sha256=bsatHyHszgbufneeJvFvHBTLzDuY006nP2yHPHs8s7M,14389
|
|
7
|
-
m3Drop/NormalizationCPU.py,sha256=_YQtKG1UkmY34LHSGkeOmPju5esTv2-qZiG6-_ade7I,12656
|
|
8
|
-
m3Drop/NormalizationGPU.py,sha256=Vk3Tend1BcNnMKuReEgztWSBo1-F1kVk34O9z4ebAM0,15399
|
|
9
|
-
m3Drop/__init__.py,sha256=W_TQ9P8_7Tdsa6kDZ6IJKT0FMkX_JFvBqiP821CZIrk,2180
|
|
10
|
-
m3drop-0.4.58.dist-info/licenses/LICENSE,sha256=44Iqpp8Fc10Xzd5T7cT9UhO31Qftk3gBiCjtpwilP_k,1074
|
|
11
|
-
m3drop-0.4.58.dist-info/METADATA,sha256=B8V0jyIuOsViRAeluilVmMYePDH-2azDpmdVm6Ovab0,5248
|
|
12
|
-
m3drop-0.4.58.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
13
|
-
m3drop-0.4.58.dist-info/top_level.txt,sha256=AEULFEFIgFtAwS-KBlIFoYXrqczX_rwqrEcdK46GIrA,7
|
|
14
|
-
m3drop-0.4.58.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|