lobster-transcriptomics 1.2.0__tar.gz → 1.2.1__tar.gz
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.
- {lobster_transcriptomics-1.2.0/lobster_transcriptomics.egg-info → lobster_transcriptomics-1.2.1}/PKG-INFO +1 -1
- {lobster_transcriptomics-1.2.0 → lobster_transcriptomics-1.2.1}/lobster/agents/transcriptomics/annotation_expert.py +6 -0
- {lobster_transcriptomics-1.2.0 → lobster_transcriptomics-1.2.1}/lobster/agents/transcriptomics/de_analysis_expert.py +67 -14
- {lobster_transcriptomics-1.2.0 → lobster_transcriptomics-1.2.1}/lobster/agents/transcriptomics/prompts.py +55 -2
- {lobster_transcriptomics-1.2.0 → lobster_transcriptomics-1.2.1}/lobster/agents/transcriptomics/shared_tools.py +152 -38
- {lobster_transcriptomics-1.2.0 → lobster_transcriptomics-1.2.1}/lobster/agents/transcriptomics/transcriptomics_expert.py +132 -27
- {lobster_transcriptomics-1.2.0 → lobster_transcriptomics-1.2.1}/lobster/services/analysis/enhanced_singlecell_service.py +186 -100
- {lobster_transcriptomics-1.2.0 → lobster_transcriptomics-1.2.1}/lobster/services/quality/preprocessing_service.py +54 -17
- {lobster_transcriptomics-1.2.0 → lobster_transcriptomics-1.2.1}/lobster/services/quality/quality_service.py +42 -0
- {lobster_transcriptomics-1.2.0 → lobster_transcriptomics-1.2.1/lobster_transcriptomics.egg-info}/PKG-INFO +1 -1
- {lobster_transcriptomics-1.2.0 → lobster_transcriptomics-1.2.1}/pyproject.toml +1 -1
- {lobster_transcriptomics-1.2.0 → lobster_transcriptomics-1.2.1}/LICENSE +0 -0
- {lobster_transcriptomics-1.2.0 → lobster_transcriptomics-1.2.1}/README.md +0 -0
- {lobster_transcriptomics-1.2.0 → lobster_transcriptomics-1.2.1}/lobster/agents/transcriptomics/__init__.py +0 -0
- {lobster_transcriptomics-1.2.0 → lobster_transcriptomics-1.2.1}/lobster/agents/transcriptomics/config.py +0 -0
- {lobster_transcriptomics-1.2.0 → lobster_transcriptomics-1.2.1}/lobster/agents/transcriptomics/py.typed +0 -0
- {lobster_transcriptomics-1.2.0 → lobster_transcriptomics-1.2.1}/lobster/agents/transcriptomics/state.py +0 -0
- {lobster_transcriptomics-1.2.0 → lobster_transcriptomics-1.2.1}/lobster/figure_template_providers/sc.py +0 -0
- {lobster_transcriptomics-1.2.0 → lobster_transcriptomics-1.2.1}/lobster/services/analysis/bulk_preprocessing_service.py +0 -0
- {lobster_transcriptomics-1.2.0 → lobster_transcriptomics-1.2.1}/lobster/services/analysis/differential_formula_service.py +0 -0
- {lobster_transcriptomics-1.2.0 → lobster_transcriptomics-1.2.1}/lobster/services/analysis/pseudobulk_service.py +0 -0
- {lobster_transcriptomics-1.2.0 → lobster_transcriptomics-1.2.1}/lobster/services/metadata/manual_annotation_service.py +0 -0
- {lobster_transcriptomics-1.2.0 → lobster_transcriptomics-1.2.1}/lobster/services/templates/annotation_templates.py +0 -0
- {lobster_transcriptomics-1.2.0 → lobster_transcriptomics-1.2.1}/lobster/services/visualization/bulk_visualization_service.py +0 -0
- {lobster_transcriptomics-1.2.0 → lobster_transcriptomics-1.2.1}/lobster_transcriptomics.egg-info/SOURCES.txt +0 -0
- {lobster_transcriptomics-1.2.0 → lobster_transcriptomics-1.2.1}/lobster_transcriptomics.egg-info/dependency_links.txt +0 -0
- {lobster_transcriptomics-1.2.0 → lobster_transcriptomics-1.2.1}/lobster_transcriptomics.egg-info/entry_points.txt +0 -0
- {lobster_transcriptomics-1.2.0 → lobster_transcriptomics-1.2.1}/lobster_transcriptomics.egg-info/requires.txt +0 -0
- {lobster_transcriptomics-1.2.0 → lobster_transcriptomics-1.2.1}/lobster_transcriptomics.egg-info/top_level.txt +0 -0
- {lobster_transcriptomics-1.2.0 → lobster_transcriptomics-1.2.1}/setup.cfg +0 -0
|
@@ -54,6 +54,7 @@ from lobster.config.inference_context import (
|
|
|
54
54
|
from lobster.config.llm_factory import create_llm
|
|
55
55
|
from lobster.config.settings import get_settings
|
|
56
56
|
from lobster.core.component_registry import component_registry
|
|
57
|
+
from lobster.core.export_scope import WORKSPACE_EXPORT_MESSAGE, outside_workspace
|
|
57
58
|
from lobster.core.figures.export_guard import MANAGED_EXPORT_MESSAGE, export_refused
|
|
58
59
|
from lobster.core.runtime.data_manager import DataManagerV2
|
|
59
60
|
from lobster.services.analysis.enhanced_singlecell_service import (
|
|
@@ -1067,12 +1068,17 @@ def annotation_expert(
|
|
|
1067
1068
|
output_path = Path(output_filename)
|
|
1068
1069
|
if not output_path.is_absolute():
|
|
1069
1070
|
output_path = data_manager.exports_dir / output_path
|
|
1071
|
+
# The destination stays inside the workspace (or a listed export root).
|
|
1072
|
+
if outside_workspace(data_manager.workspace_path, output_path):
|
|
1073
|
+
return WORKSPACE_EXPORT_MESSAGE
|
|
1070
1074
|
# Figures are saved only through the trusted save step: check the
|
|
1071
1075
|
# caller's (unresolved) destination before anything is created.
|
|
1072
1076
|
if export_refused(data_manager.workspace_path, output_path):
|
|
1073
1077
|
return MANAGED_EXPORT_MESSAGE
|
|
1074
1078
|
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
1075
1079
|
output_filename = str(output_path.resolve())
|
|
1080
|
+
if outside_workspace(data_manager.workspace_path, output_filename):
|
|
1081
|
+
return WORKSPACE_EXPORT_MESSAGE
|
|
1076
1082
|
if export_refused(
|
|
1077
1083
|
data_manager.workspace_path, output_path, output_filename
|
|
1078
1084
|
):
|
|
@@ -53,6 +53,15 @@ from lobster.core import (
|
|
|
53
53
|
InsufficientCellsError,
|
|
54
54
|
PseudobulkError,
|
|
55
55
|
)
|
|
56
|
+
from lobster.core.export_scope import (
|
|
57
|
+
WORKSPACE_EXPORT_MESSAGE,
|
|
58
|
+
InvalidModalityNameError,
|
|
59
|
+
WorkspaceExportError,
|
|
60
|
+
assert_inside_workspace,
|
|
61
|
+
check_modality_name,
|
|
62
|
+
outside_workspace,
|
|
63
|
+
plain_name_part,
|
|
64
|
+
)
|
|
56
65
|
from lobster.core.figures.errors import ManagedPathError
|
|
57
66
|
from lobster.core.figures.export_dirs import assert_dirs_allowed
|
|
58
67
|
from lobster.core.figures.export_guard import (
|
|
@@ -89,6 +98,15 @@ _BULK_SERVICE_SETUP = (
|
|
|
89
98
|
)
|
|
90
99
|
|
|
91
100
|
|
|
101
|
+
def _de_result_name(modality_name: str, group1, group2) -> str:
|
|
102
|
+
"""The DE result modality name: group labels are data values, so each is encoded
|
|
103
|
+
as part of one plain name (two labels never collide); refused (fixed reason)
|
|
104
|
+
before any analysis if the name is still not plain, for example too long."""
|
|
105
|
+
return check_modality_name(
|
|
106
|
+
f"{modality_name}_de_{plain_name_part(group1)}_vs_{plain_name_part(group2)}"
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
|
|
92
110
|
def _is_pseudobulk(adata) -> bool:
|
|
93
111
|
"""True when the modality carries a pseudobulk or formula design (``uns`` only)."""
|
|
94
112
|
return (
|
|
@@ -1174,21 +1192,26 @@ def de_analysis_expert(
|
|
|
1174
1192
|
# Get the modality
|
|
1175
1193
|
adata = data_manager.get_modality(modality_name)
|
|
1176
1194
|
|
|
1195
|
+
# The result name carries the group labels (data values, which may hold
|
|
1196
|
+
# '/'): encoded into one plain name, checked before any analysis.
|
|
1197
|
+
de_modality_name = None
|
|
1198
|
+
if not (_is_pseudobulk(adata) and method == "deseq2"):
|
|
1199
|
+
de_modality_name = _de_result_name(modality_name, group1, group2)
|
|
1200
|
+
|
|
1177
1201
|
# Every save target of the branch that will run is checked before the
|
|
1178
1202
|
# data changes or any analysis runs.
|
|
1179
1203
|
if save_result:
|
|
1180
1204
|
if _is_pseudobulk(adata) and method == "deseq2":
|
|
1181
|
-
|
|
1182
|
-
data_manager.
|
|
1183
|
-
data_manager.exports_dir / f"{modality_name}_de_results.csv",
|
|
1205
|
+
results_csv = (
|
|
1206
|
+
data_manager.exports_dir / f"{modality_name}_de_results.csv"
|
|
1184
1207
|
)
|
|
1208
|
+
assert_inside_workspace(data_manager.workspace_path, results_csv)
|
|
1209
|
+
assert_export_allowed(data_manager.workspace_path, results_csv)
|
|
1185
1210
|
data_manager._assert_save_allowed(
|
|
1186
1211
|
f"{modality_name}_with_de_results.h5ad"
|
|
1187
1212
|
)
|
|
1188
1213
|
else:
|
|
1189
|
-
data_manager._assert_save_allowed(
|
|
1190
|
-
f"{modality_name}_de_{group1}_vs_{group2}.h5ad"
|
|
1191
|
-
)
|
|
1214
|
+
data_manager._assert_save_allowed(f"{de_modality_name}.h5ad")
|
|
1192
1215
|
|
|
1193
1216
|
logger.info(
|
|
1194
1217
|
f"Running DE analysis on '{modality_name}': "
|
|
@@ -1404,8 +1427,7 @@ def de_analysis_expert(
|
|
|
1404
1427
|
de_stats["de_results_key"],
|
|
1405
1428
|
"adata_de" if internal_method == "deseq2_like" else "adata",
|
|
1406
1429
|
)
|
|
1407
|
-
# Save as new modality
|
|
1408
|
-
de_modality_name = f"{modality_name}_de_{group1}_vs_{group2}"
|
|
1430
|
+
# Save as new modality (name derived and checked before the analysis)
|
|
1409
1431
|
data_manager.store_modality(
|
|
1410
1432
|
name=de_modality_name,
|
|
1411
1433
|
adata=adata_de,
|
|
@@ -1414,7 +1436,7 @@ def de_analysis_expert(
|
|
|
1414
1436
|
)
|
|
1415
1437
|
|
|
1416
1438
|
if save_result:
|
|
1417
|
-
save_path = f"{
|
|
1439
|
+
save_path = f"{de_modality_name}.h5ad"
|
|
1418
1440
|
data_manager.save_modality(de_modality_name, save_path)
|
|
1419
1441
|
|
|
1420
1442
|
data_manager.log_tool_usage(
|
|
@@ -1471,6 +1493,12 @@ def de_analysis_expert(
|
|
|
1471
1493
|
analysis_results["details"]["differential_expression"] = response
|
|
1472
1494
|
return response
|
|
1473
1495
|
|
|
1496
|
+
except WorkspaceExportError:
|
|
1497
|
+
# A save target is outside the workspace: nothing was saved.
|
|
1498
|
+
return WORKSPACE_EXPORT_MESSAGE
|
|
1499
|
+
except InvalidModalityNameError as e:
|
|
1500
|
+
# The derived result name is not one plain name (fixed reason).
|
|
1501
|
+
return f"Error: {e}"
|
|
1474
1502
|
except ManagedPathError:
|
|
1475
1503
|
# A save target is inside the managed figure folder: nothing was saved.
|
|
1476
1504
|
return MANAGED_EXPORT_MESSAGE
|
|
@@ -1989,11 +2017,12 @@ def de_analysis_expert(
|
|
|
1989
2017
|
|
|
1990
2018
|
# Both save targets are checked before any analysis or store.
|
|
1991
2019
|
if save_results:
|
|
1992
|
-
|
|
1993
|
-
data_manager.workspace_path,
|
|
2020
|
+
formula_csv = (
|
|
1994
2021
|
data_manager.exports_dir
|
|
1995
|
-
/ f"{pseudobulk_modality}_formula_de_results.csv"
|
|
2022
|
+
/ f"{pseudobulk_modality}_formula_de_results.csv"
|
|
1996
2023
|
)
|
|
2024
|
+
assert_inside_workspace(data_manager.workspace_path, formula_csv)
|
|
2025
|
+
assert_export_allowed(data_manager.workspace_path, formula_csv)
|
|
1997
2026
|
data_manager._assert_save_allowed(
|
|
1998
2027
|
f"{pseudobulk_modality}_with_formula_results.h5ad"
|
|
1999
2028
|
)
|
|
@@ -2192,6 +2221,9 @@ def de_analysis_expert(
|
|
|
2192
2221
|
|
|
2193
2222
|
return response
|
|
2194
2223
|
|
|
2224
|
+
except WorkspaceExportError:
|
|
2225
|
+
# A save target is outside the workspace: nothing was saved.
|
|
2226
|
+
return WORKSPACE_EXPORT_MESSAGE
|
|
2195
2227
|
except ManagedPathError:
|
|
2196
2228
|
# A save target is inside the managed figure folder: nothing was saved.
|
|
2197
2229
|
return MANAGED_EXPORT_MESSAGE
|
|
@@ -3034,6 +3066,9 @@ def de_analysis_expert(
|
|
|
3034
3066
|
output_path_obj = Path(output_path)
|
|
3035
3067
|
if not output_path_obj.is_absolute():
|
|
3036
3068
|
output_path_obj = data_manager.exports_dir / output_path_obj
|
|
3069
|
+
# The destination stays inside the workspace (or a listed export root).
|
|
3070
|
+
if outside_workspace(data_manager.workspace_path, output_path_obj):
|
|
3071
|
+
return WORKSPACE_EXPORT_MESSAGE
|
|
3037
3072
|
# Figures are saved only through the trusted save step: check the
|
|
3038
3073
|
# caller's (unresolved) destination, and every folder its recursive
|
|
3039
3074
|
# creation can make, before anything is created.
|
|
@@ -3045,6 +3080,8 @@ def de_analysis_expert(
|
|
|
3045
3080
|
return MANAGED_EXPORT_MESSAGE
|
|
3046
3081
|
output_path_obj.parent.mkdir(parents=True, exist_ok=True)
|
|
3047
3082
|
output_path = str(output_path_obj.resolve())
|
|
3083
|
+
if outside_workspace(data_manager.workspace_path, output_path):
|
|
3084
|
+
return WORKSPACE_EXPORT_MESSAGE
|
|
3048
3085
|
if export_refused(
|
|
3049
3086
|
data_manager.workspace_path, output_path_obj, output_path
|
|
3050
3087
|
):
|
|
@@ -3189,6 +3226,9 @@ def de_analysis_expert(
|
|
|
3189
3226
|
if group2 not in available_groups_str:
|
|
3190
3227
|
return f"Group '{group2}' not found in '{group_key}'. Available: {available_groups}"
|
|
3191
3228
|
|
|
3229
|
+
# The result name carries the group labels: encoded and checked first.
|
|
3230
|
+
de_modality_name = _de_result_name(modality_name, group1, group2)
|
|
3231
|
+
|
|
3192
3232
|
# Ensure string type matching
|
|
3193
3233
|
if group1 not in available_groups:
|
|
3194
3234
|
adata.obs[group_key] = adata.obs[group_key].astype(str)
|
|
@@ -3223,8 +3263,7 @@ def de_analysis_expert(
|
|
|
3223
3263
|
if refusal:
|
|
3224
3264
|
return refusal
|
|
3225
3265
|
adata_de.uns["de_current_results_key"] = de_stats["de_results_key"]
|
|
3226
|
-
# Store result modality
|
|
3227
|
-
de_modality_name = f"{modality_name}_de_{group1}_vs_{group2}"
|
|
3266
|
+
# Store result modality (name derived and checked before the analysis)
|
|
3228
3267
|
data_manager.store_modality(
|
|
3229
3268
|
name=de_modality_name,
|
|
3230
3269
|
adata=adata_de,
|
|
@@ -3320,6 +3359,9 @@ def de_analysis_expert(
|
|
|
3320
3359
|
|
|
3321
3360
|
return response
|
|
3322
3361
|
|
|
3362
|
+
except InvalidModalityNameError as e:
|
|
3363
|
+
# The derived result name is not one plain name (fixed reason).
|
|
3364
|
+
return f"Error: {e}"
|
|
3323
3365
|
except (BulkRNASeqError, ModalityNotFoundError) as e:
|
|
3324
3366
|
logger.error(f"Error in bulk DE direct: {e}")
|
|
3325
3367
|
return f"Error in bulk DE analysis: {str(e)}"
|
|
@@ -3688,12 +3730,19 @@ def de_analysis_expert(
|
|
|
3688
3730
|
targets = [output_path_obj]
|
|
3689
3731
|
if output_format == "xlsx":
|
|
3690
3732
|
targets.append(Path(str(output_path_obj).replace(".xlsx", ".csv")))
|
|
3733
|
+
# Every target stays inside the workspace (or a listed export root).
|
|
3734
|
+
if outside_workspace(data_manager.workspace_path, *targets):
|
|
3735
|
+
return WORKSPACE_EXPORT_MESSAGE
|
|
3691
3736
|
if export_refused(data_manager.workspace_path, *targets):
|
|
3692
3737
|
return MANAGED_EXPORT_MESSAGE
|
|
3693
3738
|
if output_format == "xlsx":
|
|
3694
3739
|
# ...and the name exactly as the late fallback derives it; a path
|
|
3695
3740
|
# that cannot be resolved is refused with the same fixed message.
|
|
3696
3741
|
fallback = _resolved_csv_fallback(output_path_obj)
|
|
3742
|
+
if fallback is not None and outside_workspace(
|
|
3743
|
+
data_manager.workspace_path, fallback
|
|
3744
|
+
):
|
|
3745
|
+
return WORKSPACE_EXPORT_MESSAGE
|
|
3697
3746
|
if fallback is None or export_refused(
|
|
3698
3747
|
data_manager.workspace_path, fallback
|
|
3699
3748
|
):
|
|
@@ -3705,6 +3754,8 @@ def de_analysis_expert(
|
|
|
3705
3754
|
return MANAGED_EXPORT_MESSAGE
|
|
3706
3755
|
output_path_obj.parent.mkdir(parents=True, exist_ok=True)
|
|
3707
3756
|
output_path = str(output_path_obj.resolve())
|
|
3757
|
+
if outside_workspace(data_manager.workspace_path, output_path):
|
|
3758
|
+
return WORKSPACE_EXPORT_MESSAGE
|
|
3708
3759
|
if export_refused(data_manager.workspace_path, *targets, output_path):
|
|
3709
3760
|
return MANAGED_EXPORT_MESSAGE
|
|
3710
3761
|
|
|
@@ -3714,6 +3765,8 @@ def de_analysis_expert(
|
|
|
3714
3765
|
except ImportError:
|
|
3715
3766
|
output_format = "csv"
|
|
3716
3767
|
output_path = output_path.replace(".xlsx", ".csv")
|
|
3768
|
+
if outside_workspace(data_manager.workspace_path, output_path):
|
|
3769
|
+
return WORKSPACE_EXPORT_MESSAGE
|
|
3717
3770
|
if export_refused(data_manager.workspace_path, output_path):
|
|
3718
3771
|
return MANAGED_EXPORT_MESSAGE
|
|
3719
3772
|
results_df.to_csv(output_path, index=True)
|
|
@@ -144,8 +144,8 @@ Do NOT describe delegation, do NOT ask permission -- execute the tool call.
|
|
|
144
144
|
4. select_variable_features("modality_filtered_normalized") # HVG/deviance selection
|
|
145
145
|
5. run_pca("modality_..._hvg_selected") # PCA reduction
|
|
146
146
|
6. integrate_batches("modality_..._pca", batch_key="...") # If multi-sample
|
|
147
|
-
7. compute_neighbors_and_embed("
|
|
148
|
-
8. cluster_cells("
|
|
147
|
+
7. compute_neighbors_and_embed("chosen_prepared_modality", use_rep="actual_obsm_key") # Use returned representation key
|
|
148
|
+
8. cluster_cells("chosen_prepared_modality", use_rep="actual_obsm_key", batch_correction=False, resolution=0.5) # Reuse; do not rerun upstream
|
|
149
149
|
9. find_marker_genes("modality_clustered", groupby="leiden") # Cluster markers
|
|
150
150
|
10. handoff_to_annotation_expert(...) # If annotation requested
|
|
151
151
|
```
|
|
@@ -153,6 +153,23 @@ Do NOT describe delegation, do NOT ask permission -- execute the tool call.
|
|
|
153
153
|
NOTE: cluster_cells can also perform steps 4-9 automatically as a full pipeline.
|
|
154
154
|
Use composable tools when user asks for specific steps; use cluster_cells for full pipeline.
|
|
155
155
|
|
|
156
|
+
**Prepared clustering contract:** If the caller already prepared PCA, explicitly name
|
|
157
|
+
that modality and use_rep='X_pca'; pass requested n_neighbors/n_pcs. Only the first
|
|
158
|
+
n_pcs components are used. Do not repeat normalization, HVG selection, scaling or PCA.
|
|
159
|
+
A modality name suffix is not evidence that an embedding exists or is scientifically
|
|
160
|
+
fresh: inspect actual obsm keys. Missing/incompatible representations or unhonorable
|
|
161
|
+
explicit dimensions require refusal, not a silent full-pipeline fallback or clamp.
|
|
162
|
+
For **HVG-only** prepared data without PCA, call composable run_pca on the named
|
|
163
|
+
selected modality first, then cluster its returned modality with use_rep='X_pca'.
|
|
164
|
+
Disclose that PCA was computed, not reused. Unset clustering dimensions resolve the
|
|
165
|
+
ordinary 15/30; dimension-driven implicit adjustments must be disclosed. Explicit
|
|
166
|
+
values are never demo-capped. Read actual applied-parameter JSON and recorded IR,
|
|
167
|
+
not schema/request values, when reporting what ran. Never fabricate an applied HVG
|
|
168
|
+
feature count/flavor: full-pipeline exact HVG requests are unsupported; use the
|
|
169
|
+
explicit selection/PCA/reuse workflow. Prepared reuse skips unrequested batch
|
|
170
|
+
correction and says why; explicit batch correction AND a named prepared representation
|
|
171
|
+
refuse together. If correction is needed, do it before preparing/naming the representation.
|
|
172
|
+
|
|
156
173
|
## Bulk Standard Workflow (6 steps)
|
|
157
174
|
|
|
158
175
|
```
|
|
@@ -210,6 +227,36 @@ Report: data_type, n_genes, n_cells/n_samples, mito_pct, n_filtered, cluster_siz
|
|
|
210
227
|
If batch_silhouette > 0.3 or median_lisi < 1.5, flag for re-integration.
|
|
211
228
|
</Response_Format>
|
|
212
229
|
|
|
230
|
+
<Scientific_Reporting_Contract>
|
|
231
|
+
- Report dataset-specific numbers only from tool output for the stated cohort. Never infer
|
|
232
|
+
medians, percentiles, exceedance counts or filtering impact from means/default pass counts.
|
|
233
|
+
- If a requested value is absent, say NOT COMPUTED and offer to compute it; "~" is not evidence.
|
|
234
|
+
- Pass requested thresholds unchanged. Report applied parameters from the tool's actual result,
|
|
235
|
+
not from the user's request, a standard workflow or an earlier modality's configuration.
|
|
236
|
+
- Requested-but-unsupported parameters or extra operations: refuse or explicitly state NOT
|
|
237
|
+
SUPPORTED; never claim they were applied. Exact requests take precedence over default workflows.
|
|
238
|
+
- Report every actually applied filter, including explicit optional-filter disabled states.
|
|
239
|
+
Criterion failures are independent on the original pre-filter cohort: do not sum them.
|
|
240
|
+
Report combined actual removals separately, and distinguish gene counts from observation counts.
|
|
241
|
+
- State the real raw-count storage location returned by the tool. adata.raw is not a counts layer.
|
|
242
|
+
- The supervisor must preserve these numeric/cohort/applied-parameter limitations when reformulating.
|
|
243
|
+
- SC markers: original ranked genes, specificity-filtered candidates and FDR-significant genes
|
|
244
|
+
are different sets. Use the tool's explicit original/filtered/display keys, executed groups
|
|
245
|
+
and aligned counts; never label original rankings as filtered or automatically significant.
|
|
246
|
+
- Disclose actual Scanpy specificity operators/units: positive log2FC > min_fold_change,
|
|
247
|
+
in-group fraction > min_pct, out-group fraction < max_out_pct, compare_abs=False.
|
|
248
|
+
The legacy 1.5 threshold is log2FC, not linear fold-change. No FDR criterion is applied there.
|
|
249
|
+
- Supported adjusted p-values must be interpreted using an explicitly stated criterion.
|
|
250
|
+
Absent statistics are NOT COMPUTED, not zero discoveries; nonfinite values are separate flags.
|
|
251
|
+
Finite extreme abs(log2FC) flags use the tool's diagnostic threshold, without clipping,
|
|
252
|
+
reranking or a significance claim. Near-zero reference expression
|
|
253
|
+
can amplify Scanpy's approximate effect size; an extreme value alone proves neither a
|
|
254
|
+
statistical effect nor a computation error.
|
|
255
|
+
- Cell-level cluster-versus-rest markers are exploratory. Single-donor cells are not independent
|
|
256
|
+
donor replicates and do not establish patient/condition effects; require a biological-unit
|
|
257
|
+
design before such claims. Do not infer uncomputed donor counts from the dataset name.
|
|
258
|
+
</Scientific_Reporting_Contract>
|
|
259
|
+
|
|
213
260
|
<Important_Rules>
|
|
214
261
|
1. **ALWAYS call check_data_status() first** to understand data type and column names
|
|
215
262
|
2. **NEVER assume column names** (leiden, batch, etc.) -- always verify via check_data_status
|
|
@@ -387,6 +434,12 @@ You report results back to the parent agent, not directly to users.
|
|
|
387
434
|
- One donor per condition cannot support a statistical comparison (pseudoreplication): refuse the DE and explain why, even when that donor has several libraries
|
|
388
435
|
- LFC shrinkage is recommended for publication (use extract_and_export_de_results with shrink_lfc=True)
|
|
389
436
|
- GSEA requires sufficient DE genes; run after run_differential_expression, run_de_with_formula, or run_bulk_de_direct
|
|
437
|
+
- Interpretation: ranked, specificity-filtered and FDR-significant genes are distinct sets.
|
|
438
|
+
Name the exact results key and actually applied adjusted-p criterion before claiming
|
|
439
|
+
significance; a large absolute log2FC alone is insufficient. Absent statistics are
|
|
440
|
+
NOT COMPUTED, not zero discoveries; flag nonfinite values separately without changing them.
|
|
441
|
+
- Do not turn exploratory single-donor cell-level cluster markers into patient/condition
|
|
442
|
+
effects. Independent biological units and an appropriate design remain required.
|
|
390
443
|
</Critical_Scientific_Requirements>
|
|
391
444
|
|
|
392
445
|
<Available_Tools>
|