@inflexa-ai/harness 0.45.0 → 0.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -3
- package/dist/agents/conversation-agent.d.ts +19 -3
- package/dist/agents/conversation-agent.js +49 -30
- package/dist/agents/report-session-agent.d.ts +15 -15
- package/dist/agents/report-session-agent.js +23 -15
- package/dist/agents/sandbox/index.d.ts +1 -1
- package/dist/agents/sandbox/index.js +1 -1
- package/dist/agents/sandbox/shared.d.ts +35 -16
- package/dist/agents/sandbox/shared.js +63 -24
- package/dist/agents/sandbox/translational-safety-agent.js +26 -0
- package/dist/agents/sandbox/types.d.ts +26 -3
- package/dist/agents/sandbox/validate-skills.d.ts +2 -2
- package/dist/agents/sandbox/validate-skills.js +3 -1
- package/dist/agents/sandbox-catalog.d.ts +16 -2
- package/dist/agents/sandbox-catalog.js +22 -3
- package/dist/agents/system-prompt.d.ts +2 -2
- package/dist/app/approve-plan.d.ts +5 -2
- package/dist/app/approve-plan.js +1 -1
- package/dist/app/chat-turn-workflow.d.ts +114 -0
- package/dist/app/chat-turn-workflow.js +307 -0
- package/dist/app/chat-turn.d.ts +85 -57
- package/dist/app/chat-turn.js +125 -99
- package/dist/app/data-profile-orientation.js +10 -8
- package/dist/app/data-profile-view.d.ts +4 -4
- package/dist/app/data-profile-view.js +9 -8
- package/dist/app/in-process-turn.d.ts +42 -0
- package/dist/app/in-process-turn.js +139 -0
- package/dist/app/message-assembly.d.ts +10 -4
- package/dist/app/message-assembly.js +13 -8
- package/dist/app/report-session-runtime.d.ts +4 -4
- package/dist/app/report-session-runtime.js +36 -21
- package/dist/app/spawn-report-session.d.ts +33 -28
- package/dist/app/spawn-report-session.js +25 -40
- package/dist/app/synthesize-run.d.ts +22 -16
- package/dist/app/synthesize-run.js +41 -35
- package/dist/app/work.d.ts +96 -0
- package/dist/app/work.js +147 -0
- package/dist/auth/local-auth-context.d.ts +1 -3
- package/dist/auth/local-auth-context.js +1 -3
- package/dist/auth/local-run-authorizer.d.ts +1 -1
- package/dist/auth/local-run-authorizer.js +5 -3
- package/dist/auth/types.d.ts +26 -26
- package/dist/billing/cached-resolver.d.ts +4 -4
- package/dist/billing/run-charge.d.ts +5 -8
- package/dist/billing/run-charge.js +2 -2
- package/dist/billing/usage-recorder.d.ts +9 -9
- package/dist/citations/aggregate.js +1 -1
- package/dist/citations/clients/arxiv.d.ts +2 -2
- package/dist/citations/clients/arxiv.js +12 -4
- package/dist/citations/clients/common.js +4 -2
- package/dist/citations/clients/crossref.d.ts +2 -2
- package/dist/citations/clients/crossref.js +37 -37
- package/dist/citations/clients/doi-registry.js +15 -16
- package/dist/citations/clients/pubmed.d.ts +2 -2
- package/dist/citations/clients/pubmed.js +20 -13
- package/dist/citations/clients/semantic-scholar.d.ts +2 -2
- package/dist/citations/clients/semantic-scholar.js +9 -9
- package/dist/citations/compare.js +2 -2
- package/dist/citations/match.d.ts +2 -2
- package/dist/citations/match.js +12 -7
- package/dist/citations/normalize.js +35 -26
- package/dist/citations/plan.js +6 -2
- package/dist/citations/resolve.d.ts +6 -6
- package/dist/citations/resolve.js +34 -25
- package/dist/citations/types.d.ts +77 -77
- package/dist/config/environment-stores.d.ts +10 -8
- package/dist/config/resource-limits.js +1 -3
- package/dist/contracts/analogy-report.d.ts +7 -7
- package/dist/contracts/analogy-report.js +2 -2
- package/dist/contracts/chat-events.d.ts +46 -22
- package/dist/contracts/chat-events.js +1 -1
- package/dist/contracts/chat-frame.d.ts +15 -5
- package/dist/contracts/chat-frame.js +67 -40
- package/dist/contracts/chat-parts.d.ts +130 -67
- package/dist/contracts/chat-parts.js +1 -0
- package/dist/contracts/content-url.js +16 -2
- package/dist/contracts/data-profile.d.ts +38 -38
- package/dist/contracts/index.d.ts +3 -3
- package/dist/contracts/index.js +1 -1
- package/dist/contracts/message.d.ts +6 -6
- package/dist/contracts/organ-system.d.ts +11 -11
- package/dist/contracts/part-registry.d.ts +5 -4
- package/dist/contracts/part-registry.js +5 -0
- package/dist/contracts/profile-vocabulary.d.ts +11 -10
- package/dist/contracts/profile-vocabulary.js +10 -3
- package/dist/contracts/report-blocks.d.ts +329 -329
- package/dist/contracts/report-reference.d.ts +105 -81
- package/dist/contracts/report-reference.js +30 -13
- package/dist/contracts/schemas/chat-events.d.ts +45 -6
- package/dist/contracts/schemas/chat-events.js +16 -0
- package/dist/contracts/schemas/chat-parts.d.ts +214 -102
- package/dist/contracts/schemas/chat-parts.js +50 -7
- package/dist/contracts/schemas/index.d.ts +1 -1
- package/dist/contracts/schemas/index.js +1 -1
- package/dist/contracts/severity.d.ts +1 -1
- package/dist/contracts/structure-source.d.ts +3 -3
- package/dist/contracts/structure-source.js +6 -2
- package/dist/contracts/subagent-activity.d.ts +2 -2
- package/dist/contracts/subagent-activity.js +5 -3
- package/dist/contracts/usage.d.ts +2 -2
- package/dist/data/safety-panel-schema.d.ts +25 -25
- package/dist/data/safety-panel-schema.js +13 -4
- package/dist/execution/artifact-metadata.d.ts +23 -15
- package/dist/execution/artifact-metadata.js +33 -10
- package/dist/execution/artifact-record.d.ts +2 -2
- package/dist/execution/artifact-registration.d.ts +5 -5
- package/dist/execution/artifact-registry.d.ts +8 -8
- package/dist/execution/dbos-run-launcher.d.ts +24 -4
- package/dist/execution/dbos-run-launcher.js +58 -4
- package/dist/execution/dbos-workflow-purger.d.ts +7 -6
- package/dist/execution/dbos-workflow-purger.js +29 -21
- package/dist/execution/input-signature.d.ts +2 -2
- package/dist/execution/post-step-pipeline.d.ts +9 -9
- package/dist/execution/post-step-pipeline.js +1 -1
- package/dist/execution/post-step.js +2 -2
- package/dist/execution/reconcile-manifest.d.ts +4 -4
- package/dist/execution/reconcile-manifest.js +3 -2
- package/dist/execution/run-authorizer.d.ts +46 -37
- package/dist/execution/run-authorizer.js +8 -8
- package/dist/execution/run-canceler.d.ts +39 -17
- package/dist/execution/run-canceler.js +137 -28
- package/dist/execution/run-end-record.d.ts +29 -0
- package/dist/execution/run-end-record.js +27 -0
- package/dist/execution/run-event-parts.d.ts +0 -8
- package/dist/execution/run-event-parts.js +29 -24
- package/dist/execution/run-event-stream.d.ts +8 -8
- package/dist/execution/run-event-stream.js +3 -4
- package/dist/execution/run-launcher.d.ts +4 -4
- package/dist/execution/run-synthesis.d.ts +49 -48
- package/dist/execution/run-synthesis.js +96 -255
- package/dist/execution/staged-input.d.ts +2 -2
- package/dist/execution/step-summary.d.ts +6 -6
- package/dist/execution/step-summary.js +4 -8
- package/dist/execution/topo-sort.js +4 -3
- package/dist/execution/workflow-purger.d.ts +2 -2
- package/dist/index.d.ts +25 -24
- package/dist/index.js +36 -37
- package/dist/input-sanitization.js +9 -2
- package/dist/input-scan/clustering.d.ts +6 -6
- package/dist/input-scan/clustering.js +11 -5
- package/dist/input-scan/companions.js +3 -2
- package/dist/input-scan/detect-sets.d.ts +2 -2
- package/dist/input-scan/detect-sets.js +25 -21
- package/dist/input-scan/enrich.d.ts +6 -6
- package/dist/input-scan/enrich.js +29 -12
- package/dist/input-scan/formats.d.ts +2 -2
- package/dist/input-scan/formats.js +8 -2
- package/dist/input-scan/markers.d.ts +2 -2
- package/dist/input-scan/markers.js +14 -5
- package/dist/input-scan/menu.d.ts +10 -10
- package/dist/input-scan/menu.js +0 -0
- package/dist/input-scan/quarantine.d.ts +2 -2
- package/dist/input-scan/quarantine.js +23 -18
- package/dist/input-scan/readout-budget.d.ts +2 -2
- package/dist/input-scan/readout-budget.js +1 -1
- package/dist/input-scan/readout.d.ts +2 -2
- package/dist/input-scan/readout.js +47 -34
- package/dist/input-scan/scan.d.ts +2 -2
- package/dist/input-scan/scan.js +7 -5
- package/dist/input-scan/set-types.d.ts +28 -28
- package/dist/input-scan/shapes.d.ts +4 -4
- package/dist/input-scan/shapes.js +0 -0
- package/dist/input-scan/templates.d.ts +10 -10
- package/dist/input-scan/templates.js +30 -22
- package/dist/input-scan/tokens.d.ts +6 -4
- package/dist/input-scan/tokens.js +100 -38
- package/dist/input-scan/types.d.ts +22 -22
- package/dist/lib/async-utils.d.ts +3 -7
- package/dist/lib/async-utils.js +5 -9
- package/dist/lib/cache.js +1 -1
- package/dist/lib/chrome.d.ts +46 -6
- package/dist/lib/console-logger.js +2 -2
- package/dist/lib/db-result.d.ts +22 -6
- package/dist/lib/db-result.js +9 -13
- package/dist/lib/eyes.d.ts +4 -4
- package/dist/lib/eyes.js +1 -1
- package/dist/lib/fs-helpers.js +18 -6
- package/dist/lib/fs-result.d.ts +1 -0
- package/dist/lib/fs-result.js +5 -6
- package/dist/lib/hooks.d.ts +23 -7
- package/dist/lib/hooks.js +17 -3
- package/dist/lib/host-concurrency.js +3 -2
- package/dist/lib/logger.d.ts +2 -2
- package/dist/lib/logger.js +2 -1
- package/dist/lib/metrics.d.ts +1 -1
- package/dist/lib/null-proto.d.ts +6 -0
- package/dist/lib/null-proto.js +17 -0
- package/dist/lib/otel-spans.d.ts +1 -1
- package/dist/lib/otel-spans.js +9 -5
- package/dist/lib/otel.d.ts +4 -2
- package/dist/lib/otel.js +10 -2
- package/dist/lib/page-capture.d.ts +8 -8
- package/dist/lib/page-capture.js +9 -4
- package/dist/lib/parse-json.d.ts +5 -0
- package/dist/lib/parse-json.js +12 -0
- package/dist/lib/present.d.ts +12 -0
- package/dist/lib/present.js +39 -0
- package/dist/lib/rate-limit.d.ts +4 -4
- package/dist/lib/rate-limit.js +12 -13
- package/dist/lib/regulatory-corpus/fetch-fda-guidance.d.ts +4 -4
- package/dist/lib/regulatory-corpus/fetch-fda-guidance.js +4 -10
- package/dist/lib/regulatory-corpus/fetch-ich.d.ts +4 -4
- package/dist/lib/regulatory-corpus/fetch-ich.js +18 -14
- package/dist/lib/regulatory-corpus/normalize-whitespace.d.ts +6 -0
- package/dist/lib/regulatory-corpus/normalize-whitespace.js +41 -0
- package/dist/lib/regulatory-corpus.d.ts +10 -10
- package/dist/lib/regulatory-corpus.js +3 -1
- package/dist/lib/result.d.ts +10 -11
- package/dist/lib/result.js +15 -13
- package/dist/lib/storage.d.ts +2 -2
- package/dist/lib/test/async-iterable.d.ts +9 -0
- package/dist/lib/test/async-iterable.js +28 -0
- package/dist/lib/test/request-url.d.ts +5 -0
- package/dist/lib/test/request-url.js +7 -0
- package/dist/lib/test/result-assert.d.ts +12 -0
- package/dist/lib/test/result-assert.js +17 -0
- package/dist/lib/test/text-shapes.d.ts +24 -0
- package/dist/lib/test/text-shapes.js +63 -0
- package/dist/lib/text.d.ts +22 -0
- package/dist/lib/text.js +68 -0
- package/dist/lib/thrown.d.ts +18 -0
- package/dist/lib/thrown.js +30 -0
- package/dist/lib/unknown-array.d.ts +6 -0
- package/dist/lib/unknown-array.js +8 -0
- package/dist/lib/unknown-containers.d.ts +14 -0
- package/dist/lib/unknown-containers.js +17 -0
- package/dist/lib/unknown-text.d.ts +8 -0
- package/dist/lib/unknown-text.js +28 -0
- package/dist/lib/zod-issue-shape.d.ts +1 -1
- package/dist/lib/zod-issue-shape.js +31 -31
- package/dist/lib/zod-issues.d.ts +3 -3
- package/dist/lib/zod-issues.js +30 -17
- package/dist/literature/sources/arxiv.d.ts +6 -6
- package/dist/literature/sources/arxiv.js +92 -35
- package/dist/literature/sources/http.d.ts +2 -2
- package/dist/literature/sources/http.js +16 -15
- package/dist/literature/sources/pubmed.d.ts +16 -16
- package/dist/literature/sources/pubmed.js +96 -61
- package/dist/literature/sources/semantic-scholar.d.ts +8 -8
- package/dist/literature/sources/semantic-scholar.js +22 -13
- package/dist/loop/accounting.d.ts +63 -0
- package/dist/loop/accounting.js +141 -0
- package/dist/loop/call-policy.d.ts +73 -0
- package/dist/loop/call-policy.js +109 -0
- package/dist/loop/chat-stream.d.ts +62 -0
- package/dist/loop/chat-stream.js +237 -0
- package/dist/loop/compaction.d.ts +14 -9
- package/dist/loop/compaction.js +17 -0
- package/dist/loop/metrics.d.ts +12 -15
- package/dist/loop/metrics.js +14 -26
- package/dist/loop/run-loop.d.ts +233 -0
- package/dist/loop/run-loop.js +770 -0
- package/dist/loop/sub-agent.d.ts +61 -0
- package/dist/loop/sub-agent.js +161 -0
- package/dist/loop/tool-adapter.d.ts +98 -0
- package/dist/loop/tool-adapter.js +364 -0
- package/dist/loop/tool-detail.d.ts +1 -1
- package/dist/loop/tool-detail.js +6 -5
- package/dist/loop/tool-outcome.d.ts +1 -1
- package/dist/loop/tool-output.d.ts +4 -4
- package/dist/loop/tool-output.js +2 -2
- package/dist/loop/turn-credentials.d.ts +34 -0
- package/dist/loop/turn-credentials.js +73 -0
- package/dist/loop/types.d.ts +34 -37
- package/dist/loop/types.js +2 -7
- package/dist/memory/ai-sdk-message-storage.d.ts +5 -5
- package/dist/memory/ai-sdk-message-storage.js +13 -11
- package/dist/memory/card-builders.d.ts +14 -14
- package/dist/memory/card-builders.js +19 -15
- package/dist/memory/conversation-display-recorder.d.ts +22 -6
- package/dist/memory/conversation-display-recorder.js +64 -20
- package/dist/memory/conversation-display-replay.js +3 -2
- package/dist/memory/conversation-display-storage.d.ts +15 -7
- package/dist/memory/conversation-display-storage.js +141 -36
- package/dist/memory/conversation-view.d.ts +4 -4
- package/dist/memory/conversation-view.js +5 -4
- package/dist/memory/count-tokens.js +10 -8
- package/dist/memory/derive-thread-title.d.ts +0 -13
- package/dist/memory/derive-thread-title.js +2 -1
- package/dist/memory/message-backfill.d.ts +12 -5
- package/dist/memory/message-backfill.js +5 -3
- package/dist/memory/thread-history.d.ts +66 -24
- package/dist/memory/thread-history.js +212 -79
- package/dist/memory/thread-store.d.ts +26 -17
- package/dist/memory/thread-store.js +15 -9
- package/dist/memory/tool-call-integrity.d.ts +2 -2
- package/dist/memory/tool-call-integrity.js +4 -3
- package/dist/memory/working-memory.d.ts +16 -12
- package/dist/memory/working-memory.js +72 -61
- package/dist/prompts/briefing.d.ts +63 -9
- package/dist/prompts/briefing.js +130 -3
- package/dist/prompts/planner.js +13 -2
- package/dist/prompts/synthesis-agent.d.ts +1 -1
- package/dist/prompts/synthesis-agent.js +6 -14
- package/dist/provenance/collector.d.ts +6 -6
- package/dist/provenance/collector.js +15 -8
- package/dist/provenance/exec-frame.d.ts +2 -2
- package/dist/provenance/exec-frame.js +6 -1
- package/dist/provenance/seam.d.ts +24 -19
- package/dist/provenance/seam.js +7 -5
- package/dist/provenance/types.d.ts +6 -6
- package/dist/providers/ai-sdk.d.ts +113 -62
- package/dist/providers/ai-sdk.js +303 -458
- package/dist/providers/embedding.d.ts +2 -2
- package/dist/providers/embedding.js +1 -1
- package/dist/providers/errors.d.ts +22 -2
- package/dist/providers/errors.js +98 -50
- package/dist/providers/prompt-cache.d.ts +8 -8
- package/dist/providers/prompt-cache.js +13 -11
- package/dist/providers/reasoning.d.ts +2 -2
- package/dist/providers/reasoning.js +2 -2
- package/dist/providers/types.d.ts +59 -92
- package/dist/reference-data/catalog.d.ts +2 -15
- package/dist/reference-data/catalog.js +166 -10
- package/dist/reference-data/receipt.d.ts +2 -2
- package/dist/report-model/assert-rules.js +1 -1
- package/dist/report-model/authoring-grammar.d.ts +209 -231
- package/dist/report-model/block-walk.d.ts +10 -10
- package/dist/report-model/block-walk.js +2 -0
- package/dist/report-model/draft-finish.d.ts +8 -8
- package/dist/report-model/draft-finish.js +1 -1
- package/dist/report-model/draft-hash.js +8 -7
- package/dist/report-model/draft-operations.d.ts +22 -10
- package/dist/report-model/draft-operations.js +48 -30
- package/dist/report-model/draft-read.d.ts +19 -7
- package/dist/report-model/draft-read.js +16 -6
- package/dist/report-model/draft.d.ts +844 -2
- package/dist/report-model/draft.js +3 -1
- package/dist/report-model/fixture-resolver.js +39 -16
- package/dist/report-model/pin-snapshot.d.ts +2 -2
- package/dist/report-model/pin-snapshot.js +15 -15
- package/dist/report-model/production-resolver.d.ts +18 -18
- package/dist/report-model/production-resolver.js +50 -42
- package/dist/report-model/reference-resolver.d.ts +26 -10
- package/dist/report-model/reference-resolver.js +68 -5
- package/dist/report-model/reference-stamp.js +30 -38
- package/dist/report-model/structural-validation.js +12 -4
- package/dist/report-model/validate.d.ts +7 -7
- package/dist/report-model/validate.js +6 -6
- package/dist/report-render/assets.d.ts +2 -2
- package/dist/report-render/assets.js +27 -3
- package/dist/report-render/chart-export.d.ts +10 -2
- package/dist/report-render/chart-export.js +37 -11
- package/dist/report-render/chart-presets.d.ts +8 -8
- package/dist/report-render/chart-presets.js +3 -3
- package/dist/report-render/chart-renderers.d.ts +23 -16
- package/dist/report-render/chart-renderers.js +74 -53
- package/dist/report-render/chart-toolbox.d.ts +2 -2
- package/dist/report-render/chart-toolbox.js +7 -6
- package/dist/report-render/chart.d.ts +15 -16
- package/dist/report-render/chart.js +369 -252
- package/dist/report-render/design.d.ts +36 -297
- package/dist/report-render/design.js +0 -12
- package/dist/report-render/figures/common.d.ts +12 -12
- package/dist/report-render/figures/common.js +42 -31
- package/dist/report-render/figures/dendrogram.d.ts +3 -3
- package/dist/report-render/figures/dendrogram.js +10 -10
- package/dist/report-render/figures/dense.js +15 -8
- package/dist/report-render/figures/dotplot.js +46 -33
- package/dist/report-render/figures/embedding.js +52 -43
- package/dist/report-render/figures/equal-units.d.ts +10 -10
- package/dist/report-render/figures/equal-units.js +27 -27
- package/dist/report-render/figures/forest.js +9 -7
- package/dist/report-render/figures/gsea.js +21 -11
- package/dist/report-render/figures/heatmap.js +13 -9
- package/dist/report-render/figures/index.d.ts +10 -10
- package/dist/report-render/figures/index.js +4 -2
- package/dist/report-render/figures/km.js +10 -9
- package/dist/report-render/figures/label-room.d.ts +12 -12
- package/dist/report-render/figures/label-room.js +7 -2
- package/dist/report-render/figures/locuszoom.d.ts +2 -2
- package/dist/report-render/figures/locuszoom.js +59 -31
- package/dist/report-render/figures/lollipop.js +3 -2
- package/dist/report-render/figures/ma.js +8 -4
- package/dist/report-render/figures/manhattan.d.ts +1 -2
- package/dist/report-render/figures/manhattan.js +52 -34
- package/dist/report-render/figures/oncoprint.js +4 -5
- package/dist/report-render/figures/pca.js +25 -11
- package/dist/report-render/figures/qq.js +20 -9
- package/dist/report-render/figures/roc.js +1 -1
- package/dist/report-render/figures/sankey.d.ts +2 -2
- package/dist/report-render/figures/sankey.js +11 -10
- package/dist/report-render/figures/upset.d.ts +6 -6
- package/dist/report-render/figures/upset.js +7 -4
- package/dist/report-render/figures/volcano.js +12 -10
- package/dist/report-render/hybrid-svg.d.ts +4 -4
- package/dist/report-render/hybrid-svg.js +7 -5
- package/dist/report-render/number-format.d.ts +4 -4
- package/dist/report-render/number-format.js +62 -27
- package/dist/report-render/page.js +2 -1
- package/dist/report-render/provenance-data.d.ts +2 -2
- package/dist/report-render/references.d.ts +4 -4
- package/dist/report-render/render.d.ts +2 -2
- package/dist/report-render/render.js +10 -11
- package/dist/report-render/script-json.js +1 -1
- package/dist/report-render/table-data.d.ts +6 -6
- package/dist/report-render/test/options.d.ts +49 -0
- package/dist/report-render/test/options.js +143 -0
- package/dist/report-render/test/page-function.d.ts +19 -0
- package/dist/report-render/test/page-function.js +33 -0
- package/dist/report-render/types.d.ts +10 -10
- package/dist/report-render/value-bridge.d.ts +4 -4
- package/dist/report-render/value-bridge.js +27 -14
- package/dist/report-render/views/chart-view.d.ts +2 -2
- package/dist/report-render/views/chart-view.js +2 -2
- package/dist/report-render/views/lineage.d.ts +6 -6
- package/dist/report-render/views/lineage.js +2 -0
- package/dist/report-render/views/page-view.d.ts +2 -2
- package/dist/report-render/views/page-view.js +1 -0
- package/dist/report-render/views/prose.js +25 -8
- package/dist/report-render/views/references-view.js +12 -1
- package/dist/report-render/views/values.js +1 -1
- package/dist/runtime/assemble.d.ts +53 -26
- package/dist/runtime/assemble.js +103 -56
- package/dist/runtime/boot.d.ts +8 -7
- package/dist/runtime/boot.js +1 -1
- package/dist/runtime/connection-budget.d.ts +6 -6
- package/dist/runtime/connection-budget.js +1 -1
- package/dist/runtime/dbos.d.ts +29 -19
- package/dist/runtime/dbos.js +35 -20
- package/dist/runtime/result-serialization.js +18 -5
- package/dist/runtime/shutdown.d.ts +2 -2
- package/dist/sandbox/client.d.ts +7 -3
- package/dist/sandbox/cpu-files.d.ts +2 -2
- package/dist/sandbox/cpu-files.js +21 -4
- package/dist/sandbox/create-sandbox.d.ts +7 -8
- package/dist/sandbox/create-sandbox.js +6 -12
- package/dist/sandbox/docker-client.d.ts +48 -3
- package/dist/sandbox/docker-client.js +10 -6
- package/dist/sandbox/estimate-data-profile-resources.js +2 -7
- package/dist/sandbox/exec-outcome.d.ts +2 -2
- package/dist/sandbox/exec-outcome.js +1 -1
- package/dist/sandbox/exec.d.ts +10 -6
- package/dist/sandbox/exec.js +27 -12
- package/dist/sandbox/execution-id.js +14 -6
- package/dist/sandbox/farm.d.ts +2 -2
- package/dist/sandbox/farm.js +22 -27
- package/dist/sandbox/identity.d.ts +7 -0
- package/dist/sandbox/identity.js +14 -3
- package/dist/sandbox/image-packages.d.ts +26 -4
- package/dist/sandbox/image-packages.js +29 -27
- package/dist/sandbox/k8s-client.d.ts +35 -8
- package/dist/sandbox/k8s-client.js +6 -5
- package/dist/sandbox/labels.js +1 -0
- package/dist/sandbox/liveness.js +3 -1
- package/dist/sandbox/mount-plan.d.ts +10 -10
- package/dist/sandbox/mount-plan.js +13 -14
- package/dist/sandbox/notification-sweep.d.ts +4 -4
- package/dist/sandbox/notification-sweep.js +4 -7
- package/dist/sandbox/package-identity.d.ts +6 -13
- package/dist/sandbox/package-identity.js +46 -28
- package/dist/sandbox/reaper.d.ts +10 -10
- package/dist/sandbox/reaper.js +4 -6
- package/dist/sandbox/sandbox-error.d.ts +2 -9
- package/dist/sandbox/sandbox-error.js +21 -8
- package/dist/sandbox/sandbox-step-translate.d.ts +8 -5
- package/dist/sandbox/sandbox-step-translate.js +22 -8
- package/dist/sandbox/step-sandbox.d.ts +47 -0
- package/dist/sandbox/step-sandbox.js +53 -0
- package/dist/sandbox/types.d.ts +18 -19
- package/dist/sandbox/types.js +1 -1
- package/dist/schemas/artifact-manifest.d.ts +4 -4
- package/dist/schemas/data-profile-schemas.d.ts +351 -306
- package/dist/schemas/file-metadata.js +2 -4
- package/dist/schemas/plan-schemas.d.ts +79 -25
- package/dist/schemas/plan-schemas.js +1 -1
- package/dist/schemas/run-synthesis.d.ts +95 -26
- package/dist/schemas/run-synthesis.js +3 -1
- package/dist/schemas/validate-plan.d.ts +4 -4
- package/dist/schemas/validate-plan.js +17 -5
- package/dist/schemas/workflow-state.d.ts +127 -14
- package/dist/schemas/workflow-state.js +56 -2
- package/dist/state/active-turns.d.ts +36 -0
- package/dist/state/active-turns.js +67 -0
- package/dist/state/analyses-metrics.d.ts +8 -8
- package/dist/state/analyses-metrics.js +4 -4
- package/dist/state/analyses.d.ts +0 -14
- package/dist/state/analyses.js +0 -32
- package/dist/state/artifacts.d.ts +47 -18
- package/dist/state/artifacts.js +48 -7
- package/dist/state/data-profile.d.ts +2 -2
- package/dist/state/db.d.ts +12 -2
- package/dist/state/db.js +5 -0
- package/dist/state/edit-intents.d.ts +4 -0
- package/dist/state/edit-intents.js +71 -0
- package/dist/state/index.d.ts +5 -5
- package/dist/state/index.js +3 -3
- package/dist/state/init.d.ts +2 -1
- package/dist/state/init.js +5 -2
- package/dist/state/migrations/20260927120000_baseline.js +3 -1
- package/dist/state/migrations/20261026120000_add_the_edit_intents.d.ts +7 -0
- package/dist/state/migrations/20261026120000_add_the_edit_intents.js +21 -0
- package/dist/state/migrations/20261027120000_record_the_applied_memory_edits.d.ts +7 -0
- package/dist/state/migrations/20261027120000_record_the_applied_memory_edits.js +16 -0
- package/dist/state/migrations/20261027120100_store_the_authoring_results.d.ts +8 -0
- package/dist/state/migrations/20261027120100_store_the_authoring_results.js +20 -0
- package/dist/state/migrations/20261027120200_key_the_groups_of_a_turn.d.ts +7 -0
- package/dist/state/migrations/20261027120200_key_the_groups_of_a_turn.js +12 -0
- package/dist/state/migrations/20261027120300_mark_the_active_turn_of_a_thread.d.ts +7 -0
- package/dist/state/migrations/20261027120300_mark_the_active_turn_of_a_thread.js +11 -0
- package/dist/state/migrations/20261028120000_record_the_paused_work.d.ts +7 -0
- package/dist/state/migrations/20261028120000_record_the_paused_work.js +25 -0
- package/dist/state/migrations/20261028120100_end_the_suspended_runs.d.ts +8 -0
- package/dist/state/migrations/20261028120100_end_the_suspended_runs.js +13 -0
- package/dist/state/migrations/20261029120000_reference_the_run_mandate.d.ts +7 -0
- package/dist/state/migrations/20261029120000_reference_the_run_mandate.js +23 -0
- package/dist/state/migrations/20261029120100_record_the_run_session_of_a_pause.d.ts +7 -0
- package/dist/state/migrations/20261029120100_record_the_run_session_of_a_pause.js +11 -0
- package/dist/state/migrations/index.js +18 -0
- package/dist/state/paused-work.d.ts +52 -0
- package/dist/state/paused-work.js +105 -0
- package/dist/state/plans.d.ts +27 -8
- package/dist/state/plans.js +14 -11
- package/dist/state/purge-analysis.d.ts +6 -6
- package/dist/state/purge-analysis.js +10 -2
- package/dist/state/report-session-state.d.ts +43 -18
- package/dist/state/report-session-state.js +43 -4
- package/dist/state/report-versions.d.ts +16 -11
- package/dist/state/report-versions.js +5 -3
- package/dist/state/runs.d.ts +70 -25
- package/dist/state/runs.js +127 -64
- package/dist/state/schema.d.ts +18 -21
- package/dist/state/schema.js +4 -5
- package/dist/state/snapshot-parse.d.ts +2 -2
- package/dist/state/snapshot-parse.js +14 -8
- package/dist/state/step-executions.d.ts +29 -8
- package/dist/state/step-executions.js +28 -4
- package/dist/state/tool-outputs.d.ts +2 -2
- package/dist/state/tool-outputs.js +2 -1
- package/dist/state/vector-store.d.ts +16 -16
- package/dist/state/vector-store.js +11 -7
- package/dist/tasks/data-profile-absorb.d.ts +3 -3
- package/dist/tasks/data-profile-absorb.js +21 -16
- package/dist/tasks/data-profile-activity.d.ts +5 -5
- package/dist/tasks/data-profile-activity.js +5 -5
- package/dist/tasks/data-profile-index.d.ts +4 -4
- package/dist/tasks/data-profile-index.js +32 -17
- package/dist/tasks/data-profile-resolve.d.ts +8 -8
- package/dist/tasks/data-profile-resolve.js +88 -62
- package/dist/tasks/data-profile.d.ts +40 -31
- package/dist/tasks/data-profile.js +138 -95
- package/dist/tasks/extract-values.d.ts +26 -79
- package/dist/tasks/extract-values.js +48 -108
- package/dist/tasks/refresh-regulatory-corpus.d.ts +4 -20
- package/dist/tasks/refresh-regulatory-corpus.js +12 -8
- package/dist/tasks/regulatory-corpus-boot-refresh.d.ts +2 -2
- package/dist/tasks/regulatory-corpus-boot-refresh.js +12 -10
- package/dist/testing.d.ts +60 -0
- package/dist/testing.js +96 -0
- package/dist/tools/ad-hoc-router.d.ts +11 -9
- package/dist/tools/ad-hoc-router.js +80 -51
- package/dist/tools/analysis-invocation.d.ts +7 -0
- package/dist/tools/analysis-invocation.js +29 -5
- package/dist/tools/approval/contract.d.ts +8 -52
- package/dist/tools/approval/contract.js +7 -36
- package/dist/tools/approval/gateway.d.ts +27 -28
- package/dist/tools/approval/gateway.js +33 -130
- package/dist/tools/approval/queries.d.ts +6 -11
- package/dist/tools/approval/queries.js +43 -29
- package/dist/tools/approval/uuidv7.js +2 -2
- package/dist/tools/bio/chembl.d.ts +3 -3
- package/dist/tools/bio/chembl.js +10 -0
- package/dist/tools/bio/comptox.d.ts +25 -8
- package/dist/tools/bio/comptox.js +4 -2
- package/dist/tools/bio/drug-gene-interactions.d.ts +27 -17
- package/dist/tools/bio/drug-gene-interactions.js +11 -8
- package/dist/tools/bio/gene-disease-evidence.d.ts +61 -15
- package/dist/tools/bio/gene-disease-evidence.js +10 -6
- package/dist/tools/bio/gene-preclinical-profile.d.ts +11 -11
- package/dist/tools/bio/keys.d.ts +2 -2
- package/dist/tools/bio/keys.js +3 -3
- package/dist/tools/bio/lookup-annotation.d.ts +5 -5
- package/dist/tools/bio/lookup-annotation.js +3 -0
- package/dist/tools/bio/opentargets.d.ts +1 -1
- package/dist/tools/bio/opentargets.js +6 -0
- package/dist/tools/bio/pubchem.d.ts +2 -2
- package/dist/tools/bio/pubchem.js +6 -0
- package/dist/tools/bio/pubmed.d.ts +26 -16
- package/dist/tools/bio/pubmed.js +9 -3
- package/dist/tools/bio/search-clinical-trials.d.ts +4 -4
- package/dist/tools/bio/search-clinical-trials.js +5 -1
- package/dist/tools/bio/search-faers.d.ts +2 -2
- package/dist/tools/bio/search-faers.js +1 -1
- package/dist/tools/bio/search-gene.d.ts +2 -2
- package/dist/tools/bio/search-gene.js +1 -0
- package/dist/tools/bio/search-geo-datasets.d.ts +4 -4
- package/dist/tools/bio/search-geo-datasets.js +5 -5
- package/dist/tools/bio/search-interactions.d.ts +1 -1
- package/dist/tools/bio/search-patents.d.ts +28 -22
- package/dist/tools/bio/search-patents.js +20 -17
- package/dist/tools/bio/search-protein.d.ts +2 -2
- package/dist/tools/bio/search-protein.js +1 -1
- package/dist/tools/bio/search-regulatory-approvals.d.ts +64 -18
- package/dist/tools/bio/search-regulatory-approvals.js +21 -16
- package/dist/tools/bio/target-safety.d.ts +8 -8
- package/dist/tools/bio/target-safety.js +11 -6
- package/dist/tools/capability-data.d.ts +40 -0
- package/dist/tools/capability-data.js +74 -0
- package/dist/tools/define-tool.d.ts +55 -46
- package/dist/tools/define-tool.js +39 -27
- package/dist/tools/display/normalize-echart-spec.d.ts +2 -2
- package/dist/tools/display/normalize-echart-spec.js +51 -27
- package/dist/tools/display/show-user.d.ts +2 -2
- package/dist/tools/display/show-user.js +1 -1
- package/dist/tools/execute-analysis.d.ts +54 -17
- package/dist/tools/execute-analysis.js +193 -62
- package/dist/tools/knowledge/check.d.ts +182 -0
- package/dist/tools/knowledge/check.js +94 -0
- package/dist/tools/knowledge/client.d.ts +351 -0
- package/dist/tools/knowledge/client.js +319 -0
- package/dist/tools/knowledge/environment.d.ts +78 -0
- package/dist/tools/knowledge/environment.js +116 -0
- package/dist/tools/knowledge/index.d.ts +49 -0
- package/dist/tools/knowledge/index.js +70 -0
- package/dist/tools/knowledge/local-slots.d.ts +62 -0
- package/dist/tools/knowledge/local-slots.js +184 -0
- package/dist/tools/knowledge/pin.d.ts +14 -0
- package/dist/tools/knowledge/pin.js +17 -0
- package/dist/tools/knowledge/recommend.d.ts +67 -0
- package/dist/tools/knowledge/recommend.js +106 -0
- package/dist/tools/knowledge/situation.d.ts +143 -0
- package/dist/tools/knowledge/situation.js +157 -0
- package/dist/tools/knowledge/skeleton.d.ts +69 -0
- package/dist/tools/knowledge/skeleton.js +201 -0
- package/dist/tools/knowledge/template.d.ts +139 -0
- package/dist/tools/knowledge/template.js +273 -0
- package/dist/tools/lib/alphafold-client.js +2 -1
- package/dist/tools/lib/amass-client.d.ts +28 -28
- package/dist/tools/lib/amass-client.js +20 -10
- package/dist/tools/lib/api-utils.d.ts +13 -3
- package/dist/tools/lib/api-utils.js +17 -3
- package/dist/tools/lib/bgee-client.d.ts +6 -6
- package/dist/tools/lib/bgee-client.js +16 -10
- package/dist/tools/lib/cbioportal-client.d.ts +4 -4
- package/dist/tools/lib/cbioportal-client.js +9 -8
- package/dist/tools/lib/chembl-client.d.ts +14 -14
- package/dist/tools/lib/chembl-client.js +11 -4
- package/dist/tools/lib/clinical-benchmarks-client.d.ts +4 -4
- package/dist/tools/lib/clinical-benchmarks-client.js +4 -7
- package/dist/tools/lib/clinical-trials-client.d.ts +18 -18
- package/dist/tools/lib/clinical-trials-client.js +10 -10
- package/dist/tools/lib/clinvar-client.d.ts +2 -2
- package/dist/tools/lib/clinvar-client.js +6 -6
- package/dist/tools/lib/ctx-ops.d.ts +23 -23
- package/dist/tools/lib/ctx-ops.js +13 -10
- package/dist/tools/lib/dgidb-client.d.ts +6 -6
- package/dist/tools/lib/dgidb-client.js +10 -12
- package/dist/tools/lib/disgenet-client.d.ts +4 -4
- package/dist/tools/lib/ema-client.d.ts +2 -2
- package/dist/tools/lib/ensembl-client.d.ts +4 -4
- package/dist/tools/lib/ensembl-client.js +5 -4
- package/dist/tools/lib/gwas-catalog-client.d.ts +4 -4
- package/dist/tools/lib/gwas-catalog-client.js +17 -17
- package/dist/tools/lib/html-text.d.ts +6 -0
- package/dist/tools/lib/html-text.js +9 -0
- package/dist/tools/lib/identifier-resolver.d.ts +4 -4
- package/dist/tools/lib/identifier-resolver.js +7 -3
- package/dist/tools/lib/impc-client.d.ts +8 -8
- package/dist/tools/lib/impc-client.js +46 -35
- package/dist/tools/lib/iuphar-client.d.ts +2 -2
- package/dist/tools/lib/iuphar-client.js +7 -16
- package/dist/tools/lib/monarch-client.d.ts +4 -4
- package/dist/tools/lib/openfda-client.d.ts +22 -22
- package/dist/tools/lib/openfda-client.js +23 -22
- package/dist/tools/lib/opentargets-client.d.ts +12 -12
- package/dist/tools/lib/pathway-client.d.ts +4 -4
- package/dist/tools/lib/pathway-client.js +15 -19
- package/dist/tools/lib/pharmgkb-client.d.ts +2 -2
- package/dist/tools/lib/pharmgkb-client.js +1 -1
- package/dist/tools/lib/protein-family-modality.d.ts +2 -2
- package/dist/tools/lib/protein-family-modality.js +0 -2
- package/dist/tools/lib/protein-family-normalize.js +7 -0
- package/dist/tools/lib/pubchem-client.d.ts +2 -2
- package/dist/tools/lib/pubchem-client.js +1 -0
- package/dist/tools/lib/pubchem-ops.d.ts +4 -4
- package/dist/tools/lib/pubchem-ops.js +8 -0
- package/dist/tools/lib/pubmed-client.d.ts +9 -9
- package/dist/tools/lib/pubmed-client.js +1 -1
- package/dist/tools/lib/string-client.d.ts +6 -6
- package/dist/tools/lib/uniprot-client.d.ts +8 -8
- package/dist/tools/lib/uniprot-client.js +5 -1
- package/dist/tools/memory/update-working-memory.d.ts +16 -13
- package/dist/tools/memory/update-working-memory.js +21 -3
- package/dist/tools/read-tool-output.js +8 -2
- package/dist/tools/registry.d.ts +2 -2
- package/dist/tools/report-authoring/authoring-tools.d.ts +54 -23
- package/dist/tools/report-authoring/authoring-tools.js +128 -62
- package/dist/tools/report-session/derive-table.d.ts +19 -59
- package/dist/tools/report-session/derive-table.js +120 -122
- package/dist/tools/report-session/examine-page.d.ts +6 -6
- package/dist/tools/report-session/examine-page.js +14 -12
- package/dist/tools/report-session/list-artifacts.d.ts +6 -6
- package/dist/tools/report-session/list-artifacts.js +5 -5
- package/dist/tools/report-session/page-faults.d.ts +6 -6
- package/dist/tools/report-session/page-faults.js +3 -1
- package/dist/tools/report-session/preview-report.d.ts +4 -3
- package/dist/tools/report-session/preview-report.js +26 -7
- package/dist/tools/report-session/record-version.d.ts +9 -4
- package/dist/tools/report-session/record-version.js +16 -9
- package/dist/tools/report-session/session-page-publisher.d.ts +6 -6
- package/dist/tools/research/generate-analogy-report.d.ts +14 -7
- package/dist/tools/research/generate-analogy-report.js +80 -76
- package/dist/tools/research/generate-plan.d.ts +39 -16
- package/dist/tools/research/generate-plan.js +565 -338
- package/dist/tools/research/guarded-address.d.ts +20 -0
- package/dist/tools/research/guarded-address.js +149 -0
- package/dist/tools/research/inspect-data-profile.d.ts +27 -20
- package/dist/tools/research/inspect-data-profile.js +26 -25
- package/dist/tools/research/inspect-run.d.ts +54 -27
- package/dist/tools/research/inspect-run.js +50 -40
- package/dist/tools/research/literature-reviewer.d.ts +8 -7
- package/dist/tools/research/literature-reviewer.js +29 -28
- package/dist/tools/research/search-arxiv.d.ts +1 -1
- package/dist/tools/research/search-arxiv.js +1 -1
- package/dist/tools/research/search-github-repos.d.ts +10 -7
- package/dist/tools/research/search-github-repos.js +25 -22
- package/dist/tools/research/search-semantic-scholar.js +1 -1
- package/dist/tools/research/searxng-engine.d.ts +40 -0
- package/dist/tools/research/searxng-engine.js +122 -0
- package/dist/tools/research/web-fetch.d.ts +127 -0
- package/dist/tools/research/web-fetch.js +618 -0
- package/dist/tools/research/web-search.d.ts +84 -0
- package/dist/tools/research/web-search.js +117 -0
- package/dist/tools/sandbox/link-packages.d.ts +11 -7
- package/dist/tools/sandbox/link-packages.js +11 -8
- package/dist/tools/sandbox/list-available-packages.d.ts +24 -12
- package/dist/tools/sandbox/list-available-packages.js +43 -29
- package/dist/tools/sandbox/list-available-refs.d.ts +38 -14
- package/dist/tools/sandbox/list-available-refs.js +119 -37
- package/dist/tools/sandbox/report-blocker.d.ts +30 -37
- package/dist/tools/sandbox/report-blocker.js +22 -68
- package/dist/tools/sandbox/skills.d.ts +16 -12
- package/dist/tools/sandbox/skills.js +16 -12
- package/dist/tools/sandbox/submit-file-metadata.d.ts +12 -9
- package/dist/tools/sandbox/submit-file-metadata.js +18 -21
- package/dist/tools/start-report-session.d.ts +13 -5
- package/dist/tools/start-report-session.js +35 -8
- package/dist/tools/terminal-text.d.ts +14 -0
- package/dist/tools/terminal-text.js +51 -0
- package/dist/tools/workspace/decision-record.d.ts +81 -0
- package/dist/tools/workspace/decision-record.js +127 -0
- package/dist/tools/workspace/edit-file.d.ts +59 -18
- package/dist/tools/workspace/edit-file.js +98 -15
- package/dist/tools/workspace/execute-command.d.ts +31 -12
- package/dist/tools/workspace/execute-command.js +37 -8
- package/dist/tools/workspace/file-stat.d.ts +6 -3
- package/dist/tools/workspace/grep.d.ts +10 -7
- package/dist/tools/workspace/grep.js +9 -3
- package/dist/tools/workspace/index.d.ts +1 -0
- package/dist/tools/workspace/index.js +1 -0
- package/dist/tools/workspace/list-files.d.ts +6 -3
- package/dist/tools/workspace/mutator.d.ts +28 -15
- package/dist/tools/workspace/mutator.js +107 -53
- package/dist/tools/workspace/read-file.d.ts +8 -5
- package/dist/tools/workspace/result-bounds.d.ts +5 -5
- package/dist/tools/workspace/result-bounds.js +4 -2
- package/dist/tools/workspace/run-exec.d.ts +2 -2
- package/dist/tools/workspace/run-exec.js +3 -3
- package/dist/tools/workspace/scan-inputs.d.ts +8 -5
- package/dist/tools/workspace/scan-inputs.js +17 -5
- package/dist/tools/workspace/show-file.d.ts +1 -1
- package/dist/tools/workspace/show-file.js +2 -1
- package/dist/tools/workspace/show-plan.d.ts +8 -5
- package/dist/tools/workspace/show-plan.js +9 -8
- package/dist/tools/workspace/workspace-search.d.ts +41 -13
- package/dist/tools/workspace/workspace-search.js +27 -14
- package/dist/tools/workspace/write-file.d.ts +9 -7
- package/dist/workflows/execute-analysis-scheduler.d.ts +9 -9
- package/dist/workflows/execute-analysis-scheduler.js +6 -3
- package/dist/workflows/execute-analysis.d.ts +100 -76
- package/dist/workflows/execute-analysis.js +380 -247
- package/dist/workflows/pause.d.ts +71 -0
- package/dist/workflows/pause.js +173 -0
- package/dist/workflows/sandbox-step.d.ts +50 -61
- package/dist/workflows/sandbox-step.js +99 -106
- package/dist/workflows/test/sql-writes.d.ts +21 -0
- package/dist/workflows/test/sql-writes.js +36 -0
- package/dist/workspace/filesystem.d.ts +6 -6
- package/dist/workspace/filesystem.js +10 -8
- package/dist/workspace/paths.d.ts +1 -1
- package/dist/workspace/paths.js +15 -4
- package/dist/workspace/search-config.d.ts +2 -2
- package/dist/workspace/search-config.js +1 -1
- package/package.json +25 -22
- package/dist/loop/continue-agent.d.ts +0 -40
- package/dist/loop/continue-agent.js +0 -38
- package/dist/loop/genai-spans.d.ts +0 -47
- package/dist/loop/genai-spans.js +0 -134
- package/dist/loop/run-agent.d.ts +0 -236
- package/dist/loop/run-agent.js +0 -1110
- package/dist/loop/run-step.d.ts +0 -29
- package/dist/loop/run-step.js +0 -34
- package/dist/loop/run-to-terminal.d.ts +0 -66
- package/dist/loop/run-to-terminal.js +0 -90
- package/dist/loop/tool-mask.d.ts +0 -23
- package/dist/loop/tool-mask.js +0 -46
- package/dist/providers/streaming-chat.d.ts +0 -32
- package/dist/providers/streaming-chat.js +0 -91
- package/dist/tasks/derive-table-exec.d.ts +0 -54
- package/dist/tasks/derive-table-exec.js +0 -86
- package/dist/workflows/suspension.d.ts +0 -32
- package/dist/workflows/suspension.js +0 -38
|
@@ -25,9 +25,12 @@
|
|
|
25
25
|
* other value axis keeps the tick values that ECharts computes. A custom series names its renderer as a
|
|
26
26
|
* string, and each consumer of the option binds the name (`chart-renderers.ts`).
|
|
27
27
|
*/
|
|
28
|
+
import { textOf } from "../lib/unknown-text.js";
|
|
28
29
|
import { err, ok } from "neverthrow";
|
|
29
30
|
import { channelColumn, channelOrder, channelTransform, } from "../contracts/report-blocks.js";
|
|
30
31
|
import { declaredForColumn } from "../contracts/report-reference.js";
|
|
32
|
+
import { isUnknownArray } from "../lib/unknown-array.js";
|
|
33
|
+
import { parseUnknownRecord } from "../lib/unknown-containers.js";
|
|
31
34
|
import { normalizeEchartSpec } from "../tools/display/normalize-echart-spec.js";
|
|
32
35
|
import { categoryInterval, INTERVAL_RENDERER, LABEL_LINE_SHARE, OUTLINE_RENDERER, VIOLIN_GRID_POINTS } from "./chart-renderers.js";
|
|
33
36
|
import { BAR_VALUE_LABEL_LIMIT, CHART_BODY_PX, CHART_FONT_STACK, CHART_INK, CHART_INLINE_OPTION_BOUND, CHART_PAGE_TEXT_PX, CHART_PAGE_WIDTH_PX, CHART_SLOT_LIMIT, COLOR_SCALE_BAND_PCT, FACET_COLUMNS, FACET_PANEL_LIMIT, FACET_ROW_PX, FOCUS_CHART_COLOR, MUTED_CHART_COLOR, SCATTER_CROWD_OPACITY, SCATTER_CROWD_ROWS, SCATTER_CROWD_SYMBOL_SIZE, SCATTER_HOVER_ROWS, SCATTER_HOVER_SYMBOL_SIZE, SIZE_CHANNEL_RANGE_PX, } from "./design.js";
|
|
@@ -35,7 +38,7 @@ import { applyFigureRules, axisNameFields, categoryAxisTitle, categoryName, char
|
|
|
35
38
|
import { FIGURE_MEMBER_READERS, FIGURE_MODULES, isModuleOnlyType, } from "./figures/index.js";
|
|
36
39
|
import { SHAPED_SCATTER_FIGURE } from "./figures/pca.js";
|
|
37
40
|
import { formatNumberCell, selectNumberKind } from "./number-format.js";
|
|
38
|
-
export { transformColumn };
|
|
41
|
+
export { transformColumn } from "./figures/common.js";
|
|
39
42
|
/**
|
|
40
43
|
* The category values that carry no finding.
|
|
41
44
|
*
|
|
@@ -174,7 +177,7 @@ function bodyPxOf(raw, option) {
|
|
|
174
177
|
const grids = option.grid;
|
|
175
178
|
if (!Array.isArray(grids))
|
|
176
179
|
return CHART_BODY_PX;
|
|
177
|
-
const panels = grids.filter((grid) =>
|
|
180
|
+
const panels = grids.filter((grid) => parseUnknownRecord(grid)?.outerBoundsMode === FACET_BOUNDS_MODE).length;
|
|
178
181
|
const rows = panels <= 2 ? 1 : Math.ceil(panels / FACET_COLUMNS);
|
|
179
182
|
return CHART_BODY_PX + (rows - 1) * FACET_ROW_PX;
|
|
180
183
|
}
|
|
@@ -193,7 +196,7 @@ function blockWidthOf(option, bodyPx) {
|
|
|
193
196
|
return undefined;
|
|
194
197
|
let width;
|
|
195
198
|
for (const rule of media) {
|
|
196
|
-
const query =
|
|
199
|
+
const query = parseUnknownRecord(parseUnknownRecord(rule)?.query);
|
|
197
200
|
if (query === undefined || query.maxWidth !== undefined || typeof query.minWidth !== "number" || typeof query.minHeight !== "number")
|
|
198
201
|
continue;
|
|
199
202
|
if (query.minHeight <= bodyPx)
|
|
@@ -247,7 +250,7 @@ function chartRender(pass) {
|
|
|
247
250
|
readsPayload: pass.readsPayload,
|
|
248
251
|
inline: pass.inline,
|
|
249
252
|
bodyPx: pass.bodyPx,
|
|
250
|
-
|
|
253
|
+
widthPx,
|
|
251
254
|
};
|
|
252
255
|
}
|
|
253
256
|
/**
|
|
@@ -288,7 +291,7 @@ function describesLead(series, collector) {
|
|
|
288
291
|
return (composed !== undefined &&
|
|
289
292
|
composed.length === described &&
|
|
290
293
|
described < series.length &&
|
|
291
|
-
composed.every((name, index) => series[index]
|
|
294
|
+
composed.every((name, index) => parseUnknownRecord(series[index])?.name === name));
|
|
292
295
|
}
|
|
293
296
|
/**
|
|
294
297
|
* The quick path of one block that draws one point for one row, or `undefined` for every other block.
|
|
@@ -319,12 +322,12 @@ function perRowQuickPath(block, opts) {
|
|
|
319
322
|
function sourcedOption(option, series, collector, key) {
|
|
320
323
|
const source = {
|
|
321
324
|
payload: key,
|
|
322
|
-
|
|
325
|
+
rule: collector.rule,
|
|
323
326
|
series: collector.series,
|
|
324
327
|
};
|
|
325
328
|
return {
|
|
326
329
|
...option,
|
|
327
|
-
series: series.map((entry, index) => (index < collector.series.length ? { ...entry, data: [] } : entry)),
|
|
330
|
+
series: series.map((entry, index) => (index < collector.series.length ? { ...parseUnknownRecord(entry), data: [] } : entry)),
|
|
328
331
|
[CHART_SOURCE_MEMBER]: source,
|
|
329
332
|
};
|
|
330
333
|
}
|
|
@@ -409,8 +412,8 @@ function deriveRaw(block, rows, columns, collector, inputs, opts) {
|
|
|
409
412
|
return deriveBase({
|
|
410
413
|
...quick.value.block,
|
|
411
414
|
meanings,
|
|
412
|
-
|
|
413
|
-
|
|
415
|
+
focus: block.focus,
|
|
416
|
+
facet: stackedFacet === undefined ? undefined : channelColumn(stackedFacet),
|
|
414
417
|
}, quick.value.rows, columns);
|
|
415
418
|
}
|
|
416
419
|
/** The members that the canonical figures add. A chart type with no figure module reads none of them. */
|
|
@@ -435,10 +438,32 @@ function declaresMember(block, member) {
|
|
|
435
438
|
}
|
|
436
439
|
}
|
|
437
440
|
/** Each member that one block declares, in the order of the grammar. */
|
|
441
|
+
const ENCODING_KEYS = [
|
|
442
|
+
"x",
|
|
443
|
+
"y",
|
|
444
|
+
"group",
|
|
445
|
+
"value",
|
|
446
|
+
"label",
|
|
447
|
+
"color",
|
|
448
|
+
"size",
|
|
449
|
+
"low",
|
|
450
|
+
"high",
|
|
451
|
+
"facet",
|
|
452
|
+
"shape",
|
|
453
|
+
"p",
|
|
454
|
+
"censor",
|
|
455
|
+
"risk",
|
|
456
|
+
"hit",
|
|
457
|
+
"metric",
|
|
458
|
+
"tracks",
|
|
459
|
+
];
|
|
460
|
+
function isEncodingKey(key) {
|
|
461
|
+
return ENCODING_KEYS.some((member) => member === key);
|
|
462
|
+
}
|
|
438
463
|
function declaredMembers(block) {
|
|
439
464
|
const members = [];
|
|
440
465
|
for (const key of Object.keys(block.encoding ?? {})) {
|
|
441
|
-
if (block.encoding?.[key] !== undefined)
|
|
466
|
+
if (isEncodingKey(key) && block.encoding?.[key] !== undefined)
|
|
442
467
|
members.push(key);
|
|
443
468
|
}
|
|
444
469
|
for (const member of ["statistics", "track", "trees", "focus"]) {
|
|
@@ -450,7 +475,7 @@ function declaredMembers(block) {
|
|
|
450
475
|
/** The sentence that names the chart types that read one member that the canonical figures add. */
|
|
451
476
|
function readersSentence(member) {
|
|
452
477
|
const readers = FIGURE_MEMBER_READERS[member];
|
|
453
|
-
const list = readers.length <= 2 ? readers.join(" and ") : `${readers.slice(0, -1).join(", ")}, and ${readers[readers.length - 1]}`;
|
|
478
|
+
const list = readers.length <= 2 ? readers.join(" and ") : `${readers.slice(0, -1).join(", ")}, and ${String(readers[readers.length - 1])}`;
|
|
454
479
|
switch (member) {
|
|
455
480
|
case "statistics":
|
|
456
481
|
return `The statistics are legal on the ${list} charts.`;
|
|
@@ -516,10 +541,10 @@ function deriveFigure(block, chartType, figure, rows, columns, collector, inputs
|
|
|
516
541
|
blockId: block.id,
|
|
517
542
|
labels,
|
|
518
543
|
meanings,
|
|
519
|
-
|
|
544
|
+
columns,
|
|
520
545
|
statistics: statistics.value,
|
|
521
|
-
|
|
522
|
-
|
|
546
|
+
track: track.value,
|
|
547
|
+
trees: trees.value,
|
|
523
548
|
textPx: CHART_PAGE_TEXT_PX,
|
|
524
549
|
compose: (composition, { keepsRowsInline, ...extras } = {}) => {
|
|
525
550
|
// A composition with no collector describes no page build, thus the chart keeps its rows inline.
|
|
@@ -528,7 +553,7 @@ function deriveFigure(block, chartType, figure, rows, columns, collector, inputs
|
|
|
528
553
|
if (described !== undefined && option.isOk()) {
|
|
529
554
|
// The names of the composition output let the pass tell it apart from a series that the
|
|
530
555
|
// figure adds after it.
|
|
531
|
-
described.composed = Array.isArray(option.value.series) ? option.value.series.map((entry) =>
|
|
556
|
+
described.composed = Array.isArray(option.value.series) ? option.value.series.map((entry) => textOf(parseUnknownRecord(entry)?.name)) : [];
|
|
532
557
|
}
|
|
533
558
|
return option;
|
|
534
559
|
},
|
|
@@ -552,10 +577,18 @@ function figureStatistics(block, values) {
|
|
|
552
577
|
if (values === undefined || values.length !== declared.length) {
|
|
553
578
|
return err(missingPart(block.id, `The chart declares ${declared.length} statistics, and its value entry carries ${values?.length ?? 0}.`));
|
|
554
579
|
}
|
|
555
|
-
|
|
580
|
+
const pairs = [];
|
|
581
|
+
for (const [index, statistic] of declared.entries()) {
|
|
582
|
+
const resolved = values[index];
|
|
583
|
+
if (resolved === undefined) {
|
|
584
|
+
return err(missingPart(block.id, `The chart declares ${declared.length} statistics, and its value entry carries ${values.length}.`));
|
|
585
|
+
}
|
|
586
|
+
pairs.push([statistic, resolved]);
|
|
587
|
+
}
|
|
588
|
+
return ok(pairs.map(([statistic, resolved]) => ({
|
|
556
589
|
label: statistic.label,
|
|
557
|
-
value:
|
|
558
|
-
text: statisticText(
|
|
590
|
+
value: resolved.value,
|
|
591
|
+
text: statisticText(resolved.value, statistic.value.locator.column, statistic.value.unit),
|
|
559
592
|
})));
|
|
560
593
|
}
|
|
561
594
|
/** The resolved track of one block, or `undefined` for a block that declares none. An entry with no track refuses. */
|
|
@@ -568,11 +601,11 @@ function figureTrack(block, value) {
|
|
|
568
601
|
}
|
|
569
602
|
return ok({
|
|
570
603
|
rows: value.rows,
|
|
571
|
-
|
|
604
|
+
columns: value.columns,
|
|
572
605
|
start: declared.start,
|
|
573
606
|
end: declared.end,
|
|
574
607
|
label: declared.label,
|
|
575
|
-
|
|
608
|
+
length: declared.length,
|
|
576
609
|
labels: declared.binding.columnLabels,
|
|
577
610
|
meanings: declared.binding.columnMeanings,
|
|
578
611
|
});
|
|
@@ -596,7 +629,7 @@ function figureTrees(block, values) {
|
|
|
596
629
|
}
|
|
597
630
|
trees[axis] = {
|
|
598
631
|
rows: value.rows,
|
|
599
|
-
|
|
632
|
+
columns: value.columns,
|
|
600
633
|
parent: tree.parent,
|
|
601
634
|
child: tree.child,
|
|
602
635
|
height: tree.height,
|
|
@@ -741,19 +774,19 @@ function deriveAsComposition(blockId, chartType, encoding, rows, columns, labels
|
|
|
741
774
|
encoding: {
|
|
742
775
|
x: x.value,
|
|
743
776
|
y: y.value,
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
777
|
+
group: encoding.group,
|
|
778
|
+
label: encoding.label,
|
|
779
|
+
color: encoding.color,
|
|
780
|
+
size: encoding.size,
|
|
781
|
+
low: encoding.low,
|
|
782
|
+
high: encoding.high,
|
|
750
783
|
},
|
|
751
784
|
// The caller refused an orientation on every type but the bar, thus the form here is a bar
|
|
752
785
|
// wherever one arrives. The arrangement crosses onto the series, and no name channel loses it.
|
|
753
|
-
|
|
786
|
+
orientation,
|
|
754
787
|
},
|
|
755
788
|
],
|
|
756
|
-
|
|
789
|
+
facet: encoding.facet,
|
|
757
790
|
};
|
|
758
791
|
return deriveComposition(blockId, composition, rows, columns, labels, extras);
|
|
759
792
|
}
|
|
@@ -820,18 +853,18 @@ const CHANNELS = ["x", "y", "group", "value"];
|
|
|
820
853
|
* without a value drops, thus no substitute value ever appears.
|
|
821
854
|
*/
|
|
822
855
|
function deriveTransformedRows(rows, derived) {
|
|
823
|
-
const
|
|
856
|
+
const columns = derived.map((entry) => ({ name: entry.name, values: transformColumn(rows, entry.column, entry.transform) }));
|
|
824
857
|
const out = [];
|
|
825
|
-
for (
|
|
826
|
-
const next = { ...
|
|
858
|
+
for (const [index, row] of rows.entries()) {
|
|
859
|
+
const next = { ...row };
|
|
827
860
|
let complete = true;
|
|
828
|
-
for (
|
|
829
|
-
const value = values[
|
|
861
|
+
for (const column of columns) {
|
|
862
|
+
const value = column.values[index] ?? null;
|
|
830
863
|
if (value === null) {
|
|
831
864
|
complete = false;
|
|
832
865
|
break;
|
|
833
866
|
}
|
|
834
|
-
next[
|
|
867
|
+
next[column.name] = value;
|
|
835
868
|
}
|
|
836
869
|
if (complete)
|
|
837
870
|
out.push(next);
|
|
@@ -875,19 +908,23 @@ function deriveBar(block, rows, columns, mode) {
|
|
|
875
908
|
if (focused.isErr())
|
|
876
909
|
return err(focused.error);
|
|
877
910
|
const focus = focused.value;
|
|
878
|
-
const bars = groupedSeries(rows, group, (groupRows, name) =>
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
911
|
+
const bars = groupedSeries(rows, group, (groupRows, name) => {
|
|
912
|
+
const bar = {
|
|
913
|
+
type: "bar",
|
|
914
|
+
...categoryStyle(name, focus),
|
|
915
|
+
barGap: 0,
|
|
916
|
+
barCategoryGap: BAR_CATEGORY_GAP,
|
|
917
|
+
data: groupRows.map((row) => {
|
|
918
|
+
const pair = horizontal ? [row[y], categoryCell(row[x])] : [categoryCell(row[x]), row[y]];
|
|
919
|
+
// A bar with no group reads the focus over its own categories, thus each item carries its color.
|
|
920
|
+
const color = group === undefined ? focusColor(focus, row[x]) : undefined;
|
|
921
|
+
return color === undefined ? pair : { value: pair, itemStyle: { color } };
|
|
922
|
+
}),
|
|
923
|
+
};
|
|
924
|
+
if (name !== undefined)
|
|
925
|
+
bar.name = categoryName(name);
|
|
926
|
+
return bar;
|
|
927
|
+
});
|
|
891
928
|
series = withValueLabels(bars, horizontal, (cell) => valueLabelText(y, cell, block.meanings));
|
|
892
929
|
}
|
|
893
930
|
else {
|
|
@@ -899,7 +936,12 @@ function deriveBar(block, rows, columns, mode) {
|
|
|
899
936
|
return err(stacked.error);
|
|
900
937
|
series = stacked.value;
|
|
901
938
|
}
|
|
902
|
-
const valueAxis = { type: "value"
|
|
939
|
+
const valueAxis = { type: "value" };
|
|
940
|
+
if (mode === "normalized") {
|
|
941
|
+
valueAxis.min = 0;
|
|
942
|
+
valueAxis.max = 1;
|
|
943
|
+
}
|
|
944
|
+
Object.assign(valueAxis, labelRoom(series, horizontal));
|
|
903
945
|
if (horizontal) {
|
|
904
946
|
return ok({
|
|
905
947
|
xAxis: { ...valueAxis, ...xAxisName(axisTitle(block.labels, y)) },
|
|
@@ -1009,7 +1051,7 @@ function deriveStackedFacets(block, rows, columns, x, y, categories, normalized,
|
|
|
1009
1051
|
let negative = 0;
|
|
1010
1052
|
for (const entry of panel.value) {
|
|
1011
1053
|
// `stackedSeries` gives each series one part or null for each category, in category order.
|
|
1012
|
-
const part = toNumber(entry.data[index]);
|
|
1054
|
+
const part = toNumber(isUnknownArray(entry.data) ? entry.data[index] : undefined);
|
|
1013
1055
|
if (part === null)
|
|
1014
1056
|
continue;
|
|
1015
1057
|
if (part > 0)
|
|
@@ -1076,13 +1118,23 @@ function derivePointForm(block, rows, columns, form) {
|
|
|
1076
1118
|
const xText = xAxis.value.type === "category";
|
|
1077
1119
|
const yText = yAxis.value.type === "category";
|
|
1078
1120
|
const pairOf = (row) => [xText ? categoryCell(row[x]) : row[x], yText ? categoryCell(row[y]) : row[y]];
|
|
1079
|
-
const series = groupedSeries(rows, group, (groupRows, name) =>
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1121
|
+
const series = groupedSeries(rows, group, (groupRows, name) => {
|
|
1122
|
+
const entry = {
|
|
1123
|
+
type: form,
|
|
1124
|
+
...categoryStyle(name, focused.value),
|
|
1125
|
+
data: form === "line" ? sortByX(groupRows.map(pairOf), places) : groupRows.map(pairOf),
|
|
1126
|
+
};
|
|
1127
|
+
if (name !== undefined)
|
|
1128
|
+
entry.name = categoryName(name);
|
|
1129
|
+
if (form === "line") {
|
|
1130
|
+
entry.showSymbol = false;
|
|
1131
|
+
}
|
|
1132
|
+
else {
|
|
1133
|
+
entry.large = true;
|
|
1134
|
+
entry.largeThreshold = 2000;
|
|
1135
|
+
}
|
|
1136
|
+
return entry;
|
|
1137
|
+
});
|
|
1086
1138
|
return ok({ xAxis: xAxis.value, yAxis: yAxis.value, series });
|
|
1087
1139
|
}
|
|
1088
1140
|
/**
|
|
@@ -1158,22 +1210,21 @@ function deriveBox(block, rows, columns) {
|
|
|
1158
1210
|
return err(focused.error);
|
|
1159
1211
|
const series = [];
|
|
1160
1212
|
const buckets = slotBuckets(rows, x, y, groupColumn);
|
|
1161
|
-
const
|
|
1162
|
-
const pointed = drawsDistributionPoints(
|
|
1213
|
+
const lanes = groups.map((group) => ({ name: group.name, values: categories.map((category) => buckets.get(slotKey(group.name, category)) ?? []) }));
|
|
1214
|
+
const pointed = drawsDistributionPoints(lanes.flatMap((lane) => lane.values));
|
|
1163
1215
|
// The axis jitter centers each point on its category and not on its slot, thus a grouped box places its
|
|
1164
1216
|
// points on the slot axis.
|
|
1165
1217
|
const grouped = groups.length > 1;
|
|
1166
1218
|
const points = [];
|
|
1167
1219
|
const slotted = [];
|
|
1168
|
-
for (const [place,
|
|
1169
|
-
const color = focusColor(focused.value,
|
|
1220
|
+
for (const [place, lane] of lanes.entries()) {
|
|
1221
|
+
const color = focusColor(focused.value, lane.name);
|
|
1170
1222
|
const slot = boxSlot(place, groups.length);
|
|
1171
1223
|
const boxData = [];
|
|
1172
1224
|
const outliers = [];
|
|
1173
1225
|
const slotPointList = [];
|
|
1174
1226
|
const medians = [];
|
|
1175
|
-
for (
|
|
1176
|
-
const values = valuesOf[place][index];
|
|
1227
|
+
for (const [index, values] of lane.values.entries()) {
|
|
1177
1228
|
if (pointed && grouped)
|
|
1178
1229
|
slotPointList.push(...slotPoints(values, index, slot));
|
|
1179
1230
|
else if (pointed) {
|
|
@@ -1195,30 +1246,34 @@ function deriveBox(block, rows, columns) {
|
|
|
1195
1246
|
outliers.push([index, outlier]);
|
|
1196
1247
|
}
|
|
1197
1248
|
}
|
|
1198
|
-
|
|
1249
|
+
const box = {
|
|
1199
1250
|
type: "boxplot",
|
|
1200
|
-
...(group.name !== undefined ? { name: categoryName(group.name) } : {}),
|
|
1201
1251
|
// A box draws its median in the border color, thus a focus colors the border and never the fill.
|
|
1202
|
-
|
|
1252
|
+
itemStyle: { borderColor: color },
|
|
1203
1253
|
data: boxData,
|
|
1204
|
-
}
|
|
1254
|
+
};
|
|
1255
|
+
if (lane.name !== undefined)
|
|
1256
|
+
box.name = categoryName(lane.name);
|
|
1257
|
+
series.push(box);
|
|
1205
1258
|
// The outlier scatter pairs with its box series, thus it only appears when an outlier exists. A box with
|
|
1206
1259
|
// no group takes no palette slot by name, thus its outliers take the ink of the points.
|
|
1207
1260
|
if (outliers.length > 0) {
|
|
1208
|
-
const outlierColor = color ?? (
|
|
1209
|
-
|
|
1261
|
+
const outlierColor = color ?? (lane.name === undefined ? CHART_INK : undefined);
|
|
1262
|
+
const outlierMarks = {
|
|
1210
1263
|
type: "scatter",
|
|
1211
|
-
|
|
1212
|
-
...(outlierColor !== undefined ? { itemStyle: { color: outlierColor } } : {}),
|
|
1264
|
+
itemStyle: { color: outlierColor },
|
|
1213
1265
|
symbolSize: 4,
|
|
1214
1266
|
data: outliers,
|
|
1215
|
-
}
|
|
1267
|
+
};
|
|
1268
|
+
if (lane.name !== undefined)
|
|
1269
|
+
outlierMarks.name = categoryName(lane.name);
|
|
1270
|
+
series.push(outlierMarks);
|
|
1216
1271
|
}
|
|
1217
|
-
const onSlots = slotSeries(
|
|
1272
|
+
const onSlots = slotSeries(lane.name === undefined ? undefined : categoryName(lane.name), slotPointList, medians, grouped ? color : CHART_INK);
|
|
1218
1273
|
if (onSlots !== undefined)
|
|
1219
1274
|
slotted.push(onSlots);
|
|
1220
1275
|
}
|
|
1221
|
-
const pointName =
|
|
1276
|
+
const pointName = lanes[0]?.name;
|
|
1222
1277
|
if (points.length > 0)
|
|
1223
1278
|
series.push(pointSeries(points, pointName === undefined ? undefined : categoryName(pointName)));
|
|
1224
1279
|
series.push(...slotted);
|
|
@@ -1226,8 +1281,9 @@ function deriveBox(block, rows, columns) {
|
|
|
1226
1281
|
type: "category",
|
|
1227
1282
|
data: categories,
|
|
1228
1283
|
...axisNameFields("x", categoryAxisTitle(block.labels, x)),
|
|
1229
|
-
...(points.length > 0 ? JITTERED_AXIS : {}),
|
|
1230
1284
|
};
|
|
1285
|
+
if (points.length > 0)
|
|
1286
|
+
Object.assign(categoryAxis, JITTERED_AXIS);
|
|
1231
1287
|
return ok({
|
|
1232
1288
|
xAxis: slotted.length > 0 ? [categoryAxis, slotAxis(categories.length)] : categoryAxis,
|
|
1233
1289
|
yAxis: { type: "value", ...yAxisName(axisTitle(block.labels, y)) },
|
|
@@ -1297,19 +1353,17 @@ function slotSeries(name, points, medians, color) {
|
|
|
1297
1353
|
return undefined;
|
|
1298
1354
|
return {
|
|
1299
1355
|
...pointSeries(points, name),
|
|
1300
|
-
itemStyle: {
|
|
1356
|
+
itemStyle: { color, opacity: DISTRIBUTION_POINT_OPACITY },
|
|
1301
1357
|
xAxisIndex: 1,
|
|
1302
|
-
|
|
1358
|
+
markLine: medians.length > 0
|
|
1303
1359
|
? {
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
data: medians.map((line) => [...line]),
|
|
1310
|
-
},
|
|
1360
|
+
silent: true,
|
|
1361
|
+
symbol: "none",
|
|
1362
|
+
label: { show: false },
|
|
1363
|
+
lineStyle: { width: MEDIAN_LINE_WIDTH_PX, type: "solid", opacity: 1 },
|
|
1364
|
+
data: medians.map((line) => [...line]),
|
|
1311
1365
|
}
|
|
1312
|
-
:
|
|
1366
|
+
: undefined,
|
|
1313
1367
|
};
|
|
1314
1368
|
}
|
|
1315
1369
|
/**
|
|
@@ -1338,7 +1392,7 @@ const JITTERED_AXIS = { jitter: 24, jitterOverlap: false, jitterMargin: 0 };
|
|
|
1338
1392
|
function pointSeries(points, name) {
|
|
1339
1393
|
return {
|
|
1340
1394
|
type: "scatter",
|
|
1341
|
-
|
|
1395
|
+
name,
|
|
1342
1396
|
silent: true,
|
|
1343
1397
|
symbolSize: DISTRIBUTION_POINT_SIZE,
|
|
1344
1398
|
itemStyle: { color: CHART_INK, opacity: DISTRIBUTION_POINT_OPACITY },
|
|
@@ -1414,31 +1468,34 @@ function deriveViolin(block, rows, columns) {
|
|
|
1414
1468
|
if (focused.isErr())
|
|
1415
1469
|
return err(focused.error);
|
|
1416
1470
|
const buckets = slotBuckets(rows, x, y, groupColumn);
|
|
1417
|
-
const
|
|
1418
|
-
|
|
1419
|
-
|
|
1471
|
+
const lanes = groups.map((group) => ({
|
|
1472
|
+
name: group.name,
|
|
1473
|
+
shapes: categories.flatMap((category, index) => {
|
|
1474
|
+
const shape = violinShape(buckets.get(slotKey(group.name, category)) ?? []);
|
|
1475
|
+
return shape === undefined ? [] : [{ ...shape, category: index }];
|
|
1476
|
+
}),
|
|
1477
|
+
values: categories.map((category) => buckets.get(slotKey(group.name, category)) ?? []),
|
|
1420
1478
|
}));
|
|
1421
1479
|
let largest = 0;
|
|
1422
|
-
for (const shape of
|
|
1480
|
+
for (const shape of lanes.flatMap((lane) => lane.shapes)) {
|
|
1423
1481
|
for (const density of shape.densities)
|
|
1424
1482
|
largest = Math.max(largest, density);
|
|
1425
1483
|
}
|
|
1426
|
-
const
|
|
1427
|
-
const pointed = drawsDistributionPoints(valuesOf.flat());
|
|
1484
|
+
const pointed = drawsDistributionPoints(lanes.flatMap((lane) => lane.values));
|
|
1428
1485
|
// The axis jitter centers each point on its category and not on its slot, thus a grouped violin places its
|
|
1429
1486
|
// points on the slot axis.
|
|
1430
1487
|
const grouped = groups.length > 1;
|
|
1431
1488
|
const slotted = [];
|
|
1432
1489
|
const series = [];
|
|
1433
1490
|
const legend = [];
|
|
1434
|
-
for (const [place,
|
|
1435
|
-
const name =
|
|
1491
|
+
for (const [place, lane] of lanes.entries()) {
|
|
1492
|
+
const name = lane.name !== undefined ? categoryName(lane.name) : axisTitle(block.labels, y);
|
|
1436
1493
|
const offset = slotOffset(place, groups.length);
|
|
1437
1494
|
const slot = violinSlot(place, groups.length);
|
|
1438
|
-
const shaped = new Set(shapes
|
|
1439
|
-
const medians =
|
|
1440
|
-
const slotPointList = pointed && grouped ?
|
|
1441
|
-
const color = focusColor(focused.value,
|
|
1495
|
+
const shaped = new Set(lane.shapes.map((shape) => shape.category));
|
|
1496
|
+
const medians = lane.values.flatMap((values, index) => (shaped.has(index) || values.length === 0 ? [] : [medianLine(values, index, slot)]));
|
|
1497
|
+
const slotPointList = pointed && grouped ? lane.values.flatMap((values, index) => slotPoints(values, index, slot)) : [];
|
|
1498
|
+
const color = focusColor(focused.value, lane.name);
|
|
1442
1499
|
const onSlots = slotSeries(name, slotPointList, medians, grouped ? color : CHART_INK);
|
|
1443
1500
|
if (onSlots !== undefined)
|
|
1444
1501
|
slotted.push(onSlots);
|
|
@@ -1449,13 +1506,13 @@ function deriveViolin(block, rows, columns) {
|
|
|
1449
1506
|
renderItem: OUTLINE_RENDERER,
|
|
1450
1507
|
silent: true,
|
|
1451
1508
|
encode: { x: 0, y: [1, 2] },
|
|
1452
|
-
|
|
1453
|
-
data: shapes
|
|
1509
|
+
itemStyle: color !== undefined ? { color } : nullCategoryStyle(lane.name).itemStyle,
|
|
1510
|
+
data: lane.shapes.map((shape) => [
|
|
1454
1511
|
shape.category,
|
|
1455
1512
|
shape.grid[0],
|
|
1456
1513
|
shape.grid[shape.grid.length - 1],
|
|
1457
1514
|
offset,
|
|
1458
|
-
...shape.grid.flatMap((value, point) => [roundWidth(largest > 0 ? (shape.densities[point] / largest) * halfWidth : 0), value]),
|
|
1515
|
+
...shape.grid.flatMap((value, point) => [roundWidth(largest > 0 ? ((shape.densities[point] ?? 0) / largest) * halfWidth : 0), value]),
|
|
1459
1516
|
]),
|
|
1460
1517
|
});
|
|
1461
1518
|
series.push({
|
|
@@ -1464,13 +1521,13 @@ function deriveViolin(block, rows, columns) {
|
|
|
1464
1521
|
renderItem: INTERVAL_RENDERER,
|
|
1465
1522
|
silent: true,
|
|
1466
1523
|
encode: { x: 0, y: [1, 2, 3] },
|
|
1467
|
-
data: shapes
|
|
1524
|
+
data: lane.shapes.map((shape) => [shape.category, shape.median, shape.q1, shape.q3, 1, offset, 1]),
|
|
1468
1525
|
});
|
|
1469
1526
|
legend.push(name);
|
|
1470
1527
|
}
|
|
1471
1528
|
const points = [];
|
|
1472
1529
|
if (pointed && !grouped) {
|
|
1473
|
-
for (const [index, values] of (
|
|
1530
|
+
for (const [index, values] of (lanes[0]?.values ?? []).entries()) {
|
|
1474
1531
|
for (const value of values)
|
|
1475
1532
|
points.push([index, value]);
|
|
1476
1533
|
}
|
|
@@ -1482,8 +1539,9 @@ function deriveViolin(block, rows, columns) {
|
|
|
1482
1539
|
type: "category",
|
|
1483
1540
|
data: categories,
|
|
1484
1541
|
...axisNameFields("x", categoryAxisTitle(block.labels, x)),
|
|
1485
|
-
...(points.length > 0 ? JITTERED_AXIS : {}),
|
|
1486
1542
|
};
|
|
1543
|
+
if (points.length > 0)
|
|
1544
|
+
Object.assign(categoryAxis, JITTERED_AXIS);
|
|
1487
1545
|
return ok({
|
|
1488
1546
|
xAxis: slotted.length > 0 ? [categoryAxis, slotAxis(categories.length)] : categoryAxis,
|
|
1489
1547
|
yAxis: { type: "value", scale: true, ...yAxisName(axisTitle(block.labels, y)) },
|
|
@@ -1650,7 +1708,8 @@ function deriveComposition(blockId, composition, rows, columns, labels, extras =
|
|
|
1650
1708
|
return err(series.error);
|
|
1651
1709
|
resolved.push(series.value);
|
|
1652
1710
|
}
|
|
1653
|
-
|
|
1711
|
+
const first = resolved[0];
|
|
1712
|
+
if (first === undefined) {
|
|
1654
1713
|
// The schema holds a composition to one series at least. The guard states the same rule for a
|
|
1655
1714
|
// value that reaches the renderer without a parse, because the axes come from the first series.
|
|
1656
1715
|
return err(problem(blockId, "The composition carries no series."));
|
|
@@ -1659,7 +1718,7 @@ function deriveComposition(blockId, composition, rows, columns, labels, extras =
|
|
|
1659
1718
|
const labeled = pointLabelRows(blockId, annotations, rows, columns, plottedRows(resolved, rows.length));
|
|
1660
1719
|
if (labeled.isErr())
|
|
1661
1720
|
return err(labeled.error);
|
|
1662
|
-
const focused = focusSet(blockId, extras.focus, rows.length, compositionCategories(resolved
|
|
1721
|
+
const focused = focusSet(blockId, extras.focus, rows.length, compositionCategories(resolved));
|
|
1663
1722
|
if (focused.isErr())
|
|
1664
1723
|
return err(focused.error);
|
|
1665
1724
|
if (collector !== undefined && classification !== undefined) {
|
|
@@ -1686,10 +1745,9 @@ function deriveComposition(blockId, composition, rows, columns, labels, extras =
|
|
|
1686
1745
|
density: scatterDensity(rows.length),
|
|
1687
1746
|
annotations,
|
|
1688
1747
|
// The axes come from the first series, thus its order sorts the shared x axis of every series.
|
|
1689
|
-
orderedX:
|
|
1748
|
+
orderedX: first.x.order !== undefined,
|
|
1690
1749
|
colorOnTop: extras.colorOnTop === true,
|
|
1691
1750
|
};
|
|
1692
|
-
const first = resolved[0];
|
|
1693
1751
|
const axes = compositionAxes(context, first, composition.axes);
|
|
1694
1752
|
if (axes.isErr())
|
|
1695
1753
|
return err(axes.error);
|
|
@@ -1706,21 +1764,26 @@ function deriveComposition(blockId, composition, rows, columns, labels, extras =
|
|
|
1706
1764
|
const series = labeledSeries(context, emitted.value, horizontal);
|
|
1707
1765
|
const room = first.declared.form === "bar" ? labelRoom(series, horizontal) : {};
|
|
1708
1766
|
const colored = emitted.value.some((entry) => entry.entry?.color !== undefined);
|
|
1709
|
-
const grid = {
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1767
|
+
const grid = {};
|
|
1768
|
+
// A continuous color draws its scale at the right edge, thus the grid leaves that band free.
|
|
1769
|
+
if (colored)
|
|
1770
|
+
grid.right = COLOR_SCALE_GRID_RIGHT;
|
|
1771
|
+
// A horizontal bar draws its category names as y labels, thus the grid must hold them.
|
|
1772
|
+
if (isHorizontalBar(first.declared))
|
|
1773
|
+
Object.assign(grid, LABEL_CONTAINING_GRID);
|
|
1774
|
+
const panel = {
|
|
1716
1775
|
tooltip: named ? { ...NAMED_TOOLTIP } : { ...PLAIN_TOOLTIP },
|
|
1717
1776
|
xAxis: horizontal ? { ...axes.value.xAxis, ...room } : axes.value.xAxis,
|
|
1718
1777
|
yAxis: horizontal ? axes.value.yAxis : { ...axes.value.yAxis, ...room },
|
|
1719
1778
|
series,
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1779
|
+
};
|
|
1780
|
+
if (maps.length > 0)
|
|
1781
|
+
panel.visualMap = maps;
|
|
1782
|
+
if (emitted.value.some((entry) => entry.auxiliary))
|
|
1783
|
+
panel.legend = legendOf(drawnNames(emitted.value));
|
|
1784
|
+
if (Object.keys(grid).length > 0)
|
|
1785
|
+
panel.grid = grid;
|
|
1786
|
+
return ok(panel);
|
|
1724
1787
|
}
|
|
1725
1788
|
/** The stack prefix of a band. A facet panel adds its own place, thus two panels never stack each other. */
|
|
1726
1789
|
const BAND_STACK_PREFIX = "band-";
|
|
@@ -1804,14 +1867,13 @@ function compositionFault(composition, focus) {
|
|
|
1804
1867
|
* The categories that a focus of one composition can name: the values of each group channel, and the `x`
|
|
1805
1868
|
* values of each bar series that splits by no group.
|
|
1806
1869
|
*/
|
|
1807
|
-
function compositionCategories(resolved
|
|
1870
|
+
function compositionCategories(resolved) {
|
|
1808
1871
|
const categories = [];
|
|
1809
1872
|
for (const entry of resolved) {
|
|
1810
1873
|
const channel = entry.group ?? (entry.declared.form === "bar" ? entry.x : undefined);
|
|
1811
1874
|
if (channel === undefined)
|
|
1812
1875
|
continue;
|
|
1813
|
-
for (
|
|
1814
|
-
const value = channel.values[index];
|
|
1876
|
+
for (const value of channel.values) {
|
|
1815
1877
|
if (value !== null)
|
|
1816
1878
|
categories.push(value);
|
|
1817
1879
|
}
|
|
@@ -1845,22 +1907,23 @@ function composePanel(context, resolved, members, axes, stackPrefix) {
|
|
|
1845
1907
|
emitted.push(...built.value);
|
|
1846
1908
|
}
|
|
1847
1909
|
const marks = markMembers(context.annotations);
|
|
1848
|
-
const
|
|
1849
|
-
if (Object.keys(marks).length > 0 &&
|
|
1850
|
-
|
|
1910
|
+
const carrier = markCarrier(emitted);
|
|
1911
|
+
if (Object.keys(marks).length > 0 && carrier !== undefined) {
|
|
1912
|
+
const target = emitted.indexOf(carrier);
|
|
1913
|
+
emitted[target] = { ...carrier, option: { ...carrier.option, ...marks } };
|
|
1851
1914
|
}
|
|
1852
1915
|
return ok(emitted);
|
|
1853
1916
|
}
|
|
1854
1917
|
/** The option of each emitted series, with the value label of each bar of a small bar chart. */
|
|
1855
1918
|
function labeledSeries(context, emitted, horizontal) {
|
|
1856
1919
|
return withValueLabels(emitted.map((entry) => entry.option), horizontal, (cell, index) => {
|
|
1857
|
-
const value = emitted[index]
|
|
1920
|
+
const value = emitted[index]?.entry?.y;
|
|
1858
1921
|
return value === undefined ? String(cell) : valueLabelText(value.transformed ? value.name : value.column, cell, context.meanings);
|
|
1859
|
-
}, (index) => emitted[index]
|
|
1922
|
+
}, (index) => emitted[index]?.entry?.low === undefined);
|
|
1860
1923
|
}
|
|
1861
1924
|
/** The names of the drawn series, in series order. An auxiliary series names no entry of its own. */
|
|
1862
1925
|
function drawnNames(emitted) {
|
|
1863
|
-
return emitted.filter((entry) => !entry.auxiliary).map((entry) =>
|
|
1926
|
+
return emitted.filter((entry) => !entry.auxiliary).map((entry) => textOf(entry.option.name));
|
|
1864
1927
|
}
|
|
1865
1928
|
/**
|
|
1866
1929
|
* The visual maps of one composition: one map over the continuous color, and one map over the symbol size
|
|
@@ -1912,8 +1975,8 @@ function visualMaps(context, resolved, emitted) {
|
|
|
1912
1975
|
show: false,
|
|
1913
1976
|
seriesIndex,
|
|
1914
1977
|
dimension,
|
|
1915
|
-
min:
|
|
1916
|
-
max:
|
|
1978
|
+
min: lowest(sizes) ?? 0,
|
|
1979
|
+
max: highest(sizes) ?? 1,
|
|
1917
1980
|
inRange: { symbolSize: [...SIZE_CHANNEL_RANGE_PX] },
|
|
1918
1981
|
});
|
|
1919
1982
|
}
|
|
@@ -1926,11 +1989,12 @@ function visualMaps(context, resolved, emitted) {
|
|
|
1926
1989
|
function drawnMembers(emitted, seriesIndex, dimension) {
|
|
1927
1990
|
const members = [];
|
|
1928
1991
|
for (const index of seriesIndex) {
|
|
1929
|
-
const data = emitted[index]
|
|
1992
|
+
const data = emitted[index]?.option.data;
|
|
1930
1993
|
if (!Array.isArray(data))
|
|
1931
1994
|
continue;
|
|
1932
1995
|
for (const item of data) {
|
|
1933
|
-
const
|
|
1996
|
+
const fields = parseUnknownRecord(item);
|
|
1997
|
+
const value = Array.isArray(item) ? item : fields?.value;
|
|
1934
1998
|
const member = Array.isArray(value) ? toNumber(value[dimension]) : null;
|
|
1935
1999
|
if (member !== null)
|
|
1936
2000
|
members.push(member);
|
|
@@ -1938,20 +2002,22 @@ function drawnMembers(emitted, seriesIndex, dimension) {
|
|
|
1938
2002
|
}
|
|
1939
2003
|
return members;
|
|
1940
2004
|
}
|
|
1941
|
-
/** The smallest of some values,
|
|
2005
|
+
/** The smallest of some values, or `undefined` for no value. */
|
|
1942
2006
|
function lowest(values) {
|
|
1943
|
-
let min
|
|
1944
|
-
for (const value of values)
|
|
1945
|
-
if (value < min)
|
|
2007
|
+
let min;
|
|
2008
|
+
for (const value of values) {
|
|
2009
|
+
if (min === undefined || value < min)
|
|
1946
2010
|
min = value;
|
|
2011
|
+
}
|
|
1947
2012
|
return min;
|
|
1948
2013
|
}
|
|
1949
|
-
/** The largest of some values,
|
|
2014
|
+
/** The largest of some values, or `undefined` for no value. */
|
|
1950
2015
|
function highest(values) {
|
|
1951
|
-
let max
|
|
1952
|
-
for (const value of values)
|
|
1953
|
-
if (value > max)
|
|
2016
|
+
let max;
|
|
2017
|
+
for (const value of values) {
|
|
2018
|
+
if (max === undefined || value > max)
|
|
1954
2019
|
max = value;
|
|
2020
|
+
}
|
|
1955
2021
|
return max;
|
|
1956
2022
|
}
|
|
1957
2023
|
/**
|
|
@@ -1968,9 +2034,9 @@ function intervalAlongX(entry, axes) {
|
|
|
1968
2034
|
}
|
|
1969
2035
|
/** The place of each category of one axis, keyed by the text of the category, or `undefined` for a value axis. */
|
|
1970
2036
|
function categoryPlaces(axis) {
|
|
1971
|
-
if (axis.type !== "category" || !
|
|
2037
|
+
if (axis.type !== "category" || !isUnknownArray(axis.data))
|
|
1972
2038
|
return undefined;
|
|
1973
|
-
return new Map(axis.data.map((category, place) => [
|
|
2039
|
+
return new Map(axis.data.map((category, place) => [textOf(category), place]));
|
|
1974
2040
|
}
|
|
1975
2041
|
/**
|
|
1976
2042
|
* The interval series of one runtime series: one custom series with the `interval` renderer, after the series
|
|
@@ -2039,6 +2105,10 @@ function deriveFacets(context, facet, columns, resolved, axes) {
|
|
|
2039
2105
|
if (context.collector !== undefined) {
|
|
2040
2106
|
context.collector.failed = true;
|
|
2041
2107
|
}
|
|
2108
|
+
const first = resolved[0];
|
|
2109
|
+
if (first === undefined) {
|
|
2110
|
+
return err(problem(context.blockId, "The composition carries no series."));
|
|
2111
|
+
}
|
|
2042
2112
|
const split = splitByChannel(context.rows, channel.value);
|
|
2043
2113
|
if (split.length > FACET_PANEL_LIMIT) {
|
|
2044
2114
|
return err(problem(context.blockId, `The facet splits the table into ${split.length} panels. A facet holds ${FACET_PANEL_LIMIT} panels at most, thus a table of fewer groups serves the reader.`));
|
|
@@ -2055,24 +2125,26 @@ function deriveFacets(context, facet, columns, resolved, axes) {
|
|
|
2055
2125
|
emitted.push({ ...entry, option: { ...entry.option, xAxisIndex: place, yAxisIndex: place } });
|
|
2056
2126
|
}
|
|
2057
2127
|
}
|
|
2058
|
-
const labeledPanels = labeledSeries(context, emitted, isHorizontalBar(
|
|
2059
|
-
const labeled =
|
|
2060
|
-
const shared = sharedAxes(context, resolved, axes, labeled);
|
|
2128
|
+
const labeledPanels = labeledSeries(context, emitted, isHorizontalBar(first.declared));
|
|
2129
|
+
const labeled = first.declared.form === "bar" && Object.keys(labelRoom(labeledPanels, isHorizontalBar(first.declared))).length > 0;
|
|
2130
|
+
const shared = sharedAxes(context, resolved, axes, labeled, isHorizontalBar(first.declared));
|
|
2061
2131
|
// A continuous color draws its scale at the right edge, thus the panels leave that band free.
|
|
2062
2132
|
const scaleBand = emitted.some((entry) => entry.entry?.color !== undefined) ? COLOR_SCALE_BAND_PCT : 0;
|
|
2063
2133
|
const layout = facetLayout(panels.map((panel) => panel.name), shared, legendOf(drawnNames(emitted)), scaleBand);
|
|
2064
2134
|
const named = resolved.some((entry) => entry.label !== undefined) || context.labeled.size > 0;
|
|
2065
2135
|
const maps = visualMaps(context, resolved, emitted);
|
|
2066
|
-
|
|
2136
|
+
const panel = {
|
|
2067
2137
|
tooltip: named ? { ...NAMED_TOOLTIP } : { ...PLAIN_TOOLTIP },
|
|
2068
2138
|
grid: layout.grid,
|
|
2069
2139
|
xAxis: layout.xAxis,
|
|
2070
2140
|
yAxis: layout.yAxis,
|
|
2071
2141
|
series: labeledPanels,
|
|
2072
2142
|
graphic: layout.graphic,
|
|
2073
|
-
...(maps.length > 0 ? { visualMap: maps } : {}),
|
|
2074
2143
|
legend: layout.legend,
|
|
2075
|
-
}
|
|
2144
|
+
};
|
|
2145
|
+
if (maps.length > 0)
|
|
2146
|
+
panel.visualMap = maps;
|
|
2147
|
+
return ok(panel);
|
|
2076
2148
|
}
|
|
2077
2149
|
/**
|
|
2078
2150
|
* The layout of the panels of a facet, one panel for each name in order.
|
|
@@ -2140,12 +2212,12 @@ function facetLayout(names, shared, legend, scaleBand) {
|
|
|
2140
2212
|
* turned label still covers its neighbor. `widthPx` is the panel width on the page, and an x axis alone states it.
|
|
2141
2213
|
*/
|
|
2142
2214
|
function panelAxis(axis, widthPx) {
|
|
2143
|
-
const label =
|
|
2215
|
+
const label = parseUnknownRecord(axis.axisLabel) ?? {};
|
|
2144
2216
|
const base = { ...withoutName(axis), splitNumber: FACET_SPLIT_NUMBER };
|
|
2145
|
-
if (axis.type !== "category" || !
|
|
2217
|
+
if (axis.type !== "category" || !isUnknownArray(axis.data))
|
|
2146
2218
|
return { ...base, axisLabel: { ...label, hideOverlap: true } };
|
|
2147
2219
|
const turn = widthPx === undefined || label.rotate !== undefined ? undefined : categoryTurn(axis.data, widthPx);
|
|
2148
|
-
return { ...base, axisLabel: { ...label, interval: 0,
|
|
2220
|
+
return { ...base, axisLabel: { ...label, interval: 0, rotate: turn } };
|
|
2149
2221
|
}
|
|
2150
2222
|
/** The width of one character of the chart text, as a share of the text size. */
|
|
2151
2223
|
const LABEL_CHARACTER_SHARE = 0.6;
|
|
@@ -2178,30 +2250,36 @@ function categoryTurn(categories, widthPx) {
|
|
|
2178
2250
|
function thinnedLabels(option) {
|
|
2179
2251
|
if (option.xAxis === undefined)
|
|
2180
2252
|
return option;
|
|
2181
|
-
let thinned = false;
|
|
2182
2253
|
const thin = (axis) => {
|
|
2183
|
-
|
|
2254
|
+
const fields = parseUnknownRecord(axis);
|
|
2255
|
+
if (fields === undefined)
|
|
2184
2256
|
return axis;
|
|
2185
|
-
const
|
|
2186
|
-
|
|
2187
|
-
if (fields.type !== "category" || !Array.isArray(fields.data) || label.rotate !== 90 || label.show === false)
|
|
2257
|
+
const label = parseUnknownRecord(fields.axisLabel) ?? {};
|
|
2258
|
+
if (fields.type !== "category" || !isUnknownArray(fields.data) || label.rotate !== 90 || label.show === false)
|
|
2188
2259
|
return axis;
|
|
2189
2260
|
const interval = categoryInterval(fields.data.length, CHART_PAGE_TEXT_PX, pagePlotWidth(option.grid, fields));
|
|
2190
2261
|
if (interval === 0)
|
|
2191
2262
|
return axis;
|
|
2192
|
-
thinned = true;
|
|
2193
2263
|
return { ...fields, axisLabel: { ...label, interval } };
|
|
2194
2264
|
};
|
|
2195
|
-
const
|
|
2196
|
-
|
|
2265
|
+
const declared = option.xAxis;
|
|
2266
|
+
const axes = Array.isArray(declared) ? declared : [declared];
|
|
2267
|
+
const thinnedAxes = axes.map(thin);
|
|
2268
|
+
const thinned = thinnedAxes.some((axis, index) => axis !== axes[index]);
|
|
2269
|
+
const [singleAxis] = thinnedAxes;
|
|
2270
|
+
const xAxis = Array.isArray(declared) ? thinnedAxes : singleAxis;
|
|
2271
|
+
const result = { ...option, xAxis };
|
|
2272
|
+
if (thinned && option.tooltip === undefined)
|
|
2273
|
+
result.tooltip = { trigger: "axis" };
|
|
2274
|
+
return result;
|
|
2197
2275
|
}
|
|
2198
2276
|
/**
|
|
2199
2277
|
* The plot width of the grid of one axis on the page, in pixels. A grid that states its width gives that width,
|
|
2200
2278
|
* as a facet panel does. Every other grid spans the page chart body less its two side margins.
|
|
2201
2279
|
*/
|
|
2202
2280
|
function pagePlotWidth(grid, axis) {
|
|
2203
|
-
const entry =
|
|
2204
|
-
const fields =
|
|
2281
|
+
const entry = isUnknownArray(grid) ? grid[typeof axis.gridIndex === "number" ? axis.gridIndex : 0] : grid;
|
|
2282
|
+
const fields = parseUnknownRecord(entry) ?? {};
|
|
2205
2283
|
const stated = pagePx(fields.width);
|
|
2206
2284
|
return stated > 0 ? stated : CHART_PAGE_WIDTH_PX - pagePx(fields.left) - pagePx(fields.right);
|
|
2207
2285
|
}
|
|
@@ -2242,7 +2320,7 @@ function withoutName(axis) {
|
|
|
2242
2320
|
* values. A category axis already lists the categories of every row, and a log axis keeps the range of the
|
|
2243
2321
|
* chart runtime.
|
|
2244
2322
|
*/
|
|
2245
|
-
function sharedAxes(context, resolved, axes, labeled) {
|
|
2323
|
+
function sharedAxes(context, resolved, axes, labeled, horizontal) {
|
|
2246
2324
|
const xs = [];
|
|
2247
2325
|
const ys = [];
|
|
2248
2326
|
for (const entry of resolved) {
|
|
@@ -2268,7 +2346,6 @@ function sharedAxes(context, resolved, axes, labeled) {
|
|
|
2268
2346
|
(horizontal ? xs : ys).push(0);
|
|
2269
2347
|
}
|
|
2270
2348
|
// The value labels of a bar sit past the bar ends, thus the value axis of the bar takes the label room.
|
|
2271
|
-
const horizontal = isHorizontalBar(resolved[0].declared);
|
|
2272
2349
|
return { xAxis: sharedRange(axes.xAxis, xs, labeled && horizontal), yAxis: sharedRange(axes.yAxis, ys, labeled && !horizontal) };
|
|
2273
2350
|
}
|
|
2274
2351
|
/**
|
|
@@ -2278,11 +2355,11 @@ function sharedAxes(context, resolved, axes, labeled) {
|
|
|
2278
2355
|
* of a bar chart with labels does on one panel. The zero of a bar stays the end of its side.
|
|
2279
2356
|
*/
|
|
2280
2357
|
function sharedRange(axis, values, room) {
|
|
2281
|
-
if (axis.type !== "value" || values.length === 0) {
|
|
2282
|
-
return axis;
|
|
2283
|
-
}
|
|
2284
2358
|
let low = lowest(values);
|
|
2285
2359
|
let high = highest(values);
|
|
2360
|
+
if (axis.type !== "value" || low === undefined || high === undefined) {
|
|
2361
|
+
return axis;
|
|
2362
|
+
}
|
|
2286
2363
|
if (room) {
|
|
2287
2364
|
const span = high - low;
|
|
2288
2365
|
if (high > 0)
|
|
@@ -2363,12 +2440,12 @@ function plottedSeries(entry, axes, meanings) {
|
|
|
2363
2440
|
const horizontal = isHorizontalBar(entry.declared);
|
|
2364
2441
|
const xAxis = horizontal ? axes.yAxis : axes.xAxis;
|
|
2365
2442
|
const yAxis = horizontal ? axes.xAxis : axes.yAxis;
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2443
|
+
const plotted = { ...entry };
|
|
2444
|
+
plotted.x = plottedChannel(entry.x, xAxis, meanings);
|
|
2445
|
+
plotted.y = plottedChannel(entry.y, yAxis, meanings);
|
|
2446
|
+
if (entry.y0 !== undefined)
|
|
2447
|
+
plotted.y0 = plottedChannel(entry.y0, yAxis, meanings);
|
|
2448
|
+
return plotted;
|
|
2372
2449
|
}
|
|
2373
2450
|
/**
|
|
2374
2451
|
* One plotted channel in the form that its axis reads.
|
|
@@ -2385,7 +2462,11 @@ function plottedSeries(entry, axes, meanings) {
|
|
|
2385
2462
|
function plottedChannel(channel, axis, meanings) {
|
|
2386
2463
|
if (axis.type === "category") {
|
|
2387
2464
|
const retyped = channel.values.some((cell) => typeof cell === "number");
|
|
2388
|
-
return {
|
|
2465
|
+
return {
|
|
2466
|
+
...channel,
|
|
2467
|
+
values: channel.values.map((cell) => (cell === null ? null : (categoryCell(cell) ?? null))),
|
|
2468
|
+
retyped: retyped ? true : undefined,
|
|
2469
|
+
};
|
|
2389
2470
|
}
|
|
2390
2471
|
if (channel.transformed || channel.values.some((cell) => cell !== null && isNonNumericString(cell)))
|
|
2391
2472
|
return channel;
|
|
@@ -2474,8 +2555,7 @@ function splitByChannel(rows, group) {
|
|
|
2474
2555
|
}
|
|
2475
2556
|
const buckets = [];
|
|
2476
2557
|
const byKey = new Map();
|
|
2477
|
-
for (
|
|
2478
|
-
const value = group.values[index];
|
|
2558
|
+
for (const [index, value] of group.values.entries()) {
|
|
2479
2559
|
if (value === null)
|
|
2480
2560
|
continue;
|
|
2481
2561
|
// The key carries the type of the cell, thus the number `1` and the string `"1"` are two groups.
|
|
@@ -2588,20 +2668,28 @@ function collectSource(collector, entry, split, labeled, form, rises) {
|
|
|
2588
2668
|
return;
|
|
2589
2669
|
}
|
|
2590
2670
|
const flags = split.indices.filter((index) => labeled.has(index));
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2671
|
+
const described = { x, y };
|
|
2672
|
+
if (color !== undefined)
|
|
2673
|
+
described.color = color;
|
|
2674
|
+
if (size !== undefined)
|
|
2675
|
+
described.size = size;
|
|
2676
|
+
if (group !== undefined)
|
|
2677
|
+
described.group = group;
|
|
2678
|
+
if (split.category === undefined && split.name !== undefined)
|
|
2679
|
+
described.value = split.name;
|
|
2680
|
+
if (split.category !== undefined)
|
|
2681
|
+
described.category = split.category;
|
|
2682
|
+
if (label !== undefined)
|
|
2683
|
+
described.label = label;
|
|
2684
|
+
if (flags.length > 0)
|
|
2685
|
+
described.flags = flags;
|
|
2686
|
+
if (SORTED_FORMS.has(form))
|
|
2687
|
+
described.sort = true;
|
|
2688
|
+
if (rises)
|
|
2689
|
+
described.rise = true;
|
|
2690
|
+
if (isHorizontalBar(entry.declared))
|
|
2691
|
+
described.swap = true;
|
|
2692
|
+
collector.series.push(described);
|
|
2605
2693
|
}
|
|
2606
2694
|
/**
|
|
2607
2695
|
* The payload column of one resolved channel, or `undefined` when the payload holds no such column or when the
|
|
@@ -2623,10 +2711,11 @@ function columnSource(collector, channel) {
|
|
|
2623
2711
|
* no item style, and the theme answers for it.
|
|
2624
2712
|
*/
|
|
2625
2713
|
function seriesItemStyle(color, form, density) {
|
|
2626
|
-
const fields = {
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2714
|
+
const fields = {};
|
|
2715
|
+
if (color !== undefined)
|
|
2716
|
+
fields.color = color;
|
|
2717
|
+
if (form === "scatter" && density === "crowd")
|
|
2718
|
+
fields.opacity = SCATTER_CROWD_OPACITY;
|
|
2630
2719
|
return Object.keys(fields).length > 0 ? { itemStyle: fields } : {};
|
|
2631
2720
|
}
|
|
2632
2721
|
/**
|
|
@@ -2640,11 +2729,9 @@ function seriesItemStyle(color, form, density) {
|
|
|
2640
2729
|
* then any carrier at all. Each guide reaches the page under every one of the three.
|
|
2641
2730
|
*/
|
|
2642
2731
|
function markCarrier(emitted) {
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
const colored = emitted.findIndex((entry) => entry.carriesMarks && !entry.muted);
|
|
2647
|
-
return colored >= 0 ? colored : emitted.findIndex((entry) => entry.carriesMarks);
|
|
2732
|
+
return (emitted.find((entry) => entry.carriesMarks && !entry.muted && !entry.empty) ??
|
|
2733
|
+
emitted.find((entry) => entry.carriesMarks && !entry.muted) ??
|
|
2734
|
+
emitted.find((entry) => entry.carriesMarks));
|
|
2648
2735
|
}
|
|
2649
2736
|
/**
|
|
2650
2737
|
* The points of one group. A row whose channel gives no value drops, and no substitute value appears. A wide
|
|
@@ -2655,7 +2742,7 @@ function collectPoints(entry, indices) {
|
|
|
2655
2742
|
for (const index of indices) {
|
|
2656
2743
|
const x = entry.x.values[index];
|
|
2657
2744
|
const y = entry.y.values[index];
|
|
2658
|
-
if (x === null || y === null)
|
|
2745
|
+
if (x === null || x === undefined || y === null || y === undefined)
|
|
2659
2746
|
continue;
|
|
2660
2747
|
const point = { index, x, y };
|
|
2661
2748
|
if (entry.y0 !== undefined) {
|
|
@@ -2733,14 +2820,21 @@ function seriesData(entry, points, labeled, horizontal, itemColor) {
|
|
|
2733
2820
|
continue;
|
|
2734
2821
|
}
|
|
2735
2822
|
itemObjects = true;
|
|
2736
|
-
|
|
2823
|
+
const item = {
|
|
2737
2824
|
value: pair,
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
}
|
|
2825
|
+
};
|
|
2826
|
+
// A marked point of a series with no label channel takes the x cell as its name. Thus the
|
|
2827
|
+
// `{b}` of the label template and of the tooltip names a cell of the row, and never nothing.
|
|
2828
|
+
if (named || marked) {
|
|
2829
|
+
item.name = named ? String(label) : String(point.x);
|
|
2830
|
+
}
|
|
2831
|
+
if (color !== undefined) {
|
|
2832
|
+
item.itemStyle = { color };
|
|
2833
|
+
}
|
|
2834
|
+
if (marked) {
|
|
2835
|
+
item.label = { ...POINT_LABEL };
|
|
2836
|
+
}
|
|
2837
|
+
data.push(item);
|
|
2744
2838
|
}
|
|
2745
2839
|
return { data, itemObjects };
|
|
2746
2840
|
}
|
|
@@ -2806,13 +2900,19 @@ function formOptions(form, density, perPoint) {
|
|
|
2806
2900
|
return { step: "end", showSymbol: false };
|
|
2807
2901
|
case "area":
|
|
2808
2902
|
return { showSymbol: false, areaStyle: {} };
|
|
2809
|
-
case "scatter":
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2903
|
+
case "scatter": {
|
|
2904
|
+
const scatter = {};
|
|
2905
|
+
if (density !== "normal") {
|
|
2906
|
+
scatter.symbolSize = density === "crowd" ? SCATTER_CROWD_SYMBOL_SIZE : SCATTER_HOVER_SYMBOL_SIZE;
|
|
2907
|
+
}
|
|
2908
|
+
// The large path draws a simplified point in one fill, and it drops a per-item style. Thus a
|
|
2909
|
+
// series whose items carry a name, a label, a color, or a size keeps the normal path.
|
|
2910
|
+
if (!perPoint) {
|
|
2911
|
+
scatter.large = true;
|
|
2912
|
+
scatter.largeThreshold = LARGE_SCATTER_THRESHOLD;
|
|
2913
|
+
}
|
|
2914
|
+
return scatter;
|
|
2915
|
+
}
|
|
2816
2916
|
}
|
|
2817
2917
|
}
|
|
2818
2918
|
/**
|
|
@@ -2869,15 +2969,16 @@ function pointLabelRows(blockId, annotations, rows, columns, plotted) {
|
|
|
2869
2969
|
*/
|
|
2870
2970
|
function topRows(rows, column, order, n, plotted) {
|
|
2871
2971
|
const ranked = [];
|
|
2872
|
-
for (
|
|
2873
|
-
|
|
2874
|
-
|
|
2972
|
+
for (const [index, row] of rows.entries()) {
|
|
2973
|
+
const cell = row[column];
|
|
2974
|
+
if (plotted.has(index) && cell !== undefined)
|
|
2975
|
+
ranked.push({ index, cell });
|
|
2875
2976
|
}
|
|
2876
2977
|
ranked.sort((a, b) => {
|
|
2877
|
-
const compared = compareCell(
|
|
2978
|
+
const compared = compareCell(a.cell, b.cell);
|
|
2878
2979
|
return order === "asc" ? compared : -compared;
|
|
2879
2980
|
});
|
|
2880
|
-
return ranked.slice(0, n);
|
|
2981
|
+
return ranked.slice(0, n).map((entry) => entry.index);
|
|
2881
2982
|
}
|
|
2882
2983
|
/**
|
|
2883
2984
|
* The mark members of the annotations.
|
|
@@ -2902,10 +3003,12 @@ function markMembers(annotations) {
|
|
|
2902
3003
|
]);
|
|
2903
3004
|
}
|
|
2904
3005
|
}
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
3006
|
+
const marks = {};
|
|
3007
|
+
if (lines.length > 0)
|
|
3008
|
+
marks.markLine = guideMarkLine(lines);
|
|
3009
|
+
if (areas.length > 0)
|
|
3010
|
+
marks.markArea = { silent: true, data: areas };
|
|
3011
|
+
return marks;
|
|
2909
3012
|
}
|
|
2910
3013
|
/**
|
|
2911
3014
|
* The label of one mark member. The text is a constant of the annotation, and never a template.
|
|
@@ -2914,10 +3017,11 @@ function markMembers(annotations) {
|
|
|
2914
3017
|
* its own default, and a member of either kind that states nothing gives the same bytes as before.
|
|
2915
3018
|
*/
|
|
2916
3019
|
function markLabel(label, position) {
|
|
2917
|
-
const fields = {
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
3020
|
+
const fields = {};
|
|
3021
|
+
if (label !== undefined)
|
|
3022
|
+
fields.formatter = label;
|
|
3023
|
+
if (position !== undefined)
|
|
3024
|
+
fields.position = position;
|
|
2921
3025
|
return Object.keys(fields).length > 0 ? { label: fields } : {};
|
|
2922
3026
|
}
|
|
2923
3027
|
/** The mark key of one axis. A mark member names `xAxis` or `yAxis`, and the constant that sits on it. */
|
|
@@ -3014,13 +3118,13 @@ function compositionAxis(context, channel, axis, declared, preset) {
|
|
|
3014
3118
|
if (base.type !== "category") {
|
|
3015
3119
|
return err(problem(context.blockId, valueAxisOrderFault(channel.column)));
|
|
3016
3120
|
}
|
|
3017
|
-
const ordered = orderChannel(context, channel, base.data);
|
|
3121
|
+
const ordered = orderChannel(context, channel, isUnknownArray(base.data) ? base.data : []);
|
|
3018
3122
|
return ordered.map((data) => ({ ...base, data }));
|
|
3019
3123
|
}
|
|
3020
3124
|
/** Sort the categories of one composition channel by its order, or keep them where it declares none. */
|
|
3021
3125
|
function orderChannel(context, channel, categories) {
|
|
3022
3126
|
const order = channel.order;
|
|
3023
|
-
return orderCategories(context.blockId, context.rows.length, (index) => channel.values[index], categories, order, (index) => (order === undefined ? undefined : context.rows[index][order.by]));
|
|
3127
|
+
return orderCategories(context.blockId, context.rows.length, (index) => channel.values[index], categories, order, (index) => (order === undefined ? undefined : context.rows[index]?.[order.by]));
|
|
3024
3128
|
}
|
|
3025
3129
|
// ── The shared building blocks ──────────────────────────────────────────────
|
|
3026
3130
|
/**
|
|
@@ -3096,7 +3200,7 @@ function orderedAxis(blockId, rows, column, axis, titles, order, categorical) {
|
|
|
3096
3200
|
if (inferred.type !== "category") {
|
|
3097
3201
|
return err(problem(blockId, valueAxisOrderFault(column)));
|
|
3098
3202
|
}
|
|
3099
|
-
const sorted = orderCategories(blockId, rows.length, (index) => String(rows[index][column]), inferred.data, order, (index) => rows[index][order.by]);
|
|
3203
|
+
const sorted = orderCategories(blockId, rows.length, (index) => String(rows[index]?.[column]), isUnknownArray(inferred.data) ? inferred.data : [], order, (index) => rows[index]?.[order.by]);
|
|
3100
3204
|
return sorted.map((data) => ({ ...inferred, data }));
|
|
3101
3205
|
}
|
|
3102
3206
|
/** The refusal of an order on a channel whose axis draws values. */
|
|
@@ -3134,24 +3238,26 @@ function focusSet(blockId, focus, rowCount, categories) {
|
|
|
3134
3238
|
* no function and the plotted value stays the cell.
|
|
3135
3239
|
*/
|
|
3136
3240
|
function withValueLabels(series, horizontal, textOf, labelable = () => true) {
|
|
3137
|
-
const labeled = (entry) => entry.type === "bar" && entry.stack === undefined &&
|
|
3241
|
+
const labeled = (entry) => entry.type === "bar" && entry.stack === undefined && isUnknownArray(entry.data);
|
|
3138
3242
|
let count = 0;
|
|
3139
3243
|
for (const entry of series) {
|
|
3140
|
-
if (labeled(entry))
|
|
3244
|
+
if (labeled(entry) && isUnknownArray(entry.data))
|
|
3141
3245
|
count += entry.data.length;
|
|
3142
3246
|
}
|
|
3143
3247
|
if (count === 0 || count > BAR_VALUE_LABEL_LIMIT) {
|
|
3144
3248
|
return [...series];
|
|
3145
3249
|
}
|
|
3146
3250
|
return series.map((entry, index) => {
|
|
3147
|
-
if (!labeled(entry) || !labelable(index))
|
|
3251
|
+
if (!labeled(entry) || !labelable(index) || !isUnknownArray(entry.data))
|
|
3148
3252
|
return entry;
|
|
3149
3253
|
const data = entry.data.map((item) => {
|
|
3150
3254
|
// A bar item is a pair or an object whose value is the pair, thus the two forms read one field.
|
|
3151
|
-
const fields =
|
|
3152
|
-
|
|
3255
|
+
const fields = parseUnknownRecord(item) ?? { value: item };
|
|
3256
|
+
const itemValue = fields.value;
|
|
3257
|
+
if (fields.label !== undefined || !isUnknownArray(itemValue))
|
|
3153
3258
|
return item;
|
|
3154
|
-
const
|
|
3259
|
+
const read = itemValue[horizontal ? 0 : 1];
|
|
3260
|
+
const cell = typeof read === "number" || typeof read === "string" ? read : undefined;
|
|
3155
3261
|
return { ...fields, label: { show: true, position: labelPosition(cell, horizontal), formatter: textOf(cell, index) } };
|
|
3156
3262
|
});
|
|
3157
3263
|
return { ...entry, data };
|
|
@@ -3173,12 +3279,13 @@ function labelRoom(series, horizontal) {
|
|
|
3173
3279
|
let negative = false;
|
|
3174
3280
|
let positive = false;
|
|
3175
3281
|
for (const entry of series) {
|
|
3176
|
-
if (entry.type !== "bar" || !
|
|
3282
|
+
if (entry.type !== "bar" || !isUnknownArray(entry.data))
|
|
3177
3283
|
continue;
|
|
3178
3284
|
for (const item of entry.data) {
|
|
3179
|
-
|
|
3285
|
+
const fields = parseUnknownRecord(item);
|
|
3286
|
+
if (fields?.label === undefined)
|
|
3180
3287
|
continue;
|
|
3181
|
-
const value =
|
|
3288
|
+
const value = fields.value;
|
|
3182
3289
|
// The sign rule of `labelPosition`: a bar under zero puts its label at its lower end.
|
|
3183
3290
|
if ((toNumber(Array.isArray(value) ? value[horizontal ? 0 : 1] : null) ?? 0) < 0)
|
|
3184
3291
|
negative = true;
|
|
@@ -3303,6 +3410,9 @@ function histogramEdges(values) {
|
|
|
3303
3410
|
const sorted = [...values].sort((a, b) => a - b);
|
|
3304
3411
|
const min = sorted[0];
|
|
3305
3412
|
const max = sorted[sorted.length - 1];
|
|
3413
|
+
if (min === undefined || max === undefined) {
|
|
3414
|
+
return [];
|
|
3415
|
+
}
|
|
3306
3416
|
if (max === min) {
|
|
3307
3417
|
return [min, max];
|
|
3308
3418
|
}
|
|
@@ -3335,16 +3445,20 @@ function autoBinCount(sorted, min, max) {
|
|
|
3335
3445
|
/** The bin counts for the values against the edges. The max value falls in the last bin. */
|
|
3336
3446
|
function binCounts(values, edges) {
|
|
3337
3447
|
const bins = edges.length - 1;
|
|
3338
|
-
const counts = new Array(bins).fill(0);
|
|
3339
3448
|
const min = edges[0];
|
|
3340
|
-
const
|
|
3449
|
+
const max = edges[bins];
|
|
3450
|
+
if (bins < 1 || min === undefined || max === undefined) {
|
|
3451
|
+
return [];
|
|
3452
|
+
}
|
|
3453
|
+
const width = (max - min) / bins;
|
|
3454
|
+
const counts = new Array(bins).fill(0);
|
|
3341
3455
|
for (const value of values) {
|
|
3342
3456
|
let index = width === 0 ? 0 : Math.floor((value - min) / width);
|
|
3343
3457
|
if (index < 0)
|
|
3344
3458
|
index = 0;
|
|
3345
3459
|
if (index >= bins)
|
|
3346
3460
|
index = bins - 1;
|
|
3347
|
-
counts[index]
|
|
3461
|
+
counts[index] = (counts[index] ?? 0) + 1;
|
|
3348
3462
|
}
|
|
3349
3463
|
return counts;
|
|
3350
3464
|
}
|
|
@@ -3352,8 +3466,12 @@ function binCounts(values, edges) {
|
|
|
3352
3466
|
function histogramSeries(values, edges, name) {
|
|
3353
3467
|
const counts = binCounts(values, edges);
|
|
3354
3468
|
const data = [];
|
|
3355
|
-
for (
|
|
3356
|
-
|
|
3469
|
+
for (const [index, count] of counts.entries()) {
|
|
3470
|
+
const low = edges[index];
|
|
3471
|
+
const high = edges[index + 1];
|
|
3472
|
+
if (low === undefined || high === undefined)
|
|
3473
|
+
continue;
|
|
3474
|
+
data.push([(low + high) / 2, count]);
|
|
3357
3475
|
}
|
|
3358
3476
|
if (name === undefined) {
|
|
3359
3477
|
return { type: "bar", barWidth: "99%", data };
|
|
@@ -3439,6 +3557,8 @@ function violinShape(values) {
|
|
|
3439
3557
|
return undefined;
|
|
3440
3558
|
const min = sorted[0];
|
|
3441
3559
|
const max = sorted[n - 1];
|
|
3560
|
+
if (min === undefined || max === undefined)
|
|
3561
|
+
return undefined;
|
|
3442
3562
|
const grid = [];
|
|
3443
3563
|
for (let point = 0; point < VIOLIN_GRID_POINTS; point += 1) {
|
|
3444
3564
|
grid.push(min + (point * (max - min)) / (VIOLIN_GRID_POINTS - 1));
|
|
@@ -3469,13 +3589,10 @@ function roundWidth(width) {
|
|
|
3469
3589
|
* linearly between the `floor` and the `ceil` of that index.
|
|
3470
3590
|
*/
|
|
3471
3591
|
function quantileType7(sorted, p) {
|
|
3472
|
-
const
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
if (low === high)
|
|
3479
|
-
return sorted[low];
|
|
3480
|
-
return sorted[low] + (index - low) * (sorted[high] - sorted[low]);
|
|
3592
|
+
const index = p * (sorted.length - 1);
|
|
3593
|
+
const low = sorted[Math.floor(index)];
|
|
3594
|
+
const high = sorted[Math.ceil(index)];
|
|
3595
|
+
if (low === undefined || high === undefined)
|
|
3596
|
+
return Number.NaN;
|
|
3597
|
+
return low + (index - Math.floor(index)) * (high - low);
|
|
3481
3598
|
}
|