From 0260008341d776fb5feade7c998365c3b3c1b80b Mon Sep 17 00:00:00 2001 From: Fotis Baltoumas Date: Thu, 17 Sep 2026 11:03:18 +0300 Subject: [PATCH] Revert "Update architecture" --- .claude/launch.json | 6 - .dockerignore | 20 - .github/workflows/ci.yml | 46 - .gitignore | 13 - .pre-commit-config.yaml | 30 - .serena/.gitignore | 2 - .serena/project.yml | 169 - AGENTS.md | 107 - CHANGELOG.md | 51 - CLAUDE.md | 6 - Dockerfile | 24 - LICENSE | 2 +- NORMA.Rproj | 13 + README.md | 300 +- backend/norma/__init__.py | 20 - backend/norma/api.py | 53 - backend/norma/config.py | 176 - backend/norma/handler.py | 248 -- backend/norma/main.py | 117 - backend/norma/relays.py | 224 - backend/norma/static.py | 31 - backend/pyproject.toml | 27 - backend/server.py | 12 - backend/tests/conftest.py | 131 - backend/tests/test_api.py | 92 - backend/tests/test_config.py | 101 - backend/tests/test_relays.py | 154 - .../tests/test_static_and_config_routes.py | 66 - backend/uv.lock | 587 --- deploy/apache-normaviz.conf | 61 - deploy/nginx.conf | 34 - deploy/norma.service | 19 - docker-compose.yml | 28 - docs/NAR_CHECKLIST.md | 55 - examples/norma_api_client.py | 173 - frontend/.prettierignore | 2 - frontend/.prettierrc | 7 - frontend/e2e/helpers.ts | 44 - frontend/e2e/smoke.spec.ts | 137 - frontend/e2e/tsconfig.json | 12 - frontend/eslint.config.js | 38 - frontend/norma.html | 3229 --------------- frontend/package-lock.json | 3072 -------------- frontend/package.json | 31 - frontend/playwright.config.ts | 22 - frontend/public/assets/apple-touch-icon.png | Bin 19248 -> 0 bytes frontend/public/assets/banner.svg | 374 -- frontend/public/assets/favicon-32.png | Bin 2325 -> 0 bytes frontend/public/assets/favicon.ico | Bin 14429 -> 0 bytes frontend/public/assets/favicon.svg | 9 - frontend/public/assets/logo.svg | 1 - frontend/public/index.html | 14 - frontend/public/norma-config.js | 22 - frontend/src/api/tester.ts | 639 --- frontend/src/api/wiring.ts | 453 -- frontend/src/arena3d.test.ts | 47 - frontend/src/arena3d.ts | 285 -- frontend/src/benchmark.ts | 274 -- frontend/src/clustering/clustering.test.ts | 46 - frontend/src/clustering/label_propagation.ts | 39 - frontend/src/clustering/leiden.ts | 193 - frontend/src/clustering/mapping.ts | 814 ---- frontend/src/clustering/mcl.ts | 257 -- frontend/src/clustering/values.test.ts | 34 - frontend/src/clustering/walktrap.ts | 198 - frontend/src/clustering/wiring.ts | 377 -- frontend/src/config.test.ts | 16 - frontend/src/config.ts | 57 - frontend/src/contours.ts | 551 --- frontend/src/cy.ts | 181 - frontend/src/demo_downloads.ts | 323 -- frontend/src/directed_stats.ts | 184 - frontend/src/enrichment.ts | 3078 -------------- frontend/src/examples.ts | 78 - frontend/src/export/dialog.ts | 611 --- frontend/src/export/draw.ts | 516 --- frontend/src/export/raster.ts | 145 - frontend/src/export/shading.ts | 128 - frontend/src/export/svg.ts | 319 -- frontend/src/export_norma.ts | 257 -- frontend/src/group_network.ts | 101 - frontend/src/hulls.test.ts | 42 - frontend/src/hulls.ts | 787 ---- frontend/src/label_colors.ts | 332 -- frontend/src/layouts/controls.ts | 1079 ----- frontend/src/layouts/cose.worker.ts | 19 - frontend/src/layouts/input.ts | 592 --- frontend/src/layouts/run.ts | 260 -- frontend/src/library.ts | 298 -- frontend/src/main.ts | 182 - frontend/src/metrics.ts | 1338 ------ frontend/src/network_state.ts | 402 -- frontend/src/palette.ts | 106 - frontend/src/parallel_edges.ts | 80 - frontend/src/profiler.ts | 2630 ------------ frontend/src/recording.ts | 291 -- frontend/src/sample_data.ts | 546 --- frontend/src/side_panel.ts | 104 - frontend/src/side_tabs.ts | 273 -- frontend/src/state.ts | 26 - frontend/src/string/groupings.ts | 185 - frontend/src/string/import.ts | 292 -- frontend/src/string/requests.ts | 160 - frontend/src/string/ui_state.ts | 80 - frontend/src/string/wiring.ts | 191 - frontend/src/style.css | 3644 ----------------- frontend/src/themes.ts | 142 - frontend/src/uploads.ts | 192 - frontend/src/view3d/cache.ts | 102 - frontend/src/view3d/camera.ts | 182 - frontend/src/view3d/draw.ts | 395 -- frontend/src/view3d/export.ts | 189 - frontend/src/view3d/input.ts | 367 -- frontend/src/view3d/layouts.ts | 411 -- frontend/src/view3d/painters.ts | 226 - frontend/src/view3d/state.ts | 86 - frontend/src/view3d/tab.ts | 119 - frontend/src/viewbar.ts | 54 - frontend/src/welcome.ts | 132 - frontend/src/wiring.ts | 1154 ------ frontend/tsconfig.json | 17 - frontend/vite.config.ts | 27 - frontend/vitest.setup.ts | 15 - functions/annotations.R | 1527 +++++++ functions/helpDownloadHandlers.R | 232 ++ functions/network.R | 96 + functions/refreshing/convex_hulls_3D.R | 535 +++ functions/refreshing/modularity.R | 25 + functions/topology.R | 131 + functions/upload.R | 386 ++ global.R | 231 ++ norma.config.hosted.json | 31 - norma.config.json | 8 - run_local.bat | 9 - run_local.sh | 8 - server.R | 1459 +++++++ ui.R | 31 + user_temp/folder_create | 0 views/about.R | 20 + views/annotations.R | 434 ++ views/help.R | 302 ++ views/network.R | 45 + views/topology.R | 82 + views/upload.R | 169 + views/welcome.R | 24 + www/Examples/BCAR3/BCAR3.txt | 92 + www/Examples/BCAR3/BCAR3_GO_BP.txt | 99 + www/Examples/BCAR3/BCAR3_GO_MF.txt | 20 + www/Examples/BCAR3/BCAR3_KEGG.txt | 27 + ..._Gallus_Pathways_KEGG_PATHWAY_FILTERED.txt | 13 + .../Biogrid_no_self_loops.txt | 333 ++ ...MA_Human_coexpression_Annotation_GO_BP.txt | 147 + ...MA_Human_coexpression_Annotation_GO_CC.txt | 75 + ...MA_Human_coexpression_Annotation_GO_MF.txt | 114 + ...RMA_Human_coexpression_Annotation_KEGG.txt | 56 + ...MA_Human_coexpression_Expression_MCODE.txt | 557 +++ .../NORMA_Human_coexpression_NETWORK.txt | 2144 ++++++++++ ...ene_Ontology_GOTERM_BP_DIRECT_FILTERED.txt | 89 + ...ene_Ontology_GOTERM_CC_DIRECT_FILTERED.txt | 53 + ...ene_Ontology_GOTERM_MF_DIRECT_FILTERED.txt | 33 + ...Sapiens_Pathways_KEGG_PATHWAY_FILTERED.txt | 4 + ...iens_Protein_Domains_INTERPRO_FILTERED.txt | 58 + ...Sapiens_Protein_Domains_SMART_FILTERED.txt | 12 + .../Intact-data_COVID19_no_self_loops.txt | 1094 +++++ .../TAU/TAU_KEGG_Annotation_NORMA.txt | 10 + www/Examples/TAU/TAU_Louvain.txt | 9 + www/Examples/TAU/TAU_expressions.txt | 363 ++ www/Examples/TAU/TAU_network_DEGs_NORMA.txt | 3177 ++++++++++++++ .../TP53/string_expression_colors.txt | 10 + www/Examples/TP53/string_interactions.txt | 47 + ...ng_interactions_groups_comma_duplicate.txt | 5 + www/Figures/Banner.png | Bin 0 -> 160700 bytes .../Community_detection_algorithms.png | Bin 0 -> 98667 bytes www/Figures/Convex_Hulls.PNG | Bin 0 -> 152694 bytes www/Figures/Convex_Hulls_3D.PNG | Bin 0 -> 62480 bytes www/Figures/Expression_colors.png | Bin 0 -> 128780 bytes www/Figures/Network_view_interactive.png | Bin 0 -> 95103 bytes www/Figures/Pies.PNG | Bin 0 -> 129438 bytes www/Figures/Strategy_1.png | Bin 0 -> 140226 bytes www/Figures/Strategy_2.png | Bin 0 -> 231360 bytes www/Figures/Strategy_3.png | Bin 0 -> 186834 bytes www/Figures/Topology.PNG | Bin 0 -> 31998 bytes www/Figures/Topology_comparisons.PNG | Bin 0 -> 41165 bytes www/Figures/Upload-1.png | Bin 0 -> 114182 bytes www/Figures/Upload-2.png | Bin 0 -> 90593 bytes www/Figures/Upload-3.png | Bin 0 -> 106823 bytes www/Figures/venn.png | Bin 0 -> 73141 bytes www/annot_table.css | 600 +++ www/annotation_cleaner.R | 68 + www/favicon.ico | Bin 0 -> 496 bytes www/intro.css | 506 +++ www/intro.js | 2531 ++++++++++++ www/introbutton.js | 30 + www/norma.css | 91 + 194 files changed, 18360 insertions(+), 38054 deletions(-) delete mode 100644 .claude/launch.json delete mode 100644 .dockerignore delete mode 100644 .github/workflows/ci.yml delete mode 100644 .pre-commit-config.yaml delete mode 100644 .serena/.gitignore delete mode 100644 .serena/project.yml delete mode 100644 AGENTS.md delete mode 100644 CHANGELOG.md delete mode 100644 CLAUDE.md delete mode 100644 Dockerfile create mode 100644 NORMA.Rproj delete mode 100644 backend/norma/__init__.py delete mode 100644 backend/norma/api.py delete mode 100644 backend/norma/config.py delete mode 100644 backend/norma/handler.py delete mode 100644 backend/norma/main.py delete mode 100644 backend/norma/relays.py delete mode 100644 backend/norma/static.py delete mode 100644 backend/pyproject.toml delete mode 100755 backend/server.py delete mode 100644 backend/tests/conftest.py delete mode 100644 backend/tests/test_api.py delete mode 100644 backend/tests/test_config.py delete mode 100644 backend/tests/test_relays.py delete mode 100644 backend/tests/test_static_and_config_routes.py delete mode 100644 backend/uv.lock delete mode 100644 deploy/apache-normaviz.conf delete mode 100644 deploy/nginx.conf delete mode 100644 deploy/norma.service delete mode 100644 docker-compose.yml delete mode 100644 docs/NAR_CHECKLIST.md delete mode 100755 examples/norma_api_client.py delete mode 100644 frontend/.prettierignore delete mode 100644 frontend/.prettierrc delete mode 100644 frontend/e2e/helpers.ts delete mode 100644 frontend/e2e/smoke.spec.ts delete mode 100644 frontend/e2e/tsconfig.json delete mode 100644 frontend/eslint.config.js delete mode 100644 frontend/norma.html delete mode 100644 frontend/package-lock.json delete mode 100644 frontend/package.json delete mode 100644 frontend/playwright.config.ts delete mode 100644 frontend/public/assets/apple-touch-icon.png delete mode 100644 frontend/public/assets/banner.svg delete mode 100644 frontend/public/assets/favicon-32.png delete mode 100644 frontend/public/assets/favicon.ico delete mode 100644 frontend/public/assets/favicon.svg delete mode 100644 frontend/public/assets/logo.svg delete mode 100644 frontend/public/index.html delete mode 100644 frontend/public/norma-config.js delete mode 100644 frontend/src/api/tester.ts delete mode 100644 frontend/src/api/wiring.ts delete mode 100644 frontend/src/arena3d.test.ts delete mode 100644 frontend/src/arena3d.ts delete mode 100644 frontend/src/benchmark.ts delete mode 100644 frontend/src/clustering/clustering.test.ts delete mode 100644 frontend/src/clustering/label_propagation.ts delete mode 100644 frontend/src/clustering/leiden.ts delete mode 100644 frontend/src/clustering/mapping.ts delete mode 100644 frontend/src/clustering/mcl.ts delete mode 100644 frontend/src/clustering/values.test.ts delete mode 100644 frontend/src/clustering/walktrap.ts delete mode 100644 frontend/src/clustering/wiring.ts delete mode 100644 frontend/src/config.test.ts delete mode 100644 frontend/src/config.ts delete mode 100644 frontend/src/contours.ts delete mode 100644 frontend/src/cy.ts delete mode 100644 frontend/src/demo_downloads.ts delete mode 100644 frontend/src/directed_stats.ts delete mode 100644 frontend/src/enrichment.ts delete mode 100644 frontend/src/examples.ts delete mode 100644 frontend/src/export/dialog.ts delete mode 100644 frontend/src/export/draw.ts delete mode 100644 frontend/src/export/raster.ts delete mode 100644 frontend/src/export/shading.ts delete mode 100644 frontend/src/export/svg.ts delete mode 100644 frontend/src/export_norma.ts delete mode 100644 frontend/src/group_network.ts delete mode 100644 frontend/src/hulls.test.ts delete mode 100644 frontend/src/hulls.ts delete mode 100644 frontend/src/label_colors.ts delete mode 100644 frontend/src/layouts/controls.ts delete mode 100644 frontend/src/layouts/cose.worker.ts delete mode 100644 frontend/src/layouts/input.ts delete mode 100644 frontend/src/layouts/run.ts delete mode 100644 frontend/src/library.ts delete mode 100644 frontend/src/main.ts delete mode 100644 frontend/src/metrics.ts delete mode 100644 frontend/src/network_state.ts delete mode 100644 frontend/src/palette.ts delete mode 100644 frontend/src/parallel_edges.ts delete mode 100644 frontend/src/profiler.ts delete mode 100644 frontend/src/recording.ts delete mode 100644 frontend/src/sample_data.ts delete mode 100644 frontend/src/side_panel.ts delete mode 100644 frontend/src/side_tabs.ts delete mode 100644 frontend/src/state.ts delete mode 100644 frontend/src/string/groupings.ts delete mode 100644 frontend/src/string/import.ts delete mode 100644 frontend/src/string/requests.ts delete mode 100644 frontend/src/string/ui_state.ts delete mode 100644 frontend/src/string/wiring.ts delete mode 100644 frontend/src/style.css delete mode 100644 frontend/src/themes.ts delete mode 100644 frontend/src/uploads.ts delete mode 100644 frontend/src/view3d/cache.ts delete mode 100644 frontend/src/view3d/camera.ts delete mode 100644 frontend/src/view3d/draw.ts delete mode 100644 frontend/src/view3d/export.ts delete mode 100644 frontend/src/view3d/input.ts delete mode 100644 frontend/src/view3d/layouts.ts delete mode 100644 frontend/src/view3d/painters.ts delete mode 100644 frontend/src/view3d/state.ts delete mode 100644 frontend/src/view3d/tab.ts delete mode 100644 frontend/src/viewbar.ts delete mode 100644 frontend/src/welcome.ts delete mode 100644 frontend/src/wiring.ts delete mode 100644 frontend/tsconfig.json delete mode 100644 frontend/vite.config.ts delete mode 100644 frontend/vitest.setup.ts create mode 100644 functions/annotations.R create mode 100644 functions/helpDownloadHandlers.R create mode 100644 functions/network.R create mode 100644 functions/refreshing/convex_hulls_3D.R create mode 100644 functions/refreshing/modularity.R create mode 100644 functions/topology.R create mode 100644 functions/upload.R create mode 100644 global.R delete mode 100644 norma.config.hosted.json delete mode 100644 norma.config.json delete mode 100644 run_local.bat delete mode 100755 run_local.sh create mode 100644 server.R create mode 100644 ui.R create mode 100644 user_temp/folder_create create mode 100644 views/about.R create mode 100644 views/annotations.R create mode 100644 views/help.R create mode 100644 views/network.R create mode 100644 views/topology.R create mode 100644 views/upload.R create mode 100644 views/welcome.R create mode 100644 www/Examples/BCAR3/BCAR3.txt create mode 100644 www/Examples/BCAR3/BCAR3_GO_BP.txt create mode 100644 www/Examples/BCAR3/BCAR3_GO_MF.txt create mode 100644 www/Examples/BCAR3/BCAR3_KEGG.txt create mode 100644 www/Examples/BioGrid_Chicken_Gallus/BioGrid_Chicken_Gallus_Pathways_KEGG_PATHWAY_FILTERED.txt create mode 100644 www/Examples/BioGrid_Chicken_Gallus/Biogrid_no_self_loops.txt create mode 100644 www/Examples/Human_Coexpression/NORMA_Human_coexpression_Annotation_GO_BP.txt create mode 100644 www/Examples/Human_Coexpression/NORMA_Human_coexpression_Annotation_GO_CC.txt create mode 100644 www/Examples/Human_Coexpression/NORMA_Human_coexpression_Annotation_GO_MF.txt create mode 100644 www/Examples/Human_Coexpression/NORMA_Human_coexpression_Annotation_KEGG.txt create mode 100644 www/Examples/Human_Coexpression/NORMA_Human_coexpression_Expression_MCODE.txt create mode 100644 www/Examples/Human_Coexpression/NORMA_Human_coexpression_NETWORK.txt create mode 100644 www/Examples/IntAct_COVID19/HomoSapiens_Gene_Ontology_GOTERM_BP_DIRECT_FILTERED.txt create mode 100644 www/Examples/IntAct_COVID19/HomoSapiens_Gene_Ontology_GOTERM_CC_DIRECT_FILTERED.txt create mode 100644 www/Examples/IntAct_COVID19/HomoSapiens_Gene_Ontology_GOTERM_MF_DIRECT_FILTERED.txt create mode 100644 www/Examples/IntAct_COVID19/HomoSapiens_Pathways_KEGG_PATHWAY_FILTERED.txt create mode 100644 www/Examples/IntAct_COVID19/HomoSapiens_Protein_Domains_INTERPRO_FILTERED.txt create mode 100644 www/Examples/IntAct_COVID19/HomoSapiens_Protein_Domains_SMART_FILTERED.txt create mode 100644 www/Examples/IntAct_COVID19/Intact-data_COVID19_no_self_loops.txt create mode 100644 www/Examples/TAU/TAU_KEGG_Annotation_NORMA.txt create mode 100644 www/Examples/TAU/TAU_Louvain.txt create mode 100644 www/Examples/TAU/TAU_expressions.txt create mode 100644 www/Examples/TAU/TAU_network_DEGs_NORMA.txt create mode 100644 www/Examples/TP53/string_expression_colors.txt create mode 100644 www/Examples/TP53/string_interactions.txt create mode 100644 www/Examples/TP53/string_interactions_groups_comma_duplicate.txt create mode 100644 www/Figures/Banner.png create mode 100644 www/Figures/Community_detection_algorithms.png create mode 100644 www/Figures/Convex_Hulls.PNG create mode 100644 www/Figures/Convex_Hulls_3D.PNG create mode 100644 www/Figures/Expression_colors.png create mode 100644 www/Figures/Network_view_interactive.png create mode 100644 www/Figures/Pies.PNG create mode 100644 www/Figures/Strategy_1.png create mode 100644 www/Figures/Strategy_2.png create mode 100644 www/Figures/Strategy_3.png create mode 100644 www/Figures/Topology.PNG create mode 100644 www/Figures/Topology_comparisons.PNG create mode 100644 www/Figures/Upload-1.png create mode 100644 www/Figures/Upload-2.png create mode 100644 www/Figures/Upload-3.png create mode 100644 www/Figures/venn.png create mode 100644 www/annot_table.css create mode 100644 www/annotation_cleaner.R create mode 100644 www/favicon.ico create mode 100644 www/intro.css create mode 100644 www/intro.js create mode 100644 www/introbutton.js create mode 100644 www/norma.css diff --git a/.claude/launch.json b/.claude/launch.json deleted file mode 100644 index 70d7ae1..0000000 --- a/.claude/launch.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "version": "0.0.1", - "configurations": [ - { "name": "norma", "runtimeExecutable": "python3", "runtimeArgs": ["backend/server.py", "--mode", "local", "--port", "8765", "--no-open"], "port": 8765 } - ] -} diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 98f7754..0000000 --- a/.dockerignore +++ /dev/null @@ -1,20 +0,0 @@ -# Keep the build context to what the image needs. -.git -.github -.serena -.claude -docs -deploy -tests -backend/tests -backend/.venv -backend/.ruff_cache -backend/.mypy_cache -backend/.pytest_cache -frontend/node_modules -frontend/dist -frontend/test-results -frontend/playwright-report -frontend/e2e -**/__pycache__ -*.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 1119d14..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,46 +0,0 @@ -name: CI - -on: - push: - branches: [master, NORMA_v3, update_architecture] - pull_request: - -jobs: - backend: - runs-on: ubuntu-latest - defaults: - run: { working-directory: backend } - steps: - - uses: actions/checkout@v4 - - uses: astral-sh/setup-uv@v5 - - run: uv sync --frozen - - run: uv run ruff check . - - run: uv run ruff format --check . - - run: uv run mypy norma - - run: uv run pytest - - frontend: - runs-on: ubuntu-latest - defaults: - run: { working-directory: frontend } - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: { node-version: 22, cache: npm, cache-dependency-path: frontend/package-lock.json } - - run: npm ci - - run: npm run lint - - run: npx prettier --check src e2e - - run: npx tsc --noEmit - - run: npm test -- --run - - run: npm run build - - e2e: - runs-on: ubuntu-latest - needs: [backend, frontend] - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: { node-version: 22, cache: npm, cache-dependency-path: frontend/package-lock.json } - - run: cd frontend && npm ci && npx playwright install --with-deps chromium - # playwright.config.ts builds the page and starts backend/server.py itself - - run: cd frontend && npm run test:e2e diff --git a/.gitignore b/.gitignore index 401f651..4a1f431 100644 --- a/.gitignore +++ b/.gitignore @@ -40,16 +40,3 @@ vignettes/*.pdf user_temp/*.html user_temp/*.rda - -# Python -__pycache__/ -.pytest_cache/ -.ruff_cache/ -.mypy_cache/ -.venv/ - -# Node -node_modules/ -frontend/dist/ -frontend/test-results/ -frontend/playwright-report/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index d2e1dd3..0000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,30 +0,0 @@ -repos: - - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.15.0 - hooks: - - id: ruff-check - args: [--fix] - files: ^backend/ - - id: ruff-format - files: ^backend/ - - - repo: local - hooks: - - id: eslint - name: eslint - language: system - entry: bash -c 'cd frontend && npx eslint src e2e' - files: ^frontend/(src|e2e)/.*\.ts$ - pass_filenames: false - - id: prettier - name: prettier - language: system - entry: bash -c 'cd frontend && npx prettier --check src e2e' - files: ^frontend/(src|e2e)/ - pass_filenames: false - - id: tsc - name: tsc - language: system - entry: bash -c 'cd frontend && npx tsc --noEmit' - files: ^frontend/.*\.ts$ - pass_filenames: false diff --git a/.serena/.gitignore b/.serena/.gitignore deleted file mode 100644 index 2e510af..0000000 --- a/.serena/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/cache -/project.local.yml diff --git a/.serena/project.yml b/.serena/project.yml deleted file mode 100644 index 1d3b834..0000000 --- a/.serena/project.yml +++ /dev/null @@ -1,169 +0,0 @@ -# the name by which the project can be referenced within Serena/when chatting with the LLM. -project_name: "NORMA" - -# list of language servers to start when using the LSP backend; choose from: -# ada al angular ansible bash -# bsl clojure cpp cpp_ccls crystal -# csharp csharp_omnisharp cue dart deno -# elixir elm erlang fortran fsharp -# gdscript gleam go groovy haskell -# haxe hlsl html java json -# julia kotlin latex lean4 lua -# luau markdown matlab msl nextflow -# nix ocaml pascal perl php -# php_phpactor php_phpantom powershell python python_basedpyright -# python_jedi python_pyrefly python_ty qml r -# rego ruby ruby_solargraph rust scala -# scss solidity svelte swift systemverilog -# terraform toml typescript typescript_vts vue -# wolfram yaml zig -# (This list may be outdated; generated with scripts/print_language_list.py; -# For the current list, see values of the LanguageServerId enum here: -# https://github.com/oraios/serena/blob/main/src/solidlsp/ls_config.py) -# For some languages, there are several alternative language servers, e.g. csharp_omnisharp, ruby_solargraph.) -# Note: -# - For C, use cpp -# - For JavaScript, use typescript -# - For Angular projects, use angular (subsumes typescript+html; requires `npm install` in the project root) -# - For Svelte projects, use svelte (subsumes typescript/javascript for .svelte projects; requires npm) -# - For Deno projects, use deno (serves the same .ts/.js files as typescript; requires the deno CLI on PATH) -# - For SCSS / Sass / plain CSS, use scss (some-sass-language-server handles all three) -# - For Free Pascal/Lazarus, use pascal -# Special requirements: -# Some language servers require additional setup/installations. -# See here for details: https://oraios.github.io/serena/01-about/020_programming-languages.html#language-servers -# When using multiple language servers, the first language server that supports a given file will be used for that file. -# The first language server is the default language and the respective language server will be used as a fallback. -# Note that when using the JetBrains backend, language servers are not used and this list is correspondingly ignored. -language_servers: -- typescript - -# the encoding used by text files in the project -# For a list of possible encodings, see https://docs.python.org/3.11/library/codecs.html#standard-encodings -encoding: "utf-8" - -# optional shell command to run before the language backend (LSP or JetBrains) is initialised. -# the command runs in the project root directory and is only executed if the project is trusted -# (see trusted_project_path_patterns in the global configuration). -# serena waits for the command to exit: a non-zero exit code is logged as an error but does not -# abort activation. a per-project timeout (activation_command_timeout, default 180s) is the safety -# backstop for non-terminating commands; on expiry the process is killed and activation continues. -# example: activation_command: "npx nx run-many -t build" -activation_command: - -# maximum time in seconds to wait for activation_command to complete before killing it (default 180s). -# must be a positive number. -activation_command_timeout: 180.0 - -# line ending convention to use when writing source files. -# Possible values: unset (use global setting), "lf", "crlf", or "native" (platform default) -# This does not affect Serena's own files (e.g. memories and configuration files), which always use native line endings. -line_ending: - -# The language backend to use for this project. -# If not set, the global setting from serena_config.yml is used. -# Valid values: LSP, JetBrains -# Note: the backend is fixed at startup. If a project with a different backend -# is activated post-init, an error will be returned. -language_backend: - -# whether to use project's .gitignore files to ignore files -ignore_all_files_in_gitignore: true - -# advanced configuration option allowing to configure language server-specific options. -# Maps the language key to the options. -# The settings are considered only if the project is trusted (see global configuration to define trusted projects). -# See https://oraios.github.io/serena/02-usage/050_configuration.html#language-server-specific-settings -ls_specific_settings: {} - -# list of workspace folder paths (LSP backend only). -# These folders will be used to build up Serena's symbol index. -# Paths must be within the project root and should thus be relative to the project root. -# Furthermore, the paths should not be filtered by ignore settings. -# Default setting: The entire project root folder (".") is considered. -# In (large) monorepos, this can be used to index only subfolders of the project root, e.g. -# ls_workspace_folders: -# - "./subproject1" -# - "./subproject2" -ls_workspace_folders: -- "." - -# list of additional workspace folder paths for cross-package reference support. -# Paths can be absolute or relative to the project root. -# Each folder is registered as an LSP workspace folder, enabling language servers to discover -# symbols and references across package boundaries, but these folders are not indexed by Serena, -# i.e. the respective symbols will not be found using Serena's symbol search tools. -# Example: -# additional_workspace_folders: -# - ../sibling-package -# - ../shared-lib -ls_additional_workspace_folders: [] - -# list of additional paths to ignore in this project. -# Same syntax as gitignore, so you can use * and **. -# Important: quote patterns that start with `*`, otherwise YAML treats them as aliases. -# Example: -# ignored_paths: -# - "examples/**" -# - ".worktrees/**" -# - "**/bin/**" -# - "**/obj/**" -# Note: global ignored_paths from serena_config.yml are also applied additively. -ignored_paths: [] - -# whether the project is in read-only mode -# If set to true, all editing tools will be disabled and attempts to use them will result in an error -# Added on 2025-04-18 -read_only: false - -# list of tool names to exclude. -# This extends the existing exclusions (e.g. from the global configuration) -# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html -excluded_tools: [] - -# list of tools to include that would otherwise be disabled (particularly optional tools that are disabled by default). -# This extends the existing inclusions (e.g. from the global configuration). -# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html -included_optional_tools: [] - -# fixed set of tools to use as the base tool set (if non-empty), replacing Serena's default set of tools. -# This cannot be combined with non-empty excluded_tools or included_optional_tools. -# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html -fixed_tools: [] - -# list of mode names that are to be activated by default, overriding the setting in the global configuration. -# The full set of modes to be activated is base_modes (from global config) + default_modes + added_modes. -# If the setting is undefined/empty, the default_modes from the global configuration (serena_config.yml) apply. -# Otherwise, this overrides the setting from the global configuration (serena_config.yml). -# Therefore, you can set this to [] if you do not want the default modes defined in the global config to apply -# for this project. -# This setting can, in turn, be overridden by CLI parameters (--mode). -# See https://oraios.github.io/serena/02-usage/050_configuration.html#modes -default_modes: - -# list of mode names to be activated additionally for this project, e.g. ["query-projects"] -# The full set of modes to be activated is base_modes (from global config) + default_modes + added_modes. -# See https://oraios.github.io/serena/02-usage/050_configuration.html#modes -added_modes: - -# initial prompt for the project. It will always be given to the LLM upon activating the project -# (contrary to the memories, which are loaded on demand). -initial_prompt: "" - -# time budget (seconds) per tool call for the retrieval of additional symbol information -# such as docstrings or parameter information. -# This overrides the corresponding setting in the global configuration; see the documentation there. -# If null or missing, use the setting from the global configuration. -symbol_info_budget: - -# list of regex patterns which, when matched, mark a memory entry as read‑only. -# Extends the list from the global configuration, merging the two lists. -read_only_memory_patterns: [] - -# list of regex patterns for memories to completely ignore. -# Matching memories will not appear in list_memories or activate_project output -# and cannot be accessed via read_memory or write_memory. -# To access ignored memory files, use the read_file tool on the raw file path. -# Extends the list from the global configuration, merging the two lists. -# Example: ["_archive/.*", "_episodes/.*"] -ignored_memory_patterns: [] diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index ad0f1c3..0000000 --- a/AGENTS.md +++ /dev/null @@ -1,107 +0,0 @@ -# AGENTS.md - -Guidance for coding agents (Claude Code, Codex, …) working in this repository. - -NORMA 3 (The Network Makeup Artist) visualises and analyses networks together with their annotated -groups. It is a **browser application** (Vite / TypeScript / Cytoscape.js, in `frontend/`) served by a -**dependency-free Python server** (`backend/`, standard library only) that adds the REST API and the -STRING / Arena3D / database relays. Everything computational (layouts, clustering, statistics, -exports) runs in the browser; the server never sees network data except for the token API. - -The app was migrated from R/Shiny (branch `master`) to this stack (branches `NORMA_v3`, -`update_architecture`). The architecture decisions live in `docs/superpowers/specs/`. - -## Rules for Agents - -- **Never push to remote.** Commit only when explicitly asked, one commit per feature. -- **Always use the `token-saviour` skill** — and the tools/skills it routes to — wherever it makes sense. -- **When a plan is active** (`docs/superpowers/plans/*.md`): one feature per commit, tick the checkboxes - as you go, and verify each feature at runtime before moving to the next. -- **Before every commit**: run lint, typecheck and the relevant test suite (commands below). Verify UI - changes at runtime with Playwright. -- **Keep the server dependency-free.** `backend/` must run with a plain `python3`; dev tools (pytest, - ruff, mypy) go in the `dev` group only. -- **Keep the single-file build working.** `frontend/dist/norma.html` must open from disk without a server. -- **Keep responses concise** — summarise rather than dumping full files. - -## Running the App - -**Backend** (no runtime dependencies; `uv` only for dev tools): -```bash -python3 backend/server.py # http://localhost:8000, serves frontend/dist -python3 backend/server.py --help # every option; also norma.config.json / NORMA_* env -cd backend && uv sync # dev tools into .venv -``` - -**Frontend:** -```bash -cd frontend -npm install -npm run dev # http://localhost:5173 — /api, /string-api, … proxied to :8000 -npm run build # frontend/dist/ (norma.html is self-contained) -``` - -**Docker:** `docker compose up -d` (two-stage image: node build → python:slim). - -**Tests:** -```bash -cd backend && uv run pytest # server unit/integration tests (fake upstreams, no network) -cd frontend && npm test # Vitest unit tests -cd frontend && npm run test:e2e # Playwright (starts backend/server.py itself) -``` - -**Lint / format / typecheck:** -```bash -cd backend && uv run ruff check . && uv run ruff format . && uv run mypy norma -cd frontend && npm run lint && npm run format && npx tsc --noEmit -``` - -`pre-commit install` wires the same checks into git. - -## Architecture Overview - -### Backend (`backend/norma/`) -`http.server`-based, stateless apart from the in-memory token store. -- `config.py` — `DEFAULTS`, `ENV_MAP`, `load_config` (defaults < JSON file < `NORMA_*` env < CLI), - `client_config` (the subset sent to the page as `/norma-config.js`). -- `api.py` — token store for `POST /api/external` / `GET /api/session/TOKEN` (TTL, size and count caps). -- `relays.py` — read-only relays to STRING, Arena3D and the database importers; strict upstream - allowlists, body limits, rate spacing. -- `handler.py` — `NormaHandler` routing, security headers, access log; `ThreadingServer`, `RedirectHandler`. -- `static.py` — static root (`frontend/dist`) and the blocklist for deployment files. -- `main.py` — argparse, TLS, browser opening, serve loop. `backend/server.py` is the entry point. - -### Frontend (`frontend/src/`) -The former 15K-line ` - - - - -
- -
- -
3.0The Network Makeup Artist
-
- -
- -
- -
- - - - - - -
- - - -
-
- -
- - -
- -
-
- - - - - -
- -
- -
-
-
- 0 nodes - 0 edges - 0 channels - 0 groups - -
-
- - - - -
-

Delete file

- -
-
- - -
-
-
- - -
-

Export image

-

Saves the current view as it looks, including group shading, shapes and labels.

-
- Format - - - - - -
-
- - - - - -

- -
- - -
- -
.png
-
- - - -
-
- - -
-
-
- - - -
- -
- - - - - -
Drag nodes · Shift-drag or Shift-click to select several · scroll to zoom · double-click to recenter
-
- - - - - 100% -
- - -
- -

-
- -
-
- -
-
-
- -
-
Source
-
Target
-
Direction
-
Edge ID
-
-
-
- -
-
-
-
- -
-

The Network Makeup Artist

-

See how annotated groups sit in a network: bubble sets, hulls and fog clouds, pie nodes and shapes, group-aware layouts, numeric values, a 3D view, communities, enrichment and network comparison.

-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Bubble-set groups -outlines that hug only the members - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -−2 -0 -2 -log2FC -Numeric values -color scales, sizes, legends, steps - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Ribosome - -Proteasome - -Spliceosome - -Glycolysis - -−log10 FDR -Communities and enrichment -Leiden, MCL, Walktrap; term tests - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -3D network -rotate, tilt and zoom freely - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -A - -B - -C -shared -edges -Compare networks -UpSet plots, Venn diagrams, statistics -
-
    -
  1. Load a networkupload files, fetch one from a database, or open an example
  2. -
  3. Add groups and valuesannotations, expression colors or numbers, communities
  4. -
  5. Arrange, analyse, sharelayouts, statistics, images, Arena3D, Cytoscape, Gephi
  6. -
-
- - - - -
- -

NORMA 3.0 runs in your browser: your files stay on this computer, except what you send to online databases or Arena3D yourself. Networks of up to 10,000 nodes.

-
-
-
- -
-
-
-

Network Profiler

-

Topology statistics for one or more networks, computed the way igraph computes them. Each network is treated as a simple undirected graph: self-loops and parallel edges are set aside first.

-
-
-
-
Networks to profile
-
-
-
- - - -
-
-
-
-
-

Group analysis (current view)

-

Statistics of the ticked groups of the current view, the network of groups, and an enrichment test, all on the shown part of the view (ticked groups and channels).

-
- - - -
-
-
-

Enrichment

-

Tests whether groups of an annotation (terms) are over-represented, with a one-sided hypergeometric test and Benjamini–Hochberg FDR per tested set.

-
- - - -
- - - - - - - - -
-
-
- - -
-
-
-
-
-

Layout benchmark

-

Runs every layout on the current view (its ticked groups and channels) without changing it, and scores how well each separates the groups: the silhouette width of the node positions (higher is better), the share of nodes inside another group's outline, and how much the outlines overlap (lower is better). Group layouts use the settings of the Layout section.

-
- - - -
-
-
-
-
-

Runtime table

-

Times the main steps on random networks of growing size (generated from fixed seeds; the table lists their edges), in this browser: reading the network file, building the network, the weighted layout, edge bundling, the profile statistics, Louvain and the group separation score. The view is not changed.

-
- - - -
-
-
-
-
-
- -
-
-
-

Network Comparison

-

Compare two to ten networks from your open views or from the network files: which nodes and edges they share, how similar they are, whether hubs stay hubs, and how their topology differs.

-
-
-
-
Networks to compare
-
-
-
- - - - -
- -
-
-
-
-
- -
-
-

NORMA API

-

Other applications can open NORMA with their own networks, groups and values, so that a pathway database, an analysis pipeline, a notebook or a web page can show its results in NORMA with one call. There are three ways in, all taking the same payload:

-
-
RESTPOST the payload to /api/external on a server running server.py; open the link it returns. Works from any language.
-
LinksA link to norma.html that points to the data (?data=, ?network=) or carries it (#json=). Needs no server.
-
postMessageA web page opens NORMA in a window or an iframe and sends it the payload directly. Needs no server.
-
- -

This copy of NORMA answers at …

-
- Python template script -

A ready-to-run client that checks a NORMA server, sends a network with groups, reads the stored payload back and builds a link that needs no server; it parses every answer and uses only Python's standard library. Adapt its build_payload() to your data.

-

python3 norma_api_client.py --server http://localhost:8000/ --open

-
- -

The payload

-

A JSON object. Give the network in one of three forms, and add groups, values and settings as needed:

- - - - - - - - - - - - - - - - -
FieldTypeMeaning
nametextThe view's name (and the prefix of its files in Files).
edgeslistThe network as {"source", "target"} objects, each optionally with type (the channel), weight (a number) and directed (true/false).
nodeslistOptional, with edges: {"id", …} objects whose other fields become node attributes (shown in node details and searchable).
filesobjectThe network as NORMA files instead: network (text, or a list for several networks), annotation (text or list) and expression (text), in the tab-separated formats. A list item can be {"name", "text"}.
networkobjectOr a complete NORMA view (nodes, edges, groupOrder, …) as saved by Save view file; see JSON format.
groupsobject or list{"Group": ["node", …]}, or [{"name", "members", "color", "description"}]. Nodes may be in several groups.
annotationslistMore groupings, each {"name", "groups"}; the view's Grouping list switches between them.
expressionobject{"node": "#e11d48"} (colors), {"node": 1.7} (one numeric value) or {"node": {"t0": 0.2, "t1": 1.4}} (several columns, e.g. time points).
directedtrue/falseRead files.network as directed.
settingsobjectDisplay settings by their names in a settings file (for example edgeDirection, edgeCurveStyle, showGroupHulls, hullStyle, nodeFillSelect, legendShow), plus theme and layout (fr, kk, stress, cose, circle, …).
tabtext"3d" opens the 3D page instead of the 2D page.
format / views—A whole session file ("format": "norma3-session") can be sent as the payload too.
-

With edges or files, NORMA adds the network, groupings and values to Files like uploaded files and opens them in a new view, so everything in NORMA works on them. Networks larger than 10,000 nodes are cut to their first 10,000. The example in Try it shows all common fields.

- -

REST

-

When NORMA runs with server.py (see Running NORMA locally or on a server), the server offers:

- - - - - - - - -
Web services (all answer in JSON)
RequestAnswer
POST /api/external with the payload as JSON (Content-Type: application/json){"token", "url", "expiresInHours"}. Open url in a browser: NORMA starts with the payload loaded.
GET /api/session/TOKENThe stored payload (NORMA fetches it when opened with ?session=TOKEN); 404 once it has expired.
GET /api/health{"status": "ok", "api": "1.0"}, to check that a server offers the API.
-

The token is made by the server; you never build the link yourself. Payloads are kept in the server's memory for 24 hours (set NORMA_API_TTL_HOURS), up to 50 MB each; the API accepts calls from any web page (CORS).

-

curl

-
curl -X POST http://localhost:8000/api/external \
-  -H "Content-Type: application/json" \
-  -d '{"name": "My network",
-       "edges": [{"source": "A", "target": "B"}, {"source": "B", "target": "C"}],
-       "groups": {"Module 1": ["A", "B"], "Module 2": ["C"]}}'
-
-# answer:
-# {"token": "k3J9…", "url": "http://localhost:8000/norma.html?session=k3J9…",
-#  "expiresInHours": 24}
-

Python

-
import requests, webbrowser
-
-payload = {
-    "name": "My network",
-    "edges": [{"source": s, "target": t} for s, t in [("A", "B"), ("B", "C"), ("C", "A")]],
-    "groups": {"Module 1": ["A", "B"], "Module 2": ["C"]},
-    "expression": {"A": 1.5, "B": -0.4, "C": 2.1},
-    "settings": {"layout": "fr", "showGroupHulls": True},
-}
-r = requests.post("http://localhost:8000/api/external", json=payload, timeout=30)
-r.raise_for_status()
-webbrowser.open(r.json()["url"])      # opens NORMA with the network
-

R

-
library(httr)
-payload <- list(
-  name   = "My network",
-  edges  = data.frame(source = c("A", "B"), target = c("B", "C")),
-  groups = list(`Module 1` = c("A", "B"), `Module 2` = list("C"))
-)
-r <- POST("http://localhost:8000/api/external", body = payload, encode = "json")
-browseURL(content(r)$url)
-

JavaScript

-
const r = await fetch("http://localhost:8000/api/external", {
-  method: "POST",
-  headers: { "Content-Type": "application/json" },
-  body: JSON.stringify({ name: "My network", edges, groups }),
-});
-const { url } = await r.json();
-window.open(url, "_blank");
- - -

Links need no server: any copy of norma.html, on a web server or opened from disk, reads them when it starts.

-
http://localhost:8000/norma.html?data=https://example.org/my-payload.json
-http://localhost:8000/norma.html?network=https://example.org/net.txt&annotation=https://example.org/groups.txt&expression=https://example.org/values.txt&layout=fr
-http://localhost:8000/norma.html#json=eyJuYW1lIjoiTXkgbmV0d29yayIsImVkZ2VzIjpb…
-
    -
  • ?data=URL fetches a payload file. ?network=, ?annotation= and ?expression= fetch NORMA files; add &name=, &layout=, &theme= or &tab=3d if you like. The site holding the files must allow cross-site downloads (CORS), as GitHub raw files, Zenodo and most data portals do.
  • -
  • #json= carries the payload itself, as base64url-encoded JSON. It suits small networks (links longer than a few thousand characters may be cut by chat and mail programs); the part after # is never sent to any server. Make a link below builds one.
  • -
-

A button on your own site:

-
<a href="http://localhost:8000/norma.html?data=https://example.org/pathway-42.json"
-   target="_blank">Open in NORMA</a>
- -

postMessage

-

A web page can open NORMA and hand it data directly, with no server and no size limit other than the browser's. NORMA sends {"type": "norma:ready"} to the page that opened or embedded it when it has started (and answers {"type": "norma:ping"} the same way). Send {"type": "norma:load", "payload": …, "requestId": …}; NORMA answers {"type": "norma:loaded", "ok": true, "summary": …} or {"ok": false, "error": …} with the same requestId. Each load opens a new view, so a page can send several networks.

-

In a new window

-
// open NORMA (any copy: a file, a web server or server.py)
-const norma = window.open("http://localhost:8000/norma.html", "_blank");
-
-window.addEventListener("message", (e) => {
-  if (e.source !== norma) return;
-  if (e.data.type === "norma:ready") {           // NORMA has started
-    norma.postMessage({
-      type: "norma:load",
-      requestId: 1,
-      payload: { name: "My network", edges, groups, expression },
-    }, "*");
-  }
-  if (e.data.type === "norma:loaded") {          // the answer
-    console.log(e.data.ok ? e.data.summary : e.data.error);
-  }
-});
-

In an iframe

-
<iframe id="norma" src="norma.html" style="width:100%;height:700px;border:0"></iframe>
-<script>
-  const frame = document.getElementById("norma");
-  window.addEventListener("message", (e) => {
-    if (e.data.type === "norma:ready")
-      frame.contentWindow.postMessage({ type: "norma:load", payload }, "*");
-  });
-</script>
- -

Try it

-

Edit the payload and choose what to do with it.

- -
- - - - -
-
- - -
-
- -

Limits and privacy

-
    -
  • Payloads up to 50 MB; networks up to 10,000 nodes are shown in full.
  • -
  • Data sent with postMessage or #json links stays in the browser. With REST, the payload is kept only in the memory of the server you sent it to, for the time set there, and anyone with the link can open it until then; don't use it for confidential data on a shared server.
  • -
  • NORMA only displays what it receives: payloads cannot run code, and NORMA sends nothing back except the norma:loaded summary to the page that asked.
  • -
-
-
- -
-
- -
-
- How to cite NORMA -

If NORMA helps your work, please cite:

-
    -
  • Karatzas E, Koutrouli M, Baltoumas FA, Papanikolopoulou K, Bouyioukos C, Pavlopoulos GA. The network makeup artist (NORMA-2.0): distinguishing annotated groups in a network using innovative layout strategies. Bioinformatics Advances. 2022;2(1):vbac036. doi:10.1093/bioadv/vbac036
  • -
  • Koutrouli M, Karatzas E, Papanikolopoulou K, Pavlopoulos GA. NORMA: The Network Makeup Artist, a web tool for network annotation visualization. Genomics, Proteomics & Bioinformatics. 2022;20(3):578–586. doi:10.1016/j.gpb.2021.02.005
  • -
-

Please also cite the databases and methods you use; see Resources and methods.

-
-

This is NORMA's technical help: how to load data, use each control and page, save your work and run NORMA on a server. For an overview of NORMA, its data sources, what's new and how to cite it, see About.

- -
Getting started
-

Getting started

-

NORMA 3.0 shows networks whose nodes belong to groups (annotations) and whose node pairs can be linked by several kinds of edge (channels); unlike earlier versions of NORMA, it handles these multi-edge networks. The application is a single file, norma.html, that opens in a browser. It starts on the Welcome tab, which shows what NORMA does and offers quick ways to open an example, fetch a network from a database or upload files; the tab stays there, so you can always go back to it. Opening a network moves to 2D Network. It reads the same tab-delimited files as NORMA, plus a richer JSON format.

-

The screen has eight pages. Welcome is the start page, 2D Network is the interactive view, 3D Network shows the same view in three dimensions, Network Profiler computes topology statistics and group analyses, Network Comparison sets up to ten networks side by side, API explains how other programs can open NORMA with their data, Help is this page, and About describes NORMA, its data sources and how to cite it. The NORMA logo at the top left always leads back to Welcome. The ? next to a sidebar heading opens the matching section here. Finding your way around explains the rest of the screen.

-
    -
  1. Upload your files or open an example in the sidebar's Upload Data tab, or fetch a network from a database (STRING, Reactome, OmniPath, NDEx, IntAct or GO-CAM) in the Database importers tab.
  2. -
  3. Tick networks and choose an annotation and an expression file, then choose Open in new view.
  4. -
  5. Style that view in the Display tab: layout, groups, colors, sizes, labels and edges.
  6. -
  7. Repeat with other combinations. Each becomes its own view; switch between them with the View list in the top bar.
  8. -
  9. Save a picture with Export image (camera button, top bar), or the data in other formats with the Export tab.
  10. -
- -

Finding your way around

-
    -
  • Top bar (purple): the View list, which picks the visualization you are working on, with Duplicate, Rename and Delete…, and the Grouping list (amber), which switches the current view to any annotation in Files while keeping node positions. For views opened from a built-in demo or a JSON file, the groups come with the data and the list only shows how many there are. On the right are Export image (the camera button), undo and redo and the theme.
  • -
  • Page tabs: Welcome (the start page, always available), 2D Network, 3D Network, Network Profiler, Network Comparison and Help. In the row below them, three colored labels say what the current view shows: the Network (blue), the Grouping with its number of groups (amber) and where node Colors come from (pink). Hover a label for its full text. At the right end of that row are the numbers of nodes, edges, channels and groups, with a directed or mixed direction tag when edges have a direction; when some groups are unticked, the group count reads, for example, 8/9. The labels and counts stay visible on every page, so the Network Profiler and Network Comparison pages always tell you which view "Current view" means.
  • -
  • Sidebar tabs: Upload Data (blue) holds examples, your files and opening saved work; Database importers (red) fetches networks and groupings from STRING, Reactome, OmniPath, NDEx, IntAct and the Gene Ontology; Export (purple) saves pictures, files for NORMA and other tools, Arena3D networks and sessions; Display (green) holds everything about how the current view looks. The Examples list only chooses what Open example opens next; it doesn't show what is on screen. The View list and the colored labels do.
  • -
  • Opening and closing sections: click a section's title (or focus it and press Enter or Space) to fold it away or open it again; the ? in a title opens its help instead. All sections start folded, so each tab shows a short list of titles; open the ones you need. Inside a section, small colored headings with a line (for example Direction and arrows or Session file (.json)) separate groups of related options.
  • -
  • Section order and colors: every sidebar section has a color of its own, and neighbouring sections always have clearly different ones. Upload Data: Examples (green), Files (blue) and Open saved work (purple). Database importers: STRING (red), Reactome (blue), OmniPath (teal), NDEx (orange), IntAct (green) and Gene Ontology (purple); click an importer's title to open or close it. Export: NORMA files (blue), Image (pink), Other tools (orange), Save your work (slate) and Arena3D (teal). The Display tab starts with the groups and how they are drawn and placed, then the look of nodes and edges, then extras: Node groups (amber), Group highlighting (magenta), Layout (green; 3D layout, teal, on the 3D page), Colors (pink), Nodes (sky blue), Labels (orange), Edges (slate), Edge channels (lime), Legend (crimson), Attributes (cyan) and Performance (brown). The labels below the page tabs use the matching colors: Network blue like Files, Grouping amber like Node groups, and Colors pink like Colors.
  • -
- -

Views

-

A view is one visualization: a set of networks with an annotation and an expression file, or an example or JSON file, together with how it looks. Each view keeps its own display settings, node positions, zoom, ticked groups and channels, group colors and shapes, channel colors, edge style including bundling, and its 3D positions and camera, so you can prepare several pictures from the same uploads and move between them without losing work. The theme and the search options apply to every view.

-
    -
  • Duplicate copies the current view, for example to compare two annotations or two layouts of the same network.
  • -
  • Rename names the current view; press Enter to keep the name or Escape to cancel.
  • -
  • Grouping (top bar) regroups the current view by another annotation, or by none, and keeps node positions; the same as ticking an annotation in Files and choosing Show in this view.
  • -
-

In the Upload Data tab, Show in this view replaces what the current view shows with the ticked files and keeps its display settings; if only the annotation or expression file changed, node positions are kept. Open in new view shows the ticked files in a new view and leaves the current one as it was. Open example always opens a new view, reusing an empty untitled one if there is one.

- -

Undo and redo

-

The arrows in the top bar undo and redo changes to the current view: moved nodes, layouts, spread, display settings, ticked groups and channels, group and channel colors, and switching or clearing what the view shows. Keyboard: Ctrl+Z (⌘Z on a Mac) undoes, Ctrl+Shift+Z or Ctrl+Y redoes. A quick series of changes, such as dragging a slider or a layout's animation, counts as one step. Each view has its own history of up to 60 steps, kept while the page is open. Zooming, panning, searching, selecting and the theme are not part of the history.

- -
Data
-

Examples

-

The first block of the list holds NORMA's example datasets. The TP53 documentation example also brings a small file of simulated log2 fold changes and adjusted p-values, for trying the numeric color scale; tick it under Expressions. Opening one adds its network, annotations and expression file to Files, selects them and shows the result in a new view. Their other annotations stay in the list so you can switch between them.

- - - - - - - - - - - - - - -
ExampleFilesSource
STRING: TP53 interactorsNetwork (weighted), groups, expressionSTRING
STRING: BCAR3 interactorsNetwork; GO biological process, GO molecular function, KEGGSTRING
Drosophila Tau networkNetwork; KEGG, Louvain communities; expressionPMID 31488613, doi:10.1523/JNEUROSCI.0391-19.2019
Human gene co-expressionNetwork; GO biological process, molecular function, cellular component; KEGG; MCODE cluster colorsPMID 19081792, doi:10.1371/journal.pone.0003911, bioinfow.dep.usal.es/coexpression
COVID-19Network; InterPro, SMART, GO (three), KEGGIntAct
Gallus gallusNetwork; KEGGBioGRID
Signalling cascade (showcase)Directed multi-edge network with five channels; four cascade levels; simulated log2FC and adjusted p-values. Opens with arrows, curved parallel edges, the numeric color scale and the legend.Simulated for NORMA 3.0
Healthy vs disease (showcase)Two networks over the same 64 nodes (the disease network loses about a fifth of the edges and gains links in one module); four modules; simulated log2FC. Opens with both networks overlaid as two channels; compare them on the Network Comparison page.Simulated for NORMA 3.0
Arena3D example (showcase)The seven-layer example network from Arena3D's documentation; its layers become groups. Try Open in Arena3D to send it back.Arena3D
TP53, NORMA documentationThe small example from NORMA's help pagesNORMA
-

The second block holds built-in demos in JSON form: a curated multi-edge operon, two synthetic networks of four overlapping modules with attributes on nodes, edges and groups, and random networks from 20 to 5,000 nodes. The 40-node random directed multi-edge network opens with arrows, curved parallel edges and a hierarchical layout: its four groups form a signalling cascade from receptors to target genes, pairs carry one to three channels, and about a quarter of them also have a feedback edge in the opposite direction. The 20-node random network opens with edge labels: each edge carries an interaction attribute (activates, inhibits, binds, …) shown at its middle. All demos are generated from fixed seeds and can be downloaded under Example files. Clear view empties the current view but keeps your files.

- -

Sample data and sample output

-

Every example opens with one click, from Open an example on the Welcome page or the Examples list in the Upload Data tab. Its files (the sample data) can be downloaded under Example files, to see the formats or to try uploading them. The links below open a sample result directly; they behave exactly like results from your own data:

- - - - - - - - - - -
Sample outputShows
Drosophila Tau networkA published network with KEGG pathways, Louvain communities and expression colors; try the Network Profiler and Group analysis on it.
STRING: TP53 interactorsA STRING network with evidence channels, groups and expression.
Signalling cascadeDirected, multi-channel edges with numeric values, a color scale and a legend.
Healthy vs diseaseTwo networks to compare on the Network Comparison page.
Arena3D exampleSeven layers, ready to open in Arena3D.
Four overlapping modules in 3DPie-chart nodes and group layouts on the 3D page.
-

Each link can also be bookmarked or shared: norma.html?example=NAME (add &tab=3d for the 3D page).

- -

Example files

-

Sample data: every file behind the examples, so you can see the file formats and try NORMA's upload with them. Click a name to download the file; the same examples can be opened directly from the Examples list or with the sample-output links in Sample data and sample output.

-
-

Built-in demos

-

The demos are generated from fixed random seeds, so each download matches what Open example shows. Network and Groups are NORMA files: the network has a Weight column when any edge is weighted (edges without one are written with weight 1) and a Type column when there are several channels. JSON keeps everything, including attributes, group descriptions and, for the labelled demo, the settings that turn edge labels on.

-
- -

Files and formats

-

Upload one or many files at once with Upload files…, or drop them on the upload box. Detect file type recognizes networks by their header and expression files by their colors; anything else is read as an annotation. Pick a type yourself if detection guesses wrong. Networks with more than 10,000 nodes are cut to their first 10,000 nodes, with a note in the list. Arena3D network files (columns SourceNode, SourceLayer, TargetNode, TargetLayer, Weight, Channel) are recognized too: each becomes a network and an annotation with one group per layer. The list below it chooses whether network rows without a Direction value are read as undirected or directed. The name box names a single upload; with several files, each keeps its file name. Every file appears in one of three lists (Networks, Annotations, Expressions), in A–Z order, and stays there until you delete it (see Deleting files). Files live only in this browser tab.

-

Deleting files

-

There are four ways to remove things completely:

-
    -
  • Delete… in the top bar (next to Rename) lists the current view and every file it shows (its network files, grouping and expression file), each with a tick box; untick what you want to keep. Removing the view closes it (the previous view is shown; removing the only view leaves an empty one). For a view opened from an example or a JSON file, only the view itself can be removed, since its data belongs to the view.
  • -
  • The ✕ next to the Grouping menu removes the grouping file the view uses.
  • -
  • The ✕ next to a network, annotation (grouping) or expression file in Upload Data → Files removes that file.
  • -
  • Delete all files… under the Files lists removes every file at once.
  • -
-

Each asks Are you sure you want to completely remove …? and names the views that will change; nothing happens until you choose Yes, remove. Deleting a file:

-
    -
  • removes the file from Files, from the Grouping menu and from every other file list and menu, together with everything NORMA read from it (for STRING and database imports, also the extra node details that came with the network);
  • -
  • updates every view that shows it, including views you are not looking at: a view keeps its remaining networks, node positions, group colors and ticked groups and channels, and loses the deleted network's nodes and edges, or the deleted groups or colors; a view left with no network becomes empty (its display settings stay);
  • -
  • clears the undo history of those views, so the deleted data can't come back, and removes Network Profiler and Network Comparison results that were computed from it;
  • -
  • leaves out the deleted data from sessions saved afterwards;
  • -
  • renames views that were named after their files automatically (views you renamed keep their names).
  • -
-

Groupings that were fetched for a deleted network (for example from STRING) are not deleted with it; delete them separately if you don't need them. Deleting never touches the files on your disk, and cannot be undone inside NORMA: to use a file again, upload it again. Views opened from examples or JSON files hold their own data; empty them with Clear view.

-

Network file

-

Tab-separated, with a header row Source, Target and optionally Weight. Connections are undirected: A–B and B–A are the same connection, so repeats and self-loops are removed and reported.

-
Source	Target	Weight
-CDKN1A	TP53	5
-TP53	MDM2	1
-

An optional Type column (also accepted as Channel, Layer or Interaction) keeps several edges between the same pair, one per type, and makes each type a channel. Only a repeat of the same pair and type is removed. This column is new in NORMA 3.0: earlier versions of NORMA read only Source, Target and Weight and kept a single connection per pair.

-
Source	Target	Weight	Type
-TP53	MDM2	0.9	experiments
-TP53	MDM2	0.7	textmining
-

An optional Direction column (also accepted as Directed, Dir or Arrow) marks each row as directed (also yes, true, 1 or ->) or undirected (also no, false, 0 or -). A directed row points from Source to Target, so A→B and B→A are two connections; for undirected rows they are one. Rows with an empty or unknown value follow the direction chosen when uploading. This column is new in NORMA 3.0; see Directed and undirected networks.

-
Source	Target	Type	Direction
-EGFR	GRB2	binding	undirected
-MAPK1	ELK1	phosphorylation	directed
-ELK1	FOS	expression	directed
-

Annotation file

-

No header. Each line is a group name, a tab, then the group's nodes separated by commas without spaces. Group names may contain spaces and commas; node names may not contain commas. A node can be in any number of groups.

-
Group-2	BCL2L1,MDM4,MDM2,CHEK2
-Group-5	TP53,EP300
-

Expression file

-

No header. Each line is a node name, a tab, then a color: a name such as red or a hex code such as #ff0000. Nodes without a color are gray.

-
CDKN1A	blue
-MDM4	#00ff00
-

Numeric values can be used instead of colors (new in NORMA 3.0): each line is a node name, a tab, then one or more numbers, such as a log2 fold change and an adjusted p-value. An optional first line names the columns; without it they are called value, value 2 and so on. NA, empty cells and similar entries count as missing. Decimal commas are accepted. Detect file type recognizes such files, and the list shows how many value columns they have.

-
Gene	log2FC	padj
-CDKN1A	2.4	0.000001
-BCL2L1	-1.8	0.0003
-TP53	NA	NA
-

Choosing what to show

-

Tick one or more networks, choose one annotation and one expression file (or None), then choose Show in this view or Open in new view. A note under the buttons tells you when the selection differs from what the view shows. If only the annotation or expression changed, Show in this view updates in place and keeps node positions, so you can flip between GO, KEGG and community groupings of the same layout, or open each grouping in its own view to keep them side by side.

-

With an expression file selected, nodes are filled with its colors and groups are shaded behind them, as in NORMA. Without one, nodes are filled with their groups' colors, split into a pie for nodes in several groups.

-

Annotation names not in the network

-

Node names in an annotation must also appear in the network. The check happens twice:

-
    -
  • When you upload an annotation, its names are compared with the networks uploaded together with it, or, if there are none, with the ticked networks, or else with every network in the list. Names found in none of them are discarded right away, groups left empty are removed, and a warning lists what was dropped. Download corrected annotation saves the cleaned file, which is what NORMA's companion R script produces. If no name matches at all, the file is not kept. If no network has been uploaded yet, the check waits until the annotation is shown.
  • -
  • When you show files, annotation and expression entries for nodes that aren't in the selected networks are left out and listed in the status notes, again with a corrected annotation to download.
  • -
- -

Several networks and multi-edges

-

New in NORMA 3.0. Previous versions of NORMA did not support multi-edge graphs: every pair of nodes could have only one connection, and repeated connections were removed when a network was loaded. NORMA 3.0 keeps all of them, as parallel edges in separate channels.

-

Parallel edges come from three sources: a Type column in a network file, several network files shown together, or JSON files with more than one edge per pair.

-

Ticking more than one network overlays them. Nodes with the same name are merged, and each network becomes its own edge channel, so a connection found in two networks is drawn as two parallel edges in two colors. Edges and nodes then carry a network / networks attribute naming their source, which you can search for.

-

Ways to work with parallel edges:

-
    -
  • Edge channels turns each channel on or off and recolors it.
  • -
  • Edges → Parallel edges: merge per node pair draws one edge per pair, thicker the more channels it carries. It's gray when channels disagree and in the channel's color when there's only one. Clicking a merged edge lists all its channels.
  • -
  • Edges → Shape: curved fans parallel edges apart so each stays visible.
  • -
  • Layout → Use checked channels only positions nodes using only the channels you've ticked, so you can lay the graph out by one network and compare the others on top.
  • -
  • Edges → Shape: bundled draws edges running in similar directions together, and Labels → Edge labels can name each edge's channel.
  • -
  • Network Profiler reports, for the current view, how many node pairs are shared between channels and how similar each pair of channels is; Network Comparison sets whole networks side by side.
  • -
  • Export → NORMA files → Keep channels as a Type column saves parallel edges in a NORMA network file instead of merging them.
  • -
- -

Directed and undirected networks

-

New in NORMA 3.0. Earlier versions of NORMA treated every connection as undirected. Edges can now point from a source to a target, and a network can mix directed and undirected edges.

-

Bringing direction in

-
    -
  • When uploading, the list under the file type sets how network rows are read: undirected (A–B), the default, or directed (Source → Target). Choose directed before uploading if A→B and B→A are different interactions: an undirected upload treats them as the same connection and keeps only one.
  • -
  • A Direction column in the network file overrides that choice row by row (see Network file), so one file can mix both kinds.
  • -
  • In JSON, "directed": true at the top makes every edge directed, and "directed": true or false on an edge sets that edge (see JSON format).
  • -
  • The built-in Random directed multi-edge network shows a signalling cascade with up to three channels per pair and some feedback edges.
  • -
-

Handling a network as directed or undirected

-

Display → Edges → Direction decides, for the current view:

-
    -
  • Treat all edges as undirected (default): direction is ignored everywhere, as in earlier versions of NORMA. When the data does mark edges as directed, the top bar shows a direction ignored tag; click it to switch to As in the data.
  • -
  • As in the data: edges marked as directed get arrows and are treated as directed; the rest are undirected.
  • -
  • Treat all edges as directed: every edge points from its source to its target, whatever the file says.
  • -
-

With arrows shown, Arrow chooses a triangle, vee, curved triangle or chevron, and Arrow size scales them. The top bar shows a directed or mixed direction tag next to the counts.

-

What direction changes

-
    -
  • Parallel edges: A→B and B→A are separate edges. With Shape: curved they are drawn apart; merge per node pair merges only edges running the same way.
  • -
  • Node size and details: In-degree and Out-degree count incoming and outgoing edges (an undirected edge counts as both). Betweenness and closeness follow edge directions when the shown part has directed edges; clustering ignores direction. A node's details show in- and out-degree and mark each neighbor with → (outgoing) or ← (incoming); an edge's details show its direction.
  • -
  • Layout: Hierarchical places sources above their targets. Force-directed layouts and the group strategies ignore direction.
  • -
  • Network Profiler and Network Comparison: with Use edge direction ticked, they add directed statistics and match edges by direction (see below).
  • -
  • Exports: NORMA network files get a Direction column when any edge is directed, and JSON keeps each edge's direction. Earlier versions of NORMA read neither.
  • -
-

Search, group shading, shapes, bundling and edge labels work the same for directed and undirected edges.

- -

Database importers

-

The Database importers tab fetches networks and groupings from public databases; no account is needed. Every import is added to Files (a network plus one annotation per grouping) and opens in a new view, where the Grouping list switches between its groupings. Nodes keep useful identifiers as attributes, in particular uniprot, which the Gene Ontology importer uses. Networks with directed edges open with arrows. Very large results are cut to 10,000 nodes, and every importer has a Cancel button. When NORMA runs with server.py, all requests go through the server (see Running NORMA locally or on a server); otherwise the browser calls the services directly, which some browsers block. STRING is described in Importing from STRING.

-

Reactome

-

Curated pathways from Reactome. Type a pathway name (choose the species) or a stable identifier such as R-HSA-69278, choose Search pathways, pick one, and choose Fetch pathway network. NORMA reads the pathway's reactions (up to Most reactions) and their participating molecules: nodes are the proteins (and, if ticked, small molecules), and two nodes are linked when they take part in the same reaction, weighted by how many reactions they share. Reactions with more than the chosen number of molecules are left out, since they would link everything to everything. Groupings: the pathway's sub-pathways (the proteins of the reactions each contains) and, optionally, the 40 largest reactions.

-

OmniPath

-

Signalling, transcriptional and ligand–receptor interactions from OmniPath for human, mouse or rat. Type gene symbols or UniProt accessions and tick the datasets (OmniPath core, pathway, kinase–substrate and ligand–receptor extras, CollecTRI and DoRothEA). NORMA fetches their interactions with all partners (keeping the Most partners best supported by curation effort) or only those among the given proteins. Edges keep OmniPath's direction; Channels split them by effect (stimulation, inhibition, both, unsigned) or by interaction type, and their weight is the curation effort. Groupings: protein complexes with at least two members in the network, intercellular roles (ligand, receptor, …) and, optionally, an annotation resource such as SignaLink pathways or NetPath.

-

NDEx

-

Public networks from the Network Data Exchange. Search with words or paste a network UUID, pick a network (the list shows its size and owner) and choose Fetch network. Node names, edge interactions and numeric weights are read from the network, its saved layout is kept, and node attributes become node attributes in NORMA. Groups depend on the network ("limited"): every node attribute with 2 to 60 distinct values covering at least 30% of the nodes (such as a type or module) becomes a grouping, up to six.

-

IntAct

-

Experimentally detected molecular interactions from IntAct, through its PSICQUIC service. Type gene names or UniProt accessions and choose the organism (both partners must belong to it). Interaction records below the Lowest MI-score are left out; the others are merged per pair and interaction type (physical association, direct interaction, …), which become channels, with the best MI-score as the weight. Most partners keeps the highest-scoring partners, and Most records limits how much is read. IntAct has no groupings of its own, so NORMA adds one that separates the query proteins from their partners; add GO terms or communities for more.

-

Gene Ontology

-
    -
  • GO-CAM network (limited): GO-CAM models from the Gene Ontology link the activities of gene products causally. Choose the organism, List models, filter and pick one (or type a model ID), and Fetch GO-CAM network. Nodes are the gene products that enable the activities; directed edges follow the causal relations (directly positively regulates, provides input for, …), which become channels. Groupings: the biological process, cellular component and molecular function of each activity.
  • -
  • GO groupings add GO terms as groups to the network already shown, from QuickGO annotations of the nodes' UniProt accessions (the node name or its uniprot attribute). Tick the aspects; Leave out electronic annotations skips IEA evidence, NOT annotations are always skipped, and each aspect keeps up to Groups per aspect terms with at least Smallest group members (terms that contain every node are left out). The groupings are added to Files and shown in the current view.
  • -
- -

Importing from STRING

-

New in NORMA 3.0. STRING, in the Database importers tab, fetches a protein interaction network, and functional groupings for it, directly from the STRING database. It needs an internet connection.

-

The network

-
    -
  • Proteins or genes: one or more names, such as TP53, p53 or a UniProt accession, separated by spaces, commas or new lines. STRING matches each name to its best protein and the status notes say how each was matched and which names weren't found.
  • -
  • Organism: pick one from the list, or choose Other organism and type its NCBI taxon ID (for example 7955 for zebrafish). Any organism in STRING can be used.
  • -
  • Network: functional associations use all of STRING's evidence; physical interactions only keeps proteins that bind each other or form a complex.
  • -
  • Interactors to add (0–500) extends the network with the proteins most confidently connected to yours, best first. With 0 and several names, only the connections among them are fetched; with a single name STRING always adds its 10 best interactors.
  • -
  • Minimum confidence: highest (0.900), high (0.700), medium (0.400), low (0.150) or a custom value; weaker connections are left out.
  • -
  • Evidence channels: gene neighborhood, gene fusion, co-occurrence, co-expression, experiments, curated databases and text mining. Untick channels to leave that evidence out: each connection's confidence is then recomputed from the ticked channels only, the way STRING combines them, and connections that fall below the minimum are dropped (the notes say how many).
  • -
  • Edges: one edge per channel makes a multi-edge network in which each channel has STRING's color and its own score as the weight, so you can tick channels on and off, merge or bundle them later. One edge per pair keeps a single edge with the combined score.
  • -
-

Each protein carries its STRING identifier, STRING's description of it, and whether it was one of your query proteins, as attributes: they appear in the node's details and can be searched.

-

Groupings from functional terms

-
    -
  • Terms: enriched in the network (recommended) runs STRING's enrichment analysis on the network's proteins and keeps terms with an FDR at or below the chosen value; all annotations of its proteins takes every term any of them has. STRING doesn't share full KEGG annotations for licensing reasons, so KEGG pathways come only with enriched terms.
  • -
  • Term collections: GO biological process, molecular function and cellular component, KEGG, Reactome and WikiPathways pathways, UniProt keywords, Pfam, InterPro and SMART domains, diseases, tissues, subcellular localization, phenotype ontologies (human, mammalian, fly, worm, zebrafish, fission yeast), STRING's local network clusters and reference publications. Which ones have terms depends on the organism and the STRING version; the notes list what STRING returned. Any other collection STRING offers includes collections not in the list.
  • -
  • Groups per collection keeps the most significant (enrichment) or largest (all annotations) terms, and Smallest group leaves out terms with fewer proteins in the network.
  • -
-

Each collection becomes an annotation in Files, named after the network and the collection, and the view opens grouped by the first available of KEGG, Reactome, GO biological process and so on. Switch collections with the Grouping list in the top bar; node positions stay. Every group carries the term's identifier and collection and, for enrichment, its FDR, p-value and number of proteins in the genome, shown in the group's details (its i button). Fetch groupings for the current view adds more collections, or the same ones with other settings, to a STRING network that is already shown.

-

STRING server

-

By default NORMA asks https://string-db.org, which always answers with the latest STRING version; the notes say which version was used. To get the same answers every time, enter a version address such as https://version-12-0.string-db.org. NORMA identifies itself to STRING and waits a second between requests, as STRING asks, so a full import takes a few seconds. Cancel stops a request that takes too long. Untick Fetch protein descriptions to save one request.

-

Networks and groupings fetched from STRING can be saved as NORMA files or JSON like any other; please cite STRING (Szklarczyk et al., Nucleic Acids Research 2023;51(D1):D638–D646, doi:10.1093/nar/gkac1000) when you use them.

- -

JSON format

-

The only required fields are nodes and edges:

-
{
-  "nodes": [
-    { "id": "A", "groups": ["g1", "g2"], "size": 40, "color": "#e07a7a", "tissue": "liver" },
-    { "id": "B", "group": "g1" }
-  ],
-  "edges": [
-    { "source": "A", "target": "B", "type": "experiments", "weight": 0.8, "pmid": 123 },
-    { "source": "B", "target": "A", "type": "regulation", "directed": true }
-  ],
-  "directed": false,
-  "groupAttrs": { "g1": { "label": "Group one", "description": "…", "curated": true } },
-  "nodeColors": { "g1": "#e8a15f" },
-  "edgeColors": { "experiments": "#b464c9" },
-  "groupShapes": { "g1": "diamond" },
-  "config": { "showEdgeLabels": true, "edgeLabelContent": "attr:pmid" }
-}
-
    -
  • Nodes: id, group or groups, size and color have fixed meanings; any other field is kept as an attribute.
  • -
  • Edges: id, source, target, type (the channel) and weight have fixed meanings; any other field is kept as an attribute. Any number of edges may join the same pair, for example one per channel. directed (true or false) sets an edge's direction.
  • -
  • Direction: a top-level "directed": true makes every edge without its own directed field directed.
  • -
  • Numeric values: "values": { "log2FC": 1.2, "padj": 0.003 } on a node gives it numeric values for the color scale and node size.
  • -
  • Groups: in groupAttrs, label, description and color have fixed meanings; anything else is a group attribute. Attributes can also be nested under an attrs object.
  • -
  • Colors: nodeColors and edgeColors fix group and channel colors.
  • -
  • Shapes: groupShapes gives a group a node shape. Names are Cytoscape's: rectangle, round-rectangle, diamond, triangle, vee, pentagon, hexagon, octagon, star, rhomboid, tag, concave-hexagon, barrel; groups not listed are circles.
  • -
  • Group order: an optional groupOrder list sets the order of groups in the legend and the order palette colors are handed out.
  • -
  • Settings: an optional config object holds display settings in the same shape as a settings file. For example, "edgeLabelContent": "attr:pmid" labels edges with their pmid attribute.
  • -
- -
Viewing and styling
-

Exploring the network

-
    -
  • Selecting several nodes: Shift-click (or Ctrl/⌘-click) adds or removes a node, Shift-drag on the background draws a selection box, Ctrl+A selects every visible node and Escape clears the selection. Selected nodes get a thick yellow border and halo, which disappears as soon as they are deselected; a bar at the top right shows how many are selected with Zoom to selection and Clear, and dragging any selected node moves them all.
  • -
  • Drag nodes to move them, scroll to zoom, and drag the background to pan. Zoom has no practical limit in either direction, and the view always keeps the network in frame: a network smaller than the canvas can't be pushed off it, and a larger one can't be panned past its edges. The +, – and Fit buttons at the bottom left zoom around the center; the number under them is the zoom level. Double-click the background to fit everything, or a node to center it.
  • -
  • Click a node for its groups, degree (with in- and out-degree for directed edges), betweenness, closeness, clustering coefficient (computed on the ticked groups and channels), attributes and neighbors; with directed edges, → and ← mark outgoing and incoming connections. Group names in that panel open the group's details.
  • -
  • Neighbourhoods and paths (new in NORMA 3.0): the node details offer Open neighbourhood as a view with 1, 2 or 3 steps. With nodes selected, Neighbourhood in the selection bar opens them with their direct neighbours; with exactly two selected, Shortest paths opens every shortest path from the node selected first to the second, keeping only the edges on those paths, and says how many paths there are. Both follow edge directions where edges are directed, use only the ticked groups and channels, and open as new views that keep the nodes' positions, groups, colors and settings; the starting nodes are selected and carry a role attribute (center, source or target).
  • -
  • Click an edge for its channel, endpoints, direction, weight and attributes.
  • -
  • Click the i next to a group for its description, attributes, member and edge counts, density, and the groups it shares members with.
  • -
  • Click empty space to clear the highlight.
  • -
  • Find nodes, at the top left of the network (the – button at its right minimizes the panel to a small Find nodes button, which still shows the number of matches; click it to open the panel again), highlights matching nodes and shows how many matched. Choose how to match: Contains, Exact name, Starts with, Ends with (suffix) or Regular expression. A regular expression can be typed as is, such as ^Rp[LS]\d+$, or between slashes with flags, such as /kinase$/i. Matching ignores case unless Match case is ticked, and also checks attribute values while Search attributes is ticked. Press Enter to zoom to the matches and Escape to clear.
  • -
  • The numbers at the top right count nodes, edges, edge channels and groups in the view; with groups unticked, the group count shows ticked/all, for example 8/9.
  • -
- -

3D Network

-

New in NORMA 3.0. The 3D Network page shows the current view in three dimensions. It is the same view as 2D Network: groups, colors, pie slices, node shapes, borders, labels, edge labels, arrows, curved parallel edges, group shading, ticked groups and channels, search results and selected nodes all carry over, and every setting in the Display tab except the 2D Layout section changes both pictures. Node positions and the camera are separate for 3D, and each view keeps its own.

-

Moving around

-
    -
  • Drag the background to rotate, right-drag (or Alt-drag) to pan, and scroll to zoom. Turning and tilting have no limit: drag on, or keep pressing a turn or tilt button, and the network rolls over as often as you like, so it can be seen from any side, including upside down.
  • -
  • Drag a node to move it within the screen plane; with several nodes selected, dragging one moves them all.
  • -
  • Click a node or an edge for its details, exactly as in 2D; click the background to clear. Shift-click selects nodes and Shift-drag draws a selection box. Double-click a node to turn around it, or the background to fit everything.
  • -
  • The buttons at the bottom left zoom (+, –, Fit), turn (↺, ↻), tilt (↑, ↓), reset the view (⟲) and switch automatic rotation on and off (Auto). With the 3D picture focused, the arrow keys turn and tilt, + and – zoom, and F fits.
  • -
  • Find nodes, Zoom to selection and Export image work here too and act on the 3D picture.
  • -
-

3D layout

-

On this page the Display tab shows a 3D layout section in place of the 2D one. As in 2D, layouts arrange only the nodes of ticked groups and, with Use checked channels only, only the ticked channels count.

-
    -
  • Force-directed 3D, weighted: the Fruchterman–Reingold idea in three dimensions; heavier edges pull harder. Each connected piece is laid out on its own and smaller pieces are placed around the largest. It runs in the background and is used the first time a view is shown in 3D.
  • -
  • Sphere, Cube grid and Random place nodes on a sphere, in a cube or at random, best-connected nodes first.
  • -
  • Groups as 3D clusters: each ticked group becomes a ball of its nodes, with hubs in the middle. Groups that share many edges are placed close together, and the balls never overlap. Nodes in several groups sit between their groups.
  • -
  • Groups on stacked layers: the 2D layout lies flat and each group gets its own layer, one above the other, so the links between groups run between the layers.
  • -
  • Same as 2D (flat), Height by hierarchy level and Height by degree keep the 2D layout and add height: none, the level from the top of a hierarchy (following edge directions when edges are directed), or the number of connections, so hubs rise above the rest. Height step sets the distance between levels.
  • -
-

Spread pushes nodes apart or pulls them together, as in 2D. Double-click the slider to go back to 1×.

-

Look

-
    -
  • View from turns the camera to the front, top, side or a tilted angle and fits the network.
  • -
  • Perspective: normal, strong (wide angle, more depth) or none (parallel projection, where sizes don't change with distance).
  • -
  • Nodes: shaded spheres or flat, as in 2D. Group shapes and pies are always drawn flat, facing you.
  • -
  • Depth fading blends distant nodes and edges into the background, which helps tell near from far.
  • -
  • Floor grid and axes draws a grid under the network and short x, y and z axes at its center.
  • -
  • Rotate automatically turns the network slowly; Rotation speed sets how fast.
  • -
-

Group shading follows the nodes as seen from the camera. Edge bundling applies to the 2D picture only; in 3D, edges are straight, and parallel edges curve apart when Shape is curved or bundled. On large networks the picture is simplified while you move it (no labels, pies or arrows) and drawn in full as soon as you stop; at most 500 node labels and 300 edge labels are drawn at a time, the nearest first.

- -

Layout

-

This section is about the 2D Network page; the 3D page has its own layouts (see 3D Network). Every layout arranges only the shown part of the view: nodes in ticked groups, connected by edges of ticked channels while Use checked channels only is on. Nodes of unticked groups stay where they are, so ticking them again brings them back in place.

-

The switch at the top of Layout chooses how nodes are arranged. Only one side is active at a time; the other is shown greyed out and marked frozen, and Run layout runs only the active side. The choice is saved with the view.

-

By connections

-

Positions come from the edges alone; groups play no part. Force-directed (cose) places connected nodes near each other. Force-directed, weighted is the Fruchterman–Reingold layout NORMA uses: heavier edges pull their nodes closer, and the result is the same every time for the same input. Kamada–Kawai (new in NORMA 3.0) treats every pair of nodes as a spring whose length is the number of steps between them and relaxes the springs one node at a time; stress majorization starts from a pivot-MDS layout and then minimises the same kind of stress (the mismatch between on-screen and network distances) for all nodes together, which is usually faster and keeps distances most faithfully. Both ignore edge weights, lay out each connected part separately, and handle parts of up to 2,500 nodes. They are also available as group strategies and inside groups. Concentric puts high-degree nodes in the middle; hierarchical arranges nodes in levels from a root, following edge directions when the view has directed edges. Networks above 700 nodes load with a grid layout, since a force-directed layout can freeze the page for a while at that size; you can still run it yourself.

-

By groups

-

Group arrangement decides where each group goes, and Layout inside each group arranges the group's own nodes (circle, force-directed, concentric, hierarchical, grid or random). A node in several groups sits at the average of its positions, between those groups. Only groups ticked under Node groups count.

-
    -
  • Groups as separate blocks treats each group, plus one block for nodes in no group, as a disc sized to fit its nodes, and places the discs so they never overlap. Force-directed puts groups that share many edges next to each other and packs the rest around them; Circle lines them up on a ring; Grid packs them in rows; Hierarchical stacks them in levels starting from the best-connected group; Concentric puts the largest group in the middle with the others in rings by size. Space between groups sets the gap.
  • -
  • NORMA-2.0 strategies (Karatzas et al., 2022, Bioinformatics Advances 2:vbac036, Figure 1) use the same weights and steps as NORMA's own code, with the algorithm you pick under Algorithm the strategy runs. A small diagram shows how the selected strategy works; links a strategy adds exist only while positions are computed. Weights change the result only with the two force-directed algorithms. -
      -
    • Strategy 1, virtual node per group: each group gets a hidden hub linked to all its members with weight 50. Real edges get weight 5, and every pair of members gets a light link (0.1). The algorithm runs on this larger network and the hubs are then removed.
    • -
    • Strategy 2, group gravity: every pair of nodes in a group gets a link at the network's highest weight. Real edges inside a group are multiplied by Force strength, and edges between groups, or to ungrouped nodes, are divided by it.
    • -
    • Strategy 3, super nodes per group: each group becomes a single node and ungrouped nodes stay as they are. The algorithm lays out this collapsed network and Force strength pushes the result outward.
    • -
    - Strategies 1 and 2 place every node themselves. With them, Layout inside each group can also be Keep the strategy's arrangement; any other choice rearranges each group around where the strategy put it and keeps groups from overlapping.
  • -
-

Group size scales each group's local layout. Force strength runs from 1 to 20 (NORMA's default is 10). Use checked channels only applies to both sides. A group with more than 400 nodes gets 60 random partner links per node instead of links to every other member, to keep the layout fast. While By groups is active, it is also used when a network loads and when you switch annotations.

-

Fit to screen zooms to show the whole network. Spread changes how strongly nodes repel each other compared with the pull of their links, from a quarter to four times the strength of the current arrangement. To the right, dense clusters open up and loosely linked parts move apart; to the left, linked nodes are drawn together while nodes are kept from overlapping. It starts from the current positions and keeps the overall arrangement, and going back to 1× restores them. Double-click the slider to go back to 1×. Moving nodes by hand starts again from their new positions, and running a layout resets it.

- -

Node groups

-

Groups are listed A–Z (numbers in numeric order, so Group-2 comes before Group-10). The Order menu under the filter also sorts them by their number of nodes (the count shown on each row), Most nodes first or Fewest nodes first (groups of equal size stay A–Z), or keeps the File order of the annotation file. Nodes in no group always come last. The legend follows the same order, each view remembers the choice, and group colors don't change. Node names in the details panels, and the files in Files and in every file menu (Grouping, Network Profiler, Network Comparison, enrichment) are always listed A–Z.

-

Lists the groups of the current annotation with their node counts. Untick a group to hide nodes that are only in inactive groups; a node stays visible while any of its groups is active, and its pie shows only its active groups. Click a swatch to recolor a group. Nodes that no group lists appear under Not in any group.

-

Type in the filter box to narrow long lists such as GO terms. While a filter is set, the two buttons activate or deactivate only the matching groups, which makes it quick to show, for example, only terms containing "signaling". Pies show up to 16 slices; a node in more active groups gets a gray slice for the rest.

-

Node shapes

-

The small shape button on each group row opens a choice of shapes: circle, square, rounded square, diamond, triangle, vee, pentagon, hexagon, octagon, star, rhomboid, tag, concave hexagon and barrel. Use the arrow keys to move through them and Escape to close. The same shapes are offered in a group's details panel (its i button). Assign shapes gives each listed group a different shape at once, and Reset shapes makes them circular again; with a filter set, both apply only to the matching groups.

-

A node takes its group's shape only when exactly one of its groups is ticked. Nodes shown with two or more active groups stay circular, so their pie slices stay readable. Unticking groups therefore changes shapes: a node in a square group and a diamond group is a two-color circle, becomes a square when the diamond group is unticked, and a diamond when the square one is. Shapes combine with either fill: with expression colors, the shape shows the group and the color shows expression. Each view keeps its own shapes, and they are saved in JSON.

- -

Group highlighting

-

Shades the area behind each active group in its color, as NORMA does. Opacity controls how strong the shading is. Three styles are available:

-
    -
  • Convex hull draws a sharp outline around all of the group's nodes. Groups of one or two nodes get a circle or capsule.
  • -
  • Bubble sets draws contours that hug the group, in the style of Collins, Penn and Carpendale's Bubble Sets (IEEE TVCG 2009): the outline follows the group's nodes closely, links them with narrow bands so each group stays in one piece where possible, and bends around nodes that are not in the group, leaving holes where outsiders sit inside. Interleaved groups therefore stay readable where convex hulls would cover each other. Contours are recomputed when nodes move, groups are ticked or the zoom changes a lot; on networks with more than 1,500 shown nodes they are updated once the movement stops.
  • -
  • Fog cloud draws a soft, blurred area.
  • -
-

All three styles appear in image exports (SVG included) and on the 3D Network page, where bubble sets are drawn from the camera's point of view and simplified while the picture moves.

- -

Colors

-
    -
  • Node fill chooses between group colors, expression colors (from an expression file or each node's color field) and numeric values on a color scale, when the view has numeric values.
  • -
  • Numeric values (shown when the view has them): -
      -
    • Column picks which value to show, for example log2FC or padj.
    • -
    • Transform: use the values as they are, their −log10 (so small p-values become large), or their absolute values.
    • -
    • Scale: diverging scales (blue–white–red, purple–white–orange, purple–white–green, brown–white–teal) show values below and above a Center (0 by default), which suits fold changes; sequential scales (viridis, magma, blues, reds) run from low to high, which suits p-values and intensities. Most of these scales stay readable under common forms of color vision deficiency.
    • -
    • Range: symmetric around the center (diverging scales), from the lowest to the highest shown value, or custom; values beyond the range get the end colors.
    • -
    • No value sets the color of nodes without a value. A line under the controls says how many shown nodes have a value and their range.
    • -
    - Steps (time points or conditions) appear when there are several value columns: ◀ and ▶ move one step, Play steps through them repeatedly at the chosen speed, and the slider jumps to any step, while node positions stay put. The current step shows at the top of the network. Same color scale for all steps (on by default) fixes the scale over all columns so colors can be compared between steps. Add the numeric files in Files as steps adds every column of the other numeric files as further steps, named file: column; nodes a file doesn't list get no value for its steps. - A numeric file selected in Files switches the fill to numeric values automatically.
  • -
  • Group palette recolors all groups. The Okabe–Ito, IBM and Viridis palettes stay distinguishable under common forms of color vision deficiency. Past a palette's own colors, further colors are spread evenly around the color wheel, which keeps around 100 groups distinguishable.
  • -
  • Channel palette does the same for edge channels. Classic uses STRING's evidence colors.
  • -
-

Themes (top bar) change the interface and canvas background, not the data colors.

- -

Node size

-

Nodes can keep the size given in the data or be sized by degree, in-degree, out-degree, betweenness, closeness, clustering coefficient or a numeric value (the column and transform chosen under Colors; on a diverging scale the distance from the center, so strongly raised and strongly lowered nodes are both large). With directed edges, betweenness and closeness follow edge directions. Sizes run from Min px for the lowest value to Max px for the highest. Metrics are computed on the nodes of ticked groups; Use checked channels only (on by default) also limits them to the ticked channels. Sizes update as you tick and untick. Node scale multiplies every size, from a tenth to five times.

- -

Labels

-
    -
  • Node labels show node names, centered on the node by default; the position list moves them above, below or to a side. Node label size sets their size, and Grow labels with node size scales each label with its node, so bigger nodes get bigger names.
  • -
  • Edge labels are drawn at the middle of each edge, whether straight, curved or bundled. They can show the channel, the weight, both, or any edge attribute in the network. Merged edges show how many channels they combine and their highest weight. Orientation runs them along the edge or keeps them horizontal, and Edge label size sets their size. With edge labels on, straight edges are drawn with a slightly slower method that supports labels.
  • -
  • Label colors: node and edge labels can follow the theme, use black, dark gray, white, blue, red or green, match their node's color or their edge's channel color, or use any color chosen with Custom…. White labels get a dark outline so they stay readable on a light background.
  • -
  • Hide labels when zoomed out drops labels that would appear smaller than the chosen size on screen, which keeps large networks readable and fast.
  • -
- -

Edges

-
    -
  • Direction: handle edges as in the data, all as directed, or all as undirected; with arrows shown, choose their shape and size (see Directed and undirected networks).
  • -
  • Parallel edges: draw every channel separately, or merge each node pair into one edge (see multi-edges); directed edges merge only with edges running the same way.
  • -
  • Shape: straight lines are fastest. Curved edges fan parallel edges apart, and Fan-out sets how far.
  • -
  • Bundled draws edges that run in similar directions together, like cables in a tray, which untangles dense networks and shows the main routes between groups. It uses force-directed edge bundling (Holten and van Wijk, 2009): edges whose direction, length, position and overlap are similar pull on each other, while springs keep each edge smooth. Bundling strength sets how readily edges join a bundle and how tightly they are drawn together. Bundles are computed in the background, so the page stays usable: about 5 seconds for 3,000 edges and half a minute for 8,000. They are recomputed after a layout, after dragging nodes, after using Spread, and when groups or channels are ticked or unticked. Parallel edges between the same pair follow the same bundle. Only visible edges are bundled, up to 10,000 at a time; merging parallel edges or unticking channels brings larger networks under that limit.
  • -
  • Thickness: a fixed width, or mapped from each edge's weight between Min and Max px. Edges without a weight get the middle width.
  • -
  • Edge opacity: how solid edges are drawn; lower it to let dense networks show their nodes.
  • -
- -

Edge channels

-

Lists each kind of edge with its count. Untick a channel to hide its edges; click its swatch to recolor it. For files loaded from Files, each network (or each value of its Type column) is a channel.

- -

Legend

-

Display → Legend → Show a legend on the network places a legend at the bottom right of the 2D and 3D network (it steps aside while a node's or edge's details are open). It can include the color scale of numeric values with its ticks and the "no value" color, the groups with their colors and, with Group shapes, their node shapes, and the edge channels when there are two or more. An optional title goes on top. Groups and channels follow what is ticked, and the legend updates as colors, shapes or settings change.

-

Views made by Show as network on the comparison page come with the legend switched on and an extra Networks part that says which letter stands for which network.

-

In Export image, Add the legend puts the same legend to the right of the picture, at the picture's scale, in every format; in SVG files it is a separate, editable group. The legend is included whether or not it is shown on screen.

- -

Attributes

-

Summarizes the extra data carried by nodes, edges and groups: each field, its kind (text, number, yes/no, list), its range or values, and how many items have it. Values appear when you click a node, an edge or a group's i, and search looks through node attribute values.

- -
Analysis
-

Network Profiler

-

Besides the statistics below, the page holds Group analysis, the Layout benchmark and the Runtime table.

-

Tick any mix of the current view and networks from Files, then choose Compute statistics. Results appear side by side so networks can be compared, and Download table saves them as tab-separated text. Each network is profiled as a simple undirected graph. The current view is profiled as shown: only nodes of ticked groups and edges of ticked channels count, and parallel edges from different channels count as one connection.

-

With Use edge direction ticked (it is off by default), networks with directed edges get a second table, Direction: directed edges, reciprocity (the share of directed edges whose reverse also exists), maximum in- and out-degree, source and sink nodes, strongly connected components, the share of node pairs that can reach each other, and the average directed path length and diameter. Undirected edges can be walked both ways. The main table always treats edges as undirected, as igraph does for these statistics.

- - - - -
StatisticMeaning
-

Below the table:

-
    -
  • Degree distribution: how many nodes have each degree. Tick log–log to check for a power law.
  • -
  • Most central nodes: the top ten by the measure you choose. Click a name to find it in the 2D Network page when it's in the current view.
  • -
  • Communities: choose an algorithm and choose Find communities; Louvain is shown by default. Add as annotation saves the communities (without single nodes) to Files as a new annotation you can view like any other; NORMA's Tau example ships such a file. All algorithms work on the simple undirected network, use a fixed random seed so results repeat, and are scored by the same modularity. -
      -
    • Louvain (Blondel et al., 2008): greedy modularity optimisation. Resolution above 1 gives more, smaller communities.
    • -
    • Leiden (Traag et al., 2019): Louvain with a refinement step that guarantees every community is connected; same resolution setting.
    • -
    • Label propagation (Raghavan et al., 2007): each node repeatedly takes the most common label among its neighbours; very fast. Communities that end up in pieces are split into connected parts.
    • -
    • Walktrap (Pons and Latapy, 2006): merges communities that short random walks of the chosen walk length cannot tell apart, and keeps the partition with the highest modularity. Limited to 2,000 nodes.
    • -
    • Markov clustering, MCL (van Dongen, 2000): simulates flow on the network; higher inflation gives more, smaller clusters. Clusters that end up in pieces are split into connected parts.
    • -
  • -
  • Edge channels (current view only, with two or more channels): how many node pairs carry one, two or more channels, and how much each pair of channels overlaps (Jaccard index of their node pairs).
  • -
-

Path-based statistics (distances, betweenness, closeness) visit every node from every node, so networks above 8,000 nodes skip them.

- -

Group analysis

-

The Group analysis part of the Network Profiler page works on the current view: its ticked groups and channels.

-
    -
  • Group statistics: for each group, its nodes, the edges inside it and leaving it, its density inside (edges inside divided by all possible pairs), the mean degree inside, its conductance (edges leaving divided by the smaller of the group's and the rest's total degree; lower means a better-separated group) and its share of the modularity. Above the table, the modularity of the grouping says how well the groups as a whole follow the network's structure (above about 0.3 is clear structure). For this number, a node in several groups counts for its first group and a node in none counts as a group of its own. Download statistics saves the table.
  • -
  • Open group network opens a new view with one node per group, sized by the group's size, and an edge between two groups weighted (and labelled) by how many of their members are connected; each node also carries its group's edges inside as an attribute. Parallel channels count once. This is the network NORMA-2.0's strategy 3 lays out internally.
  • -
  • Enrichment tests whether the groups of an annotation (the terms, for example KEGG pathways) are over-represented, with a one-sided hypergeometric test: -
      -
    • Test: the nodes selected in the view (for example a cluster you selected by hand, or the nodes a Select button picked), or each group of an annotation (for example Louvain communities or the view's own groups).
    • -
    • Terms from: any annotation in Files, or the current view's groups.
    • -
    • Background: the shown nodes of the current view (the usual choice), or those plus every node of the term annotation.
    • -
    • Only terms and tested sets with at least Smallest overlap nodes count. p-values are adjusted with the Benjamini–Hochberg procedure within each tested set, and terms with an FDR above the limit are left out.
    • -
    - The table lists each enriched term with its overlap, its size in the background, the fold enrichment, the p-value and the FDR; Select selects the overlapping nodes in the view, and Download results saves every row with the node names.
  • -
- -

Group separation and layout benchmark

-

The Group separation box in the 2D Layout section measures how well the current layout separates the ticked groups. It updates after every layout, after dragging nodes or using Spread, and when groups are ticked or unticked.

-
    -
  • Silhouette: the mean silhouette width (Rousseeuw, 1987) of the nodes that are in exactly one group, from their positions. For each node, it compares the mean distance to its own group with the mean distance to the nearest other group. It runs from −1 (groups intermixed) through 0 (no separation) to 1 (compact, well-separated groups). On large networks it is computed on a fixed sample of 1,500 nodes.
  • -
  • Inside other outlines: the share of shown nodes that lie inside the convex outline of a group they don't belong to. These are the nodes a hull drawing would misleadingly shade.
  • -
  • Outline overlap: the share of the outlined area that is covered by two or more group outlines. Groups of fewer than three nodes have no outline.
  • -
-

The Layout benchmark at the end of the Network Profiler page runs every layout on the current view without changing it: the seven layouts by connections (random as a baseline), the six group arrangements and the three NORMA-2.0 strategies, with the Layout section's settings for group layouts. For each it reports the run time and the three scores, as the mean (and standard deviation) over 1, 3 or 5 runs; the best value in each column is highlighted. Use applies a layout to the view, and Download table saves the results as tab-separated text, ready for a supplementary table.

- -

Network Comparison

-

The Network Comparison page sets two to ten networks side by side. Tick them in the list: Open views compare what each view shows: its files, and only its ticked groups and channels, and Network files compare uploaded or example networks directly. Choose Compare; each network gets a letter (A to J) and a color used throughout the results. Nodes are matched by name and edges by the pair of nodes they join, ignoring channels. With Use edge direction ticked (off by default), direction counts: A→B, B→A and an undirected A–B are three different edges, and directed statistics are added to the topology table. Untick it to match edges regardless of direction.

-
    -
  • Networks compared: the size of each network and how many nodes and edges all of them share.
  • -
  • Node overlap and Edge overlap: for two or three networks, a Venn diagram with the count in every region (circle sizes are schematic). For any number, an UpSet plot: each column is a group of nodes or edges found in exactly the networks marked by dots below it, sorted largest first; the bars at the left give each network's total. Hover a bar for its count. With many networks only the 40 largest combinations are drawn; the rest are listed in the downloaded table.
  • -
  • Jaccard similarity: for each pair, shared items divided by items in either network, from 0 (nothing in common) to 1 (identical). Darker cells are more similar; hover for the counts.
  • -
  • Degree agreement on shared nodes: the Spearman correlation of a node's degree in two networks, over the nodes they share. Close to 1 means hubs in one are hubs in the other; negative values (red) mean roles swap. A dash means fewer than three shared nodes.
  • -
  • Degree distributions: for each network, the share of nodes with at least a given degree, on log–log axes.
  • -
  • Topology side by side: every Network Profiler statistic for each network, with the highest value in each row in bold.
  • -
-

Download table saves the node and edge membership (1 or 0 per network) and the topology table as tab-separated text.

-

Show as network (new in NORMA 3.0) opens the compared networks as one view, with a legend that explains its colors: which letter stands for which network, which node colors mean "in which networks", and which edge colors mean "A only", "B only" or "Shared". Every edge becomes a channel that says which networks contain it: A only and B only in the networks' colors and Shared in gray (for three or more networks, combinations such as A + C and In all). Nodes are grouped the same way. Tick channels in the Display tab to see, for example, only what the disease network gained, and use edge direction as set for the comparison.

- -
Saving and sharing
-

Interpreting the results

-

NORMA's results are pictures and numbers about how groups sit in a network. How to read them:

-

The network picture

-
    -
  • Groups: a shaded area (hull, bubble set or fog cloud) shows which nodes belong to a group; a pie-chart node belongs to several groups (one slice each), and a node shape stands for one group. Overlapping shading means shared members or nodes placed close together, not necessarily shared biology.
  • -
  • Positions: in layouts by connections, nodes that are close are well connected, so groups that come out compact and separate really are separated in the network. Layouts by groups place groups apart on purpose, which makes them easy to see but says nothing about how separated they are; use the group separation score on a connection layout to judge that.
  • -
  • Colors, sizes and edges: node colors show group membership, expression colors or numeric values (read them against the legend; with Same color scale for all steps, colors can be compared between time points). Node size follows the chosen measure (for example degree: bigger nodes have more connections). Edge colors are channels (evidence types, interaction types or networks), thickness can follow weight, and arrows show direction.
  • -
  • Edge weights from databases: STRING's confidence score (0–1), the number of shared reactions (Reactome), curation effort (OmniPath) and the IntAct MI-score (0–1). Higher means better supported.
  • -
-

Network Profiler

-
    -
  • Size and density: density is the share of possible connections present; biological networks are usually sparse (well below 0.1).
  • -
  • Connectivity: the number of connected components and the size of the largest; the average path length and diameter say how far apart nodes are (small values mean a "small-world" network).
  • -
  • Clustering coefficient (0–1): how often a node's neighbours are connected to each other; high values mean tightly knit neighbourhoods.
  • -
  • Degree distribution: a straight line on the log–log plot suggests a few highly connected hubs and many poorly connected nodes.
  • -
  • Centrality: nodes with high betweenness lie on many shortest paths (bridges between modules); high closeness means close to all others; high degree means many partners. The top-ten lists point to candidate key nodes.
  • -
  • Communities and modularity: each community is a set of nodes more connected among themselves than to the rest. Modularity above about 0.3 indicates clear community structure; compare the communities with your annotation using Group analysis or enrichment.
  • -
-

Group analysis and enrichment

-
    -
  • Density inside higher than the network's density, and conductance close to 0, mean a group is a real module of the network; conductance near 1 means its members mostly connect outside the group. The modularity of the grouping summarises this for all groups (above about 0.3: the grouping follows the network's structure).
  • -
  • Enrichment: fold enrichment above 1 means a term is more common in the tested set than in the background; the FDR (Benjamini–Hochberg adjusted p-value) says how likely that is by chance, and terms with FDR ≤ 0.05 are usually reported. Small overlaps (2–3 nodes) and the choice of background strongly affect the result; the background should be the nodes you could have picked.
  • -
-

Group separation and layout benchmark

-
    -
  • Silhouette (−1 to 1): above about 0.5, groups are well separated in the picture; 0.25–0.5 moderately; below 0.25 they overlap; negative values mean nodes sit closer to other groups than to their own.
  • -
  • Outline intrusion and overlap (0–100%): the share of nodes inside another group's outline and of shaded area covered twice; lower is clearer. The benchmark compares layouts on these scores, averaged over repeated runs.
  • -
-

Network Comparison

-
    -
  • Venn and UpSet plots count the nodes and edges found in exactly each combination of networks; the tallest UpSet bars show the largest shared or unique parts.
  • -
  • Jaccard similarity (0–1): shared items divided by items in either network; 1 means identical. Degree agreement (Spearman, −1 to 1) says whether shared nodes are similarly connected in both networks.
  • -
  • Show as network colors each edge by the networks that contain it (A only, B only, shared), so gained and lost connections can be seen directly.
  • -
- -

Export and saved work

-

The Export tab saves and sends: NORMA files, Image, Other tools, Save your work and, at the bottom, Arena3D. Saved work is opened again under Upload Data → Open saved work. Three kinds of NORMA JSON file keep work for later, and each is saved and opened with its own button:

- - - - - - - -
FileHoldsSave / open
View file (.json)One view: its network, groups, colors, attributes and node positions (see JSON format)Save view file / Open view file… or Paste JSON…
Session file (.json)Every open view and every file in FilesSave session file / Open session file…
Settings file (.json)Display settings only, to apply the same look to other viewsSave settings file / Open settings file…
-

The other JSON files NORMA writes are for other programs: Arena3D (.json) for Arena3D and Cytoscape (.cyjs) for Cytoscape.

-
    -
  • NORMA files save the current view as a network, annotation or expression file that NORMA can read. -
      -
    • Parallel edges are merged into one connection and keep their highest weight, unless you tick Keep channels as a Type column. When any edge is directed, a Direction column is added and A→B and B→A stay separate rows. Files with Type or Direction columns open in NORMA 3.0 as multi-edge or directed networks; earlier versions of NORMA expect only Source, Target and Weight and may not read them, so leave the box unticked for files meant for those versions.
    • -
    • Nodes without connections are left out, since NORMA can't list them.
    • -
    • Commas in node names become semicolons.
    • -
    • With no expression colors loaded, each node gets its first group's color.
    • -
    -
  • -
  • Only ticked groups and channels (on by default) makes every export below save just the shown part of the view; untick it to save the whole network.
  • -
  • Export image… (also the camera button in the top bar) saves the current view as a picture: -
      -
    • Formats: PNG (supports a transparent background), JPEG (smaller files), WebP (small, sharp web images), SVG (vector: stays sharp at any size and can be edited in Illustrator, Inkscape or PowerPoint, with nodes, edges, labels and group shading in separate layers) and PDF (one page with a high-resolution image, sized so one screen pixel is one point).
    • -
    • Area: the whole network (the ticked groups and channels, with a margin for group shading) or exactly what is on screen.
    • -
    • Resolution: 1× to 8× the on-screen size. The screen counts as 96 dpi, so each step adds 96 dpi at the size the network has on screen: 1× is 96 dpi, 2× 192 dpi, 3× 288 dpi (about the 300 dpi journals ask for), 4× 384 dpi, 6× 576 dpi and 8× 768 dpi. Below the options, the dialog shows the image's exact size in pixels, the dpi and print size (inches and centimeters) at the on-screen size, and the print size at 300 dpi. PNG and JPEG files store this dpi, so layout and print programs open them at the right size. For a figure of a given width, divide the pixel width by the dpi you need: a 3,000-pixel-wide image prints 10 inches (25.4 cm) wide at 300 dpi. SVG is vector graphics, sharp at any size, so its "resolution" only sets the picture's size in the file; PDF pages have the on-screen size. Very large images are reduced to the biggest size the browser can draw, and the dialog says so.
    • -
    • Background: the theme color, white, transparent (PNG, WebP and SVG) or any color.
    • -
    • Add the legend puts the legend set under Display → Legend to the right of the picture.
    • -
    • Include group shading adds the shaded group areas, and Leave out selection and search highlighting (on by default) draws the network without yellow selection borders or dimmed nodes; the selection is restored afterwards.
    • -
    - The picture shows the view as it looks: layout, colors, shapes, pies, labels, edge labels and bundled edges. On the 3D Network page the dialog saves the 3D picture from the current angle, in any of the same formats (SVG included); Whole network fits the network into the picture without changing the angle.
  • -
  • Other tools: GraphML (yEd, Cytoscape, igraph, NetworkX), GEXF 1.3 with node colors, sizes and positions (Gephi), SIF (Cytoscape's simple interaction format: source, channel, target) and Cytoscape (.cyjs) (with positions, for Cytoscape desktop and Cytoscape.js). Nodes carry their groups (separated by semicolons), color, size, numeric values and attributes; edges their channel, color, weight, direction and attributes. Like the other exports, they include only ticked groups and channels unless that option is off.
  • -
  • Session: Save session file saves every open view (network, positions, settings, 3D camera) and every file in Files, including groupings fetched from STRING, in one JSON file; Open session file… brings it all back, replacing the current views and files.
  • -
  • Arena3D: open the view in Arena3D, or save it in Arena3D's formats, with each group as a layer (see Arena3D).
  • -
  • Save view file saves everything in the current view, including attributes, colors and group descriptions. Open view file… and Paste JSON… load that format into a new view.
  • -
  • Save settings file stores the current view's display options (palettes, layout, sizing, labels, shading, edges) and the theme in a small file that Open settings file… applies to the current view.
  • -
- -

Arena3D

-

Arena3D shows multilayer networks in 3D. Under Export → Arena3D, NORMA turns the current view into an Arena3D network in which each ticked group is a layer:

-
    -
  • Layers appear in the order of the group list, side by side, each floor in its group's color; nodes in no group get a layer of their own.
  • -
  • Inside a layer, nodes keep their 2D positions from NORMA, scaled to fit the layer, and their size.
  • -
  • Edges between members of the same group stay in that group's layer; edges between groups run between the layers. A node in several groups appears in each of its layers, and with Link the copies of a node that is in several layers (on by default) its copies are joined by white edges.
  • -
  • Edge colors are the channel colors; with weights, stronger edges are more opaque. Several channels are kept as Arena3D channels, and directed edges switch on Arena3D's direction display.
  • -
  • Node colors: as shown in NORMA (group, expression or numeric colors; pie nodes take the color of the layer they are drawn in), or the color of each node's layer.
  • -
  • Only the ticked groups and channels are exported, like everywhere else in NORMA. Arena3D takes up to 20 layers: with more ticked groups (counting the layer for nodes in no group), only the first 20 in the group list are exported, and the status note says how many groups and nodes were left out. Untick groups you don't need to choose which 20 go.
  • -
-

Comparing networks in Arena3D: after Compare, the Network Comparison page offers the same three ways out for the comparison, with one layer per compared network (A, B, … in the networks' colors). Each layer holds that network's nodes and edges; nodes and edges found only in that network take its color, and common ones are gray. All networks are laid out together, so a node sits at the same place in every layer. Between layers chooses what links the layers: Common edges (an edge found in networks A and B also runs from its source in layer A to its target in layer B, in white), Common nodes (the copies of a node found in several networks are joined, in yellow), or both. Up to 20 layers fit, so all ten comparable networks can go.

-

Three ways out (for the current view, under Export → Arena3D):

-
    -
  • Open in Arena3D sends the network to Arena3D (/api/external) and opens the returned link in a new tab. Some browsers block direct calls to other sites; running NORMA with server.py avoids that, because the server passes the request on (see Running NORMA locally or on a server). The address can be changed under Arena3D options.
  • -
  • Arena3D (.json) saves the same network in Arena3D's JSON format, to load in Arena3D yourself.
  • -
  • Table (.txt) saves Arena3D's tab-separated upload format: SourceNode, SourceLayer, TargetNode, TargetLayer, Weight, Channel. NORMA can read such files back (see Files and formats).
  • -
- -
Running, API and troubleshooting
-

API for other applications

-

Other programs can open NORMA with their own networks, groups and values, through the API tab's three routes (full reference, code for curl, Python, R and JavaScript, and a tester are on that tab):

-
    -
  • REST (needs server.py): POST /api/external with a JSON payload returns {"token", "url"}; opening url (norma.html?session=TOKEN) shows the data. Payloads are kept in the server's memory for 24 hours (NORMA_API_TTL_HOURS). GET /api/health tells whether a server offers the API.
  • -
  • Links (no server needed): norma.html?data=URL loads a payload file, ?network=URL&annotation=URL&expression=URL loads NORMA files (the other site must allow cross-site downloads), and #json=… carries a small payload inside the link.
  • -
  • postMessage (no server needed): a page that opens NORMA in a window or iframe receives norma:ready, sends {"type": "norma:load", "payload": …} and gets norma:loaded back with a summary or an error.
  • -
-

The payload is a JSON object: name; the network as edges (source, target, optional type, weight, directed), as NORMA files or as a complete network view; optional nodes with attributes, groups (and more groupings in annotations), expression (colors or numbers per node), settings (display settings, theme, layout) and tab. A whole session file is accepted too. Each call opens a new view; the network, groupings and values also appear in Files. If a link's data cannot be read, NORMA opens the API tab and says why.

- -

Running NORMA locally or on a server

-

NORMA is one web page (norma.html) plus a small server program (server.py, Python 3.8 or newer, no extra packages). The same package runs NORMA on your own computer or as a public web server; everything that differs is a setting.

-

On your own computer

-
    -
  • Double-click run_local.sh (macOS, Linux) or run_local.bat (Windows), or run python3 server.py: NORMA opens in your browser at http://localhost:8000, reachable only from this computer.
  • -
  • Without Python: open norma.html directly. Everything works except the REST API and the relays; database importers then call the services directly, which some browsers block.
  • -
-

As a public web server

-
    -
  • Run python3 server.py --mode hosted --config norma.config.json (start from norma.config.hosted.json), behind a web server that provides HTTPS on port 443 (deploy/nginx.conf), as a system service (deploy/norma.service) or in a container (Dockerfile, docker-compose.yml). The server can also serve HTTPS itself (--tls-cert, --tls-key, optional --http-redirect-port 80).
  • -
  • Hosted mode listens on all addresses, trusts the proxy's X-Forwarded-* headers, logs requests without IP addresses, sends security headers (HSTS over HTTPS) and never opens a browser.
  • -
  • Any static web server (nginx, Apache, GitHub Pages) can also serve the folder; settings then come from norma-config.js, and the REST API and relays are not available.
  • -
-

Settings

-

Settings come from, in increasing priority: built-in defaults, the settings file (norma.config.json, or --config / NORMA_CONFIG), environment variables and command-line options; python3 server.py --print-config shows the result, and --help lists every option. The server hands the page its part of the settings as /norma-config.js.

- - - - - - - - - - - - - - -
SettingOption / variableMeaning
mode--mode, NORMA_MODElocal (default) or hosted; sets sensible defaults for the rest
server.host, server.port--host, --port, NORMA_HOST, NORMA_PORTWhere the server listens (local 127.0.0.1, hosted 0.0.0.0; port 8000)
server.publicUrl--public-url, NORMA_PUBLIC_URLThe address users see (e.g. https://norma.example.org/); used in API links
server.tlsCert, tlsKey, httpRedirectPort, hsts--tls-cert, --tls-key, --http-redirect-portServe HTTPS directly, redirect HTTP to it, send Strict-Transport-Security
server.trustProxyNORMA_TRUST_PROXYRead the reverse proxy's forwarded headers (hosted: on)
server.accessLog--access-log, NORMA_ACCESS_LOGoff (local), anonymous (hosted: no IP addresses) or full
api.enabled, ttlHours, maxMB, maxSessions--no-api, NORMA_API, NORMA_API_TTL_HOURS, NORMA_API_MAX_MBThe REST API and how long, how large and how many payloads it keeps
relays.string, arena3d, databases--no-relays, NORMA_RELAYSTurn the relays on or off; without them the page calls the services directly
site.*NORMA_CONTACT_EMAIL, NORMA_INSTITUTION, NORMA_NOTICEName, institution, contact e-mail and page, source code, licence name and link, privacy policy and imprint links, maintenance statement, tested browsers, and a notice shown at the top of the page (e.g. planned maintenance)
app.maxNodes, theme, startTab, cdnFallbackNORMA_MAX_NODESLargest network shown (default 10,000), starting theme and page, and whether Cytoscape.js may be downloaded if the bundled copy is missing
-

What the server offers

-
    -
  • API: NORMA's REST API (/api/external, /api/session/TOKEN, /api/health); see API for other applications.
  • -
  • STRING relay: /string-api/ passes read-only STRING calls to string-db.org addresses, spaced a second apart. With Database importers → STRING → STRING server → Connect set to Automatically, NORMA uses the relay when it is available and otherwise calls STRING directly.
  • -
  • Database relay: /db-api/fetch passes the importers' calls to Reactome, OmniPath, NDEx, IntAct, QuickGO and the GO API, and only to those services' API addresses.
  • -
  • Arena3D relay: /arena3d-api/external passes Open in Arena3D to arena3d.org.
  • -
  • Package contents: norma.html, index.html (forwards static web servers' root address to norma.html), norma-config.js, server.py, norma.config.json and norma.config.hosted.json, norma_api_client.py (Python template), run_local.sh / run_local.bat, Dockerfile, docker-compose.yml, deploy/ (nginx, systemd), vendor/ (Cytoscape.js), assets/, README.md and NAR_CHECKLIST.md.
  • -
  • STRING logo: to show STRING's official logo in the importer, save it as assets/string-logo.png.
  • -
- -

Performance

-
    -
  • Display → Performance → Draw with WebGL uses Cytoscape.js's WebGL renderer, which draws large networks much faster. It is experimental: the choice is made when the page starts, so NORMA asks to reload the page (save the session first to keep your views). Adding ?webgl=1 or ?webgl=0 to the address sets it for one visit. Exported images, group shading, the 3D page and everything else work the same.
  • -
  • The Runtime table at the end of the Network Profiler page times the main steps on random networks of 100 to 10,000 nodes in your browser: reading the network file, building the network, the weighted layout, edge bundling, the profile statistics, Louvain and the group separation score. Drawing time depends on the screen and is not included. Download table saves the times with the browser and processor count, for a supplementary table.
  • -
  • Network size: NORMA shows networks of up to 10,000 nodes. A network file, JSON file, session or combination of networks with more nodes is cut to its first 10,000 nodes (in the order they first appear) and the edges among them, and a message says how much was left out. To study part of a bigger network, filter it first (for example to a pathway, a STRING neighbourhood or a community).
  • -
  • Networks of a few thousand nodes are comfortable; beyond that, turn on WebGL drawing, turn off labels, curved edges and edge bundling, and use the grid or weighted force-directed layout.
  • -
- -

Keyboard shortcuts

- - - - - - - - - - - - - - - - - -
KeysAction
Ctrl+Z (⌘Z)Undo the last change to the view
Ctrl+Shift+Z or Ctrl+YRedo
Ctrl+A (⌘A)Select every shown node (2D and 3D Network pages)
EscapeClear the selection; in the search box, clear the search; in a dialog or shape chooser, close it
Enter in the search boxZoom to the matching nodes
Shift-drag on the backgroundDraw a selection box
Shift-click or Ctrl/⌘-clickAdd a node to the selection or remove it
Double-clickOn the background: fit the network; on a node: center it
Left/Right arrows on a tabMove between pages or between the Data and Display tabs
Arrow keys in the shape chooserMove between shapes; Enter picks one
Arrow keys on the 3D networkTurn and tilt the view (with Shift: in bigger steps)
+ / – on the 3D networkZoom in and out
F or 0 on the 3D networkFit the network to the screen
- -

Troubleshooting

-
    -
  • Only part of my network appears: NORMA shows up to 10,000 nodes and keeps the first 10,000 of a larger network (see Performance).
  • -
  • A network file is rejected: its first line must be the header Source, Target (optionally Weight and Type), separated by tabs.
  • -
  • Groups are missing: node names in the annotation must match the network exactly, including capitalization. Names that don't match are discarded when the annotation is uploaded and when it is shown; the status notes list them, and Download corrected annotation saves the cleaned file.
  • -
  • An annotation was not kept: none of its names matched the networks it was checked against. Upload it together with its network, or tick the right network before uploading it.
  • -
  • A node doesn't take its group's shape: it is shown with more than one active group, so it stays a circle. Untick the other groups to see the shape.
  • -
  • Arena3D doesn't open: if the browser blocked the new tab, use the Open Arena3D link in the status note. If Arena3D can't be reached, run NORMA with server.py, or save the Arena3D (.json) and load it in Arena3D.
  • -
  • STRING can't be reached: check the internet connection, and run NORMA with server.py (see Running NORMA locally or on a server) so that requests go through its relay. If the server is running but requests fail, set Connect to Through this server to see its error. If a request takes too long, lower Interactors to add or try again later.
  • -
  • STRING found none of the names: check the spelling and the organism; a gene name from one species often isn't found in another.
  • -
  • A STRING grouping is missing: that collection had no terms passing the FDR and group-size limits, or isn't available for the organism. The notes list what STRING returned; raise the FDR limit or lower Smallest group.
  • -
  • A file was read as the wrong type: remove it, pick its type in the upload box and upload it again.
  • -
  • The view is slow: try straight edges instead of bundled or curved ones, turn off group shading or use the hull style instead of fog, merge parallel edges, or deactivate groups you don't need.
  • -
  • Colors look alike: switch to a colorblind-safe palette, or click a swatch to set a color yourself.
  • -
  • No arrows are shown: the edges aren't marked as directed, or Edges → Direction is set to undirected. Choose Treat all edges as directed, or upload the file again as directed or with a Direction column.
  • -
  • B→A disappeared after uploading: the file was read as undirected, where A→B and B→A are the same connection. Delete it (its ✕ in Files) and upload it again with Networks: directed.
  • -
  • My parallel edges became one edge: the network file has no Type column, or Edges → Parallel edges is set to merge. Add a Type column, show the networks together as separate files, or switch back to drawing each channel.
  • -
  • A function ignores some nodes or edges: layouts, sizes, statistics, Network Comparison and exports work on the ticked groups and channels only. Tick them again, or untick Only ticked groups and channels before exporting.
  • -
  • An exported image is smaller than chosen: the browser can't draw images beyond about 16,000 pixels per side; the dialog says when the size was reduced. Choose a lower resolution or export only what is on screen, or use SVG, which has no size limit.
  • -
  • The 3D picture is slow: turn off group shading or shaded spheres, lower Depth fading, hide labels, or untick groups and channels you don't need. Large networks are drawn simplified while they move.
  • -
  • The 3D network looks flat: the layout is Same as 2D (flat), or the camera is facing it from the front. Run another 3D layout or choose View from → Tilted.
  • -
  • A few edges are missing: edges between two nodes that sit on top of each other can't be drawn. Run a layout again or use Spread.
  • -
- -
-
-
- -
-
-
- -
-

NORMA 3.0 The Network Makeup Artist

-

A browser application for visualising and analysing biological networks together with their functional annotations: how genes, proteins or other entities that share a pathway, complex, GO term or community sit in a network, and how several networks compare.

-
-
- -
-

How to cite

-

If NORMA helps your work, please cite:

-
    -
  • Karatzas E, Koutrouli M, Baltoumas FA, Papanikolopoulou K, Bouyioukos C, Pavlopoulos GA. The network makeup artist (NORMA-2.0): distinguishing annotated groups in a network using innovative layout strategies. Bioinformatics Advances. 2022;2(1):vbac036. PMID: 36699373, doi:10.1093/bioadv/vbac036 (NORMA-2.0, group-aware layout strategies)
  • -
  • Koutrouli M, Karatzas E, Papanikolopoulou K, Pavlopoulos GA. NORMA: The Network Makeup Artist, a web tool for network annotation visualization. Genomics, Proteomics & Bioinformatics. 2022;20(3):578–586. doi:10.1016/j.gpb.2021.02.005 (the original NORMA application)
  • -
-

Please also cite the databases and methods you use; see Resources and methods.

-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Bubble-set groups -outlines that hug only the members - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -−2 -0 -2 -log2FC -Numeric values -color scales, sizes, legends, steps - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Ribosome - -Proteasome - -Spliceosome - -Glycolysis - -−log10 FDR -Communities and enrichment -Leiden, MCL, Walktrap; term tests - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -3D network -rotate, tilt and zoom freely - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -A - -B - -C -shared -edges -Compare networks -UpSet plots, Venn diagrams, statistics -
- -

What NORMA does

-

Networks of interacting molecules are easier to understand when you can see which nodes belong together. NORMA takes a network and one or more annotations (groupings of nodes, such as pathways, complexes, GO terms, tissues or communities) and shows them together: groups are shaded with hulls, bubble sets or fog clouds, nodes in several groups become pie charts, and layouts can arrange the network by its connections or by its groups, so that groups separate cleanly.

-

On top of the picture, NORMA adds node colors from expression data or numeric values, node sizes from topology, several edge channels between the same nodes (evidence types, interaction types or whole networks), directed edges, a 3D view, network statistics, community detection, group enrichment and a side-by-side comparison of up to ten networks. Networks can be uploaded as simple tab-separated files, fetched from six public databases, and exported as images, as files for Cytoscape, Gephi and yEd, or straight into Arena3D.

-

Everything runs in your browser, from a single file (norma.html); a small optional server (server.py) relays database requests. NORMA 3.0 continues NORMA and NORMA-2.0, which introduced group-aware layout strategies.

- -

Highlights

-
-
Groups made visibleConvex hulls, bubble sets and fog clouds; pie-chart nodes; one shape per group; group colors and descriptions.
-
Group-aware layoutsThe NORMA-2.0 strategies, groups as blocks, clusters or layers, plus force-directed, Kamada–Kawai and stress majorization; a separation score and benchmark.
-
Multi-edge and directedSeveral channels per node pair, merged, fanned, bundled or labelled; arrows and direction-aware statistics.
-
Values and legendsExpression colors, numeric color scales, time-series steps, node sizes and exportable legends.
-
AnalysisNetwork profiles, five community detection methods, group statistics, enrichment, neighbourhoods and shortest paths.
-
ComparisonUp to ten networks with Venn and UpSet plots, similarity and degree statistics, drawn as one network or sent to Arena3D.
-
Database importersSTRING, Reactome, OmniPath, NDEx, IntAct and the Gene Ontology, with their groupings.
-
3D and exportA 3D page, high-resolution PNG, SVG and PDF, NORMA files, GraphML, GEXF, SIF, Cytoscape, Arena3D and sessions.
-
- -

Data sources

-

NORMA reads your own files and the resources below. Nothing is sent to a resource until you use its importer; see Database importers in Help for how each one works.

- - - - - - - - - - - -
ResourceNetworkGroupingsWhat NORMA fetches
STRINGYesYesProtein association networks with evidence channels; enriched GO, KEGG, Reactome, UniProt, domain, disease and tissue terms
ReactomeYesYesThe molecules of a pathway's reactions, linked when they share a reaction; sub-pathways and reactions as groups
OmniPathYesYesSigned, directed signalling, TF–target and ligand–receptor interactions; complexes, intercellular roles, pathway annotations
NDExYesLimitedPublic networks with their layout; groups from node attributes
IntActYesNoExperimentally detected interactions with MI-scores and interaction types
Gene OntologyLimited (GO-CAM)YesCausal GO-CAM models as networks; GO terms (QuickGO) as groups for any network
Arena3DExportViews and comparisons as multilayer networks, one layer per group or network
-

None of these services needs an account for public data. Please follow each resource's terms of use and cite it when you use its data (see Resources and methods).

- -

What's new in NORMA 3.0

-
-

Everything works on the groups and channels you tick

-

This is the main difference from earlier versions of NORMA. Untick groups under Node groups or channels under Edge channels, and every function works on the part that stays ticked: nodes in at least one ticked group, and edges of ticked channels between those nodes. Nothing has to be re-uploaded or filtered by hand.

-
    -
  • Layouts, both by connections and by groups (including the NORMA-2.0 strategies), arrange only the shown nodes using only the ticked channels; hidden nodes keep their places.
  • -
  • Node sizes by degree, betweenness, closeness or clustering, and the statistics in a node's details panel, are computed on the shown part.
  • -
  • Group shading, node shapes and pie slices follow the ticked groups: a node in two groups turns into a single-group shape when the other group is unticked.
  • -
  • Edge bundling, edge merging and edge labels use only the ticked channels.
  • -
  • Search finds only shown nodes, and Spread and Fit to screen work on what you see.
  • -
  • The Network Profiler and Network Comparison pages analyse the shown part of each view.
  • -
  • Exports (NORMA files and JSON) save the shown part, unless you untick Only ticked groups and channels.
  • -
-

So you can, for example, tick two KEGG pathways and one evidence channel, lay them out, size nodes by betweenness within that sub-network, profile it, compare it with another view, and export exactly that.

-
-
-

Multi-edge networks are supported

-

Previous versions of NORMA did not support multi-edge graphs. A network could hold only one connection per pair of nodes: repeated connections were removed automatically when a file was loaded, so a pair supported by, say, both experiments and text mining ended up as one plain edge.

-

NORMA 3.0 keeps every connection. The same pair of nodes can be linked by several edges, each belonging to a channel (an interaction type, an evidence source or a whole network):

-
    -
  • An optional Type column in a network file keeps one edge per pair and type; only exact repeats of the same pair and type are removed (see Network file).
  • -
  • Ticking several network files overlays them, with each network as its own channel (see Several networks and multi-edges).
  • -
  • JSON files and the built-in demos can carry any number of edges per pair, each with its own type, weight, direction and attributes.
  • -
  • Channels can be colored, ticked and unticked one by one; parallel edges can be fanned apart, merged per pair, bundled or labelled; and layouts, node sizes, the Network Profiler and Network Comparison can be limited to the ticked channels.
  • -
-
- -
-

Directed networks

-

Edges can point from a source to a target, and each view can handle its network as directed or undirected. Arrows show the direction; a Direction column in network files, a directed/undirected choice when uploading, and a directed field in JSON bring direction in; in- and out-degree, direction-following betweenness and closeness, reciprocity, strongly connected components and directed path lengths analyse it. See Directed and undirected networks.

-
- -
-

A 3D Network page

-

The new 3D Network tab shows the current view in three dimensions: the same groups, colors, pies, shapes, labels, arrows and group shading, with its own 3D layouts (weighted force-directed, groups as 3D clusters, groups on stacked layers, height by hierarchy or degree), rotate, pan and zoom controls, automatic rotation and 3D image export. See 3D Network.

-
-
-

Import networks and groupings from STRING

-

STRING in the Database importers tab fetches the interaction network of one or more proteins for any organism, with control over the number of interactors, confidence, network type and evidence channels, and turns enriched GO terms, KEGG and Reactome pathways, UniProt keywords, protein domains, diseases, tissues and more into groupings you can switch between. See Importing from STRING.

-
- -

Also new

-
    -
  • Deleting files and views: views, networks, groupings and expression files can be removed completely with Delete… next to Rename, the ✕ next to the Grouping menu, or the ✕ in Files.
  • -
  • API: other applications can open NORMA with their networks and groups by REST, links or postMessage; see the API tab.
  • -
  • Welcome tab and tidier menus: a permanent Welcome tab; every sidebar section folds open and closed from its title; separators group related options; the three NORMA JSON files are named view, session and settings files.
  • -
  • Database importers: besides STRING, Reactome, OmniPath, NDEx, IntAct and the Gene Ontology (GO-CAM networks and GO term groupings), in a tab of their own; exports moved to an Export tab.
  • -
  • Welcome page: NORMA starts on a page that shows what it does, with quick ways to open an example, fetch from STRING or upload files.
  • -
  • Classic layouts: Kamada–Kawai and stress majorization, for connections, as group strategies and inside groups.
  • -
  • Group analysis: group statistics and the modularity of a grouping, a network of groups, and enrichment of annotation terms in selected nodes or in each group of another annotation.
  • -
  • Comparison as a network: Show as network merges compared networks into one view whose edges say which networks contain them.
  • -
  • Local exploration: a node's neighbourhood or the shortest paths between two nodes, opened as a new view.
  • -
  • Time series and conditions: step through value columns or several numeric files, by hand or as an animation, with the layout fixed.
  • -
  • More export formats and sessions: GraphML, GEXF, SIF and Cytoscape (.cyjs) for Cytoscape, Gephi and yEd, and whole sessions (all views and files) in one file.
  • -
  • Performance: optional WebGL drawing for large networks, and a runtime table of the main steps.
  • -
  • Export to Arena3D: open the current view in Arena3D with one click, each group as its own layer, or save it as an Arena3D file (.json) or table (.txt); Arena3D tables can also be uploaded.
  • -
  • Showcase examples: a directed signalling cascade with simulated fold changes, a simulated healthy-vs-disease pair for Network Comparison, and Arena3D's seven-layer example (see Examples).
  • -
  • Numeric expression values: log2 fold changes, p-values or any numbers in expression files, shown on diverging or sequential color scales and as node size, with an optional legend that can also go into exported images.
  • -
  • More community detection: Leiden, label propagation, Walktrap and Markov clustering next to Louvain in the Network Profiler, each able to become a grouping.
  • -
  • A number for group separation: silhouette width, nodes inside other groups' outlines and outline overlap after every layout, and a layout benchmark that compares all layouts, including the NORMA-2.0 strategies, on the current view.
  • -
  • STRING import: fetch a protein's interaction network from the STRING database for any organism, with control over the number of interactors, confidence and evidence channels, and turn its enriched GO terms, KEGG and Reactome pathways, keywords, domains, diseases, tissues and more into groupings.
  • -
  • A 3D network: the 3D Network page shows the current view in three dimensions, with the same groups, colors, shapes, labels, arrows and shading, its own 3D layouts, and rotate, pan and zoom controls.
  • -
  • Working with several visualizations: views, each with its own settings; a Grouping list in the top bar to regroup a view while keeping positions; undo and redo for every change to a view.
  • -
  • A clearer screen: the View list in the top bar, colored labels saying which network, grouping and colors are shown, node, edge, channel and group counts, and color-coded sidebar sections split into Upload Data, Database importers, Display and Export (see Finding your way around).
  • -
  • Layout: arrangement by connections or by groups, NORMA-2.0's three group strategies, groups as non-overlapping blocks, a weighted Fruchterman–Reingold layout, and a Spread slider.
  • -
  • Groups: Bubble Sets–style contours that hug each group, node shapes per group alongside group colors, a filter for long group lists, pies of up to 16 slices, and group details with shared members.
  • -
  • Labels: adjustable sizes and colors for node and edge labels, edge labels showing channels, weights or any edge attribute, and hiding labels when zoomed out.
  • -
  • Edges: edge bundling, merging of parallel edges, curved fan-out, weight-based thickness and edge opacity.
  • -
  • Exploring: search by name, prefix, suffix or regular expression in a panel that can be minimized; selecting several nodes (shown in yellow); zoom without limits while the network stays in frame.
  • -
  • Data: attributes on nodes, edges and groups (Attributes, JSON format); annotation checks on upload with a corrected annotation to download (Files and formats).
  • -
  • Direction: networks are handled as undirected by default, as in earlier versions of NORMA; directed data can be shown with arrows in one click (see Directed and undirected networks).
  • -
  • Analysis: a Network Profiler with a short description of each statistic, Louvain communities that can be added as an annotation, and Network Comparison of up to ten networks with Venn diagrams, UpSet plots, similarity matrices, degree agreement and topology side by side.
  • -
  • Output: image export in high resolution as PNG, JPEG, WebP, vector SVG or PDF; NORMA files and JSON limited to the ticked groups and channels if you like.
  • -
  • Examples: NORMA's example datasets and built-in demos, with every file downloadable.
  • -
  • A white theme by default, and keyboard shortcuts.
  • -
- - -

Resources and methods

-

NORMA builds on the following software, data resources and published methods. When you use their data or results, please cite them as well.

-

Software

-
    -
  • Cytoscape.js draws the 2D network; statistic definitions follow igraph; color scales follow ColorBrewer and viridis.
  • -
-

Data resources

-
    -
  • STRING: Szklarczyk et al., Nucleic Acids Research 2023;51(D1):D638–D646.
  • -
  • Reactome: Milacic et al., Nucleic Acids Research 2024;52(D1):D672–D678.
  • -
  • OmniPath: Türei et al., Molecular Systems Biology 2021;17:e9923.
  • -
  • NDEx: Pratt et al., Cell Systems 2015;1(4):302–305.
  • -
  • IntAct: del Toro et al., Nucleic Acids Research 2022;50(D1):D648–D653.
  • -
  • Gene Ontology: Gene Ontology Consortium, Genetics 2023;224(1):iyad031.
  • -
  • Arena3D: Karatzas et al., Nucleic Acids Research 2021;49(W1):W36–W45, doi:10.1093/nar/gkab278.
  • -
-

Methods

-
    -
  • Community detection: Louvain (Blondel et al., J Stat Mech 2008:P10008), Leiden (Traag et al., Sci Rep 2019;9:5233), label propagation (Raghavan et al., Phys Rev E 2007;76:036106), Walktrap (Pons and Latapy, J Graph Algorithms Appl 2006;10(2):191–218) and MCL (van Dongen, PhD thesis, University of Utrecht, 2000).
  • -
  • Layouts: Kamada and Kawai (Inf Process Lett 1989;31(1):7–15); stress majorization (Gansner, Koren and North, Graph Drawing 2004, LNCS 3383:239–250) with a pivot-MDS start (Brandes and Pich, Graph Drawing 2006, LNCS 4372:42–53).
  • -
  • Edge bundling: Holten and van Wijk's force-directed method (Computer Graphics Forum 2009;28(3):983–990, doi:10.1111/j.1467-8659.2009.01450.x).
  • -
  • Statistics: enrichment p-values adjusted as in Benjamini and Hochberg (J R Stat Soc B 1995;57(1):289–300); group separation by the silhouette width of Rousseeuw (J Comput Appl Math 1987;20:53–65).
  • -
- -

Team, access and maintenance

-
    -
  • Team: NORMA is developed by the Pavlopoulos Lab (GitHub). Source code: github.com/PavlopoulosLab/NORMA.
  • -
  • Access: NORMA is free and open to all users. It needs no login, registration or e-mail address, and no installation: it runs in the web browser.
  • -
  • Licence: NORMA is released under the licence shown on the Welcome page (MIT by default), which allows free use, including non-commercial and commercial use. The data resources have their own terms of use.
  • -
-
    - -

    Privacy, data and cookies

    -
      -
    • Your data stays private. Files you upload, the networks you build, views and sessions are processed in your own browser and are not uploaded anywhere. Nobody else can see them. Deleting a file removes it and everything read from it; closing the browser tab removes everything.
    • -
    • What leaves your browser: only what you send yourself: the names you search for with a database importer (to that database), a network you open in Arena3D (to Arena3D), and a payload you send to the NORMA REST API (to that server). On a NORMA server, these requests pass through the server, which does not store them; API payloads are kept in the server's memory only for the time shown in the API tab, and only someone with the link can open them.
    • -
    • No cookies, no tracking. NORMA sets no cookies and uses no analytics, advertising or third-party tracking. The only thing it stores is the WebGL drawing preference, in your browser's local storage, when you change it. Public NORMA servers log requests without IP addresses by default.
    • -
    • Third-party content: NORMA loads no fonts, scripts or images from other sites (a copy of Cytoscape.js is bundled).
    • -
    -
    -
    - - -
    - - - - diff --git a/frontend/package-lock.json b/frontend/package-lock.json deleted file mode 100644 index af73f76..0000000 --- a/frontend/package-lock.json +++ /dev/null @@ -1,3072 +0,0 @@ -{ - "name": "norma", - "version": "3.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "norma", - "version": "3.0.0", - "dependencies": { - "cytoscape": "^3.34.3" - }, - "devDependencies": { - "@playwright/test": "^1.61.1", - "@types/cytoscape": "^3.31.0", - "@types/node": "^26.2.0", - "eslint": "^10.6.0", - "jsdom": "^30.0.1", - "prettier": "^3.9.4", - "typescript": "^6.0.3", - "typescript-eslint": "^8.62.1", - "vite": "^8.1.3", - "vite-plugin-singlefile": "^2.3.3", - "vitest": "^5.0.1" - } - }, - "node_modules/@asamuzakjp/css-color": { - "version": "6.0.7", - "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-6.0.7.tgz", - "integrity": "sha512-vC/bk1Lz7Tn/EfU9/apOTBk80/8dyGyWMowPoV1tJ52muDGsDqt2HPT2klrFUiY60MQmQv9q8yIht15JnBgDGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@csstools/css-calc": "^3.3.0", - "@csstools/css-color-parser": "^4.1.10", - "@csstools/css-parser-algorithms": "^4.0.0", - "@csstools/css-tokenizer": "^4.0.0", - "lru-cache": "^11.5.2" - }, - "engines": { - "node": "^22.13.0 || >=24.0.0" - } - }, - "node_modules/@asamuzakjp/dom-selector": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-8.3.2.tgz", - "integrity": "sha512-93Z1N+BQNXysodoicpOIyNh2drHfz/CTf9nnT0FEx72GJcIiwgydD7tGAr78j41LsYn3hlRn+LdGPuBLn1Bl8Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "bidi-js": "^1.0.3", - "css-tree": "^3.2.1", - "is-potential-custom-element-name": "^1.0.1", - "lru-cache": "^11.5.2" - }, - "engines": { - "node": "^22.13.0 || >=24.0.0" - } - }, - "node_modules/@bramus/specificity": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", - "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", - "dev": true, - "license": "MIT", - "dependencies": { - "css-tree": "^3.0.0" - }, - "bin": { - "specificity": "bin/cli.js" - } - }, - "node_modules/@cacheable/memory": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@cacheable/memory/-/memory-2.2.0.tgz", - "integrity": "sha512-CTLKqLItRCEixEAewD3/j9DB3/o96gpTPD4eJ1v+DGOlxZRZncRQkGYqqnAGCscYd6RNeXfGeiuCphsPtqyIfQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cacheable/utils": "^2.5.0", - "@keyv/bigmap": "^1.3.1", - "hookified": "^1.15.1", - "keyv": "^5.6.0" - } - }, - "node_modules/@cacheable/utils": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@cacheable/utils/-/utils-2.5.0.tgz", - "integrity": "sha512-buipgOVDkkPXNR5+xBpDw7Zk2n1EvU7qBJCNUcL7rhQ//kfpOXPAvQ511Os0vpLYJ1pZnvudNytkQt2hst3wqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "hashery": "^1.5.1", - "keyv": "^5.6.0" - } - }, - "node_modules/@csstools/color-helpers": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.1.1.tgz", - "integrity": "sha512-gLNsunvwf3mCi5u5o46/Z/JcJMnhbHSaZ69rkgPzNM3J4s8hWwpPUQB6/tt0EDFyCiWzxANlx+2LJwpYj4zS1w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "engines": { - "node": ">=20.19.0" - } - }, - "node_modules/@csstools/css-calc": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.4.0.tgz", - "integrity": "sha512-XQKj5B7QiZcHiegCOCAzcAOJdhGgWOHbbu62h5e5mkHnn8lWcfiJhllkqWmxu5zWR9jucPHuo1iTB56P033hcg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=20.19.0" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^4.0.0", - "@csstools/css-tokenizer": "^4.0.0" - } - }, - "node_modules/@csstools/css-color-parser": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.2.3.tgz", - "integrity": "sha512-y4LpL+lmpuyKDiEFq2PnZUVFdAjsoB/qQJod79yLNokXyW7jewi+/WJ69EfItj8A2unWtxXnGjw6LYXgXu5ZjA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "dependencies": { - "@csstools/color-helpers": "^6.1.1", - "@csstools/css-calc": "^3.4.0" - }, - "engines": { - "node": ">=20.19.0" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^4.0.0", - "@csstools/css-tokenizer": "^4.0.0" - } - }, - "node_modules/@csstools/css-parser-algorithms": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", - "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=20.19.0" - }, - "peerDependencies": { - "@csstools/css-tokenizer": "^4.0.0" - } - }, - "node_modules/@csstools/css-syntax-patches-for-csstree": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.14.tgz", - "integrity": "sha512-HpbVXyrofRXpHpgkNIjU/3EWR4WJvOkO3emNK/L6X/mTJU7bGUI3AkkpoTNXznQLp0KRjLHELTGeKI5dIkI9JQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "peerDependencies": { - "css-tree": "^3.2.1" - }, - "peerDependenciesMeta": { - "css-tree": { - "optional": true - } - } - }, - "node_modules/@csstools/css-tokenizer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", - "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=20.19.0" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", - "integrity": "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.23.5", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", - "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^3.0.5", - "debug": "^4.3.1", - "minimatch": "^10.2.4" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@eslint/config-helpers": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.7.0.tgz", - "integrity": "sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^1.2.1" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@eslint/core": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", - "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@eslint/object-schema": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", - "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.3.tgz", - "integrity": "sha512-IkO+/KEUvwbVpiURZg+P7zF74z5Jxe0UgJxVni+RtoHQ6IZieXaO02kmadomap/q+l6bc/jdPGGqTjhuZnuz1Q==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^1.2.1", - "levn": "^0.4.1" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@exodus/bytes": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.1.tgz", - "integrity": "sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" - }, - "peerDependencies": { - "@noble/hashes": "^1.8.0 || ^2.0.0" - }, - "peerDependenciesMeta": { - "@noble/hashes": { - "optional": true - } - } - }, - "node_modules/@humanfs/core": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", - "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/types": "^0.15.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", - "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.2", - "@humanfs/types": "^0.15.0", - "@humanwhocodes/retry": "^0.4.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/types": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", - "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", - "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", - "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@keyv/bigmap": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@keyv/bigmap/-/bigmap-1.3.1.tgz", - "integrity": "sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "hashery": "^1.4.0", - "hookified": "^1.15.0" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "keyv": "^5.6.0" - } - }, - "node_modules/@keyv/serialize": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.1.1.tgz", - "integrity": "sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@oxc-project/types": { - "version": "0.150.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.150.0.tgz", - "integrity": "sha512-rDS5/31E9HfPl/CIzGrn0DOlvBbXFseQ5URJ9sYMfstbKLD/c6Gm9vmRzRGDdAXyOIL4zmO37lc9RIwYqVruZw==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/oxc-project" - } - }, - "node_modules/@playwright/test": { - "version": "1.63.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.63.0.tgz", - "integrity": "sha512-oxMK4vllB9RK5NQ2l1pq1IfOf2AvnEuj/vYGDj0H2nMtmtZpKtCwt/l00GEO6xjGfpBNAvjovvYdCm50dRQkpQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "playwright": "1.63.0" - }, - "bin": { - "playwright": "cli.js" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/@rolldown/binding-android-arm-eabi": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.9.tgz", - "integrity": "sha512-tNISae1QEf/vkb3xkRcjV5SEdzPE97We5IVaa2Z8jSszQPZ8U60B/YCYpw4QI7VidYsBtKavczXf+DyDs9WGxw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-android-arm64": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.9.tgz", - "integrity": "sha512-YC8YsI30o606GTZi0VyzYlsDKFP8W61i/QzayHDkLbNEz/IShqAmTa+hsJRj13xTHA0H+6fk4b2UmGn+Q/cMlg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.9.tgz", - "integrity": "sha512-IwhlH3qK5urrY8hZiEgGkHKEFN901p/p2bjxCxJlr4GyNnF7wYpUvK+Y43uaRYuC4hpfjzbR3SJC3arX1jGvmw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.9.tgz", - "integrity": "sha512-XxpJfVzFh+jilRxIXUqcfYAYcunIc/XEzIizsOL1fcJee5Sf7H3mH8WlLmfHfluz5amqR88QQo9izKtmMlavAw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.9.tgz", - "integrity": "sha512-kSfvhmgeWyfkbT3p/1s5vSgboogoah2zkm9fX2zjg2hHxSV7T4KhMWRUUaRk4OXNqoD3QAUeRqLcs1aZOK4U1g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.9.tgz", - "integrity": "sha512-1RVzG17pxqbTfYLC352JlLt6kKLG+6Hr30n8DlIJqsnV5luUDd2Qdx9Ayw1Cabfyb1K9k0jXEZ7evxkRoT+uiw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.9.tgz", - "integrity": "sha512-BXqPvZ2drqVD+/Z8UpKwcs4Mp7grM+eGFku4CAEKrEtcbAsUpzREphK1sogCRZGreVPiMkiiBtw0n3TPteuqvw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.9.tgz", - "integrity": "sha512-11vWvo8YDwLzukt27J3aYDWU+gg2P7J+ZOmiJ0hkF5BXZDW7pVya7r40MXDy6ya0i9KamoENSVKIugvJNgFXIA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.9.tgz", - "integrity": "sha512-a1tijMkdwsIARtc0F39ApURROkf3NwqinI6TOiSSWCTR7dT96dffNvMUtDHnq64wKNTIZOIlzKrFvvFUznJiyw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.9.tgz", - "integrity": "sha512-x6SQNdAvv4c3hWqTMaWuawzMX9myaCs/yEmlGsxJzkdClnHW7FbrjQuSiRDhuSYzEYoEMhsaJy9qHG/XNemJPQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.9.tgz", - "integrity": "sha512-9s0AZ8BFK5/n7B/TBoa2yJE3gI3KURrbXcPBlsAsvjU4VeJKgE90y1YtNxyEUIcHPQkg6/yfF3qihUrcM/Kf0Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.9.tgz", - "integrity": "sha512-P7VWAmV+WdJluH7ovnRGoiv2i8To7GAZ+kGzfGup635cyL7SyYl3lSUaA3Gp5THf0n/Co5EyEqb2zbqq+nMOHQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.9.tgz", - "integrity": "sha512-1qixtsE4BK8h+yS3BfmZ09UhA7O/N4IACva6YBr7EBvCJraByTuRcgOTaiA62Tm0vey3UcKXLOaoGHtYmNGEVg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.9.tgz", - "integrity": "sha512-ok8IQjcEPs1AKZfuEUznVBrJw+gK4soq+bx8b1X2XoMqVClarc1q5JDmVtWXY1xfr6ZuHTAsPXHTgTrqKTZeww==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.9.tgz", - "integrity": "sha512-Ip2mXoU0hM0boq3Rf+ekuT653OROSo6aSYcPT1VHE4q52KvyxgFkQgrgb/IEsxOuvQ2fZZbs8khJAyCEPM24/g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", - "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/chai": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", - "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/deep-eql": "*", - "assertion-error": "^2.0.1" - } - }, - "node_modules/@types/cytoscape": { - "version": "3.31.0", - "resolved": "https://registry.npmjs.org/@types/cytoscape/-/cytoscape-3.31.0.tgz", - "integrity": "sha512-EXHOHxqQjGxLDEh5cP4te6J0bi7LbCzmZkzsR6f703igUac8UGMdEohMyU3GHAayCTZrLQOMnaE/lqB2Ekh8Ww==", - "deprecated": "This is a stub types definition. cytoscape provides its own type definitions, so you do not need this installed.", - "dev": true, - "license": "MIT", - "dependencies": { - "cytoscape": "*" - } - }, - "node_modules/@types/deep-eql": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/esrecurse": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", - "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/estree": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", - "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "26.6.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.1.tgz", - "integrity": "sha512-VqGJBMCtdhqkBUCcBLvywI0NJ+KLuVzgNnlBUNFOQjqVxzo2lxLUNg1DSey8+u2u6ktswSAxg+s68QLzWHNOuA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~8.9.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.70.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.70.0.tgz", - "integrity": "sha512-/v8HZt6RlyIZxB3ntehELOcUcfxKPVGWXnQdJuHRmzrqgF8nQypcC/oxGW+Ot4VGKDq81XugPKxx0n5PBtf9PA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.70.0", - "@typescript-eslint/type-utils": "8.70.0", - "@typescript-eslint/utils": "8.70.0", - "@typescript-eslint/visitor-keys": "8.70.0", - "ignore": "^7.0.5", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.70.0", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.9.tgz", - "integrity": "sha512-brTTsvFRt5C1gGHtPst/281UjPD5t9fBqbgoMPlVWy11ZLTPfu7HxK4ZYqO9H7o/yC9rSTCI85EaQ4OoY12qYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "8.70.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.70.0.tgz", - "integrity": "sha512-zYvrmj9Yxd63UGaXw+kdt6A0F0s0qveJyuatIM77bYC2DE4pgmg7a50u8LR7PRtXd0x+h+Tl3eXabGm06SWd3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.70.0", - "@typescript-eslint/types": "8.70.0", - "@typescript-eslint/typescript-estree": "8.70.0", - "@typescript-eslint/visitor-keys": "8.70.0", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/project-service": { - "version": "8.70.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.70.0.tgz", - "integrity": "sha512-hFHbTNqhU9G+2eKFXCBVb1tjFT/LceiJ4+HfLO4pTpDI0KHi6iajpcFFkaSQ9gXmCh7n82A0PthaayEdN6mspQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.70.0", - "@typescript-eslint/types": "^8.70.0", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.70.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.70.0.tgz", - "integrity": "sha512-8nP3Kwh5hlgZ4FicGvmznAmJe8UL4sdU8tLukrPaMuQmDuk4Y8xYfzu/aYZW4xT2JCgc7H/TpDI5cGlxcWJSqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.70.0", - "@typescript-eslint/visitor-keys": "8.70.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.70.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.70.0.tgz", - "integrity": "sha512-adnkeeNq9Sq1sUf4+FRVc0KdgYghzsgFpZSQVZVvY0LCuUuN0FnQgyGzCJeC4fW1cdXseBAjU2EOqUIjbNcZUw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.70.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.70.0.tgz", - "integrity": "sha512-NUMKIhYVaVIVLnRL9CRt+VVcuLgSHUCpXn4/+K8wql+vdInUzvx8BjUO1oJ7cG9shjFJKtF8F8Hh2kCh3/KBVw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.70.0", - "@typescript-eslint/typescript-estree": "8.70.0", - "@typescript-eslint/utils": "8.70.0", - "debug": "^4.4.3", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "8.70.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.70.0.tgz", - "integrity": "sha512-asTOIYhDg4zdzOScCyaytrsV3cR6B4ecPQlXw/dJIm7J/MZTtCtfVII9JD8Geh4jTCrK/Xe6cg5UevoleMcoJQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.70.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.70.0.tgz", - "integrity": "sha512-d9NmHMPEKQ7QCLLm1jI3zmoQBwT5KwFYjXBJ9ymZfKCUU+5rmTRykKAFvH5Qn/ZCds3CEAFS9OC9M/jkl0X2bA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.70.0", - "@typescript-eslint/tsconfig-utils": "8.70.0", - "@typescript-eslint/types": "8.70.0", - "@typescript-eslint/visitor-keys": "8.70.0", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "8.70.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.70.0.tgz", - "integrity": "sha512-oZmtKJz/4fufZ2p3+Cn3ijEojcdfR+1zYDH2xKYrEly0dR/Q/1xUPRCOlKGxod78nWlU2UnDe09GZ3TaknBFGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.70.0", - "@typescript-eslint/types": "8.70.0", - "@typescript-eslint/typescript-estree": "8.70.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.70.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.70.0.tgz", - "integrity": "sha512-BoC8PiO4Hkdo0TVJh9Ntxr5MxPDI7/oFsrygN5ADelFSeXG/qgNuucIGA+L5Z6JpPTE/uRfcTWtscjbUaufepQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.70.0", - "eslint-visitor-keys": "^5.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@vitest/mocker": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-5.0.1.tgz", - "integrity": "sha512-6K1DoBNAPGvuOcSsGA4D6x+5zEEff/KmOOP3uetT2TrGpVfI+HRHRnJJfKi5ib/g1vx8IYHQD8s0pbJz8WQI7Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.31", - "@vitest/spy": "5.0.1", - "estree-walker": "^3.0.3", - "magic-string": "^1.2.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } - } - }, - "node_modules/@vitest/spy": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-5.0.1.tgz", - "integrity": "sha512-rbto/mF/SGERxEgYOek7Xm6B9b+y+mVoo+f4b2LymYO8zM1b7uB5nHuhVMTP2hxdzgxvGiZYGxGIaMvL5y180Q==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/acorn": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", - "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", - "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - } - }, - "node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/bidi-js": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.1.0.tgz", - "integrity": "sha512-fX1Onk0tdVPC7obPWB5EbJ1z7NVhLq4m2xZLq2YXBkxzMXIGRpNMU88n0EPgWseKl12J7zXs7qrDxPK4sRs2fg==", - "dev": true, - "license": "MIT", - "dependencies": { - "require-from-string": "^2.0.2" - } - }, - "node_modules/brace-expansion": { - "version": "5.0.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", - "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cacheable": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/cacheable/-/cacheable-2.5.0.tgz", - "integrity": "sha512-60cyAOytib/OzBw1JNSoSV/boK1AtHryDIjvVBk7XbN4ugfkM3+Sry7fEjNgPMGgOjuaZPAp8ruZ0Cxafwyq9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cacheable/memory": "^2.2.0", - "@cacheable/utils": "^2.5.0", - "hookified": "^1.15.0", - "keyv": "^5.6.0", - "qified": "^0.10.1" - } - }, - "node_modules/chai": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", - "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/css-tree": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", - "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", - "dev": true, - "license": "MIT", - "dependencies": { - "mdn-data": "2.27.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" - } - }, - "node_modules/cytoscape": { - "version": "3.34.3", - "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.34.3.tgz", - "integrity": "sha512-yfYGhRcGAntq6YBD583j4n0Eg3jIxvWmZtz/5uz9UYkeIStSlMxuUja+ec5j3iBD8nv1rwaOAYMW09tBdkSeaQ==", - "license": "MIT", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/data-urls": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz", - "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==", - "dev": true, - "license": "MIT", - "dependencies": { - "whatwg-mimetype": "^5.0.0", - "whatwg-url": "^16.0.0" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" - } - }, - "node_modules/data-urls/node_modules/whatwg-url": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.1.tgz", - "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@exodus/bytes": "^1.11.0", - "tr46": "^6.0.0", - "webidl-conversions": "^8.0.1" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decimal.js": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", - "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", - "dev": true, - "license": "MIT" - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/entities": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-8.1.0.tgz", - "integrity": "sha512-kxL7msIffSuh9aaFAMD7rxAIuTRMAHMeBtgHW2yUdWw732ZNh4MehkF2gdjvtdmikkaIP9bFDDJOPlsvm7avrA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=20.19.0" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/es-module-lexer": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", - "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", - "dev": true, - "license": "MIT" - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.10.0.tgz", - "integrity": "sha512-NPXn6r5zl4uET1DAVPaOwzX3rut4c0wcmw3dWJAfOsTM5+TogXo0DDjz8pwm/hL8cyVNpHqeK4JpN0NjnyFFNw==", - "dev": true, - "license": "MIT", - "workspaces": [ - "packages/*" - ], - "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.2", - "@eslint/config-array": "^0.23.5", - "@eslint/config-helpers": "^0.7.0", - "@eslint/core": "^1.2.1", - "@eslint/plugin-kit": "^0.7.3", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "ajv": "^6.14.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^9.1.2", - "eslint-visitor-keys": "^5.0.1", - "espree": "^11.2.0", - "esquery": "^1.7.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "11.1.5 || >11.1.6 <12", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "minimatch": "^10.2.5", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-scope": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", - "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@types/esrecurse": "^4.3.1", - "@types/estree": "^1.0.8", - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", - "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.16.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^5.0.1" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", - "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expect-type": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", - "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/file-entry-cache": { - "version": "11.1.5", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-11.1.5.tgz", - "integrity": "sha512-+PFTHITI08JIGhnNpGNI8T8inUpgZfk3GNEqfT9R2zZV2iFXg3CvqzSl/uEhs7TSGujYRELEANyDvS8Fj7+S7Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^6.1.23" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "6.1.23", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.23.tgz", - "integrity": "sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "cacheable": "^2.5.0", - "flatted": "^3.4.2", - "hookified": "^1.15.0" - } - }, - "node_modules/flatted": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz", - "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/hashery": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/hashery/-/hashery-1.5.1.tgz", - "integrity": "sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "hookified": "^1.15.0" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/hookified": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/hookified/-/hookified-1.15.1.tgz", - "integrity": "sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==", - "dev": true, - "license": "MIT" - }, - "node_modules/html-encoding-sniffer": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", - "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@exodus/bytes": "^1.6.0" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" - } - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/jsdom": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-30.0.1.tgz", - "integrity": "sha512-52v7mUVUfNQVYYqE1lcdaymWL0njO7lTLUog6ZvW2U5KsbiLk/GnZlVJ+qx0xfNJZ6Gn+KSpPNE52vurbxZwrA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@asamuzakjp/css-color": "^6.0.5", - "@asamuzakjp/dom-selector": "^8.3.0", - "@bramus/specificity": "^2.4.2", - "@csstools/css-syntax-patches-for-csstree": "^1.1.7", - "@exodus/bytes": "^1.15.1", - "css-tree": "^3.2.1", - "data-urls": "^7.0.0", - "decimal.js": "^10.6.0", - "html-encoding-sniffer": "^6.0.0", - "is-potential-custom-element-name": "^1.0.1", - "lru-cache": "^11.5.2", - "parse5": "^8.0.1", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^6.0.2", - "undici": "^8.9.0", - "w3c-xmlserializer": "^5.0.0", - "webidl-conversions": "^8.0.1", - "whatwg-mimetype": "^5.0.0", - "whatwg-url": "^17.1.0", - "xml-name-validator": "^5.0.0" - }, - "engines": { - "node": "^22.22.2 || ^24.15.0 || >=26.0.0" - }, - "peerDependencies": { - "canvas": "^3.2.3" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/keyv": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz", - "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@keyv/serialize": "^1.1.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lightningcss": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", - "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.33.0", - "lightningcss-darwin-arm64": "1.33.0", - "lightningcss-darwin-x64": "1.33.0", - "lightningcss-freebsd-x64": "1.33.0", - "lightningcss-linux-arm-gnueabihf": "1.33.0", - "lightningcss-linux-arm64-gnu": "1.33.0", - "lightningcss-linux-arm64-musl": "1.33.0", - "lightningcss-linux-x64-gnu": "1.33.0", - "lightningcss-linux-x64-musl": "1.33.0", - "lightningcss-win32-arm64-msvc": "1.33.0", - "lightningcss-win32-x64-msvc": "1.33.0" - } - }, - "node_modules/lightningcss-android-arm64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", - "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", - "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", - "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", - "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", - "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", - "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", - "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", - "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", - "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", - "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", - "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lru-cache": { - "version": "11.5.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", - "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/magic-string": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.4.1.tgz", - "integrity": "sha512-8lyCu36ErXR0J9uaGKlKQoiLZKmtI63YGLE8G2o9jyRPdr4X47LusSOwgOJOzcVtp81fTAAjxR7BwKz682Jhow==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.6.0" - } - }, - "node_modules/mdn-data": { - "version": "2.27.1", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", - "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", - "dev": true, - "license": "CC0-1.0" - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/minimatch": { - "version": "10.2.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", - "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.8" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/nanoid": { - "version": "3.3.19", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.19.tgz", - "integrity": "sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/obug": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.2.1.tgz", - "integrity": "sha512-XrsrhT5sybtKI6wakr2SPOlGZWWYbUXZ7a0jT8/QOeAPau+1X/bSegNe5YR75oJmEZQbKningirmGOEJCIk61Q==", - "dev": true, - "funding": [ - "https://github.com/sponsors/sxzz", - "https://opencollective.com/debug" - ], - "license": "MIT", - "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parse5": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", - "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", - "dev": true, - "license": "MIT", - "dependencies": { - "entities": "^8.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", - "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/playwright": { - "version": "1.63.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.63.0.tgz", - "integrity": "sha512-+7ziBLidS4NaNCdt57SUDT+wYmmd5fmiQejUic/kb+YsYSCPyOOE9sebzMjNmQrsnNpDJqd4WHvV/8lfKfUDUg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "playwright-core": "1.63.0" - }, - "bin": { - "playwright": "cli.js" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/playwright-core": { - "version": "1.63.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.63.0.tgz", - "integrity": "sha512-rYCsBF/M5HjUch52bbtVONEFjv6Xu8sm8h72dNlR5bzIE1fvC/bxgspzkjSfU+MweEMmPM8KJebG6nnyxo5mCg==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "playwright-core": "cli.js" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/postcss": { - "version": "8.5.28", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz", - "integrity": "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.18", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.9.7", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.7.tgz", - "integrity": "sha512-T3mF5P7HFzZVLDQuCUNtJj6WK1pcpLMweMNUVwGb01bLNkH9AkKxtZvmInw8K6bnn2O3d6/5RHl6zSHiBAD0Og==", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/qified": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/qified/-/qified-0.10.1.tgz", - "integrity": "sha512-+Owyggi9IxT1ePKGafcI87ubSmxol6smwJ+RAHDQlx9+9cPwFWDiKFFCPuWhr9ignlGpZ9vDQLw67N4dcTVFEA==", - "dev": true, - "license": "MIT", - "dependencies": { - "hookified": "^2.1.1" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/qified/node_modules/hookified": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/hookified/-/hookified-2.2.0.tgz", - "integrity": "sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA==", - "dev": true, - "license": "MIT" - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/rolldown": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.9.tgz", - "integrity": "sha512-hx/Pv0N1haXRb11qkfnK5MXB/iqr7i0yjWQqmO9uHqZpBgQSqzc8UsSnEpalsh+j1I8qQ2CkXAkJC8Br3dKSlg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@oxc-project/types": "=0.150.0", - "@rolldown/pluginutils": "^1.0.0" - }, - "bin": { - "rolldown": "bin/cli.mjs" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "optionalDependencies": { - "@rolldown/binding-android-arm-eabi": "1.2.9", - "@rolldown/binding-android-arm64": "1.2.9", - "@rolldown/binding-darwin-arm64": "1.2.9", - "@rolldown/binding-darwin-x64": "1.2.9", - "@rolldown/binding-freebsd-x64": "1.2.9", - "@rolldown/binding-linux-arm-gnueabihf": "1.2.9", - "@rolldown/binding-linux-arm64-gnu": "1.2.9", - "@rolldown/binding-linux-arm64-musl": "1.2.9", - "@rolldown/binding-linux-ppc64-gnu": "1.2.9", - "@rolldown/binding-linux-s390x-gnu": "1.2.9", - "@rolldown/binding-linux-x64-gnu": "1.2.9", - "@rolldown/binding-linux-x64-musl": "1.2.9", - "@rolldown/binding-openharmony-arm64": "1.2.9", - "@rolldown/binding-win32-arm64-msvc": "1.2.9", - "@rolldown/binding-win32-x64-msvc": "1.2.9" - } - }, - "node_modules/saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", - "dev": true, - "license": "ISC", - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=v12.22.7" - } - }, - "node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true, - "license": "ISC" - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true, - "license": "MIT" - }, - "node_modules/std-env": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz", - "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", - "dev": true, - "license": "MIT" - }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinybench": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-6.1.4.tgz", - "integrity": "sha512-9APumHG7r4yOk4X4WlkmE71aZcv1gvin1czO3OQ1U9iJcFA5Ja/ygyb0vPOVHTthFozUYs8CLoLUlM8grb2lTQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/tinyexec": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.0.tgz", - "integrity": "sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", - "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tldts": { - "version": "7.4.13", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.13.tgz", - "integrity": "sha512-iHtaIWWIbMDkCeJdTBzZFGgbluE5J+oHlb2g7+oAz1S1gpuVpabRZdQyd471Vl8UUkcz2vXSL8xZH2kyCe8tfA==", - "dev": true, - "license": "MIT", - "dependencies": { - "tldts-core": "^7.4.13" - }, - "bin": { - "tldts": "bin/cli.js" - } - }, - "node_modules/tldts-core": { - "version": "7.4.13", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.13.tgz", - "integrity": "sha512-mbYsrih5FRtGxs3Usvl/PqwJsNpp+jsmrdFviiK02teHDG0/HebBG/pqCylje3kzgXYzuLoHJF/0mz9W53t8Xg==", - "dev": true, - "license": "MIT" - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tough-cookie": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.2.tgz", - "integrity": "sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "tldts": "^7.0.5" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/tr46": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", - "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", - "dev": true, - "license": "MIT", - "dependencies": { - "punycode": "^2.3.1" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/ts-api-utils": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", - "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12" - }, - "peerDependencies": { - "typescript": ">=4.8.4" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/typescript": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", - "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-eslint": { - "version": "8.70.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.70.0.tgz", - "integrity": "sha512-P/W5cz70/cQAuKfY3xwQMWWTV7BvJ0mAQmi+9mBcsVPaBUpd6Ohpa+fECv9rBFrQcig86jAiNBFNWUqnTjr4pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/eslint-plugin": "8.70.0", - "@typescript-eslint/parser": "8.70.0", - "@typescript-eslint/typescript-estree": "8.70.0", - "@typescript-eslint/utils": "8.70.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/undici": { - "version": "8.10.2", - "resolved": "https://registry.npmjs.org/undici/-/undici-8.10.2.tgz", - "integrity": "sha512-/y4/bH9YNU5hi9NIrpOuvGXFcxrj3CMrV+/AYpowAYTpHn8gX/XPFjNy766FPoYY0miQhdW977JFWKGNhBdwyQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=22.19.0" - } - }, - "node_modules/undici-types": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.9.0.tgz", - "integrity": "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==", - "dev": true, - "license": "MIT" - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/vite": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.0.tgz", - "integrity": "sha512-lhZBVvEHefgE+HQZC9O7EBJgCU/nVzFNl7vkS4RE0APtWLP02/8QVIkQtzBxPquh7lq5/78NHipTj7ODQ6XuyQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "lightningcss": "^1.33.0", - "picomatch": "^4.0.7", - "postcss": "^8.5.28", - "rolldown": "~1.2.6", - "tinyglobby": "^0.2.17" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.7.1", - "esbuild": "^0.27.0 || ^0.28.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "@vitejs/devtools": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/vite-plugin-singlefile": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/vite-plugin-singlefile/-/vite-plugin-singlefile-2.3.3.tgz", - "integrity": "sha512-XVnGH0QzbOa8fxRSsHdCarVN1BSBXNi7uLMQYlrGRN5apdHkk62XQWRJhVever0lnfuyBkwn+kvVChdm/OoOUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">18.0.0" - }, - "peerDependencies": { - "rollup": "^4.59.0", - "vite": "^5.4.21 || ^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/vitest": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-5.0.1.tgz", - "integrity": "sha512-iA95lQbKEkvrtTkdAgnWbXfbipWiiWe/hDl2P5tMi6WFwD76G0NxXAGp/M9EOcYupeGJRr6wppMc7CoA41TQjg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/chai": "^5.2.2", - "@vitest/mocker": "5.0.1", - "chai": "^6.2.2", - "es-module-lexer": "^2.3.2", - "expect-type": "^1.4.0", - "magic-string": "^1.2.3", - "obug": "^2.1.4", - "picomatch": "^4.0.7", - "std-env": "^4.2.0", - "tinybench": "6.1.4", - "tinyexec": "1.3.0", - "tinyglobby": "^0.2.17", - "why-is-node-running": "^2.3.0" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": "^22.12.0 || ^24.0.0 || >=26.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@opentelemetry/api": "^1.9.0", - "@types/node": "^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "5.0.1", - "@vitest/browser-preview": "5.0.1", - "@vitest/browser-webdriverio": "^5.0.0-beta.5 || >=5.0.0", - "@vitest/coverage-istanbul": "5.0.1", - "@vitest/coverage-v8": "5.0.1", - "@vitest/ui": "5.0.1", - "happy-dom": "*", - "jsdom": "*", - "vite": "^6.4.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@opentelemetry/api": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser-playwright": { - "optional": true - }, - "@vitest/browser-preview": { - "optional": true - }, - "@vitest/browser-webdriverio": { - "optional": true - }, - "@vitest/coverage-istanbul": { - "optional": true - }, - "@vitest/coverage-v8": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - }, - "vite": { - "optional": false - } - } - }, - "node_modules/w3c-xmlserializer": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", - "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "xml-name-validator": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/webidl-conversions": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", - "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=20" - } - }, - "node_modules/whatwg-mimetype": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", - "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - } - }, - "node_modules/whatwg-url": { - "version": "17.1.1", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-17.1.1.tgz", - "integrity": "sha512-ohjk1mdUebJVadRt3bAhQhx8lSnISq+GDttK79LFl8EHQkAPvzwctoasC4hs8tBt6kLAncBWWyq1N52qEfKvDw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@exodus/bytes": "^1.15.1", - "tr46": "^6.0.0", - "webidl-conversions": "^8.0.1" - }, - "engines": { - "node": "^22.14.0 || >=24.0.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", - "dev": true, - "license": "MIT", - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/xml-name-validator": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", - "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true, - "license": "MIT" - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/frontend/package.json b/frontend/package.json deleted file mode 100644 index 25b7615..0000000 --- a/frontend/package.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "norma", - "private": true, - "version": "3.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc --noEmit && vite build", - "preview": "vite preview", - "lint": "eslint src e2e", - "format": "prettier --write src e2e", - "test": "vitest", - "test:e2e": "playwright test" - }, - "dependencies": { - "cytoscape": "^3.34.3" - }, - "devDependencies": { - "@playwright/test": "^1.61.1", - "@types/cytoscape": "^3.31.0", - "@types/node": "^26.2.0", - "eslint": "^10.6.0", - "jsdom": "^30.0.1", - "prettier": "^3.9.4", - "typescript": "^6.0.3", - "typescript-eslint": "^8.62.1", - "vite": "^8.1.3", - "vite-plugin-singlefile": "^2.3.3", - "vitest": "^5.0.1" - } -} diff --git a/frontend/playwright.config.ts b/frontend/playwright.config.ts deleted file mode 100644 index f52e8cb..0000000 --- a/frontend/playwright.config.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { defineConfig, devices } from '@playwright/test' - -// E2E runs against server.py serving the page (relays off, API on). -export default defineConfig({ - testDir: './e2e', - fullyParallel: false, - retries: process.env.CI ? 2 : 0, - timeout: 60_000, - reporter: [['list']], - use: { - baseURL: 'http://127.0.0.1:8765', - trace: 'on-first-retry', - }, - projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }], - webServer: { - command: - 'npm run build && python3 ../backend/server.py --port 8765 --no-open --no-relays --access-log off', - url: 'http://127.0.0.1:8765/api/health', - reuseExistingServer: !process.env.CI, - timeout: 30_000, - }, -}) diff --git a/frontend/public/assets/apple-touch-icon.png b/frontend/public/assets/apple-touch-icon.png deleted file mode 100644 index 9817c97817ebb70aeef483e49c27c256d53407db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19248 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Bubble-set groups -outlines that hug only the members - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -−2 -0 -2 -log2FC -Numeric values -color scales, sizes, legends, steps - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Ribosome - -Proteasome - -Spliceosome - -Glycolysis - -−log10 FDR -Communities and enrichment -Leiden, MCL, Walktrap; term tests - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -3D network -rotate, tilt and zoom freely - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -A - -B - -C -shared -edges -Compare networks -UpSet plots, Venn diagrams, statistics - \ No newline at end of file diff --git a/frontend/public/assets/favicon-32.png b/frontend/public/assets/favicon-32.png deleted file mode 100644 index a3062957083e1035ad75db22b1f1ea73a343c1f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2325 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 diff --git a/frontend/public/assets/favicon.ico b/frontend/public/assets/favicon.ico deleted file mode 100644 index 63437669ddae5cc56cbcc921554aa2d9924f8726..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14429 zcmajFV{|6b5-uFPvEDb<#I`54ZQGpKwryjAiLHrk+fF9tOq|@DbN+lkzIAV}R_$7= zc6Ifx-Op3I!N9=50AN5M*w;n`CJqS(CjOs0qW{SlaA06DUu{fG|C5D5U|@xaU|@oR z|C7CN!N3l_fq_LT%1a=@5EDbU z)^Rx)4^k|)hQiV&v+VsSNoBJ#6kaGtW9@OjYJY6Yc)IEyf+U=opat_Cf{CkO@(X6d zhe~;Z>%$)80t!*Xl8Vu)%7<{~nht%x?KmnCP>}xd)Ted2x{x%{d&Las)6){?INPOE zVxWjX56+Ajc;o=zTRB2>$0eX<%u#dcM;SHS9ScspN1UcwR7p;_mRJYJoKmFNe^N~? zZh2aF@@YUtGNq%h6i`K74~mK38^^FKee5$K4+^!(phVusXq_u}<@7Pg?pa}HMRU!g zU25z8@le=t-Xx-@7!fc>g*O*LPjSRLpZ?R!F>*?x)DjUhL0<9?BKMCXy=3`fDQrau zaR8g*_o!2ubK4mN34PC0G>dKuz1Ps`N$lqmz-N`(v-!Ige!{W^+*n`$gpjD^8nQ|< z%pY1z&(F%4r^7!B#iaS0%{{AJdBhGNn19zsMNL>(EkfudL8u@>#Ue}gY(TxlziChX zk0-uvZ{@tJo)2%2di!RV=1_6R}eS@^px| zvkdX-uBl!VpmTjx?tXC{lJKy{lrb~-t6OFCbXr_N447Ggk3cJqa;^AWNbs5T3SF%Q z*t$x?pN#%9=hAw$W4m$h&fGBy?cD^M@1(FnbTuT+&>jTh#<+zPJ2qS{3XlN^-y2o4 z;CvW!&;s7#BDsqG$OSndg2<(6c~0mzw1p_QvsedDi?yXHZgP(*vE)Btwmw-T8quZ0 zzw!f2N=#m~M%Xau|0j!xzSKnj%_3(nuLm$N*v&}n17SJ9gm(opUxjMpWDtgV7)8|wXf`d zSJ;gnBuF-?X9E<$VPS>)irL_6QvKmu!!}W-F-D^$!y_(~(!Fb5ZO_ZZWT}y@&&#U% zGc1NOe)on4E%YX`2TClltgZy$p~d)65&>EIAftp*339xvUN7cW3^OqT&X`qtY^t}S zxK#(!WtR(JZ^wJh{3!%~MFlL>LbXCGYXw&*s+@wAFrxKGS@Z7a7*}COpWHqEYa-mB z_&F?>d8itP$Gk*yX3AufxgN5~3t1isllfROmv%53$qI}PO4B6BYZqj(X)Cu1IATqX zk@5h`Q3zl4Yf1~gWUly`SE~uRZV`erTwcXIybRdoqK!T_yz2PI!u1f$@wJa0Ca6X4 z#lg7iU`nZ@|mNoRyP>raA z#to-O7ikkW%nSXwVr#vKyO&dV}b_39ktZvr3jL(Vj%NQVWvZ8H3ih<5Uw6Q^J# z=A5{NdGVQUT2MA%RRB>I7HCK`02MMkDfFs~nRYzo0cQwg|W zCN~H{c*!@GJcJbbd-ZO&Q2QWq0;Oe!Zo#VlpO-!%%y98%(u6yKAR1Yzv0=o_11M`T zCREuz)!&5dK}w;%5{4garjD#hXA(n(vBvOOiuCY{M4^w(4jKDRh-p|+1HC!WncPGE zu7r?d=#airPPG?DdB@Ko2Wp48q#?%ty5eo}!aAJ!Ikw`NQGqz>_-T~xv8CTL3%_UX zmGMX%)D4nGIg5Zofg*B%JN{Bfe6NOJYQ`=(C&PeKq*z<;TMgUoca3G+b;9AM3qpb-57d1y^q@Hx`}ZqwVukyrXcZ>rNp%<2+w*4Z=?MO-6DNybLu4 zG@M3~BYG5)oFDlF_N$3S6-qf+GQ=Cq4h#OyXYcVPARHLy!K`a44DaH}-;1w~16LXA z+?LPlWS8Ky8qHH3gbntr^9W$c2o6G*7L@^aZ-a&hN#0Tmszrv09G06-EdMR$-xjxC z-0E~NWa)UJF!o|>xSfKX`BrhF>x19I5a-1|96&;)43S{gX^Z`h^vXb|GuaHOJ%?pK>A zB*_55otk7wLrg6Oa{dFS(w@?N^;+9D|1`M>T}Ez+r!JvhKC&PQ^j=hfQ<}}w>>d-X zKMu9>OnP+_FJ~2~e~+pH7f{jH(e8uk%0C=)XxP?R1T9)z6)3YFV`MHSbv%%BjpA%a zIyjv}?7VC8OOB~Vea#v8`+|-_uF~R0828|rw9YH?dY{d-*oreqOR44E0u}EE@7SD{ zhQrg+<)IEm9f_J$e&*D*{$@YrJK^nJSh&&&Q{f$|%3?sw%{O@5-3bs@Pho%xv5_;r zq+Va8IROg$qr=2}{idRGU|^)iTwPt7!i&KEapke|&fUoEVB*XX6G;RWw{cMDkJCz) zG)bssjG`FT-4kAG5`t_m3sh^q@pt#8`~6idRi04_mCnvRqc^j7=MBCICD6alrnFA9 z7*$1_z`nPH!;(%+-3D|>OU2!poP$EjJop-S*S_LXHtN_M zZ9iI~kd_`KyKk%KwZmM63|FfjrgS0R9uE2_**moZD@@BX4JSvgwmZ)ZOI!Z?={u*; zyQkkr=I8YX`l(ZB%%mX6g(3jWEZGuJ!jJSt6~D78vH*o@tp{K%TujhqiW*1tx4lOf zmfwcX+PkoQ>Wt=tJ>$Asga5ieGXLft|8qvAz}OY=OTvHIFs#W*Y?KK4WW1kN^mK7g zR|q!rISxYpR_#}`r>$+diG&S(<;h>;p+xtz3QgBQrSP+aM})XsX=+%=Gb2QnjL_(J zrb2?TquZ7XiAFBA?17C2!sL6y{-fFSus%A?V3k6KW2}r{N8!%i<&oShc}AC4O2v)B zG_+M)d{IJJ$63r=zZWpbSULVgt91b-%Ob1<0nP<#o8wR+rR;lze6c)p$N^JF^$S@J z$&`kz-JucGsVD|tMsME&C%~V!F9>)wM!FZ8o8Bm(djqhJODp+~Wu@zX>;Ob(h5ue6 zmj7XZjJIUFa6YR_b^nOeVZvMBMBaE73t%ZE`0mMjyoJJCHZ81%KIa7G4DZUEFBg6$ z6asVX+xPe2Am<_u%t6jKY7I^0ZBO$X%*Fv(QMU>W-4l97Yb}ah3i? z0Ea?omL^d`x8LL*T1K+PT*WBUO(Di2wxl^-D_hC)zXycHp`ez|GJ(Ok<+-LDsf37^ zZsXV@Y6X|yV2j^3>*h6Ivnn9_D3e+DRewc6Z^JYM>eBY$c6t~?&2vSo6jGdl3$xfT z2Mv>Ut5mTM@4vRI<(47aC+;7+$PP?;53O5(SWC$^`iF!2j~_k*v0l#aj#Vc*C_q9( zMbo(&JABKYFSF`t7#w9oM8h1@wu&Z%7-n#@0g`ompVD=p=@M-5Q_9sm(r?D5?#Pel zGaJaR=**umkp&G0kx@5aq~rezivB}JnEnfjG$5Y85EKaRf1oHe%PK*4$@M>=Xl3Hz z!FE2zTwF33Kq@FX2pb{?fDY1It#`ET6^0webX&CrWN_AS9;t?+l&g|MCmZfT1S6Q5 zzyO8Kn07N@gAxSIK@D0VWSCP#R^pA8X;-IzyS(rA{&FMK8>EVFJ#M>Se_ovAEeLNl zF83dU6*QkW-2;{@{)7s~3z8BkK1ZhrEXFL+C;pCnDQTRPGLuzHqz1h}tsUcMOYm>L z_q)U_xWQ5;>6PW-_Pyctp8!n+g&cAq1ZEm_u z-o3YL$cr9^p9y%cTU{A?bYmY?KvEUXM7XfVKtST%*xpA4aTd+_F@P~(91*p02N0tQ zSGlH*kwdhM9bF*<^JgaxfAd`ur!l46>QvjY9MmW#68B274{nGE07v&xM2hEtE+X*2 z%vm0&s1V|Nv`CH!z_`gx_#4_An$!%v50V%ZE>JEK_XQmg2XVWfD(+lW*Db>n$z4u( zS6e(1u@zL17z5!>XO0W010P(3ZCC(Ic|jkqHh#>4kt90kpDmT@Csx#A`Sii+`d=|G=Q8)bi3S*~Z?iIS zn|VI{RVVOiM%oF_CDj)(zrXw-_Z@+i=UblhB*SnYOlAa;~kt)K5q(P6^8Q>nG$*}NtFpd$%4UWA) z2ZTi&%wQh3IcR02zoNdq*J83{eiyYH%I5?n_Bzxwxm7iDS>0PEp z^8MiExo&)2c)#^q$&uuRQ{W}c_(4#V?oLl7&)41N7LW}4uJ-|TWG z7%An24`gAp0{>&{Cdy}|-+%JrEWRdyfABjTOAS$vm}yx1Bq$$yx6?s~IU>-Op#4Tx zb3XRtMJ(eBI>rFsKJ;|wB%=MEo=0Jm#`@5B3fn;(J~+6>l7+C#lP;+t(AncSHM)F# zIMGg<&AtRCI1_o{I%o%5r*=?I6(gVGl;%Tf1aS?)o*tFu(xvyTUr8ISitxl8@VPLtxBoZhkI0C`MUNU{UFml%fnp~J1^jM1*Os43ON8vAmaY7+&7md*a_~` zXnA?Z`5@l(t)39Ufl)=&p%f6AlG3y>^8?2i;NhFtI~X4?YLJ01JUS#5^yt}+W%x@fiBZiZHHK`6(P`7YiQTxVu}*gDrL> zf${LSziuw@;Fbkuh3w1bHwyqYxQJyZD*9cs){R1eLGgThoSUx_upeeOpNfTxU5lo9KZ%!G?|!Xgdf)(o{+cCpbLApw_kx1A`14K<*lU+9$Z`egV9#gw6F5 zn~?xmpd_4CNYi!Sq`>%np8d8Nsbc3|(7O>UDkPOFg`Fe7fusPT-oq#K3Pn0hsg@~| z^EfPrv;P?X6((BT`Wbjx%Riy-PLnJa9R73cUW=K3@-e-$f3=_Ul$a4w90P^nDbU20 z7c$_QCuTB0sib7Tzc;(@d0mVhGahz046Es;H{f3y=2u7{X~+FH>jGt!ET5ubxK`b1 zHwZjagx5`iIPET#{^hr2Y@PC+%M*|>3j}5lYk}(AN;UG6D<@AwD-2ARXO>2|^1osl zDbhpK{H|Se3ynZ(qYd?pQ8j>u;U{8B8GHf5Hikw;q|Z8v4>F zQIu0Pri z!a^w93bb^Au!TsRU}$7fNd}APjCQ0mLnotlumv%d-n>8~@4%c=IQ=2$ga{#xy=U0!TJyl|Xm&#pY_`}z#Eta)$(6;qD4i10_Ck#0s#LasPmT+c)x%K$fxrQI{9KmW`un1Cz(zz8* z)jfze_Rm;h*Bsd%!xWEll(*v*KWX4te-R+M?`6#>g_e~G`bQzrDfP5HlS1l-Veo!u zfgP!1+b1DTIe_Sh)M3wnM*Qfk-62aTfd&*XiS3+8mh)LqOpKGrLxWRXQuZq*X{Ggse z-0;~$jOU}?$cwolU0-Fwtt|o@hBITiLtyTV{mI7)54Kg#jG9J{=$EC2cHVOh|J-=@ z9C>b@NOm`QXt@D{ljRBjt~G|8#(gzd2#qeY6#aTCPrC0gHtmcr2sH+4Gx0F;q{~~v z_6)%VlAXaCrQ5?hu7n!7e~}isYC3N@9LBG{DeQVGDIz_Vb))OZ%piVpZbh81c&QC} zq@^v3Yir}x=V|B^5Z6ErAJF?8^eC8ld~$xzsYB^#3Xa5}Oy;{JQ=Ujm_@h5~uJD!w zbNwdY&eos$eP{aYzI$+R6_{ul(y|P&tA^v9DQHwy8c-}3-S@&5Xhv(kJilJ$&L>!@+RPUzm{h?8C z^VJn;V#I=h=5RcrZ8}izL=`&LC|jW#^yixQt|~=NZja=@Ak)A4a+~ z!S7|2mRf$iU?1DT0C!%*>u#8NrYqGqR4QT+*8n>Ty|Kf*$p9BAn>fT> zNl*=f&-!t5ED41!T?qII@dyBYt?d9jPmBQ zsEK+^J`T8}-?Q~uUx$;PrC-}{nhFiIRFSA?pTi|-G>)w2ro$C%EVIORy0SqpbCz74 zapK+udE-iG8a)*Y(~pQ%U{d)3OQQ#I|BZlLx_N}%u_u z0j>eIVSK2a6zh*D+H}G)t8k)UVVP>r1~}SwWK7MlLm74Rwuplyk~XN&;uedc87t^< zNHJkHMfy+EgQ{w{AsnE1&Uw#)=Ija4m|1Lu3>xe>8&`bnxVrP;RXW!~?CV(3Q(JY^ zFQiXHs*+g29s0CHl|*fWq=dr71}I1T-G+u1YZ$MiSdIXy2iCWxKkk3t5MS&=Wmp1Q z+t4UjM+^7r+=1$GGE3vLJaR|$D|T0KOQ$(T`}%^sG&%FtK7Rx27|^4sm=!$##R3ex z3xbn7QZ+?2yNM<&hYv1)A`Oxvt5I)Qi*tL)`%4VwRdHgNgp|{H&5g|UaKm`o@+3_i z5aN<>vH=h_M3xC~`WUnWzBOP# zoaY+YA@TLV2BgMrDX93tiFKyizyaR_=Rfm54yRBO21t#z(1-}c;?D&&7{vIod--o% zRuN-7j2i86Z*X}=a7Qtb?2y0(-uA<*E~f8#t~qX}6?0^n4-H86In9L95WG}6xmJ7K z39gMuPC)lfHEUSE@@T=njnuw0H*cTl?S65ZI$dg&7X%pB7-yrI(*|LWwCSXy9XW0ekO*zHft~Dcmn>-!9~g1 zH{H#7Sb)Cd@PAz%^ody-sgJw7Kes;7+fI%iJZGVepPK!*4fm*e)QwNRVlvN^M zc{}!`;BDo~s8^%i62RkaG1#^$!|Mh@?nsPpL752Ko5(dkzk{quZT>5yRY-VSDUp9T{gz6GS6^e9r>3F6zzs!3&$0+g zMp<6fj5(U0EhAIV0;CT_23UkNClz6gt7CWBGE@cH&SnGkbhJ8_8$6vAqqwsnHEqIQ z_5JAz9MZU3amc>NSfVl*BMdXv$CF9RxgLH0?}_k9@a|(r+zQo#Alj0@B;ql*RS|%* z&0|3Xi>09aQ2!-^K$m=nN?G@6zuSm=_+>hgGL6 z@e>>a`RR`p#z##=e6tOpbGX^$Vrg}a`?#^{bbe#`YvH-Z!j42!^#%m)k30;@2^Gll zSq9aeMx>AXFZq%{kPMyR8X{=>F)x0<=8rFBu~QLxgl=*n=va*SOIvcG5<7=&&(aDg zg6~emEw;A!w2|pPtE4tIMbwn06Q$O@{Glknch>i=vr}y*JcMYme$%k9*?uUT!b?RG zD{cd$xF6Yrsp-34dj3f(<<|fPh{r1Gvs7w{orBZuGI!WHrj%|{?^H?gSt+`Y)r^Pa z5a%Houjz*q#8{f#z0H(fVm-3(ryoo2!($?MQ?(4`aLq7@AuX~6NZ{SC?eWY=A=NS>=e@DazQ%bqT33kG7j|J8I-IKiZ$J)rv^OI~YjR zF;Jz27_Q|w?I{|5VVz!v7#57C@S0zPb@pKKT+$^|U ze}t8=Hi|;vLXtU0*}(*Nc9#XZzd}+$8TAY=l|YdaQJFMVrhId3b|!QX$1!$Z*=LNr zd#{{}gIran_99Q1Ch5|1=(8Giln9=IIi=$i(=pZoA`5qeZSW8B{^h>-CWss4nm(9_ z%D5jGZ$Xdge$;jxqcp9bP}En8GoyW|cm1u$%o6^0@m&;_8;8?OrCp~0IvK9ZT&dfS z1F8uNo*M6=o4nXZglMeSpW%mg2=S~8*k$*wPbw zuq&PPz!@5KMwy%B86@D0=9`~)2>oktgy5_N??E&;sVV-9B)$Oc0F(@>XfVTfKK^9N zmhT{>-)&37a}iXaYK=8$e#)ZWHf^dJU-E=0??Ini6`+EV{%QzLBq@@REO+#?B`lhZ zC+GL?M0$3=9Dr_wAs+D4{2&HC7<{DKAE6N=A*5ROX@V66nv1CiEouY!(pqmXQw($^A?@o=`4AS~-&6pBt5+edC6UDlAAN#^#KqXA& zbjLHVideq*=Xm)NS-8X+0lMH;)`Ks@9n8+6}O_X=G{@SL#voVkW=WY z_W??x>h}lpnS<t;%L(Gt3IaTTBn0cb2n~YG^pNU0AhUNPgM^p`Bsm>n>Gtr7Ev@-< zIkx-Gfk;8Oeg4Qws%&Kj#Rqi|6F@^rw|Hoefg*;ds)0AC(ssV=T{C@68#U-*(?uL| zKZ~FliI~{VXX>m)S3-gPi#D^a#1d_~FQ8pmar)sNnNsI2knGoQ(--RBk&&2`zN=A@-7Uy#Y zZ?pvt{O|QujRi`znM-ccv%A6Fp_}ELADd~g`Ini|F=Zfdi#51Tc8<~K{GNn5f!^I! zY+6jZ!|rVR<8hvAvNY*=AmZ+C2CI?M0;q|*Jv?c{<(}aCNHoXK3F|l1;=N|MUy5zk z7-@~z^mMs)88~uidCmkPQh1=fMp}g8M_vV;^Hxxv^($^tP|bCb6)H|)6O3Y1?PS%$p$M}UapDys$%7^$h(^16jwn;n^<2^0 zbYGaN(yR;E(~L>RoIJ_H>lw;@+#EOC!h3R2NJr5Tr}&XAY{35-sF7t{H*o_}yWgQ0}2W1a;k7f?i?S zL^sjD6eh_j$(woj74H9ry%_2qCw4@W-=7%8@0@V7>XT$6Jd{4t6MryQl*4MwxBRatH*taXFbm z_xVWY#|Hy0?uI0##H<}nv*sX4yOEA2 z3>8E#T?-WyZUH#v{kQ4tf;7;w8C^Y{Rx9K{SSPDTb(V8RGmjmL-@iLNUNTSG_s(>< z670!eOQIwEuAKgWAhF+aLV+ec`D+)Z&jA zq~kILKhQPVpA(tIB8e~8>7wwBmo6MzP>!CLAY1Pjo#UO~m%g(&snW^`bRhqIX1!&+ zJbHkFsuB1;jJHFut8%Zx`|g99Jmt)Ed{DS&;&3u4x}MeRSiWAB+c~8PbCN~4KS#{c z2dhT^ekvPjM030tM{hY)&MFR9$-9x%h%Hz8^iN<@vWi&pzFK1+`VA;!JnxyrMa=#K zgk*X3IS$*H?bO-KB@%pygX=Q(Br;m1Zm&?kT=@+%IkL7nOX;PW;u2SZ^aU*ZLgE6cV!JEP^1wJZm>vZa+=1QJ#JQ(IsRy!#Gax5YQb{9v)Mteo z#V2ZWtsQQkdX|R7x@0?lT5If2-E=WZjsrphV(%6EL|II$NTNNk#Dc=YG4jOL_Cu`L z2Me92GQu4pDwbef8Q3FSP9|j&NNZ5ljf#qAqx3!n`p^W_xGq-^JGUJgleT4@-gfNw z`|v<{h8%(M(s}?-gwt>Zvc9JqWjUT-B=@!H-F=pp0H)!}Hs;l{Nl2nD-s8424^~c3 zR9^eNX2<)Et7FG7!Z$w0pHD?i0cHzp`n&np9~4+Qtx@mq!T78;AOo8>ZkznB zBw7C89^xR!t(TiPSc`bRB@sDCfr2de@cc6-Fm_>0jMco{zRTzPC&EI?rw;OW-Z~o& z$S1CY7^*Q{*36h_mas5rg#639`TVPrGI!*W2Rd`!Zzew`@M}I^K20xk4M>wC_E18i zDPdGVPlOkV%0w<1aMn6}=+>9v(Ihll1dr9b%NNg0QdzW^j|;B0X!R|~L2~@s=75M6 z7^Os_=@>Wh-vd=!w>EC^*W~lF!X#Y7IbxKKORdYO*0vP+GCxz)U|v!l+OjVM zQC}7D*L;EJf4|)v(gHr4awjExtGe!OF4mqo64P+VhQ%`)9k>kI&FBlmC|rm|WSr6F zN{OcAgo@;1x4Go``qXyykY8!}K4aD>RjVPuV=DL7djj*2JuWa9fz;4b<1M2j$vInF z(PW)^T4-?h`@Q;abK;DPV!)q$Cn5$OxDEc;JD<VL?(& zYpL4Ae^m)U+R#BZN|$IA z?d$#WVfQY1*u&6-_4UB7pFcL52)4%U7Dm`K$_kLtnI~x1Et7^pyT1_ji!F;WCx<68S~bahrTlt8s$@CvIqX>FVzTP z^BltM2Ln&b;N#y*;8)!~AwJ@gW_=URr}<>9ER2wrag^*gPFrkA;?1;nFsbr)rKg#L1J#Tl50<^@WI} ztOTcFAFEHX70!eciid0bkG%>@=jaU$an_`}dKdM;nh58NmjDP6xNF6hrciSkS0!ok zG1okVBDs2|qEZdQQhvjEV!t^U4A!1?;QZ1ouG{mY9lg&1;v;d_|tMJ0mxHXOPf7O%lBBCmPT_ z)nA>;*UyKH3&evDmm}lzQqsJJb#``D!`(4hA0tk({RIyRZbRt_h%Bo!ZxQM1YvK@M z+MQA>0as4V)>sd@=H1d;4$1pvfyU(E5}x@B1y)Xj(2%u9C7GVeT!7WOLUHJM@h~heR!YDx!)_YG$-?w+`oawgMeVOpaXkThGpFiexuyPf_ zJ8>8|j6J!TnJ`6s{fL3Wab`+T5>ao8*23U#Ub^mx=q#(%q+whWs%{+qLbhLfL=xtW?DD9=f-G*# z;M!tp#anyg|C(wb{G<_-qHG#Dz?@?W*$>wMfbO1({0a4#+ibaN{Fqm*?en6+|In4& z(PO6QjxJ3T@1FR*kg0M6-MDPK2s64gH#1Hn^{f+j@il%R$%Q-ZH7a&Wgyoh6!m(=t z8t=T!h;g1@#mV;~tiQ(U40mT?;RmbE7De3Jv+qAMg2Q=b*5{&J-+YRh0p)b&;;iOJ z^$D^j??x)Ax0R_r)p}I);r=`8L0~%qwfPhByo2@}%}$1!GjLs5+c;4C_{tZ!a1gUR zBKPIw$WundY4v|1kJ}xjVnmns4YvRMf}Hih4X{m!Tch;Bo$x|dF)5`#T7s+L#q=HW zOc*Ds?Fq-nh6W8PQE~WK1S49iINF@bR{ErCN?s z?|h>QVkVJBoNn*mANu&GYS@U{Jesk;Z7a4+nTc;cB>aFi9TrA(fg|`2x!)3h48y({ z%2rkfePIKtOHW_1=}OFW0S1UH3lu1qD=zu_oBn7E<7smqyESJ)!9?(WIuN)4E&R3q zKE|ELg|eQNcg!o((TKm3OOdJZ_9rxxx4SD;QgKE7yhB=Ryv@sdFs>RH@NfG_gJz<8 zr7bQvf)6C-ofz~rDz+IW+i96)js<70+s8W3V;^2SEi!rUwh0!U?TLMZ^IDnA$Jq@O z?wVuj2Z1x|IZU)uOJ#`8FPmgWJu)m7iS!e ze&s9$n5^;Z@Jy$^x^@4ng`k?|RcXGKvaL&TO_o0JW(sogvhP)WBjzrNPyuQfwmrDF@|uH1Fo;_^O1H92hs2t)r2jjD7~4pi+1 zi~C3Oy=wno%DLCoLJO~*An({G%(4%?2~7u5iHwTyZz9ebEbG_lqj_*b^iwpwZz5e6TvThk;k{+~WhiL5Yz0*SPOesNv-&cl!ztGA2QV>N zv^c|TX{P4WKcN#Hk`qNE*pQ>}sjT~3?R#ljixoDQN0w5Ns_UeVXA5fMy5&7w!cV|L zNQ55Okb&9M3X^kCYKdjDaVK*e2nTDGl7umuCI0W_>J4h1c#4ayGRONT7!r>M;~>n4 K-2Zpw>Hh#?GG|Eu diff --git a/frontend/public/assets/favicon.svg b/frontend/public/assets/favicon.svg deleted file mode 100644 index da43f50..0000000 --- a/frontend/public/assets/favicon.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/frontend/public/assets/logo.svg b/frontend/public/assets/logo.svg deleted file mode 100644 index 81a4b8b..0000000 --- a/frontend/public/assets/logo.svg +++ /dev/null @@ -1 +0,0 @@ -NORMA \ No newline at end of file diff --git a/frontend/public/index.html b/frontend/public/index.html deleted file mode 100644 index 25312bf..0000000 --- a/frontend/public/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - -NORMA - - - - - -

    Open NORMA

    - - diff --git a/frontend/public/norma-config.js b/frontend/public/norma-config.js deleted file mode 100644 index 61181b0..0000000 --- a/frontend/public/norma-config.js +++ /dev/null @@ -1,22 +0,0 @@ -// NORMA page settings for static hosting or opening norma.html from disk. -// When NORMA runs with server.py, the server replaces this file with the -// settings from norma.config.json. Every field is optional. -window.NORMA_CONFIG = { - mode: "local", - site: { - name: "NORMA", - institution: "", - contactName: "Pavlopoulos Lab", - contactEmail: "", - contactUrl: "https://github.com/PavlopoulosLab/NORMA/issues", - sourceUrl: "https://github.com/PavlopoulosLab/NORMA", - licenceName: "MIT License", - licenceUrl: "https://opensource.org/licenses/MIT", - privacyUrl: "", - imprintUrl: "", - maintainedUntil: "", - notice: "", - testedBrowsers: [] - }, - app: { maxNodes: 10000, theme: "white", startTab: "welcome", cdnFallback: true } -}; diff --git a/frontend/src/api/tester.ts b/frontend/src/api/tester.ts deleted file mode 100644 index 64c62c1..0000000 --- a/frontend/src/api/tester.ts +++ /dev/null @@ -1,639 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import apiClientTemplate from '../../../examples/norma_api_client.py?raw' -import { - MAX_NETWORK_NODES, - escapeHtml, - getUsedGroups, - refreshNodeVisual, - sanitizeColor, -} from '../network_state' -import { NORMA_CFG } from '../config' -import { S } from '../state' -import { - activeView, - captureActiveView, - closeActiveView, - nameForSelection, - profilerState, - renderProfilerNetworkList, - renderProfilerResults, - renderViewBar, - restoreView, - uniqueViewName, - views, -} from '../profiler' -import { applyGroupVisibility, buildGroupLegend, buildLegend, getUsedTypes } from '../hulls' -import { applyTypeVisibility } from '../parallel_edges' -import { b64urlEncode, normaApiLoad } from './wiring' -import { compareState, renderCompareList } from '../label_colors' -import { currentTab } from '../wiring' -import { cy } from '../cy' -import { dataVersion, setHistoryBaseline, updateUndoButtons } from '../demo_downloads' -import { - downloadText, - libEntry, - libSelection, - normaLibrary, - plural, - renderLibraryLists, - setStatus, -} from '../layouts/controls' -import { refreshEnrichmentChoices, toast } from '../enrichment' -import { refreshLibraryView } from '../library' -import { renderGroupingSelect, updateContextInfo } from '../recording' -import { updateEmptyState } from '../welcome' - -/* ---------- the API tab's tester ---------- */ -const API_EXAMPLE = { - name: 'API example', - edges: [ - { source: 'TP53', target: 'MDM2', type: 'binding', weight: 0.9 }, - { source: 'MDM2', target: 'TP53', type: 'ubiquitination', directed: true }, - { source: 'TP53', target: 'CDKN1A', type: 'expression', directed: true }, - { source: 'CDKN1A', target: 'CDK2', type: 'inhibition', directed: true }, - { source: 'CDK2', target: 'CCNE1', type: 'binding' }, - { source: 'ATM', target: 'TP53', type: 'phosphorylation', directed: true }, - { source: 'ATM', target: 'CHEK2', type: 'phosphorylation', directed: true }, - { source: 'CHEK2', target: 'TP53', type: 'phosphorylation', directed: true }, - ], - groups: [ - { name: 'DNA damage sensing', members: ['ATM', 'CHEK2'], color: '#8b5cf6' }, - { - name: 'p53 core', - members: ['TP53', 'MDM2'], - color: '#f59e0b', - description: 'p53 and its E3 ligase', - }, - { name: 'Cell cycle', members: ['CDKN1A', 'CDK2', 'CCNE1', 'TP53'] }, - ], - expression: { TP53: 1.8, MDM2: 1.2, CDKN1A: 2.6, CDK2: -1.1, CCNE1: -0.7, ATM: 0.3, CHEK2: 0.4 }, - settings: { - edgeDirection: 'data', - edgeCurveStyle: 'bezier', - showGroupHulls: true, - hullStyle: 'bubble', - legendShow: true, - layout: 'fr', - }, -} - -function apiPayloadFromBox() { - const text = document.getElementById('apiPayload').value - try { - return JSON.parse(text) - } catch (e) { - throw new Error(`The payload is not valid JSON: ${e.message}`) - } -} - -function apiBase() { - return location.href.replace(/[?#].*$/, '') -} - -/* ============================================================ - SITE INFORMATION (licence, access, privacy, contact) - Shown on the Welcome page, in About and as an optional notice, from - the settings (see Help: Running NORMA locally or on a server). - ============================================================ */ -function siteLink(url, text) { - return url - ? `${escapeHtml(text)}` - : escapeHtml(text) -} - -export function renderSiteInfo() { - const S = NORMA_CFG.site - const hosted = NORMA_CFG.mode === 'hosted' - const contact = S.contactEmail - ? `${escapeHtml(S.contactEmail)}` - : siteLink(S.contactUrl, S.contactName || 'contact') - const foot = document.getElementById('siteFooter') - if (foot) { - foot.innerHTML = [ - `Free and open to all users. No login, registration or e-mail address is needed.`, - `No cookies and no tracking; your data stays in your browser (privacy).`, - `Licence: ${siteLink(S.licenceUrl, S.licenceName || 'MIT License')}`, - `${siteLink(S.sourceUrl, 'Source code')}`, - `Contact: ${contact}`, - `Programmatic access: Python template`, - S.privacyUrl ? `${siteLink(S.privacyUrl, 'Privacy policy')}` : '', - S.imprintUrl ? `${siteLink(S.imprintUrl, 'Imprint')}` : '', - ] - .filter(Boolean) - .join('·') - } - const box = document.getElementById('aboutSiteInfo') - if (box) { - const browsers = - Array.isArray(S.testedBrowsers) && S.testedBrowsers.length ? S.testedBrowsers.join(', ') : '' - box.innerHTML = ` -
  • Running here: ${hosted ? `a public NORMA server${NORMA_CFG.publicUrl ? ` at ${siteLink(NORMA_CFG.publicUrl, NORMA_CFG.publicUrl)}` : ''}` : NORMA_CFG.served ? 'a NORMA copy on this computer or network' : 'a NORMA file opened on this computer'}${S.institution ? `, provided by ${escapeHtml(S.institution)}` : ''}. NORMA ${escapeHtml(NORMA_CFG.version || '3.0')}.
  • -
  • Contact: ${contact}${S.contactEmail && S.contactUrl ? ` · ${siteLink(S.contactUrl, 'issue tracker')}` : ''}.
  • -
  • Maintenance: ${S.maintainedUntil ? `this server is maintained at least until ${escapeHtml(S.maintainedUntil)}.` : 'NORMA is maintained by the Pavlopoulos Lab; the source code stays available in its public repository.'}
  • -
  • Browsers: NORMA is made for current versions of Chrome, Edge, Firefox and Safari on Windows, macOS and Linux, and needs no plug-ins or installation.${browsers ? ` Tested on this server with ${escapeHtml(browsers)}.` : ''}
  • ` - } - if (S.notice) { - const bar = document.getElementById('siteNotice') - bar.querySelector('span').textContent = S.notice - bar.hidden = false - } - document.querySelectorAll('[data-download-template]').forEach((a) => - a.addEventListener('click', (e) => { - e.preventDefault() - downloadApiTemplate() - }) - ) - const wf = document.querySelector('.welcome-foot') - if (wf) - wf.textContent = `NORMA ${NORMA_CFG.version || '3.0'} runs in your browser: your files stay on this computer, except what you send to online databases or Arena3D yourself. Networks of up to ${MAX_NETWORK_NODES.toLocaleString('en-US')} nodes.` - // REST API availability - const restBtn = document.getElementById('btnApiServer') - const setRest = (on) => { - restBtn.disabled = !on - restBtn.title = on - ? '' - : 'The REST API needs NORMA to run with server.py (with the API turned on).' - } - if (NORMA_CFG.features.restApi === false) setRest(false) - else if (!NORMA_CFG.served) setRest(false) - else if (NORMA_CFG.features.restApi !== true) { - fetch('api/health') - .then((r) => (r.ok ? r.json() : null)) - .then((j) => setRest(!!(j && j.status === 'ok'))) - .catch(() => setRest(false)) - } -} - -function downloadApiTemplate() { - const el = { textContent: apiClientTemplate } - let text = el ? el.textContent : '' - const base = - NORMA_CFG.publicUrl || - (NORMA_CFG.served - ? location.href.replace(/[?#].*$/, '').replace(/norma\.html$|index\.html$/, '') - : '') - if (base) - text = text.replace('DEFAULT_SERVER = "http://localhost:8000/"', `DEFAULT_SERVER = "${base}"`) - downloadText('norma_api_client.py', text) -} - -/* ============================================================ - DELETING FILES - A network, annotation or expression file can be deleted completely: - it leaves Files, every view that shows it is updated (views left with - no network become empty), undo can't bring it back, and results of - the Network Profiler and Network Comparison that used it are removed. - ============================================================ */ -const KIND_WORD = { network: 'network', annotation: 'annotation', colors: 'expression file' } - -const SEL_FIELD = { annotation: 'annotation', colors: 'colors' } - -function libViewUses(lv, kind, id) { - if (!lv) return false - if (kind === 'network') - return String(lv.nets || '') - .split('|') - .includes(id) - return lv[SEL_FIELD[kind]] === id -} - -// views that show a file (the current one as it is now, others as saved) -function viewsShowing(kind, id) { - return views.filter((v) => - libViewUses(v.id === S.activeViewId ? S.currentLibView : v.state && v.state.libView, kind, id) - ) -} - -export let nextLoadPositions = null - -const KIND_TITLE = { network: 'network file', annotation: 'grouping', colors: 'expression file' } - -// items: [{ kind, id }] files; opts.view: also offer to remove this view -export function askDelete(items, opts = {}) { - const files = items - .map(({ kind, id }) => ({ kind, id, entry: libEntry(kind, id) })) - .filter((x) => x.entry) - const choices = [ - ...(opts.view ? [{ type: 'view', view: opts.view }] : []), - ...files.map((f) => ({ type: 'file', ...f })), - ] - if (!choices.length) return - const dlg = document.getElementById('deleteDialog') - const box = document.getElementById('deleteChoices') - const single = choices.length === 1 - const label = (c) => - c.type === 'view' ? `the view "${c.view.name}"` : `the ${KIND_TITLE[c.kind]} "${c.entry.name}"` - document.getElementById('deleteTitle').textContent = single - ? `Are you sure you want to completely remove ${label(choices[0])}?` - : opts.all - ? `Are you sure you want to completely remove all ${plural(files.length, 'file')}?` - : 'Are you sure you want to completely remove these?' - box.innerHTML = '' - box.hidden = single || opts.all - if (!box.hidden) { - choices.forEach((c, i) => { - const row = document.createElement('label') - const cb = document.createElement('input') - cb.type = 'checkbox' - cb.checked = true - cb.dataset.index = i - const others = - c.type === 'file' - ? viewsShowing(c.kind, c.id).filter((v) => !opts.view || v.id !== opts.view.id) - : [] - const note = - c.type === 'view' - ? 'closes the view; its display settings and positions are lost' - : others.length - ? `also shown in ${others.map((v) => `"${v.name}"`).join(', ')}, which will be updated` - : 'removed from Files and every menu' - const text = document.createElement('span') - text.innerHTML = `${escapeHtml( - label(c) - .replace(/^the /, '') - .replace(/^./, (ch) => ch.toUpperCase()) - )}${escapeHtml(note)}` - row.append(cb, text) - box.appendChild(row) - cb.addEventListener('change', update) - }) - } - const confirm = document.getElementById('btnDeleteConfirm') - function picked() { - if (box.hidden) return choices - return [...box.querySelectorAll('input')] - .filter((x) => x.checked) - .map((x) => choices[+x.dataset.index]) - } - function update() { - const p = picked() - const pf = p.filter((c) => c.type === 'file') - const shown = new Map() - pf.forEach(({ kind, id }) => viewsShowing(kind, id).forEach((v) => shown.set(v.id, v))) - if (opts.view && p.some((c) => c.type === 'view')) shown.delete(opts.view.id) - const lines = [] - if (pf.length) - lines.push( - `${pf.length === 1 ? 'The file' : 'The files'} will be removed from Files, from the Grouping menu and every other list, together with everything NORMA read from ${pf.length === 1 ? 'it' : 'them'}.` - ) - if (shown.size) { - lines.push( - `${shown.size === 1 ? 'This view shows' : 'These views show'} ${pf.length === 1 ? 'it' : 'them'} and will be updated: ${[...shown.values()].map((v) => `"${v.name}"`).join(', ')}. ${pf.some((c) => c.kind === 'network') ? 'A view left without networks becomes empty; other views keep their remaining networks and node positions.' : 'They keep their networks and node positions but lose these groups or colors.'}` - ) - } - if (p.some((c) => c.type === 'view')) - lines.push( - views.length === 1 - ? 'This is the only view; a new empty view takes its place.' - : 'The view is closed and the previous view is shown.' - ) - lines.push('This cannot be undone. Your files on disk are not touched.') - document.getElementById('deleteText').innerHTML = lines - .map((t) => `

    ${escapeHtml(t)}

    `) - .join('') - confirm.disabled = !p.length - confirm.textContent = p.length > 1 ? `Yes, remove ${p.length}` : 'Yes, remove' - } - update() - confirm.onclick = () => { - const p = picked() - if (!p.length) return - closeDeleteDialog() - const pf = p.filter((c) => c.type === 'file').map(({ kind, id }) => ({ kind, id })) - const closeView = p.some((c) => c.type === 'view') && opts.view - if (pf.length) deleteLibEntries(pf) - if (closeView) { - if (S.activeViewId !== closeView.id && views.some((v) => v.id === closeView.id)) { - captureActiveView() - S.activeViewId = closeView.id - } - const name = closeView.name - closeActiveView() - renderLibraryLists() - renderGroupingSelect() - updateContextInfo() - updateEmptyState() - toast(`Removed the view "${name}"${pf.length ? ` and ${plural(pf.length, 'file')}` : ''}.`) - } - } - if (typeof dlg.showModal === 'function') dlg.showModal() - else dlg.setAttribute('open', '') - document.getElementById('btnDeleteCancel').focus() -} - -function closeDeleteDialog() { - const dlg = document.getElementById('deleteDialog') - if (typeof dlg.close === 'function' && dlg.open) dlg.close() - else dlg.removeAttribute('open') -} - -export function deleteLibEntries(items) { - const entries = items - .map(({ kind, id }) => ({ kind, id, entry: libEntry(kind, id) })) - .filter((x) => x.entry) - if (!entries.length) return - captureActiveView() - const affected = new Set() - const lostNetwork = new Set() - entries.forEach(({ kind, id }) => { - views.forEach((v) => { - const sel = v.selection || (v.selection = { networks: [], annotation: '', colors: '' }) - if (kind === 'network') sel.networks = (sel.networks || []).filter((x) => x !== id) - else if (sel[SEL_FIELD[kind]] === id) sel[SEL_FIELD[kind]] = '' - const lv = v.state && v.state.libView - if (libViewUses(lv, kind, id)) { - affected.add(v) - if (kind === 'network') { - lv.nets = String(lv.nets) - .split('|') - .filter((x) => x !== id) - .join('|') - lostNetwork.add(v) - } else { - lv[SEL_FIELD[kind]] = '' - } - } - }) - normaLibrary[kind] = normaLibrary[kind].filter((e) => e.id !== id) - // groupings fetched for a deleted network stay usable on their own - if (kind === 'network') - normaLibrary.annotation.forEach((e) => { - if (e.forNetwork === id) delete e.forNetwork - }) - }) - affected.forEach((v) => { - v.history = { undo: [], redo: [], committed: null } // no way back to deleted data - const lv = v.state.libView - if (!lv.nets) { - v.data = null - if (v.autoName) v.name = uniqueViewName('Untitled view') - v.state = { config: v.state.config || { ...S.DEFAULT_VIEW_CONFIG } } - v.selection = { networks: [], annotation: '', colors: '' } - v.needsRefresh = null - } else { - // the saved picture still holds the deleted data: drop it now and - // rebuild the view from its remaining files when it is shown - v.data = null - v.needsRefresh = { reload: true } - } - }) - // drop analysis results that used deleted networks or changed views - const deletedNets = new Set(entries.filter((e) => e.kind === 'network').map((e) => e.id)) - const staleView = (id) => [...affected].some((v) => v.id === id) - let droppedResults = 0 - if (profilerState.results.length) { - const keep = profilerState.results.filter( - (r) => - !( - deletedNets.has(r.sourceValue) || - (r.sourceValue === 'view' && affected.has(activeView())) - ) - ) - droppedResults += profilerState.results.length - keep.length - if (keep.length !== profilerState.results.length) { - profilerState.results = keep - if (keep.length) renderProfilerResults(keep) - else { - document.getElementById('profResults').innerHTML = '' - document.getElementById('btnProfileTsv').disabled = true - } - } - } - if (compareState.results) { - const used = compareState.results.some((r) => - (r.sourceValue || '').startsWith('lib:') - ? deletedNets.has(r.sourceValue.slice(4)) - : staleView((r.sourceValue || '').slice(5)) - ) - if (used) { - droppedResults += 1 - compareState.results = null - document.getElementById('cmpResults').innerHTML = '' - ;['btnCompareTsv', 'btnCompareNet'].forEach((b) => { - document.getElementById(b).disabled = true - }) - document.getElementById('cmpArena').hidden = true - } - } - // show the current view again - const act = activeView() - S.historySuspended++ - try { - restoreView(act) - } finally { - S.historySuspended-- - } - S.dataCache = { version: dataVersion, data: act.data } - setHistoryBaseline() - renderViewBar() - updateUndoButtons() - renderLibraryLists() - renderGroupingSelect() - updateContextInfo() - updateEmptyState() - if (typeof refreshEnrichmentChoices === 'function') refreshEnrichmentChoices() - if (currentTab === 'profiler') renderProfilerNetworkList() - if (currentTab === 'compare') renderCompareList() - const names = entries.map((e) => `"${e.entry.name}"`) - const notes = [ - { - level: 'ok', - text: `Deleted ${entries.length === 1 ? names[0] : plural(entries.length, 'file')}${affected.size ? `; updated ${plural(affected.size, 'view')} that showed ${entries.length === 1 ? 'it' : 'them'}` : ''}.`, - }, - ] - if (droppedResults) - notes.push({ - level: 'ok', - text: 'Profiler or comparison results that used the deleted data were removed.', - }) - setStatus('normaStatus', notes) - toast(notes[0].text) -} - -// Brings a view up to date after files it showed were deleted: rebuilds it -// from its remaining files with its saved node positions, group colors and -// ticked groups and channels. -export function refreshAfterDelete(v) { - v.needsRefresh = null - const st = v.state || {} - const lv = st.libView - if (!lv) return - libSelection.networks = new Set( - String(lv.nets) - .split('|') - .filter((id) => libEntry('network', id)) - ) - libSelection.annotation = - lv.annotation && libEntry('annotation', lv.annotation) ? lv.annotation : '' - libSelection.colors = lv.colors && libEntry('colors', lv.colors) ? lv.colors : '' - if (!libSelection.networks.size) return - nextLoadPositions = st.positions && Object.keys(st.positions).length ? st.positions : null - S.currentLibView = null - const status = document.getElementById('normaStatus').innerHTML - try { - refreshLibraryView() - } finally { - nextLoadPositions = null - } - document.getElementById('normaStatus').innerHTML = status - // keep what the view looked like - if (st.groupColors) { - Object.entries(st.groupColors).forEach(([g, c]) => { - if (S.nodeColorMap[g]) { - const sc = sanitizeColor(c) - if (sc) S.nodeColorMap[g] = sc - } - }) - } - const used = new Set(getUsedGroups()) - if (Array.isArray(st.activeGroups)) { - const was = new Set(st.activeGroups) - used.forEach((g) => { - if (g in (st.groupColors || {}) && !was.has(g)) S.activeGroups.delete(g) - }) - } - if (Array.isArray(st.activeTypes)) { - const was = new Set(st.activeTypes) - getUsedTypes().forEach((t) => { - if (!was.has(t) && (st.typeColors || {})[t]) S.activeTypes.delete(t) - }) - } - cy.batch(() => cy.nodes().forEach((n) => refreshNodeVisual(n))) - if (typeof applyGroupVisibility === 'function') applyGroupVisibility() - if (typeof applyTypeVisibility === 'function') applyTypeVisibility() - buildGroupLegend() - buildLegend(getUsedTypes()) - if (st.positions && typeof st.zoom === 'number') cy.viewport({ zoom: st.zoom, pan: st.pan }) - v.selection = { - networks: [...libSelection.networks], - annotation: libSelection.annotation, - colors: libSelection.colors, - } - if (v.autoName) { - const base = nameForSelection() - if (base && base !== v.name) v.name = uniqueViewName(base) - renderViewBar() - } - captureActiveView() -} - -// page wiring, run by main.ts in the original order -export function init() { - ;(function setupApiTab() { - const box = document.getElementById('apiPayload') - box.value = JSON.stringify(API_EXAMPLE, null, 2) - document.getElementById('btnApiReset').addEventListener('click', () => { - box.value = JSON.stringify(API_EXAMPLE, null, 2) - }) - document.getElementById('btnApiLoad').addEventListener('click', async () => { - try { - await normaApiLoad(apiPayloadFromBox(), 'the API tab') - } catch (err) { - setStatus('apiStatus', [{ level: 'error', text: err.message }]) - } - }) - document.getElementById('btnApiLink').addEventListener('click', async () => { - try { - const url = `${apiBase()}#json=${b64urlEncode(JSON.stringify(apiPayloadFromBox()))}` - document.getElementById('apiResultUrl').value = url - const note = - url.length > 8000 - ? ' This link is long; browsers and chat programs may cut it. For larger networks use the server (Send to server) or a data URL.' - : '' - setStatus('apiStatus', [ - { - level: url.length > 8000 ? 'warn' : 'ok', - text: `Made a link of ${url.length.toLocaleString()} characters that opens this payload.${note}`, - }, - ]) - try { - await navigator.clipboard.writeText(url) - } catch (e) {} - } catch (err) { - setStatus('apiStatus', [{ level: 'error', text: err.message }]) - } - }) - document.getElementById('btnApiServer').addEventListener('click', async () => { - try { - const body = JSON.stringify(apiPayloadFromBox()) - const r = await fetch('api/external', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body, - }) - const text = await r.text() - let j - try { - j = JSON.parse(text) - } catch (e) { - throw new Error( - 'This page is not served by server.py, so the REST API is not available here. Run NORMA with server.py, or use Make a link.' - ) - } - if (!r.ok) throw new Error(j.message || `The server answered ${r.status}.`) - document.getElementById('apiResultUrl').value = j.url - setStatus('apiStatus', [ - { - level: 'ok', - text: `The server stored the payload (token ${j.token}, kept for ${j.expiresInHours} hours).`, - action: { label: 'Open link', run: () => window.open(j.url, '_blank') }, - }, - ]) - } catch (err) { - setStatus('apiStatus', [ - { - level: 'error', - text: err.message.includes('fetch') - ? 'This page is not served by server.py, so the REST API is not available here.' - : err.message, - }, - ]) - } - }) - document.getElementById('btnApiCopy').addEventListener('click', async () => { - const v = document.getElementById('apiResultUrl').value - if (!v) return - try { - await navigator.clipboard.writeText(v) - toast('Copied the link.') - } catch (e) { - document.getElementById('apiResultUrl').select() - } - }) - // show the address this copy of NORMA answers on - const served = /^https?:$/.test(location.protocol) - const base = served - ? apiBase().replace(/norma\.html$|index\.html$/, '') - : 'http://localhost:8000/' - document.querySelectorAll('[data-api-base]').forEach((el) => { - el.textContent = base - }) - if (!served) { - document.querySelector('.api-base').innerHTML = - 'This copy of NORMA was opened from a file, so the examples use http://localhost:8000/, where server.py runs by default. Links with #json= and postMessage work from a file too.' - } - document.querySelectorAll('.api-code').forEach((pre) => { - const btn = document.createElement('button') - btn.type = 'button' - btn.className = 'api-copy' - btn.textContent = 'Copy' - btn.addEventListener('click', async () => { - try { - await navigator.clipboard.writeText(pre.innerText) - btn.textContent = 'Copied' - setTimeout(() => { - btn.textContent = 'Copy' - }, 1200) - } catch (e) {} - }) - pre.parentElement.insertBefore(btn, pre) - }) - })() - - document.getElementById('siteNoticeClose').addEventListener('click', () => { - document.getElementById('siteNotice').hidden = true - }) - - document.getElementById('btnDeleteCancel').addEventListener('click', closeDeleteDialog) -} diff --git a/frontend/src/api/wiring.ts b/frontend/src/api/wiring.ts deleted file mode 100644 index df69f03..0000000 --- a/frontend/src/api/wiring.ts +++ /dev/null @@ -1,453 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { - REACTOME_SPECIES, - dbCancel, - filterGoModels, - goAnnotateView, - goFetchModel, - goLoadModels, - intactFetch, - isSessionObject, - loadSession, - ndexFetch, - ndexSearch, - omnipathFetch, - reactomeFetch, - reactomeSearch, - toast, -} from '../enrichment' -import { UNGROUPED, getUsedGroups } from '../network_state' -import { - addNormaEntry, - libSelection, - plural, - renderLibraryLists, - setLayoutMode, - setStatus, -} from '../layouts/controls' -import { applyConfig, loadData } from '../hulls' -import { applyTheme } from '../themes' -import { cy } from '../cy' -import { openInNewView } from '../profiler' -import { refreshLibraryView } from '../library' -import { runLayout } from '../layouts/run' -import { switchTab } from '../wiring' - -/* ============================================================ - NORMA API - Other applications can open NORMA with their own networks and groups: - 1. REST (with server.py): POST a payload to /api/external; the answer - { token, url } holds a link that opens NORMA with the data loaded - (norma.html?session=TOKEN). - 2. Links: norma.html?data=URL (a payload file), or - norma.html?network=URL&annotation=URL&expression=URL (NORMA files), - or norma.html#json=BASE64URL (a small payload inside the link). - 3. postMessage: a page that opens NORMA in a window or iframe sends - { type: 'norma:load', payload, requestId } and gets back - { type: 'norma:loaded', ok, summary | error, requestId }. - Every route ends in normaApiLoad(payload). - ============================================================ */ -const NORMA_API_VERSION = '1.0' - -const API_MAX_BYTES = 50 * 1024 * 1024 - -function apiTextOf(v) { - if (v == null) return [] - return (Array.isArray(v) ? v : [v]) - .map((x) => (typeof x === 'string' ? { text: x } : x)) - .filter((x) => x && typeof x.text === 'string') -} - -function apiSafe(s) { - return String(s ?? '') - .replace(/[\t\r\n]+/g, ' ') - .trim() -} - -function apiNode(s) { - return apiSafe(s).replace(/,/g, ';') -} - -// { edges: [...] } -> NORMA network text -function apiEdgesText(edges) { - if (!Array.isArray(edges) || !edges.length) - throw new Error('"edges" must be a non-empty list of { source, target } objects.') - const weighted = edges.some((e) => typeof e.weight === 'number') - const typed = edges.some((e) => e.type) - const directed = edges.some((e) => e.directed) - const head = [ - 'Source', - 'Target', - ...(weighted ? ['Weight'] : []), - ...(typed ? ['Type'] : []), - ...(directed ? ['Direction'] : []), - ] - const rows = edges.map((e, i) => { - if (!e || e.source == null || e.target == null) - throw new Error(`Edge ${i + 1} needs a source and a target.`) - return [ - apiNode(e.source), - apiNode(e.target), - ...(weighted ? [typeof e.weight === 'number' ? e.weight : 1] : []), - ...(typed ? [apiSafe(e.type || 'link')] : []), - ...(directed ? [e.directed ? 'directed' : 'undirected'] : []), - ].join('\t') - }) - return [head.join('\t'), ...rows].join('\n') + '\n' -} - -// groups as { name: [members] } or [{ name, members, color, description }] -function apiGroupsText(groups) { - const list = Array.isArray(groups) - ? groups - : Object.entries(groups || {}).map(([name, members]) => ({ name, members })) - const meta = {} - const rows = list.map((g, i) => { - if (!g || !Array.isArray(g.members)) throw new Error(`Group ${i + 1} needs a "members" list.`) - const name = apiSafe(g.name || `Group ${i + 1}`) - const m = {} - if (g.color) m.color = String(g.color) - if (g.description) m.description = String(g.description) - if (Object.keys(m).length) meta[name] = m - return `${name}\t${g.members.map(apiNode).join(',')}` - }) - return { text: rows.join('\n') + '\n', meta } -} - -// expression as { node: '#color' } or { node: number } or { node: { col: number } } -function apiExpressionText(expr) { - const entries = Object.entries(expr || {}) - if (!entries.length) return null - const first = entries[0][1] - if (first && typeof first === 'object') { - const cols = [...new Set(entries.flatMap(([, v]) => Object.keys(v || {})))] - return ( - [ - 'Node\t' + cols.join('\t'), - ...entries.map(([n, v]) => - [apiNode(n), ...cols.map((c) => (v && v[c] != null ? v[c] : 'NA'))].join('\t') - ), - ].join('\n') + '\n' - ) - } - if (typeof first === 'number') - return ( - ['Node\tvalue', ...entries.map(([n, v]) => `${apiNode(n)}\t${v == null ? 'NA' : v}`)].join( - '\n' - ) + '\n' - ) - return entries.map(([n, v]) => `${apiNode(n)}\t${v}`).join('\n') + '\n' -} - -export async function normaApiLoad(payload, origin = 'API') { - if (typeof payload === 'string') { - if (payload.length > API_MAX_BYTES) throw new Error('The payload is larger than 50 MB.') - try { - payload = JSON.parse(payload) - } catch (e) { - throw new Error('The payload is not valid JSON.') - } - } - if (!payload || typeof payload !== 'object' || Array.isArray(payload)) - throw new Error('The payload must be a JSON object.') - // a whole session - if (isSessionObject(payload) || isSessionObject(payload.session)) { - const r = loadSession(isSessionObject(payload) ? payload : payload.session) - switchTab('network') - return { kind: 'session', views: r.views, files: r.files } - } - const name = apiSafe(payload.name) || 'API network' - const settings = - payload.settings && typeof payload.settings === 'object' ? payload.settings : null - const files = payload.files || {} - const netTexts = [...apiTextOf(files.network)] - if (payload.edges) netTexts.push({ text: apiEdgesText(payload.edges), name }) - let summary - if (netTexts.length) { - const directed = payload.directed === true - const nets = netTexts.map((t, i) => - addNormaEntry( - 'network', - t.name || (netTexts.length > 1 ? `${name} ${i + 1}` : name), - t.text, - '', - null, - { directed } - ) - ) - // node attributes - if (Array.isArray(payload.nodes)) { - const attrs = {} - payload.nodes.forEach((n) => { - if (n && n.id != null) { - const { id, ...rest } = n - attrs[apiNode(id)] = rest - } - }) - nets.forEach((e) => { - e.nodeAttrs = attrs - }) - } - const anns = [] - apiTextOf(files.annotation).forEach((t, i) => - anns.push( - addNormaEntry('annotation', t.name || `${name}: grouping ${i + 1}`, t.text, '', null, {}) - ) - ) - if (payload.groups) { - const g = apiGroupsText(payload.groups) - const e = addNormaEntry('annotation', `${name}: groups`, g.text, '', null, {}) - e.groupMeta = g.meta - anns.push(e) - } - ;(Array.isArray(payload.annotations) ? payload.annotations : []).forEach((a, i) => { - const g = apiGroupsText(a.groups || {}) - const e = addNormaEntry( - 'annotation', - `${name}: ${apiSafe(a.name) || `grouping ${i + 1}`}`, - g.text, - '', - null, - {} - ) - e.groupMeta = g.meta - anns.push(e) - }) - let col = null - const exprText = - apiTextOf(files.expression)[0] || - (payload.expression ? { text: apiExpressionText(payload.expression) } : null) - if (exprText && exprText.text) - col = addNormaEntry( - 'colors', - `${name}: ${payload.expression && typeof Object.values(payload.expression)[0] !== 'string' ? 'values' : 'colors'}`, - exprText.text, - '', - null, - {} - ) - openInNewView(name, () => { - libSelection.networks = new Set(nets.map((e) => e.id)) - libSelection.annotation = anns[0] ? anns[0].id : '' - libSelection.colors = col ? col.id : '' - renderLibraryLists() - refreshLibraryView() - }) - summary = { - kind: 'files', - view: name, - networks: nets.length, - groupings: anns.length, - expression: !!col, - notes: [...nets, ...anns, ...(col ? [col] : [])].flatMap((e) => e.parsed.notes || []), - } - } else if (payload.network || Array.isArray(payload.nodes)) { - const data = payload.network || payload - if (!Array.isArray(data.nodes) || !Array.isArray(data.edges)) - throw new Error('A NORMA view needs "nodes" and "edges" lists (see the JSON format in Help).') - openInNewView(name, () => loadData(data)) - summary = { kind: 'view', view: name } - } else { - throw new Error( - 'Nothing to show: give "edges", "files.network", "network" (a NORMA view) or a session.' - ) - } - if (settings) { - applyConfig(settings) - if (settings.theme) applyTheme(settings.theme) - if (settings.layout) { - setLayoutMode('connections') - document.getElementById('layoutSelect').value = settings.layout - runLayout(settings.layout) - } - } - switchTab(payload.tab === '3d' ? 'network3d' : 'network') - summary.nodes = cy.nodes().length - summary.edges = cy.edges().length - summary.groups = getUsedGroups().filter((g) => g !== UNGROUPED).length - setStatus('apiStatus', [ - { - level: 'ok', - text: `${origin}: opened "${name}" with ${plural(summary.nodes, 'node')}, ${plural(summary.edges, 'edge')} and ${plural(summary.groups, 'group')}.`, - }, - ]) - toast(`Opened "${name}" from ${origin}.`) - return summary -} - -export function b64urlEncode(text) { - const bytes = new TextEncoder().encode(text) - let bin = '' - bytes.forEach((b) => { - bin += String.fromCharCode(b) - }) - return btoa(bin).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '') -} - -function b64urlDecode(s) { - const bin = atob(s.replace(/-/g, '+').replace(/_/g, '/') + '==='.slice((s.length + 3) % 4)) - return new TextDecoder().decode(Uint8Array.from(bin, (c) => c.charCodeAt(0))) -} - -async function apiFetchText(url) { - const r = await fetch(url) - if (!r.ok) throw new Error(`${url} answered ${r.status}.`) - return r.text() -} - -// what the address asks for -export async function apiFromLocation() { - const q = new URLSearchParams(location.search) - const hash = new URLSearchParams(location.hash.replace(/^#/, '')) - try { - if (q.get('example')) { - const sel = document.getElementById('sampleSelect') - const key = q.get('example') - if (![...sel.options].some((o) => o.value === key)) - throw new Error(`there is no example called "${key}".`) - sel.value = key - document.getElementById('btnSample').click() - switchTab(q.get('tab') === '3d' ? 'network3d' : 'network') - return { kind: 'example', example: key } - } - if (q.get('session')) { - const token = q.get('session') - const r = await fetch(`api/session/${encodeURIComponent(token)}`) - if (!r.ok) - throw new Error( - r.status === 404 - ? 'This link has expired or does not exist on this server.' - : `The server answered ${r.status}.` - ) - return await normaApiLoad(await r.text(), 'a shared link') - } - if (hash.get('json')) { - let text - try { - text = b64urlDecode(hash.get('json')) - } catch (e) { - throw new Error( - 'the data part of the link (after #json=) is damaged; it may have been cut when the link was copied.' - ) - } - return await normaApiLoad(text, 'the link') - } - if (q.get('data')) return await normaApiLoad(await apiFetchText(q.get('data')), q.get('data')) - if (q.get('network')) { - const files = { network: await apiFetchText(q.get('network')) } - if (q.get('annotation')) files.annotation = await apiFetchText(q.get('annotation')) - if (q.get('expression')) files.expression = await apiFetchText(q.get('expression')) - const settings = {} - if (q.get('layout')) settings.layout = q.get('layout') - if (q.get('theme')) settings.theme = q.get('theme') - return await normaApiLoad( - { name: q.get('name') || 'Linked network', files, settings, tab: q.get('tab') || '' }, - 'the link' - ) - } - } catch (err) { - switchTab('api') - setStatus('apiStatus', [ - { level: 'error', text: `The data in this link could not be opened: ${err.message}` }, - ]) - } - return null -} - -export function apiAnnounceReady() { - const msg = { type: 'norma:ready', version: NORMA_API_VERSION } - try { - if (window.opener) window.opener.postMessage(msg, '*') - } catch (e) {} - try { - if (window.parent && window.parent !== window) window.parent.postMessage(msg, '*') - } catch (e) {} -} - -// page wiring, run by main.ts in the original order -export function init() { - /* ---------- wiring ---------- */ - ;(function setupDbImporters() { - const rs = document.getElementById('reactomeSpecies') - REACTOME_SPECIES.forEach((s) => rs.add(new Option(s, s))) - const bind = (id, fn) => document.getElementById(id).addEventListener('click', fn) - bind('btnReactomeSearch', reactomeSearch) - bind('btnReactomeFetch', reactomeFetch) - bind('btnOmnipathFetch', omnipathFetch) - bind('btnNdexSearch', ndexSearch) - bind('btnNdexFetch', ndexFetch) - bind('btnIntactFetch', intactFetch) - bind('btnGoModels', goLoadModels) - bind('btnGoModelFetch', goFetchModel) - bind('btnGoAnnotate', goAnnotateView) - document.getElementById('goModelFilter').addEventListener('input', filterGoModels) - const sc = document.getElementById('intactScore') - sc.addEventListener('input', () => { - document.getElementById('intactScoreValue').textContent = parseFloat(sc.value).toFixed(2) - }) - ;['reactome', 'omnipath', 'ndex', 'intact', 'go'].forEach((k) => - bind(`${k}Cancel`, () => dbCancel(k)) - ) - document.getElementById('reactomeQuery').addEventListener('keydown', (e) => { - if (e.key === 'Enter') { - e.preventDefault() - reactomeSearch() - } - }) - document.getElementById('ndexQuery').addEventListener('keydown', (e) => { - if (e.key === 'Enter') { - e.preventDefault() - ndexSearch() - } - }) - // collapsible importer sections - // every sidebar section opens and closes from its title - document.querySelectorAll('.section.collapsible > h3').forEach((h) => { - const toggle = () => { - h.parentElement.classList.toggle('collapsed') - h.setAttribute('aria-expanded', String(!h.parentElement.classList.contains('collapsed'))) - } - h.addEventListener('click', (e) => { - if (!e.target.closest('button, a, input, select')) toggle() - }) - h.addEventListener('keydown', (e) => { - if (e.target !== h || (e.key !== 'Enter' && e.key !== ' ')) return - e.preventDefault() - toggle() - }) - }) - document - .querySelectorAll('.section.collapsible.collapsed > h3') - .forEach((h) => h.setAttribute('aria-expanded', 'false')) - })() - - // postMessage - window.addEventListener('message', async (e) => { - const m = e.data - if (!m || typeof m !== 'object' || typeof m.type !== 'string' || !m.type.startsWith('norma:')) - return - const reply = (obj) => { - try { - ;(e.source || window.parent).postMessage( - { ...obj, requestId: m.requestId }, - e.origin === 'null' ? '*' : e.origin - ) - } catch (err) {} - } - if (m.type === 'norma:ping') { - reply({ type: 'norma:ready', version: NORMA_API_VERSION }) - return - } - if (m.type !== 'norma:load') return - try { - const summary = await normaApiLoad( - m.payload, - e.origin && e.origin !== 'null' ? e.origin : 'another page' - ) - reply({ type: 'norma:loaded', ok: true, summary }) - } catch (err) { - reply({ type: 'norma:loaded', ok: false, error: err.message }) - } - }) -} diff --git a/frontend/src/arena3d.test.ts b/frontend/src/arena3d.test.ts deleted file mode 100644 index 69e78fb..0000000 --- a/frontend/src/arena3d.test.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { expect, test } from 'vitest' -import { - benjaminiHochberg, - convertArena3dNetwork, - hypergeomUpper, - isArena3dNetworkText, -} from './arena3d' - -const ARENA = [ - 'SourceNode\tSourceLayer\tTargetNode\tTargetLayer\tWeight\tChannel', - 'A\tL1\tB\tL1\t2\tppi', - 'B\tL1\tC\tL2\t\tgenetic', - 'C\tL2\tD\tL2\t1\tppi', - '', -].join('\n') - -test('recognises Arena3D network files', () => { - expect(isArena3dNetworkText(ARENA)).toBe(true) - expect(isArena3dNetworkText('Source\tTarget\nA\tB\n')).toBe(false) - expect(isArena3dNetworkText('')).toBe(false) -}) - -test('converts layers to groups and keeps weights and channels', () => { - const r = convertArena3dNetwork(ARENA) - expect(r.layers).toBe(2) - expect(r.network.split('\n').filter(Boolean)).toEqual([ - 'Source\tTarget\tWeight\tType', - 'A\tB\t2\tppi', - 'B\tC\t1\tgenetic', - 'C\tD\t1\tppi', - ]) - expect(r.annotation).toBe('L1\tA,B\nL2\tC,D\n') -}) - -test('hypergeometric upper tail', () => { - // urn: 10 balls, 4 white, draw 3: P(X >= 3) = C(4,3)/C(10,3) = 4/120 - expect(hypergeomUpper(3, 10, 4, 3)).toBeCloseTo(4 / 120, 10) - expect(hypergeomUpper(0, 10, 4, 3)).toBeCloseTo(1, 10) - expect(hypergeomUpper(5, 10, 4, 3)).toBe(0) -}) - -test('Benjamini-Hochberg keeps order and is monotone', () => { - // ranks: 0.01, 0.03, 0.04, 0.5 -> q = min over higher ranks of p * n / rank - const q = benjaminiHochberg([0.01, 0.04, 0.03, 0.5]) - expect(q.map((x) => +x.toFixed(4))).toEqual([0.04, 0.0533, 0.0533, 0.5]) - expect(benjaminiHochberg([])).toEqual([]) -}) diff --git a/frontend/src/arena3d.ts b/frontend/src/arena3d.ts deleted file mode 100644 index 8e7d5b3..0000000 --- a/frontend/src/arena3d.ts +++ /dev/null @@ -1,285 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { S } from './state' -import { - UNGROUPED, - effectiveGroupsFor, - escapeHtml, - getUsedGroups, - groupLabel, - refreshNodeVisual, - sanitizeColor, -} from './network_state' -import { activeView } from './profiler' -import { applyGroupVisibility, buildGroupLegend } from './hulls' -import { cy } from './cy' -import { downloadText, fileStem, normaCols, normaLines, plural } from './layouts/controls' -import { groupAnalysisState } from './enrichment' -import { partitionStats } from './welcome' -import { shownEdges, shownNodes } from './metrics' -import { simpleGraph } from './wiring' - -/* ---------- reading Arena3D network files ---------- */ -// SourceNode, SourceLayer, TargetNode, TargetLayer, Weight, Channel: -// becomes a NORMA network (one channel per Channel value when there are -// several) and an annotation with one group per layer. -export function isArena3dNetworkText(text) { - const first = normaLines(text).find((l) => l.trim()) - if (!first) return false - const h = normaCols(first).map((c) => c.trim().toLowerCase()) - return ( - h[0] === 'sourcenode' && - h[1] === 'sourcelayer' && - h[2] === 'targetnode' && - h[3] === 'targetlayer' - ) -} - -export function convertArena3dNetwork(text) { - const lines = normaLines(text).filter((l) => l.trim()) - const head = normaCols(lines[0]).map((c) => c.trim().toLowerCase()) - const wCol = head.indexOf('weight'), - cCol = head.indexOf('channel') - const members = new Map() - const channels = new Set() - const rows = [] - lines.slice(1).forEach((line) => { - const c = normaCols(line) - if (c.length < 4) return - const [sn, sl, tn, tl] = c.map((x) => x.trim()) - ;[ - [sn, sl], - [tn, tl], - ].forEach(([n, l]) => { - if (!members.has(l)) members.set(l, new Set()) - members.get(l).add(n) - }) - const ch = cCol >= 0 ? (c[cCol] || '').trim() : '' - if (ch) channels.add(ch) - rows.push([sn, tn, wCol >= 0 ? (c[wCol] || '').trim() : '', ch]) - }) - const typed = channels.size > 1 - const weighted = wCol >= 0 - const header = ['Source', 'Target', ...(weighted ? ['Weight'] : []), ...(typed ? ['Type'] : [])] - const network = - [ - header.join('\t'), - ...rows.map((r) => - [r[0], r[1], ...(weighted ? [r[2] || '1'] : []), ...(typed ? [r[3] || '1'] : [])].join('\t') - ), - ].join('\n') + '\n' - const annotation = [...members].map(([l, set]) => `${l}\t${[...set].join(',')}`).join('\n') + '\n' - return { network, annotation, layers: members.size } -} - -/* ============================================================ - GROUP ANALYSIS (Network Profiler page, current view) - - per-group statistics and the modularity of the grouping - - the group network: one node per group, edges weighted by the - connections between groups, opened as a new view - - enrichment: hypergeometric test of annotation terms in selected - nodes or in each group of another annotation, with - Benjamini-Hochberg FDR - All of it uses the shown part of the view (ticked groups and channels). - ============================================================ */ - -// log n! with a cached table -const LOG_FACT = [0] - -function logFact(n) { - for (let i = LOG_FACT.length; i <= n; i++) LOG_FACT[i] = LOG_FACT[i - 1] + Math.log(i) - return LOG_FACT[n] -} - -function logChoose(n, k) { - return k < 0 || k > n ? -Infinity : logFact(n) - logFact(k) - logFact(n - k) -} - -// P(X >= k) for X ~ Hypergeometric(N population, K successes, n draws) -export function hypergeomUpper(k, N, K, n) { - const hi = Math.min(K, n) - if (k > hi) return 0 - const lo = Math.max(k, 0) - const denom = logChoose(N, n) - const logs = [] - for (let x = lo; x <= hi; x++) logs.push(logChoose(K, x) + logChoose(N - K, n - x) - denom) - const m = Math.max(...logs) - const p = Math.exp(m) * logs.reduce((s, l) => s + Math.exp(l - m), 0) - return Math.min(1, p) -} - -export function benjaminiHochberg(ps) { - const idx = ps.map((p, i) => [p, i]).sort((a, b) => a[0] - b[0]) - const q = new Array(ps.length) - let min = 1 - for (let r = idx.length - 1; r >= 0; r--) { - const [p, i] = idx[r] - min = Math.min(min, (p * idx.length) / (r + 1)) - q[i] = min - } - return q -} - -// the shown part of the view as a simple undirected graph -function shownSimpleGraph() { - const nodes = shownNodes() - const ids = nodes.map((n) => n.id()) - const idSet = new Set(ids) - const pairs = [] - shownEdges(true).forEach((e) => { - const s = e.data('source'), - t = e.data('target') - if (s !== t && idSet.has(s) && idSet.has(t)) pairs.push([s, t]) - }) - return { nodes, ids, graph: simpleGraph(ids, pairs) } -} - -function groupStatistics() { - const { nodes, ids, graph } = shownSimpleGraph() - const index = new Map(ids.map((id, i) => [id, i])) - const groupsOf = ids.map((id) => effectiveGroupsFor(cy.$id(id)).filter((g) => g !== UNGROUPED)) - const order = getUsedGroups().filter((g) => S.activeGroups.has(g) && g !== UNGROUPED) - const members = new Map(order.map((g) => [g, []])) - groupsOf.forEach((gs, i) => - gs.forEach((g) => { - if (members.has(g)) members.get(g).push(i) - }) - ) - const m = graph.m, - twoM = 2 * m - const deg = graph.adj.map((a) => a.length) - const rows = [] - members.forEach((list, g) => { - if (!list.length) return - const inG = new Set(list) - let internal2 = 0, - boundary = 0, - vol = 0 - list.forEach((i) => { - vol += deg[i] - graph.adj[i].forEach((j) => { - if (inG.has(j)) internal2++ - else boundary++ - }) - }) - const internal = internal2 / 2 - const k = list.length - const pairsIn = (k * (k - 1)) / 2 - const volRest = twoM - vol - rows.push({ - group: g, - label: groupLabel(g), - size: k, - internal, - boundary, - density: pairsIn ? internal / pairsIn : NaN, - avgInternalDegree: k ? internal2 / k : NaN, - conductance: Math.min(vol, volRest) > 0 ? boundary / Math.min(vol, volRest) : NaN, - share: twoM ? internal / m - Math.pow(vol / twoM, 2) : NaN, // modularity term - }) - }) - // modularity of the grouping: nodes in several groups count for their first group, nodes in none are singletons - const raw = new Int32Array(ids.length) - const gIndex = new Map(order.map((g, i) => [g, i])) - groupsOf.forEach((gs, i) => { - raw[i] = gs.length ? gIndex.get(gs[0]) : order.length + i - }) - const part = partitionStats(graph, raw) - const overlapping = groupsOf.filter((gs) => gs.length > 1).length - const ungrouped = groupsOf.filter((gs) => !gs.length).length - // how much denser groups are inside than the network as a whole - const netDensity = ids.length > 1 ? m / ((ids.length * (ids.length - 1)) / 2) : NaN - return { - rows, - modularity: part.modularity, - overlapping, - ungrouped, - nodes: ids.length, - edges: m, - netDensity, - } -} - -export function renderGroupStats() { - const root = document.getElementById('gaStats') - if (!cy.nodes().length) { - root.innerHTML = '

    Show a network first.

    ' - return - } - const st = groupStatistics() - if (!st.rows.length) { - root.innerHTML = '

    The current view has no ticked groups.

    ' - return - } - const f = (v, d = 3) => (Number.isFinite(v) ? v.toFixed(d) : '—') - const notes = [] - if (st.overlapping) - notes.push( - `${plural(st.overlapping, 'node')} in several groups ${st.overlapping === 1 ? 'counts' : 'count'} for ${st.overlapping === 1 ? 'its' : 'their'} first group` - ) - if (st.ungrouped) - notes.push( - `${plural(st.ungrouped, 'node')} in no group ${st.ungrouped === 1 ? 'counts as a group of its own' : 'count as groups of their own'}` - ) - root.innerHTML = ` -

    Modularity of the grouping: ${f(st.modularity)} on ${plural(st.nodes, 'shown node')} and ${plural(st.edges, 'edge')} (network density ${f(st.netDensity, 4)})${notes.length ? `; ${notes.join(', ')}` : ''}. Values above about 0.3 mean the groups follow the network's structure.

    -
    - - ${st.rows - .map( - (r) => ` - - - - ` - ) - .join('')} -
    GroupNodesEdges insideEdges leavingDensity insideMean degree insideConductance ↓Modularity share
    ${escapeHtml(r.label)}${r.size}${r.internal}${r.boundary}${f(r.density)}${f(r.avgInternalDegree, 2)}${f(r.conductance)}${f(r.share, 4)}
    ` - document.getElementById('btnGaStatsTsv').disabled = false - groupAnalysisState.stats = st -} - -export function groupStatsTsv() { - const st = groupAnalysisState.stats - if (!st) return - const f = (v) => (Number.isFinite(v) ? String(Math.round(v * 1e6) / 1e6) : '') - const lines = [ - `# modularity of the grouping\t${f(st.modularity)}`, - [ - 'Group', - 'Nodes', - 'Edges inside', - 'Edges leaving', - 'Density inside', - 'Mean degree inside', - 'Conductance', - 'Modularity share', - ].join('\t'), - ...st.rows.map((r) => - [ - r.label, - r.size, - r.internal, - r.boundary, - f(r.density), - f(r.avgInternalDegree), - f(r.conductance), - f(r.share), - ].join('\t') - ), - ] - const v = activeView() - downloadText(`group-statistics${v ? '-' + fileStem(v.name) : ''}.tsv`, lines.join('\n') + '\n') -} - -// Group colors given with generated data win over the palette that a -// data config re-applies. -export function applyGroupColorOverrides(colors) { - Object.entries(colors || {}).forEach(([g, c]) => { - const sc = sanitizeColor(c) - if (sc) S.nodeColorMap[g] = sc - }) - cy.batch(() => cy.nodes().forEach((n) => refreshNodeVisual(n))) - buildGroupLegend() - applyGroupVisibility() -} diff --git a/frontend/src/benchmark.ts b/frontend/src/benchmark.ts deleted file mode 100644 index 88cc5dc..0000000 --- a/frontend/src/benchmark.ts +++ /dev/null @@ -1,274 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { S } from './state' -import { activeView } from './profiler' -import { - applyLocalLayoutsAfter, - blockGroupLayout, - collectLayoutGraph, - strategyGravity, - strategySuperNodes, - strategyVirtualNodes, -} from './layouts/input' -import { - computeSubLayout, - computeSubLayoutAsync, - makeLayoutProgress, - normalizeSpacing, - targetNodeSpacing, -} from './metrics' -import { - downloadText, - fileStem, - nextPaint, - plural, - setLayoutMode, - setStatus, -} from './layouts/controls' -import { escapeHtml } from './network_state' -import { groupSeparation } from './clustering/mapping' -import { runActiveLayout } from './layouts/run' -import { switchTab } from './wiring' - -/* ---------- layout benchmark (Network Profiler) ---------- */ -const BENCH_LAYOUTS = [ - ['conn', 'cose', 'Force-directed (cose)'], - ['conn', 'fr', 'Force-directed, weighted'], - ['conn', 'kk', 'Kamada–Kawai'], - ['conn', 'stress', 'Stress majorization'], - ['conn', 'circle', 'Circle'], - ['conn', 'concentric', 'Concentric'], - ['conn', 'breadthfirst', 'Hierarchical'], - ['conn', 'grid', 'Grid'], - ['conn', 'random', 'Random (baseline)'], - ['groups', 'fr', 'Groups: force-directed, weighted'], - ['groups', 'cose', 'Groups: force-directed (cose)'], - ['groups', 'circle', 'Groups: circle'], - ['groups', 'grid', 'Groups: grid'], - ['groups', 'breadthfirst', 'Groups: hierarchical'], - ['groups', 'concentric', 'Groups: concentric'], - ['groups', 'virtual', 'NORMA-2.0 strategy 1: virtual nodes'], - ['groups', 'gravity', 'NORMA-2.0 strategy 2: group gravity'], - ['groups', 'supernodes', 'NORMA-2.0 strategy 3: super nodes'], -] - -const benchState = { rows: [], running: false, cancel: false } - -async function benchmarkPositions(kind, name, graph) { - const spacing = targetNodeSpacing() - if (kind === 'conn') { - const pos = ['fr', 'kk', 'stress'].includes(name) - ? await computeSubLayoutAsync(graph.nodeIds, graph.edges, name) - : computeSubLayout(graph.nodeIds, graph.edges, name) - return pos ? normalizeSpacing(pos, spacing) : null - } - const algorithm = document.getElementById('strategyAlgorithm').value - const force = parseFloat(document.getElementById('groupForce').value) || 10 - const clusterScale = parseFloat(document.getElementById('groupClusterRadius').value) || 1 - let localName = document.getElementById('localGroupLayout').value - const keepAllowed = name === 'virtual' || name === 'gravity' - if (localName === 'keep' && !keepAllowed) localName = 'circle' - if (name === 'virtual') - return applyLocalLayoutsAfter( - graph, - await strategyVirtualNodes(graph, algorithm), - localName, - force, - clusterScale - ) - if (name === 'gravity') - return applyLocalLayoutsAfter( - graph, - await strategyGravity(graph, algorithm, force), - localName, - force, - clusterScale - ) - if (name === 'supernodes') - return strategySuperNodes(graph, algorithm, localName, force, clusterScale) - return blockGroupLayout(graph, name, localName, force, clusterScale) -} - -export async function runLayoutBenchmark() { - if (benchState.running) { - benchState.cancel = true - return - } - const graph = collectLayoutGraph() - const btn = document.getElementById('btnBench') - if (graph.nodeIds.length < 3) { - setStatus('benchStatus', [ - { level: 'error', text: 'Show a network with at least three nodes first.' }, - ]) - return - } - if (graph.groupMembers.size < 2) { - setStatus('benchStatus', [ - { - level: 'error', - text: 'The current view needs at least two ticked groups to measure separation.', - }, - ]) - return - } - const repeats = parseInt(document.getElementById('benchRepeats').value, 10) || 1 - benchState.running = true - benchState.cancel = false - btn.textContent = 'Stop' - const rows = [] - const started = performance.now() - try { - for (const [li, [kind, name, label]] of BENCH_LAYOUTS.entries()) { - if (benchState.cancel) break - const text = `Running ${label} (${li + 1} of ${BENCH_LAYOUTS.length})…` - const show = (f) => setStatus('benchStatus', [{ level: 'busy', text, progress: f }]) - show(li / BENCH_LAYOUTS.length) - await nextPaint() - const runs = [] - for (let k = 0; k < repeats; k++) { - const t0 = performance.now() - let pos - S.layoutProgress = makeLayoutProgress((f) => - show((li + (k + f) / repeats) / BENCH_LAYOUTS.length) - ) - try { - pos = await benchmarkPositions(kind, name, graph) - } catch (err) { - pos = null - } finally { - S.layoutProgress = null - } - show((li + (k + 1) / repeats) / BENCH_LAYOUTS.length) - await nextPaint() - const ms = performance.now() - t0 - if (!pos) continue - runs.push({ ms, ...groupSeparation(pos, graph.groupsOf) }) - } - const agg = (key) => { - const vals = runs.map((r) => r[key]).filter(Number.isFinite) - if (!vals.length) return { mean: NaN, sd: NaN } - const mean = vals.reduce((s, v) => s + v, 0) / vals.length - const sd = - vals.length > 1 - ? Math.sqrt(vals.reduce((s, v) => s + (v - mean) ** 2, 0) / (vals.length - 1)) - : NaN - return { mean, sd } - } - rows.push({ - kind, - name, - label, - runs: runs.length, - ms: agg('ms'), - silhouette: agg('silhouette'), - intruders: agg('intruders'), - overlap: agg('overlap'), - }) - benchState.rows = rows - renderBenchmark(graph) - } - const secs = ((performance.now() - started) / 1000).toFixed(1) - setStatus('benchStatus', [ - { - level: benchState.cancel ? 'warn' : 'ok', - text: `${benchState.cancel ? 'Stopped after' : 'Benchmarked'} ${plural(rows.length, 'layout')} on ${plural(graph.nodeIds.length, 'node')} and ${plural(graph.groupMembers.size, 'group')} in ${secs} s. The view itself was not changed.`, - }, - ]) - document.getElementById('btnBenchTsv').disabled = !rows.length - } finally { - benchState.running = false - btn.textContent = 'Benchmark layouts' - } -} - -function renderBenchmark(graph) { - const root = document.getElementById('benchResults') - const rows = benchState.rows - if (!rows.length) { - root.innerHTML = '' - return - } - const best = (key) => { - const vals = rows.map((r) => r[key].mean).filter(Number.isFinite) - if (!vals.length) return null - return key === 'silhouette' ? Math.max(...vals) : Math.min(...vals) - } - const bS = best('silhouette'), - bI = best('intruders'), - bO = best('overlap') - const cell = (v, fmt, isBest) => - `${Number.isFinite(v.mean) ? fmt(v.mean) + (Number.isFinite(v.sd) ? ` ± ${fmt(v.sd)}` : '') : '—'}` - const pct = (v) => `${(v * 100).toFixed(1)}%` - const num = (v) => v.toFixed(3) - const ms = (v) => (v < 1000 ? `${Math.round(v)} ms` : `${(v / 1000).toFixed(1)} s`) - root.innerHTML = `
    - - ${rows - .map( - (r, i) => ` - - ${cell(r.ms, ms, false)} - ${cell(r.silhouette, num, r.silhouette.mean === bS)} - ${cell(r.intruders, pct, r.intruders.mean === bI)} - ${cell(r.overlap, pct, r.overlap.mean === bO)} - - ` - ) - .join('')}
    LayoutTimeSilhouette ↑Inside other outlines ↓Outline overlap ↓
    ${escapeHtml(r.label)}
    ` - root - .querySelectorAll('.bench-use') - .forEach((b) => b.addEventListener('click', () => useBenchLayout(rows[+b.dataset.row]))) -} - -function useBenchLayout(row) { - if (row.kind === 'conn') { - setLayoutMode('connections') - document.getElementById('layoutSelect').value = row.name - } else { - setLayoutMode('groups') - document.getElementById('groupArrangement').value = row.name - document - .getElementById('groupArrangement') - .dispatchEvent(new Event('change', { bubbles: true })) - } - switchTab('network') - runActiveLayout() -} - -export function benchmarkTsv() { - const rows = benchState.rows - if (!rows.length) return - const f = (v, d = 4) => (Number.isFinite(v) ? v.toFixed(d) : '') - const lines = [ - [ - 'Layout', - 'Runs', - 'Time ms (mean)', - 'Time ms (sd)', - 'Silhouette (mean)', - 'Silhouette (sd)', - 'Inside other outlines (mean)', - 'Inside other outlines (sd)', - 'Outline overlap (mean)', - 'Outline overlap (sd)', - ].join('\t'), - ] - rows.forEach((r) => - lines.push( - [ - r.label, - r.runs, - f(r.ms.mean, 1), - f(r.ms.sd, 1), - f(r.silhouette.mean), - f(r.silhouette.sd), - f(r.intruders.mean), - f(r.intruders.sd), - f(r.overlap.mean), - f(r.overlap.sd), - ].join('\t') - ) - ) - const v = typeof activeView === 'function' && activeView() - downloadText(`layout-benchmark${v ? '-' + fileStem(v.name) : ''}.tsv`, lines.join('\n') + '\n') -} diff --git a/frontend/src/clustering/clustering.test.ts b/frontend/src/clustering/clustering.test.ts deleted file mode 100644 index 23f6252..0000000 --- a/frontend/src/clustering/clustering.test.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { describe, expect, test } from 'vitest' -import { runCommunityAlgorithm } from './mcl' - -// Two 4-cliques joined by a single edge: every algorithm must find the two cliques. -function twoCliques() { - const edges: [number, number][] = [] - for (const base of [0, 4]) - for (let i = 0; i < 4; i++) for (let j = i + 1; j < 4; j++) edges.push([base + i, base + j]) - edges.push([3, 4]) - const adj: number[][] = Array.from({ length: 8 }, () => []) - for (const [a, b] of edges) { - adj[a].push(b) - adj[b].push(a) - } - return { n: 8, m: edges.length, adj } -} - -describe.each(['louvain', 'leiden', 'lpa', 'walktrap', 'mcl'])('%s', (algo) => { - test('separates two cliques', () => { - const r = runCommunityAlgorithm(twoCliques(), algo) - expect(r.count).toBe(2) - const m = Array.from(r.membership as Int32Array) - expect(new Set(m.slice(0, 4)).size).toBe(1) - expect(new Set(m.slice(4)).size).toBe(1) - expect(m[0]).not.toBe(m[7]) - expect(r.sizes).toEqual([4, 4]) - // 13 edges; each clique: 12/26 - (13/26)^2 - expect(r.modularity).toBeCloseTo(2 * (12 / 26 - (13 / 26) ** 2), 6) - }) - - test('is deterministic', () => { - const a = runCommunityAlgorithm(twoCliques(), algo) - const b = runCommunityAlgorithm(twoCliques(), algo) - expect(Array.from(a.membership as Int32Array)).toEqual(Array.from(b.membership as Int32Array)) - }) -}) - -test('a graph without edges is one community per node', () => { - const r = runCommunityAlgorithm({ n: 3, m: 0, adj: [[], [], []] }, 'leiden') - expect(r.count).toBe(3) - expect(Number.isNaN(r.modularity)).toBe(true) -}) - -test('unknown algorithm throws', () => { - expect(() => runCommunityAlgorithm(twoCliques(), 'nope')).toThrow(/Unknown community algorithm/) -}) diff --git a/frontend/src/clustering/label_propagation.ts b/frontend/src/clustering/label_propagation.ts deleted file mode 100644 index a4541c5..0000000 --- a/frontend/src/clustering/label_propagation.ts +++ /dev/null @@ -1,39 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { mulberry32 } from '../sample_data' -import { partitionStats, splitDisconnected } from '../welcome' - -/* ---------- label propagation ---------- */ -export function labelPropagation(g, opts = {}) { - const rand = mulberry32(opts.seed ?? 7) - const n = g.n - const label = Int32Array.from({ length: n }, (_, i) => i) - const order = Array.from({ length: n }, (_, i) => i) - for (let it = 0; it < 200; it++) { - for (let i = n - 1; i > 0; i--) { - const j = Math.floor(rand() * (i + 1)) - ;[order[i], order[j]] = [order[j], order[i]] - } - let changed = false - for (const v of order) { - const a = g.adj[v] - if (!a.length) continue - const counts = new Map() - let best = 0 - for (let k = 0; k < a.length; k++) { - const c = (counts.get(label[a[k]]) || 0) + 1 - counts.set(label[a[k]], c) - if (c > best) best = c - } - const top = [] - counts.forEach((c, l) => { - if (c === best) top.push(l) - }) - if (top.includes(label[v])) continue // already a most frequent label - label[v] = top[Math.floor(rand() * top.length)] - changed = true - } - if (!changed) break - } - return partitionStats(g, splitDisconnected(g, label)) -} diff --git a/frontend/src/clustering/leiden.ts b/frontend/src/clustering/leiden.ts deleted file mode 100644 index 4e01099..0000000 --- a/frontend/src/clustering/leiden.ts +++ /dev/null @@ -1,193 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { mulberry32 } from '../sample_data' -import { partitionStats } from '../welcome' - -/* ---------- Leiden ---------- */ -export function leidenCommunities(g, opts = {}) { - const gamma = opts.resolution ?? 1 - const theta = opts.theta ?? 0.01 - const rand = mulberry32(opts.seed ?? 42) - const n = g.n - if (!g.m) - return partitionStats( - g, - Int32Array.from({ length: n }, (_, i) => i) - ) - // weighted graph: nbr[i] = Map(j -> w), kw[i] = weighted degree - let nbr = g.adj.map((a) => { - const mp = new Map() - a.forEach((v) => mp.set(v, 1)) - return mp - }) - let N = n - const twoM = 2 * g.m - let nodeOf = Int32Array.from({ length: n }, (_, i) => i) // original node -> aggregate node - let part = Int32Array.from({ length: n }, (_, i) => i) // aggregate node -> community - - const shuffle = (arr) => { - for (let i = arr.length - 1; i > 0; i--) { - const j = Math.floor(rand() * (i + 1)) - ;[arr[i], arr[j]] = [arr[j], arr[i]] - } - return arr - } - - for (let level = 0; level < 50; level++) { - const kw = new Float64Array(N) - nbr.forEach((mp, i) => { - let s = 0 - mp.forEach((w, j) => { - s += j === i ? 2 * w : w - }) - kw[i] = s - }) - // --- move nodes fast - const tot = new Float64Array(N) - for (let i = 0; i < N; i++) tot[part[i]] += kw[i] - const queue = shuffle(Array.from({ length: N }, (_, i) => i)) - const inQueue = new Uint8Array(N).fill(1) - let head = 0 - let changed = false - while (head < queue.length) { - const v = queue[head++] - inQueue[v] = 0 - const cv = part[v] - const links = new Map() - nbr[v].forEach((w, u) => { - if (u !== v) { - const cu = part[u] - links.set(cu, (links.get(cu) || 0) + w) - } - }) - tot[cv] -= kw[v] - let best = cv - let bestGain = (links.get(cv) || 0) - (gamma * kw[v] * tot[cv]) / twoM - links.forEach((w, c) => { - const gain = w - (gamma * kw[v] * tot[c]) / twoM - if (gain > bestGain + 1e-12) { - bestGain = gain - best = c - } - }) - tot[best] += kw[v] - if (best !== cv) { - part[v] = best - changed = true - nbr[v].forEach((w, u) => { - if (u !== v && part[u] !== best && !inQueue[u]) { - inQueue[u] = 1 - queue.push(u) - } - }) - } - } - // communities of the current level - const commMembers = new Map() - for (let i = 0; i < N; i++) { - if (!commMembers.has(part[i])) commMembers.set(part[i], []) - commMembers.get(part[i]).push(i) - } - if (commMembers.size === N) break // every community is a single node: done - // --- refinement: well-connected sub-communities inside each community - const refined = Int32Array.from({ length: N }, (_, i) => i) - const rTot = Float64Array.from(kw) - const rSingle = new Uint8Array(N).fill(1) - commMembers.forEach((members, c) => { - if (members.length === 1) return - const totC = members.reduce((s, i) => s + kw[i], 0) - const inC = new Set(members) - // links from each node to the rest of its community - const kIn = new Map() - members.forEach((v) => { - let s = 0 - nbr[v].forEach((w, u) => { - if (u !== v && inC.has(u)) s += w - }) - kIn.set(v, s) - }) - // links from each refined community to the rest of C (start: singletons) - const extC = new Map(members.map((v) => [v, kIn.get(v)])) - shuffle([...members]).forEach((v) => { - if (!rSingle[v]) return - const kv = kw[v] - if (kIn.get(v) < (gamma * kv * (totC - kv)) / twoM) return // v not well connected - const links = new Map() - nbr[v].forEach((w, u) => { - if (u !== v && inC.has(u)) { - const r = refined[u] - links.set(r, (links.get(r) || 0) + w) - } - }) - const own = refined[v] - const candidates = [] - let maxGain = 0 - links.forEach((w, r) => { - if (r === own) return - const totR = rTot[r] - // only well-connected refined communities are eligible - if (extC.get(r) < (gamma * totR * (totC - totR)) / twoM) return - const gain = w - (gamma * kv * totR) / twoM - if (gain >= 0) { - candidates.push([r, gain]) - if (gain > maxGain) maxGain = gain - } - }) - if (!candidates.length) return - // choose randomly, favouring larger gains (theta controls randomness) - const weights = candidates.map(([, gain]) => Math.exp((gain - maxGain) / theta)) - let pick = rand() * weights.reduce((s, w) => s + w, 0) - let chosen = candidates[candidates.length - 1][0] - for (let i = 0; i < candidates.length; i++) { - pick -= weights[i] - if (pick <= 0) { - chosen = candidates[i][0] - break - } - } - // move v from its singleton into `chosen` - const linksToChosen = links.get(chosen) || 0 - extC.set(chosen, extC.get(chosen) + kIn.get(v) - 2 * linksToChosen) - extC.delete(own) - rTot[chosen] += kv - rTot[own] -= kv - refined[v] = chosen - rSingle[v] = 0 - rSingle[chosen] = 0 // refined ids are node indices, so this is the community's first node - }) - }) - // --- aggregate on the refined partition; each aggregate node keeps its - // (non-refined) community as its starting community - const rmap = new Map() - for (let i = 0; i < N; i++) if (!rmap.has(refined[i])) rmap.set(refined[i], rmap.size) - const nextN = rmap.size - if (nextN === N && !changed) break - const agg = Array.from({ length: nextN }, () => new Map()) - const nextPart = new Int32Array(nextN) - for (let i = 0; i < N; i++) { - const ri = rmap.get(refined[i]) - nextPart[ri] = part[i] - nbr[i].forEach((w, j) => { - const rj = rmap.get(refined[j]) - // self-loops are stored once with their full weight - if (ri === rj) { - if (j >= i) agg[ri].set(ri, (agg[ri].get(ri) || 0) + (i === j ? w : w)) - } else agg[ri].set(rj, (agg[ri].get(rj) || 0) + w) - }) - } - nodeOf = nodeOf.map((x) => rmap.get(refined[x])) - // community ids of the aggregate start partition - const cmap = new Map() - for (let i = 0; i < nextN; i++) { - if (!cmap.has(nextPart[i])) cmap.set(nextPart[i], cmap.size) - nextPart[i] = cmap.get(nextPart[i]) - } - nbr = agg - part = nextPart - N = nextN - if (nextN === cmap.size) break // aggregation changes nothing more - } - const raw = new Int32Array(n) - for (let i = 0; i < n; i++) raw[i] = part[nodeOf[i]] - return partitionStats(g, raw) -} diff --git a/frontend/src/clustering/mapping.ts b/frontend/src/clustering/mapping.ts deleted file mode 100644 index eda41c6..0000000 --- a/frontend/src/clustering/mapping.ts +++ /dev/null @@ -1,814 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { EDGE_TYPES } from '../palette' -import { S } from '../state' -import { - UNGROUPED, - effectiveGroupsFor, - formatAttrValue, - getUsedGroups, - groupLabel, - nodeFillMode, - refreshNodeVisual, -} from '../network_state' -import { VALUE_SCALES, VALUE_TRANSFORMS } from './mcl' -import { applyNodeSizing, shownNodes } from '../metrics' -import { convexHull, displayGroups, getUsedTypes, legendExtra } from '../hulls' -import { currentTheme } from '../themes' -import { cy } from '../cy' -import { mulberry32 } from '../sample_data' -import { plural } from '../layouts/controls' -import { rgbOf } from '../view3d/state' -import { stopFramePlay, updateFrameControls } from '../enrichment' -import { updateContextInfo } from '../recording' - -/* ---------- mapping ---------- */ -export function viewHasValues() { - return cy.nodes().some((n) => n.data('values')) -} - -export function valueColumns() { - const cols = new Set() - cy.nodes().forEach((n) => { - const v = n.data('values') - if (v) Object.keys(v).forEach((k) => cols.add(k)) - }) - return [...cols] -} - -function valueSettings() { - const scale = - VALUE_SCALES[document.getElementById('valueScale').value] || VALUE_SCALES['div-rdbu'] - return { - column: document.getElementById('valueColumn').value, - transform: - VALUE_TRANSFORMS[document.getElementById('valueTransform').value] || VALUE_TRANSFORMS.none, - scaleKey: document.getElementById('valueScale').value, - scale, - center: parseFloat(document.getElementById('valueCenter').value) || 0, - range: document.getElementById('valueRange').value, - min: parseFloat(document.getElementById('valueMin').value), - max: parseFloat(document.getElementById('valueMax').value), - missing: document.getElementById('valueMissing').value || '#c8c8c8', - } -} - -function nodeValue(node, st) { - const v = node.data('values') - if (!v || v[st.column] === null || v[st.column] === undefined) return null - const t = st.transform.fn(v[st.column]) - return Number.isFinite(t) ? t : null -} - -// Range of the scale: [lo, hi], plus the center for diverging scales. -function valueDomain(st) { - const vals = [] - const cols = document.getElementById('valueSameRange').checked ? valueColumns() : [st.column] - cy.nodes().forEach((n) => { - if (n.hasClass('hidden-group')) return - cols.forEach((c) => { - const x = nodeValue(n, { ...st, column: c }) - if (x !== null) vals.push(x) - }) - }) - if (!vals.length) return { lo: 0, hi: 1, center: st.center, count: 0 } - let lo = Math.min(...vals), - hi = Math.max(...vals) - if ( - st.range === 'custom' && - Number.isFinite(st.min) && - Number.isFinite(st.max) && - st.max > st.min - ) { - lo = st.min - hi = st.max - } else if (st.scale.diverging && st.range === 'symmetric') { - const m = Math.max(Math.abs(lo - st.center), Math.abs(hi - st.center)) || 1 - lo = st.center - m - hi = st.center + m - } - if (hi === lo) { - lo -= 1 - hi += 1 - } - return { - lo, - hi, - center: st.center, - count: vals.length, - dataMin: Math.min(...vals), - dataMax: Math.max(...vals), - } -} - -function interpolateStops(stops, t) { - t = Math.max(0, Math.min(1, t)) - const pos = t * (stops.length - 1) - const i = Math.min(stops.length - 2, Math.floor(pos)) - const f = pos - i - const a = rgbOf(stops[i]), - b = rgbOf(stops[i + 1]) - const h = (x) => Math.round(x).toString(16).padStart(2, '0') - return ( - '#' + h(a[0] + (b[0] - a[0]) * f) + h(a[1] + (b[1] - a[1]) * f) + h(a[2] + (b[2] - a[2]) * f) - ) -} - -function valueToColor(x, st, dom) { - if (x === null) return st.missing - let t - if (st.scale.diverging) { - const c = Math.min(Math.max(dom.center, dom.lo), dom.hi) - t = x < c ? (0.5 * (x - dom.lo)) / (c - dom.lo || 1) : 0.5 + (0.5 * (x - c)) / (dom.hi - c || 1) - } else { - t = (x - dom.lo) / (dom.hi - dom.lo) - } - return interpolateStops(st.scale.stops, t) -} - -// Size by value: distance from the center on diverging scales, the value itself otherwise. -export function valueForSize(node) { - const st = valueSettings() - const x = nodeValue(node, st) - if (x === null) return 0 - return st.scale.diverging ? Math.abs(x - st.center) : x -} - -export function applyValueColors() { - const has = viewHasValues() - document.getElementById('valueControls').hidden = !has - const fillSel = document.getElementById('nodeFillSelect') - fillSel.querySelector('option[value="values"]').disabled = !has - if (!has && fillSel.value === 'values') fillSel.value = 'groups' - if (!has) { - scheduleLegend() - if (typeof updateFrameControls === 'function') { - stopFramePlay() - updateFrameControls() - } - return - } - // keep the column list current - const colSel = document.getElementById('valueColumn') - const cols = valueColumns() - const current = colSel.value - if ([...colSel.options].map((o) => o.value).join('\u0000') !== cols.join('\u0000')) { - colSel.innerHTML = '' - cols.forEach((c) => colSel.add(new Option(c, c))) - } - if (!cols.includes(colSel.value)) colSel.value = cols.includes(current) ? current : cols[0] - const st = valueSettings() - document.getElementById('valueCenterRow').hidden = !st.scale.diverging - document.getElementById('valueCustomRow').hidden = st.range !== 'custom' - const symOpt = document.getElementById('valueRange').querySelector('option[value="symmetric"]') - symOpt.disabled = !st.scale.diverging - if (!st.scale.diverging && st.range === 'symmetric') - document.getElementById('valueRange').value = 'data' - const dom = valueDomain(st) - cy.batch(() => { - cy.nodes().forEach((n) => { - const c = valueToColor(nodeValue(n, st), st, dom) - if (n.data('valueColor') !== c) n.data('valueColor', c) - }) - if (nodeFillMode() === 'values') cy.nodes().forEach((n) => refreshNodeVisual(n)) - }) - const fmt = (v) => formatAttrValue(Math.round(v * 1000) / 1000) - const own = cy - .nodes() - .filter((n) => !n.hasClass('hidden-group') && nodeValue(n, st) !== null) - .map((n) => nodeValue(n, st)) - document.getElementById('valueSummary').textContent = own.length - ? `${plural(own.length, 'shown node')} with a value, from ${fmt(Math.min(...own))} to ${fmt(Math.max(...own))}${st.transform.fn === VALUE_TRANSFORMS.none.fn ? '' : ' after the transform'}${valueColumns().length > 1 && document.getElementById('valueSameRange').checked ? '; the scale covers all columns' : ''}.` - : 'No shown node has a value in this column.' - if (document.getElementById('sizeMetric').value === 'value') applyNodeSizing() - scheduleLegend() - updateContextInfo() - if (typeof updateFrameControls === 'function') updateFrameControls() -} - -/* ============================================================ - LEGEND - One layout, drawn three ways: on screen (inline SVG), into exported - raster images (canvas) and into exported SVG files. - ============================================================ */ -const LEGEND_W = 230 - -function legendOptions() { - return { - show: document.getElementById('legendShow').checked, - scale: document.getElementById('legendScale').checked, - groups: document.getElementById('legendGroups').checked, - shapes: document.getElementById('legendShapes').checked, - channels: document.getElementById('legendChannels').checked, - title: document.getElementById('legendTitle').value.trim(), - } -} - -export function legendModel() { - const o = legendOptions() - const model = { title: o.title, sections: [], scale: null } - if (legendExtra) - legendExtra.forEach((sec) => - model.sections.push({ - title: sec.title, - items: sec.items.map((it) => ({ - kind: it.kind || 'glyph', - label: it.label, - color: it.color, - shape: 'ellipse', - })), - }) - ) - if ( - o.scale && - viewHasValues() && - (nodeFillMode() === 'values' || document.getElementById('sizeMetric').value === 'value') - ) { - const st = valueSettings() - const dom = valueDomain(st) - const missing = cy.nodes().some((n) => !n.hasClass('hidden-group') && nodeValue(n, st) === null) - model.scale = { - title: st.transform.title(st.column), - stops: st.scale.stops, - diverging: st.scale.diverging, - lo: dom.lo, - hi: dom.hi, - center: Math.min(Math.max(dom.center, dom.lo), dom.hi), - missing: missing ? st.missing : null, - colored: nodeFillMode() === 'values', - sized: document.getElementById('sizeMetric').value === 'value', - } - } - if (o.groups) { - const groups = displayGroups(getUsedGroups()).filter( - (g) => S.activeGroups.has(g) && g !== UNGROUPED - ) - const showing = - nodeFillMode() === 'groups' || - document.getElementById('showGroupHulls').checked || - Object.keys(S.groupShapes).length - if (groups.length && showing) { - const items = groups.slice(0, 40).map((g) => ({ - kind: 'glyph', - label: groupLabel(g), - color: S.nodeColorMap[g] || '#888888', - shape: o.shapes && S.groupShapes[g] ? S.groupShapes[g] : 'ellipse', - })) - if (groups.length > 40) - items.push({ kind: 'note', label: `and ${groups.length - 40} more groups` }) - model.sections.push({ title: legendExtra ? 'Nodes (in which networks)' : 'Groups', items }) - } - } - if (o.channels) { - const types = getUsedTypes().filter((t) => S.activeTypes.has(t)) - if (types.length > 1) { - const items = types.slice(0, 30).map((t) => ({ - kind: 'line', - label: (EDGE_TYPES[t] || { label: t }).label, - color: (EDGE_TYPES[t] || { color: '#888' }).color, - })) - if (types.length > 30) - items.push({ kind: 'note', label: `and ${types.length - 30} more channels` }) - model.sections.push({ - title: legendExtra ? 'Edges (in which networks)' : 'Edge channels', - items, - }) - } - } - return model -} - -export function legendIsEmpty(m) { - return !m.scale && !m.sections.length -} - -function niceTicks(lo, hi, count = 5) { - const span = hi - lo - const step0 = span / (count - 1) - const mag = Math.pow(10, Math.floor(Math.log10(step0))) - const norm = step0 / mag - const step = (norm < 1.5 ? 1 : norm < 3 ? 2 : norm < 7 ? 5 : 10) * mag - const ticks = [] - for (let v = Math.ceil(lo / step - 1e-9) * step; v <= hi + 1e-9; v += step) - ticks.push(Math.abs(v) < step * 1e-9 ? 0 : v) - return ticks -} - -function tickLabel(v) { - const a = Math.abs(v) - if (a !== 0 && (a >= 1e5 || a < 1e-3)) return v.toExponential(1) - return String(Math.round(v * 1000) / 1000) -} - -// Layout in unit pixels: a list of drawing operations. -export function layoutLegend(m) { - const ops = [] - const pad = 12, - w = LEGEND_W - let y = pad - const text = (str, x, yy, size, opts = {}) => - ops.push({ t: 'text', str, x, y: yy, size, ...opts }) - if (m.title) { - text(m.title, pad, y + 12, 14, { bold: true }) - y += 24 - } - if (m.scale) { - const s = m.scale - text(s.title, pad, y + 11, 12, { bold: true }) - y += 18 - const barW = w - 2 * pad, - barH = 12 - ops.push({ - t: 'grad', - x: pad, - y, - w: barW, - h: barH, - stops: s.diverging - ? divergingStopsFor(s) - : s.stops.map((c, i) => [i / (s.stops.length - 1), c]), - }) - ops.push({ t: 'rect', x: pad, y, w: barW, h: barH, stroke: true }) - const ticks = niceTicks(s.lo, s.hi) - ticks.forEach((v) => { - const tx = pad + ((v - s.lo) / (s.hi - s.lo)) * barW - ops.push({ t: 'line', x1: tx, y1: y + barH, x2: tx, y2: y + barH + 4, muted: true }) - text(tickLabel(v), tx, y + barH + 15, 10, { anchor: 'middle', muted: true }) - }) - y += barH + 22 - const notes = [] - if (s.colored && s.sized) notes.push('node color and size') - else if (s.sized) notes.push('node size') - if (notes.length) { - text(`Shown as ${notes.join(', ')}`, pad, y + 8, 10, { muted: true }) - y += 14 - } - if (s.missing) { - ops.push({ t: 'glyph', shape: 'ellipse', x: pad + 6, y: y + 7, r: 6, fill: s.missing }) - text('no value', pad + 18, y + 11, 11, {}) - y += 18 - } - y += 6 - } - m.sections.forEach((sec) => { - text(sec.title, pad, y + 11, 12, { bold: true }) - y += 18 - sec.items.forEach((it) => { - if (it.kind === 'glyph') - ops.push({ t: 'glyph', shape: it.shape, x: pad + 7, y: y + 7, r: 6.5, fill: it.color }) - else if (it.kind === 'line') - ops.push({ - t: 'line', - x1: pad, - y1: y + 7, - x2: pad + 16, - y2: y + 7, - color: it.color, - width: 3, - }) - const label = it.label.length > 30 ? it.label.slice(0, 29) + '…' : it.label - text(label, it.kind === 'note' ? pad : pad + 22, y + 11, 11, { - muted: it.kind === 'note', - full: it.label, - }) - y += 17 - }) - y += 6 - }) - return { w, h: y + pad - 6, ops } -} - -function divergingStopsFor(s) { - // put the middle stop at the center value - const c = (s.center - s.lo) / (s.hi - s.lo) - const n = s.stops.length, - mid = (n - 1) / 2 - return s.stops.map((col, i) => [i <= mid ? (c * i) / mid : c + ((1 - c) * (i - mid)) / mid, col]) -} - -function legendSvg(layout, scale, colors, x0 = 0, y0 = 0) { - const f = (v) => (Math.round(v * 100) / 100).toString() - const esc = (v) => - String(v).replace( - /[&<>"]/g, - (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"' })[c] - ) - const id = 'lg' + Math.random().toString(36).slice(2, 8) - let defs = '', - body = '' - let gi = 0 - layout.ops.forEach((op) => { - if (op.t === 'text') { - body += `${op.full && op.full !== op.str ? `${esc(op.full)}` : ''}${esc(op.str)}` - } else if (op.t === 'grad') { - const gid = `${id}g${gi++}` - defs += `${op.stops.map(([o, c]) => ``).join('')}` - body += `` - } else if (op.t === 'rect') { - body += `` - } else if (op.t === 'line') { - body += `` - } else if (op.t === 'glyph') { - body += glyphSvg(op.shape, op.x, op.y, op.r, op.fill, colors.text) - } - }) - return `${defs ? `${defs}` : ''}${body}` -} - -function glyphSvg(shape, x, y, r, fill, stroke) { - const f = (v) => (Math.round(v * 100) / 100).toString() - const def = shape !== 'ellipse' && cy.renderer().nodeShapes[shape] - if (def && def.points) { - const pts = [] - for (let i = 0; i < def.points.length; i += 2) - pts.push(`${f(x + def.points[i] * r)},${f(y + def.points[i + 1] * r)}`) - return `` - } - return `` -} - -function drawLegendOnCanvas(ctx, layout, scale, colors, x0, y0, bg) { - ctx.save() - ctx.translate(x0, y0) - ctx.scale(scale, scale) - if (bg) { - ctx.fillStyle = bg - ctx.fillRect(0, 0, layout.w, layout.h) - } - layout.ops.forEach((op) => { - if (op.t === 'text') { - ctx.font = `${op.bold ? '700 ' : ''}${op.size}px Inter, Helvetica, Arial, sans-serif` - ctx.fillStyle = op.muted ? colors.muted : colors.text - ctx.textAlign = op.anchor === 'middle' ? 'center' : 'left' - ctx.textBaseline = 'alphabetic' - ctx.fillText(op.str, op.x, op.y) - } else if (op.t === 'grad') { - const g = ctx.createLinearGradient(op.x, 0, op.x + op.w, 0) - op.stops.forEach(([o, c]) => g.addColorStop(Math.max(0, Math.min(1, o)), c)) - ctx.fillStyle = g - ctx.fillRect(op.x, op.y, op.w, op.h) - } else if (op.t === 'rect') { - ctx.strokeStyle = colors.line - ctx.lineWidth = 1 - ctx.strokeRect(op.x, op.y, op.w, op.h) - } else if (op.t === 'line') { - ctx.strokeStyle = op.color || colors.muted - ctx.lineWidth = op.width || 1 - ctx.lineCap = 'round' - ctx.beginPath() - ctx.moveTo(op.x1, op.y1) - ctx.lineTo(op.x2, op.y2) - ctx.stroke() - } else if (op.t === 'glyph') { - ctx.fillStyle = op.fill - ctx.strokeStyle = colors.text - ctx.globalAlpha = 1 - ctx.lineWidth = 0.8 - const def = op.shape !== 'ellipse' && cy.renderer().nodeShapes[op.shape] - ctx.beginPath() - if (def && def.points) { - for (let i = 0; i < def.points.length; i += 2) { - const px = op.x + def.points[i] * op.r, - py = op.y + def.points[i + 1] * op.r - i ? ctx.lineTo(px, py) : ctx.moveTo(px, py) - } - ctx.closePath() - } else ctx.arc(op.x, op.y, op.r, 0, Math.PI * 2) - ctx.fill() - ctx.globalAlpha = 0.35 - ctx.stroke() - ctx.globalAlpha = 1 - } - }) - ctx.restore() -} - -function legendColorsFor(bg) { - // readable text on the export background (or the theme on screen) - const dark = bg - ? (() => { - const [r, g, b] = rgbOf(bg) - return (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255 < 0.45 - })() - : isDarkTheme() - return dark - ? { text: '#e5e7eb', muted: '#9ca3af', line: '#6b7280' } - : { text: '#111827', muted: '#6b7280', line: '#9ca3af' } -} - -function isDarkTheme() { - const [r, g, b] = rgbOf(currentTheme.bg) - return (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255 < 0.45 -} - -// On-screen legend -let legendQueued = false - -export function scheduleLegend() { - if (legendQueued) return - legendQueued = true - requestAnimationFrame(() => { - legendQueued = false - renderLegendPanel() - }) -} - -function renderLegendPanel() { - const el = document.getElementById('legendPanel') - if (!el) return - const o = legendOptions() - const m = o.show ? legendModel() : null - if (!m || legendIsEmpty(m) || !cy.nodes().length) { - el.hidden = true - return - } - const layout = layoutLegend(m) - const colors = { text: currentTheme.text, muted: currentTheme.muted, line: currentTheme.line } - el.innerHTML = `${legendSvg(layout, 1, colors)}` - el.hidden = false -} - -// Adds the legend to the right of an exported picture. -export function exportLegendLayout(o) { - if (!o.legend) return null - const m = legendModel() - return legendIsEmpty(m) ? null : layoutLegend(m) -} - -export function composeCanvasWithLegend(canvas, layout, scale, bg) { - if (!layout) return canvas - const lw = Math.round(layout.w * scale), - lh = Math.round(layout.h * scale) - const out = document.createElement('canvas') - out.width = canvas.width + lw - out.height = Math.max(canvas.height, lh) - const ctx = out.getContext('2d') - if (bg) { - ctx.fillStyle = bg - ctx.fillRect(0, 0, out.width, out.height) - } - ctx.drawImage(canvas, 0, 0) - drawLegendOnCanvas(ctx, layout, scale, legendColorsFor(bg || '#ffffff'), canvas.width, 0, null) - return out -} - -export function composeSvgWithLegend(svgText, layout, scale, bg) { - if (!layout) return svgText - const body = svgText.replace(/^<\?xml[^>]*>\s*/, '') - const wm = /]*\swidth="([\d.]+)"/.exec(body), - hm = /]*\sheight="([\d.]+)"/.exec(body) - const W = wm ? parseFloat(wm[1]) : 1000, - H = hm ? parseFloat(hm[1]) : 800 - const lw = layout.w * scale, - lh = layout.h * scale - const totalW = Math.ceil(W + lw), - totalH = Math.ceil(Math.max(H, lh)) - const inner = body.replace(/\n\n` + - (bg ? `\n` : '') + - inner + - '\n' + - `${legendSvg(layout, scale, legendColorsFor(bg || '#ffffff'), W, 0)}\n` - ) -} - -/* ============================================================ - GROUP SEPARATION - How well a layout separates the ticked groups: - silhouette mean silhouette width of nodes in exactly one group, - from their positions (-1..1, higher = better separated) - intruders share of shown nodes lying inside the convex outline of - a group they don't belong to (lower = better) - overlap share of the area covered by group outlines that is - covered by two or more of them (lower = better) - Scores are computed after every layout and by the layout benchmark. - ============================================================ */ -const SEPARATION_SAMPLE = 1500 - -export function groupSeparation(positions, groupsOf) { - const ids = Object.keys(groupsOf).filter((id) => positions[id]) - const out = { - nodes: ids.length, - groups: 0, - silhouette: NaN, - intruders: NaN, - overlap: NaN, - silhouetteNodes: 0, - } - const members = new Map() - ids.forEach((id) => - groupsOf[id].forEach((g) => { - if (!members.has(g)) members.set(g, []) - members.get(g).push(id) - }) - ) - out.groups = members.size - if (members.size < 2) return out - - // --- silhouette (nodes in exactly one group) - const single = ids.filter((id) => groupsOf[id].length === 1) - const byGroup = new Map() - single.forEach((id) => { - const g = groupsOf[id][0] - if (!byGroup.has(g)) byGroup.set(g, []) - byGroup.get(g).push(id) - }) - if (byGroup.size >= 2) { - const rand = mulberry32(99) - let sample = single - if (single.length > SEPARATION_SAMPLE) { - sample = [...single] - for (let i = sample.length - 1; i > 0; i--) { - const j = Math.floor(rand() * (i + 1)) - ;[sample[i], sample[j]] = [sample[j], sample[i]] - } - sample = sample.slice(0, SEPARATION_SAMPLE) - } - // reference points per group (all single-group nodes, capped per group), as flat arrays - const refs = new Map() - byGroup.forEach((list, g) => { - let pts = list - if (list.length > 400) { - pts = [] - const stepK = list.length / 400 - for (let k = 0; k < 400; k++) pts.push(list[Math.floor(k * stepK)]) - } - const xs = new Float64Array(pts.length), - ys = new Float64Array(pts.length) - pts.forEach((id, k) => { - xs[k] = positions[id].x - ys[k] = positions[id].y - }) - refs.set(g, { xs, ys, ids: new Set(pts) }) - }) - const groupKeys = [...refs.keys()] - let total = 0 - sample.forEach((id) => { - const g = groupsOf[id][0] - const px = positions[id].x, - py = positions[id].y - const own = refs.get(g) - let a = 0, - na = 0 - for (let k = 0; k < own.xs.length; k++) { - const dx = px - own.xs[k], - dy = py - own.ys[k] - const d = Math.sqrt(dx * dx + dy * dy) - if (d === 0 && own.ids.has(id)) continue // the node itself - a += d - na++ - } - if (!na) return // a group of one: silhouette 0 - a /= na - let b = Infinity - for (const h of groupKeys) { - if (h === g) continue - const r = refs.get(h) - let sum = 0 - for (let k = 0; k < r.xs.length; k++) { - const dx = px - r.xs[k], - dy = py - r.ys[k] - sum += Math.sqrt(dx * dx + dy * dy) - } - const mean = sum / r.xs.length - if (mean < b) b = mean - } - const m = Math.max(a, b) - total += m > 0 ? (b - a) / m : 0 - }) - out.silhouette = total / sample.length - out.silhouetteNodes = sample.length - } - - // --- outlines: convex hulls of groups with three or more members - const hulls = [] - members.forEach((list, g) => { - if (list.length < 3) return - const hull = convexHull(list.map((id) => positions[id])) - if (hull.length < 3) return - const xs = hull.map((p) => p.x), - ys = hull.map((p) => p.y) - hulls.push({ - g, - hull, - set: new Set(list), - x1: Math.min(...xs), - x2: Math.max(...xs), - y1: Math.min(...ys), - y2: Math.max(...ys), - }) - }) - if (!hulls.length) return out - const inside = (hull, x, y) => { - // convex polygon in either orientation - let sign = 0 - for (let i = 0; i < hull.length; i++) { - const a = hull[i], - b = hull[(i + 1) % hull.length] - const cr = (b.x - a.x) * (y - a.y) - (b.y - a.y) * (x - a.x) - if (Math.abs(cr) < 1e-9) continue - const s = cr > 0 ? 1 : -1 - if (!sign) sign = s - else if (s !== sign) return false - } - return true - } - let intr = 0 - ids.forEach((id) => { - const p = positions[id] - for (const h of hulls) { - if (h.set.has(id) || p.x < h.x1 || p.x > h.x2 || p.y < h.y1 || p.y > h.y2) continue - if (inside(h.hull, p.x, p.y)) { - intr++ - break - } - } - }) - out.intruders = intr / ids.length - - // --- overlap by rasterising the outlines - const X1 = Math.min(...hulls.map((h) => h.x1)), - X2 = Math.max(...hulls.map((h) => h.x2)) - const Y1 = Math.min(...hulls.map((h) => h.y1)), - Y2 = Math.max(...hulls.map((h) => h.y2)) - const G = 160 - const sx = (X2 - X1) / G || 1, - sy = (Y2 - Y1) / G || 1 - const cover = new Uint16Array(G * G) - hulls.forEach((h) => { - const i1 = Math.max(0, Math.floor((h.x1 - X1) / sx)), - i2 = Math.min(G - 1, Math.floor((h.x2 - X1) / sx)) - const j1 = Math.max(0, Math.floor((h.y1 - Y1) / sy)), - j2 = Math.min(G - 1, Math.floor((h.y2 - Y1) / sy)) - for (let j = j1; j <= j2; j++) { - const y = Y1 + (j + 0.5) * sy - for (let i = i1; i <= i2; i++) { - if (inside(h.hull, X1 + (i + 0.5) * sx, y)) cover[j * G + i]++ - } - } - }) - let any = 0, - multi = 0 - for (let k = 0; k < cover.length; k++) { - if (cover[k]) any++ - if (cover[k] > 1) multi++ - } - out.overlap = any ? multi / any : 0 - return out -} - -// Current 2D positions and ticked groups of the shown nodes. -function currentSeparationInput() { - const positions = {}, - groupsOf = {} - shownNodes().forEach((n) => { - positions[n.id()] = n.position() - groupsOf[n.id()] = effectiveGroupsFor(n).filter((g) => g !== UNGROUPED) - }) - return { positions, groupsOf } -} - -function formatSeparation(r) { - const pct = (v) => (Number.isFinite(v) ? `${(v * 100).toFixed(v < 0.1 ? 1 : 0)}%` : '—') - return { - silhouette: Number.isFinite(r.silhouette) ? r.silhouette.toFixed(2) : '—', - intruders: pct(r.intruders), - overlap: pct(r.overlap), - } -} - -let separationTimer = null - -export function scheduleSeparation() { - clearTimeout(separationTimer) - separationTimer = setTimeout(updateSeparationBox, 350) -} - -function updateSeparationBox() { - const box = document.getElementById('sepValues') - if (!box) return - if (!cy.nodes().length) { - box.innerHTML = 'No network shown.' - return - } - const { positions, groupsOf } = currentSeparationInput() - const r = groupSeparation(positions, groupsOf) - if (r.groups < 2) { - box.innerHTML = 'Needs at least two ticked groups.' - return - } - const f = formatSeparation(r) - const bar = Number.isFinite(r.silhouette) - ? `` - : '' - box.innerHTML = ` -
    Silhouette${f.silhouette}${bar}
    -
    Inside other outlines${f.intruders}
    -
    Outline overlap${f.overlap}
    ` -} - -// page wiring, run by main.ts in the original order -export function init() { - cy.on('layoutstop dragfree', scheduleSeparation) -} diff --git a/frontend/src/clustering/mcl.ts b/frontend/src/clustering/mcl.ts deleted file mode 100644 index 21071bc..0000000 --- a/frontend/src/clustering/mcl.ts +++ /dev/null @@ -1,257 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { labelPropagation } from './label_propagation' -import { leidenCommunities } from './leiden' -import { listSample, normaCols, normaLines, plural } from '../layouts/controls' -import { louvain } from '../wiring' -import { partitionStats, splitDisconnected } from '../welcome' -import { walktrap } from './walktrap' - -/* ---------- Markov clustering ---------- */ -function markovClustering(g, opts = {}) { - const inflation = opts.inflation ?? 2 - const n = g.n - const keep = opts.keep ?? 60 // largest entries kept per column - const eps = 1e-5 - // column-stochastic matrix with self-loops; cols[j] = Map(i -> value) - let cols = new Array(n) - for (let j = 0; j < n; j++) { - const a = g.adj[j] - const w = 1 / (a.length + 1) - const m = new Map([[j, w]]) - for (let k = 0; k < a.length; k++) m.set(a[k], w) - cols[j] = m - } - const prune = (m) => { - let entries = [...m].filter(([, v]) => v > eps) - if (entries.length > keep) { - entries.sort((x, y) => y[1] - x[1]) - entries = entries.slice(0, keep) - } - let s = 0 - entries.forEach((e) => { - s += e[1] - }) - return new Map(entries.map(([i, v]) => [i, v / s])) - } - for (let it = 0; it < 100; it++) { - // expansion: M * M, column by column - const next = new Array(n) - let delta = 0 - for (let j = 0; j < n; j++) { - const out = new Map() - cols[j].forEach((vkj, k) => { - cols[k].forEach((vik, i) => { - out.set(i, (out.get(i) || 0) + vik * vkj) - }) - }) - // inflation - out.forEach((v, i) => out.set(i, Math.pow(v, inflation))) - const pruned = prune(out) - pruned.forEach((v, i) => { - delta = Math.max(delta, Math.abs(v - (cols[j].get(i) || 0))) - }) - next[j] = pruned - } - cols = next - if (delta < 1e-6) break - } - // each node joins its attractor (strongest row in its column); attractors - // that point at each other form one cluster - const parent = Int32Array.from({ length: n }, (_, i) => i) - const find = (x) => { - while (parent[x] !== x) { - parent[x] = parent[parent[x]] - x = parent[x] - } - return x - } - const union = (a, b) => { - const ra = find(a), - rb = find(b) - if (ra !== rb) parent[ra] = rb - } - for (let j = 0; j < n; j++) { - let best = j, - bestV = -1 - cols[j].forEach((v, i) => { - if (v > bestV + 1e-12) { - bestV = v - best = i - } - }) - union(j, best) - } - const raw = new Int32Array(n) - for (let i = 0; i < n; i++) raw[i] = find(i) - return partitionStats(g, splitDisconnected(g, raw)) -} - -export function runCommunityAlgorithm(g, algo, params = {}) { - if (algo === 'louvain') return louvain(g, params.resolution ?? 1) - if (algo === 'leiden') return leidenCommunities(g, { resolution: params.resolution ?? 1 }) - if (algo === 'lpa') return labelPropagation(g) - if (algo === 'walktrap') return walktrap(g, { steps: params.steps ?? 4 }) - if (algo === 'mcl') return markovClustering(g, { inflation: params.inflation ?? 2 }) - throw new Error('Unknown community algorithm: ' + algo) -} - -/* ============================================================ - NUMERIC NODE VALUES - Expression files may hold numbers (log2 fold changes, p-values, ...) - in one or more named columns instead of colors. Each node then carries - data('values') = { column: number | null }, and the chosen column is - mapped to a diverging or sequential color scale and, optionally, to - node size. - ============================================================ */ -export const VALUE_SCALES = { - 'div-rdbu': { - label: 'Blue – white – red', - diverging: true, - stops: ['#2166ac', '#67a9cf', '#f7f7f7', '#ef8a62', '#b2182b'], - }, - 'div-puor': { - label: 'Purple – white – orange', - diverging: true, - stops: ['#5e3c99', '#b2abd2', '#f7f7f7', '#fdb863', '#e66101'], - }, - 'div-prgn': { - label: 'Purple – white – green', - diverging: true, - stops: ['#762a83', '#af8dc3', '#f7f7f7', '#7fbf7b', '#1b7837'], - }, - 'div-brbg': { - label: 'Brown – white – teal', - diverging: true, - stops: ['#8c510a', '#d8b365', '#f5f5f5', '#5ab4ac', '#01665e'], - }, - 'seq-viridis': { - label: 'Viridis', - diverging: false, - stops: ['#440154', '#3b528b', '#21918c', '#5ec962', '#fde725'], - }, - 'seq-magma': { - label: 'Magma', - diverging: false, - stops: ['#000004', '#51127c', '#b73779', '#fc8961', '#fcfdbf'], - }, - 'seq-blues': { - label: 'Light to dark blue', - diverging: false, - stops: ['#f7fbff', '#c6dbef', '#6baed6', '#2171b5', '#08306b'], - }, - 'seq-reds': { - label: 'Light to dark red', - diverging: false, - stops: ['#fff5f0', '#fcbba1', '#fb6a4a', '#cb181d', '#67000d'], - }, -} - -export const VALUE_TRANSFORMS = { - none: { label: 'as they are', fn: (v) => v, title: (c) => c }, - neglog10: { - label: '−log10 (for p-values)', - fn: (v) => (v > 0 ? -Math.log10(v) : null), - title: (c) => `−log10(${c})`, - }, - abs: { label: 'absolute values', fn: (v) => Math.abs(v), title: (c) => `|${c}|` }, -} - -const NUMERIC_MISSING = new Set([ - '', - 'na', - 'n/a', - 'nan', - 'null', - 'none', - '-', - '.', - '?', - 'inf', - '-inf', -]) - -export function parseNumber(s) { - const t = String(s ?? '').trim() - if (NUMERIC_MISSING.has(t.toLowerCase())) return null - // allow decimal commas when there is no dot - const x = Number(/^[-+]?\d+,\d+(e[-+]?\d+)?$/i.test(t) ? t.replace(',', '.') : t) - return Number.isFinite(x) ? x : undefined // undefined: not a number at all -} - -// Does a table look numeric (node name, then numbers)? Used by detection and parsing. -export function numericShare(lines) { - let rows = 0, - numeric = 0 - lines.forEach((line) => { - const cols = normaCols(line) - if (cols.length < 2) return - rows++ - if ( - cols.slice(1).every((c) => parseNumber(c) !== undefined) && - cols.slice(1).some((c) => parseNumber(c) !== null) - ) - numeric++ - }) - return rows ? numeric / rows : 0 -} - -export function parseNumericValues(text) { - const lines = normaLines(text).filter((l) => l.trim()) - let header = null - const first = normaCols(lines[0] || '') - if (first.length >= 2 && first.slice(1).some((c) => parseNumber(c) === undefined)) header = first - const body = header ? lines.slice(1) : lines - const width = Math.max(...body.map((l) => normaCols(l).length), header ? header.length : 2) - const names = [] - for (let c = 1; c < width; c++) { - const raw = header && header[c] ? header[c].trim() : width === 2 ? 'value' : `value ${c}` - let name = raw || `value ${c}` - while (names.includes(name)) name += '′' - names.push(name) - } - const values = new Map() - const bad = [], - repeated = [] - body.forEach((line, i) => { - const cols = normaCols(line) - const node = (cols[0] || '').trim() - if (!node) return - const row = {} - let any = false - names.forEach((name, k) => { - const v = parseNumber(cols[k + 1]) - if (v === undefined) { - bad.push(i + 1 + (header ? 1 : 0)) - row[name] = null - } else { - row[name] = v - if (v !== null) any = true - } - }) - if (values.has(node)) repeated.push(node) - if (any || !values.has(node)) values.set(node, row) - }) - if (!values.size) - throw new Error( - 'No numeric values were found. Each line should be a node name, a tab, then one or more numbers.' - ) - const notes = [] - if (header) notes.push(`Read the first line as column names: ${names.join(', ')}.`) - if (bad.length) - notes.push( - `Read ${plural(bad.length, 'value')} that ${bad.length === 1 ? "isn't a number" : "aren't numbers"} as missing: line ${listSample([...new Set(bad)])}.` - ) - if (repeated.length) - notes.push( - `Kept the last line for ${plural(repeated.length, 'repeated node')}: ${listSample(repeated)}.` - ) - return { - colors: new Map(), - numeric: true, - columns: names, - values, - notes, - summary: `${plural(values.size, 'node')}, ${names.length === 1 ? `values (${names[0]})` : `${names.length} value columns`}`, - } -} diff --git a/frontend/src/clustering/values.test.ts b/frontend/src/clustering/values.test.ts deleted file mode 100644 index b4f9a5c..0000000 --- a/frontend/src/clustering/values.test.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { expect, test } from 'vitest' -import { numericShare, parseNumber, parseNumericValues } from './mcl' - -test('parseNumber: numbers, decimal commas, missing markers, junk', () => { - expect(parseNumber('1.5')).toBe(1.5) - expect(parseNumber('-2,5')).toBe(-2.5) - expect(parseNumber(' 3e2 ')).toBe(300) - expect(parseNumber('NA')).toBeNull() - expect(parseNumber('')).toBeNull() - expect(parseNumber('abc')).toBeUndefined() -}) - -test('numericShare counts rows whose value columns are all numbers', () => { - expect(numericShare(['A\t1', 'B\t2', 'C\tred'])).toBeCloseTo(2 / 3) - expect(numericShare(['A'])).toBe(0) -}) - -test('parseNumericValues reads a header, names columns and reports bad values', () => { - const r = parseNumericValues('node\tlog2fc\tpval\nA\t1.5\t0.01\nB\tx\t0.2\nB\t-1\t0.3\n') - expect(r.values.get('A')).toEqual({ log2fc: 1.5, pval: 0.01 }) - expect(r.values.get('B')).toEqual({ log2fc: -1, pval: 0.3 }) - expect(r.notes.join(' ')).toMatch(/column names: log2fc, pval/) - expect(r.notes.join(' ')).toMatch(/isn't a number/) - expect(r.notes.join(' ')).toMatch(/repeated node/) -}) - -test('parseNumericValues without a header names the single column "value"', () => { - const r = parseNumericValues('A\t1\nB\t2\n') - expect(r.values.get('B')).toEqual({ value: 2 }) -}) - -test('parseNumericValues throws when nothing is numeric', () => { - expect(() => parseNumericValues('A\tred\n')).toThrow(/No numeric values/) -}) diff --git a/frontend/src/clustering/walktrap.ts b/frontend/src/clustering/walktrap.ts deleted file mode 100644 index 4657c8d..0000000 --- a/frontend/src/clustering/walktrap.ts +++ /dev/null @@ -1,198 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { WALKTRAP_NODE_LIMIT, partitionStats } from '../welcome' - -/* ---------- Walktrap ---------- */ -export function walktrap(g, opts = {}) { - const t = opts.steps ?? 4 - const n = g.n - if (n > WALKTRAP_NODE_LIMIT) - throw new Error( - `Walktrap is limited to ${WALKTRAP_NODE_LIMIT.toLocaleString('en-US')} nodes in the browser.` - ) - if (!g.m) - return partitionStats( - g, - Int32Array.from({ length: n }, (_, i) => i) - ) - // random walk with a self-loop on every node (as in the original method) - const deg = g.adj.map((a) => a.length + 1) - const step = (vec) => { - const out = new Map() - vec.forEach((p, u) => { - const share = p / deg[u] - out.set(u, (out.get(u) || 0) + share) - const a = g.adj[u] - for (let k = 0; k < a.length; k++) out.set(a[k], (out.get(a[k]) || 0) + share) - }) - return out - } - // P^t for every node (sparse) - const P = new Array(n) - for (let i = 0; i < n; i++) { - let v = new Map([[i, 1]]) - for (let s = 0; s < t; s++) v = step(v) - // negligible probabilities are dropped to keep memory in check - v.forEach((p, k) => { - if (p < 1e-7) v.delete(k) - }) - P[i] = v - } - const dist2 = (a, b) => { - // sum_k (a_k - b_k)^2 / d_k - let s = 0 - a.forEach((x, k) => { - const y = b.get(k) || 0 - s += ((x - y) * (x - y)) / deg[k] - }) - b.forEach((y, k) => { - if (!a.has(k)) s += (y * y) / deg[k] - }) - return s - } - const size = new Int32Array(2 * n).fill(0) - for (let i = 0; i < n; i++) size[i] = 1 - const vec = P // community vectors, extended as merges happen - const nbrs = Array.from({ length: n }, (_, i) => new Map()) // community -> Map(neighbour -> delta sigma) - const alive = new Uint8Array(2 * n) - for (let i = 0; i < n; i++) alive[i] = 1 - // min-heap of [delta, a, b] - const heap = [] - const push = (item) => { - heap.push(item) - let i = heap.length - 1 - while (i > 0) { - const p = (i - 1) >> 1 - if (heap[p][0] <= heap[i][0]) break - ;[heap[p], heap[i]] = [heap[i], heap[p]] - i = p - } - } - const pop = () => { - const top = heap[0] - const last = heap.pop() - if (heap.length) { - heap[0] = last - let i = 0 - for (;;) { - const l = 2 * i + 1, - r = l + 1 - let m = i - if (l < heap.length && heap[l][0] < heap[m][0]) m = l - if (r < heap.length && heap[r][0] < heap[m][0]) m = r - if (m === i) break - ;[heap[m], heap[i]] = [heap[i], heap[m]] - i = m - } - } - return top - } - const deltaSigma = (a, b) => - (((size[a] * size[b]) / (size[a] + size[b])) * dist2(vec[a], vec[b])) / n - for (let u = 0; u < n; u++) { - g.adj[u].forEach((v) => { - if (v <= u) return - const d = deltaSigma(u, v) - nbrs[u].set(v, d) - nbrs[v].set(u, d) - push([d, u, v]) - }) - } - // modularity bookkeeping on the original graph - const twoM = 2 * g.m - const inW = new Float64Array(2 * n), - totW = new Float64Array(2 * n) - for (let i = 0; i < n; i++) totW[i] = g.adj[i].length - const between = Array.from({ length: n }, (_, u) => { - const mp = new Map() - g.adj[u].forEach((v) => mp.set(v, (mp.get(v) || 0) + 1)) - return mp - }) - let q = 0 - for (let i = 0; i < n; i++) q -= Math.pow(totW[i] / twoM, 2) - const merges = [] - let bestQ = q, - bestStep = 0 - let next = n - while (heap.length) { - const [d, a, b] = pop() - if (!alive[a] || !alive[b] || nbrs[a].get(b) !== d) continue - const c = next++ - alive[a] = 0 - alive[b] = 0 - alive[c] = 1 - size[c] = size[a] + size[b] - const va = vec[a], - vb = vec[b] - const vc = new Map() - va.forEach((x, k) => vc.set(k, (x * size[a]) / size[c])) - vb.forEach((x, k) => vc.set(k, (vc.get(k) || 0) + (x * size[b]) / size[c])) - vec[c] = vc - vec[a] = null - vec[b] = null - // modularity change - const eab = between[a].get(b) || 0 - q += (2 * eab) / twoM - (2 * totW[a] * totW[b]) / (twoM * twoM) - inW[c] = inW[a] + inW[b] + 2 * eab - totW[c] = totW[a] + totW[b] - const bc = new Map() - ;[a, b].forEach((x) => - between[x].forEach((w, y) => { - if (y !== a && y !== b) bc.set(y, (bc.get(y) || 0) + w) - }) - ) - between[c] = bc - bc.forEach((w, y) => { - between[y].delete(a) - between[y].delete(b) - between[y].set(c, w) - }) - merges.push([a, b, c]) - if (q > bestQ + 1e-12) { - bestQ = q - bestStep = merges.length - } - // new distances to neighbouring communities (Lance-Williams where possible) - const nc = new Map() - const neighbours = new Set([...nbrs[a].keys(), ...nbrs[b].keys()]) - neighbours.delete(a) - neighbours.delete(b) - neighbours.forEach((x) => { - let dnew - if (nbrs[a].has(x) && nbrs[b].has(x)) { - dnew = - ((size[a] + size[x]) * nbrs[a].get(x) + - (size[b] + size[x]) * nbrs[b].get(x) - - size[x] * d) / - (size[a] + size[b] + size[x]) - } else { - dnew = deltaSigma(c, x) - } - nc.set(x, dnew) - nbrs[x].delete(a) - nbrs[x].delete(b) - nbrs[x].set(c, dnew) - push([dnew, Math.min(c, x), Math.max(c, x)]) - }) - nbrs[c] = nc - nbrs[a] = new Map() - nbrs[b] = new Map() - } - // replay merges up to the step with the highest modularity - const parent = Int32Array.from({ length: 2 * n }, (_, i) => i) - const find = (x) => { - while (parent[x] !== x) { - parent[x] = parent[parent[x]] - x = parent[x] - } - return x - } - for (let s = 0; s < bestStep; s++) { - const [a, b, c] = merges[s] - parent[a] = c - parent[b] = c - } - const raw = new Int32Array(n) - for (let i = 0; i < n; i++) raw[i] = find(i) - return partitionStats(g, raw) -} diff --git a/frontend/src/clustering/wiring.ts b/frontend/src/clustering/wiring.ts deleted file mode 100644 index f1091ed..0000000 --- a/frontend/src/clustering/wiring.ts +++ /dev/null @@ -1,377 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { VALUE_SCALES } from './mcl' -import { applyValueColors, scheduleLegend, scheduleSeparation } from './mapping' -import { benchmarkTsv, runLayoutBenchmark } from '../benchmark' -import { buildGroupLegend } from '../hulls' -import { cy, onCommitStyle } from '../cy' - -/* ---------- wiring: values, legend, separation, benchmark ---------- */ -export function updateValueScalePreview() { - const sc = VALUE_SCALES[document.getElementById('valueScale').value] || VALUE_SCALES['div-rdbu'] - document.getElementById('valueScalePreview').style.background = - `linear-gradient(90deg, ${sc.stops.join(', ')})` -} - -/* ============================================================ - BUBBLE SETS - Group contours that hug their members (after Collins, Penn and - Carpendale, "Bubble Sets", IEEE TVCG 2009). For each group an energy - field is built on a grid: positive around member nodes and along - "virtual edges" that tie the members together (a minimum spanning - tree, so the contour stays one piece), negative around nodes that are - not members, so the contour bends away from them. The outline is the - iso-line of that field (marching squares), smoothed. - Works in any coordinate system: pass positions and radii in the units - the result should be drawn in. - ============================================================ */ -const BUBBLE_THRESHOLD = 0.45 - -// members / others: [{ x, y, r }]; opts: { margin, edgeRadius, avoid, cell } -export function bubbleContour(members, others, opts) { - if (!members.length) return [] - const margin = opts.margin, - edgeR = opts.edgeRadius, - avoid = opts.avoid - let x1 = Infinity, - y1 = Infinity, - x2 = -Infinity, - y2 = -Infinity, - maxR = 0 - members.forEach((p) => { - x1 = Math.min(x1, p.x - p.r) - y1 = Math.min(y1, p.y - p.r) - x2 = Math.max(x2, p.x + p.r) - y2 = Math.max(y2, p.y + p.r) - maxR = Math.max(maxR, p.r) - }) - const pad = margin * 1.6 + 2 - x1 -= pad - y1 -= pad - x2 += pad - y2 += pad - // grid resolution: fine enough for the margin, capped for speed - let cell = opts.cell || Math.max(margin / 3, 0.5) - const maxCells = opts.maxCells || 250000 - while (((x2 - x1) / cell) * ((y2 - y1) / cell) > maxCells) cell *= 1.25 - const nx = Math.ceil((x2 - x1) / cell) + 1, - ny = Math.ceil((y2 - y1) / cell) + 1 - const F = new Float32Array(nx * ny) - - // positive energy around members: 1 inside the node, fading to 0 at `margin` - const splatDisc = (p, reach, weight) => { - const R = p.r + reach - const i0 = Math.max(0, Math.floor((p.x - R - x1) / cell)), - i1 = Math.min(nx - 1, Math.ceil((p.x + R - x1) / cell)) - const j0 = Math.max(0, Math.floor((p.y - R - y1) / cell)), - j1 = Math.min(ny - 1, Math.ceil((p.y + R - y1) / cell)) - for (let j = j0; j <= j1; j++) { - const gy = y1 + j * cell, - dy = gy - p.y - for (let i = i0; i <= i1; i++) { - const gx = x1 + i * cell, - dx = gx - p.x - const d = Math.sqrt(dx * dx + dy * dy) - p.r - if (d >= reach) continue - const t = d <= 0 ? 1 : 1 - d / reach - F[j * nx + i] += weight * t * t - } - } - } - members.forEach((p) => splatDisc(p, margin, 1)) - - // virtual edges: a minimum spanning tree over the members (Prim) - const m = members.length - const segs = [] - if (m > 1 && m <= 2500) { - const inTree = new Uint8Array(m), - best = new Float64Array(m).fill(Infinity), - from = new Int32Array(m).fill(-1) - best[0] = 0 - for (let k = 0; k < m; k++) { - let u = -1, - bu = Infinity - for (let v = 0; v < m; v++) - if (!inTree[v] && best[v] < bu) { - bu = best[v] - u = v - } - if (u < 0) break - inTree[u] = 1 - if (from[u] >= 0) segs.push([members[from[u]], members[u]]) - const pu = members[u] - for (let v = 0; v < m; v++) { - if (inTree[v]) continue - const d = Math.hypot(members[v].x - pu.x, members[v].y - pu.y) - if (d < best[v]) { - best[v] = d - from[v] = u - } - } - } - } else if (opts.links) { - opts.links.forEach(([a, b]) => segs.push([a, b])) - } - segs.forEach(([a, b]) => { - const R = edgeR - const i0 = Math.max(0, Math.floor((Math.min(a.x, b.x) - R - x1) / cell)), - i1 = Math.min(nx - 1, Math.ceil((Math.max(a.x, b.x) + R - x1) / cell)) - const j0 = Math.max(0, Math.floor((Math.min(a.y, b.y) - R - y1) / cell)), - j1 = Math.min(ny - 1, Math.ceil((Math.max(a.y, b.y) + R - y1) / cell)) - const vx = b.x - a.x, - vy = b.y - a.y, - L2 = vx * vx + vy * vy || 1 - for (let j = j0; j <= j1; j++) { - const gy = y1 + j * cell - for (let i = i0; i <= i1; i++) { - const gx = x1 + i * cell - const t = Math.max(0, Math.min(1, ((gx - a.x) * vx + (gy - a.y) * vy) / L2)) - const d = Math.hypot(gx - (a.x + t * vx), gy - (a.y + t * vy)) - if (d >= R) continue - const s = 1 - d / R - // take the stronger of node and edge energy so tree links don't bloat the nodes - const idx = j * nx + i - F[idx] = Math.max(F[idx], s * s) - } - } - }) - - // negative energy around non-members, strongest at their rim - others.forEach((p) => { - if ( - p.x + p.r + avoid < x1 || - p.x - p.r - avoid > x2 || - p.y + p.r + avoid < y1 || - p.y - p.r - avoid > y2 - ) - return - const R = p.r + avoid - const i0 = Math.max(0, Math.floor((p.x - R - x1) / cell)), - i1 = Math.min(nx - 1, Math.ceil((p.x + R - x1) / cell)) - const j0 = Math.max(0, Math.floor((p.y - R - y1) / cell)), - j1 = Math.min(ny - 1, Math.ceil((p.y + R - y1) / cell)) - for (let j = j0; j <= j1; j++) { - const gy = y1 + j * cell, - dy = gy - p.y - for (let i = i0; i <= i1; i++) { - const gx = x1 + i * cell, - dx = gx - p.x - const d = Math.sqrt(dx * dx + dy * dy) - p.r - if (d >= avoid) continue - const t = d <= 0 ? 1 : 1 - d / avoid - F[j * nx + i] -= 0.9 * t * t - } - } - }) - // members always stay inside their own contour - members.forEach((p) => { - const i = Math.round((p.x - x1) / cell), - j = Math.round((p.y - y1) / cell) - for (let b = -1; b <= 1; b++) - for (let a = -1; a <= 1; a++) { - const ii = i + a, - jj = j + b - if (ii >= 0 && jj >= 0 && ii < nx && jj < ny) F[jj * nx + ii] = Math.max(F[jj * nx + ii], 1) - } - }) - - return marchingSquares(F, nx, ny, x1, y1, cell, BUBBLE_THRESHOLD) -} - -// Iso-lines of a grid as closed loops of points. -function marchingSquares(F, nx, ny, x0, y0, cell, T) { - // edge ids: horizontal edge (i, j)->(i+1, j) = 2 * (j * nx + i); vertical = +1 - const point = new Map() - const edgePoint = (i, j, horizontal) => { - const key = 2 * (j * nx + i) + (horizontal ? 0 : 1) - let p = point.get(key) - if (p) return key - const a = F[j * nx + i] - const b = horizontal ? F[j * nx + i + 1] : F[(j + 1) * nx + i] - const t = Math.abs(b - a) < 1e-9 ? 0.5 : (T - a) / (b - a) - p = horizontal - ? { x: x0 + (i + t) * cell, y: y0 + j * cell } - : { x: x0 + i * cell, y: y0 + (j + t) * cell } - point.set(key, p) - return key - } - const next = new Map() // directed segments: from edge -> to edge - for (let j = 0; j < ny - 1; j++) { - for (let i = 0; i < nx - 1; i++) { - const vtl = F[j * nx + i], - vtr = F[j * nx + i + 1], - vbr = F[(j + 1) * nx + i + 1], - vbl = F[(j + 1) * nx + i] - const tl = vtl >= T, - tr = vtr >= T, - br = vbr >= T, - bl = vbl >= T - const code = (tl ? 8 : 0) | (tr ? 4 : 0) | (br ? 2 : 0) | (bl ? 1 : 0) - if (code === 0 || code === 15) continue - const cx0 = x0 + i * cell, - cy0 = y0 + j * cell, - cx1 = cx0 + cell, - cy1 = cy0 + cell - // orient a segment with a reference corner whose side is known: the - // inside always ends up on the same side of the walking direction - const link = (a, b, px, py, inside) => { - const pa = point.get(a), - pb = point.get(b) - const cross = (pb.x - pa.x) * (py - pa.y) - (pb.y - pa.y) * (px - pa.x) - if (cross > 0 === inside) next.set(a, b) - else next.set(b, a) - } - const top = () => edgePoint(i, j, true), - bottom = () => edgePoint(i, j + 1, true) - const left = () => edgePoint(i, j, false), - right = () => edgePoint(i + 1, j, false) - const TL = (s) => (s ? link(left(), top(), cx0, cy0, tl) : null) - switch (code) { - case 1: - case 14: - link(left(), bottom(), cx0, cy1, bl) - break - case 2: - case 13: - link(bottom(), right(), cx1, cy1, br) - break - case 3: - case 12: - link(left(), right(), cx0, cy0, tl) - break - case 4: - case 11: - link(right(), top(), cx1, cy0, tr) - break - case 6: - case 9: - link(bottom(), top(), cx0, cy0, tl) - break - case 7: - case 8: - link(left(), top(), cx0, cy0, tl) - break - case 5: - case 10: { - const centre = (vtl + vtr + vbr + vbl) / 4 >= T - // saddle: the two corners that differ from the centre are cut off - if (centre === tl) { - link(left(), bottom(), cx0, cy1, bl) - link(top(), right(), cx1, cy0, tr) - } else { - link(left(), top(), cx0, cy0, tl) - link(bottom(), right(), cx1, cy1, br) - } - break - } - } - } - } - const loops = [] - const used = new Set() - next.forEach((_, start) => { - if (used.has(start)) return - const loop = [] - let cur = start - while (cur !== undefined && !used.has(cur)) { - used.add(cur) - loop.push(point.get(cur)) - cur = next.get(cur) - } - if (loop.length >= 3) { - loop.closed = cur === start - loops.push(loop) - } - }) - return loops -} - -// Smooth closed path (quadratic curves through edge midpoints), simplified first. -export function bubblePathD(loops, map) { - const f = (v) => Math.round(v * 100) / 100 - let d = '' - loops.forEach((loop) => { - // drop nearly collinear points to keep paths small - const pts = [] - for (let i = 0; i < loop.length; i++) { - const p = map ? map(loop[i]) : loop[i] - const last = pts[pts.length - 1] - if (!last || Math.hypot(p.x - last.x, p.y - last.y) > 0.8) pts.push(p) - } - if (pts.length < 3) return - const n = pts.length - const mid = (a, b) => ({ x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 }) - const m0 = mid(pts[n - 1], pts[0]) - d += `M${f(m0.x)},${f(m0.y)}` - for (let i = 0; i < n; i++) { - const p = pts[i], - q = mid(p, pts[(i + 1) % n]) - d += `Q${f(p.x)},${f(p.y)} ${f(q.x)},${f(q.y)}` - } - d += 'Z' - }) - return d -} - -// page wiring, run by main.ts in the original order -export function init() { - ;[ - 'valueColumn', - 'valueTransform', - 'valueScale', - 'valueCenter', - 'valueRange', - 'valueMin', - 'valueMax', - 'valueMissing', - ].forEach((id) => { - const el = document.getElementById(id) - const run = () => { - updateValueScalePreview() - applyValueColors() - } - el.addEventListener('change', run) - el.addEventListener('input', run) - }) - - updateValueScalePreview() - - ;[ - 'legendShow', - 'legendScale', - 'legendGroups', - 'legendShapes', - 'legendChannels', - 'legendTitle', - ].forEach((id) => { - document.getElementById(id).addEventListener('input', scheduleLegend) - document.getElementById(id).addEventListener('change', scheduleLegend) - }) - - document.getElementById('sizeMetric').addEventListener('change', scheduleLegend) - - document.getElementById('showGroupHulls').addEventListener('change', scheduleLegend) - - document.getElementById('groupSortSelect').addEventListener('change', () => { - buildGroupLegend() - scheduleLegend() - }) - - document.getElementById('spreadSlider').addEventListener('input', scheduleSeparation) - - document.getElementById('btnBench').addEventListener('click', runLayoutBenchmark) - - document.getElementById('btnBenchTsv').addEventListener('click', benchmarkTsv) - - { - onCommitStyle(scheduleLegend) - } - - cy.on('data', () => { - if ( - !document.getElementById('legendPanel').hidden || - document.getElementById('legendShow').checked - ) - scheduleLegend() - }) -} diff --git a/frontend/src/config.test.ts b/frontend/src/config.test.ts deleted file mode 100644 index 8c7909f..0000000 --- a/frontend/src/config.test.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { expect, test } from 'vitest' - -test('NORMA_CFG merges window.NORMA_CONFIG over the defaults', async () => { - ;(window as unknown as { NORMA_CONFIG: unknown }).NORMA_CONFIG = { - site: { name: 'Test NORMA' }, - app: { maxNodes: 10 }, - features: { relays: { string: false } }, - } - const { NORMA_CFG } = await import('./config') - expect(NORMA_CFG.site.name).toBe('Test NORMA') - expect(NORMA_CFG.site.contactName).toBe('Pavlopoulos Lab') - expect(NORMA_CFG.app.maxNodes).toBe(10) - expect(NORMA_CFG.app.theme).toBe('white') - expect(NORMA_CFG.features.relays).toEqual({ string: false, arena3d: true, databases: true }) - expect((NORMA_CFG as { fromServer?: boolean }).fromServer).toBe(true) -}) diff --git a/frontend/src/config.ts b/frontend/src/config.ts deleted file mode 100644 index 535ff06..0000000 --- a/frontend/src/config.ts +++ /dev/null @@ -1,57 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import cytoscape from 'cytoscape' - -/* ============================================================ - SETTINGS - window.NORMA_CONFIG comes from server.py (/norma-config.js) or from a - norma-config.js file next to norma.html; everything has a default, so - NORMA also runs with no settings at all. - ============================================================ */ -export const NORMA_CFG = (() => { - const d = { - mode: 'local', - version: '3.0', - publicUrl: '', - features: { - restApi: null, - relays: { string: true, arena3d: true, databases: true }, - apiTtlHours: 24, - }, - site: { - name: 'NORMA', - institution: '', - contactName: 'Pavlopoulos Lab', - contactEmail: '', - contactUrl: 'https://github.com/PavlopoulosLab/NORMA/issues', - sourceUrl: 'https://github.com/PavlopoulosLab/NORMA', - licenceName: 'MIT License', - licenceUrl: 'https://opensource.org/licenses/MIT', - privacyUrl: '', - imprintUrl: '', - maintainedUntil: '', - notice: '', - testedBrowsers: [], - }, - app: { maxNodes: 10000, theme: 'white', startTab: 'welcome', cdnFallback: true }, - } - const c = (typeof window.NORMA_CONFIG === 'object' && window.NORMA_CONFIG) || {} - const merge = (a, b) => { - Object.keys(b || {}).forEach((k) => { - if ( - b[k] && - typeof b[k] === 'object' && - !Array.isArray(b[k]) && - a[k] && - typeof a[k] === 'object' - ) - merge(a[k], b[k]) - else if (b[k] !== undefined && b[k] !== null) a[k] = b[k] - }) - return a - } - merge(d, c) - d.served = /^https?:$/.test(location.protocol) - d.fromServer = d.served && !!c.features // server.py writes "features" - return d -})() diff --git a/frontend/src/contours.ts b/frontend/src/contours.ts deleted file mode 100644 index 52fc57a..0000000 --- a/frontend/src/contours.ts +++ /dev/null @@ -1,551 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { EDGE_TYPES } from './palette' -import { NORMA_CFG } from './config' -import { S } from './state' -import { - UNGROUPED, - effectiveGroupsFor, - getUsedGroups, - groupLabel, - nodeFillMode, -} from './network_state' -import { activeView } from './profiler' -import { bubbleContour, bubblePathD } from './clustering/wiring' -import { buildCompareArena3dModel } from './enrichment' -import { cy } from './cy' -import { dataVersion } from './demo_downloads' -import { downloadText, fileStem, plural, setStatus } from './layouts/controls' -import { drawGroupHulls, hexToRgba, hullCanvasCss } from './hulls' -import { edgeIsDirected } from './export/dialog' -import { resolveStringRoute } from './string/requests' -import { rgbOf } from './view3d/state' -import { shownEdges, shownNodes } from './metrics' - -/* ---------- 2D: cached contours in model coordinates ---------- */ -var bubbleCache = { key: '', paths: new Map(), computedAt: 0, timer: null } - -function bubbleSettings(zoom) { - // screen-pixel margins turned into model units at this zoom - const mScale = Math.max(0.15, Math.min(1, zoom)) - return { - margin: (36 * mScale) / zoom, // contour about 12 px outside the nodes - edgeRadius: (24 * mScale) / zoom, // links about 8 px wide on each side - avoid: (14 * mScale) / zoom, - } -} - -function bubbleKey(nodes, zoom) { - let h = 0 - nodes.forEach((n, i) => { - const p = n.position() - h = - (h * 31 + Math.round(p.x * 2) * 7 + Math.round(p.y * 2) * 13 + Math.round(n.width()) + i) % - 1000000007 - }) - const zb = Math.round(Math.log2(zoom) * 4) - return `${dataVersion}|${zb}|${h}|${nodes.length}|${[...S.activeGroups].join('\u0001')}` -} - -// Contours for every ticked group, as SVG path data in model coordinates. -export function bubblePathsModel(force) { - const shown = cy.nodes().filter((n) => !n.hasClass('hidden-group')) - const zoom = cy.zoom() - const key = bubbleKey(shown, zoom) - if (!force && key === bubbleCache.key) return bubbleCache.paths - // while things move, recompute at most every 120 ms (large networks: only - // once they stop) and redraw when they stop - const now = performance.now() - const big = shown.length > 1500 - const sameData = bubbleCache.key.split('|')[0] === String(dataVersion) - if (!force && bubbleCache.key && sameData && (big || now - bubbleCache.computedAt < 120)) { - clearTimeout(bubbleCache.timer) - // redraw inside an animation frame: a canvas drawn from a bare timer is - // not always shown until something else repaints (seen in Chrome on macOS) - bubbleCache.timer = setTimeout( - () => - requestAnimationFrame(() => { - bubbleCache.computedAt = 0 - bubbleCache.settled = true - drawGroupHulls() - }), - big ? 300 : 140 - ) - if (!(big && bubbleCache.settled)) return bubbleCache.paths - } - bubbleCache.settled = false - const zb = Math.pow(2, Math.round(Math.log2(zoom) * 4) / 4) - const opts = bubbleSettings(zb) - const all = shown.map((n) => ({ - id: n.id(), - x: n.position().x, - y: n.position().y, - r: n.width() / 2, - groups: effectiveGroupsFor(n), - })) - const paths = new Map() - getUsedGroups() - .filter((g) => S.activeGroups.has(g) && g !== UNGROUPED) - .forEach((g) => { - const members = all.filter((p) => p.groups.includes(g)) - if (!members.length) return - const others = all.filter((p) => !p.groups.includes(g)) - const loops = bubbleContour(members, others, opts) - paths.set(g, bubblePathD(loops)) - }) - bubbleCache.key = key - bubbleCache.paths = paths - bubbleCache.computedAt = now - return paths -} - -export function drawBubbleSets(ctx, opacity) { - const paths = bubblePathsModel(false) - const z = cy.zoom(), - pan = cy.pan() - // the scale the canvas was actually sized with, not a pixel ratio that - // may have changed since - const dpr = hullCanvasCss.dpr || 1 - ctx.save() - ctx.setTransform(z * dpr, 0, 0, z * dpr, pan.x * dpr, pan.y * dpr) - paths.forEach((d, g) => { - if (!d) return - const color = S.nodeColorMap[g] || '#888888' - const path = new Path2D(d) - ctx.fillStyle = hexToRgba(color, opacity) - ctx.fill(path, 'evenodd') - ctx.lineWidth = 1.6 / z - ctx.strokeStyle = hexToRgba(color, Math.min(1, opacity + 0.45)) - ctx.stroke(path) - }) - ctx.restore() -} - -/* ============================================================ - ARENA3D EXPORT - Arena3D (https://arena3d.org) shows multilayer networks in 3D. Each - ticked group of the current view becomes one layer; nodes keep their - 2D positions inside their layer, edges inside a group stay in its layer - and edges between groups run between layers. A node in several groups - appears once in each of its layers. - Three outputs: - - Arena3D JSON (Arena3D's own export format) - - Arena3D network file (SourceNode, SourceLayer, TargetNode, - TargetLayer, Weight, Channel) - - Open in Arena3D: the JSON is POSTed to /api/external, - which answers { token, url }; the url is opened in a new tab. - ============================================================ */ -export const ARENA3D_LAYER_SPACING = 960 - -export const ARENA3D_LAYER_WIDTH = 947 - -const ARENA3D_COPY_CHANNEL = 'same node' - -export const ARENA3D_MAX_LAYERS = 20 - -function arena3dBase() { - const raw = (document.getElementById('arenaAddress').value || 'https://arena3d.org') - .trim() - .replace(/\/+$/, '') - return /^https?:\/\//i.test(raw) ? raw : 'https://' + raw -} - -export function hexColor(c) { - const [r, g, b] = rgbOf(c) - const h = (x) => - Math.max(0, Math.min(255, Math.round(x))) - .toString(16) - .padStart(2, '0') - return '#' + h(r) + h(g) + h(b) -} - -// Arena3D layer names can't contain underscores (node ids are name_layer). -export function arenaSafe(s) { - return ( - String(s) - .replace(/_/g, '-') - .replace(/[\t\r\n]+/g, ' ') - .trim() || '-' - ) -} - -function buildArena3dModel() { - const connectCopies = document.getElementById('arenaCopies').checked - const colorMode = document.getElementById('arenaNodeColors').value - const nodes = shownNodes() - const edges = shownEdges(true).filter((e) => e.data('source') !== e.data('target')) - if (!nodes.length) throw new Error('Show a network first.') - - // layers: ticked groups in legend order, then one for nodes in no group - const groupOrder = getUsedGroups().filter((g) => S.activeGroups.has(g) && g !== UNGROUPED) - const layersOf = new Map() - let ungrouped = false - nodes.forEach((n) => { - let gs = effectiveGroupsFor(n).filter((g) => g !== UNGROUPED) - if (!gs.length) { - gs = [UNGROUPED] - ungrouped = true - } - layersOf.set(n.id(), gs) - }) - let layerKeys = [...groupOrder.filter((g) => nodes.some((n) => layersOf.get(n.id()).includes(g)))] - if (ungrouped) layerKeys.push(UNGROUPED) - // Arena3D takes up to 20 layers: keep the first 20 (group list order) - let droppedLayers = 0, - droppedNodes = 0 - if (layerKeys.length > ARENA3D_MAX_LAYERS) { - droppedLayers = layerKeys.length - ARENA3D_MAX_LAYERS - layerKeys = layerKeys.slice(0, ARENA3D_MAX_LAYERS) - const kept = new Set(layerKeys) - ;[...layersOf].forEach(([id, gs]) => { - const left = gs.filter((g) => kept.has(g)) - if (left.length) layersOf.set(id, left) - else { - layersOf.delete(id) - droppedNodes++ - } - }) - } - const usedNames = new Set() - const layerName = new Map( - layerKeys.map((g) => { - let name = arenaSafe(g === UNGROUPED ? 'No group' : groupLabel(g)) - while (usedNames.has(name)) name += '′' - usedNames.add(name) - return [g, name] - }) - ) - const nodeName = (id) => arenaSafe(id) - - // positions: each layer's nodes are fitted into the layer's square - const layers = layerKeys.map((g, i) => ({ - key: g, - name: layerName.get(g), - position_x: String((i - (layerKeys.length - 1) / 2) * ARENA3D_LAYER_SPACING), - position_y: '0', - position_z: '0', - last_layer_scale: '1', - rotation_x: '0', - rotation_y: '0', - rotation_z: '0', - floor_current_color: g === UNGROUPED ? '#777777' : hexColor(S.nodeColorMap[g] || '#777777'), - geometry_parameters_width: String(ARENA3D_LAYER_WIDTH), - })) - const outNodes = [] - const half = ARENA3D_LAYER_WIDTH * 0.42 - layers.forEach((layer) => { - const members = nodes.filter( - (n) => layersOf.has(n.id()) && layersOf.get(n.id()).includes(layer.key) - ) - const xs = members.map((n) => n.position('x')), - ys = members.map((n) => n.position('y')) - const cx = (Math.min(...xs) + Math.max(...xs)) / 2, - cy0 = (Math.min(...ys) + Math.max(...ys)) / 2 - const span = Math.max(Math.max(...xs) - Math.min(...xs), Math.max(...ys) - Math.min(...ys)) || 1 - const k = members.length > 1 ? (2 * half) / span : 0 - members.forEach((n) => { - // pie nodes (several groups) take the color of the layer they are drawn in - const multi = nodeFillMode() === 'groups' && effectiveGroupsFor(n).length > 1 - const color = - (colorMode === 'group' || multi) && layer.key !== UNGROUPED - ? S.nodeColorMap[layer.key] || '#777777' - : n.style('background-color') - const attrs = n.data('attrs') || {} - outNodes.push({ - name: nodeName(n.id()), - layer: layer.name, - position_x: '0', - position_y: String(-(n.position('y') - cy0) * k), - position_z: String((n.position('x') - cx) * k), - scale: String(Math.round(Math.max(0.3, Math.min(3, (n.width() || 42) / 42)) * 100) / 100), - color: hexColor(color), - url: - typeof attrs.url === 'string' - ? attrs.url - : attrs.stringId - ? `https://string-db.org/network/${attrs.stringId}` - : '', - descr: typeof attrs.description === 'string' ? attrs.description : '', - }) - }) - }) - - // edges - const weights = edges.map((e) => e.data('weight')).filter((w) => typeof w === 'number') - const weighted = weights.length > 0 - const wMin = weighted ? Math.min(...weights) : 0, - wMax = weighted ? Math.max(...weights) : 1 - const opacityOf = (w) => { - if (!weighted || typeof w !== 'number' || wMax === wMin) return 1 - return Math.round((0.2 + (0.8 * (w - wMin)) / (wMax - wMin)) * 1000) / 1000 - } - const multiChannel = new Set(edges.map((e) => e.data('type'))).size > 1 - const outEdges = [] - const rows = [] - const seen = new Set() - let interLayer = 0 - edges.forEach((e) => { - const s = e.data('source'), - t = e.data('target') - const ls = layersOf.get(s), - lt = layersOf.get(t) - if (!ls || !lt) return - const shared = ls.filter((g) => lt.includes(g)) - const pairs = shared.length ? shared.map((g) => [g, g]) : [[ls[0], lt[0]]] - if (!shared.length) interLayer++ - const channelLabel = (EDGE_TYPES[e.data('type')] || { label: e.data('type') }).label - const channel = multiChannel ? arenaSafe(channelLabel) : '' - pairs.forEach(([gs, gt]) => { - const src = `${nodeName(s)}_${layerName.get(gs)}`, - trg = `${nodeName(t)}_${layerName.get(gt)}` - const key = [src, trg, channel].join('\u0000') - if (seen.has(key)) return - seen.add(key) - outEdges.push({ - src, - trg, - opacity: String(opacityOf(e.data('weight'))), - color: hexColor(e.style('line-color') || e.data('color')), - channel, - }) - rows.push([ - nodeName(s), - layerName.get(gs), - nodeName(t), - layerName.get(gt), - typeof e.data('weight') === 'number' ? e.data('weight') : 1, - channel || '1', - ]) - }) - }) - // optional edges linking the copies of a node in different layers - let copyEdges = 0 - if (connectCopies) { - layersOf.forEach((gs, id) => { - for (let i = 0; i + 1 < gs.length; i++) { - const src = `${nodeName(id)}_${layerName.get(gs[i])}`, - trg = `${nodeName(id)}_${layerName.get(gs[i + 1])}` - outEdges.push({ - src, - trg, - opacity: '0.6', - color: '#FFFFFF', - channel: multiChannel ? ARENA3D_COPY_CHANNEL : '', - }) - rows.push([ - nodeName(id), - layerName.get(gs[i]), - nodeName(id), - layerName.get(gs[i + 1]), - 1, - multiChannel ? ARENA3D_COPY_CHANNEL : '1', - ]) - copyEdges++ - } - }) - } - const json = { - scene: { - position_x: '0', - position_y: '0', - scale: String( - layers.length > 4 ? Math.round(((0.6561 * 4) / layers.length) * 1e4) / 1e4 : 0.6561 - ), - color: '#000000', - rotation_x: '0.261799387799149', - rotation_y: '0.261799387799149', - rotation_z: '0.0872664625997165', - }, - layers: layers.map(({ key, ...rest }) => rest), - nodes: outNodes, - edges: outEdges, - universalLabelColor: '#FFFFFF', - direction: edges.some((e) => edgeIsDirected(e)), - edgeOpacityByWeight: weighted, - edgeWidthByWeight: false, - } - const multiLayerNodes = [...layersOf.values()].filter((gs) => gs.length > 1).length - return { - json, - rows, - stats: { - layers: layers.length, - nodes: outNodes.length, - edges: outEdges.length, - interLayer, - copyEdges, - multiLayerNodes, - distinctNodes: layersOf.size, - droppedLayers, - droppedNodes, - }, - } -} - -function arena3dNetworkText(rows) { - return ( - [ - 'SourceNode\tSourceLayer\tTargetNode\tTargetLayer\tWeight\tChannel', - ...rows.map((r) => r.join('\t')), - ].join('\n') + '\n' - ) -} - -function arena3dSummary(st) { - const parts = [ - `${plural(st.layers, 'layer')}, ${plural(st.nodes, 'node')} (${st.distinctNodes.toLocaleString()} distinct), ${plural(st.edges, 'edge')}`, - ] - if (st.interLayer) parts.push(`${plural(st.interLayer, 'edge')} between layers`) - if (st.multiLayerNodes) parts.push(`${plural(st.multiLayerNodes, 'node')} in several layers`) - if (st.droppedLayers) - parts.push( - `Arena3D takes up to ${ARENA3D_MAX_LAYERS} layers, so only the first ${ARENA3D_MAX_LAYERS} groups were exported (${plural(st.droppedLayers, 'group')} left out${st.droppedNodes ? `, with ${plural(st.droppedNodes, 'node')} that ${st.droppedNodes === 1 ? 'is' : 'are'} only in those` : ''})` - ) - return parts.join('; ') -} - -// The current view, or the Network Comparison (`src`), as an Arena3D network. -const ARENA3D_SOURCES = { - view: { - build: async () => buildArena3dModel(), - status: 'arenaStatus', - button: 'btnArenaOpen', - stem: () => { - const v = typeof activeView === 'function' && activeView() - return `arena3d-${v ? fileStem(v.name) : 'network'}` - }, - }, - compare: { - build: async () => buildCompareArena3dModel(), - status: 'cmpArenaStatus', - button: 'btnCmpArenaOpen', - stem: () => 'arena3d-comparison', - }, -} - -export async function exportArena3d(kind, src = 'view') { - const S = ARENA3D_SOURCES[src] - try { - setStatus(S.status, [{ level: 'busy', text: 'Preparing the Arena3D network…', progress: null }]) - const model = await S.build() - const stem = S.stem() - if (kind === 'json') { - downloadText(`${stem}.json`, JSON.stringify(model.json, null, 2)) - setStatus(S.status, [ - { level: 'ok', text: `Saved ${stem}.json: ${arena3dSummary(model.stats)}.` }, - ]) - } else { - downloadText(`${stem}.txt`, arena3dNetworkText(model.rows)) - setStatus(S.status, [ - { - level: 'ok', - text: `Saved ${stem}.txt (Arena3D network file): ${arena3dSummary(model.stats)}. Use Upload Network in Arena3D to open it.`, - }, - ]) - } - } catch (err) { - setStatus(S.status, [{ level: 'error', text: err.message }]) - } -} - -export async function openInArena3d(src = 'view') { - const S = ARENA3D_SOURCES[src] - // open the tab now, while the click still counts as a user action, so - // pop-up blockers let it through; it is pointed at Arena3D once the - // server answers - const tab = window.open('', '_blank') - if (tab) { - try { - tab.document.write( - 'Opening Arena3D…

    Sending the network to Arena3D…

    ' - ) - } catch (e) {} - } - const btn = document.getElementById(S.button) - btn.disabled = true - let model - try { - model = await S.build() - } catch (err) { - if (tab && !tab.closed) tab.close() - btn.disabled = false - setStatus(S.status, [{ level: 'error', text: err.message }]) - return - } - setStatus(S.status, [ - { level: 'busy', text: `Sending ${arena3dSummary(model.stats)} to Arena3D…`, progress: null }, - ]) - try { - const route = - NORMA_CFG.features.relays.arena3d === false ? 'direct' : await resolveStringRoute() - const body = JSON.stringify(model.json) - const url = - route === 'proxy' - ? `arena3d-api/external?upstream=${encodeURIComponent(arena3dBase())}` - : `${arena3dBase()}/api/external` - let response - try { - response = await fetch(url, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body, - }) - } catch (err) { - throw new Error( - route === 'proxy' - ? `The server relay could not be reached (${err.message}). Check that server.py is still running.` - : `Arena3D could not be reached (${err.message}). Browsers may block direct calls to other sites; run NORMA with server.py, or save the Arena3D JSON and load it in Arena3D yourself.` - ) - } - const text = await response.text() - if (!response.ok) { - if (route === 'proxy' && !/^\s*[\[{]/.test(text) && response.status !== 502) - throw new Error( - 'This server has no Arena3D relay. Start NORMA with server.py, or save the Arena3D JSON instead.' - ) - throw new Error(`Arena3D answered with an error (${response.status}): ${text.slice(0, 200)}`) - } - let answer - try { - answer = JSON.parse(text) - } catch (e) { - throw new Error('Arena3D sent an answer that is not JSON.') - } - if (!answer || !answer.url) throw new Error('Arena3D did not return a link to the network.') - if (tab && !tab.closed) tab.location.href = answer.url - else window.open(answer.url, '_blank') - setStatus(S.status, [ - { level: 'ok', text: `Opened in Arena3D: ${arena3dSummary(model.stats)}.` }, - { - level: 'ok', - text: 'If no new tab appeared, open the link:', - action: { label: 'Open Arena3D', run: () => window.open(answer.url, '_blank') }, - }, - ]) - } catch (err) { - if (tab && !tab.closed) tab.close() - setStatus(S.status, [ - { level: 'error', text: err.message }, - { - level: 'ok', - text: 'You can still save the Arena3D JSON and load it in Arena3D.', - action: { label: 'Save Arena3D JSON', run: () => exportArena3d('json', src) }, - }, - ]) - } finally { - btn.disabled = false - } -} - -// page wiring, run by main.ts in the original order -export function init() { - document.getElementById('btnArenaOpen').addEventListener('click', () => openInArena3d('view')) - - document - .getElementById('btnArenaJson') - .addEventListener('click', () => exportArena3d('json', 'view')) - - document - .getElementById('btnArenaTsv') - .addEventListener('click', () => exportArena3d('tsv', 'view')) -} diff --git a/frontend/src/cy.ts b/frontend/src/cy.ts deleted file mode 100644 index 1e71443..0000000 --- a/frontend/src/cy.ts +++ /dev/null @@ -1,181 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import cytoscape from 'cytoscape' -import { webglPreference } from './enrichment' - -/* ---------- cytoscape setup ---------- */ -/* ---------- stylesheet ---------- - BASE_STYLE is the fixed rule list. Settings change it only through - setStyle(selector, props), which merges into the rule for that selector. - The whole sheet is then rebuilt once per tick, so it never grows no - matter how often sliders move, and rule order (and therefore which rule - wins) stays fixed: node, node.dimmed, ..., edge, ..., edge.highlighted. */ -export const SELECTION_YELLOW = '#facc15' - -const BASE_STYLE = [ - { - selector: 'node', - style: { - 'background-color': 'data(color)', - 'pie-size': '100%', - // Cytoscape supports up to 16 pie slices per node - ...Object.fromEntries( - Array.from({ length: 16 }, (_, i) => [ - [`pie-${i + 1}-background-color`, `data(pieColor${i + 1})`], - [`pie-${i + 1}-background-size`, `data(pieSize${i + 1})`], - ]).flat() - ), - width: 'data(size)', - height: 'data(size)', - shape: 'data(shape)', - label: 'data(id)', - color: '#e7ebf5', - 'font-size': 'data(labelPx)', - 'font-family': 'Inter, sans-serif', - 'text-valign': 'center', - 'text-margin-y': 0, - 'text-outline-width': 3, - 'text-outline-color': '#0f1420', - 'border-width': 2, - 'border-color': 'rgba(255,255,255,0.35)', - 'overlay-opacity': 0, - }, - }, - { - selector: 'node.dimmed', - style: { opacity: 0.12 }, - }, - { - selector: 'node.highlighted', - style: { 'border-color': '#5fd3c4', 'border-width': 3 }, - }, - { - // several nodes can be selected (Shift/Ctrl/Cmd-click or Shift-drag); - // a thick border plus a soft halo keeps them visible at any zoom - selector: 'node:selected', - style: { - 'border-width': 5, - 'border-color': '#facc15', - 'underlay-color': '#facc15', - 'underlay-opacity': 0.35, - 'underlay-padding': 7, - 'underlay-shape': 'ellipse', - }, - }, - { - selector: 'edge', - style: { - 'curve-style': 'haystack', - 'haystack-radius': 0.4, - width: 2, - 'line-color': 'data(color)', - opacity: 0.85, - }, - }, - { - selector: 'edge.hidden-type', - style: { display: 'none' }, - }, - { - selector: 'edge.merged-hidden', - style: { display: 'none' }, - }, - { - selector: 'node.hidden-group', - style: { display: 'none' }, - }, - { - selector: 'edge.dimmed', - style: { opacity: 0.04 }, - }, - { - selector: 'edge.highlighted', - style: { opacity: 1, width: 3.2 }, - }, - { - selector: 'edge:selected', - style: { - 'underlay-color': '#facc15', - 'underlay-opacity': 0.45, - 'underlay-padding': 4, - opacity: 1, - }, - }, - { - selector: 'core', - style: { - 'selection-box-color': '#0f766e', - 'selection-box-opacity': 0.12, - 'selection-box-border-color': '#0f766e', - 'selection-box-border-width': 1, - 'active-bg-opacity': 0, - }, - }, -] - -const DYNAMIC_STYLE = {} - -let styleCommitQueued = false - -function buildStylesheet() { - const seen = new Set() - const sheet = BASE_STYLE.map((rule) => { - seen.add(rule.selector) - return { - selector: rule.selector, - style: { ...rule.style, ...(DYNAMIC_STYLE[rule.selector] || {}) }, - } - }) - Object.keys(DYNAMIC_STYLE).forEach((sel) => { - if (!seen.has(sel)) sheet.push({ selector: sel, style: { ...DYNAMIC_STYLE[sel] } }) - }) - return sheet -} - -// other modules (3D view, legend) react after every style commit -const styleHooks = [] - -export function onCommitStyle(fn) { - styleHooks.push(fn) -} - -function commitStyle() { - styleCommitQueued = false - cy.style().fromJson(buildStylesheet()).update() - styleHooks.forEach((fn) => fn()) -} - -export function setStyle(selector, props) { - DYNAMIC_STYLE[selector] = { ...(DYNAMIC_STYLE[selector] || {}), ...props } - if (!styleCommitQueued) { - styleCommitQueued = true - queueMicrotask(commitStyle) - } -} - -// WebGL drawing is chosen once, when the canvas is created (see Display → Performance). -export const WEBGL_ACTIVE = (() => { - try { - return webglPreference() - } catch (e) { - return false - } -})() - -export const cy = cytoscape({ - container: document.getElementById('cy'), - ...(WEBGL_ACTIVE ? { renderer: { name: 'canvas', webgl: true } } : {}), - elements: [], - // Effectively unlimited zoom. Cytoscape's own limits are 1e-50..1e50, - // but canvas drawing breaks down long before that; a millionfold either - // way is far past anything useful. Panning is kept in bounds by - // clampViewport() below, so the network can't be lost off-screen. - minZoom: 1e-6, - maxZoom: 1e6, - // with panning on, box selection needs Shift (or Ctrl/Cmd/Alt) while dragging - boxSelectionEnabled: true, - selectionType: 'single', - wheelSensitivity: 0.25, - style: BASE_STYLE, - layout: { name: 'grid' }, -}) diff --git a/frontend/src/demo_downloads.ts b/frontend/src/demo_downloads.ts deleted file mode 100644 index 6f5e205..0000000 --- a/frontend/src/demo_downloads.ts +++ /dev/null @@ -1,323 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { EDGE_TYPES } from './palette' -import { S } from './state' -import { SAMPLE_GENERATORS } from './sample_data' -import { activeView, restoreView, snapshotData, spreadBase, viewSettings } from './profiler' -import { cy } from './cy' -import { downloadText, libSelection } from './layouts/controls' -import { escapeHtml } from './network_state' -import { getUsedTypes } from './hulls' - -/* ---------- built-in demo downloads (Help > Example files) ---------- */ -// Converts a demo in loadData's JSON shape to NORMA's text formats. -export function demoToNormaTexts(data) { - const weighted = data.edges.some((e) => typeof e.weight === 'number') - const typed = new Set(data.edges.map((e) => e.type || 'link')).size > 1 - const isDirected = (e) => (e.directed === undefined ? !!data.directed : !!e.directed) - const withDirection = data.edges.some(isDirected) - const header = ['Source', 'Target'] - if (weighted) header.push('Weight') - if (typed) header.push('Type') - if (withDirection) header.push('Direction') - const netLines = [header.join('\t')] - data.edges.forEach((e) => { - const row = [e.source, e.target] - if (weighted) row.push(String(typeof e.weight === 'number' ? e.weight : 1)) - if (typed) row.push(e.type || 'link') - if (withDirection) row.push(isDirected(e) ? 'directed' : 'undirected') - netLines.push(row.join('\t')) - }) - const members = new Map() - ;(data.groupOrder || []).forEach((g) => members.set(g, [])) - data.nodes.forEach((n) => { - const groups = n.groups && n.groups.length ? n.groups : n.group ? [n.group] : [] - groups.forEach((g) => { - if (!members.has(g)) members.set(g, []) - members.get(g).push(n.id) - }) - }) - const attrs = data.groupAttrs || {} - const annLines = [...members] - .filter(([, m]) => m.length) - .map(([g, m]) => `${(attrs[g] && attrs[g].label) || g}\t${m.join(',')}`) - return { network: netLines.join('\n') + '\n', annotation: annLines.join('\n') + '\n' } -} - -const DEMO_DOWNLOADS = [ - [ - 'trp', - 'E. coli trp operon, multi-edge', - 'Channels, weights, gene function and EC number attributes, group descriptions', - ], - ['modules50', '4 overlapping modules (50 nodes)', 'Attributes on nodes, edges and groups'], - ['modules100', '4 overlapping modules (100 nodes)', 'Attributes on nodes, edges and groups'], - [ - 'tiny', - 'Random network with edge labels (20 nodes)', - 'Each edge has an interaction attribute, shown as its label', - ], - [ - 'directed', - 'Random directed multi-edge network (40 nodes)', - 'Arrows from source to target, up to three channels per pair, some reciprocal edges; the network file has a Direction column', - ], - ['small', 'Random network (60 nodes)', ''], - ['medium', 'Random network (200 nodes)', ''], - ['large', 'Random network (800 nodes)', ''], - ['massive', 'Random network (5,000 nodes)', ''], -] - -function renderDemoDownloads() { - const root = document.getElementById('helpDemoFiles') - if (!root) return - const table = document.createElement('table') - table.className = 'help-table' - table.innerHTML = 'DemoDownload' - const body = document.createElement('tbody') - DEMO_DOWNLOADS.forEach(([key, title, note]) => { - const tr = document.createElement('tr') - const td1 = document.createElement('td') - td1.innerHTML = `${escapeHtml(title)}${note ? `${escapeHtml(note)}` : ''}` - const td2 = document.createElement('td') - td2.className = 'dl-buttons' - const make = (label, fileName, build) => { - const btn = document.createElement('button') - btn.type = 'button' - btn.className = 'dl-copy' - btn.textContent = label - btn.title = `Download ${fileName}` - btn.addEventListener('click', () => downloadText(fileName, build())) - td2.appendChild(btn) - } - const gen = () => SAMPLE_GENERATORS[key]() - make('Network', `demo-${key}-network.txt`, () => demoToNormaTexts(gen()).network) - make('Groups', `demo-${key}-annotation.txt`, () => demoToNormaTexts(gen()).annotation) - make('JSON', `demo-${key}.json`, () => JSON.stringify(gen(), null, 2)) - tr.append(td1, td2) - body.appendChild(tr) - }) - table.appendChild(body) - root.appendChild(table) -} - -/* ============================================================ - UNDO / REDO - Each view keeps its own history. An entry is the view's full visual - state (settings, node positions, ticked groups and channels, colors, - spread) plus a reference to its data; data snapshots are reused until - the data actually changes, so moving a node doesn't copy the network. - Recording: the first change after a quiet moment pushes the last - settled state onto the undo stack; further changes within the same - burst (slider drags, layout animations) join that entry, and the state - settles once nothing has changed for a moment. Entries that turn out to - change nothing are dropped. Zoom, pan, search and selection are not - part of the history, and neither is the theme. - ============================================================ */ -const HISTORY_LIMIT = 60 - -const HISTORY_SETTLE_MS = 450 - -export let historyTimer = null - -export let dataVersion = 0 - -export function bumpDataVersion() { - dataVersion++ -} - -function viewHistory() { - const v = activeView() - if (!v) return null - if (!v.history) v.history = { undo: [], redo: [], committed: null } - return v.history -} - -function currentDataSnapshot() { - if (S.dataCache.version !== dataVersion) - S.dataCache = { version: dataVersion, data: snapshotData() } - return S.dataCache.data -} - -function captureHistoryState() { - const positions = {} - cy.nodes().forEach((n) => { - const p = n.position() - positions[n.id()] = { x: p.x, y: p.y } - }) - const typeColors = {} - getUsedTypes().forEach((t) => { - if (EDGE_TYPES[t]) typeColors[t] = EDGE_TYPES[t].color - }) - return { - data: currentDataSnapshot(), - selection: { - networks: [...libSelection.networks], - annotation: libSelection.annotation, - colors: libSelection.colors, - }, - state: { - config: viewSettings(), - positions, - activeGroups: [...S.activeGroups], - activeTypes: [...S.activeTypes], - groupColors: { ...S.nodeColorMap }, - typeColors, - libView: S.currentLibView ? { ...S.currentLibView } : null, - spread: parseFloat(document.getElementById('spreadSlider').value) || 0, - // kept in memory only: lets Spread return to the exact positions after undo - spreadBase: spreadBase ? { ...spreadBase } : null, - groupFilter: document.getElementById('groupFilter').value, - }, - } -} - -function sameHistoryState(a, b) { - if (!a || !b || a.data !== b.data) return false - const pa = a.state.positions, - pb = b.state.positions - const ids = Object.keys(pa) - if (ids.length !== Object.keys(pb).length) return false - for (const id of ids) { - const p = pa[id], - q = pb[id] - if (!q || Math.abs(p.x - q.x) > 0.01 || Math.abs(p.y - q.y) > 0.01) return false - } - const strip = (e) => - JSON.stringify({ ...e.state, positions: null, spreadBase: null, sel: e.selection }) - return strip(a) === strip(b) -} - -function layoutStillRunning() { - return ( - S.cyLayoutsRunning > 0 || - document.getElementById('btnRunLayout').disabled || - cy.nodes().animated() - ) -} - -export function scheduleSettle() { - clearTimeout(historyTimer) - historyTimer = setTimeout(settleHistory, HISTORY_SETTLE_MS) -} - -function settleHistory() { - clearTimeout(historyTimer) - historyTimer = null - const h = viewHistory() - if (!h) { - S.historyGestureOpen = false - return - } - if (layoutStillRunning()) { - scheduleSettle() - return - } - const now = captureHistoryState() - if (S.historyGestureOpen && h.undo.length && sameHistoryState(h.undo[h.undo.length - 1], now)) { - h.undo.pop() - } - h.committed = now - S.historyGestureOpen = false - updateUndoButtons() -} - -// Settles right away (used before switching views and before undo/redo). -export function flushHistory() { - if (historyTimer || S.historyGestureOpen) { - clearTimeout(historyTimer) - historyTimer = null - const h = viewHistory() - if (h) { - const now = captureHistoryState() - if (S.historyGestureOpen && h.undo.length && sameHistoryState(h.undo[h.undo.length - 1], now)) - h.undo.pop() - h.committed = now - } - S.historyGestureOpen = false - } -} - -// Call after something the user did changed (or is about to change) the view. -export function noteChange() { - if (S.historySuspended) return - const h = viewHistory() - if (!h) return - if (!S.historyGestureOpen) { - if (h.committed) { - h.undo.push(h.committed) - if (h.undo.length > HISTORY_LIMIT) h.undo.shift() - h.redo.length = 0 - } - S.historyGestureOpen = true - } - scheduleSettle() - updateUndoButtons() -} - -// Records the current state as the starting point (no undo entry). -export function setHistoryBaseline() { - S.historyGestureOpen = false - scheduleSettle() -} - -function applyHistoryState(entry) { - S.historySuspended++ - try { - const reuse = entry.data === currentDataSnapshot() && cy.nodes().length > 0 - restoreView( - { data: entry.data, selection: entry.selection, state: { ...entry.state } }, - { reuseData: reuse } - ) - if (!reuse) S.dataCache = { version: dataVersion, data: entry.data } - } finally { - S.historySuspended-- - } -} - -export function undo() { - flushHistory() - const h = viewHistory() - if (!h || !h.undo.length) return - const target = h.undo.pop() - if (h.committed) h.redo.push(h.committed) - applyHistoryState(target) - h.committed = target - updateUndoButtons() -} - -export function redo() { - flushHistory() - const h = viewHistory() - if (!h || !h.redo.length) return - const target = h.redo.pop() - if (h.committed) h.undo.push(h.committed) - applyHistoryState(target) - h.committed = target - updateUndoButtons() -} - -export function updateUndoButtons() { - const h = viewHistory() - const u = document.getElementById('btnUndo'), - r = document.getElementById('btnRedo') - const canUndo = !!h && h.undo.length > 0 - const canRedo = !!h && h.redo.length > 0 && !S.historyGestureOpen - u.disabled = !canUndo - r.disabled = !canRedo - u.title = canUndo - ? `Undo (Ctrl+Z), ${h.undo.length} step${h.undo.length === 1 ? '' : 's'} available` - : 'Nothing to undo' - r.title = canRedo - ? `Redo (Ctrl+Shift+Z), ${h.redo.length} step${h.redo.length === 1 ? '' : 's'} available` - : 'Nothing to redo' -} - -// page wiring, run by main.ts in the original order -export function init() { - renderDemoDownloads() - - cy.on('layoutstart', () => { - S.cyLayoutsRunning++ - }) -} diff --git a/frontend/src/directed_stats.ts b/frontend/src/directed_stats.ts deleted file mode 100644 index 1ff1705..0000000 --- a/frontend/src/directed_stats.ts +++ /dev/null @@ -1,184 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { PROFILE_PATH_LIMIT, formatStat } from './wiring' -import { escapeHtml } from './network_state' - -/* ---------- directed statistics (Profiler and Compare) ---------- */ -export const PROFILE_DIRECTED_STATS = [ - { key: 'dirEdges', label: 'Directed edges', desc: 'Distinct source → target connections.' }, - { - key: 'reciprocity', - label: 'Reciprocity', - desc: 'Share of directed edges whose reverse edge also exists.', - }, - { key: 'maxIn', label: 'Maximum in-degree', desc: 'Most incoming neighbors of any node.' }, - { key: 'maxOut', label: 'Maximum out-degree', desc: 'Most outgoing neighbors of any node.' }, - { key: 'sources', label: 'Source nodes', desc: 'Nodes with outgoing but no incoming edges.' }, - { key: 'sinks', label: 'Sink nodes', desc: 'Nodes with incoming but no outgoing edges.' }, - { - key: 'scc', - label: 'Strongly connected components', - desc: 'Groups of nodes that can all reach each other along edge directions.', - }, - { - key: 'largestScc', - label: 'Largest strongly connected component', - desc: 'Nodes in the biggest such group, with its share of all nodes.', - }, - { - key: 'reachable', - label: 'Reachable node pairs', - desc: 'Share of ordered pairs (A, B) where B can be reached from A along edge directions.', - }, - { - key: 'dirAvgPath', - label: 'Average directed path length', - desc: 'Mean shortest path following edge directions, over reachable pairs.', - }, - { - key: 'dirDiameter', - label: 'Directed diameter', - desc: 'Longest shortest path following edge directions.', - }, -] - -// edges: [source, target, directed]; undirected edges can be walked both ways -export function profileDirected(ids, edges) { - const n = ids.length - const index = new Map(ids.map((id, i) => [id, i])) - const out = Array.from({ length: n }, () => new Set()) - const arcKeys = new Set() - edges.forEach(([s, t, d]) => { - const a = index.get(s), - b = index.get(t) - if (a === undefined || b === undefined || a === b) return - out[a].add(b) - if (d) arcKeys.add(a + ',' + b) - else out[b].add(a) - }) - const r = {} - r.dirEdges = arcKeys.size - let recip = 0 - arcKeys.forEach((k) => { - const [a, b] = k.split(',') - if (arcKeys.has(b + ',' + a)) recip++ - }) - r.reciprocity = arcKeys.size ? recip / arcKeys.size : NaN - const indeg = new Int32Array(n) - const adj = out.map((set) => Int32Array.from(set)) - adj.forEach((list) => - list.forEach((w) => { - indeg[w]++ - }) - ) - r.maxIn = n ? Math.max(...indeg) : NaN - r.maxOut = n ? Math.max(...adj.map((l) => l.length)) : NaN - r.sources = 0 - r.sinks = 0 - for (let v = 0; v < n; v++) { - if (indeg[v] === 0 && adj[v].length > 0) r.sources++ - if (adj[v].length === 0 && indeg[v] > 0) r.sinks++ - } - - // strongly connected components (iterative Tarjan) - const idx = new Int32Array(n).fill(-1), - low = new Int32Array(n), - onStack = new Uint8Array(n) - const stack = [], - sccSizes = [] - let counter = 0 - for (let root = 0; root < n; root++) { - if (idx[root] >= 0) continue - const call = [[root, 0]] - idx[root] = low[root] = counter++ - stack.push(root) - onStack[root] = 1 - while (call.length) { - const frame = call[call.length - 1] - const v = frame[0] - if (frame[1] < adj[v].length) { - const w = adj[v][frame[1]++] - if (idx[w] < 0) { - idx[w] = low[w] = counter++ - stack.push(w) - onStack[w] = 1 - call.push([w, 0]) - } else if (onStack[w]) low[v] = Math.min(low[v], idx[w]) - } else { - call.pop() - if (call.length) { - const u = call[call.length - 1][0] - low[u] = Math.min(low[u], low[v]) - } - if (low[v] === idx[v]) { - let size = 0, - w - do { - w = stack.pop() - onStack[w] = 0 - size++ - } while (w !== v) - sccSizes.push(size) - } - } - } - } - r.scc = sccSizes.length - const big = sccSizes.length ? Math.max(...sccSizes) : 0 - r.largestScc = n ? `${big.toLocaleString('en-US')} (${((100 * big) / n).toFixed(1)}%)` : '—' - - // directed shortest paths - if (n <= PROFILE_PATH_LIMIT) { - const dist = new Int32Array(n), - queue = new Int32Array(Math.max(1, n)) - let pairs = 0, - total = 0, - diameter = 0 - for (let s = 0; s < n; s++) { - dist.fill(-1) - dist[s] = 0 - let head = 0, - tail = 0 - queue[tail++] = s - while (head < tail) { - const v = queue[head++] - const nb = adj[v] - for (let k = 0; k < nb.length; k++) { - const w = nb[k] - if (dist[w] < 0) { - dist[w] = dist[v] + 1 - queue[tail++] = w - pairs++ - total += dist[w] - if (dist[w] > diameter) diameter = dist[w] - } - } - } - } - r.reachable = n > 1 ? `${((100 * pairs) / (n * (n - 1))).toFixed(1)}%` : '—' - r.dirAvgPath = pairs ? total / pairs : NaN - r.dirDiameter = pairs ? diameter : NaN - } else { - r.reachable = r.dirAvgPath = r.dirDiameter = 'skipped' - } - return r -} - -export function directedStatsTable(results) { - let html = - '
    ' + - results.map((r) => ``).join('') + - '' - PROFILE_DIRECTED_STATS.forEach((st) => { - html += - `` + - results - .map( - (r) => - `` - ) - .join('') + - '' - }) - return html + '
    Statistic${escapeHtml(r.name)}
    ${escapeHtml(st.label)}${escapeHtml(st.desc)}${escapeHtml(r.directed ? formatStat(r.directed[st.key]) : '—')}
    ' -} diff --git a/frontend/src/enrichment.ts b/frontend/src/enrichment.ts deleted file mode 100644 index 0eb4925..0000000 --- a/frontend/src/enrichment.ts +++ /dev/null @@ -1,3078 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import cytoscape from 'cytoscape' -import { - ARENA3D_LAYER_SPACING, - ARENA3D_LAYER_WIDTH, - ARENA3D_MAX_LAYERS, - arenaSafe, - exportArena3d, - hexColor, - openInArena3d, -} from './contours' -import { - BUNDLE_MAX_EDGES, - activeView, - captureActiveView, - createView, - openInNewView, - renderViewBar, - restoreView, - setControls, - snapshotData, - viewSettings, - views, -} from './profiler' -import { EDGE_TYPES, NODE_PALETTES, colorAtIndex } from './palette' -import { - MAX_NETWORK_NODES, - UNGROUPED, - effectiveGroupsFor, - escapeHtml, - groupLabel, - nextAutoEdgeColor, - nodeFillMode, - sanitizeColor, -} from './network_state' -import { NORMA_CFG } from './config' -import { - NORMA_PARSERS, - addNormaEntry, - downloadText, - fileStem, - libEntry, - libSelection, - listSample, - nextPaint, - normaLibrary, - parseNormaNetwork, - plural, - readTextWithProgress, - renderLibraryLists, - setStatus, - startProgress, -} from './layouts/controls' -import { S } from './state' -import { WEBGL_ACTIVE, cy } from './cy' -import { - applyGroupColorOverrides, - benjaminiHochberg, - groupStatsTsv, - hypergeomUpper, - renderGroupStats, -} from './arena3d' -import { applyGroupsAndColorsInPlace, refreshLibraryView } from './library' -import { applyTheme } from './themes' -import { - applyValueColors, - groupSeparation, - valueColumns, - viewHasValues, -} from './clustering/mapping' -import { - bundleAsync, - exportEdges, - exportNodes, - exportShownOnly, - frLayoutAsync, - shownEdges, - shownNodes, -} from './metrics' -import { compareState } from './label_colors' -import { currentTab, louvain, profileGraph, simpleGraph, switchTab } from './wiring' -import { - dataVersion, - demoToNormaTexts, - setHistoryBaseline, - updateUndoButtons, -} from './demo_downloads' -import { edgeIsDirected } from './export/dialog' -import { generateRandomNetwork } from './sample_data' -import { loadData, refreshAllDerivedUI, sortedByName } from './hulls' -import { net3d, requestRender3d, rgbOf } from './view3d/state' -import { openGroupNetwork } from './group_network' -import { readFileText } from './uploads' -import { resolveStringRoute } from './string/requests' - -/* ---------- enrichment ---------- */ -export const groupAnalysisState = { stats: null, enrichment: null } - -function annotationChoices() { - const out = [{ value: 'view', label: 'Groups of the current view' }] - sortedByName(normaLibrary.annotation, (e) => e.name).forEach((e) => - out.push({ value: e.id, label: e.name }) - ) - return out -} - -// Map term -> Set(member ids) for an annotation choice -function termSetsFor(choice) { - const terms = new Map() - if (choice === 'view') { - cy.nodes().forEach((n) => - (n.data('groups') || []).forEach((g) => { - if (g === UNGROUPED) return - const label = groupLabel(g) - if (!terms.has(label)) terms.set(label, new Set()) - terms.get(label).add(n.id()) - }) - ) - return terms - } - const entry = libEntry('annotation', choice) - if (!entry) return terms - entry.parsed.groups.forEach(({ name, members }) => terms.set(name, new Set(members))) - return terms -} - -export function refreshEnrichmentChoices() { - ;['gaTerms', 'gaSetsFrom'].forEach((id) => { - const sel = document.getElementById(id) - const current = sel.value - sel.innerHTML = '' - annotationChoices().forEach((o) => sel.add(new Option(o.label, o.value))) - if ([...sel.options].some((o) => o.value === current)) sel.value = current - else if (id === 'gaTerms') { - // default: terms from a file other than the view's own grouping - const own = S.currentLibView && S.currentLibView.annotation - const other = normaLibrary.annotation.find((e) => e.id !== own) - if (other) sel.value = other.id - } - }) - const groupsMode = document.getElementById('gaSets').value === 'groups' - document.getElementById('gaSetsFromRow').hidden = !groupsMode - document.getElementById('gaSetsFromLabel').hidden = !groupsMode - const selected = cy.nodes(':selected').length - document.getElementById('gaSelectedNote').textContent = - document.getElementById('gaSets').value === 'selected' - ? selected - ? `${plural(selected, 'node')} selected in the view.` - : 'Select nodes in the 2D or 3D view first (Shift-drag or Shift-click).' - : '' -} - -function runEnrichment() { - const setsMode = document.getElementById('gaSets').value - const termChoice = document.getElementById('gaTerms').value - const bgMode = document.getElementById('gaBackground').value - const minOverlap = Math.max(1, parseInt(document.getElementById('gaMinOverlap').value, 10) || 2) - const fdrMax = parseFloat(document.getElementById('gaFdr').value) || 0.05 - const shown = new Set(shownNodes().map((n) => n.id())) - if (!shown.size) { - setStatus('gaEnrichStatus', [{ level: 'error', text: 'Show a network first.' }]) - return - } - const terms = termSetsFor(termChoice) - if (!terms.size) { - setStatus('gaEnrichStatus', [{ level: 'error', text: 'The chosen annotation has no groups.' }]) - return - } - // universe - let universe - if (bgMode === 'view') universe = shown - else { - universe = new Set() - terms.forEach((set) => set.forEach((id) => universe.add(id))) - shown.forEach((id) => universe.add(id)) - } - // test sets - const tests = [] - if (setsMode === 'selected') { - const sel = cy - .nodes(':selected') - .map((n) => n.id()) - .filter((id) => universe.has(id)) - if (!sel.length) { - setStatus('gaEnrichStatus', [ - { - level: 'error', - text: 'Select nodes in the view first (Shift-drag or Shift-click), or test each group of an annotation.', - }, - ]) - return - } - tests.push({ name: 'Selected nodes', members: new Set(sel) }) - } else { - termSetsFor(document.getElementById('gaSetsFrom').value).forEach((set, name) => { - const members = new Set([...set].filter((id) => universe.has(id))) - if (members.size >= minOverlap) tests.push({ name, members }) - }) - } - const N = universe.size - const termList = [...terms] - .map(([name, set]) => ({ name, set: new Set([...set].filter((id) => universe.has(id))) })) - .filter((t) => t.set.size >= minOverlap) - const rows = [] - let tested = 0 - tests.forEach((t) => { - const n = t.members.size - const cand = termList - .map((term) => { - let k = 0 - term.set.forEach((id) => { - if (t.members.has(id)) k++ - }) - return { - term: term.name, - k, - K: term.set.size, - genes: [...term.set].filter((id) => t.members.has(id)), - } - }) - .filter( - (c) => - c.k >= 1 && - !( - setsMode === 'groups' && - c.term === t.name && - document.getElementById('gaSetsFrom').value === termChoice - ) - ) - const ps = cand.map((c) => hypergeomUpper(c.k, N, c.K, n)) - const qs = benjaminiHochberg(ps) - tested += cand.length - cand.forEach((c, i) => { - if (c.k < minOverlap || qs[i] > fdrMax) return - rows.push({ - set: t.name, - n, - term: c.term, - k: c.k, - K: c.K, - N, - fold: c.k / n / (c.K / N), - p: ps[i], - fdr: qs[i], - genes: c.genes, - }) - }) - }) - rows.sort((a, b) => a.fdr - b.fdr || a.p - b.p) - groupAnalysisState.enrichment = { rows, tests: tests.length, tested, N, termChoice, setsMode } - renderEnrichment() - setStatus('gaEnrichStatus', [ - { - level: rows.length ? 'ok' : 'warn', - text: `Tested ${plural(tested, 'term–set pair')} in ${plural(tests.length, 'set')} against a background of ${plural(N, 'node')}: ${rows.length ? `${plural(rows.length, 'enriched term')} with FDR ≤ ${fdrMax}` : `no term reaches FDR ≤ ${fdrMax}`}.`, - }, - ]) - document.getElementById('btnGaEnrichTsv').disabled = !rows.length -} - -function renderEnrichment() { - const st = groupAnalysisState.enrichment - const root = document.getElementById('gaEnrichResults') - if (!st || !st.rows.length) { - root.innerHTML = '' - return - } - const fp = (v) => (v < 1e-3 ? v.toExponential(2) : v.toFixed(4)) - const shown = st.rows.slice(0, 300) - root.innerHTML = `
    - ${st.setsMode === 'groups' ? '' : ''} - ${shown - .map( - (r, i) => ` - ${st.setsMode === 'groups' ? `` : ''} - - - ` - ) - .join('')} -
    SetTermIn setTerm sizeFoldp-valueFDR
    ${escapeHtml(r.set)}${escapeHtml(r.term)}${r.k} / ${r.n}${r.K} / ${r.N}${r.fold.toFixed(2)}${fp(r.p)}${fp(r.fdr)}
    ${st.rows.length > shown.length ? `

    Showing the first ${shown.length} of ${st.rows.length}; the download has all.

    ` : ''}` - root.querySelectorAll('.ga-show').forEach((b) => - b.addEventListener('click', () => { - const r = shown[+b.dataset.row] - cy.batch(() => { - cy.$(':selected').unselect() - r.genes.forEach((id) => cy.$id(id).select()) - }) - switchTab('network') - const sel = cy.nodes(':selected') - if (sel.length) cy.animate({ fit: { eles: sel, padding: 80 } }, { duration: 300 }) - }) - ) -} - -function enrichmentTsv() { - const st = groupAnalysisState.enrichment - if (!st) return - const lines = [ - [ - 'Set', - 'Set size', - 'Term', - 'Overlap', - 'Term size', - 'Background', - 'Fold enrichment', - 'p-value', - 'FDR (BH)', - 'Nodes', - ].join('\t'), - ...st.rows.map((r) => - [ - r.set, - r.n, - r.term, - r.k, - r.K, - r.N, - r.fold.toFixed(4), - r.p.toExponential(4), - r.fdr.toExponential(4), - r.genes.join(','), - ].join('\t') - ), - ] - downloadText('enrichment.tsv', lines.join('\n') + '\n') -} - -/* ============================================================ - COMPARISON AS A NETWORK - The compared networks merged into one view: each edge's channel says - which networks contain it (A only, B only, A + B, ...), and each node's - group says which networks contain the node. - ============================================================ */ -function patternLabel(mask, nets) { - const letters = nets.map((_, i) => String.fromCharCode(65 + i)).filter((_, i) => mask & (1 << i)) - if (letters.length === nets.length) return nets.length === 2 ? 'Shared' : 'In all' - return letters.length === 1 ? `${letters[0]} only` : letters.join(' + ') -} - -function openComparisonNetwork() { - const nets = compareState.results - if (!nets || nets.length < 2) return - const nodeMask = new Map() - nets.forEach((net, i) => - net.ids.forEach((id) => nodeMask.set(id, (nodeMask.get(id) || 0) | (1 << i))) - ) - const edgeMask = new Map() - nets.forEach((net, i) => - net.edgeSet.forEach((key) => edgeMask.set(key, (edgeMask.get(key) || 0) | (1 << i))) - ) - const full = (1 << nets.length) - 1 - const colorFor = (mask) => { - if (mask === full) return '#9ca3af' - const bits = nets.map((_, i) => i).filter((i) => mask & (1 << i)) - if (bits.length === 1) return nets[bits[0]].color - return colorAtIndex(NODE_PALETTES.vivid, mask + 3) - } - const edgeColors = {}, - nodeColors = {} - const edges = [...edgeMask].map(([key, mask], i) => { - const [a, b, dir] = key.split('\t') - const type = patternLabel(mask, nets) - edgeColors[type] = colorFor(mask) - return { - id: 'c' + i, - source: a, - target: b, - type, - directed: dir === 'directed', - 'in networks': type, - } - }) - const nodes = [...nodeMask].map(([id, mask]) => { - const g = `Nodes: ${patternLabel(mask, nets)}` - nodeColors[g] = colorFor(mask) - return { id, groups: [g] } - }) - // groups and channels in a readable order: single networks first, shared last - const order = (masks) => - [...new Set(masks)].sort( - (x, y) => (x === full) - (y === full) || popcount(x) - popcount(y) || x - y - ) - const popcount = (x) => { - let c = 0 - while (x) { - c += x & 1 - x >>= 1 - } - return c - } - const data = { - nodes, - edges, - nodeColors, - edgeColors, - groupOrder: order([...nodeMask.values()]).map((m) => `Nodes: ${patternLabel(m, nets)}`), - groupAttrs: Object.fromEntries( - nets.map((net, i) => [ - `Nodes: ${String.fromCharCode(65 + i)} only`, - { description: `Only in ${net.name}` }, - ]) - ), - config: { - layoutSelect: 'fr', - edgeCurveStyle: 'bezier', - legendShow: true, - legendGroups: true, - legendChannels: true, - legendTitle: 'Network comparison', - nodeFillSelect: 'groups', - }, - legendExtra: [ - { - title: 'Networks', - items: nets.map((net, i) => ({ - kind: 'glyph', - label: `${String.fromCharCode(65 + i)}: ${net.name}`, - color: net.color, - })), - }, - ], - } - const title = nets.map((n, i) => `${String.fromCharCode(65 + i)}`).join(' vs ') - openInNewView(`Comparison ${title}: ${nets.map((n) => n.name).join(' / ')}`.slice(0, 80), () => { - loadData(data) - applyGroupColorOverrides(data.nodeColors) - }) - switchTab('network') - const counts = order([...edgeMask.values()]).map( - (m) => `${patternLabel(m, nets)}: ${[...edgeMask.values()].filter((x) => x === m).length}` - ) - setStatus('cmpStatus', [ - { - level: 'ok', - text: `Opened the merged network with ${plural(nodes.length, 'node')} and ${plural(edges.length, 'edge')} (${counts.join(', ')}). Tick channels in the Display tab to show or hide each part.`, - }, - ]) -} - -/* ============================================================ - LOCAL EXPLORATION - Neighbourhood of a node (or the selected nodes) and all shortest paths - between two selected nodes, each opened as a new view that keeps the - nodes' positions, groups, colors and attributes. - ============================================================ */ -function adjacencyForPaths() { - // follows edge directions where edges are directed - const out = new Map(), - inn = new Map() - const add = (m, a, b) => { - if (!m.has(a)) m.set(a, new Set()) - m.get(a).add(b) - } - shownEdges(true).forEach((e) => { - const s = e.data('source'), - t = e.data('target') - if (s === t) return - add(out, s, t) - add(inn, t, s) - if (!edgeIsDirected(e)) { - add(out, t, s) - add(inn, s, t) - } - }) - return { out, inn } -} - -function bfsDistances(start, adj, limit = Infinity) { - const dist = new Map([[start, 0]]) - const q = [start] - for (let h = 0; h < q.length; h++) { - const v = q[h] - const d = dist.get(v) - if (d >= limit) continue - ;(adj.get(v) || []).forEach((w) => { - if (!dist.has(w)) { - dist.set(w, d + 1) - q.push(w) - } - }) - } - return dist -} - -function openSubnetworkView(name, keepIds, marks, keepEdge) { - const data = snapshotData() - const keep = new Set(keepIds) - data.nodes = data.nodes - .filter((n) => keep.has(n.id)) - .map((n) => (marks.has(n.id) ? { ...n, role: marks.get(n.id) } : n)) - const shownEdgeIds = new Set(shownEdges(true).map((e) => e.id())) - data.edges = data.edges.filter( - (e) => - shownEdgeIds.has(e.id) && - keep.has(e.source) && - keep.has(e.target) && - (!keepEdge || keepEdge(e)) - ) - const used = new Set(data.nodes.flatMap((n) => n.groups)) - data.groupOrder = data.groupOrder.filter((g) => used.has(g)) - const positions = {} - cy.nodes().forEach((n) => { - if (keep.has(n.id())) positions[n.id()] = { ...n.position() } - }) - const config = viewSettings() - openInNewView(name, () => { - setControls(config) - loadData(data, { positions }) - refreshAllDerivedUI() - }) - switchTab(net3dActiveTab()) - cy.batch(() => - cy.nodes().forEach((n) => { - if (marks.has(n.id())) n.select() - }) - ) - cy.fit(undefined, 60) -} - -function net3dActiveTab() { - return net3d.active ? 'network3d' : 'network' -} - -function openNeighbourhood(ids, steps) { - const { out, inn } = adjacencyForPaths() - // neighbours in either direction - const both = new Map() - ;[out, inn].forEach((m) => - m.forEach((set, k) => { - if (!both.has(k)) both.set(k, new Set()) - set.forEach((v) => both.get(k).add(v)) - }) - ) - const keep = new Set() - ids.forEach((id) => bfsDistances(id, both, steps).forEach((_, v) => keep.add(v))) - const marks = new Map(ids.map((id) => [id, 'center'])) - const label = ids.length === 1 ? ids[0] : `${ids.length} nodes` - openSubnetworkView(`${label}: ${steps}-step neighbourhood`, [...keep], marks) - toast(`Opened the ${steps}-step neighbourhood of ${label}: ${plural(keep.size, 'node')}.`) -} - -function openShortestPaths(a, b) { - const { out, inn } = adjacencyForPaths() - const ds = bfsDistances(a, out), - dt = bfsDistances(b, inn) - if (!ds.has(b)) { - toast(`No path leads from ${a} to ${b} in the shown part of the network.`, 'warn') - return - } - const d = ds.get(b) - const keep = [...ds.keys()].filter((v) => dt.has(v) && ds.get(v) + dt.get(v) === d) - const keepSet = new Set(keep) - // only edges that lie on a shortest path - const onPath = (e) => { - const s = e.source, - t = e.target - const fwd = ds.has(s) && dt.has(t) && ds.get(s) + 1 + dt.get(t) === d - const rev = !e.directed && ds.has(t) && dt.has(s) && ds.get(t) + 1 + dt.get(s) === d - return keepSet.has(s) && keepSet.has(t) && (fwd || rev) - } - const marks = new Map([ - [a, 'source'], - [b, 'target'], - ]) - openSubnetworkView(`Shortest paths ${a} → ${b}`, keep, marks, onPath) - const count = countShortestPaths(a, b, out, ds, d) - toast( - `Opened ${plural(count, 'shortest path')} of length ${d} from ${a} to ${b} (${plural(keep.length, 'node')}).` - ) -} - -function countShortestPaths(a, b, out, ds, d) { - const ways = new Map([[a, 1]]) - const layers = [...ds].filter(([, x]) => x <= d).sort((x, y) => x[1] - y[1]) - layers.forEach(([v, x]) => { - const w = ways.get(v) || 0 - ;(out.get(v) || []).forEach((u) => { - if (ds.get(u) === x + 1) ways.set(u, (ways.get(u) || 0) + w) - }) - }) - return ways.get(b) || 0 -} - -export function toast(text, level = 'ok') { - let el = document.getElementById('toast') - if (!el) { - el = document.createElement('div') - el.id = 'toast' - el.setAttribute('role', 'status') - el.setAttribute('aria-live', 'polite') - document.getElementById('canvas').appendChild(el) - } - el.className = `toast ${level}` - el.textContent = text - el.hidden = false - clearTimeout(toast.timer) - toast.timer = setTimeout(() => { - el.hidden = true - }, 6000) -} - -// remembers the order in which nodes were selected (paths go first -> second) -const selectionOrder = [] - -/* ============================================================ - TIME SERIES AND CONDITIONS - With several numeric columns (time points, conditions) the view can - step through them, by hand or as an animation, with the layout fixed - and, by default, one color scale for all steps. Columns of other - numeric expression files can be added as further steps. - ============================================================ */ -const frameState = { playing: false, timer: null } - -function frameColumns() { - return valueColumns() -} - -function numericLibraryEntries() { - return normaLibrary.colors.filter((e) => e.parsed.numeric) -} - -export function updateFrameControls() { - const box = document.getElementById('valueFrames') - if (!box) return - const cols = viewHasValues() ? frameColumns() : [] - const otherFiles = numericLibraryEntries().length - box.hidden = !(cols.length > 1 || (cols.length && otherFiles > 1)) - const slider = document.getElementById('frameSlider') - slider.max = Math.max(0, cols.length - 1) - const i = Math.max(0, cols.indexOf(document.getElementById('valueColumn').value)) - slider.value = i - document.getElementById('frameLabel').textContent = cols.length - ? `Step ${i + 1} of ${cols.length}: ${cols[i]}` - : '' - document.getElementById('btnFramePlay').textContent = frameState.playing ? '❚❚ Pause' : '▶ Play' - const badge = document.getElementById('frameBadge') - badge.hidden = - box.hidden || - (nodeFillMode() !== 'values' && document.getElementById('sizeMetric').value !== 'value') - badge.textContent = cols.length ? `${cols[i]} · ${i + 1} / ${cols.length}` : '' -} - -function showFrame(i) { - const cols = frameColumns() - if (!cols.length) return - const k = ((i % cols.length) + cols.length) % cols.length - document.getElementById('valueColumn').value = cols[k] - applyValueColors() - if (net3d.active) requestRender3d() -} - -function stepFrame(delta) { - const cols = frameColumns() - showFrame(Math.max(0, cols.indexOf(document.getElementById('valueColumn').value)) + delta) -} - -function toggleFramePlay() { - frameState.playing = !frameState.playing - clearInterval(frameState.timer) - if (frameState.playing) { - if (nodeFillMode() !== 'values') { - document.getElementById('nodeFillSelect').value = 'values' - document - .getElementById('nodeFillSelect') - .dispatchEvent(new Event('change', { bubbles: true })) - } - const ms = parseInt(document.getElementById('frameSpeed').value, 10) || 1000 - frameState.timer = setInterval(() => { - if (!cy.nodes().length || !viewHasValues()) { - toggleFramePlay() - return - } - stepFrame(1) - }, ms) - } - updateFrameControls() -} - -export function stopFramePlay() { - if (frameState.playing) toggleFramePlay() -} - -// Adds the columns of every numeric expression file in Files as steps. -function addFramesFromFiles() { - const entries = numericLibraryEntries() - if (!entries.length) return - const nodeIds = new Set(cy.nodes().map((n) => n.id())) - const existing = new Set(frameColumns()) - const added = [] - cy.batch(() => { - entries.forEach((entry) => { - entry.parsed.columns.forEach((col) => { - const name = entry.parsed.columns.length === 1 ? entry.name : `${entry.name}: ${col}` - // the view's own numeric file is already there under its plain column names - const ownFile = S.currentLibView && S.currentLibView.colors === entry.id - if (existing.has(name) || (ownFile && existing.has(col))) return - existing.add(name) - added.push(name) - cy.nodes().forEach((n) => { - const row = entry.parsed.values.get(n.id()) - const vals = { ...(n.data('values') || {}) } - vals[name] = row ? row[col] : null - n.data('values', vals) - }) - }) - }) - }) - applyValueColors() - setStatus('frameStatus', [ - { - level: added.length ? 'ok' : 'warn', - text: added.length - ? `Added ${plural(added.length, 'step')}: ${listSample(added)}.` - : 'All numeric files are already steps.', - }, - ]) - updateFrameControls() - void nodeIds -} - -/* ============================================================ - EXPORT TO OTHER TOOLS - GraphML (yEd, Cytoscape, igraph, NetworkX), GEXF 1.3 with colors, - sizes and positions (Gephi), SIF (Cytoscape) and Cytoscape JSON - (.cyjs, Cytoscape desktop and Cytoscape.js). - ============================================================ */ -function xmlEsc(v) { - return String(v).replace( - /[&<>"']/g, - (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[c] - ) -} - -function exportModel() { - const nodes = exportNodes() - const idSet = new Set(nodes.map((n) => n.id())) - const edges = exportEdges().filter( - (e) => idSet.has(e.data('source')) && idSet.has(e.data('target')) - ) - const nodeAttrKeys = new Set(), - edgeAttrKeys = new Set(), - valueKeys = new Set() - nodes.forEach((n) => { - Object.keys(n.data('attrs') || {}).forEach((k) => nodeAttrKeys.add(k)) - Object.keys(n.data('values') || {}).forEach((k) => valueKeys.add(k)) - }) - edges.forEach((e) => Object.keys(e.data('attrs') || {}).forEach((k) => edgeAttrKeys.add(k))) - const kind = (list, key, get) => - list.every((x) => { - const v = get(x) - return v === undefined || v === null || typeof v === 'number' - }) - ? 'double' - : 'string' - return { - nodes, - edges, - nodeAttrs: [...nodeAttrKeys].map((k) => ({ - key: k, - type: kind(nodes, k, (n) => (n.data('attrs') || {})[k]), - })), - edgeAttrs: [...edgeAttrKeys].map((k) => ({ - key: k, - type: kind(edges, k, (e) => (e.data('attrs') || {})[k]), - })), - valueKeys: [...valueKeys], - weighted: edges.some((e) => typeof e.data('weight') === 'number'), - anyDirected: edges.some((e) => edgeIsDirected(e)), - } -} - -function nodeGroupsText(n) { - return effectiveGroupsFor(n) - .filter((g) => g !== UNGROUPED) - .map(groupLabel) - .join(';') -} - -function attrText(v) { - return v === null || v === undefined ? '' : typeof v === 'object' ? JSON.stringify(v) : String(v) -} - -function channelLabel(t) { - return (EDGE_TYPES[t] || { label: t }).label -} - -function toGraphML() { - const m = exportModel() - const keys = [ - ['n_label', 'node', 'label', 'string'], - ['n_groups', 'node', 'groups', 'string'], - ['n_color', 'node', 'color', 'string'], - ['n_size', 'node', 'size', 'double'], - ['n_x', 'node', 'x', 'double'], - ['n_y', 'node', 'y', 'double'], - ...m.valueKeys.map((k, i) => [`n_v${i}`, 'node', `value: ${k}`, 'double']), - ...m.nodeAttrs.map((a, i) => [`n_a${i}`, 'node', a.key, a.type]), - ['e_channel', 'edge', 'channel', 'string'], - ['e_color', 'edge', 'color', 'string'], - ...(m.weighted ? [['e_weight', 'edge', 'weight', 'double']] : []), - ...m.edgeAttrs.map((a, i) => [`e_a${i}`, 'edge', a.key, a.type]), - ] - const lines = [ - '', - '', - ' ', - ...keys.map( - ([id, forWhat, name, type]) => - ` ` - ), - ` `, - ] - const d = (k, v) => - v === '' || v === null || v === undefined || (typeof v === 'number' && !Number.isFinite(v)) - ? '' - : `${xmlEsc(v)}` - m.nodes.forEach((n) => { - const p = n.position() - const vals = n.data('values') || {} - const attrs = n.data('attrs') || {} - lines.push( - ` ` + - d('n_label', n.id()) + - d('n_groups', nodeGroupsText(n)) + - d('n_color', hexColor(n.style('background-color'))) + - d('n_size', Math.round(n.width() * 100) / 100) + - d('n_x', Math.round(p.x * 100) / 100) + - d('n_y', Math.round(p.y * 100) / 100) + - m.valueKeys.map((k, i) => d(`n_v${i}`, vals[k])).join('') + - m.nodeAttrs.map((a, i) => d(`n_a${i}`, attrText(attrs[a.key]))).join('') + - '' - ) - }) - m.edges.forEach((e, i) => { - const attrs = e.data('attrs') || {} - lines.push( - ` ` + - d('e_channel', channelLabel(e.data('type'))) + - d('e_color', hexColor(e.style('line-color'))) + - (m.weighted ? d('e_weight', e.data('weight')) : '') + - m.edgeAttrs.map((a, k) => d(`e_a${k}`, attrText(attrs[a.key]))).join('') + - '' - ) - }) - lines.push(' ', '') - return lines.join('\n') + '\n' -} - -function toGEXF() { - const m = exportModel() - const nodeAttrDefs = [ - ['groups', 'string'], - ...m.valueKeys.map((k) => [`value: ${k}`, 'double']), - ...m.nodeAttrs.map((a) => [a.key, a.type]), - ] - const edgeAttrDefs = [['channel', 'string'], ...m.edgeAttrs.map((a) => [a.key, a.type])] - const lines = [ - '', - '', - ` NORMA 3.0${xmlEsc((activeView() || {}).name || 'NORMA network')}`, - ` `, - ' ', - ...nodeAttrDefs.map( - ([k, t], i) => ` ` - ), - ' ', - ' ', - ...edgeAttrDefs.map( - ([k, t], i) => ` ` - ), - ' ', - ' ', - ] - const att = (i, v) => - v === '' || v === null || v === undefined || (typeof v === 'number' && !Number.isFinite(v)) - ? '' - : `` - m.nodes.forEach((n) => { - const [r, g, b] = rgbOf(n.style('background-color')) - const p = n.position() - const vals = n.data('values') || {}, - attrs = n.data('attrs') || {} - const values = [ - nodeGroupsText(n), - ...m.valueKeys.map((k) => vals[k]), - ...m.nodeAttrs.map((a) => attrText(attrs[a.key])), - ] - lines.push( - ` ${values.map((v, i) => att(i, v)).join('')}` + - `` - ) - }) - lines.push(' ', ' ') - m.edges.forEach((e, i) => { - const [r, g, b] = rgbOf(e.style('line-color')) - const attrs = e.data('attrs') || {} - const values = [channelLabel(e.data('type')), ...m.edgeAttrs.map((a) => attrText(attrs[a.key]))] - const w = typeof e.data('weight') === 'number' ? ` weight="${e.data('weight')}"` : '' - lines.push( - ` ` + - `${values.map((v, k) => att(k, v)).join('')}` - ) - }) - lines.push(' ', ' ', '') - return lines.join('\n') + '\n' -} - -function toSIF() { - const m = exportModel() - const lines = [] - const connected = new Set() - const clean = (s) => String(s).replace(/[\t\r\n]+/g, ' ') - m.edges.forEach((e) => { - connected.add(e.data('source')) - connected.add(e.data('target')) - lines.push( - [ - clean(e.data('source')), - clean(channelLabel(e.data('type'))).replace(/\s+/g, '_') || 'pp', - clean(e.data('target')), - ].join('\t') - ) - }) - m.nodes.forEach((n) => { - if (!connected.has(n.id())) lines.push(clean(n.id())) - }) - return lines.join('\n') + '\n' -} - -function toCyJS() { - const m = exportModel() - const v = activeView() - const json = { - format_version: '1.0', - generated_by: 'NORMA 3.0', - target_cytoscapejs_version: '~3.0', - data: { - name: v ? v.name : 'NORMA network', - shared_name: v ? v.name : 'NORMA network', - selected: true, - }, - elements: { - nodes: m.nodes.map((n) => { - const p = n.position() - return { - data: { - id: n.id(), - name: n.id(), - shared_name: n.id(), - groups: nodeGroupsText(n), - color: hexColor(n.style('background-color')), - size: Math.round(n.width() * 100) / 100, - ...Object.fromEntries( - Object.entries(n.data('values') || {}).map(([k, x]) => [`value: ${k}`, x]) - ), - ...(n.data('attrs') || {}), - }, - position: { x: Math.round(p.x * 100) / 100, y: Math.round(p.y * 100) / 100 }, - } - }), - edges: m.edges.map((e, i) => ({ - data: { - id: `e${i}`, - source: e.data('source'), - target: e.data('target'), - interaction: channelLabel(e.data('type')), - shared_interaction: channelLabel(e.data('type')), - name: `${e.data('source')} (${channelLabel(e.data('type'))}) ${e.data('target')}`, - directed: edgeIsDirected(e), - color: hexColor(e.style('line-color')), - ...(typeof e.data('weight') === 'number' ? { weight: e.data('weight') } : {}), - ...(e.data('attrs') || {}), - }, - })), - }, - } - return JSON.stringify(json, null, 1) -} - -function exportOtherFormat(kind) { - if (!cy.nodes().length) { - setStatus('otherExportStatus', [{ level: 'error', text: 'Show a network first.' }]) - return - } - const v = activeView() - const stem = v ? fileStem(v.name) : 'network' - const spec = { - graphml: ['GraphML', 'graphml', toGraphML], - gexf: ['GEXF', 'gexf', toGEXF], - sif: ['SIF', 'sif', toSIF], - cyjs: ['Cytoscape JSON', 'cyjs', toCyJS], - }[kind] - const text = spec[2]() - downloadText(`${stem}.${spec[1]}`, text) - const m = exportModel() - setStatus('otherExportStatus', [ - { - level: 'ok', - text: `Saved ${stem}.${spec[1]} (${spec[0]}): ${plural(m.nodes.length, 'node')}, ${plural(m.edges.length, 'edge')}${exportShownOnly() ? ', ticked groups and channels only' : ''}.`, - }, - ]) -} - -/* ============================================================ - SESSIONS - One file with every view (data, positions, settings, 3D camera) and - every file in Files (including STRING extras), to continue later. - ============================================================ */ -const SESSION_FORMAT = 'norma3-session' - -function sessionObject() { - captureActiveView() - const lib = {} - Object.keys(normaLibrary).forEach((kind) => { - lib[kind] = normaLibrary[kind].map((e) => { - const { parsed, ...rest } = e - return rest - }) - }) - return { - format: SESSION_FORMAT, - version: 1, - savedAt: new Date().toISOString(), - app: 'NORMA 3.0', - activeViewId: S.activeViewId, - theme: document.getElementById('themeSelect').value, - views: views.map((v) => ({ - id: v.id, - name: v.name, - autoName: v.autoName, - data: v.data, - selection: v.selection, - state: v.state, - ...(v.needsRefresh ? { needsRefresh: v.needsRefresh } : {}), - })), - library: lib, - edgeTypes: JSON.parse(JSON.stringify(EDGE_TYPES)), - } -} - -function saveSession() { - const s = sessionObject() - const stamp = new Date().toISOString().slice(0, 16).replace(/[:T]/g, '-') - downloadText(`norma-session-${stamp}.json`, JSON.stringify(s)) - setStatus('sessionSaveStatus', [ - { - level: 'ok', - text: `Saved the session: ${plural(s.views.length, 'view')} and ${plural( - Object.values(s.library).reduce((n, l) => n + l.length, 0), - 'file' - )}.`, - }, - ]) -} - -export function isSessionObject(obj) { - return obj && obj.format === SESSION_FORMAT && Array.isArray(obj.views) -} - -export function loadSession(obj) { - if (!isSessionObject(obj)) throw new Error('This is not a NORMA session file.') - stopFramePlay() - // files - const kinds = Object.keys(normaLibrary) - const rebuilt = {} - let maxSeq = S.normaEntrySeq - kinds.forEach((kind) => { - rebuilt[kind] = [] - ;((obj.library && obj.library[kind]) || []).forEach((saved) => { - const parsed = NORMA_PARSERS[kind](saved.text, saved.options || {}) - rebuilt[kind].push({ ...saved, parsed }) - const n = parseInt(String(saved.id).replace(/\D/g, ''), 10) - if (Number.isFinite(n)) maxSeq = Math.max(maxSeq, n) - }) - }) - kinds.forEach((kind) => { - normaLibrary[kind].length = 0 - normaLibrary[kind].push(...rebuilt[kind]) - }) - S.normaEntrySeq = maxSeq - if (obj.edgeTypes) - Object.entries(obj.edgeTypes).forEach(([k, t]) => { - const safe = { - ...t, - color: - sanitizeColor(t && t.color) || - (EDGE_TYPES[k] && EDGE_TYPES[k].color) || - nextAutoEdgeColor(), - } - if (!EDGE_TYPES[k]) EDGE_TYPES[k] = safe - else Object.assign(EDGE_TYPES[k], safe) - }) - // views - views.length = 0 - let maxView = S.viewSeq - obj.views.forEach((v) => { - views.push({ - id: v.id, - name: v.name, - autoName: v.autoName, - data: v.data, - selection: v.selection || { networks: [], annotation: '', colors: '' }, - state: v.state || { config: { ...S.DEFAULT_VIEW_CONFIG } }, - needsRefresh: v.needsRefresh || null, - }) - const n = parseInt(String(v.id).replace(/\D/g, ''), 10) - if (Number.isFinite(n)) maxView = Math.max(maxView, n) - }) - S.viewSeq = maxView - if (!views.length) { - S.activeViewId = null - createView('Untitled view') - } else { - S.activeViewId = views.some((v) => v.id === obj.activeViewId) ? obj.activeViewId : views[0].id - const v = activeView() - libSelection.networks = new Set(v.selection.networks || []) - libSelection.annotation = v.selection.annotation || '' - libSelection.colors = v.selection.colors || '' - S.historySuspended++ - try { - restoreView(v) - } finally { - S.historySuspended-- - } - S.dataCache = { version: dataVersion, data: v.data } - } - if (obj.theme) { - document.getElementById('themeSelect').value = obj.theme - applyTheme(obj.theme) - } - renderLibraryLists() - setHistoryBaseline() - renderViewBar() - updateUndoButtons() - return { views: views.length, files: kinds.reduce((n, k) => n + normaLibrary[k].length, 0) } -} - -async function openSessionFile(file) { - try { - const obj = JSON.parse(await readFileText(file)) - const r = loadSession(obj) - setStatus('sessionStatus', [ - { - level: 'ok', - text: `Opened the session "${file.name}": ${plural(r.views, 'view')} and ${plural(r.files, 'file')}.`, - }, - ]) - } catch (err) { - setStatus('sessionStatus', [ - { level: 'error', text: `The session couldn't be opened: ${err.message}` }, - ]) - } -} - -/* ============================================================ - WEBGL DRAWING (experimental) - Cytoscape.js can draw with WebGL, which is much faster on large - networks. It is chosen before the network canvas is created, so the - setting takes effect after reloading the page. - ============================================================ */ -export function webglPreference() { - try { - const q = new URLSearchParams(location.search).get('webgl') - if (q !== null) return q === '1' || q === 'true' - return localStorage.getItem('norma3-webgl') === '1' - } catch (e) { - return false - } -} - -/* ============================================================ - RUNTIME TABLE (Network Profiler) - Times the main steps on random networks of growing size, for a - supplementary table: reading the network file, building the network, - weighted layout, edge bundling, profiling, Louvain and the group - separation score. Nothing on screen changes. - ============================================================ */ -const RUNTIME_SIZES = [100, 500, 1000, 2500, 5000, 10000] - -const runtimeState = { rows: [], running: false, cancel: false } - -async function runRuntimeTable() { - if (runtimeState.running) { - runtimeState.cancel = true - return - } - const btn = document.getElementById('btnRuntime') - const sizes = RUNTIME_SIZES.filter( - (n) => n <= (parseInt(document.getElementById('runtimeMax').value, 10) || 5000) - ) - runtimeState.running = true - runtimeState.cancel = false - btn.textContent = 'Stop' - runtimeState.rows = [] - const time = async (fn) => { - const t = performance.now() - const r = await fn() - return [performance.now() - t, r] - } - try { - // larger networks take much longer: weigh each size by n^1.5 - const weightOf = (n) => Math.pow(n, 1.5) - const totalWeight = sizes.reduce((a, n) => a + weightOf(n), 0) - let doneWeight = 0 - for (const n of sizes) { - if (runtimeState.cancel) break - const text = `Timing a network of ${n.toLocaleString()} nodes…` - const show = (f) => - setStatus('runtimeStatus', [ - { level: 'busy', text, progress: (doneWeight + weightOf(n) * f) / totalWeight }, - ]) - show(0) - await nextPaint() - const demo = generateRandomNetwork(n, { seed: n + 3 }) - const texts = demoToNormaTexts(demo) - const row = { nodes: n } - const [tParse, parsed] = await time(() => parseNormaNetwork(texts.network, {})) - row.edges = parsed.edges.length - row.parse = tParse - const [tBuild, headless] = await time(() => - cytoscape({ - headless: true, - styleEnabled: false, - elements: [ - ...demo.nodes.map((x) => ({ data: { id: x.id } })), - ...demo.edges.map((e, i) => ({ - data: { id: 'r' + i, source: e.source, target: e.target }, - })), - ], - }) - ) - row.build = tBuild - headless.destroy() - const edges = demo.edges.map((e) => ({ source: e.source, target: e.target, weight: 1 })) - const ids = demo.nodes.map((x) => x.id) - const [tLayout, pos] = await time(() => frLayoutAsync(ids, edges, (f) => show(0.1 + 0.4 * f))) - row.layout = tLayout - if (runtimeState.cancel) break - const segs = demo.edges.map((e) => ({ - sx: pos[e.source].x * 40, - sy: pos[e.source].y * 40, - tx: pos[e.target].x * 40, - ty: pos[e.target].y * 40, - })) - if (segs.length <= BUNDLE_MAX_EDGES) { - show(0.5) - const [tBundle] = await time(() => - bundleAsync(segs, { threshold: 0.6, iterations: 60 }, (f) => show(0.5 + 0.4 * f)) - ) - row.bundle = tBundle - } else row.bundle = NaN - show(0.9) - await nextPaint() - const g = simpleGraph( - ids, - demo.edges.map((e) => [e.source, e.target]) - ) - const [tProfile] = await time(() => profileGraph(g)) - row.profile = tProfile - const [tLouvain] = await time(() => louvain(g)) - row.louvain = tLouvain - const groupsOf = Object.fromEntries(demo.nodes.map((x) => [x.id, x.groups || []])) - const [tSep] = await time(() => groupSeparation(pos, groupsOf)) - row.separation = tSep - runtimeState.rows.push(row) - renderRuntimeTable() - doneWeight += weightOf(n) - await new Promise((r) => setTimeout(r, 30)) - } - setStatus('runtimeStatus', [ - { - level: runtimeState.cancel ? 'warn' : 'ok', - text: `${runtimeState.cancel ? 'Stopped' : 'Done'}: timed ${plural(runtimeState.rows.length, 'network size')} in this browser (${navigator.hardwareConcurrency || '?'} logical processors). Rendering time depends on the screen and is not included.`, - }, - ]) - document.getElementById('btnRuntimeTsv').disabled = !runtimeState.rows.length - } finally { - runtimeState.running = false - btn.textContent = 'Time the main steps' - } -} - -const RUNTIME_COLUMNS = [ - ['parse', 'Read file'], - ['build', 'Build network'], - ['layout', 'Weighted layout'], - ['bundle', 'Edge bundling'], - ['profile', 'Profile statistics'], - ['louvain', 'Louvain'], - ['separation', 'Separation score'], -] - -function renderRuntimeTable() { - const root = document.getElementById('runtimeResults') - const fmt = (v) => - !Number.isFinite(v) ? '—' : v < 1000 ? `${Math.round(v)} ms` : `${(v / 1000).toFixed(2)} s` - root.innerHTML = `
    - ${RUNTIME_COLUMNS.map(([, l]) => ``).join('')} - ${runtimeState.rows.map((r) => `${RUNTIME_COLUMNS.map(([k]) => ``).join('')}`).join('')} -
    NodesEdges${l}
    ${r.nodes.toLocaleString()}${r.edges.toLocaleString()}${fmt(r[k])}
    ` -} - -function runtimeTsv() { - const lines = [ - ['Nodes', 'Edges', ...RUNTIME_COLUMNS.map(([, l]) => `${l} (ms)`)].join('\t'), - ...runtimeState.rows.map((r) => - [ - r.nodes, - r.edges, - ...RUNTIME_COLUMNS.map(([k]) => (Number.isFinite(r[k]) ? r[k].toFixed(1) : '')), - ].join('\t') - ), - ] - lines.push( - `# ${navigator.userAgent}; ${navigator.hardwareConcurrency || '?'} logical processors; WebGL drawing ${WEBGL_ACTIVE ? 'on' : 'off'}` - ) - downloadText('norma-runtime.tsv', lines.join('\n') + '\n') -} - -/* ---------- Network Comparison -> Arena3D ---------- - Each compared network is one layer holding its own nodes and edges. - Every node keeps the same position in every layer (one layout of all - networks together), so layers line up. Between layers, the common - edges (and, if chosen, the copies of common nodes) link the layers: - an edge present in networks A and B also runs from its source in - layer A to its target in layer B. */ -export async function buildCompareArena3dModel() { - const nets = compareState.results - if (!nets || nets.length < 2) throw new Error('Compare at least two networks first.') - if (nets.length > ARENA3D_MAX_LAYERS) - throw new Error(`Arena3D takes up to ${ARENA3D_MAX_LAYERS} layers.`) - const between = document.getElementById('cmpArenaBetween').value - const letter = (i) => String.fromCharCode(65 + i) - const layerName = nets.map((n, i) => arenaSafe(`${letter(i)} ${n.name}`).slice(0, 60)) - // union network and one shared layout - const nodeMask = new Map(), - edgeMask = new Map() - nets.forEach((net, i) => { - net.ids.forEach((id) => nodeMask.set(id, (nodeMask.get(id) || 0) | (1 << i))) - net.edgeSet.forEach((k) => edgeMask.set(k, (edgeMask.get(k) || 0) | (1 << i))) - }) - const ids = [...nodeMask.keys()] - if (ids.length > MAX_NETWORK_NODES) - throw new Error( - `The compared networks have ${ids.length.toLocaleString('en-US')} nodes together; NORMA handles up to ${MAX_NETWORK_NODES.toLocaleString('en-US')}.` - ) - const unionEdges = [...edgeMask.keys()].map((k) => { - const [a, b] = k.split('\t') - return { source: a, target: b, weight: 1 } - }) - const raw = ids.length > 1 ? await frLayoutAsync(ids, unionEdges) : { [ids[0]]: { x: 0, y: 0 } } - const xs = ids.map((id) => raw[id].x), - ys = ids.map((id) => raw[id].y) - const cx = (Math.min(...xs) + Math.max(...xs)) / 2, - cy0 = (Math.min(...ys) + Math.max(...ys)) / 2 - const span = Math.max(Math.max(...xs) - Math.min(...xs), Math.max(...ys) - Math.min(...ys)) || 1 - const half = ARENA3D_LAYER_WIDTH * 0.42 - const k = ids.length > 1 ? (2 * half) / span : 0 - const pos = (id) => ({ y: String(-(raw[id].y - cy0) * k), z: String((raw[id].x - cx) * k) }) - const full = (1 << nets.length) - 1 - const bits = (m) => nets.map((_, i) => i).filter((i) => m & (1 << i)) - const COMMON = '#9CA3AF' - - const layers = nets.map((net, i) => ({ - name: layerName[i], - position_x: String((i - (nets.length - 1) / 2) * ARENA3D_LAYER_SPACING), - position_y: '0', - position_z: '0', - last_layer_scale: '1', - rotation_x: '0', - rotation_y: '0', - rotation_z: '0', - floor_current_color: hexColor(net.color), - geometry_parameters_width: String(ARENA3D_LAYER_WIDTH), - })) - const nodes = [] - nets.forEach((net, i) => - net.ids.forEach((id) => { - const m = nodeMask.get(id) - const p = pos(id) - nodes.push({ - name: arenaSafe(id), - layer: layerName[i], - position_x: '0', - position_y: p.y, - position_z: p.z, - scale: '1', - color: bits(m).length === 1 ? hexColor(net.color) : COMMON, - url: '', - descr: - bits(m).length === 1 ? `Only in ${net.name}` : `In ${bits(m).map(letter).join(', ')}`, - }) - }) - ) - const edges = [], - rows = [] - const add = (a, la, b, lb, color, channel, opacity = '1') => { - edges.push({ - src: `${arenaSafe(a)}_${la}`, - trg: `${arenaSafe(b)}_${lb}`, - opacity, - color, - channel, - }) - rows.push([arenaSafe(a), la, arenaSafe(b), lb, 1, channel]) - } - let within = 0, - across = 0, - nodeLinks = 0, - directed = false - // edges inside each layer - nets.forEach((net, i) => - net.edgeSet.forEach((key) => { - const [a, b, dir] = key.split('\t') - if (dir === 'directed') directed = true - const m = edgeMask.get(key) - const only = bits(m).length === 1 - add( - a, - layerName[i], - b, - layerName[i], - only ? hexColor(net.color) : COMMON, - only ? `${letter(i)} only` : 'common', - '1' - ) - within++ - }) - ) - // common edges between consecutive layers that contain them - if (between === 'edges' || between === 'both') { - edgeMask.forEach((m, key) => { - const bs = bits(m) - if (bs.length < 2) return - const [a, b] = key.split('\t') - for (let j = 0; j + 1 < bs.length; j++) { - add( - a, - layerName[bs[j]], - b, - layerName[bs[j + 1]], - '#FFFFFF', - 'common edge between layers', - '0.7' - ) - across++ - } - }) - } - // copies of common nodes - if (between === 'nodes' || between === 'both') { - nodeMask.forEach((m, id) => { - const bs = bits(m) - for (let j = 0; j + 1 < bs.length; j++) { - add(id, layerName[bs[j]], id, layerName[bs[j + 1]], '#FACC15', 'same node', '0.5') - nodeLinks++ - } - }) - } - const json = { - scene: { - position_x: '0', - position_y: '0', - scale: String( - nets.length > 4 ? Math.round(((0.6561 * 4) / nets.length) * 1e4) / 1e4 : 0.6561 - ), - color: '#000000', - rotation_x: '0.261799387799149', - rotation_y: '0.261799387799149', - rotation_z: '0.0872664625997165', - }, - layers, - nodes, - edges, - universalLabelColor: '#FFFFFF', - direction: directed, - edgeOpacityByWeight: false, - edgeWidthByWeight: false, - } - const commonEdges = [...edgeMask.values()].filter((m) => bits(m).length > 1).length - const commonNodes = [...nodeMask.values()].filter((m) => bits(m).length > 1).length - return { - json, - rows, - stats: { - layers: layers.length, - nodes: nodes.length, - edges: edges.length, - interLayer: across + nodeLinks, - copyEdges: nodeLinks, - multiLayerNodes: commonNodes, - distinctNodes: ids.length, - droppedLayers: 0, - droppedNodes: 0, - compare: { - within, - across, - nodeLinks, - commonEdges, - full: [...edgeMask.values()].filter((m) => m === full).length, - }, - }, - } -} - -/* ============================================================ - DATABASE IMPORTERS - Reactome, OmniPath, NDEx, IntAct and the Gene Ontology, next to - STRING. Each one builds a network and/or groupings and adds them to - Files like any uploaded file. Requests go through server.py's relay - when NORMA runs on it (no cross-site restrictions), otherwise straight - to the service. Bodies are always strings (see the STRING importer). - ============================================================ */ -const DB_URLS = { - reactome: 'https://reactome.org/ContentService', - omnipath: 'https://omnipathdb.org', - ndex: 'https://www.ndexbio.org', - intact: 'https://www.ebi.ac.uk/Tools/webservices/psicquic/intact/webservices/current/search', - quickgo: 'https://www.ebi.ac.uk/QuickGO/services', - goapi: 'https://api.geneontology.org/api', -} - -const DB_LABELS = { - reactome: 'Reactome', - omnipath: 'OmniPath', - ndex: 'NDEx', - intact: 'IntAct', - go: 'Gene Ontology', -} - -const dbState = { busy: {}, abort: {}, task: {}, mapping: {} } - -async function dbFetch( - key, - url, - { - method = 'GET', - body = null, - contentType = null, - accept = 'application/json', - text = false, - } = {} -) { - const route = - NORMA_CFG.features.relays.databases === false ? 'direct' : await resolveStringRoute() - const target = route === 'proxy' ? `db-api/fetch?url=${encodeURIComponent(url)}` : url - const headers = { Accept: accept } - if (contentType) headers['Content-Type'] = contentType - const ctl = new AbortController() - dbState.abort[key] = ctl - const timer = setTimeout(() => ctl.abort(), 120000) - let response - try { - response = await fetch(target, { method, headers, body, signal: ctl.signal }) - } catch (err) { - if (err.name === 'AbortError') - throw new Error( - dbState.cancelled && dbState.cancelled[key] - ? 'Cancelled.' - : `${DB_LABELS[key]} did not answer within 2 minutes.` - ) - throw new Error( - route === 'proxy' - ? `The server relay could not be reached (${err.message}). Check that server.py is still running.` - : `${DB_LABELS[key]} could not be reached (${err.message}). Browsers may block direct calls to other sites; running NORMA with server.py avoids that (see Help).` - ) - } finally { - clearTimeout(timer) - } - // download progress, except for the many small requests of dbMap (counted there) - const task = dbState.task[key] - const body2 = await readTextWithProgress( - response, - task && !dbState.mapping[key] ? (got, total) => task.bytes(got, total) : null - ) - if (!response.ok) { - if (route === 'proxy' && !response.headers.get('X-Norma-Relay')) - throw new Error( - 'This server has no database relay. Start NORMA with server.py, or choose Connect: Directly under Import from STRING → STRING server.' - ) - let detail = body2 - .slice(0, 200) - .replace(/<[^>]+>/g, ' ') - .replace(/\s+/g, ' ') - .trim() - try { - const j = JSON.parse(body2) - detail = j.message || j.errorMessage || j.error || detail - } catch (e) {} - throw new Error( - `${DB_LABELS[key]} answered with an error (${response.status})${detail ? ': ' + detail : ''}.` - ) - } - if (text) return body2 - try { - return body2.trim() ? JSON.parse(body2) : null - } catch (e) { - throw new Error(`${DB_LABELS[key]} sent an answer that is not JSON.`) - } -} - -// runs fn over items with a few requests at a time -async function dbMap(key, items, limit, fn, progress) { - const out = new Array(items.length) - let next = 0, - done = 0 - dbState.mapping[key] = (dbState.mapping[key] || 0) + 1 - const worker = async () => { - while (next < items.length) { - if (dbState.cancelled[key]) throw new Error('Cancelled.') - const i = next++ - try { - out[i] = await fn(items[i], i) - } catch (err) { - if (/Cancelled/.test(err.message)) throw err - out[i] = { error: err } - } - done++ - if (progress) progress(done, items.length) - if (dbState.task[key]) dbState.task[key].sub(done / items.length) - } - } - try { - await Promise.all(Array.from({ length: Math.min(limit, items.length) }, worker)) - } finally { - dbState.mapping[key]-- - } - return out -} - -function dbStatus(key, notes) { - setStatus(`${key}Status`, notes) -} - -// Progress of an import: dbPlan sets its weighted steps, dbStep moves on, -// dbProgress changes the text of the current step. -function dbPlan(key, weights) { - dbState.task[key] = startProgress(`${key}Status`, weights) - return dbState.task[key] -} - -function dbStep(key, i, text) { - if (!dbState.task[key] || !dbState.task[key].active) dbPlan(key, [1]) - dbState.task[key].step(i, text) -} - -function dbProgress(key, text) { - const task = dbState.task[key] - if (task && task.active) task.say(text) - else dbStep(key, 0, text) -} - -function dbBusy(key, busy) { - dbState.busy[key] = busy - if (busy) dbState.cancelled[key] = false - document.querySelectorAll(`[data-db-run="${key}"]`).forEach((b) => { - b.disabled = busy - }) - const cancel = document.getElementById(`${key}Cancel`) - if (cancel) cancel.hidden = !busy -} - -async function dbRun(key, fn) { - if (dbState.busy[key]) return - dbBusy(key, true) - dbState.mapping[key] = 0 - dbStep(key, 0, `Contacting ${DB_LABELS[key]}…`) - try { - await fn() - } catch (err) { - dbStatus(key, [{ level: 'error', text: err.message }]) - } finally { - if (dbState.task[key]) dbState.task[key].stop() - dbState.task[key] = null - dbBusy(key, false) - } -} - -export function dbCancel(key) { - dbState.cancelled[key] = true - if (dbState.abort[key]) dbState.abort[key].abort() -} - -const dbSafe = (s) => - String(s ?? '') - .replace(/[\t\r\n]+/g, ' ') - .replace(/,/g, ';') - .trim() - -function dbSplitList(v) { - return String(v || '') - .split(/[\s,;]+/) - .map((x) => x.trim()) - .filter(Boolean) -} - -const UNIPROT_RE = /^([OPQ][0-9][A-Z0-9]{3}[0-9]|[A-NR-Z][0-9]([A-Z][A-Z0-9]{2}[0-9]){1,2})(-\d+)?$/ - -/* Adds a fetched network and its groupings to Files and opens them. - edges: [{ source, target, type, weight, directed }] with node names - nodeAttrs: { name: {...} }, groupings: [{ label, groups: [{ name, members, meta }] }] */ -function dbAddImport( - key, - { - name, - edges, - nodeAttrs = {}, - groupings = [], - positions = null, - notes = [], - summary = '', - preferGrouping = 0, - } -) { - if (!edges.length) throw new Error('No connections were found with these settings.') - const weighted = edges.some((e) => typeof e.weight === 'number') - const typed = - new Set(edges.map((e) => e.type || '')).size > 1 || - edges.some((e) => e.type && e.type !== 'link') - const anyDirected = edges.some((e) => e.directed) - const header = [ - 'Source', - 'Target', - ...(weighted ? ['Weight'] : []), - ...(typed ? ['Type'] : []), - ...(anyDirected ? ['Direction'] : []), - ] - const lines = edges.map((e) => - [ - dbSafe(e.source), - dbSafe(e.target), - ...(weighted ? [typeof e.weight === 'number' ? Math.round(e.weight * 1e4) / 1e4 : 1] : []), - ...(typed ? [dbSafe(e.type || 'link')] : []), - ...(anyDirected ? [e.directed ? 'directed' : 'undirected'] : []), - ].join('\t') - ) - const netEntry = addNormaEntry( - 'network', - name, - [header.join('\t'), ...lines].join('\n') + '\n', - '', - null, - {} - ) - const cleanAttrs = {} - Object.entries(nodeAttrs).forEach(([k, v]) => { - cleanAttrs[dbSafe(k)] = v - }) - netEntry.nodeAttrs = cleanAttrs - netEntry.dbSource = key - if (positions) { - const pos = {} - Object.entries(positions).forEach(([k, p]) => { - pos[dbSafe(k)] = p - }) - netEntry.nodePositions = pos - } - const nodeSet = new Set(netEntry.parsed.nodes) - const annEntries = [] - groupings.forEach((gr) => { - const used = new Set() - const meta = {} - const rows = [] - gr.groups.forEach((g) => { - const members = [...new Set(g.members.map(dbSafe))].filter((m) => nodeSet.has(m)) - if (members.length < (gr.minSize || 1)) return - let gname = - String(g.name) - .replace(/[\t\r\n]+/g, ' ') - .trim() || 'group' - while (used.has(gname)) gname += '′' - used.add(gname) - if (g.meta) meta[gname] = g.meta - rows.push(`${gname}\t${members.join(',')}`) - }) - if (!rows.length) return - const entry = addNormaEntry( - 'annotation', - `${name}: ${gr.label}`, - rows.join('\n') + '\n', - '', - null, - {} - ) - entry.groupMeta = meta - entry.forNetwork = netEntry.id - annEntries.push(entry) - }) - const chosen = annEntries[Math.min(preferGrouping, annEntries.length - 1)] - openInNewView(name, () => { - libSelection.networks = new Set([netEntry.id]) - libSelection.annotation = chosen ? chosen.id : '' - libSelection.colors = '' - renderLibraryLists() - refreshLibraryView() - if (anyDirected) { - // directed databases (OmniPath, GO-CAM) open with arrows - const dirSel = document.getElementById('edgeDirection') - dirSel.value = 'data' - dirSel.dispatchEvent(new Event('change', { bubbles: true })) - } - }) - switchTab('network') - dbStatus(key, [ - { - level: 'ok', - text: `Imported "${name}": ${netEntry.parsed.summary}${summary ? `. ${summary}` : ''}.`, - }, - ...(annEntries.length - ? [ - { - level: 'ok', - text: `Added ${plural(annEntries.length, 'grouping')}: ${annEntries.map((e) => e.name.slice(name.length + 2)).join(', ')}. Switch between them with the Grouping list at the top.`, - }, - ] - : []), - ...netEntry.parsed.notes.map((t) => ({ level: 'warn', text: t })), - ...notes, - ]) - return { netEntry, annEntries } -} - -// Adds groupings for the network already shown (GO terms, ...). -function dbAddGroupingsToView(key, groupings, label) { - const entries = [] - groupings.forEach((gr) => { - const rows = [], - meta = {}, - used = new Set() - gr.groups.forEach((g) => { - let gname = String(g.name) - .replace(/[\t\r\n]+/g, ' ') - .trim() - while (used.has(gname)) gname += '′' - used.add(gname) - if (g.meta) meta[gname] = g.meta - rows.push(`${gname}\t${g.members.join(',')}`) - }) - if (!rows.length) return - const entry = addNormaEntry( - 'annotation', - `${label}: ${gr.label}`, - rows.join('\n') + '\n', - '', - null, - {} - ) - entry.groupMeta = meta - entries.push(entry) - }) - if (!entries.length) return entries - if (S.currentLibView) { - libSelection.annotation = entries[0].id - renderLibraryLists() - refreshLibraryView() - } else { - // views from examples or JSON: apply the first grouping directly - const groupsOf = {} - entries[0].parsed.groups.forEach((g) => - g.members.forEach((m) => (groupsOf[m] = groupsOf[m] || []).push(g.name)) - ) - document.getElementById('nodeFillSelect').value = 'groups' - applyGroupsAndColorsInPlace( - groupsOf, - new Map(), - entries[0].parsed.groups.map((g) => g.name), - entries[0].groupMeta - ) - renderLibraryLists() - } - return entries -} - -/* --------------------------------------------------------------- - REACTOME: the proteins of a pathway's reactions, linked when they - take part in the same reaction; groups are its sub-pathways. - --------------------------------------------------------------- */ -export const REACTOME_SPECIES = [ - 'Homo sapiens', - 'Mus musculus', - 'Rattus norvegicus', - 'Danio rerio', - 'Drosophila melanogaster', - 'Caenorhabditis elegans', - 'Saccharomyces cerevisiae', - 'Gallus gallus', - 'Sus scrofa', - 'Bos taurus', - 'Canis familiaris', - 'Xenopus tropicalis', - 'Dictyostelium discoideum', - 'Plasmodium falciparum', - 'Schizosaccharomyces pombe', -] - -const REACTION_CLASSES = new Set([ - 'Reaction', - 'BlackBoxEvent', - 'Polymerisation', - 'Depolymerisation', - 'FailedReaction', - 'ReactionLikeEvent', - 'CellLineagePath', - 'CellDevelopmentStep', -]) - -const stripTags = (s) => String(s || '').replace(/<[^>]+>/g, '') - -export async function reactomeSearch() { - await dbRun('reactome', async () => { - const q = document.getElementById('reactomeQuery').value.trim() - const species = document.getElementById('reactomeSpecies').value - if (!q) throw new Error('Type a pathway name or a Reactome identifier such as R-HSA-69278.') - const sel = document.getElementById('reactomePathway') - sel.innerHTML = '' - if (/^R-[A-Z]{3}-\d+(\.\d+)?$/i.test(q)) { - const p = await dbFetch('reactome', `${DB_URLS.reactome}/data/query/${encodeURIComponent(q)}`) - sel.add(new Option(`${p.displayName} (${p.stId || q})`, p.stId || q)) - } else { - dbProgress('reactome', 'Searching Reactome…') - const r = await dbFetch( - 'reactome', - `${DB_URLS.reactome}/search/query?query=${encodeURIComponent(q)}&species=${encodeURIComponent(species)}&types=Pathway&cluster=true` - ) - const entries = ((r && r.results) || []).flatMap((g) => g.entries || []) - entries - .slice(0, 40) - .forEach((e) => - sel.add(new Option(`${stripTags(e.name)} (${e.stId || e.id})`, e.stId || e.id)) - ) - } - document.getElementById('reactomePickRow').hidden = !sel.options.length - dbStatus( - 'reactome', - sel.options.length - ? [ - { - level: 'ok', - text: `Found ${plural(sel.options.length, 'pathway')}. Choose one and fetch its network.`, - }, - ] - : [{ level: 'warn', text: 'No pathway matched. Try another name or check the species.' }] - ) - }) -} - -export async function reactomeFetch() { - await dbRun('reactome', async () => { - const pid = document.getElementById('reactomePathway').value - if (!pid) throw new Error('Search for a pathway and choose one first.') - const maxReactions = Math.max( - 5, - Math.min(500, parseInt(document.getElementById('reactomeMaxReactions').value, 10) || 150) - ) - const maxSize = Math.max( - 2, - parseInt(document.getElementById('reactomeMaxSize').value, 10) || 25 - ) - const smallMolecules = document.getElementById('reactomeSmall').checked - // steps: pathway, sub-pathways, reactions, building - dbPlan('reactome', [2, 1, 6, 1]) - dbStep('reactome', 0, 'Reading the pathway…') - const top = await dbFetch( - 'reactome', - `${DB_URLS.reactome}/data/query/${encodeURIComponent(pid)}` - ) - const contained = - (await dbFetch( - 'reactome', - `${DB_URLS.reactome}/data/pathway/${encodeURIComponent(pid)}/containedEvents` - )) || [] - const byDbId = new Map( - contained.filter((e) => e && typeof e === 'object').map((e) => [e.dbId, e]) - ) - const resolve = (x) => (typeof x === 'object' ? x : byDbId.get(x)) - const reactions = [ - ...new Map( - contained.filter((e) => e && REACTION_CLASSES.has(e.schemaClass)).map((e) => [e.stId, e]) - ).values(), - ] - const notes = [] - let used = reactions - if (reactions.length > maxReactions) { - used = reactions.slice(0, maxReactions) - notes.push({ - level: 'warn', - text: `The pathway has ${reactions.length} reactions; the first ${maxReactions} were read (raise "Most reactions" for more).`, - }) - } - if (!used.length) throw new Error('This pathway has no reactions to read.') - // sub-pathways and the reactions each contains - const children = (top.hasEvent || []) - .map(resolve) - .filter((e) => e && e.schemaClass === 'Pathway') - .slice(0, 40) - dbStep('reactome', 1, `Reading ${plural(children.length, 'sub-pathway')}…`) - const childReactions = await dbMap('reactome', children, 4, async (ch) => { - const evs = - (await dbFetch( - 'reactome', - `${DB_URLS.reactome}/data/pathway/${encodeURIComponent(ch.stId)}/containedEvents` - )) || [] - return new Set(evs.filter((e) => e && typeof e === 'object').map((e) => e.stId)) - }) - // participants of each reaction - dbStep('reactome', 2, `Reading reactions: 0 of ${used.length}…`) - const parts = await dbMap( - 'reactome', - used, - 4, - (r) => - dbFetch('reactome', `${DB_URLS.reactome}/data/participants/${encodeURIComponent(r.stId)}`), - (d, n) => dbProgress('reactome', `Reading reactions: ${d} of ${n}…`) - ) - const nodeAttrs = {} - const nameOf = new Map() // reference identifier -> node name - const usedNames = new Map() - const reactionMembers = new Map() - let skippedBig = 0, - failed = 0 - parts.forEach((p, i) => { - if (!p || p.error) { - failed++ - return - } - const members = new Set() - ;(Array.isArray(p) ? p : []).forEach((part) => - (part.refEntities || []).forEach((ref) => { - const cls = ref.schemaClass || '' - const isProtein = - /ReferenceGeneProduct|ReferenceIsoform|ReferenceDNASequence|ReferenceRNASequence/.test( - cls - ) || UNIPROT_RE.test(ref.identifier || '') - if (!isProtein && !(smallMolecules && /ReferenceMolecule/.test(cls))) return - const id = String(ref.identifier || ref.dbId) - if (!nameOf.has(id)) { - const disp = String(ref.displayName || '') - let label = disp.includes(' ') - ? disp.split(/\s+/).slice(1).join(' ') - : (Array.isArray(ref.name) ? ref.name[0] : ref.name) || id - label = label || id - if (usedNames.has(label) && usedNames.get(label) !== id) label = `${label} (${id})` - usedNames.set(label, id) - nameOf.set(id, label) - nodeAttrs[label] = { - ...(isProtein ? { uniprot: id } : { chebi: id }), - reactome: `https://reactome.org/content/query?q=${encodeURIComponent(id)}`, - } - } - members.add(nameOf.get(id)) - }) - ) - if (members.size > maxSize) { - skippedBig++ - return - } - reactionMembers.set(used[i].stId, { name: used[i].displayName, members: [...members] }) - }) - if (failed) - notes.push({ level: 'warn', text: `${plural(failed, 'reaction')} could not be read.` }) - if (skippedBig) - notes.push({ - level: 'ok', - text: `Left out ${plural(skippedBig, 'reaction')} with more than ${maxSize} molecules, which would link them all to each other.`, - }) - // edges: molecules sharing a reaction, weighted by how many they share - const pairs = new Map() - reactionMembers.forEach(({ members }) => { - for (let a = 0; a < members.length; a++) - for (let b = a + 1; b < members.length; b++) { - const [x, y] = - members[a] < members[b] ? [members[a], members[b]] : [members[b], members[a]] - const k = x + '\t' + y - pairs.set(k, (pairs.get(k) || 0) + 1) - } - }) - const edges = [...pairs].map(([k, w]) => { - const [s, t] = k.split('\t') - return { source: s, target: t, weight: w, type: 'same reaction' } - }) - const groupings = [] - if (document.getElementById('reactomeGroupSub').checked && children.length) { - const groups = children.map((ch, i) => { - const set = childReactions[i] && !childReactions[i].error ? childReactions[i] : new Set() - const members = new Set() - reactionMembers.forEach((r, rid) => { - if (set.has(rid)) r.members.forEach((m) => members.add(m)) - }) - return { - name: stripTags(ch.displayName), - members: [...members], - meta: { description: `Reactome ${ch.stId}`, stId: ch.stId }, - } - }) - groupings.push({ label: 'sub-pathways', groups }) - } - if (document.getElementById('reactomeGroupReactions').checked) { - const groups = [...reactionMembers] - .filter(([, r]) => r.members.length >= 2) - .sort((a, b) => b[1].members.length - a[1].members.length) - .slice(0, 40) - .map(([rid, r]) => ({ - name: stripTags(r.name), - members: r.members, - meta: { description: `Reactome reaction ${rid}`, stId: rid }, - })) - groupings.push({ label: 'reactions', groups }) - } - dbStep('reactome', 3, 'Building and opening the network…') - await nextPaint() - dbAddImport('reactome', { - name: `Reactome ${stripTags(top.displayName)} (${pid})`, - edges, - nodeAttrs, - groupings, - notes, - summary: `from ${plural(reactionMembers.size, 'reaction')}; edges join molecules of the same reaction, weighted by how many they share`, - }) - }) -} - -/* --------------------------------------------------------------- - OMNIPATH: signalling, TF-target and ligand-receptor interactions - of the given proteins; groups from complexes, intercellular roles - or pathway annotations. - --------------------------------------------------------------- */ -export async function omnipathFetch() { - await dbRun('omnipath', async () => { - const names = dbSplitList(document.getElementById('omnipathQuery').value) - if (!names.length) - throw new Error('Type one or more gene symbols or UniProt accessions, for example EGFR.') - const organism = document.getElementById('omnipathOrganism').value - const datasets = [...document.querySelectorAll('#omnipathDatasets input:checked')].map( - (i) => i.value - ) - if (!datasets.length) throw new Error('Tick at least one dataset.') - const among = document.getElementById('omnipathAmong').checked - const maxPartners = Math.max(0, parseInt(document.getElementById('omnipathMax').value, 10) || 0) - const channels = document.getElementById('omnipathChannels').value - const wantedGroups = [...document.querySelectorAll('#omnipathGroups input:checked')].map( - (i) => i.value - ) - const annResource = document.getElementById('omnipathAnnotation').value.trim() - // steps: interactions, complexes, intercellular roles, annotations, building - const omniSteps = [ - 6, - wantedGroups.includes('complexes') ? 2 : 0, - wantedGroups.includes('intercell') ? 2 : 0, - wantedGroups.includes('annotations') && annResource ? 2 : 0, - 1, - ] - dbPlan('omnipath', omniSteps) - dbStep('omnipath', 0, 'Fetching interactions from OmniPath…') - const url = `${DB_URLS.omnipath}/interactions?partners=${encodeURIComponent(names.join(','))}&genesymbols=yes&organisms=${organism}&datasets=${datasets.join(',')}&fields=sources,references,curation_effort,type${among ? '&source_target=AND' : ''}&format=json` - const rows = (await dbFetch('omnipath', url)) || [] - if (!Array.isArray(rows) || !rows.length) - throw new Error('OmniPath has no interactions for these proteins with the ticked datasets.') - const query = new Set(names.map((n) => n.toUpperCase())) - const nodeAttrs = {} - const nodeOf = (id, sym) => { - const name = sym || id - if (!nodeAttrs[name]) - nodeAttrs[name] = { - ...(UNIPROT_RE.test(id) ? { uniprot: id } : { omnipath_id: id }), - query: query.has(String(name).toUpperCase()) || query.has(String(id).toUpperCase()), - } - return name - } - let edges = rows - .map((r) => { - const s = nodeOf(r.source, r.source_genesymbol), - t = nodeOf(r.target, r.target_genesymbol) - const stim = +r.is_stimulation === 1 || r.is_stimulation === true, - inh = +r.is_inhibition === 1 || r.is_inhibition === true - const type = - channels === 'sign' - ? stim && inh - ? 'stimulation and inhibition' - : stim - ? 'stimulation' - : inh - ? 'inhibition' - : 'unsigned' - : channels === 'type' - ? String(r.type || 'interaction').replace(/_/g, ' ') - : 'interaction' - const sources = Array.isArray(r.sources) - ? r.sources - : String(r.sources || '') - .split(';') - .filter(Boolean) - return { - source: s, - target: t, - directed: +r.is_directed === 1 || r.is_directed === true, - type, - weight: Number.isFinite(+r.curation_effort) ? +r.curation_effort : sources.length || 1, - } - }) - .filter((e) => e.source !== e.target) - const notes = [] - // keep the best-supported partners - if (!among && maxPartners > 0) { - const support = new Map() - edges.forEach((e) => - [e.source, e.target].forEach((n) => { - if (!nodeAttrs[n].query) support.set(n, (support.get(n) || 0) + e.weight) - }) - ) - if (support.size > maxPartners) { - const keep = new Set( - [...support] - .sort((a, b) => b[1] - a[1]) - .slice(0, maxPartners) - .map((x) => x[0]) - ) - const before = support.size - edges = edges.filter((e) => - [e.source, e.target].every((n) => nodeAttrs[n].query || keep.has(n)) - ) - notes.push({ - level: 'ok', - text: `Kept the ${maxPartners} best-supported of ${before} partners (by curation effort).`, - }) - } - } - // one edge per pair, channel and direction - const merged = new Map() - edges.forEach((e) => { - const k = [ - e.directed ? e.source : [e.source, e.target].sort().join('\u0000'), - e.directed ? e.target : '', - e.type, - e.directed, - ].join('\t') - const m = merged.get(k) - if (m) m.weight = Math.max(m.weight, e.weight) - else merged.set(k, { ...e }) - }) - edges = [...merged.values()] - const present = new Set(edges.flatMap((e) => [e.source, e.target])) - const uniprots = [...present].map((n) => nodeAttrs[n].uniprot).filter(Boolean) - const symOf = new Map( - [...present].filter((n) => nodeAttrs[n].uniprot).map((n) => [nodeAttrs[n].uniprot, n]) - ) - const groupings = [] - const wanted = [...document.querySelectorAll('#omnipathGroups input:checked')].map( - (i) => i.value - ) - const batches = [] - for (let i = 0; i < uniprots.length; i += 150) batches.push(uniprots.slice(i, i + 150)) - const fetchAll = async (path) => - ( - await dbMap('omnipath', batches, 2, (b) => - dbFetch( - 'omnipath', - `${DB_URLS.omnipath}/${path}${path.includes('?') ? '&' : '?'}proteins=${b.join(',')}&format=json` - ) - ) - ).flatMap((x) => (Array.isArray(x) ? x : [])) - if (wanted.includes('complexes') && uniprots.length) { - dbStep('omnipath', 1, 'Fetching complexes…') - const cx = await fetchAll('complexes') - const groups = new Map() - cx.forEach((c) => { - const comps = Array.isArray(c.components) - ? c.components - : String(c.components || '').split('_') - const members = comps.map((u) => symOf.get(u)).filter(Boolean) - if (members.length < 2) return - const name = - c.name || String(c.components_genesymbols || '').replace(/_/g, ':') || comps.join(':') - if (!groups.has(name)) - groups.set(name, { - name, - members, - meta: { - description: `Complex; sources: ${Array.isArray(c.sources) ? c.sources.join(', ') : c.sources || ''}`, - }, - }) - }) - groupings.push({ - label: 'complexes', - minSize: 2, - groups: [...groups.values()] - .sort((a, b) => b.members.length - a.members.length) - .slice(0, 60), - }) - } - if (wanted.includes('intercell') && uniprots.length) { - dbStep('omnipath', 2, 'Fetching intercellular roles…') - const ic = await fetchAll('intercell?scope=generic') - const groups = new Map() - ic.forEach((r) => { - const name = String(r.parent || r.category || '').replace(/_/g, ' ') - const sym = symOf.get(r.uniprot) - if (!name || !sym) return - if (!groups.has(name)) groups.set(name, { name, members: [] }) - groups.get(name).members.push(sym) - }) - groupings.push({ label: 'intercellular roles', groups: [...groups.values()] }) - } - const resource = document.getElementById('omnipathAnnotation').value.trim() - if (wanted.includes('annotations') && resource && uniprots.length) { - dbStep('omnipath', 3, `Fetching ${resource} annotations…`) - const an = await fetchAll(`annotations?resources=${encodeURIComponent(resource)}`) - const LABELS = [ - 'pathway', - 'location', - 'state', - 'function', - 'category', - 'mainclass', - 'classification', - 'family', - 'disease', - ] - const groups = new Map() - an.forEach((r) => { - const sym = symOf.get(r.uniprot) - if (!sym || r.value === undefined || r.value === null || r.value === '') return - if (!LABELS.includes(String(r.label).toLowerCase())) return - const name = String(r.value) - if (!groups.has(name)) - groups.set(name, { - name, - members: new Set(), - meta: { description: `${resource}: ${r.label}` }, - }) - groups.get(name).members.add(sym) - }) - if (!groups.size) - notes.push({ - level: 'warn', - text: `${resource} has no pathway-like annotations for these proteins.`, - }) - groupings.push({ - label: resource, - groups: [...groups.values()].map((g) => ({ ...g, members: [...g.members] })), - }) - } - dbStep('omnipath', omniSteps.length - 1, 'Building and opening the network…') - await nextPaint() - dbAddImport('omnipath', { - name: `OmniPath ${names.slice(0, 3).join(', ')}${names.length > 3 ? ` +${names.length - 3}` : ''}`, - edges, - nodeAttrs, - groupings, - notes, - summary: `datasets ${datasets.join(', ')}; channels by ${channels === 'sign' ? 'effect sign' : channels === 'type' ? 'interaction type' : 'nothing'}; weights are curation effort`, - }) - }) -} - -/* --------------------------------------------------------------- - NDEx: public networks by search or UUID, in CX2; node attributes - become groupings and NDEx positions are kept. - --------------------------------------------------------------- */ -export async function ndexSearch() { - await dbRun('ndex', async () => { - const q = document.getElementById('ndexQuery').value.trim() - if (!q) throw new Error('Type search words (for example "TP53 signaling") or a network UUID.') - const sel = document.getElementById('ndexNetwork') - sel.innerHTML = '' - if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(q)) { - sel.add(new Option(`Network ${q}`, q)) - } else { - dbProgress('ndex', 'Searching NDEx…') - const r = await dbFetch('ndex', `${DB_URLS.ndex}/v2/search/network?start=0&size=40`, { - method: 'POST', - body: JSON.stringify({ searchString: q }), - contentType: 'application/json', - }) - ;((r && r.networks) || []).forEach((n) => { - const big = (n.nodeCount || 0) > MAX_NETWORK_NODES ? ' — larger than NORMA shows' : '' - sel.add( - new Option( - `${n.name} · ${(n.nodeCount || 0).toLocaleString()} nodes, ${(n.edgeCount || 0).toLocaleString()} edges · ${n.owner || ''}${big}`, - n.externalId - ) - ) - }) - } - document.getElementById('ndexPickRow').hidden = !sel.options.length - dbStatus( - 'ndex', - sel.options.length - ? [ - { - level: 'ok', - text: `Found ${plural(sel.options.length, 'network')}. Choose one and fetch it.`, - }, - ] - : [{ level: 'warn', text: 'No public network matched.' }] - ) - }) -} - -// Reads a CX2 document: attribute aliases and defaults are resolved. -function readCx2(cx) { - const aspects = {} - ;(Array.isArray(cx) ? cx : []).forEach((part) => - Object.entries(part).forEach(([k, v]) => { - if (Array.isArray(v)) (aspects[k] = aspects[k] || []).push(...v) - }) - ) - const decl = (aspects.attributeDeclarations || [])[0] || {} - const resolver = (kind) => { - const d = decl[kind] || {} - const alias = {}, - defaults = {} - Object.entries(d).forEach(([name, spec]) => { - if (spec && spec.a) alias[spec.a] = name - if (spec && spec.v !== undefined) defaults[name] = spec.v - }) - return (v) => { - const out = { ...defaults } - Object.entries(v || {}).forEach(([k, val]) => { - out[alias[k] || k] = val - }) - return out - } - } - const rn = resolver('nodes'), - re = resolver('edges') - const netAttrs = Object.assign({}, ...(aspects.networkAttributes || [])) - return { - name: netAttrs.name || '', - nodes: (aspects.nodes || []).map((n) => ({ id: n.id, v: rn(n.v), x: n.x, y: n.y })), - edges: (aspects.edges || []).map((e) => ({ id: e.id, s: e.s, t: e.t, v: re(e.v) })), - declarations: decl, - } -} - -export async function ndexFetch() { - await dbRun('ndex', async () => { - const uuid = document.getElementById('ndexNetwork').value - if (!uuid) throw new Error('Search and choose a network first.') - dbPlan('ndex', [8, 1]) - dbStep('ndex', 0, 'Downloading the network from NDEx…') - const cx = await dbFetch('ndex', `${DB_URLS.ndex}/v3/networks/${encodeURIComponent(uuid)}`) - const net = readCx2(cx) - if (!net.nodes.length) throw new Error('This network has no nodes, or is not public.') - const names = new Map(), - used = new Set() - net.nodes.forEach((n) => { - let name = String(n.v.name ?? n.v.n ?? n.v.label ?? n.id).trim() || String(n.id) - if (used.has(name)) name = `${name} (${n.id})` - used.add(name) - names.set(n.id, name) - }) - const weightKey = ['weight', 'Weight', 'score', 'Score', 'confidence'].find((k) => - net.edges.some((e) => typeof e.v[k] === 'number') - ) - const edges = net.edges - .filter((e) => names.has(e.s) && names.has(e.t) && e.s !== e.t) - .map((e) => ({ - source: names.get(e.s), - target: names.get(e.t), - type: String(e.v.interaction ?? e.v.i ?? 'interacts'), - ...(weightKey && typeof e.v[weightKey] === 'number' ? { weight: e.v[weightKey] } : {}), - directed: e.v.directed === true, - })) - // node attributes and groupings from categorical attributes - const SKIP = /^(name|n|represents|r|alias|aliases|id|x|y|z|label|description|url|uri|link)$/i - const keys = new Set() - net.nodes.forEach((n) => Object.keys(n.v).forEach((k) => keys.add(k))) - const nodeAttrs = {} - net.nodes.forEach((n) => { - const a = {} - Object.entries(n.v).forEach(([k, v]) => { - if ( - !/^(name|n)$/.test(k) && - (typeof v !== 'object' || v === null) && - Object.keys(a).length < 25 - ) - a[k] = v - }) - const rep = String(n.v.represents || n.v.r || '') - const m = rep.match(/uniprot(?:kb)?:([A-Z0-9-]+)/i) - if (m) a.uniprot = m[1] - nodeAttrs[names.get(n.id)] = a - }) - const groupings = [] - ;[...keys] - .filter((k) => !SKIP.test(k)) - .forEach((k) => { - const groups = new Map() - let covered = 0 - net.nodes.forEach((n) => { - const v = n.v[k] - const vals = Array.isArray(v) - ? v - : typeof v === 'string' || typeof v === 'boolean' - ? [String(v)] - : [] - const clean = vals.map((x) => String(x).trim()).filter((x) => x && x.length <= 80) - if (clean.length) covered++ - clean.forEach((x) => { - if (!groups.has(x)) groups.set(x, []) - groups.get(x).push(names.get(n.id)) - }) - }) - if (groups.size < 2 || groups.size > 60 || covered < net.nodes.length * 0.3) return - groupings.push({ - label: `groups by ${k}`, - groups: [...groups].map(([name, members]) => ({ name, members })), - score: covered, - }) - }) - groupings.sort((a, b) => b.score - a.score) - const positions = net.nodes.every((n) => Number.isFinite(n.x) && Number.isFinite(n.y)) - ? Object.fromEntries(net.nodes.map((n) => [names.get(n.id), { x: n.x, y: n.y }])) - : null - const notes = [] - if (!groupings.length) - notes.push({ - level: 'ok', - text: 'The network has no node attribute that makes useful groups (2 to 60 values covering at least 30% of the nodes); add an annotation or use communities.', - }) - if (positions) notes.push({ level: 'ok', text: 'The layout saved in NDEx is kept.' }) - dbStep('ndex', 1, 'Building and opening the network…') - await nextPaint() - dbAddImport('ndex', { - name: `NDEx ${net.name || uuid}`.slice(0, 90), - edges, - nodeAttrs, - groupings: groupings.slice(0, 6), - positions, - notes, - summary: `network ${uuid}`, - }) - }) -} - -/* --------------------------------------------------------------- - INTACT: molecular interactions from the IntAct PSICQUIC service - (PSI-MITAB 2.5), filtered by the IntAct MI-score. - --------------------------------------------------------------- */ -function mitabName(idField, altField, aliasField) { - const all = [aliasField, altField].join('|').split('|') - const pick = (re) => { - for (const x of all) { - const m = x.match(re) - if (m) return m[1] - } - return null - } - return ( - pick(/^uniprotkb:([^(]+)\(gene name\)/) || - pick(/^[^:]+:([^(]+)\(gene name\)/) || - pick(/^psi-mi:([^(]+)\(display_short\)/) || - String(idField) - .split('|')[0] - .replace(/^[^:]+:/, '') - ) -} - -function mitabTerm(field) { - const m = String(field).match(/\(([^)]+)\)/) - return m ? m[1] : String(field).replace(/^[^:]+:/, '') -} - -export async function intactFetch() { - await dbRun('intact', async () => { - const names = dbSplitList(document.getElementById('intactQuery').value) - if (!names.length) - throw new Error('Type one or more gene names or UniProt accessions, for example TP53.') - const taxon = document.getElementById('intactTaxon').value - const minScore = parseFloat(document.getElementById('intactScore').value) || 0 - const maxRows = Math.max( - 50, - Math.min(5000, parseInt(document.getElementById('intactMaxRows').value, 10) || 1000) - ) - const among = document.getElementById('intactAmong').checked - const maxPartners = Math.max(0, parseInt(document.getElementById('intactMax').value, 10) || 0) - const ids = names.map((n) => (/[\s():]/.test(n) ? `"${n}"` : n)).join(' OR ') - let miql = `identifier:(${ids})` - if (taxon) miql += ` AND taxidA:${taxon} AND taxidB:${taxon}` - dbPlan('intact', [8, 1]) - dbStep('intact', 0, 'Fetching interactions from IntAct…') - const text = await dbFetch( - 'intact', - `${DB_URLS.intact}/query/${encodeURIComponent(miql)}?format=tab25&firstResult=0&maxResults=${maxRows}`, - { accept: 'text/plain', text: true } - ) - const lines = String(text || '') - .split('\n') - .filter((l) => l.trim()) - if (!lines.length) - throw new Error('IntAct has no interactions for these names in this organism.') - const nodeAttrs = {} - const query = new Set(names.map((n) => n.toUpperCase())) - const agg = new Map() - let lowScore = 0 - lines.forEach((line) => { - const c = line.split('\t') - if (c.length < 15) return - const nameA = mitabName(c[0], c[2], c[4]), - nameB = mitabName(c[1], c[3], c[5]) - if (!nameA || !nameB || nameA === nameB) return - const score = (String(c[14]).match(/intact-miscore:([\d.]+)/) || [])[1] - const s = score === undefined ? NaN : parseFloat(score) - if (Number.isFinite(s) && s < minScore) { - lowScore++ - return - } - ;[ - [nameA, c[0]], - [nameB, c[1]], - ].forEach(([nm, idf]) => { - if (nodeAttrs[nm]) return - const acc = (String(idf).match(/uniprotkb:([A-Z0-9-]+)/) || [])[1] - nodeAttrs[nm] = { - ...(acc ? { uniprot: acc } : { intact_id: String(idf).split('|')[0] }), - query: query.has(nm.toUpperCase()) || (acc && query.has(acc.toUpperCase())), - } - }) - const type = mitabTerm(String(c[11]).split('|')[0]) || 'interaction' - const [x, y] = nameA < nameB ? [nameA, nameB] : [nameB, nameA] - const k = `${x}\t${y}\t${type}` - const cur = agg.get(k) || { source: x, target: y, type, weight: 0, evidence: 0 } - cur.weight = Math.max(cur.weight, Number.isFinite(s) ? s : 0) - cur.evidence++ - agg.set(k, cur) - }) - let edges = [...agg.values()] - if (among) edges = edges.filter((e) => nodeAttrs[e.source].query && nodeAttrs[e.target].query) - const notes = [] - if (lines.length >= maxRows) - notes.push({ - level: 'warn', - text: `Read the first ${maxRows} interaction records; raise "Most records" for more.`, - }) - if (lowScore) - notes.push({ - level: 'ok', - text: `Left out ${plural(lowScore, 'record')} with an MI-score below ${minScore}.`, - }) - if (!among && maxPartners > 0) { - const best = new Map() - edges.forEach((e) => - [e.source, e.target].forEach((n) => { - if (!nodeAttrs[n].query) best.set(n, Math.max(best.get(n) || 0, e.weight)) - }) - ) - if (best.size > maxPartners) { - const keep = new Set( - [...best] - .sort((a, b) => b[1] - a[1]) - .slice(0, maxPartners) - .map((x) => x[0]) - ) - notes.push({ - level: 'ok', - text: `Kept the ${maxPartners} highest-scoring of ${best.size} partners.`, - }) - edges = edges.filter((e) => - [e.source, e.target].every((n) => nodeAttrs[n].query || keep.has(n)) - ) - } - } - const present = new Set(edges.flatMap((e) => [e.source, e.target])) - const groupings = [ - { - label: 'query and partners', - groups: [ - { name: 'Query proteins', members: [...present].filter((n) => nodeAttrs[n].query) }, - { - name: 'Interaction partners', - members: [...present].filter((n) => !nodeAttrs[n].query), - }, - ], - }, - ] - dbStep('intact', 1, 'Building and opening the network…') - await nextPaint() - dbAddImport('intact', { - name: `IntAct ${names.slice(0, 3).join(', ')}${names.length > 3 ? ` +${names.length - 3}` : ''}`, - edges: edges.map(({ evidence, ...e }) => e), - nodeAttrs, - groupings, - notes, - summary: `MI-score at least ${minScore}; channels are interaction types, weights the best MI-score`, - }) - }) -} - -/* --------------------------------------------------------------- - GENE ONTOLOGY: a GO-CAM model as a causal gene-to-gene network, - and GO terms (QuickGO annotations) as groupings for the view. - --------------------------------------------------------------- */ -const RO_LABELS = { - 'RO:0002629': 'directly positively regulates', - 'RO:0002630': 'directly negatively regulates', - 'RO:0002413': 'directly provides input for', - 'RO:0002211': 'regulates', - 'RO:0002213': 'positively regulates', - 'RO:0002212': 'negatively regulates', - 'RO:0002304': 'causally upstream of, positive effect', - 'RO:0002305': 'causally upstream of, negative effect', - 'RO:0002411': 'causally upstream of', - 'RO:0002418': 'causally upstream of or within', - 'RO:0012009': 'constitutively upstream of', - 'RO:0012010': 'removes input for', - 'RO:0002407': 'indirectly positively regulates', - 'RO:0002409': 'indirectly negatively regulates', -} - -const termOf = (x) => (x == null ? null : typeof x === 'string' ? x : x.term || x.id || null) - -export async function goLoadModels() { - await dbRun('go', async () => { - const taxon = document.getElementById('goTaxon').value - dbProgress('go', 'Listing GO-CAM models…') - const r = await dbFetch('go', `${DB_URLS.goapi}/taxon/${encodeURIComponent(taxon)}/models`) - const list = (Array.isArray(r) ? r : (r && (r.models || r.results)) || []).map((m) => - typeof m === 'string' - ? { id: m, title: m } - : { id: m.id || m.gocam || m.model_id, title: m.title || m.name || m.id || m.gocam } - ) - goState.models = list.filter((m) => m.id) - filterGoModels() - dbStatus('go', [ - { - level: goState.models.length ? 'ok' : 'warn', - text: goState.models.length - ? `Found ${plural(goState.models.length, 'GO-CAM model')}. Filter and choose one.` - : 'No GO-CAM models for this organism.', - }, - ]) - }) -} - -const goState = { models: [] } - -export function filterGoModels() { - const f = document.getElementById('goModelFilter').value.trim().toLowerCase() - const sel = document.getElementById('goModel') - sel.innerHTML = '' - goState.models - .filter( - (m) => - !f || String(m.title).toLowerCase().includes(f) || String(m.id).toLowerCase().includes(f) - ) - .slice(0, 300) - .forEach((m) => sel.add(new Option(m.title, m.id))) - document.getElementById('goPickRow').hidden = !goState.models.length -} - -export async function goFetchModel() { - await dbRun('go', async () => { - const typed = document.getElementById('goModelId').value.trim() - const id = (typed || document.getElementById('goModel').value || '').replace(/^gomodel:/, '') - if (!id) throw new Error('Choose a GO-CAM model or type its identifier.') - dbPlan('go', [6, 1]) - dbStep('go', 0, 'Downloading the GO-CAM model…') - const m = await dbFetch('go', `${DB_URLS.goapi}/gocam-model/${encodeURIComponent(id)}`) - const labels = new Map((m.objects || []).map((o) => [o.id, o.label || o.id])) - const label = (t) => { - const l = labels.get(t) || t - // gene product labels carry the organism, e.g. "Tp53 Mmus" - return String(l).replace(/\s+[A-Z][a-z]{3}$/, '') - } - const acts = new Map((m.activities || []).map((a) => [a.id, a])) - const enabler = (a) => termOf(a && a.enabled_by) - const nodeAttrs = {} - const nodeName = (t) => { - const n = label(t) - if (!nodeAttrs[n]) - nodeAttrs[n] = { - go_cam_id: t, - ...(/UniProtKB:/.test(t) ? { uniprot: t.replace('UniProtKB:', '') } : {}), - } - return n - } - const edges = [] - acts.forEach((a) => { - const src = enabler(a) - if (!src) return - nodeName(src) - ;(a.causal_associations || []).forEach((ca) => { - const down = acts.get(termOf(ca.downstream_activity)) - const tgt = enabler(down) - if (!tgt) return - const pred = termOf(ca.predicate) - edges.push({ - source: nodeName(src), - target: nodeName(tgt), - directed: true, - type: labels.get(pred) || RO_LABELS[pred] || pred || 'causally related', - }) - }) - }) - const byAspect = (field, lbl) => { - const groups = new Map() - acts.forEach((a) => { - const src = enabler(a) - const raw = a[field] - const terms = (Array.isArray(raw) ? raw : raw ? [raw] : []).map(termOf).filter(Boolean) - if (!src) return - terms.forEach((t) => { - const n = labels.get(t) || t - if (!groups.has(n)) - groups.set(n, { name: n, members: [], meta: { description: `${lbl} ${t}`, term: t } }) - groups.get(n).members.push(label(src)) - }) - }) - return { label: lbl, groups: [...groups.values()] } - } - const groupings = [ - byAspect('part_of', 'biological process'), - byAspect('occurs_in', 'cellular component'), - byAspect('molecular_function', 'molecular function'), - ] - if (!edges.length) throw new Error('This model has no causal links between gene products.') - dbStep('go', 1, 'Building and opening the network…') - await nextPaint() - dbAddImport('go', { - name: `GO-CAM ${m.title || id}`.slice(0, 90), - edges, - nodeAttrs, - groupings, - summary: `model ${id}; edges are causal relations between activities, pointing downstream`, - }) - }) -} - -export async function goAnnotateView() { - await dbRun('go', async () => { - if (!cy.nodes().length) throw new Error('Show a network first.') - const aspects = [...document.querySelectorAll('#goAspects input:checked')].map((i) => i.value) - if (!aspects.length) throw new Error('Tick at least one GO aspect.') - const noIEA = document.getElementById('goNoIea').checked - const minSize = Math.max(1, parseInt(document.getElementById('goMinSize').value, 10) || 2) - const maxGroups = Math.max(1, parseInt(document.getElementById('goMaxGroups').value, 10) || 30) - // UniProt accessions from node attributes or node names - const accOf = new Map() - cy.nodes().forEach((n) => { - const a = n.data('attrs') || {} - const acc = a.uniprot || (UNIPROT_RE.test(n.id()) ? n.id() : null) - if (acc) accOf.set(String(acc).replace(/-\d+$/, ''), n.id()) - }) - if (!accOf.size) - throw new Error( - 'No node has a UniProt accession (as its name or in a "uniprot" attribute). Networks from Reactome, OmniPath, IntAct and many NDEx networks carry them.' - ) - const accs = [...accOf.keys()] - const batches = [] - for (let i = 0; i < accs.length; i += 100) batches.push(accs.slice(i, i + 100)) - const groupings = [] - // steps: one per aspect, then adding the groupings - dbPlan('go', [...aspects.map(() => 3), 1]) - for (const [ai, aspect] of aspects.entries()) { - dbStep( - 'go', - ai, - `Reading ${aspect.replace('_', ' ')} annotations: 0 of ${batches.length} batches…` - ) - const terms = new Map() - const results = await dbMap( - 'go', - batches, - 2, - async (b) => { - const all = [] - for (let page = 1; page <= 25; page++) { - const r = await dbFetch( - 'go', - `${DB_URLS.quickgo}/annotation/search?geneProductId=${b.join(',')}&aspect=${aspect}&limit=200&page=${page}&includeFields=goName` - ) - all.push(...((r && r.results) || [])) - const info = r && r.pageInfo - if (!info || page >= (info.total || 1)) break - } - return all - }, - (d, n) => - dbProgress('go', `Reading ${aspect.replace('_', ' ')} annotations: ${d} of ${n} batches…`) - ) - results.flat().forEach((r) => { - if (!r || r.error) return - if (noIEA && (r.goEvidence === 'IEA' || r.evidenceCode === 'ECO:0000501')) return - if (r.qualifier && /^NOT/i.test(r.qualifier)) return - const acc = String(r.geneProductId || '') - .replace(/^UniProtKB:/, '') - .replace(/-\d+$/, '') - const node = accOf.get(acc) - if (!node) return - const name = r.goName || r.goId - if (!terms.has(name)) - terms.set(name, { - name, - members: new Set(), - meta: { description: `GO ${aspect.replace('_', ' ')}`, term: r.goId }, - }) - terms.get(name).members.add(node) - }) - const groups = [...terms.values()] - .map((t) => ({ ...t, members: [...t.members] })) - .filter((t) => t.members.length >= minSize && t.members.length < accOf.size) - .sort((a, b) => b.members.length - a.members.length) - .slice(0, maxGroups) - groupings.push({ label: `GO ${aspect.replace('_', ' ')}`, groups }) - } - dbStep('go', aspects.length, 'Adding the groupings…') - await nextPaint() - const v = activeView() - const entries = dbAddGroupingsToView('go', groupings, v ? v.name : 'View') - dbStatus( - 'go', - entries.length - ? [ - { - level: 'ok', - text: `Added ${plural(entries.length, 'GO grouping')} for ${plural(accOf.size, 'node')} with a UniProt accession: ${entries.map((e) => `${e.name.split(': ').pop()} (${e.parsed.summary})`).join(', ')}.`, - }, - ] - : [{ level: 'warn', text: 'No GO terms with enough members were found.' }] - ) - }) -} - -// page wiring, run by main.ts in the original order -export function init() { - document.getElementById('btnGaStats').addEventListener('click', renderGroupStats) - - document.getElementById('btnGaStatsTsv').addEventListener('click', groupStatsTsv) - - document.getElementById('btnGaGroupNet').addEventListener('click', openGroupNetwork) - - document.getElementById('btnGaEnrich').addEventListener('click', runEnrichment) - - document.getElementById('btnGaEnrichTsv').addEventListener('click', enrichmentTsv) - - document.getElementById('gaSets').addEventListener('change', refreshEnrichmentChoices) - - cy.on('select unselect', () => { - if (currentTab === 'profiler') refreshEnrichmentChoices() - }) - - document.getElementById('btnCompareNet').addEventListener('click', openComparisonNetwork) - - document.querySelectorAll('#infoExplore [data-steps]').forEach((btn) => - btn.addEventListener('click', () => { - if (S.infoNodeId && cy.$id(S.infoNodeId).length) - openNeighbourhood([S.infoNodeId], +btn.dataset.steps) - }) - ) - - document.getElementById('btnSelNeighbours').addEventListener('click', () => { - const ids = cy.nodes(':selected').map((n) => n.id()) - if (ids.length) openNeighbourhood(ids, 1) - }) - - document.getElementById('btnSelPaths').addEventListener('click', () => { - const ids = cy.nodes(':selected').map((n) => n.id()) - if (ids.length !== 2) return - // paths go from the node selected first to the one selected second - const rank = (id) => { - const i = selectionOrder.indexOf(id) - return i < 0 ? Infinity : i - } - const [a, b] = rank(ids[0]) <= rank(ids[1]) ? ids : [ids[1], ids[0]] - openShortestPaths(a, b) - }) - - cy.on('select', 'node', (e) => { - const id = e.target.id() - const i = selectionOrder.indexOf(id) - if (i >= 0) selectionOrder.splice(i, 1) - selectionOrder.push(id) - if (selectionOrder.length > 50) selectionOrder.shift() - }) - - cy.on('unselect', 'node', (e) => { - const i = selectionOrder.indexOf(e.target.id()) - if (i >= 0) selectionOrder.splice(i, 1) - }) - - document - .querySelectorAll('[data-export-format]') - .forEach((b) => b.addEventListener('click', () => exportOtherFormat(b.dataset.exportFormat))) - - document.getElementById('btnSessionSave').addEventListener('click', saveSession) - - document - .getElementById('btnSessionOpen') - .addEventListener('click', () => document.getElementById('sessionFileInput').click()) - - document.getElementById('sessionFileInput').addEventListener('change', (e) => { - const f = e.target.files[0] - if (f) openSessionFile(f) - e.target.value = '' - }) - - ;(function setupWebglToggle() { - const box = document.getElementById('webglToggle') - const note = document.getElementById('webglNote') - box.checked = WEBGL_ACTIVE - let stored = true - try { - localStorage.getItem('x') - } catch (e) { - stored = false - } - const describe = () => { - const wanted = box.checked - if (wanted === WEBGL_ACTIVE) { - note.textContent = WEBGL_ACTIVE ? 'WebGL drawing is on.' : '' - document.getElementById('btnWebglReload').hidden = true - } else { - note.textContent = stored - ? 'Reload the page to switch; open views are lost unless you save the session first.' - : 'This page can\u2019t store the setting; open it with ?webgl=1 at the end of the address instead.' - document.getElementById('btnWebglReload').hidden = !stored - } - } - box.addEventListener('change', () => { - try { - localStorage.setItem('norma3-webgl', box.checked ? '1' : '0') - } catch (e) {} - describe() - }) - document.getElementById('btnWebglReload').addEventListener('click', () => location.reload()) - describe() - })() - - document.getElementById('btnRuntime').addEventListener('click', runRuntimeTable) - - document.getElementById('btnRuntimeTsv').addEventListener('click', runtimeTsv) - - /* frames wiring */ - document.getElementById('btnFramePrev').addEventListener('click', () => { - stopFramePlay() - stepFrame(-1) - }) - - document.getElementById('btnFrameNext').addEventListener('click', () => { - stopFramePlay() - stepFrame(1) - }) - - document.getElementById('btnFramePlay').addEventListener('click', toggleFramePlay) - - document.getElementById('frameSlider').addEventListener('input', (e) => { - stopFramePlay() - showFrame(parseInt(e.target.value, 10) || 0) - }) - - document.getElementById('frameSpeed').addEventListener('change', () => { - if (frameState.playing) { - toggleFramePlay() - toggleFramePlay() - } - }) - - document.getElementById('btnFramesFromFiles').addEventListener('click', addFramesFromFiles) - - document.getElementById('valueSameRange').addEventListener('change', applyValueColors) - - document - .getElementById('btnCmpArenaOpen') - .addEventListener('click', () => openInArena3d('compare')) - - document - .getElementById('btnCmpArenaJson') - .addEventListener('click', () => exportArena3d('json', 'compare')) - - document - .getElementById('btnCmpArenaTsv') - .addEventListener('click', () => exportArena3d('tsv', 'compare')) - - dbState.cancelled = {} -} diff --git a/frontend/src/examples.ts b/frontend/src/examples.ts deleted file mode 100644 index 76c0f94..0000000 --- a/frontend/src/examples.ts +++ /dev/null @@ -1,78 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { NORMA_EXAMPLE_SETS } from './wiring' -import { - addNormaEntry, - libSelection, - normaLibrary, - plural, - renderLibraryLists, - setLayoutMode, -} from './layouts/controls' -import { applyEdgeCurveStyle } from './profiler' -import { applyEdgeDirection } from './export/dialog' -import { applyValueColors, scheduleLegend } from './clustering/mapping' -import { refreshLibraryView } from './library' - -/* ---------- NORMA example sets ---------- */ -// A layout to use the next time a network loads (set by showcase examples). -let nextLoadLayout = null - -export function takeNextLoadLayout() { - const name = nextLoadLayout - nextLoadLayout = null - if (name) { - setLayoutMode('connections') - document.getElementById('layoutSelect').value = name - } - return name -} - -export function loadNormaExampleSet(key) { - const set = NORMA_EXAMPLE_SETS[key] - if (!set) return - const entries = set.files.map((f, i) => { - if (!normaLibrary[f.kind]) return null // e.g. original-format copies, offered only as downloads - const sourceKey = `${key}/${i}` - const existing = normaLibrary[f.kind].find((e) => e.sourceKey === sourceKey) - return ( - existing || - addNormaEntry(f.kind, f.name, f.text, f.fileName, sourceKey, { directed: !!f.directed }) - ) - }) - const real = entries.filter(Boolean) - const net = real.find((e) => e.kind === 'network') - const ann = real.find((e) => e.kind === 'annotation') - const col = real.find((e) => e.kind === 'colors') - libSelection.networks = new Set( - set.showAll ? real.filter((e) => e.kind === 'network').map((e) => e.id) : [net.id] - ) - libSelection.annotation = ann ? ann.id : '' - libSelection.colors = col ? col.id : '' - renderLibraryLists() - nextLoadLayout = (set.display && set.display.layoutSelect) || null - refreshLibraryView() - nextLoadLayout = null - // showcase examples switch on the features they are meant to show - if (set.display) { - Object.entries(set.display).forEach(([id, value]) => { - const el = document.getElementById(id) - if (!el) return - if (el.type === 'checkbox') el.checked = !!value - else el.value = value - if (id !== 'layoutSelect') el.dispatchEvent(new Event('change', { bubbles: true })) - }) - applyEdgeDirection() - applyEdgeCurveStyle() - applyValueColors() - scheduleLegend() - } - const others = real.filter((e) => e.kind === 'annotation').length - 1 - if (others > 0) { - const el = document.getElementById('normaStatus') - const note = document.createElement('div') - note.className = 'note ok' - note.textContent = `This example has ${plural(others, 'more annotation')} in the Annotations list. Tick one and choose Show in this view to switch; node positions are kept.` - el.insertBefore(note, el.children[1] || null) - } -} diff --git a/frontend/src/export/dialog.ts b/frontend/src/export/dialog.ts deleted file mode 100644 index 4b1b760..0000000 --- a/frontend/src/export/dialog.ts +++ /dev/null @@ -1,611 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { S } from '../state' -import { activeView, applyEdgeCurveStyle } from '../profiler' -import { applyEdgeMerge } from '../parallel_edges' -import { - applyNodeSizing, - frPending, - getFrWorker, - invalidateFullMetrics, - updateStats, - workStep, -} from '../metrics' -import { buildSvg } from './svg' -import { buildSvg3d, export3dSize, renderExportCanvas3d } from '../view3d/export' -import { canvasToBlob, pdfFromCanvas, renderExportCanvas, withDpi } from './raster' -import { - composeCanvasWithLegend, - composeSvgWithLegend, - exportLegendLayout, - legendIsEmpty, - legendModel, -} from '../clustering/mapping' -import { currentTheme } from '../themes' -import { cy, setStyle } from '../cy' -import { exportFrame, exportPixelSize, exportSizeText, withLegendSize } from './draw' -import { markDirty3d, net3d } from '../view3d/state' -import { mulberry32 } from '../sample_data' -import { nextPaint, setStatus } from '../layouts/controls' - -/* ---------- dialog ---------- */ -const EXPORT_FORMATS = { - png: { label: 'PNG', ext: 'png', raster: true, transparent: true }, - jpeg: { label: 'JPEG', ext: 'jpg', raster: true, transparent: false }, - webp: { label: 'WebP', ext: 'webp', raster: true, transparent: true }, - svg: { label: 'SVG', ext: 'svg', raster: false, transparent: true }, - pdf: { label: 'PDF', ext: 'pdf', raster: true, transparent: false }, -} - -function exportOptions() { - const format = document.querySelector('input[name="imgFormat"]:checked').value - const bgMode = document.getElementById('imgBackground').value - const fmtInfo = EXPORT_FORMATS[format] - let bg = null - if (bgMode === 'theme') bg = currentTheme.bg - else if (bgMode === 'white') bg = '#ffffff' - else if (bgMode === 'custom') bg = document.getElementById('imgBgColor').value - if (!bg && !fmtInfo.transparent) bg = '#ffffff' - return { - format, - area: document.getElementById('imgArea').value, - scale: parseFloat(document.getElementById('imgScale').value) || 2, - bg, - hulls: - document.getElementById('imgHulls').checked && - document.getElementById('showGroupHulls').checked, - clean: document.getElementById('imgClean').checked, - legend: document.getElementById('imgLegend').checked, - fileName: (document.getElementById('imgFileName').value.trim() || 'network').replace( - /[\\/:*?"<>|]+/g, - '_' - ), - } -} - -function updateExportDialog() { - const o = exportOptions() - const info = EXPORT_FORMATS[o.format] - const bgSel = document.getElementById('imgBackground') - const transparentOpt = bgSel.querySelector('option[value="transparent"]') - transparentOpt.disabled = !info.transparent - if (!info.transparent && bgSel.value === 'transparent') bgSel.value = 'white' - document.getElementById('imgBgColor').hidden = bgSel.value !== 'custom' - document.getElementById('imgHullsRow').hidden = !document.getElementById('showGroupHulls').checked - document.getElementById('imgLegendRow').hidden = legendIsEmpty(legendModel()) - document.getElementById('imgScaleLabel').textContent = info.raster - ? 'Resolution' - : 'Size in the file' - document.getElementById('exportTitle').textContent = net3d.active - ? 'Export 3D image' - : 'Export image' - const size = document.getElementById('imgSize') - if (net3d.active) { - document.getElementById('btnImgSave').disabled = !cy.nodes().length - const s3 = export3dSize(o.scale) - const all3 = withLegendSize( - s3.outW, - s3.outH, - o.format === 'svg' ? Math.min(o.scale, 8) : s3.k, - o - ) - let t3 = exportSizeText(all3.W, all3.H, s3.k, o.format) - if (all3.W !== s3.outW) t3 += ' · legend included' - t3 += ' · 3D view from the current angle' - if (s3.limited) t3 += ' · reduced to the largest size this browser can draw' - size.textContent = t3 - document.getElementById('imgExt').textContent = '.' + info.ext - return - } - const frame = exportFrame(o.area) - if (!frame) { - size.textContent = 'Nothing is shown to export.' - document.getElementById('btnImgSave').disabled = true - return - } - document.getElementById('btnImgSave').disabled = false - const { W, H, k, limited } = exportPixelSize(frame, o.scale) - const all = withLegendSize(W, H, k / frame.unitPx, o) - let text = exportSizeText(all.W, all.H, k / frame.unitPx, o.format) - if (all.W !== W) text += ' · legend included' - if (limited) text += ' · reduced to the largest size this browser can draw' - size.textContent = text - document.getElementById('imgExt').textContent = '.' + info.ext -} - -function openExportDialog() { - const dlg = document.getElementById('exportDialog') - const v = typeof activeView === 'function' && activeView() - const nameInput = document.getElementById('imgFileName') - nameInput.value = (v ? v.name : 'network').replace(/[\\/:*?"<>|]+/g, '_') - setStatus('imgStatus', []) - updateExportDialog() - if (typeof dlg.showModal === 'function') dlg.showModal() - else dlg.setAttribute('open', '') -} - -async function saveExportImage() { - const o = exportOptions() - const info = EXPORT_FORMATS[o.format] - const btn = document.getElementById('btnImgSave') - btn.disabled = true - setStatus('imgStatus', [{ level: 'busy', text: 'Drawing the image…', progress: null }]) - await nextPaint() - // optionally hide selection and search/click highlighting while drawing - let restore = null - if (o.clean) { - const selected = cy.elements(':selected') - const dimmed = cy.elements('.dimmed'), - highlighted = cy.elements('.highlighted') - cy.batch(() => { - selected.unselect() - dimmed.removeClass('dimmed') - highlighted.removeClass('highlighted') - }) - restore = () => - cy.batch(() => { - selected.select() - dimmed.addClass('dimmed') - highlighted.addClass('highlighted') - }) - } - try { - let blob - // the legend (optional) is drawn to the right, at the picture's scale - const legendLayout = exportLegendLayout(o) - const mime = - o.format === 'jpeg' ? 'image/jpeg' : o.format === 'webp' ? 'image/webp' : 'image/png' - if (net3d.active) { - net3d.cacheDirty = true - const s3 = export3dSize(o.scale) - if (o.format === 'svg') { - const text = await buildSvg3d({ ...o, title: o.fileName }).text() - blob = new Blob([composeSvgWithLegend(text, legendLayout, Math.min(o.scale, 8), o.bg)], { - type: 'image/svg+xml', - }) - } else { - const canvas = composeCanvasWithLegend(renderExportCanvas3d(o), legendLayout, s3.k, o.bg) - blob = - o.format === 'pdf' - ? await pdfFromCanvas(canvas, canvas.width / s3.k, canvas.height / s3.k) - : await withDpi(await canvasToBlob(canvas, mime, 0.95), 96 * s3.k) - } - } else if (o.format === 'svg') { - cy.forceRender && cy.forceRender() - const frame = exportFrame(o.area) - const { k } = exportPixelSize(frame, o.scale) - const text = await buildSvg({ ...o, title: o.fileName }).text() - blob = new Blob([composeSvgWithLegend(text, legendLayout, k / frame.unitPx, o.bg)], { - type: 'image/svg+xml', - }) - } else { - cy.forceRender && cy.forceRender() - const frame = exportFrame(o.area) - const { k } = exportPixelSize(frame, o.scale) - const legendScale = k / frame.unitPx - const canvas = composeCanvasWithLegend(renderExportCanvas(o), legendLayout, legendScale, o.bg) - if (o.format === 'pdf') { - // one screen pixel = one point, so the page matches the on-screen size - blob = await pdfFromCanvas(canvas, canvas.width / legendScale, canvas.height / legendScale) - } else { - blob = await withDpi(await canvasToBlob(canvas, mime, 0.95), 96 * legendScale) - } - } - const url = URL.createObjectURL(blob) - const a = document.createElement('a') - a.href = url - a.download = `${o.fileName}.${info.ext}` - document.body.appendChild(a) - a.click() - a.remove() - setTimeout(() => URL.revokeObjectURL(url), 2000) - setStatus('imgStatus', [ - { - level: 'ok', - text: `Saved ${o.fileName}.${info.ext} (${(blob.size / 1024 / 1024).toFixed(blob.size > 1024 * 1024 ? 1 : 2)} MB).`, - }, - ]) - } catch (err) { - setStatus('imgStatus', [ - { level: 'error', text: `The image couldn't be saved: ${err.message}` }, - ]) - } finally { - if (restore) restore() - if (net3d.active) markDirty3d() - btn.disabled = false - } -} - -/* ============================================================ - EDGE DIRECTION - Each edge may be directed (source -> target) or undirected, from its - file or JSON. The view's Direction setting decides how edges are - handled: as in the data, all as directed, or all as undirected. - Arrows, merging, node degrees and centralities, the breadthfirst - layout, node and edge details, the Profiler, Compare and exports all - follow the effective direction. - ============================================================ */ -export function directionMode() { - const el = document.getElementById('edgeDirection') - return el ? el.value : 'data' -} - -export function edgeIsDirected(e) { - const mode = directionMode() - if (mode === 'directed') return true - if (mode === 'undirected') return false - return !!e.data('directed') -} - -// 'undirected', 'directed' or 'mixed' for a collection of edges -export function directionOf(edges) { - let d = 0, - n = 0 - edges.forEach((e) => { - n++ - if (edgeIsDirected(e)) d++ - }) - return d === 0 ? 'undirected' : d === n ? 'directed' : 'mixed' -} - -export function anyEdgeDirected(edges) { - return (edges || cy.edges()).some((e) => edgeIsDirected(e)) -} - -export function arrowsShown() { - return directionMode() !== 'undirected' && anyEdgeDirected(cy.edges()) -} - -export function applyEdgeDirection() { - const shape = document.getElementById('arrowShape').value - const scale = parseFloat(document.getElementById('arrowScale').value) || 1 - document.getElementById('arrowScaleValue').textContent = scale.toFixed(1) + '×' - const anyDirectedData = cy.edges().some((e) => e.data('directed')) - document.getElementById('edgeDirectionHint').textContent = - directionMode() === 'data' - ? anyDirectedData - ? 'Arrows show the edges marked as directed in the data.' - : 'No edge in this view is marked as directed.' - : directionMode() === 'directed' - ? 'Every edge is treated as pointing from its source to its target.' - : anyDirectedData - ? 'Direction is ignored (the default). This network has directed edges: choose "As in the data" to show them.' - : 'Direction is ignored everywhere (the default), as in earlier versions of NORMA.' - cy.batch(() => { - cy.edges().forEach((e) => { - const arrow = edgeIsDirected(e) ? shape : 'none' - if (e.data('arrow') !== arrow) e.data('arrow', arrow) - }) - }) - document.getElementById('arrowControls').hidden = !arrowsShown() - setStyle('edge', { - 'target-arrow-shape': 'data(arrow)', - 'target-arrow-color': 'data(color)', - 'arrow-scale': scale, - }) - // merged edges and haystack edges depend on direction - applyEdgeMerge() - applyEdgeCurveStyle() - invalidateFullMetrics() - if (document.getElementById('sizeMetric').value !== 'fixed') applyNodeSizing() - updateStats() -} - -/* ============================================================ - 3D NETWORK - A second view of the same network, drawn in 3D on a plain canvas. - Everything visual is read from the 2D (Cytoscape) elements, so groups, - colors, pies, shapes, labels, edge labels, arrows, selection, search - highlighting and ticked groups/channels look and behave the same. - Only node positions (x, y, z) and the camera are 3D-specific; both are - kept per view. - Coordinates: x to the right, y down (as in 2D), z away from the viewer. - ============================================================ */ - -/* ---------- 3D force-directed layout (weighted Fruchterman-Reingold) ---------- - Self-contained so it can also run in the background worker. - edges: [{ s, t, w }] with node ids; init: optional { id: [x, y, z] }. */ -export function fr3dLayout(ids, edges, opts) { - opts = opts || {} - const n = ids.length - const out = {} - if (!n) return out - const rand = mulberry32(opts.seed || 123) - const idx = new Map(ids.map((id, i) => [id, i])) - const K = opts.spacing || 60 // ideal edge length - const E = [] - let maxW = 0 - edges.forEach((e) => { - const a = idx.get(e.s), - b = idx.get(e.t) - if (a === undefined || b === undefined || a === b) return - const w = Number.isFinite(e.w) && e.w > 0 ? e.w : 1 - if (w > maxW) maxW = w - E.push([a, b, w]) - }) - // connected components (union-find); each is laid out on its own, as in - // the 2D weighted layout, so unconnected pieces don't drift away - const parent = Int32Array.from({ length: n }, (_, i) => i) - const find = (x) => { - while (parent[x] !== x) { - parent[x] = parent[parent[x]] - x = parent[x] - } - return x - } - E.forEach(([a, b]) => { - const ra = find(a), - rb = find(b) - if (ra !== rb) parent[ra] = rb - }) - const compMap = new Map() - for (let i = 0; i < n; i++) { - const r = find(i) - if (!compMap.has(r)) compMap.set(r, []) - compMap.get(r).push(i) - } - const comps = [...compMap.values()].sort((x, y) => y.length - x.length) - const compOf = new Int32Array(n), - local = new Int32Array(n) - comps.forEach((m, c) => - m.forEach((g, i) => { - compOf[g] = c - local[g] = i - }) - ) - const compEdges = comps.map(() => []) - E.forEach(([a, b, w]) => compEdges[compOf[a]].push([local[a], local[b], w])) - - function layoutComponent(m, CE) { - const N = m - const X = new Float64Array(N), - Y = new Float64Array(N), - Z = new Float64Array(N) - const R0 = K * Math.cbrt(N) * 0.9 - for (let i = 0; i < N; i++) { - let x, y, z - do { - x = rand() * 2 - 1 - y = rand() * 2 - 1 - z = rand() * 2 - 1 - } while (x * x + y * y + z * z > 1) - X[i] = x * R0 - Y[i] = y * R0 - Z[i] = z * R0 - } - if (N === 1) { - X[0] = Y[0] = Z[0] = 0 - return { X, Y, Z, R: K * 0.5 } - } - const iters = opts.iterations || (N <= 300 ? 400 : N <= 1500 ? 250 : 120) - const DX = new Float64Array(N), - DY = new Float64Array(N), - DZ = new Float64Array(N) - const K2 = K * K - const useGrid = N > 1500 - let temp = R0 * 0.5 - const cool = temp / (iters + 1) - for (let it = 0; it < iters; it++) { - if ((it & 3) === 0) workStep(it / iters) - DX.fill(0) - DY.fill(0) - DZ.fill(0) - if (!useGrid) { - for (let i = 0; i < N; i++) { - for (let j = i + 1; j < N; j++) { - let dx = X[i] - X[j], - dy = Y[i] - Y[j], - dz = Z[i] - Z[j] - let d2 = dx * dx + dy * dy + dz * dz - if (d2 < 0.01) { - dx = rand() - 0.5 - dy = rand() - 0.5 - dz = rand() - 0.5 - d2 = 0.01 - } - const f = K2 / d2 - DX[i] += dx * f - DY[i] += dy * f - DZ[i] += dz * f - DX[j] -= dx * f - DY[j] -= dy * f - DZ[j] -= dz * f - } - } - } else { - // repulsion only from nodes in the neighbouring grid cells - const cell = 2 * K - const grid = new Map() - const key = (p, q, r) => p + ',' + q + ',' + r - for (let i = 0; i < N; i++) { - const k = key(Math.floor(X[i] / cell), Math.floor(Y[i] / cell), Math.floor(Z[i] / cell)) - const list = grid.get(k) - if (list) list.push(i) - else grid.set(k, [i]) - } - for (let i = 0; i < N; i++) { - const cx = Math.floor(X[i] / cell), - cy = Math.floor(Y[i] / cell), - cz = Math.floor(Z[i] / cell) - for (let p = -1; p <= 1; p++) - for (let q = -1; q <= 1; q++) - for (let r = -1; r <= 1; r++) { - const list = grid.get(key(cx + p, cy + q, cz + r)) - if (!list) continue - for (let t = 0; t < list.length; t++) { - const j = list[t] - if (j === i) continue - let dx = X[i] - X[j], - dy = Y[i] - Y[j], - dz = Z[i] - Z[j] - let d2 = dx * dx + dy * dy + dz * dz - if (d2 < 0.01) { - dx = rand() - 0.5 - dy = rand() - 0.5 - dz = rand() - 0.5 - d2 = 0.01 - } - const f = K2 / d2 - DX[i] += dx * f - DY[i] += dy * f - DZ[i] += dz * f - } - } - } - } - for (let e = 0; e < CE.length; e++) { - const [p, q, w] = CE[e] - const dx = X[p] - X[q], - dy = Y[p] - Y[q], - dz = Z[p] - Z[q] - const d = Math.sqrt(dx * dx + dy * dy + dz * dz) || 0.01 - const f = (d / K) * (w / maxW) // (d^2 / K) / d, scaled by weight - DX[p] -= dx * f - DY[p] -= dy * f - DZ[p] -= dz * f - DX[q] += dx * f - DY[q] += dy * f - DZ[q] += dz * f - } - for (let i = 0; i < N; i++) { - DX[i] -= X[i] * 0.01 - DY[i] -= Y[i] * 0.01 - DZ[i] -= Z[i] * 0.01 - const d = Math.sqrt(DX[i] * DX[i] + DY[i] * DY[i] + DZ[i] * DZ[i]) || 1 - const step = Math.min(d, temp) - X[i] += (DX[i] / d) * step - Y[i] += (DY[i] / d) * step - Z[i] += (DZ[i] / d) * step - } - temp = Math.max(K * 0.02, temp - cool) - } - let mx = 0, - my = 0, - mz = 0 - for (let i = 0; i < N; i++) { - mx += X[i] - my += Y[i] - mz += Z[i] - } - mx /= N - my /= N - mz /= N - let R = 0 - for (let i = 0; i < N; i++) { - X[i] -= mx - Y[i] -= my - Z[i] -= mz - R = Math.max(R, Math.sqrt(X[i] * X[i] + Y[i] * Y[i] + Z[i] * Z[i])) - } - return { X, Y, Z, R: R + K * 0.5 } - } - - let laidOut = 0 - const parts = comps.map((m, c) => { - S.workRange = [laidOut / n, (laidOut + m.length) / n] - laidOut += m.length - return layoutComponent(m.length, compEdges[c]) - }) - S.workRange = [0, 1] - // pack: the largest piece in the middle, the others on a shell around it - const centers = [[0, 0, 0]] - if (parts.length > 1) { - const others = parts.slice(1) - const maxR = Math.max(...others.map((p) => p.R)) - const area = others.reduce((s, p) => s + Math.PI * (p.R + K * 0.5) ** 2, 0) * 1.4 - const shell = Math.max(parts[0].R + maxR + K, Math.sqrt(area / (4 * Math.PI))) - const golden = Math.PI * (3 - Math.sqrt(5)) - others.forEach((p, i) => { - const m = others.length - const y = m === 1 ? 0 : 1 - (i / (m - 1)) * 2 - const r = Math.sqrt(Math.max(0, 1 - y * y)) - const t = golden * i - centers.push([Math.cos(t) * r * shell, y * shell, Math.sin(t) * r * shell]) - }) - } - comps.forEach((m, c) => { - const p = parts[c], - ctr = centers[c] - m.forEach((g, i) => { - out[ids[g]] = [p.X[i] + ctr[0], p.Y[i] + ctr[1], p.Z[i] + ctr[2]] - }) - }) - return out -} - -export function fr3dAsync(ids, edges, opts, onProgress) { - const worker = ids.length > 150 ? getFrWorker() : null - if (!worker) return Promise.resolve(fr3dLayout(ids, edges, opts)) - const id = ++S.frRequestSeq - return new Promise((resolve) => { - frPending.set(id, { resolve, onProgress, local: () => fr3dLayout(ids, edges, opts) }) - worker.postMessage({ id, kind: 'fr3d', ids, edges, opts }) - }) -} - -// Points spread evenly on a unit sphere (Fibonacci lattice). -export function fibonacciSphere(count) { - const pts = [] - const golden = Math.PI * (3 - Math.sqrt(5)) - for (let i = 0; i < count; i++) { - const y = count === 1 ? 0 : 1 - (i / (count - 1)) * 2 - const r = Math.sqrt(Math.max(0, 1 - y * y)) - const t = golden * i - pts.push([Math.cos(t) * r, y, Math.sin(t) * r]) - } - return pts -} - -// Points filling a ball of the given radius, first ones in the middle. -export function fibonacciBall(count, radius) { - const shell = fibonacciSphere(count) - return shell.map((p, i) => { - const r = radius * Math.cbrt((i + 0.5) / count) - return [p[0] * r, p[1] * r, p[2] * r] - }) -} - -// page wiring, run by main.ts in the original order -export function init() { - ;['imgArea', 'imgScale', 'imgBackground', 'imgHulls', 'imgClean', 'imgLegend'].forEach((id) => { - document.getElementById(id).addEventListener('change', updateExportDialog) - }) - - document - .querySelectorAll('input[name="imgFormat"]') - .forEach((r) => r.addEventListener('change', updateExportDialog)) - - document.getElementById('btnImgSave').addEventListener('click', saveExportImage) - - document - .getElementById('btnImgCancel') - .addEventListener('click', () => document.getElementById('exportDialog').close()) - - document.getElementById('btnExportImage').addEventListener('click', openExportDialog) - - document.getElementById('btnExportImage2').addEventListener('click', openExportDialog) - - ;(function () { - const tag = document.getElementById('statDirection') - const useData = () => { - if (!tag.classList.contains('stat-dir-off')) return - const sel = document.getElementById('edgeDirection') - sel.value = 'data' - // a real change event, so undo and the view's settings follow as usual - sel.dispatchEvent(new Event('change', { bubbles: true })) - } - tag.addEventListener('click', useData) - tag.addEventListener('keydown', (ev) => { - if (ev.key === 'Enter' || ev.key === ' ') { - ev.preventDefault() - useData() - } - }) - })() - - ;['edgeDirection', 'arrowShape'].forEach((id) => { - document.getElementById(id).addEventListener('change', applyEdgeDirection) - }) - - document.getElementById('arrowScale').addEventListener('input', applyEdgeDirection) -} diff --git a/frontend/src/export/draw.ts b/frontend/src/export/draw.ts deleted file mode 100644 index 22526fd..0000000 --- a/frontend/src/export/draw.ts +++ /dev/null @@ -1,516 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { PROFILE_DIRECTED_STATS } from '../directed_stats' -import { PROFILE_STATS, formatStat } from '../wiring' -import { - UPSET_MAX_COLUMNS, - compareState, - exclusiveCounts, - jaccard, - membership, - runComparison, - spearman, -} from '../label_colors' -import { cy } from '../cy' -import { downloadText } from '../layouts/controls' -import { escapeHtml } from '../network_state' -import { layoutLegend, legendIsEmpty, legendModel } from '../clustering/mapping' -import { profSection } from '../profiler' - -/* ---------- drawing ---------- */ -function legendHtml(nets) { - return `
    ${nets - .map( - (n, i) => - `${String.fromCharCode(65 + i)}: ${escapeHtml(n.name)}` - ) - .join('')}
    ` -} - -// Venn diagram for 2 or 3 sets. Regions are labelled with exact counts; -// circle sizes are schematic, not proportional. -function vennSvg(nets, sets) { - const k = sets.length - const counts = exclusiveCounts(membership(sets)) - const c = (m) => (counts.get(m) || 0).toLocaleString() - const W = 360, - H = k === 2 ? 220 : 300 - const circles = - k === 2 - ? [ - { x: 140, y: 110, r: 88 }, - { x: 220, y: 110, r: 88 }, - ] - : [ - { x: 145, y: 115, r: 88 }, - { x: 215, y: 115, r: 88 }, - { x: 180, y: 180, r: 88 }, - ] - const regions = - k === 2 - ? [ - [1, 95, 114], - [2, 265, 114], - [3, 180, 114], - ] - : [ - [1, 105, 100], - [2, 255, 100], - [4, 180, 240], - [3, 180, 72], - [5, 128, 178], - [6, 232, 178], - [7, 180, 140], - ] - let svg = `` - circles.forEach((ci, i) => { - svg += `` - }) - const labelPos = - k === 2 - ? [ - [12, 18, 'start'], - [348, 18, 'end'], - ] - : [ - [12, 18, 'start'], - [348, 18, 'end'], - [180, 294, 'middle'], - ] - labelPos.forEach(([x, y, anchor], i) => { - svg += `${String.fromCharCode(65 + i)} (${sets[i].size.toLocaleString()})` - }) - regions.forEach(([m, x, y]) => { - svg += `${c(m)}` - }) - return svg + '' -} - -// UpSet plot: every non-empty exclusive intersection as a column. -function upsetSvg(nets, sets) { - const k = sets.length - const allCounts = [...exclusiveCounts(membership(sets))].sort( - (a, b) => b[1] - a[1] || a[0] - b[0] - ) - // with many networks there can be hundreds of combinations: show the largest - const counts = allCounts.slice(0, UPSET_MAX_COLUMNS) - const colW = k > 6 ? 22 : 26, - rowH = k > 6 ? 18 : 22, - leftW = 220, - barH = 130, - top = 16 - const W = leftW + counts.length * colW + 20 - const H = top + barH + 10 + k * rowH + 10 - const maxC = Math.max(...counts.map((x) => x[1]), 1) - const maxS = Math.max(...sets.map((s) => s.size), 1) - let svg = `` - // intersection bars - counts.forEach(([m, n], j) => { - const x = leftW + j * colW + 5 - const h = (n / maxC) * barH - const y = top + barH - h - svg += `${n.toLocaleString()} in exactly: ${sets - .map((_, i) => ((m >> i) & 1 ? String.fromCharCode(65 + i) : '')) - .filter(Boolean) - .join(' + ')}` - svg += `${n.toLocaleString()}` - }) - svg += `` - // set rows: size bars (right-aligned toward the matrix) and names - const matrixTop = top + barH + 10 - sets.forEach((set, i) => { - const y = matrixTop + i * rowH - if (i % 2 === 0) - svg += `` - const bw = (set.size / maxS) * 60 - svg += `${set.size.toLocaleString()}` - const short = nets[i].name.length > 20 ? nets[i].name.slice(0, 19) + '…' : nets[i].name - svg += `${escapeHtml(nets[i].name)}${String.fromCharCode(65 + i)} ${escapeHtml(short)}` - }) - // dot matrix - counts.forEach(([m], j) => { - const cx = leftW + j * colW + colW / 2 - const on = [] - for (let i = 0; i < k; i++) { - const cy0 = matrixTop + i * rowH + rowH / 2 - const member = (m >> i) & 1 - if (member) on.push(cy0) - svg += `` - } - if (on.length > 1) - svg += `` - }) - svg += '' - if (allCounts.length > counts.length) { - const rest = allCounts.slice(counts.length).reduce((t, c) => t + c[1], 0) - svg += `

    Showing the ${counts.length} largest of ${allCounts.length} combinations; the other ${allCounts.length - counts.length} hold ${rest.toLocaleString()} items in total (all are in the downloaded table).

    ` - } - return svg -} - -// Square matrix with shaded cells; values in [0, 1] unless `signed`. -function matrixHtml(nets, value, format, signed) { - let html = - '' + - nets - .map( - (n, i) => - `` - ) - .join('') + - '' - nets.forEach((a, i) => { - html += `` - nets.forEach((b, j) => { - const v = value(i, j) - if (v == null || Number.isNaN(v.v)) { - html += '' - return - } - const t = signed ? Math.abs(v.v) : v.v - const hue = signed && v.v < 0 ? '#dc2626' : '#2563eb' - html += `` - }) - html += '' - }) - return html + '
    ${String.fromCharCode(65 + i)}
    ${String.fromCharCode(65 + i)}–${format(v)}
    ' -} - -// Complementary cumulative degree distribution, log-log, one line per network. -function ccdfSvg(nets) { - const W = 520, - H = 260, - L = 48, - R = 12, - T = 12, - B = 34 - const pw = W - L - R, - ph = H - T - B - let maxDeg = 1 - nets.forEach((n) => - n.stats.degree.forEach((d) => { - if (d > maxDeg) maxDeg = d - }) - ) - const lx = Math.log10(Math.max(maxDeg, 10)) - const minP = Math.min( - ...nets.map((n) => 1 / Math.max(1, n.stats.degree.filter((d) => d > 0).length)) - ) - const ly = Math.log10(minP) - const X = (d) => L + (Math.log10(d) / lx) * pw - const Y = (p) => T + (Math.log10(p) / ly) * ph - let svg = `` - svg += `` - for (let e = 0; e <= Math.ceil(lx); e++) { - const d = 10 ** e - if (d > 10 ** lx * 1.001) break - svg += `${d.toLocaleString()}` - } - for (let e = 0; e >= Math.ceil(ly - 1e-9); e--) { - const p = 10 ** e - svg += `${p >= 0.01 ? p : p.toExponential(0)}` - } - svg += `degree k` - svg += `share of nodes with degree ≥ k` - nets.forEach((n) => { - const degs = n.stats.degree.filter((d) => d > 0).sort((a, b) => a - b) - if (!degs.length) return - const pts = [] - const total = degs.length - for (let i = 0; i < degs.length; i++) { - if (i > 0 && degs[i] === degs[i - 1]) continue - pts.push([degs[i], (total - i) / total]) - } - const path = pts - .map(([d, p], i) => `${i ? 'L' : 'M'}${X(d).toFixed(1)},${Y(p).toFixed(1)}`) - .join('') - svg += `` - }) - return svg + '' -} - -export function renderComparison(nets) { - const root = document.getElementById('cmpResults') - root.innerHTML = '' - const letter = (i) => String.fromCharCode(65 + i) - const nodeSets = nets.map((n) => n.nodeSet) - const edgeSets = nets.map((n) => n.edgeSet) - - // overview - const ov = profSection( - 'Networks compared', - document.getElementById('cmpDirected').checked - ? 'Nodes are matched by name, edges by the nodes they join and their direction (channels ignored): A→B, B→A and an undirected A–B are different edges.' - : 'Nodes are matched by name, edges by the pair of nodes they join (channels and direction ignored).' - ) - ov.insertAdjacentHTML( - 'beforeend', - `
    ${nets - .map( - (n, i) => ` -
    -
    ${letter(i)}
    -
    ${escapeHtml(n.name)}
    -
    ${n.kind === 'view' ? 'view' : 'file'} · ${n.nodeSet.size.toLocaleString()} nodes · ${n.edgeSet.size.toLocaleString()} edges
    -
    ` - ) - .join('')}
    ` - ) - const shareNodes = [...membership(nodeSets).values()].filter( - (m) => m === (1 << nets.length) - 1 - ).length - const shareEdges = [...membership(edgeSets).values()].filter( - (m) => m === (1 << nets.length) - 1 - ).length - ov.insertAdjacentHTML( - 'beforeend', - `

    ${shareNodes.toLocaleString()} nodes and ${shareEdges.toLocaleString()} edges are in all ${nets.length} networks.

    ` - ) - root.appendChild(ov) - - // overlaps - ;[ - ['Node overlap', nodeSets, 'nodes'], - ['Edge overlap', edgeSets, 'edges'], - ].forEach(([title, sets, what]) => { - const sec = profSection( - title, - nets.length <= 3 - ? `Left: Venn diagram with the number of ${what} in each region (circle sizes are schematic). Right: the same regions as an UpSet plot, largest first.` - : `UpSet plot: each column is a group of ${what} found in exactly the networks marked below it, largest first. Venn diagrams are shown for two or three networks.` - ) - sec.insertAdjacentHTML('beforeend', legendHtml(nets)) - const cards = document.createElement('div') - cards.className = 'cmp-row' - if (nets.length <= 3) - cards.insertAdjacentHTML( - 'beforeend', - `
    ${vennSvg(nets, sets)}
    ` - ) - cards.insertAdjacentHTML( - 'beforeend', - `
    ${upsetSvg(nets, sets)}
    ` - ) - sec.appendChild(cards) - sec.insertAdjacentHTML( - 'beforeend', - `

    Jaccard similarity of ${what}

    Shared ${what} divided by ${what} in either network; hover a cell for the counts.

    ` + - matrixHtml( - nets, - (i, j) => { - const r = jaccard(sets[i], sets[j]) - return { - v: r.j, - title: `${letter(i)} and ${letter(j)}: ${r.inter.toLocaleString()} shared of ${r.union.toLocaleString()}`, - } - }, - (v) => v.v.toFixed(2) - ) - ) - root.appendChild(sec) - }) - - // degree agreement - const dsec = profSection( - 'Degree agreement on shared nodes', - 'Spearman correlation between the degrees a node has in two networks, over the nodes both contain. Near 1: hubs stay hubs; near 0: unrelated; negative: roles swap.' - ) - dsec.insertAdjacentHTML( - 'beforeend', - matrixHtml( - nets, - (i, j) => { - if (i === j) return { v: 1, title: 'same network' } - const shared = [...nets[i].nodeSet].filter((x) => nets[j].nodeSet.has(x)) - const rho = spearman( - shared.map((x) => nets[i].degreeOf.get(x)), - shared.map((x) => nets[j].degreeOf.get(x)) - ) - return { v: rho, title: `${shared.length.toLocaleString()} shared nodes` } - }, - (v) => v.v.toFixed(2), - true - ) - ) - root.appendChild(dsec) - - // degree distributions - const ccdf = profSection( - 'Degree distributions', - 'Share of nodes with at least a given degree, on log–log axes. Straight, shallow lines indicate heavy-tailed (hub-dominated) networks.' - ) - ccdf.insertAdjacentHTML( - 'beforeend', - legendHtml(nets) + `
    ${ccdfSvg(nets)}
    ` - ) - root.appendChild(ccdf) - - // topology table - const tsec = profSection( - 'Topology side by side', - 'The profiler\u2019s statistics for each network. The highest value in each row is marked.' - ) - let html = - '
    ' + - nets - .map( - (n, i) => - `` - ) - .join('') + - '' - PROFILE_STATS.forEach((st) => { - const vals = nets.map((n) => n.stats[st.key]) - const nums = vals.filter((v) => typeof v === 'number' && Number.isFinite(v)) - const max = nums.length > 1 && new Set(nums).size > 1 ? Math.max(...nums) : null - html += - `` + - vals - .map( - (v) => - `` - ) - .join('') + - '' - }) - if (nets.some((n) => n.directed)) { - html += `` - PROFILE_DIRECTED_STATS.forEach((st) => { - const vals = nets.map((n) => (n.directed ? n.directed[st.key] : undefined)) - const nums = vals.filter((v) => typeof v === 'number' && Number.isFinite(v)) - const max = nums.length > 1 && new Set(nums).size > 1 ? Math.max(...nums) : null - html += - `` + - vals - .map( - (v) => - `` - ) - .join('') + - '' - }) - } - html += '
    Statistic${letter(i)}: ${escapeHtml(n.name)}
    ${escapeHtml(st.label)}${escapeHtml(st.desc)}${escapeHtml(formatStat(v))}
    Direction
    ${escapeHtml(st.label)}${escapeHtml(st.desc)}${v === undefined ? '—' : escapeHtml(formatStat(v))}
    ' - tsec.insertAdjacentHTML('beforeend', html) - root.appendChild(tsec) -} - -function comparisonTsv() { - const nets = compareState.results - if (!nets) return - const letter = (i) => String.fromCharCode(65 + i) - const header = nets.map((n, i) => `${letter(i)} ${n.name}`) - const nodeMask = membership(nets.map((n) => n.nodeSet)) - const edgeMask = membership(nets.map((n) => n.edgeSet)) - const lines = ['# Node membership (1 = present)', ['Node', ...header].join('\t')] - ;[...nodeMask] - .sort((a, b) => (a[0] < b[0] ? -1 : 1)) - .forEach(([id, m]) => lines.push([id, ...nets.map((_, i) => (m >> i) & 1)].join('\t'))) - lines.push( - '', - '# Edge membership (1 = present)', - ['Source', 'Target', 'Direction', ...header].join('\t') - ) - ;[...edgeMask] - .sort((a, b) => (a[0] < b[0] ? -1 : 1)) - .forEach(([key, m]) => - lines.push([...key.split('\t'), ...nets.map((_, i) => (m >> i) & 1)].join('\t')) - ) - lines.push('', '# Topology', ['Statistic', ...header].join('\t')) - PROFILE_STATS.forEach((st) => - lines.push([st.label, ...nets.map((n) => formatStat(n.stats[st.key]))].join('\t')) - ) - if (nets.some((n) => n.directed)) - PROFILE_DIRECTED_STATS.forEach((st) => - lines.push( - [st.label, ...nets.map((n) => (n.directed ? formatStat(n.directed[st.key]) : ''))].join( - '\t' - ) - ) - ) - downloadText('network-comparison.tsv', lines.join('\n') + '\n') -} - -/* ============================================================ - IMAGE EXPORT - PNG, JPEG and WebP are drawn by Cytoscape's own renderer onto a - canvas of the chosen resolution, with group shading drawn underneath - (it lives on a separate layer on screen). SVG is written element by - element, so it stays sharp at any size and can be edited. PDF wraps - a high-resolution JPEG in a single page sized to the image. - Area: the whole shown network, or exactly what is on screen. - ============================================================ */ -export const EXPORT_MAX_SIDE = 16384 -// common browser canvas limit -export const EXPORT_MAX_PIXELS = (16384 * 16384) / 2.2 - -export function exportFrame(area) { - if (area === 'view') { - const z = cy.zoom(), - pan = cy.pan() - return { x1: -pan.x / z, y1: -pan.y / z, w: cy.width() / z, h: cy.height() / z, unitPx: z } - } - const eles = cy.elements().filter((e) => e.visible()) - if (!eles.length) return null - const bb = eles.boundingBox({ includeLabels: true, includeOverlays: false }) - // room for group shading around the outermost nodes - const shading = document.getElementById('showGroupHulls').checked ? hullMarginModel() + 8 : 0 - const pad = Math.max(16, shading) - return { x1: bb.x1 - pad, y1: bb.y1 - pad, w: bb.w + 2 * pad, h: bb.h + 2 * pad, unitPx: 1 } -} - -// Shading margin in model units, matching what the screen shows. -export function hullMarginModel() { - const z = cy.zoom() - return (30 * Math.max(0.15, Math.min(1, z))) / z -} - -// Size of the whole exported picture, including the legend when it is added. -export function withLegendSize(W, H, factor, o) { - if (!o.legend || document.getElementById('imgLegendRow').hidden) return { W, H } - const m = legendModel() - if (legendIsEmpty(m)) return { W, H } - const lay = layoutLegend(m) - return { W: W + Math.round(lay.w * factor), H: Math.max(H, Math.round(lay.h * factor)) } -} - -// "W × H px · N dpi at on-screen size · print size at 300 dpi" for the export dialog. -export function exportSizeText(W, H, factor, format) { - const px = `${W.toLocaleString('en-US')} × ${H.toLocaleString('en-US')} px` - if (format === 'svg') - return `${px} (the picture's size in the file); vector graphics stay sharp at any size and print resolution` - const dpi = Math.round(96 * factor) - const inch = (v) => v.toFixed(v < 10 ? 1 : 0) - const at = (d) => - `${inch(W / d)} × ${inch(H / d)} in (${((W / d) * 2.54).toFixed(1)} × ${((H / d) * 2.54).toFixed(1)} cm)` - let text = `${px} · ${dpi} dpi when printed at the on-screen size, ${at(dpi)} · ${at(300)} at 300 dpi` - if (format === 'pdf') text += ' · one page at the on-screen size' - return text -} - -// Pixel size for a frame at a given scale, reduced to stay within canvas limits. -export function exportPixelSize(frame, scale) { - let k = frame.unitPx * scale - const W = frame.w * k, - H = frame.h * k - const shrink = Math.min( - 1, - EXPORT_MAX_SIDE / W, - EXPORT_MAX_SIDE / H, - Math.sqrt(EXPORT_MAX_PIXELS / (W * H)) - ) - k *= shrink - return { - k, - W: Math.max(1, Math.round(frame.w * k)), - H: Math.max(1, Math.round(frame.h * k)), - limited: shrink < 1, - } -} - -// page wiring, run by main.ts in the original order -export function init() { - document.getElementById('btnCompare').addEventListener('click', runComparison) - - document.getElementById('btnCompareTsv').addEventListener('click', comparisonTsv) -} diff --git a/frontend/src/export/raster.ts b/frontend/src/export/raster.ts deleted file mode 100644 index 6ab443e..0000000 --- a/frontend/src/export/raster.ts +++ /dev/null @@ -1,145 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { cy } from '../cy' -import { drawHullsOnCanvas, hullShapes } from './shading' -import { exportFrame, exportPixelSize } from './draw' - -/* ---------- raster ---------- */ -export function renderExportCanvas(opts) { - const frame = exportFrame(opts.area) - if (!frame) throw new Error('Nothing is shown to export.') - const { k, W, H } = exportPixelSize(frame, opts.scale) - const canvas = document.createElement('canvas') - canvas.width = W - canvas.height = H - const ctx = canvas.getContext('2d') - if (opts.bg) { - ctx.fillStyle = opts.bg - ctx.fillRect(0, 0, W, H) - } - const toOut = (p) => ({ x: (p.x - frame.x1) * k, y: (p.y - frame.y1) * k }) - if (opts.hulls) drawHullsOnCanvas(ctx, hullShapes(toOut, k), k) - const R = cy.renderer() - if (R && typeof R.drawElements === 'function' && typeof R.getCachedZSortedEles === 'function') { - ctx.save() - ctx.setTransform(k, 0, 0, k, -frame.x1 * k, -frame.y1 * k) - R.drawElements(ctx, R.getCachedZSortedEles()) - ctx.restore() - } else { - throw new Error('This browser build of Cytoscape cannot draw images.') - } - return canvas -} - -// Writes the resolution into PNG (pHYs chunk) and JPEG (JFIF density) -// files, so layout and print programs open them at the right size. -const CRC_TABLE = (() => { - const t = new Uint32Array(256) - for (let n = 0; n < 256; n++) { - let c = n - for (let k = 0; k < 8; k++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1 - t[n] = c >>> 0 - } - return t -})() - -function crc32(bytes) { - let c = 0xffffffff - for (let i = 0; i < bytes.length; i++) c = CRC_TABLE[(c ^ bytes[i]) & 0xff] ^ (c >>> 8) - return (c ^ 0xffffffff) >>> 0 -} - -export async function withDpi(blob, dpi) { - if (!blob || !(dpi > 0)) return blob - const buf = new Uint8Array(await blob.arrayBuffer()) - if (blob.type === 'image/png' && buf[12] === 0x49 && buf[13] === 0x48) { - // IHDR first - const ppm = Math.round(dpi / 0.0254) - const chunk = new Uint8Array(21) - const dv = new DataView(chunk.buffer) - dv.setUint32(0, 9) - chunk.set([0x70, 0x48, 0x59, 0x73], 4) // "pHYs" - dv.setUint32(8, ppm) - dv.setUint32(12, ppm) - chunk[16] = 1 // per metre - dv.setUint32(17, crc32(chunk.subarray(4, 17))) - const ihdrEnd = 8 + 25 - const out = new Uint8Array(buf.length + chunk.length) - out.set(buf.subarray(0, ihdrEnd), 0) - out.set(chunk, ihdrEnd) - out.set(buf.subarray(ihdrEnd), ihdrEnd + chunk.length) - return new Blob([out], { type: 'image/png' }) - } - if ( - blob.type === 'image/jpeg' && - buf[2] === 0xff && - buf[3] === 0xe0 && - buf[6] === 0x4a && - buf[7] === 0x46 - ) { - // JFIF APP0 - const d = Math.min(65535, Math.round(dpi)) - buf[13] = 1 // dots per inch - buf[14] = d >> 8 - buf[15] = d & 255 - buf[16] = d >> 8 - buf[17] = d & 255 - return new Blob([buf], { type: 'image/jpeg' }) - } - return blob -} - -export function canvasToBlob(canvas, type, quality) { - return new Promise((resolve, reject) => { - canvas.toBlob( - (b) => - b - ? resolve(b) - : reject( - new Error('The image is too large for this browser. Choose a smaller resolution.') - ), - type, - quality - ) - }) -} - -/* ---------- PDF (single page, embedded JPEG) ---------- */ -export async function pdfFromCanvas(canvas, pageWidthPt, pageHeightPt) { - const jpeg = new Uint8Array(await (await canvasToBlob(canvas, 'image/jpeg', 0.95)).arrayBuffer()) - const enc = new TextEncoder() - const parts = [] - const offsets = [] - let length = 0 - const push = (chunk) => { - const bytes = typeof chunk === 'string' ? enc.encode(chunk) : chunk - parts.push(bytes) - length += bytes.length - } - const w = pageWidthPt.toFixed(2), - h = pageHeightPt.toFixed(2) - const content = `q ${w} 0 0 ${h} 0 0 cm /Im0 Do Q` - push('%PDF-1.4\n%\u00e2\u00e3\u00cf\u00d3\n') - const obj = (n, body) => { - offsets[n] = length - push(`${n} 0 obj\n${body}\nendobj\n`) - } - obj(1, '<< /Type /Catalog /Pages 2 0 R >>') - obj(2, '<< /Type /Pages /Kids [3 0 R] /Count 1 >>') - obj( - 3, - `<< /Type /Page /Parent 2 0 R /MediaBox [0 0 ${w} ${h}] /Resources << /XObject << /Im0 4 0 R >> >> /Contents 5 0 R >>` - ) - offsets[4] = length - push( - `4 0 obj\n<< /Type /XObject /Subtype /Image /Width ${canvas.width} /Height ${canvas.height} /ColorSpace /DeviceRGB /BitsPerComponent 8 /Filter /DCTDecode /Length ${jpeg.length} >>\nstream\n` - ) - push(jpeg) - push('\nendstream\nendobj\n') - obj(5, `<< /Length ${content.length} >>\nstream\n${content}\nendstream`) - const xref = length - let table = `xref\n0 6\n0000000000 65535 f \n` - for (let i = 1; i <= 5; i++) table += `${String(offsets[i]).padStart(10, '0')} 00000 n \n` - push(table + `trailer\n<< /Size 6 /Root 1 0 R >>\nstartxref\n${xref}\n%%EOF\n`) - return new Blob(parts, { type: 'application/pdf' }) -} diff --git a/frontend/src/export/shading.ts b/frontend/src/export/shading.ts deleted file mode 100644 index cf47cc0..0000000 --- a/frontend/src/export/shading.ts +++ /dev/null @@ -1,128 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { S } from '../state' -import { UNGROUPED, effectiveGroupsFor, getUsedGroups } from '../network_state' -import { bubblePathsModel } from '../contours' -import { convexHull, hexToRgba, inflateHull } from '../hulls' -import { cy } from '../cy' -import { hullMarginModel } from './draw' - -/* ---------- group shading geometry, in output coordinates ---------- */ -export function hullShapes(toOut, k) { - if (!document.getElementById('showGroupHulls').checked) return [] - const style = document.getElementById('hullStyle').value - const opacity = parseFloat(document.getElementById('hullOpacity').value) || 0.25 - const margin = hullMarginModel() * k - const shapes = [] - if (style === 'bubble') { - const paths = bubblePathsModel(true) - paths.forEach((d, g) => { - if (d) - shapes.push({ - kind: 'path', - color: S.nodeColorMap[g] || '#888888', - d: transformPathD(d, toOut), - }) - }) - return shapes.map((s) => ({ ...s, style, opacity })) - } - getUsedGroups() - .filter((g) => S.activeGroups.has(g) && g !== UNGROUPED) - .forEach((g) => { - const nodes = cy - .nodes() - .filter((n) => !n.hasClass('hidden-group') && effectiveGroupsFor(n).includes(g)) - if (!nodes.length) return - const pts = nodes.map((n) => { - const p = toOut(n.position()) - return { x: p.x, y: p.y, r: (n.width() * k) / 2 } - }) - const color = S.nodeColorMap[g] || '#888888' - if (pts.length === 1) { - shapes.push({ - kind: 'circle', - color, - cx: pts[0].x, - cy: pts[0].y, - r: pts[0].r + (margin * 28) / 30, - }) - } else if (pts.length === 2) { - shapes.push({ - kind: 'capsule', - color, - a: pts[0], - b: pts[1], - pad: Math.max(pts[0].r, pts[1].r) + margin, - }) - } else { - const maxR = Math.max(...pts.map((p) => p.r)) - shapes.push({ kind: 'blob', color, hull: inflateHull(convexHull(pts), margin + maxR) }) - } - }) - return shapes.map((s) => ({ ...s, style, opacity })) -} - -export function capsulePath(a, b, pad) { - const dx = b.x - a.x, - dy = b.y - a.y - const d = Math.hypot(dx, dy) || 1 - const nx = (-dy / d) * pad, - ny = (dx / d) * pad - return ( - `M${a.x + nx},${a.y + ny}L${b.x + nx},${b.y + ny}` + - `A${pad},${pad} 0 0 0 ${b.x - nx},${b.y - ny}` + - `L${a.x - nx},${a.y - ny}A${pad},${pad} 0 0 0 ${a.x + nx},${a.y + ny}Z` - ) -} - -export function blobPath(points) { - const n = points.length - const mid = (p, q) => ({ x: (p.x + q.x) / 2, y: (p.y + q.y) / 2 }) - const m0 = mid(points[n - 1], points[0]) - let d = `M${m0.x.toFixed(2)},${m0.y.toFixed(2)}` - for (let i = 0; i < n; i++) { - const p = points[i], - m = mid(p, points[(i + 1) % n]) - d += `Q${p.x.toFixed(2)},${p.y.toFixed(2)} ${m.x.toFixed(2)},${m.y.toFixed(2)}` - } - return d + 'Z' -} - -// Maps every coordinate pair of an absolute path (M, L, Q, Z commands). -function transformPathD(d, map) { - return d.replace(/(-?\d*\.?\d+(?:e[-+]?\d+)?),(-?\d*\.?\d+(?:e[-+]?\d+)?)/gi, (_, x, y) => { - const p = map({ x: parseFloat(x), y: parseFloat(y) }) - return `${Math.round(p.x * 100) / 100},${Math.round(p.y * 100) / 100}` - }) -} - -export function hullPathData(s) { - if (s.kind === 'path') return s.d - if (s.kind === 'circle') - return `M${s.cx - s.r},${s.cy}a${s.r},${s.r} 0 1 0 ${2 * s.r},0a${s.r},${s.r} 0 1 0 ${-2 * s.r},0Z` - if (s.kind === 'capsule') return capsulePath(s.a, s.b, s.pad) - return blobPath(s.hull) -} - -export function drawHullsOnCanvas(ctx, shapes, k) { - shapes.forEach((s) => { - const path = new Path2D(hullPathData(s)) - ctx.save() - ctx.fillStyle = hexToRgba(s.color, s.opacity) - if (s.style === 'bubble') { - ctx.fill(path, 'evenodd') - ctx.lineWidth = 1.6 * Math.max(1, k) - ctx.strokeStyle = hexToRgba(s.color, Math.min(1, s.opacity + 0.45)) - ctx.stroke(path) - } else if (s.style === 'fog') { - ctx.filter = `blur(${Math.max(1, ((16 * k) / Math.max(cy.zoom(), 1e-6)) * Math.max(0.15, Math.min(1, cy.zoom())))}px)` - ctx.fill(path) - } else { - ctx.fill(path) - ctx.lineWidth = 1.5 * Math.max(1, k) - ctx.strokeStyle = hexToRgba(s.color, Math.min(1, s.opacity + 0.35)) - ctx.stroke(path) - } - ctx.restore() - }) -} diff --git a/frontend/src/export/svg.ts b/frontend/src/export/svg.ts deleted file mode 100644 index e5ff507..0000000 --- a/frontend/src/export/svg.ts +++ /dev/null @@ -1,319 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { PIE_MAX_SLICES } from '../network_state' -import { cy } from '../cy' -import { exportFrame, exportPixelSize, hullMarginModel } from './draw' -import { hullPathData, hullShapes } from './shading' - -/* ---------- SVG ---------- */ -const svgEsc = (v) => - String(v).replace( - /[&<>"]/g, - (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"' })[c] - ) - -const fmt = (v) => (Math.round(v * 100) / 100).toString() - -function nodeShapeSvg(n, fill, strokeAttrs) { - const shape = n.style('shape') - const p = n.position(), - w = n.width(), - h = n.height() - if (shape === 'ellipse') - return `` - if ( - shape === 'rectangle' || - shape === 'square' || - shape === 'barrel' || - /round-?rectangle/.test(shape) - ) { - const rx = /round/.test(shape) - ? Math.min(w / 4, h / 4, 8) - : shape === 'barrel' - ? Math.min(w, h) * 0.15 - : 0 - return `` - } - const def = cy.renderer().nodeShapes[shape] - if (def && def.points) { - const pts = [] - for (let i = 0; i < def.points.length; i += 2) { - pts.push(`${fmt(p.x + (def.points[i] * w) / 2)},${fmt(p.y + (def.points[i + 1] * h) / 2)}`) - } - return `` - } - return `` -} - -function pieSvg(n) { - if (n.style('shape') !== 'ellipse') return '' - const p = n.position() - const r = Math.min(n.width(), n.height()) / 2 - let start = -Math.PI / 2 - let out = '' - for (let i = 1; i <= PIE_MAX_SLICES; i++) { - const size = parseFloat(n.data('pieSize' + i)) || 0 - if (size <= 0) continue - const color = n.data('pieColor' + i) - if (size >= 99.999) { - out += `` - break - } - const end = start + (size / 100) * 2 * Math.PI - const large = end - start > Math.PI ? 1 : 0 - out += - `` - start = end - } - return out -} - -function edgePathSvg(e) { - const rs = e._private.rscratch || {} - const pts = rs.allpts - if (pts && pts.length >= 4 && pts.every(Number.isFinite)) { - if (['bezier', 'multibezier', 'self', 'compound'].includes(rs.edgeType) && pts.length >= 6) { - let d = `M${fmt(pts[0])},${fmt(pts[1])}` - for (let i = 2; i + 3 < pts.length; i += 4) - d += `Q${fmt(pts[i])},${fmt(pts[i + 1])} ${fmt(pts[i + 2])},${fmt(pts[i + 3])}` - return { d, mid: bezierMid(pts) } - } - let d = `M${fmt(pts[0])},${fmt(pts[1])}` - for (let i = 2; i + 1 < pts.length; i += 2) d += `L${fmt(pts[i])},${fmt(pts[i + 1])}` - const m = Math.floor((pts.length / 2 - 1) / 2) * 2 - return { - d, - mid: { - x: (pts[m] + pts[m + 2]) / 2, - y: (pts[m + 1] + pts[m + 3]) / 2, - angle: Math.atan2(pts[m + 3] - pts[m + 1], pts[m + 2] - pts[m]), - }, - } - } - const a = e.source().position(), - b = e.target().position() - return { - d: `M${fmt(a.x)},${fmt(a.y)}L${fmt(b.x)},${fmt(b.y)}`, - mid: { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2, angle: Math.atan2(b.y - a.y, b.x - a.x) }, - } -} - -function bezierMid(pts) { - // middle quadratic segment, evaluated at t = 0.5 - const segs = Math.floor((pts.length - 2) / 4) - const s = Math.floor((segs - 1) / 2) * 4 - const x0 = pts[s], - y0 = pts[s + 1], - cx = pts[s + 2], - cy0 = pts[s + 3], - x1 = pts[s + 4], - y1 = pts[s + 5] - const t = segs % 2 ? 0.5 : 1 - const x = (1 - t) * (1 - t) * x0 + 2 * (1 - t) * t * cx + t * t * x1 - const y = (1 - t) * (1 - t) * y0 + 2 * (1 - t) * t * cy0 + t * t * y1 - const dx = 2 * (1 - t) * (cx - x0) + 2 * t * (x1 - cx), - dy = 2 * (1 - t) * (cy0 - y0) + 2 * t * (y1 - cy0) - return { x, y, angle: Math.atan2(dy, dx) } -} - -// Arrowhead at an edge's target, drawn like Cytoscape does: its outline in -// unit coordinates (tip at the origin, back toward negative y), scaled with -// the edge width and turned along the edge's last segment. -function arrowSvg(e, shape, width) { - const rs = e._private.rscratch || {} - const def = cy.renderer().arrowShapes && cy.renderer().arrowShapes[shape] - if (!def || !def.points || !Number.isFinite(rs.arrowEndX)) return '' - const pts = rs.allpts || [] - const endX = Number.isFinite(rs.endX) ? rs.endX : pts[pts.length - 2] - const endY = Number.isFinite(rs.endY) ? rs.endY : pts[pts.length - 1] - let dx = rs.arrowEndX - endX, - dy = rs.arrowEndY - endY - let len = Math.hypot(dx, dy) - if (len < 1e-6) { - // fall back to the direction of the last path segment - const px = pts[pts.length - 4], - py = pts[pts.length - 3] - dx = rs.arrowEndX - px - dy = rs.arrowEndY - py - len = Math.hypot(dx, dy) || 1 - } - const ux = dx / len, - uy = dy / len // forward along the edge - const size = Math.max(Math.pow(width * 13.37, 0.9), 29) * (e.pstyle('arrow-scale').value || 1) - const poly = [] - for (let i = 0; i < def.points.length; i += 2) { - const px = def.points[i] * size, - py = def.points[i + 1] * size - poly.push(`${fmt(rs.arrowEndX - uy * px + ux * py)},${fmt(rs.arrowEndY + ux * px + uy * py)}`) - } - return `` -} - -function textSvg(text, x, y, attrs, fontPx, color, halo, haloWidth, rotate) { - const upright = rotate - ? rotate > Math.PI / 2 || rotate < -Math.PI / 2 - ? rotate + Math.PI - : rotate - : 0 - const transform = upright - ? ` transform="rotate(${fmt((upright * 180) / Math.PI)} ${fmt(x)} ${fmt(y)})"` - : '' - const haloAttr = - haloWidth > 0 - ? ` stroke="${halo}" stroke-width="${fmt(haloWidth * 2)}" stroke-linejoin="round" paint-order="stroke"` - : '' - return `${svgEsc(text)}` -} - -export function buildSvg(opts) { - const frame = exportFrame(opts.area) - if (!frame) throw new Error('Nothing is shown to export.') - const { W, H } = exportPixelSize(frame, opts.scale) - const out = [] - out.push(``) - out.push( - `` - ) - out.push(`${svgEsc(opts.title || 'NORMA network')}`) - if (opts.bg) - out.push( - `` - ) - - if (opts.hulls) { - const shapes = hullShapes((p) => p, 1) - if (shapes.length) { - const fog = shapes[0].style === 'fog' - if (fog) - out.push( - `` - ) - out.push('') - shapes.forEach((s) => { - const stroke = fog - ? '' - : ` stroke="${s.color}" stroke-opacity="${fmt(Math.min(1, s.opacity + 0.35))}" stroke-width="${fmt(1.5 / Math.max(cy.zoom(), 0.01))}"` - const rule = s.kind === 'path' ? ' fill-rule="evenodd"' : '' - out.push( - `` - ) - }) - out.push('') - } - } - - const visible = (ele) => ele.visible() && ele.effectiveOpacity() > 0 - const inFrame = (bb) => - !( - bb.x2 < frame.x1 || - bb.y2 < frame.y1 || - bb.x1 > frame.x1 + frame.w || - bb.y1 > frame.y1 + frame.h - ) - - out.push('') - const edgeLabels = [] - cy.edges().forEach((e) => { - if (!visible(e) || !inFrame(e.boundingBox({ includeLabels: false }))) return - const { d, mid } = edgePathSvg(e) - const width = e.pstyle('width').pfValue - const arrowShape = e.style('target-arrow-shape') - const hasArrow = arrowShape && arrowShape !== 'none' - out.push( - `${svgEsc(`${e.data('source')} ${hasArrow ? '→' : '–'} ${e.data('target')} (${e.data('type')})`)}` - ) - if (hasArrow) { - const arrow = arrowSvg(e, arrowShape, width) - if (arrow) out.push(arrow) - } - const label = e.style('label') - if (label) { - const rs = e._private.rscratch || {} - const pos = Number.isFinite(rs.labelX) ? { x: rs.labelX, y: rs.labelY } : mid - const rot = - e.style('text-rotation') === 'autorotate' - ? Number.isFinite(rs.labelAutoAngle) - ? rs.labelAutoAngle - : mid.angle - : 0 - edgeLabels.push( - textSvg( - label, - pos.x, - pos.y, - ' text-anchor="middle" dominant-baseline="central"', - e.pstyle('font-size').pfValue, - e.style('color'), - e.style('text-background-color'), - 2, - rot - ) - ) - } - }) - out.push('') - - out.push('') - const nodeLabels = [] - cy.nodes().forEach((n) => { - if (!visible(n) || !inFrame(n.boundingBox({ includeLabels: false }))) return - const bw = n.pstyle('border-width').pfValue - const strokeAttrs = - bw > 0 ? ` stroke="${n.style('border-color')}" stroke-width="${fmt(bw)}"` : '' - const opacity = n.effectiveOpacity() - out.push( - `${svgEsc(n.id())}` - ) - out.push(nodeShapeSvg(n, n.style('background-color'), '')) - out.push(pieSvg(n)) - if (bw > 0) out.push(nodeShapeSvg(n, 'none', strokeAttrs)) - out.push('') - const label = n.style('label') - if (label) { - const p = n.position(), - w = n.width(), - h = n.height() - const valign = n.style('text-valign'), - halign = n.style('text-halign') - const mx = n.pstyle('text-margin-x').pfValue || 0, - my = n.pstyle('text-margin-y').pfValue || 0 - let x = p.x + mx, - y = p.y + my, - anchor = 'middle', - baseline = 'central' - if (valign === 'top') { - y = p.y - h / 2 + my - baseline = 'text-after-edge' - } else if (valign === 'bottom') { - y = p.y + h / 2 + my - baseline = 'text-before-edge' - } - if (halign === 'left') { - x = p.x - w / 2 + mx - anchor = 'end' - } else if (halign === 'right') { - x = p.x + w / 2 + mx - anchor = 'start' - } - nodeLabels.push( - textSvg( - label, - x, - y, - ` text-anchor="${anchor}" dominant-baseline="${baseline}"`, - n.pstyle('font-size').pfValue, - n.style('color'), - n.style('text-outline-color'), - n.pstyle('text-outline-width').pfValue, - 0 - ) - ) - } - }) - out.push('') - if (edgeLabels.length) out.push('', ...edgeLabels, '') - if (nodeLabels.length) out.push('', ...nodeLabels, '') - out.push('') - return new Blob([out.join('\n')], { type: 'image/svg+xml' }) -} diff --git a/frontend/src/export_norma.ts b/frontend/src/export_norma.ts deleted file mode 100644 index 6cafb10..0000000 --- a/frontend/src/export_norma.ts +++ /dev/null @@ -1,257 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { S } from './state' -import { UNGROUPED, getUsedGroups, groupLabel } from './network_state' -import { cy } from './cy' -import { downloadText, listSample, normalizeCssColor, plural, setStatus } from './layouts/controls' -import { edgeIsDirected } from './export/dialog' -import { exportEdges, exportNodes, exportShownOnly } from './metrics' -import { getUsedTypes } from './hulls' - -/* ---------- NORMA export ---------- */ -// NORMA can't read tabs or line breaks inside names, and node names can't -// contain commas (the annotation separator). Group names may keep commas. -function normaSafeName(name, renamed, isNode = true) { - let safe = String(name).replace(/[\t\r\n]+/g, ' ') - if (isNode) safe = safe.replace(/,/g, ';') - if (safe !== String(name)) renamed.add(String(name)) - return safe -} - -function renamedNote(renamed) { - return renamed.size - ? [ - { - level: 'warn', - text: `Changed ${plural(renamed.size, 'name')} that NORMA can't read (commas in node names became semicolons, tabs became spaces): ${listSample([...renamed])}.`, - }, - ] - : [] -} - -function connectedNodeIds() { - const ids = new Set() - exportEdges().forEach((e) => { - if (e.data('source') !== e.data('target')) { - ids.add(e.data('source')) - ids.add(e.data('target')) - } - }) - return ids -} - -function requireLoadedNetwork() { - if (exportEdges().length) return true - setStatus('saveStatus', [ - { - level: 'error', - text: cy.edges().length - ? 'No edges are shown: tick at least one group and channel, or untick "Only ticked groups and channels".' - : 'Load a network with at least one edge before saving NORMA files.', - }, - ]) - return false -} - -export function exportNormaNetwork() { - if (!requireLoadedNetwork()) return - const renamed = new Set() - const types = getUsedTypes() - const keepTypes = document.getElementById('normaKeepTypes').checked && types.length > 1 - const rowsByKey = new Map() - let selfLoops = 0, - merged = 0 - exportEdges().forEach((e) => { - const s = e.data('source'), - t = e.data('target') - if (s === t) { - selfLoops++ - return - } - const type = e.data('type') - const directed = edgeIsDirected(e) - const pair = directed ? 'D\t' + s + '\t' + t : 'U\t' + (s < t ? s + '\t' + t : t + '\t' + s) - const key = pair + (keepTypes ? '\t' + type : '') - const w = e.data('weight') - const row = rowsByKey.get(key) - if (row) { - merged++ - if (typeof w === 'number') row.weight = row.weight === undefined ? w : Math.max(row.weight, w) - } else { - rowsByKey.set(key, { - source: s, - target: t, - type, - directed, - weight: typeof w === 'number' ? w : undefined, - }) - } - }) - const rows = [...rowsByKey.values()] - const withDirection = rows.some((r) => r.directed) - const weighted = rows.some((r) => r.weight !== undefined) - const unweighted = weighted ? rows.filter((r) => r.weight === undefined).length : 0 - const header = ['Source', 'Target'] - if (weighted) header.push('Weight') - if (keepTypes) header.push('Type') - if (withDirection) header.push('Direction') - const lines = [header.join('\t')] - rows.forEach((r) => { - const cols = [normaSafeName(r.source, renamed), normaSafeName(r.target, renamed)] - if (weighted) cols.push(String(r.weight === undefined ? 1 : r.weight)) - if (keepTypes) cols.push(normaSafeName(r.type, renamed, false)) - if (withDirection) cols.push(r.directed ? 'directed' : 'undirected') - lines.push(cols.join('\t')) - }) - downloadText('norma-network.txt', lines.join('\n') + '\n') - - const notes = [ - { - level: 'ok', - text: `Saved norma-network.txt with ${plural(rows.length, 'row')}${weighted ? ', weighted' : ''}${keepTypes ? `, ${plural(types.length, 'type')} in a Type column` : ''}${withDirection ? ', with a Direction column' : ''}.`, - }, - ] - if (merged) - notes.push({ - level: 'ok', - text: keepTypes - ? `Merged ${plural(merged, 'repeated edge')} with the same pair and channel.` - : `Merged ${plural(merged, 'parallel edge')} into single connections${weighted ? ', keeping the highest weight' : ''}. Tick "Keep channels as a Type column" to keep them apart.`, - }) - if (document.getElementById('normaKeepTypes').checked && types.length <= 1) - notes.push({ - level: 'ok', - text: 'The view has a single channel, so no Type column was needed.', - }) - if (keepTypes || withDirection) - notes.push({ - level: 'warn', - text: `The ${[keepTypes && 'Type', withDirection && 'Direction'].filter(Boolean).join(' and ')} column${keepTypes && withDirection ? 's are' : ' is'} new in NORMA 3.0; earlier versions of NORMA read only Source, Target and Weight.`, - }) - if (unweighted) - notes.push({ - level: 'warn', - text: `${plural(unweighted, 'row')} had no weight and got weight 1.`, - }) - if (selfLoops) notes.push({ level: 'ok', text: `Left out ${plural(selfLoops, 'self-loop')}.` }) - const isolated = exportNodes().length - connectedNodeIds().size - if (isolated) - notes.push({ - level: 'warn', - text: `${plural(isolated, 'node has', 'nodes have')} no edges and can't appear in a network file.`, - }) - setStatus('saveStatus', [...notes, ...renamedNote(renamed)]) -} - -export function exportNormaAnnotation() { - if (!requireLoadedNetwork()) return - const groups = getUsedGroups().filter( - (g) => g !== UNGROUPED && (!exportShownOnly() || S.activeGroups.has(g)) - ) - if (!groups.length) { - setStatus('saveStatus', [ - { - level: 'error', - text: 'This view has no ticked groups, so there is no annotation to save.', - }, - ]) - return - } - const renamed = new Set() - const connected = connectedNodeIds() - // A group's display label is its NORMA name, unless two groups share a - // label; then the group key keeps them apart. - const labelCounts = {} - groups.forEach((g) => { - const l = groupLabel(g) - labelCounts[l] = (labelCounts[l] || 0) + 1 - }) - const membersOf = {} - exportNodes().forEach((n) => - (n.data('groups') || []).forEach((g) => (membersOf[g] = membersOf[g] || []).push(n.id())) - ) - const skippedGroups = [] - const droppedNodes = new Set() - const lines = [] - groups.forEach((g) => { - const members = membersOf[g] || [] - const present = members.filter((id) => connected.has(id)) - members.forEach((id) => { - if (!connected.has(id)) droppedNodes.add(id) - }) - const name = labelCounts[groupLabel(g)] > 1 ? g : groupLabel(g) - if (!present.length) { - skippedGroups.push(name) - return - } - lines.push( - `${normaSafeName(name, renamed, false)}\t${present.map((id) => normaSafeName(id, renamed)).join(',')}` - ) - }) - if (!lines.length) { - setStatus('saveStatus', [ - { - level: 'error', - text: 'None of the grouped nodes have edges, so the annotation would be empty.', - }, - ]) - return - } - downloadText('norma-annotation.txt', lines.join('\n') + '\n') - const notes = [ - { level: 'ok', text: `Saved norma-annotation.txt with ${plural(lines.length, 'group')}.` }, - ] - if (droppedNodes.size) - notes.push({ - level: 'warn', - text: `Left out ${plural(droppedNodes.size, 'node')} without edges, since NORMA needs every annotated node in the network file: ${listSample([...droppedNodes])}.`, - }) - if (skippedGroups.length) - notes.push({ - level: 'warn', - text: `Left out ${plural(skippedGroups.length, 'group')} whose nodes have no edges: ${listSample(skippedGroups)}.`, - }) - setStatus('saveStatus', [...notes, ...renamedNote(renamed)]) -} - -export function exportNormaColors() { - if (!requireLoadedNetwork()) return - const renamed = new Set() - const connected = connectedNodeIds() - const nodes = exportNodes().filter((n) => connected.has(n.id())) - const useOwn = nodes.some((n) => n.data('nodeColor')) - const lines = [] - nodes.forEach((n) => { - let color - if (useOwn) { - color = n.data('nodeColor') - } else { - const g = (n.data('groups') || []).find((x) => x !== UNGROUPED) - color = g ? S.nodeColorMap[g] : null - } - if (!color) return - // canvas-normalized rgba() values aren't NORMA colors; keep hex only - const hex = String(color).startsWith('#') ? color : normalizeCssColor(color) || '' - if (!hex.startsWith('#')) return - lines.push(`${normaSafeName(n.id(), renamed)}\t${hex}`) - }) - if (!lines.length) { - setStatus('saveStatus', [ - { - level: 'error', - text: 'No node has a color to save. Load an expression file, or give nodes groups so their group colors can be used.', - }, - ]) - return - } - downloadText('norma-expression.txt', lines.join('\n') + '\n') - setStatus('saveStatus', [ - { - level: 'ok', - text: useOwn - ? `Saved norma-expression.txt with the expression colors of ${plural(lines.length, 'node')}.` - : `Saved norma-expression.txt using each node's first group color (${plural(lines.length, 'node')}), since no expression colors are loaded.`, - }, - ...renamedNote(renamed), - ]) -} diff --git a/frontend/src/group_network.ts b/frontend/src/group_network.ts deleted file mode 100644 index 5814b4b..0000000 --- a/frontend/src/group_network.ts +++ /dev/null @@ -1,101 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { S } from './state' -import { UNGROUPED, effectiveGroupsFor, getUsedGroups, groupLabel } from './network_state' -import { activeView, openInNewView } from './profiler' -import { applyGroupColorOverrides } from './arena3d' -import { cy } from './cy' -import { loadData } from './hulls' -import { plural, setStatus } from './layouts/controls' -import { shownEdges, shownNodes } from './metrics' -import { switchTab } from './wiring' - -/* ---------- group network ---------- */ -export function openGroupNetwork() { - if (!cy.nodes().length) return - const order = getUsedGroups().filter((g) => S.activeGroups.has(g) && g !== UNGROUPED) - if (order.length < 2) { - setStatus('gaStatus', [ - { level: 'error', text: 'The group network needs at least two ticked groups.' }, - ]) - return - } - const nodes = shownNodes() - const groupsOf = new Map( - nodes.map((n) => [n.id(), effectiveGroupsFor(n).filter((g) => g !== UNGROUPED)]) - ) - const size = new Map(order.map((g) => [g, 0])) - groupsOf.forEach((gs) => gs.forEach((g) => size.set(g, (size.get(g) || 0) + 1))) - const inside = new Map(order.map((g) => [g, 0])) - const between = new Map() - const seenPairs = new Set() - shownEdges(true).forEach((e) => { - const s = e.data('source'), - t = e.data('target') - if (s === t || !groupsOf.has(s) || !groupsOf.has(t)) return - const pk = s < t ? s + '\t' + t : t + '\t' + s - if (seenPairs.has(pk)) return // parallel channels count once - seenPairs.add(pk) - const gs = groupsOf.get(s), - gt = groupsOf.get(t) - gs.forEach((a) => - gt.forEach((b) => { - if (a === b) { - inside.set(a, inside.get(a) + 1) - return - } - const key = a < b ? a + '\u0000' + b : b + '\u0000' + a - between.set(key, (between.get(key) || 0) + 1) - }) - ) - }) - const maxSize = Math.max(...size.values()) - const data = { - nodes: order - .filter((g) => size.get(g)) - .map((g) => ({ - id: groupLabel(g), - groups: [groupLabel(g)], - size: Math.round(30 + 70 * Math.sqrt(size.get(g) / maxSize)), - members: size.get(g), - 'edges inside': inside.get(g), - })), - edges: [...between].map(([key, w]) => { - const [a, b] = key.split('\u0000') - return { - source: groupLabel(a), - target: groupLabel(b), - weight: w, - type: 'connections', - connections: w, - } - }), - groupOrder: order.filter((g) => size.get(g)).map((g) => groupLabel(g)), - nodeColors: Object.fromEntries( - order.map((g) => [groupLabel(g), S.nodeColorMap[g] || '#888888']) - ), - edgeColors: { connections: '#64748b' }, - config: { - layoutSelect: 'fr', - edgeWidthMode: 'weight', - edgeWidthMin: '1', - edgeWidthMax: '10', - sizeMetric: 'fixed', - showEdgeLabels: true, - edgeLabelContent: 'attr:connections', - edgeLabelSize: '11', - }, - } - const v = activeView() - openInNewView(`${v ? v.name : 'View'}: group network`, () => { - loadData(data) - applyGroupColorOverrides(data.nodeColors) - }) - switchTab('network') - setStatus('gaStatus', [ - { - level: 'ok', - text: `Opened the group network: ${plural(data.nodes.length, 'group')}, ${plural(data.edges.length, 'connection')} between groups. Node size follows group size; edge width follows the number of connections.`, - }, - ]) -} diff --git a/frontend/src/hulls.test.ts b/frontend/src/hulls.test.ts deleted file mode 100644 index 1f9d904..0000000 --- a/frontend/src/hulls.test.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { expect, test } from 'vitest' -import { convexHull, hexToRgba, inflateHull } from './hulls' - -type Pt = { x: number; y: number } - -test('convexHull drops interior points and keeps counter-clockwise corners', () => { - const pts = [ - { x: 0, y: 0 }, - { x: 2, y: 0 }, - { x: 2, y: 2 }, - { x: 0, y: 2 }, - { x: 1, y: 1 }, - { x: 1, y: 0.5 }, - ] - const hull = convexHull(pts) - expect(hull).toHaveLength(4) - expect(hull.map((p: Pt) => `${p.x},${p.y}`)).toEqual(['0,0', '2,0', '2,2', '0,2']) -}) - -test('convexHull leaves fewer than three points alone', () => { - expect(convexHull([{ x: 1, y: 1 }])).toEqual([{ x: 1, y: 1 }]) - expect(convexHull([])).toEqual([]) -}) - -test('inflateHull pushes every vertex away from the centroid by the padding', () => { - const square = [ - { x: -1, y: -1 }, - { x: 1, y: -1 }, - { x: 1, y: 1 }, - { x: -1, y: 1 }, - ] - const big = inflateHull(square, 2) - big.forEach((p: Pt, i: number) => { - const before = Math.hypot(square[i].x, square[i].y) - expect(Math.hypot(p.x, p.y)).toBeCloseTo(before + 2) - }) -}) - -test('hexToRgba', () => { - expect(hexToRgba('#ff8000', 0.5)).toBe('rgba(255,128,0,0.5)') - expect(hexToRgba('#zz', 1)).toBe('rgba(0,0,0,1)') -}) diff --git a/frontend/src/hulls.ts b/frontend/src/hulls.ts deleted file mode 100644 index 04fb50d..0000000 --- a/frontend/src/hulls.ts +++ /dev/null @@ -1,787 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { - EDGE_PALETTES, - EDGE_TYPES, - NODE_PALETTES, - ORIGINAL_EDGE_TYPES, - colorAtIndex, -} from './palette' -import { - LARGE_NETWORK_NODES, - applyNodeSizing, - cancelFrJobs, - invalidateFullMetrics, - updateStats, -} from './metrics' -import { - MAX_NETWORK_NODES, - RESERVED_EDGE_KEYS, - RESERVED_NODE_KEYS, - UNGROUPED, - UNGROUPED_LABEL, - buildAttrSchema, - cleanValues, - collectAttrs, - colorForGroup, - computeNodeVisualFields, - effectiveGroupsFor, - escapeHtml, - getUsedGroups, - groupDescription, - groupLabel, - nextAutoEdgeColor, - refreshNodeVisual, - renderAttrSchema, - sanitizeColor, - setGroupOrder, -} from './network_state' -import { S } from './state' -import { - SHAPE_BY_KEY, - applyEdgeCurveStyle, - applyEdgeOpacity, - applyEdgeWidth, - closeShapePopover, - hideEdgePopup, - hideInfo, - invalidateViewBox, - openShapePopover, - scheduleBundling, - shapePopoverGroup, - shapeSvg, - showGroupInfo, - updateLabelStyle, -} from './profiler' -import { applyEdgeDirection } from './export/dialog' -import { applyEdgeMerge, applyTypeVisibility } from './parallel_edges' -import { applyTheme } from './themes' -import { applyValueColors } from './clustering/mapping' -import { bumpDataVersion } from './demo_downloads' -import { currentTab, switchTab } from './wiring' -import { cy } from './cy' -import { drawBubbleSets } from './contours' -import { layoutMode, runLayout, runStrategyLayout } from './layouts/run' -import { plural, updateRefreshState, updateStrategyUI } from './layouts/controls' -import { reset3dForNewData } from './view3d/tab' -import { takeNextLoadLayout } from './examples' -import { toast } from './enrichment' -import { updateValueScalePreview } from './clustering/wiring' - -/* ---------- group highlighting: convex hulls / fog clouds ---------- */ -const hullCanvas = document.getElementById('groupHullCanvas') - -const hullCtx = hullCanvas.getContext('2d') - -// The shading canvas must match Cytoscape's drawing area and the current -// pixel ratio. The pixel ratio can change without a 'resize' event (a window -// dragged between a Retina and a standard display on macOS), and the canvas -// area can change size without one too, so drawGroupHulls() re-checks both. -export let hullCanvasCss = { w: 0, h: 0, dpr: 0 } - -export function resizeHullCanvas() { - const rect = document.getElementById('canvas').getBoundingClientRect() - const w = rect.width || cy.width(), - h = rect.height || cy.height() - const dpr = window.devicePixelRatio || 1 - hullCanvas.width = Math.max(1, Math.round(w * dpr)) - hullCanvas.height = Math.max(1, Math.round(h * dpr)) - hullCanvas.style.width = w + 'px' - hullCanvas.style.height = h + 'px' - hullCanvasCss = { w, h, dpr } - hullCtx.setTransform(dpr, 0, 0, dpr, 0, 0) -} - -function hullCanvasStale() { - return ( - hullCanvasCss.dpr !== (window.devicePixelRatio || 1) || - Math.abs(hullCanvasCss.w - cy.width()) > 0.5 || - Math.abs(hullCanvasCss.h - cy.height()) > 0.5 - ) -} - -// Andrew's monotone chain convex hull. -export function convexHull(points) { - const pts = points.slice().sort((a, b) => a.x - b.x || a.y - b.y) - const n = pts.length - if (n < 3) return pts - const cross = (o, a, b) => (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x) - const lower = [] - for (const p of pts) { - while (lower.length >= 2 && cross(lower[lower.length - 2], lower[lower.length - 1], p) <= 0) - lower.pop() - lower.push(p) - } - const upper = [] - for (let i = n - 1; i >= 0; i--) { - const p = pts[i] - while (upper.length >= 2 && cross(upper[upper.length - 2], upper[upper.length - 1], p) <= 0) - upper.pop() - upper.push(p) - } - upper.pop() - lower.pop() - return lower.concat(upper) -} - -// Pushes each hull vertex outward from the hull's centroid so the shape -// clears the nodes themselves rather than hugging their centers. -export function inflateHull(hull, padding) { - const cx = hull.reduce((s, p) => s + p.x, 0) / hull.length - const cy0 = hull.reduce((s, p) => s + p.y, 0) / hull.length - return hull.map((p) => { - const dx = p.x - cx, - dy = p.y - cy0 - const len = Math.sqrt(dx * dx + dy * dy) || 1 - return { x: p.x + (dx / len) * padding, y: p.y + (dy / len) * padding } - }) -} - -export function hexToRgba(hex, alpha) { - const r = parseInt(hex.slice(1, 3), 16) || 0 - const g = parseInt(hex.slice(3, 5), 16) || 0 - const b = parseInt(hex.slice(5, 7), 16) || 0 - return `rgba(${r},${g},${b},${alpha})` -} - -function paintHullPath(ctx, color, opacity, style) { - ctx.fillStyle = hexToRgba(color, opacity) - if (style === 'fog') { - ctx.filter = 'blur(16px)' - ctx.fill() - ctx.filter = 'none' - } else { - ctx.fill() - ctx.lineWidth = 1.5 - ctx.strokeStyle = hexToRgba(color, Math.min(1, opacity + 0.35)) - ctx.stroke() - } -} - -// Shading margin in screen pixels: full size from 100% zoom up, shrinking -// with the network when zoomed out so neighbouring groups stay apart. -let hullMarginScale = 1 - -export function drawGroupHulls() { - hullMarginScale = Math.max(0.15, Math.min(1, cy.zoom())) - if (!hullCtx) return - if (hullCanvasStale()) resizeHullCanvas() - hullCtx.setTransform(hullCanvasCss.dpr, 0, 0, hullCanvasCss.dpr, 0, 0) - hullCtx.clearRect(0, 0, hullCanvasCss.w, hullCanvasCss.h) - if (!document.getElementById('showGroupHulls').checked) return - - const style = document.getElementById('hullStyle').value - const opacity = parseFloat(document.getElementById('hullOpacity').value) || 0.25 - if (style === 'bubble') { - drawBubbleSets(hullCtx, opacity) - return - } - const groups = getUsedGroups().filter((g) => S.activeGroups.has(g) && g !== UNGROUPED) - - groups.forEach((g) => { - const nodes = cy - .nodes() - .filter((n) => !n.hasClass('hidden-group') && effectiveGroupsFor(n).includes(g)) - if (!nodes.length) return - const color = S.nodeColorMap[g] || '#888888' - const points = nodes.map((n) => { - const rp = n.renderedPosition() - return { x: rp.x, y: rp.y, r: (n.renderedWidth() || n.width() * cy.zoom()) / 2 } - }) - - hullCtx.save() - if (points.length === 1) { - const p = points[0] - hullCtx.beginPath() - hullCtx.arc(p.x, p.y, p.r + 28 * hullMarginScale, 0, Math.PI * 2) - hullCtx.closePath() - paintHullPath(hullCtx, color, opacity, style) - } else if (points.length === 2) { - const [a, b] = points - const dx = b.x - a.x, - dy = b.y - a.y - const dist = Math.sqrt(dx * dx + dy * dy) || 1 - const nx = -dy / dist, - ny = dx / dist - const pad = Math.max(a.r, b.r) + 30 * hullMarginScale - hullCtx.beginPath() - hullCtx.moveTo(a.x + nx * pad, a.y + ny * pad) - hullCtx.lineTo(b.x + nx * pad, b.y + ny * pad) - // end caps bulge outward: around b away from a, around a away from b - hullCtx.arc(b.x, b.y, pad, Math.atan2(ny, nx), Math.atan2(-ny, -nx), true) - hullCtx.lineTo(a.x - nx * pad, a.y - ny * pad) - hullCtx.arc(a.x, a.y, pad, Math.atan2(-ny, -nx), Math.atan2(ny, nx), true) - hullCtx.closePath() - paintHullPath(hullCtx, color, opacity, style) - } else { - const maxR = Math.max(...points.map((p) => p.r || 0)) - const hull = inflateHull(convexHull(points), 30 * hullMarginScale + maxR) - // Both styles must actually contain every member node, so trace the - // true polygon through the inflated hull points rather than rounding - // the corners: a rounded corner falls short of the padded vertex by - // an amount that grows with its distance from its neighbors, so a - // far-dragged node ends up outside the shape (too far for "fog"'s - // blur in paintHullPath to hide). "fog" gets its soft look from that - // blur filter, not from rounding this path. - hullCtx.beginPath() - hullCtx.moveTo(hull[0].x, hull[0].y) - for (let i = 1; i < hull.length; i++) hullCtx.lineTo(hull[i].x, hull[i].y) - hullCtx.closePath() - paintHullPath(hullCtx, color, opacity, style) - } - hullCtx.restore() - }) -} - -export function applyGroupVisibility() { - cy.batch(() => cy.nodes().forEach((n) => refreshNodeVisual(n))) - invalidateViewBox() - invalidateFullMetrics() - if (document.getElementById('sizeMetric').value !== 'fixed') applyNodeSizing() - updateStats() - if (typeof scheduleBundling === 'function') scheduleBundling() -} - -function groupFilterText() { - const el = document.getElementById('groupFilter') - return el ? el.value.trim().toLowerCase() : '' -} - -// Groups whose label or key contains the filter text (all groups if empty). -// A–Z with numbers in order (Group-2 before Group-10), ignoring case and accents -const NAME_COLLATOR = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }) - -export const byName = (a, b) => NAME_COLLATOR.compare(String(a), String(b)) - -export function sortedByName(list, nameOf = (x) => x) { - return [...list].sort((a, b) => byName(nameOf(a), nameOf(b))) -} - -function groupSortMode() { - const el = document.getElementById('groupSortSelect') - return el ? el.value : 'az' -} - -// nodes per group, as the Node groups list counts them -function groupNodeCounts() { - const counts = {} - cy.nodes().forEach((n) => - (n.data('groups') || []).forEach((g) => { - counts[g] = (counts[g] || 0) + 1 - }) - ) - return counts -} - -// groups in the order lists and legends show them (colors keep their own order): -// A–Z, by number of nodes (either way, ties A–Z), or as in the file -export function displayGroups(groups) { - const mode = groupSortMode() - if (mode === 'file') return groups - let rest = sortedByName( - groups.filter((g) => g !== UNGROUPED), - groupLabel - ) - if (mode === 'size-desc' || mode === 'size-asc') { - const counts = groupNodeCounts() - const dir = mode === 'size-desc' ? -1 : 1 - rest = rest.sort( - (a, b) => dir * ((counts[a] || 0) - (counts[b] || 0)) || byName(groupLabel(a), groupLabel(b)) - ) - } - return groups.includes(UNGROUPED) ? rest.concat([UNGROUPED]) : rest -} - -export function filteredGroups() { - const q = groupFilterText() - const groups = displayGroups(getUsedGroups()) - return q - ? groups.filter((g) => groupLabel(g).toLowerCase().includes(q) || g.toLowerCase().includes(q)) - : groups -} - -function updateGroupButtons() { - const filtered = !!groupFilterText() - document.getElementById('btnGroupsAll').textContent = filtered - ? 'Activate matches' - : 'Activate all' - document.getElementById('btnGroupsNone').textContent = filtered - ? 'Deactivate matches' - : 'Deactivate all' -} - -export function buildGroupLegend() { - const el = document.getElementById('nodeGroupLegend') - if (!el) return - el.innerHTML = '' - const allGroups = getUsedGroups() - updateGroupButtons() - if (!allGroups.length) { - el.innerHTML = - '

    Load a network to see its groups.

    ' - return - } - const groups = filteredGroups() - if (!groups.length) { - el.innerHTML = - '

    No group matches the filter.

    ' - return - } - const counts = {} - cy.nodes().forEach((n) => - (n.data('groups') || []).forEach((g) => { - counts[g] = (counts[g] || 0) + 1 - }) - ) - groups.forEach((g) => { - const count = counts[g] || 0 - const label = groupLabel(g) - const description = groupDescription(g) - const row = document.createElement('label') - row.className = 'toggle-row' - if (description) row.title = description - row.innerHTML = ` - - - - ${escapeHtml(label)} - ${count} - - ` - row.querySelector('.ginfo').addEventListener('click', (ev) => { - ev.preventDefault() - ev.stopPropagation() - showGroupInfo(g) - }) - row.querySelector('.gshape').addEventListener('click', (ev) => { - ev.preventDefault() - ev.stopPropagation() - if (shapePopoverGroup === g) closeShapePopover(true) - else openShapePopover(g, ev.currentTarget) - }) - row.querySelector('input[type=checkbox]').addEventListener('change', (ev) => { - if (ev.target.checked) S.activeGroups.add(g) - else S.activeGroups.delete(g) - applyGroupVisibility() - }) - const picker = row.querySelector('.swatch-picker') - picker.addEventListener('click', (ev) => ev.stopPropagation()) - picker.addEventListener('input', (ev) => { - ev.stopPropagation() - S.nodeColorMap[g] = ev.target.value - cy.batch(() => cy.nodes().forEach((n) => refreshNodeVisual(n))) - }) - el.appendChild(row) - }) -} - -/* ============================================================ - CONFIG MODULE - Every user-adjustable visual/style control is listed once here. - getCurrentConfig() / applyConfig() are generated from this single - table, so adding a new control to the "settings" file format is a - one-line change here rather than hand-wiring an export and an - import path separately. This is what backs the "Settings" section - (export/import a standalone settings JSON) and the optional - top-level "config" object a network-data file may also carry. - ============================================================ */ -export const CONFIG_FIELDS = [ - { id: 'themeSelect', prop: 'value' }, - { id: 'nodePaletteSelect', prop: 'value' }, - { id: 'nodeLabelSize', prop: 'value' }, - { id: 'nodeLabelColorMode', prop: 'value' }, - { id: 'nodeLabelColor', prop: 'value' }, - { id: 'edgeLabelColorMode', prop: 'value' }, - { id: 'edgeLabelColor', prop: 'value' }, - { id: 'labelScaleWithNode', prop: 'checked' }, - { id: 'edgeLabelContent', prop: 'value' }, - { id: 'edgeLabelOrientation', prop: 'value' }, - { id: 'edgeLabelSize', prop: 'value' }, - { id: 'labelMinScreenSize', prop: 'value' }, - { id: 'edgeOpacity', prop: 'value' }, - { id: 'bundleStrength', prop: 'value' }, - { id: 'valueColumn', prop: 'value' }, - { id: 'valueTransform', prop: 'value' }, - { id: 'valueScale', prop: 'value' }, - { id: 'valueCenter', prop: 'value' }, - { id: 'valueRange', prop: 'value' }, - { id: 'valueMin', prop: 'value' }, - { id: 'valueMax', prop: 'value' }, - { id: 'valueMissing', prop: 'value' }, - { id: 'valueSameRange', prop: 'checked' }, - { id: 'groupSortSelect', prop: 'value' }, - { id: 'legendShow', prop: 'checked' }, - { id: 'legendScale', prop: 'checked' }, - { id: 'legendGroups', prop: 'checked' }, - { id: 'legendShapes', prop: 'checked' }, - { id: 'legendChannels', prop: 'checked' }, - { id: 'legendTitle', prop: 'value' }, - { id: 'layout3d', prop: 'value' }, - { id: 'layout3dChannels', prop: 'checked' }, - { id: 'layer3dSpacing', prop: 'value' }, - { id: 'persp3d', prop: 'value' }, - { id: 'style3d', prop: 'value' }, - { id: 'fog3d', prop: 'value' }, - { id: 'grid3d', prop: 'checked' }, - { id: 'autoRotate3d', prop: 'checked' }, - { id: 'autoSpeed3d', prop: 'value' }, - { id: 'edgeDirection', prop: 'value' }, - { id: 'arrowShape', prop: 'value' }, - { id: 'arrowScale', prop: 'value' }, - { id: 'exportShownOnly', prop: 'checked' }, - { id: 'nodeFillSelect', prop: 'value' }, - { id: 'edgePaletteSelect', prop: 'value' }, - { id: 'showNodeLabels', prop: 'checked' }, - { id: 'showEdgeLabels', prop: 'checked' }, - { id: 'labelPosition', prop: 'value' }, - { id: 'edgeCurveStyle', prop: 'value' }, - { id: 'edgeMergeMode', prop: 'value' }, - { id: 'edgeCurvature', prop: 'value' }, - { id: 'edgeWidthMode', prop: 'value' }, - { id: 'edgeWidthFixed', prop: 'value' }, - { id: 'edgeWidthMin', prop: 'value' }, - { id: 'edgeWidthMax', prop: 'value' }, - { id: 'sizeMetric', prop: 'value' }, - { id: 'sizeMin', prop: 'value' }, - { id: 'sizeMax', prop: 'value' }, - { id: 'sizeChannelOnly', prop: 'checked' }, - { id: 'nodeScale', prop: 'value' }, - { id: 'showGroupHulls', prop: 'checked' }, - { id: 'hullStyle', prop: 'value' }, - { id: 'hullOpacity', prop: 'value' }, - { id: 'layoutSelect', prop: 'value' }, - { id: 'layoutOnActiveOnly', prop: 'checked' }, - { id: 'layoutMode', prop: 'value' }, - { id: 'groupArrangement', prop: 'value' }, - { id: 'strategyAlgorithm', prop: 'value' }, - { id: 'localGroupLayout', prop: 'value' }, - { id: 'groupForce', prop: 'value' }, - { id: 'groupClusterRadius', prop: 'value' }, - { id: 'searchMode', prop: 'value' }, - { id: 'searchCase', prop: 'checked' }, - { id: 'searchAttrs', prop: 'checked' }, -] - -export function getCurrentConfig() { - const cfg = {} - CONFIG_FIELDS.forEach(({ id, prop }) => { - const el = document.getElementById(id) - if (!el) return - cfg[id] = prop === 'checked' ? el.checked : el.value - }) - return cfg -} - -// Sets every control named in cfg, then re-runs each style/layout -// function once so the change actually takes visual effect -- a control's -// own change-listener only fires on real user interaction, not on a value -// set programmatically, so this step can't be skipped. -// Settings files saved before the three NORMA-2.0 strategies had a single -// "layout by groups" toggle (the super-node strategy) with its own global -// layout and a 0.5-4 spacing slider. -function upgradeLegacyConfig(cfg) { - const out = { ...cfg } - if (out.groupStrategy === undefined && 'groupedLayoutToggle' in out) { - out.groupStrategy = out.groupedLayoutToggle ? 'supernodes' : 'none' - if (out.groupedLayoutToggle && out.globalGroupLayout && out.layoutSelect === undefined) { - out.layoutSelect = out.globalGroupLayout - } - } - // settings from before "by connections / by groups": a strategy select - // whose algorithm was the main layout choice - if (out.layoutMode === undefined && out.groupStrategy !== undefined) { - if (out.groupStrategy === 'none') { - out.layoutMode = 'connections' - } else { - out.layoutMode = 'groups' - out.groupArrangement = out.groupStrategy - if (out.layoutSelect) out.strategyAlgorithm = out.layoutSelect - } - } - if (out.groupForce === undefined && out.groupSpacing !== undefined) { - const spacing = parseFloat(out.groupSpacing) - if (Number.isFinite(spacing)) - out.groupForce = String(Math.min(20, Math.max(1, Math.round(spacing / 0.16)))) - } - return out -} - -export function applyConfig(cfg) { - if (!cfg || typeof cfg !== 'object') return - cfg = upgradeLegacyConfig(cfg) - CONFIG_FIELDS.forEach(({ id, prop }) => { - if (!(id in cfg)) return - const el = document.getElementById(id) - if (!el) return - if (prop === 'checked') el.checked = !!cfg[id] - else el.value = cfg[id] - }) - refreshAllDerivedUI() -} - -export function refreshAllDerivedUI() { - applyTheme(document.getElementById('themeSelect').value) - if (typeof applyValueColors === 'function') { - updateValueScalePreview() - applyValueColors() - } - applyNodePalette(document.getElementById('nodePaletteSelect').value, true) - applyEdgePalette(document.getElementById('edgePaletteSelect').value) - updateLabelStyle() - applyEdgeCurveStyle() - applyEdgeWidth() - applyNodeSizing() - applyEdgeOpacity() - applyEdgeDirection() - document.getElementById('hullControls').style.display = document.getElementById('showGroupHulls') - .checked - ? 'block' - : 'none' - updateStrategyUI() - drawGroupHulls() -} - -// Cuts data with too many nodes to the first MAX_NETWORK_NODES. -function capNetworkData(data) { - if (!data || !Array.isArray(data.nodes) || data.nodes.length <= MAX_NETWORK_NODES) return data - const total = data.nodes.length - const nodes = data.nodes.slice(0, MAX_NETWORK_NODES) - const keep = new Set(nodes.map((n) => n.id)) - const edges = (data.edges || []).filter((e) => keep.has(e.source) && keep.has(e.target)) - const text = `This network has ${total.toLocaleString('en-US')} nodes; NORMA shows up to ${MAX_NETWORK_NODES.toLocaleString('en-US')}, so only the first ${MAX_NETWORK_NODES.toLocaleString('en-US')} and the ${plural(edges.length, 'edge')} among them are shown.` - setTimeout(() => { - if (typeof toast === 'function') toast(text, 'warn') - const el = document.getElementById('normaStatus') - if (el) { - const note = document.createElement('div') - note.className = 'note warn' - note.textContent = text - el.prepend(note) - } - }, 0) - return { ...data, nodes, edges } -} - -// Extra legend sections that come with generated views (e.g. the comparison). -export let legendExtra = null - -export function loadData(data, opts = {}) { - data = capNetworkData(data) - legendExtra = Array.isArray(data.legendExtra) ? data.legendExtra : null - bumpDataVersion() - S.currentLibView = null - S.nodeColorMap = {} - S.groupShapes = - data.groupShapes && typeof data.groupShapes === 'object' ? { ...data.groupShapes } : {} - S.groupAttrs = - data.groupAttrs && typeof data.groupAttrs === 'object' ? { ...data.groupAttrs } : {} - setGroupOrder(data.groupOrder) - // give groups their palette colors in display order - if (Array.isArray(data.groupOrder)) { - data.groupOrder.forEach((g) => { - const explicit = sanitizeColor( - (data.nodeColors && data.nodeColors[g]) || (S.groupAttrs[g] && S.groupAttrs[g].color) - ) - if (explicit) S.nodeColorMap[g] = explicit - else colorForGroup(g) - }) - } - cy.elements().remove() - - const usedTypes = new Set() - const els = [] - - data.nodes.forEach((n) => { - const groupsArr = n.groups && n.groups.length ? n.groups : [n.group || UNGROUPED] - if (groupsArr.includes(UNGROUPED) && !S.groupAttrs[UNGROUPED]) { - S.groupAttrs[UNGROUPED] = { - label: UNGROUPED_LABEL, - description: 'Nodes that no group lists as a member', - } - } - groupsArr.forEach((g) => { - // explicit color precedence: nodeColors[g], then groupAttrs[g].color - const explicit = sanitizeColor( - (data.nodeColors && data.nodeColors[g]) || (S.groupAttrs[g] && S.groupAttrs[g].color) - ) - if (explicit) S.nodeColorMap[g] = explicit - }) - // a node's own "color" is kept separately and used when - // Colors -> Node fill is set to "Node colors from data" - const visual = computeNodeVisualFields(groupsArr) - els.push({ - group: 'nodes', - data: { - id: n.id, - size: n.size || 42, - baseSize: n.size || 42, - group: groupsArr.join(', '), - groups: groupsArr, - nodeColor: n.color || null, - values: n.values && typeof n.values === 'object' ? cleanValues(n.values) : null, - valueColor: null, - labelPx: 12, - labelColor: '#111827', - shape: 'ellipse', - attrs: collectAttrs(n, RESERVED_NODE_KEYS), - ...visual, - }, - }) - }) - - data.edges.forEach((e, i) => { - const type = e.type || 'link' - usedTypes.add(type) - const explicit = sanitizeColor((data.edgeColors && data.edgeColors[type]) || e.color) - if (!EDGE_TYPES[type]) { - EDGE_TYPES[type] = { color: explicit || nextAutoEdgeColor(), label: type } - } else if (explicit) { - EDGE_TYPES[type].color = explicit - } - els.push({ - group: 'edges', - data: { - id: e.id || 'e' + i, - source: e.source, - target: e.target, - type, - color: EDGE_TYPES[type].color, - elabel: '', - directed: e.directed === undefined ? !!data.directed : !!e.directed, - arrow: 'none', - attrs: collectAttrs(e, RESERVED_EDGE_KEYS), - ...(typeof e.weight === 'number' ? { weight: e.weight } : {}), - }, - }) - }) - - cy.add(els) - S.activeTypes = new Set(usedTypes.size ? usedTypes : Object.keys(EDGE_TYPES)) - S.activeGroups = new Set(getUsedGroups()) - buildLegend([...usedTypes]) - buildGroupLegend() - applyTypeVisibility() - applyGroupVisibility() - invalidateFullMetrics() - buildAttrSchema() - renderAttrSchema() - hideInfo() - hideEdgePopup() - if (currentTab === 'welcome' && typeof switchTab === 'function') switchTab('network') - if (data.config) { - applyConfig(data.config) // also covers applyEdgeWidth() and applyNodeSizing() - } else { - applyEdgeWidth() - applyNodeSizing() - } - const nodeCount = cy.nodes().length - updateRefreshState() - if (!opts.positions && typeof reset3dForNewData === 'function') reset3dForNewData() - if (opts.positions) { - // restoring a saved view: put nodes back where they were - cancelFrJobs() - S.layoutRunSeq++ - cy.nodes().positions((n) => opts.positions[n.id()] || n.position()) - } else if (layoutMode() === 'groups' && nodeCount <= LARGE_NETWORK_NODES) { - runStrategyLayout() - } else { - // a data file's settings may pick the opening layout - const preferred = (data.config && data.config.layoutSelect) || takeNextLoadLayout() - runLayout(nodeCount > LARGE_NETWORK_NODES ? 'grid' : preferred || 'cose') - } - applyEdgeDirection() // also merges parallel edges - if (typeof applyValueColors === 'function') applyValueColors() - updateStats() -} - -export function buildLegend(typesInData) { - const el = document.getElementById('edgeLegend') - el.innerHTML = '' - const list = typesInData.length ? typesInData : Object.keys(EDGE_TYPES) - list.forEach((type) => { - const meta = EDGE_TYPES[type] || { color: '#6c7793', label: type } - const count = cy.edges().filter((e) => e.data('type') === type).length - const row = document.createElement('label') - row.className = 'toggle-row' - row.innerHTML = ` - - - ${escapeHtml(meta.label)} - ${count} - ` - row.querySelector('input[type=checkbox]').addEventListener('change', (ev) => { - if (ev.target.checked) S.activeTypes.add(type) - else S.activeTypes.delete(type) - applyTypeVisibility() - }) - const picker = row.querySelector('.swatch-picker') - picker.addEventListener('click', (ev) => ev.stopPropagation()) - picker.addEventListener('input', (ev) => { - ev.stopPropagation() - const newColor = ev.target.value - if (!EDGE_TYPES[type]) EDGE_TYPES[type] = { color: newColor, label: type } - else EDGE_TYPES[type].color = newColor - cy.edges() - .filter((ed) => ed.data('type') === type) - .forEach((ed) => ed.data('color', newColor)) - applyEdgeMerge() - }) - el.appendChild(row) - }) -} - -export function getUsedTypes() { - return [...new Set(cy.edges().map((e) => e.data('type')))] -} - -// keepDataColors: groups whose data gives a color keep it (settings applied -// from files or the API); choosing a palette by hand recolors every group. -export function applyNodePalette(name, keepDataColors = false) { - S.currentNodePalette = name - const palette = NODE_PALETTES[name] || NODE_PALETTES.vivid - const groups = Object.keys(S.nodeColorMap).filter((g) => g !== UNGROUPED) - groups.forEach((g, i) => { - const own = keepDataColors && sanitizeColor(S.groupAttrs[g] && S.groupAttrs[g].color) - S.nodeColorMap[g] = own || colorAtIndex(palette, i) - }) - cy.batch(() => cy.nodes().forEach((n) => refreshNodeVisual(n))) - buildGroupLegend() -} - -export function applyEdgePalette(name) { - const types = getUsedTypes() - if (name === 'classic') { - types.forEach((t) => { - EDGE_TYPES[t] = ORIGINAL_EDGE_TYPES[t] - ? { ...ORIGINAL_EDGE_TYPES[t] } - : EDGE_TYPES[t] || { color: nextAutoEdgeColor(), label: t } - }) - } else { - const palette = EDGE_PALETTES[name] || EDGE_PALETTES.categorical - types.forEach((t, i) => { - const label = (EDGE_TYPES[t] && EDGE_TYPES[t].label) || t - EDGE_TYPES[t] = { color: colorAtIndex(palette, i), label } - }) - } - cy.edges().forEach((e) => { - const meta = EDGE_TYPES[e.data('type')] - if (meta) e.data('color', meta.color) - }) - buildLegend(types) - applyEdgeMerge() -} - -// page wiring, run by main.ts in the original order -export function init() { - window.addEventListener('resize', () => { - resizeHullCanvas() - drawGroupHulls() - }) - - if (typeof ResizeObserver !== 'undefined') { - new ResizeObserver(() => { - resizeHullCanvas() - drawGroupHulls() - }).observe(document.getElementById('canvas')) - } -} diff --git a/frontend/src/label_colors.ts b/frontend/src/label_colors.ts deleted file mode 100644 index c0b5a82..0000000 --- a/frontend/src/label_colors.ts +++ /dev/null @@ -1,332 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { S } from './state' -import { UNGROUPED, escapeHtml } from './network_state' -import { currentTheme } from './themes' -import { edgeIsDirected } from './export/dialog' -import { libEntry, nextPaint, normaLibrary, plural, setStatus } from './layouts/controls' -import { profileDirected } from './directed_stats' -import { profileGraph, simpleGraph } from './wiring' -import { renderComparison } from './export/draw' -import { setStyle } from './cy' -import { shownEdges, shownNodes } from './metrics' -import { sortedByName } from './hulls' -import { updateLabelStyle, views } from './profiler' - -/* ---------- label colors ---------- */ -function isLightColor(hex) { - const m = /^#?([0-9a-f]{6})$/i.exec(hex || '') - if (!m) return false - const n = parseInt(m[1], 16) - const r = (n >> 16) & 255, - g = (n >> 8) & 255, - b = n & 255 - return (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255 > 0.72 -} - -function chosenLabelColor(modeId, pickerId) { - const mode = document.getElementById(modeId).value - const picker = document.getElementById(pickerId) - picker.hidden = mode !== 'custom' - if (mode === 'custom') return picker.value - return mode // 'auto', 'match' or a hex color -} - -export function applyLabelColors() { - const node = chosenLabelColor('nodeLabelColorMode', 'nodeLabelColor') - const edge = chosenLabelColor('edgeLabelColorMode', 'edgeLabelColor') - const theme = currentTheme - // light text gets a dark halo so it stays readable on a light canvas - const halo = (c) => (c !== 'auto' && c !== 'match' && isLightColor(c) ? '#1b2333' : theme.bg) - setStyle('node', { - color: node === 'auto' ? theme.text : node === 'match' ? 'data(labelColor)' : node, - 'text-outline-color': halo(node), - }) - setStyle('edge', { - color: edge === 'auto' ? theme.text : edge === 'match' ? 'data(color)' : edge, - 'text-background-color': isLightColor(edge) ? '#1b2333' : theme.bg, - }) -} - -/* ============================================================ - NETWORK COMPARISON - Up to ten networks, taken from open views or from the file library, - compared by node and edge overlap (Venn diagrams for two or three - networks, UpSet plots for any number), pairwise Jaccard similarity, - degree agreement on shared nodes, degree distributions, and the - profiler's topology statistics side by side. Nodes are matched by - name; edges by their unordered node pair, ignoring channels. - ============================================================ */ -const COMPARE_MAX = 10 - -const COMPARE_COLORS = [ - '#2563eb', - '#e0782b', - '#16a34a', - '#c026d3', - '#0891b2', - '#dc2626', - '#7c3aed', - '#ca8a04', - '#db2777', - '#475569', -] - -export const UPSET_MAX_COLUMNS = 40 - -export const compareState = { results: null } - -function compareSourceOptions() { - const opts = [] - views.forEach((v) => { - const n = v.id === S.activeViewId ? shownNodes().length : v.data ? v.data.nodes.length : 0 - if (n) - opts.push({ - value: 'view:' + v.id, - label: v.name, - meta: `view, ticked groups and channels`, - group: 'Open views', - }) - }) - sortedByName(normaLibrary.network, (e) => e.name).forEach((e) => { - opts.push({ - value: 'lib:' + e.id, - label: e.name, - meta: e.parsed.summary, - group: 'Network files', - }) - }) - return opts -} - -export function renderCompareList() { - const el = document.getElementById('cmpNetList') - if (!el) return - const previous = new Set([...el.querySelectorAll('input:checked')].map((i) => i.value)) - el.innerHTML = '' - const opts = compareSourceOptions() - if (!opts.length) { - el.innerHTML = '

    Open an example or upload networks first.

    ' - updateCompareLimit() - return - } - let lastGroup = null - opts.forEach((o) => { - if (o.group !== lastGroup) { - const h = document.createElement('div') - h.className = 'cmp-group-head' - h.textContent = o.group - el.appendChild(h) - lastGroup = o.group - } - const label = document.createElement('label') - label.className = 'cmp-option' - const input = document.createElement('input') - input.type = 'checkbox' - input.value = o.value - input.checked = previous.has(o.value) - input.addEventListener('change', updateCompareLimit) - const text = document.createElement('span') - text.innerHTML = `${escapeHtml(o.label)}${escapeHtml(o.meta)}` - label.append(input, text) - el.appendChild(label) - }) - updateCompareLimit() -} - -function updateCompareLimit() { - const boxes = [...document.querySelectorAll('#cmpNetList input')] - const checked = boxes.filter((b) => b.checked) - boxes.forEach((b) => { - b.disabled = !b.checked && checked.length >= COMPARE_MAX - }) - const btn = document.getElementById('btnCompare') - btn.disabled = checked.length < 2 - document.getElementById('cmpCount').textContent = - `${checked.length} of ${COMPARE_MAX} chosen` + - (checked.length < 2 ? ' (choose at least 2)' : '') -} - -function compareSource(value) { - if (value.startsWith('view:')) { - const v = views.find((x) => x.id === value.slice(5)) - if (!v) return null - let ids, pairs - if (v.id === S.activeViewId) { - ids = shownNodes().map((n) => n.id()) - pairs = shownEdges(true).map((e) => [e.data('source'), e.data('target'), edgeIsDirected(e)]) - } else { - if (!v.data) return null - // the part that view shows: its ticked groups and channels - const st = v.state || {} - const groupsOn = st.activeGroups ? new Set(st.activeGroups) : null - const typesOn = st.activeTypes ? new Set(st.activeTypes) : null - const shown = new Set( - v.data.nodes - .filter((n) => { - if (!groupsOn) return true - const gs = n.groups && n.groups.length ? n.groups : n.group ? [n.group] : [UNGROUPED] - return gs.some((g) => groupsOn.has(g)) - }) - .map((n) => n.id) - ) - ids = [...shown] - const mode = (st.config && st.config.edgeDirection) || 'data' - pairs = v.data.edges - .filter( - (e) => - shown.has(e.source) && - shown.has(e.target) && - (!typesOn || typesOn.has(e.type || 'link')) - ) - .map((e) => [ - e.source, - e.target, - mode === 'directed' ? true : mode === 'undirected' ? false : !!e.directed, - ]) - } - return { name: v.name, kind: 'view', ids, pairs } - } - const entry = libEntry('network', value.slice(4)) - if (!entry) return null - return { - name: entry.name, - kind: 'file', - ids: entry.parsed.nodes, - pairs: entry.parsed.edges.map((e) => [e.source, e.target, !!e.directed]), - } -} - -// Edge identity: an unordered pair, or with direction on, an ordered pair -// for directed edges (so A->B, B->A and undirected A-B all differ). -function pairKey(a, b, directed) { - if (directed) return a + '\t' + b + '\tdirected' - return (a < b ? a + '\t' + b : b + '\t' + a) + '\tundirected' -} - -// element -> bitmask of the sets containing it -export function membership(sets) { - const mask = new Map() - sets.forEach((set, i) => set.forEach((x) => mask.set(x, (mask.get(x) || 0) | (1 << i)))) - return mask -} - -export function exclusiveCounts(mask) { - const counts = new Map() - mask.forEach((m) => counts.set(m, (counts.get(m) || 0) + 1)) - return counts -} - -export function jaccard(a, b) { - let inter = 0 - const [small, big] = a.size < b.size ? [a, b] : [b, a] - small.forEach((x) => { - if (big.has(x)) inter++ - }) - const union = a.size + b.size - inter - return { inter, union, j: union ? inter / union : 0 } -} - -export function spearman(xs, ys) { - const rank = (arr) => { - const idx = arr.map((v, i) => [v, i]).sort((p, q) => p[0] - q[0]) - const r = new Array(arr.length) - for (let i = 0; i < idx.length;) { - let j = i - while (j + 1 < idx.length && idx[j + 1][0] === idx[i][0]) j++ - const avg = (i + j) / 2 + 1 - for (let k = i; k <= j; k++) r[idx[k][1]] = avg - i = j + 1 - } - return r - } - const n = xs.length - if (n < 3) return NaN - const rx = rank(xs), - ry = rank(ys) - const mx = (n + 1) / 2 - let num = 0, - dx = 0, - dy = 0 - for (let i = 0; i < n; i++) { - num += (rx[i] - mx) * (ry[i] - mx) - dx += (rx[i] - mx) ** 2 - dy += (ry[i] - mx) ** 2 - } - return dx && dy ? num / Math.sqrt(dx * dy) : NaN -} - -export function runComparison() { - const chosen = [...document.querySelectorAll('#cmpNetList input:checked')] - .map((i) => i.value) - .slice(0, COMPARE_MAX) - if (chosen.length < 2) { - setStatus('cmpStatus', [{ level: 'error', text: 'Choose at least two networks to compare.' }]) - return - } - // steps: one per network, then the overlaps and drawing - const cmpShow = (text, f) => setStatus('cmpStatus', [{ level: 'busy', text, progress: f }]) - cmpShow('Comparing networks…', 0) - document.getElementById('btnCompare').disabled = true - ;(async () => { - await nextPaint() - try { - const started = performance.now() - const nets = chosen - .map((value) => { - const n = compareSource(value) - if (n) n.sourceValue = value - return n - }) - .filter(Boolean) - const useDir = document.getElementById('cmpDirected').checked - for (const [i, net] of nets.entries()) { - cmpShow(`Profiling network ${i + 1} of ${nets.length}…`, i / (nets.length + 1)) - await nextPaint() - net.color = COMPARE_COLORS[i] - net.nodeSet = new Set(net.ids) - net.edgeSet = new Set() - net.pairs.forEach(([a, b, d]) => { - if (a !== b && net.nodeSet.has(a) && net.nodeSet.has(b)) - net.edgeSet.add(pairKey(a, b, useDir && d)) - }) - net.graph = simpleGraph( - net.ids, - net.pairs.map((p) => [p[0], p[1]]) - ) - net.stats = profileGraph(net.graph) - net.directed = - useDir && net.pairs.some((p) => p[2]) ? profileDirected(net.ids, net.pairs) : null - net.degreeOf = new Map(net.ids.map((id, k) => [id, net.stats.degree[k]])) - } - cmpShow('Computing overlaps and drawing…', nets.length / (nets.length + 1)) - await nextPaint() - compareState.results = nets - renderComparison(nets) - const secs = ((performance.now() - started) / 1000).toFixed(2) - setStatus('cmpStatus', [ - { level: 'ok', text: `Compared ${plural(nets.length, 'network')} in ${secs} s.` }, - ]) - document.getElementById('btnCompareTsv').disabled = false - document.getElementById('btnCompareNet').disabled = false - document.getElementById('cmpArena').hidden = false - } catch (err) { - setStatus('cmpStatus', [ - { level: 'error', text: `The comparison couldn't be computed: ${err.message}` }, - ]) - } finally { - updateCompareLimit() - } - })() -} - -// page wiring, run by main.ts in the original order -export function init() { - ;['nodeLabelColorMode', 'edgeLabelColorMode'].forEach((id) => { - document.getElementById(id).addEventListener('change', updateLabelStyle) - }) - - ;['nodeLabelColor', 'edgeLabelColor'].forEach((id) => { - document.getElementById(id).addEventListener('input', updateLabelStyle) - }) -} diff --git a/frontend/src/layouts/controls.ts b/frontend/src/layouts/controls.ts deleted file mode 100644 index 5aa19c7..0000000 --- a/frontend/src/layouts/controls.ts +++ /dev/null @@ -1,1079 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { MAX_NETWORK_NODES, UNGROUPED, getUsedGroups } from '../network_state' -import { S } from '../state' -import { SAMPLE_GENERATORS } from '../sample_data' -import { STRATEGIES, groupArrangement, layoutMode, runActiveLayout } from './run' -import { - applyConfig, - applyGroupVisibility, - buildGroupLegend, - filteredGroups, - getCurrentConfig, - loadData, - sortedByName, -} from '../hulls' -import { askDelete, deleteLibEntries } from '../api/tester' -import { clearCanvas, fitView, openInNewView, renderProfilerNetworkList } from '../profiler' -import { cy } from '../cy' -import { edgeIsDirected } from '../export/dialog' -import { exportEdges, exportNodes } from '../metrics' -import { loadNormaExampleSet } from '../examples' -import { numericShare, parseNumericValues } from '../clustering/mcl' - -/* ---------- layout controls ---------- */ -const ARRANGEMENT_CAPTIONS = { - fr: 'Groups are placed by how strongly they connect to each other (weighted force-directed), then pushed apart so none overlap.', - cose: 'Groups are placed by how they connect to each other (Cytoscape force-directed), then pushed apart so none overlap.', - circle: 'Groups sit side by side on a ring, in legend order.', - grid: 'Groups are packed in rows, in legend order.', - breadthfirst: - 'Groups are stacked in levels: the best-connected group on top, the groups it links to below it, and so on.', - concentric: 'The largest group sits in the middle, with the others in rings around it by size.', - virtual: - 'Each group gets a hidden hub tied to all its members by heavy links (dashed), so the layout pulls each group together. The hubs are removed afterwards.', - gravity: - 'Links inside a group are strengthened by the force and links between groups weakened by it. Layout-only links (dashed) join every pair in a group.', - supernodes: - 'Each group is collapsed into one node and the collapsed network is laid out. Groups are then pushed apart by the force, and each group\u2019s nodes are arranged around its position. Nodes in several groups sit between them.', -} - -export function setLayoutMode(mode) { - document.getElementById('layoutMode').value = mode === 'groups' ? 'groups' : 'connections' - updateStrategyUI() -} - -export function updateStrategyUI() { - const mode = layoutMode() - const arrangement = groupArrangement() - const isStrategy = STRATEGIES.has(arrangement) - document.querySelectorAll('#layoutModeSwitch [role="radio"]').forEach((btn) => { - const on = btn.dataset.mode === mode - btn.setAttribute('aria-checked', on ? 'true' : 'false') - btn.tabIndex = on ? 0 : -1 - }) - document.getElementById('connLayoutSet').disabled = mode !== 'connections' - document.getElementById('groupLayoutSet').disabled = mode !== 'groups' - - const fig = document.getElementById('strategyFig') - fig - .querySelectorAll('svg') - .forEach((svg) => svg.classList.toggle('on', svg.dataset.strategy === arrangement)) - document.getElementById('strategyCaption').textContent = ARRANGEMENT_CAPTIONS[arrangement] || '' - document.getElementById('strategyAlgorithmRow').hidden = !isStrategy - document.getElementById('strategyAlgorithmLabel').textContent = - arrangement === 'supernodes' - ? 'Algorithm for the collapsed network' - : 'Algorithm the strategy runs' - - const keepOpt = document.querySelector('#localGroupLayout option[value="keep"]') - const keepAllowed = arrangement === 'virtual' || arrangement === 'gravity' - keepOpt.disabled = !keepAllowed - keepOpt.hidden = !keepAllowed - const localSel = document.getElementById('localGroupLayout') - if (!keepAllowed && localSel.value === 'keep') localSel.value = 'circle' - - document.getElementById('forceLabelText').textContent = isStrategy - ? 'Force strength' - : 'Space between groups' - document.getElementById('forceRow').hidden = - arrangement === 'virtual' && localSel.value === 'keep' - document.getElementById('clusterRow').hidden = localSel.value === 'keep' - document.getElementById('groupForceValue').textContent = - document.getElementById('groupForce').value - document.getElementById('groupClusterRadiusValue').textContent = ( - parseFloat(document.getElementById('groupClusterRadius').value) || 1 - ).toFixed(1) - document.getElementById('btnRunLayout').textContent = - mode === 'groups' ? 'Run group layout' : 'Run layout' -} - -/* ============================================================ - FILES: NORMA-FORMAT LIBRARY - Reads and writes the three tab-delimited inputs used by NORMA - (Koutrouli et al. 2022; Karatzas et al. 2022): - network -- header "SourceTarget[Weight][Type]", - undirected; self-loops and repeats are dropped. The - optional Type column is this tool's extension: it keeps - parallel edges, one per type. - annotation -- no header; "groupnode1,node2,..." - expression -- no header; "nodecolor" (name or hex) - Every uploaded file is kept in an in-memory library. Any set of networks - can be viewed together (each becomes an edge channel) with one - annotation and one expression file. Annotation and expression entries - for nodes missing from the chosen networks are discarded at view time - (the job of NORMA's companion R script); the corrected annotation can be - downloaded. - ============================================================ */ -export const NORMA_KINDS = ['network', 'annotation', 'colors'] - -export const NORMA_KIND_NAMES = { - network: 'network', - annotation: 'annotation', - colors: 'expression file', -} - -const LIB_LIST_IDS = { - network: 'libNetworks', - annotation: 'libAnnotations', - colors: 'libExpressions', -} - -export const normaLibrary = { network: [], annotation: [], colors: [] } - -export const libSelection = { networks: new Set(), annotation: '', colors: '' } - -export function plural(n, one, many) { - return `${n} ${n === 1 ? one : many || one + 's'}` -} - -export function listSample(items, max = 6) { - const shown = items.slice(0, max).join(', ') - return items.length > max ? `${shown} and ${items.length - max} more` : shown -} - -export function articleFor(word) { - return /^[aeiou]/i.test(word) ? 'an' : 'a' -} - -export function normaLines(text) { - return String(text) - .replace(/^\uFEFF/, '') - .split(/\r\n|\n|\r/) -} - -// Tab-separated columns. Files saved with spaces instead of tabs (common -// after copy-pasting) fall back to splitting on whitespace. -export function normaCols(line) { - let cols = line.split('\t') - if (cols.length === 1) cols = line.trim().split(/\s+/) - cols = cols.map((c) => c.trim()) - while (cols.length && cols[cols.length - 1] === '') cols.pop() - return cols -} - -const NETWORK_TYPE_HEADERS = new Set(['type', 'channel', 'layer', 'interaction']) - -const NETWORK_DIRECTION_HEADERS = new Set(['direction', 'directed', 'dir', 'arrow']) - -const DIRECTED_WORDS = new Set(['directed', 'yes', 'y', 'true', '1', '->', '-->', '→', 'forward']) - -const UNDIRECTED_WORDS = new Set([ - 'undirected', - 'no', - 'n', - 'false', - '0', - '-', - '--', - '—', - 'both', - 'none', - '', -]) - -// options.directed: how to read rows without a Direction value -export function parseNormaNetwork(text, options = {}) { - const defaultDirected = !!options.directed - const lines = normaLines(text) - const headerIdx = lines.findIndex((l) => l.trim() !== '') - if (headerIdx < 0) throw new Error('The file is empty.') - const header = normaCols(lines[headerIdx]).map((h) => h.toLowerCase()) - if (header[0] !== 'source' || header[1] !== 'target') { - throw new Error( - 'The first line must be the header "Source, Target" (optionally followed by Weight, Type and Direction), separated by tabs.' - ) - } - let weightCol = -1, - typeCol = -1, - dirCol = -1 - for (let c = 2; c < header.length; c++) { - if (header[c] === 'weight' && weightCol < 0) weightCol = c - else if (NETWORK_TYPE_HEADERS.has(header[c]) && typeCol < 0) typeCol = c - else if (NETWORK_DIRECTION_HEADERS.has(header[c]) && dirCol < 0) dirCol = c - else - throw new Error( - `The header column "${header[c]}" isn't recognised. After Source and Target, only Weight, Type and Direction are allowed.` - ) - } - const minCols = Math.max(2, weightCol + 1, typeCol + 1) - const badDirections = [] - - const nodes = new Set() - const seen = new Set() - const edges = [] - const types = new Set() - let selfLoops = 0, - repeats = 0, - directedCount = 0 - const shortLines = [], - badWeights = [] - for (let i = headerIdx + 1; i < lines.length; i++) { - if (!lines[i].trim()) continue - const cols = normaCols(lines[i]) - if (cols.length < minCols) { - shortLines.push(i + 1) - continue - } - const [source, target] = cols - nodes.add(source) - nodes.add(target) - if (source === target) { - selfLoops++ - continue - } - const type = typeCol >= 0 ? cols[typeCol] : '' - let directed = defaultDirected - if (dirCol >= 0 && cols[dirCol] !== undefined) { - const word = cols[dirCol].trim().toLowerCase() - if (DIRECTED_WORDS.has(word)) directed = true - else if (UNDIRECTED_WORDS.has(word)) directed = false - else badDirections.push(i + 1) - } - // A directed edge A->B differs from B->A; an undirected A-B doesn't. - const pair = directed - ? 'D\t' + source + '\t' + target - : 'U\t' + (source < target ? source + '\t' + target : target + '\t' + source) - const key = pair + '\t' + type - if (seen.has(key)) { - repeats++ - continue - } - seen.add(key) - const edge = { source, target } - if (directed) { - edge.directed = true - directedCount++ - } - if (type) { - edge.type = type - types.add(type) - } - if (weightCol >= 0) { - const w = Number(cols[weightCol]) - if (Number.isFinite(w)) edge.weight = w - else badWeights.push(i + 1) - } - edges.push(edge) - } - if (!edges.length) throw new Error('No connections were found below the header row.') - - const notes = [] - if (nodes.size > MAX_NETWORK_NODES) { - // keep the first nodes in the order they appear, and the edges among them - const keep = new Set([...nodes].slice(0, MAX_NETWORK_NODES)) - const total = nodes.size, - before = edges.length - const kept = edges.filter((e) => keep.has(e.source) && keep.has(e.target)) - edges.length = 0 - edges.push(...kept) - nodes.clear() - keep.forEach((n) => nodes.add(n)) - types.clear() - directedCount = 0 - edges.forEach((e) => { - if (e.type) types.add(e.type) - if (e.directed) directedCount++ - }) - notes.push( - `This network has ${total.toLocaleString('en-US')} nodes; NORMA shows up to ${MAX_NETWORK_NODES.toLocaleString('en-US')}, so only the first ${MAX_NETWORK_NODES.toLocaleString('en-US')} (in file order) and the ${plural(edges.length, 'edge')} among them were kept (${(before - edges.length).toLocaleString('en-US')} edges left out).` - ) - if (!edges.length) - throw new Error( - `The first ${MAX_NETWORK_NODES.toLocaleString('en-US')} nodes of this network have no connections among them.` - ) - } - if (selfLoops) notes.push(`Removed ${plural(selfLoops, 'self-loop')}.`) - if (repeats) - notes.push( - directedCount === edges.length - ? `Removed ${plural(repeats, 'repeated connection')} with the same source, target${typeCol >= 0 ? ' and type' : ''}.` - : typeCol >= 0 - ? `Removed ${plural(repeats, 'repeated connection')} with the same pair and type${directedCount ? ' (for undirected rows, A–B and B–A are the same pair)' : ''}.` - : `Removed ${plural(repeats, 'repeated connection')} (for undirected rows, A–B and B–A count as the same connection).` - ) - if (badDirections.length) - notes.push( - `Read ${plural(badDirections.length, 'Direction value')} that ${badDirections.length === 1 ? "isn't" : "aren't"} "directed" or "undirected" as ${defaultDirected ? 'directed' : 'undirected'}: line ${listSample(badDirections)}.` - ) - if (shortLines.length) - notes.push( - `Skipped ${plural(shortLines.length, 'line')} with fewer than ${minCols} columns: line ${listSample(shortLines)}.` - ) - if (badWeights.length) - notes.push( - `Left out ${plural(badWeights.length, 'weight')} that ${badWeights.length === 1 ? "isn't a number" : "aren't numbers"}: line ${listSample(badWeights)}.` - ) - const commaNames = [...nodes].filter((n) => n.includes(',')) - if (commaNames.length) - notes.push( - `${plural(commaNames.length, 'node name contains', 'node names contain')} a comma, so annotation files can't list ${commaNames.length === 1 ? 'it' : 'them'}: ${listSample(commaNames)}.` - ) - - const summaryParts = [plural(nodes.size, 'node'), plural(edges.length, 'edge')] - if (types.size) summaryParts.push(plural(types.size, 'type')) - if (weightCol >= 0) summaryParts.push('weighted') - const direction = - directedCount === 0 ? 'undirected' : directedCount === edges.length ? 'directed' : 'mixed' - if (direction !== 'undirected') - summaryParts.push( - direction === 'mixed' ? `mixed (${directedCount.toLocaleString()} directed)` : 'directed' - ) - return { - nodes: [...nodes], - edges, - weighted: weightCol >= 0, - types: [...types], - notes, - direction, - directedCount, - summary: summaryParts.join(', '), - } -} - -const ANNOTATION_HEADER_WORDS = - /^(groups?|annotations?|terms?|pathways?|names?|modules?|clusters?)$/i - -function parseNormaAnnotation(text) { - const lines = normaLines(text) - const groups = new Map() - let spacesStripped = 0, - merged = 0, - headerSkipped = false - const shortLines = [] - let firstDataLine = true - lines.forEach((raw, i) => { - if (!raw.trim()) return - let name, list - const tab = raw.indexOf('\t') - if (tab >= 0) { - name = raw.slice(0, tab).trim() - list = raw.slice(tab + 1).replace(/\t/g, '') - } else { - // no tab: only accept the unambiguous "namelist" shape - const parts = raw.trim().split(/\s+/) - if (parts.length === 2) { - name = parts[0] - list = parts[1] - } - } - if (!name || !list || !list.trim()) { - shortLines.push(i + 1) - firstDataLine = false - return - } - if (firstDataLine && ANNOTATION_HEADER_WORDS.test(name) && !list.includes(',')) { - headerSkipped = true - firstDataLine = false - return - } - firstDataLine = false - if (/\s/.test(list.trim())) spacesStripped++ - const members = list - .split(',') - .map((m) => m.trim()) - .filter(Boolean) - if (groups.has(name)) merged++ - const set = groups.get(name) || new Set() - members.forEach((m) => set.add(m)) - groups.set(name, set) - }) - if (!groups.size) { - throw new Error( - 'No groups were found. Each line should be a group name, a tab, then node names separated by commas.' - ) - } - const notes = [] - if (headerSkipped) - notes.push( - 'Skipped the first line because it looks like a header. Annotation files have no header row.' - ) - if (shortLines.length) - notes.push( - `Skipped ${plural(shortLines.length, 'line')} without a group name and node list: line ${listSample(shortLines)}.` - ) - if (spacesStripped) - notes.push( - `Removed spaces from the node lists on ${plural(spacesStripped, 'line')}. NORMA expects commas only.` - ) - if (merged) notes.push(`Merged ${plural(merged, 'repeated group name')} into one group each.`) - const list = [...groups].map(([name, set]) => ({ name, members: [...set] })) - return { groups: list, notes, summary: plural(list.length, 'group') } -} - -const colorProbeCtx = document.createElement('canvas').getContext('2d') - -// Returns a canvas-normalized color ("#rrggbb" or "rgba(...)"), or null -// if the browser doesn't recognise the value as a CSS color. -export function normalizeCssColor(value) { - const probe = new Option().style - probe.color = value - if (!probe.color) return null - colorProbeCtx.fillStyle = '#000000' - colorProbeCtx.fillStyle = value - return colorProbeCtx.fillStyle -} - -function parseNormaColors(text) { - // numbers instead of colors: a numeric expression file - const sample = normaLines(text) - .filter((l) => l.trim()) - .slice(0, 300) - if (sample.length && numericShare(sample.slice(1)) >= 0.8) return parseNumericValues(text) - const lines = normaLines(text) - const colors = new Map() - const invalid = [], - shortLines = [] - let headerSkipped = false, - firstDataLine = true - lines.forEach((raw, i) => { - if (!raw.trim()) return - const cols = normaCols(raw) - if (cols.length < 2) { - shortLines.push(i + 1) - firstDataLine = false - return - } - const [node, value] = cols - const color = normalizeCssColor(value) - if (!color) { - if (firstDataLine && /^(nodes?|genes?|names?|ids?|proteins?)$/i.test(node)) { - headerSkipped = true - } else invalid.push(`${node} (${value})`) - firstDataLine = false - return - } - firstDataLine = false - colors.set(node, color) - }) - if (!colors.size) { - throw new Error( - 'No node colors were found. Each line should be a node name, a tab, then a color such as red or #ff0000.' - ) - } - const notes = [] - if (headerSkipped) - notes.push( - 'Skipped the first line because it looks like a header. Node-color files have no header row.' - ) - if (shortLines.length) - notes.push( - `Skipped ${plural(shortLines.length, 'line')} without both a node and a color: line ${listSample(shortLines)}.` - ) - if (invalid.length) - notes.push( - `Ignored ${plural(invalid.length, 'unrecognised color')}: ${listSample(invalid)}. Use a color name like red or a hex code like #ff0000.` - ) - return { colors, notes, summary: plural(colors.size, 'colored node') } -} - -export const NORMA_PARSERS = { - network: parseNormaNetwork, - annotation: parseNormaAnnotation, - colors: parseNormaColors, -} - -// Guesses a file's kind: a Source/Target header means a network; a second -// column that is (almost) always a color means an expression file; -// anything else is read as an annotation. -export function detectNormaKind(text) { - const lines = normaLines(text) - .filter((l) => l.trim()) - .slice(0, 300) - if (!lines.length) return null - const head = normaCols(lines[0]).map((c) => c.toLowerCase()) - if (head[0] === 'source' && head[1] === 'target') return 'network' - if (numericShare(lines.slice(1)) >= 0.8) return 'colors' - let rows = 0, - colorish = 0, - commas = 0 - lines.forEach((line) => { - const tab = line.indexOf('\t') - const second = (tab >= 0 ? line.slice(tab + 1) : line.trim().split(/\s+/)[1] || '').trim() - if (!second) return - rows++ - if (second.includes(',')) commas++ - else if (normalizeCssColor(second)) colorish++ - }) - if (rows && !commas && colorish >= rows * 0.8) return 'colors' - return 'annotation' -} - -function uniqueNormaName(kind, name) { - const taken = new Set(normaLibrary[kind].map((e) => e.name)) - if (!taken.has(name)) return name - let n = 2 - while (taken.has(`${name} (${n})`)) n++ - return `${name} (${n})` -} - -// Parses and stores a file. Throws with a readable message if the file -// doesn't match the format; returns the new library entry otherwise. -export function addNormaEntry(kind, name, text, fileName, sourceKey, options) { - const parsed = NORMA_PARSERS[kind](text, options || {}) - const entry = { - id: 'lib' + ++S.normaEntrySeq, - kind, - name: uniqueNormaName(kind, name), - fileName: fileName || '', - sourceKey: sourceKey || null, - text, - options: options || {}, - parsed, - } - normaLibrary[kind].push(entry) - return entry -} - -export function libEntry(kind, id) { - return normaLibrary[kind].find((e) => e.id === id) || null -} - -export function selectedNetworks() { - return normaLibrary.network.filter((e) => libSelection.networks.has(e.id)) -} - -export function selectionKey() { - return { - nets: selectedNetworks() - .map((e) => e.id) - .join('|'), - annotation: libSelection.annotation, - colors: libSelection.colors, - } -} - -function selectionDiffersFromView() { - if (!S.currentLibView) return libSelection.networks.size > 0 - const k = selectionKey() - return ( - k.nets !== S.currentLibView.nets || - k.annotation !== S.currentLibView.annotation || - k.colors !== S.currentLibView.colors - ) -} - -export function updateRefreshState() { - const pending = selectionDiffersFromView() && libSelection.networks.size > 0 - document.getElementById('refreshHint').hidden = !pending - const btn = document.getElementById('btnRefreshView') - btn.classList.toggle('pending', pending) - btn.disabled = libSelection.networks.size === 0 - const nb = document.getElementById('btnOpenNewView') - if (nb) nb.disabled = libSelection.networks.size === 0 -} - -export function renderLibraryLists() { - const delAll = document.getElementById('btnDeleteAllFiles') - if (delAll) delAll.disabled = !NORMA_KINDS.some((k) => normaLibrary[k].length) - NORMA_KINDS.forEach((kind) => { - const el = document.getElementById(LIB_LIST_IDS[kind]) - el.innerHTML = '' - const entries = normaLibrary[kind] - const multi = kind === 'network' - const groupName = 'lib-' + kind - - if (!multi) { - el.appendChild( - libRow({ - kind, - inputType: 'radio', - groupName, - id: '', - name: 'None', - meta: '', - checked: (kind === 'annotation' ? libSelection.annotation : libSelection.colors) === '', - }) - ) - } - if (multi && !entries.length) { - const empty = document.createElement('div') - empty.className = 'lib-empty' - empty.textContent = 'Upload a network or load an example.' - el.appendChild(empty) - } - sortedByName(entries, (e) => e.name).forEach((e) => { - const checked = multi - ? libSelection.networks.has(e.id) - : (kind === 'annotation' ? libSelection.annotation : libSelection.colors) === e.id - el.appendChild( - libRow({ - kind, - inputType: multi ? 'checkbox' : 'radio', - groupName, - id: e.id, - name: e.name, - meta: e.parsed.summary, - checked, - removable: true, - title: e.fileName ? `${e.name} (${e.fileName})` : e.name, - }) - ) - }) - }) - updateRefreshState() - if (typeof renderProfilerNetworkList === 'function') renderProfilerNetworkList() -} - -function libRow({ kind, inputType, groupName, id, name, meta, checked, removable, title }) { - const row = document.createElement('label') - row.className = 'lib-row' - if (title) row.title = title - const input = document.createElement('input') - input.type = inputType - input.name = groupName - input.checked = checked - input.value = id - input.addEventListener('change', () => { - if (kind === 'network') { - if (input.checked) libSelection.networks.add(id) - else libSelection.networks.delete(id) - } else if (input.checked) { - if (kind === 'annotation') libSelection.annotation = id - else libSelection.colors = id - } - updateRefreshState() - }) - const text = document.createElement('span') - text.className = 'lib-text' - const nameEl = document.createElement('span') - nameEl.className = 'lib-name' - nameEl.textContent = name - text.appendChild(nameEl) - if (meta) { - const metaEl = document.createElement('span') - metaEl.className = 'lib-meta' - metaEl.textContent = meta - text.appendChild(metaEl) - } - row.append(input, text) - if (removable) { - const rm = document.createElement('button') - rm.type = 'button' - rm.className = 'lib-remove' - rm.textContent = '✕' - rm.setAttribute('aria-label', `Delete ${name}`) - rm.title = 'Delete this file from NORMA' - rm.addEventListener('click', (ev) => { - ev.preventDefault() - ev.stopPropagation() - askDelete([{ kind, id }]) - }) - row.appendChild(rm) - } - return row -} - -// kept for scripts: deletes without asking -function removeLibEntry(kind, id) { - deleteLibEntries([{ kind, id }]) -} - -// items: [{ level: 'ok' | 'warn' | 'error' | 'busy', text, action?: { label, run } }] -// opens the folded sidebar section that holds `el` -function revealSection(el) { - const sec = el && el.closest && el.closest('.section.collapsible.collapsed') - if (!sec) return - sec.classList.remove('collapsed') - const h = sec.querySelector(':scope > h3') - if (h) h.setAttribute('aria-expanded', 'true') -} - -// A busy item may carry `progress`: a fraction from 0 to 1, or null while -// the amount of work is unknown (an animated bar). Repeated progress updates -// change the bar in place, so it moves smoothly and screen readers are not -// sent every percentage. -export function setStatus(elId, items) { - const el = document.getElementById(elId) - if (!el) return - const withProgress = items.length === 1 && items[0].progress !== undefined - if (!withProgress && progressTasks && progressTasks.has(elId)) progressTasks.get(elId).stop() - if (withProgress) { - const note = el.children.length === 1 ? el.firstElementChild : null - if (note && note.classList.contains('busy') && note._progress) { - updateProgressNote(note, items[0]) - return - } - } - // sections start folded: an error opens the section so it is seen - if (items.some((i) => i.level === 'error')) revealSection(el) - el.innerHTML = '' - items.forEach((item) => { - const note = document.createElement('div') - note.className = 'note ' + (item.level || 'ok') - if (item.progress !== undefined) { - const label = document.createElement('span') - const row = document.createElement('div') - row.className = 'progress-row' - const bar = document.createElement('div') - bar.className = 'progress' - bar.setAttribute('role', 'progressbar') - bar.setAttribute('aria-valuemin', '0') - bar.setAttribute('aria-valuemax', '100') - bar.appendChild(document.createElement('span')) - const pct = document.createElement('span') - pct.className = 'progress-pct' - pct.setAttribute('aria-hidden', 'true') - row.append(bar, pct) - note.append(label, row) - note._progress = { label, bar, pct } - updateProgressNote(note, item) - el.appendChild(note) - return - } - note.textContent = item.text - if (item.action) { - const btn = document.createElement('button') - btn.type = 'button' - btn.textContent = item.action.label - btn.addEventListener('click', item.action.run) - note.appendChild(btn) - } - el.appendChild(note) - }) -} - -function updateProgressNote(note, item) { - const { label, bar, pct } = note._progress - if (label.textContent !== item.text) { - label.textContent = item.text - bar.setAttribute('aria-label', item.text) - } - const f = item.progress - if (typeof f === 'number' && Number.isFinite(f)) { - const v = Math.max(0, Math.min(1, f)) - bar.classList.remove('indeterminate') - bar.firstElementChild.style.width = (v * 100).toFixed(1) + '%' - bar.setAttribute('aria-valuenow', String(Math.round(v * 100))) - pct.textContent = Math.floor(v * 100) + '%' - } else { - bar.classList.add('indeterminate') - bar.firstElementChild.style.width = '' - bar.removeAttribute('aria-valuenow') - pct.textContent = '' - } -} - -/* ---------- progress of a task made of weighted steps ---------- - const task = startProgress('stringStatus', [1, 2, 5]); - task.step(0, 'Checking the version…'); // moves to a step - task.sub(0.4); // measured progress in the step - task.say('Reading 3 of 8…'); // new text, same step - task.bytes(received, total); // download progress in the step - Until a step reports measured progress, its bar creeps slowly toward the - end of the step (never reaching it), so a long single request still shows - that work goes on. Any status that is not a progress update, such as the - result or an error, ends the task. */ -var progressTasks = new Map() - -function formatBytes(n) { - if (n < 1024) return `${n} B` - if (n < 1048576) return `${(n / 1024).toFixed(0)} kB` - return `${(n / 1048576).toFixed(n < 10485760 ? 1 : 0)} MB` -} - -export function startProgress(elId, weights) { - const old = progressTasks.get(elId) - if (old) old.stop() - const w = weights.map((x) => Math.max(0, +x || 0)) - const total = w.reduce((a, b) => a + b, 0) || 1 - const starts = w.map((_, i) => w.slice(0, i).reduce((a, b) => a + b, 0)) - const task = { - index: 0, - text: '', - measured: null, - stepStart: performance.now(), - received: 0, - active: true, - timer: null, - last: 0, - fraction() { - const i = Math.min(this.index, w.length - 1) - let sub = this.measured - if (sub === null) { - // creep: about half of the step after ~6 s, never more than 85% - const t = (performance.now() - this.stepStart) / 1000 - sub = 0.85 * (1 - Math.exp(-t / 8)) - } - return (starts[i] + w[i] * Math.max(0, Math.min(1, sub))) / total - }, - render(force) { - if (!this.active) return - const now = performance.now() - if (!force && now - this.last < 100) return - this.last = now - const extra = this.received ? ` (${formatBytes(this.received)} received)` : '' - setStatus(elId, [{ level: 'busy', text: this.text + extra, progress: this.fraction() }]) - }, - step(i, text) { - this.index = i - this.text = text - this.measured = null - this.received = 0 - this.stepStart = performance.now() - this.render(true) - }, - say(text) { - this.text = text - this.render(true) - }, - sub(f) { - this.measured = Math.max(0, Math.min(1, f)) - this.render() - }, - bytes(received, totalBytes) { - this.received = received - if (totalBytes > 0 && received <= totalBytes) this.measured = received / totalBytes - this.render() - }, - stop() { - this.active = false - clearInterval(this.timer) - if (progressTasks.get(elId) === this) progressTasks.delete(elId) - }, - } - progressTasks.set(elId, task) - task.timer = setInterval(() => task.render(true), 400) - return task -} - -// Resolves once the browser has had a chance to paint (for example a -// progress note) before synchronous work; does not wait in a hidden tab. -export function nextPaint() { - return new Promise((resolve) => { - let done = false - const finish = () => { - if (!done) { - done = true - resolve() - } - } - requestAnimationFrame(() => setTimeout(finish, 0)) - setTimeout(finish, 60) - }) -} - -// Reads a response body as text, reporting the bytes received so far and, -// when the server gives it, the total. -export async function readTextWithProgress(response, onBytes) { - if (!onBytes || !response.body || typeof response.body.getReader !== 'function') - return response.text() - const total = Number(response.headers.get('Content-Length')) || 0 - const reader = response.body.getReader() - const decoder = new TextDecoder() - let received = 0, - out = '' - for (;;) { - const { done, value } = await reader.read() - if (done) break - received += value.length - out += decoder.decode(value, { stream: true }) - onBytes(received, total) - } - return out + decoder.decode() -} - -export function downloadText(fileName, text) { - const blob = new Blob([text], { type: 'text/plain' }) - const a = document.createElement('a') - a.href = URL.createObjectURL(blob) - a.download = fileName - document.body.appendChild(a) - a.click() - a.remove() - setTimeout(() => URL.revokeObjectURL(a.href), 1000) -} - -export function annotationText(groups) { - return groups.map((g) => `${g.name}\t${g.members.join(',')}`).join('\n') + '\n' -} - -export function fileStem(name) { - return ( - String(name) - .replace(/\.[^.]+$/, '') - .replace(/[^\w.-]+/g, '_') - .replace(/^_+|_+$/g, '') || 'file' - ) -} - -// page wiring, run by main.ts in the original order -export function init() { - document.getElementById('btnRunLayout').addEventListener('click', runActiveLayout) - - document.querySelectorAll('#layoutModeSwitch [role="radio"]').forEach((btn) => { - btn.addEventListener('click', () => setLayoutMode(btn.dataset.mode)) - btn.addEventListener('keydown', (e) => { - if (!['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(e.key)) return - e.preventDefault() - const next = btn.dataset.mode === 'groups' ? 'connections' : 'groups' - setLayoutMode(next) - document.querySelector(`#layoutModeSwitch [data-mode="${next}"]`).focus() - }) - }) - - ;['groupArrangement', 'localGroupLayout'].forEach((id) => { - document.getElementById(id).addEventListener('change', updateStrategyUI) - }) - - ;['groupForce', 'groupClusterRadius'].forEach((id) => { - document.getElementById(id).addEventListener('input', updateStrategyUI) - }) - - document.getElementById('btnFit').addEventListener('click', () => fitView()) - - document.getElementById('btnSample').addEventListener('click', () => { - const sel = document.getElementById('sampleSelect') - const key = sel.value - const title = sel.options[sel.selectedIndex].text.replace(/\s*\([^)]*nodes\)\s*$/, '') - openInNewView(title, () => { - if (key.startsWith('norma:')) { - loadNormaExampleSet(key.slice(6)) - return - } - libSelection.networks = new Set() - libSelection.annotation = '' - libSelection.colors = '' - renderLibraryLists() - const gen = SAMPLE_GENERATORS[key] || SAMPLE_GENERATORS.trp - loadData(gen()) - setStatus('normaStatus', []) - }) - }) - - document.getElementById('btnClear').addEventListener('click', () => { - clearCanvas() - setStatus('normaStatus', []) - updateRefreshState() - buildGroupLegend() - }) - - // With a filter set, these act only on the matching groups. - document.getElementById('btnGroupsAll').addEventListener('click', () => { - filteredGroups().forEach((g) => S.activeGroups.add(g)) - buildGroupLegend() - applyGroupVisibility() - }) - - document.getElementById('btnGroupsNone').addEventListener('click', () => { - filteredGroups().forEach((g) => S.activeGroups.delete(g)) - buildGroupLegend() - applyGroupVisibility() - }) - - document.getElementById('groupFilter').addEventListener('input', buildGroupLegend) - - document.getElementById('btnImportToggle').addEventListener('click', () => { - const box = document.getElementById('importBox') - box.style.display = box.style.display === 'none' ? 'block' : 'none' - }) - - document.getElementById('btnImportGo').addEventListener('click', () => { - try { - const parsed = JSON.parse(document.getElementById('importArea').value) - if (!parsed.nodes || !parsed.edges) throw new Error('JSON needs "nodes" and "edges" arrays.') - openInNewView('Pasted JSON', () => loadData(parsed)) - document.getElementById('importBox').style.display = 'none' - } catch (err) { - alert('Could not parse JSON: ' + err.message) - } - }) - - document - .getElementById('btnFileTrigger') - .addEventListener('click', () => document.getElementById('fileInput').click()) - - document.getElementById('fileInput').addEventListener('change', (e) => { - const file = e.target.files[0] - if (!file) return - const reader = new FileReader() - reader.onload = (ev) => { - try { - const parsed = JSON.parse(ev.target.result) - if (!parsed.nodes || !parsed.edges) - throw new Error('JSON needs "nodes" and "edges" arrays.') - openInNewView(file.name.replace(/\.json$/i, ''), () => loadData(parsed)) - } catch (err) { - alert('Could not read file: ' + err.message) - } - } - reader.readAsText(file) - e.target.value = '' - }) - - document.getElementById('btnExport').addEventListener('click', () => { - const nodeColors = {} - cy.nodes().forEach((n) => { - ;(n.data('groups') || []).forEach((g) => { - nodeColors[g] = S.nodeColorMap[g] || nodeColors[g] - }) - }) - const edgeColors = {} - cy.edges().forEach((e) => { - edgeColors[e.data('type')] = e.data('color') - }) - const data = { - nodes: exportNodes().map((n) => ({ - id: n.data('id'), - groups: (n.data('groups') || []).filter((g) => g !== UNGROUPED), - size: n.data('baseSize'), - ...(n.data('nodeColor') ? { color: n.data('nodeColor') } : {}), - ...(n.data('values') ? { values: n.data('values') } : {}), - ...(n.data('attrs') || {}), - })), - edges: exportEdges().map((e) => { - const out = { - id: e.data('id'), - source: e.data('source'), - target: e.data('target'), - type: e.data('type'), - } - const w = e.data('weight') - if (typeof w === 'number') out.weight = w - if (edgeIsDirected(e)) out.directed = true - return { ...out, ...(e.data('attrs') || {}) } - }), - nodeColors, - edgeColors, - groupOrder: getUsedGroups().filter((g) => g !== UNGROUPED), - ...(Object.keys(S.groupShapes).length ? { groupShapes: S.groupShapes } : {}), - ...(Object.keys(S.groupAttrs).length ? { groupAttrs: S.groupAttrs } : {}), - } - const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' }) - const a = document.createElement('a') - a.href = URL.createObjectURL(blob) - a.download = 'network.json' - a.click() - }) - - /* settings (config) export / import -- separate from network data */ - document.getElementById('btnExportConfig').addEventListener('click', () => { - const blob = new Blob([JSON.stringify(getCurrentConfig(), null, 2)], { - type: 'application/json', - }) - const a = document.createElement('a') - a.href = URL.createObjectURL(blob) - a.download = 'norma-settings.json' - a.click() - }) - - document - .getElementById('btnImportConfigTrigger') - .addEventListener('click', () => document.getElementById('configFileInput').click()) - - document.getElementById('configFileInput').addEventListener('change', (e) => { - const file = e.target.files[0] - if (!file) return - const reader = new FileReader() - reader.onload = (ev) => { - try { - const parsed = JSON.parse(ev.target.result) - applyConfig(parsed) - } catch (err) { - alert('Could not read settings file: ' + err.message) - } - } - reader.readAsText(file) - e.target.value = '' - }) -} diff --git a/frontend/src/layouts/cose.worker.ts b/frontend/src/layouts/cose.worker.ts deleted file mode 100644 index 4419df6..0000000 --- a/frontend/src/layouts/cose.worker.ts +++ /dev/null @@ -1,19 +0,0 @@ -// Cytoscape's cose layout, headless, off the main thread. See coseInWorker in run.ts. -import cytoscape from 'cytoscape' - -self.onmessage = (e: MessageEvent) => { - const { elements, style, opts } = e.data - try { - const cy = cytoscape({ headless: true, styleEnabled: true, elements, style }) - cy.elements() - .layout({ ...opts, animate: false }) - .run() - const positions: Record = {} - cy.nodes().forEach((n) => { - positions[n.id()] = n.position() - }) - self.postMessage({ positions }) - } catch (err) { - self.postMessage({ error: String(err) }) - } -} diff --git a/frontend/src/layouts/input.ts b/frontend/src/layouts/input.ts deleted file mode 100644 index 1188648..0000000 --- a/frontend/src/layouts/input.ts +++ /dev/null @@ -1,592 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { - EDGE_BLIND_LAYOUTS, - FR_SEED, - computeSubLayoutAsync, - normalizeSpacing, - targetNodeSpacing, -} from '../metrics' -import { S } from '../state' -import { UNGROUPED, effectiveGroupsFor } from '../network_state' -import { cy } from '../cy' -import { mulberry32 } from '../sample_data' -import { nextPaint } from './controls' - -/* ---------- layout input: what the strategies see ---------- */ -// Visible nodes, their active groups, and one weighted edge per node pair -// (parallel channels collapse, keeping the highest weight, as NORMA's -// simplify(edge.attr.comb = "max") does). Missing weights count as 1. -export function collectLayoutGraph() { - const channelOnly = document.getElementById('layoutOnActiveOnly').checked - const nodes = cy.nodes().filter((n) => !n.hasClass('hidden-group')) - const nodeIds = nodes.map((n) => n.id()) - const visible = new Set(nodeIds) - const groupsOf = {} - const groupMembers = new Map() - nodes.forEach((n) => { - const gs = effectiveGroupsFor(n).filter((g) => g !== UNGROUPED) - groupsOf[n.id()] = gs - gs.forEach((g) => { - if (!groupMembers.has(g)) groupMembers.set(g, []) - groupMembers.get(g).push(n.id()) - }) - }) - const pairs = new Map() - cy.edges().forEach((e) => { - if (channelOnly && !S.activeTypes.has(e.data('type'))) return - const s = e.data('source'), - t = e.data('target') - if (s === t || !visible.has(s) || !visible.has(t)) return - const key = s < t ? s + '\t' + t : t + '\t' + s - const w = typeof e.data('weight') === 'number' && e.data('weight') > 0 ? e.data('weight') : 1 - const p = pairs.get(key) - if (p) p.weight = Math.max(p.weight, w) - else pairs.set(key, { source: s, target: t, weight: w }) - }) - return { nodeIds, groupsOf, groupMembers, edges: [...pairs.values()] } -} - -function sharesGroup(a, b) { - return a.length > 0 && b.length > 0 && a.some((g) => b.includes(g)) -} - -// All-vs-all pairs inside a group. Very large groups get a sparse random -// subset per member instead of a full clique, which would otherwise add -// hundreds of thousands of layout-only edges. -const CLIQUE_FULL_LIMIT = 400 - -const CLIQUE_SPARSE_DEGREE = 60 - -function groupPairs(members, rand) { - const out = [] - if (members.length <= CLIQUE_FULL_LIMIT) { - for (let i = 0; i < members.length; i++) { - for (let j = i + 1; j < members.length; j++) out.push([members[i], members[j]]) - } - } else { - members.forEach((a) => { - for (let k = 0; k < CLIQUE_SPARSE_DEGREE; k++) { - const b = members[Math.floor(rand() * members.length)] - if (a !== b) out.push([a, b]) - } - }) - } - return out -} - -/* ============================================================ - NORMA-2.0 GROUP LAYOUT STRATEGIES - Karatzas et al. (2022) Bioinformatics Advances 2(1):vbac036, - Figure 1. Weights and steps follow NORMA's own implementation - (strategy1_virtualNodes, strategy2_gravity, strategy3_superNodes in - github.com/PavlopoulosLab/NORMA, functions/annotations.R). - ============================================================ */ - -// Strategy 1 -- virtual nodes (Fig. 1A). One hidden hub per group, tied to -// every member with a heavy edge (50); real edges get weight 5 and group -// members get light all-pairs edges (0.1). The chosen layout runs on this -// enlarged graph and the hubs are then dropped. -export async function strategyVirtualNodes(graph, layoutName) { - const rand = mulberry32(FR_SEED) - const ids = [...graph.nodeIds] - const edges = graph.edges.map((e) => ({ source: e.source, target: e.target, weight: 5 })) - graph.groupMembers.forEach((members, g) => { - const hub = '\u0000virtual:' + g - ids.push(hub) - if (members.length >= 2 && !EDGE_BLIND_LAYOUTS.has(layoutName)) { - groupPairs(members, rand).forEach(([a, b]) => - edges.push({ source: a, target: b, weight: 0.1 }) - ) - } - members.forEach((m) => edges.push({ source: hub, target: m, weight: 50 })) - }) - const pos = await computeSubLayoutAsync(ids, edges, layoutName) - if (!pos) return null - const real = {} - graph.nodeIds.forEach((id) => { - real[id] = pos[id] - }) - return normalizeSpacing(real, targetNodeSpacing()) -} - -// Strategy 2 -- group gravity (Fig. 1B). Groups become cliques with -// layout-only edges at the network's highest weight; real edges inside a -// group are multiplied by the force and edges that leave a group (or touch -// an ungrouped node) are divided by it. Parallel pairs keep the max. -export async function strategyGravity(graph, layoutName, force) { - const rand = mulberry32(FR_SEED) - const maxW = graph.edges.reduce((m, e) => Math.max(m, e.weight), 1) - const pairs = new Map() - const put = (a, b, w) => { - const key = a < b ? a + '\t' + b : b + '\t' + a - const p = pairs.get(key) - if (p) p.weight = Math.max(p.weight, w) - else pairs.set(key, { source: a, target: b, weight: w }) - } - graph.edges.forEach((e) => { - const inside = sharesGroup(graph.groupsOf[e.source], graph.groupsOf[e.target]) - put(e.source, e.target, inside ? e.weight * force : e.weight / force) - }) - if (!EDGE_BLIND_LAYOUTS.has(layoutName)) { - graph.groupMembers.forEach((members) => { - groupPairs(members, rand).forEach(([a, b]) => put(a, b, maxW)) - }) - } - const pos = await computeSubLayoutAsync(graph.nodeIds, [...pairs.values()], layoutName) - return pos ? normalizeSpacing(pos, targetNodeSpacing()) : null -} - -/* ---------- shared group placement ---------- - Radius a group's local layout gets, in pixels. A ring must fit every - member at the usual node spacing, so circles of big groups get a larger - radius than the area-based estimate used for the other local layouts. */ -function localGroupRadius(k, localName, spacing, clusterScale) { - const area = 0.95 * spacing * Math.sqrt(Math.max(1, k)) - const ring = localName === 'circle' ? (k * spacing) / (2 * Math.PI) : 0 - return Math.max(spacing / 2, area, ring) * clusterScale -} - -// Lays each group's members out with `localName`, scaled to `radii[g]` and -// centred on `centers[g]`. Returns { nodeId: [candidate positions] } so that -// a node in several groups can be averaged afterwards. -async function placeGroupsLocally(graph, groups, centers, radii, localName, force) { - const rand = mulberry32(FR_SEED) - const candidates = {} - const lp0 = S.layoutProgress - if (lp0) lp0.begin([...groups].reduce((a, [, m]) => a + m.length, 0)) - let lastPaint = performance.now() - for (const [g, members] of groups) { - if (lp0) lp0.part(members.length) - if (performance.now() - lastPaint > 60) { - await nextPaint() - lastPaint = performance.now() - } - const center = centers[g] - const radius = radii[g] - if (members.length === 1) { - ;(candidates[members[0]] = candidates[members[0]] || []).push({ x: center.x, y: center.y }) - continue - } - const memberSet = new Set(members) - const local = graph.edges - .filter((e) => memberSet.has(e.source) && memberSet.has(e.target)) - .map((e) => ({ ...e })) - if (!EDGE_BLIND_LAYOUTS.has(localName)) { - const minW = local.length ? local.reduce((m, e) => Math.min(m, e.weight), Infinity) : 1 - groupPairs(members, rand).forEach(([a, b]) => - local.push({ source: a, target: b, weight: minW / Math.max(1, force) }) - ) - } - const lp = await computeSubLayoutAsync(members, local, localName) - if (!lp) return null - let x1 = Infinity, - x2 = -Infinity, - y1 = Infinity, - y2 = -Infinity - members.forEach((id) => { - x1 = Math.min(x1, lp[id].x) - x2 = Math.max(x2, lp[id].x) - y1 = Math.min(y1, lp[id].y) - y2 = Math.max(y2, lp[id].y) - }) - const mx = (x1 + x2) / 2, - my = (y1 + y2) / 2 - // fit the farthest member onto the disc's edge, so every shape - // (square grids included) stays inside the group's disc - const reach = members.reduce( - (m, id) => Math.max(m, Math.hypot(lp[id].x - mx, lp[id].y - my)), - 0 - ) - const scale = reach > 1e-9 ? radius / reach : 0 - members.forEach((id) => { - ;(candidates[id] = candidates[id] || []).push({ - x: center.x + (lp[id].x - mx) * scale, - y: center.y + (lp[id].y - my) * scale, - }) - }) - } - return candidates -} - -function averageCandidates(candidates, fallback) { - const out = { ...(fallback || {}) } - Object.entries(candidates).forEach(([id, list]) => { - out[id] = { - x: list.reduce((a, p) => a + p.x, 0) / list.length, - y: list.reduce((a, p) => a + p.y, 0) / list.length, - } - }) - return out -} - -// Pushes discs apart until none overlap (keeping `gap` between them). -// Smaller discs give way more than big ones. With `compact`, discs are -// first drawn toward the middle while being kept apart, which packs -// scattered groups (for example unconnected ones) into a tidy cluster. -function resolveOverlaps(keys, centers, radii, gap, { compact = false } = {}) { - const n = keys.length - if (n < 2) return - const pullPasses = compact ? 250 : 0 - for (let pass = 0; pass < pullPasses + 400; pass++) { - if (pass < pullPasses) { - let mx = 0, - my = 0 - keys.forEach((k) => { - mx += centers[k].x - my += centers[k].y - }) - mx /= n - my /= n - const pull = 0.04 * (1 - pass / pullPasses) - keys.forEach((k) => { - centers[k].x += (mx - centers[k].x) * pull - centers[k].y += (my - centers[k].y) * pull - }) - } - let worst = 0 - for (let i = 0; i < n; i++) { - const a = centers[keys[i]], - ra = radii[keys[i]] - for (let j = i + 1; j < n; j++) { - const b = centers[keys[j]], - rb = radii[keys[j]] - let dx = b.x - a.x, - dy = b.y - a.y - let d = Math.hypot(dx, dy) - const overlap = ra + rb + gap - d - if (overlap <= 0) continue - if (d < 1e-6) { - dx = Math.cos(i * 2.399 + j) - dy = Math.sin(i * 2.399 + j) - d = 1 - } - const shareA = rb / (ra + rb), - shareB = ra / (ra + rb) - a.x -= (dx / d) * overlap * shareA - a.y -= (dy / d) * overlap * shareA - b.x += (dx / d) * overlap * shareB - b.y += (dy / d) * overlap * shareB - worst = Math.max(worst, overlap) - } - } - if (pass >= pullPasses && worst < 0.5) break - } -} - -// Places discs around a ring so neighbours are exactly far enough apart -// (straight-line distance, not arc length). Returns the ring radius. -function ringRadiusFor(radii, gap, minR) { - const needAngle = (R) => - radii.reduce((acc, r) => acc + 2 * Math.asin(Math.min(1, (r + gap / 2) / R)), 0) - let lo = Math.max(minR, Math.max(...radii) + gap / 2), - hi = lo - while (needAngle(hi) > 2 * Math.PI) hi *= 1.5 - if (needAngle(lo) <= 2 * Math.PI) return lo - for (let i = 0; i < 40; i++) { - const mid = (lo + hi) / 2 - if (needAngle(mid) > 2 * Math.PI) lo = mid - else hi = mid - } - return hi -} - -function placeOnRing(keys, radii, gap, R, centers, startAngle) { - const halves = keys.map((g) => Math.asin(Math.min(1, (radii[g] + gap / 2) / R))) - const used = halves.reduce((a, h) => a + 2 * h, 0) - const slack = keys.length ? Math.max(0, 2 * Math.PI - used) / keys.length : 0 - let angle = startAngle - keys.forEach((g, i) => { - angle += halves[i] + slack / 2 - centers[g] = { x: R * Math.cos(angle), y: R * Math.sin(angle) } - angle += halves[i] + slack / 2 - }) -} - -// The collapsed "group network": one node per group, linked when real -// edges cross between groups, weighted by how many do. -function groupSuperGraph(graph, groups) { - const memberOf = {} - groups.forEach(([g, members]) => - members.forEach((id) => (memberOf[id] = memberOf[id] || []).push(g)) - ) - const pairs = new Map() - graph.edges.forEach((e) => { - ;(memberOf[e.source] || []).forEach((a) => - (memberOf[e.target] || []).forEach((b) => { - if (a === b) return - const key = a < b ? a + '\t' + b : b + '\t' + a - const p = pairs.get(key) - if (p) p.count += 1 - else pairs.set(key, { source: a, target: b, count: 1 }) - }) - ) - }) - // log scale: a pair of groups with hundreds of links shouldn't collapse - return [...pairs.values()].map((p) => ({ - source: p.source, - target: p.target, - weight: 1 + Math.log(p.count), - })) -} - -/* ---------- group blocks ---------- - Each group (plus one block for nodes in no group) is a disc sized to its - local layout; the discs are arranged with the chosen scheme and never - overlap. `spacing` sets the gap between discs. */ -const UNGROUPED_BLOCK = '\u0000ungrouped' - -export async function blockGroupLayout(graph, arrangement, localName, force, clusterScale) { - const spacing = targetNodeSpacing() - const groups = [...graph.groupMembers] - const ungrouped = graph.nodeIds.filter((id) => !graph.groupsOf[id].length) - if (ungrouped.length) groups.push([UNGROUPED_BLOCK, ungrouped]) - const keys = groups.map(([g]) => g) - const radii = {} - groups.forEach(([g, m]) => { - radii[g] = localGroupRadius(m.length, localName, spacing, clusterScale) - }) - // room for the group shading (it extends beyond the outermost nodes) - const gap = spacing * 2.5 * (force / 10) - const centers = {} - - if (arrangement === 'circle') { - if (keys.length === 1) { - centers[keys[0]] = { x: 0, y: 0 } - } else { - const R = ringRadiusFor( - keys.map((g) => radii[g]), - gap, - 0 - ) - placeOnRing(keys, radii, gap, R, centers, -Math.PI / 2) - } - } else if (arrangement === 'grid') { - const cells = keys.map((g) => 2 * radii[g] + gap) - const area = cells.reduce((a, c) => a + c * c, 0) - const rowWidth = Math.max(Math.max(...cells), Math.sqrt(area) * 1.15) - let x = 0, - y = 0, - rowH = 0 - keys.forEach((g, i) => { - if (x > 0 && x + cells[i] > rowWidth) { - x = 0 - y += rowH - rowH = 0 - } - centers[g] = { x: x + cells[i] / 2, y: y + cells[i] / 2 } - x += cells[i] - rowH = Math.max(rowH, cells[i]) - }) - } else if (arrangement === 'concentric') { - // biggest group in the middle, then rings of the next biggest - const order = keys.slice().sort((x, y) => radii[y] - radii[x]) - centers[order[0]] = { x: 0, y: 0 } - let inner = radii[order[0]] - let i = 1, - ringIndex = 0 - while (i < order.length) { - const ringR = inner + gap + radii[order[i]] - const ring = [] - let usedAngle = 0 - while (i < order.length) { - const need = 2 * Math.asin(Math.min(1, (radii[order[i]] + gap / 2) / ringR)) - if (ring.length && usedAngle + need > 2 * Math.PI) break - ring.push(order[i]) - usedAngle += need - i++ - } - placeOnRing(ring, radii, gap, ringR, centers, ringIndex * 0.7) - inner = ringR + Math.max(...ring.map((g) => radii[g])) - ringIndex++ - } - } else if (arrangement === 'breadthfirst') { - // levels by distance in the group network from its best-connected group - const edges = groupSuperGraph(graph, groups) - const adj = {} - keys.forEach((g) => { - adj[g] = new Set() - }) - edges.forEach((e) => { - adj[e.source].add(e.target) - adj[e.target].add(e.source) - }) - const level = {} - const byDegree = keys.slice().sort((a, b) => adj[b].size - adj[a].size || radii[b] - radii[a]) - let depthBase = 0 - byDegree.forEach((root) => { - if (level[root] !== undefined) return - level[root] = depthBase - const queue = [root] - let maxDepth = depthBase - while (queue.length) { - const g = queue.shift() - adj[g].forEach((h) => { - if (level[h] === undefined) { - level[h] = level[g] + 1 - maxDepth = Math.max(maxDepth, level[h]) - queue.push(h) - } - }) - } - depthBase = maxDepth + 1 - }) - const rows = [] - keys.forEach((g) => { - ;(rows[level[g]] = rows[level[g]] || []).push(g) - }) - let y = 0 - rows.filter(Boolean).forEach((row) => { - const h = Math.max(...row.map((g) => 2 * radii[g])) + gap - const width = row.reduce((a, g) => a + 2 * radii[g] + gap, 0) - let x = -width / 2 - row.forEach((g) => { - centers[g] = { x: x + radii[g] + gap / 2, y: y + h / 2 } - x += 2 * radii[g] + gap - }) - y += h - }) - } else { - // force-directed arrangement of the group network, then de-overlap - const algorithm = arrangement === 'cose' ? 'cose' : 'fr' - const pos = - keys.length > 1 - ? await computeSubLayoutAsync(keys, groupSuperGraph(graph, groups), algorithm) - : { [keys[0]]: { x: 0, y: 0 } } - if (!pos) return null - const mx = keys.reduce((a, g) => a + pos[g].x, 0) / keys.length - const my = keys.reduce((a, g) => a + pos[g].y, 0) / keys.length - const spread = - keys.reduce((a, g) => a + Math.hypot(pos[g].x - mx, pos[g].y - my), 0) / keys.length || 1 - const target = keys.reduce((a, g) => a + radii[g] + gap / 2, 0) / Math.PI - keys.forEach((g) => { - centers[g] = { - x: ((pos[g].x - mx) / spread) * target, - y: ((pos[g].y - my) / spread) * target, - } - }) - resolveOverlaps(keys, centers, radii, gap, { compact: true }) - } - - const candidates = await placeGroupsLocally(graph, groups, centers, radii, localName, force) - return candidates ? averageCandidates(candidates) : null -} - -// Strategies 1 and 2 place every node themselves. With a local layout -// chosen, each group is then rearranged around where the strategy put it. -export async function applyLocalLayoutsAfter(graph, positions, localName, force, clusterScale) { - if (!positions || localName === 'keep') return positions - const spacing = targetNodeSpacing() - const groups = [...graph.groupMembers] - const keys = groups.map(([g]) => g) - const centers = {}, - radii = {} - groups.forEach(([g, members]) => { - centers[g] = { - x: members.reduce((a, id) => a + positions[id].x, 0) / members.length, - y: members.reduce((a, id) => a + positions[id].y, 0) / members.length, - } - radii[g] = localGroupRadius(members.length, localName, spacing, clusterScale) - }) - resolveOverlaps(keys, centers, radii, spacing * 1.5) - const candidates = await placeGroupsLocally(graph, groups, centers, radii, localName, force) - return candidates ? averageCandidates(candidates, positions) : null -} - -// Strategy 3 -- super nodes (Fig. 1C). Each group collapses into one -// super-node; ungrouped nodes stay as themselves. The chosen algorithm runs -// on that small super-network, the result is pushed outward by the force, -// and each group's members are then laid out locally (with light all-pairs -// edges, min weight / force) around their super-node. A node in several -// groups is placed at the average of its positions. -export async function strategySuperNodes(graph, globalName, localName, force, clusterScale) { - const spacing = targetNodeSpacing() - const superOf = (id) => - graph.groupsOf[id].length ? graph.groupsOf[id].map((g) => 'g\u0000' + g) : ['n\u0000' + id] - - const superIds = new Set() - graph.nodeIds.forEach((id) => superOf(id).forEach((s) => superIds.add(s))) - const superPairs = new Map() - graph.edges.forEach((e) => { - superOf(e.source).forEach((a) => - superOf(e.target).forEach((b) => { - if (a === b) return - const key = a < b ? a + '\t' + b : b + '\t' + a - const p = superPairs.get(key) - if (p) p.weight = Math.max(p.weight, e.weight) - else superPairs.set(key, { source: a, target: b, weight: e.weight }) - }) - ) - }) - const superList = [...superIds] - const superPos = await computeSubLayoutAsync(superList, [...superPairs.values()], globalName) - if (!superPos) return null - - const radiusOf = (s) => - s.startsWith('n\u0000') - ? spacing / 2 - : localGroupRadius( - graph.groupMembers.get(s.slice(2)).length, - localName, - spacing, - clusterScale - ) - const cx = superList.reduce((a, s) => a + superPos[s].x, 0) / superList.length - const cyc = superList.reduce((a, s) => a + superPos[s].y, 0) / superList.length - let normalize = 1 - if (superList.length > 1) { - const radii = superList.map(radiusOf) - const ring = radii.reduce((a, r) => a + r, 0) / Math.PI - const disk = (2 / 3) * Math.sqrt(2 * radii.reduce((a, r) => a + r * r, 0)) - const targetSpread = Math.min(ring, disk) - const meanSpread = - superList.reduce((a, s) => a + Math.hypot(superPos[s].x - cx, superPos[s].y - cyc), 0) / - superList.length - if (meanSpread > 1e-9) { - const spreadFactor = targetSpread / meanSpread - const groupSupers = superList.filter((s) => s.startsWith('g\u0000')) - let pairFactor = 0 - for (let i = 0; i < groupSupers.length; i++) { - for (let j = i + 1; j < groupSupers.length; j++) { - const a = superPos[groupSupers[i]], - b = superPos[groupSupers[j]] - const d = Math.hypot(a.x - b.x, a.y - b.y) - if (d > 1e-9) - pairFactor = Math.max( - pairFactor, - (radiusOf(groupSupers[i]) + radiusOf(groupSupers[j])) / d - ) - } - } - normalize = Math.min(Math.max(spreadFactor, pairFactor), spreadFactor * 2.5) - } else { - superList.forEach((s, i) => { - const angle = (2 * Math.PI * i) / superList.length - superPos[s] = { x: cx + Math.cos(angle), y: cyc + Math.sin(angle) } - }) - normalize = targetSpread - } - } - // NORMA multiplies the super-node coordinates by the force (default 10); - // here force 10 gives 1.6x the "just touching" arrangement. - const repel = normalize * force * 0.16 - const placed = {} - superList.forEach((s) => { - placed[s] = { x: (superPos[s].x - cx) * repel, y: (superPos[s].y - cyc) * repel } - }) - - const groups = [...graph.groupMembers] - const centers = {}, - radii = {} - groups.forEach(([g]) => { - centers[g] = placed['g\u0000' + g] - radii[g] = radiusOf('g\u0000' + g) - }) - const candidates = await placeGroupsLocally(graph, groups, centers, radii, localName, force) - if (!candidates) return null - const ungrouped = {} - graph.nodeIds.forEach((id) => { - if (!graph.groupsOf[id].length) ungrouped[id] = placed['n\u0000' + id] - }) - return averageCandidates(candidates, ungrouped) -} diff --git a/frontend/src/layouts/run.ts b/frontend/src/layouts/run.ts deleted file mode 100644 index b288679..0000000 --- a/frontend/src/layouts/run.ts +++ /dev/null @@ -1,260 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { S } from '../state' -import { - applyLocalLayoutsAfter, - blockGroupLayout, - collectLayoutGraph, - strategyGravity, - strategySuperNodes, - strategyVirtualNodes, -} from './input' -import { - applyPositions, - cancelFrJobs, - computeSubLayoutAsync, - layoutOptsFor, - makeLayoutProgress, - normalizeSpacing, - shownEdges, - shownNodes, - targetNodeSpacing, -} from '../metrics' -import { cy } from '../cy' -import { setStatus } from './controls' -import CoseWorker from './cose.worker?worker&inline' - -/* ---------- running layouts ---------- */ -export const STRATEGIES = new Set(['virtual', 'gravity', 'supernodes']) - -export function layoutMode() { - return document.getElementById('layoutMode').value === 'groups' ? 'groups' : 'connections' -} - -export function groupArrangement() { - return document.getElementById('groupArrangement').value -} - -export function setLayoutBusy(busy) { - document.getElementById('btnRunLayout').disabled = busy - setStatus( - 'layoutStatus', - busy ? [{ level: 'busy', text: 'Computing layout…', progress: null }] : [] - ) -} - -async function runComputedLayout(compute) { - cancelFrJobs() - cancelCoseJob() - const run = ++S.layoutRunSeq - const nodeCount = cy.nodes().length - setLayoutBusy(true) - S.layoutProgress = makeLayoutProgress((f) => { - if (run === S.layoutRunSeq) - setStatus('layoutStatus', [{ level: 'busy', text: 'Computing layout…', progress: f }]) - }) - // let the busy note paint before any work on the page starts - await new Promise((r) => setTimeout(r, 0)) - try { - const positions = await compute() - if (run !== S.layoutRunSeq || cy.nodes().length !== nodeCount) return - if (positions) applyPositions(positions) - } catch (err) { - if (run === S.layoutRunSeq) - setStatus('layoutStatus', [ - { level: 'error', text: `The layout couldn't be computed: ${err.message}` }, - ]) - return - } finally { - if (run === S.layoutRunSeq) { - document.getElementById('btnRunLayout').disabled = false - S.layoutProgress = null - } - } - if (run === S.layoutRunSeq) setStatus('layoutStatus', []) -} - -// Layout by connections: groups play no part. -export function runLayout(name) { - if (name === 'fr' || name === 'kk' || name === 'stress') { - runComputedLayout(async () => { - const graph = collectLayoutGraph() - if (!graph.nodeIds.length) return null - const pos = await computeSubLayoutAsync(graph.nodeIds, graph.edges, name) - return pos ? normalizeSpacing(pos, targetNodeSpacing()) : null - }) - return - } - // a Cytoscape layout replaces any computed one still running - cancelFrJobs() - cancelCoseJob() - S.layoutRunSeq++ - setLayoutBusy(false) - // Animating every force-directed iteration is slow on bigger graphs; - // there, compute first and animate only to the final positions. - const nodes = shownNodes() - const animate = name === 'cose' && nodes.length > 150 ? 'end' : true - const opts = { ...layoutOptsFor(name), animate, animationDuration: 500, padding: 50 } - - // Only the shown part is arranged: nodes of ticked groups and, with - // "Use checked channels only", edges of ticked channels. Hidden nodes - // keep their positions. Shown nodes without a counted edge still take - // part (repulsion only). - const channelOnly = document.getElementById('layoutOnActiveOnly').checked - if (!nodes.length) return - const eles = nodes.union(shownEdges(channelOnly)) - if (animate !== 'end') { - eles.layout(opts).run() - return - } - // Computed in one go, in a worker, then animated to the final positions. - // Once the page has painted a frame, Cytoscape's cose runs 5-7x slower on - // the main thread (a V8 effect, reproducible with plain Cytoscape); a - // worker is a fresh isolate, so it stays fast and the page stays usable. - const run = S.layoutRunSeq - document.getElementById('btnRunLayout').disabled = true - setStatus('layoutStatus', [{ level: 'busy', text: 'Computing layout…', progress: null }]) - const finish = () => { - if (run !== S.layoutRunSeq) return - document.getElementById('btnRunLayout').disabled = false - setStatus('layoutStatus', []) - } - coseInWorker(eles, opts) - .then((positions) => { - if (run !== S.layoutRunSeq) return - if (positions) { - eles - .nodes() - .layout({ - name: 'preset', - positions, - fit: true, - padding: opts.padding, - animate: true, - animationDuration: opts.animationDuration, - }) - .run() - } else eles.layout(opts).run() // no worker (very old browser): as before - }) - .finally(finish) -} - -/* ---------- cose in a worker ---------- */ -let coseWorker = null -let coseJob = null // { resolve } of the run in progress - -function coseInWorker(eles, opts) { - cancelCoseJob() - if (!coseWorker) { - try { - coseWorker = new CoseWorker() - } catch (e) { - return Promise.resolve(null) - } - coseWorker.onmessage = (e) => { - const job = coseJob - coseJob = null - if (job) job.resolve(e.data.error ? null : e.data.positions) - } - coseWorker.onerror = (e) => { - e.preventDefault() - const job = coseJob - coseJob = null - coseWorker = null - if (job) job.resolve(null) - } - } - // what cose reads: node ids, positions and outer sizes, edges, the viewport - const elements = eles.nodes().map((n) => ({ - data: { id: n.id(), w: n.outerWidth(), h: n.outerHeight() }, - position: n.position(), - })) - eles - .edges() - .forEach((e) => - elements.push({ data: { id: e.id(), source: e.source().id(), target: e.target().id() } }) - ) - const { animate, animationDuration, ...rest } = opts - const layout = { ...rest, boundingBox: { x1: 0, y1: 0, w: cy.width(), h: cy.height() } } - return new Promise((resolve) => { - coseJob = { resolve } - coseWorker.postMessage({ - elements, - style: [{ selector: 'node', style: { width: 'data(w)', height: 'data(h)' } }], - opts: layout, - }) - }) -} - -// Stops a cose computation still running in the worker; its caller sees null. -export function cancelCoseJob() { - if (!coseJob) return - const job = coseJob - coseJob = null - coseWorker.terminate() - coseWorker = null - job.resolve(null) -} - -// Layout by groups: block arrangements or a NORMA-2.0 strategy, each -// followed by the chosen layout inside every group. -export function runGroupLayout() { - const graph = collectLayoutGraph() - if (!graph.nodeIds.length) return - if (!graph.groupMembers.size) { - setStatus('layoutStatus', [ - { - level: 'warn', - text: 'This view has no active groups to arrange, so the nodes were arranged by their connections instead.', - }, - ]) - runLayout('fr') - return - } - const arrangement = groupArrangement() - const algorithm = document.getElementById('strategyAlgorithm').value - const force = parseFloat(document.getElementById('groupForce').value) || 10 - const clusterScale = parseFloat(document.getElementById('groupClusterRadius').value) || 1 - let localName = document.getElementById('localGroupLayout').value - const keepAllowed = arrangement === 'virtual' || arrangement === 'gravity' - if (localName === 'keep' && !keepAllowed) localName = 'circle' - runComputedLayout(async () => { - if (arrangement === 'virtual') { - return applyLocalLayoutsAfter( - graph, - await strategyVirtualNodes(graph, algorithm), - localName, - force, - clusterScale - ) - } - if (arrangement === 'gravity') { - return applyLocalLayoutsAfter( - graph, - await strategyGravity(graph, algorithm, force), - localName, - force, - clusterScale - ) - } - if (arrangement === 'supernodes') { - return strategySuperNodes(graph, algorithm, localName, force, clusterScale) - } - return blockGroupLayout(graph, arrangement, localName, force, clusterScale) - }) -} - -// Runs whichever layout mode is active. -export function runActiveLayout() { - if (layoutMode() === 'groups') runGroupLayout() - else runLayout(document.getElementById('layoutSelect').value) -} - -// Older names still called elsewhere (loading data, switching annotations). -export function runStrategyLayout() { - runActiveLayout() -} - -function runGroupedLayout() { - runActiveLayout() -} diff --git a/frontend/src/library.ts b/frontend/src/library.ts deleted file mode 100644 index a011816..0000000 --- a/frontend/src/library.ts +++ /dev/null @@ -1,298 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { S } from './state' -import { - UNGROUPED, - UNGROUPED_LABEL, - buildAttrSchema, - colorForGroup, - getUsedGroups, - renderAttrSchema, - setGroupOrder, -} from './network_state' -import { - annotationText, - downloadText, - fileStem, - libEntry, - libSelection, - listSample, - plural, - selectedNetworks, - selectionKey, - setStatus, - updateRefreshState, -} from './layouts/controls' -import { applyGroupVisibility, buildGroupLegend, drawGroupHulls, loadData } from './hulls' -import { applyValueColors } from './clustering/mapping' -import { bumpDataVersion, noteChange } from './demo_downloads' -import { cy } from './cy' -import { hideEdgePopup, hideInfo } from './profiler' -import { layoutMode, runGroupLayout } from './layouts/run' -import { nextLoadPositions } from './api/tester' -import { updateContextInfo } from './recording' - -/* ---------- combining library files into a view ---------- */ -// Merges the chosen networks into one node/edge set. With one network its -// edges keep their Type (or the network name) as channel; with several, -// every network is its own channel ("name" or "name: type"), so pairs -// found in more than one network become parallel edges. -function combineNetworks(netEntries) { - const multi = netEntries.length > 1 - const nodeOrder = [] - const nodeNetworks = new Map() - const edges = [] - netEntries.forEach((ne) => { - ne.parsed.nodes.forEach((id) => { - if (!nodeNetworks.has(id)) { - nodeNetworks.set(id, []) - nodeOrder.push(id) - } - nodeNetworks.get(id).push(ne.name) - }) - ne.parsed.edges.forEach((e, i) => { - const type = e.type ? (multi ? `${ne.name}: ${e.type}` : e.type) : ne.name - edges.push({ - id: `${ne.id}-${i}`, - source: e.source, - target: e.target, - type, - ...(e.weight !== undefined ? { weight: e.weight } : {}), - ...(e.directed ? { directed: true } : {}), - ...(multi ? { network: ne.name } : {}), - }) - }) - }) - return { nodeOrder, nodeNetworks, edges, multi } -} - -// Resolves an annotation and an expression file against a set of node ids. -function resolveGroupsAndColors(nodeIds, viewName, annEntry, colEntry) { - const nodeSet = new Set(nodeIds) - const notes = [] - const groupsOf = {} - let groupCount = 0 - let groupOrder = null - - if (annEntry) { - const missing = new Set() - const emptied = [] - const kept = [] - annEntry.parsed.groups.forEach(({ name, members }) => { - const present = members.filter((m) => nodeSet.has(m)) - members.forEach((m) => { - if (!nodeSet.has(m)) missing.add(m) - }) - if (!present.length) { - emptied.push(name) - return - } - kept.push({ name, members: present }) - present.forEach((m) => (groupsOf[m] = groupsOf[m] || []).push(name)) - }) - groupCount = kept.length - groupOrder = kept.map((g) => g.name) - if (!kept.length) { - notes.push({ - level: 'error', - text: `None of the names in "${annEntry.name}" are in ${viewName}, so no groups are shown. Check that the files belong together.`, - }) - } else { - if (missing.size || emptied.length) { - const parts = [] - if (missing.size) - parts.push( - `Dropped ${plural(missing.size, 'annotation name')} not found in ${viewName}: ${listSample([...missing])}.` - ) - if (emptied.length) - parts.push( - `Left out ${plural(emptied.length, 'group')} with no nodes in the view: ${listSample(emptied)}.` - ) - const text = annotationText(kept) - notes.push({ - level: 'warn', - text: parts.join(' '), - action: { - label: 'Download corrected annotation', - run: () => downloadText(`${fileStem(annEntry.name)}-corrected.txt`, text), - }, - }) - } - const ungrouped = nodeIds.filter((n) => !groupsOf[n]).length - if (ungrouped) - notes.push({ - level: 'ok', - text: `${plural(ungrouped, 'node is', 'nodes are')} in no group and listed as "${UNGROUPED_LABEL}".`, - }) - } - } - - const colorOf = new Map() - const valuesOf = new Map() - if (colEntry && colEntry.parsed.numeric) { - const unknown = [] - colEntry.parsed.values.forEach((row, node) => { - if (nodeSet.has(node)) valuesOf.set(node, row) - else unknown.push(node) - }) - if (unknown.length) - notes.push({ - level: 'warn', - text: `Ignored values for ${plural(unknown.length, 'node')} not found in ${viewName}: ${listSample(unknown)}.`, - }) - const without = nodeIds.length - valuesOf.size - if (without) - notes.push({ - level: 'ok', - text: `${plural(without, 'node has', 'nodes have')} no value and ${without === 1 ? 'is' : 'are'} drawn in the "no value" color.`, - }) - } else if (colEntry) { - const unknown = [] - colEntry.parsed.colors.forEach((color, node) => { - if (nodeSet.has(node)) colorOf.set(node, color) - else unknown.push(node) - }) - if (unknown.length) - notes.push({ - level: 'warn', - text: `Ignored colors for ${plural(unknown.length, 'node')} not found in ${viewName}: ${listSample(unknown)}.`, - }) - const uncolored = nodeIds.length - colorOf.size - if (uncolored) - notes.push({ - level: 'ok', - text: `${plural(uncolored, 'node has', 'nodes have')} no expression color and ${uncolored === 1 ? 'is' : 'are'} gray.`, - }) - } - return { groupsOf, colorOf, valuesOf, notes, groupCount, groupOrder } -} - -// NORMA's look: node fill from expression colors with groups shaded behind; -// without an expression file, fill nodes with their group colors. -function applyLibraryDisplayDefaults(annEntry, colEntry) { - document.getElementById('nodeFillSelect').value = colEntry - ? colEntry.parsed.numeric - ? 'values' - : 'data' - : 'groups' - if (colEntry && annEntry) { - document.getElementById('showGroupHulls').checked = true - document.getElementById('hullControls').style.display = 'block' - } -} - -// Changes groups and colors of the nodes already on screen, keeping their -// positions (unless grouped layout is on, which depends on the groups). -export function applyGroupsAndColorsInPlace(groupsOf, colorOf, groupOrder, meta) { - bumpDataVersion() - S.nodeColorMap = {} - S.groupAttrs = meta ? JSON.parse(JSON.stringify(meta)) : {} - setGroupOrder(groupOrder) - let anyUngrouped = false - cy.batch(() => { - cy.nodes().forEach((n) => { - const own = groupsOf[n.id()] - const groups = own && own.length ? own : [UNGROUPED] - if (!own || !own.length) anyUngrouped = true - n.data({ groups, group: groups.join(', '), nodeColor: colorOf.get(n.id()) || null }) - }) - }) - if (anyUngrouped) - S.groupAttrs[UNGROUPED] = { - label: UNGROUPED_LABEL, - description: 'Nodes that no group lists as a member', - } - const used = getUsedGroups() - used.forEach((g) => colorForGroup(g)) - S.activeGroups = new Set(used) - buildGroupLegend() - applyGroupVisibility() - buildAttrSchema() - renderAttrSchema() - hideInfo() - hideEdgePopup() - cy.elements().removeClass('dimmed highlighted') - if (layoutMode() === 'groups') runGroupLayout() - drawGroupHulls() -} - -export function refreshLibraryView() { - noteChange() - const nets = selectedNetworks() - if (!nets.length) { - setStatus('normaStatus', [ - { - level: 'error', - text: 'Tick at least one network, then show it in this view or open it in a new one.', - }, - ]) - return - } - const annEntry = libEntry('annotation', libSelection.annotation) - const colEntry = libEntry('colors', libSelection.colors) - const key = selectionKey() - const sameNetworks = - S.currentLibView && S.currentLibView.nets === key.nets && cy.nodes().length > 0 - - const combined = combineNetworks(nets) - const viewName = nets.length === 1 ? `"${nets[0].name}"` : 'the selected networks' - const { groupsOf, colorOf, valuesOf, notes, groupCount, groupOrder } = resolveGroupsAndColors( - combined.nodeOrder, - viewName, - annEntry, - colEntry - ) - applyLibraryDisplayDefaults(annEntry, colEntry) - - // extra details carried by library entries (e.g. from STRING) - const groupMeta = annEntry && annEntry.groupMeta ? annEntry.groupMeta : null - const nodeExtra = (id) => { - const out = {} - nets.forEach((e) => { - if (e.nodeAttrs && e.nodeAttrs[id]) Object.assign(out, e.nodeAttrs[id]) - }) - return out - } - const keptPositions = nets.length === 1 && nets[0].nodePositions ? nets[0].nodePositions : null - if (sameNetworks) { - cy.batch(() => cy.nodes().forEach((n) => n.data('values', valuesOf.get(n.id()) || null))) - applyGroupsAndColorsInPlace(groupsOf, colorOf, groupOrder, groupMeta) - applyValueColors() - } else { - loadData( - { - groupOrder, - ...(groupMeta ? { groupAttrs: JSON.parse(JSON.stringify(groupMeta)) } : {}), - nodes: combined.nodeOrder.map((id) => ({ - ...nodeExtra(id), - id, - groups: groupsOf[id] || [], - ...(colorOf.has(id) ? { color: colorOf.get(id) } : {}), - ...(valuesOf.has(id) ? { values: valuesOf.get(id) } : {}), - ...(combined.multi ? { networks: combined.nodeNetworks.get(id) } : {}), - })), - edges: combined.edges, - }, - nextLoadPositions || keptPositions ? { positions: nextLoadPositions || keptPositions } : {} - ) - } - S.currentLibView = key - updateRefreshState() - updateContextInfo() - - const shownNets = - nets.length === 1 - ? `"${nets[0].name}" (${nets[0].parsed.summary})` - : `${nets.length} networks overlaid as channels: ${combined.nodeOrder.length} nodes, ${combined.edges.length} edges` - const parts = [`Showing ${shownNets}`] - if (annEntry) parts.push(`${plural(groupCount, 'group')} from "${annEntry.name}"`) - if (colEntry) parts.push(`colors from "${colEntry.name}"`) - const lead = (sameNetworks ? 'Updated groups and colors in place. ' : '') + parts.join(', ') + '.' - if (groupCount > 30 && document.getElementById('showGroupHulls').checked) { - notes.push({ - level: 'ok', - text: `With ${groupCount} groups shaded at once the view gets crowded. Type in the Node groups filter and use "Deactivate matches" / "Activate matches" to focus on a few.`, - }) - } - setStatus('normaStatus', [{ level: 'ok', text: lead }, ...notes]) -} diff --git a/frontend/src/main.ts b/frontend/src/main.ts deleted file mode 100644 index 03c6477..0000000 --- a/frontend/src/main.ts +++ /dev/null @@ -1,182 +0,0 @@ -// @ts-nocheck -// ponytail: boot order of the former single-file script; typed later with the rest -import { NORMA_CFG } from './config' -import { NORMA_KINDS, normaLibrary, renderLibraryLists, updateStrategyUI } from './layouts/controls' -import { S } from './state' -import { TAB_VIEWS, currentTab, switchTab } from './wiring' -import { - activeView, - applyEdgeCurveStyle, - applyEdgeOpacity, - applyEdgeWidth, - renderViewBar, - updateSpreadReadout, - updateZoomReadout, - viewSettings, - views, -} from './profiler' -import { apiAnnounceReady, apiFromLocation } from './api/wiring' -import { applyEdgeDirection } from './export/dialog' -import { applyTheme } from './themes' -import { askDelete, renderSiteInfo } from './api/tester' -import { cy } from './cy' -import { net3d } from './view3d/state' -import { resizeHullCanvas } from './hulls' -import { setHistoryBaseline, updateUndoButtons } from './demo_downloads' -import { updateEmptyState } from './welcome' -import { updateStats } from './metrics' - -import './style.css' -import './state' -import './config' -import './palette' -import './themes' -import './sample_data' -import './cy' -import './network_state' -import { init as initHulls } from './hulls' -import './parallel_edges' -import './metrics' -import './layouts/input' -import './layouts/run' -import { init as initLayoutsControls } from './layouts/controls' -import './library' -import './uploads' -import './examples' -import './export_norma' -import { init as initWiring } from './wiring' -import { init as initProfiler } from './profiler' -import { init as initViewbar } from './viewbar' -import { init as initSideTabs } from './side_tabs' -import './directed_stats' -import { init as initDemoDownloads } from './demo_downloads' -import { init as initRecording } from './recording' -import { init as initLabelColors } from './label_colors' -import { init as initExportDraw } from './export/draw' -import './export/shading' -import './export/raster' -import './export/svg' -import { init as initExportDialog } from './export/dialog' -import { init as initView3dState } from './view3d/state' -import './view3d/cache' -import './view3d/camera' -import './view3d/painters' -import './view3d/draw' -import './view3d/layouts' -import './view3d/tab' -import { init as initView3dInput } from './view3d/input' -import './view3d/export' -import './string/requests' -import './string/ui_state' -import './string/import' -import './string/groupings' -import { init as initStringWiring } from './string/wiring' -import { init as initWelcome } from './welcome' -import './clustering/leiden' -import './clustering/label_propagation' -import './clustering/walktrap' -import './clustering/mcl' -import { init as initClusteringMapping } from './clustering/mapping' -import './benchmark' -import { init as initClusteringWiring } from './clustering/wiring' -import { init as initContours } from './contours' -import './arena3d' -import './group_network' -import { init as initEnrichment } from './enrichment' -import { init as initApiWiring } from './api/wiring' -import { init as initApiTester } from './api/tester' -import { init as initSidePanel } from './side_panel' - -initHulls() -initLayoutsControls() -initWiring() -initProfiler() -initViewbar() -initSideTabs() -initDemoDownloads() -initRecording() -initLabelColors() -initExportDraw() -initExportDialog() -initView3dState() -initView3dInput() -initStringWiring() -initWelcome() -initClusteringMapping() -initClusteringWiring() -initContours() -initEnrichment() -initApiWiring() -initApiTester() - -document.getElementById('btnViewDelete').addEventListener('click', () => { - const lv = S.currentLibView - const items = [] - if (lv) { - String(lv.nets || '') - .split('|') - .filter(Boolean) - .forEach((id) => items.push({ kind: 'network', id })) - if (lv.annotation) items.push({ kind: 'annotation', id: lv.annotation }) - if (lv.colors) items.push({ kind: 'colors', id: lv.colors }) - } - askDelete(items, { view: activeView() }) -}) -document.getElementById('btnGroupingDelete').addEventListener('click', () => { - const id = S.currentLibView && S.currentLibView.annotation - if (id) askDelete([{ kind: 'annotation', id }]) -}) -document.getElementById('btnDeleteAllFiles').addEventListener('click', () => { - askDelete( - NORMA_KINDS.flatMap((kind) => normaLibrary[kind].map((e) => ({ kind, id: e.id }))), - { all: true } - ) -}) -/* boot */ -applyTheme(NORMA_CFG.app.theme || 'white') -if ( - document.getElementById('themeSelect') && - [...document.getElementById('themeSelect').options].some((o) => o.value === NORMA_CFG.app.theme) -) - document.getElementById('themeSelect').value = NORMA_CFG.app.theme -applyEdgeCurveStyle() -applyEdgeWidth() -applyEdgeOpacity() -applyEdgeDirection() -updateSpreadReadout() -initSidePanel() - -resizeHullCanvas() -updateStrategyUI() -updateZoomReadout() -renderLibraryLists() -S.DEFAULT_VIEW_CONFIG = viewSettings() -// NORMA starts with an empty view and the welcome page -views.push({ - id: 'view' + ++S.viewSeq, - name: 'Untitled view', - autoName: true, - data: null, - selection: { networks: [], annotation: '', colors: '' }, - state: { config: { ...S.DEFAULT_VIEW_CONFIG } }, -}) -S.activeViewId = views[0].id -updateStats() -renderViewBar() -updateEmptyState() -switchTab(TAB_VIEWS[NORMA_CFG.app.startTab] ? NORMA_CFG.app.startTab : 'welcome') -renderSiteInfo() -// the API: data in the address, and a hello to a page that opened NORMA -apiFromLocation() -apiAnnounceReady() -setHistoryBaseline() -updateUndoButtons() -// test hook: the canvas is opaque to the DOM, so end-to-end tests read state here -window.__norma = { - cy, - net3d, - views, - get currentTab() { - return currentTab - }, -} diff --git a/frontend/src/metrics.ts b/frontend/src/metrics.ts deleted file mode 100644 index 7f8085f..0000000 --- a/frontend/src/metrics.ts +++ /dev/null @@ -1,1338 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import cytoscape from 'cytoscape' -import { S } from './state' -import { UNGROUPED, getUsedGroups } from './network_state' -import { - anyEdgeDirected, - directionMode, - directionOf, - edgeIsDirected, - fr3dLayout, -} from './export/dialog' -import { applyBundleResult, applyLabelSizes } from './profiler' -import { cy } from './cy' -import { mulberry32 } from './sample_data' -import { scheduleLegend, scheduleSeparation, valueForSize } from './clustering/mapping' -import { updateContextInfo } from './recording' - -/* ---------- centrality metrics ---------- */ - -// Computes a raw value per node for the given metric, over either the whole -// graph or just the currently active (checked) edge channels. -// directed = true: out-neighbours only for directed edges (undirected -// edges still count both ways) -function buildAdjacency(activeEdges, nodes, directed = false) { - const adjSet = {} - nodes.forEach((n) => { - adjSet[n.id()] = new Set() - }) - activeEdges.forEach((e) => { - const s = e.data('source'), - t = e.data('target') - if (s === t || !adjSet[s] || !adjSet[t]) return - adjSet[s].add(t) - if (!directed || !edgeIsDirected(e)) adjSet[t].add(s) - }) - const adj = {} - Object.keys(adjSet).forEach((k) => { - adj[k] = [...adjSet[k]] - }) - return adj -} - -// Runs a single unweighted BFS-based pass (Brandes' algorithm) to get both -// betweenness and closeness together, since they share the same shortest-path work. -function bfsCentralities(nodeIds, adj, directed = false) { - const betweenness = {} - const closenessSum = {} - const reached = {} - nodeIds.forEach((id) => { - betweenness[id] = 0 - closenessSum[id] = 0 - reached[id] = 0 - }) - - nodeIds.forEach((s) => { - const P = {}, - sigma = {}, - d = {} - nodeIds.forEach((v) => { - P[v] = [] - sigma[v] = 0 - d[v] = -1 - }) - sigma[s] = 1 - d[s] = 0 - const S = [] - const queue = [s] - while (queue.length) { - const v = queue.shift() - S.push(v) - ;(adj[v] || []).forEach((w) => { - if (d[w] < 0) { - d[w] = d[v] + 1 - queue.push(w) - } - if (d[w] === d[v] + 1) { - sigma[w] += sigma[v] - P[w].push(v) - } - }) - } - nodeIds.forEach((v) => { - if (d[v] > 0) { - closenessSum[s] += d[v] - reached[s]++ - } - }) - const delta = {} - nodeIds.forEach((v) => (delta[v] = 0)) - while (S.length) { - const w = S.pop() - P[w].forEach((v) => { - delta[v] += (sigma[v] / sigma[w]) * (1 + delta[w]) - }) - if (w !== s) betweenness[w] += delta[w] - } - }) - // each shortest path is counted from both endpoints in an undirected graph - if (!directed) - nodeIds.forEach((v) => { - betweenness[v] /= 2 - }) - - const closeness = {} - nodeIds.forEach((v) => { - closeness[v] = closenessSum[v] > 0 ? reached[v] / closenessSum[v] : 0 - }) - - return { betweenness, closeness } -} - -// Self-contained (no reliance on cytoscape's own centrality helpers, which -// resolve neighborhoods against the full core graph rather than a given -// subset) so "compute on selected channels only" is honored exactly. -/* ============================================================ - THE SHOWN PART OF A VIEW - NORMA works on what is ticked: nodes in at least one ticked group, - and edges of ticked channels whose two ends are shown. Layouts, node - sizing, node statistics, the Profiler, Compare, search, bundling, - group shading and (by default) exports all use this part only. - ============================================================ */ -export function shownNodes() { - return cy.nodes().filter((n) => !n.hasClass('hidden-group')) -} - -export function shownEdges(channelOnly = true) { - return cy - .edges() - .filter( - (e) => - (!channelOnly || S.activeTypes.has(e.data('type'))) && - !e.source().hasClass('hidden-group') && - !e.target().hasClass('hidden-group') - ) -} - -export function exportShownOnly() { - const el = document.getElementById('exportShownOnly') - return !el || el.checked -} - -export function exportNodes() { - return exportShownOnly() ? shownNodes() : cy.nodes() -} - -export function exportEdges() { - return exportShownOnly() ? shownEdges(true) : cy.edges() -} - -export function computeMetricValues(metric, channelOnly) { - const activeEdges = shownEdges(channelOnly) - const nodes = shownNodes() - const nodeIds = nodes.map((n) => n.id()) - const values = {} - - if (metric === 'value') { - nodes.forEach((n) => { - values[n.id()] = valueForSize(n) - }) - return values - } - if (metric === 'degree' || metric === 'indegree' || metric === 'outdegree') { - nodeIds.forEach((id) => { - values[id] = 0 - }) - const add = (id) => { - if (id in values) values[id]++ - } - activeEdges.forEach((e) => { - const s = e.data('source'), - t = e.data('target') - if (metric === 'degree' || !edgeIsDirected(e)) { - add(s) - add(t) - return - } - if (metric === 'outdegree') add(s) - else add(t) - }) - return values - } - - // shortest paths follow edge direction when the shown part has any - // directed edge; clustering always ignores direction - const directed = metric !== 'clustering' && anyEdgeDirected(activeEdges) - const adj = buildAdjacency(activeEdges, nodes, directed) - - if (metric === 'clustering') { - nodeIds.forEach((id) => { - const neigh = adj[id] - const k = neigh.length - if (k < 2) { - values[id] = 0 - return - } - let links = 0 - for (let i = 0; i < neigh.length; i++) { - for (let j = i + 1; j < neigh.length; j++) { - if (adj[neigh[i]].includes(neigh[j])) links++ - } - } - values[id] = links / ((k * (k - 1)) / 2) - }) - return values - } - - if (metric === 'betweenness' || metric === 'closeness') { - const { betweenness, closeness } = bfsCentralities(nodeIds, adj, directed) - return metric === 'betweenness' ? betweenness : closeness - } - - return values -} - -// Cache of all four metrics computed on the full graph, used by the node info -// popup. Computed lazily (on first node click after a load) rather than -// eagerly on every data load: betweenness/closeness are O(V*(V+E)), and with -// networks up to several thousand nodes that eager pass would stall the UI -// even when the person never opens the info popup. -let fullMetricsCache = null - -export function invalidateFullMetrics() { - fullMetricsCache = null -} - -export function ensureFullMetrics() { - if (!fullMetricsCache) { - fullMetricsCache = { - degree: computeMetricValues('degree', true), - indegree: computeMetricValues('indegree', true), - outdegree: computeMetricValues('outdegree', true), - betweenness: computeMetricValues('betweenness', true), - closeness: computeMetricValues('closeness', true), - clustering: computeMetricValues('clustering', true), - } - } - return fullMetricsCache -} - -export function applyNodeSizing() { - const metric = document.getElementById('sizeMetric').value - const scale = parseFloat(document.getElementById('nodeScale').value) || 1 - document.getElementById('nodeScaleValue').textContent = scale.toFixed(2).replace(/0$/, '') + '×' - - if (metric === 'fixed') { - cy.batch(() => cy.nodes().forEach((n) => n.data('size', n.data('baseSize') * scale))) - applyLabelSizes() - if (typeof applyBundleResult === 'function') applyBundleResult() - return - } - - const channelOnly = document.getElementById('sizeChannelOnly').checked - const minPx = parseFloat(document.getElementById('sizeMin').value) || 22 - const maxPx = parseFloat(document.getElementById('sizeMax').value) || 74 - const values = computeMetricValues(metric, channelOnly) - const nums = Object.values(values) - if (!nums.length) return - const lo = Math.min(...nums), - hi = Math.max(...nums) - - cy.nodes().forEach((n) => { - const v = values[n.id()] || 0 - const size = hi === lo ? (minPx + maxPx) / 2 : minPx + ((v - lo) / (hi - lo)) * (maxPx - minPx) - n.data('size', size * scale) - }) - applyLabelSizes() - if (typeof applyBundleResult === 'function') applyBundleResult() -} - -export function updateStats() { - document.getElementById('statNodes').textContent = cy.nodes().length.toLocaleString() - document.getElementById('statEdges').textContent = cy.edges().length.toLocaleString() - const types = new Set(cy.edges().map((e) => e.data('type'))) - document.getElementById('statTypes').textContent = types.size - const groups = getUsedGroups().filter((g) => g !== UNGROUPED) - const active = groups.filter((g) => S.activeGroups.has(g)).length - document.getElementById('statGroups').textContent = - active === groups.length ? groups.length : `${active}/${groups.length}` - const word = (id, n, one, many) => { - document.getElementById(id).textContent = n === 1 ? one : many - } - word('statNodesWord', cy.nodes().length, 'node', 'nodes') - word('statEdgesWord', cy.edges().length, 'edge', 'edges') - word('statTypesWord', types.size, 'channel', 'channels') - word('statGroupsWord', groups.length, 'group', 'groups') - const dirEl = document.getElementById('statDirection') - dirEl.classList.remove('stat-dir-off') - if (typeof directionOf === 'function' && cy.edges().length) { - const dir = directionOf(cy.edges()) - const dataDirected = cy.edges().filter((e) => e.data('directed')).length - if (dir === 'undirected' && dataDirected && directionMode() === 'undirected') { - // the data has direction but the view ignores it (the default) - dirEl.hidden = false - dirEl.textContent = 'direction ignored' - dirEl.classList.add('stat-dir-off') - dirEl.title = `${dataDirected.toLocaleString()} edges are marked as directed in the data. Click to show them as directed (Edges → Direction: As in the data).` - } else { - dirEl.hidden = dir === 'undirected' - dirEl.textContent = dir === 'mixed' ? 'mixed direction' : 'directed' - dirEl.title = - dir === 'mixed' - ? 'Some edges are directed, some are not' - : 'Edges point from source to target' - } - } else dirEl.hidden = true - if (typeof updateContextInfo === 'function') updateContextInfo() - if (typeof scheduleLegend === 'function') { - scheduleLegend() - scheduleSeparation() - } -} - -// Per-layout-name option tweaks shared between the normal single-graph -// layout and the headless sub-layouts used by the group strategies. -export function layoutOptsFor(name) { - const opts = { name } - if (name === 'concentric') { - opts.concentric = (n) => n.degree() - opts.levelWidth = () => 1 - } - if (name === 'breadthfirst') { - opts.directed = typeof anyEdgeDirected === 'function' && anyEdgeDirected(shownEdges(true)) - opts.spacingFactor = 1.1 - } - if (name === 'cose') { - opts.idealEdgeLength = 90 - opts.nodeRepulsion = 6000 - opts.gravity = 0.4 - } - return opts -} - -// Above this size a network loads with a grid layout instead of force-directed. -export const LARGE_NETWORK_NODES = 700 - -/* ============================================================ - FORCE-DIRECTED EDGE BUNDLING - Holten D, van Wijk JJ (2009) Force-directed edge bundling for graph - visualization. Computer Graphics Forum 28(3):983-990. - Each edge becomes a polyline whose inner points are pulled toward the - matching points of "compatible" edges (similar direction, length, - position and mutual visibility) and held in shape by springs. The - number of points doubles each cycle while the step size halves. - Input: [{sx, sy, tx, ty}] in model coordinates. Output: for each edge, - a flat array [x1, y1, x2, y2, ...] of its inner points, or null. - ============================================================ */ -// Progress of long computations (layouts, edge bundling), reported from -// inside their loops as a fraction of the part in workRange. In the worker, -// workSink posts it to the page; on the page itself it is not used. -var workSink = null, - workLast = 0 - -export function workStep(f) { - if (!workSink) return - const now = Date.now() - if (now - workLast < 80) return - workLast = now - workSink(S.workRange[0] + (S.workRange[1] - S.workRange[0]) * Math.max(0, Math.min(1, f))) -} - -function fdebBundle(segs, opts) { - const E = segs.length - const threshold = opts.threshold - const K = 0.1, - EPS = 1e-6 - // 4 cycles give 8 inner points per edge; Cytoscape stops drawing - // unbundled-bezier edges with more than 8 control points (tested) - const cycles = 4 - let iterations = opts.iterations - let S = 0.1 - const COMPAT_CAP = 150 - - const len = new Float64Array(E), - mx = new Float64Array(E), - my = new Float64Array(E) - const dx = new Float64Array(E), - dy = new Float64Array(E) - for (let i = 0; i < E; i++) { - const s = segs[i] - dx[i] = s.tx - s.sx - dy[i] = s.ty - s.sy - len[i] = Math.hypot(dx[i], dy[i]) - mx[i] = (s.sx + s.tx) / 2 - my[i] = (s.sy + s.ty) / 2 - } - // how much of segment q is "visible" from segment p (projection overlap) - function visibility(p, q) { - const s = segs[p], - t = segs[q] - const L2 = len[p] * len[p] - const u0 = ((t.sx - s.sx) * dx[p] + (t.sy - s.sy) * dy[p]) / L2 - const u1 = ((t.tx - s.sx) * dx[p] + (t.ty - s.sy) * dy[p]) / L2 - const i0x = s.sx + u0 * dx[p], - i0y = s.sy + u0 * dy[p] - const i1x = s.sx + u1 * dx[p], - i1y = s.sy + u1 * dy[p] - const il = Math.hypot(i1x - i0x, i1y - i0y) - if (il < EPS) return 0 - const imx = (i0x + i1x) / 2, - imy = (i0y + i1y) / 2 - return Math.max(0, 1 - (2 * Math.hypot(mx[p] - imx, my[p] - imy)) / il) - } - - // compatible partners per edge; `flip` marks partners running the other way - const partners = Array.from({ length: E }, () => []) - for (let p = 0; p < E; p++) { - if ((p & 31) === 0) workStep(0.2 * (1 - ((E - p) * (E - p)) / (E * E))) - if (len[p] < EPS) continue - for (let q = p + 1; q < E; q++) { - if (len[q] < EPS) continue - const dot = dx[p] * dx[q] + dy[p] * dy[q] - const angle = Math.abs(dot) / (len[p] * len[q]) - if (angle < threshold) continue - const lavg = (len[p] + len[q]) / 2 - const scale = 2 / (lavg / Math.min(len[p], len[q]) + Math.max(len[p], len[q]) / lavg) - let c = angle * scale - if (c < threshold) continue - c *= lavg / (lavg + Math.hypot(mx[p] - mx[q], my[p] - my[q])) - if (c < threshold) continue - c *= Math.min(visibility(p, q), visibility(q, p)) - if (c < threshold) continue - const flip = dot < 0 - partners[p].push({ e: q, c, flip }) - partners[q].push({ e: p, c, flip }) - if (partners[p].length > COMPAT_CAP * 4) { - partners[p].sort((a, b) => b.c - a.c) - partners[p].length = COMPAT_CAP - } - if (partners[q].length > COMPAT_CAP * 4) { - partners[q].sort((a, b) => b.c - a.c) - partners[q].length = COMPAT_CAP - } - } - } - partners.forEach((list) => { - if (list.length > COMPAT_CAP) { - list.sort((a, b) => b.c - a.c) - list.length = COMPAT_CAP - } - }) - - // polylines, stored as [x0, y0, ..., xn, yn] including both endpoints - let P = 1 - let pts = segs.map((s) => - Float64Array.from([s.sx, s.sy, (s.sx + s.tx) / 2, (s.sy + s.ty) / 2, s.tx, s.ty]) - ) - - function resample(line, segments) { - const n = line.length / 2 - let total = 0 - for (let i = 1; i < n; i++) - total += Math.hypot(line[2 * i] - line[2 * i - 2], line[2 * i + 1] - line[2 * i - 1]) - const out = new Float64Array((segments + 1) * 2) - out[0] = line[0] - out[1] = line[1] - out[segments * 2] = line[(n - 1) * 2] - out[segments * 2 + 1] = line[(n - 1) * 2 + 1] - if (total < EPS) { - for (let k = 1; k < segments; k++) { - out[2 * k] = line[0] - out[2 * k + 1] = line[1] - } - return out - } - const step = total / segments - let seg = 1, - acc = 0 - for (let k = 1; k < segments; k++) { - const target = step * k - while (seg < n) { - const sl = Math.hypot( - line[2 * seg] - line[2 * seg - 2], - line[2 * seg + 1] - line[2 * seg - 1] - ) - if (acc + sl >= target || seg === n - 1) { - const f = sl > EPS ? (target - acc) / sl : 0 - out[2 * k] = line[2 * seg - 2] + (line[2 * seg] - line[2 * seg - 2]) * f - out[2 * k + 1] = line[2 * seg - 1] + (line[2 * seg + 1] - line[2 * seg - 1]) * f - break - } - acc += sl - seg++ - } - } - return out - } - - // work per iteration grows with the points per edge (2, 4, 8, 16) - let planned = 0, - spent = 0 - for (let c = 0, its = opts.iterations; c < cycles; c++) { - if (c > 0) its = Math.max(3, Math.round((its * 2) / 3)) - planned += its * 2 ** c - } - for (let cycle = 0; cycle < cycles; cycle++) { - if (cycle > 0) { - P *= 2 - S /= 2 - iterations = Math.max(3, Math.round((iterations * 2) / 3)) - pts = pts.map((line) => resample(line, P + 1)) - } - const nPts = P + 2 // including endpoints - for (let it = 0; it < iterations; it++) { - workStep(0.2 + (0.8 * spent) / planned) - spent += 2 ** cycle - const next = pts.map((line) => Float64Array.from(line)) - for (let e = 0; e < E; e++) { - const line = pts[e] - if (len[e] < EPS) continue - const kP = K / (len[e] * (P + 1)) - const plist = partners[e] - for (let i = 1; i < nPts - 1; i++) { - const x = line[2 * i], - y = line[2 * i + 1] - let fx = kP * (line[2 * i - 2] - x + line[2 * i + 2] - x) - let fy = kP * (line[2 * i - 1] - y + line[2 * i + 3] - y) - for (let j = 0; j < plist.length; j++) { - const other = pts[plist[j].e] - const oi = plist[j].flip ? nPts - 1 - i : i - const ex = other[2 * oi] - x, - ey = other[2 * oi + 1] - y - const d = Math.hypot(ex, ey) - if (d > EPS) { - fx += ex / d - fy += ey / d - } - } - next[e][2 * i] = x + S * fx - next[e][2 * i + 1] = y + S * fy - } - } - pts = next - } - } - return pts.map((line, e) => (len[e] < EPS ? null : Array.from(line.slice(2, line.length - 2)))) -} - -/* ============================================================ - WEIGHTED FRUCHTERMAN-REINGOLD - NORMA computes its layouts with igraph, where layout_with_fr - multiplies the spring attraction along an edge by that edge's weight. - The group strategies depend on this: they work by adding heavy or - light edges. Cytoscape has no equivalent, so this is a direct - implementation with igraph's defaults: 500 iterations, a start - temperature of sqrt(n)/10 cooling linearly to zero, repulsion k²/d and - attraction w·d²/k with k = 1. It is seeded (NORMA uses set.seed(123)), - so the same input always gives the same picture. - Each connected component is laid out on its own and the components - are then packed side by side; otherwise small components drift - arbitrarily far from the main one. - ============================================================ */ -export const FR_SEED = 123 - -function connectedComponents(n, edges) { - const parent = Int32Array.from({ length: n }, (_, i) => i) - const find = (i) => { - while (parent[i] !== i) { - parent[i] = parent[parent[i]] - i = parent[i] - } - return i - } - edges.forEach((e) => { - const a = find(e.s), - b = find(e.t) - if (a !== b) parent[a] = b - }) - const byRoot = new Map() - for (let i = 0; i < n; i++) { - const r = find(i) - if (!byRoot.has(r)) byRoot.set(r, []) - byRoot.get(r).push(i) - } - return [...byRoot.values()] -} - -// n nodes (0..n-1), edges [{s, t, w}] -> { x: Float64Array, y: Float64Array } -function frComponent(n, edges, rand) { - const X = new Float64Array(n), - Y = new Float64Array(n) - if (n === 1) return { x: X, y: Y } - const side = Math.sqrt(n) - for (let i = 0; i < n; i++) { - X[i] = (rand() - 0.5) * side - Y[i] = (rand() - 0.5) * side - } - const iterations = n > 3000 ? 150 : n > 1000 ? 300 : 500 - const temp0 = Math.sqrt(n) / 10 - const DX = new Float64Array(n), - DY = new Float64Array(n) - const useGrid = n > 1500 - const CELL = 2 // FR's grid variant: repulsion only within 2k - - for (let it = 0; it < iterations; it++) { - if ((it & 3) === 0) workStep(it / iterations) - DX.fill(0) - DY.fill(0) - if (!useGrid) { - for (let i = 0; i < n; i++) { - for (let j = i + 1; j < n; j++) { - let dx = X[i] - X[j], - dy = Y[i] - Y[j] - let d2 = dx * dx + dy * dy - if (d2 < 1e-9) { - dx = (rand() - 0.5) * 1e-3 - dy = (rand() - 0.5) * 1e-3 - d2 = dx * dx + dy * dy - } - const f = 1 / d2 // (k²/d) along the unit vector - DX[i] += dx * f - DY[i] += dy * f - DX[j] -= dx * f - DY[j] -= dy * f - } - } - } else { - const grid = new Map() - for (let i = 0; i < n; i++) { - const key = Math.floor(X[i] / CELL) + ',' + Math.floor(Y[i] / CELL) - let cell = grid.get(key) - if (!cell) grid.set(key, (cell = [])) - cell.push(i) - } - for (let i = 0; i < n; i++) { - const cx = Math.floor(X[i] / CELL), - cyy = Math.floor(Y[i] / CELL) - for (let gx = cx - 1; gx <= cx + 1; gx++) { - for (let gy = cyy - 1; gy <= cyy + 1; gy++) { - const cell = grid.get(gx + ',' + gy) - if (!cell) continue - for (const j of cell) { - if (j <= i) continue - let dx = X[i] - X[j], - dy = Y[i] - Y[j] - let d2 = dx * dx + dy * dy - if (d2 > CELL * CELL * 4) continue - if (d2 < 1e-9) { - dx = (rand() - 0.5) * 1e-3 - dy = (rand() - 0.5) * 1e-3 - d2 = dx * dx + dy * dy - } - const f = 1 / d2 - DX[i] += dx * f - DY[i] += dy * f - DX[j] -= dx * f - DY[j] -= dy * f - } - } - } - } - } - for (const e of edges) { - const dx = X[e.s] - X[e.t], - dy = Y[e.s] - Y[e.t] - const d = Math.sqrt(dx * dx + dy * dy) - const f = e.w * d // (w·d²/k) along the unit vector - DX[e.s] -= dx * f - DY[e.s] -= dy * f - DX[e.t] += dx * f - DY[e.t] += dy * f - } - const temp = temp0 * (1 - it / iterations) - for (let i = 0; i < n; i++) { - const len = Math.sqrt(DX[i] * DX[i] + DY[i] * DY[i]) - if (len > temp) { - DX[i] *= temp / len - DY[i] *= temp / len - } - X[i] += DX[i] - Y[i] += DY[i] - } - } - return { x: X, y: Y } -} - -// Shelf-packs laid-out components, largest first, into a roughly square block. -function packComponents(parts) { - const PAD = 1.5 - parts.forEach((p) => { - let x1 = Infinity, - y1 = Infinity, - x2 = -Infinity, - y2 = -Infinity - for (let i = 0; i < p.x.length; i++) { - x1 = Math.min(x1, p.x[i]) - x2 = Math.max(x2, p.x[i]) - y1 = Math.min(y1, p.y[i]) - y2 = Math.max(y2, p.y[i]) - } - p.x1 = x1 - p.y1 = y1 - p.w = x2 - x1 + PAD - p.h = y2 - y1 + PAD - }) - parts.sort((a, b) => b.w * b.h - a.w * a.h) - const area = parts.reduce((s, p) => s + p.w * p.h, 0) - const rowWidth = Math.max(parts[0].w, Math.sqrt(area) * 1.2) - let cx = 0, - cyy = 0, - rowH = 0 - parts.forEach((p) => { - if (cx > 0 && cx + p.w > rowWidth) { - cx = 0 - cyy += rowH - rowH = 0 - } - p.ox = cx - p.x1 - p.oy = cyy - p.y1 - cx += p.w - rowH = Math.max(rowH, p.h) - }) -} - -// ids: string[], edges: [{source, target, weight}] -> { id: {x, y} } in FR units -function frLayout(ids, edges) { - const index = new Map(ids.map((id, i) => [id, i])) - const all = [] - edges.forEach((e) => { - const s = index.get(e.source), - t = index.get(e.target) - if (s === undefined || t === undefined || s === t) return - const w = Number.isFinite(e.weight) && e.weight > 0 ? e.weight : 1 - all.push({ s, t, w }) - }) - const rand = mulberry32(FR_SEED) - const comps = connectedComponents(ids.length, all) - const compOf = new Int32Array(ids.length) - const localIdx = new Int32Array(ids.length) - comps.forEach((members, c) => - members.forEach((g, i) => { - compOf[g] = c - localIdx[g] = i - }) - ) - const compEdges = comps.map(() => []) - all.forEach((e) => compEdges[compOf[e.s]].push({ s: localIdx[e.s], t: localIdx[e.t], w: e.w })) - let laidOut = 0 - const parts = comps.map((members, c) => { - S.workRange = [laidOut / ids.length, (laidOut + members.length) / ids.length] - laidOut += members.length - return { members, ...frComponent(members.length, compEdges[c], rand) } - }) - S.workRange = [0, 1] - packComponents(parts) - const out = {} - parts.forEach((p) => - p.members.forEach((g, i) => { - out[ids[g]] = { x: p.x[i] + p.ox, y: p.y[i] + p.oy } - }) - ) - return out -} - -/* ============================================================ - DISTANCE-BASED LAYOUTS - kkLayout Kamada & Kawai (1989): springs between all pairs, with - lengths equal to graph distances (hops), relaxed node by - node with Newton-Raphson steps. - stressLayout Stress majorization (Gansner, Koren & North 2004): - pivot MDS start, then weighted stress minimisation - (weights 1/d^2). - Both lay out each connected component separately and pack them, like - the weighted Fruchterman-Reingold layout, and run in the worker. - Edge weights are not used: distances are shortest paths in hops. - ============================================================ */ -const DIST_LAYOUT_LIMIT = 2500 -// nodes per component - -// all-pairs hop distances of one component (local indices) -function componentDistances(n, adj) { - const D = new Float64Array(n * n) - const q = new Int32Array(n) - for (let s = 0; s < n; s++) { - const row = s * n - for (let i = 0; i < n; i++) D[row + i] = -1 - D[row + s] = 0 - let head = 0, - tail = 0 - q[tail++] = s - while (head < tail) { - const v = q[head++] - const dv = D[row + v] - const a = adj[v] - for (let k = 0; k < a.length; k++) { - const w = a[k] - if (D[row + w] < 0) { - D[row + w] = dv + 1 - q[tail++] = w - } - } - } - } - return D -} - -// Pivot MDS (Brandes & Pich 2006): a quick, good starting layout. -function pivotMDS(n, D) { - const X = new Float64Array(n), - Y = new Float64Array(n) - if (n < 3) { - for (let i = 0; i < n; i++) { - X[i] = i - } - return { X, Y } - } - const k = Math.min(50, n) - const pivots = [0] - const minD = new Float64Array(n).fill(Infinity) - for (let p = 1; p < k; p++) { - const last = pivots[p - 1] - let best = 0, - bestD = -1 - for (let i = 0; i < n; i++) { - minD[i] = Math.min(minD[i], D[last * n + i]) - if (minD[i] > bestD) { - bestD = minD[i] - best = i - } - } - pivots.push(best) - } - // C: n x k squared distances, double centered - const C = new Float64Array(n * k) - const colMean = new Float64Array(k), - rowMean = new Float64Array(n) - let total = 0 - for (let i = 0; i < n; i++) - for (let j = 0; j < k; j++) { - const v = Math.pow(D[pivots[j] * n + i], 2) - C[i * k + j] = v - colMean[j] += v - rowMean[i] += v - total += v - } - for (let j = 0; j < k; j++) colMean[j] /= n - for (let i = 0; i < n; i++) rowMean[i] /= k - total /= n * k - for (let i = 0; i < n; i++) - for (let j = 0; j < k; j++) { - C[i * k + j] = -0.5 * (C[i * k + j] - rowMean[i] - colMean[j] + total) - } - // top two eigenvectors of C^T C by power iteration - const CtC = new Float64Array(k * k) - for (let a = 0; a < k; a++) - for (let b = a; b < k; b++) { - let s = 0 - for (let i = 0; i < n; i++) s += C[i * k + a] * C[i * k + b] - CtC[a * k + b] = s - CtC[b * k + a] = s - } - const vecs = [] - for (let e = 0; e < 2; e++) { - let v = Float64Array.from({ length: k }, (_, i) => Math.sin(i * (e + 1) + 1)) - for (let it = 0; it < 100; it++) { - const w = new Float64Array(k) - for (let a = 0; a < k; a++) { - let s = 0 - for (let b = 0; b < k; b++) s += CtC[a * k + b] * v[b] - w[a] = s - } - vecs.forEach((u) => { - let d = 0 - for (let a = 0; a < k; a++) d += w[a] * u[a] - for (let a = 0; a < k; a++) w[a] -= d * u[a] - }) - let norm = 0 - for (let a = 0; a < k; a++) norm += w[a] * w[a] - norm = Math.sqrt(norm) || 1 - for (let a = 0; a < k; a++) w[a] /= norm - v = w - } - vecs.push(v) - } - for (let i = 0; i < n; i++) { - let x = 0, - y = 0 - for (let j = 0; j < k; j++) { - x += C[i * k + j] * vecs[0][j] - y += C[i * k + j] * vecs[1][j] - } - X[i] = x - Y[i] = y - } - // scale to hop units - let spread = 0, - count = 0 - for (let i = 0; i < n; i++) - for (let j = i + 1; j < Math.min(n, i + 20); j++) { - const d = Math.hypot(X[i] - X[j], Y[i] - Y[j]) - if (d > 0) { - spread += D[i * n + j] / d - count++ - } - } - const s = count ? spread / count : 1 - for (let i = 0; i < n; i++) { - X[i] *= s - Y[i] *= s - } - // break exact ties - for (let i = 0; i < n; i++) { - X[i] += 1e-3 * Math.sin(i * 12.9898) - Y[i] += 1e-3 * Math.cos(i * 78.233) - } - return { X, Y } -} - -function kkComponent(n, adj) { - const X = new Float64Array(n), - Y = new Float64Array(n) - if (n === 1) return { x: X, y: Y } - const D = componentDistances(n, adj) - // start on a circle, as igraph does - let maxD = 0 - for (let i = 0; i < D.length; i++) if (D[i] > maxD) maxD = D[i] - for (let i = 0; i < n; i++) { - X[i] = (Math.cos((2 * Math.PI * i) / n) * maxD) / 2 - Y[i] = (Math.sin((2 * Math.PI * i) / n) * maxD) / 2 - } - const gx = new Float64Array(n), - gy = new Float64Array(n) - const term = (m, i) => { - // gradient contribution of pair (m, i) to m - const d = D[m * n + i] - if (d <= 0) return [0, 0] - const dx = X[m] - X[i], - dy = Y[m] - Y[i] - const dist = Math.sqrt(dx * dx + dy * dy) || 1e-9 - const k = 1 / (d * d) - return [k * (dx - (d * dx) / dist), k * (dy - (d * dy) / dist)] - } - for (let m = 0; m < n; m++) - for (let i = 0; i < n; i++) { - if (i === m) continue - const [a, b] = term(m, i) - gx[m] += a - gy[m] += b - } - const maxIter = Math.min(50 * n, 40000) - const eps = 1e-4 - for (let it = 0; it < maxIter; it++) { - if ((it & 63) === 0) workStep(it / maxIter) - let m = -1, - best = eps - for (let i = 0; i < n; i++) { - const g = gx[i] * gx[i] + gy[i] * gy[i] - if (g > best) { - best = g - m = i - } - } - if (m < 0) break - // remove m's old contributions from everybody else - for (let i = 0; i < n; i++) { - if (i === m) continue - const [a, b] = term(i, m) - gx[i] -= a - gy[i] -= b - } - // Newton-Raphson on node m - for (let step = 0; step < 20; step++) { - let dxx = 0, - dyy = 0, - dxy = 0, - ex = 0, - ey = 0 - for (let i = 0; i < n; i++) { - if (i === m) continue - const d = D[m * n + i] - if (d <= 0) continue - const k = 1 / (d * d) - const dx = X[m] - X[i], - dy = Y[m] - Y[i] - const dist2 = dx * dx + dy * dy || 1e-12 - const dist = Math.sqrt(dist2) - const dist3 = dist2 * dist - ex += k * (dx - (d * dx) / dist) - ey += k * (dy - (d * dy) / dist) - dxx += k * (1 - (d * dy * dy) / dist3) - dyy += k * (1 - (d * dx * dx) / dist3) - dxy += k * ((d * dx * dy) / dist3) - } - const det = dxx * dyy - dxy * dxy - if (Math.abs(det) < 1e-12) break - const sx = (-ex * dyy + ey * dxy) / det - const sy = (-ey * dxx + ex * dxy) / det - X[m] += sx - Y[m] += sy - gx[m] = ex - gy[m] = ey - if (sx * sx + sy * sy < 1e-8) break - } - // recompute m's gradient and add its new contributions to everybody - gx[m] = 0 - gy[m] = 0 - for (let i = 0; i < n; i++) { - if (i === m) continue - const [a, b] = term(m, i) - gx[m] += a - gy[m] += b - const [c, e] = term(i, m) - gx[i] += c - gy[i] += e - } - } - return { x: X, y: Y } -} - -function stressComponent(n, adj) { - if (n === 1) return { x: new Float64Array(1), y: new Float64Array(1) } - const D = componentDistances(n, adj) - const { X, Y } = pivotMDS(n, D) - const iters = Math.max(20, Math.min(300, Math.floor(4e7 / (n * n)))) - let prev = Infinity - for (let it = 0; it < iters; it++) { - workStep(it / iters) - let stress = 0 - for (let i = 0; i < n; i++) { - let sx = 0, - sy = 0, - sw = 0 - for (let j = 0; j < n; j++) { - if (j === i) continue - const d = D[i * n + j] - if (d <= 0) continue - const w = 1 / (d * d) - const dx = X[i] - X[j], - dy = Y[i] - Y[j] - const dist = Math.sqrt(dx * dx + dy * dy) || 1e-9 - sx += w * (X[j] + (d * dx) / dist) - sy += w * (Y[j] + (d * dy) / dist) - sw += w - stress += w * (dist - d) * (dist - d) - } - if (sw) { - X[i] = sx / sw - Y[i] = sy / sw - } - } - if (Math.abs(prev - stress) / (stress || 1) < 1e-5) break - prev = stress - } - return { x: X, y: Y } -} - -function distanceLayout(ids, edges, kind) { - const index = new Map(ids.map((id, i) => [id, i])) - const all = [] - edges.forEach((e) => { - const s = index.get(e.source), - t = index.get(e.target) - if (s === undefined || t === undefined || s === t) return - all.push({ s, t, w: 1 }) - }) - const comps = connectedComponents(ids.length, all) - const compOf = new Int32Array(ids.length), - localIdx = new Int32Array(ids.length) - comps.forEach((members, c) => - members.forEach((g, i) => { - compOf[g] = c - localIdx[g] = i - }) - ) - const adjs = comps.map((m) => m.map(() => [])) - all.forEach((e) => { - const c = compOf[e.s] - adjs[c][localIdx[e.s]].push(localIdx[e.t]) - adjs[c][localIdx[e.t]].push(localIdx[e.s]) - }) - let laidOut = 0 - const parts = comps.map((members, c) => { - S.workRange = [laidOut / ids.length, (laidOut + members.length) / ids.length] - laidOut += members.length - if (members.length > DIST_LAYOUT_LIMIT) - throw new Error( - `${kind === 'kk' ? 'Kamada–Kawai' : 'Stress majorization'} handles connected parts of up to ${DIST_LAYOUT_LIMIT.toLocaleString('en-US')} nodes; this network has one of ${members.length.toLocaleString('en-US')}. Use a force-directed layout instead.` - ) - const lay = - kind === 'kk' - ? kkComponent(members.length, adjs[c]) - : stressComponent(members.length, adjs[c]) - // hop units -> FR-like units so packing gaps look alike - return { members, x: lay.x, y: lay.y } - }) - S.workRange = [0, 1] - packComponents(parts) - const out = {} - parts.forEach((p) => - p.members.forEach((g, i) => { - out[ids[g]] = { x: p.x[i] + p.ox, y: p.y[i] + p.oy } - }) - ) - return out -} - -function distanceLayoutAsync(ids, edges, kind, onProgress) { - const worker = ids.length > 60 ? getFrWorker() : null - if (!worker) return Promise.resolve(distanceLayout(ids, edges, kind)) - const id = ++S.frRequestSeq - return new Promise((resolve, reject) => { - frPending.set(id, { - resolve, - reject, - onProgress, - local: () => distanceLayout(ids, edges, kind), - }) - worker.postMessage({ id, kind, ids, edges }) - }) -} - -// The weighted layout runs in a background worker when the browser allows -// it, so large networks don't freeze the page. The worker is built from -// the same functions as above; if it can't be created, or fails, the -// layout runs on the page instead. -let frWorker = null - -let frWorkerFailed = false - -export const frPending = new Map() - -export function getFrWorker() { - if (frWorker || frWorkerFailed) return frWorker - try { - const src = - [ - mulberry32, - connectedComponents, - frComponent, - packComponents, - frLayout, - fdebBundle, - fr3dLayout, - componentDistances, - pivotMDS, - kkComponent, - stressComponent, - distanceLayout, - workStep, - ] - .map((f) => f.toString()) - .join('\n') + - `\nconst FR_SEED = ${FR_SEED};\nconst DIST_LAYOUT_LIMIT = ${DIST_LAYOUT_LIMIT};\nvar workRange = [0, 1], workSink = null, workLast = 0;\n` + - // The dispatcher below used to call these by their literal source - // names, which broke once the production build's minifier renamed - // these (non-exported) functions: the worker still got their bodies - // via .toString(), but under whatever new name the minifier picked, - // so the hardcoded names threw "X is not defined". Using .name reads - // each function's *current* runtime name, so it always matches the - // identifier its .toString() source was declared under. - `onmessage = e => { const m = e.data; let result; workRange = [0, 1]; workLast = 0; workSink = f => postMessage({ id: m.id, progress: f }); try{ result = m.kind === "fdeb" ? ${fdebBundle.name}(m.segs, m.opts) : m.kind === "fr3d" ? ${fr3dLayout.name}(m.ids, m.edges, m.opts) : (m.kind === "kk" || m.kind === "stress") ? ${distanceLayout.name}(m.ids, m.edges, m.kind) : ${frLayout.name}(m.ids, m.edges); } catch(err){ postMessage({ id: m.id, error: String(err && err.message || err) }); return; } postMessage({ id: m.id, result }); };` - const url = URL.createObjectURL(new Blob([src], { type: 'text/javascript' })) - frWorker = new Worker(url) - frWorker.onmessage = (e) => { - const job = frPending.get(e.data.id) - if (!job) return - if (e.data.progress !== undefined) { - if (job.onProgress) job.onProgress(e.data.progress) - return - } - frPending.delete(e.data.id) - if (e.data.error) { - if (job.reject) job.reject(new Error(e.data.error)) - else job.resolve(null) - } else job.resolve(e.data.result) - } - frWorker.onerror = (e) => { - e.preventDefault() - frWorkerFailed = true - frWorker = null - // finish anything still waiting on the page itself - frPending.forEach((job) => job.resolve(job.local())) - frPending.clear() - } - } catch (err) { - frWorkerFailed = true - frWorker = null - } - return frWorker -} - -// Stops any weighted layout still computing in the worker; its callers see -// null and, being superseded, discard it. -export function cancelFrJobs() { - if (!frWorker || !frPending.size) return - frWorker.terminate() - frWorker = null - frPending.forEach((job) => job.resolve(null)) - frPending.clear() -} - -export function frLayoutAsync(ids, edges, onProgress) { - const worker = ids.length > 60 ? getFrWorker() : null // small graphs: not worth the round trip - if (!worker) return Promise.resolve(frLayout(ids, edges)) - const id = ++S.frRequestSeq - return new Promise((resolve) => { - frPending.set(id, { resolve, onProgress, local: () => frLayout(ids, edges) }) - worker.postMessage({ id, kind: 'fr', ids, edges }) - }) -} - -export function bundleAsync(segs, opts, onProgress) { - const worker = segs.length > 150 ? getFrWorker() : null - if (!worker) return Promise.resolve(fdebBundle(segs, opts)) - const id = ++S.frRequestSeq - return new Promise((resolve) => { - frPending.set(id, { resolve, onProgress, local: () => fdebBundle(segs, opts) }) - worker.postMessage({ id, kind: 'fdeb', segs, opts }) - }) -} - -// Layouts that place nodes without looking at edges; strategies can skip -// adding layout-only links for these, since they change nothing. -export const EDGE_BLIND_LAYOUTS = new Set(['circle', 'grid', 'random']) - -// Runs a layout on a detached, invisible headless Cytoscape instance (or the -// weighted FR above) and returns a { nodeId: {x,y} } position map in -// arbitrary units; callers rescale. Edge weights are honored by 'fr' -// (attraction x weight) and by 'cose' (shorter, stiffer springs). -export async function computeSubLayoutAsync(nodeIds, edgeDefs, layoutName) { - const onProgress = S.layoutProgress ? (f) => S.layoutProgress && S.layoutProgress.report(f) : null - if (layoutName === 'fr' && nodeIds.length > 1) return frLayoutAsync(nodeIds, edgeDefs, onProgress) - if ((layoutName === 'kk' || layoutName === 'stress') && nodeIds.length > 1) - return distanceLayoutAsync(nodeIds, edgeDefs, layoutName, onProgress) - return computeSubLayout(nodeIds, edgeDefs, layoutName) -} - -export function makeLayoutProgress(show) { - return { - total: 1, - done: 0, - current: 1, - begin(total) { - this.total = Math.max(1e-9, total) - this.done = 0 - this.current = 0 - }, - part(weight) { - this.done += this.current - this.current = weight - this.report(0) - }, - report(f) { - show(Math.min(1, (this.done + this.current * Math.max(0, Math.min(1, f))) / this.total)) - }, - } -} - -export function computeSubLayout(nodeIds, edgeDefs, layoutName) { - if (nodeIds.length === 1) { - return { [nodeIds[0]]: { x: 0, y: 0 } } - } - if (layoutName === 'fr') return frLayout(nodeIds, edgeDefs) - if (layoutName === 'kk' || layoutName === 'stress') - return distanceLayout(nodeIds, edgeDefs, layoutName) - const size = Math.max(300, Math.sqrt(nodeIds.length) * 90) - const sub = cytoscape({ - headless: true, - styleEnabled: false, - elements: { - nodes: nodeIds.map((id) => ({ data: { id } })), - edges: edgeDefs.map((e, i) => ({ - data: { - id: 'sub' + i, - source: e.source, - target: e.target, - weight: Math.min(100, Math.max(0.02, Number.isFinite(e.weight) ? e.weight : 1)), - }, - })), - }, - }) - const opts = { - ...layoutOptsFor(layoutName), - animate: false, - fit: false, - boundingBox: { x1: 0, y1: 0, w: size, h: size }, - } - if (layoutName === 'cose') { - opts.idealEdgeLength = (e) => 90 / Math.sqrt(e.data('weight')) - opts.edgeElasticity = (e) => 32 / e.data('weight') - opts.randomize = true - } - sub.layout(opts).run() - const positions = {} - sub.nodes().forEach((n) => { - positions[n.id()] = { x: n.position('x'), y: n.position('y') } - }) - sub.destroy() - return positions -} - -// Typical spacing between neighboring nodes on screen, from current node sizes. -export function targetNodeSpacing() { - const nodes = cy.nodes(':visible') - if (!nodes.length) return 64 - const mean = nodes.reduce((s, n) => s + (n.data('size') || 42), 0) / nodes.length - return Math.max(24, mean * 1.6) -} - -// Rescales a position map so the median nearest-neighbor distance equals -// `spacing` pixels. Positions from different algorithms come in very -// different units; this puts them all on the same screen scale. -export function normalizeSpacing(positions, spacing) { - const ids = Object.keys(positions) - if (ids.length < 2) return positions - const sample = - ids.length > 1500 ? ids.filter((_, i) => i % Math.ceil(ids.length / 1500) === 0) : ids - const pts = sample.map((id) => positions[id]) - const nn = [] - for (let i = 0; i < pts.length; i++) { - let best = Infinity - for (let j = 0; j < pts.length; j++) { - if (i === j) continue - const d = Math.hypot(pts[i].x - pts[j].x, pts[i].y - pts[j].y) - if (d > 1e-9 && d < best) best = d - } - if (Number.isFinite(best)) nn.push(best) - } - if (!nn.length) return positions - nn.sort((a, b) => a - b) - const scale = spacing / nn[Math.floor(nn.length / 2)] - const out = {} - ids.forEach((id) => { - out[id] = { x: positions[id].x * scale, y: positions[id].y * scale } - }) - return out -} - -export function applyPositions(positions) { - cy.layout({ - name: 'preset', - positions: (node) => positions[node.id()] || node.position(), - animate: cy.nodes().length <= 1500, - animationDuration: 500, - fit: true, - padding: 50, - }).run() -} diff --git a/frontend/src/network_state.ts b/frontend/src/network_state.ts deleted file mode 100644 index 7e8a6e6..0000000 --- a/frontend/src/network_state.ts +++ /dev/null @@ -1,402 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { EDGE_TYPES, NODE_PALETTES, colorAtIndex } from './palette' -import { NORMA_CFG } from './config' -import { S } from './state' -import { cy } from './cy' -import { nodeShapeFor, refreshEdgeLabelOptions } from './profiler' -import { parseNumber } from './clustering/mcl' - -const AUTO_EDGE_COLORS = ['#6c7793', '#d68fc0', '#7fd68a', '#e8a15f', '#8fb8e8', '#e07a7a'] - -export const PIE_MAX_SLICES = 16 - -// Nodes that belong to no group are collected under this key so they still -// have something to toggle in the legend. It is never written out as a -// real group (JSON export omits it; NORMA export skips it). -export const UNGROUPED = '__ungrouped__' - -export const UNGROUPED_LABEL = 'Not in any group' - -// Fill for nodes without their own color when coloring nodes from data, -// matching NORMA's default gray. -const NO_NODE_COLOR = '#9aa0a6' - -// Keeps only numeric (or missing) entries of a JSON values object. -export function cleanValues(obj) { - const out = {} - let any = false - Object.entries(obj).forEach(([k, v]) => { - const x = typeof v === 'number' ? v : parseNumber(v) - if (x === undefined) return - out[k] = x - any = true - }) - return any ? out : null -} - -export function nodeFillMode() { - const el = document.getElementById('nodeFillSelect') - return el ? el.value : 'groups' -} - -/* ============================================================ - ATTRIBUTE MODULE - One model for all three levels of the network: - - level | structural (reserved) keys | where custom attrs live - -------+-------------------------------------+-------------------------------- - node | id, group, groups, size, color | extra fields, or node.attrs - edge | id, source, target, type, color, | extra fields, or edge.attrs - | weight | - group | label, description, color | extra fields in groupAttrs[g], - | | or groupAttrs[g].attrs - - Reserved keys drive rendering; everything else is carried through - untouched, shown in the inspectors via one shared formatter, summarised - per level in the sidebar "Attributes" section, and written back out - on export in the same shape it came in. - ============================================================ */ -// NORMA shows networks of up to this many nodes; larger ones are cut to -// their first nodes (in file order) with a message. -export const MAX_NETWORK_NODES = Math.max( - 100, - Math.min(50000, parseInt(NORMA_CFG.app.maxNodes, 10) || 10000) -) - -export const RESERVED_NODE_KEYS = new Set([ - 'id', - 'group', - 'groups', - 'size', - 'color', - 'values', - 'attrs', -]) - -export const RESERVED_EDGE_KEYS = new Set([ - 'id', - 'source', - 'target', - 'type', - 'color', - 'weight', - 'directed', - 'attrs', -]) - -const RESERVED_GROUP_KEYS = new Set(['label', 'description', 'color', 'attrs']) - -export function collectAttrs(obj, reservedKeys) { - if (!obj || typeof obj !== 'object') return {} - const attrs = { ...(obj.attrs && typeof obj.attrs === 'object' ? obj.attrs : {}) } - Object.keys(obj).forEach((k) => { - if (!reservedKeys.has(k)) attrs[k] = obj[k] - }) - return attrs -} - -// Colors from loaded network/session data (nodeColors, groupAttrs.color, ...) -// are untrusted and end up in style/attribute values, so only a strict CSS -// color syntax is let through; anything else (e.g. an attribute-breakout -// attempt) is rejected rather than escaped, since these values are used both -// in innerHTML templates and as literal Cytoscape style colors. -export function sanitizeColor(c) { - if (typeof c !== 'string') return null - const v = c.trim() - if (/^#[0-9a-fA-F]{3,4}$|^#[0-9a-fA-F]{6}$|^#[0-9a-fA-F]{8}$/.test(v)) return v - if (/^(rgb|rgba|hsl|hsla)\(\s*[\d.]+%?(\s*,\s*[\d.]+%?){2,3}\s*\)$/.test(v)) return v - if (/^[a-zA-Z]{3,20}$/.test(v)) return v - return null -} - -export function escapeHtml(str) { - return String(str).replace( - /[&<>"']/g, - (ch) => - ({ - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''', - })[ch] - ) -} - -export function attrKind(v) { - if (v === null || v === undefined || v === '') return 'empty' - if (Array.isArray(v)) return 'list' - if (typeof v === 'number') return Number.isFinite(v) ? 'number' : 'text' - if (typeof v === 'boolean') return 'boolean' - if (typeof v === 'object') return 'object' - return 'text' -} - -export function formatAttrValue(v) { - switch (attrKind(v)) { - case 'empty': - return '—' - case 'number': - return Number.isInteger(v) ? String(v) : String(+v.toPrecision(4)) - case 'boolean': - return v ? 'yes' : 'no' - case 'list': - return v - .map((x) => { - const k = attrKind(x) - return k === 'list' || k === 'object' ? JSON.stringify(x) : formatAttrValue(x) - }) - .join(', ') - case 'object': - return JSON.stringify(v) - default: - return String(v) - } -} - -// Plain-text form used by search, so lists and objects are matched on -// their contents rather than on "[object Object]". -function attrSearchText(attrs) { - return Object.values(attrs || {}) - .map(formatAttrValue) - .join(' ') - .toLowerCase() -} - -export function attrRowsHtml(attrs, rowClass) { - return Object.entries(attrs || {}) - .map( - ([k, v]) => - `
    ${escapeHtml(k)}${escapeHtml(formatAttrValue(v))}
    ` - ) - .join('') -} - -export function groupLabel(g) { - return (S.groupAttrs[g] && S.groupAttrs[g].label) || g -} - -export function groupDescription(g) { - return (S.groupAttrs[g] && S.groupAttrs[g].description) || '' -} - -export function customGroupAttrs(g) { - return collectAttrs(S.groupAttrs[g], RESERVED_GROUP_KEYS) -} - -// Summary of which attribute keys the loaded network uses, per level: -// { node: { key: { count, kinds:Set, min, max, values:Set } }, edge: {...}, group: {...} } -export let attrSchema = { node: {}, edge: {}, group: {} } - -const SCHEMA_DISTINCT_CAP = 50 - -function recordAttrs(bucket, attrs) { - Object.entries(attrs || {}).forEach(([k, v]) => { - const entry = - bucket[k] || - (bucket[k] = { count: 0, kinds: new Set(), min: Infinity, max: -Infinity, values: new Set() }) - const kind = attrKind(v) - if (kind === 'empty') return - entry.count++ - entry.kinds.add(kind) - if (kind === 'number') { - entry.min = Math.min(entry.min, v) - entry.max = Math.max(entry.max, v) - } else if (kind === 'text' && entry.values.size <= SCHEMA_DISTINCT_CAP) { - entry.values.add(v) - } else if (kind === 'list' && entry.values.size <= SCHEMA_DISTINCT_CAP) { - v.forEach((x) => entry.values.add(formatAttrValue(x))) - } - }) -} - -export function buildAttrSchema() { - attrSchema = { node: {}, edge: {}, group: {} } - cy.nodes().forEach((n) => recordAttrs(attrSchema.node, n.data('attrs'))) - cy.edges().forEach((e) => recordAttrs(attrSchema.edge, e.data('attrs'))) - getUsedGroups().forEach((g) => recordAttrs(attrSchema.group, customGroupAttrs(g))) -} - -function describeSchemaEntry(entry) { - if (entry.kinds.size > 1) return 'mixed: ' + [...entry.kinds].join(', ') - const kind = [...entry.kinds][0] - if (kind === 'number') { - return entry.min === entry.max - ? `number, always ${formatAttrValue(entry.min)}` - : `number, ${formatAttrValue(entry.min)} to ${formatAttrValue(entry.max)}` - } - if (kind === 'text') { - const n = entry.values.size - if (n > SCHEMA_DISTINCT_CAP) return `text, over ${SCHEMA_DISTINCT_CAP} values` - return n <= 4 ? `text: ${[...entry.values].join(', ')}` : `text, ${n} values` - } - if (kind === 'boolean') return 'yes / no' - if (kind === 'list') { - const n = entry.values.size - return n > SCHEMA_DISTINCT_CAP - ? `list, over ${SCHEMA_DISTINCT_CAP} distinct items` - : `list, ${n} distinct ${n === 1 ? 'item' : 'items'}` - } - return kind || 'empty' -} - -export function renderAttrSchema() { - refreshEdgeLabelOptions() - const el = document.getElementById('attrSchema') - if (!el) return - const totals = { node: cy.nodes().length, edge: cy.edges().length, group: getUsedGroups().length } - if (!totals.node) { - el.innerHTML = '

    Load a network to see its attributes.

    ' - return - } - const titles = { node: 'Nodes', edge: 'Edges', group: 'Groups' } - el.innerHTML = ['node', 'edge', 'group'] - .map((level) => { - const entries = Object.entries(attrSchema[level]).filter(([, e]) => e.count > 0) - const rows = entries.length - ? entries - .map( - ([k, e]) => ` -
    - ${escapeHtml(k)} - ${e.count}/${totals[level]} - ${escapeHtml(describeSchemaEntry(e))} -
    ` - ) - .join('') - : '

    No custom attributes

    ' - return `
    -
    ${titles[level]}${totals[level]}
    - ${rows} -
    ` - }) - .join('') -} - -// "Not in any group" is always neutral gray and doesn't use up a palette color. -export function colorForGroup(g) { - if (!S.nodeColorMap[g]) { - if (g === UNGROUPED) { - S.nodeColorMap[g] = NO_NODE_COLOR - } else { - const palette = NODE_PALETTES[S.currentNodePalette] || NODE_PALETTES.vivid - const idx = Object.keys(S.nodeColorMap).filter((k) => k !== UNGROUPED).length - S.nodeColorMap[g] = colorAtIndex(palette, idx) - } - } - return S.nodeColorMap[g] -} - -export function nextAutoEdgeColor() { - const c = colorAtIndex(AUTO_EDGE_COLORS, S.autoEdgeIdx) - S.autoEdgeIdx++ - return c -} - -// Computes the color/pie-slice data fields for a node given its list of groups. -// A single-group node gets one 100% slice (looks like a plain colored circle); -// a multi-group node gets one evenly-sized slice per group, in order. -// Slices are equal-sized. A node in more groups than there are slices shows -// its first PIE_MAX_SLICES - 1 groups plus one gray slice sized for the rest. -export function computeNodeVisualFields(groupsArr) { - const all = groupsArr && groupsArr.length ? groupsArr : [UNGROUPED] - const overflow = all.length > PIE_MAX_SLICES - const shown = overflow ? all.slice(0, PIE_MAX_SLICES - 1) : all - const slices = shown.map((g) => ({ color: colorForGroup(g), size: 100 / all.length })) - if (overflow) - slices.push({ color: NO_NODE_COLOR, size: (100 * (all.length - shown.length)) / all.length }) - const fields = { color: slices[0].color } - for (let i = 0; i < PIE_MAX_SLICES; i++) { - const idx = i + 1 - fields['pieColor' + idx] = i < slices.length ? slices[i].color : '#000000' - fields['pieSize' + idx] = i < slices.length ? slices[i].size.toFixed(3) + '%' : '0%' - } - return fields -} - -// Optional display order for groups (e.g. the line order of an annotation -// file); groups not listed keep node order, and "Not in any group" is last. -let groupOrderHint = null - -export function getUsedGroups() { - const groups = [ - ...new Set( - cy - .nodes() - .map((n) => n.data('groups') || []) - .flat() - ), - ] - const rank = (g) => - g === UNGROUPED - ? Infinity - : groupOrderHint && groupOrderHint.has(g) - ? groupOrderHint.get(g) - : 1e9 - return groups - .map((g, i) => [g, i]) - .sort((a, b) => rank(a[0]) - rank(b[0]) || a[1] - b[1]) - .map((x) => x[0]) -} - -export function setGroupOrder(names) { - groupOrderHint = Array.isArray(names) ? new Map(names.map((g, i) => [g, i])) : null -} - -// A node's *effective* groups are whichever of its assigned groups are -// currently active. Deactivating one of a node's several groups doesn't just -// toggle visibility -- the node is redrawn using only its remaining active -// groups, so a 2-group node with one group turned off becomes a plain single -// color instead of staying a two-slice pie. -export function effectiveGroupsFor(node) { - const groups = node.data('groups') || [] - return groups.filter((g) => S.activeGroups.has(g)) -} - -// One solid color across the whole node, used when node fill comes from -// each node's own "color" field (e.g. a NORMA node-coloring file). -function solidVisualFields(color) { - const fields = { color, pieColor1: color, pieSize1: '100%' } - for (let i = 2; i <= PIE_MAX_SLICES; i++) { - fields['pieColor' + i] = '#000000' - fields['pieSize' + i] = '0%' - } - return fields -} - -export function refreshNodeVisual(node) { - const eff = effectiveGroupsFor(node) - if (!eff.length) { - node.addClass('hidden-group') - return - } - if (node.hasClass('hidden-group')) node.removeClass('hidden-group') - const fill = nodeFillMode() - const visual = - fill === 'data' - ? solidVisualFields(node.data('nodeColor') || NO_NODE_COLOR) - : fill === 'values' - ? solidVisualFields( - node.data('valueColor') || - document.getElementById('valueMissing').value || - NO_NODE_COLOR - ) - : computeNodeVisualFields(eff) - visual.shape = nodeShapeFor(eff) - visual.labelColor = visual.color - if (visual.shape !== 'ellipse') { - // a single-color shaped node: the fill carries the color, no pie - for (let i = 1; i <= PIE_MAX_SLICES; i++) visual['pieSize' + i] = '0%' - } - // only write fields that changed, in a single update - const changed = {} - let any = false - for (const k in visual) { - if (node.data(k) !== visual[k]) { - changed[k] = visual[k] - any = true - } - } - if (any) node.data(changed) -} diff --git a/frontend/src/palette.ts b/frontend/src/palette.ts deleted file mode 100644 index eacbce9..0000000 --- a/frontend/src/palette.ts +++ /dev/null @@ -1,106 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -/* ---------- edge type palette (STRING-style evidence channels) ---------- */ -export const EDGE_TYPES = { - neighborhood: { color: '#59c46b', label: 'Gene neighborhood' }, - fusion: { color: '#d9534f', label: 'Gene fusion' }, - cooccurrence: { color: '#3a6cd6', label: 'Co-occurrence' }, - coexpression: { color: '#111827', label: 'Co-expression' }, - experiments: { color: '#b464c9', label: 'Experiments' }, - database: { color: '#8fc7e8', label: 'Curated database' }, - textmining: { color: '#c9c14a', label: 'Text mining' }, - homology: { color: '#caa6ea', label: 'Homology' }, -} - -export const ORIGINAL_EDGE_TYPES = JSON.parse(JSON.stringify(EDGE_TYPES)) - -// Colorblind-safe palettes, shared between node and edge use. -// Okabe-Ito: Okabe,M. and Ito,K. (2008) Color Universal Design (CUD) - a widely -// used 8-color palette designed to stay distinguishable under the common forms -// of color vision deficiency (protanopia, deuteranopia, tritanopia). -const CB_OKABE_ITO = [ - '#E69F00', - '#56B4E9', - '#009E73', - '#F0E442', - '#0072B2', - '#D55E00', - '#CC79A7', - '#000000', -] - -// IBM Design Language's colorblind-safe categorical set. -const CB_IBM = ['#648FFF', '#785EF0', '#DC267F', '#FE6100', '#FFB000'] - -// Viridis-inspired perceptually-uniform sequence (also colorblind-safe by design). -const CB_VIRIDIS = [ - '#440154', - '#482878', - '#3E4A89', - '#31688E', - '#26828E', - '#1F9E89', - '#35B779', - '#FDE725', -] - -// Once a category count exceeds a curated palette's length (all palettes here -// have 5-8 hand-picked colors), further colors are generated on the fly using -// a golden-angle hue rotation. Successive hues stay well-spread around the -// color wheel however many categories are added -- this is what lets the -// legends stay usable up to ~100 distinct edge channels or node groups -// instead of the palette repeating every 6-8 entries. -function hslToHex(h, s, l) { - s /= 100 - l /= 100 - const k = (n) => (n + h / 30) % 12 - const a = s * Math.min(l, 1 - l) - const f = (n) => l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1))) - const toHex = (x) => - Math.round(255 * x) - .toString(16) - .padStart(2, '0') - return `#${toHex(f(0))}${toHex(f(8))}${toHex(f(4))}` -} - -function goldenAngleColor(index) { - const hue = (index * 137.508) % 360 // golden angle, avoids hue clustering - const s = 62, - l = index % 2 === 0 ? 52 : 62 // alternate lightness for extra separation - return hslToHex(hue, s, l) -} - -export function colorAtIndex(palette, index) { - return index < palette.length ? palette[index] : goldenAngleColor(index) -} - -export const NODE_PALETTES = { - vivid: ['#e8a15f', '#5fd3c4', '#e07a7a', '#8fb8e8', '#c9c14a', '#a97fd6', '#7fd68a', '#d68fc0'], - sunset: ['#f4a261', '#e76f51', '#e9c46a', '#f2a65a', '#bc6c25', '#dda15e', '#ffb703', '#fb8500'], - ocean: ['#264653', '#2a9d8f', '#8ecae6', '#219ebc', '#023047', '#48cae4', '#90e0ef', '#00b4d8'], - forest: ['#606c38', '#283618', '#a3b18a', '#588157', '#3a5a40', '#344e41', '#6a994e', '#a7c957'], - pastel: ['#ffd6ff', '#c8b6ff', '#bde0fe', '#a2d2ff', '#ffafcc', '#caffbf', '#fdffb6', '#ffc6ff'], - mono: ['#3a4a6b', '#4c5f8a', '#6478a8', '#7d91c0', '#96a9d3', '#b0bfe0', '#c9d3ea', '#e2e7f4'], - cbOkabeIto: CB_OKABE_ITO, - cbIBM: CB_IBM, - viridis: CB_VIRIDIS, -} - -export const EDGE_PALETTES = { - categorical: [ - '#e07a7a', - '#5fd3c4', - '#e8a15f', - '#8fb8e8', - '#c9c14a', - '#a97fd6', - '#7fd68a', - '#d68fc0', - ], - warm: ['#e63946', '#f4a261', '#e9c46a', '#f77f00', '#d62828', '#fb8500', '#c1121f', '#ee9b00'], - cool: ['#264653', '#2a9d8f', '#457b9d', '#1d3557', '#48cae4', '#219ebc', '#023047', '#90e0ef'], - mono: ['#3a4a6b', '#4c5f8a', '#6478a8', '#7d91c0', '#96a9d3', '#b0bfe0', '#c9d3ea', '#e2e7f4'], - cbOkabeIto: CB_OKABE_ITO, - cbIBM: CB_IBM, - viridis: CB_VIRIDIS, -} diff --git a/frontend/src/parallel_edges.ts b/frontend/src/parallel_edges.ts deleted file mode 100644 index 96fa9d3..0000000 --- a/frontend/src/parallel_edges.ts +++ /dev/null @@ -1,80 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { S } from './state' -import { applyEdgeLabels, scheduleBundling } from './profiler' -import { applyNodeSizing, invalidateFullMetrics } from './metrics' -import { currentTheme } from './themes' -import { cy } from './cy' -import { edgeIsDirected } from './export/dialog' - -/* ---------- parallel edges: merge per node pair ---------- */ -// In merge mode each node pair keeps one visible edge (its first edge in an -// active channel). That edge is widened by the number of active channels -// on the pair and turns gray when they disagree; the popup lists them all. -// Uses per-edge style bypasses so it layers over whatever width and color -// rules the stylesheet currently has. -function edgeMergeOn() { - const el = document.getElementById('edgeMergeMode') - return !!el && el.value === 'merge' -} - -export function applyEdgeMerge() { - if (typeof cy === 'undefined') return - const on = edgeMergeOn() - cy.batch(() => { - cy.edges('.merged-rep').forEach((e) => { - e.removeStyle('width line-color target-arrow-color') - e.removeClass('merged-rep') - }) - cy.edges('.merged-hidden').removeClass('merged-hidden') - cy.edges().forEach((e) => { - if (e.data('mergedWith')) e.data('mergedWith', null) - }) - if (!on) return - const byPair = new Map() - cy.edges().forEach((e) => { - if (e.hasClass('hidden-type')) return - const s = e.data('source'), - t = e.data('target') - // directed edges merge only with edges running the same way - const key = edgeIsDirected(e) - ? 'D\t' + s + '\t' + t - : 'U\t' + (s < t ? s + '\t' + t : t + '\t' + s) - const list = byPair.get(key) - if (list) list.push(e) - else byPair.set(key, [e]) - }) - const baseFixed = parseFloat(document.getElementById('edgeWidthFixed').value) || 2 - const byWeight = document.getElementById('edgeWidthMode').value === 'weight' - byPair.forEach((list) => { - if (list.length < 2) return - const [rep, ...rest] = list - rest.forEach((e) => e.addClass('merged-hidden')) - rep.data( - 'mergedWith', - list.map((e) => e.id()) - ) - const colors = new Set(list.map((e) => e.data('color'))) - const base = byWeight ? rep.data('edgeWidth') || baseFixed : baseFixed - rep.addClass('merged-rep') - rep.style({ - width: Math.min(base * (1 + 0.7 * (list.length - 1)), base * 6), - 'line-color': colors.size === 1 ? rep.data('color') : currentTheme.muted, - 'target-arrow-color': colors.size === 1 ? rep.data('color') : currentTheme.muted, - }) - }) - }) - applyEdgeLabels() - if (typeof scheduleBundling === 'function') scheduleBundling() -} - -export function applyTypeVisibility() { - cy.edges().forEach((e) => { - if (S.activeTypes.has(e.data('type'))) e.removeClass('hidden-type') - else e.addClass('hidden-type') - }) - applyEdgeMerge() - invalidateFullMetrics() - // if node sizes are being driven by a channel-scoped metric, keep them live - if (document.getElementById('sizeChannelOnly').checked) applyNodeSizing() -} diff --git a/frontend/src/profiler.ts b/frontend/src/profiler.ts deleted file mode 100644 index de1a316..0000000 --- a/frontend/src/profiler.ts +++ /dev/null @@ -1,2630 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { COMMUNITY_ALGORITHMS, WALKTRAP_NODE_LIMIT } from './welcome' -import { - CONFIG_FIELDS, - applyEdgePalette, - applyGroupVisibility, - applyNodePalette, - buildGroupLegend, - buildLegend, - byName, - drawGroupHulls, - filteredGroups, - getCurrentConfig, - getUsedTypes, - legendExtra, - loadData, - refreshAllDerivedUI, - sortedByName, -} from './hulls' -import { EDGE_TYPES, NODE_PALETTES, ORIGINAL_EDGE_TYPES, colorAtIndex } from './palette' -import { PROFILE_DIRECTED_STATS, directedStatsTable, profileDirected } from './directed_stats' -import { - PROFILE_PATH_LIMIT, - PROFILE_STATS, - formatStat, - profileGraph, - simpleGraph, - switchTab, -} from './wiring' -import { S } from './state' -import { - UNGROUPED, - attrKind, - attrRowsHtml, - attrSchema, - buildAttrSchema, - customGroupAttrs, - escapeHtml, - formatAttrValue, - getUsedGroups, - groupDescription, - groupLabel, - nodeFillMode, - refreshNodeVisual, - renderAttrSchema, - sanitizeColor, -} from './network_state' -import { WEBGL_ACTIVE, cy, setStyle } from './cy' -import { - addNormaEntry, - annotationText, - downloadText, - libEntry, - libSelection, - listSample, - nextPaint, - normaLibrary, - plural, - renderLibraryLists, - selectedNetworks, - setStatus, -} from './layouts/controls' -import { applyEdgeMerge, applyTypeVisibility } from './parallel_edges' -import { applyGroupsAndColorsInPlace, refreshLibraryView } from './library' -import { applyLabelColors } from './label_colors' -import { - applyNodeSizing, - bundleAsync, - cancelFrJobs, - ensureFullMetrics, - invalidateFullMetrics, - shownEdges, - shownNodes, - updateStats, -} from './metrics' -import { applyTheme, currentTheme } from './themes' -import { applyValueColors, scheduleLegend } from './clustering/mapping' -import { arrowsShown, edgeIsDirected } from './export/dialog' -import { - bumpDataVersion, - dataVersion, - flushHistory, - historyTimer, - setHistoryBaseline, - updateUndoButtons, -} from './demo_downloads' -import { capture3d, restore3d } from './view3d/tab' -import { fit3d } from './view3d/camera' -import { net3d } from './view3d/state' -import { refreshAfterDelete } from './api/tester' -import { runCommunityAlgorithm } from './clustering/mcl' -import { setLayoutBusy } from './layouts/run' -import { updateContextInfo } from './recording' - -/* ---------- profiler UI ---------- */ -export const profilerState = { results: [] } - -export function renderProfilerNetworkList() { - const el = document.getElementById('profNetList') - if (!el) return - const previous = new Set([...el.querySelectorAll('input:checked')].map((i) => i.value)) - const firstRender = !el.dataset.rendered - el.dataset.rendered = '1' - el.innerHTML = '' - const cur = typeof activeView === 'function' && activeView() - const options = [ - { - value: 'view', - label: `Current view: ${cur ? cur.name : 'untitled'} (${shownNodes().length} shown nodes)`, - }, - ].concat( - sortedByName(normaLibrary.network, (e) => e.name).map((e) => ({ value: e.id, label: e.name })) - ) - options.forEach((o) => { - const label = document.createElement('label') - const input = document.createElement('input') - input.type = 'checkbox' - input.value = o.value - input.checked = firstRender ? o.value === 'view' : previous.has(o.value) - const span = document.createElement('span') - span.textContent = o.label - label.append(input, span) - el.appendChild(label) - }) -} - -function graphForSource(value) { - if (value === 'view') { - const ids = shownNodes().map((n) => n.id()) - const shownE = shownEdges(true) - const pairs = shownE.map((e) => [e.data('source'), e.data('target')]) - const dirEdges = shownE.map((e) => [e.data('source'), e.data('target'), edgeIsDirected(e)]) - const viewIds = S.currentLibView ? S.currentLibView.nets.split('|') : [] - const nets = normaLibrary.network.filter((e) => viewIds.includes(e.id)) - const viewLabel = nets.length ? nets.map((e) => e.name).join(' + ') : 'Current view' - const cur = typeof activeView === 'function' && activeView() - return { - name: cur ? `View: ${cur.name}` : 'Current view', - label: viewLabel, - graph: simpleGraph(ids, pairs), - isView: true, - ids, - dirEdges, - } - } - const entry = libEntry('network', value) - if (!entry) return null - return { - name: entry.name, - graph: simpleGraph( - entry.parsed.nodes, - entry.parsed.edges.map((e) => [e.source, e.target]) - ), - ids: entry.parsed.nodes, - dirEdges: entry.parsed.edges.map((e) => [e.source, e.target, !!e.directed]), - isView: false, - entry, - } -} - -function runProfiler() { - const chosen = [...document.querySelectorAll('#profNetList input:checked')].map((i) => i.value) - if (!chosen.length) { - setStatus('profStatus', [{ level: 'error', text: 'Tick at least one network to profile.' }]) - return - } - if (chosen.includes('view') && !cy.nodes().length) { - setStatus('profStatus', [ - { - level: 'error', - text: 'The current view is empty. Load a network first, or untick "Current view".', - }, - ]) - return - } - const profText = (i) => - chosen.length > 1 - ? `Computing statistics: network ${i + 1} of ${chosen.length}…` - : 'Computing statistics…' - setStatus('profStatus', [ - { level: 'busy', text: profText(0), progress: chosen.length > 1 ? 0 : null }, - ]) - document.getElementById('btnProfile').disabled = true - // one network at a time, letting the progress paint in between - ;(async () => { - await nextPaint() - try { - const started = performance.now() - const useDir = document.getElementById('profDirected').checked - const results = [] - for (const [i, value] of chosen.entries()) { - if (i > 0) { - setStatus('profStatus', [ - { level: 'busy', text: profText(i), progress: i / chosen.length }, - ]) - await nextPaint() - } - const g = graphForSource(value) - if (!g) continue - const src = { ...g, sourceValue: value } - results.push({ - ...src, - stats: profileGraph(src.graph), - directed: - useDir && src.dirEdges.some((d) => d[2]) - ? profileDirected(src.ids, src.dirEdges) - : null, - }) - } - profilerState.results = results - renderProfilerResults(results) - const secs = ((performance.now() - started) / 1000).toFixed(2) - const notes = [ - { level: 'ok', text: `Profiled ${plural(results.length, 'network')} in ${secs} s.` }, - ] - if (results.some((r) => r.stats.pathsSkipped)) - notes.push({ - level: 'warn', - text: `Path-based statistics were skipped for networks above ${PROFILE_PATH_LIMIT.toLocaleString('en-US')} nodes.`, - }) - setStatus('profStatus', notes) - document.getElementById('btnProfileTsv').disabled = false - } catch (err) { - setStatus('profStatus', [ - { level: 'error', text: `The statistics couldn't be computed: ${err.message}` }, - ]) - } finally { - document.getElementById('btnProfile').disabled = false - } - })() -} - -export function renderProfilerResults(results) { - const root = document.getElementById('profResults') - root.innerHTML = '' - - // statistics table - const sec = profSection('Statistics', '') - const wrap = document.createElement('div') - wrap.className = 'table-wrap' - const table = document.createElement('table') - table.className = 'data' - const head = document.createElement('tr') - head.innerHTML = - 'Statistic' + - results.map((r) => `${escapeHtml(r.name)}`).join('') - const thead = document.createElement('thead') - thead.appendChild(head) - const tbody = document.createElement('tbody') - PROFILE_STATS.forEach((st) => { - const tr = document.createElement('tr') - tr.innerHTML = - `${escapeHtml(st.label)}${escapeHtml(st.desc)}` + - results.map((r) => `${escapeHtml(formatStat(r.stats[st.key]))}`).join('') - tbody.appendChild(tr) - }) - table.append(thead, tbody) - wrap.appendChild(table) - sec.appendChild(wrap) - const split = results.filter((r) => r.stats.components > 1).map((r) => r.name) - if (split.length) { - sec.insertAdjacentHTML( - 'beforeend', - `

    ${escapeHtml(listSample(split, 4))} ${split.length === 1 ? 'has' : 'have'} more than one component. As in igraph, closeness is then computed within each component, so closeness centralization can exceed 1 and isn't comparable with connected networks.

    ` - ) - } - root.appendChild(sec) - - if (results.some((r) => r.directed)) { - const dsec = profSection( - 'Direction', - 'Statistics that follow edge directions, for networks with directed edges. Undirected edges can be walked both ways. A dash means the network has no directed edges.' - ) - dsec.insertAdjacentHTML('beforeend', directedStatsTable(results)) - root.appendChild(dsec) - } - - // degree distributions - const degSec = profSection('Degree distribution', 'Number of nodes with each degree.') - const controls = document.createElement('div') - controls.className = 'inline-controls' - controls.innerHTML = '' - degSec.appendChild(controls) - const degCards = document.createElement('div') - degCards.className = 'cards' - degSec.appendChild(degCards) - const drawDeg = () => { - const log = document.getElementById('degLogLog').checked - degCards.innerHTML = '' - results.forEach((r) => { - const card = document.createElement('div') - card.className = 'card chart' - card.innerHTML = - `

    ${escapeHtml(r.name)}

    ` + - degreeChartSvg(r.stats.degree, log) - degCards.appendChild(card) - }) - } - controls.querySelector('input').addEventListener('change', drawDeg) - root.appendChild(degSec) - drawDeg() - - // central nodes - const cSec = profSection('Most central nodes', 'Top ten nodes by the chosen measure.') - const cControls = document.createElement('div') - cControls.className = 'inline-controls' - cControls.innerHTML = `` - cSec.appendChild(cControls) - const cCards = document.createElement('div') - cCards.className = 'cards' - cCards.style.gridTemplateColumns = 'repeat(auto-fill, minmax(400px, 1fr))' - cSec.appendChild(cCards) - const drawCentral = () => { - const by = document.getElementById('centralBy').value - cCards.innerHTML = '' - results.forEach((r) => { - const s = r.stats - const values = - by === 'degree' - ? s.degree - : by === 'betweenness' - ? s.betweenness - : by === 'closeness' - ? s.closeness - : s.localClustering - const card = document.createElement('div') - card.className = 'card' - card.innerHTML = `

    ${escapeHtml(r.name)}

    ` - if (!values) { - card.insertAdjacentHTML( - 'beforeend', - '

    Not computed for a network this large.

    ' - ) - cCards.appendChild(card) - return - } - const idx = Array.from({ length: r.graph.n }, (_, i) => i) - .filter((i) => Number.isFinite(values[i])) - .sort((a, b) => values[b] - values[a]) - .slice(0, 10) - const rows = idx - .map((i) => { - const id = r.graph.ids[i] - const inView = !!cy.getElementById(id).length - const nameCell = inView - ? `` - : escapeHtml(id) - return `${nameCell}${escapeHtml(formatStat(s.degree[i]))}${s.betweenness ? escapeHtml(formatStat(s.betweenness[i])) : '—'}${s.closeness ? escapeHtml(formatStat(s.closeness[i])) : '—'}` - }) - .join('') - card.insertAdjacentHTML( - 'beforeend', - `
    ${rows}
    NodeDegreeBetweennessCloseness
    ` - ) - cCards.appendChild(card) - }) - cCards - .querySelectorAll('button[data-node]') - .forEach((b) => b.addEventListener('click', () => focusNodeInNetwork(b.dataset.node))) - } - cControls.querySelector('select').addEventListener('change', drawCentral) - root.appendChild(cSec) - drawCentral() - - // communities - const lSec = profSection( - 'Communities', - 'Find communities with one of five algorithms and add them to Files as an annotation to view them as groups. Modularity is computed the same way for every algorithm.' - ) - const algo = profilerState.cmAlgo || 'louvain' - lSec.insertAdjacentHTML( - 'beforeend', - `
    - - - - -
    ` - ) - const lCards = document.createElement('div') - lCards.className = 'cards' - lSec.appendChild(lCards) - const drawCommunities = () => { - lCards.innerHTML = '' - results.forEach((r) => { - const lv = r.cmResult || r.stats.louvain - const label = r.cmLabel || 'Louvain' - const card = document.createElement('div') - card.className = 'card' - if (r.cmError) { - card.innerHTML = `

    ${escapeHtml(r.name)}

    ${escapeHtml(r.cmError)}

    ` - lCards.appendChild(card) - return - } - const nonSingle = lv.sizes.filter((x) => x > 1) - const sorted = [...lv.sizes].sort((a, b) => b - a) - const strip = sorted - .slice(0, 40) - .map( - (sz, i) => - `` - ) - .join('') - card.innerHTML = ` -

    ${escapeHtml(r.name)}

    -

    ${escapeHtml(label)}: ${plural(lv.count, 'community', 'communities')} (${nonSingle.length} with more than one node), modularity ${escapeHtml(formatStat(lv.modularity))}${r.cmMs !== undefined ? `, ${Math.round(r.cmMs)} ms` : ''}. Largest: ${sorted.slice(0, 5).join(', ')} nodes.

    - ` - const btn = document.createElement('button') - btn.type = 'button' - btn.textContent = 'Add as annotation' - btn.disabled = !nonSingle.length - btn.addEventListener('click', () => addCommunitiesAsAnnotation(r)) - card.appendChild(btn) - lCards.appendChild(card) - }) - } - const paramFor = (a) => - ({ - louvain: [ - 'Resolution', - 1, - 0.05, - 10, - 0.1, - 'Higher resolution gives more, smaller communities.', - ], - leiden: [ - 'Resolution', - 1, - 0.05, - 10, - 0.1, - 'Like Louvain, but every community is guaranteed to be connected.', - ], - lpa: [ - null, - null, - 0, - 0, - 0, - 'Each node takes the most common label among its neighbours until nothing changes.', - ], - walktrap: [ - 'Walk length', - 4, - 2, - 10, - 1, - `Short random walks tend to stay inside communities. Up to ${WALKTRAP_NODE_LIMIT.toLocaleString('en-US')} nodes.`, - ], - mcl: ['Inflation', 2, 1.1, 6, 0.1, 'Higher inflation gives more, smaller clusters.'], - })[a] - const syncParam = () => { - const a = lSec.querySelector('#cmAlgo').value - const [name, def, min, max, step, hint] = paramFor(a) - const input = lSec.querySelector('#cmParam') - lSec.querySelector('#cmParamLabel').hidden = !name - if (name) { - lSec.querySelector('#cmParamName').textContent = name - Object.assign(input, { min, max, step }) - const saved = profilerState.cmParams && profilerState.cmParams[a] - input.value = saved ?? def - } - lSec.querySelector('#cmHint').textContent = hint - } - lSec.querySelector('#cmAlgo').addEventListener('change', syncParam) - lSec.querySelector('#btnCommunities').addEventListener('click', () => { - const a = lSec.querySelector('#cmAlgo').value - const value = parseFloat(lSec.querySelector('#cmParam').value) - const [name, def, min, max] = paramFor(a) - const v = name ? Math.min(max, Math.max(min, Number.isFinite(value) ? value : def)) : null - profilerState.cmAlgo = a - profilerState.cmParams = { ...(profilerState.cmParams || {}), [a]: v } - const params = - a === 'walktrap' - ? { steps: Math.round(v) } - : a === 'mcl' - ? { inflation: v } - : { resolution: v } - const cmText = `Finding communities with ${COMMUNITY_ALGORITHMS[a].label}…` - setStatus('profStatus', [ - { level: 'busy', text: cmText, progress: results.length > 1 ? 0 : null }, - ]) - ;(async () => { - await nextPaint() - for (const [i, r] of results.entries()) { - if (i > 0) { - setStatus('profStatus', [{ level: 'busy', text: cmText, progress: i / results.length }]) - await nextPaint() - } - const t0 = performance.now() - try { - r.cmResult = runCommunityAlgorithm(r.graph, a, params) - r.cmError = null - } catch (err) { - r.cmResult = null - r.cmError = err.message - } - r.cmMs = performance.now() - t0 - r.cmAlgo = a - r.cmLabel = `${COMMUNITY_ALGORITHMS[a].label}${name ? ` (${name.toLowerCase()} ${a === 'walktrap' ? Math.round(v) : v})` : ''}` - } - drawCommunities() - setStatus('profStatus', [ - { level: 'ok', text: `Found communities with ${COMMUNITY_ALGORITHMS[a].label}.` }, - ]) - })() - }) - syncParam() - drawCommunities() - root.appendChild(lSec) - - // channels of the current view - const viewResult = results.find((r) => r.isView) - const channels = viewResult ? channelProfile() : null - if (channels) root.appendChild(renderChannelSection(channels)) -} - -export function profSection(title, sub) { - const sec = document.createElement('section') - sec.className = 'prof-section' - sec.innerHTML = - `

    ${escapeHtml(title)}

    ` + (sub ? `

    ${escapeHtml(sub)}

    ` : '') - return sec -} - -function degreeChartSvg(deg, logScale) { - const W = 340, - H = 170, - L = 40, - R = 10, - T = 10, - B = 28 - const counts = new Map() - let maxDeg = 0 - deg.forEach((d) => { - counts.set(d, (counts.get(d) || 0) + 1) - if (d > maxDeg) maxDeg = d - }) - const pw = W - L - R, - ph = H - T - B - let body = '' - let xLabels = '', - yLabels = '' - if (logScale) { - const pts = [...counts].filter(([d]) => d > 0) - if (!pts.length) return '

    No connected nodes to plot.

    ' - const maxC = Math.max(...pts.map((p) => p[1])) - const lx = Math.log10(Math.max(maxDeg, 10)), - ly = Math.log10(Math.max(maxC, 10)) - pts.forEach(([d, c]) => { - const x = L + (Math.log10(d) / lx) * pw - const y = T + ph - (Math.log10(c) / ly) * ph - body += `degree ${d}: ${c} nodes` - }) - xLabels = `1${Math.round(Math.pow(10, lx))}` - yLabels = `1${Math.round(Math.pow(10, ly))}` - } else { - const binWidth = Math.max(1, Math.ceil((maxDeg + 1) / 60)) - const bins = new Array(Math.floor(maxDeg / binWidth) + 1).fill(0) - counts.forEach((c, d) => { - bins[Math.floor(d / binWidth)] += c - }) - const maxC = Math.max(...bins, 1) - const bw = pw / bins.length - bins.forEach((c, i) => { - if (!c) return - const h = (c / maxC) * ph - const lo = i * binWidth, - hi = lo + binWidth - 1 - body += `degree ${binWidth > 1 ? `${lo}–${hi}` : lo}: ${c} nodes` - }) - xLabels = `0${maxDeg}` - yLabels = `0${maxC}` - } - return ` - - - ${body}${xLabels}${yLabels} - degree - ` -} - -function focusNodeInNetwork(id) { - const node = cy.getElementById(id) - if (!node.length) return - switchTab('network') - if (node.hasClass('hidden-group')) { - ;(node.data('groups') || []).forEach((g) => S.activeGroups.add(g)) - buildGroupLegend() - applyGroupVisibility() - } - cy.animate( - { center: { eles: node }, zoom: Math.max(cy.zoom(), 1.2) }, - { duration: 300, complete: clampViewport } - ) - node.emit('tap') -} - -function addCommunitiesAsAnnotation(result) { - const lv = result.cmResult || result.stats.louvain - const algoName = COMMUNITY_ALGORITHMS[result.cmAlgo || 'louvain'].short - const members = new Map() - result.graph.ids.forEach((id, i) => { - const c = lv.membership[i] - if (!members.has(c)) members.set(c, []) - members.get(c).push(id) - }) - const groups = [...members.values()] - .filter((list) => list.length > 1) - .sort((a, b) => b.length - a.length) - .map((list, i) => ({ name: `Community-${i + 1}`, members: list })) - const skippedNodes = result.graph.n - groups.reduce((s, g) => s + g.members.length, 0) - const entry = addNormaEntry( - 'annotation', - `${result.label || result.name} ${algoName} communities`, - annotationText(groups), - '' - ) - libSelection.annotation = entry.id - renderLibraryLists() - const notes = [ - { - level: 'ok', - text: `Added the annotation "${entry.name}" with ${plural(groups.length, 'community', 'communities')} to Files and selected it.`, - }, - ] - if (skippedNodes) - notes.push({ - level: 'ok', - text: `${plural(skippedNodes, 'node')} that form a community on their own ${skippedNodes === 1 ? 'was' : 'were'} left out.`, - }) - if (result.isView && S.currentLibView) { - notes.push({ - level: 'ok', - text: 'Show them in this view to see the communities as groups.', - action: { - label: 'Show in this view', - run: () => { - refreshLibraryView() - switchTab('network') - }, - }, - }) - } else if (result.isView) { - notes.push({ - level: 'ok', - text: 'The current view came from an example or JSON rather than Files, so the communities can be applied to it here.', - action: { - label: 'Show as groups now', - run: () => { - applyCommunitiesToView(groups) - switchTab('network') - }, - }, - }) - } else { - notes.push({ - level: 'ok', - text: `Tick "${result.name}" under Files and choose Show in this view to see them.`, - }) - } - setStatus('profStatus', notes) -} - -// For views that didn't come from Files: set groups directly. -function applyCommunitiesToView(groups) { - const groupsOf = {} - groups.forEach((g) => g.members.forEach((id) => (groupsOf[id] = groupsOf[id] || []).push(g.name))) - document.getElementById('nodeFillSelect').value = 'groups' - applyGroupsAndColorsInPlace( - groupsOf, - new Map(), - groups.map((g) => g.name) - ) -} - -function channelProfile() { - const types = getUsedTypes() - if (types.length < 2) return null - const pairsByType = new Map(types.map((t) => [t, new Set()])) - const typesByPair = new Map() - cy.edges().forEach((e) => { - const s = e.data('source'), - t = e.data('target') - if (s === t) return - const key = s < t ? s + '\t' + t : t + '\t' + s - const type = e.data('type') - pairsByType.get(type).add(key) - if (!typesByPair.has(key)) typesByPair.set(key, new Set()) - typesByPair.get(key).add(type) - }) - const perPair = new Map() - typesByPair.forEach((set) => { - perPair.set(set.size, (perPair.get(set.size) || 0) + 1) - }) - return { - types, - pairsByType, - perPair, - totalPairs: typesByPair.size, - totalEdges: cy.edges().length, - } -} - -function renderChannelSection(ch) { - const sec = profSection( - 'Edge channels in the current view', - `${plural(ch.totalEdges, 'edge')} over ${plural(ch.totalPairs, 'connected node pair')}.` - ) - const byCount = [...ch.perPair] - .sort((a, b) => a[0] - b[0]) - .map( - ([k, v]) => - `${plural(k, 'channel')}${v.toLocaleString('en-US')}${((100 * v) / ch.totalPairs).toFixed(1)}%` - ) - .join('') - const shown = ch.types.slice(0, 12) - const matrixHead = - 'ChannelPairs' + - shown.map((t, i) => `${i + 1}`).join('') + - '' - const matrixRows = shown - .map((a, i) => { - const A = ch.pairsByType.get(a) - const cells = shown - .map((b, j) => { - if (i === j) return '—' - const B = ch.pairsByType.get(b) - let shared = 0 - const [small, big] = A.size < B.size ? [A, B] : [B, A] - small.forEach((k) => { - if (big.has(k)) shared++ - }) - const union = A.size + B.size - shared - const jac = union ? shared / union : 0 - return `${jac.toFixed(2)}` - }) - .join('') - return `${i + 1}. ${escapeHtml(a)}${A.size.toLocaleString('en-US')}${cells}` - }) - .join('') - sec.insertAdjacentHTML( - 'beforeend', - ` -
    -
    -

    Node pairs by number of channels

    -
    ${byCount}
    Carried byPairsShare
    -
    -
    -

    Channel overlap (Jaccard index of node pairs)

    -

    1 means two channels connect exactly the same pairs; 0 means they share none.${ch.types.length > shown.length ? ` Showing the first ${shown.length} of ${ch.types.length} channels.` : ''}

    -
    ${matrixHead}${matrixRows}
    -
    -
    ` - ) - return sec -} - -function profilerTsv() { - const results = profilerState.results - if (!results.length) return - const lines = [['Statistic', ...results.map((r) => r.name)].join('\t')] - PROFILE_STATS.forEach((st) => - lines.push([st.label, ...results.map((r) => formatStat(r.stats[st.key]))].join('\t')) - ) - if (results.some((r) => r.directed)) { - PROFILE_DIRECTED_STATS.forEach((st) => - lines.push( - [st.label, ...results.map((r) => (r.directed ? formatStat(r.directed[st.key]) : ''))].join( - '\t' - ) - ) - ) - } - downloadText('network-profile.tsv', lines.join('\n') + '\n') -} - -/* labels */ -// Node label size per node: fixed, or grown in proportion to node size. -export function applyLabelSizes() { - const base = parseFloat(document.getElementById('nodeLabelSize').value) || 12 - const grow = document.getElementById('labelScaleWithNode').checked - cy.batch(() => { - cy.nodes().forEach((n) => { - const px = grow ? Math.max(3, (base * (n.data('size') || 42)) / 42) : base - if (n.data('labelPx') !== px) n.data('labelPx', px) - }) - }) -} - -// Edge label text. A merged edge speaks for all the parallel edges it stands for. -function edgeLabelText(e, mode) { - const merged = e.data('mergedWith') - const group = merged && merged.length > 1 ? merged.map((id) => cy.getElementById(id)) : [e] - const channel = - group.length > 1 - ? `${group.length} channels` - : (EDGE_TYPES[e.data('type')] || {}).label || e.data('type') - const weights = group.map((x) => x.data('weight')).filter((w) => typeof w === 'number') - const weight = weights.length ? formatAttrValue(Math.max(...weights)) : '' - if (mode === 'weight') return weight - if (mode === 'type+weight') return weight ? `${channel} (${weight})` : channel - if (mode.startsWith('attr:')) { - const key = mode.slice(5) - const values = group - .map((x) => (x.data('attrs') || {})[key]) - .filter((v) => attrKind(v) !== 'empty') - return [...new Set(values.map(formatAttrValue))].join(', ') - } - return channel -} - -export function applyEdgeLabels() { - if (!document.getElementById('showEdgeLabels').checked) return - const mode = document.getElementById('edgeLabelContent').value || 'type' - cy.batch(() => { - cy.edges().forEach((e) => { - const text = edgeLabelText(e, mode) - if (e.data('elabel') !== text) e.data('elabel', text) - }) - }) -} - -// Keeps the "attribute" choices in the edge label list in step with the -// edge attributes of the loaded network. -export function refreshEdgeLabelOptions() { - const sel = document.getElementById('edgeLabelContent') - const current = sel.value - ;[...sel.querySelectorAll('option[data-attr]')].forEach((o) => o.remove()) - Object.keys(attrSchema.edge || {}).forEach((key) => { - const opt = new Option(`Text: attribute "${key}"`, 'attr:' + key) - opt.dataset.attr = '1' - sel.add(opt) - }) - sel.value = [...sel.options].some((o) => o.value === current) ? current : 'type' -} - -export function updateLabelStyle() { - const showNode = document.getElementById('showNodeLabels').checked - const showEdge = document.getElementById('showEdgeLabels').checked - const pos = document.getElementById('labelPosition').value - const nodePx = parseFloat(document.getElementById('nodeLabelSize').value) || 12 - const edgePx = parseFloat(document.getElementById('edgeLabelSize').value) || 9 - const minPx = parseFloat(document.getElementById('labelMinScreenSize').value) || 0 - document.getElementById('nodeLabelSizeValue').textContent = `${nodePx} px` - document.getElementById('edgeLabelSizeValue').textContent = `${edgePx} px` - document.getElementById('edgeLabelControls').hidden = !showEdge - - let valign = 'center', - halign = 'center', - marginY = 0, - marginX = 0 - if (pos === 'top') { - valign = 'top' - marginY = -4 - } else if (pos === 'bottom') { - valign = 'bottom' - marginY = 4 - } else if (pos === 'left') { - halign = 'left' - marginX = -6 - } else if (pos === 'right') { - halign = 'right' - marginX = 6 - } - - applyLabelSizes() - applyEdgeLabels() - setStyle('node', { - label: showNode ? 'data(id)' : '', - 'text-valign': valign, - 'text-halign': halign, - 'text-margin-y': marginY, - 'text-margin-x': marginX, - 'min-zoomed-font-size': minPx, - }) - setStyle('edge', { - label: showEdge ? 'data(elabel)' : '', - 'font-size': edgePx, - 'font-family': 'Inter, sans-serif', - color: currentTheme.text, - 'text-background-color': currentTheme.bg, - 'text-background-opacity': 0.85, - 'text-background-padding': 2, - 'text-background-shape': 'roundrectangle', - 'text-rotation': document.getElementById('edgeLabelOrientation').value, - 'min-zoomed-font-size': minPx, - }) - applyEdgeCurveStyle() - applyLabelColors() -} - -/* edge opacity */ -export function applyEdgeOpacity() { - const o = parseFloat(document.getElementById('edgeOpacity').value) || 0.85 - document.getElementById('edgeOpacityValue').textContent = o.toFixed(2) - setStyle('edge', { opacity: o }) - setStyle('edge.dimmed', { opacity: Math.min(0.04, o) }) -} - -/* spread: nodes repel (right) or attract (left) each other. - The slider sets the strength of repulsion (which acts between all nearby - nodes) against the pull of the links, from a quarter to four times the - current arrangement (the "base"). Each pair of nearby nodes, plus a few - distant anchors, gets a target distance from the base: pushed apart, - unlinked neighbours separate most and links resist, so linked groups - stay together and move apart; drawn together, links shorten most and - nodes stop before they overlap. Stress majorization moves the nodes - toward those distances, keeping the arrangement. At 1x the targets are - the base distances, and returning to 1x restores the base exactly. - Dragging nodes, undo and layouts start a new base. */ -let spreadApplied = 0 - -export let spreadBase = null -// { v0, ids, pos, out } -let spreadFrame = 0 - -function spreadFactor(v) { - return Math.pow(2, v) -} - -export function updateSpreadReadout() { - const v = parseFloat(document.getElementById('spreadSlider').value) || 0 - document.getElementById('spreadValue').textContent = spreadFactor(v).toFixed(2) + '×' -} - -// The positions the slider last produced, if the nodes are still there. -function spreadBaseValid(nodes) { - const b = spreadBase - if (!b || b.ids.length !== nodes.length) return false - for (let i = 0; i < nodes.length; i++) { - const n = nodes[i] - if (n.id() !== b.ids[i]) return false - const p = n.position() - if (Math.abs(p.x - b.out[2 * i]) > 1e-6 || Math.abs(p.y - b.out[2 * i + 1]) > 1e-6) return false - } - return true -} - -// Nodes may come as close as they were in the base, but not overlap more. -function spreadSeparate(X, B, n, radii, passes) { - const gap = 4 - const maxR = radii.reduce((a, r) => Math.max(a, r), 0) - if (!(maxR > 0)) return - const size = 2 * maxR + gap - for (let pass = 0; pass < passes; pass++) { - const grid = new Map() - for (let i = 0; i < n; i++) { - const key = - (Math.floor(X[2 * i] / size) + 50000) * 100003 + Math.floor(X[2 * i + 1] / size) + 50000 - let c = grid.get(key) - if (!c) grid.set(key, (c = [])) - c.push(i) - } - let moved = false - grid.forEach((list, key) => { - for (let ox = -1; ox <= 1; ox++) - for (let oy = -1; oy <= 1; oy++) { - const other = grid.get(key + ox * 100003 + oy) - if (!other) continue - for (const i of list) - for (const j of other) { - if (i >= j) continue - let dx = X[2 * i] - X[2 * j], - dy = X[2 * i + 1] - X[2 * j + 1] - const d = Math.hypot(dx, dy) - const want = Math.min( - radii[i] + radii[j] + gap, - Math.hypot(B[2 * i] - B[2 * j], B[2 * i + 1] - B[2 * j + 1]) - ) - if (d >= want - 1e-6) continue - let len = d - if (d < 1e-9) { - dx = (i + j) % 2 ? 1 : -1 - dy = 0 - len = 1 - } - const push = (want - d) / 2 / len - X[2 * i] += dx * push - X[2 * i + 1] += dy * push - X[2 * j] -= dx * push - X[2 * j + 1] -= dy * push - moved = true - } - } - }) - if (!moved) break - } -} - -// Target distances from the base: repulsion acts on every pair of nearby -// nodes and attraction only along links, so pushing apart stretches unlinked -// pairs most (links resist) and drawing together shortens links most -// (unlinked pairs follow less). Crowded pairs change most, distant pairs -// least. Stress majorization then moves the nodes toward those distances. -function spreadRelax(base, n, edges, radii, rel) { - const B = base.pos - if (n < 2) return B.slice() - const dist = (i, j) => Math.hypot(B[2 * i] - B[2 * j], B[2 * i + 1] - B[2 * j + 1]) - let minX = Infinity, - minY = Infinity, - maxX = -Infinity, - maxY = -Infinity - for (let i = 0; i < n; i++) { - minX = Math.min(minX, B[2 * i]) - maxX = Math.max(maxX, B[2 * i]) - minY = Math.min(minY, B[2 * i + 1]) - maxY = Math.max(maxY, B[2 * i + 1]) - } - const cell = Math.max(Math.sqrt(Math.max((maxX - minX) * (maxY - minY), 1) / n) * 2, 1e-6) - const cellOf = (i) => [ - Math.floor((B[2 * i] - minX) / cell), - Math.floor((B[2 * i + 1] - minY) / cell), - ] - const cells = new Map() - for (let i = 0; i < n; i++) { - const [gx, gy] = cellOf(i), - key = gx * 100003 + gy - let c = cells.get(key) - if (!c) cells.set(key, (c = [])) - c.push(i) - } - const NN = 12, - FAR = 12 - const pairs = new Map() - const addPair = (i, j, linked) => { - if (i === j) return - const a = Math.min(i, j), - b = Math.max(i, j), - key = a * n + b - const had = pairs.get(key) - if (had) { - if (linked) had[2] = true - return - } - pairs.set(key, [a, b, linked]) - } - for (let e = 0; e < edges.length; e += 2) addPair(edges[e], edges[e + 1], true) - const nnDist = [] - for (let i = 0; i < n; i++) { - const [gx, gy] = cellOf(i) - let cand = [] - for (let r = 1; r <= 4 && cand.length < NN; r++) { - cand = [] - for (let ox = -r; ox <= r; ox++) - for (let oy = -r; oy <= r; oy++) { - const c = cells.get((gx + ox) * 100003 + gy + oy) - if (c) for (const j of c) if (j !== i) cand.push(j) - } - } - cand.sort((a, b) => dist(i, a) - dist(i, b)) - cand.slice(0, NN).forEach((j) => addPair(i, j, false)) - if (cand.length && dist(i, cand[0]) > 1e-9) nnDist.push(dist(i, cand[0])) - let seed = (i * 2654435761) >>> 0 - for (let f = 0; f < FAR; f++) { - seed = (seed * 1664525 + 1013904223) >>> 0 - addPair(i, seed % n, false) - } - } - nnDist.sort((a, b) => a - b) - const k = nnDist.length ? nnDist[nnDist.length >> 1] * 2 : 50 - - const lr = Math.log(rel) - const P = [] - pairs.forEach(([i, j, linked]) => { - const d0 = dist(i, j) - if (d0 < 1e-9) return - const ratio = d0 / k - const near = ratio <= 1 ? 1 : ratio >= 12 ? 0.08 : 1 - (0.92 * Math.log(ratio)) / Math.log(12) - const follows = rel >= 1 ? (linked ? 0.6 : 1) : linked ? 1 : 0.6 - let t = d0 * Math.exp(lr * near * follows) - if (rel < 1) t = Math.max(t, Math.min(d0, radii[i] + radii[j] + 4)) - P.push(i, j, t) - }) - const X = B.slice() - const iters = n > 2500 ? 30 : n > 800 ? 45 : 70 - const nx = new Float64Array(2 * n), - ws = new Float64Array(n) - let cx = 0, - cyy = 0 - for (let i = 0; i < n; i++) { - cx += B[2 * i] - cyy += B[2 * i + 1] - } - cx /= n - cyy /= n - for (let it = 0; it < iters; it++) { - nx.fill(0) - ws.fill(0) - for (let p = 0; p < P.length; p += 3) { - const i = P[p], - j = P[p + 1], - t = P[p + 2] - let dx = X[2 * i] - X[2 * j], - dy = X[2 * i + 1] - X[2 * j + 1] - let d = Math.hypot(dx, dy) - if (d < 1e-9) { - dx = 1e-3 - dy = 0 - d = 1e-3 - } - const w = 1 / t - const ux = (dx / d) * t, - uy = (dy / d) * t - nx[2 * i] += w * (X[2 * j] + ux) - nx[2 * i + 1] += w * (X[2 * j + 1] + uy) - ws[i] += w - nx[2 * j] += w * (X[2 * i] - ux) - nx[2 * j + 1] += w * (X[2 * i + 1] - uy) - ws[j] += w - } - for (let i = 0; i < n; i++) { - if (ws[i] > 0) { - X[2 * i] = nx[2 * i] / ws[i] - X[2 * i + 1] = nx[2 * i + 1] / ws[i] - } - } - spreadSeparate(X, B, n, radii, 6) - } - spreadSeparate(X, B, n, radii, 150) - let mx = 0, - my = 0 - for (let i = 0; i < n; i++) { - mx += X[2 * i] - my += X[2 * i + 1] - } - mx = mx / n - cx - my = my / n - cyy - for (let i = 0; i < n; i++) { - X[2 * i] -= mx - X[2 * i + 1] -= my - } - return X -} - -function applySpread() { - const v = parseFloat(document.getElementById('spreadSlider').value) || 0 - updateSpreadReadout() - const nodes = cy.nodes() - if (!nodes.length) { - spreadApplied = v - return - } - if (!spreadBaseValid(nodes)) { - const ids = nodes.map((nd) => nd.id()) - const pos = new Float64Array(2 * nodes.length) - nodes.forEach((nd, i) => { - const p = nd.position() - pos[2 * i] = p.x - pos[2 * i + 1] = p.y - }) - spreadBase = { v0: spreadApplied, ids, pos, out: pos } - } - spreadApplied = v - const b = spreadBase - const rel = spreadFactor(v - b.v0) - let out - if (Math.abs(v - b.v0) < 1e-9) out = b.pos - else { - const index = new Map(b.ids.map((id, i) => [id, i])) - const seen = new Set(), - edges = [] - cy.edges().forEach((e) => { - const i = index.get(e.source().id()), - j = index.get(e.target().id()) - if (i === undefined || j === undefined || i === j) return - const key = i < j ? i * nodes.length + j : j * nodes.length + i - if (seen.has(key)) return - seen.add(key) - edges.push(i, j) - }) - const radii = nodes.map((nd) => (nd.width() || 0) / 2) - out = spreadRelax(b, nodes.length, edges, radii, rel) - } - b.out = out - cy.batch(() => { - nodes.forEach((nd, i) => nd.position({ x: out[2 * i], y: out[2 * i + 1] })) - }) - drawGroupHulls() -} - -// Large networks take a moment per step, so they follow the slider when it -// is released rather than while it is dragged. -const SPREAD_LIVE_MAX = 1500 - -function queueSpread() { - updateSpreadReadout() - if (spreadFrame || cy.nodes().length > SPREAD_LIVE_MAX) return - spreadFrame = requestAnimationFrame(() => { - spreadFrame = 0 - applySpread() - }) -} - -function resetSpread() { - spreadApplied = 0 - spreadBase = null - document.getElementById('spreadSlider').value = 0 - updateSpreadReadout() -} - -/* edge curve style (straight / curved / bundled) */ -export const BUNDLE_MAX_EDGES = 10000 - -const BUNDLED_STYLE_PROPS = - 'curve-style control-point-distances control-point-weights edge-distances' - -let bundleSeq = 0 - -let bundleTimer = null - -let bundleSignature = '' - -function bundlingOn() { - return document.getElementById('edgeCurveStyle').value === 'bundled' -} - -function clearBundles() { - bundleSignature = '' - lastBundle = null - cy.batch(() => - cy.edges('.bundled').forEach((e) => { - e.removeStyle(BUNDLED_STYLE_PROPS) - e.removeClass('bundled') - }) - ) -} - -export function applyEdgeCurveStyle() { - const curveStyle = document.getElementById('edgeCurveStyle').value - const curvature = parseInt(document.getElementById('edgeCurvature').value, 10) || 40 - document.getElementById('curvatureValue').textContent = curvature - document.getElementById('curvatureRow').style.display = curveStyle === 'bezier' ? 'block' : 'none' - document.getElementById('bundleRow').hidden = curveStyle !== 'bundled' - document.getElementById('bundleStrengthValue').textContent = - document.getElementById('bundleStrength').value + '%' - - // Cytoscape can't draw labels on haystack edges; with edge labels on, - // straight edges use the (equally straight) 'straight' style instead. - // Bundled edges start straight and are bent individually once computed. - const labelsOn = document.getElementById('showEdgeLabels').checked - let effective = curveStyle - if (curveStyle === 'bundled') effective = 'straight' - else if ( - curveStyle === 'haystack' && - (labelsOn || (typeof arrowsShown === 'function' && arrowsShown())) - ) - effective = 'straight' - setStyle('edge', { - 'curve-style': effective, - 'control-point-step-size': curvature, - 'haystack-radius': 0.4, - }) - - if (curveStyle === 'bundled') scheduleBundling(true) - else { - bundleSeq++ - clearBundles() - setStatus('bundleStatus', []) - } -} - -// Recomputes bundles shortly after the drawing changes. Repeated triggers -// within the delay collapse into one run. -export function scheduleBundling(force) { - if (!bundlingOn()) return - if (force) bundleSignature = '' - clearTimeout(bundleTimer) - bundleTimer = setTimeout(runBundling, 250) -} - -// The last computed bundles, kept so they can be re-applied cheaply when -// node sizes change (which changes which bend points fall inside nodes). -var lastBundle = null - -// Bends each edge through its bundled points. Points that fall inside the -// source or target node are left out: Cytoscape can't find where such an -// edge leaves its node and silently skips drawing it. -export function applyBundleResult() { - if (!lastBundle || !bundlingOn()) return - const { list, segs, result } = lastBundle - const keep = new Set(list.map((e) => e.id())) - cy.batch(() => { - cy.edges('.bundled').forEach((e) => { - if (!keep.has(e.id())) { - e.removeStyle(BUNDLED_STYLE_PROPS) - e.removeClass('bundled') - } - }) - list.forEach((e, k) => { - const pts = result[k] - if (!pts || e.removed()) return - const s = segs[k] - const vx = s.tx - s.sx, - vy = s.ty - s.sy - const L2 = vx * vx + vy * vy - if (L2 < 1e-9) return - const L = Math.sqrt(L2) - const srcR = e.source().outerWidth() / 2 + 3 - const tgtR = e.target().outerWidth() / 2 + 3 - const weights = [], - distances = [] - for (let i = 0; i < pts.length; i += 2) { - if (Math.hypot(pts[i] - s.sx, pts[i + 1] - s.sy) <= srcR) continue - if (Math.hypot(pts[i] - s.tx, pts[i + 1] - s.ty) <= tgtR) continue - const px = pts[i] - s.sx, - py = pts[i + 1] - s.sy - // rounded: Cytoscape's style parser rejects exponent notation (1e-15) - weights.push( - Math.round(Math.min(0.999, Math.max(0.001, (px * vx + py * vy) / L2)) * 1000) / 1000 - ) - // Cytoscape measures positive distances to the left of source->target - distances.push(Math.round(((py * vx - px * vy) / L) * 100) / 100) - } - if (!weights.length || distances.every((d) => d === 0)) { - if (e.hasClass('bundled')) { - e.removeStyle(BUNDLED_STYLE_PROPS) - e.removeClass('bundled') - } - return - } - e.style({ - 'curve-style': 'unbundled-bezier', - 'edge-distances': 'node-position', - 'control-point-weights': weights, - 'control-point-distances': distances, - }) - e.addClass('bundled') - }) - }) -} - -async function runBundling() { - if (!bundlingOn()) return - const edges = cy.edges(':visible').filter((e) => e.data('source') !== e.data('target')) - const strength = (parseFloat(document.getElementById('bundleStrength').value) || 50) / 100 - const signature = - strength + - '|' + - edges - .map((e) => { - const a = e.source().position(), - b = e.target().position() - return ( - e.id() + - ':' + - Math.round(a.x) + - ',' + - Math.round(a.y) + - ',' + - Math.round(b.x) + - ',' + - Math.round(b.y) - ) - }) - .join(';') - if (signature === bundleSignature) return - if (edges.length > BUNDLE_MAX_EDGES) { - clearBundles() - setStatus('bundleStatus', [ - { - level: 'warn', - text: `Bundling handles up to ${BUNDLE_MAX_EDGES.toLocaleString()} visible edges; this view shows ${edges.length.toLocaleString()}. Untick some channels or groups, or merge parallel edges.`, - }, - ]) - return - } - const run = ++bundleSeq - setStatus( - 'bundleStatus', - edges.length > 300 - ? [{ level: 'busy', text: `Bundling ${edges.length.toLocaleString()} edges…`, progress: 0 }] - : [] - ) - const list = edges.toArray() - const segs = list.map((e) => { - const a = e.source().position(), - b = e.target().position() - return { sx: a.x, sy: a.y, tx: b.x, ty: b.y } - }) - const result = await bundleAsync( - segs, - { - threshold: 0.85 - 0.5 * strength, - iterations: Math.round(30 + 60 * strength), - }, - (f) => { - if (run === bundleSeq && edges.length > 300) - setStatus('bundleStatus', [ - { level: 'busy', text: `Bundling ${edges.length.toLocaleString()} edges…`, progress: f }, - ]) - } - ) - if (run !== bundleSeq || !result || !bundlingOn()) return - bundleSignature = signature - lastBundle = { list, segs, result } - applyBundleResult() - setStatus('bundleStatus', []) -} - -/* edge thickness */ -export function applyEdgeWidth() { - const mode = document.getElementById('edgeWidthMode').value - document.getElementById('edgeWidthFixedRow').style.display = mode === 'fixed' ? 'block' : 'none' - document.getElementById('edgeWidthWeightRow').style.display = mode === 'weight' ? 'block' : 'none' - - if (mode === 'fixed') { - const w = parseFloat(document.getElementById('edgeWidthFixed').value) || 2 - document.getElementById('edgeWidthFixedValue').textContent = w - setStyle('edge', { width: w }) - setStyle('edge.highlighted', { width: w * 1.6 }) - } else { - const minW = parseFloat(document.getElementById('edgeWidthMin').value) || 1 - const maxW = parseFloat(document.getElementById('edgeWidthMax').value) || 8 - const knownWeights = cy - .edges() - .map((e) => e.data('weight')) - .filter((w) => typeof w === 'number' && !isNaN(w)) - const lo = knownWeights.length ? Math.min(...knownWeights) : 0 - const hi = knownWeights.length ? Math.max(...knownWeights) : 1 - cy.edges().forEach((e) => { - const w = e.data('weight') - const v = typeof w === 'number' && !isNaN(w) ? w : (lo + hi) / 2 - const width = hi === lo ? (minW + maxW) / 2 : minW + ((v - lo) / (hi - lo)) * (maxW - minW) - e.data('edgeWidth', width) - }) - setStyle('edge', { width: 'data(edgeWidth)' }) - setStyle('edge.highlighted', { width: 'data(edgeWidth)' }) - } - applyEdgeMerge() -} - -/* ============================================================ - VIEWPORT: unbounded zoom, but the network never leaves the frame - Zoom is effectively unlimited (see minZoom/maxZoom). After every pan - or zoom the view is nudged so that: - - a network smaller than the canvas stays entirely inside it, and - - a network larger than the canvas always covers it, so there is - no panning off into empty space. - The model-space bounding box of the visible nodes is cached and only - recomputed when nodes move, appear or disappear, so the check itself - is cheap enough to run on every viewport change. - ============================================================ */ -const VIEW_MARGIN = 40 - -var viewBoxCache = null - -var clampingViewport = false - -export function invalidateViewBox() { - viewBoxCache = null -} - -function visibleModelBox() { - if (!viewBoxCache) { - const nodes = cy.nodes(':visible') - viewBoxCache = nodes.length - ? nodes.boundingBox({ includeLabels: false, includeOverlays: false }) - : 'empty' - } - return viewBoxCache === 'empty' ? null : viewBoxCache -} - -function axisCorrection(lo, hi, size) { - const m = Math.min(VIEW_MARGIN, size / 4) - if (hi - lo <= size - 2 * m) { - if (lo < m) return m - lo - if (hi > size - m) return size - m - hi - return 0 - } - if (lo > m) return m - lo - if (hi < size - m) return size - m - hi - return 0 -} - -function clampViewport() { - if (clampingViewport || cy.animated()) return - const W = cy.width(), - H = cy.height() - if (!W || !H) return - const bb = visibleModelBox() - if (!bb) return - const z = cy.zoom(), - pan = cy.pan() - const dx = axisCorrection(bb.x1 * z + pan.x, bb.x2 * z + pan.x, W) - const dy = axisCorrection(bb.y1 * z + pan.y, bb.y2 * z + pan.y, H) - if (Math.abs(dx) > 0.5 || Math.abs(dy) > 0.5) { - clampingViewport = true - cy.panBy({ x: dx, y: dy }) - clampingViewport = false - } -} - -export function formatZoom(z) { - const pct = z * 100 - if (pct >= 1e5 || pct < 0.01) return pct.toExponential(0).replace('e+', 'e') + '%' - if (pct >= 100) return Math.round(pct).toLocaleString() + '%' - if (pct >= 1) return pct.toFixed(pct < 10 ? 1 : 0) + '%' - return pct.toPrecision(2) + '%' -} - -export function updateZoomReadout() { - document.getElementById('zoomLevel').textContent = formatZoom(cy.zoom()) -} - -function zoomAroundCenter(factor) { - const level = Math.min(cy.maxZoom(), Math.max(cy.minZoom(), cy.zoom() * factor)) - cy.zoom({ level, renderedPosition: { x: cy.width() / 2, y: cy.height() / 2 } }) -} - -export function fitView(eles, padding = 40) { - if (typeof net3d !== 'undefined' && net3d.active) { - fit3d(eles) - return - } - const target = eles && eles.length ? eles : cy.elements(':visible') - if (!target.length) return - cy.animate( - { fit: { eles: target, padding } }, - { duration: 400, easing: 'ease-out', complete: clampViewport } - ) -} - -/* ============================================================ - NODE SEARCH - Matches node names (and, optionally, attribute values) by substring, - exact name, prefix, suffix or regular expression. A regular expression - may be written plainly (^Rp[LS]\d+$) or with slashes and flags - (/^rp[ls]/i). Enter zooms to the matches; Escape clears. - ============================================================ */ -var searchMatches = null - -var searchTimer = null - -function attrValueStrings(attrs) { - const out = [] - Object.values(attrs || {}).forEach((v) => { - if (Array.isArray(v)) v.forEach((x) => out.push(formatAttrValue(x))) - else if (attrKind(v) !== 'empty') out.push(formatAttrValue(v)) - }) - return out -} - -// Returns { test(str) -> bool } or throws with a readable message. -function buildSearchMatcher(query, mode, matchCase) { - if (mode === 'regex') { - let pattern = query, - flags = '' - const slashed = query.match(/^\/(.*)\/([a-z]*)$/s) - if (slashed) { - pattern = slashed[1] - flags = slashed[2] - } - flags = flags.replace(/[gy]/g, '') // stateful flags would skip matches - if (!matchCase && !flags.includes('i')) flags += 'i' - let re - try { - re = new RegExp(pattern, flags) - } catch (err) { - // browsers phrase this as "Invalid regular expression: /pattern/flags: reason" - const reason = err.message.split(': ').pop() - throw new Error( - `Not a valid regular expression (${reason.charAt(0).toLowerCase() + reason.slice(1)}). Check brackets and escape special characters with \\.` - ) - } - return { test: (str) => re.test(str) } - } - const q = matchCase ? query : query.toLowerCase() - const norm = (str) => (matchCase ? str : str.toLowerCase()) - if (mode === 'exact') return { test: (str) => norm(str) === q } - if (mode === 'prefix') return { test: (str) => norm(str).startsWith(q) } - if (mode === 'suffix') return { test: (str) => norm(str).endsWith(q) } - return { test: (str) => norm(str).includes(q) } -} - -function setSearchStatus(text, isError) { - const el = document.getElementById('searchStatus') - el.textContent = text - el.classList.toggle('error', !!isError) - const badge = document.getElementById('searchBadge') - if (badge) badge.textContent = isError ? '!' : text - document.getElementById('search').setAttribute('aria-invalid', isError ? 'true' : 'false') -} - -function clearSearchHighlight() { - searchMatches = null - cy.elements().removeClass('dimmed highlighted') -} - -function runSearch() { - const input = document.getElementById('search') - const mode = document.getElementById('searchMode').value - // keep surrounding spaces in regex and exact modes; they may be intended - const query = mode === 'regex' || mode === 'exact' ? input.value : input.value.trim() - if (!query) { - clearSearchHighlight() - setSearchStatus('', false) - return - } - let matcher - try { - matcher = buildSearchMatcher(query, mode, document.getElementById('searchCase').checked) - } catch (err) { - clearSearchHighlight() - setSearchStatus(err.message, true) - return - } - const withAttrs = document.getElementById('searchAttrs').checked - const candidates = cy.nodes().filter((n) => !n.hasClass('hidden-group')) - const matched = candidates.filter( - (n) => - matcher.test(n.id()) || - (withAttrs && attrValueStrings(n.data('attrs')).some((v) => matcher.test(v))) - ) - searchMatches = matched - cy.batch(() => { - cy.elements().removeClass('highlighted').addClass('dimmed') - matched.removeClass('dimmed').addClass('highlighted') - matched.connectedEdges().removeClass('dimmed') - }) - setSearchStatus( - matched.length - ? `${matched.length.toLocaleString()} of ${candidates.length.toLocaleString()}` - : 'No matches', - false - ) -} - -function scheduleSearch() { - clearTimeout(searchTimer) - searchTimer = setTimeout(runSearch, cy.nodes().length > 2000 ? 200 : 60) -} - -/* node click -> info panel */ -export function hideInfo() { - document.getElementById('infopanel').classList.remove('show') -} - -function setInfoDesc(text) { - const el = document.getElementById('infoDesc') - el.textContent = text || '' - el.style.display = text ? 'block' : 'none' -} - -/* group inspector: reuses the node info panel for a whole group */ -export function showGroupInfo(g) { - hideEdgePopup() - const members = cy.nodes().filter((n) => (n.data('groups') || []).includes(g)) - const memberIds = new Set(members.map((n) => n.id())) - - let internalEdges = 0, - boundaryEdges = 0 - const internalPairs = new Set() - const internal = cy.collection() - cy.edges().forEach((e) => { - const s = e.data('source'), - t = e.data('target') - const inS = memberIds.has(s), - inT = memberIds.has(t) - if (inS && inT) { - internalEdges++ - internal.merge(e) - if (s !== t) internalPairs.add(s < t ? s + '|' + t : t + '|' + s) - } else if (inS || inT) { - boundaryEdges++ - } - }) - const k = members.length - const density = k > 1 ? internalPairs.size / ((k * (k - 1)) / 2) : 0 - - const overlaps = {} - members.forEach((n) => - (n.data('groups') || []).forEach((o) => { - if (o !== g) overlaps[o] = (overlaps[o] || 0) + 1 - }) - ) - const sharedCount = members.filter((n) => (n.data('groups') || []).length > 1).length - - cy.elements().removeClass('highlighted').addClass('dimmed') - members.removeClass('dimmed').addClass('highlighted') - internal.removeClass('dimmed') - - document.getElementById('infoDots').innerHTML = - `` - document.getElementById('infoName').textContent = groupLabel(g) - document.getElementById('infoExplore').hidden = true - document.getElementById('infoSub').textContent = - groupLabel(g) === g ? `group · ${k} members` : `group "${g}" · ${k} members` - setInfoDesc(groupDescription(g)) - - const stat = (label, value) => - `
    ${label}${value}
    ` - document.getElementById('infoMetrics').innerHTML = - stat('Shared', sharedCount) + - stat('Density', density.toFixed(3)) + - stat('Inside', internalEdges) + - stat('Outgoing', boundaryEdges) - - const custom = customGroupAttrs(g) - const currentShape = S.groupShapes[g] || 'ellipse' - document.getElementById('infoAttrs').innerHTML = - '
    Node shape for this group
    ' + - NODE_SHAPES.map( - ([key, name]) => - `` - ).join('') + - '
    ' + - (Object.keys(custom).length - ? '
    Group attributes
    ' + attrRowsHtml(custom, 'kvrow') - : '') - document.querySelectorAll('#infoAttrs .shape-opt').forEach((btn) => { - btn.addEventListener('click', () => { - setGroupShape(g, btn.dataset.shape) - document - .querySelectorAll('#infoAttrs .shape-opt') - .forEach((b) => b.setAttribute('aria-selected', b === btn ? 'true' : 'false')) - }) - }) - - const overlapEntries = Object.entries(overlaps).sort((a, b) => - byName(groupLabel(a[0]), groupLabel(b[0])) - ) - const connEl = document.getElementById('infoConns') - connEl.innerHTML = overlapEntries.length - ? '
    Shares members with
    ' + - overlapEntries - .map( - ([o, c]) => ` -
    - ${escapeHtml(groupLabel(o))}${c} ${c === 1 ? 'node' : 'nodes'} -
    ` - ) - .join('') - : '
    No members shared with other groups
    ' - connEl.querySelectorAll('.conn.jump').forEach((row) => { - const go = () => showGroupInfo(row.dataset.group) - row.addEventListener('click', go) - row.addEventListener('keydown', (ev) => { - if (ev.key === 'Enter' || ev.key === ' ') { - ev.preventDefault() - go() - } - }) - }) - - document.getElementById('infopanel').classList.add('show') -} - -/* edge click -> popup */ -export function hideEdgePopup() { - document.getElementById('edgePopup').classList.remove('show') -} - -/* ============================================================ - GROUP SHAPES - Each group can have a node shape. A node takes its group's shape only - when exactly one of its groups is currently ticked; nodes showing two - or more active groups stay circular so their pie slices remain - readable. Unticking groups therefore changes which shape a node shows. - ============================================================ */ -function polyPoints(n, r, rot = -Math.PI / 2, cx = 8, cy = 8) { - return Array.from({ length: n }, (_, i) => { - const a = rot + (2 * Math.PI * i) / n - return `${(cx + r * Math.cos(a)).toFixed(2)},${(cy + r * Math.sin(a)).toFixed(2)}` - }).join(' ') -} - -function starPoints() { - return Array.from({ length: 10 }, (_, i) => { - const a = -Math.PI / 2 + (Math.PI * i) / 5 - const r = i % 2 ? 3 : 7 - return `${(8 + r * Math.cos(a)).toFixed(2)},${(8.6 + r * Math.sin(a)).toFixed(2)}` - }).join(' ') -} - -// [cytoscape shape, name, svg markup inside a 16x16 box] -var NODE_SHAPES = [ - ['ellipse', 'Circle', ''], - ['rectangle', 'Square', ''], - ['round-rectangle', 'Rounded square', ''], - ['diamond', 'Diamond', ''], - ['triangle', 'Triangle', ''], - ['vee', 'Vee', ''], - ['pentagon', 'Pentagon', ``], - ['hexagon', 'Hexagon', ``], - ['octagon', 'Octagon', ``], - ['star', 'Star', ``], - ['rhomboid', 'Rhomboid', ''], - ['tag', 'Tag', ''], - ['concave-hexagon', 'Concave hexagon', ''], - ['barrel', 'Barrel', ''], -] - -export var SHAPE_BY_KEY = Object.fromEntries(NODE_SHAPES.map((s) => [s[0], s])) - -export function shapeSvg(key) { - const s = SHAPE_BY_KEY[key] || SHAPE_BY_KEY.ellipse - return `` -} - -// The shape a node should show given its currently active groups. -export function nodeShapeFor(effectiveGroups) { - return effectiveGroups.length === 1 ? S.groupShapes[effectiveGroups[0]] || 'ellipse' : 'ellipse' -} - -function setGroupShape(g, shape) { - if (!shape || shape === 'ellipse') delete S.groupShapes[g] - else S.groupShapes[g] = shape - cy.batch(() => cy.nodes().forEach((n) => refreshNodeVisual(n))) - buildGroupLegend() -} - -function assignDistinctShapes() { - const choices = NODE_SHAPES.map((s) => s[0]).filter((k) => k !== 'ellipse') - const groups = typeof filteredGroups === 'function' ? filteredGroups() : getUsedGroups() - groups.forEach((g, i) => { - S.groupShapes[g] = choices[i % choices.length] - }) - cy.batch(() => cy.nodes().forEach((n) => refreshNodeVisual(n))) - buildGroupLegend() -} - -function resetShapes() { - const groups = typeof filteredGroups === 'function' ? filteredGroups() : getUsedGroups() - groups.forEach((g) => { - delete S.groupShapes[g] - }) - cy.batch(() => cy.nodes().forEach((n) => refreshNodeVisual(n))) - buildGroupLegend() -} - -/* shape chooser popover, shared by all group rows */ -function positionShapePopover() { - const pop = document.getElementById('shapePopover') - if (pop.hidden || !shapePopoverAnchor) return - const r = shapePopoverAnchor.getBoundingClientRect() - const side = document.getElementById('sidebar').getBoundingClientRect() - if (!document.body.contains(shapePopoverAnchor) || r.bottom < side.top || r.top > side.bottom) { - closeShapePopover(false) - return - } - const w = pop.offsetWidth, - h = pop.offsetHeight - pop.style.left = Math.min(window.innerWidth - w - 8, Math.max(8, r.left)) + 'px' - pop.style.top = - (r.bottom + 4 + h > window.innerHeight ? Math.max(8, r.top - h - 4) : r.bottom + 4) + 'px' -} - -export let shapePopoverGroup = null - -let shapePopoverAnchor = null - -export function closeShapePopover(returnFocus) { - const pop = document.getElementById('shapePopover') - if (pop.hidden) return - pop.hidden = true - if (returnFocus && shapePopoverAnchor && document.body.contains(shapePopoverAnchor)) - shapePopoverAnchor.focus() - shapePopoverGroup = null - shapePopoverAnchor = null -} - -export function openShapePopover(g, anchor) { - const pop = document.getElementById('shapePopover') - shapePopoverGroup = g - shapePopoverAnchor = anchor - const current = S.groupShapes[g] || 'ellipse' - pop.innerHTML = - `
    Shape for ${escapeHtml(groupLabel(g))}
    ` + - NODE_SHAPES.map( - ([key, name]) => - `` - ).join('') + - '
    ' - pop.hidden = false - positionShapePopover() - const opts = [...pop.querySelectorAll('.shape-opt')] - opts.forEach((btn, i) => { - btn.addEventListener('click', () => { - setGroupShape(g, btn.dataset.shape) - closeShapePopover(false) - }) - btn.addEventListener('keydown', (e) => { - const cols = 7 - let j = i - if (e.key === 'ArrowRight') j = i + 1 - else if (e.key === 'ArrowLeft') j = i - 1 - else if (e.key === 'ArrowDown') j = i + cols - else if (e.key === 'ArrowUp') j = i - cols - else if (e.key === 'Escape') { - e.preventDefault() - closeShapePopover(true) - return - } else return - e.preventDefault() - opts[(j + opts.length) % opts.length].focus() - }) - }) - ;(pop.querySelector('[aria-selected="true"]') || opts[0]).focus() -} - -/* ============================================================ - VIEWS - A view is one network visualization with everything that belongs to - it: the data on the canvas, which library files it was built from, - every Display setting, node positions, zoom and pan, which groups and - channels are ticked, and group and channel colors. The theme and the - search options are app-wide and are not part of a view. - Only the active view lives on the canvas; switching saves it into its - record and rebuilds the other one from its record. - ============================================================ */ -const APP_WIDE_SETTINGS = new Set(['themeSelect', 'searchMode', 'searchCase', 'searchAttrs']) - -export const views = [] - -export function viewSettings() { - const cfg = getCurrentConfig() - APP_WIDE_SETTINGS.forEach((k) => delete cfg[k]) - return cfg -} - -// Writes settings into the controls without side effects; callers refresh. -export function setControls(cfg) { - CONFIG_FIELDS.forEach(({ id, prop }) => { - if (!cfg || !(id in cfg) || APP_WIDE_SETTINGS.has(id)) return - const el = document.getElementById(id) - if (!el) return - if (prop === 'checked') el.checked = !!cfg[id] - else el.value = cfg[id] - }) -} - -// The canvas contents in loadData's JSON shape (the same shape Save JSON writes). -export function snapshotData() { - if (!cy.nodes().length) return null - const nodeColors = {} - Object.entries(S.nodeColorMap).forEach(([g, c]) => { - if (g !== UNGROUPED) nodeColors[g] = c - }) - const edgeColors = {} - cy.edges().forEach((e) => { - edgeColors[e.data('type')] = e.data('color') - }) - return { - nodes: cy.nodes().map((n) => ({ - id: n.id(), - groups: (n.data('groups') || []).filter((g) => g !== UNGROUPED), - size: n.data('baseSize'), - ...(n.data('nodeColor') ? { color: n.data('nodeColor') } : {}), - ...(n.data('values') ? { values: n.data('values') } : {}), - ...(n.data('attrs') || {}), - })), - edges: cy.edges().map((e) => { - const out = { - id: e.id(), - source: e.data('source'), - target: e.data('target'), - type: e.data('type'), - } - if (typeof e.data('weight') === 'number') out.weight = e.data('weight') - if (e.data('directed')) out.directed = true - return { ...out, ...(e.data('attrs') || {}) } - }), - nodeColors, - edgeColors, - groupOrder: getUsedGroups().filter((g) => g !== UNGROUPED), - ...(Object.keys(S.groupShapes).length ? { groupShapes: { ...S.groupShapes } } : {}), - ...(Object.keys(S.groupAttrs).length ? { groupAttrs: { ...S.groupAttrs } } : {}), - ...(legendExtra ? { legendExtra } : {}), - } -} - -export function selectionFromKey(key) { - return { - networks: key && key.nets ? key.nets.split('|').filter(Boolean) : [], - annotation: key ? key.annotation || '' : '', - colors: key ? key.colors || '' : '', - } -} - -export function activeView() { - return views.find((v) => v.id === S.activeViewId) || null -} - -export function captureActiveView() { - const v = activeView() - if (!v) return - flushHistory() - cancelFrJobs() - S.layoutRunSeq++ - const positions = {} - cy.nodes().forEach((n) => { - const p = n.position() - positions[n.id()] = { x: p.x, y: p.y } - }) - const typeColors = {} - getUsedTypes().forEach((t) => { - if (EDGE_TYPES[t]) typeColors[t] = EDGE_TYPES[t].color - }) - v.data = snapshotData() - v.selection = { - networks: [...libSelection.networks], - annotation: libSelection.annotation, - colors: libSelection.colors, - } - v.state = { - config: viewSettings(), - positions, - zoom: cy.zoom(), - pan: { ...cy.pan() }, - activeGroups: [...S.activeGroups], - activeTypes: [...S.activeTypes], - groupColors: { ...S.nodeColorMap }, - typeColors, - libView: S.currentLibView ? { ...S.currentLibView } : null, - spread: parseFloat(document.getElementById('spreadSlider').value) || 0, - groupFilter: document.getElementById('groupFilter').value, - status: document.getElementById('normaStatus').innerHTML, - view3d: capture3d(), - } -} - -export function clearCanvas() { - bumpDataVersion() - cancelFrJobs() - S.layoutRunSeq++ - cy.elements().remove() - document.getElementById('edgeLegend').innerHTML = '' - document.getElementById('nodeGroupLegend').innerHTML = '' - Object.keys(EDGE_TYPES).forEach((k) => { - if (ORIGINAL_EDGE_TYPES[k]) EDGE_TYPES[k] = { ...ORIGINAL_EDGE_TYPES[k] } - else delete EDGE_TYPES[k] - }) - S.autoEdgeIdx = 0 - S.nodeColorMap = {} - S.groupShapes = {} - S.groupAttrs = {} - S.activeGroups = new Set() - invalidateFullMetrics() - buildAttrSchema() - renderAttrSchema() - buildGroupLegend() - updateStats() - hideInfo() - hideEdgePopup() - S.currentLibView = null - drawGroupHulls() -} - -// With reuseData, the network already on the canvas is kept and only the -// view's look and positions are put back (used by undo/redo). -export function restoreView(v, { reuseData = false } = {}) { - const st = v.state || {} - setControls(st.config || S.DEFAULT_VIEW_CONFIG) - document.getElementById('groupFilter').value = st.groupFilter || '' - if (reuseData) { - cancelFrJobs() - S.layoutRunSeq++ - setLayoutBusy(false) - } else if (v.data) { - loadData(v.data, { positions: st.positions || null }) - } else { - clearCanvas() - } - // some choices (e.g. an edge attribute as label text) only exist once - // the view's data is loaded, so apply the settings again - if (v.data) setControls(st.config || S.DEFAULT_VIEW_CONFIG) - refreshAllDerivedUI() - if (v.data) { - if (st.groupColors) { - S.nodeColorMap = {} - Object.entries(st.groupColors).forEach(([g, c]) => { - const sc = sanitizeColor(c) - if (sc) S.nodeColorMap[g] = sc - }) - } - if (st.typeColors) { - Object.entries(st.typeColors).forEach(([t, c]) => { - const sc = sanitizeColor(c) - if (!sc) return - if (EDGE_TYPES[t]) EDGE_TYPES[t].color = sc - else EDGE_TYPES[t] = { color: sc, label: t } - }) - cy.edges().forEach((e) => { - const m = EDGE_TYPES[e.data('type')] - if (m) e.data('color', m.color) - }) - } - const used = new Set(getUsedGroups()) - if (st.activeGroups) S.activeGroups = new Set(st.activeGroups.filter((g) => used.has(g))) - const usedTypes = getUsedTypes() - if (st.activeTypes) S.activeTypes = new Set(st.activeTypes.filter((t) => usedTypes.includes(t))) - buildGroupLegend() - buildLegend(usedTypes) - applyGroupVisibility() - applyTypeVisibility() - if (reuseData && st.positions) { - cy.batch(() => - cy.nodes().forEach((n) => { - const p = st.positions[n.id()] - if (p) n.position(p) - }) - ) - invalidateViewBox() - } - if (!reuseData && st.positions && typeof st.zoom === 'number') { - cy.viewport({ zoom: st.zoom, pan: st.pan }) - } - } - restore3d(st.view3d) - spreadApplied = st.spread || 0 - spreadBase = st.spreadBase ? { ...st.spreadBase } : null - document.getElementById('spreadSlider').value = spreadApplied - updateSpreadReadout() - - const sel = v.selection || { networks: [], annotation: '', colors: '' } - libSelection.networks = new Set(sel.networks.filter((id) => libEntry('network', id))) - libSelection.annotation = libEntry('annotation', sel.annotation) ? sel.annotation : '' - libSelection.colors = libEntry('colors', sel.colors) ? sel.colors : '' - S.currentLibView = st.libView || null - renderLibraryLists() - if (!reuseData) document.getElementById('normaStatus').innerHTML = st.status || '' - updateStats() - invalidateViewBox() - drawGroupHulls() - cy.elements().removeClass('dimmed highlighted') - if (document.getElementById('search').value) runSearch() - if (v.needsRefresh && !reuseData) refreshAfterDelete(v) -} - -export function uniqueViewName(base) { - const taken = new Set(views.map((v) => v.name)) - if (!taken.has(base)) return base - let n = 2 - while (taken.has(`${base} ${n}`)) n++ - return `${base} ${n}` -} - -export function renderViewBar() { - const sel = document.getElementById('viewSelect') - sel.innerHTML = '' - views.forEach((v) => sel.add(new Option(v.name, v.id))) - sel.value = S.activeViewId - document.getElementById('viewCount').textContent = - views.length > 1 ? `${views.length} views open` : '' - if (typeof updateContextInfo === 'function') updateContextInfo() -} - -// Creates a view and makes it active. With `copy`, it starts as a copy of -// the current view; otherwise it starts empty with default settings. -export function createView(name, { copy = false } = {}) { - captureActiveView() - const from = activeView() - const v = { - id: 'view' + ++S.viewSeq, - name: uniqueViewName(name || 'Untitled view'), - autoName: !name || name === 'Untitled view', - data: copy && from ? from.data : null, - selection: - copy && from - ? { ...from.selection, networks: [...from.selection.networks] } - : { networks: [], annotation: '', colors: '' }, - state: - copy && from - ? JSON.parse(JSON.stringify(from.state)) - : { config: { ...S.DEFAULT_VIEW_CONFIG } }, - } - views.push(v) - S.activeViewId = v.id - S.historySuspended++ - try { - restoreView(v) - } finally { - S.historySuspended-- - } - setHistoryBaseline() - renderViewBar() - return v -} - -export function switchView(id) { - if (id === S.activeViewId || !views.some((v) => v.id === id)) return - captureActiveView() - S.activeViewId = id - S.historySuspended++ - try { - restoreView(activeView()) - } finally { - S.historySuspended-- - } - S.dataCache = { version: dataVersion, data: activeView().data } - setHistoryBaseline() - renderViewBar() - updateUndoButtons() -} - -export function closeActiveView() { - const idx = views.findIndex((v) => v.id === S.activeViewId) - if (idx < 0) return - views.splice(idx, 1) - if (!views.length) { - S.activeViewId = null - createView('Untitled view') - return - } - S.activeViewId = views[Math.max(0, idx - 1)].id - S.historyGestureOpen = false - clearTimeout(historyTimer) - S.historySuspended++ - try { - restoreView(activeView()) - } finally { - S.historySuspended-- - } - S.dataCache = { version: dataVersion, data: activeView().data } - setHistoryBaseline() - renderViewBar() - updateUndoButtons() -} - -// Runs `load` in a view of its own. An untouched empty view is reused -// rather than leaving it behind. -export function openInNewView(name, load) { - const cur = activeView() - if (cur && !cy.nodes().length && cur.autoName !== false && !cur.data) { - cur.name = uniqueViewName(name) - cur.autoName = false - setControls(S.DEFAULT_VIEW_CONFIG) - refreshAllDerivedUI() - } else { - createView(name) - activeView().autoName = false - } - S.historySuspended++ - try { - load() - } finally { - S.historySuspended-- - } - setHistoryBaseline() - renderViewBar() - updateUndoButtons() -} - -export function nameForSelection() { - const nets = selectedNetworks() - const ann = libEntry('annotation', libSelection.annotation) - const base = - nets.length === 1 ? nets[0].name : nets.length ? `${nets.length} networks` : 'Untitled view' - return ann ? `${base}, ${ann.name}` : base -} - -// page wiring, run by main.ts in the original order -export function init() { - document.getElementById('btnProfile').addEventListener('click', runProfiler) - - document.getElementById('btnProfileTsv').addEventListener('click', profilerTsv) - - // statistic definitions in the Help tab come from the same table - document.getElementById('helpStatsRows').innerHTML = PROFILE_STATS.map( - (st) => `${escapeHtml(st.label)}${escapeHtml(st.desc)}` - ).join('') - - ;[ - 'showNodeLabels', - 'showEdgeLabels', - 'labelPosition', - 'labelScaleWithNode', - 'edgeLabelContent', - 'edgeLabelOrientation', - 'labelMinScreenSize', - ].forEach((id) => { - document.getElementById(id).addEventListener('change', updateLabelStyle) - }) - - ;['nodeLabelSize', 'edgeLabelSize'].forEach((id) => { - document.getElementById(id).addEventListener('input', updateLabelStyle) - }) - - document.getElementById('edgeOpacity').addEventListener('input', applyEdgeOpacity) - - document.getElementById('spreadSlider').addEventListener('input', queueSpread) - - document.getElementById('spreadSlider').addEventListener('change', () => { - const v = parseFloat(document.getElementById('spreadSlider').value) || 0 - if (spreadFrame) { - cancelAnimationFrame(spreadFrame) - spreadFrame = 0 - } - if (v !== spreadApplied || cy.nodes().length > SPREAD_LIVE_MAX) applySpread() - scheduleBundling() - }) - - document.getElementById('spreadSlider').addEventListener('dblclick', () => { - document.getElementById('spreadSlider').value = 0 - applySpread() - }) - - cy.on('layoutstart', resetSpread) - - document.getElementById('edgeCurveStyle').addEventListener('change', applyEdgeCurveStyle) - - document.getElementById('edgeCurvature').addEventListener('input', applyEdgeCurveStyle) - - document.getElementById('bundleStrength').addEventListener('input', () => { - document.getElementById('bundleStrengthValue').textContent = - document.getElementById('bundleStrength').value + '%' - }) - - document.getElementById('bundleStrength').addEventListener('change', () => scheduleBundling(true)) - - cy.on('layoutstop dragfree', () => scheduleBundling()) - - document.getElementById('edgeMergeMode').addEventListener('change', applyEdgeMerge) - - document.getElementById('edgeWidthMode').addEventListener('change', applyEdgeWidth) - - document.getElementById('edgeWidthFixed').addEventListener('input', applyEdgeWidth) - - document.getElementById('edgeWidthMin').addEventListener('change', applyEdgeWidth) - - document.getElementById('edgeWidthMax').addEventListener('change', applyEdgeWidth) - - /* node fill mode */ - document.getElementById('nodeFillSelect').addEventListener('change', () => { - if (nodeFillMode() === 'values') applyValueColors() - cy.batch(() => cy.nodes().forEach((n) => refreshNodeVisual(n))) - scheduleLegend() - updateContextInfo() - }) - - /* color palettes */ - document - .getElementById('nodePaletteSelect') - .addEventListener('change', (e) => applyNodePalette(e.target.value)) - - document - .getElementById('edgePaletteSelect') - .addEventListener('change', (e) => applyEdgePalette(e.target.value)) - - /* node size by centrality */ - ;['sizeMetric', 'sizeChannelOnly'].forEach((id) => { - document.getElementById(id).addEventListener('change', applyNodeSizing) - }) - - document.getElementById('sizeMin').addEventListener('change', applyNodeSizing) - - document.getElementById('sizeMax').addEventListener('change', applyNodeSizing) - - document.getElementById('nodeScale').addEventListener('input', applyNodeSizing) - - cy.on('viewport', () => { - clampViewport() - updateZoomReadout() - }) - - cy.on('position add remove', invalidateViewBox) - - cy.on('style data', 'node', invalidateViewBox) - - cy.on('dragfree layoutstop', () => { - invalidateViewBox() - clampViewport() - }) - - window.addEventListener('resize', () => { - invalidateViewBox() - clampViewport() - }) - - document.getElementById('zoomIn').addEventListener('click', () => zoomAroundCenter(1.25)) - - document.getElementById('zoomOut').addEventListener('click', () => zoomAroundCenter(0.8)) - - document.getElementById('zoomFit').addEventListener('click', () => fitView()) - - document.getElementById('search').addEventListener('input', scheduleSearch) - - ;['searchMode', 'searchCase', 'searchAttrs'].forEach((id) => { - document.getElementById(id).addEventListener('change', runSearch) - }) - - document.getElementById('search').addEventListener('keydown', (e) => { - if (e.key === 'Enter') { - e.preventDefault() - clearTimeout(searchTimer) - runSearch() - if (searchMatches && searchMatches.length) fitView(searchMatches, 80) - } else if (e.key === 'Escape') { - e.target.value = '' - runSearch() - } - }) - - document.getElementById('searchMode').addEventListener('change', (e) => { - document.getElementById('search').placeholder = - { - contains: 'Find nodes', - exact: 'Exact node name', - prefix: 'Name starts with…', - suffix: 'Name ends with…', - regex: 'e.g. ^Rp[LS]\\d+ or /kinase$/i', - }[e.target.value] || 'Find nodes' - }) - - cy.on('tap', 'node', (evt) => { - const node = evt.target - hideEdgePopup() - cy.elements().removeClass('highlighted') - cy.elements().addClass('dimmed') - node.removeClass('dimmed').addClass('highlighted') - const neigh = node.closedNeighborhood() - neigh.removeClass('dimmed') - node.connectedEdges().addClass('highlighted') - - const panel = document.getElementById('infopanel') - const groupsArr = node.data('groups') || [UNGROUPED] - document.getElementById('infoDots').innerHTML = groupsArr - .map((g) => ``) - .join('') - document.getElementById('infoName').textContent = node.data('id') - const groupLinks = groupsArr - .map( - (g) => - `` - ) - .join(' + ') - const subEl = document.getElementById('infoSub') - subEl.innerHTML = `${groupLinks} · ${node.connectedEdges().length} edges · ${node.neighborhood('node').length} neighbors` - subEl - .querySelectorAll('.glink') - .forEach((b) => b.addEventListener('click', () => showGroupInfo(b.dataset.group))) - setInfoDesc('') - - const nid = node.id() - const m = ensureFullMetrics() - const nodeDirected = node.connectedEdges().some((e) => edgeIsDirected(e)) - document.getElementById('infoMetrics').innerHTML = ` -
    Degree${m.degree[nid] || 0}
    - ${nodeDirected ? `
    In / out${m.indegree[nid] || 0} / ${m.outdegree[nid] || 0}
    ` : ''} -
    Betweenness${(m.betweenness[nid] || 0).toFixed(3)}
    -
    Closeness${(m.closeness[nid] || 0).toFixed(3)}
    -
    Clustering${(m.clustering[nid] || 0).toFixed(3)}
    - ` - - const attrs = { - ...(node.data('nodeColor') ? { color: node.data('nodeColor') } : {}), - ...(node.data('attrs') || {}), - } - document.getElementById('infoAttrs').innerHTML = Object.keys(attrs).length - ? '
    Node attributes
    ' + attrRowsHtml(attrs, 'kvrow') - : '' - - const connsByNeighbor = {} - node.connectedEdges().forEach((e) => { - const outgoing = e.source().id() === node.id() - const other = outgoing ? e.target().id() : e.source().id() - connsByNeighbor[other] = connsByNeighbor[other] || [] - const meta = EDGE_TYPES[e.data('type')] || { label: e.data('type') } - const arrow = edgeIsDirected(e) ? (outgoing ? '→ ' : '← ') : '' - connsByNeighbor[other].push(arrow + meta.label) - }) - const connEl = document.getElementById('infoConns') - connEl.innerHTML = - (nodeDirected - ? '
    → outgoing · ← incoming
    ' - : '') + - Object.entries(connsByNeighbor) - .sort((a, b) => byName(a[0], b[0])) - .map( - ([other, types]) => ` -
    ${escapeHtml(other)}${escapeHtml(types.join(', '))}
    - ` - ) - .join('') - - S.infoNodeId = node.id() - document.getElementById('infoExplore').hidden = false - panel.classList.add('show') - }) - - cy.on('tap', 'edge', (evt) => { - const edge = evt.target - hideInfo() - cy.elements().removeClass('highlighted') - cy.elements().addClass('dimmed') - edge.removeClass('dimmed').addClass('highlighted') - edge.connectedNodes().removeClass('dimmed') - - const meta = EDGE_TYPES[edge.data('type')] || { - color: edge.data('color'), - label: edge.data('type'), - } - document.getElementById('epDot').style.background = meta.color - document.getElementById('epType').textContent = meta.label - document.getElementById('epSource').textContent = edge.data('source') - document.getElementById('epTarget').textContent = edge.data('target') - document.getElementById('epId').textContent = edge.data('id') - document.getElementById('epDirection').textContent = edgeIsDirected(edge) - ? `${edge.data('source')} → ${edge.data('target')}` - : 'undirected' - - const weight = edge.data('weight') - const attrs = edge.data('attrs') || {} - const rows = [] - if (typeof weight === 'number') - rows.push(`
    weight${weight}
    `) - rows.push(attrRowsHtml(attrs, 'eprow')) - const merged = edge.data('mergedWith') - if (merged && merged.length > 1) { - rows.push( - `
    Merged channels${merged.length}
    ` - ) - merged.forEach((id) => { - const other = cy.getElementById(id) - if (!other.length) return - const m = EDGE_TYPES[other.data('type')] || { label: other.data('type') } - const w = other.data('weight') - rows.push( - `
    ${escapeHtml(m.label)}${typeof w === 'number' ? escapeHtml(formatAttrValue(w)) : ''}
    ` - ) - }) - } - document.getElementById('epExtra').innerHTML = rows.join('') - - const canvasRect = document.getElementById('canvas').getBoundingClientRect() - const pos = evt.renderedPosition || { x: canvasRect.width / 2, y: canvasRect.height / 2 } - const popup = document.getElementById('edgePopup') - const left = Math.min(pos.x + 14, canvasRect.width - 266) - const top = Math.min(pos.y + 14, canvasRect.height - 180) - popup.style.left = Math.max(10, left) + 'px' - popup.style.top = Math.max(10, top) + 'px' - popup.classList.add('show') - }) - - document.getElementById('edgePopupClose').addEventListener('click', () => { - cy.elements().removeClass('dimmed highlighted') - hideEdgePopup() - }) - - cy.on('tap', (evt) => { - if (evt.target === cy) { - cy.elements().removeClass('dimmed highlighted') - hideInfo() - hideEdgePopup() - } - }) - - /* double-click to recenter */ - cy.on('dbltap', (evt) => { - if (evt.target === cy) { - fitView() - } - }) - - cy.on('dbltap', 'node', (evt) => { - cy.animate( - { center: { eles: evt.target } }, - { duration: 300, easing: 'ease-out', complete: clampViewport } - ) - }) - - document.getElementById('infoClose').addEventListener('click', () => { - cy.elements().removeClass('dimmed highlighted') - hideInfo() - }) - - /* theme */ - document - .getElementById('themeSelect') - .addEventListener('change', (e) => applyTheme(e.target.value)) - - /* group highlighting (hulls / fog clouds) */ - cy.on('render', drawGroupHulls) - - // The WebGL renderer does not emit 'render', so the shading follows the - // changes that move or restyle nodes instead (once per frame). - if (WEBGL_ACTIVE) { - let hullQueued = false - const queueHulls = () => { - if (hullQueued) return - hullQueued = true - requestAnimationFrame(() => { - hullQueued = false - drawGroupHulls() - }) - } - cy.on('viewport position add remove data style class resize layoutstop', queueHulls) - } - - document.getElementById('showGroupHulls').addEventListener('change', (e) => { - document.getElementById('hullControls').style.display = e.target.checked ? 'block' : 'none' - drawGroupHulls() - }) - - document.getElementById('hullStyle').addEventListener('change', drawGroupHulls) - - document.getElementById('hullOpacity').addEventListener('input', (e) => { - document.getElementById('hullOpacityValue').textContent = e.target.value - drawGroupHulls() - }) - - document.addEventListener('mousedown', (e) => { - const pop = document.getElementById('shapePopover') - if (!pop.hidden && !pop.contains(e.target) && !e.target.closest('.gshape')) - closeShapePopover(false) - }) - - document.getElementById('sidebar').addEventListener('scroll', positionShapePopover) - - window.addEventListener('resize', positionShapePopover) - - document.getElementById('btnShapesAssign').addEventListener('click', assignDistinctShapes) - - document.getElementById('btnShapesReset').addEventListener('click', resetShapes) -} diff --git a/frontend/src/recording.ts b/frontend/src/recording.ts deleted file mode 100644 index 79dbb8c..0000000 --- a/frontend/src/recording.ts +++ /dev/null @@ -1,291 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { S } from './state' -import { UNGROUPED, escapeHtml, getUsedGroups, nodeFillMode } from './network_state' -import { activeView, fitView } from './profiler' -import { currentTab } from './wiring' -import { cy } from './cy' -import { - historyTimer, - noteChange, - redo, - scheduleSettle, - setHistoryBaseline, - undo, -} from './demo_downloads' -import { libEntry, libSelection, normaLibrary, renderLibraryLists } from './layouts/controls' -import { refreshLibraryView } from './library' -import { sortedByName } from './hulls' -import { updateStats } from './metrics' -import { updateStringUI } from './string/ui_state' - -/* ---------- what gets recorded ---------- */ -const panelDisplayEl = document.getElementById('panelDisplay') - -function typingInField(target) { - if (!target) return false - if (target.isContentEditable) return true - if (target.tagName === 'TEXTAREA') return true - if (target.tagName === 'INPUT') { - const t = (target.type || '').toLowerCase() - return !['checkbox', 'radio', 'range', 'button', 'color', 'file'].includes(t) - } - return false -} - -/* ============================================================ - MULTIPLE SELECTION - Shift/Ctrl/Cmd-click adds or removes nodes, Shift-drag on the - background draws a selection box, Ctrl/Cmd+A selects every visible - node, Escape clears. Selected nodes get a thick border and a halo; - dragging one moves them all. - ============================================================ */ -let selectionUpdateQueued = false - -function updateSelectionBar() { - selectionUpdateQueued = false - const nodes = cy.nodes(':selected').length - const edges = cy.edges(':selected').length - const bar = document.getElementById('selectionBar') - bar.hidden = nodes + edges < 2 && !(nodes === 1 && edges > 0) - if (bar.hidden) return - const parts = [] - if (nodes) parts.push(`${nodes.toLocaleString()} node${nodes === 1 ? '' : 's'}`) - if (edges) parts.push(`${edges.toLocaleString()} edge${edges === 1 ? '' : 's'}`) - document.getElementById('selectionText').textContent = `${parts.join(' and ')} selected` - document.getElementById('btnSelPaths').hidden = nodes !== 2 - document.getElementById('btnSelNeighbours').hidden = !nodes -} - -/* ============================================================ - CONTEXT LINE: what the current view shows - Network, grouping and node colors of the active view, shown next to - the page tabs so they stay visible on every page. - ============================================================ */ -function contextChip(tint, label, value, title) { - return `${escapeHtml(label)}${escapeHtml(value)}` -} - -// Grouping choices for the current view: every annotation in the file -// library when the view was built from files, otherwise the groups that -// came with the data. -let groupingSelectKey = '' - -export function renderGroupingSelect() { - const sel = document.getElementById('viewGrouping') - if (!sel) return - const lib = S.currentLibView - const groupCount = getUsedGroups().filter((g) => g !== UNGROUPED).length - let options, value, disabled, title - if (lib) { - options = [['', 'None']].concat( - sortedByName(normaLibrary.annotation, (e) => e.name).map((e) => [ - e.id, - `${e.name} (${e.parsed.summary})`, - ]) - ) - value = lib.annotation || '' - disabled = false - title = 'Group the nodes of this view by another annotation. Node positions are kept.' - } else if (cy.nodes().length) { - options = [ - ['data', groupCount ? `From the data (${groupCount} groups)` : 'No groups in the data'], - ] - value = 'data' - disabled = true - title = - 'This view was opened from a built-in demo or a JSON file, so its groups come with the data. Views opened from network files can switch annotations here.' - } else { - options = [['', 'No network shown']] - value = '' - disabled = true - title = 'Open an example or files first.' - } - const key = JSON.stringify([options, value, disabled]) - if (key === groupingSelectKey) { - updateGroupingDelete() - return - } - groupingSelectKey = key - sel.innerHTML = '' - options.forEach(([v, t]) => sel.add(new Option(t, v))) - sel.value = value - sel.disabled = disabled - sel.title = title - updateGroupingDelete() -} - -function updateGroupingDelete() { - const btn = document.getElementById('btnGroupingDelete') - if (!btn) return - const id = S.currentLibView && S.currentLibView.annotation - const e = id && libEntry('annotation', id) - btn.disabled = !e - btn.title = e ? `Completely remove the grouping "${e.name}"` : 'No grouping file to remove' -} - -export function updateContextInfo() { - renderGroupingSelect() - if (typeof updateStringUI === 'function') updateStringUI() - const el = document.getElementById('contextInfo') - if (!el) return - const v = typeof activeView === 'function' ? activeView() : null - if (!cy.nodes().length) { - el.innerHTML = - 'Empty view. Open an example or files in the Upload Data tab, or fetch a network under Database importers.' - return - } - const lib = S.currentLibView - const groups = getUsedGroups().filter((g) => g !== UNGROUPED) - let network, grouping, colors - if (lib) { - const nets = lib.nets - .split('|') - .map((id) => libEntry('network', id)) - .filter(Boolean) - .map((e) => e.name) - network = nets.length ? nets.join(' + ') : 'network files' - const ann = lib.annotation ? libEntry('annotation', lib.annotation) : null - grouping = ann ? ann.name : 'none' - const col = lib.colors ? libEntry('colors', lib.colors) : null - const fill = nodeFillMode() - colors = - fill === 'groups' - ? groups.length - ? 'group colors' - : 'default' - : fill === 'values' - ? `${col ? col.name : 'values'}: ${document.getElementById('valueColumn').value}` - : col - ? col.name - : 'from the data' - } else { - network = v ? v.name : 'current data' - grouping = groups.length ? 'from the data' : 'none' - const hasOwn = cy.nodes().some((n) => n.data('nodeColor')) - const fill = nodeFillMode() - colors = - fill === 'values' - ? `values: ${document.getElementById('valueColumn').value}` - : fill === 'data' && hasOwn - ? 'from the data' - : groups.length - ? 'group colors' - : 'default' - } - const groupText = groups.length - ? `${grouping} (${groups.length.toLocaleString()} groups)` - : grouping - el.innerHTML = - contextChip('data', 'Network', network) + - contextChip('groups', 'Grouping', groupText) + - contextChip('colors', 'Colors', colors) -} - -// page wiring, run by main.ts in the original order -export function init() { - ;['input', 'change'].forEach((type) => { - panelDisplayEl.addEventListener( - type, - (e) => { - if (e.target.id === 'groupFilter') return - noteChange() - }, - true - ) - }) - - panelDisplayEl.addEventListener( - 'click', - (e) => { - const btn = e.target.closest('button') - if ( - !btn || - btn.disabled || - btn.classList.contains('helplink') || - btn.classList.contains('ginfo') || - btn.id === 'btnFit' - ) - return - if (btn.getAttribute('role') === 'radio') return // switching layout mode alone moves nothing - noteChange() - }, - true - ) - - ;['btnRefreshView', 'btnClear'].forEach((id) => { - document.getElementById(id).addEventListener('click', noteChange, true) - }) - - document.getElementById('configFileInput').addEventListener('change', noteChange, true) - - cy.on('dragfree', 'node', noteChange) - - cy.on('layoutstop', () => { - S.cyLayoutsRunning = Math.max(0, S.cyLayoutsRunning - 1) - if (S.historySuspended) return - // a layout the user started belongs to the open entry; one that ran by - // itself (e.g. when data loads) just moves the starting point - if (historyTimer || S.historyGestureOpen) scheduleSettle() - else setHistoryBaseline() - }) - - document.getElementById('btnUndo').addEventListener('click', undo) - - document.getElementById('btnRedo').addEventListener('click', redo) - - document.addEventListener('keydown', (e) => { - if (typingInField(e.target)) return - const mod = e.ctrlKey || e.metaKey - const key = e.key.toLowerCase() - if (mod && key === 'z') { - e.preventDefault() - if (e.shiftKey) redo() - else undo() - } else if (mod && key === 'y') { - e.preventDefault() - redo() - } else if ( - (currentTab === 'network' || currentTab === 'network3d') && - mod && - key === 'a' && - !['SELECT'].includes(e.target.tagName) - ) { - e.preventDefault() - cy.nodes(':visible').select() - } else if ( - (currentTab === 'network' || currentTab === 'network3d') && - key === 'escape' && - cy.$(':selected').length - ) { - cy.$(':selected').unselect() - } - }) - - cy.on('select unselect remove', () => { - if (selectionUpdateQueued) return - selectionUpdateQueued = true - requestAnimationFrame(updateSelectionBar) - }) - - document - .getElementById('btnSelClear') - .addEventListener('click', () => cy.$(':selected').unselect()) - - document.getElementById('btnSelFit').addEventListener('click', () => { - const sel = cy.$(':selected') - if (sel.length) - fitView(sel.union(sel.connectedNodes ? sel.connectedNodes() : cy.collection()), 60) - }) - - document.getElementById('viewGrouping').addEventListener('change', (e) => { - if (!S.currentLibView) return - libSelection.networks = new Set(S.currentLibView.nets.split('|').filter(Boolean)) - libSelection.annotation = e.target.value - if (S.currentLibView.colors !== undefined) libSelection.colors = S.currentLibView.colors - renderLibraryLists() - refreshLibraryView() - groupingSelectKey = '' - updateStats() - }) -} diff --git a/frontend/src/sample_data.ts b/frontend/src/sample_data.ts deleted file mode 100644 index c9736e5..0000000 --- a/frontend/src/sample_data.ts +++ /dev/null @@ -1,546 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -/* ---------- sample data, modeled on the STRING trp-operon screenshot ---------- */ -function buildSampleData() { - // seeded, so the demo (and its download in Help) is the same every time - const rand = mulberry32(3) - const hub = ['trpA', 'trpB', 'trpC', 'trpD', 'trpE', 'pabB', 'tyrA'] - const secondGroup = { - trpA: 'indole-pathway', - pabB: 'folate-pathway', - tyrA: 'tyrosine-pathway', - } - // node attributes: arbitrary metadata about an individual node, shown in - // its info popup (distinct from group attributes below, which describe - // the *group* rather than any one member). - const geneFunction = { - trpA: 'Tryptophan synthase, alpha subunit', - trpB: 'Tryptophan synthase, beta subunit', - trpC: 'Indole-3-glycerol-phosphate synthase', - trpD: 'Anthranilate phosphoribosyltransferase', - trpE: 'Anthranilate synthase component I', - pabB: 'Aminodeoxychorismate synthase component I', - tyrA: 'Chorismate mutase / prephenate dehydrogenase', - lgt: 'Prolipoprotein diacylglyceryl transferase', - putP: 'Sodium/proline symporter', - tnaA: 'Tryptophanase', - glyA: 'Serine hydroxymethyltransferase', - } - const ecNumber = { - trpA: '4.2.1.20', - trpB: '4.2.1.20', - trpC: '4.1.1.48', - trpD: '2.4.2.18', - trpE: '4.1.3.27', - tnaA: '4.1.99.1', - glyA: '2.1.2.1', - } - const nodes = [ - ...hub.map((id) => ({ - id, - groups: secondGroup[id] ? ['core', secondGroup[id]] : ['core'], - size: id === 'trpA' ? 54 : 46, - function: geneFunction[id], - ...(ecNumber[id] ? { ecNumber: ecNumber[id] } : {}), - })), - { id: 'lgt', groups: ['peripheral'], size: 40, function: geneFunction.lgt }, - { id: 'putP', groups: ['peripheral', 'transport'], size: 40, function: geneFunction.putP }, - { - id: 'tnaA', - groups: ['peripheral', 'tryptophan-catabolism'], - size: 40, - function: geneFunction.tnaA, - ecNumber: ecNumber.tnaA, - }, - { - id: 'glyA', - groups: ['peripheral'], - size: 40, - function: geneFunction.glyA, - ecNumber: ecNumber.glyA, - }, - ] - - // group attributes: metadata about each group as a whole -- a nicer - // display label and a short description -- shown in the Node groups - // legend (as the row's label and hover tooltip) and in a node's info - // popup subtitle. - const groupAttrs = { - core: { label: 'Core operon', description: 'Tryptophan biosynthesis operon genes (trpA-E)' }, - 'indole-pathway': { - label: 'Indole pathway', - description: 'Shared branch point with indole/tryptophan interconversion', - }, - 'folate-pathway': { - label: 'Folate pathway', - description: 'para-aminobenzoate / folate biosynthesis branch', - }, - 'tyrosine-pathway': { - label: 'Tyrosine pathway', - description: 'Aromatic amino acid biosynthesis branch', - }, - peripheral: { - label: 'Peripheral genes', - description: 'Functionally related genes outside the core operon', - }, - transport: { label: 'Transport', description: 'Membrane transport function' }, - 'tryptophan-catabolism': { - label: 'Trp catabolism', - description: 'Tryptophan breakdown pathway', - }, - } - - const edges = [] - let eid = 0 - const pairTypes = [ - 'neighborhood', - 'cooccurrence', - 'coexpression', - 'experiments', - 'textmining', - 'database', - ] - - // dense, richly multi-edged core cluster - for (let i = 0; i < hub.length; i++) { - for (let j = i + 1; j < hub.length; j++) { - const a = hub[i], - b = hub[j] - const n = 3 + Math.floor(rand() * 3) // 3-5 parallel edges - const shuffled = [...pairTypes].sort(() => rand() - 0.5).slice(0, n) - shuffled.forEach((t) => { - // edge attributes: arbitrary metadata about an individual edge - // (evidenceCount here), shown in its popup alongside weight/type. - edges.push({ - id: 'e' + eid++, - source: a, - target: b, - type: t, - weight: +(0.4 + rand() * 0.59).toFixed(2), - evidenceCount: 1 + Math.floor(rand() * 14), - }) - }) - } - } - - // peripheral, sparser connections - edges.push({ id: 'e' + eid++, source: 'lgt', target: 'trpA', type: 'coexpression' }) - edges.push({ id: 'e' + eid++, source: 'lgt', target: 'trpA', type: 'textmining' }) - - edges.push({ id: 'e' + eid++, source: 'putP', target: 'trpA', type: 'database' }) - edges.push({ id: 'e' + eid++, source: 'putP', target: 'pabB', type: 'database' }) - edges.push({ id: 'e' + eid++, source: 'putP', target: 'tyrA', type: 'database' }) - - edges.push({ id: 'e' + eid++, source: 'tnaA', target: 'trpB', type: 'database' }) - edges.push({ id: 'e' + eid++, source: 'tnaA', target: 'trpB', type: 'cooccurrence' }) - edges.push({ id: 'e' + eid++, source: 'tnaA', target: 'trpA', type: 'database' }) - - edges.push({ id: 'e' + eid++, source: 'glyA', target: 'trpB', type: 'database' }) - edges.push({ id: 'e' + eid++, source: 'glyA', target: 'trpB', type: 'cooccurrence' }) - - return { nodes, edges, groupAttrs } -} - -// Procedurally generates a plausible multi-group, multi-channel network of a -// given size, for demonstrating the tool across a range of scales (a handful -// of nodes up to several thousand). Group count grows with network size; -// edges are a random spanning backbone (guarantees connectivity) plus extra -// random links for density, each carrying a random channel and weight. -export function generateRandomNetwork(n, opts = {}) { - // seeded, so each demo (and its download in Help) is the same every time - const rand = mulberry32(opts.seed ?? n * 7919 + 17) - const INTERACTIONS = ['activates', 'inhibits', 'binds', 'phosphorylates', 'regulates'] - const groupCount = opts.groupCount || Math.max(2, Math.min(16, Math.round(Math.sqrt(n)))) - const groupNames = Array.from({ length: groupCount }, (_, i) => 'group-' + (i + 1)) - const edgeTypePool = [ - 'neighborhood', - 'cooccurrence', - 'coexpression', - 'experiments', - 'database', - 'textmining', - ] - - const nodes = [] - for (let i = 0; i < n; i++) { - const primary = groupNames[i % groupNames.length] - const groups = [primary] - if (rand() < 0.12) { - const second = groupNames[Math.floor(rand() * groupNames.length)] - if (second !== primary) groups.push(second) - } - nodes.push({ id: 'n' + i, groups, size: 30 + rand() * 20 }) - } - - const edges = [] - let eid = 0 - const makeEdge = (i, j) => ({ - id: 'ge' + eid++, - source: 'n' + i, - target: 'n' + j, - type: edgeTypePool[Math.floor(rand() * edgeTypePool.length)], - weight: +(0.3 + rand() * 0.69).toFixed(2), - ...(opts.edgeLabels - ? { interaction: INTERACTIONS[Math.floor(rand() * INTERACTIONS.length)] } - : {}), - }) - - // random spanning backbone -- every node (after the first) attaches to - // some earlier node, so the whole network stays connected - for (let i = 1; i < n; i++) { - edges.push(makeEdge(i, Math.floor(rand() * i))) - } - // extra random edges for density - const avgExtra = opts.avgExtraEdges ?? (n <= 100 ? 2 : n <= 1000 ? 1.2 : 0.6) - const extraCount = Math.round(n * avgExtra) - for (let k = 0; k < extraCount; k++) { - const a = Math.floor(rand() * n) - const b = Math.floor(rand() * n) - if (a === b) continue - edges.push(makeEdge(a, b)) - } - - const data = { nodes, edges } - if (opts.edgeLabels) { - // open with each edge labelled by its interaction, on curved edges so - // parallel labels don't sit on top of each other - data.config = { - showEdgeLabels: true, - edgeLabelContent: 'attr:interaction', - edgeLabelSize: '10', - edgeCurveStyle: 'bezier', - } - } - return data -} - -// A directed multi-edge network: each connected pair gets one to three -// channels (regulation, phosphorylation, binding, ...), each drawn as an -// arrow from source to target; some pairs also have edges in the reverse -// direction, so reciprocal and parallel arrows can be explored. -export function generateDirectedMultiNetwork(n, opts = {}) { - const rand = mulberry32(opts.seed ?? 4242) - const channels = ['activation', 'inhibition', 'phosphorylation', 'binding', 'expression'] - const groupNames = ['receptors', 'kinases', 'transcription factors', 'targets'] - const groupAttrs = { - receptors: { description: 'Upstream sensors that start the signal' }, - kinases: { description: 'Relay the signal by phosphorylation' }, - 'transcription factors': { description: 'Turn target genes on or off' }, - targets: { description: 'Downstream genes and effectors' }, - } - const nodes = [] - const layerOf = [] - for (let i = 0; i < n; i++) { - // nodes are spread over four layers, roughly a signalling cascade - const layer = Math.min(3, Math.floor((i / n) * 4)) - layerOf.push(layer) - const groups = [groupNames[layer]] - if (rand() < 0.1 && layer < 3) groups.push(groupNames[layer + 1]) - nodes.push({ id: ['R', 'K', 'TF', 'G'][layer] + (i + 1), groups, size: 34 + rand() * 16 }) - } - const edges = [] - let eid = 0 - const addPair = (a, b) => { - const count = 1 + Math.floor(rand() * 3) // 1-3 channels - const picked = [...channels].sort(() => rand() - 0.5).slice(0, count) - picked.forEach((type) => - edges.push({ - id: 'de' + eid++, - source: nodes[a].id, - target: nodes[b].id, - type, - weight: +(0.3 + rand() * 0.7).toFixed(2), - directed: true, - }) - ) - if (rand() < 0.25) { - // feedback in the other direction - edges.push({ - id: 'de' + eid++, - source: nodes[b].id, - target: nodes[a].id, - type: rand() < 0.5 ? 'inhibition' : 'binding', - weight: +(0.3 + rand() * 0.7).toFixed(2), - directed: true, - }) - } - } - const used = new Set() - const pairOnce = (a, b) => { - const key = a < b ? a + ',' + b : b + ',' + a - if (a === b || used.has(key)) return - used.add(key) - addPair(a, b) - } - // every node below the top layer is reached from an earlier layer - for (let i = 0; i < n; i++) { - if (layerOf[i] === 0) continue - const upstream = [] - for (let j = 0; j < n; j++) if (layerOf[j] === layerOf[i] - 1) upstream.push(j) - pairOnce(upstream[Math.floor(rand() * upstream.length)], i) - } - // extra links within and across neighbouring layers - for (let k = 0; k < n * 0.9; k++) { - const a = Math.floor(rand() * n) - const candidates = [] - for (let j = 0; j < n; j++) - if (layerOf[j] === layerOf[a] || layerOf[j] === layerOf[a] + 1) candidates.push(j) - pairOnce(a, candidates[Math.floor(rand() * candidates.length)]) - } - return { - nodes, - edges, - groupAttrs, - groupOrder: groupNames, - directed: true, - config: { - edgeDirection: 'data', - edgeCurveStyle: 'bezier', - edgeCurvature: '28', - arrowShape: 'triangle', - arrowScale: '1', - layoutSelect: 'breadthfirst', - }, - } -} - -// Small seeded PRNG so the module examples come out identical on every load. -export function mulberry32(seed) { - return function () { - seed |= 0 - seed = (seed + 0x6d2b79f5) | 0 - let t = Math.imul(seed ^ (seed >>> 15), 1 | seed) - t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t - return ((t ^ (t >>> 14)) >>> 0) / 4294967296 - } -} - -// Four synthetic functional modules (not real genes). Each module biases -// what its members look like (localization, domains) and which evidence -// channels its internal links tend to come from. -const MODULE_DEFS = [ - { - key: 'signaling', - prefix: 'SIG', - label: 'Signaling', - category: 'regulatory', - description: 'Receptors and kinases that relay outside cues into the cell', - localization: ['membrane', 'cytoplasm', 'cytoplasm'], - domains: ['kinase', 'SH2', 'PH', 'GTPase'], - channels: ['experiments', 'experiments', 'coexpression', 'textmining'], - }, - { - key: 'metabolism', - prefix: 'MET', - label: 'Central metabolism', - category: 'enzymatic', - description: 'Enzymes that turn nutrients into energy and building blocks', - localization: ['cytoplasm', 'mitochondrion', 'mitochondrion'], - domains: ['Rossmann fold', 'TIM barrel', 'aldolase', 'NAD-binding'], - channels: ['database', 'neighborhood', 'cooccurrence', 'coexpression'], - }, - { - key: 'transport', - prefix: 'TRN', - label: 'Membrane transport', - category: 'transport', - description: 'Carriers and channels that move solutes across membranes', - localization: ['membrane', 'membrane', 'vesicle'], - domains: ['MFS', 'ABC', 'ion channel', 'porin'], - channels: ['cooccurrence', 'database', 'neighborhood', 'experiments'], - }, - { - key: 'transcription', - prefix: 'TSC', - label: 'Transcription control', - category: 'regulatory', - description: 'Factors that switch target genes on and off', - localization: ['nucleus', 'nucleus', 'cytoplasm'], - domains: ['zinc finger', 'HTH', 'bZIP', 'bromodomain'], - channels: ['textmining', 'coexpression', 'experiments', 'database'], - }, -] - -const CROSS_MODULE_CHANNELS = ['textmining', 'database', 'cooccurrence'] - -// Builds a 4-module network that exercises all three attribute levels: -// node attrs: localization (text), expression (number), essential (yes/no), -// length (integer), domains (list) -// edge attrs: evidenceCount (integer), firstReported (year) -// group attrs: label/description (built-in) plus category, enrichmentFDR, -// curated, keyMembers (custom) -// sizes -- members per module (before overlaps), sums to the node count -// overlaps -- one entry per shared node: [homeModule, ...extraModules] -// pIn/pOut -- link probability for a node pair inside / across modules -export function buildModuleNetwork({ sizes, overlaps, pIn, pOut, seed }) { - const rand = mulberry32(seed) - const pick = (arr) => arr[Math.floor(rand() * arr.length)] - const shuffle = (arr) => { - const a = arr.slice() - for (let i = a.length - 1; i > 0; i--) { - const j = Math.floor(rand() * (i + 1)) - ;[a[i], a[j]] = [a[j], a[i]] - } - return a - } - const pickDistinct = (pool, n) => { - const out = [] - const distinct = new Set(pool).size - while (out.length < Math.min(n, distinct)) { - const v = pick(pool) - if (!out.includes(v)) out.push(v) - } - return out - } - - // 1. nodes, each with a single home module - const nodes = [] - const members = MODULE_DEFS.map(() => []) - MODULE_DEFS.forEach((m, gi) => { - for (let i = 0; i < sizes[gi]; i++) { - const node = { - id: `${m.prefix}-${String(i + 1).padStart(2, '0')}`, - groups: [m.key], - size: 30 + Math.round(rand() * 16), - localization: pick(m.localization), - expression: +((rand() * 2 - 1) * 3).toFixed(2), - essential: rand() < 0.2, - length: 120 + Math.round(rand() * 1280), - domains: pickDistinct(m.domains, rand() < 0.35 ? 2 : 1), - } - nodes.push(node) - members[gi].push(node) - } - }) - - // 2. small overlaps: a few nodes join one or two extra modules and pick - // up a domain typical of each module they join - overlaps.forEach(([home, ...extra]) => { - const candidates = members[home].filter((n) => n.groups.length === 1) - if (!candidates.length) return - const node = pick(candidates) - extra.forEach((gj) => { - const m = MODULE_DEFS[gj] - node.groups.push(m.key) - members[gj].push(node) - const d = pick(m.domains) - if (!node.domains.includes(d)) node.domains.push(d) - }) - }) - - // 3. edges: 1-3 parallel channels per linked pair - const edges = [] - const seenPairs = new Set() - const degree = {} - let eid = 0 - const link = (a, b, channelPool) => { - if (a === b) return - const key = a.id < b.id ? a.id + '|' + b.id : b.id + '|' + a.id - if (seenPairs.has(key)) return - seenPairs.add(key) - const channelCount = 1 + (rand() < 0.45 ? 1 : 0) + (rand() < 0.15 ? 1 : 0) - pickDistinct(channelPool, channelCount).forEach((type) => { - edges.push({ - id: 'm' + eid++, - source: a.id, - target: b.id, - type, - weight: +(0.4 + rand() * 0.59).toFixed(2), - evidenceCount: 1 + Math.floor(rand() * 12), - firstReported: 1995 + Math.floor(rand() * 30), - }) - degree[a.id] = (degree[a.id] || 0) + 1 - degree[b.id] = (degree[b.id] || 0) + 1 - }) - } - - // inside each module: a random tree keeps the module connected, then - // extra links at density pIn - members.forEach((list, gi) => { - const pool = MODULE_DEFS[gi].channels - const order = shuffle(list) - for (let i = 1; i < order.length; i++) link(order[i], order[Math.floor(rand() * i)], pool) - for (let i = 0; i < list.length; i++) { - for (let j = i + 1; j < list.length; j++) { - if (rand() < pIn) link(list[i], list[j], pool) - } - } - }) - - // across modules: sparse links between nodes that share no module - for (let i = 0; i < nodes.length; i++) { - for (let j = i + 1; j < nodes.length; j++) { - const a = nodes[i], - b = nodes[j] - if (a.groups.some((g) => b.groups.includes(g))) continue - if (rand() < pOut) link(a, b, CROSS_MODULE_CHANNELS) - } - } - - // 4. group attributes - const groupAttrs = {} - MODULE_DEFS.forEach((m, gi) => { - const keyMembers = members[gi] - .slice() - .sort((a, b) => (degree[b.id] || 0) - (degree[a.id] || 0)) - .slice(0, 3) - .map((n) => n.id) - groupAttrs[m.key] = { - label: m.label, - description: m.description, - category: m.category, - enrichmentFDR: +Math.pow(10, -(2 + rand() * 6)).toPrecision(2), - curated: gi % 2 === 0, - keyMembers, - } - }) - - return { nodes, edges, groupAttrs } -} - -export const SAMPLE_GENERATORS = { - trp: () => buildSampleData(), - // 50 nodes; 5 shared nodes (10%): one bridge per neighbouring module pair - // around the ring, plus one node sitting in three modules - modules50: () => - buildModuleNetwork({ - sizes: [14, 12, 13, 11], - overlaps: [ - [0, 1], - [1, 2], - [2, 3], - [3, 0], - [0, 1, 2], - ], - pIn: 0.26, - pOut: 0.012, - seed: 50, - }), - // 100 nodes; 10 shared nodes (10%): two bridges per neighbouring pair, - // one across the ring and one node in three modules - modules100: () => - buildModuleNetwork({ - sizes: [28, 24, 26, 22], - overlaps: [ - [0, 1], - [1, 0], - [1, 2], - [2, 1], - [2, 3], - [3, 2], - [3, 0], - [0, 3], - [0, 2], - [1, 2, 3], - ], - pIn: 0.16, - pOut: 0.006, - seed: 100, - }), - tiny: () => generateRandomNetwork(20, { edgeLabels: true, avgExtraEdges: 1 }), - directed: () => generateDirectedMultiNetwork(40), - small: () => generateRandomNetwork(60), - medium: () => generateRandomNetwork(200), - large: () => generateRandomNetwork(800), - massive: () => generateRandomNetwork(5000, { avgExtraEdges: 0.6 }), -} diff --git a/frontend/src/side_panel.ts b/frontend/src/side_panel.ts deleted file mode 100644 index ac5df23..0000000 --- a/frontend/src/side_panel.ts +++ /dev/null @@ -1,104 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) - -/* ---------- side panel: drag to resize, arrow to collapse ---------- */ -// page wiring, run by main.ts in the original order -export function init() { - const app = document.getElementById('app') - const handle = document.getElementById('sideResizer') - const toggle = document.getElementById('sideToggle') - const DEFAULT_W = 300, - MIN_W = 260, - COLLAPSE_BELOW = 150 - const maxW = () => Math.max(MIN_W, Math.min(720, Math.round(window.innerWidth * 0.6))) - let width = DEFAULT_W, - collapsed = false - try { - const saved = JSON.parse(localStorage.getItem('norma3-sidebar') || 'null') - if (saved) { - width = Number(saved.width) || DEFAULT_W - collapsed = !!saved.collapsed - } - } catch (e) {} - const save = () => { - try { - localStorage.setItem('norma3-sidebar', JSON.stringify({ width, collapsed })) - } catch (e) {} - } - function apply() { - width = Math.max(MIN_W, Math.min(maxW(), Math.round(width))) - app.style.setProperty('--side-w', collapsed ? '0px' : width + 'px') - app.classList.toggle('side-collapsed', collapsed) - const label = collapsed ? 'Expand the side panel' : 'Collapse the side panel' - toggle.setAttribute('aria-expanded', collapsed ? 'false' : 'true') - toggle.setAttribute('aria-label', label) - toggle.title = label - handle.setAttribute('aria-valuemin', MIN_W) - handle.setAttribute('aria-valuemax', maxW()) - handle.setAttribute('aria-valuenow', width) - } - function setCollapsed(c) { - collapsed = c - apply() - save() - } - toggle.addEventListener('click', () => setCollapsed(!collapsed)) - - handle.addEventListener('pointerdown', (e) => { - if (e.button !== 0) return - e.preventDefault() - handle.setPointerCapture(e.pointerId) - app.classList.add('side-resizing') - const left = app.getBoundingClientRect().left - const beforeW = width - const move = (ev) => { - const w = ev.clientX - left - if (w < COLLAPSE_BELOW) { - if (!collapsed) { - collapsed = true - apply() - } - return - } - collapsed = false - width = w - apply() - } - const up = () => { - app.classList.remove('side-resizing') - // dragged shut: reopen later at the width it had before the drag - if (collapsed) width = beforeW - handle.removeEventListener('pointermove', move) - handle.removeEventListener('pointerup', up) - handle.removeEventListener('pointercancel', up) - save() - } - handle.addEventListener('pointermove', move) - handle.addEventListener('pointerup', up) - handle.addEventListener('pointercancel', up) - }) - handle.addEventListener('dblclick', () => { - width = DEFAULT_W - collapsed = false - apply() - save() - }) - handle.addEventListener('keydown', (e) => { - const step = e.shiftKey ? 50 : 10 - if (e.key === 'ArrowLeft') width -= step - else if (e.key === 'ArrowRight') width += step - else if (e.key === 'Home') width = MIN_W - else if (e.key === 'End') width = maxW() - else if (e.key === 'Enter') { - setCollapsed(true) - toggle.focus() - e.preventDefault() - return - } else return - e.preventDefault() - apply() - save() - }) - window.addEventListener('resize', apply) - apply() -} diff --git a/frontend/src/side_tabs.ts b/frontend/src/side_tabs.ts deleted file mode 100644 index 3cd2473..0000000 --- a/frontend/src/side_tabs.ts +++ /dev/null @@ -1,273 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { NORMA_EXAMPLE_SETS } from './wiring' -import { downloadText } from './layouts/controls' - -/* ---------- Data / Display sub-tabs ---------- */ -const SIDE_TABS = [ - ['data', 'sideTabData', 'panelData'], - ['db', 'sideTabDb', 'panelDb'], - ['display', 'sideTabDisplay', 'panelDisplay'], - ['export', 'sideTabExport', 'panelExport'], -] - -export function switchSideTab(name) { - SIDE_TABS.forEach(([k, tabId, panelId]) => { - const on = k === name - const tab = document.getElementById(tabId) - tab.setAttribute('aria-selected', on ? 'true' : 'false') - tab.tabIndex = on ? 0 : -1 - document.getElementById(panelId).hidden = !on - }) - document.getElementById('sidebar').scrollTop = 0 -} - -/* ---------- example file links (Help > Examples) ---------- - Download links for NORMA's example files as published by the NORMA - server, each paired with the copy bundled in this page (by example set - and file name), which keeps working offline. */ -const NORMA_DOWNLOAD_BASE = - 'https://pavlopoulos-lab-services.org/shiny/app_proxy/a64cd611-0420-4151-a75c-e1e2066f6bc5/session/ef352e36fc9ed86bf6e69f45a83d6216/download/' - -const EXAMPLE_FILE_LINKS = [ - { - title: 'STRING example 1 (TP53 interactors)', - set: 'string-tp53', - files: [ - ['STRING Network file', 'string_net_tp53', 'string_interactions.txt'], - ['STRING Annotation file', 'string_annot', 'string_interactions_groups_comma_duplicate.txt'], - ['STRING Expression file', 'string_expr', 'string_expression_colors.txt'], - ], - }, - { - title: 'STRING example 2 (BCAR3 interactors)', - set: 'string-bcar3', - files: [ - ['STRING Network file', 'string_net_bcar3', 'BCAR3.txt'], - ['GO Annotation - Biological Process', 'string_bp', 'BCAR3_GO_BP.txt'], - ['GO Annotation - Molecular Function', 'string_mf', 'BCAR3_GO_MF.txt'], - ['KEGG pathways', 'string_kegg', 'BCAR3_KEGG.txt'], - ], - }, - { - title: 'Drosophila (Tau) Network', - set: 'tau', - refs: [ - ['PMID:31488613', 'https://pubmed.ncbi.nlm.nih.gov/31488613/'], - ['PMCID:PMC6794924', 'https://www.ncbi.nlm.nih.gov/pmc/articles/PMC6794924/'], - ['DOI:10.1523/JNEUROSCI.0391-19.2019', 'https://doi.org/10.1523/JNEUROSCI.0391-19.2019'], - ], - files: [ - ['Drosophila Network file', 'dros_net', 'TAU_network_DEGs_NORMA.txt'], - ['Drosophila Kegg pathways', 'dros_annot', 'TAU_KEGG_Annotation_NORMA.txt'], - ['Drosophila Louvain automated annotation file', 'dros_louvain', 'TAU_Louvain.txt'], - ['Drosophila Expression file', 'dros_express', 'TAU_expressions.txt'], - ], - }, - { - title: 'Human Gene Co-expression Network', - set: 'coexpr', - refs: [ - ['PMID:19081792', 'https://pubmed.ncbi.nlm.nih.gov/19081792/'], - ['PMCID:PMC2597745', 'https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2597745/'], - ['DOI:10.1371/journal.pone.0003911', 'https://doi.org/10.1371/journal.pone.0003911'], - ['bioinfow.dep.usal.es/coexpression', 'http://bioinfow.dep.usal.es/coexpression/'], - ], - files: [ - ['Gene Co-expression Network', 'co_express', 'NORMA_Human_coexpression_NETWORK.txt'], - [ - 'GO Annotation - Biological Process', - 'co_express_bp', - 'NORMA_Human_coexpression_Annotation_GO_BP.txt', - ], - [ - 'GO Annotation - Molecular Function', - 'co_express_mf', - 'NORMA_Human_coexpression_Annotation_GO_MF.txt', - ], - [ - 'GO Annotation - Cellular Components', - 'co_express_cc', - 'NORMA_Human_coexpression_Annotation_GO_CC.txt', - ], - ['KEGG pathways', 'co_express_kegg', 'NORMA_Human_coexpression_Annotation_KEGG.txt'], - ['MCODE Node coloring', 'co_express_mcode', 'NORMA_Human_coexpression_Expression_MCODE.txt'], - ], - }, - { - title: 'COVID-19: IntAct Database', - set: 'covid', - files: [ - ['COVID-19 Network', 'covid_19_net', 'Intact-data_COVID19_no_self_loops.txt'], - [ - 'HomoSapiens Protein Domains - INTERPRO', - 'covid_19_interpro', - 'HomoSapiens_Protein_Domains_INTERPRO_FILTERED.txt', - ], - [ - 'HomoSapiens GO Annotation - Biological Process', - 'covid_19_bp', - 'HomoSapiens_Gene_Ontology_GOTERM_BP_DIRECT_FILTERED.txt', - ], - [ - 'HomoSapiens GO Annotation - Molecular Function', - 'covid_19_mf', - 'HomoSapiens_Gene_Ontology_GOTERM_MF_DIRECT_FILTERED.txt', - ], - [ - 'HomoSapiens Protein Domains GO Annotation - Cellular Components', - 'covid_19_cc', - 'HomoSapiens_Gene_Ontology_GOTERM_CC_DIRECT_FILTERED.txt', - ], - [ - 'HomoSapiens Protein Domains KEGG pathways', - 'covid_19_kegg', - 'HomoSapiens_Pathways_KEGG_PATHWAY_FILTERED.txt', - ], - [ - 'HomoSapiens Protein Domains SMART', - 'covid_19_smart', - 'HomoSapiens_Protein_Domains_SMART_FILTERED.txt', - ], - ], - }, - { - title: 'Gallus gallus: BioGrid Database', - set: 'gallus', - files: [ - ['Gallus gallus Network', 'Gallus_gallus_net', 'Biogrid_no_self_loops.txt'], - [ - 'BioGrid Gallus gallus KEGG pathways', - 'Gallus_gallus_kegg', - 'BioGrid_Chicken_Gallus_Pathways_KEGG_PATHWAY_FILTERED.txt', - ], - ], - }, -] - -function bundledExampleFile(setKey, fileName) { - const set = NORMA_EXAMPLE_SETS[setKey] - return set ? set.files.find((f) => f.fileName === fileName) || null : null -} - -function renderLocalExampleSets(root) { - Object.values(NORMA_EXAMPLE_SETS) - .filter((set) => set.local) - .forEach((set) => { - const block = document.createElement('div') - block.className = 'dl-group' - const h = document.createElement('h3') - h.textContent = set.title - block.appendChild(h) - const list = document.createElement('ul') - list.className = 'dl-list' - set.files.forEach((f) => { - const li = document.createElement('li') - li.append(`${f.name} `) - const btn = document.createElement('button') - btn.type = 'button' - btn.className = 'dl-copy' - btn.textContent = 'Download' - btn.title = `Download ${f.fileName}` - btn.addEventListener('click', () => downloadText(f.fileName, f.text)) - li.appendChild(btn) - list.appendChild(li) - }) - block.appendChild(list) - root.appendChild(block) - }) -} - -function renderExampleLinks() { - const root = document.getElementById('helpExampleFiles') - if (!root) return - root.innerHTML = '' - renderLocalExampleSets(root) - EXAMPLE_FILE_LINKS.forEach((group) => { - const block = document.createElement('div') - block.className = 'dl-group' - const h = document.createElement('h3') - h.textContent = group.title - block.appendChild(h) - if (group.refs) { - const refs = document.createElement('p') - refs.className = 'dl-refs' - group.refs.forEach(([label, url], i) => { - if (i) refs.append(', ') - const a = document.createElement('a') - a.href = url - a.target = '_blank' - a.rel = 'noopener' - a.textContent = label - refs.appendChild(a) - }) - block.appendChild(refs) - } - const list = document.createElement('ul') - list.className = 'dl-list' - group.files.forEach(([label, slug, fileName]) => { - const li = document.createElement('li') - const a = document.createElement('a') - const local = bundledExampleFile(group.set, fileName) - if (local) { - // the sample file itself, from this page, so it never goes missing - a.href = '#' - a.title = `Download ${fileName}` - a.addEventListener('click', (e) => { - e.preventDefault() - downloadText(fileName, local.text) - }) - } else { - a.href = `${NORMA_DOWNLOAD_BASE}${slug}?w=` - a.target = '_blank' - a.rel = 'noopener' - } - a.textContent = label - li.appendChild(a) - const fn = document.createElement('span') - fn.className = 'dl-name' - fn.textContent = fileName - li.appendChild(fn) - list.appendChild(li) - }) - block.appendChild(list) - root.appendChild(block) - }) -} - -/* ---------- search panel: collapse / expand ---------- */ -function setSearchCollapsed(collapsed) { - const panel = document.getElementById('searchPanel') - const toggle = document.getElementById('searchToggle') - panel.classList.toggle('collapsed', collapsed) - toggle.setAttribute('aria-expanded', String(!collapsed)) - toggle.title = collapsed ? 'Open the search panel' : 'Minimize the search panel' - toggle.setAttribute('aria-label', collapsed ? 'Open node search' : 'Minimize node search') - if (!collapsed) document.getElementById('search').focus() -} - -// page wiring, run by main.ts in the original order -export function init() { - document.querySelectorAll('#sideTabs [role="tab"]').forEach((tab) => { - tab.addEventListener('click', () => switchSideTab(tab.dataset.side)) - tab.addEventListener('keydown', (e) => { - if (e.key !== 'ArrowLeft' && e.key !== 'ArrowRight') return - const keys = SIDE_TABS.map((t) => t[0]) - const i = keys.indexOf(tab.dataset.side) - const next = keys[(i + (e.key === 'ArrowRight' ? 1 : keys.length - 1)) % keys.length] - switchSideTab(next) - document.querySelector(`#sideTabs [data-side="${next}"]`).focus() - }) - }) - - renderExampleLinks() - - document.getElementById('searchToggle').addEventListener('click', () => { - setSearchCollapsed(!document.getElementById('searchPanel').classList.contains('collapsed')) - }) - - document.getElementById('searchMinimize').addEventListener('click', () => { - setSearchCollapsed(true) - document.getElementById('searchToggle').focus() - }) -} diff --git a/frontend/src/state.ts b/frontend/src/state.ts deleted file mode 100644 index a39fe88..0000000 --- a/frontend/src/state.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { EDGE_TYPES } from './palette' - -// ponytail: mutable page state that several modules assign; ES module bindings are read-only across files -export const S = { - currentLibView: null, - nodeColorMap: {}, - groupShapes: {}, - groupAttrs: {}, - activeTypes: new Set(Object.keys(EDGE_TYPES)), - activeGroups: new Set(), - layoutRunSeq: 0, - currentNodePalette: 'vivid', - layoutProgress: null, - infoNodeId: null, - autoEdgeIdx: 0, - historySuspended: 0, - dataCache: { version: -1, data: null }, - historyGestureOpen: false, - cyLayoutsRunning: 0, - workRange: [0, 1], - frRequestSeq: 0, - normaEntrySeq: 0, - viewSeq: 0, - activeViewId: null, - DEFAULT_VIEW_CONFIG: null, -} diff --git a/frontend/src/string/groupings.ts b/frontend/src/string/groupings.ts deleted file mode 100644 index 63ed838..0000000 --- a/frontend/src/string/groupings.ts +++ /dev/null @@ -1,185 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { STRING_CATEGORIES, stringCategoryKey, stringCategoryName } from '../view3d/export' -import { - addNormaEntry, - libSelection, - plural, - renderLibraryLists, - setStatus, - startProgress, -} from '../layouts/controls' -import { refreshLibraryView } from '../library' -import { stringCall, stringState } from './requests' -import { stringNetworkInView, stringSettings, updateStringUI } from './ui_state' - -/* ---------- groupings ---------- */ -// task/step: the import's progress; on its own, it shows a progress of its own. -export async function fetchStringGroupings(netEntry, st, notes, task = null, step = 0) { - const meta = netEntry.stringMeta - const nameOf = new Map(Object.entries(meta.nameOf)) - const byPreferred = new Map([...nameOf.values()].map((n) => [n.toLowerCase(), n])) - const ids = meta.stringIds - const enrichment = st.annotMode === 'enrichment' - const own = !task - if (own) { - task = startProgress('stringStatus', [1]) - step = 0 - } - task.step( - step, - enrichment - ? `Running functional enrichment for ${plural(ids.length, 'protein')}…` - : `Fetching functional annotations for ${plural(ids.length, 'protein')}…` - ) - let rows - try { - rows = await stringCall( - enrichment ? 'enrichment' : 'functional_annotation', - { identifiers: ids.join('\r'), species: meta.taxon }, - { onBytes: (got, total) => task.bytes(got, total) } - ) - } catch (err) { - notes.push({ level: 'warn', text: `Groupings couldn't be fetched: ${err.message}` }) - if (own) task.stop() - return [] - } - if (own) task.stop() - const wanted = new Set(st.categories) - const byCat = new Map() - const seenCats = new Map() - ;(rows || []).forEach((r) => { - const cat = stringCategoryKey(r.category) - seenCats.set(cat, (seenCats.get(cat) || 0) + 1) - const known = STRING_CATEGORIES.some((c) => c[0] === cat) - if (!(wanted.has(cat) || (!known && st.otherCategories))) return - if (enrichment && !(Number(r.fdr) <= st.fdr)) return - // members: map STRING ids (inputGenes) or names back to node names - const inputs = Array.isArray(r.inputGenes) - ? r.inputGenes - : String(r.inputGenes || '').split(',') - const names = Array.isArray(r.preferredNames) - ? r.preferredNames - : String(r.preferredNames || '').split(',') - const members = new Set() - inputs.forEach((g, i) => { - const n = - nameOf.get(g) || - byPreferred.get(String(names[i] || g).toLowerCase()) || - byPreferred.get(String(g).toLowerCase()) - if (n) members.add(n) - }) - if (members.size < st.minGroup) return - if (!byCat.has(cat)) byCat.set(cat, []) - byCat.get(cat).push({ - term: r.term, - description: r.description || r.term, - members: [...members], - fdr: Number(r.fdr), - p: Number(r.p_value), - background: Number(r.number_of_genes_in_background), - ratio: Number(r.ratio_in_set), - }) - }) - const entries = [] - const order = [ - ...STRING_CATEGORIES.map((c) => c[0]), - ...[...byCat.keys()].filter((k) => !STRING_CATEGORIES.some((c) => c[0] === k)), - ] - order.forEach((cat) => { - const list = byCat.get(cat) - if (!list || !list.length) return - list.sort((a, b) => - enrichment - ? a.fdr - b.fdr || b.members.length - a.members.length - : b.members.length - a.members.length - ) - const top = list.slice(0, st.maxTerms) - const usedNames = new Set() - const groupMeta = {} - const lines = top.map((t) => { - let name = String(t.description) - .replace(/[\t\r\n]+/g, ' ') - .trim() - if (usedNames.has(name)) name = `${name} (${t.term})` - usedNames.add(name) - const info = { - description: `${stringCategoryName(cat)}${t.term && t.term !== name ? ', ' + t.term : ''}`, - term: t.term, - category: stringCategoryName(cat), - 'proteins in network': t.members.length, - } - if (enrichment) { - info.FDR = t.fdr - if (Number.isFinite(t.p)) info['p-value'] = t.p - if (Number.isFinite(t.background)) info['proteins in genome'] = t.background - } - groupMeta[name] = info - return `${name}\t${t.members.join(',')}` - }) - const label = `${netEntry.name}: ${stringCategoryName(cat)}${enrichment ? ` (FDR ≤ ${st.fdr})` : ''}` - const entry = addNormaEntry('annotation', label, lines.join('\n') + '\n', '', null, {}) - entry.groupMeta = groupMeta - entry.stringCategory = cat - entry.stringCategoryName = stringCategoryName(cat) - entry.forNetwork = netEntry.id - entries.push(entry) - if (list.length > top.length) - notes.push({ - level: 'ok', - text: `${stringCategoryName(cat)}: kept the ${top.length} ${enrichment ? 'most significant' : 'largest'} of ${list.length} terms.`, - }) - }) - const offered = [...seenCats.keys()].map((k) => `${stringCategoryName(k)} (${seenCats.get(k)})`) - if (offered.length) - notes.push({ - level: 'ok', - text: `STRING returned ${enrichment ? 'enriched terms' : 'annotations'} in: ${offered.join(', ')}.`, - }) - const emptyWanted = st.categories.filter((k) => !byCat.has(k) && !(k === 'KEGG' && !enrichment)) - if (emptyWanted.length) - notes.push({ - level: 'warn', - text: `No ${enrichment ? `terms with FDR ≤ ${st.fdr}` : 'annotations'} and at least ${st.minGroup} proteins for: ${emptyWanted.map(stringCategoryName).join(', ')}.`, - }) - if (!enrichment && wanted.has('KEGG')) - notes.push({ - level: 'ok', - text: 'STRING does not share full KEGG annotations for licensing reasons; choose Terms: "Enriched in the network" to get KEGG pathways.', - }) - return entries -} - -export async function runStringGroupings() { - const net = stringNetworkInView() - if (!net) return - const st = stringSettings() - if (!st.categories.length && !st.otherCategories) { - setStatus('stringStatus', [{ level: 'error', text: 'Tick at least one term collection.' }]) - return - } - stringState.busy = true - stringState.cancelled = false - updateStringUI() - const notes = [] - try { - const entries = await fetchStringGroupings(net, st, notes) - if (entries.length) { - libSelection.annotation = entries[0].id - renderLibraryLists() - refreshLibraryView() - } - setStatus('stringStatus', [ - { - level: entries.length ? 'ok' : 'warn', - text: entries.length - ? `Added ${plural(entries.length, 'grouping')} for "${net.name}": ${entries.map((e) => e.stringCategoryName).join(', ')}.` - : `No new groupings for "${net.name}".`, - }, - ...notes, - ]) - } finally { - stringState.busy = false - updateStringUI() - } -} diff --git a/frontend/src/string/import.ts b/frontend/src/string/import.ts deleted file mode 100644 index 01796cf..0000000 --- a/frontend/src/string/import.ts +++ /dev/null @@ -1,292 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { STRING_CHANNELS, STRING_PREFERRED_GROUPING } from '../view3d/export' -import { - addNormaEntry, - libSelection, - listSample, - plural, - renderLibraryLists, - setStatus, - startProgress, -} from '../layouts/controls' -import { - combineStringScores, - scoreValue, - stringBase, - stringCall, - stringState, - stringVersion, -} from './requests' -import { fetchStringGroupings } from './groupings' -import { openInNewView } from '../profiler' -import { refreshLibraryView } from '../library' -import { stringSettings, updateStringUI } from './ui_state' - -/* ---------- import ---------- */ - -export async function runStringImport() { - const st = stringSettings() - if (!st.names.length) { - setStatus('stringStatus', [ - { level: 'error', text: 'Type at least one protein or gene name, for example TP53.' }, - ]) - return - } - if (!/^(\d+|STRG\w+)$/.test(st.taxon)) { - setStatus('stringStatus', [ - { - level: 'error', - text: 'Enter the organism as an NCBI taxon number, for example 9606 for human.', - }, - ]) - return - } - if (!st.channels.length) { - setStatus('stringStatus', [{ level: 'error', text: 'Tick at least one evidence channel.' }]) - return - } - if (st.names.length > 2000) { - setStatus('stringStatus', [ - { level: 'error', text: 'STRING accepts at most 2,000 names per query.' }, - ]) - return - } - stringState.busy = true - stringState.cancelled = false - updateStringUI() - const notes = [] - const withGroupings = !!(st.categories.length || st.otherCategories) - // steps: version, names, network, descriptions, groupings, opening - const task = startProgress('stringStatus', [ - 1, - 2, - 6, - st.descriptions ? 2 : 0, - withGroupings ? 4 : 0, - 1, - ]) - const onBytes = (got, total) => task.bytes(got, total) - try { - task.step(0, 'Checking the STRING version…') - const ver = await stringVersion() - - task.step(1, `Looking up ${plural(st.names.length, 'name')} in ${st.speciesLabel}…`) - const mapped = await stringCall( - 'get_string_ids', - { identifiers: st.names.join('\r'), species: st.taxon, echo_query: 1 }, - { onBytes } - ) - const byQuery = new Map() - ;(mapped || []).forEach((r) => { - const q = r.queryItem ?? st.names[r.queryIndex] - if (q !== undefined && !byQuery.has(q)) byQuery.set(q, r) - }) - const found = st.names.filter((n) => byQuery.has(n)) - const missing = st.names.filter((n) => !byQuery.has(n)) - if (!found.length) - throw new Error( - `STRING found none of the names in ${st.speciesLabel}. Check the spelling and the organism.` - ) - if (missing.length) - notes.push({ - level: 'warn', - text: `Not found in ${st.speciesLabel}: ${listSample(missing)}.`, - }) - const renamed = found.filter( - (n) => - byQuery.get(n).preferredName && - byQuery.get(n).preferredName.toLowerCase() !== n.toLowerCase() - ) - if (renamed.length) - notes.push({ - level: 'ok', - text: `Matched ${listSample(renamed.map((n) => `${n} as ${byQuery.get(n).preferredName}`))}.`, - }) - const queryIds = [...new Set(found.map((n) => byQuery.get(n).stringId))] - const taxonName = byQuery.get(found[0]).taxonName || st.speciesLabel - - task.step( - 2, - st.addNodes - ? `Fetching the network with up to ${st.addNodes} interactors…` - : 'Fetching the network…' - ) - const params = { - identifiers: queryIds.join('\r'), - species: st.taxon, - required_score: Math.round(st.threshold * 1000), - network_type: st.networkType, - } - if (st.addNodes > 0) params.add_nodes = st.addNodes - const rows = await stringCall('network', params, { onBytes }) - const built = buildStringNetwork(rows || [], queryIds, byQuery, st) - if (!built.edges.length) - throw new Error( - `No ${st.networkType} connections pass a confidence of ${st.threshold.toFixed(2)} with the ticked channels. Lower the confidence, tick more channels or add interactors.` - ) - notes.push(...built.notes) - - // descriptions for every protein - if (st.descriptions) { - task.step(3, `Fetching descriptions for ${plural(built.nodeIds.length, 'protein')}…`) - try { - const info = await stringCall( - 'get_string_ids', - { identifiers: built.stringIds.join('\r'), species: st.taxon }, - { onBytes } - ) - ;(info || []).forEach((r) => { - const name = built.nameOf.get(r.stringId) - if (name && r.annotation) built.nodeAttrs[name].description = r.annotation - }) - } catch (err) { - notes.push({ - level: 'warn', - text: `Protein descriptions couldn't be fetched: ${err.message}`, - }) - } - } - - const netName = `STRING ${found - .slice(0, 3) - .map((n) => byQuery.get(n).preferredName || n) - .join(', ')}${found.length > 3 ? ` +${found.length - 3}` : ''} (${shortSpecies(taxonName)})` - const netEntry = addNormaEntry('network', netName, built.text, '', null, {}) - netEntry.nodeAttrs = built.nodeAttrs - netEntry.stringMeta = { - taxon: st.taxon, - taxonName, - version: ver.version, - address: ver.address || stringBase(), - query: found, - stringIds: built.stringIds, - nameOf: Object.fromEntries(built.nameOf), - threshold: st.threshold, - networkType: st.networkType, - channels: st.channels.map((c) => c[1]), - } - - // groupings - let annEntries = [] - if (withGroupings) { - annEntries = await fetchStringGroupings(netEntry, st, notes, task, 4) - } - task.step(5, 'Opening the network…') - - // show it - const preferred = - STRING_PREFERRED_GROUPING.map((k) => annEntries.find((e) => e.stringCategory === k)).find( - Boolean - ) || annEntries[0] - openInNewView(netName, () => { - // a new view starts with its own (empty) file selection - libSelection.networks = new Set([netEntry.id]) - libSelection.annotation = preferred ? preferred.id : '' - libSelection.colors = '' - renderLibraryLists() - refreshLibraryView() - }) - const summary = `Imported ${netEntry.parsed.summary} from STRING${ver.version ? ' ' + ver.version : ''} (${taxonName}, ${st.networkType}, confidence ≥ ${st.threshold.toFixed(2)}).` - const groupText = annEntries.length - ? `Added ${plural(annEntries.length, 'grouping')}: ${annEntries.map((e) => e.stringCategoryName).join(', ')}. Switch between them with the Grouping list at the top.` - : 'No groupings were added.' - setStatus('stringStatus', [ - { level: 'ok', text: summary }, - { level: 'ok', text: groupText }, - ...notes, - ]) - } catch (err) { - setStatus('stringStatus', [{ level: 'error', text: err.message }, ...notes]) - } finally { - task.stop() - stringState.busy = false - stringState.abort = null - updateStringUI() - } -} - -function shortSpecies(name) { - const parts = String(name || '').split(/\s+/) - return parts.length >= 2 ? `${parts[0][0]}. ${parts[1]}` : name -} - -function buildStringNetwork(rows, queryIds, byQuery, st) { - const notes = [] - const nameOf = new Map() // stringId -> node name - const used = new Set() - const nodeAttrs = {} - const querySet = new Set(queryIds) - const addNode = (sid, preferred) => { - if (nameOf.has(sid)) return nameOf.get(sid) - // node names must be unique and can't contain commas (annotation files) - let name = - String(preferred || sid) - .replace(/,/g, ';') - .trim() || sid - if (used.has(name)) name = `${name} (${sid})` - used.add(name) - nameOf.set(sid, name) - nodeAttrs[name] = { stringId: sid, query: querySet.has(sid) } - return name - } - queryIds.forEach((sid) => { - const q = [...byQuery.values()].find((r) => r.stringId === sid) - addNode(sid, q && q.preferredName) - }) - const seen = new Set() - const lines = [] - let dropped = 0, - pairs = 0 - rows.forEach((r) => { - const a = r.stringId_A, - b = r.stringId_B - if (!a || !b || a === b) return - const key = a < b ? a + '\t' + b : b + '\t' + a - if (seen.has(key)) return // STRING may list a pair in both directions - seen.add(key) - const scores = st.channels.map((c) => scoreValue(r[c[0]])) - const combined = - st.channels.length === STRING_CHANNELS.length - ? scoreValue(r.score) - : combineStringScores(scores) - if (combined < st.threshold - 1e-9) { - dropped++ - return - } - const na = addNode(a, r.preferredName_A), - nb = addNode(b, r.preferredName_B) - pairs++ - if (st.edgeMode === 'combined') { - lines.push([na, nb, combined.toFixed(3), 'combined']) - } else { - st.channels.forEach((c, i) => { - if (scores[i] > 0) lines.push([na, nb, scores[i].toFixed(3), c[1]]) - }) - } - }) - if (dropped) - notes.push({ - level: 'ok', - text: `Left out ${plural(dropped, 'connection')} whose score from the ticked channels alone is below ${st.threshold.toFixed(2)}.`, - }) - const connected = new Set(lines.flatMap((l) => [l[0], l[1]])) - const lonely = [...nameOf.values()].filter((n) => !connected.has(n)) - if (lonely.length) - notes.push({ - level: 'warn', - text: `${plural(lonely.length, 'protein has', 'proteins have')} no connection that passes the filters and ${lonely.length === 1 ? 'is' : 'are'} not shown: ${listSample(lonely)}.`, - }) - const text = ['Source\tTarget\tWeight\tType', ...lines.map((l) => l.join('\t'))].join('\n') + '\n' - const kept = [...nameOf.entries()].filter(([, n]) => connected.has(n)) - return { - text, - edges: lines, - pairs, - nodeIds: kept.map(([, n]) => n), - stringIds: kept.map(([sid]) => sid), - nameOf: new Map(kept), - nodeAttrs: Object.fromEntries(kept.map(([, n]) => [n, nodeAttrs[n]])), - notes, - } -} diff --git a/frontend/src/string/requests.ts b/frontend/src/string/requests.ts deleted file mode 100644 index 720fa6a..0000000 --- a/frontend/src/string/requests.ts +++ /dev/null @@ -1,160 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { STRING_CALLER, STRING_PRIOR } from '../view3d/export' -import { readTextWithProgress } from '../layouts/controls' - -/* ---------- requests ---------- */ -export const stringState = { busy: false, abort: null, lastCall: 0, versions: new Map() } - -// How requests reach STRING: through server.py's relay (same origin, so no -// cross-site restrictions) or directly from the browser. -export const stringRoute = { mode: null, checked: false } - -export async function resolveStringRoute() { - const choice = document.getElementById('stringConnect').value - if (choice !== 'auto') { - stringRoute.mode = choice - return choice - } - if (stringRoute.checked) return stringRoute.mode - stringRoute.checked = true - stringRoute.mode = 'direct' - if (/^https?:$/.test(location.protocol)) { - try { - const ctl = new AbortController() - const t = setTimeout(() => ctl.abort(), 2500) - const r = await fetch('string-api/ping', { signal: ctl.signal, cache: 'no-store' }) - clearTimeout(t) - const j = r.ok ? await r.json() : null - if (j && j.norma_proxy) stringRoute.mode = 'proxy' - } catch (e) { - /* no relay: go direct */ - } - } - updateStringConnectState() - return stringRoute.mode -} - -export function updateStringConnectState() { - const el = document.getElementById('stringConnectState') - if (!el) return - const choice = document.getElementById('stringConnect').value - const mode = choice === 'auto' ? stringRoute.mode : choice - el.textContent = !mode - ? 'Decided at the first request.' - : mode === 'proxy' - ? 'Requests go through this server to STRING.' - : 'Requests go from the browser straight to STRING.' -} - -export function stringBase() { - const raw = (document.getElementById('stringAddress').value || 'https://string-db.org') - .trim() - .replace(/\/+$/, '') - return /^https?:\/\//i.test(raw) ? raw : 'https://' + raw -} - -export async function stringCall(method, params, { onBytes = null } = {}) { - // one second between calls, as STRING asks - const wait = stringState.lastCall + 1050 - Date.now() - if (wait > 0) await new Promise((r) => setTimeout(r, wait)) - stringState.lastCall = Date.now() - // The body is sent as a plain string: some environments pass fetch - // requests on with postMessage, which can't copy URLSearchParams objects. - const body = new URLSearchParams({ ...params, caller_identity: STRING_CALLER }).toString() - const route = await resolveStringRoute() - const url = - route === 'proxy' - ? `string-api/json/${method}?upstream=${encodeURIComponent(stringBase())}` - : `${stringBase()}/api/json/${method}` - const controller = new AbortController() - stringState.abort = controller - const timer = setTimeout(() => controller.abort(), 90000) - let response - try { - // a form-encoded POST with a plain-text body is a "simple" request: no CORS preflight - response = await fetch(url, { - method: 'POST', - headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }, - body, - signal: controller.signal, - }) - } catch (err) { - if (err.name === 'AbortError') - throw new Error( - stringState.cancelled - ? 'Cancelled.' - : 'STRING did not answer within 90 seconds. Try again, or ask for fewer interactors.' - ) - throw new Error( - route === 'proxy' - ? `The server relay could not be reached (${err.message}). Check that server.py is still running, or choose Connect: Directly.` - : `STRING could not be reached (${err.message}). Check the internet connection. The most reliable setup is to run NORMA with server.py, which passes requests on to STRING; see the README.` - ) - } finally { - clearTimeout(timer) - } - const text = await readTextWithProgress(response, onBytes) - if (!response.ok) { - if (route === 'proxy') { - if (response.status === 502 && /could not be reached from this server/.test(text)) - throw new Error(`${text.slice(0, 200)} Check the server's internet connection.`) - // a plain web server answers relay requests with its own (non-JSON) error page - if (!/^\s*[\[{]/.test(text)) - throw new Error( - 'This server has no STRING relay. Start NORMA with server.py, or choose Connect: Directly.' - ) - } - if (response.status === 404) - throw new Error('STRING found none of the given names for this organism.') - let detail = '' - try { - const j = JSON.parse(text) - detail = (Array.isArray(j) ? j[0] : j)?.message || '' - } catch (e) { - detail = text.slice(0, 160) - } - throw new Error( - `STRING answered with an error (${response.status})${detail ? ': ' + detail : ''}.` - ) - } - try { - return JSON.parse(text) - } catch (e) { - throw new Error('STRING sent an answer that is not JSON. The STRING address may be wrong.') - } -} - -export async function stringVersion() { - const base = stringBase() - if (stringState.versions.has(base)) return stringState.versions.get(base) - try { - const res = await stringCall('version', {}) - const v = Array.isArray(res) ? res[0] : res - const info = { version: v && v.string_version, address: v && v.string_stable_address } - stringState.versions.set(base, info) - return info - } catch (err) { - return { version: null, address: null } - } -} - -/* ---------- scores ---------- */ -// STRING's rule for combining channel scores: remove the prior from each -// channel, combine as independent evidence, then add the prior back. -export function combineStringScores(scores) { - let miss = 1 - scores.forEach((s) => { - if (!(s > 0)) return - const noPrior = Math.max(0, (s - STRING_PRIOR) / (1 - STRING_PRIOR)) - miss *= 1 - noPrior - }) - const combined = 1 - miss - return combined + STRING_PRIOR * (1 - combined) -} - -export function scoreValue(v) { - const x = Number(v) - if (!Number.isFinite(x)) return 0 - return x > 1 ? x / 1000 : x // accept 0-1 or 0-1000 scales -} diff --git a/frontend/src/string/ui_state.ts b/frontend/src/string/ui_state.ts deleted file mode 100644 index 0b8d8c8..0000000 --- a/frontend/src/string/ui_state.ts +++ /dev/null @@ -1,80 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { S } from '../state' -import { STRING_CATEGORIES, STRING_CHANNELS, STRING_SPECIES } from '../view3d/export' -import { libEntry } from '../layouts/controls' -import { stringState } from './requests' - -/* ---------- UI state ---------- */ -export function stringSettings() { - const speciesSel = document.getElementById('stringSpecies').value - const taxon = - speciesSel === 'other' ? document.getElementById('stringTaxon').value.trim() : speciesSel - const preset = document.getElementById('stringScorePreset').value - const threshold = - preset === 'custom' - ? parseFloat(document.getElementById('stringScore').value) - : parseFloat(preset) - return { - names: document - .getElementById('stringQuery') - .value.split(/[\s,;]+/) - .map((s) => s.trim()) - .filter(Boolean), - taxon, - speciesLabel: - speciesSel === 'other' - ? `taxon ${taxon}` - : (STRING_SPECIES.find((s) => String(s[0]) === speciesSel) || [0, speciesSel])[1], - networkType: document.getElementById('stringNetType').value, - addNodes: parseInt(document.getElementById('stringAddNodes').value, 10) || 0, - threshold: Number.isFinite(threshold) ? threshold : 0.4, - channels: STRING_CHANNELS.filter((c) => document.getElementById('stringCh_' + c[1]).checked), - edgeMode: document.getElementById('stringEdgeMode').value, - annotMode: document.getElementById('stringAnnotMode').value, - fdr: parseFloat(document.getElementById('stringFdr').value) || 0.05, - categories: STRING_CATEGORIES.map((c) => c[0]).filter( - (k) => document.getElementById('stringCat_' + k).checked - ), - otherCategories: document.getElementById('stringCatOther').checked, - maxTerms: Math.max(1, parseInt(document.getElementById('stringMaxTerms').value, 10) || 30), - minGroup: Math.max(1, parseInt(document.getElementById('stringMinGroup').value, 10) || 2), - descriptions: document.getElementById('stringDescriptions').checked, - } -} - -export function updateStringUI() { - const st = stringSettings() - document.getElementById('stringTaxonRow').hidden = - document.getElementById('stringSpecies').value !== 'other' - document.getElementById('stringAddNodesValue').textContent = st.addNodes - const preset = document.getElementById('stringScorePreset').value - document.getElementById('stringScoreRow').hidden = preset !== 'custom' - document.getElementById('stringScoreValue').textContent = parseFloat( - document.getElementById('stringScore').value - ).toFixed(2) - document.getElementById('stringFdrRow').hidden = st.annotMode !== 'enrichment' - document.getElementById('stringKeggNote').hidden = st.annotMode !== 'annotation' - const busy = stringState.busy - document.getElementById('btnStringFetch').disabled = busy - document.getElementById('btnStringCancel').hidden = !busy - const view = stringNetworkInView() - document.getElementById('btnStringGroupings').disabled = busy || !view - document.getElementById('btnStringGroupings').title = view - ? `Fetch groupings for "${view.name}" with the settings above` - : 'Show a network imported from STRING in the current view first' - let hint = '' - if (st.names.length === 1 && st.addNodes === 0) - hint = 'With a single protein STRING always adds its 10 best interactors.' - else if (st.names.length > 1 && st.addNodes === 0) - hint = 'Only connections among the given proteins are fetched.' - document.getElementById('stringNodesHint').textContent = hint -} - -// The STRING network shown in the current view, if any. -export function stringNetworkInView() { - if (!S.currentLibView) return null - const ids = S.currentLibView.nets.split('|').filter(Boolean) - const nets = ids.map((id) => libEntry('network', id)).filter((e) => e && e.stringMeta) - return nets.length === 1 ? nets[0] : null -} diff --git a/frontend/src/string/wiring.ts b/frontend/src/string/wiring.ts deleted file mode 100644 index ad3937e..0000000 --- a/frontend/src/string/wiring.ts +++ /dev/null @@ -1,191 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { EDGE_TYPES } from '../palette' -import { STRING_CATEGORIES, STRING_CHANNELS, STRING_SPECIES } from '../view3d/export' -import { escapeHtml } from '../network_state' -import { runStringGroupings } from './groupings' -import { runStringImport } from './import' -import { stringRoute, stringState, updateStringConnectState } from './requests' -import { updateStringUI } from './ui_state' - -/* ============================================================ - ICONS AND WELCOME CARD - Small line icons (16 x 16, drawn in the current text color) for the - page tabs, sidebar tabs and sidebar sections, and the welcome card - shown while the current view is empty. - ============================================================ */ -const ICON_PATHS = { - code: '', - legend: - '', - gauge: - '', - info: '', - home: '', - graph: - '', - cube: '', - chart: - '', - venn: '', - help: '', - database: - '', - sliders: - '', - sparkle: '', - cloud: - '', - folder: - '', - swap: '', - layout: - '', - groups: - '', - fog: '', - palette: - '', - node: '', - tag: '', - edge: '', - layers: '', - list: '', - play: '', - upload: '', -} - -function iconSvg(name) { - const body = ICON_PATHS[name] - if (!body) return '' - return `` -} - -function iconSpan(name) { - const span = document.createElement('span') - span.className = 'ico' - span.innerHTML = iconSvg(name) - return span -} - -// page wiring, run by main.ts in the original order -export function init() { - /* ---------- wiring ---------- */ - ;(function setupStringImporter() { - const sel = document.getElementById('stringSpecies') - STRING_SPECIES.forEach(([id, name]) => sel.add(new Option(name, String(id)))) - sel.add(new Option('Other organism (enter the taxon ID)…', 'other')) - const chBox = document.getElementById('stringChannels') - STRING_CHANNELS.forEach(([, key, label]) => { - const row = document.createElement('label') - row.className = 'string-check' - row.innerHTML = `${escapeHtml(label)}` - chBox.appendChild(row) - }) - const catBox = document.getElementById('stringCategories') - STRING_CATEGORIES.forEach(([key, label, on]) => { - const row = document.createElement('label') - row.className = 'string-check' - row.innerHTML = `${escapeHtml(label)}` - catBox.appendChild(row) - }) - const other = document.createElement('label') - other.className = 'string-check' - other.innerHTML = - 'Any other collection STRING offers' - catBox.appendChild(other) - document.getElementById('stringSection').addEventListener('input', updateStringUI) - document.getElementById('stringSection').addEventListener('change', updateStringUI) - document.getElementById('btnStringFetch').addEventListener('click', runStringImport) - document.getElementById('btnStringGroupings').addEventListener('click', runStringGroupings) - document.getElementById('btnStringCancel').addEventListener('click', () => { - stringState.cancelled = true - if (stringState.abort) stringState.abort.abort() - }) - document.getElementById('stringQuery').addEventListener('keydown', (ev) => { - if (ev.key === 'Enter' && (ev.ctrlKey || ev.metaKey)) { - ev.preventDefault() - runStringImport() - } - }) - document.getElementById('stringConnect').addEventListener('change', () => { - stringRoute.checked = false - stringRoute.mode = null - updateStringConnectState() - }) - updateStringConnectState() - document.getElementById('btnStringCatAll').addEventListener('click', () => { - STRING_CATEGORIES.forEach((c) => { - document.getElementById('stringCat_' + c[0]).checked = true - }) - updateStringUI() - }) - document.getElementById('btnStringCatNone').addEventListener('click', () => { - STRING_CATEGORIES.forEach((c) => { - document.getElementById('stringCat_' + c[0]).checked = false - }) - document.getElementById('stringCatOther').checked = false - updateStringUI() - }) - updateStringUI() - })() - - ;(function addIcons() { - const tabIcons = { - welcome: 'home', - about: 'info', - api: 'code', - network: 'graph', - network3d: 'cube', - profiler: 'chart', - compare: 'venn', - help: 'help', - } - document.querySelectorAll('#tabs .tab').forEach((t) => { - if (tabIcons[t.dataset.tab]) t.prepend(iconSpan(tabIcons[t.dataset.tab])) - }) - const sideIcons = { data: 'upload', db: 'database', display: 'sliders', export: 'swap' } - document - .querySelectorAll('#sideTabs [data-side]') - .forEach((t) => t.prepend(iconSpan(sideIcons[t.dataset.side]))) - const sectionIcons = { - Examples: 'sparkle', - STRING: 'cloud', - Files: 'folder', - 'Open saved work': 'upload', - Reactome: 'cloud', - OmniPath: 'cloud', - NDEx: 'cloud', - IntAct: 'cloud', - 'Gene Ontology': 'cloud', - 'NORMA files': 'folder', - Image: 'palette', - Arena3D: 'cube', - 'Other tools': 'swap', - 'Save your work': 'upload', - '3D layout': 'cube', - Layout: 'layout', - 'Node groups': 'groups', - 'Group highlighting': 'fog', - Colors: 'palette', - Nodes: 'node', - Labels: 'tag', - Edges: 'edge', - 'Edge channels': 'layers', - Attributes: 'list', - Legend: 'legend', - Performance: 'gauge', - } - document.querySelectorAll('.section > h3').forEach((h) => { - const title = [...h.childNodes] - .filter((n) => n.nodeType === 3) - .map((n) => n.textContent) - .join('') - .trim() - if (sectionIcons[title]) h.prepend(iconSpan(sectionIcons[title])) - }) - document.querySelectorAll('.ico[data-icon]').forEach((s) => { - s.innerHTML = iconSvg(s.dataset.icon) - }) - })() -} diff --git a/frontend/src/style.css b/frontend/src/style.css deleted file mode 100644 index 4bcf0dc..0000000 --- a/frontend/src/style.css +++ /dev/null @@ -1,3644 +0,0 @@ -:root { - --bg: #0f1420; - --panel: #161d2e; - --panel-2: #1d2740; - --panel-2-hover: #223050; - --line: #2a3554; - --text: #e7ebf5; - --muted: #8993ad; - --accent: #5fd3c4; - --accent-dim: #3a7d74; - --accent-hover: #7fe0d3; - --accent-text: #08221e; - --warn: #e7a15f; - --canvas-dot: #1c2540; - --mono: 'IBM Plex Mono', 'SFMono-Regular', Consolas, monospace; - --sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; -} -* { - box-sizing: border-box; -} -[hidden] { - display: none !important; -} -#shapePopover { - position: fixed; - z-index: 100; - background: var(--panel); - border: 1px solid var(--line); - border-radius: 8px; - padding: 8px; - box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18); -} -.shape-pop-title { - font-size: 11.5px; - color: var(--muted); - margin: 0 2px 6px; - max-width: 220px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} -.shape-grid { - display: grid; - grid-template-columns: repeat(7, 28px); - gap: 3px; -} -.shape-opt { - width: 28px; - height: 28px; - padding: 5px; - display: flex; - align-items: center; - justify-content: center; -} -.shape-opt svg, -.gshape svg { - width: 100%; - height: 100%; - fill: var(--muted); -} -.shape-opt[aria-selected='true'] { - border-color: var(--accent); - background: var(--panel-2-hover); -} -.shape-opt[aria-selected='true'] svg { - fill: var(--accent); -} -.toggle-row .gshape { - width: 20px; - height: 20px; - padding: 3px; - flex-shrink: 0; - border-radius: 4px; - display: flex; - align-items: center; - justify-content: center; -} -html, -body { - margin: 0; - padding: 0; - height: 100%; - background: var(--bg); - color: var(--text); - font-family: var(--sans); - overflow: hidden; -} -#app { - display: grid; - --side-w: 300px; - position: relative; - grid-template-columns: var(--side-w) minmax(0, 1fr); - grid-template-rows: 52px 42px 36px minmax(0, 1fr); - grid-template-areas: - 'brand viewhead' - 'sidetabs topbar' - 'sidebar ctxbar' - 'sidebar canvas'; - height: 100vh; - width: 100vw; -} -#brand { - grid-area: brand; - display: flex; - align-items: center; - gap: 10px; - padding: 0 18px; - border-bottom: 1px solid var(--line); - border-right: 1px solid var(--line); - background: var(--panel); -} -#brand .dot { - width: 10px; - height: 10px; - border-radius: 50%; - background: var(--accent); - box-shadow: 0 0 10px var(--accent); -} -#brand .title { - font-weight: 600; - font-size: 14.5px; - letter-spacing: 0.2px; -} -#brand .title small { - display: block; - font-size: 10.5px; - color: var(--muted); - font-weight: 400; - margin-top: 1px; -} -#topbar { - grid-area: topbar; - display: flex; - align-items: center; - justify-content: space-between; - padding: 0 18px; - border-bottom: 1px solid var(--line); - background: var(--panel); - gap: 14px; -} -#topbar .group { - display: flex; - align-items: center; - gap: 8px; -} -#search { - background: var(--bg); - border: 1px solid var(--line); - color: var(--text); - padding: 7px 10px; - border-radius: 6px; - font-size: 13px; - width: 220px; - outline: none; -} -#search:focus { - border-color: var(--accent-dim); -} -#stats { - font-size: 12px; - color: var(--muted); - font-family: var(--mono); - white-space: nowrap; - flex-shrink: 0; -} -@media (max-width: 1180px) { - #stats { - font-size: 11px; - } -} -#stats b { - color: var(--text); - font-weight: 600; -} -button { - font-family: var(--sans); - font-size: 12.5px; - background: var(--panel-2); - color: var(--text); - border: 1px solid var(--line); - padding: 7px 12px; - border-radius: 6px; - cursor: pointer; - transition: - border-color 0.15s, - background 0.15s; -} -button:hover { - border-color: var(--accent-dim); - background: var(--panel-2-hover); -} -button.primary { - background: var(--accent); - color: var(--accent-text); - border-color: var(--accent); - font-weight: 600; -} -button.primary:hover { - background: var(--accent-hover); -} -#sidebar { - grid-area: sidebar; - background: var(--panel); - border-right: 1px solid var(--line); - overflow-y: auto; - padding: 16px 16px 40px; -} -#sidebar { - padding-top: 0; -} -.dl-group { - margin: 14px 0 4px; -} -.help-callout { - border: 1px solid color-mix(in srgb, #10b981 45%, var(--line)); - border-left: 4px solid #10b981; - background: color-mix(in srgb, #10b981 8%, var(--panel)); - border-radius: 8px; - padding: 12px 16px; - margin: 8px 0 14px; -} -.help-callout h3 { - margin: 0 0 6px; - font-size: 15px; - color: color-mix(in srgb, #10b981 55%, var(--text)); -} -.help-callout p { - margin: 6px 0; -} -.help-callout-alt { - border-color: color-mix(in srgb, #3b82f6 45%, var(--line)); - border-left-color: #3b82f6; - background: color-mix(in srgb, #3b82f6 8%, var(--panel)); -} -.help-callout-dir { - border-color: color-mix(in srgb, #8b5cf6 45%, var(--line)); - border-left-color: #8b5cf6; - background: color-mix(in srgb, #8b5cf6 8%, var(--panel)); -} -.help-callout-dir h3 { - color: color-mix(in srgb, #8b5cf6 60%, var(--text)); -} -.help-callout-3d { - border-color: color-mix(in srgb, #0ea5e9 45%, var(--line)); - border-left-color: #0ea5e9; - background: color-mix(in srgb, #0ea5e9 8%, var(--panel)); -} -.help-callout-3d h3 { - color: color-mix(in srgb, #0ea5e9 60%, var(--text)); -} -.help-callout-string { - border-color: color-mix(in srgb, #ef4444 40%, var(--line)); - border-left-color: #ef4444; - background: color-mix(in srgb, #ef4444 6%, var(--panel)); -} -.help-callout-string h3 { - color: color-mix(in srgb, #ef4444 60%, var(--text)); -} -.help-callout-alt h3 { - color: color-mix(in srgb, #3b82f6 60%, var(--text)); -} -.help-callout ul { - margin: 6px 0; -} -.help-note { - padding: 8px 12px; - border-left: 3px solid #3b82f6; - background: color-mix(in srgb, #3b82f6 7%, var(--panel)); - border-radius: 6px; -} -.help-body p.cite { - padding-left: 12px; - border-left: 2px solid var(--accent); -} -.dl-group h3 { - margin: 0 0 4px; -} -.dl-refs { - margin: 0 0 6px; - font-size: 12.5px; -} -.dl-list { - margin: 0; - padding-left: 18px; -} -.dl-list li { - margin: 3px 0; -} -.dl-buttons { - white-space: nowrap; -} -.dl-buttons .dl-copy:first-child { - margin-left: 0; -} -.dl-copy { - margin-left: 8px; - padding: 2px 7px; - font-size: 11px; - vertical-align: 1px; -} -#viewBar { - position: sticky; - top: 0; - z-index: 5; - background: var(--panel); - margin: 0 -16px 14px; - padding: 12px 16px 0; - border-bottom: 1px solid var(--line); -} -.viewbar-head { - display: flex; - justify-content: space-between; - align-items: baseline; - margin-bottom: 4px; -} -.viewbar-head label { - font-size: 12px; - font-weight: 600; - color: var(--text); -} -#viewSelect { - font-weight: 600; -} -.view-actions { - margin-top: 6px; -} -.view-actions button { - padding: 5px 8px; - font-size: 11.5px; -} -#sideTabs { - display: flex; - margin-top: 10px; -} -#sideTabs button { - flex: 1; - background: none; - border: none; - border-radius: 0; - border-bottom: 2px solid transparent; - padding: 8px 4px 7px; - font-size: 12.5px; - font-weight: 600; - color: var(--muted); -} -#sideTabs button:hover { - color: var(--text); - background: none; -} -#sideTabs button[aria-selected='true'] { - color: var(--text); - border-bottom-color: var(--accent); -} -.row.stack { - flex-direction: column; - gap: 6px; -} -.seg { - display: flex; - border: 1px solid var(--line); - border-radius: 7px; - padding: 2px; - background: var(--bg); - margin-bottom: 8px; -} -.seg button { - flex: 1; - border: none; - background: none; - border-radius: 5px; - padding: 6px 4px; - font-size: 12px; - font-weight: 600; - color: var(--muted); -} -.seg button:hover { - background: none; - color: var(--text); -} -.seg button[aria-checked='true'] { - background: var(--accent); - color: var(--accent-text); -} -.layout-set { - border: 1px solid var(--line); - border-radius: 7px; - margin: 0 0 8px; - padding: 8px 10px 10px; - min-width: 0; - transition: opacity 0.15s; -} -.layout-set legend { - font-size: 11px; - font-weight: 600; - color: var(--muted); - padding: 0 4px; -} -.layout-set:disabled { - opacity: 0.45; -} -.layout-set:disabled .strategy-fig { - display: none; -} -.layout-set:disabled legend::after { - content: ' (frozen)'; - font-weight: 400; -} -.hint-line { - font-size: 11px; - color: var(--muted); - line-height: 1.4; - margin-top: 4px; -} -#sidebar::-webkit-scrollbar { - width: 8px; -} -#sidebar::-webkit-scrollbar-thumb { - background: var(--line); - border-radius: 4px; -} -.section { - margin-bottom: 22px; -} -.section h3 { - font-size: 11px; - text-transform: uppercase; - letter-spacing: 0.8px; - color: var(--muted); - margin: 0 0 10px; - font-weight: 600; -} -select { - width: 100%; - background: var(--bg); - color: var(--text); - border: 1px solid var(--line); - padding: 8px 10px; - border-radius: 6px; - font-size: 13px; - outline: none; -} -.row { - display: flex; - gap: 8px; - margin-top: 8px; -} -/* buttons in a row share the width equally and may shrink below their - text width, so a row never sticks out of its (padded) section */ -.row > button { - flex: 1 1 0; - min-width: 0; - padding-left: 6px; - padding-right: 6px; -} -.row.three > button { - font-size: 12px; - padding-left: 4px; - padding-right: 4px; -} -input[type='range'] { - width: 100%; - margin-left: 0; - margin-right: 0; - box-sizing: border-box; -} -.toggle-row { - display: flex; - align-items: center; - gap: 9px; - padding: 6px 0; - font-size: 12.5px; - cursor: pointer; - user-select: none; -} -.toggle-row input { - accent-color: var(--accent); - width: 14px; - height: 14px; - cursor: pointer; -} -.swatch { - width: 22px; - height: 3px; - border-radius: 2px; - flex-shrink: 0; -} -input[type='color'].swatch-picker { - -webkit-appearance: none; - appearance: none; - width: 20px; - height: 14px; - flex-shrink: 0; - border: 1px solid var(--line); - padding: 0; - border-radius: 3px; - background: none; - cursor: pointer; -} -input[type='color'].swatch-picker::-webkit-color-swatch-wrapper { - padding: 0; -} -input[type='color'].swatch-picker::-webkit-color-swatch { - border: none; - border-radius: 2px; -} -input[type='color'].swatch-picker::-moz-color-swatch { - border: none; - border-radius: 2px; -} -input[type='color'].swatch-picker.round { - width: 14px; - height: 14px; - border-radius: 50%; -} -input[type='color'].swatch-picker.round::-webkit-color-swatch { - border-radius: 50%; -} -input[type='color'].swatch-picker.round::-moz-color-swatch { - border-radius: 50%; -} -.toggle-row .label { - flex: 1; - color: var(--text); -} -.toggle-row .count { - color: var(--muted); - font-family: var(--mono); - font-size: 11px; -} -#edgeLegend, -#nodeGroupLegend { - max-height: 260px; - overflow-y: auto; - padding-right: 4px; -} -#edgeLegend::-webkit-scrollbar, -#nodeGroupLegend::-webkit-scrollbar { - width: 6px; -} -#edgeLegend::-webkit-scrollbar-thumb, -#nodeGroupLegend::-webkit-scrollbar-thumb { - background: var(--line); - border-radius: 3px; -} -textarea { - width: 100%; - height: 110px; - background: var(--bg); - color: var(--text); - border: 1px solid var(--line); - border-radius: 6px; - font-family: var(--mono); - font-size: 11.5px; - padding: 8px; - resize: vertical; - outline: none; -} -textarea:focus { - border-color: var(--accent-dim); -} -#canvas { - grid-area: canvas; - position: relative; - background: - radial-gradient(circle at 1px 1px, var(--canvas-dot) 1.5px, transparent 0) 0 0/22px 22px, - var(--bg); -} -#groupHullCanvas { - position: absolute; - inset: 0; - pointer-events: none; -} -#cy { - position: absolute; - inset: 0; -} -#cy3d { - position: absolute; - inset: 0; - width: 100%; - height: 100%; - display: block; - cursor: grab; - outline: none; - touch-action: none; -} -#cy3d[hidden] { - display: none !important; -} -#canvas.mode3d #cy, -#canvas.mode3d #groupHullCanvas { - visibility: hidden; -} -#canvas.mode3d { - background: var(--bg); -} -#selectBox3d { - position: absolute; - border: 1px solid var(--accent); - background: color-mix(in srgb, var(--accent) 12%, transparent); - pointer-events: none; -} -#nav3d { - display: flex; - flex-direction: column; - gap: 6px; - margin-top: 4px; - padding-top: 8px; - border-top: 1px solid var(--line); -} -.nav3d-pad { - display: grid; - grid-template-columns: repeat(3, 32px); - gap: 3px; -} -#zoomctl #nav3d button { - width: 32px; - height: 32px; -} -#zoomctl #nav3d #btnAuto3d { - padding: 0 8px; - font-size: 11px; - width: 102px; -} -#zoomctl, -#hint, -#nav3d { - user-select: none; - -webkit-user-select: none; -} -#canvas.mode3d #hint { - left: 132px; -} -#btnAuto3d[aria-pressed='true'] { - background: var(--accent); - color: var(--accent-text); - border-color: var(--accent); -} -#infopanel { - position: absolute; - bottom: 16px; - right: 16px; - width: 280px; - background: var(--panel); - border: 1px solid var(--line); - border-radius: 10px; - padding: 14px 16px; - box-shadow: 0 10px 30px rgba(0, 0, 0, 0.4); - display: none; - max-height: 60%; - overflow-y: auto; -} -#infopanel.show { - display: block; -} -#infopanel h4 { - margin: 0 0 2px; - font-size: 15px; - display: flex; - align-items: center; - gap: 8px; -} -#infopanel .nodedot { - width: 12px; - height: 12px; - border-radius: 50%; - flex-shrink: 0; -} -#infopanel .sub { - font-size: 11px; - color: var(--muted); - margin-bottom: 10px; - font-family: var(--mono); -} -#infopanel .connlist { - font-size: 12px; -} -#infopanel .conn { - display: flex; - justify-content: space-between; - gap: 8px; - padding: 5px 0; - border-top: 1px solid var(--line); -} -#infopanel .conn .ename { - color: var(--muted); -} -#infopanel .close { - position: absolute; - top: 10px; - right: 10px; - background: none; - border: none; - color: var(--muted); - cursor: pointer; - font-size: 16px; - padding: 2px 6px; -} -#edgePopup { - position: absolute; - width: 250px; - max-height: 60%; - overflow-y: auto; - background: var(--panel); - border: 1px solid var(--line); - border-radius: 10px; - padding: 13px 15px; - box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45); - display: none; - z-index: 30; -} -#edgePopup.show { - display: block; -} -#edgePopup .eptitle { - display: flex; - align-items: center; - gap: 8px; - font-weight: 600; - font-size: 13.5px; - margin: 0 0 8px; -} -#edgePopup .epdot { - width: 11px; - height: 11px; - border-radius: 50%; - flex-shrink: 0; -} -#edgePopup .eprow { - display: flex; - justify-content: space-between; - gap: 10px; - padding: 4px 0; - border-top: 1px solid var(--line); - font-size: 12px; - color: var(--muted); -} -#edgePopup .eprow span:last-child { - color: var(--text); - font-family: var(--mono); - font-size: 11px; - text-align: right; -} -#edgePopup .close { - position: absolute; - top: 8px; - right: 8px; - background: none; - border: none; - color: var(--muted); - cursor: pointer; - font-size: 15px; - padding: 2px 6px; -} -#selectionBar { - position: absolute; - top: 12px; - right: 12px; - z-index: 20; - display: flex; - align-items: center; - gap: 6px; - background: var(--panel); - border: 1px solid var(--accent); - border-radius: 8px; - padding: 5px 6px 5px 10px; - font-size: 12px; - box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18); -} -#selectionBar button { - padding: 4px 8px; - font-size: 11.5px; -} -#selectionText { - font-weight: 600; - margin-right: 2px; -} -.undo-group { - display: flex; - gap: 2px; -} -.undo-group button { - width: 32px; - height: 32px; - padding: 0; - display: grid; - place-items: center; -} -.undo-group svg { - width: 16px; - height: 16px; -} -#searchPanel { - position: absolute; - top: 12px; - left: 12px; - z-index: 20; - background: var(--panel); - border: 1px solid var(--line); - border-radius: 8px; - padding: 8px; - box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18); - width: min(400px, calc(100% - 24px)); -} -#searchPanel .search-row { - display: flex; - gap: 6px; - align-items: center; -} -#search { - flex: 1; - min-width: 0; - width: auto; -} -#search[aria-invalid='true'] { - border-color: var(--warn); -} -#searchMode { - width: auto; - flex-shrink: 0; - padding: 7px 8px; - font-size: 12.5px; -} -#searchPanel .search-opts { - margin-top: 6px; - gap: 12px; - font-size: 11.5px; - color: var(--muted); - flex-wrap: wrap; -} -#searchPanel .search-opts label { - display: flex; - align-items: center; - gap: 5px; - cursor: pointer; - user-select: none; -} -#searchPanel .search-opts input { - accent-color: var(--accent); - margin: 0; -} -#searchStatus { - margin-left: auto; - font-family: var(--mono); - font-size: 11px; -} -#searchStatus.error { - color: var(--warn); - font-family: var(--sans); - margin-left: 0; - flex-basis: 100%; -} -#zoomLevel { - font-family: var(--mono); - font-size: 10px; - color: var(--muted); - text-align: center; - padding-top: 2px; -} -#zoomctl button.fit { - font-size: 11px; -} -#hint { - position: absolute; - bottom: 16px; - left: 64px; - font-size: 11.5px; - color: var(--muted); - background: var(--panel); - border: 1px solid var(--line); - padding: 6px 10px; - border-radius: 6px; - pointer-events: none; - box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18); -} -/* NORMA-2.0 strategy schematic (after Fig. 1 of Karatzas et al. 2022) */ -.strategy-fig { - margin: 8px 0 0; - padding: 8px 8px 6px; - background: var(--bg); - border: 1px solid var(--line); - border-radius: 6px; -} -.strategy-fig svg { - display: none; - width: 100%; - height: auto; -} -.strategy-fig svg.on { - display: block; -} -.strategy-fig .e { - stroke: var(--muted); - stroke-width: 1.3; -} -.strategy-fig .e.add { - stroke-dasharray: 3 3; -} -.strategy-fig .e.heavy { - stroke-width: 3; -} -.strategy-fig .e.faint { - opacity: 0.35; -} -.strategy-fig .na { - fill: #e8a15f; -} -.strategy-fig .nb { - fill: #5fd3c4; -} -.strategy-fig .nab { - fill: url(#figSplit); -} -.strategy-fig .n0 { - fill: #9aa0a6; -} -.strategy-fig .vn { - fill: var(--bg); - stroke: var(--text); - stroke-width: 1.3; - stroke-dasharray: 2 2; -} -.strategy-fig .ring { - fill: none; - stroke: var(--line); - stroke-dasharray: 2 3; -} -.strategy-fig .arrow { - fill: none; - stroke: var(--muted); - stroke-width: 1.5; -} -.strategy-fig text { - fill: var(--muted); - font-size: 9.5px; - font-family: var(--sans); -} -.strategy-fig figcaption { - font-size: 11px; - color: var(--muted); - line-height: 1.45; - margin-top: 6px; -} -/* shared key/value row for node, group and edge attributes */ -.kvrow { - display: flex; - justify-content: space-between; - gap: 8px; - padding: 2px 0; -} -.kvrow span:first-child { - color: var(--muted); - flex-shrink: 0; -} -.kvrow span:last-child { - color: var(--text); - text-align: right; - word-break: break-word; -} -.kvhead { - color: var(--muted); - margin-bottom: 3px; -} -#infopanel .desc { - font-size: 12px; - color: var(--text); - line-height: 1.45; - margin: -4px 0 10px; -} -#infopanel .conn.jump { - cursor: pointer; -} -#infopanel .conn.jump:hover span:first-child { - color: var(--accent); -} -.glink { - background: none; - border: none; - padding: 0; - margin: 0; - font: inherit; - color: inherit; - text-decoration: underline dotted; - text-underline-offset: 2px; - cursor: pointer; -} -.glink:hover { - color: var(--accent); - background: none; -} -.toggle-row .ginfo { - width: 18px; - height: 18px; - padding: 0; - flex-shrink: 0; - border-radius: 50%; - font-size: 10.5px; - font-weight: 600; - line-height: 1; - font-family: var(--mono); - color: var(--muted); -} -.toggle-row .ginfo:hover { - color: var(--text); -} -button:focus-visible, -input:focus-visible, -select:focus-visible { - outline: 2px solid var(--accent); - outline-offset: 1px; -} -/* NORMA files */ -.field-label { - font-size: 11px; - color: var(--muted); - display: block; - margin: 10px 0 3px; -} -.select-row { - display: flex; - gap: 6px; -} -.select-row select { - flex: 1; - min-width: 0; -} -.select-row button { - flex-shrink: 0; - padding: 7px 9px; -} -button:disabled { - opacity: 0.45; - cursor: not-allowed; -} -button:disabled:hover { - border-color: var(--line); - background: var(--panel-2); -} -.text-input { - width: 100%; - background: var(--bg); - color: var(--text); - border: 1px solid var(--line); - border-radius: 6px; - padding: 7px 10px; - font-size: 12.5px; - outline: none; -} -.text-input:focus { - border-color: var(--accent-dim); -} -.status { - margin-top: 10px; -} -.status:empty { - display: none; -} -.status:empty { - display: none; -} -.status .note { - font-size: 11.5px; - line-height: 1.45; - padding: 5px 0 5px 10px; - border-left: 2px solid var(--line); - margin-bottom: 4px; - overflow-wrap: anywhere; -} -.status .note.ok { - border-left-color: var(--accent); -} -.status .note.warn { - border-left-color: var(--warn); - color: var(--text); -} -.status .note.error { - border-left-color: var(--warn); - color: var(--warn); - font-weight: 600; -} -.status .note button { - display: block; - margin-top: 6px; -} -.status .note.busy { - border-left-color: var(--muted); - color: var(--muted); -} -.status .note .progress-row { - display: flex; - align-items: center; - gap: 8px; - margin-top: 6px; -} -.status .note .progress { - position: relative; - flex: 1; - height: 6px; - border-radius: 3px; - overflow: hidden; - background: color-mix(in srgb, var(--muted) 22%, transparent); -} -.status .note .progress > span { - position: absolute; - top: 0; - bottom: 0; - left: 0; - width: 0; - border-radius: 3px; - background: var(--accent); - transition: width 0.25s ease; -} -.status .note .progress.indeterminate > span { - width: 35%; - animation: progress-slide 1.3s ease-in-out infinite; -} -.status .note .progress-pct { - font-family: var(--mono); - font-size: 11px; - min-width: 3.2em; - text-align: right; - color: var(--text); -} -@keyframes progress-slide { - from { - transform: translateX(-100%); - } - to { - transform: translateX(290%); - } -} -@media (prefers-reduced-motion: reduce) { - .status .note .progress.indeterminate > span { - animation: none; - width: 100%; - opacity: 0.45; - } - .status .note .progress > span { - transition: none; - } -} - -/* sidebar structure */ -.section h3 { - display: flex; - align-items: center; - justify-content: space-between; -} -.helplink { - width: 18px; - height: 18px; - padding: 0; - border-radius: 50%; - font-size: 10.5px; - line-height: 1; - font-weight: 600; - color: var(--muted); - background: transparent; - letter-spacing: 0; - text-transform: none; -} -.helplink:hover { - color: var(--text); -} -.slider-label { - font-size: 11px; - color: var(--muted); - display: flex; - justify-content: space-between; - margin-top: 8px; -} -input[type='range'] { - width: 100%; - accent-color: var(--accent); -} -.num-input { - width: 100%; - background: var(--bg); - color: var(--text); - border: 1px solid var(--line); - border-radius: 6px; - padding: 6px 8px; - font-size: 12.5px; -} -.upload-box { - border: 1px dashed var(--line); - border-radius: 8px; - padding: 8px; - transition: - border-color 0.15s, - background 0.15s; -} -.upload-box.dragging { - border-color: var(--accent); - background: var(--panel-2); -} -.drop-hint { - font-size: 11px; - color: var(--muted); - text-align: center; - margin-top: 6px; -} -.lib-head { - display: flex; - justify-content: space-between; - align-items: baseline; - font-size: 12px; - font-weight: 600; - margin: 12px 0 4px; -} -.lib-hint { - font-size: 11px; - color: var(--muted); - font-weight: 400; -} -.lib-list { - max-height: 176px; - overflow-y: auto; - border: 1px solid var(--line); - border-radius: 6px; - background: var(--bg); -} -.lib-row { - display: flex; - align-items: center; - gap: 8px; - padding: 5px 4px 5px 8px; - font-size: 12px; - cursor: pointer; - border-top: 1px solid var(--line); -} -.lib-row:first-child { - border-top: none; -} -.lib-row:hover { - background: var(--panel-2); -} -.lib-row input { - accent-color: var(--accent); - margin: 0; - flex-shrink: 0; - cursor: pointer; -} -.lib-text { - flex: 1; - min-width: 0; -} -.lib-name { - display: block; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} -.lib-meta { - display: block; - font-size: 10.5px; - color: var(--muted); - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} -.lib-remove { - flex-shrink: 0; - width: 22px; - height: 22px; - padding: 0; - background: transparent; - border-color: transparent; - color: var(--muted); - font-size: 12px; -} -.lib-remove:hover { - color: var(--warn); - border-color: var(--line); -} -.lib-empty { - font-size: 11.5px; - color: var(--muted); - padding: 7px 8px; -} -.refresh-hint { - font-size: 11px; - color: var(--warn); - margin-top: 5px; -} -#btnRefreshView.pending { - box-shadow: - 0 0 0 2px var(--panel), - 0 0 0 3px var(--warn); -} - -/* tabs */ -#tabs { - display: flex; - gap: 2px; - height: 100%; - align-items: stretch; -} -.tab { - background: none; - border: none; - border-radius: 0; - border-bottom: 2px solid transparent; - padding: 0 12px; - font-size: 13px; - color: var(--muted); -} -.tab:hover { - background: none; - color: var(--text); - border-color: transparent; - border-bottom-color: var(--line); -} -.tab[aria-selected='true'] { - color: var(--text); - border-bottom-color: var(--accent); - font-weight: 600; -} -#topTools { - margin-right: auto; - margin-left: 10px; -} -#topbar { - padding: 0 18px 0 8px; -} - -/* full-page views */ -.page { - grid-area: canvas; - overflow-y: auto; - background: var(--bg); - display: none; -} -.page.active { - display: block; -} -#canvas.inactive { - display: none; -} -.page-inner { - max-width: 1180px; - padding: 26px 32px 64px; -} -.page-head h2 { - margin: 0 0 6px; - font-size: 20px; - font-weight: 600; -} -.page-head p { - margin: 0 0 18px; - color: var(--muted); - font-size: 13px; - line-height: 1.5; - max-width: 72ch; -} - -/* profiler */ -.prof-controls { - display: flex; - gap: 18px; - align-items: flex-end; - flex-wrap: wrap; -} -.prof-netlist { - display: flex; - flex-wrap: wrap; - gap: 6px; - max-width: 760px; -} -.prof-netlist label { - display: flex; - align-items: center; - gap: 6px; - border: 1px solid var(--line); - border-radius: 6px; - background: var(--panel); - padding: 5px 9px; - font-size: 12px; - cursor: pointer; -} -.prof-netlist input { - accent-color: var(--accent); - margin: 0; -} -.prof-actions .toggle-row { - margin: 0 6px 0 0; -} -.prof-actions { - display: flex; - gap: 8px; -} -.prof-section { - margin-top: 28px; -} -.prof-section h3 { - font-size: 14px; - font-weight: 600; - margin: 0 0 10px; -} -.prof-section .sub { - font-size: 12px; - color: var(--muted); - margin: -4px 0 10px; -} -.table-wrap { - overflow-x: auto; - border: 1px solid var(--line); - border-radius: 8px; - background: var(--panel); -} -table.data { - border-collapse: collapse; - width: 100%; - font-size: 12.5px; -} -table.data th, -table.data td { - padding: 6px 12px; - border-bottom: 1px solid var(--line); - text-align: right; - white-space: nowrap; -} -table.data th:first-child, -table.data td:first-child { - text-align: left; -} -table.data thead th { - font-weight: 600; - background: var(--panel-2); - position: sticky; - top: 0; -} -table.data tbody tr:last-child td { - border-bottom: none; -} -table.data td.num { - font-family: var(--mono); - font-size: 12px; -} -table.data td .stat-desc { - display: block; - font-size: 11px; - color: var(--muted); - line-height: 1.35; - max-width: 34ch; - white-space: normal; - margin-top: 1px; -} -.cards { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); - gap: 14px; -} -.card { - border: 1px solid var(--line); - border-radius: 8px; - background: var(--panel); - padding: 12px 14px; - min-width: 0; -} -.card h4 { - margin: 0 0 8px; - font-size: 13px; - font-weight: 600; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} -.card .meta { - font-size: 11.5px; - color: var(--muted); - margin: 0 0 8px; - line-height: 1.45; -} -.chart svg { - display: block; - width: 100%; - height: auto; -} -.chart .bar { - fill: var(--accent); -} -.chart .dot { - fill: var(--accent); -} -.chart .axis { - stroke: var(--line); -} -.chart text { - fill: var(--muted); - font-size: 10px; - font-family: var(--sans); -} -.inline-controls { - display: flex; - gap: 14px; - align-items: center; - font-size: 12px; - margin-bottom: 10px; - flex-wrap: wrap; -} -.inline-controls label { - display: flex; - gap: 6px; - align-items: center; - cursor: pointer; -} -.inline-controls select { - width: auto; -} -.linkish { - background: none; - border: none; - padding: 0; - color: var(--text); - font: inherit; - text-decoration: underline dotted; - text-underline-offset: 2px; - cursor: pointer; -} -.linkish:hover { - background: none; - color: var(--accent); -} -.size-strip { - display: flex; - height: 10px; - border-radius: 3px; - overflow: hidden; - margin: 6px 0 10px; - background: var(--panel-2); -} -.size-strip span { - display: block; - height: 100%; - border-right: 1px solid var(--panel); -} - -/* help */ -.help-layout { - display: grid; - grid-template-columns: 220px minmax(0, 1fr); - gap: 28px; - padding: 26px 32px 80px; - max-width: 1100px; -} -.help-nav { - position: sticky; - top: 20px; - align-self: start; - display: flex; - flex-direction: column; - gap: 1px; - max-height: calc(100vh - 170px); - overflow-y: auto; - overscroll-behavior: contain; - padding-right: 6px; - scrollbar-width: thin; -} -.help-nav a { - flex-shrink: 0; -} -.help-nav-group { - margin: 14px 0 4px; - padding: 0 10px; - font-size: 10.5px; - font-weight: 700; - letter-spacing: 0.06em; - text-transform: uppercase; - color: var(--muted); - flex-shrink: 0; -} -.help-nav-group:first-child { - margin-top: 0; -} -.help-nav .help-nav-about { - color: var(--accent); -} -.cite-box { - margin: 0 0 18px; - padding: 14px 18px; - border-radius: 10px; - border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--line)); - border-left: 5px solid var(--accent); - background: color-mix(in srgb, var(--accent) 8%, var(--panel)); -} -.cite-box > b { - display: block; - font-size: 15px; - margin-bottom: 4px; -} -.cite-list { - margin: 6px 0 8px; - padding-left: 20px; -} -.cite-list li { - margin: 6px 0; - font-size: 13px; - line-height: 1.5; - padding-left: 2px; -} -.cite-list li::marker { - color: var(--accent); -} -.cite-note { - color: var(--muted); - font-size: 12px; -} -.cite-box p { - margin: 6px 0; - font-size: 13px; - line-height: 1.5; -} -.cite-box .cite-more { - color: var(--muted); - font-size: 12.5px; -} -.about-cite-box h2 { - margin-top: 0 !important; -} -.help-nav .help-nav-cite { - font-weight: 600; - color: var(--accent); - margin-bottom: 4px; -} -.api-title { - margin: 0 0 8px; - font-size: 26px; -} -.api-ways { - margin: 12px 0 8px; -} -.api-base { - color: var(--muted); - font-size: 13px; -} -.api-code-wrap { - position: relative; - margin: 8px 0 14px; -} -.api-code { - margin: 0; - padding: 12px 14px; - border-radius: 8px; - background: var(--panel-2, var(--panel)); - border: 1px solid var(--line); - overflow-x: auto; - font-size: 12.5px; - line-height: 1.5; -} -.api-copy { - position: absolute; - top: 6px; - right: 6px; - padding: 2px 10px; - font-size: 11.5px; - z-index: 1; -} -.api-payload { - width: 100%; - min-height: 300px; - font-family: var(--mono); - font-size: 12.5px; - line-height: 1.45; -} -.api-actions { - display: flex; - flex-wrap: wrap; - gap: 8px; - margin: 10px 0; -} -.api-result { - display: flex; - gap: 8px; - align-items: center; - margin: 6px 0; -} -.api-result input { - flex: 1; - font-family: var(--mono); - font-size: 12px; -} -.help-part { - margin: 34px 0 -6px; - padding-top: 14px; - border-top: 2px solid var(--line); - font-size: 11.5px; - font-weight: 700; - letter-spacing: 0.08em; - text-transform: uppercase; - color: var(--accent); -} -.help-intro { - font-size: 14px; - color: var(--muted); -} -.brand-home { - display: inline-flex; - border-radius: 6px; -} -.brand-home:hover .brand-logo { - filter: brightness(1.06); -} -.brand-home:focus-visible { - outline: 2px solid var(--accent); - outline-offset: 2px; -} -.about-layout { - max-width: 960px; - margin: 0 auto; - padding: 28px 32px 60px; - line-height: 1.6; - font-size: 14px; -} -.about-layout h2 { - margin: 34px 0 10px; - font-size: 20px; - scroll-margin-top: 12px; -} -.about-layout h3 { - margin: 18px 0 6px; - font-size: 15px; -} -.about-hero { - display: flex; - align-items: center; - gap: 24px; - margin-bottom: 14px; -} -.about-hero h1 { - margin: 0 0 6px; - font-size: 26px; -} -.about-hero h1 span { - font-weight: 500; - color: var(--muted); - font-size: 18px; - margin-left: 6px; -} -.about-hero p { - margin: 0; - color: var(--muted); - max-width: 70ch; -} -.about-logo { - flex-shrink: 0; -} -.about-logo-svg { - height: 84px !important; - width: auto; -} -.about-toc { - display: flex; - flex-wrap: wrap; - gap: 6px; - margin: 10px 0 16px; -} -.about-toc a { - padding: 4px 10px; - border-radius: 999px; - border: 1px solid var(--line); - background: var(--panel); - font-size: 12px; - text-decoration: none; - color: var(--text); -} -.about-toc a:hover { - border-color: var(--accent); -} -.about-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); - gap: 10px; -} -.about-card { - display: flex; - flex-direction: column; - gap: 4px; - padding: 12px 14px; - border-radius: 10px; - border: 1px solid var(--line); - background: var(--panel); - border-top: 3px solid var(--accent); -} -.about-card span { - color: var(--muted); - font-size: 12.5px; - line-height: 1.45; -} -.about-layout h2.flash { - animation: flash 1.2s ease-out; -} -@media (max-width: 760px) { - .about-hero { - flex-direction: column; - align-items: flex-start; - } -} -.help-nav a { - color: var(--muted); - text-decoration: none; - font-size: 12.5px; - padding: 4px 10px; - border-left: 2px solid var(--line); -} -.help-nav a:hover, -.help-nav a.current { - color: var(--text); - border-left-color: var(--accent); -} -.help-body { - max-width: 74ch; - font-size: 14px; - line-height: 1.6; -} -.help-body h2 { - font-size: 18px; - font-weight: 600; - margin: 34px 0 8px; - scroll-margin-top: 16px; -} -.help-body h2:first-child { - margin-top: 0; -} -.help-body h3 { - font-size: 14px; - font-weight: 600; - margin: 18px 0 4px; -} -.help-body p, -.help-body li { - color: var(--text); -} -.help-body a, -.about-layout a { - color: var(--accent); -} -.help-body code { - font-family: var(--mono); - font-size: 12.5px; - background: var(--panel-2); - padding: 1px 4px; - border-radius: 3px; -} -.help-body pre { - font-family: var(--mono); - font-size: 12px; - line-height: 1.5; - background: var(--panel); - border: 1px solid var(--line); - border-radius: 6px; - padding: 10px 12px; - overflow-x: auto; - tab-size: 12; -} -.help-body h2.flash { - animation: flash 1.2s ease-out; -} -@keyframes flash { - from { - color: var(--accent); - } - to { - color: var(--text); - } -} -.help-table { - border-collapse: collapse; - font-size: 12.5px; - line-height: 1.45; - margin: 8px 0 12px; - width: 100%; -} -.help-table th, -.help-table td { - text-align: left; - vertical-align: top; - padding: 6px 10px 6px 0; - border-bottom: 1px solid var(--line); -} -.help-table th { - font-weight: 600; -} -.help-table code { - font-size: 11px; -} -@media (prefers-reduced-motion: reduce) { - .help-body h2.flash { - animation: none; - } -} -@media (max-width: 900px) { - .help-layout { - grid-template-columns: 1fr; - padding: 18px; - } - .help-nav { - position: static; - flex-direction: row; - flex-wrap: wrap; - } -} -#attrSchema .schema-block { - margin-bottom: 10px; -} -#attrSchema .schema-head { - display: flex; - justify-content: space-between; - font-size: 12px; - font-weight: 600; - padding-bottom: 3px; - border-bottom: 1px solid var(--line); - margin-bottom: 3px; -} -#attrSchema .schema-head span { - color: var(--muted); - font-weight: 400; - font-family: var(--mono); - font-size: 11px; -} -#attrSchema .schema-row { - display: grid; - grid-template-columns: minmax(0, 1fr) auto; - gap: 0 8px; - padding: 3px 0; - font-size: 12px; -} -#attrSchema .schema-row .k { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} -#attrSchema .schema-row .cov { - color: var(--muted); - font-family: var(--mono); - font-size: 11px; - text-align: right; -} -#attrSchema .schema-row .kind { - grid-column: 1 / -1; - color: var(--muted); - font-size: 11px; -} -#attrSchema .schema-empty { - font-size: 11.5px; - color: var(--muted); - margin: 0 0 4px; -} -#zoomctl { - position: absolute; - bottom: 16px; - left: 16px; - display: flex; - flex-direction: column; - gap: 6px; -} -#zoomctl button { - width: 32px; - height: 32px; - padding: 0; - font-size: 16px; - line-height: 1; - border-radius: 8px; -} - -/* ---------- comparison page ---------- */ -.cmp-controls { - display: flex; - gap: 18px; - align-items: flex-end; - flex-wrap: wrap; -} -.cmp-pick { - flex: 1; - min-width: 320px; -} -.cmp-count { - color: var(--muted); - font-weight: 400; - margin-left: 6px; -} -.cmp-netlist { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); - gap: 4px 12px; - padding: 10px 12px; - border: 1px solid var(--line); - border-radius: 8px; - background: var(--panel); - max-height: 240px; - overflow-y: auto; -} -.cmp-group-head { - grid-column: 1 / -1; - font-size: 11px; - font-weight: 600; - color: var(--muted); - margin-top: 4px; -} -.cmp-option { - display: flex; - gap: 7px; - align-items: flex-start; - font-size: 12.5px; - cursor: pointer; - padding: 3px 0; - min-width: 0; -} -.cmp-option input { - margin-top: 2px; - accent-color: var(--accent); -} -.cmp-option input:disabled + span { - opacity: 0.45; -} -.cmp-name { - display: block; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} -.cmp-meta { - display: block; - font-size: 11px; - color: var(--muted); -} -.cmp-overview { - display: flex; - gap: 10px; - flex-wrap: wrap; -} -.cmp-card { - display: flex; - gap: 10px; - align-items: center; - min-width: 200px; - max-width: 280px; - flex: 1; - padding: 8px 12px; - border-radius: 8px; - background: color-mix(in srgb, var(--c) 9%, var(--panel)); - border: 1px solid color-mix(in srgb, var(--c) 35%, var(--line)); -} -.cmp-letter { - width: 26px; - height: 26px; - border-radius: 50%; - background: var(--c); - color: #fff; - font-weight: 700; - display: flex; - align-items: center; - justify-content: center; - flex-shrink: 0; -} -.cmp-card-body { - min-width: 0; -} -.cmp-card-name { - font-weight: 600; - font-size: 13px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} -.cmp-card-meta { - font-size: 11.5px; - color: var(--muted); -} -.cmp-legend { - display: flex; - gap: 14px; - flex-wrap: wrap; - font-size: 12px; - margin: 0 0 8px; -} -.cmp-legend i, -.cmp-matrix i, -.cmp-topo i { - display: inline-block; - width: 10px; - height: 10px; - border-radius: 50%; - margin-right: 5px; - vertical-align: -1px; -} -.cmp-row { - display: flex; - gap: 14px; - flex-wrap: wrap; - align-items: flex-start; -} -.cmp-venn { - flex: 0 0 340px; -} -.cmp-upset { - flex: 1 1 420px; - overflow-x: auto; -} -.cmp-ccdf { - max-width: 620px; -} -.chart .venn-count { - fill: var(--text); - font-size: 13px; - font-weight: 600; -} -.chart .venn-set { - font-size: 12px; - font-weight: 600; -} -.chart .upset-num { - fill: var(--text); - font-size: 9.5px; -} -.chart .upset-set { - fill: var(--text); - font-size: 11px; -} -.chart .upset-on { - fill: var(--text); -} -.chart .upset-off { - fill: var(--line); -} -.chart .upset-link { - stroke: var(--text); - stroke-width: 2; -} -.chart .upset-stripe { - fill: color-mix(in srgb, var(--text) 4%, transparent); -} -.cmp-subhead { - margin: 16px 0 2px; - font-size: 13px; -} -.cmp-matrix { - border-collapse: collapse; - font-size: 12.5px; - margin-top: 6px; -} -.cmp-matrix th, -.cmp-matrix td { - border: 1px solid var(--line); - padding: 6px 10px; - text-align: center; - min-width: 52px; -} -.cmp-matrix th { - background: var(--panel); - font-weight: 600; -} -.cmp-matrix td { - font-family: var(--mono); -} -.cmp-matrix td.na { - color: var(--muted); -} -.cmp-topo th.cmp-rowhead { - text-align: left; - font-size: 11px; - text-transform: uppercase; - letter-spacing: 0.6px; - color: var(--muted); - background: var(--panel); -} -.cmp-topo td.cmp-max { - font-weight: 700; - color: color-mix(in srgb, #2563eb 70%, var(--text)); -} - -/* ---------- search panel collapse ---------- */ -#searchPanel .search-toggle { - flex-shrink: 0; - min-width: 28px; - height: 28px; - padding: 0 7px; - display: flex; - align-items: center; - justify-content: center; - gap: 6px; -} -#searchPanel .search-toggle svg, -#searchPanel .search-min svg { - width: 14px; - height: 14px; - flex-shrink: 0; -} -#searchPanel .search-min { - flex-shrink: 0; - width: 28px; - height: 28px; - padding: 0; - display: flex; - align-items: center; - justify-content: center; -} -#searchPanel .search-toggle-text { - display: none; - font-size: 12.5px; - font-weight: 600; -} -#searchPanel.collapsed { - width: auto; - padding: 5px; -} -#searchPanel.collapsed .search-row > :not(.search-toggle), -#searchPanel.collapsed .search-opts { - display: none; -} -#searchPanel.collapsed .search-toggle-text { - display: inline; -} -#searchPanel .search-badge { - display: none; - font-size: 11px; - font-family: var(--mono); - color: var(--muted); -} -#searchPanel.collapsed .search-badge:not(:empty) { - display: inline; -} - -/* ---------- label color controls ---------- */ -.label-color-row { - display: flex; - gap: 6px; - align-items: center; -} -.label-color-row select { - flex: 1; - min-width: 0; -} -.label-color-row input[type='color'] { - width: 34px; - height: 32px; - padding: 2px; - border: 1px solid var(--line); - border-radius: 6px; - background: var(--bg); - flex-shrink: 0; -} -.info-shapes { - display: flex; - flex-wrap: wrap; - gap: 3px; - margin: 4px 0 10px; -} -.info-shapes .shape-opt { - width: 24px; - height: 24px; - padding: 4px; -} - -/* ---------- brand, banner, empty state, icons ---------- */ -#brand .dot { - display: none; -} -.brand-logo { - height: 38px; - width: auto; - flex-shrink: 0; - display: block; - margin-left: -4px; -} -.brand-logo .lg-edge { - stroke: var(--text); - opacity: 0.88; -} -.brand-logo .lg-ring { - stroke: var(--panel); -} -#brand .title { - display: flex; - flex-direction: column; - line-height: 1.1; -} -.brand-version { - font-size: 12px; - font-weight: 700; - color: var(--accent); -} -.norma-banner { - width: 100%; - height: auto; - display: block; - --bn-card: var(--panel); - --bn-line: var(--line); - --bn-edge: var(--muted); - --bn-stroke: var(--bg); - --bn-accent: var(--accent); - font-family: var(--sans); -} -.norma-banner .bn-cap { - font-size: 15px; - font-weight: 700; - fill: var(--text); -} -.norma-banner .bn-sub { - font-size: 12px; - fill: var(--muted); -} -.norma-banner .bn-tick { - font-size: 10px; - fill: var(--muted); -} -.help-banner { - margin: 0 0 18px; - width: min(920px, calc(100vw - 560px)); - max-width: none; -} -#emptyState { - position: absolute; - inset: 0; - display: flex; - align-items: center; - justify-content: center; - padding: 24px; - z-index: 3; - pointer-events: none; -} -#emptyState[hidden] { - display: none !important; -} -.welcome-page { - min-height: 100%; - display: flex; - align-items: flex-start; - justify-content: center; - padding: 28px 24px 40px; -} -.welcome-page .welcome { - max-height: none; - overflow: visible; -} -.empty-card.compact { - max-width: 560px; - padding: 20px 24px; -} -.empty-card.compact h2 { - margin-top: 0; -} -.welcome { - pointer-events: auto; - width: min(1080px, 100%); - max-height: 100%; - overflow: auto; - background: color-mix(in srgb, var(--panel) 95%, transparent); - border: 1px solid var(--line); - border-radius: 18px; - padding: 22px 28px 18px; - box-shadow: 0 18px 50px rgba(0, 0, 0, 0.12); -} -.welcome-head { - display: flex; - align-items: center; - gap: 22px; - margin-bottom: 12px; -} -.welcome-logo-svg { - height: 72px !important; - width: auto; -} -.welcome-title h1 { - margin: 0 0 4px; - font-size: 22px; - letter-spacing: 0.2px; -} -.welcome-title p { - margin: 0; - color: var(--muted); - font-size: 13.5px; - line-height: 1.5; - max-width: 70ch; -} -.welcome .empty-banner { - margin: 6px 0 12px; -} -.welcome-steps { - list-style: none; - counter-reset: step; - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 10px; - padding: 0; - margin: 0 0 14px; -} -.welcome-steps li { - counter-increment: step; - display: flex; - flex-direction: column; - gap: 2px; - padding: 10px 12px 10px 44px; - position: relative; - border-radius: 10px; - background: var(--bg); - border: 1px solid var(--line); - font-size: 13px; -} -.welcome-steps li::before { - content: counter(step); - position: absolute; - left: 12px; - top: 10px; - width: 22px; - height: 22px; - border-radius: 50%; - background: var(--accent); - color: #fff; - font-weight: 700; - font-size: 12px; - display: flex; - align-items: center; - justify-content: center; -} -.welcome-steps span { - color: var(--muted); - font-size: 12px; -} -button.danger { - background: #dc2626; - border-color: #dc2626; - color: #fff; - font-weight: 600; -} -button.danger:hover { - background: #b91c1c; - border-color: #b91c1c; -} -.danger-link { - background: none; - border: none; - color: var(--muted); - font-size: 12px; - padding: 2px 0; - margin-left: auto; - text-decoration: underline; -} -.danger-link:hover { - color: #dc2626; - background: none; -} -.danger-link:disabled { - opacity: 0.5; - text-decoration: none; -} -.lib-danger-row { - margin-top: 4px; -} -.delete-text p { - margin: 0 0 8px; - font-size: 13px; - line-height: 1.5; -} -.delete-choices { - margin: 4px 0 12px; - padding: 8px 10px; - border: 1px solid var(--line); - border-radius: 8px; - background: var(--bg); -} -.delete-choices label { - display: flex; - gap: 8px; - align-items: flex-start; - padding: 4px 0; - font-size: 13px; - cursor: pointer; -} -.delete-choices label small { - display: block; - color: var(--muted); - font-size: 11.5px; -} -.icon-del { - padding: 2px 7px; - min-width: 0; - line-height: 1.2; - color: var(--muted); -} -.icon-del:not(:disabled):hover { - color: #dc2626; - border-color: #dc2626; -} -.del-btn:hover { - color: #dc2626; - border-color: #dc2626; -} -#deleteDialog { - width: min(520px, calc(100vw - 32px)); -} -.list-empty { - margin: 0; - padding: 6px 2px; - font-size: 12.5px; - line-height: 1.45; - color: var(--muted); -} -.group-tools { - display: flex; - gap: 8px; - align-items: center; - margin-top: 6px; -} -.group-tools label { - font-size: 12px; - color: var(--muted); - flex-shrink: 0; -} -.group-tools select { - flex: 1; - min-width: 0; -} -.site-footer { - margin: 14px 0 0; - text-align: center; - font-size: 12px; - line-height: 1.7; - color: var(--text); -} -.site-footer .dot { - margin: 0 7px; - color: var(--muted); -} -.site-footer a { - color: var(--accent); -} -#siteNotice { - position: fixed; - left: 50%; - top: 8px; - transform: translateX(-50%); - z-index: 50; - max-width: min(760px, 92vw); - display: flex; - gap: 12px; - align-items: center; - padding: 8px 12px 8px 16px; - border-radius: 10px; - background: #fef3c7; - color: #78350f; - border: 1px solid #f59e0b; - box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15); - font-size: 13px; -} -#siteNotice[hidden] { - display: none; -} -#siteNotice button { - padding: 2px 8px; - background: transparent; - border-color: #d97706; - color: #78350f; -} -.api-template-box { - margin-top: 6px; -} -.api-template-usage { - margin-left: 8px; - font-size: 12px; - color: var(--muted); -} -.api-caption { - caption-side: top; - text-align: left; - font-weight: 600; - padding: 0 0 6px; -} -.dl-name { - margin-left: 8px; - font-family: var(--mono); - font-size: 11px; - color: var(--muted); -} -.welcome-foot { - margin: 12px 0 0; - text-align: center; - color: var(--muted); - font-size: 11.5px; -} -#canvas.is-empty #searchPanel, -#canvas.is-empty #zoomctl, -#canvas.is-empty #hint, -#canvas.is-empty #nav3d, -#canvas.is-empty #frameBadge, -#canvas.is-empty #legendPanel { - display: none !important; -} -@media (max-width: 900px) { - .welcome-steps { - grid-template-columns: 1fr; - } - .welcome-head { - flex-direction: column; - align-items: flex-start; - } -} -.empty-card { - pointer-events: auto; - max-width: 980px; - width: 100%; - background: color-mix(in srgb, var(--panel) 92%, transparent); - border: 1px solid var(--line); - border-radius: 16px; - padding: 22px 26px; - box-shadow: 0 18px 50px rgba(0, 0, 0, 0.12); - text-align: center; -} -.empty-card h2 { - margin: 14px 0 4px; - font-size: 20px; -} -.empty-card p { - margin: 0 auto 14px; - color: var(--muted); - max-width: 62ch; - font-size: 13.5px; - line-height: 1.5; -} -.empty-actions { - display: flex; - gap: 8px; - justify-content: center; - flex-wrap: wrap; -} -.empty-actions button { - display: inline-flex; - align-items: center; - gap: 7px; - padding: 8px 14px; -} -.ico { - display: inline-flex; - width: 15px; - height: 15px; - flex-shrink: 0; -} -.ico svg { - width: 100%; - height: 100%; -} -.section > h3 .ico { - margin-right: 7px; - width: 14px; - height: 14px; - color: color-mix(in srgb, var(--tint) 75%, var(--text)); -} -.section > h3 { - justify-content: flex-start; -} -.section > h3 .helplink { - margin-left: auto; -} -.tab .ico, -#sideTabs .ico { - margin-right: 6px; - vertical-align: -2px; - opacity: 0.85; -} -#sideTabs button { - display: inline-flex; - align-items: center; - justify-content: center; -} -.string-brand { - display: flex; - align-items: center; - gap: 8px; - margin: -2px 0 10px; - text-decoration: none; - color: var(--muted); -} -.string-brand img { - height: 28px; - width: auto; - display: block; -} -.string-wordmark { - font-weight: 800; - letter-spacing: 1.5px; - font-size: 15px; - color: var(--text); - padding: 2px 8px; - border: 1.5px solid var(--line); - border-radius: 6px; -} -.string-tag { - font-size: 10.5px; - line-height: 1.25; -} -/* ---------- numeric values, legend, separation, benchmark ---------- */ -.value-box { - margin-top: 8px; - padding: 8px 10px; - border-radius: 6px; - border: 1px dashed color-mix(in srgb, var(--tint) 35%, var(--line)); -} -.value-scale-preview { - height: 10px; - border-radius: 3px; - margin-top: 6px; - border: 1px solid var(--line); -} -.inline-num { - display: flex; - align-items: center; - gap: 6px; - font-size: 12px; - color: var(--muted); - white-space: nowrap; -} -.inline-num .num-input { - width: 80px; -} -.inline-color { - display: flex; - align-items: center; - gap: 8px; - font-size: 12px; - color: var(--muted); - margin-top: 8px; -} -.inline-color input { - width: 34px; - height: 24px; - padding: 1px; - border: 1px solid var(--line); - border-radius: 4px; - background: var(--bg); -} -#legendPanel { - position: absolute; - right: 16px; - bottom: 16px; - z-index: 4; - background: color-mix(in srgb, var(--panel) 94%, transparent); - border: 1px solid var(--line); - border-radius: 8px; - box-shadow: 0 4px 14px rgba(0, 0, 0, 0.14); - max-height: calc(100% - 140px); - overflow: auto; -} -#legendPanel[hidden] { - display: none; -} -#canvas:has(#infopanel.show) #legendPanel, -#canvas:has(#edgePopup.show) #legendPanel { - display: none; -} -#legendPanel svg { - display: block; -} -.sep-box { - margin-top: 12px; - padding: 8px 10px; - border-radius: 6px; - background: var(--panel); - border: 1px solid color-mix(in srgb, var(--tint) 25%, var(--line)); -} -.sep-head { - display: flex; - align-items: center; - justify-content: space-between; - font-size: 12px; - font-weight: 600; - margin-bottom: 4px; -} -.sep-row { - display: grid; - grid-template-columns: 1fr auto; - align-items: center; - gap: 2px 8px; - font-size: 12px; - color: var(--muted); - padding: 1px 0; -} -.sep-row b { - color: var(--text); - font-family: var(--mono); - font-weight: 600; -} -.sep-bar { - grid-column: 1 / -1; - position: relative; - height: 5px; - border-radius: 3px; - background: linear-gradient(90deg, #ef4444, #f59e0b 50%, #10b981); - opacity: 0.75; -} -.sep-bar i { - position: absolute; - top: -3px; - width: 3px; - height: 11px; - margin-left: -1.5px; - background: var(--text); - border-radius: 1px; -} -.sep-empty { - font-size: 12px; - color: var(--muted); -} -.cm-controls, -.bench-controls { - display: flex; - flex-wrap: wrap; - gap: 10px; - align-items: center; - margin: 4px 0 10px; -} -.bench-table td .sd { - color: var(--muted); - font-size: 11px; -} -.bench-table .bench-use { - padding: 2px 8px; - font-size: 11.5px; -} -#benchSection { - margin-top: 18px; -} -/* ---------- analysis, frames, exports ---------- */ -.frames { - margin-top: 10px; - padding-top: 8px; - border-top: 1px solid var(--line); -} -.frame-row { - display: flex; - gap: 6px; - align-items: center; - margin-bottom: 6px; -} -.frame-row button { - padding: 4px 9px; -} -.frame-row select { - width: auto; - flex: 1; -} -#frameBadge { - position: absolute; - top: 16px; - left: 50%; - transform: translateX(-50%); - z-index: 4; - padding: 4px 12px; - border-radius: 999px; - font-size: 13px; - font-weight: 600; - background: color-mix(in srgb, var(--panel) 92%, transparent); - border: 1px solid var(--line); - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); - pointer-events: none; -} -#frameBadge[hidden] { - display: none; -} -.export-grid { - display: grid !important; - grid-template-columns: 1fr 1fr; - gap: 6px; -} -.info-explore { - display: flex; - flex-wrap: wrap; - align-items: center; - gap: 4px; - font-size: 11px; - color: var(--muted); - margin: 0 0 10px; -} -.info-explore[hidden] { - display: none; -} -.info-explore button { - padding: 2px 7px; - font-size: 11px; -} -#btnSelNeighbours[hidden], -#btnSelPaths[hidden] { - display: none; -} -.cmp-arena { - display: flex; - flex-wrap: wrap; - align-items: center; - gap: 8px 10px; - margin-top: 10px; - padding: 8px 10px; - border-radius: 8px; - border: 1px dashed var(--line); -} -.cmp-arena[hidden] { - display: none; -} -.cmp-arena-title { - font-weight: 600; - font-size: 12.5px; - display: inline-flex; - align-items: center; - gap: 6px; -} -.cmp-arena .status { - flex-basis: 100%; -} -.toast { - position: absolute; - left: 50%; - bottom: 56px; - transform: translateX(-50%); - z-index: 6; - max-width: 70%; - padding: 8px 14px; - border-radius: 8px; - font-size: 12.5px; - background: var(--panel); - border: 1px solid var(--line); - border-left: 4px solid var(--accent); - box-shadow: 0 6px 18px rgba(0, 0, 0, 0.16); -} -.toast.warn { - border-left-color: #f59e0b; -} -.toast[hidden] { - display: none; -} -.ga-sub { - margin: 18px 0 2px; - font-size: 14px; -} -.ga-grid { - display: grid; - grid-template-columns: auto minmax(200px, 360px); - justify-content: start; - gap: 6px 12px; - align-items: center; - margin: 6px 0; - font-size: 12.5px; -} -.ga-grid .num-input { - width: 100px; -} -#gaSetsFromRow[hidden] { - display: none; -} -.nodedot { - display: inline-block; - width: 10px; - height: 10px; - border-radius: 50%; - vertical-align: -1px; -} -#gaSection, -#runtimeSection { - margin-top: 18px; -} - -/* ---------- STRING import ---------- */ -.string-query { - resize: vertical; - min-height: 44px; - font-family: var(--mono); - font-size: 12px; - width: 100%; -} -.string-more { - margin-top: 10px; - border-top: 1px solid color-mix(in srgb, var(--tint) 20%, var(--line)); - padding-top: 6px; -} -.string-more > summary { - cursor: pointer; - font-size: 12px; - font-weight: 600; - color: var(--text); - padding: 3px 0; -} -.string-checks { - display: flex; - flex-direction: column; - gap: 2px; - margin-top: 6px; - max-height: 230px; - overflow-y: auto; -} -.string-check { - display: flex; - align-items: center; - gap: 7px; - font-size: 12px; - cursor: pointer; - padding: 1px 0; -} -.string-check input { - margin: 0; - accent-color: var(--accent); -} -.row button .ico { - margin-right: 6px; - vertical-align: -2px; -} -.arena-more { - border-top-color: var(--line); -} -.string-check .swatch { - width: 14px; - height: 4px; - border-radius: 2px; - flex-shrink: 0; -} -/* ---------- image export ---------- */ -.export-btn { - display: flex; - align-items: center; - gap: 6px; - padding: 5px 10px; - font-size: 12px; -} -.export-btn svg { - width: 15px; - height: 15px; -} -@media (max-width: 1500px) { - .export-btn span { - display: none; - } - .export-btn { - padding: 5px 8px; - } - #viewHeader .vh-count { - display: none; - } -} -#exportDialog, -#deleteDialog { - border: 1px solid var(--line); - border-radius: 12px; - padding: 0; - background: var(--panel); - color: var(--text); - width: min(560px, calc(100vw - 32px)); - box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); -} -#exportDialog::backdrop, -#deleteDialog::backdrop { - background: rgba(15, 20, 32, 0.45); -} -.dlg { - padding: 18px 20px 16px; - margin: 0; -} -.dlg h2 { - margin: 0 0 2px; - font-size: 17px; -} -.dlg-sub { - margin: 0 0 12px; - font-size: 12.5px; - color: var(--muted); -} -.fmt-grid { - border: none; - padding: 0; - margin: 0 0 12px; - display: grid; - grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); - gap: 6px; -} -.fmt-grid legend { - font-size: 12px; - font-weight: 600; - margin-bottom: 6px; - padding: 0; -} -.fmt-grid label { - display: flex; - gap: 8px; - align-items: flex-start; - cursor: pointer; - border: 1px solid var(--line); - border-radius: 8px; - padding: 8px 10px; - background: var(--bg); -} -.fmt-grid label:has(input:checked) { - border-color: var(--accent); - background: color-mix(in srgb, var(--accent) 10%, var(--bg)); -} -.fmt-grid input { - margin-top: 3px; - accent-color: var(--accent); -} -.fmt-grid b { - display: block; - font-size: 13px; -} -.fmt-grid small { - display: block; - font-size: 11px; - color: var(--muted); - line-height: 1.35; -} -.dlg-grid { - display: grid; - grid-template-columns: 100px 1fr; - gap: 8px 12px; - align-items: center; - font-size: 12.5px; -} -.dlg-grid > label { - color: var(--muted); -} -.dlg-size { - margin: -2px 0 2px; - font-size: 11.5px; - color: var(--muted); - font-family: var(--mono); -} -.dlg-file { - display: flex; - align-items: center; - gap: 4px; -} -.dlg-file span { - font-family: var(--mono); - font-size: 12px; - color: var(--muted); -} -.dlg-actions { - display: flex; - justify-content: flex-end; - gap: 8px; - margin-top: 12px; -} -.dlg-actions button { - min-width: 110px; -} -/* ---------- header: view switcher ---------- */ -#viewHeader { - grid-area: viewhead; - display: flex; - align-items: center; - gap: 10px; - padding: 0 18px 0 14px; - background: color-mix(in srgb, #6366f1 9%, var(--panel)); - border-bottom: 1px solid color-mix(in srgb, #6366f1 25%, var(--line)); - min-width: 0; -} -.vh-label { - display: flex; - align-items: center; - gap: 6px; - font-size: 12px; - font-weight: 700; - letter-spacing: 0.2px; - color: color-mix(in srgb, #6366f1 70%, var(--text)); - flex-shrink: 0; -} -.vh-label svg { - width: 16px; - height: 16px; -} -.vh-select { - display: flex; - gap: 6px; - align-items: center; - min-width: 0; -} -.vh-sub { - margin-left: 6px; - color: color-mix(in srgb, #f59e0b 70%, var(--text)); -} -#viewGrouping { - width: 270px; - min-width: 120px; - flex: 0 1 270px; - padding: 6px 10px; - font-weight: 600; - background: color-mix(in srgb, #f59e0b 8%, var(--bg)); - border-color: color-mix(in srgb, #f59e0b 40%, var(--line)); -} -#viewGrouping:disabled { - opacity: 0.75; - font-weight: 400; -} - -#viewSelect { - width: 230px; - min-width: 140px; - font-weight: 600; - padding: 6px 10px; - border-color: color-mix(in srgb, #6366f1 35%, var(--line)); -} -.vh-select { - flex: 0 1 auto; -} -#viewNameInput { - width: 240px; -} -.vh-count { - font-size: 11.5px; - color: var(--muted); - white-space: nowrap; -} -#viewHeader .view-actions { - display: flex; - gap: 4px; - margin-top: 0; -} -#viewHeader .view-actions button { - padding: 5px 9px; - font-size: 12px; -} -#viewHeader #topTools { - margin-left: auto; - margin-right: 0; - display: flex; - align-items: center; - gap: 8px; - flex-shrink: 0; -} -#viewHeader { - overflow: hidden; -} -#viewHeader .view-actions { - flex-shrink: 0; -} -#brand { - border-bottom: 1px solid color-mix(in srgb, #6366f1 25%, var(--line)); -} - -/* ---------- sidebar tabs sit in the grid, aligned with the page tabs ---------- */ -#sideTabs { - grid-area: sidetabs; - display: flex; - margin: 0; - background: var(--panel); - border-right: 1px solid var(--line); - border-bottom: 1px solid var(--line); - padding: 0 10px; -} -#sideTabs { - padding: 0 4px; - gap: 2px; -} -#sideTabs button { - padding: 0 2px; - font-size: 11px; - line-height: 1.15; - white-space: normal; - text-align: center; - flex-direction: row; - gap: 3px; -} -#sideTabs button .ico { - margin-right: 2px; - width: 13px; - height: 13px; - flex-shrink: 0; -} -#sideTabs button[data-side='data'][aria-selected='true'] { - border-bottom-color: #2563eb; - color: color-mix(in srgb, #2563eb 60%, var(--text)); -} -#sideTabs button[data-side='db'][aria-selected='true'] { - border-bottom-color: #dc2626; - color: color-mix(in srgb, #dc2626 60%, var(--text)); -} -#sideTabs button[data-side='display'][aria-selected='true'] { - border-bottom-color: #16a34a; - color: color-mix(in srgb, #16a34a 55%, var(--text)); -} -#sideTabs button[data-side='export'][aria-selected='true'] { - border-bottom-color: #7c3aed; - color: color-mix(in srgb, #7c3aed 60%, var(--text)); -} -#sidebar { - padding-top: 14px; -} - -/* ---------- resizable / collapsible sidebar ---------- */ -#brand, -#sideTabs, -#sidebar { - min-width: 0; -} -#brand { - overflow: hidden; -} -#sideResizer { - position: absolute; - top: 0; - bottom: 0; - left: calc(var(--side-w) - 4px); - width: 8px; - cursor: col-resize; - z-index: 30; - touch-action: none; - outline: none; -} -#sideResizer::after { - content: ''; - position: absolute; - top: 0; - bottom: 0; - left: 3px; - width: 2px; - background: transparent; - transition: background 0.15s; -} -#sideResizer:hover::after, -#sideResizer:focus-visible::after, -#app.side-resizing #sideResizer::after { - background: var(--accent); -} -#sideToggle { - position: absolute; - top: 50%; - left: calc(var(--side-w) - 1px); - z-index: 31; - transform: translateY(-50%); - width: 16px; - height: 44px; - padding: 0; - display: flex; - align-items: center; - justify-content: center; - border: 1px solid var(--line); - border-left: none; - border-radius: 0 6px 6px 0; - background: var(--panel); - color: var(--muted); -} -#sideToggle:hover { - color: var(--text); - border-color: var(--accent-dim); - background: var(--panel-2-hover); -} -#sideToggle:focus-visible { - outline: 2px solid var(--accent); - outline-offset: 1px; -} -#sideToggle svg { - width: 10px; - height: 10px; - transition: transform 0.15s; -} -#app.side-collapsed #brand, -#app.side-collapsed #sideTabs, -#app.side-collapsed #sidebar { - display: none; -} -#app.side-collapsed #sideResizer { - display: none; -} -#app.side-collapsed #sideToggle { - left: 0; -} -#app.side-collapsed #sideToggle svg { - transform: rotate(180deg); -} -#app.side-resizing, -#app.side-resizing * { - cursor: col-resize !important; - user-select: none !important; -} - -/* ---------- what the current view shows ---------- */ -#topbar { - gap: 12px; -} -#ctxbar { - grid-area: ctxbar; - display: flex; - align-items: center; - gap: 14px; - padding: 0 18px; - background: color-mix(in srgb, var(--text) 2.5%, var(--panel)); - border-bottom: 1px solid var(--line); - min-width: 0; -} -#contextInfo { - flex: 1 1 0; - min-width: 0; - display: flex; - gap: 6px; - align-items: center; - overflow: hidden; -} -.ctx-chip { - --tint: #64748b; - display: inline-flex; - align-items: center; - gap: 5px; - min-width: 0; - max-width: 40%; - padding: 3px 9px; - border-radius: 999px; - font-size: 12px; - white-space: nowrap; - background: color-mix(in srgb, var(--tint) 12%, var(--panel)); - border: 1px solid color-mix(in srgb, var(--tint) 30%, var(--line)); -} -.ctx-chip b { - font-weight: 600; - color: color-mix(in srgb, var(--tint) 65%, var(--text)); - flex-shrink: 0; -} -.ctx-chip span { - overflow: hidden; - text-overflow: ellipsis; -} -.ctx-chip[data-tint='data'] { - --tint: #2563eb; -} -.ctx-chip[data-tint='groups'] { - --tint: #d97706; -} -.ctx-chip[data-tint='colors'] { - --tint: #db2777; -} -.ctx-empty { - font-size: 12px; - color: var(--muted); -} -#stats { - display: flex; - gap: 12px; - flex-shrink: 0; - align-items: center; -} -.stat-dir-off { - cursor: pointer; - opacity: 0.85; - border-style: dashed !important; -} -.stat-dir { - font-family: var(--sans); - font-size: 11px; - padding: 1px 7px; - border-radius: 999px; - border: 1px solid color-mix(in srgb, #06b6d4 45%, var(--line)); - background: color-mix(in srgb, #06b6d4 12%, var(--panel)); - color: color-mix(in srgb, #06b6d4 55%, var(--text)); -} -@media (max-width: 1380px) { - #stats { - gap: 8px; - font-size: 11px; - } - .vh-count { - display: none; - } -} - -/* ---------- tinted sidebar sections ---------- */ -.section { - --tint: #64748b; - background: color-mix(in srgb, var(--tint) 6%, var(--panel)); - border: 1px solid color-mix(in srgb, var(--tint) 20%, var(--line)); - border-left: 3px solid color-mix(in srgb, var(--tint) 70%, var(--panel)); - border-radius: 8px; - padding: 10px 12px 12px; - margin-bottom: 12px; -} -.section > h3 { - color: color-mix(in srgb, var(--tint) 60%, var(--text)); -} -/* Data tab */ -.section[data-tint='examples'] { - --tint: #059669; -} -.section[data-tint='string'] { - --tint: #dc2626; -} -.section[data-tint='files'] { - --tint: #2563eb; -} -.section[data-tint='saved'] { - --tint: #7c3aed; -} -/* Database importers tab */ -.section[data-tint='reactome'] { - --tint: #2563eb; -} -.section[data-tint='omnipath'] { - --tint: #0d9488; -} -.section[data-tint='ndex'] { - --tint: #ea580c; -} -.section[data-tint='intact'] { - --tint: #16a34a; -} -.section[data-tint='go'] { - --tint: #7c3aed; -} -/* Export tab */ -.section[data-tint='exfiles'] { - --tint: #2563eb; -} -.section[data-tint='eximage'] { - --tint: #db2777; -} -.section[data-tint='exarena'] { - --tint: #0d9488; -} -.section[data-tint='exother'] { - --tint: #ea580c; -} -.section[data-tint='exsave'] { - --tint: #475569; -} -.section.collapsible > h3 { - cursor: pointer; - user-select: none; -} -.section.collapsible > h3::after { - content: '▾'; - margin-left: 6px; - font-size: 11px; - color: var(--muted); - order: 3; -} -.section.collapsible.collapsed > h3::after { - content: '▸'; -} -.section.collapsible.collapsed > h3 { - margin-bottom: 0; -} -.section.collapsible > h3:focus-visible { - outline: 2px solid var(--accent); - outline-offset: 2px; - border-radius: 4px; -} -.section.collapsible.collapsed > *:not(h3) { - display: none !important; -} -.section.collapsible > h3 .helplink { - order: 2; -} -.db-tag { - margin: -2px 0 8px; - font-size: 11px; - color: var(--muted); - line-height: 1.35; -} -.db-tag a { - color: inherit; -} -.db-pick { - width: 100%; - margin-top: 6px; - font-size: 12px; -} -.menu-sep { - display: flex; - align-items: center; - gap: 8px; - margin: 14px 0 8px; - font-size: 10.5px; - font-weight: 700; - letter-spacing: 0.06em; - text-transform: uppercase; - color: color-mix(in srgb, var(--tint) 60%, var(--muted)); -} -.menu-sep::after { - content: ''; - flex: 1; - height: 1px; - background: color-mix(in srgb, var(--tint) 28%, var(--line)); -} -.menu-sep > span { - display: inline-flex; - align-items: baseline; - gap: 6px; - flex-wrap: wrap; -} -.menu-sep .lib-hint { - text-transform: none; - letter-spacing: 0; - font-weight: 400; - font-size: 11px; - color: var(--muted); -} -.section > h3 + .menu-sep, -.db-tag + .menu-sep, -.db-body > .menu-sep:first-child, -details > summary + .menu-sep { - margin-top: 4px; -} -.panel-intro { - margin: 0 2px 12px; - font-size: 12px; - color: var(--muted); - line-height: 1.45; -} -/* Display tab, in order; neighbours always differ clearly */ -.section[data-tint='groups'] { - --tint: #d97706; -} -.section[data-tint='hulls'] { - --tint: #a21caf; -} -.section[data-tint='layout3d'] { - --tint: #0d9488; -} -.section[data-tint='layout'] { - --tint: #16a34a; -} -.section[data-tint='colors'] { - --tint: #db2777; -} -.section[data-tint='nodes'] { - --tint: #0284c7; -} -.section[data-tint='labels'] { - --tint: #ea580c; -} -.section[data-tint='edges'] { - --tint: #475569; -} -.section[data-tint='channels'] { - --tint: #65a30d; -} -.section[data-tint='legend'] { - --tint: #be123c; -} -.section[data-tint='attrs'] { - --tint: #0891b2; -} -.section[data-tint='perf'] { - --tint: #92400e; -} -.section .upload-box, -.section .lib-list, -.section .strategy-fig { - background: var(--panel); -} -::selection { - background: #fde68a; - color: #111827; -} diff --git a/frontend/src/themes.ts b/frontend/src/themes.ts deleted file mode 100644 index 5770be1..0000000 --- a/frontend/src/themes.ts +++ /dev/null @@ -1,142 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { SELECTION_YELLOW, setStyle } from './cy' -import { applyEdgeMerge } from './parallel_edges' -import { updateLabelStyle } from './profiler' - -/* ---------- UI themes (chrome + canvas; independent of node/edge data palettes) ---------- */ -const THEMES = { - dark: { - bg: '#0f1420', - panel: '#161d2e', - panel2: '#1d2740', - panel2Hover: '#223050', - line: '#2a3554', - text: '#e7ebf5', - muted: '#8993ad', - accent: '#5fd3c4', - accentDim: '#3a7d74', - accentHover: '#7fe0d3', - accentText: '#08221e', - warn: '#e7a15f', - canvasDot: '#1c2540', - nodeBorder: 'rgba(255,255,255,0.35)', - }, - midnight: { - bg: '#050608', - panel: '#0c0e12', - panel2: '#131620', - panel2Hover: '#1a1e2b', - line: '#1f2430', - text: '#dfe3ee', - muted: '#767c8c', - accent: '#7c5cff', - accentDim: '#5540b3', - accentHover: '#9b82ff', - accentText: '#0a0612', - warn: '#e7a15f', - canvasDot: '#111420', - nodeBorder: 'rgba(255,255,255,0.3)', - }, - light: { - bg: '#f4f5f8', - panel: '#ffffff', - panel2: '#eef1f6', - panel2Hover: '#e2e7ef', - line: '#d7dce6', - text: '#1b2333', - muted: '#6b7387', - accent: '#2a9d8f', - accentDim: '#1f7a6f', - accentHover: '#39b7a7', - accentText: '#ffffff', - warn: '#c76b1f', - canvasDot: '#e4e8f0', - nodeBorder: 'rgba(20,25,40,0.25)', - }, - white: { - bg: '#ffffff', - panel: '#ffffff', - panel2: '#f5f5f7', - panel2Hover: '#e9e9ec', - line: '#e0e0e5', - text: '#111114', - muted: '#6e6e76', - accent: '#0f766e', - accentDim: '#0b5c56', - accentHover: '#14958a', - accentText: '#ffffff', - warn: '#b45309', - canvasDot: '#eeeeee', - nodeBorder: 'rgba(0,0,0,0.2)', - }, - gray: { - bg: '#2b2e33', - panel: '#34383f', - panel2: '#3d424a', - panel2Hover: '#464b54', - line: '#4a4f58', - text: '#e7e8ea', - muted: '#9a9fa8', - accent: '#8fb8e8', - accentDim: '#5f83ad', - accentHover: '#a9cdf5', - accentText: '#12161c', - warn: '#e0a458', - canvasDot: '#3a3f47', - nodeBorder: 'rgba(255,255,255,0.2)', - }, - paper: { - bg: '#f3ecdd', - panel: '#fbf6ea', - panel2: '#efe6d2', - panel2Hover: '#e6dac0', - line: '#ddd0b0', - text: '#3a2f1f', - muted: '#8a7a5c', - accent: '#b3541e', - accentDim: '#8a4017', - accentHover: '#d06a2c', - accentText: '#fff7ec', - warn: '#7a5a1e', - canvasDot: '#e9ddc2', - nodeBorder: 'rgba(58,47,31,0.3)', - }, -} - -export let currentTheme = THEMES.dark - -export function applyTheme(name) { - const t = THEMES[name] || THEMES.dark - currentTheme = t - - const root = document.documentElement.style - root.setProperty('--bg', t.bg) - root.setProperty('--panel', t.panel) - root.setProperty('--panel-2', t.panel2) - root.setProperty('--panel-2-hover', t.panel2Hover) - root.setProperty('--line', t.line) - root.setProperty('--text', t.text) - root.setProperty('--muted', t.muted) - root.setProperty('--accent', t.accent) - root.setProperty('--accent-dim', t.accentDim) - root.setProperty('--accent-hover', t.accentHover) - root.setProperty('--accent-text', t.accentText) - root.setProperty('--warn', t.warn) - root.setProperty('--canvas-dot', t.canvasDot) - - // cytoscape doesn't read CSS variables, so the canvas-drawn parts - // (node label color/halo, node border, highlight color) are set directly - setStyle('node', { color: t.text, 'text-outline-color': t.bg, 'border-color': t.nodeBorder }) - setStyle('node.highlighted', { 'border-color': t.accent }) - // selected nodes and edges are marked in yellow on every theme - setStyle('node:selected', { - 'border-color': SELECTION_YELLOW, - 'underlay-color': SELECTION_YELLOW, - }) - setStyle('edge:selected', { 'underlay-color': SELECTION_YELLOW }) - setStyle('core', { 'selection-box-color': t.accent, 'selection-box-border-color': t.accent }) - - updateLabelStyle() // edge label color/halo also depend on the theme - applyEdgeMerge() // merged edges use the theme's muted color -} diff --git a/frontend/src/uploads.ts b/frontend/src/uploads.ts deleted file mode 100644 index cf762ce..0000000 --- a/frontend/src/uploads.ts +++ /dev/null @@ -1,192 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { - NORMA_KIND_NAMES, - addNormaEntry, - annotationText, - articleFor, - detectNormaKind, - downloadText, - fileStem, - libSelection, - listSample, - normaLibrary, - plural, - renderLibraryLists, - selectedNetworks, - setStatus, -} from './layouts/controls' -import { convertArena3dNetwork, isArena3dNetworkText } from './arena3d' - -/* ---------- uploads ---------- */ -export function readFileText(file) { - return new Promise((resolve, reject) => { - const reader = new FileReader() - reader.onload = (ev) => resolve(ev.target.result) - reader.onerror = () => - reject(new Error('The file could not be read. Check that it is a plain text file.')) - reader.readAsText(file) - }) -} - -// Splits an annotation's members into those present in `known` and those not. -function checkAnnotationAgainst(entry, known) { - const missing = new Set() - const emptied = [] - const kept = [] - entry.parsed.groups.forEach(({ name, members }) => { - const present = members.filter((m) => known.has(m)) - members.forEach((m) => { - if (!known.has(m)) missing.add(m) - }) - if (present.length) kept.push({ name, members: present }) - else emptied.push(name) - }) - return { missing: [...missing], emptied, kept } -} - -export async function handleNormaUploads(fileList) { - const files = [...fileList] - if (!files.length) return - const chosenKind = document.getElementById('normaKind').value - const nameInput = document.getElementById('normaName') - const typedName = files.length === 1 ? nameInput.value.trim() : '' - const notes = [] - const added = [] - const addedNotes = new Map() - for (const file of files) { - try { - const text = await readFileText(file) - if ((chosenKind === 'auto' || chosenKind === 'network') && isArena3dNetworkText(text)) { - // an Arena3D network file: a network plus its layers as groups - const conv = convertArena3dNetwork(text) - const base = typedName || file.name.replace(/\.[^.]+$/, '') || file.name - const netEntry = addNormaEntry('network', base, conv.network, file.name, null, { - directed: document.getElementById('normaDirected').value === 'directed', - }) - const annEntry = addNormaEntry( - 'annotation', - `${base} layers`, - conv.annotation, - file.name, - null, - {} - ) - ;[netEntry, annEntry].forEach((entry) => { - added.push(entry) - const note = { - level: 'ok', - text: `Added ${articleFor(NORMA_KIND_NAMES[entry.kind])} ${NORMA_KIND_NAMES[entry.kind]} "${entry.name}" from an Arena3D network file: ${entry.parsed.summary}.`, - } - addedNotes.set(entry, note) - notes.push(note) - entry.parsed.notes.forEach((t) => - notes.push({ level: 'warn', text: `${entry.name}: ${t}` }) - ) - }) - continue - } - const kind = chosenKind === 'auto' ? detectNormaKind(text) : chosenKind - if (!kind) throw new Error('The file is empty.') - const name = typedName || file.name.replace(/\.[^.]+$/, '') || file.name - const entry = addNormaEntry(kind, name, text, file.name, null, { - directed: document.getElementById('normaDirected').value === 'directed', - }) - added.push(entry) - const addedNote = { - level: 'ok', - text: `Added ${articleFor(NORMA_KIND_NAMES[kind])} ${NORMA_KIND_NAMES[kind]} "${entry.name}": ${entry.parsed.summary}.`, - } - addedNotes.set(entry, addedNote) - notes.push(addedNote) - entry.parsed.notes.forEach((t) => notes.push({ level: 'warn', text: `${entry.name}: ${t}` })) - } catch (err) { - const kindText = - chosenKind === 'auto' - ? 'a file' - : `${articleFor(NORMA_KIND_NAMES[chosenKind])} ${NORMA_KIND_NAMES[chosenKind]}` - notes.push({ - level: 'error', - text: `"${file.name}" wasn't added as ${kindText}. ${err.message}`, - }) - } - } - // Check new annotations against the networks they will most likely be - // used with: networks uploaded together with them, otherwise the ticked - // networks, otherwise every network in the list. Names missing from all - // of those are discarded now, with a download of the corrected file. - const newAnnotations = added.filter((e) => e.kind === 'annotation') - if (newAnnotations.length) { - const batchNets = added.filter((e) => e.kind === 'network') - const tickedNets = selectedNetworks() - const refNets = batchNets.length - ? batchNets - : tickedNets.length - ? tickedNets - : normaLibrary.network - const refNames = - refNets.length === 1 - ? `"${refNets[0].name}"` - : `the ${refNets.length} ${batchNets.length ? 'uploaded' : tickedNets.length ? 'ticked' : 'listed'} networks` - if (!refNets.length) { - notes.push({ - level: 'ok', - text: 'No network is loaded yet, so annotation names will be checked when you show them with a network.', - }) - } - const known = new Set(refNets.flatMap((e) => e.parsed.nodes)) - newAnnotations.forEach((entry) => { - if (!refNets.length) return - const check = checkAnnotationAgainst(entry, known) - if (!check.missing.length) return - if (!check.kept.length) { - normaLibrary.annotation = normaLibrary.annotation.filter((x) => x !== entry) - added.splice(added.indexOf(entry), 1) - notes.splice(notes.indexOf(addedNotes.get(entry)), 1) - notes.push({ - level: 'error', - text: `"${entry.name}" was not kept: none of its ${plural(check.missing.length, 'node name')} are in ${refNames}. Check that the annotation belongs to this network.`, - }) - return - } - entry.parsed.groups = check.kept - entry.parsed.summary = plural(check.kept.length, 'group') - addedNotes.get(entry).text = - `Added the annotation "${entry.name}": ${entry.parsed.summary} after the check below.` - entry.correctedText = annotationText(check.kept) - const parts = [ - `Discarded ${plural(check.missing.length, 'node name')} from "${entry.name}" that ${check.missing.length === 1 ? 'is' : 'are'} not in ${refNames}: ${listSample(check.missing)}.`, - ] - if (check.emptied.length) - parts.push( - `${plural(check.emptied.length, 'group')} left with no nodes ${check.emptied.length === 1 ? 'was' : 'were'} removed: ${listSample(check.emptied)}.` - ) - const fileName = `${fileStem(entry.name)}-corrected.txt` - notes.push({ - level: 'warn', - text: parts.join(' '), - action: { - label: 'Download corrected annotation', - run: () => downloadText(fileName, entry.correctedText), - }, - }) - }) - } - if (added.length) { - nameInput.value = '' - // Select what was just added: new networks replace the network - // selection; the last new annotation / expression becomes the choice. - const newNets = added.filter((e) => e.kind === 'network') - if (newNets.length) libSelection.networks = new Set(newNets.map((e) => e.id)) - const lastAnn = added.filter((e) => e.kind === 'annotation').pop() - if (lastAnn) libSelection.annotation = lastAnn.id - const lastCol = added.filter((e) => e.kind === 'colors').pop() - if (lastCol) libSelection.colors = lastCol.id - notes.push({ - level: 'ok', - text: 'The new files are ticked. Choose Show in this view or Open in new view to see them.', - }) - } - renderLibraryLists() - setStatus('normaStatus', notes) -} diff --git a/frontend/src/view3d/cache.ts b/frontend/src/view3d/cache.ts deleted file mode 100644 index f89b367..0000000 --- a/frontend/src/view3d/cache.ts +++ /dev/null @@ -1,102 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { PIE_MAX_SLICES, effectiveGroupsFor } from '../network_state' -import { cy } from '../cy' -import { net3d } from './state' - -/* ---------- element cache: everything read from the 2D elements ---------- */ -export function buildCache3d() { - const nodes = [] - const byId = new Map() - cy.nodes().forEach((n) => { - if (!n.visible()) return - const pies = [] - if (n.style('shape') === 'ellipse') { - for (let i = 1; i <= PIE_MAX_SLICES; i++) { - const size = parseFloat(n.data('pieSize' + i)) || 0 - if (size > 0) pies.push([n.data('pieColor' + i), size / 100]) - } - } - const rec = { - id: n.id(), - el: n, - size: n.width(), - color: n.style('background-color'), - pies, - shape: n.style('shape'), - border: n.style('border-color'), - borderW: n.pstyle('border-width').pfValue, - opacity: n.effectiveOpacity(), - underlay: - n.pstyle('underlay-opacity').value > 0 - ? { - color: n.style('underlay-color'), - alpha: n.pstyle('underlay-opacity').value, - pad: n.pstyle('underlay-padding').pfValue, - } - : null, - label: n.style('label'), - labelColor: n.style('color'), - halo: n.style('text-outline-color'), - haloW: n.pstyle('text-outline-width').pfValue, - fontPx: n.pstyle('font-size').pfValue, - valign: n.style('text-valign'), - halign: n.style('text-halign'), - marginX: n.pstyle('text-margin-x').pfValue || 0, - marginY: n.pstyle('text-margin-y').pfValue || 0, - groups: effectiveGroupsFor(n), - highlighted: n.hasClass('highlighted'), - } - nodes.push(rec) - byId.set(rec.id, rec) - }) - const edges = [] - const pairCount = new Map() - cy.edges().forEach((e) => { - if (!e.visible()) return - const s = e.data('source'), - t = e.data('target') - if (!byId.has(s) || !byId.has(t) || s === t) return - const pair = s < t ? s + '\t' + t : t + '\t' + s - const k = pairCount.get(pair) || 0 - pairCount.set(pair, k + 1) - const arrow = e.style('target-arrow-shape') - edges.push({ - id: e.id(), - el: e, - s, - t, - pair, - index: k, - color: e.style('line-color'), - width: e.pstyle('width').pfValue, - opacity: e.effectiveOpacity(), - arrow: arrow && arrow !== 'none' ? arrow : null, - arrowColor: e.style('target-arrow-color'), - arrowScale: e.pstyle('arrow-scale').value || 1, - label: e.style('label'), - labelColor: e.style('color'), - labelBg: e.style('text-background-color'), - fontPx: e.pstyle('font-size').pfValue, - rotate: e.style('text-rotation') === 'autorotate', - underlay: e.pstyle('underlay-opacity').value > 0 ? e.style('underlay-color') : null, - }) - }) - edges.forEach((e) => { - e.siblings = pairCount.get(e.pair) - }) - net3d.cache = { nodes, edges, byId } - net3d.cacheDirty = false -} - -/* ---------- positions ---------- */ -export function pos3dOf(id) { - let p = net3d.pos.get(id) - if (!p) { - const n = cy.getElementById(id) - const q = n.length ? n.position() : { x: 0, y: 0 } - p = [q.x, q.y, 0] - net3d.pos.set(id, p) - } - return p -} diff --git a/frontend/src/view3d/camera.ts b/frontend/src/view3d/camera.ts deleted file mode 100644 index b948474..0000000 --- a/frontend/src/view3d/camera.ts +++ /dev/null @@ -1,182 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { buildCache3d, pos3dOf } from './cache' -import { canvas3d, el3, net3d, requestRender3d } from './state' -import { cy } from '../cy' -import { formatZoom } from '../profiler' -import { render3d } from './draw' - -/* ---------- camera and projection ---------- */ -function perspectiveMode() { - return el3('persp3d').value -} - -export function focalLength(H) { - const fov = perspectiveMode() === 'strong' ? 65 : 30 - return H / 2 / Math.tan((fov * Math.PI) / 360) -} - -// Returns a projector for a given viewport size and camera. -export function makeProjector(W, H, cam) { - const cyaw = Math.cos(cam.yaw), - syaw = Math.sin(cam.yaw) - const cp = Math.cos(cam.pitch), - sp = Math.sin(cam.pitch) - const f = focalLength(H) - const ortho = perspectiveMode() === 'none' - const orthoScale = f / cam.dist - const near = cam.dist * 0.02 - return (p) => { - const qx = p[0] - cam.tx, - qy = p[1] - cam.ty, - qz = p[2] - cam.tz - const x1 = cyaw * qx - syaw * qz - const z1 = syaw * qx + cyaw * qz - const y2 = cp * qy - sp * z1 - const z2 = sp * qy + cp * z1 - const depth = cam.dist + z2 - if (!ortho && depth < near) return null - const scale = ortho ? orthoScale : f / depth - return { x: W / 2 + x1 * scale, y: H / 2 + y2 * scale, depth, scale } - } -} - -// Inverse of the rotation: a screen-plane vector (dx, dy) to world units at a given scale. -export function screenToWorldDelta(dx, dy, scale, cam) { - const cyaw = Math.cos(cam.yaw), - syaw = Math.sin(cam.yaw) - const cp = Math.cos(cam.pitch), - sp = Math.sin(cam.pitch) - const x1 = dx / scale, - y2 = dy / scale - // camera-space vector (x1, y2, 0) back to world space - const qy = cp * y2 - const z1 = -sp * y2 - const qx = cyaw * x1 + syaw * z1 - const qz = -syaw * x1 + cyaw * z1 - return [qx, qy, qz] -} - -/* ---------- camera helpers ---------- */ -export function shownIds3d(eles) { - if (eles && eles.length) - return eles.filter((e) => (e.isNode ? e.isNode() : true)).map((n) => n.id()) - if (net3d.cacheDirty || !net3d.cache) buildCache3d() - return net3d.cache.nodes.map((n) => n.id) -} - -export function fit3d(eles, animate = true) { - const ids = shownIds3d( - eles && eles.nodes - ? eles.nodes().union(eles.connectedNodes ? eles.connectedNodes() : cy.collection()) - : eles - ) - if (!ids.length) return - const pts = ids.map((id) => ({ p: pos3dOf(id), r: (cy.getElementById(id).width() || 40) / 2 })) - // aim at the middle of the bounding box - const lo = [Infinity, Infinity, Infinity], - hi = [-Infinity, -Infinity, -Infinity] - pts.forEach(({ p }) => { - for (let d = 0; d < 3; d++) { - lo[d] = Math.min(lo[d], p[d]) - hi[d] = Math.max(hi[d], p[d]) - } - }) - const cam = { - ...net3d.cam, - tx: (lo[0] + hi[0]) / 2, - ty: (lo[1] + hi[1]) / 2, - tz: (lo[2] + hi[2]) / 2, - } - const cv = canvas3d() - const W = cv.clientWidth || 800, - H = cv.clientHeight || 600 - const margin = 40 - cam.dist = Math.max(60, Math.hypot(hi[0] - lo[0], hi[1] - lo[1], hi[2] - lo[2]) * 1.2) - // refine: project, measure how far the picture reaches, rescale the distance - for (let it = 0; it < 6; it++) { - const project = makeProjector(W, H, cam) - let need = 0 - for (const { p, r } of pts) { - const q = project(p) - if (!q) { - need = Infinity - break - } - const ex = Math.abs(q.x - W / 2) + r * q.scale, - ey = Math.abs(q.y - H / 2) + r * q.scale - need = Math.max(need, ex / (W / 2 - margin), ey / (H / 2 - margin)) - } - if (!Number.isFinite(need)) { - cam.dist *= 2 - continue - } - if (Math.abs(need - 1) < 0.02) break - cam.dist *= perspectiveMode() === 'none' ? need : Math.max(0.3, need) - } - moveCamera3d({ tx: cam.tx, ty: cam.ty, tz: cam.tz, dist: cam.dist }, animate) -} - -export function moveCamera3d(target, animate = true) { - const from = { ...net3d.cam } - const to = { ...from, ...target } - if (!animate) { - Object.assign(net3d.cam, to) - requestRender3d() - return - } - // turn the short way round (both angles are unlimited) - ;['yaw', 'pitch'].forEach((k) => { - if (target[k] === undefined) return - to[k] = from[k] + wrapAngle(to[k] - from[k]) - }) - const start = performance.now() - const step = (now) => { - const t = Math.min(1, (now - start) / 450) - const e = 1 - Math.pow(1 - t, 3) - Object.keys(to).forEach((key) => { - net3d.cam[key] = from[key] + (to[key] - from[key]) * e - }) - if (t >= 1) { - net3d.cam.yaw = wrapAngle(net3d.cam.yaw) - net3d.cam.pitch = wrapAngle(net3d.cam.pitch) - } - render3d() - if (t < 1) requestAnimationFrame(step) - } - requestAnimationFrame(step) -} - -export function zoom3d(factor) { - net3d.cam.dist = Math.min(1e7, Math.max(5, net3d.cam.dist / factor)) - requestRender3d() -} - -// keeps an angle in (-pi, pi] -export function wrapAngle(a) { - a = a % (Math.PI * 2) - if (a > Math.PI) a -= Math.PI * 2 - if (a <= -Math.PI) a += Math.PI * 2 - return a -} - -export function rotate3d(dyaw, dpitch) { - // turning and tilting have no limits: the view can go over the poles - // as often as wanted - net3d.cam.yaw = wrapAngle(net3d.cam.yaw + dyaw) - net3d.cam.pitch = wrapAngle(net3d.cam.pitch + dpitch) - requestRender3d() -} - -export const VIEW_PRESETS_3D = { - front: { yaw: 0, pitch: 0 }, - top: { yaw: 0, pitch: Math.PI / 2 - 0.02 }, - side: { yaw: Math.PI / 2, pitch: 0 }, - tilted: { yaw: 0.6, pitch: 0.45 }, -} - -export function updateZoomReadout3d() { - const H = canvas3d().clientHeight || 600 - const scale = focalLength(H) / net3d.cam.dist - document.getElementById('zoomLevel').textContent = formatZoom(scale) -} diff --git a/frontend/src/view3d/draw.ts b/frontend/src/view3d/draw.ts deleted file mode 100644 index aec2d6d..0000000 --- a/frontend/src/view3d/draw.ts +++ /dev/null @@ -1,395 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { S } from '../state' -import { UNGROUPED, getUsedGroups } from '../network_state' -import { blobPath, capsulePath } from '../export/shading' -import { bubbleContour, bubblePathD } from '../clustering/wiring' -import { buildCache3d, pos3dOf } from './cache' -import { canvas3d, el3, mixColor, net3d } from './state' -import { canvasPainter } from './painters' -import { convexHull, inflateHull } from '../hulls' -import { currentTheme } from '../themes' -import { cy } from '../cy' -import { makeProjector, updateZoomReadout3d } from './camera' - -/* ---------- drawing ---------- */ -function nodeShapePoints(shape, x, y, r) { - const def = cy.renderer().nodeShapes[shape] - if (!def || !def.points) return null - const pts = [] - for (let i = 0; i < def.points.length; i += 2) - pts.push([x + def.points[i] * r, y + def.points[i + 1] * r]) - return pts -} - -export function drawScene3d(painter, W, H, opts) { - if (net3d.cacheDirty || !net3d.cache) buildCache3d() - const { nodes, edges, byId } = net3d.cache - const cam = opts.cam || net3d.cam - const project = makeProjector(W, H, cam) - const fast = !!opts.fast - const bg = opts.bg - painter.clear(W, H, bg) - const fogColor = opts.fogColor || currentTheme.bg - const fogAmount = parseFloat(el3('fog3d').value) || 0 - const shaded = el3('style3d').value === 'shaded' - const k = opts.pixelScale || 1 // extra scaling for high-resolution export - - const T = { t: performance.now() } - const mark = (k) => { - const now = performance.now() - T[k] = Math.round(now - T.t) - T.t = now - } - // project nodes - const P = new Map() - let dMin = Infinity, - dMax = -Infinity - nodes.forEach((nd) => { - const pr = project(pos3dOf(nd.id)) - if (!pr) return - pr.x *= k - pr.y *= k - pr.scale *= k - P.set(nd.id, pr) - if (pr.depth < dMin) dMin = pr.depth - if (pr.depth > dMax) dMax = pr.depth - }) - const span = Math.max(1e-6, dMax - dMin) - const fogOf = (depth) => (fogAmount * 0.75 * (depth - dMin)) / span - - mark('project') - const floorPx = labelFloor3d() * k - const nodeLabelMin = labelCutoff3d( - nodes.filter((nd) => nd.label && P.has(nd.id)).map((nd) => nd.fontPx * P.get(nd.id).scale), - floorPx, - 500 - ) - const edgeLabelMin = labelCutoff3d( - edges - .filter((e) => e.label && P.has(e.s) && P.has(e.t)) - .map((e) => (e.fontPx * (P.get(e.s).scale + P.get(e.t).scale)) / 2), - floorPx, - 300 - ) - // floor grid and axes - if (el3('grid3d').checked && nodes.length) drawFloor3d(painter, project, k) - - // group shading, from the projected positions - if (document.getElementById('showGroupHulls').checked) { - const style = document.getElementById('hullStyle').value - const opacity = parseFloat(document.getElementById('hullOpacity').value) || 0.25 - const groups = getUsedGroups().filter((g) => S.activeGroups.has(g) && g !== UNGROUPED) - const bubbles = style === 'bubble' && !fast - const projected = bubbles - ? nodes - .filter((nd) => P.has(nd.id)) - .map((nd) => { - const pr = P.get(nd.id) - return { x: pr.x, y: pr.y, r: (nd.size / 2) * pr.scale, groups: nd.groups } - }) - : null - groups.forEach((g) => { - const pts = [] - nodes.forEach((nd) => { - if (!nd.groups.includes(g)) return - const pr = P.get(nd.id) - if (pr) pts.push({ x: pr.x, y: pr.y, r: (nd.size / 2) * pr.scale }) - }) - if (!pts.length) return - const color = S.nodeColorMap[g] || '#888888' - if (bubbles) { - const loops = bubbleContour( - pts, - projected.filter((p) => !p.groups.includes(g)), - { margin: 30 * k, edgeRadius: 21 * k, avoid: 12 * k, cell: 3 * k, maxCells: 120000 } - ) - const d = bubblePathD(loops) - if (d) - painter.pathD(d, { - fill: color, - fillAlpha: opacity, - stroke: color, - strokeAlpha: Math.min(1, opacity + 0.45), - width: 1.6 * k, - evenodd: true, - }) - return - } - const pad = 18 * k - let d - if (pts.length === 1) - d = `M${pts[0].x - pts[0].r - pad},${pts[0].y}a${pts[0].r + pad},${pts[0].r + pad} 0 1 0 ${2 * (pts[0].r + pad)},0a${pts[0].r + pad},${pts[0].r + pad} 0 1 0 ${-2 * (pts[0].r + pad)},0Z` - else if (pts.length === 2) d = capsulePath(pts[0], pts[1], Math.max(pts[0].r, pts[1].r) + pad) - else d = blobPath(inflateHull(convexHull(pts), pad + Math.max(...pts.map((p) => p.r)))) - painter.pathD( - d, - style === 'fog' - ? { fill: color, fillAlpha: opacity, blur: 14 * k } - : { - fill: color, - fillAlpha: opacity, - stroke: color, - strokeAlpha: Math.min(1, opacity + 0.35), - width: 1.5 * k, - } - ) - }) - } - - mark('hulls') - // edges, far to near - const curveStyle = document.getElementById('edgeCurveStyle').value - const fan = curveStyle === 'bezier' || curveStyle === 'bundled' - const fanStep = (parseInt(document.getElementById('edgeCurvature').value, 10) || 40) * 0.6 * k - const edgeList = [] - edges.forEach((e) => { - const a = P.get(e.s), - b = P.get(e.t) - if (!a || !b) return - edgeList.push({ e, a, b, depth: (a.depth + b.depth) / 2 }) - }) - edgeList.sort((p, q) => q.depth - p.depth) - const projEdges = [] - const labelsLater = [] - edgeList.forEach(({ e, a, b, depth }) => { - const fog = fogOf(depth) - const color = mixColor(e.color, fogColor, fog) - const avgScale = (a.scale + b.scale) / 2 - const width = Math.max(0.6 * k, Math.min(e.width * avgScale, 12 * k)) - let cx, cy0 - if (fan && e.siblings > 1) { - const off = (e.index - (e.siblings - 1) / 2) * fanStep * Math.min(1.5, avgScale) - // perpendicular in a direction that doesn't depend on edge orientation - const [p, q] = e.s < e.t ? [a, b] : [b, a] - const dx = q.x - p.x, - dy = q.y - p.y, - len = Math.hypot(dx, dy) || 1 - cx = (a.x + b.x) / 2 - (dy / len) * off - cy0 = (a.y + b.y) / 2 + (dx / len) * off - } - // shorten the line at the target so an arrow sits on the node's rim - let x2 = b.x, - y2 = b.y - const rb = (byId.get(e.t).size / 2) * b.scale - if (e.arrow) { - const fx = cx !== undefined ? cx : a.x, - fy = cx !== undefined ? cy0 : a.y - const dx = b.x - fx, - dy = b.y - fy, - len = Math.hypot(dx, dy) || 1 - const ux = dx / len, - uy = dy / len - const tipX = b.x - ux * rb, - tipY = b.y - uy * rb - const size = Math.max(Math.pow(e.width * 13.37, 0.9), 29) * e.arrowScale * avgScale - x2 = tipX - ux * size * 0.25 - y2 = tipY - uy * size * 0.25 - if (e.underlay) painter.line(a.x, a.y, x2, y2, e.underlay, width + 6 * k, 0.4, cx, cy0) - painter.line(a.x, a.y, x2, y2, color, width, e.opacity, cx, cy0) - const def = cy.renderer().arrowShapes[e.arrow] - if (def && def.points && !fast) { - const pts = [] - for (let i = 0; i < def.points.length; i += 2) { - const px = def.points[i] * size, - py = def.points[i + 1] * size - pts.push([tipX - uy * px + ux * py, tipY + ux * px + uy * py]) - } - painter.poly(pts, mixColor(e.arrowColor, fogColor, fog), e.opacity) - } - } else { - if (e.underlay) painter.line(a.x, a.y, x2, y2, e.underlay, width + 6 * k, 0.4, cx, cy0) - painter.line(a.x, a.y, x2, y2, color, width, e.opacity, cx, cy0) - } - const mx = cx !== undefined ? 0.25 * a.x + 0.5 * cx + 0.25 * b.x : (a.x + b.x) / 2 - const my = cx !== undefined ? 0.25 * a.y + 0.5 * cy0 + 0.25 * b.y : (a.y + b.y) / 2 - projEdges.push({ id: e.id, ax: a.x, ay: a.y, bx: b.x, by: b.y, cx, cy: cy0, mx, my, width }) - if (e.label && !fast) { - const size = e.fontPx * avgScale - if (size >= edgeLabelMin) { - let angle = 0 - if (e.rotate) { - angle = Math.atan2(b.y - a.y, b.x - a.x) - if (angle > Math.PI / 2 || angle < -Math.PI / 2) angle += Math.PI - } - labelsLater.push({ - str: e.label, - x: mx, - y: my, - o: { - size, - color: e.labelColor, - alpha: e.opacity, - align: 'center', - baseline: 'middle', - rotate: angle, - bg: e.labelBg, - }, - }) - } - } - }) - - mark('edges') - // nodes, far to near - const order = nodes - .filter((nd) => P.has(nd.id)) - .sort((p, q) => P.get(q.id).depth - P.get(p.id).depth) - const proj = [] - order.forEach((nd) => { - const pr = P.get(nd.id) - const r = Math.max(1.2 * k, (nd.size / 2) * pr.scale) - const fog = fogOf(pr.depth) - const alpha = nd.opacity - if (nd.underlay) - painter.circle( - pr.x, - pr.y, - r + nd.underlay.pad * pr.scale, - nd.underlay.color, - nd.underlay.alpha * alpha - ) - const bw = nd.borderW > 0 ? Math.max(0.5 * k, Math.min(nd.borderW * pr.scale, 8 * k)) : 0 - const border = mixColor(nd.border, fogColor, fog) - if (nd.shape === 'ellipse' || fast || r < 2.5 * k) { - if (nd.pies.length > 1 && !fast && r > 3 * k) { - painter.circle(pr.x, pr.y, r, mixColor(nd.color, fogColor, fog), alpha) - let a0 = -Math.PI / 2 - nd.pies.forEach(([c, share]) => { - const a1 = a0 + share * Math.PI * 2 - painter.wedge(pr.x, pr.y, r, a0, a1, mixColor(c, fogColor, fog), alpha) - a0 = a1 - }) - if (bw) painter.circle(pr.x, pr.y, r, null, alpha, border, bw) - } else { - const fill = nd.pies.length === 1 ? nd.pies[0][0] : nd.color - painter.circle(pr.x, pr.y, r, mixColor(fill, fogColor, fog), alpha, bw ? border : null, bw) - } - if (shaded && !fast && r > 3 * k) painter.shade(pr.x, pr.y, r, alpha) - } else { - const pts = - nodeShapePoints(nd.shape, pr.x, pr.y, r) || nodeShapePoints('rectangle', pr.x, pr.y, r) - painter.poly(pts, mixColor(nd.color, fogColor, fog), alpha, bw ? border : null, bw) - } - proj.push({ id: nd.id, x: pr.x, y: pr.y, r, depth: pr.depth, scale: pr.scale }) - if (nd.label && !fast) { - const size = nd.fontPx * pr.scale - if (size >= nodeLabelMin) { - let x = pr.x + nd.marginX * pr.scale, - y = pr.y + nd.marginY * pr.scale - let align = 'center', - baseline = 'middle' - if (nd.valign === 'top') { - y = pr.y - r + nd.marginY * pr.scale - baseline = 'bottom' - } else if (nd.valign === 'bottom') { - y = pr.y + r + nd.marginY * pr.scale - baseline = 'top' - } - if (nd.halign === 'left') { - x = pr.x - r + nd.marginX * pr.scale - align = 'right' - } else if (nd.halign === 'right') { - x = pr.x + r + nd.marginX * pr.scale - align = 'left' - } - painter.text(nd.label, x, y, { - size, - color: mixColor(nd.labelColor, fogColor, fog * 0.6), - alpha, - align, - baseline, - halo: nd.halo, - haloWidth: nd.haloW * Math.min(1.5, pr.scale), - }) - } - } - }) - mark('nodes') - labelsLater.forEach((l) => painter.text(l.str, l.x, l.y, l.o)) - painter.done() - mark('labels') - net3d.timing = T - if (!opts.offscreen) { - net3d.proj = proj.reverse() // nearest first, for picking - net3d.projEdges = projEdges - } -} - -// Smallest label size worth drawing: the user's floor, raised so that at -// most `budget` labels are drawn (the largest, i.e. nearest, ones win). -function labelCutoff3d(sizes, floor, budget) { - if (sizes.length <= budget) return floor - const sorted = sizes.filter((v) => v >= floor).sort((a, b) => b - a) - return sorted.length > budget ? Math.max(floor, sorted[budget]) + 1e-9 : floor -} - -function labelFloor3d() { - const min = parseFloat(document.getElementById('labelMinScreenSize').value) || 0 - return Math.max(3, min) -} - -function drawFloor3d(painter, project, k) { - // a square grid under the network, plus short x/y/z axes at the centre - let minY = Infinity, - maxY = -Infinity, - R = 0 - net3d.cache.nodes.forEach((nd) => { - const p = pos3dOf(nd.id) - if (p[1] < minY) minY = p[1] - if (p[1] > maxY) maxY = p[1] - R = Math.max(R, Math.hypot(p[0] - net3d.cam.tx, p[2] - net3d.cam.tz)) - }) - const floorY = maxY + 40 - const half = Math.ceil((R + 60) / 100) * 100 - const step = half / 5 - const color = currentTheme.muted - for (let i = -5; i <= 5; i++) { - const v = i * step - const a = project([net3d.cam.tx + v, floorY, net3d.cam.tz - half]), - b = project([net3d.cam.tx + v, floorY, net3d.cam.tz + half]) - const c = project([net3d.cam.tx - half, floorY, net3d.cam.tz + v]), - d = project([net3d.cam.tx + half, floorY, net3d.cam.tz + v]) - if (a && b) painter.line(a.x * k, a.y * k, b.x * k, b.y * k, color, k, 0.18) - if (c && d) painter.line(c.x * k, c.y * k, d.x * k, d.y * k, color, k, 0.18) - } - const o = [net3d.cam.tx, net3d.cam.ty, net3d.cam.tz] - const len = step - ;[ - [[len, 0, 0], '#e05252', 'x'], - [[0, -len, 0], '#3fae5a', 'y'], - [[0, 0, len], '#3b7ddd', 'z'], - ].forEach(([v, col, name]) => { - const a = project(o), - b = project([o[0] + v[0], o[1] + v[1], o[2] + v[2]]) - if (!a || !b) return - painter.line(a.x * k, a.y * k, b.x * k, b.y * k, col, 2 * k, 0.8) - painter.text(name, b.x * k, b.y * k, { - size: 11 * k, - color: col, - alpha: 0.9, - align: 'center', - baseline: 'middle', - }) - }) -} - -export function render3d() { - if (!net3d.active) return - const cv = canvas3d() - const rect = cv.getBoundingClientRect() - const dpr = window.devicePixelRatio || 1 - const W = Math.max(1, Math.round(rect.width)), - H = Math.max(1, Math.round(rect.height)) - if (cv.width !== Math.round(W * dpr) || cv.height !== Math.round(H * dpr)) { - cv.width = Math.round(W * dpr) - cv.height = Math.round(H * dpr) - } - const ctx = cv.getContext('2d') - ctx.setTransform(dpr, 0, 0, dpr, 0, 0) - const big = - (net3d.cache ? net3d.cache.nodes.length + net3d.cache.edges.length : cy.elements().length) > - 3000 - drawScene3d(canvasPainter(ctx), W, H, { fast: net3d.interacting && big }) - updateZoomReadout3d() -} diff --git a/frontend/src/view3d/export.ts b/frontend/src/view3d/export.ts deleted file mode 100644 index b8dc6b6..0000000 --- a/frontend/src/view3d/export.ts +++ /dev/null @@ -1,189 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { EXPORT_MAX_PIXELS, EXPORT_MAX_SIDE } from '../export/draw' -import { canvas3d, net3d } from './state' -import { canvasPainter, svgPainter } from './painters' -import { currentTheme } from '../themes' -import { drawScene3d } from './draw' -import { fit3d } from './camera' - -/* ---------- image export of the 3D view ---------- */ -export function export3dSize(scale) { - const cv = canvas3d() - const W = cv.clientWidth || 800, - H = cv.clientHeight || 600 - let k = scale - const shrink = Math.min( - 1, - EXPORT_MAX_SIDE / (W * k), - EXPORT_MAX_SIDE / (H * k), - Math.sqrt(EXPORT_MAX_PIXELS / (W * H * k * k)) - ) - k *= shrink - return { W, H, k, outW: Math.round(W * k), outH: Math.round(H * k), limited: shrink < 1 } -} - -function export3dCamera(area) { - if (area !== 'full') return { ...net3d.cam } - const saved = { ...net3d.cam } - fit3d(null, false) - const cam = { ...net3d.cam } - Object.assign(net3d.cam, saved) - return cam -} - -export function renderExportCanvas3d(o) { - const { W, H, k, outW, outH } = export3dSize(o.scale) - const canvas = document.createElement('canvas') - canvas.width = outW - canvas.height = outH - const ctx = canvas.getContext('2d') - const savedHulls = document.getElementById('showGroupHulls').checked - if (!o.hulls) document.getElementById('showGroupHulls').checked = false - try { - drawScene3d(canvasPainter(ctx), W, H, { - cam: export3dCamera(o.area), - bg: o.bg, - pixelScale: k, - offscreen: true, - fogColor: o.bg || currentTheme.bg, - }) - } finally { - document.getElementById('showGroupHulls').checked = savedHulls - } - return canvas -} - -export function buildSvg3d(o) { - const { W, H } = export3dSize(1) - const s = Math.min(o.scale, 8) - const painter = svgPainter(Math.round(W * s), Math.round(H * s)) - const savedHulls = document.getElementById('showGroupHulls').checked - if (!o.hulls) document.getElementById('showGroupHulls').checked = false - try { - drawScene3d(painter, W, H, { - cam: export3dCamera(o.area), - bg: o.bg, - pixelScale: s, - offscreen: true, - fogColor: o.bg || currentTheme.bg, - }) - } finally { - document.getElementById('showGroupHulls').checked = savedHulls - } - return new Blob([painter.toString(o.title)], { type: 'image/svg+xml' }) -} - -/* ============================================================ - STRING IMPORT - Queries the STRING database (https://string-db.org, Szklarczyk et al.) - through its public API: - 1. get_string_ids resolve the typed names for the chosen organism - 2. network the query proteins plus their best interactors - 3. get_string_ids descriptions for every protein in the network - 4. enrichment or functional_annotation term collections for the - network's proteins (GO, KEGG, Reactome, keywords, domains, - diseases, tissues, ...), turned into NORMA groupings - The network and each term collection become ordinary files in the - library, so everything else in NORMA works on them unchanged. - STRING asks callers to wait a second between requests and to identify - themselves (caller_identity); both are respected here. - ============================================================ */ -export const STRING_CALLER = 'NORMA3' - -export const STRING_SPECIES = [ - [9606, 'Homo sapiens (human)'], - [10090, 'Mus musculus (mouse)'], - [10116, 'Rattus norvegicus (rat)'], - [7955, 'Danio rerio (zebrafish)'], - [7227, 'Drosophila melanogaster (fruit fly)'], - [6239, 'Caenorhabditis elegans (nematode)'], - [4932, 'Saccharomyces cerevisiae (baker\u2019s yeast)'], - [4896, 'Schizosaccharomyces pombe (fission yeast)'], - [3702, 'Arabidopsis thaliana (thale cress)'], - [39947, 'Oryza sativa japonica (rice)'], - [511145, 'Escherichia coli K-12 MG1655'], - [224308, 'Bacillus subtilis 168'], - [83332, 'Mycobacterium tuberculosis H37Rv'], - [9031, 'Gallus gallus (chicken)'], - [9913, 'Bos taurus (cattle)'], - [9823, 'Sus scrofa (pig)'], - [9615, 'Canis lupus familiaris (dog)'], - [8364, 'Xenopus tropicalis (western clawed frog)'], - [36329, 'Plasmodium falciparum 3D7 (malaria parasite)'], -] - -// score field -> NORMA channel (the classic palette uses STRING's colors) -export const STRING_CHANNELS = [ - ['nscore', 'neighborhood', 'Gene neighborhood'], - ['fscore', 'fusion', 'Gene fusion'], - ['pscore', 'cooccurrence', 'Co-occurrence'], - ['ascore', 'coexpression', 'Co-expression'], - ['escore', 'experiments', 'Experiments'], - ['dscore', 'database', 'Curated databases'], - ['tscore', 'textmining', 'Text mining'], -] - -// STRING category key -> readable name, in the order they are offered -export const STRING_CATEGORIES = [ - ['Process', 'GO Biological Process', true], - ['Function', 'GO Molecular Function', true], - ['Component', 'GO Cellular Component', true], - ['KEGG', 'KEGG pathways', true], - ['RCTM', 'Reactome pathways', true], - ['WikiPathways', 'WikiPathways', false], - ['Keyword', 'UniProt keywords', true], - ['Pfam', 'Pfam domains', false], - ['InterPro', 'InterPro domains and features', true], - ['SMART', 'SMART domains', false], - ['DISEASES', 'Diseases (DISEASES)', true], - ['TISSUES', 'Tissues (TISSUES)', false], - ['COMPARTMENTS', 'Subcellular localization (COMPARTMENTS)', false], - ['HPO', 'Human phenotypes (Monarch)', false], - ['MPO', 'Mammalian phenotypes (Monarch)', false], - ['DPO', 'Drosophila phenotypes (Monarch)', false], - ['WPO', 'C. elegans phenotypes (Monarch)', false], - ['ZPO', 'Zebrafish phenotypes (Monarch)', false], - ['FYPO', 'Fission yeast phenotypes (Monarch)', false], - ['NetworkNeighborAL', 'Local network clusters (STRING)', false], - ['PMID', 'Reference publications (PubMed)', false], -] - -const STRING_CATEGORY_ALIASES = { - 'go process': 'Process', - 'biological process': 'Process', - 'go function': 'Function', - 'molecular function': 'Function', - 'go component': 'Component', - 'cellular component': 'Component', - 'kegg pathways': 'KEGG', - reactome: 'RCTM', - 'reactome pathways': 'RCTM', - 'uniprot keywords': 'Keyword', - keywords: 'Keyword', -} - -export const STRING_PRIOR = 0.041 - -export const STRING_PREFERRED_GROUPING = [ - 'KEGG', - 'RCTM', - 'Process', - 'WikiPathways', - 'Function', - 'Component', - 'Keyword', - 'InterPro', - 'DISEASES', -] - -export function stringCategoryKey(raw) { - if (!raw) return 'Other' - if (STRING_CATEGORIES.some((c) => c[0] === raw)) return raw - return STRING_CATEGORY_ALIASES[String(raw).toLowerCase()] || raw -} - -export function stringCategoryName(key) { - const c = STRING_CATEGORIES.find((x) => x[0] === key) - return c ? c[1] : key -} diff --git a/frontend/src/view3d/input.ts b/frontend/src/view3d/input.ts deleted file mode 100644 index 76fc7f3..0000000 --- a/frontend/src/view3d/input.ts +++ /dev/null @@ -1,367 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { - VIEW_PRESETS_3D, - fit3d, - focalLength, - moveCamera3d, - rotate3d, - screenToWorldDelta, - zoom3d, -} from './camera' -import { applySpread3d, runLayout3d, updateSpread3dReadout } from './layouts' -import { canvas3d, el3, markDirty3d, net3d, requestRender3d } from './state' -import { cy, onCommitStyle } from '../cy' -import { hideEdgePopup, hideInfo } from '../profiler' -import { pos3dOf } from './cache' -import { toggleAutoRotate3d } from './tab' - -/* ---------- picking ---------- */ -function pickNode3d(x, y) { - for (const p of net3d.proj) { - if (Math.hypot(p.x - x, p.y - y) <= Math.max(p.r, 4)) return p - } - return null -} - -function pickEdge3d(x, y) { - let best = null, - bestD = 6 - for (const e of net3d.projEdges) { - let d - if (e.cx !== undefined) { - d = Infinity - let px = e.ax, - py = e.ay - for (let i = 1; i <= 12; i++) { - const t = i / 12 - const qx = (1 - t) * (1 - t) * e.ax + 2 * (1 - t) * t * e.cx + t * t * e.bx - const qy = (1 - t) * (1 - t) * e.ay + 2 * (1 - t) * t * e.cy + t * t * e.by - d = Math.min(d, segDist(x, y, px, py, qx, qy)) - px = qx - py = qy - } - } else d = segDist(x, y, e.ax, e.ay, e.bx, e.by) - if (d < bestD + e.width / 2) { - bestD = d - best = e - } - } - return best -} - -function segDist(x, y, x1, y1, x2, y2) { - const dx = x2 - x1, - dy = y2 - y1 - const l2 = dx * dx + dy * dy - const t = l2 ? Math.max(0, Math.min(1, ((x - x1) * dx + (y - y1) * dy) / l2)) : 0 - return Math.hypot(x - (x1 + t * dx), y - (y1 + t * dy)) -} - -function updateLook3dReadouts() { - el3('fog3dValue').textContent = Math.round((parseFloat(el3('fog3d').value) || 0) * 100) + '%' - el3('layer3dRow').hidden = !['layers', 'hierarchy', 'degree'].includes(el3('layout3d').value) - el3('layer3dSpacingValue').textContent = el3('layer3dSpacing').value -} - -// page wiring, run by main.ts in the original order -export function init() { - /* ---------- mouse, touch and keyboard ---------- */ - ;(function setupInput3d() { - const cv = canvas3d() - const box = el3('selectBox3d') - let drag = null - const local = (ev) => { - const r = cv.getBoundingClientRect() - return { x: ev.clientX - r.left, y: ev.clientY - r.top } - } - const startInteracting = () => { - net3d.interacting = true - clearTimeout(net3d.interactTimer) - } - const stopInteracting = () => { - clearTimeout(net3d.interactTimer) - net3d.interactTimer = setTimeout(() => { - net3d.interacting = false - requestRender3d() - }, 160) - } - - cv.addEventListener('contextmenu', (ev) => ev.preventDefault()) - cv.addEventListener('pointerdown', (ev) => { - cv.focus() - const p = local(ev) - const node = pickNode3d(p.x, p.y) - let mode - if (ev.button === 2 || ev.button === 1 || ev.altKey) mode = 'pan' - else if (ev.shiftKey && !node) mode = 'box' - else if (node && !ev.shiftKey) mode = 'node' - else mode = 'rotate' - drag = { - mode, - x0: p.x, - y0: p.y, - x: p.x, - y: p.y, - moved: false, - node, - shift: ev.shiftKey, - meta: ev.metaKey || ev.ctrlKey, - cam: { ...net3d.cam }, - } - if (mode === 'node') { - const sel = cy.getElementById(node.id) - drag.group = sel.selected() ? cy.nodes(':selected').map((n) => n.id()) : [node.id] - } - cv.setPointerCapture(ev.pointerId) - ev.preventDefault() - }) - cv.addEventListener('pointermove', (ev) => { - if (!drag) { - const p = local(ev) - cv.style.cursor = pickNode3d(p.x, p.y) ? 'pointer' : 'grab' - return - } - const p = local(ev) - const dx = p.x - drag.x, - dy = p.y - drag.y - if (!drag.moved && Math.hypot(p.x - drag.x0, p.y - drag.y0) < 3) return - if (!drag.moved) { - drag.moved = true - startInteracting() - } - drag.x = p.x - drag.y = p.y - if (drag.mode === 'rotate') { - cv.style.cursor = 'grabbing' - rotate3d(dx * 0.008, dy * 0.008) - } else if (drag.mode === 'pan') { - const H = cv.clientHeight - const scale = focalLength(H) / net3d.cam.dist - const d = screenToWorldDelta(-dx, -dy, scale, net3d.cam) - net3d.cam.tx += d[0] - net3d.cam.ty += d[1] - net3d.cam.tz += d[2] - requestRender3d() - } else if (drag.mode === 'node') { - const d = screenToWorldDelta(dx, dy, drag.node.scale, net3d.cam) - drag.group.forEach((id) => { - const q = pos3dOf(id) - net3d.pos.set(id, [q[0] + d[0], q[1] + d[1], q[2] + d[2]]) - }) - requestRender3d() - } else if (drag.mode === 'box') { - box.hidden = false - box.style.left = Math.min(drag.x0, p.x) + 'px' - box.style.top = Math.min(drag.y0, p.y) + 'px' - box.style.width = Math.abs(p.x - drag.x0) + 'px' - box.style.height = Math.abs(p.y - drag.y0) + 'px' - } - }) - const finish = (ev) => { - if (!drag) return - const p = local(ev) - const d = drag - drag = null - cv.style.cursor = 'grab' - box.hidden = true - if (d.moved) { - stopInteracting() - if (d.mode === 'box') { - const x1 = Math.min(d.x0, p.x), - x2 = Math.max(d.x0, p.x), - y1 = Math.min(d.y0, p.y), - y2 = Math.max(d.y0, p.y) - const ids = net3d.proj - .filter((q) => q.x >= x1 && q.x <= x2 && q.y >= y1 && q.y <= y2) - .map((q) => q.id) - cy.batch(() => ids.forEach((id) => cy.getElementById(id).select())) - } - return - } - // a click - if (d.node) { - const n = cy.getElementById(d.node.id) - if (d.shift || d.meta) { - n.selected() ? n.unselect() : n.select() - return - } - n.emit('tap') - return - } - const edge = pickEdge3d(p.x, p.y) - if (edge) { - cy.getElementById(edge.id).emit('tap') - // place the edge details next to the click - const popup = document.getElementById('edgePopup') - const rect = document.getElementById('canvas').getBoundingClientRect() - popup.style.left = Math.max(10, Math.min(p.x + 14, rect.width - 266)) + 'px' - popup.style.top = Math.max(10, Math.min(p.y + 14, rect.height - 180)) + 'px' - return - } - cy.elements().removeClass('dimmed highlighted') - hideInfo() - hideEdgePopup() - if (!d.shift) cy.$(':selected').unselect() - } - cv.addEventListener('pointerup', finish) - cv.addEventListener('pointercancel', finish) - cv.addEventListener('dblclick', (ev) => { - const p = local(ev) - const node = pickNode3d(p.x, p.y) - if (node) { - const q = pos3dOf(node.id) - moveCamera3d({ tx: q[0], ty: q[1], tz: q[2] }) - } else fit3d() - }) - cv.addEventListener( - 'wheel', - (ev) => { - ev.preventDefault() - startInteracting() - zoom3d(Math.exp(-ev.deltaY * 0.0015)) - stopInteracting() - }, - { passive: false } - ) - cv.addEventListener('keydown', (ev) => { - const k = ev.key - const step = ev.shiftKey ? 0.25 : 0.08 - if (k === 'ArrowLeft') rotate3d(-step, 0) - else if (k === 'ArrowRight') rotate3d(step, 0) - else if (k === 'ArrowUp') rotate3d(0, -step) - else if (k === 'ArrowDown') rotate3d(0, step) - else if (k === '+' || k === '=') zoom3d(1.25) - else if (k === '-' || k === '_') zoom3d(0.8) - else if (k === '0' || k === 'f') fit3d() - else return - ev.preventDefault() - }) - new ResizeObserver(() => requestRender3d()).observe(cv) - })() - - /* ---------- controls ---------- */ - document.getElementById('zoomIn').addEventListener( - 'click', - (ev) => { - if (net3d.active) { - ev.stopImmediatePropagation() - zoom3d(1.25) - } - }, - true - ) - - document.getElementById('zoomOut').addEventListener( - 'click', - (ev) => { - if (net3d.active) { - ev.stopImmediatePropagation() - zoom3d(0.8) - } - }, - true - ) - - document.getElementById('zoomFit').addEventListener( - 'click', - (ev) => { - if (net3d.active) { - ev.stopImmediatePropagation() - fit3d() - } - }, - true - ) - - el3('btnRotL3d').addEventListener('click', () => - moveCamera3d({ yaw: net3d.cam.yaw - Math.PI / 8 }) - ) - - el3('btnRotR3d').addEventListener('click', () => - moveCamera3d({ yaw: net3d.cam.yaw + Math.PI / 8 }) - ) - - el3('btnRotU3d').addEventListener('click', () => - moveCamera3d({ pitch: net3d.cam.pitch - Math.PI / 8 }) - ) - - el3('btnRotD3d').addEventListener('click', () => - moveCamera3d({ pitch: net3d.cam.pitch + Math.PI / 8 }) - ) - - el3('btnReset3d').addEventListener('click', () => { - moveCamera3d({ ...VIEW_PRESETS_3D.tilted }, false) - fit3d() - }) - - el3('btnAuto3d').addEventListener('click', () => { - const on = el3('btnAuto3d').getAttribute('aria-pressed') !== 'true' - el3('autoRotate3d').checked = on - toggleAutoRotate3d(on) - }) - - el3('autoRotate3d').addEventListener('change', () => - toggleAutoRotate3d(el3('autoRotate3d').checked) - ) - - document.querySelectorAll('[data-view3d]').forEach((btn) => { - btn.addEventListener('click', () => { - moveCamera3d({ ...VIEW_PRESETS_3D[btn.dataset.view3d] }, false) - fit3d() - }) - }) - - el3('btnRun3d').addEventListener('click', () => runLayout3d()) - - el3('btnFit3d').addEventListener('click', () => fit3d()) - - el3('layout3d').addEventListener('change', () => { - const algo = el3('layout3d').value - el3('layer3dRow').hidden = !['layers', 'hierarchy', 'degree'].includes(algo) - }) - - el3('layer3dSpacing').addEventListener('input', () => { - el3('layer3dSpacingValue').textContent = el3('layer3dSpacing').value - }) - - el3('spread3d').addEventListener('input', applySpread3d) - - el3('spread3d').addEventListener('dblclick', () => { - el3('spread3d').value = 0 - applySpread3d() - }) - - ;['persp3d', 'fog3d', 'style3d', 'grid3d'].forEach((id) => { - el3(id).addEventListener('input', () => { - updateLook3dReadouts() - requestRender3d() - }) - el3(id).addEventListener('change', () => { - updateLook3dReadouts() - requestRender3d() - }) - }) - - updateLook3dReadouts() - - updateSpread3dReadout() - - // settings that change what the 2D view draws also change the 3D picture - onCommitStyle(() => { - if (net3d.active) markDirty3d() - else net3d.cacheDirty = true - }) - - ;[ - 'showGroupHulls', - 'hullStyle', - 'hullOpacity', - 'edgeCurveStyle', - 'edgeCurvature', - 'labelMinScreenSize', - ].forEach((id) => { - document.getElementById(id).addEventListener('input', requestRender3d) - document.getElementById(id).addEventListener('change', requestRender3d) - }) -} diff --git a/frontend/src/view3d/layouts.ts b/frontend/src/view3d/layouts.ts deleted file mode 100644 index f8c024e..0000000 --- a/frontend/src/view3d/layouts.ts +++ /dev/null @@ -1,411 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { S } from '../state' -import { UNGROUPED, effectiveGroupsFor, getUsedGroups } from '../network_state' -import { VIEW_PRESETS_3D, fit3d, moveCamera3d, shownIds3d } from './camera' -import { - anyEdgeDirected, - edgeIsDirected, - fibonacciBall, - fibonacciSphere, - fr3dAsync, - fr3dLayout, -} from '../export/dialog' -import { computeMetricValues, shownEdges, shownNodes, targetNodeSpacing } from '../metrics' -import { cy } from '../cy' -import { el3, net3d, requestRender3d } from './state' -import { mulberry32 } from '../sample_data' -import { pos3dOf } from './cache' -import { render3d } from './draw' -import { setStatus } from '../layouts/controls' - -/* ---------- layouts ---------- */ -function setLayoutStatus3d(items) { - setStatus('layout3dStatus', items) -} - -function positions2dOf(ids) { - const out = {} - ids.forEach((id) => { - const p = cy.getElementById(id).position() - out[id] = [p.x, p.y] - }) - return out -} - -function centerPositions(map) { - const ids = Object.keys(map) - if (!ids.length) return map - const c = [0, 0, 0] - ids.forEach((id) => { - c[0] += map[id][0] - c[1] += map[id][1] - c[2] += map[id][2] - }) - c.forEach((v, i) => { - c[i] = v / ids.length - }) - ids.forEach((id) => { - map[id] = [map[id][0] - c[0], map[id][1] - c[1], map[id][2] - c[2]] - }) - return map -} - -// Layer index (0, 1, ...) for each node: its ticked groups in legend order; -// nodes in several groups sit between their layers. -function groupLayerOf(nodes) { - const groups = getUsedGroups().filter((g) => S.activeGroups.has(g)) - const rank = new Map(groups.map((g, i) => [g, i])) - const out = {} - nodes.forEach((n) => { - const gs = effectiveGroupsFor(n).filter((g) => rank.has(g)) - out[n.id()] = gs.length ? gs.reduce((s, g) => s + rank.get(g), 0) / gs.length : groups.length - }) - return out -} - -function hierarchyLevels(nodes, edges) { - const ids = nodes.map((n) => n.id()) - const out = new Map(ids.map((id) => [id, []])) - const indeg = new Map(ids.map((id) => [id, 0])) - edges.forEach((e) => { - const s = e.data('source'), - t = e.data('target') - if (!out.has(s) || !out.has(t) || s === t) return - out.get(s).push(t) - indeg.set(t, indeg.get(t) + 1) - if (!edgeIsDirected(e)) { - out.get(t).push(s) - indeg.set(s, indeg.get(s) + 1) - } - }) - const level = new Map() - const directed = anyEdgeDirected(edges) - // roots: nodes nothing points to (directed) or the best-connected node of each component - const byDegree = [...ids].sort((a, b) => out.get(b).length - out.get(a).length) - const roots = directed ? ids.filter((id) => indeg.get(id) === 0 && out.get(id).length) : [] - const bfs = (starts) => { - const queue = [] - starts.forEach((s) => { - if (!level.has(s)) { - level.set(s, 0) - queue.push(s) - } - }) - for (let q = 0; q < queue.length; q++) { - const v = queue[q] - out.get(v).forEach((w) => { - if (!level.has(w)) { - level.set(w, level.get(v) + 1) - queue.push(w) - } - }) - } - } - bfs(roots) - byDegree.forEach((id) => { - if (!level.has(id)) bfs([id]) - }) - return level -} - -async function computeLayout3d(algo) { - const nodes = shownNodes() - const channelOnly = el3('layout3dChannels').checked - const edges = shownEdges(channelOnly) - const ids = nodes.map((n) => n.id()) - const spacing = targetNodeSpacing() - const layerGap = parseFloat(el3('layer3dSpacing').value) || 150 - const pos2 = positions2dOf(ids) - const result = {} - if (!ids.length) return result - - if (algo === 'fr3d') { - const init = {} - const r = await fr3dAsync( - ids, - edges.map((e) => ({ s: e.data('source'), t: e.data('target'), w: e.data('weight') })), - { spacing, seed: 123 }, - net3d.onLayoutProgress - ) - return r - } - if (algo === 'flat') { - ids.forEach((id) => { - result[id] = [pos2[id][0], pos2[id][1], 0] - }) - return centerPositions(result) - } - if (algo === 'layers' || algo === 'hierarchy' || algo === 'degree') { - // the 2D layout lies flat; height (y) comes from groups, levels or degree - let height - if (algo === 'layers') { - const layer = groupLayerOf(nodes) - height = (id) => layer[id] * layerGap - } else if (algo === 'hierarchy') { - const level = hierarchyLevels(nodes, edges) - height = (id) => (level.get(id) || 0) * layerGap - } else { - const deg = computeMetricValues('degree', channelOnly) - const max = Math.max(1, ...Object.values(deg)) - height = (id) => (-(deg[id] || 0) / max) * layerGap * 3 - } - ids.forEach((id) => { - result[id] = [pos2[id][0], height(id), pos2[id][1]] - }) - return centerPositions(result) - } - if (algo === 'sphere') { - const R = spacing * Math.sqrt(ids.length) * 0.5 + spacing - const order = [...nodes].sort((a, b) => b.degree() - a.degree()) - fibonacciSphere(order.length).forEach((p, i) => { - result[order[i].id()] = [p[0] * R, p[1] * R, p[2] * R] - }) - return result - } - if (algo === 'cube') { - const side = Math.ceil(Math.cbrt(ids.length)) - const order = [...nodes].sort((a, b) => b.degree() - a.degree()) - order.forEach((n, i) => { - const x = i % side, - y = Math.floor(i / side) % side, - z = Math.floor(i / (side * side)) - const step = spacing * 1.8 - result[n.id()] = [ - (x - (side - 1) / 2) * step, - (y - (side - 1) / 2) * step, - (z - (side - 1) / 2) * step, - ] - }) - return result - } - if (algo === 'random') { - const rand = mulberry32(7) - const R = spacing * Math.cbrt(ids.length) * 0.9 - ids.forEach((id) => { - result[id] = [(rand() * 2 - 1) * R, (rand() * 2 - 1) * R, (rand() * 2 - 1) * R] - }) - return result - } - if (algo === 'groups3d') { - // each ticked group becomes a ball of nodes (hubs in the middle); the - // balls are placed by a 3D force layout of the group network and then - // pushed apart until they no longer overlap - const groups = getUsedGroups().filter((g) => S.activeGroups.has(g)) - const members = new Map(groups.map((g) => [g, []])) - const memberOf = {} - nodes.forEach((n) => { - let gs = effectiveGroupsFor(n).filter((g) => members.has(g)) - if (!gs.length) { - if (!members.has(UNGROUPED)) members.set(UNGROUPED, []) - gs = [UNGROUPED] - } - memberOf[n.id()] = gs - gs.forEach((g) => members.get(g).push(n)) - }) - const keys = [...members.keys()].filter((g) => members.get(g).length) - const radius = new Map( - keys.map((g) => [g, spacing * 0.55 * Math.cbrt(members.get(g).length) + spacing * 0.3]) - ) - const weight = new Map() - edges.forEach((e) => { - const ga = memberOf[e.data('source')], - gb = memberOf[e.data('target')] - if (!ga || !gb) return - ga.forEach((a) => - gb.forEach((b) => { - if (a === b) return - const key = a < b ? a + '\u0000' + b : b + '\u0000' + a - weight.set(key, (weight.get(key) || 0) + 1) - }) - ) - }) - const metaEdges = [...weight].map(([key, w]) => { - const [s, t] = key.split('\u0000') - return { s, t, w } - }) - const maxR = Math.max(...radius.values()) - const centers = fr3dLayout(keys, metaEdges, { spacing: maxR * 2.4, seed: 11, iterations: 300 }) - const gap = spacing * 0.6 - const needOf = (a, b) => radius.get(a) + radius.get(b) + gap - if (keys.length > 1) { - // scale so that each group's nearest neighbour is about touching, - // then pull far-away groups (often unconnected ones) back in - const ratios = keys - .map((a) => { - let best = Infinity, - need = 1 - keys.forEach((b) => { - if (a === b) return - const d = - Math.hypot( - centers[a][0] - centers[b][0], - centers[a][1] - centers[b][1], - centers[a][2] - centers[b][2] - ) || 0.01 - if (d / needOf(a, b) < best) { - best = d / needOf(a, b) - need = needOf(a, b) - } - }) - return best - }) - .sort((x, y) => x - y) - const factor = 1.15 / ratios[Math.floor(ratios.length / 2)] - keys.forEach((g) => { - centers[g] = centers[g].map((v) => v * factor) - }) - keys.forEach((a) => { - let nearest = null, - best = Infinity - keys.forEach((b) => { - if (a === b) return - const d = Math.hypot( - centers[a][0] - centers[b][0], - centers[a][1] - centers[b][1], - centers[a][2] - centers[b][2] - ) - if (d < best) { - best = d - nearest = b - } - }) - const need = needOf(a, nearest) - if (best > 2.5 * need) { - const t = 1 - (1.6 * need) / best - centers[a] = centers[a].map((v, d) => v + (centers[nearest][d] - v) * t) - } - }) - } - // separate overlapping balls - for (let it = 0; it < 80; it++) { - let moved = false - for (let i = 0; i < keys.length; i++) - for (let j = i + 1; j < keys.length; j++) { - const a = centers[keys[i]], - b = centers[keys[j]] - const dx = b[0] - a[0], - dy = b[1] - a[1], - dz = b[2] - a[2] - const d = Math.hypot(dx, dy, dz) || 0.01 - const need = radius.get(keys[i]) + radius.get(keys[j]) + gap - if (d < need) { - const push = (need - d) / 2 / d - a[0] -= dx * push - a[1] -= dy * push - a[2] -= dz * push - b[0] += dx * push - b[1] += dy * push - b[2] += dz * push - moved = true - } - } - if (!moved) break - } - const acc = {} - keys.forEach((g) => { - const list = [...members.get(g)].sort((a, b) => b.degree() - a.degree()) - const ball = fibonacciBall(list.length, radius.get(g)) - const c = centers[g] - list.forEach((n, i) => { - const id = n.id() - ;(acc[id] = acc[id] || []).push([c[0] + ball[i][0], c[1] + ball[i][1], c[2] + ball[i][2]]) - }) - }) - Object.entries(acc).forEach(([id, list]) => { - result[id] = [0, 1, 2].map((d) => list.reduce((s, p) => s + p[d], 0) / list.length) - }) - return centerPositions(result) - } - return result -} - -export async function runLayout3d(algo) { - algo = algo || el3('layout3d').value - const seq = ++net3d.layoutSeq - el3('btnRun3d').disabled = true - const big3d = shownNodes().length > 300 - setLayoutStatus3d( - big3d ? [{ level: 'busy', text: 'Computing the 3D layout…', progress: null }] : [] - ) - net3d.onLayoutProgress = (f) => { - if (big3d && seq === net3d.layoutSeq) - setLayoutStatus3d([{ level: 'busy', text: 'Computing the 3D layout…', progress: f }]) - } - await new Promise((r) => setTimeout(r, 20)) - try { - const result = await computeLayout3d(algo) - if (seq !== net3d.layoutSeq || !result) return - net3d.spreadApplied = 0 - el3('spread3d').value = 0 - updateSpread3dReadout() - animatePositions3d(result) - net3d.hasLayout = true - if (algo === 'layers' || algo === 'hierarchy' || algo === 'degree') { - moveCamera3d({ ...VIEW_PRESETS_3D.tilted, pitch: 0.55 }, false) - } - setTimeout(() => fit3d(null, true), 520) - setLayoutStatus3d([]) - } catch (err) { - setLayoutStatus3d([ - { level: 'error', text: `The 3D layout couldn't be computed: ${err.message}` }, - ]) - } finally { - if (seq === net3d.layoutSeq) el3('btnRun3d').disabled = false - } -} - -function animatePositions3d(target) { - const ids = Object.keys(target) - const from = new Map(ids.map((id) => [id, pos3dOf(id).slice()])) - const start = performance.now() - const step = (now) => { - const t = Math.min(1, (now - start) / 500) - const e = 1 - Math.pow(1 - t, 3) - ids.forEach((id) => { - const a = from.get(id), - b = target[id] - net3d.pos.set(id, [ - a[0] + (b[0] - a[0]) * e, - a[1] + (b[1] - a[1]) * e, - a[2] + (b[2] - a[2]) * e, - ]) - }) - render3d() - if (t < 1) requestAnimationFrame(step) - } - requestAnimationFrame(step) -} - -export function updateSpread3dReadout() { - const v = parseFloat(el3('spread3d').value) || 0 - el3('spread3dValue').textContent = Math.pow(2, v).toFixed(2) + '×' -} - -export function applySpread3d() { - const v = parseFloat(el3('spread3d').value) || 0 - const ratio = Math.pow(2, v - net3d.spreadApplied) - net3d.spreadApplied = v - updateSpread3dReadout() - const ids = shownIds3d() - if (!ids.length) return - const c = [0, 0, 0] - ids.forEach((id) => { - const p = pos3dOf(id) - c[0] += p[0] - c[1] += p[1] - c[2] += p[2] - }) - c.forEach((x, i) => { - c[i] = x / ids.length - }) - ids.forEach((id) => { - const p = pos3dOf(id) - net3d.pos.set(id, [ - c[0] + (p[0] - c[0]) * ratio, - c[1] + (p[1] - c[1]) * ratio, - c[2] + (p[2] - c[2]) * ratio, - ]) - }) - requestRender3d() -} diff --git a/frontend/src/view3d/painters.ts b/frontend/src/view3d/painters.ts deleted file mode 100644 index dd98753..0000000 --- a/frontend/src/view3d/painters.ts +++ /dev/null @@ -1,226 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -/* ---------- painters: the same drawing code writes to a canvas or to SVG ---------- */ -export function canvasPainter(ctx) { - return { - kind: 'canvas', - clear(W, H, bg) { - ctx.clearRect(0, 0, W, H) - if (bg) { - ctx.fillStyle = bg - ctx.fillRect(0, 0, W, H) - } - }, - pathD(d, st) { - const path = new Path2D(d) - ctx.save() - if (st.blur) ctx.filter = `blur(${st.blur}px)` - if (st.fill) { - ctx.globalAlpha = st.fillAlpha ?? 1 - ctx.fillStyle = st.fill - ctx.fill(path, st.evenodd ? 'evenodd' : 'nonzero') - } - if (st.stroke) { - ctx.globalAlpha = st.strokeAlpha ?? 1 - ctx.strokeStyle = st.stroke - ctx.lineWidth = st.width || 1 - ctx.stroke(path) - } - ctx.restore() - }, - line(x1, y1, x2, y2, color, width, alpha, cx, cy0) { - ctx.globalAlpha = alpha - ctx.strokeStyle = color - ctx.lineWidth = width - ctx.beginPath() - ctx.moveTo(x1, y1) - if (cx !== undefined) ctx.quadraticCurveTo(cx, cy0, x2, y2) - else ctx.lineTo(x2, y2) - ctx.stroke() - }, - circle(x, y, r, fill, alpha, stroke, width) { - ctx.globalAlpha = alpha - ctx.beginPath() - ctx.arc(x, y, r, 0, Math.PI * 2) - if (fill) { - ctx.fillStyle = fill - ctx.fill() - } - if (stroke && width > 0) { - ctx.strokeStyle = stroke - ctx.lineWidth = width - ctx.stroke() - } - }, - wedge(x, y, r, a0, a1, fill, alpha) { - ctx.globalAlpha = alpha - ctx.fillStyle = fill - ctx.beginPath() - ctx.moveTo(x, y) - ctx.arc(x, y, r, a0, a1) - ctx.closePath() - ctx.fill() - }, - poly(pts, fill, alpha, stroke, width) { - ctx.globalAlpha = alpha - ctx.beginPath() - pts.forEach((p, i) => (i ? ctx.lineTo(p[0], p[1]) : ctx.moveTo(p[0], p[1]))) - ctx.closePath() - if (fill) { - ctx.fillStyle = fill - ctx.fill() - } - if (stroke && width > 0) { - ctx.strokeStyle = stroke - ctx.lineWidth = width - ctx.stroke() - } - }, - shade(x, y, r, alpha) { - const g = ctx.createRadialGradient(x - r * 0.35, y - r * 0.35, r * 0.1, x, y, r) - g.addColorStop(0, 'rgba(255,255,255,0.55)') - g.addColorStop(0.45, 'rgba(255,255,255,0.05)') - g.addColorStop(1, 'rgba(0,0,0,0.35)') - ctx.globalAlpha = alpha - ctx.fillStyle = g - ctx.beginPath() - ctx.arc(x, y, r, 0, Math.PI * 2) - ctx.fill() - }, - text(str, x, y, o) { - const font = `${Math.round(o.size * 2) / 2}px Inter, Helvetica, Arial, sans-serif` - if (!o.rotate && !o.bg) { - // common case: no state to save - ctx.globalAlpha = o.alpha - if (ctx.font !== font) ctx.font = font - ctx.textAlign = o.align - ctx.textBaseline = o.baseline - if (o.halo && o.haloWidth > 0) { - ctx.lineWidth = o.haloWidth * 2 - ctx.strokeStyle = o.halo - ctx.lineJoin = 'round' - ctx.strokeText(str, x, y) - } - ctx.fillStyle = o.color - ctx.fillText(str, x, y) - return - } - ctx.save() - ctx.globalAlpha = o.alpha - ctx.font = font - ctx.textAlign = o.align - ctx.textBaseline = o.baseline - ctx.translate(x, y) - if (o.rotate) ctx.rotate(o.rotate) - if (o.bg) { - const w = ctx.measureText(str).width - const h = o.size * 1.2 - const left = o.align === 'center' ? -w / 2 : o.align === 'right' ? -w : 0 - ctx.fillStyle = o.bg - ctx.globalAlpha = o.alpha * 0.85 - ctx.fillRect(left - 2, -h / 2, w + 4, h) - ctx.globalAlpha = o.alpha - } - if (o.halo && o.haloWidth > 0) { - ctx.lineWidth = o.haloWidth * 2 - ctx.strokeStyle = o.halo - ctx.lineJoin = 'round' - ctx.strokeText(str, 0, 0) - } - ctx.fillStyle = o.color - ctx.fillText(str, 0, 0) - ctx.restore() - }, - done() { - ctx.globalAlpha = 1 - }, - } -} - -export function svgPainter(W, H) { - const out = [] - const f = (v) => (Math.round(v * 100) / 100).toString() - const esc = (v) => - String(v).replace( - /[&<>"]/g, - (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"' })[c] - ) - const op = (a) => (a < 1 ? ` opacity="${f(a)}"` : '') - let blurId = 0 - const defs = [ - '', - ] - return { - kind: 'svg', - clear(w, h, bg) { - if (bg) out.push(``) - }, - pathD(d, st) { - let filter = '' - if (st.blur) { - const id = 'b' + ++blurId - defs.push( - `` - ) - filter = ` filter="url(#${id})"` - } - out.push( - `` - ) - }, - line(x1, y1, x2, y2, color, width, alpha, cx, cy0) { - const d = - cx !== undefined - ? `M${f(x1)},${f(y1)}Q${f(cx)},${f(cy0)} ${f(x2)},${f(y2)}` - : `M${f(x1)},${f(y1)}L${f(x2)},${f(y2)}` - out.push( - `` - ) - }, - circle(x, y, r, fill, alpha, stroke, width) { - out.push( - ` 0 ? ` stroke="${stroke}" stroke-width="${f(width)}"` : ''}${op(alpha)}/>` - ) - }, - wedge(x, y, r, a0, a1, fill, alpha) { - const large = a1 - a0 > Math.PI ? 1 : 0 - out.push( - `` - ) - }, - poly(pts, fill, alpha, stroke, width) { - out.push( - ` 0 ? ` stroke="${stroke}" stroke-width="${f(width)}"` : ''}${op(alpha)}/>` - ) - }, - shade(x, y, r, alpha) { - out.push(``) - }, - text(str, x, y, o) { - const anchor = o.align === 'center' ? 'middle' : o.align === 'right' ? 'end' : 'start' - const base = - o.baseline === 'middle' - ? 'central' - : o.baseline === 'top' - ? 'text-before-edge' - : 'text-after-edge' - const rot = o.rotate - ? ` transform="rotate(${f((o.rotate * 180) / Math.PI)} ${f(x)} ${f(y)})"` - : '' - const halo = - o.halo && o.haloWidth > 0 - ? ` stroke="${o.halo}" stroke-width="${f(o.haloWidth * 2)}" stroke-linejoin="round" paint-order="stroke"` - : '' - const bgHalo = o.bg - ? ` stroke="${o.bg}" stroke-width="${f(o.size * 0.5)}" stroke-linejoin="round" paint-order="stroke"` - : '' - out.push( - `${esc(str)}` - ) - }, - done() {}, - toString(title) { - return `\n\n${esc(title || 'NORMA 3D network')}\n${defs.join('')}\n${out.join('\n')}\n` - }, - } -} diff --git a/frontend/src/view3d/state.ts b/frontend/src/view3d/state.ts deleted file mode 100644 index 822397b..0000000 --- a/frontend/src/view3d/state.ts +++ /dev/null @@ -1,86 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { cy } from '../cy' -import { normalizeCssColor } from '../layouts/controls' -import { render3d } from './draw' - -/* ---------- state ---------- */ -export const net3d = { - active: false, - pos: new Map(), // node id -> [x, y, z] - cam: { yaw: 0.6, pitch: 0.35, dist: 900, tx: 0, ty: 0, tz: 0 }, - hasLayout: false, - cache: null, - cacheDirty: true, - frameQueued: false, - interacting: false, - interactTimer: null, - autoTimer: null, - lastFrame: 0, - proj: [], // last projected nodes, near first - projEdges: [], - layoutSeq: 0, - anim: null, - spreadApplied: 0, -} - -export function el3(id) { - return document.getElementById(id) -} - -export function canvas3d() { - return el3('cy3d') -} - -export function markDirty3d() { - net3d.cacheDirty = true - requestRender3d() -} - -export function requestRender3d() { - if (!net3d.active || net3d.frameQueued) return - net3d.frameQueued = true - requestAnimationFrame(() => { - net3d.frameQueued = false - render3d() - }) -} - -/* ---------- colors ---------- */ -const colorCache3d = new Map() - -export function rgbOf(color) { - if (colorCache3d.has(color)) return colorCache3d.get(color) - let rgb = [136, 136, 136] - const s = String(color || '').trim() - let m - if ((m = /^#([0-9a-f]{3})$/i.exec(s))) rgb = [...m[1]].map((c) => parseInt(c + c, 16)) - else if ((m = /^#([0-9a-f]{6})/i.exec(s))) - rgb = [0, 2, 4].map((i) => parseInt(m[1].slice(i, i + 2), 16)) - else if ((m = /rgba?\(([^)]+)\)/i.exec(s))) - rgb = m[1] - .split(',') - .slice(0, 3) - .map((v) => parseFloat(v)) - else { - const hex = typeof normalizeCssColor === 'function' ? normalizeCssColor(s) : null - if (hex) return rgbOf(hex) - } - colorCache3d.set(color, rgb) - return rgb -} - -export function mixColor(color, bg, t) { - if (t <= 0) return color - const a = rgbOf(color), - b = rgbOf(bg) - return `rgb(${Math.round(a[0] + (b[0] - a[0]) * t)},${Math.round(a[1] + (b[1] - a[1]) * t)},${Math.round(a[2] + (b[2] - a[2]) * t)})` -} - -// page wiring, run by main.ts in the original order -export function init() { - cy.on('add remove data select unselect style class', () => { - if (net3d.active) markDirty3d() - else net3d.cacheDirty = true - }) -} diff --git a/frontend/src/view3d/tab.ts b/frontend/src/view3d/tab.ts deleted file mode 100644 index 5daa36a..0000000 --- a/frontend/src/view3d/tab.ts +++ /dev/null @@ -1,119 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { cy } from '../cy' -import { el3, net3d, requestRender3d } from './state' -import { fit3d, wrapAngle } from './camera' -import { render3d } from './draw' -import { runLayout3d, updateSpread3dReadout } from './layouts' -import { updateZoomReadout } from '../profiler' - -/* ---------- entering and leaving the 3D tab ---------- */ -export function setMode3d(on) { - net3d.active = on - document.getElementById('canvas').classList.toggle('mode3d', on) - el3('cy3d').hidden = !on - el3('nav3d').hidden = !on - el3('section3d').hidden = !on - const layout2d = document.getElementById('layoutSection') - if (layout2d) layout2d.hidden = on - document.getElementById('hint').textContent = on - ? 'Drag to rotate · drag a node to move it · right-drag to pan · scroll to zoom · Shift-drag to select · double-click to fit' - : 'Drag nodes · Shift-drag or Shift-click to select several · scroll to zoom · double-click to recenter' - if (on) { - net3d.cacheDirty = true - if (!net3d.hasLayout && cy.nodes().length) { - // first visit for this view: start from the 2D picture, then lay out in 3D - cy.nodes().forEach((n) => { - if (!net3d.pos.has(n.id())) { - const p = n.position() - net3d.pos.set(n.id(), [p.x, p.y, 0]) - } - }) - fit3d(null, false) - runLayout3d(el3('layout3d').value) - } else { - render3d() - } - toggleAutoRotate3d(el3('autoRotate3d').checked) - } else { - toggleAutoRotate3d(false) - updateZoomReadout() - } -} - -// per-view state -export function capture3d() { - const pos = {} - net3d.pos.forEach((p, id) => { - pos[id] = p - }) - return { pos, cam: { ...net3d.cam }, hasLayout: net3d.hasLayout, spread: net3d.spreadApplied } -} - -export function restore3d(state) { - net3d.pos = new Map(state && state.pos ? Object.entries(state.pos) : []) - net3d.cam = - state && state.cam - ? { ...state.cam } - : { yaw: 0.6, pitch: 0.35, dist: 900, tx: 0, ty: 0, tz: 0 } - net3d.hasLayout = !!(state && state.hasLayout) - net3d.spreadApplied = (state && state.spread) || 0 - el3('spread3d').value = net3d.spreadApplied - updateSpread3dReadout() - net3d.cacheDirty = true - net3d.layoutSeq++ - if (net3d.active) { - if (!net3d.hasLayout && cy.nodes().length) { - cy.nodes().forEach((n) => { - if (!net3d.pos.has(n.id())) { - const p = n.position() - net3d.pos.set(n.id(), [p.x, p.y, 0]) - } - }) - fit3d(null, false) - runLayout3d(el3('layout3d').value) - } else render3d() - } -} - -// new data in the current view: 3D positions start over -export function reset3dForNewData() { - net3d.pos = new Map() - net3d.hasLayout = false - net3d.cacheDirty = true - net3d.layoutSeq++ - if (net3d.active && cy.nodes().length) { - cy.nodes().forEach((n) => { - const p = n.position() - net3d.pos.set(n.id(), [p.x, p.y, 0]) - }) - fit3d(null, false) - runLayout3d(el3('layout3d').value) - } -} - -/* ---------- auto-rotate ---------- */ -export function toggleAutoRotate3d(on) { - cancelAnimationFrame(net3d.autoTimer) - net3d.autoTimer = null - el3('btnAuto3d').setAttribute('aria-pressed', on ? 'true' : 'false') - if (!on || !net3d.active) return - let last = performance.now() - const tick = (now) => { - const speed = parseFloat(el3('autoSpeed3d').value) || 1 - net3d.cam.yaw = wrapAngle(net3d.cam.yaw + ((now - last) / 1000) * 0.35 * speed) - last = now - const big = net3d.cache && net3d.cache.nodes.length + net3d.cache.edges.length > 3000 - if (big) { - net3d.interacting = true - clearTimeout(net3d.interactTimer) - net3d.interactTimer = setTimeout(() => { - net3d.interacting = false - requestRender3d() - }, 200) - } - render3d() - net3d.autoTimer = requestAnimationFrame(tick) - } - net3d.autoTimer = requestAnimationFrame(tick) -} diff --git a/frontend/src/viewbar.ts b/frontend/src/viewbar.ts deleted file mode 100644 index f23e936..0000000 --- a/frontend/src/viewbar.ts +++ /dev/null @@ -1,54 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { activeView, createView, renderViewBar, switchView, uniqueViewName } from './profiler' - -function setRenaming(on) { - document.getElementById('viewSelectRow').hidden = on - document.getElementById('viewRenameRow').hidden = !on - const input = document.getElementById('viewNameInput') - if (on) { - input.value = activeView() ? activeView().name : '' - input.focus() - input.select() - } else { - document.getElementById('viewSelect').focus() - } -} - -function saveRename() { - const v = activeView() - const name = document.getElementById('viewNameInput').value.trim() - if (v && name && name !== v.name) { - v.name = uniqueViewName(name) - v.autoName = false - } - setRenaming(false) - renderViewBar() -} - -// page wiring, run by main.ts in the original order -export function init() { - /* ---------- view bar controls ---------- */ - document - .getElementById('viewSelect') - .addEventListener('change', (e) => switchView(e.target.value)) - - document.getElementById('btnViewDuplicate').addEventListener('click', () => { - const cur = activeView() - createView(`${cur ? cur.name : 'View'} copy`, { copy: true }) - }) - - document.getElementById('btnViewRename').addEventListener('click', () => setRenaming(true)) - - document.getElementById('btnViewRenameSave').addEventListener('click', saveRename) - - document.getElementById('viewNameInput').addEventListener('keydown', (e) => { - if (e.key === 'Enter') { - e.preventDefault() - saveRename() - } else if (e.key === 'Escape') { - e.preventDefault() - setRenaming(false) - } - }) -} diff --git a/frontend/src/welcome.ts b/frontend/src/welcome.ts deleted file mode 100644 index 6fe6950..0000000 --- a/frontend/src/welcome.ts +++ /dev/null @@ -1,132 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { cy } from './cy' -import { switchSideTab } from './side_tabs' -import { switchTab } from './wiring' - -/* ---------- welcome card ---------- */ -export function updateEmptyState() { - const el = document.getElementById('emptyState') - if (!el) return - const empty = !cy.nodes().length - el.hidden = !empty - document.getElementById('canvas').classList.toggle('is-empty', empty) -} - -function openWelcomeExample() { - switchSideTab('data') - const sel = document.getElementById('sampleSelect') - sel.value = 'norma:cascade' - document.getElementById('btnSample').click() - switchTab('network') -} - -/* ============================================================ - COMMUNITY DETECTION - All algorithms work on the profiler's simple undirected graph - ({ ids, n, m, adj }) and return { membership, count, sizes, modularity }. - Randomized steps use a fixed seed, so results are repeatable. - louvain Blondel et al. 2008 (resolution parameter) - leidenCommunities Traag, Waltman & van Eck 2019 - labelPropagation Raghavan, Albert & Kumara 2007 - walktrap Pons & Latapy 2005 (random walks of length t) - markovClustering van Dongen 2000 (MCL, inflation parameter) - ============================================================ */ -export const COMMUNITY_ALGORITHMS = { - louvain: { label: 'Louvain', short: 'Louvain' }, - leiden: { label: 'Leiden', short: 'Leiden' }, - lpa: { label: 'Label propagation', short: 'label propagation' }, - walktrap: { label: 'Walktrap', short: 'Walktrap' }, - mcl: { label: 'Markov clustering (MCL)', short: 'MCL' }, -} - -export const WALKTRAP_NODE_LIMIT = 2000 - -// Renumbers communities 0..k-1 in order of first appearance and scores the -// partition by (resolution-free) modularity on the original graph. -export function partitionStats(g, raw) { - const n = g.n - const remap = new Map() - const membership = new Int32Array(n) - for (let i = 0; i < n; i++) { - if (!remap.has(raw[i])) remap.set(raw[i], remap.size) - membership[i] = remap.get(raw[i]) - } - const count = remap.size - const sizes = new Array(count).fill(0) - const inW = new Float64Array(count), - totW = new Float64Array(count) - const twoM = 2 * g.m - for (let u = 0; u < n; u++) { - const cu = membership[u] - sizes[cu]++ - totW[cu] += g.adj[u].length - const a = g.adj[u] - for (let k = 0; k < a.length; k++) if (membership[a[k]] === cu) inW[cu] += 1 - } - let q = 0 - if (twoM) for (let c = 0; c < count; c++) q += inW[c] / twoM - Math.pow(totW[c] / twoM, 2) - return { membership, count, sizes, modularity: twoM ? q : NaN } -} - -// Splits communities that fall apart into connected pieces. -export function splitDisconnected(g, raw) { - const n = g.n - const out = new Int32Array(n).fill(-1) - let next = 0 - for (let s0 = 0; s0 < n; s0++) { - if (out[s0] >= 0) continue - const c = raw[s0] - out[s0] = next - const stack = [s0] - while (stack.length) { - const v = stack.pop() - const a = g.adj[v] - for (let k = 0; k < a.length; k++) { - const u = a[k] - if (out[u] < 0 && raw[u] === c) { - out[u] = next - stack.push(u) - } - } - } - next++ - } - return out -} - -// page wiring, run by main.ts in the original order -export function init() { - cy.on('add remove', () => requestAnimationFrame(updateEmptyState)) - - document.getElementById('btnEmptyExample').addEventListener('click', openWelcomeExample) - - document.getElementById('btnEmpty2Example').addEventListener('click', openWelcomeExample) - - document.getElementById('btnEmpty2Db').addEventListener('click', () => switchSideTab('db')) - - document.getElementById('btnEmpty2Upload').addEventListener('click', () => { - switchSideTab('data') - document.getElementById('btnNormaAdd').click() - }) - - document.getElementById('btnEmpty2Welcome').addEventListener('click', () => switchTab('welcome')) - - document.getElementById('btnEmptyString').addEventListener('click', () => { - switchSideTab('db') - document.getElementById('stringSection').classList.remove('collapsed') - document.querySelector('#stringSection > h3').setAttribute('aria-expanded', 'true') - const q = document.getElementById('stringQuery') - q.scrollIntoView({ block: 'center', behavior: 'smooth' }) - q.focus() - }) - - document.getElementById('btnEmptyUpload').addEventListener('click', () => { - switchSideTab('data') - document.getElementById('btnNormaAdd').click() - }) - - document - .getElementById('btnEmptyHelp') - .addEventListener('click', () => switchTab('help', 'help-start')) -} diff --git a/frontend/src/wiring.ts b/frontend/src/wiring.ts deleted file mode 100644 index 864f915..0000000 --- a/frontend/src/wiring.ts +++ /dev/null @@ -1,1154 +0,0 @@ -// @ts-nocheck -// ponytail: split verbatim from the former single-file script; typed one file at a time (remove @ts-nocheck as it lands) -import { S } from './state' -import { - activeView, - nameForSelection, - openInNewView, - renderProfilerNetworkList, - renderViewBar, - selectionFromKey, - uniqueViewName, -} from './profiler' -import { buildModuleNetwork, generateDirectedMultiNetwork, mulberry32 } from './sample_data' -import { convertArena3dNetwork } from './arena3d' -import { cy } from './cy' -import { demoToNormaTexts } from './demo_downloads' -import { drawGroupHulls, resizeHullCanvas } from './hulls' -import { exportNormaAnnotation, exportNormaColors, exportNormaNetwork } from './export_norma' -import { handleNormaUploads } from './uploads' -import { libSelection, plural, setStatus } from './layouts/controls' -import { net3d } from './view3d/state' -import { refreshEnrichmentChoices } from './enrichment' -import { refreshLibraryView } from './library' -import { renderCompareList } from './label_colors' -import { setMode3d } from './view3d/tab' - -// Example files from NORMA (github.com/PavlopoulosLab/NORMA, MIT license), -// www/Examples/, embedded verbatim so they work offline. -export const NORMA_EXAMPLE_SETS = { - 'string-tp53': { - title: 'STRING: TP53 interactors', - source: 'STRING database export', - link: null, - files: [ - { - kind: 'network', - name: 'STRING TP53', - fileName: 'string_interactions.txt', - text: 'Source\tTarget\tWeight\nCDKN1A\tTP53\t70\nTP53\tMDM2\t2\nMDM4\tTP53\t3\nBCL2L1\tTP53\t4\nCHEK2\tATM\t5\nTP53\tEP300\t20\nATM\tTP53\t7\nTP53\tCREBB\t1\nMDM4\tMDM2\t1\nCHEK2\tTP53\t1\nTP53BP2\tTP53\t1\nCDKN2A\tTP53\t1\nCDKN2A\tMDM2\t1\nATM\tMDM2\t2\nEP300\tCREBBP\t1\nMDM4\tATM\t2\nCHEK2\tMDM4\t1\nCHEK2\tMDM2\t1\nCDKN2A\tCDKN1A\t1\nCDKN2A\tMDM4\t1\nEP300\tMDM2\t1\nCDKN1A\tEP300\t1\nCREBBP\tMDM2\t1\nCDKN1A\tMDM2\t1\nCDKN2A\tBCL2L1\t1\nBCL2L1\tMDM2\t2\nCDKN2A\tATM\t1\nCDKN1A\tMDM4\t1\nCDKN1A\tCHEK2\t1\nCDKN1A\tATM\t2\nCDKN1A\tCREBBP\t1\nCDKN1A\tBCL2L1\t1\nCDKN2A\tCHEK2\t1\nATM\tEP300\t1\nTP53BP2\tBCL2L1\t3\nCDKN2A\tEP300\t3\nBCL2L1\tATM\t3\nMDM4\tEP300\t1\nATM\tCREBBP\t1\nCHEK2\tEP300\t1\nTP53BP2\tMDM2\t1\nCHEK2\tBCL2L1\t1\nCDKN2A\tCREBBP\t1\nTP53BP2\tEP300\t1\nBCL2L1\tEP300\t1\nMDM4\tBCL2L1\t1\n', - }, - { - kind: 'annotation', - name: 'STRING TP53 groups', - fileName: 'string_interactions_groups_comma_duplicate.txt', - text: 'Group-1\tBCL2L1,MDM4,MDM2,CHEK2\nGroup-2\tCDKN2A,ATM,TP53BP2,MDM2\nGroup-3\tCHEK2,MDM2\nGroup-4\tTP53,EP300\nGroup-5\tMDM4,MDM2\n', - }, - { - kind: 'colors', - name: 'STRING TP53 expression', - fileName: 'string_expression_colors.txt', - text: 'CDKN1A\tblue\nTP53\tblue\nMDM4\tblue\nBCL2L1\tred\nCHEK2\tred\nATM\tred\nTP53BP2\tred\nCDKN2A\tblue\nEP300\tred\nCREBBP\tred\n', - }, - ], - }, - 'string-bcar3': { - title: 'STRING: BCAR3 interactors', - source: 'STRING database export', - link: null, - files: [ - { - kind: 'network', - name: 'STRING BCAR3', - fileName: 'BCAR3.txt', - text: 'Source\tTarget\nVCP\tNPLOC4\nBCAR1\tPXN\nVCP\tDERL2\nNSFL1C\tVCP\nCDC42\tWASL\nVCP\tDERL1\nNPLOC4\tUFD1L\nSYVN1\tVCP\nVCP\tUFD1L\nCDC42\tWAS\nCDC42\tPAK1\nCDC42\tBAIAP2\nVCP\tFAF2\nCDC42\tARHGAP1\nVIMP\tVCP\nCDC42\tPARD6A\nCDC42\tTNK2\nCDC42\tITSN1\nCDC42\tARHGDIA\nCDC42\tPARD6B\nSYVN1\tDERL2\nCDC42\tPAK2\nVIMP\tDERL1\nDERL1\tDERL2\nWAS\tBAIAP2\nCDC42\tPXN\nFAF2\tDERL2\nSYVN1\tDERL1\nUFD1L\tFAF2\nNPLOC4\tFAF2\nBCAR1\tBCAR3\nITSN1\tWASL\nBAIAP2\tWASL\nBCAR1\tTNK2\nBCAR1\tCDC42\nPAK1\tPXN\nPAK1\tARHGDIA\nFAF2\tDERL1\nNEDD9\tPXN\nPAK2\tPAK1\nVIMP\tDERL2\nSYVN1\tFAF2\nVIMP\tSYVN1\nCDC42\tBCAR3\nUFD1L\tDERL1\nPAK2\tPXN\nNSFL1C\tUFD1L\nNEDD9\tBCAR3\nPARD6B\tPARD6A\nBAIAP2\tPXN\nNSFL1C\tNPLOC4\nBCAR1\tBAIAP2\nPAK2\tPARD6A\nSYVN1\tUFD1L\nWAS\tWASL\nTULP4\tSPSB1\nSYVN1\tNPLOC4\nVIMP\tFAF2\nUFD1L\tDERL2\nNPLOC4\tDERL1\nNPLOC4\tDERL2\nITSN1\tWAS\nVIMP\tNPLOC4\nTNK2\tWAS\nNSFL1C\tFAF2\nTULP4\tKCNE4\nBCAR3\tTULP4\nBCAR3\tKCNE4\nNSFL1C\tDERL2\nSAT1\tBCAR3\nNSFL1C\tDERL1\nBCAR3\tVCP\nPAK2\tARHGDIA\nKCNE4\tTULP1\nBCAR3\tTULP1\nPXN\tWASL\nVIMP\tUFD1L\nWAS\tARHGAP1\nWAS\tPXN\nWAS\tPAK1\nBCAR3\tSPSB1\nARHGAP1\tARHGDIA\nBCAR1\tPARD6A\nPAK1\tWASL\nBCAR1\tWASL\nARHGDIA\tPXN\nBCAR1\tWAS\nPAK2\tWASL\nWAS\tPAK2\nARHGAP1\tPXN\nARHGDIA\tWASL', - }, - { - kind: 'annotation', - name: 'BCAR3 KEGG pathways', - fileName: 'BCAR3_KEGG.txt', - text: 'Protein processing in endoplasmic reticulum\tDERL1,DERL2,NPLOC4,NSFL1C,SYVN1,UFD1L,VCP,VIMP\nRegulation of actin cytoskeleton\tBAIAP2,BCAR1,CDC42,PAK1,PAK2,PXN,WAS,WASL\nChemokine signaling pathway\tBCAR1,CDC42,PAK1,PXN,WAS,WASL\nBacterial invasion of epithelial cells\tBCAR1,CDC42,PXN,WAS,WASL\nTight junction\tCDC42,PARD6A,PARD6B,WAS,WASL\nAxon guidance\tCDC42,PAK1,PAK2,PARD6A,PARD6B\nFocal adhesion\tBCAR1,CDC42,PAK1,PAK2,PXN\nEndocytosis\tCDC42,PARD6A,PARD6B,WAS,WASL\nAdherens junction\tBAIAP2,CDC42,WAS,WASL\nFc gamma R-mediated phagocytosis\tCDC42,PAK1,WAS,WASL\nRap1 signaling pathway\tBCAR1,CDC42,PARD6A,PARD6B\nHuman papillomavirus infection\tCDC42,PARD6A,PARD6B,PXN\nPathogenic Escherichia coli infection\tCDC42,WAS,WASL\nShigellosis\tCDC42,WAS,WASL\nRenal cell carcinoma\tCDC42,PAK1,PAK2\nSalmonella infection\tCDC42,WAS,WASL\nT cell receptor signaling pathway\tCDC42,PAK1,PAK2\nLeukocyte transendothelial migration\tBCAR1,CDC42,PXN\nProteoglycans in cancer\tCDC42,PAK1,PXN\nRas signaling pathway\tCDC42,PAK1,PAK2\nMAPK signaling pathway\tCDC42,PAK1,PAK2\nVEGF signaling pathway\tCDC42,PXN\nEpithelial cell signaling in Helicobacter pylori infection\tCDC42,PAK1\nErbB signaling pathway\tPAK1,PAK2\nCholine metabolism in cancer\tWAS,WASL\nNeurotrophin signaling pathway\tARHGDIA,CDC42\nHippo signaling pathway\tPARD6A,PARD6B', - }, - { - kind: 'annotation', - name: 'BCAR3 GO molecular function', - fileName: 'BCAR3_GO_MF.txt', - text: 'protein binding\tARHGAP1,BAIAP2,BCAR1,BCAR3,CDC42,DERL1,FAF2,ITSN1,KCNE4,NPLOC4,NSFL1C,PAK1,PAK2,PARD6A,PXN,SAT1,SYVN1,TNK2,TULP1,UFD1L,VCP,VIMP,WAS,WASL\nenzyme binding\tARHGAP1,BCAR1,BCAR3,CDC42,DERL1,FAF2,ITSN1,NPLOC4,NSFL1C,PAK1,PAK2,PARD6A,PXN,SYVN1,TNK2,UFD1L,VCP,VIMP,WAS\nmolecular function regulator\tARHGAP1,ARHGDIA,BCAR3,FAF2,ITSN1,NSFL1C,PAK2,TNK2,VCP,WAS,WASL\nenzyme regulator activity\tARHGAP1,ARHGDIA,FAF2,ITSN1,NSFL1C,PAK2,TNK2,VCP,WAS,WASL\nidentical protein binding\tBAIAP2,CDC42,PAK1,PAK2,SAT1,TNK2,VCP,WAS\nprotein kinase binding\tBCAR1,CDC42,PAK1,PAK2,PARD6A,PXN,WAS\nGTPase binding\tARHGAP1,BCAR3,ITSN1,PAK1,PAK2,PARD6A,WAS\nprotein domain specific binding\tARHGAP1,BAIAP2,BCAR1,CDC42,TNK2,VCP,WAS\nubiquitin protein ligase binding\tDERL1,FAF2,NPLOC4,PXN,TNK2,VCP\nRas GTPase binding\tARHGAP1,ITSN1,PAK1,PAK2,PARD6A,WAS\nATPase binding\tDERL1,NSFL1C,SYVN1,UFD1L,VIMP\nRho GTPase binding\tITSN1,PAK1,PAK2,PARD6A,WAS\nGTPase regulator activity\tARHGAP1,ARHGDIA,TNK2,WAS,WASL\nenzyme activator activity\tARHGAP1,ARHGDIA,ITSN1,PAK2,VCP\nubiquitin-specific protease binding\tDERL1,SYVN1,VCP,VIMP\nprotein serine/threonine kinase activity\tCDC42,PAK1,PAK2,TNK2\nRac GTPase binding\tPAK1,PAK2,WAS\nubiquitin binding\tFAF2,NPLOC4,NSFL1C\nSH3 domain binding\tARHGAP1,BCAR1,WAS\nprotein binding, bridging\tARHGAP1,BAIAP2,BCAR3\n', - }, - { - kind: 'annotation', - name: 'BCAR3 GO biological process', - fileName: 'BCAR3_GO_BP.txt', - text: 'cellular process\tARHGAP1,ARHGDIA,BAIAP2,BCAR1,BCAR3,CDC42,DERL1,DERL2,FAF2,ITSN1,KCNE4,NEDD9,NPLOC4,NSFL1C,PAK1,PAK2,PARD6A,PARD6B,PXN,SAT1,SPSB1,SYVN1,TNK2,TULP1,TULP4,UFD1L,VCP,VIMP,WAS,WASL\nbiological regulation\tARHGAP1,ARHGDIA,BAIAP2,BCAR1,BCAR3,CDC42,DERL1,DERL2,FAF2,ITSN1,KCNE4,NEDD9,NPLOC4,NSFL1C,PAK1,PAK2,PARD6A,PARD6B,PXN,SAT1,SYVN1,TNK2,TULP1,UFD1L,VCP,VIMP,WAS,WASL\nregulation of biological process\tARHGAP1,ARHGDIA,BAIAP2,BCAR1,BCAR3,CDC42,DERL1,DERL2,ITSN1,KCNE4,NEDD9,NPLOC4,NSFL1C,PAK1,PAK2,PARD6A,PARD6B,PXN,SAT1,SYVN1,TNK2,TULP1,UFD1L,VCP,VIMP,WAS,WASL\nregulation of cellular process\tARHGAP1,ARHGDIA,BAIAP2,BCAR1,BCAR3,CDC42,DERL1,DERL2,ITSN1,NEDD9,NPLOC4,NSFL1C,PAK1,PAK2,PARD6A,PARD6B,PXN,SAT1,SYVN1,TNK2,TULP1,UFD1L,VCP,VIMP,WAS,WASL\nresponse to stimulus\tARHGAP1,ARHGDIA,BAIAP2,BCAR1,BCAR3,CDC42,DERL1,DERL2,FAF2,ITSN1,NEDD9,NPLOC4,PAK1,PAK2,PARD6A,PXN,SYVN1,TNK2,TULP1,UFD1L,VCP,VIMP,WAS,WASL\nlocalization\tARHGAP1,BAIAP2,BCAR1,CDC42,DERL1,DERL2,FAF2,ITSN1,KCNE4,NPLOC4,NSFL1C,PAK1,PAK2,PXN,SYVN1,TNK2,TULP1,TULP4,UFD1L,VCP,VIMP,WAS,WASL\ncellular response to stimulus\tARHGAP1,ARHGDIA,BAIAP2,BCAR1,BCAR3,CDC42,DERL1,DERL2,FAF2,ITSN1,NEDD9,NPLOC4,PAK1,PAK2,PARD6A,PXN,SYVN1,TNK2,UFD1L,VCP,VIMP,WAS,WASL\nsignal transduction\tARHGAP1,ARHGDIA,BAIAP2,BCAR1,BCAR3,CDC42,DERL1,DERL2,ITSN1,NEDD9,PAK1,PAK2,PARD6A,PXN,SYVN1,TNK2,VCP,VIMP,WAS,WASL\nestablishment of localization\tARHGAP1,BAIAP2,CDC42,DERL1,DERL2,FAF2,ITSN1,KCNE4,NPLOC4,NSFL1C,PAK1,SYVN1,TNK2,TULP1,UFD1L,VCP,VIMP,WAS,WASL\npositive regulation of biological process\tARHGAP1,ARHGDIA,BAIAP2,BCAR1,BCAR3,CDC42,DERL1,DERL2,ITSN1,NSFL1C,PAK1,PAK2,PARD6A,PXN,TNK2,TULP1,VCP,WAS,WASL\nregulation of response to stimulus\tARHGAP1,ARHGDIA,BAIAP2,BCAR1,BCAR3,CDC42,DERL2,ITSN1,NPLOC4,PAK1,PAK2,PXN,SYVN1,UFD1L,VCP,VIMP,WAS,WASL\ntransport\tARHGAP1,BAIAP2,CDC42,DERL1,DERL2,FAF2,ITSN1,KCNE4,NPLOC4,PAK1,SYVN1,TNK2,TULP1,UFD1L,VCP,VIMP,WAS,WASL\npositive regulation of cellular process\tARHGAP1,ARHGDIA,BAIAP2,BCAR1,BCAR3,CDC42,DERL1,DERL2,ITSN1,NSFL1C,PAK1,PAK2,PXN,TNK2,TULP1,VCP,WAS,WASL\ncellular component organization\tBAIAP2,BCAR1,CDC42,DERL1,FAF2,ITSN1,NEDD9,NPLOC4,NSFL1C,PAK1,PAK2,PARD6A,PARD6B,PXN,TULP1,VCP,WAS,WASL\nresponse to chemical\tBAIAP2,BCAR1,BCAR3,CDC42,DERL1,DERL2,FAF2,NPLOC4,PAK1,PAK2,PARD6A,PXN,SYVN1,UFD1L,VCP,VIMP,WAS\ncellular localization\tARHGAP1,CDC42,DERL1,DERL2,FAF2,ITSN1,NPLOC4,NSFL1C,SYVN1,TULP1,TULP4,UFD1L,VCP,VIMP,WAS,WASL\nresponse to organic substance\tBAIAP2,BCAR1,CDC42,DERL1,DERL2,FAF2,NPLOC4,PAK1,PAK2,PARD6A,PXN,SYVN1,UFD1L,VCP,VIMP,WAS\nnegative regulation of biological process\tARHGAP1,ARHGDIA,CDC42,DERL2,ITSN1,NPLOC4,NSFL1C,PAK1,PAK2,PARD6A,SYVN1,TNK2,UFD1L,VIMP,WAS,WASL\norganonitrogen compound metabolic process\tCDC42,DERL1,DERL2,FAF2,NPLOC4,NSFL1C,PAK1,PAK2,SAT1,SPSB1,SYVN1,TNK2,TULP4,UFD1L,VCP,VIMP\ncellular protein metabolic process\tCDC42,DERL1,DERL2,FAF2,NPLOC4,NSFL1C,PAK1,PAK2,SPSB1,SYVN1,TNK2,TULP4,UFD1L,VCP,VIMP\nestablishment of localization in cell\tARHGAP1,CDC42,DERL1,DERL2,FAF2,ITSN1,NPLOC4,NSFL1C,SYVN1,UFD1L,VCP,VIMP,WAS,WASL\ncellular response to organic substance\tBAIAP2,BCAR1,CDC42,DERL1,DERL2,PAK1,PAK2,PARD6A,PXN,SYVN1,UFD1L,VCP,VIMP,WAS\nregulation of signal transduction\tARHGAP1,ARHGDIA,BAIAP2,BCAR3,CDC42,ITSN1,NPLOC4,PAK1,PAK2,PXN,SYVN1,UFD1L,VCP,VIMP\nresponse to stress\tCDC42,DERL1,DERL2,FAF2,NPLOC4,PAK1,PAK2,PXN,SYVN1,TNK2,UFD1L,VCP,VIMP,WAS\nnegative regulation of cellular process\tARHGAP1,ARHGDIA,CDC42,DERL2,ITSN1,NPLOC4,PAK1,PAK2,PARD6A,SYVN1,UFD1L,VIMP,WAS,WASL\nprotein localization\tARHGAP1,BAIAP2,DERL1,DERL2,FAF2,NPLOC4,SYVN1,TULP1,TULP4,UFD1L,VCP,VIMP,WASL\ncell surface receptor signaling pathway\tARHGDIA,BAIAP2,BCAR1,CDC42,ITSN1,NEDD9,PAK1,PAK2,PARD6A,PXN,TNK2,WAS,WASL\nregulation of cellular component organization\tARHGDIA,BAIAP2,BCAR1,CDC42,DERL2,NSFL1C,PAK1,PXN,TNK2,TULP1,VCP,WAS,WASL\nregulation of localization\tARHGAP1,BCAR1,DERL2,KCNE4,NSFL1C,PAK1,PARD6A,PARD6B,TNK2,TULP1,VIMP,WAS,WASL\nregulation of molecular function\tARHGAP1,ARHGDIA,BCAR3,DERL1,FAF2,ITSN1,NSFL1C,PAK1,PAK2,TNK2,VCP,WAS,WASL\nresponse to organonitrogen compound\tBAIAP2,BCAR1,DERL1,DERL2,FAF2,NPLOC4,PAK1,PXN,SYVN1,UFD1L,VCP,VIMP\nintracellular transport\tARHGAP1,CDC42,DERL1,DERL2,FAF2,NPLOC4,SYVN1,UFD1L,VCP,VIMP,WAS,WASL\ncellular protein modification process\tCDC42,DERL1,DERL2,PAK1,PAK2,SPSB1,SYVN1,TNK2,TULP4,UFD1L,VCP,VIMP\norganelle organization\tBAIAP2,BCAR1,CDC42,FAF2,NEDD9,NPLOC4,NSFL1C,PAK1,PAK2,PARD6A,WAS,WASL\ncellular protein localization\tDERL1,DERL2,FAF2,NPLOC4,SYVN1,TULP1,TULP4,UFD1L,VCP,VIMP,WASL\nvesicle-mediated transport\tARHGAP1,BAIAP2,CDC42,FAF2,ITSN1,PAK1,TNK2,TULP1,VCP,WAS,WASL\npositive regulation of response to stimulus\tARHGAP1,BAIAP2,BCAR1,BCAR3,CDC42,ITSN1,PAK1,PAK2,VCP,WAS,WASL\nregulation of catalytic activity\tARHGAP1,ARHGDIA,FAF2,ITSN1,NSFL1C,PAK1,PAK2,TNK2,VCP,WAS,WASL\ncellular component assembly\tBAIAP2,CDC42,DERL1,NEDD9,NSFL1C,PARD6A,PARD6B,PXN,VCP,WAS,WASL\nenzyme linked receptor protein signaling pathway\tBAIAP2,BCAR1,CDC42,ITSN1,PAK1,PAK2,PARD6A,PXN,TNK2,WASL\nregulation of immune response\tBAIAP2,BCAR1,CDC42,NPLOC4,PAK1,PAK2,UFD1L,VIMP,WAS,WASL\ncytoskeleton organization\tBAIAP2,BCAR1,CDC42,NEDD9,NSFL1C,PAK1,PAK2,PARD6A,WAS,WASL\norganonitrogen compound catabolic process\tDERL1,DERL2,FAF2,NPLOC4,NSFL1C,SAT1,SYVN1,UFD1L,VCP,VIMP\npositive regulation of cellular component organization\tARHGDIA,BAIAP2,CDC42,NSFL1C,PAK1,PXN,TULP1,VCP,WAS,WASL\ncellular response to stress\tDERL1,DERL2,FAF2,NPLOC4,PAK2,PXN,SYVN1,UFD1L,VCP,VIMP\ncellular catabolic process\tDERL1,DERL2,FAF2,NPLOC4,NSFL1C,SAT1,SYVN1,UFD1L,VCP,VIMP\nregulation of intracellular signal transduction\tARHGAP1,ARHGDIA,CDC42,ITSN1,NPLOC4,PAK1,PAK2,SYVN1,UFD1L,VIMP\nmulti-organism process\tBAIAP2,CDC42,DERL1,DERL2,ITSN1,PAK2,PARD6A,VCP,VIMP,WASL\nimmune system process\tBAIAP2,BCAR1,CDC42,FAF2,PAK1,PAK2,TNK2,VCP,WAS,WASL\nproteasome-mediated ubiquitin-dependent protein catabolic process\tDERL1,DERL2,FAF2,NPLOC4,NSFL1C,SYVN1,UFD1L,VCP,VIMP\ntransmembrane receptor protein tyrosine kinase signaling pathway\tBAIAP2,BCAR1,CDC42,ITSN1,PAK1,PAK2,PXN,TNK2,WASL\nimport into cell\tARHGAP1,BAIAP2,CDC42,ITSN1,PAK1,TNK2,TULP1,WAS,WASL\nprotein transport\tARHGAP1,DERL1,DERL2,FAF2,NPLOC4,SYVN1,UFD1L,VCP,VIMP\nregulation of cellular protein metabolic process\tBCAR3,DERL1,DERL2,NSFL1C,PAK1,PAK2,PARD6A,TNK2,VCP\nretrograde protein transport, ER to cytosol\tDERL1,DERL2,FAF2,NPLOC4,SYVN1,UFD1L,VCP,VIMP\nsmall GTPase mediated signal transduction\tARHGAP1,BCAR3,CDC42,ITSN1,PAK1,PAK2,TNK2,WAS\nactin cytoskeleton organization\tBAIAP2,BCAR1,CDC42,NEDD9,PAK1,PAK2,WAS,WASL\nregulation of cytoskeleton organization\tARHGDIA,BAIAP2,CDC42,NSFL1C,PAK1,PXN,WAS,WASL\nendocytosis\tBAIAP2,CDC42,ITSN1,PAK1,TNK2,TULP1,WAS,WASL\nprotein modification by small protein conjugation or removal\tCDC42,DERL1,SPSB1,SYVN1,TULP4,UFD1L,VCP,VIMP\ngeneration of neurons\tARHGDIA,BAIAP2,CDC42,PAK1,PAK2,PARD6B,TULP1,WASL\nregulation of apoptotic process\tARHGDIA,BCAR1,ITSN1,PAK1,PAK2,SYVN1,VCP,VIMP\nregulation of phosphate metabolic process\tBCAR3,ITSN1,NSFL1C,PAK1,PAK2,PARD6A,TNK2,VCP\nregulation of transport\tARHGAP1,DERL2,KCNE4,PAK1,TNK2,TULP1,VIMP,WASL\nregulation of protein modification process\tBCAR3,DERL1,NSFL1C,PAK1,PAK2,PARD6A,TNK2,VCP\nanatomical structure morphogenesis\tBAIAP2,BCAR3,CDC42,PAK1,PARD6B,SAT1,TULP1,WASL\nubiquitin-dependent ERAD pathway\tDERL1,DERL2,FAF2,NPLOC4,SYVN1,VCP,VIMP\nresponse to topologically incorrect protein\tDERL1,DERL2,FAF2,SYVN1,UFD1L,VCP,VIMP\npositive regulation of cytoskeleton organization\tBAIAP2,CDC42,NSFL1C,PAK1,PXN,WAS,WASL\nimmune response-activating cell surface receptor signaling pathway\tBAIAP2,BCAR1,CDC42,PAK1,PAK2,WAS,WASL\nregulation of actin cytoskeleton organization\tARHGDIA,BAIAP2,CDC42,PAK1,PXN,WAS,WASL\npositive regulation of cellular component biogenesis\tBAIAP2,CDC42,PAK1,PXN,VCP,WAS,WASL\nneuron projection development\tBAIAP2,CDC42,PAK1,PAK2,PARD6B,TULP1,WASL\nprotein ubiquitination\tCDC42,DERL1,SPSB1,SYVN1,TULP4,VCP,VIMP\nimmune effector process\tBAIAP2,CDC42,FAF2,PAK1,VCP,WAS,WASL\nregulation of response to stress\tDERL2,NPLOC4,PAK1,PAK2,SYVN1,UFD1L,VIMP\nmovement of cell or subcellular component\tBCAR1,CDC42,PAK2,PXN,TNK2,WAS,WASL\nregulation of phosphorylation\tBCAR3,ITSN1,PAK1,PAK2,PARD6A,TNK2,VCP\npositive regulation of signal transduction\tARHGAP1,BAIAP2,BCAR3,ITSN1,PAK1,PAK2,VCP\nFc receptor signaling pathway\tBAIAP2,CDC42,PAK1,PAK2,WAS,WASL\ncellular response to topologically incorrect protein\tDERL1,DERL2,SYVN1,UFD1L,VCP,VIMP\nresponse to unfolded protein\tDERL1,DERL2,FAF2,SYVN1,VCP,VIMP\npositive regulation of supramolecular fiber organization\tBAIAP2,CDC42,PAK1,PXN,WAS,WASL\nphagocytosis\tBAIAP2,CDC42,PAK1,TULP1,WAS,WASL\nactin filament organization\tBAIAP2,BCAR1,CDC42,NEDD9,WAS,WASL\nregulation of actin filament organization\tBAIAP2,CDC42,PAK1,PXN,WAS,WASL\nregulation of protein complex assembly\tBAIAP2,CDC42,PAK1,VCP,WAS,WASL\nviral process\tCDC42,DERL1,ITSN1,PAK2,PARD6A,VCP\nregulation of plasma membrane bounded cell projection organization\tARHGDIA,BAIAP2,CDC42,PAK1,WAS,WASL\nregulation of growth\tBCAR1,CDC42,DERL2,NEDD9,PAK1,PAK2\npositive regulation of phosphorylation\tBCAR3,ITSN1,PAK1,PAK2,TNK2,VCP\ncellular response to endogenous stimulus\tBAIAP2,BCAR1,PAK1,PARD6A,PXN,VIMP\npositive regulation of protein modification process\tBCAR3,DERL1,PAK1,PAK2,TNK2,VCP\nregulation of hydrolase activity\tARHGAP1,ARHGDIA,NSFL1C,PAK2,TNK2,VCP\nvascular endothelial growth factor receptor signaling pathway\tBAIAP2,BCAR1,CDC42,PAK2,PXN\nFc-gamma receptor signaling pathway involved in phagocytosis\tBAIAP2,CDC42,PAK1,WAS,WASL\ndendrite development\tBAIAP2,CDC42,PAK2,TULP1,WASL\nendoplasmic reticulum unfolded protein response\tDERL1,DERL2,SYVN1,VCP,VIMP\nestablishment or maintenance of cell polarity\tCDC42,NSFL1C,PAK1,PARD6A,PARD6B\n', - }, - ], - }, - tau: { - title: 'Drosophila Tau network', - source: 'PMID 31488613, PMCID PMC6794924', - link: 'https://doi.org/10.1523/JNEUROSCI.0391-19.2019', - files: [ - { - kind: 'network', - name: 'Drosophila Tau', - fileName: 'TAU_network_DEGs_NORMA.txt', - text: "Source\tTarget\nCG6178\tyip2\nshep\tScpX\nnito\tRef1\nbol\tHrb27C\nLar\tAbl\nLar\tCadN\nCG31715\tcpb\nMapmodulin\tAats-ile\nCG5590\tCG17597\nSc2\tOst48\nfrj\tCG10932\nKap-alpha3\temb\nUch\tUsp5\nPrx2540-1\tPrx2540-2\nCG2082\tCG2091\nlig\tCapr\nlig\trin\nclu\tDp1\nclu\teIF3-S10\nclu\trin\nclu\teIF3-S8\nclu\teIF3-S9\nCG9090\tCyt-c-p\nCG9090\tCOX5A\nAce\tCat\nDbp80\temb\nSsadh\tCG33791\nSsadh\tCG32026\nSsadh\tMdh2\nCG4572\tCG10576\nCG4572\tHsc70-3\nPlexA\talpha-Cat\nl(1)G0156\tCG11876\nl(1)G0156\tSsadh\nl(1)G0156\tCG33791\nPlc21C\tGbeta76C\nPlc21C\tPkc53E\nHrb27C\tpoe\nHrb27C\theph\nHrb27C\tPyK\nHrb27C\tbel\nHrb27C\tme31B\nHrb27C\tpAbp\nHrb27C\tTER94\nKhc\tTAU\nCG32026\tCG33791\nbel\tRef1\nbel\tpoe\nbel\temb\nbel\tvig\nbel\tme31B\nDp1\tCG2918\nSgt\tTrap1\nSgt\tTcp-1zeta\nMen-b\tCG11876\nMen-b\tPyK\nMen-b\tMdh2\nCG11899\tCG3011\nMgstl\tCG3529\nMgstl\tOst48\nCG14715\tCG2852\nLpin\tPkc53E\ngammaSnap2\tzetaCOP\ngammaSnap2\tbetaCOP\ngammaSnap2\tepsilonCOP\ngammaSnap2\tbeta'COP\ngammaSnap2\tdeltaCOP\nCG10359\tGp93\nCG10359\tCG1354\nCG10359\tCaBP1\nCG10359\tPdi\nKP78a\tCG32683\nKP78a\tArr2\nCG9257\tpoe\nCG9257\tCG3529\nEct3\tRpn5\nEct3\tCG6891\nEct3\tCat\nEct3\tCalpB\nCG4882\tbonsai\nCalpB\tCG6891\nCalpB\tCat\npar-1\tCG32683\npar-1\tKP78a\npar-1\tArr2\nPrx5\tPrx2540-2\nPrx5\tCat\nPkc53E\tzip\nCG31064\tRab5\nNlp\tmago\nNlp\teEF1delta\nNlp\tsmt3\nCG10186\tbetaCOP\nCG10186\tcpb\nCG10186\tcpa\nCG10186\tbeta'COP\nCG10186\tbai\nCG10186\tepsilonCOP\nCG10186\tDlic\nCG10186\tp115\nCG10186\tzetaCOP\nCG10186\tdeltaCOP\nrin\tCapr\nLpR1\tArr2\nLpR1\tArr1\nLpR1\tUbqn\nLpR1\tCG32683\nLpR1\tlqf\nLpR1\tHrs\nLpR1\tLpR2\nLpR1\tRab5\nCG16935\tCG12262\nCG16935\tyip2\npoe\tbetaCOP\npoe\tCG3529\nCG43367\tbetaCOP\nCG43367\tpoe\nRab39\tRab5\nRab39\tGdi\nemb\tRae1\nemb\talphaCOP\nemb\tCG10576\nAGBE\tEno\nAGBE\tPyK\nLpR2\tUbqn\nLpR2\tCG32683\nLpR2\tArr2\nLpR2\tHrs\nLpR2\tlqf\nLpR2\tRab5\nCG3529\tOst48\nOst48\tCG2918\nHsp60C\tHop\nHsp60C\tHsc70-3\nPrx2540-2\tCat\nEfTuM\tRpS14a\nEfTuM\tHsc70-5\nEfTuM\tRpL10Ab\nEfTuM\tRpS13\nEfTuM\tRpS16\nEfTuM\tRpS23\nEfTuM\tRpS15Aa\nEfTuM\tRpL4\nEfTuM\tCG11876\nEfTuM\tbonsai\nEfTuM\tmRpS10\nEfTuM\tRpL12\nEfTuM\tsta\nEfTuM\tRpL3\nEfTuM\tHsp60\nEfTuM\tRpS18\nEfTuM\tRpS2\nEfTuM\tmRpS9\nEfTuM\tRpS3\nEfTuM\tmRpL12\nEfTuM\tRpL11\nfne\tTango4\nfne\tSrp54\nfne\tCG10777\nfne\tPrp8\nfne\tmago\nfne\tCG16941\nfne\typs\nfne\tCG10077\nfne\tRbp9\nfne\tU2A\nfne\tPkc53E\nfne\tHrb98DE\nfne\tLS2\nfne\tSF2\nfne\tmub\nfne\theph\nKlp10A\tdeltaCOP\nMtl\tzip\nMtl\ttsr\nMtl\tRhoGDI\nHsp60\tCG7033\nRanBPM\tCG6617\nyps\tTango4\nyps\tLS2\nyps\tmago\nyps\tCG10777\nArt4\tCG10777\nArt4\tCG10077\nArt4\tpAbp\nImpL3\tCat\nImpL3\tMen-b\nImpL3\tPfk\nImpL3\tMen\nImpL3\tEno\nImpL3\tTpi\nImpL3\tPyK\nImpL3\tCG11876\nCG10077\tCG10777\nCG10077\tLS2\nCG10077\tTango4\nCG10077\typs\nCG10077\tmago\nLam\tRab5\nLamC\tLam\nUbqn\tHDAC6\nUbqn\tCG32683\nmub\tCG3800\nmub\tmago\nmub\tU2A\nmub\tSrp54\nmub\tTango4\nmub\tPrp8\nmub\tCG10777\nmub\tCG16941\nmub\typs\nmub\tCG10077\nmub\tLS2\nmub\tHrb98DE\nmub\tRbp9\nmub\tSF2\nAGO1\tRbp9\nAGO1\tpAbp\nAGO1\tRae1\nAGO1\tme31B\nglo\tHrb98DE\nSap-r\tCG3529\nSap-r\tMgstl\nSap-r\tpins\nSap-r\tRab5\nSap-r\tOst48\nNdg\tCg25C\nNdg\tLanB2\ntrol\tCp1\ntrol\tLanB2\ntrol\tCg25C\ntrol\tNdg\nHsp70Ab\tPdi\nHsp70Ab\tDnaJ-H\nHsp70Ab\tHop\nHsp70Ab\tHsp27\nbai\tSrp19\nbai\tCG2852\nbai\tgammaSnap2\nbai\tKlp10A\nbai\tKlc\nbai\tDlic\nbai\tcpa\nbai\tp115\nbai\tcpb\nbai\tdeltaCOP\nbai\tbetaCOP\nbai\tepsilonCOP\nbai\tbeta'COP\nbai\tzetaCOP\nNc73EF\tSsadh\nNc73EF\tCG32026\nNc73EF\tl(1)G0156\nNc73EF\tCG33791\nNc73EF\tCG11876\nSrp54\typs\nSrp54\tCG10777\nSrp54\tmago\nSrp54\tLS2\nSrp54\tCG10077\nSrp54\tTango4\nUgt\tCG2918\nRbp9\tCG10777\nRbp9\tTango4\nRbp9\tSrp54\nRbp9\tPrp8\nRbp9\tCG10077\nRbp9\tCG16941\nRbp9\tU2A\nRbp9\tPkc53E\nRbp9\tLS2\nRbp9\tHrb98DE\nRbp9\typs\nRbp9\tmago\nAct79B\tcpb\nAct79B\tflr\nAct79B\tzip\nRbp2\tpAbp\nRbp2\tRpL10Ab\nRbp2\tRpS4\nRbp2\tRpL18A\nRbp2\tRpS3\nRbp2\tRpS11\nRbp2\teIF3-S9\nRbp2\tRpL11\nRbp2\teIF3-S10\nRbp2\tRpL13\nRbp2\teIF3-S8\nRbp2\tRpS10b\nRbp2\tRpS10a\nRbp2\tRpS27\nRbp2\tRpL3\nRbp2\tRpS12\nRbp2\tRpS7\nRbp2\tRpL12\nRbp2\tTango7\nRbp2\tRpS23\nRbp2\tRpS13\nRbp2\tsta\nRbp2\tRpS18\nRbp2\tRpS16\nRbp2\tRpL4\nRbp2\tRpS6\nRbp2\tTrip1\nRbp2\tRpS2\nRbp2\teIF-3p66\nRbp2\tCG5642\nRbp2\tCG9769\nIswi\tHis1\nIswi\tBap55\nIswi\tsmt3\nIswi\tmor\nVps60\tHrs\neEF1delta\teIF3-S10\neEF1delta\tRpS10b\neEF1delta\tRpS13\neEF1delta\tRpS6\neEF1delta\tRpS16\neEF1delta\tRpL12\neEF1delta\tsta\neEF1delta\tRpS2\neEF1delta\tCG5642\neEF1delta\tRpL13\neEF1delta\tTrip1\nCG10576\tRpS6\nCG10576\tRpS4\nCG10576\tCapr\nCG10576\tsta\nCG10576\tRpS16\nCG10576\tTcp-1zeta\nCG10576\twuho\nCG10576\tRpL12\nCG10576\tCG7033\nAbl\tDscam1\nAbl\tsyd\nAbl\talpha-Cat\nAbl\tarm\nRae1\tmago\nMtor\tmago\nMtor\tAGO1\nMtor\tHsc70-3\nMtor\tHsc70-5\nMtor\tsmt3\nMtor\tRae1\nRef1\tLS2\nRef1\tmago\nTrap1\tHsp70Ab\nTrap1\tHop\nTrap1\tHsp60C\nTrap1\tHsp60\nTrap1\tCG2918\nTrap1\tHsc70-3\nTrap1\tCG1416\nCG17597\tCat\nCG17597\tScpX\nCG17597\tMfe2\nlqf\tCG32683\nlqf\tUbqn\nlqf\tArr2\nlqf\tRab5\nlqf\tHrs\nTim17b\tTim9a\nCG3902\tCG10932\nCat\tCG6891\np115\tdeltaCOP\nSec24AB\tdeltaCOP\nSec24AB\tbetaCOP\nSec24AB\tepsilonCOP\nSec24AB\tzetaCOP\nSec24AB\talphaCOP\nSec24AB\tbeta'COP\nSec24AB\tp115\nninaC\tAct79B\nninaC\tzip\nninaC\tArr2\nmago\tsta\nmago\tRpS6\nmago\tCG10777\nCG11876\tMen\nCG11876\tMdh2\nCG11876\tPyK\nCG11876\tND-PDSW\nCG11876\tAcCoAS\nCG11876\tEno\nCG11876\tCG33791\nPdk\tade3\nPdk\tCG11876\nB52\tRpS3\nB52\tHrb27C\nB52\tglo\nB52\tCG10777\nB52\tfne\nB52\tCG10077\nB52\typs\nB52\tRbp9\nB52\tCG16941\nB52\tTango4\nB52\tU2A\nB52\tmago\nB52\tSrp54\nB52\tmub\nB52\theph\nB52\tPrp8\nB52\tLS2\nB52\tHrb98DE\nB52\tU2af50\nB52\tSF2\nVha100-1\tsun\nVha100-1\tVha100-2\nVha100-1\tVha68-2\nrobl\tDlic\nHsc70-5\tCG7033\nHsc70-5\tT-cp1\nHsc70-5\tTpi\nHsc70-5\tDnaJ-H\nHsc70-5\tTcp-1eta\nHsc70-5\tHop\nHsc70-5\tRae1\nHsc70-5\tTrap1\nHsc70-5\tHsp60C\nHsc70-5\tHsc70-3\nHsc70-5\tHsp60\nHsc70-5\tGp93\ntsr\tsqh\ntsr\tcpa\ntsr\tRpS6\nflr\tcpa\nflr\ttsr\nAcCoAS\tCG12262\nAcCoAS\tCG10932\nACC\tEno\nACC\tCG10932\nACC\tAcCoAS\nLS2\tmago\nLS2\tCG10777\nFKBP59\tninaC\nFKBP59\tDlic\nFKBP59\tcpb\nFKBP59\tcpa\nFKBP59\tHop\nU2af50\tRef1\nU2af50\tLS2\nU2af50\typs\nU2af50\tCG10777\nU2af50\tCG10077\nU2af50\tRbp9\nU2af50\tfne\nU2af50\tSrp54\nU2af50\tmago\nU2af50\tmub\nU2af50\tTango4\nU2af50\theph\nU2af50\tCG16941\nU2af50\tHrb98DE\nU2af50\tPrp8\nU2af50\tSF2\nU2af50\tU2A\nFmr1\tdock\nFmr1\tPyK\nFmr1\tpoe\nFmr1\tbel\nFmr1\tpAbp\nFmr1\teIF4G\nFmr1\tDscam1\nFmr1\tRanBPM\nFmr1\tHrb98DE\nFmr1\tHrb27C\nFmr1\tCapr\nFmr1\tTER94\nFmr1\tRbp9\nFmr1\tme31B\nFmr1\tAGO1\nFmr1\tvig\nScpX\tCat\nScpX\tMfe2\nTop2\tRpS13\nTop2\tPkc53E\nTop2\tUba2\nTop2\tIswi\nTop2\tsmt3\nCG8209\tUfd1-like\nheph\tTango4\nheph\tSrp54\nheph\tCG16941\nheph\tCG10077\nheph\tCG10777\nheph\tU2A\nheph\tmago\nheph\typs\nheph\tPrp8\nheph\tmub\nheph\tLS2\nheph\tpAbp\nheph\tHrb98DE\nheph\tRbp9\nheph\tSF2\nHrs\tCG4572\nHrs\tCG32683\nHrs\tArr2\nHrs\tUbqn\nHrs\tRab5\nHrb98DE\tCG10777\nHrb98DE\tmago\nHrb98DE\tSrp54\nHrb98DE\tCG16941\nHrb98DE\tCG10077\nHrb98DE\typs\nHrb98DE\tLS2\nHrb98DE\tTango4\nbic\tRpS3\nNacalpha\tRpS13\nNacalpha\tRpS2\nNacalpha\tsta\nNacalpha\tRpS6\nNacalpha\tRpS16\nNacalpha\tRpS27\nNacalpha\tRpS4\nNacalpha\tRpS23\nNacalpha\tRpS18\nNacalpha\tRpL12\nNacalpha\tRpL18A\nNacalpha\tRpL11\nNacalpha\tRpS10b\nNacalpha\tRpS17\nNacalpha\tRpL13\nNacalpha\tRpS3\nNacalpha\tRpL4\nNacalpha\tbic\nAats-val\teEF1delta\nAats-val\tEf1beta\nAats-val\tAats-asp\nAats-val\tAats-ile\nAats-val\tCG33123\nAats-val\tAats-arg\nBicD\tLam\nBicD\tbic\nBicD\tKhc\nBicD\tcpb\nBicD\tcpa\nBicD\tDlic\nDnaJ-H\tCG2918\nDnaJ-H\tHsc70-3\nDnaJ-H\tHop\nmRpS34\tCG4882\nmRpS34\tbonsai\nCadN\talpha-Cat\nCadN\tarm\nvig\tRpS15Aa\nvig\tRpS13\nvig\tRpS16\nvig\tRpS17\nvig\tRpL12\nTudor-SN\tbel\nTudor-SN\tAGO1\nTudor-SN\tFmr1\nTudor-SN\tvig\nMdh2\tAldh\nMdh2\tND-51\nMdh2\tCOX4\nMdh2\tCyt-c-p\nMdh2\tCOX5A\nMdh2\tMen\nMdh2\tEno\nCyt-c-p\tCat\nCyt-c-p\tporin\nCyt-c-p\tND-PDSW\nCyt-c-p\tCOX6B\nAldh\tCat\nAldh\tEno\nAldh\tCG12262\nAldh\tAcCoAS\nCG15093\tCG12262\nCG15093\tAcCoAS\nCG15093\tCG3902\nCG15093\tAldh\nCG4679\tmRpS34\nCG4679\tbsf\nCG4679\tCG4882\nCG4679\tmRpL12\nCG4679\tmRpL44\nCG4679\tbonsai\nCG4679\tmRpS10\nCG4679\tmRpS23\nCG4679\tmRpS22\nCG4679\tmRpS9\nCG4679\tmRpS18B\nSF2\tCG10777\nSF2\tCG10077\nSF2\tU2A\nSF2\tTango4\nSF2\typs\nSF2\tPrp8\nSF2\tRbp9\nSF2\tCG16941\nSF2\tSrp54\nSF2\tRef1\nSF2\tLS2\nSF2\tmago\nSF2\tHrb98DE\np47\tCG8209\np47\tUfd1-like\np47\tRpt2\nRad23\tme31B\nRad23\tUch-L5\nRad23\tRpt1\nRad23\tHDAC6\nRad23\tUsp5\nRad23\tUba2\nRad23\tUfd1-like\nRad23\tSgt\nRad23\tRpt5\nRad23\tBap55\nRad23\tpont\nRad23\tCG8209\nRad23\tIswi\nRad23\tRpn13\nRad23\tUbqn\nRad23\tsmt3\nRad23\tRpt2\nRad23\tTER94\nme31B\tpoe\nme31B\tCG2091\nme31B\typs\nND-51L1\tND-51\nND-51L1\tNP15.6\nND-51L1\tND-PDSW\nND-51L1\tND-B16.6\nsyd\talpha-Cat\nsyd\tDlic\nsyd\tKlc\nArr2\tUbqn\nArr2\tCG32683\nArr1\tninaC\nArr1\tchp\nArr1\tKP78a\nArr1\tLpR2\nArr1\tUbqn\nArr1\tCG32683\nArr1\tpar-1\nArr1\tHrs\nArr1\tlqf\nArr1\tRab5\nArr1\tArr2\nND-51\tND-B16.6\nND-51\tND-PDSW\nCG16941\typs\nCG16941\tmago\nCG16941\tCG10777\nCG16941\tCG10077\nCG16941\tSrp54\nCG16941\tLS2\nCG16941\tTango4\nCnx99A\tOst48\nCnx99A\tHsp70Ab\nCnx99A\tCG2918\nCnx99A\tUgt\nCnx99A\tGp93\nCnx99A\tPdi\nCnx99A\tHsc70-3\nCnx99A\tERp60\nAats-his\tAats-asp\nAats-his\tCct5\nAats-his\tAats-arg\nAats-his\tAats-val\nAats-his\tCG33123\nAats-his\tAats-ile\nmRpS35\tRpS2\nmRpS35\tCG4882\nmRpS35\tmRpL12\nmRpS35\tmRpS34\nmRpS35\tmRpL44\nmRpS35\tCG4679\nmRpS35\tmRpS23\nmRpS35\tmRpS18B\nmRpS35\tmRpS10\nmRpS35\tmRpS9\nmRpS35\tmRpS22\nmRpS35\tbonsai\nmRpS35\tmRpS5\nVha68-2\tsun\nVha68-2\tEno\nVha100-2\tsun\nVha100-2\tVha68-2\nRac1\tsqh\nRac1\tFmr1\nRac1\ttsr\nRac1\tDscam2\nRac1\tGdi\nRac1\tAbl\nRac1\tdock\nRac1\tzip\nRac1\tRhoGDI\nmRpS7\tade3\nmRpS7\tCG9769\nmRpS7\tCG4882\nmRpS7\teIF3-S8\nmRpS7\tSrp19\nmRpS7\tEfTuM\nmRpS7\teIF3-S10\nmRpS7\teIF-2gamma\nmRpS7\tSrp54k\nmRpS7\teRF1\nmRpS7\tTango7\nmRpS7\tRpLP2\nmRpS7\teIF3-S9\nmRpS7\tRpL4\nmRpS7\tRpS10a\nmRpS7\tRpS12\nmRpS7\tRpS10b\nmRpS7\tCG7048\nmRpS7\tRpS15Ab\nmRpS7\tRpS15Aa\nmRpS7\tRpL10Ab\nmRpS7\tRpS14a\nmRpS7\tRpL18A\nmRpS7\tRack1\nmRpS7\tRpS4\nmRpS7\tRpS17\nmRpS7\tRpL13\nmRpS7\tRpS7\nmRpS7\tRpS6\nmRpS7\tRpS8\nmRpS7\tRpS16\nmRpS7\tsta\nmRpS7\tRpS13\nmRpS7\tRpL3\nmRpS7\tRpS23\nmRpS7\tRpS27\nmRpS7\tRpL12\nmRpS7\tRpS18\nmRpS7\tRpS3A\nmRpS7\tRpS2\nmRpS7\tRpS3\nmRpS7\tRpS11\nmRpS7\tRpL11\nmRpS7\tRpL30\nmRpS7\tmRpL44\nmRpS7\tmRpS22\nmRpS7\tmRpS34\nmRpS7\tCG4679\nmRpS7\tmRpS23\nmRpS7\tbonsai\nmRpS7\tmRpS10\nmRpS7\tmRpS35\nmRpS7\tmRpL12\nmRpS7\tmRpS18B\nmRpS7\tmRpS9\nmRpS7\tmRpS5\nPrp8\typs\nPrp8\tSrp54\nPrp8\tCG10777\nPrp8\tCG10077\nPrp8\tLS2\nPrp8\tmago\nPrp8\tHrb98DE\nPrp8\tCG16941\nPrp8\tTango4\npont\tTcp-1zeta\npont\tTcp-1eta\npont\tRpt6\npont\tUch-L5\nmRpL44\tmRpS34\nmRpL44\tmRpL12\nmRpL44\tbonsai\nmRpS22\tCG4882\nmRpS22\tmRpL12\nmRpS22\tmRpS10\nmRpS22\tmRpL44\nmRpS22\tmRpS34\nmRpS22\tmRpS23\nmRpS22\tbonsai\nmRpS22\tmRpS18B\nmRpS22\tmRpS9\nCp1\tEct3\nCp1\tPyK\nCp1\tRpn5\nCp1\tCG6891\nCp1\tCalpB\nCp1\tRpn6\nCp1\tCat\nCp1\tRpt5\ncathD\tCG4572\ncathD\tCG6891\ncathD\tPyK\ncathD\tCG8258\ncathD\tEct3\ncathD\tPfk\ncathD\tRpn5\ncathD\tCalpB\ncathD\tRpt5\ncathD\tRpn6\ncathD\tCat\ncathD\tSap-r\ncathD\tCp1\nTango4\tCG10777\nTango4\tLS2\nTango4\tmago\nU2A\typs\nU2A\tCG10077\nU2A\tCG10777\nU2A\tSrp54\nU2A\tHrb98DE\nU2A\tmago\nU2A\tLS2\nU2A\tCG16941\nU2A\tPrp8\nU2A\tTango4\nUba2\tUsp5\nUba2\tUbqn\nsmt3\ttsr\nsmt3\tmago\nsmt3\tUfd1-like\nsmt3\tCG10777\nsmt3\tCG10077\nsmt3\tRae1\nsmt3\tUba2\nzip\tsqh\nND-15\tCG11752\nND-15\tND-51L1\nND-15\tCOX5A\nND-15\tND-51\nND-15\tNP15.6\nND-15\tND-B16.6\nND-15\tND-PDSW\npAbp\trin\npAbp\tRpL3\npAbp\tRpL4\npAbp\temb\npAbp\tDp1\npAbp\tRpS6\npAbp\ttyf\npAbp\tbel\npAbp\typs\npAbp\tCG11505\npAbp\tme31B\neIF4G\tDp1\neIF4G\tkra\neIF4G\tbel\neIF4G\tPlexA\neIF4G\tme31B\neIF4G\tRpL18A\neIF4G\tRpL12\neIF4G\tRpS12\neIF4G\tHsp67Bc\neIF4G\tRpS4\neIF4G\tRpL11\neIF4G\tRpS23\neIF4G\tRpS7\neIF4G\tRpS27\neIF4G\tRpLP2\neIF4G\tRpS10b\neIF4G\tRpS10a\neIF4G\tsta\neIF4G\tRpS16\neIF4G\tRpL4\neIF4G\tRpL13\neIF4G\tRpS18\neIF4G\tRpS13\neIF4G\tRpL3\neIF4G\tRpL10Ab\neIF4G\tRpS11\neIF4G\tRpS8\neIF4G\tRpS2\neIF4G\tHsp27\neIF4G\teIF-3p66\neIF4G\tmago\neIF4G\tTango7\neIF4G\tRpS3\neIF4G\tCG5642\neIF4G\tCG9769\neIF4G\tTrip1\neIF4G\tRbp2\neIF4G\tRpS6\neIF4G\talpha-Cat\neIF4G\teIF3-S10\neIF4G\teIF3-S8\neIF4G\teIF3-S9\neIF4G\tpAbp\nPfk\tCG11876\nPfk\tCG6891\nPfk\tEct3\nPfk\tRpt5\nPfk\tCp1\nPfk\tRpn6\nPfk\tCalpB\nPfk\tRpn5\nPfk\tCat\nPfk\tEno\nPfk\tTpi\nPfk\tPyK\nbonsai\tRpS14a\nbonsai\tRpS16\nbonsai\tsta\nbonsai\tRpS6\nCG12262\tCG10932\nyip2\tUch\nyip2\tAcCoAS\nyip2\tCG10932\nyip2\tCG3902\nyip2\tCG12262\nRab5\tMgstl\nRab5\tCG32683\nRab5\tOst48\nRab5\tCG3529\nRab5\tArr2\nGdi\tCat\nGdi\tCG6891\nGdi\tPfk\nGdi\tRpt1\nGdi\tRpt5\nGdi\tRpn5\nGdi\tCG8258\nGdi\tRpn6\nGdi\tRpn3\nGdi\tPyK\nGdi\tTER94\nGdi\tRhoGDI\nGdi\tRab5\nmRpS10\tSrp54k\nmRpS10\tCG4882\nmRpS10\tRpL10Ab\nmRpS10\tRpS14a\nmRpS10\tRpS16\nmRpS10\tRpS10b\nmRpS10\tRpS13\nmRpS10\tRpS2\nmRpS10\tRpS15Aa\nmRpS10\tRpL3\nmRpS10\tRpL12\nmRpS10\tRpL13\nmRpS10\tRpS4\nmRpS10\tRpS17\nmRpS10\tRpS6\nmRpS10\tsta\nmRpS10\tmRpS23\nmRpS10\tmRpS18B\nmRpS10\tmRpS34\nmRpS10\tmRpL12\nmRpS10\tmRpL44\nmRpS10\tbonsai\nmRpS10\tmRpS9\nSrp54k\tbonsai\nSrp54k\tRpS14a\nSrp54k\tRpS15Aa\nSrp54k\tRpS17\nSrp54k\tRpL10Ab\nSrp54k\tRpS10b\nSrp54k\tRpL12\nSrp54k\tRpS4\nSrp54k\tRpS6\nSrp54k\tRpS16\nSrp54k\tRpS12\nSrp54k\tsta\nSrp54k\tSrp19\nmRpL12\tRpS14a\nmRpL12\tRpL10Ab\nmRpL12\tRpS16\nmRpL12\tsta\nmRpL12\tmRpS34\nmRpL12\tRpS15Aa\nmRpL12\tRpL12\nmRpL12\tbonsai\nTctp\tRpS10b\nTctp\teEF1delta\nTctp\tRpL10Ab\nTctp\tRpS14a\nTctp\tRpS15Aa\nTctp\tRpS4\nTctp\tRpS17\nTctp\tsta\nTctp\tRpS6\nTctp\tRpS16\nTctp\tRpL12\nTctp\tRpS13\nTctp\tRpS12\nTctp\tRpS2\nTctp\tRpL13\neIF-2gamma\tTcp-1zeta\neIF-2gamma\tTcp-1eta\neIF-2gamma\tCG10576\neIF-2gamma\tCctgamma\neIF-2gamma\tCG7033\neIF-2gamma\tpAbp\neIF-2gamma\tCct5\neIF-2gamma\tRpS14a\neIF-2gamma\tCG8258\neIF-2gamma\tCG33123\neIF-2gamma\tCG1354\neIF-2gamma\tRpS15Ab\neIF-2gamma\tRpS15Aa\neIF-2gamma\tT-cp1\neIF-2gamma\tRpS17\neIF-2gamma\tRpL10Ab\neIF-2gamma\tRpLP2\neIF-2gamma\tRpL18A\neIF-2gamma\tRbp2\neIF-2gamma\tCG5642\neIF-2gamma\tRpL30\neIF-2gamma\teIF-3p66\neIF-2gamma\teIF4G\neIF-2gamma\tRpS3A\neIF-2gamma\tCG9769\neIF-2gamma\tRpL12\neIF-2gamma\tRpL11\neIF-2gamma\tRpS8\neIF-2gamma\tRpS10a\neIF-2gamma\tRpS10b\neIF-2gamma\tRpL13\neIF-2gamma\tRpS27\neIF-2gamma\tRpS23\neIF-2gamma\tRpS18\neIF-2gamma\tRpS11\neIF-2gamma\tRpS7\neIF-2gamma\tRpL3\neIF-2gamma\tRpS12\neIF-2gamma\tRpL4\neIF-2gamma\tRpS4\neIF-2gamma\tRpS13\neIF-2gamma\tTrip1\neIF-2gamma\tRpS2\neIF-2gamma\teIF3-S10\neIF-2gamma\tRpS16\neIF-2gamma\tRpS6\neIF-2gamma\tTango7\neIF-2gamma\tsta\neIF-2gamma\tRpS3\neIF-2gamma\teIF3-S8\neIF-2gamma\teIF3-S9\nUch-L5\tUsp5\nUch-L5\tRpt4R\nUch-L5\tRpn12\nRpt4R\tRpn12\nProsalpha1\tRpt4R\nProsalpha1\tRpn2\nProsalpha1\tRpn12\nProsalpha1\tRpn6\nProsalpha1\tRpt6R\nProsalpha1\tRpn5\nProsalpha1\tRpt6\nProsalpha1\tRpt5\nProsalpha1\tProsalpha6\nProsalpha1\tRpt2\nProsalpha1\tProsbeta7\nmRpS23\tCG4882\nmRpS23\tmRpL44\nmRpS23\tmRpL12\nmRpS23\tbonsai\nmRpS23\tmRpS34\nmRpS18B\tCG4882\nmRpS18B\tmRpL12\nmRpS18B\tbonsai\nmRpS18B\tmRpS34\nmRpS18B\tmRpL44\nmRpS18B\tmRpS23\nmor\tpont\nBap55\tUch-L5\nBap55\tpont\nBap55\tmor\nade5\tCG3011\nCg25C\tLanA\nvkg\tGlt\nvkg\tLanA\nvkg\tNdg\nvkg\ttrol\nvkg\tCg25C\nUfd1-like\tUbqn\nUfd1-like\tUsp5\nTER94\tpoe\nTER94\tbel\nTER94\tCnx99A\nTER94\tERp60\nTER94\tPdi\nTER94\tsmt3\nTER94\tHop\nTER94\tHsc70-3\nTER94\tCalpB\nTER94\tPfk\nTER94\tCG6891\nTER94\tEct3\nTER94\tPyK\nTER94\tRpn2\nTER94\tCat\nTER94\tCp1\nTER94\tme31B\nTER94\tCG8258\nTER94\tcathD\nTER94\tUbqn\nTER94\tRpn5\nTER94\tRpn6\nTER94\tRpt1\nTER94\tRpt5\nTER94\tCG8209\nTER94\tRpt2\nTER94\tp47\nTER94\tUfd1-like\nade3\tRpS15Aa\nade3\tRpL12\nade3\tRpS14a\nade3\tRpL10Ab\nade3\tsu(r)\nade3\tRpS6\nade3\tRpS4\nade3\tade5\nade3\tCG3011\nmRpS9\tCG4882\nmRpS9\tade3\nmRpS9\tRpS14a\nmRpS9\tRpL10Ab\nmRpS9\tRpS16\nmRpS9\tsta\nmRpS9\tRpS13\nmRpS9\tRpS15Aa\nmRpS9\tRpL12\nmRpS9\tRpS2\nmRpS9\tmRpS34\nmRpS9\tmRpL44\nmRpS9\tmRpS18B\nmRpS9\tmRpS23\nmRpS9\tbonsai\nmRpS9\tmRpL12\nmRpS5\tCG11876\nmRpS5\tRpS16\nmRpS5\tRpS14a\nmRpS5\tRpL10Ab\nmRpS5\tRpLP2\nmRpS5\tCG4882\nmRpS5\tSrp54k\nmRpS5\tRpS10b\nmRpS5\tRpL4\nmRpS5\tRpS10a\nmRpS5\tRpS8\nmRpS5\tRpS13\nmRpS5\tsta\nmRpS5\tRpL3\nmRpS5\tRpL12\nmRpS5\tRpS15Aa\nmRpS5\tRpS23\nmRpS5\tRpS15Ab\nmRpS5\tRpS27\nmRpS5\tRpS7\nmRpS5\tEfTuM\nmRpS5\tRpL18A\nmRpS5\tRpL13\nmRpS5\tRpS4\nmRpS5\tRpS17\nmRpS5\tRpS6\nmRpS5\tRpS18\nmRpS5\tRpS11\nmRpS5\tRpL11\nmRpS5\tRpS3\nmRpS5\tmRpS34\nmRpS5\tmRpS18B\nmRpS5\tmRpS23\nmRpS5\tmRpS22\nmRpS5\tCG4679\nmRpS5\tmRpL44\nmRpS5\tmRpL12\nmRpS5\tmRpS10\nmRpS5\tbonsai\nmRpS5\tmRpS9\nNot1\tIswi\nNot1\teIF4G\nNot1\tpAbp\nNot1\tPrp8\nNot1\tme31B\nNot3\tfrj\nNot3\tme31B\nNot3\tNot1\nHsc70-3\tCG2852\nHsc70-3\tHsp60\nHsc70-3\tOst48\nHsc70-3\tRae1\nHsc70-3\tCG2918\nPyK\tbel\nPyK\tpoe\nPyK\tme31B\nPyK\tMen\nPyK\tAldh\nPyK\tEct3\nPyK\tCG6891\nPyK\tCalpB\nPyK\tND-51\nPyK\tRpn5\nPyK\tVha68-2\nPyK\tCat\nPyK\tMdh2\nPyK\tEno\nLanA\tLanB2\nalphaCOP\tdeltaCOP\nSrp19\tRpS14a\nSrp19\tRpS15Aa\nSrp19\tRpS17\nSrp19\tRpL10Ab\nSrp19\tRpS10b\nSrp19\tRpS6\nSrp19\tRpS4\nSrp19\tsta\nSrp19\tRpS12\nSrp19\tRpL12\nSrp19\tRpS16\nSrp72\tRpS12\nSrp72\tRpS10b\nSrp72\tRpS6\nSrp72\tRpS13\nSrp72\tRpL10Ab\nSrp72\tRpL13\nSrp72\tsta\nSrp72\tRpS4\nSrp72\tRpS2\nSrp72\tRpL3\nSrp72\tRpS16\nSrp72\tRpL12\nSrp72\tSrp54k\nSrp72\tSrp19\nHsp83\tTcp-1zeta\nHsp83\tRack1\nHsp83\tzip\nHsp83\tERp60\nHsp83\tpont\nHsp83\tPdi\nHsp83\tTpi\nHsp83\tHDAC6\nHsp83\tbai\nHsp83\tCctgamma\nHsp83\tCnx99A\nHsp83\tCG2918\nHsp83\tCct5\nHsp83\tCG7033\nHsp83\tSgt\nHsp83\tHsp27\nHsp83\tT-cp1\nHsp83\tCalpB\nHsp83\tEct3\nHsp83\tCG6891\nHsp83\tDlic\nHsp83\tcpa\nHsp83\tCp1\nHsp83\tDhc64C\nHsp83\tHsp60C\nHsp83\tcpb\nHsp83\tcathD\nHsp83\tPfk\nHsp83\tGdi\nHsp83\tRac1\nHsp83\tPyK\nHsp83\tRpn6\nHsp83\tHsp60\nHsp83\tRpn5\nHsp83\tRpt1\nHsp83\tRpn3\nHsp83\tRpt5\nHsp83\tHsp70Ab\nHsp83\tCat\nHsp83\tCG8258\nHsp83\tHsc70-5\nHsp83\tFKBP59\nHsp83\tTER94\nHsp83\tDnaJ-H\nHsp83\tHsc70-3\nHsp83\tCG1416\nHsp83\tHop\nCG11089\tade5\nCG11089\tade3\nCG11089\tCG3011\nERp60\tPdi\nERp60\tOst48\nERp60\tCG2852\nERp60\tCG2918\nERp60\tCaBP1\nERp60\tHsc70-3\nERp60\tGp93\nzetaCOP\tKlp10A\nzetaCOP\tDlic\nzetaCOP\tp115\nzetaCOP\tcpa\nzetaCOP\talphaCOP\nzetaCOP\tbetaCOP\nzetaCOP\tdeltaCOP\nCOX6B\tND-B16.6\nCG7048\tcpa\nCG7048\tSrp19\nCG7048\tNlp\nCG7048\tmRpS23\nCG7048\tCG8498\nCG7048\trobl\nCG7048\tTim9a\nCG7048\teEF1delta\nCG7770\tRpS18\nCG7770\tpont\nCG7770\tCG7048\narm\tHsc70-3\narm\tProsalpha6\narm\tUch-L5\narm\tRpn5\narm\tProsbeta7\narm\tRpn12\narm\tRpt6R\narm\tRpt6\narm\tsyd\narm\tRpn2\narm\tRpn6\narm\tRpt1\narm\tRpt2\narm\tRpt5\narm\temb\narm\tRpt4R\narm\tpont\narm\talpha-Cat\neIF-3p66\tTcp-1eta\neIF-3p66\tCct5\neIF-3p66\tCctgamma\neIF-3p66\tRpS12\neIF-3p66\tRpS16\neIF-3p66\tRpS11\neIF-3p66\tRpS27\neIF-3p66\tRpS23\neIF-3p66\tRpS10a\neIF-3p66\tRpS10b\neIF-3p66\tRpS13\neIF-3p66\tRpL10Ab\neIF-3p66\tRpL13\neIF-3p66\tRpS7\neIF-3p66\tRpL12\neIF-3p66\tsta\neIF-3p66\tRpS4\neIF-3p66\tRpL11\neIF-3p66\tRpS18\neIF-3p66\tRpS2\neIF-3p66\tRpL3\neIF-3p66\tRpL18A\neIF-3p66\tRpS3\neIF-3p66\tRpL4\neIF-3p66\tRpS6\neIF-3p66\tCG9769\neIF-3p66\teIF3-S10\neIF-3p66\tTango7\neIF-3p66\teIF3-S8\neIF-3p66\teIF3-S9\neIF-3p66\tTrip1\neIF-3p66\tCG5642\nCG11752\tND-B16.6\nCOX4\tCG11752\nCOX4\tporin\nCOX4\tND-B16.6\nCOX4\tND-PDSW\nCOX4\tCyt-c-p\nCOX4\tCOX6B\nCOX5A\tsun\nCOX5A\tND-51\nCOX5A\tCG7603\nCOX5A\tCG11752\nCOX5A\tND-B16.6\nCOX5A\tCyt-c-p\nCOX5A\tND-PDSW\nCOX5A\tCOX6B\nCOX5A\tCOX4\nEno\tHsc70-3\nEno\tsta\nTpi\tCat\nTpi\tCG11899\nTpi\tRpS13\nTpi\tCG11876\nTpi\tade3\nTpi\tCG3011\nTpi\tHsc70-3\nTpi\tMdh2\nTpi\tPyK\nTpi\tEno\nCctgamma\tTrip1\nCctgamma\tCG10576\nCctgamma\tCG3800\nCctgamma\tHop\nCctgamma\tTcp-1zeta\nCctgamma\tTcp-1eta\nCctgamma\tCG7033\nRpt1\tUch\nRpt1\tRpS15Aa\nRpt1\tRpS15Ab\nRpt1\tRpS6\nRpt1\tUbqn\nRpt1\tRpL3\nRpt1\tRpS11\nRpt1\tRpS18\nRpt1\tUfd1-like\nRpt1\tCct5\nRpt1\tCalpB\nRpt1\tEct3\nRpt1\tCG6891\nRpt1\tPyK\nRpt1\tCp1\nRpt1\tCat\nRpt1\tPfk\nRpt1\tCG8258\nRpt1\tcathD\nRpt1\tProsalpha1\nRpt1\tUch-L5\nRpt1\tRpt6R\nRpt1\tRpt4R\nRpt1\tProsalpha6\nRpt1\tRpn12\nRpt1\tRpt5\nRpt1\tRpn5\nRpt1\tProsbeta7\nRpt1\tRpn2\nRpt1\tRpt6\nRpt1\tRpt2\nRpt1\tRpn6\nDlic\tp115\nDlic\tdeltaCOP\nDlic\tcpa\nDhc64C\tCLIP-190\nDhc64C\tbetaTub56D\nDhc64C\tKlc\nDhc64C\tpoe\nDhc64C\tbai\nDhc64C\tFKBP59\nDhc64C\tbetaCOP\nDhc64C\tdeltaCOP\nDhc64C\tepsilonCOP\nDhc64C\tbeta'COP\nDhc64C\tCG10186\nDhc64C\tzetaCOP\nDhc64C\tp115\nDhc64C\tcpa\nDhc64C\tcpb\nDhc64C\trobl\nDhc64C\tKhc\nDhc64C\tBicD\nDhc64C\tDlic\nEf1beta\tFeCH\nEf1beta\tCG7048\nEf1beta\tAats-asp\nEf1beta\tRpS15Aa\nEf1beta\tRpS10a\nEf1beta\tRpS15Ab\nEf1beta\tCG5642\nEf1beta\tRpL3\nEf1beta\tRpS3A\nEf1beta\tRpS12\nEf1beta\tRpS13\nEf1beta\tRpS10b\nEf1beta\tRpS16\nEf1beta\tRpS2\nEf1beta\tRpS6\nEf1beta\tRpL12\nEf1beta\tRpL30\nEf1beta\tRpS23\nEf1beta\tRpS11\nEf1beta\teEF1delta\nEf1beta\tRpL13\nEf1beta\tsta\nEf1beta\tRpS7\nEf1beta\tTctp\nEf1beta\tTrip1\nEf1beta\tRpS8\nEf1beta\tRpS18\nEf1beta\tRack1\nEf1beta\tRpS17\nEf1beta\tRpL10Ab\nEf1beta\tRpL18A\nEf1beta\tRpS3\nEf1beta\tRpS4\nEf1beta\tRpL11\nEf1beta\tRpLP2\nEf1beta\tRpL4\nRpn13\tTER94\nRpn13\tUfd1-like\nRpn13\tUbqn\nRpn13\tProsalpha6\nRpn13\tProsbeta7\nRpn13\tRpt4R\nRpn13\tProsalpha7\nRpn13\tRpn12\nRpn13\tRpt6R\nRpn13\tRpn5\nRpn13\tRpt6\nRpn13\tRpn6\nRpn13\tUch-L5\nRpn13\tRpt2\nRpn13\tRpt5\nRpn13\tRpt1\nRpn13\tRpn2\nTango7\tCG7033\nTango7\tTcp-1zeta\nTango7\tmRpS10\nTango7\tRpn5\nTango7\tbonsai\nTango7\tRpn2\nTango7\tRpn6\nTango7\tRpS14a\nTango7\tRpS15Aa\nTango7\tRpS17\nTango7\tRpL10Ab\nTango7\tRpL12\nTango7\tRpL13\nTango7\tRpL18A\nTango7\tRpL3\nTango7\tRpS10a\nTango7\tRpL11\nTango7\tRpS10b\nTango7\tRpS2\nTango7\tRpS27\nTango7\tRpS23\nTango7\tRpS18\nTango7\tRpS12\nTango7\tRpS13\nTango7\tRpS4\nTango7\tRpS6\nTango7\tRpS16\nTango7\tsta\nTango7\teIF3-S10\nTango7\tRpS3\nTango7\tTrip1\nTango7\tRpL4\nTango7\tCG9769\nTango7\teIF3-S9\nTango7\tCG5642\nTango7\teIF3-S8\nRpt2\tUbqn\nRpt2\tUfd1-like\nRpt2\tCG8209\nRpt2\tUch-L5\nRpt2\tRpt4R\nRpt2\tRpn12\nRpt2\tRpt5\nRpt2\tRpt6\nRpt2\tProsalpha6\nRpt2\tRpn5\nRpt2\tProsbeta7\nRpn5\tUbqn\nRpn5\tUfd1-like\nRpn5\tCat\nRpn5\tCalpB\nRpn5\tCG6891\nRpn5\tUch-L5\nRpn5\tRpt4R\nRpn5\tRpt6\nRpn5\tRpn12\nbetaCOP\tcpa\nbetaCOP\tDlic\nbetaCOP\tKlp10A\nbetaCOP\tp115\nbetaCOP\talphaCOP\nbetaCOP\tdeltaCOP\nRpt6R\tRpS4\nRpt6R\tpont\nRpt6R\tRpt6\nRpt6R\tUch-L5\nRpt6R\tRpt4R\nRpt6R\tProsalpha6\nRpt6R\tRpt2\nRpt6R\tRpt5\nRpt6R\tProsbeta7\nRpt6R\tRpn12\nRpt6R\tRpn2\nRpt6R\tRpn5\nRpn2\tTrip1\nRpn2\tRpS2\nRpn2\tUsp5\nRpn2\tUch-L5\nRpn2\tProsalpha6\nRpn2\tRpt4R\nRpn2\tProsbeta7\nRpn2\tRpn12\nRpn2\tRpn5\nRpn2\tRpt6\nRpn2\tRpt2\nRpn2\tRpt5\nRpL10Ab\tbonsai\nRpL10Ab\tmago\nRpL10Ab\tCG5642\nRpL10Ab\tRpS15Aa\nRpL10Ab\tRpS14a\nRpL10Ab\tRpL12\nRpL10Ab\tRpS16\nRpL10Ab\tRpS12\nRpL10Ab\tRpS10b\nRpL10Ab\tRpS4\nRpL10Ab\tsta\nRpL10Ab\tRpS6\nTrip1\tRpS14a\nTrip1\tTcp-1zeta\nTrip1\tCG10576\nTrip1\tRpS17\nTrip1\tCG7033\nTrip1\tRpL10Ab\nTrip1\tRpS10b\nTrip1\tRpL12\nTrip1\tRpS12\nTrip1\tRpS4\nTrip1\tRpS6\nTrip1\tRpS16\nTrip1\tsta\nTrip1\tCG9769\nTrip1\teIF3-S10\nTrip1\tCG5642\ncpa\tp115\ncpa\tdeltaCOP\ncpb\tCG6891\ncpb\tflr\ncpb\tp115\ncpb\tdeltaCOP\ncpb\ttsr\ncpb\tbetaCOP\ncpb\tzetaCOP\ncpb\tDlic\ncpb\tcpa\neIF3-S10\tCG33123\neIF3-S10\tAats-ile\neIF3-S10\tRpS14a\neIF3-S10\tRpS17\neIF3-S10\tRpS15Aa\neIF3-S10\tRpL10Ab\neIF3-S10\tRpL12\neIF3-S10\tRpS12\neIF3-S10\tRpS10b\neIF3-S10\tRpS6\neIF3-S10\tRpS16\neIF3-S10\tRpS4\neIF3-S10\tsta\neIF3-S10\tCG5642\neIF3-S10\tCG9769\neIF3-S9\tCctgamma\neIF3-S9\trin\neIF3-S9\tRpS14a\neIF3-S9\tRpS15Aa\neIF3-S9\tRpS17\neIF3-S9\tTcp-1eta\neIF3-S9\tCG7033\neIF3-S9\tT-cp1\neIF3-S9\tCG10576\neIF3-S9\tpAbp\neIF3-S9\tRpL10Ab\neIF3-S9\tRpL12\neIF3-S9\tRpS12\neIF3-S9\tRpS10a\neIF3-S9\tRpS27\neIF3-S9\tRpS10b\neIF3-S9\tRpS18\neIF3-S9\tRpL11\neIF3-S9\tRpL13\neIF3-S9\tRpL3\neIF3-S9\tRpL4\neIF3-S9\tRpS16\neIF3-S9\tsta\neIF3-S9\tRpS2\neIF3-S9\tRpS13\neIF3-S9\tRpS4\neIF3-S9\tRpS6\neIF3-S9\tRpS3\neIF3-S9\tCG5642\neIF3-S9\teIF3-S8\neIF3-S9\tCG9769\neIF3-S9\tTrip1\neIF3-S9\teIF3-S10\nPdi\tUgt\nPdi\tOst48\nPdi\tCG2852\nPdi\tCG2918\nPdi\tHsc70-3\nepsilonCOP\tDlic\nepsilonCOP\tKlc\nepsilonCOP\tKlp10A\nepsilonCOP\tcpb\nepsilonCOP\tcpa\nepsilonCOP\tp115\nepsilonCOP\tdeltaCOP\nepsilonCOP\tzetaCOP\nepsilonCOP\talphaCOP\nepsilonCOP\tbetaCOP\nbeta'COP\tcpb\nbeta'COP\tcpa\nbeta'COP\tDlic\nbeta'COP\tKlp10A\nbeta'COP\tKlc\nbeta'COP\tp115\nbeta'COP\tzetaCOP\nbeta'COP\talphaCOP\nbeta'COP\tdeltaCOP\nbeta'COP\tbetaCOP\nbeta'COP\tepsilonCOP\nCaBP1\tUgt\nCaBP1\tOst48\nCaBP1\tCG2918\nCaBP1\tHsc70-3\nCaBP1\tPdi\nGp93\tCctgamma\nGp93\tbai\nGp93\tHsp27\nGp93\tHop\nGp93\tHsp70Ab\nGp93\tCG11577\nGp93\tPdi\nGp93\tHsc70-3\nGp93\tCG2918\nGp93\tCaBP1\nTcp-1eta\tRpL12\nTcp-1eta\tRpS6\nTcp-1eta\tRpL13\nTcp-1eta\tRpL10Ab\nTcp-1eta\tsta\nTcp-1eta\tRpS2\nTcp-1eta\tRpS12\nTcp-1eta\tRpS13\nTcp-1eta\tCG10576\nTcp-1eta\tRpS4\nTcp-1eta\tRpS16\nTcp-1eta\tTrip1\nTcp-1eta\tHop\nTcp-1eta\tade3\nTcp-1eta\tTcp-1zeta\nTcp-1eta\tCG7033\nRpL13\tmRpL12\nRpL13\tCG7033\nRpL13\tade3\nRpL13\tbonsai\nRpL13\tSrp19\nRpL13\tmago\nRpL13\tCG5642\nRpL13\teIF3-S10\nRpL13\tCG10576\nRpL13\tSrp54k\nRpL13\tCG9769\nRpL13\tTrip1\nRpL13\tRpS15Aa\nRpL13\tRpL12\nRpL13\tRpS12\nRpL13\tRpS13\nRpL13\tRpS6\nRpL13\tRpS14a\nRpL13\tRpL10Ab\nRpL13\tRpS4\nRpL13\tsta\nRpL13\tRpS17\nRpL13\tRpS10b\nRpL13\tRpS16\nRpt4\tProsalpha1\nRpt4\tarm\nRpt4\tRpt4R\nRpt4\tUch-L5\nRpt4\tRpt6R\nRpt4\tRpn13\nRpt4\tRpt1\nRpt4\tRpt6\nRpt4\tProsalpha6\nRpt4\tProsbeta7\nRpt4\tRpn6\nRpt4\tRpt2\nRpt4\tRpn3\nRpt4\tProsalpha7\nRpt4\tRpn2\nRpt4\tRpn12\nRpt4\tRpn5\nRpt4\tRpt5\nRpS11\tvig\nRpS11\tbic\nRpS11\tCG7033\nRpS11\tTctp\nRpS11\tTcp-1eta\nRpS11\teEF1delta\nRpS11\tmago\nRpS11\tEfTuM\nRpS11\tSrp72\nRpS11\tbonsai\nRpS11\tmRpS10\nRpS11\tCG5642\nRpS11\tmRpS9\nRpS11\tmRpL12\nRpS11\teIF3-S8\nRpS11\tCG9769\nRpS11\teIF3-S10\nRpS11\tSrp19\nRpS11\tade3\nRpS11\teIF3-S9\nRpS11\tSrp54k\nRpS11\tTango7\nRpS11\tTrip1\nRpS11\tRpL10Ab\nRpS11\tRpS23\nRpS11\tRpL3\nRpS11\tRpL12\nRpS11\tRpL11\nRpS11\tRpS14a\nRpS11\tRpL4\nRpS11\tRpS18\nRpS11\tRpS6\nRpS11\tsta\nRpS11\tRpS10a\nRpS11\tRpS17\nRpS11\tRpS2\nRpS11\tRpL18A\nRpS11\tRpS12\nRpS11\tRpS3\nRpS11\tRpS13\nRpS11\tRpS27\nRpS11\tRpS10b\nRpS11\tRpL13\nRpS11\tRpS16\nRpS11\tRpS15Aa\nRpS11\tRpS4\neIF3-S8\tCG33123\neIF3-S8\tTcp-1zeta\neIF3-S8\teEF1delta\neIF3-S8\tpAbp\neIF3-S8\tRpS14a\neIF3-S8\tRpS17\neIF3-S8\tRpS15Aa\neIF3-S8\tCG10576\neIF3-S8\tRpL12\neIF3-S8\tRpL10Ab\neIF3-S8\tRpL11\neIF3-S8\tRpL13\neIF3-S8\tRpL3\neIF3-S8\tRpS12\neIF3-S8\tsta\neIF3-S8\tRpS2\neIF3-S8\tRpS13\neIF3-S8\tRpS4\neIF3-S8\tRpS10b\neIF3-S8\tRpS27\neIF3-S8\tRpS10a\neIF3-S8\tRpS16\neIF3-S8\tRpL4\neIF3-S8\tRpS18\neIF3-S8\tRpS6\neIF3-S8\tRpS3\neIF3-S8\teIF3-S10\neIF3-S8\tTrip1\neIF3-S8\tCG9769\neIF3-S8\tCG5642\nHop\tHsp60\nHop\tHsc70-3\nHop\tUbqn\nCG1416\tCG7033\nCG1416\tHsp60\nCG1416\tGp93\nCG1416\tCctgamma\nCG1416\tHop\nRpS6\tRpS14a\nRpS6\tsta\nRpS2\tCG10576\nRpS2\tade3\nRpS2\tbonsai\nRpS2\tCG7033\nRpS2\tmago\nRpS2\tmRpL12\nRpS2\tCG5642\nRpS2\teIF3-S10\nRpS2\tSrp19\nRpS2\tCG9769\nRpS2\tSrp54k\nRpS2\tTrip1\nRpS2\tRpS6\nRpS2\tRpS15Aa\nRpS2\tRpL12\nRpS2\tRpS14a\nRpS2\tRpS10b\nRpS2\tRpS16\nRpS2\tRpL10Ab\nRpS2\tRpS17\nRpS2\tsta\nRpS2\tRpS4\nRpS2\tRpS13\nRpS2\tRpL13\nRpS2\tRpS12\nProsalpha6\tTrip1\nProsalpha6\tTcp-1zeta\nProsalpha6\tUch-L5\nProsalpha6\tRpn5\nProsalpha6\tRpt4R\nProsalpha6\tRpt6\nProsalpha6\tProsbeta7\nProsalpha6\tRpn12\nND-PDSW\tCOX6B\nND-PDSW\tCG7603\nND-PDSW\tND-B16.6\nND-PDSW\tCG11752\nNP15.6\tCG7603\nNP15.6\tCOX4\nNP15.6\tCG11752\nNP15.6\tND-51\nNP15.6\tCOX5A\nNP15.6\tND-B16.6\nNP15.6\tND-PDSW\nKlc\tDlic\nKlc\tbetaCOP\nKlc\tdeltaCOP\nKlc\tzetaCOP\nKlc\tKlp10A\nKhc\tDlic\nKhc\tzetaCOP\nKhc\tepsilonCOP\nKhc\tbai\nKhc\tdeltaCOP\nKhc\tbeta'COP\nKhc\tsyd\nKhc\tbetaCOP\nKhc\tKlp10A\nKhc\tbetaTub56D\nKhc\tKlc\nRpL12\tbonsai\nRpL12\tmago\nRpL12\tRpS16\nRpL12\tsta\nRpL12\tRpS14a\nRpL12\tRpS6\nRpt5\tUbqn\nRpt5\tCat\nRpt5\tCalpB\nRpt5\tCG6891\nRpt5\tEct3\nRpt5\tPyK\nRpt5\tTcp-1eta\nRpt5\tUfd1-like\nRpt5\tUch-L5\nRpt5\tRpt4R\nRpt5\tProsalpha6\nRpt5\tProsbeta7\nRpt5\tRpn5\nRpt5\tRpt6\nRpt5\tRpn12\nProsalpha7\tRpS16\nProsalpha7\tCct5\nProsalpha7\tTcp-1eta\nProsalpha7\tCG7033\nProsalpha7\tTrip1\nProsalpha7\tCG8258\nProsalpha7\tarm\nProsalpha7\tUch-L5\nProsalpha7\tRpt4R\nProsalpha7\tProsalpha1\nProsalpha7\tRpt6R\nProsalpha7\tRpn12\nProsalpha7\tRpt6\nProsalpha7\tRpn6\nProsalpha7\tRpt2\nProsalpha7\tRpt1\nProsalpha7\tProsbeta7\nProsalpha7\tProsalpha6\nProsalpha7\tRpn5\nProsalpha7\tRpn2\nProsalpha7\tRpt5\nRpn6\tTrip1\nRpn6\tRpS2\nRpn6\tUbqn\nRpn6\tCalpB\nRpn6\tCat\nRpn6\tPyK\nRpn6\tEct3\nRpn6\tCG6891\nRpn6\tUch-L5\nRpn6\tProsalpha6\nRpn6\tRpt4R\nRpn6\tProsbeta7\nRpn6\tRpn2\nRpn6\tRpt5\nRpn6\tRpn12\nRpn6\tRpn5\nRpn6\tRpt2\nRpn6\tRpt6R\nRpn6\tRpt6\nATPsynbeta\tRack1\nATPsynbeta\tCOX4\nATPsynbeta\tCOX6B\nATPsynbeta\tsta\nATPsynbeta\tHsc70-5\nATPsynbeta\tEno\nATPsynbeta\tRpL4\nATPsynbeta\tRpS3A\nATPsynbeta\tCG11876\nATPsynbeta\tMpcp\nATPsynbeta\tporin\nATPsynbeta\tVha100-1\nATPsynbeta\tRpS2\nATPsynbeta\tVha100-2\nATPsynbeta\tHsp83\nATPsynbeta\tND-51\nATPsynbeta\tVha68-2\nATPsynbeta\tEfTuM\nATPsynbeta\tMdh2\nATPsynbeta\tCG9090\nATPsynbeta\tCOX5A\nATPsynbeta\tsun\nATPsynCF6\tVha100-1\nATPsynCF6\tVha100-2\nATPsynCF6\tNP15.6\nATPsynCF6\tVha68-2\nATPsynCF6\tND-B16.6\nATPsynCF6\tCOX6B\nATPsynCF6\tCG11752\nATPsynCF6\tCyt-c-p\nATPsynCF6\tCOX4\nATPsynCF6\tND-PDSW\nATPsynCF6\tCOX5A\nATPsynCF6\tsun\nATPsynCF6\tATPsynbeta\nCG8258\tRpS13\nCG8258\tRpL11\nCG8258\teIF3-S9\nCG8258\tTango7\nCG8258\tHsp60C\nCG8258\tRpn2\nCG8258\tRpS3\nCG8258\tRpL12\nCG8258\tRpL3\nCG8258\tHsc70-5\nCG8258\tRpL4\nCG8258\tRpS4\nCG8258\tRpS2\nCG8258\tRpS16\nCG8258\tHsp60\nCG8258\tCG10576\nCG8258\tCat\nCG8258\tCG6891\nCG8258\tCalpB\nCG8258\tEct3\nCG8258\tCp1\nCG8258\tPfk\nCG8258\tPyK\nCG8258\tade3\nCG8258\tTrip1\nCG8258\tRpt5\nCG8258\tRpn6\nCG8258\tRpn5\nCG8258\tHop\nCG8258\tCct5\nCG8258\tCctgamma\nCG8258\tTcp-1zeta\nCG8258\tCG7033\nCG8258\tTcp-1eta\nCG8258\tT-cp1\nRpS7\tRpt6R\nRpS7\tRpt6\nRpS7\tvig\nRpS7\teEF1delta\nRpS7\tRpt1\nRpS7\tRpt2\nRpS7\tade3\nRpS7\tmRpS10\nRpS7\tSrp72\nRpS7\tmago\nRpS7\tbonsai\nRpS7\tTctp\nRpS7\tCG5642\nRpS7\tCG9769\nRpS7\teIF3-S10\nRpS7\tSrp54k\nRpS7\tSrp19\nRpS7\tTrip1\nRpS7\teIF3-S9\nRpS7\teIF3-S8\nRpS7\tTango7\nRpS7\tRpS15Ab\nRpS7\tRpS10a\nRpS7\tRpS15Aa\nRpS7\tRpS14a\nRpS7\tRpL4\nRpS7\tRpL13\nRpS7\tsta\nRpS7\tRpS2\nRpS7\tRpS23\nRpS7\tRpS16\nRpS7\tRpL10Ab\nRpS7\tRpS6\nRpS7\tRpS18\nRpS7\tRpL11\nRpS7\tRpS12\nRpS7\tRpS4\nRpS7\tRpS3\nRpS7\tRpS13\nRpS7\tRpS27\nRpS7\tRpL3\nRpS7\tRpS10b\nRpS7\tRpS17\nRpS7\tRpL18A\nRpS7\tRpS11\nRpS7\tRpL12\nRpL10\tmRpS10\nRpL10\tade3\nRpL10\tCct5\nRpL10\tmRpS5\nRpL10\teEF1delta\nRpL10\tmRpL12\nRpL10\tmRpS9\nRpL10\tEf1beta\nRpL10\teIF4G\nRpL10\tSrp72\nRpL10\tmago\nRpL10\tRbp2\nRpL10\teIF3-S10\nRpL10\teIF3-S8\nRpL10\tCG5642\nRpL10\tCG10576\nRpL10\tTango7\nRpL10\tTrip1\nRpL10\tSrp19\nRpL10\tmRpS7\nRpL10\teIF-2gamma\nRpL10\tElf\nRpL10\teIF-3p66\nRpL10\tCG9769\nRpL10\teIF3-S9\nRpL10\tSrp54k\nRpL10\teRF1\nRpL10\tRpS15Ab\nRpL10\tTctp\nRpL10\tRpS14a\nRpL10\tRpS15Aa\nRpL10\tRpS10b\nRpL10\tRpS17\nRpL10\tRpL13\nRpL10\tRpS8\nRpL10\tRpS16\nRpL10\tsta\nRpL10\tRpL12\nRpL10\tRpS3\nRpL10\tRpL4\nRpL10\tRpS27\nRpL10\tRpL3\nRpL10\tRpS12\nRpL10\tRpL11\nRpL10\tRpLP2\nRpL10\tRpL18A\nRpL10\tRpL26\nRpL10\tRpS4\nRpL10\tRack1\nRpL10\tRpS3A\nRpL10\tRpS11\nRpL10\tRpS13\nRpL10\tRpS10a\nRpL10\tRpL30\nRpL10\tRpS2\nRpL10\tRpS18\nRpL10\tRpS23\nRpL10\tRpL10Ab\nRpL10\tRpS6\nRpL10\tRpS7\nAats-asp\tCG5642\nAats-asp\tCG31739\nAats-asp\tCG33123\nAats-asp\tAats-arg\nAats-asp\tAats-ile\nCG33123\tAats-arg\nAats-ile\tCG33123\nAats-ile\tAats-arg\nRpS8\tT-cp1\nRpS8\tvig\nRpS8\tRpn2\nRpS8\tCct5\nRpS8\teEF1delta\nRpS8\tmRpS10\nRpS8\tCG8258\nRpS8\tTcp-1eta\nRpS8\tbonsai\nRpS8\tCG7033\nRpS8\tade3\nRpS8\tCG10576\nRpS8\tSrp72\nRpS8\tmago\nRpS8\tRbp2\nRpS8\tNacalpha\nRpS8\tCG5642\nRpS8\teIF-3p66\nRpS8\tSrp54k\nRpS8\tSrp19\nRpS8\teIF3-S10\nRpS8\tTctp\nRpS8\tTrip1\nRpS8\tTango7\nRpS8\teIF3-S8\nRpS8\tCG9769\nRpS8\teIF3-S9\nRpS8\tRpL13\nRpS8\tRpS17\nRpS8\tRpL11\nRpS8\tRpS12\nRpS8\tRpL4\nRpS8\tRpS3\nRpS8\tRpS27\nRpS8\tRpS18\nRpS8\tRpS2\nRpS8\tRpS13\nRpS8\tRpS7\nRpS8\tRpS6\nRpS8\tsta\nRpS8\tRpL10Ab\nRpS8\tRpS10b\nRpS8\tRpS10a\nRpS8\tRpS14a\nRpS8\tRpS4\nRpS8\tRpL12\nRpS8\tRpS11\nRpS8\tRpL18A\nRpS8\tRpLP2\nRpS8\tRpL3\nRpS8\tRpS23\nRpS8\tRpS15Ab\nRpS8\tRpS15Aa\nRpS8\tRpS16\nRpt6\tUbqn\nRpt6\tRpS4\nRpt6\tUch-L5\nRpt6\tRpt4R\nRpt6\tRpn12\nRpn3\tbel\nRpn3\tUbqn\nRpn3\tCalpB\nRpn3\tEct3\nRpn3\tPfk\nRpn3\tCG6891\nRpn3\tCat\nRpn3\tCp1\nRpn3\tPyK\nRpn3\tarm\nRpn3\tcathD\nRpn3\tCG8258\nRpn3\tProsalpha1\nRpn3\tUch-L5\nRpn3\tTER94\nRpn3\tProsalpha6\nRpn3\tProsbeta7\nRpn3\tProsalpha7\nRpn3\tRpt4R\nRpn3\tRpn2\nRpn3\tRpt6R\nRpn3\tRpt2\nRpn3\tRpn5\nRpn3\tRpt1\nRpn3\tRpt5\nRpn3\tRpn6\nRpn3\tRpn13\nRpn3\tRpn12\nRpn3\tRpt6\nRpL30\tvig\nRpL30\tNacalpha\nRpL30\tCG10576\nRpL30\tSrp72\nRpL30\teIF4G\nRpL30\tbonsai\nRpL30\teIF3-S8\nRpL30\tmago\nRpL30\teIF3-S10\nRpL30\tCG5642\nRpL30\tmRpS5\nRpL30\tRbp2\nRpL30\tmRpS10\nRpL30\teIF-3p66\nRpL30\tTctp\nRpL30\teIF3-S9\nRpL30\tTango7\nRpL30\tCG9769\nRpL30\tTrip1\nRpL30\tSrp54k\nRpL30\tSrp19\nRpL30\tRpS15Aa\nRpL30\tRpS15Ab\nRpL30\tRpS10a\nRpL30\tRpL18A\nRpL30\tRpS27\nRpL30\tRpL12\nRpL30\tRpS12\nRpL30\tRpS18\nRpL30\tRpS17\nRpL30\tRpS2\nRpL30\tRpL11\nRpL30\tRpS7\nRpL30\tRpS14a\nRpL30\tRpS4\nRpL30\tRpS8\nRpL30\tRpS10b\nRpL30\tRpLP2\nRpL30\tRpL13\nRpL30\tRpS16\nRpL30\tRpS3\nRpL30\tRpS13\nRpL30\tRpS11\nRpL30\tRpS6\nRpL30\tRpL3\nRpL30\tRpL10Ab\nRpL30\tRpS23\nRpL30\tRpL4\nRpL30\tsta\nRpS10a\tTctp\nRpS10a\teEF1delta\nRpS10a\tbonsai\nRpS10a\tmRpS10\nRpS10a\tRpS10b\nRpS10a\tSrp72\nRpS10a\tmago\nRpS10a\tCG5642\nRpS10a\tCG9769\nRpS10a\teIF3-S10\nRpS10a\tTrip1\nRpS10a\tSrp19\nRpS10a\tSrp54k\nRpS10a\tRpS15Aa\nRpS10a\tsta\nRpS10a\tRpS2\nRpS10a\tRpS3\nRpS10a\tRpL10Ab\nRpS10a\tRpS4\nRpS10a\tRpS13\nRpS10a\tRpS6\nRpS10a\tRpS12\nRpS10a\tRpS16\nRpS10a\tRpS14a\nRpS10a\tRpS27\nRpS10a\tRpL13\nRpS10a\tRpL12\nRpS10a\tRpS17\nRpS10a\tRpL3\nRpS17\tCG7033\nRpS17\tCG5642\nRpS17\tbonsai\nRpS17\tRpS6\nRpS17\tRpL12\nRpS17\tRpL10Ab\nRpS17\tRpS15Aa\nRpS17\tRpS12\nRpS17\tsta\nRpS17\tRpS14a\nRpS17\tRpS4\nRpS17\tRpS16\nRpS17\tRpS10b\nRpLP0\tATPsynbeta\nRpLP0\tTcp-1zeta\nRpLP0\tT-cp1\nRpLP0\tCG7033\nRpLP0\tEfTuM\nRpLP0\tNacalpha\nRpLP0\tbonsai\nRpLP0\tTcp-1eta\nRpLP0\tmRpS10\nRpLP0\tade3\nRpLP0\tCct5\nRpLP0\tmRpS5\nRpLP0\teEF1delta\nRpLP0\tSrp72\nRpLP0\teIF4G\nRpLP0\tmRpS9\nRpLP0\tRbp2\nRpLP0\tmago\nRpLP0\tCG5642\nRpLP0\teIF3-S8\nRpLP0\tElf\nRpLP0\teIF3-S10\nRpLP0\tCG10576\nRpLP0\tmRpL12\nRpLP0\tmRpS7\nRpLP0\tTctp\nRpLP0\tSrp19\nRpLP0\tTango7\nRpLP0\teIF-2gamma\nRpLP0\teIF-3p66\nRpLP0\tCG9769\nRpLP0\teIF3-S9\nRpLP0\tRpS15Aa\nRpLP0\tSrp54k\nRpLP0\tTrip1\nRpLP0\tRpS15Ab\nRpLP0\teRF1\nRpLP0\tRpS14a\nRpLP0\tRpS10a\nRpLP0\tEf1beta\nRpLP0\tRpS6\nRpLP0\tRpS13\nRpLP0\tRpS23\nRpLP0\tsta\nRpLP0\tRpS11\nRpLP0\tRpS16\nRpLP0\tRpS7\nRpLP0\tRpS27\nRpLP0\tRpL10\nRpLP0\tRpS3\nRpLP0\tRpS10b\nRpLP0\tRpS8\nRpLP0\tRpLP2\nRpLP0\tRpS12\nRpLP0\tRpL3\nRpLP0\tRack1\nRpLP0\tRpL13\nRpLP0\tRpL26\nRpLP0\tRpL30\nRpLP0\tRpL18A\nRpLP0\tRpL4\nRpLP0\tRpL10Ab\nRpLP0\tRpS18\nRpLP0\tRpS3A\nRpLP0\tRpL12\nRpLP0\tRpL11\nRpLP0\tRpS2\nRpLP0\tRpS4\nRpLP0\tRpS17\neRF1\tbonsai\neRF1\tT-cp1\neRF1\teIF3-S8\neRF1\tCG8635\neRF1\tCG7033\neRF1\tCctgamma\neRF1\tmRpS5\neRF1\tmRpS10\neRF1\twuho\neRF1\tRpS15Ab\neRF1\tRpS14a\neRF1\tRpS15Aa\neRF1\teIF3-S10\neRF1\tpAbp\neRF1\tCG10576\neRF1\tRpS17\neRF1\teIF-2gamma\neRF1\tTrip1\neRF1\tmago\neRF1\tRpLP2\neRF1\teIF3-S9\neRF1\teIF4G\neRF1\tRack1\neRF1\tRpS10a\neRF1\tRpS10b\neRF1\tRpL3\neRF1\tRpL10Ab\neRF1\tRpS27\neRF1\tRpS12\neRF1\tRpS7\neRF1\tRpS18\neRF1\tRpL12\neRF1\tRpS23\neRF1\tRpL18A\neRF1\tRpS16\neRF1\tRpL30\neRF1\tRpS11\neRF1\tRpS3\neRF1\tRpS3A\neRF1\tsta\neRF1\tRpS13\neRF1\tRpS6\neRF1\tRpS8\neRF1\tRpL4\neRF1\tRpS4\neRF1\tRpL11\neRF1\tRpS2\neRF1\tRpL13\nElf\tade5\nElf\tmRpS7\nElf\tRpS15Aa\nElf\tRpS15Ab\nElf\tT-cp1\nElf\teIF3-S9\nElf\tCctgamma\nElf\tRpS17\nElf\tCG33123\nElf\tCct5\nElf\tRpS14a\nElf\teIF3-S8\nElf\teIF3-S10\nElf\teIF-2gamma\nElf\tRpL10Ab\nElf\tRpLP2\nElf\tmago\nElf\tRpL13\nElf\tRpL3\nElf\tRpL30\nElf\tRpL18A\nElf\tRpL12\nElf\tRpL11\nElf\tRack1\nElf\tRpL4\nElf\tRpS4\nElf\tRpS10b\nElf\tRpS10a\nElf\tRpS12\nElf\teIF4G\nElf\tRpS11\nElf\tRpS13\nElf\tRpS27\nElf\tRpS8\nElf\tRpS16\nElf\tRpS3\nElf\tsta\nElf\tRpS23\nElf\tRpS18\nElf\tRpS7\nElf\tRpS6\nElf\tRpS3A\nElf\tRpS2\nElf\tpAbp\nElf\teRF1\nRpS15Aa\tbonsai\nRpS15Aa\tRpL12\nRpS15Aa\tsta\nRpS15Aa\tRpS6\nRpS15Aa\tRpS16\nRpS15Aa\tRpS14a\nRpS27\tvig\nRpS27\tSrp72\nRpS27\tmRpS10\nRpS27\tbonsai\nRpS27\tmago\nRpS27\tTctp\nRpS27\tCG5642\nRpS27\tCG9769\nRpS27\tTrip1\nRpS27\teIF3-S10\nRpS27\tSrp19\nRpS27\tSrp54k\nRpS27\tRpS13\nRpS27\tRpS17\nRpS27\tRpS4\nRpS27\tRpS2\nRpS27\tRpL13\nRpS27\tRpL12\nRpS27\tRpS6\nRpS27\tRpS12\nRpS27\tRpS10b\nRpS27\tsta\nRpS27\tRpS16\nRpS27\tRpS14a\nRpS27\tRpL10Ab\nRpS27\tRpL3\nRpS27\tRpS3\nRpS27\tRpS15Aa\nRpS18\tRpt6R\nRpS18\tRpt6\nRpS18\tTcp-1eta\nRpS18\tRpt2\nRpS18\tvig\nRpS18\tade3\nRpS18\tSrp72\nRpS18\tmago\nRpS18\tbonsai\nRpS18\tTctp\nRpS18\tCG5642\nRpS18\tmRpL12\nRpS18\tmRpS10\nRpS18\tmRpS9\nRpS18\teIF3-S10\nRpS18\tCG9769\nRpS18\tSrp19\nRpS18\tSrp54k\nRpS18\tTrip1\nRpS18\tRpS12\nRpS18\tRpS2\nRpS18\tRpS16\nRpS18\tsta\nRpS18\tRpL10Ab\nRpS18\tRpL4\nRpS18\tRpS14a\nRpS18\tRpS17\nRpS18\tRpS3\nRpS18\tRpS4\nRpS18\tRpL3\nRpS18\tRpS10a\nRpS18\tRpS13\nRpS18\tRpS10b\nRpS18\tRpL13\nRpS18\tRpL12\nRpS18\tRpS15Aa\nRpS18\tRpS6\nRpS18\tRpS27\nRpS10b\tbonsai\nRpS10b\tmago\nRpS10b\tRpS15Aa\nRpS10b\tRpS16\nRpS10b\tRpS14a\nRpS10b\tRpL12\nRpS10b\tsta\nRpS10b\tRpS6\nRpS3A\tCG7048\nRpS3A\tNacalpha\nRpS3A\tvig\nRpS3A\teEF1delta\nRpS3A\tCct5\nRpS3A\tCG8258\nRpS3A\tCG7033\nRpS3A\tTcp-1eta\nRpS3A\tSrp72\nRpS3A\tmRpS5\nRpS3A\tRbp2\nRpS3A\tmRpS10\nRpS3A\teIF4G\nRpS3A\tbonsai\nRpS3A\tmago\nRpS3A\tCG5642\nRpS3A\teIF-3p66\nRpS3A\teIF3-S8\nRpS3A\tSrp54k\nRpS3A\teIF3-S10\nRpS3A\tSrp19\nRpS3A\tCG9769\nRpS3A\tade3\nRpS3A\tTrip1\nRpS3A\tTango7\nRpS3A\teIF3-S9\nRpS3A\tTctp\nRpS3A\tRpS12\nRpS3A\tRpS13\nRpS3A\tRpS2\nRpS3A\tRpS17\nRpS3A\tRpS15Ab\nRpS3A\tRpL13\nRpS3A\tRpS15Aa\nRpS3A\tRpS8\nRpS3A\tRpS10a\nRpS3A\tRpS4\nRpS3A\tRpL11\nRpS3A\tRpS23\nRpS3A\tRpS7\nRpS3A\tRpLP2\nRpS3A\tsta\nRpS3A\tRpS6\nRpS3A\tRpL12\nRpS3A\tRpS11\nRpS3A\tRpL30\nRpS3A\tRpL3\nRpS3A\tRpS3\nRpS3A\tRpS14a\nRpS3A\tRpL10Ab\nRpS3A\tRpL18A\nRpS3A\tRpS27\nRpS3A\tRpL4\nRpS3A\tRpS16\nRpS3A\tRpS18\nRpS3A\tRpS10b\nRpS16\tmago\nRpS16\tRpS14a\nRpS16\tRpS6\nRpS16\tsta\nRpS15Ab\tvig\nRpS15Ab\tCG9769\nRpS15Ab\tade3\nRpS15Ab\tEfTuM\nRpS15Ab\tSrp19\nRpS15Ab\teIF3-S9\nRpS15Ab\teIF3-S10\nRpS15Ab\teIF3-S8\nRpS15Ab\tbonsai\nRpS15Ab\tmRpS10\nRpS15Ab\tSrp54k\nRpS15Ab\tTango7\nRpS15Ab\tTctp\nRpS15Ab\tmRpS9\nRpS15Ab\tmRpL12\nRpS15Ab\tRpS15Aa\nRpS15Ab\tRpS12\nRpS15Ab\tRpL10Ab\nRpS15Ab\tRpL13\nRpS15Ab\tRpL18A\nRpS15Ab\tRpL12\nRpS15Ab\tRpL3\nRpS15Ab\tRpL4\nRpS15Ab\tRpS10a\nRpS15Ab\tRpL11\nRpS15Ab\tRpS6\nRpS15Ab\tRpS2\nRpS15Ab\tRpS13\nRpS15Ab\tRpS23\nRpS15Ab\tRpS18\nRpS15Ab\tRpS3\nRpS15Ab\tRpS10b\nRpS15Ab\tRpS17\nRpS15Ab\tRpS14a\nRpS15Ab\tsta\nRpS15Ab\tRpS11\nRpS15Ab\tRpS27\nRpS15Ab\tRpS4\nRpS15Ab\tRpS16\nRpL3\teEF1delta\nRpL3\tbonsai\nRpL3\tTcp-1zeta\nRpL3\tTcp-1eta\nRpL3\tCG7033\nRpL3\tTctp\nRpL3\tmago\nRpL3\tSrp19\nRpL3\tmRpL12\nRpL3\tmRpS9\nRpL3\teIF3-S10\nRpL3\tCG10576\nRpL3\tCG5642\nRpL3\tCG9769\nRpL3\tSrp54k\nRpL3\tTrip1\nRpL3\tade3\nRpL3\tRpS14a\nRpL3\tRpS10b\nRpL3\tRpS15Aa\nRpL3\tRpS13\nRpL3\tRpS16\nRpL3\tRpS2\nRpL3\tRpS4\nRpL3\tRpS17\nRpL3\tsta\nRpL3\tRpL12\nRpL3\tRpL13\nRpL3\tRpL10Ab\nRpL3\tRpS12\nRpL3\tRpS6\nTcp-1zeta\tTim9a\nTcp-1zeta\tRpL12\nTcp-1zeta\tHsp60\nTcp-1zeta\tsta\nTcp-1zeta\tCG7033\nT-cp1\tRpS13\nT-cp1\tRpS2\nT-cp1\tRpL13\nT-cp1\tHop\nT-cp1\tsta\nT-cp1\tRpL12\nT-cp1\tAats-ile\nT-cp1\tRpS4\nT-cp1\tRpL3\nT-cp1\tCG10576\nT-cp1\tCG7033\nT-cp1\tCctgamma\nT-cp1\tTcp-1eta\nT-cp1\tTcp-1zeta\nRpS3\tTcp-1zeta\nRpS3\tvig\nRpS3\tCG7033\nRpS3\teEF1delta\nRpS3\tade3\nRpS3\tTcp-1eta\nRpS3\tSrp72\nRpS3\tmago\nRpS3\tbonsai\nRpS3\tmRpS10\nRpS3\tmRpS9\nRpS3\tmRpL12\nRpS3\tSrp19\nRpS3\tCG5642\nRpS3\tSrp54k\nRpS3\tCG9769\nRpS3\tTctp\nRpS3\teIF3-S10\nRpS3\tRpS15Aa\nRpS3\tRpL13\nRpS3\tRpS6\nRpS3\tRpS2\nRpS3\tRpL12\nRpS3\tRpL10Ab\nRpS3\tRpS14a\nRpS3\tRpS12\nRpS3\tRpS13\nRpS3\tRpS16\nRpS3\tRpS10b\nRpS3\tsta\nRpS3\tRpS4\nRpS3\tRpL3\nRpS3\tRpS17\nRpS3\tTrip1\nRpL26\tCG10576\nRpL26\teEF1delta\nRpL26\tEfTuM\nRpL26\tNacalpha\nRpL26\tbonsai\nRpL26\tade3\nRpL26\tmRpS10\nRpL26\tmRpS5\nRpL26\tTctp\nRpL26\teIF4G\nRpL26\tCG5642\nRpL26\tmago\nRpL26\teIF3-S10\nRpL26\tRbp2\nRpL26\tmRpS9\nRpL26\teIF3-S9\nRpL26\tmRpL12\nRpL26\teIF-3p66\nRpL26\teIF3-S8\nRpL26\tSrp72\nRpL26\teIF-2gamma\nRpL26\tmRpS7\nRpL26\tCG9769\nRpL26\tElf\nRpL26\tTango7\nRpL26\tTrip1\nRpL26\tEf1beta\nRpL26\tSrp19\nRpL26\teRF1\nRpL26\tSrp54k\nRpL26\tRpS15Aa\nRpL26\tRpS15Ab\nRpL26\tRpL10Ab\nRpL26\tRpL11\nRpL26\tRpL3\nRpL26\tRpS13\nRpL26\tRpS2\nRpL26\tRpS6\nRpL26\tRpS4\nRpL26\tRpS27\nRpL26\tRpL30\nRpL26\tRpL18A\nRpL26\tRpS12\nRpL26\tRpS10a\nRpL26\tRpS18\nRpL26\tRpS3A\nRpL26\tRpS8\nRpL26\tRpS17\nRpL26\tsta\nRpL26\tRpS14a\nRpL26\tRpS11\nRpL26\tRpS23\nRpL26\tRpL13\nRpL26\tRpL12\nRpL26\tRpS10b\nRpL26\tRack1\nRpL26\tRpL4\nRpL26\tRpS3\nRpL26\tRpS7\nRpL26\tRpS16\nRpL26\tRpLP2\nRpS12\tmago\nRpS12\tRpS14a\nRpS12\tRpS15Aa\nRpS12\tRpS10b\nRpS12\tRpS6\nRpS12\tRpS16\nRpS12\tRpL12\nRpS12\tsta\nCG5642\tRpL12\nCG5642\tRpS6\nCG5642\tsta\nCG5642\tRpS10b\nCG5642\tRpS12\nCG5642\tRpS16\nCG5642\tRpS4\nCG9769\tRpS15Aa\nCG9769\tRpS17\nCG9769\tRpS12\nCG9769\tRpL12\nCG9769\tRpS10b\nCG9769\tRpL10Ab\nCG9769\tRpS4\nCG9769\tsta\nCG9769\tRpS6\nCG9769\tRpS16\nCG9769\tCG5642\nCG7033\tRpS14a\nCG7033\tsta\nCct5\tRpS13\nCct5\tade3\nCct5\tProsalpha6\nCct5\tHsc70-5\nCct5\tRpt6\nCct5\tRpS3\nCct5\tRef1\nCct5\tRpS16\nCct5\tRpL12\nCct5\tRpL13\nCct5\tCG5642\nCct5\tRpL18A\nCct5\tRpS6\nCct5\tsta\nCct5\tRpL11\nCct5\tAats-ile\nCct5\tpont\nCct5\tTrip1\nCct5\tRpS4\nCct5\tTango7\nCct5\teIF3-S9\nCct5\tRpL3\nCct5\tRpS2\nCct5\tCG10576\nCct5\tRpL4\nCct5\tHop\nCct5\tCctgamma\nCct5\tTcp-1eta\nCct5\tT-cp1\nCct5\tTcp-1zeta\nCct5\tCG7033\nRpLP2\tCG10576\nRpLP2\tbonsai\nRpLP2\tmRpS10\nRpLP2\tSrp72\nRpLP2\tSrp54k\nRpLP2\tSrp19\nRpLP2\tmago\nRpLP2\teIF3-S8\nRpLP2\teIF3-S10\nRpLP2\tCG5642\nRpLP2\tRbp2\nRpLP2\tTango7\nRpLP2\teIF3-S9\nRpLP2\teIF-3p66\nRpLP2\tNacalpha\nRpLP2\tRpS15Aa\nRpLP2\tCG9769\nRpLP2\tTrip1\nRpLP2\tTctp\nRpLP2\tRpS10a\nRpLP2\tRpS10b\nRpLP2\tRpS27\nRpLP2\tRpS3\nRpLP2\tRpS13\nRpLP2\tRpS18\nRpLP2\tRpL4\nRpLP2\tRpS7\nRpLP2\tRpL13\nRpLP2\tRpS23\nRpLP2\tRpL10Ab\nRpLP2\tRpS15Ab\nRpLP2\tRpS6\nRpLP2\tRpS14a\nRpLP2\tRpS2\nRpLP2\tRpL3\nRpLP2\tRpL12\nRpLP2\tRpL18A\nRpLP2\tRpL11\nRpLP2\tRpS11\nRpLP2\tsta\nRpLP2\tRpS16\nRpLP2\tRpS17\nRpLP2\tRpS12\nRpLP2\tRpS4\nRpS23\tCG7033\nRpS23\tvig\nRpS23\teEF1delta\nRpS23\tbonsai\nRpS23\tmRpS10\nRpS23\tSrp72\nRpS23\tmago\nRpS23\tCG5642\nRpS23\tmRpL12\nRpS23\tmRpS9\nRpS23\tTctp\nRpS23\teIF3-S9\nRpS23\teIF3-S8\nRpS23\teIF3-S10\nRpS23\tCG9769\nRpS23\tTrip1\nRpS23\tSrp19\nRpS23\tSrp54k\nRpS23\tRpS16\nRpS23\tRpS27\nRpS23\tRpL18A\nRpS23\tRpS10b\nRpS23\tRpS15Aa\nRpS23\tRpS12\nRpS23\tRpS3\nRpS23\tRpS18\nRpS23\tRpS14a\nRpS23\tRpL11\nRpS23\tRpL3\nRpS23\tRpS2\nRpS23\tsta\nRpS23\tRpS6\nRpS23\tRpL10Ab\nRpS23\tRpL12\nRpS23\tRpL13\nRpS23\tRpS17\nRpS23\tRpL4\nRpS23\tRpS4\nRpS23\tRpS10a\nRpS23\tRpS13\nRpS14a\tsta\nRack1\tvig\nRack1\tbel\nRack1\tProsalpha7\nRack1\tRpn6\nRack1\tRpn2\nRack1\teEF1delta\nRack1\tCctgamma\nRack1\tEno\nRack1\tpAbp\nRack1\tNacalpha\nRack1\teIF3-S8\nRack1\tCG10576\nRack1\tCG9769\nRack1\tade3\nRack1\tDp1\nRack1\tT-cp1\nRack1\tTcp-1zeta\nRack1\tSrp54k\nRack1\tTcp-1eta\nRack1\tSrp19\nRack1\tCG8258\nRack1\tCG7033\nRack1\tCct5\nRack1\tmRpS5\nRack1\tbonsai\nRack1\tmRpS10\nRack1\teIF3-S10\nRack1\tTctp\nRack1\teIF3-S9\nRack1\teIF-2gamma\nRack1\tTrip1\nRack1\tRpS15Ab\nRack1\tTango7\nRack1\tRpS15Aa\nRack1\tRpS10a\nRack1\tRpS14a\nRack1\tRpS10b\nRack1\tRpL10Ab\nRack1\tRpS8\nRack1\tRpL3\nRack1\tRpS11\nRack1\tRpS17\nRack1\tRpS2\nRack1\tRpS16\nRack1\tRpS13\nRack1\tRpS12\nRack1\tRpS4\nRack1\tRpS3A\nRack1\tRpS3\nRack1\tRpS18\nRack1\tRpS23\nRack1\tRpS6\nRack1\tRpL12\nRack1\tRpL13\nRack1\tRpS27\nRack1\tRpL11\nRack1\tRpL18A\nRack1\tRpL30\nRack1\tRpS7\nRack1\tRpLP2\nRack1\tRpL4\nRack1\tsta\nRpL11\tCG7033\nRpL11\tvig\nRpL11\teEF1delta\nRpL11\tTcp-1eta\nRpL11\tmago\nRpL11\teIF3-S10\nRpL11\tCG10576\nRpL11\tCG5642\nRpL11\tbonsai\nRpL11\tmRpS10\nRpL11\tSrp72\nRpL11\tmRpS9\nRpL11\tTctp\nRpL11\tmRpL12\nRpL11\tCG9769\nRpL11\tSrp19\nRpL11\tSrp54k\nRpL11\tTrip1\nRpL11\tRpS15Aa\nRpL11\tRpS13\nRpL11\tRpS18\nRpL11\tRpL3\nRpL11\tRpL12\nRpL11\tRpS10b\nRpL11\tRpS17\nRpL11\tRpL10Ab\nRpL11\tRpS10a\nRpL11\tRpL13\nRpL11\tRpS4\nRpL11\tRpS16\nRpL11\tRpS12\nRpL11\tRpS27\nRpL11\tRpS2\nRpL11\tRpS3\nRpL11\tRpS6\nRpL11\tRpS14a\nRpL11\tRpL4\nRpL11\tsta\nRpn12\tUbqn\nProsbeta7\tUba2\nProsbeta7\tCG7033\nProsbeta7\tUch-L5\nProsbeta7\tRpt4R\nProsbeta7\tRpn5\nProsbeta7\tRpt6\nProsbeta7\tRpn12\nRpS13\tCG10576\nRpS13\tCG7033\nRpS13\tmRpL12\nRpS13\tade3\nRpS13\tmago\nRpS13\tCG5642\nRpS13\teIF3-S10\nRpS13\tCG9769\nRpS13\tSrp19\nRpS13\tSrp54k\nRpS13\tTrip1\nRpS13\tRpL10Ab\nRpS13\tRpS15Aa\nRpS13\tRpS12\nRpS13\tRpS17\nRpS13\tRpL12\nRpS13\tRpS10b\nRpS13\tsta\nRpS13\tRpS16\nRpS13\tRpS4\nRpS13\tRpS6\nRpS13\tRpS14a\nRpL18A\tTcp-1zeta\nRpL18A\tvig\nRpL18A\tCG7033\nRpL18A\teEF1delta\nRpL18A\tTcp-1eta\nRpL18A\tade3\nRpL18A\tmRpS10\nRpL18A\tmago\nRpL18A\tbonsai\nRpL18A\tCG10576\nRpL18A\tCG5642\nRpL18A\teIF3-S8\nRpL18A\teIF3-S10\nRpL18A\tSrp72\nRpL18A\teIF3-S9\nRpL18A\tTctp\nRpL18A\tSrp19\nRpL18A\tCG9769\nRpL18A\tSrp54k\nRpL18A\tTrip1\nRpL18A\tRpS15Aa\nRpL18A\tRpS14a\nRpL18A\tsta\nRpL18A\tRpL10Ab\nRpL18A\tRpS2\nRpL18A\tRpL3\nRpL18A\tRpS17\nRpL18A\tRpL4\nRpL18A\tRpL13\nRpL18A\tRpS4\nRpL18A\tRpL11\nRpL18A\tRpS10a\nRpL18A\tRpS6\nRpL18A\tRpL12\nRpL18A\tRpS18\nRpL18A\tRpS16\nRpL18A\tRpS12\nRpL18A\tRpS27\nRpL18A\tRpS10b\nRpL18A\tRpS3\nRpL18A\tRpS13\nRpS4\tTcp-1zeta\nRpS4\tCG7033\nRpS4\tmago\nRpS4\tbonsai\nRpS4\tRpS15Aa\nRpS4\tRpL12\nRpS4\tsta\nRpS4\tRpS10b\nRpS4\tRpS14a\nRpS4\tRpS16\nRpS4\tRpS6\nRpS4\tRpS12\nRpL4\tvig\nRpL4\tbonsai\nRpL4\tCctgamma\nRpL4\tmRpS10\nRpL4\tTcp-1eta\nRpL4\tTctp\nRpL4\tT-cp1\nRpL4\tCG7033\nRpL4\tTcp-1zeta\nRpL4\tade3\nRpL4\tmRpS9\nRpL4\tmRpL12\nRpL4\tSrp72\nRpL4\tmago\nRpL4\tSrp19\nRpL4\tCG5642\nRpL4\tCG10576\nRpL4\tSrp54k\nRpL4\tCG9769\nRpL4\teIF3-S10\nRpL4\tRpS15Aa\nRpL4\tRpS10a\nRpL4\tRpL10Ab\nRpL4\tTrip1\nRpL4\tRpS16\nRpL4\tRpS6\nRpL4\tRpS12\nRpL4\tRpS14a\nRpL4\tRpS2\nRpL4\tRpL12\nRpL4\tRpS27\nRpL4\tsta\nRpL4\tRpS13\nRpL4\tRpS10b\nRpL4\tRpS3\nRpL4\tRpS17\nRpL4\tRpL13\nRpL4\tRpL3\nRpL4\tRpS4", - }, - { - kind: 'annotation', - name: 'Tau Louvain communities', - fileName: 'TAU_Louvain.txt', - text: "Group-1\tMgstl,KP78a,CG9257,par-1,CG31064,LpR1,Rab39,LpR2,CG3529,Lam,LamC,Sap-r,Vps60,lqf,ninaC,Hrs,Arr2,Arr1,Rab5,CG32683,pins,chp\nGroup-2\tSc2,Uch,Prx2540-1,Ace,CG4572,Sgt,CG14715,CG10359,Ect3,CalpB,Prx5,Ost48,Hsp60C,Prx2540-2,Hsp60,Ubqn,Hsp70Ab,Ugt,Iswi,Trap1,Cat,Hsc70-5,CG8209,DnaJ-H,p47,Rad23,Cnx99A,pont,Cp1,cathD,Uba2,Pfk,Gdi,Uch-L5,Rpt4R,Prosalpha1,mor,Bap55,Ufd1-like,TER94,Hsc70-3,PyK,Hsp83,ERp60,arm,Rpt1,Rpn13,Rpt2,Rpn5,Rpt6R,Rpn2,Pdi,CaBP1,Gp93,Rpt4,Hop,CG1416,Prosalpha6,Rpt5,Prosalpha7,Rpn6,CG8258,Rpt6,Rpn3,Rpn12,Prosbeta7,Usp5,CG2918,CG2852,CG1354,CG6891,HDAC6,Hsp27,His1,CG11577\nGroup-3\tshep,CG5590,CG17597,ScpX,Mfe2\nGroup-4\tCG4882,EfTuM,Rbp2,eEF1delta,CG10576,Nacalpha,mRpS34,vig,CG4679,mRpS35,mRpS7,mRpL44,mRpS22,eIF4G,bonsai,mRpS10,Srp54k,mRpL12,Tctp,eIF-2gamma,mRpS23,mRpS18B,ade3,mRpS9,mRpS5,Srp19,Srp72,eIF-3p66,Cctgamma,Ef1beta,Tango7,RpL10Ab,Trip1,eIF3-S10,eIF3-S9,Tcp-1eta,RpL13,RpS11,eIF3-S8,RpS6,RpS2,RpL12,RpS7,RpL10,RpS8,RpL30,RpS10a,RpS17,RpLP0,eRF1,Elf,RpS15Aa,RpS27,RpS18,RpS10b,RpS3A,RpS16,RpS15Ab,RpL3,Tcp-1zeta,T-cp1,RpS3,RpL26,RpS12,CG5642,CG9769,CG7033,Cct5,RpLP2,RpS23,RpS14a,Rack1,RpL11,RpS13,RpL18A,RpS4,RpL4,sta,wuho,bsf,kra,Hsp67Bc,su(r),FeCH,CG8635\nGroup-5\tnito,bol,Kap-alpha3,CG2082,lig,clu,Dbp80,Plc21C,Hrb27C,bel,Dp1,Lpin,Pkc53E,Nlp,rin,poe,CG43367,emb,fne,RanBPM,yps,Art4,CG10077,mub,AGO1,glo,Srp54,Rbp9,Rae1,Mtor,Ref1,mago,B52,LS2,U2af50,Fmr1,Top2,heph,Hrb98DE,Tudor-SN,SF2,me31B,CG16941,Prp8,Tango4,U2A,smt3,pAbp,Not1,Not3,CG2091,Capr,Gbeta76C,CG10777,CG6617,CG3800,tyf,CG11505\nGroup-6\tCG6178,frj,CG9090,Ssadh,l(1)G0156,CG32026,Men-b,CG11899,CG16935,AGBE,ImpL3,Nc73EF,CG3902,CG11876,Pdk,Vha100-1,AcCoAS,ACC,Mdh2,Cyt-c-p,Aldh,CG15093,ND-51L1,ND-51,Vha68-2,Vha100-2,ND-15,CG12262,yip2,ade5,CG11089,COX6B,CG11752,COX4,COX5A,Eno,Tpi,ND-PDSW,NP15.6,ATPsynbeta,ATPsynCF6,CG10932,CG33791,CG3011,Men,sun,porin,ND-B16.6,CG7603,Mpcp\nGroup-7\tNdg,trol,Cg25C,vkg,LanA,LanB2,Glt\nGroup-8\tLar,CG31715,PlexA,gammaSnap2,CG10186,Klp10A,Mtl,bai,Act79B,Abl,Tim17b,p115,Sec24AB,robl,tsr,flr,FKBP59,bic,BicD,CadN,syd,Rac1,zip,alphaCOP,zetaCOP,CG7048,CG7770,Dlic,Dhc64C,betaCOP,cpa,cpb,epsilonCOP,beta'COP,Klc,Khc,alpha-Cat,deltaCOP,RhoGDI,Dscam1,Tim9a,sqh,dock,Dscam2,CG8498,CLIP-190,betaTub56D\nGroup-9\tMapmodulin,Aats-val,Aats-his,Aats-asp,CG33123,Aats-ile,Aats-arg,CG31739\n", - }, - { - kind: 'annotation', - name: 'Tau KEGG pathways', - fileName: 'TAU_KEGG_Annotation_NORMA.txt', - text: 'Ribosome\tRpL10,RpL10Ab,RpL11,RpL12,RpL13,RpL18A,RpL26,RpL3,RpL30,RpL4,RpLP0,RpLP2,RpS10a,RpS10b,RpS11,RpS12,RpS13,RpS15Aa,RpS15Ab,RpS16,RpS17,RpS18,RpS2,RpS23,RpS27,RpS3,RpS3A,RpS4,RpS6,RpS7,RpS8,bonsai,mRpL12,mRpS10,mRpS7,mRpS9,sta\nProteasome\tProsalpha6,Prosalpha7,Prosbeta7,Rpn12,Rpn13,Rpn2,Rpn3,Rpn5,Rpn6,Rpt1,Rpt2,Rpt4,Rpt4R,Rpt5,Rpt6,Rpt6R\nSpliceosome\tB52,CG10077,CG10777,CG16941,Hrb98DE,LS2,Prp8,Ref1,SF2,Tango4,U2A,U2af50,mago\nPhagosome\tAct79B,Cnx99A,Cp1,Dhc64C,Dlic,Hrs,Mtl,Rab5,Rac1,Vha100-1,Vha100-2,Vha68-2,betaTub56D\nCarbon metabolism\tAcCoAS,CG10932,CG11876,CG11899,CG12262,CG3011,CG32026,CG33791,Cat,Eno,Mdh2,Men,Men-b,Nc73EF,Pfk,PyK,Tpi,l(1)G0156\nOxidative phosphorylation\tATPsynCF6,ATPsynbeta,COX4,COX5A,COX6B,ND-15,ND-51,ND-51L1,ND-B16.6,ND-PDSW,NP15.6,Vha100-1,Vha100-2,Vha68-2,sun\nRNA degradation\tCG2091,Eno,Hsc70-5,Hsp60,Hsp60C,Not1,Not3,Pfk,me31B,pAbp\nRNA transport\tCG9769,Fmr1,Mtor,Rae1,Ref1,Trip1,eIF-3p66,eIF3-S10,eIF3-S8,eIF3-S9,eIF4G,emb,mago,pAbp,smt3\nGlycolysis\tAcCoAS,Aldh,CG11876,Eno,ImpL3,Pfk,PyK,Tpi\nPyruvate metabolism\tACC,AcCoAS,Aldh,CG10932,CG11876,ImpL3,Mdh2,Men,Men-b,PyK\n', - }, - { - kind: 'colors', - name: 'Tau expression', - fileName: 'TAU_expressions.txt', - text: "CG7603\tred\nHis1\tred\nAct79B\tred\nGbeta76C\tred\nCG11876\tred\nKap-alpha3\tred\nCG2082\tred\nLanA\tred\nVha68-2\tred\nCalpB\tred\nSsadh\tred\nCG43367\tred\nl(1)G0156\tred\nCG9090\tred\nPrx5\tred\nCG1354\tred\nporin\tred\nGstD9\tred\nCG32026\tred\nAldh\tred\nGlt\tred\nTpi\tred\nPyK\tred\nATPsynbeta\tred\nEno\tred\nMtl\tred\nArr1\tred\nMpcp\tred\nArr2\tred\nNdg\tred\nFeCH\tred\nNc73EF\tred\nCG10932\tred\nCG33791\tred\nbetaTub56D\tred\nCyt-c-p\tred\nCG16935\tred\nPrx2540-2\tred\nGstE4\tred\npins\tred\nchp\tred\nMen-b\tred\nGstD3\tred\nHDAC6\tred\nCG10359\tred\nmago\tred\nLamC\tred\nAce\tred\nMdh2\tred\nninaC\tred\nLanB2\tred\nCg25C\tred\nsun\tred\nvkg\tred\nPfk\tred\nPrx2540-1\tred\nEfTuM\tred\nVha100-1\tred\nVha100-2\tred\nAGBE\tred\nfrj\tred\nDnaJ-H\tred\ntrol\tred\nMen\tgreen\np47\tgreen\nmRpS10\tgreen\nNP15.6\tgreen\nRpS15Ab\tgreen\nNot3\tgreen\nTim17b\tgreen\neIF4G\tgreen\ncathD\tgreen\nCG12262\tgreen\nProsalpha7\tgreen\nUsp5\tgreen\nyip2\tgreen\nDscam1\tgreen\nCG2918\tgreen\ncpa\tgreen\nRpS4\tgreen\nade3\tgreen\nCG8209\tgreen\nCG11505\tgreen\nFKBP59\tgreen\nRpS11\tgreen\nRab39\tgreen\nRpL13\tgreen\nCG1371\tgreen\nPrp8\tgreen\nProsalpha6\tgreen\nRpn12\tgreen\nRpn2\tgreen\nRpn5\tgreen\nNacalpha\tgreen\nHsp60\tgreen\nTudor-SN\tgreen\nRpt5\tgreen\nRpt4\tgreen\nlqf\tgreen\nRpt1\tgreen\nTop2\tgreen\nRpn6\tgreen\nND-PDSW\tgreen\nsta\tgreen\nsqh\tgreen\nCG6178\tgreen\nCG32683\tgreen\nAats-asp\tgreen\nLpR2\tgreen\neIF-2gamma\tgreen\nRpL11\tgreen\nElf\tgreen\nERp60\tgreen\nSec24AB\tgreen\nCG11089\tgreen\nRae1\tgreen\nCG3011\tgreen\nAbl\tgreen\nRpt6R\tgreen\nUch\tgreen\nTrap1\tgreen\nCG7048\tgreen\nRpt6\tgreen\nCG10186\tgreen\nwuho\tgreen\nAats-arg\tgreen\nLam\tgreen\nHsp60C\tgreen\nTrip1\tgreen\nRpS3\tgreen\nTctp\tgreen\nCG31064\tgreen\nDscam2\tgreen\nemb\tgreen\nUba2\tgreen\npAbp\tgreen\nCapr\tgreen\nCG4972\tgreen\nAats-his\tgreen\nAats-ile\tgreen\nPlexA\tgreen\nCctgamma\tgreen\nRab5\tgreen\nzip\tgreen\nMi-2\tgreen\nAcCoAS\tgreen\nsu(r)\tgreen\nmRpS23\tgreen\narm\tgreen\nCG10077\tgreen\nRef1\tgreen\nRpS7\tgreen\nCG10777\tgreen\nAats-val\tgreen\nImpL3\tgreen\nPdi\tgreen\nSgt\tgreen\nbeta'COP\tgreen\nalphaCOP\tgreen\nFmr1\tgreen\nCG31715\tgreen\nmRpS7\tgreen\nEf1beta\tgreen\nND-B16.6\tgreen\nScpX\tgreen\nCat\tgreen\nlig\tgreen\nCG10576\tgreen\np115\tgreen\nade5\tgreen\nBap55\tgreen\nHsp83\tgreen\nRpL4\tgreen\nProsbeta7\tgreen\nRpLP2\tgreen\nCG4572\tgreen\nCG31739\tgreen\nTim9a\tgreen\npont\tgreen\nHsc70-5\tgreen\nHsp27\tgreen\nbic\tgreen\nHsp67Bc\tgreen\nKP78a\tgreen\nCG3529\tgreen\nBicD\tgreen\nRpS12\tgreen\nbsf\tgreen\nHsc70-3\tgreen\nHrb98DE\tgreen\nRpS8\tgreen\nCG8498\tgreen\nDp1\tgreen\nOst48\tgreen\nSrp54k\tgreen\nRad23\tgreen\nTango4\tgreen\nkra\tgreen\nHsp70Ab\tgreen\nRpS15Aa\tgreen\ntyf\tgreen\nLpin\tgreen\nCnx99A\tgreen\nmRpS18B\tgreen\neEF1delta\tgreen\nCG3800\tgreen\nRpL18A\tgreen\npar-1\tgreen\nme31B\tgreen\nCOX4\tgreen\neIF3-S10\tgreen\nCG11752\tgreen\nCG14715\tgreen\nMtor\tgreen\nU2af50\tgreen\nmRpS5\tgreen\nKhc\tgreen\nCct5\tgreen\nRpL12\tgreen\nyps\tgreen\nB52\tgreen\nCG1416\tgreen\nbonsai\tgreen\nTER94\tgreen\nLar\tgreen\nalpha-Cat\tgreen\nglo\tgreen\nCadN\tgreen\nCG7033\tgreen\nCG2091\tgreen\nRpS17\tgreen\nArt4\tgreen\nsyd\tgreen\nRpL3\tgreen\nTcp-1eta\tgreen\nCG4679\tgreen\nSrp54\tgreen\nmRpS34\tgreen\nvig\tgreen\nSrp72\tgreen\nND-15\tgreen\nMapmodulin\tgreen\nRack1\tgreen\nCp1\tgreen\nDlic\tgreen\nRpS18\tgreen\nfne\tgreen\nRpS14a\tgreen\neIF3-S8\tgreen\nCG5642\tgreen\nRpLP0\tgreen\ngammaSnap2\tgreen\nrobl\tgreen\nRpS16\tgreen\nUgt\tgreen\nHrs\tgreen\nKlc\tgreen\neIF-3p66\tgreen\nND-51L1\tgreen\nbetaCOP\tgreen\nzetaCOP\tgreen\nUbqn\tgreen\nrin\tgreen\neRF1\tgreen\nLS2\tgreen\nDbp80\tgreen\nUfd1-like\tgreen\neIF3-S9\tgreen\nND-51\tgreen\nCOX6B\tgreen\nmRpS9\tgreen\nCG33123\tgreen\nCG9769\tgreen\nbel\tgreen\nSap-r\tgreen\ndeltaCOP\tgreen\nRbp9\tgreen\nRpS13\tgreen\nCG9257\tgreen\nmRpL12\tgreen\nMfe2\tgreen\nCaBP1\tgreen\nAGO1\tgreen\nMgstl\tgreen\nCG17597\tgreen\nCG6617\tgreen\nmub\tgreen\nATPsynCF6\tgreen\nRbp2\tgreen\nUch-L5\tgreen\ndock\tgreen\nLpR1\tgreen\nCG6891\tgreen\nRpL10\tgreen\nheph\tgreen\nHop\tgreen\nRpL10Ab\tgreen\nCOX5A\tgreen\nRpL30\tgreen\nmRpS22\tgreen\nTcp-1zeta\tgreen\nNlp\tgreen\nRpt4R\tgreen\nEct3\tgreen\npoe\tgreen\nVps60\tgreen\ntsr\tgreen\nRanBPM\tgreen\nPlc21C\tgreen\nmor\tgreen\nepsilonCOP\tgreen\nRpt2\tgreen\nACC\tgreen\nRpn3\tgreen\nbol\tgreen\nRpS10a\tgreen\nCG4882\tgreen\nCG8258\tgreen\nbai\tgreen\nshep\tgreen\nSrp19\tgreen\nCG2852\tgreen\nCG11899\tgreen\nclu\tgreen\nIswi\tgreen\nDhc64C\tgreen\nRpS6\tgreen\nRpS10b\tgreen\nCG5590\tgreen\nKlp10A\tgreen\nGdi\tgreen\nRpS2\tgreen\nRpS27\tgreen\nNot1\tgreen\nflr\tgreen\nPkc53E\tgreen\nCG11577\tgreen\nCG15093\tgreen\nCLIP-190\tgreen\nsmt3\tgreen\nRac1\tgreen\ncpb\tgreen\nCG16941\tgreen\nRhoGDI\tgreen\nProsalpha1\tgreen\nmRpL44\tgreen\nGp93\tgreen\nPdk\tgreen\nRpS23\tgreen\nT-cp1\tgreen\nRpL26\tgreen\nCG3902\tgreen\nCG7770\tgreen\nmRpS35\tgreen\nCG8635\tgreen\nRpS3A\tgreen\nTango7\tgreen\nHrb27C\tgreen\nnito\tgreen\nSc2\tgreen\nU2A\tgreen\nRpn13\tgreen\nSF2\tgreen\n", - }, - ], - }, - coexpr: { - title: 'Human gene co-expression', - source: 'PMID 19081792, PMCID PMC2597745', - link: 'https://doi.org/10.1371/journal.pone.0003911', - files: [ - { - kind: 'network', - name: 'Human co-expression', - fileName: 'NORMA_Human_coexpression_NETWORK.txt', - text: 'Source\tTarget\nRPL24\tRPL41\nRPL24\tRPL26\nRPL24\tRPL30\nRPL24\tTPT1\nRPL24\tRPL9\nRPL24\tRPS25\nRPL24\tRPS23\nRPL24\tRPL31\nRPL24\tRPS27A\nRPL24\tU16\nRPL24\tRPS4X\nRPL24\tRPL7\nRPL24\tRPL4\nRPL24\tRPL5\nRPL24\tRPS3A\nRPL24\tRPS7\nRPL24\tRPL34\nRPL24\tRPL35A\nRPL24\tRPS24\nRPL24\tRPL6\nRPL41\tRPL5\nRPL41\tRPS3A\nRPL41\tTPT1\nRPL41\tRPS23\nRPL41\tRPS4X\nHNRPA1\tRPS25\nHNRPA1\tRPS24\nHNRPA1\tRPS4X\nHNRPA1\tRPS6\nHNRPA1\tRPL22\nHNRPA1\tNCL\nHNRPA1\tRPL24\nHNRPA1\tNPM1\nHNRPA1\tRPL4\nHNRPA1\tMDS1\nHNRPA1\tU16\nHNRPA1\tRPS23\nHNRPA1\tRPS7\nHNRPA1\tSF3B1\nHNRPA1\tNAP1L1\nHNRPA1\tRPL17\nHNRPA1\tRPL11\nHNRPA1\tRPL6\nHNRPA1\tRPL34\nHNRPA1\tLOC440055\nHNRPA1\tRPS3A\nHNRPA1\tRPL7\nRPS25\tRPS4X\nRPS25\tRPS3A\nRPS25\tRPS6\nRPS25\tU16\nRPS25\tRPS7\nRPS25\tRPS27A\nH3F3A\tRPA1\nH3F3A\tRAP1B\nH3F3A\tRPLP2\nH3F3A\tRPS20\nH3F3A\tRPL27\nH3F3A\tRPS11\nH3F3A\tRPL27A\nCOX8A\tCYC1\nCOX8A\tNDUFS8\nCOX8A\tSLC25A11\nCOX8A\tSLC25A3\nCOX8A\tNDUFAB1\nCOX8A\tNDUFB11\nCOX8A\tMRPS12\nCYC1\tETFB\nCYC1\tUQCRC1\nATP8B1\tPDE4C\nATP8B1\tFLJ42393\nATP8B1\tDKFZP566N034\nATP8B1\tCEP27\nATP8B1\tKNS2\nATP8B1\tRIOK3\nATP8B1\tDBT\nATP8B1\tPGF\nATP8B1\tZNF611\nATP8B1\tSLC35E1\nATP8B1\tLOC152719\nATP8B1\tFBXW12\nATP8B1\tZNF160\nPDE4C\tSPG21\nPDE4C\tUBE2D2\nPDE4C\tPRKAR2A\nPDE4C\tZNF611\nPDE4C\tPRR11\nPDE4C\tPGF\nPDE4C\tZNF160\nPDE4C\tRIOK3\nPDE4C\tSLC35E1\nLOC58486\tSUB1\nLOC58486\tMGEA5\nLOC58486\tRNPC2\nLOC58486\tPFAAP5\nLOC58486\tWAC\nLOC58486\tMATR3\nLOC58486\tPNRC2\nLOC58486\tPAPOLA\nLOC58486\tZNF638\nLOC58486\tSF3B1\nLOC58486\tUSP34\nLOC402057\tRPS7\nLOC402057\tRPS15A\nLOC402057\tRPL34\nLOC402057\tRPS4X\nLOC402057\tRPS6\nLOC402057\tRPL31\nLOC402057\tRPL35A\nLOC402057\tRPL37\nLOC402057\tRPL22\nLOC402057\tRPL4\nLOC402057\tRPL9\nLOC402057\tRPS23\nLOC402057\tRPL11\nLOC402057\tLOC440055\nLOC402057\tRPL30\nLOC402057\tRPL23\nLOC402057\tRPL36A\nLOC402057\tRPL39\nLOC402057\tMDS1\nLOC402057\tRPL32\nLOC402057\tRPS17\nRPS7\tSFRS5\nRPS7\tSF3B1\nRPS7\tU16\nMDS1\tRPL23\nMDS1\tRNPC2\nMDS1\tRPL17\nMDS1\tRPL5\nMDS1\tRPS3A\nMDS1\tRPL41\nMDS1\tRPL4\nMDS1\tTPT1\nMDS1\tNPM1\nMDS1\tRPS6\nMDS1\tRPL7\nMDS1\tRPL24\nMDS1\tRPL34\nMDS1\tRPL26\nMDS1\tRPL22\nMDS1\tRPS27A\nMDS1\tRPL6\nMDS1\tRPS25\nMDS1\tRPS15A\nMDS1\tU16\nMDS1\tRPS7\nMDS1\tRPS24\nMDS1\tRPL36A\nMDS1\tRPS4X\nMDS1\tRPL21\nMDS1\tRPL31\nMDS1\tRPL35A\nMDS1\tRPL30\nMDS1\tRPS17\nMDS1\tRPL9\nMDS1\tRPL11\nMDS1\tRPS23\nRPL23\tRPL7\nRPL23\tRPL26\nRPL23\tRPL5\nRPL23\tRPL24\nRPL23\tRPS27\nRPL23\tRPS15A\nRPL23\tRPS27A\nRPL23\tRPL6\nRPL23\tRPL36A\nRPL23\tU16\nRPL23\tRPS25\nRPL23\tRPS17\nRPL23\tRPS4X\nRPL23\tRPS7\nRPL23\tRPS3A\nRPL23\tRPS23\nRPL23\tRPL30\nRPL23\tRPS24\nRPL23\tRPL9\nRPL23\tRPL31\nRPL23\tRPS6\nRPL23\tRPL35A\nRPL23\tRPL4\nRPL23\tRPL34\nRPL5\tRPS6\nRPL5\tRPS23\nRPL5\tTPT1\nRPL5\tRPS25\nRPL5\tRPS3A\nRPL5\tRPS4X\nRPL5\tRPL9\nRPL5\tRPS27A\nRPL5\tRPL7\nRPL5\tRPS7\nRPL5\tU16\nRPL5\tRPS24\nRPL5\tRPL6\nATP5G3\tCOX8A\nATP5G3\tNDUFB11\nATP5G3\tSLC25A3\nATP5G3\tUQCRC1\nATP5G3\tUQCRQ\nATP5G3\tCOX5A\nATP5G3\tCOX4I1\nATP5G3\tNDUFAB1\nATP5G3\tUQCRFS1\nATP5G3\tCOX5B\nATP5G3\tMDH2\nCOPB\tTRAM1\nCOPB\tLOC58486\nCOPB\tRNPC2\nCOPB\tHSP90B1\nCOPB\tYME1L1\nCOPB\tPAPOLA\nPRKACB\tSEPT7\nSEPT7\tSH3BGRL\nSEPT7\tZFR\nUBE2D2\tZNF160\nRNPC2\tTAF7\nRNPC2\tTCEA1\nRNPC2\tZNF638\nRNPC2\tRPS3A\nRNPC2\tSF3B1\nRNPC2\tRPL5\nRNPC2\tRPL6\nRNPC2\tRPL17\nRNPC2\tSRP72\nIGHM\tIGKC\nIGHM\tIGLC2\nIGHM\tIGKV1-5\nIGHM\tLOC91316\nIGHM\tIGLV3-10\nIGHM\tIGL@\nIGHM\tIGHV1-69\nIGHM\tIGKV1D-13\nIGHM\tIGLV3-25\nIGHM\tIGLC1\nIGHM\tIGKV1OR2-108\nIGKC\tIGLJ3\nIGKC\tIGLC2\nIGKC\tIGKV1D-13\nIGKC\tIGLV3-25\nIGKC\tIGKV1OR2-108\nIGKC\tIGKV1-5\nIGKC\tIGLV3-10\nIGKC\tIGL@\nIGKC\tLOC91316\nIGKC\tIGLC1\nIGKC\tIGKV1OR15-118\nLOC342346\tYTHDC1\nLOC342346\tXPO1\nLOC342346\tSON\nLOC342346\tTAF7\nLOC342346\tPAPOLA\nLOC342346\tSH3BGRL\nEEF1A1\tRPL17\nEEF1A1\tMDS1\nEEF1A1\tRPS24\nEEF1A1\tRPS3A\nEEF1A1\tRPL22\nEEF1A1\tNPM1\nEEF1A1\tRPL11\nEEF1A1\tRPS7\nEEF1A1\tRPS27A\nEEF1A1\tTPT1\nEEF1A1\tRPS6\nEEF1A1\tRPL7\nEEF1A1\tRPS4X\nEEF1A1\tRPL23\nRPL17\tSFRS5\nRPL17\tRPS25\nRPL17\tRPL9\nRPL17\tTPT1\nRPL17\tRPL30\nRPL17\tRPL26\nRPL17\tRPL7\nRPL17\tRPL36A\nRPL17\tRPL22\nRPL17\tRPS6\nRPL17\tSF3B1\nRPL17\tRPS4X\nRPL17\tTINP1\nRPL17\tRPL35A\nRPL17\tRPS23\nRPL17\tU16\nRPL17\tRPS3A\nRPL17\tRPL24\nRPL17\tRPS7\nRPL17\tRPL23\nRPL17\tRPL31\nRPL17\tRPS27A\nRPL17\tRPL21\nRPL17\tRPL4\nRPL17\tRPL5\nRPL17\tRPL34\nRPL17\tRPL6\nRPL17\tRPS24\nRPL13A\tRPS9\nRPL13A\tRPS18\nRPL13A\tRPL18A\nRPL13A\tRPL27A\nRPL13A\tRPL14\nRPL13A\tRPS16\nRPL13A\tRPS14\nRPL13A\tRPL15\nRPL13A\tRPLP2\nRPL13A\tRPS21\nRPL13A\tRPL29\nRPL13A\tRPS19\nRPL13A\tRPL36\nRPL13A\tRPS5\nNDUFAB1\tNDUFB4\nNDUFAB1\tNDUFS3\nNDUFAB1\tUQCRC1\nNDUFAB1\tNDUFV1\nNDUFAB1\tUQCR\nNDUFAB1\tNDUFB2\nNDUFAB1\tUQCRQ\nNDUFAB1\tNDUFS7\nNDUFAB1\tNDUFB11\nNDUFAB1\tNDUFC1\nNDUFAB1\tPOLR2I\nNDUFAB1\tNDUFS8\nNDUFAB1\tUQCRFS1\nNDUFB4\tNDUFS3\nNDUFB4\tNDUFS8\nNDUFB4\tUQCRFS1\nNDUFB4\tUCRC\nAKR7A2\tCLPP\nAKR7A2\tTIMM13\nAKR7A2\tNDUFV1\nAKR7A2\tMRPL34\nAKR7A2\tC21orf33\nAKR7A2\tNDUFS8\nCLPP\tTUFM\nCLPP\tMRPL34\nhfl-B5\tHNRPA2B1\nhfl-B5\tHIATL1\nhfl-B5\tHNRPH1\nhfl-B5\tHNRPA1\nHNRPA2B1\tXPO1\nHNRPA2B1\tSRP46\nSET\tSFRS3\nSET\tSRP46\nSET\tSON\nSET\tSFRS10\nHLA-C\tISG20\nHLA-C\tMAN2B1\nHLA-C\tHLA-G\nHLA-C\tHLA-F\nHLA-C\tHLA-E\nHLA-C\tTAPBP\nHLA-C\tHLA-J\nISG20\tRAC2\nISG20\tPSMB9\nISG20\tUCP2\nRPS24\tTPT1\nRPS24\tTCEA1\nRPS24\tSF3B1\nRPS24\tRPS25\nRPS24\tRPS3A\nRPS24\tRPS6\nRPS24\tRPS4X\nRPS24\tU16\nRPS24\tRPS27A\nRPS24\tRPS7\nDDX1\tKTN1\nKTN1\tUSP47\nRPS4X\tU16\nRPS4X\tTPT1\nRPS4X\tRPS7\nRPS4X\tRPS6\nCCNL1\tRPL4\nCCNL1\tZNF638\nCCNL1\tNACA\nCCNL1\tRPL5\nCCNL1\tRPS27A\nCCNL1\tRPL17\nCCNL1\tRNPC2\nCCNL1\tRPL21\nCCNL1\tRPL6\nCCNL1\tEIF3S6\nRPL4\tTPT1\nRPL4\tRPL7\nRPL4\tSFRS5\nRPL4\tRPS15A\nRPL4\tRPL5\nRPL4\tRPS17\nRPL4\tRPS25\nRPL4\tRPL9\nRPL4\tRPS7\nRPL4\tRPS27A\nRPL4\tRPL6\nRPL4\tRPS23\nRPL4\tRPS4X\nRPL4\tRPS3A\nRPL4\tRPS24\nRPL4\tU16\nRPL4\tRPS6\nFLJ11021\tNAP1L1\nFLJ11021\tZNF403\nFLJ11021\tHIATL1\nFLJ11021\tKIAA0907\nFLJ11021\tWAC\nFLJ11021\tTUG1\nFLJ11021\tPAPOLA\nFLJ11021\tRNPC2\nFLJ11021\tXPO1\nFLJ11021\tLOC58486\nFLJ11021\tNPM1\nNAP1L1\tRPL17\nNAP1L1\tYTHDC1\nNAP1L1\tPAPOLA\nNAP1L1\tZNF9\nNAP1L1\tXPO1\nC21orf33\tETFB\nC21orf33\tCOX5B\nC21orf33\tNDUFS7\nC21orf33\tNDUFS8\nETFB\tNDUFS8\nETFB\tUQCRQ\nCOX5A\tNDUFS8\nCOX5A\tNDUFB11\nCOX5A\tNDUFS7\nCOX5A\tMDH2\nCOX5A\tCOX5B\nCOX5A\tNDUFAB1\nCOX5A\tUQCRFS1\nCOX5A\tUQCRC1\nNDUFS8\tSLC25A3\nNDUFS8\tPOLR2I\nNDUFS8\tPOLR2L\nNDUFS8\tTIMM13\nNDUFS8\tUQCRFS1\nNDUFS8\tTMEM93\nNDUFS8\tUQCRQ\nCROP\tIL6ST\nCROP\tZNF638\nCROP\tHNRPA3P1\nCROP\tRNPC2\nCROP\tMATR3\nCROP\tSFRS5\nCROP\tXPO1\nCROP\tSFPQ\nCROP\tLOC58486\nCROP\tHNRPDL\nCROP\tTUG1\nCROP\tSFRS11\nCROP\tZC3H11A\nCROP\tPFAAP5\nCROP\tNPM1\nCROP\tFLJ10154\nCROP\tGOLGA8A\nIL6ST\tSFRS11\nPOLR2E\tSIAHBP1\nRPL26\tRPS3A\nRPL26\tRPL4\nRPL26\tRPL7\nRPL26\tRPS7\nRPL26\tRPS6\nRPL26\tRPS27A\nRPL26\tRPL34\nRPL26\tRPS24\nRPL26\tRPS25\nRPL26\tRPL5\nRPL26\tRPL6\n216858_x_at\tCEP27\n216858_x_at\tZNF611\n216858_x_at\tFLJ14346\n216858_x_at\tLOC152719\nCEP27\tPRR11\nCEP27\tPGF\nCEP27\tPRKAR2A\nCEP27\tLOC152719\nCEP27\tPDE4C\nCEP27\tRIOK3\nCEP27\tZNF611\nCEP27\tKNS2\nCEP27\tFBXW12\nCEP27\tDBT\nCEP27\tZNF160\nCEP27\tSLC35E1\nCEP27\tFLJ12151\nRPL6\tRPL9\nRPL6\tSFRS5\nRPL6\tTPT1\nRPL6\tRPL7\nRPL6\tRPS23\nRPL6\tSF3B1\nRPL6\tRPS4X\nRPL6\tRPS25\nRPL6\tRPS3A\nRPL6\tRPS6\nRPL6\tU16\nRPL6\tRPS7\nRPL6\tRPS27A\nRPL6\tRPS24\nRPL9\tRPS27A\nRPL9\tRPS24\nRPL9\tU16\nRPL9\tRPS25\nRPL9\tRPS4X\nRPL9\tRPS23\nRPL9\tRPS7\nRPL9\tRPS3A\nRPL9\tRPS17\nRPL9\tRPS6\nRPL9\tRPS27\nRPL9\tRPS15A\nDDX3X\tXPO1\nDDX3X\tNAP1L1\nDDX3X\tPAPOLA\nDDX3X\tSON\nDDX3X\tHNRPR\nDDX3X\tTHRAP1\nDDX3X\tSH3BGRL\nDDX3X\tHNRPH1\nDDX3X\tMGEA5\nDDX3X\tHIATL1\nDDX3X\tDDX5\nDDX3X\tLOC342346\nDDX3X\tEIF4G2\nDDX3X\tSF3B1\nDDX3X\tYTHDC1\nCOPE\tSCAND1\nCOPE\tMRPS12\nCOPE\tNAPA\nCOPE\tFIBP\nSCAND1\tTHRAP5\nCOPS2\tRPL15\nCOPS2\tHSP90B1\nCOPS2\tHNRPH3\nCOPS2\tZNF638\nCOPS2\tKIDINS220\nCOPS2\tVDP\nCOPS2\tTLOC1\nCOPS2\tCSDE1\nRPL15\tRPL35\nRPL15\tRPS16\nITGB2\tRAC2\nITGB2\tRGS19\nRAC2\tTRA@\nRAC2\tTRB@\nDBT\tPRR11\nDBT\tDIP2A\nDBT\tFLJ42393\nDBT\tZNF611\nDBT\tFLJ12151\nDBT\tPGF\nDBT\tLOC152719\nDBT\tRIOK3\nDBT\tPDE4C\nDBT\tWDR45\nDBT\tZNF160\nDBT\tFBXW12\nDBT\tKNS2\nDBT\tSLC35E1\nPRR11\tZNF611\nPRR11\tSLC35E1\nPRR11\tZNF160\n207730_x_at\t216858_x_at\n207730_x_at\tUBE2D2\n207730_x_at\tFLJ42393\n207730_x_at\t208246_x_at\n207730_x_at\tPRKAR2A\n207730_x_at\t217679_x_at\n207730_x_at\tPDE4C\n207730_x_at\tPRR11\n207730_x_at\tPGF\n207730_x_at\tRIOK3\n207730_x_at\t208238_x_at\n207730_x_at\tKNS2\n207730_x_at\t216524_x_at\n207730_x_at\tATP8B1\n207730_x_at\tFLJ12151\n207730_x_at\tLOC152719\n207730_x_at\tDBT\n207730_x_at\tZNF611\n207730_x_at\tSLC35E1\n207730_x_at\tZNF160\n207730_x_at\tCEP27\n207730_x_at\tFBXW12\nEEF1D\tRPS9\nEEF1D\tGLTSCR2\nEEF1D\tRPL38\nPRDX2\tRIOK3\nRIOK3\tZNF611\nRIOK3\tZNF160\nRIOK3\tSLC35E1\nRPS23\tRPS27A\nRPS23\tU16\nRPS23\tRPS7\nRPS23\tRPS24\nRPS23\tRPS25\nRPS23\tRPS6\nRPS23\tRPS4X\nRPS23\tRPS3A\nRPS27A\tSFRS5\nRPS27A\tRPS4X\nRPS27A\tU16\nRPS27A\tTINP1\nRPS27A\tRPS3A\nRPS27A\tRPS7\nRPS27A\tRPS6\nRPL34\tTPT1\nRPL34\tSF3B1\nRPL34\tRPL7\nRPL34\tRPS25\nRPL34\tRPL36A\nRPL34\tRPL5\nRPL34\tRPS27A\nRPL34\tRPS4X\nRPL34\tRPS3A\nRPL34\tRPS6\nRPL34\tRPS7\nRPL34\tRPL4\nRPL34\tRPL9\nRPL34\tRPS23\nRPL34\tRPL6\nRPL34\tRPL35A\nRPL34\tRPS24\nHNRPDL\tMATR3\nHNRPDL\tSON\nHNRPDL\tNAP1L1\nHNRPDL\tNPM1\nHNRPDL\tSF3B1\nHNRPDL\tIL6ST\nHNRPDL\tSERBP1\nHNRPDL\tSFRS11\nMATR3\tWAC\nMATR3\tSERBP1\nMATR3\tNARS\nMATR3\tXPO1\nMATR3\tYTHDC1\nMATR3\tSFRS11\nMATR3\tSON\nMATR3\tMGEA5\nMATR3\tPAPOLA\nMATR3\tSH3BGRL\nMATR3\tSEPT7\nMATR3\tSEPT2\nMATR3\tTAF7\nMATR3\tNPM1\nMATR3\tPCNP\nMATR3\tRNPC2\nMATR3\tTLOC1\nEIF3S3\tMATR3\nEIF3S3\tHSP90AA1\nEIF3S3\tTTC3\nEIF3S3\tNARS\nEIF3S3\tFNTA\nEIF3S3\tSEPT2\nWAC\tZNF403\nRPL22\tRPL5\nRPL22\tTPT1\nRPL22\tRPS15A\nRPL22\tRPS23\nRPL22\tRPS27A\nRPL22\tRPS7\nRPL22\tRPL30\nRPL22\tRPS3A\nRPL22\tRPL6\nRPL22\tRPL34\nRPL22\tRPL26\nRPL22\tRPL9\nRPL22\tRPL24\nRPL22\tRPS25\nRPL22\tRPL35A\nRPL22\tRPS17\nRPL22\tRPS24\nRPL22\tRPL4\nRPL22\tRPL41\nRPL22\tRPL7\nRPL22\tRPS6\nRPL22\tRPL36A\nRPL22\tRPL23\nRPL22\tRPS4X\nRPL22\tRPL31\nSH3BGRL\tYTHDC1\nSH3BGRL\tTAF7\nSH3BGRL\tSON\nMRPL34\tNDUFS3\nMRPL34\tUQCRFS1\nMRPL34\tUQCRC1\nMRPL34\tNDUFV1\nMRPL34\tPOLR2I\nNDUFS3\tPOLR2I\nNDUFS3\tNDUFS8\nNDUFS3\tUQCRFS1\nFIBP\tSIAHBP1\nFIBP\tWIPI2\nFIBP\tPOLR2E\nAURKAIP1\tCOX5A\nAURKAIP1\tC12orf10\nAURKAIP1\tMRPL34\nAURKAIP1\tGPX4\nAURKAIP1\tNDUFS3\nAURKAIP1\tTUFM\nAURKAIP1\tNDUFS8\nAURKAIP1\tNDUFS7\nAURKAIP1\tNDUFA2\nAURKAIP1\tC3orf60\nAURKAIP1\tNDUFA3\nAURKAIP1\tUQCRFS1\nAURKAIP1\tTMEM93\nAURKAIP1\tUQCRC1\nAURKAIP1\tFIBP\nAURKAIP1\tEXOSC4\nDIP2A\tPGF\nCD52\tIL7R\nCD52\tTRBV3-1\nCD52\tFAIM3\nCD52\tLCK\nCD52\tISG20\nCD52\tTRA@\nCD52\tTRB@\nCD52\tRAC2\nCD52\tTRBC1\nCSNK1A1\tPAPOLA\nCSNK1A1\tEIF4G2\nPAPOLA\tTAF7\nPAPOLA\tPUM2\nPAPOLA\tSON\nPAPOLA\tZNF9\nPAPOLA\tSSR1\nPAPOLA\tSRP72\nPAPOLA\tTRAM1\nPAPOLA\tTHRAP1\nPAPOLA\tTMEM123\nPAPOLA\tUSP34\nPAPOLA\tRNPC2\nPAPOLA\tPNRC2\nPAPOLA\tYTHDC1\nPAPOLA\tSF3B1\nHLA-G\tMAN2B1\nHLA-G\tTGFB1\nHLA-G\tISG20\nHLA-G\tIFI30\nHLA-G\tHLA-J\nMAN2B1\tTGFB1\nATP5D\tCOX5B\nATP5D\tCYC1\nCOX5B\tFLJ14346\nCOX5B\tNDUFS3\nCOX5B\tNDUFB2\nCOX5B\tNDUFA3\nCOX5B\tMRPS12\nCOX5B\tNDUFS8\nCOX5B\tUQCRC1\nCOX5B\tCYC1\nCOX5B\tMSRB2\nCOX5B\tUQCRQ\nCOX5B\tNDUFB11\nCOX5B\tMDH2\nCOX5B\tNDUFV1\nCOX5B\tUQCRFS1\nCOX5B\tNDUFS7\nCOX5B\tNDUFAB1\nCOX5B\tCOX8A\nCOX5B\tUQCR\nIGLJ3\tIGLV3-25\nIGLJ3\tLOC91316\n215176_x_at\tIGHG3\n215176_x_at\t217258_x_at\n215176_x_at\tIGHV1-69\n215176_x_at\t217281_x_at\n215176_x_at\tIGLC2\n215176_x_at\tIGHA1\n215176_x_at\tIGKC\n215176_x_at\tIGHM\n215176_x_at\tIGLV3-25\n215176_x_at\tIGKV1OR2-108\n215176_x_at\tIGLJ3\n215176_x_at\tIGKV1-5\n215176_x_at\tIGKV1OR15-118\n215176_x_at\tIGLC1\n215176_x_at\tIGL@\n215176_x_at\tLOC91316\n215176_x_at\tIGKV1D-13\n215176_x_at\t221651_x_at\n215176_x_at\tCTA-246H3.1\nIGHG3\tIGHM\nIGHG3\tIGHV1-69\nIGHG3\tIGKV1-5\nIGHG3\tIGLJ3\nIGHG3\tIGKV1D-13\nIGHG3\tIGKC\nIGHG3\tIGKV1OR2-108\nIGHG3\tIGLC2\nIGHG3\tIGLC1\nIGHG3\tLOC91316\n217258_x_at\tIGLC2\n217258_x_at\tIGKC\n217258_x_at\tIGL@\n217258_x_at\tCTA-246H3.1\n217258_x_at\tIGLJ3\n217258_x_at\tIGKV1-5\n217258_x_at\tIGLV3-25\nRPL14\tRPL17\nRPL14\tRPS4X\nRPL14\tRPS3A\nRPL14\tRPL5\nRPL14\tRPS7\nRPL14\tU16\nRPL14\tRPL21\nRPL14\tRPL4\nRPL14\tRPL6\nRPL14\tRPL35A\nRPL14\tRPL39\nRPL14\tRPL23\nDYNLT3\tPAFAH1B1\nPAFAH1B1\tPRKACB\nPAFAH1B1\tPOPDC3\nPAFAH1B1\tREEP5\nPAFAH1B1\tZFR\nPAFAH1B1\tPCNP\nPAFAH1B1\tSEPT7\nRPS18\tRPS19\nSF3B1\tWAC\nSF3B1\tSON\nSF3B1\tTUG1\nSF3B1\tSFRS5\nSF3B1\tYTHDC1\nSF3B1\tTCEA1\nIQGAP1\tMBNL1\nIQGAP1\tROCK1\nMBNL1\tOSBPL8\nMBNL1\tROCK1\nMBNL1\tPNRC2\nMBNL1\tPUM2\nNPM1\tRPS3A\nNPM1\tSFRS5\nNPM1\tSFRS11\nNPM1\tRPS7\nNPM1\tRPS6\nNPM1\tRPL7\nNPM1\tRPL34\nNPM1\tTCEA1\nNPM1\tTUG1\nNPM1\tRPL5\nNPM1\tRPL17\nNPM1\tRPL24\nNPM1\tSF3B1\nNPM1\tTINP1\nNPM1\tRPL6\nNPM1\tRPS24\nNPM1\tRPL4\nNPM1\tRPS27A\nNPM1\tRNPC2\nRPS3A\tSF3B1\nRPS3A\tTPT1\nRPS3A\tU16\nRPS3A\tRPS4X\nRPS3A\tRPS7\nRPS3A\tRPS6\nSPN\tZNF552\nDDX50\tRNPC2\nEIF5\tPCNP\nEIF5\tPAPOLA\nEIF5\tTAF7\nEIF5\tMATR3\nEIF5\tHSP90AA1\nPCNP\tSEPT2\nPCNP\tTLOC1\nPCNP\tRNPC2\n217281_x_at\tIGHM\n217281_x_at\tIGHV1-69\n217281_x_at\tIGLJ3\n217281_x_at\tIGKC\n217281_x_at\tIGLC2\n217281_x_at\tIGHA1\n217281_x_at\tIGHG3\n217281_x_at\tIGKV1OR2-108\nCHCHD2\tMIF\nCHCHD2\tNDUFAB1\nCHCHD2\tCOX5B\nCHCHD2\tMRPS12\nCHCHD2\tMRP63\nCHCHD2\tCOX8A\nCHCHD2\tSLC25A3\nCHCHD2\tNDUFB11\nMIF\tTIMM13\nARPC5\tCAP1\nARPC5\tPRG1\nSFRS11\tTUG1\nACTR10\tSKP1A\nACTR10\tPRKAR1A\nSKP1A\tSUMO2\nACTR2\tARPC3\nACTR2\tACTR3\nACTR2\tCAPZA1\nACTR2\tPDCD10\nARPC3\tCAPZA1\nCAV1\tMMP2\nCAV1\tCOL6A1\nCAV1\tFBLN1\nCAV1\tCOL1A2\nCAV1\tPTRF\nCAV1\tLAMC1\nACTG2\tMYH11\nMYH11\tMYLK\nMYH11\tTPM1\nMYH11\tTAGLN\nRPL38\tRPS20\nRPL38\tRPLP2\nRPL38\tRPS19\nRPS20\tRPS27\nCSDE1\tFLJ11021\nCSDE1\tWAC\nCSDE1\tNFE2L2\nCOL1A2\tCOL3A1\nCOL3A1\tCOL6A3\nCD7\tLCK\nCD7\tHMHA1\nLCK\tRAC2\nLCK\tTRA@\nLCK\tTRB@\nLCK\tTRBC1\nLCK\tTRBV3-1\nNDUFB11\tNDUFS3\nNDUFB11\tUQCRQ\nNDUFB11\tUQCR\nNDUFB11\tNDUFB4\nNDUFB11\tUQCRFS1\nNDUFB11\tSLC25A3\nNDUFB11\tNDUFS8\nNDUFB11\tPOLR2L\nC3orf60\tEXOSC4\nC3orf60\tPOLR2I\nC3orf60\tMRPL34\nC3orf60\tGPX4\n211639_x_at\tIGKC\nRPL11\tRPS15A\nRPL11\tRPL5\nRPL11\tRPS24\nRPL11\tRPL17\nRPL11\tRPL7\nRPL11\tU16\nRPL11\tRPL24\nRPL11\tRPL21\nRPL11\tRPL35A\nRPL11\tRPS25\nRPL11\tRPL14\nRPL11\tRPS6\nRPL11\tRPL22\nRPL11\tRPL34\nRPL11\tRPL4\nRPL11\tRPS4X\nRPL11\tRPS3A\nRPL11\tRPS7\nRPL11\tRPL39\nRPL11\tRPL31\nRPL11\tRPL36A\nRPL11\tRPL23\nRPL11\tRPS17\nRPL11\tRPL30\nRPL11\tRPS23\nRPS15A\tRPS6\nRPS15A\tRPS17\nRPS15A\tRPS7\nRPS15A\tRPS3A\nRPS15A\tRPS20\nRPS15A\tRPS27\nRPS15A\tRPS23\nGNB2L1\tRPL13A\nGNB2L1\tRPS19\nGNB2L1\tRPL29\nGNB2L1\tRPS16\nRPL29\tRPS9\nRPL29\tRPS16\nRPL29\tRPL35\nRPL13\tRPL18A\nRPL13\tRPL28\nRPL13\tRPS2\nRPL13\tRPL18\nRPL13\tRPLP2\nRPL13\tRPS15\nRPL18A\tRPS2\nRPL18A\tRPS19\nRPL18A\tRPLP2\nRPL18A\tRPL28\nHLA-A\tHLA-F\nHLA-A\tMAN2B1\nHLA-A\tHLA-E\nHLA-A\tHLA-G\nHLA-A\tHLA-B\nHLA-A\tHLA-J\nHLA-A\tHLA-C\nHLA-F\tISG20\nHLA-F\tHLA-G\nHLA-F\tIFI30\nHLA-F\tMAN2B1\nHLA-F\tHLA-J\nBTF3\tMDS1\nBTF3\tRPS27\nBTF3\tRPS17\nBTF3\tRPS15A\nBTF3\tRPL30\nBTF3\tLOC402057\nBTF3\tRPL22\nNACA\tRPL35A\nNACA\tRPS3A\nNACA\tRPL5\nNACA\tNAP1L1\nNACA\tSFRS5\nNACA\tRPS7\nNACA\tRPL24\nNACA\tU16\nNACA\tRPL21\nNACA\tRPL9\nNACA\tNPM1\nNACA\tRPS23\nNACA\tRPL4\nNACA\tRPS27A\nNACA\tRPS24\nNACA\tRPL17\nNACA\tRPL6\nNACA\tTINP1\nRPL35A\tRPL7\nRPL35A\tRPS17\nRPL35A\tRPS27A\nRPL35A\tRPS20\nRPL35A\tRPS27\nRPL35A\tRPS15A\nRPL35A\tRPS3A\nRPL35A\tRPS25\nRPL35A\tRPL36A\nRPL35A\tRPL39\nRPL35A\tRPL6\nRPL35A\tRPS6\nRPL35A\tRPS4X\nRPL35A\tRPL4\nRPL35A\tRPL5\nRPL35A\tRPS23\nRPL35A\tRPS24\nRPL35A\tU16\nRPL35A\tRPL9\nRPL35A\tRPS7\nBIRC2\tDDX5\nBIRC2\tZNF403\nBIRC2\tLOC58486\nBIRC2\tTHRAP1\nBIRC2\tSERBP1\nBIRC2\tPAPOLA\nBIRC2\tUSP34\nBIRC2\tC1orf63\nDDX5\tSERBP1\nDDX5\tSRP46\nDDX5\thfl-B5\nDDX5\tTUG1\nDDX5\tNAP1L1\nDDX5\tHNRPH1\nDDX5\tNBPF1\nDDX5\tSFRS5\nDDX5\tLOC342346\nDDX5\tNBPF12\nDDX5\tMGEA5\nDDX5\tHNRPA2B1\nDDX5\tSON\nDDX5\tFLJ10154\nDDX5\tUSP34\nDDX5\tNPM1\nDDX5\tTARDBP\nDDX5\tEIF4G2\nDDX5\tPAPOLA\nDDX5\tHIATL1\nDDX5\tYTHDC1\nDDX5\tSF3B1\nRPL30\tU16\nRPL30\tRPS7\nRPL30\tRPS25\nRPL30\tRPS13\nRPL30\tRPS3A\nRPL30\tRPS4X\nRPL30\tRPL4\nRPL30\tRPS6\nRPL30\tRPL37\nRPL30\tRPL31\nRPL30\tRPL36A\nRPL30\tRPL35A\nRPL30\tRPS27\nRPL30\tRPS17\nRPL30\tRPS15A\nRPL30\tRPL9\nRPL30\tRPS20\nRPL30\tRPS23\nRPL30\tRPL32\nRPL30\tRPL39\nTMEM123\tTRAM1\nIGHA1\tIGHV1-69\nIGHA1\tIGKC\nIGHA1\tIGLJ3\nIGHA1\tIGLV3-25\nIGHA1\tIGHM\nIGHA1\tIGKV1OR15-118\nIGHA1\tIGLC2\nIGHA1\tIGL@\nIGHA1\tIGKV1-5\nIGHA1\tIGKV1D-13\nIGHA1\tIGHG3\nIGHA1\tIGKV1OR2-108\nIGHA1\tLOC91316\nIGHA1\tIGLC1\nIGHV1-69\tIGLC2\nIGHV1-69\tIGKC\nIGHV1-69\tIGLC1\nIGHV1-69\tIGKV1OR2-108\nNDUFS7\tPOLR2I\nNDUFS7\tNDUFV1\nNDUFS7\tNDUFS8\nPOLR2I\tUQCRFS1\n214836_x_at\t217258_x_at\n214836_x_at\t217281_x_at\n214836_x_at\tIGLC2\n214836_x_at\tIGLV3-25\n214836_x_at\tIGL@\n214836_x_at\tIGKV1OR2-108\n214836_x_at\tIGKV1OR15-118\n214836_x_at\tIGLJ3\n214836_x_at\tIGHG3\n214836_x_at\tIGKC\n214836_x_at\tLOC91316\n214836_x_at\tIGKV1-5\n214836_x_at\tIGKV1D-13\n214836_x_at\tIGLC1\n214836_x_at\tIGHA1\n214836_x_at\t221651_x_at\n214836_x_at\tCTA-246H3.1\n214836_x_at\t215176_x_at\nRPS6\tTPT1\nRPS6\tRPS7\nRPS6\tU16\nGTF2I\tSRP9\nGTF2I\tTMEM66\nSRP9\tSUMO1\nATP2A3\tTRA@\nATP2A3\tTRB@\nATP2A3\tTRBC1\nTRA@\tTRBC1\nTRA@\tTRB@\nIGLC2\tIGLJ3\nIGLC2\tLOC91316\nIGLC2\tIGLV3-25\nIGLC2\tIGLV3-10\nHSP90B1\tZNF638\nHSP90B1\tRNPC2\nHSP90B1\tVDP\nRPL7\tTPT1\nRPL7\tRPS3A\nRPL7\tRPS6\nRPL7\tRPS24\nRPL7\tTCEA1\nRPL7\tSF3B1\nRPL7\tRPS7\nRPL7\tRPS25\nRPL7\tRPL9\nRPL7\tRPS23\nRPL7\tRPS27A\nRPL7\tRPS4X\nMGEA5\tNAP1L1\nMGEA5\tPAPOLA\nMGEA5\tXPO1\nMGEA5\tSF3B1\nMGEA5\tRNPC2\nMGEA5\tYTHDC1\nMGEA5\tPNRC2\nBCLAF1\tPCM1\nBCLAF1\tRNPC2\nBCLAF1\tPUM2\nBCLAF1\tEIF3S6\nBCLAF1\tUSP47\nBCLAF1\tSF3B1\nBCLAF1\tSLC38A2\nBCLAF1\tFLJ11021\nBCLAF1\tCOPS2\nBCLAF1\tPCNP\nBCLAF1\tCSDE1\nBCLAF1\tMATR3\nBCLAF1\tWAC\nBCLAF1\tCROP\nBCLAF1\tSRP72\nBCLAF1\tLOC58486\nBCLAF1\tPHIP\nBCLAF1\tZNF638\nBCLAF1\tVDP\nBCLAF1\tNPM1\nBCLAF1\tHSP90B1\nBCLAF1\tTLOC1\nPCM1\tVDP\nCXorf9\tGPSM3\nCXorf9\tTRA@\nCXorf9\tIL2RG\nCXorf9\tIL16\n216342_x_at\tRPL7\n216342_x_at\tTPT1\n216342_x_at\tRPL14\n216342_x_at\tRPL9\n216342_x_at\tRPS27A\n216342_x_at\tRPL17\n216342_x_at\tRPS17\n216342_x_at\tRPL5\n216342_x_at\tU16\n216342_x_at\tRPL22\n216342_x_at\tRPL36A\n216342_x_at\tRPS25\n216342_x_at\tLOC402057\n216342_x_at\tRPS7\n216342_x_at\tRPL21\n216342_x_at\tRPL24\n216342_x_at\tRPL41\n216342_x_at\tRPS24\n216342_x_at\tMDS1\n216342_x_at\tRPL6\n216342_x_at\tLOC440055\n216342_x_at\tRPL4\n216342_x_at\tRPL34\n216342_x_at\tRPS3A\n216342_x_at\tRPL11\n216342_x_at\tRPS6\n216342_x_at\tRPL23\n216342_x_at\tRPL30\n216342_x_at\tRPL31\n216342_x_at\tRPS23\n216342_x_at\tRPL35A\n216342_x_at\tRPS4X\nNDUFA13\tNDUFA3\nNDUFA13\tNDUFB2\nNDUFA3\tNDUFAB1\nNDUFA3\tUCRC\nNDUFA3\tNDUFB2\nNDUFA3\tNDUFB11\nNDUFA3\tUQCR\nNDUFA3\tUQCRC1\nNDUFA3\tNDUFB4\nCDKN1B\tPPP2CA\nCDKN1B\tMARCKS\nHMGB1\tHNRPR\nHMGB1\tHNRPA2B1\nHNRPR\tSRP9\nHNRPR\tSON\nHNRPR\tSFRS10\nAP2S1\tATP6V0C\nAP2S1\tPOLR2E\nAP2S1\tGPX1\nAP2S1\tGUK1\nAP2S1\tNAPA\nAP2S1\tCOPE\nAP2S1\tATP6V0B\nAP2S1\tMRPS12\n211637_x_at\tIGKC\n211637_x_at\tIGHA1\n211637_x_at\tIGLC2\n211637_x_at\t211639_x_at\n211637_x_at\tIGHM\n211637_x_at\t211908_x_at\n211637_x_at\tIGHV1-69\n211637_x_at\tCTA-246H3.1\n211637_x_at\t211641_x_at\n211637_x_at\t215176_x_at\n211637_x_at\t211645_x_at\n211637_x_at\tIGHG3\n211637_x_at\t217281_x_at\n211637_x_at\tLOC91316\nCOL4A1\tCOL4A2\nCOL4A1\tFBLN1\nCOL4A2\tRBPMS\nFLJ42393\tPDE4C\nFLJ42393\tZNF160\nFLJ42393\tPOLR1B\nFLJ42393\tKNS2\nFLJ42393\tSLC35E1\nFLJ42393\tLOC152719\nMORF4L1\tPTGES3\nMORF4L1\tSKP1A\nPTGES3\tSUMO2\nSON\tXPO1\nSON\tSRP46\nSON\tYTHDC1\nIFI30\tTGFB1\nIFI30\tNCF1\nAASDHPPT\tPOPDC3\nAASDHPPT\tPAFAH1B1\nPOPDC3\tRAB6C\nPOPDC3\tPRKACB\nFXYD5\tITGB2\nFXYD5\tPSMB9\nCD79A\tIGKC\nCD79A\tIGHA1\nCD79A\tIGLC2\nCD79A\tIGLJ3\nFLJ14346\tZNF611\nFLJ14346\tGPAA1\nFLJ14346\tMRPS12\nFLJ14346\tLOC152719\nFLJ14346\tSLC35E1\nHLA-DPA1\tHLA-DQB1\nHLA-DPA1\tHLA-DQA1\nHLA-DPA1\tHLA-DRA\nHLA-DPA1\tHLA-DRB5\nHLA-DPA1\tHLA-DRB4\nHLA-DPA1\tHLA-DRB1\nHLA-DPA1\tHLA-DPB1\nHLA-DQB1\tHLA-DRB4\nHLA-DQB1\tHLA-DRB5\nHLA-DQB1\tHLA-DRB1\nIFNGR1\tROCK1\nC6orf12\tHLA-F\nC6orf12\tHLA-G\nC6orf12\tHLA-B\nC6orf12\tHLA-C\nC6orf12\tHLA-J\nC6orf12\tHLA-A\nNARS\tTLOC1\nNARS\tTTC3\nNARS\tSRP9\nRPL36A\tRPL6\nRPL36A\tRPS7\nRPL36A\tRPS24\nRPL36A\tRPS3A\nRPL36A\tRPL4\nRPL36A\tRPS4X\nRPL36A\tRPS25\nRPL36A\tRPS15A\nRPL36A\tRPS6\nRPL36A\tRPS17\nRPL36A\tRPS23\nRPL36A\tRPL39\n217718_s_at\tYWHAZ\n217718_s_at\tCAB39\nRPL23A\tRPS20\nTAF7\tUBE4A\nTAF7\tYTHDC1\nTAF7\tXPO1\nDHX15\tOGT\nDHX15\tKIAA0907\nDHX15\tNPM1\nCD2\tTRA@\nCD2\tCD52\nCD2\tIL7R\nDST\tPLEKHC1\nDST\tSPARCL1\nCOL6A1\tCOL6A3\nCOL6A1\tFBLN1\nCOL6A1\tPTRF\nFIS1\tNDUFA13\nEIF4G2\tSRP46\nEIF4G2\tHSP90AA1\nEIF4G2\tSERBP1\nEIF4G2\tSON\nEIF4G2\tEIF5\nEIF4G2\tNPM1\nEIF4G2\tPUM2\nEIF4G2\tSET\nEIF4G2\tPCNP\nEIF4G2\tLOC342346\nEIF4G2\tHNRPA2B1\nEIF4G2\tYTHDC1\nEIF4G2\tXPO1\nEIF4G2\tMATR3\nEIF4G2\tPAPOLA\nEIF4G2\tTHRAP1\nEIF4G2\tSF3B1\nEIF4G2\tHIATL1\nSRP46\tXPO1\nCOL1A1\tCOL6A3\nCOL1A1\tCOL1A2\nCOL1A1\tCOL3A1\nC12orf10\tFIBP\nC12orf10\tC3orf60\nLMOD1\tMYH11\n208246_x_at\tPOLR1B\n208246_x_at\tZNF611\n208246_x_at\tPGF\n208246_x_at\tATP8B1\n208246_x_at\tRIOK3\n208246_x_at\tKNS2\n208246_x_at\tDBT\n208246_x_at\tLOC152719\n208246_x_at\tFBXW12\n208246_x_at\tPDE4C\n208246_x_at\tSLC35E1\n208246_x_at\tZNF160\n208246_x_at\t216524_x_at\nHNRPH1\tSON\nHNRPH1\tSF3B1\nHNRPH1\tYTHDC1\nRPS14\tRPS16\nRPS14\tRPS5\nRPS14\tRPS9\nRPS16\tRPS19\nRPS16\tRPS9\nRPS16\tRPS5\nARHGDIB\tLAPTM5\nARHGDIB\tPRG1\nARHGDIB\tUCP2\nARHGDIB\tRAC2\nARHGDIB\tCXCR4\nARHGDIB\tCECR1\nLAPTM5\tRAC2\nLAPTM5\tPRG1\nATRX\tCOPS2\nATRX\tPCNP\nATRX\tPUM2\nATRX\tMATR3\nATRX\tSH3BGRL\nATRX\tSEPT7\nATRX\tBCLAF1\nATRX\tTLOC1\nHIATL1\tSFRS5\nHIATL1\tRPL6\nHIATL1\tRPL17\nHIATL1\tTUG1\nHIATL1\tHNRPA2B1\nHIATL1\tRAVER2\nHIATL1\tRNPC2\nHIATL1\tHNRPH1\nHIATL1\tYTHDC1\nHIATL1\tTCEA1\nHIATL1\tNPM1\nHIATL1\tLOC58486\nHIATL1\tTHRAP1\nHIATL1\tPAPOLA\nHIATL1\tSF3B1\nFAIM3\tTRA@\nFAIM3\tHCLS1\nFAIM3\tRAC2\nIGKV1D-13\tIGLJ3\nIGKV1D-13\tIGLV3-25\nIGKV1D-13\tIGLC2\nIGKV1D-13\tLOC91316\nIGKV1D-13\tIGL@\nIGKV1D-13\tIGLC1\nIGKV1D-13\tIGKV1OR15-118\nHSP90AA1\tMATR3\nHSP90AA1\tSRP9\nHSP90AA1\tSERBP1\nHSP90AA1\tSEPT2\nHSP90AA1\tNARS\nRPL19\tRPS20\nLOC283412\tRPL29\nLOC283412\tRPS9\nDGCR6\tPOLR2I\nLTB\tTRBC1\nLTB\tTRB@\nHMHA1\tPSMB8\nHMHA1\tTRBC1\nHMHA1\tRAC2\nPSMB8\tTAPBP\nPSMB8\tPSMB9\nIGKV1-5\tIGL@\nIGKV1-5\tIGKV1OR2-108\nIGKV1-5\tIGLC2\nIGKV1-5\tIGLJ3\nIGKV1-5\tIGLV3-25\nIGKV1-5\tIGLC1\nIGKV1-5\tIGKV1D-13\nIGKV1-5\tIGKV1OR15-118\nRPL28\tRPS10\nRPL28\tRPS2\nRPL28\tRPS19\nRPL28\tRPS16\nRPL28\tRPLP2\nHCLS1\tITGB2\nHCLS1\tSELL\nHCLS1\tRAC2\nHCLS1\tTRA@\nFBLN1\tMMP2\nFBLN1\tPTRF\nNDUFA2\tUQCRFS1\nNDUFA2\tUQCR\nNDUFA2\tNDUFS8\nNDUFA2\tUQCRC1\nNDUFA2\tNDUFB4\nNDUFA2\tTCEB2\nNDUFA2\tNDUFA3\nNDUFA2\tUCRC\nHLA-DRB4\tHLA-DRB5\nFAM96B\tNDUFV1\nFAM96B\tNDUFS8\nFAM96B\tNDUFS3\nFAM96B\tTUFM\nFAM96B\tNDUFS7\nFAM96B\tNDUFA10\nFAM96B\tNDUFA2\nFAM96B\tNDUFA3\nCOQ9\tNDUFB4\nCOQ9\tUQCRFS1\nEEF1B2\tRPL30\nEEF1B2\tRPL10A\nEEF1B2\tRPS23\nEEF1B2\tRPS15A\nEEF1B2\tRPL35A\nEEF1B2\tRPL14\nEEF1B2\tRPL36A\nEEF1B2\tRPL37\nEEF1B2\tRPL39\nEEF1B2\tLOC440055\nPUM2\tWAC\nPUM2\tSF3B1\nALOX5AP\tLAPTM5\nALOX5AP\tITGB2\nDKFZP566N034\tZNF160\nDKFZP566N034\tSLC35E1\nARL6IP5\tPAFAH1B1\nTRB@\tTRBV3-1\nTRB@\tTRBC1\nIFI16\tROCK1\nIFI16\tIQGAP1\nIFI16\tTRIM22\nIFI16\tMBNL1\nIFI16\tIFNGR1\n211641_x_at\t211908_x_at\n211641_x_at\t211645_x_at\n211641_x_at\tIGHG3\n211641_x_at\tIGKV1-5\n211641_x_at\t217281_x_at\n211641_x_at\tIGHA1\n211641_x_at\tIGHM\n211908_x_at\tIGHV1-69\n211908_x_at\t217281_x_at\n211908_x_at\tIGHM\nWSB1\tXPO1\nARPC1B\tHLA-C\nARPC1B\tHLA-A\nARPC1B\tHLA-B\nARPC1B\tISG20\nARPC1B\tHLA-G\nCD53\tITGB2\nCD53\tIL10RA\nCD53\tHCLS1\nHLA-E\tHLA-F\nHLA-E\tPSMB8\nHLA-E\tHLA-J\nHLA-E\tMAN2B1\nHLA-E\tHLA-G\n211645_x_at\tIGHA1\n211645_x_at\tIGKC\n211645_x_at\tIGHM\n211645_x_at\tIGLC2\n211645_x_at\tIGHG3\n211645_x_at\tIGL@\n211645_x_at\tIGLV3-25\n211645_x_at\tIGLJ3\n211645_x_at\tLOC91316\n211645_x_at\tIGLC1\n211645_x_at\tIGKV1-5\n211645_x_at\t221651_x_at\n211645_x_at\tIGKV1OR15-118\n211645_x_at\tCTA-246H3.1\n211645_x_at\tIGKV1D-13\n211645_x_at\t214836_x_at\n211645_x_at\t215176_x_at\nNDUFB2\tNDUFS7\nNDUFB2\tUQCRC1\nNDUFB2\tUQCR\nNDUFB2\tNDUFV1\nFLJ10154\tLOC58486\nFLJ10154\tXPO1\nFLJ10154\tPFAAP5\nFLJ10154\tRNPC2\nFLJ10154\tHNRPDL\nFLJ10154\tSFPQ\nFLJ10154\tSFRS11\nFLJ10154\tNPM1\nEIF4A2\tTTC3\nEIF4A2\tMATR3\nGPX4\tR3HCC1\nGPX4\tPOLR2I\nGPX4\tMRPL34\nPRKAR2A\tSLC35E1\nSLC35E1\tUBE2D2\nSLC35E1\tWDR45\nSLC35E1\tZNF611\nSLC35E1\tZNF160\nIGLC1\tIGLJ3\nIGLC1\tIGLV3-25\nIGLC1\tIGLC2\nIGLC1\tLOC91316\nUQCRC1\tUQCRFS1\nTMED5\tWAC\nMDH2\tNDUFB11\nMDH2\tUQCRQ\nMDH2\tUQCRC1\nMDH2\tUQCRFS1\nMDH2\tNDUFS8\nIGL@\tIGLV3-25\nIGL@\tIGLC2\nIGL@\tIGLC1\nIGL@\tIGLJ3\nHLA-DRB1\tHLA-F\nHLA-DRB1\tHLA-DRB4\nHLA-DRB1\tHLA-DRB5\nCD74\tHLA-DQB1\nCD74\tHLA-DRB4\nCD74\tHLA-DRB1\nCD74\tHLA-DRA\nCD74\tHLA-DMA\nCD74\tHLA-DPB1\nCD74\tHLA-DRB5\nCD74\tHLA-DPA1\nCLTC\tNARS\nRPS17\tRPS25\nRPS17\tRPS4X\nRPS17\tRPS6\nRPS17\tRPS7\nRPS17\tRPS3A\nRPS17\tRPS20\nRPS17\tRPS23\nRPS17\tRPS27\nACTR3\tCAP1\nACTR3\tARPC3\nACTR3\tYWHAZ\nACTR3\tCAPZA1\nRPS10\tRPS16\nRPS10\tRPS21\nRPS10\tRPS19\nRPL27A\tRPS11\nRPL27A\tRPLP2\nRPL27A\tRPS19\nRPL27A\tRPL38\nRPL27A\tRPS20\nRPL27A\tRPS18\nDDX17\tSON\nDDX17\tHNRPH1\nC11orf58\tYTHDC1\nC11orf58\tHNRPK\nC11orf58\tLOC342346\nC11orf58\tSON\nNAPA\tWIPI2\nRGPD5\tTTC3\nCD3D\tTRA@\nCD3D\tTRB@\nCD3D\tTRBC1\nIGKV1OR2-108\tLOC91316\nIGKV1OR2-108\tIGLC2\nIGKV1OR2-108\tIGLC1\nIGKV1OR2-108\tIGLJ3\nCAB39\tSUB1\nATP6V0B\tGPX1\nATP6V0B\tCOPE\nATP6V0B\tMRPS12\nATP6V0B\tATP6V0D1\nATP6V0B\tATP6V0C\nGPX1\tPPP1CA\nGPX1\tPGLS\nGPX1\tOAZ1\nENDOG\tNDUFS7\nLOC388344\tRPS2\nLOC388344\tRPL18\nLOC388344\tRPL18A\nLOC388344\tRPL13\nLOC388344\tRPS15\nLOC440055\tRPL22\nLOC440055\tRPL17\nLOC440055\tRPS7\nLOC440055\tRPL9\nLOC440055\tRPS3A\nLOC440055\tRPS15A\nLOC440055\tRPL21\nLOC440055\tRPS4X\nLOC440055\tU16\nLOC440055\tRPL31\nLOC440055\tRPL37\nLOC440055\tRPL35A\nLOC440055\tMDS1\nLOC440055\tRPS6\nLOC440055\tRPS17\nLOC440055\tRPL32\nLOC440055\tRPL23\nLOC440055\tRPL4\nLOC440055\tRPL39\nLOC440055\tRPS20\nLOC440055\tRPL36A\nLOC440055\tRPL30\nLOC440055\tRPS23\nLOC440055\tRPL11\nCYBA\tIFI30\nCYBA\tHLA-G\nCYBA\tHLA-B\nCYBA\tHLA-J\nCYBA\tTGFB1\nRBPMS\tTGFB1I1\nKNS2\tPRR11\nKNS2\tSPG21\nKNS2\tLOC152719\nKNS2\tPGF\nKNS2\tUBE2D2\nKNS2\tPRKAR2A\nKNS2\tRIOK3\nKNS2\tZNF611\nKNS2\tZNF160\nKNS2\tPDE4C\nKNS2\tSLC35E1\nNPEPPS\tSEPT7\nMRPS12\tZNHIT1\nGLTSCR2\tRPS2\nGLTSCR2\tRPL13\nGLTSCR2\tLOC388344\nHLA-DMB\tHLA-DRA\n220725_x_at\tCDC5L\n220725_x_at\tSLC25A16\n220725_x_at\tC12orf38\n220725_x_at\tOPHN1\n220725_x_at\tMCM3AP\n220725_x_at\tLOC56902\nCDC5L\tLOC56902\nCDC5L\tMCM3AP\nARL8B\tHSP90AA1\nARL8B\tNARS\nCTA-246H3.1\tIGLC2\nCTA-246H3.1\tIGLV3-25\nCTA-246H3.1\tIGKC\nCTA-246H3.1\tIGKV1OR15-118\nCTA-246H3.1\tIGHM\nCTA-246H3.1\tIGLJ3\nCTA-246H3.1\tIGKV1OR2-108\nCTA-246H3.1\tIGL@\nCTA-246H3.1\tIGHG3\nCTA-246H3.1\tIGKV1-5\nCTA-246H3.1\tIGKV1D-13\nCTA-246H3.1\tLOC91316\nCTA-246H3.1\tIGLC1\nCTA-246H3.1\tIGHA1\n218041_x_at\tBCLAF1\n218041_x_at\tPUM2\n218041_x_at\tSLC38A2\nMEFV\tSPN\nSMTN\tTGFB1I1\nZNF160\tZNF611\nTUFM\tUQCRFS1\nTUFM\tUQCRC1\nCD164\tCOPB\nARF5\tPOLR2J\nARF5\tATP6V0D1\nHLA-B\tMYH9\nHLA-B\tMAN2B1\nHLA-B\tHLA-G\nHLA-B\tHLA-F\nHLA-B\tHLA-E\nHLA-B\tHLA-C\nHLA-B\tHLA-J\nIGHD\tIGHM\nADRM1\tEXOSC4\nADRM1\tAP2S1\nADRM1\tFIBP\nADRM1\tAURKAIP1\n211650_x_at\tIGLV3-25\n211650_x_at\tIGHG3\n211650_x_at\tIGKC\n211650_x_at\tIGHV1-69\n211650_x_at\tIGHM\nFLJ12151\tPPP2CA\nFLJ12151\tLOC152719\nFLJ12151\tPRR11\nFLJ12151\tPDE4C\nFLJ12151\tZNF611\nFLJ12151\tSLC35E1\nFLJ12151\tZNF160\nHNRPK\tHNRPU\nHNRPK\tSET\nTOMM20\tZMYND11\nTOMM20\tTTC3\nTOMM20\tTTC19\nCORO1A\tLAPTM5\nAD7C-NTP\tARL6IP2\nAD7C-NTP\tMEFV\nAD7C-NTP\tCDC5L\nARL6IP2\tCDC5L\nARL6IP2\tLOC56902\nARL6IP2\tMEFV\nC1orf63\tPAPOLA\nC1orf63\tLOC342346\nRPL31\tRPL5\nRPL31\tTPT1\nRPL31\tRPS27A\nRPL31\tRPS7\nRPL31\tRPS17\nRPL31\tRPL9\nRPL31\tRPS3A\nRPL31\tRPL6\nRPL31\tRPL35A\nRPL31\tRPL36A\nRPL31\tRPL7\nRPL31\tRPS6\nRPL31\tRPL4\nRPL31\tRPS24\nRPL31\tRPS23\nRPL31\tRPL34\nRPL31\tRPS4X\nSDHA\tTUFM\nUQCR\tUQCRQ\nUQCR\tUQCRC1\nFNBP4\tRPL26\nFNBP4\tRNPC2\nFNBP4\tRPL17\nFNBP4\tOGT\nFNBP4\tRPL6\nFNBP4\tRPS27A\nPNRC2\tZNF638\nPNRC2\tPUM2\nPNRC2\tSF3B1\nPNRC2\tROCK1\nIGLV3-10\tIGLV3-25\nMSN\tPRG1\nPPIB\tRPN1\nPPIB\tSEC61A1\nTHRAP1\tZNF638\nIRF7\tPRKD2\nIRF7\tMAN2B1\n221651_x_at\tIGLJ3\n221651_x_at\tIGKV1OR15-118\n221651_x_at\tIGLC2\n221651_x_at\tIGKV1-5\n221651_x_at\tIGKC\n221651_x_at\tIGKV1OR2-108\n221651_x_at\tIGHG3\n221651_x_at\tLOC91316\n221651_x_at\tIGKV1D-13\n221651_x_at\tCTA-246H3.1\n221651_x_at\tIGHA1\n221651_x_at\tIGLC1\nLOC152719\tPRR11\nLOC152719\tLRRFIP1\nLOC152719\tPDE4C\nLOC152719\tRIOK3\nLOC152719\tZNF611\nLOC152719\tSLC35E1\nLOC152719\tZNF160\nPRKAR1A\tRNF11\nPRKAR1A\tSRP9\nPRKAR1A\tTMEM66\nINPP5D\tITGB2\n216524_x_at\tZNF611\n216524_x_at\tZNF160\n216524_x_at\tPGF\n216524_x_at\tKNS2\n216524_x_at\tCEP27\n216524_x_at\tRIOK3\n216524_x_at\tDBT\n216524_x_at\tPDE4C\n216524_x_at\tFBXW12\nRPL10A\tRPL39\nRPL10A\tRPL14\nRPL10A\tRPL12\nRPL27\tRPS20\nRPL27\tRPS11\nRPL27\tRPLP2\nRPL27\tRPL38\nRPL27\tRPS19\nRPL27\tRPL27A\nERH\tHNRPK\nERH\tSUMO2\nPGF\tPOLR1B\nPGF\tPRR11\nPGF\tZNF160\nPGF\tWDR45\nPGF\tRIOK3\nPGF\tZNF611\nCAPNS1\tCLPTM1\nCLPTM1\tNAPA\nRPS19\tRPS2\nRPS19\tRPS21\nRPS19\tRPS20\nDDX42\tMT1H\nDDX42\tMT1M\nDDX42\tMT1G\nDDX42\tMT1F\nMT1H\tMT1L\nMT1H\tMT2A\nMT1H\tMT1M\nMT1H\tMT1X\nCD37\tPTPRCAP\nCD37\tISG20\nPTPRCAP\tTRBV3-1\nEIF3S6\tRPS4X\nEIF3S6\tRPL26\nEIF3S6\tZNF638\nEIF3S6\tMDS1\nEIF3S6\tRPS3A\nEIF3S6\tRPL24\nEIF3S6\tRPL7\nEIF3S6\tRPL31\nEIF3S6\tRPL4\nEIF3S6\tRPL21\nEIF3S6\tU16\nEIF3S6\tNPM1\nEIF3S6\tRNPC2\nEIF3S6\tNACA\nEIF3S6\tRPS7\nEIF3S6\tTINP1\nEIF3S6\tVDP\nEIF3S6\tRPS27A\nEIF3S6\tRPL34\nEIF3S6\tRPL5\nEIF3S6\tRPS24\nEIF3S6\tRPL17\nEIF3S6\tRPL6\nIGKV1OR15-118\tIGL@\nIGKV1OR15-118\tIGLC2\nIGKV1OR15-118\tIGLV3-25\nNDUFB6\tTCEB2\nACTA2\tLMOD1\nACTA2\tMYH11\nACTA2\tTAGLN\nGMFG\tITGB2\nHNRPU\tSET\nHNRPH3\tLOC58486\nHNRPH3\tRNPC2\nHNRPH3\tMATR3\nHNRPH3\tKIDINS220\nC16orf24\tSCAND1\nNBPF1\tNBPF12\nARPP-19\tPRKACB\n217052_x_at\tG3BP\n217052_x_at\t220725_x_at\nCCL5\tHLA-F\nCCL5\tHLA-C\nCCL5\tHLA-G\nRPLP2\tRPS16\nRPLP2\tRPS20\nRPLP2\tRPS19\nRPLP2\tRPS11\nECH1\tUQCRQ\nRPL12\tRPL14\nRPL12\tRPL39\nRPL12\tRPL19\nCECR1\tLAPTM5\nATP6V0D1\tCHMP2A\nATP6V0D1\tPOLR2J\nATP6V0D1\tPSMB3\nATP6V0D1\tOAZ2\nCBX3\tHNRPA2B1\nCBX3\tXPO1\nSFRS10\tSON\nTIMM8B\tUQCRC1\nCD48\tIL16\nARF1\tCOPE\nARF1\tYIPF3\nARF1\tCAPNS1\nARF1\tRPN1\nKPNB1\tPAFAH1B1\nHLA-J\tIFI30\nHLA-J\tMAN2B1\nUSP47\tZNF638\nUSP47\tVDP\nRPL36\tRPS16\nRPL36\tRPS18\nRPL36\tRPS19\nRPL36\tRPS10\nCUL4B\tSH3BGRL\nADD3\tWAC\nADD3\tSEPT7\nADD3\tMATR3\nDEXI\tNDUFB11\nLYSMD4\tSEPT7\nPFAAP5\tZNF638\nPFAAP5\tRNPC2\n215182_x_at\tSPN\n215182_x_at\tCDC5L\n215182_x_at\t220725_x_at\n215182_x_at\tLOC56902\n215182_x_at\tMCM3AP\nHLA-DQA1\tHLA-DRB4\nHLA-DQA1\tHLA-DRA\nDDT\tZNHIT1\nDDT\tMRPS12\nRAVER2\tSF3B1\nHLA-DMA\tHLA-DQB1\nHLA-DMA\tHLA-DRA\nHLA-DMA\tHLA-DRB1\nHLA-DMA\tHLA-DPA1\nHLA-DMA\tHLA-DQA1\nHLA-DMA\tHLA-DRB4\nHLA-DMA\tHLA-DPB1\nHLA-DMA\tHLA-DRB5\nRAB6A\tRAB6C\nC1orf160\tTCEB2\nC1orf160\tNDUFA13\n217679_x_at\tPDE4C\n217679_x_at\tDBT\n217679_x_at\tPGF\n217679_x_at\tCEP27\n217679_x_at\tZNF160\n217679_x_at\tFLJ12151\n217679_x_at\tSLC35E1\n217679_x_at\tKNS2\n217679_x_at\tFBXW12\n217679_x_at\tZNF611\nRPL21\tRPL26\nRPL21\tRPL36A\nRPL21\tRPL5\nRPL21\tRPL9\nRPL21\tRPL30\nRPL21\tRPS17\nRPL21\tTPT1\nRPL21\tRPS7\nRPL21\tRPL39\nRPL21\tRPS23\nRPL21\tRPL24\nRPL21\tRPS27A\nRPL21\tRPS3A\nRPL21\tU16\nRPL21\tRPL22\nRPL21\tRPS6\nRPL21\tRPL6\nRPL21\tRPL23\nRPL21\tRPL7\nRPL21\tRPS4X\nRPL21\tRPL4\nRPL21\tRPS24\nRPL21\tRPL34\nRPL21\tRPL31\nRPS13\tRPS20\nRPS13\tRPS27\nRPL18\tRPS2\nRPL18\tRPL18A\nRPS11\tRPS20\nNPTN\tRAB1A\nNPTN\tPRKAR1A\nMCM3AP\tOPHN1\nMCM3AP\tORC6L\nEIF4G1\tTHRAP5\n216412_x_at\tIGLV3-10\n216412_x_at\tIGLC2\nCXCR4\tLAPTM5\nCXCR4\tPRG1\nCXCR4\tHCLS1\nFAU\tRPS9\nFAU\tRPL35\nFAU\tRPS5\nFAU\tRPS16\nFAU\tRPL28\nRPL39\tRPL4\nRPL39\tRPS4X\nRPL39\tRPS20\nRPL39\tRPS15A\nRPL39\tRPS17\nRPL39\tRPS23\nIL2RG\tTRA@\nKIDINS220\tZFR\nKIDINS220\tSEPT7\nCOX4I1\tNDUFA7\nORC6L\tSLC25A16\nORC6L\tRPS11\nGBL\tGPX4\nATPIF1\tFIBP\nMGC2474\tTXNL2\nSEPT2\tSFRS11\nMT1F\tMT1L\nMT1F\tMT1X\nMT1F\tMT2A\nMT1F\tMT1G\nMT1F\tMT1H\nMT1F\tMT1M\nMT1L\tMT1M\nMT1L\tMT2A\nMT1L\tMT1X\nC11orf2\tFLJ14346\nATP6AP2\tPRKAR1A\nSTAT1\tTRIM22\nRPL35\tRPS9\nRPL35\tRPS5\nRPL35\tRPS16\nMT1E\tMT1L\nMT1E\tMT1F\nMT1E\tMT1G\nMT1E\tMT1X\nMT1E\tMT2A\nMT1E\tMT1M\nMT1E\tMT1H\nAKT1\tPGLS\nLOC56902\tMCM3AP\nLOC56902\tMGC2474\nHNRPM\tSERBP1\nCALD1\tPLEKHC1\nCALD1\tTPM1\nMT1M\tMT2A\nMT1M\tMT1X\nC17orf62\tIRF7\nKIAA1840\tPAPOLA\nDES\tTPM1\nMASP1\tPOLR2J\n212498_at\tTTC19\nHLA-DPB1\tHLA-DQB1\nHLA-DPB1\tHLA-DQA1\nHLA-DPB1\tHLA-DRB1\nHLA-DPB1\tHLA-DRB4\nHLA-DPB1\tHLA-DRB5\nFBXW12\tPRR11\nFBXW12\tRIOK3\nFBXW12\tPDE4C\nFBXW12\tFLJ42393\nFBXW12\tFLJ12151\nFBXW12\tPGF\nFBXW12\tSLC35E1\nFBXW12\tZNF611\nFBXW12\tLOC152719\nFBXW12\tKNS2\nFBXW12\tZNF160\nREEP5\tZMYND11\nPHIP\tZNF638\nRPS5\tRPS9\nWDR45\tZNF611\nMT1X\tMT2A\nCNOT2\tFLJ11021\nP4HB\tSEC61A1\nTMEM93\tUQCRFS1\nRPL37\tRPS15A\nRPL37\tRPS17\nRPL37\tRPS13\nRPL37\tRPL39\nACO2\tNDUFB2\nMT1G\tMT1L\nMT1G\tMT1M\nMT1G\tMT2A\nMT1G\tMT1H\nMT1G\tMT1X\nATP5J2\tUCRC\nRPL32\tRPL35A\nRPL32\tRPS15A\nRPL32\tRPS17\nRPL32\tRPL37\nGOLGA8A\tGOLGA8B\nCAST\tNFE2L2\nLOC645745\tMT1L\nLOC645745\tMT1F\nLOC645745\tMT2A\nLOC645745\tMT1M\nLOC645745\tMT1E\nLOC645745\tMT1X\nLOC645745\tMT1G\nLOC645745\tMT1H\nITGAV\tZMYND11\nCNN1\tMYH11\n208238_x_at\tRIOK3\nFLJ20294\tRPLP2\nFLJ20294\tRPS11\nFLJ20294\tRPL38\nFLJ20294\tH3F3A\nFLJ20294\tRPS20\nFLJ20294\tRPS19\nFLJ20294\tRPL27A\nFLJ20294\tRPL27\nSPCS2\tSRP9\n208120_x_at\tORC6L\n', - }, - { - kind: 'annotation', - name: 'Co-expression KEGG pathways', - fileName: 'NORMA_Human_coexpression_Annotation_KEGG.txt', - text: 'Ribosome\tRPS5,RPS5,RPL35,FAU,RPL18,RPL21,RPL36,RPL12,RPLP2,RPS19,RPL27,RPL10A,LOC440055,RPS27,LOC388344,RPL27A,RPS10,RPS17,RPL28,LOC283412,RPL23A,RPL36A,RPL7,RPS2,U16,RPL35A,RPL18A,RPL13,RPL29,RPS15A,RPS3A,RPL14,RPL22,RPL34,RPS27A,RPL9,RPL6,RPL4,RPS4X,RPS9,RPL13A,RPL17,RPL5,MDS1,LOC402057\nOxidative phosphorylation\tNDUFC1,NDUFC1,ATP5J2,NDUFA10,NDUFA7,COX4I1,ATP6V0D1,NDUFB6,UCRC,SDHA,ATP6V0B,UQCRC1,NDUFB2,UQCRFS1,NDUFA2,NDUFV1,ATP6V0C,NDUFA3,NDUFA13,NDUFS7,COX5B,ATP5D,NDUFS3,NDUFS8,COX5A,NDUFB4,NDUFAB1,ATP5G3,CYC1,COX8A,RPA1\nAntigen processing and presentation\tHLA-DPB1,HLA-DPB1,TAPBP,HLA-DMA,HLA-DQA1,HLA-J,HLA-B,HLA-DRA,HLA-DMB,HLA-DRB5,CD74,HLA-DRB1,HLA-E,HLA-DRB4,HSP90AA1,C6orf12,HLA-DQB1,HLA-DPA1,IFI30,HLA-A,HLA-G,EIF3S3,HLA-C\nCell adhesion molecules (CAMs)\tITGAV,ITGAV,HLA-DPB1,HLA-DMA,HLA-DQA1,HLA-J,HLA-B,HLA-DRA,HLA-DMB,SELL,HLA-DRB5,HLA-DRB1,HLA-E,HLA-DRB4,CD2,C6orf12,HLA-DQB1,HLA-DPA1,HLA-A,SPN,HLA-G,ITGB2,HLA-C\nType I diabetes mellitus\tHLA-DPB1,HLA-DPB1,HLA-DMA,HLA-DQA1,HLA-J,HLA-B,HLA-DRA,HLA-DMB,HLA-DRB5,HLA-DRB1,HLA-E,HLA-DRB4,C6orf12,HLA-DQB1,HLA-DPA1,HLA-A,HLA-G,HLA-C\nFocal adhesion\tITGAV,ITGAV,AKT1,RAP1B,LAMC1,PGF,MYLK,COL6A3,COL1A1,COL6A1,ROCK1,COL4A2,COL4A1,BIRC2,COL3A1,COL1A2,CAV1,RAC2\nNatural killer cell mediated cytotoxicity\tHLA-J,HLA-J,CD48,HLA-B,HLA-E,C6orf12,IFNGR1,HLA-A,LCK,HLA-G,RAC2,ITGB2,HLA-C\nRegulation of actin cytoskeleton\tITGAV,ITGAV,MSN,MYH9,MYLK,ARPC1B,ROCK1,ARPC3,ARPC5,IQGAP1,RAC2,ITGB2\nCell Communication\tDES,DES,LAMC1,COL6A3,COL1A1,COL6A1,COL4A2,COL4A1,COL3A1,COL1A2,RPL38\nPyrimidine metabolism\tPOLR2L,POLR2L,POLR2J,HMHA1,POLR1B,208246_x_at,POLR2I,RPS15A,POLR2E\nECM-receptor interaction\tITGAV,ITGAV,LAMC1,COL6A3,COL1A1,COL6A1,COL4A2,COL4A1,COL3A1,COL1A2\nPurine metabolism\tGUK1,GUK1,POLR2L,POLR2J,HMHA1,POLR1B,POLR2I,RPS15A,POLR2E,PDE4C\nHematopoietic cell lineage\tCD37,CD37,HLA-DRA,CD3D,HLA-DRB5,HLA-DRB1,HLA-DRB4,CD2,CD7,IL7R\nCytokine-cytokine receptor interaction\tIL2RG,IL2RG,CXCR4,CCL5,IL10RA,LTB,IFNGR1,TGFB1,IL7R,IL6ST\nLeukocyte transendothelial migration\tRAP1B,RAP1B,CXCR4,NCF1,MSN,CYBA,ROCK1,MMP2,RAC2,ITGB2\nJak-STAT signaling pathway\tAKT1,AKT1,STAT1,IL2RG,RAVER2,IL10RA,IFNGR1,IL7R,IL6ST\nCell cycle\tORC6L,ORC6L,YWHAZ,217718_s_at,TGFB1,CDKN1B,SKP1A\nRNA polymerase\tPOLR2L,POLR2L,POLR2J,HMHA1,POLR1B,POLR2I,POLR2E\nApoptosis\tAKT1,AKT1,PRKAR1A,ENDOG,PRKAR2A,BIRC2,PRKACB\nCholera - Infection\tSEC61A1,SEC61A1,ATP6V0D1,ATP6V0B,ATP6V0C\nPathogenic Escherichia coli infection - EPEC\tHCLS1,HCLS1,YWHAZ,ROCK1,NCL,RPL38,ARPC5\nPathogenic Escherichia coli infection - EHEC\tHCLS1,HCLS1,YWHAZ,ROCK1,NCL,RPL38,ARPC5\nEpithelial cell signaling in Helicobacter pylori infection\tATP6V0D1,ATP6V0D1,CCL5,ATP6V0B,ATP6V0C\nWnt signaling pathway\tROCK1,ROCK1,SKP1A,CSNK1A1,RAC2,PRKACB\nPancreatic cancer\tAKT1,AKT1,STAT1,RAVER2,PGF,TGFB1,RAC2\nMAPK signaling pathway\tAKT1,AKT1,RAP1B,TGFB1,RAC2,PRKACB\nInsulin signaling pathway\tAKT1,AKT1,PRKAR1A,PRKAR2A,PRKACB\nProtein export\tSEC61A1,SEC61A1,SRP72,SRP9\nUbiquitin mediated proteolysis\tTCEB2,TCEB2,SKP1A,UBE2D2\nCitrate cycle (TCA cycle)\tACO2,ACO2,SDHA,MDH2,RPA1\nTGF-beta signaling pathway\tROCK1,ROCK1,TGFB1,SKP1A\nCalcium signaling pathway\tMYLK,MYLK,ATP2A3,PRKACB\nHedgehog signaling pathway\tCSNK1A1,CSNK1A1,PRKACB\nChronic myeloid leukemia\tAKT1,AKT1,TGFB1,CDKN1B\nAxon guidance\tCXCR4,CXCR4,ROCK1,RAC2\nToll-like receptor signaling pathway\tAKT1,AKT1,STAT1,CCL5\nTight junction\tAKT1,AKT1,MYH9,HCLS1\nGlycan structures - degradation\tPOPDC3,POPDC3,MAN2B1\nColorectal cancer\tAKT1,AKT1,TGFB1,RAC2\nB cell receptor signaling pathway\tAKT1,AKT1,CD79A,RAC2\nPrion disease\tNFE2L2,NFE2L2,LAMC1\nT cell receptor signaling pathway\tAKT1,AKT1,CD3D,LCK\nLong-term potentiation\tRAP1B,RAP1B,PRKACB\nAdherens junction\tIQGAP1,IQGAP1,RAC2\nGlycan structures - biosynthesis 2\tCOL6A3,COL6A3,OGT\nGnRH signaling pathway\tMMP2,MMP2,PRKACB\nAdipocytokine signaling pathway\tAKT1,AKT1,RAVER2\nBasal transcription factors\tTAF7,TAF7,GTF2I\nVEGF signaling pathway\tAKT1,AKT1,RAC2\nReductive carboxylate cycle (CO2 fixation)\tACO2,ACO2,MDH2\nGlyoxylate and dicarboxylate metabolism\tACO2,ACO2,MDH2\nGlutathione metabolism\tGPX1,GPX1,GPX4\nFc epsilon RI signaling pathway\tAKT1,AKT1,RAC2\nArachidonic acid metabolism\tGPX1,GPX1,GPX4\nmTOR signaling pathway\tAKT1,AKT1,PGF\nTyrosine metabolism\tECH1,ECH1,MIF\n', - }, - { - kind: 'annotation', - name: 'Co-expression GO biological process', - fileName: 'NORMA_Human_coexpression_Annotation_GO_BP.txt', - text: 'protein biosynthesis\tRPS15,RPS15,RPL37,RPS5,RPL35,FAU,RPS11,RPS21,RPL18,RPS13,RPL21,RPL36,RPL12,RPLP2,RPS19,RPL27,RPL31,MRPS12,LOC440055,RPS27,LOC388344,RPL27A,RPS10,RPS17,RPL28,LOC283412,RPL19,RPS16,RPS14,NARS,RPL7,RPS6,RPS2,U16,NACA,RPL18A,RPL13,RPL29,RPS15A,RPS20,RPS3A,RPS18,RPL14,MRPL34,RPL22,RPL34,RPS27A,EEF1D,RPL15,RPL9,RPL6,RPL26,RPL4,RPS4X,RPS24,RPS9,RPL13A,RPL17,EEF1A1,RPL5,RPL23,MDS1,RPS7,LOC402057,RPS25\nimmune response\tHLA-DPB1,HLA-DPB1,TAPBP,IL2RG,HLA-DMA,HLA-DQA1,IL16,221651_x_at,IGLV3-10,ARL6IP2,HLA-B,CD164,HLA-DRA,HLA-DMB,TRIM22,HLA-DRB5,HLA-DRB1,IGL@,IGLC1,IGLV3-25,TRB@,HLA-DRB4,LTB,ARHGDIB,C6orf12,HLA-DQB1,HLA-DPA1,TRBV3-1,GPSM3,IGLC2,TRA@,214836_x_at,IGHV1-69,IGHA1,HLA-A,CD7,IGHG3,IGLJ3,IL7R,IL6ST,HLA-C,IGKC,IGHM\nsignal transduction\tAKT1,AKT1,STAT1,IL2RG,CXCR4,OPHN1,CCL5,PGF,INPP5D,PRKAR1A,CD164,RPS27,HLA-DRB5,CD74,HLA-DRB1,PRKAR2A,CD53,HLA-DRB4,LTB,HSP90AA1,OGT,ROCK1,IFNGR1,PTGES3,HMGB1,GTF2I,GNB2L1,CAP1,SPN,NPM1,IQGAP1,PAFAH1B1,EIF3S3,RAC2,COPS2,PRKACB,PDE4C\nantigen presentation, endogenous antigen\tHLA-J,HLA-J,RPLP2,221651_x_at,IGLV3-10,IGHD,HLA-B,CD74,IGL@,IGLC1,HLA-E,IGLV3-25,C6orf12,IGLC2,214836_x_at,IGHV1-69,IGHA1,HLA-F,HLA-A,IGHG3,IGLJ3,HLA-G,HLA-C,IGKC,IGHM\nantigen processing, endogenous antigen via ...\tCAST,CAST,HLA-J,RPLP2,221651_x_at,IGLV3-10,IGHD,HLA-B,IGL@,IGLC1,HLA-E,IGLV3-25,C6orf12,IGLC2,214836_x_at,IGHV1-69,IGHA1,HLA-F,HLA-A,IGHG3,IGLJ3,HLA-G,HLA-C,IGKC,IGHM\nregulation of transcription, DNA-dependent\tNFE2L2,NFE2L2,STAT1,MGC2474,LYSMD4,ZMYND11,ZNF160,CDC5L,TRIM22,SFPQ,IFI16,HCLS1,ATRX,HMGB1,CSDE1,SCAND1,RPL6,LOC342346,SUB1\nelectron transport\tMT1X,MT1X,MT1L,COX4I1,NCF1,SDHA,UQCRQ,UQCRC1,GPX4,UQCRFS1,NDUFV1,COX5B,NDUFS3,NDUFS8,COX5A,NDUFB4,CYC1,COX8A,RPA1\nprotein amino acid phosphorylation\tAKT1,AKT1,RAVER2,GMFG,PRKAR1A,PRKD2,MYLK,PRKAR2A,ROCK1,TGFB1,PCM1,U16,LCK,CSNK1A1,HNRPDL,RPL4,PRKACB\nantigen processing, exogenous antigen via M...\tHLA-DPB1,HLA-DPB1,HLA-DMA,HLA-DQA1,HLA-DRA,HLA-DMB,HLA-DRB5,HLA-DRB1,HLA-DRB4,HLA-DQB1,HLA-DPA1\nantigen presentation, exogenous antigen\tHLA-DPB1,HLA-DPB1,HLA-DMA,HLA-DQA1,HLA-DRA,HLA-DMB,HLA-DRB5,HLA-DRB1,HLA-DRB4,HLA-DQB1,HLA-DPA1\ncell adhesion\tITGAV,ITGAV,LAMC1,CCL5,FNBP4,ADRM1,CD164,TGFB1I1,SELL,DGCR6,COL6A1,PLEKHC1,CD2,ITGB2\nintracellular signaling cascade\tSTAT1,STAT1,RAVER2,INPP5D,PRKAR1A,PRKD2,NCF1,PRKAR2A,WSB1,HCLS1,HMHA1,ROCK1,LCK\ntranscription from RNA polymerase II promoter\tTARDBP,TARDBP,NFE2L2,STAT1,POLR2J,TGFB1I1,TCEA1,HMHA1,POLR2I,BTF3,COPS2,POLR2E\ncell motility\tCALD1,CALD1,CAPZA1,CCL5,TPM1,MSN,ACTR3,ARPC1B,ARHGDIB,ARPC3,ARPC5,PAFAH1B1\ndetection of pest, pathogen or parasite\tHLA-DPB1,HLA-DPB1,HLA-DMA,HLA-J,HLA-DMB,HLA-DRB5,HLA-DRB1,HLA-DRB4,HLA-G\nnuclear mRNA splicing, via spliceosome\tHNRPM,HNRPM,SFRS10,HNRPH3,SFPQ,HIATL1,RPL35A,SF3B1,HNRPA2B1,HNRPA1\nmitochondrial electron transport, NADH to u...\tNDUFC1,NDUFC1,NDUFB6,NDUFB2,NDUFV1,NDUFS7,NDUFS3,NDUFS8,NDUFB4\ndevelopment\tCECR1,CECR1,CLPTM1,CD164,ARHGDIB,COL6A3,MYH11,ITGB2,DDX1\nphosphate transport\tCOL6A3,COL6A3,COL1A1,COL6A1,COL4A2,COL4A1,COL3A1,COL1A2\nantigen presentation\tHLA-J,HLA-J,HLA-B,HLA-E,C6orf12,HLA-F,HLA-A,HLA-G,HLA-C\ntransport\tG3BP,G3BP,SLC25A16,UCP2,SLC25A11,TMED5,SLC25A3,ATP2A3\ncell proliferation\tRPS21,RPS21,PGF,ZMYND11,RPS27,CD74,IFI16,MIF,ISG20\nanti-apoptosis\tAKT1,AKT1,FAIM3,SON,HMGB1,HSP90B1,NPM1,TPT1,PRDX2\ncell surface receptor linked signal transdu...\tCD3D,CD3D,CD2,CD79A,BIRC2,MIF,CSNK1A1,IL7R,IL6ST\ngeneration of precursor metabolites and energy\tACO2,ACO2,ATPIF1,COX4I1,ECH1,UQCR,SLC25A3,COX8A\nprotein complex assembly\tTAPBP,TAPBP,CAPZA1,GPAA1,LAMC1,TCEB2,CD3D,CD74\nmRNA processing\tSFPQ,SFPQ,SRP46,DHX15,HNRPR,SFRS11,SFRS5,RNPC2\npositive regulation of cell proliferation\tSSR1,SSR1,CAPNS1,PGF,RPL31,HCLS1,TGFB1,NAP1L1\nRNA splicing\tHNRPH3,HNRPH3,SFPQ,DHX15,PPP2CA,ZNF638,SFRS11\ntranscription\tLYSMD4,LYSMD4,POLR2J,ZNF160,SFPQ,POLR1B,PCM1\nregulation of translational initiation\tEIF4G1,EIF4G1,EIF4A2,EIF4G2,EIF5,EIF3S3,DDX1\npathogenesis\tHLA-DPB1,HLA-DPB1,HLA-DRB5,HLA-DRB1,HLA-DRB4\nproton transport\tATP5J2,ATP5J2,ATP6V0D1,UCP2,ATP6V0B,ATP6V0C\nRNA processing\tHNRPU,HNRPU,RBPMS,DDX17,HNRPH1,HNRPDL,RNPC2\nregulation of transcription from RNA polyme...\tTHRAP5,THRAP5,PRKAR1A,HMGB1,LOC342346,SUB1\nprotein transport\tRAB1A,RAB1A,RAB6A,RAB6C,TLOC1,HSP90B1,COPB\nsmall GTPase mediated signal transduction\tRAP1B,RAP1B,RGS19,RAB1A,RAB6A,RAB6C,RPL29\nresponse to virus\tCCL5,CCL5,IRF7,TRIM22,IFI16,IFNGR1,ISG20\ninflammatory response\tCCL5,CCL5,IRF7,MEFV,ALOX5AP,TGFB1,ITGB2\nactin cytoskeleton organization and biogenesis\tARHGDIB,ARHGDIB,PLEKHC1,DST,ROCK1,ARPC5\nprotein folding\tPPIB,PPIB,HSP90AA1,HSP90B1,EIF3S3,KTN1\ninduction of apoptosis\tCD2,CD2,PPP2CA,BCLAF1,LCK,RPS3A,SCAND1\nskeletal development\tCNOT2,CNOT2,COL1A1,TGFB1,COL1A2,MYH11\nregulation of progression through cell cycle\tSTAT1,STAT1,PGF,ERH,PPP2CA,LCK,SCAND1\nnegative regulation of cell proliferation\tCD164,CD164,TGFB1I1,TGFB1,CDKN1B,NPM1\ncellular defense response\tHLA-J,HLA-J,CCL5,NCF1,FAIM3,SPN,HLA-G\ntranslational elongation\tRPLP2,RPLP2,TUFM,EEF1B2,EEF1D,EEF1A1\nmuscle development\tTAGLN,TAGLN,LYSMD4,SMTN,COL6A3,MBNL1\nATP synthesis coupled proton transport\tATP6V0B,ATP6V0B,ATP6V0C,ATP5D,ATP5G3\nproteolysis\tCAST,CAST,MASP1,YME1L1,MMP2,IGHG3\nmicrotubule-based movement\t220725_x_at,220725_x_at,KNS2,KTN1\nmetabolism\tACO2,ACO2,ECH1,POPDC3,IGLC2,DIP2A\napoptosis\tAD7C-NTP,AD7C-NTP,FIS1,ITGB2,CROP\namino acid transport\tSLC38A2,SLC38A2,218041_x_at,RPL24\nresponse to unfolded protein\tHSP90AA1,HSP90AA1,HSP90B1,EIF3S3\nintracellular protein transport\tVDP,VDP,NAPA,CLTC,CD74,NPM1,COPE\ntranscription initiation from RNA polymeras...\tTHRAP5,THRAP5,IRF7,THRAP1,GTF2I\nresponse to oxidative stress\tCCL5,CCL5,GPX1,GPX4,CSDE1,PRDX2\nnucleobase, nucleoside, nucleotide and nucl...\tNDUFA10,NDUFA10,ERH,208246_x_at\ncarbohydrate metabolism\tLOC91316,LOC91316,MAN2B1,AKR7A2\nprotein modification\tSUMO2,SUMO2,RPN1,MAN2B1,RPS27A\nubiquitin-dependent protein catabolism\tUSP34,USP34,UBE4A,PSMB9,PSMB8\ndefense response\tCD48,CD48,PTPRCAP,HLA-B,CD79A\nDNA replication\tMCM3AP,MCM3AP,NARS,NAP1L1,SET\nandrogen receptor signaling pathway\tTHRAP5,THRAP5,THRAP1,TGFB1I1\nprotein targeting to mitochondrion\tTIMM8B,TIMM8B,TOMM20,TIMM13\noxygen transport\tSLC38A2,SLC38A2,218041_x_at\nG-protein coupled receptor protein signalin...\tAKT1,AKT1,RGS19,CXCR4,FNBP4\nnervous system development\tOPHN1,OPHN1,MBNL1,PAFAH1B1\nmitochondrial transport\tUCP2,UCP2,HSP90AA1,EIF3S3\nembryo implantation\tLOC283412,LOC283412,RPL29\nDNA repair\tSFPQ,SFPQ,ATRX,HMGB1,RPA1\nprotein refolding\tHSP90AA1,HSP90AA1,EIF3S3\npositive regulation of nitric oxide biosynt...\tHSP90AA1,HSP90AA1,EIF3S3\nlipid metabolism\tPAFAH1B1,PAFAH1B1,ATP8B1\ncell cycle arrest\tEIF4G2,EIF4G2,DST,CDKN1B\ncell cycle\tCUL4B,CUL4B,RPS27A,SEPT7\nprotein ubiquitination\tUBE4A,UBE4A,PCNP,RPS27A\nprotein targeting\tTOMM20,TOMM20,SRP9,COPB\nnucleosome assembly\tNAP1L1,NAP1L1,SET,H3F3A\nnegative regulation of cell adhesion\tCD164,CD164,ARHGDIB,SPN\ncell-cell signaling\tCCL5,CCL5,PGF,LTB,ITGB2\npositive regulation of transcription\tTGFB1I1,TGFB1I1,RPS27A\nnegative regulation of transcription\tIRF7,IRF7,SUMO1,BCLAF1\nhemopoiesis\tCD164,CD164,ZNF160,LCK\ncellular defense response (sensu Vertebrata)\tIGHA1,IGHA1,IGHG3,IGHM\nretrograde vesicle-mediated transport, Golg...\tTAPBP,TAPBP,COPE,COPB\nprotein import into nucleus\tMCM3AP,MCM3AP,NDUFA13\npositive regulation of transcription, DNA-d...\tTGFB1I1,TGFB1I1,TGFB1\nnegative regulation of cell growth\tPPP2CA,PPP2CA,NDUFA13\nintegrin-mediated signaling pathway\tITGAV,ITGAV,DST,ITGB2\ncotranslational protein targeting to membrane\tSSR1,SSR1,TLOC1,TRAM1\nRho protein signal transduction\tARHGDIB,ARHGDIB,ROCK1\nsensory perception of sound\tTIMM8B,TIMM8B,TIMM13\nregulation of translation\tPPP2CA,PPP2CA,EEF1A1\nregulation of transcription\tPOLR2L,POLR2L,PPP2CA\nprostaglandin biosynthesis\tCD74,CD74,PTGES3,MIF\nmitosis\tTARDBP,TARDBP,CORO1A\ninsulin receptor signaling pathway\tPHIP,PHIP,AKT1,MYH11\nDNA recombination\tATRX,ATRX,HMGB1,RPA1\ntricarboxylic acid cycle\tACO2,ACO2,SDHA,RPA1\nnegative regulation of transcription, DNA-d...\tRPS14,RPS14,NDUFA13\nintra-Golgi vesicle-mediated transport\tNAPA,NAPA,COPE,COPB\ncell death\tEIF4G2,EIF4G2,TGFB1\nprotein amino acid autophosphorylation\tRPS2,RPS2,U16,RPL4\ncirculation\tRPL31,RPL31,COL3A1\ncalcium ion transport\tATP2A3,ATP2A3,TPT1\naxon guidance\tOPHN1,OPHN1,RPS27A\nER-associated protein catabolism\tRPL27,RPL27,RPS27A\nregulation of actin filament polymerization\tARPC3,ARPC3,ARPC5\npositive regulation of I-kappaB kinase/NF-k...\tBIRC2,BIRC2,EEF1D\norgan morphogenesis\tDGCR6,DGCR6,TGFB1\nnegative regulation of transcription from R...\tIRF7,IRF7,ZMYND11\nmRNA splice site selection\tSRP46,SRP46,SFRS5\nerythrocyte differentiation\tRPS19,RPS19,HCLS1\ncytokinesis\tSEPT2,SEPT2,SEPT7\nchromosome segregation\tARL8B,ARL8B,RIOK3\ncell-matrix adhesion\tITGAV,ITGAV,ITGB2\nactivation of NF-kappaB transcription factor\tU16,U16,NPM1,RPL4\nT cell activation\tCD3D,CD3D,CD2,CD7\nubiquitin cycle\tTPT1,TPT1,UBE2D2\nregulation of cell adhesion\tNPTN,NPTN,PPP2CA\ncell growth\tTGFB1,TGFB1,DDX5\nangiogenesis\tCAST,CAST,ATPIF1\ntranslational initiation\tEIF5,EIF5,RPS3A\ntransforming growth factor beta receptor si...\tFNTA,FNTA,TGFB1\nresponse to drug\tRAB6C,RAB6C,LCK\nregulation of apoptosis\tTPT1,TPT1,PRDX2\nchromosome organization and biogenesis (sen...\tATRX,ATRX,H3F3A\ncaspase activation\tSTAT1,STAT1,LCK\nantimicrobial humoral response (sensu Verte...\tIL7R,IL7R,ITGB2\nI-kappaB kinase/NF-kappaB cascade\tPHIP,PHIP,STAT1\ntransmembrane receptor protein tyrosine kin...\tCD7,CD7,COL1A2\nresponse to stress\tNPM1,NPM1,CROP\nresponse to metal ion\tMT1X,MT1X,MT1L\ncalcium ion homeostasis\tCCL5,CCL5,TPT1\nregulation of macrophage activation\tCD74,CD74,MIF\nnucleocytoplasmic transport\tNPM1,NPM1,SET\nnegative regulation of apoptosis\tCD74,CD74,MIF\nmuscle contraction\tDES,DES,CALD1\nestablishment and/or maintenance of cell po...\tCAP1,CAP1,SPN\nchemotaxis\tCCL5,CCL5,SPN\nRas protein signal transduction\tG3BP,G3BP,LCK\nregulation of heart contraction\tDES,DES,TPM1\nactivation of MAPKK activity\tU16,U16,RPL4\nJNK cascade\tU16,U16,RPL4\ncytoskeleton organization and biogenesis\tDES,DES,DST\n', - }, - { - kind: 'annotation', - name: 'Co-expression GO molecular function', - fileName: 'NORMA_Human_coexpression_Annotation_GO_MF.txt', - text: "protein binding\tTARDBP,TARDBP,ITGAV,CAST,RPS15,PHIP,NFE2L2,OAZ1,STAT1,SEPT2,TXNL2,ORC6L,IL2RG,RGS19,EIF4G1,RPS13,C1orf160,RAB6A,HLA-DMA,ZNHIT1,GPAA1,CUL4B,HLA-J,KPNB1,ARF1,IL16,CD48,CBX3,G3BP,SUMO2,ACTA2,TCEB2,EIF3S6,MT1H,RPS19,INPP5D,RAB6C,RNF11,PRKAR1A,NCF1,ZMYND11,HNRPK,SUMO1,TGFB1I1,CDC5L,KNS2,RBPMS,CAB39,SFPQ,CD3D,NAPA,ACTR3,CLTC,TTC3,EIF4A2,IFI16,ARL6IP5,EEF1B2,HCLS1,PSMB8,HMHA1,HSP90AA1,HNRPH1,SRP46,EIF4G2,FIS1,PLEKHC1,CD2,OGT,TAF7,217718_s_at,NARS,C6orf12,TGFB1,CDKN1B,NDUFA13,GPSM3,BCLAF1,HSP90B1,SERBP1,GTF2I,RPS6,U16,BIRC2,RPL35A,HLA-A,RPS15A,EXOSC4,RPS20,RPL38,ACTG2,CAV1,ACTR2,SKP1A,ACTR10,MIF,PCNP,RPS3A,RPL14,HLA-G,IL7R,AURKAIP1,FIBP,EIF3S3,HNRPDL,RPS27A,RAC2,ITGB2,COPS2,XPO1,SIAHBP1,POLR2E,NAP1L1,RPL4,SFRS5,HNRPA2B1,EEF1A1,UBE2D2,SEPT7,COPB,ATP5G3,RPL5,RPS7,RPA1,HNRPA1,RPL24\nRNA binding\tTARDBP,TARDBP,RPS5,HNRPM,LOC56902,EIF4G1,RPL18,RPL21,SFRS10,RPLP2,G3BP,HNRPH3,HNRPU,DDX42,RPS19,HNRPK,RBPMS,LOC440055,RPS27,LOC388344,SFPQ,DDX17,RPL27A,RPS10,RPS17,EIF4A2,RPL28,LOC283412,RPS14,HNRPH1,SRP46,EIF4G2,HNRPR,NCL,RPL7,HSP90B1,SRP9,HNRPA3P1,RPS2,U16,DDX5,ZNF638,RPL18A,RPL13,RPL29,SFRS11,DDX50,NPM1,RPS18,RPL14,PAPOLA,RPL22,MATR3,HNRPDL,RPL34,SCAND1,RPL9,RPL6,SIAHBP1,RPL4,RPS4X,SFRS5,SFRS3,HNRPA2B1,RPS9,RNPC2,RPL5,MDS1,LOC402057,HNRPA1\nstructural constituent of ribosome\tRPS15,RPS15,RPL37,RPS5,RPL35,FAU,RPS11,RPS21,RPL18,RPS13,RPL21,RPL36,RPL12,RPLP2,RPS19,RPL27,RPL31,MRPS12,LOC440055,RPS27,LOC388344,RPL27A,RPS10,RPS17,RPL28,LOC283412,RPL19,RPS16,RPS14,RPL7,RPS6,RPS2,U16,RPL18A,RPL13,RPL29,RPS15A,RPS20,RPS3A,RPS18,RPL14,MRPL34,RPL22,RPL34,RPS27A,RPS23,RPL15,RPL9,RPL6,RPL26,RPL4,RPS4X,RPS24,RPS9,RPL13A,RPL17,RPL5,RPL23,MDS1,RPS7,LOC402057,RPS25\nnucleotide binding\tTARDBP,TARDBP,HNRPM,RAP1B,MCM3AP,RAB1A,RAB6A,RAVER2,SFRS10,G3BP,HNRPH3,ACTA2,DDX42,RAB6C,PRKD2,RBPMS,YME1L1,SFPQ,DDX17,EIF4A2,HSP90AA1,HNRPH1,SRP46,NARS,HNRPR,NCL,PCM1,HSP90B1,HNRPA3P1,U16,DDX5,ACTG2,SFRS11,DDX50,CSNK1A1,EIF3S3,MATR3,HNRPDL,DDX3X,SIAHBP1,RPL4,SFRS5,HNRPA2B1,EEF1A1,RNPC2,SEPT7,PRKACB,HNRPA1\nnucleic acid binding\tTARDBP,TARDBP,ZFR,HNRPM,LOC56902,MGC2474,RPS11,SFRS10,G3BP,HNRPH3,ZNF9,DDX42,HNRPK,ZNF160,MRPS12,SFPQ,DDX17,R3HCC1,EIF4A2,IFI16,HNRPH1,SRP46,NARS,ZNF611,SON,HNRPR,DDX5,SFRS11,DDX50,ZNF552,NPM1,MBNL1,MATR3,HNRPDL,DDX3X,SIAHBP1,SFRS5\nATP binding\tNDUFA10,NDUFA10,AKT1,RAVER2,ACTA2,DDX42,PRKD2,MYH9,220725_x_at,YME1L1,DDX17,EIF4A2,HSP90AA1,208246_x_at,DHX15,NARS,ROCK1,NDUFA13,PCM1,HSP90B1,ATP2A3,RPS2,U16,DDX5,LCK,MYH11,ACTG2,DDX50,CSNK1A1,EIF3S3,DDX3X,RPL4,PRKACB\nreceptor activity\tITGAV,ITGAV,HNRPM,IL2RG,CXCR4,THRAP5,PTPRCAP,RPL27,IL10RA,THRAP1,TLOC1,HLA-DRB5,HLA-DRB1,HLA-DRB4,CD2,IFNGR1,TRBV3-1,IGHA1,U16,CD7,IGHG3,IL7R,IL6ST,RPL4,EEF1A1,IGHM,TRAM1\nMHC class I receptor activity\tHLA-J,HLA-J,RPLP2,221651_x_at,IGLV3-10,IGHD,HLA-B,IGL@,IGLC1,HLA-E,IGLV3-25,C6orf12,IGLC2,214836_x_at,IGHV1-69,IGHA1,HLA-F,HLA-A,IGHG3,IGLJ3,HLA-G,HLA-C,IGKC,IGHM\nzinc ion binding\tCAST,CAST,ZFR,MT1E,MT1F,KPNB1,MSRB2,TIMM8B,ZNF9,DDX42,RNF11,PRKD2,SDHA,ZMYND11,ZNF160,MEFV,RPS27,TTC3,ZNF611,TIMM13,POLR2I,MMP2,ZNF552,MBNL1,MATR3\nbinding\tSRP72,SRP72,VDP,CAPZA1,TTC19,KPNB1,SLC25A16,MSN,UCP2,KNS2,CAB39,RGPD5,NAPA,SLC25A11,TTC3,SLC25A3,ALOX5AP,HIATL1,OGT,CHCHD2,SF3B1,COPS2,COPE,COPB\nDNA binding\tMCM3AP,MCM3AP,HNRPU,RNF11,IRF7,SDHA,POLR2L,POLR2J,CDC5L,SFPQ,POLR1B,SON,HMGB1,PCM1,BCLAF1,CSDE1,RPL6,LOC342346,SUB1,LOC58486,H3F3A\nNADH dehydrogenase (ubiquinone) activity\tNDUFC1,NDUFC1,NDUFA10,NDUFA7,NDUFB6,NDUFB2,NDUFA2,NDUFV1,NDUFA3,NDUFA13,NDUFS7,NDUFS3,NDUFS8,NDUFB4,NDUFAB1\nMHC class II receptor activity\tHLA-DPB1,HLA-DPB1,HLA-DMA,HLA-DQA1,HLA-DRA,HLA-DMB,HLA-DRB5,HLA-DRB1,HLA-DRB4,HLA-DQB1,HLA-DPA1,HLA-C\nelectron carrier activity\tP4HB,P4HB,MT1X,MT1L,NCF1,UQCR,CYBA,FLJ14346,NDUFS3,NDUFS8,COX5A,ETFB,KTN1,AKR7A2,CYC1\nGTPase activity\tSEPT2,SEPT2,RAB6A,ARF1,RAB6C,NCF1,ARL6IP2,ARF5,ARL8B,RPL29,EIF5,RAC2,EEF1A1\nantigen binding\tIGL@,IGL@,IGLC1,IGLV3-25,IGLC2,IGHV1-69,IGHA1,IGHG3,IGLJ3,IL7R,IGKC,IGHM\ntransferase activity\tFNTA,FNTA,PRKD2,POLR2J,POLR1B,COL6A3,NARS,RPS2,U16,CSNK1A1,RPL4,PRKACB\ntranscription factor activity\tTARDBP,TARDBP,NFE2L2,STAT1,LYSMD4,MSRB2,TRIM22,HCLS1,GTF2I,SCAND1,MDS1\nmetal ion binding\tMT1X,MT1X,ZFR,MT1M,MT1L,PRKD2,ZNF160,TTC3,ZNF611,ZNF552,MATR3,NDUFS8\nstructural molecule activity\tDES,DES,FNBP4,CORO1A,NPEPPS,CLTC,COL6A3,RPL38,CAV1,MATR3,SEPT7\nGTP binding\tRAP1B,RAP1B,RAB1A,RAB6A,RAB6C,NCF1,ARL6IP2,ARL8B,EEF1A1,SEPT7\nextracellular matrix structural constituent\tLAMC1,LAMC1,FBLN1,COL1A1,COL6A1,COL4A2,COL4A1,COL3A1,COL1A2\nstructural constituent of cytoskeleton\tDES,DES,ADD3,ACTA2,TPM1,MSN,ARPC1B,DST,ACTG2,ARPC3,ARPC5\nhydrolase activity\tDDX42,DDX42,PPP1CA,DDX17,EIF4A2,PPP2CA,DDX5,DDX50,DDX3X\nunfolded protein binding\tTAPBP,TAPBP,PPIB,HSP90AA1,PTGES3,HSP90B1,NPM1,EIF3S3\ntransporter activity\tG3BP,G3BP,UCP2,ATP6V0B,SLC25A11,SLC25A3,ATP5D,ATP5G3\nkinase activity\tGUK1,GUK1,MYLK,PRKAR2A,WSB1,208246_x_at,ROCK1,CDKN1B\niron ion binding\tACO2,ACO2,MT1X,MT1L,PPP1CA,NDUFV1,PPP2CA,NDUFS8,CYC1\nDNA-directed RNA polymerase activity\tPOLR2L,POLR2L,POLR2J,HMHA1,POLR1B,PCM1,POLR2I,POLR2E\nATP-dependent helicase activity\tDDX42,DDX42,DDX17,EIF4A2,DHX15,DDX5,DDX50,DDX3X,DDX1\nprotein serine/threonine kinase activity\tAKT1,AKT1,PRKD2,ROCK1,RPS2,U16,CSNK1A1,RPL4,PRKACB\ncalcium ion binding\tMASP1,MASP1,SPARCL1,STAT1,FBLN1,HSP90B1,IGHG3,TPT1\nactin binding\tCNN1,CNN1,CALD1,CAPZA1,GMFG,SMTN,MEFV,NPEPPS,FXYD5\nprotein homodimerization activity\tATPIF1,ATPIF1,HSP90AA1,U16,NPM1,EIF3S3,RPL4\nsignal transducer activity\tSTAT1,STAT1,RGS19,BIRC2,HNRPDL,EEF1D,COPS2\noxidoreductase activity\tNDUFA10,NDUFA10,GPX1,MDH2,GPX4,IGLC2,PRDX2\ntranscription coactivator activity\tTGFB1I1,TGFB1I1,TAF7,NPM1,LOC342346,SUB1\ntranslation initiation factor activity\tEIF4G1,EIF4G1,EIF4A2,EIF4G2,EIF5,EIF3S3\nprotein-tyrosine kinase activity\tRAVER2,RAVER2,PCM1,U16,LCK,HNRPDL,RPL4\ncatalytic activity\tKIAA1840,KIAA1840,LOC91316,DIP2A,PDE4C\nhydrogen-transporting ATPase activity, rota...\tATP6V0B,ATP6V0B,ATP6V0C,ATP5D,ATP5G3\nhydrogen-transporting ATP synthase activity...\tATP6V0B,ATP6V0B,ATP6V0C,ATP5D,ATP5G3\nhematopoietin/interferon-class (D200-domain...\tSTAT1,STAT1,IL2RG,IL10RA,IFNGR1,IL7R\noxidoreductase activity, acting on NADH or ...\tNDUFV1,NDUFV1,NDUFS7,NDUFS3,NDUFS8\nsingle-stranded DNA binding\tHNRPDL,HNRPDL,LOC342346,SUB1,RPA1\namino acid-polyamine transporter activity\tSLC38A2,SLC38A2,218041_x_at,RPL24\nreceptor binding\tCCL5,CCL5,ARPP-19,MSN,LTB,GNB2L1\ncalmodulin binding\tCALD1,CALD1,MARCKS,ATPIF1,IQGAP1\ncytochrome-c oxidase activity\tCOX4I1,COX4I1,COX5B,COX5A,COX8A\nubiquinol-cytochrome-c reductase activity\tUCRC,UCRC,UQCRQ,UQCRC1,UQCRFS1\nprotein transporter activity\tVDP,VDP,KPNB1,TLOC1,AP2S1,COPE\ntranslation elongation factor activity\tTUFM,TUFM,EEF1B2,EEF1D,EEF1A1\npeptide antigen binding\tTAPBP,TAPBP,TRB@,TRBV3-1,TRA@\nmicrotubule motor activity\t220725_x_at,220725_x_at,KNS2\nphosphotransferase activity, alcohol group ...\tNDUFA10,NDUFA10,208246_x_at\noxygen transporter activity\tSLC38A2,SLC38A2,218041_x_at\nRNA helicase activity\tDDX17,DDX17,DHX15,DDX5,DDX1\ngrowth factor activity\tCECR1,CECR1,GMFG,PGF,TGFB1\nRNA splicing factor activity, transesterifi...\tSFRS10,SFRS10,HIATL1,SF3B1\nheparin binding\tLOC283412,LOC283412,RPL29\ndouble-stranded DNA binding\tIFI16,IFI16,ZNF638,HNRPDL\nRNA polymerase II transcription mediator ac...\tCNOT2,CNOT2,THRAP5,THRAP1\nnitric-oxide synthase regulator activity\tHSP90AA1,HSP90AA1,EIF3S3\nisomerase activity\tP4HB,P4HB,ECH1,PPIB,KTN1\nTPR domain binding\tHSP90AA1,HSP90AA1,EIF3S3\nubiquitin-protein ligase activity\tUBE4A,UBE4A,TPT1,UBE2D2\nprotein domain specific binding\tYWHAZ,YWHAZ,217718_s_at\ncAMP-dependent protein kinase regulator act...\tPRKAR1A,PRKAR1A,PRKAR2A\ntranscriptional repressor activity\tIRF7,IRF7,IFI16,BCLAF1\nprotein kinase binding\tU16,U16,LCK,ITGB2,RPL4\ngeneral RNA polymerase II transcription fac...\tTCEA1,TCEA1,TAF7,GTF2I\nMHC protein binding\tTRB@,TRB@,TRBV3-1,TRA@\nATP-dependent RNA helicase activity\tG3BP,G3BP,RPL35A,DDX3X\nprotein heterodimerization activity\tCD3D,CD3D,PPP2CA,NPM1\npeptidase activity\tMASP1,MASP1,ZNF9,CLPP\nidentical protein binding\tAKT1,AKT1,CD74,SCAND1\nvitamin D receptor binding\tTHRAP5,THRAP5,THRAP1\nthyroid hormone receptor binding\tTHRAP5,THRAP5,THRAP1\nserine-type endopeptidase inhibitor activity\tNFE2L2,NFE2L2,COL6A3\nsequence-specific DNA binding\tNFE2L2,NFE2L2,LYSMD4\nprotein dimerization activity\tNFE2L2,NFE2L2,POLR2J\nmotor activity\tMYH9,MYH9,KNS2,MYH11\ncopper ion binding\tMT1E,MT1E,MT1F,DDX42\ncadmium ion binding\tMT1E,MT1E,MT1F,DDX42\ntransmembrane receptor activity\tCD3D,CD3D,CD79A,SPN\ntranslation factor activity, nucleic acid b...\tEIF3S3,EIF3S3,EEF1D\ntranscriptional activator activity\tTHRAP5,THRAP5,TGFB1\n3'-5'-exoribonuclease activity\tEXOSC4,EXOSC4,ISG20\ntropomyosin binding\tCALD1,CALD1,LMOD1\ntranscription factor binding\tYWHAZ,YWHAZ,HMGB1\nthreonine endopeptidase activity\tPSMB9,PSMB9,PSMB8\nserine-type endopeptidase activity\tMASP1,MASP1,IGHG3\nperoxidase activity\tCSDE1,CSDE1,PRDX2\nenzyme activator activity\tGMFG,GMFG,ALOX5AP\nantioxidant activity\tRPL27,RPL27,PRDX2\nactin filament binding\tMARCKS,MARCKS,DST\nacetylglucosaminyltransferase activity\tCOL6A3,COL6A3,OGT\nATPase binding\tATPIF1,ATPIF1,LCK\ntranscription regulator activity\tRPL7,RPL7,RPS27A\nsugar binding\tMASP1,MASP1,SELL\nligase activity\tNARS,NARS,UBE2D2\ncytokine binding\tCD74,CD74,IFNGR1\naminopeptidase activity\tCAST,CAST,NPEPPS\nprotein phosphatase inhibitor activity\tPSMB9,PSMB9,SET\nsuccinate dehydrogenase activity\tSDHA,SDHA,RPA1\nstructural constituent of muscle\tTPM1,TPM1,SMTN\nprotein disulfide oxidoreductase activity\tP4HB,P4HB,KTN1\nprotein disulfide isomerase activity\tP4HB,P4HB,KTN1\nornithine decarboxylase inhibitor activity\tOAZ2,OAZ2,OAZ1\nglutathione peroxidase activity\tGPX1,GPX1,GPX4\ndouble-stranded RNA binding\tSON,SON,MBNL1\nCD4 receptor binding\tLCK,LCK,SPG21\nMAP kinase kinase kinase activity\tU16,U16,RPL4\nprotein C-terminus binding\tDST,DST,LCK\n", - }, - { - kind: 'annotation', - name: 'Co-expression GO cellular component', - fileName: 'NORMA_Human_coexpression_Annotation_GO_CC.txt', - text: 'integral to membrane\tSPCS2,SPCS2,ITGAV,CAST,REEP5,HLA-DPB1,SSR1,C11orf2,TAPBP,IL2RG,CXCR4,HLA-J,RPLP2,CD37,SLC25A16,221651_x_at,RPN1,IGLV3-10,FNBP4,UCP2,AD7C-NTP,ADRM1,IGHD,HLA-B,HLA-DMB,TLOC1,ATP6V0B,HLA-DRB5,SLC25A11,CD74,HLA-DRB1,IGL@,TMED5,IGLC1,HLA-E,SLC25A3,IGLV3-25,TRB@,ARL6IP5,HLA-DRB4,TRBC1,LAPTM5,CD2,C6orf12,IFNGR1,HLA-DQB1,FXYD5,POPDC3,ATP6V0C,TRBV3-1,IGLC2,214836_x_at,IGHV1-69,IGHA1,U16,HLA-F,HLA-A,CD7,CAV1,IGHG3,215176_x_at,IGLJ3,HLA-G,IL7R,ITGB2,IL6ST,RPL4,HLA-C,IGKC,IGHM,TRAM1,RPA1\nmembrane\tHLA-DPB1,HLA-DPB1,SLC38A2,RAP1B,VDP,IL2RG,CXCR4,RAB1A,NPTN,RAB6A,HLA-DMA,HLA-DQA1,ADD3,SLC25A16,PGF,IL10RA,RAB6C,221651_x_at,MSN,IGLV3-10,RPL31,UCP2,IGHD,218041_x_at,HLA-DRA,HLA-DMB,YME1L1,SELL,ATP6V0B,HLA-DRB5,SLC25A11,HLA-DRB1,IGL@,IGLC1,SLC25A3,IGLV3-25,TRB@,HLA-DRB4,TRBC1,LTB,COL6A3,IFNGR1,HLA-DQB1,HLA-DPA1,CD79A,FXYD5,ATP6V0C,PPP2CA,TRBV3-1,IGLC2,ATP2A3,214836_x_at,IGHV1-69,IGHA1,IGHG3,215176_x_at,IGLJ3,IL7R,COPE,HLA-C,IGKC,IGHM,ATP5G3,RPA1,RPL24\nnucleus\tTARDBP,TARDBP,CNOT2,NFE2L2,ZFR,STAT1,SEPT2,MCM3AP,TINP1,LYSMD4,KPNB1,SFRS10,CBX3,THRAP5,G3BP,HNRPH3,IRF7,THRAP1,ZMYND11,POLR2J,ZNF160,MEFV,CDC5L,TRIM22,DDX17,IFI16,HCLS1,ATRX,HNRPH1,POLR1B,OGT,DHX15,ZNF611,MORF4L1,HNRPR,HMGB1,PPP2CA,CDKN1B,PCM1,BCLAF1,TIMM13,SRP9,RPS6,DDX5,ZNF638,RPL35A,SFRS11,PCNP,DDX50,ZNF552,RPS3A,NPM1,MBNL1,PAPOLA,AURKAIP1,FIBP,SH3BGRL,MATR3,RPS27A,SCAND1,DDX3X,SET,HNRPA2B1,RNPC2,SEPT7,H3F3A\ncytoplasm\tAKT1,AKT1,MT1E,FNTA,STAT1,MT1F,SEPT2,VDP,EIF4G1,KPNB1,DDX42,IRF7,MSN,ARL8B,CD3D,PRKAR2A,HCLS1,ARHGDIB,COL6A3,COL1A1,COL6A1,DST,217718_s_at,RPL36A,NARS,COL4A2,COL4A1,CDKN1B,NDUFA13,PCM1,ZNF638,NACA,EXOSC4,COL3A1,COL1A2,ARPC5,EIF5,NPM1,MBNL1,PAPOLA,SH3BGRL,TPT1,PRDX2,COPS2,COPE,XPO1,DDX3X,EEF1A1,HNRPA1\nribosome\tRPL37,RPL37,RPS11,RPS21,RPL21,RPL36,RPL12,RPLP2,RPS19,RPL27,RPL31,LOC440055,LOC388344,RPL27A,RPL28,LOC283412,RPL19,RPS16,RPL36A,RPS6,RPS2,U16,RPL18A,RPL13,RPL29,RPS3A,RPS18,RPL14,RPL22,RPL34,RPS23,RPL15,RPL9,RPL6,RPL4,RPS4X,RPS24,RPL5,RPL23,MDS1,RPS7\nintracellular\tRPL37,RPL37,RAP1B,MGC2474,RPS21,RPL21,RPLP2,G3BP,GMFG,RPS19,RAB6C,PRKD2,RPL31,ZNF160,TGFB1I1,MEFV,GLTSCR2,MRPS12,CD74,RPL28,LOC283412,RPL19,ROCK1,SON,RPS6,RPS2,U16,RPL18A,RPL29,RPS18,RPL14,RPL22,RPL34,RPL15,RPL4,RPS4X,RPS24,RPL13A,RPL5,MDS1,RPS7\nintegral to plasma membrane\tHNRPM,HNRPM,IL2RG,HLA-DQA1,CD48,CD37,CLPTM1,ADRM1,HLA-B,CD164,HLA-DRA,SELL,HLA-DRB5,SLC25A11,HLA-DRB1,SLC25A3,HLA-DRB4,LAPTM5,CD2,C6orf12,IFNGR1,HLA-DPA1,ATP2A3,IGHA1,HLA-A,CAV1,SPN,IGHG3,CD52,IL6ST,HLA-C,IGHM,ATP8B1\ncytosolic small ribosomal subunit (sensu Eu...\tRPS15,RPS15,RPS5,FAU,RPS11,RPS21,RPS13,RPS19,LOC440055,RPS27,RPS10,RPS17,RPS16,RPS14,RPS6,RPS2,RPS15A,RPS20,RPS3A,RPS18,RPS27A,RPS23,RPS24,RPS9,RPS7,LOC402057,RPS25\ncytosolic large ribosomal subunit (sensu Eu...\tRPL35,RPL35,RPL18,RPL21,RPL36,RPLP2,RPL27A,RPL28,LOC283412,RPL7,U16,RPL18A,RPL29,RPL14,RPL22,RPL34,RPL6,RPL4,RPL5,MDS1\nplasma membrane\tARF1,ARF1,CD48,PTPRCAP,CD37,IL10RA,MSN,CD164,HLA-DRA,SELL,PRKAR2A,CD53,TRB@,TRBV3-1,TRA@,LCK,CD7,IL6ST\nmitochondrion\tACO2,ACO2,ATPIF1,MSRB2,SDHA,UCP2,TUFM,LOC440055,GPX4,SLC25A3,PPP2CA,NDUFA13,FIBP,DBT,NDUFB4,CYC1,RPA1\ncytosol\tCAST,CAST,NCF1,NPEPPS,KNS2,PSMB9,PSMB8,HSP90AA1,OGT,PPP2CA,HSP90B1,EIF5,RPS3A,EIF3S3,SPG21,COPB\nmembrane fraction\tRGS19,RGS19,ADRM1,HLA-B,PRKAR2A,LMOD1,COL6A3,IGHV1-69,IGHA1,U16,CD7,IGHG3,CD52,FIBP,RPL4,IGHM\nendoplasmic reticulum\tCAST,CAST,P4HB,SSR1,TAPBP,RPN1,PPIB,TLOC1,NAPA,HSP90B1,CAV1,KTN1,SET,TRAM1\ncytoskeleton\tCALD1,CALD1,RAVER2,ACTA2,TPM1,MSN,NPEPPS,ARHGDIB,LMOD1,ACTG2,ARPC3,ARPC5\nribonucleoprotein complex\tHNRPM,HNRPM,SRP72,HNRPH3,HNRPU,HNRPK,HNRPR,HNRPA3P1,SIAHBP1,HNRPA1\nextracellular region\tCAST,CAST,P4HB,CNOT2,MASP1,IGL@,FBLN1,IFI30,COL4A1,MIF,IGHG3,IGKC\nMHC class I protein complex\tHLA-J,HLA-J,RPLP2,HLA-B,HLA-E,C6orf12,HLA-F,HLA-A,HLA-G,HLA-C\nheterogeneous nuclear ribonucleoprotein com...\tHNRPH3,HNRPH3,HNRPU,HNRPH1,HNRPR,HNRPDL,HNRPA2B1,HNRPA1\nmitochondrial inner membrane\tNDUFA7,NDUFA7,SLC25A16,UCP2,SLC25A11,SLC25A3,NDUFV1\nextracellular space\tCNOT2,CNOT2,IL16,AD7C-NTP,FBLN1,TGFB1,MMP2,SPN,TPT1\nnucleoplasm\tIFI16,IFI16,NDUFA13,ZNF638,XPO1,ISG20,RNPC2,HNRPA1\ncollagen\tCOL1A1,COL1A1,COL6A1,COL4A2,COL4A1,COL3A1,COL1A2\nnucleolus\tRPL35,RPL35,RPS19,IFI16,NCL,EXOSC4,NPM1,RPS7\nspliceosome complex\tHNRPM,HNRPM,HIATL1,SF3B1,HNRPA2B1,HNRPA1\nproton-transporting two-sector ATPase complex\tATP6V0B,ATP6V0B,ATP6V0C,ATP5D,ATP5G3\nextracellular matrix (sensu Metazoa)\tLAMC1,LAMC1,FBLN1,DGCR6,COL6A3,TGFB1\nperinuclear region\t217718_s_at,217718_s_at,HSP90B1,SET\nDNA-directed RNA polymerase II, core complex\tPOLR2J,POLR2J,HCLS1,HMHA1,POLR2E\nactin cytoskeleton\tMARCKS,MARCKS,FNBP4,CORO1A,SMTN\ncAMP-dependent protein kinase complex\tPRKAR1A,PRKAR1A,PRKAR2A,PRKACB\nArp2/3 protein complex\tACTR3,ACTR3,ARPC1B,ARPC3,ARPC5\nlysosome\tHLA-DRA,HLA-DRA,LAPTM5,IFI30\nlarge ribosomal subunit\tRPL7,RPL7,RPL26,RPL13A,RPL17\nGolgi apparatus\tRGS19,RGS19,RAB6A,RAB6C,NAPA\nsoluble fraction\tNCF1,NCF1,FBLN1,NARS,PPP2CA\neukaryotic translation initiation factor 4F...\tEIF4G1,EIF4G1,EIF4A2,EIF4G2\nproton-transporting ATP synthase complex (s...\tATP5J2,ATP5J2,ATP5D,ATP5G3\nmicrosome\tSPCS2,SPCS2,TAPBP,HSP90B1\ncytosolic ribosome (sensu Eukaryota)\tLOC388344,LOC388344,RPL13\nGolgi membrane\tTAPBP,TAPBP,VDP,CAV1,COPB\ntranscription factor complex\tLOC342346,LOC342346,SUB1\nendoplasmic reticulum membrane\tTAPBP,TAPBP,HSP90B1,KTN1\nactin filament\tACTA2,ACTA2,ACTG2,IQGAP1\nproteasome complex (sensu Eukaryota)\tPSMB3,PSMB3,PSMB9,PSMB8\nnuclear envelope\tPAFAH1B1,PAFAH1B1,XPO1\nendoplasmic reticulum lumen\tCAST,CAST,PPIB,HSP90B1\nstress fiber\tPLEKHC1,PLEKHC1,SEPT7\nsmall ribosomal subunit\tRPS5,RPS5,MRPS12,RPS2\nmitochondrial electron transport chain\tUQCRC1,UQCRC1,NDUFA13\nmitochondrial ribosome\tMRPS12,MRPS12,MRPL34\nmitochondrial inner membrane presequence tr...\tTIMM8B,TIMM8B,TIMM13\nmediator complex\tTHRAP5,THRAP5,THRAP1\ncollagen type VI\tCOL6A3,COL6A3,COL6A1\nER-Golgi intermediate compartment\tP4HB,P4HB,TMED5,KTN1\nrespiratory chain complex III (sensu Eukary...\tUQCRQ,UQCRQ,UQCRFS1\neukaryotic translation elongation factor 1 ...\tEEF1B2,EEF1B2,EEF1D\ncytoplasmic membrane-bound vesicle\tARHGDIB,ARHGDIB,DST\nmicrotubule associated complex\tMEFV,MEFV,PAFAH1B1\nubiquitin ligase complex\tRNF11,RNF11,UBE4A\nprotein complex\tPSMB9,PSMB9,PSMB8\nproteasome core complex (sensu Eukaryota)\tPSMB9,PSMB9,PSMB8\nnuclear pore\tKPNB1,KPNB1,RGPD5\nintegrin complex\tITGAV,ITGAV,ITGB2\nsignal recognition particle (sensu Eukaryota)\tSRP72,SRP72,SRP9\ncell surface\tP4HB,P4HB,ATPIF1\nmyosin\tMYH9,MYH9,MYH11\nmitochondrial envelope\tUCRC,UCRC,COX5B\ncentrosome\tNPM1,NPM1,CEP27\nbasement membrane\tLAMC1,LAMC1,DST\nmitochondrial matrix\tMDH2,MDH2,ETFB\nCOPI vesicle coat\tCOPE,COPE,COPB\npericentriolar material\tPCM1,PCM1,LCK\nintermediate filament\tDES,DES,RPL38\nlipid raft\tLCK,LCK,CAV1\n', - }, - { - kind: 'colors', - name: 'Co-expression MCODE clusters', - fileName: 'NORMA_Human_coexpression_Expression_MCODE.txt', - text: '207730_x_at\tgreen\n214836_x_at\tgreen\n215176_x_at\tgreen\n215182_x_at\tgreen\n216342_x_at\tgreen\n216524_x_at\tgreen\n217281_x_at\tgreen\n220725_x_at\tgreen\n221651_x_at\tgreen\nACTA2\tgreen\nACTR2\tgreen\nACTR3\tgreen\nAD7C-NTP\tgreen\nAP2S1\tgreen\nARF5\tgreen\nARHGDIB\tgreen\nARL6IP2\tgreen\nARPC3\tgreen\nATP8B1\tgreen\nATRX\tgreen\nAURKAIP1\tgreen\nBIRC2\tgreen\nC6orf12\tgreen\nCAV1\tgreen\nCD52\tgreen\nCD74\tgreen\nCDC5L\tgreen\nCEP27\tgreen\nCHCHD2\tgreen\nCOL1A1\tgreen\nCOL1A2\tgreen\nCOL3A1\tgreen\nCOL6A1\tgreen\nCOPE\tgreen\nCOX5A\tgreen\nCOX5B\tgreen\nCOX8A\tgreen\nCROP\tgreen\nCTA-246H3.1\tgreen\nCYBA\tgreen\nDBT\tgreen\nDDT\tgreen\nDDX3X\tgreen\nDDX5\tgreen\nEIF3S3\tgreen\nEIF3S6\tgreen\nEIF4G2\tgreen\nFAU\tgreen\nFBLN1\tgreen\nFBXW12\tgreen\nFLJ11021\tgreen\nFLJ12151\tgreen\nFLJ20294\tgreen\nFLJ42393\tgreen\nGNB2L1\tgreen\nH3F3A\tgreen\nHIATL1\tgreen\nHLA-A\tgreen\nHLA-B\tgreen\nHLA-C\tgreen\nHLA-DMA\tgreen\nHLA-DPA1\tgreen\nHLA-DQB1\tgreen\nHLA-DRB1\tgreen\nHLA-DRB4\tgreen\nHLA-DRB5\tgreen\nHLA-E\tgreen\nHLA-F\tgreen\nHLA-G\tgreen\nHLA-J\tgreen\nHNRPDL\tgreen\nHNRPH3\tgreen\nIFI30\tgreen\nIGHA1\tgreen\nIGHG3\tgreen\nIGHM\tgreen\nIGHV1-69\tgreen\nIGKC\tgreen\nIGKV1-5\tgreen\nIGKV1D-13\tgreen\nIGKV1OR15-118\tgreen\nIGKV1OR2-108\tgreen\nIGL@\tgreen\nIGLC1\tgreen\nIGLC2\tgreen\nIGLJ3\tgreen\nIGLV3-25\tgreen\nIQGAP1\tgreen\nKNS2\tgreen\nLAPTM5\tgreen\nLCK\tgreen\nLMOD1\tgreen\nLOC152719\tgreen\nLOC388344\tgreen\nLOC440055\tgreen\nLOC91316\tgreen\nMAN2B1\tgreen\nMATR3\tgreen\nMBNL1\tgreen\nMCM3AP\tgreen\nMDS1\tgreen\nMGEA5\tgreen\nMORF4L1\tgreen\nMRPL34\tgreen\nMT1E\tgreen\nMT1F\tgreen\nMT1G\tgreen\nMT1H\tgreen\nMT1L\tgreen\nMT1M\tgreen\nMT1X\tgreen\nMT2A\tgreen\nMYH11\tgreen\nNACA\tgreen\nNAP1L1\tgreen\nNARS\tgreen\nNDUFA2\tgreen\nNDUFA3\tgreen\nNDUFAB1\tgreen\nNDUFB11\tgreen\nNDUFB2\tgreen\nNDUFB4\tgreen\nNDUFS3\tgreen\nNDUFS7\tgreen\nNPM1\tgreen\nPAPOLA\tgreen\nPCNP\tgreen\nPDE4C\tgreen\nPFAAP5\tgreen\nPGF\tgreen\nPNRC2\tgreen\nPOLR2J\tgreen\nPRG1\tgreen\nPRR11\tgreen\nPTGES3\tgreen\nRAC2\tgreen\nRIOK3\tgreen\nROCK1\tgreen\nRPL11\tgreen\nRPL13\tgreen\nRPL13A\tgreen\nRPL17\tgreen\nRPL18\tgreen\nRPL21\tgreen\nRPL22\tgreen\nRPL23\tgreen\nRPL24\tgreen\nRPL27\tgreen\nRPL27A\tgreen\nRPL28\tgreen\nRPL29\tgreen\nRPL30\tgreen\nRPL34\tgreen\nRPL35A\tgreen\nRPL36\tgreen\nRPL36A\tgreen\nRPL38\tgreen\nRPL4\tgreen\nRPL5\tgreen\nRPL6\tgreen\nRPL7\tgreen\nRPL9\tgreen\nRPLP2\tgreen\nRPS14\tgreen\nRPS17\tgreen\nRPS18\tgreen\nRPS19\tgreen\nRPS2\tgreen\nRPS23\tgreen\nRPS24\tgreen\nRPS25\tgreen\nRPS27A\tgreen\nRPS3A\tgreen\nRPS4X\tgreen\nRPS5\tgreen\nRPS6\tgreen\nRPS7\tgreen\nRPS9\tgreen\nSEPT2\tgreen\nSERBP1\tgreen\nSFRS11\tgreen\nSH3BGRL\tgreen\nSKP1A\tgreen\nSLC35E1\tgreen\nSON\tgreen\nSUMO2\tgreen\nTAF7\tgreen\nTLOC1\tgreen\nTRA@\tgreen\nTRB@\tgreen\nTUG1\tgreen\nU16\tgreen\nUQCR\tgreen\nUQCRC1\tgreen\nUQCRFS1\tgreen\nUSP34\tgreen\nXPO1\tgreen\nYTHDC1\tgreen\nZNF160\tgreen\nZNF611\tgreen\nZNF638\tgreen\nZNHIT1\tgreen\n208246_x_at\tyellow\n211637_x_at\tyellow\n211645_x_at\tyellow\nATP5G3\tyellow\nATP6V0B\tyellow\nATP6V0D1\tyellow\nBCLAF1\tyellow\nCAPZA1\tyellow\nCOL6A3\tyellow\nCXCR4\tyellow\nHLA-DPB1\tyellow\nHNRPH1\tyellow\nIFI16\tyellow\nLOC342346\tyellow\nLOC56902\tyellow\nLOC58486\tyellow\nLOC645745\tyellow\nMEFV\tyellow\nMRPS12\tyellow\nNDUFS8\tyellow\nPTRF\tyellow\nRPL31\tyellow\nRPL35\tyellow\nRPS11\tyellow\nTAGLN\tyellow\nTGFB1\tyellow\nTRBC1\tyellow\n208120_x_at\tred\n208238_x_at\tred\n211639_x_at\tred\n211641_x_at\tred\n211650_x_at\tred\n211908_x_at\tred\n212498_at\tred\n216412_x_at\tred\n216858_x_at\tred\n217052_x_at\tred\n217258_x_at\tred\n217679_x_at\tred\n217718_s_at\tred\n218041_x_at\tred\nAASDHPPT\tred\nACO2\tred\nACTG2\tred\nACTR10\tred\nADD3\tred\nADRM1\tred\nAKR7A2\tred\nAKT1\tred\nALOX5AP\tred\nARF1\tred\nARL6IP5\tred\nARL8B\tred\nARPC1B\tred\nARPC5\tred\nARPP-19\tred\nATP2A3\tred\nATP5D\tred\nATP5J2\tred\nATP6AP2\tred\nATP6V0C\tred\nATPIF1\tred\nBTF3\tred\nC11orf2\tred\nC11orf58\tred\nC12orf10\tred\nC12orf38\tred\nC16orf24\tred\nC17orf62\tred\nC1orf160\tred\nC1orf63\tred\nC21orf33\tred\nC3orf60\tred\nCAB39\tred\nCALD1\tred\nCAP1\tred\nCAPNS1\tred\nCAST\tred\nCBX3\tred\nCCL5\tred\nCCNL1\tred\nCD164\tred\nCD2\tred\nCD37\tred\nCD3D\tred\nCD48\tred\nCD53\tred\nCD7\tred\nCD79A\tred\nCDKN1B\tred\nCECR1\tred\nCHMP2A\tred\nCLPP\tred\nCLPTM1\tred\nCLTC\tred\nCNN1\tred\nCNOT2\tred\nCOL4A1\tred\nCOL4A2\tred\nCOPB\tred\nCOPS2\tred\nCOQ9\tred\nCORO1A\tred\nCOX4I1\tred\nCSDE1\tred\nCSNK1A1\tred\nCUL4B\tred\nCXorf9\tred\nCYC1\tred\nDDX1\tred\nDDX17\tred\nDDX42\tred\nDDX50\tred\nDES\tred\nDEXI\tred\nDGCR6\tred\nDHX15\tred\nDIP2A\tred\nDKFZP566N034\tred\nDST\tred\nDYNLT3\tred\nECH1\tred\nEEF1A1\tred\nEEF1B2\tred\nEEF1D\tred\nEIF4A2\tred\nEIF4G1\tred\nEIF5\tred\nENDOG\tred\nERH\tred\nETFB\tred\nEXOSC4\tred\nFAIM3\tred\nFAM96B\tred\nFIBP\tred\nFIS1\tred\nFLJ10154\tred\nFLJ14346\tred\nFNBP4\tred\nFNTA\tred\nFXYD5\tred\nG3BP\tred\nGBL\tred\nGLTSCR2\tred\nGMFG\tred\nGOLGA8A\tred\nGOLGA8B\tred\nGPAA1\tred\nGPSM3\tred\nGPX1\tred\nGPX4\tred\nGTF2I\tred\nGUK1\tred\nHCLS1\tred\nHLA-DMB\tred\nHLA-DQA1\tred\nHLA-DRA\tred\nHMGB1\tred\nHMHA1\tred\nHNRPA1\tred\nHNRPA2B1\tred\nHNRPA3P1\tred\nHNRPK\tred\nHNRPM\tred\nHNRPR\tred\nHNRPU\tred\nHSP90AA1\tred\nHSP90B1\tred\nIFNGR1\tred\nIGHD\tred\nIGLV3-10\tred\nIL10RA\tred\nIL16\tred\nIL2RG\tred\nIL6ST\tred\nIL7R\tred\nINPP5D\tred\nIRF7\tred\nISG20\tred\nITGAV\tred\nITGB2\tred\nKIAA0907\tred\nKIAA1840\tred\nKIDINS220\tred\nKPNB1\tred\nKTN1\tred\nLAMC1\tred\nLOC283412\tred\nLOC402057\tred\nLRRFIP1\tred\nLTB\tred\nLYSMD4\tred\nMARCKS\tred\nMASP1\tred\nMDH2\tred\nMGC2474\tred\nMIF\tred\nMMP2\tred\nMRP63\tred\nMSN\tred\nMSRB2\tred\nMYH9\tred\nMYLK\tred\nNAPA\tred\nNBPF1\tred\nNBPF12\tred\nNCF1\tred\nNCL\tred\nNDUFA10\tred\nNDUFA13\tred\nNDUFA7\tred\nNDUFB6\tred\nNDUFC1\tred\nNDUFV1\tred\nNFE2L2\tred\nNPEPPS\tred\nNPTN\tred\nOAZ1\tred\nOAZ2\tred\nOGT\tred\nOPHN1\tred\nORC6L\tred\nOSBPL8\tred\nP4HB\tred\nPAFAH1B1\tred\nPCM1\tred\nPDCD10\tred\nPGLS\tred\nPHIP\tred\nPLEKHC1\tred\nPOLR1B\tred\nPOLR2E\tred\nPOLR2I\tred\nPOLR2L\tred\nPOPDC3\tred\nPPIB\tred\nPPP1CA\tred\nPPP2CA\tred\nPRDX2\tred\nPRKACB\tred\nPRKAR1A\tred\nPRKAR2A\tred\nPRKD2\tred\nPSMB3\tred\nPSMB8\tred\nPSMB9\tred\nPTPRCAP\tred\nPUM2\tred\nR3HCC1\tred\nRAB1A\tred\nRAB6A\tred\nRAB6C\tred\nRAP1B\tred\nRAVER2\tred\nRBPMS\tred\nREEP5\tred\nRGPD5\tred\nRGS19\tred\nRNF11\tred\nRNPC2\tred\nRPA1\tred\nRPL10A\tred\nRPL12\tred\nRPL14\tred\nRPL15\tred\nRPL18A\tred\nRPL19\tred\nRPL23A\tred\nRPL26\tred\nRPL32\tred\nRPL37\tred\nRPL39\tred\nRPL41\tred\nRPN1\tred\nRPS10\tred\nRPS13\tred\nRPS15\tred\nRPS15A\tred\nRPS16\tred\nRPS20\tred\nRPS21\tred\nRPS27\tred\nSCAND1\tred\nSDHA\tred\nSEC61A1\tred\nSELL\tred\nSEPT7\tred\nSET\tred\nSF3B1\tred\nSFPQ\tred\nSFRS10\tred\nSFRS3\tred\nSFRS5\tred\nSIAHBP1\tred\nSLC25A11\tred\nSLC25A16\tred\nSLC25A3\tred\nSLC38A2\tred\nSMTN\tred\nSPARCL1\tred\nSPCS2\tred\nSPG21\tred\nSPN\tred\nSRP46\tred\nSRP72\tred\nSRP9\tred\nSSR1\tred\nSTAT1\tred\nSUB1\tred\nSUMO1\tred\nTAPBP\tred\nTARDBP\tred\nTCEA1\tred\nTCEB2\tred\nTGFB1I1\tred\nTHRAP1\tred\nTHRAP5\tred\nTIMM13\tred\nTIMM8B\tred\nTINP1\tred\nTMED5\tred\nTMEM123\tred\nTMEM66\tred\nTMEM93\tred\nTOMM20\tred\nTPM1\tred\nTPT1\tred\nTRAM1\tred\nTRBV3-1\tred\nTRIM22\tred\nTTC19\tred\nTTC3\tred\nTUFM\tred\nTXNL2\tred\nUBE2D2\tred\nUBE4A\tred\nUCP2\tred\nUCRC\tred\nUQCRQ\tred\nUSP47\tred\nVDP\tred\nWAC\tred\nWDR45\tred\nWIPI2\tred\nWSB1\tred\nYIPF3\tred\nYME1L1\tred\nYWHAZ\tred\nZC3H11A\tred\nZFR\tred\nZMYND11\tred\nZNF403\tred\nZNF552\tred\nZNF9\tred\nhfl-B5\tred\n', - }, - ], - }, - covid: { - title: 'COVID-19 (IntAct)', - source: 'IntAct database', - link: null, - files: [ - { - kind: 'network', - name: 'COVID-19 IntAct', - fileName: 'Intact-data_COVID19_no_self_loops.txt', - text: 'Source\tTarget\nP31809\tP11224\nP33767\tP41811\nQ3T133\tP41811\nP39656\tP41811\nP41811\tO15503\nQ91AV1\tP41811\nQ96WV5\tP68978\nQ9Y5U4\tP41811\nP53622\tP41811\nP53622\tQ3T133\nP53622\tP41811\nP53622\tP33767\nP53622\tP41811\nP53622\tP68978\nP53622\tP41811\nP53622\tP39656\nQ3T133\tQ96WV5\nQ96WV5\tP39656\nQ96WV5\tP33767\nQ96WV5\tP68978\nP53622\tP41811\nP53622\tQ9Y5U4\nP53622\tP41811\nP53622\tQ91AV1\nP53622\tP41811\nP53622\tO15503\nQ96WV5\tQ9Y5U4\nQ96WV5\tO15503\nQ91AV1\tQ96WV5\nP53622\tP41811\nP53622\tP41811\nP53622\tP41811\nP53622\tP41811\nP53622\tP41811\nP27487\tK0BRG7\nP27487\tK0BRG7\nQ9BYF1-1\tP59594\nP27487\tK0BRG7\nQ9BYF1-1\tP59594\nP27487\tK0BRG7\nP27487\tK0BRG7\nP0C6U8\tP62753\nQ9BYF1-1\tQ6Q1S2\nQ9BYF1-1\tQ6Q1S2\nQ9BYF1-1\tQ6Q1S2\nQ7TLC7\tO14964\nQ7TLC7\tP05155\nQ7TLC7\tQ13561\nQ7TLC7\tQ9NRH1\nJ9TC74\tQ13561\nJ9TC74\tP62258\nJ9TC74\tQ99471\nP59633\tQ13561\nP59633\tP05155\nP59633\tP02768\nQ6S8E0\tP08708\nQ6S8E0\tP25787\nP59634\tQ13561\nP59634\tQ92994\nQ19QW4\tQ9BQB6\nQ19QW4\tQ9H4F8\nQ7T6S2\tP49069\nQ7T6S2\tP05155\nQ6S8E0\tP60866\nQ6S8E0\tP27448\nQ19QW2\tP46379\nQ6S8E0\tP60866\nQ19QW2\tP46379\nP59634\tQ13561\nQ7T6S2\tP49069\nQ19QW4\tQ9BQB6\nQ6S8E0\tP27448\nQ6S8E0\tP25787\nQ7TLC7\tO14964\nQ7TLC7\tQ13561\nQ1HVL3\tP15144\nQ1HVL8\tP15144\nQ1HVK9\tP15144\nQ9BYF1\tP0DTC2\nQ9BYF1\tP59594\nK9N5Q8\tP27487\nQ9BYF1\tP0DTC2\nQ9BYF1\tP59594\nQ9BYF1\tP0DTC2\nQ9BYF1\tP59594\nQ9BYF1\tP0DTC2\nQ9BYF1\tP59594\nQ9BYF1\tP59594\nP61769\tP04439\nP61769\tP59595\nP61769\tP04439\nP61769\tP03407\nP61769\tP04439\nP61769\tP59595\nP61769\tP04439\nP61769\tP59596\nP61769\tP04439\nP61769\tQ692E0\nP61769\tP04439\nP61769\tP59596\nP61769\tP04439\nP61769\tQ76R37\nP61769\tP04439\nP61769\tP59637\nQ9BYF1\tP0DTC2\nQ9BYF1\tP0DTC2\nQ9BYF1\tP0DTC2\nQ9BYF1\tP0DTC2\nQ9BYF1\tP59594\nQ9BYF1\tP0DTC2\nQ9BYF1\tP0DTC2\nQ9BYF1\tQ695T7\nQ9BYF1\tQ695T7\nQ9BYF1\tP0DTC2\nQ9BYF1\tQ695T7\nQ9BYF1\tP37173\nQ9BYF1\tP37173\nP11021\tK0BRG7\nP11021\tK0BRG7\nP11021\tK0BRG7\nP11021\tK0BRG7\nP11021\tK0BRG7\nP11021\tK0BRG7\nP11021\tK0BRG7\nP11021\tK0BRG7\nK0BRG7\tP11021\nP0DTC4\tQ8IWA5\nP0DTC4\tQ86VM9\nP0DTC4\tQ6UX04\nP0DTC4\tP25440\nP0DTC4\tO60885\nP0DTC4\tO00203\nP0DTC9\tQ9Y3U8\nP0DTC9\tQ9NW13\nP0DTC9\tQ9NR30\nP0DTC9\tQ9UN86\nP0DTC9\tQ9HCE1\nP0DTC9\tQ92900\nP0DTC9\tQ8TAD8\nP0DTC9\tQ8NCA5\nP0DTC9\tQ6PKG0\nP0DTC9\tQ13310\nP0DTC9\tQ13283\nP0DTC9\tP67870\nP0DTC9\tP19784\nP0DTC9\tP11940\nP0DTC9\tO43818\nP0DTC2\tQ9C0B5\nP0DTC2\tQ7Z5G4\nP0DTC5\tQ9Y6E2\nP0DTC5\tQ9Y312\nP0DTC5\tQ9ULX6\nP0DTC5\tQ9UDR5\nP0DTC5\tQ9UBU6\nP0DTC5\tQ9NQC3\nP0DTC5\tQ9BW92\nP0DTC5\tQ9BSJ2\nP0DTC5\tQ9BQT8\nP0DTC5\tQ96HW7\nP0DTC5\tQ96HR9\nP0DTC5\tQ96ER3\nP0DTC5\tQ96D53\nP0DTC5\tQ96CW5\nP0DTC5\tQ8NEW0\nP0DTC5\tQ7L8L6\nP0DTC5\tQ6PML9\nP0DTC5\tQ5JRX3\nP0DTC5\tQ4KMQ2\nP0DTC5\tQ10713\nP0DTC5\tQ00765\nP0DTC5\tP48556\nP0DTC5\tP38606\nP0DTC5\tP38435\nP0DTC5\tP27105\nP0DTC5\tP13804\nP0DTC5\tP11310\nP0DTC5\tP05026\nP0DTC5\tO95070\nP0DTC5\tO75439\nP0DTC6\tQ9NZJ7\nP0DTC6\tP78406\nP0DTC6\tP52948\nP0DTC3\tQ9Y673\nP0DTC3\tQ9UH99\nP0DTC3\tQ9H270\nP0DTC3\tQ96S66\nP0DTC3\tQ96JC1\nP0DTC3\tQ8N6S5\nP0DTC3\tQ8IWR1\nP0DTC3\tP09601\nP0DTC7\tQ9NU22\nP0DTC7\tQ7Z4Q2\nP0DTC8\tQ96IV0\nP0DTC8\tQ8N0Z8\nP0DTC8\tQ96AY3\nP0DTC8\tQ13443\nP0DTC8\tQ9Y680\nP0DTC8\tQ9Y4L1\nP0DTC8\tQ9UHI8\nP0DTC8\tQ9P2E5\nP0DTC8\tQ9NYU1\nP0DTC8\tQ9NXK8\nP0DTC8\tQ9H8W4\nP0DTC8\tQ9H4F8\nP0DTC8\tQ9H488\nP0DTC8\tQ9H173\nP0DTC8\tQ9BZQ6\nP0DTC8\tQ9BS26\nP0DTC8\tQ9BRN9\nP0DTC8\tQ99988\nP0DTC8\tQ99519\nP0DTC8\tQ99470\nP0DTC8\tQ96MM7\nP0DTC8\tQ96F46\nP0DTC8\tQ96DZ1\nP0DTC8\tQ92820\nP0DTC8\tQ8N766\nP0DTC8\tQ8IZ52\nP0DTC8\tQ8IWF2\nP0DTC8\tQ8IV08\nP0DTC8\tQ86YB8\nP0DTC8\tQ7Z4H8\nP0DTC8\tQ6UW63\nP0DTC8\tQ15818\nP0DTC8\tQ13438\nP0DTC8\tQ08431\nP0DTC8\tP61916\nP0DTC8\tP58166\nP0DTC8\tP29122\nP0DTC8\tP28300\nP0DTC8\tP26358\nP0DTC8\tP15151\nP0DTC8\tP12109\nP0DTC8\tP0C7P0\nP0DTC8\tP05556\nP0DTC8\tP00750\nP0DTC8\tO76061\nP0DTC8\tO14656\nP0DTC8\tO00469\nP0DTD2\tQ9UL15\nP0DTD2\tQ9UKA9\nP0DTD2\tQ9P0L2\nP0DTD2\tQ9H773\nP0DTD2\tQ9H2P9\nP0DTD2\tQ7KZI7\nP0DTD2\tP27448\nP0DTD2\tO94826\nP0DTD2\tO75534\nP0DTD2\tO43633\nP0DTD2\tO14745\nP0DTD3\tQ9Y3A6\nP0DTD3\tQ2PZI1\nP0DTD3\tQ96S52\nP0DTD3\tQ9Y6M9\nP0DTD3\tQ9Y375\nP0DTD3\tQ9Y276\nP0DTD3\tQ9NV92\nP0DTD3\tQ9H845\nP0DTD3\tQ9H3K2\nP0DTD3\tQ9GZU3\nP0DTD3\tQ9BVK2\nP0DTD3\tQ9BQ95\nP0DTD3\tQ96K12\nP0DTD3\tQ8TEQ8\nP0DTD3\tQ86VR2\nP0DTD3\tQ86UT6\nP0DTD3\tQ7Z2K6\nP0DTD3\tQ6NXT6\nP0DTD3\tQ6NXT4\nP0DTD3\tQ5BJF2\nP0DTD3\tQ12770\nP0DTD3\tP55085\nP0DTD3\tP33527\nP0DTD3\tO76024\nP0DTD3\tO43292\nP0DTD3\tO00124\nQ1LZX8\tP59594\nQ1LZX8\tP84198\nQ1LZX8\tP84198\nQ1LZX8\tP59594\nP84198\tP59594\nP84198\tP59594\nP59637\tQ64373\nP59637\tO35843\nQ64373\tQ07817\nQ64373\tP59637\nP59637\tO35843\nP59637\tQ07817\nP06731-1\tK0BRG7\nP06731\tK0BRG7\nK0BRG7\tP06731\nP06731\tK0BRG7\nP06731\tK0BRG7\nP59637\tP59636\nP59633\tP59637\nQ7TFA0\tP59636\nQ7TFA1\tQ19QW5\nQ80H93\tQ7TFA0\nP59596\tP59632\nP59594\tP59635\nQ7TFA1\tP59637\nP59594\tQ80H93\nQ7TFA1\tQ80H93\nQ7TFA0\tQ80H93\nQ7TLC7\tP59636\nQ7TFA1\tP59636\nQ80H93\tP59636\nQ7TLC7\tQ80H93\nQ7TFA1\tP59637\nP59595\tP59596\nQ7TFA1\tQ19QW5\nQ7TLC7\tP59636\nQ7TLC7\tP59636\nQ9BYF1\tP02768\nF1RG45\tK7GLM4\nQ9BYF1\tP05814\nQ9BYF1\tP0DTC2\nQ9BYF1\tP59594\nQ92793\tQ14653\nQ92793\tQ14653\nQ07817\tP59635\nP59635\tP10415\nQ07820\tP59635\nQ16548\tP59635\nP59635\tQ92843\nQ9BYF1\tP59594\nQ9BYF1\tQ6Q1S2\nQ9BYF1\tP59594\nQ9BYF1\tQ6Q1S2\nQ9BYF1\tQ6Q1S2\nP59594\tP00747\nP59594\tP00762\nQ6ZMR5\tP59594\nQ9BYF1\tP59594\nQ9BYF1\tP59594\nQ9BYF1\tP59594\nQ9BYF1\tP59594\nQ9BYF1\tP59594\nQ9BYF1\tP59594\nP59594\tQ56NL1\nP59595\tP63279\nP59595\tP63279\nP59595\tP63279\nP59595\tP63279\nP20290\tQ86VG3\nQ86U32\tQ86VG3\nP24928\tQ86VG3\nP20290\tQ86VG3\nP20290\tQ86VG3\nP20290\tQ86VG3\nO00303\tP59594\nO00303\tP59594\nO00303\tP11223\nO00303\tP59594\nO00303\tP11223\nO00303\tP59594\nO00303\tP59594\nP59595\tQ05639\nP03070\tP02340\nP59595\tQ05639\nQ05639\tP59595\nP59595\tQ05639\nP59595\tQ05639\nP15130\tQ05639\nQ05639\tP59595\nQ05639\tP08107\nQ05639\tP59595\nQ05639\tP08107\nP59595\tQ05639\nP59595\tQ05639\nP59595\tQ05639\nP59595\tP63279\nP59595\tP63279\nP59595\tP63279\nP59595\tP63279\nP59595\tP63279\nP59595\tP63279\nP59595\tP63279\nP59595\tP63279\nP59595\tP62937\nP59595\tP62937\nP35613\tP62937\nQ9BYF1\tP59594\nP59594\tQ5EGZ1\nQ9BYF1\tP59594\nP59594\tQ5EGZ1\nP59594\tQ56NL1\nQ9BYF1\tQ5GDB5\nQ9BYF1\tP59594\nQ56NL1\tP59594\nQ9BYF1\tP59594\nP59594\tQ56NL1\nQ56NL1\tQ5GDB5\nQ9BYF1\tQ5GDB5\nQ9BYF1\tP59594\nP0DTC2\tP62269\nP0DTC2\tQ96N67\nP0DTC2\tP63244\nP0DTC2\tP40227\nP0DTC2\tP07195\nP0DTC2\tP08621\nP0DTC2\tP60660\nP0DTC2\tP47756\nP0DTC2\tP52907\nP0DTC2\tQ9NYL9\nP0DTC2\tP13797\nP0DTC2\tQ9ULV4\nP0DTC2\tP59998\nP0DTC2\tP61158\nP0DTC2\tQ9UM54\nP0DTC4\tQ9ULX6\nP0DTC4\tP50402\nP0DTC4\tQ00325\nP0DTC4\tP05023\nP0DTC4\tO75746\nP0DTC4\tP16615\nP0DTC4\tQ9P035\nP0DTC4\tQ5H9R7\nP0DTC5\tP30876\nP0DTC5\tO15397\nP0DTC5\tQ9H078\nP0DTC5\tP62195\nP0DTC5\tP26599\nP0DTC5\tO60762\nP0DTC5\tQ9H936\nP0DTC5\tO00231\nP0DTC5\tQ9ULX6\nP0DTC5\tQ9UHI6\nP0DTC5\tQ7Z4H7\nP0DTC5\tQ96EY1\nP0DTC5\tQ00325\nP0DTC5\tQ15008\nP0DTC5\tO14818\nP0DTC5\tP40939\nP0DTC5\tP50402\nP0DTC5\tQ5H9R7\nP0DTC5\tO95757\nP0DTC5\tP57678\nP0DTC5\tP31689\nP0DTC5\tO15027\nP0DTC5\tP60900\nP0DTC5\tP25705\nP0DTC5\tP51665\nP0DTC5\tP62191\nP0DTC5\tP06576\nP0DTC5\tQ14257\nP0DTC5\tQ99615\nP0DTC5\tO95816\nP0DTC5\tO95071\nP0DTC5\tP46379\nP0DTC5\tO75746\nP0DTC5\tQ9Y5A9\nP0DTC5\tQ13200\nP0DTC5\tP53618\nP0DTC5\tQ9NZ01\nP0DTC5\tP35998\nP0DTC5\tQ16891\nP0DTC5\tO60884\nP0DTC5\tO43852\nP0DTC5\tQ99460\nP0DTC5\tQ9NTJ3\nP0DTC5\tP53621\nP0DTC5\tP55786\nP0DTC5\tQ15293\nP0DTC5\tP34932\nP0DTC5\tQ9UBF2\nP0DTC5\tO43592\nP0DTC5\tP35606\nP0DTC5\tP05023\nP0DTC5\tO95347\nP0DTC5\tP16615\nP0DTC5\tO14980\nP0DTC5\tQ96CS3\nP0DTC5\tQ9P035\nP0DTC9\tP09622\nP0DTC9\tP08621\nP0DTC9\tP38159\nP0DTC9\tQ13151\nP0DTC9\tQ9UN86\nP0DTC9\tQ13283\nP0DTC9\tQ9UM54\nP0DTC3\tP40939\nP0DTC3\tQ14257\nP0DTC3\tP22314\nP0DTC3\tP04406\nP0DTC3\tP57088\nP0DTC3\tQ8IXB1\nP0DTC3\tQ00325\nP0DTC3\tP31689\nP0DTC3\tP25705\nP0DTC3\tO43852\nP0DTC3\tO95757\nP0DTC3\tP46379\nP0DTC3\tP53621\nP0DTC3\tQ9H936\nP0DTC3\tO60884\nP0DTC3\tP26599\nP0DTC3\tO75746\nP0DTC3\tP11586\nP0DTC3\tQ9NZ01\nP0DTC3\tP53007\nP0DTC3\tP05023\nP0DTC3\tQ96CS3\nP0DTC3\tO43592\nP0DTC3\tO95347\nP0DTC3\tP16615\nP0DTC3\tQ16891\nP0DTC3\tO14980\nP0DTC3\tQ9P035\nP0DTC6\tQ5SW79\nP0DTC6\tP25705\nP0DTC6\tQ92552\nP0DTC6\tP06576\nP0DTC6\tP15924\nP0DTC6\tP53396\nP0DTC6\tP16615\nP0DTC6\tQ5T9A4\nP0DTC6\tP05023\nP0DTC6\tO75592\nP0DTC6\tO75934\nP0DTC6\tO14980\nP0DTC6\tQ96CS3\nP0DTC6\tP78406\nP0DTC6\tQ9NVI7\nP0DTC6\tP33176\nP0DTC6\tQ13561\nP0DTC6\tQ6P2E9\nP0DTC7\tP30153\nP0DTC7\tP06576\nP0DTC7\tP40939\nP0DTC7\tQ8IXB1\nP0DTC7\tQ9UHI6\nP0DTC7\tO95816\nP0DTC7\tP53007\nP0DTC7\tQ96EY1\nP0DTC7\tP50402\nP0DTC7\tO43852\nP0DTC7\tQ9H936\nP0DTC7\tP62195\nP0DTC7\tP30876\nP0DTC7\tQ99615\nP0DTC7\tP55786\nP0DTC7\tP57678\nP0DTC7\tQ00325\nP0DTC7\tO75746\nP0DTC7\tO15027\nP0DTC7\tP34932\nP0DTC7\tQ15008\nP0DTC7\tQ9UNM6\nP0DTC7\tO95071\nP0DTC7\tO60884\nP0DTC7\tP62191\nP0DTC7\tP05023\nP0DTC7\tP51665\nP0DTC7\tP53618\nP0DTC7\tQ9NZ01\nP0DTC7\tP35998\nP0DTC7\tQ13200\nP0DTC7\tP53621\nP0DTC7\tQ5H9R7\nP0DTC7\tP16615\nP0DTC7\tQ99460\nP0DTC7\tO43592\nP0DTC7\tQ9NXS2\nP0DTC7\tP46379\nP0DTC7\tQ16891\nP0DTC7\tO95347\nP0DTC7\tP35606\nP0DTC7\tQ9UBF2\nP0DTC7\tQ9P035\nP0DTC7\tO14980\nP0DTC7\tQ96CS3\nP0DTD8\tQ14257\nP0DTD8\tO60762\nP0DTD8\tO43852\nP0DTD8\tP25705\nP0DTD8\tP31689\nP0DTD8\tP06576\nP0DTD8\tQ8WTT2\nP0DTD8\tQ7KZF4\nP0DTD8\tQ9NVI7\nP0DTD8\tP05023\nP0DTD8\tP55786\nP0DTD8\tQ00325\nP0DTD8\tP53618\nP0DTD8\tP57088\nP0DTD8\tO43592\nP0DTD8\tO95347\nP0DTD8\tQ9NZ01\nP0DTD8\tQ16891\nP0DTD8\tP16615\nP0DTD8\tP53621\nP0DTD8\tQ9NXS2\nP0DTD8\tQ96CS3\nP0DTD8\tQ02978\nP0DTD8\tP35606\nP0DTD8\tQ9UBF2\nP0DTD8\tQ9P035\nP0DTD8\tO14980\nP0DTD8\tP10155\nP0DTC8\tQ14152\nP0DTC8\tP50402\nP0DTC8\tQ9UHI6\nP0DTC8\tP06576\nP0DTC8\tP62195\nP0DTC8\tP25705\nP0DTC8\tP40939\nP0DTC8\tQ5JWF2\nP0DTC8\tO14818\nP0DTC8\tP55786\nP0DTC8\tP57678\nP0DTC8\tO43852\nP0DTC8\tQ12789\nP0DTC8\tQ9H936\nP0DTC8\tP31689\nP0DTC8\tQ15008\nP0DTC8\tQ9UNM6\nP0DTC8\tQ00325\nP0DTC8\tO15027\nP0DTC8\tP30876\nP0DTC8\tQ7KZF4\nP0DTC8\tQ9NVI7\nP0DTC8\tO60884\nP0DTC8\tQ13200\nP0DTC8\tP05023\nP0DTC8\tO95071\nP0DTC8\tP35998\nP0DTC8\tO43592\nP0DTC8\tQ02978\nP0DTC8\tQ9NZ01\nP0DTC8\tP53618\nP0DTC8\tQ99460\nP0DTC8\tO75746\nP0DTC8\tP16615\nP0DTC8\tP53621\nP0DTC8\tQ16891\nP0DTC8\tO95347\nP0DTC8\tO14980\nP0DTC8\tQ9P035\nP0DTC8\tQ9UBF2\nP0DTC8\tP46379\nP0DTD2\tP19105\nP0DTD2\tQ14315\nP0DTD2\tP62140\nP0DTD2\tP0DP23\nP0DTD2\tP09622\nP0DTD2\tP52907\nP0DTD2\tP60660\nP0DTD2\tQ9NYL9\nP0DTD2\tP13797\nP0DTD2\tQ9UM54\nP0DTD2\tQ9ULV4\nP0DTD2\tP59998\nP0DTD3\tQ9BUQ8\nP0DTD3\tQ96N67\nP0DTD3\tQ15365\nP0DTD3\tP17987\nP0DTD3\tO00231\nP0DTD3\tQ14257\nP0DTD3\tQ16576\nP0DTD3\tP62269\nP0DTD3\tQ58FF8\nP0DTD3\tP27348\nP0DTD3\tP40227\nP0DTD3\tP63244\nP0DTD3\tP49368\nP0DTD3\tQ9Y265\nP0DTD3\tP07355\nP0DTD3\tP46379\nP0DTD3\tP48643\nP0DTD3\tQ99832\nP0DTD3\tQ9UHI6\nP0DTD3\tP31948\nP0DTD3\tQ3ZCQ8\nP0DTD3\tQ9NVI7\nP0DTD3\tP46782\nP0DTD3\tP25205\nP0DTD3\tP30153\nP0DTD3\tQ9ULX6\nP0DTD3\tP42677\nP0DTD3\tP61158\nP0DTD3\tP09874\nP0DTD3\tP50402\nP0DTD3\tP30876\nP0DTD3\tQ9NXS2\nP0DTD3\tP40939\nP0DTD3\tP06493\nP0DTD3\tP51570\nP0DTD3\tQ7Z4H7\nP0DTD3\tP57088\nP0DTD3\tQ14739\nP0DTD3\tP10155\nP0DTD3\tQ9UM54\nP0DTD3\tP04406\nP0DTD3\tQ9H936\nP0DTD3\tP11586\nP0DTD3\tQ9UBX3\nP0DTD3\tQ5H9R7\nP0DTD3\tP53618\nP0DTD3\tP53007\nP0DTD3\tP12004\nP0DTD3\tP05023\nP0DTD3\tQ16891\nP0DTD3\tQ9NZ01\nP0DTD3\tO14980\nP0DTD3\tO95347\nP0DTD3\tQ9NTJ3\nP0DTD3\tP53621\nP0DTD3\tP16615\nP0DTD3\tO43592\nP0DTD3\tQ9UBF2\nP0DTD3\tP35606\nP0DTD3\tQ9P035\nP59594\tP35247\nP52294\tP52630\nP52294\tP42224\nP52292\tQ14974\nP52294\tP42224\nP52294\tQ14974\nP52292\tQ14974\nP52294\tP42224\nP52292\tQ14974\nP52292\tQ14974\nQ99623\tP35232\nQ99623\tP35232\nO35129\tP67778\nO35129\tQ9JIA7\nO35129\tP67778\nO35129\tP19783\nO35129\tP00397\nO35129\tP67778\nP00405\tP19783\nP00405\tP12787\nP00405\tP19536\nP00405\tQ9CPQ1\nP00405\tP56391\nP00405\tP56392\nP12904\tP06782\nP33469\tP13010\nP33469\tP39019\nP33469\tP61254\nP33469\tP16402\nP33469\tP09651\nP33469\tP67809\nP33469\tP0DMV8\nP33469\tP11940\nP33469\tP12956\nP33469\tQ00839\nP33469\tP19338\nP33469\tP67809\nP33469\tP12956\nP33469\tQ00839\nP33469\tP19338\nK0BWD0\tP05161\nP05161\tK0BWD0\nK0BWD0\tP05161\nK0BWD0\tP05161\nR9QB93\tK0BWD0\nO43765\tP59635\nO43765\tP59635\nP59635\tP59596\nP59635\tP59637\nQ5MAG3\tP59635\nO43765\tP59635\nP59595\tP59596\nP0DTC2\tP35613\nP0DTC2\tP35613\nP0DTC2\tP35613\nP0DTC2\tP35613\nP0DTC2\tP35613\nP04135\tF1S215\nP04135\tF1RNN5\nP04135\tA6M930\nP04135\tA6M930\nP04135\tA6M930\nP04135\tA6M930\nQ9BYF1\tP0DTC2\nQ9BYF1\tP59594\nQ9BYF1\tP0DTC2\nQ9BYF1\tP59594\nQ9BYF1\tP0DTC2\nQ9BYF1\tP59594\nQ9BYF1\tP0DTC2\nQ9BYF1\tP0DTC2\nQ53F19\tP56270\nQ53F19\tQ14011\nQ53F19\tQ8N0Z6\nQ53F19\tQ8N8U2\nQ53F19\tP35052\nQ53F19\tO95373\nQ53F19\tQ9UH99\nQ53F19\tQ8NEM0\nQ53F19\tQ32M45\nQ53F19\tQ6L8Q7\nQ53F19\tQ6PJT7\nQ53F19\tQ02224\nQ53F19\tP31150\nQ53F19\tQ5DJT8\nQ53F19\tQ9UER7\nQ53F19\tP48668\nQ53F19\tO75940\nQ53F19\tJ3QSV6\nQ53F19\tO95619\nQ53F19\tQ7L590\nQ53F19\tQ96GX9\nQ53F19\tQ6IEG0\nQ53F19\tQ9BY42\nQ53F19\tP61326\nQ53F19\tQ96IZ7\nQ53F19\tQ8TF76\nQ53F19\tO00148\nQ53F19\tP49756\nQ53F19\tQ10589\nQ53F19\tP31431\nQ53F19\tP34741\nQ53F19\tP83916\nQ53F19\tP63104\nQ53F19\tO75400\nQ53F19\tQ8TDD1\nQ53F19\tP09603\nQ53F19\tQ86WX3\nQ53F19\tQ00403\nQ53F19\tQ13352\nQ53F19\tQ13011\nQ53F19\tQ9BRP8\nQ53F19\tQ9BSM1\nQ53F19\tQ6SPF0\nQ53F19\tO60684\nQ53F19\tQ16630\nQ53F19\tP55198\nQ53F19\tP78563\nQ53F19\tO00422\nQ53F19\tQ9ULL5\nQ53F19\tP52298\nQ53F19\tQ09161\nQ53F19\tQ9BXP5\nQ53F19\tQ96PV6\nQ53F19\tQ9UHI6\nQ53F19\tQ9UKV3\nQ53F19\tQ86U42\nQ53F19\tQ13155\nQ53F19\tP34897\nQ53F19\tQ9UKS6\nQ53F19\tO14950\nQ53F19\tP53582\nQ53F19\tP20700\nQ53F19\tP68400\nQ53F19\tQ5JVF3\nQ53F19\tP19784\nQ53F19\tO00629\nQ53F19\tP68036\nQ53F19\tQ96A72\nQ53F19\tQ9Y5S9\nQ53F19\tP15692\nQ53F19\tP35637\nQ53F19\tQ00688\nQ53F19\tP98179\nQ53F19\tQ9P289\nQ53F19\tO00505\nQ53F19\tQ96K17\nQ53F19\tQ9H307\nQ53F19\tQ96J01\nQ53F19\tQ8NI27\nQ53F19\tQ13769\nQ53F19\tQ13838\nQ53F19\tQ86W42\nQ53F19\tQ96FV9\nQ53F19\tP38919\nQ53F19\tQ6I9Y2\nQ53F19\tP51148\nQ53F19\tP50395\nP52298\tQ9UH99\nP52298\tP04003\nP52298\tQ8N0X7\nP52298\tK7ELV2\nP52298\tP14735\nP52298\tQ5VV67\nP52298\tP31150\nP52298\tQ5DJT8\nP52298\tP52294\nP52298\tP09603\nP52298\tP53007\nP52298\tQ9NWV8\nP52298\tQ8N5P1\nP52298\tQ9ULL5\nP52298\tO94762\nP52298\tP39880\nP52298\tQ8IXH7\nP52298\tQ9H3P2\nP52298\tQ6NZY4\nP52298\tQ8WX92\nP52298\tQ9Y580\nP52298\tQ86VM9\nP52298\tQ9H814\nP52298\tP18615\nP52298\tQ09161\nP52298\tQ9BXP5\nP52298\tQ9UHI6\nP52298\tQ8NC51\nP52298\tO75822\nP52298\tQ9P289\nP52298\tO00505\nP52298\tP51148\nP52298\tP50395\nP52298\tP61927\nP52298\tO00505\nP52298\tQ13769\nP52298\tQ9H814\nP52298\tQ09161\nP52298\tQ9BXP5\nP52298\tP38919\nQ53F19\tO00505\nQ53F19\tQ13769\nQ53F19\tQ9H814\nQ53F19\tP38919\nQ53F19\tQ09161\nQ53F19\tQ9BXP5\nQ09161\tQ53F19\nP33724\tP59632\nP33724\tP59632\nP33724\tP59632\nP33724\tP59632\nP59632\tP33724\nP0DTC9\tP0DTC4\nP0DTC3\tP0DTC4\nP0DTD2\tP0DTC4\nQ14160\tB7Z2Y1\nQ14160\tQ14155\nQ14160\tQ7Z628\nP22460\tQ14160\nQ96DN2\tQ14160\nO00429\tQ14160\nQ99569\tQ14160\nQ96DL1\tQ14160\nB7Z2Y1\tQ14160\nQ14155\tQ14160\nQ9UQB3\tQ14160\nQ9BR11\tQ14160\nQ96DL1\tQ14160\nQ14155\tQ14160\nB7Z2Y1\tQ14160\nQ9ULI0\tQ14160\nP25100\tQ14160\nP53778\tQ14160\nQ9NYB5\tQ14160\nQ15311\tQ14160\nP33402\tQ14160\nQ9P0K1\tQ14160\nQ92953\tQ14160\nO15439\tQ14160\nP35222\tQ14160\nP48065\tQ14160\nQ14160\tP08581\nP22460\tQ14160\nO00429\tQ14160\nQ14160\tQ6UY11\nQ14160\tQ9ULJ7\nQ14160\tA6NIM6\nP81408\tQ14160\nQ9NQG5\tQ14160\nQ6UXZ0\tQ14160\nQ92502\tQ14160\nQ8TA94\tQ14160\nQ9Y6R1\tQ14160\nQ9Y466\tQ14160\nQ8TBB1\tQ14160\nP22460\tQ12959\nQ9UQB3\tQ12959\nQ12959\tQ96DL1\nQ12959\tQ15311\nQ12959\tQ96A65\nQ6ZTQ3\tQ12959\nQ12959\tQ14CM0\nQ12959\tQ9NYB5\nQ12959\tQ14524\nQ12959\tQ13224\nQ12959\tP85299\nQ12959\tQ9NVW2\nQ12959\tQ99569\nQ12959\tQ6DN90\nQ12959\tQ86W11\nQ12959\tA1L4L8\nQ12959\tQ15303\nQ12959\tQ96GG9\nQ96GL9\tQ12959\nQ86UD3\tQ12959\nO60333\tQ12959\nA1A5B4\tQ12959\nQ7Z628\tQ12959\nP0C2L3\tQ12959\nQ9NS75\tQ12959\nQ96SF7\tQ12959\nB7Z2Y1\tQ12959\nQ9NS75\tQ12959\nQ9P021\tQ12959\nQ7Z628\tQ12959\nQ99569\tQ96NW7\nQ9UQB3\tQ96NW7\nQ9UQB3\tQ96RT1\nQ99569\tQ96RT1\nO00192\tQ96RT1\nQ9BY21\tQ96RT1\nQ96DL1\tQ96RT1\nQ8NHY3\tQ96RT1\nP50804\tQ12959\nP24835\tQ12959\nP50804\tQ12959\nP24835\tQ12959\nP27228\tQ12959\nQ06093\tQ12959\nP06463\tQ12959\nP21735\tQ12959\nP30911\tQ12959\nP06427\tQ12959\nP0C213\tQ12959\nP03126\tQ12959\nP27962\tQ12959\nP54667\tQ12959\nP54667\tQ12959\nP09708\tQ12959\nP17386\tQ12959\nP36807\tQ12959\nP26554\tQ12959\nQ0A442\tQ12959\nP30910\tQ12959\nP26555\tQ12959\nP16717\tQ12959\nP50804\tQ12959\nP24835\tQ12959\nP21735\tQ12959\nP06427\tQ12959\nP27228\tQ12959\nP09708\tQ12959\nA3EX99\tQ96RT1\nA3EXD5\tQ96RT1\nP06427\tQ96RT1\nQ9IDV3\tQ96RT1\nQ1A244\tQ96RT1\nP03126\tQ96RT1\nP50804\tQ96RT1\nP0C9G5\tQ96RT1\nA3EXD4\tQ96RT1\nP89432\tQ96RT1\nP0C213\tQ96RT1\nQ14160\tP06427\nQ14160\tP03126\nQ14160\tP17589\nP0C213\tQ14160\nQ14160\tP0C222\nP06427\tQ14160\nP03126\tQ14160\nP0C213\tQ14160\nP27228\tQ14160\nP24835\tQ14160\nP04299\tQ14160\nP16717\tQ14160\nP50804\tQ14160\nP21735\tQ14160\nP0C222\tQ14160\nP03333\tQ14160\nQ09SZ7\tQ14160\nQ08089\tQ14160\nQ18LE1\tQ96RT1\nQ14500\tQ14160\nP48050\tQ14160\nP12814\tQ14160\nP35609\tQ14160\nQ08043\tQ14160\nO43707\tQ14160\nQ8IWK6\tQ12959\nQ86SQ6\tQ12959\nQ96PE1\tQ12959\nP22459\tQ12959\nQ14500\tQ12959\nQ14155\tQ14160\nP33402\tQ14160\nP53778\tQ14160\nQ99569\tQ14160\nQ99569\tQ14160\nQ14155\tQ14160\nP53778\tQ14160\nP33402\tQ14160\nP35222\tQ14160\nP59595\tP63165\nP59595\tP63165\nP59595\tP09651\nP59595\tP09651\nP59595\tP09651\nP0C6X7\tO75348\nP0C6X7\tO75348\nP0C6X7\tO75348\nP0C6X7\tO75348\nP0C6X7\tO75348\n', - }, - { - kind: 'annotation', - name: 'COVID-19 KEGG pathways', - fileName: 'HomoSapiens_Pathways_KEGG_PATHWAY_FILTERED.txt', - text: 'Viral carcinogenesis\tQ00403,Q08043,Q14160,P04439,Q96EY1,Q92793,P06493,P35609,Q14653,P12814,P27348,Q7KZF4,P62258,O43707,P62191,P63104,Q12959\nInfluenza A\tP52294,P42224,P78406,Q92793,P53778,P52948,Q13838,Q14653,P08107,P52630,P0DMV8,O14980,P52292,Q86UT6,P00747,Q86U42\nHerpes simplex infection\tP19784,P42224,P62140,P67870,P04439,Q92793,P06493,P68400,P24928,Q14653,P52630,Q9UER7,Q86U32\nProximal tubule bicarbonate reclamation\tQ9Y6R1,Q9UBX3,P05023,P05026\n', - }, - { - kind: 'annotation', - name: 'COVID-19 SMART domains', - fileName: 'HomoSapiens_Protein_Domains_SMART_FILTERED.txt', - text: 'SM00265:BH4\tQ07817,Q92843,P10415\nSM00033:CH\tQ14315,P12814,Q08043,O43707,P13797,Q8NHY3,P35609,Q14155\nSM00361:RRM_1\tP11940,Q14011,Q13310,P19338,P38159\nSM00150:SPEC\tP12814,Q08043,P15924,O43707,P35609\nSM00088:PINT\tQ9UNM6,Q15008,Q14152,O00231\nSM00101:14_3_3\tP27348,P62258,P63104\nSM00948:SM00948\tP25787,O14818,P60900\nSM00557:IG_FLMN\tQ14315,Q7Z4H8,Q6UW63\nSM00490:HELICc\tQ9NR30,Q8TDD1,Q9BUQ8,Q9UHI6,O00148,P38919,Q13838,O94762\nSM00487:DEXDc\tQ9NR30,Q8TDD1,Q9BUQ8,Q9UHI6,O00148,P38919,Q13838,O94762\nSM00244:PHB\tP27105,P35232,Q99623\nSM00271:DnaJ\tQ8IXB1,Q99615,P31689,Q96EY1,O60884\n', - }, - { - kind: 'annotation', - name: 'COVID-19 InterPro domains', - fileName: 'HomoSapiens_Protein_Domains_INTERPRO_FILTERED.txt', - text: 'P-loop containing nucleoside triphosphate hydrolase\tQ9UM54,P35998,Q9NVI7,Q9ULI0,Q5T9A4,Q9HCE1,Q9NTJ3,P11586,P62195,Q02224,P33176,Q9H078,P38606,O00429,O15439,O00148,Q00839,Q9Y265,P38919,Q92900,Q96MM7,O14656,O94762,Q05639,Q5JWF2,Q9NR30,Q8TDD1,Q9UHI6,Q9BUQ8,Q13838,P51148,P25205,P06576,P33527,O95347,Q9NU22,P25705,O60333,P62191,Q9Y276,Q12959\nEF-hand-like domain\tQ08043,P42224,P60660,Q15293,Q07820,P35609,Q9Y680,O14950,P0DP23,P12814,P19105,P52630,O75746,Q9H4F8,Q96AY3,O43707,O43852,Q14257,P13797\nApoptosis regulator,Bcl-2,BH4 motif,conserved site\tQ07817,Q92843,P10415\nATPase,F1/V1/A1 complex,alpha/beta subunit,C-terminal\tP06576,P38606,P25705\nApoptosis regulator,Bcl-2 protein,BH4\tQ07817,Q92843,P10415\nDNA/RNA helicase,DEAD/DEAH box type,N-terminal\tQ9NR30,Q8TDD1,Q9BUQ8,Q9UHI6,O00148,P38919,Q13838,O94762\nFilamin/ABP280 repeat-like\tQ14315,O75592,Q7Z4H8,Q6UW63\nChaperone DnaJ\tP31689,Q96EY1,O60884\nCalponin homology domain\tQ14315,P12814,Q08043,O43707,P13797,Q8NHY3,P35609,Q14155\nRNA recognition motif domain,eukaryote\tP11940,Q14011,Q13310,P19338,P38159\nATPase,AAA-type,conserved site\tP35998,Q9ULI0,P62191,Q9Y276,P62195\nPeptidase M16,zinc-binding site\tQ10713,O75439,P14735\nKinase associated domain 1 (KA1)\tQ9P0L2,Q7KZI7,P27448\nATPase,alpha/beta subunit,N-terminal\tP06576,P38606,P25705\nHeat shock protein DnaJ,cysteine-rich domain\tP31689,Q96EY1,O60884\nATPase,F1/V1/A1 complex,alpha/beta subunit,nucleotide-binding domain\tP06576,P38606,P25705\nATPase,alpha/beta subunit,nucleotide-binding domain,active site\tP06576,P38606,P25705\nSpectrin/alpha-actinin\tP12814,Q08043,P15924,O43707,P35609\nImmunoglobulin E-set\tQ14315,Q96DL1,O75592,P08581,Q14500,Q7Z4H8,P48050,P61916,Q6UW63\nEF-Hand 1,calcium-binding site\tP0DP23,P12814,P19105,O75746,Q9H4F8,Q15293,Q96AY3,O43707,O43852,P13797,Q14257,Q9Y680,O14950\nEF-hand domain\tQ08043,P60660,Q15293,P35609,Q9Y680,O14950,P12814,P0DP23,P19105,O75746,Q96AY3,O43707,O43852,P13797,Q14257\n26S proteasome subunit P45\tP35998,P62191,P62195\nG-protein beta WD-40 repeat\tO43818,P53621,K7ELV2,P78406,P35606,P63244,Q16576,Q96J01\n14-3-3 protein\tP27348,P62258,P63104\n14-3-3 protein,conserved site\tP27348,P62258,P63104\n14-3-3 domain\tP27348,P62258,P63104\nApoptosis regulator,Bcl-2,BH3 motif,conserved site\tQ07817,Q07820,P10415\nProteasome A-type subunit\tP25787,O14818,P60900\nProteasome,alpha-subunit,N-terminal domain\tP25787,O14818,P60900\nChaperone DnaJ,C-terminal\tP31689,Q96EY1,O60884\nHSP40/DnaJ peptide-binding\tP31689,Q96EY1,O60884\nHelicase,C-terminal\tQ9NR30,Q8TDD1,Q9BUQ8,Q9UHI6,O00148,P38919,Q13838,O94762\nCation efflux protein\tQ8NEW0,Q6NXT4,Q6PML9\nCation efflux protein transmembrane domain\tQ8NEW0,Q6NXT4,Q6PML9\nFilamin/ABP280 repeat\tQ14315,Q7Z4H8,Q6UW63\nSpectrin repeat\tP12814,Q08043,O43707,P35609\nHelicase,superfamily 1/2,ATP-binding domain\tQ9NR30,Q8TDD1,Q9BUQ8,Q9UHI6,O00148,P38919,Q13838,O94762\nBromodomain,conserved site\tP25440,Q9ULI0,Q92793,O60885\nAnoctamin/TMEM 16\tA1A5B4,Q32M45,Q4KMQ2\nRNA helicase,ATP-dependent,DEAD-box,conserved site\tQ8TDD1,Q9BUQ8,Q9UHI6,P38919\nMitochondrial carrier protein\tP53007,O75746,Q9BQT8,Q9H936\nTetratricopeptide TPR-1\tQ99615,O94826,P31948,O43765\nBand 7 protein\tP27105,P35232,Q99623\nWD40-repeat-containing domain\tK7ELV2,Q9ULV4,P78406,P35606,Q86W42,Q16576,Q96JC1,O43818,B7Z2Y1,P53621,Q6P2E9,Q9H270,Q12770,P63244,Q96J01\nvon Willebrand factor,type A\tQ9NWV8,P05556,P12109,P12956,Q9NU22,P13010,P10155\nDnaJ domain\tQ8IXB1,Q99615,P31689,Q96EY1,O60884\nProteasome/cyclosome,regulatory subunit\tQ13200,Q99460\nApoptosis regulator,Bcl-2/ BclX\tQ07817,P10415\nTranscription factor TFIIB,cyclin-like domain\tQ00403,Q92994\nInsulin-induced protein family\tO15503,Q9Y5U4\nCoatomer,WD associated region\tP53621,P35606\nKu70/Ku80 C-terminal arm\tP12956,P13010\nKu70/Ku80,N-terminal alpha/beta\tP12956,P13010\nKu70/Ku80 beta-barrel domain\tP12956,P13010\nRab GDI protein\tP50395,P31150\nATPase,F1 complex beta subunit/V1 complex,C-terminal\tP06576,P38606\nMago nashi protein\tP61326,Q96A72\nClathrin/coatomer adaptor,adaptin-like,N-terminal\tQ9UBF2,O00203,P53618', - }, - { - kind: 'annotation', - name: 'COVID-19 GO biological process', - fileName: 'HomoSapiens_Gene_Ontology_GOTERM_BP_DIRECT_FILTERED.txt', - text: 'negative regulation of anoikis\tP06731,Q07817,P05556,Q07820,P10415\nT cell receptor signaling pathway\tP35998,P48556,Q13200,P25787,Q99460,P62195,Q9UNM6,O14818,Q15008,P51665,P60900,O00231,P62191\nregulation of cellular response to heat\tQ99615,P08107,K7ELV2,P62258,Q9UL15,O95816,P0DMV8,P78406,Q92793,P52948\nRNA secondary structure unwinding\tQ9NR30,Q8TDD1,Q9BUQ8,Q9UHI6,O00148,P38919,Q13838\nSRP-dependent cotranslational protein targeting to membrane\tP60866,P08708,P61254,P62269,P39019,P42677,P61927,P62753,Q9Y3U8,P46782\npositive regulation of establishment of protein localization to telomere\tP40227,P17987,P48643,Q99832\nFc-epsilon receptor signaling pathway\tP35998,P48556,Q13200,P25787,Q99460,P62195,P0DP23,Q9UNM6,O14818,Q15008,P51665,P60900,O00231,P62191\nmRNA transport\tQ09161,O14980,Q9Y5S9,Q53F19,P09651,Q96A72,Q9UN86\nnegative regulation of transcription elongation from RNA polymerase II promoter\tQ8WX92,Q9H3P2,P18615,O94762\nnuclear export\tQ09161,Q9H814,P52298,P09651\nresponse to hydrogen peroxide\tO00629,Q13443,P22460,P42224,Q9P289,P09601,P10415\nintracellular protein transport\tQ9UM54,Q9H173,Q9ULJ7,Q14974,O00203,P35606,O14964,Q96JC1,P53621,O95373,Q9UBF2,Q9H270,O15397,O14980,O43592,P53618\nrRNA processing\tP60866,Q9NR30,P39019,P62753,P61927,P57678,O43818,P08708,P61254,Q9NU22,P62269,P42677,P38919,P46782,Q9Y3U8\nrelease of cytochrome c from mitochondria\tQ07817,Q16548,Q3ZCQ8,O00429,P10415\npositive regulation of translation\tP11940,Q9BRP8,Q14011,Q6PKG0,P98179,P38919,Q13838\nfocal adhesion assembly\tP12814,Q08043,P35609,Q14155,P10415\ncalcium activated phosphatidylserine scrambling\tA1A5B4,Q32M45,Q4KMQ2\ngene silencing by RNA\tP30876,Q09161,Q7KZF4,P11940,K7ELV2,P52298,O15397,P78406,P52948,P24928\nnegative regulation of programmed cell death\tP02768,Q96EY1,O76024,P62195\nprotein folding in endoplasmic reticulum\tQ8N766,Q8IXB1,Q86YB8,P11021\npositive regulation of viral genome replication\tP62937,P11940,Q6PKG0,Q9P035,P78563\nprotein complex assembly\tP52907,O14745,Q9BSJ2,O43292,Q9Y375,Q9NU22,P30153,Q92793,P06493,O00505\nmitochondrion organization\tP06576,P35232,Q5VV67,O00429,Q96EY1,P09874,Q9Y276,Q99623\nT cell differentiation in thymus\tP61769,Q96EY1,P62753,P35222,P10415\nintra-Golgi vesicle-mediated transport\tP53621,Q9UBF2,P35606,P39880,P53618\nprotein homotetramerization\tQ9H773,Q96GX9,O00429,P34897,Q14500,P35609,P14735\ncalcium activated galactosylceramide scrambling\tA1A5B4,Q32M45,Q4KMQ2\ncalcium activated phosphatidylcholine scrambling\tA1A5B4,Q32M45,Q4KMQ2\nviral entry into host cell\tP08107,P27487,P05556,P15151,P0DMV8,Q9BYF1,P15144,O00505,P14735\nDNA duplex unwinding\tQ13283,P12956,P13010,Q9Y265,P25205,O94762\nplatelet degranulation\tP0DP23,P12814,P05155,P02768,O15439,P15692,O43707,P00747,P35609\nregulation of nucleic acid-templated transcription\tP12814,P35637,O43707,P35609\ncell proliferation\tO15503,P68036,Q14160,Q13561,P08581,P13010,Q16576,P06493,Q15303,P25100,Q07817,P09603,Q9BXP5,Q6PKG0,O95071,P42677,Q7L590,P12004,Q10589,P10415\nosteoblast differentiation\tP35998,Q9NR30,Q7KZF4,P06576,P35232,P12109,Q00839,J3QSV6,P38159\nintrinsic apoptotic signaling pathway in response to DNA damage\tQ07817,Q16548,Q92843,Q07820,P09601,P10415\nregulation of DNA recombination\tP52294,P52292,Q96FV9\npositive regulation of histone H3-K4 methylation\tP26358,P35222,Q9H3P2,P18615\ntransport\tP53007,Q9Y6R1,P02768,Q9UBX3,P52948,Q15818,Q9UN86,Q9NZJ7,Q15311,P46379,P33527,P38606,Q13283,Q00325,Q02978,Q9Y3A6,Q13224,Q9H936,P48065\npositive regulation of intrinsic apoptotic signaling pathway\tO14745,Q07817,O00429,P63244,P10415\n7-methylguanosine mRNA capping\tP30876,Q09161,P52298,Q53F19,P24928\nSREBP signaling pathway\tO15503,Q9Y5U4,Q12770\nIRES-dependent viral translational initiation\tP26599,Q14152,O00303\nextrinsic apoptotic signaling pathway in absence of ligand\tQ07817,Q16548,Q92843,Q07820,P10415\nribosomal small subunit assembly\tP08708,P39019,P42677,P46782\nubiquitin-dependent protein catabolic process\tP35998,P68036,P46379,Q9UNM6,P25787,O14818,Q9NXK8,O95071,P60900,O00231,P63279,Q9NVW2\nregulation of translational initiation\tQ09161,P52298,O75822,Q14152,O00303\nestablishment of integrated proviral latency\tP62937,P12956,P13010\nresponse to endoplasmic reticulum stress\tQ8IXB1,Q13438,P57088,Q9Y4L1,P16615,O76024,Q9BS26\nchaperone-mediated protein folding\tQ96AY3,P68400,O14656,Q9Y680,Q00688\ngastrulation\tP37173,P63244,P62753,P09622\nfibrinolysis\tP07355,P00750,P05155,P00747\nnegative regulation of mRNA splicing,via spliceosome\tO00422,P26599,Q9UKV3,P38159\nRNA processing\tQ13310,Q8TDD1,Q9UHI6,P98179,Q96FV9,Q00839,P78563,Q86U42\nnegative regulation of apoptotic process\tQ9NVI7,P31689,P02768,Q96GX9,Q92843,Q96EY1,P62753,Q86W42,P06493,Q07820,Q15303,P06731,Q07817,Q16548,P46379,Q9Y466,P11021,P15692,Q5JVF3,Q99623,P10415,P63104\nnegative regulation of intrinsic apoptotic signaling pathway\tQ07817,Q92843,Q07820,P10415\nprotein targeting\tP27348,Q13438,P62258,Q96RT1,P63104\nregulation of smooth muscle cell proliferation\tP12956,P13010,P35222\npositive regulation of RNA polymerase II transcriptional preinitiation complex assembly\tP35998,P62191,P62195\nresponse to hypoxia\tP22460,P00750,P37173,P27487,O00469,Q12770,P15692,Q92793,P09601,O43707,P05026\nresponse to drug\tQ9UM54,Q5JWF2,P42224,P13010,P06493,Q92820,P35222,P61769,P37173,P33527,O14980,P40939,O15439,P28300,P05023,P10415\nmembrane repolarization during cardiac muscle cell action potential\tP62258,P05023,P05026\nendoplasmic reticulum mannose trimming\tQ13438,Q9BZQ6,Q9NYU1\npositive regulation of potassium ion transport\tP33176,P35609,Q12959\npositive regulation of cellular component movement\tP39019,P15692,O43707\nresponse to unfolded protein\tP34932,Q96CS3,P31689,O95757,Q9BS26\ncellular protein modification process\tP00750,P68036,P38435,O00469,Q86YB8,P22314,P28300,P63279\nprotein peptidyl-prolyl isomerization\tQ6UX04,P62937,Q96AY3,Q9Y680,Q00688\nmuscle contraction\tQ9NYL9,P0DP23,P19105,Q08043,P60660,Q14500,P50402,Q86U42,O14950\ntype I interferon signaling pathway\tP42224,P52630,P04439,P05161,Q10589,Q14653\npositive regulation of protein ubiquitination\tQ9NV92,P68036,Q13155,Q96EY1,P11021,O76024\ngluconeogenesis\tP04406,P53007,O75746,Q9UBX3,Q02978\nmitotic nuclear envelope disassembly\tK7ELV2,P78406,P06493,P50402,P52948\npositive regulation of mesenchymal cell proliferation\tP37173,P42224,P15692,P35222\nprotein targeting to plasma membrane\tP07355,P19105,Q92953,P35613,O14950\npositive regulation of protein targeting to mitochondrion\tP19784,P48556,Q8TAD8,P68036,Q9H270,P55786,Q9Y265\nnuclear pore complex assembly\tP57088,Q9NQC3,P52948\npositive regulation of DNA-templated transcription,elongation\tQ13769,Q96FV9,Q13838\nendoplasmic reticulum unfolded protein response\tO76061,P11021,Q9BZQ6,Q9NYU1,O76024\nER-associated misfolded protein catabolic process\tQ99470,Q9NYU1,O14656\nrelaxation of cardiac muscle\tP05023,P16615,P05026\nproteasome assembly\tP48556,Q9UNM6,O00231\nregulation of cardiac muscle cell contraction\tQ14524,P05023,P63165\nlysine catabolic process\tQ9UDR5,Q9BQT8,P09622\npotassium ion import\tQ14500,P48050,P05023,P05026\nproteolysis involved in cellular protein catabolic process\tP25787,O14818,P11021,P60900,P14735\nsubstantia nigra development\tP0DP23,P27348,O15027,P62258,P11021\nestablishment or maintenance of epithelial cell apical/basal polarity\tQ7KZI7,Q96RT1,Q12959\nmicrotubule cytoskeleton organization\tQ9P0L2,P04406,Q96N67,Q7KZI7,P06493,P27448\npositive regulation of protein insertion into mitochondrial membrane involved in apoptotic signaling pathway\tP27348,P62258,P10415,P63104\n', - }, - { - kind: 'annotation', - name: 'COVID-19 GO molecular function', - fileName: 'HomoSapiens_Gene_Ontology_GOTERM_MF_DIRECT_FILTERED.txt', - text: 'poly(A) RNA binding\tP62753,J3QSV6,Q16630,Q13283,P62269,O00148,Q02978,O43707,Q00839,Q86WX3,Q13151,P68036,Q9BRP8,P17987,P39019,Q8TDD1,Q6NZY4,P11940,Q9UKV3,P62258,P56270,P16402,P67809,P61254,P63244,Q8NC51,P38159,P40227,Q9Y580,Q14974,P12956,P09874,Q00688,P78563,P30876,Q7KZF4,Q6PKG0,P63279,Q92900,P63104,Q7L8L6,Q8N5P1,Q9BUQ8,Q86VM9,Q14152,P63165,Q9UN86,Q13838,Q8WTT2,O43818,P50395,Q9BXP5,O75400,P61326,Q96A72,Q9Y3U8,P07355,Q09161,Q9Y5A9,P31948,P18615,Q6PJT7,Q9H307,Q5VV67,Q8NCA5,P09651,P15924,Q13310,P20290,P52298,P22314,P49756,P04439,P24928,P26599,P35637,Q9Y5S9,Q9NW13,P19338,P62191,Q15365,P04003,O75534,Q9ULX6,Q9HCE1,Q53F19,O00422,P52292,Q14739,P98179,P38919,Q9UKA9,P46782,Q86U42,Q16891,P60866,Q8TAD8,Q9NR30,P13010,P08708,P62937,P49368,Q14011,P25705,Q7KZI7,P42677,P08621,Q9NQC3,Q86U32,O75940,Q10589\nprotein binding\tQ9P021,Q13200,Q96GX9,Q13769,Q5H9R7,Q3ZCQ8,Q99988,Q86VR2,P62753,Q9NTJ3,P0DP23,P61769,Q9BSJ2,O43292,P62269,Q8TBB1,P59998,P50402,Q8IXH7,Q00839,P34741,Q99569,Q13561,Q07820,P55198,Q13352,Q4KMQ2,Q9NZJ7,Q96GG9,Q9H3K2,Q07817,Q9UKV3,P52630,P62258,Q86YB8,Q8NC51,P35998,P40227,Q00403,P26358,Q96PE1,P35606,Q92793,Q96FV9,Q15303,P09874,P35609,Q9Y680,Q00688,P78563,Q13443,Q15311,P27348,Q6PKG0,Q12789,P11021,Q92900,P63104,Q9ULJ7,Q8WX92,Q7L8L6,P35613,Q9BUQ8,Q9UBX3,Q9P035,P25100,Q13838,Q9NQG5,P06576,Q9Y5U4,Q13438,Q9BXP5,O60333,P55085,Q13224,Q9NS75,P53618,Q09161,O14745,Q9P0K1,Q9UL15,Q9Y5A9,P31948,P30153,Q9H773,Q6PJT7,O75592,Q8NCA5,Q9Y3A6,P57088,O00303,P05023,P09651,P05026,Q9NZ01,P52294,Q9BQ95,Q96CW5,O95619,Q13310,P20290,P52298,Q8N0Z6,P49756,P14735,P24928,P37173,Q9H270,Q9Y5S9,P51665,O00192,P60900,Q96HW7,P00747,P19338,Q15365,Q12959,P27105,Q9BSM1,P25787,P04003,Q9UQB3,Q14CM0,P81408,P67870,Q9HCE1,P68400,Q8IXB1,P33176,O00422,P00750,Q96IZ7,P08107,P46379,P83916,Q8NEM0,Q96DZ1,P48643,O00429,P52292,P05161,O43765,P46782,Q99623,Q9UKS6,Q9NR30,O75348,P52948,P51148,Q8N0X7,P49368,Q99615,P05155,O15397,P0DMV8,P08621,Q6ZTQ3,Q9NQC3,O43852,Q10589,O76024,P25440,P04406,Q9ULV4,Q14524,Q96EY1,P53778,P35247,P09601,Q16630,Q5BJF2,Q9H845,O15027,Q13283,P15151,Q9NXK8,O00148,O95071,O95070,P53396,Q7L590,O43707,O14656,P10415,Q05639,Q86WX3,P68036,Q9BRP8,Q9Y6R1,P05556,O75822,P17987,Q13155,P39019,Q00765,Q13011,Q15293,P48668,O60884,Q6NZY4,O60885,O60684,P11940,P61254,P56270,P67809,Q9NU22,Q15008,P63244,Q96HR9,P31150,P48065,P38159,Q9BS26,Q9H173,Q9UM54,P34932,Q96A65,Q14974,O43633,Q96IV0,P12956,Q14160,Q96PV6,P16615,P35222,Q99832,P62195,P12814,P30876,P19105,Q9H078,Q02224,P52907,Q7KZF4,P35232,Q9Y375,O95816,Q14257,P63279,Q5JWF2,O94826,Q8N5P1,Q86VM9,Q14152,P07195,Q9H3P2,P63165,Q9UN86,Q14155,Q6DN90,Q14653,Q96NW7,P09603,P50395,Q9H814,O95347,P40939,P31431,O75400,Q8IWR1,Q9UER7,P61326,Q96A72,P07355,P31689,P42224,K7ELV2,P39656,Q16576,Q9BYF1,P11586,P18615,P27487,Q9NWV8,Q7Z5G4,Q9H8W4,P13804,Q9Y6M9,Q8N8U2,Q9Y265,Q96SF7,O00629,Q5SW79,P15924,P62140,P22459,P22314,Q9UHI6,Q99471,Q9UH99,P04439,Q96RT1,O14950,Q96S52,P22460,P26599,O14818,P20700,P35637,Q12770,Q8NI27,Q9H4F8,Q86UT6,P15692,Q9P289,P61158,P62191,Q9Y276,P19784,Q8IV08,Q96CS3,O15503,P08581,Q92843,O75534,P06493,Q9ULX6,P61916,Q53F19,O14964,O95373,Q9NV92,Q16548,Q96F46,O00124,Q14739,P28300,O75934,P98179,P48050,P38919,P12004,Q86U42,Q16891,P60866,Q8IWF2,Q6I9Y2,Q8TAD8,Q08043,Q8TF76,P02768,P60660,P13010,P34897,P57678,Q9NYU1,O00505,P27448,P25205,Q14315,Q6P2E9,P62937,O60762,Q14011,Q92552,O14980,P25705,Q7KZI7,P42677,Q96K17,Q5JVF3,O00231,Q86U32,O75940,P49069\nprotein domain specific binding\tQ14974,O43633,Q14524,Q9UHI6,P67870,P35609,O14964,P0DP23,P27348,Q9H270,P62258,O14980,P11021,P05023,P00747,P63104\nion channel binding\tP0DP23,P12814,P27348,Q08043,P62258,Q14524,O43707,P35222,P63165,P35609,Q12959\nHsp70 protein binding\tQ8IXB1,P31689,P46379,P31948,Q96EY1,P06493\nglycoprotein binding\tQ8IWF2,P61769,P00750,Q13438,Q96DZ1,P11021,Q9BYF1,P14735\nTBP-class protein binding\tP35998,Q00403,Q92994,P62191,P62195\nestrogen receptor binding\tP35637,Q8TDD1,P09874,P12004,P35222,Q99623\nmisfolded protein binding\tQ8IXB1,P46379,P11021,O14656\nprotein transporter activity\tO00629,P52294,O60684,O95373,Q14974,O15397,P52292,O00505\nBH3 domain binding\tQ07817,Q07820,P10415\nactin filament binding\tQ14315,P12814,Q9UM54,P47756,Q9ULV4,P59998,O43707,P61158,P13797,Q8NHY3,P35609\npoly(A) binding\tP11940,Q6PJT7,Q13310,P38919\nidentical protein binding\tP04406,P42224,Q96GX9,P67870,P09874,Q99832,P35609,P61769,Q9H773,P11310,P27487,Q8NEM0,O95816,O00429,O00148,Q7L590,P12004,P10415,P63104,P02768,Q13561,Q9UH99,P34897,P07195,Q13838,Q14653,P06731,Q07817,O14818,P52630,P35637,P15692,Q9P289,P19338,P38159\nRan GTPase binding\tO95373,Q14974,O15397,O14980,O43592\nintegrin binding\tQ13443,P12814,Q08043,Q9P0K1,P05556,O43707,Q96RT1,Q08431,P35609\nproteasome-activating ATPase activity\tP35998,P62191,P62195\ndolichyl-phosphate-mannose-protein mannosyltransferase activity\tO60762,Q9Y673,Q99470\ncytoskeletal protein binding\tP07355,Q14315,Q9UKS6,O14656,P35609,Q12959\noxidoreductase activity,acting on the CH-CH group of donors\tQ9NZ01,Q9H845,P11310,Q14739\nvirus receptor activity\tP08107,P27487,P05556,P15151,P0DMV8,Q9BYF1,P15144,P14735\nprotein N-terminus binding\tP19784,Q96A65,P27348,Q9UER7,O43707,P09874,P68400,Q99623\nprotein homodimerization activity\tP27105,P42224,Q92843,O76061,P09601,Q15303,P35609,P12814,Q16548,P83916,P27487,P15151,O00429,O43707,Q96SF7,P10415,Q08043,P39019,Q07820,P14735,Q14653,Q4KMQ2,P06731,Q07817,P09603,P63244,P15692,P51665,Q9UER7,Q9P289,Q10589,Q6UY11\nNAD binding\tP04406,P40939,P07195,P09622,P09874\nprotein kinase binding\tQ05639,Q13151,P62140,Q14524,Q9UL15,P39019,Q96EY1,P62753,P09874,P35222,Q14155,P0DP23,Q07817,P22460,P62269,Q9UER7,P05023,P63104,Q12959\nrRNA binding\tQ9NR30,Q7L8L6,P62269,P61927,P46782\nhistone deacetylase binding\tP35232,P08107,P62258,P0DMV8,P52292,Q9UHI6,Q9Y466,Q9ULX6,P09874\ntelomeric DNA binding\tP12956,P13010,P19338,Q92900\nRNA cap binding\tQ09161,Q6PKG0,P52298\nchromatin binding\tP25440,P26358,Q8N0Z6,Q9ULI0,P67870,P34897,Q92793,P06493,O60885,Q9H3P2,P18615,P30876,Q8WTT2,P83916,P67809,Q92900,P12004,Q6PML9,P38159\ncation transmembrane transporter activity\tQ8NEW0,Q6NXT4,Q6PML9\nphospholipid scramblase activity\tA1A5B4,Q32M45,Q4KMQ2\npeptidyl-prolyl cis-trans isomerase activity\tQ6UX04,P62937,Q96AY3,Q9Y680,Q00688', - }, - { - kind: 'annotation', - name: 'COVID-19 GO cellular component', - fileName: 'HomoSapiens_Gene_Ontology_GOTERM_CC_DIRECT_FILTERED.txt', - text: 'membrane\tP04406,Q13200,O00203,P62753,Q9NXS2,P09601,Q16630,J3QSV6,P61769,P53621,Q9BSJ2,O43292,P62269,O00148,O95071,P53396,Q2PZI1,P50402,Q00839,Q8IXH7,Q8TEQ8,O14656,P10415,P05556,Q13561,Q13155,P39019,Q8TDD1,Q13011,O60884,Q9BZQ6,Q07820,P29122,Q13352,Q4KMQ2,Q9NZJ7,Q9P2E5,O60684,P11940,Q07817,P62258,P61254,Q9NU22,P38159,Q8NC51,Q9UM54,P35998,Q96A65,Q14974,O43633,P12956,P09874,P16615,P35222,P62195,P30876,Q02224,Q7KZF4,P27348,Q15311,P35232,Q9Y673,Q6PKG0,Q12789,P11021,Q5JWF2,O94826,P35613,Q14152,P07195,Q6DN90,P06576,P50395,P09603,P33527,O75400,Q9Y3U8,P53618,P07355,O14745,P31689,Q9H488,Q99519,Q9UL15,P39656,P30153,Q9Y6E2,Q99460,Q96S66,P11586,P27487,O75592,Q9H307,O00303,Q9Y265,P05023,P09651,P05026,P51570,Q96CW5,Q9UHI6,P04439,Q99470,Q7Z2K6,Q96S52,P26599,P20700,P47756,Q00325,P15692,P51665,P61158,P62191,P19338,Q15365,P27105,P06493,P33176,Q8IXB1,O95373,P46379,O15439,Q14739,P52292,O00429,P38919,O43765,P46782,Q99623,Q16891,P60866,Q9NR30,Q9C0B5,P60660,P13010,P57678,P25205,P08708,Q6P2E9,P62937,Q99615,Q8NEW0,O60762,P38435,P12109,Q9UNM6,O14980,P25705,Q7KZI7,Q9Y4L1,O43852,O00231,Q08431,P49069,Q6NXT4,Q10589\nnucleoplasm\tP48556,Q13200,Q13769,Q5H9R7,Q3ZCQ8,P53778,P62753,Q16630,Q9NTJ3,P0DP23,Q9BSJ2,P62269,O00148,O95071,P53396,Q7L590,Q00839,Q8IXH7,Q96J01,Q86WX3,Q13151,Q9BRP8,P39019,P39880,Q6NZY4,Q86W42,Q07820,O60885,Q13352,O60684,Q6IEG0,Q9UKV3,P52630,P67809,Q15008,Q9H936,P38159,Q9UM54,P35998,Q00403,Q9Y580,Q14974,P26358,Q14160,P12956,Q92793,P09622,Q96FV9,Q15303,P09874,P35222,P62195,P78563,P30876,P35232,Q6PKG0,Q12789,Q96MM7,Q92900,P63279,O94762,P63104,Q8WX92,Q86VM9,Q9BUQ8,Q92994,Q8N5P1,Q9H3P2,Q9NVW2,P63165,Q14653,Q13838,Q9NQG5,O43818,Q9BXP5,Q9H814,O95347,Q9Y466,O75400,O43592,Q9UER7,P61326,Q09161,P42224,Q99460,Q16576,P18615,Q6PJT7,Q9NWV8,Q5VV67,Q9H307,Q9Y265,P09651,O00629,P52294,Q9BQ95,O95619,P62140,P52298,Q8N0Z6,P49756,Q9UHI6,Q96RT1,P14735,P24928,P26599,P20700,O14818,P35637,Q9Y5S9,Q8NI27,P51665,Q96HW7,P60900,P62191,P19338,Q15365,P19784,Q7Z4H7,P25787,P67870,P06493,Q9ULX6,P68400,O00422,O95373,P08107,P83916,P46379,Q8NEM0,P52292,O75934,P98179,P38919,P12004,P05161,P46782,Q86U42,P60866,Q6I9Y2,Q9UKS6,Q9NR30,Q8TAD8,P13010,P57678,O00505,P52948,P25205,P08708,Q6P2E9,Q99615,Q14011,Q9UNM6,O15397,O14980,P0DMV8,P42677,P08621,Q86U32,O00231\npseudopodium\tP12814,Q08043,P55085,O43707,P35609\nbrush border\tP12814,P19105,Q08043,P47756,P60660,O00429,O43707,P61158,O14950\nnuclear matrix\tO95619,P20700,O75400,O43592,P60900,Q9ULX6,Q96FV9,Q9Y265,Q99623,Q13838\nzona pellucida receptor complex\tP49368,P17987,P48643,Q99832\nextracellular matrix\tP07355,P60866,P40227,P04406,P15924,P60660,P39019,P29122,P08708,P06576,P00750,P12109,P62269,P40939,P25705,P11021,Q00839,Q08431,P46782\ncytosolic small ribosomal subunit\tP60866,P08708,P62269,P39019,P42677,P62753,P46782\nactin filament\tP12814,Q08043,Q9H270,P47756,Q7KZI7,Q96EY1,P13797,P35609\ncytosolic proteasome complex\tP35998,P62191,P14735,P62195\nsarcolemma\tP07355,Q14315,P05556,P12109,Q14524,P35613,P05023,P05026,Q12959\nvesicle\tP07355,P0DP23,P27105,P33176,P50395,O14745,Q8NEW0,P04406,Q13561,Q9ULV4,P60660\nplatelet alpha granule lumen\tP12814,P05155,P02768,P15692,O43707,P00747,P35609\nperinuclear region of cytoplasm\tP07355,Q9UM54,P27105,O14745,P04406,P31689,P42224,Q9UL15,O76061,P62753,P09601,P16615,P35222,P33176,Q9NV92,P08107,O00429,O43707,Q5JWF2,P05556,Q99569,P25205,Q8NEW0,P09603,P22460,P35637,P0DMV8,P63244,Q9P289,Q8NC51,Q12959\nspliceosomal complex\tP49756,O00148,O75934,P08621,Q9NW13,Q9UKA9,O75940,P09651,Q13838\nendoplasmic reticulum quality control compartment\tQ13438,Q96DZ1,Q9BZQ6,Q9NYU1\nmembrane raft\tP07355,P27105,O14745,P22460,P37173,P27487,P05556,P35613,P31431,P35052,Q9BYF1,P07195,Q10589,Q12959\nZ disc\tQ14315,P12814,P19105,P22460,Q08043,P47756,Q14524,O43707,P35222,P35609,O14950\nCOPI vesicle coat\tP53621,Q9UBF2,P35606,P53618\nsmall ribosomal subunit\tP60866,P62269,P63244,P62753,P46782\nmitochondrial nucleoid\tP06576,Q9NVI7,Q7L8L6,P40939,P34897,Q96EY1\ncell surface\tP07355,P05556,Q96PE1,Q14524,P08581,P04439,Q9BYF1,P29122,P14735,Q4KMQ2,Q13443,P06576,P00750,P35232,P27487,P15151,P31431,P11021,P15692,Q13224,Q00839,P00747,Q10589,P34741,Q9BS26,Q99623\nCRD-mediated mRNA stability complex\tP67809,O75534,Q00839\nendoplasmic reticulum-Golgi intermediate compartment\tO95070,P11021,Q9Y3A6,P15144,Q9NYU1,Q9BS26,P53618\nmicrotubule\tP40227,Q5SW79,Q96CW5,Q7Z4H7,P17987,Q13561,Q14152,Q99832,P49368,P33176,Q02224,Q9BSJ2,P48643,O00429,O60333,P50402,Q12959\nendocytic vesicle\tQ9UM54,P33176,Q9H270,P27487,P35247,P51148\ncytoplasmic stress granule\tP11940,Q14011,Q13310,Q13283,P67809\nproteasome regulatory particle,lid subcomplex\tP48556,Q9UNM6,O00231\nproteasome core complex,alpha-subunit complex\tP25787,O14818,P60900\nnuclear proteasome complex\tP35998,P62191,P62195\nmitochondrial matrix\tQ96EY1,P34897,O75439,Q07820,Q15303,P09622,Q8IZ52,Q9UDR5,Q07817,P06576,P11310,Q5JRX3,Q9BW92,Q10713,P25705,P13804,Q6L8Q7\ncytoplasmic mRNA processing body\tP35998,Q6P2E9,P25787,Q9Y5A9,P60900,Q9HCE1,Q92900\nlysosomal membrane\tP07355,Q9UM54,Q8IWA5,O75348,Q99519,O00203,P22314,Q96JC1,P51148,B7Z2Y1,P12109,P27487,Q9H270,P38606,P15144\nintracellular membrane-bounded organelle\tP35998,P04406,O14745,Q99519,P39656,Q96EY1,Q96S66,O14964,Q9NV92,P46379,O00429,O95070,Q9Y265,P05023,Q8N0Z8,P25205,P51148,Q9UDR5,Q6P2E9,O60762,Q9H814,P67809,O14980,Q15365,P53618\nmitochondrial outer membrane\tQ07817,Q16548,O94826,Q92843,O00429,Q86UT6,Q07820,Q99623,P10415,Q8N0X7\nintegral component of endoplasmic reticulum membrane\tQ9NZ01,O00124,Q14739,P11021,P57088,Q9P035,Q9NQC3,O76024\ndesmosome\tP15924,Q99569,P22314,Q9H307\ncentrosome\tQ6NXT6,O14745,Q5SW79,Q96CW5,Q8TF76,Q7Z4H7,P17987,Q13561,P06493,P35222,P25205,Q9NQG5,P0DP23,Q07817,Q9H814,Q9BSJ2,P48643,Q8IWR1,Q9P289,P12004\nfascia adherens\tP12814,P15924,P35222\ncytoplasmic ribonucleoprotein granule\tP11940,P62753,Q00839,P19338\ncaveola\tP22460,P37173,Q14524,P09601,P05023,P05026\nendoplasmic reticulum chaperone complex\tQ8IXB1,P11021,Q9Y4L1\nAP-3 adaptor complex\tQ9H270,O00203,Q96JC1\nDNA-directed RNA polymerase II,holoenzyme\tQ9NQG5,Q9UM54,O94762\nnuclear euchromatin\tP16402,P35222,P24928,P38159\nPcG protein complex\tP19784,Q9BSM1,P67870,P68400\nruffle\tP07355,P12814,Q5JWF2,Q9UM54,O14745,P05556,Q14155\nribosome\tP60866,P08708,Q86WX3,Q92552,P62269,P39019,P42677,P61927,P62753,Q9Y3U8\ntransport vesicle\tQ5JWF2,P53621,Q9UBF2,Q9H8W4,P35606,Q15818,P53618\ncell-cell junction\tP07355,Q9NYL9,P12814,Q99569,Q14160,Q9H307,O43707,P61158,P35222,Q12959\nRNA cap binding complex\tQ09161,Q53F19\nScrib-APC-beta-catenin complex\tQ14160,P35222\nproteasome storage granule\tQ13200,Q99460\n', - }, - ], - }, - gallus: { - title: 'Gallus gallus (BioGRID)', - source: 'BioGRID database', - link: null, - files: [ - { - kind: 'network', - name: 'Gallus gallus BioGRID', - fileName: 'Biogrid_no_self_loops.txt', - text: 'Source\tTarget\nP62760\tP60706\nP62764\tP60706\nO15392\tP53352\nQ9IAY5\tP49024\nQ9IAY5\tP49024\nP49024\tQ9IAY5\nQ13625\tP46936\nO93512\tO60542\nP41238\tQ7T2T1\nO42414\tQ9JI92\nO42414\tQ9JI92\nP05556\tQ00944\nP05556\tP49024\nP27986\tQ9DDT2\nP28497\tP23297\nP49024\tP12003\nP49024\tQ00944\nQ4KWZ7\tQ9DEA3\nQ9DEA3\tQ4KWZ7\nP53478\tQ9UUJ1\nP53478\tP32390\nP53478\tP78929\nP12003\tP60010\nP79987\tP56517\nP79987\tP56519\nP79987\tQ9W7I5\nP79987\tQ3C1E9\nQ9W7I5\tP79987\nP56517\tP79987\nP56519\tP79987\nQ5ZJY5\tO93257\nQ5R1T0\tP56517\nQ5R1T0\tP56519\nQ5R1T0\tP56517\nQ5R1T0\tP56519\nQ5R1T0\tP56520\nQ09472\tP17678\nP23204\tP17678\nP23204\tP23824\nP23204\tP23825\nQ92993\tP70082\nQ92993\tP0C1H3\nQ92993\tP84247\nQ92993\tP62801\nP56519\tQ9HAZ2\nO18738\tP31696\nQ8AYS7\tQ1T7B8\nQ8AYS7\tQ1T7C0\nQ8AYS7\tQ1T7B7\nQ8AYS7\tQ1T7C1\nQ8AYS7\tQ1T7B9\nQ90ZF9\tQ1T7B8\nQ90ZF9\tQ1T7C0\nQ90ZF9\tQ1T7B7\nQ90ZF9\tQ1T7C1\nQ90ZF9\tQ1T7B9\nQ76I90\tQ76I89\nQ76I89\tQ76I90\nQ8AYS8\tP09572\nQ8AYS8\tP11501\nQ8AYS8\tQ90593\nQ8AYS8\tP16053\nQ8AYS8\tP08106\nQ8AYS8\tO73885\nQ8AYS8\tQ5ZHY5\nQ8AYS8\tQ5ZL72\nQ8AYS8\tP09207\nQ8AYS8\tQ5ZLC5\nQ8AYS8\tP05094\nQ8AYS8\tP00508\nQ8AYS8\tP54097\nQ8AYS8\tP17153\nQ8AYS8\tQ5ZMT0\nQ8AYS8\tP28497\nQ8AYS8\tP62207\nQ8AYS8\tQ5ZKC9\nQ8AYS8\tQ5F3W6\nQ8AYS8\tP60878\nQ8AYS8\tQ5ZM44\nQ8AYS8\tP08250\nQ8AYS8\tQ5ZMB2\nQ8AYS8\tQ00649\nQ8AYS8\tQ5ZKK4\nQ8AYS8\tQ5ZIV5\nQ8AYS8\tQ5ZMD1\nQ8AYS8\tQ5ZLQ6\nQ8AYS8\tP07090\nQ8AYS8\tP81628\nQ8AYS8\tP42324\nQ8AYS8\tP62758\nQ8AYS8\tP62764\nQ8AYS8\tP08110\nQ8AYS8\tO93510\nQ8AYS8\tP13731\nQ8AYS8\tQ5F425\nQ8AYS8\tP18359\nQ8AYS8\tP02789\nQ8AYS8\tQ5ZL57\nQ8AYS8\tP19121\nQ8AYS8\tO57391\nQ8AYS8\tQ9PTG6\nQ8AYS8\tP63270\nQ8AYS8\tP51913\nQ8AYS8\tP05122\nQ8AYS8\tQ5ZME2\nQ8AYS8\tQ5ZHP5\nQ8AYS8\tP48463\nQ8AYS8\tP04354\nQ8AYS8\tP50890\nQ8AYS8\tP05419\nQ8AYS8\tP80566\nQ8AYS8\tP31395\nQ8AYS8\tP00940\nQ8AYS8\tQ5ZLN1\nQ8AYS8\tQ5ZJF4\nQ8AYS8\tP00340\nQ8AYS8\tP09654\nQ8AYS8\tO42163\nQ8AYS8\tP16580\nQ8AYS8\tP02112\nQ8AYS8\tP80026\nQ8AYS8\tQ5ZLG1\nQ8AYS8\tO57535\nQ8AYS8\tQ07212\nQ8AYS8\tO13268\nQ8AYS8\tP00337\nQ8AYS8\tP00356\nQ8AYS8\tP51903\nQ8AYS8\tP07341\nQ8AYS8\tP00548\nQ8AYS8\tP14732\nQ8AYS8\tP13648\nQ8AYS8\tQ5F3W6\nQ8AYS8\tP42324\nQ8AYS8\tP60878\nQ8AYS8\tP17153\nQ8AYS8\tQ5ZL72\nQ8AYS8\tQ5F425\nQ8AYS8\tP80566\nQ8AYS8\tQ01406\nQ8AYS8\tP08106\nQ8AYS8\tP31395\nQ8AYS8\tQ90593\nQ8AYS8\tQ04619\nQ8AYS8\tP14731\nQ5F3W6\tQ8AYS8\nP42324\tQ8AYS8\nP60878\tQ8AYS8\nP17153\tQ8AYS8\nQ5ZL72\tQ8AYS8\nQ5F425\tQ8AYS8\nP80566\tQ8AYS8\nQ01406\tQ8AYS8\nP08106\tQ8AYS8\nP31395\tQ8AYS8\nQ90593\tQ8AYS8\nQ04619\tQ8AYS8\nP14731\tQ8AYS8\nP84023\tP49140\nP84023\tP83038\nP38531\tP04637\nP38531\tP06876\nP38531\tP01103\nF1N9Y5\tP00548\nF1N9Y5\tP09244\nF1N9Y5\tO73885\nF1N9Y5\tQ5ZL72\nF1N9Y5\tP11501\nF1N9Y5\tQ90705\nF1N9Y5\tQ5ZLC5\nF1N9Y5\tP51913\nF1N9Y5\tQ5ZM98\nF1N9Y5\tP38024\nF1N9Y5\tP47826\nF1N9Y5\tP08070\nF1N9Y5\tQ90593\nF1N9Y5\tP15771\nF1N9Y5\tQ9IAY5\nF1N9Y5\tP50890\nF1N9Y5\tQ5ZJK8\nF1N9Y5\tP51903\nF1N9Y5\tP67883\nF1N9Y5\tP00340\nF1N9Y5\tQ6EE31\nF1N9Y5\tP22451\nF1N9Y5\tQ8UVD9\nF1N9Y5\tQ5ZJU3\nF1N9Y5\tO57535\nF1N9Y5\tQ5ZLP8\nF1N9Y5\tQ04619\nF1N9Y5\tQ5ZIQ3\nF1N9Y5\tP47836\nF1N9Y5\tQ5ZKC9\nF1N9Y5\tQ5ZK03\nF1N9Y5\tQ8AYC9\nF1N9Y5\tP00356\nF1N9Y5\tQ5ZLN4\nF1N9Y5\tQ5ZJ56\nF1N9Y5\tP18660\nF1N9Y5\tQ5ZMT0\nF1N9Y5\tQ8JFP1\nF1N9Y5\tP32429\nF1N9Y5\tP16039\nF1N9Y5\tP00337\nF1N9Y5\tP08106\nF1N9Y5\tQ5ZMS3\nF1N9Y5\tP61355\nF1N9Y5\tQ5ZJ54\nF1N9Y5\tP63247\nF1N9Y5\tQ5ZKA5\nF1N9Y5\tP08629\nF1N9Y5\tP16527\nF1N9Y5\tQ5ZMN2\nF1N9Y5\tQ5ZJZ5\nF1N9Y5\tP18359\nF1N9Y5\tQ5ZKF5\nF1N9Y5\tQ5ZLN1\nF1N9Y5\tQ9YGC1\nF1N9Y5\tQ5ZLE6\nF1N9Y5\tQ8UW59\nF1N9Y5\tQ5ZKB9\nF1N9Y5\tP13863\nF1N9Y5\tQ90WU3\nF1N9Y5\tQ5ZI72\nF1N9Y5\tQ5ZIA5\nF1N9Y5\tP11029\nF1N9Y5\tQ98TF8\nF1N9Y5\tQ5ZL42\nF1N9Y5\tQ5ZKC1\nF1N9Y5\tP17790\nF1N9Y5\tQ5ZMN3\nF1N9Y5\tQ98TF6\nF1N9Y5\tQ5ZLC6\nF1N9Y5\tP24367\nF1N9Y5\tP11799\nF1N9Y5\tQ5ZK62\nF1N9Y5\tP26584\nF1N9Y5\tP14315\nF1N9Y5\tQ5ZKG5\nF1N9Y5\tP42558\nF1N9Y5\tP41239\nF1N9Y5\tP05419\nF1N9Y5\tP43347\nF1N9Y5\tP63283\nF1N9Y5\tQ5ZJN4\nF1N9Y5\tQ5ZL57\nF1N9Y5\tQ8JG64\nF1N9Y5\tO42392\nF1N9Y5\tQ5ZK01\nF1N9Y5\tP19179\nF1N9Y5\tO93256\nF1N9Y5\tQ02391\nP28683\tP62140\nQ6A078\tP00698\nP68400\tO13016\nP12931\tO13016\nP07812\tQ04619\nP07812\tP08106\nP62207\tQ90623\nQ90ZF9\tQ76I89\nQ90ZF9\tQ76I90\nQ90ZF9\tQ76I89\nP00523\tP19785\nP11501\tQ5ZL72\nP11501\tP08106\nQ04619\tQ5ZL72\nQ04619\tP08106\nP68399\tP01109\nP67868\tP01109\nQ12341\tP02263\nQ12341\tP62801\nQ5ZL72\tP08106\nQ5ZL72\tQ04619\nQ04619\tP08106\nQ06592\tP62801\nQ06592\tP84247\nP39979\tP62801\nQ3C1E9\tP79987\nQ3C1E9\tQ5R1S9\nQ3C1E9\tP84247\nQ3C1E9\tP62801\nP07812\tQ15185\nP07812\tP07900\nP07812\tP34932\nP07812\tP25685\nP07812\tP31948\nP25293\tP70082\nP25293\tP0C1H3\nP25293\tP84247\nP25293\tP62801\nQ702N8\tP68139\nA4UGR9\tP68139\nP68139\tP42639\nP42684\tQ04929\nQ92831\tP02263\nQ92831\tP62801\nQ9DEA3\tQ4KWZ7\nQ02842\tQ5ZJL9\nQ15185\tP11501\nP00523\tP51913\nQ04982\tQ5ZIK9\nQ04982\tP48463\nQ04982\tQ5ZM98\nQ04982\tP67869\nQ04982\tO73885\nQ04982\tQ5ZMN3\nQ04982\tP16039\nQ04982\tP42558\nQ04982\tQ6U7I1\nQ04982\tP05625\nQ04982\tQ5ZMD1\nQ04982\tQ5ZLQ6\nQ04982\tQ5ZMT0\nQ04982\tQ5ZKC9\nQ04982\tP50147\nQ04982\tQ5F3W6\nQ04982\tO57476\nQ04982\tP11501\nQ04982\tQ90828\nQ04982\tQ90891\nQ04982\tQ90593\nQ04982\tP08110\nP18652\tO95071\nO42414\tP16092\nP16092\tO42414\nP61088\tQ9DEA3\nQ15819\tQ9DEA3\nQ9W7C5\tQ401C0\nQ401C0\tQ9W7C5\nP11275\tP13387\nQ7T0L4\tQ9PU53\nQ07496\tP32004\n', - }, - { - kind: 'annotation', - name: 'Gallus gallus KEGG pathways', - fileName: 'BioGrid_Chicken_Gallus_Pathways_KEGG_PATHWAY_FILTERED.txt', - text: 'ErbB signaling pathway\tQ00944,Q04929,P00523,P01109,Q90891,P13387,Q9W7C5,P05625,Q04982\nCarbon metabolism\tP00356,O57391,P00548,P07341,P51903,Q5ZLN1,Q5ZME2,P51913,P00940,P00508\nBiosynthesis of antibiotics\tP00356,O57391,P00548,P07341,O57535,P51903,Q5ZLN1,P00337,Q5ZME2,P51913,P00940,P00508,P00340,P38024\nGap junction\tP00523,P09244,Q90891,P08070,P13387,P50147,P09207,P05625,P13863\nRibosome\tQ98TF6,Q98TF8,P67883,P32429,P61355,P47826,Q5ZJ56,P47836,P50890,P18660,P22451\nFocal adhesion\tQ00944,Q04929,P00523,Q90623,P13387,P05094,P60706,P53478,P11799,P49024,P12003,Q04982,P62207,P05625\nProgesterone-mediated oocyte maturation\tQ04619,P07812,P18652,P11501,P50147,P05625,Q04982,P13863\nVascular smooth muscle contraction\tQ8AYS8,P11799,Q90623,P05419,P63270,Q90891,P62207,P05625,Q04982\nProtein processing in endoplasmic reticulum\tQ04619,Q5ZKF5,Q90593,Q8JG64,O73885,P11501,P08110,Q5ZHY5,P81628,Q5ZK03,P08106\nPyruvate metabolism\tP00548,P00337,Q5ZME2,P11029,P00340\nVEGF signaling pathway\tQ00944,P00523,P49024,Q90891,P05625,Q00649\nInsulin signaling pathway\tQ04929,P05419,Q90891,P11029,P62207,P05625,Q04982,O13016\nTight junction\tP00523,P48463,P05094,P60706,P53478,Q01406', - }, - ], - }, - 'docs-tp53': { - title: 'TP53 (NORMA documentation)', - source: 'Example from the NORMA help pages', - link: null, - files: [ - { - kind: 'network', - name: 'TP53 docs network', - fileName: '', - text: 'Source\tTarget\tWeight\nCDKN1A\tTP53\t5\nTP53\tMDM2\t1\nMDM4\tTP53\t3\nBCL2L1\tTP53\t4\nCHEK2\tATM\t2\nTP53\tEP300\t1\nATM\tTP53\t4\nTP53\tCREBBP\t1\nMDM4\tMDM2\t1\nCHEK2\tTP53\t2\nTP53BP2\tTP53\t8\nCDKN2A\tTP53\t3\nCDKN2A\tMDM2\t3\nATM\tMDM2\t1\nEP300\tCREBBP\t2\n', - }, - { - kind: 'annotation', - name: 'TP53 docs groups', - fileName: '', - text: 'Group-2\tBCL2L1,MDM4,MDM2,CHEK2\nGroup-5\tTP53,EP300\nGroup-1\tCDKN2A,ATM,TP53BP2,MDM2\nGroup-4\tCHEK2,CREBBP,MDM2\nGroup-3\tTP53,BCL2L1\nGroup-6\tMDM4,MDM2\n', - }, - { - kind: 'colors', - name: 'TP53 docs expression', - fileName: '', - text: 'CDKN1A\tblue\nTP53\tblue\nMDM4\t#00ff00\nBCL2L1\tred\nCHEK2\tred\nATM\tred\nTP53BP2\tred\nCDKN2A\tblue\nEP300\t#ffff00\nCREBBP\tred\nMDM2\tblue\n', - }, - ], - }, -} - -/* ============================================================ - TABS AND HELP LINKS - ============================================================ */ -export const TAB_VIEWS = { - welcome: 'welcomeView', - network: 'canvas', - network3d: 'canvas', - profiler: 'profilerView', - compare: 'compareView', - help: 'helpView', - about: 'aboutView', - api: 'apiView', -} - -export let currentTab = 'welcome' - -export function switchTab(name, helpAnchor) { - if (!TAB_VIEWS[name]) return - currentTab = name - document.querySelectorAll('#tabs .tab').forEach((btn) => { - const on = btn.dataset.tab === name - btn.setAttribute('aria-selected', on ? 'true' : 'false') - btn.tabIndex = on ? 0 : -1 - }) - const onNetwork = name === 'network' || name === 'network3d' - document.getElementById('canvas').classList.toggle('inactive', !onNetwork) - if (typeof setMode3d === 'function' && (name === 'network3d') !== net3d.active) - setMode3d(name === 'network3d') - document.getElementById('welcomeView').classList.toggle('active', name === 'welcome') - document.getElementById('profilerView').classList.toggle('active', name === 'profiler') - if (name === 'profiler' && typeof refreshEnrichmentChoices === 'function') - refreshEnrichmentChoices() - document.getElementById('compareView').classList.toggle('active', name === 'compare') - document.getElementById('helpView').classList.toggle('active', name === 'help') - document.getElementById('aboutView').classList.toggle('active', name === 'about') - document.getElementById('apiView').classList.toggle('active', name === 'api') - if (name === 'network') { - document.getElementById('cy').style.visibility = '' - cy.resize() - resizeHullCanvas() - drawGroupHulls() - } - if (name === 'profiler') renderProfilerNetworkList() - if (name === 'compare') renderCompareList() - if ((name === 'help' || name === 'about' || name === 'api') && helpAnchor) { - const target = document.getElementById(helpAnchor) - if (target) { - target.scrollIntoView({ block: 'start' }) - target.classList.remove('flash') - void target.offsetWidth - target.classList.add('flash') - } - } -} - -/* ============================================================ - NETWORK PROFILER - Topology statistics following igraph's definitions, computed on a - simple undirected graph (self-loops and parallel edges set aside). - Path-based measures use one BFS per node (Brandes' algorithm for - betweenness), so they are skipped above PROFILE_PATH_LIMIT nodes. - ============================================================ */ -export const PROFILE_PATH_LIMIT = 8000 - -export const PROFILE_STATS = [ - { key: 'n', label: 'Nodes', igraph: 'vcount(g)', desc: 'Number of nodes.' }, - { - key: 'm', - label: 'Edges', - igraph: 'ecount(g)', - desc: 'Connections between distinct node pairs.', - }, - { - key: 'density', - label: 'Density', - igraph: 'edge_density(g)', - desc: 'Share of all possible node pairs that are connected.', - }, - { - key: 'avgDegree', - label: 'Average degree', - igraph: 'mean(degree(g))', - desc: 'Mean number of neighbors per node.', - }, - { - key: 'maxDegree', - label: 'Maximum degree', - igraph: 'max(degree(g))', - desc: 'Most neighbors of any node.', - }, - { - key: 'isolated', - label: 'Isolated nodes', - igraph: 'sum(degree(g) == 0)', - desc: 'Nodes without any connection.', - }, - { - key: 'components', - label: 'Connected components', - igraph: 'count_components(g)', - desc: 'Separate pieces of the network.', - }, - { - key: 'largest', - label: 'Largest component', - igraph: 'max(components(g)$csize)', - desc: 'Nodes in the biggest piece, with its share of all nodes.', - }, - { - key: 'diameter', - label: 'Diameter', - igraph: 'diameter(g)', - desc: 'Longest shortest path between any two connected nodes.', - }, - { - key: 'radius', - label: 'Radius', - igraph: 'radius(g)', - desc: 'Smallest eccentricity of any node.', - }, - { - key: 'avgPath', - label: 'Average path length', - igraph: 'mean_distance(g)', - desc: 'Mean shortest-path length over all connected node pairs.', - }, - { - key: 'avgEcc', - label: 'Average eccentricity', - igraph: 'mean(eccentricity(g))', - desc: 'Mean, over nodes, of the distance to the farthest reachable node.', - }, - { - key: 'transitivity', - label: 'Clustering coefficient', - igraph: 'transitivity(g, "global")', - desc: 'Share of connected triples that close into triangles.', - }, - { - key: 'avgLocal', - label: 'Average local clustering', - igraph: 'transitivity(g, "average")', - desc: "Mean of each node's own clustering coefficient, over nodes with two or more neighbors.", - }, - { - key: 'triangles', - label: 'Triangles', - igraph: 'sum(count_triangles(g)) / 3', - desc: 'Number of three-node cycles.', - }, - { - key: 'assortativity', - label: 'Degree assortativity', - igraph: 'assortativity_degree(g)', - desc: 'Above 0: hubs link to hubs. Below 0: hubs link to sparsely connected nodes.', - }, - { - key: 'centrDegree', - label: 'Degree centralization', - igraph: 'centr_degree(g, loops = FALSE)$centralization', - desc: 'How strongly connections concentrate on one node (1 for a star).', - }, - { - key: 'centrBetw', - label: 'Betweenness centralization', - igraph: 'centr_betw(g)$centralization', - desc: 'How strongly shortest paths run through one node.', - }, - { - key: 'centrClo', - label: 'Closeness centralization', - igraph: 'centr_clo(g)$centralization', - desc: 'How much one node is closer to all others than the rest are.', - }, - { - key: 'modularity', - label: 'Modularity (Louvain)', - igraph: 'modularity(cluster_louvain(g))', - desc: 'How well the network splits into dense communities; above about 0.3 suggests clear structure.', - }, - { - key: 'communities', - label: 'Communities (Louvain)', - igraph: 'length(cluster_louvain(g))', - desc: 'Number of communities Louvain finds, including single nodes.', - }, - { - key: 'setAside', - label: 'Set aside before profiling', - igraph: 'simplify(g)', - desc: 'Self-loops and parallel edges not counted as connections.', - }, -] - -export function formatStat(v) { - if (v === null || v === undefined || (typeof v === 'number' && Number.isNaN(v))) return '—' - if (typeof v === 'string') return v - if (!Number.isFinite(v)) return '—' - if (Number.isInteger(v)) return v.toLocaleString('en-US') - const abs = Math.abs(v) - if (abs !== 0 && abs < 0.001) return v.toExponential(2) - return (+v.toFixed(4)).toString() -} - -// ids: node names; pairs: [source, target] per edge -export function simpleGraph(ids, pairs) { - const index = new Map(ids.map((id, i) => [id, i])) - const n = ids.length - const sets = Array.from({ length: n }, () => new Set()) - let loops = 0, - parallel = 0 - pairs.forEach(([s, t]) => { - const a = index.get(s), - b = index.get(t) - if (a === undefined || b === undefined) return - if (a === b) { - loops++ - return - } - if (sets[a].has(b)) { - parallel++ - return - } - sets[a].add(b) - sets[b].add(a) - }) - const adj = sets.map((x) => Int32Array.from(x)) - let m = 0 - adj.forEach((a) => { - m += a.length - }) - return { ids, n, m: m / 2, adj, loops, parallel } -} - -export function profileGraph(g) { - const { n, m, adj } = g - const deg = adj.map((a) => a.length) - const r = { n, m, degree: deg } - r.density = n > 1 ? (2 * m) / (n * (n - 1)) : NaN - r.avgDegree = n ? (2 * m) / n : NaN - r.maxDegree = n ? Math.max(...deg) : NaN - r.isolated = deg.filter((d) => d === 0).length - r.setAside = - g.loops || g.parallel - ? [ - g.loops ? plural(g.loops, 'self-loop') : '', - g.parallel ? plural(g.parallel, 'parallel edge') : '', - ] - .filter(Boolean) - .join(', ') - : 'none' - - // connected components - const comp = new Int32Array(n).fill(-1) - const queue = new Int32Array(Math.max(1, n)) - const compSizes = [] - for (let s = 0; s < n; s++) { - if (comp[s] >= 0) continue - const c = compSizes.length - let head = 0, - tail = 0 - queue[tail++] = s - comp[s] = c - while (head < tail) { - const v = queue[head++] - const nb = adj[v] - for (let k = 0; k < nb.length; k++) { - const w = nb[k] - if (comp[w] < 0) { - comp[w] = c - queue[tail++] = w - } - } - } - compSizes.push(tail) - } - r.components = compSizes.length - const largest = compSizes.length ? Math.max(...compSizes) : 0 - r.largest = n ? `${largest.toLocaleString('en-US')} (${((100 * largest) / n).toFixed(1)}%)` : '—' - - // triangles and clustering - const tri = new Float64Array(n) - const mark = new Int32Array(n).fill(-1) - for (let u = 0; u < n; u++) { - const nu = adj[u] - for (let k = 0; k < nu.length; k++) mark[nu[k]] = u - for (let k = 0; k < nu.length; k++) { - const v = nu[k] - if (v <= u) continue - const nv = adj[v] - for (let q = 0; q < nv.length; q++) { - const w = nv[q] - if (w > v && mark[w] === u) { - tri[u]++ - tri[v]++ - tri[w]++ - } - } - } - } - let triSum = 0, - triples = 0, - localSum = 0, - localCount = 0 - const localClustering = new Float64Array(n) - for (let v = 0; v < n; v++) { - const d = deg[v] - triSum += tri[v] - const t = (d * (d - 1)) / 2 - triples += t - if (d >= 2) { - localClustering[v] = tri[v] / t - localSum += localClustering[v] - localCount++ - } - } - r.triangles = triSum / 3 - r.transitivity = triples > 0 ? triSum / triples : NaN - r.avgLocal = localCount ? localSum / localCount : NaN - r.localClustering = localClustering - - // degree assortativity (Newman), over each undirected edge once - if (m > 0) { - let sProd = 0, - sMean = 0, - sSq = 0 - for (let u = 0; u < n; u++) { - const nu = adj[u] - for (let k = 0; k < nu.length; k++) { - const v = nu[k] - if (v <= u) continue - const j = deg[u], - q = deg[v] - sProd += j * q - sMean += (j + q) / 2 - sSq += (j * j + q * q) / 2 - } - } - const mean = sMean / m - const denom = sSq / m - mean * mean - r.assortativity = Math.abs(denom) > 1e-12 ? (sProd / m - mean * mean) / denom : NaN - } else { - r.assortativity = NaN - } - - r.centrDegree = n > 2 ? deg.reduce((s, d) => s + (r.maxDegree - d), 0) / ((n - 1) * (n - 2)) : NaN - - // shortest paths, eccentricity, closeness, betweenness - if (n <= PROFILE_PATH_LIMIT) { - const dist = new Int32Array(n).fill(-1) - const sigma = new Float64Array(n) - const delta = new Float64Array(n) - const order = new Int32Array(Math.max(1, n)) - const betw = new Float64Array(n) - const ecc = new Float64Array(n) - const closeness = new Float64Array(n).fill(NaN) - let pathSum = 0, - pathCount = 0, - diameter = 0 - for (let s = 0; s < n; s++) { - let head = 0, - tail = 0 - order[tail++] = s - dist[s] = 0 - sigma[s] = 1 - let far = 0, - sum = 0 - while (head < tail) { - const v = order[head++] - const dv = dist[v] - if (dv > far) far = dv - sum += dv - const nb = adj[v] - for (let k = 0; k < nb.length; k++) { - const w = nb[k] - if (dist[w] < 0) { - dist[w] = dv + 1 - order[tail++] = w - } - if (dist[w] === dv + 1) sigma[w] += sigma[v] - } - } - const reached = tail - 1 - ecc[s] = far - if (far > diameter) diameter = far - if (reached > 0) { - closeness[s] = reached / sum - pathSum += sum - pathCount += reached - } - for (let i = tail - 1; i >= 0; i--) { - const w = order[i] - const nb = adj[w] - for (let k = 0; k < nb.length; k++) { - const v = nb[k] - if (dist[v] === dist[w] - 1) delta[v] += (sigma[v] / sigma[w]) * (1 + delta[w]) - } - if (w !== s) betw[w] += delta[w] - } - for (let i = 0; i < tail; i++) { - const v = order[i] - dist[v] = -1 - sigma[v] = 0 - delta[v] = 0 - } - } - for (let v = 0; v < n; v++) betw[v] /= 2 - r.betweenness = betw - r.closeness = closeness - r.diameter = n ? diameter : NaN - r.radius = n ? Math.min(...ecc) : NaN - r.avgEcc = n ? ecc.reduce((a, b) => a + b, 0) / n : NaN - r.avgPath = pathCount ? pathSum / pathCount : NaN - const maxB = n ? Math.max(...betw) : 0 - r.centrBetw = - n > 2 ? betw.reduce((s, b) => s + (maxB - b), 0) / (((n - 1) * (n - 1) * (n - 2)) / 2) : NaN - const finiteClo = [...closeness].filter(Number.isFinite) - const maxC = finiteClo.length ? Math.max(...finiteClo) : NaN - r.centrClo = - n > 2 && finiteClo.length - ? finiteClo.reduce((s, c) => s + (maxC - c), 0) / (((n - 1) * (n - 2)) / (2 * n - 3)) - : NaN - } else { - r.pathsSkipped = true - ;['diameter', 'radius', 'avgEcc', 'avgPath', 'centrBetw', 'centrClo'].forEach((k) => { - r[k] = NaN - }) - } - - const lv = louvain(g) - r.louvain = lv - r.modularity = lv.modularity - r.communities = lv.count - return r -} - -// Louvain community detection (Blondel et al. 2008), unweighted input, -// nodes visited in a fixed order so results are repeatable. -export function louvain(g, gamma = 1) { - const n = g.n - const twoM = 2 * g.m - if (!twoM) { - return { - membership: Int32Array.from({ length: n }, (_, i) => i), - count: n, - modularity: NaN, - sizes: new Array(n).fill(1), - } - } - let nbr = g.adj.map((a) => { - const mp = new Map() - a.forEach((v) => mp.set(v, 1)) - return mp - }) - let size = n - let membership = Int32Array.from({ length: n }, (_, i) => i) - for (let level = 0; level < 32; level++) { - const k = new Float64Array(size) - nbr.forEach((mp, i) => { - let s = 0 - mp.forEach((w) => { - s += w - }) - k[i] = s - }) - const comm = Int32Array.from({ length: size }, (_, i) => i) - const tot = Float64Array.from(k) - let moved = true, - anyMove = false, - passes = 0 - while (moved && passes < 100) { - moved = false - passes++ - for (let i = 0; i < size; i++) { - const ci = comm[i], - ki = k[i] - const links = new Map() - nbr[i].forEach((w, j) => { - if (j !== i) { - const cj = comm[j] - links.set(cj, (links.get(cj) || 0) + w) - } - }) - tot[ci] -= ki - let best = ci - let bestGain = (links.get(ci) || 0) - (gamma * tot[ci] * ki) / twoM - links.forEach((w, c) => { - const gain = w - (gamma * tot[c] * ki) / twoM - if (gain > bestGain + 1e-12) { - bestGain = gain - best = c - } - }) - tot[best] += ki - if (best !== ci) { - comm[i] = best - moved = true - anyMove = true - } - } - } - if (!anyMove) break - const remap = new Map() - for (let i = 0; i < size; i++) if (!remap.has(comm[i])) remap.set(comm[i], remap.size) - const next = remap.size - const agg = Array.from({ length: next }, () => new Map()) - for (let i = 0; i < size; i++) { - const ci = remap.get(comm[i]) - nbr[i].forEach((w, j) => { - const cj = remap.get(comm[j]) - agg[ci].set(cj, (agg[ci].get(cj) || 0) + w) - }) - } - membership = membership.map((x) => remap.get(comm[x])) - nbr = agg - if (next === size) break - size = next - } - // modularity on the original graph - let count = 0 - membership.forEach((c) => { - if (c + 1 > count) count = c + 1 - }) - const inW = new Float64Array(count), - totW = new Float64Array(count), - sizes = new Array(count).fill(0) - for (let u = 0; u < n; u++) { - const cu = membership[u] - sizes[cu]++ - totW[cu] += g.adj[u].length - g.adj[u].forEach((v) => { - if (membership[v] === cu) inW[cu] += 1 - }) - } - let q = 0 - for (let c = 0; c < count; c++) q += inW[c] / twoM - Math.pow(totW[c] / twoM, 2) - return { membership, count, modularity: q, sizes } -} - -// page wiring, run by main.ts in the original order -export function init() { - /* ---------- wiring ---------- */ - document - .getElementById('btnNormaAdd') - .addEventListener('click', () => document.getElementById('normaFileInput').click()) - - document.getElementById('normaFileInput').addEventListener('change', (e) => { - handleNormaUploads(e.target.files) - e.target.value = '' - }) - - ;(function setupDropZone() { - const zone = document.getElementById('dropZone') - let depth = 0 - zone.addEventListener('dragenter', (e) => { - e.preventDefault() - depth++ - zone.classList.add('dragging') - }) - zone.addEventListener('dragover', (e) => { - e.preventDefault() - e.dataTransfer.dropEffect = 'copy' - }) - zone.addEventListener('dragleave', () => { - depth = Math.max(0, depth - 1) - if (!depth) zone.classList.remove('dragging') - }) - zone.addEventListener('drop', (e) => { - e.preventDefault() - depth = 0 - zone.classList.remove('dragging') - if (e.dataTransfer.files && e.dataTransfer.files.length) - handleNormaUploads(e.dataTransfer.files) - }) - })() - - document.getElementById('btnRefreshView').addEventListener('click', () => { - const v = activeView() - refreshLibraryView() - if (v && v.autoName && cy.nodes().length) { - v.name = uniqueViewName(nameForSelection()) - renderViewBar() - } - }) - - document.getElementById('btnOpenNewView').addEventListener('click', () => { - if (!libSelection.networks.size) { - setStatus('normaStatus', [{ level: 'error', text: 'Tick at least one network first.' }]) - return - } - // the ticked files move to the new view; this view keeps what it shows - const pending = { - networks: [...libSelection.networks], - annotation: libSelection.annotation, - colors: libSelection.colors, - } - const cur = activeView() - const shown = selectionFromKey(S.currentLibView) - const name = nameForSelection() - if (cur && cy.nodes().length) { - libSelection.networks = new Set(shown.networks) - libSelection.annotation = shown.annotation - libSelection.colors = shown.colors - } - openInNewView(name, () => { - libSelection.networks = new Set(pending.networks) - libSelection.annotation = pending.annotation - libSelection.colors = pending.colors - refreshLibraryView() - }) - }) - - document.getElementById('btnNormaExportNetwork').addEventListener('click', exportNormaNetwork) - - document - .getElementById('btnNormaExportAnnotation') - .addEventListener('click', exportNormaAnnotation) - - document.getElementById('btnNormaExportColors').addEventListener('click', exportNormaColors) - - // A numeric expression file for the documentation example (simulated values, - // for trying the color scale; not measured data). - NORMA_EXAMPLE_SETS['docs-tp53'].files.push({ - kind: 'colors', - name: 'TP53 docs log2FC and adjusted p-values (simulated)', - fileName: 'TP53_docs_values_simulated.txt', - text: 'Gene\tlog2FC\tpadj\nCDKN1A\t2.4\t0.000001\nTP53\t-0.3\t0.41\nMDM4\t1.1\t0.02\nBCL2L1\t-1.8\t0.0003\nCHEK2\t-1.2\t0.004\nATM\t-0.9\t0.03\nTP53BP2\t-2.2\t0.00005\nCDKN2A\t1.7\t0.0002\nEP300\t0.4\t0.21\nCREBBP\t-0.6\t0.09\nMDM2\t2.9\t0.00000001\n', - }) - - // ---------- NORMA 3.0 examples that showcase the new features ---------- - ;(function addNorma3Examples() { - // 1. The example network from Arena3D's documentation: layers become groups - const arenaRows = [ - ['An', 'Group1', 'Cn', 'Group1', 2], - ['An', 'Group1', 'Bn', 'Group1', 10], - ['Bn', 'Group1', 'Cn', 'Group1', 1], - ['Cn', 'Group1', 'Dn', 'Group1', 3], - ['En', 'Group2', 'Fn', 'Group2', 4], - ['En', 'Group2', 'Hn', 'Group2', 5], - ['Fn', 'Group2', 'Gn', 'Group2', 6], - ['Gn', 'Group2', 'Hn', 'Group2', 7], - ['In', 'Group3', 'Jn', 'Group3', 8], - ['Bn', 'Group1', 'Fn', 'Group2', 9], - ['Dn', 'Group1', 'Hn', 'Group2', 11], - ['Dn', 'Group1', 'In', 'Group3', 1], - ['Cn', 'Group1', 'Jn', 'Group3', 1], - ['Hn', 'Group2', 'In', 'Group3', 1], - ['Hn', 'Group2', 'Kn', 'Group4', 1], - ['Kn', 'Group4', 'Ln', 'Group4', 0.1], - ['Kn', 'Group4', 'Mn', 'Group5', 1], - ['An', 'Group1', 'Nn', 'Group5', 1], - ['Kn', 'Group4', 'On', 'Group5', 1], - ['Kn', 'Group4', 'Pn', 'Group5', 12], - ['Kn', 'Group4', 'Qn', 'Group6', 1], - ['Kn', 'Group4', 'Rn', 'Group6', 1], - ['Kn', 'Group4', 'Sn', 'Group7', 1], - ['Kn', 'Group4', 'Tn', 'Group7', 10], - ] - const arenaText = - [ - 'SourceNode\tSourceLayer\tTargetNode\tTargetLayer\tWeight\tChannel', - ...arenaRows.map((r) => [...r, 1].join('\t')), - ].join('\n') + '\n' - const arenaConv = convertArena3dNetwork(arenaText) - NORMA_EXAMPLE_SETS['arena3d'] = { - title: 'Arena3D example: 7 layers', - source: 'Arena3D documentation', - link: 'https://arena3d.org', - local: true, - files: [ - { - kind: 'network', - name: 'Arena3D example network', - fileName: 'arena3d_example_network.txt', - text: arenaConv.network, - }, - { - kind: 'annotation', - name: 'Arena3D example layers', - fileName: 'arena3d_example_layers.txt', - text: arenaConv.annotation, - }, - { - kind: 'raw', - name: 'Arena3D network file (original format)', - fileName: 'arena3d_example_upload_network.txt', - text: arenaText, - }, - ], - } - - // 2. A directed signalling cascade with simulated fold changes - const cascade = generateDirectedMultiNetwork(40) - const cTexts = demoToNormaTexts(cascade) - const rc = mulberry32(2024) - const gauss = () => { - let u = 0, - v = 0 - while (!u) u = rc() - while (!v) v = rc() - return Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * v) - } - const layerShift = { receptors: 1.6, kinases: 1.0, 'transcription factors': 0.3, targets: -1.4 } - const cValues = - [ - 'Gene\tlog2FC\tpadj', - ...cascade.nodes.map((n) => { - if (rc() < 0.06) return `${n.id}\tNA\tNA` - const fc = Math.round((layerShift[n.groups[0]] + gauss() * 0.9) * 1000) / 1000 - const p = Math.min(1, Math.pow(10, -Math.abs(fc) * (1.2 + rc() * 1.8))) - return `${n.id}\t${fc}\t${p.toPrecision(3)}` - }), - ].join('\n') + '\n' - NORMA_EXAMPLE_SETS['cascade'] = { - title: 'Signalling cascade with fold changes (simulated)', - source: 'Simulated for NORMA 3.0', - link: null, - local: true, - display: { - edgeDirection: 'data', - edgeCurveStyle: 'bezier', - layoutSelect: 'fr', - legendShow: true, - sizeMetric: 'fixed', - }, - files: [ - { - kind: 'network', - name: 'Signalling cascade (directed, multi-edge)', - fileName: 'cascade_network.txt', - text: cTexts.network, - }, - { - kind: 'annotation', - name: 'Cascade levels', - fileName: 'cascade_levels.txt', - text: cTexts.annotation, - }, - { - kind: 'colors', - name: 'Cascade log2FC and padj (simulated)', - fileName: 'cascade_values_simulated.txt', - text: cValues, - }, - ], - } - - // 3. A healthy and a disease network (simulated) for Network Comparison - const base = buildModuleNetwork({ - sizes: [18, 16, 16, 14], - overlaps: [ - [0, 1], - [1, 2], - [2, 3], - [3, 0], - [1, 2, 3], - ], - pIn: 0.22, - pOut: 0.01, - seed: 64, - }) - const rh = mulberry32(64) - const ids = base.nodes.map((n) => n.id) - const moduleOf = new Map(base.nodes.map((n) => [n.id, n.groups])) - const healthy = base.edges.map((e) => [e.source, e.target]) - const key = (a, b) => (a < b ? a + '\t' + b : b + '\t' + a) - const hSet = new Set(healthy.map(([a, b]) => key(a, b))) - // disease: 20% of the edges are lost, and the third module gains new links - const disease = healthy.filter(() => rh() > 0.2) - const dSet = new Set(disease.map(([a, b]) => key(a, b))) - const third = base.groupOrder - ? base.groupOrder[2] - : [...new Set(base.nodes.flatMap((n) => n.groups))][2] - const inThird = ids.filter((id) => (moduleOf.get(id) || []).includes(third)) - let added = 0 - while (added < Math.round(healthy.length * 0.15)) { - const a = - rh() < 0.7 ? inThird[Math.floor(rh() * inThird.length)] : ids[Math.floor(rh() * ids.length)] - const b = inThird[Math.floor(rh() * inThird.length)] - if (a === b || dSet.has(key(a, b))) continue - dSet.add(key(a, b)) - disease.push([a, b]) - added++ - } - const netText = (pairs) => - ['Source\tTarget', ...pairs.map((p) => p.join('\t'))].join('\n') + '\n' - const annText = demoToNormaTexts(base).annotation - const dValues = - [ - 'Gene\tlog2FC\tpadj', - ...ids.map((id) => { - const boost = (moduleOf.get(id) || []).includes(third) ? 1.8 : 0 - const fc = Math.round((boost + gauss() * 0.7) * 1000) / 1000 - const p = Math.min(1, Math.pow(10, -Math.abs(fc) * (1 + rh() * 2))) - return `${id}\t${fc}\t${p.toPrecision(3)}` - }), - ].join('\n') + '\n' - NORMA_EXAMPLE_SETS['healthy-disease'] = { - title: 'Healthy vs disease networks (simulated)', - source: 'Simulated for NORMA 3.0', - link: null, - local: true, - showAll: true, - display: { edgeCurveStyle: 'bezier', legendShow: true, showGroupHulls: true }, - files: [ - { - kind: 'network', - name: 'Healthy (simulated)', - fileName: 'healthy_network_simulated.txt', - text: netText(healthy), - }, - { - kind: 'network', - name: 'Disease (simulated)', - fileName: 'disease_network_simulated.txt', - text: netText(disease), - }, - { kind: 'annotation', name: 'Modules', fileName: 'modules.txt', text: annText }, - { - kind: 'colors', - name: 'Disease vs healthy log2FC (simulated)', - fileName: 'disease_vs_healthy_values_simulated.txt', - text: dValues, - }, - ], - } - })() - - // links between Help and About (and to the Welcome page) switch pages - document.addEventListener('click', (e) => { - const sample = e.target.closest('a[data-sample-link]') - if (sample) { - e.preventDefault() - const q = new URLSearchParams(sample.getAttribute('href').replace(/^\?/, '')) - const sel = document.getElementById('sampleSelect') - sel.value = q.get('example') - document.getElementById('btnSample').click() - switchTab(q.get('tab') === '3d' ? 'network3d' : 'network') - return - } - const a = e.target.closest( - 'a[href^="#help-"], a[href^="#about-"], a[href^="#api-"], a[href="#welcome"], [data-go-welcome]' - ) - if (!a) return - const href = a.getAttribute('href') || '#welcome' - e.preventDefault() - if (href === '#welcome') { - switchTab('welcome') - return - } - const id = href.slice(1) - const page = id.startsWith('about-') ? 'about' : id.startsWith('api-') ? 'api' : 'help' - if (currentTab !== page) switchTab(page, id) - else { - const t = document.getElementById(id) - if (t) { - t.scrollIntoView({ block: 'start' }) - t.classList.remove('flash') - void t.offsetWidth - t.classList.add('flash') - } - } - }) - - document.querySelectorAll('#tabs .tab').forEach((btn) => { - btn.addEventListener('click', () => switchTab(btn.dataset.tab)) - btn.addEventListener('keydown', (ev) => { - const tabs = [...document.querySelectorAll('#tabs .tab')] - const i = tabs.indexOf(btn) - let next = null - if (ev.key === 'ArrowRight') next = tabs[(i + 1) % tabs.length] - if (ev.key === 'ArrowLeft') next = tabs[(i - 1 + tabs.length) % tabs.length] - if (next) { - ev.preventDefault() - next.focus() - switchTab(next.dataset.tab) - } - }) - }) - - document.querySelectorAll('.helplink').forEach((btn) => { - btn.title = 'Open help for this section' - btn.addEventListener('click', () => switchTab('help', btn.dataset.help)) - }) - - document.querySelectorAll('.help-nav a').forEach((a) => { - a.addEventListener('click', (ev) => { - ev.preventDefault() - const id = a.getAttribute('href').slice(1) - switchTab('help', id) - }) - }) - - document.querySelectorAll('.help-body a[href^="#"]').forEach((a) => { - a.addEventListener('click', (ev) => { - ev.preventDefault() - switchTab('help', a.getAttribute('href').slice(1)) - }) - }) -} diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json deleted file mode 100644 index 3412153..0000000 --- a/frontend/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "ESNext", - "moduleResolution": "bundler", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true, - "sourceMap": true, - "noEmit": true, - "skipLibCheck": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["node", "vite/client"] - }, - "include": ["src", "playwright.config.ts", "vite.config.ts"] -} diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts deleted file mode 100644 index 148c913..0000000 --- a/frontend/vite.config.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { defineConfig } from 'vitest/config' -import { viteSingleFile } from 'vite-plugin-singlefile' - -const backend = process.env.VITE_PROXY_TARGET ?? 'http://localhost:8000' - -// The page is norma.html (so ?example=, ?session= links keep working) and the -// build inlines everything into dist/norma.html, which opens from disk too. -export default defineConfig({ - base: './', - plugins: [viteSingleFile()], - build: { rollupOptions: { input: 'norma.html' } }, - server: { - // examples/norma_api_client.py (the API template) is imported ?raw from outside frontend/ - fs: { allow: ['..'] }, - proxy: Object.fromEntries( - ['/api', '/string-api', '/db-api', '/arena3d-api', '/norma-config.js'].map((p) => [ - p, - backend, - ]) - ), - }, - test: { - environment: 'jsdom', - setupFiles: ['./vitest.setup.ts'], - exclude: ['e2e/**', 'node_modules/**'], - }, -}) diff --git a/frontend/vitest.setup.ts b/frontend/vitest.setup.ts deleted file mode 100644 index 5ffca92..0000000 --- a/frontend/vitest.setup.ts +++ /dev/null @@ -1,15 +0,0 @@ -// Unit tests import modules that read the page at load (canvases, controls), -// so give jsdom the real markup and a no-op 2D canvas context. -import fs from 'node:fs' -import path from 'node:path' - -const html = fs.readFileSync(path.join(process.cwd(), 'norma.html'), 'utf8') -document.body.innerHTML = html.slice(html.indexOf('')) - -const noop = () => stub -const stub: unknown = new Proxy( - {}, - { get: (_, key) => (key === 'measureText' ? () => ({ width: 0 }) : noop), set: () => true } -) -HTMLCanvasElement.prototype.getContext = (() => - stub) as typeof HTMLCanvasElement.prototype.getContext diff --git a/functions/annotations.R b/functions/annotations.R new file mode 100644 index 0000000..7eca190 --- /dev/null +++ b/functions/annotations.R @@ -0,0 +1,1527 @@ +# main functions #### + +# This function handles the Annotations - convex hulls tab +convex_hulls <- function(g, annotation_graph){ + set.seed(123) + + original_dataset_weighted <- fetchFirstSelectedStoredDataset_annotations_tab() + if (is.null(original_dataset_weighted)) return(NULL) + + + my_network<- as.data.frame(get.edgelist(g)) + my_network<- data.frame(Source = my_network$V1, Target = my_network$V2) + + annotation_graph <- as.data.frame(annotation_graph) + groups<-annotation_graph + + annotation1 <- groups + + groups<- data.frame(V1 = groups$Annotations, stri_split_fixed(groups$Nodes, ",", simplify = TRUE)) + groups<-mutate_all(groups, funs(na_if(.,""))) + number_of_groups<-dim(groups)[1] + + x <- list() + for (i in 1:number_of_groups) { + group_i<- groups[i,] + group_i<- group_i[,-1] + group_i <- group_i[!is.na(group_i)] + x[[i]]<- (group_i) + } + + GO <- list() + for (i in 1:number_of_groups) { + GO[[i]]<-rep(groups[i,1], length(x[[i]])) + } + + column1<-my_network$Source + column2<-my_network$Target + node_names<-unique(union(column1, column2)) + tt<-unlist(x) + nodes_with_NA_groups<-setdiff(node_names,tt) + + members <- data_frame(id=unlist(x),group = unlist(GO)) + members_with_NA_groups <- data_frame(id=unlist(x),group = unlist(GO)) + + dataset1<- get.edgelist(g) + dataset1 <- as.matrix(dataset1) + annotation1 <- as.matrix(annotation1) + + nrowdat <- nrow(dataset1) + nrowannot <- nrow(annotation1) + + if(length(nodes_with_NA_groups)>0){ + for (i in 1:length(nodes_with_NA_groups)){ + members_with_NA_groups[nrow(members_with_NA_groups)+1,1] <- nodes_with_NA_groups[i] + } + members_with_NA_groups<-unique(members_with_NA_groups) + } + + #---------------------------------# + if (input$convex_layout_strategy == 'Supernodes per group'){ + shinyjs::show("repeling_force") + shinyjs::show("local_layout") + } else if (input$convex_layout_strategy == 'Group gravity'){ + shinyjs::show("repeling_force") + shinyjs::hide("local_layout") + } else { + shinyjs::hide("repeling_force") + shinyjs::hide("local_layout") + } + + if(input$convex_layout_strategy == 'Simple layout'){ + lay <- layout_choices(g, input$layouts) + node_name <- names(V(g)) + } else if(input$convex_layout_strategy == 'Virtual node per group'){ + lay <- strategy1_virtualNodes(g, annotation_graph) + node_name <- unique(members_with_NA_groups$id) + } else if(input$convex_layout_strategy == 'Group gravity'){ + result <- strategy2_gravity(g, annotation_graph, input$layouts, input$repeling_force) + lay <- result$lay + node_name <- result$network_nodes + } else if(input$convex_layout_strategy == 'Supernodes per group'){ + result <- strategy3_superNodes(g, annotation_graph, input$layouts, input$local_layout, input$repeling_force) + lay <- result$lay + node_name <- result$network_nodes + } + node_name_links <- node_name + + # Opening out conn + fileConn <- file(paste(USER_TEMP_FOLDER, "/output_convex_", session$token,".html", sep=""), "w") + + s <- input$chooseGroups_rows_selected + if (length(s)==0) + { + s<-c(1:nrowannot) + } + + if (length(s)) { + s<-sort(s) + x<- length(s) + ccc<-group_pal_rows(length(x)) + tmp_selected_colors<- c() + + tmp_selected_colors<- c(tmp_selected_colors, ccc[s[i]]) + group_color <- tmp_selected_colors + group_color_fill <- adjustcolor(group_color, alpha.f = 0.2) + + cat(sprintf(paste(" + + + + + + + + + + +\n"), file = fileConn) + + + close(fileConn) + + + }#if (length(s)) +}#function + +# This function handles the Annotations - pie chart tab +pie_charts<- function(g, annotation_graph){ + dataset1<- get.edgelist(g) + annotation_graph <- as.data.frame(annotation_graph) + groups<-annotation_graph + original_dataset_weighted <- fetchFirstSelectedStoredDataset_annotations_tab() + if (is.null(original_dataset_weighted)) return(NULL) + + my_network<- as.data.frame(get.edgelist(g)) + my_network<- data.frame(Source = my_network$V1, Target = my_network$V2) + + annotation1<- groups + + groups<- data.frame(V1 = groups$Annotations, stri_split_fixed(groups$Nodes, ",", simplify = TRUE)) + groups<-mutate_all(groups, funs(na_if(.,""))) + number_of_groups<-dim(groups)[1] + + x <- list() + for (i in 1:number_of_groups) { + group_i<- groups[i,] + group_i<- group_i[,-1] + group_i <- group_i[!is.na(group_i)] + x[[i]]<- (group_i) + } + + GO <- list() + for (i in 1:number_of_groups) { + GO[[i]]<-rep(groups[i,1], length(x[[i]])) + } + + column1<-my_network$Source + column2<-my_network$Target + node_names<-unique(union(column1, column2)) + tt<-unlist(x) + nodes_with_NA_groups<-setdiff(node_names,tt) + + members <- data_frame(id=unlist(x),group = unlist(GO)) + members_with_NA_groups <- data_frame(id=unlist(x),group = unlist(GO)) + dataset1 <- as.matrix(dataset1) + annotation1 <- as.matrix(annotation1) + + nrowdat <- nrow(dataset1) + nrowannot <- nrow(annotation1) + + s <- input$chooseGroups2_rows_selected + if (length(s)==0) + { + s<-c(1:nrowannot) + } + + if (length(s)) { + s<-sort(s) + x<- length(s) + ccc<-group_pal_rows(length(x)) + tmp_selected_colors<- c() + + tmp_selected_colors<- c(tmp_selected_colors, ccc[s[i]]) + group_color <- tmp_selected_colors + group_color_fill <- adjustcolor(group_color, alpha.f = 0.2) + + fileConn <- file(paste(USER_TEMP_FOLDER, "/output_pies_", session$token,".html", sep=""), "w") + cat(sprintf(paste(" + + + + + + + + + +"), file = fileConn) + + close(fileConn) + }#if (length(s)) +}#function + +# Function for Layouts with virtual nodes (per group) that pull all in-group nodes +# @param g(igraph obj): the selected network +# @param groups(dataframe): the selected annotation file -> names and respective nodes +# @return lay: the layout coordinates +strategy1_virtualNodes <- function(g, groups){ + if (is.null(g) || is.null(groups)) return() + set.seed(123) + + my_network<- as.data.frame(get.edgelist(g)) + my_network<- data.frame(Source = my_network$V1, Target = my_network$V2) + + groups<- data.frame(V1 = groups$Annotations, stri_split_fixed(groups$Nodes, ",", simplify = TRUE)) + groups<-mutate_all(groups, funs(na_if(.,""))) + number_of_groups<-dim(groups)[1] + + x <- list() + for (i in 1:number_of_groups) { + group_i<- groups[i,] + group_i<- group_i[,-1] + group_i <- group_i[!is.na(group_i)] + x[[i]]<- (group_i) + } + + GO <- list() + for (i in 1:number_of_groups) { + GO[[i]]<-rep(groups[i,1], length(x[[i]])) + } + + column1<-my_network$Source + column2<-my_network$Target + node_names<-unique(union(column1, column2)) + tt<-unlist(x) + nodes_with_NA_groups<-setdiff(node_names,tt) + + members <- data_frame(id=unlist(x),group = unlist(GO)) + members_with_NA_groups <- data_frame(id=unlist(x),group = unlist(GO)) + + if(length(nodes_with_NA_groups)>0){ + for (i in 1:length(nodes_with_NA_groups)) + { + members_with_NA_groups[nrow(members_with_NA_groups)+1,1] <- nodes_with_NA_groups[i] + } + members_with_NA_groups<-unique(members_with_NA_groups) + } + + edge <- data_frame(Source = my_network$Source, Target = my_network$Target, group = NA) #edge --> not edges + + within_group_edges <- members %>% + split(.$group) %>% + map_dfr(function (grp) { + if(length(grp$id)>=2){ + id2id <- combn(grp$id, 2) + data_frame(Source = id2id[1,], + Target = id2id[2,], + group = unique(grp$group)) + } + }) + + # sort by group as in file + group_order<-(as.list(unique(members_with_NA_groups$group))) + EE <- new.env(hash = TRUE) + EE_positions <- new.env(hash = TRUE) + for(i in 1: length(group_order)) + { + group_name_as_key<-group_order[[i]] + EE[[ as.character(group_name_as_key) ]]<-i + EE_positions[[ as.character(i) ]]<-group_order[[i]] + } + for(i in 1: length(group_order)) + { + group_name_as_key<-group_order[[i]] + index<-EE[[ as.character(group_name_as_key) ]] + } + + group_ids_tmp <- lapply(members_with_NA_groups %>% split(.$group), function(grp) { grp$id }) + group_ids<-c() + for(i in 1: length(group_ids_tmp)) + { + group_ids<-c(group_ids, group_ids_tmp[ EE_positions[[ as.character(i) ]]]) + } + + virt_group_nodes <- length(members_with_NA_groups$id) + 1:number_of_groups + names(virt_group_nodes) <- unique(members$group) # altered from c(letters[1:number_of_groups]) + edges_virt <- data_frame(Source = edge$Source, Target = edge$Target, weight = 5, group = edge$group) + + within_virt <- members %>% split(.$group) %>% map_dfr(function (grp) { + group_name <- unique(grp$group) + virt_from <- rep(virt_group_nodes[group_name], length(grp$id)) + if(length(grp$id)>=2){ + id2id <- combn(grp$id, 2) + data_frame( + Source = c(id2id[1,], virt_from), + Target = c(id2id[2,], grp$id), # also connects from virtual_from node to each group node + weight = c(rep(0.1, ncol(id2id)), # weight between group nodes + rep(50, length(grp$id))), + to_be_deleted = c(rep(T, ncol(id2id)), # weight between group nodes + rep(T, length(grp$id))), # weight that 'ties together' the group (via the virtual group node) + group = group_name + ) + } + }) + + edges_virt <-bind_rows(mutate_all(edges_virt, as.character), mutate_all(within_virt, as.character)) # vgazei 38,39,40 + virt_group_na <- virt_group_nodes[is.na(names(virt_group_nodes))] + non_group_nodes <- (members_with_NA_groups %>% filter(is.na(group)))$id + nodes_virt <- data_frame(id = 1:(length(members_with_NA_groups$id) + length(virt_group_nodes)), + is_virt = c(rep(FALSE, length(members_with_NA_groups$id)), + rep(TRUE, length(virt_group_nodes)))) + nodes_virt$id <- as.character(nodes_virt$id) + + #replace with the right names from our network + nodes_virt[1:length(members_with_NA_groups$id), ]$id <- members_with_NA_groups$id + + nodes_virt <- unique(nodes_virt) + + edge_names <- unique(c(edges_virt$Source, edges_virt$Target)) + nodes_virt <- nodes_virt[which(nodes_virt$id %in% edge_names), ] + g_virt <- graph_from_data_frame(edges_virt, directed = FALSE, vertices = nodes_virt) + + # use "auto layout" + # lay2 <- layout_nicely(g_virt) + lay <- layout_choices(g_virt, input$layouts) + + # remove virtual group nodes from graph + nodes_to_remove <- nodes_virt[which(nodes_virt$is_virt),]$id + nodes_to_remove <- nodes_to_remove[nodes_to_remove %in% V(g_virt)$name] + if (!identical(nodes_to_remove, character(0))) + g_virt <- delete_vertices(g_virt, nodes_to_remove) + + # remove virtual group nodes' positions from the layout matrix + tmp<-which(nodes_virt$is_virt == T ) + + lay <- lay[-tmp, ] + return(lay) +} + +# Function for Layouts with enhanced gravity for in-group nodes +# @param g(igraph obj): the selected network +# @param groups(dataframe): the selected annotation file -> names and respective nodes +# @param layout(string): the user-selected layout choice +# @param repeling_force(int): the user-selected repeling force +# @return lay (2d double matrix): the layout coordinates +# @return network_nodes (character vector): the proper order of nodes(names) to correctly attach to canvas +strategy2_gravity <- function(g, groups, layout, repeling_force){ + lay <- NULL + network_nodes <- NULL + if (!(is.null(g) || is.null(groups))){ + set.seed(123) + + # network + my_network <- as.data.frame(get.edgelist(g)) + my_network <- cbind(my_network, as.double(E(g)$Weight)) + colnames(my_network) <- c('Source', 'Target', 'Weight') + network_nodes <- unique(c(my_network$Source, my_network$Target)) + + # annotations + groups_expanded <- groups %>% separate_rows(Nodes, sep=",") + groups_expanded <- groups_expanded[which(groups_expanded$Nodes %in% network_nodes), ] # removing non-existing nodes + + # 1. create dataframe with extra edges (all against all in same groups that do not already exist in my_network) + extra_edges <- merge(groups_expanded, groups_expanded, by.x = "Annotations", by.y = "Annotations") + temp_g <- graph_from_data_frame(extra_edges[, c(2,3)], directed = F) + if ('Kamada-Kawai' == str_split(layout, "\t")[[1]][1]) E(temp_g)$weight <- min(my_network$Weight) + else E(temp_g)$weight <- max(my_network$Weight) # * 1.0001 # invisible weight = max network value *2 + temp_g <- igraph::simplify(temp_g, remove.multiple = T, remove.loops = T, edge.attr.comb = "first") + extra_edges <- as.data.frame(cbind( get.edgelist(temp_g) , E(temp_g)$weight )) + colnames(extra_edges) <- c('Source', 'Target', 'Weight') + + # 2. check network edges one by one; if exist in same group, weight * 100, else weight/100 + # This brings nodes ultra-close - unneeded + for (i in 1:nrow(my_network)){ + source_groups <- groups_expanded[which( groups_expanded$Nodes %in% my_network$Source[i]), ]$Annotations + target_groups <- groups_expanded[which( groups_expanded$Nodes %in% my_network$Target[i]), ]$Annotations + if ('Kamada-Kawai' == str_split(layout, "\t")[[1]][1]){ + if (identical(source_groups, character(0)) || + identical(target_groups, character(0)) || + identical(intersect(source_groups, target_groups), character(0))) + my_network$Weight[i] <- my_network$Weight[i] * repeling_force # kamada-kawai swap + else my_network$Weight[i] <- my_network$Weight[i] / repeling_force + } else { + if (identical(source_groups, character(0)) || + identical(target_groups, character(0)) || + identical(intersect(source_groups, target_groups), character(0))) + my_network$Weight[i] <- my_network$Weight[i] / repeling_force # kamada-kawai swap + else my_network$Weight[i] <- my_network$Weight[i] * repeling_force + } + } + + # 3. append to my_network + my_network <- rbind(my_network, extra_edges) + + # 4. graph handling + out_g <- graph_from_data_frame(my_network, directed = F, vertices = network_nodes) + E(out_g)$weight <- as.numeric(my_network$Weight) + out_g <- igraph::simplify(out_g, remove.multiple = T, remove.loops = T, edge.attr.comb = "max") + lay <- layout_choices(out_g, layout) + } + + return(list(lay = lay, network_nodes = network_nodes, groups_expanded = groups_expanded)) +} + +# Function for Layouts with superNodes per Annotation Group +# @param g(igraph obj): the selected network +# @param groups(dataframe): the selected annotation file -> names and respective nodes +# @param layout(string): the user-selected layout choice +# @param local_layout(string): the user-selected layout choice for in-group layouts +# @param repeling_force(int): the user-selected repeling force +# @return lay (2d double matrix): the layout coordinates +# @return network_nodes (character vector): the proper order of nodes(names) to correctly attach to canvas +strategy3_superNodes <- function(g, groups, layout, local_layout, repeling_force){ + lay <- NULL + network_nodes <- NULL + if (!(is.null(g) || is.null(groups))){ + set.seed(123) + + # network + my_network <- as.data.frame(get.edgelist(g)) + my_network <- cbind(my_network, as.double(E(g)$Weight)) + colnames(my_network) <- c('Source', 'Target', 'Weight') + network_nodes <- unique(c(my_network$Source, my_network$Target)) + + # annotations + groups_expanded <- groups %>% separate_rows(Nodes, sep=",") + groups_expanded <- groups_expanded[which(groups_expanded$Nodes %in% network_nodes), ] # removing non-existing nodes + + noGroupNodes <- network_nodes[!(network_nodes %in% groups_expanded$Nodes)] + + # 1. create dataframe of one supernode per group plus no-group nodes + # Source Target -> swap all nodes with their respective Group Name(s) + # if multiple groups per node, add the extra edges + # e.g. Group1+2Node - noGroupNode -> Group1 - noGroupNode, Group2 - noGroupNode + # merge my_network with groups_expanded two times ( Source - Nodes, Target - Nodes) + # where annotations not NA, swap Source or Target with respective Group Name + superFrame <- merge(my_network, groups_expanded, by.x = 'Source', by.y = 'Nodes', all.x = T) + superFrame <- merge(superFrame, groups_expanded, by.x = 'Target', by.y = 'Nodes', all.x = T) + graphFrame <- superFrame # keeping this for later on + graphFrame$Source[!is.na(graphFrame$Annotations.x)] <- graphFrame$Annotations.x[!is.na(graphFrame$Annotations.x)] + graphFrame$Target[!is.na(graphFrame$Annotations.y)] <- graphFrame$Annotations.y[!is.na(graphFrame$Annotations.y)] + graphFrame <- graphFrame[, c('Source', 'Target', 'Weight')] + + # 2. create graph and apply layout on this compound supernode network + temp_g <- graph_from_data_frame(graphFrame, directed = F) + E(temp_g)$weight <- as.numeric(graphFrame$Weight) + temp_g <- igraph::simplify(temp_g, remove.multiple = T, remove.loops = T, edge.attr.comb = "max") + lay_super <- layout_choices(temp_g, layout) + # lay_super <- layout_with_fr(temp_g) + lay_super <- cbind(lay_super, names(V(temp_g))) + # plot(temp_g, layout = lay_super) + + # 3. push all nodes above away from 0,0 // also check minx maxx for layout as alternative + # foreach node, calculate a = y/x + # then multiply x by an input number n (e.g.) and solve for y + # keep the (x, y) coords system in a matrix for all supernodes + lay_super <- as.data.frame(lay_super) + lay_super$V1 <- as.numeric(lay_super$V1) + lay_super$V2 <- as.numeric(lay_super$V2) + lay_super$a <- ifelse(lay_super$V1 != 0, lay_super$V2 / lay_super$V1, lay_super$V2 / 0.01) + lay_super$X <- repeling_force * lay_super$V1 + lay_super$Y <- lay_super$a * lay_super$X + lay_super <- lay_super[, c('X', 'Y', 'V3')] + colnames(lay_super)[3] <- 'Node' + + # 4. foreach group, add low-weight within group edges and + # apply layout (2nd input choice) with the respective (x,y) coords system + # extra edges dataframe for all groups + extra_edges <- merge(groups_expanded, groups_expanded, by.x = "Annotations", by.y = "Annotations") + lay <- matrix(, nrow = 0, ncol = 3) + for (group in unique(groups_expanded$Annotations)){ + tempFrame <- superFrame + tempFrame <- tempFrame[(tempFrame$Annotations.x == group & tempFrame$Annotations.y == group), ] + tempFrame <- tempFrame[!is.na(tempFrame$Source) & !is.na(tempFrame$Target), ] + tempFrame <- tempFrame[, c('Source', 'Target', 'Weight')] + + # create any missing in-group edges with minimum weight + # (all against all in same groups that do not already exist in tempFrame) + temp_extra_edges <- extra_edges[extra_edges$Annotations == group, ] + temp_g <- graph_from_data_frame(temp_extra_edges[, c(2,3)], directed = F) + min_weight <- ifelse(identical(min(tempFrame$Weight), Inf), 1, min(tempFrame$Weight)) + if ('Kamada-Kawai' == str_split(layout, "\t")[[1]][1]) E(temp_g)$weight <- min_weight * repeling_force + else E(temp_g)$weight <- min_weight / repeling_force # * 1.0001 # invisible weight = max network value *2 + temp_g <- igraph::simplify(temp_g, remove.multiple = T, remove.loops = T, edge.attr.comb = "first") + temp_extra_edges <- as.data.frame(cbind( get.edgelist(temp_g) , E(temp_g)$weight )) + colnames(temp_extra_edges) <- c('Source', 'Target', 'Weight') + + tempFrame <- rbind(tempFrame, temp_extra_edges) + + if (nrow(tempFrame) > 0){ + temp_g <- graph_from_data_frame(tempFrame, directed = F) + E(temp_g)$weight <- as.numeric(tempFrame$Weight) + temp_g <- igraph::simplify(temp_g, remove.multiple = T, remove.loops = T, edge.attr.comb = "max") + temp_lay <- layout_choices(temp_g, local_layout) + # temp_lay <- layout_with_fr(temp_g) + temp_lay <- cbind(temp_lay, names(V(temp_g))) + # plot(temp_g, layout = temp_lay) + + groupX <- lay_super[lay_super[,3] == group, 1] + groupY <- lay_super[lay_super[,3] == group, 2] + temp_lay[, 1] <- as.numeric(temp_lay[, 1]) + groupX + temp_lay[, 2] <- as.numeric(temp_lay[, 2]) + groupY + + lay <- rbind(lay, temp_lay) + } else{ + lay <- rbind(lay, c(lay_super[lay_super[,3] == group, 1], + lay_super[lay_super[,3] == group, 2], + groups$Nodes[groups$Annotations == group])) + } + } # end for + + # 5. calculate coordinates for duplicate nodes + dflay <- as.data.frame(lay) + dflay$V1 <- as.numeric(dflay$V1) + dflay$V2 <- as.numeric(dflay$V2) + meanX <- aggregate(dflay$V1, by=list(dflay$V3), FUN=mean) + colnames(meanX) <- c("Node", "X") + meanY <- aggregate(dflay$V2, by=list(dflay$V3), FUN=mean) + colnames(meanY) <- c("Node", "Y") + dflay <- merge(meanX, meanY) + dflay <- as.matrix(dflay[, c("X", "Y", "Node")]) + + # 6. append non-group nodes from lay_super + lay_noGroupNodes <- lay_super[lay_super[,3] %in% noGroupNodes, ] + lay <- rbind(dflay, lay_noGroupNodes) + network_nodes <- lay[, 3] + + lay <- cbind(as.numeric(lay[, 1]), as.numeric(lay[, 2])) + } + + return(list(lay = lay, network_nodes = network_nodes, groups_expanded = groups_expanded)) +} + +vennDiagrams <- function(){ + g <- fetchFirstSelectedStoredIgraph_annotations_tab() + if (is.null(g)) return() + + my_network <- as.data.frame(get.edgelist(g)) + my_network <- data.frame(Source = my_network$V1, Target = my_network$V2) + + annotation_graph <- fetchFirstSelectedStoredGroups2_annotations_tab() + + if (is.null(annotation_graph)) + return() + annotation_graph <- as.data.frame(annotation_graph) + groups <- annotation_graph + groups <- data.frame(V1 = groups$Annotations, stri_split_fixed(groups$Nodes, ",", simplify = TRUE)) + groups <- mutate_all(groups, funs(na_if(., ""))) + number_of_groups <- dim(groups)[1] + + x <- list() + for (i in 1:number_of_groups) { + group_i <- groups[i, ] + group_i <- group_i[, -1] + group_i <- group_i[!is.na(group_i)] + x[[i]] <- (group_i) + } + + GO <- list() + for (i in 1:number_of_groups) { + GO[[i]] <- rep(groups[i, 1], length(x[[i]])) + } + + column1 <- my_network$Source + column2 <- my_network$Target + node_names <- unique(union(column1, column2)) + tt <- unlist(x) + nodes_with_NA_groups <- setdiff(node_names, tt) + + members <- data_frame(id = unlist(x), group = unlist(GO)) + members_with_NA_groups <- + data_frame(id = unlist(x), group = unlist(GO)) + if (length(nodes_with_NA_groups) > 0) { + for (i in 1:length(nodes_with_NA_groups)) + { + members_with_NA_groups[nrow(members_with_NA_groups) + 1, 1] <- + nodes_with_NA_groups[i] + } + members_with_NA_groups <- unique(members_with_NA_groups) + } + + venn<- members_with_NA_groups %>% group_by(id) %>% summarise_all(funs(trimws(paste(., collapse = ',')))) + + return(venn) +} + +getStoredNetsChoices_annotations_tab <- function() { + snets <- StoredNets_annotations_tab() + if (nrow(snets) == 0) return(NULL) + choices <- snets$id + names(choices) <- snets$name + return(choices) +} + +getStoredNetsChoices2_annotations_tab <- function() { + snets <- StoredNets2_annotations_tab() + if (nrow(snets) == 0) + return(NULL) + choices <- snets$id + names(choices) <- snets$name + return(choices) +} + +getStoredExpressionChoices <- function() { + sexpress <- StoredExpress() + if (nrow(sexpress) == 0) + return(NULL) + choices <- sexpress$id + names(choices) <- sexpress$name + return(choices) +} + +fetchDataset_annotations_tab <- function(nid) { + retVal <- NULL + if (length(nid) > 0) { + retVal <- readRDS(paste0(USER_TEMP_FOLDER, "/", nid, ".rda")) + attr(retVal, "id") <- nid + } + return(retVal) +} + +fetchDataset2_annotations_tab <- function(nid) { + retVal <- NULL + if (length(nid) > 0) { + retVal <- readRDS(paste0(USER_TEMP_FOLDER, "/",nid, ".rda")) + attr(retVal, "id") <- nid + } + return(retVal) +} + +SelectedStoredNets2_annotations_tab <- function() { + if (length(reactiveVars$SelectedStoredNetworksIds2_annotations_tab) > 0) { + return(StoredNets2_annotations_tab()[which( + reactiveVars$StoredNetworks2_annotations_tab$id %in% + reactiveVars$SelectedStoredNetworksIds2_annotations_tab + ),]) + } + else if (nrow(StoredNets2_annotations_tab()) == 0 || + is.na(StoredNets2_annotations_tab()[1,])) + return(NULL) + else { + updateCheckboxGroupInput( + session, + "uiLoadGraphOptionsOutput_annotations_annotations_tab", + "Selected network(s)", + choices = getStoredNetsChoices2_annotations_tab(), + selected = getStoredNetsChoices2_annotations_tab()[1] + ) + return(StoredNets2_annotations_tab()[1,]) + } +} + +SelectedStoredExpress <- function() { + if (length(reactiveVars$SelectedStoredExpressionIds) > 0) + return(StoredExpress()[which( + reactiveVars$StoredExpressions$id %in% + reactiveVars$SelectedStoredExpressionIds + ),]) + else if (nrow(StoredAnnots()) == 0 || is.na(StoredAnnots()[1,])) + return(NULL) + else return(StoredAnnots()[1,]) +} + +fetchDatasetEx <- function(nid) { + retVal <- NULL + if (length(nid) > 0) { + retVal <- readRDS(paste0(USER_TEMP_FOLDER, "/", nid, ".rda")) + attr(retVal, "id") <- nid + } + return(retVal) +} + +# sub-routines #### +fetchFirstSelectedStoredIgraph_annotations_tab <- function() { + dataset <- fetchFirstSelectedStoredDataset_annotations_tab() + if (is.null(dataset)) + return(NULL) + else + return(convert_to_igraph(dataset)) +} + +SelectedStoredNets_annotations_tab <- function() { + if (length(reactiveVars$SelectedStoredNetworksIds_annotations_tab) > 0) { + return(StoredNets_annotations_tab()[which( + reactiveVars$StoredNetworks_annotations_tab$id %in% + reactiveVars$SelectedStoredNetworksIds_annotations_tab + ),]) + } + else if (nrow(StoredNets_annotations_tab()) == 0 || + is.na(StoredNets_annotations_tab()[1,])) + return(NULL) + else { + updateCheckboxGroupInput( + session, + "uiLoadGraphOptionsOutput_annotations_tab", + "Selected network(s)", + choices = getStoredNetsChoices_annotations_tab(), + selected = getStoredNetsChoices_annotations_tab()[1] + ) + return(StoredNets_annotations_tab()[1,]) + } +} + +# Output after choosing selected annotations +SelectedStoredAnnots <- function() { + if (length(reactiveVars$SelectedStoredAnnotationIds) > 0) + return(StoredAnnots()[which( + reactiveVars$StoredAnnotations$id %in% + reactiveVars$SelectedStoredAnnotationIds + ),]) + else if (nrow(StoredAnnots()) == 0 || is.na(StoredAnnots()[1,])) + return(NULL) + else return(StoredAnnots()[1,]) +} + +layout_choices_3D <- function(igraph, layouts_3D){ + if(length(layouts_3D)==0) + return(NULL) + results<-list() + for(i in layouts_3D){ + tmp<-unlist(strsplit(i,"\t",fixed=T)) + description<-tmp[1] + command<-tmp[2] + results[[description]]<-eval(parse(text=command)) + } + + return(results[[description]]) +} + +# functions for selectbox choices +layout_choices <- function(igraph,layouts_ui){ + if(length(layouts_ui)==0) + return(NULL) + results<-list() + for(i in layouts_ui){ + tmp<-unlist(strsplit(i,"\t",fixed=T)) + description<-tmp[1] + command<-tmp[2] + results[[description]]<-eval(parse(text=command)) + } + return(results[[description]]) +} diff --git a/functions/helpDownloadHandlers.R b/functions/helpDownloadHandlers.R new file mode 100644 index 0000000..1a09d96 --- /dev/null +++ b/functions/helpDownloadHandlers.R @@ -0,0 +1,232 @@ +# Help pages - Download Example files #### +output$dros_net <- downloadHandler( + filename = function() { + paste('Drosophila (TAU) Network file', '.txt', sep = '') + }, + content = function(file) { + write.table(dros_net, file, row.names = F, sep = "\t", quote = F) + } +) +output$dros_annot <- downloadHandler( + filename = function() { + paste('Drosophila KEGG pathways', '.txt', sep = '') + }, + content = function(file) { + write.table(dros_annot, file,row.names = F, col.names = F, sep = "\t", quote = F) + } +) +output$dros_louvain <- downloadHandler( + filename = function() { + paste('Drosophila Louvain automated annotation', '.txt', sep = '') + }, + content = function(file) { + write.table(dros_louvain, file,row.names = F, col.names = F, sep = "\t", quote = F) + } +) +output$dros_express <- downloadHandler( + filename = function() { + paste('Drosophila Expressions file', '.txt', sep = '') + }, + content = function(file) { + write.table(dros_express, file,row.names = F, col.names = F, sep = "\t", quote = F) + } +) + +#-------------------------------------------# + +output$string_net_tp53 <- downloadHandler( + filename = function() { + paste('STRING TP53 Network file', '.txt', sep = '') + }, + content = function(file) { + write.table(string_net_tp53, file, row.names = F, sep = "\t", quote = F) + } +) +output$string_annot <- downloadHandler( + filename = function() { + paste('STRING TP53 Annotation file', '.txt', sep = '') + }, + content = function(file) { + write.table(string_annot, file, row.names = F,col.names = F, sep = "\t", quote = F) + } +) +output$string_expr <- downloadHandler( + filename = function() { + paste('STRING TP53 Expression file', '.txt', sep = '') + }, + content = function(file) { + write.table(string_expr, file, row.names = F,col.names = F, sep = "\t", quote = F) + } +) + +#-------------------------------------------# + +output$string_net_bcar3 <- downloadHandler( + filename = function() { + paste('STRING BCAR3 Network file', '.txt', sep = '') + }, + content = function(file) { + write.table(string_net_bcar3, file, row.names = F, sep = "\t", quote = F) + } +) +output$string_bp <- downloadHandler( + filename = function() { + paste('STRING BCAR3 GO Biological Processes file', '.txt', sep = '') + }, + content = function(file) { + write.table(string_bp, file, row.names = F,col.names = F, sep = "\t", quote = F) + } +) +output$string_mf <- downloadHandler( + filename = function() { + paste('STRING BCAR3 GO Molecular functions file', '.txt', sep = '') + }, + content = function(file) { + write.table(string_mf, file, row.names = F,col.names = F, sep = "\t", quote = F) + } +) +output$string_kegg <- downloadHandler( + filename = function() { + paste('STRING BCAR3 GO KEGG file', '.txt', sep = '') + }, + content = function(file) { + write.table(string_kegg, file, row.names = F,col.names = F, sep = "\t", quote = F) + } +) + +#-------------------------------------------# + +output$co_express <- downloadHandler( + filename = function() { + paste('Human Gene Co-expression Network file', '.txt', sep = '') + }, + content = function(file) { + write.table(co_express, file, row.names = F, sep = "\t", quote = F) + } +) +output$co_express_bp <- downloadHandler( + filename = function() { + paste('Human Gene Co-expression GO Biological Processes file', '.txt', sep = '') + }, + content = function(file) { + write.table(co_express_bp, file,row.names = F,col.names = F, sep = "\t", quote = F) + } +) +output$co_express_mf <- downloadHandler( + filename = function() { + paste('Human Gene Co-expression GO Molecura functions file', '.txt', sep = '') + }, + content = function(file) { + write.table(co_express_mf, file,row.names = F,col.names = F, sep = "\t", quote = F) + } +) +output$co_express_cc <- downloadHandler( + filename = function() { + paste('Human Gene Co-expression Cellular Componets file', '.txt', sep = '') + }, + content = function(file) { + write.table(co_express_cc, file,row.names = F,col.names = F, sep = "\t", quote = F) + } +) +output$co_express_kegg <- downloadHandler( + filename = function() { + paste('Human Gene Co-expression KEGG pathways file', '.txt', sep = '') + }, + content = function(file) { + write.table(co_express_kegg, file,row.names = F,col.names = F, sep = "\t", quote = F) + } +) +output$co_express_mcode <- downloadHandler( + filename = function() { + paste('Human Gene Co-expression MCODE node coloring file', '.txt', sep = '') + }, + content = function(file) { + write.table(co_express_mcode, file,row.names = F,col.names = F, sep = "\t", quote = F) + } +) +#-----------------------------------------------------------------------------# + +output$covid_19_net <- downloadHandler( + filename = function() { + paste('COVID-19 Network file', '.txt', sep = '') + }, + content = function(file) { + write.table(covid_19_net, file, row.names = F, quote = F, sep = "\t") + } +) +output$covid_19_interpro <- downloadHandler( + filename = function() { + paste('HomoSapiens Protein Domains - INTERPRO file', '.txt', sep = '') + }, + content = function(file) { + write.table(covid_19_interpro, file, row.names = F, col.names= F, quote = F, sep = "\t") + } +) +output$covid_19_bp <- downloadHandler( + filename = function() { + paste('HomoSapiens GO Annotation - Biological Process file', '.txt', sep = '') + }, + content = function(file) { + write.table(covid_19_bp, file, row.names = F, col.names= F, quote = F, sep = "\t") + } +) +output$covid_19_mf <- downloadHandler( + filename = function() { + paste('HomoSapiens GO Annotation - Molecular Function file', '.txt', sep = '') + }, + content = function(file) { + write.table(covid_19_mf, file, row.names = F, col.names= F, quote = F, sep = "\t") + } +) +output$covid_19_cc <- downloadHandler( + filename = function() { + paste('HomoSapiens Protein Domains GO Annotation - Cellular Components file', '.txt', sep = '') + }, + content = function(file) { + write.table(covid_19_cc, file, row.names = F, col.names= F, quote = F, sep = "\t") + } +) +output$covid_19_kegg <- downloadHandler( + filename = function() { + paste('HomoSapiens Protein Domains KEGG pathways file', '.txt', sep = '') + }, + content = function(file) { + write.table(covid_19_kegg, file, row.names = F, col.names= F, quote = F, sep = "\t") + } +) +output$covid_19_smart <- downloadHandler( + filename = function() { + paste('HomoSapiens Protein Domains SMART file', '.txt', sep = '') + }, + content = function(file) { + write.table(covid_19_smart, file, row.names = F, col.names= F, quote = F, sep = "\t") + } +) + +#-----------------------------------------------------------------------------# + +output$Gallus_gallus_net <- downloadHandler( + filename = function() { + paste('Gallus gallus Network file', '.txt', sep = '') + }, + content = function(file) { + write.table(Gallus_gallus_net, file,row.names = F, quote = F, sep = "\t") + } +) +output$Gallus_gallus_kegg <- downloadHandler( + filename = function() { + paste('BioGrid Chicken Gallus KEGG pathways file', '.txt', sep = '') + }, + content = function(file) { + write.table(Gallus_gallus_kegg, file,row.names = F, col.names = F, quote = F, sep = "\t") + } +) + +output$R_script <- downloadHandler( + filename = function() { + paste('Annotation_cleaner', '.R', sep = '') + }, + content = function(file) { + write.table(R_script, file, row.names = F,col.names = F, sep = "\t", quote = F) + } +) diff --git a/functions/network.R b/functions/network.R new file mode 100644 index 0000000..11c0de9 --- /dev/null +++ b/functions/network.R @@ -0,0 +1,96 @@ +# main functions #### +getStoredNetsChoices_just_network <- function() { + snets <- StoredNets_just_network() + if (nrow(snets) == 0) return(NULL) + choices <- snets$id + names(choices) <- snets$name + return(choices) +} + +fetchFirstSelectedStoredIgraph_just_network <- function() { + dataset <- fetchFirstSelectedStoredDataset_just_network() + if (is.null(dataset)) + return(NULL) + else + return(convert_to_igraph(dataset)) +} + +# Download-button for automated annotations +file_name <- function() { + automated_annotations <- input$automated_annotations + + if (automated_annotations == "Fast-Greedy\tcluster_fast_greedy(igraph)") { + filename <- "Fast-Greedy_" + } + if (automated_annotations == "Louvain\tcluster_louvain(igraph)") { + filename <- "Louvain_" + } + if (automated_annotations == "Label-Propagation\tcluster_label_prop(igraph)") { + filename <- "Label-Propagation_" + } + if (automated_annotations == "Walktrap\tcluster_walktrap(igraph)") { + filename <- "Walktrap_" + } + if (automated_annotations == "Betweenness\tcluster_edge_betweenness(igraph)") { + filename <- "Betweenness_" + } + return(filename) +} + +# sub-routines #### +fetchFirstSelectedStoredDataset_just_network <- reactive({ + ssn <- SelectedStoredNets_just_network() + if (!is.null(ssn) && nrow(ssn) > 0) { + return(fetchDataset_just_network(ssn[1,]$id)) + } else { + return(NULL) + } +}) + +StoredNets_just_network <- reactive({ + return(reactiveVars$StoredNetworks_just_network) +}) + +SelectedStoredNets_just_network <- function() { + if (length(reactiveVars$SelectedStoredNetworksIds_just_network) > 0) { + return(StoredNets_just_network()[which( + reactiveVars$StoredNetworks_just_network$id %in% + reactiveVars$SelectedStoredNetworksIds_just_network + ),]) + } + else if (nrow(StoredNets_just_network()) == 0 || + is.na(StoredNets_just_network()[1,])) + return(NULL) + else { + updateCheckboxGroupInput( + session, + "uiLoadGraphOptionsOutput_just_network", + "Selected network(s)", + choices = getStoredNetsChoices_just_network(), + selected = getStoredNetsChoices_just_network()[1] + ) + return(StoredNets_just_network()[1,]) + } +} + +fetchDataset_just_network <- function(nid) { + retVal <- NULL + if (length(nid) > 0) { + retVal <- readRDS(paste0(USER_TEMP_FOLDER, "/", nid, ".rda")) + attr(retVal, "id") <- nid + } + return(retVal) +} + +convert_to_igraph <- function(dataset1){ + weighted_tf <- FALSE + if (attr(dataset1, "weighted")) { + weighted_tf <- attr(dataset1, "weighted") + } + set.seed(123) + igraph <- graph.data.frame(dataset1, directed = F, vertices = NULL) + if (attr(dataset1, which = "weighted")) + E(igraph)$weight <- dataset1$Weight + return(igraph) +} + diff --git a/functions/refreshing/convex_hulls_3D.R b/functions/refreshing/convex_hulls_3D.R new file mode 100644 index 0000000..83eb9b6 --- /dev/null +++ b/functions/refreshing/convex_hulls_3D.R @@ -0,0 +1,535 @@ +convex_hull_3D <- function() { + set.seed(123) + + g <- fetchFirstSelectedStoredIgraph_annotations_tab() + if (is.null(g)) + return() + + # dataset <- get.edgelist(g) + dataset <- fetchFirstSelectedStoredDataset_annotations_tab() + if (is.null(dataset)) + return() + + original_dataset_weighted <- fetchFirstSelectedStoredDataset_annotations_tab() + if (is.null(original_dataset_weighted)) + return(NULL) + + annotation_graph <- fetchFirstSelectedStoredGroups2_annotations_tab() + if (is.null(annotation_graph)) + return() + + #---------------------------------------------------------------# + my_network<- as.data.frame(get.edgelist(g)) + my_network<- data.frame(Source = my_network$V1, Target = my_network$V2) + + groups <- as.data.frame(annotation_graph) + + groups<- data.frame(V1 = groups$Annotations, stri_split_fixed(groups$Nodes, ",", simplify = TRUE)) + groups<-mutate_all(groups, funs(na_if(.,""))) + number_of_groups<-dim(groups)[1] + + x <- list() + for (i in 1:number_of_groups) { + group_i<- groups[i,] + group_i<- group_i[,-1] + group_i <- group_i[!is.na(group_i)] + x[[i]]<- (group_i) + } + + GO <- list() + for (i in 1:number_of_groups) { + GO[[i]]<-rep(groups[i,1], length(x[[i]])) + } + + column1<-my_network$Source + column2<-my_network$Target + node_names<-unique(union(column1, column2)) + tt<-unlist(x) + nodes_with_NA_groups<-setdiff(node_names,tt) + + members <- data_frame(id=unlist(x),group = unlist(GO)) + members_with_NA_groups <- data_frame(id=unlist(x),group = unlist(GO)) + #----------------------------------------------------------------# + + #-------------------------------------------------------------------------# + + new_nodes <- unique(union(dataset[,1], dataset[,2])) + + new_annot <- annotation_graph %>% + mutate(V2 = strsplit(as.character(annotation_graph$Nodes), ",")) %>% + unnest(V2) + + intersect_g_annot <- intersect(new_nodes, new_annot$V2) + + if(identical(intersect_g_annot, character(0))){ + showModal(modalDialog( + title = "Important message", + "Please check if the selected annotation file corresponds to the selected network.", + easyClose = T + )) + } + #-------------------------------------------------------------------------# + + set.seed(123) + lay <- layout_choices_3D(g, lay) + + #----------------------------------------------------------------# + scene_scale_x_max <- max(lay[,1])*scaling_coordinates_convex_3D_X() + scene_scale_x_min <- min(lay[,1])*scaling_coordinates_convex_3D_X() + + scene_scale_y_max <- max(lay[,2])*scaling_coordinates_convex_3D_Y() + scene_scale_y_min <- min(lay[,2])*scaling_coordinates_convex_3D_Y() + + scene_scale_z_max <- max(lay[,3])*scaling_coordinates_convex_3D_Z() + scene_scale_z_min <- min(lay[,3])*scaling_coordinates_convex_3D_Z() + #----------------------------------------------------------------# + # lay <- lay*scaling_coordinates_convex_3D() + #-- Scaling coordinates --# + coorx<- lay[,1]*scaling_coordinates_convex_3D_X() + lay <- cbind(coorx,lay[,2:ncol(lay)]) + + coory<- lay[,2]*scaling_coordinates_convex_3D_Y() + lay <- cbind(lay[,1], coory,lay[,3]) + + coorz<- lay[,3]*scaling_coordinates_convex_3D_Z() + lay <- cbind(lay[,1:2], coorz) + #-------------------------# + + colnames(lay) <- c("x", "y", "z") + # node_names_3D <- unique(union(dataset[,1], dataset[,2])) + + + #---------------------------------# + + node_names_3D <- names(V(g)) + node_name_links_3D <- names(V(g)) + #--------------------------------# + + + if(length(node_names_3D) != nrow(lay)){ + showModal(modalDialog( + title = "Important message", + "Please check if the selected annotation file corresponds to the selected network.", + easyClose = T + )) + } + else{ + node_names_with_coords <- data.frame("Source" = node_names_3D, + "x" = lay[,1], + "y" = lay[,2], + "z" = lay[,3]) + } + + + #--- hash table for names and coordinates ---# + coordinates_hashmap <- new.env(hash = TRUE) + for(i in 1:nrow(node_names_with_coords)){ + coordinates_hashmap[[as.character(node_names_with_coords[i,1])]]<-c(node_names_with_coords[i,2], node_names_with_coords[i,3], node_names_with_coords[i,4]) + } + + #---------------------------------------------------# + + nrowdat <- nrow(dataset) + nrowannot <- nrow(annotation_graph) + + + if(!(is.weighted(g))){ + original_dataset_weighted <- cbind(original_dataset_weighted[,1:2],"Weight"=rep(0.5, nrow(original_dataset_weighted))) + } else{ + minx <- min(original_dataset_weighted[,3]) + maxx <- max(original_dataset_weighted[,3]) + + scaling_weight_values<- c() + for (i in 1:nrow(original_dataset_weighted)){ + scaling_weight_values_i <- mapper(original_dataset_weighted[i,3], minx, maxx, 0.5, 20) + scaling_weight_values <- c(scaling_weight_values, scaling_weight_values_i) + } + if(maxx > 50){ + original_dataset_weighted <- cbind(original_dataset_weighted[,1:2],"Weight"=scaling_weight_values) + } + } + + if (length(s)==0) + { + s<-c(1:nrowannot) + } + + if (length(s)) { + s<-sort(s)#----------------------------------- + x<- length(s) + + dataset1 <- get.edgelist(g) + dataset1 <- data.frame("Source" = dataset[,1], "Target" = dataset[,2]) + + source <- matrix(ncol=3, nrow=nrow(dataset1)) + target <- matrix(ncol=3, nrow=nrow(dataset1)) + for(i in 1:nrow(dataset1)){ + source[i,] <- coordinates_hashmap[[as.character(dataset1[i,1])]] + target[i,] <- coordinates_hashmap[[as.character(dataset1[i,2])]] + } + + edges_for_plotly <- data.frame("Source.x" = source[,1], "Source.y" = source[,2], "Source.z" = source[,3], + "Target.x" = target[,1], "Target.y" = target[,2], "Target.z" = target[,3]) + # x<- c() + # for(i in 1:nrow(edges_for_plotly)){ + # if(i == nrow(edges_for_plotly)){ + # a <- paste(edges_for_plotly$Source.x[i], edges_for_plotly$Target.x[i], "null", sep = "," ) + # }else{ + # a <- paste(edges_for_plotly$Source.x[i], edges_for_plotly$Target.x[i], "null,", sep = "," ) + # + # } + # x<- c(x, a) + # } + # + # x <- as.vector(unlist(x)) + # x <- paste(x, collapse=" ") + # + # y<- c() + # for(i in 1:nrow(edges_for_plotly)){ + # if(i == nrow(edges_for_plotly)){ + # a = paste(edges_for_plotly$Source.y[i], edges_for_plotly$Target.y[i], "null", sep = "," ) + # }else{ + # a = paste(edges_for_plotly$Source.y[i], edges_for_plotly$Target.y[i], "null,", sep = "," ) + # } + # y<- c(y, a) + # } + # + # y <- as.vector(unlist(y)) + # y <- paste(y, collapse=" ") + # + # + # z<- c() + # for(i in 1:nrow(edges_for_plotly)){ + # if(i == nrow(edges_for_plotly)){ + # a = paste(edges_for_plotly$Source.z[i], edges_for_plotly$Target.z[i], "null", sep = "," ) + # }else{ + # a = paste(edges_for_plotly$Source.z[i], edges_for_plotly$Target.z[i], "null,", sep = "," ) + # } + # z<- c(z, a) + # } + # + # z <- as.vector(unlist(z)) + # z <- paste(z, collapse=" ") + + #--------------------------------------------------------------------# + fileConn <- file(paste(USER_TEMP_FOLDER, "/convex_3D_", session$token,".html", sep=""), "w") + #--------------------------------------------------------------------# + + cat(sprintf(" + + + + + +
    + + + + + ", sep = ""), file = fileConn, append = T) + + + + } # if(length(s)) +} \ No newline at end of file diff --git a/functions/refreshing/modularity.R b/functions/refreshing/modularity.R new file mode 100644 index 0000000..edd6b90 --- /dev/null +++ b/functions/refreshing/modularity.R @@ -0,0 +1,25 @@ +modularity<- function(method){ + + set.seed(123) + + clp <- automated_annotation_choices(net, automated_annotations) + + groups_all<- c() + for (i in 1:length(clp)){ + clp_i <- as.data.frame(clp[[i]]) + ss<-paste(clp_i[,1], collapse="," ) + groups_all[[i]]<-ss + } + + prefix <- "Group-" + suffix <- seq(1:length(clp)) + + max.length <- max(sapply(groups_all, length)) + l <- lapply(groups_all, function(v) { c(v, rep(NA, max.length-length(v)))}) + df<-as.data.frame(do.call(rbind, l)) + groups_column_name<- paste(prefix, suffix, sep="") + df<- cbind(groups_column_name, df) + names(df) <- NULL + + return(df) +} diff --git a/functions/topology.R b/functions/topology.R new file mode 100644 index 0000000..5727c9c --- /dev/null +++ b/functions/topology.R @@ -0,0 +1,131 @@ +# main functions #### +getStoredNetsChoices_topology_tab <- function() { + snets <- StoredNets_topology_tab() + if (nrow(snets) == 0) + return(NULL) + choices <- snets$id + names(choices) <- snets$name + return(choices) +} + +getDatasetName <- function(id) { + sn <- StoredNets() + idi <- which(sn$id == id) + if (is.null(sn) || nrow(sn) == 0 || length(idi) == 0) + return(NULL) + return(sn[idi,]$name) +} + +fetchDataset_topology_tab <- function(nid) { + retVal <- NULL + if (length(nid) > 0) { + retVal <- readRDS(paste0(USER_TEMP_FOLDER, "/", nid, ".rda")) + attr(retVal, "id") <- nid + } + return(retVal) +} + +fetchAllSelectedStoredDataset_topology_tab <- function() { + ssn <- SelectedStoredNets_topology_tab() + ids <- c() + if (!is.null(ssn) && nrow(ssn) > 0) { + ret <- list() + for (i in 1:nrow(ssn)) { + ret[[i]] <- fetchDataset_topology_tab(ssn[i,]$id) + ids <- c(ids, ssn[i,]$id) + } + names(ret) <- ids + return(ret) + } else { + return(NULL) + } +} + +# Statistics +stat_dataset <- function(dataset, datasetName) { + res <- tryCatch({ + columns <- c("Statistic", paste0("Value for ", datasetName)) + if (is.null(dataset)) { + dataset <- EmptyDataset(columns) + } else { + igraph <- convert_to_igraph(dataset) + if (length(input$statistics) == 0) { + dataset <- EmptyDataset(columns) + } else { + dataset <- netstats(igraph, input$statistics) + colnames(dataset) <- columns + } + } + return(dataset) + }, warning = function(w) { + + }, error = function(e) { + cat(paste0("ERROR while executing stat_dataset: ", e, "\n")) + return(NULL) + }, finally = { + + }) + return(res) +} + +stat_dataset2 <- function(dataset, datasetName) { + res <- tryCatch({ + columns <- c("Statistic", paste0("Value for ", datasetName)) + if (is.null(dataset)) { + dataset <- EmptyDataset(columns) + } else { + igraph <- convert_to_igraph(dataset) + if (length(input$statistics2) == 0) { + dataset <- EmptyDataset(columns) + } else { + dataset <- netstats(igraph, input$statistics2) + colnames(dataset) <- columns + } + } + return(dataset) + }, warning = function(w) { + + }, error = function(e) { + cat(paste0("ERROR while executing stat_dataset: ", e, "\n")) + return(NULL) + }, finally = { + + }) + return(res) +} + +# sub-routines #### +SelectedStoredNets_topology_tab <- function() { + if (length(reactiveVars$SelectedStoredNetworksIds_topology_tab) > 0) { + return(StoredNets_topology_tab()[which( + reactiveVars$StoredNetworks_topology_tab$id %in% + reactiveVars$SelectedStoredNetworksIds_topology_tab + ),]) + } + else if (nrow(StoredNets_topology_tab()) == 0 || + is.na(StoredNets_topology_tab()[1,])) + return(NULL) + else { + updateCheckboxGroupInput( + session, + "uiStoredGraphsOutputSelectTopolopgy", + "Selected network(s)", + choices = getStoredNetsChoices_topology_tab(), + selected = getStoredNetsChoices_topology_tab()[1] + ) + return(StoredNets_topology_tab()[1,]) + } +} + +netstats <- function(igraph,statistics){ + if(length(statistics)==0) + return(NULL) + results<-list() + for(i in statistics){ + tmp<-unlist(strsplit(i,"\t",fixed=T)) + description<-tmp[1] + command<-tmp[2] + results[[description]]<-eval(parse(text=command)) + } + return(data.frame(cbind(names(results),as.character(results)))) +} diff --git a/functions/upload.R b/functions/upload.R new file mode 100644 index 0000000..99295ae --- /dev/null +++ b/functions/upload.R @@ -0,0 +1,386 @@ +# main functions #### +addNetwork <- function(){ + dataset <- loadNetworkFromFile() + + if (!is.null(dataset)) { + if (nrow(dataset) < 10000) { + nid <- UUIDgenerate(T) #time-base UUID is generated + nn <- input$networkName + cnt <- 1 #count + while (nn %in% reactiveVars$StoredNetworks$name) { + #reactiveVars: represents a single reactive variable. + cnt <- cnt + 1 + nn <- + paste(input$networkName, cnt) #paste: converts its arguments (via as.character) to character strings + } + df <- data.frame(id = nid, name = nn, stringsAsFactors = F) + if (nrow(dataset) > 10000) { + dataset <- dataset[1:10000,] + } + if (ncol(dataset) == 3) attr(dataset, which = 'weighted') <- T + else attr(dataset, which = 'weighted') <- F + + reactiveVars$StoredNetworks <- + rbind(reactiveVars$StoredNetworks, df) + reactiveVars$StoredNetworks_just_network <- + reactiveVars$StoredNetworks + reactiveVars$StoredNetworks_annotations_tab <- + reactiveVars$StoredNetworks + reactiveVars$StoredNetworks_topology_tab <- + reactiveVars$StoredNetworks + + saveRDS(dataset, paste0(USER_TEMP_FOLDER, "/", nid, ".rda")) + if (length(reactiveVars$SelectedStoredNetworksIds) == 0) { + reactiveVars$SelectedStoredNetworksIds <- c(nid) + } + } + + if (nrow(dataset) >= 10000) { + dataset <- dataset[1:10000, ] + shinyalert("Warning!", "Keeping the first 10,000 connections.", type = "error") + } + + } else shinyalert("Error!", "Your input generated a NULL network.\n + Please, follow the guidelines at the Help pages to upload a network in the required format.", type = "error") +} + +remNetwork <- function(){ + if (!is.null(input$availableNetworks)) { + reactiveVars$StoredNetworks <- + reactiveVars$StoredNetworks[-which(reactiveVars$StoredNetworks$id %in% + input$availableNetworks),] + nr <- nrow(reactiveVars$StoredNetworks) + if (nr > 0) { + reactiveVars$SelectedStoredNetworksIds <- + reactiveVars$StoredNetworks[nr,]$id + } + } + + if (!is.null(input$availableNetworks)) { + reactiveVars$StoredNetworks_just_network <- + reactiveVars$StoredNetworks_just_network[-which(reactiveVars$StoredNetworks_just_network$id %in% + input$availableNetworks),] + nr <- nrow(reactiveVars$StoredNetworks_just_network) + if (nr > 0) { + reactiveVars$SelectedStoredNetworksIds_just_network <- + reactiveVars$StoredNetworks_just_network[nr,]$id + } + } + + if (!is.null(input$availableNetworks)) { + reactiveVars$StoredNetworks_annotations_tab <- + reactiveVars$StoredNetworks_annotations_tab[-which( + reactiveVars$StoredNetworks_annotations_tab$id %in% + input$availableNetworks + ),] + nr <- nrow(reactiveVars$StoredNetworks_annotations_tab) + if (nr > 0) { + reactiveVars$SelectedStoredNetworksIds_annotations_tab <- + reactiveVars$StoredNetworks_annotations_tab[nr,]$id + } + } + + if (!is.null(input$availableNetworks)) { + reactiveVars$StoredNetworks_topology_tab <- + reactiveVars$StoredNetworks_topology_tab[-which(reactiveVars$StoredNetworks_topology_tab$id %in% + input$availableNetworks),] + nr <- nrow(reactiveVars$StoredNetworks_topology_tab) + if (nr > 0) { + reactiveVars$SelectedStoredNetworksIds_topology_tab <- + reactiveVars$StoredNetworks_topology_tab[nr,]$id + } + } +} + +addAnnotations <- function(){ + annotation <- loadAnnotations() + if (!is.null(annotation)) { + if (nrow(annotation) < 300) { + nid <- UUIDgenerate(T) #time-base UUID is generated + nn <- input$annotationName + cnt <- 1 #count + while (nn %in% reactiveVars$StoredAnnotations$name) { + #reactiveVars: represents a single reactive variable. + cnt <- cnt + 1 + nn <- + paste(input$annotationName, cnt) #paste: converts its arguments (via as.character) to character strings + } + dtf <- data.frame(id = nid, + name = nn, + stringsAsFactors = F) + if (nrow(annotation) > 10000) { + annotation <- annotation[1:10000,] + } + reactiveVars$StoredAnnotations <- + rbind(reactiveVars$StoredAnnotations, dtf) + reactiveVars$StoredNetworks2_annotations_tab <- + reactiveVars$StoredAnnotations + + saveRDS(annotation, paste0(USER_TEMP_FOLDER, "/", nid, ".rda")) + if (length(reactiveVars$SelectedStoredAnnotationIds) == 0) { + reactiveVars$SelectedStoredAnnotationIds <- c(nid) + } + } + + if (nrow(annotation) >= 300) { + annotation <- annotation[1:300, ] + shinyalert("Warning!", "Keeping the first 300 lines.", type = "error") + } + + } else shinyalert("Error!", "Your input generated a NULL annotation table.\n + Please, follow the guidelines at the Help pages to upload an annotation file in the required format.", type = "error") +} + +remAnnotations <- function(){ + if (!is.null(input$availableAnnotations)) { + reactiveVars$StoredAnnotations <- + reactiveVars$StoredAnnotations[-which(reactiveVars$StoredAnnotations$id %in% + input$availableAnnotations),] + nr <- nrow(reactiveVars$StoredAnnotations) + if (nr > 0) + reactiveVars$SelectedStoredAnnotationIds <- + reactiveVars$StoredAnnotations[nr,]$id + } + + + if (!is.null(input$availableAnnotations)) { + reactiveVars$StoredNetworks2_annotations_tab <- + reactiveVars$StoredNetworks2_annotations_tab[-which( + reactiveVars$StoredNetworks2_annotations_tab$id %in% + input$availableAnnotations + ),] + nr <- nrow(reactiveVars$StoredNetworks2_annotations_tab) + if (nr > 0) + reactiveVars$SelectedStoredNetworksIds2_annotations_tab <- + reactiveVars$StoredNetworks2_annotations_tab[nr,]$id + } +} + +addExpression <- function(){ + expression <- loadExpressions() + if (!is.null(expression)) { + nid <- UUIDgenerate(T) #time-base UUID is generated + nn <- input$expressionName + cnt <- 1 #count + while (nn %in% reactiveVars$StoredExpressions$name) { + #reactiveVars: represents a single reactive variable. + cnt <- cnt + 1 + nn <- + paste(input$expressionName, cnt) #paste: converts its arguments (via as.character) to character strings + } + dtf <- data.frame(id = nid, + name = nn, + stringsAsFactors = F) + if (nrow(expression) > 10000) { + expressionName <- expressionName[1:10000,] + shinyalert("Warning!", "Keeping the 10000 first rows.", type = "error") + } + reactiveVars$StoredExpressions <- + rbind(reactiveVars$StoredExpressions, dtf) + saveRDS(expression, paste0(USER_TEMP_FOLDER, "/", nid, ".rda")) + if (length(reactiveVars$SelectedStoredExpressionIds) == 0) { + reactiveVars$SelectedStoredExpressionIds <- c(nid) + } + } else shinyalert("Error!", "Your input generated a NULL expressions table.\n + Please, follow the guidelines at the Help pages to upload an annotation file in the required format.", type = "error") +} + +remExpression <- function(){ + if (!is.null(input$availableExpressions)) { + reactiveVars$StoredExpressions <- + reactiveVars$StoredExpressions[-which(reactiveVars$StoredExpressions$id %in% + input$availableExpressions),] + nr <- nrow(reactiveVars$StoredExpressions) + if (nr > 0) + reactiveVars$SelectedStoredExpressionIds <- + reactiveVars$StoredExpressions[nr,]$id + } +} + +getStoredNetsChoices <- function() { + snets <- StoredNets() + if (nrow(snets) == 0) + return(NULL) + choices <- snets$id + names(choices) <- snets$name + return(choices) +} + +SelectedStoredNets <- function() { + if (length(reactiveVars$SelectedStoredNetworksIds) > 0) { + return(StoredNets()[which(reactiveVars$StoredNetworks$id %in% + reactiveVars$SelectedStoredNetworksIds),]) + } + else if (nrow(StoredNets()) == 0 || + is.na(StoredNets()[1,])) + return(NULL) + else return(StoredNets()[1,]) +} + +fetchDataset <- function(nid) { + retVal <- NULL + if (length(nid) > 0) { + retVal <- readRDS(paste0(USER_TEMP_FOLDER, "/", nid, ".rda")) + attr(retVal, "id") <- nid + } + return(retVal) +} + +getStoredAnnotChoices <- function() { + sannots <- StoredAnnots() + if (nrow(sannots) == 0) + return(NULL) + choices <- sannots$id + names(choices) <- sannots$name + return(choices) +} + +# sub-routines #### +loadNetworkFromFile <- function() { + dataset1 <- NULL + set.seed(123) + + switch( + input$uiLoadGraphOptionsInput, + oF = { + if (!is.null(input$file1)) { + tryCatch({ + dataset1 <- read_data(input$file1$datapath) + }, error = function(e) { + print(paste("Upload tab error: ", e)) + shinyalert("Error!", "Network format problem. Please ensure that columns are tab separated.", type = "error") + }) + } + }, + oR_String_interactions = { + dataset1 <- string_net_bcar3 # "Examples/BCAR3/BCAR3.txt" + dataset1 <- cbind(dataset1[,1:2], "Weight" = rep(1, nrow(dataset1))) + }, + oR_Drosophila = { + n <- as.integer(input$oR_selected_size) + dataset1 <- dros_net # "Examples/TAU/TAU_network_DEGs_NORMA.txt" + dataset1 <- cbind(dataset1[,1:2], "Weight" = rep(1, nrow(dataset1))) + } + ) + + if (input$uiLoadGraphOptionsInput != "oF" && !is.null(dataset1)) { + set.seed(123) + if(ncol(dataset1) < 3) { + dataset1 <- cbind(dataset1[,1:2], "Weight" = rep(1, nrow(dataset1))) + } else { + if (ncol(dataset1) == 2) { + dataset1$V3 <- 1 + } else if (ncol(dataset1) > 3) { + dataset1 <- dataset1[, 1:3] + } else if (ncol(dataset1) != 3) + return(NULL) + } + colnames(dataset1) <- c("Source", "Target", "Weight") + } + + if (!is.null(dataset1)){ + row_to_keep <- c() + for(i in 1:nrow(dataset1)){ + if(dataset1[i,1]==dataset1[i,2]){ + row_to_keep <- c(row_to_keep, FALSE) + } + if(dataset1[i,1]!=dataset1[i,2]){ + row_to_keep <- c(row_to_keep, TRUE) + } + } + dataset1 = dataset1[row_to_keep,] + } + + return(dataset1) +} + +# Load annotations +loadAnnotations <- function() { + annotation1 <- NULL + + switch( + input$uiLoadGraphOptionsInput_annotations, + oF = { + if (!is.null(input$file2)) { + tryCatch({ + annotation1 <- read_annotations(input$file2$datapath) + }, error = function(e) { + print(paste("Upload tab error: ", e)) + shinyalert("Error!", "Annotations format problem. Please ensure that columns are tab separated.", type = "error") + }) + } + }, + oR_String_Annotation_BP = { + annotation1 <- string_bp # "Examples/BCAR3/BCAR3_GO_BP.txt" + }, + oR_String_Annotation_MF = { + annotation1 <- string_mf # "Examples/BCAR3/BCAR3_GO_MF.txt" + }, + oR_String_Annotation_KEGG = { + annotation1 <- string_kegg # "Examples/BCAR3/BCAR3_KEGG.txt" + }, + oR_Drosophila_KEGG = { + # n <- as.integer(input$oR_selected_size) + annotation1 <- dros_annot # "Examples/TAU/TAU_KEGG_Annotation_NORMA.txt" + }, + oR_Drosophila_Luvain = { + # n <- as.integer(input$oR_selected_size) + annotation1 <- dros_louvain # "Examples/TAU/TAU_Louvain.txt" + } + ) + + if (!is.null(annotation1)) { + colnames(annotation1) <- c("Annotations", "Nodes") + } + + return(annotation1) +} + +# Load expression files +loadExpressions <- function() { + expression1 <- NULL + switch(input$uiLoadExpressionsInput, + oF = { + if (!is.null(input$file3)) { + tryCatch({ + expression1 <- read_expressions(input$file3$datapath) + }, error = function(e) { + print(paste("Upload tab error: ", e)) + shinyalert("Error!", "Expressions format problem. Please ensure that columns are tab separated.", type = "error") + }) + } + }, + oR_Expression_file_Drosophila = { + expression1 <- dros_express # "Examples/TAU/TAU_expressions.txt" + } + ) + if (!is.null(expression1)) { + colnames(expression1) <- c("ID", "Color") + } + return(expression1) +} + +read_expressions <- function(datapath, type = c("txt"), header = F, sep = "\t", + quote = "\"", weighted = F, na.strings = c("", "NA")){ + expression1 <- read.table(datapath, header = header, sep = sep, + quote = quote, comment.char="?") +} + +read_data <- function(datapath, type = c("txt"), header = T, sep = "\t", quote = "\"", weighted = F){ + dataset1 <- read.table(datapath, header = header, sep = sep, quote = quote) + + if (ncol(dataset1) == 2) dataset1$V3 <- 1 + else if (ncol(dataset1) > 3) dataset1 <- dataset1[, 1:3] + else if (ncol(dataset1) != 3) return(NULL) + + colnames(dataset1) <- c("Source", "Target", "Weight") + + return(dataset1) +} + +read_annotations <- function(datapath, type = c("txt"), header = F, sep = "\t", + quote = "\"", weighted = F, na.strings = c("", "NA")){ + annotation1 <- read.table(datapath, header = header, sep = sep, quote = quote) + + return(annotation1) +} diff --git a/global.R b/global.R new file mode 100644 index 0000000..ee805bc --- /dev/null +++ b/global.R @@ -0,0 +1,231 @@ +# Load libraries or install dependencies #### +if (!require(shinyBS)) install.packages('shinyBS') +if (!require(bsplus)) install.packages('bsplus') +if (!require(visNetwork)) install.packages("visNetwork") +if (!require(shinyWidgets)) install.packages('shinyWidgets') +if (!require(shinythemes)) install.packages('shinythemes') +if (!require(shinyjs)) install.packages('shinyjs') +if (!require(shinyalert)) install.packages('shinyalert') +if (!require(shinycssloaders)) install.packages('shinycssloaders') +if (!require(randomcoloR)) install.packages('randomcoloR') +if (!require(DT)) install.packages('DT') +if (!require(uuid))install.packages('uuid') +if (!require(igraph)) install.packages('igraph') +if (!require(stringi)) install.packages('stringi') +if (!require(dplyr)) install.packages('dplyr') +if (!require(tidyr)) install.packages('tidyr') +if (!require(stringr)) install.packages('tidyr') +if (!require(VennDiagram)) install.packages("VennDiagram") +if (!require(lattice)) install.packages("lattice") +if (!require(purrr)) install.packages('purrr') + +# Options #### +options(shiny.usecairo = F) +options(shiny.maxRequestSize = 30*1024^2) # 30 MB for uploaded networks +# options(shiny.reactlog = TRUE) # debugging +# options(shiny.error = browser) # debugging + +# Global variables #### +PRINT_TIMES <- F # true, to benchmark some function speeds +USER_TEMP_FOLDER <- 'user_temp' + +ui_options <- c(ui_table_font_sz = "80%") +layouts_ui <- c( + "Fruchterman-Reingold"="Fructerman\tlayout_nicely(igraph, dim=2)", + # "Fruchterman-Reingold"="Fructerman\tlayout.fruchterman.reingold(igraph, dim=2)", + "Random"="Random\tlayout.random(igraph, dim=2)", + "Circle"="Circle\tlayout.circle(igraph)", + "Kamada-Kawai"="Kamada-Kawai\tlayout.kamada.kawai(igraph, dim=2)", + "Reingold-Tilford"="Reingold-Tilford\tlayout.reingold.tilford(igraph)", + "Lgl"="Lgl\tlayout.lgl(igraph)", + "Graphopt"="Graphopt\tlayout.graphopt(igraph)", + "Gem"="Graphopt\tlayout.gem(igraph)", + "Star"="Graphopt\tlayout_as_star(igraph)", + "Grid"="Grid\tlayout.grid(igraph)" + # "Auto"="Auto\tlayout.auto(igraph, dim=2)", + # "SVD"="SVD\tlayout.svd(igraph, d=shortest.paths(igraph))" + # "Nicely"="Nicely\tlayout_nicely(igraph, dim=2)", + # "Tree"="Graphopt\tlayout_as_tree(igraph)", + # "Spring"="Spring\tlayout.spring(igraph)", + # "Fruchterman-Reingold Grid"="Fruchterman Grid\tlayout.fruchterman.reingold.grid(igraph)", + # "Sphere"="Sphere\tlayout.sphere(igraph)", +) +selected_layouts <- c( "Fructerman\tlayout_nicely(igraph, dim=2)" ) +layouts_3D<-c( + "Fruchterman-Reingold"="Fructerman\tlayout_with_fr(igraph, dim=3)", + "Random"="Random\tlayout.random(igraph, dim=3)", + "Kamada-Kawai"="Kamada-Kawai\tlayout.kamada.kawai(igraph, dim=3)", + # "Reingold-Tilford"="Reingold-Tilford\tlayout.reingold.tilford(igraph, dim=3)", + # "Lgl"="Lgl\tlayout.lgl(igraph, dim=3)", + # "Graphopt"="Graphopt\tlayout.graphopt(igraph, dim=3)", + # "Gem"="Graphopt\tlayout.gem(igraph, dim=3)", + "Grid"="Grid\tlayout.grid(igraph, dim=3)" +) +selected_layouts_3d <- c( "Fructerman\tlayout_with_fr(igraph, dim=3)" ) +automated_annotations_ui <- c( + # "Fast-Greedy"="Fast-Greedy\tcluster_fast_greedy(igraph)", + "Louvain"="Louvain\tcluster_louvain(igraph)", + "Label-Propagation"="Label-Propagation\tcluster_label_prop(igraph)", + "Walktrap"="Walktrap\tcluster_walktrap(igraph)", + "Betweenness"="Betweenness\tcluster_edge_betweenness(igraph)" +) +selected_automated_annotations <- c( "Louvain\tcluster_louvain(igraph)" ) +statistics <- c( + "Number of Edges" = "Number of Edges\tecount(igraph)", + "Number of Nodes" = "Number of Nodes\tvcount(igraph)", + "Density" = "Density\tgraph.density(igraph)", + "Average path length" = "Average path length\taverage.path.length(igraph)", + "Clustering Coefficient" = "Clustering Coefficient\ttransitivity(igraph)", + "Modularity" = "Modularity\tmodularity(igraph,membership(walktrap.community(igraph)))", + "Average Eccentricity" = "Average Eccentricity\tmean(eccentricity(igraph))", + "Average number of Neighbors" = "Average number of Neighbors\t(centr_eigen(igraph)$centralization)", + "Centralization betweenness" = "Centralization.betweenness\tcentralization.betweenness(igraph)$centralization", + # "Centralization closeness" = "Centralization.closeness\tcentralization.closeness(igraph)$centralization", + "Centralization degree" = "Centralization.degree\tcentralization.degree(igraph)$centralization" +) +selected_statistics <- c("Number of Edges" = "Number of Edges\tecount(igraph)") + +max_pixels_panel <- 5000 + +# 300 Colors - Up to 100 are distinct +qual_col_pals<-c("#1B9E77","#D95F02","#7570B3","#E7298A","#66A61E","#E6AB02","#A6761D","#666666","#7FC97F","#BEAED4", + "#FDC086","#FFFF99","#386CB0","#F0027F","#BF5B17","#A6CEE3","#1F78B4","#B2DF8A","#33A02C","#FB9A99", + "#E31A1C","#FDBF6F","#FF7F00","#CAB2D6","#a17bc9","#B15928","#FBB4AE","#B3CDE3","#CCEBC5","#a9a9a9", + "#dcdcdc","#98fb98","#556b2f","#8b4513","#6b8e23","#2e8b57","#800000","#FDDAEC","#006400","#808000", + "#6c3920","#778899","#3cb371","#bc8f8f","#b0737c","#008080","#b8860b","#bdb76b","#cd853f","#4682b4", + "#d2691e","#9acd32","#20b2aa","#008b7b","#82007e","#32cd32","#8fbc8f","#0ba47e","#b03060","#d2b48c", + "#66cdaa","#9932cc","#ff0000","#ffa500","#ffd700","#ffff00","#c71585","#0303ff","#7fff00","#00ff00", + "#ba55d3","#00ff7f","#4169e1","#e9967a","#dc143c","#00ffff","#00bfff","#9370db","#0000ff","#a020f0", + "#adff2f","#d8bfd8","#ff7f50","#ff00ff","#db7093","#f0e68c","#fa8072","#ffff54","#6495ed","#dda0dd", + "#87ceeb","#ff1493","#afeeee","#ee82ee","#2f4f4f","#7fffd4","#ff69b4","#ffe4c4","#ffb6c1","#DECBE4", + "#FED9A6","#FFFFCC","#E5D8BD","#191970","#F2F2F2","#B3E2CD","#FDCDAC","#CBD5E8","#F4CAE4","#E6F5C9", + "#FFF2AE","#F1E2CC","#CCCCCC","#E41A1C","#377EB8","#4DAF4A","#984EA3","#FFFF33","#A65628","#F781BF", + "#999999","#66C2A5","#FC8D62","#8DA0CB","#E78AC3","#A6D854","#FFD92F","#E5C494","#B3B3B3","#8DD3C7", + "#FFFFB3","#BEBADA","#FB8072","#80B1D3","#FDB462","#B3DE69","#FCCDE5","#D9D9D9","#BC80BD","#095F02", + "#E31A97","#A81AD2","#74ED33","#38F76B","#E607E1","#17D214","#E2E749","#5522DF","#1FF696","#1406E9", + "#6A43DE","#C2F309","#E92D57","#5004DE","#9C4AE9","#2EF613","#EDAA2D","#2FB5EA","#47FAB2","#CC9221", + "#5C4AFC","#E843D0","#FE3F64","#21DD3A","#1988D2","#BC11EF","#EEFB3D","#1B9E77","#D95F02","#7570B3", + "#88e99a","#ca2dc5","#bce333","#643176","#34f50e","#b22839","#4be8f9","#6c3920","#bfcd8e","#1642cd", + "#f4d403","#5310f0","#609111","#c697f4","#34466d","#b3d9fa","#155126","#fab5b5","#0ba47e","#ff0087", + "#3d99ce","#bf711e","#fa718e","#798872","#fe5900","#b0737c","#E31A97","#A81AD2","#74ED33","#38F76B", + "#DECBE4","#FED9A6","#FFFFCC","#E5D8BD","#FDDAEC","#F2F2F2","#B3E2CD","#FDCDAC","#CBD5E8","#F4CAE4", + "#E6F5C9","#FFF2AE","#F1E2CC","#CCCCCC","#E41A1C","#377EB8","#4DAF4A","#984EA3","#FFFF33","#A65628", + "#F781BF","#999999","#66C2A5","#FC8D62","#8DA0CB","#E78AC3","#A6D854","#FFD92F","#E5C494","#B3B3B3", + "#8DD3C7","#FFFFB3","#BEBADA","#FB8072","#80B1D3","#FDB462","#B3DE69","#FCCDE5","#D9D9D9","#BC80BD", + "#095F02","#E31A97","#A81AD2","#74ED33","#38F76B","#E607E1","#17D214","#E2E749","#5522DF","#1FF696", + "#1406E9","#6A43DE","#C2F309","#E92D57","#5004DE","#9C4AE9","#2EF613","#EDAA2D","#2FB5EA","#47FAB2", + "#CC9221","#5C4AFC","#E843D0","#FE3F64","#21DD3A","#1988D2","#BC11EF","#EEFB3D","#1B9E77","#D95F02", + "#7570B3","#88e99a","#ca2dc5","#bce333","#643176","#34f50e","#b22839","#4be8f9","#483d8b","#bfcd8e", + "#1642cd","#f4d403","#5310f0","#609111","#c697f4","#34466d","#b3d9fa","#155126","#fab5b5","#800080", + "#ff0087","#3d99ce","#bf711e","#fa718e","#798872","#fe5900","#663399","#E31A97","#A81AD2","#74ED33") + +# Images for help pages and banner +b64_1 <- base64enc::dataURI(file = "./www/Figures/Banner.png", mime = "image/png") +b64_2 <- base64enc::dataURI(file = "./www/Figures/Upload-1.png", mime = "image/png") +b64_3 <- base64enc::dataURI(file = "./www/Figures/Upload-2.png", mime = "image/png") +b64_4 <- base64enc::dataURI(file = "./www/Figures/Upload-3.png", mime = "image/png") +b64_5 <- base64enc::dataURI(file = "./www/Figures/Network_view_interactive.png", mime = "image/png") +b64_6 <- base64enc::dataURI(file = "./www/Figures/Community_detection_algorithms.png", mime = "image/png") +b64_7 <- base64enc::dataURI(file = "./www/Figures/Convex_Hulls.PNG", mime = "image/png") +b64_8 <- base64enc::dataURI(file = "./www/Figures/Pies.PNG", mime = "image/png") +b64_9 <- base64enc::dataURI(file = "./www/Figures/Expression_colors.png", mime = "image/png") +b64_10 <- base64enc::dataURI(file = "./www/Figures/Topology.PNG", mime = "image/png") +b64_11 <- base64enc::dataURI(file = "./www/Figures/Topology_comparisons.PNG", mime = "image/png") +b64_12 <- base64enc::dataURI(file = "./www/Figures/venn.png", mime = "image/png") +b64_3D_convex <- base64enc::dataURI(file = "./www/Figures/Convex_Hulls_3D.PNG", mime = "image/png") +b64_strategy1 <- base64enc::dataURI(file = "./www/Figures/Strategy_1.png", mime = "image/png") +b64_strategy2 <- base64enc::dataURI(file = "./www/Figures/Strategy_2.png", mime = "image/png") +b64_strategy3 <- base64enc::dataURI(file = "./www/Figures/Strategy_3.png", mime = "image/png") + + + +# Help pages examples for download +dros_net <- read.delim("./www/Examples/TAU/TAU_network_DEGs_NORMA.txt", header = T) +dros_annot <- read.delim("./www/Examples/TAU/TAU_KEGG_Annotation_NORMA.txt", header = F) +dros_louvain <- read.delim("./www/Examples/TAU/TAU_Louvain.txt", header = F) +dros_express <- read.delim("./www/Examples/TAU/TAU_expressions.txt", header = F) +string_net_tp53 <- read.delim("./www/Examples/TP53/string_interactions.txt", header = T) +string_annot <- read.delim("./www/Examples/TP53/string_interactions_groups_comma_duplicate.txt", header = F) +string_expr <- read.delim("./www/Examples/TP53/string_expression_colors.txt", header = F) +string_net_bcar3 <- read.delim("./www/Examples/BCAR3/BCAR3.txt", header = T) +string_bp <- read.delim("./www/Examples/BCAR3/BCAR3_GO_BP.txt", header = F) +string_mf <- read.delim("./www/Examples/BCAR3/BCAR3_GO_MF.txt", header = F) +string_kegg <- read.delim("./www/Examples/BCAR3/BCAR3_KEGG.txt", header = F) +co_express <- read.delim("./www/Examples/Human_Coexpression/NORMA_Human_coexpression_NETWORK.txt", header = T) +co_express_bp <- read.delim("./www/Examples/Human_Coexpression/NORMA_Human_coexpression_Annotation_GO_BP.txt", header = F) +co_express_mf <- read.delim("./www/Examples/Human_Coexpression/NORMA_Human_coexpression_Annotation_GO_MF.txt", header = F) +co_express_cc <- read.delim("./www/Examples/Human_Coexpression/NORMA_Human_coexpression_Annotation_GO_CC.txt", header = F) +co_express_kegg <- read.delim("./www/Examples/Human_Coexpression/NORMA_Human_coexpression_Annotation_KEGG.txt", header = F) +co_express_mcode <- read.delim("./www/Examples/Human_Coexpression/NORMA_Human_coexpression_Expression_MCODE.txt", header = F) +covid_19_net <- read.delim("./www/Examples/IntAct_COVID19/Intact-data_COVID19_no_self_loops.txt", header = T) +covid_19_interpro <- read.delim("./www/Examples/IntAct_COVID19/HomoSapiens_Protein_Domains_INTERPRO_FILTERED.txt", header = F) +covid_19_bp <- read.delim("./www/Examples/IntAct_COVID19/HomoSapiens_Gene_Ontology_GOTERM_BP_DIRECT_FILTERED.txt", header = F) +covid_19_mf <- read.delim("./www/Examples/IntAct_COVID19/HomoSapiens_Gene_Ontology_GOTERM_MF_DIRECT_FILTERED.txt", header = F) +covid_19_cc <- read.delim("./www/Examples/IntAct_COVID19/HomoSapiens_Gene_Ontology_GOTERM_CC_DIRECT_FILTERED.txt", header = F) +covid_19_kegg <- read.delim("./www/Examples/IntAct_COVID19/HomoSapiens_Pathways_KEGG_PATHWAY_FILTERED.txt", header = F) +covid_19_smart <- read.delim("./www/Examples/IntAct_COVID19/HomoSapiens_Protein_Domains_SMART_FILTERED.txt", header = F) +Gallus_gallus_net <- read.delim("./www/Examples/BioGrid_Chicken_Gallus/Biogrid_no_self_loops.txt", header = T) +Gallus_gallus_kegg <- read.delim("./www/Examples/BioGrid_Chicken_Gallus/BioGrid_Chicken_Gallus_Pathways_KEGG_PATHWAY_FILTERED.txt", header = F) + +R_script <- read.delim("./www/annotation_cleaner.R", header = F) + +# General functions #### +automated_annotation_choices <- function(igraph,automated_annotations_ui){ + if(length(automated_annotations_ui)==0) return(NULL) + results<-list() + + for(i in automated_annotations_ui){ + tmp<-unlist(strsplit(i,"\t",fixed=T)) + description<-tmp[1] + command<-tmp[2] + results[[description]] <- eval(parse(text=command)) + } + return(results[[description]]) +} + +# Colors if there is NOT "NA" in dataset (nodes) +group_pal_rows <- function(n){ + + qual_col_pals[1:300] + + if(n>=300){ + qual_col_pals<-c(qual_col_pals, rep(c("grey50"), times = (n-300) )) + nn<- qual_col_pals[1:n] + nnames<-c(nn) + } else { + nn<- qual_col_pals[1:n] + nnames<-c(nn) + } +} + +mapper <- function(value, istart, istop, ostart, ostop){ + return (ostart + (ostop - ostart) * ((value - istart) / (istop - istart))) +} + +# ui helper function +ui_dataTable_panel <- function(datasetName, pagination = TRUE) { + return(parse( + text = paste0( + "div(div(DT::dataTableOutput('", + datasetName, + "'), class='box-panel-padding'), class='box-panel')" + ) + )) +} + +EmptyDataset <- function(columns) { + dataset <- data.frame(V1 = integer()) + lapply(columns[-1], function(x) + dataset[, x] <<- integer()) + colnames(dataset) <- columns + return(dataset) +} + +# # DO ONCE +# css_colors <- group_pal_rows(300) +# css_generated <- "" +# for (i in 1: 300){ +# css_generated <- paste(css_generated, ".x", i, "{background-color: ", css_colors[i],";}","table.dataTable tr.selected td.x",i,"{background-color: ",css_colors[i], " !important;}", sep="") +# css_generated <- paste(css_generated," ", sep="\n") +# } +# print(css_generated) diff --git a/norma.config.hosted.json b/norma.config.hosted.json deleted file mode 100644 index 6169e10..0000000 --- a/norma.config.hosted.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "_comment": "Settings for the normaviz.org public server, behind an HTTPS reverse proxy (see deploy/apache-normaviz.conf). Copy to norma.config.json or pass with --config.", - "mode": "hosted", - "server": { - "host": "127.0.0.1", - "port": 8000, - "publicUrl": "https://normaviz.org/", - "trustProxy": true, - "hsts": true, - "accessLog": "anonymous", - "openBrowser": false - }, - "api": { "enabled": true, "ttlHours": 24, "maxMB": 50, "maxSessions": 500 }, - "relays": { "string": true, "arena3d": true, "databases": true }, - "site": { - "name": "NORMA", - "institution": "TODO: your institute, City, Country", - "contactName": "The NORMA team", - "contactEmail": "admin@normaviz.org", - "contactUrl": "https://github.com/PavlopoulosLab/NORMA/issues", - "sourceUrl": "https://github.com/PavlopoulosLab/NORMA", - "licenceName": "MIT License", - "licenceUrl": "https://opensource.org/licenses/MIT", - "privacyUrl": "", - "imprintUrl": "", - "maintainedUntil": "2031", - "notice": "", - "testedBrowsers": ["Chrome", "Firefox", "Safari", "Edge"] - }, - "app": { "maxNodes": 10000, "theme": "white", "startTab": "welcome", "cdnFallback": false } -} diff --git a/norma.config.json b/norma.config.json deleted file mode 100644 index 4dd8427..0000000 --- a/norma.config.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "_comment": "Settings for running NORMA on this computer. See norma.config.hosted.json for a public server and README.md for every option.", - "mode": "local", - "server": { "host": "127.0.0.1", "port": 8000, "accessLog": "off" }, - "api": { "enabled": true, "ttlHours": 24, "maxMB": 50, "maxSessions": 500 }, - "relays": { "string": true, "arena3d": true, "databases": true }, - "app": { "maxNodes": 10000, "theme": "white", "startTab": "welcome", "cdnFallback": true } -} diff --git a/run_local.bat b/run_local.bat deleted file mode 100644 index b1115b0..0000000 --- a/run_local.bat +++ /dev/null @@ -1,9 +0,0 @@ -@echo off -REM Start NORMA on this computer and open it in the browser (Windows). -cd /d "%~dp0" -if not exist frontend\dist\norma.html ( - echo Building the page (needs Node 22 and npm)... - cd frontend && call npm install && call npm run build && cd .. -) -python backend\server.py --mode local %* -pause diff --git a/run_local.sh b/run_local.sh deleted file mode 100755 index 902c461..0000000 --- a/run_local.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -# Start NORMA on this computer and open it in the browser (macOS, Linux). -cd "$(dirname "$0")" -if [ ! -f frontend/dist/norma.html ]; then - echo "Building the page (needs Node 22 and npm)..." - (cd frontend && npm install && npm run build) || exit 1 -fi -exec python3 backend/server.py --mode local "$@" diff --git a/server.R b/server.R new file mode 100644 index 0000000..b263007 --- /dev/null +++ b/server.R @@ -0,0 +1,1459 @@ +shinyServer(function(input, output, session) { + # source function files + source('./functions/upload.R', local=TRUE) + source('./functions/network.R', local=TRUE) + source('./functions/annotations.R', local=TRUE) + source('./functions/topology.R', local=TRUE) + source('./functions/helpDownloadHandlers.R', local=TRUE) + + set.seed(123) + + # ~~~GLOBAL VARS~~~ #### + colors <- randomColor(50) + area1<- NULL + area2<- NULL + v1<- NULL + v2<- NULL + + # reactiveValues #### + reactiveVars <- reactiveValues() + reactiveVars$StoredNetworks <- data.frame(id = character(), + name = character(), + stringsAsFactors = F) + reactiveVars$SelectedStoredNetworksIds <- c() + reactiveVars$StoredAnnotations <- data.frame(id = character(), + name = character(), + stringsAsFactors = F) + reactiveVars$SelectedStoredAnnotationIds <- c() + reactiveVars$StoredExpressions <- data.frame(id = character(), + name = character(), + stringsAsFactors = F) + reactiveVars$SelectedStoredExpressionIds <- c() + reactiveVars$StoredNetworks_just_network <- data.frame(id = character(), + name = character(), + stringsAsFactors = F) + reactiveVars$SelectedStoredNetworksIds_just_network <- c() + ### Duplicated upload for selctInput boxes of networks in annotation-tab (_annotations_tab)### + reactiveVars$StoredNetworks_annotations_tab <- + data.frame(id = character(), + name = character(), + stringsAsFactors = F) + reactiveVars$SelectedStoredNetworksIds_annotations_tab <- c() + ### Duplicated upload for annotations in annotation-tab ### + reactiveVars$StoredNetworks2_annotations_tab <- + data.frame(id = character(), + name = character(), + stringsAsFactors = F) + reactiveVars$SelectedStoredNetworksIds2_annotations_tab <- c() + ### Topology tab ### + reactiveVars$StoredNetworks_topology_tab <- + data.frame(id = character(), + name = character(), + stringsAsFactors = F) + reactiveVars$SelectedStoredNetworksIds_topology_tab <- c() + + # reactive #### + StoredNets <- reactive({ return(reactiveVars$StoredNetworks) }) + StoredNets_annotations_tab <- reactive({ return(reactiveVars$StoredNetworks_annotations_tab) }) + StoredNets2_annotations_tab <- reactive({ return(reactiveVars$StoredNetworks2_annotations_tab) }) + StoredNets_topology_tab <- reactive({ return(reactiveVars$StoredNetworks_topology_tab) }) + StoredAnnots <- reactive({ return(reactiveVars$StoredAnnotations) }) + StoredExpress <- reactive({ return(reactiveVars$StoredExpressions) }) + fetchFirstSelectedStoredDataset <- reactive({ + ssn <- SelectedStoredNets() + if (!is.null(ssn) && nrow(ssn) > 0) { + return(fetchDataset(ssn[1,]$id)) + } else { + return(NULL) + } + }) + fetchFirstSelectedStoredDataset2 <- reactive({ + sannots <- SelectedStoredAnnots() + if (!is.null(sannots) && nrow(sannots) > 0) { + return(fetchDataset(sannots[1,]$id)) + } else { + return(NULL) + } + }) + fetchFirstSelectedStoredDataset_annotations_tab <- reactive({ + ssn <- SelectedStoredNets_annotations_tab() + if (!is.null(ssn) && nrow(ssn) > 0) { + return(fetchDataset_annotations_tab(ssn[1,]$id)) + } else { + return(NULL) + } + }) + fetchFirstSelectedStoredGroups2_annotations_tab <- reactive({ + sannots <- SelectedStoredNets2_annotations_tab() + if (!is.null(sannots) && nrow(sannots) > 0) { + return(fetchDataset2_annotations_tab(sannots[1,]$id)) + } else { + return(NULL) + } + }) + fetchFirstSelectedStoredExpression <- reactive({ + sexpress <- SelectedStoredExpress() + if (!is.null(sexpress) && nrow(sexpress) > 0) { + return(fetchDatasetEx(sexpress[1,]$id)) + } else { + return(NULL) + } + }) + fetchFirstSelectedStoredDataset_topology_tab <- reactive({ + ssn <- SelectedStoredNets_topology_tab() + if (!is.null(ssn) && nrow(ssn) > 0) { + return(fetchDataset_topology_tab(ssn[1,]$id)) + } else { + return(NULL) + } + }) + datasetInput <- reactive({ + automated_annotations <- input$automated_annotations + + source("./functions/refreshing/modularity.R", local = T) + net <- fetchFirstSelectedStoredIgraph_just_network() + if (is.null(net)) + return() + modularity() + }) + # Scaling - Sliders + scaling_coordinates_convex <- reactive({ input$scaling_coordinates_convex }) + scaling_coordinates_pies <- reactive({ input$scaling_coordinates_pies }) + scaling_nodes_convex <- reactive({ input$scaling_nodes_convex }) + scaling_nodes_pies <- reactive({ input$scaling_nodes_pies }) + scaling_labels_convex <- reactive({ input$scaling_labels_convex }) + scaling_labels_pies <- reactive({ input$scaling_labels_pies }) + scaling_coordinates_convex_3D_X <- reactive({ input$scaling_coordinates_convex_3D_X }) + scaling_coordinates_convex_3D_Y <- reactive({ input$scaling_coordinates_convex_3D_Y }) + scaling_coordinates_convex_3D_Z <- reactive({ input$scaling_coordinates_convex_3D_Z }) + + # ~~~UPLOAD~~~ #### + # ~~Upload sidebar~~ #### + # observeEvents #### + doAddNetwork <- observeEvent(input$btnAddNetwork, { + tryCatch({ + addNetwork() + }, error = function(e) { + print(paste("Upload tab error: ", e)) + shinyalert("Error!", "Upload tab error.", type = "error") + }) + }) + + doRemNetwork <- observeEvent(input$btnRemoveNetworks, { + tryCatch({ + remNetwork() + }, error = function(e) { + print(paste("Upload tab error: ", e)) + shinyalert("Error!", "Upload tab error.", type = "error") + }) + }) + + doAddAnnotations <- observeEvent(input$btnAddNetwork2, { + tryCatch({ + addAnnotations() + }, error = function(e) { + print(paste("Upload tab error: ", e)) + shinyalert("Error!", "Upload tab error.", type = "error") + }) + }) + + doRemAnnotations <- observeEvent(input$btnRemoveNetworks2, { + tryCatch({ + remAnnotations() + }, error = function(e) { + print(paste("Upload tab error: ", e)) + shinyalert("Error!", "Upload tab error.", type = "error") + }) + }) + + doAddExpression <- observeEvent(input$btnAddExpression, { + tryCatch({ + addExpression() + }, error = function(e) { + print(paste("Upload tab error: ", e)) + shinyalert("Error!", "Upload tab error.", type = "error") + }) + }) + + doRemExpression <- observeEvent(input$btnRemoveExpression, { + tryCatch({ + remExpression() + }, error = function(e) { + print(paste("Upload tab error: ", e)) + shinyalert("Error!", "Upload tab error.", type = "error") + }) + }) + + uploadTabSetSelectedNetwork <- observeEvent(input$storedGraphsOutputSelectUpload, { + tryCatch({ + reactiveVars$SelectedStoredNetworksIds <- c(input$storedGraphsOutputSelectUpload) + }, error = function(e) { + print(paste("Upload tab error: ", e)) + shinyalert("Error!", "Upload tab error.", type = "error") + }) + }, ignoreNULL = FALSE) + + # Add-Annotations button + uploadTabSetSelectedNetwork2 <- observeEvent(input$storedGraphsOutputSelectUpload2, { + tryCatch({ + reactiveVars$SelectedStoredAnnotationIds <- c(input$storedGraphsOutputSelectUpload2) + }, error = function(e) { + print(paste("Upload tab error: ", e)) + shinyalert("Error!", "Upload tab error.", type = "error") + }) + }, ignoreNULL = FALSE) + + # observes #### + # Change of Network Name based on input choices + dochangeNetworkName <- observe({ + tryCatch({ + updateTextInput(session, + inputId = "networkName", + value = (if (input$uiLoadGraphOptionsInput == "OF") { + paste("Network name") + } else if (input$uiLoadGraphOptionsInput == "oR_String_interactions"){ + paste("BCAR3 STRING Network") + } else if (input$uiLoadGraphOptionsInput == "oR_Drosophila"){ + paste("Drosophila TAU Network") + })) + }, error = function(e) { + print(paste("Upload tab error: ", e)) + shinyalert("Error!", "Upload tab error.", type = "error") + }) + }) + + # Change Annotation Name based on input choices + dochangeAnnotationName <- observe({ + tryCatch({ + updateTextInput(session, + inputId = "annotationName", + value = (if (input$uiLoadGraphOptionsInput_annotations == "OF") { + paste("Annotation name") + } else if (input$uiLoadGraphOptionsInput_annotations == "oR_String_Annotation_BP"){ + paste("BCAR3 GO Biological Process") + } else if (input$uiLoadGraphOptionsInput_annotations == "oR_String_Annotation_MF"){ + paste("BCAR3 GO Molecular Function") + } else if (input$uiLoadGraphOptionsInput_annotations == "oR_String_Annotation_KEGG"){ + paste("BCAR3 GO KEGG pathways") + } else if (input$uiLoadGraphOptionsInput_annotations == "oR_Drosophila_KEGG"){ + paste("Drosophila TAU KEGG pathways") + } else if (input$uiLoadGraphOptionsInput_annotations == "oR_Drosophila_Luvain"){ + paste("Drosophila TAU Louvain") + })) + }, error = function(e) { + print(paste("Upload tab error: ", e)) + shinyalert("Error!", "Upload tab error.", type = "error") + }) + }) + + # Change Expression Name based on input choices + dochangeExpressionName <- observe({ + tryCatch({ + updateTextInput(session, + inputId = "expressionName", + value = (if (input$uiLoadExpressionsInput == "oR_Expression_file_Drosophila"){ + paste("Drosophila TAU node - coloring file") + })) + }, error = function(e) { + print(paste("Upload tab error: ", e)) + shinyalert("Error!", "Upload tab error.", type = "error") + }) + }) + + # UI render outputs #### + output$uiLoadGraphOptionsOutput <- renderUI({ + tryCatch({ + if (is.null(input$uiLoadGraphOptionsInput)) return() + # Depending on input$input_type, we'll generate a different UI + # component and send it to the client. + if (input$uiLoadGraphOptionsInput == "oF") { + wellPanel(fileInput( + "file1", + "Choose file to upload", + accept = c( + "text/csv", + "text/comma-separated-values,text/plain", + ".csv" + ))#, + #div(list(div(wellPanel(checkboxInput(inputId = "weighted1", label = "Weighted", value = F)), class = "col-md-6")), class = "row") + ) + } + # else { + # div(list(div(wellPanel(checkboxInput(inputId = "weighted1", label = "Weighted", value = F)), class = "col-md-6")), class = "row") + # } + }, error = function(e) { + print(paste("Upload tab error: ", e)) + shinyalert("Error!", "Upload tab error.", type = "error") + }) + }) + + output$uiStoredGraphsOutputRadio <- renderUI({ + tryCatch({ + input$btnAddNetwork + input$btnRemoveNetworks + choices <- getStoredNetsChoices() + if (is.null(choices)) + return() + return(list( + br(), + wellPanel( + h4("Available networks"), + checkboxGroupInput( + "availableNetworks", + label = "", + choices = choices + ) + ), + div(div( + actionButton("btnRemoveNetworks", "REMOVE", icon = icon("minus")), + class = "col-md-5 centerBlock" + ), class = "row text-center") + )) + }, error = function(e) { + print(paste("Upload tab error: ", e)) + shinyalert("Error!", "Upload tab error.", type = "error") + }) + }) + + output$uiLoadGraphOptionsOutput_annotations <- renderUI({ + tryCatch({ + if (is.null(input$uiLoadGraphOptionsInput_annotations)) return() + # Depending on input$input_type, we'll generate a different UI + # component and send it to the client. + if (input$uiLoadGraphOptionsInput_annotations == "oF") { + wellPanel(fileInput( + "file2", + "Choose file to upload", + accept = c( + "text/csv", + "text/comma-separated-values,text/plain", + ".csv" + ) + )) + } + }, error = function(e) { + print(paste("Upload tab error: ", e)) + shinyalert("Error!", "Upload tab error.", type = "error") + }) + }) + + output$uiLoadExpressionsOutput <- renderUI({ + tryCatch({ + if (is.null(input$uiLoadExpressionsInput)) return() + # Depending on input$input_type, we'll generate a different UI + # component and send it to the client. + if (input$uiLoadExpressionsInput == "oF") { + wellPanel(fileInput( + "file3", + "Choose file to upload", + accept = c( + "text/csv", + "text/comma-separated-values,text/plain", + ".csv" + ) + )) + } + }, error = function(e) { + print(paste("Upload tab error: ", e)) + shinyalert("Error!", "Upload tab error.", type = "error") + }) + }) + + output$uiStoredGraphsOutputRadioEx <- renderUI({ + tryCatch({ + input$btnAddExpression + input$btnRemoveExpression + choices <- getStoredExpressionChoices() + if (is.null(choices)) + return() + return(list( + br(), + wellPanel( + h4("Available Expressions"), + checkboxGroupInput( + "availableExpressions", + label = "", + choices = choices + ) + ), + div(div( + actionButton("btnRemoveExpression", "REMOVE", icon = icon("minus")), + class = "col-md-5 centerBlock" + ), class = "row text-center") + )) + }, error = function(e) { + print(paste("Upload tab error: ", e)) + shinyalert("Error!", "Upload tab error.", type = "error") + }) + }) + + # ~~Upload mainPanel~~ #### + # UI render outputs #### + + # select box for network edgelists + output$uiStoredGraphsOutputSelectUpload <- renderUI({ + tryCatch({ + input$btnAddNetwork + input$btnRemoveNetworks + choices <- getStoredNetsChoices() + if (is.null(choices)) return() + return(selectInput( + "storedGraphsOutputSelectUpload", + "Selected network", + choices + )) + }, error = function(e) { + print(paste("Upload tab error: ", e)) + shinyalert("Error!", "Upload tab error.", type = "error") + }) + }) + + # select box for annotations + output$uiStoredGraphsOutputSelectUpload2 <- renderUI({ + tryCatch({ + input$btnAddNetwork2 + input$btnRemoveNetworks2 + choices <- getStoredAnnotChoices() + if (is.null(choices)) return() + return( + selectInput( + "storedGraphsOutputSelectUpload2", + "Selected annotation", + choices + ) + ) + }, error = function(e) { + print(paste("Upload tab error: ", e)) + shinyalert("Error!", "Upload tab error.", type = "error") + }) + }) + + # Table format - No loops allowed (simplify) + output$datasettab1 <- DT::renderDataTable({ + tryCatch({ + dataset <- fetchFirstSelectedStoredDataset() + if (is.null(dataset)) + dataset <- EmptyDataset(c("Source", "Target", "Weight")) + if (nrow(dataset) == 0 || attr(dataset, 'weighted')){ + return(datatable(dataset, rownames = F, editable = F, options=list(deferRender = TRUE, scrollY = 500, scroller = TRUE,pageLength = 500) + ) %>% + formatStyle(colnames(dataset), fontSize = ui_options["ui_table_font_sz"]) %>% + formatRound("Weight") + ) + } else { + return(datatable(dataset, rownames = FALSE, options=list(deferRender = TRUE, + scrollY = 500, + scroller = TRUE,pageLength = 500, + columnDefs = list(list(visible=FALSE, targets=c(2))))) %>% + formatStyle(colnames(dataset), fontSize = ui_options["ui_table_font_sz"]) %>% + formatRound("Weight")) + } + }, error = function(e) { + print(paste("Upload tab error: ", e)) + shinyalert("Error!", "Upload tab error.", type = "error") + }) + }) + + # Table view of Annotations + output$datasettab2 <- DT::renderDataTable({ + tryCatch({ + annotation <- fetchFirstSelectedStoredDataset2() + if (is.null(annotation)) annotation <- EmptyDataset(c("Annotations", "Nodes")) + annotation$Nodes <- gsub(',', ', ', annotation$Nodes) + datatable(annotation, rownames = FALSE, extensions = 'Responsive') %>% + formatStyle(colnames(annotation), fontSize = ui_options["ui_table_font_sz"]) + }, error = function(e) { + print(paste("Upload tab error: ", e)) + shinyalert("Error!", "Upload tab error.", type = "error") + }) + }) + + output$uiStoredGraphsOutputRadio_annotations <- renderUI({ + tryCatch({ + input$btnAddNetwork2 + input$btnRemoveNetworks2 + choices <- getStoredAnnotChoices() + if (is.null(choices)) + return() + return(list( + br(), + wellPanel( + h4("Available Annotations"), + checkboxGroupInput( + "availableAnnotations", + label = "", + choices = choices + ) + ), + div(div( + actionButton("btnRemoveNetworks2", "REMOVE", icon = icon("minus")), + class = "col-md-5 centerBlock" + ), class = "row text-center") + )) + }, error = function(e) { + print(paste("Upload tab error: ", e)) + shinyalert("Error!", "Upload tab error.", type = "error") + }) + }) + + # ~~~NETWORK ~~~ #### + # ObserveEvents #### + uploadTabSetSelectedNetwork_just_network <- observeEvent(input$storedGraphsOutputSelectUpload_just_network, { + tryCatch({ + reactiveVars$SelectedStoredNetworksIds_just_network <- c(input$storedGraphsOutputSelectUpload_just_network) + }, error = function(e) { + print(paste("Network tab error: ", e)) + shinyalert("Error!", "Network tab error.", type = "error") + }) + }, ignoreNULL = FALSE) + + # UI render outputs #### + # Duplicated upload for networks in network-tab (just_network) + output$uiLoadGraphOptionsOutput_just_network <- renderUI({ + tryCatch({ + input$btnAddNetwork + input$btnRemoveNetworks + choices <- getStoredNetsChoices_just_network() + if (is.null(choices)) return() + return( selectInput( + "storedGraphsOutputSelectUpload_just_network", + "Selected network", choices) + ) + }, error = function(e) { + print(paste("Network tab error: ", e)) + shinyalert("Error!", "Network tab error.", type = "error") + }) + }) + + # Interactive visNetwork + output$tabVizIgraphSimple <- renderVisNetwork({ + tryCatch({ + set.seed(123) + g <- fetchFirstSelectedStoredIgraph_just_network() + if (is.null(g)) + return() + igraph_visn <- toVisNetworkData(g) + igraph_visn$edges$value <- E(g)$weight + + set.seed(123) + if(is.weighted(g)){ + withProgress(min = 0, max = 1, { + incProgress(message = "Plotting", + detail = "This may take a while...", + amount = .1) + set.seed(123) + visNetwork(igraph_visn$nodes, igraph_visn$edges) %>% + visNodes(size = 25, shape = "ellipse") %>% + visEdges(smooth = FALSE) %>% + visIgraphLayout(layout = "layout_with_fr") %>% + visOptions(highlightNearest = TRUE, + nodesIdSelection = TRUE) %>% + visPhysics(enabled = F) %>% + visInteraction( + keyboard = TRUE, + navigationButtons = TRUE, + zoomView = TRUE, + multiselect = TRUE, + dragView = TRUE + ) + }) + } else{ + withProgress(min = 0, max = 1, { + incProgress(message = "Plotting", + detail = "This may take a while...", + amount = .1) + visIgraph(as.undirected(g)) %>% + visNodes(size = 25, shape = "ellipse") %>% + visOptions(highlightNearest = TRUE, + nodesIdSelection = TRUE) %>% + visInteraction( + keyboard = TRUE, + navigationButtons = TRUE, + zoomView = TRUE, + multiselect = TRUE, + dragView = TRUE + ) + }) + } + }, error = function(e) { + print(paste("Network tab error: ", e)) + shinyalert("Error!", "Network tab error.", type = "error") + }) + }) + + output$modularity_plot <- renderPlot({ + tryCatch({ + # show_labels_algorithms_tab <- T + automated_annotations <- input$automated_annotations + net <- fetchFirstSelectedStoredIgraph_just_network() + if (is.null(net)) + return() + clp <- + automated_annotation_choices(net, automated_annotations) + + if (input$show_labels_algorithms_tab == F) { + # show_labels_algorithms_tab = F + set.seed(123) + withProgress(min = 0, max = 1, { + incProgress(message = "Plotting", + detail = "This may take a while...", + amount = .1) + plot( + clp, + net, + edge.color = 'grey50', + mark.col = qual_col_pals, + vertex.size = 5, + # vertex.label.color = "black", + vertex.color = 'grey50', + vertex.label = NA + ) + }) + } + + else{ + set.seed(123) + withProgress(min = 0, max = 1, { + incProgress(message = "Plotting", + detail = "This may take a while...", + amount = .1) + plot( + clp, + net, + edge.color = 'grey50', + mark.col = qual_col_pals, + vertex.size = 5, + vertex.label.color = "black", + vertex.color = 'grey50' + ) + }) + } + }, error = function(e) { + print(paste("Network tab error: ", e)) + shinyalert("Error!", "Network tab error.", type = "error") + }) + }) + + output$Modularity_table <- DT::renderDataTable({ + tryCatch({ + net <- fetchFirstSelectedStoredIgraph_just_network() + if (is.null(net)) { + df <- EmptyDataset(c("Annotations", "Nodes")) + } + else{ + automated_annotations <- input$automated_annotations + source("./functions/refreshing/modularity.R", local = T) + df <- modularity() + datatable( + df, + colnames = c("Annotations", "Nodes"), + rownames = FALSE, + extensions = 'Responsive' + ) %>% formatStyle(colnames(df), fontSize = ui_options["ui_table_font_sz"]) + } + }, error = function(e) { + print(paste("Network tab error: ", e)) + shinyalert("Error!", "Network tab error.", type = "error") + }) + }) + + # downloadHandlers #### + output$downloadData <- downloadHandler( + filename = function() { + automated_annotations <- input$automated_annotations + paste(file_name(), Sys.Date(), '.txt', sep = '') + }, + content = function(file) { + write.table( + datasetInput(), + file, + row.names = FALSE, + col.names = F, + quote = F, + sep = "\t" + ) + } + ) + + # ~~~ANNOTATIONS~~~ #### + # observeEvents #### + uploadTabSetSelectedNetwork_annotations_tab <- observeEvent(input$storedGraphsOutputSelectUpload_annotations_tab, { + tryCatch({ + reactiveVars$SelectedStoredNetworksIds_annotations_tab <- c(input$storedGraphsOutputSelectUpload_annotations_tab) + }, error = function(e) { + print(paste("Annotations tab error: ", e)) + shinyalert("Error!", "Annotations tab error.", type = "error") + }) + }, ignoreNULL = FALSE) + + uploadTabSetSelectedNetwork2_annotations_tab <- observeEvent(input$storedGraphsOutputSelectUpload2_annotations_tab, { + tryCatch({ + reactiveVars$SelectedStoredNetworksIds2_annotations_tab <- c(input$storedGraphsOutputSelectUpload2_annotations_tab) + }, error = function(e) { + print(paste("Annotations tab error: ", e)) + shinyalert("Error!", "Annotations tab error.", type = "error") + }) + }, ignoreNULL = FALSE) + + uploadTabSetSelectedExpression <- observeEvent(input$uiStoredGraphsOutputSelectUploadExpressions, { + tryCatch({ + reactiveVars$SelectedStoredExpressionIds <- c(input$uiStoredGraphsOutputSelectUploadExpressions) + }, error = function(e) { + print(paste("Annotations tab error: ", e)) + shinyalert("Error!", "Annotations tab error.", type = "error") + }) + }, ignoreNULL = FALSE) + + # observes #### + node1_choice<- observe({ + tryCatch({ + node1 <- input$node_1 + node2 <- input$node_2 + + venn<- vennDiagrams() + if(is.null(input$node1)) + df<- EmptyDataset(c("V1", "V2")) + + if(!is.null(input$node_1)){ + for(i in length(venn$id)){ + venn_1<-which(venn$id==input$node_1) + venn_2<-which(venn$id==input$node_2) + v2 <- unlist(stri_split(venn[venn_2,2],fixed=',')) + v1 <- unlist(stri_split(venn[venn_1,2],fixed=',')) + area1<-length(v1) + + df <- cbind("Node 1"=input$node_1,"Unique Groups"= v1[which((v1%in%v2)==F)]) + df<- as.data.frame(df) + } + } + output$venn_table1 <- DT::renderDataTable({ + datatable(df,rownames = FALSE, extensions = 'Responsive') %>% formatStyle(colnames(df), fontSize = ui_options["ui_table_font_sz"]) + }) + }, error = function(e) { + print(paste("Annotations tab error: ", e)) + shinyalert("Error!", "Annotations tab error.", type = "error") + }) + }) + + node2_choice<- observe({ + tryCatch({ + node2 <- input$node_2 + node1 <- input$node_1 + + venn<- vennDiagrams() + if(is.null(input$node2)) + df<- EmptyDataset(c("V1", "V2")) + + if(!is.null(input$node_2)){ + for(i in length(venn$id)){ + venn_1<-which(venn$id==input$node_1) + venn_2<-which(venn$id==input$node_2) + v2 <- unlist(stri_split(venn[venn_2,2],fixed=',')) + v1 <- unlist(stri_split(venn[venn_1,2],fixed=',')) + area2<-length(v2) + + v1 %in% v2 + + df <- cbind("Node 2"=input$node_2, "Unique Groups"=v2[which((v2%in%v1)==F)]) + df<- as.data.frame(df) + } + } + output$venn_table2 <- DT::renderDataTable({ + datatable(df,rownames = FALSE, extensions = 'Responsive') %>% formatStyle(colnames(df), fontSize = ui_options["ui_table_font_sz"]) + }) + }, error = function(e) { + print(paste("Annotations tab error: ", e)) + shinyalert("Error!", "Annotations tab error.", type = "error") + }) + }) + + # UI render outputs #### + # 3 conditional panels + output$uiLoadGraphOptionsOutput_annotations_tab <- renderUI({ + tryCatch({ + input$btnAddNetwork + input$btnRemoveNetworks + choices <- getStoredNetsChoices_annotations_tab() + if (is.null(choices)) return() + return( + selectInput( + "storedGraphsOutputSelectUpload_annotations_tab", + "Selected network", + choices + ) + ) + }, error = function(e) { + print(paste("Annotations tab error: ", e)) + shinyalert("Error!", "Annotations tab error.", type = "error") + }) + }) + + output$uiLoadGraphOptionsOutput_annotations_annotations_tab <- renderUI({ + tryCatch({ + input$btnAddNetwork2 + input$btnRemoveNetworks2 + choices <- getStoredNetsChoices2_annotations_tab() + if (is.null(choices)) return() + return( + selectInput( + "storedGraphsOutputSelectUpload2_annotations_tab", + "Selected annotation", + choices + ) + ) + }, error = function(e) { + print(paste("Annotations tab error: ", e)) + shinyalert("Error!", "Annotations tab error.", type = "error") + }) + }) + + output$uiStoredGraphsOutputSelectUploadExpressions <- renderUI({ + tryCatch({ + input$btnAddExpression + input$btnRemoveExpression + choices <- getStoredExpressionChoices() + if (is.null(choices)) return() + return( + selectInput( + "uiStoredGraphsOutputSelectUploadExpressions", + "Selected Expression", + choices + ) + ) + }, error = function(e) { + print(paste("Annotations tab error: ", e)) + shinyalert("Error!", "Annotations tab error.", type = "error") + }) + }) + + # Convex hulls + output$interactive_convex_hulls <- renderUI({ + tryCatch({ + g <- fetchFirstSelectedStoredIgraph_annotations_tab() + annotation_graph <- fetchFirstSelectedStoredGroups2_annotations_tab() + if (is.null(g) | is.null(annotation_graph)) return(NULL) + + withProgress(min = 0, max = 1, { + incProgress(message = "Plotting", + detail = "This may take a while...", + amount = .1) + + start_time <- Sys.time() + convex_hulls(g, annotation_graph) + end_time <- Sys.time() + if (PRINT_TIMES) print(paste("### TIME:", input$convex_layout_strategy, ": ", end_time - start_time, " seconds.")) + + tags$iframe( + srcdoc = paste(readLines( + paste(USER_TEMP_FOLDER, "/output_convex_", session$token, ".html", sep = "") + ), collapse = '\n'), + width = "100%", + height = "850px" + ) + }) + }, error = function(e) { + print(paste("Annotations tab error: ", e)) + shinyalert("Error!", "Annotations tab error.", type = "error") + }) + }) + + output$chooseGroups <- DT::renderDataTable({ + tryCatch({ + annotation <- fetchFirstSelectedStoredGroups2_annotations_tab() + if (is.null(annotation)) + annotation <- EmptyDataset(c("Annotations", "Nodes")) + rowCallback_generated <- + "function(row, dat, displayNum, index){" + for (i in 1:length(rownames(annotation))) + { + rowCallback_generated <- + paste( + rowCallback_generated, + "if(dat[0]==", + i, + "){", + "$('td:eq(1)', row).addClass('x", + i, + "');}" , + sep = "" + ) + } + rowCallback_generated <- + paste(rowCallback_generated, "}", sep = "") + + css_colors <- group_pal_rows(length(rownames(annotation))) + + x <- length(rownames(annotation)) + tmp_css_colors <- c() + for (i in 1:x) + { + tmp_css_colors <- c(tmp_css_colors, css_colors[i]) + } + datatable( + annotation, + extensions = 'Scroller', + options = list( + rownames = T, + deferRender = TRUE, + scrollY = 200, + scroller = TRUE, + rowCallback = JS(rowCallback_generated) + ) + ) + }, error = function(e) { + print(paste("Annotations tab error: ", e)) + shinyalert("Error!", "Annotations tab error.", type = "error") + }) + }) + + # PieCharts + output$tabVizPie_charts <- renderUI({ + tryCatch({ + g <- fetchFirstSelectedStoredIgraph_annotations_tab() + annotation_graph <- fetchFirstSelectedStoredGroups2_annotations_tab() + if (is.null(g) | is.null(annotation_graph)) return(NULL) + + withProgress(min = 0, max = 1, { + incProgress(message = "Plotting", + detail = "This may take a while...", + amount = .1) + + pie_charts(g, annotation_graph) + tags$iframe( + srcdoc = paste(readLines( + paste(USER_TEMP_FOLDER, "/output_pies_", session$token, ".html", sep = "") + ), collapse = '\n'), + width = "100%", + height = "850px" + ) + }) + }, error = function(e) { + print(paste("Annotations tab error: ", e)) + shinyalert("Error!", "Annotations tab error.", type = "error") + }) + }) + + # PieCharts + output$chooseGroups2 <- DT::renderDataTable({ + tryCatch({ + annotation <- fetchFirstSelectedStoredGroups2_annotations_tab() + if (is.null(annotation)) + annotation <- EmptyDataset(c("Annotations", "Nodes")) + rowCallback_generated <- + "function(row, dat, displayNum, index){" + for (i in 1:length(rownames(annotation))) + { + rowCallback_generated <- + paste( + rowCallback_generated, + "if(dat[0]==", + i, + "){", + "$('td:eq(1)', row).addClass('x", + i, + "');}" , + sep = "" + ) + } + rowCallback_generated <- + paste(rowCallback_generated, "}", sep = "") + + css_colors <- group_pal_rows(length(rownames(annotation))) + + x <- length(rownames(annotation)) + tmp_css_colors <- c() + for (i in 1:x) + { + tmp_css_colors <- c(tmp_css_colors, css_colors[i]) + } + datatable( + annotation, + extensions = 'Scroller', + options = list( + rownames = T, + deferRender = TRUE, + scrollY = 200, + scroller = TRUE, + rowCallback = JS(rowCallback_generated) + ) + ) + }, error = function(e) { + print(paste("Annotations tab error: ", e)) + shinyalert("Error!", "Annotations tab error.", type = "error") + }) + }) + + # Convex hulls 3D + output$convex_hull_3D<- renderUI({ + tryCatch({ + s = input$chooseGroups_3D_rows_selected + + g <- fetchFirstSelectedStoredIgraph_annotations_tab() + annotation_graph <- fetchFirstSelectedStoredGroups2_annotations_tab() + if (is.null(g) | is.null(annotation_graph)) + return(NULL) + + if (input$Dark == T) { + Dark_mode = T + } + else if (input$Dark == F) { + Dark_mode = F + } + if (input$show_labels_3D == T) { + show_labels_3D = T + } + else if (input$show_labels_3D == F) { + show_labels_3D = F + } + if (input$expressions_3D == T) { + expression_colors_3D = T + } + else if (input$expressions_3D == F) { + expression_colors_3D = F + } + # if (input$layouts_with_virtual_nodes_3D == T) { + # layouts_with_virtual_nodes_3D = T + # } + # else if (input$layouts_with_virtual_nodes_3D == F) { + # layouts_with_virtual_nodes_3D = F + # } + if (input$show_some_labels_3D == T) { + show_some_labels_3D = T + } + else if (input$show_some_labels_3D == F) { + show_some_labels_3D = F + } + + withProgress(min = 0, max = 1, { + incProgress(message = "Plotting", + detail = "This may take a while...", + amount = .1) + + lay <- input$layouts_3D + source("./functions/refreshing/convex_hulls_3D.R", local = T) + convex_hull_3D() + + tags$iframe( + srcdoc = paste(readLines( + paste(USER_TEMP_FOLDER, "/convex_3D_", session$token,".html", sep="") + ), collapse = '\n'), + width = "100%", + height = "850px" + ) + }) + }, error = function(e) { + print(paste("Annotations tab error: ", e)) + shinyalert("Error!", "Annotations tab error.", type = "error") + }) + }) + + output$chooseGroups_3D <- DT::renderDataTable({ + tryCatch({ + annotation <- fetchFirstSelectedStoredGroups2_annotations_tab() + if (is.null(annotation)) + annotation <- EmptyDataset(c("Annotations", "Nodes")) + rowCallback_generated <- + "function(row, dat, displayNum, index){" + for (i in 1:length(rownames(annotation))) + { + rowCallback_generated <- + paste( + rowCallback_generated, + "if(dat[0]==", + i, + "){", + "$('td:eq(1)', row).addClass('x", + i, + "');}" , + sep = "" + ) + } + rowCallback_generated <- + paste(rowCallback_generated, "}", sep = "") + + css_colors <- group_pal_rows(length(rownames(annotation))) + + x <- length(rownames(annotation)) + tmp_css_colors <- c() + for (i in 1:x) + { + tmp_css_colors <- c(tmp_css_colors, css_colors[i]) + } + datatable( + annotation, + extensions = 'Scroller', + options = list( + rownames = T, + deferRender = TRUE, + scrollY = 200, + scroller = TRUE, + rowCallback = JS(rowCallback_generated) + ) + ) + }, error = function(e) { + print(paste("Annotations tab error: ", e)) + shinyalert("Error!", "Annotations tab error.", type = "error") + }) + }) + + # Venn Diagrams + output$vennDiagram1<- renderUI({ + tryCatch({ + venn <- vennDiagrams() + selectInput("node_1", label = "Node 1", choices = c("-",venn$id), selected = "-") + }, error = function(e) { + print(paste("Annotations tab error: ", e)) + shinyalert("Error!", "Annotations tab error.", type = "error") + }) + }) + + output$vennDiagram2<- renderUI({ + tryCatch({ + venn<-vennDiagrams() + selectInput("node_2", label = "Node 2", choices = c("-",venn$id), selected = "-") + }, error = function(e) { + print(paste("Annotations tab error: ", e)) + shinyalert("Error!", "Annotations tab error.", type = "error") + }) + }) + + output$vennDiagrams <- renderPlot({ + tryCatch({ + node1_choice<- observe({ node1 <- input$node_1 }) + + if(!is.null(input$node_1)){ + venn <- vennDiagrams() + for(i in length(venn$id)){ + venn_i<-which(venn$id==input$node_1) + v1 <- unlist(stri_split(venn[venn_i,2],fixed=',')) + area1<-length(v1) + } + } + + node2_choice<- observe({ node2 <- input$node_2 }) + + if(!is.null(input$node_2)){ + venn<- vennDiagrams() + for(i in length(venn$id)){ + venn_i<-which(venn$id==input$node_2) + v2 <- unlist(stri_split(venn[venn_i,2],fixed=',')) + area2<-length(v2) + } + } + + v12<-length(which(v1 %in% v2)) + + length_of_gaps<- c(input$node_1, input$node_2) + if(!is.null(length_of_gaps)){ + empty_length<- length(which(length_of_gaps %in% "-")) + + if(empty_length==0){ # 2 nodes + if( (input$node_1 != input$node_2) ) + { + draw.pairwise.venn(area1 = area1, + area2 = area2, + cross.area = v12, + category = c(input$node_1, input$node_2), + lty = "blank", + fill = c("skyblue", "pink1")) + } + } + } + }, error = function(e) { + print(paste("Annotations tab error: ", e)) + shinyalert("Error!", "Annotations tab error.", type = "error") + }) + }) + + output$venn_table_summ <- DT::renderDataTable({ + tryCatch({ + venn<- vennDiagrams() + length_of_gaps<- c(input$node_1, input$node_2, input$node_3) + empty_length<- length(which(length_of_gaps %in% "-")) + + if(is.null(input$node_1)|is.null(input$node_2)) + df<- EmptyDataset(c("Node 1", "Node 2", "Intersection")) + + for(i in length(venn$id)){ + venn_1<-which(venn$id==input$node_1) + venn_2<-which(venn$id==input$node_2) + v1 <- unlist(stri_split(venn[venn_1,2],fixed=',')) + v2 <- unlist(stri_split(venn[venn_2,2],fixed=',')) + area1<-length(v1) + area2<-length(v2) + v12<-length(which(v1 %in% v2)) + + df <- cbind("Node 1"=input$node_1, "Node 2"=input$node_2, "Intersection"=paste(v1[which(v1 %in% v2)], sep = "")) + df<- as.data.frame(df) + } + datatable(df,rownames = FALSE, extensions = 'Responsive') %>% formatStyle(colnames(df), fontSize = ui_options["ui_table_font_sz"]) + }, error = function(e) { + print(paste("Annotations tab error: ", e)) + shinyalert("Error!", "Annotations tab error.", type = "error") + }) + }) + + # downloadHandlers #### + output$HTML_convex <- downloadHandler( + filename = function() { + paste("Convex_hulls_2D_", session$token, ".html", sep = "") + }, + content = function(file) { + HTML_convex <- paste(readLines(paste(USER_TEMP_FOLDER, "/output_convex_", session$token, ".html", sep = "") + ), collapse = '\n') + write.table(HTML_convex, file, row.names = F,col.names = F, sep = "\t", quote = F) + } + ) + + output$HTML_pies <- downloadHandler( + filename = function() { + paste("Pie_charts_", session$token, ".html", sep = "") + }, + content = function(file) { + HTML_pies <- paste(readLines( + paste(USER_TEMP_FOLDER, "/output_pies_", session$token, ".html", sep = "") + ), collapse = '\n') + write.table(HTML_pies, file, row.names = F,col.names = F, sep = "\t", quote = F) + } + ) + + output$HTML_convex_3D <- downloadHandler( + filename = function() { + paste("Convex_hulls_3D_", session$token, ".html", sep = "") + }, + content = function(file) { + HTML_convex_3D <- paste(readLines( + paste(USER_TEMP_FOLDER, "/convex_3D_", session$token, ".html", sep="") + ), collapse = '\n') + write.table(HTML_convex_3D, file, row.names = F,col.names = F, sep = "\t", quote = F) + } + ) + + # ~~~TOPOLOGY~~~ #### + # ~~Topology sidebar~~ #### + # UI render outputs #### + output$uiStoredGraphsOutputSelectTopolopgy <- renderUI({ + tryCatch({ + input$btnAddNetwork + input$btnRemoveNetworks + choices <- getStoredNetsChoices_topology_tab() + if (is.null(choices)) return() + return(selectInput( + "storedGraphsOutputSelectTopolopgy", + "Selected network", + choices + )) + }, error = function(e) { + print(paste("Topology tab error: ", e)) + shinyalert("Error!", "Topology tab error.", type = "error") + }) + }) + + output$uiStoredGraphsOutputMultipleSelectTopolopgy <- renderUI({ + tryCatch({ + input$btnAddNetwork + input$btnRemoveNetworks + choices <- getStoredNetsChoices_topology_tab() + if (is.null(choices)) + return() + return( + checkboxGroupInput( + "storedGraphsOutputMultipleSelectTopolopgy", + "Selected network(s)", + choices, + selected = getStoredNetsChoices_topology_tab()[1] + ) + ) + }, error = function(e) { + print(paste("Topology tab error: ", e)) + shinyalert("Error!", "Topology tab error.", type = "error") + }) + }) + + # ~~Topology mainPanel~~ #### + # observeEvents #### + topologyTableViewSetSelectedNetwork <- observeEvent({ + input$storedGraphsOutputSelectTopolopgy + input$statisticsMethodsMainTabsetPanel + }, { + tryCatch({ + if (input$statisticsMethodsMainTabsetPanel == "tableView" && + !( + length(reactiveVars$SelectedStoredNetworksIds_topology_tab) == + 1 && + reactiveVars$SelectedStoredNetworksIds_topology_tab == input$storedGraphsOutputSelectTopolopgy + )) { + reactiveVars$SelectedStoredNetworksIds_topology_tab <- + c(input$storedGraphsOutputSelectTopolopgy) + } + }, error = function(e) { + print(paste("Topology tab error: ", e)) + shinyalert("Error!", "Topology tab error.", type = "error") + }) + }, ignoreNULL = FALSE) + + topologyPlotViewSetSelectedNetwork <- observeEvent({ + input$storedGraphsOutputMultipleSelectTopolopgy + input$statisticsMethodsMainTabsetPanel}, { + tryCatch({ + if (input$statisticsMethodsMainTabsetPanel == "plotView" && + !( + length(reactiveVars$SelectedStoredNetworksIds_topology_tab) == + length(input$storedGraphsOutputMultipleSelectTopolopgy) && + all( + reactiveVars$SelectedStoredNetworksIds_topology_tab == input$storedGraphsOutputMultipleSelectTopolopgy + ) + )) { + reactiveVars$SelectedStoredNetworksIds_topology_tab <- + c(input$storedGraphsOutputMultipleSelectTopolopgy) + } + }, error = function(e) { + print(paste("Topology tab error: ", e)) + shinyalert("Error!", "Topology tab error.", type = "error") + }) + }, ignoreNULL = FALSE) + + doStatSelectAll <- observeEvent(input$btnStatSelectAll, { + tryCatch({ + updateCheckboxGroupInput(session, "statistics2", selected = statistics) + }, error = function(e) { + print(paste("Topology tab error: ", e)) + shinyalert("Error!", "Topology tab error.", type = "error") + }) + }) + + doStatSelectNone <- observeEvent(input$btnStatSelectNone, { + tryCatch({ + updateCheckboxGroupInput(session, "statistics2", selected = character(0)) + }, error = function(e) { + print(paste("Topology tab error: ", e)) + shinyalert("Error!", "Topology tab error.", type = "error") + }) + }) + + doRefreshPalette <- observeEvent(input$btnRefreshPalette, { + tryCatch({ + ncolors <- length(colors) + colors <<- randomColor(ncolors) + }, error = function(e) { + print(paste("Topology tab error: ", e)) + shinyalert("Error!", "Topology tab error.", type = "error") + }) + }) + + # UI render outputs #### + output$statisticsMethodsPlotRender <- renderUI({ + tryCatch({ + plotOutput("statisticsMethodsBarPlot", height = paste0(as.integer( + 480 + + 480 * (input$statisticsPlotPercentMagnify / 100) + ), "px")) + }, error = function(e) { + print(paste("Topology tab error: ", e)) + shinyalert("Error!", "Topology tab error.", type = "error") + }) + }) + + output$statisticsMethodsBarPlot <- renderPlot({ + tryCatch({ + input$btnRefreshPalette + datasets <- fetchAllSelectedStoredDataset_topology_tab() + if (length(datasets) == 0) + return() + stat_res <- NULL + for (dataset_i in 1:length(datasets)) { + dataset <- datasets[[dataset_i]] + datasetName <- + getDatasetName(names(datasets)[dataset_i]) + dataset_stat_res <- stat_dataset(dataset, "") + if (is.null(dataset_stat_res) || + nrow(dataset_stat_res) == + 0) + next + if (is.null(stat_res)) { + stat_res <- dataset_stat_res + stat_res$network <- datasetName + } else { + dataset_stat_res$network <- datasetName + stat_res <- rbind(stat_res, dataset_stat_res) + } + } + if (is.null(stat_res)) + return() + colnames(stat_res) <- c("statistic", "value", "network") + stat_res$value <- as.numeric(as.character(stat_res$value)) + stat_res$network <- factor(stat_res$network) + ncolors <- length(levels(stat_res$network)) + if (length(colors) < ncolors) + colors <<- randomColor(ncolors) + plot.settings <- + list( + superpose.polygon = list(col = colors[1:ncolors], border = "transparent"), + strip.border = list(col = "black") + ) + barchart( + value ~ statistic, + group = network, + data = stat_res, + origin = 0, + horizontal = F, + auto.key = list( + space = "right", + points = F, + rectangles = T + ), + par.settings = plot.settings, + scales = list(x = list(rot = 45)), + panel = function(x, y, ...) { + panel.grid(h = -1, v = 0, col = "gray") + panel.barchart(x, y, ...) + } + ) + }, error = function(e) { + print(paste("Topology tab error: ", e)) + shinyalert("Error!", "Topology tab error.", type = "error") + }) + }) + + output$statres <- DT::renderDataTable({ + tryCatch({ + dset <- fetchFirstSelectedStoredDataset_topology_tab() + DT::datatable( + stat_dataset2(dset, getDatasetName(attr(dset, "id"))), + options = list( + paging = FALSE, + dom = "t", + rowCallback = JS( + "function(row, data) {", + "var num = parseFloat(data[2]).toFixed(2);", + "if(isNaN(num)){num = data[2];}", + "$('td:eq(2)', row).html(num);", + "}" + ) + ) + ) + }, error = function(e) { + print(paste("Topology tab error: ", e)) + shinyalert("Error!", "Topology tab error.", type = "error") + }) + }) + + # onSessionEnded #### + session$onSessionEnded(function() { + snets <- isolate(StoredNets()) + if (nrow(snets) > 0) { + unlink(c(paste0(USER_TEMP_FOLDER, "/", "*.rda"), "*.zip")) + } + + sannots <- isolate(StoredAnnots()) + if (nrow(sannots) > 0) { + unlink(c(paste0(USER_TEMP_FOLDER, "/", "*.rda"), "*.zip")) + } + + sexpress <- isolate(StoredExpress()) + if (nrow(sexpress) > 0) { + unlink(c(paste0(USER_TEMP_FOLDER, "/", "*.rda"), "*.zip")) + } + }) + +}) diff --git a/ui.R b/ui.R new file mode 100644 index 0000000..9d6f66e --- /dev/null +++ b/ui.R @@ -0,0 +1,31 @@ +# libs and files #### +source("./views/welcome.R", local=TRUE) +source("./views/upload.R", local=TRUE) +source("./views/network.R", local=TRUE) +source("./views/annotations.R", local=TRUE) +source("./views/topology.R", local=TRUE) +source("./views/help.R", local=TRUE) +source("./views/about.R", local=TRUE) + +# UI fixedPage #### +fixedPage( + theme = shinytheme("sandstone"), + useShinyjs(), + useShinyalert(), + tags$head(tags$script(src = "intro.js")), + tags$head(tags$script(src = "introbutton.js")), + tags$head(tags$link(rel = "stylesheet", type = "text/css", href = "norma.css")), + tags$head(tags$link(rel = "stylesheet", type = "text/css", href = "intro.css")), + tags$head(tags$link(rel = "stylesheet", type = "text/css", href = "annot_table.css")), + tags$head(tags$link(rel = "shortcut icon", href = "favicon.ico")), + tags$img(src = b64_1), + navbarPage("NORMA: The NetwORk Makeup Artist", + tabPanel( "Welcome", welcomePage ), + tabPanel( "Upload", icon = icon("upload"), uploadPage ), + tabPanel( "Network", networkPage ), + tabPanel( "Annotations", annotationsPage), + tabPanel( "Topology", icon = icon("globe", lib = "glyphicon"), topologyPage ), + tabPanel( "Help", icon = icon("question"), helpPage ), + tabPanel( "About", icon = icon("users"), aboutPage ) + ) +) diff --git a/user_temp/folder_create b/user_temp/folder_create new file mode 100644 index 0000000..e69de29 diff --git a/views/about.R b/views/about.R new file mode 100644 index 0000000..5783208 --- /dev/null +++ b/views/about.R @@ -0,0 +1,20 @@ +aboutPage <- div(id = "about_div", + strong("The Team:"), + tags$ul( + tags$li("Mikaela Koutrouli - BSRC 'Alexander Fleming'"), + tags$li("Evangelos Karatzas - BSRC 'Alexander Fleming'"), + tags$li("Katerina Papanikolopoulou - BSRC 'Alexander Fleming'"), + tags$li("Yorgos Sofianatos - BSRC 'Alexander Fleming'"), + tags$li("Georgios A. Pavlopoulos - BSRC 'Alexander Fleming'") + ), + br(), + strong("Code:"), + helpText("Available at: https://github.com/PavlopoulosLab/NORMA"), + br(), + strong("Publications:"), + br(), + tags$a(target="_blank", href="https://www.biorxiv.org/content/10.1101/2022.03.02.482621v1.abstract", "The network makeup artist (NORMA-2.0): Distinguishing annotated groups in a network using innovative layout strategies"), + helpText("bioRxiv, 2022 March, doi: 10.1101/2022.03.02.482621"), + tags$a(target="_blank", href="https://pubmed.ncbi.nlm.nih.gov/34171457", "NORMA: The Network Makeup Artist - A Web Tool for Network Annotation Visualization"), + helpText("Genomics Proteomics Bioinformatics, 2021 Jun 22:S1672-0229(21)00130-3, doi: 10.1016/j.gpb.2021.02.005, Epub ahead of print, PMID: 34171457.") +) diff --git a/views/annotations.R b/views/annotations.R new file mode 100644 index 0000000..d42462b --- /dev/null +++ b/views/annotations.R @@ -0,0 +1,434 @@ +annotationsPage <- div(id = "annotations_div", + conditionalPanel( + condition = "input.availableNetworks == 0", + bsAlert("tabUploadMainAlert"), + uiOutput("uiLoadGraphOptionsOutput_annotations_tab") + ), + conditionalPanel( + condition = "input.availableAnnotations == 0", + bsAlert("tabUploadMainAlert"), + uiOutput("uiLoadGraphOptionsOutput_annotations_annotations_tab") + ), + conditionalPanel( + condition = "input.availableExpressions == 0", + bsAlert("tabUploadMainAlert3"), + uiOutput("uiStoredGraphsOutputSelectUploadExpressions") + ), + br(), + tabsetPanel( + tabPanel( + "Convex Hulls", + br(), + tags$div(class = "strategies", + selectInput( + "layouts", + "General layout:", + choices = layouts_ui, + selected = selected_layouts, + multiple = FALSE + ), + selectInput( + "local_layout", + "Local layout:", + choices = layouts_ui, + selected = selected_layouts, + multiple = FALSE + ), + br(), + prettyRadioButtons( + inputId = "convex_layout_strategy", + label = "Layout modification strategy:", + choices = c("Simple layout", "Virtual node per group", "Group gravity", "Supernodes per group"), + thick = TRUE, + shape = "curve", + animation = "pulse", + status = "info" + ), + sliderInput( + inputId = "repeling_force", + label = "Adjust force strength:", + min = 1, + max = 20, + value = 10 + ) + ), # strategies + br(), + prettyCheckbox( + inputId = "show_labels",outline = T,fill = T,bigger = T, + label = "Show Labels", + thick = TRUE, + shape = "curve", + animation = "pulse", + status = "info", + inline = F, + value = T + ), + prettyCheckbox( + inputId = "expressions",outline = T,fill = T,bigger = T, + label = "Show node - coloring", + thick = TRUE, + shape = "curve", + animation = "pulse", + status = "info", + inline = F, + value = F + ), + prettyCheckbox( + inputId = "some_labels",outline = T,fill = T,bigger = T, + label = "Show only labels of selected annotation groups", + thick = TRUE, + shape = "curve", + animation = "pulse", + status = "info", + inline = F, + value = F + ), + hr(), + div(id="interactive_convex_hulls_loader", + shinycssloaders::withSpinner( + uiOutput("interactive_convex_hulls") + ) + ), + eval(ui_dataTable_panel("chooseGroups")), + tags$style( + HTML( + ".js-irs-3 .irs-bar {border-top-color: #2C8160; border-bottom-color: #2C8160;} .js-irs-3 .irs-bar-edge {border-color: #2C8160;} + .js-irs-3 .irs-single, .js-irs-3 .irs-bar-edge, .js-irs-3 .irs-bar {background: #2C8160;}" + ) + ), + + tags$style( + HTML( + ".js-irs-4 .irs-bar {border-top-color: #2C8160;border-bottom-color: #2C8160;} .js-irs-4 .irs-bar-edge {border-color: #2C8160;} + .js-irs-4 .irs-single, .js-irs-4 .irs-bar-edge, .js-irs-4 .irs-bar {background: #2C8160;}" + ) + ), + + tags$style( + HTML( + ".js-irs-5 .irs-bar {border-top-color: #2C8160; border-bottom-color: #2C8160;} .js-irs-5 .irs-bar-edge {border-color: #2C8160;} + .js-irs-5 .irs-single, .js-irs-5 .irs-bar-edge, .js-irs-5 .irs-bar {background: #2C8160;}" + ) + ), + + div( + style = "display:inline-block", + sliderInput( + inputId = "scaling_coordinates_convex", + label = "Scale the coordinates:", + min = 1, + max = 10, + value = 1 + ) + ), + div( + style = "display:inline-block", + sliderInput( + "scaling_nodes_convex", + "Adjust node size:", + min = 0.2, + max = 5, + value = 2, + step = 0.2 + ) + ), + div( + style = "display:inline-block", + sliderInput( + "scaling_labels_convex", + "Adjust label size:", + min = 0, + max = 30, + value = 10, + step = 2 + ) + ), + br(), + br(), + downloadBttn("HTML_convex", "Download HTML file", + style = "bordered", + color = "success", + size = "sm", + no_outline = T), + br(), + br() + ), + + tabPanel( + "Pie - Chart Nodes", + fluidRow( + tags$div(class = "strategies", + selectInput( + "layouts2", + "General layout:", + choices = layouts_ui, + selected = selected_layouts, + multiple = FALSE + ), + selectInput( + "local_layout2", + "Local layout:", + choices = layouts_ui, + selected = selected_layouts, + multiple = FALSE + ), + br(), + prettyRadioButtons( + inputId = "piechart_layout_strategy", + label = "Layout modification strategy:", + choices = c("Simple layout", "Virtual node per group", "Group gravity", "Supernodes per group"), + thick = TRUE, + shape = "curve", + animation = "pulse", + status = "info" + ), + sliderInput( + inputId = "repeling_force2", + label = "Adjust force strength:", + min = 1, + max = 20, + value = 10 + ) + ), # strategies pies + hr(), + prettyCheckbox( + inputId = "show_labels_pies",outline = T,fill = T,bigger = T, + label = "Show Labels", + thick = TRUE, + shape = "curve", + animation = "pulse", + status = "info", + inline = F, + value = T + ), + prettyCheckbox( + inputId = "expressions_pies",outline = T,fill = T,bigger = T, + label = "Show node - coloring", + thick = TRUE, + shape = "curve", + animation = "pulse", + status = "info", + inline = F, + value = F + ), + prettyCheckbox( + inputId = "some_labels_pies",outline = T,fill = T,bigger = T, + label = "Show only labels of selected annotation groups", + thick = TRUE, + shape = "curve", + animation = "pulse", + status = "info", + inline = F, + value = F + ), + div(id="tabVizPie_charts_loader", + shinycssloaders::withSpinner( + uiOutput('tabVizPie_charts') + ) + ), + eval(ui_dataTable_panel("chooseGroups2")), + ), + tags$style( + HTML( + ".js-irs-0 .irs-bar {border-top-color: #2C8160; border-bottom-color: #2C8160;} .js-irs-0 .irs-bar-edge {border-color: #2C8160;} + .js-irs-0 .irs-single, .js-irs-0 .irs-bar-edge, .js-irs-0 .irs-bar {background: #2C8160;}" + ) + ), + + tags$style( + HTML( + ".js-irs-1 .irs-bar {border-top-color: #2C8160;border-bottom-color: #2C8160;} .js-irs-1 .irs-bar-edge {border-color: #2C8160;} + .js-irs-1 .irs-single, .js-irs-1 .irs-bar-edge, .js-irs-1 .irs-bar {background: #2C8160;}" + ) + ), + + tags$style( + HTML( + ".js-irs-2 .irs-bar {border-top-color: #2C8160; border-bottom-color: #2C8160;} .js-irs-2 .irs-bar-edge {border-color: #2C8160;} + .js-irs-2 .irs-single, .js-irs-2 .irs-bar-edge, .js-irs-2 .irs-bar {background: #2C8160;}" + ) + ), + + div( + style = "display:inline-block", + sliderInput( + "scaling_coordinates_pies", + "Scale the coordinates", + min = 1, + max = 10, + value = 1 + ) + ), + div( + style = "display:inline-block", + sliderInput( + "scaling_nodes_pies", + "Adjust node size:", + min = 10, + max = 30, + value = 15 + ) + ), + div( + style = "display:inline-block", + sliderInput( + "scaling_labels_pies", + "Adjust label size:", + min = 0, + max = 30, + value = 10, + step = 2 + ) + ), + + + hr(), + class = 'box-panel-padding', + class = 'box-panel', + + br(), + br(), + downloadBttn("HTML_pies", "Download HTML file", + style = "bordered", + color = "success", + size = "sm", + no_outline = T), + br(), + br() + + ), + + tabPanel( + "Convex Hulls - 3D", + helpText("Select the layout you want in the analysis."), + selectInput( + "layouts_3D", + "3D layout:", + choices = layouts_3D, + selected = selected_layouts_3d, + multiple = FALSE + ), + prettyCheckbox( + inputId = "Dark",outline = T,fill = T,bigger = T, + label = "Dark mode", + thick = TRUE, + shape = "curve", + animation = "pulse", + status = "info", + inline = F, + value = F + ), + prettyCheckbox( + inputId = "show_labels_3D",outline = T,fill = T,bigger = T, + label = "Show labels on network", + thick = TRUE, + shape = "curve", + animation = "pulse", + status = "info", + inline = F, + value = F + ), + prettyCheckbox( + inputId = "show_some_labels_3D",outline = T,fill = T,bigger = T, + label = "Show only labels of selected annotation groups", + thick = TRUE, + shape = "curve", + animation = "pulse", + status = "info", + inline = F, + value = F + ), + prettyCheckbox( + inputId = "expressions_3D",outline = T,fill = T,bigger = T, + label = "Show node - coloring", + thick = TRUE, + shape = "curve", + animation = "pulse", + status = "info", + inline = F, + value = F + ), + div(id="convex_hull_3D_loader", + shinycssloaders::withSpinner( + uiOutput("convex_hull_3D") + ) + ), + eval(ui_dataTable_panel("chooseGroups_3D")), + + tags$style( + HTML( + ".js-irs-0 .irs-bar {border-top-color: #2C8160; border-bottom-color: #2C8160;} .js-irs-0 .irs-bar-edge {border-color: #2C8160;} + .js-irs-0 .irs-single, .js-irs-0 .irs-bar-edge, .js-irs-0 .irs-bar {background: #2C8160;}" + ) + ), + + tags$style( + HTML( + ".js-irs-1 .irs-bar {border-top-color: #2C8160;border-bottom-color: #2C8160;} .js-irs-1 .irs-bar-edge {border-color: #2C8160;} + .js-irs-1 .irs-single, .js-irs-1 .irs-bar-edge, .js-irs-1 .irs-bar {background: #2C8160;}" + ) + ), + + tags$style( + HTML( + ".js-irs-2 .irs-bar {border-top-color: #2C8160; border-bottom-color: #2C8160;} .js-irs-2 .irs-bar-edge {border-color: #2C8160;} + .js-irs-2 .irs-single, .js-irs-2 .irs-bar-edge, .js-irs-2 .irs-bar {background: #2C8160;}" + ) + ), + div( + style = "display:inline-block", + sliderInput( + inputId = "scaling_coordinates_convex_3D_X", + label = "Scale x coordinates:", + min = 1, + max = 10, + value = 1 + ) + ), + div( + style = "display:inline-block", + sliderInput( + inputId = "scaling_coordinates_convex_3D_Y", + label = "Scale y coordinates:", + min = 1, + max = 10, + value = 1 + ) + ), + div( + style = "display:inline-block", + sliderInput( + inputId = "scaling_coordinates_convex_3D_Z", + label = "Scale z coordinates:", + min = 1, + max = 10, + value = 1 + ) + ), + + br(), + br(), + downloadBttn("HTML_convex_3D", "Download HTML file", + style = "bordered", + color = "success", + size = "sm", + no_outline = T), + br(), + br() + ), + + tabPanel("Venn Diagrams", + br(), + div(style = "display:inline-block",uiOutput("vennDiagram1")), + div(style = "display:inline-block",uiOutput("vennDiagram2")), + br(), + plotOutput("vennDiagrams",width = 600, height = 600), + div(style = "display:inline-block",eval(ui_dataTable_panel("venn_table1", FALSE))), + div(style = "display:inline-block",eval(ui_dataTable_panel("venn_table2", FALSE))), + div(style = "display:inline-block",eval(ui_dataTable_panel("venn_table_summ", FALSE))) + + ) + + ) #tabsetPanel + +) diff --git a/views/help.R b/views/help.R new file mode 100644 index 0000000..ff38b3f --- /dev/null +++ b/views/help.R @@ -0,0 +1,302 @@ +helpPage <- tabsetPanel( + tabPanel( "Input File", + br(), + strong("NORMA mainly accepts 3 different files as input:."), + br(), br(), + strong("The network file:"), + helpText( "It is an obligatory, 2-column (unweighted) or 3-column (weighted), tab-delimited file, containing all network connections of an undirected network. This file must contain headers, namely: 'Source' and 'Target' (and 'Weight' optionally). Notably, self-loops and multiple-edges are eliminated automatically." ), + strong("The annotation file:"), + helpText( " It is an obligatory, 2-column, tab-delimited file which contains information about the defined groups. The first column contains the group names whereas the second column contains the node names in a group separated by a comma (,) and without spaces. No headers are allowed."), + strong("The expression file:"), + helpText( "The expression file: It is an optional, 2-column, tab-delimited file which contains information about node coloring (e.g. gene expressions). The first column contains the node names and the second column the node colors (e.g. red, green, yellow, blue, orange, #00ff00, #ff0000, #ffff00). Nodes without color assignment will be colored gray. No headers are allowed in this file."), + helpText(" Examples are shown below:"), + pre( + " +Network File: Annotation File: Node-coloring file Warnings! + +Source Target Weight Group-2 BCL2L1,MDM4,MDM2,CHEK2 CDKN1A blue - Network file: Must have headers: Source - Target +CDKN1A TP53 5 Group-5 TP53,EP300 TP53 blue - Annotation file: no headers, no spaces only commas +TP53 MDM2 1 Group-1 CDKN2A,ATM,TP53BP2,MDM2 MDM4 #00ff00 (e.g. BCL2L1,MDM4,MDM2) +MDM4 TP53 3 Group-4 CHEK2,CREBBP,MDM2 BCL2L1 red +BCL2L1 TP53 4 Group-3 TP53,BCL2L1 CHEK2 red - Node-coloring file: no headers +CHEK2 ATM 2 Group-6 MDM4,MDM2 ATM red Colors can be either color names (e.g. blue, red) +TP53 EP300 1 TP53BP2 red or hex codes (#00ff00, #ff0000, #ffff00) +ATM TP53 4 CDKN2A blue +TP53 CREBBP 1 EP300 #ffff00 +MDM4 MDM2 1 CREBBP red +CHEK2 TP53 2 MDM2 blue +TP53BP2 TP53 8 +CDKN2A TP53 3 +CDKN2A MDM2 3 +ATM MDM2 1 +EP300 CREBBP 2 + . . . + . . . + . . . +" + ), + + strong("Usage:"), + helpText( "Users can upload as many network and annotation files as they like. Every time a network or an annotation file is uploaded, a name can be given first. + Once a network or an annotation file has been named and uploaded, it will appear as an option in any of the NORMA's dropdown selection lists. Users can remove indifferent annotations or networks at any time."), + br(), br(), + strong("Troubleshooting:"), + helpText("Nodes referenced in the annotation file must comply with nodes referenced in the network file. If a node in the annotation does not appear in the network file, NORMA won't be able to process the files and produce a proper visualization. To address this problem, we have implemented an R script which accepts a network file and an annotation file as inputs and generates a corrected annotation output file. In this output file, node names in annotations which do not appear in the network file are discarded. Notably, node names in both files must not contain any commas (,)."), + br(), + downloadLink('R_script', "Download R script here"), + br(), + helpText(tags$ul( + tags$li("Install R / Rstudio"), + tags$li("Open the file with Rstudio"), + tags$li("Run the file"), + tags$li("The output will be written in a new file named 'annotations_cleaned.txt'. ") + )), + br(), br() + ), #Tabpanel Input File + + tabPanel( + "EXAMPLES", + br(), + strong("STRING example 1 (TP53 interactors):"), + br(), + downloadLink('string_net_tp53', "STRING Network file"), + br(), + downloadLink('string_annot', "STRING Annotation file"), + br(), + downloadLink('string_expr', "STRING Expression file"), + br(), hr(), br(), + strong("STRING example 2 (BCAR3 interactors):"), + br(), + downloadLink('string_net_bcar3', "STRING Network file"), + br(), + downloadLink('string_bp', "GO Annotation - Biological Process"), + br(), + downloadLink('string_mf', "GO Annotation - Molecular Function"), + br(), + downloadLink('string_kegg', "KEGG pathways"), + br(), hr(), br(), + strong("Drosophila (Tau) Network (PMID:31488613, PMCID:PMC6794924, DOI:10.1523/JNEUROSCI.0391-19.2019):"), + br(), + downloadLink('dros_net', "Drosophila Network file"), + br(), + downloadLink('dros_annot', "Drosophila Kegg pathways"), + br(), + downloadLink('dros_louvain', "Drosophila Louvain automated annotation file"), + br(), + downloadLink('dros_express', "Drosophila Expression file"), + br(), hr(), br(), + strong("Human Gene Co-expression Network (PMID:19081792, PMCID:PMC2597745, DOI:10.1371/journal.pone.0003911):"), + helpText("http://bioinfow.dep.usal.es/coexpression/"), + br(), + downloadLink('co_express', "Gene Co-expression Network"), + br(), + downloadLink('co_express_bp', "GO Annotation - Biological Process"), + br(), + downloadLink('co_express_mf', "GO Annotation - Molecular Function"), + br(), + downloadLink('co_express_cc', "GO Annotation - Cellular Components"), + br(), + downloadLink('co_express_kegg', "KEGG pathways"), + br(), + downloadLink('co_express_mcode', "MCODE Node coloring"), + br(), hr(), br(), + strong("COVID-19:"), + helpText("Intact Database"), + br(), + downloadLink('covid_19_net', "COVID-19 Network"), + br(), + downloadLink('covid_19_interpro', "HomoSapiens Protein Domains - INTERPRO"), + br(), + downloadLink('covid_19_bp', "HomoSapiens GO Annotation - Biological Process"), + br(), + downloadLink('covid_19_mf', "HomoSapiens GO Annotation - Molecular Function"), + br(), + downloadLink('covid_19_cc', "HomoSapiens Protein Domains GO Annotation - Cellular Components"), + br(), + downloadLink('covid_19_kegg', "HomoSapiens Protein Domains KEGG pathways"), + br(), + downloadLink('covid_19_smart', "HomoSapiens Protein Domains SMART"), + br(), hr(), br(), + strong("Gallus gallus:"), + helpText("BioGrid Database"), + br(), + downloadLink('Gallus_gallus_net', "Gallus gallus Network"), + br(), + downloadLink('Gallus_gallus_kegg', "BioGrid Gallus gallus KEGG pathways"), + br(), br() + ), + + tabPanel( + "The Upload Tab", + br(), + helpText( + "Once one or more network and annotation files have been named and uploaded, they will appear as options in the dropdown selection lists. Users can select a network or an annotation file at a time and see its content as an interactive table. Notably, one can search by suffix in the table, using the Search field. " + ), + tags$img(src = b64_2), + tags$img(src = b64_3), + tags$img(src = b64_4), + br(), br() + ), #Tabpanel Upload + + tabPanel( + "The Network Tab", + br(), + strong( + "This Tab consists of two sub-tabs dedicated to network analysis and visualization. These are: (i) the Interactive Network and the (ii) the Automated Community Detection." + ), + br(), br(), + strong("Interactive Network:"), + helpText( + "This Tab offers a dynamic network visualization in its simplest form. Nodes are connected with undirected edges and their coordinates are calculated using a force-directed layout. The network is fully interactive as zooming, dragging and panning are allowed either by using the mouse or the navigation buttons. In addition, nodes can be selected and dragged anywhere on the plane, whereas the first neighbors of any node can be highlighted upon selection. Finally, the network view is automatically updated when a different network is selected." + ), + br(), + tags$img(src = b64_5), + br(), br(), + strong("Automated Community Detection:"), + helpText( + "This Tab is used for the automatic calculation of communities whereas the exported file(s) can be used as input annotation file(s). Users can assign nodes to communities (not necessarily uniquely), using various options. These are:" + ), + helpText(tags$ul( + # tags$li( "Fast-Greedy: This function tries to find densely connected subgraphs (also called communities) via directly optimizing a modularity score."), + tags$li( "Louvain: This function implements a multi-level modularity optimization algorithm for finding community structures and is based on the modularity measure and a hierarchical approach."), + tags$li( "Label-Propagation: This is a fast, nearly linear time algorithm for detecting community structures in a network by labeling the vertices with unique labels and then updating the labels by majority voting in the neighborhood of the vertex."), + tags$li( "Walktrap: This function tries to find densely connected subgraphs in a graph via random walks. The idea is that short random walks tend to stay in the same community."), + tags$li( "Betweenness: Many networks consist of modules which are densely connected between themselves but sparsely connected to other modules. Clustering is made by 'breaking' the bridges which connect densely connected regions."), + )), + br(), + tags$img(src = b64_6), + br(), + br(), + helpText( "Once a community detection method has been selected, users can see the results as interactive and searchable tables or as static plots for an at-a-glance view. In order for users to take advantage of NORMA's advanced interactive visualization capabilities, the automatically generated annotations must be first exported and then imported as annotation input files.") + + ), #Tabpanel Network + + tabPanel( + "The Annotations Tab", + br(), + strong( "This Tab is NORMA's strongest feature and is used to visualize annotated networks in an easy and user-friendly way. Annotated, are the networks with (pre-)defined clusters, communities, subgraphs, marked regions or neighborhoods. + Through the Annotation Tab, users can select between any of the uploaded networks or annotation files and visualize them in combination. Network and Annotation selections can be done by the offered dropdown selection lists. + The Annotation Tab consists of three sub-tabs. These are the: (i) Convex Hull, (ii) Pie-chart nodes and (iii) Venn diagrams." + ), + br(), br(), + strong("Convex Hulls:"), + helpText( "In this tab, the selected network is initially visualized after applying any of the offered layout algorithms and shaded convex hulls are then used to highlight communities in a Venn-diagram-like view. A node might belong to more than one group. In this case, NORMA tries to bring closer together the overlapping regions which share common nodes while simultaneously it tries to keep the distinct groups apart. Groups are highlighted using visually distinct colors, whereas transparency is used to efficiently highlight the overlapping regions."), + br(), + tags$img(src = b64_7), + br(), br(), + strong("Pie-chart nodes:"), + helpText( "In this Tab, the selected network is initially visualized after applying any of the offered layout algorithms and nodes are then visualized as pie-charts, divided into slices to illustrate the groups a node belongs to. If a node for example belongs to four groups, then the pie chart will consist of four equal slices colored with distinct colors. Nodes which do not belong to any group are marked gray."), + br(), + tags$img(src = b64_8), + br(), br(), + + strong("Convex Hulls 3D:"), + helpText( "Like in 2D Convex Hulls, in this tab, the selected network is initially visualized after applying any of the offered 3D layout algorithms and 3D shaded convex hulls are then used to highlight communities in a 3D Venn-diagram-like view. The visualization is fully interactive and a dark mode visualization is also supported."), + br(), + tags$img(src = b64_3D_convex), + br(), br(), + strong("Node coloring:"), + helpText( "Often, one might want to assign certain colors to nodes in order to encode certain information. In a gene expression network for example, one might want to highlight the up- and down-regulated genes. Once an expression file has been loaded (see Input file section), nodes in the Convex Hull will be filled with the color of interest whereas nodes in the Pie-Chart tab will appear with a colored border. As node coloring is an optional feature, one can enable or disable this functionality at any time (selection box)."), + br(), + tags$img(src = b64_9), + br(), br(), + strong("Layouts:"), + helpText( "Several layouts are offered for network visualization in both Convex Hull and Pie Chart sub-tabs. These are:"), + helpText( + tags$ul( + tags$li( "Fruchterman-Reingold: It places nodes on the plane using the force-directed layout algorithm developed by Fruchterman and Reingold."), + tags$li( "Random: This function places the vertices of the graph on a 2D plane uniformly using random coordinates."), + tags$li( "Circle: It places vertices on a circle, ordered by their vertex ids."), + tags$li( "Kamada-Kawai: This layout places the vertices on a 2D plane by simulating a physical model of springs."), + tags$li( "Reingold-Tilford: This is a tree-like layout and is suitable for trees or graphs without many cycles."), + tags$li( "LGL: A force directed layout suitable for larger graphs."), + tags$li( "Graphopt: A force-directed layout algorithm, which scales relatively well to large graphs."), + tags$li( "Gem: It places vertices on the plane using the GEM force-directed layout algorithm."), + tags$li( "Star: It places vertices of a graph on the plane, according to the simulated annealing algorithm by Davidson and Harel."), + tags$li("Grid: This layout places vertices on a rectangular 2D grid.") + ), + helpText("NOTE: NORMA provides the option to slightly modify the selected layout in order to make groups as distinct as possible, thus avoiding unecessary overlaps which may occur due to the original layout.") + ), + br(), + strong("Interactivity and Visualization:"), + helpText( + "NORMA gives a variety of options for the creation of optimal custom views. Network zoom in/out and panning functionalities are offered while users can interactively drag any node and place it anywhere on the plane. In addition to the visualized networks, groups are shown in an interactive table whose rows are colored accordingly. By selecting one or more groups, one can adjust the convex hulls as well as the pie-chart nodes accordingly. Colored groups (rows) in the table correspond to colored groups in the offered views and vice versa. In addition, users have the option to show and hide the labels or only keep the labels of the selected groups of interest while labels below a certain zoom level are hidden for clarity. Finally, sliders to adjust node and label sizes as well as a slider to scale the network size are offered." + ), + br(), + strong("Venn Diagrams:"), + helpText("Users are allowed to choose any pair of nodes and visualize the common groups they belong to as a Venn diagram. As it is not in the scope of NORMA to provide more complex Venn diagrams, users are encouraged to visit other online applications dedicated to this purpose. "), + tags$img(src = b64_12) + + ), #Tabpanel Annotations + + + + + tabPanel( + "Layout Strategies", + br(), + helpText( + "Users are allowed to choose between three different strategies to visually separate annotated areas of interest in a network in combination with established layout algorithms. + " + ), + br(), + br(), + strong("Strategy 1 - Virtual nodes:"), + helpText( + "As in the original version, NORMA-2.0 introduces one virtual node per group which behaves as a hub. Upon creation, edges with heavy weights are assigned to this node, linking it with all nodes from the same group. Then, any traditional layout algorithm can be utilized until it converges. The difference compared to directly applying a layout algorithm on the network is that the virtual nodes will attract the group-specific nodes as if they were parts of the network. After completing the layout execution, all virtual nodes are removed." + ), + tags$img(src = b64_strategy1, class="layout_strat_img"), + br(), + br(), + strong("Strategy 2 - Gravity:"), + helpText( + "Here, NORMA-2.0 introduces intra-group edges where necessary to generate clique-like subnetworks (all-vs-all connections). As a second step, the intra-group edge weights are significantly increased whereas the inter-group edge weights are simultaneously decreased. Then, any of the offered layouts can be applied to adjust node coordinates. The introduced edges and weights only exist for the calculation of the layout coordinates, and do not carry over to the final visualized network. + "), + tags$img(src = b64_strategy2, class="layout_strat_img"), + br(), + br(), + strong("Strategy 3 - Super nodes:"), + helpText( + "In this scenario, NORMA-2.0 introduces 'super-nodes' to represent each of the uploaded annotation groups. Then, it connects these groups with edges which correspond to the connections from the initial network. For example, if node A belonging to the annotation group 1 is connected to node B from group 2, then the group 1 super-node will also be connected to the group 2 super-node. Notably, the network becomes significantly smaller both in terms of node and connection numbers. In a second step, any of the available layouts can be applied on the 'super-network'. Upon layout convergence, all centroid coordinates of these super-nodes as well as the coordinates of no-group nodes can be further repelled according to a user-defined input. Then, all initial nodes will be placed around their respective super-nodes according to a second user-selected local layout choice. If a node belongs to more than one group, the average values for their (x, y) coordinates are used for the final visualization. + "), + tags$img(src = b64_strategy3, class="layout_strat_img"), + br(), br() + ), #Tabpanel Layout Strategies + + + tabPanel( + "The Topology Tab", + br(), + strong( + "This Tab is used for automated topological analysis and direct comparison of topological features between two or more networks." + ), + helpText("The topological features are: "), + helpText( + tags$ul( + tags$li( "Number of Edges: Shows the number of edges in the network. NORMA accepts networks with less than 10000 edges." ), + tags$li( "Number of Nodes: Shows the number of nodes in the network." ), + tags$li( "Density: The density of a graph is the ratio of the number of edges and the number of possible edges." ), + tags$li( "Average path length: The average number of steps needed to go from one node to another." ), + tags$li( "Clustering Coefficient: A metric which shows if the network has the tendency to form clusters. Values between 0 and 1." ), + tags$li( "Modularity: This function calculates how modular is a given division of a graph into subgraphs." ), + tags$li( "Average Eccentricity: The distance from a particular vertex to all other vertices in the graph is taken and among those distances, the eccentricity is the highest of distances." ), + tags$li( "Average number of Neighbors: It is the total number of neighbors per node divided by the number of nodes." ), + tags$li( "Centralization betweenness: It is an indicator of a node's centrality in a network. It is equal to the number of shortest paths from all vertices to all others that pass through that node. Betweenness centrality quantifies the number of times a node acts as a bridge along the shortest path between two other nodes." ), + tags$li( "Centralization degree: It is defined as the number of links incident upon a node." ) + ) + ), + br(), + strong( "The Topology Tab is divided into two sub-tabs. These are: (i) the Summaries and (ii) the Comparative Plots." ), + br(), + strong("Summaries:"), + helpText( "This Tab shows the aforementioned topological measures in a numerical form as a table view. Users can select one or more features of interest through the offered checkboxes and show them accordingly. Notably, this can be done for one network at a time upon selection (dropdown selection list)." ), + br(), + tags$img(src = b64_10), + br(), + strong("Comparative Plots:"), + helpText( "This Tab can be used to directly compare the topological features of two or more networks simultaneously. In contrast to the previous Tab, users are allowed to select one topological feature at a time (radio buttons) but as many networks as they like (check boxes). Once two or more networks and one topological feature have been selected, direct comparisons can be made by the generated bar charts. A slider to adjust the chart height is offered." ), + tags$img(src = b64_11), + br() + + ) #Tabpanel Topology +) #tabsetPanel diff --git a/views/network.R b/views/network.R new file mode 100644 index 0000000..87f56f4 --- /dev/null +++ b/views/network.R @@ -0,0 +1,45 @@ +networkPage <- div(id = "network_div", + conditionalPanel( + condition = "input.availableNetworks == 0", + bsAlert("tabUploadMainAlert"), + uiOutput("uiLoadGraphOptionsOutput_just_network") + ), + br(), br(), + tabsetPanel( + tabPanel( + "Interactive Network", + visNetworkOutput('tabVizIgraphSimple', width = 1000, height = 550), + class = 'box-panel-padding', + + class = 'box-panel', + ), + + tabPanel( + "Automated Community Detection", + br(), + selectInput( + "automated_annotations", + "Community Detection Algorithms:", + choices = automated_annotations_ui, + selected = selected_automated_annotations, + multiple = FALSE + ), + downloadButton("downloadData", "Export as annotation file", icon("download")), + br(), + br(), + prettyCheckbox( + inputId = "show_labels_algorithms_tab",outline = T,fill = T,bigger = T, + label = "Show Labels", + thick = T, + shape = "curve", + animation = "pulse", + status = "info", + inline = F, + value = F + ), + plotOutput("modularity_plot", width = 1000, height = 600), + eval(ui_dataTable_panel('Modularity_table')), + br() + ) + ) #tabsetPanel +) diff --git a/views/topology.R b/views/topology.R new file mode 100644 index 0000000..b7744dd --- /dev/null +++ b/views/topology.R @@ -0,0 +1,82 @@ +topologyPage <- div(id = "topology_div", + sidebarLayout( + sidebarPanel( + bsAlert("tabTopologySideAlert"), + conditionalPanel(condition = "input.statisticsMethodsMainTabsetPanel == 'tableView'", + uiOutput("uiStoredGraphsOutputSelectTopolopgy")), + conditionalPanel( + condition = "input.statisticsMethodsMainTabsetPanel == 'plotView'", + uiOutput("uiStoredGraphsOutputMultipleSelectTopolopgy") + ), + ), + conditionalPanel(condition = "input.availableNetworks == 0", + mainPanel( + bsAlert("tabTopologyMainAlert"), + tabsetPanel( + id = "statisticsMethodsMainTabsetPanel", + tabPanel( + "Summaries", + value = "tableView", + icon = icon("table"), + div( + div( + checkboxGroupInput( + "statistics2", + "The statistics:", + choices = statistics, + selected = selected_statistics + ), + eval(ui_dataTable_panel("statres", FALSE)), + class = 'box-panel-padding', + class = 'box-panel' + ), + div( + span( + actionButton("btnStatSelectAll", "Select all", style = "float: right;"), + class = "input-group-btn" + ), + span(actionButton("btnStatSelectNone", "Clear"), class = "input-group-btn"), + class = "input-group" + ) + ) + ), + tabPanel( + "Comparative Plots", + value = "plotView", + icon = icon("chart-bar"), + div( + div( + radioButtons( + "statistics", + "The statistics:", + choices = statistics, + selected = selected_statistics + ), + uiOutput("statisticsMethodsPlotRender"), + class = 'box-panel-padding' + ), + class = 'box-panel' + ), + tags$style( + HTML( + ".js-irs-6 .irs-bar {border-top-color: #2C8160; border-bottom-color: #2C8160;} .js-irs-6 .irs-bar-edge {border-color: #2C8160;} + .js-irs-6 .irs-single, .js-irs-6 .irs-bar-edge, .js-irs-6 .irs-bar {background: #2C8160;}" + ) + ), + + sliderInput( + "statisticsPlotPercentMagnify", + "Adjust plot height (% taller)", + min = 0, + max = 100, + value = 0 + ), + span( + actionButton("btnRefreshPalette", "Refresh palette", icon = icon("sync")) + ) + ) + + ) + )) + ) +) diff --git a/views/upload.R b/views/upload.R new file mode 100644 index 0000000..2c39804 --- /dev/null +++ b/views/upload.R @@ -0,0 +1,169 @@ +uploadPage <- div(id = "upload_div", + sidebarLayout( + + # sidebarPanel #### + sidebarPanel( + actionButton("introButton", "Guide Tutorial"), + br(), + hr(), + tags$div(class="network_div", + tags$h3('1. Networks'), + selectInput( + "uiLoadGraphOptionsInput", + "Choose Network(s)", + c( + "File upload" = "oF", + "Example STRING BCAR3 Network" = "oR_String_interactions", + "Example Drosophila TAU Network" = "oR_Drosophila" + ) + )%>% + shinyInput_label_embed( + shiny_iconlink() %>% + bs_embed_popover( + title = paste0("Please follow the steps below: +- Load your network file in tab delimited format +- Give it a name +- Hit the ADD button") + ) + ), + uiOutput("uiLoadGraphOptionsOutput"), + # checkboxInput("weighted",label = "Weight", value =F), + div( + span( + actionButton( + "btnAddNetwork", + "ADD", + icon = icon("plus"), + style = "color: #fff; background-color: #7F461B; border-color: #7F461B" + ), + class = "input-group-btn" + ), + tags$input( + id = "networkName", + type = "text", + class = "form-control", + placeholder = "Type network name ..", + value = "Network name" + ), + class = "input-group" + ), + uiOutput("uiStoredGraphsOutputRadio") + ), + hr(), + tags$div(class="annotations_div", + tags$h3('2. Annotations'), + ######2nd button-annotation + selectInput( + "uiLoadGraphOptionsInput_annotations", + "Choose Annotation(s)", + c( + "File upload" = "oF", + "Example BCAR3 STRING GO KEGG" = "oR_String_Annotation_KEGG", + "Example BCAR3 STRING GO MF" = "oR_String_Annotation_MF", + "Example BCAR3 STRING GO BP" = "oR_String_Annotation_BP", + "Example TAU Drosophila KEGG" = "oR_Drosophila_KEGG", + "Example TAU Drosophila Louvain" = "oR_Drosophila_Luvain" + ) + )%>% + shinyInput_label_embed( + shiny_iconlink() %>% + bs_embed_popover( + title = paste0("Please follow the steps below: +- Load your annotation file in tab delimited format +- Give it a name +- Hit the ADD button") + ) + ), + uiOutput("uiLoadGraphOptionsOutput_annotations"), + div( + span( + actionButton( + "btnAddNetwork2", + "ADD", + icon = icon("plus"), + style = "color: #fff; background-color: #8D4A43; border-color: #8D4A43" + ), + class = "input-group-btn" + ), + tags$input( + id = "annotationName", + type = "text", + class = "form-control", + placeholder = "Type annotation name ..", + value = "Annotation name" + ), + class = "input-group" + ), + uiOutput("uiStoredGraphsOutputRadio_annotations") + ), + hr(), + tags$div(class="expressions_div", + ######3rd button-expression + tags$h3('3. Node-coloring'), + selectInput( + "uiLoadExpressionsInput", + "Choose node - coloring file(s)", + c("File upload" = "oF", + # "Expression_file_STRING" = "oR_Expression_file_STRING", + "Example TAU Drosophila node - coloring file" = "oR_Expression_file_Drosophila" + ) + )%>% + shinyInput_label_embed( + shiny_iconlink() %>% + bs_embed_popover( + title = paste0("Please follow the steps below: +- Load your node - coloring file in tab delimited format +- Give it a name +- Hit the ADD button") + ) + ), + uiOutput("uiLoadExpressionsOutput"), + div( + span( + actionButton( + "btnAddExpression", + "ADD", + icon = icon("plus"), + style = "color: #fff; background-color: #B89778; border-color: #B89778" + ), + class = "input-group-btn" + ), + tags$input( + id = "expressionName", + type = "text", + class = "form-control", + placeholder = "Type expression name ..", + value = "Node - coloring file name" + ), + class = "input-group" + ), + uiOutput("uiStoredGraphsOutputRadioEx") + ) + ), #sidebarPanel + + # mainPanel #### + mainPanel( + conditionalPanel( + condition = "input.availableNetworks == 0", + uiOutput("uiStoredGraphsOutputSelectUpload") + ), + + conditionalPanel( + condition = "input.availableAnnotations == 0", + uiOutput("uiStoredGraphsOutputSelectUpload2") + ), + tabsetPanel( + tabPanel( + "Table View of Network(s)", + icon = icon("table"), + eval(ui_dataTable_panel('datasettab1')) + ), + tabPanel( + "Table View of Annotation(s)", + icon = icon("table"), + eval(ui_dataTable_panel('datasettab2')) + ) + ) #tabsetPanel + ) # mainPanel + ) # sidebarLayout +) diff --git a/views/welcome.R b/views/welcome.R new file mode 100644 index 0000000..4f69e7a --- /dev/null +++ b/views/welcome.R @@ -0,0 +1,24 @@ +welcomePage <- div(id = "welcome_div", + h1("Welcome to NORMA, the NetwORk Makeup Artist"), + strong("a tool that enables the visualization of annotation groups."), + br(), + br(), + helpText( + "NORMA is a handy tool for interactive network annotation, visualization and topological analysis, + able to handle multiple networks and annotations simultaneously. Annotations and/or node groups can + be precomputed or automatically calculated and users can combine several networks and groupings they + are interested in. Annotated networks can be visualized using both pie-chart nodes and shaded convex + hulls and can be shown using several layouts while users can isolate the groups of interest interactively. + In addition, NORMA is suitable for direct comparison of topological features between one or more networks. + In order for NORMA to run, two simple steps are required:" + ), + tags$ul( + tags$li("1. Please load your network file(s), name it and hit the add button"), + tags$li( + "2. Please load your annotation file(s), name it and hit the add button" + ) + ), + tags$ul( + "Input file instructions as well as downloadable examples can be found in the HELP/EXAMPLES page." + ) +) diff --git a/www/Examples/BCAR3/BCAR3.txt b/www/Examples/BCAR3/BCAR3.txt new file mode 100644 index 0000000..6d04212 --- /dev/null +++ b/www/Examples/BCAR3/BCAR3.txt @@ -0,0 +1,92 @@ +Source Target +VCP NPLOC4 +BCAR1 PXN +VCP DERL2 +NSFL1C VCP +CDC42 WASL +VCP DERL1 +NPLOC4 UFD1L +SYVN1 VCP +VCP UFD1L +CDC42 WAS +CDC42 PAK1 +CDC42 BAIAP2 +VCP FAF2 +CDC42 ARHGAP1 +VIMP VCP +CDC42 PARD6A +CDC42 TNK2 +CDC42 ITSN1 +CDC42 ARHGDIA +CDC42 PARD6B +SYVN1 DERL2 +CDC42 PAK2 +VIMP DERL1 +DERL1 DERL2 +WAS BAIAP2 +CDC42 PXN +FAF2 DERL2 +SYVN1 DERL1 +UFD1L FAF2 +NPLOC4 FAF2 +BCAR1 BCAR3 +ITSN1 WASL +BAIAP2 WASL +BCAR1 TNK2 +BCAR1 CDC42 +PAK1 PXN +PAK1 ARHGDIA +FAF2 DERL1 +NEDD9 PXN +PAK2 PAK1 +VIMP DERL2 +SYVN1 FAF2 +VIMP SYVN1 +CDC42 BCAR3 +UFD1L DERL1 +PAK2 PXN +NSFL1C UFD1L +NEDD9 BCAR3 +PARD6B PARD6A +BAIAP2 PXN +NSFL1C NPLOC4 +BCAR1 BAIAP2 +PAK2 PARD6A +SYVN1 UFD1L +WAS WASL +TULP4 SPSB1 +SYVN1 NPLOC4 +VIMP FAF2 +UFD1L DERL2 +NPLOC4 DERL1 +NPLOC4 DERL2 +ITSN1 WAS +VIMP NPLOC4 +TNK2 WAS +NSFL1C FAF2 +TULP4 KCNE4 +BCAR3 TULP4 +BCAR3 KCNE4 +NSFL1C DERL2 +SAT1 BCAR3 +NSFL1C DERL1 +BCAR3 VCP +PAK2 ARHGDIA +KCNE4 TULP1 +BCAR3 TULP1 +PXN WASL +VIMP UFD1L +WAS ARHGAP1 +WAS PXN +WAS PAK1 +BCAR3 SPSB1 +ARHGAP1 ARHGDIA +BCAR1 PARD6A +PAK1 WASL +BCAR1 WASL +ARHGDIA PXN +BCAR1 WAS +PAK2 WASL +WAS PAK2 +ARHGAP1 PXN +ARHGDIA WASL \ No newline at end of file diff --git a/www/Examples/BCAR3/BCAR3_GO_BP.txt b/www/Examples/BCAR3/BCAR3_GO_BP.txt new file mode 100644 index 0000000..a068ffe --- /dev/null +++ b/www/Examples/BCAR3/BCAR3_GO_BP.txt @@ -0,0 +1,99 @@ +cellular process ARHGAP1,ARHGDIA,BAIAP2,BCAR1,BCAR3,CDC42,DERL1,DERL2,FAF2,ITSN1,KCNE4,NEDD9,NPLOC4,NSFL1C,PAK1,PAK2,PARD6A,PARD6B,PXN,SAT1,SPSB1,SYVN1,TNK2,TULP1,TULP4,UFD1L,VCP,VIMP,WAS,WASL +biological regulation ARHGAP1,ARHGDIA,BAIAP2,BCAR1,BCAR3,CDC42,DERL1,DERL2,FAF2,ITSN1,KCNE4,NEDD9,NPLOC4,NSFL1C,PAK1,PAK2,PARD6A,PARD6B,PXN,SAT1,SYVN1,TNK2,TULP1,UFD1L,VCP,VIMP,WAS,WASL +regulation of biological process ARHGAP1,ARHGDIA,BAIAP2,BCAR1,BCAR3,CDC42,DERL1,DERL2,ITSN1,KCNE4,NEDD9,NPLOC4,NSFL1C,PAK1,PAK2,PARD6A,PARD6B,PXN,SAT1,SYVN1,TNK2,TULP1,UFD1L,VCP,VIMP,WAS,WASL +regulation of cellular process ARHGAP1,ARHGDIA,BAIAP2,BCAR1,BCAR3,CDC42,DERL1,DERL2,ITSN1,NEDD9,NPLOC4,NSFL1C,PAK1,PAK2,PARD6A,PARD6B,PXN,SAT1,SYVN1,TNK2,TULP1,UFD1L,VCP,VIMP,WAS,WASL +response to stimulus ARHGAP1,ARHGDIA,BAIAP2,BCAR1,BCAR3,CDC42,DERL1,DERL2,FAF2,ITSN1,NEDD9,NPLOC4,PAK1,PAK2,PARD6A,PXN,SYVN1,TNK2,TULP1,UFD1L,VCP,VIMP,WAS,WASL +localization ARHGAP1,BAIAP2,BCAR1,CDC42,DERL1,DERL2,FAF2,ITSN1,KCNE4,NPLOC4,NSFL1C,PAK1,PAK2,PXN,SYVN1,TNK2,TULP1,TULP4,UFD1L,VCP,VIMP,WAS,WASL +cellular response to stimulus ARHGAP1,ARHGDIA,BAIAP2,BCAR1,BCAR3,CDC42,DERL1,DERL2,FAF2,ITSN1,NEDD9,NPLOC4,PAK1,PAK2,PARD6A,PXN,SYVN1,TNK2,UFD1L,VCP,VIMP,WAS,WASL +signal transduction ARHGAP1,ARHGDIA,BAIAP2,BCAR1,BCAR3,CDC42,DERL1,DERL2,ITSN1,NEDD9,PAK1,PAK2,PARD6A,PXN,SYVN1,TNK2,VCP,VIMP,WAS,WASL +establishment of localization ARHGAP1,BAIAP2,CDC42,DERL1,DERL2,FAF2,ITSN1,KCNE4,NPLOC4,NSFL1C,PAK1,SYVN1,TNK2,TULP1,UFD1L,VCP,VIMP,WAS,WASL +positive regulation of biological process ARHGAP1,ARHGDIA,BAIAP2,BCAR1,BCAR3,CDC42,DERL1,DERL2,ITSN1,NSFL1C,PAK1,PAK2,PARD6A,PXN,TNK2,TULP1,VCP,WAS,WASL +regulation of response to stimulus ARHGAP1,ARHGDIA,BAIAP2,BCAR1,BCAR3,CDC42,DERL2,ITSN1,NPLOC4,PAK1,PAK2,PXN,SYVN1,UFD1L,VCP,VIMP,WAS,WASL +transport ARHGAP1,BAIAP2,CDC42,DERL1,DERL2,FAF2,ITSN1,KCNE4,NPLOC4,PAK1,SYVN1,TNK2,TULP1,UFD1L,VCP,VIMP,WAS,WASL +positive regulation of cellular process ARHGAP1,ARHGDIA,BAIAP2,BCAR1,BCAR3,CDC42,DERL1,DERL2,ITSN1,NSFL1C,PAK1,PAK2,PXN,TNK2,TULP1,VCP,WAS,WASL +cellular component organization BAIAP2,BCAR1,CDC42,DERL1,FAF2,ITSN1,NEDD9,NPLOC4,NSFL1C,PAK1,PAK2,PARD6A,PARD6B,PXN,TULP1,VCP,WAS,WASL +response to chemical BAIAP2,BCAR1,BCAR3,CDC42,DERL1,DERL2,FAF2,NPLOC4,PAK1,PAK2,PARD6A,PXN,SYVN1,UFD1L,VCP,VIMP,WAS +cellular localization ARHGAP1,CDC42,DERL1,DERL2,FAF2,ITSN1,NPLOC4,NSFL1C,SYVN1,TULP1,TULP4,UFD1L,VCP,VIMP,WAS,WASL +response to organic substance BAIAP2,BCAR1,CDC42,DERL1,DERL2,FAF2,NPLOC4,PAK1,PAK2,PARD6A,PXN,SYVN1,UFD1L,VCP,VIMP,WAS +negative regulation of biological process ARHGAP1,ARHGDIA,CDC42,DERL2,ITSN1,NPLOC4,NSFL1C,PAK1,PAK2,PARD6A,SYVN1,TNK2,UFD1L,VIMP,WAS,WASL +organonitrogen compound metabolic process CDC42,DERL1,DERL2,FAF2,NPLOC4,NSFL1C,PAK1,PAK2,SAT1,SPSB1,SYVN1,TNK2,TULP4,UFD1L,VCP,VIMP +cellular protein metabolic process CDC42,DERL1,DERL2,FAF2,NPLOC4,NSFL1C,PAK1,PAK2,SPSB1,SYVN1,TNK2,TULP4,UFD1L,VCP,VIMP +establishment of localization in cell ARHGAP1,CDC42,DERL1,DERL2,FAF2,ITSN1,NPLOC4,NSFL1C,SYVN1,UFD1L,VCP,VIMP,WAS,WASL +cellular response to organic substance BAIAP2,BCAR1,CDC42,DERL1,DERL2,PAK1,PAK2,PARD6A,PXN,SYVN1,UFD1L,VCP,VIMP,WAS +regulation of signal transduction ARHGAP1,ARHGDIA,BAIAP2,BCAR3,CDC42,ITSN1,NPLOC4,PAK1,PAK2,PXN,SYVN1,UFD1L,VCP,VIMP +response to stress CDC42,DERL1,DERL2,FAF2,NPLOC4,PAK1,PAK2,PXN,SYVN1,TNK2,UFD1L,VCP,VIMP,WAS +negative regulation of cellular process ARHGAP1,ARHGDIA,CDC42,DERL2,ITSN1,NPLOC4,PAK1,PAK2,PARD6A,SYVN1,UFD1L,VIMP,WAS,WASL +protein localization ARHGAP1,BAIAP2,DERL1,DERL2,FAF2,NPLOC4,SYVN1,TULP1,TULP4,UFD1L,VCP,VIMP,WASL +cell surface receptor signaling pathway ARHGDIA,BAIAP2,BCAR1,CDC42,ITSN1,NEDD9,PAK1,PAK2,PARD6A,PXN,TNK2,WAS,WASL +regulation of cellular component organization ARHGDIA,BAIAP2,BCAR1,CDC42,DERL2,NSFL1C,PAK1,PXN,TNK2,TULP1,VCP,WAS,WASL +regulation of localization ARHGAP1,BCAR1,DERL2,KCNE4,NSFL1C,PAK1,PARD6A,PARD6B,TNK2,TULP1,VIMP,WAS,WASL +regulation of molecular function ARHGAP1,ARHGDIA,BCAR3,DERL1,FAF2,ITSN1,NSFL1C,PAK1,PAK2,TNK2,VCP,WAS,WASL +response to organonitrogen compound BAIAP2,BCAR1,DERL1,DERL2,FAF2,NPLOC4,PAK1,PXN,SYVN1,UFD1L,VCP,VIMP +intracellular transport ARHGAP1,CDC42,DERL1,DERL2,FAF2,NPLOC4,SYVN1,UFD1L,VCP,VIMP,WAS,WASL +cellular protein modification process CDC42,DERL1,DERL2,PAK1,PAK2,SPSB1,SYVN1,TNK2,TULP4,UFD1L,VCP,VIMP +organelle organization BAIAP2,BCAR1,CDC42,FAF2,NEDD9,NPLOC4,NSFL1C,PAK1,PAK2,PARD6A,WAS,WASL +cellular protein localization DERL1,DERL2,FAF2,NPLOC4,SYVN1,TULP1,TULP4,UFD1L,VCP,VIMP,WASL +vesicle-mediated transport ARHGAP1,BAIAP2,CDC42,FAF2,ITSN1,PAK1,TNK2,TULP1,VCP,WAS,WASL +positive regulation of response to stimulus ARHGAP1,BAIAP2,BCAR1,BCAR3,CDC42,ITSN1,PAK1,PAK2,VCP,WAS,WASL +regulation of catalytic activity ARHGAP1,ARHGDIA,FAF2,ITSN1,NSFL1C,PAK1,PAK2,TNK2,VCP,WAS,WASL +cellular component assembly BAIAP2,CDC42,DERL1,NEDD9,NSFL1C,PARD6A,PARD6B,PXN,VCP,WAS,WASL +enzyme linked receptor protein signaling pathway BAIAP2,BCAR1,CDC42,ITSN1,PAK1,PAK2,PARD6A,PXN,TNK2,WASL +regulation of immune response BAIAP2,BCAR1,CDC42,NPLOC4,PAK1,PAK2,UFD1L,VIMP,WAS,WASL +cytoskeleton organization BAIAP2,BCAR1,CDC42,NEDD9,NSFL1C,PAK1,PAK2,PARD6A,WAS,WASL +organonitrogen compound catabolic process DERL1,DERL2,FAF2,NPLOC4,NSFL1C,SAT1,SYVN1,UFD1L,VCP,VIMP +positive regulation of cellular component organization ARHGDIA,BAIAP2,CDC42,NSFL1C,PAK1,PXN,TULP1,VCP,WAS,WASL +cellular response to stress DERL1,DERL2,FAF2,NPLOC4,PAK2,PXN,SYVN1,UFD1L,VCP,VIMP +cellular catabolic process DERL1,DERL2,FAF2,NPLOC4,NSFL1C,SAT1,SYVN1,UFD1L,VCP,VIMP +regulation of intracellular signal transduction ARHGAP1,ARHGDIA,CDC42,ITSN1,NPLOC4,PAK1,PAK2,SYVN1,UFD1L,VIMP +multi-organism process BAIAP2,CDC42,DERL1,DERL2,ITSN1,PAK2,PARD6A,VCP,VIMP,WASL +immune system process BAIAP2,BCAR1,CDC42,FAF2,PAK1,PAK2,TNK2,VCP,WAS,WASL +proteasome-mediated ubiquitin-dependent protein catabolic process DERL1,DERL2,FAF2,NPLOC4,NSFL1C,SYVN1,UFD1L,VCP,VIMP +transmembrane receptor protein tyrosine kinase signaling pathway BAIAP2,BCAR1,CDC42,ITSN1,PAK1,PAK2,PXN,TNK2,WASL +import into cell ARHGAP1,BAIAP2,CDC42,ITSN1,PAK1,TNK2,TULP1,WAS,WASL +protein transport ARHGAP1,DERL1,DERL2,FAF2,NPLOC4,SYVN1,UFD1L,VCP,VIMP +regulation of cellular protein metabolic process BCAR3,DERL1,DERL2,NSFL1C,PAK1,PAK2,PARD6A,TNK2,VCP +retrograde protein transport, ER to cytosol DERL1,DERL2,FAF2,NPLOC4,SYVN1,UFD1L,VCP,VIMP +small GTPase mediated signal transduction ARHGAP1,BCAR3,CDC42,ITSN1,PAK1,PAK2,TNK2,WAS +actin cytoskeleton organization BAIAP2,BCAR1,CDC42,NEDD9,PAK1,PAK2,WAS,WASL +regulation of cytoskeleton organization ARHGDIA,BAIAP2,CDC42,NSFL1C,PAK1,PXN,WAS,WASL +endocytosis BAIAP2,CDC42,ITSN1,PAK1,TNK2,TULP1,WAS,WASL +protein modification by small protein conjugation or removal CDC42,DERL1,SPSB1,SYVN1,TULP4,UFD1L,VCP,VIMP +generation of neurons ARHGDIA,BAIAP2,CDC42,PAK1,PAK2,PARD6B,TULP1,WASL +regulation of apoptotic process ARHGDIA,BCAR1,ITSN1,PAK1,PAK2,SYVN1,VCP,VIMP +regulation of phosphate metabolic process BCAR3,ITSN1,NSFL1C,PAK1,PAK2,PARD6A,TNK2,VCP +regulation of transport ARHGAP1,DERL2,KCNE4,PAK1,TNK2,TULP1,VIMP,WASL +regulation of protein modification process BCAR3,DERL1,NSFL1C,PAK1,PAK2,PARD6A,TNK2,VCP +anatomical structure morphogenesis BAIAP2,BCAR3,CDC42,PAK1,PARD6B,SAT1,TULP1,WASL +ubiquitin-dependent ERAD pathway DERL1,DERL2,FAF2,NPLOC4,SYVN1,VCP,VIMP +response to topologically incorrect protein DERL1,DERL2,FAF2,SYVN1,UFD1L,VCP,VIMP +positive regulation of cytoskeleton organization BAIAP2,CDC42,NSFL1C,PAK1,PXN,WAS,WASL +immune response-activating cell surface receptor signaling pathway BAIAP2,BCAR1,CDC42,PAK1,PAK2,WAS,WASL +regulation of actin cytoskeleton organization ARHGDIA,BAIAP2,CDC42,PAK1,PXN,WAS,WASL +positive regulation of cellular component biogenesis BAIAP2,CDC42,PAK1,PXN,VCP,WAS,WASL +neuron projection development BAIAP2,CDC42,PAK1,PAK2,PARD6B,TULP1,WASL +protein ubiquitination CDC42,DERL1,SPSB1,SYVN1,TULP4,VCP,VIMP +immune effector process BAIAP2,CDC42,FAF2,PAK1,VCP,WAS,WASL +regulation of response to stress DERL2,NPLOC4,PAK1,PAK2,SYVN1,UFD1L,VIMP +movement of cell or subcellular component BCAR1,CDC42,PAK2,PXN,TNK2,WAS,WASL +regulation of phosphorylation BCAR3,ITSN1,PAK1,PAK2,PARD6A,TNK2,VCP +positive regulation of signal transduction ARHGAP1,BAIAP2,BCAR3,ITSN1,PAK1,PAK2,VCP +Fc receptor signaling pathway BAIAP2,CDC42,PAK1,PAK2,WAS,WASL +cellular response to topologically incorrect protein DERL1,DERL2,SYVN1,UFD1L,VCP,VIMP +response to unfolded protein DERL1,DERL2,FAF2,SYVN1,VCP,VIMP +positive regulation of supramolecular fiber organization BAIAP2,CDC42,PAK1,PXN,WAS,WASL +phagocytosis BAIAP2,CDC42,PAK1,TULP1,WAS,WASL +actin filament organization BAIAP2,BCAR1,CDC42,NEDD9,WAS,WASL +regulation of actin filament organization BAIAP2,CDC42,PAK1,PXN,WAS,WASL +regulation of protein complex assembly BAIAP2,CDC42,PAK1,VCP,WAS,WASL +viral process CDC42,DERL1,ITSN1,PAK2,PARD6A,VCP +regulation of plasma membrane bounded cell projection organization ARHGDIA,BAIAP2,CDC42,PAK1,WAS,WASL +regulation of growth BCAR1,CDC42,DERL2,NEDD9,PAK1,PAK2 +positive regulation of phosphorylation BCAR3,ITSN1,PAK1,PAK2,TNK2,VCP +cellular response to endogenous stimulus BAIAP2,BCAR1,PAK1,PARD6A,PXN,VIMP +positive regulation of protein modification process BCAR3,DERL1,PAK1,PAK2,TNK2,VCP +regulation of hydrolase activity ARHGAP1,ARHGDIA,NSFL1C,PAK2,TNK2,VCP +vascular endothelial growth factor receptor signaling pathway BAIAP2,BCAR1,CDC42,PAK2,PXN +Fc-gamma receptor signaling pathway involved in phagocytosis BAIAP2,CDC42,PAK1,WAS,WASL +dendrite development BAIAP2,CDC42,PAK2,TULP1,WASL +endoplasmic reticulum unfolded protein response DERL1,DERL2,SYVN1,VCP,VIMP +establishment or maintenance of cell polarity CDC42,NSFL1C,PAK1,PARD6A,PARD6B diff --git a/www/Examples/BCAR3/BCAR3_GO_MF.txt b/www/Examples/BCAR3/BCAR3_GO_MF.txt new file mode 100644 index 0000000..1a7dc02 --- /dev/null +++ b/www/Examples/BCAR3/BCAR3_GO_MF.txt @@ -0,0 +1,20 @@ +protein binding ARHGAP1,BAIAP2,BCAR1,BCAR3,CDC42,DERL1,FAF2,ITSN1,KCNE4,NPLOC4,NSFL1C,PAK1,PAK2,PARD6A,PXN,SAT1,SYVN1,TNK2,TULP1,UFD1L,VCP,VIMP,WAS,WASL +enzyme binding ARHGAP1,BCAR1,BCAR3,CDC42,DERL1,FAF2,ITSN1,NPLOC4,NSFL1C,PAK1,PAK2,PARD6A,PXN,SYVN1,TNK2,UFD1L,VCP,VIMP,WAS +molecular function regulator ARHGAP1,ARHGDIA,BCAR3,FAF2,ITSN1,NSFL1C,PAK2,TNK2,VCP,WAS,WASL +enzyme regulator activity ARHGAP1,ARHGDIA,FAF2,ITSN1,NSFL1C,PAK2,TNK2,VCP,WAS,WASL +identical protein binding BAIAP2,CDC42,PAK1,PAK2,SAT1,TNK2,VCP,WAS +protein kinase binding BCAR1,CDC42,PAK1,PAK2,PARD6A,PXN,WAS +GTPase binding ARHGAP1,BCAR3,ITSN1,PAK1,PAK2,PARD6A,WAS +protein domain specific binding ARHGAP1,BAIAP2,BCAR1,CDC42,TNK2,VCP,WAS +ubiquitin protein ligase binding DERL1,FAF2,NPLOC4,PXN,TNK2,VCP +Ras GTPase binding ARHGAP1,ITSN1,PAK1,PAK2,PARD6A,WAS +ATPase binding DERL1,NSFL1C,SYVN1,UFD1L,VIMP +Rho GTPase binding ITSN1,PAK1,PAK2,PARD6A,WAS +GTPase regulator activity ARHGAP1,ARHGDIA,TNK2,WAS,WASL +enzyme activator activity ARHGAP1,ARHGDIA,ITSN1,PAK2,VCP +ubiquitin-specific protease binding DERL1,SYVN1,VCP,VIMP +protein serine/threonine kinase activity CDC42,PAK1,PAK2,TNK2 +Rac GTPase binding PAK1,PAK2,WAS +ubiquitin binding FAF2,NPLOC4,NSFL1C +SH3 domain binding ARHGAP1,BCAR1,WAS +protein binding, bridging ARHGAP1,BAIAP2,BCAR3 diff --git a/www/Examples/BCAR3/BCAR3_KEGG.txt b/www/Examples/BCAR3/BCAR3_KEGG.txt new file mode 100644 index 0000000..d60cdab --- /dev/null +++ b/www/Examples/BCAR3/BCAR3_KEGG.txt @@ -0,0 +1,27 @@ +Protein processing in endoplasmic reticulum DERL1,DERL2,NPLOC4,NSFL1C,SYVN1,UFD1L,VCP,VIMP +Regulation of actin cytoskeleton BAIAP2,BCAR1,CDC42,PAK1,PAK2,PXN,WAS,WASL +Chemokine signaling pathway BCAR1,CDC42,PAK1,PXN,WAS,WASL +Bacterial invasion of epithelial cells BCAR1,CDC42,PXN,WAS,WASL +Tight junction CDC42,PARD6A,PARD6B,WAS,WASL +Axon guidance CDC42,PAK1,PAK2,PARD6A,PARD6B +Focal adhesion BCAR1,CDC42,PAK1,PAK2,PXN +Endocytosis CDC42,PARD6A,PARD6B,WAS,WASL +Adherens junction BAIAP2,CDC42,WAS,WASL +Fc gamma R-mediated phagocytosis CDC42,PAK1,WAS,WASL +Rap1 signaling pathway BCAR1,CDC42,PARD6A,PARD6B +Human papillomavirus infection CDC42,PARD6A,PARD6B,PXN +Pathogenic Escherichia coli infection CDC42,WAS,WASL +Shigellosis CDC42,WAS,WASL +Renal cell carcinoma CDC42,PAK1,PAK2 +Salmonella infection CDC42,WAS,WASL +T cell receptor signaling pathway CDC42,PAK1,PAK2 +Leukocyte transendothelial migration BCAR1,CDC42,PXN +Proteoglycans in cancer CDC42,PAK1,PXN +Ras signaling pathway CDC42,PAK1,PAK2 +MAPK signaling pathway CDC42,PAK1,PAK2 +VEGF signaling pathway CDC42,PXN +Epithelial cell signaling in Helicobacter pylori infection CDC42,PAK1 +ErbB signaling pathway PAK1,PAK2 +Choline metabolism in cancer WAS,WASL +Neurotrophin signaling pathway ARHGDIA,CDC42 +Hippo signaling pathway PARD6A,PARD6B \ No newline at end of file diff --git a/www/Examples/BioGrid_Chicken_Gallus/BioGrid_Chicken_Gallus_Pathways_KEGG_PATHWAY_FILTERED.txt b/www/Examples/BioGrid_Chicken_Gallus/BioGrid_Chicken_Gallus_Pathways_KEGG_PATHWAY_FILTERED.txt new file mode 100644 index 0000000..eef2edf --- /dev/null +++ b/www/Examples/BioGrid_Chicken_Gallus/BioGrid_Chicken_Gallus_Pathways_KEGG_PATHWAY_FILTERED.txt @@ -0,0 +1,13 @@ +ErbB signaling pathway Q00944,Q04929,P00523,P01109,Q90891,P13387,Q9W7C5,P05625,Q04982 +Carbon metabolism P00356,O57391,P00548,P07341,P51903,Q5ZLN1,Q5ZME2,P51913,P00940,P00508 +Biosynthesis of antibiotics P00356,O57391,P00548,P07341,O57535,P51903,Q5ZLN1,P00337,Q5ZME2,P51913,P00940,P00508,P00340,P38024 +Gap junction P00523,P09244,Q90891,P08070,P13387,P50147,P09207,P05625,P13863 +Ribosome Q98TF6,Q98TF8,P67883,P32429,P61355,P47826,Q5ZJ56,P47836,P50890,P18660,P22451 +Focal adhesion Q00944,Q04929,P00523,Q90623,P13387,P05094,P60706,P53478,P11799,P49024,P12003,Q04982,P62207,P05625 +Progesterone-mediated oocyte maturation Q04619,P07812,P18652,P11501,P50147,P05625,Q04982,P13863 +Vascular smooth muscle contraction Q8AYS8,P11799,Q90623,P05419,P63270,Q90891,P62207,P05625,Q04982 +Protein processing in endoplasmic reticulum Q04619,Q5ZKF5,Q90593,Q8JG64,O73885,P11501,P08110,Q5ZHY5,P81628,Q5ZK03,P08106 +Pyruvate metabolism P00548,P00337,Q5ZME2,P11029,P00340 +VEGF signaling pathway Q00944,P00523,P49024,Q90891,P05625,Q00649 +Insulin signaling pathway Q04929,P05419,Q90891,P11029,P62207,P05625,Q04982,O13016 +Tight junction P00523,P48463,P05094,P60706,P53478,Q01406 \ No newline at end of file diff --git a/www/Examples/BioGrid_Chicken_Gallus/Biogrid_no_self_loops.txt b/www/Examples/BioGrid_Chicken_Gallus/Biogrid_no_self_loops.txt new file mode 100644 index 0000000..8b23baf --- /dev/null +++ b/www/Examples/BioGrid_Chicken_Gallus/Biogrid_no_self_loops.txt @@ -0,0 +1,333 @@ +Source Target +P62760 P60706 +P62764 P60706 +O15392 P53352 +Q9IAY5 P49024 +Q9IAY5 P49024 +P49024 Q9IAY5 +Q13625 P46936 +O93512 O60542 +P41238 Q7T2T1 +O42414 Q9JI92 +O42414 Q9JI92 +P05556 Q00944 +P05556 P49024 +P27986 Q9DDT2 +P28497 P23297 +P49024 P12003 +P49024 Q00944 +Q4KWZ7 Q9DEA3 +Q9DEA3 Q4KWZ7 +P53478 Q9UUJ1 +P53478 P32390 +P53478 P78929 +P12003 P60010 +P79987 P56517 +P79987 P56519 +P79987 Q9W7I5 +P79987 Q3C1E9 +Q9W7I5 P79987 +P56517 P79987 +P56519 P79987 +Q5ZJY5 O93257 +Q5R1T0 P56517 +Q5R1T0 P56519 +Q5R1T0 P56517 +Q5R1T0 P56519 +Q5R1T0 P56520 +Q09472 P17678 +P23204 P17678 +P23204 P23824 +P23204 P23825 +Q92993 P70082 +Q92993 P0C1H3 +Q92993 P84247 +Q92993 P62801 +P56519 Q9HAZ2 +O18738 P31696 +Q8AYS7 Q1T7B8 +Q8AYS7 Q1T7C0 +Q8AYS7 Q1T7B7 +Q8AYS7 Q1T7C1 +Q8AYS7 Q1T7B9 +Q90ZF9 Q1T7B8 +Q90ZF9 Q1T7C0 +Q90ZF9 Q1T7B7 +Q90ZF9 Q1T7C1 +Q90ZF9 Q1T7B9 +Q76I90 Q76I89 +Q76I89 Q76I90 +Q8AYS8 P09572 +Q8AYS8 P11501 +Q8AYS8 Q90593 +Q8AYS8 P16053 +Q8AYS8 P08106 +Q8AYS8 O73885 +Q8AYS8 Q5ZHY5 +Q8AYS8 Q5ZL72 +Q8AYS8 P09207 +Q8AYS8 Q5ZLC5 +Q8AYS8 P05094 +Q8AYS8 P00508 +Q8AYS8 P54097 +Q8AYS8 P17153 +Q8AYS8 Q5ZMT0 +Q8AYS8 P28497 +Q8AYS8 P62207 +Q8AYS8 Q5ZKC9 +Q8AYS8 Q5F3W6 +Q8AYS8 P60878 +Q8AYS8 Q5ZM44 +Q8AYS8 P08250 +Q8AYS8 Q5ZMB2 +Q8AYS8 Q00649 +Q8AYS8 Q5ZKK4 +Q8AYS8 Q5ZIV5 +Q8AYS8 Q5ZMD1 +Q8AYS8 Q5ZLQ6 +Q8AYS8 P07090 +Q8AYS8 P81628 +Q8AYS8 P42324 +Q8AYS8 P62758 +Q8AYS8 P62764 +Q8AYS8 P08110 +Q8AYS8 O93510 +Q8AYS8 P13731 +Q8AYS8 Q5F425 +Q8AYS8 P18359 +Q8AYS8 P02789 +Q8AYS8 Q5ZL57 +Q8AYS8 P19121 +Q8AYS8 O57391 +Q8AYS8 Q9PTG6 +Q8AYS8 P63270 +Q8AYS8 P51913 +Q8AYS8 P05122 +Q8AYS8 Q5ZME2 +Q8AYS8 Q5ZHP5 +Q8AYS8 P48463 +Q8AYS8 P04354 +Q8AYS8 P50890 +Q8AYS8 P05419 +Q8AYS8 P80566 +Q8AYS8 P31395 +Q8AYS8 P00940 +Q8AYS8 Q5ZLN1 +Q8AYS8 Q5ZJF4 +Q8AYS8 P00340 +Q8AYS8 P09654 +Q8AYS8 O42163 +Q8AYS8 P16580 +Q8AYS8 P02112 +Q8AYS8 P80026 +Q8AYS8 Q5ZLG1 +Q8AYS8 O57535 +Q8AYS8 Q07212 +Q8AYS8 O13268 +Q8AYS8 P00337 +Q8AYS8 P00356 +Q8AYS8 P51903 +Q8AYS8 P07341 +Q8AYS8 P00548 +Q8AYS8 P14732 +Q8AYS8 P13648 +Q8AYS8 Q5F3W6 +Q8AYS8 P42324 +Q8AYS8 P60878 +Q8AYS8 P17153 +Q8AYS8 Q5ZL72 +Q8AYS8 Q5F425 +Q8AYS8 P80566 +Q8AYS8 Q01406 +Q8AYS8 P08106 +Q8AYS8 P31395 +Q8AYS8 Q90593 +Q8AYS8 Q04619 +Q8AYS8 P14731 +Q5F3W6 Q8AYS8 +P42324 Q8AYS8 +P60878 Q8AYS8 +P17153 Q8AYS8 +Q5ZL72 Q8AYS8 +Q5F425 Q8AYS8 +P80566 Q8AYS8 +Q01406 Q8AYS8 +P08106 Q8AYS8 +P31395 Q8AYS8 +Q90593 Q8AYS8 +Q04619 Q8AYS8 +P14731 Q8AYS8 +P84023 P49140 +P84023 P83038 +P38531 P04637 +P38531 P06876 +P38531 P01103 +F1N9Y5 P00548 +F1N9Y5 P09244 +F1N9Y5 O73885 +F1N9Y5 Q5ZL72 +F1N9Y5 P11501 +F1N9Y5 Q90705 +F1N9Y5 Q5ZLC5 +F1N9Y5 P51913 +F1N9Y5 Q5ZM98 +F1N9Y5 P38024 +F1N9Y5 P47826 +F1N9Y5 P08070 +F1N9Y5 Q90593 +F1N9Y5 P15771 +F1N9Y5 Q9IAY5 +F1N9Y5 P50890 +F1N9Y5 Q5ZJK8 +F1N9Y5 P51903 +F1N9Y5 P67883 +F1N9Y5 P00340 +F1N9Y5 Q6EE31 +F1N9Y5 P22451 +F1N9Y5 Q8UVD9 +F1N9Y5 Q5ZJU3 +F1N9Y5 O57535 +F1N9Y5 Q5ZLP8 +F1N9Y5 Q04619 +F1N9Y5 Q5ZIQ3 +F1N9Y5 P47836 +F1N9Y5 Q5ZKC9 +F1N9Y5 Q5ZK03 +F1N9Y5 Q8AYC9 +F1N9Y5 P00356 +F1N9Y5 Q5ZLN4 +F1N9Y5 Q5ZJ56 +F1N9Y5 P18660 +F1N9Y5 Q5ZMT0 +F1N9Y5 Q8JFP1 +F1N9Y5 P32429 +F1N9Y5 P16039 +F1N9Y5 P00337 +F1N9Y5 P08106 +F1N9Y5 Q5ZMS3 +F1N9Y5 P61355 +F1N9Y5 Q5ZJ54 +F1N9Y5 P63247 +F1N9Y5 Q5ZKA5 +F1N9Y5 P08629 +F1N9Y5 P16527 +F1N9Y5 Q5ZMN2 +F1N9Y5 Q5ZJZ5 +F1N9Y5 P18359 +F1N9Y5 Q5ZKF5 +F1N9Y5 Q5ZLN1 +F1N9Y5 Q9YGC1 +F1N9Y5 Q5ZLE6 +F1N9Y5 Q8UW59 +F1N9Y5 Q5ZKB9 +F1N9Y5 P13863 +F1N9Y5 Q90WU3 +F1N9Y5 Q5ZI72 +F1N9Y5 Q5ZIA5 +F1N9Y5 P11029 +F1N9Y5 Q98TF8 +F1N9Y5 Q5ZL42 +F1N9Y5 Q5ZKC1 +F1N9Y5 P17790 +F1N9Y5 Q5ZMN3 +F1N9Y5 Q98TF6 +F1N9Y5 Q5ZLC6 +F1N9Y5 P24367 +F1N9Y5 P11799 +F1N9Y5 Q5ZK62 +F1N9Y5 P26584 +F1N9Y5 P14315 +F1N9Y5 Q5ZKG5 +F1N9Y5 P42558 +F1N9Y5 P41239 +F1N9Y5 P05419 +F1N9Y5 P43347 +F1N9Y5 P63283 +F1N9Y5 Q5ZJN4 +F1N9Y5 Q5ZL57 +F1N9Y5 Q8JG64 +F1N9Y5 O42392 +F1N9Y5 Q5ZK01 +F1N9Y5 P19179 +F1N9Y5 O93256 +F1N9Y5 Q02391 +P28683 P62140 +Q6A078 P00698 +P68400 O13016 +P12931 O13016 +P07812 Q04619 +P07812 P08106 +P62207 Q90623 +Q90ZF9 Q76I89 +Q90ZF9 Q76I90 +Q90ZF9 Q76I89 +P00523 P19785 +P11501 Q5ZL72 +P11501 P08106 +Q04619 Q5ZL72 +Q04619 P08106 +P68399 P01109 +P67868 P01109 +Q12341 P02263 +Q12341 P62801 +Q5ZL72 P08106 +Q5ZL72 Q04619 +Q04619 P08106 +Q06592 P62801 +Q06592 P84247 +P39979 P62801 +Q3C1E9 P79987 +Q3C1E9 Q5R1S9 +Q3C1E9 P84247 +Q3C1E9 P62801 +P07812 Q15185 +P07812 P07900 +P07812 P34932 +P07812 P25685 +P07812 P31948 +P25293 P70082 +P25293 P0C1H3 +P25293 P84247 +P25293 P62801 +Q702N8 P68139 +A4UGR9 P68139 +P68139 P42639 +P42684 Q04929 +Q92831 P02263 +Q92831 P62801 +Q9DEA3 Q4KWZ7 +Q02842 Q5ZJL9 +Q15185 P11501 +P00523 P51913 +Q04982 Q5ZIK9 +Q04982 P48463 +Q04982 Q5ZM98 +Q04982 P67869 +Q04982 O73885 +Q04982 Q5ZMN3 +Q04982 P16039 +Q04982 P42558 +Q04982 Q6U7I1 +Q04982 P05625 +Q04982 Q5ZMD1 +Q04982 Q5ZLQ6 +Q04982 Q5ZMT0 +Q04982 Q5ZKC9 +Q04982 P50147 +Q04982 Q5F3W6 +Q04982 O57476 +Q04982 P11501 +Q04982 Q90828 +Q04982 Q90891 +Q04982 Q90593 +Q04982 P08110 +P18652 O95071 +O42414 P16092 +P16092 O42414 +P61088 Q9DEA3 +Q15819 Q9DEA3 +Q9W7C5 Q401C0 +Q401C0 Q9W7C5 +P11275 P13387 +Q7T0L4 Q9PU53 +Q07496 P32004 diff --git a/www/Examples/Human_Coexpression/NORMA_Human_coexpression_Annotation_GO_BP.txt b/www/Examples/Human_Coexpression/NORMA_Human_coexpression_Annotation_GO_BP.txt new file mode 100644 index 0000000..2f7250b --- /dev/null +++ b/www/Examples/Human_Coexpression/NORMA_Human_coexpression_Annotation_GO_BP.txt @@ -0,0 +1,147 @@ +protein biosynthesis RPS15,RPS15,RPL37,RPS5,RPL35,FAU,RPS11,RPS21,RPL18,RPS13,RPL21,RPL36,RPL12,RPLP2,RPS19,RPL27,RPL31,MRPS12,LOC440055,RPS27,LOC388344,RPL27A,RPS10,RPS17,RPL28,LOC283412,RPL19,RPS16,RPS14,NARS,RPL7,RPS6,RPS2,U16,NACA,RPL18A,RPL13,RPL29,RPS15A,RPS20,RPS3A,RPS18,RPL14,MRPL34,RPL22,RPL34,RPS27A,EEF1D,RPL15,RPL9,RPL6,RPL26,RPL4,RPS4X,RPS24,RPS9,RPL13A,RPL17,EEF1A1,RPL5,RPL23,MDS1,RPS7,LOC402057,RPS25 +immune response HLA-DPB1,HLA-DPB1,TAPBP,IL2RG,HLA-DMA,HLA-DQA1,IL16,221651_x_at,IGLV3-10,ARL6IP2,HLA-B,CD164,HLA-DRA,HLA-DMB,TRIM22,HLA-DRB5,HLA-DRB1,IGL@,IGLC1,IGLV3-25,TRB@,HLA-DRB4,LTB,ARHGDIB,C6orf12,HLA-DQB1,HLA-DPA1,TRBV3-1,GPSM3,IGLC2,TRA@,214836_x_at,IGHV1-69,IGHA1,HLA-A,CD7,IGHG3,IGLJ3,IL7R,IL6ST,HLA-C,IGKC,IGHM +signal transduction AKT1,AKT1,STAT1,IL2RG,CXCR4,OPHN1,CCL5,PGF,INPP5D,PRKAR1A,CD164,RPS27,HLA-DRB5,CD74,HLA-DRB1,PRKAR2A,CD53,HLA-DRB4,LTB,HSP90AA1,OGT,ROCK1,IFNGR1,PTGES3,HMGB1,GTF2I,GNB2L1,CAP1,SPN,NPM1,IQGAP1,PAFAH1B1,EIF3S3,RAC2,COPS2,PRKACB,PDE4C +antigen presentation, endogenous antigen HLA-J,HLA-J,RPLP2,221651_x_at,IGLV3-10,IGHD,HLA-B,CD74,IGL@,IGLC1,HLA-E,IGLV3-25,C6orf12,IGLC2,214836_x_at,IGHV1-69,IGHA1,HLA-F,HLA-A,IGHG3,IGLJ3,HLA-G,HLA-C,IGKC,IGHM +antigen processing, endogenous antigen via ... CAST,CAST,HLA-J,RPLP2,221651_x_at,IGLV3-10,IGHD,HLA-B,IGL@,IGLC1,HLA-E,IGLV3-25,C6orf12,IGLC2,214836_x_at,IGHV1-69,IGHA1,HLA-F,HLA-A,IGHG3,IGLJ3,HLA-G,HLA-C,IGKC,IGHM +regulation of transcription, DNA-dependent NFE2L2,NFE2L2,STAT1,MGC2474,LYSMD4,ZMYND11,ZNF160,CDC5L,TRIM22,SFPQ,IFI16,HCLS1,ATRX,HMGB1,CSDE1,SCAND1,RPL6,LOC342346,SUB1 +electron transport MT1X,MT1X,MT1L,COX4I1,NCF1,SDHA,UQCRQ,UQCRC1,GPX4,UQCRFS1,NDUFV1,COX5B,NDUFS3,NDUFS8,COX5A,NDUFB4,CYC1,COX8A,RPA1 +protein amino acid phosphorylation AKT1,AKT1,RAVER2,GMFG,PRKAR1A,PRKD2,MYLK,PRKAR2A,ROCK1,TGFB1,PCM1,U16,LCK,CSNK1A1,HNRPDL,RPL4,PRKACB +antigen processing, exogenous antigen via M... HLA-DPB1,HLA-DPB1,HLA-DMA,HLA-DQA1,HLA-DRA,HLA-DMB,HLA-DRB5,HLA-DRB1,HLA-DRB4,HLA-DQB1,HLA-DPA1 +antigen presentation, exogenous antigen HLA-DPB1,HLA-DPB1,HLA-DMA,HLA-DQA1,HLA-DRA,HLA-DMB,HLA-DRB5,HLA-DRB1,HLA-DRB4,HLA-DQB1,HLA-DPA1 +cell adhesion ITGAV,ITGAV,LAMC1,CCL5,FNBP4,ADRM1,CD164,TGFB1I1,SELL,DGCR6,COL6A1,PLEKHC1,CD2,ITGB2 +intracellular signaling cascade STAT1,STAT1,RAVER2,INPP5D,PRKAR1A,PRKD2,NCF1,PRKAR2A,WSB1,HCLS1,HMHA1,ROCK1,LCK +transcription from RNA polymerase II promoter TARDBP,TARDBP,NFE2L2,STAT1,POLR2J,TGFB1I1,TCEA1,HMHA1,POLR2I,BTF3,COPS2,POLR2E +cell motility CALD1,CALD1,CAPZA1,CCL5,TPM1,MSN,ACTR3,ARPC1B,ARHGDIB,ARPC3,ARPC5,PAFAH1B1 +detection of pest, pathogen or parasite HLA-DPB1,HLA-DPB1,HLA-DMA,HLA-J,HLA-DMB,HLA-DRB5,HLA-DRB1,HLA-DRB4,HLA-G +nuclear mRNA splicing, via spliceosome HNRPM,HNRPM,SFRS10,HNRPH3,SFPQ,HIATL1,RPL35A,SF3B1,HNRPA2B1,HNRPA1 +mitochondrial electron transport, NADH to u... NDUFC1,NDUFC1,NDUFB6,NDUFB2,NDUFV1,NDUFS7,NDUFS3,NDUFS8,NDUFB4 +development CECR1,CECR1,CLPTM1,CD164,ARHGDIB,COL6A3,MYH11,ITGB2,DDX1 +phosphate transport COL6A3,COL6A3,COL1A1,COL6A1,COL4A2,COL4A1,COL3A1,COL1A2 +antigen presentation HLA-J,HLA-J,HLA-B,HLA-E,C6orf12,HLA-F,HLA-A,HLA-G,HLA-C +transport G3BP,G3BP,SLC25A16,UCP2,SLC25A11,TMED5,SLC25A3,ATP2A3 +cell proliferation RPS21,RPS21,PGF,ZMYND11,RPS27,CD74,IFI16,MIF,ISG20 +anti-apoptosis AKT1,AKT1,FAIM3,SON,HMGB1,HSP90B1,NPM1,TPT1,PRDX2 +cell surface receptor linked signal transdu... CD3D,CD3D,CD2,CD79A,BIRC2,MIF,CSNK1A1,IL7R,IL6ST +generation of precursor metabolites and energy ACO2,ACO2,ATPIF1,COX4I1,ECH1,UQCR,SLC25A3,COX8A +protein complex assembly TAPBP,TAPBP,CAPZA1,GPAA1,LAMC1,TCEB2,CD3D,CD74 +mRNA processing SFPQ,SFPQ,SRP46,DHX15,HNRPR,SFRS11,SFRS5,RNPC2 +positive regulation of cell proliferation SSR1,SSR1,CAPNS1,PGF,RPL31,HCLS1,TGFB1,NAP1L1 +RNA splicing HNRPH3,HNRPH3,SFPQ,DHX15,PPP2CA,ZNF638,SFRS11 +transcription LYSMD4,LYSMD4,POLR2J,ZNF160,SFPQ,POLR1B,PCM1 +regulation of translational initiation EIF4G1,EIF4G1,EIF4A2,EIF4G2,EIF5,EIF3S3,DDX1 +pathogenesis HLA-DPB1,HLA-DPB1,HLA-DRB5,HLA-DRB1,HLA-DRB4 +proton transport ATP5J2,ATP5J2,ATP6V0D1,UCP2,ATP6V0B,ATP6V0C +RNA processing HNRPU,HNRPU,RBPMS,DDX17,HNRPH1,HNRPDL,RNPC2 +regulation of transcription from RNA polyme... THRAP5,THRAP5,PRKAR1A,HMGB1,LOC342346,SUB1 +protein transport RAB1A,RAB1A,RAB6A,RAB6C,TLOC1,HSP90B1,COPB +small GTPase mediated signal transduction RAP1B,RAP1B,RGS19,RAB1A,RAB6A,RAB6C,RPL29 +response to virus CCL5,CCL5,IRF7,TRIM22,IFI16,IFNGR1,ISG20 +inflammatory response CCL5,CCL5,IRF7,MEFV,ALOX5AP,TGFB1,ITGB2 +actin cytoskeleton organization and biogenesis ARHGDIB,ARHGDIB,PLEKHC1,DST,ROCK1,ARPC5 +protein folding PPIB,PPIB,HSP90AA1,HSP90B1,EIF3S3,KTN1 +induction of apoptosis CD2,CD2,PPP2CA,BCLAF1,LCK,RPS3A,SCAND1 +skeletal development CNOT2,CNOT2,COL1A1,TGFB1,COL1A2,MYH11 +regulation of progression through cell cycle STAT1,STAT1,PGF,ERH,PPP2CA,LCK,SCAND1 +negative regulation of cell proliferation CD164,CD164,TGFB1I1,TGFB1,CDKN1B,NPM1 +cellular defense response HLA-J,HLA-J,CCL5,NCF1,FAIM3,SPN,HLA-G +translational elongation RPLP2,RPLP2,TUFM,EEF1B2,EEF1D,EEF1A1 +muscle development TAGLN,TAGLN,LYSMD4,SMTN,COL6A3,MBNL1 +ATP synthesis coupled proton transport ATP6V0B,ATP6V0B,ATP6V0C,ATP5D,ATP5G3 +proteolysis CAST,CAST,MASP1,YME1L1,MMP2,IGHG3 +microtubule-based movement 220725_x_at,220725_x_at,KNS2,KTN1 +metabolism ACO2,ACO2,ECH1,POPDC3,IGLC2,DIP2A +apoptosis AD7C-NTP,AD7C-NTP,FIS1,ITGB2,CROP +amino acid transport SLC38A2,SLC38A2,218041_x_at,RPL24 +response to unfolded protein HSP90AA1,HSP90AA1,HSP90B1,EIF3S3 +intracellular protein transport VDP,VDP,NAPA,CLTC,CD74,NPM1,COPE +transcription initiation from RNA polymeras... THRAP5,THRAP5,IRF7,THRAP1,GTF2I +response to oxidative stress CCL5,CCL5,GPX1,GPX4,CSDE1,PRDX2 +nucleobase, nucleoside, nucleotide and nucl... NDUFA10,NDUFA10,ERH,208246_x_at +carbohydrate metabolism LOC91316,LOC91316,MAN2B1,AKR7A2 +protein modification SUMO2,SUMO2,RPN1,MAN2B1,RPS27A +ubiquitin-dependent protein catabolism USP34,USP34,UBE4A,PSMB9,PSMB8 +defense response CD48,CD48,PTPRCAP,HLA-B,CD79A +DNA replication MCM3AP,MCM3AP,NARS,NAP1L1,SET +androgen receptor signaling pathway THRAP5,THRAP5,THRAP1,TGFB1I1 +protein targeting to mitochondrion TIMM8B,TIMM8B,TOMM20,TIMM13 +oxygen transport SLC38A2,SLC38A2,218041_x_at +G-protein coupled receptor protein signalin... AKT1,AKT1,RGS19,CXCR4,FNBP4 +nervous system development OPHN1,OPHN1,MBNL1,PAFAH1B1 +mitochondrial transport UCP2,UCP2,HSP90AA1,EIF3S3 +embryo implantation LOC283412,LOC283412,RPL29 +DNA repair SFPQ,SFPQ,ATRX,HMGB1,RPA1 +protein refolding HSP90AA1,HSP90AA1,EIF3S3 +positive regulation of nitric oxide biosynt... HSP90AA1,HSP90AA1,EIF3S3 +lipid metabolism PAFAH1B1,PAFAH1B1,ATP8B1 +cell cycle arrest EIF4G2,EIF4G2,DST,CDKN1B +cell cycle CUL4B,CUL4B,RPS27A,SEPT7 +protein ubiquitination UBE4A,UBE4A,PCNP,RPS27A +protein targeting TOMM20,TOMM20,SRP9,COPB +nucleosome assembly NAP1L1,NAP1L1,SET,H3F3A +negative regulation of cell adhesion CD164,CD164,ARHGDIB,SPN +cell-cell signaling CCL5,CCL5,PGF,LTB,ITGB2 +positive regulation of transcription TGFB1I1,TGFB1I1,RPS27A +negative regulation of transcription IRF7,IRF7,SUMO1,BCLAF1 +hemopoiesis CD164,CD164,ZNF160,LCK +cellular defense response (sensu Vertebrata) IGHA1,IGHA1,IGHG3,IGHM +retrograde vesicle-mediated transport, Golg... TAPBP,TAPBP,COPE,COPB +protein import into nucleus MCM3AP,MCM3AP,NDUFA13 +positive regulation of transcription, DNA-d... TGFB1I1,TGFB1I1,TGFB1 +negative regulation of cell growth PPP2CA,PPP2CA,NDUFA13 +integrin-mediated signaling pathway ITGAV,ITGAV,DST,ITGB2 +cotranslational protein targeting to membrane SSR1,SSR1,TLOC1,TRAM1 +Rho protein signal transduction ARHGDIB,ARHGDIB,ROCK1 +sensory perception of sound TIMM8B,TIMM8B,TIMM13 +regulation of translation PPP2CA,PPP2CA,EEF1A1 +regulation of transcription POLR2L,POLR2L,PPP2CA +prostaglandin biosynthesis CD74,CD74,PTGES3,MIF +mitosis TARDBP,TARDBP,CORO1A +insulin receptor signaling pathway PHIP,PHIP,AKT1,MYH11 +DNA recombination ATRX,ATRX,HMGB1,RPA1 +tricarboxylic acid cycle ACO2,ACO2,SDHA,RPA1 +negative regulation of transcription, DNA-d... RPS14,RPS14,NDUFA13 +intra-Golgi vesicle-mediated transport NAPA,NAPA,COPE,COPB +cell death EIF4G2,EIF4G2,TGFB1 +protein amino acid autophosphorylation RPS2,RPS2,U16,RPL4 +circulation RPL31,RPL31,COL3A1 +calcium ion transport ATP2A3,ATP2A3,TPT1 +axon guidance OPHN1,OPHN1,RPS27A +ER-associated protein catabolism RPL27,RPL27,RPS27A +regulation of actin filament polymerization ARPC3,ARPC3,ARPC5 +positive regulation of I-kappaB kinase/NF-k... BIRC2,BIRC2,EEF1D +organ morphogenesis DGCR6,DGCR6,TGFB1 +negative regulation of transcription from R... IRF7,IRF7,ZMYND11 +mRNA splice site selection SRP46,SRP46,SFRS5 +erythrocyte differentiation RPS19,RPS19,HCLS1 +cytokinesis SEPT2,SEPT2,SEPT7 +chromosome segregation ARL8B,ARL8B,RIOK3 +cell-matrix adhesion ITGAV,ITGAV,ITGB2 +activation of NF-kappaB transcription factor U16,U16,NPM1,RPL4 +T cell activation CD3D,CD3D,CD2,CD7 +ubiquitin cycle TPT1,TPT1,UBE2D2 +regulation of cell adhesion NPTN,NPTN,PPP2CA +cell growth TGFB1,TGFB1,DDX5 +angiogenesis CAST,CAST,ATPIF1 +translational initiation EIF5,EIF5,RPS3A +transforming growth factor beta receptor si... FNTA,FNTA,TGFB1 +response to drug RAB6C,RAB6C,LCK +regulation of apoptosis TPT1,TPT1,PRDX2 +chromosome organization and biogenesis (sen... ATRX,ATRX,H3F3A +caspase activation STAT1,STAT1,LCK +antimicrobial humoral response (sensu Verte... IL7R,IL7R,ITGB2 +I-kappaB kinase/NF-kappaB cascade PHIP,PHIP,STAT1 +transmembrane receptor protein tyrosine kin... CD7,CD7,COL1A2 +response to stress NPM1,NPM1,CROP +response to metal ion MT1X,MT1X,MT1L +calcium ion homeostasis CCL5,CCL5,TPT1 +regulation of macrophage activation CD74,CD74,MIF +nucleocytoplasmic transport NPM1,NPM1,SET +negative regulation of apoptosis CD74,CD74,MIF +muscle contraction DES,DES,CALD1 +establishment and/or maintenance of cell po... CAP1,CAP1,SPN +chemotaxis CCL5,CCL5,SPN +Ras protein signal transduction G3BP,G3BP,LCK +regulation of heart contraction DES,DES,TPM1 +activation of MAPKK activity U16,U16,RPL4 +JNK cascade U16,U16,RPL4 +cytoskeleton organization and biogenesis DES,DES,DST diff --git a/www/Examples/Human_Coexpression/NORMA_Human_coexpression_Annotation_GO_CC.txt b/www/Examples/Human_Coexpression/NORMA_Human_coexpression_Annotation_GO_CC.txt new file mode 100644 index 0000000..4b57291 --- /dev/null +++ b/www/Examples/Human_Coexpression/NORMA_Human_coexpression_Annotation_GO_CC.txt @@ -0,0 +1,75 @@ +integral to membrane SPCS2,SPCS2,ITGAV,CAST,REEP5,HLA-DPB1,SSR1,C11orf2,TAPBP,IL2RG,CXCR4,HLA-J,RPLP2,CD37,SLC25A16,221651_x_at,RPN1,IGLV3-10,FNBP4,UCP2,AD7C-NTP,ADRM1,IGHD,HLA-B,HLA-DMB,TLOC1,ATP6V0B,HLA-DRB5,SLC25A11,CD74,HLA-DRB1,IGL@,TMED5,IGLC1,HLA-E,SLC25A3,IGLV3-25,TRB@,ARL6IP5,HLA-DRB4,TRBC1,LAPTM5,CD2,C6orf12,IFNGR1,HLA-DQB1,FXYD5,POPDC3,ATP6V0C,TRBV3-1,IGLC2,214836_x_at,IGHV1-69,IGHA1,U16,HLA-F,HLA-A,CD7,CAV1,IGHG3,215176_x_at,IGLJ3,HLA-G,IL7R,ITGB2,IL6ST,RPL4,HLA-C,IGKC,IGHM,TRAM1,RPA1 +membrane HLA-DPB1,HLA-DPB1,SLC38A2,RAP1B,VDP,IL2RG,CXCR4,RAB1A,NPTN,RAB6A,HLA-DMA,HLA-DQA1,ADD3,SLC25A16,PGF,IL10RA,RAB6C,221651_x_at,MSN,IGLV3-10,RPL31,UCP2,IGHD,218041_x_at,HLA-DRA,HLA-DMB,YME1L1,SELL,ATP6V0B,HLA-DRB5,SLC25A11,HLA-DRB1,IGL@,IGLC1,SLC25A3,IGLV3-25,TRB@,HLA-DRB4,TRBC1,LTB,COL6A3,IFNGR1,HLA-DQB1,HLA-DPA1,CD79A,FXYD5,ATP6V0C,PPP2CA,TRBV3-1,IGLC2,ATP2A3,214836_x_at,IGHV1-69,IGHA1,IGHG3,215176_x_at,IGLJ3,IL7R,COPE,HLA-C,IGKC,IGHM,ATP5G3,RPA1,RPL24 +nucleus TARDBP,TARDBP,CNOT2,NFE2L2,ZFR,STAT1,SEPT2,MCM3AP,TINP1,LYSMD4,KPNB1,SFRS10,CBX3,THRAP5,G3BP,HNRPH3,IRF7,THRAP1,ZMYND11,POLR2J,ZNF160,MEFV,CDC5L,TRIM22,DDX17,IFI16,HCLS1,ATRX,HNRPH1,POLR1B,OGT,DHX15,ZNF611,MORF4L1,HNRPR,HMGB1,PPP2CA,CDKN1B,PCM1,BCLAF1,TIMM13,SRP9,RPS6,DDX5,ZNF638,RPL35A,SFRS11,PCNP,DDX50,ZNF552,RPS3A,NPM1,MBNL1,PAPOLA,AURKAIP1,FIBP,SH3BGRL,MATR3,RPS27A,SCAND1,DDX3X,SET,HNRPA2B1,RNPC2,SEPT7,H3F3A +cytoplasm AKT1,AKT1,MT1E,FNTA,STAT1,MT1F,SEPT2,VDP,EIF4G1,KPNB1,DDX42,IRF7,MSN,ARL8B,CD3D,PRKAR2A,HCLS1,ARHGDIB,COL6A3,COL1A1,COL6A1,DST,217718_s_at,RPL36A,NARS,COL4A2,COL4A1,CDKN1B,NDUFA13,PCM1,ZNF638,NACA,EXOSC4,COL3A1,COL1A2,ARPC5,EIF5,NPM1,MBNL1,PAPOLA,SH3BGRL,TPT1,PRDX2,COPS2,COPE,XPO1,DDX3X,EEF1A1,HNRPA1 +ribosome RPL37,RPL37,RPS11,RPS21,RPL21,RPL36,RPL12,RPLP2,RPS19,RPL27,RPL31,LOC440055,LOC388344,RPL27A,RPL28,LOC283412,RPL19,RPS16,RPL36A,RPS6,RPS2,U16,RPL18A,RPL13,RPL29,RPS3A,RPS18,RPL14,RPL22,RPL34,RPS23,RPL15,RPL9,RPL6,RPL4,RPS4X,RPS24,RPL5,RPL23,MDS1,RPS7 +intracellular RPL37,RPL37,RAP1B,MGC2474,RPS21,RPL21,RPLP2,G3BP,GMFG,RPS19,RAB6C,PRKD2,RPL31,ZNF160,TGFB1I1,MEFV,GLTSCR2,MRPS12,CD74,RPL28,LOC283412,RPL19,ROCK1,SON,RPS6,RPS2,U16,RPL18A,RPL29,RPS18,RPL14,RPL22,RPL34,RPL15,RPL4,RPS4X,RPS24,RPL13A,RPL5,MDS1,RPS7 +integral to plasma membrane HNRPM,HNRPM,IL2RG,HLA-DQA1,CD48,CD37,CLPTM1,ADRM1,HLA-B,CD164,HLA-DRA,SELL,HLA-DRB5,SLC25A11,HLA-DRB1,SLC25A3,HLA-DRB4,LAPTM5,CD2,C6orf12,IFNGR1,HLA-DPA1,ATP2A3,IGHA1,HLA-A,CAV1,SPN,IGHG3,CD52,IL6ST,HLA-C,IGHM,ATP8B1 +cytosolic small ribosomal subunit (sensu Eu... RPS15,RPS15,RPS5,FAU,RPS11,RPS21,RPS13,RPS19,LOC440055,RPS27,RPS10,RPS17,RPS16,RPS14,RPS6,RPS2,RPS15A,RPS20,RPS3A,RPS18,RPS27A,RPS23,RPS24,RPS9,RPS7,LOC402057,RPS25 +cytosolic large ribosomal subunit (sensu Eu... RPL35,RPL35,RPL18,RPL21,RPL36,RPLP2,RPL27A,RPL28,LOC283412,RPL7,U16,RPL18A,RPL29,RPL14,RPL22,RPL34,RPL6,RPL4,RPL5,MDS1 +plasma membrane ARF1,ARF1,CD48,PTPRCAP,CD37,IL10RA,MSN,CD164,HLA-DRA,SELL,PRKAR2A,CD53,TRB@,TRBV3-1,TRA@,LCK,CD7,IL6ST +mitochondrion ACO2,ACO2,ATPIF1,MSRB2,SDHA,UCP2,TUFM,LOC440055,GPX4,SLC25A3,PPP2CA,NDUFA13,FIBP,DBT,NDUFB4,CYC1,RPA1 +cytosol CAST,CAST,NCF1,NPEPPS,KNS2,PSMB9,PSMB8,HSP90AA1,OGT,PPP2CA,HSP90B1,EIF5,RPS3A,EIF3S3,SPG21,COPB +membrane fraction RGS19,RGS19,ADRM1,HLA-B,PRKAR2A,LMOD1,COL6A3,IGHV1-69,IGHA1,U16,CD7,IGHG3,CD52,FIBP,RPL4,IGHM +endoplasmic reticulum CAST,CAST,P4HB,SSR1,TAPBP,RPN1,PPIB,TLOC1,NAPA,HSP90B1,CAV1,KTN1,SET,TRAM1 +cytoskeleton CALD1,CALD1,RAVER2,ACTA2,TPM1,MSN,NPEPPS,ARHGDIB,LMOD1,ACTG2,ARPC3,ARPC5 +ribonucleoprotein complex HNRPM,HNRPM,SRP72,HNRPH3,HNRPU,HNRPK,HNRPR,HNRPA3P1,SIAHBP1,HNRPA1 +extracellular region CAST,CAST,P4HB,CNOT2,MASP1,IGL@,FBLN1,IFI30,COL4A1,MIF,IGHG3,IGKC +MHC class I protein complex HLA-J,HLA-J,RPLP2,HLA-B,HLA-E,C6orf12,HLA-F,HLA-A,HLA-G,HLA-C +heterogeneous nuclear ribonucleoprotein com... HNRPH3,HNRPH3,HNRPU,HNRPH1,HNRPR,HNRPDL,HNRPA2B1,HNRPA1 +mitochondrial inner membrane NDUFA7,NDUFA7,SLC25A16,UCP2,SLC25A11,SLC25A3,NDUFV1 +extracellular space CNOT2,CNOT2,IL16,AD7C-NTP,FBLN1,TGFB1,MMP2,SPN,TPT1 +nucleoplasm IFI16,IFI16,NDUFA13,ZNF638,XPO1,ISG20,RNPC2,HNRPA1 +collagen COL1A1,COL1A1,COL6A1,COL4A2,COL4A1,COL3A1,COL1A2 +nucleolus RPL35,RPL35,RPS19,IFI16,NCL,EXOSC4,NPM1,RPS7 +spliceosome complex HNRPM,HNRPM,HIATL1,SF3B1,HNRPA2B1,HNRPA1 +proton-transporting two-sector ATPase complex ATP6V0B,ATP6V0B,ATP6V0C,ATP5D,ATP5G3 +extracellular matrix (sensu Metazoa) LAMC1,LAMC1,FBLN1,DGCR6,COL6A3,TGFB1 +perinuclear region 217718_s_at,217718_s_at,HSP90B1,SET +DNA-directed RNA polymerase II, core complex POLR2J,POLR2J,HCLS1,HMHA1,POLR2E +actin cytoskeleton MARCKS,MARCKS,FNBP4,CORO1A,SMTN +cAMP-dependent protein kinase complex PRKAR1A,PRKAR1A,PRKAR2A,PRKACB +Arp2/3 protein complex ACTR3,ACTR3,ARPC1B,ARPC3,ARPC5 +lysosome HLA-DRA,HLA-DRA,LAPTM5,IFI30 +large ribosomal subunit RPL7,RPL7,RPL26,RPL13A,RPL17 +Golgi apparatus RGS19,RGS19,RAB6A,RAB6C,NAPA +soluble fraction NCF1,NCF1,FBLN1,NARS,PPP2CA +eukaryotic translation initiation factor 4F... EIF4G1,EIF4G1,EIF4A2,EIF4G2 +proton-transporting ATP synthase complex (s... ATP5J2,ATP5J2,ATP5D,ATP5G3 +microsome SPCS2,SPCS2,TAPBP,HSP90B1 +cytosolic ribosome (sensu Eukaryota) LOC388344,LOC388344,RPL13 +Golgi membrane TAPBP,TAPBP,VDP,CAV1,COPB +transcription factor complex LOC342346,LOC342346,SUB1 +endoplasmic reticulum membrane TAPBP,TAPBP,HSP90B1,KTN1 +actin filament ACTA2,ACTA2,ACTG2,IQGAP1 +proteasome complex (sensu Eukaryota) PSMB3,PSMB3,PSMB9,PSMB8 +nuclear envelope PAFAH1B1,PAFAH1B1,XPO1 +endoplasmic reticulum lumen CAST,CAST,PPIB,HSP90B1 +stress fiber PLEKHC1,PLEKHC1,SEPT7 +small ribosomal subunit RPS5,RPS5,MRPS12,RPS2 +mitochondrial electron transport chain UQCRC1,UQCRC1,NDUFA13 +mitochondrial ribosome MRPS12,MRPS12,MRPL34 +mitochondrial inner membrane presequence tr... TIMM8B,TIMM8B,TIMM13 +mediator complex THRAP5,THRAP5,THRAP1 +collagen type VI COL6A3,COL6A3,COL6A1 +ER-Golgi intermediate compartment P4HB,P4HB,TMED5,KTN1 +respiratory chain complex III (sensu Eukary... UQCRQ,UQCRQ,UQCRFS1 +eukaryotic translation elongation factor 1 ... EEF1B2,EEF1B2,EEF1D +cytoplasmic membrane-bound vesicle ARHGDIB,ARHGDIB,DST +microtubule associated complex MEFV,MEFV,PAFAH1B1 +ubiquitin ligase complex RNF11,RNF11,UBE4A +protein complex PSMB9,PSMB9,PSMB8 +proteasome core complex (sensu Eukaryota) PSMB9,PSMB9,PSMB8 +nuclear pore KPNB1,KPNB1,RGPD5 +integrin complex ITGAV,ITGAV,ITGB2 +signal recognition particle (sensu Eukaryota) SRP72,SRP72,SRP9 +cell surface P4HB,P4HB,ATPIF1 +myosin MYH9,MYH9,MYH11 +mitochondrial envelope UCRC,UCRC,COX5B +centrosome NPM1,NPM1,CEP27 +basement membrane LAMC1,LAMC1,DST +mitochondrial matrix MDH2,MDH2,ETFB +COPI vesicle coat COPE,COPE,COPB +pericentriolar material PCM1,PCM1,LCK +intermediate filament DES,DES,RPL38 +lipid raft LCK,LCK,CAV1 diff --git a/www/Examples/Human_Coexpression/NORMA_Human_coexpression_Annotation_GO_MF.txt b/www/Examples/Human_Coexpression/NORMA_Human_coexpression_Annotation_GO_MF.txt new file mode 100644 index 0000000..9c3e94a --- /dev/null +++ b/www/Examples/Human_Coexpression/NORMA_Human_coexpression_Annotation_GO_MF.txt @@ -0,0 +1,114 @@ +protein binding TARDBP,TARDBP,ITGAV,CAST,RPS15,PHIP,NFE2L2,OAZ1,STAT1,SEPT2,TXNL2,ORC6L,IL2RG,RGS19,EIF4G1,RPS13,C1orf160,RAB6A,HLA-DMA,ZNHIT1,GPAA1,CUL4B,HLA-J,KPNB1,ARF1,IL16,CD48,CBX3,G3BP,SUMO2,ACTA2,TCEB2,EIF3S6,MT1H,RPS19,INPP5D,RAB6C,RNF11,PRKAR1A,NCF1,ZMYND11,HNRPK,SUMO1,TGFB1I1,CDC5L,KNS2,RBPMS,CAB39,SFPQ,CD3D,NAPA,ACTR3,CLTC,TTC3,EIF4A2,IFI16,ARL6IP5,EEF1B2,HCLS1,PSMB8,HMHA1,HSP90AA1,HNRPH1,SRP46,EIF4G2,FIS1,PLEKHC1,CD2,OGT,TAF7,217718_s_at,NARS,C6orf12,TGFB1,CDKN1B,NDUFA13,GPSM3,BCLAF1,HSP90B1,SERBP1,GTF2I,RPS6,U16,BIRC2,RPL35A,HLA-A,RPS15A,EXOSC4,RPS20,RPL38,ACTG2,CAV1,ACTR2,SKP1A,ACTR10,MIF,PCNP,RPS3A,RPL14,HLA-G,IL7R,AURKAIP1,FIBP,EIF3S3,HNRPDL,RPS27A,RAC2,ITGB2,COPS2,XPO1,SIAHBP1,POLR2E,NAP1L1,RPL4,SFRS5,HNRPA2B1,EEF1A1,UBE2D2,SEPT7,COPB,ATP5G3,RPL5,RPS7,RPA1,HNRPA1,RPL24 +RNA binding TARDBP,TARDBP,RPS5,HNRPM,LOC56902,EIF4G1,RPL18,RPL21,SFRS10,RPLP2,G3BP,HNRPH3,HNRPU,DDX42,RPS19,HNRPK,RBPMS,LOC440055,RPS27,LOC388344,SFPQ,DDX17,RPL27A,RPS10,RPS17,EIF4A2,RPL28,LOC283412,RPS14,HNRPH1,SRP46,EIF4G2,HNRPR,NCL,RPL7,HSP90B1,SRP9,HNRPA3P1,RPS2,U16,DDX5,ZNF638,RPL18A,RPL13,RPL29,SFRS11,DDX50,NPM1,RPS18,RPL14,PAPOLA,RPL22,MATR3,HNRPDL,RPL34,SCAND1,RPL9,RPL6,SIAHBP1,RPL4,RPS4X,SFRS5,SFRS3,HNRPA2B1,RPS9,RNPC2,RPL5,MDS1,LOC402057,HNRPA1 +structural constituent of ribosome RPS15,RPS15,RPL37,RPS5,RPL35,FAU,RPS11,RPS21,RPL18,RPS13,RPL21,RPL36,RPL12,RPLP2,RPS19,RPL27,RPL31,MRPS12,LOC440055,RPS27,LOC388344,RPL27A,RPS10,RPS17,RPL28,LOC283412,RPL19,RPS16,RPS14,RPL7,RPS6,RPS2,U16,RPL18A,RPL13,RPL29,RPS15A,RPS20,RPS3A,RPS18,RPL14,MRPL34,RPL22,RPL34,RPS27A,RPS23,RPL15,RPL9,RPL6,RPL26,RPL4,RPS4X,RPS24,RPS9,RPL13A,RPL17,RPL5,RPL23,MDS1,RPS7,LOC402057,RPS25 +nucleotide binding TARDBP,TARDBP,HNRPM,RAP1B,MCM3AP,RAB1A,RAB6A,RAVER2,SFRS10,G3BP,HNRPH3,ACTA2,DDX42,RAB6C,PRKD2,RBPMS,YME1L1,SFPQ,DDX17,EIF4A2,HSP90AA1,HNRPH1,SRP46,NARS,HNRPR,NCL,PCM1,HSP90B1,HNRPA3P1,U16,DDX5,ACTG2,SFRS11,DDX50,CSNK1A1,EIF3S3,MATR3,HNRPDL,DDX3X,SIAHBP1,RPL4,SFRS5,HNRPA2B1,EEF1A1,RNPC2,SEPT7,PRKACB,HNRPA1 +nucleic acid binding TARDBP,TARDBP,ZFR,HNRPM,LOC56902,MGC2474,RPS11,SFRS10,G3BP,HNRPH3,ZNF9,DDX42,HNRPK,ZNF160,MRPS12,SFPQ,DDX17,R3HCC1,EIF4A2,IFI16,HNRPH1,SRP46,NARS,ZNF611,SON,HNRPR,DDX5,SFRS11,DDX50,ZNF552,NPM1,MBNL1,MATR3,HNRPDL,DDX3X,SIAHBP1,SFRS5 +ATP binding NDUFA10,NDUFA10,AKT1,RAVER2,ACTA2,DDX42,PRKD2,MYH9,220725_x_at,YME1L1,DDX17,EIF4A2,HSP90AA1,208246_x_at,DHX15,NARS,ROCK1,NDUFA13,PCM1,HSP90B1,ATP2A3,RPS2,U16,DDX5,LCK,MYH11,ACTG2,DDX50,CSNK1A1,EIF3S3,DDX3X,RPL4,PRKACB +receptor activity ITGAV,ITGAV,HNRPM,IL2RG,CXCR4,THRAP5,PTPRCAP,RPL27,IL10RA,THRAP1,TLOC1,HLA-DRB5,HLA-DRB1,HLA-DRB4,CD2,IFNGR1,TRBV3-1,IGHA1,U16,CD7,IGHG3,IL7R,IL6ST,RPL4,EEF1A1,IGHM,TRAM1 +MHC class I receptor activity HLA-J,HLA-J,RPLP2,221651_x_at,IGLV3-10,IGHD,HLA-B,IGL@,IGLC1,HLA-E,IGLV3-25,C6orf12,IGLC2,214836_x_at,IGHV1-69,IGHA1,HLA-F,HLA-A,IGHG3,IGLJ3,HLA-G,HLA-C,IGKC,IGHM +zinc ion binding CAST,CAST,ZFR,MT1E,MT1F,KPNB1,MSRB2,TIMM8B,ZNF9,DDX42,RNF11,PRKD2,SDHA,ZMYND11,ZNF160,MEFV,RPS27,TTC3,ZNF611,TIMM13,POLR2I,MMP2,ZNF552,MBNL1,MATR3 +binding SRP72,SRP72,VDP,CAPZA1,TTC19,KPNB1,SLC25A16,MSN,UCP2,KNS2,CAB39,RGPD5,NAPA,SLC25A11,TTC3,SLC25A3,ALOX5AP,HIATL1,OGT,CHCHD2,SF3B1,COPS2,COPE,COPB +DNA binding MCM3AP,MCM3AP,HNRPU,RNF11,IRF7,SDHA,POLR2L,POLR2J,CDC5L,SFPQ,POLR1B,SON,HMGB1,PCM1,BCLAF1,CSDE1,RPL6,LOC342346,SUB1,LOC58486,H3F3A +NADH dehydrogenase (ubiquinone) activity NDUFC1,NDUFC1,NDUFA10,NDUFA7,NDUFB6,NDUFB2,NDUFA2,NDUFV1,NDUFA3,NDUFA13,NDUFS7,NDUFS3,NDUFS8,NDUFB4,NDUFAB1 +MHC class II receptor activity HLA-DPB1,HLA-DPB1,HLA-DMA,HLA-DQA1,HLA-DRA,HLA-DMB,HLA-DRB5,HLA-DRB1,HLA-DRB4,HLA-DQB1,HLA-DPA1,HLA-C +electron carrier activity P4HB,P4HB,MT1X,MT1L,NCF1,UQCR,CYBA,FLJ14346,NDUFS3,NDUFS8,COX5A,ETFB,KTN1,AKR7A2,CYC1 +GTPase activity SEPT2,SEPT2,RAB6A,ARF1,RAB6C,NCF1,ARL6IP2,ARF5,ARL8B,RPL29,EIF5,RAC2,EEF1A1 +antigen binding IGL@,IGL@,IGLC1,IGLV3-25,IGLC2,IGHV1-69,IGHA1,IGHG3,IGLJ3,IL7R,IGKC,IGHM +transferase activity FNTA,FNTA,PRKD2,POLR2J,POLR1B,COL6A3,NARS,RPS2,U16,CSNK1A1,RPL4,PRKACB +transcription factor activity TARDBP,TARDBP,NFE2L2,STAT1,LYSMD4,MSRB2,TRIM22,HCLS1,GTF2I,SCAND1,MDS1 +metal ion binding MT1X,MT1X,ZFR,MT1M,MT1L,PRKD2,ZNF160,TTC3,ZNF611,ZNF552,MATR3,NDUFS8 +structural molecule activity DES,DES,FNBP4,CORO1A,NPEPPS,CLTC,COL6A3,RPL38,CAV1,MATR3,SEPT7 +GTP binding RAP1B,RAP1B,RAB1A,RAB6A,RAB6C,NCF1,ARL6IP2,ARL8B,EEF1A1,SEPT7 +extracellular matrix structural constituent LAMC1,LAMC1,FBLN1,COL1A1,COL6A1,COL4A2,COL4A1,COL3A1,COL1A2 +structural constituent of cytoskeleton DES,DES,ADD3,ACTA2,TPM1,MSN,ARPC1B,DST,ACTG2,ARPC3,ARPC5 +hydrolase activity DDX42,DDX42,PPP1CA,DDX17,EIF4A2,PPP2CA,DDX5,DDX50,DDX3X +unfolded protein binding TAPBP,TAPBP,PPIB,HSP90AA1,PTGES3,HSP90B1,NPM1,EIF3S3 +transporter activity G3BP,G3BP,UCP2,ATP6V0B,SLC25A11,SLC25A3,ATP5D,ATP5G3 +kinase activity GUK1,GUK1,MYLK,PRKAR2A,WSB1,208246_x_at,ROCK1,CDKN1B +iron ion binding ACO2,ACO2,MT1X,MT1L,PPP1CA,NDUFV1,PPP2CA,NDUFS8,CYC1 +DNA-directed RNA polymerase activity POLR2L,POLR2L,POLR2J,HMHA1,POLR1B,PCM1,POLR2I,POLR2E +ATP-dependent helicase activity DDX42,DDX42,DDX17,EIF4A2,DHX15,DDX5,DDX50,DDX3X,DDX1 +protein serine/threonine kinase activity AKT1,AKT1,PRKD2,ROCK1,RPS2,U16,CSNK1A1,RPL4,PRKACB +calcium ion binding MASP1,MASP1,SPARCL1,STAT1,FBLN1,HSP90B1,IGHG3,TPT1 +actin binding CNN1,CNN1,CALD1,CAPZA1,GMFG,SMTN,MEFV,NPEPPS,FXYD5 +protein homodimerization activity ATPIF1,ATPIF1,HSP90AA1,U16,NPM1,EIF3S3,RPL4 +signal transducer activity STAT1,STAT1,RGS19,BIRC2,HNRPDL,EEF1D,COPS2 +oxidoreductase activity NDUFA10,NDUFA10,GPX1,MDH2,GPX4,IGLC2,PRDX2 +transcription coactivator activity TGFB1I1,TGFB1I1,TAF7,NPM1,LOC342346,SUB1 +translation initiation factor activity EIF4G1,EIF4G1,EIF4A2,EIF4G2,EIF5,EIF3S3 +protein-tyrosine kinase activity RAVER2,RAVER2,PCM1,U16,LCK,HNRPDL,RPL4 +catalytic activity KIAA1840,KIAA1840,LOC91316,DIP2A,PDE4C +hydrogen-transporting ATPase activity, rota... ATP6V0B,ATP6V0B,ATP6V0C,ATP5D,ATP5G3 +hydrogen-transporting ATP synthase activity... ATP6V0B,ATP6V0B,ATP6V0C,ATP5D,ATP5G3 +hematopoietin/interferon-class (D200-domain... STAT1,STAT1,IL2RG,IL10RA,IFNGR1,IL7R +oxidoreductase activity, acting on NADH or ... NDUFV1,NDUFV1,NDUFS7,NDUFS3,NDUFS8 +single-stranded DNA binding HNRPDL,HNRPDL,LOC342346,SUB1,RPA1 +amino acid-polyamine transporter activity SLC38A2,SLC38A2,218041_x_at,RPL24 +receptor binding CCL5,CCL5,ARPP-19,MSN,LTB,GNB2L1 +calmodulin binding CALD1,CALD1,MARCKS,ATPIF1,IQGAP1 +cytochrome-c oxidase activity COX4I1,COX4I1,COX5B,COX5A,COX8A +ubiquinol-cytochrome-c reductase activity UCRC,UCRC,UQCRQ,UQCRC1,UQCRFS1 +protein transporter activity VDP,VDP,KPNB1,TLOC1,AP2S1,COPE +translation elongation factor activity TUFM,TUFM,EEF1B2,EEF1D,EEF1A1 +peptide antigen binding TAPBP,TAPBP,TRB@,TRBV3-1,TRA@ +microtubule motor activity 220725_x_at,220725_x_at,KNS2 +phosphotransferase activity, alcohol group ... NDUFA10,NDUFA10,208246_x_at +oxygen transporter activity SLC38A2,SLC38A2,218041_x_at +RNA helicase activity DDX17,DDX17,DHX15,DDX5,DDX1 +growth factor activity CECR1,CECR1,GMFG,PGF,TGFB1 +RNA splicing factor activity, transesterifi... SFRS10,SFRS10,HIATL1,SF3B1 +heparin binding LOC283412,LOC283412,RPL29 +double-stranded DNA binding IFI16,IFI16,ZNF638,HNRPDL +RNA polymerase II transcription mediator ac... CNOT2,CNOT2,THRAP5,THRAP1 +nitric-oxide synthase regulator activity HSP90AA1,HSP90AA1,EIF3S3 +isomerase activity P4HB,P4HB,ECH1,PPIB,KTN1 +TPR domain binding HSP90AA1,HSP90AA1,EIF3S3 +ubiquitin-protein ligase activity UBE4A,UBE4A,TPT1,UBE2D2 +protein domain specific binding YWHAZ,YWHAZ,217718_s_at +cAMP-dependent protein kinase regulator act... PRKAR1A,PRKAR1A,PRKAR2A +transcriptional repressor activity IRF7,IRF7,IFI16,BCLAF1 +protein kinase binding U16,U16,LCK,ITGB2,RPL4 +general RNA polymerase II transcription fac... TCEA1,TCEA1,TAF7,GTF2I +MHC protein binding TRB@,TRB@,TRBV3-1,TRA@ +ATP-dependent RNA helicase activity G3BP,G3BP,RPL35A,DDX3X +protein heterodimerization activity CD3D,CD3D,PPP2CA,NPM1 +peptidase activity MASP1,MASP1,ZNF9,CLPP +identical protein binding AKT1,AKT1,CD74,SCAND1 +vitamin D receptor binding THRAP5,THRAP5,THRAP1 +thyroid hormone receptor binding THRAP5,THRAP5,THRAP1 +serine-type endopeptidase inhibitor activity NFE2L2,NFE2L2,COL6A3 +sequence-specific DNA binding NFE2L2,NFE2L2,LYSMD4 +protein dimerization activity NFE2L2,NFE2L2,POLR2J +motor activity MYH9,MYH9,KNS2,MYH11 +copper ion binding MT1E,MT1E,MT1F,DDX42 +cadmium ion binding MT1E,MT1E,MT1F,DDX42 +transmembrane receptor activity CD3D,CD3D,CD79A,SPN +translation factor activity, nucleic acid b... EIF3S3,EIF3S3,EEF1D +transcriptional activator activity THRAP5,THRAP5,TGFB1 +3'-5'-exoribonuclease activity EXOSC4,EXOSC4,ISG20 +tropomyosin binding CALD1,CALD1,LMOD1 +transcription factor binding YWHAZ,YWHAZ,HMGB1 +threonine endopeptidase activity PSMB9,PSMB9,PSMB8 +serine-type endopeptidase activity MASP1,MASP1,IGHG3 +peroxidase activity CSDE1,CSDE1,PRDX2 +enzyme activator activity GMFG,GMFG,ALOX5AP +antioxidant activity RPL27,RPL27,PRDX2 +actin filament binding MARCKS,MARCKS,DST +acetylglucosaminyltransferase activity COL6A3,COL6A3,OGT +ATPase binding ATPIF1,ATPIF1,LCK +transcription regulator activity RPL7,RPL7,RPS27A +sugar binding MASP1,MASP1,SELL +ligase activity NARS,NARS,UBE2D2 +cytokine binding CD74,CD74,IFNGR1 +aminopeptidase activity CAST,CAST,NPEPPS +protein phosphatase inhibitor activity PSMB9,PSMB9,SET +succinate dehydrogenase activity SDHA,SDHA,RPA1 +structural constituent of muscle TPM1,TPM1,SMTN +protein disulfide oxidoreductase activity P4HB,P4HB,KTN1 +protein disulfide isomerase activity P4HB,P4HB,KTN1 +ornithine decarboxylase inhibitor activity OAZ2,OAZ2,OAZ1 +glutathione peroxidase activity GPX1,GPX1,GPX4 +double-stranded RNA binding SON,SON,MBNL1 +CD4 receptor binding LCK,LCK,SPG21 +MAP kinase kinase kinase activity U16,U16,RPL4 +protein C-terminus binding DST,DST,LCK diff --git a/www/Examples/Human_Coexpression/NORMA_Human_coexpression_Annotation_KEGG.txt b/www/Examples/Human_Coexpression/NORMA_Human_coexpression_Annotation_KEGG.txt new file mode 100644 index 0000000..1d2de7e --- /dev/null +++ b/www/Examples/Human_Coexpression/NORMA_Human_coexpression_Annotation_KEGG.txt @@ -0,0 +1,56 @@ +Ribosome RPS5,RPS5,RPL35,FAU,RPL18,RPL21,RPL36,RPL12,RPLP2,RPS19,RPL27,RPL10A,LOC440055,RPS27,LOC388344,RPL27A,RPS10,RPS17,RPL28,LOC283412,RPL23A,RPL36A,RPL7,RPS2,U16,RPL35A,RPL18A,RPL13,RPL29,RPS15A,RPS3A,RPL14,RPL22,RPL34,RPS27A,RPL9,RPL6,RPL4,RPS4X,RPS9,RPL13A,RPL17,RPL5,MDS1,LOC402057 +Oxidative phosphorylation NDUFC1,NDUFC1,ATP5J2,NDUFA10,NDUFA7,COX4I1,ATP6V0D1,NDUFB6,UCRC,SDHA,ATP6V0B,UQCRC1,NDUFB2,UQCRFS1,NDUFA2,NDUFV1,ATP6V0C,NDUFA3,NDUFA13,NDUFS7,COX5B,ATP5D,NDUFS3,NDUFS8,COX5A,NDUFB4,NDUFAB1,ATP5G3,CYC1,COX8A,RPA1 +Antigen processing and presentation HLA-DPB1,HLA-DPB1,TAPBP,HLA-DMA,HLA-DQA1,HLA-J,HLA-B,HLA-DRA,HLA-DMB,HLA-DRB5,CD74,HLA-DRB1,HLA-E,HLA-DRB4,HSP90AA1,C6orf12,HLA-DQB1,HLA-DPA1,IFI30,HLA-A,HLA-G,EIF3S3,HLA-C +Cell adhesion molecules (CAMs) ITGAV,ITGAV,HLA-DPB1,HLA-DMA,HLA-DQA1,HLA-J,HLA-B,HLA-DRA,HLA-DMB,SELL,HLA-DRB5,HLA-DRB1,HLA-E,HLA-DRB4,CD2,C6orf12,HLA-DQB1,HLA-DPA1,HLA-A,SPN,HLA-G,ITGB2,HLA-C +Type I diabetes mellitus HLA-DPB1,HLA-DPB1,HLA-DMA,HLA-DQA1,HLA-J,HLA-B,HLA-DRA,HLA-DMB,HLA-DRB5,HLA-DRB1,HLA-E,HLA-DRB4,C6orf12,HLA-DQB1,HLA-DPA1,HLA-A,HLA-G,HLA-C +Focal adhesion ITGAV,ITGAV,AKT1,RAP1B,LAMC1,PGF,MYLK,COL6A3,COL1A1,COL6A1,ROCK1,COL4A2,COL4A1,BIRC2,COL3A1,COL1A2,CAV1,RAC2 +Natural killer cell mediated cytotoxicity HLA-J,HLA-J,CD48,HLA-B,HLA-E,C6orf12,IFNGR1,HLA-A,LCK,HLA-G,RAC2,ITGB2,HLA-C +Regulation of actin cytoskeleton ITGAV,ITGAV,MSN,MYH9,MYLK,ARPC1B,ROCK1,ARPC3,ARPC5,IQGAP1,RAC2,ITGB2 +Cell Communication DES,DES,LAMC1,COL6A3,COL1A1,COL6A1,COL4A2,COL4A1,COL3A1,COL1A2,RPL38 +Pyrimidine metabolism POLR2L,POLR2L,POLR2J,HMHA1,POLR1B,208246_x_at,POLR2I,RPS15A,POLR2E +ECM-receptor interaction ITGAV,ITGAV,LAMC1,COL6A3,COL1A1,COL6A1,COL4A2,COL4A1,COL3A1,COL1A2 +Purine metabolism GUK1,GUK1,POLR2L,POLR2J,HMHA1,POLR1B,POLR2I,RPS15A,POLR2E,PDE4C +Hematopoietic cell lineage CD37,CD37,HLA-DRA,CD3D,HLA-DRB5,HLA-DRB1,HLA-DRB4,CD2,CD7,IL7R +Cytokine-cytokine receptor interaction IL2RG,IL2RG,CXCR4,CCL5,IL10RA,LTB,IFNGR1,TGFB1,IL7R,IL6ST +Leukocyte transendothelial migration RAP1B,RAP1B,CXCR4,NCF1,MSN,CYBA,ROCK1,MMP2,RAC2,ITGB2 +Jak-STAT signaling pathway AKT1,AKT1,STAT1,IL2RG,RAVER2,IL10RA,IFNGR1,IL7R,IL6ST +Cell cycle ORC6L,ORC6L,YWHAZ,217718_s_at,TGFB1,CDKN1B,SKP1A +RNA polymerase POLR2L,POLR2L,POLR2J,HMHA1,POLR1B,POLR2I,POLR2E +Apoptosis AKT1,AKT1,PRKAR1A,ENDOG,PRKAR2A,BIRC2,PRKACB +Cholera - Infection SEC61A1,SEC61A1,ATP6V0D1,ATP6V0B,ATP6V0C +Pathogenic Escherichia coli infection - EPEC HCLS1,HCLS1,YWHAZ,ROCK1,NCL,RPL38,ARPC5 +Pathogenic Escherichia coli infection - EHEC HCLS1,HCLS1,YWHAZ,ROCK1,NCL,RPL38,ARPC5 +Epithelial cell signaling in Helicobacter pylori infection ATP6V0D1,ATP6V0D1,CCL5,ATP6V0B,ATP6V0C +Wnt signaling pathway ROCK1,ROCK1,SKP1A,CSNK1A1,RAC2,PRKACB +Pancreatic cancer AKT1,AKT1,STAT1,RAVER2,PGF,TGFB1,RAC2 +MAPK signaling pathway AKT1,AKT1,RAP1B,TGFB1,RAC2,PRKACB +Insulin signaling pathway AKT1,AKT1,PRKAR1A,PRKAR2A,PRKACB +Protein export SEC61A1,SEC61A1,SRP72,SRP9 +Ubiquitin mediated proteolysis TCEB2,TCEB2,SKP1A,UBE2D2 +Citrate cycle (TCA cycle) ACO2,ACO2,SDHA,MDH2,RPA1 +TGF-beta signaling pathway ROCK1,ROCK1,TGFB1,SKP1A +Calcium signaling pathway MYLK,MYLK,ATP2A3,PRKACB +Hedgehog signaling pathway CSNK1A1,CSNK1A1,PRKACB +Chronic myeloid leukemia AKT1,AKT1,TGFB1,CDKN1B +Axon guidance CXCR4,CXCR4,ROCK1,RAC2 +Toll-like receptor signaling pathway AKT1,AKT1,STAT1,CCL5 +Tight junction AKT1,AKT1,MYH9,HCLS1 +Glycan structures - degradation POPDC3,POPDC3,MAN2B1 +Colorectal cancer AKT1,AKT1,TGFB1,RAC2 +B cell receptor signaling pathway AKT1,AKT1,CD79A,RAC2 +Prion disease NFE2L2,NFE2L2,LAMC1 +T cell receptor signaling pathway AKT1,AKT1,CD3D,LCK +Long-term potentiation RAP1B,RAP1B,PRKACB +Adherens junction IQGAP1,IQGAP1,RAC2 +Glycan structures - biosynthesis 2 COL6A3,COL6A3,OGT +GnRH signaling pathway MMP2,MMP2,PRKACB +Adipocytokine signaling pathway AKT1,AKT1,RAVER2 +Basal transcription factors TAF7,TAF7,GTF2I +VEGF signaling pathway AKT1,AKT1,RAC2 +Reductive carboxylate cycle (CO2 fixation) ACO2,ACO2,MDH2 +Glyoxylate and dicarboxylate metabolism ACO2,ACO2,MDH2 +Glutathione metabolism GPX1,GPX1,GPX4 +Fc epsilon RI signaling pathway AKT1,AKT1,RAC2 +Arachidonic acid metabolism GPX1,GPX1,GPX4 +mTOR signaling pathway AKT1,AKT1,PGF +Tyrosine metabolism ECH1,ECH1,MIF diff --git a/www/Examples/Human_Coexpression/NORMA_Human_coexpression_Expression_MCODE.txt b/www/Examples/Human_Coexpression/NORMA_Human_coexpression_Expression_MCODE.txt new file mode 100644 index 0000000..b663b07 --- /dev/null +++ b/www/Examples/Human_Coexpression/NORMA_Human_coexpression_Expression_MCODE.txt @@ -0,0 +1,557 @@ +207730_x_at green +214836_x_at green +215176_x_at green +215182_x_at green +216342_x_at green +216524_x_at green +217281_x_at green +220725_x_at green +221651_x_at green +ACTA2 green +ACTR2 green +ACTR3 green +AD7C-NTP green +AP2S1 green +ARF5 green +ARHGDIB green +ARL6IP2 green +ARPC3 green +ATP8B1 green +ATRX green +AURKAIP1 green +BIRC2 green +C6orf12 green +CAV1 green +CD52 green +CD74 green +CDC5L green +CEP27 green +CHCHD2 green +COL1A1 green +COL1A2 green +COL3A1 green +COL6A1 green +COPE green +COX5A green +COX5B green +COX8A green +CROP green +CTA-246H3.1 green +CYBA green +DBT green +DDT green +DDX3X green +DDX5 green +EIF3S3 green +EIF3S6 green +EIF4G2 green +FAU green +FBLN1 green +FBXW12 green +FLJ11021 green +FLJ12151 green +FLJ20294 green +FLJ42393 green +GNB2L1 green +H3F3A green +HIATL1 green +HLA-A green +HLA-B green +HLA-C green +HLA-DMA green +HLA-DPA1 green +HLA-DQB1 green +HLA-DRB1 green +HLA-DRB4 green +HLA-DRB5 green +HLA-E green +HLA-F green +HLA-G green +HLA-J green +HNRPDL green +HNRPH3 green +IFI30 green +IGHA1 green +IGHG3 green +IGHM green +IGHV1-69 green +IGKC green +IGKV1-5 green +IGKV1D-13 green +IGKV1OR15-118 green +IGKV1OR2-108 green +IGL@ green +IGLC1 green +IGLC2 green +IGLJ3 green +IGLV3-25 green +IQGAP1 green +KNS2 green +LAPTM5 green +LCK green +LMOD1 green +LOC152719 green +LOC388344 green +LOC440055 green +LOC91316 green +MAN2B1 green +MATR3 green +MBNL1 green +MCM3AP green +MDS1 green +MGEA5 green +MORF4L1 green +MRPL34 green +MT1E green +MT1F green +MT1G green +MT1H green +MT1L green +MT1M green +MT1X green +MT2A green +MYH11 green +NACA green +NAP1L1 green +NARS green +NDUFA2 green +NDUFA3 green +NDUFAB1 green +NDUFB11 green +NDUFB2 green +NDUFB4 green +NDUFS3 green +NDUFS7 green +NPM1 green +PAPOLA green +PCNP green +PDE4C green +PFAAP5 green +PGF green +PNRC2 green +POLR2J green +PRG1 green +PRR11 green +PTGES3 green +RAC2 green +RIOK3 green +ROCK1 green +RPL11 green +RPL13 green +RPL13A green +RPL17 green +RPL18 green +RPL21 green +RPL22 green +RPL23 green +RPL24 green +RPL27 green +RPL27A green +RPL28 green +RPL29 green +RPL30 green +RPL34 green +RPL35A green +RPL36 green +RPL36A green +RPL38 green +RPL4 green +RPL5 green +RPL6 green +RPL7 green +RPL9 green +RPLP2 green +RPS14 green +RPS17 green +RPS18 green +RPS19 green +RPS2 green +RPS23 green +RPS24 green +RPS25 green +RPS27A green +RPS3A green +RPS4X green +RPS5 green +RPS6 green +RPS7 green +RPS9 green +SEPT2 green +SERBP1 green +SFRS11 green +SH3BGRL green +SKP1A green +SLC35E1 green +SON green +SUMO2 green +TAF7 green +TLOC1 green +TRA@ green +TRB@ green +TUG1 green +U16 green +UQCR green +UQCRC1 green +UQCRFS1 green +USP34 green +XPO1 green +YTHDC1 green +ZNF160 green +ZNF611 green +ZNF638 green +ZNHIT1 green +208246_x_at yellow +211637_x_at yellow +211645_x_at yellow +ATP5G3 yellow +ATP6V0B yellow +ATP6V0D1 yellow +BCLAF1 yellow +CAPZA1 yellow +COL6A3 yellow +CXCR4 yellow +HLA-DPB1 yellow +HNRPH1 yellow +IFI16 yellow +LOC342346 yellow +LOC56902 yellow +LOC58486 yellow +LOC645745 yellow +MEFV yellow +MRPS12 yellow +NDUFS8 yellow +PTRF yellow +RPL31 yellow +RPL35 yellow +RPS11 yellow +TAGLN yellow +TGFB1 yellow +TRBC1 yellow +208120_x_at red +208238_x_at red +211639_x_at red +211641_x_at red +211650_x_at red +211908_x_at red +212498_at red +216412_x_at red +216858_x_at red +217052_x_at red +217258_x_at red +217679_x_at red +217718_s_at red +218041_x_at red +AASDHPPT red +ACO2 red +ACTG2 red +ACTR10 red +ADD3 red +ADRM1 red +AKR7A2 red +AKT1 red +ALOX5AP red +ARF1 red +ARL6IP5 red +ARL8B red +ARPC1B red +ARPC5 red +ARPP-19 red +ATP2A3 red +ATP5D red +ATP5J2 red +ATP6AP2 red +ATP6V0C red +ATPIF1 red +BTF3 red +C11orf2 red +C11orf58 red +C12orf10 red +C12orf38 red +C16orf24 red +C17orf62 red +C1orf160 red +C1orf63 red +C21orf33 red +C3orf60 red +CAB39 red +CALD1 red +CAP1 red +CAPNS1 red +CAST red +CBX3 red +CCL5 red +CCNL1 red +CD164 red +CD2 red +CD37 red +CD3D red +CD48 red +CD53 red +CD7 red +CD79A red +CDKN1B red +CECR1 red +CHMP2A red +CLPP red +CLPTM1 red +CLTC red +CNN1 red +CNOT2 red +COL4A1 red +COL4A2 red +COPB red +COPS2 red +COQ9 red +CORO1A red +COX4I1 red +CSDE1 red +CSNK1A1 red +CUL4B red +CXorf9 red +CYC1 red +DDX1 red +DDX17 red +DDX42 red +DDX50 red +DES red +DEXI red +DGCR6 red +DHX15 red +DIP2A red +DKFZP566N034 red +DST red +DYNLT3 red +ECH1 red +EEF1A1 red +EEF1B2 red +EEF1D red +EIF4A2 red +EIF4G1 red +EIF5 red +ENDOG red +ERH red +ETFB red +EXOSC4 red +FAIM3 red +FAM96B red +FIBP red +FIS1 red +FLJ10154 red +FLJ14346 red +FNBP4 red +FNTA red +FXYD5 red +G3BP red +GBL red +GLTSCR2 red +GMFG red +GOLGA8A red +GOLGA8B red +GPAA1 red +GPSM3 red +GPX1 red +GPX4 red +GTF2I red +GUK1 red +HCLS1 red +HLA-DMB red +HLA-DQA1 red +HLA-DRA red +HMGB1 red +HMHA1 red +HNRPA1 red +HNRPA2B1 red +HNRPA3P1 red +HNRPK red +HNRPM red +HNRPR red +HNRPU red +HSP90AA1 red +HSP90B1 red +IFNGR1 red +IGHD red +IGLV3-10 red +IL10RA red +IL16 red +IL2RG red +IL6ST red +IL7R red +INPP5D red +IRF7 red +ISG20 red +ITGAV red +ITGB2 red +KIAA0907 red +KIAA1840 red +KIDINS220 red +KPNB1 red +KTN1 red +LAMC1 red +LOC283412 red +LOC402057 red +LRRFIP1 red +LTB red +LYSMD4 red +MARCKS red +MASP1 red +MDH2 red +MGC2474 red +MIF red +MMP2 red +MRP63 red +MSN red +MSRB2 red +MYH9 red +MYLK red +NAPA red +NBPF1 red +NBPF12 red +NCF1 red +NCL red +NDUFA10 red +NDUFA13 red +NDUFA7 red +NDUFB6 red +NDUFC1 red +NDUFV1 red +NFE2L2 red +NPEPPS red +NPTN red +OAZ1 red +OAZ2 red +OGT red +OPHN1 red +ORC6L red +OSBPL8 red +P4HB red +PAFAH1B1 red +PCM1 red +PDCD10 red +PGLS red +PHIP red +PLEKHC1 red +POLR1B red +POLR2E red +POLR2I red +POLR2L red +POPDC3 red +PPIB red +PPP1CA red +PPP2CA red +PRDX2 red +PRKACB red +PRKAR1A red +PRKAR2A red +PRKD2 red +PSMB3 red +PSMB8 red +PSMB9 red +PTPRCAP red +PUM2 red +R3HCC1 red +RAB1A red +RAB6A red +RAB6C red +RAP1B red +RAVER2 red +RBPMS red +REEP5 red +RGPD5 red +RGS19 red +RNF11 red +RNPC2 red +RPA1 red +RPL10A red +RPL12 red +RPL14 red +RPL15 red +RPL18A red +RPL19 red +RPL23A red +RPL26 red +RPL32 red +RPL37 red +RPL39 red +RPL41 red +RPN1 red +RPS10 red +RPS13 red +RPS15 red +RPS15A red +RPS16 red +RPS20 red +RPS21 red +RPS27 red +SCAND1 red +SDHA red +SEC61A1 red +SELL red +SEPT7 red +SET red +SF3B1 red +SFPQ red +SFRS10 red +SFRS3 red +SFRS5 red +SIAHBP1 red +SLC25A11 red +SLC25A16 red +SLC25A3 red +SLC38A2 red +SMTN red +SPARCL1 red +SPCS2 red +SPG21 red +SPN red +SRP46 red +SRP72 red +SRP9 red +SSR1 red +STAT1 red +SUB1 red +SUMO1 red +TAPBP red +TARDBP red +TCEA1 red +TCEB2 red +TGFB1I1 red +THRAP1 red +THRAP5 red +TIMM13 red +TIMM8B red +TINP1 red +TMED5 red +TMEM123 red +TMEM66 red +TMEM93 red +TOMM20 red +TPM1 red +TPT1 red +TRAM1 red +TRBV3-1 red +TRIM22 red +TTC19 red +TTC3 red +TUFM red +TXNL2 red +UBE2D2 red +UBE4A red +UCP2 red +UCRC red +UQCRQ red +USP47 red +VDP red +WAC red +WDR45 red +WIPI2 red +WSB1 red +YIPF3 red +YME1L1 red +YWHAZ red +ZC3H11A red +ZFR red +ZMYND11 red +ZNF403 red +ZNF552 red +ZNF9 red +hfl-B5 red diff --git a/www/Examples/Human_Coexpression/NORMA_Human_coexpression_NETWORK.txt b/www/Examples/Human_Coexpression/NORMA_Human_coexpression_NETWORK.txt new file mode 100644 index 0000000..4aa6aaf --- /dev/null +++ b/www/Examples/Human_Coexpression/NORMA_Human_coexpression_NETWORK.txt @@ -0,0 +1,2144 @@ +Source Target +RPL24 RPL41 +RPL24 RPL26 +RPL24 RPL30 +RPL24 TPT1 +RPL24 RPL9 +RPL24 RPS25 +RPL24 RPS23 +RPL24 RPL31 +RPL24 RPS27A +RPL24 U16 +RPL24 RPS4X +RPL24 RPL7 +RPL24 RPL4 +RPL24 RPL5 +RPL24 RPS3A +RPL24 RPS7 +RPL24 RPL34 +RPL24 RPL35A +RPL24 RPS24 +RPL24 RPL6 +RPL41 RPL5 +RPL41 RPS3A +RPL41 TPT1 +RPL41 RPS23 +RPL41 RPS4X +HNRPA1 RPS25 +HNRPA1 RPS24 +HNRPA1 RPS4X +HNRPA1 RPS6 +HNRPA1 RPL22 +HNRPA1 NCL +HNRPA1 RPL24 +HNRPA1 NPM1 +HNRPA1 RPL4 +HNRPA1 MDS1 +HNRPA1 U16 +HNRPA1 RPS23 +HNRPA1 RPS7 +HNRPA1 SF3B1 +HNRPA1 NAP1L1 +HNRPA1 RPL17 +HNRPA1 RPL11 +HNRPA1 RPL6 +HNRPA1 RPL34 +HNRPA1 LOC440055 +HNRPA1 RPS3A +HNRPA1 RPL7 +RPS25 RPS4X +RPS25 RPS3A +RPS25 RPS6 +RPS25 U16 +RPS25 RPS7 +RPS25 RPS27A +H3F3A RPA1 +H3F3A RAP1B +H3F3A RPLP2 +H3F3A RPS20 +H3F3A RPL27 +H3F3A RPS11 +H3F3A RPL27A +COX8A CYC1 +COX8A NDUFS8 +COX8A SLC25A11 +COX8A SLC25A3 +COX8A NDUFAB1 +COX8A NDUFB11 +COX8A MRPS12 +CYC1 ETFB +CYC1 UQCRC1 +ATP8B1 PDE4C +ATP8B1 FLJ42393 +ATP8B1 DKFZP566N034 +ATP8B1 CEP27 +ATP8B1 KNS2 +ATP8B1 RIOK3 +ATP8B1 DBT +ATP8B1 PGF +ATP8B1 ZNF611 +ATP8B1 SLC35E1 +ATP8B1 LOC152719 +ATP8B1 FBXW12 +ATP8B1 ZNF160 +PDE4C SPG21 +PDE4C UBE2D2 +PDE4C PRKAR2A +PDE4C ZNF611 +PDE4C PRR11 +PDE4C PGF +PDE4C ZNF160 +PDE4C RIOK3 +PDE4C SLC35E1 +LOC58486 SUB1 +LOC58486 MGEA5 +LOC58486 RNPC2 +LOC58486 PFAAP5 +LOC58486 WAC +LOC58486 MATR3 +LOC58486 PNRC2 +LOC58486 PAPOLA +LOC58486 ZNF638 +LOC58486 SF3B1 +LOC58486 USP34 +LOC402057 RPS7 +LOC402057 RPS15A +LOC402057 RPL34 +LOC402057 RPS4X +LOC402057 RPS6 +LOC402057 RPL31 +LOC402057 RPL35A +LOC402057 RPL37 +LOC402057 RPL22 +LOC402057 RPL4 +LOC402057 RPL9 +LOC402057 RPS23 +LOC402057 RPL11 +LOC402057 LOC440055 +LOC402057 RPL30 +LOC402057 RPL23 +LOC402057 RPL36A +LOC402057 RPL39 +LOC402057 MDS1 +LOC402057 RPL32 +LOC402057 RPS17 +RPS7 SFRS5 +RPS7 SF3B1 +RPS7 U16 +MDS1 RPL23 +MDS1 RNPC2 +MDS1 RPL17 +MDS1 RPL5 +MDS1 RPS3A +MDS1 RPL41 +MDS1 RPL4 +MDS1 TPT1 +MDS1 NPM1 +MDS1 RPS6 +MDS1 RPL7 +MDS1 RPL24 +MDS1 RPL34 +MDS1 RPL26 +MDS1 RPL22 +MDS1 RPS27A +MDS1 RPL6 +MDS1 RPS25 +MDS1 RPS15A +MDS1 U16 +MDS1 RPS7 +MDS1 RPS24 +MDS1 RPL36A +MDS1 RPS4X +MDS1 RPL21 +MDS1 RPL31 +MDS1 RPL35A +MDS1 RPL30 +MDS1 RPS17 +MDS1 RPL9 +MDS1 RPL11 +MDS1 RPS23 +RPL23 RPL7 +RPL23 RPL26 +RPL23 RPL5 +RPL23 RPL24 +RPL23 RPS27 +RPL23 RPS15A +RPL23 RPS27A +RPL23 RPL6 +RPL23 RPL36A +RPL23 U16 +RPL23 RPS25 +RPL23 RPS17 +RPL23 RPS4X +RPL23 RPS7 +RPL23 RPS3A +RPL23 RPS23 +RPL23 RPL30 +RPL23 RPS24 +RPL23 RPL9 +RPL23 RPL31 +RPL23 RPS6 +RPL23 RPL35A +RPL23 RPL4 +RPL23 RPL34 +RPL5 RPS6 +RPL5 RPS23 +RPL5 TPT1 +RPL5 RPS25 +RPL5 RPS3A +RPL5 RPS4X +RPL5 RPL9 +RPL5 RPS27A +RPL5 RPL7 +RPL5 RPS7 +RPL5 U16 +RPL5 RPS24 +RPL5 RPL6 +ATP5G3 COX8A +ATP5G3 NDUFB11 +ATP5G3 SLC25A3 +ATP5G3 UQCRC1 +ATP5G3 UQCRQ +ATP5G3 COX5A +ATP5G3 COX4I1 +ATP5G3 NDUFAB1 +ATP5G3 UQCRFS1 +ATP5G3 COX5B +ATP5G3 MDH2 +COPB TRAM1 +COPB LOC58486 +COPB RNPC2 +COPB HSP90B1 +COPB YME1L1 +COPB PAPOLA +PRKACB SEPT7 +SEPT7 SH3BGRL +SEPT7 ZFR +UBE2D2 ZNF160 +RNPC2 TAF7 +RNPC2 TCEA1 +RNPC2 ZNF638 +RNPC2 RPS3A +RNPC2 SF3B1 +RNPC2 RPL5 +RNPC2 RPL6 +RNPC2 RPL17 +RNPC2 SRP72 +IGHM IGKC +IGHM IGLC2 +IGHM IGKV1-5 +IGHM LOC91316 +IGHM IGLV3-10 +IGHM IGL@ +IGHM IGHV1-69 +IGHM IGKV1D-13 +IGHM IGLV3-25 +IGHM IGLC1 +IGHM IGKV1OR2-108 +IGKC IGLJ3 +IGKC IGLC2 +IGKC IGKV1D-13 +IGKC IGLV3-25 +IGKC IGKV1OR2-108 +IGKC IGKV1-5 +IGKC IGLV3-10 +IGKC IGL@ +IGKC LOC91316 +IGKC IGLC1 +IGKC IGKV1OR15-118 +LOC342346 YTHDC1 +LOC342346 XPO1 +LOC342346 SON +LOC342346 TAF7 +LOC342346 PAPOLA +LOC342346 SH3BGRL +EEF1A1 RPL17 +EEF1A1 MDS1 +EEF1A1 RPS24 +EEF1A1 RPS3A +EEF1A1 RPL22 +EEF1A1 NPM1 +EEF1A1 RPL11 +EEF1A1 RPS7 +EEF1A1 RPS27A +EEF1A1 TPT1 +EEF1A1 RPS6 +EEF1A1 RPL7 +EEF1A1 RPS4X +EEF1A1 RPL23 +RPL17 SFRS5 +RPL17 RPS25 +RPL17 RPL9 +RPL17 TPT1 +RPL17 RPL30 +RPL17 RPL26 +RPL17 RPL7 +RPL17 RPL36A +RPL17 RPL22 +RPL17 RPS6 +RPL17 SF3B1 +RPL17 RPS4X +RPL17 TINP1 +RPL17 RPL35A +RPL17 RPS23 +RPL17 U16 +RPL17 RPS3A +RPL17 RPL24 +RPL17 RPS7 +RPL17 RPL23 +RPL17 RPL31 +RPL17 RPS27A +RPL17 RPL21 +RPL17 RPL4 +RPL17 RPL5 +RPL17 RPL34 +RPL17 RPL6 +RPL17 RPS24 +RPL13A RPS9 +RPL13A RPS18 +RPL13A RPL18A +RPL13A RPL27A +RPL13A RPL14 +RPL13A RPS16 +RPL13A RPS14 +RPL13A RPL15 +RPL13A RPLP2 +RPL13A RPS21 +RPL13A RPL29 +RPL13A RPS19 +RPL13A RPL36 +RPL13A RPS5 +NDUFAB1 NDUFB4 +NDUFAB1 NDUFS3 +NDUFAB1 UQCRC1 +NDUFAB1 NDUFV1 +NDUFAB1 UQCR +NDUFAB1 NDUFB2 +NDUFAB1 UQCRQ +NDUFAB1 NDUFS7 +NDUFAB1 NDUFB11 +NDUFAB1 NDUFC1 +NDUFAB1 POLR2I +NDUFAB1 NDUFS8 +NDUFAB1 UQCRFS1 +NDUFB4 NDUFS3 +NDUFB4 NDUFS8 +NDUFB4 UQCRFS1 +NDUFB4 UCRC +AKR7A2 CLPP +AKR7A2 TIMM13 +AKR7A2 NDUFV1 +AKR7A2 MRPL34 +AKR7A2 C21orf33 +AKR7A2 NDUFS8 +CLPP TUFM +CLPP MRPL34 +hfl-B5 HNRPA2B1 +hfl-B5 HIATL1 +hfl-B5 HNRPH1 +hfl-B5 HNRPA1 +HNRPA2B1 XPO1 +HNRPA2B1 SRP46 +SET SFRS3 +SET SRP46 +SET SON +SET SFRS10 +HLA-C ISG20 +HLA-C MAN2B1 +HLA-C HLA-G +HLA-C HLA-F +HLA-C HLA-E +HLA-C TAPBP +HLA-C HLA-J +ISG20 RAC2 +ISG20 PSMB9 +ISG20 UCP2 +RPS24 TPT1 +RPS24 TCEA1 +RPS24 SF3B1 +RPS24 RPS25 +RPS24 RPS3A +RPS24 RPS6 +RPS24 RPS4X +RPS24 U16 +RPS24 RPS27A +RPS24 RPS7 +DDX1 KTN1 +KTN1 USP47 +RPS4X U16 +RPS4X TPT1 +RPS4X RPS7 +RPS4X RPS6 +CCNL1 RPL4 +CCNL1 ZNF638 +CCNL1 NACA +CCNL1 RPL5 +CCNL1 RPS27A +CCNL1 RPL17 +CCNL1 RNPC2 +CCNL1 RPL21 +CCNL1 RPL6 +CCNL1 EIF3S6 +RPL4 TPT1 +RPL4 RPL7 +RPL4 SFRS5 +RPL4 RPS15A +RPL4 RPL5 +RPL4 RPS17 +RPL4 RPS25 +RPL4 RPL9 +RPL4 RPS7 +RPL4 RPS27A +RPL4 RPL6 +RPL4 RPS23 +RPL4 RPS4X +RPL4 RPS3A +RPL4 RPS24 +RPL4 U16 +RPL4 RPS6 +FLJ11021 NAP1L1 +FLJ11021 ZNF403 +FLJ11021 HIATL1 +FLJ11021 KIAA0907 +FLJ11021 WAC +FLJ11021 TUG1 +FLJ11021 PAPOLA +FLJ11021 RNPC2 +FLJ11021 XPO1 +FLJ11021 LOC58486 +FLJ11021 NPM1 +NAP1L1 RPL17 +NAP1L1 YTHDC1 +NAP1L1 PAPOLA +NAP1L1 ZNF9 +NAP1L1 XPO1 +C21orf33 ETFB +C21orf33 COX5B +C21orf33 NDUFS7 +C21orf33 NDUFS8 +ETFB NDUFS8 +ETFB UQCRQ +COX5A NDUFS8 +COX5A NDUFB11 +COX5A NDUFS7 +COX5A MDH2 +COX5A COX5B +COX5A NDUFAB1 +COX5A UQCRFS1 +COX5A UQCRC1 +NDUFS8 SLC25A3 +NDUFS8 POLR2I +NDUFS8 POLR2L +NDUFS8 TIMM13 +NDUFS8 UQCRFS1 +NDUFS8 TMEM93 +NDUFS8 UQCRQ +CROP IL6ST +CROP ZNF638 +CROP HNRPA3P1 +CROP RNPC2 +CROP MATR3 +CROP SFRS5 +CROP XPO1 +CROP SFPQ +CROP LOC58486 +CROP HNRPDL +CROP TUG1 +CROP SFRS11 +CROP ZC3H11A +CROP PFAAP5 +CROP NPM1 +CROP FLJ10154 +CROP GOLGA8A +IL6ST SFRS11 +POLR2E SIAHBP1 +RPL26 RPS3A +RPL26 RPL4 +RPL26 RPL7 +RPL26 RPS7 +RPL26 RPS6 +RPL26 RPS27A +RPL26 RPL34 +RPL26 RPS24 +RPL26 RPS25 +RPL26 RPL5 +RPL26 RPL6 +216858_x_at CEP27 +216858_x_at ZNF611 +216858_x_at FLJ14346 +216858_x_at LOC152719 +CEP27 PRR11 +CEP27 PGF +CEP27 PRKAR2A +CEP27 LOC152719 +CEP27 PDE4C +CEP27 RIOK3 +CEP27 ZNF611 +CEP27 KNS2 +CEP27 FBXW12 +CEP27 DBT +CEP27 ZNF160 +CEP27 SLC35E1 +CEP27 FLJ12151 +RPL6 RPL9 +RPL6 SFRS5 +RPL6 TPT1 +RPL6 RPL7 +RPL6 RPS23 +RPL6 SF3B1 +RPL6 RPS4X +RPL6 RPS25 +RPL6 RPS3A +RPL6 RPS6 +RPL6 U16 +RPL6 RPS7 +RPL6 RPS27A +RPL6 RPS24 +RPL9 RPS27A +RPL9 RPS24 +RPL9 U16 +RPL9 RPS25 +RPL9 RPS4X +RPL9 RPS23 +RPL9 RPS7 +RPL9 RPS3A +RPL9 RPS17 +RPL9 RPS6 +RPL9 RPS27 +RPL9 RPS15A +DDX3X XPO1 +DDX3X NAP1L1 +DDX3X PAPOLA +DDX3X SON +DDX3X HNRPR +DDX3X THRAP1 +DDX3X SH3BGRL +DDX3X HNRPH1 +DDX3X MGEA5 +DDX3X HIATL1 +DDX3X DDX5 +DDX3X LOC342346 +DDX3X EIF4G2 +DDX3X SF3B1 +DDX3X YTHDC1 +COPE SCAND1 +COPE MRPS12 +COPE NAPA +COPE FIBP +SCAND1 THRAP5 +COPS2 RPL15 +COPS2 HSP90B1 +COPS2 HNRPH3 +COPS2 ZNF638 +COPS2 KIDINS220 +COPS2 VDP +COPS2 TLOC1 +COPS2 CSDE1 +RPL15 RPL35 +RPL15 RPS16 +ITGB2 RAC2 +ITGB2 RGS19 +RAC2 TRA@ +RAC2 TRB@ +DBT PRR11 +DBT DIP2A +DBT FLJ42393 +DBT ZNF611 +DBT FLJ12151 +DBT PGF +DBT LOC152719 +DBT RIOK3 +DBT PDE4C +DBT WDR45 +DBT ZNF160 +DBT FBXW12 +DBT KNS2 +DBT SLC35E1 +PRR11 ZNF611 +PRR11 SLC35E1 +PRR11 ZNF160 +207730_x_at 216858_x_at +207730_x_at UBE2D2 +207730_x_at FLJ42393 +207730_x_at 208246_x_at +207730_x_at PRKAR2A +207730_x_at 217679_x_at +207730_x_at PDE4C +207730_x_at PRR11 +207730_x_at PGF +207730_x_at RIOK3 +207730_x_at 208238_x_at +207730_x_at KNS2 +207730_x_at 216524_x_at +207730_x_at ATP8B1 +207730_x_at FLJ12151 +207730_x_at LOC152719 +207730_x_at DBT +207730_x_at ZNF611 +207730_x_at SLC35E1 +207730_x_at ZNF160 +207730_x_at CEP27 +207730_x_at FBXW12 +EEF1D RPS9 +EEF1D GLTSCR2 +EEF1D RPL38 +PRDX2 RIOK3 +RIOK3 ZNF611 +RIOK3 ZNF160 +RIOK3 SLC35E1 +RPS23 RPS27A +RPS23 U16 +RPS23 RPS7 +RPS23 RPS24 +RPS23 RPS25 +RPS23 RPS6 +RPS23 RPS4X +RPS23 RPS3A +RPS27A SFRS5 +RPS27A RPS4X +RPS27A U16 +RPS27A TINP1 +RPS27A RPS3A +RPS27A RPS7 +RPS27A RPS6 +RPL34 TPT1 +RPL34 SF3B1 +RPL34 RPL7 +RPL34 RPS25 +RPL34 RPL36A +RPL34 RPL5 +RPL34 RPS27A +RPL34 RPS4X +RPL34 RPS3A +RPL34 RPS6 +RPL34 RPS7 +RPL34 RPL4 +RPL34 RPL9 +RPL34 RPS23 +RPL34 RPL6 +RPL34 RPL35A +RPL34 RPS24 +HNRPDL MATR3 +HNRPDL SON +HNRPDL NAP1L1 +HNRPDL NPM1 +HNRPDL SF3B1 +HNRPDL IL6ST +HNRPDL SERBP1 +HNRPDL SFRS11 +MATR3 WAC +MATR3 SERBP1 +MATR3 NARS +MATR3 XPO1 +MATR3 YTHDC1 +MATR3 SFRS11 +MATR3 SON +MATR3 MGEA5 +MATR3 PAPOLA +MATR3 SH3BGRL +MATR3 SEPT7 +MATR3 SEPT2 +MATR3 TAF7 +MATR3 NPM1 +MATR3 PCNP +MATR3 RNPC2 +MATR3 TLOC1 +EIF3S3 MATR3 +EIF3S3 HSP90AA1 +EIF3S3 TTC3 +EIF3S3 NARS +EIF3S3 FNTA +EIF3S3 SEPT2 +WAC ZNF403 +RPL22 RPL5 +RPL22 TPT1 +RPL22 RPS15A +RPL22 RPS23 +RPL22 RPS27A +RPL22 RPS7 +RPL22 RPL30 +RPL22 RPS3A +RPL22 RPL6 +RPL22 RPL34 +RPL22 RPL26 +RPL22 RPL9 +RPL22 RPL24 +RPL22 RPS25 +RPL22 RPL35A +RPL22 RPS17 +RPL22 RPS24 +RPL22 RPL4 +RPL22 RPL41 +RPL22 RPL7 +RPL22 RPS6 +RPL22 RPL36A +RPL22 RPL23 +RPL22 RPS4X +RPL22 RPL31 +SH3BGRL YTHDC1 +SH3BGRL TAF7 +SH3BGRL SON +MRPL34 NDUFS3 +MRPL34 UQCRFS1 +MRPL34 UQCRC1 +MRPL34 NDUFV1 +MRPL34 POLR2I +NDUFS3 POLR2I +NDUFS3 NDUFS8 +NDUFS3 UQCRFS1 +FIBP SIAHBP1 +FIBP WIPI2 +FIBP POLR2E +AURKAIP1 COX5A +AURKAIP1 C12orf10 +AURKAIP1 MRPL34 +AURKAIP1 GPX4 +AURKAIP1 NDUFS3 +AURKAIP1 TUFM +AURKAIP1 NDUFS8 +AURKAIP1 NDUFS7 +AURKAIP1 NDUFA2 +AURKAIP1 C3orf60 +AURKAIP1 NDUFA3 +AURKAIP1 UQCRFS1 +AURKAIP1 TMEM93 +AURKAIP1 UQCRC1 +AURKAIP1 FIBP +AURKAIP1 EXOSC4 +DIP2A PGF +CD52 IL7R +CD52 TRBV3-1 +CD52 FAIM3 +CD52 LCK +CD52 ISG20 +CD52 TRA@ +CD52 TRB@ +CD52 RAC2 +CD52 TRBC1 +CSNK1A1 PAPOLA +CSNK1A1 EIF4G2 +PAPOLA TAF7 +PAPOLA PUM2 +PAPOLA SON +PAPOLA ZNF9 +PAPOLA SSR1 +PAPOLA SRP72 +PAPOLA TRAM1 +PAPOLA THRAP1 +PAPOLA TMEM123 +PAPOLA USP34 +PAPOLA RNPC2 +PAPOLA PNRC2 +PAPOLA YTHDC1 +PAPOLA SF3B1 +HLA-G MAN2B1 +HLA-G TGFB1 +HLA-G ISG20 +HLA-G IFI30 +HLA-G HLA-J +MAN2B1 TGFB1 +ATP5D COX5B +ATP5D CYC1 +COX5B FLJ14346 +COX5B NDUFS3 +COX5B NDUFB2 +COX5B NDUFA3 +COX5B MRPS12 +COX5B NDUFS8 +COX5B UQCRC1 +COX5B CYC1 +COX5B MSRB2 +COX5B UQCRQ +COX5B NDUFB11 +COX5B MDH2 +COX5B NDUFV1 +COX5B UQCRFS1 +COX5B NDUFS7 +COX5B NDUFAB1 +COX5B COX8A +COX5B UQCR +IGLJ3 IGLV3-25 +IGLJ3 LOC91316 +215176_x_at IGHG3 +215176_x_at 217258_x_at +215176_x_at IGHV1-69 +215176_x_at 217281_x_at +215176_x_at IGLC2 +215176_x_at IGHA1 +215176_x_at IGKC +215176_x_at IGHM +215176_x_at IGLV3-25 +215176_x_at IGKV1OR2-108 +215176_x_at IGLJ3 +215176_x_at IGKV1-5 +215176_x_at IGKV1OR15-118 +215176_x_at IGLC1 +215176_x_at IGL@ +215176_x_at LOC91316 +215176_x_at IGKV1D-13 +215176_x_at 221651_x_at +215176_x_at CTA-246H3.1 +IGHG3 IGHM +IGHG3 IGHV1-69 +IGHG3 IGKV1-5 +IGHG3 IGLJ3 +IGHG3 IGKV1D-13 +IGHG3 IGKC +IGHG3 IGKV1OR2-108 +IGHG3 IGLC2 +IGHG3 IGLC1 +IGHG3 LOC91316 +217258_x_at IGLC2 +217258_x_at IGKC +217258_x_at IGL@ +217258_x_at CTA-246H3.1 +217258_x_at IGLJ3 +217258_x_at IGKV1-5 +217258_x_at IGLV3-25 +RPL14 RPL17 +RPL14 RPS4X +RPL14 RPS3A +RPL14 RPL5 +RPL14 RPS7 +RPL14 U16 +RPL14 RPL21 +RPL14 RPL4 +RPL14 RPL6 +RPL14 RPL35A +RPL14 RPL39 +RPL14 RPL23 +DYNLT3 PAFAH1B1 +PAFAH1B1 PRKACB +PAFAH1B1 POPDC3 +PAFAH1B1 REEP5 +PAFAH1B1 ZFR +PAFAH1B1 PCNP +PAFAH1B1 SEPT7 +RPS18 RPS19 +SF3B1 WAC +SF3B1 SON +SF3B1 TUG1 +SF3B1 SFRS5 +SF3B1 YTHDC1 +SF3B1 TCEA1 +IQGAP1 MBNL1 +IQGAP1 ROCK1 +MBNL1 OSBPL8 +MBNL1 ROCK1 +MBNL1 PNRC2 +MBNL1 PUM2 +NPM1 RPS3A +NPM1 SFRS5 +NPM1 SFRS11 +NPM1 RPS7 +NPM1 RPS6 +NPM1 RPL7 +NPM1 RPL34 +NPM1 TCEA1 +NPM1 TUG1 +NPM1 RPL5 +NPM1 RPL17 +NPM1 RPL24 +NPM1 SF3B1 +NPM1 TINP1 +NPM1 RPL6 +NPM1 RPS24 +NPM1 RPL4 +NPM1 RPS27A +NPM1 RNPC2 +RPS3A SF3B1 +RPS3A TPT1 +RPS3A U16 +RPS3A RPS4X +RPS3A RPS7 +RPS3A RPS6 +SPN ZNF552 +DDX50 RNPC2 +EIF5 PCNP +EIF5 PAPOLA +EIF5 TAF7 +EIF5 MATR3 +EIF5 HSP90AA1 +PCNP SEPT2 +PCNP TLOC1 +PCNP RNPC2 +217281_x_at IGHM +217281_x_at IGHV1-69 +217281_x_at IGLJ3 +217281_x_at IGKC +217281_x_at IGLC2 +217281_x_at IGHA1 +217281_x_at IGHG3 +217281_x_at IGKV1OR2-108 +CHCHD2 MIF +CHCHD2 NDUFAB1 +CHCHD2 COX5B +CHCHD2 MRPS12 +CHCHD2 MRP63 +CHCHD2 COX8A +CHCHD2 SLC25A3 +CHCHD2 NDUFB11 +MIF TIMM13 +ARPC5 CAP1 +ARPC5 PRG1 +SFRS11 TUG1 +ACTR10 SKP1A +ACTR10 PRKAR1A +SKP1A SUMO2 +ACTR2 ARPC3 +ACTR2 ACTR3 +ACTR2 CAPZA1 +ACTR2 PDCD10 +ARPC3 CAPZA1 +CAV1 MMP2 +CAV1 COL6A1 +CAV1 FBLN1 +CAV1 COL1A2 +CAV1 PTRF +CAV1 LAMC1 +ACTG2 MYH11 +MYH11 MYLK +MYH11 TPM1 +MYH11 TAGLN +RPL38 RPS20 +RPL38 RPLP2 +RPL38 RPS19 +RPS20 RPS27 +CSDE1 FLJ11021 +CSDE1 WAC +CSDE1 NFE2L2 +COL1A2 COL3A1 +COL3A1 COL6A3 +CD7 LCK +CD7 HMHA1 +LCK RAC2 +LCK TRA@ +LCK TRB@ +LCK TRBC1 +LCK TRBV3-1 +NDUFB11 NDUFS3 +NDUFB11 UQCRQ +NDUFB11 UQCR +NDUFB11 NDUFB4 +NDUFB11 UQCRFS1 +NDUFB11 SLC25A3 +NDUFB11 NDUFS8 +NDUFB11 POLR2L +C3orf60 EXOSC4 +C3orf60 POLR2I +C3orf60 MRPL34 +C3orf60 GPX4 +211639_x_at IGKC +RPL11 RPS15A +RPL11 RPL5 +RPL11 RPS24 +RPL11 RPL17 +RPL11 RPL7 +RPL11 U16 +RPL11 RPL24 +RPL11 RPL21 +RPL11 RPL35A +RPL11 RPS25 +RPL11 RPL14 +RPL11 RPS6 +RPL11 RPL22 +RPL11 RPL34 +RPL11 RPL4 +RPL11 RPS4X +RPL11 RPS3A +RPL11 RPS7 +RPL11 RPL39 +RPL11 RPL31 +RPL11 RPL36A +RPL11 RPL23 +RPL11 RPS17 +RPL11 RPL30 +RPL11 RPS23 +RPS15A RPS6 +RPS15A RPS17 +RPS15A RPS7 +RPS15A RPS3A +RPS15A RPS20 +RPS15A RPS27 +RPS15A RPS23 +GNB2L1 RPL13A +GNB2L1 RPS19 +GNB2L1 RPL29 +GNB2L1 RPS16 +RPL29 RPS9 +RPL29 RPS16 +RPL29 RPL35 +RPL13 RPL18A +RPL13 RPL28 +RPL13 RPS2 +RPL13 RPL18 +RPL13 RPLP2 +RPL13 RPS15 +RPL18A RPS2 +RPL18A RPS19 +RPL18A RPLP2 +RPL18A RPL28 +HLA-A HLA-F +HLA-A MAN2B1 +HLA-A HLA-E +HLA-A HLA-G +HLA-A HLA-B +HLA-A HLA-J +HLA-A HLA-C +HLA-F ISG20 +HLA-F HLA-G +HLA-F IFI30 +HLA-F MAN2B1 +HLA-F HLA-J +BTF3 MDS1 +BTF3 RPS27 +BTF3 RPS17 +BTF3 RPS15A +BTF3 RPL30 +BTF3 LOC402057 +BTF3 RPL22 +NACA RPL35A +NACA RPS3A +NACA RPL5 +NACA NAP1L1 +NACA SFRS5 +NACA RPS7 +NACA RPL24 +NACA U16 +NACA RPL21 +NACA RPL9 +NACA NPM1 +NACA RPS23 +NACA RPL4 +NACA RPS27A +NACA RPS24 +NACA RPL17 +NACA RPL6 +NACA TINP1 +RPL35A RPL7 +RPL35A RPS17 +RPL35A RPS27A +RPL35A RPS20 +RPL35A RPS27 +RPL35A RPS15A +RPL35A RPS3A +RPL35A RPS25 +RPL35A RPL36A +RPL35A RPL39 +RPL35A RPL6 +RPL35A RPS6 +RPL35A RPS4X +RPL35A RPL4 +RPL35A RPL5 +RPL35A RPS23 +RPL35A RPS24 +RPL35A U16 +RPL35A RPL9 +RPL35A RPS7 +BIRC2 DDX5 +BIRC2 ZNF403 +BIRC2 LOC58486 +BIRC2 THRAP1 +BIRC2 SERBP1 +BIRC2 PAPOLA +BIRC2 USP34 +BIRC2 C1orf63 +DDX5 SERBP1 +DDX5 SRP46 +DDX5 hfl-B5 +DDX5 TUG1 +DDX5 NAP1L1 +DDX5 HNRPH1 +DDX5 NBPF1 +DDX5 SFRS5 +DDX5 LOC342346 +DDX5 NBPF12 +DDX5 MGEA5 +DDX5 HNRPA2B1 +DDX5 SON +DDX5 FLJ10154 +DDX5 USP34 +DDX5 NPM1 +DDX5 TARDBP +DDX5 EIF4G2 +DDX5 PAPOLA +DDX5 HIATL1 +DDX5 YTHDC1 +DDX5 SF3B1 +RPL30 U16 +RPL30 RPS7 +RPL30 RPS25 +RPL30 RPS13 +RPL30 RPS3A +RPL30 RPS4X +RPL30 RPL4 +RPL30 RPS6 +RPL30 RPL37 +RPL30 RPL31 +RPL30 RPL36A +RPL30 RPL35A +RPL30 RPS27 +RPL30 RPS17 +RPL30 RPS15A +RPL30 RPL9 +RPL30 RPS20 +RPL30 RPS23 +RPL30 RPL32 +RPL30 RPL39 +TMEM123 TRAM1 +IGHA1 IGHV1-69 +IGHA1 IGKC +IGHA1 IGLJ3 +IGHA1 IGLV3-25 +IGHA1 IGHM +IGHA1 IGKV1OR15-118 +IGHA1 IGLC2 +IGHA1 IGL@ +IGHA1 IGKV1-5 +IGHA1 IGKV1D-13 +IGHA1 IGHG3 +IGHA1 IGKV1OR2-108 +IGHA1 LOC91316 +IGHA1 IGLC1 +IGHV1-69 IGLC2 +IGHV1-69 IGKC +IGHV1-69 IGLC1 +IGHV1-69 IGKV1OR2-108 +NDUFS7 POLR2I +NDUFS7 NDUFV1 +NDUFS7 NDUFS8 +POLR2I UQCRFS1 +214836_x_at 217258_x_at +214836_x_at 217281_x_at +214836_x_at IGLC2 +214836_x_at IGLV3-25 +214836_x_at IGL@ +214836_x_at IGKV1OR2-108 +214836_x_at IGKV1OR15-118 +214836_x_at IGLJ3 +214836_x_at IGHG3 +214836_x_at IGKC +214836_x_at LOC91316 +214836_x_at IGKV1-5 +214836_x_at IGKV1D-13 +214836_x_at IGLC1 +214836_x_at IGHA1 +214836_x_at 221651_x_at +214836_x_at CTA-246H3.1 +214836_x_at 215176_x_at +RPS6 TPT1 +RPS6 RPS7 +RPS6 U16 +GTF2I SRP9 +GTF2I TMEM66 +SRP9 SUMO1 +ATP2A3 TRA@ +ATP2A3 TRB@ +ATP2A3 TRBC1 +TRA@ TRBC1 +TRA@ TRB@ +IGLC2 IGLJ3 +IGLC2 LOC91316 +IGLC2 IGLV3-25 +IGLC2 IGLV3-10 +HSP90B1 ZNF638 +HSP90B1 RNPC2 +HSP90B1 VDP +RPL7 TPT1 +RPL7 RPS3A +RPL7 RPS6 +RPL7 RPS24 +RPL7 TCEA1 +RPL7 SF3B1 +RPL7 RPS7 +RPL7 RPS25 +RPL7 RPL9 +RPL7 RPS23 +RPL7 RPS27A +RPL7 RPS4X +MGEA5 NAP1L1 +MGEA5 PAPOLA +MGEA5 XPO1 +MGEA5 SF3B1 +MGEA5 RNPC2 +MGEA5 YTHDC1 +MGEA5 PNRC2 +BCLAF1 PCM1 +BCLAF1 RNPC2 +BCLAF1 PUM2 +BCLAF1 EIF3S6 +BCLAF1 USP47 +BCLAF1 SF3B1 +BCLAF1 SLC38A2 +BCLAF1 FLJ11021 +BCLAF1 COPS2 +BCLAF1 PCNP +BCLAF1 CSDE1 +BCLAF1 MATR3 +BCLAF1 WAC +BCLAF1 CROP +BCLAF1 SRP72 +BCLAF1 LOC58486 +BCLAF1 PHIP +BCLAF1 ZNF638 +BCLAF1 VDP +BCLAF1 NPM1 +BCLAF1 HSP90B1 +BCLAF1 TLOC1 +PCM1 VDP +CXorf9 GPSM3 +CXorf9 TRA@ +CXorf9 IL2RG +CXorf9 IL16 +216342_x_at RPL7 +216342_x_at TPT1 +216342_x_at RPL14 +216342_x_at RPL9 +216342_x_at RPS27A +216342_x_at RPL17 +216342_x_at RPS17 +216342_x_at RPL5 +216342_x_at U16 +216342_x_at RPL22 +216342_x_at RPL36A +216342_x_at RPS25 +216342_x_at LOC402057 +216342_x_at RPS7 +216342_x_at RPL21 +216342_x_at RPL24 +216342_x_at RPL41 +216342_x_at RPS24 +216342_x_at MDS1 +216342_x_at RPL6 +216342_x_at LOC440055 +216342_x_at RPL4 +216342_x_at RPL34 +216342_x_at RPS3A +216342_x_at RPL11 +216342_x_at RPS6 +216342_x_at RPL23 +216342_x_at RPL30 +216342_x_at RPL31 +216342_x_at RPS23 +216342_x_at RPL35A +216342_x_at RPS4X +NDUFA13 NDUFA3 +NDUFA13 NDUFB2 +NDUFA3 NDUFAB1 +NDUFA3 UCRC +NDUFA3 NDUFB2 +NDUFA3 NDUFB11 +NDUFA3 UQCR +NDUFA3 UQCRC1 +NDUFA3 NDUFB4 +CDKN1B PPP2CA +CDKN1B MARCKS +HMGB1 HNRPR +HMGB1 HNRPA2B1 +HNRPR SRP9 +HNRPR SON +HNRPR SFRS10 +AP2S1 ATP6V0C +AP2S1 POLR2E +AP2S1 GPX1 +AP2S1 GUK1 +AP2S1 NAPA +AP2S1 COPE +AP2S1 ATP6V0B +AP2S1 MRPS12 +211637_x_at IGKC +211637_x_at IGHA1 +211637_x_at IGLC2 +211637_x_at 211639_x_at +211637_x_at IGHM +211637_x_at 211908_x_at +211637_x_at IGHV1-69 +211637_x_at CTA-246H3.1 +211637_x_at 211641_x_at +211637_x_at 215176_x_at +211637_x_at 211645_x_at +211637_x_at IGHG3 +211637_x_at 217281_x_at +211637_x_at LOC91316 +COL4A1 COL4A2 +COL4A1 FBLN1 +COL4A2 RBPMS +FLJ42393 PDE4C +FLJ42393 ZNF160 +FLJ42393 POLR1B +FLJ42393 KNS2 +FLJ42393 SLC35E1 +FLJ42393 LOC152719 +MORF4L1 PTGES3 +MORF4L1 SKP1A +PTGES3 SUMO2 +SON XPO1 +SON SRP46 +SON YTHDC1 +IFI30 TGFB1 +IFI30 NCF1 +AASDHPPT POPDC3 +AASDHPPT PAFAH1B1 +POPDC3 RAB6C +POPDC3 PRKACB +FXYD5 ITGB2 +FXYD5 PSMB9 +CD79A IGKC +CD79A IGHA1 +CD79A IGLC2 +CD79A IGLJ3 +FLJ14346 ZNF611 +FLJ14346 GPAA1 +FLJ14346 MRPS12 +FLJ14346 LOC152719 +FLJ14346 SLC35E1 +HLA-DPA1 HLA-DQB1 +HLA-DPA1 HLA-DQA1 +HLA-DPA1 HLA-DRA +HLA-DPA1 HLA-DRB5 +HLA-DPA1 HLA-DRB4 +HLA-DPA1 HLA-DRB1 +HLA-DPA1 HLA-DPB1 +HLA-DQB1 HLA-DRB4 +HLA-DQB1 HLA-DRB5 +HLA-DQB1 HLA-DRB1 +IFNGR1 ROCK1 +C6orf12 HLA-F +C6orf12 HLA-G +C6orf12 HLA-B +C6orf12 HLA-C +C6orf12 HLA-J +C6orf12 HLA-A +NARS TLOC1 +NARS TTC3 +NARS SRP9 +RPL36A RPL6 +RPL36A RPS7 +RPL36A RPS24 +RPL36A RPS3A +RPL36A RPL4 +RPL36A RPS4X +RPL36A RPS25 +RPL36A RPS15A +RPL36A RPS6 +RPL36A RPS17 +RPL36A RPS23 +RPL36A RPL39 +217718_s_at YWHAZ +217718_s_at CAB39 +RPL23A RPS20 +TAF7 UBE4A +TAF7 YTHDC1 +TAF7 XPO1 +DHX15 OGT +DHX15 KIAA0907 +DHX15 NPM1 +CD2 TRA@ +CD2 CD52 +CD2 IL7R +DST PLEKHC1 +DST SPARCL1 +COL6A1 COL6A3 +COL6A1 FBLN1 +COL6A1 PTRF +FIS1 NDUFA13 +EIF4G2 SRP46 +EIF4G2 HSP90AA1 +EIF4G2 SERBP1 +EIF4G2 SON +EIF4G2 EIF5 +EIF4G2 NPM1 +EIF4G2 PUM2 +EIF4G2 SET +EIF4G2 PCNP +EIF4G2 LOC342346 +EIF4G2 HNRPA2B1 +EIF4G2 YTHDC1 +EIF4G2 XPO1 +EIF4G2 MATR3 +EIF4G2 PAPOLA +EIF4G2 THRAP1 +EIF4G2 SF3B1 +EIF4G2 HIATL1 +SRP46 XPO1 +COL1A1 COL6A3 +COL1A1 COL1A2 +COL1A1 COL3A1 +C12orf10 FIBP +C12orf10 C3orf60 +LMOD1 MYH11 +208246_x_at POLR1B +208246_x_at ZNF611 +208246_x_at PGF +208246_x_at ATP8B1 +208246_x_at RIOK3 +208246_x_at KNS2 +208246_x_at DBT +208246_x_at LOC152719 +208246_x_at FBXW12 +208246_x_at PDE4C +208246_x_at SLC35E1 +208246_x_at ZNF160 +208246_x_at 216524_x_at +HNRPH1 SON +HNRPH1 SF3B1 +HNRPH1 YTHDC1 +RPS14 RPS16 +RPS14 RPS5 +RPS14 RPS9 +RPS16 RPS19 +RPS16 RPS9 +RPS16 RPS5 +ARHGDIB LAPTM5 +ARHGDIB PRG1 +ARHGDIB UCP2 +ARHGDIB RAC2 +ARHGDIB CXCR4 +ARHGDIB CECR1 +LAPTM5 RAC2 +LAPTM5 PRG1 +ATRX COPS2 +ATRX PCNP +ATRX PUM2 +ATRX MATR3 +ATRX SH3BGRL +ATRX SEPT7 +ATRX BCLAF1 +ATRX TLOC1 +HIATL1 SFRS5 +HIATL1 RPL6 +HIATL1 RPL17 +HIATL1 TUG1 +HIATL1 HNRPA2B1 +HIATL1 RAVER2 +HIATL1 RNPC2 +HIATL1 HNRPH1 +HIATL1 YTHDC1 +HIATL1 TCEA1 +HIATL1 NPM1 +HIATL1 LOC58486 +HIATL1 THRAP1 +HIATL1 PAPOLA +HIATL1 SF3B1 +FAIM3 TRA@ +FAIM3 HCLS1 +FAIM3 RAC2 +IGKV1D-13 IGLJ3 +IGKV1D-13 IGLV3-25 +IGKV1D-13 IGLC2 +IGKV1D-13 LOC91316 +IGKV1D-13 IGL@ +IGKV1D-13 IGLC1 +IGKV1D-13 IGKV1OR15-118 +HSP90AA1 MATR3 +HSP90AA1 SRP9 +HSP90AA1 SERBP1 +HSP90AA1 SEPT2 +HSP90AA1 NARS +RPL19 RPS20 +LOC283412 RPL29 +LOC283412 RPS9 +DGCR6 POLR2I +LTB TRBC1 +LTB TRB@ +HMHA1 PSMB8 +HMHA1 TRBC1 +HMHA1 RAC2 +PSMB8 TAPBP +PSMB8 PSMB9 +IGKV1-5 IGL@ +IGKV1-5 IGKV1OR2-108 +IGKV1-5 IGLC2 +IGKV1-5 IGLJ3 +IGKV1-5 IGLV3-25 +IGKV1-5 IGLC1 +IGKV1-5 IGKV1D-13 +IGKV1-5 IGKV1OR15-118 +RPL28 RPS10 +RPL28 RPS2 +RPL28 RPS19 +RPL28 RPS16 +RPL28 RPLP2 +HCLS1 ITGB2 +HCLS1 SELL +HCLS1 RAC2 +HCLS1 TRA@ +FBLN1 MMP2 +FBLN1 PTRF +NDUFA2 UQCRFS1 +NDUFA2 UQCR +NDUFA2 NDUFS8 +NDUFA2 UQCRC1 +NDUFA2 NDUFB4 +NDUFA2 TCEB2 +NDUFA2 NDUFA3 +NDUFA2 UCRC +HLA-DRB4 HLA-DRB5 +FAM96B NDUFV1 +FAM96B NDUFS8 +FAM96B NDUFS3 +FAM96B TUFM +FAM96B NDUFS7 +FAM96B NDUFA10 +FAM96B NDUFA2 +FAM96B NDUFA3 +COQ9 NDUFB4 +COQ9 UQCRFS1 +EEF1B2 RPL30 +EEF1B2 RPL10A +EEF1B2 RPS23 +EEF1B2 RPS15A +EEF1B2 RPL35A +EEF1B2 RPL14 +EEF1B2 RPL36A +EEF1B2 RPL37 +EEF1B2 RPL39 +EEF1B2 LOC440055 +PUM2 WAC +PUM2 SF3B1 +ALOX5AP LAPTM5 +ALOX5AP ITGB2 +DKFZP566N034 ZNF160 +DKFZP566N034 SLC35E1 +ARL6IP5 PAFAH1B1 +TRB@ TRBV3-1 +TRB@ TRBC1 +IFI16 ROCK1 +IFI16 IQGAP1 +IFI16 TRIM22 +IFI16 MBNL1 +IFI16 IFNGR1 +211641_x_at 211908_x_at +211641_x_at 211645_x_at +211641_x_at IGHG3 +211641_x_at IGKV1-5 +211641_x_at 217281_x_at +211641_x_at IGHA1 +211641_x_at IGHM +211908_x_at IGHV1-69 +211908_x_at 217281_x_at +211908_x_at IGHM +WSB1 XPO1 +ARPC1B HLA-C +ARPC1B HLA-A +ARPC1B HLA-B +ARPC1B ISG20 +ARPC1B HLA-G +CD53 ITGB2 +CD53 IL10RA +CD53 HCLS1 +HLA-E HLA-F +HLA-E PSMB8 +HLA-E HLA-J +HLA-E MAN2B1 +HLA-E HLA-G +211645_x_at IGHA1 +211645_x_at IGKC +211645_x_at IGHM +211645_x_at IGLC2 +211645_x_at IGHG3 +211645_x_at IGL@ +211645_x_at IGLV3-25 +211645_x_at IGLJ3 +211645_x_at LOC91316 +211645_x_at IGLC1 +211645_x_at IGKV1-5 +211645_x_at 221651_x_at +211645_x_at IGKV1OR15-118 +211645_x_at CTA-246H3.1 +211645_x_at IGKV1D-13 +211645_x_at 214836_x_at +211645_x_at 215176_x_at +NDUFB2 NDUFS7 +NDUFB2 UQCRC1 +NDUFB2 UQCR +NDUFB2 NDUFV1 +FLJ10154 LOC58486 +FLJ10154 XPO1 +FLJ10154 PFAAP5 +FLJ10154 RNPC2 +FLJ10154 HNRPDL +FLJ10154 SFPQ +FLJ10154 SFRS11 +FLJ10154 NPM1 +EIF4A2 TTC3 +EIF4A2 MATR3 +GPX4 R3HCC1 +GPX4 POLR2I +GPX4 MRPL34 +PRKAR2A SLC35E1 +SLC35E1 UBE2D2 +SLC35E1 WDR45 +SLC35E1 ZNF611 +SLC35E1 ZNF160 +IGLC1 IGLJ3 +IGLC1 IGLV3-25 +IGLC1 IGLC2 +IGLC1 LOC91316 +UQCRC1 UQCRFS1 +TMED5 WAC +MDH2 NDUFB11 +MDH2 UQCRQ +MDH2 UQCRC1 +MDH2 UQCRFS1 +MDH2 NDUFS8 +IGL@ IGLV3-25 +IGL@ IGLC2 +IGL@ IGLC1 +IGL@ IGLJ3 +HLA-DRB1 HLA-F +HLA-DRB1 HLA-DRB4 +HLA-DRB1 HLA-DRB5 +CD74 HLA-DQB1 +CD74 HLA-DRB4 +CD74 HLA-DRB1 +CD74 HLA-DRA +CD74 HLA-DMA +CD74 HLA-DPB1 +CD74 HLA-DRB5 +CD74 HLA-DPA1 +CLTC NARS +RPS17 RPS25 +RPS17 RPS4X +RPS17 RPS6 +RPS17 RPS7 +RPS17 RPS3A +RPS17 RPS20 +RPS17 RPS23 +RPS17 RPS27 +ACTR3 CAP1 +ACTR3 ARPC3 +ACTR3 YWHAZ +ACTR3 CAPZA1 +RPS10 RPS16 +RPS10 RPS21 +RPS10 RPS19 +RPL27A RPS11 +RPL27A RPLP2 +RPL27A RPS19 +RPL27A RPL38 +RPL27A RPS20 +RPL27A RPS18 +DDX17 SON +DDX17 HNRPH1 +C11orf58 YTHDC1 +C11orf58 HNRPK +C11orf58 LOC342346 +C11orf58 SON +NAPA WIPI2 +RGPD5 TTC3 +CD3D TRA@ +CD3D TRB@ +CD3D TRBC1 +IGKV1OR2-108 LOC91316 +IGKV1OR2-108 IGLC2 +IGKV1OR2-108 IGLC1 +IGKV1OR2-108 IGLJ3 +CAB39 SUB1 +ATP6V0B GPX1 +ATP6V0B COPE +ATP6V0B MRPS12 +ATP6V0B ATP6V0D1 +ATP6V0B ATP6V0C +GPX1 PPP1CA +GPX1 PGLS +GPX1 OAZ1 +ENDOG NDUFS7 +LOC388344 RPS2 +LOC388344 RPL18 +LOC388344 RPL18A +LOC388344 RPL13 +LOC388344 RPS15 +LOC440055 RPL22 +LOC440055 RPL17 +LOC440055 RPS7 +LOC440055 RPL9 +LOC440055 RPS3A +LOC440055 RPS15A +LOC440055 RPL21 +LOC440055 RPS4X +LOC440055 U16 +LOC440055 RPL31 +LOC440055 RPL37 +LOC440055 RPL35A +LOC440055 MDS1 +LOC440055 RPS6 +LOC440055 RPS17 +LOC440055 RPL32 +LOC440055 RPL23 +LOC440055 RPL4 +LOC440055 RPL39 +LOC440055 RPS20 +LOC440055 RPL36A +LOC440055 RPL30 +LOC440055 RPS23 +LOC440055 RPL11 +CYBA IFI30 +CYBA HLA-G +CYBA HLA-B +CYBA HLA-J +CYBA TGFB1 +RBPMS TGFB1I1 +KNS2 PRR11 +KNS2 SPG21 +KNS2 LOC152719 +KNS2 PGF +KNS2 UBE2D2 +KNS2 PRKAR2A +KNS2 RIOK3 +KNS2 ZNF611 +KNS2 ZNF160 +KNS2 PDE4C +KNS2 SLC35E1 +NPEPPS SEPT7 +MRPS12 ZNHIT1 +GLTSCR2 RPS2 +GLTSCR2 RPL13 +GLTSCR2 LOC388344 +HLA-DMB HLA-DRA +220725_x_at CDC5L +220725_x_at SLC25A16 +220725_x_at C12orf38 +220725_x_at OPHN1 +220725_x_at MCM3AP +220725_x_at LOC56902 +CDC5L LOC56902 +CDC5L MCM3AP +ARL8B HSP90AA1 +ARL8B NARS +CTA-246H3.1 IGLC2 +CTA-246H3.1 IGLV3-25 +CTA-246H3.1 IGKC +CTA-246H3.1 IGKV1OR15-118 +CTA-246H3.1 IGHM +CTA-246H3.1 IGLJ3 +CTA-246H3.1 IGKV1OR2-108 +CTA-246H3.1 IGL@ +CTA-246H3.1 IGHG3 +CTA-246H3.1 IGKV1-5 +CTA-246H3.1 IGKV1D-13 +CTA-246H3.1 LOC91316 +CTA-246H3.1 IGLC1 +CTA-246H3.1 IGHA1 +218041_x_at BCLAF1 +218041_x_at PUM2 +218041_x_at SLC38A2 +MEFV SPN +SMTN TGFB1I1 +ZNF160 ZNF611 +TUFM UQCRFS1 +TUFM UQCRC1 +CD164 COPB +ARF5 POLR2J +ARF5 ATP6V0D1 +HLA-B MYH9 +HLA-B MAN2B1 +HLA-B HLA-G +HLA-B HLA-F +HLA-B HLA-E +HLA-B HLA-C +HLA-B HLA-J +IGHD IGHM +ADRM1 EXOSC4 +ADRM1 AP2S1 +ADRM1 FIBP +ADRM1 AURKAIP1 +211650_x_at IGLV3-25 +211650_x_at IGHG3 +211650_x_at IGKC +211650_x_at IGHV1-69 +211650_x_at IGHM +FLJ12151 PPP2CA +FLJ12151 LOC152719 +FLJ12151 PRR11 +FLJ12151 PDE4C +FLJ12151 ZNF611 +FLJ12151 SLC35E1 +FLJ12151 ZNF160 +HNRPK HNRPU +HNRPK SET +TOMM20 ZMYND11 +TOMM20 TTC3 +TOMM20 TTC19 +CORO1A LAPTM5 +AD7C-NTP ARL6IP2 +AD7C-NTP MEFV +AD7C-NTP CDC5L +ARL6IP2 CDC5L +ARL6IP2 LOC56902 +ARL6IP2 MEFV +C1orf63 PAPOLA +C1orf63 LOC342346 +RPL31 RPL5 +RPL31 TPT1 +RPL31 RPS27A +RPL31 RPS7 +RPL31 RPS17 +RPL31 RPL9 +RPL31 RPS3A +RPL31 RPL6 +RPL31 RPL35A +RPL31 RPL36A +RPL31 RPL7 +RPL31 RPS6 +RPL31 RPL4 +RPL31 RPS24 +RPL31 RPS23 +RPL31 RPL34 +RPL31 RPS4X +SDHA TUFM +UQCR UQCRQ +UQCR UQCRC1 +FNBP4 RPL26 +FNBP4 RNPC2 +FNBP4 RPL17 +FNBP4 OGT +FNBP4 RPL6 +FNBP4 RPS27A +PNRC2 ZNF638 +PNRC2 PUM2 +PNRC2 SF3B1 +PNRC2 ROCK1 +IGLV3-10 IGLV3-25 +MSN PRG1 +PPIB RPN1 +PPIB SEC61A1 +THRAP1 ZNF638 +IRF7 PRKD2 +IRF7 MAN2B1 +221651_x_at IGLJ3 +221651_x_at IGKV1OR15-118 +221651_x_at IGLC2 +221651_x_at IGKV1-5 +221651_x_at IGKC +221651_x_at IGKV1OR2-108 +221651_x_at IGHG3 +221651_x_at LOC91316 +221651_x_at IGKV1D-13 +221651_x_at CTA-246H3.1 +221651_x_at IGHA1 +221651_x_at IGLC1 +LOC152719 PRR11 +LOC152719 LRRFIP1 +LOC152719 PDE4C +LOC152719 RIOK3 +LOC152719 ZNF611 +LOC152719 SLC35E1 +LOC152719 ZNF160 +PRKAR1A RNF11 +PRKAR1A SRP9 +PRKAR1A TMEM66 +INPP5D ITGB2 +216524_x_at ZNF611 +216524_x_at ZNF160 +216524_x_at PGF +216524_x_at KNS2 +216524_x_at CEP27 +216524_x_at RIOK3 +216524_x_at DBT +216524_x_at PDE4C +216524_x_at FBXW12 +RPL10A RPL39 +RPL10A RPL14 +RPL10A RPL12 +RPL27 RPS20 +RPL27 RPS11 +RPL27 RPLP2 +RPL27 RPL38 +RPL27 RPS19 +RPL27 RPL27A +ERH HNRPK +ERH SUMO2 +PGF POLR1B +PGF PRR11 +PGF ZNF160 +PGF WDR45 +PGF RIOK3 +PGF ZNF611 +CAPNS1 CLPTM1 +CLPTM1 NAPA +RPS19 RPS2 +RPS19 RPS21 +RPS19 RPS20 +DDX42 MT1H +DDX42 MT1M +DDX42 MT1G +DDX42 MT1F +MT1H MT1L +MT1H MT2A +MT1H MT1M +MT1H MT1X +CD37 PTPRCAP +CD37 ISG20 +PTPRCAP TRBV3-1 +EIF3S6 RPS4X +EIF3S6 RPL26 +EIF3S6 ZNF638 +EIF3S6 MDS1 +EIF3S6 RPS3A +EIF3S6 RPL24 +EIF3S6 RPL7 +EIF3S6 RPL31 +EIF3S6 RPL4 +EIF3S6 RPL21 +EIF3S6 U16 +EIF3S6 NPM1 +EIF3S6 RNPC2 +EIF3S6 NACA +EIF3S6 RPS7 +EIF3S6 TINP1 +EIF3S6 VDP +EIF3S6 RPS27A +EIF3S6 RPL34 +EIF3S6 RPL5 +EIF3S6 RPS24 +EIF3S6 RPL17 +EIF3S6 RPL6 +IGKV1OR15-118 IGL@ +IGKV1OR15-118 IGLC2 +IGKV1OR15-118 IGLV3-25 +NDUFB6 TCEB2 +ACTA2 LMOD1 +ACTA2 MYH11 +ACTA2 TAGLN +GMFG ITGB2 +HNRPU SET +HNRPH3 LOC58486 +HNRPH3 RNPC2 +HNRPH3 MATR3 +HNRPH3 KIDINS220 +C16orf24 SCAND1 +NBPF1 NBPF12 +ARPP-19 PRKACB +217052_x_at G3BP +217052_x_at 220725_x_at +CCL5 HLA-F +CCL5 HLA-C +CCL5 HLA-G +RPLP2 RPS16 +RPLP2 RPS20 +RPLP2 RPS19 +RPLP2 RPS11 +ECH1 UQCRQ +RPL12 RPL14 +RPL12 RPL39 +RPL12 RPL19 +CECR1 LAPTM5 +ATP6V0D1 CHMP2A +ATP6V0D1 POLR2J +ATP6V0D1 PSMB3 +ATP6V0D1 OAZ2 +CBX3 HNRPA2B1 +CBX3 XPO1 +SFRS10 SON +TIMM8B UQCRC1 +CD48 IL16 +ARF1 COPE +ARF1 YIPF3 +ARF1 CAPNS1 +ARF1 RPN1 +KPNB1 PAFAH1B1 +HLA-J IFI30 +HLA-J MAN2B1 +USP47 ZNF638 +USP47 VDP +RPL36 RPS16 +RPL36 RPS18 +RPL36 RPS19 +RPL36 RPS10 +CUL4B SH3BGRL +ADD3 WAC +ADD3 SEPT7 +ADD3 MATR3 +DEXI NDUFB11 +LYSMD4 SEPT7 +PFAAP5 ZNF638 +PFAAP5 RNPC2 +215182_x_at SPN +215182_x_at CDC5L +215182_x_at 220725_x_at +215182_x_at LOC56902 +215182_x_at MCM3AP +HLA-DQA1 HLA-DRB4 +HLA-DQA1 HLA-DRA +DDT ZNHIT1 +DDT MRPS12 +RAVER2 SF3B1 +HLA-DMA HLA-DQB1 +HLA-DMA HLA-DRA +HLA-DMA HLA-DRB1 +HLA-DMA HLA-DPA1 +HLA-DMA HLA-DQA1 +HLA-DMA HLA-DRB4 +HLA-DMA HLA-DPB1 +HLA-DMA HLA-DRB5 +RAB6A RAB6C +C1orf160 TCEB2 +C1orf160 NDUFA13 +217679_x_at PDE4C +217679_x_at DBT +217679_x_at PGF +217679_x_at CEP27 +217679_x_at ZNF160 +217679_x_at FLJ12151 +217679_x_at SLC35E1 +217679_x_at KNS2 +217679_x_at FBXW12 +217679_x_at ZNF611 +RPL21 RPL26 +RPL21 RPL36A +RPL21 RPL5 +RPL21 RPL9 +RPL21 RPL30 +RPL21 RPS17 +RPL21 TPT1 +RPL21 RPS7 +RPL21 RPL39 +RPL21 RPS23 +RPL21 RPL24 +RPL21 RPS27A +RPL21 RPS3A +RPL21 U16 +RPL21 RPL22 +RPL21 RPS6 +RPL21 RPL6 +RPL21 RPL23 +RPL21 RPL7 +RPL21 RPS4X +RPL21 RPL4 +RPL21 RPS24 +RPL21 RPL34 +RPL21 RPL31 +RPS13 RPS20 +RPS13 RPS27 +RPL18 RPS2 +RPL18 RPL18A +RPS11 RPS20 +NPTN RAB1A +NPTN PRKAR1A +MCM3AP OPHN1 +MCM3AP ORC6L +EIF4G1 THRAP5 +216412_x_at IGLV3-10 +216412_x_at IGLC2 +CXCR4 LAPTM5 +CXCR4 PRG1 +CXCR4 HCLS1 +FAU RPS9 +FAU RPL35 +FAU RPS5 +FAU RPS16 +FAU RPL28 +RPL39 RPL4 +RPL39 RPS4X +RPL39 RPS20 +RPL39 RPS15A +RPL39 RPS17 +RPL39 RPS23 +IL2RG TRA@ +KIDINS220 ZFR +KIDINS220 SEPT7 +COX4I1 NDUFA7 +ORC6L SLC25A16 +ORC6L RPS11 +GBL GPX4 +ATPIF1 FIBP +MGC2474 TXNL2 +SEPT2 SFRS11 +MT1F MT1L +MT1F MT1X +MT1F MT2A +MT1F MT1G +MT1F MT1H +MT1F MT1M +MT1L MT1M +MT1L MT2A +MT1L MT1X +C11orf2 FLJ14346 +ATP6AP2 PRKAR1A +STAT1 TRIM22 +RPL35 RPS9 +RPL35 RPS5 +RPL35 RPS16 +MT1E MT1L +MT1E MT1F +MT1E MT1G +MT1E MT1X +MT1E MT2A +MT1E MT1M +MT1E MT1H +AKT1 PGLS +LOC56902 MCM3AP +LOC56902 MGC2474 +HNRPM SERBP1 +CALD1 PLEKHC1 +CALD1 TPM1 +MT1M MT2A +MT1M MT1X +C17orf62 IRF7 +KIAA1840 PAPOLA +DES TPM1 +MASP1 POLR2J +212498_at TTC19 +HLA-DPB1 HLA-DQB1 +HLA-DPB1 HLA-DQA1 +HLA-DPB1 HLA-DRB1 +HLA-DPB1 HLA-DRB4 +HLA-DPB1 HLA-DRB5 +FBXW12 PRR11 +FBXW12 RIOK3 +FBXW12 PDE4C +FBXW12 FLJ42393 +FBXW12 FLJ12151 +FBXW12 PGF +FBXW12 SLC35E1 +FBXW12 ZNF611 +FBXW12 LOC152719 +FBXW12 KNS2 +FBXW12 ZNF160 +REEP5 ZMYND11 +PHIP ZNF638 +RPS5 RPS9 +WDR45 ZNF611 +MT1X MT2A +CNOT2 FLJ11021 +P4HB SEC61A1 +TMEM93 UQCRFS1 +RPL37 RPS15A +RPL37 RPS17 +RPL37 RPS13 +RPL37 RPL39 +ACO2 NDUFB2 +MT1G MT1L +MT1G MT1M +MT1G MT2A +MT1G MT1H +MT1G MT1X +ATP5J2 UCRC +RPL32 RPL35A +RPL32 RPS15A +RPL32 RPS17 +RPL32 RPL37 +GOLGA8A GOLGA8B +CAST NFE2L2 +LOC645745 MT1L +LOC645745 MT1F +LOC645745 MT2A +LOC645745 MT1M +LOC645745 MT1E +LOC645745 MT1X +LOC645745 MT1G +LOC645745 MT1H +ITGAV ZMYND11 +CNN1 MYH11 +208238_x_at RIOK3 +FLJ20294 RPLP2 +FLJ20294 RPS11 +FLJ20294 RPL38 +FLJ20294 H3F3A +FLJ20294 RPS20 +FLJ20294 RPS19 +FLJ20294 RPL27A +FLJ20294 RPL27 +SPCS2 SRP9 +208120_x_at ORC6L diff --git a/www/Examples/IntAct_COVID19/HomoSapiens_Gene_Ontology_GOTERM_BP_DIRECT_FILTERED.txt b/www/Examples/IntAct_COVID19/HomoSapiens_Gene_Ontology_GOTERM_BP_DIRECT_FILTERED.txt new file mode 100644 index 0000000..a2e2438 --- /dev/null +++ b/www/Examples/IntAct_COVID19/HomoSapiens_Gene_Ontology_GOTERM_BP_DIRECT_FILTERED.txt @@ -0,0 +1,89 @@ +negative regulation of anoikis P06731,Q07817,P05556,Q07820,P10415 +T cell receptor signaling pathway P35998,P48556,Q13200,P25787,Q99460,P62195,Q9UNM6,O14818,Q15008,P51665,P60900,O00231,P62191 +regulation of cellular response to heat Q99615,P08107,K7ELV2,P62258,Q9UL15,O95816,P0DMV8,P78406,Q92793,P52948 +RNA secondary structure unwinding Q9NR30,Q8TDD1,Q9BUQ8,Q9UHI6,O00148,P38919,Q13838 +SRP-dependent cotranslational protein targeting to membrane P60866,P08708,P61254,P62269,P39019,P42677,P61927,P62753,Q9Y3U8,P46782 +positive regulation of establishment of protein localization to telomere P40227,P17987,P48643,Q99832 +Fc-epsilon receptor signaling pathway P35998,P48556,Q13200,P25787,Q99460,P62195,P0DP23,Q9UNM6,O14818,Q15008,P51665,P60900,O00231,P62191 +mRNA transport Q09161,O14980,Q9Y5S9,Q53F19,P09651,Q96A72,Q9UN86 +negative regulation of transcription elongation from RNA polymerase II promoter Q8WX92,Q9H3P2,P18615,O94762 +nuclear export Q09161,Q9H814,P52298,P09651 +response to hydrogen peroxide O00629,Q13443,P22460,P42224,Q9P289,P09601,P10415 +intracellular protein transport Q9UM54,Q9H173,Q9ULJ7,Q14974,O00203,P35606,O14964,Q96JC1,P53621,O95373,Q9UBF2,Q9H270,O15397,O14980,O43592,P53618 +rRNA processing P60866,Q9NR30,P39019,P62753,P61927,P57678,O43818,P08708,P61254,Q9NU22,P62269,P42677,P38919,P46782,Q9Y3U8 +release of cytochrome c from mitochondria Q07817,Q16548,Q3ZCQ8,O00429,P10415 +positive regulation of translation P11940,Q9BRP8,Q14011,Q6PKG0,P98179,P38919,Q13838 +focal adhesion assembly P12814,Q08043,P35609,Q14155,P10415 +calcium activated phosphatidylserine scrambling A1A5B4,Q32M45,Q4KMQ2 +gene silencing by RNA P30876,Q09161,Q7KZF4,P11940,K7ELV2,P52298,O15397,P78406,P52948,P24928 +negative regulation of programmed cell death P02768,Q96EY1,O76024,P62195 +protein folding in endoplasmic reticulum Q8N766,Q8IXB1,Q86YB8,P11021 +positive regulation of viral genome replication P62937,P11940,Q6PKG0,Q9P035,P78563 +protein complex assembly P52907,O14745,Q9BSJ2,O43292,Q9Y375,Q9NU22,P30153,Q92793,P06493,O00505 +mitochondrion organization P06576,P35232,Q5VV67,O00429,Q96EY1,P09874,Q9Y276,Q99623 +T cell differentiation in thymus P61769,Q96EY1,P62753,P35222,P10415 +intra-Golgi vesicle-mediated transport P53621,Q9UBF2,P35606,P39880,P53618 +protein homotetramerization Q9H773,Q96GX9,O00429,P34897,Q14500,P35609,P14735 +calcium activated galactosylceramide scrambling A1A5B4,Q32M45,Q4KMQ2 +calcium activated phosphatidylcholine scrambling A1A5B4,Q32M45,Q4KMQ2 +viral entry into host cell P08107,P27487,P05556,P15151,P0DMV8,Q9BYF1,P15144,O00505,P14735 +DNA duplex unwinding Q13283,P12956,P13010,Q9Y265,P25205,O94762 +platelet degranulation P0DP23,P12814,P05155,P02768,O15439,P15692,O43707,P00747,P35609 +regulation of nucleic acid-templated transcription P12814,P35637,O43707,P35609 +cell proliferation O15503,P68036,Q14160,Q13561,P08581,P13010,Q16576,P06493,Q15303,P25100,Q07817,P09603,Q9BXP5,Q6PKG0,O95071,P42677,Q7L590,P12004,Q10589,P10415 +osteoblast differentiation P35998,Q9NR30,Q7KZF4,P06576,P35232,P12109,Q00839,J3QSV6,P38159 +intrinsic apoptotic signaling pathway in response to DNA damage Q07817,Q16548,Q92843,Q07820,P09601,P10415 +regulation of DNA recombination P52294,P52292,Q96FV9 +positive regulation of histone H3-K4 methylation P26358,P35222,Q9H3P2,P18615 +transport P53007,Q9Y6R1,P02768,Q9UBX3,P52948,Q15818,Q9UN86,Q9NZJ7,Q15311,P46379,P33527,P38606,Q13283,Q00325,Q02978,Q9Y3A6,Q13224,Q9H936,P48065 +positive regulation of intrinsic apoptotic signaling pathway O14745,Q07817,O00429,P63244,P10415 +7-methylguanosine mRNA capping P30876,Q09161,P52298,Q53F19,P24928 +SREBP signaling pathway O15503,Q9Y5U4,Q12770 +IRES-dependent viral translational initiation P26599,Q14152,O00303 +extrinsic apoptotic signaling pathway in absence of ligand Q07817,Q16548,Q92843,Q07820,P10415 +ribosomal small subunit assembly P08708,P39019,P42677,P46782 +ubiquitin-dependent protein catabolic process P35998,P68036,P46379,Q9UNM6,P25787,O14818,Q9NXK8,O95071,P60900,O00231,P63279,Q9NVW2 +regulation of translational initiation Q09161,P52298,O75822,Q14152,O00303 +establishment of integrated proviral latency P62937,P12956,P13010 +response to endoplasmic reticulum stress Q8IXB1,Q13438,P57088,Q9Y4L1,P16615,O76024,Q9BS26 +chaperone-mediated protein folding Q96AY3,P68400,O14656,Q9Y680,Q00688 +gastrulation P37173,P63244,P62753,P09622 +fibrinolysis P07355,P00750,P05155,P00747 +negative regulation of mRNA splicing,via spliceosome O00422,P26599,Q9UKV3,P38159 +RNA processing Q13310,Q8TDD1,Q9UHI6,P98179,Q96FV9,Q00839,P78563,Q86U42 +negative regulation of apoptotic process Q9NVI7,P31689,P02768,Q96GX9,Q92843,Q96EY1,P62753,Q86W42,P06493,Q07820,Q15303,P06731,Q07817,Q16548,P46379,Q9Y466,P11021,P15692,Q5JVF3,Q99623,P10415,P63104 +negative regulation of intrinsic apoptotic signaling pathway Q07817,Q92843,Q07820,P10415 +protein targeting P27348,Q13438,P62258,Q96RT1,P63104 +regulation of smooth muscle cell proliferation P12956,P13010,P35222 +positive regulation of RNA polymerase II transcriptional preinitiation complex assembly P35998,P62191,P62195 +response to hypoxia P22460,P00750,P37173,P27487,O00469,Q12770,P15692,Q92793,P09601,O43707,P05026 +response to drug Q9UM54,Q5JWF2,P42224,P13010,P06493,Q92820,P35222,P61769,P37173,P33527,O14980,P40939,O15439,P28300,P05023,P10415 +membrane repolarization during cardiac muscle cell action potential P62258,P05023,P05026 +endoplasmic reticulum mannose trimming Q13438,Q9BZQ6,Q9NYU1 +positive regulation of potassium ion transport P33176,P35609,Q12959 +positive regulation of cellular component movement P39019,P15692,O43707 +response to unfolded protein P34932,Q96CS3,P31689,O95757,Q9BS26 +cellular protein modification process P00750,P68036,P38435,O00469,Q86YB8,P22314,P28300,P63279 +protein peptidyl-prolyl isomerization Q6UX04,P62937,Q96AY3,Q9Y680,Q00688 +muscle contraction Q9NYL9,P0DP23,P19105,Q08043,P60660,Q14500,P50402,Q86U42,O14950 +type I interferon signaling pathway P42224,P52630,P04439,P05161,Q10589,Q14653 +positive regulation of protein ubiquitination Q9NV92,P68036,Q13155,Q96EY1,P11021,O76024 +gluconeogenesis P04406,P53007,O75746,Q9UBX3,Q02978 +mitotic nuclear envelope disassembly K7ELV2,P78406,P06493,P50402,P52948 +positive regulation of mesenchymal cell proliferation P37173,P42224,P15692,P35222 +protein targeting to plasma membrane P07355,P19105,Q92953,P35613,O14950 +positive regulation of protein targeting to mitochondrion P19784,P48556,Q8TAD8,P68036,Q9H270,P55786,Q9Y265 +nuclear pore complex assembly P57088,Q9NQC3,P52948 +positive regulation of DNA-templated transcription,elongation Q13769,Q96FV9,Q13838 +endoplasmic reticulum unfolded protein response O76061,P11021,Q9BZQ6,Q9NYU1,O76024 +ER-associated misfolded protein catabolic process Q99470,Q9NYU1,O14656 +relaxation of cardiac muscle P05023,P16615,P05026 +proteasome assembly P48556,Q9UNM6,O00231 +regulation of cardiac muscle cell contraction Q14524,P05023,P63165 +lysine catabolic process Q9UDR5,Q9BQT8,P09622 +potassium ion import Q14500,P48050,P05023,P05026 +proteolysis involved in cellular protein catabolic process P25787,O14818,P11021,P60900,P14735 +substantia nigra development P0DP23,P27348,O15027,P62258,P11021 +establishment or maintenance of epithelial cell apical/basal polarity Q7KZI7,Q96RT1,Q12959 +microtubule cytoskeleton organization Q9P0L2,P04406,Q96N67,Q7KZI7,P06493,P27448 +positive regulation of protein insertion into mitochondrial membrane involved in apoptotic signaling pathway P27348,P62258,P10415,P63104 diff --git a/www/Examples/IntAct_COVID19/HomoSapiens_Gene_Ontology_GOTERM_CC_DIRECT_FILTERED.txt b/www/Examples/IntAct_COVID19/HomoSapiens_Gene_Ontology_GOTERM_CC_DIRECT_FILTERED.txt new file mode 100644 index 0000000..1f0d7e4 --- /dev/null +++ b/www/Examples/IntAct_COVID19/HomoSapiens_Gene_Ontology_GOTERM_CC_DIRECT_FILTERED.txt @@ -0,0 +1,53 @@ +membrane P04406,Q13200,O00203,P62753,Q9NXS2,P09601,Q16630,J3QSV6,P61769,P53621,Q9BSJ2,O43292,P62269,O00148,O95071,P53396,Q2PZI1,P50402,Q00839,Q8IXH7,Q8TEQ8,O14656,P10415,P05556,Q13561,Q13155,P39019,Q8TDD1,Q13011,O60884,Q9BZQ6,Q07820,P29122,Q13352,Q4KMQ2,Q9NZJ7,Q9P2E5,O60684,P11940,Q07817,P62258,P61254,Q9NU22,P38159,Q8NC51,Q9UM54,P35998,Q96A65,Q14974,O43633,P12956,P09874,P16615,P35222,P62195,P30876,Q02224,Q7KZF4,P27348,Q15311,P35232,Q9Y673,Q6PKG0,Q12789,P11021,Q5JWF2,O94826,P35613,Q14152,P07195,Q6DN90,P06576,P50395,P09603,P33527,O75400,Q9Y3U8,P53618,P07355,O14745,P31689,Q9H488,Q99519,Q9UL15,P39656,P30153,Q9Y6E2,Q99460,Q96S66,P11586,P27487,O75592,Q9H307,O00303,Q9Y265,P05023,P09651,P05026,P51570,Q96CW5,Q9UHI6,P04439,Q99470,Q7Z2K6,Q96S52,P26599,P20700,P47756,Q00325,P15692,P51665,P61158,P62191,P19338,Q15365,P27105,P06493,P33176,Q8IXB1,O95373,P46379,O15439,Q14739,P52292,O00429,P38919,O43765,P46782,Q99623,Q16891,P60866,Q9NR30,Q9C0B5,P60660,P13010,P57678,P25205,P08708,Q6P2E9,P62937,Q99615,Q8NEW0,O60762,P38435,P12109,Q9UNM6,O14980,P25705,Q7KZI7,Q9Y4L1,O43852,O00231,Q08431,P49069,Q6NXT4,Q10589 +nucleoplasm P48556,Q13200,Q13769,Q5H9R7,Q3ZCQ8,P53778,P62753,Q16630,Q9NTJ3,P0DP23,Q9BSJ2,P62269,O00148,O95071,P53396,Q7L590,Q00839,Q8IXH7,Q96J01,Q86WX3,Q13151,Q9BRP8,P39019,P39880,Q6NZY4,Q86W42,Q07820,O60885,Q13352,O60684,Q6IEG0,Q9UKV3,P52630,P67809,Q15008,Q9H936,P38159,Q9UM54,P35998,Q00403,Q9Y580,Q14974,P26358,Q14160,P12956,Q92793,P09622,Q96FV9,Q15303,P09874,P35222,P62195,P78563,P30876,P35232,Q6PKG0,Q12789,Q96MM7,Q92900,P63279,O94762,P63104,Q8WX92,Q86VM9,Q9BUQ8,Q92994,Q8N5P1,Q9H3P2,Q9NVW2,P63165,Q14653,Q13838,Q9NQG5,O43818,Q9BXP5,Q9H814,O95347,Q9Y466,O75400,O43592,Q9UER7,P61326,Q09161,P42224,Q99460,Q16576,P18615,Q6PJT7,Q9NWV8,Q5VV67,Q9H307,Q9Y265,P09651,O00629,P52294,Q9BQ95,O95619,P62140,P52298,Q8N0Z6,P49756,Q9UHI6,Q96RT1,P14735,P24928,P26599,P20700,O14818,P35637,Q9Y5S9,Q8NI27,P51665,Q96HW7,P60900,P62191,P19338,Q15365,P19784,Q7Z4H7,P25787,P67870,P06493,Q9ULX6,P68400,O00422,O95373,P08107,P83916,P46379,Q8NEM0,P52292,O75934,P98179,P38919,P12004,P05161,P46782,Q86U42,P60866,Q6I9Y2,Q9UKS6,Q9NR30,Q8TAD8,P13010,P57678,O00505,P52948,P25205,P08708,Q6P2E9,Q99615,Q14011,Q9UNM6,O15397,O14980,P0DMV8,P42677,P08621,Q86U32,O00231 +pseudopodium P12814,Q08043,P55085,O43707,P35609 +brush border P12814,P19105,Q08043,P47756,P60660,O00429,O43707,P61158,O14950 +nuclear matrix O95619,P20700,O75400,O43592,P60900,Q9ULX6,Q96FV9,Q9Y265,Q99623,Q13838 +zona pellucida receptor complex P49368,P17987,P48643,Q99832 +extracellular matrix P07355,P60866,P40227,P04406,P15924,P60660,P39019,P29122,P08708,P06576,P00750,P12109,P62269,P40939,P25705,P11021,Q00839,Q08431,P46782 +cytosolic small ribosomal subunit P60866,P08708,P62269,P39019,P42677,P62753,P46782 +actin filament P12814,Q08043,Q9H270,P47756,Q7KZI7,Q96EY1,P13797,P35609 +cytosolic proteasome complex P35998,P62191,P14735,P62195 +sarcolemma P07355,Q14315,P05556,P12109,Q14524,P35613,P05023,P05026,Q12959 +vesicle P07355,P0DP23,P27105,P33176,P50395,O14745,Q8NEW0,P04406,Q13561,Q9ULV4,P60660 +platelet alpha granule lumen P12814,P05155,P02768,P15692,O43707,P00747,P35609 +perinuclear region of cytoplasm P07355,Q9UM54,P27105,O14745,P04406,P31689,P42224,Q9UL15,O76061,P62753,P09601,P16615,P35222,P33176,Q9NV92,P08107,O00429,O43707,Q5JWF2,P05556,Q99569,P25205,Q8NEW0,P09603,P22460,P35637,P0DMV8,P63244,Q9P289,Q8NC51,Q12959 +spliceosomal complex P49756,O00148,O75934,P08621,Q9NW13,Q9UKA9,O75940,P09651,Q13838 +endoplasmic reticulum quality control compartment Q13438,Q96DZ1,Q9BZQ6,Q9NYU1 +membrane raft P07355,P27105,O14745,P22460,P37173,P27487,P05556,P35613,P31431,P35052,Q9BYF1,P07195,Q10589,Q12959 +Z disc Q14315,P12814,P19105,P22460,Q08043,P47756,Q14524,O43707,P35222,P35609,O14950 +COPI vesicle coat P53621,Q9UBF2,P35606,P53618 +small ribosomal subunit P60866,P62269,P63244,P62753,P46782 +mitochondrial nucleoid P06576,Q9NVI7,Q7L8L6,P40939,P34897,Q96EY1 +cell surface P07355,P05556,Q96PE1,Q14524,P08581,P04439,Q9BYF1,P29122,P14735,Q4KMQ2,Q13443,P06576,P00750,P35232,P27487,P15151,P31431,P11021,P15692,Q13224,Q00839,P00747,Q10589,P34741,Q9BS26,Q99623 +CRD-mediated mRNA stability complex P67809,O75534,Q00839 +endoplasmic reticulum-Golgi intermediate compartment O95070,P11021,Q9Y3A6,P15144,Q9NYU1,Q9BS26,P53618 +microtubule P40227,Q5SW79,Q96CW5,Q7Z4H7,P17987,Q13561,Q14152,Q99832,P49368,P33176,Q02224,Q9BSJ2,P48643,O00429,O60333,P50402,Q12959 +endocytic vesicle Q9UM54,P33176,Q9H270,P27487,P35247,P51148 +cytoplasmic stress granule P11940,Q14011,Q13310,Q13283,P67809 +proteasome regulatory particle,lid subcomplex P48556,Q9UNM6,O00231 +proteasome core complex,alpha-subunit complex P25787,O14818,P60900 +nuclear proteasome complex P35998,P62191,P62195 +mitochondrial matrix Q96EY1,P34897,O75439,Q07820,Q15303,P09622,Q8IZ52,Q9UDR5,Q07817,P06576,P11310,Q5JRX3,Q9BW92,Q10713,P25705,P13804,Q6L8Q7 +cytoplasmic mRNA processing body P35998,Q6P2E9,P25787,Q9Y5A9,P60900,Q9HCE1,Q92900 +lysosomal membrane P07355,Q9UM54,Q8IWA5,O75348,Q99519,O00203,P22314,Q96JC1,P51148,B7Z2Y1,P12109,P27487,Q9H270,P38606,P15144 +intracellular membrane-bounded organelle P35998,P04406,O14745,Q99519,P39656,Q96EY1,Q96S66,O14964,Q9NV92,P46379,O00429,O95070,Q9Y265,P05023,Q8N0Z8,P25205,P51148,Q9UDR5,Q6P2E9,O60762,Q9H814,P67809,O14980,Q15365,P53618 +mitochondrial outer membrane Q07817,Q16548,O94826,Q92843,O00429,Q86UT6,Q07820,Q99623,P10415,Q8N0X7 +integral component of endoplasmic reticulum membrane Q9NZ01,O00124,Q14739,P11021,P57088,Q9P035,Q9NQC3,O76024 +desmosome P15924,Q99569,P22314,Q9H307 +centrosome Q6NXT6,O14745,Q5SW79,Q96CW5,Q8TF76,Q7Z4H7,P17987,Q13561,P06493,P35222,P25205,Q9NQG5,P0DP23,Q07817,Q9H814,Q9BSJ2,P48643,Q8IWR1,Q9P289,P12004 +fascia adherens P12814,P15924,P35222 +cytoplasmic ribonucleoprotein granule P11940,P62753,Q00839,P19338 +caveola P22460,P37173,Q14524,P09601,P05023,P05026 +endoplasmic reticulum chaperone complex Q8IXB1,P11021,Q9Y4L1 +AP-3 adaptor complex Q9H270,O00203,Q96JC1 +DNA-directed RNA polymerase II,holoenzyme Q9NQG5,Q9UM54,O94762 +nuclear euchromatin P16402,P35222,P24928,P38159 +PcG protein complex P19784,Q9BSM1,P67870,P68400 +ruffle P07355,P12814,Q5JWF2,Q9UM54,O14745,P05556,Q14155 +ribosome P60866,P08708,Q86WX3,Q92552,P62269,P39019,P42677,P61927,P62753,Q9Y3U8 +transport vesicle Q5JWF2,P53621,Q9UBF2,Q9H8W4,P35606,Q15818,P53618 +cell-cell junction P07355,Q9NYL9,P12814,Q99569,Q14160,Q9H307,O43707,P61158,P35222,Q12959 +RNA cap binding complex Q09161,Q53F19 +Scrib-APC-beta-catenin complex Q14160,P35222 +proteasome storage granule Q13200,Q99460 diff --git a/www/Examples/IntAct_COVID19/HomoSapiens_Gene_Ontology_GOTERM_MF_DIRECT_FILTERED.txt b/www/Examples/IntAct_COVID19/HomoSapiens_Gene_Ontology_GOTERM_MF_DIRECT_FILTERED.txt new file mode 100644 index 0000000..f576830 --- /dev/null +++ b/www/Examples/IntAct_COVID19/HomoSapiens_Gene_Ontology_GOTERM_MF_DIRECT_FILTERED.txt @@ -0,0 +1,33 @@ +poly(A) RNA binding P62753,J3QSV6,Q16630,Q13283,P62269,O00148,Q02978,O43707,Q00839,Q86WX3,Q13151,P68036,Q9BRP8,P17987,P39019,Q8TDD1,Q6NZY4,P11940,Q9UKV3,P62258,P56270,P16402,P67809,P61254,P63244,Q8NC51,P38159,P40227,Q9Y580,Q14974,P12956,P09874,Q00688,P78563,P30876,Q7KZF4,Q6PKG0,P63279,Q92900,P63104,Q7L8L6,Q8N5P1,Q9BUQ8,Q86VM9,Q14152,P63165,Q9UN86,Q13838,Q8WTT2,O43818,P50395,Q9BXP5,O75400,P61326,Q96A72,Q9Y3U8,P07355,Q09161,Q9Y5A9,P31948,P18615,Q6PJT7,Q9H307,Q5VV67,Q8NCA5,P09651,P15924,Q13310,P20290,P52298,P22314,P49756,P04439,P24928,P26599,P35637,Q9Y5S9,Q9NW13,P19338,P62191,Q15365,P04003,O75534,Q9ULX6,Q9HCE1,Q53F19,O00422,P52292,Q14739,P98179,P38919,Q9UKA9,P46782,Q86U42,Q16891,P60866,Q8TAD8,Q9NR30,P13010,P08708,P62937,P49368,Q14011,P25705,Q7KZI7,P42677,P08621,Q9NQC3,Q86U32,O75940,Q10589 +protein binding Q9P021,Q13200,Q96GX9,Q13769,Q5H9R7,Q3ZCQ8,Q99988,Q86VR2,P62753,Q9NTJ3,P0DP23,P61769,Q9BSJ2,O43292,P62269,Q8TBB1,P59998,P50402,Q8IXH7,Q00839,P34741,Q99569,Q13561,Q07820,P55198,Q13352,Q4KMQ2,Q9NZJ7,Q96GG9,Q9H3K2,Q07817,Q9UKV3,P52630,P62258,Q86YB8,Q8NC51,P35998,P40227,Q00403,P26358,Q96PE1,P35606,Q92793,Q96FV9,Q15303,P09874,P35609,Q9Y680,Q00688,P78563,Q13443,Q15311,P27348,Q6PKG0,Q12789,P11021,Q92900,P63104,Q9ULJ7,Q8WX92,Q7L8L6,P35613,Q9BUQ8,Q9UBX3,Q9P035,P25100,Q13838,Q9NQG5,P06576,Q9Y5U4,Q13438,Q9BXP5,O60333,P55085,Q13224,Q9NS75,P53618,Q09161,O14745,Q9P0K1,Q9UL15,Q9Y5A9,P31948,P30153,Q9H773,Q6PJT7,O75592,Q8NCA5,Q9Y3A6,P57088,O00303,P05023,P09651,P05026,Q9NZ01,P52294,Q9BQ95,Q96CW5,O95619,Q13310,P20290,P52298,Q8N0Z6,P49756,P14735,P24928,P37173,Q9H270,Q9Y5S9,P51665,O00192,P60900,Q96HW7,P00747,P19338,Q15365,Q12959,P27105,Q9BSM1,P25787,P04003,Q9UQB3,Q14CM0,P81408,P67870,Q9HCE1,P68400,Q8IXB1,P33176,O00422,P00750,Q96IZ7,P08107,P46379,P83916,Q8NEM0,Q96DZ1,P48643,O00429,P52292,P05161,O43765,P46782,Q99623,Q9UKS6,Q9NR30,O75348,P52948,P51148,Q8N0X7,P49368,Q99615,P05155,O15397,P0DMV8,P08621,Q6ZTQ3,Q9NQC3,O43852,Q10589,O76024,P25440,P04406,Q9ULV4,Q14524,Q96EY1,P53778,P35247,P09601,Q16630,Q5BJF2,Q9H845,O15027,Q13283,P15151,Q9NXK8,O00148,O95071,O95070,P53396,Q7L590,O43707,O14656,P10415,Q05639,Q86WX3,P68036,Q9BRP8,Q9Y6R1,P05556,O75822,P17987,Q13155,P39019,Q00765,Q13011,Q15293,P48668,O60884,Q6NZY4,O60885,O60684,P11940,P61254,P56270,P67809,Q9NU22,Q15008,P63244,Q96HR9,P31150,P48065,P38159,Q9BS26,Q9H173,Q9UM54,P34932,Q96A65,Q14974,O43633,Q96IV0,P12956,Q14160,Q96PV6,P16615,P35222,Q99832,P62195,P12814,P30876,P19105,Q9H078,Q02224,P52907,Q7KZF4,P35232,Q9Y375,O95816,Q14257,P63279,Q5JWF2,O94826,Q8N5P1,Q86VM9,Q14152,P07195,Q9H3P2,P63165,Q9UN86,Q14155,Q6DN90,Q14653,Q96NW7,P09603,P50395,Q9H814,O95347,P40939,P31431,O75400,Q8IWR1,Q9UER7,P61326,Q96A72,P07355,P31689,P42224,K7ELV2,P39656,Q16576,Q9BYF1,P11586,P18615,P27487,Q9NWV8,Q7Z5G4,Q9H8W4,P13804,Q9Y6M9,Q8N8U2,Q9Y265,Q96SF7,O00629,Q5SW79,P15924,P62140,P22459,P22314,Q9UHI6,Q99471,Q9UH99,P04439,Q96RT1,O14950,Q96S52,P22460,P26599,O14818,P20700,P35637,Q12770,Q8NI27,Q9H4F8,Q86UT6,P15692,Q9P289,P61158,P62191,Q9Y276,P19784,Q8IV08,Q96CS3,O15503,P08581,Q92843,O75534,P06493,Q9ULX6,P61916,Q53F19,O14964,O95373,Q9NV92,Q16548,Q96F46,O00124,Q14739,P28300,O75934,P98179,P48050,P38919,P12004,Q86U42,Q16891,P60866,Q8IWF2,Q6I9Y2,Q8TAD8,Q08043,Q8TF76,P02768,P60660,P13010,P34897,P57678,Q9NYU1,O00505,P27448,P25205,Q14315,Q6P2E9,P62937,O60762,Q14011,Q92552,O14980,P25705,Q7KZI7,P42677,Q96K17,Q5JVF3,O00231,Q86U32,O75940,P49069 +protein domain specific binding Q14974,O43633,Q14524,Q9UHI6,P67870,P35609,O14964,P0DP23,P27348,Q9H270,P62258,O14980,P11021,P05023,P00747,P63104 +ion channel binding P0DP23,P12814,P27348,Q08043,P62258,Q14524,O43707,P35222,P63165,P35609,Q12959 +Hsp70 protein binding Q8IXB1,P31689,P46379,P31948,Q96EY1,P06493 +glycoprotein binding Q8IWF2,P61769,P00750,Q13438,Q96DZ1,P11021,Q9BYF1,P14735 +TBP-class protein binding P35998,Q00403,Q92994,P62191,P62195 +estrogen receptor binding P35637,Q8TDD1,P09874,P12004,P35222,Q99623 +misfolded protein binding Q8IXB1,P46379,P11021,O14656 +protein transporter activity O00629,P52294,O60684,O95373,Q14974,O15397,P52292,O00505 +BH3 domain binding Q07817,Q07820,P10415 +actin filament binding Q14315,P12814,Q9UM54,P47756,Q9ULV4,P59998,O43707,P61158,P13797,Q8NHY3,P35609 +poly(A) binding P11940,Q6PJT7,Q13310,P38919 +identical protein binding P04406,P42224,Q96GX9,P67870,P09874,Q99832,P35609,P61769,Q9H773,P11310,P27487,Q8NEM0,O95816,O00429,O00148,Q7L590,P12004,P10415,P63104,P02768,Q13561,Q9UH99,P34897,P07195,Q13838,Q14653,P06731,Q07817,O14818,P52630,P35637,P15692,Q9P289,P19338,P38159 +Ran GTPase binding O95373,Q14974,O15397,O14980,O43592 +integrin binding Q13443,P12814,Q08043,Q9P0K1,P05556,O43707,Q96RT1,Q08431,P35609 +proteasome-activating ATPase activity P35998,P62191,P62195 +dolichyl-phosphate-mannose-protein mannosyltransferase activity O60762,Q9Y673,Q99470 +cytoskeletal protein binding P07355,Q14315,Q9UKS6,O14656,P35609,Q12959 +oxidoreductase activity,acting on the CH-CH group of donors Q9NZ01,Q9H845,P11310,Q14739 +virus receptor activity P08107,P27487,P05556,P15151,P0DMV8,Q9BYF1,P15144,P14735 +protein N-terminus binding P19784,Q96A65,P27348,Q9UER7,O43707,P09874,P68400,Q99623 +protein homodimerization activity P27105,P42224,Q92843,O76061,P09601,Q15303,P35609,P12814,Q16548,P83916,P27487,P15151,O00429,O43707,Q96SF7,P10415,Q08043,P39019,Q07820,P14735,Q14653,Q4KMQ2,P06731,Q07817,P09603,P63244,P15692,P51665,Q9UER7,Q9P289,Q10589,Q6UY11 +NAD binding P04406,P40939,P07195,P09622,P09874 +protein kinase binding Q05639,Q13151,P62140,Q14524,Q9UL15,P39019,Q96EY1,P62753,P09874,P35222,Q14155,P0DP23,Q07817,P22460,P62269,Q9UER7,P05023,P63104,Q12959 +rRNA binding Q9NR30,Q7L8L6,P62269,P61927,P46782 +histone deacetylase binding P35232,P08107,P62258,P0DMV8,P52292,Q9UHI6,Q9Y466,Q9ULX6,P09874 +telomeric DNA binding P12956,P13010,P19338,Q92900 +RNA cap binding Q09161,Q6PKG0,P52298 +chromatin binding P25440,P26358,Q8N0Z6,Q9ULI0,P67870,P34897,Q92793,P06493,O60885,Q9H3P2,P18615,P30876,Q8WTT2,P83916,P67809,Q92900,P12004,Q6PML9,P38159 +cation transmembrane transporter activity Q8NEW0,Q6NXT4,Q6PML9 +phospholipid scramblase activity A1A5B4,Q32M45,Q4KMQ2 +peptidyl-prolyl cis-trans isomerase activity Q6UX04,P62937,Q96AY3,Q9Y680,Q00688 \ No newline at end of file diff --git a/www/Examples/IntAct_COVID19/HomoSapiens_Pathways_KEGG_PATHWAY_FILTERED.txt b/www/Examples/IntAct_COVID19/HomoSapiens_Pathways_KEGG_PATHWAY_FILTERED.txt new file mode 100644 index 0000000..6571ad7 --- /dev/null +++ b/www/Examples/IntAct_COVID19/HomoSapiens_Pathways_KEGG_PATHWAY_FILTERED.txt @@ -0,0 +1,4 @@ +Viral carcinogenesis Q00403,Q08043,Q14160,P04439,Q96EY1,Q92793,P06493,P35609,Q14653,P12814,P27348,Q7KZF4,P62258,O43707,P62191,P63104,Q12959 +Influenza A P52294,P42224,P78406,Q92793,P53778,P52948,Q13838,Q14653,P08107,P52630,P0DMV8,O14980,P52292,Q86UT6,P00747,Q86U42 +Herpes simplex infection P19784,P42224,P62140,P67870,P04439,Q92793,P06493,P68400,P24928,Q14653,P52630,Q9UER7,Q86U32 +Proximal tubule bicarbonate reclamation Q9Y6R1,Q9UBX3,P05023,P05026 diff --git a/www/Examples/IntAct_COVID19/HomoSapiens_Protein_Domains_INTERPRO_FILTERED.txt b/www/Examples/IntAct_COVID19/HomoSapiens_Protein_Domains_INTERPRO_FILTERED.txt new file mode 100644 index 0000000..21ddc96 --- /dev/null +++ b/www/Examples/IntAct_COVID19/HomoSapiens_Protein_Domains_INTERPRO_FILTERED.txt @@ -0,0 +1,58 @@ +P-loop containing nucleoside triphosphate hydrolase Q9UM54,P35998,Q9NVI7,Q9ULI0,Q5T9A4,Q9HCE1,Q9NTJ3,P11586,P62195,Q02224,P33176,Q9H078,P38606,O00429,O15439,O00148,Q00839,Q9Y265,P38919,Q92900,Q96MM7,O14656,O94762,Q05639,Q5JWF2,Q9NR30,Q8TDD1,Q9UHI6,Q9BUQ8,Q13838,P51148,P25205,P06576,P33527,O95347,Q9NU22,P25705,O60333,P62191,Q9Y276,Q12959 +EF-hand-like domain Q08043,P42224,P60660,Q15293,Q07820,P35609,Q9Y680,O14950,P0DP23,P12814,P19105,P52630,O75746,Q9H4F8,Q96AY3,O43707,O43852,Q14257,P13797 +Apoptosis regulator,Bcl-2,BH4 motif,conserved site Q07817,Q92843,P10415 +ATPase,F1/V1/A1 complex,alpha/beta subunit,C-terminal P06576,P38606,P25705 +Apoptosis regulator,Bcl-2 protein,BH4 Q07817,Q92843,P10415 +DNA/RNA helicase,DEAD/DEAH box type,N-terminal Q9NR30,Q8TDD1,Q9BUQ8,Q9UHI6,O00148,P38919,Q13838,O94762 +Filamin/ABP280 repeat-like Q14315,O75592,Q7Z4H8,Q6UW63 +Chaperone DnaJ P31689,Q96EY1,O60884 +Calponin homology domain Q14315,P12814,Q08043,O43707,P13797,Q8NHY3,P35609,Q14155 +RNA recognition motif domain,eukaryote P11940,Q14011,Q13310,P19338,P38159 +ATPase,AAA-type,conserved site P35998,Q9ULI0,P62191,Q9Y276,P62195 +Peptidase M16,zinc-binding site Q10713,O75439,P14735 +Kinase associated domain 1 (KA1) Q9P0L2,Q7KZI7,P27448 +ATPase,alpha/beta subunit,N-terminal P06576,P38606,P25705 +Heat shock protein DnaJ,cysteine-rich domain P31689,Q96EY1,O60884 +ATPase,F1/V1/A1 complex,alpha/beta subunit,nucleotide-binding domain P06576,P38606,P25705 +ATPase,alpha/beta subunit,nucleotide-binding domain,active site P06576,P38606,P25705 +Spectrin/alpha-actinin P12814,Q08043,P15924,O43707,P35609 +Immunoglobulin E-set Q14315,Q96DL1,O75592,P08581,Q14500,Q7Z4H8,P48050,P61916,Q6UW63 +EF-Hand 1,calcium-binding site P0DP23,P12814,P19105,O75746,Q9H4F8,Q15293,Q96AY3,O43707,O43852,P13797,Q14257,Q9Y680,O14950 +EF-hand domain Q08043,P60660,Q15293,P35609,Q9Y680,O14950,P12814,P0DP23,P19105,O75746,Q96AY3,O43707,O43852,P13797,Q14257 +26S proteasome subunit P45 P35998,P62191,P62195 +G-protein beta WD-40 repeat O43818,P53621,K7ELV2,P78406,P35606,P63244,Q16576,Q96J01 +14-3-3 protein P27348,P62258,P63104 +14-3-3 protein,conserved site P27348,P62258,P63104 +14-3-3 domain P27348,P62258,P63104 +Apoptosis regulator,Bcl-2,BH3 motif,conserved site Q07817,Q07820,P10415 +Proteasome A-type subunit P25787,O14818,P60900 +Proteasome,alpha-subunit,N-terminal domain P25787,O14818,P60900 +Chaperone DnaJ,C-terminal P31689,Q96EY1,O60884 +HSP40/DnaJ peptide-binding P31689,Q96EY1,O60884 +Helicase,C-terminal Q9NR30,Q8TDD1,Q9BUQ8,Q9UHI6,O00148,P38919,Q13838,O94762 +Cation efflux protein Q8NEW0,Q6NXT4,Q6PML9 +Cation efflux protein transmembrane domain Q8NEW0,Q6NXT4,Q6PML9 +Filamin/ABP280 repeat Q14315,Q7Z4H8,Q6UW63 +Spectrin repeat P12814,Q08043,O43707,P35609 +Helicase,superfamily 1/2,ATP-binding domain Q9NR30,Q8TDD1,Q9BUQ8,Q9UHI6,O00148,P38919,Q13838,O94762 +Bromodomain,conserved site P25440,Q9ULI0,Q92793,O60885 +Anoctamin/TMEM 16 A1A5B4,Q32M45,Q4KMQ2 +RNA helicase,ATP-dependent,DEAD-box,conserved site Q8TDD1,Q9BUQ8,Q9UHI6,P38919 +Mitochondrial carrier protein P53007,O75746,Q9BQT8,Q9H936 +Tetratricopeptide TPR-1 Q99615,O94826,P31948,O43765 +Band 7 protein P27105,P35232,Q99623 +WD40-repeat-containing domain K7ELV2,Q9ULV4,P78406,P35606,Q86W42,Q16576,Q96JC1,O43818,B7Z2Y1,P53621,Q6P2E9,Q9H270,Q12770,P63244,Q96J01 +von Willebrand factor,type A Q9NWV8,P05556,P12109,P12956,Q9NU22,P13010,P10155 +DnaJ domain Q8IXB1,Q99615,P31689,Q96EY1,O60884 +Proteasome/cyclosome,regulatory subunit Q13200,Q99460 +Apoptosis regulator,Bcl-2/ BclX Q07817,P10415 +Transcription factor TFIIB,cyclin-like domain Q00403,Q92994 +Insulin-induced protein family O15503,Q9Y5U4 +Coatomer,WD associated region P53621,P35606 +Ku70/Ku80 C-terminal arm P12956,P13010 +Ku70/Ku80,N-terminal alpha/beta P12956,P13010 +Ku70/Ku80 beta-barrel domain P12956,P13010 +Rab GDI protein P50395,P31150 +ATPase,F1 complex beta subunit/V1 complex,C-terminal P06576,P38606 +Mago nashi protein P61326,Q96A72 +Clathrin/coatomer adaptor,adaptin-like,N-terminal Q9UBF2,O00203,P53618 \ No newline at end of file diff --git a/www/Examples/IntAct_COVID19/HomoSapiens_Protein_Domains_SMART_FILTERED.txt b/www/Examples/IntAct_COVID19/HomoSapiens_Protein_Domains_SMART_FILTERED.txt new file mode 100644 index 0000000..c464f8e --- /dev/null +++ b/www/Examples/IntAct_COVID19/HomoSapiens_Protein_Domains_SMART_FILTERED.txt @@ -0,0 +1,12 @@ +SM00265:BH4 Q07817,Q92843,P10415 +SM00033:CH Q14315,P12814,Q08043,O43707,P13797,Q8NHY3,P35609,Q14155 +SM00361:RRM_1 P11940,Q14011,Q13310,P19338,P38159 +SM00150:SPEC P12814,Q08043,P15924,O43707,P35609 +SM00088:PINT Q9UNM6,Q15008,Q14152,O00231 +SM00101:14_3_3 P27348,P62258,P63104 +SM00948:SM00948 P25787,O14818,P60900 +SM00557:IG_FLMN Q14315,Q7Z4H8,Q6UW63 +SM00490:HELICc Q9NR30,Q8TDD1,Q9BUQ8,Q9UHI6,O00148,P38919,Q13838,O94762 +SM00487:DEXDc Q9NR30,Q8TDD1,Q9BUQ8,Q9UHI6,O00148,P38919,Q13838,O94762 +SM00244:PHB P27105,P35232,Q99623 +SM00271:DnaJ Q8IXB1,Q99615,P31689,Q96EY1,O60884 diff --git a/www/Examples/IntAct_COVID19/Intact-data_COVID19_no_self_loops.txt b/www/Examples/IntAct_COVID19/Intact-data_COVID19_no_self_loops.txt new file mode 100644 index 0000000..69e87de --- /dev/null +++ b/www/Examples/IntAct_COVID19/Intact-data_COVID19_no_self_loops.txt @@ -0,0 +1,1094 @@ +Source Target +P31809 P11224 +P33767 P41811 +Q3T133 P41811 +P39656 P41811 +P41811 O15503 +Q91AV1 P41811 +Q96WV5 P68978 +Q9Y5U4 P41811 +P53622 P41811 +P53622 Q3T133 +P53622 P41811 +P53622 P33767 +P53622 P41811 +P53622 P68978 +P53622 P41811 +P53622 P39656 +Q3T133 Q96WV5 +Q96WV5 P39656 +Q96WV5 P33767 +Q96WV5 P68978 +P53622 P41811 +P53622 Q9Y5U4 +P53622 P41811 +P53622 Q91AV1 +P53622 P41811 +P53622 O15503 +Q96WV5 Q9Y5U4 +Q96WV5 O15503 +Q91AV1 Q96WV5 +P53622 P41811 +P53622 P41811 +P53622 P41811 +P53622 P41811 +P53622 P41811 +P27487 K0BRG7 +P27487 K0BRG7 +Q9BYF1-1 P59594 +P27487 K0BRG7 +Q9BYF1-1 P59594 +P27487 K0BRG7 +P27487 K0BRG7 +P0C6U8 P62753 +Q9BYF1-1 Q6Q1S2 +Q9BYF1-1 Q6Q1S2 +Q9BYF1-1 Q6Q1S2 +Q7TLC7 O14964 +Q7TLC7 P05155 +Q7TLC7 Q13561 +Q7TLC7 Q9NRH1 +J9TC74 Q13561 +J9TC74 P62258 +J9TC74 Q99471 +P59633 Q13561 +P59633 P05155 +P59633 P02768 +Q6S8E0 P08708 +Q6S8E0 P25787 +P59634 Q13561 +P59634 Q92994 +Q19QW4 Q9BQB6 +Q19QW4 Q9H4F8 +Q7T6S2 P49069 +Q7T6S2 P05155 +Q6S8E0 P60866 +Q6S8E0 P27448 +Q19QW2 P46379 +Q6S8E0 P60866 +Q19QW2 P46379 +P59634 Q13561 +Q7T6S2 P49069 +Q19QW4 Q9BQB6 +Q6S8E0 P27448 +Q6S8E0 P25787 +Q7TLC7 O14964 +Q7TLC7 Q13561 +Q1HVL3 P15144 +Q1HVL8 P15144 +Q1HVK9 P15144 +Q9BYF1 P0DTC2 +Q9BYF1 P59594 +K9N5Q8 P27487 +Q9BYF1 P0DTC2 +Q9BYF1 P59594 +Q9BYF1 P0DTC2 +Q9BYF1 P59594 +Q9BYF1 P0DTC2 +Q9BYF1 P59594 +Q9BYF1 P59594 +P61769 P04439 +P61769 P59595 +P61769 P04439 +P61769 P03407 +P61769 P04439 +P61769 P59595 +P61769 P04439 +P61769 P59596 +P61769 P04439 +P61769 Q692E0 +P61769 P04439 +P61769 P59596 +P61769 P04439 +P61769 Q76R37 +P61769 P04439 +P61769 P59637 +Q9BYF1 P0DTC2 +Q9BYF1 P0DTC2 +Q9BYF1 P0DTC2 +Q9BYF1 P0DTC2 +Q9BYF1 P59594 +Q9BYF1 P0DTC2 +Q9BYF1 P0DTC2 +Q9BYF1 Q695T7 +Q9BYF1 Q695T7 +Q9BYF1 P0DTC2 +Q9BYF1 Q695T7 +Q9BYF1 P37173 +Q9BYF1 P37173 +P11021 K0BRG7 +P11021 K0BRG7 +P11021 K0BRG7 +P11021 K0BRG7 +P11021 K0BRG7 +P11021 K0BRG7 +P11021 K0BRG7 +P11021 K0BRG7 +K0BRG7 P11021 +P0DTC4 Q8IWA5 +P0DTC4 Q86VM9 +P0DTC4 Q6UX04 +P0DTC4 P25440 +P0DTC4 O60885 +P0DTC4 O00203 +P0DTC9 Q9Y3U8 +P0DTC9 Q9NW13 +P0DTC9 Q9NR30 +P0DTC9 Q9UN86 +P0DTC9 Q9HCE1 +P0DTC9 Q92900 +P0DTC9 Q8TAD8 +P0DTC9 Q8NCA5 +P0DTC9 Q6PKG0 +P0DTC9 Q13310 +P0DTC9 Q13283 +P0DTC9 P67870 +P0DTC9 P19784 +P0DTC9 P11940 +P0DTC9 O43818 +P0DTC2 Q9C0B5 +P0DTC2 Q7Z5G4 +P0DTC5 Q9Y6E2 +P0DTC5 Q9Y312 +P0DTC5 Q9ULX6 +P0DTC5 Q9UDR5 +P0DTC5 Q9UBU6 +P0DTC5 Q9NQC3 +P0DTC5 Q9BW92 +P0DTC5 Q9BSJ2 +P0DTC5 Q9BQT8 +P0DTC5 Q96HW7 +P0DTC5 Q96HR9 +P0DTC5 Q96ER3 +P0DTC5 Q96D53 +P0DTC5 Q96CW5 +P0DTC5 Q8NEW0 +P0DTC5 Q7L8L6 +P0DTC5 Q6PML9 +P0DTC5 Q5JRX3 +P0DTC5 Q4KMQ2 +P0DTC5 Q10713 +P0DTC5 Q00765 +P0DTC5 P48556 +P0DTC5 P38606 +P0DTC5 P38435 +P0DTC5 P27105 +P0DTC5 P13804 +P0DTC5 P11310 +P0DTC5 P05026 +P0DTC5 O95070 +P0DTC5 O75439 +P0DTC6 Q9NZJ7 +P0DTC6 P78406 +P0DTC6 P52948 +P0DTC3 Q9Y673 +P0DTC3 Q9UH99 +P0DTC3 Q9H270 +P0DTC3 Q96S66 +P0DTC3 Q96JC1 +P0DTC3 Q8N6S5 +P0DTC3 Q8IWR1 +P0DTC3 P09601 +P0DTC7 Q9NU22 +P0DTC7 Q7Z4Q2 +P0DTC8 Q96IV0 +P0DTC8 Q8N0Z8 +P0DTC8 Q96AY3 +P0DTC8 Q13443 +P0DTC8 Q9Y680 +P0DTC8 Q9Y4L1 +P0DTC8 Q9UHI8 +P0DTC8 Q9P2E5 +P0DTC8 Q9NYU1 +P0DTC8 Q9NXK8 +P0DTC8 Q9H8W4 +P0DTC8 Q9H4F8 +P0DTC8 Q9H488 +P0DTC8 Q9H173 +P0DTC8 Q9BZQ6 +P0DTC8 Q9BS26 +P0DTC8 Q9BRN9 +P0DTC8 Q99988 +P0DTC8 Q99519 +P0DTC8 Q99470 +P0DTC8 Q96MM7 +P0DTC8 Q96F46 +P0DTC8 Q96DZ1 +P0DTC8 Q92820 +P0DTC8 Q8N766 +P0DTC8 Q8IZ52 +P0DTC8 Q8IWF2 +P0DTC8 Q8IV08 +P0DTC8 Q86YB8 +P0DTC8 Q7Z4H8 +P0DTC8 Q6UW63 +P0DTC8 Q15818 +P0DTC8 Q13438 +P0DTC8 Q08431 +P0DTC8 P61916 +P0DTC8 P58166 +P0DTC8 P29122 +P0DTC8 P28300 +P0DTC8 P26358 +P0DTC8 P15151 +P0DTC8 P12109 +P0DTC8 P0C7P0 +P0DTC8 P05556 +P0DTC8 P00750 +P0DTC8 O76061 +P0DTC8 O14656 +P0DTC8 O00469 +P0DTD2 Q9UL15 +P0DTD2 Q9UKA9 +P0DTD2 Q9P0L2 +P0DTD2 Q9H773 +P0DTD2 Q9H2P9 +P0DTD2 Q7KZI7 +P0DTD2 P27448 +P0DTD2 O94826 +P0DTD2 O75534 +P0DTD2 O43633 +P0DTD2 O14745 +P0DTD3 Q9Y3A6 +P0DTD3 Q2PZI1 +P0DTD3 Q96S52 +P0DTD3 Q9Y6M9 +P0DTD3 Q9Y375 +P0DTD3 Q9Y276 +P0DTD3 Q9NV92 +P0DTD3 Q9H845 +P0DTD3 Q9H3K2 +P0DTD3 Q9GZU3 +P0DTD3 Q9BVK2 +P0DTD3 Q9BQ95 +P0DTD3 Q96K12 +P0DTD3 Q8TEQ8 +P0DTD3 Q86VR2 +P0DTD3 Q86UT6 +P0DTD3 Q7Z2K6 +P0DTD3 Q6NXT6 +P0DTD3 Q6NXT4 +P0DTD3 Q5BJF2 +P0DTD3 Q12770 +P0DTD3 P55085 +P0DTD3 P33527 +P0DTD3 O76024 +P0DTD3 O43292 +P0DTD3 O00124 +Q1LZX8 P59594 +Q1LZX8 P84198 +Q1LZX8 P84198 +Q1LZX8 P59594 +P84198 P59594 +P84198 P59594 +P59637 Q64373 +P59637 O35843 +Q64373 Q07817 +Q64373 P59637 +P59637 O35843 +P59637 Q07817 +P06731-1 K0BRG7 +P06731 K0BRG7 +K0BRG7 P06731 +P06731 K0BRG7 +P06731 K0BRG7 +P59637 P59636 +P59633 P59637 +Q7TFA0 P59636 +Q7TFA1 Q19QW5 +Q80H93 Q7TFA0 +P59596 P59632 +P59594 P59635 +Q7TFA1 P59637 +P59594 Q80H93 +Q7TFA1 Q80H93 +Q7TFA0 Q80H93 +Q7TLC7 P59636 +Q7TFA1 P59636 +Q80H93 P59636 +Q7TLC7 Q80H93 +Q7TFA1 P59637 +P59595 P59596 +Q7TFA1 Q19QW5 +Q7TLC7 P59636 +Q7TLC7 P59636 +Q9BYF1 P02768 +F1RG45 K7GLM4 +Q9BYF1 P05814 +Q9BYF1 P0DTC2 +Q9BYF1 P59594 +Q92793 Q14653 +Q92793 Q14653 +Q07817 P59635 +P59635 P10415 +Q07820 P59635 +Q16548 P59635 +P59635 Q92843 +Q9BYF1 P59594 +Q9BYF1 Q6Q1S2 +Q9BYF1 P59594 +Q9BYF1 Q6Q1S2 +Q9BYF1 Q6Q1S2 +P59594 P00747 +P59594 P00762 +Q6ZMR5 P59594 +Q9BYF1 P59594 +Q9BYF1 P59594 +Q9BYF1 P59594 +Q9BYF1 P59594 +Q9BYF1 P59594 +Q9BYF1 P59594 +P59594 Q56NL1 +P59595 P63279 +P59595 P63279 +P59595 P63279 +P59595 P63279 +P20290 Q86VG3 +Q86U32 Q86VG3 +P24928 Q86VG3 +P20290 Q86VG3 +P20290 Q86VG3 +P20290 Q86VG3 +O00303 P59594 +O00303 P59594 +O00303 P11223 +O00303 P59594 +O00303 P11223 +O00303 P59594 +O00303 P59594 +P59595 Q05639 +P03070 P02340 +P59595 Q05639 +Q05639 P59595 +P59595 Q05639 +P59595 Q05639 +P15130 Q05639 +Q05639 P59595 +Q05639 P08107 +Q05639 P59595 +Q05639 P08107 +P59595 Q05639 +P59595 Q05639 +P59595 Q05639 +P59595 P63279 +P59595 P63279 +P59595 P63279 +P59595 P63279 +P59595 P63279 +P59595 P63279 +P59595 P63279 +P59595 P63279 +P59595 P62937 +P59595 P62937 +P35613 P62937 +Q9BYF1 P59594 +P59594 Q5EGZ1 +Q9BYF1 P59594 +P59594 Q5EGZ1 +P59594 Q56NL1 +Q9BYF1 Q5GDB5 +Q9BYF1 P59594 +Q56NL1 P59594 +Q9BYF1 P59594 +P59594 Q56NL1 +Q56NL1 Q5GDB5 +Q9BYF1 Q5GDB5 +Q9BYF1 P59594 +P0DTC2 P62269 +P0DTC2 Q96N67 +P0DTC2 P63244 +P0DTC2 P40227 +P0DTC2 P07195 +P0DTC2 P08621 +P0DTC2 P60660 +P0DTC2 P47756 +P0DTC2 P52907 +P0DTC2 Q9NYL9 +P0DTC2 P13797 +P0DTC2 Q9ULV4 +P0DTC2 P59998 +P0DTC2 P61158 +P0DTC2 Q9UM54 +P0DTC4 Q9ULX6 +P0DTC4 P50402 +P0DTC4 Q00325 +P0DTC4 P05023 +P0DTC4 O75746 +P0DTC4 P16615 +P0DTC4 Q9P035 +P0DTC4 Q5H9R7 +P0DTC5 P30876 +P0DTC5 O15397 +P0DTC5 Q9H078 +P0DTC5 P62195 +P0DTC5 P26599 +P0DTC5 O60762 +P0DTC5 Q9H936 +P0DTC5 O00231 +P0DTC5 Q9ULX6 +P0DTC5 Q9UHI6 +P0DTC5 Q7Z4H7 +P0DTC5 Q96EY1 +P0DTC5 Q00325 +P0DTC5 Q15008 +P0DTC5 O14818 +P0DTC5 P40939 +P0DTC5 P50402 +P0DTC5 Q5H9R7 +P0DTC5 O95757 +P0DTC5 P57678 +P0DTC5 P31689 +P0DTC5 O15027 +P0DTC5 P60900 +P0DTC5 P25705 +P0DTC5 P51665 +P0DTC5 P62191 +P0DTC5 P06576 +P0DTC5 Q14257 +P0DTC5 Q99615 +P0DTC5 O95816 +P0DTC5 O95071 +P0DTC5 P46379 +P0DTC5 O75746 +P0DTC5 Q9Y5A9 +P0DTC5 Q13200 +P0DTC5 P53618 +P0DTC5 Q9NZ01 +P0DTC5 P35998 +P0DTC5 Q16891 +P0DTC5 O60884 +P0DTC5 O43852 +P0DTC5 Q99460 +P0DTC5 Q9NTJ3 +P0DTC5 P53621 +P0DTC5 P55786 +P0DTC5 Q15293 +P0DTC5 P34932 +P0DTC5 Q9UBF2 +P0DTC5 O43592 +P0DTC5 P35606 +P0DTC5 P05023 +P0DTC5 O95347 +P0DTC5 P16615 +P0DTC5 O14980 +P0DTC5 Q96CS3 +P0DTC5 Q9P035 +P0DTC9 P09622 +P0DTC9 P08621 +P0DTC9 P38159 +P0DTC9 Q13151 +P0DTC9 Q9UN86 +P0DTC9 Q13283 +P0DTC9 Q9UM54 +P0DTC3 P40939 +P0DTC3 Q14257 +P0DTC3 P22314 +P0DTC3 P04406 +P0DTC3 P57088 +P0DTC3 Q8IXB1 +P0DTC3 Q00325 +P0DTC3 P31689 +P0DTC3 P25705 +P0DTC3 O43852 +P0DTC3 O95757 +P0DTC3 P46379 +P0DTC3 P53621 +P0DTC3 Q9H936 +P0DTC3 O60884 +P0DTC3 P26599 +P0DTC3 O75746 +P0DTC3 P11586 +P0DTC3 Q9NZ01 +P0DTC3 P53007 +P0DTC3 P05023 +P0DTC3 Q96CS3 +P0DTC3 O43592 +P0DTC3 O95347 +P0DTC3 P16615 +P0DTC3 Q16891 +P0DTC3 O14980 +P0DTC3 Q9P035 +P0DTC6 Q5SW79 +P0DTC6 P25705 +P0DTC6 Q92552 +P0DTC6 P06576 +P0DTC6 P15924 +P0DTC6 P53396 +P0DTC6 P16615 +P0DTC6 Q5T9A4 +P0DTC6 P05023 +P0DTC6 O75592 +P0DTC6 O75934 +P0DTC6 O14980 +P0DTC6 Q96CS3 +P0DTC6 P78406 +P0DTC6 Q9NVI7 +P0DTC6 P33176 +P0DTC6 Q13561 +P0DTC6 Q6P2E9 +P0DTC7 P30153 +P0DTC7 P06576 +P0DTC7 P40939 +P0DTC7 Q8IXB1 +P0DTC7 Q9UHI6 +P0DTC7 O95816 +P0DTC7 P53007 +P0DTC7 Q96EY1 +P0DTC7 P50402 +P0DTC7 O43852 +P0DTC7 Q9H936 +P0DTC7 P62195 +P0DTC7 P30876 +P0DTC7 Q99615 +P0DTC7 P55786 +P0DTC7 P57678 +P0DTC7 Q00325 +P0DTC7 O75746 +P0DTC7 O15027 +P0DTC7 P34932 +P0DTC7 Q15008 +P0DTC7 Q9UNM6 +P0DTC7 O95071 +P0DTC7 O60884 +P0DTC7 P62191 +P0DTC7 P05023 +P0DTC7 P51665 +P0DTC7 P53618 +P0DTC7 Q9NZ01 +P0DTC7 P35998 +P0DTC7 Q13200 +P0DTC7 P53621 +P0DTC7 Q5H9R7 +P0DTC7 P16615 +P0DTC7 Q99460 +P0DTC7 O43592 +P0DTC7 Q9NXS2 +P0DTC7 P46379 +P0DTC7 Q16891 +P0DTC7 O95347 +P0DTC7 P35606 +P0DTC7 Q9UBF2 +P0DTC7 Q9P035 +P0DTC7 O14980 +P0DTC7 Q96CS3 +P0DTD8 Q14257 +P0DTD8 O60762 +P0DTD8 O43852 +P0DTD8 P25705 +P0DTD8 P31689 +P0DTD8 P06576 +P0DTD8 Q8WTT2 +P0DTD8 Q7KZF4 +P0DTD8 Q9NVI7 +P0DTD8 P05023 +P0DTD8 P55786 +P0DTD8 Q00325 +P0DTD8 P53618 +P0DTD8 P57088 +P0DTD8 O43592 +P0DTD8 O95347 +P0DTD8 Q9NZ01 +P0DTD8 Q16891 +P0DTD8 P16615 +P0DTD8 P53621 +P0DTD8 Q9NXS2 +P0DTD8 Q96CS3 +P0DTD8 Q02978 +P0DTD8 P35606 +P0DTD8 Q9UBF2 +P0DTD8 Q9P035 +P0DTD8 O14980 +P0DTD8 P10155 +P0DTC8 Q14152 +P0DTC8 P50402 +P0DTC8 Q9UHI6 +P0DTC8 P06576 +P0DTC8 P62195 +P0DTC8 P25705 +P0DTC8 P40939 +P0DTC8 Q5JWF2 +P0DTC8 O14818 +P0DTC8 P55786 +P0DTC8 P57678 +P0DTC8 O43852 +P0DTC8 Q12789 +P0DTC8 Q9H936 +P0DTC8 P31689 +P0DTC8 Q15008 +P0DTC8 Q9UNM6 +P0DTC8 Q00325 +P0DTC8 O15027 +P0DTC8 P30876 +P0DTC8 Q7KZF4 +P0DTC8 Q9NVI7 +P0DTC8 O60884 +P0DTC8 Q13200 +P0DTC8 P05023 +P0DTC8 O95071 +P0DTC8 P35998 +P0DTC8 O43592 +P0DTC8 Q02978 +P0DTC8 Q9NZ01 +P0DTC8 P53618 +P0DTC8 Q99460 +P0DTC8 O75746 +P0DTC8 P16615 +P0DTC8 P53621 +P0DTC8 Q16891 +P0DTC8 O95347 +P0DTC8 O14980 +P0DTC8 Q9P035 +P0DTC8 Q9UBF2 +P0DTC8 P46379 +P0DTD2 P19105 +P0DTD2 Q14315 +P0DTD2 P62140 +P0DTD2 P0DP23 +P0DTD2 P09622 +P0DTD2 P52907 +P0DTD2 P60660 +P0DTD2 Q9NYL9 +P0DTD2 P13797 +P0DTD2 Q9UM54 +P0DTD2 Q9ULV4 +P0DTD2 P59998 +P0DTD3 Q9BUQ8 +P0DTD3 Q96N67 +P0DTD3 Q15365 +P0DTD3 P17987 +P0DTD3 O00231 +P0DTD3 Q14257 +P0DTD3 Q16576 +P0DTD3 P62269 +P0DTD3 Q58FF8 +P0DTD3 P27348 +P0DTD3 P40227 +P0DTD3 P63244 +P0DTD3 P49368 +P0DTD3 Q9Y265 +P0DTD3 P07355 +P0DTD3 P46379 +P0DTD3 P48643 +P0DTD3 Q99832 +P0DTD3 Q9UHI6 +P0DTD3 P31948 +P0DTD3 Q3ZCQ8 +P0DTD3 Q9NVI7 +P0DTD3 P46782 +P0DTD3 P25205 +P0DTD3 P30153 +P0DTD3 Q9ULX6 +P0DTD3 P42677 +P0DTD3 P61158 +P0DTD3 P09874 +P0DTD3 P50402 +P0DTD3 P30876 +P0DTD3 Q9NXS2 +P0DTD3 P40939 +P0DTD3 P06493 +P0DTD3 P51570 +P0DTD3 Q7Z4H7 +P0DTD3 P57088 +P0DTD3 Q14739 +P0DTD3 P10155 +P0DTD3 Q9UM54 +P0DTD3 P04406 +P0DTD3 Q9H936 +P0DTD3 P11586 +P0DTD3 Q9UBX3 +P0DTD3 Q5H9R7 +P0DTD3 P53618 +P0DTD3 P53007 +P0DTD3 P12004 +P0DTD3 P05023 +P0DTD3 Q16891 +P0DTD3 Q9NZ01 +P0DTD3 O14980 +P0DTD3 O95347 +P0DTD3 Q9NTJ3 +P0DTD3 P53621 +P0DTD3 P16615 +P0DTD3 O43592 +P0DTD3 Q9UBF2 +P0DTD3 P35606 +P0DTD3 Q9P035 +P59594 P35247 +P52294 P52630 +P52294 P42224 +P52292 Q14974 +P52294 P42224 +P52294 Q14974 +P52292 Q14974 +P52294 P42224 +P52292 Q14974 +P52292 Q14974 +Q99623 P35232 +Q99623 P35232 +O35129 P67778 +O35129 Q9JIA7 +O35129 P67778 +O35129 P19783 +O35129 P00397 +O35129 P67778 +P00405 P19783 +P00405 P12787 +P00405 P19536 +P00405 Q9CPQ1 +P00405 P56391 +P00405 P56392 +P12904 P06782 +P33469 P13010 +P33469 P39019 +P33469 P61254 +P33469 P16402 +P33469 P09651 +P33469 P67809 +P33469 P0DMV8 +P33469 P11940 +P33469 P12956 +P33469 Q00839 +P33469 P19338 +P33469 P67809 +P33469 P12956 +P33469 Q00839 +P33469 P19338 +K0BWD0 P05161 +P05161 K0BWD0 +K0BWD0 P05161 +K0BWD0 P05161 +R9QB93 K0BWD0 +O43765 P59635 +O43765 P59635 +P59635 P59596 +P59635 P59637 +Q5MAG3 P59635 +O43765 P59635 +P59595 P59596 +P0DTC2 P35613 +P0DTC2 P35613 +P0DTC2 P35613 +P0DTC2 P35613 +P0DTC2 P35613 +P04135 F1S215 +P04135 F1RNN5 +P04135 A6M930 +P04135 A6M930 +P04135 A6M930 +P04135 A6M930 +Q9BYF1 P0DTC2 +Q9BYF1 P59594 +Q9BYF1 P0DTC2 +Q9BYF1 P59594 +Q9BYF1 P0DTC2 +Q9BYF1 P59594 +Q9BYF1 P0DTC2 +Q9BYF1 P0DTC2 +Q53F19 P56270 +Q53F19 Q14011 +Q53F19 Q8N0Z6 +Q53F19 Q8N8U2 +Q53F19 P35052 +Q53F19 O95373 +Q53F19 Q9UH99 +Q53F19 Q8NEM0 +Q53F19 Q32M45 +Q53F19 Q6L8Q7 +Q53F19 Q6PJT7 +Q53F19 Q02224 +Q53F19 P31150 +Q53F19 Q5DJT8 +Q53F19 Q9UER7 +Q53F19 P48668 +Q53F19 O75940 +Q53F19 J3QSV6 +Q53F19 O95619 +Q53F19 Q7L590 +Q53F19 Q96GX9 +Q53F19 Q6IEG0 +Q53F19 Q9BY42 +Q53F19 P61326 +Q53F19 Q96IZ7 +Q53F19 Q8TF76 +Q53F19 O00148 +Q53F19 P49756 +Q53F19 Q10589 +Q53F19 P31431 +Q53F19 P34741 +Q53F19 P83916 +Q53F19 P63104 +Q53F19 O75400 +Q53F19 Q8TDD1 +Q53F19 P09603 +Q53F19 Q86WX3 +Q53F19 Q00403 +Q53F19 Q13352 +Q53F19 Q13011 +Q53F19 Q9BRP8 +Q53F19 Q9BSM1 +Q53F19 Q6SPF0 +Q53F19 O60684 +Q53F19 Q16630 +Q53F19 P55198 +Q53F19 P78563 +Q53F19 O00422 +Q53F19 Q9ULL5 +Q53F19 P52298 +Q53F19 Q09161 +Q53F19 Q9BXP5 +Q53F19 Q96PV6 +Q53F19 Q9UHI6 +Q53F19 Q9UKV3 +Q53F19 Q86U42 +Q53F19 Q13155 +Q53F19 P34897 +Q53F19 Q9UKS6 +Q53F19 O14950 +Q53F19 P53582 +Q53F19 P20700 +Q53F19 P68400 +Q53F19 Q5JVF3 +Q53F19 P19784 +Q53F19 O00629 +Q53F19 P68036 +Q53F19 Q96A72 +Q53F19 Q9Y5S9 +Q53F19 P15692 +Q53F19 P35637 +Q53F19 Q00688 +Q53F19 P98179 +Q53F19 Q9P289 +Q53F19 O00505 +Q53F19 Q96K17 +Q53F19 Q9H307 +Q53F19 Q96J01 +Q53F19 Q8NI27 +Q53F19 Q13769 +Q53F19 Q13838 +Q53F19 Q86W42 +Q53F19 Q96FV9 +Q53F19 P38919 +Q53F19 Q6I9Y2 +Q53F19 P51148 +Q53F19 P50395 +P52298 Q9UH99 +P52298 P04003 +P52298 Q8N0X7 +P52298 K7ELV2 +P52298 P14735 +P52298 Q5VV67 +P52298 P31150 +P52298 Q5DJT8 +P52298 P52294 +P52298 P09603 +P52298 P53007 +P52298 Q9NWV8 +P52298 Q8N5P1 +P52298 Q9ULL5 +P52298 O94762 +P52298 P39880 +P52298 Q8IXH7 +P52298 Q9H3P2 +P52298 Q6NZY4 +P52298 Q8WX92 +P52298 Q9Y580 +P52298 Q86VM9 +P52298 Q9H814 +P52298 P18615 +P52298 Q09161 +P52298 Q9BXP5 +P52298 Q9UHI6 +P52298 Q8NC51 +P52298 O75822 +P52298 Q9P289 +P52298 O00505 +P52298 P51148 +P52298 P50395 +P52298 P61927 +P52298 O00505 +P52298 Q13769 +P52298 Q9H814 +P52298 Q09161 +P52298 Q9BXP5 +P52298 P38919 +Q53F19 O00505 +Q53F19 Q13769 +Q53F19 Q9H814 +Q53F19 P38919 +Q53F19 Q09161 +Q53F19 Q9BXP5 +Q09161 Q53F19 +P33724 P59632 +P33724 P59632 +P33724 P59632 +P33724 P59632 +P59632 P33724 +P0DTC9 P0DTC4 +P0DTC3 P0DTC4 +P0DTD2 P0DTC4 +Q14160 B7Z2Y1 +Q14160 Q14155 +Q14160 Q7Z628 +P22460 Q14160 +Q96DN2 Q14160 +O00429 Q14160 +Q99569 Q14160 +Q96DL1 Q14160 +B7Z2Y1 Q14160 +Q14155 Q14160 +Q9UQB3 Q14160 +Q9BR11 Q14160 +Q96DL1 Q14160 +Q14155 Q14160 +B7Z2Y1 Q14160 +Q9ULI0 Q14160 +P25100 Q14160 +P53778 Q14160 +Q9NYB5 Q14160 +Q15311 Q14160 +P33402 Q14160 +Q9P0K1 Q14160 +Q92953 Q14160 +O15439 Q14160 +P35222 Q14160 +P48065 Q14160 +Q14160 P08581 +P22460 Q14160 +O00429 Q14160 +Q14160 Q6UY11 +Q14160 Q9ULJ7 +Q14160 A6NIM6 +P81408 Q14160 +Q9NQG5 Q14160 +Q6UXZ0 Q14160 +Q92502 Q14160 +Q8TA94 Q14160 +Q9Y6R1 Q14160 +Q9Y466 Q14160 +Q8TBB1 Q14160 +P22460 Q12959 +Q9UQB3 Q12959 +Q12959 Q96DL1 +Q12959 Q15311 +Q12959 Q96A65 +Q6ZTQ3 Q12959 +Q12959 Q14CM0 +Q12959 Q9NYB5 +Q12959 Q14524 +Q12959 Q13224 +Q12959 P85299 +Q12959 Q9NVW2 +Q12959 Q99569 +Q12959 Q6DN90 +Q12959 Q86W11 +Q12959 A1L4L8 +Q12959 Q15303 +Q12959 Q96GG9 +Q96GL9 Q12959 +Q86UD3 Q12959 +O60333 Q12959 +A1A5B4 Q12959 +Q7Z628 Q12959 +P0C2L3 Q12959 +Q9NS75 Q12959 +Q96SF7 Q12959 +B7Z2Y1 Q12959 +Q9NS75 Q12959 +Q9P021 Q12959 +Q7Z628 Q12959 +Q99569 Q96NW7 +Q9UQB3 Q96NW7 +Q9UQB3 Q96RT1 +Q99569 Q96RT1 +O00192 Q96RT1 +Q9BY21 Q96RT1 +Q96DL1 Q96RT1 +Q8NHY3 Q96RT1 +P50804 Q12959 +P24835 Q12959 +P50804 Q12959 +P24835 Q12959 +P27228 Q12959 +Q06093 Q12959 +P06463 Q12959 +P21735 Q12959 +P30911 Q12959 +P06427 Q12959 +P0C213 Q12959 +P03126 Q12959 +P27962 Q12959 +P54667 Q12959 +P54667 Q12959 +P09708 Q12959 +P17386 Q12959 +P36807 Q12959 +P26554 Q12959 +Q0A442 Q12959 +P30910 Q12959 +P26555 Q12959 +P16717 Q12959 +P50804 Q12959 +P24835 Q12959 +P21735 Q12959 +P06427 Q12959 +P27228 Q12959 +P09708 Q12959 +A3EX99 Q96RT1 +A3EXD5 Q96RT1 +P06427 Q96RT1 +Q9IDV3 Q96RT1 +Q1A244 Q96RT1 +P03126 Q96RT1 +P50804 Q96RT1 +P0C9G5 Q96RT1 +A3EXD4 Q96RT1 +P89432 Q96RT1 +P0C213 Q96RT1 +Q14160 P06427 +Q14160 P03126 +Q14160 P17589 +P0C213 Q14160 +Q14160 P0C222 +P06427 Q14160 +P03126 Q14160 +P0C213 Q14160 +P27228 Q14160 +P24835 Q14160 +P04299 Q14160 +P16717 Q14160 +P50804 Q14160 +P21735 Q14160 +P0C222 Q14160 +P03333 Q14160 +Q09SZ7 Q14160 +Q08089 Q14160 +Q18LE1 Q96RT1 +Q14500 Q14160 +P48050 Q14160 +P12814 Q14160 +P35609 Q14160 +Q08043 Q14160 +O43707 Q14160 +Q8IWK6 Q12959 +Q86SQ6 Q12959 +Q96PE1 Q12959 +P22459 Q12959 +Q14500 Q12959 +Q14155 Q14160 +P33402 Q14160 +P53778 Q14160 +Q99569 Q14160 +Q99569 Q14160 +Q14155 Q14160 +P53778 Q14160 +P33402 Q14160 +P35222 Q14160 +P59595 P63165 +P59595 P63165 +P59595 P09651 +P59595 P09651 +P59595 P09651 +P0C6X7 O75348 +P0C6X7 O75348 +P0C6X7 O75348 +P0C6X7 O75348 +P0C6X7 O75348 diff --git a/www/Examples/TAU/TAU_KEGG_Annotation_NORMA.txt b/www/Examples/TAU/TAU_KEGG_Annotation_NORMA.txt new file mode 100644 index 0000000..6543980 --- /dev/null +++ b/www/Examples/TAU/TAU_KEGG_Annotation_NORMA.txt @@ -0,0 +1,10 @@ +Ribosome RpL10,RpL10Ab,RpL11,RpL12,RpL13,RpL18A,RpL26,RpL3,RpL30,RpL4,RpLP0,RpLP2,RpS10a,RpS10b,RpS11,RpS12,RpS13,RpS15Aa,RpS15Ab,RpS16,RpS17,RpS18,RpS2,RpS23,RpS27,RpS3,RpS3A,RpS4,RpS6,RpS7,RpS8,bonsai,mRpL12,mRpS10,mRpS7,mRpS9,sta +Proteasome Prosalpha6,Prosalpha7,Prosbeta7,Rpn12,Rpn13,Rpn2,Rpn3,Rpn5,Rpn6,Rpt1,Rpt2,Rpt4,Rpt4R,Rpt5,Rpt6,Rpt6R +Spliceosome B52,CG10077,CG10777,CG16941,Hrb98DE,LS2,Prp8,Ref1,SF2,Tango4,U2A,U2af50,mago +Phagosome Act79B,Cnx99A,Cp1,Dhc64C,Dlic,Hrs,Mtl,Rab5,Rac1,Vha100-1,Vha100-2,Vha68-2,betaTub56D +Carbon metabolism AcCoAS,CG10932,CG11876,CG11899,CG12262,CG3011,CG32026,CG33791,Cat,Eno,Mdh2,Men,Men-b,Nc73EF,Pfk,PyK,Tpi,l(1)G0156 +Oxidative phosphorylation ATPsynCF6,ATPsynbeta,COX4,COX5A,COX6B,ND-15,ND-51,ND-51L1,ND-B16.6,ND-PDSW,NP15.6,Vha100-1,Vha100-2,Vha68-2,sun +RNA degradation CG2091,Eno,Hsc70-5,Hsp60,Hsp60C,Not1,Not3,Pfk,me31B,pAbp +RNA transport CG9769,Fmr1,Mtor,Rae1,Ref1,Trip1,eIF-3p66,eIF3-S10,eIF3-S8,eIF3-S9,eIF4G,emb,mago,pAbp,smt3 +Glycolysis AcCoAS,Aldh,CG11876,Eno,ImpL3,Pfk,PyK,Tpi +Pyruvate metabolism ACC,AcCoAS,Aldh,CG10932,CG11876,ImpL3,Mdh2,Men,Men-b,PyK diff --git a/www/Examples/TAU/TAU_Louvain.txt b/www/Examples/TAU/TAU_Louvain.txt new file mode 100644 index 0000000..cc8efac --- /dev/null +++ b/www/Examples/TAU/TAU_Louvain.txt @@ -0,0 +1,9 @@ +Group-1 Mgstl,KP78a,CG9257,par-1,CG31064,LpR1,Rab39,LpR2,CG3529,Lam,LamC,Sap-r,Vps60,lqf,ninaC,Hrs,Arr2,Arr1,Rab5,CG32683,pins,chp +Group-2 Sc2,Uch,Prx2540-1,Ace,CG4572,Sgt,CG14715,CG10359,Ect3,CalpB,Prx5,Ost48,Hsp60C,Prx2540-2,Hsp60,Ubqn,Hsp70Ab,Ugt,Iswi,Trap1,Cat,Hsc70-5,CG8209,DnaJ-H,p47,Rad23,Cnx99A,pont,Cp1,cathD,Uba2,Pfk,Gdi,Uch-L5,Rpt4R,Prosalpha1,mor,Bap55,Ufd1-like,TER94,Hsc70-3,PyK,Hsp83,ERp60,arm,Rpt1,Rpn13,Rpt2,Rpn5,Rpt6R,Rpn2,Pdi,CaBP1,Gp93,Rpt4,Hop,CG1416,Prosalpha6,Rpt5,Prosalpha7,Rpn6,CG8258,Rpt6,Rpn3,Rpn12,Prosbeta7,Usp5,CG2918,CG2852,CG1354,CG6891,HDAC6,Hsp27,His1,CG11577 +Group-3 shep,CG5590,CG17597,ScpX,Mfe2 +Group-4 CG4882,EfTuM,Rbp2,eEF1delta,CG10576,Nacalpha,mRpS34,vig,CG4679,mRpS35,mRpS7,mRpL44,mRpS22,eIF4G,bonsai,mRpS10,Srp54k,mRpL12,Tctp,eIF-2gamma,mRpS23,mRpS18B,ade3,mRpS9,mRpS5,Srp19,Srp72,eIF-3p66,Cctgamma,Ef1beta,Tango7,RpL10Ab,Trip1,eIF3-S10,eIF3-S9,Tcp-1eta,RpL13,RpS11,eIF3-S8,RpS6,RpS2,RpL12,RpS7,RpL10,RpS8,RpL30,RpS10a,RpS17,RpLP0,eRF1,Elf,RpS15Aa,RpS27,RpS18,RpS10b,RpS3A,RpS16,RpS15Ab,RpL3,Tcp-1zeta,T-cp1,RpS3,RpL26,RpS12,CG5642,CG9769,CG7033,Cct5,RpLP2,RpS23,RpS14a,Rack1,RpL11,RpS13,RpL18A,RpS4,RpL4,sta,wuho,bsf,kra,Hsp67Bc,su(r),FeCH,CG8635 +Group-5 nito,bol,Kap-alpha3,CG2082,lig,clu,Dbp80,Plc21C,Hrb27C,bel,Dp1,Lpin,Pkc53E,Nlp,rin,poe,CG43367,emb,fne,RanBPM,yps,Art4,CG10077,mub,AGO1,glo,Srp54,Rbp9,Rae1,Mtor,Ref1,mago,B52,LS2,U2af50,Fmr1,Top2,heph,Hrb98DE,Tudor-SN,SF2,me31B,CG16941,Prp8,Tango4,U2A,smt3,pAbp,Not1,Not3,CG2091,Capr,Gbeta76C,CG10777,CG6617,CG3800,tyf,CG11505 +Group-6 CG6178,frj,CG9090,Ssadh,l(1)G0156,CG32026,Men-b,CG11899,CG16935,AGBE,ImpL3,Nc73EF,CG3902,CG11876,Pdk,Vha100-1,AcCoAS,ACC,Mdh2,Cyt-c-p,Aldh,CG15093,ND-51L1,ND-51,Vha68-2,Vha100-2,ND-15,CG12262,yip2,ade5,CG11089,COX6B,CG11752,COX4,COX5A,Eno,Tpi,ND-PDSW,NP15.6,ATPsynbeta,ATPsynCF6,CG10932,CG33791,CG3011,Men,sun,porin,ND-B16.6,CG7603,Mpcp +Group-7 Ndg,trol,Cg25C,vkg,LanA,LanB2,Glt +Group-8 Lar,CG31715,PlexA,gammaSnap2,CG10186,Klp10A,Mtl,bai,Act79B,Abl,Tim17b,p115,Sec24AB,robl,tsr,flr,FKBP59,bic,BicD,CadN,syd,Rac1,zip,alphaCOP,zetaCOP,CG7048,CG7770,Dlic,Dhc64C,betaCOP,cpa,cpb,epsilonCOP,beta'COP,Klc,Khc,alpha-Cat,deltaCOP,RhoGDI,Dscam1,Tim9a,sqh,dock,Dscam2,CG8498,CLIP-190,betaTub56D +Group-9 Mapmodulin,Aats-val,Aats-his,Aats-asp,CG33123,Aats-ile,Aats-arg,CG31739 diff --git a/www/Examples/TAU/TAU_expressions.txt b/www/Examples/TAU/TAU_expressions.txt new file mode 100644 index 0000000..0af4485 --- /dev/null +++ b/www/Examples/TAU/TAU_expressions.txt @@ -0,0 +1,363 @@ +CG7603 red +His1 red +Act79B red +Gbeta76C red +CG11876 red +Kap-alpha3 red +CG2082 red +LanA red +Vha68-2 red +CalpB red +Ssadh red +CG43367 red +l(1)G0156 red +CG9090 red +Prx5 red +CG1354 red +porin red +GstD9 red +CG32026 red +Aldh red +Glt red +Tpi red +PyK red +ATPsynbeta red +Eno red +Mtl red +Arr1 red +Mpcp red +Arr2 red +Ndg red +FeCH red +Nc73EF red +CG10932 red +CG33791 red +betaTub56D red +Cyt-c-p red +CG16935 red +Prx2540-2 red +GstE4 red +pins red +chp red +Men-b red +GstD3 red +HDAC6 red +CG10359 red +mago red +LamC red +Ace red +Mdh2 red +ninaC red +LanB2 red +Cg25C red +sun red +vkg red +Pfk red +Prx2540-1 red +EfTuM red +Vha100-1 red +Vha100-2 red +AGBE red +frj red +DnaJ-H red +trol red +Men green +p47 green +mRpS10 green +NP15.6 green +RpS15Ab green +Not3 green +Tim17b green +eIF4G green +cathD green +CG12262 green +Prosalpha7 green +Usp5 green +yip2 green +Dscam1 green +CG2918 green +cpa green +RpS4 green +ade3 green +CG8209 green +CG11505 green +FKBP59 green +RpS11 green +Rab39 green +RpL13 green +CG1371 green +Prp8 green +Prosalpha6 green +Rpn12 green +Rpn2 green +Rpn5 green +Nacalpha green +Hsp60 green +Tudor-SN green +Rpt5 green +Rpt4 green +lqf green +Rpt1 green +Top2 green +Rpn6 green +ND-PDSW green +sta green +sqh green +CG6178 green +CG32683 green +Aats-asp green +LpR2 green +eIF-2gamma green +RpL11 green +Elf green +ERp60 green +Sec24AB green +CG11089 green +Rae1 green +CG3011 green +Abl green +Rpt6R green +Uch green +Trap1 green +CG7048 green +Rpt6 green +CG10186 green +wuho green +Aats-arg green +Lam green +Hsp60C green +Trip1 green +RpS3 green +Tctp green +CG31064 green +Dscam2 green +emb green +Uba2 green +pAbp green +Capr green +CG4972 green +Aats-his green +Aats-ile green +PlexA green +Cctgamma green +Rab5 green +zip green +Mi-2 green +AcCoAS green +su(r) green +mRpS23 green +arm green +CG10077 green +Ref1 green +RpS7 green +CG10777 green +Aats-val green +ImpL3 green +Pdi green +Sgt green +beta'COP green +alphaCOP green +Fmr1 green +CG31715 green +mRpS7 green +Ef1beta green +ND-B16.6 green +ScpX green +Cat green +lig green +CG10576 green +p115 green +ade5 green +Bap55 green +Hsp83 green +RpL4 green +Prosbeta7 green +RpLP2 green +CG4572 green +CG31739 green +Tim9a green +pont green +Hsc70-5 green +Hsp27 green +bic green +Hsp67Bc green +KP78a green +CG3529 green +BicD green +RpS12 green +bsf green +Hsc70-3 green +Hrb98DE green +RpS8 green +CG8498 green +Dp1 green +Ost48 green +Srp54k green +Rad23 green +Tango4 green +kra green +Hsp70Ab green +RpS15Aa green +tyf green +Lpin green +Cnx99A green +mRpS18B green +eEF1delta green +CG3800 green +RpL18A green +par-1 green +me31B green +COX4 green +eIF3-S10 green +CG11752 green +CG14715 green +Mtor green +U2af50 green +mRpS5 green +Khc green +Cct5 green +RpL12 green +yps green +B52 green +CG1416 green +bonsai green +TER94 green +Lar green +alpha-Cat green +glo green +CadN green +CG7033 green +CG2091 green +RpS17 green +Art4 green +syd green +RpL3 green +Tcp-1eta green +CG4679 green +Srp54 green +mRpS34 green +vig green +Srp72 green +ND-15 green +Mapmodulin green +Rack1 green +Cp1 green +Dlic green +RpS18 green +fne green +RpS14a green +eIF3-S8 green +CG5642 green +RpLP0 green +gammaSnap2 green +robl green +RpS16 green +Ugt green +Hrs green +Klc green +eIF-3p66 green +ND-51L1 green +betaCOP green +zetaCOP green +Ubqn green +rin green +eRF1 green +LS2 green +Dbp80 green +Ufd1-like green +eIF3-S9 green +ND-51 green +COX6B green +mRpS9 green +CG33123 green +CG9769 green +bel green +Sap-r green +deltaCOP green +Rbp9 green +RpS13 green +CG9257 green +mRpL12 green +Mfe2 green +CaBP1 green +AGO1 green +Mgstl green +CG17597 green +CG6617 green +mub green +ATPsynCF6 green +Rbp2 green +Uch-L5 green +dock green +LpR1 green +CG6891 green +RpL10 green +heph green +Hop green +RpL10Ab green +COX5A green +RpL30 green +mRpS22 green +Tcp-1zeta green +Nlp green +Rpt4R green +Ect3 green +poe green +Vps60 green +tsr green +RanBPM green +Plc21C green +mor green +epsilonCOP green +Rpt2 green +ACC green +Rpn3 green +bol green +RpS10a green +CG4882 green +CG8258 green +bai green +shep green +Srp19 green +CG2852 green +CG11899 green +clu green +Iswi green +Dhc64C green +RpS6 green +RpS10b green +CG5590 green +Klp10A green +Gdi green +RpS2 green +RpS27 green +Not1 green +flr green +Pkc53E green +CG11577 green +CG15093 green +CLIP-190 green +smt3 green +Rac1 green +cpb green +CG16941 green +RhoGDI green +Prosalpha1 green +mRpL44 green +Gp93 green +Pdk green +RpS23 green +T-cp1 green +RpL26 green +CG3902 green +CG7770 green +mRpS35 green +CG8635 green +RpS3A green +Tango7 green +Hrb27C green +nito green +Sc2 green +U2A green +Rpn13 green +SF2 green diff --git a/www/Examples/TAU/TAU_network_DEGs_NORMA.txt b/www/Examples/TAU/TAU_network_DEGs_NORMA.txt new file mode 100644 index 0000000..5f02df8 --- /dev/null +++ b/www/Examples/TAU/TAU_network_DEGs_NORMA.txt @@ -0,0 +1,3177 @@ +Source Target +CG6178 yip2 +shep ScpX +nito Ref1 +bol Hrb27C +Lar Abl +Lar CadN +CG31715 cpb +Mapmodulin Aats-ile +CG5590 CG17597 +Sc2 Ost48 +frj CG10932 +Kap-alpha3 emb +Uch Usp5 +Prx2540-1 Prx2540-2 +CG2082 CG2091 +lig Capr +lig rin +clu Dp1 +clu eIF3-S10 +clu rin +clu eIF3-S8 +clu eIF3-S9 +CG9090 Cyt-c-p +CG9090 COX5A +Ace Cat +Dbp80 emb +Ssadh CG33791 +Ssadh CG32026 +Ssadh Mdh2 +CG4572 CG10576 +CG4572 Hsc70-3 +PlexA alpha-Cat +l(1)G0156 CG11876 +l(1)G0156 Ssadh +l(1)G0156 CG33791 +Plc21C Gbeta76C +Plc21C Pkc53E +Hrb27C poe +Hrb27C heph +Hrb27C PyK +Hrb27C bel +Hrb27C me31B +Hrb27C pAbp +Hrb27C TER94 +Khc TAU +CG32026 CG33791 +bel Ref1 +bel poe +bel emb +bel vig +bel me31B +Dp1 CG2918 +Sgt Trap1 +Sgt Tcp-1zeta +Men-b CG11876 +Men-b PyK +Men-b Mdh2 +CG11899 CG3011 +Mgstl CG3529 +Mgstl Ost48 +CG14715 CG2852 +Lpin Pkc53E +gammaSnap2 zetaCOP +gammaSnap2 betaCOP +gammaSnap2 epsilonCOP +gammaSnap2 beta'COP +gammaSnap2 deltaCOP +CG10359 Gp93 +CG10359 CG1354 +CG10359 CaBP1 +CG10359 Pdi +KP78a CG32683 +KP78a Arr2 +CG9257 poe +CG9257 CG3529 +Ect3 Rpn5 +Ect3 CG6891 +Ect3 Cat +Ect3 CalpB +CG4882 bonsai +CalpB CG6891 +CalpB Cat +par-1 CG32683 +par-1 KP78a +par-1 Arr2 +Prx5 Prx2540-2 +Prx5 Cat +Pkc53E zip +CG31064 Rab5 +Nlp mago +Nlp eEF1delta +Nlp smt3 +CG10186 betaCOP +CG10186 cpb +CG10186 cpa +CG10186 beta'COP +CG10186 bai +CG10186 epsilonCOP +CG10186 Dlic +CG10186 p115 +CG10186 zetaCOP +CG10186 deltaCOP +rin Capr +LpR1 Arr2 +LpR1 Arr1 +LpR1 Ubqn +LpR1 CG32683 +LpR1 lqf +LpR1 Hrs +LpR1 LpR2 +LpR1 Rab5 +CG16935 CG12262 +CG16935 yip2 +poe betaCOP +poe CG3529 +CG43367 betaCOP +CG43367 poe +Rab39 Rab5 +Rab39 Gdi +emb Rae1 +emb alphaCOP +emb CG10576 +AGBE Eno +AGBE PyK +LpR2 Ubqn +LpR2 CG32683 +LpR2 Arr2 +LpR2 Hrs +LpR2 lqf +LpR2 Rab5 +CG3529 Ost48 +Ost48 CG2918 +Hsp60C Hop +Hsp60C Hsc70-3 +Prx2540-2 Cat +EfTuM RpS14a +EfTuM Hsc70-5 +EfTuM RpL10Ab +EfTuM RpS13 +EfTuM RpS16 +EfTuM RpS23 +EfTuM RpS15Aa +EfTuM RpL4 +EfTuM CG11876 +EfTuM bonsai +EfTuM mRpS10 +EfTuM RpL12 +EfTuM sta +EfTuM RpL3 +EfTuM Hsp60 +EfTuM RpS18 +EfTuM RpS2 +EfTuM mRpS9 +EfTuM RpS3 +EfTuM mRpL12 +EfTuM RpL11 +fne Tango4 +fne Srp54 +fne CG10777 +fne Prp8 +fne mago +fne CG16941 +fne yps +fne CG10077 +fne Rbp9 +fne U2A +fne Pkc53E +fne Hrb98DE +fne LS2 +fne SF2 +fne mub +fne heph +Klp10A deltaCOP +Mtl zip +Mtl tsr +Mtl RhoGDI +Hsp60 CG7033 +RanBPM CG6617 +yps Tango4 +yps LS2 +yps mago +yps CG10777 +Art4 CG10777 +Art4 CG10077 +Art4 pAbp +ImpL3 Cat +ImpL3 Men-b +ImpL3 Pfk +ImpL3 Men +ImpL3 Eno +ImpL3 Tpi +ImpL3 PyK +ImpL3 CG11876 +CG10077 CG10777 +CG10077 LS2 +CG10077 Tango4 +CG10077 yps +CG10077 mago +Lam Rab5 +LamC Lam +Ubqn HDAC6 +Ubqn CG32683 +mub CG3800 +mub mago +mub U2A +mub Srp54 +mub Tango4 +mub Prp8 +mub CG10777 +mub CG16941 +mub yps +mub CG10077 +mub LS2 +mub Hrb98DE +mub Rbp9 +mub SF2 +AGO1 Rbp9 +AGO1 pAbp +AGO1 Rae1 +AGO1 me31B +glo Hrb98DE +Sap-r CG3529 +Sap-r Mgstl +Sap-r pins +Sap-r Rab5 +Sap-r Ost48 +Ndg Cg25C +Ndg LanB2 +trol Cp1 +trol LanB2 +trol Cg25C +trol Ndg +Hsp70Ab Pdi +Hsp70Ab DnaJ-H +Hsp70Ab Hop +Hsp70Ab Hsp27 +bai Srp19 +bai CG2852 +bai gammaSnap2 +bai Klp10A +bai Klc +bai Dlic +bai cpa +bai p115 +bai cpb +bai deltaCOP +bai betaCOP +bai epsilonCOP +bai beta'COP +bai zetaCOP +Nc73EF Ssadh +Nc73EF CG32026 +Nc73EF l(1)G0156 +Nc73EF CG33791 +Nc73EF CG11876 +Srp54 yps +Srp54 CG10777 +Srp54 mago +Srp54 LS2 +Srp54 CG10077 +Srp54 Tango4 +Ugt CG2918 +Rbp9 CG10777 +Rbp9 Tango4 +Rbp9 Srp54 +Rbp9 Prp8 +Rbp9 CG10077 +Rbp9 CG16941 +Rbp9 U2A +Rbp9 Pkc53E +Rbp9 LS2 +Rbp9 Hrb98DE +Rbp9 yps +Rbp9 mago +Act79B cpb +Act79B flr +Act79B zip +Rbp2 pAbp +Rbp2 RpL10Ab +Rbp2 RpS4 +Rbp2 RpL18A +Rbp2 RpS3 +Rbp2 RpS11 +Rbp2 eIF3-S9 +Rbp2 RpL11 +Rbp2 eIF3-S10 +Rbp2 RpL13 +Rbp2 eIF3-S8 +Rbp2 RpS10b +Rbp2 RpS10a +Rbp2 RpS27 +Rbp2 RpL3 +Rbp2 RpS12 +Rbp2 RpS7 +Rbp2 RpL12 +Rbp2 Tango7 +Rbp2 RpS23 +Rbp2 RpS13 +Rbp2 sta +Rbp2 RpS18 +Rbp2 RpS16 +Rbp2 RpL4 +Rbp2 RpS6 +Rbp2 Trip1 +Rbp2 RpS2 +Rbp2 eIF-3p66 +Rbp2 CG5642 +Rbp2 CG9769 +Iswi His1 +Iswi Bap55 +Iswi smt3 +Iswi mor +Vps60 Hrs +eEF1delta eIF3-S10 +eEF1delta RpS10b +eEF1delta RpS13 +eEF1delta RpS6 +eEF1delta RpS16 +eEF1delta RpL12 +eEF1delta sta +eEF1delta RpS2 +eEF1delta CG5642 +eEF1delta RpL13 +eEF1delta Trip1 +CG10576 RpS6 +CG10576 RpS4 +CG10576 Capr +CG10576 sta +CG10576 RpS16 +CG10576 Tcp-1zeta +CG10576 wuho +CG10576 RpL12 +CG10576 CG7033 +Abl Dscam1 +Abl syd +Abl alpha-Cat +Abl arm +Rae1 mago +Mtor mago +Mtor AGO1 +Mtor Hsc70-3 +Mtor Hsc70-5 +Mtor smt3 +Mtor Rae1 +Ref1 LS2 +Ref1 mago +Trap1 Hsp70Ab +Trap1 Hop +Trap1 Hsp60C +Trap1 Hsp60 +Trap1 CG2918 +Trap1 Hsc70-3 +Trap1 CG1416 +CG17597 Cat +CG17597 ScpX +CG17597 Mfe2 +lqf CG32683 +lqf Ubqn +lqf Arr2 +lqf Rab5 +lqf Hrs +Tim17b Tim9a +CG3902 CG10932 +Cat CG6891 +p115 deltaCOP +Sec24AB deltaCOP +Sec24AB betaCOP +Sec24AB epsilonCOP +Sec24AB zetaCOP +Sec24AB alphaCOP +Sec24AB beta'COP +Sec24AB p115 +ninaC Act79B +ninaC zip +ninaC Arr2 +mago sta +mago RpS6 +mago CG10777 +CG11876 Men +CG11876 Mdh2 +CG11876 PyK +CG11876 ND-PDSW +CG11876 AcCoAS +CG11876 Eno +CG11876 CG33791 +Pdk ade3 +Pdk CG11876 +B52 RpS3 +B52 Hrb27C +B52 glo +B52 CG10777 +B52 fne +B52 CG10077 +B52 yps +B52 Rbp9 +B52 CG16941 +B52 Tango4 +B52 U2A +B52 mago +B52 Srp54 +B52 mub +B52 heph +B52 Prp8 +B52 LS2 +B52 Hrb98DE +B52 U2af50 +B52 SF2 +Vha100-1 sun +Vha100-1 Vha100-2 +Vha100-1 Vha68-2 +robl Dlic +Hsc70-5 CG7033 +Hsc70-5 T-cp1 +Hsc70-5 Tpi +Hsc70-5 DnaJ-H +Hsc70-5 Tcp-1eta +Hsc70-5 Hop +Hsc70-5 Rae1 +Hsc70-5 Trap1 +Hsc70-5 Hsp60C +Hsc70-5 Hsc70-3 +Hsc70-5 Hsp60 +Hsc70-5 Gp93 +tsr sqh +tsr cpa +tsr RpS6 +flr cpa +flr tsr +AcCoAS CG12262 +AcCoAS CG10932 +ACC Eno +ACC CG10932 +ACC AcCoAS +LS2 mago +LS2 CG10777 +FKBP59 ninaC +FKBP59 Dlic +FKBP59 cpb +FKBP59 cpa +FKBP59 Hop +U2af50 Ref1 +U2af50 LS2 +U2af50 yps +U2af50 CG10777 +U2af50 CG10077 +U2af50 Rbp9 +U2af50 fne +U2af50 Srp54 +U2af50 mago +U2af50 mub +U2af50 Tango4 +U2af50 heph +U2af50 CG16941 +U2af50 Hrb98DE +U2af50 Prp8 +U2af50 SF2 +U2af50 U2A +Fmr1 dock +Fmr1 PyK +Fmr1 poe +Fmr1 bel +Fmr1 pAbp +Fmr1 eIF4G +Fmr1 Dscam1 +Fmr1 RanBPM +Fmr1 Hrb98DE +Fmr1 Hrb27C +Fmr1 Capr +Fmr1 TER94 +Fmr1 Rbp9 +Fmr1 me31B +Fmr1 AGO1 +Fmr1 vig +ScpX Cat +ScpX Mfe2 +Top2 RpS13 +Top2 Pkc53E +Top2 Uba2 +Top2 Iswi +Top2 smt3 +CG8209 Ufd1-like +heph Tango4 +heph Srp54 +heph CG16941 +heph CG10077 +heph CG10777 +heph U2A +heph mago +heph yps +heph Prp8 +heph mub +heph LS2 +heph pAbp +heph Hrb98DE +heph Rbp9 +heph SF2 +Hrs CG4572 +Hrs CG32683 +Hrs Arr2 +Hrs Ubqn +Hrs Rab5 +Hrb98DE CG10777 +Hrb98DE mago +Hrb98DE Srp54 +Hrb98DE CG16941 +Hrb98DE CG10077 +Hrb98DE yps +Hrb98DE LS2 +Hrb98DE Tango4 +bic RpS3 +Nacalpha RpS13 +Nacalpha RpS2 +Nacalpha sta +Nacalpha RpS6 +Nacalpha RpS16 +Nacalpha RpS27 +Nacalpha RpS4 +Nacalpha RpS23 +Nacalpha RpS18 +Nacalpha RpL12 +Nacalpha RpL18A +Nacalpha RpL11 +Nacalpha RpS10b +Nacalpha RpS17 +Nacalpha RpL13 +Nacalpha RpS3 +Nacalpha RpL4 +Nacalpha bic +Aats-val eEF1delta +Aats-val Ef1beta +Aats-val Aats-asp +Aats-val Aats-ile +Aats-val CG33123 +Aats-val Aats-arg +BicD Lam +BicD bic +BicD Khc +BicD cpb +BicD cpa +BicD Dlic +DnaJ-H CG2918 +DnaJ-H Hsc70-3 +DnaJ-H Hop +mRpS34 CG4882 +mRpS34 bonsai +CadN alpha-Cat +CadN arm +vig RpS15Aa +vig RpS13 +vig RpS16 +vig RpS17 +vig RpL12 +Tudor-SN bel +Tudor-SN AGO1 +Tudor-SN Fmr1 +Tudor-SN vig +Mdh2 Aldh +Mdh2 ND-51 +Mdh2 COX4 +Mdh2 Cyt-c-p +Mdh2 COX5A +Mdh2 Men +Mdh2 Eno +Cyt-c-p Cat +Cyt-c-p porin +Cyt-c-p ND-PDSW +Cyt-c-p COX6B +Aldh Cat +Aldh Eno +Aldh CG12262 +Aldh AcCoAS +CG15093 CG12262 +CG15093 AcCoAS +CG15093 CG3902 +CG15093 Aldh +CG4679 mRpS34 +CG4679 bsf +CG4679 CG4882 +CG4679 mRpL12 +CG4679 mRpL44 +CG4679 bonsai +CG4679 mRpS10 +CG4679 mRpS23 +CG4679 mRpS22 +CG4679 mRpS9 +CG4679 mRpS18B +SF2 CG10777 +SF2 CG10077 +SF2 U2A +SF2 Tango4 +SF2 yps +SF2 Prp8 +SF2 Rbp9 +SF2 CG16941 +SF2 Srp54 +SF2 Ref1 +SF2 LS2 +SF2 mago +SF2 Hrb98DE +p47 CG8209 +p47 Ufd1-like +p47 Rpt2 +Rad23 me31B +Rad23 Uch-L5 +Rad23 Rpt1 +Rad23 HDAC6 +Rad23 Usp5 +Rad23 Uba2 +Rad23 Ufd1-like +Rad23 Sgt +Rad23 Rpt5 +Rad23 Bap55 +Rad23 pont +Rad23 CG8209 +Rad23 Iswi +Rad23 Rpn13 +Rad23 Ubqn +Rad23 smt3 +Rad23 Rpt2 +Rad23 TER94 +me31B poe +me31B CG2091 +me31B yps +ND-51L1 ND-51 +ND-51L1 NP15.6 +ND-51L1 ND-PDSW +ND-51L1 ND-B16.6 +syd alpha-Cat +syd Dlic +syd Klc +Arr2 Ubqn +Arr2 CG32683 +Arr1 ninaC +Arr1 chp +Arr1 KP78a +Arr1 LpR2 +Arr1 Ubqn +Arr1 CG32683 +Arr1 par-1 +Arr1 Hrs +Arr1 lqf +Arr1 Rab5 +Arr1 Arr2 +ND-51 ND-B16.6 +ND-51 ND-PDSW +CG16941 yps +CG16941 mago +CG16941 CG10777 +CG16941 CG10077 +CG16941 Srp54 +CG16941 LS2 +CG16941 Tango4 +Cnx99A Ost48 +Cnx99A Hsp70Ab +Cnx99A CG2918 +Cnx99A Ugt +Cnx99A Gp93 +Cnx99A Pdi +Cnx99A Hsc70-3 +Cnx99A ERp60 +Aats-his Aats-asp +Aats-his Cct5 +Aats-his Aats-arg +Aats-his Aats-val +Aats-his CG33123 +Aats-his Aats-ile +mRpS35 RpS2 +mRpS35 CG4882 +mRpS35 mRpL12 +mRpS35 mRpS34 +mRpS35 mRpL44 +mRpS35 CG4679 +mRpS35 mRpS23 +mRpS35 mRpS18B +mRpS35 mRpS10 +mRpS35 mRpS9 +mRpS35 mRpS22 +mRpS35 bonsai +mRpS35 mRpS5 +Vha68-2 sun +Vha68-2 Eno +Vha100-2 sun +Vha100-2 Vha68-2 +Rac1 sqh +Rac1 Fmr1 +Rac1 tsr +Rac1 Dscam2 +Rac1 Gdi +Rac1 Abl +Rac1 dock +Rac1 zip +Rac1 RhoGDI +mRpS7 ade3 +mRpS7 CG9769 +mRpS7 CG4882 +mRpS7 eIF3-S8 +mRpS7 Srp19 +mRpS7 EfTuM +mRpS7 eIF3-S10 +mRpS7 eIF-2gamma +mRpS7 Srp54k +mRpS7 eRF1 +mRpS7 Tango7 +mRpS7 RpLP2 +mRpS7 eIF3-S9 +mRpS7 RpL4 +mRpS7 RpS10a +mRpS7 RpS12 +mRpS7 RpS10b +mRpS7 CG7048 +mRpS7 RpS15Ab +mRpS7 RpS15Aa +mRpS7 RpL10Ab +mRpS7 RpS14a +mRpS7 RpL18A +mRpS7 Rack1 +mRpS7 RpS4 +mRpS7 RpS17 +mRpS7 RpL13 +mRpS7 RpS7 +mRpS7 RpS6 +mRpS7 RpS8 +mRpS7 RpS16 +mRpS7 sta +mRpS7 RpS13 +mRpS7 RpL3 +mRpS7 RpS23 +mRpS7 RpS27 +mRpS7 RpL12 +mRpS7 RpS18 +mRpS7 RpS3A +mRpS7 RpS2 +mRpS7 RpS3 +mRpS7 RpS11 +mRpS7 RpL11 +mRpS7 RpL30 +mRpS7 mRpL44 +mRpS7 mRpS22 +mRpS7 mRpS34 +mRpS7 CG4679 +mRpS7 mRpS23 +mRpS7 bonsai +mRpS7 mRpS10 +mRpS7 mRpS35 +mRpS7 mRpL12 +mRpS7 mRpS18B +mRpS7 mRpS9 +mRpS7 mRpS5 +Prp8 yps +Prp8 Srp54 +Prp8 CG10777 +Prp8 CG10077 +Prp8 LS2 +Prp8 mago +Prp8 Hrb98DE +Prp8 CG16941 +Prp8 Tango4 +pont Tcp-1zeta +pont Tcp-1eta +pont Rpt6 +pont Uch-L5 +mRpL44 mRpS34 +mRpL44 mRpL12 +mRpL44 bonsai +mRpS22 CG4882 +mRpS22 mRpL12 +mRpS22 mRpS10 +mRpS22 mRpL44 +mRpS22 mRpS34 +mRpS22 mRpS23 +mRpS22 bonsai +mRpS22 mRpS18B +mRpS22 mRpS9 +Cp1 Ect3 +Cp1 PyK +Cp1 Rpn5 +Cp1 CG6891 +Cp1 CalpB +Cp1 Rpn6 +Cp1 Cat +Cp1 Rpt5 +cathD CG4572 +cathD CG6891 +cathD PyK +cathD CG8258 +cathD Ect3 +cathD Pfk +cathD Rpn5 +cathD CalpB +cathD Rpt5 +cathD Rpn6 +cathD Cat +cathD Sap-r +cathD Cp1 +Tango4 CG10777 +Tango4 LS2 +Tango4 mago +U2A yps +U2A CG10077 +U2A CG10777 +U2A Srp54 +U2A Hrb98DE +U2A mago +U2A LS2 +U2A CG16941 +U2A Prp8 +U2A Tango4 +Uba2 Usp5 +Uba2 Ubqn +smt3 tsr +smt3 mago +smt3 Ufd1-like +smt3 CG10777 +smt3 CG10077 +smt3 Rae1 +smt3 Uba2 +zip sqh +ND-15 CG11752 +ND-15 ND-51L1 +ND-15 COX5A +ND-15 ND-51 +ND-15 NP15.6 +ND-15 ND-B16.6 +ND-15 ND-PDSW +pAbp rin +pAbp RpL3 +pAbp RpL4 +pAbp emb +pAbp Dp1 +pAbp RpS6 +pAbp tyf +pAbp bel +pAbp yps +pAbp CG11505 +pAbp me31B +eIF4G Dp1 +eIF4G kra +eIF4G bel +eIF4G PlexA +eIF4G me31B +eIF4G RpL18A +eIF4G RpL12 +eIF4G RpS12 +eIF4G Hsp67Bc +eIF4G RpS4 +eIF4G RpL11 +eIF4G RpS23 +eIF4G RpS7 +eIF4G RpS27 +eIF4G RpLP2 +eIF4G RpS10b +eIF4G RpS10a +eIF4G sta +eIF4G RpS16 +eIF4G RpL4 +eIF4G RpL13 +eIF4G RpS18 +eIF4G RpS13 +eIF4G RpL3 +eIF4G RpL10Ab +eIF4G RpS11 +eIF4G RpS8 +eIF4G RpS2 +eIF4G Hsp27 +eIF4G eIF-3p66 +eIF4G mago +eIF4G Tango7 +eIF4G RpS3 +eIF4G CG5642 +eIF4G CG9769 +eIF4G Trip1 +eIF4G Rbp2 +eIF4G RpS6 +eIF4G alpha-Cat +eIF4G eIF3-S10 +eIF4G eIF3-S8 +eIF4G eIF3-S9 +eIF4G pAbp +Pfk CG11876 +Pfk CG6891 +Pfk Ect3 +Pfk Rpt5 +Pfk Cp1 +Pfk Rpn6 +Pfk CalpB +Pfk Rpn5 +Pfk Cat +Pfk Eno +Pfk Tpi +Pfk PyK +bonsai RpS14a +bonsai RpS16 +bonsai sta +bonsai RpS6 +CG12262 CG10932 +yip2 Uch +yip2 AcCoAS +yip2 CG10932 +yip2 CG3902 +yip2 CG12262 +Rab5 Mgstl +Rab5 CG32683 +Rab5 Ost48 +Rab5 CG3529 +Rab5 Arr2 +Gdi Cat +Gdi CG6891 +Gdi Pfk +Gdi Rpt1 +Gdi Rpt5 +Gdi Rpn5 +Gdi CG8258 +Gdi Rpn6 +Gdi Rpn3 +Gdi PyK +Gdi TER94 +Gdi RhoGDI +Gdi Rab5 +mRpS10 Srp54k +mRpS10 CG4882 +mRpS10 RpL10Ab +mRpS10 RpS14a +mRpS10 RpS16 +mRpS10 RpS10b +mRpS10 RpS13 +mRpS10 RpS2 +mRpS10 RpS15Aa +mRpS10 RpL3 +mRpS10 RpL12 +mRpS10 RpL13 +mRpS10 RpS4 +mRpS10 RpS17 +mRpS10 RpS6 +mRpS10 sta +mRpS10 mRpS23 +mRpS10 mRpS18B +mRpS10 mRpS34 +mRpS10 mRpL12 +mRpS10 mRpL44 +mRpS10 bonsai +mRpS10 mRpS9 +Srp54k bonsai +Srp54k RpS14a +Srp54k RpS15Aa +Srp54k RpS17 +Srp54k RpL10Ab +Srp54k RpS10b +Srp54k RpL12 +Srp54k RpS4 +Srp54k RpS6 +Srp54k RpS16 +Srp54k RpS12 +Srp54k sta +Srp54k Srp19 +mRpL12 RpS14a +mRpL12 RpL10Ab +mRpL12 RpS16 +mRpL12 sta +mRpL12 mRpS34 +mRpL12 RpS15Aa +mRpL12 RpL12 +mRpL12 bonsai +Tctp RpS10b +Tctp eEF1delta +Tctp RpL10Ab +Tctp RpS14a +Tctp RpS15Aa +Tctp RpS4 +Tctp RpS17 +Tctp sta +Tctp RpS6 +Tctp RpS16 +Tctp RpL12 +Tctp RpS13 +Tctp RpS12 +Tctp RpS2 +Tctp RpL13 +eIF-2gamma Tcp-1zeta +eIF-2gamma Tcp-1eta +eIF-2gamma CG10576 +eIF-2gamma Cctgamma +eIF-2gamma CG7033 +eIF-2gamma pAbp +eIF-2gamma Cct5 +eIF-2gamma RpS14a +eIF-2gamma CG8258 +eIF-2gamma CG33123 +eIF-2gamma CG1354 +eIF-2gamma RpS15Ab +eIF-2gamma RpS15Aa +eIF-2gamma T-cp1 +eIF-2gamma RpS17 +eIF-2gamma RpL10Ab +eIF-2gamma RpLP2 +eIF-2gamma RpL18A +eIF-2gamma Rbp2 +eIF-2gamma CG5642 +eIF-2gamma RpL30 +eIF-2gamma eIF-3p66 +eIF-2gamma eIF4G +eIF-2gamma RpS3A +eIF-2gamma CG9769 +eIF-2gamma RpL12 +eIF-2gamma RpL11 +eIF-2gamma RpS8 +eIF-2gamma RpS10a +eIF-2gamma RpS10b +eIF-2gamma RpL13 +eIF-2gamma RpS27 +eIF-2gamma RpS23 +eIF-2gamma RpS18 +eIF-2gamma RpS11 +eIF-2gamma RpS7 +eIF-2gamma RpL3 +eIF-2gamma RpS12 +eIF-2gamma RpL4 +eIF-2gamma RpS4 +eIF-2gamma RpS13 +eIF-2gamma Trip1 +eIF-2gamma RpS2 +eIF-2gamma eIF3-S10 +eIF-2gamma RpS16 +eIF-2gamma RpS6 +eIF-2gamma Tango7 +eIF-2gamma sta +eIF-2gamma RpS3 +eIF-2gamma eIF3-S8 +eIF-2gamma eIF3-S9 +Uch-L5 Usp5 +Uch-L5 Rpt4R +Uch-L5 Rpn12 +Rpt4R Rpn12 +Prosalpha1 Rpt4R +Prosalpha1 Rpn2 +Prosalpha1 Rpn12 +Prosalpha1 Rpn6 +Prosalpha1 Rpt6R +Prosalpha1 Rpn5 +Prosalpha1 Rpt6 +Prosalpha1 Rpt5 +Prosalpha1 Prosalpha6 +Prosalpha1 Rpt2 +Prosalpha1 Prosbeta7 +mRpS23 CG4882 +mRpS23 mRpL44 +mRpS23 mRpL12 +mRpS23 bonsai +mRpS23 mRpS34 +mRpS18B CG4882 +mRpS18B mRpL12 +mRpS18B bonsai +mRpS18B mRpS34 +mRpS18B mRpL44 +mRpS18B mRpS23 +mor pont +Bap55 Uch-L5 +Bap55 pont +Bap55 mor +ade5 CG3011 +Cg25C LanA +vkg Glt +vkg LanA +vkg Ndg +vkg trol +vkg Cg25C +Ufd1-like Ubqn +Ufd1-like Usp5 +TER94 poe +TER94 bel +TER94 Cnx99A +TER94 ERp60 +TER94 Pdi +TER94 smt3 +TER94 Hop +TER94 Hsc70-3 +TER94 CalpB +TER94 Pfk +TER94 CG6891 +TER94 Ect3 +TER94 PyK +TER94 Rpn2 +TER94 Cat +TER94 Cp1 +TER94 me31B +TER94 CG8258 +TER94 cathD +TER94 Ubqn +TER94 Rpn5 +TER94 Rpn6 +TER94 Rpt1 +TER94 Rpt5 +TER94 CG8209 +TER94 Rpt2 +TER94 p47 +TER94 Ufd1-like +ade3 RpS15Aa +ade3 RpL12 +ade3 RpS14a +ade3 RpL10Ab +ade3 su(r) +ade3 RpS6 +ade3 RpS4 +ade3 ade5 +ade3 CG3011 +mRpS9 CG4882 +mRpS9 ade3 +mRpS9 RpS14a +mRpS9 RpL10Ab +mRpS9 RpS16 +mRpS9 sta +mRpS9 RpS13 +mRpS9 RpS15Aa +mRpS9 RpL12 +mRpS9 RpS2 +mRpS9 mRpS34 +mRpS9 mRpL44 +mRpS9 mRpS18B +mRpS9 mRpS23 +mRpS9 bonsai +mRpS9 mRpL12 +mRpS5 CG11876 +mRpS5 RpS16 +mRpS5 RpS14a +mRpS5 RpL10Ab +mRpS5 RpLP2 +mRpS5 CG4882 +mRpS5 Srp54k +mRpS5 RpS10b +mRpS5 RpL4 +mRpS5 RpS10a +mRpS5 RpS8 +mRpS5 RpS13 +mRpS5 sta +mRpS5 RpL3 +mRpS5 RpL12 +mRpS5 RpS15Aa +mRpS5 RpS23 +mRpS5 RpS15Ab +mRpS5 RpS27 +mRpS5 RpS7 +mRpS5 EfTuM +mRpS5 RpL18A +mRpS5 RpL13 +mRpS5 RpS4 +mRpS5 RpS17 +mRpS5 RpS6 +mRpS5 RpS18 +mRpS5 RpS11 +mRpS5 RpL11 +mRpS5 RpS3 +mRpS5 mRpS34 +mRpS5 mRpS18B +mRpS5 mRpS23 +mRpS5 mRpS22 +mRpS5 CG4679 +mRpS5 mRpL44 +mRpS5 mRpL12 +mRpS5 mRpS10 +mRpS5 bonsai +mRpS5 mRpS9 +Not1 Iswi +Not1 eIF4G +Not1 pAbp +Not1 Prp8 +Not1 me31B +Not3 frj +Not3 me31B +Not3 Not1 +Hsc70-3 CG2852 +Hsc70-3 Hsp60 +Hsc70-3 Ost48 +Hsc70-3 Rae1 +Hsc70-3 CG2918 +PyK bel +PyK poe +PyK me31B +PyK Men +PyK Aldh +PyK Ect3 +PyK CG6891 +PyK CalpB +PyK ND-51 +PyK Rpn5 +PyK Vha68-2 +PyK Cat +PyK Mdh2 +PyK Eno +LanA LanB2 +alphaCOP deltaCOP +Srp19 RpS14a +Srp19 RpS15Aa +Srp19 RpS17 +Srp19 RpL10Ab +Srp19 RpS10b +Srp19 RpS6 +Srp19 RpS4 +Srp19 sta +Srp19 RpS12 +Srp19 RpL12 +Srp19 RpS16 +Srp72 RpS12 +Srp72 RpS10b +Srp72 RpS6 +Srp72 RpS13 +Srp72 RpL10Ab +Srp72 RpL13 +Srp72 sta +Srp72 RpS4 +Srp72 RpS2 +Srp72 RpL3 +Srp72 RpS16 +Srp72 RpL12 +Srp72 Srp54k +Srp72 Srp19 +Hsp83 Tcp-1zeta +Hsp83 Rack1 +Hsp83 zip +Hsp83 ERp60 +Hsp83 pont +Hsp83 Pdi +Hsp83 Tpi +Hsp83 HDAC6 +Hsp83 bai +Hsp83 Cctgamma +Hsp83 Cnx99A +Hsp83 CG2918 +Hsp83 Cct5 +Hsp83 CG7033 +Hsp83 Sgt +Hsp83 Hsp27 +Hsp83 T-cp1 +Hsp83 CalpB +Hsp83 Ect3 +Hsp83 CG6891 +Hsp83 Dlic +Hsp83 cpa +Hsp83 Cp1 +Hsp83 Dhc64C +Hsp83 Hsp60C +Hsp83 cpb +Hsp83 cathD +Hsp83 Pfk +Hsp83 Gdi +Hsp83 Rac1 +Hsp83 PyK +Hsp83 Rpn6 +Hsp83 Hsp60 +Hsp83 Rpn5 +Hsp83 Rpt1 +Hsp83 Rpn3 +Hsp83 Rpt5 +Hsp83 Hsp70Ab +Hsp83 Cat +Hsp83 CG8258 +Hsp83 Hsc70-5 +Hsp83 FKBP59 +Hsp83 TER94 +Hsp83 DnaJ-H +Hsp83 Hsc70-3 +Hsp83 CG1416 +Hsp83 Hop +CG11089 ade5 +CG11089 ade3 +CG11089 CG3011 +ERp60 Pdi +ERp60 Ost48 +ERp60 CG2852 +ERp60 CG2918 +ERp60 CaBP1 +ERp60 Hsc70-3 +ERp60 Gp93 +zetaCOP Klp10A +zetaCOP Dlic +zetaCOP p115 +zetaCOP cpa +zetaCOP alphaCOP +zetaCOP betaCOP +zetaCOP deltaCOP +COX6B ND-B16.6 +CG7048 cpa +CG7048 Srp19 +CG7048 Nlp +CG7048 mRpS23 +CG7048 CG8498 +CG7048 robl +CG7048 Tim9a +CG7048 eEF1delta +CG7770 RpS18 +CG7770 pont +CG7770 CG7048 +arm Hsc70-3 +arm Prosalpha6 +arm Uch-L5 +arm Rpn5 +arm Prosbeta7 +arm Rpn12 +arm Rpt6R +arm Rpt6 +arm syd +arm Rpn2 +arm Rpn6 +arm Rpt1 +arm Rpt2 +arm Rpt5 +arm emb +arm Rpt4R +arm pont +arm alpha-Cat +eIF-3p66 Tcp-1eta +eIF-3p66 Cct5 +eIF-3p66 Cctgamma +eIF-3p66 RpS12 +eIF-3p66 RpS16 +eIF-3p66 RpS11 +eIF-3p66 RpS27 +eIF-3p66 RpS23 +eIF-3p66 RpS10a +eIF-3p66 RpS10b +eIF-3p66 RpS13 +eIF-3p66 RpL10Ab +eIF-3p66 RpL13 +eIF-3p66 RpS7 +eIF-3p66 RpL12 +eIF-3p66 sta +eIF-3p66 RpS4 +eIF-3p66 RpL11 +eIF-3p66 RpS18 +eIF-3p66 RpS2 +eIF-3p66 RpL3 +eIF-3p66 RpL18A +eIF-3p66 RpS3 +eIF-3p66 RpL4 +eIF-3p66 RpS6 +eIF-3p66 CG9769 +eIF-3p66 eIF3-S10 +eIF-3p66 Tango7 +eIF-3p66 eIF3-S8 +eIF-3p66 eIF3-S9 +eIF-3p66 Trip1 +eIF-3p66 CG5642 +CG11752 ND-B16.6 +COX4 CG11752 +COX4 porin +COX4 ND-B16.6 +COX4 ND-PDSW +COX4 Cyt-c-p +COX4 COX6B +COX5A sun +COX5A ND-51 +COX5A CG7603 +COX5A CG11752 +COX5A ND-B16.6 +COX5A Cyt-c-p +COX5A ND-PDSW +COX5A COX6B +COX5A COX4 +Eno Hsc70-3 +Eno sta +Tpi Cat +Tpi CG11899 +Tpi RpS13 +Tpi CG11876 +Tpi ade3 +Tpi CG3011 +Tpi Hsc70-3 +Tpi Mdh2 +Tpi PyK +Tpi Eno +Cctgamma Trip1 +Cctgamma CG10576 +Cctgamma CG3800 +Cctgamma Hop +Cctgamma Tcp-1zeta +Cctgamma Tcp-1eta +Cctgamma CG7033 +Rpt1 Uch +Rpt1 RpS15Aa +Rpt1 RpS15Ab +Rpt1 RpS6 +Rpt1 Ubqn +Rpt1 RpL3 +Rpt1 RpS11 +Rpt1 RpS18 +Rpt1 Ufd1-like +Rpt1 Cct5 +Rpt1 CalpB +Rpt1 Ect3 +Rpt1 CG6891 +Rpt1 PyK +Rpt1 Cp1 +Rpt1 Cat +Rpt1 Pfk +Rpt1 CG8258 +Rpt1 cathD +Rpt1 Prosalpha1 +Rpt1 Uch-L5 +Rpt1 Rpt6R +Rpt1 Rpt4R +Rpt1 Prosalpha6 +Rpt1 Rpn12 +Rpt1 Rpt5 +Rpt1 Rpn5 +Rpt1 Prosbeta7 +Rpt1 Rpn2 +Rpt1 Rpt6 +Rpt1 Rpt2 +Rpt1 Rpn6 +Dlic p115 +Dlic deltaCOP +Dlic cpa +Dhc64C CLIP-190 +Dhc64C betaTub56D +Dhc64C Klc +Dhc64C poe +Dhc64C bai +Dhc64C FKBP59 +Dhc64C betaCOP +Dhc64C deltaCOP +Dhc64C epsilonCOP +Dhc64C beta'COP +Dhc64C CG10186 +Dhc64C zetaCOP +Dhc64C p115 +Dhc64C cpa +Dhc64C cpb +Dhc64C robl +Dhc64C Khc +Dhc64C BicD +Dhc64C Dlic +Ef1beta FeCH +Ef1beta CG7048 +Ef1beta Aats-asp +Ef1beta RpS15Aa +Ef1beta RpS10a +Ef1beta RpS15Ab +Ef1beta CG5642 +Ef1beta RpL3 +Ef1beta RpS3A +Ef1beta RpS12 +Ef1beta RpS13 +Ef1beta RpS10b +Ef1beta RpS16 +Ef1beta RpS2 +Ef1beta RpS6 +Ef1beta RpL12 +Ef1beta RpL30 +Ef1beta RpS23 +Ef1beta RpS11 +Ef1beta eEF1delta +Ef1beta RpL13 +Ef1beta sta +Ef1beta RpS7 +Ef1beta Tctp +Ef1beta Trip1 +Ef1beta RpS8 +Ef1beta RpS18 +Ef1beta Rack1 +Ef1beta RpS17 +Ef1beta RpL10Ab +Ef1beta RpL18A +Ef1beta RpS3 +Ef1beta RpS4 +Ef1beta RpL11 +Ef1beta RpLP2 +Ef1beta RpL4 +Rpn13 TER94 +Rpn13 Ufd1-like +Rpn13 Ubqn +Rpn13 Prosalpha6 +Rpn13 Prosbeta7 +Rpn13 Rpt4R +Rpn13 Prosalpha7 +Rpn13 Rpn12 +Rpn13 Rpt6R +Rpn13 Rpn5 +Rpn13 Rpt6 +Rpn13 Rpn6 +Rpn13 Uch-L5 +Rpn13 Rpt2 +Rpn13 Rpt5 +Rpn13 Rpt1 +Rpn13 Rpn2 +Tango7 CG7033 +Tango7 Tcp-1zeta +Tango7 mRpS10 +Tango7 Rpn5 +Tango7 bonsai +Tango7 Rpn2 +Tango7 Rpn6 +Tango7 RpS14a +Tango7 RpS15Aa +Tango7 RpS17 +Tango7 RpL10Ab +Tango7 RpL12 +Tango7 RpL13 +Tango7 RpL18A +Tango7 RpL3 +Tango7 RpS10a +Tango7 RpL11 +Tango7 RpS10b +Tango7 RpS2 +Tango7 RpS27 +Tango7 RpS23 +Tango7 RpS18 +Tango7 RpS12 +Tango7 RpS13 +Tango7 RpS4 +Tango7 RpS6 +Tango7 RpS16 +Tango7 sta +Tango7 eIF3-S10 +Tango7 RpS3 +Tango7 Trip1 +Tango7 RpL4 +Tango7 CG9769 +Tango7 eIF3-S9 +Tango7 CG5642 +Tango7 eIF3-S8 +Rpt2 Ubqn +Rpt2 Ufd1-like +Rpt2 CG8209 +Rpt2 Uch-L5 +Rpt2 Rpt4R +Rpt2 Rpn12 +Rpt2 Rpt5 +Rpt2 Rpt6 +Rpt2 Prosalpha6 +Rpt2 Rpn5 +Rpt2 Prosbeta7 +Rpn5 Ubqn +Rpn5 Ufd1-like +Rpn5 Cat +Rpn5 CalpB +Rpn5 CG6891 +Rpn5 Uch-L5 +Rpn5 Rpt4R +Rpn5 Rpt6 +Rpn5 Rpn12 +betaCOP cpa +betaCOP Dlic +betaCOP Klp10A +betaCOP p115 +betaCOP alphaCOP +betaCOP deltaCOP +Rpt6R RpS4 +Rpt6R pont +Rpt6R Rpt6 +Rpt6R Uch-L5 +Rpt6R Rpt4R +Rpt6R Prosalpha6 +Rpt6R Rpt2 +Rpt6R Rpt5 +Rpt6R Prosbeta7 +Rpt6R Rpn12 +Rpt6R Rpn2 +Rpt6R Rpn5 +Rpn2 Trip1 +Rpn2 RpS2 +Rpn2 Usp5 +Rpn2 Uch-L5 +Rpn2 Prosalpha6 +Rpn2 Rpt4R +Rpn2 Prosbeta7 +Rpn2 Rpn12 +Rpn2 Rpn5 +Rpn2 Rpt6 +Rpn2 Rpt2 +Rpn2 Rpt5 +RpL10Ab bonsai +RpL10Ab mago +RpL10Ab CG5642 +RpL10Ab RpS15Aa +RpL10Ab RpS14a +RpL10Ab RpL12 +RpL10Ab RpS16 +RpL10Ab RpS12 +RpL10Ab RpS10b +RpL10Ab RpS4 +RpL10Ab sta +RpL10Ab RpS6 +Trip1 RpS14a +Trip1 Tcp-1zeta +Trip1 CG10576 +Trip1 RpS17 +Trip1 CG7033 +Trip1 RpL10Ab +Trip1 RpS10b +Trip1 RpL12 +Trip1 RpS12 +Trip1 RpS4 +Trip1 RpS6 +Trip1 RpS16 +Trip1 sta +Trip1 CG9769 +Trip1 eIF3-S10 +Trip1 CG5642 +cpa p115 +cpa deltaCOP +cpb CG6891 +cpb flr +cpb p115 +cpb deltaCOP +cpb tsr +cpb betaCOP +cpb zetaCOP +cpb Dlic +cpb cpa +eIF3-S10 CG33123 +eIF3-S10 Aats-ile +eIF3-S10 RpS14a +eIF3-S10 RpS17 +eIF3-S10 RpS15Aa +eIF3-S10 RpL10Ab +eIF3-S10 RpL12 +eIF3-S10 RpS12 +eIF3-S10 RpS10b +eIF3-S10 RpS6 +eIF3-S10 RpS16 +eIF3-S10 RpS4 +eIF3-S10 sta +eIF3-S10 CG5642 +eIF3-S10 CG9769 +eIF3-S9 Cctgamma +eIF3-S9 rin +eIF3-S9 RpS14a +eIF3-S9 RpS15Aa +eIF3-S9 RpS17 +eIF3-S9 Tcp-1eta +eIF3-S9 CG7033 +eIF3-S9 T-cp1 +eIF3-S9 CG10576 +eIF3-S9 pAbp +eIF3-S9 RpL10Ab +eIF3-S9 RpL12 +eIF3-S9 RpS12 +eIF3-S9 RpS10a +eIF3-S9 RpS27 +eIF3-S9 RpS10b +eIF3-S9 RpS18 +eIF3-S9 RpL11 +eIF3-S9 RpL13 +eIF3-S9 RpL3 +eIF3-S9 RpL4 +eIF3-S9 RpS16 +eIF3-S9 sta +eIF3-S9 RpS2 +eIF3-S9 RpS13 +eIF3-S9 RpS4 +eIF3-S9 RpS6 +eIF3-S9 RpS3 +eIF3-S9 CG5642 +eIF3-S9 eIF3-S8 +eIF3-S9 CG9769 +eIF3-S9 Trip1 +eIF3-S9 eIF3-S10 +Pdi Ugt +Pdi Ost48 +Pdi CG2852 +Pdi CG2918 +Pdi Hsc70-3 +epsilonCOP Dlic +epsilonCOP Klc +epsilonCOP Klp10A +epsilonCOP cpb +epsilonCOP cpa +epsilonCOP p115 +epsilonCOP deltaCOP +epsilonCOP zetaCOP +epsilonCOP alphaCOP +epsilonCOP betaCOP +beta'COP cpb +beta'COP cpa +beta'COP Dlic +beta'COP Klp10A +beta'COP Klc +beta'COP p115 +beta'COP zetaCOP +beta'COP alphaCOP +beta'COP deltaCOP +beta'COP betaCOP +beta'COP epsilonCOP +CaBP1 Ugt +CaBP1 Ost48 +CaBP1 CG2918 +CaBP1 Hsc70-3 +CaBP1 Pdi +Gp93 Cctgamma +Gp93 bai +Gp93 Hsp27 +Gp93 Hop +Gp93 Hsp70Ab +Gp93 CG11577 +Gp93 Pdi +Gp93 Hsc70-3 +Gp93 CG2918 +Gp93 CaBP1 +Tcp-1eta RpL12 +Tcp-1eta RpS6 +Tcp-1eta RpL13 +Tcp-1eta RpL10Ab +Tcp-1eta sta +Tcp-1eta RpS2 +Tcp-1eta RpS12 +Tcp-1eta RpS13 +Tcp-1eta CG10576 +Tcp-1eta RpS4 +Tcp-1eta RpS16 +Tcp-1eta Trip1 +Tcp-1eta Hop +Tcp-1eta ade3 +Tcp-1eta Tcp-1zeta +Tcp-1eta CG7033 +RpL13 mRpL12 +RpL13 CG7033 +RpL13 ade3 +RpL13 bonsai +RpL13 Srp19 +RpL13 mago +RpL13 CG5642 +RpL13 eIF3-S10 +RpL13 CG10576 +RpL13 Srp54k +RpL13 CG9769 +RpL13 Trip1 +RpL13 RpS15Aa +RpL13 RpL12 +RpL13 RpS12 +RpL13 RpS13 +RpL13 RpS6 +RpL13 RpS14a +RpL13 RpL10Ab +RpL13 RpS4 +RpL13 sta +RpL13 RpS17 +RpL13 RpS10b +RpL13 RpS16 +Rpt4 Prosalpha1 +Rpt4 arm +Rpt4 Rpt4R +Rpt4 Uch-L5 +Rpt4 Rpt6R +Rpt4 Rpn13 +Rpt4 Rpt1 +Rpt4 Rpt6 +Rpt4 Prosalpha6 +Rpt4 Prosbeta7 +Rpt4 Rpn6 +Rpt4 Rpt2 +Rpt4 Rpn3 +Rpt4 Prosalpha7 +Rpt4 Rpn2 +Rpt4 Rpn12 +Rpt4 Rpn5 +Rpt4 Rpt5 +RpS11 vig +RpS11 bic +RpS11 CG7033 +RpS11 Tctp +RpS11 Tcp-1eta +RpS11 eEF1delta +RpS11 mago +RpS11 EfTuM +RpS11 Srp72 +RpS11 bonsai +RpS11 mRpS10 +RpS11 CG5642 +RpS11 mRpS9 +RpS11 mRpL12 +RpS11 eIF3-S8 +RpS11 CG9769 +RpS11 eIF3-S10 +RpS11 Srp19 +RpS11 ade3 +RpS11 eIF3-S9 +RpS11 Srp54k +RpS11 Tango7 +RpS11 Trip1 +RpS11 RpL10Ab +RpS11 RpS23 +RpS11 RpL3 +RpS11 RpL12 +RpS11 RpL11 +RpS11 RpS14a +RpS11 RpL4 +RpS11 RpS18 +RpS11 RpS6 +RpS11 sta +RpS11 RpS10a +RpS11 RpS17 +RpS11 RpS2 +RpS11 RpL18A +RpS11 RpS12 +RpS11 RpS3 +RpS11 RpS13 +RpS11 RpS27 +RpS11 RpS10b +RpS11 RpL13 +RpS11 RpS16 +RpS11 RpS15Aa +RpS11 RpS4 +eIF3-S8 CG33123 +eIF3-S8 Tcp-1zeta +eIF3-S8 eEF1delta +eIF3-S8 pAbp +eIF3-S8 RpS14a +eIF3-S8 RpS17 +eIF3-S8 RpS15Aa +eIF3-S8 CG10576 +eIF3-S8 RpL12 +eIF3-S8 RpL10Ab +eIF3-S8 RpL11 +eIF3-S8 RpL13 +eIF3-S8 RpL3 +eIF3-S8 RpS12 +eIF3-S8 sta +eIF3-S8 RpS2 +eIF3-S8 RpS13 +eIF3-S8 RpS4 +eIF3-S8 RpS10b +eIF3-S8 RpS27 +eIF3-S8 RpS10a +eIF3-S8 RpS16 +eIF3-S8 RpL4 +eIF3-S8 RpS18 +eIF3-S8 RpS6 +eIF3-S8 RpS3 +eIF3-S8 eIF3-S10 +eIF3-S8 Trip1 +eIF3-S8 CG9769 +eIF3-S8 CG5642 +Hop Hsp60 +Hop Hsc70-3 +Hop Ubqn +CG1416 CG7033 +CG1416 Hsp60 +CG1416 Gp93 +CG1416 Cctgamma +CG1416 Hop +RpS6 RpS14a +RpS6 sta +RpS2 CG10576 +RpS2 ade3 +RpS2 bonsai +RpS2 CG7033 +RpS2 mago +RpS2 mRpL12 +RpS2 CG5642 +RpS2 eIF3-S10 +RpS2 Srp19 +RpS2 CG9769 +RpS2 Srp54k +RpS2 Trip1 +RpS2 RpS6 +RpS2 RpS15Aa +RpS2 RpL12 +RpS2 RpS14a +RpS2 RpS10b +RpS2 RpS16 +RpS2 RpL10Ab +RpS2 RpS17 +RpS2 sta +RpS2 RpS4 +RpS2 RpS13 +RpS2 RpL13 +RpS2 RpS12 +Prosalpha6 Trip1 +Prosalpha6 Tcp-1zeta +Prosalpha6 Uch-L5 +Prosalpha6 Rpn5 +Prosalpha6 Rpt4R +Prosalpha6 Rpt6 +Prosalpha6 Prosbeta7 +Prosalpha6 Rpn12 +ND-PDSW COX6B +ND-PDSW CG7603 +ND-PDSW ND-B16.6 +ND-PDSW CG11752 +NP15.6 CG7603 +NP15.6 COX4 +NP15.6 CG11752 +NP15.6 ND-51 +NP15.6 COX5A +NP15.6 ND-B16.6 +NP15.6 ND-PDSW +Klc Dlic +Klc betaCOP +Klc deltaCOP +Klc zetaCOP +Klc Klp10A +Khc Dlic +Khc zetaCOP +Khc epsilonCOP +Khc bai +Khc deltaCOP +Khc beta'COP +Khc syd +Khc betaCOP +Khc Klp10A +Khc betaTub56D +Khc Klc +RpL12 bonsai +RpL12 mago +RpL12 RpS16 +RpL12 sta +RpL12 RpS14a +RpL12 RpS6 +Rpt5 Ubqn +Rpt5 Cat +Rpt5 CalpB +Rpt5 CG6891 +Rpt5 Ect3 +Rpt5 PyK +Rpt5 Tcp-1eta +Rpt5 Ufd1-like +Rpt5 Uch-L5 +Rpt5 Rpt4R +Rpt5 Prosalpha6 +Rpt5 Prosbeta7 +Rpt5 Rpn5 +Rpt5 Rpt6 +Rpt5 Rpn12 +Prosalpha7 RpS16 +Prosalpha7 Cct5 +Prosalpha7 Tcp-1eta +Prosalpha7 CG7033 +Prosalpha7 Trip1 +Prosalpha7 CG8258 +Prosalpha7 arm +Prosalpha7 Uch-L5 +Prosalpha7 Rpt4R +Prosalpha7 Prosalpha1 +Prosalpha7 Rpt6R +Prosalpha7 Rpn12 +Prosalpha7 Rpt6 +Prosalpha7 Rpn6 +Prosalpha7 Rpt2 +Prosalpha7 Rpt1 +Prosalpha7 Prosbeta7 +Prosalpha7 Prosalpha6 +Prosalpha7 Rpn5 +Prosalpha7 Rpn2 +Prosalpha7 Rpt5 +Rpn6 Trip1 +Rpn6 RpS2 +Rpn6 Ubqn +Rpn6 CalpB +Rpn6 Cat +Rpn6 PyK +Rpn6 Ect3 +Rpn6 CG6891 +Rpn6 Uch-L5 +Rpn6 Prosalpha6 +Rpn6 Rpt4R +Rpn6 Prosbeta7 +Rpn6 Rpn2 +Rpn6 Rpt5 +Rpn6 Rpn12 +Rpn6 Rpn5 +Rpn6 Rpt2 +Rpn6 Rpt6R +Rpn6 Rpt6 +ATPsynbeta Rack1 +ATPsynbeta COX4 +ATPsynbeta COX6B +ATPsynbeta sta +ATPsynbeta Hsc70-5 +ATPsynbeta Eno +ATPsynbeta RpL4 +ATPsynbeta RpS3A +ATPsynbeta CG11876 +ATPsynbeta Mpcp +ATPsynbeta porin +ATPsynbeta Vha100-1 +ATPsynbeta RpS2 +ATPsynbeta Vha100-2 +ATPsynbeta Hsp83 +ATPsynbeta ND-51 +ATPsynbeta Vha68-2 +ATPsynbeta EfTuM +ATPsynbeta Mdh2 +ATPsynbeta CG9090 +ATPsynbeta COX5A +ATPsynbeta sun +ATPsynCF6 Vha100-1 +ATPsynCF6 Vha100-2 +ATPsynCF6 NP15.6 +ATPsynCF6 Vha68-2 +ATPsynCF6 ND-B16.6 +ATPsynCF6 COX6B +ATPsynCF6 CG11752 +ATPsynCF6 Cyt-c-p +ATPsynCF6 COX4 +ATPsynCF6 ND-PDSW +ATPsynCF6 COX5A +ATPsynCF6 sun +ATPsynCF6 ATPsynbeta +CG8258 RpS13 +CG8258 RpL11 +CG8258 eIF3-S9 +CG8258 Tango7 +CG8258 Hsp60C +CG8258 Rpn2 +CG8258 RpS3 +CG8258 RpL12 +CG8258 RpL3 +CG8258 Hsc70-5 +CG8258 RpL4 +CG8258 RpS4 +CG8258 RpS2 +CG8258 RpS16 +CG8258 Hsp60 +CG8258 CG10576 +CG8258 Cat +CG8258 CG6891 +CG8258 CalpB +CG8258 Ect3 +CG8258 Cp1 +CG8258 Pfk +CG8258 PyK +CG8258 ade3 +CG8258 Trip1 +CG8258 Rpt5 +CG8258 Rpn6 +CG8258 Rpn5 +CG8258 Hop +CG8258 Cct5 +CG8258 Cctgamma +CG8258 Tcp-1zeta +CG8258 CG7033 +CG8258 Tcp-1eta +CG8258 T-cp1 +RpS7 Rpt6R +RpS7 Rpt6 +RpS7 vig +RpS7 eEF1delta +RpS7 Rpt1 +RpS7 Rpt2 +RpS7 ade3 +RpS7 mRpS10 +RpS7 Srp72 +RpS7 mago +RpS7 bonsai +RpS7 Tctp +RpS7 CG5642 +RpS7 CG9769 +RpS7 eIF3-S10 +RpS7 Srp54k +RpS7 Srp19 +RpS7 Trip1 +RpS7 eIF3-S9 +RpS7 eIF3-S8 +RpS7 Tango7 +RpS7 RpS15Ab +RpS7 RpS10a +RpS7 RpS15Aa +RpS7 RpS14a +RpS7 RpL4 +RpS7 RpL13 +RpS7 sta +RpS7 RpS2 +RpS7 RpS23 +RpS7 RpS16 +RpS7 RpL10Ab +RpS7 RpS6 +RpS7 RpS18 +RpS7 RpL11 +RpS7 RpS12 +RpS7 RpS4 +RpS7 RpS3 +RpS7 RpS13 +RpS7 RpS27 +RpS7 RpL3 +RpS7 RpS10b +RpS7 RpS17 +RpS7 RpL18A +RpS7 RpS11 +RpS7 RpL12 +RpL10 mRpS10 +RpL10 ade3 +RpL10 Cct5 +RpL10 mRpS5 +RpL10 eEF1delta +RpL10 mRpL12 +RpL10 mRpS9 +RpL10 Ef1beta +RpL10 eIF4G +RpL10 Srp72 +RpL10 mago +RpL10 Rbp2 +RpL10 eIF3-S10 +RpL10 eIF3-S8 +RpL10 CG5642 +RpL10 CG10576 +RpL10 Tango7 +RpL10 Trip1 +RpL10 Srp19 +RpL10 mRpS7 +RpL10 eIF-2gamma +RpL10 Elf +RpL10 eIF-3p66 +RpL10 CG9769 +RpL10 eIF3-S9 +RpL10 Srp54k +RpL10 eRF1 +RpL10 RpS15Ab +RpL10 Tctp +RpL10 RpS14a +RpL10 RpS15Aa +RpL10 RpS10b +RpL10 RpS17 +RpL10 RpL13 +RpL10 RpS8 +RpL10 RpS16 +RpL10 sta +RpL10 RpL12 +RpL10 RpS3 +RpL10 RpL4 +RpL10 RpS27 +RpL10 RpL3 +RpL10 RpS12 +RpL10 RpL11 +RpL10 RpLP2 +RpL10 RpL18A +RpL10 RpL26 +RpL10 RpS4 +RpL10 Rack1 +RpL10 RpS3A +RpL10 RpS11 +RpL10 RpS13 +RpL10 RpS10a +RpL10 RpL30 +RpL10 RpS2 +RpL10 RpS18 +RpL10 RpS23 +RpL10 RpL10Ab +RpL10 RpS6 +RpL10 RpS7 +Aats-asp CG5642 +Aats-asp CG31739 +Aats-asp CG33123 +Aats-asp Aats-arg +Aats-asp Aats-ile +CG33123 Aats-arg +Aats-ile CG33123 +Aats-ile Aats-arg +RpS8 T-cp1 +RpS8 vig +RpS8 Rpn2 +RpS8 Cct5 +RpS8 eEF1delta +RpS8 mRpS10 +RpS8 CG8258 +RpS8 Tcp-1eta +RpS8 bonsai +RpS8 CG7033 +RpS8 ade3 +RpS8 CG10576 +RpS8 Srp72 +RpS8 mago +RpS8 Rbp2 +RpS8 Nacalpha +RpS8 CG5642 +RpS8 eIF-3p66 +RpS8 Srp54k +RpS8 Srp19 +RpS8 eIF3-S10 +RpS8 Tctp +RpS8 Trip1 +RpS8 Tango7 +RpS8 eIF3-S8 +RpS8 CG9769 +RpS8 eIF3-S9 +RpS8 RpL13 +RpS8 RpS17 +RpS8 RpL11 +RpS8 RpS12 +RpS8 RpL4 +RpS8 RpS3 +RpS8 RpS27 +RpS8 RpS18 +RpS8 RpS2 +RpS8 RpS13 +RpS8 RpS7 +RpS8 RpS6 +RpS8 sta +RpS8 RpL10Ab +RpS8 RpS10b +RpS8 RpS10a +RpS8 RpS14a +RpS8 RpS4 +RpS8 RpL12 +RpS8 RpS11 +RpS8 RpL18A +RpS8 RpLP2 +RpS8 RpL3 +RpS8 RpS23 +RpS8 RpS15Ab +RpS8 RpS15Aa +RpS8 RpS16 +Rpt6 Ubqn +Rpt6 RpS4 +Rpt6 Uch-L5 +Rpt6 Rpt4R +Rpt6 Rpn12 +Rpn3 bel +Rpn3 Ubqn +Rpn3 CalpB +Rpn3 Ect3 +Rpn3 Pfk +Rpn3 CG6891 +Rpn3 Cat +Rpn3 Cp1 +Rpn3 PyK +Rpn3 arm +Rpn3 cathD +Rpn3 CG8258 +Rpn3 Prosalpha1 +Rpn3 Uch-L5 +Rpn3 TER94 +Rpn3 Prosalpha6 +Rpn3 Prosbeta7 +Rpn3 Prosalpha7 +Rpn3 Rpt4R +Rpn3 Rpn2 +Rpn3 Rpt6R +Rpn3 Rpt2 +Rpn3 Rpn5 +Rpn3 Rpt1 +Rpn3 Rpt5 +Rpn3 Rpn6 +Rpn3 Rpn13 +Rpn3 Rpn12 +Rpn3 Rpt6 +RpL30 vig +RpL30 Nacalpha +RpL30 CG10576 +RpL30 Srp72 +RpL30 eIF4G +RpL30 bonsai +RpL30 eIF3-S8 +RpL30 mago +RpL30 eIF3-S10 +RpL30 CG5642 +RpL30 mRpS5 +RpL30 Rbp2 +RpL30 mRpS10 +RpL30 eIF-3p66 +RpL30 Tctp +RpL30 eIF3-S9 +RpL30 Tango7 +RpL30 CG9769 +RpL30 Trip1 +RpL30 Srp54k +RpL30 Srp19 +RpL30 RpS15Aa +RpL30 RpS15Ab +RpL30 RpS10a +RpL30 RpL18A +RpL30 RpS27 +RpL30 RpL12 +RpL30 RpS12 +RpL30 RpS18 +RpL30 RpS17 +RpL30 RpS2 +RpL30 RpL11 +RpL30 RpS7 +RpL30 RpS14a +RpL30 RpS4 +RpL30 RpS8 +RpL30 RpS10b +RpL30 RpLP2 +RpL30 RpL13 +RpL30 RpS16 +RpL30 RpS3 +RpL30 RpS13 +RpL30 RpS11 +RpL30 RpS6 +RpL30 RpL3 +RpL30 RpL10Ab +RpL30 RpS23 +RpL30 RpL4 +RpL30 sta +RpS10a Tctp +RpS10a eEF1delta +RpS10a bonsai +RpS10a mRpS10 +RpS10a RpS10b +RpS10a Srp72 +RpS10a mago +RpS10a CG5642 +RpS10a CG9769 +RpS10a eIF3-S10 +RpS10a Trip1 +RpS10a Srp19 +RpS10a Srp54k +RpS10a RpS15Aa +RpS10a sta +RpS10a RpS2 +RpS10a RpS3 +RpS10a RpL10Ab +RpS10a RpS4 +RpS10a RpS13 +RpS10a RpS6 +RpS10a RpS12 +RpS10a RpS16 +RpS10a RpS14a +RpS10a RpS27 +RpS10a RpL13 +RpS10a RpL12 +RpS10a RpS17 +RpS10a RpL3 +RpS17 CG7033 +RpS17 CG5642 +RpS17 bonsai +RpS17 RpS6 +RpS17 RpL12 +RpS17 RpL10Ab +RpS17 RpS15Aa +RpS17 RpS12 +RpS17 sta +RpS17 RpS14a +RpS17 RpS4 +RpS17 RpS16 +RpS17 RpS10b +RpLP0 ATPsynbeta +RpLP0 Tcp-1zeta +RpLP0 T-cp1 +RpLP0 CG7033 +RpLP0 EfTuM +RpLP0 Nacalpha +RpLP0 bonsai +RpLP0 Tcp-1eta +RpLP0 mRpS10 +RpLP0 ade3 +RpLP0 Cct5 +RpLP0 mRpS5 +RpLP0 eEF1delta +RpLP0 Srp72 +RpLP0 eIF4G +RpLP0 mRpS9 +RpLP0 Rbp2 +RpLP0 mago +RpLP0 CG5642 +RpLP0 eIF3-S8 +RpLP0 Elf +RpLP0 eIF3-S10 +RpLP0 CG10576 +RpLP0 mRpL12 +RpLP0 mRpS7 +RpLP0 Tctp +RpLP0 Srp19 +RpLP0 Tango7 +RpLP0 eIF-2gamma +RpLP0 eIF-3p66 +RpLP0 CG9769 +RpLP0 eIF3-S9 +RpLP0 RpS15Aa +RpLP0 Srp54k +RpLP0 Trip1 +RpLP0 RpS15Ab +RpLP0 eRF1 +RpLP0 RpS14a +RpLP0 RpS10a +RpLP0 Ef1beta +RpLP0 RpS6 +RpLP0 RpS13 +RpLP0 RpS23 +RpLP0 sta +RpLP0 RpS11 +RpLP0 RpS16 +RpLP0 RpS7 +RpLP0 RpS27 +RpLP0 RpL10 +RpLP0 RpS3 +RpLP0 RpS10b +RpLP0 RpS8 +RpLP0 RpLP2 +RpLP0 RpS12 +RpLP0 RpL3 +RpLP0 Rack1 +RpLP0 RpL13 +RpLP0 RpL26 +RpLP0 RpL30 +RpLP0 RpL18A +RpLP0 RpL4 +RpLP0 RpL10Ab +RpLP0 RpS18 +RpLP0 RpS3A +RpLP0 RpL12 +RpLP0 RpL11 +RpLP0 RpS2 +RpLP0 RpS4 +RpLP0 RpS17 +eRF1 bonsai +eRF1 T-cp1 +eRF1 eIF3-S8 +eRF1 CG8635 +eRF1 CG7033 +eRF1 Cctgamma +eRF1 mRpS5 +eRF1 mRpS10 +eRF1 wuho +eRF1 RpS15Ab +eRF1 RpS14a +eRF1 RpS15Aa +eRF1 eIF3-S10 +eRF1 pAbp +eRF1 CG10576 +eRF1 RpS17 +eRF1 eIF-2gamma +eRF1 Trip1 +eRF1 mago +eRF1 RpLP2 +eRF1 eIF3-S9 +eRF1 eIF4G +eRF1 Rack1 +eRF1 RpS10a +eRF1 RpS10b +eRF1 RpL3 +eRF1 RpL10Ab +eRF1 RpS27 +eRF1 RpS12 +eRF1 RpS7 +eRF1 RpS18 +eRF1 RpL12 +eRF1 RpS23 +eRF1 RpL18A +eRF1 RpS16 +eRF1 RpL30 +eRF1 RpS11 +eRF1 RpS3 +eRF1 RpS3A +eRF1 sta +eRF1 RpS13 +eRF1 RpS6 +eRF1 RpS8 +eRF1 RpL4 +eRF1 RpS4 +eRF1 RpL11 +eRF1 RpS2 +eRF1 RpL13 +Elf ade5 +Elf mRpS7 +Elf RpS15Aa +Elf RpS15Ab +Elf T-cp1 +Elf eIF3-S9 +Elf Cctgamma +Elf RpS17 +Elf CG33123 +Elf Cct5 +Elf RpS14a +Elf eIF3-S8 +Elf eIF3-S10 +Elf eIF-2gamma +Elf RpL10Ab +Elf RpLP2 +Elf mago +Elf RpL13 +Elf RpL3 +Elf RpL30 +Elf RpL18A +Elf RpL12 +Elf RpL11 +Elf Rack1 +Elf RpL4 +Elf RpS4 +Elf RpS10b +Elf RpS10a +Elf RpS12 +Elf eIF4G +Elf RpS11 +Elf RpS13 +Elf RpS27 +Elf RpS8 +Elf RpS16 +Elf RpS3 +Elf sta +Elf RpS23 +Elf RpS18 +Elf RpS7 +Elf RpS6 +Elf RpS3A +Elf RpS2 +Elf pAbp +Elf eRF1 +RpS15Aa bonsai +RpS15Aa RpL12 +RpS15Aa sta +RpS15Aa RpS6 +RpS15Aa RpS16 +RpS15Aa RpS14a +RpS27 vig +RpS27 Srp72 +RpS27 mRpS10 +RpS27 bonsai +RpS27 mago +RpS27 Tctp +RpS27 CG5642 +RpS27 CG9769 +RpS27 Trip1 +RpS27 eIF3-S10 +RpS27 Srp19 +RpS27 Srp54k +RpS27 RpS13 +RpS27 RpS17 +RpS27 RpS4 +RpS27 RpS2 +RpS27 RpL13 +RpS27 RpL12 +RpS27 RpS6 +RpS27 RpS12 +RpS27 RpS10b +RpS27 sta +RpS27 RpS16 +RpS27 RpS14a +RpS27 RpL10Ab +RpS27 RpL3 +RpS27 RpS3 +RpS27 RpS15Aa +RpS18 Rpt6R +RpS18 Rpt6 +RpS18 Tcp-1eta +RpS18 Rpt2 +RpS18 vig +RpS18 ade3 +RpS18 Srp72 +RpS18 mago +RpS18 bonsai +RpS18 Tctp +RpS18 CG5642 +RpS18 mRpL12 +RpS18 mRpS10 +RpS18 mRpS9 +RpS18 eIF3-S10 +RpS18 CG9769 +RpS18 Srp19 +RpS18 Srp54k +RpS18 Trip1 +RpS18 RpS12 +RpS18 RpS2 +RpS18 RpS16 +RpS18 sta +RpS18 RpL10Ab +RpS18 RpL4 +RpS18 RpS14a +RpS18 RpS17 +RpS18 RpS3 +RpS18 RpS4 +RpS18 RpL3 +RpS18 RpS10a +RpS18 RpS13 +RpS18 RpS10b +RpS18 RpL13 +RpS18 RpL12 +RpS18 RpS15Aa +RpS18 RpS6 +RpS18 RpS27 +RpS10b bonsai +RpS10b mago +RpS10b RpS15Aa +RpS10b RpS16 +RpS10b RpS14a +RpS10b RpL12 +RpS10b sta +RpS10b RpS6 +RpS3A CG7048 +RpS3A Nacalpha +RpS3A vig +RpS3A eEF1delta +RpS3A Cct5 +RpS3A CG8258 +RpS3A CG7033 +RpS3A Tcp-1eta +RpS3A Srp72 +RpS3A mRpS5 +RpS3A Rbp2 +RpS3A mRpS10 +RpS3A eIF4G +RpS3A bonsai +RpS3A mago +RpS3A CG5642 +RpS3A eIF-3p66 +RpS3A eIF3-S8 +RpS3A Srp54k +RpS3A eIF3-S10 +RpS3A Srp19 +RpS3A CG9769 +RpS3A ade3 +RpS3A Trip1 +RpS3A Tango7 +RpS3A eIF3-S9 +RpS3A Tctp +RpS3A RpS12 +RpS3A RpS13 +RpS3A RpS2 +RpS3A RpS17 +RpS3A RpS15Ab +RpS3A RpL13 +RpS3A RpS15Aa +RpS3A RpS8 +RpS3A RpS10a +RpS3A RpS4 +RpS3A RpL11 +RpS3A RpS23 +RpS3A RpS7 +RpS3A RpLP2 +RpS3A sta +RpS3A RpS6 +RpS3A RpL12 +RpS3A RpS11 +RpS3A RpL30 +RpS3A RpL3 +RpS3A RpS3 +RpS3A RpS14a +RpS3A RpL10Ab +RpS3A RpL18A +RpS3A RpS27 +RpS3A RpL4 +RpS3A RpS16 +RpS3A RpS18 +RpS3A RpS10b +RpS16 mago +RpS16 RpS14a +RpS16 RpS6 +RpS16 sta +RpS15Ab vig +RpS15Ab CG9769 +RpS15Ab ade3 +RpS15Ab EfTuM +RpS15Ab Srp19 +RpS15Ab eIF3-S9 +RpS15Ab eIF3-S10 +RpS15Ab eIF3-S8 +RpS15Ab bonsai +RpS15Ab mRpS10 +RpS15Ab Srp54k +RpS15Ab Tango7 +RpS15Ab Tctp +RpS15Ab mRpS9 +RpS15Ab mRpL12 +RpS15Ab RpS15Aa +RpS15Ab RpS12 +RpS15Ab RpL10Ab +RpS15Ab RpL13 +RpS15Ab RpL18A +RpS15Ab RpL12 +RpS15Ab RpL3 +RpS15Ab RpL4 +RpS15Ab RpS10a +RpS15Ab RpL11 +RpS15Ab RpS6 +RpS15Ab RpS2 +RpS15Ab RpS13 +RpS15Ab RpS23 +RpS15Ab RpS18 +RpS15Ab RpS3 +RpS15Ab RpS10b +RpS15Ab RpS17 +RpS15Ab RpS14a +RpS15Ab sta +RpS15Ab RpS11 +RpS15Ab RpS27 +RpS15Ab RpS4 +RpS15Ab RpS16 +RpL3 eEF1delta +RpL3 bonsai +RpL3 Tcp-1zeta +RpL3 Tcp-1eta +RpL3 CG7033 +RpL3 Tctp +RpL3 mago +RpL3 Srp19 +RpL3 mRpL12 +RpL3 mRpS9 +RpL3 eIF3-S10 +RpL3 CG10576 +RpL3 CG5642 +RpL3 CG9769 +RpL3 Srp54k +RpL3 Trip1 +RpL3 ade3 +RpL3 RpS14a +RpL3 RpS10b +RpL3 RpS15Aa +RpL3 RpS13 +RpL3 RpS16 +RpL3 RpS2 +RpL3 RpS4 +RpL3 RpS17 +RpL3 sta +RpL3 RpL12 +RpL3 RpL13 +RpL3 RpL10Ab +RpL3 RpS12 +RpL3 RpS6 +Tcp-1zeta Tim9a +Tcp-1zeta RpL12 +Tcp-1zeta Hsp60 +Tcp-1zeta sta +Tcp-1zeta CG7033 +T-cp1 RpS13 +T-cp1 RpS2 +T-cp1 RpL13 +T-cp1 Hop +T-cp1 sta +T-cp1 RpL12 +T-cp1 Aats-ile +T-cp1 RpS4 +T-cp1 RpL3 +T-cp1 CG10576 +T-cp1 CG7033 +T-cp1 Cctgamma +T-cp1 Tcp-1eta +T-cp1 Tcp-1zeta +RpS3 Tcp-1zeta +RpS3 vig +RpS3 CG7033 +RpS3 eEF1delta +RpS3 ade3 +RpS3 Tcp-1eta +RpS3 Srp72 +RpS3 mago +RpS3 bonsai +RpS3 mRpS10 +RpS3 mRpS9 +RpS3 mRpL12 +RpS3 Srp19 +RpS3 CG5642 +RpS3 Srp54k +RpS3 CG9769 +RpS3 Tctp +RpS3 eIF3-S10 +RpS3 RpS15Aa +RpS3 RpL13 +RpS3 RpS6 +RpS3 RpS2 +RpS3 RpL12 +RpS3 RpL10Ab +RpS3 RpS14a +RpS3 RpS12 +RpS3 RpS13 +RpS3 RpS16 +RpS3 RpS10b +RpS3 sta +RpS3 RpS4 +RpS3 RpL3 +RpS3 RpS17 +RpS3 Trip1 +RpL26 CG10576 +RpL26 eEF1delta +RpL26 EfTuM +RpL26 Nacalpha +RpL26 bonsai +RpL26 ade3 +RpL26 mRpS10 +RpL26 mRpS5 +RpL26 Tctp +RpL26 eIF4G +RpL26 CG5642 +RpL26 mago +RpL26 eIF3-S10 +RpL26 Rbp2 +RpL26 mRpS9 +RpL26 eIF3-S9 +RpL26 mRpL12 +RpL26 eIF-3p66 +RpL26 eIF3-S8 +RpL26 Srp72 +RpL26 eIF-2gamma +RpL26 mRpS7 +RpL26 CG9769 +RpL26 Elf +RpL26 Tango7 +RpL26 Trip1 +RpL26 Ef1beta +RpL26 Srp19 +RpL26 eRF1 +RpL26 Srp54k +RpL26 RpS15Aa +RpL26 RpS15Ab +RpL26 RpL10Ab +RpL26 RpL11 +RpL26 RpL3 +RpL26 RpS13 +RpL26 RpS2 +RpL26 RpS6 +RpL26 RpS4 +RpL26 RpS27 +RpL26 RpL30 +RpL26 RpL18A +RpL26 RpS12 +RpL26 RpS10a +RpL26 RpS18 +RpL26 RpS3A +RpL26 RpS8 +RpL26 RpS17 +RpL26 sta +RpL26 RpS14a +RpL26 RpS11 +RpL26 RpS23 +RpL26 RpL13 +RpL26 RpL12 +RpL26 RpS10b +RpL26 Rack1 +RpL26 RpL4 +RpL26 RpS3 +RpL26 RpS7 +RpL26 RpS16 +RpL26 RpLP2 +RpS12 mago +RpS12 RpS14a +RpS12 RpS15Aa +RpS12 RpS10b +RpS12 RpS6 +RpS12 RpS16 +RpS12 RpL12 +RpS12 sta +CG5642 RpL12 +CG5642 RpS6 +CG5642 sta +CG5642 RpS10b +CG5642 RpS12 +CG5642 RpS16 +CG5642 RpS4 +CG9769 RpS15Aa +CG9769 RpS17 +CG9769 RpS12 +CG9769 RpL12 +CG9769 RpS10b +CG9769 RpL10Ab +CG9769 RpS4 +CG9769 sta +CG9769 RpS6 +CG9769 RpS16 +CG9769 CG5642 +CG7033 RpS14a +CG7033 sta +Cct5 RpS13 +Cct5 ade3 +Cct5 Prosalpha6 +Cct5 Hsc70-5 +Cct5 Rpt6 +Cct5 RpS3 +Cct5 Ref1 +Cct5 RpS16 +Cct5 RpL12 +Cct5 RpL13 +Cct5 CG5642 +Cct5 RpL18A +Cct5 RpS6 +Cct5 sta +Cct5 RpL11 +Cct5 Aats-ile +Cct5 pont +Cct5 Trip1 +Cct5 RpS4 +Cct5 Tango7 +Cct5 eIF3-S9 +Cct5 RpL3 +Cct5 RpS2 +Cct5 CG10576 +Cct5 RpL4 +Cct5 Hop +Cct5 Cctgamma +Cct5 Tcp-1eta +Cct5 T-cp1 +Cct5 Tcp-1zeta +Cct5 CG7033 +RpLP2 CG10576 +RpLP2 bonsai +RpLP2 mRpS10 +RpLP2 Srp72 +RpLP2 Srp54k +RpLP2 Srp19 +RpLP2 mago +RpLP2 eIF3-S8 +RpLP2 eIF3-S10 +RpLP2 CG5642 +RpLP2 Rbp2 +RpLP2 Tango7 +RpLP2 eIF3-S9 +RpLP2 eIF-3p66 +RpLP2 Nacalpha +RpLP2 RpS15Aa +RpLP2 CG9769 +RpLP2 Trip1 +RpLP2 Tctp +RpLP2 RpS10a +RpLP2 RpS10b +RpLP2 RpS27 +RpLP2 RpS3 +RpLP2 RpS13 +RpLP2 RpS18 +RpLP2 RpL4 +RpLP2 RpS7 +RpLP2 RpL13 +RpLP2 RpS23 +RpLP2 RpL10Ab +RpLP2 RpS15Ab +RpLP2 RpS6 +RpLP2 RpS14a +RpLP2 RpS2 +RpLP2 RpL3 +RpLP2 RpL12 +RpLP2 RpL18A +RpLP2 RpL11 +RpLP2 RpS11 +RpLP2 sta +RpLP2 RpS16 +RpLP2 RpS17 +RpLP2 RpS12 +RpLP2 RpS4 +RpS23 CG7033 +RpS23 vig +RpS23 eEF1delta +RpS23 bonsai +RpS23 mRpS10 +RpS23 Srp72 +RpS23 mago +RpS23 CG5642 +RpS23 mRpL12 +RpS23 mRpS9 +RpS23 Tctp +RpS23 eIF3-S9 +RpS23 eIF3-S8 +RpS23 eIF3-S10 +RpS23 CG9769 +RpS23 Trip1 +RpS23 Srp19 +RpS23 Srp54k +RpS23 RpS16 +RpS23 RpS27 +RpS23 RpL18A +RpS23 RpS10b +RpS23 RpS15Aa +RpS23 RpS12 +RpS23 RpS3 +RpS23 RpS18 +RpS23 RpS14a +RpS23 RpL11 +RpS23 RpL3 +RpS23 RpS2 +RpS23 sta +RpS23 RpS6 +RpS23 RpL10Ab +RpS23 RpL12 +RpS23 RpL13 +RpS23 RpS17 +RpS23 RpL4 +RpS23 RpS4 +RpS23 RpS10a +RpS23 RpS13 +RpS14a sta +Rack1 vig +Rack1 bel +Rack1 Prosalpha7 +Rack1 Rpn6 +Rack1 Rpn2 +Rack1 eEF1delta +Rack1 Cctgamma +Rack1 Eno +Rack1 pAbp +Rack1 Nacalpha +Rack1 eIF3-S8 +Rack1 CG10576 +Rack1 CG9769 +Rack1 ade3 +Rack1 Dp1 +Rack1 T-cp1 +Rack1 Tcp-1zeta +Rack1 Srp54k +Rack1 Tcp-1eta +Rack1 Srp19 +Rack1 CG8258 +Rack1 CG7033 +Rack1 Cct5 +Rack1 mRpS5 +Rack1 bonsai +Rack1 mRpS10 +Rack1 eIF3-S10 +Rack1 Tctp +Rack1 eIF3-S9 +Rack1 eIF-2gamma +Rack1 Trip1 +Rack1 RpS15Ab +Rack1 Tango7 +Rack1 RpS15Aa +Rack1 RpS10a +Rack1 RpS14a +Rack1 RpS10b +Rack1 RpL10Ab +Rack1 RpS8 +Rack1 RpL3 +Rack1 RpS11 +Rack1 RpS17 +Rack1 RpS2 +Rack1 RpS16 +Rack1 RpS13 +Rack1 RpS12 +Rack1 RpS4 +Rack1 RpS3A +Rack1 RpS3 +Rack1 RpS18 +Rack1 RpS23 +Rack1 RpS6 +Rack1 RpL12 +Rack1 RpL13 +Rack1 RpS27 +Rack1 RpL11 +Rack1 RpL18A +Rack1 RpL30 +Rack1 RpS7 +Rack1 RpLP2 +Rack1 RpL4 +Rack1 sta +RpL11 CG7033 +RpL11 vig +RpL11 eEF1delta +RpL11 Tcp-1eta +RpL11 mago +RpL11 eIF3-S10 +RpL11 CG10576 +RpL11 CG5642 +RpL11 bonsai +RpL11 mRpS10 +RpL11 Srp72 +RpL11 mRpS9 +RpL11 Tctp +RpL11 mRpL12 +RpL11 CG9769 +RpL11 Srp19 +RpL11 Srp54k +RpL11 Trip1 +RpL11 RpS15Aa +RpL11 RpS13 +RpL11 RpS18 +RpL11 RpL3 +RpL11 RpL12 +RpL11 RpS10b +RpL11 RpS17 +RpL11 RpL10Ab +RpL11 RpS10a +RpL11 RpL13 +RpL11 RpS4 +RpL11 RpS16 +RpL11 RpS12 +RpL11 RpS27 +RpL11 RpS2 +RpL11 RpS3 +RpL11 RpS6 +RpL11 RpS14a +RpL11 RpL4 +RpL11 sta +Rpn12 Ubqn +Prosbeta7 Uba2 +Prosbeta7 CG7033 +Prosbeta7 Uch-L5 +Prosbeta7 Rpt4R +Prosbeta7 Rpn5 +Prosbeta7 Rpt6 +Prosbeta7 Rpn12 +RpS13 CG10576 +RpS13 CG7033 +RpS13 mRpL12 +RpS13 ade3 +RpS13 mago +RpS13 CG5642 +RpS13 eIF3-S10 +RpS13 CG9769 +RpS13 Srp19 +RpS13 Srp54k +RpS13 Trip1 +RpS13 RpL10Ab +RpS13 RpS15Aa +RpS13 RpS12 +RpS13 RpS17 +RpS13 RpL12 +RpS13 RpS10b +RpS13 sta +RpS13 RpS16 +RpS13 RpS4 +RpS13 RpS6 +RpS13 RpS14a +RpL18A Tcp-1zeta +RpL18A vig +RpL18A CG7033 +RpL18A eEF1delta +RpL18A Tcp-1eta +RpL18A ade3 +RpL18A mRpS10 +RpL18A mago +RpL18A bonsai +RpL18A CG10576 +RpL18A CG5642 +RpL18A eIF3-S8 +RpL18A eIF3-S10 +RpL18A Srp72 +RpL18A eIF3-S9 +RpL18A Tctp +RpL18A Srp19 +RpL18A CG9769 +RpL18A Srp54k +RpL18A Trip1 +RpL18A RpS15Aa +RpL18A RpS14a +RpL18A sta +RpL18A RpL10Ab +RpL18A RpS2 +RpL18A RpL3 +RpL18A RpS17 +RpL18A RpL4 +RpL18A RpL13 +RpL18A RpS4 +RpL18A RpL11 +RpL18A RpS10a +RpL18A RpS6 +RpL18A RpL12 +RpL18A RpS18 +RpL18A RpS16 +RpL18A RpS12 +RpL18A RpS27 +RpL18A RpS10b +RpL18A RpS3 +RpL18A RpS13 +RpS4 Tcp-1zeta +RpS4 CG7033 +RpS4 mago +RpS4 bonsai +RpS4 RpS15Aa +RpS4 RpL12 +RpS4 sta +RpS4 RpS10b +RpS4 RpS14a +RpS4 RpS16 +RpS4 RpS6 +RpS4 RpS12 +RpL4 vig +RpL4 bonsai +RpL4 Cctgamma +RpL4 mRpS10 +RpL4 Tcp-1eta +RpL4 Tctp +RpL4 T-cp1 +RpL4 CG7033 +RpL4 Tcp-1zeta +RpL4 ade3 +RpL4 mRpS9 +RpL4 mRpL12 +RpL4 Srp72 +RpL4 mago +RpL4 Srp19 +RpL4 CG5642 +RpL4 CG10576 +RpL4 Srp54k +RpL4 CG9769 +RpL4 eIF3-S10 +RpL4 RpS15Aa +RpL4 RpS10a +RpL4 RpL10Ab +RpL4 Trip1 +RpL4 RpS16 +RpL4 RpS6 +RpL4 RpS12 +RpL4 RpS14a +RpL4 RpS2 +RpL4 RpL12 +RpL4 RpS27 +RpL4 sta +RpL4 RpS13 +RpL4 RpS10b +RpL4 RpS3 +RpL4 RpS17 +RpL4 RpL13 +RpL4 RpL3 +RpL4 RpS4 \ No newline at end of file diff --git a/www/Examples/TP53/string_expression_colors.txt b/www/Examples/TP53/string_expression_colors.txt new file mode 100644 index 0000000..d049f2d --- /dev/null +++ b/www/Examples/TP53/string_expression_colors.txt @@ -0,0 +1,10 @@ +CDKN1A blue +TP53 blue +MDM4 blue +BCL2L1 red +CHEK2 red +ATM red +TP53BP2 red +CDKN2A blue +EP300 red +CREBBP red diff --git a/www/Examples/TP53/string_interactions.txt b/www/Examples/TP53/string_interactions.txt new file mode 100644 index 0000000..14e1e05 --- /dev/null +++ b/www/Examples/TP53/string_interactions.txt @@ -0,0 +1,47 @@ +Source Target Weight +CDKN1A TP53 70 +TP53 MDM2 2 +MDM4 TP53 3 +BCL2L1 TP53 4 +CHEK2 ATM 5 +TP53 EP300 20 +ATM TP53 7 +TP53 CREBB 1 +MDM4 MDM2 1 +CHEK2 TP53 1 +TP53BP2 TP53 1 +CDKN2A TP53 1 +CDKN2A MDM2 1 +ATM MDM2 2 +EP300 CREBBP 1 +MDM4 ATM 2 +CHEK2 MDM4 1 +CHEK2 MDM2 1 +CDKN2A CDKN1A 1 +CDKN2A MDM4 1 +EP300 MDM2 1 +CDKN1A EP300 1 +CREBBP MDM2 1 +CDKN1A MDM2 1 +CDKN2A BCL2L1 1 +BCL2L1 MDM2 2 +CDKN2A ATM 1 +CDKN1A MDM4 1 +CDKN1A CHEK2 1 +CDKN1A ATM 2 +CDKN1A CREBBP 1 +CDKN1A BCL2L1 1 +CDKN2A CHEK2 1 +ATM EP300 1 +TP53BP2 BCL2L1 3 +CDKN2A EP300 3 +BCL2L1 ATM 3 +MDM4 EP300 1 +ATM CREBBP 1 +CHEK2 EP300 1 +TP53BP2 MDM2 1 +CHEK2 BCL2L1 1 +CDKN2A CREBBP 1 +TP53BP2 EP300 1 +BCL2L1 EP300 1 +MDM4 BCL2L1 1 diff --git a/www/Examples/TP53/string_interactions_groups_comma_duplicate.txt b/www/Examples/TP53/string_interactions_groups_comma_duplicate.txt new file mode 100644 index 0000000..1d41847 --- /dev/null +++ b/www/Examples/TP53/string_interactions_groups_comma_duplicate.txt @@ -0,0 +1,5 @@ +Group-1 BCL2L1,MDM4,MDM2,CHEK2 +Group-2 CDKN2A,ATM,TP53BP2,MDM2 +Group-3 CHEK2,MDM2 +Group-4 TP53,EP300 +Group-5 MDM4,MDM2 diff --git a/www/Figures/Banner.png b/www/Figures/Banner.png new file mode 100644 index 0000000000000000000000000000000000000000..6d5e4d4306beec8a2cd8c00191202848622b75f8 GIT binary patch literal 160700 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 {6L+qNa}yo)Tl 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 z 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 O(0KCnaj7yi`2PbMnBArT literal 0 HcmV?d00001 diff --git a/www/Figures/Convex_Hulls.PNG b/www/Figures/Convex_Hulls.PNG new file mode 100644 index 0000000000000000000000000000000000000000..c6fb6f498e0b976ffeb87aee5c3970a538398b25 GIT binary patch literal 152694 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�Pa}Jm9*!Aeyn;Nu@f! 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%0AkW zcVeXSgB*RAuqn$U=tDm8+0DI@@QBG6<*AbbEmI{=Xd0AT4H;UVn4p4(p>_*=ClK&~Ln{ zldAOg?``ROv^erKPok{*Mj2_cf%L1UZ z&7j^A1n~B}X8^TYF3|9ha`Z3^k~PS1XF0MxN{Sr$y^(6&+wc|v3;3K9gU zKH@yMMlwFqO-eNU+q6V@n1h$4eU$kiIUI!1e-B^d&-3%;G;Mk1tE&)$YkSLj7=Ycm zdo0s{Q7ZTlfq@x;gF#$_sGf*Pz?T>|J=sVi zVjs|S`sVdEesPNw_uo$r%*8+y?ee{t(2cVoCL{s$H}d)%`v0Fi8AkdRTgfOQQ%~*? zZo-Wp$om}N;97yVDY*4dBZNdxtlw;fb8u^T?(Qz&tOcN69F#wM)@|L&1bdB9Ylz|N;8sRgOy!M%)}xrx+Wy!tQ3 z74Ab~?1t5rSlrm$8(B4FSsp`T8<4fEnsnI*zW__8G>s$|&O_xyOiry?&2pb;QBhG` z?6q^Bvp?;0RODqif!=>JL!9yRwEuXm%_hF;yTz^~ur;lOQ66)9YSc15-RWjPNM8K_ zDO-I*p>#GBQcA_gR0keuD|00Nk(;Zr7k87P+~m`R?fG2mWs z*Bn?b5X;ugB@P{=t<8IhWj=5@qZ8b0+V&}FEl2<(!x%g%dSKhx&eqWak9rts_Ehnj zZ^`;;9W9#!j>uS7X;>4w#>-vJGpzUtXL9+9*3?>ucRF0akWHL|^QrsM0vcUiu-2lc zp2w0}&5uN+@PVD>0W>sQMQKSgEomVji?oTgw*K?&(5~fl9{qOd)Cg=W9I*etx~!dKnUAP^;Y>t{`XcBP6ItO3ai@jc8pr{=(|zK0k${-ffliEl1KfeFsxUD02KKY;)*%BF}CN@Rz-PL!)u7jC~&P zvU_+wJHMR|nJ<|VZ9S4~JJJpFAxNhLegMgmbXS27MueP6I3k%^y`)I~aTlj(_(O!s znQ<=JrK_4zfi7lrkhaocluGrCe?Um0!nV{tjg* zv?9axqkOdSR1SUhO!e2DAdvgvnVb&ojrzQUha&>Lgjs%epDPoIb@L-XiZ|y^%^xR%G!n)=yPgS-T@9x5*#SZwIdL6@{s$N25378;7OdLMhlmjFG%R3n* z2pk90Nic9(3Wpcg2-FG3aJ=^V?u9yoiv!2WF#ovroOCA5bLi-CLA>Kfi90B903=i; zOqZ=0a`o&n9h{(Eq$~QUUqTMuu>^AP)xm6%;ijH}jO%n^&oe`m-PBRI*Ht^06C}}b zm>U|v>6rQ70;yL}03=g#0=UnSD%)U!oyK#jq(?jY(C?3PTLg-Uo)b5vm;A-q>G0~J zOFo5vpM>P2eZOwo#y8hb>Isg&c(S706aL9;+?|*{oiov$k_c+o^(_1ZP*_A$+xW(#C9bRTNahRk0a$zEbups?7muHg1BEyM}>b z9-bl^jt|xl(dYh$mq=scfFN{Ts_`WRP-GQPDEJsMqzBwQfv-Y6?OlLgf zYgykDQeUK_+J1UC^TUvp^>n`RcXF{4==_`uZBx%*>SI+ixwXuCXbOUEw)f;7L~J{$ zYgwO8n1goI`x8%Ip5EPYZ~4Lnkp++-=)q21CoeCN$^?|^JuMWmDxUaI^!r1Gz%DyfU5`_aJA2mIQE zA+xX*4g4)FDS|9YjtpVKEuEr>N z^Wy{%R-NykZu)Po(yHQ5>-T5;f^#3p*ozW|Q`tF;`zZ*(I_C2yjB_OyWfZV9teCFk z#tF^z7Lch2q#dW9ocrw`zfYBZ7`DlDb_Yq^{C$2J{=|!Lua-sC=+|J%x<_CpvhO?! z4(^QDtk^$@JqX$9Y}Ka5akBqIJUU;4HIY)8)>(rxvnD5PHg++iJF0-#*I;| zSjP6}kA0e3(Luzp-AxF_V0LR7&P)8q^Tei9NreO>+^W9~GmgIHa9-W$V;g(4y{?dm zPxWH6+PsD5#Cec9kG-`!4@u0Y!x-S}`zyqmC?bGYM^E_eHZ$_-ry0#P-$HC-;+X-3 z{g1eGcoh8aEa;TEvrniiJRF-0{*`{9W;`Uqt5K8KO7b5({Je2kx#Wo^(V6W|h0OC$ z2-iW)W^~NecZmAO)p_E<@kr|p_Wgrt;1hT21Rk;EV=eBQA>4w#q8sv1IF+3TxfA!- z?r14BYGSN$G;v18F53;IpN&@B74u_lSb%Tl+4Rtrq z<@gk-a3TpwQC(BreC=F?laa=|d?gxNn}f>d$W!BiIveZWgYSIxEus{G40J zJ9sx6`RWenPZ_oNR-5?O2vnD~cf0OG>X(K3D#>j~(vDf4~76^Qm-@iE7dCuBSNlJ$4SgU_@rGm$AbUiJ0so}b@0 zie0)k-+T7Nd>&;y&t`h{yoh3Z)$cqaP)c}AN7KFNfA28_Hj*pNG)UJi`cELa54mcw}OIMuw$6f z_eF2b$;WH7N}?!9o#C_Ja=F4!dVN`FXCG(@z(21@#5|6aUR3+V;djb79^h@Tnk@hN zc%mEx%CU9j9jVXfB8mle`VTSpr#<>dFR=3vURDYqXTNa|1=S5MqRL(hM08OAi^ETr z0q7hA^PNiPYVM{6SdozH;g*BibV;kflWl1srFoJz6@`S^d)F?FHpz5a-C+33{Kt48 zWx*J6NxJL3$DG*`!)tbA#C(0{4~_{}ZENFJc*?C~V2OWJxEPUhVa>w+NleXDC`|qr zJB`}7W@OwrLq7}ez|)OHzyK0h;75M>OyMIUwOFO9duVfGJP*YET^Sr8?(UJ&i8#UU zI=z$xm!*|css)K{$~U5nC78_uuAS4G4oH_GIV$sB+Nd!a+tCKKC5>8ly?B!Ee!r>r zJ{X%{|EBD95iarSg)Acs5p8Mp*CT(Ph1>#vJ48-u7Efp*c9RAmI{aCANb1o|z!{%= zmsMexoEmETq?2Io+%^64?-c6aq}?F2+%rPpont!$j-qj$t;G1=XPVtbwSCy9rjW;W zN9wtC)r{5hwegAz^o}2ERmL7gA5{_BeW0aW1N_LIuw1$wGiw4ewZcqLk6F4tHtk@JP% z|Csv9u&BE)S|tP|hoPGRLAtwj=x!uLx^XD!kQ_QiI)`qgQvvB522i?FK)M9(@cy5B zpZkgV$T`1r_Fj9fwfCu)upsj(X-ucBU(RjkGLjYP!31K%)c`w1kqx#4kqkbeYqH*e zcU^3TXzY-c>}JmOkO!ytvAGxnG8s%O{>?@23`c&}^;__&Z+Z@jKBA)3^Fr7$1v4^} z1(nX(=TBa>9;nZQ$`Tj5F&E(l?pbG;R}zPA3!u|*1Ipc_=UFCzI=_$5g;N}@j#4}R zmThAPEx?VF`LiC+TuftC4!Ca_@09n`ceelEcV^1b_O#L$u5Uc^>r%sGOEy=ud_Jd8 zfUk0$UMZNC%F?}?#Ex5RGke=GSWkzZqW28UI?%3oaiz_-Sbw_oSn43^U!jrx;t?Sv z8@7O90iPLji87Kiq`g18mW0;QO%hOii4`?b=1NiT4@X_<0EGL>c1Fxf!0POHxvVK|ww$`_+^*kNb6Q}L2iX+%6NG#Jkt~wA~RUC zWJw$H0`1wG5Zia(eoNl0?`W9vX9>1)B7&VHvnx=-9WY^F^UdJvD$W+>+Dv)6ehR0v z@7pd zu{1`3r-pB-A*0%!F9crk`$^Ck{uS%_oJ6E#e_A>w=GA&$nvHQtey#HEudiGSJ$E}- z3HePS(0Q?av3YR>d6)YOfBbiu6K3UJYO@1gf@t}Liko7g8tmMkjRP3vWho>E2$1uw zdDQ6$fiz`#%h>voeG3x{!NgGwj36pWpyw!CsX$>)0+diw7QWGP^mfr9HBnN@JyfR` z9peq4aPW*7olsL=iN(BFl&&YN0#pD?U(lCzp#6+_v{;)W41UQ(3ybV0)I80LAb;ce zcRonc*uab1D9)Je^;w#rNPgt*$fvs)W-1{GG`pM!W#$f3%8X)j-?^I(t%Daxltd4h z9;A@6e;#O<=CSfF#ly~@XE6I9eW3^`)1?WbPWiNiy$y{m-9zylGaS9J<3H2TO+b5)TXz?N6D4Hsr zM=RLz@yVA{B`AXZF=LZj#;Ru#3-O`eT?vCA`$v&{_8N#WMJ=j!%%w+=uANK#^*B^( zT~4vDstt!`7ohK{6h1q(=4bH!oS6bTj;w&i34XqM^(hJXaSJQX7Gly$+Hy<~MCSY< z)O98@2SN}1MPD$|SOb-2#|QO6?Qq-!_P~5^VrH?-p3Cl23Ks6NL{F05#zEwM9}sozneIShk%c=A0!lDMFIU`0NGFRHRcGV6+NP zw3q$FP;{;B-6^@Y1u!#$J3KG@xuzg^0GD}JOZnEFeh~s-=gS+Eac9(^g;3Hg0w_7Mn8W8jS0u-!rPh%c!+kkN;(oGDiqJgn-N@P{6 zu#FT(j^r6($WP)$*VEXK>5MgFG!3sZKbhB!*(O^#Ie0P{v<&V*s+)~u7aa(VJ z8UtQ2y`1xJHLbx41kQ+gy^_4bL8+>0_src-Waq+B(B+}2%89jt*_zkCWlT_Dy+YrX zSQglPpZD7j-?I|)roNgZ7<)>2o_&WL4t6|m&5K9VJkOUmXK0W-+y)P6uE#0NDa!imGPhhH+6 zMq2m3T&ES%LVH#9+@7$S9SEVOZI({eLp$oA;+mpi?!^m)Rh zAQfo03-FcQAsS&nJ*J@6D)gG?CRV;Lh=M6b&~~0b6o6r$AWDiMPpV62B&M6n6v$?AVsS(w)y6L6 z(8@ErRmwb8+_js~gt0Tx_X|P~N1-(S&egB2DWDX`G5TEHUamFpmo+=?Lhsu0+UGt3 z=GB&u_9*ZuMV4w6%Xw~`UZ@ljDKPwy)|irahzA-W2+e|cJ}EaLTSimHm4o4~@1-dw zPL=QX@~3R|qyw^g>x1~Sfk@sV>w2v* zGc^u9a_V7nPtfIJj}F88a1fc)KW+)_J8M8btGWi@o!M!&I|t(=fd%YfEmYBeW_L`+ zqs7RZQUA{0M3Dm?>8C0~6pWaVx>7Ey{rqC*OeL2{b&j!Z2rb7=B(V99Pnm)A=7*2! z77+V_b##}tp?6Shb070;t0NY@I! z`aYW)M}4W{B1x9b#1_BZ=SS;y1JHx=b8(Q-3q49VNfMoOeH(7j3vzJIq!RORS6#a7 zAVI0?xv5@7$0)C6@#p zcGHp9@IHYfJ9SGT{);!<)2Rz*S%Z$DiD-D&DU8=SA`>T-uiudiaS`Fjp73yRS~O5D zzE>}x0heRGND}4<7-y42<`)Y*3YO zQlVxfLa>)xr*5B)2?Q{xCb_+}g>cjs(l)Z> z9evS_bc7s2dHsc6F&tflX7NppL81fDn6Dhf=?mm_oaz_!`CCj&>o#(}Q_%86Do7lL zz6uU+STyxeP3`C772q`jKtEi$7K|yEZFX&SF>sJ52kak1sJGT+WMxSqBRMUac`WfC z@sukNz2RGmBFLEZIyNPhcxK3&S&nBp%^V&N&u2c zbm_O2jaImvbfn;=(N+zl9R*Her@R^|NCW!-4rak%iOMn9%3+L>4{<7h6B7$KMsx)P zQl=GDyZdy#;W%tGJtQGA>&m)Lr?~#@!7uGPzuvGRJemj z&db-K^S=&f*k+X||B%uPEmF&OH+sWe12nqQ5?DeOH!oaYfpE_8-$Kpsf8I%i3 zKBzWZA}tMFhIw<(H3vdd8XC%rv1ie!j)l}-uj&~9Lh!&p^nrYcEXI1hs52%dIdGV0 zZ&Yy!poo$9;;xJwA4b-njKgdI;05OpxbCWHIVd{CkV4H1Dxn1id2#Upwu|}`=W0_5 zB<8NZ=voG4l&|1&5|leXJ%3y&-9nOp`bdre=1M5Cbys*4cbCRL9wkk|U)GDv63KjO zUV23K_uNb5wf&|}D*}MAe9C`~>sPj9;U|p$DQuWb{+L86Z}-(shVc1NS(6GPOTiRl z+b_26r}kL+0i-J1Wa!Rt=r0g!KN@nls=t1dyIb-wSHI1mXENVRTb8IOQW{_`#kELM z1@8RCa&Zb)m>#frQ-$79Jhk=1Q@w5Jn?JYRPzoh^5w;mf9Je@Zk*Kw6OO{IHMO>II z(_N_=few`T$Re*lJ|OT!$>ddmtWJ$MkN`O|G>O?YjC@3l0e%#{RCsht?+7854bq5+ z_#P=P*OlyG7Y1L!%8M;=^~hvrh>{nJIlV1H77=6ARRD$0n`d?3ucCKBr~Mz%=m!EU zWNDwN3{IZUd&&0owtmrMjJ3H%q)#IQvI6^4-opLd@?-5N8cTBT8W(;y}p(?}yg>wNjso3-eZJ=aS$#~$4LXe^wvnBGMRjU2OZsjHlrB|?og zWrlsY)+qtwIqI3QSOq1>Je%Zh(^&B(wOTHeAj5b7wMm|+rs0<395*=98ZmL9npols zvz=!ht7VW`CCCP$M0|gP18TeBBv4u`BwL~*QoI7wB~$!zNmQ5Bt*mwKEF-@SLb;kd zEzmKV*tGYjtCYy8D9g_JShu(!lRYY|P>H7d>$?M`U zKaG+v9e1)8H^p1hdq_&8dZlH+-Fqv0qG)8(pY@kP_%Gk95!$VfHJ!}Fb&E-sy@ERsnZPC%nZ(e zk9f%bnre;>2q6wjG3_G*-L7u=4UKc%rtS+RUTI7nf#mw^||C<>n zhU38Le_fEf0!8)MuDWsPMf$1#9S=Nj+Kc>~fV$L3+t@9K#x(Zq9^Y|g$Bm1G_eSCI z5q2}r!s%8CPv&M#O_z2x!~*iKMYG9tv!;Pq9HE{pl28HQ;`G0um+jPEfmP0ER4@T4AMmy+KsrlvKbhW;jQqD=YeMcVVM24=Bc};ErZ)FBs7DG-bV)Jo#CWO*hLq9xso{0i!~W< zh}4u1+B6WY=m{iv{cq#8f0?SD4?#J$=DvCNR0Wi{oXTz-skz@+ou?Y_iQCoq&3$U| zo2mS$v(~>WauDjL)g6Lk`n4?h@L>BMX4cHY`(aPOzk6nN3*NHhe)G3|_9~2WFJelAbc3-UNJyXWp zu{CX4X**bk$Q56@S5)#~%+(#Dt_7t0E+|QcT)kpQw=h+iPDY)p7;oq!}_DNkI)9^(OZGEo; zAQBN@o3;MMN^IS^la;h~z^7X(a44p}-$0{P4xw!M6Yi(eT!mxcs+)0T`dZ38y>ww; z+@(3@SHhO0n2yi5q_=6y$#0U7R3%d8m)*zQOxA1t-_g(R%FzV=%dZ%lkN43zqBKn<{`J)!+M z)X*&EjS1pU=kNK5ntJnLRLv-bvq5*1FA5AEiRxD>dOV@&@>b}x`4u zRYR*|7W^*t>iej|R^11@|0g`^Fo-LD6b`X9awK`ofgErB6bE(5jd;fjecojm{V>?Hc8H9C7`e$YZ13caKEkU%ptMK;EaPfo>B)fy+o15oLet}c{r8gXm+>C3BY`)dt6aqW4 z^jfUAFB=24%r&bymOD$yvCM9bB_MpGmTKKH+PB7u0m9}Xz&M+0t@3|$K_!Z?^AP15X zijp4@st%I`x*eR#Ef?vYaXJJ(3#8Y7JH_vT69@6rw*z7i~-| zEY-W0EjWkbUD7Jkw(>Y<3q=$;Fy_|-?dNd27Fyws$)Qa=!2nrtj9vx*=5$eS*BL94E`$w=7%KK zWkw8|Z)tW@URbjr@v`QIfpW+O;~V*<%?IT#-IDM7QqI+$l3v{to}R%Wxy??!H~H{I zpeKwncz?s^a5MP@wZOdGyro@_Q^OtAh2u&S6>NmSc?^R+{0yOW1qwT7G}U)M!= zGeG%*w9NbEHZ6<@-X0siU~uvk{Y{z=mlNGF_!f~Za}bh;3`uLOPEE#JKB z;pm`#RtPFf>J=m|6;XVgd433#r{xMoZB!^+LL(gUU|KQwa>hvO@&gv|GtoGk{iEcU z5}+Cd)iLBTDfRM+f$tCh#c)qhr>)nprWyPjXNq%NEEN++EfP~AhS6NLiXFT1I&kWh z4ww8UbOb!Vx9Sm)-oel=H}*VE^H2FvCzgp`s{*Cb zXe7zCfir=Emxf(~5-Ou8D_vP7nOf+7VJkf@AwB%6>5(|Hhu(dUP2Lc66=0{9w|EE3 zg;RXK9fbFB&y|!I?PNxhe~B}2%l^tdGoBNL+%|OzB!5ttu@)&pvbLgfIikVrQxHl2 zk#5#!RJ`27iGRA^Hk1PSh_kEZV0k;-uE&|YiAi-D1h8DDo1Y!Q5~J|=MqS{5)AV`u zK=K~irhRJJbqHP8~gss6uX=x}#DHNPKsQ`8`!3PpP8DI#Zx2QS2+ zhG9}LYjj%D5G-C>liS8;M19^Nvro1MA#*hH};IGm3zlmN63ESwQ*GDvGV%mCEs&BhGDs}#ZuMhRVEee zh>oeG&lrT_d1)OCr2?*2MUvs)eqagRE}z{0eZ;a5#8C3k-I{luaLWb6a&i!VN)=0; z2vD0NT8>(my@bY4J{`*^+ePW~(!~7S`LDolu;ck(R7^l89Jhk1hx4EgabeZM7b;}w z4M`}eK#P4cw+TPydT1yCM-T2vTc%FD2hiZw&8$Vn34cnMsad6dE@yD26f03I6f1eF z&IqaE%f8ki4SNmpNZiGrB4!$3i`!0dWK(DEn#-E3P^wD8SlBV(fkVUk`S^5q$CmUj zZUsS--G4IJRTl*dWeuRCbdK^Z2SKl;7xjd|^91s+VK_$Ye67Knq``jZ&7E2$;0rhi z$wNYwJ2yUge#A5A6~L5Gp{sAWcl4_~i^NPO9KHY9i&5|%Dw6sI{lZneZ+eI9?4{j16V(IRjB&{u3Y-<3>h10kk((+c{J> z0fwpWhN(u*d`Dmk3H|AR!ph+vafSiRI9_e>X`p@Sd;Hl4OlGDUL?_QsB_?dnpI1%AE(StbR!U7eEsV%|f|(6rqp^!2 z{AoVe5PPn>K}wOGn?=^{s;}9b&I`vb3hi2n%f#fzzuq`2t8*!mpopy>eRnqxWvu5( z)w*4+d0^VnG?dz9#iQX|4m1Q_ z5}b72DO7Ad1D`JihlyPzL-jeZ|<>{+a_;~Ag^GPYyPh9YAA#ssR-{EEzN_rrjQSQG$QO>s}&&Als z;e%Aby;CZ(x$Hr0&0yu_*7g}n7Eqf@Z=~etn#ahbz4^fEWHF&?EC6Sp3|*9mUy|4{vMd~=^(oT%H3=dF<0ZD|lJwKO z6Y-IFa+6dGM9g5Vhd^g_nSWUykIaTITFH!&B`S0smn=0JuY#@RJtbP->xN+xtpEnV zIu(x;-Ir+F!W^-W?vO?Xlzt#RVW$kF^Q^#T*W#GB*5aQCL zehBDAjW&?36mUnmJ3riyAAHIUCr{`?9K|b2jpD;bx}=>jgYrDrP$E6$(x#_!e$28S zS@NsE4h)h5FfKedz09I+_LS#;6&BKwU=v1b!u`V?wBA7{PrY#@W^)H;97GUUCmKXGmPHhs3BY{Vi8<(P6eGT% z!dB7cH-4z)oLe_g%fFQtG%e~~E1i;g$B@*V4RMfIxtg>A(HAJ%Gc81Vq9KK<-qQE~ zabB?R_b_fZvKB$Qu|>3+i{K!42&j5)U!1&F(v+GC;5rqmr#nE_Y%(hM!g=s(m%}M+ z8g6X&jqWwawzUY)`d8eN)8W`8T{Nac#4}COh#R!BFPK@M9o~jBRxHA3-xAulEK}t$ zWoFe{1yjT$TD{&FzSjGfsG20AGM=cTriHG!1g>0v7HK86qtF*7DgfsP)KM>WBjneH zhkTQpFa(xT8s3J|?D>PWZ-t)+**XYIyj{X+jf1@f{o@XkfkCPWe2Pps<4AYLb>-b= zVo+qr)S=>pOQ6Fq^Ka4K2}89(^;~#Lnr_4(tt@QF64Y5vnJb348dZ+l?P_PRu>nMm z^m=X!$`X&v$BL02k=PG&t_U^S!X!@V^7uc8C6rhbB=(2khjw5TWHzkasKuOSyLDcF zjbIc9dwE*6{pmK&131LULrYJ%Y7}=m_N%cka=_6ykJ(@^Ve_ZTDh`=L6rQDlfgB&| zM;P(xk*#eS^XxbZ(cUt4TWGrS%)4#XgSwh?fhJu|q|#ooi?>&=mkgK(k&V8Qy!N|Z zxe7F(+Ge25lAiGACiVfWKF1p~Yw516lvk!|e-)92>Z%LFK#--N77!?k_JY$NoJ+vm zA|K~AAl(=BnwVqUKx!0#-s3}%QSF#~zXKIU9tp{ng_)1R%c((=8Y(|K~8Rg#g>e2Jgp*zBOG2hJgk9pY zEPpVTC@8d)q%24PYtR29uKM(l^E3Wxc$CxoIVn zMg0jY@R@g|567h5Q8}al&^4*z(wjH@cFdLgy-b_UG_n-X(%t*ppWbw$hBx6TLX2T& zpmFtqu3Y!au8D_qIfte`jr3$g&T-fsIiPvZy&8rQecpU51CBeGup#J#9{xDGT5*$A zNI1E3Zlp63<;0bk%zvLcD1vYI!Urp)YzY(4>fE1EEw*r zso_(JxsS>~gGPr3=tahQIrAqPnvjag4gB3}KJIr|>@cw8p%Z1f|~#0t=?O>*=qqj+xn=<^WTzM8r^V2XYTG3jl4y zZX0{gVCqgd$Cw`$IuASnDpf%4hWPh}Qa`=k16NcFN2Zn0JQ%wvtM88@3Y z!^bHtw3{x#>o3oh1K`fBlEPdd>5cStN-k*i$+Pek?!VM7>OjCxvWQd?W9@(izlne2 zW%y3};N#}xZ#pn<76fL!CWTde&I^-7nTDLhI+H%ryPs;4WB9vQ0>7zA!}T0#{<9HwB z+$bF!8-<8hTKkR03N8y<;)+h}To?Ql;Opz^PPrMxWa1GiO{)^orSYKtfNHgq@Ztj4 zvNZzG-XbxZoy0;LJCv|}hBAMZn6i_>&G81ap7v76_HCEk1*OW>o?(Z;XtCT z-pSqUIfj@3L+~Mu05}M0VD{5=3NtFI8}UZq`g_CYQquMOn=F;a@)8j@D{b~Np}Rjj zI8|7zxb|1j53Uj;%4O`haNy&jlXopSTCnr?qK713s9jecSbvFSc7k6gFTFc;jOXn0``>Q>Nu*x+rlbF0TLq&@x;Y zs=2+t`zMs*dW6ABi$paeAfS5E0CZ>^okCYmT7Fqc(T`8u`Zw7?MsN`8%bw&EaDgrr z!<*VR`l=*;MUV~bv+D!#bC=jbpNS|Y&^Sy;V zOn^w3;S|f?bN}^h1~U|jKM?eqUIHJWK>>5>I;y7Cj2bqUq9T3#B_{i@Ki*#1zjN{; zUuiG&1AxoGtJFy@kOKRF z^u(Pff|T4-5t?1f#An1r-k5!_BHmnS3p++oj6WP12V?;g%rdbHqL}*sUZlg#76t93 ztj|yj&tMX~?yBYP**>eEw@ga@d_@W*8Sh2xwKdvQmOURk-@B;|?Q*n=wy9zHS1%w! zc+KDHA^d$qHhKxl4(iM0t)G~^sHfx@gYf}0X8BY{o$dsbi7GPPUc9DbgwlaEDlTiCHVASLp{xz;u#|-%VNcUsCh* zh&(n-?l9d8b62$TOx9T$_nG1LQ%S-HZ zPx3zHs>_+lBaou(xS6(HR@QI<;IM_14Lrn5AAT9l{5;YcY=fb~WXE2Ahlwr2u6Iy|<*GO(l>6F0pAW)>OZUaICjbJaD zicR7GYV2cib`%E0i6xH7v3pF{Z}q-5F_V@uUjwKHmQ>+|OlW$!<7c+mv;I&tw-gJ@NR zINfl+9!iwwP{+-)ebplY8$`kgd8Sjbk8(D}W}p6i z=Se;{yv0fK8NO*W-JRap_A47;pl<%bpL?kl%@n6ZS%)d~BKXe}CrmNtv#Vr>@Xv@@ zA~B(>&(?F!?w2SYLCVUSbCFaMdfTGU5B2LDo=jCwy&=7?iQ$)}RyX!<+Wr+N*Bf>M z!^-T^7`r9ebu+`XGtWzZL3q_`P}L&WxD(|k>5LUJdxb+}z||AO>;hBQ=6-GSx6@Ra zH1<>WE6|<}Nq$vX)<)yVXY0_Ew{fjwD7nQ%pnhndeX_f!8tkiU4YVH?`$yCZc9EKPoapRlWB9IA=e5)!S0yWgQ(na=c7uQO>REXH5m}KLmP=PBJ_No$Y z;8bTeQ`Ob&fI7E>S*4NKwm8^&H#|tx#N1o`n?qClHwJT-#6B!dE|4>oP)`yddVzVb z02T-Tkl`DCwr;Ba9l{Z*QJ3XU_pEm!)0V`48`@CkTsbuY4&J3KOJ2TTJ(>E2)3^}N z6r)6Gh1D!2d1pgx6VohN#pS=9J#((GKbLV~nzxsDDCgXn&v5kYnVW?oSVm{Et?37w z^9rdQRCrXm%XwM-c2tTo*^8m`+eT7QmM@qEfs6#|pr?-u#j;O@>@w_!`O+m8!uM0l zQSD0%M^EgkC|PVy>`P4mP{G80g)uFDVYvcF@D`JprgkciVqLrY96TD)g31S^;QHpY z$jEd4eLjbRm+8JT;x7Zop(a#h9Gj2iw)(!Gnn57I;IH;ZpZ^bf`VMX$#ZNUZ7O+|T zWYSqXQ8w*qd7D2&i6VCj#G{&p@h1!Qx={7S9FAzbt>JPD`UrU~t#}izgpH#!n7m-d z-gMx`A-f^)ufGc?qFr_w--*Ohv6;A4GfdNtVOD1d-jB3DY%b`9JPBX;nEdt&T@HLI zqH4d&P`Li_P06h^-oRaWrqnY@pAI+Cf9oeNpia{jU*WRM;juNz>({!4_N@*NblDNc z*@0CZ(lj$e45tNLweu{8LRNjCcU#~5wfL)e^$5Nr67Gj1L5_c1SYg#T@)P-LeN+5Y z-^f4#luN!~@w$qV@d|bqGJNiX58cR8OM7bB`LlXq2v`D8OZJsOx3|)w4QSabh*mV6 zg!I^LeD#_Br)3jm+U2%!xA(j;>7$5LsfURZskJhtkl`qHo7Hdl;{C`SZt+<Qf+9exwW)l7umjxfC%X26Cw>-ZKk&}*2OYCwI zLv|J!!>go0!)Ch(L})05@I+SVmV`Bx?%FKUPLc+4_VZ*A)a&dnK=P~rv8T-`B_LPJ z`at|RKdDh@rM0TyQGrDujL-pGkT(mICa+|K&U5a!DY?lof(tdP(%kDk9 z7x`rr*(YdNWg$?R(BW}H)RZByJ=xT%N8Yr5-~0wz6Y}U$f`=5v^8zBfJ|PXjGdZr% z_~~YBek($upU8GIwUiqjOZv97QP20OY@K>LcDRT^jxaSeaPIY2f$LEPW^09kgTtnu zf(x9(sl{#~YP;yLyVE=|lG{3~iW}^yL2&4CB6PFkKEHo^0oi$l{Tx&Y8wCwZ-HB+o z>Cx@$X(A(qs?UV0xl>FWSLWsHZS&tx&oD*cjG6cbj0}rSpk{!`ZROZkrf>E96pl}) zh3dZz;fDPI$kLsLL3^xt_Utb*Q$L{8@4V^i5aLz+*+<_z@t4MaM)gjX{=oM(K(>dG zIzlnjV1EmPlShqS^_;wC^RDfU<&2k?rhdy$mc+m>pcKYUgElv3<2v zVnw22;43XdMg2YvbYKz^<_-dp>)fQw$+S&2{<@y#6V6os*{gp72Bm3 zTs*AkUSO^chqel0qrkl*P0`sk2Q#WW(coa76B+l9qS-s4hH-KrF|Hwa@ezWzDPw1P z3mJ*t;?=3KzUFvtIC`dxw3=y7h`18qB3~vgJ~#1N3sBnFt!kYQYUh_9{QF{YshCD9 zf8Z4Pt3zFf^YmLHs^-H{DNby?93Si{U;fuHZ>IB-$q5Ri0+x;4y1ofllVh82t}M{_ z7&a!!5>2M(<=<*S}mhmuf z>m5dK+Nl1i^IFP>oaf!-k4(Xo9D#V7lNCcq&zAH#s8$D%Hyt$zH1s)pki zL!QZX)%Z%e0^Yoq7BXS*yK;w^Pv$Oz#V8U?aaGGY#>}WQde~p}H7aojZgNOkeS-p= z8UjnD1U9`CsVS#4V%$HO4(bc3fKn>uGniKZR}R;`;Z#>X$oU+iDunMUv7Q_Mo^r9P z_7msS{%NiHaP&m!5d3#I2+KZ$s(j6p9@q04lmxP?UzaR}Uib3swW$}73jAzN=A98o zvbPaekpx<2sgf)d?;?pMLy|2Y1s?3HkmZzRm6$X9tSdKTFVwv4Wt)o;iVrTpzl8?G z%N?{fA0Q;6y-am9n@NpO&~F&>1L4Bi%D(#AK{7_GzIzhjWen%~s{iD&W&x8gwB6l( z%jMhL`cXDNQTz37yi|no;>6xQG3BBvaanBEWTO}0#INxAm6B2gZdYKnkmlTR@oizw zLLn9Ah1@q3d%_R`fv3{-sjaBDlvm}}w+eG6&@4>-Ub{ik>csNjY{K_zOJko{f#>}% zY0XGf*{yeo9dgCyU#$|6V}scv^}2SzL{q~VeYr-JxHFNLIK~J10}62Ix|@>29u!>2k;micG=G25DQP+N;=+S0b29vyJQ54I(7(bZrk7P+G%-yy{C#G^A*^uDo;Nl@ zsWJfx7I;gUr!B7ti(#7g{Kl#;A0b^RnDl_`Wxrs0d3y-MA+|TR0ks6~<+5HBTemn6 zPI`1_C9qVHwjJ!CX_uk5}(6%pWs6Lf9S9eovHV{yr(Z% zkp=lwaNGX6k72&wS}5V0kX?DzzwkUA@9K|Hvw^Zn>s+ZN*?*@b-B`9V8#PE}8IF;@ z+S$^D!qPF60zZTyy5g^;-|tPE?n$kZFFixcB2j^5GG@D*6RR*gc&h5|F4-G0}h zV~$)h$hS)O1zaBh1&cHbCqDkzb+01*_vG8}0@y=6<{3v_uQ-c&*H)y8Y5xTTWKk=r z7g>D|N;2%(Cv-vJ*WW)sIP(bn(>&9`UNs}O6IYWFvinpp;~=e3I1J8cr%_h#wBkA> z#8s!e=ef$?4=AdLa8G#IfHP*JbcMjzrSgSR?-(=Hw#uM?Y9~v=8MZzjFao}kW|N6~ z98B@^^q&w+-StoM$NuBbN@PKb1Bz@ycC>XxexE1pdN^;&?P!tW^Wo<$D0V0%N_3YQ zJ44cJ?E%q~zweNI)@)Iay!JdpZW|)%xQNWfYyoz&f%*LVJgQ;FOP?5E8`s&lzXf~e z6hhQCtOkeMZ$B;o4&1%30~jzg8Tu#zm5O5ZR_#C==0#6=Tw`voE~U^6^=jtCMr30E zg6>7#rF(pWfv<-``I8NPfg&OJ-Fu)nJXS;vjk)P=>8nVcm{i`*w2NKbxj}jfD4J+C zDysF4iRAvXEWfp%bjQgH?-pE|Su$cF3a@!TzUVu2ZZ#M@U zgYCA_LEfqL2DSO$L>kkn~z`B7Nn2Njv}-4>3mtEP3~g;D$&^mS1(uDgdQ z$Pg9=$RF`15hUX1FYR!aF?QilZq|SmxLFE?Sh#2UXe>WAg~b>gw|9>MovXsxzvfqH z!vY3e;GZ@{n`2SzBtPT>eUq)ux2fzVy*sMk>fnjp(YC1|ww6CBQN9%-R`@3J{P%9C zhsR<_*=O_L9+IX^PM$qBIqH%$%9b2D3{X0zBt?71L?IBQD7_~Ioh1j{X{&bB8gcoK zI;9C474DV#G~UPav8~%?8W_Lz`*eDp%C4Jn;6AhJDD!;W;RsCIXn$c-D|wXne6RCm z^Q2??K~wurr`&rT&x|LRzNQFLYYNxoNC=oC)7VhlVgnuTR&qdf`@kQ}40-u+O+?^B(5qv`86k&s9l@g7k=3g5PNc89cZAErxxk3G$*eROWX|L`F?;^g zOS+2m4Nl?L+iBiL5s{Twn%33K&Lz=!+eqgQV3*#x)9dp!&PNOxS}{;0(y7uYWfvv!8Lj~JvB1ikkc8v>#)(#>YkoBRgM143)%BP zp0Hq~cUNaco^1A>g>liAP_-{^E1UUnW)4}?%1!8c!)9E0&FEPFI)_X8vIs`G}{UtpB3KUi6&@1lh_IpR4c=7X4~$ z&^!LU;}(|oZ7I)G;H>ID2VU7E=5lmNZN`S>@mullratS$xJ^ zdci!KA(lTTfK7{B)U@?ZM2+M>+DQn3Q$<`VZCDj+)%LCBN>PSGEb{c5A;kYn-JcZr zvR1*U1rdr|0AAzQ8|YJLRH%T6v7PHppA?<`a@TW1q|1qyQ8$VKFS|_;WU!QK^@TkW zFD~po8ezpvMqcf8&f+jTJVW#{x+S}V;f~(Hvw#P-AdpQt**`mlrmTkR@6`H!`@kVp z-dW5Q!s$d3Zr?J@8!HpD5gb*>&={~NKOy2WCQyi%K;zutn|I@z1azpI)lO1t-7&v- z$qIMsrpnbk9Y!k3UdB)6H@R5psM(}mk@=mNHX$Et6J<8U*2%Lvx&0MB=cG<{7NH}S zbTSRPMQFKfFeSrI!>aV&6nH#2e5?jXG1*hDxP9moasUmBUAox#j$*bV`6)KDw4`TG z2t^5;!rvm|aT?U^Zj?@`olO}Rk0=2=cR(NZbyd<4g-8)miS*~AdO3G?3V+7#cc zJZ61I@2@IeYoo!nq~(tdXdgt1Uv=QEST{@|RcB;RSpvBlg3kQ&EngS2q2dP$_y@z{ ze`ThnC&KqL+;DnVQBTt*DmQbk)LA^M&j&0L59Qe75%c3lx}__8Ps|*~f5+PeBJj^e zuQ-YfZ2V3$FDmFWX6heD&;9CaIXVayxJ4i<=UqKx-?FkdD+v!13x|L8^|Ay~c2s{4 z=?N;G+v7!hulvIj1sK;=@$a+)$QVeSP_A06_%#MS^cim1fy#;E&Q=}e7smPBE?)J0 zwTrUMb)Mu{AXZ=5wfFhznW|1_|a93OT_A4@$z)H#|(b5OW0Ne%4CzT$(mcfw$2RB_w zujp${ndjxsYx#GVWQiguI*=X3Jah88;mJa8oyY=?<0AVv(;VpfSy2Qce=P~+e0ddX zgJJn0#(#;>4Cl8Fo$Ahuq8y+T>MYv-A@3`{qI{!vRRjb?Km-)&8XBd$yHgsZySo)> zB!-k$x{>Y>kPaET25HHGp(N)#gTHs3_a8W)&RWk0m$P_c-}k-uwd>mXKIMpRfpOArb2RMyo`HHH<*tT zJNNPz1{aqpCt)SyRKvs+vEN+|VTuExI$mFsnHgloW9QRiZx)`}a|oxxr-iq%;aek5 z%63f;jt#gVU$bM9#;9lES|jh!gu|0>+(C*WWEqr7+m9`d`fBWk$Tq)Dct&5&!_On0 zUOKxMV{nV7?TuYXBif%u`!mYo6-I2wa|I4!XroL`pBb#O`49wE77*EDJ+PHRBBFj| z1-Xf!`Y!^G3-dA|Vf_7%b}0NMmGY-3Ke{Ee4h{r~a;$s1xbA)(HwOthThg3?H=FRJ zQ67dgAsa8AF5)7RxGV81)2BvVNcPcx5La1KFBb80&?x>vff5lP67(jPK$SvS%q^f&19uKYAJw&~a)H;et0T{*K2 zKiwcI?LyeID7MzE@lj;`iw_c$fN@nNq}%cE4`ZWiH(cev>CI~ss#qf_1(#9EFiT?X z+5D+utB3S^CO6{R6BSYfKhH}4{xq@Ux-adY=KwUkB}%=BPts6-Amh~cmnIP3NBs%V zMKg|RR%x=v!XHzSOG;GRS@^$t(IAEB+yA?~PQPxWBSclzzfe{vNkNJmrZ79NE6akH~oNbIc_KF<+__Vm%(SD^Uprcl4;#z3CqK&c4M8T=RWb&3%tLb8NeT^8hJo__O9 zd%*e=Fz^G{-Y@e5Srgq?HSyg|YvJX9v=xjVK?f?b?7kr{iM@xre;cw#6HyPZ6qm9q zxIRkoJYMF)hu0RqGS4wft zB_cEEtLu*C)X;>?-cI(n2yLw;lDF5QO+IQBPeJdkZMtd#QppIFo{&7IHvLqr)zCw>x?t7cH%ic<9JLOMdH_5Be}p05A?;_{Hf{*;|9~I=n6uVbMTkPq~%M z5C_+nX1RHsjP^d2!|6qIX804G7E-6D{!Z-z4p#&<(j>_8e)-G6_j8wI^0}`g-j9+I znzJPQ$K(7DWf>{gzSbb)bW**QCzRl@SA$j}MP=SmGt}7OGQ9*74c=)oxQ4kfQV&D6 zmIGG4O#D<|?xzOnsKGM~_2H&q*{G;+!Tq6T3g)fEkM{^RGmqKfgZvMt$F z!Q#P#!Z{L8-^^E7t8m0=XMPcDB5fvq?kE|E%X|8y$B>;w{X%a9W4d?Zl#k4wKe_DM zECcAU1z4=G>dwTpDAeZw!)c^niPH{4t2`T?uIp~%l#D|Y5Bu|)j`3xr>ZgGV1@q@( zS69C@ZQjlnsqydrE%l9!!_56UWz+ZCKwd7f_e*|5gbp&9kL;d%O1-M$jNdq z-xZ%SO7+g+P~ny#0IpLt@T7^_y8S&%KB{c*^x%UvD5 zD9tmy*Q!?XmDDS=TU5N74Qbnnn{v$wyECo(K$CN#6--l@KmAE&lNtr-vKN7q_3ax+ z1yxVY#GOc_VroLZc;373*Ww+8*>6`t6|qq34QA>Ny*2@NOTDm$>&nnUIcpAGaAuV4wdsL0uXye?|unLfu;#orF~a#!=MqukiXUsMe8C4qR^>gtY7b~`9}&Ci~`OJ)Ag$@xSLYEbcl<8ZwJI63J)=DahjYbGrbiXeS}r$U{B>+Lv`WjPe3zE)zthVFS80$Zr8JpHrj9-Eq-tn7?ZJ(+A?81+bG^M zYtv0hqMr2p8Ps}@XYTz+JrpXGiK!ru0hffW*%O@JnLO;;Ck7aoB!yH2ku7+az8yiO z(sQ^`GL-~>I`)7z=dwd@K?usvi_p!_%k$|o@6?J@d!!N%68q*nKdQtEP-=h!J)bZ@ zhX!P~FCW+&gKc4CkJ_Ex23&%p@_3o_{=|C}g>S{>yAMy0p3zsG-<&b<61PDIB#F8sMPVr%pEJ>U+}2;bvH4^<8>dkImgmtn+DYIK%xT!L;q z)x$8cY^O|7S3@LdCK!9y(Re692Q{;pol#t(?mXEuM_55~?*ly=m0f-9EbNl~FZpAoF4yEbK14un4ZJ&T2Md z_e6Hxd7xf5S8|z=IuQROl&MDZcYh+sVY>Rdu3_I>q)<)&2^AxZ^5kN>*qVa0>L9qh zxZ!3soPYoI)u!&A`x&W|n^ljuz?9@A^6rH%UIL>HAWy-xe@9LNr=}=N zR!nv^NtXD%4`j4f||*0HD(!p~2Lw?#t^F7FtKJ!qZ-gB(&84z(ZWnoV7sJa+wM$Wy)*nd`!W z_p#2zy9WbpiGF*37`z8eWHnm!PS}i%b_d3_&eAy#0qi<^AGz_gLc4 zU4Oen{4g4o`LB)AhqQhs3GslbFGs1Uxp-<(@BJn)xYVg4r#y@gQw_Jxi0loBY)^`N z7G3FRo^+7pR60Duwa*U;Ts3m@k6vmHUjiuz8}!7-Mybg;1pDQ$*mgE>N1#vDof%}) zhAX6ZB70I)=#X#fZU5EB4TtB)Pm0IkJpkb_jcSx1&0fdO%nt*zv+5;wDKgKisn7Ms z8YF?D4lWkE#w|7u^Er6D-3+-Un~_^`y*gM^0&-jI*P|M8Rb{;s{w17Q@Jk+EAwZqF+oVGb z6kbhp;eC?~i9HyDzGjc4pppuh2Y9vX`CN75i3b~SlRMqlqNSHXj)c}L4YIg;Y4bm8 zHk@PmF{tLOWsaKheZS=WcGpd(#}3c7$xzuY!2)?`BcZq5r@u6t_+oFojANzYvZ;!a z{oOmQwH{N1+}T6Z+)s{MQY8I}$V->82a&L=^!}jtKT{`{tEN7K*?^iBSdMH$SV%(f z#6zuL*~D8Y)d2w&TXWlu!Vf?~%#hkc2Qm4+wengp81qYaU_<0M-uoV1d;o;DOUt#_Ou#o9n)1Y;&{ z06-KgRT0!(o#4BQM6axR5Q9WeQQq3F`fCecfsTeoVSBnMMscZJsp@)pnT)N|c8 z{#~SKg}vVgnTP!X4%!V--xj*^NyX+pDA`!)Si>t{SYxuTbONXT*!-V7)9q}e;L{=Q z1aEcD@GUTjSR%O82}@4WTR2{7eef_&Dab9`j$$Sd&u4`?cVoXD@RYOqjJCKC$ZAYV zt{aCo-6R(Fsf%V;YJpCgngl)fAjYJm=15d|>WWMF)6x2z+;lHzXasS8SQiZe9O!sl zxQLdXizHKH!s)22^};Lwfbd^a>$*F7F&(q>;B{*)YV)O{De45qvtJjgducMAJr8myEb`l1nt3A6}{V}6RM^}4$YYS_=XWp-YBN~9P<+P>D|y5>3t zMW5uxdtjfTClniArx+V4OIhzKIVT%_<7?W&|3)2g-lTLINv}Ldm}IzpQpy}rir+E& z(eBpet(Vv@e1{&@J^)s~LAtERa}vEfN7Ii=_CjW>GUIcDUQZOe=zjuu??wF_@d&6* zL%pxv4O-f`sFbk9vSF#E-G55R^2x&#h3@z%>N3w($de0iXN!&V&|>?hB3hIcYU=u8 zHRWxS+BA8Vs3Tk6Qp%iCKEaCtLYSPcGA%R|$`Pzt9fn_bGV}SLuU?x~y@(ldY2)la zY~fVcIviI^OzeNv(c{tYW-&DOUXe9D4wFQ*x$%#eHo;$j0)Bkj=ryU zQ&3+rPwiU*$bW1d^uncd;j4e#0bFDb0|~IgzZ=6CX#h>n zQy)Lc7Jval35YPo{vqpr_EAcuD$TFP;_f3!OrQT+2qiuMf&7;L0IUKCcpz3!L;*Ev2fx;`769ZDCEw+D} z&ihu%a%Zz9)q}7sHme`$`sRxglDYO*3#eR`V-DeP_}jh_cj8+>!>y)f0T}4>4Gue# zs??gYwofdkw!WUL_tfOjlkZW^IREUe3%PqQ=_=dr_nh(;zhC;XQmzpSL{kp@bH0`l z*W&g1A$kLnlK3UEZv3+zc5e8TB;*O6#FK21Go|G5ELCcLZVT<~D8|QxrhC>5!OYP0 zFZkZ*Sq}ht(d^?!Nz80pC&d<%csNB2&1Mz*0cc%%%Nl-AAm-`0=7y~KWd}&`XvZT{ zBr6X}8I+-nzchQT+b^Gg1h}Kj`ws0Lqo9g=Is)jj?fK~b| ztchuYu|I)r1gZmZq^8$QK!~OvT(9c5zXqH>Kfbc(O)Ijg{K4*fkSy~Ne@9Y>h-Act zs?r?U?s(k$4-ulA|B;-V$r;hY$D`7O#SX>eDL(+Oy;OQbdnGyo){}D}#p8XddR6f( zEiGyK^`V?4?5F>$rarcL3~Tk^A0z5KrE9y9V%S^UV5N2BSAkw5ebFgQS@PEOcf~@} zvb6r=7!7I}Zgqq#>Q6~K(%G0iGr_2P&xGD^lXo!4R1)p-OLlo?%C;k*Yf3T}-hpy3)8(8ll0rEuXMUf(>~*?H&Rr6e5* zL>^fL{h0Ys&7AZi|2wy^auKjqiK|*yQ{I_iP9Z+sb3vW15X-aUB}Oh@nJ?!C*;@Bu z{x{U`qfe5)Fck zr@(X-{DW~7{KJ2B%e30Cv)&j(z4wH4I}t-DIVRsbX_fbH=UQqx5hdaFe6H8uJld)+ z)T=+c2cK5p?bs^ToJ$^>%_g!SeRWW~_LYJWEn37r1CWUuPHRh`P0m|k?6em)tam_e z^EmSRkcIbm30Mt{LX3=W`IDi;Xp15#-|h;#PPMD6xlz-YgaG)a7rX7QdW=7p?Sv8k zIWe8zxaAK2YaF9Qum<7qR(?hSR-;`gyWJ(LZqr@7^jY7i0mF*_isZWkLH$DKj2h=e z|6`>9pX1Hhe3#)^3rrp-W_|+-^3Q`!D{q#(an&vLfvTCy*2qL<*+l1%*LbxRRRKoh5!k(66zy|5t5YYUy3#nsd7W1$b-<{+JH~pgJm7M{&heLCCnmwV z*dGfX`+%<-(|PDUBq6V{X8;NS*V9sDod2`zeZ=$#h}HfIn{hkemLcE+_uxAQ1>Uj2 zcV9aVmsNGL1O*&h?990p@AD_KqV$g>@vPjca+9`@ot;!aY1~{?-WBe+Y4|uZmQ1^J zo;?h?rTT43;P}~4IiK6ZH2EF+_MxWHQ^88ry&2nV6;>MAsRMD>Z&l!1^)D{>#XoYkH1dejEu)zT(KKO1t=e)-c2yI^V(fe3MPg4dw z3U)!DEj=S&J1lP&UU2f9gBDp;m3yxOLi(edMl0U;vKTZS2<;`Nkow9+=lBlHy<*xJ zAMgCi8jpOeZg_in%{qrIcW@fUaG6At+OUjovDA`0=%+Ew0g;7`!(5&vV$(lu zSCXcJgb}l{1it~*;wN}1ffm@2VaF8zwq&W^df%K2l@xLP9|}_6r(kUKO4%&5(fsl6 za=T9kuV1E&=vC``W-BsjHIcR((V)nTCs}0&C=+udUBgt^(?0OM&Z|d z{^OHk3e$!|?@Gm$EEcJs7xF26&(0C}jp#~Wk^WD?edPj)N?ah6SYU497p^W7=T;14*nBPs*o-F0<1-$#+k!K;tr{|`v_6Najt0C%X zI8c`K2YD8l?)~w)xocNzZ!&m zb-9oleNX1^n~m+Kms+#t6)Se^92yCgTXsr0YAyge1f!z6(ZKNXQ>f}}P*o?k7KK4G zg$J1LYE^D?4Oh$+HC;;5&(In+P{+aQw!WaFY;owNJ=Jc4rvsA2*+zR(HK zAmH?hkPxoV4wBu_>v>Fmcb5Tj3 z>{&m;Sq-P4=5o8fq?&gxlnq^t%0mTu{yvTf#Ipg(oWZ$@X2?87e~X4cGO$jNq;e(; z4%*9PMnGwG9qvl(_`Uk+_KzQ}D!lMqA54!kGFcaKHB&u&C(7yCrZ2xlQ;{-(T($en zA()cigu%&u3}ES@FDzofi96_iePdDi>%RXYO(;HL{FoObks&3G{LC)b!kQSyXS zxTzXgTnj`a(EJf6u^|ITCj2m<(TYp zui??JX@8IIQ@RsLo#Ih_pzAAiV^TyPUK!N1$vC@Ax zOi;#EhRK_q-C;;CvDB_<@X=j6*RB1XxlKBfJIo~MzDFmU*SScN0-POI+&#)ht;1Y$ zN0lYHGD4qVr|fJp8Mx~BZALlE4WZuY&Q-5Ex#lSFP@09H@I}YIDaHn&g7TfvL35a> z8M`s@zDQ318s)r?TuO`CU4vgu8#}MoRV92+IA*98p$;VDvvlF5S7PM{?O#Caji?GK zy?uQe`Er)pvitWZ<~~sMh72!4pm%*x9~EM2lp=WWn1mteNwb(8ifa#sY~C70W@I+N zwBBQ8L7CfnXkIy^{VoK`bnE)pHgJ&X{>Ap0?fAh!ibGbWkZEn5PT>5V}8bDtlZ0fR(r zS}7EOZpcER-8aa{Iz@jakxt?k<}V+Yl*|^bTQ#2DT{?TLA!u~93^3t$AZ6Z+A#7k+Gu2cXN24|3Jd$)Zj3cblbK=t_j#X zYOVM0q!vxV5|@Iy-iWs80a|+V)~8S<3Mi5+2_xxS`B9(P(gip(Z)JKIdkl@MIkOI! zYEeV_&rZc{_{NLE=#V%-4ewq?Q|i{g71s{|R$ipSD9^jAQ{?jp$jHk;53f#?pszH0 zQg_#SM<4Apj2Od9?TcG8I$BL{p@1oQit_IUuE5}zp?Hsn4%DL5u$2pW@XU$7t!XgU zW+GJj{o=eJD5a);$H(LQreZdbS)upQ;{THW>wP<2CM#0H{r5WOWgG@kA{H0RQDXHD zydTN{|NPov>snK1skBe?hh+EwP5sBy!D!m7>RdqMvAA6%8_USVtjT(jSkfaSgPLea zbMrC|uMUqQm&4IcwIeNw63~Gu+gF9Mi>Si7Zp_+_=9*PKrn&4u27AQoQ5nA;3a-PV zbItx$x9LUu2sDF5;n}8a$8;m|KqPk|SF6wLiPE>oE=odT#o?)|MiIV;7d@wnX|-(n zhX65uVv?8-ONA;w%UHtc`x}ISv|SkW?2vMhBKC`tE&+e8PQBbf;8uO>NWLH7J6}Ft z0&+6C{=71~ibKDIor88$sQ^BZ0U%3~kcBYMKOi7j(EyDl%dD>uf1P-mW8gL0#2m|S z!eis7>Uh21nFriVdK1Zw6L$PqG>W3$2&tgM^Cq>rZab`^fV`)n#uFQkqb9dQk9 zezGG(V*z3rL%_!8j<#L;0h9-YcUs}#{ya1*89mxwrfzRQpVfU?XYx6F^W^;!b9g0= zwF=+=zK!!u^G{n-IMBX(fO-KlOsGe5T>U}9#rsY9&?WaIfqCAe!=7kBXWs9vieGIq z+9U9l_)`<)M$BVGI*&bX>g2p!-+{~d)5|JQfEZP-a+0yiNIWof&J}L?!%PF+>#yxc zcjFXVzDq5U8~}r{TUhPnex8~PEJJa7A(=~Dt|y@ zIS~L5I}5#6`&q$yPT#=?k6)|Rz?pB%OdzrLx*p}H>3sW$`PszxcSwp3O}2a4d@jai z$rX;C>bCL)`247K0d>ZBt9`v`>Ut1EK`Gb>Q~^w6Jklck7EvRi4OcJ{8u>H&P}ff| z(2^dxc@poVTTk;e-^_mP!`6rcIO!Rofzw>NfwLS^XchPA-~=u^oJ@SRpWxS@TnnQZ zKC^6FBro(-eAn67i`=o4zvl}Dr>UBGZb z>c}Vy)Uy7e?NT4#gxqNbySXKi!Y7-F*SB(Wd~L# z`NIj!K5pLWH$xarjnespfDWm+7N4VGCs~=wnyTSuY~1q1yo<;*5W%W512G}Ub<(WM=EGG08+xjY*qcG^vBFoX>sC?mjB*K&Cyw`y*U1;O=nSnO=fg|jPJ{Gb-%}D1n z*b*{teXoc-93xAK6_ecCN>a~9AuuLHB1h86MGsKt>IMMHDhyBi z->XcIO;3qCEZwF8t<{T%gYau328eHmNEs7UQ zyKG?QX7qf1{&!yUiy#j1uMYfKph+()P{_;s))KaV@53c8HX&5;@pUa9{fhF)FYZS{ z&Q#AN;->puwVrA?Z`(VU&@#bNv=RIn?1hSvdFsu~FnK#n~Sb0ATXJ^s)QCVR(P?k>dn_6$lB7AOwG(zpmLt zmck&UA6Jg$Kh<@nkYS}GO37Hz!E?+fDp{u;OD%Z&&!^R%NZCFY0;mDbn`VJm3R5%u zCn;O(sV)|gguKJJ@e7rScaM-N`gk!IP|;!rk4YAFd^okUSn?d=ikH6DKjd?5?~0W7 z?IMr|V)_>`NOGO0dHnZA&}52VHgU<7PGy1h$mVgZurpwwehtjd3uskw5FP(MvsvS0?phc;13 zcH*8iVymUwtc)>3h?}Arz8&ynt|nr6jVARXjUSTg3iz;kV&7sg#QTr@$2wrtv9Xsz z3X)Bq2rYl;H-L#!3<-ZM`L#TI&Hbmd|9f#VrgNhaZLzZ#4vzsS zx`I|XG{+*w=T#&M6b_{NT-Rz@Q?@~0rLh8Kna)H9H3RCbad?zikARf(Lg>_D_Bd*U+>@%B{R9X}FqNu|xX z%VcnhkxflSFB$}TQ}dU*nJ<0xRsGscik}ZKrI3Jlu`pqBE?o6IfOy`J-6t*pP=@_7 zJYLv`p+I$S8A_bZ3g8|_pej4HQO0tpQKKfa3sc??G;qa>$L;U-@$<3~{krE1t;Lt^ z6{={JW%8?znLCklG5D_C z>ZZHu>%=SSkuc)vfBQ@CPjkbmbLFW%Y5cQj6eLAIKie=k&<@CY%=A9DwTP)+j5Z(W zd$dy>RX1#JvpJTx2>+l6;Dp{(AgWZhiit(#P^h z{(2d%2;yf@ov)7$uSxsgKm5HA%0^euBd;! zG;ScCfhkMJ^FeWd_Rjv#NMhi${{l>Msx-$fFgU|VQw^W5&ygwqa56F9u@w&zbew!W zoN-}XJS^=rI6ZqyWSHP3?3BMp)wJtHQWWI3$Kg9BNN3EsQ_@}8|2Yr78P}dayPxRT znz~t`vNzmSFzX>CjL@p>fY=_n5_s+xU496?XqY`)p)025vh729%?44r4N&0Lml%w65}s0j`^I+$RMEh1IfFto zsmur*CA5nMtgu@LRPuOiUK}j5Wgwf?3goJEA#O8oU)8c0&#oIA&DwBi61!(pNW7!9 zE8PHkmRMK3Ugqr~ep%%D&su&tP4jx!=g8(Q+eCQ2Nv%?dia11jV9zAaX@5 z9wz2Q95(XP^Kk5UBB!sZVE(7`3%~x!9$C!EBfOlDRJ6(CT%9S0`THESS8Zevq9D8Q zH)_fG?UEdT<~hjm_5pn1+PKX5y5rWmLT#_{C?RkR-x0f2*>exaBZxdTFq&0}VhP~t zr#lNIrp=<;hnz)@wBPzjEXN%VV@OiD=5brCi1b0-RED)juZo>dd(C}N&_{u(D;rZ4 z;RqB*;Is>7|7UK~yVv|`w!AB6Jf-m87R0EB>UW~Tz)@t45AAkh^Qe6)dwRuCWaDd3e zNVC3YDL{kai%CR;vVru@1Ny6XB_jv0h#a5pP6OSUjrbpJa0=wZ;($2?#a%t$5*+#% z7y9g(lHOqjvjeW{qh?E00OB6!BU7Y6xvTdd!!Xqn9w0!}&`amcNWGMPo>gR%&=!6< z(7)2Cy%^a0vXDx0^=eF{iXjeY9gVhCR%yx6`V@*%O_Qlb2HdHP7_zd>w2+NDSX8zY_`+I z`hI(fFeH`#v|z}EY??U`_nuA$T12dq?1A=PTgz@&C;#Q#&ZmZnr8zch=RJ4b7e6Qr zpR2vRYsTrcGc3%Y4X)oV6|@naWdn$)k_`xuB9y!Dcnnjs`+9sDf&I{i8#G1yexNV7 zm}=XF_`VLmUitedmi*qOZq0>h;NUdUuw>KxXLzIb+f0!ZbI364N%KRSR(gH3^5N9C zZ)YN=Q^Z2BT^2^N%w{bf0u-k*j`4*JZbnY1rq_slskJ!BqPG ze+@+c13k1C1S^S4!F~zJ8q5Hsm+PE<8WmYI zL!95K3crRW0?{ai=w{)xb~YK-C6=W98$b2my~Me|MDw0Eg8#%6#}X=aQO9Zz^lQAT zW2IP88cWg+FXR(T-RU(*;mjt8=f-lYODSJz@qg7&qG~rB5p06l{gR;PXlAoE-}c#3 zeATmf(v%I^S|70zk!3bx75JcE9%K_BAcaqMGpAJxAZH@tcAl9cO{eL7;3Vu=5^U_P zQpxwW5#icV&YNCl6Nxf|mcPEnY{T6TQd+it%cGz-I;>9A&wX+Wu@tke)5neX1e!t{ zHn{TY{c0izNB$Puwit)a%7Kr(NOd8G% zR$X2?7@=wg%Fg>JkbcPC(j>Hb76Q+ z|3rlRw+RjJz0w2j3|!Ai?%lEbA6{Z0**1~?3tXQc|2y@_zj!Gf{Ld}9|Bd>`eO&JT zhcNK(e|qZvk7S+y|9ng%qw_?NUW#E3gW1?w%EO|?p)L-Q!N1Wc<~>;jt{mIxOKymJ zyakALLGieqiZ9hee7ikw{4D8?_5_MSgudH$;W>t#aWV6NZi!J8+-h@+s#_!AlX&C( z+w9VH77Kng6O`C#e`V!kxgG?z;<^2F<1mbfzwi`hSt0dS^3AcO1O6*1Id%jfx`q>(`q2%AFazk^}Csj&Go-%s_ zt*zM!IG(p+(#C&Syu6>A@E}W9feZZm#f$B|w#LmLY#W;~2o31Mx!sP-noQQk^Q5Mf zfWc9}@!{3a%lt5hfDNXsi@>JqIQCTtMb-uJaes*ZQ;LPy0`hqBiy&q;$D1JYu9BRM zQhXax9o|k}708J?4Tp$fjuQ|kVQOsu>wye`K$cJAo(TfYp7_X2CvZh71gd3| z$S-;XK?U{|iJA%9G~tf!@F>?!)jn1mw^Mx|v;Hb~Xhuqo0lX3q@ZytE#P^*S9Bn** zYg{^Clbi1rm?WeSwctg5rJPBDW>SifmN8|i+)xN;aLcZ?iwAW6HL5lk?V#ux^GL?= z6rsKyuS@o;DP|L^z;klfYGj365Q_aaUv^Xyi$ijtvQJ~Z0CueZ!`ns zC(g|AFKt&8T$xYa59(3kI)VJ<)M3B%+5gzf3^I)|`SkxM5i%k2gTJ3R1x~9CFf+mH zpxEJ&G!Bd1sS?-QtFr{I+{DyWker+xBRqx8nDtf1(=03w*w1_%7<%6B7iXqVZo2)O zJa!0`%S&+)k68?K%6Ew00+6F$ey)sr5le2l&rBLY4$=Ni+kB%ii!A3iZ(q4qMsvzt zNmg1Jv+CO39}B=uOquMUhF_l{)CvvBDo>zENiUQVCF5f38GPY z7Q`&la%n%AKc4>+%x3Ycqq4?)@OiWMajrqLt5hh-3G~h?D1p0w*Lo&h%>xkAkMFgH z8{-)Wwetc87TxE$-LD_JZFT8CYg{n;xsQEy3D+=nwLrSExpoetJeveA{Z|BW)PIvIGt4t2@$owMh%h0G2~Pi?lhIE_~ib9U^}# z6+8J`%mGw$|AK;g(B)%&pB0SSjV1K$%A;I-_m#t-f{p1 zGA>w~-qxE(su3W?gO!13ZL43`PSDQO2j1Z0DJi_s0gl z6IiZ+7A?xwQs>yYbvx_8u0O#B{$K^jr~D_NzP!znGlZD%;z?2XR{PP=IYN7v#Jd7` z0g5H)%B>6wdenyJm`91mUu$px}9ri0koM3e1S`7nIjRdWJ!`A-|>?&tDV0a_Nv6Oz4!@(p}Gwvw)t-(JFi{ zecxU2v?bG;zRCf?b0C5z_YL2Csd(6NH03HBn%tw@RM8@2EDTr~UC#d49?o`NC%;(4v^is#u`2!t^Zj97KXCTOBRGu%1WkI&4yS+A!V0yq+n)s zKSm=ee7>U-Fm9mQQJ*PMIOH^paVvHW}vFJ)WPiOTxT;iMW2xwKz5jIrL=4Y4>eTebG zvU#;rVHw3~AU5gDb#27u6^~F$d@EW& z>4bsfrorsRM~~X*;Pmyy%c(dBY(xczPYIc_0It5gEz{q1{*4F^8`$I7^jZb;lXImS zn@Ku3Wo1@fYW@g}y6(f}*3GW!+nR%OUz?ycbUkAaLR18^H$?ey@v`M8Cdb{i8!7>c}=@3 zNSZJ>;2IW}74vX2ND*X5l6oFoBjy(56F2i<(8p^-{C6E-zmi98+!;KBW8e?NGeL8HCxd`|7soNc}XyCeU^ zXhgQn$LXC(;h0}zVfn<(~);W-5q0E0Q@vK)SKj>gLt{axrL>@06-e60&zIVtz| zI#RL;D35g)n%4Bqv7rtCAeNDpo?JLScEQdBTmJf>^r5s-nNnkO^Zb8bY(m2hZA*pr za#Y5q;G7GBJa9S+PN0s^wu|zNi|l8kenEop<_sL3MADMi8;($x{~#yr*Gtc@zd(R7 z82nI6nr{M;fp6Yv=f~o^Iw(&iGHA=#vb;_~Y~>=;@W3_o?#sm$Cd5L2h(GJ%F8=ge z#zn{eR=bnjBL2!=+r?)@)5bzuSo;#O~1#A;;Hr+0{UJLA< z`x#sW{Rone1C>$K>RsGd^#Y&CJmNQbqQ2C2VcOevk;_`N=U)U5dGtJQvf^y{)1SWk4=)hAiUkbX&nc?ABNBmtUW{|SaIJHAq^m8>rW&5 z!O#=Fq-qVPx?En)$L1?OQq8Wk&PFLlIg}{M4T)8r2qmMr)0NGgGX(kNau|Y!&FNa( z#`{R3|EK19!#Pz?gWngI{2eP4trx=JZI5TpmJGh4=8hG6}n$N+4)?IPI$ zp}*a3#(D~787!mWyYQ41edhwTlPr3N!Sfhb<)w7i4#UbppqA7y&h<(P6r?}UgcV=` zFQ8<y#=z#K22+@KbeIe+@)FovzuHYUOH0R7OUu88ex~(Ai1(n#sfLrH+lZe z*Qh(LH|Vc+8bppE6r?@l9?8%8cL$67?wDcwHx;LX(<2y71ZzwK#So>;&A^aFSY`5| zOvb>Xeo%$T0=Jy;@Gp)m^X{J?*>@oCFYZn}!#+t>&iW7uWJn4e4*?AyuMueQeM zF+UOLNoHH;o)_d=Q(-=(?cH{}^i2s@H}=mUUWdjyAp;qs<+2mH<$(ZJ0reR>`o>)66C-Q`cacm-IJBWCfA9_m zNU75IbKuyvP%TQ%5kQ%ytben3<>m7q9aQeI*696lZ-LW0SBGTgLtv^9HD#VZQXd z7=}+*b`E`UYqwC@wFC{YDtvvTa4~!rSy`|Fogm+XWN_r)9{a*44y`QyUOKu8I}cTu ztsw)OK(u?p1nNiO5njjpH?*z#k_fWyt&w$+P$-**dt&GW%}C2BWQcx@iI(M1bpqv< z=>#v^WOz90sCmx?4F&;1fZ5;1a0(nnGPiL{eWDogb0Y_Ij|XtefL8njiKWa7?900@ zeSVlltZi?q9_13SOy*v2I-4e#p^x2O71EDQS5c^R(xuR3$AWM=9G$cWO=Q^U4-vPo znugNPPj{j21m$M6`UEivE#qw0!HUW7VU$y`mWOWQHihMFT-rgZ`xn{QZ;zoJbrq09 z9nwp8*a`dI0`D=Ad5S$Bcd&BZXeYZIbmd&&GH@j$olXv0-)AT8@-W<=-f9o$@U;8z!3SmmdYN_sZ~lPq0vIaUVQS;u zHm@HsgXs-6y>TH#j!^8Wo8MOOg%pH#p&{{Mh{C>2czLSfi==ul!eO3kV=$pihqL&e z=t#+@`B1S}L6x0tEtf$GaqA+xqk91AvoqIY$dbH$y&H5l)fMJpsiTS)$6aHI!5 zw1uE`Na#@8&OUONxHEFGYiMiTvq^LH`SO(aB$3d@2s4{Wm-?}aY^?cVA`%<1U9=ao zeyQHS_B{8vG~cd;k2S0e0TE8dN7N<)H}Sv-se;e?eW^37ozq>7OXn>&Sg$^+` z$W$J1Nso$$*#1qc1U7-Ek7NP$yNJf*#%<))SQQM%rq$_M~2dJ$k|d% z5hZ64K~O*uIB#EjpYQ*<4%hpGA6&3l>lyF+SK2#5y(t6o-EKYm1RwSU=c#Knxpdx|DbJ6)XqzPCEo)A_-DC}PZu={j!n6PA>H@ax+^7JNlAwk8WnDT?{r?BSiinbI2D8pYr)gr z`vG2Zg zT)(7lxfkJejvEjxJ##Z)gkK*P9yoR?BLtQY|2a<`cx<-&+afSa#=dAySdKt9q+r(+ zJCH)@mJ-j1vl8AKLS~<%6Xx|?&Mq5`*sbQQl-^j>Z;ESHJ}rfQ&m_7Cu;)D`9pT^2 zy{u$EAOsZk7F~tbY`^iz&p@P-Ad)wIi|B@dr`+;19g@wG3!jo!hhFX9dYl%kA4X*E zn+-6zBmC%)l9_fa5byA8i_GYi-T~>K#>bybw5|J`CMQqU@~E4H0gYZ51xv;U5HHTk zdG3fDz8_K`PG9oP*syKC>e?UfL#vRvbfv9ZG!7`WG)fG%WFHzGT5%28sJi|8k~Q*T zKp)sMEM%UCchYg*nPYgZWtLnD+j!r-#eE*QgJ~9G{+APhwBAY^E01}Fs|FyEFK@D$ z0mIlUHOe-D0{4wtw-rlm_o4K|b`~T}S(Ag#;&cDIc@>)>Uu29ikT9p30mH+dkCn{c zB%lwOt4J&|4cC97DNvgStSP;9@L|v3q8yOF{4 zyib0IP=7n-gyFvo8;8Gfb~TJT6CC>q9f|b51V!AHdd!Qms_Sl7#2-Ngiy%S6FU3@9 zhc18Gk|AGbc!bwG2{h63E4Zgg@IM!6QnRS4eeAdAi@ zBAJgWBZWnOY|`H01$NT!sq;uv z!WLyIT~7H8_h7dnn>9927C0vNJ&EWNA$tcE#+rJ4?TNA-e^-tbDV&lRAj44iCsv8IideYw;3 zn$_&DO>PRBn3a=W04Rx~&Cg>M;pgFFdJ@k7r!SDorNI>9MYB<9ez88>(fyD|9cb^R z#LCbCaVULc9~nNb`FC9ra}h$hVS%SxMJ?{`RFNJ4}*Bx>J4? ztN}3EhP_-dd>j*y?_Jx4qShMH0s+j{-tG4dyl(=5iFSO>O;6)Hx5M7Cz3L7yBzxN^ zc#-)803^)-39Rv+8){k}DlQdT76vtecza_g`vAHkp6uAxz=|Ah(4FO;0038PWMZut z$un=0)p7~tK6Bgq?C8Rl)%$GTTteu|2zug>5*e$#nLMa!SLWbKpnTKw8<~{k$0fgn@P@h4vc0IEW$R^bjl!)-(RZXHO0@ z?%4$llyl$O7dhc4&@lAimhMPT(zjc+Y4+HEy;9Q%phx;8d(-UBb`DnjaBove4EG+o z$6U`pIdflY-=xLC+bRAAoS-Pq>X%_&A+POlpZId1?H5{E%i!|2L~j4%wBY}hGlOaK zQXbtl4X8VT`)276|NX6%Trxa&PW;&0c!q}HeDBI!v1}-5MIzXGu%KL~C2eN*s-VX; z;FRdhc)d;T_a#i3|M(ec|JY{ebUEI1_)*Ti*{NI>jaEe(4zbP%4<>BcBkwhzbOEk& zfXse8ZFDbsm{9go7Q{UD=j!>p?w~RNwZm~v!Sh%vRZBsQ8p#r+i^oC&5w8vW&_Yk& zAmK)>+||~19T7uEL;wh&Z@+ruT%~(1Y&scxg}4+9rDYn&6PjT^5yq*(kV!M7aFJup zZBFnoo9JnE5KfXQw&HVaE9_t3HX6kIfaLs^Y#4jfw}_}0CYya9PHb~V2LkZzOh+BR zibx(;uG9{WAQvw}&%T?);R}&FS2{iH%QQx1H|KeX7+2M5KRano+23j=4SNh#E^qCZSQJl9MYJwd_tDRwYy zxu_{lwQxKx8i-X*9c#WV*-S-lGPql3=rueZJo#_|n`CNPvhbKXSuoP=^GJi&%sR>} z6txxCBTRN4F;?HKgxUOLS2~x(9?<$)t|U4f^|kYR$&Gz#(;G{IvaG{o3Rij|UduUA z|2Ux9?>5-`KQ^UkRh~HVF?JKE@1(M5rt|BR514euHs(G62u<~?SJX1%{7>#UUnqZg zdL;E-+Nz&y8mRu*43=N>Mw)ov*8NJQ<|cTOA5AXysO+f_Mr!G|47EX*17a6>?}h#y z!3N9)oqkn?+d#XBxiEsrIV05fEm`N7&gBx7Psdt1$Joivwk}Plg*UW#Y6Dk4<|rIZFTyQ^p9kE`bGAIW zbh=AP@u}TR|JBPk3aP&tP*-Q|g@j zx>83nm4e|1C={1!vaX9jkN9Tuybq z{lXitX?x%nab2s4WxX<|JbH~<125f zPxNyFQphjwI>d0XOt)&;CH3oteo4`xhW>ybug|%6_-LKN>CPzw1@C!a*w$POz}ROatGHC2_z zLNQ(@so$i>D_b^=i7P|uozy7kJers=f-?qHwm#pu0Vkg}3Z-b-76Qe#* zB!jd8+oj0LM0;7hx~mhd+TXZ44W~%5RvqiN z!Ut)3|H)Tb9Y+SsAZfrB$r=D+jIAlyns8Jb2CIx;Dt>?zYx=(iH;B#tr{NcTZ^L znXnOSfIYryO&JJmg>=QQ&!=eava z05E1R4<9<$9YRGCpdrTZE_b>>)V-Ch^0reYIg&?$D-H&(>w!Si_G^OL3+G^ZXlxz3Hg1d?QPDIrqLvv<{UNG9(r@ zyX}90Bfk$xHM^{RO{JXjW8gq(2@xj0Ec8kkS=@xRdNSR9I}of=<#pWO?CCzFdcFC!)FBUeY zN0C)|ds}ngSdR!OMY)+HxCmD|Pi>}jqmVD0jMN821~EWAfMpVQZ$4u8p_Jnf0cdU> zq(|;-E4$KjD?R4zozV_$L&qu7p!BO&#_7wUzn@?qI@c8od2dy_zAAn>o^g4VMc`K-~G$7d{ zJwE}oQn=%whiH$2$?%0~l5&JMjab9I8*~SLl5Hu=H|f7Pr-HVZ6Q&E2R;+&0+Sp_| zMY{9;Ru_~t=K}!y#;>)aE(G6u?!R$U3Z+L&3mxOti}f8kPR>y}s!xqv=EDLJU82a>ev-%DFk>&tQzDTWi=IuL?S{P==)Hi(zM=*4!ieJ?mEE-%X zaJTrpBm0UX?8EfRdY(m;WdE8E3YgI_Kcjq6%0cywab)_|W~hDbV*g@ewFX14=hd6W zY-L;iWi)hrwvK7Hrg&O>r4iF)gdL|c1V|o0j%T(4R1~3Y87Mq?kSo~IU$*|Gfu!$6 zERx-_{|I2FKWLmkgQ@F#x&iz867#1>`|BY~AAf_ZU3^Q_Qc!-7?EI{PUFA+hs8qKo zJXtk#+4a`xqN3rJvxAXOO+Q`+i;5p6vcCG`O4R1F9yE!u=ePHNFrCr)*@N&WpJaA6 zkkUg`zP9AUbDwIGEuPB~?727F)x@JS`;FMAR0^;D_TS>Xe~Pz%o#X#=+1|-*HQLuI zY;N7U_3OIxfApi^@QXTRMWEu$ty?2nM#z+Nd@sI@? zjz+s-pYab93|v~c8%t31vbVQSe)@F#Q5_u})N9sM$zjDn1OthD zXaRAYJHV6Zz;Za00#d?_J+KiUjiF@@U7N+jF)QUHe6onMtS;q~r+t{H2tgy>bt2Ye zii6Step}p1WeoGH658} zAaxwXLmR1E%?CK1+kjOC3%xaD*imdfE(!Q55r?ke0YPU#)ki%+y>w5D+z5fYkU}42 zFj067>Q*Tf9on*kd~A)!U?bZ#x<^3t%2pm%f+dFRqn{E;mgx$r#~`dnZ%x)rtH)U} zf~J~TaGC%i3}CZcyCW$&um*<4nkk#j2_{i-Egv`u8bjRHWfIFm0+xgeQ8>1qdiSu1 zYV3r_;f!-7^3wah7*x|R#+hvyE~Ss++JX6Fbt+OT35z7}k;t;pQNV!7L;{Ay04EDF zDI^vO-z3F81n0w=elD&1QG4w}Mtc+9%UAk{c|si@Mi`Gj-I$nxX&*ueIjM^)t-P&L zI|he8UoR%BBLFP93+hb;{)&LtEnVvtP~*^e z0)wS7gkop}Na@x480;ttzZxV7pWqBES_!>LjN{`Th)|}q$$Tw>%&%6G7y@#aQk_uK z+1ec{x`h;)HN^mn&1r>&GE?{~J{steR@MVDuDwwJHVefQJb#B-(9h91U5^#X2{m|* zpvin1%MlQ}BUP2z$l=l%Z=xc(qDH=e5cr!aPPAODSVsflL~%G8fHS$s`xCR<21jJ68RYliDSO6Odu22|_uOV?1>yDvE0nv3wv12I8 zWXFlhRzFOS+_Uq`#4leZP~^L&E8h*(I`R!k?-(se-$B9FGRs*Z6{Tq_}8Jy9=!6D~Yyu>eK8(nWM5 z2EK{9Xf_RNa#bM%b^eVq?L_AIo9VE_+$uT>$KNfAVxM6M zEE3NK7YI}^*5M^|GeF0pL(1u>A~^)9uOg}@0ZOEq-E_V>W7xC$S!*%SA`oLBL9>VObm;nr~*O}Ndf-lT5TwzB>{|4{(1ZV*Yj%(!!H(l`~RsX cdp}NU&N}?Apfy;;UkAKwEgdZ?&fa|TKmIGX?*IS* literal 0 HcmV?d00001 diff --git a/www/Figures/Pies.PNG b/www/Figures/Pies.PNG new file mode 100644 index 0000000000000000000000000000000000000000..bdbb98e37608b806d1e26f9b2f5c67121bc1bf2c GIT binary patch literal 129438 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%0D~@@L%N1!neP=L0{>Hp*3R9RHf$v}_#TEbWN7 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 S?{Qa1pYlr$P}vLfkpBhm<18xx literal 0 HcmV?d00001 diff --git a/www/Figures/Strategy_1.png b/www/Figures/Strategy_1.png new file mode 100644 index 0000000000000000000000000000000000000000..817f30333965b337776a4d89fb55296358c7c437 GIT binary patch literal 140226 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 z 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 literal 0 HcmV?d00001 diff --git a/www/Figures/Strategy_2.png b/www/Figures/Strategy_2.png new file mode 100644 index 0000000000000000000000000000000000000000..829d86512e41f367b98b0848d00e6d16de15f6b1 GIT binary patch literal 231360 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

    Q1|3jkyMnQ{G{P~@ebycgzZm$1o$ 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

    8COGxOW(0Nxv>*?Wy;pQXc7R>6HOx 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¿K0aMg-KLib8x(GTSG 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 N^P1sb<=Xbq{|_GALm&VE literal 0 HcmV?d00001 diff --git a/www/Figures/Strategy_3.png b/www/Figures/Strategy_3.png new file mode 100644 index 0000000000000000000000000000000000000000..bcbf20a40042ffe33ea9fb1ef2ad1470bcc4e446 GIT binary patch literal 186834 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 literal 0 HcmV?d00001 diff --git a/www/Figures/Topology.PNG b/www/Figures/Topology.PNG new file mode 100644 index 0000000000000000000000000000000000000000..45e97063613db5d3e808f684b3fbf57b1b4289d2 GIT binary patch literal 31998 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 literal 0 HcmV?d00001 diff --git a/www/Figures/Upload-1.png b/www/Figures/Upload-1.png new file mode 100644 index 0000000000000000000000000000000000000000..1f26d8902ae284955ba80b06fd005400e061cae6 GIT binary patch literal 114182 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�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�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 z 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 literal 0 HcmV?d00001 diff --git a/www/Figures/Upload-2.png b/www/Figures/Upload-2.png new file mode 100644 index 0000000000000000000000000000000000000000..c99c6f0fef097d048e31debe62a85e77d02d26fc GIT binary patch literal 90593 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 jYexL^!$M~Bok+ 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ͮ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�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 literal 0 HcmV?d00001 diff --git a/www/Figures/venn.png b/www/Figures/venn.png new file mode 100644 index 0000000000000000000000000000000000000000..1f7a71afb645ac6a7ee719298d1e8570fa9534f0 GIT binary patch literal 73141 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 + { + annotations_new[i,1] <- annotations[i,1] + annotations_new[i,2] <- line + } + } + annotations_new<-na.omit(annotations_new) +} else { + annotations_new<-annotations +} +colnames(annotations_new)<- c('Annotations','Nodes') + +write.table(annotations_new, file = 'annotations_cleaned.txt', row.names = F, col.names = F, sep = "\t") + diff --git a/www/favicon.ico b/www/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..c7616f28feabf168fc6dd82b522106c96b6baa60 GIT binary patch literal 496 zcmVPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!~g&e!~vBn4jTXf0fk9KK~zXfy_L;P z12GVVz3Bl7u3SrE;zJha*>!j)FPF9OtLcAY3wXCuBNcVE|@^0YBW0wGcAj+4ZnE>#* zjcnStWUtoc4loI^I)P0;v~i^zftY+DkNa{lX+<2WOW-A(ciSRm|NdKauC!@*7@b?| z^($Z?p^U_QmZJCAL)d1ZRH(|j+sZ>3>(YmN?f#lu(fk)khvl?-oSz>*MLKZ*a8slM z+HZY2pDA~|1AxU@*cK&H;Ptm?h3D%yKEvF)iRPCO0Z6o}ILJ18a?;BMnh8X~-Qt=h zlZYm8X-*nIXT3507w`0-`3eBPU2l}(YjDP|59E~c8vtxVgXA@#^A$vN%Jdr`UL$K5 mq#rk688x&r-TDU3OG td, +tr.introjs-showElement > th { + z-index: 9999999 !important; +} + +.introjs-disableInteraction { + z-index: 99999999 !important; + position: absolute; + background-color: white; + opacity: 0; + filter: alpha(opacity=0); +} + +.introjs-relativePosition, +tr.introjs-showElement > td, +tr.introjs-showElement > th { + position: relative; +} + +.introjs-helperLayer { + box-sizing: content-box; + position: absolute; + z-index: 9999998; + background-color: #FFF; + background-color: rgba(255,255,255,.9); + border: 1px solid #777; + border: 1px solid rgba(0,0,0,.5); + border-radius: 4px; + box-shadow: 0 2px 15px rgba(0,0,0,.4); + -webkit-transition: all 0.3s ease-out; + -moz-transition: all 0.3s ease-out; + -ms-transition: all 0.3s ease-out; + -o-transition: all 0.3s ease-out; + transition: all 0.3s ease-out; +} + +.introjs-tooltipReferenceLayer { + box-sizing: content-box; + position: absolute; + visibility: hidden; + z-index: 100000000; + background-color: transparent; + -webkit-transition: all 0.3s ease-out; + -moz-transition: all 0.3s ease-out; + -ms-transition: all 0.3s ease-out; + -o-transition: all 0.3s ease-out; + transition: all 0.3s ease-out; +} + +.introjs-helperLayer *, +.introjs-helperLayer *:before, +.introjs-helperLayer *:after { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + -ms-box-sizing: content-box; + -o-box-sizing: content-box; + box-sizing: content-box; +} + +.introjs-helperNumberLayer { + box-sizing: content-box; + position: absolute; + visibility: visible; + top: -16px; + left: -16px; + z-index: 9999999999 !important; + padding: 2px; + font-family: Arial, verdana, tahoma; + font-size: 13px; + font-weight: bold; + color: white; + text-align: center; + text-shadow: 1px 1px 1px rgba(0,0,0,.3); + background: #ff3019; /* Old browsers */ + background: -webkit-linear-gradient(top, #ff3019 0%, #cf0404 100%); /* Chrome10+,Safari5.1+ */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ff3019), color-stop(100%, #cf0404)); /* Chrome,Safari4+ */ + background: -moz-linear-gradient(top, #ff3019 0%, #cf0404 100%); /* FF3.6+ */ + background: -ms-linear-gradient(top, #ff3019 0%, #cf0404 100%); /* IE10+ */ + background: -o-linear-gradient(top, #ff3019 0%, #cf0404 100%); /* Opera 11.10+ */ + background: linear-gradient(to bottom, #ff3019 0%, #cf0404 100%); /* W3C */ + width: 20px; + height:20px; + line-height: 20px; + border: 3px solid white; + border-radius: 50%; + filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3019', endColorstr='#cf0404', GradientType=0)"; /* IE6-9 */ + filter: "progid:DXImageTransform.Microsoft.Shadow(direction=135, strength=2, color=ff0000)"; /* IE10 text shadows */ + box-shadow: 0 2px 5px rgba(0,0,0,.4); +} + +.introjs-arrow { + border: 5px solid transparent; + content:''; + position: absolute; +} +.introjs-arrow.top { + top: -10px; + border-bottom-color:white; +} +.introjs-arrow.top-right { + top: -10px; + right: 10px; + border-bottom-color:white; +} +.introjs-arrow.top-middle { + top: -10px; + left: 50%; + margin-left: -5px; + border-bottom-color:white; +} +.introjs-arrow.right { + right: -10px; + top: 10px; + border-left-color:white; +} +.introjs-arrow.right-bottom { + bottom:10px; + right: -10px; + border-left-color:white; +} +.introjs-arrow.bottom { + bottom: -10px; + border-top-color:white; +} +.introjs-arrow.bottom-right { + bottom: -10px; + right: 10px; + border-top-color:white; +} +.introjs-arrow.bottom-middle { + bottom: -10px; + left: 50%; + margin-left: -5px; + border-top-color:white; +} +.introjs-arrow.left { + left: -10px; + top: 10px; + border-right-color:white; +} +.introjs-arrow.left-bottom { + left: -10px; + bottom:10px; + border-right-color:white; +} + +.introjs-tooltip { + box-sizing: content-box; + position: absolute; + visibility: visible; + padding: 10px; + background-color: white; + min-width: 200px; + max-width: 300px; + border-radius: 3px; + box-shadow: 0 1px 10px rgba(0,0,0,.4); + -webkit-transition: opacity 0.1s ease-out; + -moz-transition: opacity 0.1s ease-out; + -ms-transition: opacity 0.1s ease-out; + -o-transition: opacity 0.1s ease-out; + transition: opacity 0.1s ease-out; +} + +.introjs-tooltipbuttons { + text-align: right; + white-space: nowrap; +} + +/* + Buttons style by http://nicolasgallagher.com/lab/css3-github-buttons/ + Changed by Afshin Mehrabani +*/ +.introjs-button { + box-sizing: content-box; + position: relative; + overflow: visible; + display: inline-block; + padding: 0.3em 0.8em; + border: 1px solid #d4d4d4; + margin: 0; + text-decoration: none; + text-shadow: 1px 1px 0 #fff; + font: 11px/normal sans-serif; + color: #333; + white-space: nowrap; + cursor: pointer; + outline: none; + background-color: #ececec; + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f4f4f4), to(#ececec)); + background-image: -moz-linear-gradient(#f4f4f4, #ececec); + background-image: -o-linear-gradient(#f4f4f4, #ececec); + background-image: linear-gradient(#f4f4f4, #ececec); + -webkit-background-clip: padding; + -moz-background-clip: padding; + -o-background-clip: padding-box; + /*background-clip: padding-box;*/ /* commented out due to Opera 11.10 bug */ + -webkit-border-radius: 0.2em; + -moz-border-radius: 0.2em; + border-radius: 0.2em; + /* IE hacks */ + zoom: 1; + *display: inline; + margin-top: 10px; +} + +.introjs-button:hover { + border-color: #bcbcbc; + text-decoration: none; + box-shadow: 0px 1px 1px #e3e3e3; +} + +.introjs-button:focus, +.introjs-button:active { + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ececec), to(#f4f4f4)); + background-image: -moz-linear-gradient(#ececec, #f4f4f4); + background-image: -o-linear-gradient(#ececec, #f4f4f4); + background-image: linear-gradient(#ececec, #f4f4f4); +} + +/* overrides extra padding on button elements in Firefox */ +.introjs-button::-moz-focus-inner { + padding: 0; + border: 0; +} + +.introjs-skipbutton { + box-sizing: content-box; + margin-right: 5px; + color: #7a7a7a; +} + +.introjs-prevbutton { + -webkit-border-radius: 0.2em 0 0 0.2em; + -moz-border-radius: 0.2em 0 0 0.2em; + border-radius: 0.2em 0 0 0.2em; + border-right: none; +} + +.introjs-prevbutton.introjs-fullbutton { + border: 1px solid #d4d4d4; + -webkit-border-radius: 0.2em; + -moz-border-radius: 0.2em; + border-radius: 0.2em; +} + +.introjs-nextbutton { + -webkit-border-radius: 0 0.2em 0.2em 0; + -moz-border-radius: 0 0.2em 0.2em 0; + border-radius: 0 0.2em 0.2em 0; +} + +.introjs-nextbutton.introjs-fullbutton { + -webkit-border-radius: 0.2em; + -moz-border-radius: 0.2em; + border-radius: 0.2em; +} + +.introjs-disabled, .introjs-disabled:hover, .introjs-disabled:focus { + color: #9a9a9a; + border-color: #d4d4d4; + box-shadow: none; + cursor: default; + background-color: #f4f4f4; + background-image: none; + text-decoration: none; +} + +.introjs-hidden { + display: none; +} + +.introjs-bullets { + text-align: center; +} +.introjs-bullets ul { + box-sizing: content-box; + clear: both; + margin: 15px auto 0; + padding: 0; + display: inline-block; +} +.introjs-bullets ul li { + box-sizing: content-box; + list-style: none; + float: left; + margin: 0 2px; +} +.introjs-bullets ul li a { + box-sizing: content-box; + display: block; + width: 6px; + height: 6px; + background: #ccc; + border-radius: 10px; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; + text-decoration: none; + cursor: pointer; +} +.introjs-bullets ul li a:hover { + background: #999; +} +.introjs-bullets ul li a.active { + background: #999; +} + +.introjs-progress { + box-sizing: content-box; + overflow: hidden; + height: 10px; + margin: 10px 0 5px 0; + border-radius: 4px; + background-color: #ecf0f1 +} +.introjs-progressbar { + box-sizing: content-box; + float: left; + width: 0%; + height: 100%; + font-size: 10px; + line-height: 10px; + text-align: center; + background-color: #08c; +} + +.introjsFloatingElement { + position: absolute; + height: 0; + width: 0; + left: 50%; + top: 50%; +} + +.introjs-fixedTooltip { + position: fixed; +} + +.introjs-hint { + box-sizing: content-box; + position: absolute; + background: transparent; + width: 20px; + height: 15px; + cursor: pointer; +} +.introjs-hint:focus { + border: 0; + outline: 0; +} +.introjs-hidehint { + display: none; +} + +.introjs-fixedhint { + position: fixed; +} + +.introjs-hint:hover > .introjs-hint-pulse { + border: 5px solid rgba(60, 60, 60, 0.57); +} + +.introjs-hint-pulse { + box-sizing: content-box; + width: 10px; + height: 10px; + border: 5px solid rgba(60, 60, 60, 0.27); + -webkit-border-radius: 30px; + -moz-border-radius: 30px; + border-radius: 30px; + background-color: rgba(136, 136, 136, 0.24); + z-index: 10; + position: absolute; + -webkit-transition: all 0.2s ease-out; + -moz-transition: all 0.2s ease-out; + -ms-transition: all 0.2s ease-out; + -o-transition: all 0.2s ease-out; + transition: all 0.2s ease-out; +} +.introjs-hint-no-anim .introjs-hint-dot { + -webkit-animation: none; + -moz-animation: none; + animation: none; +} +.introjs-hint-dot { + box-sizing: content-box; + border: 10px solid rgba(146, 146, 146, 0.36); + background: transparent; + -webkit-border-radius: 60px; + -moz-border-radius: 60px; + border-radius: 60px; + height: 50px; + width: 50px; + -webkit-animation: introjspulse 3s ease-out; + -moz-animation: introjspulse 3s ease-out; + animation: introjspulse 3s ease-out; + -webkit-animation-iteration-count: infinite; + -moz-animation-iteration-count: infinite; + animation-iteration-count: infinite; + position: absolute; + top: -25px; + left: -25px; + z-index: 1; + opacity: 0; +} + +@-webkit-keyframes introjspulse { + 0% { + -webkit-transform: scale(0); + opacity: 0.0; + } + 25% { + -webkit-transform: scale(0); + opacity: 0.1; + } + 50% { + -webkit-transform: scale(0.1); + opacity: 0.3; + } + 75% { + -webkit-transform: scale(0.5); + opacity: 0.5; + } + 100% { + -webkit-transform: scale(1); + opacity: 0.0; + } +} + +@-moz-keyframes introjspulse { + 0% { + -moz-transform: scale(0); + opacity: 0.0; + } + 25% { + -moz-transform: scale(0); + opacity: 0.1; + } + 50% { + -moz-transform: scale(0.1); + opacity: 0.3; + } + 75% { + -moz-transform: scale(0.5); + opacity: 0.5; + } + 100% { + -moz-transform: scale(1); + opacity: 0.0; + } +} + +@keyframes introjspulse { + 0% { + transform: scale(0); + opacity: 0.0; + } + 25% { + transform: scale(0); + opacity: 0.1; + } + 50% { + transform: scale(0.1); + opacity: 0.3; + } + 75% { + transform: scale(0.5); + opacity: 0.5; + } + 100% { + transform: scale(1); + opacity: 0.0; + } +} \ No newline at end of file diff --git a/www/intro.js b/www/intro.js new file mode 100644 index 0000000..53d4cfe --- /dev/null +++ b/www/intro.js @@ -0,0 +1,2531 @@ +/** + * Intro.js v2.9.3 + * https://github.com/usablica/intro.js + * + * Copyright (C) 2017 Afshin Mehrabani (@afshinmeh) + */ + +(function(f) { + if (typeof exports === "object" && typeof module !== "undefined") { + module.exports = f(); + // deprecated function + // @since 2.8.0 + module.exports.introJs = function () { + console.warn('Deprecated: please use require("intro.js") directly, instead of the introJs method of the function'); + // introJs() + return f().apply(this, arguments); + }; + } else if (typeof define === "function" && define.amd) { + define([], f); + } else { + var g; + if (typeof window !== "undefined") { + g = window; + } else if (typeof global !== "undefined") { + g = global; + } else if (typeof self !== "undefined") { + g = self; + } else { + g = this; + } + g.introJs = f(); + } +})(function () { + //Default config/variables + var VERSION = '2.9.3'; + + /** + * IntroJs main class + * + * @class IntroJs + */ + function IntroJs(obj) { + this._targetElement = obj; + this._introItems = []; + + this._options = { + /* Next button label in tooltip box */ + nextLabel: 'Next →', + /* Previous button label in tooltip box */ + prevLabel: '← Back', + /* Skip button label in tooltip box */ + skipLabel: 'Skip', + /* Done button label in tooltip box */ + doneLabel: 'Done', + /* Hide previous button in the first step? Otherwise, it will be disabled button. */ + hidePrev: false, + /* Hide next button in the last step? Otherwise, it will be disabled button. */ + hideNext: false, + /* Default tooltip box position */ + tooltipPosition: 'bottom', + /* Next CSS class for tooltip boxes */ + tooltipClass: '', + /* CSS class that is added to the helperLayer */ + highlightClass: '', + /* Close introduction when pressing Escape button? */ + exitOnEsc: true, + /* Close introduction when clicking on overlay layer? */ + exitOnOverlayClick: true, + /* Show step numbers in introduction? */ + showStepNumbers: true, + /* Let user use keyboard to navigate the tour? */ + keyboardNavigation: true, + /* Show tour control buttons? */ + showButtons: true, + /* Show tour bullets? */ + showBullets: true, + /* Show tour progress? */ + showProgress: false, + /* Scroll to highlighted element? */ + scrollToElement: true, + /* + * Should we scroll the tooltip or target element? + * + * Options are: 'element' or 'tooltip' + */ + scrollTo: 'element', + /* Padding to add after scrolling when element is not in the viewport (in pixels) */ + scrollPadding: 30, + /* Set the overlay opacity */ + overlayOpacity: 0.8, + /* Precedence of positions, when auto is enabled */ + positionPrecedence: ["bottom", "top", "right", "left"], + /* Disable an interaction with element? */ + disableInteraction: false, + /* Set how much padding to be used around helper element */ + helperElementPadding: 10, + /* Default hint position */ + hintPosition: 'top-middle', + /* Hint button label */ + hintButtonLabel: 'Got it', + /* Adding animation to hints? */ + hintAnimation: true, + /* additional classes to put on the buttons */ + buttonClass: "introjs-button" + }; + } + + /** + * Initiate a new introduction/guide from an element in the page + * + * @api private + * @method _introForElement + * @param {Object} targetElm + * @param {String} group + * @returns {Boolean} Success or not? + */ + function _introForElement(targetElm, group) { + var allIntroSteps = targetElm.querySelectorAll("*[data-intro]"), + introItems = []; + + if (this._options.steps) { + //use steps passed programmatically + _forEach(this._options.steps, function (step) { + var currentItem = _cloneObject(step); + + //set the step + currentItem.step = introItems.length + 1; + + //use querySelector function only when developer used CSS selector + if (typeof (currentItem.element) === 'string') { + //grab the element with given selector from the page + currentItem.element = document.querySelector(currentItem.element); + } + + //intro without element + if (typeof (currentItem.element) === 'undefined' || currentItem.element === null) { + var floatingElementQuery = document.querySelector(".introjsFloatingElement"); + + if (floatingElementQuery === null) { + floatingElementQuery = document.createElement('div'); + floatingElementQuery.className = 'introjsFloatingElement'; + + document.body.appendChild(floatingElementQuery); + } + + currentItem.element = floatingElementQuery; + currentItem.position = 'floating'; + } + + currentItem.scrollTo = currentItem.scrollTo || this._options.scrollTo; + + if (typeof (currentItem.disableInteraction) === 'undefined') { + currentItem.disableInteraction = this._options.disableInteraction; + } + + if (currentItem.element !== null) { + introItems.push(currentItem); + } + }.bind(this)); + + } else { + //use steps from data-* annotations + var elmsLength = allIntroSteps.length; + var disableInteraction; + + //if there's no element to intro + if (elmsLength < 1) { + return false; + } + + _forEach(allIntroSteps, function (currentElement) { + + // PR #80 + // start intro for groups of elements + if (group && (currentElement.getAttribute("data-intro-group") !== group)) { + return; + } + + // skip hidden elements + if (currentElement.style.display === 'none') { + return; + } + + var step = parseInt(currentElement.getAttribute('data-step'), 10); + + if (typeof (currentElement.getAttribute('data-disable-interaction')) !== 'undefined') { + disableInteraction = !!currentElement.getAttribute('data-disable-interaction'); + } else { + disableInteraction = this._options.disableInteraction; + } + + if (step > 0) { + introItems[step - 1] = { + element: currentElement, + intro: currentElement.getAttribute('data-intro'), + step: parseInt(currentElement.getAttribute('data-step'), 10), + tooltipClass: currentElement.getAttribute('data-tooltipclass'), + highlightClass: currentElement.getAttribute('data-highlightclass'), + position: currentElement.getAttribute('data-position') || this._options.tooltipPosition, + scrollTo: currentElement.getAttribute('data-scrollto') || this._options.scrollTo, + disableInteraction: disableInteraction + }; + } + }.bind(this)); + + //next add intro items without data-step + //todo: we need a cleanup here, two loops are redundant + var nextStep = 0; + + _forEach(allIntroSteps, function (currentElement) { + + // PR #80 + // start intro for groups of elements + if (group && (currentElement.getAttribute("data-intro-group") !== group)) { + return; + } + + if (currentElement.getAttribute('data-step') === null) { + + while (true) { + if (typeof introItems[nextStep] === 'undefined') { + break; + } else { + nextStep++; + } + } + + if (typeof (currentElement.getAttribute('data-disable-interaction')) !== 'undefined') { + disableInteraction = !!currentElement.getAttribute('data-disable-interaction'); + } else { + disableInteraction = this._options.disableInteraction; + } + + introItems[nextStep] = { + element: currentElement, + intro: currentElement.getAttribute('data-intro'), + step: nextStep + 1, + tooltipClass: currentElement.getAttribute('data-tooltipclass'), + highlightClass: currentElement.getAttribute('data-highlightclass'), + position: currentElement.getAttribute('data-position') || this._options.tooltipPosition, + scrollTo: currentElement.getAttribute('data-scrollto') || this._options.scrollTo, + disableInteraction: disableInteraction + }; + } + }.bind(this)); + } + + //removing undefined/null elements + var tempIntroItems = []; + for (var z = 0; z < introItems.length; z++) { + if (introItems[z]) { + // copy non-falsy values to the end of the array + tempIntroItems.push(introItems[z]); + } + } + + introItems = tempIntroItems; + + //Ok, sort all items with given steps + introItems.sort(function (a, b) { + return a.step - b.step; + }); + + //set it to the introJs object + this._introItems = introItems; + + //add overlay layer to the page + if(_addOverlayLayer.call(this, targetElm)) { + //then, start the show + _nextStep.call(this); + + if (this._options.keyboardNavigation) { + DOMEvent.on(window, 'keydown', _onKeyDown, this, true); + } + //for window resize + DOMEvent.on(window, 'resize', _onResize, this, true); + } + return false; + } + + function _onResize () { + this.refresh.call(this); + } + + /** + * on keyCode: + * https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode + * This feature has been removed from the Web standards. + * Though some browsers may still support it, it is in + * the process of being dropped. + * Instead, you should use KeyboardEvent.code, + * if it's implemented. + * + * jQuery's approach is to test for + * (1) e.which, then + * (2) e.charCode, then + * (3) e.keyCode + * https://github.com/jquery/jquery/blob/a6b0705294d336ae2f63f7276de0da1195495363/src/event.js#L638 + * + * @param type var + * @return type + */ + function _onKeyDown (e) { + var code = (e.code === null) ? e.which : e.code; + + // if code/e.which is null + if (code === null) { + code = (e.charCode === null) ? e.keyCode : e.charCode; + } + + if ((code === 'Escape' || code === 27) && this._options.exitOnEsc === true) { + //escape key pressed, exit the intro + //check if exit callback is defined + _exitIntro.call(this, this._targetElement); + } else if (code === 'ArrowLeft' || code === 37) { + //left arrow + _previousStep.call(this); + } else if (code === 'ArrowRight' || code === 39) { + //right arrow + _nextStep.call(this); + } else if (code === 'Enter' || code === 13) { + //srcElement === ie + var target = e.target || e.srcElement; + if (target && target.className.match('introjs-prevbutton')) { + //user hit enter while focusing on previous button + _previousStep.call(this); + } else if (target && target.className.match('introjs-skipbutton')) { + //user hit enter while focusing on skip button + if (this._introItems.length - 1 === this._currentStep && typeof (this._introCompleteCallback) === 'function') { + this._introCompleteCallback.call(this); + } + + _exitIntro.call(this, this._targetElement); + } else if (target && target.getAttribute('data-stepnumber')) { + // user hit enter while focusing on step bullet + target.click(); + } else { + //default behavior for responding to enter + _nextStep.call(this); + } + + //prevent default behaviour on hitting Enter, to prevent steps being skipped in some browsers + if(e.preventDefault) { + e.preventDefault(); + } else { + e.returnValue = false; + } + } + } + + /* + * makes a copy of the object + * @api private + * @method _cloneObject + */ + function _cloneObject(object) { + if (object === null || typeof (object) !== 'object' || typeof (object.nodeType) !== 'undefined') { + return object; + } + var temp = {}; + for (var key in object) { + if (typeof(window.jQuery) !== 'undefined' && object[key] instanceof window.jQuery) { + temp[key] = object[key]; + } else { + temp[key] = _cloneObject(object[key]); + } + } + return temp; + } + /** + * Go to specific step of introduction + * + * @api private + * @method _goToStep + */ + function _goToStep(step) { + //because steps starts with zero + this._currentStep = step - 2; + if (typeof (this._introItems) !== 'undefined') { + _nextStep.call(this); + } + } + + /** + * Go to the specific step of introduction with the explicit [data-step] number + * + * @api private + * @method _goToStepNumber + */ + function _goToStepNumber(step) { + this._currentStepNumber = step; + if (typeof (this._introItems) !== 'undefined') { + _nextStep.call(this); + } + } + + /** + * Go to next step on intro + * + * @api private + * @method _nextStep + */ + function _nextStep() { + this._direction = 'forward'; + + if (typeof (this._currentStepNumber) !== 'undefined') { + _forEach(this._introItems, function (item, i) { + if( item.step === this._currentStepNumber ) { + this._currentStep = i - 1; + this._currentStepNumber = undefined; + } + }.bind(this)); + } + + if (typeof (this._currentStep) === 'undefined') { + this._currentStep = 0; + } else { + ++this._currentStep; + } + + var nextStep = this._introItems[this._currentStep]; + var continueStep = true; + + if (typeof (this._introBeforeChangeCallback) !== 'undefined') { + continueStep = this._introBeforeChangeCallback.call(this, nextStep.element); + } + + // if `onbeforechange` returned `false`, stop displaying the element + if (continueStep === false) { + --this._currentStep; + return false; + } + + if ((this._introItems.length) <= this._currentStep) { + //end of the intro + //check if any callback is defined + if (typeof (this._introCompleteCallback) === 'function') { + this._introCompleteCallback.call(this); + } + _exitIntro.call(this, this._targetElement); + return; + } + + _showElement.call(this, nextStep); + } + + /** + * Go to previous step on intro + * + * @api private + * @method _previousStep + */ + function _previousStep() { + this._direction = 'backward'; + + if (this._currentStep === 0) { + return false; + } + + --this._currentStep; + + var nextStep = this._introItems[this._currentStep]; + var continueStep = true; + + if (typeof (this._introBeforeChangeCallback) !== 'undefined') { + continueStep = this._introBeforeChangeCallback.call(this, nextStep.element); + } + + // if `onbeforechange` returned `false`, stop displaying the element + if (continueStep === false) { + ++this._currentStep; + return false; + } + + _showElement.call(this, nextStep); + } + + /** + * Update placement of the intro objects on the screen + * @api private + */ + function _refresh() { + // re-align intros + _setHelperLayerPosition.call(this, document.querySelector('.introjs-helperLayer')); + _setHelperLayerPosition.call(this, document.querySelector('.introjs-tooltipReferenceLayer')); + _setHelperLayerPosition.call(this, document.querySelector('.introjs-disableInteraction')); + + // re-align tooltip + if(this._currentStep !== undefined && this._currentStep !== null) { + var oldHelperNumberLayer = document.querySelector('.introjs-helperNumberLayer'), + oldArrowLayer = document.querySelector('.introjs-arrow'), + oldtooltipContainer = document.querySelector('.introjs-tooltip'); + _placeTooltip.call(this, this._introItems[this._currentStep].element, oldtooltipContainer, oldArrowLayer, oldHelperNumberLayer); + } + + //re-align hints + _reAlignHints.call(this); + return this; + } + + /** + * Exit from intro + * + * @api private + * @method _exitIntro + * @param {Object} targetElement + * @param {Boolean} force - Setting to `true` will skip the result of beforeExit callback + */ + function _exitIntro(targetElement, force) { + var continueExit = true; + + // calling onbeforeexit callback + // + // If this callback return `false`, it would halt the process + if (this._introBeforeExitCallback !== undefined) { + continueExit = this._introBeforeExitCallback.call(this); + } + + // skip this check if `force` parameter is `true` + // otherwise, if `onbeforeexit` returned `false`, don't exit the intro + if (!force && continueExit === false) return; + + //remove overlay layers from the page + var overlayLayers = targetElement.querySelectorAll('.introjs-overlay'); + + if (overlayLayers && overlayLayers.length) { + _forEach(overlayLayers, function (overlayLayer) { + overlayLayer.style.opacity = 0; + window.setTimeout(function () { + if (this.parentNode) { + this.parentNode.removeChild(this); + } + }.bind(overlayLayer), 500); + }.bind(this)); + } + + //remove all helper layers + var helperLayer = targetElement.querySelector('.introjs-helperLayer'); + if (helperLayer) { + helperLayer.parentNode.removeChild(helperLayer); + } + + var referenceLayer = targetElement.querySelector('.introjs-tooltipReferenceLayer'); + if (referenceLayer) { + referenceLayer.parentNode.removeChild(referenceLayer); + } + + //remove disableInteractionLayer + var disableInteractionLayer = targetElement.querySelector('.introjs-disableInteraction'); + if (disableInteractionLayer) { + disableInteractionLayer.parentNode.removeChild(disableInteractionLayer); + } + + //remove intro floating element + var floatingElement = document.querySelector('.introjsFloatingElement'); + if (floatingElement) { + floatingElement.parentNode.removeChild(floatingElement); + } + + _removeShowElement(); + + //remove `introjs-fixParent` class from the elements + var fixParents = document.querySelectorAll('.introjs-fixParent'); + _forEach(fixParents, function (parent) { + _removeClass(parent, /introjs-fixParent/g); + }); + + //clean listeners + DOMEvent.off(window, 'keydown', _onKeyDown, this, true); + DOMEvent.off(window, 'resize', _onResize, this, true); + + //check if any callback is defined + if (this._introExitCallback !== undefined) { + this._introExitCallback.call(this); + } + + //set the step to zero + this._currentStep = undefined; + } + + /** + * Render tooltip box in the page + * + * @api private + * @method _placeTooltip + * @param {HTMLElement} targetElement + * @param {HTMLElement} tooltipLayer + * @param {HTMLElement} arrowLayer + * @param {HTMLElement} helperNumberLayer + * @param {Boolean} hintMode + */ + function _placeTooltip(targetElement, tooltipLayer, arrowLayer, helperNumberLayer, hintMode) { + var tooltipCssClass = '', + currentStepObj, + tooltipOffset, + targetOffset, + windowSize, + currentTooltipPosition; + + hintMode = hintMode || false; + + //reset the old style + tooltipLayer.style.top = null; + tooltipLayer.style.right = null; + tooltipLayer.style.bottom = null; + tooltipLayer.style.left = null; + tooltipLayer.style.marginLeft = null; + tooltipLayer.style.marginTop = null; + + arrowLayer.style.display = 'inherit'; + + if (typeof(helperNumberLayer) !== 'undefined' && helperNumberLayer !== null) { + helperNumberLayer.style.top = null; + helperNumberLayer.style.left = null; + } + + //prevent error when `this._currentStep` is undefined + if (!this._introItems[this._currentStep]) return; + + //if we have a custom css class for each step + currentStepObj = this._introItems[this._currentStep]; + if (typeof (currentStepObj.tooltipClass) === 'string') { + tooltipCssClass = currentStepObj.tooltipClass; + } else { + tooltipCssClass = this._options.tooltipClass; + } + + tooltipLayer.className = ('introjs-tooltip ' + tooltipCssClass).replace(/^\s+|\s+$/g, ''); + tooltipLayer.setAttribute('role', 'dialog'); + + currentTooltipPosition = this._introItems[this._currentStep].position; + + // Floating is always valid, no point in calculating + if (currentTooltipPosition !== "floating") { + currentTooltipPosition = _determineAutoPosition.call(this, targetElement, tooltipLayer, currentTooltipPosition); + } + + var tooltipLayerStyleLeft; + targetOffset = _getOffset(targetElement); + tooltipOffset = _getOffset(tooltipLayer); + windowSize = _getWinSize(); + + _addClass(tooltipLayer, 'introjs-' + currentTooltipPosition); + + switch (currentTooltipPosition) { + case 'top-right-aligned': + arrowLayer.className = 'introjs-arrow bottom-right'; + + var tooltipLayerStyleRight = 0; + _checkLeft(targetOffset, tooltipLayerStyleRight, tooltipOffset, tooltipLayer); + tooltipLayer.style.bottom = (targetOffset.height + 20) + 'px'; + break; + + case 'top-middle-aligned': + arrowLayer.className = 'introjs-arrow bottom-middle'; + + var tooltipLayerStyleLeftRight = targetOffset.width / 2 - tooltipOffset.width / 2; + + // a fix for middle aligned hints + if (hintMode) { + tooltipLayerStyleLeftRight += 5; + } + + if (_checkLeft(targetOffset, tooltipLayerStyleLeftRight, tooltipOffset, tooltipLayer)) { + tooltipLayer.style.right = null; + _checkRight(targetOffset, tooltipLayerStyleLeftRight, tooltipOffset, windowSize, tooltipLayer); + } + tooltipLayer.style.bottom = (targetOffset.height + 20) + 'px'; + break; + + case 'top-left-aligned': + // top-left-aligned is the same as the default top + case 'top': + arrowLayer.className = 'introjs-arrow bottom'; + + tooltipLayerStyleLeft = (hintMode) ? 0 : 15; + + _checkRight(targetOffset, tooltipLayerStyleLeft, tooltipOffset, windowSize, tooltipLayer); + tooltipLayer.style.bottom = (targetOffset.height + 20) + 'px'; + break; + case 'right': + tooltipLayer.style.left = (targetOffset.width + 20) + 'px'; + if (targetOffset.top + tooltipOffset.height > windowSize.height) { + // In this case, right would have fallen below the bottom of the screen. + // Modify so that the bottom of the tooltip connects with the target + arrowLayer.className = "introjs-arrow left-bottom"; + tooltipLayer.style.top = "-" + (tooltipOffset.height - targetOffset.height - 20) + "px"; + } else { + arrowLayer.className = 'introjs-arrow left'; + } + break; + case 'left': + if (!hintMode && this._options.showStepNumbers === true) { + tooltipLayer.style.top = '15px'; + } + + if (targetOffset.top + tooltipOffset.height > windowSize.height) { + // In this case, left would have fallen below the bottom of the screen. + // Modify so that the bottom of the tooltip connects with the target + tooltipLayer.style.top = "-" + (tooltipOffset.height - targetOffset.height - 20) + "px"; + arrowLayer.className = 'introjs-arrow right-bottom'; + } else { + arrowLayer.className = 'introjs-arrow right'; + } + tooltipLayer.style.right = (targetOffset.width + 20) + 'px'; + + break; + case 'floating': + arrowLayer.style.display = 'none'; + + //we have to adjust the top and left of layer manually for intro items without element + tooltipLayer.style.left = '50%'; + tooltipLayer.style.top = '50%'; + tooltipLayer.style.marginLeft = '-' + (tooltipOffset.width / 2) + 'px'; + tooltipLayer.style.marginTop = '-' + (tooltipOffset.height / 2) + 'px'; + + if (typeof(helperNumberLayer) !== 'undefined' && helperNumberLayer !== null) { + helperNumberLayer.style.left = '-' + ((tooltipOffset.width / 2) + 18) + 'px'; + helperNumberLayer.style.top = '-' + ((tooltipOffset.height / 2) + 18) + 'px'; + } + + break; + case 'bottom-right-aligned': + arrowLayer.className = 'introjs-arrow top-right'; + + tooltipLayerStyleRight = 0; + _checkLeft(targetOffset, tooltipLayerStyleRight, tooltipOffset, tooltipLayer); + tooltipLayer.style.top = (targetOffset.height + 20) + 'px'; + break; + + case 'bottom-middle-aligned': + arrowLayer.className = 'introjs-arrow top-middle'; + + tooltipLayerStyleLeftRight = targetOffset.width / 2 - tooltipOffset.width / 2; + + // a fix for middle aligned hints + if (hintMode) { + tooltipLayerStyleLeftRight += 5; + } + + if (_checkLeft(targetOffset, tooltipLayerStyleLeftRight, tooltipOffset, tooltipLayer)) { + tooltipLayer.style.right = null; + _checkRight(targetOffset, tooltipLayerStyleLeftRight, tooltipOffset, windowSize, tooltipLayer); + } + tooltipLayer.style.top = (targetOffset.height + 20) + 'px'; + break; + + // case 'bottom-left-aligned': + // Bottom-left-aligned is the same as the default bottom + // case 'bottom': + // Bottom going to follow the default behavior + default: + arrowLayer.className = 'introjs-arrow top'; + + tooltipLayerStyleLeft = 0; + _checkRight(targetOffset, tooltipLayerStyleLeft, tooltipOffset, windowSize, tooltipLayer); + tooltipLayer.style.top = (targetOffset.height + 20) + 'px'; + } + } + + /** + * Set tooltip left so it doesn't go off the right side of the window + * + * @return boolean true, if tooltipLayerStyleLeft is ok. false, otherwise. + */ + function _checkRight(targetOffset, tooltipLayerStyleLeft, tooltipOffset, windowSize, tooltipLayer) { + if (targetOffset.left + tooltipLayerStyleLeft + tooltipOffset.width > windowSize.width) { + // off the right side of the window + tooltipLayer.style.left = (windowSize.width - tooltipOffset.width - targetOffset.left) + 'px'; + return false; + } + tooltipLayer.style.left = tooltipLayerStyleLeft + 'px'; + return true; + } + + /** + * Set tooltip right so it doesn't go off the left side of the window + * + * @return boolean true, if tooltipLayerStyleRight is ok. false, otherwise. + */ + function _checkLeft(targetOffset, tooltipLayerStyleRight, tooltipOffset, tooltipLayer) { + if (targetOffset.left + targetOffset.width - tooltipLayerStyleRight - tooltipOffset.width < 0) { + // off the left side of the window + tooltipLayer.style.left = (-targetOffset.left) + 'px'; + return false; + } + tooltipLayer.style.right = tooltipLayerStyleRight + 'px'; + return true; + } + + /** + * Determines the position of the tooltip based on the position precedence and availability + * of screen space. + * + * @param {Object} targetElement + * @param {Object} tooltipLayer + * @param {String} desiredTooltipPosition + * @return {String} calculatedPosition + */ + function _determineAutoPosition(targetElement, tooltipLayer, desiredTooltipPosition) { + + // Take a clone of position precedence. These will be the available + var possiblePositions = this._options.positionPrecedence.slice(); + + var windowSize = _getWinSize(); + var tooltipHeight = _getOffset(tooltipLayer).height + 10; + var tooltipWidth = _getOffset(tooltipLayer).width + 20; + var targetElementRect = targetElement.getBoundingClientRect(); + + // If we check all the possible areas, and there are no valid places for the tooltip, the element + // must take up most of the screen real estate. Show the tooltip floating in the middle of the screen. + var calculatedPosition = "floating"; + + /* + * auto determine position + */ + + // Check for space below + if (targetElementRect.bottom + tooltipHeight > windowSize.height) { + _removeEntry(possiblePositions, "bottom"); + } + + // Check for space above + if (targetElementRect.top - tooltipHeight < 0) { + _removeEntry(possiblePositions, "top"); + } + + // Check for space to the right + if (targetElementRect.right + tooltipWidth > windowSize.width) { + _removeEntry(possiblePositions, "right"); + } + + // Check for space to the left + if (targetElementRect.left - tooltipWidth < 0) { + _removeEntry(possiblePositions, "left"); + } + + // @var {String} ex: 'right-aligned' + var desiredAlignment = (function (pos) { + var hyphenIndex = pos.indexOf('-'); + if (hyphenIndex !== -1) { + // has alignment + return pos.substr(hyphenIndex); + } + return ''; + })(desiredTooltipPosition || ''); + + // strip alignment from position + if (desiredTooltipPosition) { + // ex: "bottom-right-aligned" + // should return 'bottom' + desiredTooltipPosition = desiredTooltipPosition.split('-')[0]; + } + + if (possiblePositions.length) { + if (desiredTooltipPosition !== "auto" && + possiblePositions.indexOf(desiredTooltipPosition) > -1) { + // If the requested position is in the list, choose that + calculatedPosition = desiredTooltipPosition; + } else { + // Pick the first valid position, in order + calculatedPosition = possiblePositions[0]; + } + } + + // only top and bottom positions have optional alignments + if (['top', 'bottom'].indexOf(calculatedPosition) !== -1) { + calculatedPosition += _determineAutoAlignment(targetElementRect.left, tooltipWidth, windowSize, desiredAlignment); + } + + return calculatedPosition; + } + + /** + * auto-determine alignment + * @param {Integer} offsetLeft + * @param {Integer} tooltipWidth + * @param {Object} windowSize + * @param {String} desiredAlignment + * @return {String} calculatedAlignment + */ + function _determineAutoAlignment (offsetLeft, tooltipWidth, windowSize, desiredAlignment) { + var halfTooltipWidth = tooltipWidth / 2, + winWidth = Math.min(windowSize.width, window.screen.width), + possibleAlignments = ['-left-aligned', '-middle-aligned', '-right-aligned'], + calculatedAlignment = ''; + + // valid left must be at least a tooltipWidth + // away from right side + if (winWidth - offsetLeft < tooltipWidth) { + _removeEntry(possibleAlignments, '-left-aligned'); + } + + // valid middle must be at least half + // width away from both sides + if (offsetLeft < halfTooltipWidth || + winWidth - offsetLeft < halfTooltipWidth) { + _removeEntry(possibleAlignments, '-middle-aligned'); + } + + // valid right must be at least a tooltipWidth + // width away from left side + if (offsetLeft < tooltipWidth) { + _removeEntry(possibleAlignments, '-right-aligned'); + } + + if (possibleAlignments.length) { + if (possibleAlignments.indexOf(desiredAlignment) !== -1) { + // the desired alignment is valid + calculatedAlignment = desiredAlignment; + } else { + // pick the first valid position, in order + calculatedAlignment = possibleAlignments[0]; + } + } else { + // if screen width is too small + // for ANY alignment, middle is + // probably the best for visibility + calculatedAlignment = '-middle-aligned'; + } + + return calculatedAlignment; + } + + /** + * Remove an entry from a string array if it's there, does nothing if it isn't there. + * + * @param {Array} stringArray + * @param {String} stringToRemove + */ + function _removeEntry(stringArray, stringToRemove) { + if (stringArray.indexOf(stringToRemove) > -1) { + stringArray.splice(stringArray.indexOf(stringToRemove), 1); + } + } + + /** + * Update the position of the helper layer on the screen + * + * @api private + * @method _setHelperLayerPosition + * @param {Object} helperLayer + */ + function _setHelperLayerPosition(helperLayer) { + if (helperLayer) { + //prevent error when `this._currentStep` in undefined + if (!this._introItems[this._currentStep]) return; + + var currentElement = this._introItems[this._currentStep], + elementPosition = _getOffset(currentElement.element), + widthHeightPadding = this._options.helperElementPadding; + + // If the target element is fixed, the tooltip should be fixed as well. + // Otherwise, remove a fixed class that may be left over from the previous + // step. + if (_isFixed(currentElement.element)) { + _addClass(helperLayer, 'introjs-fixedTooltip'); + } else { + _removeClass(helperLayer, 'introjs-fixedTooltip'); + } + + if (currentElement.position === 'floating') { + widthHeightPadding = 0; + } + + //set new position to helper layer + helperLayer.style.cssText = 'width: ' + (elementPosition.width + widthHeightPadding) + 'px; ' + + 'height:' + (elementPosition.height + widthHeightPadding) + 'px; ' + + 'top:' + (elementPosition.top - widthHeightPadding / 2) + 'px;' + + 'left: ' + (elementPosition.left - widthHeightPadding / 2) + 'px;'; + + } + } + + /** + * Add disableinteraction layer and adjust the size and position of the layer + * + * @api private + * @method _disableInteraction + */ + function _disableInteraction() { + var disableInteractionLayer = document.querySelector('.introjs-disableInteraction'); + + if (disableInteractionLayer === null) { + disableInteractionLayer = document.createElement('div'); + disableInteractionLayer.className = 'introjs-disableInteraction'; + this._targetElement.appendChild(disableInteractionLayer); + } + + _setHelperLayerPosition.call(this, disableInteractionLayer); + } + + /** + * Setting anchors to behave like buttons + * + * @api private + * @method _setAnchorAsButton + */ + function _setAnchorAsButton(anchor){ + anchor.setAttribute('role', 'button'); + anchor.tabIndex = 0; + } + + /** + * Show an element on the page + * + * @api private + * @method _showElement + * @param {Object} targetElement + */ + function _showElement(targetElement) { + if (typeof (this._introChangeCallback) !== 'undefined') { + this._introChangeCallback.call(this, targetElement.element); + } + + var self = this, + oldHelperLayer = document.querySelector('.introjs-helperLayer'), + oldReferenceLayer = document.querySelector('.introjs-tooltipReferenceLayer'), + highlightClass = 'introjs-helperLayer', + nextTooltipButton, + prevTooltipButton, + skipTooltipButton, + scrollParent; + + //check for a current step highlight class + if (typeof (targetElement.highlightClass) === 'string') { + highlightClass += (' ' + targetElement.highlightClass); + } + //check for options highlight class + if (typeof (this._options.highlightClass) === 'string') { + highlightClass += (' ' + this._options.highlightClass); + } + + if (oldHelperLayer !== null) { + var oldHelperNumberLayer = oldReferenceLayer.querySelector('.introjs-helperNumberLayer'), + oldtooltipLayer = oldReferenceLayer.querySelector('.introjs-tooltiptext'), + oldArrowLayer = oldReferenceLayer.querySelector('.introjs-arrow'), + oldtooltipContainer = oldReferenceLayer.querySelector('.introjs-tooltip'); + + skipTooltipButton = oldReferenceLayer.querySelector('.introjs-skipbutton'); + prevTooltipButton = oldReferenceLayer.querySelector('.introjs-prevbutton'); + nextTooltipButton = oldReferenceLayer.querySelector('.introjs-nextbutton'); + + //update or reset the helper highlight class + oldHelperLayer.className = highlightClass; + //hide the tooltip + oldtooltipContainer.style.opacity = 0; + oldtooltipContainer.style.display = "none"; + + if (oldHelperNumberLayer !== null) { + var lastIntroItem = this._introItems[(targetElement.step - 2 >= 0 ? targetElement.step - 2 : 0)]; + + if (lastIntroItem !== null && (this._direction === 'forward' && lastIntroItem.position === 'floating') || (this._direction === 'backward' && targetElement.position === 'floating')) { + oldHelperNumberLayer.style.opacity = 0; + } + } + + // scroll to element + scrollParent = _getScrollParent( targetElement.element ); + + if (scrollParent !== document.body) { + // target is within a scrollable element + _scrollParentToElement(scrollParent, targetElement.element); + } + + // set new position to helper layer + _setHelperLayerPosition.call(self, oldHelperLayer); + _setHelperLayerPosition.call(self, oldReferenceLayer); + + //remove `introjs-fixParent` class from the elements + var fixParents = document.querySelectorAll('.introjs-fixParent'); + _forEach(fixParents, function (parent) { + _removeClass(parent, /introjs-fixParent/g); + }); + + //remove old classes if the element still exist + _removeShowElement(); + + //we should wait until the CSS3 transition is competed (it's 0.3 sec) to prevent incorrect `height` and `width` calculation + if (self._lastShowElementTimer) { + window.clearTimeout(self._lastShowElementTimer); + } + + self._lastShowElementTimer = window.setTimeout(function() { + //set current step to the label + if (oldHelperNumberLayer !== null) { + oldHelperNumberLayer.innerHTML = targetElement.step; + } + //set current tooltip text + oldtooltipLayer.innerHTML = targetElement.intro; + //set the tooltip position + oldtooltipContainer.style.display = "block"; + _placeTooltip.call(self, targetElement.element, oldtooltipContainer, oldArrowLayer, oldHelperNumberLayer); + + //change active bullet + if (self._options.showBullets) { + oldReferenceLayer.querySelector('.introjs-bullets li > a.active').className = ''; + oldReferenceLayer.querySelector('.introjs-bullets li > a[data-stepnumber="' + targetElement.step + '"]').className = 'active'; + } + oldReferenceLayer.querySelector('.introjs-progress .introjs-progressbar').style.cssText = 'width:' + _getProgress.call(self) + '%;'; + oldReferenceLayer.querySelector('.introjs-progress .introjs-progressbar').setAttribute('aria-valuenow', _getProgress.call(self)); + + //show the tooltip + oldtooltipContainer.style.opacity = 1; + if (oldHelperNumberLayer) oldHelperNumberLayer.style.opacity = 1; + + //reset button focus + if (typeof skipTooltipButton !== "undefined" && skipTooltipButton !== null && /introjs-donebutton/gi.test(skipTooltipButton.className)) { + // skip button is now "done" button + skipTooltipButton.focus(); + } else if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) { + //still in the tour, focus on next + nextTooltipButton.focus(); + } + + // change the scroll of the window, if needed + _scrollTo.call(self, targetElement.scrollTo, targetElement, oldtooltipLayer); + }, 350); + + // end of old element if-else condition + } else { + var helperLayer = document.createElement('div'), + referenceLayer = document.createElement('div'), + arrowLayer = document.createElement('div'), + tooltipLayer = document.createElement('div'), + tooltipTextLayer = document.createElement('div'), + bulletsLayer = document.createElement('div'), + progressLayer = document.createElement('div'), + buttonsLayer = document.createElement('div'); + + helperLayer.className = highlightClass; + referenceLayer.className = 'introjs-tooltipReferenceLayer'; + + // scroll to element + scrollParent = _getScrollParent( targetElement.element ); + + if (scrollParent !== document.body) { + // target is within a scrollable element + _scrollParentToElement(scrollParent, targetElement.element); + } + + //set new position to helper layer + _setHelperLayerPosition.call(self, helperLayer); + _setHelperLayerPosition.call(self, referenceLayer); + + //add helper layer to target element + this._targetElement.appendChild(helperLayer); + this._targetElement.appendChild(referenceLayer); + + arrowLayer.className = 'introjs-arrow'; + + tooltipTextLayer.className = 'introjs-tooltiptext'; + tooltipTextLayer.innerHTML = targetElement.intro; + + bulletsLayer.className = 'introjs-bullets'; + + if (this._options.showBullets === false) { + bulletsLayer.style.display = 'none'; + } + + var ulContainer = document.createElement('ul'); + ulContainer.setAttribute('role', 'tablist'); + + var anchorClick = function () { + self.goToStep(this.getAttribute('data-stepnumber')); + }; + + _forEach(this._introItems, function (item, i) { + var innerLi = document.createElement('li'); + var anchorLink = document.createElement('a'); + + innerLi.setAttribute('role', 'presentation'); + anchorLink.setAttribute('role', 'tab'); + + anchorLink.onclick = anchorClick; + + if (i === (targetElement.step-1)) { + anchorLink.className = 'active'; + } + + _setAnchorAsButton(anchorLink); + anchorLink.innerHTML = " "; + anchorLink.setAttribute('data-stepnumber', item.step); + + innerLi.appendChild(anchorLink); + ulContainer.appendChild(innerLi); + }); + + bulletsLayer.appendChild(ulContainer); + + progressLayer.className = 'introjs-progress'; + + if (this._options.showProgress === false) { + progressLayer.style.display = 'none'; + } + var progressBar = document.createElement('div'); + progressBar.className = 'introjs-progressbar'; + progressBar.setAttribute('role', 'progress'); + progressBar.setAttribute('aria-valuemin', 0); + progressBar.setAttribute('aria-valuemax', 100); + progressBar.setAttribute('aria-valuenow', _getProgress.call(this)); + progressBar.style.cssText = 'width:' + _getProgress.call(this) + '%;'; + + progressLayer.appendChild(progressBar); + + buttonsLayer.className = 'introjs-tooltipbuttons'; + if (this._options.showButtons === false) { + buttonsLayer.style.display = 'none'; + } + + tooltipLayer.className = 'introjs-tooltip'; + tooltipLayer.appendChild(tooltipTextLayer); + tooltipLayer.appendChild(bulletsLayer); + tooltipLayer.appendChild(progressLayer); + + //add helper layer number + var helperNumberLayer = document.createElement('span'); + if (this._options.showStepNumbers === true) { + helperNumberLayer.className = 'introjs-helperNumberLayer'; + helperNumberLayer.innerHTML = targetElement.step; + referenceLayer.appendChild(helperNumberLayer); + } + + tooltipLayer.appendChild(arrowLayer); + referenceLayer.appendChild(tooltipLayer); + + //next button + nextTooltipButton = document.createElement('a'); + + nextTooltipButton.onclick = function() { + if (self._introItems.length - 1 !== self._currentStep) { + _nextStep.call(self); + } + }; + + _setAnchorAsButton(nextTooltipButton); + nextTooltipButton.innerHTML = this._options.nextLabel; + + //previous button + prevTooltipButton = document.createElement('a'); + + prevTooltipButton.onclick = function() { + if (self._currentStep !== 0) { + _previousStep.call(self); + } + }; + + _setAnchorAsButton(prevTooltipButton); + prevTooltipButton.innerHTML = this._options.prevLabel; + + //skip button + skipTooltipButton = document.createElement('a'); + skipTooltipButton.className = this._options.buttonClass + ' introjs-skipbutton '; + _setAnchorAsButton(skipTooltipButton); + skipTooltipButton.innerHTML = this._options.skipLabel; + + skipTooltipButton.onclick = function() { + if (self._introItems.length - 1 === self._currentStep && typeof (self._introCompleteCallback) === 'function') { + self._introCompleteCallback.call(self); + } + + if (self._introItems.length - 1 !== self._currentStep && typeof (self._introExitCallback) === 'function') { + self._introExitCallback.call(self); + } + + if (typeof(self._introSkipCallback) === 'function') { + self._introSkipCallback.call(self); + } + + _exitIntro.call(self, self._targetElement); + }; + + buttonsLayer.appendChild(skipTooltipButton); + + //in order to prevent displaying next/previous button always + if (this._introItems.length > 1) { + buttonsLayer.appendChild(prevTooltipButton); + buttonsLayer.appendChild(nextTooltipButton); + } + + tooltipLayer.appendChild(buttonsLayer); + + //set proper position + _placeTooltip.call(self, targetElement.element, tooltipLayer, arrowLayer, helperNumberLayer); + + // change the scroll of the window, if needed + _scrollTo.call(this, targetElement.scrollTo, targetElement, tooltipLayer); + + //end of new element if-else condition + } + + // removing previous disable interaction layer + var disableInteractionLayer = self._targetElement.querySelector('.introjs-disableInteraction'); + if (disableInteractionLayer) { + disableInteractionLayer.parentNode.removeChild(disableInteractionLayer); + } + + //disable interaction + if (targetElement.disableInteraction) { + _disableInteraction.call(self); + } + + // when it's the first step of tour + if (this._currentStep === 0 && this._introItems.length > 1) { + if (typeof skipTooltipButton !== "undefined" && skipTooltipButton !== null) { + skipTooltipButton.className = this._options.buttonClass + ' introjs-skipbutton'; + } + if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) { + nextTooltipButton.className = this._options.buttonClass + ' introjs-nextbutton'; + } + + if (this._options.hidePrev === true) { + if (typeof prevTooltipButton !== "undefined" && prevTooltipButton !== null) { + prevTooltipButton.className = this._options.buttonClass + ' introjs-prevbutton introjs-hidden'; + } + if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) { + _addClass(nextTooltipButton, 'introjs-fullbutton'); + } + } else { + if (typeof prevTooltipButton !== "undefined" && prevTooltipButton !== null) { + prevTooltipButton.className = this._options.buttonClass + ' introjs-prevbutton introjs-disabled'; + } + } + + if (typeof skipTooltipButton !== "undefined" && skipTooltipButton !== null) { + skipTooltipButton.innerHTML = this._options.skipLabel; + } + } else if (this._introItems.length - 1 === this._currentStep || this._introItems.length === 1) { + // last step of tour + if (typeof skipTooltipButton !== "undefined" && skipTooltipButton !== null) { + skipTooltipButton.innerHTML = this._options.doneLabel; + // adding donebutton class in addition to skipbutton + _addClass(skipTooltipButton, 'introjs-donebutton'); + } + if (typeof prevTooltipButton !== "undefined" && prevTooltipButton !== null) { + prevTooltipButton.className = this._options.buttonClass + ' introjs-prevbutton'; + } + + if (this._options.hideNext === true) { + if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) { + nextTooltipButton.className = this._options.buttonClass + ' introjs-nextbutton introjs-hidden'; + } + if (typeof prevTooltipButton !== "undefined" && prevTooltipButton !== null) { + _addClass(prevTooltipButton, 'introjs-fullbutton'); + } + } else { + if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) { + nextTooltipButton.className = this._options.buttonClass + ' introjs-nextbutton introjs-disabled'; + } + } + } else { + // steps between start and end + if (typeof skipTooltipButton !== "undefined" && skipTooltipButton !== null) { + skipTooltipButton.className = this._options.buttonClass + ' introjs-skipbutton'; + } + if (typeof prevTooltipButton !== "undefined" && prevTooltipButton !== null) { + prevTooltipButton.className = this._options.buttonClass + ' introjs-prevbutton'; + } + if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) { + nextTooltipButton.className = this._options.buttonClass + ' introjs-nextbutton'; + } + if (typeof skipTooltipButton !== "undefined" && skipTooltipButton !== null) { + skipTooltipButton.innerHTML = this._options.skipLabel; + } + } + + prevTooltipButton.setAttribute('role', 'button'); + nextTooltipButton.setAttribute('role', 'button'); + skipTooltipButton.setAttribute('role', 'button'); + + //Set focus on "next" button, so that hitting Enter always moves you onto the next step + if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) { + nextTooltipButton.focus(); + } + + _setShowElement(targetElement); + + if (typeof (this._introAfterChangeCallback) !== 'undefined') { + this._introAfterChangeCallback.call(this, targetElement.element); + } + } + + /** + * To change the scroll of `window` after highlighting an element + * + * @api private + * @method _scrollTo + * @param {String} scrollTo + * @param {Object} targetElement + * @param {Object} tooltipLayer + */ + function _scrollTo(scrollTo, targetElement, tooltipLayer) { + if (scrollTo === 'off') return; + var rect; + + if (!this._options.scrollToElement) return; + + if (scrollTo === 'tooltip') { + rect = tooltipLayer.getBoundingClientRect(); + } else { + rect = targetElement.element.getBoundingClientRect(); + } + + if (!_elementInViewport(targetElement.element)) { + var winHeight = _getWinSize().height; + var top = rect.bottom - (rect.bottom - rect.top); + + // TODO (afshinm): do we need scroll padding now? + // I have changed the scroll option and now it scrolls the window to + // the center of the target element or tooltip. + + if (top < 0 || targetElement.element.clientHeight > winHeight) { + window.scrollBy(0, rect.top - ((winHeight / 2) - (rect.height / 2)) - this._options.scrollPadding); // 30px padding from edge to look nice + + //Scroll down + } else { + window.scrollBy(0, rect.top - ((winHeight / 2) - (rect.height / 2)) + this._options.scrollPadding); // 30px padding from edge to look nice + } + } + } + + /** + * To remove all show element(s) + * + * @api private + * @method _removeShowElement + */ + function _removeShowElement() { + var elms = document.querySelectorAll('.introjs-showElement'); + + _forEach(elms, function (elm) { + _removeClass(elm, /introjs-[a-zA-Z]+/g); + }); + } + + /** + * To set the show element + * This function set a relative (in most cases) position and changes the z-index + * + * @api private + * @method _setShowElement + * @param {Object} targetElement + */ + function _setShowElement(targetElement) { + var parentElm; + // we need to add this show element class to the parent of SVG elements + // because the SVG elements can't have independent z-index + if (targetElement.element instanceof SVGElement) { + parentElm = targetElement.element.parentNode; + + while (targetElement.element.parentNode !== null) { + if (!parentElm.tagName || parentElm.tagName.toLowerCase() === 'body') break; + + if (parentElm.tagName.toLowerCase() === 'svg') { + _addClass(parentElm, 'introjs-showElement introjs-relativePosition'); + } + + parentElm = parentElm.parentNode; + } + } + + _addClass(targetElement.element, 'introjs-showElement'); + + var currentElementPosition = _getPropValue(targetElement.element, 'position'); + if (currentElementPosition !== 'absolute' && + currentElementPosition !== 'relative' && + currentElementPosition !== 'fixed') { + //change to new intro item + _addClass(targetElement.element, 'introjs-relativePosition'); + } + + parentElm = targetElement.element.parentNode; + while (parentElm !== null) { + if (!parentElm.tagName || parentElm.tagName.toLowerCase() === 'body') break; + + //fix The Stacking Context problem. + //More detail: https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Understanding_z_index/The_stacking_context + var zIndex = _getPropValue(parentElm, 'z-index'); + var opacity = parseFloat(_getPropValue(parentElm, 'opacity')); + var transform = _getPropValue(parentElm, 'transform') || _getPropValue(parentElm, '-webkit-transform') || _getPropValue(parentElm, '-moz-transform') || _getPropValue(parentElm, '-ms-transform') || _getPropValue(parentElm, '-o-transform'); + if (/[0-9]+/.test(zIndex) || opacity < 1 || (transform !== 'none' && transform !== undefined)) { + _addClass(parentElm, 'introjs-fixParent'); + } + + parentElm = parentElm.parentNode; + } + } + + /** + * Iterates arrays + * + * @param {Array} arr + * @param {Function} forEachFnc + * @param {Function} completeFnc + * @return {Null} + */ + function _forEach(arr, forEachFnc, completeFnc) { + // in case arr is an empty query selector node list + if (arr) { + for (var i = 0, len = arr.length; i < len; i++) { + forEachFnc(arr[i], i); + } + } + + if (typeof(completeFnc) === 'function') { + completeFnc(); + } + } + + /** + * Mark any object with an incrementing number + * used for keeping track of objects + * + * @param Object obj Any object or DOM Element + * @param String key + * @return Object + */ + var _stamp = (function () { + var keys = {}; + return function stamp (obj, key) { + + // get group key + key = key || 'introjs-stamp'; + + // each group increments from 0 + keys[key] = keys[key] || 0; + + // stamp only once per object + if (obj[key] === undefined) { + // increment key for each new object + obj[key] = keys[key]++; + } + + return obj[key]; + }; + })(); + + /** + * DOMEvent Handles all DOM events + * + * methods: + * + * on - add event handler + * off - remove event + */ + var DOMEvent = (function () { + function DOMEvent () { + var events_key = 'introjs_event'; + + /** + * Gets a unique ID for an event listener + * + * @param Object obj + * @param String type event type + * @param Function listener + * @param Object context + * @return String + */ + this._id = function (obj, type, listener, context) { + return type + _stamp(listener) + (context ? '_' + _stamp(context) : ''); + }; + + /** + * Adds event listener + * + * @param Object obj + * @param String type event type + * @param Function listener + * @param Object context + * @param Boolean useCapture + * @return null + */ + this.on = function (obj, type, listener, context, useCapture) { + var id = this._id.apply(this, arguments), + handler = function (e) { + return listener.call(context || obj, e || window.event); + }; + + if ('addEventListener' in obj) { + obj.addEventListener(type, handler, useCapture); + } else if ('attachEvent' in obj) { + obj.attachEvent('on' + type, handler); + } + + obj[events_key] = obj[events_key] || {}; + obj[events_key][id] = handler; + }; + + /** + * Removes event listener + * + * @param Object obj + * @param String type event type + * @param Function listener + * @param Object context + * @param Boolean useCapture + * @return null + */ + this.off = function (obj, type, listener, context, useCapture) { + var id = this._id.apply(this, arguments), + handler = obj[events_key] && obj[events_key][id]; + + if (!handler) { + return; + } + + if ('removeEventListener' in obj) { + obj.removeEventListener(type, handler, useCapture); + } else if ('detachEvent' in obj) { + obj.detachEvent('on' + type, handler); + } + + obj[events_key][id] = null; + }; + } + + return new DOMEvent(); + })(); + + /** + * Append a class to an element + * + * @api private + * @method _addClass + * @param {Object} element + * @param {String} className + * @returns null + */ + function _addClass(element, className) { + if (element instanceof SVGElement) { + // svg + var pre = element.getAttribute('class') || ''; + + element.setAttribute('class', pre + ' ' + className); + } else { + if (element.classList !== undefined) { + // check for modern classList property + var classes = className.split(' '); + _forEach(classes, function (cls) { + element.classList.add( cls ); + }); + } else if (!element.className.match( className )) { + // check if element doesn't already have className + element.className += ' ' + className; + } + } + } + + /** + * Remove a class from an element + * + * @api private + * @method _removeClass + * @param {Object} element + * @param {RegExp|String} classNameRegex can be regex or string + * @returns null + */ + function _removeClass(element, classNameRegex) { + if (element instanceof SVGElement) { + var pre = element.getAttribute('class') || ''; + + element.setAttribute('class', pre.replace(classNameRegex, '').replace(/^\s+|\s+$/g, '')); + } else { + element.className = element.className.replace(classNameRegex, '').replace(/^\s+|\s+$/g, ''); + } + } + + /** + * Get an element CSS property on the page + * Thanks to JavaScript Kit: http://www.javascriptkit.com/dhtmltutors/dhtmlcascade4.shtml + * + * @api private + * @method _getPropValue + * @param {Object} element + * @param {String} propName + * @returns Element's property value + */ + function _getPropValue (element, propName) { + var propValue = ''; + if (element.currentStyle) { //IE + propValue = element.currentStyle[propName]; + } else if (document.defaultView && document.defaultView.getComputedStyle) { //Others + propValue = document.defaultView.getComputedStyle(element, null).getPropertyValue(propName); + } + + //Prevent exception in IE + if (propValue && propValue.toLowerCase) { + return propValue.toLowerCase(); + } else { + return propValue; + } + } + + /** + * Checks to see if target element (or parents) position is fixed or not + * + * @api private + * @method _isFixed + * @param {Object} element + * @returns Boolean + */ + function _isFixed (element) { + var p = element.parentNode; + + if (!p || p.nodeName === 'HTML') { + return false; + } + + if (_getPropValue(element, 'position') === 'fixed') { + return true; + } + + return _isFixed(p); + } + + /** + * Provides a cross-browser way to get the screen dimensions + * via: http://stackoverflow.com/questions/5864467/internet-explorer-innerheight + * + * @api private + * @method _getWinSize + * @returns {Object} width and height attributes + */ + function _getWinSize() { + if (window.innerWidth !== undefined) { + return { width: window.innerWidth, height: window.innerHeight }; + } else { + var D = document.documentElement; + return { width: D.clientWidth, height: D.clientHeight }; + } + } + + /** + * Check to see if the element is in the viewport or not + * http://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport + * + * @api private + * @method _elementInViewport + * @param {Object} el + */ + function _elementInViewport(el) { + var rect = el.getBoundingClientRect(); + + return ( + rect.top >= 0 && + rect.left >= 0 && + (rect.bottom+80) <= window.innerHeight && // add 80 to get the text right + rect.right <= window.innerWidth + ); + } + + /** + * Add overlay layer to the page + * + * @api private + * @method _addOverlayLayer + * @param {Object} targetElm + */ + function _addOverlayLayer(targetElm) { + var overlayLayer = document.createElement('div'), + styleText = '', + self = this; + + //set css class name + overlayLayer.className = 'introjs-overlay'; + + //check if the target element is body, we should calculate the size of overlay layer in a better way + if (!targetElm.tagName || targetElm.tagName.toLowerCase() === 'body') { + styleText += 'top: 0;bottom: 0; left: 0;right: 0;position: fixed;'; + overlayLayer.style.cssText = styleText; + } else { + //set overlay layer position + var elementPosition = _getOffset(targetElm); + if (elementPosition) { + styleText += 'width: ' + elementPosition.width + 'px; height:' + elementPosition.height + 'px; top:' + elementPosition.top + 'px;left: ' + elementPosition.left + 'px;'; + overlayLayer.style.cssText = styleText; + } + } + + targetElm.appendChild(overlayLayer); + + overlayLayer.onclick = function() { + if (self._options.exitOnOverlayClick === true) { + _exitIntro.call(self, targetElm); + } + }; + + window.setTimeout(function() { + styleText += 'opacity: ' + self._options.overlayOpacity.toString() + ';'; + overlayLayer.style.cssText = styleText; + }, 10); + + return true; + } + + /** + * Removes open hint (tooltip hint) + * + * @api private + * @method _removeHintTooltip + */ + function _removeHintTooltip() { + var tooltip = document.querySelector('.introjs-hintReference'); + + if (tooltip) { + var step = tooltip.getAttribute('data-step'); + tooltip.parentNode.removeChild(tooltip); + return step; + } + } + + /** + * Start parsing hint items + * + * @api private + * @param {Object} targetElm + * @method _startHint + */ + function _populateHints(targetElm) { + + this._introItems = []; + + if (this._options.hints) { + _forEach(this._options.hints, function (hint) { + var currentItem = _cloneObject(hint); + + if (typeof(currentItem.element) === 'string') { + //grab the element with given selector from the page + currentItem.element = document.querySelector(currentItem.element); + } + + currentItem.hintPosition = currentItem.hintPosition || this._options.hintPosition; + currentItem.hintAnimation = currentItem.hintAnimation || this._options.hintAnimation; + + if (currentItem.element !== null) { + this._introItems.push(currentItem); + } + }.bind(this)); + } else { + var hints = targetElm.querySelectorAll('*[data-hint]'); + + if (!hints || !hints.length) { + return false; + } + + //first add intro items with data-step + _forEach(hints, function (currentElement) { + // hint animation + var hintAnimation = currentElement.getAttribute('data-hintanimation'); + + if (hintAnimation) { + hintAnimation = (hintAnimation === 'true'); + } else { + hintAnimation = this._options.hintAnimation; + } + + this._introItems.push({ + element: currentElement, + hint: currentElement.getAttribute('data-hint'), + hintPosition: currentElement.getAttribute('data-hintposition') || this._options.hintPosition, + hintAnimation: hintAnimation, + tooltipClass: currentElement.getAttribute('data-tooltipclass'), + position: currentElement.getAttribute('data-position') || this._options.tooltipPosition + }); + }.bind(this)); + } + + _addHints.call(this); + + /* + todo: + these events should be removed at some point + */ + DOMEvent.on(document, 'click', _removeHintTooltip, this, false); + DOMEvent.on(window, 'resize', _reAlignHints, this, true); + } + + /** + * Re-aligns all hint elements + * + * @api private + * @method _reAlignHints + */ + function _reAlignHints() { + _forEach(this._introItems, function (item) { + if (typeof(item.targetElement) === 'undefined') { + return; + } + + _alignHintPosition.call(this, item.hintPosition, item.element, item.targetElement); + }.bind(this)); + } + + /** + * Get a queryselector within the hint wrapper + * + * @param {String} selector + * @return {NodeList|Array} + */ + function _hintQuerySelectorAll(selector) { + var hintsWrapper = document.querySelector('.introjs-hints'); + return (hintsWrapper) ? hintsWrapper.querySelectorAll(selector) : []; + } + + /** + * Hide a hint + * + * @api private + * @method _hideHint + */ + function _hideHint(stepId) { + var hint = _hintQuerySelectorAll('.introjs-hint[data-step="' + stepId + '"]')[0]; + + _removeHintTooltip.call(this); + + if (hint) { + _addClass(hint, 'introjs-hidehint'); + } + + // call the callback function (if any) + if (typeof (this._hintCloseCallback) !== 'undefined') { + this._hintCloseCallback.call(this, stepId); + } + } + + /** + * Hide all hints + * + * @api private + * @method _hideHints + */ + function _hideHints() { + var hints = _hintQuerySelectorAll('.introjs-hint'); + + _forEach(hints, function (hint) { + _hideHint.call(this, hint.getAttribute('data-step')); + }.bind(this)); + } + + /** + * Show all hints + * + * @api private + * @method _showHints + */ + function _showHints() { + var hints = _hintQuerySelectorAll('.introjs-hint'); + + if (hints && hints.length) { + _forEach(hints, function (hint) { + _showHint.call(this, hint.getAttribute('data-step')); + }.bind(this)); + } else { + _populateHints.call(this, this._targetElement); + } + } + + /** + * Show a hint + * + * @api private + * @method _showHint + */ + function _showHint(stepId) { + var hint = _hintQuerySelectorAll('.introjs-hint[data-step="' + stepId + '"]')[0]; + + if (hint) { + _removeClass(hint, /introjs-hidehint/g); + } + } + + /** + * Removes all hint elements on the page + * Useful when you want to destroy the elements and add them again (e.g. a modal or popup) + * + * @api private + * @method _removeHints + */ + function _removeHints() { + var hints = _hintQuerySelectorAll('.introjs-hint'); + + _forEach(hints, function (hint) { + _removeHint.call(this, hint.getAttribute('data-step')); + }.bind(this)); + } + + /** + * Remove one single hint element from the page + * Useful when you want to destroy the element and add them again (e.g. a modal or popup) + * Use removeHints if you want to remove all elements. + * + * @api private + * @method _removeHint + */ + function _removeHint(stepId) { + var hint = _hintQuerySelectorAll('.introjs-hint[data-step="' + stepId + '"]')[0]; + + if (hint) { + hint.parentNode.removeChild(hint); + } + } + + /** + * Add all available hints to the page + * + * @api private + * @method _addHints + */ + function _addHints() { + var self = this; + + var hintsWrapper = document.querySelector('.introjs-hints'); + + if (hintsWrapper === null) { + hintsWrapper = document.createElement('div'); + hintsWrapper.className = 'introjs-hints'; + } + + /** + * Returns an event handler unique to the hint iteration + * + * @param {Integer} i + * @return {Function} + */ + var getHintClick = function (i) { + return function(e) { + var evt = e ? e : window.event; + + if (evt.stopPropagation) { + evt.stopPropagation(); + } + + if (evt.cancelBubble !== null) { + evt.cancelBubble = true; + } + + _showHintDialog.call(self, i); + }; + }; + + _forEach(this._introItems, function(item, i) { + // avoid append a hint twice + if (document.querySelector('.introjs-hint[data-step="' + i + '"]')) { + return; + } + + var hint = document.createElement('a'); + _setAnchorAsButton(hint); + + hint.onclick = getHintClick(i); + + hint.className = 'introjs-hint'; + + if (!item.hintAnimation) { + _addClass(hint, 'introjs-hint-no-anim'); + } + + // hint's position should be fixed if the target element's position is fixed + if (_isFixed(item.element)) { + _addClass(hint, 'introjs-fixedhint'); + } + + var hintDot = document.createElement('div'); + hintDot.className = 'introjs-hint-dot'; + var hintPulse = document.createElement('div'); + hintPulse.className = 'introjs-hint-pulse'; + + hint.appendChild(hintDot); + hint.appendChild(hintPulse); + hint.setAttribute('data-step', i); + + // we swap the hint element with target element + // because _setHelperLayerPosition uses `element` property + item.targetElement = item.element; + item.element = hint; + + // align the hint position + _alignHintPosition.call(this, item.hintPosition, hint, item.targetElement); + + hintsWrapper.appendChild(hint); + }.bind(this)); + + // adding the hints wrapper + document.body.appendChild(hintsWrapper); + + // call the callback function (if any) + if (typeof (this._hintsAddedCallback) !== 'undefined') { + this._hintsAddedCallback.call(this); + } + } + + /** + * Aligns hint position + * + * @api private + * @method _alignHintPosition + * @param {String} position + * @param {Object} hint + * @param {Object} element + */ + function _alignHintPosition(position, hint, element) { + // get/calculate offset of target element + var offset = _getOffset.call(this, element); + var iconWidth = 20; + var iconHeight = 20; + + // align the hint element + switch (position) { + default: + case 'top-left': + hint.style.left = offset.left + 'px'; + hint.style.top = offset.top + 'px'; + break; + case 'top-right': + hint.style.left = (offset.left + offset.width - iconWidth) + 'px'; + hint.style.top = offset.top + 'px'; + break; + case 'bottom-left': + hint.style.left = offset.left + 'px'; + hint.style.top = (offset.top + offset.height - iconHeight) + 'px'; + break; + case 'bottom-right': + hint.style.left = (offset.left + offset.width - iconWidth) + 'px'; + hint.style.top = (offset.top + offset.height - iconHeight) + 'px'; + break; + case 'middle-left': + hint.style.left = offset.left + 'px'; + hint.style.top = (offset.top + (offset.height - iconHeight) / 2) + 'px'; + break; + case 'middle-right': + hint.style.left = (offset.left + offset.width - iconWidth) + 'px'; + hint.style.top = (offset.top + (offset.height - iconHeight) / 2) + 'px'; + break; + case 'middle-middle': + hint.style.left = (offset.left + (offset.width - iconWidth) / 2) + 'px'; + hint.style.top = (offset.top + (offset.height - iconHeight) / 2) + 'px'; + break; + case 'bottom-middle': + hint.style.left = (offset.left + (offset.width - iconWidth) / 2) + 'px'; + hint.style.top = (offset.top + offset.height - iconHeight) + 'px'; + break; + case 'top-middle': + hint.style.left = (offset.left + (offset.width - iconWidth) / 2) + 'px'; + hint.style.top = offset.top + 'px'; + break; + } + } + + /** + * Triggers when user clicks on the hint element + * + * @api private + * @method _showHintDialog + * @param {Number} stepId + */ + function _showHintDialog(stepId) { + var hintElement = document.querySelector('.introjs-hint[data-step="' + stepId + '"]'); + var item = this._introItems[stepId]; + + // call the callback function (if any) + if (typeof (this._hintClickCallback) !== 'undefined') { + this._hintClickCallback.call(this, hintElement, item, stepId); + } + + // remove all open tooltips + var removedStep = _removeHintTooltip.call(this); + + // to toggle the tooltip + if (parseInt(removedStep, 10) === stepId) { + return; + } + + var tooltipLayer = document.createElement('div'); + var tooltipTextLayer = document.createElement('div'); + var arrowLayer = document.createElement('div'); + var referenceLayer = document.createElement('div'); + + tooltipLayer.className = 'introjs-tooltip'; + + tooltipLayer.onclick = function (e) { + //IE9 & Other Browsers + if (e.stopPropagation) { + e.stopPropagation(); + } + //IE8 and Lower + else { + e.cancelBubble = true; + } + }; + + tooltipTextLayer.className = 'introjs-tooltiptext'; + + var tooltipWrapper = document.createElement('p'); + tooltipWrapper.innerHTML = item.hint; + + var closeButton = document.createElement('a'); + closeButton.className = this._options.buttonClass; + closeButton.setAttribute('role', 'button'); + closeButton.innerHTML = this._options.hintButtonLabel; + closeButton.onclick = _hideHint.bind(this, stepId); + + tooltipTextLayer.appendChild(tooltipWrapper); + tooltipTextLayer.appendChild(closeButton); + + arrowLayer.className = 'introjs-arrow'; + tooltipLayer.appendChild(arrowLayer); + + tooltipLayer.appendChild(tooltipTextLayer); + + // set current step for _placeTooltip function + this._currentStep = hintElement.getAttribute('data-step'); + + // align reference layer position + referenceLayer.className = 'introjs-tooltipReferenceLayer introjs-hintReference'; + referenceLayer.setAttribute('data-step', hintElement.getAttribute('data-step')); + _setHelperLayerPosition.call(this, referenceLayer); + + referenceLayer.appendChild(tooltipLayer); + document.body.appendChild(referenceLayer); + + //set proper position + _placeTooltip.call(this, hintElement, tooltipLayer, arrowLayer, null, true); + } + + /** + * Get an element position on the page + * Thanks to `meouw`: http://stackoverflow.com/a/442474/375966 + * + * @api private + * @method _getOffset + * @param {Object} element + * @returns Element's position info + */ + function _getOffset(element) { + var body = document.body; + var docEl = document.documentElement; + var scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop; + var scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft; + var x = element.getBoundingClientRect(); + return { + top: x.top + scrollTop, + width: x.width, + height: x.height, + left: x.left + scrollLeft + }; + } + + /** + * Find the nearest scrollable parent + * copied from https://stackoverflow.com/questions/35939886/find-first-scrollable-parent + * + * @param Element element + * @return Element + */ + function _getScrollParent(element) { + var style = window.getComputedStyle(element); + var excludeStaticParent = (style.position === "absolute"); + var overflowRegex = /(auto|scroll)/; + + if (style.position === "fixed") return document.body; + + for (var parent = element; (parent = parent.parentElement);) { + style = window.getComputedStyle(parent); + if (excludeStaticParent && style.position === "static") { + continue; + } + if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX)) return parent; + } + + return document.body; + } + + /** + * scroll a scrollable element to a child element + * + * @param Element parent + * @param Element element + * @return Null + */ + function _scrollParentToElement (parent, element) { + parent.scrollTop = element.offsetTop - parent.offsetTop; + } + + /** + * Gets the current progress percentage + * + * @api private + * @method _getProgress + * @returns current progress percentage + */ + function _getProgress() { + // Steps are 0 indexed + var currentStep = parseInt((this._currentStep + 1), 10); + return ((currentStep / this._introItems.length) * 100); + } + + /** + * Overwrites obj1's values with obj2's and adds obj2's if non existent in obj1 + * via: http://stackoverflow.com/questions/171251/how-can-i-merge-properties-of-two-javascript-objects-dynamically + * + * @param obj1 + * @param obj2 + * @returns obj3 a new object based on obj1 and obj2 + */ + function _mergeOptions(obj1,obj2) { + var obj3 = {}, + attrname; + for (attrname in obj1) { obj3[attrname] = obj1[attrname]; } + for (attrname in obj2) { obj3[attrname] = obj2[attrname]; } + return obj3; + } + + var introJs = function (targetElm) { + var instance; + + if (typeof (targetElm) === 'object') { + //Ok, create a new instance + instance = new IntroJs(targetElm); + + } else if (typeof (targetElm) === 'string') { + //select the target element with query selector + var targetElement = document.querySelector(targetElm); + + if (targetElement) { + instance = new IntroJs(targetElement); + } else { + throw new Error('There is no element with given selector.'); + } + } else { + instance = new IntroJs(document.body); + } + // add instance to list of _instances + // passing group to _stamp to increment + // from 0 onward somewhat reliably + introJs.instances[ _stamp(instance, 'introjs-instance') ] = instance; + + return instance; + }; + + /** + * Current IntroJs version + * + * @property version + * @type String + */ + introJs.version = VERSION; + + /** + * key-val object helper for introJs instances + * + * @property instances + * @type Object + */ + introJs.instances = {}; + + //Prototype + introJs.fn = IntroJs.prototype = { + clone: function () { + return new IntroJs(this); + }, + setOption: function(option, value) { + this._options[option] = value; + return this; + }, + setOptions: function(options) { + this._options = _mergeOptions(this._options, options); + return this; + }, + start: function (group) { + _introForElement.call(this, this._targetElement, group); + return this; + }, + goToStep: function(step) { + _goToStep.call(this, step); + return this; + }, + addStep: function(options) { + if (!this._options.steps) { + this._options.steps = []; + } + + this._options.steps.push(options); + + return this; + }, + addSteps: function(steps) { + if (!steps.length) return; + + for(var index = 0; index < steps.length; index++) { + this.addStep(steps[index]); + } + + return this; + }, + goToStepNumber: function(step) { + _goToStepNumber.call(this, step); + + return this; + }, + nextStep: function() { + _nextStep.call(this); + return this; + }, + previousStep: function() { + _previousStep.call(this); + return this; + }, + exit: function(force) { + _exitIntro.call(this, this._targetElement, force); + return this; + }, + refresh: function() { + _refresh.call(this); + return this; + }, + onbeforechange: function(providedCallback) { + if (typeof (providedCallback) === 'function') { + this._introBeforeChangeCallback = providedCallback; + } else { + throw new Error('Provided callback for onbeforechange was not a function'); + } + return this; + }, + onchange: function(providedCallback) { + if (typeof (providedCallback) === 'function') { + this._introChangeCallback = providedCallback; + } else { + throw new Error('Provided callback for onchange was not a function.'); + } + return this; + }, + onafterchange: function(providedCallback) { + if (typeof (providedCallback) === 'function') { + this._introAfterChangeCallback = providedCallback; + } else { + throw new Error('Provided callback for onafterchange was not a function'); + } + return this; + }, + oncomplete: function(providedCallback) { + if (typeof (providedCallback) === 'function') { + this._introCompleteCallback = providedCallback; + } else { + throw new Error('Provided callback for oncomplete was not a function.'); + } + return this; + }, + onhintsadded: function(providedCallback) { + if (typeof (providedCallback) === 'function') { + this._hintsAddedCallback = providedCallback; + } else { + throw new Error('Provided callback for onhintsadded was not a function.'); + } + return this; + }, + onhintclick: function(providedCallback) { + if (typeof (providedCallback) === 'function') { + this._hintClickCallback = providedCallback; + } else { + throw new Error('Provided callback for onhintclick was not a function.'); + } + return this; + }, + onhintclose: function(providedCallback) { + if (typeof (providedCallback) === 'function') { + this._hintCloseCallback = providedCallback; + } else { + throw new Error('Provided callback for onhintclose was not a function.'); + } + return this; + }, + onexit: function(providedCallback) { + if (typeof (providedCallback) === 'function') { + this._introExitCallback = providedCallback; + } else { + throw new Error('Provided callback for onexit was not a function.'); + } + return this; + }, + onskip: function(providedCallback) { + if (typeof (providedCallback) === 'function') { + this._introSkipCallback = providedCallback; + } else { + throw new Error('Provided callback for onskip was not a function.'); + } + return this; + }, + onbeforeexit: function(providedCallback) { + if (typeof (providedCallback) === 'function') { + this._introBeforeExitCallback = providedCallback; + } else { + throw new Error('Provided callback for onbeforeexit was not a function.'); + } + return this; + }, + addHints: function() { + _populateHints.call(this, this._targetElement); + return this; + }, + hideHint: function (stepId) { + _hideHint.call(this, stepId); + return this; + }, + hideHints: function () { + _hideHints.call(this); + return this; + }, + showHint: function (stepId) { + _showHint.call(this, stepId); + return this; + }, + showHints: function () { + _showHints.call(this); + return this; + }, + removeHints: function () { + _removeHints.call(this); + return this; + }, + removeHint: function (stepId) { + _removeHint.call(this, stepId); + return this; + }, + showHintDialog: function (stepId) { + _showHintDialog.call(this, stepId); + return this; + } + }; + + return introJs; +}); \ No newline at end of file diff --git a/www/introbutton.js b/www/introbutton.js new file mode 100644 index 0000000..78314ff --- /dev/null +++ b/www/introbutton.js @@ -0,0 +1,30 @@ +document.addEventListener('DOMContentLoaded', function() { + var selector = document.getElementById("btnAddNetwork"); + selector.setAttribute("data-step", "1"); + selector.setAttribute("data-intro", "The network file is an obligatory, 2-column (or 3-column for weighted), tab-delimited file, containing all network connections of an undirected network. This file must contain headers, namely: 'Source' and 'Target'. Press this button to upload your network file"); + selector.setAttribute("data-position", "bottom"); + + selector = document.getElementById("uiLoadGraphOptionsOutput"); + selector.setAttribute("data-step", "2"); + selector.setAttribute("data-intro", "If the network is weighted (3 columns), check this box to allow weighted visualization."); + selector.setAttribute("data-position", "bottom"); + + selector = document.getElementById("btnAddNetwork2"); + selector.setAttribute("data-step", "3"); + selector.setAttribute("data-intro", "The annotation file is an obligatory, 2-column, tab-delimited file which contains information about the defined groups. The first column contains the group names whereas the second column contains the node names in a group separated by a comma (,) and without spaces. No headers are allowed. Press this button to upload your annotation file"); + selector.setAttribute("data-position", "bottom"); + + selector = document.getElementById("btnAddExpression"); + selector.setAttribute("data-step", "4"); + selector.setAttribute("data-intro", "The expression file is an optional, 2-column, tab-delimited file to allow node coloring (e.g. gene expressions). The first column contains the node names and the second column the node colors (color names or hex codes (e.g. Green or #00ff00, Red or #ff0000, Yellow or #ffff00)). Press this button to upload your node - coloring file"); + selector.setAttribute("data-position", "bottom"); + + selector = document.getElementById("introButton"); + selector.setAttribute("data-step", "5"); + selector.setAttribute("data-intro", "For more details, please check Help Pages tab."); + selector.setAttribute("data-position", "bottom"); + + document.getElementById("introButton").onclick = function(){ + introJs().start(); + }; +}, false); diff --git a/www/norma.css b/www/norma.css new file mode 100644 index 0000000..e0ba15e --- /dev/null +++ b/www/norma.css @@ -0,0 +1,91 @@ +body{ + text-align: justify; +} + +hr {border-top: 1px solid #000000;} + +td { + line-height: 1.2 !important; +} + +.well{ + margin-bottom: 0 !important; + padding-top: 0 !important; + padding-bottom: 0 !important; +} + +.box-panel { + border-radius: 0 0 5px 5px; + border-width: 1px; + border-color: #d7d7d7; + border-style: none solid solid solid; +} + +.box-panel-padding { + padding: 20px 20px 20px 20px; +} + +.tabBox-panel { + padding: 20px 20px 20px 20px; + border-width: 1px; + border-color: #d7d7d7; + border-radius: 0px 0px 8px 8px; + border-style: none solid solid solid; + background: #ffffff; +} + +.centerBlock { + float: none; + margin: 0 auto; +} + +.dataTables_wrapper td { + line-height: 80%; +} + +.strategies{ + background-color: #fff7f1; + border: 1px solid #ff9300; + border-radius: 25px; + padding: 5px; + padding-bottom: 0; + font-size: 1.2em; + display: block; +} + +.strategies > div{ + display: inline-block; + width: 45% !important; + margin: 20px; + margin-bottom: 5px; +} + +.strategies > div:nth-child(5){ + position: relative; + top: -87px; +} + +.irs-single{ + background-color: #2C8160 !important; +} + +.irs-bar{ + background: #2C8160 !important; +} + +.layout_strat_img{ + margin-left: auto; + margin-right: auto; + display: block; +} + +#introButton{ + width: 100%; + margin-top: 15px; +} + +@media only screen and (max-width: 991px) { + .strategies > div:nth-child(5){ + top: 0; + } +}

    +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�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°=SwmdYVf7LyDKZ`GC%^Mp? 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 F{{c|jDS`k1 literal 0 HcmV?d00001 diff --git a/www/Figures/Expression_colors.png b/www/Figures/Expression_colors.png new file mode 100644 index 0000000000000000000000000000000000000000..cf94364522d9c5be596423ecdf95135129fcd4a6 GIT binary patch literal 128780 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%0DqF+B!zAkR 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