plexora 0.0.1__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.
- plexora/__init__.py +129 -0
- plexora/__main__.py +15 -0
- plexora/_url.py +105 -0
- plexora/api/__init__.py +55 -0
- plexora/api/dataset.py +398 -0
- plexora/api/http.py +19 -0
- plexora/api/plugin.py +541 -0
- plexora/api/store.py +221 -0
- plexora/cli.py +777 -0
- plexora/client/dist/354_bundle.js +2 -0
- plexora/client/dist/354_bundle.js.LICENSE.txt +20 -0
- plexora/client/dist/418_bundle.js +2 -0
- plexora/client/dist/418_bundle.js.LICENSE.txt +1 -0
- plexora/client/dist/693b935cb1f907814be9c6199a68c217.svg +19 -0
- plexora/client/dist/713c134ff47cd328a5b711526f151082.svg +18 -0
- plexora/client/dist/770_bundle.js +1 -0
- plexora/client/dist/ff743f408972e0e96ca9153ed5ae4c83.svg +23 -0
- plexora/client/dist/vendor_bundle.js +2 -0
- plexora/client/dist/vendor_bundle.js.LICENSE.txt +308 -0
- plexora/client/external/openseadragon-bin-2.4.0/LICENSE.txt +28 -0
- plexora/client/external/openseadragon-bin-2.4.0/canvas-overlay-hd.js +140 -0
- plexora/client/external/openseadragon-bin-2.4.0/changelog.txt +501 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/.gitattributes +17 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/LICENSE.txt +116 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/Toolbar.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/fullpage.psd +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/home.psd +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/next.psd +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/previous.psd +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/rotateleft.psd +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/rotateright.psd +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/zoom.psd +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/README.md +9 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/fullpage_grouphover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/fullpage_hover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/fullpage_pressed.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/fullpage_rest.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/home_grouphover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/home_hover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/home_pressed.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/home_rest.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/next_grouphover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/next_hover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/next_pressed.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/next_rest.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/previous_grouphover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/previous_hover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/previous_pressed.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/previous_rest.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateleft_grouphover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateleft_hover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateleft_pressed.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateleft_rest.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateright_grouphover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateright_hover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateright_pressed.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateright_rest.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomin_grouphover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomin_hover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomin_pressed.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomin_rest.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomout_grouphover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomout_hover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomout_pressed.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomout_rest.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-scalebar.js +562 -0
- plexora/client/src/css/import.css +474 -0
- plexora/client/src/css/main.css +903 -0
- plexora/client/src/css/openProject.css +363 -0
- plexora/client/src/css/quickView.css +166 -0
- plexora/client/src/css/tokens.css +51 -0
- plexora/client/src/css/viewer.css +1655 -0
- plexora/client/src/img/apple-touch-icon.png +0 -0
- plexora/client/src/img/favicon.ico +0 -0
- plexora/client/src/img/logo.ai +8892 -33
- plexora/client/src/img/logo.svg +1 -0
- plexora/client/src/img/logo_with_text.ai +9011 -34
- plexora/client/src/img/logo_with_text.svg +1 -0
- plexora/client/src/js/main.js +704 -0
- plexora/client/src/js/pluginRegistry.js +108 -0
- plexora/client/src/js/services/appStatus.js +286 -0
- plexora/client/src/js/services/browsePicker.js +73 -0
- plexora/client/src/js/services/dataLayer.js +400 -0
- plexora/client/src/js/services/datasetContext.js +143 -0
- plexora/client/src/js/services/glRenderer.js +143 -0
- plexora/client/src/js/services/importFormValidation.js +257 -0
- plexora/client/src/js/services/numericData.js +100 -0
- plexora/client/src/js/services/passVariablesToFrontend.js +20 -0
- plexora/client/src/js/services/simpleEventHandler.js +25 -0
- plexora/client/src/js/vendor.js +29 -0
- plexora/client/src/js/views/channelList.js +663 -0
- plexora/client/src/js/views/colorSwatchPicker.js +202 -0
- plexora/client/src/js/views/columnClassifier.js +146 -0
- plexora/client/src/js/views/coordinateField.js +133 -0
- plexora/client/src/js/views/dataSourceField.js +276 -0
- plexora/client/src/js/views/imageViewer.js +3306 -0
- plexora/client/src/js/views/miniMap.js +787 -0
- plexora/client/src/js/views/navbarControls.js +178 -0
- plexora/client/src/js/views/openProjectPage.js +239 -0
- plexora/client/src/js/views/projectEdit.js +335 -0
- plexora/client/src/js/views/quickViewLanding.js +136 -0
- plexora/client/src/js/views/rainbow.js +326 -0
- plexora/client/src/js/views/requirementsModal.js +572 -0
- plexora/client/src/js/views/rgbImageViewer.js +115 -0
- plexora/client/src/js/views/searchableSelect.js +411 -0
- plexora/client/src/js/views/segmentationProgress.js +122 -0
- plexora/client/src/js/views/toolLoader.js +747 -0
- plexora/client/src/js/views/viewerControls.js +689 -0
- plexora/client/src/js/views/viewerManager.js +434 -0
- plexora/client/src/js/views/viewerSidebar.js +1117 -0
- plexora/client/src/js/workers/tileDecoder.js +130 -0
- plexora/client/src/shaders/frag.glsl +528 -0
- plexora/client/src/shaders/vert.glsl +12 -0
- plexora/client/templates/base.html +212 -0
- plexora/client/templates/index.html +238 -0
- plexora/client/templates/open_project.html +96 -0
- plexora/client/templates/project_columns.html +86 -0
- plexora/client/templates/project_edit.html +196 -0
- plexora/client/templates/upload.html +118 -0
- plexora/connect.py +528 -0
- plexora/datasource.py +782 -0
- plexora/jupyter.py +406 -0
- plexora/notebook_env.py +232 -0
- plexora/paths.py +486 -0
- plexora/plugins/__init__.py +12 -0
- plexora/plugins/cell_explorer/__init__.py +100 -0
- plexora/plugins/cell_explorer/server/__init__.py +11 -0
- plexora/plugins/cell_explorer/server/routes.py +167 -0
- plexora/plugins/cell_explorer/server/state.py +281 -0
- plexora/plugins/cell_explorer/server/values.py +145 -0
- plexora/plugins/cell_explorer/server/variables.py +367 -0
- plexora/plugins/cell_explorer/static/cellExplorerApi.js +158 -0
- plexora/plugins/cell_explorer/static/cellExplorerColors.js +316 -0
- plexora/plugins/cell_explorer/static/cellExplorerContinuous.js +403 -0
- plexora/plugins/cell_explorer/static/cellExplorerFigureBridge.js +133 -0
- plexora/plugins/cell_explorer/static/cellExplorerLegend.js +188 -0
- plexora/plugins/cell_explorer/static/cellExplorerRoiBridge.js +822 -0
- plexora/plugins/cell_explorer/static/cellExplorerSidebarController.js +826 -0
- plexora/plugins/cell_explorer/static/cellExplorerState.js +372 -0
- plexora/plugins/cell_explorer/static/cell_explorer.css +752 -0
- plexora/plugins/cell_explorer/templates/cell_explorer/panel.html +137 -0
- plexora/plugins/figure_builder/__init__.py +125 -0
- plexora/plugins/figure_builder/server/__init__.py +7 -0
- plexora/plugins/figure_builder/server/compose.py +365 -0
- plexora/plugins/figure_builder/server/export.py +784 -0
- plexora/plugins/figure_builder/server/export_jobs.py +148 -0
- plexora/plugins/figure_builder/server/operations.py +556 -0
- plexora/plugins/figure_builder/server/pixels.py +142 -0
- plexora/plugins/figure_builder/server/provenance.py +174 -0
- plexora/plugins/figure_builder/server/render.py +278 -0
- plexora/plugins/figure_builder/server/repository.py +701 -0
- plexora/plugins/figure_builder/server/routes.py +594 -0
- plexora/plugins/figure_builder/server/schema.py +1023 -0
- plexora/plugins/figure_builder/server/sources.py +120 -0
- plexora/plugins/figure_builder/server/textmetrics.py +155 -0
- plexora/plugins/figure_builder/static/figureActions.js +363 -0
- plexora/plugins/figure_builder/static/figureBuilderApi.js +255 -0
- plexora/plugins/figure_builder/static/figureCanvas.js +2362 -0
- plexora/plugins/figure_builder/static/figureCaptureBoxes.js +369 -0
- plexora/plugins/figure_builder/static/figureCaptureDock.js +466 -0
- plexora/plugins/figure_builder/static/figureCaptureTool.js +1034 -0
- plexora/plugins/figure_builder/static/figureConfirm.js +136 -0
- plexora/plugins/figure_builder/static/figureContextBar.js +1193 -0
- plexora/plugins/figure_builder/static/figureContextMenu.js +253 -0
- plexora/plugins/figure_builder/static/figureDocumentState.js +275 -0
- plexora/plugins/figure_builder/static/figureExportUi.js +174 -0
- plexora/plugins/figure_builder/static/figureLibrary.js +247 -0
- plexora/plugins/figure_builder/static/figureQuickEdit.js +628 -0
- plexora/plugins/figure_builder/static/figureRichText.js +634 -0
- plexora/plugins/figure_builder/static/figureSceneSnapshot.js +361 -0
- plexora/plugins/figure_builder/static/figureSchema.js +218 -0
- plexora/plugins/figure_builder/static/figureSidebarController.js +1159 -0
- plexora/plugins/figure_builder/static/figureTextEditor.js +503 -0
- plexora/plugins/figure_builder/static/figureTextPanel.js +491 -0
- plexora/plugins/figure_builder/static/figureViewOptions.js +273 -0
- plexora/plugins/figure_builder/static/figureWorkspace.js +2030 -0
- plexora/plugins/figure_builder/static/figure_builder.css +3292 -0
- plexora/plugins/figure_builder/templates/figure_builder/library.html +74 -0
- plexora/plugins/figure_builder/templates/figure_builder/workspace.html +27 -0
- plexora/plugins/figure_builder/templates/figure_builder/workspace_body.html +458 -0
- plexora/plugins/gating/__init__.py +76 -0
- plexora/plugins/gating/server/__init__.py +0 -0
- plexora/plugins/gating/server/anndata_gates.py +367 -0
- plexora/plugins/gating/server/database.py +16 -0
- plexora/plugins/gating/server/model.py +320 -0
- plexora/plugins/gating/server/routes.py +235 -0
- plexora/plugins/gating/static/csvGatingList.js +947 -0
- plexora/plugins/gating/static/gating.css +289 -0
- plexora/plugins/gating/static/gatingApi.js +221 -0
- plexora/plugins/gating/static/gatingSidebarController.js +513 -0
- plexora/plugins/gating/templates/gating/legacy.html +26 -0
- plexora/plugins/gating/templates/gating/panel.html +69 -0
- plexora/plugins/roi/__init__.py +95 -0
- plexora/plugins/roi/server/__init__.py +8 -0
- plexora/plugins/roi/server/adapters.py +655 -0
- plexora/plugins/roi/server/geojson.py +267 -0
- plexora/plugins/roi/server/geometry.py +181 -0
- plexora/plugins/roi/server/mapping.py +169 -0
- plexora/plugins/roi/server/operations.py +293 -0
- plexora/plugins/roi/server/repository.py +215 -0
- plexora/plugins/roi/server/routes.py +409 -0
- plexora/plugins/roi/server/schema.py +323 -0
- plexora/plugins/roi/static/roi.css +583 -0
- plexora/plugins/roi/static/roiApi.js +177 -0
- plexora/plugins/roi/static/roiFigureBridge.js +107 -0
- plexora/plugins/roi/static/roiGeometry.js +350 -0
- plexora/plugins/roi/static/roiRenderer.js +278 -0
- plexora/plugins/roi/static/roiSidebarController.js +1038 -0
- plexora/plugins/roi/static/roiState.js +518 -0
- plexora/plugins/roi/static/roiTools.js +993 -0
- plexora/plugins/roi/templates/roi/panel.html +240 -0
- plexora/proxy.py +57 -0
- plexora/server/models/adapters/__init__.py +94 -0
- plexora/server/models/adapters/anndata_adapter.py +388 -0
- plexora/server/models/adapters/base.py +93 -0
- plexora/server/models/adapters/classify.py +192 -0
- plexora/server/models/adapters/csv_adapter.py +105 -0
- plexora/server/models/adapters/inspection.py +265 -0
- plexora/server/models/adapters/spatialdata_adapter.py +248 -0
- plexora/server/models/centroid_tiles.py +305 -0
- plexora/server/models/data_model.py +1659 -0
- plexora/server/models/database_model.py +169 -0
- plexora/server/models/project.py +1270 -0
- plexora/server/plugins.py +199 -0
- plexora/server/routes/browse_routes.py +41 -0
- plexora/server/routes/data_routes.py +294 -0
- plexora/server/routes/import_routes.py +603 -0
- plexora/server/routes/page_routes.py +139 -0
- plexora/server/routes/project_routes.py +438 -0
- plexora/server/routes/quick_view_routes.py +62 -0
- plexora/server/routes/system_routes.py +39 -0
- plexora/server/routes/tool_routes.py +418 -0
- plexora/server/utils/addHEColumns.py +11 -0
- plexora/server/utils/fast_png.py +97 -0
- plexora/server/utils/fullConversion.py +50 -0
- plexora/server/utils/native_dialog.py +168 -0
- plexora/server/utils/pre_normalization.py +47 -0
- plexora/server/utils/segmentation_pyramid.py +598 -0
- plexora/server/utils/smallestenclosingcircle.py +126 -0
- plexora/server/utils/tiffsurgeon.py +372 -0
- plexora/server_cli.py +48 -0
- plexora/test.py +0 -0
- plexora-0.0.1.dist-info/METADATA +341 -0
- plexora-0.0.1.dist-info/RECORD +248 -0
- plexora-0.0.1.dist-info/WHEEL +5 -0
- plexora-0.0.1.dist-info/entry_points.txt +12 -0
- plexora-0.0.1.dist-info/licenses/LICENSE +207 -0
- plexora-0.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
{% extends 'base.html' %}
|
|
2
|
+
{% block style %}
|
|
3
|
+
<link rel="stylesheet" href="{{ data.base_url }}/client/src/css/import.css?v=20260819_data_table_pick">
|
|
4
|
+
{% endblock %}
|
|
5
|
+
{% block content %}
|
|
6
|
+
<title>Plexora - Edit {{ data.datasetName }}</title>
|
|
7
|
+
{#
|
|
8
|
+
Generated from the project record: every section below is gated on
|
|
9
|
+
`project.has`, so a project sees only the fields it actually has. The old
|
|
10
|
+
edit page rendered the CSV column-matching screen for every project
|
|
11
|
+
regardless of format, which is what made editing an AnnData project destroy
|
|
12
|
+
it.
|
|
13
|
+
#}
|
|
14
|
+
{% set project = data.project %}
|
|
15
|
+
<div class="import-page">
|
|
16
|
+
<div id="upload-parent">
|
|
17
|
+
{# Single quotes, and they matter. `tojson` escapes < > & and ' but NOT
|
|
18
|
+
the double quotes JSON is built out of, so in a double-quoted
|
|
19
|
+
attribute the value ends at the record's first key and the rest
|
|
20
|
+
spills into the tag as garbage attributes. `id` still parsed, so the
|
|
21
|
+
page looked completely normal -- and projectEdit.js threw on
|
|
22
|
+
JSON.parse("{"), which is where the Save button lost its listener. #}
|
|
23
|
+
<div class="import-card import-card-wide" id="project-edit"
|
|
24
|
+
data-project='{{ project|tojson }}'
|
|
25
|
+
{% if data.needs %}data-needs='{{ data.needs|tojson }}'{% endif %}>
|
|
26
|
+
<span class="import-kicker">Edit Project</span>
|
|
27
|
+
<h1>{{ data.datasetName }}</h1>
|
|
28
|
+
|
|
29
|
+
<div id="edit_needs" class="import-alert" role="status" hidden></div>
|
|
30
|
+
|
|
31
|
+
{# Image: read-only. Everything the project derives is keyed to it. #}
|
|
32
|
+
<div class="config-section">
|
|
33
|
+
<div class="config-section-title">Image</div>
|
|
34
|
+
<p class="config-summary">
|
|
35
|
+
<strong>{{ project.image.src }}</strong><br>
|
|
36
|
+
{{ project.image.channelCount or 0 }} channel(s)
|
|
37
|
+
{% if project.image.size[0] %}
|
|
38
|
+
· {{ project.image.size[0] }} × {{ project.image.size[1] }} px
|
|
39
|
+
{% endif %}
|
|
40
|
+
</p>
|
|
41
|
+
<span class="field-hint">The image cannot be changed — import a new project to use a different one.</span>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<div class="config-section">
|
|
45
|
+
<div class="config-section-title">Segmentation Mask</div>
|
|
46
|
+
<div class="import-field">
|
|
47
|
+
<div class="import-field-row">
|
|
48
|
+
<input type="text" id="edit_segmentation" class="form-control"
|
|
49
|
+
value="{{ project.segmentation.src or '' }}"
|
|
50
|
+
placeholder="/path/to/segmentation.ome.tif">
|
|
51
|
+
<button type="button" class="browse-button" data-browse-target="edit_segmentation"
|
|
52
|
+
data-browse-mode="file" data-browse-filter="image">Browse…</button>
|
|
53
|
+
</div>
|
|
54
|
+
<span class="field-hint">
|
|
55
|
+
{% if project.segmentation.pending %}
|
|
56
|
+
Converting — the mask will be ready shortly.
|
|
57
|
+
{% else %}
|
|
58
|
+
Clear the box to remove the mask.
|
|
59
|
+
{% endif %}
|
|
60
|
+
</span>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
{# Mounted by projectEdit.js from the shared control
|
|
65
|
+
(dataSourceField.js), not written out here: swapping in a .zarr
|
|
66
|
+
store with several tables needs a table picker, and the two
|
|
67
|
+
static Browse buttons this used to carry were never wired to
|
|
68
|
+
anything -- only the upload page's script attaches
|
|
69
|
+
[data-browse-target], and it does not load on this page. #}
|
|
70
|
+
<div class="config-section">
|
|
71
|
+
<div class="config-section-title">Data</div>
|
|
72
|
+
{# The path itself comes from the project record the page is
|
|
73
|
+
already carrying; only the note needs saying here. #}
|
|
74
|
+
<div class="import-field" id="edit_data_field"
|
|
75
|
+
data-hint="{% if project.data %}Detected as {{ project.data.type }}{% if project.data.table %} · table “{{ project.data.table }}”{% endif %}. Replacing the file re-detects its format.{% else %}CSV, AnnData (.h5ad) or SpatialData (.zarr).{% endif %}">
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
{# What the numbers in this project actually are. The select is shown
|
|
80
|
+
only when the file carries more than one matrix -- raw counts and a
|
|
81
|
+
log-transformed copy live side by side in one .h5ad, and which was
|
|
82
|
+
read decides what every marker histogram is a histogram of. The
|
|
83
|
+
log1p switch is offered either way: a file may carry raw counts and
|
|
84
|
+
nothing else, and thresholds on those are unreadable untransformed. #}
|
|
85
|
+
{% if project.has.features %}
|
|
86
|
+
<div class="config-section">
|
|
87
|
+
<div class="config-section-title">Expression Values</div>
|
|
88
|
+
{% if project.data.layers %}
|
|
89
|
+
<div class="import-field">
|
|
90
|
+
<select id="edit_features_layer" class="form-select">
|
|
91
|
+
{% for option in project.featureOptions %}
|
|
92
|
+
<option value="{{ option.value }}"
|
|
93
|
+
{% if project.featureSource == option.value %}selected{% endif %}>
|
|
94
|
+
{{ option.label }}
|
|
95
|
+
</option>
|
|
96
|
+
{% endfor %}
|
|
97
|
+
</select>
|
|
98
|
+
<span class="field-hint">Which matrix the marker intensities are read from.
|
|
99
|
+
Thresholds set against one do not carry to another.</span>
|
|
100
|
+
</div>
|
|
101
|
+
{% endif %}
|
|
102
|
+
<div class="import-field">
|
|
103
|
+
<label class="config-check">
|
|
104
|
+
<input type="checkbox" class="form-check-input" id="edit_features_log"
|
|
105
|
+
{% if project.featureLog %}checked{% endif %}>
|
|
106
|
+
<span class="form-check-label">Log-transform (log1p)</span>
|
|
107
|
+
<span class="field-hint">Turn this on when the values above are raw counts.</span>
|
|
108
|
+
</label>
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
{% endif %}
|
|
112
|
+
|
|
113
|
+
{# The read spec is how the adapter gets from file to table. Shown
|
|
114
|
+
so the user can see what was auto-detected; changing it means
|
|
115
|
+
replacing the data file above, which re-detects it. #}
|
|
116
|
+
{% if project.has.readSpec %}
|
|
117
|
+
<div class="config-section">
|
|
118
|
+
<div class="config-section-title">How this file is read</div>
|
|
119
|
+
{# Coordinates are no longer summarised here: they are a real
|
|
120
|
+
control in the Columns section below, because which array
|
|
121
|
+
holds a cell's position is a choice and not a detail. This
|
|
122
|
+
line read "auto-detected" for a project whose source was
|
|
123
|
+
picked by matching an obsm key against a hardcoded list of
|
|
124
|
+
names -- accurate, and no help to anyone it was wrong for. #}
|
|
125
|
+
<p class="config-summary">
|
|
126
|
+
Features: <strong>{{ project.data.features.get('layer') or project.data.features.get('source') or 'X' }}</strong>
|
|
127
|
+
{% if project.data.subset.get('column') %}
|
|
128
|
+
<br>Image: <strong>{{ project.data.subset['column'] }} = {{ project.data.subset['value'] }}</strong>
|
|
129
|
+
{% endif %}
|
|
130
|
+
</p>
|
|
131
|
+
</div>
|
|
132
|
+
{% endif %}
|
|
133
|
+
|
|
134
|
+
{# CSV only: the marker/metadata split, which also owns the roles. #}
|
|
135
|
+
{% if project.has.columns %}
|
|
136
|
+
<div class="config-section">
|
|
137
|
+
<div class="config-section-title">Columns</div>
|
|
138
|
+
<div id="edit_classifier"></div>
|
|
139
|
+
</div>
|
|
140
|
+
{% endif %}
|
|
141
|
+
|
|
142
|
+
{# Everything else with a table: only the roles backed by real
|
|
143
|
+
columns (the adapter synthesizes the rest). #}
|
|
144
|
+
{% if project.has.data and not project.has.columns %}
|
|
145
|
+
<div class="config-section">
|
|
146
|
+
<div class="config-section-title">Columns</div>
|
|
147
|
+
<div id="edit_roles"></div>
|
|
148
|
+
</div>
|
|
149
|
+
{% endif %}
|
|
150
|
+
|
|
151
|
+
{# How tools draw per-cell results. Defaulted rather than asked --
|
|
152
|
+
the mask if there is one, centroids otherwise -- so this is an
|
|
153
|
+
override.
|
|
154
|
+
|
|
155
|
+
"Automatic" is a real option and the one an untouched project is
|
|
156
|
+
on, because the alternative is that saving this page for any
|
|
157
|
+
other reason records a choice nobody made. That mattered: a
|
|
158
|
+
project whose mask was still converting could only offer
|
|
159
|
+
centroids here, and the save froze centroids in place for good
|
|
160
|
+
-- the mask landed minutes later and every tool went on drawing
|
|
161
|
+
points. #}
|
|
162
|
+
{% if project.has.cellLayer %}
|
|
163
|
+
<div class="config-section">
|
|
164
|
+
<div class="config-section-title">Cell Layer</div>
|
|
165
|
+
<div class="import-field">
|
|
166
|
+
<select id="edit_cell_layer" class="form-select"
|
|
167
|
+
data-stored="{{ project.cellLayerChoice or '' }}">
|
|
168
|
+
<option value="" {% if not project.cellLayerChoice %}selected{% endif %}>
|
|
169
|
+
Automatic — the mask if there is one, otherwise centroids
|
|
170
|
+
</option>
|
|
171
|
+
{% for option in project.cellLayerOptions %}
|
|
172
|
+
<option value="{{ option }}" {% if project.cellLayerChoice == option %}selected{% endif %}>
|
|
173
|
+
{% if option == 'segmentation' %}Segmentation mask — real cell outlines
|
|
174
|
+
{% else %}Centroids — one point per cell{% endif %}
|
|
175
|
+
</option>
|
|
176
|
+
{% endfor %}
|
|
177
|
+
</select>
|
|
178
|
+
<span class="field-hint">Used by tools that colour cells, such as Cell Explorer
|
|
179
|
+
and Thresholding. Currently drawing:
|
|
180
|
+
{% if project.cellLayer == 'segmentation' %}the segmentation mask{% else %}centroids{% endif %}.</span>
|
|
181
|
+
</div>
|
|
182
|
+
</div>
|
|
183
|
+
{% endif %}
|
|
184
|
+
|
|
185
|
+
<div class="import-actions">
|
|
186
|
+
<button id="edit_save" class="btn btn-primary" type="button">Save</button>
|
|
187
|
+
</div>
|
|
188
|
+
<div id="edit_error" class="import-alert" role="alert" hidden></div>
|
|
189
|
+
</div>
|
|
190
|
+
</div>
|
|
191
|
+
</div>
|
|
192
|
+
<script src="{{ data.base_url }}/client/src/js/views/columnClassifier.js?v=20260820_csv_markers_log1p"></script>
|
|
193
|
+
<script src="{{ data.base_url }}/client/src/js/views/coordinateField.js?v=20260819_ask_cell_id"></script>
|
|
194
|
+
<script src="{{ data.base_url }}/client/src/js/views/segmentationProgress.js?v=20260817_single_import"></script>
|
|
195
|
+
<script src="{{ data.base_url }}/client/src/js/views/projectEdit.js?v=20260821_cell_panel_one_line" defer></script>
|
|
196
|
+
{% endblock %}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
{% extends 'base.html' %}
|
|
2
|
+
{% block style %}
|
|
3
|
+
<link rel="stylesheet" href="{{ data.base_url }}/client/src/css/import.css?v=20260819_data_table_pick">
|
|
4
|
+
{% endblock %}
|
|
5
|
+
{% block content %}
|
|
6
|
+
<title>Plexora - New Project</title>
|
|
7
|
+
{#
|
|
8
|
+
One form, three inputs. The format of the data file is detected server-side
|
|
9
|
+
(/inspect_data), so there is no tab strip and no per-format duplicate of the
|
|
10
|
+
name/image/mask fields.
|
|
11
|
+
|
|
12
|
+
The two extra controls below are hidden until the file itself makes them
|
|
13
|
+
necessary: a .zarr store with several tables, and a table spanning several
|
|
14
|
+
images, cannot be read at all until the user picks one. Everything else the
|
|
15
|
+
old import wizard asked for is either worked out from the file or asked for
|
|
16
|
+
later, by whichever feature actually needs it.
|
|
17
|
+
#}
|
|
18
|
+
<div class="import-page">
|
|
19
|
+
<div id="upload-parent">
|
|
20
|
+
<div class="import-card" id="upload-container">
|
|
21
|
+
<span class="import-kicker">New Project</span>
|
|
22
|
+
<h1>Import Data</h1>
|
|
23
|
+
<p class="import-subtitle">An image is all that is required. Add a segmentation mask
|
|
24
|
+
and single-cell data now, or later from the project's Edit page.</p>
|
|
25
|
+
|
|
26
|
+
{% if data.error %}
|
|
27
|
+
<div class="import-alert" role="alert">{{ data.error }}</div>
|
|
28
|
+
{% endif %}
|
|
29
|
+
|
|
30
|
+
<form action="{{ data.base_url }}/import" id="import_form" method="POST"
|
|
31
|
+
class="needs-validation" enctype="multipart/form-data" novalidate>
|
|
32
|
+
<div class="import-field">
|
|
33
|
+
<label for="name">Project Name</label>
|
|
34
|
+
<input type="text" class="form-control" id="name" name="name"
|
|
35
|
+
oninput="markDatasetNameEdited()" required placeholder="e.g. patient_01"
|
|
36
|
+
value="{{ data.form_name or '' }}">
|
|
37
|
+
<div class="invalid-feedback">Please name the project.</div>
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
<div class="import-field">
|
|
41
|
+
<label for="image_file">Image</label>
|
|
42
|
+
<div class="import-field-row">
|
|
43
|
+
<input type="text" id="image_file" class="form-control" name="image_file"
|
|
44
|
+
onkeyup="checkFileExistence(this); suggestDatasetName(this);" required
|
|
45
|
+
placeholder="/path/to/image.ome.tif"
|
|
46
|
+
value="{{ data.form_image or '' }}">
|
|
47
|
+
<button type="button" class="browse-button" data-browse-target="image_file"
|
|
48
|
+
data-browse-mode="file" data-browse-filter="image">Browse…</button>
|
|
49
|
+
</div>
|
|
50
|
+
<div class="invalid-feedback">Please provide a valid path to the image file.</div>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<div class="import-field">
|
|
54
|
+
<label for="label_file">Segmentation Mask <span class="field-hint">(optional)</span></label>
|
|
55
|
+
<div class="import-field-row">
|
|
56
|
+
<input type="text" id="label_file" class="form-control" name="label_file"
|
|
57
|
+
onkeyup="checkOptionalFileExistence(this)"
|
|
58
|
+
placeholder="/path/to/segmentation.ome.tif"
|
|
59
|
+
value="{{ data.form_mask or '' }}">
|
|
60
|
+
<button type="button" class="browse-button" data-browse-target="label_file"
|
|
61
|
+
data-browse-mode="file" data-browse-filter="image">Browse…</button>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
<div class="import-field">
|
|
66
|
+
<label for="data_file">Data <span class="field-hint">(optional)</span></label>
|
|
67
|
+
<div class="import-field-row">
|
|
68
|
+
<input type="text" id="data_file" class="form-control" name="data_file"
|
|
69
|
+
onkeyup="inspectDataFile(this)"
|
|
70
|
+
placeholder="/path/to/cells.csv"
|
|
71
|
+
value="{{ data.form_data or '' }}">
|
|
72
|
+
{# A .zarr store is a directory and a .csv/.h5ad is a file, and
|
|
73
|
+
one input takes both -- so the picker offers each in turn. #}
|
|
74
|
+
<button type="button" class="browse-button" data-browse-target="data_file"
|
|
75
|
+
data-browse-mode="file" data-browse-filter="data">File…</button>
|
|
76
|
+
<button type="button" class="browse-button" data-browse-target="data_file"
|
|
77
|
+
data-browse-mode="directory" data-browse-filter="any">Store…</button>
|
|
78
|
+
</div>
|
|
79
|
+
<span class="field-hint" id="data_file_hint">CSV, AnnData (.h5ad) or SpatialData (.zarr).</span>
|
|
80
|
+
<div class="invalid-feedback" id="data_file_error"></div>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
{# Shown only when the store holds more than one table. #}
|
|
84
|
+
<div class="import-field" id="data_table_field" hidden>
|
|
85
|
+
<label for="data_table">Table</label>
|
|
86
|
+
<select id="data_table" class="form-select" name="data_table"></select>
|
|
87
|
+
<span class="field-hint">This store holds several tables. Choose which one holds the cells.</span>
|
|
88
|
+
</div>
|
|
89
|
+
|
|
90
|
+
{# Which expression matrix to read is deliberately NOT asked here.
|
|
91
|
+
It matters only to a plugin that reads marker intensities, so
|
|
92
|
+
it is that plugin's requirement (Requires(features=True)) and
|
|
93
|
+
the modal asks it -- along with whether to log-transform --
|
|
94
|
+
the first time such a tool opens. Importing an image is not
|
|
95
|
+
the moment to answer a question about thresholding, and this
|
|
96
|
+
form only asks what registering the project cannot proceed
|
|
97
|
+
without. The layer names are still recorded from the
|
|
98
|
+
inspection above, which is what lets the modal offer them
|
|
99
|
+
without reopening the file. #}
|
|
100
|
+
|
|
101
|
+
{# Shown only when the table spans several images. Loading them all
|
|
102
|
+
would silently mix cells from different slides onto one image. #}
|
|
103
|
+
<div class="import-field" id="subset_field" hidden>
|
|
104
|
+
<label for="subset_value">Image</label>
|
|
105
|
+
<input type="hidden" id="subset_column" name="subset_column">
|
|
106
|
+
<select id="subset_value" class="form-select" name="subset_value"></select>
|
|
107
|
+
<span class="field-hint" id="subset_hint"></span>
|
|
108
|
+
</div>
|
|
109
|
+
|
|
110
|
+
<div class="import-actions">
|
|
111
|
+
<button id="upload_button" class="btn btn-primary" type="submit">Create Project</button>
|
|
112
|
+
</div>
|
|
113
|
+
</form>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
</div>
|
|
117
|
+
<script src="{{ data.base_url }}/client/src/js/services/importFormValidation.js?v=20260819_feature_source" defer></script>
|
|
118
|
+
{% endblock %}
|