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,168 @@
|
|
|
1
|
+
# Native OS file/folder picker for the "Browse..." buttons in the quick-view
|
|
2
|
+
# and import UIs. Returns a path only -- never file bytes.
|
|
3
|
+
#
|
|
4
|
+
# macOS goes through `osascript`'s `choose file`/`choose folder` (a real
|
|
5
|
+
# Cocoa panel driven by AppleScript, no Python GUI toolkit involved) rather
|
|
6
|
+
# than tkinter. tkinter's askopenfilename on macOS routes through a hidden Tk
|
|
7
|
+
# root window that Cocoa uses to size/position/parent the panel, and that
|
|
8
|
+
# path is a long-standing source of broken behavior on recent macOS -- the
|
|
9
|
+
# panel can appear tiny and pinned to a screen corner, barely resizable, or
|
|
10
|
+
# even dismiss itself immediately (the click that opened it double-counts as
|
|
11
|
+
# a click "outside" the misplaced panel). osascript's panel is a normal,
|
|
12
|
+
# independently-managed system dialog and doesn't have any of that.
|
|
13
|
+
#
|
|
14
|
+
# Other platforms keep the tkinter subprocess approach, run out-of-process
|
|
15
|
+
# for two reasons: Tk needs to run on the process's *main* thread on macOS
|
|
16
|
+
# (moot here since macOS no longer uses this path, but still true in
|
|
17
|
+
# principle), but more importantly a request handled by waitress lands on an
|
|
18
|
+
# arbitrary worker thread; and a subprocess crash/hang (e.g. no display on a
|
|
19
|
+
# headless box) can't take the server down with it.
|
|
20
|
+
#
|
|
21
|
+
# Only meant for the terminal/`python run.py` and Jupyter (`server_cli.py`)
|
|
22
|
+
# launch paths, where sys.executable is a real Python interpreter. It is not
|
|
23
|
+
# safe to use as-is from a frozen/packaged build, where sys.executable is the
|
|
24
|
+
# packaged exe itself.
|
|
25
|
+
|
|
26
|
+
import json
|
|
27
|
+
import subprocess
|
|
28
|
+
import sys
|
|
29
|
+
|
|
30
|
+
# Keyed by the caller's `file_filter` argument (kept in sync with
|
|
31
|
+
# browsePicker.js's data-browse-filter values).
|
|
32
|
+
_TK_FILTERS = {
|
|
33
|
+
"image": [("Image files", "*.tif *.tiff *.ome.tif *.ome.tiff *.svs *.qptiff *.png *.jpg *.jpeg"), ("All files", "*.*")],
|
|
34
|
+
"csv": [("CSV files", "*.csv"), ("All files", "*.*")],
|
|
35
|
+
"h5ad": [("AnnData files", "*.h5ad"), ("All files", "*.*")],
|
|
36
|
+
# The single Data input accepts any feature-table format, so its picker
|
|
37
|
+
# offers all of them at once rather than making the user pick a format
|
|
38
|
+
# before picking a file. A .zarr store is a directory and is reached by
|
|
39
|
+
# the same field's "Store..." button in directory mode.
|
|
40
|
+
"data": [("Single-cell data", "*.csv *.tsv *.txt *.h5ad"), ("All files", "*.*")],
|
|
41
|
+
"any": [("All files", "*.*")],
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
#: The filter names callers may ask for. Exported so the route validates
|
|
45
|
+
#: against this table rather than its own hand-typed copy -- the two drifted
|
|
46
|
+
#: once already: "data" was added here for the single Data input on the import
|
|
47
|
+
#: page but not to the route's allowlist, so that field's "File..." button
|
|
48
|
+
#: posted a filter the server rejected with a 400 and did nothing at all.
|
|
49
|
+
FILTER_NAMES = frozenset(_TK_FILTERS)
|
|
50
|
+
|
|
51
|
+
# AppleScript's `choose file of type` filters by Uniform Type Identifier
|
|
52
|
+
# conformance, not literally by filename extension -- an extension string
|
|
53
|
+
# only works here when macOS actually has a UTI registered for it (true for
|
|
54
|
+
# common ones like these image formats, via system/Preview/etc.
|
|
55
|
+
# declarations). ".h5ad" has no such registration on a stock Mac, so filtering
|
|
56
|
+
# by it doesn't just fail to narrow the list -- it greys out every file,
|
|
57
|
+
# including real .h5ad ones, since none of them "conform" to an unregistered
|
|
58
|
+
# type. Left unfiltered (None -> no `of type` clause) rather than chasing a
|
|
59
|
+
# UTI that may not exist on the user's machine.
|
|
60
|
+
_APPLESCRIPT_EXTENSIONS = {
|
|
61
|
+
"image": ["tif", "tiff", "svs", "qptiff", "png", "jpg", "jpeg"],
|
|
62
|
+
"csv": ["csv"],
|
|
63
|
+
"h5ad": None,
|
|
64
|
+
# Unfiltered for the same reason as "h5ad" above: the set includes .h5ad,
|
|
65
|
+
# and one unregistered extension greys out every file in the dialog rather
|
|
66
|
+
# than just failing to match its own.
|
|
67
|
+
"data": None,
|
|
68
|
+
"any": None,
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
# The dialog script only ever receives a fixed, known filter key on argv --
|
|
72
|
+
# never an interpolated filetypes string -- since the script itself is
|
|
73
|
+
# passed to `python -c`.
|
|
74
|
+
_TK_DIALOG_SCRIPT = r"""
|
|
75
|
+
import json, sys
|
|
76
|
+
import tkinter as tk
|
|
77
|
+
from tkinter import filedialog
|
|
78
|
+
|
|
79
|
+
mode = sys.argv[1]
|
|
80
|
+
filter_key = sys.argv[2] if len(sys.argv) > 2 else "any"
|
|
81
|
+
|
|
82
|
+
FILTERS = %(filters)s
|
|
83
|
+
|
|
84
|
+
root = tk.Tk()
|
|
85
|
+
root.withdraw()
|
|
86
|
+
root.attributes("-topmost", True)
|
|
87
|
+
if mode == "directory":
|
|
88
|
+
path = filedialog.askdirectory(parent=root)
|
|
89
|
+
else:
|
|
90
|
+
path = filedialog.askopenfilename(parent=root, filetypes=FILTERS.get(filter_key, FILTERS["any"]))
|
|
91
|
+
root.destroy()
|
|
92
|
+
print(json.dumps({"path": path or None}))
|
|
93
|
+
""" % {"filters": repr(_TK_FILTERS)}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _browse_for_path_macos(mode, file_filter, timeout):
|
|
97
|
+
if mode == "directory":
|
|
98
|
+
script = 'POSIX path of (choose folder with prompt "Select a folder")'
|
|
99
|
+
else:
|
|
100
|
+
extensions = _APPLESCRIPT_EXTENSIONS.get(file_filter)
|
|
101
|
+
of_type = ""
|
|
102
|
+
if extensions:
|
|
103
|
+
quoted = ", ".join(f'"{ext}"' for ext in extensions)
|
|
104
|
+
of_type = f" of type {{{quoted}}}"
|
|
105
|
+
script = f'POSIX path of (choose file{of_type} with prompt "Select a file")'
|
|
106
|
+
|
|
107
|
+
try:
|
|
108
|
+
result = subprocess.run(
|
|
109
|
+
["osascript", "-e", script],
|
|
110
|
+
capture_output=True,
|
|
111
|
+
text=True,
|
|
112
|
+
timeout=timeout,
|
|
113
|
+
)
|
|
114
|
+
except subprocess.TimeoutExpired:
|
|
115
|
+
raise RuntimeError("Timed out waiting for the file browser.")
|
|
116
|
+
except OSError as exc:
|
|
117
|
+
raise RuntimeError(str(exc))
|
|
118
|
+
|
|
119
|
+
if result.returncode != 0:
|
|
120
|
+
stderr = (result.stderr or "").strip()
|
|
121
|
+
# AppleScript error -128 is exactly "user cancelled" -- not a failure.
|
|
122
|
+
if "-128" in stderr or "User canceled" in stderr:
|
|
123
|
+
return None
|
|
124
|
+
message = stderr.splitlines()[-1] if stderr else "Could not open the file browser."
|
|
125
|
+
raise RuntimeError(message)
|
|
126
|
+
|
|
127
|
+
path = result.stdout.strip()
|
|
128
|
+
return path or None
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _browse_for_path_tk(mode, file_filter, timeout):
|
|
132
|
+
try:
|
|
133
|
+
result = subprocess.run(
|
|
134
|
+
[sys.executable, "-c", _TK_DIALOG_SCRIPT, mode, file_filter],
|
|
135
|
+
capture_output=True,
|
|
136
|
+
text=True,
|
|
137
|
+
timeout=timeout,
|
|
138
|
+
)
|
|
139
|
+
except subprocess.TimeoutExpired:
|
|
140
|
+
raise RuntimeError("Timed out waiting for the file browser.")
|
|
141
|
+
except OSError as exc:
|
|
142
|
+
raise RuntimeError(str(exc))
|
|
143
|
+
|
|
144
|
+
if result.returncode != 0:
|
|
145
|
+
message = (result.stderr or "").strip().splitlines()
|
|
146
|
+
raise RuntimeError(message[-1] if message else "Could not open the file browser.")
|
|
147
|
+
|
|
148
|
+
try:
|
|
149
|
+
return json.loads(result.stdout.strip().splitlines()[-1])["path"]
|
|
150
|
+
except (ValueError, IndexError, KeyError):
|
|
151
|
+
raise RuntimeError("Unexpected response from the file browser.")
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def browse_for_path(mode="file", file_filter="any", timeout=300):
|
|
155
|
+
"""Opens a native file/folder picker and returns the chosen absolute
|
|
156
|
+
path, or None if the user cancelled.
|
|
157
|
+
|
|
158
|
+
`file_filter` narrows the file-type dropdown for mode="file" (ignored
|
|
159
|
+
for mode="directory") -- one of "image", "csv", "h5ad", or "any"
|
|
160
|
+
(default, no narrowing beyond "All files").
|
|
161
|
+
|
|
162
|
+
Raises RuntimeError with a user-facing message if no picker could be
|
|
163
|
+
shown at all (no display, tkinter not installed, timed out, ...) so
|
|
164
|
+
callers can fall back to a manual path input.
|
|
165
|
+
"""
|
|
166
|
+
if sys.platform == "darwin":
|
|
167
|
+
return _browse_for_path_macos(mode, file_filter, timeout)
|
|
168
|
+
return _browse_for_path_tk(mode, file_filter, timeout)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def preNormalize(input_csvPath, output_csvPath, skip_columns=[]):
|
|
5
|
+
RAW_DATA = np.genfromtxt(input_csvPath, names=True, dtype=float, delimiter=',')
|
|
6
|
+
marker_list = RAW_DATA.dtype.names
|
|
7
|
+
norm_data = RAW_DATA.view((np.float64, len(marker_list)))
|
|
8
|
+
|
|
9
|
+
# A list of markers to skip normalization
|
|
10
|
+
# markers_notToNorm = ['Field_Row', 'Field_Col', 'CellID', 'X_position','Y_position','Percent_Touching','Number_Neighbors','Neighbor_1','Neighbor_2','Neighbor_3','Neighbor_4','Neighbor_5', 'Eccentricity', 'Solidity', 'Extent', 'EulerNumber', 'Perimeter', 'MajorAxisLength', 'MinorAxisLength', 'Orientation', 'X_position', 'Y_position']
|
|
11
|
+
# A list of markers to skip log10 transform
|
|
12
|
+
# markers_notToLog = ['DAPI1', 'A488b1', 'A555b1'] # skip 'DAPI1', 'A488b1', 'A555b1'
|
|
13
|
+
markers_notToLog = [] # nothing to skip
|
|
14
|
+
|
|
15
|
+
for marker_id in range(norm_data.shape[1]):
|
|
16
|
+
if marker_list[marker_id] in skip_columns:
|
|
17
|
+
continue
|
|
18
|
+
if marker_list[marker_id] in markers_notToLog:
|
|
19
|
+
# Log10 transform
|
|
20
|
+
norm_data[:, marker_id] = np.log10(norm_data[:, marker_id] + 1)
|
|
21
|
+
print(marker_list[marker_id], 'with log10 transform')
|
|
22
|
+
else:
|
|
23
|
+
print(marker_list[marker_id], 'without log10 transform')
|
|
24
|
+
# Percentile normalization by mapping [0.1%, 99.9%] into [0, 1]
|
|
25
|
+
min_tile, max_tile = np.percentile(norm_data[:, marker_id], [0.1, 99.9])
|
|
26
|
+
|
|
27
|
+
# norm_data[:, marker_id] =(norm_data[:, marker_id] - min_tile) * (max_tile - min_tile) / (max_tile - min_tile) + min_tile
|
|
28
|
+
norm_data[:, marker_id] = (norm_data[:, marker_id] - min_tile) / (max_tile - min_tile)
|
|
29
|
+
norm_data[:, marker_id] = np.minimum(norm_data[:, marker_id], 1)
|
|
30
|
+
norm_data[:, marker_id] = np.maximum(norm_data[:, marker_id], 0)
|
|
31
|
+
|
|
32
|
+
with open(output_csvPath, 'w') as f:
|
|
33
|
+
for marker_id, marker_name in enumerate(marker_list):
|
|
34
|
+
f.write(marker_name)
|
|
35
|
+
if marker_id != (len(marker_list) - 1):
|
|
36
|
+
f.write(',')
|
|
37
|
+
f.write('\n')
|
|
38
|
+
for norm_row in norm_data:
|
|
39
|
+
for elem_id, norm_elem in enumerate(norm_row):
|
|
40
|
+
f.write(str(norm_elem))
|
|
41
|
+
if elem_id != (norm_row.shape[0] - 1):
|
|
42
|
+
f.write(',')
|
|
43
|
+
f.write('\n')
|
|
44
|
+
|
|
45
|
+
# input_csvPath = 'Sample_23.csv'
|
|
46
|
+
# output_csvPath = 'Sample_23_norm2.csv'
|
|
47
|
+
# preNormalize(input_csvPath, output_csvPath)
|