reader-workbench 1.0.0__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.
- reader_workbench/__init__.py +22 -0
- reader_workbench/__main__.py +4 -0
- reader_workbench/_version.py +17 -0
- reader_workbench/api/__init__.py +74 -0
- reader_workbench/api/_record_reads.py +75 -0
- reader_workbench/api/artifacts.py +79 -0
- reader_workbench/api/facade.py +538 -0
- reader_workbench/api/models.py +285 -0
- reader_workbench/api/notebooks.py +63 -0
- reader_workbench/contracts/__init__.py +18 -0
- reader_workbench/contracts/builtins/__init__.py +36 -0
- reader_workbench/contracts/builtins/cytometry.py +140 -0
- reader_workbench/contracts/builtins/four_state_event_window.py +214 -0
- reader_workbench/contracts/builtins/generic.py +21 -0
- reader_workbench/contracts/builtins/logic.py +149 -0
- reader_workbench/contracts/builtins/plate_reader.py +47 -0
- reader_workbench/contracts/catalog.py +257 -0
- reader_workbench/contracts/model.py +109 -0
- reader_workbench/domains/__init__.py +1 -0
- reader_workbench/domains/cytometry/__init__.py +3 -0
- reader_workbench/domains/cytometry/analysis/__init__.py +29 -0
- reader_workbench/domains/cytometry/analysis/events.py +182 -0
- reader_workbench/domains/cytometry/analysis/gating.py +175 -0
- reader_workbench/domains/cytometry/analysis/workflow.py +248 -0
- reader_workbench/domains/cytometry/io/__init__.py +3 -0
- reader_workbench/domains/cytometry/io/fcs.py +135 -0
- reader_workbench/domains/cytometry/plots/__init__.py +5 -0
- reader_workbench/domains/cytometry/plots/diagnostic.py +155 -0
- reader_workbench/domains/logic/__init__.py +3 -0
- reader_workbench/domains/logic/crosstalk/__init__.py +3 -0
- reader_workbench/domains/logic/crosstalk/pairs.py +661 -0
- reader_workbench/domains/logic/four_state_vector/__init__.py +7 -0
- reader_workbench/domains/logic/four_state_vector/builder.py +321 -0
- reader_workbench/domains/logic/four_state_vector/collection/__init__.py +20 -0
- reader_workbench/domains/logic/four_state_vector/collection/checks.py +49 -0
- reader_workbench/domains/logic/four_state_vector/collection/constants.py +29 -0
- reader_workbench/domains/logic/four_state_vector/collection/model.py +19 -0
- reader_workbench/domains/logic/four_state_vector/collection/render.py +383 -0
- reader_workbench/domains/logic/four_state_vector/collection/sources.py +185 -0
- reader_workbench/domains/logic/four_state_vector/config.py +214 -0
- reader_workbench/domains/logic/four_state_vector/diagnostic.py +361 -0
- reader_workbench/domains/logic/four_state_vector/heatmap.py +86 -0
- reader_workbench/domains/logic/four_state_vector/math.py +191 -0
- reader_workbench/domains/logic/four_state_vector/reference.py +85 -0
- reader_workbench/domains/logic/four_state_vector/selection.py +228 -0
- reader_workbench/domains/logic/four_state_vector/treatment_semantics.py +51 -0
- reader_workbench/domains/logic/four_state_vector/validation.py +19 -0
- reader_workbench/domains/logic/logic_symmetry/__init__.py +3 -0
- reader_workbench/domains/logic/logic_symmetry/encodings.py +93 -0
- reader_workbench/domains/logic/logic_symmetry/extract_corners.py +192 -0
- reader_workbench/domains/logic/logic_symmetry/main.py +236 -0
- reader_workbench/domains/logic/logic_symmetry/metrics.py +96 -0
- reader_workbench/domains/logic/logic_symmetry/overlay.py +129 -0
- reader_workbench/domains/logic/logic_symmetry/prep.py +138 -0
- reader_workbench/domains/logic/logic_symmetry/render.py +356 -0
- reader_workbench/domains/logic/treatment_columns.py +42 -0
- reader_workbench/domains/plate_reader/__init__.py +1 -0
- reader_workbench/domains/plate_reader/analysis/__init__.py +14 -0
- reader_workbench/domains/plate_reader/analysis/fold_change.py +474 -0
- reader_workbench/domains/plate_reader/analysis/four_state_event_window/__init__.py +21 -0
- reader_workbench/domains/plate_reader/analysis/four_state_event_window/aggregation.py +191 -0
- reader_workbench/domains/plate_reader/analysis/four_state_event_window/contract_fields.py +50 -0
- reader_workbench/domains/plate_reader/analysis/four_state_event_window/contracts.py +320 -0
- reader_workbench/domains/plate_reader/analysis/four_state_event_window/design_dispositions.py +54 -0
- reader_workbench/domains/plate_reader/analysis/four_state_event_window/disposition_records.py +140 -0
- reader_workbench/domains/plate_reader/analysis/four_state_event_window/event_sensitivity.py +27 -0
- reader_workbench/domains/plate_reader/analysis/four_state_event_window/materialize.py +274 -0
- reader_workbench/domains/plate_reader/analysis/four_state_event_window/observation_resampling.py +97 -0
- reader_workbench/domains/plate_reader/analysis/four_state_event_window/reduction.py +62 -0
- reader_workbench/domains/plate_reader/analysis/four_state_event_window/seeds.py +15 -0
- reader_workbench/domains/plate_reader/analysis/four_state_event_window/sources.py +308 -0
- reader_workbench/domains/plate_reader/analysis/four_state_event_window/well_exclusion_validation.py +94 -0
- reader_workbench/domains/plate_reader/analysis/four_state_event_window/well_exclusions.py +54 -0
- reader_workbench/domains/plate_reader/analysis/timepoints.py +76 -0
- reader_workbench/domains/plate_reader/io/__init__.py +6 -0
- reader_workbench/domains/plate_reader/io/sample_map.py +65 -0
- reader_workbench/domains/plate_reader/io/synergy_h1/__init__.py +6 -0
- reader_workbench/domains/plate_reader/io/synergy_h1/_kinetic.py +141 -0
- reader_workbench/domains/plate_reader/io/synergy_h1/_parser.py +295 -0
- reader_workbench/domains/plate_reader/io/synergy_h1/_shared.py +195 -0
- reader_workbench/domains/plate_reader/io/synergy_h1/_snapshot.py +130 -0
- reader_workbench/domains/plate_reader/ordering.py +59 -0
- reader_workbench/domains/plate_reader/plots/__init__.py +15 -0
- reader_workbench/domains/plate_reader/plots/_data.py +29 -0
- reader_workbench/domains/plate_reader/plots/common.py +346 -0
- reader_workbench/domains/plate_reader/plots/distributions.py +324 -0
- reader_workbench/domains/plate_reader/plots/dual_reporter_triptych.py +525 -0
- reader_workbench/domains/plate_reader/plots/dual_reporter_triptych_render.py +195 -0
- reader_workbench/domains/plate_reader/plots/four_state_event_window/__init__.py +26 -0
- reader_workbench/domains/plate_reader/plots/four_state_event_window/diagnostic.py +295 -0
- reader_workbench/domains/plate_reader/plots/four_state_event_window/diagnostic_components.py +149 -0
- reader_workbench/domains/plate_reader/plots/four_state_event_window/diagnostic_render.py +308 -0
- reader_workbench/domains/plate_reader/plots/four_state_event_window/diagnostic_style.py +51 -0
- reader_workbench/domains/plate_reader/plots/four_state_event_window/schema.py +8 -0
- reader_workbench/domains/plate_reader/plots/four_state_event_window/summary.py +140 -0
- reader_workbench/domains/plate_reader/plots/grouping.py +53 -0
- reader_workbench/domains/plate_reader/plots/panels/__init__.py +12 -0
- reader_workbench/domains/plate_reader/plots/panels/snapshot.py +161 -0
- reader_workbench/domains/plate_reader/plots/panels/snapshot_data.py +91 -0
- reader_workbench/domains/plate_reader/plots/panels/time_series.py +296 -0
- reader_workbench/domains/plate_reader/plots/single_reporter_diagnostic.py +435 -0
- reader_workbench/domains/plate_reader/plots/single_reporter_diagnostic_render.py +300 -0
- reader_workbench/domains/plate_reader/plots/snapshot_barplot/__init__.py +315 -0
- reader_workbench/domains/plate_reader/plots/snapshot_barplot/planning.py +168 -0
- reader_workbench/domains/plate_reader/plots/snapshot_heatmap/__init__.py +205 -0
- reader_workbench/domains/plate_reader/plots/snapshot_heatmap/inputs.py +103 -0
- reader_workbench/domains/plate_reader/plots/time_series.py +317 -0
- reader_workbench/domains/plate_reader/plots/ts_and_snap/__init__.py +479 -0
- reader_workbench/domains/plate_reader/plots/ts_and_snap/planning.py +283 -0
- reader_workbench/domains/time_series/__init__.py +29 -0
- reader_workbench/domains/time_series/aggregation.py +60 -0
- reader_workbench/domains/time_series/contracts.py +368 -0
- reader_workbench/domains/time_series/reduction.py +395 -0
- reader_workbench/errors.py +55 -0
- reader_workbench/maintenance/__init__.py +6 -0
- reader_workbench/maintenance/docs.py +335 -0
- reader_workbench/maintenance/model.py +28 -0
- reader_workbench/maintenance/release.py +39 -0
- reader_workbench/maintenance/skills.py +124 -0
- reader_workbench/plotting/__init__.py +20 -0
- reader_workbench/plotting/mpl.py +56 -0
- reader_workbench/plotting/sinks.py +69 -0
- reader_workbench/plotting/style.py +175 -0
- reader_workbench/plotting/utils.py +27 -0
- reader_workbench/plugins/__init__.py +1 -0
- reader_workbench/plugins/catalog.py +33 -0
- reader_workbench/plugins/export/__init__.py +0 -0
- reader_workbench/plugins/export/_paths.py +21 -0
- reader_workbench/plugins/export/csv.py +41 -0
- reader_workbench/plugins/export/xlsx.py +44 -0
- reader_workbench/plugins/ingest/__init__.py +0 -0
- reader_workbench/plugins/ingest/_discovery.py +58 -0
- reader_workbench/plugins/ingest/discovery_policy.py +66 -0
- reader_workbench/plugins/ingest/flow_cytometer.py +139 -0
- reader_workbench/plugins/ingest/synergy_h1.py +234 -0
- reader_workbench/plugins/manifests/__init__.py +1 -0
- reader_workbench/plugins/manifests/export.py +29 -0
- reader_workbench/plugins/manifests/ingest.py +29 -0
- reader_workbench/plugins/manifests/plot.py +161 -0
- reader_workbench/plugins/manifests/transform.py +172 -0
- reader_workbench/plugins/manifests/validator.py +18 -0
- reader_workbench/plugins/plot/__init__.py +0 -0
- reader_workbench/plugins/plot/_shared.py +55 -0
- reader_workbench/plugins/plot/cytometry_diagnostic.py +54 -0
- reader_workbench/plugins/plot/distributions.py +58 -0
- reader_workbench/plugins/plot/dual_reporter_triptych.py +224 -0
- reader_workbench/plugins/plot/four_state_event_window_diagnostic.py +133 -0
- reader_workbench/plugins/plot/four_state_event_window_summary.py +53 -0
- reader_workbench/plugins/plot/four_state_vector_collection.py +45 -0
- reader_workbench/plugins/plot/four_state_vector_diagnostic.py +105 -0
- reader_workbench/plugins/plot/four_state_vector_heatmap.py +63 -0
- reader_workbench/plugins/plot/logic_symmetry.py +56 -0
- reader_workbench/plugins/plot/single_reporter_diagnostic.py +279 -0
- reader_workbench/plugins/plot/snapshot_barplot.py +65 -0
- reader_workbench/plugins/plot/snapshot_heatmap.py +104 -0
- reader_workbench/plugins/plot/time_series.py +114 -0
- reader_workbench/plugins/plot/ts_and_snap.py +210 -0
- reader_workbench/plugins/transform/__init__.py +0 -0
- reader_workbench/plugins/transform/_four_state_vector.py +204 -0
- reader_workbench/plugins/transform/_labeling.py +109 -0
- reader_workbench/plugins/transform/alias.py +70 -0
- reader_workbench/plugins/transform/assay_labels.py +62 -0
- reader_workbench/plugins/transform/blank.py +79 -0
- reader_workbench/plugins/transform/crosstalk_pairs.py +180 -0
- reader_workbench/plugins/transform/cytometry_gating.py +120 -0
- reader_workbench/plugins/transform/fold_change.py +79 -0
- reader_workbench/plugins/transform/four_state_event_window.py +93 -0
- reader_workbench/plugins/transform/four_state_vector.py +62 -0
- reader_workbench/plugins/transform/four_state_vector_collection.py +41 -0
- reader_workbench/plugins/transform/logic_symmetry.py +67 -0
- reader_workbench/plugins/transform/outlier_filter.py +60 -0
- reader_workbench/plugins/transform/overflow.py +197 -0
- reader_workbench/plugins/transform/ratio.py +237 -0
- reader_workbench/plugins/transform/sample_map.py +170 -0
- reader_workbench/plugins/transform/sample_metadata.py +94 -0
- reader_workbench/plugins/validator/__init__.py +1 -0
- reader_workbench/plugins/validator/to_tidy_plus_map.py +155 -0
- reader_workbench/protocols/__init__.py +80 -0
- reader_workbench/protocols/_builtins_plate_reader_growth.py +179 -0
- reader_workbench/protocols/_builtins_plate_reader_variants.py +274 -0
- reader_workbench/protocols/builtins.py +1656 -0
- reader_workbench/protocols/compiler.py +22 -0
- reader_workbench/protocols/compilers/__init__.py +1 -0
- reader_workbench/protocols/compilers/common.py +100 -0
- reader_workbench/protocols/compilers/cytometry.py +87 -0
- reader_workbench/protocols/compilers/generic.py +14 -0
- reader_workbench/protocols/compilers/logic.py +245 -0
- reader_workbench/protocols/compilers/plate_reader.py +937 -0
- reader_workbench/protocols/compilers/plate_reader_pipeline.py +197 -0
- reader_workbench/protocols/model.py +1486 -0
- reader_workbench/protocols/semantic_coverage.py +234 -0
- reader_workbench/runtime/__init__.py +12 -0
- reader_workbench/runtime/builtin.py +23 -0
- reader_workbench/runtime/model.py +42 -0
- reader_workbench/workbench/__init__.py +60 -0
- reader_workbench/workbench/assets/__init__.py +22 -0
- reader_workbench/workbench/assets/types.py +118 -0
- reader_workbench/workbench/audit/__init__.py +5 -0
- reader_workbench/workbench/audit/experiments.py +307 -0
- reader_workbench/workbench/audit/staging.py +187 -0
- reader_workbench/workbench/cli/__init__.py +51 -0
- reader_workbench/workbench/cli/_lazy.py +9 -0
- reader_workbench/workbench/cli/_records_view.py +150 -0
- reader_workbench/workbench/cli/_surface_execution.py +443 -0
- reader_workbench/workbench/cli/audit.py +95 -0
- reader_workbench/workbench/cli/automation.py +229 -0
- reader_workbench/workbench/cli/demo.py +46 -0
- reader_workbench/workbench/cli/dop.py +91 -0
- reader_workbench/workbench/cli/experiments.py +635 -0
- reader_workbench/workbench/cli/helpers.py +232 -0
- reader_workbench/workbench/cli/main.py +59 -0
- reader_workbench/workbench/cli/maintenance.py +82 -0
- reader_workbench/workbench/cli/notebooks.py +260 -0
- reader_workbench/workbench/cli/pagination.py +117 -0
- reader_workbench/workbench/cli/protocols.py +336 -0
- reader_workbench/workbench/cli/shared.py +309 -0
- reader_workbench/workbench/cli/surfaces.py +534 -0
- reader_workbench/workbench/cli/verification.py +128 -0
- reader_workbench/workbench/commands.py +10 -0
- reader_workbench/workbench/config/__init__.py +47 -0
- reader_workbench/workbench/config/identity.py +13 -0
- reader_workbench/workbench/config/load.py +405 -0
- reader_workbench/workbench/config/model.py +274 -0
- reader_workbench/workbench/context.py +26 -0
- reader_workbench/workbench/decl/__init__.py +31 -0
- reader_workbench/workbench/decl/build.py +190 -0
- reader_workbench/workbench/decl/model.py +81 -0
- reader_workbench/workbench/dop/__init__.py +12 -0
- reader_workbench/workbench/dop/builtins.py +261 -0
- reader_workbench/workbench/dop/model.py +209 -0
- reader_workbench/workbench/engine/__init__.py +42 -0
- reader_workbench/workbench/engine/_shared.py +76 -0
- reader_workbench/workbench/engine/contracts.py +283 -0
- reader_workbench/workbench/engine/execution.py +326 -0
- reader_workbench/workbench/engine/file_outputs.py +260 -0
- reader_workbench/workbench/engine/inputs.py +161 -0
- reader_workbench/workbench/engine/invocations.py +507 -0
- reader_workbench/workbench/engine/planning.py +72 -0
- reader_workbench/workbench/engine/runtime.py +464 -0
- reader_workbench/workbench/engine/setup.py +149 -0
- reader_workbench/workbench/engine/validation.py +684 -0
- reader_workbench/workbench/experiment/__init__.py +47 -0
- reader_workbench/workbench/experiment/model.py +381 -0
- reader_workbench/workbench/experiments.py +133 -0
- reader_workbench/workbench/graph/__init__.py +47 -0
- reader_workbench/workbench/graph/nodes.py +102 -0
- reader_workbench/workbench/graph/normalize.py +177 -0
- reader_workbench/workbench/graph/refs.py +148 -0
- reader_workbench/workbench/input_discovery.py +19 -0
- reader_workbench/workbench/inspection/__init__.py +3 -0
- reader_workbench/workbench/inspection/catalogs.py +128 -0
- reader_workbench/workbench/inspection/common.py +92 -0
- reader_workbench/workbench/inspection/dop.py +64 -0
- reader_workbench/workbench/inspection/experiments.py +449 -0
- reader_workbench/workbench/inspection/inventory.py +68 -0
- reader_workbench/workbench/inspection/protocols.py +368 -0
- reader_workbench/workbench/inspection/readiness.py +333 -0
- reader_workbench/workbench/inspection/reports.py +367 -0
- reader_workbench/workbench/inspection/results.py +166 -0
- reader_workbench/workbench/inspection/runtime.py +287 -0
- reader_workbench/workbench/inspection/semantics.py +192 -0
- reader_workbench/workbench/inspection/validation.py +30 -0
- reader_workbench/workbench/notebooks/__init__.py +17 -0
- reader_workbench/workbench/notebooks/_launch_registry.py +112 -0
- reader_workbench/workbench/notebooks/_launch_runtime.py +104 -0
- reader_workbench/workbench/notebooks/components/__init__.py +21 -0
- reader_workbench/workbench/notebooks/components/deliverables.py +403 -0
- reader_workbench/workbench/notebooks/components/overview.py +119 -0
- reader_workbench/workbench/notebooks/eda.marimo.py.txt +153 -0
- reader_workbench/workbench/notebooks/launch.py +274 -0
- reader_workbench/workbench/notebooks/presentation.py +136 -0
- reader_workbench/workbench/notebooks/scaffold.py +60 -0
- reader_workbench/workbench/ontology.py +78 -0
- reader_workbench/workbench/paths.py +44 -0
- reader_workbench/workbench/ports/__init__.py +31 -0
- reader_workbench/workbench/ports/model.py +168 -0
- reader_workbench/workbench/records/__init__.py +44 -0
- reader_workbench/workbench/records/epoch.py +329 -0
- reader_workbench/workbench/records/evidence.py +247 -0
- reader_workbench/workbench/records/identity.py +87 -0
- reader_workbench/workbench/records/locking.py +185 -0
- reader_workbench/workbench/records/model.py +711 -0
- reader_workbench/workbench/records/sources.py +73 -0
- reader_workbench/workbench/records/store.py +1022 -0
- reader_workbench/workbench/records/verification.py +998 -0
- reader_workbench/workbench/registry.py +333 -0
- reader_workbench/workbench/spec_overrides.py +215 -0
- reader_workbench-1.0.0.dist-info/METADATA +91 -0
- reader_workbench-1.0.0.dist-info/RECORD +293 -0
- reader_workbench-1.0.0.dist-info/WHEEL +5 -0
- reader_workbench-1.0.0.dist-info/entry_points.txt +2 -0
- reader_workbench-1.0.0.dist-info/licenses/LICENSE +21 -0
- reader_workbench-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from reader_workbench.protocols.model import ProtocolSemanticExecution, ProtocolSemanticProgram
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _semantic_program(
|
|
9
|
+
protocol: Any,
|
|
10
|
+
*,
|
|
11
|
+
overrides: dict[str, ProtocolSemanticExecution],
|
|
12
|
+
active_profile: str | None = None,
|
|
13
|
+
) -> ProtocolSemanticProgram:
|
|
14
|
+
return protocol.semantic_program(active_profile=active_profile, execution_overrides=overrides)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _plate_reader_semantic_program(
|
|
18
|
+
protocol: Any,
|
|
19
|
+
*,
|
|
20
|
+
include_crosstalk_pairs: bool,
|
|
21
|
+
include_fold_change: bool,
|
|
22
|
+
) -> ProtocolSemanticProgram:
|
|
23
|
+
active_profile = _dual_reporter_semantic_profile(
|
|
24
|
+
include_fold_change=include_fold_change,
|
|
25
|
+
include_crosstalk_pairs=include_crosstalk_pairs,
|
|
26
|
+
)
|
|
27
|
+
overrides: dict[str, ProtocolSemanticExecution] = {
|
|
28
|
+
"OD": ProtocolSemanticExecution(
|
|
29
|
+
status="compiled",
|
|
30
|
+
step_ids=("ingest",),
|
|
31
|
+
plugin_ids=("ingest/synergy_h1",),
|
|
32
|
+
record_ids=("ingest/df",),
|
|
33
|
+
note="Raw OD600 values are materialized on the ingest dataframe.",
|
|
34
|
+
),
|
|
35
|
+
}
|
|
36
|
+
overrides.update(
|
|
37
|
+
{
|
|
38
|
+
"CFP": ProtocolSemanticExecution(
|
|
39
|
+
status="compiled",
|
|
40
|
+
step_ids=("ingest",),
|
|
41
|
+
plugin_ids=("ingest/synergy_h1",),
|
|
42
|
+
record_ids=("ingest/df",),
|
|
43
|
+
note="Raw CFP values are materialized on the ingest dataframe.",
|
|
44
|
+
),
|
|
45
|
+
"YFP": ProtocolSemanticExecution(
|
|
46
|
+
status="compiled",
|
|
47
|
+
step_ids=("ingest",),
|
|
48
|
+
plugin_ids=("ingest/synergy_h1",),
|
|
49
|
+
record_ids=("ingest/df",),
|
|
50
|
+
note="Raw YFP values are materialized on the ingest dataframe.",
|
|
51
|
+
),
|
|
52
|
+
"CFP_OD": ProtocolSemanticExecution(
|
|
53
|
+
status="compiled",
|
|
54
|
+
step_ids=("ratio_cfp_od600",),
|
|
55
|
+
plugin_ids=("transform/ratio",),
|
|
56
|
+
record_ids=("ratio_cfp_od600/df",),
|
|
57
|
+
note="The CFP/OD600 support channel is materialized as a ratio step output.",
|
|
58
|
+
),
|
|
59
|
+
"YFP_OD": ProtocolSemanticExecution(
|
|
60
|
+
status="compiled",
|
|
61
|
+
step_ids=("ratio_yfp_od600",),
|
|
62
|
+
plugin_ids=("transform/ratio",),
|
|
63
|
+
record_ids=("ratio_yfp_od600/df",),
|
|
64
|
+
note="The YFP/OD600 support channel is materialized as a ratio step output.",
|
|
65
|
+
),
|
|
66
|
+
"Ratio": ProtocolSemanticExecution(
|
|
67
|
+
status="compiled",
|
|
68
|
+
step_ids=("ratio_yfp_cfp",),
|
|
69
|
+
plugin_ids=("transform/ratio",),
|
|
70
|
+
record_ids=("ratio_yfp_cfp/df",),
|
|
71
|
+
note="The primary YFP/CFP ratio is materialized as a ratio step output.",
|
|
72
|
+
),
|
|
73
|
+
}
|
|
74
|
+
)
|
|
75
|
+
if include_fold_change:
|
|
76
|
+
fold_change_step_id = "fold_change__yfp_over_cfp"
|
|
77
|
+
fold_change_record_id = "fold_change__yfp_over_cfp/table"
|
|
78
|
+
fold_change_note = "Nearest-time fold-change summaries are materialized from the primary ratio channel."
|
|
79
|
+
overrides.update(
|
|
80
|
+
{
|
|
81
|
+
"FC": ProtocolSemanticExecution(
|
|
82
|
+
status="compiled",
|
|
83
|
+
step_ids=(fold_change_step_id,),
|
|
84
|
+
plugin_ids=("transform/fold_change",),
|
|
85
|
+
record_ids=(fold_change_record_id,),
|
|
86
|
+
note=fold_change_note,
|
|
87
|
+
),
|
|
88
|
+
"log2FC": ProtocolSemanticExecution(
|
|
89
|
+
status="compiled",
|
|
90
|
+
step_ids=(fold_change_step_id,),
|
|
91
|
+
plugin_ids=("transform/fold_change",),
|
|
92
|
+
record_ids=(fold_change_record_id,),
|
|
93
|
+
note=fold_change_note,
|
|
94
|
+
),
|
|
95
|
+
}
|
|
96
|
+
)
|
|
97
|
+
if include_crosstalk_pairs:
|
|
98
|
+
overrides["ranking"] = ProtocolSemanticExecution(
|
|
99
|
+
status="compiled",
|
|
100
|
+
step_ids=("crosstalk_pairs",),
|
|
101
|
+
plugin_ids=("transform/crosstalk_pairs",),
|
|
102
|
+
record_ids=("crosstalk_pairs/table",),
|
|
103
|
+
config_paths=("protocol.analysis.crosstalk_pairs",),
|
|
104
|
+
note="When crosstalk pair analysis is enabled, pair selection is compiled from fold-change output.",
|
|
105
|
+
)
|
|
106
|
+
return _semantic_program(protocol, overrides=overrides, active_profile=active_profile)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _plate_reader_single_reporter_semantic_program(
|
|
110
|
+
protocol: Any,
|
|
111
|
+
*,
|
|
112
|
+
reporter_channel: str,
|
|
113
|
+
normalizer_channel: str,
|
|
114
|
+
include_fold_change: bool,
|
|
115
|
+
) -> ProtocolSemanticProgram:
|
|
116
|
+
ratio_label = _single_reporter_ratio_label(
|
|
117
|
+
reporter_channel=reporter_channel,
|
|
118
|
+
normalizer_channel=normalizer_channel,
|
|
119
|
+
)
|
|
120
|
+
ratio_note = f"The primary {ratio_label} ratio is materialized as a ratio step output."
|
|
121
|
+
fold_change_note = f"Nearest-time fold-change summaries are materialized from the primary {ratio_label} channel."
|
|
122
|
+
overrides: dict[str, ProtocolSemanticExecution] = {
|
|
123
|
+
"Normalizer": ProtocolSemanticExecution(
|
|
124
|
+
status="compiled",
|
|
125
|
+
step_ids=("ingest",),
|
|
126
|
+
plugin_ids=("ingest/synergy_h1",),
|
|
127
|
+
record_ids=("ingest/df",),
|
|
128
|
+
note=f"Raw {normalizer_channel} values are materialized on the ingest dataframe.",
|
|
129
|
+
),
|
|
130
|
+
"Reporter": ProtocolSemanticExecution(
|
|
131
|
+
status="compiled",
|
|
132
|
+
step_ids=("ingest",),
|
|
133
|
+
plugin_ids=("ingest/synergy_h1",),
|
|
134
|
+
record_ids=("ingest/df",),
|
|
135
|
+
note=f"Raw {reporter_channel} values are materialized on the ingest dataframe.",
|
|
136
|
+
),
|
|
137
|
+
"Reporter_Normalizer": ProtocolSemanticExecution(
|
|
138
|
+
status="compiled",
|
|
139
|
+
step_ids=("ratio_reporter_normalizer",),
|
|
140
|
+
plugin_ids=("transform/ratio",),
|
|
141
|
+
record_ids=("ratio_reporter_normalizer/df",),
|
|
142
|
+
note=ratio_note,
|
|
143
|
+
),
|
|
144
|
+
}
|
|
145
|
+
if include_fold_change:
|
|
146
|
+
overrides.update(
|
|
147
|
+
{
|
|
148
|
+
"FC": ProtocolSemanticExecution(
|
|
149
|
+
status="compiled",
|
|
150
|
+
step_ids=("fold_change__single_reporter",),
|
|
151
|
+
plugin_ids=("transform/fold_change",),
|
|
152
|
+
record_ids=("fold_change__single_reporter/table",),
|
|
153
|
+
note=fold_change_note,
|
|
154
|
+
),
|
|
155
|
+
"log2FC": ProtocolSemanticExecution(
|
|
156
|
+
status="compiled",
|
|
157
|
+
step_ids=("fold_change__single_reporter",),
|
|
158
|
+
plugin_ids=("transform/fold_change",),
|
|
159
|
+
record_ids=("fold_change__single_reporter/table",),
|
|
160
|
+
note=fold_change_note,
|
|
161
|
+
),
|
|
162
|
+
}
|
|
163
|
+
)
|
|
164
|
+
return _semantic_program(
|
|
165
|
+
protocol, overrides=overrides, active_profile=_single_reporter_semantic_profile(include_fold_change)
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _plate_reader_growth_semantic_program(
|
|
170
|
+
protocol: Any,
|
|
171
|
+
*,
|
|
172
|
+
growth_channel: str,
|
|
173
|
+
) -> ProtocolSemanticProgram:
|
|
174
|
+
return _semantic_program(
|
|
175
|
+
protocol,
|
|
176
|
+
overrides={
|
|
177
|
+
"Growth": ProtocolSemanticExecution(
|
|
178
|
+
status="compiled",
|
|
179
|
+
step_ids=("ingest",),
|
|
180
|
+
plugin_ids=("ingest/synergy_h1",),
|
|
181
|
+
record_ids=("ingest/df",),
|
|
182
|
+
note=f"Raw {growth_channel} values are materialized on the ingest dataframe.",
|
|
183
|
+
)
|
|
184
|
+
},
|
|
185
|
+
active_profile="growth_raw",
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def _logic_semantic_program(protocol: Any, *, include_four_state_vector: bool) -> ProtocolSemanticProgram:
|
|
190
|
+
overrides: dict[str, ProtocolSemanticExecution] = {}
|
|
191
|
+
if include_four_state_vector:
|
|
192
|
+
vector_binding = ProtocolSemanticExecution(
|
|
193
|
+
status="compiled",
|
|
194
|
+
step_ids=("four_state_vector",),
|
|
195
|
+
plugin_ids=("transform/four_state_vector",),
|
|
196
|
+
record_ids=("four_state_vector/vector",),
|
|
197
|
+
config_paths=(
|
|
198
|
+
"protocol.inputs.reference",
|
|
199
|
+
"protocol.inputs.design_by",
|
|
200
|
+
"protocol.inputs.state_map_ref",
|
|
201
|
+
"protocol.inputs.time_mode",
|
|
202
|
+
"protocol.inputs.target_time_h",
|
|
203
|
+
"protocol.inputs.time_tolerance_h",
|
|
204
|
+
),
|
|
205
|
+
note="The four-state vector transform materializes the protocol control rule, summary window, and measurement vector.",
|
|
206
|
+
)
|
|
207
|
+
overrides.update(
|
|
208
|
+
{
|
|
209
|
+
"logic_corner_map": vector_binding,
|
|
210
|
+
"summary_timepoint": vector_binding,
|
|
211
|
+
"four_state_vector": vector_binding,
|
|
212
|
+
}
|
|
213
|
+
)
|
|
214
|
+
return _semantic_program(protocol, overrides=overrides)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def _cytometry_semantic_program(protocol: Any) -> ProtocolSemanticProgram:
|
|
218
|
+
return _semantic_program(protocol, overrides={})
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def _dual_reporter_semantic_profile(*, include_fold_change: bool, include_crosstalk_pairs: bool) -> str:
|
|
222
|
+
if include_crosstalk_pairs:
|
|
223
|
+
return "yfp_cfp_crosstalk"
|
|
224
|
+
if include_fold_change:
|
|
225
|
+
return "yfp_cfp_fold_change"
|
|
226
|
+
return "yfp_cfp_raw"
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def _single_reporter_semantic_profile(include_fold_change: bool) -> str:
|
|
230
|
+
return "single_reporter_fold_change" if include_fold_change else "single_reporter_raw"
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def _single_reporter_ratio_label(*, reporter_channel: str, normalizer_channel: str) -> str:
|
|
234
|
+
return f"{reporter_channel}/{normalizer_channel}"
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from importlib import import_module
|
|
4
|
+
|
|
5
|
+
from .model import ReaderRuntime
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def builtin_runtime() -> ReaderRuntime:
|
|
9
|
+
return import_module("reader_workbench.runtime.builtin").builtin_runtime()
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
__all__ = ["ReaderRuntime", "builtin_runtime"]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from functools import cache
|
|
4
|
+
|
|
5
|
+
from reader_workbench.contracts import builtin_contract_catalog
|
|
6
|
+
from reader_workbench.plotting.mpl import ensure_mpl_cache_dir
|
|
7
|
+
from reader_workbench.plugins.catalog import builtin_plugin_descriptors
|
|
8
|
+
from reader_workbench.protocols.builtins import builtin_protocol_catalog
|
|
9
|
+
from reader_workbench.workbench.registry import load_plugin_catalog
|
|
10
|
+
|
|
11
|
+
from .model import ReaderRuntime
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@cache
|
|
15
|
+
def builtin_runtime() -> ReaderRuntime:
|
|
16
|
+
ensure_mpl_cache_dir()
|
|
17
|
+
contracts = builtin_contract_catalog()
|
|
18
|
+
protocols = builtin_protocol_catalog()
|
|
19
|
+
plugins = load_plugin_catalog(
|
|
20
|
+
contracts=contracts,
|
|
21
|
+
builtin_descriptors=builtin_plugin_descriptors(),
|
|
22
|
+
)
|
|
23
|
+
return ReaderRuntime(contracts=contracts, protocols=protocols, plugins=plugins)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from importlib import import_module
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from reader_workbench.contracts import ContractCatalog
|
|
10
|
+
from reader_workbench.protocols.model import BoundProtocol, ProtocolBinding, ProtocolCatalog
|
|
11
|
+
from reader_workbench.workbench.records.store import RecordStore
|
|
12
|
+
from reader_workbench.workbench.registry import Registry
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass(frozen=True)
|
|
16
|
+
class ReaderRuntime:
|
|
17
|
+
"""Single composed runtime for contracts, protocols, plugins, and record stores."""
|
|
18
|
+
|
|
19
|
+
contracts: ContractCatalog
|
|
20
|
+
protocols: ProtocolCatalog
|
|
21
|
+
plugins: Registry
|
|
22
|
+
|
|
23
|
+
def bind_protocol(self, binding: ProtocolBinding) -> BoundProtocol:
|
|
24
|
+
return self.protocols.bind(binding)
|
|
25
|
+
|
|
26
|
+
def record_store(
|
|
27
|
+
self,
|
|
28
|
+
outputs_dir: Path,
|
|
29
|
+
*,
|
|
30
|
+
plots_subdir: str | None = "plots",
|
|
31
|
+
exports_subdir: str | None = "exports",
|
|
32
|
+
experiment_root: Path | None = None,
|
|
33
|
+
create: bool = True,
|
|
34
|
+
) -> RecordStore:
|
|
35
|
+
return import_module("reader_workbench.workbench.records.store").RecordStore(
|
|
36
|
+
outputs_dir,
|
|
37
|
+
contracts=self.contracts,
|
|
38
|
+
plots_subdir=plots_subdir,
|
|
39
|
+
exports_subdir=exports_subdir,
|
|
40
|
+
experiment_root=experiment_root,
|
|
41
|
+
create=create,
|
|
42
|
+
)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import importlib
|
|
4
|
+
|
|
5
|
+
_EXPORTS = {
|
|
6
|
+
"graph": {
|
|
7
|
+
"FileRef",
|
|
8
|
+
"InputRef",
|
|
9
|
+
"OutputRef",
|
|
10
|
+
"PluginStep",
|
|
11
|
+
"ProvenanceInput",
|
|
12
|
+
"RecipeSource",
|
|
13
|
+
"RecordRef",
|
|
14
|
+
"ResourceRef",
|
|
15
|
+
"Workbench",
|
|
16
|
+
"ensure_unique_workbench_ids",
|
|
17
|
+
"input_ref_display",
|
|
18
|
+
"input_ref_from_dict",
|
|
19
|
+
"input_ref_to_dict",
|
|
20
|
+
"materialize_workbench",
|
|
21
|
+
"output_ref_display",
|
|
22
|
+
"output_ref_from_dict",
|
|
23
|
+
"output_ref_to_dict",
|
|
24
|
+
"provenance_input_from_dict",
|
|
25
|
+
"provenance_input_to_dict",
|
|
26
|
+
"resolve_workbench",
|
|
27
|
+
"select_workbench_specs",
|
|
28
|
+
},
|
|
29
|
+
"ontology": {
|
|
30
|
+
"PluginCategory",
|
|
31
|
+
"PluginSemantics",
|
|
32
|
+
"WorkbenchItemKind",
|
|
33
|
+
"WorkbenchPluginStepKind",
|
|
34
|
+
"WorkbenchProducerKind",
|
|
35
|
+
"WorkbenchRecordKind",
|
|
36
|
+
"WorkbenchSurfaceSemantics",
|
|
37
|
+
"get_workbench_surface_semantics",
|
|
38
|
+
},
|
|
39
|
+
"records": {
|
|
40
|
+
"DataFrameArtifactRecord",
|
|
41
|
+
"FileBundleRecord",
|
|
42
|
+
"RecordProducer",
|
|
43
|
+
"RecordRecipeSource",
|
|
44
|
+
"RecordStore",
|
|
45
|
+
"WorkbenchRecord",
|
|
46
|
+
"record_from_dict",
|
|
47
|
+
"record_paths",
|
|
48
|
+
"record_to_dict",
|
|
49
|
+
},
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
__all__ = tuple(sorted({name for names in _EXPORTS.values() for name in names}))
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def __getattr__(name: str):
|
|
56
|
+
for module_name, names in _EXPORTS.items():
|
|
57
|
+
if name in names:
|
|
58
|
+
module = importlib.import_module(f"reader_workbench.workbench.{module_name}")
|
|
59
|
+
return getattr(module, name)
|
|
60
|
+
raise AttributeError(name)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import importlib
|
|
4
|
+
|
|
5
|
+
_EXPORTS = {
|
|
6
|
+
"types": {
|
|
7
|
+
"AssetCatalog",
|
|
8
|
+
"AssetDescriptor",
|
|
9
|
+
"build_plugin_asset",
|
|
10
|
+
"plugin_category_from_id",
|
|
11
|
+
},
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
__all__ = tuple(sorted({name for names in _EXPORTS.values() for name in names}))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def __getattr__(name: str):
|
|
18
|
+
for module_name, names in _EXPORTS.items():
|
|
19
|
+
if name in names:
|
|
20
|
+
module = importlib.import_module(f"reader_workbench.workbench.assets.{module_name}")
|
|
21
|
+
return getattr(module, name)
|
|
22
|
+
raise AttributeError(name)
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Any, cast
|
|
5
|
+
|
|
6
|
+
from reader_workbench.errors import ConfigError
|
|
7
|
+
from reader_workbench.workbench.ontology import (
|
|
8
|
+
PluginCategory,
|
|
9
|
+
PluginDomain,
|
|
10
|
+
PluginSemantics,
|
|
11
|
+
validate_plugin_domain,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass(frozen=True)
|
|
16
|
+
class AssetDescriptor:
|
|
17
|
+
name: str
|
|
18
|
+
domain: PluginDomain
|
|
19
|
+
family: str
|
|
20
|
+
summary: str
|
|
21
|
+
plugin_cls: type[Any]
|
|
22
|
+
tags: tuple[str, ...] = ()
|
|
23
|
+
|
|
24
|
+
def __post_init__(self) -> None:
|
|
25
|
+
object.__setattr__(self, "domain", validate_plugin_domain(self.domain))
|
|
26
|
+
if not isinstance(self.name, str) or not self.name.strip():
|
|
27
|
+
raise ValueError("AssetDescriptor.name must be a non-empty string.")
|
|
28
|
+
plugin_category_from_id(self.name)
|
|
29
|
+
if not isinstance(self.plugin_cls, type):
|
|
30
|
+
raise ValueError(f"Plugin asset {self.name!r} must declare a plugin class.")
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def plugin(self) -> str:
|
|
34
|
+
return self.name
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def plugin_id(self) -> str:
|
|
38
|
+
return self.plugin
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def key(self) -> str:
|
|
42
|
+
return self.name.split("/", 1)[1] if "/" in self.name else self.name
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def category(self) -> PluginCategory:
|
|
46
|
+
return plugin_category_from_id(self.name)
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def cls(self) -> type[Any]:
|
|
50
|
+
return self.plugin_cls
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class AssetCatalog:
|
|
54
|
+
def __init__(self, descriptors: list[AssetDescriptor]):
|
|
55
|
+
self._descriptors = tuple(sorted(descriptors, key=lambda item: (item.domain, item.family, item.name)))
|
|
56
|
+
by_name: dict[str, AssetDescriptor] = {}
|
|
57
|
+
for item in self._descriptors:
|
|
58
|
+
if item.name in by_name:
|
|
59
|
+
raise ConfigError(f"Duplicate plugin {item.name!r}.")
|
|
60
|
+
by_name[item.name] = item
|
|
61
|
+
self._by_name = by_name
|
|
62
|
+
|
|
63
|
+
def all(self) -> tuple[AssetDescriptor, ...]:
|
|
64
|
+
return self._descriptors
|
|
65
|
+
|
|
66
|
+
def filter(
|
|
67
|
+
self,
|
|
68
|
+
*,
|
|
69
|
+
category: str | None = None,
|
|
70
|
+
domain: str | None = None,
|
|
71
|
+
family: str | None = None,
|
|
72
|
+
tag: str | None = None,
|
|
73
|
+
) -> tuple[AssetDescriptor, ...]:
|
|
74
|
+
return tuple(
|
|
75
|
+
descriptor
|
|
76
|
+
for descriptor in self._descriptors
|
|
77
|
+
if (category is None or descriptor.category == category)
|
|
78
|
+
and (domain is None or descriptor.domain == domain)
|
|
79
|
+
and (family is None or descriptor.family == family)
|
|
80
|
+
and (tag is None or tag in descriptor.tags)
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
def resolve(self, name: str) -> AssetDescriptor:
|
|
84
|
+
try:
|
|
85
|
+
return self._by_name[name]
|
|
86
|
+
except KeyError:
|
|
87
|
+
opts = ", ".join(sorted(item.name for item in self._descriptors))
|
|
88
|
+
raise ConfigError(f"Unknown plugin {name!r}. Available plugins: {opts}") from None
|
|
89
|
+
|
|
90
|
+
def list(
|
|
91
|
+
self,
|
|
92
|
+
*,
|
|
93
|
+
domain: str | None = None,
|
|
94
|
+
family: str | None = None,
|
|
95
|
+
) -> list[tuple[str, str]]:
|
|
96
|
+
items = self.filter(domain=domain, family=family)
|
|
97
|
+
return [(item.name, item.summary) for item in items]
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def plugin_category_from_id(plugin_id: str) -> PluginCategory:
|
|
101
|
+
if not isinstance(plugin_id, str) or "/" not in plugin_id:
|
|
102
|
+
raise ValueError(f"Plugin id must be 'category/key', got {plugin_id!r}")
|
|
103
|
+
category = plugin_id.split("/", 1)[0]
|
|
104
|
+
if category not in {"ingest", "transform", "plot", "export", "validator"}:
|
|
105
|
+
raise ValueError(f"Unknown plugin category {category!r} in plugin id {plugin_id!r}")
|
|
106
|
+
return cast(PluginCategory, category)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def build_plugin_asset(*, plugin_id: str, semantics: PluginSemantics, plugin_cls: type[Any]) -> AssetDescriptor:
|
|
110
|
+
plugin_category_from_id(plugin_id)
|
|
111
|
+
return AssetDescriptor(
|
|
112
|
+
name=plugin_id,
|
|
113
|
+
domain=semantics.domain,
|
|
114
|
+
family=semantics.family,
|
|
115
|
+
summary=semantics.summary,
|
|
116
|
+
plugin_cls=plugin_cls,
|
|
117
|
+
tags=tuple(semantics.tags),
|
|
118
|
+
)
|