From 9ec77aa39c94731c2c618ab6e99696b935ec938e Mon Sep 17 00:00:00 2001 From: OlegWock Date: Wed, 15 Oct 2025 12:52:58 +0200 Subject: [PATCH 1/9] feat(charts): Add visualization blocks support --- build/esbuild/build.ts | 5 + package-lock.json | 2054 ++++++++++++++++- package.json | 13 + src/kernels/execution/cellExecution.ts | 9 +- .../converters/visualizationBlockConverter.ts | 68 + .../visualizationBlockConverter.unit.test.ts | 344 +++ .../deepnote/deepnoteDataConverter.ts | 81 +- .../vega-renderer/VegaRenderer.tsx | 51 + .../webview-side/vega-renderer/colors.ts | 38 + .../webview-side/vega-renderer/index.ts | 58 + .../vega-renderer/number-formats.ts | 17 + 11 files changed, 2648 insertions(+), 90 deletions(-) create mode 100644 src/notebooks/deepnote/converters/visualizationBlockConverter.ts create mode 100644 src/notebooks/deepnote/converters/visualizationBlockConverter.unit.test.ts create mode 100644 src/webviews/webview-side/vega-renderer/VegaRenderer.tsx create mode 100644 src/webviews/webview-side/vega-renderer/colors.ts create mode 100644 src/webviews/webview-side/vega-renderer/index.ts create mode 100644 src/webviews/webview-side/vega-renderer/number-formats.ts diff --git a/build/esbuild/build.ts b/build/esbuild/build.ts index 80f4393b80..eaf0837afb 100644 --- a/build/esbuild/build.ts +++ b/build/esbuild/build.ts @@ -329,6 +329,11 @@ async function buildAll() { path.join(extensionFolder, 'dist', 'webviews', 'webview-side', 'dataframeRenderer', 'dataframeRenderer.js'), { target: 'web', watch: isWatchMode } ), + build( + path.join(extensionFolder, 'src', 'webviews', 'webview-side', 'vega-renderer', 'index.ts'), + path.join(extensionFolder, 'dist', 'webviews', 'webview-side', 'vegaRenderer', 'vegaRenderer.js'), + { target: 'web', watch: isWatchMode } + ), build( path.join(extensionFolder, 'src', 'webviews', 'webview-side', 'variable-view', 'index.tsx'), path.join(extensionFolder, 'dist', 'webviews', 'webview-side', 'viewers', 'variableView.js'), diff --git a/package-lock.json b/package-lock.json index 28ab4f22db..64dba78251 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,7 @@ "bootstrap": "^5.0.0", "bootstrap-less": "^3.3.8", "cross-fetch": "^3.1.5", + "d3-format": "^3.1.0", "encoding": "^0.1.13", "fast-deep-equal": "^2.0.1", "format-util": "^1.0.5", @@ -52,6 +53,7 @@ "react-redux": "^7.1.1", "react-svg-pan-zoom": "3.9.0", "react-svgmt": "1.1.11", + "react-vega": "^7.7.1", "react-virtualized": "^9.21.1", "redux": "^4.0.4", "redux-logger": "^3.0.6", @@ -67,6 +69,7 @@ "tcp-port-used": "^1.0.1", "tmp": "^0.2.4", "url-parse": "^1.5.10", + "vega-embed": "^7.1.0", "vscode-debugprotocol": "^1.41.0", "vscode-languageclient": "8.0.2-next.5", "vscode-tas-client": "^0.1.84", @@ -87,6 +90,7 @@ "@types/chai-arrays": "^2.0.1", "@types/chai-as-promised": "^7.1.6", "@types/cors": "^2.8.6", + "@types/d3-format": "^3.0.4", "@types/debug": "^4.1.5", "@types/dedent": "^0.7.0", "@types/del": "^4.0.0", @@ -2765,12 +2769,6 @@ "url": "https://opencollective.com/unts" } }, - "node_modules/@pkgr/utils/node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true - }, "node_modules/@playwright/browser-chromium": { "version": "1.54.1", "resolved": "https://registry.npmjs.org/@playwright/browser-chromium/-/browser-chromium-1.54.1.tgz", @@ -3197,6 +3195,13 @@ "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", "dev": true }, + "node_modules/@types/d3-format": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/debug": { "version": "4.1.7", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", @@ -3235,11 +3240,10 @@ } }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true, - "optional": true, + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT", "peer": true }, "node_modules/@types/event-stream": { @@ -3266,6 +3270,13 @@ "@types/node": "*" } }, + "node_modules/@types/geojson": { + "version": "7946.0.4", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.4.tgz", + "integrity": "sha512-MHmwBtCb7OCv1DSivz2UNJXPGU/1btAWRKlqJ2saEhVJkpkvqHMMaOpKg0v4sAbDWSQekHGvPVMM8nQ+Jen03Q==", + "license": "MIT", + "peer": true + }, "node_modules/@types/get-port": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/@types/get-port/-/get-port-3.2.0.tgz", @@ -6133,7 +6144,6 @@ "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, "peer": true }, "node_modules/comment-parser": { @@ -6644,6 +6654,19 @@ "type": "^1.0.1" } }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "peer": true, + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/d3-color": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", @@ -6652,15 +6675,145 @@ "node": ">=12" } }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "license": "ISC", + "peer": true, + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "license": "ISC", + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "license": "ISC", + "peer": true, + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 10" + } + }, "node_modules/d3-ease": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.7.tgz", "integrity": "sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ==" }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "license": "ISC", + "peer": true, + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/d3-format": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "license": "ISC", + "peer": true, + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo-projection": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/d3-geo-projection/-/d3-geo-projection-4.0.0.tgz", + "integrity": "sha512-p0bK60CEzph1iqmnxut7d/1kyTmm3UWtPlwdkM31AU+LW+BXazd5zJdoCn7VFxNCHXRngPHRnsNn5uGjLRGndg==", + "license": "ISC", + "peer": true, + "dependencies": { + "commander": "7", + "d3-array": "1 - 3", + "d3-geo": "1.12.0 - 3" + }, + "bin": { + "geo2svg": "bin/geo2svg.js", + "geograticule": "bin/geograticule.js", + "geoproject": "bin/geoproject.js", + "geoquantize": "bin/geoquantize.js", + "geostitch": "bin/geostitch.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo-projection/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "license": "ISC", + "peer": true, "engines": { "node": ">=12" } @@ -6673,6 +6826,96 @@ "d3-color": "1" } }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "license": "ISC", + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "peer": true, + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "license": "ISC", + "peer": true, + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "peer": true, + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "peer": true, + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "peer": true, + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/d3-timer": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz", @@ -7029,6 +7272,16 @@ "rimraf": "bin.js" } }, + "node_modules/delaunator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "license": "ISC", + "peer": true, + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -7768,7 +8021,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, "engines": { "node": ">=6" } @@ -8731,6 +8983,12 @@ "node": ">= 6" } }, + "node_modules/fast-json-patch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz", + "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==", + "license": "MIT" + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -9168,11 +9426,23 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, "engines": { "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-east-asian-width": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", + "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-func-name": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", @@ -10297,6 +10567,16 @@ "node": ">= 0.4" } }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "peer": true, + "engines": { + "node": ">=12" + } + }, "node_modules/inversify": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/inversify/-/inversify-6.0.1.tgz", @@ -11347,6 +11627,12 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "node_modules/json-stringify-pretty-compact": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-4.0.0.tgz", + "integrity": "sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==", + "license": "MIT" + }, "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -14822,6 +15108,90 @@ "react-dom": "^16.3.0" } }, + "node_modules/react-vega": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/react-vega/-/react-vega-7.7.1.tgz", + "integrity": "sha512-Dj7n1LkfJEkY/FdwQfOZqIQ+wGUcJNwlTuWhYcuQtbBpTgvtI4wwqOvJ0QWBE19nXMU7t9HmP8sqQO5v6soOlg==", + "license": "Apache-2.0", + "dependencies": { + "@types/react": "*", + "fast-deep-equal": "^3.1.1", + "prop-types": "^15.8.1", + "vega-embed": "6.5.1" + }, + "peerDependencies": { + "react": "^16 || ^17 || ^18 || ^19", + "vega": "*", + "vega-lite": "*" + } + }, + "node_modules/react-vega/node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/react-vega/node_modules/json-stringify-pretty-compact": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-2.0.0.tgz", + "integrity": "sha512-WRitRfs6BGq4q8gTgOy4ek7iPFXjbra0H3PmDLKm2xnZ+Gh1HUhiKGgCZkSPNULlP7mvfu6FV/mOLhCarspADQ==", + "license": "MIT" + }, + "node_modules/react-vega/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/react-vega/node_modules/vega-embed": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/vega-embed/-/vega-embed-6.5.1.tgz", + "integrity": "sha512-yz/L1bN3+fLOpgXVb/8sCRv4GlZpD2/ngeKJAFRiHTIRm5zK6W0KuqZZvyGaO7E4s7RuYjW1TWhRIOqh5rS5hA==", + "license": "BSD-3-Clause", + "dependencies": { + "fast-json-patch": "^3.0.0-1", + "json-stringify-pretty-compact": "^2.0.0", + "semver": "^7.1.3", + "vega-schema-url-parser": "^1.1.0", + "vega-themes": "^2.8.2", + "vega-tooltip": "^0.22.0" + }, + "peerDependencies": { + "vega": "^5.8.0", + "vega-lite": "*" + } + }, + "node_modules/react-vega/node_modules/vega-schema-url-parser": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vega-schema-url-parser/-/vega-schema-url-parser-1.1.0.tgz", + "integrity": "sha512-Tc85J2ofMZZOsxiqDM9sbvfsa+Vdo3GwNLjEEsPOsCDeYqsUHKAlc1IpbbhPLZ6jusyM9Lk0e1izF64GGklFDg==", + "license": "BSD-3-Clause" + }, + "node_modules/react-vega/node_modules/vega-themes": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/vega-themes/-/vega-themes-2.15.0.tgz", + "integrity": "sha512-DicRAKG9z+23A+rH/3w3QjJvKnlGhSbbUXGjBvYGseZ1lvj9KQ0BXZ2NS/+MKns59LNpFNHGi9us/wMlci4TOA==", + "license": "BSD-3-Clause", + "peerDependencies": { + "vega": "*", + "vega-lite": "*" + } + }, + "node_modules/react-vega/node_modules/vega-tooltip": { + "version": "0.22.1", + "resolved": "https://registry.npmjs.org/vega-tooltip/-/vega-tooltip-0.22.1.tgz", + "integrity": "sha512-mPmzxwvi6+2ZgbZ/+mNC7XbSu5I6Ckon8zdgUfH9neb+vV7CKlV/FYypMdVN/9iDMFUqGzybYdqNOiSPPIxFEQ==", + "license": "BSD-3-Clause", + "dependencies": { + "vega-util": "^1.13.1" + } + }, "node_modules/react-virtualized": { "version": "9.22.6", "resolved": "https://registry.npmjs.org/react-virtualized/-/react-virtualized-9.22.6.tgz", @@ -15238,6 +15608,13 @@ "inherits": "^2.0.1" } }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", + "license": "Unlicense", + "peer": true + }, "node_modules/run-applescript": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", @@ -15332,6 +15709,13 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause", + "peer": true + }, "node_modules/rxjs": { "version": "6.6.7", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", @@ -16290,12 +16674,6 @@ "url": "https://opencollective.com/unts" } }, - "node_modules/synckit/node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true - }, "node_modules/tailwindcss": { "version": "4.1.14", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.14.tgz", @@ -16666,6 +17044,21 @@ "node": ">=0.6" } }, + "node_modules/topojson-client": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/topojson-client/-/topojson-client-3.1.0.tgz", + "integrity": "sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw==", + "license": "ISC", + "peer": true, + "dependencies": { + "commander": "2" + }, + "bin": { + "topo2geo": "bin/topo2geo", + "topomerge": "bin/topomerge", + "topoquantize": "bin/topoquantize" + } + }, "node_modules/transformation-matrix": { "version": "2.11.1", "resolved": "https://registry.npmjs.org/transformation-matrix/-/transformation-matrix-2.11.1.tgz", @@ -16753,9 +17146,10 @@ } }, "node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" }, "node_modules/tslint": { "version": "6.1.3", @@ -17420,9 +17814,718 @@ "node": ">= 0.8" } }, - "node_modules/vinyl-contents": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/vinyl-contents/-/vinyl-contents-2.0.0.tgz", + "node_modules/vega": { + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/vega/-/vega-5.33.0.tgz", + "integrity": "sha512-jNAGa7TxLojOpMMMrKMXXBos4K6AaLJbCgGDOw1YEkLRjUkh12pcf65J2lMSdEHjcEK47XXjKiOUVZ8L+MniBA==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "vega-crossfilter": "~4.1.3", + "vega-dataflow": "~5.7.7", + "vega-encode": "~4.10.2", + "vega-event-selector": "~3.0.1", + "vega-expression": "~5.2.0", + "vega-force": "~4.2.2", + "vega-format": "~1.1.3", + "vega-functions": "~5.18.0", + "vega-geo": "~4.4.3", + "vega-hierarchy": "~4.1.3", + "vega-label": "~1.3.1", + "vega-loader": "~4.5.3", + "vega-parser": "~6.6.0", + "vega-projection": "~1.6.2", + "vega-regression": "~1.3.1", + "vega-runtime": "~6.2.1", + "vega-scale": "~7.4.2", + "vega-scenegraph": "~4.13.1", + "vega-statistics": "~1.9.0", + "vega-time": "~2.1.3", + "vega-transforms": "~4.12.1", + "vega-typings": "~1.5.0", + "vega-util": "~1.17.2", + "vega-view": "~5.16.0", + "vega-view-transforms": "~4.6.1", + "vega-voronoi": "~4.2.4", + "vega-wordcloud": "~4.1.6" + } + }, + "node_modules/vega-canvas": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/vega-canvas/-/vega-canvas-1.2.7.tgz", + "integrity": "sha512-OkJ9CACVcN9R5Pi9uF6MZBF06pO6qFpDYHWSKBJsdHP5o724KrsgR6UvbnXFH82FdsiTOff/HqjuaG8C7FL+9Q==", + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/vega-crossfilter": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/vega-crossfilter/-/vega-crossfilter-4.1.3.tgz", + "integrity": "sha512-nyPJAXAUABc3EocUXvAL1J/IWotZVsApIcvOeZaUdEQEtZ7bt8VtP2nj3CLbHBA8FZZVV+K6SmdwvCOaAD4wFQ==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "d3-array": "^3.2.2", + "vega-dataflow": "^5.7.7", + "vega-util": "^1.17.3" + } + }, + "node_modules/vega-dataflow": { + "version": "5.7.7", + "resolved": "https://registry.npmjs.org/vega-dataflow/-/vega-dataflow-5.7.7.tgz", + "integrity": "sha512-R2NX2HvgXL+u4E6u+L5lKvvRiCtnE6N6l+umgojfi53suhhkFP+zB+2UAQo4syxuZ4763H1csfkKc4xpqLzKnw==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "vega-format": "^1.1.3", + "vega-loader": "^4.5.3", + "vega-util": "^1.17.3" + } + }, + "node_modules/vega-embed": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/vega-embed/-/vega-embed-7.1.0.tgz", + "integrity": "sha512-ZmEIn5XJrQt7fSh2lwtSdXG/9uf3yIqZnvXFEwBJRppiBgrEWZcZbj6VK3xn8sNTFQ+sQDXW5sl/6kmbAW3s5A==", + "license": "BSD-3-Clause", + "dependencies": { + "fast-json-patch": "^3.1.1", + "json-stringify-pretty-compact": "^4.0.0", + "semver": "^7.7.2", + "tslib": "^2.8.1", + "vega-interpreter": "^2.0.0", + "vega-schema-url-parser": "^3.0.2", + "vega-themes": "3.0.0", + "vega-tooltip": "1.0.0" + }, + "funding": { + "url": "https://app.hubspot.com/payments/GyPC972GD9Rt" + }, + "peerDependencies": { + "vega": "*", + "vega-lite": "*" + } + }, + "node_modules/vega-embed/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/vega-encode": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/vega-encode/-/vega-encode-4.10.2.tgz", + "integrity": "sha512-fsjEY1VaBAmqwt7Jlpz0dpPtfQFiBdP9igEefvumSpy7XUxOJmDQcRDnT3Qh9ctkv3itfPfI9g8FSnGcv2b4jQ==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "d3-array": "^3.2.2", + "d3-interpolate": "^3.0.1", + "vega-dataflow": "^5.7.7", + "vega-scale": "^7.4.2", + "vega-util": "^1.17.3" + } + }, + "node_modules/vega-encode/node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "peer": true, + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/vega-event-selector": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/vega-event-selector/-/vega-event-selector-3.0.1.tgz", + "integrity": "sha512-K5zd7s5tjr1LiOOkjGpcVls8GsH/f2CWCrWcpKy74gTCp+llCdwz0Enqo013ZlGaRNjfgD/o1caJRt3GSaec4A==", + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/vega-expression": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/vega-expression/-/vega-expression-5.2.0.tgz", + "integrity": "sha512-WRMa4ny3iZIVAzDlBh3ipY2QUuLk2hnJJbfbncPgvTF7BUgbIbKq947z+JicWksYbokl8n1JHXJoqi3XvpG0Zw==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "@types/estree": "^1.0.0", + "vega-util": "^1.17.3" + } + }, + "node_modules/vega-force": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/vega-force/-/vega-force-4.2.2.tgz", + "integrity": "sha512-cHZVaY2VNNIG2RyihhSiWniPd2W9R9kJq0znxzV602CgUVgxEfTKtx/lxnVCn8nNrdKAYrGiqIsBzIeKG1GWHw==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "d3-force": "^3.0.0", + "vega-dataflow": "^5.7.7", + "vega-util": "^1.17.3" + } + }, + "node_modules/vega-format": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/vega-format/-/vega-format-1.1.3.tgz", + "integrity": "sha512-wQhw7KR46wKJAip28FF/CicW+oiJaPAwMKdrxlnTA0Nv8Bf7bloRlc+O3kON4b4H1iALLr9KgRcYTOeXNs2MOA==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "d3-array": "^3.2.2", + "d3-format": "^3.1.0", + "d3-time-format": "^4.1.0", + "vega-time": "^2.1.3", + "vega-util": "^1.17.3" + } + }, + "node_modules/vega-functions": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/vega-functions/-/vega-functions-5.18.0.tgz", + "integrity": "sha512-+D+ey4bDAhZA2CChh7bRZrcqRUDevv05kd2z8xH+il7PbYQLrhi6g1zwvf8z3KpgGInFf5O13WuFK5DQGkz5lQ==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "d3-array": "^3.2.2", + "d3-color": "^3.1.0", + "d3-geo": "^3.1.0", + "vega-dataflow": "^5.7.7", + "vega-expression": "^5.2.0", + "vega-scale": "^7.4.2", + "vega-scenegraph": "^4.13.1", + "vega-selections": "^5.6.0", + "vega-statistics": "^1.9.0", + "vega-time": "^2.1.3", + "vega-util": "^1.17.3" + } + }, + "node_modules/vega-geo": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/vega-geo/-/vega-geo-4.4.3.tgz", + "integrity": "sha512-+WnnzEPKIU1/xTFUK3EMu2htN35gp9usNZcC0ZFg2up1/Vqu6JyZsX0PIO51oXSIeXn9bwk6VgzlOmJUcx92tA==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "d3-array": "^3.2.2", + "d3-color": "^3.1.0", + "d3-geo": "^3.1.0", + "vega-canvas": "^1.2.7", + "vega-dataflow": "^5.7.7", + "vega-projection": "^1.6.2", + "vega-statistics": "^1.9.0", + "vega-util": "^1.17.3" + } + }, + "node_modules/vega-hierarchy": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/vega-hierarchy/-/vega-hierarchy-4.1.3.tgz", + "integrity": "sha512-0Z+TYKRgOEo8XYXnJc2HWg1EGpcbNAhJ9Wpi9ubIbEyEHqIgjCIyFVN8d4nSfsJOcWDzsSmRqohBztxAhOCSaw==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "d3-hierarchy": "^3.1.2", + "vega-dataflow": "^5.7.7", + "vega-util": "^1.17.3" + } + }, + "node_modules/vega-interpreter": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/vega-interpreter/-/vega-interpreter-2.2.1.tgz", + "integrity": "sha512-o+4ZEme2mdFLewlpF76dwPWW2VkZ3TAF3DMcq75/NzA5KPvnN4wnlCM8At2FVawbaHRyGdVkJSS5ROF5KwpHPQ==", + "license": "BSD-3-Clause", + "dependencies": { + "vega-util": "^2.1.0" + } + }, + "node_modules/vega-interpreter/node_modules/vega-util": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/vega-util/-/vega-util-2.1.0.tgz", + "integrity": "sha512-PGfp0m0QCufDmcxKJCWQy4Ov23FoF8DSXmoJwSezi3itQaa2hbxK0+xwsTMP2vy4PR16Pu25HMzgMwXVW1+33w==", + "license": "BSD-3-Clause" + }, + "node_modules/vega-label": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/vega-label/-/vega-label-1.3.1.tgz", + "integrity": "sha512-Emx4b5s7pvuRj3fBkAJ/E2snCoZACfKAwxVId7f/4kYVlAYLb5Swq6W8KZHrH4M9Qds1XJRUYW9/Y3cceqzEFA==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "vega-canvas": "^1.2.7", + "vega-dataflow": "^5.7.7", + "vega-scenegraph": "^4.13.1", + "vega-util": "^1.17.3" + } + }, + "node_modules/vega-lite": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/vega-lite/-/vega-lite-6.4.1.tgz", + "integrity": "sha512-KO3ybHNouRK4A0al/+2fN9UqgTEfxrd/ntGLY933Hg5UOYotDVQdshR3zn7OfXwQ7uj0W96Vfa5R+QxO8am3IQ==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "json-stringify-pretty-compact": "~4.0.0", + "tslib": "~2.8.1", + "vega-event-selector": "~4.0.0", + "vega-expression": "~6.1.0", + "vega-util": "~2.1.0", + "yargs": "~18.0.0" + }, + "bin": { + "vl2pdf": "bin/vl2pdf", + "vl2png": "bin/vl2png", + "vl2svg": "bin/vl2svg", + "vl2vg": "bin/vl2vg" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://app.hubspot.com/payments/GyPC972GD9Rt" + }, + "peerDependencies": { + "vega": "^6.0.0" + } + }, + "node_modules/vega-lite/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/vega-lite/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/vega-lite/node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "license": "ISC", + "peer": true, + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/vega-lite/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "license": "MIT", + "peer": true + }, + "node_modules/vega-lite/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vega-lite/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/vega-lite/node_modules/vega-event-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/vega-event-selector/-/vega-event-selector-4.0.0.tgz", + "integrity": "sha512-CcWF4m4KL/al1Oa5qSzZ5R776q8lRxCj3IafCHs5xipoEHrkgu1BWa7F/IH5HrDNXeIDnqOpSV1pFsAWRak4gQ==", + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/vega-lite/node_modules/vega-expression": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/vega-expression/-/vega-expression-6.1.0.tgz", + "integrity": "sha512-hHgNx/fQ1Vn1u6vHSamH7lRMsOa/yQeHGGcWVmh8fZafLdwdhCM91kZD9p7+AleNpgwiwzfGogtpATFaMmDFYg==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "@types/estree": "^1.0.8", + "vega-util": "^2.1.0" + } + }, + "node_modules/vega-lite/node_modules/vega-util": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/vega-util/-/vega-util-2.1.0.tgz", + "integrity": "sha512-PGfp0m0QCufDmcxKJCWQy4Ov23FoF8DSXmoJwSezi3itQaa2hbxK0+xwsTMP2vy4PR16Pu25HMzgMwXVW1+33w==", + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/vega-lite/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/vega-lite/node_modules/yargs": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", + "license": "MIT", + "peer": true, + "dependencies": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^7.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/vega-lite/node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "license": "ISC", + "peer": true, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/vega-loader": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/vega-loader/-/vega-loader-4.5.3.tgz", + "integrity": "sha512-dUfIpxTLF2magoMaur+jXGvwMxjtdlDZaIS8lFj6N7IhUST6nIvBzuUlRM+zLYepI5GHtCLOnqdKU4XV0NggCA==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "d3-dsv": "^3.0.1", + "node-fetch": "^2.6.7", + "topojson-client": "^3.1.0", + "vega-format": "^1.1.3", + "vega-util": "^1.17.3" + } + }, + "node_modules/vega-parser": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/vega-parser/-/vega-parser-6.6.0.tgz", + "integrity": "sha512-jltyrwCTtWeidi/6VotLCybhIl+ehwnzvFWYOdWNUP0z/EskdB64YmawNwjCjzTBMemeiQtY6sJPPbewYqe3Vg==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "vega-dataflow": "^5.7.7", + "vega-event-selector": "^3.0.1", + "vega-functions": "^5.18.0", + "vega-scale": "^7.4.2", + "vega-util": "^1.17.3" + } + }, + "node_modules/vega-projection": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/vega-projection/-/vega-projection-1.6.2.tgz", + "integrity": "sha512-3pcVaQL9R3Zfk6PzopLX6awzrQUeYOXJzlfLGP2Xd93mqUepBa6m/reVrTUoSFXA3v9lfK4W/PS2AcVzD/MIcQ==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "d3-geo": "^3.1.0", + "d3-geo-projection": "^4.0.0", + "vega-scale": "^7.4.2" + } + }, + "node_modules/vega-regression": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/vega-regression/-/vega-regression-1.3.1.tgz", + "integrity": "sha512-AmccF++Z9uw4HNZC/gmkQGe6JsRxTG/R4QpbcSepyMvQN1Rj5KtVqMcmVFP1r3ivM4dYGFuPlzMWvuqp0iKMkQ==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "d3-array": "^3.2.2", + "vega-dataflow": "^5.7.7", + "vega-statistics": "^1.9.0", + "vega-util": "^1.17.3" + } + }, + "node_modules/vega-runtime": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/vega-runtime/-/vega-runtime-6.2.1.tgz", + "integrity": "sha512-b4eot3tWKCk++INWqot+6sLn3wDTj/HE+tRSbiaf8aecuniPMlwJEK7wWuhVGeW2Ae5n8fI/8TeTViaC94bNHA==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "vega-dataflow": "^5.7.7", + "vega-util": "^1.17.3" + } + }, + "node_modules/vega-scale": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/vega-scale/-/vega-scale-7.4.2.tgz", + "integrity": "sha512-o6Hl76aU1jlCK7Q8DPYZ8OGsp4PtzLdzI6nGpLt8rxoE78QuB3GBGEwGAQJitp4IF7Lb2rL5oAXEl3ZP6xf9jg==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "d3-array": "^3.2.2", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-scale-chromatic": "^3.1.0", + "vega-time": "^2.1.3", + "vega-util": "^1.17.3" + } + }, + "node_modules/vega-scale/node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "peer": true, + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/vega-scenegraph": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/vega-scenegraph/-/vega-scenegraph-4.13.1.tgz", + "integrity": "sha512-LFY9+sLIxRfdDI9ZTKjLoijMkIAzPLBWHpPkwv4NPYgdyx+0qFmv+puBpAUGUY9VZqAZ736Uj5NJY9zw+/M3yQ==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "d3-path": "^3.1.0", + "d3-shape": "^3.2.0", + "vega-canvas": "^1.2.7", + "vega-loader": "^4.5.3", + "vega-scale": "^7.4.2", + "vega-util": "^1.17.3" + } + }, + "node_modules/vega-schema-url-parser": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/vega-schema-url-parser/-/vega-schema-url-parser-3.0.2.tgz", + "integrity": "sha512-xAnR7KAvNPYewI3O0l5QGdT8Tv0+GCZQjqfP39cW/hbe/b3aYMAQ39vm8O2wfXUHzm04xTe7nolcsx8WQNVLRQ==", + "license": "BSD-3-Clause" + }, + "node_modules/vega-selections": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/vega-selections/-/vega-selections-5.6.0.tgz", + "integrity": "sha512-UE2w78rUUbaV3Ph+vQbQDwh8eywIJYRxBiZdxEG/Tr/KtFMLdy2BDgNZuuDO1Nv8jImPJwONmqjNhNDYwM0VJQ==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "d3-array": "3.2.4", + "vega-expression": "^5.2.0", + "vega-util": "^1.17.3" + } + }, + "node_modules/vega-statistics": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/vega-statistics/-/vega-statistics-1.9.0.tgz", + "integrity": "sha512-GAqS7mkatpXcMCQKWtFu1eMUKLUymjInU0O8kXshWaQrVWjPIO2lllZ1VNhdgE0qGj4oOIRRS11kzuijLshGXQ==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "d3-array": "^3.2.2" + } + }, + "node_modules/vega-themes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/vega-themes/-/vega-themes-3.0.0.tgz", + "integrity": "sha512-1iFiI3BNmW9FrsLnDLx0ZKEddsCitRY3XmUAwp6qmp+p+IXyJYc9pfjlVj9E6KXBPfm4cQyU++s0smKNiWzO4g==", + "license": "BSD-3-Clause", + "funding": { + "url": "https://app.hubspot.com/payments/GyPC972GD9Rt" + }, + "peerDependencies": { + "vega": "*", + "vega-lite": "*" + } + }, + "node_modules/vega-time": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/vega-time/-/vega-time-2.1.3.tgz", + "integrity": "sha512-hFcWPdTV844IiY0m97+WUoMLADCp+8yUQR1NStWhzBzwDDA7QEGGwYGxALhdMOaDTwkyoNj3V/nox2rQAJD/vQ==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "d3-array": "^3.2.2", + "d3-time": "^3.1.0", + "vega-util": "^1.17.3" + } + }, + "node_modules/vega-tooltip": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/vega-tooltip/-/vega-tooltip-1.0.0.tgz", + "integrity": "sha512-P1R0JP29v0qnTuwzCQ0SPJlkjAzr6qeyj+H4VgUFSykHmHc1OBxda//XBaFDl/bZgIscEMvjKSjZpXd84x3aZQ==", + "license": "BSD-3-Clause", + "dependencies": { + "vega-util": "^2.0.0" + }, + "funding": { + "url": "https://app.hubspot.com/payments/GyPC972GD9Rt" + } + }, + "node_modules/vega-tooltip/node_modules/vega-util": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/vega-util/-/vega-util-2.1.0.tgz", + "integrity": "sha512-PGfp0m0QCufDmcxKJCWQy4Ov23FoF8DSXmoJwSezi3itQaa2hbxK0+xwsTMP2vy4PR16Pu25HMzgMwXVW1+33w==", + "license": "BSD-3-Clause" + }, + "node_modules/vega-transforms": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/vega-transforms/-/vega-transforms-4.12.1.tgz", + "integrity": "sha512-Qxo+xeEEftY1jYyKgzOGc9NuW4/MqGm1YPZ5WrL9eXg2G0410Ne+xL/MFIjHF4hRX+3mgFF4Io2hPpfy/thjLg==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "d3-array": "^3.2.2", + "vega-dataflow": "^5.7.7", + "vega-statistics": "^1.9.0", + "vega-time": "^2.1.3", + "vega-util": "^1.17.3" + } + }, + "node_modules/vega-typings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/vega-typings/-/vega-typings-1.5.0.tgz", + "integrity": "sha512-tcZ2HwmiQEOXIGyBMP8sdCnoFoVqHn4KQ4H0MQiHwzFU1hb1EXURhfc+Uamthewk4h/9BICtAM3AFQMjBGpjQA==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "@types/geojson": "7946.0.4", + "vega-event-selector": "^3.0.1", + "vega-expression": "^5.2.0", + "vega-util": "^1.17.3" + } + }, + "node_modules/vega-util": { + "version": "1.17.3", + "resolved": "https://registry.npmjs.org/vega-util/-/vega-util-1.17.3.tgz", + "integrity": "sha512-nSNpZLUrRvFo46M5OK4O6x6f08WD1yOcEzHNlqivF+sDLSsVpstaF6fdJYwrbf/debFi2L9Tkp4gZQtssup9iQ==", + "license": "BSD-3-Clause" + }, + "node_modules/vega-view": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/vega-view/-/vega-view-5.16.0.tgz", + "integrity": "sha512-Nxp1MEAY+8bphIm+7BeGFzWPoJnX9+hgvze6wqCAPoM69YiyVR0o0VK8M2EESIL+22+Owr0Fdy94hWHnmon5tQ==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "d3-array": "^3.2.2", + "d3-timer": "^3.0.1", + "vega-dataflow": "^5.7.7", + "vega-format": "^1.1.3", + "vega-functions": "^5.18.0", + "vega-runtime": "^6.2.1", + "vega-scenegraph": "^4.13.1", + "vega-util": "^1.17.3" + } + }, + "node_modules/vega-view-transforms": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/vega-view-transforms/-/vega-view-transforms-4.6.1.tgz", + "integrity": "sha512-RYlyMJu5kZV4XXjmyTQKADJWDB25SMHsiF+B1rbE1p+pmdQPlp5tGdPl9r5dUJOp3p8mSt/NGI8GPGucmPMxtw==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "vega-dataflow": "^5.7.7", + "vega-scenegraph": "^4.13.1", + "vega-util": "^1.17.3" + } + }, + "node_modules/vega-view/node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vega-voronoi": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/vega-voronoi/-/vega-voronoi-4.2.4.tgz", + "integrity": "sha512-lWNimgJAXGeRFu2Pz8axOUqVf1moYhD+5yhBzDSmckE9I5jLOyZc/XvgFTXwFnsVkMd1QW1vxJa+y9yfUblzYw==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "d3-delaunay": "^6.0.2", + "vega-dataflow": "^5.7.7", + "vega-util": "^1.17.3" + } + }, + "node_modules/vega-wordcloud": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/vega-wordcloud/-/vega-wordcloud-4.1.6.tgz", + "integrity": "sha512-lFmF3u9/ozU0P+WqPjeThQfZm0PigdbXDwpIUCxczrCXKYJLYFmZuZLZR7cxtmpZ0/yuvRvAJ4g123LXbSZF8A==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "vega-canvas": "^1.2.7", + "vega-dataflow": "^5.7.7", + "vega-scale": "^7.4.2", + "vega-statistics": "^1.9.0", + "vega-util": "^1.17.3" + } + }, + "node_modules/vinyl-contents": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vinyl-contents/-/vinyl-contents-2.0.0.tgz", "integrity": "sha512-cHq6NnGyi2pZ7xwdHSW1v4Jfnho4TEGtxZHw01cmnc8+i7jgR6bRnED/LbrKan/Q7CvVLbnvA5OepnhbpjBZ5Q==", "dev": true, "dependencies": { @@ -17835,7 +18938,6 @@ "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, "engines": { "node": ">=10" } @@ -19913,14 +21015,6 @@ "open": "^9.1.0", "picocolors": "^1.0.0", "tslib": "^2.6.0" - }, - "dependencies": { - "tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true - } } }, "@playwright/browser-chromium": { @@ -20200,6 +21294,12 @@ "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", "dev": true }, + "@types/d3-format": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", + "dev": true + }, "@types/debug": { "version": "4.1.7", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", @@ -20237,11 +21337,9 @@ } }, "@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true, - "optional": true, + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "peer": true }, "@types/event-stream": { @@ -20268,6 +21366,12 @@ "@types/node": "*" } }, + "@types/geojson": { + "version": "7946.0.4", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.4.tgz", + "integrity": "sha512-MHmwBtCb7OCv1DSivz2UNJXPGU/1btAWRKlqJ2saEhVJkpkvqHMMaOpKg0v4sAbDWSQekHGvPVMM8nQ+Jen03Q==", + "peer": true + }, "@types/get-port": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/@types/get-port/-/get-port-3.2.0.tgz", @@ -22407,7 +23511,6 @@ "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, "peer": true }, "comment-parser": { @@ -22828,21 +23931,109 @@ "type": "^1.0.1" } }, + "d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "peer": true, + "requires": { + "internmap": "1 - 2" + } + }, "d3-color": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==" }, + "d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "peer": true, + "requires": { + "delaunator": "5" + } + }, + "d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "peer": true + }, + "d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "peer": true, + "requires": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "dependencies": { + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "peer": true + } + } + }, "d3-ease": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.7.tgz", "integrity": "sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ==" }, + "d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "peer": true, + "requires": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + } + }, "d3-format": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==" }, + "d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "peer": true, + "requires": { + "d3-array": "2.5.0 - 3" + } + }, + "d3-geo-projection": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/d3-geo-projection/-/d3-geo-projection-4.0.0.tgz", + "integrity": "sha512-p0bK60CEzph1iqmnxut7d/1kyTmm3UWtPlwdkM31AU+LW+BXazd5zJdoCn7VFxNCHXRngPHRnsNn5uGjLRGndg==", + "peer": true, + "requires": { + "commander": "7", + "d3-array": "1 - 3", + "d3-geo": "1.12.0 - 3" + }, + "dependencies": { + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "peer": true + } + } + }, + "d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "peer": true + }, "d3-interpolate": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.4.0.tgz", @@ -22851,6 +24042,68 @@ "d3-color": "3.1.0" } }, + "d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "peer": true + }, + "d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "peer": true + }, + "d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "peer": true, + "requires": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + } + }, + "d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "peer": true, + "requires": { + "d3-color": "3.1.0", + "d3-interpolate": "1 - 3" + } + }, + "d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "peer": true, + "requires": { + "d3-path": "^3.1.0" + } + }, + "d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "peer": true, + "requires": { + "d3-array": "2 - 3" + } + }, + "d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "peer": true, + "requires": { + "d3-time": "1 - 3" + } + }, "d3-timer": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz", @@ -23102,6 +24355,15 @@ } } }, + "delaunator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "peer": true, + "requires": { + "robust-predicates": "^3.0.2" + } + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -23716,8 +24978,7 @@ "escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==" }, "escape-html": { "version": "1.0.3", @@ -24428,6 +25689,11 @@ } } }, + "fast-json-patch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz", + "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==" + }, "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -24749,8 +26015,13 @@ "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-east-asian-width": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", + "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", + "peer": true }, "get-func-name": { "version": "2.0.2", @@ -25572,6 +26843,12 @@ "side-channel": "^1.0.4" } }, + "internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "peer": true + }, "inversify": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/inversify/-/inversify-6.0.1.tgz", @@ -26311,6 +27588,11 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "json-stringify-pretty-compact": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-4.0.0.tgz", + "integrity": "sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==" + }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -28842,6 +30124,66 @@ "react-move": "^2.7.0" } }, + "react-vega": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/react-vega/-/react-vega-7.7.1.tgz", + "integrity": "sha512-Dj7n1LkfJEkY/FdwQfOZqIQ+wGUcJNwlTuWhYcuQtbBpTgvtI4wwqOvJ0QWBE19nXMU7t9HmP8sqQO5v6soOlg==", + "requires": { + "@types/react": "*", + "fast-deep-equal": "^3.1.1", + "prop-types": "^15.8.1", + "vega-embed": "6.5.1" + }, + "dependencies": { + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "json-stringify-pretty-compact": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-2.0.0.tgz", + "integrity": "sha512-WRitRfs6BGq4q8gTgOy4ek7iPFXjbra0H3PmDLKm2xnZ+Gh1HUhiKGgCZkSPNULlP7mvfu6FV/mOLhCarspADQ==" + }, + "semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==" + }, + "vega-embed": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/vega-embed/-/vega-embed-6.5.1.tgz", + "integrity": "sha512-yz/L1bN3+fLOpgXVb/8sCRv4GlZpD2/ngeKJAFRiHTIRm5zK6W0KuqZZvyGaO7E4s7RuYjW1TWhRIOqh5rS5hA==", + "requires": { + "fast-json-patch": "^3.0.0-1", + "json-stringify-pretty-compact": "^2.0.0", + "semver": "^7.1.3", + "vega-schema-url-parser": "^1.1.0", + "vega-themes": "^2.8.2", + "vega-tooltip": "^0.22.0" + } + }, + "vega-schema-url-parser": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vega-schema-url-parser/-/vega-schema-url-parser-1.1.0.tgz", + "integrity": "sha512-Tc85J2ofMZZOsxiqDM9sbvfsa+Vdo3GwNLjEEsPOsCDeYqsUHKAlc1IpbbhPLZ6jusyM9Lk0e1izF64GGklFDg==" + }, + "vega-themes": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/vega-themes/-/vega-themes-2.15.0.tgz", + "integrity": "sha512-DicRAKG9z+23A+rH/3w3QjJvKnlGhSbbUXGjBvYGseZ1lvj9KQ0BXZ2NS/+MKns59LNpFNHGi9us/wMlci4TOA==", + "requires": {} + }, + "vega-tooltip": { + "version": "0.22.1", + "resolved": "https://registry.npmjs.org/vega-tooltip/-/vega-tooltip-0.22.1.tgz", + "integrity": "sha512-mPmzxwvi6+2ZgbZ/+mNC7XbSu5I6Ckon8zdgUfH9neb+vV7CKlV/FYypMdVN/9iDMFUqGzybYdqNOiSPPIxFEQ==", + "requires": { + "vega-util": "^1.13.1" + } + } + } + }, "react-virtualized": { "version": "9.22.6", "resolved": "https://registry.npmjs.org/react-virtualized/-/react-virtualized-9.22.6.tgz", @@ -29146,6 +30488,12 @@ "inherits": "^2.0.1" } }, + "robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", + "peer": true + }, "run-applescript": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", @@ -29204,6 +30552,12 @@ "queue-microtask": "^1.2.2" } }, + "rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "peer": true + }, "rxjs": { "version": "6.6.7", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", @@ -29976,14 +31330,6 @@ "requires": { "@pkgr/utils": "^2.3.1", "tslib": "^2.5.0" - }, - "dependencies": { - "tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true - } } }, "tailwindcss": { @@ -30284,6 +31630,15 @@ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true }, + "topojson-client": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/topojson-client/-/topojson-client-3.1.0.tgz", + "integrity": "sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw==", + "peer": true, + "requires": { + "commander": "2" + } + }, "transformation-matrix": { "version": "2.11.1", "resolved": "https://registry.npmjs.org/transformation-matrix/-/transformation-matrix-2.11.1.tgz", @@ -30352,9 +31707,9 @@ } }, "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" }, "tslint": { "version": "6.1.3", @@ -30877,6 +32232,590 @@ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "dev": true }, + "vega": { + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/vega/-/vega-5.33.0.tgz", + "integrity": "sha512-jNAGa7TxLojOpMMMrKMXXBos4K6AaLJbCgGDOw1YEkLRjUkh12pcf65J2lMSdEHjcEK47XXjKiOUVZ8L+MniBA==", + "peer": true, + "requires": { + "vega-crossfilter": "~4.1.3", + "vega-dataflow": "~5.7.7", + "vega-encode": "~4.10.2", + "vega-event-selector": "~3.0.1", + "vega-expression": "~5.2.0", + "vega-force": "~4.2.2", + "vega-format": "~1.1.3", + "vega-functions": "~5.18.0", + "vega-geo": "~4.4.3", + "vega-hierarchy": "~4.1.3", + "vega-label": "~1.3.1", + "vega-loader": "~4.5.3", + "vega-parser": "~6.6.0", + "vega-projection": "~1.6.2", + "vega-regression": "~1.3.1", + "vega-runtime": "~6.2.1", + "vega-scale": "~7.4.2", + "vega-scenegraph": "~4.13.1", + "vega-statistics": "~1.9.0", + "vega-time": "~2.1.3", + "vega-transforms": "~4.12.1", + "vega-typings": "~1.5.0", + "vega-util": "~1.17.2", + "vega-view": "~5.16.0", + "vega-view-transforms": "~4.6.1", + "vega-voronoi": "~4.2.4", + "vega-wordcloud": "~4.1.6" + } + }, + "vega-canvas": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/vega-canvas/-/vega-canvas-1.2.7.tgz", + "integrity": "sha512-OkJ9CACVcN9R5Pi9uF6MZBF06pO6qFpDYHWSKBJsdHP5o724KrsgR6UvbnXFH82FdsiTOff/HqjuaG8C7FL+9Q==", + "peer": true + }, + "vega-crossfilter": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/vega-crossfilter/-/vega-crossfilter-4.1.3.tgz", + "integrity": "sha512-nyPJAXAUABc3EocUXvAL1J/IWotZVsApIcvOeZaUdEQEtZ7bt8VtP2nj3CLbHBA8FZZVV+K6SmdwvCOaAD4wFQ==", + "peer": true, + "requires": { + "d3-array": "^3.2.2", + "vega-dataflow": "^5.7.7", + "vega-util": "^1.17.3" + } + }, + "vega-dataflow": { + "version": "5.7.7", + "resolved": "https://registry.npmjs.org/vega-dataflow/-/vega-dataflow-5.7.7.tgz", + "integrity": "sha512-R2NX2HvgXL+u4E6u+L5lKvvRiCtnE6N6l+umgojfi53suhhkFP+zB+2UAQo4syxuZ4763H1csfkKc4xpqLzKnw==", + "peer": true, + "requires": { + "vega-format": "^1.1.3", + "vega-loader": "^4.5.3", + "vega-util": "^1.17.3" + } + }, + "vega-embed": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/vega-embed/-/vega-embed-7.1.0.tgz", + "integrity": "sha512-ZmEIn5XJrQt7fSh2lwtSdXG/9uf3yIqZnvXFEwBJRppiBgrEWZcZbj6VK3xn8sNTFQ+sQDXW5sl/6kmbAW3s5A==", + "requires": { + "fast-json-patch": "^3.1.1", + "json-stringify-pretty-compact": "^4.0.0", + "semver": "^7.7.2", + "tslib": "^2.8.1", + "vega-interpreter": "^2.0.0", + "vega-schema-url-parser": "^3.0.2", + "vega-themes": "3.0.0", + "vega-tooltip": "1.0.0" + }, + "dependencies": { + "semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==" + } + } + }, + "vega-encode": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/vega-encode/-/vega-encode-4.10.2.tgz", + "integrity": "sha512-fsjEY1VaBAmqwt7Jlpz0dpPtfQFiBdP9igEefvumSpy7XUxOJmDQcRDnT3Qh9ctkv3itfPfI9g8FSnGcv2b4jQ==", + "peer": true, + "requires": { + "d3-array": "^3.2.2", + "d3-interpolate": "^3.0.1", + "vega-dataflow": "^5.7.7", + "vega-scale": "^7.4.2", + "vega-util": "^1.17.3" + }, + "dependencies": { + "d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "peer": true, + "requires": { + "d3-color": "3.1.0" + } + } + } + }, + "vega-event-selector": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/vega-event-selector/-/vega-event-selector-3.0.1.tgz", + "integrity": "sha512-K5zd7s5tjr1LiOOkjGpcVls8GsH/f2CWCrWcpKy74gTCp+llCdwz0Enqo013ZlGaRNjfgD/o1caJRt3GSaec4A==", + "peer": true + }, + "vega-expression": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/vega-expression/-/vega-expression-5.2.0.tgz", + "integrity": "sha512-WRMa4ny3iZIVAzDlBh3ipY2QUuLk2hnJJbfbncPgvTF7BUgbIbKq947z+JicWksYbokl8n1JHXJoqi3XvpG0Zw==", + "peer": true, + "requires": { + "@types/estree": "^1.0.0", + "vega-util": "^1.17.3" + } + }, + "vega-force": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/vega-force/-/vega-force-4.2.2.tgz", + "integrity": "sha512-cHZVaY2VNNIG2RyihhSiWniPd2W9R9kJq0znxzV602CgUVgxEfTKtx/lxnVCn8nNrdKAYrGiqIsBzIeKG1GWHw==", + "peer": true, + "requires": { + "d3-force": "^3.0.0", + "vega-dataflow": "^5.7.7", + "vega-util": "^1.17.3" + } + }, + "vega-format": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/vega-format/-/vega-format-1.1.3.tgz", + "integrity": "sha512-wQhw7KR46wKJAip28FF/CicW+oiJaPAwMKdrxlnTA0Nv8Bf7bloRlc+O3kON4b4H1iALLr9KgRcYTOeXNs2MOA==", + "peer": true, + "requires": { + "d3-array": "^3.2.2", + "d3-format": "^3.1.0", + "d3-time-format": "^4.1.0", + "vega-time": "^2.1.3", + "vega-util": "^1.17.3" + } + }, + "vega-functions": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/vega-functions/-/vega-functions-5.18.0.tgz", + "integrity": "sha512-+D+ey4bDAhZA2CChh7bRZrcqRUDevv05kd2z8xH+il7PbYQLrhi6g1zwvf8z3KpgGInFf5O13WuFK5DQGkz5lQ==", + "peer": true, + "requires": { + "d3-array": "^3.2.2", + "d3-color": "3.1.0", + "d3-geo": "^3.1.0", + "vega-dataflow": "^5.7.7", + "vega-expression": "^5.2.0", + "vega-scale": "^7.4.2", + "vega-scenegraph": "^4.13.1", + "vega-selections": "^5.6.0", + "vega-statistics": "^1.9.0", + "vega-time": "^2.1.3", + "vega-util": "^1.17.3" + } + }, + "vega-geo": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/vega-geo/-/vega-geo-4.4.3.tgz", + "integrity": "sha512-+WnnzEPKIU1/xTFUK3EMu2htN35gp9usNZcC0ZFg2up1/Vqu6JyZsX0PIO51oXSIeXn9bwk6VgzlOmJUcx92tA==", + "peer": true, + "requires": { + "d3-array": "^3.2.2", + "d3-color": "3.1.0", + "d3-geo": "^3.1.0", + "vega-canvas": "^1.2.7", + "vega-dataflow": "^5.7.7", + "vega-projection": "^1.6.2", + "vega-statistics": "^1.9.0", + "vega-util": "^1.17.3" + } + }, + "vega-hierarchy": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/vega-hierarchy/-/vega-hierarchy-4.1.3.tgz", + "integrity": "sha512-0Z+TYKRgOEo8XYXnJc2HWg1EGpcbNAhJ9Wpi9ubIbEyEHqIgjCIyFVN8d4nSfsJOcWDzsSmRqohBztxAhOCSaw==", + "peer": true, + "requires": { + "d3-hierarchy": "^3.1.2", + "vega-dataflow": "^5.7.7", + "vega-util": "^1.17.3" + } + }, + "vega-interpreter": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/vega-interpreter/-/vega-interpreter-2.2.1.tgz", + "integrity": "sha512-o+4ZEme2mdFLewlpF76dwPWW2VkZ3TAF3DMcq75/NzA5KPvnN4wnlCM8At2FVawbaHRyGdVkJSS5ROF5KwpHPQ==", + "requires": { + "vega-util": "^2.1.0" + }, + "dependencies": { + "vega-util": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/vega-util/-/vega-util-2.1.0.tgz", + "integrity": "sha512-PGfp0m0QCufDmcxKJCWQy4Ov23FoF8DSXmoJwSezi3itQaa2hbxK0+xwsTMP2vy4PR16Pu25HMzgMwXVW1+33w==" + } + } + }, + "vega-label": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/vega-label/-/vega-label-1.3.1.tgz", + "integrity": "sha512-Emx4b5s7pvuRj3fBkAJ/E2snCoZACfKAwxVId7f/4kYVlAYLb5Swq6W8KZHrH4M9Qds1XJRUYW9/Y3cceqzEFA==", + "peer": true, + "requires": { + "vega-canvas": "^1.2.7", + "vega-dataflow": "^5.7.7", + "vega-scenegraph": "^4.13.1", + "vega-util": "^1.17.3" + } + }, + "vega-lite": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/vega-lite/-/vega-lite-6.4.1.tgz", + "integrity": "sha512-KO3ybHNouRK4A0al/+2fN9UqgTEfxrd/ntGLY933Hg5UOYotDVQdshR3zn7OfXwQ7uj0W96Vfa5R+QxO8am3IQ==", + "peer": true, + "requires": { + "json-stringify-pretty-compact": "~4.0.0", + "tslib": "~2.8.1", + "vega-event-selector": "~4.0.0", + "vega-expression": "~6.1.0", + "vega-util": "~2.1.0", + "yargs": "~18.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "peer": true + }, + "ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "peer": true + }, + "cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "peer": true, + "requires": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + } + }, + "emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "peer": true + }, + "string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "peer": true, + "requires": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + } + }, + "strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "peer": true, + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "vega-event-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/vega-event-selector/-/vega-event-selector-4.0.0.tgz", + "integrity": "sha512-CcWF4m4KL/al1Oa5qSzZ5R776q8lRxCj3IafCHs5xipoEHrkgu1BWa7F/IH5HrDNXeIDnqOpSV1pFsAWRak4gQ==", + "peer": true + }, + "vega-expression": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/vega-expression/-/vega-expression-6.1.0.tgz", + "integrity": "sha512-hHgNx/fQ1Vn1u6vHSamH7lRMsOa/yQeHGGcWVmh8fZafLdwdhCM91kZD9p7+AleNpgwiwzfGogtpATFaMmDFYg==", + "peer": true, + "requires": { + "@types/estree": "^1.0.8", + "vega-util": "^2.1.0" + } + }, + "vega-util": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/vega-util/-/vega-util-2.1.0.tgz", + "integrity": "sha512-PGfp0m0QCufDmcxKJCWQy4Ov23FoF8DSXmoJwSezi3itQaa2hbxK0+xwsTMP2vy4PR16Pu25HMzgMwXVW1+33w==", + "peer": true + }, + "wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "peer": true, + "requires": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + } + }, + "yargs": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", + "peer": true, + "requires": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^7.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + } + }, + "yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "peer": true + } + } + }, + "vega-loader": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/vega-loader/-/vega-loader-4.5.3.tgz", + "integrity": "sha512-dUfIpxTLF2magoMaur+jXGvwMxjtdlDZaIS8lFj6N7IhUST6nIvBzuUlRM+zLYepI5GHtCLOnqdKU4XV0NggCA==", + "peer": true, + "requires": { + "d3-dsv": "^3.0.1", + "node-fetch": "^2.6.7", + "topojson-client": "^3.1.0", + "vega-format": "^1.1.3", + "vega-util": "^1.17.3" + } + }, + "vega-parser": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/vega-parser/-/vega-parser-6.6.0.tgz", + "integrity": "sha512-jltyrwCTtWeidi/6VotLCybhIl+ehwnzvFWYOdWNUP0z/EskdB64YmawNwjCjzTBMemeiQtY6sJPPbewYqe3Vg==", + "peer": true, + "requires": { + "vega-dataflow": "^5.7.7", + "vega-event-selector": "^3.0.1", + "vega-functions": "^5.18.0", + "vega-scale": "^7.4.2", + "vega-util": "^1.17.3" + } + }, + "vega-projection": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/vega-projection/-/vega-projection-1.6.2.tgz", + "integrity": "sha512-3pcVaQL9R3Zfk6PzopLX6awzrQUeYOXJzlfLGP2Xd93mqUepBa6m/reVrTUoSFXA3v9lfK4W/PS2AcVzD/MIcQ==", + "peer": true, + "requires": { + "d3-geo": "^3.1.0", + "d3-geo-projection": "^4.0.0", + "vega-scale": "^7.4.2" + } + }, + "vega-regression": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/vega-regression/-/vega-regression-1.3.1.tgz", + "integrity": "sha512-AmccF++Z9uw4HNZC/gmkQGe6JsRxTG/R4QpbcSepyMvQN1Rj5KtVqMcmVFP1r3ivM4dYGFuPlzMWvuqp0iKMkQ==", + "peer": true, + "requires": { + "d3-array": "^3.2.2", + "vega-dataflow": "^5.7.7", + "vega-statistics": "^1.9.0", + "vega-util": "^1.17.3" + } + }, + "vega-runtime": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/vega-runtime/-/vega-runtime-6.2.1.tgz", + "integrity": "sha512-b4eot3tWKCk++INWqot+6sLn3wDTj/HE+tRSbiaf8aecuniPMlwJEK7wWuhVGeW2Ae5n8fI/8TeTViaC94bNHA==", + "peer": true, + "requires": { + "vega-dataflow": "^5.7.7", + "vega-util": "^1.17.3" + } + }, + "vega-scale": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/vega-scale/-/vega-scale-7.4.2.tgz", + "integrity": "sha512-o6Hl76aU1jlCK7Q8DPYZ8OGsp4PtzLdzI6nGpLt8rxoE78QuB3GBGEwGAQJitp4IF7Lb2rL5oAXEl3ZP6xf9jg==", + "peer": true, + "requires": { + "d3-array": "^3.2.2", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-scale-chromatic": "^3.1.0", + "vega-time": "^2.1.3", + "vega-util": "^1.17.3" + }, + "dependencies": { + "d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "peer": true, + "requires": { + "d3-color": "3.1.0" + } + } + } + }, + "vega-scenegraph": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/vega-scenegraph/-/vega-scenegraph-4.13.1.tgz", + "integrity": "sha512-LFY9+sLIxRfdDI9ZTKjLoijMkIAzPLBWHpPkwv4NPYgdyx+0qFmv+puBpAUGUY9VZqAZ736Uj5NJY9zw+/M3yQ==", + "peer": true, + "requires": { + "d3-path": "^3.1.0", + "d3-shape": "^3.2.0", + "vega-canvas": "^1.2.7", + "vega-loader": "^4.5.3", + "vega-scale": "^7.4.2", + "vega-util": "^1.17.3" + } + }, + "vega-schema-url-parser": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/vega-schema-url-parser/-/vega-schema-url-parser-3.0.2.tgz", + "integrity": "sha512-xAnR7KAvNPYewI3O0l5QGdT8Tv0+GCZQjqfP39cW/hbe/b3aYMAQ39vm8O2wfXUHzm04xTe7nolcsx8WQNVLRQ==" + }, + "vega-selections": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/vega-selections/-/vega-selections-5.6.0.tgz", + "integrity": "sha512-UE2w78rUUbaV3Ph+vQbQDwh8eywIJYRxBiZdxEG/Tr/KtFMLdy2BDgNZuuDO1Nv8jImPJwONmqjNhNDYwM0VJQ==", + "peer": true, + "requires": { + "d3-array": "3.2.4", + "vega-expression": "^5.2.0", + "vega-util": "^1.17.3" + } + }, + "vega-statistics": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/vega-statistics/-/vega-statistics-1.9.0.tgz", + "integrity": "sha512-GAqS7mkatpXcMCQKWtFu1eMUKLUymjInU0O8kXshWaQrVWjPIO2lllZ1VNhdgE0qGj4oOIRRS11kzuijLshGXQ==", + "peer": true, + "requires": { + "d3-array": "^3.2.2" + } + }, + "vega-themes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/vega-themes/-/vega-themes-3.0.0.tgz", + "integrity": "sha512-1iFiI3BNmW9FrsLnDLx0ZKEddsCitRY3XmUAwp6qmp+p+IXyJYc9pfjlVj9E6KXBPfm4cQyU++s0smKNiWzO4g==", + "requires": {} + }, + "vega-time": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/vega-time/-/vega-time-2.1.3.tgz", + "integrity": "sha512-hFcWPdTV844IiY0m97+WUoMLADCp+8yUQR1NStWhzBzwDDA7QEGGwYGxALhdMOaDTwkyoNj3V/nox2rQAJD/vQ==", + "peer": true, + "requires": { + "d3-array": "^3.2.2", + "d3-time": "^3.1.0", + "vega-util": "^1.17.3" + } + }, + "vega-tooltip": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/vega-tooltip/-/vega-tooltip-1.0.0.tgz", + "integrity": "sha512-P1R0JP29v0qnTuwzCQ0SPJlkjAzr6qeyj+H4VgUFSykHmHc1OBxda//XBaFDl/bZgIscEMvjKSjZpXd84x3aZQ==", + "requires": { + "vega-util": "^2.0.0" + }, + "dependencies": { + "vega-util": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/vega-util/-/vega-util-2.1.0.tgz", + "integrity": "sha512-PGfp0m0QCufDmcxKJCWQy4Ov23FoF8DSXmoJwSezi3itQaa2hbxK0+xwsTMP2vy4PR16Pu25HMzgMwXVW1+33w==" + } + } + }, + "vega-transforms": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/vega-transforms/-/vega-transforms-4.12.1.tgz", + "integrity": "sha512-Qxo+xeEEftY1jYyKgzOGc9NuW4/MqGm1YPZ5WrL9eXg2G0410Ne+xL/MFIjHF4hRX+3mgFF4Io2hPpfy/thjLg==", + "peer": true, + "requires": { + "d3-array": "^3.2.2", + "vega-dataflow": "^5.7.7", + "vega-statistics": "^1.9.0", + "vega-time": "^2.1.3", + "vega-util": "^1.17.3" + } + }, + "vega-typings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/vega-typings/-/vega-typings-1.5.0.tgz", + "integrity": "sha512-tcZ2HwmiQEOXIGyBMP8sdCnoFoVqHn4KQ4H0MQiHwzFU1hb1EXURhfc+Uamthewk4h/9BICtAM3AFQMjBGpjQA==", + "peer": true, + "requires": { + "@types/geojson": "7946.0.4", + "vega-event-selector": "^3.0.1", + "vega-expression": "^5.2.0", + "vega-util": "^1.17.3" + } + }, + "vega-util": { + "version": "1.17.3", + "resolved": "https://registry.npmjs.org/vega-util/-/vega-util-1.17.3.tgz", + "integrity": "sha512-nSNpZLUrRvFo46M5OK4O6x6f08WD1yOcEzHNlqivF+sDLSsVpstaF6fdJYwrbf/debFi2L9Tkp4gZQtssup9iQ==" + }, + "vega-view": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/vega-view/-/vega-view-5.16.0.tgz", + "integrity": "sha512-Nxp1MEAY+8bphIm+7BeGFzWPoJnX9+hgvze6wqCAPoM69YiyVR0o0VK8M2EESIL+22+Owr0Fdy94hWHnmon5tQ==", + "peer": true, + "requires": { + "d3-array": "^3.2.2", + "d3-timer": "^3.0.1", + "vega-dataflow": "^5.7.7", + "vega-format": "^1.1.3", + "vega-functions": "^5.18.0", + "vega-runtime": "^6.2.1", + "vega-scenegraph": "^4.13.1", + "vega-util": "^1.17.3" + }, + "dependencies": { + "d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "peer": true + } + } + }, + "vega-view-transforms": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/vega-view-transforms/-/vega-view-transforms-4.6.1.tgz", + "integrity": "sha512-RYlyMJu5kZV4XXjmyTQKADJWDB25SMHsiF+B1rbE1p+pmdQPlp5tGdPl9r5dUJOp3p8mSt/NGI8GPGucmPMxtw==", + "peer": true, + "requires": { + "vega-dataflow": "^5.7.7", + "vega-scenegraph": "^4.13.1", + "vega-util": "^1.17.3" + } + }, + "vega-voronoi": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/vega-voronoi/-/vega-voronoi-4.2.4.tgz", + "integrity": "sha512-lWNimgJAXGeRFu2Pz8axOUqVf1moYhD+5yhBzDSmckE9I5jLOyZc/XvgFTXwFnsVkMd1QW1vxJa+y9yfUblzYw==", + "peer": true, + "requires": { + "d3-delaunay": "^6.0.2", + "vega-dataflow": "^5.7.7", + "vega-util": "^1.17.3" + } + }, + "vega-wordcloud": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/vega-wordcloud/-/vega-wordcloud-4.1.6.tgz", + "integrity": "sha512-lFmF3u9/ozU0P+WqPjeThQfZm0PigdbXDwpIUCxczrCXKYJLYFmZuZLZR7cxtmpZ0/yuvRvAJ4g123LXbSZF8A==", + "peer": true, + "requires": { + "vega-canvas": "^1.2.7", + "vega-dataflow": "^5.7.7", + "vega-scale": "^7.4.2", + "vega-statistics": "^1.9.0", + "vega-util": "^1.17.3" + } + }, "vinyl-contents": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/vinyl-contents/-/vinyl-contents-2.0.0.tgz", @@ -31195,8 +33134,7 @@ "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" }, "yallist": { "version": "4.0.0", diff --git a/package.json b/package.json index 676ef1cb77..e9e4d1b216 100644 --- a/package.json +++ b/package.json @@ -1818,6 +1818,15 @@ "application/vnd.deepnote.dataframe.v3+json" ], "requiresMessaging": "optional" + }, + { + "id": "deepnote-vega-renderer", + "displayName": "Deepnote Vega Chart Renderer", + "entrypoint": "./dist/webviews/webview-side/vegaRenderer/vegaRenderer.js", + "mimeTypes": [ + "application/vnd.vega.v5+json" + ], + "requiresMessaging": "optional" } ], "viewsContainers": { @@ -2126,6 +2135,7 @@ "bootstrap": "^5.0.0", "bootstrap-less": "^3.3.8", "cross-fetch": "^3.1.5", + "d3-format": "^3.1.0", "encoding": "^0.1.13", "fast-deep-equal": "^2.0.1", "format-util": "^1.0.5", @@ -2151,6 +2161,7 @@ "react-redux": "^7.1.1", "react-svg-pan-zoom": "3.9.0", "react-svgmt": "1.1.11", + "react-vega": "^7.7.1", "react-virtualized": "^9.21.1", "redux": "^4.0.4", "redux-logger": "^3.0.6", @@ -2166,6 +2177,7 @@ "tcp-port-used": "^1.0.1", "tmp": "^0.2.4", "url-parse": "^1.5.10", + "vega-embed": "^7.1.0", "vscode-debugprotocol": "^1.41.0", "vscode-languageclient": "8.0.2-next.5", "vscode-tas-client": "^0.1.84", @@ -2186,6 +2198,7 @@ "@types/chai-arrays": "^2.0.1", "@types/chai-as-promised": "^7.1.6", "@types/cors": "^2.8.6", + "@types/d3-format": "^3.0.4", "@types/debug": "^4.1.5", "@types/dedent": "^0.7.0", "@types/del": "^4.0.0", diff --git a/src/kernels/execution/cellExecution.ts b/src/kernels/execution/cellExecution.ts index c069cddaec..8e8a2d79f1 100644 --- a/src/kernels/execution/cellExecution.ts +++ b/src/kernels/execution/cellExecution.ts @@ -32,8 +32,8 @@ import { KernelError } from '../errors/kernelError'; import { getCachedSysPrefix } from '../../platform/interpreter/helpers'; import { getCellMetadata } from '../../platform/common/utils'; import { NotebookCellExecutionState, notebookCellExecutions } from '../../platform/notebooks/cellExecutionStateService'; -import { createBlockFromPocket } from '../../notebooks/deepnote/pocket'; import { createPythonCode } from '@deepnote/blocks'; +import { DeepnoteDataConverter } from '../../notebooks/deepnote/deepnoteDataConverter'; /** * Factory for CellExecution objects. @@ -416,10 +416,11 @@ export class CellExecution implements ICellExecution, IDisposable { metadata: this.cell.metadata, outputs: [...(this.cell.outputs || [])] }; - const deepnoteBlock = createBlockFromPocket(cellData, this.cell.index); - // Use createPythonCode to generate code with table state already included - logger.info(`Cell ${this.cell.index}: Using createPythonCode to generate execution code with table state`); + const dataConverter = new DeepnoteDataConverter(); + const deepnoteBlock = dataConverter.convertCellToBlock(cellData, this.cell.index); + + logger.info(`Cell ${this.cell.index}: Using createPythonCode for ${deepnoteBlock.type} block`); code = createPythonCode(deepnoteBlock); // Generate metadata from our cell (some kernels expect this.) diff --git a/src/notebooks/deepnote/converters/visualizationBlockConverter.ts b/src/notebooks/deepnote/converters/visualizationBlockConverter.ts new file mode 100644 index 0000000000..62717b74c0 --- /dev/null +++ b/src/notebooks/deepnote/converters/visualizationBlockConverter.ts @@ -0,0 +1,68 @@ +import { NotebookCellData, NotebookCellKind } from 'vscode'; + +import type { BlockConverter } from './blockConverter'; +import type { DeepnoteBlock } from '../deepnoteTypes'; + +/** + * Converter for Deepnote visualization blocks (chart blocks). + * Displays blocks as editable JSON with variable name, spec, and filters. + * The JSON is converted to Python code at execution time. + */ +export class VisualizationBlockConverter implements BlockConverter { + applyChangesToBlock(block: DeepnoteBlock, cell: NotebookCellData): void { + block.content = ''; + + // Parse the JSON from the cell to update metadata + try { + const config = JSON.parse(cell.value || '{}'); + + if (!block.metadata) { + block.metadata = {}; + } + + if (config.variable) { + block.metadata.deepnote_variable_name = config.variable; + } + + if (config.spec) { + block.metadata.deepnote_visualization_spec = config.spec; + } + + if (config.filters) { + if (!block.metadata.deepnote_chart_filter) { + block.metadata.deepnote_chart_filter = {}; + } + block.metadata.deepnote_chart_filter.advancedFilters = config.filters; + } + } catch (error) { + // If JSON parsing fails, leave metadata unchanged + console.warn('Failed to parse visualization JSON:', error); + } + } + + canConvert(blockType: string): boolean { + return blockType.toLowerCase() === 'visualization'; + } + + convertToCell(block: DeepnoteBlock): NotebookCellData { + const variableName = (block.metadata as any)?.deepnote_variable_name || 'df'; + const spec = (block.metadata as any)?.deepnote_visualization_spec || {}; + const filters = (block.metadata as any)?.deepnote_chart_filter?.advancedFilters || []; + + // Create a clean JSON representation that users can edit + const config = { + variable: variableName, + spec: spec, + filters: filters + }; + + const jsonContent = JSON.stringify(config, null, 2); + const cell = new NotebookCellData(NotebookCellKind.Code, jsonContent, 'python'); + + return cell; + } + + getSupportedTypes(): string[] { + return ['visualization']; + } +} diff --git a/src/notebooks/deepnote/converters/visualizationBlockConverter.unit.test.ts b/src/notebooks/deepnote/converters/visualizationBlockConverter.unit.test.ts new file mode 100644 index 0000000000..be9e5defe1 --- /dev/null +++ b/src/notebooks/deepnote/converters/visualizationBlockConverter.unit.test.ts @@ -0,0 +1,344 @@ +import { assert } from 'chai'; +import { NotebookCellData, NotebookCellKind } from 'vscode'; + +import type { DeepnoteBlock } from '../deepnoteTypes'; +import { VisualizationBlockConverter } from './visualizationBlockConverter'; + +suite('VisualizationBlockConverter', () => { + let converter: VisualizationBlockConverter; + + setup(() => { + converter = new VisualizationBlockConverter(); + }); + + suite('canConvert', () => { + test('returns true for visualization type', () => { + assert.isTrue(converter.canConvert('visualization')); + }); + + test('canConvert ignores case', () => { + assert.isTrue(converter.canConvert('VISUALIZATION')); + assert.isTrue(converter.canConvert('Visualization')); + assert.isTrue(converter.canConvert('ViSuAlIzAtIoN')); + }); + + test('returns false for non-visualization types', () => { + assert.isFalse(converter.canConvert('code')); + assert.isFalse(converter.canConvert('markdown')); + assert.isFalse(converter.canConvert('text-cell-h1')); + assert.isFalse(converter.canConvert('unknown')); + }); + }); + + suite('getSupportedTypes', () => { + test('returns array with visualization type', () => { + const types = converter.getSupportedTypes(); + + assert.deepStrictEqual(types, ['visualization']); + }); + }); + + suite('convertToCell', () => { + test('converts visualization block with metadata to Python code', () => { + const block: DeepnoteBlock = { + blockGroup: 'test-group', + content: '', + id: 'block-123', + sortingKey: 'a0', + type: 'visualization', + metadata: { + deepnote_variable_name: 'date_df', + deepnote_visualization_spec: { + layer: [{ mark: 'bar' }], + config: { legend: { disable: false } } + } + } + }; + + const cell = converter.convertToCell(block); + + assert.strictEqual(cell.kind, NotebookCellKind.Code); + assert.strictEqual(cell.languageId, 'python'); + assert.include(cell.value, '_dntk.DeepnoteChart('); + assert.include(cell.value, 'date_df'); + assert.include(cell.value, '"layer"'); + assert.include(cell.value, '"mark": "bar"'); + assert.include(cell.value, 'False'); + assert.notInclude(cell.value, 'false'); + }); + + test('converts boolean values to Python format', () => { + const block: DeepnoteBlock = { + blockGroup: 'test-group', + content: '', + id: 'block-123', + sortingKey: 'a0', + type: 'visualization', + metadata: { + deepnote_variable_name: 'df', + deepnote_visualization_spec: { + enabled: true, + disabled: false, + nullValue: null + } + } + }; + + const cell = converter.convertToCell(block); + + assert.include(cell.value, 'True'); + assert.include(cell.value, 'False'); + assert.include(cell.value, 'None'); + assert.notInclude(cell.value, 'true'); + assert.notInclude(cell.value, 'false'); + assert.notInclude(cell.value, 'null'); + }); + + test('removes usermeta field from spec', () => { + const block: DeepnoteBlock = { + blockGroup: 'test-group', + content: '', + id: 'block-123', + sortingKey: 'a0', + type: 'visualization', + metadata: { + deepnote_variable_name: 'df', + deepnote_visualization_spec: { + mark: 'bar', + usermeta: { + shouldBeRemoved: true + } + } + } + }; + + const cell = converter.convertToCell(block); + + assert.notInclude(cell.value, 'usermeta'); + assert.notInclude(cell.value, 'shouldBeRemoved'); + assert.include(cell.value, '"mark": "bar"'); + }); + + test('handles missing variable name with default', () => { + const block: DeepnoteBlock = { + blockGroup: 'test-group', + content: '', + id: 'block-123', + sortingKey: 'a0', + type: 'visualization', + metadata: { + deepnote_visualization_spec: { + layer: [] + } + } + }; + + const cell = converter.convertToCell(block); + + assert.include(cell.value, 'df,'); + }); + + test('handles missing visualization spec with empty object', () => { + const block: DeepnoteBlock = { + blockGroup: 'test-group', + content: '', + id: 'block-123', + sortingKey: 'a0', + type: 'visualization', + metadata: { + deepnote_variable_name: 'my_df' + } + }; + + const cell = converter.convertToCell(block); + + assert.include(cell.value, 'my_df'); + assert.include(cell.value, '{}'); + }); + + test('handles missing metadata', () => { + const block: DeepnoteBlock = { + blockGroup: 'test-group', + content: '', + id: 'block-123', + sortingKey: 'a0', + type: 'visualization' + }; + + const cell = converter.convertToCell(block); + + assert.strictEqual(cell.kind, NotebookCellKind.Code); + assert.include(cell.value, '_dntk.DeepnoteChart('); + assert.include(cell.value, 'df'); + assert.include(cell.value, '{}'); + }); + + test('generates properly formatted Python code', () => { + const block: DeepnoteBlock = { + blockGroup: 'test-group', + content: '', + id: 'block-123', + sortingKey: 'a0', + type: 'visualization', + metadata: { + deepnote_variable_name: 'sales_data', + deepnote_visualization_spec: { + title: 'Sales Chart', + mark: 'line' + } + } + }; + + const cell = converter.convertToCell(block); + + const expectedPattern = /_dntk\.DeepnoteChart\(\s+sales_data,\s+\{/; + + assert.match(cell.value, expectedPattern); + }); + + test('handles complex nested visualization spec', () => { + const block: DeepnoteBlock = { + blockGroup: 'test-group', + content: '', + id: 'block-123', + sortingKey: 'a0', + type: 'visualization', + metadata: { + deepnote_variable_name: 'df', + deepnote_visualization_spec: { + layer: [ + { + layer: [ + { + mark: { type: 'bar', color: '#2266D3' }, + encoding: { + x: { type: 'temporal', field: 'date' }, + y: { type: 'quantitative', aggregate: 'count' } + } + } + ] + } + ], + config: { legend: { disable: false } } + } + } + }; + + const cell = converter.convertToCell(block); + + assert.include(cell.value, '"layer"'); + assert.include(cell.value, '"mark"'); + assert.include(cell.value, '"encoding"'); + assert.include(cell.value, '"config"'); + }); + }); + + suite('applyChangesToBlock', () => { + test('sets content to empty string', () => { + const block: DeepnoteBlock = { + blockGroup: 'test-group', + content: 'old content', + id: 'block-123', + sortingKey: 'a0', + type: 'visualization', + metadata: { + deepnote_variable_name: 'df', + deepnote_visualization_spec: {} + } + }; + const cell = new NotebookCellData(NotebookCellKind.Code, '_dntk.DeepnoteChart(df, {})', 'python'); + + converter.applyChangesToBlock(block, cell); + + assert.strictEqual(block.content, ''); + }); + + test('does not modify metadata', () => { + const block: DeepnoteBlock = { + blockGroup: 'test-group', + content: '', + id: 'block-123', + sortingKey: 'a0', + type: 'visualization', + metadata: { + deepnote_variable_name: 'my_df', + deepnote_visualization_spec: { mark: 'bar' }, + custom_field: 'custom_value' + } + }; + const cell = new NotebookCellData( + NotebookCellKind.Code, + '_dntk.DeepnoteChart(different_df, {"mark": "line"})', + 'python' + ); + + converter.applyChangesToBlock(block, cell); + + assert.strictEqual(block.metadata?.deepnote_variable_name, 'my_df'); + assert.deepStrictEqual(block.metadata?.deepnote_visualization_spec, { mark: 'bar' }); + assert.strictEqual(block.metadata?.custom_field, 'custom_value'); + }); + + test('does not modify other block properties', () => { + const block: DeepnoteBlock = { + blockGroup: 'test-group', + content: '', + executionCount: 10, + id: 'block-123', + metadata: { + deepnote_variable_name: 'df', + deepnote_visualization_spec: {} + }, + outputs: [], + sortingKey: 'a0', + type: 'visualization' + }; + const cell = new NotebookCellData(NotebookCellKind.Code, 'any content', 'python'); + + converter.applyChangesToBlock(block, cell); + + assert.strictEqual(block.content, ''); + assert.strictEqual(block.id, 'block-123'); + assert.strictEqual(block.type, 'visualization'); + assert.strictEqual(block.sortingKey, 'a0'); + assert.strictEqual(block.executionCount, 10); + }); + }); + + suite('round-trip conversion', () => { + test('preserves metadata through conversion cycle', () => { + const originalBlock: DeepnoteBlock = { + blockGroup: 'test-group', + content: '', + id: 'block-123', + sortingKey: 'a0', + type: 'visualization', + metadata: { + deepnote_variable_name: 'sales_df', + deepnote_visualization_spec: { + layer: [{ mark: 'bar' }], + config: { legend: { disable: false } } + }, + execution_start: 1234567890, + execution_millis: 42 + } + }; + + const cell = converter.convertToCell(originalBlock); + + const newBlock: DeepnoteBlock = { + blockGroup: originalBlock.blockGroup, + content: 'temp', + id: originalBlock.id, + sortingKey: originalBlock.sortingKey, + type: originalBlock.type, + metadata: originalBlock.metadata + }; + + converter.applyChangesToBlock(newBlock, cell); + + assert.strictEqual(newBlock.content, ''); + assert.deepStrictEqual(newBlock.metadata, originalBlock.metadata); + }); + }); +}); diff --git a/src/notebooks/deepnote/deepnoteDataConverter.ts b/src/notebooks/deepnote/deepnoteDataConverter.ts index bda5baae3f..c5abe15aa6 100644 --- a/src/notebooks/deepnote/deepnoteDataConverter.ts +++ b/src/notebooks/deepnote/deepnoteDataConverter.ts @@ -3,10 +3,12 @@ import { NotebookCellData, NotebookCellKind, NotebookCellOutput, NotebookCellOut import type { DeepnoteBlock, DeepnoteOutput } from './deepnoteTypes'; import { generateBlockId, generateSortingKey } from './dataConversionUtils'; import { ConverterRegistry } from './converters/converterRegistry'; +import { BlockConverter } from './converters/blockConverter'; import { CodeBlockConverter } from './converters/codeBlockConverter'; import { addPocketToCellMetadata, createBlockFromPocket } from './pocket'; import { TextBlockConverter } from './converters/textBlockConverter'; import { MarkdownBlockConverter } from './converters/markdownBlockConverter'; +import { VisualizationBlockConverter } from './converters/visualizationBlockConverter'; /** * Utility class for converting between Deepnote block structures and VS Code notebook cells. @@ -19,6 +21,16 @@ export class DeepnoteDataConverter { this.registry.register(new CodeBlockConverter()); this.registry.register(new TextBlockConverter()); this.registry.register(new MarkdownBlockConverter()); + this.registry.register(new VisualizationBlockConverter()); + } + + /** + * Finds a converter for the given block type. + * @param blockType The type of block to find a converter for + * @returns The converter if found, undefined otherwise + */ + public findConverter(blockType: string): BlockConverter | undefined { + return this.registry.findConverter(blockType); } /** @@ -65,6 +77,35 @@ export class DeepnoteDataConverter { }); } + convertCellToBlock(cell: NotebookCellData, index: number): DeepnoteBlock { + const block = createBlockFromPocket(cell, index); + + const converter = this.registry.findConverter(block.type); + + if (!converter) { + return this.createFallbackBlock(cell, index); + } + + converter.applyChangesToBlock(block, cell); + + // Convert VS Code outputs to Deepnote format + // Outputs are managed by VS Code natively, not stored in the pocket + // Preserve outputs when they exist (including newly produced outputs) + // Only set if not already set to avoid overwriting converter-managed outputs + // Only set if the cell actually has outputs (non-empty array) or if the block originally had outputs + const hadOutputs = cell.metadata?.__hadOutputs; + if (cell.outputs && !block.outputs && (cell.outputs.length > 0 || hadOutputs)) { + block.outputs = this.transformOutputsForDeepnote(cell.outputs); + } + + // Clean up internal tracking flags from metadata + if (block.metadata && '__hadOutputs' in block.metadata) { + delete block.metadata.__hadOutputs; + } + + return block; + } + /** * Converts VS Code notebook cells back to Deepnote blocks. * Generates missing IDs and sorting keys as needed. @@ -72,34 +113,7 @@ export class DeepnoteDataConverter { * @returns Array of Deepnote blocks */ convertCellsToBlocks(cells: NotebookCellData[]): DeepnoteBlock[] { - return cells.map((cell, index) => { - const block = createBlockFromPocket(cell, index); - - const converter = this.registry.findConverter(block.type); - - if (!converter) { - return this.createFallbackBlock(cell, index); - } - - converter.applyChangesToBlock(block, cell); - - // Convert VS Code outputs to Deepnote format - // Outputs are managed by VS Code natively, not stored in the pocket - // Preserve outputs when they exist (including newly produced outputs) - // Only set if not already set to avoid overwriting converter-managed outputs - // Only set if the cell actually has outputs (non-empty array) or if the block originally had outputs - const hadOutputs = cell.metadata?.__hadOutputs; - if (cell.outputs && !block.outputs && (cell.outputs.length > 0 || hadOutputs)) { - block.outputs = this.transformOutputsForDeepnote(cell.outputs); - } - - // Clean up internal tracking flags from metadata - if (block.metadata && '__hadOutputs' in block.metadata) { - delete block.metadata.__hadOutputs; - } - - return block; - }); + return cells.map((cell, index) => this.convertCellToBlock(cell, index)); } private base64ToUint8Array(base64: string): Uint8Array { @@ -194,6 +208,8 @@ export class DeepnoteDataConverter { data['application/vnd.deepnote.dataframe.v3+json'] = JSON.parse( new TextDecoder().decode(item.data) ); + } else if (item.mime === 'application/vnd.vega.v5+json') { + data['application/vnd.vega.v5+json'] = JSON.parse(new TextDecoder().decode(item.data)); } } @@ -270,6 +286,15 @@ export class DeepnoteDataConverter { ); } + if (data['application/vnd.vega.v5+json']) { + items.push( + NotebookCellOutputItem.json( + data['application/vnd.vega.v5+json'], + 'application/vnd.vega.v5+json' + ) + ); + } + if (data['application/json']) { items.push(NotebookCellOutputItem.json(data['application/json'], 'application/json')); } diff --git a/src/webviews/webview-side/vega-renderer/VegaRenderer.tsx b/src/webviews/webview-side/vega-renderer/VegaRenderer.tsx new file mode 100644 index 0000000000..3c2a822f5a --- /dev/null +++ b/src/webviews/webview-side/vega-renderer/VegaRenderer.tsx @@ -0,0 +1,51 @@ +import { chartColors10, chartColors20, deepnoteBlues } from './colors' +import React, { memo, useLayoutEffect } from 'react' +import { Vega } from 'react-vega' +// @ts-expect-error can't properly pull types due to moduleResolution setting in ts-config +import { vega } from 'vega-embed' + +import { numberFormats } from './number-formats' + + +export interface VegaRendererProps { + spec: Record + renderer?: 'svg' | 'canvas' +} + +export const VegaRenderer = memo(function VegaRenderer(props: VegaRendererProps) { + const { renderer, spec } = props + + + useLayoutEffect(function registerCustomVegaConfigsOnce() { + if (vega.expressionFunction('numberFormatFromNumberType')) { + return + } + + vega.expressionFunction( + 'numberFormatFromNumberType', + (value: number, params: { type: string; decimals: number | null }) => { + // NOTE: default params.type to "default" value to ensure that eg "Sum of" labels are displayed in custom tooltip + return numberFormats[params?.type ?? 'default']?.formatter(value, params?.decimals) + } + ) + + vega.scheme('deepnote10', chartColors10) + vega.scheme('deepnote20', chartColors20) + vega.scheme('deepnote_blues', deepnoteBlues) + }, []) + +// const unfreezedSpec = useMemo(() => clone(addRuntimeDataToVegaSpec(spec, theme)), [spec, theme]) + const unfreezedSpec = spec + + return ( + + ) +}) diff --git a/src/webviews/webview-side/vega-renderer/colors.ts b/src/webviews/webview-side/vega-renderer/colors.ts new file mode 100644 index 0000000000..9f95ff2a1c --- /dev/null +++ b/src/webviews/webview-side/vega-renderer/colors.ts @@ -0,0 +1,38 @@ +export const chartColors10 = [ + '#2266D3', + '#CC8BFF', + '#0E9384', + '#8DCA4C', + '#F9732C', + '#C8338A', + '#EEC026', + '#61646C', + '#4E2B89', + '#6E7BA4' +] as const; + +// this 20-color palette has the same colors as the 10-color one, but with an extra color inserted at every second position +export const chartColors20 = [ + '#2266D3', + '#83AFF6', + '#CC8BFF', + '#8018D3', + '#0E9384', + '#5FD9C3', + '#8DCA4C', + '#BDEB92', + '#F9732C', + '#FEBD89', + '#C8338A', + '#EEB7DD', + '#EEC026', + '#F8E996', + '#61646C', + '#CECFD2', + '#4E2B89', + '#BFC6E1', + '#6E7BA4', + '#B8ABF1' +] as const; + +export const deepnoteBlues = ['#D1E0FF', '#2266D3', '#07419D']; diff --git a/src/webviews/webview-side/vega-renderer/index.ts b/src/webviews/webview-side/vega-renderer/index.ts new file mode 100644 index 0000000000..00ba702acf --- /dev/null +++ b/src/webviews/webview-side/vega-renderer/index.ts @@ -0,0 +1,58 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import type { ActivationFunction, OutputItem, RendererContext } from 'vscode-notebook-renderer'; +import { VegaRenderer } from './VegaRenderer'; + +interface Metadata { + cellId?: string; + cellIndex?: number; + executionCount?: number; + outputType?: string; +} + +/** + * Renderer for Vega/Vega-Lite charts (application/vnd.vega.v5+json). + * Currently renders static text representation of the chart spec. + */ +export const activate: ActivationFunction = (_context: RendererContext) => { + const elementsCache: Record = {}; + return { + renderOutputItem(outputItem: OutputItem, element: HTMLElement) { + console.log(`Vega renderer - rendering output item: ${outputItem.id}`); + try { + const spec = outputItem.json(); + + console.log(`Vega renderer - received spec with ${Object.keys(spec).length} keys`); + + const metadata = outputItem.metadata as Metadata | undefined; + + console.log('[VegaRenderer] Full metadata', metadata); + + const root = document.createElement('div'); + root.style.height = '500px'; + + element.appendChild(root); + elementsCache[outputItem.id] = root; + ReactDOM.render( + React.createElement(VegaRenderer, { + spec: spec + }), + root + ); + } catch (error) { + console.error(`Error rendering Vega chart: ${error}`); + const errorDiv = document.createElement('div'); + errorDiv.style.padding = '10px'; + errorDiv.style.color = 'var(--vscode-errorForeground)'; + errorDiv.textContent = `Error rendering chart: ${error}`; + element.appendChild(errorDiv); + } + }, + + disposeOutputItem(id?: string) { + if (id && elementsCache[id]) { + ReactDOM.unmountComponentAtNode(elementsCache[id]); + } + } + }; +}; diff --git a/src/webviews/webview-side/vega-renderer/number-formats.ts b/src/webviews/webview-side/vega-renderer/number-formats.ts new file mode 100644 index 0000000000..b865050c25 --- /dev/null +++ b/src/webviews/webview-side/vega-renderer/number-formats.ts @@ -0,0 +1,17 @@ +import { format } from 'd3-format'; + +export const numberFormats: Record< + string, + { + label: string; + formatter: (value: number | null, decimals: number | null) => string | null; + } +> = { + default: { label: 'Default', formatter: (value) => value?.toString() ?? null }, + number: { label: 'Number', formatter: (value, decimals) => (value ? format(`.${decimals ?? 2}f`)(value) : null) }, + scientific: { + label: 'Scientific', + formatter: (value, decimals) => (value ? format(`.${decimals ?? 2}e`)(value) : null) + }, + percent: { label: 'Percent', formatter: (value, decimals) => (value ? format(`.${decimals ?? 0}%`)(value) : null) } +}; From 238542046469b66431ccde0a6d402f016800a30a Mon Sep 17 00:00:00 2001 From: OlegWock Date: Thu, 16 Oct 2025 10:23:50 +0200 Subject: [PATCH 2/9] Fix typing issues --- .../converters/visualizationBlockConverter.ts | 45 +++++++++++++++++-- .../vega-renderer/VegaRenderer.tsx | 1 - 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/notebooks/deepnote/converters/visualizationBlockConverter.ts b/src/notebooks/deepnote/converters/visualizationBlockConverter.ts index 62717b74c0..cffb4c8e85 100644 --- a/src/notebooks/deepnote/converters/visualizationBlockConverter.ts +++ b/src/notebooks/deepnote/converters/visualizationBlockConverter.ts @@ -3,6 +3,44 @@ import { NotebookCellData, NotebookCellKind } from 'vscode'; import type { BlockConverter } from './blockConverter'; import type { DeepnoteBlock } from '../deepnoteTypes'; +type DataframeFilter = { + column: string; + operator: + | 'is-equal' + | 'is-not-equal' + | 'is-one-of' + | 'is-not-one-of' + | 'is-not-null' + | 'is-null' + | 'text-contains' + | 'text-does-not-contain' + | 'greater-than' + | 'greater-than-or-equal' + | 'less-than' + | 'less-than-or-equal' + | 'between' + | 'outside-of' + | 'is-relative-today' + | 'is-after' + | 'is-before' + | 'is-on'; + comparativeValues: string[]; +}; + +interface FilterMetadata { + /** @deprecated Use advancedFilters instead */ + filter?: unknown; + advancedFilters?: DataframeFilter[]; +} + +interface VisualizationCellMetadata { + deepnote_variable_name?: string; + deepnote_visualization_spec?: Record; + deepnote_config_collapsed?: boolean; + deepnote_chart_height?: number; + deepnote_chart_filter?: FilterMetadata; +} + /** * Converter for Deepnote visualization blocks (chart blocks). * Displays blocks as editable JSON with variable name, spec, and filters. @@ -45,9 +83,10 @@ export class VisualizationBlockConverter implements BlockConverter { } convertToCell(block: DeepnoteBlock): NotebookCellData { - const variableName = (block.metadata as any)?.deepnote_variable_name || 'df'; - const spec = (block.metadata as any)?.deepnote_visualization_spec || {}; - const filters = (block.metadata as any)?.deepnote_chart_filter?.advancedFilters || []; + const metadata = block.metadata as VisualizationCellMetadata | undefined; + const variableName = metadata?.deepnote_variable_name || 'df'; + const spec = metadata?.deepnote_visualization_spec || {}; + const filters = metadata?.deepnote_chart_filter?.advancedFilters || []; // Create a clean JSON representation that users can edit const config = { diff --git a/src/webviews/webview-side/vega-renderer/VegaRenderer.tsx b/src/webviews/webview-side/vega-renderer/VegaRenderer.tsx index 3c2a822f5a..87e67db963 100644 --- a/src/webviews/webview-side/vega-renderer/VegaRenderer.tsx +++ b/src/webviews/webview-side/vega-renderer/VegaRenderer.tsx @@ -1,7 +1,6 @@ import { chartColors10, chartColors20, deepnoteBlues } from './colors' import React, { memo, useLayoutEffect } from 'react' import { Vega } from 'react-vega' -// @ts-expect-error can't properly pull types due to moduleResolution setting in ts-config import { vega } from 'vega-embed' import { numberFormats } from './number-formats' From 64761dd6de01aac7e51dd8a45c3a121193f7bbc9 Mon Sep 17 00:00:00 2001 From: OlegWock Date: Thu, 16 Oct 2025 10:30:12 +0200 Subject: [PATCH 3/9] Fix formatting --- .../vega-renderer/VegaRenderer.tsx | 86 +++++++++---------- 1 file changed, 42 insertions(+), 44 deletions(-) diff --git a/src/webviews/webview-side/vega-renderer/VegaRenderer.tsx b/src/webviews/webview-side/vega-renderer/VegaRenderer.tsx index 87e67db963..3b686a52a0 100644 --- a/src/webviews/webview-side/vega-renderer/VegaRenderer.tsx +++ b/src/webviews/webview-side/vega-renderer/VegaRenderer.tsx @@ -1,50 +1,48 @@ -import { chartColors10, chartColors20, deepnoteBlues } from './colors' -import React, { memo, useLayoutEffect } from 'react' -import { Vega } from 'react-vega' -import { vega } from 'vega-embed' - -import { numberFormats } from './number-formats' +import { chartColors10, chartColors20, deepnoteBlues } from './colors'; +import React, { memo, useLayoutEffect } from 'react'; +import { Vega } from 'react-vega'; +import { vega } from 'vega-embed'; +import { numberFormats } from './number-formats'; export interface VegaRendererProps { - spec: Record - renderer?: 'svg' | 'canvas' + spec: Record; + renderer?: 'svg' | 'canvas'; } export const VegaRenderer = memo(function VegaRenderer(props: VegaRendererProps) { - const { renderer, spec } = props - - - useLayoutEffect(function registerCustomVegaConfigsOnce() { - if (vega.expressionFunction('numberFormatFromNumberType')) { - return - } - - vega.expressionFunction( - 'numberFormatFromNumberType', - (value: number, params: { type: string; decimals: number | null }) => { - // NOTE: default params.type to "default" value to ensure that eg "Sum of" labels are displayed in custom tooltip - return numberFormats[params?.type ?? 'default']?.formatter(value, params?.decimals) - } - ) - - vega.scheme('deepnote10', chartColors10) - vega.scheme('deepnote20', chartColors20) - vega.scheme('deepnote_blues', deepnoteBlues) - }, []) - -// const unfreezedSpec = useMemo(() => clone(addRuntimeDataToVegaSpec(spec, theme)), [spec, theme]) - const unfreezedSpec = spec - - return ( - - ) -}) + const { renderer, spec } = props; + + useLayoutEffect(function registerCustomVegaConfigsOnce() { + if (vega.expressionFunction('numberFormatFromNumberType')) { + return; + } + + vega.expressionFunction( + 'numberFormatFromNumberType', + (value: number, params: { type: string; decimals: number | null }) => { + // NOTE: default params.type to "default" value to ensure that eg "Sum of" labels are displayed in custom tooltip + return numberFormats[params?.type ?? 'default']?.formatter(value, params?.decimals); + } + ); + + vega.scheme('deepnote10', chartColors10); + vega.scheme('deepnote20', chartColors20); + vega.scheme('deepnote_blues', deepnoteBlues); + }, []); + + // const unfreezedSpec = useMemo(() => clone(addRuntimeDataToVegaSpec(spec, theme)), [spec, theme]) + const unfreezedSpec = spec; + + return ( + + ); +}); From 75ce3a23812c47aa027022f5b6daab2863bcba9f Mon Sep 17 00:00:00 2001 From: OlegWock Date: Thu, 16 Oct 2025 11:02:30 +0200 Subject: [PATCH 4/9] Fix tests --- .../converters/visualizationBlockConverter.ts | 24 +- .../visualizationBlockConverter.unit.test.ts | 419 ++++++++---------- 2 files changed, 200 insertions(+), 243 deletions(-) diff --git a/src/notebooks/deepnote/converters/visualizationBlockConverter.ts b/src/notebooks/deepnote/converters/visualizationBlockConverter.ts index cffb4c8e85..d7c263283b 100644 --- a/src/notebooks/deepnote/converters/visualizationBlockConverter.ts +++ b/src/notebooks/deepnote/converters/visualizationBlockConverter.ts @@ -54,24 +54,14 @@ export class VisualizationBlockConverter implements BlockConverter { try { const config = JSON.parse(cell.value || '{}'); - if (!block.metadata) { - block.metadata = {}; - } - - if (config.variable) { - block.metadata.deepnote_variable_name = config.variable; - } - - if (config.spec) { - block.metadata.deepnote_visualization_spec = config.spec; - } - - if (config.filters) { - if (!block.metadata.deepnote_chart_filter) { - block.metadata.deepnote_chart_filter = {}; + block.metadata = { + ...block.metadata, + deepnote_variable_name: config.variable || '', + deepnote_visualization_spec: config.spec || {}, + deepnote_chart_filter: { + advancedFilters: config.filters || [] } - block.metadata.deepnote_chart_filter.advancedFilters = config.filters; - } + }; } catch (error) { // If JSON parsing fails, leave metadata unchanged console.warn('Failed to parse visualization JSON:', error); diff --git a/src/notebooks/deepnote/converters/visualizationBlockConverter.unit.test.ts b/src/notebooks/deepnote/converters/visualizationBlockConverter.unit.test.ts index be9e5defe1..1212f8c995 100644 --- a/src/notebooks/deepnote/converters/visualizationBlockConverter.unit.test.ts +++ b/src/notebooks/deepnote/converters/visualizationBlockConverter.unit.test.ts @@ -11,46 +11,47 @@ suite('VisualizationBlockConverter', () => { converter = new VisualizationBlockConverter(); }); - suite('canConvert', () => { - test('returns true for visualization type', () => { + suite('canConvert and getSupportedTypes', () => { + test('returns true for visualization (case-insensitive) and false for other types', () => { assert.isTrue(converter.canConvert('visualization')); - }); - - test('canConvert ignores case', () => { assert.isTrue(converter.canConvert('VISUALIZATION')); assert.isTrue(converter.canConvert('Visualization')); - assert.isTrue(converter.canConvert('ViSuAlIzAtIoN')); - }); - - test('returns false for non-visualization types', () => { assert.isFalse(converter.canConvert('code')); assert.isFalse(converter.canConvert('markdown')); - assert.isFalse(converter.canConvert('text-cell-h1')); - assert.isFalse(converter.canConvert('unknown')); - }); - }); - - suite('getSupportedTypes', () => { - test('returns array with visualization type', () => { - const types = converter.getSupportedTypes(); - - assert.deepStrictEqual(types, ['visualization']); + assert.deepStrictEqual(converter.getSupportedTypes(), ['visualization']); }); }); suite('convertToCell', () => { - test('converts visualization block with metadata to Python code', () => { + test('converts block with full metadata to properly formatted JSON cell', () => { const block: DeepnoteBlock = { blockGroup: 'test-group', + id: 'viz1', + type: 'visualization', content: '', - id: 'block-123', sortingKey: 'a0', - type: 'visualization', metadata: { - deepnote_variable_name: 'date_df', + deepnote_variable_name: 'sales_data', deepnote_visualization_spec: { - layer: [{ mark: 'bar' }], - config: { legend: { disable: false } } + mark: 'bar', + encoding: { + x: { field: 'category', type: 'nominal' }, + y: { field: 'value', type: 'quantitative' } + } + }, + deepnote_chart_filter: { + advancedFilters: [ + { + column: 'status', + operator: 'is-equal', + comparativeValues: ['active'] + }, + { + column: 'age', + operator: 'greater-than', + comparativeValues: ['18'] + } + ] } } }; @@ -59,286 +60,252 @@ suite('VisualizationBlockConverter', () => { assert.strictEqual(cell.kind, NotebookCellKind.Code); assert.strictEqual(cell.languageId, 'python'); - assert.include(cell.value, '_dntk.DeepnoteChart('); - assert.include(cell.value, 'date_df'); - assert.include(cell.value, '"layer"'); - assert.include(cell.value, '"mark": "bar"'); - assert.include(cell.value, 'False'); - assert.notInclude(cell.value, 'false'); - }); - - test('converts boolean values to Python format', () => { - const block: DeepnoteBlock = { - blockGroup: 'test-group', - content: '', - id: 'block-123', - sortingKey: 'a0', - type: 'visualization', - metadata: { - deepnote_variable_name: 'df', - deepnote_visualization_spec: { - enabled: true, - disabled: false, - nullValue: null - } + assert.include(cell.value, '\n'); + assert.match(cell.value, /{\n "variable"/); + + const config = JSON.parse(cell.value); + assert.strictEqual(config.variable, 'sales_data'); + assert.deepStrictEqual(config.spec, { + mark: 'bar', + encoding: { + x: { field: 'category', type: 'nominal' }, + y: { field: 'value', type: 'quantitative' } } - }; - - const cell = converter.convertToCell(block); - - assert.include(cell.value, 'True'); - assert.include(cell.value, 'False'); - assert.include(cell.value, 'None'); - assert.notInclude(cell.value, 'true'); - assert.notInclude(cell.value, 'false'); - assert.notInclude(cell.value, 'null'); + }); + assert.strictEqual(config.filters.length, 2); + assert.strictEqual(config.filters[0].column, 'status'); + assert.strictEqual(config.filters[1].operator, 'greater-than'); }); - test('removes usermeta field from spec', () => { - const block: DeepnoteBlock = { + test('uses defaults when metadata is missing or empty', () => { + const blockWithEmptyMetadata: DeepnoteBlock = { blockGroup: 'test-group', - content: '', - id: 'block-123', - sortingKey: 'a0', + id: 'viz2', type: 'visualization', - metadata: { - deepnote_variable_name: 'df', - deepnote_visualization_spec: { - mark: 'bar', - usermeta: { - shouldBeRemoved: true - } - } - } - }; - - const cell = converter.convertToCell(block); - - assert.notInclude(cell.value, 'usermeta'); - assert.notInclude(cell.value, 'shouldBeRemoved'); - assert.include(cell.value, '"mark": "bar"'); - }); - - test('handles missing variable name with default', () => { - const block: DeepnoteBlock = { - blockGroup: 'test-group', content: '', - id: 'block-123', sortingKey: 'a0', - type: 'visualization', - metadata: { - deepnote_visualization_spec: { - layer: [] - } - } + metadata: {} }; - const cell = converter.convertToCell(block); - - assert.include(cell.value, 'df,'); - }); - - test('handles missing visualization spec with empty object', () => { - const block: DeepnoteBlock = { + const blockWithNoMetadata: DeepnoteBlock = { blockGroup: 'test-group', - content: '', - id: 'block-123', - sortingKey: 'a0', + id: 'viz3', type: 'visualization', - metadata: { - deepnote_variable_name: 'my_df' - } - }; - - const cell = converter.convertToCell(block); - - assert.include(cell.value, 'my_df'); - assert.include(cell.value, '{}'); - }); - - test('handles missing metadata', () => { - const block: DeepnoteBlock = { - blockGroup: 'test-group', content: '', - id: 'block-123', - sortingKey: 'a0', - type: 'visualization' + sortingKey: 'a0' }; - const cell = converter.convertToCell(block); - - assert.strictEqual(cell.kind, NotebookCellKind.Code); - assert.include(cell.value, '_dntk.DeepnoteChart('); - assert.include(cell.value, 'df'); - assert.include(cell.value, '{}'); + const cell1 = converter.convertToCell(blockWithEmptyMetadata); + const config1 = JSON.parse(cell1.value); + assert.strictEqual(config1.variable, 'df'); + assert.deepStrictEqual(config1.spec, {}); + assert.deepStrictEqual(config1.filters, []); + + const cell2 = converter.convertToCell(blockWithNoMetadata); + const config2 = JSON.parse(cell2.value); + assert.strictEqual(config2.variable, 'df'); + assert.deepStrictEqual(config2.spec, {}); + assert.deepStrictEqual(config2.filters, []); }); + }); - test('generates properly formatted Python code', () => { + suite('applyChangesToBlock', () => { + test('updates block metadata from valid JSON and clears content', () => { const block: DeepnoteBlock = { blockGroup: 'test-group', - content: '', - id: 'block-123', - sortingKey: 'a0', + id: 'viz1', type: 'visualization', + content: 'old content', + sortingKey: 'a0', metadata: { - deepnote_variable_name: 'sales_data', - deepnote_visualization_spec: { - title: 'Sales Chart', - mark: 'line' - } + other_field: 'should be preserved', + deepnote_chart_height: 500 } }; - const cell = converter.convertToCell(block); + const cell = new NotebookCellData( + NotebookCellKind.Code, + JSON.stringify({ + variable: 'my_data', + spec: { mark: 'point' }, + filters: [ + { column: 'status', operator: 'is-equal', comparativeValues: ['active'] }, + { column: 'date', operator: 'between', comparativeValues: ['2023-01-01', '2023-12-31'] } + ] + }), + 'python' + ); - const expectedPattern = /_dntk\.DeepnoteChart\(\s+sales_data,\s+\{/; + converter.applyChangesToBlock(block, cell); - assert.match(cell.value, expectedPattern); + assert.strictEqual(block.content, ''); + assert.strictEqual(block.metadata?.deepnote_variable_name, 'my_data'); + assert.deepStrictEqual(block.metadata?.deepnote_visualization_spec, { mark: 'point' }); + assert.strictEqual(block.metadata?.deepnote_chart_filter?.advancedFilters?.length, 2); + assert.strictEqual(block.metadata?.deepnote_chart_filter?.advancedFilters?.[0].column, 'status'); + assert.strictEqual(block.metadata?.other_field, 'should be preserved'); + assert.strictEqual(block.metadata?.deepnote_chart_height, 500); }); - test('handles complex nested visualization spec', () => { + test('sets empty values for missing fields in JSON', () => { const block: DeepnoteBlock = { blockGroup: 'test-group', + id: 'viz2', + type: 'visualization', content: '', - id: 'block-123', sortingKey: 'a0', - type: 'visualization', metadata: { - deepnote_variable_name: 'df', - deepnote_visualization_spec: { - layer: [ - { - layer: [ - { - mark: { type: 'bar', color: '#2266D3' }, - encoding: { - x: { type: 'temporal', field: 'date' }, - y: { type: 'quantitative', aggregate: 'count' } - } - } - ] - } - ], - config: { legend: { disable: false } } - } + deepnote_variable_name: 'existing_var', + deepnote_visualization_spec: { mark: 'line' }, + deepnote_chart_filter: { + advancedFilters: [{ column: 'old', operator: 'is-equal', comparativeValues: ['value'] }] + }, + other_field: 'preserved' } }; - const cell = converter.convertToCell(block); + const cellWithOnlyVariable = new NotebookCellData( + NotebookCellKind.Code, + JSON.stringify({ variable: 'updated_var', spec: {}, filters: [] }), + 'python' + ); + converter.applyChangesToBlock(block, cellWithOnlyVariable); + assert.strictEqual(block.metadata?.deepnote_variable_name, 'updated_var'); + assert.deepStrictEqual(block.metadata?.deepnote_visualization_spec, {}); + assert.deepStrictEqual(block.metadata?.deepnote_chart_filter?.advancedFilters, []); + assert.strictEqual(block.metadata?.other_field, 'preserved'); - assert.include(cell.value, '"layer"'); - assert.include(cell.value, '"mark"'); - assert.include(cell.value, '"encoding"'); - assert.include(cell.value, '"config"'); + const cellWithOnlySpec = new NotebookCellData( + NotebookCellKind.Code, + JSON.stringify({ variable: 'var2', spec: { mark: 'bar' }, filters: [] }), + 'python' + ); + converter.applyChangesToBlock(block, cellWithOnlySpec); + assert.strictEqual(block.metadata?.deepnote_variable_name, 'var2'); + assert.deepStrictEqual(block.metadata?.deepnote_visualization_spec, { mark: 'bar' }); + assert.deepStrictEqual(block.metadata?.deepnote_chart_filter?.advancedFilters, []); }); - }); - suite('applyChangesToBlock', () => { - test('sets content to empty string', () => { + test('creates metadata and chart_filter objects when they do not exist', () => { const block: DeepnoteBlock = { blockGroup: 'test-group', - content: 'old content', - id: 'block-123', - sortingKey: 'a0', + id: 'viz3', type: 'visualization', - metadata: { - deepnote_variable_name: 'df', - deepnote_visualization_spec: {} - } - }; - const cell = new NotebookCellData(NotebookCellKind.Code, '_dntk.DeepnoteChart(df, {})', 'python'); - - converter.applyChangesToBlock(block, cell); - - assert.strictEqual(block.content, ''); - }); - - test('does not modify metadata', () => { - const block: DeepnoteBlock = { - blockGroup: 'test-group', content: '', - id: 'block-123', - sortingKey: 'a0', - type: 'visualization', - metadata: { - deepnote_variable_name: 'my_df', - deepnote_visualization_spec: { mark: 'bar' }, - custom_field: 'custom_value' - } + sortingKey: 'a0' }; + const cell = new NotebookCellData( NotebookCellKind.Code, - '_dntk.DeepnoteChart(different_df, {"mark": "line"})', + JSON.stringify({ + variable: 'new_var', + spec: { mark: 'area' }, + filters: [{ column: 'category', operator: 'is-not-null', comparativeValues: [] }] + }), 'python' ); converter.applyChangesToBlock(block, cell); - assert.strictEqual(block.metadata?.deepnote_variable_name, 'my_df'); - assert.deepStrictEqual(block.metadata?.deepnote_visualization_spec, { mark: 'bar' }); - assert.strictEqual(block.metadata?.custom_field, 'custom_value'); + assert.isDefined(block.metadata); + assert.strictEqual(block.metadata?.deepnote_variable_name, 'new_var'); + assert.deepStrictEqual(block.metadata?.deepnote_visualization_spec, { mark: 'area' }); + assert.isDefined(block.metadata?.deepnote_chart_filter); + assert.strictEqual(block.metadata?.deepnote_chart_filter?.advancedFilters?.length, 1); }); - test('does not modify other block properties', () => { + test('handles invalid, empty, and undefined JSON gracefully', () => { const block: DeepnoteBlock = { blockGroup: 'test-group', + id: 'viz4', + type: 'visualization', content: '', - executionCount: 10, - id: 'block-123', - metadata: { - deepnote_variable_name: 'df', - deepnote_visualization_spec: {} - }, - outputs: [], sortingKey: 'a0', - type: 'visualization' + metadata: { + deepnote_variable_name: 'original', + deepnote_visualization_spec: { mark: 'original' }, + other_field: 'preserved' + } }; - const cell = new NotebookCellData(NotebookCellKind.Code, 'any content', 'python'); - converter.applyChangesToBlock(block, cell); - - assert.strictEqual(block.content, ''); - assert.strictEqual(block.id, 'block-123'); - assert.strictEqual(block.type, 'visualization'); - assert.strictEqual(block.sortingKey, 'a0'); - assert.strictEqual(block.executionCount, 10); + const invalidCell = new NotebookCellData(NotebookCellKind.Code, 'not valid json {', 'python'); + assert.doesNotThrow(() => converter.applyChangesToBlock(block, invalidCell)); + assert.strictEqual(block.metadata?.deepnote_variable_name, 'original'); + assert.deepStrictEqual(block.metadata?.deepnote_visualization_spec, { mark: 'original' }); + assert.strictEqual(block.metadata?.other_field, 'preserved'); + + const emptyCell = new NotebookCellData(NotebookCellKind.Code, '', 'python'); + converter.applyChangesToBlock(block, emptyCell); + assert.strictEqual(block.metadata?.deepnote_variable_name, ''); + assert.deepStrictEqual(block.metadata?.deepnote_visualization_spec, {}); + assert.deepStrictEqual(block.metadata?.deepnote_chart_filter?.advancedFilters, []); + assert.strictEqual(block.metadata?.other_field, 'preserved'); + + const undefinedCell = new NotebookCellData(NotebookCellKind.Code, '', 'python'); + undefinedCell.value = undefined as unknown as string; + converter.applyChangesToBlock(block, undefinedCell); + assert.strictEqual(block.metadata?.deepnote_variable_name, ''); + assert.deepStrictEqual(block.metadata?.deepnote_visualization_spec, {}); + assert.deepStrictEqual(block.metadata?.deepnote_chart_filter?.advancedFilters, []); + assert.strictEqual(block.metadata?.other_field, 'preserved'); }); }); - suite('round-trip conversion', () => { - test('preserves metadata through conversion cycle', () => { + suite('round trip conversion', () => { + test('block -> cell -> block preserves data', () => { const originalBlock: DeepnoteBlock = { blockGroup: 'test-group', + id: 'viz1', + type: 'visualization', content: '', - id: 'block-123', sortingKey: 'a0', - type: 'visualization', metadata: { - deepnote_variable_name: 'sales_df', + deepnote_variable_name: 'sales_data', deepnote_visualization_spec: { - layer: [{ mark: 'bar' }], - config: { legend: { disable: false } } + mark: 'bar', + encoding: { + x: { field: 'category', type: 'nominal' }, + y: { field: 'value', type: 'quantitative' } + } }, - execution_start: 1234567890, - execution_millis: 42 + deepnote_chart_filter: { + advancedFilters: [ + { + column: 'status', + operator: 'is-equal', + comparativeValues: ['active'] + } + ] + }, + deepnote_chart_height: 400 } }; const cell = converter.convertToCell(originalBlock); - const newBlock: DeepnoteBlock = { + const roundTripBlock: DeepnoteBlock = { blockGroup: originalBlock.blockGroup, - content: 'temp', id: originalBlock.id, - sortingKey: originalBlock.sortingKey, type: originalBlock.type, - metadata: originalBlock.metadata + content: originalBlock.content, + sortingKey: originalBlock.sortingKey, + metadata: { ...originalBlock.metadata } }; - converter.applyChangesToBlock(newBlock, cell); + converter.applyChangesToBlock(roundTripBlock, cell); - assert.strictEqual(newBlock.content, ''); - assert.deepStrictEqual(newBlock.metadata, originalBlock.metadata); + assert.strictEqual( + roundTripBlock.metadata?.deepnote_variable_name, + originalBlock.metadata?.deepnote_variable_name + ); + assert.deepStrictEqual( + roundTripBlock.metadata?.deepnote_visualization_spec, + originalBlock.metadata?.deepnote_visualization_spec + ); + assert.deepStrictEqual( + roundTripBlock.metadata?.deepnote_chart_filter?.advancedFilters, + originalBlock.metadata?.deepnote_chart_filter?.advancedFilters + ); }); }); }); From c695b8dcaed376cbbb65fc1d5ef11e13e80eb5da Mon Sep 17 00:00:00 2001 From: OlegWock Date: Thu, 16 Oct 2025 11:27:43 +0200 Subject: [PATCH 5/9] Update according to rabbit comments --- src/webviews/webview-side/vega-renderer/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/webviews/webview-side/vega-renderer/index.ts b/src/webviews/webview-side/vega-renderer/index.ts index 00ba702acf..7212aef95c 100644 --- a/src/webviews/webview-side/vega-renderer/index.ts +++ b/src/webviews/webview-side/vega-renderer/index.ts @@ -11,11 +11,10 @@ interface Metadata { } /** - * Renderer for Vega/Vega-Lite charts (application/vnd.vega.v5+json). - * Currently renders static text representation of the chart spec. + * Renderer for Vega charts (application/vnd.vega.v5+json). */ export const activate: ActivationFunction = (_context: RendererContext) => { - const elementsCache: Record = {}; + const elementsCache: Record = {}; return { renderOutputItem(outputItem: OutputItem, element: HTMLElement) { console.log(`Vega renderer - rendering output item: ${outputItem.id}`); @@ -52,6 +51,7 @@ export const activate: ActivationFunction = (_context: RendererContext) disposeOutputItem(id?: string) { if (id && elementsCache[id]) { ReactDOM.unmountComponentAtNode(elementsCache[id]); + elementsCache[id] = undefined; } } }; From be08703b92c93040cc03c3e529036010eb1d2517 Mon Sep 17 00:00:00 2001 From: OlegWock Date: Thu, 16 Oct 2025 11:32:48 +0200 Subject: [PATCH 6/9] Cleanup --- .../deepnote/converters/visualizationBlockConverter.ts | 2 -- src/webviews/webview-side/vega-renderer/VegaRenderer.tsx | 5 +---- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/notebooks/deepnote/converters/visualizationBlockConverter.ts b/src/notebooks/deepnote/converters/visualizationBlockConverter.ts index d7c263283b..e8ef97c1fa 100644 --- a/src/notebooks/deepnote/converters/visualizationBlockConverter.ts +++ b/src/notebooks/deepnote/converters/visualizationBlockConverter.ts @@ -36,8 +36,6 @@ interface FilterMetadata { interface VisualizationCellMetadata { deepnote_variable_name?: string; deepnote_visualization_spec?: Record; - deepnote_config_collapsed?: boolean; - deepnote_chart_height?: number; deepnote_chart_filter?: FilterMetadata; } diff --git a/src/webviews/webview-side/vega-renderer/VegaRenderer.tsx b/src/webviews/webview-side/vega-renderer/VegaRenderer.tsx index 3b686a52a0..8077285108 100644 --- a/src/webviews/webview-side/vega-renderer/VegaRenderer.tsx +++ b/src/webviews/webview-side/vega-renderer/VegaRenderer.tsx @@ -31,12 +31,9 @@ export const VegaRenderer = memo(function VegaRenderer(props: VegaRendererProps) vega.scheme('deepnote_blues', deepnoteBlues); }, []); - // const unfreezedSpec = useMemo(() => clone(addRuntimeDataToVegaSpec(spec, theme)), [spec, theme]) - const unfreezedSpec = spec; - return ( Date: Fri, 17 Oct 2025 09:51:01 +0200 Subject: [PATCH 7/9] Set cell language to JSON --- .../deepnote/converters/visualizationBlockConverter.ts | 2 +- src/platform/common/constants.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/notebooks/deepnote/converters/visualizationBlockConverter.ts b/src/notebooks/deepnote/converters/visualizationBlockConverter.ts index e8ef97c1fa..e3c7baac82 100644 --- a/src/notebooks/deepnote/converters/visualizationBlockConverter.ts +++ b/src/notebooks/deepnote/converters/visualizationBlockConverter.ts @@ -84,7 +84,7 @@ export class VisualizationBlockConverter implements BlockConverter { }; const jsonContent = JSON.stringify(config, null, 2); - const cell = new NotebookCellData(NotebookCellKind.Code, jsonContent, 'python'); + const cell = new NotebookCellData(NotebookCellKind.Code, jsonContent, 'JSON'); return cell; } diff --git a/src/platform/common/constants.ts b/src/platform/common/constants.ts index 711265499b..ede9b4fd06 100644 --- a/src/platform/common/constants.ts +++ b/src/platform/common/constants.ts @@ -125,6 +125,7 @@ export const LanguagesSupportedByPythonkernel = [ 'sql', // %%sql 'perl', // %%perl 'qsharp', // %%qsharp + 'JSON', //JSON cells for custom block types 'raw' // raw cells (no formatting) ]; export const jupyterLanguageToMonacoLanguageMapping = new Map([ From f15fed6c453d0b5dfe7b480fbd3f150a870f4b2c Mon Sep 17 00:00:00 2001 From: OlegWock Date: Fri, 17 Oct 2025 10:36:05 +0200 Subject: [PATCH 8/9] Enable render of legacy vega-lite outputs --- package-lock.json | 16 +++++++++++++ package.json | 1 + .../deepnote/deepnoteDataConverter.ts | 24 +++++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/package-lock.json b/package-lock.json index 6c776abe5f..1060aa06e7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,6 +35,7 @@ "fs-extra": "^4.0.3", "glob": "^7.1.2", "iconv-lite": "^0.6.3", + "immer": "^10.1.3", "inversify": "^6.0.1", "isomorphic-ws": "^4.0.1", "jquery": "^3.6.0", @@ -10477,6 +10478,16 @@ "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", "dev": true }, + "node_modules/immer": { + "version": "10.1.3", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.3.tgz", + "integrity": "sha512-tmjF/k8QDKydUlm3mZU+tjM6zeq9/fFpPqH9SzWmBnVVKsPBg/V66qsMwb3/Bo90cgUN+ghdVBess+hPsxUyRw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/immutable": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz", @@ -26548,6 +26559,11 @@ "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", "dev": true }, + "immer": { + "version": "10.1.3", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.3.tgz", + "integrity": "sha512-tmjF/k8QDKydUlm3mZU+tjM6zeq9/fFpPqH9SzWmBnVVKsPBg/V66qsMwb3/Bo90cgUN+ghdVBess+hPsxUyRw==" + }, "immutable": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz", diff --git a/package.json b/package.json index ad5909af76..c4b433aa77 100644 --- a/package.json +++ b/package.json @@ -2143,6 +2143,7 @@ "fs-extra": "^4.0.3", "glob": "^7.1.2", "iconv-lite": "^0.6.3", + "immer": "^10.1.3", "inversify": "^6.0.1", "isomorphic-ws": "^4.0.1", "jquery": "^3.6.0", diff --git a/src/notebooks/deepnote/deepnoteDataConverter.ts b/src/notebooks/deepnote/deepnoteDataConverter.ts index c5abe15aa6..f8c3236d63 100644 --- a/src/notebooks/deepnote/deepnoteDataConverter.ts +++ b/src/notebooks/deepnote/deepnoteDataConverter.ts @@ -9,6 +9,10 @@ import { addPocketToCellMetadata, createBlockFromPocket } from './pocket'; import { TextBlockConverter } from './converters/textBlockConverter'; import { MarkdownBlockConverter } from './converters/markdownBlockConverter'; import { VisualizationBlockConverter } from './converters/visualizationBlockConverter'; +import { compile as convertVegaLiteSpecToVega } from 'vega-lite'; +import { produce } from 'immer'; +import type { Field } from 'vega-lite/build/src/channeldef'; +import type { LayerSpec, TopLevel } from 'vega-lite/build/src/spec'; /** * Utility class for converting between Deepnote block structures and VS Code notebook cells. @@ -295,6 +299,26 @@ export class DeepnoteDataConverter { ); } + if (data['application/vnd.vegalite.v5+json']) { + const patchedVegaLiteSpec = produce( + data['application/vnd.vegalite.v5+json'] as TopLevel>, + (draft) => { + draft.height = 'container'; + draft.width = 'container'; + + draft.autosize = { + type: 'fit' + }; + if (!draft.config) { + draft.config = {}; + } + draft.config.customFormatTypes = true; + } + ); + const vegaSpec = convertVegaLiteSpecToVega(patchedVegaLiteSpec).spec; + items.push(NotebookCellOutputItem.json(vegaSpec, 'application/vnd.vega.v5+json')); + } + if (data['application/json']) { items.push(NotebookCellOutputItem.json(data['application/json'], 'application/json')); } From edc90da2f6f8febc1988a526364db6416061a171 Mon Sep 17 00:00:00 2001 From: OlegWock Date: Fri, 17 Oct 2025 10:43:10 +0200 Subject: [PATCH 9/9] Fix test --- .../converters/visualizationBlockConverter.unit.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/notebooks/deepnote/converters/visualizationBlockConverter.unit.test.ts b/src/notebooks/deepnote/converters/visualizationBlockConverter.unit.test.ts index 1212f8c995..db0936e11b 100644 --- a/src/notebooks/deepnote/converters/visualizationBlockConverter.unit.test.ts +++ b/src/notebooks/deepnote/converters/visualizationBlockConverter.unit.test.ts @@ -59,7 +59,7 @@ suite('VisualizationBlockConverter', () => { const cell = converter.convertToCell(block); assert.strictEqual(cell.kind, NotebookCellKind.Code); - assert.strictEqual(cell.languageId, 'python'); + assert.strictEqual(cell.languageId, 'JSON'); assert.include(cell.value, '\n'); assert.match(cell.value, /{\n "variable"/);