From 983f7fce85b42dd235ca8131da91a38675cb14db Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Mon, 20 Jan 2025 10:41:18 -0500 Subject: [PATCH 01/45] Setup LayerChart --- frontend/package-lock.json | 338 ++++++++++++++++++++++++++++++++++-- frontend/package.json | 3 + frontend/tailwind.config.js | 10 +- 3 files changed, 333 insertions(+), 18 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index b2cce21e49..210e2700ca 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -14,8 +14,11 @@ "@types/echarts": "^4.9.22", "clsx": "^2.1.1", "d3": "^7.9.0", + "d3-array": "^3.2.4", + "d3-scale": "^4.0.2", "dotenv": "^16.4.7", "echarts": "^5.6.0", + "layerchart": "^0.74.0", "lodash": "^4.17.21", "tailwind-merge": "^2.6.0", "tailwind-variants": "^0.3.0" @@ -74,7 +77,6 @@ }, "node_modules/@ampproject/remapping": { "version": "2.3.0", - "dev": true, "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -144,6 +146,24 @@ "node": ">=4.2.0" } }, + "node_modules/@dagrejs/dagre": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@dagrejs/dagre/-/dagre-1.1.4.tgz", + "integrity": "sha512-QUTc54Cg/wvmlEUxB+uvoPVKFazM1H18kVHBQNmK2NbrDR5ihOCR6CXLnDSZzMcSQKJtabPUWridBOlJM3WkDg==", + "license": "MIT", + "dependencies": { + "@dagrejs/graphlib": "2.2.4" + } + }, + "node_modules/@dagrejs/graphlib": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@dagrejs/graphlib/-/graphlib-2.2.4.tgz", + "integrity": "sha512-mepCf/e9+SKYy1d02/UkvSy6+6MoyXhVxP8lLDfA7BPE1X1d4dR0sZznmbM8/XVJ1GPM+Svnx7Xj6ZweByWUkw==", + "license": "MIT", + "engines": { + "node": ">17.0.0" + } + }, "node_modules/@esbuild/darwin-arm64": { "version": "0.24.0", "cpu": [ @@ -281,7 +301,6 @@ }, "node_modules/@floating-ui/core": { "version": "1.6.8", - "dev": true, "license": "MIT", "dependencies": { "@floating-ui/utils": "^0.2.8" @@ -289,7 +308,6 @@ }, "node_modules/@floating-ui/dom": { "version": "1.6.12", - "dev": true, "license": "MIT", "dependencies": { "@floating-ui/core": "^1.6.0", @@ -298,7 +316,6 @@ }, "node_modules/@floating-ui/utils": { "version": "0.2.8", - "dev": true, "license": "MIT" }, "node_modules/@humanfs/core": { @@ -453,6 +470,50 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@layerstack/svelte-actions": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/@layerstack/svelte-actions/-/svelte-actions-0.0.11.tgz", + "integrity": "sha512-sfplFX8rOBW74xjDCAY7QzHilvUGjFQTkfQXxUO6e68cKCHmxsSuTCtFbHRCfIUJCQ31gAbeY1xpWKnlVfgZ9g==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.6.12", + "@layerstack/utils": "0.0.7", + "d3-array": "^3.2.4", + "d3-scale": "^4.0.2", + "date-fns": "^4.1.0", + "lodash-es": "^4.17.21" + } + }, + "node_modules/@layerstack/svelte-stores": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/@layerstack/svelte-stores/-/svelte-stores-0.0.9.tgz", + "integrity": "sha512-5yyi7eV/2hOraw7wQgEObVR4s2/4T3G/GjGaZLR9BQH8mnsLuXw1n3k6rFT8NxiRvpEjWJ9l9ILOGc/XzFJb3g==", + "license": "MIT", + "dependencies": { + "@layerstack/utils": "0.0.7", + "d3-array": "^3.2.4", + "date-fns": "^4.1.0", + "immer": "^10.1.1", + "lodash-es": "^4.17.21", + "zod": "^3.23.8" + } + }, + "node_modules/@layerstack/tailwind": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/@layerstack/tailwind/-/tailwind-0.0.11.tgz", + "integrity": "sha512-dHvJM5xpVisPrM6NClSCNPqB/u+pSwemWzkKeb911/8pLUuyr+7HceTpv5AZMyE/I5A2RxoTa5mTZokmvEqPnQ==", + "license": "MIT", + "dependencies": { + "@layerstack/utils": "^0.0.7", + "clsx": "^2.1.1", + "culori": "^4.0.1", + "d3-array": "^3.2.4", + "date-fns": "^4.1.0", + "lodash-es": "^4.17.21", + "tailwind-merge": "^2.5.4", + "tailwindcss": "^3.4.15" + } + }, "node_modules/@layerstack/utils": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/@layerstack/utils/-/utils-0.0.7.tgz", @@ -1230,7 +1291,6 @@ }, "node_modules/@types/estree": { "version": "1.0.6", - "dev": true, "license": "MIT" }, "node_modules/@types/fs-extra": { @@ -1565,7 +1625,6 @@ }, "node_modules/acorn": { "version": "8.14.0", - "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -1584,7 +1643,6 @@ }, "node_modules/acorn-typescript": { "version": "1.4.13", - "dev": true, "license": "MIT", "peerDependencies": { "acorn": ">=8.9.0" @@ -1655,12 +1713,17 @@ }, "node_modules/aria-query": { "version": "5.3.2", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">= 0.4" } }, + "node_modules/array-source": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/array-source/-/array-source-0.0.4.tgz", + "integrity": "sha512-frNdc+zBn80vipY+GdcJkLEbMWj3xmzArYApmUGxoiV8uAu/ygcs9icPdsGdA26h0MkHUMW6EN2piIvVx+M5Mw==", + "license": "BSD-3-Clause" + }, "node_modules/assertion-error": { "version": "2.0.1", "dev": true, @@ -1707,7 +1770,6 @@ }, "node_modules/axobject-query": { "version": "4.1.0", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">= 0.4" @@ -1990,6 +2052,15 @@ "node": ">=4" } }, + "node_modules/culori": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/culori/-/culori-4.0.1.tgz", + "integrity": "sha512-LSnjA6HuIUOlkfKVbzi2OlToZE8OjFi667JWN9qNymXVXzGDmvuP60SSgC+e92sd7B7158f7Fy3Mb6rXS5EDPw==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, "node_modules/d3": { "version": "7.9.0", "license": "ISC", @@ -2031,6 +2102,8 @@ }, "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", "dependencies": { "internmap": "1 - 2" @@ -2184,6 +2257,21 @@ "node": ">=12" } }, + "node_modules/d3-geo-voronoi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/d3-geo-voronoi/-/d3-geo-voronoi-2.1.0.tgz", + "integrity": "sha512-kqE4yYuOjPbKdBXG0xztCacPwkVSK2REF1opSNrnqqtXJmNcM++UbwQ8SxvwP6IQTj9RvIjjK4qeiVsEfj0Z2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "3", + "d3-delaunay": "6", + "d3-geo": "3", + "d3-tricontour": "1" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/d3-hierarchy": { "version": "3.1.2", "license": "ISC", @@ -2201,6 +2289,12 @@ "node": ">=12" } }, + "node_modules/d3-interpolate-path": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/d3-interpolate-path/-/d3-interpolate-path-2.3.0.tgz", + "integrity": "sha512-tZYtGXxBmbgHsIc9Wms6LS5u4w6KbP8C09a4/ZYc4KLMYYqub57rRBUgpUr2CIarIrJEpdAWWxWQvofgaMpbKQ==", + "license": "BSD-3-Clause" + }, "node_modules/d3-path": { "version": "3.1.0", "license": "ISC", @@ -2229,8 +2323,50 @@ "node": ">=12" } }, + "node_modules/d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "license": "BSD-3-Clause", + "dependencies": { + "internmap": "^1.0.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-sankey/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-sankey/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", + "license": "ISC" + }, "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", "dependencies": { "d3-array": "2.10.0 - 3", @@ -2271,6 +2407,12 @@ "node": ">=12" } }, + "node_modules/d3-tile": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/d3-tile/-/d3-tile-1.0.0.tgz", + "integrity": "sha512-79fnTKpPMPDS5xQ0xuS9ir0165NEwwkFpe/DSOmc2Gl9ldYzKKRDWogmTTE8wAJ8NA7PMapNfEcyKhI9Lxdu5Q==", + "license": "BSD-3-Clause" + }, "node_modules/d3-time": { "version": "3.1.0", "license": "ISC", @@ -2315,6 +2457,19 @@ "d3-selection": "2 - 3" } }, + "node_modules/d3-tricontour": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d3-tricontour/-/d3-tricontour-1.0.2.tgz", + "integrity": "sha512-HIRxHzHagPtUPNabjOlfcyismJYIsc+Xlq4mlsts4e8eAcwyq9Tgk/sYdyhlBpQ0MHwVquc/8j+e29YjXnmxeA==", + "license": "ISC", + "dependencies": { + "d3-delaunay": "6", + "d3-scale": "4" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/d3-zoom": { "version": "3.0.0", "license": "ISC", @@ -2651,7 +2806,6 @@ }, "node_modules/esm-env": { "version": "1.2.1", - "dev": true, "license": "MIT" }, "node_modules/espree": { @@ -2683,7 +2837,6 @@ }, "node_modules/esrap": { "version": "1.3.2", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" @@ -2799,6 +2952,15 @@ "node": ">=16.0.0" } }, + "node_modules/file-source": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/file-source/-/file-source-0.6.1.tgz", + "integrity": "sha512-1R1KneL7eTXmXfKxC10V/9NeGOdbsAXJ+lQ//fvvcHUgtaZcZDWNJNblxAoVOyV1cj45pOtUrR3vZTBwqcW8XA==", + "license": "BSD-3-Clause", + "dependencies": { + "stream-source": "0.3" + } + }, "node_modules/fill-range": { "version": "7.1.1", "license": "MIT", @@ -3007,6 +3169,16 @@ "node": ">= 4" } }, + "node_modules/immer": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz", + "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/import-fresh": { "version": "3.3.0", "dev": true, @@ -3177,6 +3349,62 @@ "dev": true, "license": "MIT" }, + "node_modules/layercake": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/layercake/-/layercake-8.4.2.tgz", + "integrity": "sha512-ZVjdl6ryjz7F4jXX8Dh871nN/Nv6o3m7gLI7KrMPNGiy3Mg5BuA9j0UeucrmK/uLe20XpDyG6X4v/iYJYSPLrg==", + "license": "MIT", + "dependencies": { + "d3-array": "^3.2.4", + "d3-color": "^3.1.0", + "d3-scale": "^4.0.2", + "d3-shape": "^3.2.0" + }, + "peerDependencies": { + "svelte": "3 - 5 || >=5.0.0-next.120", + "typescript": "^5.0.2" + } + }, + "node_modules/layerchart": { + "version": "0.74.0", + "resolved": "https://registry.npmjs.org/layerchart/-/layerchart-0.74.0.tgz", + "integrity": "sha512-HCjDi0oVp8sXr8GohOY7EgGNz9wQ583pFwn/0k9erjLdkAXoG/SdlaIDGdP9/Qhm9stBwgZMy3IAag9w4v12XA==", + "license": "MIT", + "dependencies": { + "@dagrejs/dagre": "^1.1.4", + "@layerstack/svelte-actions": "^0.0.11", + "@layerstack/svelte-stores": "^0.0.9", + "@layerstack/tailwind": "^0.0.11", + "@layerstack/utils": "^0.0.7", + "d3-array": "^3.2.4", + "d3-color": "^3.1.0", + "d3-delaunay": "^6.0.4", + "d3-dsv": "^3.0.1", + "d3-force": "^3.0.0", + "d3-geo": "^3.1.1", + "d3-geo-voronoi": "^2.1.0", + "d3-hierarchy": "^3.1.2", + "d3-interpolate": "^3.0.1", + "d3-interpolate-path": "^2.3.0", + "d3-path": "^3.1.0", + "d3-quadtree": "^3.0.1", + "d3-random": "^3.0.1", + "d3-sankey": "^0.12.3", + "d3-scale": "^4.0.2", + "d3-scale-chromatic": "^3.1.0", + "d3-shape": "^3.2.0", + "d3-tile": "^1.0.0", + "d3-time": "^3.1.0", + "date-fns": "^4.1.0", + "layercake": "^8.4.2", + "lodash-es": "^4.17.21", + "shapefile": "^0.6.6", + "topojson-client": "^3.1.0" + }, + "peerDependencies": { + "svelte": "^3.56.0 || ^4.0.0 || ^5.0.0" + } + }, "node_modules/levn": { "version": "0.4.1", "dev": true, @@ -3218,7 +3446,6 @@ }, "node_modules/locate-character": { "version": "3.0.0", - "dev": true, "license": "MIT" }, "node_modules/locate-path": { @@ -3271,7 +3498,6 @@ }, "node_modules/magic-string": { "version": "0.30.17", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" @@ -3520,6 +3746,16 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/path-source": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/path-source/-/path-source-0.1.3.tgz", + "integrity": "sha512-dWRHm5mIw5kw0cs3QZLNmpUWty48f5+5v9nWD2dw3Y0Hf+s01Ag8iJEWV0Sm0kocE8kK27DrIowha03e1YR+Qw==", + "license": "BSD-3-Clause", + "dependencies": { + "array-source": "0.0", + "file-source": "0.6" + } + }, "node_modules/pathe": { "version": "1.1.2", "dev": true, @@ -4005,6 +4241,30 @@ "dev": true, "license": "MIT" }, + "node_modules/shapefile": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/shapefile/-/shapefile-0.6.6.tgz", + "integrity": "sha512-rLGSWeK2ufzCVx05wYd+xrWnOOdSV7xNUW5/XFgx3Bc02hBkpMlrd2F1dDII7/jhWzv0MSyBFh5uJIy9hLdfuw==", + "license": "BSD-3-Clause", + "dependencies": { + "array-source": "0.0", + "commander": "2", + "path-source": "0.1", + "slice-source": "0.4", + "stream-source": "0.3", + "text-encoding": "^0.6.4" + }, + "bin": { + "dbf2json": "bin/dbf2json", + "shp2json": "bin/shp2json" + } + }, + "node_modules/shapefile/node_modules/commander": { + "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==", + "license": "MIT" + }, "node_modules/shebang-command": { "version": "2.0.0", "dev": true, @@ -4042,6 +4302,12 @@ "node": ">=18" } }, + "node_modules/slice-source": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/slice-source/-/slice-source-0.4.1.tgz", + "integrity": "sha512-YiuPbxpCj4hD9Qs06hGAz/OZhQ0eDuALN0lRWJez0eD/RevzKqGdUx1IOMUnXgpr+sXZLq3g8ERwbAH0bCb8vg==", + "license": "BSD-3-Clause" + }, "node_modules/source-map-js": { "version": "1.2.1", "license": "BSD-3-Clause", @@ -4059,6 +4325,12 @@ "dev": true, "license": "MIT" }, + "node_modules/stream-source": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/stream-source/-/stream-source-0.3.5.tgz", + "integrity": "sha512-ZuEDP9sgjiAwUVoDModftG0JtYiLUV8K4ljYD1VyUMRWtbVf92474o4kuuul43iZ8t/hRuiDAx1dIJSvirrK/g==", + "license": "BSD-3-Clause" + }, "node_modules/strip-json-comments": { "version": "3.1.1", "dev": true, @@ -4120,7 +4392,6 @@ }, "node_modules/svelte": { "version": "5.15.0", - "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.3.0", @@ -4294,7 +4565,6 @@ }, "node_modules/svelte/node_modules/is-reference": { "version": "3.0.3", - "dev": true, "license": "MIT", "dependencies": { "@types/estree": "^1.0.6" @@ -4481,6 +4751,13 @@ "node": ">=8.10.0" } }, + "node_modules/text-encoding": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", + "integrity": "sha512-hJnc6Qg3dWoOMkqP53F0dzRIgtmsAge09kxUIqGrEUS4qr5rWLckGYaQAVr+opBrIMRErGgy6f5aPnyPpyGRfg==", + "deprecated": "no longer maintained", + "license": "Unlicense" + }, "node_modules/thenify": { "version": "3.3.1", "license": "MIT", @@ -4551,6 +4828,26 @@ "node": ">=8.0" } }, + "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", + "dependencies": { + "commander": "2" + }, + "bin": { + "topo2geo": "bin/topo2geo", + "topomerge": "bin/topomerge", + "topoquantize": "bin/topoquantize" + } + }, + "node_modules/topojson-client/node_modules/commander": { + "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==", + "license": "MIT" + }, "node_modules/totalist": { "version": "3.0.1", "dev": true, @@ -4592,7 +4889,6 @@ }, "node_modules/typescript": { "version": "5.7.2", - "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -4986,9 +5282,17 @@ }, "node_modules/zimmerframe": { "version": "1.1.2", - "dev": true, "license": "MIT" }, + "node_modules/zod": { + "version": "3.24.1", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz", + "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "node_modules/zrender": { "version": "5.6.1", "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.6.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index f8f874c82e..2a9ac87758 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -66,8 +66,11 @@ "@types/echarts": "^4.9.22", "clsx": "^2.1.1", "d3": "^7.9.0", + "d3-array": "^3.2.4", + "d3-scale": "^4.0.2", "dotenv": "^16.4.7", "echarts": "^5.6.0", + "layerchart": "^0.74.0", "lodash": "^4.17.21", "tailwind-merge": "^2.6.0", "tailwind-variants": "^0.3.0" diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index eab2254344..ff981be27d 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -5,7 +5,7 @@ import { createColorScale } from './src/lib/util/colors'; const config = { plugins: [typography], darkMode: ['class'], - content: ['./src/**/*.{html,js,svelte,ts}'], + content: ['./src/**/*.{html,js,svelte,ts}', './node_modules/layerchart/**/*.{svelte,js}'], safelist: [ 'dark', { @@ -93,6 +93,14 @@ const config = { border: 'hsl(var(--job-invalid-border) / )', 'active-border': 'hsl(var(--job-invalid-active-border) / )' } + }, + // Additional LayerChart colors + surface: { + content: 'hsl(var(--card-foreground) / )', + 100: 'hsl(var(--background) / )', + 200: 'hsl(var(--muted) / )', + // not sure what color maps here (should be darker than 200). Could add a new color to `app.css` + 300: 'hsl(var(--background) / )' } }, borderRadius: { From e71f7f65d9a2e938384b17181bec9f90a548dd2f Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Mon, 20 Jan 2025 11:58:49 -0500 Subject: [PATCH 02/45] feat: Add FeaturesLineChart, PercentileLineChart, and common chart props/utils --- .../charts/FeaturesLineChart.svelte | 62 ++++++++++++++++++ .../charts/PercentileLineChart.svelte | 49 ++++++++++++++ frontend/src/lib/components/charts/common.ts | 64 +++++++++++++++++++ 3 files changed, 175 insertions(+) create mode 100644 frontend/src/lib/components/charts/FeaturesLineChart.svelte create mode 100644 frontend/src/lib/components/charts/PercentileLineChart.svelte create mode 100644 frontend/src/lib/components/charts/common.ts diff --git a/frontend/src/lib/components/charts/FeaturesLineChart.svelte b/frontend/src/lib/components/charts/FeaturesLineChart.svelte new file mode 100644 index 0000000000..17ce546b27 --- /dev/null +++ b/frontend/src/lib/components/charts/FeaturesLineChart.svelte @@ -0,0 +1,62 @@ + + + { + return { + key: d.feature, + data: d.points.map((p) => { + return { + date: new Date(p.ts), + value: p.value + }; + }), + color: colorScale(d.feature) + }; + })} + padding={{ left: 24, bottom: 48 }} + legend={{ placement: 'bottom-left', classes: { root: 'right-0 overflow-auto scrollbar-none' } }} + {...lineChartProps} + {...restProps} +> + + + + {formatDate(x(data))} + + + + {#each series as s} + {@const seriesTooltipData = s.data ? findRelatedData(s.data, data, x) : data} + {@const valueAccessor = accessor(s.value ?? (s.data ? (y as any) : s.key))} + + + {/each} + + + + diff --git a/frontend/src/lib/components/charts/PercentileLineChart.svelte b/frontend/src/lib/components/charts/PercentileLineChart.svelte new file mode 100644 index 0000000000..21e5121177 --- /dev/null +++ b/frontend/src/lib/components/charts/PercentileLineChart.svelte @@ -0,0 +1,49 @@ + + + { + return { + key: c.label, + data: + data + ?.filter((d) => d.label === c.label) + .map((d) => { + return { + date: new Date(d.ts), + value: d.value + }; + }) ?? [], + color: c.color + }; + })} + padding={{ left: 36, bottom: 20 }} + {...merge( + {}, + lineChartProps, + { + props: { + yAxis: { format: 'metric' } + } + }, + restProps + )} +/> diff --git a/frontend/src/lib/components/charts/common.ts b/frontend/src/lib/components/charts/common.ts new file mode 100644 index 0000000000..b54df6dc58 --- /dev/null +++ b/frontend/src/lib/components/charts/common.ts @@ -0,0 +1,64 @@ +import type { BarChart, LineChart, PieChart } from 'layerchart'; +import type { ComponentProps } from 'svelte'; + +export const colors = [ + '#E5174B', + '#E54D4A', + '#E17545', + '#E3994C', + '#DFAF4F', + '#87BE52', + '#53B167', + '#4DA67D', + '#4EA797', + '#4491CE', + '#4592CC', + '#4172D2', + '#5B5AD1', + '#785AD4', + '#9055D5', + '#BF50D3', + '#CB5587' +]; + +export const tooltipProps = { + root: { + variant: 'none', + class: 'text-small bg-neutral-200 border border-neutral-400 rounded-md shadow-lg' + }, + header: { + class: 'text-neutral-700 bg-neutral-300 px-3 py-1' + }, + list: { + class: 'gap-4 px-3 py-2' + }, + item: { + valueAlign: 'right', + classes: { + label: 'text-neutral-800' + } + } +} satisfies NonNullable['props']>['tooltip']; + +export const barChartProps = { + props: { + tooltip: tooltipProps + } +} satisfies NonNullable>; + +export const lineChartProps = { + grid: { + x: { class: 'stroke-neutral-300' }, + y: { class: 'stroke-neutral-300' } + }, + props: { + spline: { class: 'stroke-1' }, + tooltip: tooltipProps + } +} satisfies NonNullable>; + +export const pieChartProps = { + props: { + tooltip: tooltipProps + } +} satisfies NonNullable>; From 08896328871e5a61eed5f45c4a32e44febec9d60 Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Mon, 20 Jan 2025 11:59:30 -0500 Subject: [PATCH 03/45] Replace distributions ECharts with LayerChart --- .../observability/distributions/+page.svelte | 90 +++++++++---------- 1 file changed, 44 insertions(+), 46 deletions(-) diff --git a/frontend/src/routes/joins/[slug]/observability/distributions/+page.svelte b/frontend/src/routes/joins/[slug]/observability/distributions/+page.svelte index 09f3129b35..84cf096118 100644 --- a/frontend/src/routes/joins/[slug]/observability/distributions/+page.svelte +++ b/frontend/src/routes/joins/[slug]/observability/distributions/+page.svelte @@ -1,22 +1,22 @@ {#if data.model} @@ -119,11 +119,9 @@ {#each sortedDistributions as feature} {#snippet collapsibleContent()} - +
+ +
{/snippet}
{/each} From cd3f490889d42a0b44437c7ef4a8bc616af03663 Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Mon, 20 Jan 2025 12:17:28 -0500 Subject: [PATCH 04/45] Replace drifts ECharts usage with LayerChart --- .../[slug]/observability/drift/+page.svelte | 663 ++++++------------ 1 file changed, 203 insertions(+), 460 deletions(-) diff --git a/frontend/src/routes/joins/[slug]/observability/drift/+page.svelte b/frontend/src/routes/joins/[slug]/observability/drift/+page.svelte index 433166a882..26f2dabcd3 100644 --- a/frontend/src/routes/joins/[slug]/observability/drift/+page.svelte +++ b/frontend/src/routes/joins/[slug]/observability/drift/+page.svelte @@ -1,183 +1,73 @@ {#if data.model} @@ -452,30 +187,24 @@
- {#each joinTimeseries.items as group (group.name)} + {#each data.joinTimeseries.items as group (group.name)} {#snippet collapsibleContent()} - - handleChartClick( - event.detail.detail, - groupByCharts[group.name], - event.detail.fromTooltip - )} - on:datazoom={handleZoom} - enableMousemove={true} - enableCustomZoom={true} - enableCustomTooltip={true} - enableTooltipClick={true} - showCustomLegend={true} - legendGroup={group} - /> +
+ { + selectSeries(e.series.key as string); + _selectedEvent = { series: e.series, data: e.data as any }; // TODO: Fix/improve type in LayerChart + isSheetOpen = true; + }} + /> +
{/snippet}
{/each} @@ -489,17 +218,19 @@ highlightSeries(selectedSeries ?? '', dialogGroupChart, 'highlight')} - onmouseleave={() => highlightSeries(selectedSeries ?? '', dialogGroupChart, 'downplay')} + onmouseenter={() => { + /*highlightSeries(selectedSeries ?? '', dialogGroupChart, 'highlight')*/ + }} + onmouseleave={() => { + /*highlightSeries(selectedSeries ?? '', dialogGroupChart, 'downplay')*/ + }} > - {#if selectedSeries && dialogGroupChart} -
- {/if} +
- {selectedSeries ? `${selectedSeries} at ` : ''}{formatEventDate()} + {_selectedEvent?.series.key} at {formatDate(_selectedEvent?.data.date)}
@@ -519,114 +250,126 @@ - {#if selectedEvents[0]?.seriesName} - {@const selectedGroup = joinTimeseries.items.find((group) => - group.items.some((item) => item.feature === selectedEvents[0].seriesName) + {#if _selectedEvent} + {@const selectedGroup = data.joinTimeseries.items.find((group) => + group.items.some((item) => item.feature === _selectedEvent?.series.key) )} {#if selectedGroup} {#snippet collapsibleContent()} - - handleChartClick( - event.detail.detail, - groupByCharts[selectedGroup.name], - event.detail.fromTooltip - )} - enableMousemove={true} - enableCustomZoom={true} - enableCustomTooltip={true} - enableTooltipClick={true} - showCustomLegend={true} - legendGroup={selectedGroup} - /> +
+ { + selectSeries(e.series.key as string); + _selectedEvent = { series: e.series, data: e.data as any }; // TODO: Fix/improve type in LayerChart + isSheetOpen = true; + }} + /> +
{/snippet}
{/if} {/if} - {#if selectedSeries} - {#if percentileData} - - {#snippet collapsibleContent()} - - {/snippet} - - {/if} + {#if percentileData} + + {#snippet collapsibleContent()} +
+ +
+ {/snippet} +
+ {/if} - {#if comparedFeatureData} - - {#snippet headerContentRight()} - {#if isComparedFeatureZoomed} -
- -
- {/if} - {/snippet} - {#snippet collapsibleContent()} - + {#snippet headerContentRight()} + {#if isComparedFeatureZoomed} +
+ + +
+ {/if} + {/snippet} + {#snippet collapsibleContent()} +
+ d.ts === timestamp) ?? [], + color: '#4B92FF' // TODO: copied from ECharts defaults + }, + { + key: 'current', + data: comparedFeatureData.current?.filter((d) => d.ts === timestamp) ?? [], + color: '#7DFFB3' // TODO: copied from ECharts defaults + } + ]} + seriesLayout="group" + groupPadding={0.1} + bandPadding={0.1} + {...barChartProps} + props={{ + _bars: { tweened: { duration: 200 } }, + yAxis: { tweened: { duration: 200 } }, + tooltip: tooltipProps + }} /> - {/snippet} - - {/if} +
+ {/snippet} +
+ {#snippet collapsibleContent()} - + {#if comparedFeatureData} + {@const currentData = comparedFeatureData.current?.find( + (point) => point.ts === timestamp + )} + {@const baselineData = comparedFeatureData.baseline?.find( + (point) => point.ts === timestamp + )} + +
+ {#each [{ label: 'Baseline', data: baselineData }, { label: 'Current', data: currentData }] as c} + {#if c.data} +
+
+ + +
+
+ {c.label} +
+
+ {/if} + {/each} +
+ {/if} {/snippet}
- {:else if selectedEvents.length > 1} -
-
- Select a data point - -
- {#each selectedEvents as event} - - {/each} -
{/if}
From b98202dcc2c55e02b166ddb29b0fccb60ff1bd9b Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Mon, 20 Jan 2025 12:48:35 -0500 Subject: [PATCH 05/45] Remove d3-array and d3-scale packages (and just use the main `d3` package already installed) --- frontend/package-lock.json | 4 ++-- frontend/package.json | 2 -- frontend/src/lib/components/charts/FeaturesLineChart.svelte | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 210e2700ca..7679755bda 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -14,8 +14,6 @@ "@types/echarts": "^4.9.22", "clsx": "^2.1.1", "d3": "^7.9.0", - "d3-array": "^3.2.4", - "d3-scale": "^4.0.2", "dotenv": "^16.4.7", "echarts": "^5.6.0", "layerchart": "^0.74.0", @@ -2145,6 +2143,8 @@ }, "node_modules/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==", "license": "ISC", "engines": { "node": ">=12" diff --git a/frontend/package.json b/frontend/package.json index 2a9ac87758..83f8bcee85 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -66,8 +66,6 @@ "@types/echarts": "^4.9.22", "clsx": "^2.1.1", "d3": "^7.9.0", - "d3-array": "^3.2.4", - "d3-scale": "^4.0.2", "dotenv": "^16.4.7", "echarts": "^5.6.0", "layerchart": "^0.74.0", diff --git a/frontend/src/lib/components/charts/FeaturesLineChart.svelte b/frontend/src/lib/components/charts/FeaturesLineChart.svelte index 17ce546b27..65d5664f57 100644 --- a/frontend/src/lib/components/charts/FeaturesLineChart.svelte +++ b/frontend/src/lib/components/charts/FeaturesLineChart.svelte @@ -1,7 +1,7 @@ {#snippet collapsibleContent()}
- + (xDomain = e.xDomain)} + tooltip={{ locked: lockedTooltip }} + />
{/snippet} @@ -286,13 +291,6 @@ {#if comparedFeatureData} {@const timestamp = Number(selectedEvent?.data.date)} - {#snippet headerContentRight()} - {#if isZoomed} -
- -
- {/if} - {/snippet} {#snippet collapsibleContent()}
Date: Tue, 28 Jan 2025 12:00:46 -0500 Subject: [PATCH 27/45] Upgrade LayerChart to 0.81.2, fixing chart brush resuming updating `isZoomed` derived value --- frontend/package-lock.json | 8 ++++---- frontend/package.json | 2 +- .../routes/joins/[slug]/observability/drift/+page.svelte | 3 ++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 3452f57784..d0e962886b 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -16,7 +16,7 @@ "d3": "^7.9.0", "dotenv": "^16.4.7", "echarts": "^5.6.0", - "layerchart": "^0.81.1", + "layerchart": "^0.81.2", "lodash": "^4.17.21", "tailwind-merge": "^2.6.0", "tailwind-variants": "^0.3.0" @@ -3366,9 +3366,9 @@ } }, "node_modules/layerchart": { - "version": "0.81.1", - "resolved": "https://registry.npmjs.org/layerchart/-/layerchart-0.81.1.tgz", - "integrity": "sha512-g+dxccyPdq2Vz7LWydbFkZYtV15VnznOM9xpEjsAnSiB2QkAgNx7p5SxFT+hdKknoHVKhp3peKodsuOPbQGwZg==", + "version": "0.81.2", + "resolved": "https://registry.npmjs.org/layerchart/-/layerchart-0.81.2.tgz", + "integrity": "sha512-CYJvcEmGGGSlGNvgqM/GVIF3e3/URBgbMaGt8dlWJFouXDXssMPU81eYOWnTm3bL0QmbCx+WhJNbNGXY18vDDQ==", "license": "MIT", "dependencies": { "@dagrejs/dagre": "^1.1.4", diff --git a/frontend/package.json b/frontend/package.json index 1a6d923258..43c5c8b542 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -68,7 +68,7 @@ "d3": "^7.9.0", "dotenv": "^16.4.7", "echarts": "^5.6.0", - "layerchart": "^0.81.1", + "layerchart": "^0.81.2", "lodash": "^4.17.21", "tailwind-merge": "^2.6.0", "tailwind-variants": "^0.3.0" diff --git a/frontend/src/routes/joins/[slug]/observability/drift/+page.svelte b/frontend/src/routes/joins/[slug]/observability/drift/+page.svelte index 234c8ba1ce..ab6e01c466 100644 --- a/frontend/src/routes/joins/[slug]/observability/drift/+page.svelte +++ b/frontend/src/routes/joins/[slug]/observability/drift/+page.svelte @@ -6,7 +6,6 @@ import CollapsibleSection from '$lib/components/CollapsibleSection.svelte'; import type { FeatureResponse } from '$lib/types/Model/Model'; import { ScrollArea } from '$lib/components/ui/scroll-area'; - import ResetZoomButton from '$lib/components/ResetZoomButton.svelte'; import { Api } from '$lib/api/api'; import { Dialog, DialogContent, DialogHeader } from '$lib/components/ui/dialog'; import { formatDate } from '$lib/util/format'; @@ -45,6 +44,8 @@ let isZoomed = $derived(xDomain != null); let lockedTooltip = $state(false); + $inspect({ xDomain, isZoomed }); + function resetZoom() { xDomain = null; } From ae4f0db7bfd83f17b11e07a74daf5333b6398433 Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Tue, 28 Jan 2025 12:18:01 -0500 Subject: [PATCH 28/45] feat(FeaturesLineChart): Mark selected point --- .../charts/FeaturesLineChart.svelte | 20 +++++++++++++++++-- .../[slug]/observability/drift/+page.svelte | 3 +-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/frontend/src/lib/components/charts/FeaturesLineChart.svelte b/frontend/src/lib/components/charts/FeaturesLineChart.svelte index 73bd07bd67..2fdf4d37a3 100644 --- a/frontend/src/lib/components/charts/FeaturesLineChart.svelte +++ b/frontend/src/lib/components/charts/FeaturesLineChart.svelte @@ -1,6 +1,6 @@ {#if data.model} @@ -184,14 +151,10 @@ data={group.items} yDomain={metricTypeDomain} onPointClick={({ series, data }) => { - selectSeries(series.key); - selectedEvent = { series: series, data: data as any }; // TODO: Fix/improve type in LayerChart - isSheetOpen = true; + selectSeriesPoint({ series: series, data: data as any }); }} onItemClick={({ series, data }) => { - selectSeries(series.key); - selectedEvent = { series, data }; // TODO: Fix/improve type in LayerChart - isSheetOpen = true; + selectSeriesPoint({ series: series, data: data as any }); }} {xDomain} onBrushEnd={(e) => (xDomain = e.xDomain)} @@ -205,7 +168,7 @@ {/snippet} - + (selectedSeriesPoint = null)}>
- {selectedEvent?.series.key} at {formatDate(selectedEvent?.data.date)} + {selectedSeriesPoint?.series.key} at {formatDate(selectedSeriesPoint?.data.date)}
@@ -243,9 +206,9 @@
- {#if selectedEvent} + {#if selectedSeriesPoint} {@const selectedGroup = data.joinTimeseries.items.find((group) => - group.items.some((item) => item.feature === selectedEvent?.series.key) + group.items.some((item) => item.feature === selectedSeriesPoint?.series.key) )} {#if selectedGroup} @@ -254,14 +217,12 @@ { - selectSeries(series.key); - selectedEvent = { series: series, data: data as any }; // TODO: Fix/improve type in LayerChart + selectSeriesPoint({ series: series, data: data as any }); }} onItemClick={({ series, data }) => { - selectSeries(series.key); - selectedEvent = { series, data }; // TODO: Fix/improve type in LayerChart + selectSeriesPoint({ series: series, data: data as any }); }} {xDomain} onBrushEnd={(e) => (xDomain = e.xDomain)} @@ -289,7 +250,7 @@ {/if} {#if comparedFeatureData} - {@const timestamp = Number(selectedEvent?.data.date)} + {@const timestamp = Number(selectedSeriesPoint?.data.date)} {#snippet collapsibleContent()}
From e1d2ae732ac0bdeda7eadda913b7711ca7e77768 Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Tue, 28 Jan 2025 12:47:54 -0500 Subject: [PATCH 30/45] Remove ECharts --- frontend/package.json | 2 - .../lib/components/CustomEChartLegend.svelte | 135 ------ frontend/src/lib/components/EChart.svelte | 453 ------------------ .../src/lib/components/EChartTooltip.svelte | 106 ---- .../src/lib/components/PercentileChart.svelte | 59 --- frontend/src/lib/util/chart-options.svelte.ts | 119 ----- frontend/src/lib/util/chart.ts | 37 -- .../observability/distributions/+page.svelte | 4 - .../src/routes/observability/+page.svelte | 126 ----- 9 files changed, 1041 deletions(-) delete mode 100644 frontend/src/lib/components/CustomEChartLegend.svelte delete mode 100644 frontend/src/lib/components/EChart.svelte delete mode 100644 frontend/src/lib/components/EChartTooltip.svelte delete mode 100644 frontend/src/lib/components/PercentileChart.svelte delete mode 100644 frontend/src/lib/util/chart-options.svelte.ts delete mode 100644 frontend/src/lib/util/chart.ts delete mode 100644 frontend/src/routes/observability/+page.svelte diff --git a/frontend/package.json b/frontend/package.json index 43c5c8b542..294b417a33 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -63,11 +63,9 @@ "@creditkarma/thrift-server-core": "^1.0.4", "@creditkarma/thrift-typescript": "^3.7.6", "@layerstack/utils": "^0.0.7", - "@types/echarts": "^4.9.22", "clsx": "^2.1.1", "d3": "^7.9.0", "dotenv": "^16.4.7", - "echarts": "^5.6.0", "layerchart": "^0.81.2", "lodash": "^4.17.21", "tailwind-merge": "^2.6.0", diff --git a/frontend/src/lib/components/CustomEChartLegend.svelte b/frontend/src/lib/components/CustomEChartLegend.svelte deleted file mode 100644 index ccd18e3d12..0000000000 --- a/frontend/src/lib/components/CustomEChartLegend.svelte +++ /dev/null @@ -1,135 +0,0 @@ - - -
-
-
- {#each items as { feature } (feature)} - {@const isHidden = hiddenSeries[groupName]?.has(feature)} - {@const color = getSeriesColor(chart, feature)} - - - {/each} -
- - {#if hasOverflow || isExpanded || containerHeight > containerHeightLine} - - {/if} -
-
- - diff --git a/frontend/src/lib/components/EChart.svelte b/frontend/src/lib/components/EChart.svelte deleted file mode 100644 index c04d08c017..0000000000 --- a/frontend/src/lib/components/EChart.svelte +++ /dev/null @@ -1,453 +0,0 @@ - - - - -
-
- {#if enableCustomTooltip} - - {/if} -
-{#if showCustomLegend && legendGroup && chartInstance} - -{/if} diff --git a/frontend/src/lib/components/EChartTooltip.svelte b/frontend/src/lib/components/EChartTooltip.svelte deleted file mode 100644 index b6efc5940f..0000000000 --- a/frontend/src/lib/components/EChartTooltip.svelte +++ /dev/null @@ -1,106 +0,0 @@ - - -
-
- {#if xValue !== null && visible} -
-
- {getTooltipTitle(xValue, xAxisCategories)} -
- -
- {#each series as item} - - {/each} -
-
- -
- {isMacOS() ? '⌘' : 'Ctrl'} to lock tooltip -
-
- {/if} -
diff --git a/frontend/src/lib/components/PercentileChart.svelte b/frontend/src/lib/components/PercentileChart.svelte deleted file mode 100644 index 61e3fc83b8..0000000000 --- a/frontend/src/lib/components/PercentileChart.svelte +++ /dev/null @@ -1,59 +0,0 @@ - - - diff --git a/frontend/src/lib/util/chart-options.svelte.ts b/frontend/src/lib/util/chart-options.svelte.ts deleted file mode 100644 index 7da101d2e1..0000000000 --- a/frontend/src/lib/util/chart-options.svelte.ts +++ /dev/null @@ -1,119 +0,0 @@ -import type { EChartOption } from 'echarts'; -import merge from 'lodash/merge'; -import { getCssColorAsHex } from '$lib/util/colors'; - -let neutral300 = $state(''); -let neutral700 = $state(''); - -const colorInterval = setInterval(() => { - const color300 = getCssColorAsHex('--neutral-300'); - const color700 = getCssColorAsHex('--neutral-700'); - - if (color300 && color700) { - neutral300 = color300; - neutral700 = color700; - clearInterval(colorInterval); - } -}, 100); - -export function createChartOption( - customOption: Partial = {}, - customColors = false -): EChartOption { - const defaultOption: EChartOption = { - color: customColors - ? [ - '#E5174B', - '#E54D4A', - '#E17545', - '#E3994C', - '#DFAF4F', - '#87BE52', - '#53B167', - '#4DA67D', - '#4EA797', - '#4491CE', - '#4592CC', - '#4172D2', - '#5B5AD1', - '#785AD4', - '#9055D5', - '#BF50D3', - '#CB5587' - ] - : undefined, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'line', - lineStyle: { - color: neutral700, - type: 'solid' - } - }, - position: 'top', - confine: true - }, - xAxis: { - type: 'time', - axisLabel: { - formatter: { - month: '{MMM} {d}', - day: '{MMM} {d}' - } as unknown as string, - color: neutral700 - }, - splitLine: { - show: true, - lineStyle: { - color: neutral300 - } - }, - axisLine: { - lineStyle: { - color: neutral300 - } - } - }, - yAxis: { - type: 'value', - axisLabel: { - formatter: (value: number) => (value % 1 === 0 ? value.toFixed(0) : value.toFixed(1)), - color: neutral700 - }, - splitLine: { - show: true, - lineStyle: { - color: neutral300 - } - }, - axisLine: { - lineStyle: { - color: neutral300 - } - } - }, - grid: { - top: 5, - right: 1, - bottom: 0, - left: 0, - containLabel: true - } - }; - - const baseSeriesStyle = { - showSymbol: false, - lineStyle: { - width: 1 - }, - symbolSize: 7 - }; - - if (customOption.series) { - const series = Array.isArray(customOption.series) ? customOption.series : [customOption.series]; - customOption.series = series.map((s) => merge({}, baseSeriesStyle, s)); - } - - return merge({}, defaultOption, customOption); -} diff --git a/frontend/src/lib/util/chart.ts b/frontend/src/lib/util/chart.ts deleted file mode 100644 index fc0e5e208a..0000000000 --- a/frontend/src/lib/util/chart.ts +++ /dev/null @@ -1,37 +0,0 @@ -import type { EChartsType } from 'echarts'; - -export function handleChartHighlight( - chart: EChartsType | null, - seriesName: string, - type: 'highlight' | 'downplay' -) { - if (!chart || !seriesName) return; - - // Get the series selected state from legend - const options = chart.getOption(); - const legendOpt = Array.isArray(options.legend) ? options.legend[0] : options.legend; - const isSelected = legendOpt?.selected?.[seriesName]; - - // Only highlight if the series is selected (visible) - if (isSelected !== false) { - chart.dispatchAction({ - type, - seriesName - }); - } -} - -export function getSeriesColor(chart: EChartsType | null, seriesName: string): string { - if (!chart) return '#000000'; - - const options = chart.getOption(); - if (!options?.series || !options?.color) return '#000000'; - - // Find the series index by name - const seriesIndex = options.series.findIndex((s) => s.name === seriesName); - if (seriesIndex === -1) return '#000000'; - - // Get color using the correct series index - const colors = options.color as string[]; - return colors[seriesIndex] || '#000000'; -} diff --git a/frontend/src/routes/joins/[slug]/observability/distributions/+page.svelte b/frontend/src/routes/joins/[slug]/observability/distributions/+page.svelte index 84cf096118..71481701e1 100644 --- a/frontend/src/routes/joins/[slug]/observability/distributions/+page.svelte +++ b/frontend/src/routes/joins/[slug]/observability/distributions/+page.svelte @@ -1,6 +1,4 @@ - -
- - -
- -
- ECharts heatmaps are slow when there are lots of cells. I'm figuring it out/testing optimizaiton - stuff -
- - - {#snippet main()} -
- -
- {/snippet} - - {#snippet sidebar()} -
-
Cell Details
-
Information about the clicked cell
- {#if clickedCellData} -
-

X: {Array.isArray(clickedCellData) ? clickedCellData[0] : ''}

-

Y: {Array.isArray(clickedCellData) ? clickedCellData[1] : ''}

-

Value: {Array.isArray(clickedCellData) ? clickedCellData[2] : ''}

-
- {/if} -
- {/snippet} -
From 1d09e621312a64d53bc6db3025505d910c42acb5 Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Tue, 28 Jan 2025 12:56:27 -0500 Subject: [PATCH 31/45] Update package-lock.json after removing ECharts --- frontend/package-lock.json | 42 -------------------------------------- 1 file changed, 42 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index d0e962886b..2f1ec4da9b 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -11,11 +11,9 @@ "@creditkarma/thrift-server-core": "^1.0.4", "@creditkarma/thrift-typescript": "^3.7.6", "@layerstack/utils": "^0.0.7", - "@types/echarts": "^4.9.22", "clsx": "^2.1.1", "d3": "^7.9.0", "dotenv": "^16.4.7", - "echarts": "^5.6.0", "layerchart": "^0.81.2", "lodash": "^4.17.21", "tailwind-merge": "^2.6.0", @@ -1271,13 +1269,6 @@ "@types/d3-selection": "*" } }, - "node_modules/@types/echarts": { - "version": "4.9.22", - "license": "MIT", - "dependencies": { - "@types/zrender": "*" - } - }, "node_modules/@types/eslint": { "version": "9.6.1", "dev": true, @@ -1324,10 +1315,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/zrender": { - "version": "4.0.6", - "license": "MIT" - }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.18.1", "dev": true, @@ -2569,20 +2556,6 @@ "url": "https://dotenvx.com" } }, - "node_modules/echarts": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.6.0.tgz", - "integrity": "sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "2.3.0", - "zrender": "5.6.1" - } - }, - "node_modules/echarts/node_modules/tslib": { - "version": "2.3.0", - "license": "0BSD" - }, "node_modules/electron-to-chromium": { "version": "1.5.75", "dev": true, @@ -5292,21 +5265,6 @@ "funding": { "url": "https://github.com/sponsors/colinhacks" } - }, - "node_modules/zrender": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.6.1.tgz", - "integrity": "sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==", - "license": "BSD-3-Clause", - "dependencies": { - "tslib": "2.3.0" - } - }, - "node_modules/zrender/node_modules/tslib": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", - "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", - "license": "0BSD" } } } From c80c96556e0ee02e449916986f52b88d3bc564fd Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Tue, 28 Jan 2025 13:51:52 -0500 Subject: [PATCH 32/45] feat: Setup brush/zooming on distrtibutions page --- .../observability/distributions/+page.svelte | 55 +++---------------- 1 file changed, 9 insertions(+), 46 deletions(-) diff --git a/frontend/src/routes/joins/[slug]/observability/distributions/+page.svelte b/frontend/src/routes/joins/[slug]/observability/distributions/+page.svelte index 71481701e1..b442453df1 100644 --- a/frontend/src/routes/joins/[slug]/observability/distributions/+page.svelte +++ b/frontend/src/routes/joins/[slug]/observability/distributions/+page.svelte @@ -1,5 +1,6 @@ {#if data.model} @@ -116,7 +75,11 @@ {#snippet collapsibleContent()}
- + (xDomain = e.xDomain)} + />
{/snippet}
From e6a5a8c1771df56b9c101d7288628702f2757f6f Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Tue, 28 Jan 2025 13:56:42 -0500 Subject: [PATCH 33/45] fix: Use canvas renderContext to speed up distributions percentile line charts interactions --- .../routes/joins/[slug]/observability/distributions/+page.svelte | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/routes/joins/[slug]/observability/distributions/+page.svelte b/frontend/src/routes/joins/[slug]/observability/distributions/+page.svelte index b442453df1..490e39ebe7 100644 --- a/frontend/src/routes/joins/[slug]/observability/distributions/+page.svelte +++ b/frontend/src/routes/joins/[slug]/observability/distributions/+page.svelte @@ -79,6 +79,7 @@ data={feature?.current ?? []} {xDomain} onBrushEnd={(e) => (xDomain = e.xDomain)} + renderContext="canvas" />
{/snippet} From d0a821dd34c71ffe9e77109d7d84b1feff8920ad Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Tue, 28 Jan 2025 15:35:51 -0500 Subject: [PATCH 34/45] Resolve all outstanding type errors (`npm run check`) --- frontend/package-lock.json | 8 ++++---- frontend/package.json | 2 +- .../src/lib/components/charts/FeaturesLineChart.svelte | 6 +++--- .../src/lib/components/charts/PercentileLineChart.svelte | 4 ++-- frontend/src/lib/components/charts/common.ts | 2 +- .../routes/joins/[slug]/observability/drift/+page.svelte | 5 ++--- 6 files changed, 13 insertions(+), 14 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 2f1ec4da9b..b3b5b1f8ce 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -14,7 +14,7 @@ "clsx": "^2.1.1", "d3": "^7.9.0", "dotenv": "^16.4.7", - "layerchart": "^0.81.2", + "layerchart": "^0.81.3", "lodash": "^4.17.21", "tailwind-merge": "^2.6.0", "tailwind-variants": "^0.3.0" @@ -3339,9 +3339,9 @@ } }, "node_modules/layerchart": { - "version": "0.81.2", - "resolved": "https://registry.npmjs.org/layerchart/-/layerchart-0.81.2.tgz", - "integrity": "sha512-CYJvcEmGGGSlGNvgqM/GVIF3e3/URBgbMaGt8dlWJFouXDXssMPU81eYOWnTm3bL0QmbCx+WhJNbNGXY18vDDQ==", + "version": "0.81.3", + "resolved": "https://registry.npmjs.org/layerchart/-/layerchart-0.81.3.tgz", + "integrity": "sha512-eRVSQqOZ6oZXRVybAXq5t2bE1YHFpAbGW9E+loGJFSBI+vQIv45UQK2F/xIShkKDvzBbevuihlN2Ay2MiHn3Zw==", "license": "MIT", "dependencies": { "@dagrejs/dagre": "^1.1.4", diff --git a/frontend/package.json b/frontend/package.json index 294b417a33..65aeb9ac7d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -66,7 +66,7 @@ "clsx": "^2.1.1", "d3": "^7.9.0", "dotenv": "^16.4.7", - "layerchart": "^0.81.2", + "layerchart": "^0.81.3", "lodash": "^4.17.21", "tailwind-merge": "^2.6.0", "tailwind-variants": "^0.3.0" diff --git a/frontend/src/lib/components/charts/FeaturesLineChart.svelte b/frontend/src/lib/components/charts/FeaturesLineChart.svelte index 2fdf4d37a3..c5e217c97e 100644 --- a/frontend/src/lib/components/charts/FeaturesLineChart.svelte +++ b/frontend/src/lib/components/charts/FeaturesLineChart.svelte @@ -21,9 +21,9 @@ value: any; }) => void; onBrushEnd?: BrushProps['onBrushEnd']; - } & LineChartProps; + } & Omit; - let { data, markPoint, onItemClick, onBrushEnd, ...restProps } = $props(); + let { data, markPoint, onItemClick, onBrushEnd, ...restProps }: Props = $props(); const features = $derived([...new Set(data.map((d) => d.feature))]); const colorScale = $derived(scaleOrdinal().domain(features).range(colors)); @@ -80,7 +80,7 @@
diff --git a/frontend/src/routes/joins/[slug]/observability/drift/+page.svelte b/frontend/src/routes/joins/[slug]/observability/drift/+page.svelte index e0eca6888d..d0142d7568 100644 --- a/frontend/src/routes/joins/[slug]/observability/drift/+page.svelte +++ b/frontend/src/routes/joins/[slug]/observability/drift/+page.svelte @@ -152,14 +152,14 @@ { + onpointclick={(e, { series, data }) => { selectSeriesPoint({ series: series, data: data as unknown as DateValue }); }} - onItemClick={({ series, data }) => { + onitemclick={({ series, data }) => { selectSeriesPoint({ series: series, data }); }} {xDomain} - onBrushEnd={(e) => (xDomain = e.xDomain)} + onbrushend={(e) => (xDomain = e.xDomain)} tooltip={{ locked: lockedTooltip }} />
@@ -220,14 +220,14 @@ data={selectedGroup.items} yDomain={metricTypeDomain} markPoint={selectedSeriesPoint?.data} - onPointClick={({ series, data }) => { + onpointclick={(e, { series, data }) => { selectSeriesPoint({ series: series, data: data as unknown as DateValue }); }} - onItemClick={({ series, data }) => { + onitemclick={({ series, data }) => { selectSeriesPoint({ series: series, data }); }} {xDomain} - onBrushEnd={(e) => (xDomain = e.xDomain)} + onbrushend={(e) => (xDomain = e.xDomain)} tooltip={{ locked: lockedTooltip }} /> @@ -243,7 +243,7 @@ (xDomain = e.xDomain)} + onbrushend={(e) => (xDomain = e.xDomain)} tooltip={{ locked: lockedTooltip }} /> From 8ae2f2a095c9905f2468266726c5b0bb1a25204f Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Thu, 30 Jan 2025 17:48:18 -0500 Subject: [PATCH 37/45] Handle null values --- frontend/src/lib/components/charts/FeaturesLineChart.svelte | 3 ++- frontend/src/lib/constants/common.ts | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 frontend/src/lib/constants/common.ts diff --git a/frontend/src/lib/components/charts/FeaturesLineChart.svelte b/frontend/src/lib/components/charts/FeaturesLineChart.svelte index 06df6991b8..5c557633bb 100644 --- a/frontend/src/lib/components/charts/FeaturesLineChart.svelte +++ b/frontend/src/lib/components/charts/FeaturesLineChart.svelte @@ -8,6 +8,7 @@ import { formatDate, formatValue } from '$lib/util/format'; import { Badge } from '../ui/badge'; import { isMacOS } from '$src/lib/util/browser'; + import { NULL_VALUE } from '$src/lib/constants/common'; type LineChartProps = ComponentProps; type BrushProps = ComponentProps; @@ -38,7 +39,7 @@ data: d.points.map((p) => { return { date: new Date(p.ts), - value: p.value + value: p.value === NULL_VALUE ? null : p.value }; }), color: colorScale(d.feature) diff --git a/frontend/src/lib/constants/common.ts b/frontend/src/lib/constants/common.ts new file mode 100644 index 0000000000..4416a0377d --- /dev/null +++ b/frontend/src/lib/constants/common.ts @@ -0,0 +1,2 @@ +// Maps to `Constants.magicNullDouble` on server - https://github.com/zipline-ai/chronon/blob/main/api/src/main/scala/ai/chronon/api/Constants.scala#L87 +export const NULL_VALUE = -27980863399423856; From 44a3058f473687cf9e154372b3b1e610468a0b91 Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Sun, 2 Feb 2025 21:35:39 -0500 Subject: [PATCH 38/45] Upgrade LayerChart to 0.93.0 (integrated brush context with many interaction improvements) --- frontend/package-lock.json | 8 ++++---- frontend/package.json | 2 +- .../src/lib/components/charts/FeaturesLineChart.svelte | 4 ++-- .../src/lib/components/charts/PercentileLineChart.svelte | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 05927fd37b..62b018e5fa 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -14,7 +14,7 @@ "clsx": "^2.1.1", "d3": "^7.9.0", "dotenv": "^16.4.7", - "layerchart": "^0.91.0", + "layerchart": "^0.93.0", "lodash": "^4.17.21", "tailwind-merge": "^2.6.0", "tailwind-variants": "^0.3.0" @@ -3339,9 +3339,9 @@ } }, "node_modules/layerchart": { - "version": "0.91.0", - "resolved": "https://registry.npmjs.org/layerchart/-/layerchart-0.91.0.tgz", - "integrity": "sha512-hRVRvkETnoZLIzbsNRqScSJshUO7IjdQPUjFPbA4mBRpEeTX5ikVKLQgaRKI/YK2pVe+GVbC2p481/EStOjR2Q==", + "version": "0.93.0", + "resolved": "https://registry.npmjs.org/layerchart/-/layerchart-0.93.0.tgz", + "integrity": "sha512-umrhIpidFtaCJfp3UI7ybSZ2IXzKZS6dgir1mC97+MwLicvueT0RlLcv1ntr0e29Y7jJSM8G775xmrld3aN0ZA==", "license": "MIT", "dependencies": { "@dagrejs/dagre": "^1.1.4", diff --git a/frontend/package.json b/frontend/package.json index eb2cd50503..b165a96118 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -66,7 +66,7 @@ "clsx": "^2.1.1", "d3": "^7.9.0", "dotenv": "^16.4.7", - "layerchart": "^0.91.0", + "layerchart": "^0.93.0", "lodash": "^4.17.21", "tailwind-merge": "^2.6.0", "tailwind-variants": "^0.3.0" diff --git a/frontend/src/lib/components/charts/FeaturesLineChart.svelte b/frontend/src/lib/components/charts/FeaturesLineChart.svelte index 5c557633bb..46c2cda668 100644 --- a/frontend/src/lib/components/charts/FeaturesLineChart.svelte +++ b/frontend/src/lib/components/charts/FeaturesLineChart.svelte @@ -1,6 +1,6 @@