diff --git a/.github/release-notes/0.3.0.md b/.github/release-notes/0.3.0.md index 5945c154..7639ffd4 100644 --- a/.github/release-notes/0.3.0.md +++ b/.github/release-notes/0.3.0.md @@ -1,43 +1,30 @@ -# Flint 0.3 +Flint 0.3 makes charts easier to explore after they are created. The MCP App can now switch chart types and edit chart properties in place, while the original Flint spec stays compact and readable. -Flint 0.3 makes charts easier to explore after they are created. The MCP App can -now switch between compatible chart types and edit chart properties in place, -while keeping the original Flint spec compact and readable. +### Explore chart types -## Explore chart types - -Move between compatible views without asking the agent to rebuild the chart. -Flint preserves the data roles and derives the details needed by the new chart -type. +Move between compatible views without rebuilding the chart. For example, turn a dense Line Chart of food prices into compact Sparkline rows for easier comparison. Flint preserves the data roles and derives the details for the new chart type. Switching a line chart to a Sparkline in the Flint MCP App -## Edit chart properties +### Edit chart properties -Common chart properties are available directly in the widget. Changes are -immediate, and the available controls follow the selected chart and backend. +Edit common properties directly in the widget. For example, turn labels on in a correlation heatmap to reveal the value in every cell. Controls adapt to the selected chart and backend, and changes appear immediately. Turning labels on for a heatmap in the Flint MCP App -## Flint in Chinese +### Flint in Chinese -The website and documentation are now available in Chinese, including guides for -getting started, authoring charts, and extending Flint. +The website and documentation are now available in Chinese, including guides for getting started, authoring charts, and extending Flint. The Chinese Flint website and documentation -## Smaller updates +### Also in 0.3 - Added backend-neutral chart recommendations and chart transformations. -- Improved sparse area charts, grouped bars, boxplots, Gantt charts, and - Waterfall charts across supported backends. -- Improved semantic formatting for axes, aggregates, and Sparkline averages. -- Sparklines now self-scale each row and no longer expose a shared-Y option. -- Added PNG copy, download, and reset actions to the MCP App. -- Expanded chart-property guidance in the bundled agent skill and reference - documentation. - -See the [changelog](https://github.com/microsoft/flint-chart/blob/main/CHANGELOG.md#030---2026-07-19) -for migration notes and the complete technical summary. +- Improved sparse areas, grouped bars, boxplots, Gantt charts, and Waterfall charts across backends. +- Improved semantic formatting and made Sparkline rows self-scale by default. +- Added PNG copy, download, and reset actions, plus expanded agent guidance. + +See the [changelog](https://github.com/microsoft/flint-chart/blob/main/CHANGELOG.md#030---2026-07-19) for migration notes and the complete technical summary. **Full Changelog**: https://github.com/microsoft/flint-chart/compare/0.2.1...0.3.0 \ No newline at end of file diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index e07fd7af..b9a75cea 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -34,6 +34,7 @@ jobs: - name: Audit production dependencies run: npm audit --omit=dev --audit-level=moderate + continue-on-error: true - name: Check package versions shell: bash diff --git a/CHANGELOG.md b/CHANGELOG.md index cc9f58cc..77a31201 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,13 +4,78 @@ Starting with version 0.2.1, all notable changes to `flint-chart` and `flint-chart-mcp` are documented in this file. The two npm packages are versioned and released together, so each release entry covers both packages. Versions 0.2.1 and 0.2.2 were development milestones and were not published to -npm; 0.3.0 is the next public release after 0.2.0. +npm; 0.3.0 resumed public releases after 0.2.0. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [0.4.0] - 2026-07-24 + +### Added + +- Excel backend: 18 chart templates compile the same semantic Flint input into + native, editable Office.js charts — Bar, Grouped/Stacked Bar, Pyramid, Line, + Area, Scatter, Connected Scatter, Pie, Donut, Histogram, Boxplot, + Candlestick, Waterfall, Radar, Funnel, Treemap, and Sunburst. The backend + emits a rectangular data range plus native chart/axis/legend/series metadata, + includes Office.js code generation and runtime helpers, and was visually + audited across 117 cases with `test-harness/excel/`. +- Plotly backend: expanded from the four original acceptance templates (Bar, + Line, Area, Scatter) to 33 chart types — grouped/stacked bar, pyramid, + histogram, boxplot, violin, density, ECDF, strip plot, connected scatter, + range area, streamgraph, slope, bump, waterfall, candlestick, heatmap, + lollipop, bullet, Gantt, ranged dot plot, regression, pie, donut, radar, + rose, KPI card, and the Plotly-native opportunity charts Funnel and Gauge — + leaning on Plotly's own native trace types (`box`, `violin`, `candlestick`, + `waterfall`, `heatmap`, `scatterpolar`, `barpolar`, `indicator`, `funnel`) + wherever one exists. +- Plotly backend: closed the four remaining registry gaps and added the + Plotly-native Density Contour statistical chart, now 38 chart types. + - Map, Choropleth — native `scattergeo`/`choropleth` traces with Plotly's + own built-in geo atlas (no TopoJSON fetch/join). Share the Vega-Lite + Map/Choropleth's region-name/code gazetteer (`chart-types/geo.ts`, moved + out of `vegalite/templates/` to be backend-shared), extended with USPS/ + ISO-alpha-3 code resolvers for Plotly's native `locations` binding. + - Sparkline, Bar Table — composite, self-contained Plotly figures (their + own multi-axis-pair grid + paper-anchored annotations) rather than the + generic column/row facet combiner, which only supports one cartesian + axis pair per panel. A new `ChartTemplateDef.selfManagesFacets` flag lets + a template opt out of the assembler's generic facet-splitting pass even + though it declares `x`/`y` channels. +- Plotly scatter/strip plots now use a native continuous colorscale + + colorbar for quantitative/temporal `color` fields instead of grouping them + like a categorical legend. +- `docs/reference-plotly.md` — generated chart reference for the Plotly + backend (`npm run gen:reference`). +- `test-harness/plotly/` — a headless-Chromium render/audit harness for the + Plotly backend (spec → PNG, contact sheets, VLM review script, and a + per-chart-type inspection list), mirroring the Excel backend's visual audit + harness. + +### Fixed + +- Plotly: a shared column/row facet-splitting pass ran for every template, + including axis-less ones (Pie, Donut, Radar, Rose, Gauge, KPI Card, Funnel) + that use the `column` channel for their own internal per-item grouping — + this collapsed multi-item Gauge/KPI grids onto identical, fully-overlapping + domains. Faceting is now gated on the template declaring `x`/`y` channels, + mirroring the ECharts backend's own guard. +- Plotly Choropleth: Plotly's own built-in `'Blues'` colorscale runs + dark→light as the value increases — the opposite of the light→dark + sequential convention used everywhere else, which made the *highest*-value + region read as the palest. Replaced with an explicit light→dark stop array. +- Plotly Bar Table (faceted): each facet cell's per-cell `xaxis{n}`/ + `yaxis{n}` pair needs an explicit `anchor` to each other — without it every + cell's category tick labels rendered at the same horizontal position + (overlapping across cells). Also fixed: long category names now truncate + with an ellipsis instead of overflowing past the figure's own edge; a + column-only facet with more panels than fit is now actually wrapped (using + this template's own minimum panel-width estimate, not the shared layout + engine's narrower default); sub-1 magnitude values no longer round away to + "0"; a single-row table no longer collapses to an unreadably short figure. + ## [0.3.0] - 2026-07-19 ### Added @@ -105,7 +170,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Treated only lowercase `start` and `end` Waterfall Type values as total anchors in Vega-Lite; other values now remain floating deltas colored by sign. -[Unreleased]: https://github.com/microsoft/flint-chart/compare/0.3.0...HEAD +[Unreleased]: https://github.com/microsoft/flint-chart/compare/0.4.0...HEAD +[0.4.0]: https://github.com/microsoft/flint-chart/compare/0.3.0...0.4.0 [0.3.0]: https://github.com/microsoft/flint-chart/compare/88fbeb5ebf07f18a1cf661ebef71cc570b7425d6...0.3.0 [0.2.2]: https://github.com/microsoft/flint-chart/compare/0.2.1...6a9d4e4155e3d9e2bed3fa9adf5316914f791478 [0.2.1]: https://github.com/microsoft/flint-chart/compare/c8e20b052ad9ddad29ba3ecfc825948c424e5ba5...0.2.1 \ No newline at end of file diff --git a/README.md b/README.md index 00d10810..d0903ddf 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![npm: flint-chart](https://img.shields.io/npm/v/flint-chart.svg?label=npm%3A%20flint-chart)](https://www.npmjs.com/package/flint-chart) [![npm: flint-chart-mcp](https://img.shields.io/npm/v/flint-chart-mcp.svg?label=npm%3A%20flint-chart-mcp)](https://www.npmjs.com/package/flint-chart-mcp) +[![arXiv: 2607.20775](https://img.shields.io/badge/arXiv-2607.20775-b31b1b.svg)](https://arxiv.org/abs/2607.20775) [![CI](https://github.com/microsoft/flint-chart/actions/workflows/ci.yml/badge.svg)](https://github.com/microsoft/flint-chart/actions/workflows/ci.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) @@ -15,18 +16,19 @@ derives optimized chart settings from the data, semantic types, chart type, and encodings. The result is a compact chart specification that agents can produce reliably, people can edit directly, and multiple backends can render as native [Vega-Lite](https://vega.github.io/vega-lite/), -[ECharts](https://echarts.apache.org/), or -[Chart.js](https://www.chartjs.org/) specs. +[ECharts](https://echarts.apache.org/), +[Chart.js](https://www.chartjs.org/), or +[Plotly](https://plotly.com/javascript/) specs, and native Excel charts through Office.js. This repo contains two main components: - **`flint-chart`**: a JavaScript/TypeScript library that compiles the same - Flint input into Vega-Lite, ECharts, or Chart.js specs. + Flint input into Vega-Lite, ECharts, Chart.js, Plotly, or Excel-native output. - **`flint-chart-mcp`**: an MCP server that lets agents create, validate, and render charts directly from a chat or coding environment.

- A wall of charts produced by Flint: bar, line, scatter, heatmap, donut, radar, streamgraph, boxplot, grouped bar, rose, Sankey, and treemap, rendered across Vega-Lite, ECharts, and Chart.js. + A wall of charts produced by Flint across its supported visualization backends.

## Features @@ -36,16 +38,19 @@ This repo contains two main components: semantic types such as `Rank`, `Temperature`, `Price`, or `Country`. - **Automatic layout.** Flint adapts sizing, spacing, labels, marks, and legends to the data cardinality, chart design, and canvas constraints. -- **Multiple backends.** Compile one input to 30+ chart types across +- **Multiple backends.** Compile one input to backend-native output across [Vega-Lite](https://vega.github.io/vega-lite/), - [ECharts](https://echarts.apache.org/), and - [Chart.js](https://www.chartjs.org/), with more to come soon. + [ECharts](https://echarts.apache.org/), + [Chart.js](https://www.chartjs.org/), + [Plotly](https://plotly.com/javascript/), and native Excel charts. - **Agent-ready chart authoring.** The MCP server gives agents Flint tools and chart guidance so they can choose a template, validate it, and open an interactive chart view in MCP-capable clients. ## Updates +- **July 24, 2026** — Flint 0.4.0 adds 38 Plotly chart types and 18 native, + editable Excel chart templates. ([v0.4.0](https://github.com/microsoft/flint-chart/releases/tag/0.4.0)) - **July 19, 2026** — Flint 0.3.0 adds dynamic chart widgets that switch chart types and edit chart properties in place. ([v0.3.0](https://github.com/microsoft/flint-chart/releases/tag/0.3.0)) - **July 15, 2026** — Flint 0.2.2 added compact dodge modes and grouped violin @@ -97,15 +102,19 @@ const spec = assembleVegaLite({ Swap the backend without changing the input shape: ```ts -import { assembleECharts, assembleChartjs } from 'flint-chart'; +import { assembleECharts, assembleChartjs, assemblePlotly, assembleExcel } from 'flint-chart'; const echartsOption = assembleECharts(input); const chartjsConfig = assembleChartjs(input); +const plotlyFigure = assemblePlotly(input); +const excelArtifact = assembleExcel(input); ``` -See the [API reference](docs/api-reference.md), [backend references](docs/reference-vegalite.md), -and [live editor](https://microsoft.github.io/flint-chart/#/editor) for more -library examples. +See the [API reference](docs/api-reference.md), backend references for +[Vega-Lite](docs/reference-vegalite.md), [ECharts](docs/reference-echarts.md), +[Chart.js](docs/reference-chartjs.md), [Plotly](docs/reference-plotly.md), and +[Excel](docs/reference-excel.md), plus the +[live editor](https://microsoft.github.io/flint-chart/#/editor) for more library examples. ## Use Flint As An MCP Server diff --git a/agent-skills/flint-chart-author/SKILL.md b/agent-skills/flint-chart-author/SKILL.md index c05dee2d..3b3fbedc 100644 --- a/agent-skills/flint-chart-author/SKILL.md +++ b/agent-skills/flint-chart-author/SKILL.md @@ -250,8 +250,8 @@ support a subset (verify if targeting a non-VL backend): `"Funnel"`, `"Treemap"`, `"Sunburst"`, `"Sankey"`, `"Parallel Coordinates"`, `"Graph"`, `"Tree"`. - **Chart.js** supports: Scatter, Bubble, Bar, Grouped Bar, Stacked Bar, - Combo, Line, Area, Range Area, Pie, Doughnut, Histogram, Radar, Rose, Slope, - Connected Scatter. + Combo, Line, Bump, Area, Range Area, Pie, Doughnut, Histogram, Radar, Rose, + Slope, Connected Scatter. You do not need to call the library or inspect its source to author the input — pick from this table. diff --git a/docs/README.md b/docs/README.md index fbcf3cc7..41b96e06 100644 --- a/docs/README.md +++ b/docs/README.md @@ -851,9 +851,9 @@ interface ChartTemplateDef { ### `OverflowStrategy` -Customizable per-template. The default strategy in `filter-overflow.ts` handles: -connected marks (keep all for continuity), user sorts, auto-sorts, -bar sum-aggregate, numeric sort, first-N. +Customizable per-template. The default strategy in `filter-overflow.ts` keeps +the first values in the selected display order: explicit user sort, canonical +semantic order, numeric order, then data encounter order. ```typescript type OverflowStrategy = ( @@ -917,42 +917,20 @@ visualization decisions: ## Template Catalog -### Vega-Lite (30 chart types) - -| Category | Charts | -|----------|--------| -| **Scatter & Point** | Scatter Plot, Regression, Ranged Dot Plot, Boxplot, Strip Plot | -| **Bar** | Bar Chart, Grouped Bar Chart, Stacked Bar Chart, Histogram, Heatmap, Lollipop Chart, Pyramid Chart | -| **Line & Area** | Line Chart, Dotted Line Chart, Bump Chart, Area Chart, Streamgraph | -| **Part-to-Whole** | Pie Chart, Rose Chart, Waterfall Chart | -| **Statistical** | Density Plot, Candlestick Chart, Radar Chart | -| **Map** | US Map, World Map | - -### ECharts (28 chart types) - -| Category | Charts | -|----------|--------| -| **Scatter & Point** | Scatter Plot, Regression, Ranged Dot Plot, Boxplot, Strip Plot | -| **Bar** | Bar Chart, Grouped Bar Chart, Stacked Bar Chart, Histogram, Heatmap, Lollipop Chart, Pyramid Chart | -| **Line & Area** | Line Chart, Dotted Line Chart, Bump Chart, Area Chart, Streamgraph | -| **Part-to-Whole** | Pie Chart, Funnel Chart, Treemap, Sunburst Chart | -| **Polar** | Radar Chart, Rose Chart | -| **Financial** | Candlestick Chart | -| **Indicator** | Gauge Chart | -| **Flow** | Sankey Diagram | -| **Other** | Waterfall Chart, Density Plot | - -### Chart.js (10 chart types) - -| Category | Charts | -|----------|--------| -| **Scatter & Point** | Scatter Plot | -| **Bar** | Bar Chart, Grouped Bar Chart, Stacked Bar Chart, Histogram | -| **Line & Area** | Line Chart, Area Chart | -| **Part-to-Whole** | Pie Chart | -| **Polar** | Radar Chart, Rose Chart | - -**68 template definitions** across 3 backends. +Flint currently ships **149 backend template registrations** across five +backends. Chart names overlap because the same semantic input can target more +than one renderer. + +| Backend | Registered chart types | Generated reference | +|---|---:|---| +| Vega-Lite | 35 | [Vega-Lite charts](reference-vegalite.md) | +| ECharts | 37 | [ECharts charts](reference-echarts.md) | +| Chart.js | 21 | [Chart.js charts](reference-chartjs.md) | +| Plotly | 38 | [Plotly charts](reference-plotly.md) | +| Excel | 18 | [Excel charts](reference-excel.md) | + +Run `npm run gen:reference` after changing a template registry. The generated +pages are the source of truth for chart names, channels, and exposed options. Each template defines: 1. **`template`** — spec skeleton (mark + encoding structure) @@ -1009,13 +987,14 @@ When discrete channels overflow the canvas budget, the library: count, placeholder string 5. Emits `ChartWarning` for the UI -The default overflow strategy priority: -1. Connected marks (line, area) → keep all (truncation breaks continuity) -2. User-specified sort → keep top/bottom N by sort order -3. Quantitative opposite axis → sort by opposite, keep top N -4. Bar with count aggregate → sum-aggregate and keep top N -5. Numeric field → numeric sort, keep first N -6. Fallback → keep first N in data order +The default overflow strategy follows the chart's display order: +1. User-specified sort → keep the first N values in that order +2. Canonical semantic order (months, ranks, quarters, etc.) → keep the first N +3. Numeric discrete field → numeric ascending, keep the first N +4. Fallback → keep the first N in data encounter order + +Overflow does not introduce a measure-based top-N ranking. Select an explicit +value sort when the largest or smallest categories should be retained. --- diff --git a/docs/adding-a-backend.md b/docs/adding-a-backend.md index 57c6af96..5265869b 100644 --- a/docs/adding-a-backend.md +++ b/docs/adding-a-backend.md @@ -1,6 +1,6 @@ # Extending backends -Add a backend when Flint needs to target a new rendering library or spec format. A backend is an `assemble(input)` orchestrator plus a `templates/` registry; together they turn shared compiler output into a native chart spec. Existing references live under `packages/flint-js/src/`: `vegalite/`, `echarts/`, and `chartjs/`. +Add a backend when Flint needs to target a new rendering library or spec format. A backend is an `assemble(input)` orchestrator plus a `templates/` registry; together they turn shared compiler output into a native chart spec or artifact. Existing references live under `packages/flint-js/src/`: `vegalite/`, `echarts/`, `chartjs/`, `plotly/`, and `excel/`. For pipeline stages and repo layout, see [Architecture](/documentation/architecture). diff --git a/docs/api-reference.md b/docs/api-reference.md index 7eda96b9..3ac68882 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -58,11 +58,15 @@ import { assembleVegaLite, assembleECharts, assembleChartjs, + assemblePlotly, + assembleExcel, } from 'flint-chart'; const vlSpec = assembleVegaLite(input); const ecSpec = assembleECharts(input); const cjsSpec = assembleChartjs(input); +const plFig = assemblePlotly(input); +const xlSpec = assembleExcel(input); ``` | Export | Returns | @@ -70,8 +74,37 @@ const cjsSpec = assembleChartjs(input); | `assembleVegaLite` | Vega-Lite JSON spec | | `assembleECharts` | ECharts `option` object | | `assembleChartjs` | Chart.js configuration | +| `assemblePlotly` | Plotly.js `{ data, layout }` figure | +| `assembleExcel` | Native Excel chart artifact for Office.js | -If a backend does not support a `chartType`, the assembler throws before render. Check support with `vlGetTemplateDef`, `ecGetTemplateDef`, or `cjsGetTemplateDef`. +If a backend does not support a `chartType`, the assembler throws before render. Check support with `vlGetTemplateDef`, `ecGetTemplateDef`, `cjsGetTemplateDef`, `plGetTemplateDef`, or `excelGetTemplateDef`. + +## Excel runtime and code generation + +`assembleExcel` returns a serializable `flint.excel.chart/v1` artifact. Render it +inside an Office.js Excel host, or turn it into standalone Office.js source: + +```ts +import { assembleExcel, generateOfficeJs, renderExcelChart } from 'flint-chart'; + +const artifact = assembleExcel(input); +const { pngBase64, inspection } = await renderExcelChart(Excel, artifact, { + scale: 3, + cleanWorksheet: true, + inspectNativeChart: false, +}); +const { code, meta } = generateOfficeJs(artifact, { + scale: 3, + cleanWorksheet: true, + functionName: 'renderFlintChart', +}); +``` + +`renderExcelChart` requires an Excel API object with `run` and +`ImageFittingMode.fit`. It creates the native chart on the active worksheet and +returns a PNG capture plus optional inspection data. `generateOfficeJs` does not +execute Excel; it returns portable source and metadata about the generated data +range and chart. --- @@ -160,9 +193,19 @@ interface AssembleOptions { maxColorValues?: number; // color cardinality before truncation (default 24) stepPadding?: number; // band inner padding fraction (default 0.1) defaultBandSize?: number; // baseline px per category (backend-tuned) + maxBandSize?: number; // max px per category when sparse (backend-tuned) + baseLabelFontSize?: number; // axis tick font at the reference canvas (VL 10, EC/CJS/Plotly 12) + baseTitleFontSize?: number; // header font — axis title / legend / chart title (VL 11, EC/CJS 12, Plotly 14) } ``` +Fonts adapt to canvas size around these per-backend bases: at the default +canvas each backend renders its native size, growing subtly on larger canvases +(up to base + 4) and shrinking in small-multiple subplots; axis tick labels also +shrink/rotate/truncate to avoid overlap. Set `baseLabelFontSize` / +`baseTitleFontSize` to scale all text up or down — e.g. `baseLabelFontSize: 14` +for larger tick labels across the whole chart. + Full list: `packages/flint-js/src/core/types.ts` (`AssembleOptions`). Behavior: [Auto Layout Algorithm](/documentation/layout-model). --- diff --git a/docs/architecture.md b/docs/architecture.md index efa192cf..b738faf9 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -39,10 +39,10 @@ Most design logic lives in Stages 1–2 and is identical across backends. |-------|------------|----------------|-------------| | **1. Compiler frontend** | Resolve semantic context | Phase 0 — `resolveChannelSemantics()` | `ChannelSemantics` per channel | | **2. Optimizer** | Fit layout to canvas | Phase 1 — `computeLayout()`, `filterOverflow()` | `LayoutResult`, truncated data | -| **3. Code generator** | Emit library-native spec | Phase 2 — `build*Encodings()`, `template.instantiate()` | VL / EC / CJS spec | +| **3. Code generator** | Emit backend-native output | Phase 2 — `build*Encodings()`, `template.instantiate()` | VL / EC / CJS / Plotly spec or Excel artifact | ```text -assembleVegaLite(input) // or assembleECharts, assembleChartjs +assembleVegaLite(input) // or assembleECharts, assembleChartjs, assemblePlotly, assembleExcel │ ▼ ══ STAGE 1 — COMPILER FRONTEND (core/) ═════════════════════════ @@ -108,7 +108,7 @@ The model is group-theoretic but deliberately practical. Start from the authored The visible View control is the finite orbit after validity checks and deduplication. Deduplication is the stabilizer quotient in concrete form: flip twice returns to `Default`, faceting then jittering can collapse to the same Strip Plot as jittering directly, and a chart-type round trip such as Scatter → Strip Plot → Scatter folds back onto the authored scatter. Compatibility checks are also typed: `σ` only swaps within the same field profile (measure with measure, category with category), while `τ` is allowed to cross profiles because it flips axis slots, not field roles. Line charts omit `τ`, so Flint never offers a vertical line chart. -Because the orbit is computed over Flint's backend-neutral encoding IR, the same View state ids apply across Vega-Lite, ECharts, and Chart.js. Each backend receives the already-transformed encoding map; only `θ` requires backend-specific template lookup so the sibling chart's own instantiation logic takes over. +Because the orbit is computed over Flint's backend-neutral encoding IR, the same View state ids apply across Vega-Lite, ECharts, Chart.js, and Plotly. Each backend receives the already-transformed encoding map; only `θ` requires backend-specific template lookup so the sibling chart's own instantiation logic takes over. --- @@ -150,6 +150,27 @@ Registries: `vlTemplateDefs`, `ecTemplateDefs`, `cjsTemplateDefs`. Lookup: `vlGe New backends implement Stage 3 only; the frontend and optimizer stay unchanged. See [Extending backends](/documentation/adding-a-backend). +### Excel backend + +Excel is a Stage 3 backend in `packages/flint-js`, parallel to Vega-Lite, ECharts, Chart.js, and Plotly. It is not a separate package or an additional architectural layer. + +Office.js is imperative and requires an Excel host, so the backend first builds a typed native-chart artifact (`ExcelNativeChartSpec`) containing the worksheet matrix, native chart type, series bindings, dimensions, axes, labels, legend, and formatting. This versioned artifact is the contract between compilation and execution. + +The native-chart plan is an intermediate representation of the Excel backend, not a second user-authored chart specification. Callers continue to author the same semantic Flint input used by every backend: + +```text +semantic Flint input + │ + ▼ +assembleExcel() → ExcelNativeChartSpec + │ + ├── renderExcelChart(Excel, artifact) → native Excel chart + │ + └── generateOfficeJs(artifact) → standalone Office.js source +``` + +The normal add-in path transports the artifact and passes it, with the live Excel host, to `renderExcelChart()`. `generateOfficeJs()` is an optional projection for callers that need portable Office.js source; it is not a second contract or a required step in rendering. Host concerns such as worksheet selection, image capture, and process lifecycle stay outside compilation. Test harnesses may provide those host services, but they do not define Excel chart semantics. + --- # §6 Inputs @@ -178,9 +199,11 @@ packages/flint-js/src/ ├── vegalite/ Stage 3 — Vega-Lite templates + assembleVegaLite ├── echarts/ Stage 3 — ECharts templates + assembleECharts ├── chartjs/ Stage 3 — Chart.js templates + assembleChartjs +├── excel/ Stage 3 — native Excel chart planning + Office.js generation └── test-data/ gallery fixtures (TEST_GENERATORS) packages/flint-py/ Python port preview (package planned later) +test-harness/excel/ Office.js runner + visual evaluations of Excel artifacts site/ demo site (gallery, editor, documentation) ``` diff --git a/docs/design-stretch-model.md b/docs/design-stretch-model.md index f4439ad4..f2d4063c 100644 --- a/docs/design-stretch-model.md +++ b/docs/design-stretch-model.md @@ -262,12 +262,18 @@ The `detectBandedAxis` function in `templates/utils.ts` handles this decision. ## §2.1 Problem -A discrete axis displays $N$ banded items (categories, bins, groups) along a 1D segment of length $L_0$ pixels. Each item ideally occupies $\ell_0$ pixels (the natural length). When $N \cdot \ell_0 > L_0$, the items overflow. +A discrete axis displays $N$ banded items (categories, bins, groups) along a 1D +segment of length $L_0$ pixels. Each band has a **natural size** $\ell_0$ and is +kept within a **minimum** $\ell_{\min}$ and a **maximum** $\ell_{\max}$. -Two competing goals must be balanced: +The layout balances two directions: -1. **Items resist compression** — each item pushes outward to maintain $\ell_0$, and cannot shrink below $\ell_{\min}$. -2. **The axis resists expansion** — the axis can stretch beyond $L_0$ but has a hard maximum $L_{\max}$. +1. **Too sparse.** When a few items share a wide plot, each band grows to fill + the space — but never past $\ell_{\max}$, so one or two bars don't balloon to + the whole canvas. +2. **Too dense.** When many items crowd the axis, bands compress toward + $\ell_{\min}$, and the axis itself may stretch up to $L_{\max}$ to relieve the + pressure. Beyond that, extra items overflow. ## §2.2 Parameters @@ -276,40 +282,80 @@ Two competing goals must be balanced: | $L_0$ | Natural axis length | `width` / `height` (base size) | 400 px | | $L_{\max}$ | Maximum axis length | `base × β` (β from `maxStretch` or `canvasSize`) | 800 px | | $N$ | Number of banded items | Field cardinality | data-dependent | -| $\ell_0$ | Natural length per item | `defaultStepSize` | ~20 px | -| $\ell_{\min}$ | Minimum length per item | `minStep` option | 6 px | +| $\ell_0$ | Natural (base) size per band | `defaultBandSize` | ~20 px | +| $\ell_{\min}$ | Minimum size per band | `minStep` option | 6 px | +| $\ell_{\max}$ | Maximum size per band | `maxBandSize` option | = $\ell_0$ | | $\alpha$ | Elasticity exponent | `elasticity` option | 0.5 | | $\beta$ | Maximum stretch multiplier | `maxStretch`, or derived from `canvasSize` | 1.5 | -> **Code defaults:** `elasticity: 0.5`, `minStep: 6`, and `maxStretch: 1.5` when no `canvasSize` ceiling is set. The `defaultStepSize` is computed dynamically based on canvas size: `round(20 × max(1, sizeRatio) × defaultStepMultiplier)`. +> **Code defaults:** `elasticity: 0.5`, `minStep: 6`, and `maxStretch: 1.5` when no `canvasSize` ceiling is set. $\ell_0$ and $\ell_{\max}$ are given at a 300 px reference canvas and scaled with size: `round(bandSize × max(1, sizeRatio))`. + +### §2.2.1 Band size bounds — min, base, max + +Every banded chart resolves one number, the **band step** $\ell$: the pixels +allotted to each category slot. It is a clamp of the available width per item +between the minimum and maximum band size: + +$$\ell = \operatorname{clamp}\!\left(\frac{L}{N},\; \ell_{\min},\; \ell_{\max}\right)$$ + +- $\ell_0$ (**base**) is the natural band size *and* the density threshold: it + decides when compression begins. +- $\ell_{\min}$ (**min**) is the tightest a band may compress before items + overflow. +- $\ell_{\max}$ (**max**) is the widest a band may expand when the chart is + sparse. + +The three bounds are **backend-specific**, chosen to match each renderer's native +bar sizing. Vega-Lite sizes a plot as `N × step`, so its bands never grow past +the base — $\ell_{\max} = \ell_0$. ECharts, Chart.js, and Plotly instead fill +their plot area natively, so their bands expand up to a much larger $\ell_{\max}$ +before compressing. + +| Backend | Native sizing | $\ell_{\min}$ | $\ell_0$ (base) | $\ell_{\max}$ | +|---|---|---:|---:|---:| +| Vega-Lite | `width: { step }` grows the plot to `N × step` | 6 | 20 | 20 | +| ECharts | fills the grid (`barCategoryGap`) | 6 | 24 | 100 | +| Chart.js | fills the canvas (`categoryPercentage`) | 6 | 30 | 100 | +| Plotly | fills the plot area (`bargap`) | 6 | 20 | 100 | + +*(Reference sizes at a 300 px canvas; scaled with actual size. Chart templates +may override any bound — e.g. boxplot widens the base, jitter widens both.)* ## §2.3 Three Regimes -### Regime 1: No compression needed +### Regime 1: Sparse — expand to fill **Condition:** $N \cdot \ell_0 \leq L_0$ -All items fit at their natural length: +Items would leave gaps at their base size, so each band grows to fill the base +axis, capped at the maximum: -$$\ell = \ell_0, \quad L = N \cdot \ell_0$$ +$$\ell = \min\!\left(\ell_{\max},\; \frac{L_0}{N}\right), \quad L = N \cdot \ell$$ -### Regime 2: Overflow beyond recovery +The axis does **not** grow past its base $L_0$ here — expansion happens *inside* +the base width. When $\ell_{\max} = \ell_0$ (Vega-Lite), bands simply stay at the +base size. -**Condition:** $N \cdot \ell_{\min} \geq L_{\max}$ +### Regime 2: Dense — compress and stretch -Even at minimum item length and maximum stretch, not all items fit. Excess items are truncated: +**Condition:** $N \cdot \ell_0 > L_0$ and $N \cdot \ell_{\min} < L_{\max}$ -$$N' = \left\lfloor \frac{L_{\max}}{\ell_{\min}} \right\rfloor, \quad \ell = \ell_{\min}, \quad L = L_{\max}$$ +Items overflow the base axis. Bands compress and the axis stretches up to +$L_{\max}$, governed by the elastic budget in [§2.4](#24-power-law-elastic-budget). -### Regime 3: Elastic equilibrium +### Regime 3: Overflow beyond recovery -**Condition:** $N \cdot \ell_0 > L_0$ and $N \cdot \ell_{\min} < L_{\max}$ +**Condition:** $N \cdot \ell_{\min} \geq L_{\max}$ + +Even at minimum band size and maximum stretch, not all items fit. Excess items +are truncated: -Items overflow but can be accommodated by compressing items and/or stretching the axis. This is where the elastic model applies. +$$N' = \left\lfloor \frac{L_{\max}}{\ell_{\min}} \right\rfloor, \quad \ell = \ell_{\min}, \quad L = L_{\max}$$ ## §2.4 Power-Law Elastic Budget -This is the **implemented model**. The axis stretches using a power-law of the pressure ratio: +This is the **implemented model** for the dense regime. The axis budget stretches +using a power-law of the pressure ratio: **Pressure:** @@ -317,17 +363,22 @@ $$p = \frac{N \cdot \ell_0}{L_0}$$ **Stretch factor:** -$$s = \min(\beta,\; p^{\alpha})$$ +$$s = \min(\beta,\; \max(1, p)^{\alpha})$$ -**Resulting step size:** +**Axis budget and step size:** -$$\ell = \frac{L_0 \cdot s}{N} = \frac{L_0 \cdot p^{\alpha}}{N}$$ +$$L = L_0 \cdot s, \qquad \ell = \operatorname{clamp}\!\left(\frac{L}{N},\; \ell_{\min},\; \ell_{\max}\right)$$ -With $\alpha = 0.5$, doubling the overflow only increases the stretch by $\sqrt{2} \approx 1.41\times$ — a naturally progressive response. +For sparse charts $p \le 1$, so $s = 1$: the budget stays at $L_0$ and the step +reduces to the Regime 1 fill, $\min(\ell_{\max}, L_0/N)$. For dense charts +$p > 1$, the budget grows and bands compress. With $\alpha = 0.5$, doubling the +overflow only increases the stretch by $\sqrt{2} \approx 1.41\times$ — a +naturally progressive response. -**Clamping:** The step is clamped to $[\ell_{\min},\; \ell_0]$ and the axis length to $[L_0,\; L_{\max}]$. +**Clamping:** The step is clamped to $[\ell_{\min},\; \ell_{\max}]$ and the axis +length to $[L_0,\; L_{\max}]$. -> **Implementation:** `computeElasticBudget()` in `core/decisions.ts` (lines ~549–569). Called by `computeAxisStep()` which handles both nominal and continuous-as-discrete cases. +> **Implementation:** `computeElasticBudget()` in `core/decisions.ts` produces the axis budget; `computeLayout()` in `core/compute-layout.ts` clamps the step to $[\ell_{\min}, \ell_{\max}]$ using the backend's `minStep` / `defaultBandSize` / `maxBandSize`. ## §2.5 Theoretical foundation (spring model) diff --git a/docs/overview.md b/docs/overview.md index e1a4490f..b3ac6713 100644 --- a/docs/overview.md +++ b/docs/overview.md @@ -1,6 +1,6 @@ # Overview -**Flint** is a semantics-driven intermediate language (IL) for data visualization. You declare what each field *means* and the chart you want; the compiler derives scales, axes, aggregation, formatting, layout, and color, then emits Vega-Lite, ECharts, or Chart.js. +**Flint** is a semantics-driven intermediate language (IL) for data visualization. You declare what each field *means* and the chart you want; the compiler derives scales, axes, aggregation, formatting, layout, and color, then emits Vega-Lite, ECharts, Chart.js, Plotly, or a native Excel chart artifact. If you're new to Flint, start with [Getting started](/documentation/getting-started), then come back here for the architecture and API map. @@ -135,7 +135,7 @@ Pipeline detail: [Architecture](/documentation/architecture). | Section | Pages | |---------|-------| | **Language design** | [Architecture](/documentation/architecture), [Semantic Type](/documentation/semantic-types), [Auto Layout Algorithm](/documentation/layout-model), [API reference](/documentation/api-reference) | -| **Chart reference** | [Vega-Lite charts](/documentation/reference-vegalite), [ECharts charts](/documentation/reference-echarts), [Chart.js charts](/documentation/reference-chartjs) | +| **Chart reference** | [Vega-Lite charts](/documentation/reference-vegalite), [ECharts charts](/documentation/reference-echarts), [Chart.js charts](/documentation/reference-chartjs), [Plotly charts](/documentation/reference-plotly), [Excel charts](/documentation/reference-excel) | | **Development** | [Development guide](/documentation/development), [Extending semantic types](/documentation/adding-a-semantic-type), [Extending backends](/documentation/adding-a-backend), [Extending chart templates](/documentation/adding-a-chart-template) | --- diff --git a/docs/reference-chartjs.md b/docs/reference-chartjs.md index f843ef78..f06c1265 100644 --- a/docs/reference-chartjs.md +++ b/docs/reference-chartjs.md @@ -6,7 +6,7 @@ The Chart.js backend is the lightweight embedding target for common chart famili ## What this page covers -This reference lists the 20 chart types currently supported by the Chart.js backend, grouped into 5 categories. Each chart entry shows: +This reference lists the 21 chart types currently supported by the Chart.js backend, grouped into 5 categories. Each chart entry shows: - **Encoding channels** — the visual roles accepted in `chart_spec.encodings`, such as `x`, `y`, `color`, `size`, `column`, or `row`. - **Options** — template-specific `chart_spec.chartProperties` keys, including control type, domain, default, availability, and description. @@ -127,6 +127,12 @@ _No template-specific parameters._ |---|---|---|---|---|---| | `interpolate` | choice | Default (linear) _(default)_, `linear` (Linear), `monotone` (Monotone (smooth)), `step` (Step), `step-before` (Step Before), `step-after` (Step After) | — | always | Line or area interpolation method. | +### ![](chart-icon-bump.svg) Bump Chart + +**Encoding channels:** `x`, `y`, `color`, `detail`, `column`, `row` + +_No template-specific parameters._ + ### ![](chart-icon-slope.svg) Slope Chart **Encoding channels:** `x`, `y`, `color`, `detail`, `column`, `row` diff --git a/docs/reference-excel.md b/docs/reference-excel.md new file mode 100644 index 00000000..173ae444 --- /dev/null +++ b/docs/reference-excel.md @@ -0,0 +1,53 @@ +# Excel chart reference + +> This page is generated from the live Excel chart-template registry (`scripts/gen-chart-reference.ts`). Do not edit it by hand — run `npm run gen:reference`. + +The Excel backend compiles a Flint specification into a versioned native-chart artifact, which Office.js turns into an editable chart in an Excel workbook. + +## Supported charts + +The backend currently supports 18 chart types. Use the exact name shown below in `chart_spec.chartType`. + +| Flint chart type | Encoding channels | Native `Excel.ChartType` | +|---|---|---| +| Bar Chart | `x`, `y`, `color` | `ColumnClustered` / `BarClustered` | +| Grouped Bar Chart | `x`, `y`, `group` | `ColumnClustered` / `BarClustered` | +| Stacked Bar Chart | `x`, `y`, `color` | `ColumnStacked` / `BarStacked` | +| Pyramid Chart | `x`, `y`, `color` | `BarStacked` | +| Line Chart | `x`, `y`, `color`, `strokeDash` | `Line` | +| Area Chart | `x`, `y`, `color` | `Area` | +| Scatter Plot | `x`, `y`, `color`, `size` | `XYScatter` | +| Connected Scatter Plot | `x`, `y`, `order`, `color`, `detail` | `XYScatterLines` | +| Pie Chart | `color`, `size`, `theta` | `Pie` | +| Donut Chart | `color`, `size`, `theta` | `Doughnut` | +| Histogram | `x`, `color` | `ColumnClustered` | +| Boxplot | `x`, `y`, `color` | `BoxWhisker` | +| Candlestick Chart | `x`, `open`, `high`, `low`, `close` | `StockOHLC` | +| Waterfall Chart | `x`, `y`, `color` | `Waterfall` | +| Radar Chart | `x`, `y`, `color` | `RadarMarkers` | +| Funnel Chart | `y`, `size` | `Funnel` | +| Treemap | `color`, `size`, `detail` | `Treemap` | +| Sunburst Chart | `color`, `size`, `group`, `detail` | `Sunburst` | + +## Compile and render + +`assembleExcel(input)` returns a `flint.excel.chart/v1` artifact. It describes the worksheet data matrix, native chart type, series bindings, axes, legend, labels, and formatting, but does not open Excel itself. + +```ts +import { assembleExcel, renderExcelChart } from 'flint-chart'; + +const artifact = assembleExcel(input); +const result = await renderExcelChart(Excel, artifact); +``` + +`renderExcelChart` must run in an Excel host that provides Office.js `Excel.run` and `Excel.ImageFittingMode.fit`. It creates a native chart on the active worksheet and returns a PNG captured through `Chart.getImage()`. + +Call `generateOfficeJs(artifact)` when you need portable Office.js source instead of immediate execution. + +## Limitations + +- A single native Excel chart does not support Flint `column` or `row` facets. +- Chart types without a native Excel equivalent, such as Heatmap, are rejected before rendering. +- Some charts impose stricter data requirements. For example, scatter charts require quantitative `x` and `y`, while candlesticks require `open`, `high`, `low`, and `close`. The assembler reports a specific validation error. + +Use `excelGetTemplateDef(chartType)` or `excelGetTemplateChannels(chartType)` to check support before compiling. diff --git a/docs/reference-plotly.md b/docs/reference-plotly.md new file mode 100644 index 00000000..4bdf2c8a --- /dev/null +++ b/docs/reference-plotly.md @@ -0,0 +1,348 @@ +# Plotly chart reference + +> This page is generated from the live chart-template registry (`scripts/gen-chart-reference.ts`). Do not edit it by hand — run `npm run gen:reference`. + +The Plotly backend compiles to a Plotly.js figure (`{ data, layout }`) and leans on Plotly-native trace types wherever one exists (candlestick, box, violin, heatmap, waterfall, `scatterpolar`/`barpolar`, `indicator`, `scattergeo`/`choropleth`) instead of hand-building the mark. Funnel and Gauge have no Vega-Lite equivalent and showcase Plotly-specific native primitives. Map and Choropleth use Plotly's own built-in geo atlas (no external TopoJSON fetch/join needed). Sparkline and Bar Table are composite, self-contained figures (their own multi-axis-pair grid + annotations) rather than the generic column/row facet combiner. + +## What this page covers + +This reference lists the 38 chart types currently supported by the Plotly backend, grouped into 8 categories. Each chart entry shows: + +- **Encoding channels** — the visual roles accepted in `chart_spec.encodings`, such as `x`, `y`, `color`, `size`, `column`, or `row`. +- **Options** — template-specific `chart_spec.chartProperties` keys, including control type, domain, default, availability, and description. + +Use the chart type name exactly as shown in `chart_spec.chartType`. + +## How to set encodings and options + +Set encodings in `chart_spec.encodings` and chart-specific options in `chart_spec.chartProperties`. Option keys match the parameter names below: + +```jsonc +{ + "chartType": "Bar Chart", + "encodings": { "x": { "field": "category" }, "y": { "field": "value" } }, + "chartProperties": { "cornerRadius": 4, "stackMode": "normalize" } +} +``` + +The **Availability** column shows whether a parameter is `always` available or `conditional`, meaning it appears only when the data and encodings make it relevant. For example, log-scale controls appear only on wide-range axes. Non-applicable parameters are safe to pass; the assembler ignores them. + +## Scatter & Point + +### ![](chart-icon-scatter.svg) Scatter Plot + +**Encoding channels:** `x`, `y`, `color`, `size`, `opacity`, `column`, `row` + +| Parameter | Control | Domain | Default | Availability | Description | +|---|---|---|---|---|---| +| `opacity` | number | 0.1 – 1 (step 0.05) | `1` | always | Mark opacity. | + +### ![](chart-icon-linear-regression.svg) Regression + +**Encoding channels:** `x`, `y`, `size`, `color`, `column`, `row` + +| Parameter | Control | Domain | Default | Availability | Description | +|---|---|---|---|---|---| +| `regressionMethod` | choice | `linear` (Linear), `log` (Logarithmic), `exp` (Exponential), `pow` (Power), `quad` (Quadratic), `poly` (Polynomial) | `linear` | always | Regression fit method. | +| `polyOrder` | number | 2 – 10 (step 1) | `3` | always | Polynomial order for the regression fit. | +| `opacity` | number | 0.1 – 1 (step 0.05) | `1` | always | Mark opacity. | + +### ![](chart-icon-connected-scatter.svg) Connected Scatter Plot + +**Encoding channels:** `x`, `y`, `order`, `color`, `detail`, `column`, `row` + +_No template-specific parameters._ + +### ![](chart-icon-dot-plot-horizontal.svg) Ranged Dot Plot + +**Encoding channels:** `x`, `y`, `color` + +_No template-specific parameters._ + +### ![](chart-icon-strip-plot.svg) Strip Plot + +**Encoding channels:** `x`, `y`, `color`, `size`, `column`, `row` + +_No template-specific parameters._ + +## Bar + +### ![](chart-icon-column.svg) Bar Chart + +**Encoding channels:** `x`, `y`, `color`, `opacity`, `column`, `row` + +| Parameter | Control | Domain | Default | Availability | Description | +|---|---|---|---|---|---| +| `cornerRadius` | number | 0 – 15 (step 1) | `0` | always | Corner radius for supported marks. | + +### ![](chart-icon-column-grouped.svg) Grouped Bar Chart + +**Encoding channels:** `x`, `y`, `group`, `color`, `column`, `row` + +_No template-specific parameters._ + +### ![](chart-icon-column-stacked.svg) Stacked Bar Chart + +**Encoding channels:** `x`, `y`, `color`, `column`, `row` + +| Parameter | Control | Domain | Default | Availability | Description | +|---|---|---|---|---|---| +| `stackMode` | choice | Stacked (default) _(default)_, `normalize` (Normalize (100%)) | — | conditional | Stacking strategy for overlapping series. | + +### ![](chart-icon-lollipop.svg) Lollipop Chart + +**Encoding channels:** `x`, `y`, `color`, `column`, `row` + +| Parameter | Control | Domain | Default | Availability | Description | +|---|---|---|---|---|---| +| `dotSize` | number | 20 – 300 (step 10) | `80` | always | Size of the dot mark. | + +### ![](chart-icon-waterfall.svg) Waterfall Chart + +**Encoding channels:** `x`, `y`, `color`, `column`, `row` + +| Parameter | Control | Domain | Default | Availability | Description | +|---|---|---|---|---|---| +| `totals` | choice | `auto` (Auto), `none` (None), `first` (First only), `last` (Last only), `both` (First and last) | `auto` | always | Totals | +| `showTextLabels` | toggle | on / off | `false` | always | Render value labels on the marks. | + +### ![](chart-icon-pyramid.svg) Pyramid Chart + +**Encoding channels:** `x`, `y`, `color` + +_No template-specific parameters._ + +## Distributions + +### ![](chart-icon-histogram.svg) Histogram + +**Encoding channels:** `x`, `color`, `column`, `row` + +| Parameter | Control | Domain | Default | Availability | Description | +|---|---|---|---|---|---| +| `binCount` | number | 5 – 50 (step 1) | `10` | always | Maximum bin cap; Auto lets the backend choose. | + +### ![](chart-icon-box-plot.svg) Boxplot + +**Encoding channels:** `x`, `y`, `color`, `column`, `row` + +| Parameter | Control | Domain | Default | Availability | Description | +|---|---|---|---|---|---| +| `showOutliers` | toggle | on / off | `true` | always | Outliers | + +### ![](chart-icon-violin.svg) Violin Plot + +**Encoding channels:** `x`, `y`, `color`, `column`, `row` + +| Parameter | Control | Domain | Default | Availability | Description | +|---|---|---|---|---|---| +| `showBox` | toggle | on / off | `true` | always | Inner box | +| `showPoints` | toggle | on / off | `false` | always | Overlay point markers on the line. | + +### ![](chart-icon-density.svg) Density Plot + +**Encoding channels:** `x`, `color`, `column`, `row` + +| Parameter | Control | Domain | Default | Availability | Description | +|---|---|---|---|---|---| +| `bandwidth` | number | 0.05 – 2 (step 0.05) | `0` | always | Kernel-density bandwidth (0 = auto). | + +### ![](chart-icon-ecdf.svg) ECDF Plot + +**Encoding channels:** `x`, `color`, `detail`, `column`, `row` + +| Parameter | Control | Domain | Default | Availability | Description | +|---|---|---|---|---|---| +| `showPoints` | toggle | on / off | `false` | always | Overlay point markers on the line. | + +### ![](chart-icon-candlestick.svg) Candlestick Chart + +**Encoding channels:** `x`, `open`, `high`, `low`, `close`, `column`, `row` + +| Parameter | Control | Domain | Default | Availability | Description | +|---|---|---|---|---|---| +| `showMA` | toggle | on / off | `false` | always | Show a moving-average overlay. | +| `maWindow` | number | 3 – 30 (step 1) | `5` | always | Moving-average window size. | + +### Density Contour + +**Encoding channels:** `x`, `y`, `column`, `row` + +| Parameter | Control | Domain | Default | Availability | Description | +|---|---|---|---|---|---| +| `binCount` | number | 5 – 50 (step 1) | `20` | always | Maximum bin cap; Auto lets the backend choose. | +| `showPoints` | toggle | on / off | `true` | always | Overlay point markers on the line. | + +## Line & Area + +### ![](chart-icon-line.svg) Line Chart + +**Encoding channels:** `x`, `y`, `color`, `opacity`, `column`, `row` + +| Parameter | Control | Domain | Default | Availability | Description | +|---|---|---|---|---|---| +| `interpolate` | choice | Default (linear) _(default)_, `linear` (Linear), `monotone` (Monotone (smooth)), `step` (Step), `step-before` (Step Before), `step-after` (Step After) | — | always | Line or area interpolation method. | +| `showPoints` | toggle | on / off | `false` | always | Overlay point markers on the line. | + +### ![](chart-icon-area.svg) Area Chart + +**Encoding channels:** `x`, `y`, `color`, `opacity`, `column`, `row` + +| Parameter | Control | Domain | Default | Availability | Description | +|---|---|---|---|---|---| +| `interpolate` | choice | Default (linear) _(default)_, `linear` (Linear), `monotone` (Monotone (smooth)) | — | always | Line or area interpolation method. | +| `opacity` | number | 0.1 – 1 (step 0.05) | `0.4` | always | Mark opacity. | +| `stackMode` | choice | Stacked (default) _(default)_, `normalize` (Normalize (100%)), `layered` (Layered (overlap)) | — | conditional | Stacking strategy for overlapping series. | + +### ![](chart-icon-bump.svg) Bump Chart + +**Encoding channels:** `x`, `y`, `color`, `detail`, `column`, `row` + +_No template-specific parameters._ + +### ![](chart-icon-slope.svg) Slope Chart + +**Encoding channels:** `x`, `y`, `color`, `detail`, `column`, `row` + +_No template-specific parameters._ + +### ![](chart-icon-streamgraph.svg) Streamgraph + +**Encoding channels:** `x`, `y`, `color`, `column`, `row` + +_No template-specific parameters._ + +### ![](chart-icon-range-area.svg) Range Area Chart + +**Encoding channels:** `x`, `y`, `y2`, `color`, `column`, `row` + +| Parameter | Control | Domain | Default | Availability | Description | +|---|---|---|---|---|---| +| `opacity` | number | 0.1 – 1 (step 0.05) | `0.35` | always | Mark opacity. | + +## Circular + +### ![](chart-icon-pie.svg) Pie Chart + +**Encoding channels:** `size`, `color` + +| Parameter | Control | Domain | Default | Availability | Description | +|---|---|---|---|---|---| +| `sortSlices` | choice | `none` (Data order), `descending` (Largest first), `ascending` (Smallest first) | `none` | always | Sort slices | +| `labelType` | choice | `categoryPercent` (Name + %), `category` (Name), `value` (Value), `percent` (Percent), `none` (None) | `categoryPercent` | always | Labels | + +### ![](chart-icon-doughnut.svg) Donut Chart + +**Encoding channels:** `size`, `color` + +| Parameter | Control | Domain | Default | Availability | Description | +|---|---|---|---|---|---| +| `innerRadius` | number | 20 – 80 (step 5) | `55` | always | Inner radius as a percentage of the outer radius. | +| `sortSlices` | choice | `none` (Data order), `descending` (Largest first), `ascending` (Smallest first) | `none` | always | Sort slices | +| `labelType` | choice | `categoryPercent` (Name + %), `category` (Name), `value` (Value), `percent` (Percent), `none` (None) | `categoryPercent` | always | Labels | + +### ![](chart-icon-radar.svg) Radar Chart + +**Encoding channels:** `x`, `y`, `color`, `column`, `row` + +| Parameter | Control | Domain | Default | Availability | Description | +|---|---|---|---|---|---| +| `filled` | choice | `true` (Filled (default)), `false` (Outline only) | — | always | Fill the enclosed radar area. | +| `fillOpacity` | number | 0.05 – 0.8 (step 0.05) | `0.3` | always | Fill opacity for the area or region. | + +### ![](chart-icon-rose.svg) Rose Chart + +**Encoding channels:** `x`, `y`, `color` + +| Parameter | Control | Domain | Default | Availability | Description | +|---|---|---|---|---|---| +| `sortSlices` | choice | `none` (Data order), `descending` (Largest first), `ascending` (Smallest first) | `none` | always | Sort slices | + +## Tables & KPIs + +### ![](chart-icon-heat-map.svg) Heatmap + +**Encoding channels:** `x`, `y`, `color`, `column`, `row` + +_No template-specific parameters._ + +### ![](chart-icon-gantt.svg) Gantt Chart + +**Encoding channels:** `y`, `x`, `x2`, `color`, `detail`, `column`, `row` + +| Parameter | Control | Domain | Default | Availability | Description | +|---|---|---|---|---|---| +| `taskHeight` | number | 40 – 90 (step 5) | `70` | always | Task bar height as a percentage of each row. | +| `cornerRadius` | number | 0 – 8 (step 1) | `2` | always | Corner radius for supported marks. | +| `intervalLabels` | toggle | on / off | `false` | always | Text shown on task intervals. | + +### ![](chart-icon-bullet.svg) Bullet Chart + +**Encoding channels:** `y`, `x`, `goal`, `color`, `column`, `row` + +_No template-specific parameters._ + +### ![](chart-icon-kpi-card.svg) KPI Card + +**Encoding channels:** `metric`, `value`, `goal` + +| Parameter | Control | Domain | Default | Availability | Description | +|---|---|---|---|---|---| +| `layout` | choice | `horizontal` (Horizontal (default)), `vertical` (Vertical), `grid` (Grid) | — | always | Layout | + +### Sparkline + +**Encoding channels:** `x`, `y`, `color`, `detail` + +| Parameter | Control | Domain | Default | Availability | Description | +|---|---|---|---|---|---| +| `baseline` | choice | `mean` (Average), `zero` (Zero), `median` (Median), `none` (None) | `mean` | always | Reference line | +| `trendWidth` | number | 80 – 600 (step 10) | `240` | always | Sparkline width | + +### ![](chart-icon-bar-table.svg) Bar Table + +**Encoding channels:** `y`, `x`, `color`, `column`, `row` + +| Parameter | Control | Domain | Default | Availability | Description | +|---|---|---|---|---|---| +| `maxRows` | number | 5 – 100 (step 1) | `20` | always | Maximum number of table rows to display. | +| `showPercent` | toggle | on / off | `false` | conditional | Show each value as a percentage of the total. | + +## Maps + +### ![](chart-icon-world-map.svg) Map + +**Encoding channels:** `longitude`, `latitude`, `color`, `size`, `opacity` + +| Parameter | Control | Domain | Default | Availability | Description | +|---|---|---|---|---|---| +| `region` | choice | `auto` (Auto-detect), `us` (United States), `world` (World) | `auto` | always | Region | +| `projection` | choice | `default` (Default), `mercator` (Mercator), `equalEarth` (Equal Earth), `orthographic` (Orthographic (Globe)), `stereographic` (Stereographic), `conicEqualArea` (Conic Equal Area), `conicEquidistant` (Conic Equidistant), `azimuthalEquidistant` (Azimuthal Equidistant), `mollweide` (Mollweide) | `default` | conditional | Projection | +| `projectionCenter` | choice | Default _(default)_, `0,0` (World (Atlantic) [0, 0]), `150,0` (World (Pacific) [150, 0]), `105,35` (China [105, 35]), `-98,39` (USA [-98, 39]), `10,50` (Europe [10, 50]), `138,36` (Japan [138, 36]), `78,22` (India [78, 22]), `-52,-14` (Brazil [-52, -14]), `134,-25` (Australia [134, -25]), `100,60` (Russia [100, 60]), `20,0` (Africa [20, 0]), `45,28` (Middle East [45, 28]), `115,5` (Southeast Asia [115, 5]), `-60,-15` (South America [-60, -15]), `-100,45` (North America [-100, 45]), `-2,54` (UK [-2, 54]), `10,51` (Germany [10, 51]), `2,47` (France [2, 47]), `128,36` (Korea [128, 36]) | — | conditional | Center | + +### ![](chart-icon-us-map.svg) Choropleth + +**Encoding channels:** `id`, `color`, `detail` + +| Parameter | Control | Domain | Default | Availability | Description | +|---|---|---|---|---|---| +| `region` | choice | `auto` (Auto-detect), `us` (United States), `world` (World) | `auto` | always | Region | + +## Opportunity + +### ![](chart-icon-funnel.svg) Funnel Chart + +**Encoding channels:** `y`, `size` + +| Parameter | Control | Domain | Default | Availability | Description | +|---|---|---|---|---|---| +| `sort` | choice | `descending` (Descending (default)), `ascending` (Ascending), `none` (Original order) | `descending` | always | Sort order for ordered stages or categories. | + +### ![](chart-icon-gauge.svg) Gauge Chart + +**Encoding channels:** `size`, `column` + +| Parameter | Control | Domain | Default | Availability | Description | +|---|---|---|---|---|---| +| `min` | number | 0 – 1000 (step 10) | `0` | always | Min | +| `max` | number | 0 – 10000 (step 100) | `100` | always | Max | diff --git a/docs/reference-vegalite.md b/docs/reference-vegalite.md index 574c4acc..c463217c 100644 --- a/docs/reference-vegalite.md +++ b/docs/reference-vegalite.md @@ -6,7 +6,7 @@ The Vega-Lite backend serves as Flint's reference implementation and offers the ## What this page covers -This reference lists the 34 chart types currently supported by the Vega-Lite backend, grouped into 6 categories. Each chart entry shows: +This reference lists the 35 chart types currently supported by the Vega-Lite backend, grouped into 6 categories. Each chart entry shows: - **Encoding channels** — the visual roles accepted in `chart_spec.encodings`, such as `x`, `y`, `color`, `size`, `column`, or `row`. - **Options** — template-specific `chart_spec.chartProperties` keys, including control type, domain, default, availability, and description. @@ -345,6 +345,16 @@ _No template-specific parameters._ | `sortSlices` | choice | `none` (Data order), `descending` (Largest first), `ascending` (Smallest first) | `none` | always | Sort slices | | `independentYAxis` | toggle | on / off | `false` | conditional | Use independent y-scales for facets. | +### ![](chart-icon-doughnut.svg) Donut Chart + +**Encoding channels:** `size`, `color`, `column`, `row` + +| Parameter | Control | Domain | Default | Availability | Description | +|---|---|---|---|---|---| +| `innerRadius` | number | 0 – 100 (step 5) | `0` | always | Inner radius as a percentage of the outer radius. | +| `sortSlices` | choice | `none` (Data order), `descending` (Largest first), `ascending` (Smallest first) | `none` | always | Sort slices | +| `independentYAxis` | toggle | on / off | `false` | conditional | Use independent y-scales for facets. | + ### ![](chart-icon-rose.svg) Rose Chart **Encoding channels:** `x`, `y`, `color`, `column`, `row` diff --git a/docs/tutorials/agent-workflows.md b/docs/tutorials/agent-workflows.md index 3ade4b58..fa0ba059 100644 --- a/docs/tutorials/agent-workflows.md +++ b/docs/tutorials/agent-workflows.md @@ -391,8 +391,9 @@ intent and production rendering. - [Set up Flint MCP](/documentation/setup-flint-mcp) explains how to expose Flint as an MCP server when you want a ready-made agent tool surface. - [Vega-Lite charts](/documentation/reference-vegalite), - [ECharts charts](/documentation/reference-echarts), and - [Chart.js charts](/documentation/reference-chartjs) list supported chart + [ECharts charts](/documentation/reference-echarts), + [Chart.js charts](/documentation/reference-chartjs), and + [Plotly charts](/documentation/reference-plotly) list supported chart types by backend. - [Semantic Type](/documentation/semantic-types) lists the labels the agent can use for fields. \ No newline at end of file diff --git a/docs/tutorials/chart-sizing.md b/docs/tutorials/chart-sizing.md index cc8fc585..072e464e 100644 --- a/docs/tutorials/chart-sizing.md +++ b/docs/tutorials/chart-sizing.md @@ -114,4 +114,30 @@ treats it as a box the chart fills and shrinks to fit, never overflowing: } ``` +## Font size + +Text (axis tick labels, axis titles, legend, chart title) adapts to the canvas +around each backend's native font, so a small chart isn't cramped and a large +one isn't tiny. To scale all text up or down, set the two base sizes in +`options`: + +```json +{ + "chart_spec": { + "chartType": "Bar Chart", + "encodings": { "x": { "field": "category" }, "y": { "field": "value" } } + }, + "options": { + "baseLabelFontSize": 14, + "baseTitleFontSize": 16 + } +} +``` + +`baseLabelFontSize` sets the axis tick font; `baseTitleFontSize` sets the header +font (axis titles, legend, chart title). They default to each backend's native +size (Vega-Lite 10 / 11; ECharts and Chart.js 12 / 12; Plotly 12 / 14). Dense +axes still shrink, rotate, and truncate tick labels from that base to avoid +overlap. + For facets and the model details behind these controls, continue to [Auto Layout Algorithm](/documentation/layout-model). \ No newline at end of file diff --git a/docs/tutorials/exploring-data.md b/docs/tutorials/exploring-data.md index 3a46c36d..7fcccb2d 100644 --- a/docs/tutorials/exploring-data.md +++ b/docs/tutorials/exploring-data.md @@ -191,6 +191,8 @@ The same `ChartAssemblyInput` compiles to every supported backend: | `assembleVegaLite(input)` | Vega-Lite v6 spec | | `assembleECharts(input)` | ECharts `option` object | | `assembleChartjs(input)` | Chart.js config | +| `assemblePlotly(input)` | Plotly.js `{ data, layout }` figure | +| `assembleExcel(input)` | Native Excel chart artifact for Office.js | Not every `chartType` exists in every backend. The [gallery](/gallery) shows only tabs for supported engines — e.g. **Sankey** is @@ -201,11 +203,15 @@ import { vlGetTemplateDef, ecGetTemplateDef, cjsGetTemplateDef, + plGetTemplateDef, + excelGetTemplateDef, } from 'flint-chart'; vlGetTemplateDef('Bar Chart'); // defined ecGetTemplateDef('Bar Chart'); // defined cjsGetTemplateDef('Sankey Diagram'); // undefined +plGetTemplateDef('Density Contour'); // defined +excelGetTemplateDef('Treemap'); // defined ``` When a template is missing, the assembler throws a clear error before your diff --git a/docs/tutorials/getting-started.md b/docs/tutorials/getting-started.md index db389f73..9e5c0044 100644 --- a/docs/tutorials/getting-started.md +++ b/docs/tutorials/getting-started.md @@ -2,7 +2,8 @@ Flint starts from a simple idea: describe **what your data means**, then say **what picture you want**. Flint turns that into a render-ready chart spec for -Vega-Lite, ECharts, or Chart.js. +Vega-Lite, ECharts, Chart.js, or Plotly, and can emit a native Excel chart +artifact for Office.js hosts. This page keeps the first pass intentionally small. You will install the package, look at one complete Flint spec, and compile it into a chart. @@ -146,12 +147,17 @@ await embed('#chart', spec); The same Flint input can also target other backends in JavaScript: ```ts -import { assembleChartjs, assembleECharts } from 'flint-chart'; +import { assembleChartjs, assembleECharts, assembleExcel, assemblePlotly } from 'flint-chart'; const chartjsConfig = assembleChartjs(input); const echartsOption = assembleECharts(input); +const plotlyFigure = assemblePlotly(input); +const excelArtifact = assembleExcel(input); ``` +Plotly returns a `{ data, layout }` figure. Excel returns a versioned native-chart +artifact that an Office.js host can pass to `renderExcelChart`. + Python support will use the same input shape and is planned for a later release. ## What to read next @@ -165,6 +171,7 @@ Python support will use the same input shape and is planned for a later release. - [Semantic Type](/documentation/semantic-types) explains the semantic labels Flint understands, such as `YearMonth`, `Quantity`, `Category`, and `Profit`. - [Gallery](/gallery) lists the chart templates available across Vega-Lite, - ECharts, and Chart.js. + ECharts, Chart.js, and Plotly; the [Excel gallery](/gallery/excel) shows native + editable charts captured from Excel. - [Overview](/documentation/overview) gives the deeper architecture when you are ready for the full model. diff --git a/docs/tutorials/setup-flint-mcp.md b/docs/tutorials/setup-flint-mcp.md index fec53d72..16b4a2e0 100644 --- a/docs/tutorials/setup-flint-mcp.md +++ b/docs/tutorials/setup-flint-mcp.md @@ -59,6 +59,18 @@ npx -y flint-chart-mcp That command starts a stdio MCP server. In practice, you usually put it in your client's MCP configuration instead of running it by hand. +## Use the hosted server + +If your client only supports remote HTTP MCP servers, connect to the public +Flint endpoint: + +```text +https://flint.data-formulator.ai/mcp +``` + +Prefer the local stdio server when your client supports it, especially when +charting local files. The hosted server accepts data embedded in tool calls. + ## Configure VS Code For VS Code, add a server entry in `.vscode/mcp.json`: @@ -234,6 +246,7 @@ support MCP Apps; ask the agent to use `render_chart` instead. - [Getting started](/documentation/getting-started) explains the `DataSpec` and `ChartSpec` shape with a tiny first chart. - [Vega-Lite charts](/documentation/reference-vegalite), - [ECharts charts](/documentation/reference-echarts), and - [Chart.js charts](/documentation/reference-chartjs) list supported chart + [ECharts charts](/documentation/reference-echarts), + [Chart.js charts](/documentation/reference-chartjs), and + [Plotly charts](/documentation/reference-plotly) list supported chart types by backend. diff --git a/docs/zh-CN/adding-a-backend.md b/docs/zh-CN/adding-a-backend.md index 9a16df05..d488736c 100644 --- a/docs/zh-CN/adding-a-backend.md +++ b/docs/zh-CN/adding-a-backend.md @@ -1,6 +1,6 @@ # 扩展后端 -当 Flint 需要面向新的渲染库或 spec 格式时,添加后端。后端是 `assemble(input)` 编排器加上 `templates/` 注册表;二者共同将共享编译器输出转换为原生图表 spec。现有参考实现位于 `packages/flint-js/src/` 下的 `vegalite/`、`echarts/` 和 `chartjs/`。 +当 Flint 需要面向新的渲染库或 spec 格式时,添加后端。后端是 `assemble(input)` 编排器加上 `templates/` 注册表;二者共同将共享编译器输出转换为原生图表 spec 或工件。现有参考实现位于 `packages/flint-js/src/` 下的 `vegalite/`、`echarts/`、`chartjs/`、`plotly/` 和 `excel/`。 流水线阶段与仓库结构见 [Architecture](/documentation/architecture)。 diff --git a/docs/zh-CN/api-reference.md b/docs/zh-CN/api-reference.md index 3099edf7..6f9d3320 100644 --- a/docs/zh-CN/api-reference.md +++ b/docs/zh-CN/api-reference.md @@ -57,11 +57,15 @@ import { assembleVegaLite, assembleECharts, assembleChartjs, + assemblePlotly, + assembleExcel, } from 'flint-chart'; const vlSpec = assembleVegaLite(input); const ecSpec = assembleECharts(input); const cjsSpec = assembleChartjs(input); +const plFig = assemblePlotly(input); +const xlSpec = assembleExcel(input); ``` | 导出 | 返回 | @@ -69,8 +73,32 @@ const cjsSpec = assembleChartjs(input); | `assembleVegaLite` | Vega-Lite JSON spec | | `assembleECharts` | ECharts `option` object | | `assembleChartjs` | Chart.js configuration | +| `assemblePlotly` | Plotly.js `{ data, layout }` figure | +| `assembleExcel` | 供 Office.js 使用的原生 Excel 图表工件 | -若某后端不支持某 `chartType`,assembler 会在渲染前抛出。可用 `vlGetTemplateDef`、`ecGetTemplateDef` 或 `cjsGetTemplateDef` 检查支持情况。 +若某后端不支持某 `chartType`,assembler 会在渲染前抛出。可用 `vlGetTemplateDef`、`ecGetTemplateDef`、`cjsGetTemplateDef`、`plGetTemplateDef` 或 `excelGetTemplateDef` 检查支持情况。 + +## Excel 运行时与代码生成 + +`assembleExcel` 返回可序列化的 `flint.excel.chart/v1` 工件。可在 Office.js Excel 宿主中渲染它,或生成独立的 Office.js 源码: + +```ts +import { assembleExcel, generateOfficeJs, renderExcelChart } from 'flint-chart'; + +const artifact = assembleExcel(input); +const { pngBase64, inspection } = await renderExcelChart(Excel, artifact, { + scale: 3, + cleanWorksheet: true, + inspectNativeChart: false, +}); +const { code, meta } = generateOfficeJs(artifact, { + scale: 3, + cleanWorksheet: true, + functionName: 'renderFlintChart', +}); +``` + +`renderExcelChart` 需要包含 `run` 和 `ImageFittingMode.fit` 的 Excel API 对象。它会在活动工作表中创建原生图表,并返回 PNG 捕获结果及可选的检查数据。`generateOfficeJs` 不执行 Excel;它返回可移植源码以及生成的数据区域和图表元数据。 --- @@ -151,9 +179,17 @@ interface AssembleOptions { maxColorValues?: number; // color cardinality before truncation (default 24) stepPadding?: number; // band inner padding fraction (default 0.1) defaultBandSize?: number; // baseline px per category (backend-tuned) + maxBandSize?: number; // max px per category when sparse (backend-tuned) + baseLabelFontSize?: number; // axis tick font at the reference canvas (VL 10, EC/CJS/Plotly 12) + baseTitleFontSize?: number; // header font — axis title / legend / chart title (VL 11, EC/CJS 12, Plotly 14) } ``` +字体会围绕这些各后端基准值随画布尺寸自适应:默认画布下每个后端渲染其原生字号, +在更大画布上略微增大(最多 base + 4),在小型分面子图中缩小;坐标轴刻度标签还会 +缩小/旋转/截断以避免重叠。设置 `baseLabelFontSize` / `baseTitleFontSize` 可整体 +放大或缩小全部文字。 + 完整列表:`packages/flint-js/src/core/types.ts`(`AssembleOptions`)。行为见[自动布局算法](/documentation/layout-model)。 --- diff --git a/docs/zh-CN/overview.md b/docs/zh-CN/overview.md index f221d4dd..93ddb497 100644 --- a/docs/zh-CN/overview.md +++ b/docs/zh-CN/overview.md @@ -1,6 +1,6 @@ # 概览 -**Flint** 是一种可视化中间语言。你只需说明每个字段的*含义*和想要的图表;编译器会自动设置比例尺、坐标轴、聚合、格式、布局和颜色,再生成 Vega-Lite、ECharts 或 Chart.js 配置。 +**Flint** 是一种可视化中间语言。你只需说明每个字段的*含义*和想要的图表;编译器会自动设置比例尺、坐标轴、聚合、格式、布局和颜色,再生成 Vega-Lite、ECharts、Chart.js、Plotly 配置或原生 Excel 图表工件。 如果你是 Flint 新手,请从[入门指南](/documentation/getting-started)开始,然后再回到这里了解架构与 API 地图。 @@ -135,7 +135,7 @@ data + semantic_types + chart_spec → assemble*() → 后端配置 | 章节 | 页面 | |---------|-------| | **语言设计** | [架构](/documentation/architecture)、[语义类型](/documentation/semantic-types)、[自动布局算法](/documentation/layout-model)、[API 参考](/documentation/api-reference) | -| **图表参考** | [Vega-Lite 图表](/documentation/reference-vegalite)、[ECharts 图表](/documentation/reference-echarts)、[Chart.js 图表](/documentation/reference-chartjs) | +| **图表参考** | [Vega-Lite 图表](/documentation/reference-vegalite)、[ECharts 图表](/documentation/reference-echarts)、[Chart.js 图表](/documentation/reference-chartjs)、[Plotly 图表](/documentation/reference-plotly)、[Excel 图表](/documentation/reference-excel) | | **开发** | [开发指南](/documentation/development)、[扩展语义类型](/documentation/adding-a-semantic-type)、[扩展后端](/documentation/adding-a-backend)、[扩展图表模板](/documentation/adding-a-chart-template) | --- diff --git a/docs/zh-CN/reference-excel.md b/docs/zh-CN/reference-excel.md new file mode 100644 index 00000000..c8b95095 --- /dev/null +++ b/docs/zh-CN/reference-excel.md @@ -0,0 +1,53 @@ +# Excel 图表参考 + +> 本页由实时 Excel 图表模板注册表生成(`scripts/gen-chart-reference.ts`)。请勿手动编辑;请运行 `npm run gen:reference`。 + +Excel 后端把 Flint 规范编译为带版本的原生图表工件,再由 Office.js 在 Excel 工作簿中创建可编辑图表。 + +## 支持的图表 + +当前支持 18 种图表。请在 `chart_spec.chartType` 中使用下表所示的精确名称。 + +| Flint 图表类型 | 编码通道 | 原生 `Excel.ChartType` | +|---|---|---| +| Bar Chart | `x`, `y`, `color` | `ColumnClustered` / `BarClustered` | +| Grouped Bar Chart | `x`, `y`, `group` | `ColumnClustered` / `BarClustered` | +| Stacked Bar Chart | `x`, `y`, `color` | `ColumnStacked` / `BarStacked` | +| Pyramid Chart | `x`, `y`, `color` | `BarStacked` | +| Line Chart | `x`, `y`, `color`, `strokeDash` | `Line` | +| Area Chart | `x`, `y`, `color` | `Area` | +| Scatter Plot | `x`, `y`, `color`, `size` | `XYScatter` | +| Connected Scatter Plot | `x`, `y`, `order`, `color`, `detail` | `XYScatterLines` | +| Pie Chart | `color`, `size`, `theta` | `Pie` | +| Donut Chart | `color`, `size`, `theta` | `Doughnut` | +| Histogram | `x`, `color` | `ColumnClustered` | +| Boxplot | `x`, `y`, `color` | `BoxWhisker` | +| Candlestick Chart | `x`, `open`, `high`, `low`, `close` | `StockOHLC` | +| Waterfall Chart | `x`, `y`, `color` | `Waterfall` | +| Radar Chart | `x`, `y`, `color` | `RadarMarkers` | +| Funnel Chart | `y`, `size` | `Funnel` | +| Treemap | `color`, `size`, `detail` | `Treemap` | +| Sunburst Chart | `color`, `size`, `group`, `detail` | `Sunburst` | + +## 编译与渲染 + +`assembleExcel(input)` 返回一个 `flint.excel.chart/v1` 工件。它描述工作表数据矩阵、原生图表类型、系列绑定、坐标轴、图例、标签及格式,但不会自行打开 Excel。 + +```ts +import { assembleExcel, renderExcelChart } from 'flint-chart'; + +const artifact = assembleExcel(input); +const result = await renderExcelChart(Excel, artifact); +``` + +`renderExcelChart` 必须在提供 Office.js `Excel.run` 和 `Excel.ImageFittingMode.fit` 的 Excel 宿主中运行。它会在活动工作表中创建原生图表,并返回由 `Chart.getImage()` 捕获的 PNG。 + +若需要可移植的 Office.js 源码而不是立即执行,可调用 `generateOfficeJs(artifact)`。 + +## 限制 + +- 一个原生 Excel 图表不支持 Flint 的 `column` 或 `row` 分面。 +- 没有原生 Excel 对应类型的图表(例如 Heatmap)会在渲染前被拒绝。 +- 部分图表有更严格的数据要求;例如散点图要求定量 `x` 和 `y`,蜡烛图要求 `open`、`high`、`low`、`close` 通道。Assembler 会返回具体的验证错误。 + +可使用 `excelGetTemplateDef(chartType)` 或 `excelGetTemplateChannels(chartType)` 在编译前检查支持情况。 diff --git a/docs/zh-CN/reference-plotly.md b/docs/zh-CN/reference-plotly.md new file mode 100644 index 00000000..c5313b39 --- /dev/null +++ b/docs/zh-CN/reference-plotly.md @@ -0,0 +1,344 @@ +# Plotly 图表参考 + +> 本页由实时图表模板注册表生成(`scripts/gen-chart-reference.ts`)。请勿手动编辑;请运行 `npm run gen:reference`。 + +Plotly 后端编译为 Plotly.js `{ data, layout }` 图形,并优先使用原生 trace 类型。地图使用 Plotly 内置地理图集,无需外部 TopoJSON。 + +## 本页内容 + +本参考列出 Plotly 后端当前支持的 38 种图表,分为 8 类。图表名称必须与 `chart_spec.chartType` 中的值完全一致。 + +- **编码通道**:`chart_spec.encodings` 接受的视觉角色。 +- **选项**:模板专用的 `chart_spec.chartProperties` 键及其取值范围、默认值和可用性。 + +## 设置编码与选项 + +```jsonc +{ + "chartType": "Bar Chart", + "encodings": { "x": { "field": "category" }, "y": { "field": "value" } }, + "chartProperties": { "cornerRadius": 4, "stackMode": "normalize" } +} +``` + +可用性为 `conditional` 的参数仅在数据和编码适用时生效;不适用的参数会被 assembler 忽略。 + +## 散点与点图 + +### ![](chart-icon-scatter.svg) Scatter Plot + +**编码通道:** `x`, `y`, `color`, `size`, `opacity`, `column`, `row` + +| 参数 | 控件 | 取值范围 | 默认值 | 可用性 | 说明 | +|---|---|---|---|---|---| +| `opacity` | number | 0.1 – 1 (step 0.05) | `1` | always | 标记不透明度。 | + +### ![](chart-icon-linear-regression.svg) Regression + +**编码通道:** `x`, `y`, `size`, `color`, `column`, `row` + +| 参数 | 控件 | 取值范围 | 默认值 | 可用性 | 说明 | +|---|---|---|---|---|---| +| `regressionMethod` | choice | `linear` (Linear), `log` (Logarithmic), `exp` (Exponential), `pow` (Power), `quad` (Quadratic), `poly` (Polynomial) | `linear` | always | 回归拟合方法。 | +| `polyOrder` | number | 2 – 10 (step 1) | `3` | always | 多项式回归阶数。 | +| `opacity` | number | 0.1 – 1 (step 0.05) | `1` | always | 标记不透明度。 | + +### ![](chart-icon-connected-scatter.svg) Connected Scatter Plot + +**编码通道:** `x`, `y`, `order`, `color`, `detail`, `column`, `row` + +_无模板专用参数。_ + +### ![](chart-icon-dot-plot-horizontal.svg) Ranged Dot Plot + +**编码通道:** `x`, `y`, `color` + +_无模板专用参数。_ + +### ![](chart-icon-strip-plot.svg) Strip Plot + +**编码通道:** `x`, `y`, `color`, `size`, `column`, `row` + +_无模板专用参数。_ + +## 条形图 + +### ![](chart-icon-column.svg) Bar Chart + +**编码通道:** `x`, `y`, `color`, `opacity`, `column`, `row` + +| 参数 | 控件 | 取值范围 | 默认值 | 可用性 | 说明 | +|---|---|---|---|---|---| +| `cornerRadius` | number | 0 – 15 (step 1) | `0` | always | 受支持标记的圆角半径。 | + +### ![](chart-icon-column-grouped.svg) Grouped Bar Chart + +**编码通道:** `x`, `y`, `group`, `color`, `column`, `row` + +_无模板专用参数。_ + +### ![](chart-icon-column-stacked.svg) Stacked Bar Chart + +**编码通道:** `x`, `y`, `color`, `column`, `row` + +| 参数 | 控件 | 取值范围 | 默认值 | 可用性 | 说明 | +|---|---|---|---|---|---| +| `stackMode` | choice | Stacked (default) _(default)_, `normalize` (Normalize (100%)) | — | conditional | 重叠系列的堆叠策略。 | + +### ![](chart-icon-lollipop.svg) Lollipop Chart + +**编码通道:** `x`, `y`, `color`, `column`, `row` + +| 参数 | 控件 | 取值范围 | 默认值 | 可用性 | 说明 | +|---|---|---|---|---|---| +| `dotSize` | number | 20 – 300 (step 10) | `80` | always | 点标记大小。 | + +### ![](chart-icon-waterfall.svg) Waterfall Chart + +**编码通道:** `x`, `y`, `color`, `column`, `row` + +| 参数 | 控件 | 取值范围 | 默认值 | 可用性 | 说明 | +|---|---|---|---|---|---| +| `totals` | choice | `auto` (Auto), `none` (None), `first` (First only), `last` (Last only), `both` (First and last) | `auto` | always | 瀑布图总计标记。 | +| `showTextLabels` | toggle | on / off | `false` | always | 在标记上显示数值标签。 | + +### ![](chart-icon-pyramid.svg) Pyramid Chart + +**编码通道:** `x`, `y`, `color` + +_无模板专用参数。_ + +## 分布图 + +### ![](chart-icon-histogram.svg) Histogram + +**编码通道:** `x`, `color`, `column`, `row` + +| 参数 | 控件 | 取值范围 | 默认值 | 可用性 | 说明 | +|---|---|---|---|---|---| +| `binCount` | number | 5 – 50 (step 1) | `10` | always | 最大分箱数。 | + +### ![](chart-icon-box-plot.svg) Boxplot + +**编码通道:** `x`, `y`, `color`, `column`, `row` + +| 参数 | 控件 | 取值范围 | 默认值 | 可用性 | 说明 | +|---|---|---|---|---|---| +| `showOutliers` | toggle | on / off | `true` | always | 显示离群点。 | + +### ![](chart-icon-violin.svg) Violin Plot + +**编码通道:** `x`, `y`, `color`, `column`, `row` + +| 参数 | 控件 | 取值范围 | 默认值 | 可用性 | 说明 | +|---|---|---|---|---|---| +| `showBox` | toggle | on / off | `true` | always | 显示内部箱体。 | +| `showPoints` | toggle | on / off | `false` | always | 在线上叠加点标记。 | + +### ![](chart-icon-density.svg) Density Plot + +**编码通道:** `x`, `color`, `column`, `row` + +| 参数 | 控件 | 取值范围 | 默认值 | 可用性 | 说明 | +|---|---|---|---|---|---| +| `bandwidth` | number | 0.05 – 2 (step 0.05) | `0` | always | 核密度带宽,0 表示自动。 | + +### ![](chart-icon-ecdf.svg) ECDF Plot + +**编码通道:** `x`, `color`, `detail`, `column`, `row` + +| 参数 | 控件 | 取值范围 | 默认值 | 可用性 | 说明 | +|---|---|---|---|---|---| +| `showPoints` | toggle | on / off | `false` | always | 在线上叠加点标记。 | + +### ![](chart-icon-candlestick.svg) Candlestick Chart + +**编码通道:** `x`, `open`, `high`, `low`, `close`, `column`, `row` + +| 参数 | 控件 | 取值范围 | 默认值 | 可用性 | 说明 | +|---|---|---|---|---|---| +| `showMA` | toggle | on / off | `false` | always | 显示移动平均线。 | +| `maWindow` | number | 3 – 30 (step 1) | `5` | always | 移动平均窗口大小。 | + +### Density Contour + +**编码通道:** `x`, `y`, `column`, `row` + +| 参数 | 控件 | 取值范围 | 默认值 | 可用性 | 说明 | +|---|---|---|---|---|---| +| `binCount` | number | 5 – 50 (step 1) | `20` | always | 最大分箱数。 | +| `showPoints` | toggle | on / off | `true` | always | 在线上叠加点标记。 | + +## 折线与区域图 + +### ![](chart-icon-line.svg) Line Chart + +**编码通道:** `x`, `y`, `color`, `opacity`, `column`, `row` + +| 参数 | 控件 | 取值范围 | 默认值 | 可用性 | 说明 | +|---|---|---|---|---|---| +| `interpolate` | choice | Default (linear) _(default)_, `linear` (Linear), `monotone` (Monotone (smooth)), `step` (Step), `step-before` (Step Before), `step-after` (Step After) | — | always | 线或区域的插值方式。 | +| `showPoints` | toggle | on / off | `false` | always | 在线上叠加点标记。 | + +### ![](chart-icon-area.svg) Area Chart + +**编码通道:** `x`, `y`, `color`, `opacity`, `column`, `row` + +| 参数 | 控件 | 取值范围 | 默认值 | 可用性 | 说明 | +|---|---|---|---|---|---| +| `interpolate` | choice | Default (linear) _(default)_, `linear` (Linear), `monotone` (Monotone (smooth)) | — | always | 线或区域的插值方式。 | +| `opacity` | number | 0.1 – 1 (step 0.05) | `0.4` | always | 标记不透明度。 | +| `stackMode` | choice | Stacked (default) _(default)_, `normalize` (Normalize (100%)), `layered` (Layered (overlap)) | — | conditional | 重叠系列的堆叠策略。 | + +### ![](chart-icon-bump.svg) Bump Chart + +**编码通道:** `x`, `y`, `color`, `detail`, `column`, `row` + +_无模板专用参数。_ + +### ![](chart-icon-slope.svg) Slope Chart + +**编码通道:** `x`, `y`, `color`, `detail`, `column`, `row` + +_无模板专用参数。_ + +### ![](chart-icon-streamgraph.svg) Streamgraph + +**编码通道:** `x`, `y`, `color`, `column`, `row` + +_无模板专用参数。_ + +### ![](chart-icon-range-area.svg) Range Area Chart + +**编码通道:** `x`, `y`, `y2`, `color`, `column`, `row` + +| 参数 | 控件 | 取值范围 | 默认值 | 可用性 | 说明 | +|---|---|---|---|---|---| +| `opacity` | number | 0.1 – 1 (step 0.05) | `0.35` | always | 标记不透明度。 | + +## 圆形图 + +### ![](chart-icon-pie.svg) Pie Chart + +**编码通道:** `size`, `color` + +| 参数 | 控件 | 取值范围 | 默认值 | 可用性 | 说明 | +|---|---|---|---|---|---| +| `sortSlices` | choice | `none` (Data order), `descending` (Largest first), `ascending` (Smallest first) | `none` | always | 扇区排序方式。 | +| `labelType` | choice | `categoryPercent` (Name + %), `category` (Name), `value` (Value), `percent` (Percent), `none` (None) | `categoryPercent` | always | 标签内容。 | + +### ![](chart-icon-doughnut.svg) Donut Chart + +**编码通道:** `size`, `color` + +| 参数 | 控件 | 取值范围 | 默认值 | 可用性 | 说明 | +|---|---|---|---|---|---| +| `innerRadius` | number | 20 – 80 (step 5) | `55` | always | 内半径占外半径的百分比。 | +| `sortSlices` | choice | `none` (Data order), `descending` (Largest first), `ascending` (Smallest first) | `none` | always | 扇区排序方式。 | +| `labelType` | choice | `categoryPercent` (Name + %), `category` (Name), `value` (Value), `percent` (Percent), `none` (None) | `categoryPercent` | always | 标签内容。 | + +### ![](chart-icon-radar.svg) Radar Chart + +**编码通道:** `x`, `y`, `color`, `column`, `row` + +| 参数 | 控件 | 取值范围 | 默认值 | 可用性 | 说明 | +|---|---|---|---|---|---| +| `filled` | choice | `true` (Filled (default)), `false` (Outline only) | — | always | 填充雷达图围成的区域。 | +| `fillOpacity` | number | 0.05 – 0.8 (step 0.05) | `0.3` | always | 区域填充不透明度。 | + +### ![](chart-icon-rose.svg) Rose Chart + +**编码通道:** `x`, `y`, `color` + +| 参数 | 控件 | 取值范围 | 默认值 | 可用性 | 说明 | +|---|---|---|---|---|---| +| `sortSlices` | choice | `none` (Data order), `descending` (Largest first), `ascending` (Smallest first) | `none` | always | 扇区排序方式。 | + +## 表格与 KPI + +### ![](chart-icon-heat-map.svg) Heatmap + +**编码通道:** `x`, `y`, `color`, `column`, `row` + +_无模板专用参数。_ + +### ![](chart-icon-gantt.svg) Gantt Chart + +**编码通道:** `y`, `x`, `x2`, `color`, `detail`, `column`, `row` + +| 参数 | 控件 | 取值范围 | 默认值 | 可用性 | 说明 | +|---|---|---|---|---|---| +| `taskHeight` | number | 40 – 90 (step 5) | `70` | always | 任务条占每行高度的百分比。 | +| `cornerRadius` | number | 0 – 8 (step 1) | `2` | always | 受支持标记的圆角半径。 | +| `intervalLabels` | toggle | on / off | `false` | always | 在任务区间上显示文本。 | + +### ![](chart-icon-bullet.svg) Bullet Chart + +**编码通道:** `y`, `x`, `goal`, `color`, `column`, `row` + +_无模板专用参数。_ + +### ![](chart-icon-kpi-card.svg) KPI Card + +**编码通道:** `metric`, `value`, `goal` + +| 参数 | 控件 | 取值范围 | 默认值 | 可用性 | 说明 | +|---|---|---|---|---|---| +| `layout` | choice | `horizontal` (Horizontal (default)), `vertical` (Vertical), `grid` (Grid) | — | always | 布局方向。 | + +### Sparkline + +**编码通道:** `x`, `y`, `color`, `detail` + +| 参数 | 控件 | 取值范围 | 默认值 | 可用性 | 说明 | +|---|---|---|---|---|---| +| `baseline` | choice | `mean` (Average), `zero` (Zero), `median` (Median), `none` (None) | `mean` | always | 参考基线。 | +| `trendWidth` | number | 80 – 600 (step 10) | `240` | always | 迷你趋势图宽度。 | + +### ![](chart-icon-bar-table.svg) Bar Table + +**编码通道:** `y`, `x`, `color`, `column`, `row` + +| 参数 | 控件 | 取值范围 | 默认值 | 可用性 | 说明 | +|---|---|---|---|---|---| +| `maxRows` | number | 5 – 100 (step 1) | `20` | always | 最多显示的表格行数。 | +| `showPercent` | toggle | on / off | `false` | conditional | 将数值显示为总量百分比。 | + +## 地图 + +### ![](chart-icon-world-map.svg) Map + +**编码通道:** `longitude`, `latitude`, `color`, `size`, `opacity` + +| 参数 | 控件 | 取值范围 | 默认值 | 可用性 | 说明 | +|---|---|---|---|---|---| +| `region` | choice | `auto` (Auto-detect), `us` (United States), `world` (World) | `auto` | always | 地图区域。 | +| `projection` | choice | `default` (Default), `mercator` (Mercator), `equalEarth` (Equal Earth), `orthographic` (Orthographic (Globe)), `stereographic` (Stereographic), `conicEqualArea` (Conic Equal Area), `conicEquidistant` (Conic Equidistant), `azimuthalEquidistant` (Azimuthal Equidistant), `mollweide` (Mollweide) | `default` | conditional | 地图投影。 | +| `projectionCenter` | choice | Default _(default)_, `0,0` (World (Atlantic) [0, 0]), `150,0` (World (Pacific) [150, 0]), `105,35` (China [105, 35]), `-98,39` (USA [-98, 39]), `10,50` (Europe [10, 50]), `138,36` (Japan [138, 36]), `78,22` (India [78, 22]), `-52,-14` (Brazil [-52, -14]), `134,-25` (Australia [134, -25]), `100,60` (Russia [100, 60]), `20,0` (Africa [20, 0]), `45,28` (Middle East [45, 28]), `115,5` (Southeast Asia [115, 5]), `-60,-15` (South America [-60, -15]), `-100,45` (North America [-100, 45]), `-2,54` (UK [-2, 54]), `10,51` (Germany [10, 51]), `2,47` (France [2, 47]), `128,36` (Korea [128, 36]) | — | conditional | 地图投影中心。 | + +### ![](chart-icon-us-map.svg) Choropleth + +**编码通道:** `id`, `color`, `detail` + +| 参数 | 控件 | 取值范围 | 默认值 | 可用性 | 说明 | +|---|---|---|---|---|---| +| `region` | choice | `auto` (Auto-detect), `us` (United States), `world` (World) | `auto` | always | 地图区域。 | + +## Plotly 特有图表 + +### ![](chart-icon-funnel.svg) Funnel Chart + +**编码通道:** `y`, `size` + +| 参数 | 控件 | 取值范围 | 默认值 | 可用性 | 说明 | +|---|---|---|---|---|---| +| `sort` | choice | `descending` (Descending (default)), `ascending` (Ascending), `none` (Original order) | `descending` | always | 有序阶段或类别的排序方式。 | + +### ![](chart-icon-gauge.svg) Gauge Chart + +**编码通道:** `size`, `column` + +| 参数 | 控件 | 取值范围 | 默认值 | 可用性 | 说明 | +|---|---|---|---|---|---| +| `min` | number | 0 – 1000 (step 10) | `0` | always | 最小值。 | +| `max` | number | 0 – 10000 (step 100) | `100` | always | 最大值。 | diff --git a/docs/zh-CN/tutorials/agent-workflows.md b/docs/zh-CN/tutorials/agent-workflows.md index 5f071ef5..d9e0889e 100644 --- a/docs/zh-CN/tutorials/agent-workflows.md +++ b/docs/zh-CN/tutorials/agent-workflows.md @@ -321,6 +321,7 @@ execute the code, inspect the derived table, and bind data.values afterward. - [示例:数据故事](/documentation/data-story) 展示同一份源数据视图如何仅通过更改 ChartSpec 变成多种图表设计。 - [配置 Flint MCP](/documentation/setup-flint-mcp) 说明如何通过 MCP 服务器为智能体提供 Flint 图表工具。 - [Vega-Lite charts](/documentation/reference-vegalite)、 - [ECharts charts](/documentation/reference-echarts) 与 - [Chart.js charts](/documentation/reference-chartjs) 按后端列出支持的图表类型。 + [ECharts charts](/documentation/reference-echarts)、 + [Chart.js charts](/documentation/reference-chartjs) 与 + [Plotly charts](/documentation/reference-plotly) 按后端列出支持的图表类型。 - [语义类型](/documentation/semantic-types) 列出智能体可用于字段的标签。 diff --git a/docs/zh-CN/tutorials/chart-sizing.md b/docs/zh-CN/tutorials/chart-sizing.md index b3405f68..d3d49208 100644 --- a/docs/zh-CN/tutorials/chart-sizing.md +++ b/docs/zh-CN/tutorials/chart-sizing.md @@ -102,4 +102,26 @@ area } ``` +## 字体大小 + +文字(坐标轴刻度标签、轴标题、图例、图表标题)会围绕各后端的原生字号随画布自适应, +因此小图不会拥挤、大图也不会过小。要整体放大或缩小文字,可在 `options` 中设置两个基准字号: + +```json +{ + "chart_spec": { + "chartType": "Bar Chart", + "encodings": { "x": { "field": "category" }, "y": { "field": "value" } } + }, + "options": { + "baseLabelFontSize": 14, + "baseTitleFontSize": 16 + } +} +``` + +`baseLabelFontSize` 设置坐标轴刻度字号;`baseTitleFontSize` 设置标题类字号(轴标题、图例、 +图表标题)。默认取各后端原生字号(Vega-Lite 10 / 11;ECharts 与 Chart.js 12 / 12;Plotly 12 / 14)。 +密集坐标轴仍会在此基准上缩小、旋转并截断刻度标签以避免重叠。 + 要了解多面板布局和这些控件背后的模型,请继续阅读[自动布局算法](/documentation/layout-model)。 diff --git a/docs/zh-CN/tutorials/getting-started.md b/docs/zh-CN/tutorials/getting-started.md index cf03cb7e..65c1b043 100644 --- a/docs/zh-CN/tutorials/getting-started.md +++ b/docs/zh-CN/tutorials/getting-started.md @@ -1,6 +1,6 @@ # 入门指南 -Flint 的思路很简单:先描述**数据代表什么**,再说明**你想要什么图表**。Flint 会据此生成 Vega-Lite、ECharts 或 Chart.js 可以直接使用的规范。 +Flint 的思路很简单:先描述**数据代表什么**,再说明**你想要什么图表**。Flint 会据此生成 Vega-Lite、ECharts、Chart.js 或 Plotly 可以直接使用的规范,也可为 Office.js 宿主生成原生 Excel 图表工件。 本页只介绍最基本的流程:安装 Flint、阅读一份完整规范,再将它编译成图表。 @@ -132,12 +132,16 @@ await embed('#chart', spec); 同一份 Flint 输入也可以编译为其他后端的配置: ```ts -import { assembleChartjs, assembleECharts } from 'flint-chart'; +import { assembleChartjs, assembleECharts, assembleExcel, assemblePlotly } from 'flint-chart'; const chartjsConfig = assembleChartjs(input); const echartsOption = assembleECharts(input); +const plotlyFigure = assemblePlotly(input); +const excelArtifact = assembleExcel(input); ``` +Plotly 返回 `{ data, layout }` 图形。Excel 返回带版本的原生图表工件,Office.js 宿主可将其传给 `renderExcelChart`。 + Python 支持将使用相同的输入结构,计划在后续版本发布。 ## 接下来读什么 @@ -146,5 +150,5 @@ Python 支持将使用相同的输入结构,计划在后续版本发布。 - [配置 Flint MCP](/documentation/setup-flint-mcp):在聊天工具或 IDE 中连接 Flint MCP。 - [智能体工作流](/documentation/agent-workflows):将 Flint 集成到自己的智能体产品中。 - [语义类型](/documentation/semantic-types):了解 `YearMonth`、`Quantity`、`Category` 和 `Profit` 等语义标签。 -- [图表示例](/gallery):浏览 Vega-Lite、ECharts 和 Chart.js 支持的图表模板。 +- [图表示例](/gallery):浏览 Vega-Lite、ECharts、Chart.js 和 Plotly 支持的图表模板;[Excel 图表示例](/gallery/excel)展示在 Excel 中捕获的原生可编辑图表。 - [概览](/documentation/overview):进一步了解 Flint 的整体设计和架构。 diff --git a/docs/zh-CN/tutorials/setup-flint-mcp.md b/docs/zh-CN/tutorials/setup-flint-mcp.md index 48d31abb..9ec4eebe 100644 --- a/docs/zh-CN/tutorials/setup-flint-mcp.md +++ b/docs/zh-CN/tutorials/setup-flint-mcp.md @@ -45,6 +45,16 @@ npx -y flint-chart-mcp 该命令会启动 stdio MCP 服务器。通常只需把它写入 MCP 客户端配置,无需手动运行。 +## 使用托管服务器 + +如果客户端仅支持远程 HTTP MCP 服务器,可连接 Flint 公共端点: + +```text +https://flint.data-formulator.ai/mcp +``` + +客户端支持本地 stdio 时建议优先使用本地服务器,尤其是需要读取本地图表数据文件时。托管服务器接受直接嵌入工具调用的数据。 + ## 配置 VS Code 在 VS Code 中,于 `.vscode/mcp.json` 添加服务器条目: @@ -194,5 +204,6 @@ Open it with create_chart_view if this client supports MCP Apps; otherwise rende - [智能体工作流](/documentation/agent-workflows) 说明如何将 Flint 的语义图表契约嵌入自定义智能体或智能体产品。 - [入门指南](/documentation/getting-started) 用一张小图解释 `DataSpec` 与 `ChartSpec` 的结构。 - [Vega-Lite 图表](/documentation/reference-vegalite)、 - [ECharts 图表](/documentation/reference-echarts) 和 - [Chart.js 图表](/documentation/reference-chartjs) 按后端列出支持的图表类型。 + [ECharts 图表](/documentation/reference-echarts)、 + [Chart.js 图表](/documentation/reference-chartjs) 和 + [Plotly 图表](/documentation/reference-plotly) 按后端列出支持的图表类型。 diff --git a/package-lock.json b/package-lock.json index 5ed9d821..65d5d1a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,12 @@ "packages/flint-mcp", "site" ], + "devDependencies": { + "@types/react": "^18.3.0", + "@types/react-dom": "^18.3.0", + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, "engines": { "node": ">=18" }, @@ -21,8 +27,8 @@ }, "node_modules/@babel/runtime": { "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", - "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha1-EgIkUMRaTabY2Ch7GKT/Ldsj92g=", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -30,8 +36,8 @@ }, "node_modules/@codemirror/autocomplete": { "version": "6.20.3", - "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.20.3.tgz", - "integrity": "sha512-tlosUqb+3BbxCxZdu4tKeRghPFC+QM7q4X5YhKV2eCmPG+1r2F3f4AaSz5sCrFqUtX4Jh20VFTKecl16MgiV9g==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@codemirror/autocomplete/-/autocomplete-6.20.3.tgz", + "integrity": "sha1-aWt0AxLGqWLhRWe0mjZhtZJLxa4=", "license": "MIT", "dependencies": { "@codemirror/language": "^6.0.0", @@ -42,8 +48,8 @@ }, "node_modules/@codemirror/commands": { "version": "6.10.4", - "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.10.4.tgz", - "integrity": "sha512-Ryk9y9T0FFVF0cUGhAknveAyUOl/A1qReTFi+qPKtOh2Z9F4AUBz3XOrYD4ZEgZirdugVzHvd/2/Wcwy5OliTg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@codemirror/commands/-/commands-6.10.4.tgz", + "integrity": "sha1-ZN7BvQQ5dus0TjzJ0VrxO29yS/0=", "license": "MIT", "dependencies": { "@codemirror/language": "^6.0.0", @@ -54,8 +60,8 @@ }, "node_modules/@codemirror/lang-json": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.2.tgz", - "integrity": "sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@codemirror/lang-json/-/lang-json-6.0.2.tgz", + "integrity": "sha1-BUsWBnEwZmfiXYA4UoYEmEGDYXk=", "license": "MIT", "dependencies": { "@codemirror/language": "^6.0.0", @@ -63,9 +69,9 @@ } }, "node_modules/@codemirror/language": { - "version": "6.12.3", - "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.12.3.tgz", - "integrity": "sha512-QwCZW6Tt1siP37Jet9Tb02Zs81TQt6qQrZR2H+eGMcFsL1zMrk2/b9CLC7/9ieP1fjIUMgviLWMmgiHoJrj+ZA==", + "version": "6.12.4", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@codemirror/language/-/language-6.12.4.tgz", + "integrity": "sha1-AecP1ao6igZ/8d/sddW2OUzfoFg=", "license": "MIT", "dependencies": { "@codemirror/state": "^6.0.0", @@ -78,8 +84,8 @@ }, "node_modules/@codemirror/lint": { "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.9.7.tgz", - "integrity": "sha512-28/+iWLYxKxsvGYhSYL7zaCZqLz5+FFFDq9tVsvGv9kv8RY4fFAchJ5WX9M3YrrRlTIsECjsXPqeNgnSmNP2dg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@codemirror/lint/-/lint-6.9.7.tgz", + "integrity": "sha1-hB/HM2dDidkf5JocNAJ607q98QU=", "license": "MIT", "dependencies": { "@codemirror/state": "^6.0.0", @@ -89,8 +95,8 @@ }, "node_modules/@codemirror/search": { "version": "6.7.1", - "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.7.1.tgz", - "integrity": "sha512-uMe5UO6PamJtSHrXhhHOzSX3ReWtiJrva6GnPMwSOrZtiExb5X5eExhr2OUZQVvdxPsKpY3Ro2mFbQadpPWmHA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@codemirror/search/-/search-6.7.1.tgz", + "integrity": "sha1-JSOnYocdGK2YLtwtSy+h2kg7A5I=", "license": "MIT", "dependencies": { "@codemirror/state": "^6.0.0", @@ -99,9 +105,9 @@ } }, "node_modules/@codemirror/state": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.7.0.tgz", - "integrity": "sha512-Zbl9NyscLMZkfXPQnNAIIAFftidrA1UbcJEIMp24C0Bukc2I5T8wJS0wsXYsnDOqCFJUeJ1BITGNs5CqPDSmSg==", + "version": "6.7.1", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@codemirror/state/-/state-6.7.1.tgz", + "integrity": "sha1-noihdEjB28e1Csvu7Jee18zx1vw=", "license": "MIT", "dependencies": { "@marijn/find-cluster-break": "^1.0.0" @@ -109,8 +115,8 @@ }, "node_modules/@codemirror/theme-one-dark": { "version": "6.1.3", - "resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.3.tgz", - "integrity": "sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@codemirror/theme-one-dark/-/theme-one-dark-6.1.3.tgz", + "integrity": "sha1-Hbtz9uc8U8Eq0q7Z9IwmPE5j6jc=", "license": "MIT", "dependencies": { "@codemirror/language": "^6.0.0", @@ -120,9 +126,9 @@ } }, "node_modules/@codemirror/view": { - "version": "6.43.2", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.43.2.tgz", - "integrity": "sha512-8kU6WNRYBKV9Sw3cxNz+uSvUvx3tt+1qgupGFPubnbLFDHOgh5qQdIGmXcD7bkA/PROK6LDKVhKMpcY7H++Amg==", + "version": "6.43.6", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@codemirror/view/-/view-6.43.6.tgz", + "integrity": "sha1-geTusoVefLbGIwX7qN8xm1R2KAw=", "license": "MIT", "dependencies": { "@codemirror/state": "^6.7.0", @@ -133,8 +139,8 @@ }, "node_modules/@emnapi/core": { "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", - "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@emnapi/core/-/core-1.11.1.tgz", + "integrity": "sha1-ueEGTzprFjHiQeY460jXNr/TcqY=", "dev": true, "license": "MIT", "optional": true, @@ -145,16 +151,16 @@ }, "node_modules/@emnapi/core/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha1-YS7+TtI11Wfoq6Xypfq3AoCt6D8=", "dev": true, "license": "0BSD", "optional": true }, "node_modules/@emnapi/runtime": { "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", - "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha1-WPHz1dgamxL3k6tojJY3GQECfCQ=", "dev": true, "license": "MIT", "optional": true, @@ -164,16 +170,16 @@ }, "node_modules/@emnapi/runtime/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha1-YS7+TtI11Wfoq6Xypfq3AoCt6D8=", "dev": true, "license": "0BSD", "optional": true }, "node_modules/@emnapi/wasi-threads": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", - "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha1-TJO+z1v6OxPRu9zAau44MhrYE5o=", "dev": true, "license": "MIT", "optional": true, @@ -183,16 +189,16 @@ }, "node_modules/@emnapi/wasi-threads/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha1-YS7+TtI11Wfoq6Xypfq3AoCt6D8=", "dev": true, "license": "0BSD", "optional": true }, "node_modules/@esbuild/aix-ppc64": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", - "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha1-egGo0uwvuy2seK2tCbD6eB5Agr4=", "cpu": [ "ppc64" ], @@ -208,8 +214,8 @@ }, "node_modules/@esbuild/android-arm": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", - "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha1-cEvSl95tdi3lTqu+r79V9nVqvi8=", "cpu": [ "arm" ], @@ -225,8 +231,8 @@ }, "node_modules/@esbuild/android-arm64": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", - "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha1-tUCifRTkr9BYSWpNvsTT9BTbEQo=", "cpu": [ "arm64" ], @@ -242,8 +248,8 @@ }, "node_modules/@esbuild/android-x64": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", - "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha1-0csWbTSw+/D+irRgpVlPJKN4cB4=", "cpu": [ "x64" ], @@ -259,8 +265,8 @@ }, "node_modules/@esbuild/darwin-arm64": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", - "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha1-EDSyZFf8iGNo/mG70J9lP2r6jlQ=", "cpu": [ "arm64" ], @@ -276,8 +282,8 @@ }, "node_modules/@esbuild/darwin-x64": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", - "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha1-ZVVqQyoeTXIDLYIYwZMvzKGkl3I=", "cpu": [ "x64" ], @@ -293,8 +299,8 @@ }, "node_modules/@esbuild/freebsd-arm64": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", - "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha1-LmHgWS+QMNfj2uGO4l68U1kYrvY=", "cpu": [ "arm64" ], @@ -310,8 +316,8 @@ }, "node_modules/@esbuild/freebsd-x64": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", - "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha1-yV7CiZWe+AecTcqBeh4sS+Zrm9M=", "cpu": [ "x64" ], @@ -327,8 +333,8 @@ }, "node_modules/@esbuild/linux-arm": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", - "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha1-wJoPZ5F1kqwN6JKpvk04FN69Kmw=", "cpu": [ "arm" ], @@ -344,8 +350,8 @@ }, "node_modules/@esbuild/linux-arm64": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", - "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha1-QLIhdd2gYYLz7oFBGGxf8wTEpxc=", "cpu": [ "arm64" ], @@ -361,8 +367,8 @@ }, "node_modules/@esbuild/linux-ia32": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", - "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha1-pYD5xnZ5eDOJHlGfx6EzfIr9jbM=", "cpu": [ "ia32" ], @@ -378,8 +384,8 @@ }, "node_modules/@esbuild/linux-loong64": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", - "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha1-RkUs8yHcf56Rwvp4Cla7Vuec1os=", "cpu": [ "loong64" ], @@ -395,8 +401,8 @@ }, "node_modules/@esbuild/linux-mips64el": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", - "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha1-QhGzGE3WYI9T3LIuOfXTTuCIUsg=", "cpu": [ "mips64el" ], @@ -412,8 +418,8 @@ }, "node_modules/@esbuild/linux-ppc64": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", - "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha1-aXhXwqYcubC2u2ZS5AwdxeHKjl0=", "cpu": [ "ppc64" ], @@ -429,8 +435,8 @@ }, "node_modules/@esbuild/linux-riscv64": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", - "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha1-0ZKUPrFGpArExkl9DPe+NbmGvwg=", "cpu": [ "riscv64" ], @@ -446,8 +452,8 @@ }, "node_modules/@esbuild/linux-s390x": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", - "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha1-rOoDVtoODrwI+Xz3ucLkAeHmSNw=", "cpu": [ "s390x" ], @@ -463,8 +469,8 @@ }, "node_modules/@esbuild/linux-x64": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", - "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha1-bww84MtkxTS3DExF7LLBbTTjXf0=", "cpu": [ "x64" ], @@ -480,8 +486,8 @@ }, "node_modules/@esbuild/netbsd-arm64": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", - "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha1-i813B3oNzjN4tXT+2ybSolO3PTY=", "cpu": [ "arm64" ], @@ -497,8 +503,8 @@ }, "node_modules/@esbuild/netbsd-x64": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", - "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha1-5/sqAemcgwyU5mI82f77TI+1g0c=", "cpu": [ "x64" ], @@ -514,8 +520,8 @@ }, "node_modules/@esbuild/openbsd-arm64": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", - "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha1-xSkJNy24uG4sVeBaiUADO1Zgo7I=", "cpu": [ "arm64" ], @@ -531,8 +537,8 @@ }, "node_modules/@esbuild/openbsd-x64": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", - "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha1-xCe5vlpkwmL/mn63C1+7qt9EbGw=", "cpu": [ "x64" ], @@ -548,8 +554,8 @@ }, "node_modules/@esbuild/openharmony-arm64": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", - "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha1-3JsUe6yi5sSzyFVxdB70hgpIkJc=", "cpu": [ "arm64" ], @@ -565,8 +571,8 @@ }, "node_modules/@esbuild/sunos-x64": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", - "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha1-zoZtEt8TwV5MmfBzo9Rm9uBkmzo=", "cpu": [ "x64" ], @@ -582,8 +588,8 @@ }, "node_modules/@esbuild/win32-arm64": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", - "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha1-dGjjaS0B1inVlB5dg4F7uA+eObQ=", "cpu": [ "arm64" ], @@ -599,8 +605,8 @@ }, "node_modules/@esbuild/win32-ia32": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", - "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha1-pbwAY/sryrbQ7WPyoVN5WLwmnsY=", "cpu": [ "ia32" ], @@ -616,8 +622,8 @@ }, "node_modules/@esbuild/win32-x64": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", - "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha1-EAZO5E9DR7kMmgK0Rrv4CpFjKxI=", "cpu": [ "x64" ], @@ -633,8 +639,8 @@ }, "node_modules/@eslint-community/eslint-utils": { "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", - "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha1-TpCvZ7xR3e5s3vUoTt9XLsN2tZU=", "dev": true, "license": "MIT", "dependencies": { @@ -652,8 +658,8 @@ }, "node_modules/@eslint-community/regexpp": { "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha1-vM32Fbz3tujbgw7AuNIcmiXeWXs=", "dev": true, "license": "MIT", "engines": { @@ -662,8 +668,8 @@ }, "node_modules/@eslint/config-array": { "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", - "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha1-8p4iBXrVMWzyODbO6aNMgf/8t+Y=", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -677,15 +683,15 @@ }, "node_modules/@eslint/config-array/node_modules/balanced-match": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha1-6D46fj8wCzTLnYf2FfoMvzV2kO4=", "dev": true, "license": "MIT" }, "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", - "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "version": "1.1.16", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/brace-expansion/-/brace-expansion-1.1.16.tgz", + "integrity": "sha1-cj06MMBVjCJavJ/Eeac+FOJsPC8=", "dev": true, "license": "MIT", "dependencies": { @@ -695,8 +701,8 @@ }, "node_modules/@eslint/config-array/node_modules/minimatch": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha1-WAyI+NVEXyvWqo88re+g3nn71p4=", "dev": true, "license": "ISC", "dependencies": { @@ -708,8 +714,8 @@ }, "node_modules/@eslint/config-helpers": { "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", - "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha1-G9AGzut+LlWyt3OrMY0wDhpmrto=", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -721,8 +727,8 @@ }, "node_modules/@eslint/core": { "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", - "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha1-dyJYIEE9lhdQnak0IZCiAZ54dhw=", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -733,9 +739,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", - "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", + "version": "3.3.6", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@eslint/eslintrc/-/eslintrc-3.3.6.tgz", + "integrity": "sha1-0iv9azp9jh8sCy8ubeERtT7G4T4=", "dev": true, "license": "MIT", "dependencies": { @@ -745,7 +751,7 @@ "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^4.1.1", + "js-yaml": "^4.3.0", "minimatch": "^3.1.5", "strip-json-comments": "^3.1.1" }, @@ -758,8 +764,8 @@ }, "node_modules/@eslint/eslintrc/node_modules/ajv": { "version": "6.15.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", - "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha1-B+mCx0YmFnqnoklcU4F4ktcTlJI=", "dev": true, "license": "MIT", "dependencies": { @@ -775,15 +781,15 @@ }, "node_modules/@eslint/eslintrc/node_modules/balanced-match": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha1-6D46fj8wCzTLnYf2FfoMvzV2kO4=", "dev": true, "license": "MIT" }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", - "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "version": "1.1.16", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/brace-expansion/-/brace-expansion-1.1.16.tgz", + "integrity": "sha1-cj06MMBVjCJavJ/Eeac+FOJsPC8=", "dev": true, "license": "MIT", "dependencies": { @@ -793,8 +799,8 @@ }, "node_modules/@eslint/eslintrc/node_modules/ignore": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha1-PNQOcp82Q/2HywTlC/DrcivFlvU=", "dev": true, "license": "MIT", "engines": { @@ -803,15 +809,15 @@ }, "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=", "dev": true, "license": "MIT" }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha1-WAyI+NVEXyvWqo88re+g3nn71p4=", "dev": true, "license": "ISC", "dependencies": { @@ -822,9 +828,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.39.4", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", - "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", + "version": "9.39.5", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@eslint/js/-/js-9.39.5.tgz", + "integrity": "sha1-by+8/3VQDSKdU14KlJrhNHLIR4c=", "dev": true, "license": "MIT", "engines": { @@ -836,8 +842,8 @@ }, "node_modules/@eslint/object-schema": { "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", - "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha1-biEmoTR+hqTe34cG7Gf/jhB+u60=", "dev": true, "license": "Apache-2.0", "engines": { @@ -846,8 +852,8 @@ }, "node_modules/@eslint/plugin-kit": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", - "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha1-l3nj/Zt+4zVxpXQ1z0M1oXlKbLI=", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -860,20 +866,20 @@ }, "node_modules/@fontsource-variable/inter": { "version": "5.2.8", - "resolved": "https://registry.npmjs.org/@fontsource-variable/inter/-/inter-5.2.8.tgz", - "integrity": "sha512-kOfP2D+ykbcX/P3IFnokOhVRNoTozo5/JxhAIVYLpea/UBmCQ/YWPBfWIDuBImXX/15KH+eKh4xpEUyS2sQQGQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@fontsource-variable/inter/-/inter-5.2.8.tgz", + "integrity": "sha1-KbEUdvUUn2pEO032UW4mAC2HlBo=", "license": "OFL-1.1", "funding": { "url": "https://github.com/sponsors/ayuhito" } }, "node_modules/@hono/node-server": { - "version": "1.19.14", - "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz", - "integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==", + "version": "2.0.10", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@hono/node-server/-/node-server-2.0.10.tgz", + "integrity": "sha1-zq0Nl2OasTjC9aOBKJMXY+mSr9U=", "license": "MIT", "engines": { - "node": ">=18.14.1" + "node": ">=20" }, "peerDependencies": { "hono": "^4" @@ -881,8 +887,8 @@ }, "node_modules/@humanfs/core": { "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", - "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha1-qCcsoDsqz0kmcCIrIyC2xCG/3mA=", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -894,8 +900,8 @@ }, "node_modules/@humanfs/node": { "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", - "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha1-j4AMzME/T4zTEW4tnAqUk52j4+0=", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -909,8 +915,8 @@ }, "node_modules/@humanfs/types": { "version": "0.15.0", - "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", - "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha1-8qCfYgEjkLK/8/xvskjd7IwJoJA=", "dev": true, "license": "Apache-2.0", "engines": { @@ -919,8 +925,8 @@ }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha1-r1smkaIrRL6EewyoFkHF+2rQFyw=", "dev": true, "license": "Apache-2.0", "engines": { @@ -933,8 +939,8 @@ }, "node_modules/@humanwhocodes/retry": { "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", - "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha1-wrnS43TuYsWG062+qHGZsdenpro=", "dev": true, "license": "Apache-2.0", "engines": { @@ -947,8 +953,8 @@ }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha1-Y0Khn0Q0dRjJPkOxrGnes8Rlah8=", "dev": true, "license": "MIT", "dependencies": { @@ -958,8 +964,8 @@ }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha1-eg7mAfYPmaIMfHxf8MgDiMEYm9Y=", "dev": true, "license": "MIT", "engines": { @@ -968,15 +974,15 @@ }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha1-aRKwDSxjHA0Vzhp6tXzWV/Ko+Lo=", "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha1-2xXWeByTHzolGj2sOVAcmKYIL9A=", "dev": true, "license": "MIT", "dependencies": { @@ -986,20 +992,20 @@ }, "node_modules/@kurkle/color": { "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz", - "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@kurkle/color/-/color-0.3.4.tgz", + "integrity": "sha1-TU/2d+FgkhT8ccWAEl3d3Yaryr8=", "license": "MIT" }, "node_modules/@lezer/common": { "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.5.2.tgz", - "integrity": "sha512-sxQE460fPZyU3sdc8lafxiPwJHBzZRy/udNFynGQky1SePYBdhkBl1kOagA9uT3pxR8K09bOrmTUqA9wb/PjSQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@lezer/common/-/common-1.5.2.tgz", + "integrity": "sha1-1oQNsTd54/G0LnDJqXxAhtEvriI=", "license": "MIT" }, "node_modules/@lezer/highlight": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz", - "integrity": "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@lezer/highlight/-/highlight-1.2.3.tgz", + "integrity": "sha1-og8yS3EUii6pum/0Lli7+uxwKFc=", "license": "MIT", "dependencies": { "@lezer/common": "^1.3.0" @@ -1007,8 +1013,8 @@ }, "node_modules/@lezer/json": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.3.tgz", - "integrity": "sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@lezer/json/-/json-1.0.3.tgz", + "integrity": "sha1-53OgEq0AiPvwfOSc+6h1zJ5bwF8=", "license": "MIT", "dependencies": { "@lezer/common": "^1.2.0", @@ -1018,23 +1024,23 @@ }, "node_modules/@lezer/lr": { "version": "1.4.10", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.10.tgz", - "integrity": "sha512-rnCpTIBafOx4mRp43xOxDJbFipJm/c0cia/V5TiGlhmMa+wsSdoGmUN3w5Bqrks/09Q/D4tNAmWaT8p6NRi77A==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@lezer/lr/-/lr-1.4.10.tgz", + "integrity": "sha1-s6zDblrQSbdN23cZWU5+dNkWH/U=", "license": "MIT", "dependencies": { "@lezer/common": "^1.0.0" } }, "node_modules/@marijn/find-cluster-break": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz", - "integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==", + "version": "1.0.3", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@marijn/find-cluster-break/-/find-cluster-break-1.0.3.tgz", + "integrity": "sha1-vb6QfgDBfITjP8UbFRnZqiEefo4=", "license": "MIT" }, "node_modules/@modelcontextprotocol/ext-apps": { "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/ext-apps/-/ext-apps-1.7.4.tgz", - "integrity": "sha512-QQqysE549cf/Y0VabBmAACXhj92EhB3t8yVct2BHbkWiPTFA1S91EqTVjYXXcZEefXU0pmHcdObhsNMcomJIOQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@modelcontextprotocol/ext-apps/-/ext-apps-1.7.4.tgz", + "integrity": "sha1-i5cAWhNKbakM4Ii/2iCXRkvtm0Y=", "license": "MIT", "workspaces": [ "examples/*" @@ -1062,8 +1068,8 @@ }, "node_modules/@modelcontextprotocol/sdk": { "version": "1.29.0", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz", - "integrity": "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz", + "integrity": "sha1-eXhti1JeJp3oUKyCsfH3V/ORX0Q=", "license": "MIT", "dependencies": { "@hono/node-server": "^1.19.9", @@ -1101,9 +1107,9 @@ } }, "node_modules/@napi-rs/canvas": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-1.0.0.tgz", - "integrity": "sha512-Jqxcy1XOIqj+lH9sl1GT+il6GR3uQv13vI2mrwubP3uT8Olak2ClDrK2RnxlQKjwv8BRr4b3ug0YR7c6hBX8wg==", + "version": "1.0.2", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@napi-rs/canvas/-/canvas-1.0.2.tgz", + "integrity": "sha1-YkMd86TIdQBuGYl5vrioc8vKDrA=", "license": "MIT", "workspaces": [ "e2e/*" @@ -1116,23 +1122,23 @@ "url": "https://github.com/sponsors/Brooooooklyn" }, "optionalDependencies": { - "@napi-rs/canvas-android-arm64": "1.0.0", - "@napi-rs/canvas-darwin-arm64": "1.0.0", - "@napi-rs/canvas-darwin-x64": "1.0.0", - "@napi-rs/canvas-linux-arm-gnueabihf": "1.0.0", - "@napi-rs/canvas-linux-arm64-gnu": "1.0.0", - "@napi-rs/canvas-linux-arm64-musl": "1.0.0", - "@napi-rs/canvas-linux-riscv64-gnu": "1.0.0", - "@napi-rs/canvas-linux-x64-gnu": "1.0.0", - "@napi-rs/canvas-linux-x64-musl": "1.0.0", - "@napi-rs/canvas-win32-arm64-msvc": "1.0.0", - "@napi-rs/canvas-win32-x64-msvc": "1.0.0" + "@napi-rs/canvas-android-arm64": "1.0.2", + "@napi-rs/canvas-darwin-arm64": "1.0.2", + "@napi-rs/canvas-darwin-x64": "1.0.2", + "@napi-rs/canvas-linux-arm-gnueabihf": "1.0.2", + "@napi-rs/canvas-linux-arm64-gnu": "1.0.2", + "@napi-rs/canvas-linux-arm64-musl": "1.0.2", + "@napi-rs/canvas-linux-riscv64-gnu": "1.0.2", + "@napi-rs/canvas-linux-x64-gnu": "1.0.2", + "@napi-rs/canvas-linux-x64-musl": "1.0.2", + "@napi-rs/canvas-win32-arm64-msvc": "1.0.2", + "@napi-rs/canvas-win32-x64-msvc": "1.0.2" } }, "node_modules/@napi-rs/canvas-android-arm64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-1.0.0.tgz", - "integrity": "sha512-3hNKJObUK7JsCF9aJlVCs1J0/KE/gGfZNeK8MO1ge6bB3aicr5walGme9t9No1f/oyk9GgvdAT/rjSdsx3gbIw==", + "version": "1.0.2", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-1.0.2.tgz", + "integrity": "sha1-jUVdBqjygqSRi/Ez3Qhdupt0YGI=", "cpu": [ "arm64" ], @@ -1150,9 +1156,9 @@ } }, "node_modules/@napi-rs/canvas-darwin-arm64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-1.0.0.tgz", - "integrity": "sha512-ZIja19/BiGz2puhki+WUYSRriwFeFJ8Mi9eK3hZdSS85w4Y60cuEAJVhMCfKwswQkKkUtrnzdKMBuO7TupvexA==", + "version": "1.0.2", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-1.0.2.tgz", + "integrity": "sha1-n0znqx+bwQVjinQydK8DVxv1bP8=", "cpu": [ "arm64" ], @@ -1170,9 +1176,9 @@ } }, "node_modules/@napi-rs/canvas-darwin-x64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-1.0.0.tgz", - "integrity": "sha512-hImggWc82jqZVpEsFR9S7PE9OQYjq/H/D7vwCGB6X1jRH+UVBP1+1niJTPBOat1B154T6GKK7/kcFtoWgjgFzQ==", + "version": "1.0.2", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-1.0.2.tgz", + "integrity": "sha1-X/mTWFb6NAnLAvoXzYUwBeoffYg=", "cpu": [ "x64" ], @@ -1190,9 +1196,9 @@ } }, "node_modules/@napi-rs/canvas-linux-arm-gnueabihf": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-1.0.0.tgz", - "integrity": "sha512-hlJRy6d+kWLKVOG/+1rEvNQVURZ0DxxRPJsLmEWwhwiXZUJc0BF5o9esALHSEP4CoJK4wChRtj3hnyBgVx2oWA==", + "version": "1.0.2", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-1.0.2.tgz", + "integrity": "sha1-++4fOk1qJ/G+VTmUh8K/NCucO7Y=", "cpu": [ "arm" ], @@ -1210,9 +1216,9 @@ } }, "node_modules/@napi-rs/canvas-linux-arm64-gnu": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-1.0.0.tgz", - "integrity": "sha512-5Hru4T3RXkosRQafcjelv7AUzw9mXqmGYsxnzeDDOWveFCJyEPMSJltvGCM+jfH98seOCbfwm9KyFg6Jm5FhAA==", + "version": "1.0.2", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-1.0.2.tgz", + "integrity": "sha1-ZDLLhhNwQ38LEgb+Re0MvUyjK/Q=", "cpu": [ "arm64" ], @@ -1230,9 +1236,9 @@ } }, "node_modules/@napi-rs/canvas-linux-arm64-musl": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-1.0.0.tgz", - "integrity": "sha512-LTUl9jS8WsLSUGaxQZKQkxfluOJRpgvBuxxdM4pYcjib+di8AU4OzQc6+L6SzGMLcKc9H0RAjojRatBhTMqYdg==", + "version": "1.0.2", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-1.0.2.tgz", + "integrity": "sha1-ZURXdDYrmQGVZlziwUYFo0LIOIc=", "cpu": [ "arm64" ], @@ -1250,9 +1256,9 @@ } }, "node_modules/@napi-rs/canvas-linux-riscv64-gnu": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-1.0.0.tgz", - "integrity": "sha512-Iz931SAZf+WVDzpjk52Q3ffW3zw0YflFwEZMgs036Wfu1kX/LrwT9wGjsuSqyduqefUkl91/vTdAjn8hQu5ezA==", + "version": "1.0.2", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-1.0.2.tgz", + "integrity": "sha1-ULJ+W7f/2vjauz423K4uuIKz2TQ=", "cpu": [ "riscv64" ], @@ -1270,9 +1276,9 @@ } }, "node_modules/@napi-rs/canvas-linux-x64-gnu": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-1.0.0.tgz", - "integrity": "sha512-pFEQ5eFK4JusgN1K6KkO9DKP/Hi1WMJOkF8Ch03/khTc4bFbCKkCCsJG4YcOMOW9bI4XbT2/eMAWxhO0xaWgPA==", + "version": "1.0.2", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-1.0.2.tgz", + "integrity": "sha1-gOfVc+oDAdSOXeMM2YPb132oiNE=", "cpu": [ "x64" ], @@ -1290,9 +1296,9 @@ } }, "node_modules/@napi-rs/canvas-linux-x64-musl": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-1.0.0.tgz", - "integrity": "sha512-jnvr8NrLHiZ3NCiOKWqDbkI4Ah+QDrqtZ+sddPZBltEb1mQ2coSvCSJYfict+oAwcm0c970oTmVySpjKP/lnaA==", + "version": "1.0.2", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-1.0.2.tgz", + "integrity": "sha1-n+OlDOwJMc0vIA2Ke6yR2LDd1aA=", "cpu": [ "x64" ], @@ -1310,9 +1316,9 @@ } }, "node_modules/@napi-rs/canvas-win32-arm64-msvc": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-arm64-msvc/-/canvas-win32-arm64-msvc-1.0.0.tgz", - "integrity": "sha512-y2j9/Gfd5joqiqxdP/L1smqjQ+uAx3C4N0EC7bDHrnZEEH8ToM/OC5p3uHvtj4Lq591aHj+ArL01UDLNwT5HgQ==", + "version": "1.0.2", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@napi-rs/canvas-win32-arm64-msvc/-/canvas-win32-arm64-msvc-1.0.2.tgz", + "integrity": "sha1-0w4oQfM2Av+ev3L8Aovu7hV398g=", "cpu": [ "arm64" ], @@ -1330,9 +1336,9 @@ } }, "node_modules/@napi-rs/canvas-win32-x64-msvc": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-1.0.0.tgz", - "integrity": "sha512-qwdhh9N6Gge/hC4pL9S1tQp0iKwhSl/dYjg7+RGp9k26iRGRi5MqqUyKGOXIWli0zOcuy5Y2wIH/jk2ry6i/jA==", + "version": "1.0.2", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-1.0.2.tgz", + "integrity": "sha1-hhul5Ib/GqOB8yXCfOiM+fI3BiY=", "cpu": [ "x64" ], @@ -1351,8 +1357,8 @@ }, "node_modules/@napi-rs/wasm-runtime": { "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", - "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", + "integrity": "sha1-7TOAbQ+b6Y3HbQw9T9hy/acBtdU=", "dev": true, "license": "MIT", "optional": true, @@ -1369,28 +1375,19 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.137.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.137.0.tgz", - "integrity": "sha512-WT+Gb24i8hmvo85AIv2oEYouEXkRlKAlT9WaCa3TfLgNCN+GhrJOGZuIlMouAh38Qe4QOx26eUOVsq70qXrywA==", + "version": "0.139.0", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@oxc-project/types/-/types-0.139.0.tgz", + "integrity": "sha1-ONdrnb+TTCoCvhdPsyzuvxgv50I=", "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/Boshen" } }, - "node_modules/@remix-run/router": { - "version": "1.23.3", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.3.tgz", - "integrity": "sha512-4An71tdz9X8+3sI4Qqqd2LWd9vS39J7sqd9EU4Scw7TJE/qB10Flv/UuqbPVgfQV9XoK8Np6jNquZitnZq5i+Q==", - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/@resvg/resvg-js": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@resvg/resvg-js/-/resvg-js-2.6.2.tgz", - "integrity": "sha512-xBaJish5OeGmniDj9cW5PRa/PtmuVU3ziqrbr5xJj901ZDN4TosrVaNZpEiLZAxdfnhAe7uQ7QFWfjPe9d9K2Q==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@resvg/resvg-js/-/resvg-js-2.6.2.tgz", + "integrity": "sha1-PpKpB9iNh5JWxYU0fFshp/O7W0Y=", "license": "MPL-2.0", "engines": { "node": ">= 10" @@ -1412,8 +1409,8 @@ }, "node_modules/@resvg/resvg-js-android-arm-eabi": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@resvg/resvg-js-android-arm-eabi/-/resvg-js-android-arm-eabi-2.6.2.tgz", - "integrity": "sha512-FrJibrAk6v29eabIPgcTUMPXiEz8ssrAk7TXxsiZzww9UTQ1Z5KAbFJs+Z0Ez+VZTYgnE5IQJqBcoSiMebtPHA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@resvg/resvg-js-android-arm-eabi/-/resvg-js-android-arm-eabi-2.6.2.tgz", + "integrity": "sha1-52HgtogSfbZIefRVF4ySRoqa6r4=", "cpu": [ "arm" ], @@ -1428,8 +1425,8 @@ }, "node_modules/@resvg/resvg-js-android-arm64": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@resvg/resvg-js-android-arm64/-/resvg-js-android-arm64-2.6.2.tgz", - "integrity": "sha512-VcOKezEhm2VqzXpcIJoITuvUS/fcjIw5NA/w3tjzWyzmvoCdd+QXIqy3FBGulWdClvp4g+IfUemigrkLThSjAQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@resvg/resvg-js-android-arm64/-/resvg-js-android-arm64-2.6.2.tgz", + "integrity": "sha1-uMtWTX9rPzfZtDEp9dxf4XHiSeQ=", "cpu": [ "arm64" ], @@ -1444,8 +1441,8 @@ }, "node_modules/@resvg/resvg-js-darwin-arm64": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@resvg/resvg-js-darwin-arm64/-/resvg-js-darwin-arm64-2.6.2.tgz", - "integrity": "sha512-nmok2LnAd6nLUKI16aEB9ydMC6Lidiiq2m1nEBDR1LaaP7FGs4AJ90qDraxX+CWlVuRlvNjyYJTNv8qFjtL9+A==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@resvg/resvg-js-darwin-arm64/-/resvg-js-darwin-arm64-2.6.2.tgz", + "integrity": "sha1-Sb0/rtpcSfUzAtlw5uedAG3hjn0=", "cpu": [ "arm64" ], @@ -1460,8 +1457,8 @@ }, "node_modules/@resvg/resvg-js-darwin-x64": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@resvg/resvg-js-darwin-x64/-/resvg-js-darwin-x64-2.6.2.tgz", - "integrity": "sha512-GInyZLjgWDfsVT6+SHxQVRwNzV0AuA1uqGsOAW+0th56J7Nh6bHHKXHBWzUrihxMetcFDmQMAX1tZ1fZDYSRsw==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@resvg/resvg-js-darwin-x64/-/resvg-js-darwin-x64-2.6.2.tgz", + "integrity": "sha1-4TRBc6onv7TYgKtXbRrPHBZI+so=", "cpu": [ "x64" ], @@ -1476,8 +1473,8 @@ }, "node_modules/@resvg/resvg-js-linux-arm-gnueabihf": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-arm-gnueabihf/-/resvg-js-linux-arm-gnueabihf-2.6.2.tgz", - "integrity": "sha512-YIV3u/R9zJbpqTTNwTZM5/ocWetDKGsro0SWp70eGEM9eV2MerWyBRZnQIgzU3YBnSBQ1RcxRZvY/UxwESfZIw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@resvg/resvg-js-linux-arm-gnueabihf/-/resvg-js-linux-arm-gnueabihf-2.6.2.tgz", + "integrity": "sha1-NMRF66Re/Wj2EwsqtCbXanQkJT0=", "cpu": [ "arm" ], @@ -1492,8 +1489,8 @@ }, "node_modules/@resvg/resvg-js-linux-arm64-gnu": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-arm64-gnu/-/resvg-js-linux-arm64-gnu-2.6.2.tgz", - "integrity": "sha512-zc2BlJSim7YR4FZDQ8OUoJg5holYzdiYMeobb9pJuGDidGL9KZUv7SbiD4E8oZogtYY42UZEap7dqkkYuA91pg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@resvg/resvg-js-linux-arm64-gnu/-/resvg-js-linux-arm64-gnu-2.6.2.tgz", + "integrity": "sha1-MNpHCH3YFTGCGYuU/p+NmUiQ2uU=", "cpu": [ "arm64" ], @@ -1508,8 +1505,8 @@ }, "node_modules/@resvg/resvg-js-linux-arm64-musl": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-arm64-musl/-/resvg-js-linux-arm64-musl-2.6.2.tgz", - "integrity": "sha512-3h3dLPWNgSsD4lQBJPb4f+kvdOSJHa5PjTYVsWHxLUzH4IFTJUAnmuWpw4KqyQ3NA5QCyhw4TWgxk3jRkQxEKg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@resvg/resvg-js-linux-arm64-musl/-/resvg-js-linux-arm64-musl-2.6.2.tgz", + "integrity": "sha1-XXW4/1yDEDcpwco3eZhzAnU8UNQ=", "cpu": [ "arm64" ], @@ -1524,8 +1521,8 @@ }, "node_modules/@resvg/resvg-js-linux-x64-gnu": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-x64-gnu/-/resvg-js-linux-x64-gnu-2.6.2.tgz", - "integrity": "sha512-IVUe+ckIerA7xMZ50duAZzwf1U7khQe2E0QpUxu5MBJNao5RqC0zwV/Zm965vw6D3gGFUl7j4m+oJjubBVoftw==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@resvg/resvg-js-linux-x64-gnu/-/resvg-js-linux-x64-gnu-2.6.2.tgz", + "integrity": "sha1-QRq+367l7cV8u3cBc2zsulIuJvM=", "cpu": [ "x64" ], @@ -1540,8 +1537,8 @@ }, "node_modules/@resvg/resvg-js-linux-x64-musl": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-x64-musl/-/resvg-js-linux-x64-musl-2.6.2.tgz", - "integrity": "sha512-UOf83vqTzoYQO9SZ0fPl2ZIFtNIz/Rr/y+7X8XRX1ZnBYsQ/tTb+cj9TE+KHOdmlTFBxhYzVkP2lRByCzqi4jQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@resvg/resvg-js-linux-x64-musl/-/resvg-js-linux-x64-musl-2.6.2.tgz", + "integrity": "sha1-/kmEA48DcvJ54/9XC3KTTdfrKlw=", "cpu": [ "x64" ], @@ -1556,8 +1553,8 @@ }, "node_modules/@resvg/resvg-js-win32-arm64-msvc": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@resvg/resvg-js-win32-arm64-msvc/-/resvg-js-win32-arm64-msvc-2.6.2.tgz", - "integrity": "sha512-7C/RSgCa+7vqZ7qAbItfiaAWhyRSoD4l4BQAbVDqRRsRgY+S+hgS3in0Rxr7IorKUpGE69X48q6/nOAuTJQxeQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@resvg/resvg-js-win32-arm64-msvc/-/resvg-js-win32-arm64-msvc-2.6.2.tgz", + "integrity": "sha1-06BTz3/2hwh6IQYzDA/arnBiVNE=", "cpu": [ "arm64" ], @@ -1572,8 +1569,8 @@ }, "node_modules/@resvg/resvg-js-win32-ia32-msvc": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@resvg/resvg-js-win32-ia32-msvc/-/resvg-js-win32-ia32-msvc-2.6.2.tgz", - "integrity": "sha512-har4aPAlvjnLcil40AC77YDIk6loMawuJwFINEM7n0pZviwMkMvjb2W5ZirsNOZY4aDbo5tLx0wNMREp5Brk+w==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@resvg/resvg-js-win32-ia32-msvc/-/resvg-js-win32-ia32-msvc-2.6.2.tgz", + "integrity": "sha1-fN2hzinvcgnigZHZF/pb7wYkpK0=", "cpu": [ "ia32" ], @@ -1588,8 +1585,8 @@ }, "node_modules/@resvg/resvg-js-win32-x64-msvc": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@resvg/resvg-js-win32-x64-msvc/-/resvg-js-win32-x64-msvc-2.6.2.tgz", - "integrity": "sha512-ZXtYhtUr5SSaBrUDq7DiyjOFJqBVL/dOBN7N/qmi/pO0IgiWW/f/ue3nbvu9joWE5aAKDoIzy/CxsY0suwGosQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@resvg/resvg-js-win32-x64-msvc/-/resvg-js-win32-x64-msvc-2.6.2.tgz", + "integrity": "sha1-ywrQRSXWXz3vTI00YVeleXbVs4g=", "cpu": [ "x64" ], @@ -1603,9 +1600,9 @@ } }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.3.tgz", - "integrity": "sha512-DT6Z3PhvioeHMvxo+xHc3KtqggrI7CCTXCmC2h/5zUlp5jVitv7XEy+9q5/7v8IolhlioawpMo8Kg0EEBy7J0g==", + "version": "1.1.5", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.5.tgz", + "integrity": "sha1-9Yy5oKgSjtBYIoJyBShUf8XANfM=", "cpu": [ "arm64" ], @@ -1620,9 +1617,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.3.tgz", - "integrity": "sha512-0NwgwsjM7LrsuVnXMK3koTpagBNOhloc/BNjKqZjv4V5zI5r13qx69uVhRx+o5Z0yy4Hzq+lpy7TAgUG/ocvrw==", + "version": "1.1.5", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.5.tgz", + "integrity": "sha1-RBFEwFpKgxqnUmmrw6SjJDdOpwc=", "cpu": [ "arm64" ], @@ -1637,9 +1634,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.3.tgz", - "integrity": "sha512-YtiBp4disu6V560loT6PjMdiRaWmVvDNrUunAalbiFx2ggeJwxdAsgZMcoGP17uyAsTwAj5V1niksxlHnVQ1Sw==", + "version": "1.1.5", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.5.tgz", + "integrity": "sha1-yC4wZSzvUsSvkl1cZsiVWkAxmBY=", "cpu": [ "x64" ], @@ -1654,9 +1651,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.3.tgz", - "integrity": "sha512-yD3EkEdXk2LypPxnf/kSZHirarsI8gcPzc62SukhR9VJTyvV+F9Q/GxWNuCojc7sXyuVC4DxRGhdDK4X8VSsbw==", + "version": "1.1.5", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.5.tgz", + "integrity": "sha1-wy6c5/ocD7K4CROio6BcPpB9BrA=", "cpu": [ "x64" ], @@ -1671,9 +1668,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.3.tgz", - "integrity": "sha512-c+8vieQbsD7HNAHKIA34w0GJ9FedFFuJGD+7E6vz7Q3uqAIugL5p45fhlsj4UaAsHpcmlqugBWMhA0/j7o0sIg==", + "version": "1.1.5", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.5.tgz", + "integrity": "sha1-zpC14iMWretQLqAQWC9JjNBgTyc=", "cpu": [ "arm" ], @@ -1688,9 +1685,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.3.tgz", - "integrity": "sha512-50jD0uUwLvur7Zz9LHz17kaAdTPjn5wN93hEgjvmYFRZwiR7ZJYovTd5ipyWJDAnXKvZ+wgc+/Ika6dwSF5OcA==", + "version": "1.1.5", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.5.tgz", + "integrity": "sha1-kZRxEMTdqk7vsATlJogHCXcIUgE=", "cpu": [ "arm64" ], @@ -1705,9 +1702,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.3.tgz", - "integrity": "sha512-BO9+oPL8K9poZJBfYPsXNtYjPE5uM3qeehT3aFcW4LITOl+iSqhp0abzjR2nWBUNjIZeKXjAEWBZ64WjNoHd6w==", + "version": "1.1.5", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.5.tgz", + "integrity": "sha1-6zKy1BCMHHArkejN6KBD6uXKqU0=", "cpu": [ "arm64" ], @@ -1722,9 +1719,9 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.3.tgz", - "integrity": "sha512-f3VpLB1vQ0Eo6ecr/6cekLnvYMFF4YBFoVGkfkvPLq1bAkbAwHYQPZKoAmG6OJyTcxxoC+AvezGx/S1obNC0Mw==", + "version": "1.1.5", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.5.tgz", + "integrity": "sha1-zLlDwR5acmVcuwL8EWNUHOtkB4I=", "cpu": [ "ppc64" ], @@ -1739,9 +1736,9 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.3.tgz", - "integrity": "sha512-AmurZ26Pqx/RI9N1gzEOCklkKXl927yjfXWUUS0O7Puh8ARM/Ob8qfrD3qnWksScdw6cSrW5PSHE9DyLu7+PtA==", + "version": "1.1.5", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.5.tgz", + "integrity": "sha1-ozcx7lZ+kLdfrG5eVTB+iiswOPA=", "cpu": [ "s390x" ], @@ -1756,9 +1753,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.3.tgz", - "integrity": "sha512-JJpqs8bRGITDOdbkNKnlojzBabbOHrqjSvDr0IVsZObE1lBcPjxItUEY9eWIDbxaJ3cGrXPWGfGkIxFijg/URg==", + "version": "1.1.5", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.5.tgz", + "integrity": "sha1-p0wBqqzt/BHDm2/rozpfoMZUlJ8=", "cpu": [ "x64" ], @@ -1773,9 +1770,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.3.tgz", - "integrity": "sha512-rSJcdjPxzA/by/6/rYs+v+bXU7UjvnbUWz8MJb6kh6+knqB1dCrtHg0uu7C/4haqJvqdkYHQ5IGn+tCH9GLW/g==", + "version": "1.1.5", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.5.tgz", + "integrity": "sha1-KM0XhJT6HmXbpBIim1zlXE3Vy9E=", "cpu": [ "x64" ], @@ -1790,9 +1787,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.3.tgz", - "integrity": "sha512-hQ3/PYkDJICgevvyNcVrihVeqq7k1Pp3VZ9lY+dauAYUJKO+auqApvANhvR1An9BhmqYKvW2Mu1F9u4DXSMLxQ==", + "version": "1.1.5", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.5.tgz", + "integrity": "sha1-98dfqRP8IIhNJqfUiNT1xZfNccA=", "cpu": [ "arm64" ], @@ -1807,9 +1804,9 @@ } }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.3.tgz", - "integrity": "sha512-Elcv/BtML9lXrV6JuKITc/grN2kYV9gjsQpW8Jfw4ioK0TOkjBjye0nnyqQNy9STNaI20lXNaQBRrD5gSgR0Yg==", + "version": "1.1.5", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.5.tgz", + "integrity": "sha1-w3lYGUd4cIHfNj6hBhQPzV/sJS0=", "cpu": [ "wasm32" ], @@ -1826,9 +1823,9 @@ } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.3.tgz", - "integrity": "sha512-2DrEfhluH9yhiaFApmsjsjwrSYbNcY1oFTzYSP1a535jDbV98zCFanA/96TBUd0iDFcxGmw9QRExwGCXz3U+/g==", + "version": "1.1.5", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.5.tgz", + "integrity": "sha1-8jyIaU96cpoS85UCSu4434Cha6M=", "cpu": [ "arm64" ], @@ -1843,9 +1840,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.3.tgz", - "integrity": "sha512-OL4OMk7UPXOeVGGd3qo5zJyPIljf4AFgk5QAkPPS+OoLuOOozhuaQGC18MxVTnw/06q93gShAJzlwnSCY9YtqA==", + "version": "1.1.5", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.5.tgz", + "integrity": "sha1-M3fI3g5WqIV/ESF1YRRwkOh0y0Y=", "cpu": [ "x64" ], @@ -1860,16 +1857,16 @@ } }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.27", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", - "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "version": "1.0.1", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha1-4/zuCT+7XOdl4a0Ij/TeKIn2+b4=", "dev": true, "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz", - "integrity": "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz", + "integrity": "sha1-XphJtmHCIpz5Z6CNvi276ejJkeU=", "cpu": [ "arm" ], @@ -1882,8 +1879,8 @@ }, "node_modules/@rollup/rollup-android-arm64": { "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.2.tgz", - "integrity": "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.2.tgz", + "integrity": "sha1-WwaZ7l3UhLIiye10r/Q8keqLF/g=", "cpu": [ "arm64" ], @@ -1896,8 +1893,8 @@ }, "node_modules/@rollup/rollup-darwin-arm64": { "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.2.tgz", - "integrity": "sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.2.tgz", + "integrity": "sha1-i8UsnXo86NBTPDUanJNd54HaoG8=", "cpu": [ "arm64" ], @@ -1910,8 +1907,8 @@ }, "node_modules/@rollup/rollup-darwin-x64": { "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.2.tgz", - "integrity": "sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.2.tgz", + "integrity": "sha1-ui7z6PsxDwrzVYjycM+lqpbkh2Q=", "cpu": [ "x64" ], @@ -1924,8 +1921,8 @@ }, "node_modules/@rollup/rollup-freebsd-arm64": { "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.2.tgz", - "integrity": "sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.2.tgz", + "integrity": "sha1-k7EL2/6K2iJri8DALva39URHTZY=", "cpu": [ "arm64" ], @@ -1938,8 +1935,8 @@ }, "node_modules/@rollup/rollup-freebsd-x64": { "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.2.tgz", - "integrity": "sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.2.tgz", + "integrity": "sha1-PoqjjvPJwwCUaHHj/bsMMOCiD4Y=", "cpu": [ "x64" ], @@ -1952,8 +1949,8 @@ }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.2.tgz", - "integrity": "sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.2.tgz", + "integrity": "sha1-HXmUOEuwrRvEGSG1BuFkLU+df8M=", "cpu": [ "arm" ], @@ -1966,8 +1963,8 @@ }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.2.tgz", - "integrity": "sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.2.tgz", + "integrity": "sha1-plQPR8+ESla4DKn/ldKs37LO+Xs=", "cpu": [ "arm" ], @@ -1980,8 +1977,8 @@ }, "node_modules/@rollup/rollup-linux-arm64-gnu": { "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.2.tgz", - "integrity": "sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.2.tgz", + "integrity": "sha1-QE8gRWUYQMv0jakbptD0kPC8LL8=", "cpu": [ "arm64" ], @@ -1994,8 +1991,8 @@ }, "node_modules/@rollup/rollup-linux-arm64-musl": { "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.2.tgz", - "integrity": "sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.2.tgz", + "integrity": "sha1-o0BP/d97R0tIyZuciTtiR7t2W6U=", "cpu": [ "arm64" ], @@ -2008,8 +2005,8 @@ }, "node_modules/@rollup/rollup-linux-loong64-gnu": { "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.2.tgz", - "integrity": "sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.2.tgz", + "integrity": "sha1-6KrG1Umzd5ReNJiC8Zm3yOt1yjg=", "cpu": [ "loong64" ], @@ -2022,8 +2019,8 @@ }, "node_modules/@rollup/rollup-linux-loong64-musl": { "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.2.tgz", - "integrity": "sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.2.tgz", + "integrity": "sha1-bi5E6lAxCzpYIHipFeX+uHnIINQ=", "cpu": [ "loong64" ], @@ -2036,8 +2033,8 @@ }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.2.tgz", - "integrity": "sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.2.tgz", + "integrity": "sha1-aJgwLabXegU3zeZLK0xrYGWb0RA=", "cpu": [ "ppc64" ], @@ -2050,8 +2047,8 @@ }, "node_modules/@rollup/rollup-linux-ppc64-musl": { "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.2.tgz", - "integrity": "sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.2.tgz", + "integrity": "sha1-MzcXyV3Vpmvvj2Pn74qf2EX9GNA=", "cpu": [ "ppc64" ], @@ -2064,8 +2061,8 @@ }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.2.tgz", - "integrity": "sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.2.tgz", + "integrity": "sha1-gbwGujgDUgBNAfSCbrfNzO+gW60=", "cpu": [ "riscv64" ], @@ -2078,8 +2075,8 @@ }, "node_modules/@rollup/rollup-linux-riscv64-musl": { "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.2.tgz", - "integrity": "sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.2.tgz", + "integrity": "sha1-lafNOd4hOJrWeIpShOqqc44pykw=", "cpu": [ "riscv64" ], @@ -2092,8 +2089,8 @@ }, "node_modules/@rollup/rollup-linux-s390x-gnu": { "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.2.tgz", - "integrity": "sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.2.tgz", + "integrity": "sha1-BubbLsG8SLU3THkj74PC6wJLJFI=", "cpu": [ "s390x" ], @@ -2106,8 +2103,8 @@ }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.2.tgz", - "integrity": "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.2.tgz", + "integrity": "sha1-XcgYmIKF4J6IeQxkYt73JBPfLaM=", "cpu": [ "x64" ], @@ -2119,8 +2116,8 @@ }, "node_modules/@rollup/rollup-linux-x64-musl": { "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.2.tgz", - "integrity": "sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.2.tgz", + "integrity": "sha1-IID0qTNJ6a/TS+b8GjfgH8i/yA8=", "cpu": [ "x64" ], @@ -2133,8 +2130,8 @@ }, "node_modules/@rollup/rollup-openbsd-x64": { "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.2.tgz", - "integrity": "sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.2.tgz", + "integrity": "sha1-IdZKistmIhckuSPlGvUzPfGvBEs=", "cpu": [ "x64" ], @@ -2147,8 +2144,8 @@ }, "node_modules/@rollup/rollup-openharmony-arm64": { "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.2.tgz", - "integrity": "sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.2.tgz", + "integrity": "sha1-jg/NnQIUHjN7TFtc/1dsuadrG6A=", "cpu": [ "arm64" ], @@ -2161,8 +2158,8 @@ }, "node_modules/@rollup/rollup-win32-arm64-msvc": { "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.2.tgz", - "integrity": "sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.2.tgz", + "integrity": "sha1-vbTMTv1Y7+gIIDNH8PVGPw6hblI=", "cpu": [ "arm64" ], @@ -2175,8 +2172,8 @@ }, "node_modules/@rollup/rollup-win32-ia32-msvc": { "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.2.tgz", - "integrity": "sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.2.tgz", + "integrity": "sha1-26695a/STq4O7+kV2QFjLny1mGA=", "cpu": [ "ia32" ], @@ -2189,8 +2186,8 @@ }, "node_modules/@rollup/rollup-win32-x64-gnu": { "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.2.tgz", - "integrity": "sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.2.tgz", + "integrity": "sha1-hBCehf6l+PE1NJn5ZXj9wqDosTg=", "cpu": [ "x64" ], @@ -2203,8 +2200,8 @@ }, "node_modules/@rollup/rollup-win32-x64-msvc": { "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz", - "integrity": "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz", + "integrity": "sha1-NnHOP5uSjVwB+Hl5LVwLYK4U1K0=", "cpu": [ "x64" ], @@ -2217,14 +2214,14 @@ }, "node_modules/@standard-schema/spec": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha1-p5tV26+GBIEvUtFAssmrQbwVC7g=", "license": "MIT" }, "node_modules/@swc/core": { "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.43.tgz", - "integrity": "sha512-1CuKjFkPxIgGdeHVuNbkxmBxkcbdc08u0aiI43pFq6yY1tTVKmXT9hFEooyyKs/sJ3xf1GPHyEwTtk9Xl8dvQw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@swc/core/-/core-1.15.43.tgz", + "integrity": "sha1-ZT5lc5aP1cdBY7mIXqCpMwEsnyI=", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", @@ -2264,8 +2261,8 @@ }, "node_modules/@swc/core-darwin-arm64": { "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.43.tgz", - "integrity": "sha512-v1aVuvXdo/BHxJzco9V2xpHrvwWmhfS8t6gziY5wJxd+Z2h8AeJRnAwPD8itCDaGXVBwJ/CaKfxEzTkG0Va0OA==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.43.tgz", + "integrity": "sha1-OGKU+EJ93i3xpw3QpYJtZ69w6ZY=", "cpu": [ "arm64" ], @@ -2281,8 +2278,8 @@ }, "node_modules/@swc/core-darwin-x64": { "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.43.tgz", - "integrity": "sha512-lp3d4Lamc8dt5huYdGLSR+9hLxmfr1jb0l+4XXG2zPqZwYWRN9R0U2qYoTrggiU2RWW0oV9VbWM3kBnqIc2kdQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@swc/core-darwin-x64/-/core-darwin-x64-1.15.43.tgz", + "integrity": "sha1-xII1KcQk4q4lt+t4ZDhHR0FSH8s=", "cpu": [ "x64" ], @@ -2298,8 +2295,8 @@ }, "node_modules/@swc/core-linux-arm-gnueabihf": { "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.43.tgz", - "integrity": "sha512-JWTQQELtsG5GgphDrr/XqqmM2pDN3cZqbMS0Mrg+iTiXL3F74sn/S2IyYE/5u4h2KLkTf9qQ7dXyxsbx7YzkeA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.43.tgz", + "integrity": "sha1-wKDtF8/8XUrxkpNWZ/EvBf7rOfk=", "cpu": [ "arm" ], @@ -2315,8 +2312,8 @@ }, "node_modules/@swc/core-linux-arm64-gnu": { "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.43.tgz", - "integrity": "sha512-B4otJRdPWIsmiSBf0uG7Z/+vMWmkufjz5MmYxubwKuZazDW14Zd3symga1N62QR4RT+kEFeHEgsXfZGyn/w0hw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.43.tgz", + "integrity": "sha1-HrLZxe7uW7nQBZm0dd3DHcKHDSI=", "cpu": [ "arm64" ], @@ -2332,8 +2329,8 @@ }, "node_modules/@swc/core-linux-arm64-musl": { "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.43.tgz", - "integrity": "sha512-6zB6OnpViBxYy4tgY3v2i6AZY9fwkcHZ032UOwtwUuW1d19sdT07qF0kZe6/3UR1tUaK6jjg2rmVcUIBCEYVjQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.43.tgz", + "integrity": "sha1-6mtcOAiPOSGleSLTkxstdP0jqf0=", "cpu": [ "arm64" ], @@ -2349,8 +2346,8 @@ }, "node_modules/@swc/core-linux-ppc64-gnu": { "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.43.tgz", - "integrity": "sha512-coxE1ZWdB3uSDVNoEtYNrRi/1epvckZx9cTJ8ICUxTMTxGk+yvQ/Twacp3ruZSaMPGCriUjP86C37VhaT6nyRg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.43.tgz", + "integrity": "sha1-U4+sMLvV8eZ4u3usnMxiJGpvbXo=", "cpu": [ "ppc64" ], @@ -2366,8 +2363,8 @@ }, "node_modules/@swc/core-linux-s390x-gnu": { "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.43.tgz", - "integrity": "sha512-lXfLhs+LpBsD5inuYx+YDH5WsPPBQ95KPUiy8P5wq9ob9xKDZFqwNfU2QW6bGO8NqRO/H9JQomTSt5Yyh+FGfA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.43.tgz", + "integrity": "sha1-7lZLRfP1eLH8ghNsTasWMYkxZkE=", "cpu": [ "s390x" ], @@ -2383,8 +2380,8 @@ }, "node_modules/@swc/core-linux-x64-gnu": { "version": "1.15.33", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.33.tgz", - "integrity": "sha512-mGTH0YxmUN+x6vRN/I6NOk5X0ogNktkwPnJ94IMvR7QjhRDwL0O8RXEDhyUM0YtwWrryBOqaJQBX4zruxEPRGw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.33.tgz", + "integrity": "sha1-SfNlWO3gcucZmao38SM2fa7SpmI=", "cpu": [ "x64" ], @@ -2399,8 +2396,8 @@ }, "node_modules/@swc/core-linux-x64-musl": { "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.43.tgz", - "integrity": "sha512-TJc+bsSIaBh+hZvZ5GRtW/K1bw66TJ9vsUwvVIsZdiWxU5ObLwZvfcnZ3UpgVfMnFibRes9uriJrQNBHEEogRQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.43.tgz", + "integrity": "sha1-U59vJyHAzDLl21zw1FPIIEX2Zi0=", "cpu": [ "x64" ], @@ -2416,8 +2413,8 @@ }, "node_modules/@swc/core-win32-arm64-msvc": { "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.43.tgz", - "integrity": "sha512-jfd7s2/bUQYkOHLs+LWQNKZdmDa8+sufKLllhpWAhVQ2GDCwsHe3vR/j+OSiItZNtkzFuaawa3+SAKz9y5gYfw==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.43.tgz", + "integrity": "sha1-t7trYR1ISsGdDuIUaecBLWRsKLU=", "cpu": [ "arm64" ], @@ -2433,8 +2430,8 @@ }, "node_modules/@swc/core-win32-ia32-msvc": { "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.43.tgz", - "integrity": "sha512-rLAE8JvucqEW1ZGohxPQrQWPBQeJG4+ypKbWfdlU/qmKScvCkxf9/Jxnzki1dkUQCQ7P5Enp13RlvqOlvx/32g==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.43.tgz", + "integrity": "sha1-5bJXIqfSe7DJqb3ueGPynIZ0Nk4=", "cpu": [ "ia32" ], @@ -2450,8 +2447,8 @@ }, "node_modules/@swc/core-win32-x64-msvc": { "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.43.tgz", - "integrity": "sha512-h8MLDHZcfIukwQWj03rIJZx1I0E81AYj2X7J/nGErG4nz+QAv6G1Z+peotvinL3lqpbo32tLYSMFo32/ySzxKg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.43.tgz", + "integrity": "sha1-0ohCYhIBw0U4PUaNQMCWSLbNbmg=", "cpu": [ "x64" ], @@ -2467,8 +2464,8 @@ }, "node_modules/@swc/core/node_modules/@swc/core-linux-x64-gnu": { "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.43.tgz", - "integrity": "sha512-07XnKwTmKy8TGOZG3D9fRnLWGynxPjwQnZLVmBFbo6F+7vHYzBIOuwXEhemrChBWb6yDNZsVCcMWCPX6FDD2xg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.43.tgz", + "integrity": "sha1-5uO/6naSHH9eFtUKEmYV8uBM4cg=", "cpu": [ "x64" ], @@ -2484,15 +2481,15 @@ }, "node_modules/@swc/counter": { "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", - "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha1-zHRjvQKUlhHGMpWW/M0rDseCsOk=", "dev": true, "license": "Apache-2.0" }, "node_modules/@swc/types": { "version": "0.1.27", - "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.27.tgz", - "integrity": "sha512-K6h3iUlqeM946U4sXFYeahefR1YBbXJvko+hv8WS8/0BNJ4OHiHRywMnQUJCqkR7Y9+hqQ1TvEpiKqUhz7NEFg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@swc/types/-/types-0.1.27.tgz", + "integrity": "sha1-EggLDEJt6kUGNPIC2aPIKsOW55M=", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -2501,8 +2498,8 @@ }, "node_modules/@tybys/wasm-util": { "version": "0.10.3", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", - "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", + "integrity": "sha1-AVy6np3UfOFNA9KoxdVHv7FpZl0=", "dev": true, "license": "MIT", "optional": true, @@ -2512,16 +2509,16 @@ }, "node_modules/@tybys/wasm-util/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha1-YS7+TtI11Wfoq6Xypfq3AoCt6D8=", "dev": true, "license": "0BSD", "optional": true }, "node_modules/@types/chai": { "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", - "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha1-jpzZ4cNYH6azQaWu1ViOsoW+C0o=", "dev": true, "license": "MIT", "dependencies": { @@ -2531,8 +2528,8 @@ }, "node_modules/@types/debug": { "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", - "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha1-ItHMnVQtNZPK6nZPl0MGqzYobuc=", "license": "MIT", "dependencies": { "@types/ms": "*" @@ -2540,21 +2537,21 @@ }, "node_modules/@types/deep-eql": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha1-M0MRlx06BxIefrkbaEpgXn7qnL0=", "dev": true, "license": "MIT" }, "node_modules/@types/estree": { "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", - "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha1-zz8Oh2177hWpOrkluCv1cKOQSiQ=", "license": "MIT" }, "node_modules/@types/estree-jsx": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", - "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha1-hYqI6iDzT+ZREfAFpon6Hr9w3Bg=", "license": "MIT", "dependencies": { "@types/estree": "*" @@ -2562,14 +2559,14 @@ }, "node_modules/@types/geojson": { "version": "7946.0.16", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", - "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha1-jr5T1p762nBERU4zBcGQF9l87So=", "license": "MIT" }, "node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "version": "3.0.5", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@types/hast/-/hast-3.0.5.tgz", + "integrity": "sha1-SAIN5MDmNJL0yp20IGjBCPaLf48=", "license": "MIT", "dependencies": { "@types/unist": "*" @@ -2577,21 +2574,21 @@ }, "node_modules/@types/json-schema": { "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha1-WWoXRyM2lNUPatinhp/Lb1bPWEE=", "dev": true, "license": "MIT" }, "node_modules/@types/katex": { "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.8.tgz", - "integrity": "sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@types/katex/-/katex-0.16.8.tgz", + "integrity": "sha1-gL8+CBTQmoRkEqCw8UCUa3nDbD4=", "license": "MIT" }, "node_modules/@types/mdast": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha1-fM9y7dLxqn3TQ34YDGQ3NYWATdY=", "license": "MIT", "dependencies": { "@types/unist": "*" @@ -2599,14 +2596,14 @@ }, "node_modules/@types/ms": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha1-BSqmekjszEMJ1/AZG35BQ0uQu3g=", "license": "MIT" }, "node_modules/@types/node": { "version": "20.19.43", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz", - "integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@types/node/-/node-20.19.43.tgz", + "integrity": "sha1-/Oz1gLpCoNtVz0BMNyyXlzw3bJc=", "dev": true, "license": "MIT", "dependencies": { @@ -2615,20 +2612,20 @@ }, "node_modules/@types/prismjs": { "version": "1.26.6", - "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.6.tgz", - "integrity": "sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@types/prismjs/-/prismjs-1.26.6.tgz", + "integrity": "sha1-bqJ8Em1kUxmuT3BV7aY6noNcAYc=", "license": "MIT" }, "node_modules/@types/prop-types": { "version": "15.7.15", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", - "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha1-5uWobWAr6spxzlFj+t9fldcJMcc=", "license": "MIT" }, "node_modules/@types/react": { "version": "18.3.31", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.31.tgz", - "integrity": "sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@types/react/-/react-18.3.31.tgz", + "integrity": "sha1-teleKP/M6rjZgvM/LrB24XZTwqQ=", "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -2637,8 +2634,8 @@ }, "node_modules/@types/react-dom": { "version": "18.3.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", - "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha1-uJ3fLNg7T+r8xOLqQa/fuVoNGU8=", "dev": true, "license": "MIT", "peerDependencies": { @@ -2647,8 +2644,8 @@ }, "node_modules/@types/react-syntax-highlighter": { "version": "15.5.13", - "resolved": "https://registry.npmjs.org/@types/react-syntax-highlighter/-/react-syntax-highlighter-15.5.13.tgz", - "integrity": "sha512-uLGJ87j6Sz8UaBAooU0T6lWJ0dBmjZgN1PZTrj05TNql2/XpC6+4HhMT5syIdFUUt+FASfCeLLv4kBygNU+8qA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@types/react-syntax-highlighter/-/react-syntax-highlighter-15.5.13.tgz", + "integrity": "sha1-xbr2KjIZs78o05z+pV0KSaJj0fI=", "dev": true, "license": "MIT", "dependencies": { @@ -2657,22 +2654,22 @@ }, "node_modules/@types/unist": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha1-rKqw+RnOaczmKcLU7S60rcG2wgw=", "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.62.0.tgz", - "integrity": "sha512-o+mpz7EYiMzXoySXiKmzlabIvTVqUuK5yLrAedRPRDA0IpPFMUV1IXt6OqljIxX/kumN6EjUYp41Hqelh6p/Dw==", + "version": "8.64.0", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.64.0.tgz", + "integrity": "sha1-caDD1fil5sXf208PBL0b+1ctXiQ=", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.62.0", - "@typescript-eslint/type-utils": "8.62.0", - "@typescript-eslint/utils": "8.62.0", - "@typescript-eslint/visitor-keys": "8.62.0", + "@typescript-eslint/scope-manager": "8.64.0", + "@typescript-eslint/type-utils": "8.64.0", + "@typescript-eslint/utils": "8.64.0", + "@typescript-eslint/visitor-keys": "8.64.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" @@ -2685,22 +2682,22 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.62.0", + "@typescript-eslint/parser": "^8.64.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.62.0.tgz", - "integrity": "sha512-dzHeT2gySzZtLDsuqxU9AkYgIsQoHAHtRBpOqM+Ofzx1Bwrd2RcCjQJ+6iQbsHOIR6NS33bF2W1k3blN1zLDrA==", + "version": "8.64.0", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@typescript-eslint/parser/-/parser-8.64.0.tgz", + "integrity": "sha1-yYZKHMKKE/8ppzFPve8FKLsSL3I=", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.62.0", - "@typescript-eslint/types": "8.62.0", - "@typescript-eslint/typescript-estree": "8.62.0", - "@typescript-eslint/visitor-keys": "8.62.0", + "@typescript-eslint/scope-manager": "8.64.0", + "@typescript-eslint/types": "8.64.0", + "@typescript-eslint/typescript-estree": "8.64.0", + "@typescript-eslint/visitor-keys": "8.64.0", "debug": "^4.4.3" }, "engines": { @@ -2716,14 +2713,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.62.0.tgz", - "integrity": "sha512-wexnCqiTg7BOGtbLDftYpRWlmLq4xfoMd7BKFR6Y75sZS3QmRKLdN3yWLhmIYgqMmP/OXWpj3H8odkb5nGURCQ==", + "version": "8.64.0", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@typescript-eslint/project-service/-/project-service-8.64.0.tgz", + "integrity": "sha1-FMTik5DXMlp/ihIYwniP1km4XaY=", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.62.0", - "@typescript-eslint/types": "^8.62.0", + "@typescript-eslint/tsconfig-utils": "^8.64.0", + "@typescript-eslint/types": "^8.64.0", "debug": "^4.4.3" }, "engines": { @@ -2738,14 +2735,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.62.0.tgz", - "integrity": "sha512-1lX38kNxXIRb8mEc3lbq5mdHq1Pf2+U0nFU65KfT18mtPxxl0fvjuEE92mHuXPuCtElJhOrddOpyMlM3Z0umEA==", + "version": "8.64.0", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@typescript-eslint/scope-manager/-/scope-manager-8.64.0.tgz", + "integrity": "sha1-1F8VMEqUyFw52zF7cXsVj7YlmVg=", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.62.0", - "@typescript-eslint/visitor-keys": "8.62.0" + "@typescript-eslint/types": "8.64.0", + "@typescript-eslint/visitor-keys": "8.64.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2756,9 +2753,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.62.0.tgz", - "integrity": "sha512-y2GAdB6ykaXUvuspbYnizQc4oDDz0Tz/Yc7iWrXf9mx8vm/L/0vLHCe0tS2boG96Zy+DivnVDQ9ZUEWoHqqx1g==", + "version": "8.64.0", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.64.0.tgz", + "integrity": "sha1-xirI6pFzw8rIs4uOZuMKBGtUiFE=", "dev": true, "license": "MIT", "engines": { @@ -2773,15 +2770,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.62.0.tgz", - "integrity": "sha512-+g5O3j0w2ldzC86Pv6fvbO/xhAonbJFIdf/MKQ1d30gndlsVzUOE83ldfSE15Qrl9fhFjK6AovHs5Wpp6vx86w==", + "version": "8.64.0", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@typescript-eslint/type-utils/-/type-utils-8.64.0.tgz", + "integrity": "sha1-EG+n1Yz5z3dY892OQmrII37OrPM=", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.62.0", - "@typescript-eslint/typescript-estree": "8.62.0", - "@typescript-eslint/utils": "8.62.0", + "@typescript-eslint/types": "8.64.0", + "@typescript-eslint/typescript-estree": "8.64.0", + "@typescript-eslint/utils": "8.64.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, @@ -2798,9 +2795,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.62.0.tgz", - "integrity": "sha512-KvAclkktORPvM54TgLgA4z9HIV1M8zOgw9ZVNXl9f/8dLYfXYX1wkMXP7qmabpijQRV5bHJLOmoyGQbLMaUYeg==", + "version": "8.64.0", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@typescript-eslint/types/-/types-8.64.0.tgz", + "integrity": "sha1-tB+O9d1AYWkIZYuZEZep1IbNpgs=", "dev": true, "license": "MIT", "engines": { @@ -2812,16 +2809,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.62.0.tgz", - "integrity": "sha512-+hVbNxtW64pIcZWDPGbyaKF7vp2IBTVY5ma1blwwksrjdsbdqqEKvJWMGbBofei4F6Dovx1M0RJgoFeNu2279A==", + "version": "8.64.0", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@typescript-eslint/typescript-estree/-/typescript-estree-8.64.0.tgz", + "integrity": "sha1-uNUSVeLXJutL2A05ek+0FwwC7sw=", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.62.0", - "@typescript-eslint/tsconfig-utils": "8.62.0", - "@typescript-eslint/types": "8.62.0", - "@typescript-eslint/visitor-keys": "8.62.0", + "@typescript-eslint/project-service": "8.64.0", + "@typescript-eslint/tsconfig-utils": "8.64.0", + "@typescript-eslint/types": "8.64.0", + "@typescript-eslint/visitor-keys": "8.64.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -2840,16 +2837,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.62.0.tgz", - "integrity": "sha512-82r66fi9zYwZ+mTq3vKgwjbZ1PVk/DJzrXFLpG6RnBbdvH8TEGVHIs9H4d2drhkOzf0syZuD/OZvvlu6GDbP4g==", + "version": "8.64.0", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@typescript-eslint/utils/-/utils-8.64.0.tgz", + "integrity": "sha1-mLsgEM+3VLQZhbnJPm6LPc171gA=", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.62.0", - "@typescript-eslint/types": "8.62.0", - "@typescript-eslint/typescript-estree": "8.62.0" + "@typescript-eslint/scope-manager": "8.64.0", + "@typescript-eslint/types": "8.64.0", + "@typescript-eslint/typescript-estree": "8.64.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2864,13 +2861,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.62.0.tgz", - "integrity": "sha512-CY3uyFSRbcQv3nnSv8S0+lDftMVz6P963PoRlxrV7ew/Md564g9ut60PYzdLM5qW4jFn93GBF+Soi90ISAN+GQ==", + "version": "8.64.0", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@typescript-eslint/visitor-keys/-/visitor-keys-8.64.0.tgz", + "integrity": "sha1-eghCHRDlSWBzM1LNfJX6sXhOhHM=", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.62.0", + "@typescript-eslint/types": "8.64.0", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -2883,8 +2880,8 @@ }, "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha1-njyUiWl4JNLUzjqK0SYo+R6fWb4=", "dev": true, "license": "Apache-2.0", "engines": { @@ -2895,9 +2892,9 @@ } }, "node_modules/@uiw/codemirror-extensions-basic-setup": { - "version": "4.25.10", - "resolved": "https://registry.npmjs.org/@uiw/codemirror-extensions-basic-setup/-/codemirror-extensions-basic-setup-4.25.10.tgz", - "integrity": "sha512-P3vytLlpE62KYSWrMUnwDCv2lvaQDuDZzyj03mHntuHo5bSl34fRZpjTY3kQTPGuXHxkGSYpoPFFj+hMTqaaMQ==", + "version": "4.25.11", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@uiw/codemirror-extensions-basic-setup/-/codemirror-extensions-basic-setup-4.25.11.tgz", + "integrity": "sha1-pF4GBOtqKf/6FStoTQx3Asbmm98=", "license": "MIT", "dependencies": { "@codemirror/autocomplete": "^6.0.0", @@ -2922,16 +2919,16 @@ } }, "node_modules/@uiw/react-codemirror": { - "version": "4.25.10", - "resolved": "https://registry.npmjs.org/@uiw/react-codemirror/-/react-codemirror-4.25.10.tgz", - "integrity": "sha512-DzgSMwM5qzB7v1FIb4gEeriYt67iiay756/HIOM9mAbeOVK0MO7rqefHf0O5c0269pJKMW7AH9FjclExD23V9w==", + "version": "4.25.11", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@uiw/react-codemirror/-/react-codemirror-4.25.11.tgz", + "integrity": "sha1-AfFUrM36PfZ03C4AQQZ/UU30j8I=", "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.6", "@codemirror/commands": "^6.1.0", "@codemirror/state": "^6.1.1", "@codemirror/theme-one-dark": "^6.0.0", - "@uiw/codemirror-extensions-basic-setup": "4.25.10", + "@uiw/codemirror-extensions-basic-setup": "4.25.11", "codemirror": "^6.0.0" }, "funding": { @@ -2948,36 +2945,48 @@ } }, "node_modules/@ungap/structured-clone": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.2.tgz", - "integrity": "sha512-5jsZFwgR5rTdKwidH9Qmat75RKwqfpKlWWB1frDkljN127mwqBu8K0PYo7/hFpF03IEJpfVPpCQDY/eDx3iHvA==", + "version": "1.3.3", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@ungap/structured-clone/-/structured-clone-1.3.3.tgz", + "integrity": "sha1-CUBB4aTLGYfwODNUISgayL45C8w=", "license": "ISC" }, - "node_modules/@vitejs/plugin-react-swc": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.11.0.tgz", - "integrity": "sha512-YTJCGFdNMHCMfjODYtxRNVAYmTWQ1Lb8PulP/2/f/oEEtglw8oKxKIZmmRkyXrVrHfsKOaVkAc3NT9/dMutO5w==", + "node_modules/@vitejs/plugin-react": { + "version": "6.0.3", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@vitejs/plugin-react/-/plugin-react-6.0.3.tgz", + "integrity": "sha1-VfHX9VhTTRCu8DwAfcIIt8N3HOQ=", "dev": true, "license": "MIT", "dependencies": { - "@rolldown/pluginutils": "1.0.0-beta.27", - "@swc/core": "^1.12.11" + "@rolldown/pluginutils": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" }, "peerDependencies": { - "vite": "^4 || ^5 || ^6 || ^7" + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + } } }, "node_modules/@vitest/expect": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.9.tgz", - "integrity": "sha512-vl/rYsUKcBr3SnQn166+XR5ZQcgMx3DQhFWdfli/cWpLnLUmbxZvyrJZotLFUryib+LtArYMSTJ5RbQ57ZqrlA==", + "version": "4.1.10", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@vitest/expect/-/expect-4.1.10.tgz", + "integrity": "sha1-eZwG/ES7DPfieEE3tifFzBcyhdQ=", "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.9", - "@vitest/utils": "4.1.9", + "@vitest/spy": "4.1.10", + "@vitest/utils": "4.1.10", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" }, @@ -2986,13 +2995,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.9.tgz", - "integrity": "sha512-EVkXzBjrPGM+cK8/ANWgBrkUCfJfb38/EfTSO8h7pWvKkyPkpWxvR7BkD2MyItMF62C97zAEoqdpUixwR/e+Rw==", + "version": "4.1.10", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@vitest/mocker/-/mocker-4.1.10.tgz", + "integrity": "sha1-JBOYerTNf6HCthS0BMQHv2rR6tE=", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.9", + "@vitest/spy": "4.1.10", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -3013,9 +3022,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.9.tgz", - "integrity": "sha512-s0iufns3iIFitdgm+YR7g1whCAaGtXz459VS9/PqyKDEEFgYIhsHOQmXgIgDuYCt7DeQmiZT0Qe2OA2p4ZPu5A==", + "version": "4.1.10", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@vitest/pretty-format/-/pretty-format-4.1.10.tgz", + "integrity": "sha1-dVQucnOgjMEP1Nja1OPrHxbNlYw=", "dev": true, "license": "MIT", "dependencies": { @@ -3026,13 +3035,13 @@ } }, "node_modules/@vitest/runner": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.9.tgz", - "integrity": "sha512-KXLMDtc7oe70+3mJfGrPUWPesswH+3sTxAMAMl8DG7I8IUQT4XW718dY5ID3vPUcmlu27CcKfY4P3h3I29SLJg==", + "version": "4.1.10", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@vitest/runner/-/runner-4.1.10.tgz", + "integrity": "sha1-/r8KIakWhCFCLRlVNw5gb+q2A1U=", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.1.9", + "@vitest/utils": "4.1.10", "pathe": "^2.0.3" }, "funding": { @@ -3040,14 +3049,14 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.9.tgz", - "integrity": "sha512-Jc7RKGNBo8Z28WYIm0Niej4xdSPByRf6mU58VpHQkd6Zh05rlnA+twjbK5HyeIGHxrzsc3mJgS43uM0CZKzaIA==", + "version": "4.1.10", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@vitest/snapshot/-/snapshot-4.1.10.tgz", + "integrity": "sha1-fj6f7H1NRyMuSTz9y9IXDeQ3HAQ=", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.9", - "@vitest/utils": "4.1.9", + "@vitest/pretty-format": "4.1.10", + "@vitest/utils": "4.1.10", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -3056,9 +3065,9 @@ } }, "node_modules/@vitest/spy": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.9.tgz", - "integrity": "sha512-fHpsS6mIi+PiEW+vcRVOMkX1oSaPKne3VOclSFICPcGOmfKgXPU5iAah+wcNcj2xPrCCmfq99IDGf+EojhhvhA==", + "version": "4.1.10", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@vitest/spy/-/spy-4.1.10.tgz", + "integrity": "sha1-XAv6l7Vrup43QDyXbbd2/2q1b2U=", "dev": true, "license": "MIT", "funding": { @@ -3066,13 +3075,13 @@ } }, "node_modules/@vitest/utils": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.9.tgz", - "integrity": "sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA==", + "version": "4.1.10", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@vitest/utils/-/utils-4.1.10.tgz", + "integrity": "sha1-/8cQVfGL/Msf0FhjZevCgkiS5AM=", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.9", + "@vitest/pretty-format": "4.1.10", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" }, @@ -3082,8 +3091,8 @@ }, "node_modules/accepts": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha1-u89LpQdUZ/PyEx6rPP/HPC9deJU=", "license": "MIT", "dependencies": { "mime-types": "^3.0.0", @@ -3095,8 +3104,8 @@ }, "node_modules/acorn": { "version": "8.17.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", - "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/acorn/-/acorn-8.17.0.tgz", + "integrity": "sha1-F4WtuE+vjYrdEDabk4Jvwr0I8f4=", "dev": true, "license": "MIT", "bin": { @@ -3108,8 +3117,8 @@ }, "node_modules/acorn-jsx": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha1-ftW7VZCLOy8bxVxq8WU7rafweTc=", "dev": true, "license": "MIT", "peerDependencies": { @@ -3118,8 +3127,8 @@ }, "node_modules/ajv": { "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha1-MEs2Nq3Yi6fZNnYN1Q7OAG3qlfk=", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -3134,8 +3143,8 @@ }, "node_modules/ajv-formats": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha1-PV3HYryhdnnDwup+kK1rdTIwlXg=", "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -3151,8 +3160,8 @@ }, "node_modules/ansi-regex": { "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha1-YCFu6kZNhkWXzigyAAc4oFiWUME=", "license": "MIT", "engines": { "node": ">=12" @@ -3162,16 +3171,12 @@ } }, "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, + "version": "6.2.3", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha1-wETV3MUhoHZBNHJZehrLHxA8QEE=", "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" @@ -3179,22 +3184,22 @@ }, "node_modules/any-promise": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", "dev": true, "license": "MIT" }, "node_modules/argparse": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha1-JG9Q88p4oyQPbJl+ipvR6sSeSzg=", "dev": true, "license": "Python-2.0" }, "node_modules/assertion-error": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha1-9kGhlrM1aQsQcL8AtudZP+wZC/c=", "dev": true, "license": "MIT", "engines": { @@ -3203,8 +3208,8 @@ }, "node_modules/bail": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", - "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/bail/-/bail-2.0.2.tgz", + "integrity": "sha1-0m9c2P5db4MqMVF7n3w1YEC6bV0=", "license": "MIT", "funding": { "type": "github", @@ -3213,8 +3218,8 @@ }, "node_modules/balanced-match": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha1-v7EGYv7tgZaixi58aOF3IMJ0F5o=", "dev": true, "license": "MIT", "engines": { @@ -3223,8 +3228,8 @@ }, "node_modules/body-parser": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", - "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/body-parser/-/body-parser-2.3.0.tgz", + "integrity": "sha1-bYZi9NjDNgKLismqJCUbDKZLpDc=", "license": "MIT", "dependencies": { "bytes": "^3.1.2", @@ -3247,8 +3252,8 @@ }, "node_modules/body-parser/node_modules/content-type": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", - "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha1-L7Pt5p3/oK94ynxM51iWgGOLVt8=", "license": "MIT", "engines": { "node": ">=18" @@ -3259,9 +3264,9 @@ } }, "node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "version": "5.0.7", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/brace-expansion/-/brace-expansion-5.0.7.tgz", + "integrity": "sha1-Gw5GlltHna1lr3N7SgJ5CgVJgzc=", "dev": true, "license": "MIT", "dependencies": { @@ -3273,8 +3278,8 @@ }, "node_modules/braces": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/braces/-/braces-3.0.3.tgz", + "integrity": "sha1-SQMy9AkZRSJy1VqEgK3AxEE1h4k=", "dev": true, "license": "MIT", "dependencies": { @@ -3286,8 +3291,8 @@ }, "node_modules/bundle-require": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-5.1.0.tgz", - "integrity": "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/bundle-require/-/bundle-require-5.1.0.tgz", + "integrity": "sha1-jbZvQZUNo9d68e8zIvTD4EAJ+u4=", "dev": true, "license": "MIT", "dependencies": { @@ -3302,8 +3307,8 @@ }, "node_modules/bytes": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha1-iwvuuYYFrfGxKPpDhkA8AJ4CIaU=", "license": "MIT", "engines": { "node": ">= 0.8" @@ -3311,8 +3316,8 @@ }, "node_modules/cac": { "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/cac/-/cac-6.7.14.tgz", + "integrity": "sha1-gE4eb1Bu42PLDjzLsJytXdmHCVk=", "dev": true, "license": "MIT", "engines": { @@ -3321,8 +3326,8 @@ }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha1-S1QowiK+mF15w9gmV0edvgtZstY=", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -3334,8 +3339,8 @@ }, "node_modules/call-bound": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha1-I43pNdKippKSjFOMfM+pEGf9Bio=", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -3350,8 +3355,8 @@ }, "node_modules/callsites": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha1-s2MKvYlDQy9Us/BRkjjjPNffL3M=", "dev": true, "license": "MIT", "engines": { @@ -3360,8 +3365,8 @@ }, "node_modules/ccount": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", - "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha1-F6O/gjAuCHDW2kOgExGovAKj7PU=", "license": "MIT", "funding": { "type": "github", @@ -3370,8 +3375,8 @@ }, "node_modules/chai": { "version": "6.2.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", - "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/chai/-/chai-6.2.2.tgz", + "integrity": "sha1-rkG1LJrKh3NFBTYnF/MlX6zaNg4=", "dev": true, "license": "MIT", "engines": { @@ -3380,8 +3385,8 @@ }, "node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", "dev": true, "license": "MIT", "dependencies": { @@ -3395,10 +3400,26 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha1-7dgDYornHATIWuegkG7a00tkiTc=", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/character-entities": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", - "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha1-LQnC5yzZUjB2zLIRV9/2atQ/zCI=", "license": "MIT", "funding": { "type": "github", @@ -3407,8 +3428,8 @@ }, "node_modules/character-entities-html4": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", - "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha1-HxrblAyXGksiujndymthjcblays=", "license": "MIT", "funding": { "type": "github", @@ -3417,8 +3438,8 @@ }, "node_modules/character-entities-legacy": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", - "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha1-dryDqQc4kB17wiOp6TdZ/dVgEls=", "license": "MIT", "funding": { "type": "github", @@ -3427,8 +3448,8 @@ }, "node_modules/character-reference-invalid": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", - "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha1-hcZrBB5DtHIQ+vQBJ4q/gIrEXLk=", "license": "MIT", "funding": { "type": "github", @@ -3437,8 +3458,8 @@ }, "node_modules/chart.js": { "version": "4.5.1", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz", - "integrity": "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/chart.js/-/chart.js-4.5.1.tgz", + "integrity": "sha1-Gd0amjhqP2OXaRZyIxy1/JwFLDU=", "license": "MIT", "dependencies": { "@kurkle/color": "^0.3.0" @@ -3449,8 +3470,8 @@ }, "node_modules/chokidar": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha1-e+N6TAPJruHs/oYqSiOyxwwgXTA=", "dev": true, "license": "MIT", "dependencies": { @@ -3465,8 +3486,8 @@ }, "node_modules/cliui": { "version": "9.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", - "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha1-b3iQ84b28feZU63B943sRvzC0pE=", "license": "ISC", "dependencies": { "string-width": "^7.2.0", @@ -3479,8 +3500,8 @@ }, "node_modules/codemirror": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.2.tgz", - "integrity": "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/codemirror/-/codemirror-6.0.2.tgz", + "integrity": "sha1-TT/qGtYLZ1P5fKg18vSMaTaolG4=", "license": "MIT", "dependencies": { "@codemirror/autocomplete": "^6.0.0", @@ -3494,8 +3515,8 @@ }, "node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=", "dev": true, "license": "MIT", "dependencies": { @@ -3507,15 +3528,15 @@ }, "node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=", "dev": true, "license": "MIT" }, "node_modules/comma-separated-tokens": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", - "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha1-TonJRYrLYbyP7xn0UplzsjkoOe4=", "license": "MIT", "funding": { "type": "github", @@ -3524,8 +3545,8 @@ }, "node_modules/commander": { "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/commander/-/commander-8.3.0.tgz", + "integrity": "sha1-SDfqGy2me5xhamevuw+v7lZ7ymY=", "license": "MIT", "engines": { "node": ">= 12" @@ -3533,22 +3554,22 @@ }, "node_modules/concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true, "license": "MIT" }, "node_modules/confbox": { "version": "0.1.8", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", - "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha1-gg1z07PILZvZEGUsXU1Znvj/iwY=", "dev": true, "license": "MIT" }, "node_modules/consola": { "version": "3.4.2", - "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", - "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/consola/-/consola-3.4.2.tgz", + "integrity": "sha1-WvEQFFOXu2ev2rdwE/3DTK5ZDqc=", "dev": true, "license": "MIT", "engines": { @@ -3557,8 +3578,8 @@ }, "node_modules/content-disposition": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", - "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha1-89t4nHUtRVZMx+nh4LMXkNSjjhc=", "license": "MIT", "engines": { "node": ">=18" @@ -3570,8 +3591,8 @@ }, "node_modules/content-type": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha1-i3cxYmVtHRCGeEyPI6VM5tc9eRg=", "license": "MIT", "engines": { "node": ">= 0.6" @@ -3579,15 +3600,15 @@ }, "node_modules/convert-source-map": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha1-S1YPZJ/E6RjdCrdc9JYei8iC2Co=", "dev": true, "license": "MIT" }, "node_modules/cookie": { "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha1-VWNpxHKiupEPKXmJG1JrNDYjftc=", "license": "MIT", "engines": { "node": ">= 0.6" @@ -3595,8 +3616,8 @@ }, "node_modules/cookie-signature": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha1-V8f8PMKTrKuf7FTXPhVpDr5KF5M=", "license": "MIT", "engines": { "node": ">=6.6.0" @@ -3604,8 +3625,8 @@ }, "node_modules/cors": { "version": "2.8.6", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", - "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/cors/-/cors-2.8.6.tgz", + "integrity": "sha1-/13Wm9leVHUDgg0pq6T4+vjf7JY=", "license": "MIT", "dependencies": { "object-assign": "^4", @@ -3620,15 +3641,15 @@ } }, "node_modules/crelt": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", - "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==", + "version": "1.0.7", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/crelt/-/crelt-1.0.7.tgz", + "integrity": "sha1-O0QbLd+nMWHWoncKpM1nf4leryg=", "license": "MIT" }, "node_modules/cross-spawn": { "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha1-ilj+ePANzXDDcEUXWd+/rwPo7p8=", "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -3641,14 +3662,14 @@ }, "node_modules/csstype": { "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha1-7EjA8+mT5QZIyG2lWeJhCZXPmJo=", "license": "MIT" }, "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==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha1-Ff7DOyN/l6xdfJhtx32ic6jtC7U=", "license": "ISC", "dependencies": { "internmap": "1 - 2" @@ -3659,8 +3680,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==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha1-OVsoM9+scVB/EqwvevI7+BneJOI=", "license": "ISC", "engines": { "node": ">=12" @@ -3668,8 +3689,8 @@ }, "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==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha1-mBaQOHM6ClurvtpVBU95W7nkpYs=", "license": "ISC", "dependencies": { "delaunator": "5" @@ -3680,8 +3701,8 @@ }, "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==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha1-X8dShOnCN1w2yDlBGgz1UMv8TV4=", "license": "ISC", "engines": { "node": ">=12" @@ -3689,8 +3710,8 @@ }, "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==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha1-xjr5ePTWoNCEpSpnOSK+IWB4m3M=", "license": "ISC", "dependencies": { "commander": "7", @@ -3714,8 +3735,8 @@ }, "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==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/commander/-/commander-7.2.0.tgz", + "integrity": "sha1-o2y1fQtQHOEI5NIFWaFQo5HZerc=", "license": "MIT", "engines": { "node": ">= 10" @@ -3723,8 +3744,8 @@ }, "node_modules/d3-dsv/node_modules/iconv-lite": { "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha1-pS+AvzjaGVLrXGgXkHGYcaGnJQE=", "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -3735,8 +3756,8 @@ }, "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==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha1-Piuhph5wiI/j2RlOMNbRTuzhVcQ=", "license": "ISC", "dependencies": { "d3-dispatch": "1 - 3", @@ -3749,8 +3770,8 @@ }, "node_modules/d3-format": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", - "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha1-Af20a1i+sfVbELQq1wtuNE1esq4=", "license": "ISC", "engines": { "node": ">=12" @@ -3758,8 +3779,8 @@ }, "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==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha1-YCfPUSRvmy69ZPmeAdx8M2QDOk0=", "license": "ISC", "dependencies": { "d3-array": "2.5.0 - 3" @@ -3770,8 +3791,8 @@ }, "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==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/d3-geo-projection/-/d3-geo-projection-4.0.0.tgz", + "integrity": "sha1-3CKeXq140xhppOh88fRb0nFsSMo=", "license": "ISC", "dependencies": { "commander": "7", @@ -3791,8 +3812,8 @@ }, "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==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/commander/-/commander-7.2.0.tgz", + "integrity": "sha1-o2y1fQtQHOEI5NIFWaFQo5HZerc=", "license": "MIT", "engines": { "node": ">= 10" @@ -3800,8 +3821,8 @@ }, "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==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha1-sBzULB7tPUbbd6WWbPcm+MCRYMY=", "license": "ISC", "engines": { "node": ">=12" @@ -3809,8 +3830,8 @@ }, "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==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha1-PEeqWzLFs9+1bvP9Q0IHimMrQA0=", "license": "ISC", "dependencies": { "d3-color": "1 - 3" @@ -3821,8 +3842,8 @@ }, "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==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha1-It+TkDL7WnGuixgA1h3beFHEJSY=", "license": "ISC", "engines": { "node": ">=12" @@ -3830,8 +3851,8 @@ }, "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==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha1-bco+i+Kzk8mp1RTau9gKkt7vGk8=", "license": "ISC", "engines": { "node": ">=12" @@ -3839,8 +3860,8 @@ }, "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==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha1-grOOjo/3CAdk+Nzsd71L45Nok5Y=", "license": "ISC", "dependencies": { "d3-array": "2.10.0 - 3", @@ -3855,8 +3876,8 @@ }, "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==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha1-NMOdopiyPCDgLxpLI5vQ8i5/ExQ=", "license": "ISC", "dependencies": { "d3-color": "1 - 3", @@ -3868,8 +3889,8 @@ }, "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==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha1-oag5y9m6RfKGdMadf4Vbz5HfxqU=", "license": "ISC", "dependencies": { "d3-path": "^3.1.0" @@ -3880,8 +3901,8 @@ }, "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==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha1-kxDbVumS48AXXh7zheVF5Iqbtcc=", "license": "ISC", "dependencies": { "d3-array": "2 - 3" @@ -3892,8 +3913,8 @@ }, "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==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha1-erUlelBB0R7LT+cKXH0WoZW7QIo=", "license": "ISC", "dependencies": { "d3-time": "1 - 3" @@ -3904,8 +3925,8 @@ }, "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==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha1-YoTSonCChbGrt+IB7aQ4CvNeY7A=", "license": "ISC", "engines": { "node": ">=12" @@ -3913,8 +3934,8 @@ }, "node_modules/debug": { "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/debug/-/debug-4.4.3.tgz", + "integrity": "sha1-xq5DLZvZZiWC/OCHCbA4xY6ePWo=", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -3930,8 +3951,8 @@ }, "node_modules/decode-named-character-reference": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", - "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha1-PkBgN2CHTC5YZ2kbWZ1zp9oltT8=", "license": "MIT", "dependencies": { "character-entities": "^2.0.0" @@ -3943,15 +3964,15 @@ }, "node_modules/deep-is": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha1-pvLc5hL63S7x9Rm3NVHxfoUZmDE=", "dev": true, "license": "MIT" }, "node_modules/delaunator": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.1.0.tgz", - "integrity": "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/delaunator/-/delaunator-5.1.0.tgz", + "integrity": "sha1-0TJx+/Ov9nU/nqbiNVV/IJAQRuo=", "license": "ISC", "dependencies": { "robust-predicates": "^3.0.2" @@ -3959,8 +3980,8 @@ }, "node_modules/depd": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/depd/-/depd-2.0.0.tgz", + "integrity": "sha1-tpYWPMdXVg0JzyLMj60Vcbeedt8=", "license": "MIT", "engines": { "node": ">= 0.8" @@ -3968,8 +3989,8 @@ }, "node_modules/dequal": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha1-JkQhTxmX057Q7g7OcjNUkKesZ74=", "license": "MIT", "engines": { "node": ">=6" @@ -3977,8 +3998,8 @@ }, "node_modules/detect-libc": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha1-aJxdzcGQDvVYOky59te0c3QgdK0=", "dev": true, "license": "Apache-2.0", "engines": { @@ -3987,8 +4008,8 @@ }, "node_modules/devlop": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", - "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha1-TbfCyk3G4Og0wwvnDJS7yXbccBg=", "license": "MIT", "dependencies": { "dequal": "^2.0.0" @@ -4000,8 +4021,8 @@ }, "node_modules/dunder-proto": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha1-165mfh3INIL4tw/Q9u78UNow9Yo=", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -4014,8 +4035,8 @@ }, "node_modules/echarts": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/echarts/-/echarts-6.1.0.tgz", - "integrity": "sha512-q0yaFPggC9FUdsWH4blavRWFmxdrIodbkoKNAjJudAI6CA9gNPxHtV2RcZNEepZVlk4yvBYkOkbk6HIVpIyHZA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/echarts/-/echarts-6.1.0.tgz", + "integrity": "sha1-rg9oWQ9eu9co2QCQfCes3nxUVtE=", "license": "Apache-2.0", "dependencies": { "tslib": "2.3.0", @@ -4024,20 +4045,20 @@ }, "node_modules/ee-first": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", "license": "MIT" }, "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==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha1-vz1uj3+P0ipl2XA0dbwBRzV6aw0=", "license": "MIT" }, "node_modules/encodeurl": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha1-e46omAd9fkCdOsRUdOo46vCFelg=", "license": "MIT", "engines": { "node": ">= 0.8" @@ -4045,8 +4066,8 @@ }, "node_modules/entities": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/entities/-/entities-6.0.1.tgz", + "integrity": "sha1-wow0pDN5yn9h0HQTCy9fcCCjBpQ=", "license": "BSD-2-Clause", "engines": { "node": ">=0.12" @@ -4057,8 +4078,8 @@ }, "node_modules/es-define-property": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha1-mD6y+aZyTpMD9hrd8BHHLgngsPo=", "license": "MIT", "engines": { "node": ">= 0.4" @@ -4066,24 +4087,24 @@ }, "node_modules/es-errors": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha1-BfdaJdq5jk+x3NXhRywFRtUFfI8=", "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/es-module-lexer": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", - "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", + "version": "2.3.1", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/es-module-lexer/-/es-module-lexer-2.3.1.tgz", + "integrity": "sha1-W/LfBpmdu+XwBqX0ahH7n1t7ORs=", "dev": true, "license": "MIT" }, "node_modules/es-object-atoms": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", - "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha1-otCzcyBXJN+lJdI7DD4bHKWCyZs=", "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -4094,8 +4115,8 @@ }, "node_modules/esbuild": { "version": "0.28.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", - "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha1-70W0Y0ycnZeilq6kEUpfmED5VXg=", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -4136,8 +4157,8 @@ }, "node_modules/escalade": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha1-ARo/aYVroYnf+n3I/M6Z0qh5A+U=", "license": "MIT", "engines": { "node": ">=6" @@ -4145,27 +4166,26 @@ }, "node_modules/escape-html": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", "license": "MIT" }, "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, + "version": "5.0.0", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha1-RoMSa1ALYXYvLb66zhgG6L4xscg=", "license": "MIT", "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/eslint": { - "version": "9.39.4", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", - "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", + "version": "9.39.5", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/eslint/-/eslint-9.39.5.tgz", + "integrity": "sha1-Kk48iw91MZbvrpQ8j/qocw/Go/o=", "dev": true, "license": "MIT", "dependencies": { @@ -4174,8 +4194,8 @@ "@eslint/config-array": "^0.21.2", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.5", - "@eslint/js": "9.39.4", + "@eslint/eslintrc": "^3.3.6", + "@eslint/js": "9.39.5", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", @@ -4224,8 +4244,8 @@ }, "node_modules/eslint-plugin-unused-imports": { "version": "4.4.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.4.1.tgz", - "integrity": "sha512-oZGYUz1X3sRMGUB+0cZyK2VcvRX5lm/vB56PgNNcU+7ficUCKm66oZWKUubXWnOuPjQ8PvmXtCViXBMONPe7tQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.4.1.tgz", + "integrity": "sha1-qDHwopN9djHrowy4cJGrfTpdoOE=", "dev": true, "license": "MIT", "peerDependencies": { @@ -4240,8 +4260,8 @@ }, "node_modules/eslint-scope": { "version": "8.4.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", - "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha1-iOZGogf61hQ2/6OetQUUcgBlXII=", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -4257,8 +4277,8 @@ }, "node_modules/eslint-visitor-keys": { "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha1-DNcv6FUOPC6uFWqWpN3c0cisWAA=", "dev": true, "license": "Apache-2.0", "engines": { @@ -4270,8 +4290,8 @@ }, "node_modules/eslint/node_modules/ajv": { "version": "6.15.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", - "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha1-B+mCx0YmFnqnoklcU4F4ktcTlJI=", "dev": true, "license": "MIT", "dependencies": { @@ -4287,15 +4307,15 @@ }, "node_modules/eslint/node_modules/balanced-match": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha1-6D46fj8wCzTLnYf2FfoMvzV2kO4=", "dev": true, "license": "MIT" }, "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", - "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "version": "1.1.16", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/brace-expansion/-/brace-expansion-1.1.16.tgz", + "integrity": "sha1-cj06MMBVjCJavJ/Eeac+FOJsPC8=", "dev": true, "license": "MIT", "dependencies": { @@ -4303,10 +4323,23 @@ "concat-map": "0.0.1" } }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha1-FLqDpdNz49MR5a/KKc9b+tllvzQ=", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/eslint/node_modules/eslint-visitor-keys": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha1-TP6mD+fdCtjoFuHtAmwdUlG1EsE=", "dev": true, "license": "Apache-2.0", "engines": { @@ -4318,8 +4351,8 @@ }, "node_modules/eslint/node_modules/ignore": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha1-PNQOcp82Q/2HywTlC/DrcivFlvU=", "dev": true, "license": "MIT", "engines": { @@ -4328,15 +4361,15 @@ }, "node_modules/eslint/node_modules/json-schema-traverse": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=", "dev": true, "license": "MIT" }, "node_modules/eslint/node_modules/minimatch": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha1-WAyI+NVEXyvWqo88re+g3nn71p4=", "dev": true, "license": "ISC", "dependencies": { @@ -4348,8 +4381,8 @@ }, "node_modules/espree": { "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/espree/-/espree-10.4.0.tgz", + "integrity": "sha1-1U9JSdRikAWh+haNk3w/8ffiqDc=", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -4366,8 +4399,8 @@ }, "node_modules/espree/node_modules/eslint-visitor-keys": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha1-TP6mD+fdCtjoFuHtAmwdUlG1EsE=", "dev": true, "license": "Apache-2.0", "engines": { @@ -4379,8 +4412,8 @@ }, "node_modules/esquery": { "version": "1.7.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", - "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha1-CNBI8mHw3e21uulfRoCUY9nJSW0=", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -4392,8 +4425,8 @@ }, "node_modules/esrecurse": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha1-eteWTWeauyi+5yzsY3WLHF0smSE=", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -4405,8 +4438,8 @@ }, "node_modules/estraverse": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha1-LupSkHAvJquP5TcDcP+GyWXSESM=", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -4415,8 +4448,8 @@ }, "node_modules/estree-util-is-identifier-name": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", - "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha1-C170xP8TUIs03NAez6lF9h/OXb0=", "license": "MIT", "funding": { "type": "opencollective", @@ -4425,8 +4458,8 @@ }, "node_modules/estree-walker": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha1-Z8PlSexAKkh7T8GT0ZU6UkdSNA0=", "dev": true, "license": "MIT", "dependencies": { @@ -4435,8 +4468,8 @@ }, "node_modules/esutils": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha1-dNLrTeC42hKTcRkQ1Qd1ubcQ72Q=", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -4445,8 +4478,8 @@ }, "node_modules/etag": { "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", "license": "MIT", "engines": { "node": ">= 0.6" @@ -4454,8 +4487,8 @@ }, "node_modules/eventsource": { "version": "3.0.7", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", - "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha1-EVdiLi9Td7tq7yEUNycougwVaYk=", "license": "MIT", "dependencies": { "eventsource-parser": "^3.0.1" @@ -4466,17 +4499,17 @@ }, "node_modules/eventsource-parser": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.1.0.tgz", - "integrity": "sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/eventsource-parser/-/eventsource-parser-3.1.0.tgz", + "integrity": "sha1-ThmOuRzTM9Co3cwDZQKzYYol9Ek=", "license": "MIT", "engines": { "node": ">=18.0.0" } }, "node_modules/expect-type": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", - "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "version": "1.4.0", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha1-JO338MxppE0AhWe6RZSrlvPDo9Y=", "dev": true, "license": "Apache-2.0", "engines": { @@ -4485,8 +4518,8 @@ }, "node_modules/express": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", - "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/express/-/express-5.2.1.tgz", + "integrity": "sha1-jyHRW20yf5K0eU7PjLCKcvlWrAQ=", "license": "MIT", "dependencies": { "accepts": "^2.0.0", @@ -4527,11 +4560,12 @@ } }, "node_modules/express-rate-limit": { - "version": "8.5.2", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.5.2.tgz", - "integrity": "sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==", + "version": "8.6.0", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/express-rate-limit/-/express-rate-limit-8.6.0.tgz", + "integrity": "sha1-LmSrEDYdo1iBUZ6pK0JqQ/iqjHk=", "license": "MIT", "dependencies": { + "debug": "^4.4.3", "ip-address": "^10.2.0" }, "engines": { @@ -4546,40 +4580,40 @@ }, "node_modules/extend": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/extend/-/extend-3.0.2.tgz", + "integrity": "sha1-+LETa0Bx+9jrFAr/hYsQGewpFfo=", "license": "MIT" }, "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==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU=", "license": "MIT" }, "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==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/fast-json-patch/-/fast-json-patch-3.1.1.tgz", + "integrity": "sha1-hQZOobHr+Xo/etAeI/kzfnLGaUc=", "license": "MIT" }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha1-h0v2nG9ATCtdmcSBNBOZ/VWJJjM=", "dev": true, "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true, "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", - "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", + "version": "3.1.3", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/fast-uri/-/fast-uri-3.1.3.tgz", + "integrity": "sha1-9pWkDwBqulBWMVc6ACHdshGUrRE=", "funding": [ { "type": "github", @@ -4594,8 +4628,8 @@ }, "node_modules/fault": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", - "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/fault/-/fault-1.0.4.tgz", + "integrity": "sha1-6vz8Cm0hT8lGAeFw3ymVSk+ELxM=", "license": "MIT", "dependencies": { "format": "^0.2.0" @@ -4607,8 +4641,8 @@ }, "node_modules/fdir": { "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha1-7Sq5Z6MxreYvGNB32uGSaE1Q01A=", "dev": true, "license": "MIT", "engines": { @@ -4625,8 +4659,8 @@ }, "node_modules/file-entry-cache": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha1-d4e93PETG/+5JjbGlFe7wO3W2B8=", "dev": true, "license": "MIT", "dependencies": { @@ -4638,8 +4672,8 @@ }, "node_modules/fill-range": { "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha1-RCZdPKwH4+p9wkdRY4BkN1SgUpI=", "dev": true, "license": "MIT", "dependencies": { @@ -4651,8 +4685,8 @@ }, "node_modules/finalhandler": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", - "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha1-osUXplWYUrzbBtH4vX9Rto+tgJk=", "license": "MIT", "dependencies": { "debug": "^4.4.0", @@ -4672,8 +4706,8 @@ }, "node_modules/find-up": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha1-TJKBnstwg1YeT0okCoa+UZj1Nvw=", "dev": true, "license": "MIT", "dependencies": { @@ -4689,8 +4723,8 @@ }, "node_modules/fix-dts-default-cjs-exports": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fix-dts-default-cjs-exports/-/fix-dts-default-cjs-exports-1.0.1.tgz", - "integrity": "sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/fix-dts-default-cjs-exports/-/fix-dts-default-cjs-exports-1.0.1.tgz", + "integrity": "sha1-lVy2s9UZaRxXgosHitrfLLkulUk=", "dev": true, "license": "MIT", "dependencies": { @@ -4701,8 +4735,8 @@ }, "node_modules/flat-cache": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha1-Ds45/LFO4BL0sEEL0z3ZwfAREnw=", "dev": true, "license": "MIT", "dependencies": { @@ -4715,8 +4749,8 @@ }, "node_modules/flatted": { "version": "3.4.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", - "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha1-9cI8EH8PN96NvfJPE3IrO5jVJyY=", "dev": true, "license": "ISC" }, @@ -4734,16 +4768,16 @@ }, "node_modules/format": { "version": "0.2.2", - "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", - "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/format/-/format-0.2.2.tgz", + "integrity": "sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs=", "engines": { "node": ">=0.4.x" } }, "node_modules/forwarded": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha1-ImmTZCiq1MFcfr6XeahL8LKoGBE=", "license": "MIT", "engines": { "node": ">= 0.6" @@ -4751,8 +4785,8 @@ }, "node_modules/fresh": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha1-jdffahs6Gzpc8YbAWl3SZ2ImNaQ=", "license": "MIT", "engines": { "node": ">= 0.8" @@ -4760,10 +4794,9 @@ }, "node_modules/fsevents": { "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha1-ysZAd4XQNnWipeGlMFxpezR9kNY=", "dev": true, - "hasInstallScript": true, "license": "MIT", "optional": true, "os": [ @@ -4775,8 +4808,8 @@ }, "node_modules/function-bind": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha1-LALYZNl/PqbIgwxGTL0Rq26rehw=", "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4784,8 +4817,8 @@ }, "node_modules/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==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha1-T5RBKoLbMvNuOwuXQfipf+sDH34=", "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" @@ -4793,8 +4826,8 @@ }, "node_modules/get-east-asian-width": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", - "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha1-IWkA+R3xGossGYw+HZPWwDWndrk=", "license": "MIT", "engines": { "node": ">=18" @@ -4805,8 +4838,8 @@ }, "node_modules/get-intrinsic": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha1-dD8OO2lkqTpUke0b/6rgVNf5jQE=", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -4829,8 +4862,8 @@ }, "node_modules/get-proto": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha1-FQs/J0OGnvPoUewMSdFbHRTQDuE=", "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", @@ -4842,8 +4875,8 @@ }, "node_modules/glob": { "version": "13.0.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", - "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/glob/-/glob-13.0.6.tgz", + "integrity": "sha1-B4ZmVmpCUUfMrPvS4zLetmor5x0=", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -4860,8 +4893,8 @@ }, "node_modules/glob-parent": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha1-bSN9mQg5UMeSkPJMdkKj3poo+eM=", "dev": true, "license": "ISC", "dependencies": { @@ -4873,8 +4906,8 @@ }, "node_modules/globals": { "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/globals/-/globals-14.0.0.tgz", + "integrity": "sha1-iY10E8Kbq89rr+Vvyt3thYrack4=", "dev": true, "license": "MIT", "engines": { @@ -4886,8 +4919,8 @@ }, "node_modules/gopd": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha1-ifVrghe9vIgCvSmd9tfxCB1+UaE=", "license": "MIT", "engines": { "node": ">= 0.4" @@ -4898,8 +4931,8 @@ }, "node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=", "dev": true, "license": "MIT", "engines": { @@ -4908,8 +4941,8 @@ }, "node_modules/has-symbols": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha1-/JxqeDoISVHQuXH+EBjegTcHozg=", "license": "MIT", "engines": { "node": ">= 0.4" @@ -4920,8 +4953,8 @@ }, "node_modules/hasown": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", - "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha1-jGLYy5C+sqrV0KW2dYGtmFTD8AM=", "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -4932,8 +4965,8 @@ }, "node_modules/hast-util-from-dom": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/hast-util-from-dom/-/hast-util-from-dom-5.0.1.tgz", - "integrity": "sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/hast-util-from-dom/-/hast-util-from-dom-5.0.1.tgz", + "integrity": "sha1-w8kvvY1OHBYl7es6dzlSueStZKg=", "license": "ISC", "dependencies": { "@types/hast": "^3.0.0", @@ -4947,8 +4980,8 @@ }, "node_modules/hast-util-from-html": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", - "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", + "integrity": "sha1-SFx0eFNYvrgMS6Y0YpkxGsTEnII=", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -4965,8 +4998,8 @@ }, "node_modules/hast-util-from-html-isomorphic": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hast-util-from-html-isomorphic/-/hast-util-from-html-isomorphic-2.0.0.tgz", - "integrity": "sha512-zJfpXq44yff2hmE0XmwEOzdWin5xwH+QIhMLOScpX91e/NSGPsAzNCvLQDIEPyO2TXi+lBmU6hjLIhV8MwP2kw==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/hast-util-from-html-isomorphic/-/hast-util-from-html-isomorphic-2.0.0.tgz", + "integrity": "sha1-sxuu44aomaJHIyajxWkvKfhtHTw=", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -4981,8 +5014,8 @@ }, "node_modules/hast-util-from-parse5": { "version": "8.0.3", - "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", - "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", + "integrity": "sha1-gwo1Ai//KMP+o2l6mML0zGuDWi4=", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -5001,8 +5034,8 @@ }, "node_modules/hast-util-is-element": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", - "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha1-bjGmUywhfltTOEjH5Sydk2nKCTI=", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" @@ -5014,8 +5047,8 @@ }, "node_modules/hast-util-parse-selector": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", - "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha1-NSh5+obiVhYDYDfdiTH7XzTLSic=", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" @@ -5027,8 +5060,8 @@ }, "node_modules/hast-util-to-jsx-runtime": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", - "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", + "integrity": "sha1-/zGJeq5Z9iIy4hWU6sfva2MzPpg=", "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", @@ -5054,8 +5087,8 @@ }, "node_modules/hast-util-to-text": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz", - "integrity": "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz", + "integrity": "sha1-V7Z2kx5xv5y4UkU2eElbMIC/rj4=", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -5070,8 +5103,8 @@ }, "node_modules/hast-util-whitespace": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", - "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha1-d3jtnTyS3Z6MXI9kiknCH8UctiE=", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" @@ -5083,8 +5116,8 @@ }, "node_modules/hastscript": { "version": "9.0.1", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", - "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/hastscript/-/hastscript-9.0.1.tgz", + "integrity": "sha1-28hL72BR1ACENCwinEUc2dxWff8=", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -5100,8 +5133,8 @@ }, "node_modules/highlight.js": { "version": "10.7.3", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", - "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha1-aXJy45kTVuQMPKxWanTu9oF1ZTE=", "license": "BSD-3-Clause", "engines": { "node": "*" @@ -5109,14 +5142,14 @@ }, "node_modules/highlightjs-vue": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/highlightjs-vue/-/highlightjs-vue-1.0.0.tgz", - "integrity": "sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/highlightjs-vue/-/highlightjs-vue-1.0.0.tgz", + "integrity": "sha1-/f6X++pjVOcO5E46lVh14RTbCG0=", "license": "CC0-1.0" }, "node_modules/hono": { - "version": "4.12.27", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.27.tgz", - "integrity": "sha512-1yrb/+w6HWQJrUCLkJ2IF5jNIPvvFkblV5RNOYl6bV+OA6p9GLcMpHFFGTosSvHvcAUibuUukRqhlYI4z32C7Q==", + "version": "4.12.30", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/hono/-/hono-4.12.30.tgz", + "integrity": "sha1-TVewUcZmF7ADt7oxiRDLW3nEx6w=", "license": "MIT", "engines": { "node": ">=16.9.0" @@ -5124,8 +5157,8 @@ }, "node_modules/html-parse-stringify": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", - "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha1-38EBc0fOn3fIFBpQfyMwQMWcVdI=", "license": "MIT", "dependencies": { "void-elements": "3.1.0" @@ -5133,8 +5166,8 @@ }, "node_modules/html-url-attributes": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", - "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/html-url-attributes/-/html-url-attributes-3.0.1.tgz", + "integrity": "sha1-g7BSzV5DcHG3Vs10rnD3CIcMLYc=", "license": "MIT", "funding": { "type": "opencollective", @@ -5143,8 +5176,8 @@ }, "node_modules/http-errors": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha1-NtL2W8kJyHkAGN02+02T2myq4Gs=", "license": "MIT", "dependencies": { "depd": "~2.0.0", @@ -5163,8 +5196,8 @@ }, "node_modules/i18next": { "version": "26.3.6", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-26.3.6.tgz", - "integrity": "sha512-Bu5Z2nAXgfVyM8xvW3jk9EKRIuX37PudsrBViThNFx7CR7aaYTpP01cxNB/E4c4UUzTDiAZRstEhsRfPOL/8xA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/i18next/-/i18next-26.3.6.tgz", + "integrity": "sha1-WZ2ydcULZtKKadj2xRYsJFzpKWs=", "funding": [ { "type": "individual", @@ -5190,9 +5223,9 @@ } }, "node_modules/iconv-lite": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", - "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "version": "0.7.3", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha1-hO4S+WPn3lC8AaE+FgoHizsPQV8=", "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -5206,9 +5239,9 @@ } }, "node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "version": "7.0.6", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/ignore/-/ignore-7.0.6.tgz", + "integrity": "sha1-aleq70yQ3yesNZCHXSno8RmIyI4=", "dev": true, "license": "MIT", "engines": { @@ -5217,8 +5250,8 @@ }, "node_modules/import-fresh": { "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha1-nOy1ZQPAraHydB271lRuSxO1fM8=", "dev": true, "license": "MIT", "dependencies": { @@ -5232,10 +5265,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha1-SrzYUq0y3Xuqv+m0DgCjbbXzkuY=", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true, "license": "MIT", "engines": { @@ -5244,20 +5287,20 @@ }, "node_modules/inherits": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w=", "license": "ISC" }, "node_modules/inline-style-parser": { "version": "0.2.7", - "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", - "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/inline-style-parser/-/inline-style-parser-0.2.7.tgz", + "integrity": "sha1-sfxov8AxO4aFdF5EZON/k3a5yQk=", "license": "MIT" }, "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==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha1-ZoXyN1XkPFJOJR0py8lySOMGEAk=", "license": "ISC", "engines": { "node": ">=12" @@ -5265,8 +5308,8 @@ }, "node_modules/ip-address": { "version": "10.2.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", - "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha1-gF/BeLIMUYvUyFSLJP4wiS1/MgY=", "license": "MIT", "engines": { "node": ">= 12" @@ -5274,8 +5317,8 @@ }, "node_modules/ipaddr.js": { "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha1-v/OFQ+64mEglB5/zoqjmy9RngbM=", "license": "MIT", "engines": { "node": ">= 0.10" @@ -5283,8 +5326,8 @@ }, "node_modules/is-alphabetical": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", - "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha1-AQcgU+p8EDbfPH0Zptqux/GeeJs=", "license": "MIT", "funding": { "type": "github", @@ -5293,8 +5336,8 @@ }, "node_modules/is-alphanumerical": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", - "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha1-fAP76W4+kxET5X+WSwo2jMLf2HU=", "license": "MIT", "dependencies": { "is-alphabetical": "^2.0.0", @@ -5307,8 +5350,8 @@ }, "node_modules/is-decimal": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", - "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha1-lGnS3BkNAhT9h9eLeMrswMwU7vc=", "license": "MIT", "funding": { "type": "github", @@ -5317,8 +5360,8 @@ }, "node_modules/is-extglob": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true, "license": "MIT", "engines": { @@ -5327,8 +5370,8 @@ }, "node_modules/is-glob": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha1-ZPYeQsu7LuwgcanawLKLoeZdUIQ=", "dev": true, "license": "MIT", "dependencies": { @@ -5340,8 +5383,8 @@ }, "node_modules/is-hexadecimal": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", - "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha1-hrW/Zo/KMHSY0xnfwDKJ14GpACc=", "license": "MIT", "funding": { "type": "github", @@ -5350,8 +5393,8 @@ }, "node_modules/is-number": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss=", "dev": true, "license": "MIT", "engines": { @@ -5360,8 +5403,8 @@ }, "node_modules/is-plain-obj": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha1-1lAl7ew2V84DL9fbY8l4g+rtcfA=", "license": "MIT", "engines": { "node": ">=12" @@ -5372,20 +5415,20 @@ }, "node_modules/is-promise": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha1-Qv+fhCBsGZHSbev1IN1cAQQt0vM=", "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "license": "ISC" }, "node_modules/jose": { "version": "6.2.3", - "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.3.tgz", - "integrity": "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/jose/-/jose-6.2.3.tgz", + "integrity": "sha1-CXUZetlzJRIhxlijzdxLlRolDC0=", "license": "MIT", "funding": { "url": "https://github.com/sponsors/panva" @@ -5393,8 +5436,8 @@ }, "node_modules/joycon": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", - "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha1-vOhZbWroCPi2gWj1/GkoCZaJTwM=", "dev": true, "license": "MIT", "engines": { @@ -5403,14 +5446,14 @@ }, "node_modules/js-tokens": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha1-GSA/tZmR35jjoocFDUZHzerzJJk=", "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", - "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", + "version": "4.3.0", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/js-yaml/-/js-yaml-4.3.0.tgz", + "integrity": "sha1-0ZAFcqf3zwtfVAyDZz5gutNDZZI=", "dev": true, "funding": [ { @@ -5432,40 +5475,40 @@ }, "node_modules/json-buffer": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha1-kziAKjDTtmBfvgYT4JQAjKjAWhM=", "dev": true, "license": "MIT" }, "node_modules/json-schema-traverse": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha1-rnvLNlard6c7pcSb9lTzjmtoYOI=", "license": "MIT" }, "node_modules/json-schema-typed": { "version": "8.0.2", - "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", - "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha1-6Y7nsYmf9KGEU00fFnwojGa77/Q=", "license": "BSD-2-Clause" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true, "license": "MIT" }, "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==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/json-stringify-pretty-compact/-/json-stringify-pretty-compact-4.0.0.tgz", + "integrity": "sha1-z0hEdwvd7jy4mmFw/ksA7uXb8dQ=", "license": "MIT" }, "node_modules/katex": { "version": "0.17.0", - "resolved": "https://registry.npmjs.org/katex/-/katex-0.17.0.tgz", - "integrity": "sha512-Vdw0ATsQ9V+LuegM/BTwQqV/6cTl5lbGcIrU+BCgLxyf6bo38ybOr372tuSIxir3CN720flu1meYR6XzNMwQnw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/katex/-/katex-0.17.0.tgz", + "integrity": "sha1-U24lh07JrIco47S3v3/sZVe32/Q=", "funding": [ "https://opencollective.com/katex", "https://github.com/sponsors/katex" @@ -5480,8 +5523,8 @@ }, "node_modules/keyv": { "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha1-qHmpnilFL5QkOfKkBeOvizHU3pM=", "dev": true, "license": "MIT", "dependencies": { @@ -5490,8 +5533,8 @@ }, "node_modules/levn": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/levn/-/levn-0.4.1.tgz", + "integrity": "sha1-rkViwAdHO5MqYgDUAyaN0v/8at4=", "dev": true, "license": "MIT", "dependencies": { @@ -5504,8 +5547,8 @@ }, "node_modules/lightningcss": { "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", - "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha1-uFqulkhtyxv0mnyFcSISc/Tx5Kk=", "dev": true, "license": "MPL-2.0", "dependencies": { @@ -5534,8 +5577,8 @@ }, "node_modules/lightningcss-android-arm64": { "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", - "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha1-8DOIURbf79nG9UeHUj41FLYeGWg=", "cpu": [ "arm64" ], @@ -5556,8 +5599,8 @@ }, "node_modules/lightningcss-darwin-arm64": { "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", - "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha1-ULcYcbAcgZlYS2SeKSVH+up6+bU=", "cpu": [ "arm64" ], @@ -5578,8 +5621,8 @@ }, "node_modules/lightningcss-darwin-x64": { "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", - "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha1-NfPpczLRMLnKGB4RtWje1q68bV4=", "cpu": [ "x64" ], @@ -5600,8 +5643,8 @@ }, "node_modules/lightningcss-freebsd-x64": { "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", - "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha1-l3enZHK2Ttb/lDQq1kx7r9eUpXU=", "cpu": [ "x64" ], @@ -5622,8 +5665,8 @@ }, "node_modules/lightningcss-linux-arm-gnueabihf": { "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", - "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha1-E65lLhq3O5E117faFy9mbEEK1T0=", "cpu": [ "arm" ], @@ -5644,8 +5687,8 @@ }, "node_modules/lightningcss-linux-arm64-gnu": { "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", - "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha1-QXhYeVqUWS9oASOhsfnaig4e8zU=", "cpu": [ "arm64" ], @@ -5666,8 +5709,8 @@ }, "node_modules/lightningcss-linux-arm64-musl": { "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", - "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha1-a+NmkugQtxgECAL9gJYjz/5zITM=", "cpu": [ "arm64" ], @@ -5688,8 +5731,8 @@ }, "node_modules/lightningcss-linux-x64-gnu": { "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", - "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha1-C3gDr06yHP043Tn+Kru1PH3QkfY=", "cpu": [ "x64" ], @@ -5710,8 +5753,8 @@ }, "node_modules/lightningcss-linux-x64-musl": { "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", - "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha1-iNyLqGXd3bGsXvBLDxYYBEGMFjs=", "cpu": [ "x64" ], @@ -5732,8 +5775,8 @@ }, "node_modules/lightningcss-win32-arm64-msvc": { "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", - "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha1-TzC6P6XpJfW3n5RejMDRdsOxqzg=", "cpu": [ "arm64" ], @@ -5754,8 +5797,8 @@ }, "node_modules/lightningcss-win32-x64-msvc": { "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", - "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha1-FBqlYFZFBkkokCu0rwRfp9n0Igo=", "cpu": [ "x64" ], @@ -5776,8 +5819,8 @@ }, "node_modules/lilconfig": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha1-obz9Ylf5WFv1rhTO7rt7VZAl5MQ=", "dev": true, "license": "MIT", "engines": { @@ -5789,15 +5832,15 @@ }, "node_modules/lines-and-columns": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha1-7KKE910pZQeTCdwK2SVauy68FjI=", "dev": true, "license": "MIT" }, "node_modules/load-tsconfig": { "version": "0.2.5", - "resolved": "https://registry.npmjs.org/load-tsconfig/-/load-tsconfig-0.2.5.tgz", - "integrity": "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/load-tsconfig/-/load-tsconfig-0.2.5.tgz", + "integrity": "sha1-RTuM2JYb+5Et6nfrbBaP6Myj06E=", "dev": true, "license": "MIT", "engines": { @@ -5806,8 +5849,8 @@ }, "node_modules/locate-path": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha1-VTIeswn+u8WcSAHZMackUqaB0oY=", "dev": true, "license": "MIT", "dependencies": { @@ -5822,15 +5865,15 @@ }, "node_modules/lodash.merge": { "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha1-VYqlO0O2YeGSWgr9+japoQhf5Xo=", "dev": true, "license": "MIT" }, "node_modules/longest-streak": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", - "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha1-YvpnzZWHQqFXSvnzmGY2QQLZDNQ=", "license": "MIT", "funding": { "type": "github", @@ -5839,8 +5882,8 @@ }, "node_modules/loose-envify": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha1-ce5R+nvkyuwaY4OffmgtgTLTDK8=", "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" @@ -5851,8 +5894,8 @@ }, "node_modules/lowlight": { "version": "1.20.0", - "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.20.0.tgz", - "integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/lowlight/-/lowlight-1.20.0.tgz", + "integrity": "sha1-3bGX0zRirQ2TvxnRe2wwGqOUGIg=", "license": "MIT", "dependencies": { "fault": "^1.0.0", @@ -5864,9 +5907,9 @@ } }, "node_modules/lru-cache": { - "version": "11.5.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", - "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", + "version": "11.5.2", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha1-AOFmZckMYg+6FKPDaHMql2ST92A=", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -5875,8 +5918,8 @@ }, "node_modules/magic-string": { "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha1-VnY+wJoPqAkd8nh5/ZTRkHjADZE=", "dev": true, "license": "MIT", "dependencies": { @@ -5885,8 +5928,8 @@ }, "node_modules/markdown-table": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", - "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha1-/kTW1BD/nW8uoXl6P2CqTStjHCo=", "license": "MIT", "funding": { "type": "github", @@ -5895,8 +5938,8 @@ }, "node_modules/math-intrinsics": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha1-oN10voHiqlwvJ+Zc4oNgXuTit/k=", "license": "MIT", "engines": { "node": ">= 0.4" @@ -5904,8 +5947,8 @@ }, "node_modules/mdast-util-find-and-replace": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", - "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", + "integrity": "sha1-cKMXTIlOFN9yKr9DvCUMuuRLEd8=", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -5918,22 +5961,10 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/mdast-util-from-markdown": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz", - "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz", + "integrity": "sha1-yVgiuRqrdfGKTL6LL1G4c+0s8Mc=", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -5956,8 +5987,8 @@ }, "node_modules/mdast-util-gfm": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", - "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha1-LN9juSwqMxQGsPsNtMB3wbAzF1E=", "license": "MIT", "dependencies": { "mdast-util-from-markdown": "^2.0.0", @@ -5975,8 +6006,8 @@ }, "node_modules/mdast-util-gfm-autolink-literal": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", - "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha1-q9VXYwM3vTCm1aS9glLhwtwIddU=", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -5992,8 +6023,8 @@ }, "node_modules/mdast-util-gfm-footnote": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", - "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha1-d3jp2co99yOMwr0/orG/amWxlAM=", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -6009,8 +6040,8 @@ }, "node_modules/mdast-util-gfm-strikethrough": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", - "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha1-1E756O0oOsjBFlqw0N/QWMJ2TBY=", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -6024,8 +6055,8 @@ }, "node_modules/mdast-util-gfm-table": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", - "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha1-ekNftiI6crCGKzOvvXErba6HjTg=", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -6041,8 +6072,8 @@ }, "node_modules/mdast-util-gfm-task-list-item": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", - "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha1-5oCV0vikMD7yQJSrZC4QR7mRqTY=", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -6057,8 +6088,8 @@ }, "node_modules/mdast-util-math": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-math/-/mdast-util-math-3.0.0.tgz", - "integrity": "sha512-Tl9GBNeG/AhJnQM221bJR2HPvLOSnLE/T9cJI9tlc6zwQk2nPk/4f0cHkOdEixQPC/j8UtKDdITswvLAy1OZ1w==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/mdast-util-math/-/mdast-util-math-3.0.0.tgz", + "integrity": "sha1-jXndO6+KuKx4H2K4hTdoGQuaALA=", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -6076,8 +6107,8 @@ }, "node_modules/mdast-util-mdx-expression": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", - "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha1-Q/CrrJrcdW4ghvY4IqOMjTw6UJY=", "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", @@ -6094,8 +6125,8 @@ }, "node_modules/mdast-util-mdx-jsx": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", - "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", + "integrity": "sha1-/QTGeip0me+5BailxXjd3J/a2g0=", "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", @@ -6118,8 +6149,8 @@ }, "node_modules/mdast-util-mdxjs-esm": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", - "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha1-AZz751etYt1VfbNaaV5zFLzJ+pc=", "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", @@ -6136,8 +6167,8 @@ }, "node_modules/mdast-util-phrasing": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", - "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha1-fMCo3sMOrwS3salmGpKtszgqpuM=", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -6150,8 +6181,8 @@ }, "node_modules/mdast-util-to-hast": { "version": "13.2.1", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", - "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha1-1/+EykmaV+LAYK5nVIrZUOaJoFM=", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -6171,8 +6202,8 @@ }, "node_modules/mdast-util-to-markdown": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", - "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha1-+RD/5giX8Eu0t+fuQ0SG92KINhs=", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -6192,8 +6223,8 @@ }, "node_modules/mdast-util-to-string": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", - "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha1-elEhR1VWoE5+3etnsmSq550xKBQ=", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0" @@ -6205,8 +6236,8 @@ }, "node_modules/media-typer": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha1-ardLjy0zIPIGSyqHo455Mf86VWE=", "license": "MIT", "engines": { "node": ">= 0.8" @@ -6214,8 +6245,8 @@ }, "node_modules/merge-descriptors": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha1-6pIvZgY1oiSe5WXgRJ+VHmtgOAg=", "license": "MIT", "engines": { "node": ">=18" @@ -6226,8 +6257,8 @@ }, "node_modules/micromark": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", - "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha1-kTlaPhiEoZjmIRbjPJxWjjmTb9s=", "funding": [ { "type": "GitHub Sponsors", @@ -6261,8 +6292,8 @@ }, "node_modules/micromark-core-commonmark": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", - "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha1-xpFjDkhQIaaM8o28Kyyifr9njNQ=", "funding": [ { "type": "GitHub Sponsors", @@ -6295,8 +6326,8 @@ }, "node_modules/micromark-extension-gfm": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", - "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha1-PhM3arld16XP0OKVYN/pmWV7PFs=", "license": "MIT", "dependencies": { "micromark-extension-gfm-autolink-literal": "^2.0.0", @@ -6315,8 +6346,8 @@ }, "node_modules/micromark-extension-gfm-autolink-literal": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", - "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha1-Yoau6WhsRGLB41UqnVBf7dzuuTU=", "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", @@ -6331,8 +6362,8 @@ }, "node_modules/micromark-extension-gfm-footnote": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", - "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha1-TatW1OOYuYU/b+TvrE/JNh8+B1A=", "license": "MIT", "dependencies": { "devlop": "^1.0.0", @@ -6351,8 +6382,8 @@ }, "node_modules/micromark-extension-gfm-strikethrough": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", - "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha1-hhBt+LOmkrX2qSKA04eb5r5G2SM=", "license": "MIT", "dependencies": { "devlop": "^1.0.0", @@ -6369,8 +6400,8 @@ }, "node_modules/micromark-extension-gfm-table": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", - "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha1-+scLy/Uf5l9fRAMxGNOb6Km1lAs=", "license": "MIT", "dependencies": { "devlop": "^1.0.0", @@ -6386,8 +6417,8 @@ }, "node_modules/micromark-extension-gfm-tagfilter": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", - "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha1-8m2KeAe1mF+6E89hRltYyl/33Fc=", "license": "MIT", "dependencies": { "micromark-util-types": "^2.0.0" @@ -6399,8 +6430,8 @@ }, "node_modules/micromark-extension-gfm-task-list-item": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", - "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha1-vMNNgFY5gpmQ7BdcPuoSu1t4Hyw=", "license": "MIT", "dependencies": { "devlop": "^1.0.0", @@ -6416,8 +6447,8 @@ }, "node_modules/micromark-extension-math": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-math/-/micromark-extension-math-3.1.0.tgz", - "integrity": "sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-extension-math/-/micromark-extension-math-3.1.0.tgz", + "integrity": "sha1-xC7jsd1amgNYToPdjwjj3lECEsE=", "license": "MIT", "dependencies": { "@types/katex": "^0.16.0", @@ -6435,8 +6466,8 @@ }, "node_modules/micromark-extension-math/node_modules/katex": { "version": "0.16.47", - "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.47.tgz", - "integrity": "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/katex/-/katex-0.16.47.tgz", + "integrity": "sha1-ChOkLC3rT3TmHxYtRAuRZaVIAw8=", "funding": [ "https://opencollective.com/katex", "https://github.com/sponsors/katex" @@ -6451,8 +6482,8 @@ }, "node_modules/micromark-factory-destination": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", - "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha1-j++OD3CB8EdPvdkt61DJkKAmRjk=", "funding": [ { "type": "GitHub Sponsors", @@ -6472,8 +6503,8 @@ }, "node_modules/micromark-factory-label": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", - "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha1-UmfvqX8eUlTvx/ILRZo4yyEFi6E=", "funding": [ { "type": "GitHub Sponsors", @@ -6494,8 +6525,8 @@ }, "node_modules/micromark-factory-space": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", - "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha1-NtAhLpYrKzEh+FJfx6PHwCnzNPw=", "funding": [ { "type": "GitHub Sponsors", @@ -6514,8 +6545,8 @@ }, "node_modules/micromark-factory-title": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", - "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha1-I35KpdWKlYY/AQMtnumwkPHebpQ=", "funding": [ { "type": "GitHub Sponsors", @@ -6536,8 +6567,8 @@ }, "node_modules/micromark-factory-whitespace": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", - "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha1-BrJrKYPE0nv8xlezPiUTTUhosLE=", "funding": [ { "type": "GitHub Sponsors", @@ -6558,8 +6589,8 @@ }, "node_modules/micromark-util-character": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha1-L5h4MaQNTFEKwmHomFLE6XA8zaY=", "funding": [ { "type": "GitHub Sponsors", @@ -6578,8 +6609,8 @@ }, "node_modules/micromark-util-chunked": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", - "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha1-R/vNk0caP8yrhs/wOEf8NVLbEFE=", "funding": [ { "type": "GitHub Sponsors", @@ -6597,8 +6628,8 @@ }, "node_modules/micromark-util-classify-character": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", - "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha1-05n6+cRcoUyLS+mLHqSBvO2Htik=", "funding": [ { "type": "GitHub Sponsors", @@ -6618,8 +6649,8 @@ }, "node_modules/micromark-util-combine-extensions": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", - "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha1-Kg9JCrCL/1zC/V7sbdDKBPibMKk=", "funding": [ { "type": "GitHub Sponsors", @@ -6638,8 +6669,8 @@ }, "node_modules/micromark-util-decode-numeric-character-reference": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", - "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha1-/PFbZgl5OI5vEYzba/fXnXPSb+U=", "funding": [ { "type": "GitHub Sponsors", @@ -6657,8 +6688,8 @@ }, "node_modules/micromark-util-decode-string": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", - "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha1-bLmVguXScehO/KjmGoB5lNcWHrI=", "funding": [ { "type": "GitHub Sponsors", @@ -6679,8 +6710,8 @@ }, "node_modules/micromark-util-encode": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", - "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha1-DVHRwJVVHPqsNoMmljz1XxX1QLg=", "funding": [ { "type": "GitHub Sponsors", @@ -6695,8 +6726,8 @@ }, "node_modules/micromark-util-html-tag-name": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", - "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha1-5AQDCWSBmGtBwQZif5j3LU0QuCU=", "funding": [ { "type": "GitHub Sponsors", @@ -6711,8 +6742,8 @@ }, "node_modules/micromark-util-normalize-identifier": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", - "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha1-ww13sugyrPZSb4vxqke8nJQ4wW0=", "funding": [ { "type": "GitHub Sponsors", @@ -6730,8 +6761,8 @@ }, "node_modules/micromark-util-resolve-all": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", - "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha1-4aLWLN0jcjCirhGDkCexk4HjHos=", "funding": [ { "type": "GitHub Sponsors", @@ -6749,8 +6780,8 @@ }, "node_modules/micromark-util-sanitize-uri": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", - "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha1-q4l4m4GKWHUrc9a1UjhiG3+qj9c=", "funding": [ { "type": "GitHub Sponsors", @@ -6770,8 +6801,8 @@ }, "node_modules/micromark-util-subtokenize": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", - "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha1-2K3lug8xl6HPaimZ+7/mNXoaGe4=", "funding": [ { "type": "GitHub Sponsors", @@ -6792,8 +6823,8 @@ }, "node_modules/micromark-util-symbol": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha1-5dpJTo6ysHGg0I+zT2zv7GwKGbg=", "funding": [ { "type": "GitHub Sponsors", @@ -6808,8 +6839,8 @@ }, "node_modules/micromark-util-types": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", - "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha1-8AIl9fWg68MlT5bDa2YFxLOTkI4=", "funding": [ { "type": "GitHub Sponsors", @@ -6824,8 +6855,8 @@ }, "node_modules/micromatch": { "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha1-1m+hjzpHB2eJMgubGvMr2G2fogI=", "dev": true, "license": "MIT", "dependencies": { @@ -6838,8 +6869,8 @@ }, "node_modules/micromatch/node_modules/picomatch": { "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha1-WpQpFeJrNy3A8OZ1MUmhbmscVgE=", "dev": true, "license": "MIT", "engines": { @@ -6851,8 +6882,8 @@ }, "node_modules/mime-db": { "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha1-zds+5PnGRTDf9kAjZmHULLajFPU=", "license": "MIT", "engines": { "node": ">= 0.6" @@ -6860,8 +6891,8 @@ }, "node_modules/mime-types": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha1-OQAtQYJXXVrwNv+hGBAPJSSy4qs=", "license": "MIT", "dependencies": { "mime-db": "^1.54.0" @@ -6876,8 +6907,8 @@ }, "node_modules/minimatch": { "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha1-vUhoegvjjtKWE5kQVgD4MglYYdE=", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -6892,8 +6923,8 @@ }, "node_modules/minipass": { "version": "7.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", - "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha1-eTibTrG7LQA6m7qH1JLyvTe9xls=", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -6902,8 +6933,8 @@ }, "node_modules/mlly": { "version": "1.8.2", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz", - "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/mlly/-/mlly-1.8.2.tgz", + "integrity": "sha1-5/eRmoLROxdEBWExFySaP0SdeLs=", "dev": true, "license": "MIT", "dependencies": { @@ -6915,14 +6946,14 @@ }, "node_modules/ms": { "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/ms/-/ms-2.1.3.tgz", + "integrity": "sha1-V0yBOM4dK1hh8LRFedut1gxmFbI=", "license": "MIT" }, "node_modules/mz": { "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/mz/-/mz-2.7.0.tgz", + "integrity": "sha1-lQCAV6Vsr63CvGPd5/n/aVWUjjI=", "dev": true, "license": "MIT", "dependencies": { @@ -6932,9 +6963,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.15", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz", - "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==", + "version": "3.3.16", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha1-oE2OxLHxAAnS1TOUeu/kKTc3gWw=", "dev": true, "funding": [ { @@ -6952,15 +6983,15 @@ }, "node_modules/natural-compare": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true, "license": "MIT" }, "node_modules/negotiator": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha1-tskbtHFy1p+Tz9fDV7u1KQGbX2o=", "license": "MIT", "engines": { "node": ">= 0.6" @@ -6968,8 +6999,8 @@ }, "node_modules/object-assign": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -6977,8 +7008,8 @@ }, "node_modules/object-inspect": { "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha1-g3UmXiG8IND6WCwi4bE0hdbgAhM=", "license": "MIT", "engines": { "node": ">= 0.4" @@ -6988,9 +7019,9 @@ } }, "node_modules/obug": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.3.tgz", - "integrity": "sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==", + "version": "2.1.4", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/obug/-/obug-2.1.4.tgz", + "integrity": "sha1-kJDYpUilIlF5FdKqaq6QcZesbPg=", "dev": true, "funding": [ "https://github.com/sponsors/sxzz", @@ -7003,8 +7034,8 @@ }, "node_modules/on-finished": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha1-WMjEQRblSEWtV/FKsQsDUzGErD8=", "license": "MIT", "dependencies": { "ee-first": "1.1.1" @@ -7015,8 +7046,8 @@ }, "node_modules/once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "license": "ISC", "dependencies": { "wrappy": "1" @@ -7024,8 +7055,8 @@ }, "node_modules/optionator": { "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha1-fqHBpdkddk+yghOciP4R4YKjpzQ=", "dev": true, "license": "MIT", "dependencies": { @@ -7042,8 +7073,8 @@ }, "node_modules/p-limit": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha1-4drMvnjQ0TiMoYxk/qOOPlfjcGs=", "dev": true, "license": "MIT", "dependencies": { @@ -7058,8 +7089,8 @@ }, "node_modules/p-locate": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha1-g8gxXGeFAF470CGDlBHJ4RDm2DQ=", "dev": true, "license": "MIT", "dependencies": { @@ -7074,15 +7105,15 @@ }, "node_modules/package-json-from-dist": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha1-TxRxoBCCeob5TP2bByfjbSZ95QU=", "dev": true, "license": "BlueOak-1.0.0" }, "node_modules/parent-module": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha1-aR0nCeeMefrjoVZiJFLQB2LKqqI=", "dev": true, "license": "MIT", "dependencies": { @@ -7094,8 +7125,8 @@ }, "node_modules/parse-entities": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", - "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha1-YdRvXtKOTuYundxD1rAQGIRD8Vk=", "license": "MIT", "dependencies": { "@types/unist": "^2.0.0", @@ -7113,14 +7144,14 @@ }, "node_modules/parse-entities/node_modules/@types/unist": { "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", - "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha1-Ea9XsSfjJId3SEH3pOVOqxZtA8Q=", "license": "MIT" }, "node_modules/parse5": { "version": "7.3.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", - "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha1-1+Ik+nI5nHoXUJn0X8KtAksF7AU=", "license": "MIT", "dependencies": { "entities": "^6.0.0" @@ -7131,8 +7162,8 @@ }, "node_modules/parseurl": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ=", "license": "MIT", "engines": { "node": ">= 0.8" @@ -7140,8 +7171,8 @@ }, "node_modules/path-exists": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha1-UTvb4tO5XXdi6METfvoZXGxhtbM=", "dev": true, "license": "MIT", "engines": { @@ -7150,8 +7181,8 @@ }, "node_modules/path-key": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha1-WB9q3mWMu6ZaDTOA3ndTKVBU83U=", "license": "MIT", "engines": { "node": ">=8" @@ -7159,8 +7190,8 @@ }, "node_modules/path-scurry": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", - "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha1-a+DQ7gKhDZ4N56mLrmXhgskGH4U=", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -7176,8 +7207,8 @@ }, "node_modules/path-to-regexp": { "version": "8.4.2", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", - "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha1-eVxCDE98pFxbiHNm9iLuDJhSzM0=", "license": "MIT", "funding": { "type": "opencollective", @@ -7186,22 +7217,22 @@ }, "node_modules/pathe": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha1-PsvsVUIWhbcKnahyss/z4cvtFxY=", "dev": true, "license": "MIT" }, "node_modules/picocolors": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha1-PTIa8+q5ObCDyPkpodEs2oHCa2s=", "dev": true, "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "version": "4.0.5", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha1-UepXoX2G9gX4EDlZX7xA7QalX6s=", "dev": true, "license": "MIT", "engines": { @@ -7213,8 +7244,8 @@ }, "node_modules/pirates": { "version": "4.0.7", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", - "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha1-ZDtKGMQlfIplEEtz8wSc6aChXiI=", "dev": true, "license": "MIT", "engines": { @@ -7223,8 +7254,8 @@ }, "node_modules/pkce-challenge": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", - "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha1-O0RGhlsXsXRems4gFqMfSN32Iw0=", "license": "MIT", "engines": { "node": ">=16.20.0" @@ -7232,8 +7263,8 @@ }, "node_modules/pkg-types": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", - "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha1-vXzHCIEZJ3fu9TJsGd60bokJF98=", "dev": true, "license": "MIT", "dependencies": { @@ -7242,10 +7273,16 @@ "pathe": "^2.0.1" } }, + "node_modules/plotly.js-dist-min": { + "version": "2.35.3", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/plotly.js-dist-min/-/plotly.js-dist-min-2.35.3.tgz", + "integrity": "sha1-uAx5VG/iHB9YVle1nYDK8aDY9WM=", + "license": "MIT" + }, "node_modules/postcss": { - "version": "8.5.15", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", - "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "version": "8.5.19", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/postcss/-/postcss-8.5.19.tgz", + "integrity": "sha1-Ra1c/eSZQI4gFHNII3VROBqSIDc=", "dev": true, "funding": [ { @@ -7273,8 +7310,8 @@ }, "node_modules/postcss-load-config": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", - "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha1-b9fc2K6JutzxstZESJy6v4OqgJY=", "dev": true, "funding": [ { @@ -7316,8 +7353,8 @@ }, "node_modules/prelude-ls": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha1-3rxkidem5rDnYRiIzsiAM30xY5Y=", "dev": true, "license": "MIT", "engines": { @@ -7325,9 +7362,9 @@ } }, "node_modules/prettier": { - "version": "3.8.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.4.tgz", - "integrity": "sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==", + "version": "3.9.5", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/prettier/-/prettier-3.9.5.tgz", + "integrity": "sha1-T+yXc24zudC2ILSJFP6TtTDoNa0=", "dev": true, "license": "MIT", "bin": { @@ -7342,8 +7379,8 @@ }, "node_modules/prismjs": { "version": "1.30.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", - "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha1-2XCZadnU4WQD9vNIxjVTsZ8Jdak=", "license": "MIT", "engines": { "node": ">=6" @@ -7351,8 +7388,8 @@ }, "node_modules/property-information": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.2.0.tgz", - "integrity": "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/property-information/-/property-information-7.2.0.tgz", + "integrity": "sha1-CAmzQmTplcC/zTInAooeNSEK+Ao=", "license": "MIT", "funding": { "type": "github", @@ -7361,8 +7398,8 @@ }, "node_modules/proxy-addr": { "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha1-8Z/mnOqzEe65S0LnDowgcPm6ECU=", "license": "MIT", "dependencies": { "forwarded": "0.2.0", @@ -7374,8 +7411,8 @@ }, "node_modules/punycode": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha1-AnQi4vrsCyXhVJw+G9gwm5EztuU=", "dev": true, "license": "MIT", "engines": { @@ -7383,12 +7420,13 @@ } }, "node_modules/qs": { - "version": "6.15.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", - "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", + "version": "6.15.3", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/qs/-/qs-6.15.3.tgz", + "integrity": "sha1-doUhMqWO1cfA72fkRBubtdYGGzs=", "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.1.0" + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" }, "engines": { "node": ">=0.6" @@ -7398,18 +7436,22 @@ } }, "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "version": "1.3.0", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/range-parser/-/range-parser-1.3.0.tgz", + "integrity": "sha1-1/Gb6BK7YnIUcrRdO+IZ7wlXK0c=", "license": "MIT", "engines": { "node": ">= 0.6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/raw-body": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", - "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha1-PjraWuVWj5CV2EN2/TpJuPsAClE=", "license": "MIT", "dependencies": { "bytes": "~3.1.2", @@ -7423,8 +7465,8 @@ }, "node_modules/react": { "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/react/-/react-18.3.1.tgz", + "integrity": "sha1-SauJIAnFOTNiW9FrJTP8dUyrKJE=", "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" @@ -7435,8 +7477,8 @@ }, "node_modules/react-dom": { "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha1-wiZdeVEbV9R5s90/36UVNklMXLQ=", "license": "MIT", "dependencies": { "loose-envify": "^1.1.0", @@ -7448,8 +7490,8 @@ }, "node_modules/react-i18next": { "version": "17.0.10", - "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-17.0.10.tgz", - "integrity": "sha512-XneHftyYA774MJkkccSkZ5oKrUpCnXIPmxio3wemqrVzCRLWiGXOMbIzObrer03fNDEnm8g8R5yYls4HcE+esg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/react-i18next/-/react-i18next-17.0.10.tgz", + "integrity": "sha1-rv30MkdIyxBc/vke00fqsSmGVpg=", "license": "MIT", "dependencies": { "@babel/runtime": "^7.29.2", @@ -7475,8 +7517,8 @@ }, "node_modules/react-markdown": { "version": "10.1.0", - "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz", - "integrity": "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/react-markdown/-/react-markdown-10.1.0.tgz", + "integrity": "sha1-4ivCD63bwHYFwVKEJVZTwPO61co=", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -7501,41 +7543,60 @@ } }, "node_modules/react-router": { - "version": "6.30.4", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.4.tgz", - "integrity": "sha512-SVUsDe+DybHM/WmYKIVYhZh1o5Dcuf16yM6WjG02Q9XVFMZIJyHYhwrr6bFBXZkVP6z69kNkMyBCujt8FaFLJA==", + "version": "7.18.1", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/react-router/-/react-router-7.18.1.tgz", + "integrity": "sha1-YSWdFZS5XBrOKZ7kxXRTVw8MIvE=", "license": "MIT", "dependencies": { - "@remix-run/router": "1.23.3" + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" }, "engines": { - "node": ">=14.0.0" + "node": ">=20.0.0" }, "peerDependencies": { - "react": ">=16.8" + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } } }, "node_modules/react-router-dom": { - "version": "6.30.4", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.4.tgz", - "integrity": "sha512-q4HvNl+mmDdkS0g+MqiBZNteQJCuimWoOyHMy4T/RQLAn9Z29+E91QXRaxOujeMl2HTzRSS0KFPd7lxX3PjV0Q==", + "version": "7.18.1", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/react-router-dom/-/react-router-dom-7.18.1.tgz", + "integrity": "sha1-DRsTjikTkwWa1IHD4Q42Y4WpeKQ=", "license": "MIT", "dependencies": { - "@remix-run/router": "1.23.3", - "react-router": "6.30.4" + "react-router": "7.18.1" }, "engines": { - "node": ">=14.0.0" + "node": ">=20.0.0" }, "peerDependencies": { - "react": ">=16.8", - "react-dom": ">=16.8" + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/react-router/node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha1-O7m9/II2nbnC9pyTycPOsxDIizw=", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/react-syntax-highlighter": { "version": "16.1.1", - "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-16.1.1.tgz", - "integrity": "sha512-PjVawBGy80C6YbC5DDZJeUjBmC7skaoEUdvfFQediQHgCL7aKyVHe57SaJGfQsloGDac+gCpTfRdtxzWWKmCXA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/react-syntax-highlighter/-/react-syntax-highlighter-16.1.1.tgz", + "integrity": "sha1-koRZhV03X1z8jmRgceINVBzry1I=", "license": "MIT", "dependencies": { "@babel/runtime": "^7.28.4", @@ -7554,8 +7615,8 @@ }, "node_modules/readdirp": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha1-64WAFDX78qfuWPGeCSGwaPxplI0=", "dev": true, "license": "MIT", "engines": { @@ -7568,8 +7629,8 @@ }, "node_modules/refractor": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/refractor/-/refractor-5.0.0.tgz", - "integrity": "sha512-QXOrHQF5jOpjjLfiNk5GFnWhRXvxjUVnlFxkeDmewR5sXkr3iM46Zo+CnRR8B+MDVqkULW4EcLVcRBNOPXHosw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/refractor/-/refractor-5.0.0.tgz", + "integrity": "sha1-hdrwRIptlH9TYXlusiwxcz1h2QQ=", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -7584,8 +7645,8 @@ }, "node_modules/rehype-katex": { "version": "7.0.1", - "resolved": "https://registry.npmjs.org/rehype-katex/-/rehype-katex-7.0.1.tgz", - "integrity": "sha512-OiM2wrZ/wuhKkigASodFoo8wimG3H12LWQaH8qSPVJn9apWKFSH3YOCtbKpBorTVw/eI7cuT21XBbvwEswbIOA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/rehype-katex/-/rehype-katex-7.0.1.tgz", + "integrity": "sha1-gy5tevJ0SiKJgdGw/olIOp58k6E=", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -7603,8 +7664,8 @@ }, "node_modules/rehype-katex/node_modules/katex": { "version": "0.16.47", - "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.47.tgz", - "integrity": "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/katex/-/katex-0.16.47.tgz", + "integrity": "sha1-ChOkLC3rT3TmHxYtRAuRZaVIAw8=", "funding": [ "https://opencollective.com/katex", "https://github.com/sponsors/katex" @@ -7619,8 +7680,8 @@ }, "node_modules/remark-gfm": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", - "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/remark-gfm/-/remark-gfm-4.0.1.tgz", + "integrity": "sha1-MyJ7KnQ5dnDTV78FwJjq+FE/DWs=", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -7637,8 +7698,8 @@ }, "node_modules/remark-math": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/remark-math/-/remark-math-6.0.0.tgz", - "integrity": "sha512-MMqgnP74Igy+S3WwnhQ7kqGlEerTETXMvJhrUzDikVZ2/uogJCb+WHUg97hK9/jcfc0dkD73s3LN8zU49cTEtA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/remark-math/-/remark-math-6.0.0.tgz", + "integrity": "sha1-Cs33RnXxwZX+pu//p4WC9+1/wNc=", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -7653,8 +7714,8 @@ }, "node_modules/remark-parse": { "version": "11.0.0", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", - "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha1-qmB0P8s36/awaSBOtNowTkDbRaE=", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -7669,8 +7730,8 @@ }, "node_modules/remark-rehype": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", - "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha1-Kt2q3agMqb2aoNp2PnTRYydoOzc=", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -7686,8 +7747,8 @@ }, "node_modules/remark-stringify": { "version": "11.0.0", - "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", - "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha1-TFsB3XEcJp3xqq4RdD634udjb9M=", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -7701,27 +7762,27 @@ }, "node_modules/require-from-string": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha1-iaf92TgmEmcxjq/hT5wy5ZjDaQk=", "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "version": "5.0.0", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha1-w1IlhD3493bfIcV1V7wIfp39/Gk=", "dev": true, "license": "MIT", "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/rimraf": { "version": "6.1.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.3.tgz", - "integrity": "sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/rimraf/-/rimraf-6.1.3.tgz", + "integrity": "sha1-r77iNrO9K+Mx1OfORJO6wXGJga8=", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -7740,18 +7801,18 @@ }, "node_modules/robust-predicates": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz", - "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/robust-predicates/-/robust-predicates-3.0.3.tgz", + "integrity": "sha1-EJkGGzNJ4sWr7GwqsKzUQNJNQGI=", "license": "Unlicense" }, "node_modules/rolldown": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.3.tgz", - "integrity": "sha512-1F1eEtUBtFvcGm1HQ9TiUIUHPQG7mSAODrhIzjxoUEFuo8OcbrGLiVLkevNgj84TE4lnHvnumwFjhJO5Eu135g==", + "version": "1.1.5", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/rolldown/-/rolldown-1.1.5.tgz", + "integrity": "sha1-M5quJQhENR/FW3TiZS0+vW+6OJ0=", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.137.0", + "@oxc-project/types": "=0.139.0", "@rolldown/pluginutils": "^1.0.0" }, "bin": { @@ -7761,34 +7822,27 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.1.3", - "@rolldown/binding-darwin-arm64": "1.1.3", - "@rolldown/binding-darwin-x64": "1.1.3", - "@rolldown/binding-freebsd-x64": "1.1.3", - "@rolldown/binding-linux-arm-gnueabihf": "1.1.3", - "@rolldown/binding-linux-arm64-gnu": "1.1.3", - "@rolldown/binding-linux-arm64-musl": "1.1.3", - "@rolldown/binding-linux-ppc64-gnu": "1.1.3", - "@rolldown/binding-linux-s390x-gnu": "1.1.3", - "@rolldown/binding-linux-x64-gnu": "1.1.3", - "@rolldown/binding-linux-x64-musl": "1.1.3", - "@rolldown/binding-openharmony-arm64": "1.1.3", - "@rolldown/binding-wasm32-wasi": "1.1.3", - "@rolldown/binding-win32-arm64-msvc": "1.1.3", - "@rolldown/binding-win32-x64-msvc": "1.1.3" - } - }, - "node_modules/rolldown/node_modules/@rolldown/pluginutils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", - "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", - "dev": true, - "license": "MIT" + "@rolldown/binding-android-arm64": "1.1.5", + "@rolldown/binding-darwin-arm64": "1.1.5", + "@rolldown/binding-darwin-x64": "1.1.5", + "@rolldown/binding-freebsd-x64": "1.1.5", + "@rolldown/binding-linux-arm-gnueabihf": "1.1.5", + "@rolldown/binding-linux-arm64-gnu": "1.1.5", + "@rolldown/binding-linux-arm64-musl": "1.1.5", + "@rolldown/binding-linux-ppc64-gnu": "1.1.5", + "@rolldown/binding-linux-s390x-gnu": "1.1.5", + "@rolldown/binding-linux-x64-gnu": "1.1.5", + "@rolldown/binding-linux-x64-musl": "1.1.5", + "@rolldown/binding-openharmony-arm64": "1.1.5", + "@rolldown/binding-wasm32-wasi": "1.1.5", + "@rolldown/binding-win32-arm64-msvc": "1.1.5", + "@rolldown/binding-win32-x64-msvc": "1.1.5" + } }, "node_modules/rollup": { "version": "4.62.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.2.tgz", - "integrity": "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/rollup/-/rollup-4.62.2.tgz", + "integrity": "sha1-2Q/Ey4EfBxMDyJC3eVlWNPNflUE=", "dev": true, "license": "MIT", "dependencies": { @@ -7832,8 +7886,8 @@ }, "node_modules/router": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/router/-/router-2.2.0.tgz", + "integrity": "sha1-AZvmILcRyHZBFnzHm5kJDwCxRu8=", "license": "MIT", "dependencies": { "debug": "^4.4.0", @@ -7848,20 +7902,20 @@ }, "node_modules/rw": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/rw/-/rw-1.3.3.tgz", + "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=", "license": "BSD-3-Clause" }, "node_modules/safer-buffer": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=", "license": "MIT" }, "node_modules/scheduler": { "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha1-QUumSjsoKJLpRM8hCOzAeNEVzcM=", "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" @@ -7869,8 +7923,8 @@ }, "node_modules/semver": { "version": "7.8.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/semver/-/semver-7.8.5.tgz", + "integrity": "sha1-ObZGA33VDBT7RR5+TKxY7YuGP2k=", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -7881,8 +7935,8 @@ }, "node_modules/send": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", - "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/send/-/send-1.2.1.tgz", + "integrity": "sha1-nqt0O4dPNVD0CiaGe/KGrWDT8+0=", "license": "MIT", "dependencies": { "debug": "^4.4.3", @@ -7907,8 +7961,8 @@ }, "node_modules/serve-static": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", - "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha1-fxhqSk5fW2Y616QpT/G/N88OmKk=", "license": "MIT", "dependencies": { "encodeurl": "^2.0.0", @@ -7924,16 +7978,22 @@ "url": "https://opencollective.com/express" } }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha1-zNCGc6muXS5E6iot4lCJ5nx+32g=", + "license": "MIT" + }, "node_modules/setprototypeof": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha1-ZsmiSnP5/CjL5msJ/tPTPcrxtCQ=", "license": "ISC" }, "node_modules/shebang-command": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha1-zNCvT4g1+9wmW4JGGq8MNmY/NOo=", "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -7944,8 +8004,8 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha1-rhbxZE2HPsrYQ7AwexQzYtTEIXI=", "license": "MIT", "engines": { "node": ">=8" @@ -7953,8 +8013,8 @@ }, "node_modules/side-channel": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", - "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha1-6gLGLgXcS+pn1EQvD7ce4ZL44Ks=", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -7972,8 +8032,8 @@ }, "node_modules/side-channel-list": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", - "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha1-wuC1oUpUCuvuO7xsP4ZmzJtQkSc=", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -7988,8 +8048,8 @@ }, "node_modules/side-channel-map": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha1-1rtrN5Asb+9RdOX1M/q0xzKib0I=", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -8006,8 +8066,8 @@ }, "node_modules/side-channel-weakmap": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha1-Ed2hnVNo5Azp7CvcH7DsvAeQ7Oo=", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -8025,15 +8085,15 @@ }, "node_modules/siginfo": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha1-MudscLeXJOO7Vny51UPrhYzPrzA=", "dev": true, "license": "ISC" }, "node_modules/source-map": { "version": "0.7.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", - "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha1-o2WKuH5bZCnIofO6AIPUxhyj7wI=", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -8042,8 +8102,8 @@ }, "node_modules/source-map-js": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha1-HOVlD93YerwJnto33P8CTCZnrkY=", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -8052,8 +8112,8 @@ }, "node_modules/space-separated-tokens": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", - "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha1-Hs2dI1CjhEVyw/SjErzrAYNIhZ8=", "license": "MIT", "funding": { "type": "github", @@ -8062,31 +8122,31 @@ }, "node_modules/stackback": { "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha1-Gsig2Ug4SNFpXkGLbQMaPDzmjjs=", "dev": true, "license": "MIT" }, "node_modules/statuses": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha1-j3XuzvdlteHPzcCA2llAntQk44I=", "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/std-env": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", - "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", + "version": "4.2.0", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/std-env/-/std-env-4.2.0.tgz", + "integrity": "sha1-jr4OxgSFZoq0ciezEvQlTN+AydM=", "dev": true, "license": "MIT" }, "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==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha1-tbuOIWXOJ11NQ0dt0nAK2Qkdttw=", "license": "MIT", "dependencies": { "emoji-regex": "^10.3.0", @@ -8102,8 +8162,8 @@ }, "node_modules/stringify-entities": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", - "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha1-s7ee9fJ3zErHPK6wI2xbqTmzpPM=", "license": "MIT", "dependencies": { "character-entities-html4": "^2.0.0", @@ -8116,8 +8176,8 @@ }, "node_modules/strip-ansi": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha1-0iomlSKDamJ6+NBLXD/Sx/o+MuM=", "license": "MIT", "dependencies": { "ansi-regex": "^6.2.2" @@ -8131,8 +8191,8 @@ }, "node_modules/strip-json-comments": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha1-MfEoGzgyYwQ0gxwxDAHMzajL4AY=", "dev": true, "license": "MIT", "engines": { @@ -8144,14 +8204,14 @@ }, "node_modules/style-mod": { "version": "4.1.3", - "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz", - "integrity": "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/style-mod/-/style-mod-4.1.3.tgz", + "integrity": "sha1-bpASJVu3mb2sN+KI92cbXXG/n3M=", "license": "MIT" }, "node_modules/style-to-js": { "version": "1.1.21", - "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz", - "integrity": "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/style-to-js/-/style-to-js-1.1.21.tgz", + "integrity": "sha1-KQiUEYf4V+eeKOnNeACLmgs+Do0=", "license": "MIT", "dependencies": { "style-to-object": "1.0.14" @@ -8159,8 +8219,8 @@ }, "node_modules/style-to-object": { "version": "1.0.14", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz", - "integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/style-to-object/-/style-to-object-1.0.14.tgz", + "integrity": "sha1-HSLw5yZruMbYyuXK9OxPAF4I9hE=", "license": "MIT", "dependencies": { "inline-style-parser": "0.2.7" @@ -8168,8 +8228,8 @@ }, "node_modules/sucrase": { "version": "3.35.1", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", - "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha1-RhnqUDk/6L0K5QccJqvZsuNGv+E=", "dev": true, "license": "MIT", "dependencies": { @@ -8191,8 +8251,8 @@ }, "node_modules/sucrase/node_modules/commander": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/commander/-/commander-4.1.1.tgz", + "integrity": "sha1-n9YCvZNilOnp70aj9NaWQESxgGg=", "dev": true, "license": "MIT", "engines": { @@ -8201,8 +8261,8 @@ }, "node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha1-G33NyzK4E4gBs+R4umpRyqiWSNo=", "dev": true, "license": "MIT", "dependencies": { @@ -8214,8 +8274,8 @@ }, "node_modules/thenify": { "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha1-iTLmhqQGYDigFt2eLKRq3Zg4qV8=", "dev": true, "license": "MIT", "dependencies": { @@ -8224,8 +8284,8 @@ }, "node_modules/thenify-all": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", "dev": true, "license": "MIT", "dependencies": { @@ -8237,22 +8297,22 @@ }, "node_modules/tinybench": { "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha1-EDyfi6bXI3pHq23R3P93JRhjQms=", "dev": true, "license": "MIT" }, "node_modules/tinyexec": { "version": "0.3.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", - "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha1-lBeU5leoXklld5lcbu9m9T9Cs9I=", "dev": true, "license": "MIT" }, "node_modules/tinyglobby": { "version": "0.2.17", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", - "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha1-ViqabJ6ys7Ej05cZ+a9btE/NdjE=", "dev": true, "license": "MIT", "dependencies": { @@ -8268,8 +8328,8 @@ }, "node_modules/tinyrainbow": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", - "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha1-HYpiOJP5XPCi3bnl0RFQ4ZFAlCE=", "dev": true, "license": "MIT", "engines": { @@ -8278,8 +8338,8 @@ }, "node_modules/to-regex-range": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ=", "dev": true, "license": "MIT", "dependencies": { @@ -8291,8 +8351,8 @@ }, "node_modules/toidentifier": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha1-O+NDIaiKgg7RvYDfqjPkefu43TU=", "license": "MIT", "engines": { "node": ">=0.6" @@ -8300,8 +8360,8 @@ }, "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==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/topojson-client/-/topojson-client-3.1.0.tgz", + "integrity": "sha1-Iuix7QiiuSL+60r29Ttu8JpGe5k=", "license": "ISC", "dependencies": { "commander": "2" @@ -8314,14 +8374,14 @@ }, "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==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/commander/-/commander-2.20.3.tgz", + "integrity": "sha1-/UhehMA+tIgcIHIrpIA16FMa6zM=", "license": "MIT" }, "node_modules/tree-kill": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha1-TKCakJLIi3OnzcXooBtQeweQoMw=", "dev": true, "license": "MIT", "bin": { @@ -8330,8 +8390,8 @@ }, "node_modules/trim-lines": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", - "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha1-2ALjMqB9+GHEiALAQyEBexvYczg=", "license": "MIT", "funding": { "type": "github", @@ -8340,8 +8400,8 @@ }, "node_modules/trough": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", - "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/trough/-/trough-2.2.0.tgz", + "integrity": "sha1-lKYL1r03XBUsHfkRpLEdWwJW9Q8=", "license": "MIT", "funding": { "type": "github", @@ -8350,8 +8410,8 @@ }, "node_modules/ts-api-utils": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", - "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha1-Ss1KFV4ic0mQpe0f6el/ETvLN8E=", "dev": true, "license": "MIT", "engines": { @@ -8363,21 +8423,21 @@ }, "node_modules/ts-interface-checker": { "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha1-eE/T1nlyK8EDsbS4AwvN212yppk=", "dev": true, "license": "Apache-2.0" }, "node_modules/tslib": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", - "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha1-gDuM2rPhK6WBpMpByIObuw2ssJ4=", "license": "0BSD" }, "node_modules/tsup": { "version": "8.5.1", - "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.5.1.tgz", - "integrity": "sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/tsup/-/tsup-8.5.1.tgz", + "integrity": "sha1-qceodbkzRL33BgDe3XjnD4jsmmU=", "dev": true, "license": "MIT", "dependencies": { @@ -8427,20 +8487,10 @@ } } }, - "node_modules/tsup/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/type-check": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha1-B7ggO/pwVsBlcFDjzNLDdzC6uPE=", "dev": true, "license": "MIT", "dependencies": { @@ -8452,8 +8502,8 @@ }, "node_modules/type-is": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", - "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha1-cdGnBTKTWC4WrJ8+uvGrmqSeVXA=", "license": "MIT", "dependencies": { "content-type": "^2.0.0", @@ -8470,8 +8520,8 @@ }, "node_modules/type-is/node_modules/content-type": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", - "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha1-L7Pt5p3/oK94ynxM51iWgGOLVt8=", "license": "MIT", "engines": { "node": ">=18" @@ -8483,8 +8533,8 @@ }, "node_modules/typescript": { "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha1-W09Z4VMQqxeiFvXWz1PuR27eZw8=", "devOptional": true, "license": "Apache-2.0", "bin": { @@ -8496,16 +8546,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.62.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.62.0.tgz", - "integrity": "sha512-8QxXi+ZACKX0kaqO4gY8kn0RSD9gFfaHDWwjqtEN48aWCBkX4MJaufWN+c3BzlrXLOxfywDL8CaoqUwcRq4j4Q==", + "version": "8.64.0", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/typescript-eslint/-/typescript-eslint-8.64.0.tgz", + "integrity": "sha1-SYTa5N6dyL+JKs9cOU0KKl8Iw+E=", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.62.0", - "@typescript-eslint/parser": "8.62.0", - "@typescript-eslint/typescript-estree": "8.62.0", - "@typescript-eslint/utils": "8.62.0" + "@typescript-eslint/eslint-plugin": "8.64.0", + "@typescript-eslint/parser": "8.64.0", + "@typescript-eslint/typescript-estree": "8.64.0", + "@typescript-eslint/utils": "8.64.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -8521,22 +8571,22 @@ }, "node_modules/ufo": { "version": "1.6.4", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz", - "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/ufo/-/ufo-1.6.4.tgz", + "integrity": "sha1-eo+4dfzGOC0sfQs2knOLBQCpJGc=", "dev": true, "license": "MIT" }, "node_modules/undici-types": { "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha1-aR0ArzkJvpOn+qE75hs6W1DvEss=", "dev": true, "license": "MIT" }, "node_modules/unified": { "version": "11.0.5", - "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", - "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/unified/-/unified-11.0.5.tgz", + "integrity": "sha1-9mZ3YQpcCp7pDKsrjU1mA3Am2eE=", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -8554,8 +8604,8 @@ }, "node_modules/unist-util-find-after": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", - "integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", + "integrity": "sha1-P8zBsIa1bzTIt5jh/5C1xURo6JY=", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -8568,8 +8618,8 @@ }, "node_modules/unist-util-is": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", - "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha1-0KP4by3Q23rNfYwkeAgLXGf5xqk=", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" @@ -8581,8 +8631,8 @@ }, "node_modules/unist-util-position": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", - "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha1-Z48gq1yhIHqX1+qKOINzyc+Ja+Q=", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" @@ -8594,8 +8644,8 @@ }, "node_modules/unist-util-remove-position": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", - "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", + "integrity": "sha1-/qaKJWWECclGBAi8a0mRuWW1IWM=", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -8608,8 +8658,8 @@ }, "node_modules/unist-util-stringify-position": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha1-RJxuIaiA4IVb9aq63rOnQDFKusI=", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" @@ -8621,8 +8671,8 @@ }, "node_modules/unist-util-visit": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", - "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha1-mioosKp2oV4NpwoIpYY6LwYOJGg=", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -8636,8 +8686,8 @@ }, "node_modules/unist-util-visit-parents": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", - "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha1-d333+5hlLOFrS3zZmdChpA76OgI=", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -8650,8 +8700,8 @@ }, "node_modules/unpipe": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", "license": "MIT", "engines": { "node": ">= 0.8" @@ -8659,8 +8709,8 @@ }, "node_modules/uri-js": { "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha1-mxpSWVIlhZ5V9mnZKPiMbFfyp34=", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -8669,8 +8719,8 @@ }, "node_modules/use-sync-external-store": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", - "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha1-sXS/plyytSZzLZ8qwKQIAnh28y0=", "license": "MIT", "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" @@ -8678,8 +8728,8 @@ }, "node_modules/vary": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", "license": "MIT", "engines": { "node": ">= 0.8" @@ -8687,8 +8737,8 @@ }, "node_modules/vega": { "version": "6.2.0", - "resolved": "https://registry.npmjs.org/vega/-/vega-6.2.0.tgz", - "integrity": "sha512-BIwalIcEGysJdQDjeVUmMWB3e50jPDNAMfLJscjEvpunU9bSt7X1OYnQxkg3uBwuRRI4nWfFZO9uIW910nLeGw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega/-/vega-6.2.0.tgz", + "integrity": "sha1-NMLeg7AOcB4EAClziybx7JkvMn8=", "license": "BSD-3-Clause", "dependencies": { "vega-crossfilter": "~5.1.0", @@ -8725,14 +8775,14 @@ }, "node_modules/vega-canvas": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/vega-canvas/-/vega-canvas-2.0.0.tgz", - "integrity": "sha512-9x+4TTw/USYST5nx4yN272sy9WcqSRjAR0tkQYZJ4cQIeon7uVsnohvoPQK1JZu7K1QXGUqzj08z0u/UegBVMA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-canvas/-/vega-canvas-2.0.0.tgz", + "integrity": "sha1-Rwneto+bT9dHWVe+2Z8Ww428B7g=", "license": "BSD-3-Clause" }, "node_modules/vega-crossfilter": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/vega-crossfilter/-/vega-crossfilter-5.1.0.tgz", - "integrity": "sha512-EmVhfP3p6AM7o/lPan/QAoqjblI19BxWUlvl2TSs0xjQd8KbaYYbS4Ixt3cmEvl0QjRdBMF6CdJJ/cy9DTS4Fw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-crossfilter/-/vega-crossfilter-5.1.0.tgz", + "integrity": "sha1-9MVtngwxcFyuQc0ONavN7iDAxIM=", "license": "BSD-3-Clause", "dependencies": { "d3-array": "^3.2.4", @@ -8742,8 +8792,8 @@ }, "node_modules/vega-dataflow": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/vega-dataflow/-/vega-dataflow-6.1.0.tgz", - "integrity": "sha512-JxumGlODtFbzoQ4c/jQK8Tb/68ih0lrexlCozcMfTAwQ12XhTqCvlafh7MAKKTMBizjOfaQTHm4Jkyb1H5CfyQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-dataflow/-/vega-dataflow-6.1.0.tgz", + "integrity": "sha1-H8SOpru+AC1FoaSO7meuoJelfFU=", "license": "BSD-3-Clause", "dependencies": { "vega-format": "^2.1.0", @@ -8753,8 +8803,8 @@ }, "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==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-embed/-/vega-embed-7.1.0.tgz", + "integrity": "sha1-QoQyuiz1uwlhwNNI956E7Kn8jPs=", "license": "BSD-3-Clause", "dependencies": { "fast-json-patch": "^3.1.1", @@ -8776,14 +8826,14 @@ }, "node_modules/vega-embed/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha1-YS7+TtI11Wfoq6Xypfq3AoCt6D8=", "license": "0BSD" }, "node_modules/vega-encode": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/vega-encode/-/vega-encode-5.1.0.tgz", - "integrity": "sha512-q26oI7B+MBQYcTQcr5/c1AMsX3FvjZLQOBi7yI0vV+GEn93fElDgvhQiYrgeYSD4Exi/jBPeUXuN6p4bLz16kA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-encode/-/vega-encode-5.1.0.tgz", + "integrity": "sha1-BfVriYgi4J35alyn8QF7n5ocTTs=", "license": "BSD-3-Clause", "dependencies": { "d3-array": "^3.2.4", @@ -8795,14 +8845,14 @@ }, "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==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-event-selector/-/vega-event-selector-4.0.0.tgz", + "integrity": "sha1-Ql6fJnHoWKGkW0tqf8RSygsiq78=", "license": "BSD-3-Clause" }, "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==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-expression/-/vega-expression-6.1.0.tgz", + "integrity": "sha1-bONYo5ublTgGv/IA9vhPRBY8njg=", "license": "BSD-3-Clause", "dependencies": { "@types/estree": "^1.0.8", @@ -8811,8 +8861,8 @@ }, "node_modules/vega-force": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/vega-force/-/vega-force-5.1.0.tgz", - "integrity": "sha512-wdnchOSeXpF9Xx8Yp0s6Do9F7YkFeOn/E/nENtsI7NOcyHpICJ5+UkgjUo9QaQ/Yu+dIDU+sP/4NXsUtq6SMaQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-force/-/vega-force-5.1.0.tgz", + "integrity": "sha1-qnz47b4q47raBw80NWXfuEHlAak=", "license": "BSD-3-Clause", "dependencies": { "d3-force": "^3.0.0", @@ -8822,8 +8872,8 @@ }, "node_modules/vega-format": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/vega-format/-/vega-format-2.1.0.tgz", - "integrity": "sha512-i9Ht33IgqG36+S1gFDpAiKvXCPz+q+1vDhDGKK8YsgMxGOG4PzinKakI66xd7SdV4q97FgpR7odAXqtDN2wKqw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-format/-/vega-format-2.1.0.tgz", + "integrity": "sha1-RlLH7J+xt/+aLFDc1Jija6YUb9o=", "license": "BSD-3-Clause", "dependencies": { "d3-array": "^3.2.4", @@ -8835,8 +8885,8 @@ }, "node_modules/vega-functions": { "version": "6.1.1", - "resolved": "https://registry.npmjs.org/vega-functions/-/vega-functions-6.1.1.tgz", - "integrity": "sha512-Due6jP0y0FfsGMTrHnzUGnEwXPu7VwE+9relfo+LjL/tRPYnnKqwWvzt7n9JkeBuZqjkgYjMzm/WucNn6Hkw5A==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-functions/-/vega-functions-6.1.1.tgz", + "integrity": "sha1-XU6XRqrd4rO3DY2j5jOIktBc2dI=", "license": "BSD-3-Clause", "dependencies": { "d3-array": "^3.2.4", @@ -8854,8 +8904,8 @@ }, "node_modules/vega-geo": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/vega-geo/-/vega-geo-5.1.0.tgz", - "integrity": "sha512-H8aBBHfthc3rzDbz/Th18+Nvp00J73q3uXGAPDQqizioDm/CoXCK8cX4pMePydBY9S6ikBiGJrLKFDa80wI20g==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-geo/-/vega-geo-5.1.0.tgz", + "integrity": "sha1-2P5q6RKtJ80rHCH1RadMB9oJNYk=", "license": "BSD-3-Clause", "dependencies": { "d3-array": "^3.2.4", @@ -8870,8 +8920,8 @@ }, "node_modules/vega-hierarchy": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/vega-hierarchy/-/vega-hierarchy-5.1.0.tgz", - "integrity": "sha512-rZlU8QJNETlB6o73lGCPybZtw2fBBsRIRuFE77aCLFHdGsh6wIifhplVarqE9icBqjUHRRUOmcEYfzwVIPr65g==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-hierarchy/-/vega-hierarchy-5.1.0.tgz", + "integrity": "sha1-Qjdw3Ry0aENw8jpojcW22tE5nb8=", "license": "BSD-3-Clause", "dependencies": { "d3-hierarchy": "^3.1.2", @@ -8881,8 +8931,8 @@ }, "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==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-interpreter/-/vega-interpreter-2.2.1.tgz", + "integrity": "sha1-lH2PKIelnRJK3diE0BsC9lc/uFE=", "license": "BSD-3-Clause", "dependencies": { "vega-util": "^2.1.0" @@ -8890,8 +8940,8 @@ }, "node_modules/vega-label": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/vega-label/-/vega-label-2.1.0.tgz", - "integrity": "sha512-/hgf+zoA3FViDBehrQT42Lta3t8In6YwtMnwjYlh72zNn1p3c7E3YUBwqmAqTM1x+tudgzMRGLYig+bX1ewZxQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-label/-/vega-label-2.1.0.tgz", + "integrity": "sha1-vZd80U6bBi/OMVk6LbKBmqnvssk=", "license": "BSD-3-Clause", "dependencies": { "vega-canvas": "^2.0.0", @@ -8902,8 +8952,8 @@ }, "node_modules/vega-lite": { "version": "6.4.3", - "resolved": "https://registry.npmjs.org/vega-lite/-/vega-lite-6.4.3.tgz", - "integrity": "sha512-d/7hPjfz560UERaQuTmGgIVfXAe3g2hJWeC+igDeaGohUdEoNrHLXgR/yTOBT8vV/lIuuKnw+0/xWWblkDwkMQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-lite/-/vega-lite-6.4.3.tgz", + "integrity": "sha1-mXPTr+E5H7CIB7wlheEp4tr3o2s=", "license": "BSD-3-Clause", "dependencies": { "json-stringify-pretty-compact": "~4.0.0", @@ -8931,14 +8981,14 @@ }, "node_modules/vega-lite/node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha1-YS7+TtI11Wfoq6Xypfq3AoCt6D8=", "license": "0BSD" }, "node_modules/vega-loader": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/vega-loader/-/vega-loader-5.1.0.tgz", - "integrity": "sha512-GaY3BdSPbPNdtrBz8SYUBNmNd8mdPc3mtdZfdkFazQ0RD9m+Toz5oR8fKnTamNSk9fRTJX0Lp3uEqxrAlQVreg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-loader/-/vega-loader-5.1.0.tgz", + "integrity": "sha1-aTePxNRujUVzrTCPdkZOZrAleeY=", "license": "BSD-3-Clause", "dependencies": { "d3-dsv": "^3.0.1", @@ -8949,8 +8999,8 @@ }, "node_modules/vega-parser": { "version": "7.1.0", - "resolved": "https://registry.npmjs.org/vega-parser/-/vega-parser-7.1.0.tgz", - "integrity": "sha512-g0lrYxtmYVW8G6yXpIS4J3Uxt9OUSkc0bLu5afoYDo4rZmoOOdll3x3ebActp5LHPW+usZIE+p5nukRS2vEc7Q==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-parser/-/vega-parser-7.1.0.tgz", + "integrity": "sha1-IO4OcKbs24yzTvFt7tSErWjECFA=", "license": "BSD-3-Clause", "dependencies": { "vega-dataflow": "^6.1.0", @@ -8962,8 +9012,8 @@ }, "node_modules/vega-projection": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/vega-projection/-/vega-projection-2.1.0.tgz", - "integrity": "sha512-EjRjVSoMR5ibrU7q8LaOQKP327NcOAM1+eZ+NO4ANvvAutwmbNVTmfA1VpPH+AD0AlBYc39ND/wnRk7SieDiXA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-projection/-/vega-projection-2.1.0.tgz", + "integrity": "sha1-zkYpHveKdBjHVnkQMpbWL0mvrBQ=", "license": "BSD-3-Clause", "dependencies": { "d3-geo": "^3.1.1", @@ -8973,8 +9023,8 @@ }, "node_modules/vega-regression": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/vega-regression/-/vega-regression-2.1.0.tgz", - "integrity": "sha512-HzC7MuoEwG1rIxRaNTqgcaYF03z/ZxYkQR2D5BN0N45kLnHY1HJXiEcZkcffTsqXdspLjn47yLi44UoCwF5fxQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-regression/-/vega-regression-2.1.0.tgz", + "integrity": "sha1-0/0QPpegruVa4qeO2BWI+13LngM=", "license": "BSD-3-Clause", "dependencies": { "d3-array": "^3.2.4", @@ -8985,8 +9035,8 @@ }, "node_modules/vega-runtime": { "version": "7.1.0", - "resolved": "https://registry.npmjs.org/vega-runtime/-/vega-runtime-7.1.0.tgz", - "integrity": "sha512-mItI+WHimyEcZlZrQ/zYR3LwHVeyHCWwp7MKaBjkU8EwkSxEEGVceyGUY9X2YuJLiOgkLz/6juYDbMv60pfwYA==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-runtime/-/vega-runtime-7.1.0.tgz", + "integrity": "sha1-GVnWFoY4+Fvc5NFXEXrKatH2n6w=", "license": "BSD-3-Clause", "dependencies": { "vega-dataflow": "^6.1.0", @@ -8995,8 +9045,8 @@ }, "node_modules/vega-scale": { "version": "8.1.0", - "resolved": "https://registry.npmjs.org/vega-scale/-/vega-scale-8.1.0.tgz", - "integrity": "sha512-VEgDuEcOec8+C8+FzLcnAmcXrv2gAJKqQifCdQhkgnsLa978vYUgVfCut/mBSMMHbH8wlUV1D0fKZTjRukA1+A==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-scale/-/vega-scale-8.1.0.tgz", + "integrity": "sha1-oGs6qNYK5GrY89ierg506z0SAOM=", "license": "BSD-3-Clause", "dependencies": { "d3-array": "^3.2.4", @@ -9009,8 +9059,8 @@ }, "node_modules/vega-scenegraph": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/vega-scenegraph/-/vega-scenegraph-5.1.0.tgz", - "integrity": "sha512-4gA89CFIxkZX+4Nvl8SZF2MBOqnlj9J5zgdPh/HPx+JOwtzSlUqIhxFpFj7GWYfwzr/PyZnguBLPihPw1Og/cA==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-scenegraph/-/vega-scenegraph-5.1.0.tgz", + "integrity": "sha1-OzwNhxeZ/oS8VjJW17nVS8LhM2g=", "license": "BSD-3-Clause", "dependencies": { "d3-path": "^3.1.0", @@ -9023,14 +9073,14 @@ }, "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==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-schema-url-parser/-/vega-schema-url-parser-3.0.2.tgz", + "integrity": "sha1-lfCmrX/JNBr8BUlcGgdMYvpxxFY=", "license": "BSD-3-Clause" }, "node_modules/vega-selections": { "version": "6.1.2", - "resolved": "https://registry.npmjs.org/vega-selections/-/vega-selections-6.1.2.tgz", - "integrity": "sha512-xJ+V4qdd46nk2RBdwIRrQm2iSTMHdlu/omhLz1pqRL3jZDrkqNBXimrisci2kIKpH2WBpA1YVagwuZEKBmF2Qw==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-selections/-/vega-selections-6.1.2.tgz", + "integrity": "sha1-Nkbbap/B1yWWm4tYQeXTM8Hw+AM=", "license": "BSD-3-Clause", "dependencies": { "d3-array": "3.2.4", @@ -9040,8 +9090,8 @@ }, "node_modules/vega-statistics": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/vega-statistics/-/vega-statistics-2.0.0.tgz", - "integrity": "sha512-dGPfDXnBlgXbZF3oxtkb8JfeRXd5TYHx25Z/tIoaa9jWua4Vf/AoW2wwh8J1qmMy8J03/29aowkp1yk4DOPazQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-statistics/-/vega-statistics-2.0.0.tgz", + "integrity": "sha1-nJY2wgaCrpjoiH+Pqw6CwkZqc2o=", "license": "BSD-3-Clause", "dependencies": { "d3-array": "^3.2.4" @@ -9049,8 +9099,8 @@ }, "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==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-themes/-/vega-themes-3.0.0.tgz", + "integrity": "sha1-lvP3nDkvwwIOXRLvWP5k9RbTbh4=", "license": "BSD-3-Clause", "funding": { "url": "https://app.hubspot.com/payments/GyPC972GD9Rt" @@ -9062,8 +9112,8 @@ }, "node_modules/vega-time": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/vega-time/-/vega-time-3.1.0.tgz", - "integrity": "sha512-G93mWzPwNa6UYQRkr8Ujur9uqxbBDjDT/WpXjbDY0yygdSkRT+zXF+Sb4gjhW0nPaqdiwkn0R6kZcSPMj1bMNA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-time/-/vega-time-3.1.0.tgz", + "integrity": "sha1-TiDF1g4/foJ6M9spvUhV9AoK48s=", "license": "BSD-3-Clause", "dependencies": { "d3-array": "^3.2.4", @@ -9073,8 +9123,8 @@ }, "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==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-tooltip/-/vega-tooltip-1.0.0.tgz", + "integrity": "sha1-xoKcm831voU4UDB2ZcnyEyEIP/I=", "license": "BSD-3-Clause", "dependencies": { "vega-util": "^2.0.0" @@ -9085,8 +9135,8 @@ }, "node_modules/vega-transforms": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/vega-transforms/-/vega-transforms-5.1.0.tgz", - "integrity": "sha512-mj/sO2tSuzzpiXX8JSl4DDlhEmVwM/46MTAzTNQUQzJPMI/n4ChCjr/SdEbfEyzlD4DPm1bjohZGjLc010yuMg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-transforms/-/vega-transforms-5.1.0.tgz", + "integrity": "sha1-TpXNfEdzqlYJKNEDhaDTPqJ0jKo=", "license": "BSD-3-Clause", "dependencies": { "d3-array": "^3.2.4", @@ -9098,8 +9148,8 @@ }, "node_modules/vega-typings": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/vega-typings/-/vega-typings-2.1.0.tgz", - "integrity": "sha512-zdis4Fg4gv37yEvTTSZEVMNhp8hwyEl7GZ4X4HHddRVRKxWFsbyKvZx/YW5Z9Ox4sjxVA2qHzEbod4Fdx+SEJA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-typings/-/vega-typings-2.1.0.tgz", + "integrity": "sha1-HB/lSMDwCZeCAkat4NPYE7h7/XY=", "license": "BSD-3-Clause", "dependencies": { "@types/geojson": "7946.0.16", @@ -9110,14 +9160,14 @@ }, "node_modules/vega-util": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/vega-util/-/vega-util-2.1.1.tgz", - "integrity": "sha512-tpNmm8bGtUa8gKfFDSjXPffxqSyPr91vaWIEBnJS/rijhoLZMwM+mgYQG6XfwdcBSN1+jkZ57P0sYSEW/jophw==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-util/-/vega-util-2.1.1.tgz", + "integrity": "sha1-0fSU4C/dK2oWeadAuFJUuGTN1Zc=", "license": "BSD-3-Clause" }, "node_modules/vega-view": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/vega-view/-/vega-view-6.1.0.tgz", - "integrity": "sha512-hmHDm/zC65lb23mb9Tr9Gx0wkxP0TMS31LpMPYxIZpvInxvUn7TYitkOtz1elr63k2YZrgmF7ztdGyQ4iCQ5fQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-view/-/vega-view-6.1.0.tgz", + "integrity": "sha1-VZb3jF68qNy1f+ykD9McuCZf0E4=", "license": "BSD-3-Clause", "dependencies": { "d3-array": "^3.2.4", @@ -9132,8 +9182,8 @@ }, "node_modules/vega-view-transforms": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/vega-view-transforms/-/vega-view-transforms-5.1.0.tgz", - "integrity": "sha512-fpigh/xn/32t+An1ShoY3MLeGzNdlbAp2+HvFKzPpmpMTZqJEWkk/J/wHU7Swyc28Ta7W1z3fO+8dZkOYO5TWQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-view-transforms/-/vega-view-transforms-5.1.0.tgz", + "integrity": "sha1-HzH3Xvz5mziWnnUAQ625Ivzsbz4=", "license": "BSD-3-Clause", "dependencies": { "vega-dataflow": "^6.1.0", @@ -9143,8 +9193,8 @@ }, "node_modules/vega-voronoi": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/vega-voronoi/-/vega-voronoi-5.1.0.tgz", - "integrity": "sha512-uKdsoR9x60mz7eYtVG+NhlkdQXeVdMr6jHNAHxs+W+i6kawkUp5S9jp1xf1FmW/uZvtO1eqinHQNwATcDRsiUg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-voronoi/-/vega-voronoi-5.1.0.tgz", + "integrity": "sha1-kpVrnXjwbjkYlw/ITQaXTiS59S8=", "license": "BSD-3-Clause", "dependencies": { "d3-delaunay": "^6.0.4", @@ -9154,8 +9204,8 @@ }, "node_modules/vega-wordcloud": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/vega-wordcloud/-/vega-wordcloud-5.1.0.tgz", - "integrity": "sha512-sSdNmT8y2D7xXhM2h76dKyaYn3PA4eV49WUUkfYfqHz/vpcu10GSAoFxLhQQTkbZXR+q5ZB63tFUow9W2IFo6g==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vega-wordcloud/-/vega-wordcloud-5.1.0.tgz", + "integrity": "sha1-eqjcv2yDsZP+cftkEL4VrSxyheY=", "license": "BSD-3-Clause", "dependencies": { "vega-canvas": "^2.0.0", @@ -9167,8 +9217,8 @@ }, "node_modules/vfile": { "version": "6.0.3", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", - "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha1-NlKrHEllMYUr9VprrFevmB68OKs=", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -9181,8 +9231,8 @@ }, "node_modules/vfile-location": { "version": "5.0.3", - "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", - "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha1-y56s0g8rZCbRlFHg6vo9CoRiJcM=", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -9195,8 +9245,8 @@ }, "node_modules/vfile-message": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", - "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha1-h7RN3de3DwZBwuPtCGS6c+LqjfQ=", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -9208,18 +9258,17 @@ } }, "node_modules/vite": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.5.tgz", - "integrity": "sha512-KuOaNhcnGFN2zIPGA7wRmzF+lJA1sea7rHq17aiJ++9lzY1WWG6Jpwqwe1KNbRVPIqHmr8GLYx7jbrQcN/7/ww==", + "version": "8.1.5", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vite/-/vite-8.1.5.tgz", + "integrity": "sha1-zP/OPuSHsYhiI7JOuye5FnSCfTA=", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.27.0", - "fdir": "^6.5.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" + "lightningcss": "^1.32.0", + "picomatch": "^4.0.5", + "postcss": "^8.5.17", + "rolldown": "~1.1.5", + "tinyglobby": "^0.2.17" }, "bin": { "vite": "bin/vite.js" @@ -9235,9 +9284,10 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.3.0", + "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", - "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", @@ -9250,13 +9300,16 @@ "@types/node": { "optional": true }, - "jiti": { + "@vitejs/devtools": { "optional": true }, - "less": { + "esbuild": { "optional": true }, - "lightningcss": { + "jiti": { + "optional": true + }, + "less": { "optional": true }, "sass": { @@ -9284,8 +9337,8 @@ }, "node_modules/vite-plugin-singlefile": { "version": "2.3.3", - "resolved": "https://registry.npmjs.org/vite-plugin-singlefile/-/vite-plugin-singlefile-2.3.3.tgz", - "integrity": "sha512-XVnGH0QzbOa8fxRSsHdCarVN1BSBXNi7uLMQYlrGRN5apdHkk62XQWRJhVever0lnfuyBkwn+kvVChdm/OoOUg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vite-plugin-singlefile/-/vite-plugin-singlefile-2.3.3.tgz", + "integrity": "sha1-6FmupMDEt0/LumuvUn6I8q0J3mk=", "dev": true, "license": "MIT", "dependencies": { @@ -9305,19 +9358,19 @@ } }, "node_modules/vitest": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.9.tgz", - "integrity": "sha512-nE3/LEyc0z87uHYLZebqCUOaJr2hdtuPp7BQ4BosVFnfltxgAvMG08NyrSGlPpOUWvR27c5flSmYFTNr78L9GQ==", + "version": "4.1.10", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vitest/-/vitest-4.1.10.tgz", + "integrity": "sha1-fpKF7+JksRZwULejp/80eI4bevw=", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.1.9", - "@vitest/mocker": "4.1.9", - "@vitest/pretty-format": "4.1.9", - "@vitest/runner": "4.1.9", - "@vitest/snapshot": "4.1.9", - "@vitest/spy": "4.1.9", - "@vitest/utils": "4.1.9", + "@vitest/expect": "4.1.10", + "@vitest/mocker": "4.1.10", + "@vitest/pretty-format": "4.1.10", + "@vitest/runner": "4.1.10", + "@vitest/snapshot": "4.1.10", + "@vitest/spy": "4.1.10", + "@vitest/utils": "4.1.10", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", @@ -9345,12 +9398,12 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.9", - "@vitest/browser-preview": "4.1.9", - "@vitest/browser-webdriverio": "4.1.9", - "@vitest/coverage-istanbul": "4.1.9", - "@vitest/coverage-v8": "4.1.9", - "@vitest/ui": "4.1.9", + "@vitest/browser-playwright": "4.1.10", + "@vitest/browser-preview": "4.1.10", + "@vitest/browser-webdriverio": "4.1.10", + "@vitest/coverage-istanbul": "4.1.10", + "@vitest/coverage-v8": "4.1.10", + "@vitest/ui": "4.1.10", "happy-dom": "*", "jsdom": "*", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -9396,8 +9449,8 @@ }, "node_modules/vitest/node_modules/tinyexec": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", - "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/tinyexec/-/tinyexec-1.2.4.tgz", + "integrity": "sha1-rkW7Lt69qUxw9OqJfg8SQ+Rw23E=", "dev": true, "license": "MIT", "engines": { @@ -9406,8 +9459,8 @@ }, "node_modules/void-elements": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", - "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha1-YU9/v42AHwu18GYfWy9XhXUOTwk=", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -9415,14 +9468,14 @@ }, "node_modules/w3c-keyname": { "version": "2.2.8", - "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", - "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha1-exfIxog9TouGrIq6edOeiA+IacU=", "license": "MIT" }, "node_modules/web-namespaces": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", - "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha1-EBD/fGUOzLJZLOvur5obJT/UBpI=", "license": "MIT", "funding": { "type": "github", @@ -9431,8 +9484,8 @@ }, "node_modules/which": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/which/-/which-2.0.2.tgz", + "integrity": "sha1-fGqN0KY2oDJ+ELWckobu6T8/UbE=", "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -9446,8 +9499,8 @@ }, "node_modules/why-is-node-running": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha1-o/aalxB/SUs83Dvd3Yg6fWXOvwQ=", "dev": true, "license": "MIT", "dependencies": { @@ -9463,8 +9516,8 @@ }, "node_modules/word-wrap": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha1-0sRcbdT7zmIaZvE2y+Mor9BBCzQ=", "dev": true, "license": "MIT", "engines": { @@ -9473,8 +9526,8 @@ }, "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==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha1-lWgy3qlJQwbm0gnrhxZDu4c9fJg=", "license": "MIT", "dependencies": { "ansi-styles": "^6.2.1", @@ -9488,28 +9541,16 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi/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", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "license": "ISC" }, "node_modules/y18n": { "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha1-f0k00PfKjFb5UxSTndzS3ZHOHVU=", "license": "ISC", "engines": { "node": ">=10" @@ -9517,8 +9558,8 @@ }, "node_modules/yargs": { "version": "18.0.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", - "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha1-bIQlmAYnOnRrCfV5CHtoo8LSW9E=", "license": "MIT", "dependencies": { "cliui": "^9.0.1", @@ -9534,8 +9575,8 @@ }, "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==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha1-h7gglAUbBWdxc0bs0A/RSASzV8g=", "license": "ISC", "engines": { "node": "^20.19.0 || ^22.12.0 || >=23" @@ -9543,8 +9584,8 @@ }, "node_modules/yocto-queue": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha1-ApTrPe4FAo0x7hpfosVWpqrxChs=", "dev": true, "license": "MIT", "engines": { @@ -9556,8 +9597,8 @@ }, "node_modules/zod": { "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/zod/-/zod-3.25.76.tgz", + "integrity": "sha1-JoQcP2/SKmonYOfMtxkXl2hHHjQ=", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" @@ -9565,8 +9606,8 @@ }, "node_modules/zod-to-json-schema": { "version": "3.25.2", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", - "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", + "integrity": "sha1-P6eZp7rdVUVBRy+2WEP9xGCy5ao=", "license": "ISC", "peerDependencies": { "zod": "^3.25.28 || ^4" @@ -9574,8 +9615,8 @@ }, "node_modules/zrender": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/zrender/-/zrender-6.1.0.tgz", - "integrity": "sha512-oEGMDB6pOP2S6OwRR4PdVv610zrjnA3Bh+JnSG12fYJlBKjtNAoEb5fSUoCOOINlH96I2fU38/A2UpRKs67xYQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/zrender/-/zrender-6.1.0.tgz", + "integrity": "sha1-w+8G5kJtXCiGW3GDA1aA1oXgATY=", "license": "BSD-3-Clause", "dependencies": { "tslib": "2.3.0" @@ -9583,8 +9624,8 @@ }, "node_modules/zwitch": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", - "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha1-yCfUsKy3b8PmhaTG7CkC1RBw6dc=", "license": "MIT", "funding": { "type": "github", @@ -9593,7 +9634,7 @@ }, "packages/flint-js": { "name": "flint-chart", - "version": "0.3.0", + "version": "0.4.0", "license": "MIT", "devDependencies": { "@types/node": "^20.14.10", @@ -9614,6 +9655,7 @@ "peerDependencies": { "chart.js": "^4.0.0", "echarts": "^5.0.0 || ^6.0.0", + "plotly.js": "^2.0.0 || ^3.0.0", "vega": "^5.0.0 || ^6.0.0", "vega-lite": "^5.0.0 || ^6.0.0" }, @@ -9624,6 +9666,9 @@ "echarts": { "optional": true }, + "plotly.js": { + "optional": true + }, "vega": { "optional": true }, @@ -9634,7 +9679,7 @@ }, "packages/flint-mcp": { "name": "flint-chart-mcp", - "version": "0.3.0", + "version": "0.4.0", "license": "MIT", "dependencies": { "@modelcontextprotocol/ext-apps": "^1.7.4", @@ -9643,7 +9688,7 @@ "@resvg/resvg-js": "^2.6.2", "chart.js": "^4.4.0", "echarts": "^6.0.0", - "flint-chart": "^0.3.0", + "flint-chart": "^0.4.0", "vega": "^6.0.0", "vega-interpreter": "^2.2.1", "vega-lite": "^6.0.0", @@ -9670,17 +9715,10 @@ "node": ">=18" } }, - "packages/flint-mcp/node_modules/@rolldown/pluginutils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", - "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", - "dev": true, - "license": "MIT" - }, "packages/flint-mcp/node_modules/@types/react": { "version": "19.2.17", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", - "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@types/react/-/react-19.2.17.tgz", + "integrity": "sha1-3MrDZbqg8XNOwnD/S1HIlGXo3H8=", "dev": true, "license": "MIT", "dependencies": { @@ -9689,44 +9727,18 @@ }, "packages/flint-mcp/node_modules/@types/react-dom": { "version": "19.2.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha1-weMF0VpSo+UI1U3Kdw0gLLY6vyw=", "dev": true, "license": "MIT", "peerDependencies": { "@types/react": "^19.2.0" } }, - "packages/flint-mcp/node_modules/@vitejs/plugin-react": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.3.tgz", - "integrity": "sha512-vmFvco5/QuC2f9Oj+wTk0+9XeDFkHxSamwZKYc7MxYwKICfvUvlMhqKI0VuICPltGqh1neqBKDvO4kes1ya8vg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rolldown/pluginutils": "^1.0.1" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "peerDependencies": { - "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", - "babel-plugin-react-compiler": "^1.0.0", - "vite": "^8.0.0" - }, - "peerDependenciesMeta": { - "@rolldown/plugin-babel": { - "optional": true - }, - "babel-plugin-react-compiler": { - "optional": true - } - } - }, "packages/flint-mcp/node_modules/react": { "version": "19.2.7", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", - "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/react/-/react-19.2.7.tgz", + "integrity": "sha1-H0ehv8BvjsiFdSxvSvFDaan4Jgs=", "dev": true, "license": "MIT", "engines": { @@ -9735,8 +9747,8 @@ }, "packages/flint-mcp/node_modules/react-dom": { "version": "19.2.7", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", - "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/react-dom/-/react-dom-19.2.7.tgz", + "integrity": "sha1-BFDcmundv/du8ZZAHNi4x/tGbMw=", "dev": true, "license": "MIT", "dependencies": { @@ -9748,23 +9760,80 @@ }, "packages/flint-mcp/node_modules/scheduler": { "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha1-DE74LWfR5cHjWej8dtOofwRf5b0=", "dev": true, "license": "MIT" }, - "packages/flint-mcp/node_modules/vite": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.0.tgz", - "integrity": "sha512-BuJcQK/56NQTWDGn4ABea3q4SSBdNPWwNZKTkkUpcMPnLoquSYH8llRtSUIgoL1KSCpHt5eghLShn50mH36y7Q==", + "site": { + "name": "flint-chart-site", + "version": "0.0.0", + "dependencies": { + "@codemirror/lang-json": "^6.0.1", + "@fontsource-variable/inter": "^5.2.8", + "@uiw/react-codemirror": "^4.23.0", + "chart.js": "^4.5.1", + "echarts": "^6.0.0", + "flint-chart": "*", + "i18next": "^26.3.6", + "katex": "^0.17.0", + "plotly.js-dist-min": "^2.35.2", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-i18next": "^17.0.10", + "react-markdown": "^10.1.0", + "react-router-dom": "^7.18.1", + "react-syntax-highlighter": "^16.1.1", + "rehype-katex": "^7.0.1", + "remark-gfm": "^4.0.1", + "remark-math": "^6.0.0", + "vega": "^6.0.0", + "vega-embed": "^7.1.0", + "vega-lite": "^6.4.1" + }, + "devDependencies": { + "@types/react": "^18.3.0", + "@types/react-dom": "^18.3.0", + "@types/react-syntax-highlighter": "^15.5.13", + "@vitejs/plugin-react-swc": "^3.7.0", + "typescript": "^5.6.0", + "vite": "^7.3.5" + } + }, + "site/node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha1-R9K/TO9tRwsi9YMbQg+JZOC/dV8=", + "dev": true, + "license": "MIT" + }, + "site/node_modules/@vitejs/plugin-react-swc": { + "version": "3.11.0", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@vitejs/plugin-react-swc/-/plugin-react-swc-3.11.0.tgz", + "integrity": "sha1-2CzDB9UwGXp3tQI4hgzzGYkP/Bc=", "dev": true, "license": "MIT", "dependencies": { - "lightningcss": "^1.32.0", - "picomatch": "^4.0.4", - "postcss": "^8.5.15", - "rolldown": "~1.1.2", - "tinyglobby": "^0.2.17" + "@rolldown/pluginutils": "1.0.0-beta.27", + "@swc/core": "^1.12.11" + }, + "peerDependencies": { + "vite": "^4 || ^5 || ^6 || ^7" + } + }, + "site/node_modules/vite": { + "version": "7.3.5", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/vite/-/vite-7.3.5.tgz", + "integrity": "sha1-kMLQt7lKIk5+fc8i0pEv8LUpEWU=", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" }, "bin": { "vite": "bin/vite.js" @@ -9780,10 +9849,9 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.3.0", - "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", + "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", @@ -9796,18 +9864,15 @@ "@types/node": { "optional": true }, - "@vitejs/devtools": { - "optional": true - }, - "esbuild": { - "optional": true - }, "jiti": { "optional": true }, "less": { "optional": true }, + "lightningcss": { + "optional": true + }, "sass": { "optional": true }, @@ -9830,40 +9895,6 @@ "optional": true } } - }, - "site": { - "name": "flint-chart-site", - "version": "0.0.0", - "dependencies": { - "@codemirror/lang-json": "^6.0.1", - "@fontsource-variable/inter": "^5.2.8", - "@uiw/react-codemirror": "^4.23.0", - "chart.js": "^4.5.1", - "echarts": "^6.0.0", - "flint-chart": "*", - "i18next": "^26.3.6", - "katex": "^0.17.0", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "react-i18next": "^17.0.10", - "react-markdown": "^10.1.0", - "react-router-dom": "^6.30.4", - "react-syntax-highlighter": "^16.1.1", - "rehype-katex": "^7.0.1", - "remark-gfm": "^4.0.1", - "remark-math": "^6.0.0", - "vega": "^6.0.0", - "vega-embed": "^7.1.0", - "vega-lite": "^6.4.1" - }, - "devDependencies": { - "@types/react": "^18.3.0", - "@types/react-dom": "^18.3.0", - "@types/react-syntax-highlighter": "^15.5.13", - "@vitejs/plugin-react-swc": "^3.7.0", - "typescript": "^5.6.0", - "vite": "^7.3.5" - } } } } diff --git a/package.json b/package.json index 8b9529ef..531653b6 100644 --- a/package.json +++ b/package.json @@ -33,12 +33,19 @@ "engines": { "node": ">=18" }, + "devDependencies": { + "@types/react": "^18.3.0", + "@types/react-dom": "^18.3.0", + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, "optionalDependencies": { "@rollup/rollup-linux-x64-gnu": "^4.0.0", "@swc/core-linux-x64-gnu": "1.15.33" }, "overrides": { "esbuild": "^0.28.1", - "js-yaml": "^4.2.0" + "js-yaml": "^4.2.0", + "@hono/node-server": "^2.0.5" } } \ No newline at end of file diff --git a/packages/flint-js/README.md b/packages/flint-js/README.md index 2737a1d2..c8ffceab 100644 --- a/packages/flint-js/README.md +++ b/packages/flint-js/README.md @@ -2,7 +2,8 @@ > A semantic-level visualization library that compiles data **+** semantic types > into chart specifications for [Vega-Lite](https://vega.github.io/vega-lite/), -> [ECharts](https://echarts.apache.org/), and [Chart.js](https://www.chartjs.org/). +> [ECharts](https://echarts.apache.org/), [Chart.js](https://www.chartjs.org/), +> [Plotly](https://plotly.com/javascript/), and native Excel charts through Office.js. You (or an LLM) describe a chart at the semantic level: chart type, field assignments, and a **semantic type** per field (e.g. `Revenue`, `Rank`, @@ -44,22 +45,26 @@ const vegaLiteSpec = assembleVegaLite(input); The same `ChartAssemblyInput` compiles to any backend: ```ts -import { assembleVegaLite, assembleECharts, assembleChartjs } from 'flint-chart'; +import { assembleVegaLite, assembleECharts, assembleChartjs, assemblePlotly, assembleExcel } from 'flint-chart'; const vl = assembleVegaLite(input); // Vega-Lite spec const ec = assembleECharts(input); // ECharts option const cj = assembleChartjs(input); // Chart.js config +const pl = assemblePlotly(input); // Plotly.js figure +const xl = assembleExcel(input); // Native Excel chart artifact ``` ## Subpath exports | Import | Contents | |---|---| -| `flint-chart` | Top-level: the three `assemble*` functions plus core types | +| `flint-chart` | Top-level assemblers plus core types | | `flint-chart/core` | Semantic types, `ChartAssemblyInput`, shared compiler logic | | `flint-chart/vegalite` | Vega-Lite backend | | `flint-chart/echarts` | ECharts backend | | `flint-chart/chartjs` | Chart.js backend | +| `flint-chart/plotly` | Plotly backend | +| `flint-chart/excel` | Native Excel / Office.js backend | | `flint-chart/test-data` | Sample data generators used by the gallery and tests | | `flint-chart/gallery` | Curated example specs | @@ -68,10 +73,13 @@ declarations for every entry point. ## Rendering -This package produces **specs**, not pixels. To render those specs to PNG or SVG +The web backends produce **specs**, not pixels. To render those specs to PNG or SVG without a browser, use the companion [`flint-chart-mcp`](https://github.com/microsoft/flint-chart/tree/main/packages/flint-mcp) -server (or pass the spec to your own Vega-Lite / ECharts / Chart.js renderer). +server (or pass the spec to your own Vega-Lite / ECharts / Chart.js / Plotly renderer). +The Excel backend instead produces a native-chart artifact: use +`renderExcelChart(Excel, artifact)` inside an Office.js Excel host, or +`generateOfficeJs(artifact)` to emit portable Office.js source. ## Documentation diff --git a/packages/flint-js/package.json b/packages/flint-js/package.json index f19123cd..893a7d74 100644 --- a/packages/flint-js/package.json +++ b/packages/flint-js/package.json @@ -1,7 +1,7 @@ { "name": "flint-chart", - "version": "0.3.0", - "description": "Semantic-level visualization library that compiles data + semantic types into chart specs for Vega-Lite, ECharts, and Chart.js.", + "version": "0.4.0", + "description": "Semantic-level visualization library that compiles data + semantic types for Vega-Lite, ECharts, Chart.js, Plotly, and Excel.", "keywords": [ "visualization", "charts", @@ -50,11 +50,21 @@ "import": "./dist/echarts/index.js", "require": "./dist/echarts/index.cjs" }, + "./plotly": { + "types": "./dist/plotly/index.d.ts", + "import": "./dist/plotly/index.js", + "require": "./dist/plotly/index.cjs" + }, "./chartjs": { "types": "./dist/chartjs/index.d.ts", "import": "./dist/chartjs/index.js", "require": "./dist/chartjs/index.cjs" }, + "./excel": { + "types": "./dist/excel/index.d.ts", + "import": "./dist/excel/index.js", + "require": "./dist/excel/index.cjs" + }, "./test-data": { "types": "./dist/test-data/index.d.ts", "import": "./dist/test-data/index.js", @@ -87,6 +97,7 @@ }, "peerDependencies": { "chart.js": "^4.0.0", + "plotly.js": "^2.0.0 || ^3.0.0", "echarts": "^5.0.0 || ^6.0.0", "vega": "^5.0.0 || ^6.0.0", "vega-lite": "^5.0.0 || ^6.0.0" @@ -103,6 +114,9 @@ }, "chart.js": { "optional": true + }, + "plotly.js": { + "optional": true } }, "devDependencies": { diff --git a/packages/flint-js/src/README.md b/packages/flint-js/src/README.md index da7b9685..fee77c2a 100644 --- a/packages/flint-js/src/README.md +++ b/packages/flint-js/src/README.md @@ -202,9 +202,12 @@ interface AssembleOptions { elasticity?: number; // axis stretch exponent (default 0.5) maxStretch?: number; // axis stretch cap (default 1.5) facetElasticity?: number; // facet stretch exponent (default 0.3) - maxStretch?: number; // unified stretch cap (default 1.5) minStep?: number; // min px per discrete tick (default 6) minSubplotSize?: number; // min facet subplot px (default 60) + defaultBandSize?: number; // baseline px per category (backend-tuned) + maxBandSize?: number; // max px per category when sparse (backend-tuned) + baseLabelFontSize?: number; // axis tick font, backend-native (VL 10, others 12) + baseTitleFontSize?: number; // header font, backend-native (VL 11, EC/CJS 12, Plotly 14) } ``` diff --git a/packages/flint-js/src/vegalite/templates/geo-lookup.ts b/packages/flint-js/src/chart-types/geo.ts similarity index 64% rename from packages/flint-js/src/vegalite/templates/geo-lookup.ts rename to packages/flint-js/src/chart-types/geo.ts index aa8ab1ba..100a41ef 100644 --- a/packages/flint-js/src/vegalite/templates/geo-lookup.ts +++ b/packages/flint-js/src/chart-types/geo.ts @@ -2,15 +2,23 @@ // Licensed under the MIT License. /** - * Geographic gazetteer for choropleth maps. + * Geographic gazetteer for choropleth maps — shared across backends. * * Real-world datasets identify regions by *name* ("California", "United * States") or by a familiar short code (USPS "CA", ISO alpha-2 "US", alpha-3 * "USA") — almost never by the numeric ids that TopoJSON feature geometries * actually carry (FIPS state codes, ISO 3166-1 *numeric* country codes). This - * module crosswalks any of those user-facing forms to the numeric id that - * matches Vega's `us-10m.json` (states) and `world-110m.json` (countries) - * feature ids, so a choropleth can join on whatever the user happens to have. + * module crosswalks any of those user-facing forms to whatever key a given + * backend's geo rendering needs: + * + * - `resolveUsState` / `resolveCountry` — numeric feature id, for the + * Vega-Lite backend's TopoJSON join (`us-10m.json` / `world-110m.json`). + * - `resolveUsStateCode` / `resolveCountryCode` — USPS / ISO alpha-3 code, + * for the Plotly backend's native `choropleth`/`scattergeo` `locations`. + * + * Living in `chart-types/` (rather than under one backend's `templates/`) + * follows the same cross-backend-shared-logic convention as + * `chart-types/gantt.ts` / `chart-types/waterfall.ts`. * * Lookups are case- and punctuation-insensitive. A value that is already the * numeric id passes through unchanged. @@ -199,3 +207,121 @@ export const resolveUsState: GeoResolver = (value) => resolveWith(US_STATE_LOOKU /** Resolve a country name / ISO alpha-2 / alpha-3 / numeric to its ISO numeric id. */ export const resolveCountry: GeoResolver = (value) => resolveWith(COUNTRY_LOOKUP, value); + +// --------------------------------------------------------------------------- +// Code resolvers — for backends (Plotly) whose native geo traces key on a +// short code rather than a TopoJSON numeric feature id. +// +// Plotly's `choropleth`/`scattergeo` traces resolve `locations` through a +// built-in atlas (no user-supplied TopoJSON needed) keyed on: +// - `locationmode: 'USA-states'` → 2-letter USPS codes ("CA") +// - default (`locationmode: 'ISO-3'`) → 3-letter ISO alpha-3 codes ("USA") +// +// These resolvers share the same gazetteer/alias tables as the numeric-id +// resolvers above (`resolveUsState` / `resolveCountry`), so a value that +// resolves for the Vega-Lite choropleth (name, USPS/ISO code, or a bare +// numeric id) resolves the same way here — same data contract, different +// output shape. +// --------------------------------------------------------------------------- + +/** A code resolver: user value → the short code a native geo trace expects. */ +export type GeoCodeResolver = (value: unknown) => string | undefined; + +function resolveCodeWith( + lookup: Map, codeById: Map, value: unknown, +): string | undefined { + if (value == null) return undefined; + // A bare numeric id (or numeric string) is resolved through the same + // id → code table used to build the gazetteer. + if (typeof value === 'number' && Number.isFinite(value)) return codeById.get(value); + const s = String(value).trim(); + if (/^\d+$/.test(s)) return codeById.get(parseInt(s, 10)); + const id = resolveWith(lookup, value); + return id !== undefined ? codeById.get(id) : undefined; +} + +const US_STATE_USPS_BY_ID = new Map(US_STATES.map(([id, , usps]) => [id, usps])); +const COUNTRY_ALPHA3_BY_ID = new Map(COUNTRIES.map(([id, , , a3]) => [id, a3])); + +/** Resolve a US state name / USPS code / FIPS id to its 2-letter USPS code. */ +export const resolveUsStateCode: GeoCodeResolver = (value) => + resolveCodeWith(US_STATE_LOOKUP, US_STATE_USPS_BY_ID, value); + +/** Resolve a country name / ISO alpha-2 / alpha-3 / numeric to its ISO alpha-3 code. */ +export const resolveCountryCode: GeoCodeResolver = (value) => + resolveCodeWith(COUNTRY_LOOKUP, COUNTRY_ALPHA3_BY_ID, value); + +// --------------------------------------------------------------------------- +// Map scope inference (US vs World) — shared by every backend's Map / +// Choropleth templates so "which base geography do we draw" is decided the +// same way regardless of which renderer draws it. +// --------------------------------------------------------------------------- + +export type MapScope = 'us' | 'world'; + +// Generous bounding box for the United States (contiguous states + Alaska + +// Hawaii). Used only to *infer* scope: a dataset whose every point falls +// inside is treated as a US map; anything outside flips the whole map to world. +const US_LON: readonly [number, number] = [-170, -66]; +const US_LAT: readonly [number, number] = [18, 72]; + +function inUsBox(lon: number, lat: number): boolean { + return lon >= US_LON[0] && lon <= US_LON[1] && lat >= US_LAT[0] && lat <= US_LAT[1]; +} + +/** Infer scope for a bubble map from its longitude/latitude points. */ +export function inferBubbleScope(rows: any[], lonField?: string, latField?: string): MapScope { + if (!lonField || !latField) return 'us'; + for (const r of rows) { + const lon = Number(r[lonField]); + const lat = Number(r[latField]); + if (!Number.isFinite(lon) || !Number.isFinite(lat)) continue; + if (!inUsBox(lon, lat)) return 'world'; + } + return 'us'; +} + +/** Infer scope for a choropleth from its region keys (names / codes / ids). */ +export function inferChoroplethScope(rows: any[], idField?: string): MapScope { + if (!idField) return 'us'; + for (const r of rows) { + const v = r[idField]; + if (v == null || v === '') continue; + // A value that resolves as a US state (by name, USPS code, FIPS id, or a + // bare numeric that passes straight through) keeps us in the US; the + // first value that doesn't flips the whole map to world. + if (resolveUsState(v) === undefined) return 'world'; + } + return 'us'; +} + +/** + * Map the id field's *semantic type* to a map scope. This is the most reliable + * signal we have: a field declared 'State' should use the US states map and the + * US-state resolver, a field declared 'Country' the world map and country + * resolver. It disambiguates the codes that collide between the two namespaces + * — "CA" (California vs Canada), "IN" (Indiana vs India), "Georgia" (US state + * vs the country) — which value inference alone cannot. Geographic types that + * neither base layer can render (City, Region, Address, ZipCode) return + * undefined so callers fall back to value inference. + */ +const SEMANTIC_SCOPE: Record = { State: 'us', Country: 'world' }; + +export function semanticScope(semType: string | undefined): MapScope | undefined { + if (!semType) return undefined; + return Object.prototype.hasOwnProperty.call(SEMANTIC_SCOPE, semType) + ? SEMANTIC_SCOPE[semType] + : undefined; +} + +/** Honor an explicit `region` choice, else the id field's semantic type, else inference. */ +export function pickMapScope( + chartProperties: any, + semScope: MapScope | undefined, + infer: () => MapScope, +): MapScope { + const choice = chartProperties?.region; + if (choice === 'us' || choice === 'world') return choice; + if (semScope) return semScope; + return infer(); +} diff --git a/packages/flint-js/src/chartjs/assemble.ts b/packages/flint-js/src/chartjs/assemble.ts index 92aad559..a4eb8053 100644 --- a/packages/flint-js/src/chartjs/assemble.ts +++ b/packages/flint-js/src/chartjs/assemble.ts @@ -39,7 +39,7 @@ import { cjsGetTemplateDef } from './templates'; import { resolveChannelSemantics, convertTemporalData } from '../core/resolve-semantics'; import { computeZeroDecision } from '../core/semantic-types'; import { filterOverflow } from '../core/filter-overflow'; -import { computeLayout, computeChannelBudgets, deriveStretchCaps, resolveBaseSize } from '../core/compute-layout'; +import { computeLayout, computeChannelBudgets, deriveStretchCaps, resolveBaseSize, resolveFacetColumnsOption } from '../core/compute-layout'; import { decideColorMaps } from '../core/color-decisions'; import { cjsApplyLayoutToSpec, cjsApplyTooltips } from './instantiate-spec'; import { normalizeStaticSeries } from '../core/static-series'; @@ -163,6 +163,13 @@ export function assembleChartjs(input: ChartAssemblyInput): any { // Chart.js fills its canvas natively — a wider default band size // matches its generous category spacing behavior. defaultBandSize: 30, + // Chart.js has no default maxBarThickness, so sparse bars fill the + // canvas. Allow bands to expand past the base to match, capped so a + // couple of bars don't span the whole canvas. + maxBandSize: 100, + // Chart.js native font default (12 for ticks, legend, and title). + baseLabelFontSize: 12, + baseTitleFontSize: 12, ...options, ...(declaration.paramOverrides || {}), }; @@ -170,6 +177,7 @@ export function assembleChartjs(input: ChartAssemblyInput): any { // Resolve the optional canvasSize ceiling into per-dimension stretch caps // (βx, βy). Falls back to maxStretch when no ceiling is set. Object.assign(effectiveOptions, deriveStretchCaps(baseSize, sizeCeiling, effectiveOptions)); + effectiveOptions.facetColumns = resolveFacetColumnsOption(input.chart_spec.chartProperties); const { addTooltips: addTooltipsOpt = false, diff --git a/packages/flint-js/src/chartjs/instantiate-spec.ts b/packages/flint-js/src/chartjs/instantiate-spec.ts index 46d4e504..93de7071 100644 --- a/packages/flint-js/src/chartjs/instantiate-spec.ts +++ b/packages/flint-js/src/chartjs/instantiate-spec.ts @@ -113,6 +113,13 @@ export function cjsApplyLayoutToSpec( size: layout.xLabel.fontSize, }; } + // Axis title (scale title) font — canvas-adaptive header size. + if (config.options.scales.x.title?.display) { + config.options.scales.x.title.font = { + ...(config.options.scales.x.title.font || {}), + size: layout.titleFontSize, + }; + } } // ── Y-axis label sizing ────────────────────────────────────────────── @@ -125,6 +132,25 @@ export function cjsApplyLayoutToSpec( size: layout.yLabel.fontSize, }; } + if (config.options.scales.y.title?.display) { + config.options.scales.y.title.font = { + ...(config.options.scales.y.title.font || {}), + size: layout.titleFontSize, + }; + } + } + + // ── Legend / chart title font — canvas-adaptive header sizes ────────── + if (config.options?.plugins?.legend) { + const legend = config.options.plugins.legend; + if (!legend.labels) legend.labels = {}; + legend.labels.font = { ...(legend.labels.font || {}), size: layout.legendFontSize }; + } + if (config.options?.plugins?.title?.display) { + config.options.plugins.title.font = { + ...(config.options.plugins.title.font || {}), + size: layout.titleFontSize, + }; } // ── Overflow truncation warnings ───────────────────────────────────── diff --git a/packages/flint-js/src/chartjs/templates/bump.ts b/packages/flint-js/src/chartjs/templates/bump.ts new file mode 100644 index 00000000..6f077cf0 --- /dev/null +++ b/packages/flint-js/src/chartjs/templates/bump.ts @@ -0,0 +1,204 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Chart.js Bump Chart — line with points, rank axis reversed so rank 1 sits on + * top (mirror of ecBumpChartDef in echarts/templates/line.ts and + * vegalite/templates/bump.ts). + * + * Unlike ECharts — where a value-axis `inverse` moves the x-axis to the top, + * forcing a category-index workaround — Chart.js reverses a linear scale in + * place (`reverse: true`), so series keep their real rank values and the + * config stays pure JSON with no tooltip formatter. + */ + +import { ChartTemplateDef } from '../../core/types'; +import { + extractCategories, + groupBy, + buildCategoryAlignedData, + getChartJsPalette, + getSeriesBorderColor, + coerceUnixMsForChartJs, +} from './utils'; +import { toTypeString } from '../../core/field-semantics'; + +/** Semantic types that indicate a rank-like field (mirror vegalite/templates/bump.ts). */ +const RANK_SEMANTIC_TYPES = new Set(['Rank', 'Score', 'Level']); + +const isDiscrete = (type: string | undefined) => type === 'nominal' || type === 'ordinal'; + +export const cjsBumpChartDef: ChartTemplateDef = { + chart: 'Bump Chart', + template: { mark: 'line', encoding: {} }, + channels: ['x', 'y', 'color', 'detail', 'column', 'row'], + markCognitiveChannel: 'position', + declareLayoutMode: () => ({ + paramOverrides: { continuousMarkCrossSection: { x: 80, y: 20, seriesCountAxis: 'auto' } }, + }), + instantiate: (spec, ctx) => { + const { channelSemantics, table, fullTable, semanticTypes } = ctx; + const xCS = channelSemantics.x; + const yCS = channelSemantics.y; + const colorField = channelSemantics.color?.field; + + if (!xCS?.field || !yCS?.field) return; + const xField = xCS.field; + const yField = yCS.field; + + const ySemType = toTypeString(semanticTypes?.[yField]); + const xSemType = toTypeString(semanticTypes?.[xField]); + const yIsRank = RANK_SEMANTIC_TYPES.has(ySemType); + const xIsRank = RANK_SEMANTIC_TYPES.has(xSemType); + const rankOnY = yIsRank && !xIsRank; + + const xIsDiscrete = isDiscrete(xCS.type); + const xIsTemporal = xCS.type === 'temporal'; + + const mapContinuousX = (raw: unknown) => + (xIsTemporal ? coerceUnixMsForChartJs(raw) : raw); + + // Pin continuous x to the data extent (same reasoning as line.ts: + // Chart.js "nice" ranges balloon on Unix-ms timestamps). + let continuousXExtent: { min: number; max: number } | undefined; + if (!xIsDiscrete) { + const xNums = (fullTable ?? table) + .map((r: any) => mapContinuousX(r[xField])) + .filter((v: any): v is number => typeof v === 'number' && Number.isFinite(v)); + if (xNums.length > 0) { + continuousXExtent = { min: Math.min(...xNums), max: Math.max(...xNums) }; + } + } + + const categories = xIsDiscrete + ? extractCategories(table, xField, xCS.ordinalSortOrder) + : undefined; + + const sortRowsByX = (rows: any[]) => + [...rows].sort((a, b) => { + const ax = mapContinuousX(a[xField]); + const bx = mapContinuousX(b[xField]); + if (typeof ax === 'number' && typeof bx === 'number') return ax - bx; + return String(ax).localeCompare(String(bx)); + }); + + const rankValues = table + .map((r: any) => Number(r[yField])) + .filter((v: number) => !isNaN(v) && isFinite(v)); + const maxRank = rankValues.length ? Math.max(...rankValues) : 1; + + const palette = getChartJsPalette(ctx, 'color'); + + const config: any = { + type: 'line', + data: { labels: categories || [], datasets: [] }, + options: { + responsive: true, + maintainAspectRatio: false, + scales: { + x: { + type: xIsDiscrete ? 'category' : 'linear', + title: { display: true, text: xField }, + ...(continuousXExtent + ? { min: continuousXExtent.min, max: continuousXExtent.max } + : {}), + ticks: { + font: { size: 10 }, + ...(xIsTemporal + ? { + maxTicksLimit: 4, + autoSkip: true, + maxRotation: 0, + callback(v: number | string) { + const n = typeof v === 'number' ? v : Number(v); + if (!Number.isFinite(n)) return String(v); + const spanDays = continuousXExtent + ? (continuousXExtent.max - continuousXExtent.min) / 86_400_000 + : 0; + const opts: Intl.DateTimeFormatOptions = spanDays > 60 + ? { month: 'short', year: 'numeric' } + : { month: 'short', day: 'numeric', year: 'numeric' }; + return new Date(n).toLocaleDateString(undefined, opts); + }, + } + : {}), + }, + }, + y: rankOnY + ? { + type: 'linear', + reverse: true, + min: 1, + max: maxRank, + title: { display: true, text: yField }, + ticks: { font: { size: 10 }, stepSize: 1, precision: 0 }, + } + : { + type: 'linear', + title: { display: true, text: yField }, + ticks: { font: { size: 10 } }, + }, + }, + plugins: { + tooltip: { enabled: true }, + }, + }, + }; + + // Zero-baseline only applies to the non-rank value axis; a reversed + // rank axis is pinned to [1, maxRank] instead. + if (!rankOnY && channelSemantics.y?.zero) { + config.options.scales.y.beginAtZero = channelSemantics.y.zero.zero !== false; + } + + const baseDataset = { + tension: 0.4, + pointRadius: 3, + fill: false, + backgroundColor: 'transparent', + }; + + if (colorField) { + const groups = groupBy(table, colorField); + config.options.plugins.legend = { display: true }; + + let colorIdx = 0; + for (const [name, rows] of groups) { + const data = xIsDiscrete + ? buildCategoryAlignedData(rows, xField, yField, categories!) + : sortRowsByX(rows) + .map(r => ({ x: mapContinuousX(r[xField]), y: r[yField] })) + .filter(p => p.y != null && (xIsTemporal ? Number.isFinite(p.x as number) : true)); + + config.data.datasets.push({ + label: name, + data, + borderColor: getSeriesBorderColor(palette, colorIdx), + ...baseDataset, + }); + colorIdx++; + } + } else { + const data = xIsDiscrete + ? categories!.map(cat => { + const row = table.find(r => String(r[xField]) === cat); + return row ? row[yField] : null; + }) + : sortRowsByX(table) + .map(r => ({ x: mapContinuousX(r[xField]), y: r[yField] })) + .filter(p => p.y != null && (xIsTemporal ? Number.isFinite(p.x as number) : true)); + + config.data.datasets.push({ + label: yField, + data, + borderColor: getSeriesBorderColor(palette, 0), + ...baseDataset, + }); + config.options.plugins.legend = { display: false }; + } + + Object.assign(spec, config); + delete spec.mark; + delete spec.encoding; + }, +}; diff --git a/packages/flint-js/src/chartjs/templates/index.ts b/packages/flint-js/src/chartjs/templates/index.ts index ce1e6a23..0a54c051 100644 --- a/packages/flint-js/src/chartjs/templates/index.ts +++ b/packages/flint-js/src/chartjs/templates/index.ts @@ -16,6 +16,7 @@ import { cjsStripPlotDef } from './jitter'; import { cjsBarChartDef, cjsStackedBarChartDef, cjsGroupedBarChartDef } from './bar'; import { cjsComboChartDef } from './combo'; import { cjsLineChartDef } from './line'; +import { cjsBumpChartDef } from './bump'; import { cjsSlopeChartDef } from './slope'; import { cjsAreaChartDef } from './area'; import { cjsRangeAreaChartDef } from './range-area'; @@ -34,7 +35,7 @@ import { cjsWaterfallChartDef } from './waterfall'; export const cjsTemplateDefs: { [key: string]: ChartTemplateDef[] } = { 'Scatter & Point': [cjsScatterPlotDef, cjsConnectedScatterDef, cjsBubbleChartDef, cjsStripPlotDef], 'Bar': [cjsBarChartDef, cjsGroupedBarChartDef, cjsStackedBarChartDef, cjsComboChartDef, cjsHistogramDef, cjsWaterfallChartDef, cjsGanttChartDef], - 'Line & Area': [cjsLineChartDef, cjsSlopeChartDef, cjsAreaChartDef, cjsRangeAreaChartDef, cjsEcdfPlotDef], + 'Line & Area': [cjsLineChartDef, cjsBumpChartDef, cjsSlopeChartDef, cjsAreaChartDef, cjsRangeAreaChartDef, cjsEcdfPlotDef], 'Part-to-Whole': [cjsPieChartDef, cjsDoughnutChartDef], 'Polar': [cjsRadarChartDef, cjsRoseChartDef], }; diff --git a/packages/flint-js/src/core/compute-layout.ts b/packages/flint-js/src/core/compute-layout.ts index 07e13cc3..b9c6d3fa 100644 --- a/packages/flint-js/src/core/compute-layout.ts +++ b/packages/flint-js/src/core/compute-layout.ts @@ -55,6 +55,7 @@ import { computeAxisStep, computeGasPressure, computeLabelSizing, + computeFontSizing, DEFAULT_GAS_PRESSURE_PARAMS, type ElasticStretchParams, type GasPressureParams, @@ -192,6 +193,22 @@ export function resolveBaseSize( }; } +/** + * Read the user's `facetColumns` chart property (the interactive facet-wrap + * control) off the RAW chart_spec.chartProperties, returning a clamped integer + * column count or undefined for auto. Read raw (pre-normalization) because + * `facetColumns` is a layout-level option, not a per-template mark property, so + * `normalizeChartProperties` would otherwise drop it as an unknown key. + */ +export function resolveFacetColumnsOption( + chartProperties: Record | undefined, +): number | undefined { + const raw = chartProperties?.facetColumns; + if (raw == null) return undefined; + const n = Number(raw); + return Number.isFinite(n) && n >= 1 ? Math.floor(n) : undefined; +} + /** * Derive per-dimension stretch ceilings (βx, βy) for an assembler. * @@ -280,6 +297,11 @@ export function computeLayout( const sizeRatio = Math.max(defaultChartWidth, defaultChartHeight) / baseRefSize; const baseBandSize = options.defaultBandSize ?? 20; const defaultStepSize = Math.round(baseBandSize * Math.max(1, sizeRatio)); + // Sparse-expansion ceiling: a band may grow past its base size to fill a + // wide plot, but never past maxStepSize. Defaults to the base band, so a + // backend that doesn't opt in keeps the old "cap at base" behavior. + const maxBandSize = Math.max(baseBandSize, options.maxBandSize ?? baseBandSize); + const maxStepSize = Math.round(maxBandSize * Math.max(1, sizeRatio)); const isDiscreteType = (t: string | undefined) => t === 'nominal' || t === 'ordinal'; @@ -795,32 +817,32 @@ export function computeLayout( if (xIsDiscrete && xHasGrouping) { const itemsPerGroup = nominalCount.group; - const defaultGroupStep = itemsPerGroup * defaultStepSize; + const defaultGroupStep = itemsPerGroup * maxStepSize; const minGroupStep = Math.max(Math.ceil(MIN_GROUP_GAP_PX / stepPaddingVal), 2 * itemsPerGroup); const groupAxis = computeAxisStep(nominalCount.x, 0, subplotWidth, elasticParamsX); const groupStep = Math.max(minGroupStep, Math.min(defaultGroupStep, groupAxis.step)); xStepSize = groupStep; xStepUnit = 'group'; } else if (xIsDiscrete) { - xStepSize = Math.max(minStepVal, Math.min(defaultStepSize, xAxis.step)); + xStepSize = Math.max(minStepVal, Math.min(maxStepSize, xAxis.step)); } else if (xContinuousAsDiscrete > 0) { - xStepSize = Math.max(minStepVal, Math.min(defaultStepSize, xAxis.step)); + xStepSize = Math.max(minStepVal, Math.min(maxStepSize, xAxis.step)); } else { xStepSize = defaultStepSize; } if (yIsDiscrete && yHasGrouping) { const itemsPerGroup = nominalCount.group; - const defaultGroupStep = itemsPerGroup * defaultStepSize; + const defaultGroupStep = itemsPerGroup * maxStepSize; const minGroupStep = Math.max(Math.ceil(MIN_GROUP_GAP_PX / stepPaddingVal), 2 * itemsPerGroup); const groupAxis = computeAxisStep(nominalCount.y, 0, subplotHeight, elasticParamsY); const groupStep = Math.max(minGroupStep, Math.min(defaultGroupStep, groupAxis.step)); yStepSize = groupStep; yStepUnit = 'group'; } else if (yIsDiscrete) { - yStepSize = Math.max(minStepVal, Math.min(defaultStepSize, yAxis.step)); + yStepSize = Math.max(minStepVal, Math.min(maxStepSize, yAxis.step)); } else if (yContinuousAsDiscrete > 0) { - yStepSize = Math.max(minStepVal, Math.min(defaultStepSize, yAxis.step)); + yStepSize = Math.max(minStepVal, Math.min(maxStepSize, yAxis.step)); } else { yStepSize = defaultStepSize; } @@ -928,10 +950,24 @@ export function computeLayout( } // --- Label sizing --- - const xHasDiscreteItems = xTotalNominalCount > 0; - const yHasDiscreteItems = yTotalNominalCount > 0; - let xLabel = computeLabelSizing(xStepSize, xHasDiscreteItems); - let yLabel = computeLabelSizing(yStepSize, yHasDiscreteItems); + // A temporal/numeric field used as a BANDED axis (one bar per value) is + // "continuous-as-discrete": its tick labels sit one-per-band exactly like a + // nominal axis, so they must follow the same discrete sizing ladder (shrink + // — and rotate when bands are narrow) rather than staying at the full + // continuous base font. Otherwise dense date/number bands render oversized + // labels that feel too large for their band and crowd together. + const xHasDiscreteItems = xTotalNominalCount > 0 || xContinuousAsDiscrete > 0; + const yHasDiscreteItems = yTotalNominalCount > 0 || yContinuousAsDiscrete > 0; + // Canvas-adaptive fonts: descend the tick ladder from the backend's native + // base, and derive header/legend sizes. Scaled by the (sub)plot's smaller + // dimension so small multiples shrink and large single views grow subtly. + const fontSizing = computeFontSizing(Math.min(subplotWidth, subplotHeight), { + baseLabelFontSize: options.baseLabelFontSize, + baseTitleFontSize: options.baseTitleFontSize, + }); + const labelOpts = { baseFont: fontSizing.tickBase, minFont: 6 }; + let xLabel = computeLabelSizing(xStepSize, xHasDiscreteItems, labelOpts); + let yLabel = computeLabelSizing(yStepSize, yHasDiscreteItems, labelOpts); if (xHasDiscreteItems) { const xf = channelSemantics.x?.field; @@ -963,7 +999,7 @@ export function computeLayout( const cap = Math.max(minStepVal, Math.floor(maxSubplotW / stats.count)); if (desiredStep <= cap) { xStepSize = Math.max(xStepSize, desiredStep); - xLabel = computeLabelSizing(xStepSize, xHasDiscreteItems); + xLabel = computeLabelSizing(xStepSize, xHasDiscreteItems, labelOpts); labelPx = stats.maxLen * xLabel.fontSize * APPROX_CHAR_WIDTH_RATIO; } } @@ -1014,6 +1050,14 @@ export function computeLayout( } } + // Keep tick labels consistent across axes. A continuous value axis stays at + // the base font, but a banded axis shrinks its labels as bands tighten — so + // the value "numbers" can end up visibly larger than the category "text". + // Unify both tick fonts to the smaller of the two so they read as one size. + const unifiedTickFont = Math.min(xLabel.fontSize, yLabel.fontSize); + if (xLabel.fontSize !== unifiedTickFont) xLabel = { ...xLabel, fontSize: unifiedTickFont }; + if (yLabel.fontSize !== unifiedTickFont) yLabel = { ...yLabel, fontSize: unifiedTickFont }; + return { subplotWidth, subplotHeight, @@ -1027,6 +1071,8 @@ export function computeLayout( yNominalCount: yTotalNominalCount, xLabel, yLabel, + titleFontSize: fontSizing.titleFontSize, + legendFontSize: fontSizing.legendFontSize, stepPadding: stepPaddingVal, facet: (facetCols > 1 || facetRows > 1) ? { columns: facetCols, @@ -1630,7 +1676,23 @@ export function computeFacetGrid( if (colCount === 0 && rowCount === 0) return undefined; + // Explicit user override: force a specific column count for a column-wrapped + // facet (the `facetColumns` chart property). Clamped to [1, colCount]; the + // remaining panels wrap into as many rows as needed (all kept, canvas grows). + const forcedCols = options.facetColumns != null && options.facetColumns >= 1 + ? Math.min(Math.max(1, Math.floor(options.facetColumns)), Math.max(1, colCount)) + : undefined; + if (colCount > 0 && rowCount === 0) { + if (forcedCols != null) { + const nRows = Math.ceil(colCount / forcedCols); + return { + columns: forcedCols, + rows: nRows, + maxColumnValues: forcedCols * nRows, + maxRowValues: Math.max(maxFacetRows, nRows), + }; + } // Column-only. If all panels fit in one row, use a single row. // Otherwise wrap into a balanced grid: pick the number of rows // that makes the grid as square as possible (cols ≈ rows) while diff --git a/packages/flint-js/src/core/decisions.ts b/packages/flint-js/src/core/decisions.ts index 29fbc1dd..0b23dc04 100644 --- a/packages/flint-js/src/core/decisions.ts +++ b/packages/flint-js/src/core/decisions.ts @@ -710,35 +710,50 @@ export interface LabelSizingDecision { * Compute label sizing for a discrete axis based on the effective step size. * Pure decision — returns sizing params without modifying any spec. * + * The font descends the **shrink → rotate → cap** ladder from a backend-native + * base font (`baseFont`), never exceeding it and never dropping below `minFont`: + * 1. Wide band → horizontal label at (up to) `baseFont`. + * 2. Medium band → shrink a little and rotate -45°. + * 3. Narrow band → shrink more and rotate -90°. + * `labelLimit` caps the label width so long text is truncated (…) rather than + * overflowing arbitrarily. + * * @param effectiveStep Pixels per discrete item * @param hasDiscreteItems Whether the axis has discrete items + * @param opts `baseFont` (native ceiling) and `minFont` (floor) */ export function computeLabelSizing( effectiveStep: number, hasDiscreteItems: boolean, + opts?: { baseFont?: number; minFont?: number }, ): LabelSizingDecision { - const defaultFontSize = 10; + const baseFont = opts?.baseFont ?? 10; + const minFont = opts?.minFont ?? 6; const defaultLimit = 100; if (!hasDiscreteItems) { - return { fontSize: defaultFontSize, labelLimit: defaultLimit }; + return { fontSize: baseFont, labelLimit: defaultLimit }; } - let fontSize = Math.max(6, Math.min(10, effectiveStep - 1)); + // Shrink lever: font tracks the band step but is bounded by [minFont, baseFont]. + let fontSize = Math.max(minFont, Math.min(baseFont, effectiveStep - 1)); let labelLimit = Math.max(30, Math.min(100, effectiveStep * 8)); let labelAngle: number | undefined; let labelAlign: string | undefined; let labelBaseline: string | undefined; if (effectiveStep < 10) { + // Narrow band → rotate vertical, shrink harder (but keep the ceiling + // one notch below base so a 12-native backend still reads ~10 here). labelAngle = -90; - fontSize = Math.max(6, Math.min(8, effectiveStep)); + fontSize = Math.max(minFont, Math.min(baseFont - 2, effectiveStep)); labelLimit = 40; labelAlign = 'right'; labelBaseline = 'middle'; } else if (effectiveStep < 16) { + // Medium band → rotate 45°, shrink slightly. labelAngle = -45; - fontSize = Math.max(7, Math.min(9, effectiveStep)); + fontSize = Math.max(minFont, Math.min(baseFont - 1, effectiveStep)); labelLimit = 60; labelAlign = 'right'; labelBaseline = 'top'; @@ -747,6 +762,49 @@ export function computeLabelSizing( return { fontSize, labelLimit, labelAngle, labelAlign, labelBaseline }; } +/** + * Canvas-adaptive font sizes for headers (axis titles, legend, chart title) and + * the base for axis tick labels. + * + * The per-backend base fonts are the preferred (native) sizes. Fonts render at + * that base and only **shrink** for genuinely small small-multiple subplots + * (so dense facets don't overflow); they are never grown above native, matching + * how the underlying renderers keep fonts constant across canvas sizes. + * + * @param minPlotDimension The smaller of the (sub)plot width/height in px + * @param opts Backend-native base font sizes + */ +export interface FontSizingDecision { + /** Ceiling for axis tick labels (feeds computeLabelSizing `baseFont`). */ + tickBase: number; + /** Header font for axis titles and chart title. */ + titleFontSize: number; + /** Legend entry font (one notch below the title). */ + legendFontSize: number; +} + +export function computeFontSizing( + minPlotDimension: number, + opts?: { baseLabelFontSize?: number; baseTitleFontSize?: number }, +): FontSizingDecision { + const baseLabel = opts?.baseLabelFontSize ?? 10; + const baseTitle = opts?.baseTitleFontSize ?? 11; + // The per-backend base fonts ARE the preferred (native) sizes: native + // renderers (Plotly/VL/ECharts) keep tick/title/legend fonts CONSTANT at + // every canvas size. So we do NOT grow above base — growth made large + // charts render heavy, oversized text. Fonts only SHRINK for genuinely + // small small-multiple subplots (minDim < 220) so dense facets don't + // overflow; otherwise they render at native base. + const minDim = minPlotDimension || 320; + const ratio = minDim >= 220 ? 1 : Math.max(0.7, minDim / 220); + const atMostNative = (base: number) => + Math.round(Math.max(base - 2, Math.min(base, base * ratio))); + const tickBase = atMostNative(baseLabel); + const titleFontSize = atMostNative(baseTitle); + const legendFontSize = Math.max(baseTitle - 2, titleFontSize - 1); + return { tickBase, titleFontSize, legendFontSize }; +} + // --------------------------------------------------------------------------- // Overflow Decision // --------------------------------------------------------------------------- diff --git a/packages/flint-js/src/core/filter-overflow.ts b/packages/flint-js/src/core/filter-overflow.ts index fee7c815..39cd07b1 100644 --- a/packages/flint-js/src/core/filter-overflow.ts +++ b/packages/flint-js/src/core/filter-overflow.ts @@ -145,7 +145,7 @@ export function filterOverflow( warnings.push({ severity: 'warning', code: 'overflow', - message: `${omittedCount} of ${uniqueValues.length} values in '${fieldName}' were omitted (showing top ${valuesToKeep.length}).`, + message: `${omittedCount} of ${uniqueValues.length} values in '${fieldName}' were omitted (showing first ${valuesToKeep.length} in sort order).`, channel, field: fieldName, }); @@ -153,7 +153,7 @@ export function filterOverflow( truncations.push({ severity: 'warning', code: 'overflow', - message: `${omittedCount} of ${uniqueValues.length} values in '${fieldName}' were omitted (showing top ${valuesToKeep.length}).`, + message: `${omittedCount} of ${uniqueValues.length} values in '${fieldName}' were omitted (showing first ${valuesToKeep.length} in sort order).`, channel, field: fieldName, keptValues: valuesToKeep, @@ -178,19 +178,16 @@ export function filterOverflow( /** * Default overflow strategy: decides which discrete values to keep. * - * - Connected marks (line/area/trail): preserve natural order (first N) * - User-specified sort: respect it - * - Auto-sort: sort by quantitative opposite axis or color, keep top N - * - Bar charts: sum-aggregate for sort (total bar height matters) + * - Canonical semantic order (months, ranks, etc.): keep the first N + * - Numeric categories: keep the first N numerically + * - Otherwise preserve data encounter order */ const defaultOverflowStrategy: OverflowStrategy = ( channel, fieldName, uniqueValues, maxToKeep, context, ) => { const { data, channelSemantics, encodings, allMarkTypes } = context; - // Connected marks need chronological/natural order preserved - const hasConnectedMark = allMarkTypes.has('line') || allMarkTypes.has('area') || allMarkTypes.has('trail'); - // Determine sort intent from user encodings const encoding = encodings[channel]; const sortBy = encoding?.sortBy; @@ -199,7 +196,7 @@ const defaultOverflowStrategy: OverflowStrategy = ( // Infer sort field and direction let sortField: string | undefined; let sortFieldType: string | undefined; - let isDescending = true; + let isDescending = false; if (sortBy) { // User explicitly specified sort @@ -221,46 +218,10 @@ const defaultOverflowStrategy: OverflowStrategy = ( } isDescending = sortOrder === 'descending'; } - } else { - // Auto-detect sort: quantitative opposite axis or quantitative color - const oppositeChannel = channel === 'x' ? 'y' : channel === 'y' ? 'x' : undefined; - - const colorCS = channelSemantics.color; - const oppositeCS = oppositeChannel ? channelSemantics[oppositeChannel] : undefined; - - // For rect marks (heatmaps), color is the primary value — don't auto-sort by it - const markType = allMarkTypes.has('rect') ? 'rect' : undefined; - if (markType !== 'rect' && colorCS?.type === 'quantitative') { - sortField = colorCS.field; - sortFieldType = colorCS.type; - } else if (oppositeCS?.type === 'quantitative') { - sortField = oppositeCS.field; - sortFieldType = oppositeCS.type; - } else { - isDescending = false; - } - } - - // For quantitative field values treated as nominal, sort numerically - const fieldOriginalType = inferVisCategory(data.map(r => r[fieldName])); - if (fieldOriginalType === 'quantitative' || channel === 'color') { - return uniqueValues.sort((a, b) => a - b) - .slice(0, maxToKeep); } - // Facet channels: first N - if (channel === 'column' || channel === 'row') { - return uniqueValues.slice(0, maxToKeep); - } - - // Connected marks: preserve natural order - if (hasConnectedMark) { - return uniqueValues.slice(0, maxToKeep); - } - - // Sort by aggregate of the quantitative sort field + // Explicit value sort takes precedence over the category field's own type. if (sortField && sortFieldType === 'quantitative') { - // Bar charts: sum aggregate (total bar height). Others: max. let aggregateOp = Math.max; let initialValue = -Infinity; if (allMarkTypes.has('bar') && sortField !== channelSemantics.color?.field) { @@ -268,10 +229,10 @@ const defaultOverflowStrategy: OverflowStrategy = ( initialValue = 0; } - const valueAggregates = new Map(); + const valueAggregates = new Map(); for (const row of data) { const fieldValue = row[fieldName]; - const sortValue = row[sortField] || 0; + const sortValue = Number(row[sortField] ?? 0); if (valueAggregates.has(fieldValue)) { valueAggregates.set(fieldValue, aggregateOp(valueAggregates.get(fieldValue)!, sortValue)); } else { @@ -286,9 +247,33 @@ const defaultOverflowStrategy: OverflowStrategy = ( .map(v => v.value); } - // Descending explicit sort: reverse then take first N + const canonicalOrder = channelSemantics[channel]?.ordinalSortOrder; + if (!sortBy && !sortOrder && canonicalOrder?.length) { + const present = new Set(uniqueValues); + const ordered = canonicalOrder.filter(value => present.has(value)); + const canonicalValues = new Set(ordered); + ordered.push(...uniqueValues.filter(value => !canonicalValues.has(value))); + return ordered.slice(0, maxToKeep); + } + + // Match the display default for quantitative values treated as discrete. + const fieldOriginalType = inferVisCategory(data.map(r => r[fieldName])); + if (fieldOriginalType === 'quantitative' || channel === 'color') { + return [...uniqueValues].sort((a, b) => Number(a) - Number(b)) + .slice(0, maxToKeep); + } + + // Facet channels: first N + if (channel === 'column' || channel === 'row') { + return uniqueValues.slice(0, maxToKeep); + } + + // Explicit field-order sort follows the displayed label order. if (sortOrder === 'descending') { - return uniqueValues.reverse().slice(0, maxToKeep); + return [...uniqueValues].sort((a, b) => String(b).localeCompare(String(a), undefined, { numeric: true })).slice(0, maxToKeep); + } + if (sortOrder === 'ascending') { + return [...uniqueValues].sort((a, b) => String(a).localeCompare(String(b), undefined, { numeric: true })).slice(0, maxToKeep); } // Default: first N values diff --git a/packages/flint-js/src/core/index.ts b/packages/flint-js/src/core/index.ts index d5ab2c01..14524256 100644 --- a/packages/flint-js/src/core/index.ts +++ b/packages/flint-js/src/core/index.ts @@ -114,6 +114,7 @@ export { computeAxisStep, computeFacetLayout, computeLabelSizing, + computeFontSizing, computeOverflow, computeGasPressure, DEFAULT_GAS_PRESSURE_PARAMS, @@ -123,6 +124,7 @@ export { type AxisStepDecision, type FacetLayoutDecision, type LabelSizingDecision, + type FontSizingDecision, type OverflowDecision, type GasPressureParams, type GasPressureDecision, diff --git a/packages/flint-js/src/core/recommendation.ts b/packages/flint-js/src/core/recommendation.ts index e5ef8890..332a0966 100644 --- a/packages/flint-js/src/core/recommendation.ts +++ b/packages/flint-js/src/core/recommendation.ts @@ -124,6 +124,13 @@ const FAMILY_DENSITY: ChannelRoleMap = { column: 'facetCol', row: 'facetRow', }; +/** 2-D density (Density Contour): both axes are measures, binned into a joint + * distribution — no series channel (colour encodes count). */ +const FAMILY_DENSITY_2D: ChannelRoleMap = { + x: 'measure', y: 'measure2', + column: 'facetCol', row: 'facetRow', +}; + /** Heatmap: x=category, y=category, color=measure */ const FAMILY_HEATMAP: ChannelRoleMap = { x: 'category', y: 'category', color: 'measure', @@ -195,6 +202,7 @@ const CHART_ROLE_MAP: Record = { // Histogram / Density 'Histogram': FAMILY_HISTOGRAM, 'Density Plot': FAMILY_DENSITY, + 'Density Contour': FAMILY_DENSITY_2D, // Geographic 'Map': FAMILY_MAP, 'Choropleth': FAMILY_CHOROPLETH, diff --git a/packages/flint-js/src/core/types.ts b/packages/flint-js/src/core/types.ts index b8f616cf..4e6db304 100644 --- a/packages/flint-js/src/core/types.ts +++ b/packages/flint-js/src/core/types.ts @@ -419,6 +419,18 @@ export interface LayoutResult { xLabel: LabelSizingDecision; yLabel: LabelSizingDecision; + /** + * Canvas-adaptive header font size (px) for axis titles and chart title. + * Derived from the backend's `baseTitleFontSize`, scaled subtly with the + * (sub)plot size. Backends should use this instead of hardcoded constants. + */ + titleFontSize: number; + /** + * Canvas-adaptive font size (px) for legend entries. Slightly smaller than + * {@link titleFontSize}. Backends should use this for legend text. + */ + legendFontSize: number; + /** Facet layout (if applicable) */ facet?: { columns: number; @@ -930,6 +942,23 @@ export interface ChartTemplateDef { /** Optional configurable properties for the chart type */ properties?: ChartPropertyDef[]; + /** + * Opt out of a backend's *generic* column/row facet-splitting pass, even + * though the template declares `x`/`y` (so the axis-less `hasAxes` gate + * alone would not exempt it). + * + * Set by templates that build their own composite, self-contained figure + * — one that already spans multiple internal axis pairs / sub-panels + * (e.g. a Sparkline table's one-row-per-series strips, a Bar Table's + * bar+%+value columns) — and so handle `column`/`row` themselves inside + * `instantiate` rather than being pre-split into N single-facet calls + * whose per-panel output a generic single-axis-pair combiner (e.g. the + * Plotly backend's `facet.ts`) cannot correctly recombine. + * + * Currently honored by the Plotly assembler only. + */ + selfManagesFacets?: boolean; + /** * Optional encoding-level quick actions (Category B). Clicking one of these * mutates the encodings map (the same state the encoding shelf edits), @@ -1148,6 +1177,15 @@ export interface AssembleOptions { * Each backend sets its own value (VL ≈ 10, ECharts ≈ 14); core uses 0. */ facetGap?: number; + /** + * Explicit number of facet COLUMNS for a column-wrapped facet, overriding + * the auto-computed wrap. When set (≥ 1) the layout uses this many columns + * (clamped to the distinct column count) and wraps the remaining panels + * into as many rows as needed. Surfaced to hosts as the `facetColumns` + * chart property so users can dial the wrap in interactively; undefined = + * auto (fill the width). + */ + facetColumns?: number; /** * Base pixels per discrete category at a 300px baseline canvas. * Scaled proportionally with canvas size by the core layout engine. @@ -1166,6 +1204,48 @@ export interface AssembleOptions { * Default: 20. */ defaultBandSize?: number; + /** + * Maximum pixels per discrete category at a 300px baseline canvas, + * scaled proportionally with canvas size (like {@link defaultBandSize}). + * + * This is the **sparse-expansion ceiling**. When few categories share a + * wide plot, each band grows to fill the available width but never past + * `maxBandSize`, so one or two bars can't balloon to the whole canvas. + * The band is thus clamped to `[minStep, maxBandSize]`: + * + * step = clamp(availableWidth / N, minStep, maxBandSize) + * + * Backends set this to match their native sparse-bar rendering: + * - VL: = defaultBandSize (VL's step-based sizing doesn't fill a container) + * - EC / CJS / Plotly: much larger (these fill their plot area natively) + * + * Defaults to {@link defaultBandSize} (no expansion beyond the base band). + */ + maxBandSize?: number; + /** + * Backend-native base font size (px) for axis **tick labels**, at a 300px + * reference canvas. The core scales it subtly with canvas size and uses it + * as the ceiling of the shrink→rotate→cap ladder, so a chart never renders + * ticks below its backend's native scale on a comfortable canvas. + * + * Learned from each renderer's defaults: + * - Vega-Lite: 10 - ECharts: 12 - Chart.js: 12 - Plotly: 12 + * + * Default: 10. + */ + baseLabelFontSize?: number; + /** + * Backend-native base font size (px) for **headers** (axis titles, legend, + * chart title), at a 300px reference canvas. Scaled subtly with canvas size + * (grows up to +4 on large canvases, shrinks toward the base in small + * multiples) so headers stay proportionate to the chart. + * + * Learned from each renderer's defaults: + * - Vega-Lite: 11 - ECharts: 12 - Chart.js: 12 - Plotly: 14 + * + * Default: 11. + */ + baseTitleFontSize?: number; /** * When true, continuous X and Y axes stretch together using the * larger of the two per-axis stretch factors. This preserves the diff --git a/packages/flint-js/src/docs/README.md b/packages/flint-js/src/docs/README.md index 3af97308..c5f00036 100644 --- a/packages/flint-js/src/docs/README.md +++ b/packages/flint-js/src/docs/README.md @@ -49,44 +49,14 @@ step differs per backend. --- -## The Problem - -### What you deal with today - -You're building an agent that needs to create charts. Maybe it's a data -analysis copilot, a dashboard generator, or an automated reporting -pipeline. At some point your agent has to produce a visualization — and -that's where the brittleness starts. - -The typical approach: your agent generates Vega-Lite (or ECharts options, -or Plotly traces) directly. You write prompt templates with examples, -add post-processing logic for edge cases, build retry loops for malformed -output. It works for your demo. Then real users arrive with real data, -and the charts break in ways you didn't anticipate. - -Here is what goes wrong: - -1. **Inconsistency across runs.** Your agent produces variable output - quality — incorrect encodings, broken layouts, poor aesthetic defaults. - You tune prompts for one chart type and break another. Even with - detailed prompts specifying exact sizing rules, formatting conventions, - and encoding guidelines, **your agent may or may not follow them** — - and the degree of compliance varies across models, prompt versions, - context length, and even individual runs. Weaker models (the ones you - want to use for cost) struggle with anything beyond basic charts; even - frontier models fail on composition, faceting, and layered designs. - Design knowledge encoded in prompts is inherently unreliable. - -2. **The quality–editability trap.** If your agent generates simple code, - users can edit it (swap a field, change chart type) — but the chart - looks mediocre. If your agent generates polished code, the chart looks - great — but every user edit breaks it, forcing another round-trip to - your agent. You can't have both, and neither option makes users happy. - -3. **Expensive and slow for what it does.** Only frontier models - *sometimes* produce correct specs for non-trivial charts, because the - parameter space (axis types, domain settings, sizing, formatting, mark - config) is large and inter-dependent. Even then, compliance with your +## Template Catalog + +Flint currently ships **149 backend template registrations** across five +backends: 35 Vega-Lite, 37 ECharts, 21 Chart.js, 38 Plotly, and 18 Excel. Chart +names overlap because the same semantic input can target multiple renderers. + +The generated references under the repository-level `docs/` directory are the +source of truth. Run `npm run gen:reference` after changing a template registry. design guidelines is probabilistic — you're paying frontier-model prices for output that still needs validation and retry. Your agent is spending its most expensive tokens on visualization plumbing instead of @@ -851,9 +821,9 @@ interface ChartTemplateDef { ### `OverflowStrategy` -Customizable per-template. The default strategy in `filter-overflow.ts` handles: -connected marks (keep all for continuity), user sorts, auto-sorts, -bar sum-aggregate, numeric sort, first-N. +Customizable per-template. The default strategy in `filter-overflow.ts` keeps +the first values in the selected display order: explicit user sort, canonical +semantic order, numeric order, then data encounter order. ```typescript type OverflowStrategy = ( @@ -917,42 +887,12 @@ visualization decisions: ## Template Catalog -### Vega-Lite (29 chart types) - -| Category | Charts | -|----------|--------| -| **Scatter & Point** | Scatter Plot, Regression, Ranged Dot Plot, Boxplot, Strip Plot | -| **Bar** | Bar Chart, Grouped Bar Chart, Stacked Bar Chart, Histogram, Heatmap, Lollipop Chart, Pyramid Chart | -| **Line & Area** | Line Chart, Bump Chart, Area Chart, Streamgraph | -| **Part-to-Whole** | Pie Chart, Rose Chart, Waterfall Chart | -| **Statistical** | Density Plot, Candlestick Chart, Radar Chart | -| **Map** | US Map, World Map | - -### ECharts (27 chart types) - -| Category | Charts | -|----------|--------| -| **Scatter & Point** | Scatter Plot, Regression, Ranged Dot Plot, Boxplot, Strip Plot | -| **Bar** | Bar Chart, Grouped Bar Chart, Stacked Bar Chart, Histogram, Heatmap, Lollipop Chart, Pyramid Chart | -| **Line & Area** | Line Chart, Bump Chart, Area Chart, Streamgraph | -| **Part-to-Whole** | Pie Chart, Funnel Chart, Treemap, Sunburst Chart | -| **Polar** | Radar Chart, Rose Chart | -| **Financial** | Candlestick Chart | -| **Indicator** | Gauge Chart | -| **Flow** | Sankey Diagram | -| **Other** | Waterfall Chart, Density Plot | - -### Chart.js (10 chart types) - -| Category | Charts | -|----------|--------| -| **Scatter & Point** | Scatter Plot | -| **Bar** | Bar Chart, Grouped Bar Chart, Stacked Bar Chart, Histogram | -| **Line & Area** | Line Chart, Area Chart | -| **Part-to-Whole** | Pie Chart | -| **Polar** | Radar Chart, Rose Chart | - -**68 template definitions** across 3 backends. +Flint currently ships **149 backend template registrations** across five +backends: 35 Vega-Lite, 37 ECharts, 21 Chart.js, 38 Plotly, and 18 Excel. Chart +names overlap because the same semantic input can target multiple renderers. + +The generated references under the repository-level `docs/` directory are the +source of truth. Run `npm run gen:reference` after changing a template registry. Each template defines: 1. **`template`** — spec skeleton (mark + encoding structure) @@ -1013,13 +953,14 @@ When discrete channels overflow the canvas budget, the library: count, placeholder string 5. Emits `ChartWarning` for the UI -The default overflow strategy priority: -1. Connected marks (line, area) → keep all (truncation breaks continuity) -2. User-specified sort → keep top/bottom N by sort order -3. Quantitative opposite axis → sort by opposite, keep top N -4. Bar with count aggregate → sum-aggregate and keep top N -5. Numeric field → numeric sort, keep first N -6. Fallback → keep first N in data order +The default overflow strategy follows the chart's display order: +1. User-specified sort → keep the first N values in that order +2. Canonical semantic order (months, ranks, quarters, etc.) → keep the first N +3. Numeric discrete field → numeric ascending, keep the first N +4. Fallback → keep the first N in data encounter order + +Overflow does not introduce a measure-based top-N ranking. Select an explicit +value sort when the largest or smallest categories should be retained. --- diff --git a/packages/flint-js/src/docs/design-stretch-model.md b/packages/flint-js/src/docs/design-stretch-model.md index 15e99e89..8ca851d1 100644 --- a/packages/flint-js/src/docs/design-stretch-model.md +++ b/packages/flint-js/src/docs/design-stretch-model.md @@ -188,12 +188,18 @@ The `detectBandedAxis` function in `templates/utils.ts` handles this decision. ## §1.1 Problem -A discrete axis displays $N$ banded items (categories, bins, groups) along a 1D segment of length $L_0$ pixels. Each item ideally occupies $\ell_0$ pixels (the natural length). When $N \cdot \ell_0 > L_0$, the items overflow. +A discrete axis displays $N$ banded items (categories, bins, groups) along a 1D +segment of length $L_0$ pixels. Each band has a **natural size** $\ell_0$ and is +kept within a **minimum** $\ell_{\min}$ and a **maximum** $\ell_{\max}$. -Two competing goals must be balanced: +The layout balances two directions: -1. **Items resist compression** — each item pushes outward to maintain $\ell_0$, and cannot shrink below $\ell_{\min}$. -2. **The axis resists expansion** — the axis can stretch beyond $L_0$ but has a hard maximum $L_{\max}$. +1. **Too sparse.** When a few items share a wide plot, each band grows to fill + the space — but never past $\ell_{\max}$, so one or two bars don't balloon to + the whole canvas. +2. **Too dense.** When many items crowd the axis, bands compress toward + $\ell_{\min}$, and the axis itself may stretch up to $L_{\max}$. Beyond that, + extra items overflow. ## §1.2 Parameters @@ -202,40 +208,70 @@ Two competing goals must be balanced: | $L_0$ | Natural axis length | `width` / `height` (canvas size) | 400 px | | $L_{\max}$ | Maximum axis length | `width × maxStretch` | 800 px | | $N$ | Number of banded items | Field cardinality | data-dependent | -| $\ell_0$ | Natural length per item | `defaultStepSize` | ~20 px | -| $\ell_{\min}$ | Minimum length per item | `minStep` option | 6 px | +| $\ell_0$ | Natural (base) size per band | `defaultBandSize` | ~20 px | +| $\ell_{\min}$ | Minimum size per band | `minStep` option | 6 px | +| $\ell_{\max}$ | Maximum size per band | `maxBandSize` option | = $\ell_0$ | | $\alpha$ | Elasticity exponent | `elasticity` option | 0.5 | | $\beta$ | Maximum stretch multiplier | `maxStretch` option | 1.5 | -> **Code defaults:** `ElasticStretchParams` in `core/decisions.ts` — `elasticity: 0.5`, `maxStretch: 1.5`, `minStep: 6`. The `defaultStepSize` is computed dynamically based on canvas size: `round(20 × max(1, sizeRatio) × defaultStepMultiplier)`. +> **Code defaults:** `ElasticStretchParams` in `core/decisions.ts` — `elasticity: 0.5`, `maxStretch: 1.5`, `minStep: 6`. $\ell_0$ (`defaultBandSize`) and $\ell_{\max}$ (`maxBandSize`) are given at a 300px reference and scaled with size: `round(bandSize × max(1, sizeRatio))`. + +### §1.2.1 Band size bounds — min, base, max + +Every banded chart resolves one number, the **band step** $\ell$: the pixels per +category slot. It is a clamp of the available width per item between the minimum +and maximum band size: + +$$\ell = \operatorname{clamp}\!\left(\frac{L}{N},\; \ell_{\min},\; \ell_{\max}\right)$$ + +- $\ell_0$ (**base**) is the natural band size *and* the density threshold. +- $\ell_{\min}$ (**min**) is the tightest a band may compress before overflow. +- $\ell_{\max}$ (**max**) is the widest a band may expand when sparse. + +The three bounds are **backend-specific**. Vega-Lite sizes a plot as `N × step`, +so its bands never grow past the base ($\ell_{\max} = \ell_0$). ECharts, Chart.js, +and Plotly fill their plot area natively, so their bands expand up to a larger +$\ell_{\max}$ before compressing. + +| Backend | Native sizing | $\ell_{\min}$ | $\ell_0$ (base) | $\ell_{\max}$ | +|---|---|---:|---:|---:| +| Vega-Lite | `width: { step }` → plot is `N × step` | 6 | 20 | 20 | +| ECharts | fills the grid (`barCategoryGap`) | 6 | 24 | 100 | +| Chart.js | fills the canvas (`categoryPercentage`) | 6 | 30 | 100 | +| Plotly | fills the plot area (`bargap`) | 6 | 20 | 100 | ## §1.3 Three Regimes -### Regime 1: No compression needed +### Regime 1: Sparse — expand to fill **Condition:** $N \cdot \ell_0 \leq L_0$ -All items fit at their natural length: +Each band grows to fill the base axis, capped at the maximum: -$$\ell = \ell_0, \quad L = N \cdot \ell_0$$ +$$\ell = \min\!\left(\ell_{\max},\; \frac{L_0}{N}\right), \quad L = N \cdot \ell$$ -### Regime 2: Overflow beyond recovery +Expansion happens *inside* the base width; the axis does not grow past $L_0$ +here. When $\ell_{\max} = \ell_0$ (Vega-Lite), bands stay at the base size. -**Condition:** $N \cdot \ell_{\min} \geq L_{\max}$ +### Regime 2: Dense — compress and stretch -Even at minimum item length and maximum stretch, not all items fit. Excess items are truncated: +**Condition:** $N \cdot \ell_0 > L_0$ and $N \cdot \ell_{\min} < L_{\max}$ -$$N' = \left\lfloor \frac{L_{\max}}{\ell_{\min}} \right\rfloor, \quad \ell = \ell_{\min}, \quad L = L_{\max}$$ +Items overflow the base axis. Bands compress and the axis stretches up to +$L_{\max}$, governed by the elastic budget in §1.4. -### Regime 3: Elastic equilibrium +### Regime 3: Overflow beyond recovery -**Condition:** $N \cdot \ell_0 > L_0$ and $N \cdot \ell_{\min} < L_{\max}$ +**Condition:** $N \cdot \ell_{\min} \geq L_{\max}$ + +Even at minimum band size and maximum stretch, not all items fit. Excess items are truncated: -Items overflow but can be accommodated by compressing items and/or stretching the axis. This is where the elastic model applies. +$$N' = \left\lfloor \frac{L_{\max}}{\ell_{\min}} \right\rfloor, \quad \ell = \ell_{\min}, \quad L = L_{\max}$$ ## §1.4 Power-Law Elastic Budget -This is the **implemented model**. The axis stretches using a power-law of the pressure ratio: +This is the **implemented model** for the dense regime. The axis budget stretches +using a power-law of the pressure ratio: **Pressure:** @@ -243,17 +279,20 @@ $$p = \frac{N \cdot \ell_0}{L_0}$$ **Stretch factor:** -$$s = \min(\beta,\; p^{\alpha})$$ +$$s = \min(\beta,\; \max(1, p)^{\alpha})$$ -**Resulting step size:** +**Axis budget and step size:** -$$\ell = \frac{L_0 \cdot s}{N} = \frac{L_0 \cdot p^{\alpha}}{N}$$ +$$L = L_0 \cdot s, \qquad \ell = \operatorname{clamp}\!\left(\frac{L}{N},\; \ell_{\min},\; \ell_{\max}\right)$$ -With $\alpha = 0.5$, doubling the overflow only increases the stretch by $\sqrt{2} \approx 1.41\times$ — a naturally progressive response. +For sparse charts $p \le 1$, so $s = 1$ and the step reduces to the Regime 1 fill, +$\min(\ell_{\max}, L_0/N)$. For dense charts $p > 1$, the budget grows and bands +compress. With $\alpha = 0.5$, doubling the overflow only increases the stretch +by $\sqrt{2} \approx 1.41\times$. -**Clamping:** The step is clamped to $[\ell_{\min},\; \ell_0]$ and the axis length to $[L_0,\; L_{\max}]$. +**Clamping:** The step is clamped to $[\ell_{\min},\; \ell_{\max}]$ and the axis length to $[L_0,\; L_{\max}]$. -> **Implementation:** `computeElasticBudget()` in `core/decisions.ts` (lines ~549–569). Called by `computeAxisStep()` which handles both nominal and continuous-as-discrete cases. +> **Implementation:** `computeElasticBudget()` in `core/decisions.ts` produces the axis budget; `computeLayout()` in `core/compute-layout.ts` clamps the step to $[\ell_{\min}, \ell_{\max}]$ using `minStep` / `defaultBandSize` / `maxBandSize`. ## §1.5 Linear Spring Model (Theoretical Foundation) diff --git a/packages/flint-js/src/echarts/assemble.ts b/packages/flint-js/src/echarts/assemble.ts index 8ab5bc75..47788b84 100644 --- a/packages/flint-js/src/echarts/assemble.ts +++ b/packages/flint-js/src/echarts/assemble.ts @@ -66,7 +66,7 @@ import { ecGetTemplateDef } from './templates'; import { resolveChannelSemantics, convertTemporalData } from '../core/resolve-semantics'; import { toTypeString, type SemanticAnnotation } from '../core/field-semantics'; import { filterOverflow } from '../core/filter-overflow'; -import { computeLayout, computeChannelBudgets, deriveStretchCaps, resolveBaseSize } from '../core/compute-layout'; +import { computeLayout, computeChannelBudgets, deriveStretchCaps, resolveBaseSize, resolveFacetColumnsOption } from '../core/compute-layout'; import { ecApplyLayoutToSpec, ecApplyTooltips } from './instantiate-spec'; import { ecCombineFacetPanels } from './facet'; import { DEFAULT_COLORS } from './templates/utils'; @@ -199,6 +199,13 @@ export function assembleECharts(input: ChartAssemblyInput): any { // but adds ~120-160px grid margins on top. A 24px base band gives // bars close to ECharts's native auto-sizing at typical category counts. defaultBandSize: 24, + // ECharts fills its grid natively (bars sized by barCategoryGap), so + // sparse categories spread out. Allow bands to expand past the base to + // match that, capped so a couple of bars don't span the whole canvas. + maxBandSize: 100, + // ECharts native font defaults (labels, titles, legend all 12). + baseLabelFontSize: 12, + baseTitleFontSize: 12, ...options, ...(declaration.paramOverrides || {}), }; @@ -218,6 +225,7 @@ export function assembleECharts(input: ChartAssemblyInput): any { // (βx, βy) so the entire layout — single plot OR facet grid — stays within // the same budget. Falls back to maxStretch when no ceiling is set. Object.assign(effectiveOptions, deriveStretchCaps(baseSize, sizeCeiling, effectiveOptions)); + effectiveOptions.facetColumns = resolveFacetColumnsOption(input.chart_spec.chartProperties); // Default true so that _encodingTooltip is applied and all charts get encoding-style tooltips const { diff --git a/packages/flint-js/src/echarts/instantiate-spec.ts b/packages/flint-js/src/echarts/instantiate-spec.ts index 582a7040..3d588e63 100644 --- a/packages/flint-js/src/echarts/instantiate-spec.ts +++ b/packages/flint-js/src/echarts/instantiate-spec.ts @@ -408,14 +408,14 @@ export function ecApplyLayoutToSpec( if (option.xAxis.name) { option.xAxis.nameLocation = option.xAxis.nameLocation || 'middle'; option.xAxis.nameGap = option.xAxis.nameGap || 25; - option.xAxis.nameTextStyle = { fontSize: 12, ...(option.xAxis.nameTextStyle || {}) }; + option.xAxis.nameTextStyle = { fontSize: layout.titleFontSize, ...(option.xAxis.nameTextStyle || {}) }; } } if (option.yAxis) { if (option.yAxis.name) { option.yAxis.nameLocation = option.yAxis.nameLocation || 'middle'; option.yAxis.nameGap = option.yAxis.nameGap || 45; - option.yAxis.nameTextStyle = { fontSize: 12, ...(option.yAxis.nameTextStyle || {}) }; + option.yAxis.nameTextStyle = { fontSize: layout.titleFontSize, ...(option.yAxis.nameTextStyle || {}) }; } } @@ -424,10 +424,10 @@ export function ecApplyLayoutToSpec( if (option.singleAxis.name) { option.singleAxis.nameLocation = option.singleAxis.nameLocation || 'middle'; option.singleAxis.nameGap = option.singleAxis.nameGap || 25; - option.singleAxis.nameTextStyle = { fontSize: 12, ...(option.singleAxis.nameTextStyle || {}) }; + option.singleAxis.nameTextStyle = { fontSize: layout.titleFontSize, ...(option.singleAxis.nameTextStyle || {}) }; } if (!option.singleAxis.axisLabel) option.singleAxis.axisLabel = {}; - option.singleAxis.axisLabel.fontSize = option.singleAxis.axisLabel.fontSize || 11; + option.singleAxis.axisLabel.fontSize = option.singleAxis.axisLabel.fontSize || layout.xLabel.fontSize; } // ── Legend positioning ──────────────────────────────────────────────── @@ -462,7 +462,7 @@ export function ecApplyLayoutToSpec( left: 'center', orient: 'horizontal', textStyle: { - fontSize: highCardinality ? 8 : 11, + fontSize: highCardinality ? 8 : layout.legendFontSize, ...(option.legend.textStyle || {}), }, ...(legendLabels.length > 10 ? { type: 'scroll' } : {}), @@ -476,7 +476,7 @@ export function ecApplyLayoutToSpec( z: 100, style: { text: legendTitle, - fontSize: 11, + fontSize: layout.legendFontSize, fontWeight: 'bold', fill: '#333', textAlign: 'center', @@ -524,7 +524,7 @@ export function ecApplyLayoutToSpec( orient: option.legend.orient || 'vertical', align: 'left', // icon on left, text on right textStyle: { - fontSize: highCardinality ? 8 : 11, + fontSize: highCardinality ? 8 : layout.legendFontSize, ...(option.legend.textStyle || {}), }, ...(legendLabels.length > 10 ? { type: 'scroll' } : {}), @@ -538,7 +538,7 @@ export function ecApplyLayoutToSpec( z: 100, style: { text: legendTitle, - fontSize: 11, + fontSize: layout.legendFontSize, fontWeight: 'bold', fill: '#333', textAlign: 'left', diff --git a/packages/flint-js/src/echarts/templates/funnel.ts b/packages/flint-js/src/echarts/templates/funnel.ts index c60c494c..27ea61e0 100644 --- a/packages/flint-js/src/echarts/templates/funnel.ts +++ b/packages/flint-js/src/echarts/templates/funnel.ts @@ -133,7 +133,7 @@ export const ecFunnelChartDef: ChartTemplateDef = { orient: 'vertical', right: 10, top: 'middle', - textStyle: { fontSize: 11 }, + textStyle: { fontSize: layout.legendFontSize }, }, series: [{ type: 'funnel', diff --git a/packages/flint-js/src/echarts/templates/parallel.ts b/packages/flint-js/src/echarts/templates/parallel.ts index 7c6f4086..9b8da7bd 100644 --- a/packages/flint-js/src/echarts/templates/parallel.ts +++ b/packages/flint-js/src/echarts/templates/parallel.ts @@ -95,7 +95,7 @@ export const ecParallelCoordinatesDef: ChartTemplateDef = { return { dim: i, name, - nameTextStyle: { fontSize: 11 }, + nameTextStyle: { fontSize: ctx.layout.titleFontSize }, nameGap: 8, axisLabel: { fontSize: 10 }, ...(bounds ? { min: bounds[0], max: bounds[1] } : {}), @@ -178,7 +178,7 @@ export const ecParallelCoordinatesDef: ChartTemplateDef = { left: 'center', orient: 'horizontal', itemWidth: 18, - textStyle: { fontSize: 11 }, + textStyle: { fontSize: ctx.layout.legendFontSize }, ...(legendData.length > 10 ? { type: 'scroll' } : {}), }; } diff --git a/packages/flint-js/src/echarts/templates/pyramid.ts b/packages/flint-js/src/echarts/templates/pyramid.ts index 80a1800e..e0e76a4b 100644 --- a/packages/flint-js/src/echarts/templates/pyramid.ts +++ b/packages/flint-js/src/echarts/templates/pyramid.ts @@ -99,7 +99,7 @@ export const ecPyramidChartDef: ChartTemplateDef = { name: catField, nameLocation: 'middle' as const, nameGap: 40, - nameTextStyle: { fontSize: 12, color: '#333' }, + nameTextStyle: { fontSize: ctx.layout.titleFontSize, color: '#333' }, boundaryGap: true, axisLine: { show: true, onZero: false, lineStyle: axisLineStyle }, axisTick: { @@ -120,7 +120,7 @@ export const ecPyramidChartDef: ChartTemplateDef = { name: valField, nameLocation: 'middle', nameGap: 28, - nameTextStyle: { fontSize: 12, color: '#333' }, + nameTextStyle: { fontSize: ctx.layout.titleFontSize, color: '#333' }, axisLine: { show: true, lineStyle: axisLineStyle }, axisTick: { show: true, length: 6, lineStyle: tickLineStyle }, axisLabel: { diff --git a/packages/flint-js/src/echarts/templates/radar.ts b/packages/flint-js/src/echarts/templates/radar.ts index 1203e113..d923378e 100644 --- a/packages/flint-js/src/echarts/templates/radar.ts +++ b/packages/flint-js/src/echarts/templates/radar.ts @@ -145,7 +145,7 @@ export const ecRadarChartDef: ChartTemplateDef = { shape: chartProperties?.shape === 'circle' ? 'circle' : 'polygon', center: ['50%', '46%'], radius: '38%', - axisName: { fontSize: 11 }, + axisName: { fontSize: ctx.layout.titleFontSize }, }, series: [{ type: 'radar', diff --git a/packages/flint-js/src/echarts/templates/rose.ts b/packages/flint-js/src/echarts/templates/rose.ts index dda87480..ee7faa4a 100644 --- a/packages/flint-js/src/echarts/templates/rose.ts +++ b/packages/flint-js/src/echarts/templates/rose.ts @@ -249,7 +249,7 @@ export const ecRoseChartDef: ChartTemplateDef = { orient: 'vertical', right: 10, top: 'middle', - textStyle: { fontSize: 11 }, + textStyle: { fontSize: ctx.layout.legendFontSize }, }; } diff --git a/packages/flint-js/src/echarts/templates/streamgraph.ts b/packages/flint-js/src/echarts/templates/streamgraph.ts index beb81b30..ef8135c7 100644 --- a/packages/flint-js/src/echarts/templates/streamgraph.ts +++ b/packages/flint-js/src/echarts/templates/streamgraph.ts @@ -148,7 +148,7 @@ export const ecStreamgraphDef: ChartTemplateDef = { name: xField, nameLocation: 'middle', nameGap: 25, - nameTextStyle: { fontSize: 12 }, + nameTextStyle: { fontSize: ctx.layout.titleFontSize }, ...(xIsTemporal ? { axisLabel: { fontSize: 11 } } : {}), }, series: [{ diff --git a/packages/flint-js/src/excel/artifact.ts b/packages/flint-js/src/excel/artifact.ts new file mode 100644 index 00000000..728cf0ed --- /dev/null +++ b/packages/flint-js/src/excel/artifact.ts @@ -0,0 +1,104 @@ +import type { ExcelNativeChartSpec } from './types'; + +export const EXCEL_ARTIFACT_SCHEMA = 'flint.excel.chart/v1' as const; + +export const SUPPORTED_EXCEL_CHART_TYPES = [ + 'Area', + 'AreaStacked', + 'BarClustered', + 'BarStacked', + 'BoxWhisker', + 'Bubble', + 'ColumnClustered', + 'ColumnStacked', + 'Doughnut', + 'Funnel', + 'Line', + 'Pie', + 'RadarMarkers', + 'StockOHLC', + 'Sunburst', + 'Treemap', + 'Waterfall', + 'XYScatter', + 'XYScatterLines', +] as const; + +const supportedChartTypes = new Set(SUPPORTED_EXCEL_CHART_TYPES); + +export interface PreparedExcelArtifact { + spec: ExcelNativeChartSpec; + data: Array>; + rows: number; + columns: number; + rangeA1: string; + chartType: string; + numericAxis: boolean; + dateAxis: boolean; + hasAxes: boolean; + isBar: boolean; + isLine: boolean; + seriesCount: number; +} + +export function excelColumnLetter(index: number): string { + if (!Number.isInteger(index) || index < 0) { + throw new Error('Column index must be a non-negative integer.'); + } + let result = ''; + let remaining = index + 1; + while (remaining > 0) { + const digit = (remaining - 1) % 26; + result = String.fromCharCode(65 + digit) + result; + remaining = Math.floor((remaining - 1) / 26); + } + return result; +} + +export function prepareExcelArtifact(value: unknown): PreparedExcelArtifact { + if (!value || typeof value !== 'object') { + throw new Error('Excel artifact must be an object.'); + } + const spec = value as Partial; + if (spec.schema !== EXCEL_ARTIFACT_SCHEMA || spec.kind !== 'chart') { + throw new Error(`Expected a ${EXCEL_ARTIFACT_SCHEMA} chart artifact.`); + } + const chartType = spec.chartType; + if (typeof chartType !== 'string' || !supportedChartTypes.has(chartType)) { + throw new Error(`Unsupported Excel chart type: ${String(spec.chartType)}.`); + } + if (spec.seriesBy !== 'Columns' && spec.seriesBy !== 'Rows') { + throw new Error('Excel artifact seriesBy must be Columns or Rows.'); + } + if (!Array.isArray(spec.data) || spec.data.length < 2 || spec.data.some((row) => !Array.isArray(row))) { + throw new Error('Excel artifact data must contain a header and at least one data row.'); + } + const columns = Math.max(...spec.data.map((row) => row.length)); + if (columns < 2) { + throw new Error('Excel artifact data must contain at least two columns.'); + } + const rows = spec.data.length; + const data = spec.data.map((row) => { + const padded = row.slice(); + while (padded.length < columns) padded.push(null); + return padded; + }); + const seriesCount = /Treemap|Sunburst/i.test(chartType) + ? 1 + : spec.series?.length ?? (spec.seriesBy === 'Rows' ? rows - 1 : columns - 1); + + return { + spec: spec as ExcelNativeChartSpec, + data, + rows, + columns, + rangeA1: `A1:${excelColumnLetter(columns - 1)}${rows}`, + chartType, + numericAxis: /XYScatter|Bubble/i.test(chartType), + dateAxis: /Stock/i.test(chartType), + hasAxes: !/Pie|Doughnut|Treemap|Sunburst|Funnel/i.test(chartType), + isBar: /Bar|Column/i.test(chartType), + isLine: /Line/i.test(chartType), + seriesCount, + }; +} diff --git a/packages/flint-js/src/excel/assemble.ts b/packages/flint-js/src/excel/assemble.ts new file mode 100644 index 00000000..de1b538d --- /dev/null +++ b/packages/flint-js/src/excel/assemble.ts @@ -0,0 +1,576 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Excel chart assembly — Stage-3 code generator for Office.js Excel charts. + * + * Reuses the SAME core analysis pipeline as the other backends: + * Phase 0: convertTemporalData + resolveChannelSemantics → ChannelSemantics + * (this decides each channel's role: quantitative = MEASURE, + * nominal/ordinal/temporal = CATEGORY — no heuristics) + * Stage 3: pivot the long/tidy rows into Excel's WIDE matrix and emit an + * ExcelChartSpec (native Office.js chart description). + * + * Excel charts consume a rectangular range (`charts.add(type, range, seriesBy)`), + * so the long/tidy data is pivoted: category field → first column, series field + * → series columns, measure → cells. Visual STYLE stays native to Excel (its + * own palette/gridlines); only Flint's LAYOUT decisions (which field is the + * category, number format, legend, orientation) are carried over. + */ + +import type { + ChartAssemblyInput, + ChartEncoding, + ChartWarning, + LayoutDeclaration, + SemanticResult, +} from '../core/types'; +import { resolveChannelSemantics, convertTemporalData } from '../core/resolve-semantics'; +import { detectBandedAxisFromSemantics } from '../core/axis-detection'; +import { computeChannelBudgets, deriveStretchCaps, resolveBaseSize } from '../core/compute-layout'; +import { filterOverflow } from '../core/filter-overflow'; +import { formatSpecToExcel } from './chart-types'; +import { excelGetTemplateDef } from './templates'; +import type { + ExcelAxisSpec, + ExcelChartSpec, + ExcelNativeChartSpec, + ExcelNativeSeriesSpec, + ExcelSeriesBy, +} from './types'; + +type Cell = string | number | null; + +const EXCEL_SERIES_COLORS = ['#4472C4', '#ED7D31', '#70AD47', '#FFC000', '#5B9BD5', '#A5A5A5']; + +function niceStep(span: number, targetTicks = 5): number { + if (!(span > 0)) return 1; + const rough = span / targetTicks; + const power = 10 ** Math.floor(Math.log10(rough)); + const fraction = rough / power; + const niceFraction = fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 5 ? 5 : 10; + return niceFraction * power; +} + +function focusedNumericAxis(values: number[]): Partial> { + const finite = values.filter(Number.isFinite); + if (finite.length === 0) return {}; + const dataMinimum = Math.min(...finite); + const dataMaximum = Math.max(...finite); + const dataSpan = dataMaximum - dataMinimum; + const referenceSpan = dataSpan > 0 ? dataSpan : Math.max(1, Math.abs(dataMaximum) * 0.1); + const majorUnit = niceStep(referenceSpan); + const precision = 10 ** Math.max(0, -Math.floor(Math.log10(majorUnit)) + 1); + const round = (value: number) => Math.round(value * precision) / precision; + if (dataSpan === 0) { + return { + minimumScale: round(dataMinimum - majorUnit), + maximumScale: round(dataMaximum + majorUnit), + majorUnit, + }; + } + const onMajorTick = (value: number) => Math.abs(value / majorUnit - Math.round(value / majorUnit)) < 1e-9; + const minimumScale = dataMinimum >= 0 && dataMinimum <= referenceSpan * 0.1 + ? 0 + : round(Math.floor(dataMinimum / majorUnit) * majorUnit); + const nextMajorTick = Math.ceil(dataMaximum / majorUnit) * majorUnit; + const maximumScale = onMajorTick(dataMaximum) + ? dataMaximum + majorUnit * 0.25 + : nextMajorTick; + return { + minimumScale, + maximumScale: round(maximumScale), + majorUnit, + }; +} + +function temporalLabelSpacing(categoryCount: number, width: number): number | undefined { + const labelBudget = Math.max(12, Math.floor((width - 90) / 14)); + return categoryCount > labelBudget ? Math.ceil(categoryCount / labelBudget) : undefined; +} + +/** Normalize shorthand (`"x": "field"`) to `{ field }`. */ +function normalizeEncodings( + raw: Record, +): Record { + const out: Record = {}; + for (const [ch, v] of Object.entries(raw ?? {})) { + if (v == null) continue; + out[ch] = typeof v === 'string' ? { field: v } : (v as ChartEncoding); + } + return out; +} + +/** Distinct values of a field, first-seen order. */ +function distinct(rows: any[], field: string): Cell[] { + const seen = new Set(); + const out: Cell[] = []; + for (const r of rows) { + const v = r[field]; + if (!seen.has(v)) { seen.add(v); out.push(v as Cell); } + } + return out; +} + +function interpolateMissing(values: Cell[]): Cell[] { + const output = [...values]; + for (let index = 0; index < output.length; index += 1) { + if (output[index] != null) continue; + let previous = index - 1; + let next = index + 1; + while (previous >= 0 && output[previous] == null) previous -= 1; + while (next < output.length && output[next] == null) next += 1; + if (previous < 0 || next >= output.length) continue; + const start = Number(output[previous]); + const end = Number(output[next]); + if (!Number.isFinite(start) || !Number.isFinite(end)) continue; + output[index] = start + ((end - start) * (index - previous)) / (next - previous); + } + return output; +} + +function normalizedBubbleSizes( + rows: any[], + field: string, + type: string | undefined, + width: number, + height: number, +): Map { + const values = rows.map((row) => row[field]).filter((value) => value != null); + const unique = [...new Set(values)]; + const maximumArea = Math.round(Math.max(16, Math.min(361, (width * height / Math.max(1, rows.length)) * 0.6))); + const minimumArea = type === 'quantitative' || type === 'temporal' + ? 9 + : Math.round(maximumArea / 4); + const output = new Map(); + if (type !== 'quantitative' && type !== 'temporal') { + unique.forEach((value, index) => { + const t = unique.length > 1 ? index / (unique.length - 1) : 0.5; + output.set(value, minimumArea + t * (maximumArea - minimumArea)); + }); + return output; + } + + const numeric = values.map(Number).filter(Number.isFinite); + const maximum = numeric.length > 0 ? Math.max(...numeric) : 1; + const sqrtMaximum = Math.sqrt(Math.max(0, maximum)); + unique.forEach((value) => { + const numericValue = Number(value); + const t = sqrtMaximum > 0 && Number.isFinite(numericValue) + ? Math.sqrt(Math.max(0, numericValue)) / sqrtMaximum + : 0; + output.set(value, minimumArea + t * (maximumArea - minimumArea)); + }); + return output; +} + +function interpolateColor(start: string, end: string, t: number): string { + const channel = (color: string, offset: number) => Number.parseInt(color.slice(offset, offset + 2), 16); + const hex = (value: number) => Math.round(value).toString(16).padStart(2, '0'); + return `#${hex(channel(start, 1) + (channel(end, 1) - channel(start, 1)) * t)}${hex(channel(start, 3) + (channel(end, 3) - channel(start, 3)) * t)}${hex(channel(start, 5) + (channel(end, 5) - channel(start, 5)) * t)}`; +} + +/** + * Assemble an {@link ExcelChartSpec} from a {@link ChartAssemblyInput}. + * + * @throws if the chart type has no native Excel equivalent (e.g. Heatmap). + */ +export function assembleExcel(input: ChartAssemblyInput): ExcelChartSpec { + const flintType = input.chart_spec.chartType; + const semanticTypes = input.semantic_types ?? {}; + const rawData: any[] = input.data.values ?? []; + const encodings = normalizeEncodings(input.chart_spec.encodings); + + // ── Phase 0 (reused core): resolve per-channel semantics ──────────────── + let convertedData = convertTemporalData(rawData, semanticTypes); + const sem: SemanticResult = resolveChannelSemantics( + encodings, rawData, semanticTypes, convertedData, + ); + const typeOf = (ch: string) => sem[ch]?.type; + const isMeasure = (ch: string) => typeOf(ch) === 'quantitative'; + const fieldOf = (ch: string) => encodings[ch]?.field; + const overflowOrder = new Map(); + const chartTemplate = excelGetTemplateDef(flintType); + if (!chartTemplate) { + throw new Error(`Excel backend does not support chart type "${flintType}" as a native Office.js chart.`); + } + if (fieldOf('column') || fieldOf('row')) { + throw new Error(`Excel backend does not support faceting in one native Excel chart: "${flintType}".`); + } + const templateContext = { input, table: convertedData, semantics: sem, fieldOf, typeOf }; + const unsupportedReason = chartTemplate.validate?.(templateContext); + if (unsupportedReason) { + throw new Error(`Excel backend ${unsupportedReason}: "${flintType}".`); + } + + if (chartTemplate.instantiate) { + return chartTemplate.instantiate(templateContext); + } + + if (flintType === 'Bar Chart' || flintType === 'Grouped Bar Chart' || flintType === 'Stacked Bar Chart') { + const detected = detectBandedAxisFromSemantics(sem, convertedData, { preferAxis: 'x' }); + const declaration: LayoutDeclaration = { + axisFlags: detected ? { [detected.axis]: { banded: true } } : { x: { banded: true } }, + resolvedTypes: detected?.resolvedTypes, + }; + const baseSize = resolveBaseSize(input.chart_spec.baseSize, input.chart_spec.canvasSize); + const options = { + facetFixedPadding: { width: 50, height: 40 }, + facetGap: 10, + targetBandAR: 10, + ...deriveStretchCaps(baseSize, input.chart_spec.canvasSize, {}), + }; + const budgets = computeChannelBudgets(sem, declaration, convertedData, baseSize, options); + const overflowResult = filterOverflow( + sem, + declaration, + encodings, + convertedData, + budgets, + new Set(['bar']), + ); + convertedData = overflowResult.filteredData; + overflowResult.truncations.forEach((truncation) => { + overflowOrder.set(truncation.field, truncation.keptValues as Cell[]); + }); + } + + const mapping = chartTemplate.typeMapping; + + // ── Resolve roles (category / measure / series) from semantics ────────── + let catCh: string | undefined; + let measCh: string | undefined; + let seriesCh: string | undefined; + let orientation: 'vertical' | 'horizontal' = 'vertical'; + let isXY = false; + + // categorical series candidate (group preferred, else categorical color) + const seriesCand = encodings.group + ? 'group' + : encodings.color && !isMeasure('color') + ? 'color' + : undefined; + const seriesField0 = seriesCand; + + if (mapping.noAxes) { + // pie/doughnut: color = slices (category), size/theta/y = value + catCh = encodings.color ? 'color' : encodings.x ? 'x' : undefined; + measCh = encodings.size ? 'size' : encodings.theta ? 'theta' : encodings.y ? 'y' : undefined; + seriesCh = undefined; + } else if (mapping.xy) { + catCh = 'x'; measCh = 'y'; isXY = true; seriesCh = seriesField0; + } else if (isMeasure('x') && !isMeasure('y')) { + catCh = 'y'; measCh = 'x'; orientation = 'horizontal'; seriesCh = seriesField0; + } else { + catCh = 'x'; measCh = 'y'; seriesCh = seriesField0; + } + + const catField = catCh ? fieldOf(catCh) : undefined; + const measField = measCh ? fieldOf(measCh) : undefined; + const seriesField = seriesCh ? fieldOf(seriesCh) : undefined; + const dashField = fieldOf('strokeDash'); + const orderField = fieldOf('order'); + const sizeField = fieldOf('size'); + const base = input.chart_spec.baseSize ?? { width: 480, height: 320 }; + const bubbleSizes = sizeField + ? normalizedBubbleSizes(convertedData, sizeField, typeOf('size'), base.width, base.height) + : undefined; + const warnings: ChartWarning[] = []; + + if (!catField || !measField) { + throw new Error( + `Excel backend could not resolve category/measure for "${flintType}" ` + + `(category=${catField}, measure=${measField}).`, + ); + } + + const numericXLine = flintType === 'Line Chart' && isMeasure('x') && isMeasure('y'); + if (numericXLine) { + isXY = true; + catCh = 'x'; + measCh = 'y'; + } + + // ── Stage 3: pivot long → wide matrix ─────────────────────────────────── + const data: Array> = []; + let explicitSeries: ExcelNativeSeriesSpec[] | undefined; + let seriesFormats: ExcelNativeChartSpec['seriesFormats']; + if (isXY) { + const seriesKeys = seriesField ? distinct(convertedData, seriesField) : [measField]; + const needsExplicitSeries = Boolean(seriesField || sizeField); + if (needsExplicitSeries) { + const columnsPerSeries = sizeField ? 3 : 2; + const groupedRows = seriesKeys.map((seriesKey) => { + const rows = convertedData.filter((row) => !seriesField || row[seriesField] === seriesKey); + if (!orderField) return rows; + return [...rows].sort((left, right) => { + const leftValue = left[orderField]; + const rightValue = right[orderField]; + const leftNumber = Number(leftValue); + const rightNumber = Number(rightValue); + if (Number.isFinite(leftNumber) && Number.isFinite(rightNumber)) return leftNumber - rightNumber; + const leftTime = new Date(String(leftValue)).getTime(); + const rightTime = new Date(String(rightValue)).getTime(); + if (Number.isFinite(leftTime) && Number.isFinite(rightTime)) return leftTime - rightTime; + return String(leftValue).localeCompare(String(rightValue), undefined, { numeric: true }); + }); + }); + const rowCount = Math.max(0, ...groupedRows.map((rows) => rows.length)); + explicitSeries = seriesKeys.map((seriesKey, index) => ({ + name: String(seriesKey), + xColumn: index * columnsPerSeries, + yColumn: index * columnsPerSeries + 1, + rowCount: groupedRows[index].length, + bubbleSizeColumn: sizeField ? index * columnsPerSeries + 2 : undefined, + })); + data.push(seriesKeys.flatMap((seriesKey) => [ + `${String(seriesKey)} ${catField}`, + `${String(seriesKey)} ${measField}`, + ...(sizeField ? [`${String(seriesKey)} ${sizeField}`] : []), + ])); + for (let rowIndex = 0; rowIndex < rowCount; rowIndex += 1) { + data.push(groupedRows.flatMap((rows) => { + const row = rows[rowIndex]; + if (!row) return new Array(columnsPerSeries).fill(null); + return [ + row[catField] as Cell, + Number(row[measField]), + ...(sizeField ? [bubbleSizes?.get(row[sizeField]) ?? 9] : []), + ]; + })); + } + } else { + data.push([catField, measField]); + const rows = orderField + ? [...convertedData].sort((left, right) => { + const leftValue = left[orderField]; + const rightValue = right[orderField]; + const leftNumber = Number(leftValue); + const rightNumber = Number(rightValue); + if (Number.isFinite(leftNumber) && Number.isFinite(rightNumber)) return leftNumber - rightNumber; + const leftTime = new Date(String(leftValue)).getTime(); + const rightTime = new Date(String(rightValue)).getTime(); + if (Number.isFinite(leftTime) && Number.isFinite(rightTime)) return leftTime - rightTime; + return String(leftValue).localeCompare(String(rightValue), undefined, { numeric: true }); + }) + : convertedData; + for (const r of rows) { + const x = r[catField]; + const y = r[measField]; + if (x == null || y == null) continue; + data.push([x as Cell, Number(y)]); + } + } + } else { + let categories = distinct(convertedData, catField); + const rankedCategories = overflowOrder.get(catField); + if (rankedCategories) categories = rankedCategories; + if (flintType === 'Line Chart' || flintType === 'Area Chart') { + if (typeOf(catCh!) === 'temporal') { + categories = [...categories].sort((a, b) => new Date(String(a)).getTime() - new Date(String(b)).getTime()); + } else if (typeOf(catCh!) === 'quantitative') { + categories = [...categories].sort((a, b) => Number(a) - Number(b)); + } + } + let seriesKeys = seriesField ? distinct(convertedData, seriesField) : [measField]; + if (seriesField && (flintType === 'Stacked Bar Chart' || flintType === 'Bar Chart')) { + seriesKeys = [...seriesKeys].sort((a, b) => String(a).localeCompare(String(b), undefined, { numeric: true })); + if (orientation === 'vertical') seriesKeys.reverse(); + } + const dashValues = dashField ? distinct(convertedData, dashField) : []; + const seriesDescriptors = dashField + ? convertedData.reduce>((output, row) => { + const seriesValue = (seriesField ? row[seriesField] : measField) as Cell; + const dashValue = row[dashField] as Cell; + const key = `${String(seriesValue)}\u0001${String(dashValue)}`; + if (!output.some((descriptor) => descriptor.key === key)) { + output.push({ + key, + label: seriesField ? `${String(seriesValue)} — ${String(dashValue)}` : String(dashValue), + seriesValue, + dashValue, + }); + } + return output; + }, []) + : seriesKeys.map((seriesValue) => ({ + key: String(seriesValue), + label: String(seriesValue), + seriesValue, + dashValue: null, + })); + const orderedSeries = Boolean(seriesField) + && typeOf(seriesCh!) === 'ordinal'; + const numericSeriesValues = orderedSeries + ? seriesKeys.map(Number).filter(Number.isFinite) + : []; + const seriesMinimum = numericSeriesValues.length > 0 ? Math.min(...numericSeriesValues) : 0; + const seriesMaximum = numericSeriesValues.length > 0 ? Math.max(...numericSeriesValues) : 1; + const orderedSeriesColor = (value: Cell) => { + const numericValue = Number(value); + const t = Number.isFinite(numericValue) && seriesMaximum !== seriesMinimum + ? (numericValue - seriesMinimum) / (seriesMaximum - seriesMinimum) + : 0.5; + return interpolateColor('#D9E2F3', '#2F5597', t); + }; + if (orderedSeries) { + seriesFormats = seriesDescriptors.map((descriptor) => ({ + color: orderedSeriesColor(descriptor.seriesValue), + })); + } + if (dashField) { + seriesFormats = seriesDescriptors.map((descriptor) => ({ + color: EXCEL_SERIES_COLORS[Math.max(0, seriesKeys.indexOf(descriptor.seriesValue)) % EXCEL_SERIES_COLORS.length], + lineStyle: dashValues.indexOf(descriptor.dashValue) === 0 ? 'Continuous' : 'Dash', + })); + } + + // aggregate duplicates per (category × series) using the measure's default + const agg = sem[measCh!]?.aggregationDefault ?? 'sum'; + const acc = new Map(); + for (const r of convertedData) { + const cv = r[catField]; + if (cv == null) continue; + const seriesValue = seriesField ? r[seriesField] : measField; + const sv = dashField + ? `${String(seriesValue)}\u0001${String(r[dashField])}` + : seriesValue; + const num = Number(r[measField]); + if (!Number.isFinite(num)) continue; + const key = `${String(cv)}\u0000${String(sv)}`; + const e = acc.get(key) ?? { sum: 0, count: 0 }; + e.sum += num; e.count += 1; acc.set(key, e); + } + const valueAt = (cv: Cell, sv: Cell): Cell => { + const e = acc.get(`${String(cv)}\u0000${String(sv)}`); + if (!e) return null; + return agg === 'average' ? e.sum / e.count : e.sum; + }; + + let seriesValues = seriesDescriptors.map((descriptor) => categories.map((category) => valueAt(category, descriptor.key))); + if (flintType === 'Line Chart' || flintType === 'Area Chart') { + seriesValues = seriesValues.map(interpolateMissing); + } + if (flintType === 'Area Chart' && typeOf(catCh!) === 'quantitative' && categories.length > 1) { + const sourceX = categories.map(Number); + const sampleCount = Math.min(97, Math.max(49, categories.length)); + const minimum = sourceX[0]; + const maximum = sourceX[sourceX.length - 1]; + const targetX = Array.from( + { length: sampleCount }, + (_value, index) => minimum + (index / (sampleCount - 1)) * (maximum - minimum), + ); + seriesValues = seriesValues.map((values) => { + let right = 1; + return targetX.map((x) => { + while (right < sourceX.length - 1 && sourceX[right] < x) right += 1; + const left = Math.max(0, right - 1); + const span = sourceX[right] - sourceX[left]; + const t = span === 0 ? 0 : (x - sourceX[left]) / span; + const leftValue = Number(values[left]); + const rightValue = Number(values[right]); + if (!Number.isFinite(leftValue)) return Number.isFinite(rightValue) ? rightValue : null; + if (!Number.isFinite(rightValue)) return leftValue; + return leftValue + (rightValue - leftValue) * t; + }); + }); + const tickLabels = new Map(Array.from( + { length: 5 }, + (_value, index) => [ + Math.round((index / 4) * (sampleCount - 1)), + Number((minimum + (index / 4) * (maximum - minimum)).toPrecision(4)), + ] as const, + )); + categories = targetX.map((_value, index) => tickLabels.get(index) ?? ''); + } + data.push([catField, ...seriesDescriptors.map((descriptor) => descriptor.label)]); + for (let categoryIndex = 0; categoryIndex < categories.length; categoryIndex += 1) { + data.push([ + String(categories[categoryIndex]), + ...seriesValues.map((values) => values[categoryIndex]), + ]); + } + } + + // ── Chart type + styling (native Excel) ───────────────────────────────── + let excelChartType = orientation === 'horizontal' && mapping.horizontal + ? mapping.horizontal + : mapping.vertical; + if (numericXLine) excelChartType = 'XYScatterLines'; + if (flintType === 'Connected Scatter Plot') excelChartType = 'XYScatterLines'; + if (flintType === 'Scatter Plot' && sizeField) excelChartType = 'Bubble'; + if (flintType === 'Area Chart' && seriesField) excelChartType = 'AreaStacked'; + if (flintType === 'Bar Chart' && seriesField) { + excelChartType = orientation === 'horizontal' ? 'BarStacked' : 'ColumnStacked'; + } + const isBarFamily = /Column|Bar/.test(excelChartType); + const hasNumericAxes = /XYScatter|Bubble/.test(excelChartType); + const numberFormat = formatSpecToExcel(measCh ? sem[measCh]?.format : undefined); + const seriesBy: ExcelSeriesBy = 'Columns'; + + const spec: ExcelNativeChartSpec = { + schema: 'flint.excel.chart/v1', + kind: 'chart', + chartType: excelChartType, + title: `${measField} by ${catField}`, + seriesBy, + series: explicitSeries, + seriesFormats, + bubbleScale: flintType === 'Scatter Plot' && sizeField ? 20 : undefined, + doughnutHoleSize: flintType === 'Donut Chart' + ? Math.max(10, Math.min(90, Number(input.chart_spec.chartProperties?.innerRadius ?? 50))) + : undefined, + data, + width: base.width, + height: base.height, + warnings, + _flint: { flintType, catField, measField, seriesField, orientation, isXY }, + }; + + if (!mapping.noAxes) { + const measureValues = convertedData + .map((row) => Number(row[measField])) + .filter(Number.isFinite); + const measureMinimum = measureValues.length > 0 ? Math.min(...measureValues) : undefined; + const measureMaximum = measureValues.length > 0 ? Math.max(...measureValues) : undefined; + const focusedLineMinimum = flintType === 'Line Chart' && measureMinimum !== undefined && measureMaximum !== undefined + ? Math.max(0, measureMinimum - (measureMaximum - measureMinimum) * 0.05) + : undefined; + const numericXScale = hasNumericAxes + ? focusedNumericAxis(convertedData.map((row) => Number(row[catField]))) + : {}; + const numericYScale = hasNumericAxes + ? focusedNumericAxis(measureValues) + : {}; + spec.categoryAxis = { + title: catField, + labelFontSize: orientation === 'horizontal' && data.length > 25 + ? Math.max(5, Math.min(10, ((base.height - 80) / (data.length - 1)) * 0.72)) + : undefined, + tickLabelSpacing: orientation === 'vertical' && typeOf(catCh!) === 'temporal' + ? temporalLabelSpacing(data.length - 1, base.width) + : undefined, + reversePlotOrder: orientation === 'horizontal' && typeOf(catCh!) !== 'temporal', + ...numericXScale, + }; + spec.valueAxis = { + title: measField, + numberFormat, + minimumScale: flintType === 'Area Chart' ? 0 : focusedLineMinimum, + ...numericYScale, + }; + } + spec.legend = mapping.noAxes + ? { visible: true, position: 'Right' } + : seriesField || dashField + ? { visible: true, position: 'Bottom' } + : { visible: false }; + if (isBarFamily) spec.gapWidth = 60; + if (flintType === 'Grouped Bar Chart') { + const seriesCount = Math.max(1, data[0].length - 1); + spec.gapWidth = Math.min(500, (excelChartType.startsWith('Column') ? 60 : 40) * seriesCount); + spec.overlap = 0; + } + + return spec; +} diff --git a/packages/flint-js/src/excel/chart-types.ts b/packages/flint-js/src/excel/chart-types.ts new file mode 100644 index 00000000..bdb6063c --- /dev/null +++ b/packages/flint-js/src/excel/chart-types.ts @@ -0,0 +1,95 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Excel chart-type mapping + FormatSpec → Excel number format. + * + * Excel's native chart types are a fixed enum (`Excel.ChartType`), so a Flint + * chart type maps to the closest native Excel chart. Orientation (vertical vs + * horizontal) is decided by the assembler from channel semantics and selects + * the Column* vs Bar* family. + */ + +import type { FormatSpec } from '../core/field-semantics'; + +/** Which native Excel family a Flint chart maps to. */ +export interface ExcelTypeMapping { + /** Vertical (category on x) Excel.ChartType. */ + vertical: string; + /** Horizontal (category on y) Excel.ChartType, when the family supports it. */ + horizontal?: string; + /** True for pie/doughnut/… charts that have no value/category axes. */ + noAxes?: boolean; + /** True for XY (both-measure) charts. */ + xy?: boolean; +} + +/** Flint chart type (display name) → Excel chart family. */ +export const EXCEL_TYPE_MAP: Record = { + 'Bar Chart': { vertical: 'ColumnClustered', horizontal: 'BarClustered' }, + 'Grouped Bar Chart': { vertical: 'ColumnClustered', horizontal: 'BarClustered' }, + 'Stacked Bar Chart': { vertical: 'ColumnStacked', horizontal: 'BarStacked' }, + 'Pyramid Chart': { vertical: 'BarStacked', horizontal: 'BarStacked' }, + 'Histogram': { vertical: 'ColumnClustered' }, + 'Line Chart': { vertical: 'Line' }, + 'Area Chart': { vertical: 'Area', horizontal: undefined }, + 'Scatter Plot': { vertical: 'XYScatter', xy: true }, + 'Connected Scatter Plot': { vertical: 'XYScatterLines', xy: true }, + 'Pie Chart': { vertical: 'Pie', noAxes: true }, + 'Donut Chart': { vertical: 'Doughnut', noAxes: true }, + 'Boxplot': { vertical: 'BoxWhisker' }, + 'Candlestick Chart': { vertical: 'StockOHLC' }, + 'Waterfall Chart': { vertical: 'Waterfall' }, + 'Radar Chart': { vertical: 'RadarMarkers' }, + 'Funnel Chart': { vertical: 'Funnel', noAxes: true }, + 'Treemap': { vertical: 'Treemap', noAxes: true }, + 'Sunburst Chart': { vertical: 'Sunburst', noAxes: true }, +}; + +/** Chart types this backend can render natively in Excel. */ +export function isExcelSupported(flintChartType: string): boolean { + return flintChartType in EXCEL_TYPE_MAP; +} + +/** + * Map a Flint {@link FormatSpec} to an Excel number-format string. + * + * Excel formats are pattern strings (`"$#,##0"`, `"0.0%"`, `"#,##0"`), distinct + * from d3/Vega patterns, so we translate from the FormatSpec's intent (prefix, + * suffix, abbreviate) rather than its d3 `pattern`. + */ +export function formatSpecToExcel(fmt: FormatSpec | undefined): string | undefined { + if (!fmt) return undefined; + const prefix = fmt.prefix ?? ''; + const suffix = fmt.suffix ?? ''; + const pat = fmt.pattern ?? ''; + + // percent + if (suffix === '%' || pat.includes('%')) { + const decimals = decimalsFromPattern(pat); + return decimals > 0 ? `0.${'0'.repeat(decimals)}%` : '0%'; + } + + // decide the numeric core + const decimals = decimalsFromPattern(pat); + let core = decimals > 0 ? `#,##0.${'0'.repeat(decimals)}` : '#,##0'; + if (fmt.abbreviate) core = '#,##0,"K"'; // thousands abbreviation (approx) + + const pre = prefix ? escapeLiteral(prefix) : ''; + const suf = suffix ? escapeLiteral(suffix) : ''; + if (!pre && !suf && !fmt.abbreviate && decimals === 0) return 'General'; + return `${pre}${core}${suf}`; +} + +/** Number of fractional digits requested by a d3-ish pattern (best-effort). */ +function decimalsFromPattern(pat: string): number { + const m = pat.match(/\.(\d+)/); + return m ? Number(m[1]) : 0; +} + +/** Wrap non-numeric literal text so Excel treats it literally in a format. */ +function escapeLiteral(s: string): string { + // A leading/trailing currency symbol is fine bare; wrap other text in quotes. + if (s === '$' || s === '€' || s === '£' || s === '¥') return s; + return `"${s}"`; +} diff --git a/packages/flint-js/src/excel/codegen.ts b/packages/flint-js/src/excel/codegen.ts new file mode 100644 index 00000000..099f549c --- /dev/null +++ b/packages/flint-js/src/excel/codegen.ts @@ -0,0 +1,157 @@ +import { prepareExcelArtifact } from './artifact'; +import type { ExcelAxisSpec, ExcelNativeChartSpec } from './types'; + +export interface OfficeJsCodegenOptions { + scale?: number; + cleanWorksheet?: boolean; + functionName?: string; +} + +export interface GeneratedOfficeJs { + code: string; + meta: { + schema: ExcelNativeChartSpec['schema']; + rangeA1: string; + chartType: string; + rows: number; + columns: number; + }; +} + +function axisCode(axisName: 'categoryAxis' | 'valueAxis', axis: ExcelAxisSpec): string[] { + const target = `chart.axes.${axisName}`; + const lines: string[] = []; + if (axis.title) { + lines.push(` ${target}.title.text = ${JSON.stringify(axis.title)};`); + lines.push(` ${target}.title.visible = true;`); + } + if (axis.numberFormat) lines.push(` ${target}.numberFormat = ${JSON.stringify(axis.numberFormat)};`); + if (axis.labelFontSize !== undefined) lines.push(` ${target}.format.font.size = ${axis.labelFontSize};`); + if (axis.tickLabelSpacing !== undefined) lines.push(` ${target}.tickLabelSpacing = ${axis.tickLabelSpacing};`); + if (axis.reversePlotOrder !== undefined) lines.push(` ${target}.reversePlotOrder = ${axis.reversePlotOrder};`); + if (axis.minimumScale !== undefined) lines.push(` ${target}.minimum = ${axis.minimumScale};`); + if (axis.maximumScale !== undefined) lines.push(` ${target}.maximum = ${axis.maximumScale};`); + if (axis.majorUnit !== undefined) lines.push(` ${target}.majorUnit = ${axis.majorUnit};`); + return lines; +} + +function positiveScale(value: number | undefined): number { + const scale = value ?? 3; + if (!Number.isFinite(scale) || scale <= 0) throw new Error('Office.js image scale must be positive.'); + return scale; +} + +export function generateOfficeJs(value: unknown, options: OfficeJsCodegenOptions = {}): GeneratedOfficeJs { + const prepared = prepareExcelArtifact(value); + const { spec } = prepared; + const functionName = options.functionName ?? 'renderFlintChart'; + if (!/^[$A-Z_a-z][$\w]*$/.test(functionName)) { + throw new Error('Office.js functionName must be a valid JavaScript identifier.'); + } + const width = spec.width ?? 400; + const height = spec.height ?? 300; + const scale = positiveScale(options.scale); + const imageWidth = Math.round(width * (96 / 72) * scale); + const imageHeight = Math.round(height * (96 / 72) * scale); + const lines = [ + `async function ${functionName}(context) {`, + ' const sheet = context.workbook.worksheets.getActiveWorksheet();', + ]; + + if (options.cleanWorksheet) { + lines.push( + " sheet.charts.load('items/name');", + ' const previousRange = sheet.getUsedRangeOrNullObject();', + ' await context.sync();', + ' sheet.charts.items.forEach((existingChart) => existingChart.delete());', + ' if (!previousRange.isNullObject) previousRange.clear();', + ); + } + + lines.push( + ` const values = ${JSON.stringify(prepared.data)};`, + ` const dataRange = sheet.getRange(${JSON.stringify(prepared.rangeA1)});`, + ' dataRange.numberFormat = values.map((row, rowIndex) =>', + ` row.map((_cell, columnIndex) => rowIndex === 0 ? '@' : columnIndex === 0 && ${prepared.dateAxis} ? 'yyyy-mm-dd' : columnIndex === 0 && ${!prepared.numericAxis} ? '@' : 'General'),`, + ' );', + ' dataRange.values = values;', + ` const chart = sheet.charts.add(${JSON.stringify(prepared.chartType)}, dataRange, ${JSON.stringify(spec.seriesBy)});`, + ); + + if (spec.series?.length) { + lines.push(" chart.series.load('items');", ' await context.sync();'); + lines.push(` if (chart.series.items.length < ${spec.series.length}) throw new Error('Excel inferred too few series.');`); + spec.series.forEach((binding, index) => { + lines.push( + ` chart.series.items[${index}].name = ${JSON.stringify(binding.name)};`, + ` chart.series.items[${index}].setXAxisValues(sheet.getRangeByIndexes(1, ${binding.xColumn}, ${binding.rowCount}, 1));`, + ` chart.series.items[${index}].setValues(sheet.getRangeByIndexes(1, ${binding.yColumn}, ${binding.rowCount}, 1));`, + ); + if (binding.bubbleSizeColumn !== undefined) { + lines.push(` chart.series.items[${index}].setBubbleSizes(sheet.getRangeByIndexes(1, ${binding.bubbleSizeColumn}, ${binding.rowCount}, 1));`); + } + }); + lines.push( + ` for (let index = chart.series.items.length - 1; index >= ${spec.series.length}; index -= 1) {`, + ' chart.series.getItemAt(index).delete();', + ' await context.sync();', + ' }', + ); + } + + lines.push(` chart.width = ${width};`, ` chart.height = ${height};`); + if (spec.title) { + lines.push(` chart.title.text = ${JSON.stringify(spec.title)};`, ' chart.title.visible = true;'); + } + if (spec.legend) { + lines.push(` chart.legend.visible = ${spec.legend.visible};`); + if (spec.legend.visible && spec.legend.position) { + lines.push(` chart.legend.position = ${JSON.stringify(spec.legend.position)};`); + } + } + if (spec.dataLabels) { + lines.push(` chart.dataLabels.visible = ${spec.dataLabels.visible};`); + if (spec.dataLabels.position) lines.push(` chart.dataLabels.position = ${JSON.stringify(spec.dataLabels.position)};`); + if (spec.dataLabels.numberFormat) lines.push(` chart.dataLabels.numberFormat = ${JSON.stringify(spec.dataLabels.numberFormat)};`); + if (spec.dataLabels.fontColor) lines.push(` chart.dataLabels.format.font.color = ${JSON.stringify(spec.dataLabels.fontColor)};`); + if (spec.dataLabels.fontSize !== undefined) lines.push(` chart.dataLabels.format.font.size = ${spec.dataLabels.fontSize};`); + } + if (prepared.hasAxes) { + if (spec.categoryAxis) lines.push(...axisCode('categoryAxis', spec.categoryAxis)); + if (spec.valueAxis) lines.push(...axisCode('valueAxis', spec.valueAxis)); + } + + lines.push(` const seriesFormats = ${JSON.stringify(spec.seriesFormats ?? [])};`); + lines.push(` for (let index = 0; index < ${prepared.seriesCount}; index += 1) {`, ' const series = chart.series.getItemAt(index);', ' const format = seriesFormats[index];'); + if (prepared.isBar && spec.gapWidth !== undefined) lines.push(` series.gapWidth = ${spec.gapWidth};`); + if (prepared.isBar && spec.overlap !== undefined) lines.push(` series.overlap = ${spec.overlap};`); + if (/Bubble/i.test(prepared.chartType) && spec.bubbleScale !== undefined) lines.push(` series.bubbleScale = ${spec.bubbleScale};`); + if (/Doughnut/i.test(prepared.chartType) && spec.doughnutHoleSize !== undefined) lines.push(` series.doughnutHoleSize = ${spec.doughnutHoleSize};`); + if (/BoxWhisker/i.test(prepared.chartType) && spec.boxWhiskerOptions) lines.push(` series.boxwhiskerOptions.set(${JSON.stringify(spec.boxWhiskerOptions)});`); + if (/Waterfall/i.test(prepared.chartType) && spec.showConnectorLines !== undefined) lines.push(` series.showConnectorLines = ${spec.showConnectorLines};`); + lines.push(' if (format?.color) {'); + if (!prepared.isLine) lines.push(' series.format.fill.setSolidColor(format.color);'); + lines.push(' series.format.line.color = format.color;', ' }', ' if (format?.lineStyle) series.format.line.lineStyle = format.lineStyle;', ' }'); + lines.push( + ` const image = chart.getImage(${imageWidth}, ${imageHeight}, Excel.ImageFittingMode.fit);`, + ' await context.sync();', + ' return image.value;', + '}', + '', + 'async function main() {', + ` return Excel.run(${functionName});`, + '}', + '', + ); + + return { + code: lines.join('\n'), + meta: { + schema: spec.schema, + rangeA1: prepared.rangeA1, + chartType: prepared.chartType, + rows: prepared.rows, + columns: prepared.columns, + }, + }; +} diff --git a/packages/flint-js/src/excel/index.ts b/packages/flint-js/src/excel/index.ts new file mode 100644 index 00000000..15f2770f --- /dev/null +++ b/packages/flint-js/src/excel/index.ts @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * @module flint-chart/excel + * + * Excel backend for flint-chart. + * + * Compiles the core semantic layer into a native Office.js Excel chart spec + * (a wide/matrix data range + chart type, axes, legend). A host renders it via + * the Office.js Excel API (`sheet.charts.add(...)` + `chart.getImage()`). + * + * Architecture contrast with other backends: + * VL: encoding-channel-based — { encoding: { x, y }, mark } + * EC: series-based — { series: [...], xAxis, yAxis } + * CJS: dataset-based — { type, data: { labels, datasets } } + * Excel: range/matrix-based — { chartType, data: [[...]], seriesBy, axes } + * + * Same core Phase 0 (semantics); Excel-specific Stage 3 output. + */ + +export { assembleExcel } from './assemble'; +export { + EXCEL_ARTIFACT_SCHEMA, + SUPPORTED_EXCEL_CHART_TYPES, + excelColumnLetter, + prepareExcelArtifact, +} from './artifact'; +export type { PreparedExcelArtifact } from './artifact'; +export { generateOfficeJs } from './codegen'; +export type { GeneratedOfficeJs, OfficeJsCodegenOptions } from './codegen'; +export { renderExcelChart } from './runtime'; +export type { ExcelRenderOptions, ExcelRenderResult, OfficeJsExcelApi } from './runtime'; +export { EXCEL_TYPE_MAP, isExcelSupported, formatSpecToExcel } from './chart-types'; +export { + excelAllTemplateDefs, + excelGetTemplateDef, + excelGetTemplateChannels, +} from './templates'; +export type { ExcelTemplateContext, ExcelTemplateDef } from './templates'; +export type { + ExcelChartSpec, + ExcelNativeChartSpec, + ExcelNativeSeriesSpec, + ExcelNativeSeriesFormatSpec, + ExcelAxisSpec, + ExcelLegendSpec, + ExcelDataLabelsSpec, + ExcelBoxWhiskerOptionsSpec, + ExcelSeriesBy, + ExcelLegendPosition, +} from './types'; diff --git a/packages/flint-js/src/excel/runtime.ts b/packages/flint-js/src/excel/runtime.ts new file mode 100644 index 00000000..82603ca2 --- /dev/null +++ b/packages/flint-js/src/excel/runtime.ts @@ -0,0 +1,195 @@ +import { prepareExcelArtifact, type PreparedExcelArtifact } from './artifact'; + +export interface OfficeJsExcelApi { + run(callback: (context: any) => Promise): Promise; + ImageFittingMode: { fit: any }; +} + +export interface ExcelRenderOptions { + scale?: number; + cleanWorksheet?: boolean; + inspectNativeChart?: boolean; +} + +export interface ExcelRenderResult { + pngBase64: string; + inspection: unknown | null; +} + +function applyChartFormat(chart: any, prepared: PreparedExcelArtifact): void { + const { spec } = prepared; + if (spec.legend) { + chart.legend.visible = spec.legend.visible; + if (spec.legend.visible && spec.legend.position) chart.legend.position = spec.legend.position; + } + if (prepared.hasAxes) { + const axes = [ + [chart.axes.categoryAxis, spec.categoryAxis], + [chart.axes.valueAxis, spec.valueAxis], + ] as const; + for (const [axis, format] of axes) { + if (!format) continue; + if (format.title) { + axis.title.text = format.title; + axis.title.visible = true; + } + if (format.numberFormat) axis.numberFormat = format.numberFormat; + if (format.labelFontSize !== undefined) axis.format.font.size = format.labelFontSize; + if (format.tickLabelSpacing !== undefined) axis.tickLabelSpacing = format.tickLabelSpacing; + if (format.reversePlotOrder !== undefined) axis.reversePlotOrder = format.reversePlotOrder; + if (format.minimumScale !== undefined) axis.minimum = format.minimumScale; + if (format.maximumScale !== undefined) axis.maximum = format.maximumScale; + if (format.majorUnit !== undefined) axis.majorUnit = format.majorUnit; + } + } + if (spec.dataLabels) { + chart.dataLabels.visible = spec.dataLabels.visible; + if (spec.dataLabels.position) chart.dataLabels.position = spec.dataLabels.position; + if (spec.dataLabels.numberFormat) chart.dataLabels.numberFormat = spec.dataLabels.numberFormat; + if (spec.dataLabels.fontColor) chart.dataLabels.format.font.color = spec.dataLabels.fontColor; + if (spec.dataLabels.fontSize !== undefined) chart.dataLabels.format.font.size = spec.dataLabels.fontSize; + } + for (let index = 0; index < prepared.seriesCount; index += 1) { + const series = chart.series.getItemAt(index); + const format = spec.seriesFormats?.[index]; + if (format?.color) { + if (!prepared.isLine) series.format.fill.setSolidColor(format.color); + series.format.line.color = format.color; + } + if (format?.lineStyle) series.format.line.lineStyle = format.lineStyle; + if (prepared.isBar && spec.gapWidth !== undefined) series.gapWidth = spec.gapWidth; + if (prepared.isBar && spec.overlap !== undefined) series.overlap = spec.overlap; + if (/Bubble/i.test(prepared.chartType) && spec.bubbleScale !== undefined) series.bubbleScale = spec.bubbleScale; + if (/Doughnut/i.test(prepared.chartType) && spec.doughnutHoleSize !== undefined) series.doughnutHoleSize = spec.doughnutHoleSize; + if (/BoxWhisker/i.test(prepared.chartType) && spec.boxWhiskerOptions) series.boxwhiskerOptions.set(spec.boxWhiskerOptions); + if (/Waterfall/i.test(prepared.chartType) && spec.showConnectorLines !== undefined) series.showConnectorLines = spec.showConnectorLines; + } +} + +async function inspectChart(context: any, sheet: any, dataRange: any, chart: any): Promise { + try { + dataRange.load('address,values,numberFormat'); + const usedRange = sheet.getUsedRangeOrNullObject(); + usedRange.load('isNullObject,address,values'); + chart.load('name,chartType'); + chart.series.load('items/name,items/chartType,items/axisGroup,items/formula'); + await context.sync(); + for (const series of chart.series.items) { + series.binOptions.load('type,count,width,allowOverflow,overflowValue,allowUnderflow,underflowValue'); + } + const primaryCategoryAxis = chart.axes.getItemOrNullObject('Category', 'Primary'); + const primaryValueAxis = chart.axes.getItemOrNullObject('Value', 'Primary'); + const secondaryValueAxis = chart.axes.getItemOrNullObject('Value', 'Secondary'); + for (const axis of [primaryCategoryAxis, primaryValueAxis, secondaryValueAxis]) { + axis.load('isNullObject,axisType,axisGroup,visible,minimum,maximum,numberFormat'); + axis.title.load('text,visible'); + } + await context.sync(); + const describeAxis = (axis: any) => axis.isNullObject ? null : { ...axis.toJSON(), title: axis.title.toJSON() }; + return { + sourceRange: { + address: dataRange.address, + values: dataRange.values, + numberFormat: dataRange.numberFormat, + }, + usedRange: usedRange.isNullObject ? null : { + address: usedRange.address, + values: usedRange.values, + }, + chart: { + name: chart.name, + chartType: chart.chartType, + series: chart.series.items.map((series: any) => ({ + ...series.toJSON(), + binOptions: series.binOptions.toJSON(), + })), + axes: { + primaryCategory: describeAxis(primaryCategoryAxis), + primaryValue: describeAxis(primaryValueAxis), + secondaryValue: describeAxis(secondaryValueAxis), + }, + }, + }; + } catch (error) { + return { error: error instanceof Error ? error.message : String(error) }; + } +} + +function imageScale(value: number | undefined): number { + const scale = value ?? 3; + if (!Number.isFinite(scale) || scale <= 0) throw new Error('Office.js image scale must be positive.'); + return scale; +} + +export async function renderExcelChart( + excelApi: OfficeJsExcelApi, + value: unknown, + options: ExcelRenderOptions = {}, +): Promise { + const prepared = prepareExcelArtifact(value); + const { spec } = prepared; + const scale = imageScale(options.scale); + return excelApi.run(async (context) => { + const sheet = context.workbook.worksheets.getActiveWorksheet(); + if (options.cleanWorksheet !== false) { + sheet.charts.load('items/name'); + const previousRange = sheet.getUsedRangeOrNullObject(); + await context.sync(); + sheet.charts.items.forEach((existingChart: any) => existingChart.delete()); + if (!previousRange.isNullObject) previousRange.clear(); + } + + const dataRange = sheet.getRange(prepared.rangeA1); + dataRange.numberFormat = prepared.data.map((row, rowIndex) => row.map((_cell, columnIndex) => + rowIndex === 0 + ? '@' + : columnIndex === 0 && prepared.dateAxis + ? 'yyyy-mm-dd' + : columnIndex === 0 && !prepared.numericAxis ? '@' : 'General', + )); + dataRange.values = prepared.data; + const chart = sheet.charts.add(prepared.chartType, dataRange, spec.seriesBy); + + if (spec.series?.length) { + chart.series.load('items'); + await context.sync(); + if (chart.series.items.length < spec.series.length) { + throw new Error(`Excel inferred ${chart.series.items.length} series; ${spec.series.length} required.`); + } + for (const [index, binding] of spec.series.entries()) { + const series = chart.series.items[index]; + series.name = binding.name; + series.setXAxisValues(sheet.getRangeByIndexes(1, binding.xColumn, binding.rowCount, 1)); + series.setValues(sheet.getRangeByIndexes(1, binding.yColumn, binding.rowCount, 1)); + if (binding.bubbleSizeColumn !== undefined) { + series.setBubbleSizes(sheet.getRangeByIndexes(1, binding.bubbleSizeColumn, binding.rowCount, 1)); + } + } + for (let index = chart.series.items.length - 1; index >= spec.series.length; index -= 1) { + chart.series.getItemAt(index).delete(); + await context.sync(); + } + } + + const width = spec.width ?? 400; + const height = spec.height ?? 300; + chart.width = width; + chart.height = height; + if (spec.title) { + chart.title.text = spec.title; + chart.title.visible = true; + } + applyChartFormat(chart, prepared); + await context.sync(); + const image = chart.getImage( + Math.round(width * (96 / 72) * scale), + Math.round(height * (96 / 72) * scale), + excelApi.ImageFittingMode.fit, + ); + await context.sync(); + const inspection = options.inspectNativeChart + ? await inspectChart(context, sheet, dataRange, chart) + : null; + return { pngBase64: image.value, inspection }; + }); +} diff --git a/packages/flint-js/src/excel/templates/area.ts b/packages/flint-js/src/excel/templates/area.ts new file mode 100644 index 00000000..6fa36d6d --- /dev/null +++ b/packages/flint-js/src/excel/templates/area.ts @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import type { ExcelTemplateDef } from './types'; + +export const excelAreaChartDef: ExcelTemplateDef = { + chart: 'Area Chart', + channels: ['x', 'y', 'color'], + typeMapping: { vertical: 'Area' }, + validate: ({ typeOf }) => typeOf('y') !== 'quantitative' + ? 'requires a quantitative y field for a native Excel area chart' + : undefined, +}; \ No newline at end of file diff --git a/packages/flint-js/src/excel/templates/bar.ts b/packages/flint-js/src/excel/templates/bar.ts new file mode 100644 index 00000000..14e97d21 --- /dev/null +++ b/packages/flint-js/src/excel/templates/bar.ts @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import type { ExcelTemplateDef } from './types'; + +export const excelBarChartDef: ExcelTemplateDef = { + chart: 'Bar Chart', + channels: ['x', 'y', 'color'], + typeMapping: { vertical: 'ColumnClustered', horizontal: 'BarClustered' }, + validate: ({ typeOf }) => typeOf('x') !== 'quantitative' && typeOf('y') !== 'quantitative' + ? 'requires one quantitative measure axis for a native Excel bar chart' + : undefined, +}; + +export const excelGroupedBarChartDef: ExcelTemplateDef = { + chart: 'Grouped Bar Chart', + channels: ['x', 'y', 'group'], + typeMapping: { vertical: 'ColumnClustered', horizontal: 'BarClustered' }, + validate: (context) => excelBarChartDef.validate?.(context) + ?? (context.typeOf('group') === 'quantitative' || context.typeOf('group') === 'temporal' + ? 'does not support continuous grouping in a native Excel grouped bar chart' + : undefined), +}; + +export const excelStackedBarChartDef: ExcelTemplateDef = { + chart: 'Stacked Bar Chart', + channels: ['x', 'y', 'color'], + typeMapping: { vertical: 'ColumnStacked', horizontal: 'BarStacked' }, + validate: (context) => excelBarChartDef.validate?.(context) + ?? (context.typeOf('color') === 'quantitative' || context.typeOf('color') === 'temporal' + ? 'does not support continuous color in a native Excel stacked bar chart' + : undefined), +}; \ No newline at end of file diff --git a/packages/flint-js/src/excel/templates/boxplot.ts b/packages/flint-js/src/excel/templates/boxplot.ts new file mode 100644 index 00000000..051ca7cf --- /dev/null +++ b/packages/flint-js/src/excel/templates/boxplot.ts @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { formatSpecToExcel } from '../chart-types'; +import type { ExcelTemplateDef } from './types'; + +export const excelBoxplotDef: ExcelTemplateDef = { + chart: 'Boxplot', + channels: ['x', 'y', 'color'], + typeMapping: { vertical: 'BoxWhisker' }, + validate: ({ input, fieldOf, typeOf }) => { + if (!fieldOf('x') || typeOf('x') === 'temporal') { + return 'requires a categorical x field for a native Excel box and whisker chart'; + } + if (!fieldOf('y') || typeOf('y') !== 'quantitative') { + return 'requires a quantitative y field for a native Excel box and whisker chart'; + } + if (fieldOf('color')) { + return 'does not yet support color-grouped native Excel box and whisker charts'; + } + if (fieldOf('column') || fieldOf('row')) { + return 'does not support faceting in one native Excel box and whisker chart'; + } + if (input.chart_spec.chartProperties?.whiskerMethod === 'minmax') { + return 'does not support min-max whiskers because Office.js exposes no native BoxWhisker whisker-method control'; + } + return undefined; + }, + instantiate: ({ input, table, semantics, fieldOf }) => { + const categoryField = fieldOf('x')!; + const valueField = fieldOf('y')!; + const rows = table.filter((row) => row[categoryField] != null && Number.isFinite(Number(row[valueField]))); + const base = input.chart_spec.baseSize ?? { width: 480, height: 320 }; + const properties = input.chart_spec.chartProperties; + + return { + schema: 'flint.excel.chart/v1', + kind: 'chart', + chartType: 'BoxWhisker', + title: `${valueField} by ${categoryField}`, + seriesBy: 'Columns', + data: [ + [categoryField, valueField], + ...rows.map((row) => [String(row[categoryField]), Number(row[valueField])]), + ], + categoryAxis: { title: categoryField }, + valueAxis: { + title: valueField, + numberFormat: formatSpecToExcel(semantics.y?.format), + }, + legend: { visible: false }, + boxWhiskerOptions: { + quartileCalculation: 'Inclusive', + showInnerPoints: false, + showMeanLine: false, + showMeanMarker: false, + showOutlierPoints: properties?.showOutliers !== false, + }, + width: base.width, + height: base.height, + warnings: [], + _flint: { flintType: 'Boxplot', categoryField, valueField, rawObservations: rows.length }, + }; + }, +}; \ No newline at end of file diff --git a/packages/flint-js/src/excel/templates/candlestick.ts b/packages/flint-js/src/excel/templates/candlestick.ts new file mode 100644 index 00000000..fada1375 --- /dev/null +++ b/packages/flint-js/src/excel/templates/candlestick.ts @@ -0,0 +1,107 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { formatSpecToExcel } from '../chart-types'; +import type { ExcelTemplateDef } from './types'; + +const PRICE_CHANNELS = ['open', 'high', 'low', 'close'] as const; +const EXCEL_EPOCH = Date.UTC(1899, 11, 30); +const DAY_MILLISECONDS = 24 * 60 * 60 * 1000; + +function excelDateSerial(value: unknown): number { + return (new Date(value as string | number | Date).getTime() - EXCEL_EPOCH) / DAY_MILLISECONDS; +} + +function niceStep(span: number): number { + const rough = span / 5; + const power = 10 ** Math.floor(Math.log10(rough)); + const fraction = rough / power; + return (fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 5 ? 5 : 10) * power; +} + +export const excelCandlestickDef: ExcelTemplateDef = { + chart: 'Candlestick Chart', + channels: ['x', 'open', 'high', 'low', 'close'], + typeMapping: { vertical: 'StockOHLC' }, + validate: ({ table, fieldOf, typeOf }) => { + const xField = fieldOf('x'); + if (!xField || !['temporal', 'ordinal'].includes(typeOf('x') ?? '')) { + return 'requires a temporal or ordered x field for a native Excel stock chart'; + } + for (const channel of PRICE_CHANNELS) { + if (!fieldOf(channel) || typeOf(channel) !== 'quantitative') { + return `requires a quantitative ${channel} field for a native Excel stock chart`; + } + } + if (fieldOf('color') || fieldOf('group') || fieldOf('detail')) { + return 'does not support color, group, or detail encodings in a native Excel stock chart'; + } + if (table.length === 0) { + return 'requires at least one OHLC row for a native Excel stock chart'; + } + + let previousTime = Number.NEGATIVE_INFINITY; + for (const [index, row] of table.entries()) { + const time = new Date(row[xField]).getTime(); + if (!Number.isFinite(time)) { + return `requires a valid date at row ${index + 1} for a native Excel stock chart`; + } + if (time <= previousTime) { + return 'requires x values sorted in strictly increasing chronological order for a native Excel stock chart'; + } + previousTime = time; + + const rawPrices = PRICE_CHANNELS.map((channel) => row[fieldOf(channel)!]); + const [open, high, low, close] = rawPrices.map(Number); + if (rawPrices.some((value) => value == null || value === '') || ![open, high, low, close].every(Number.isFinite)) { + return `requires finite open, high, low, and close values at row ${index + 1} for a native Excel stock chart`; + } + if (high < Math.max(open, low, close) || low > Math.min(open, high, close)) { + return `requires coherent OHLC values at row ${index + 1} (high >= open/close/low and low <= open/close/high)`; + } + } + return undefined; + }, + instantiate: ({ input, table, semantics, fieldOf }) => { + const xField = fieldOf('x')!; + const fields = PRICE_CHANNELS.map((channel) => fieldOf(channel)!); + const base = input.chart_spec.baseSize ?? { width: 480, height: 320 }; + const labelBudget = Math.max(12, Math.floor((base.width - 90) / 14)); + const tickLabelSpacing = table.length > labelBudget ? Math.ceil(table.length / labelBudget) : undefined; + const lows = table.map((row) => Number(row[fields[2]])); + const highs = table.map((row) => Number(row[fields[1]])); + const minimum = Math.min(...lows); + const maximum = Math.max(...highs); + const majorUnit = niceStep(Math.max(maximum - minimum, Math.abs(maximum) * 0.1, 1)); + const minimumScale = Math.floor(minimum / majorUnit) * majorUnit; + const maximumScale = Math.ceil(maximum / majorUnit) * majorUnit; + + return { + schema: 'flint.excel.chart/v1', + kind: 'chart', + chartType: 'StockOHLC', + title: `${fields[3]} by ${xField}`, + seriesBy: 'Columns', + data: [ + [xField, ...fields], + ...table.map((row) => [ + excelDateSerial(row[xField]), + ...fields.map((field) => Number(row[field])), + ]), + ], + categoryAxis: { title: xField, numberFormat: 'yyyy-mm-dd', tickLabelSpacing }, + valueAxis: { + title: 'Price', + numberFormat: formatSpecToExcel(semantics.close?.format), + minimumScale, + maximumScale: maximumScale === maximum ? maximumScale + majorUnit : maximumScale, + majorUnit, + }, + legend: { visible: false }, + width: base.width, + height: base.height, + warnings: [], + _flint: { flintType: 'Candlestick Chart', xField, priceFields: fields }, + }; + }, +}; \ No newline at end of file diff --git a/packages/flint-js/src/excel/templates/funnel.ts b/packages/flint-js/src/excel/templates/funnel.ts new file mode 100644 index 00000000..401037de --- /dev/null +++ b/packages/flint-js/src/excel/templates/funnel.ts @@ -0,0 +1,69 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { formatSpecToExcel } from '../chart-types'; +import type { ExcelTemplateDef } from './types'; + +export const excelFunnelChartDef: ExcelTemplateDef = { + chart: 'Funnel Chart', + channels: ['y', 'size'], + typeMapping: { vertical: 'Funnel', noAxes: true }, + validate: ({ table, fieldOf, typeOf }) => { + if (!fieldOf('y') || typeOf('y') === 'quantitative') { + return 'requires a categorical y stage field for a native Excel funnel chart'; + } + if (typeOf('size') !== 'quantitative') { + return 'requires a quantitative size field for a native Excel funnel chart'; + } + const valueField = fieldOf('size')!; + if (table.some((row) => Number.isFinite(Number(row[valueField])) && Number(row[valueField]) < 0)) { + return 'requires non-negative values for a native Excel funnel chart'; + } + return undefined; + }, + instantiate: ({ input, table, semantics, fieldOf }) => { + const stageField = fieldOf('y')!; + const valueField = fieldOf('size')!; + const stageValues = new Map(); + for (const row of table) { + const stage = row[stageField]; + const value = Number(row[valueField]); + if (stage == null || !Number.isFinite(value)) continue; + const label = String(stage); + stageValues.set(label, (stageValues.get(label) ?? 0) + value); + } + + const rows = [...stageValues.entries()]; + const sort = input.chart_spec.chartProperties?.sort ?? 'descending'; + if (sort === 'descending') rows.sort((left, right) => right[1] - left[1]); + if (sort === 'ascending') rows.sort((left, right) => left[1] - right[1]); + + const base = input.chart_spec.baseSize ?? { width: 480, height: 320 }; + return { + schema: 'flint.excel.chart/v1', + kind: 'chart', + chartType: 'Funnel', + title: `${valueField} by ${stageField}`, + seriesBy: 'Columns', + data: [[stageField, valueField], ...rows], + legend: { visible: false }, + dataLabels: { + visible: true, + numberFormat: formatSpecToExcel(semantics.size?.format), + fontColor: '#FFFFFF', + fontSize: 11, + }, + seriesFormats: [{ color: '#4472C4' }], + width: base.width, + height: base.height, + warnings: [], + _flint: { + flintType: 'Funnel Chart', + stageField, + valueField, + sort, + valueNumberFormat: formatSpecToExcel(semantics.size?.format), + }, + }; + }, +}; \ No newline at end of file diff --git a/packages/flint-js/src/excel/templates/histogram.ts b/packages/flint-js/src/excel/templates/histogram.ts new file mode 100644 index 00000000..bf6964eb --- /dev/null +++ b/packages/flint-js/src/excel/templates/histogram.ts @@ -0,0 +1,80 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import type { ExcelTemplateDef } from './types'; + +function niceBinStep(minimum: number, maximum: number, maxBins: number): number { + const raw = Math.max(Number.EPSILON, maximum - minimum) / Math.max(1, maxBins); + const power = 10 ** Math.floor(Math.log10(raw)); + const error = raw / power; + const factor = error >= 5 ? 10 : error >= 2 ? 5 : error >= 1 ? 2 : 1; + return factor * power; +} + +export const excelHistogramDef: ExcelTemplateDef = { + chart: 'Histogram', + channels: ['x', 'color'], + typeMapping: { vertical: 'ColumnClustered' }, + validate: ({ fieldOf, typeOf }) => { + const valueChannel = fieldOf('x') ? 'x' : 'y'; + return !fieldOf(valueChannel) || typeOf(valueChannel) !== 'quantitative' + ? 'requires a quantitative value field for a native Excel histogram' + : undefined; + }, + instantiate: ({ input, table, fieldOf }) => { + const valueField = fieldOf('x') ?? fieldOf('y')!; + const values = table.map((row) => Number(row[valueField])).filter(Number.isFinite); + if (values.length === 0) throw new Error('Excel histogram requires finite numeric values.'); + + const requestedBins = Number(input.chart_spec.chartProperties?.binCount); + const maxBins = Number.isFinite(requestedBins) && requestedBins > 0 + ? Math.max(1, Math.round(requestedBins)) + : 10; + const minimum = Math.min(...values); + const maximum = Math.max(...values); + const binWidth = maximum > minimum ? niceBinStep(minimum, maximum, maxBins) : 1; + const binMinimum = Math.floor(minimum / binWidth) * binWidth; + const binMaximum = Math.ceil(maximum / binWidth) * binWidth; + const binCount = Math.max(1, Math.round((binMaximum - binMinimum) / binWidth)); + const labels = Array.from({ length: binCount }, (_value, index) => { + const lower = binMinimum + index * binWidth; + const upper = binMinimum + (index + 1) * binWidth; + return `${Number(lower.toFixed(2))}-${Number(upper.toFixed(2))}`; + }); + const colorField = fieldOf('color'); + const seriesKeys = colorField + ? [...new Set(table.map((row) => String(row[colorField])))] + : ['Count']; + const seriesCounts = seriesKeys.map(() => new Array(binCount).fill(0)); + for (const row of table) { + const value = Number(row[valueField]); + if (!Number.isFinite(value)) continue; + const binIndex = Math.min( + binCount - 1, + Math.max(0, Math.floor((value - binMinimum) / binWidth)), + ); + const seriesIndex = colorField ? seriesKeys.indexOf(String(row[colorField])) : 0; + if (seriesIndex >= 0) seriesCounts[seriesIndex][binIndex] += 1; + } + const base = input.chart_spec.baseSize ?? { width: 480, height: 320 }; + return { + schema: 'flint.excel.chart/v1', + kind: 'chart', + chartType: colorField ? 'ColumnStacked' : 'ColumnClustered', + title: `Distribution of ${valueField}`, + seriesBy: 'Columns', + data: [ + [valueField, ...seriesKeys], + ...labels.map((label, index) => [label, ...seriesCounts.map((series) => series[index])]), + ], + categoryAxis: { title: valueField }, + valueAxis: { title: 'Count', numberFormat: '0' }, + legend: { visible: Boolean(colorField), position: 'Bottom' }, + gapWidth: 0, + width: base.width, + height: base.height, + warnings: [], + _flint: { flintType: 'Histogram', valueField, colorField, binCount, binMinimum, binMaximum }, + }; + }, +}; \ No newline at end of file diff --git a/packages/flint-js/src/excel/templates/index.ts b/packages/flint-js/src/excel/templates/index.ts new file mode 100644 index 00000000..367fbb5a --- /dev/null +++ b/packages/flint-js/src/excel/templates/index.ts @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import type { ExcelTemplateDef } from './types'; +import { excelAreaChartDef } from './area'; +import { excelBarChartDef, excelGroupedBarChartDef, excelStackedBarChartDef } from './bar'; +import { excelBoxplotDef } from './boxplot'; +import { excelCandlestickDef } from './candlestick'; +import { excelFunnelChartDef } from './funnel'; +import { excelHistogramDef } from './histogram'; +import { excelLineChartDef } from './line'; +import { excelDonutChartDef, excelPieChartDef } from './pie'; +import { excelPyramidChartDef } from './pyramid'; +import { excelRadarChartDef } from './radar'; +import { excelConnectedScatterPlotDef, excelScatterPlotDef } from './scatter'; +import { excelSunburstChartDef } from './sunburst'; +import { excelTreemapDef } from './treemap'; +import { excelWaterfallChartDef } from './waterfall'; + +export const excelAllTemplateDefs: ExcelTemplateDef[] = [ + excelBarChartDef, + excelGroupedBarChartDef, + excelStackedBarChartDef, + excelPyramidChartDef, + excelLineChartDef, + excelAreaChartDef, + excelScatterPlotDef, + excelConnectedScatterPlotDef, + excelPieChartDef, + excelDonutChartDef, + excelHistogramDef, + excelBoxplotDef, + excelCandlestickDef, + excelWaterfallChartDef, + excelRadarChartDef, + excelFunnelChartDef, + excelTreemapDef, + excelSunburstChartDef, +]; + +export function excelGetTemplateDef(chartType: string): ExcelTemplateDef | undefined { + return excelAllTemplateDefs.find((template) => template.chart === chartType); +} + +export function excelGetTemplateChannels(chartType: string): string[] { + return excelGetTemplateDef(chartType)?.channels ?? []; +} + +export type { ExcelTemplateContext, ExcelTemplateDef } from './types'; \ No newline at end of file diff --git a/packages/flint-js/src/excel/templates/line.ts b/packages/flint-js/src/excel/templates/line.ts new file mode 100644 index 00000000..871d6f4b --- /dev/null +++ b/packages/flint-js/src/excel/templates/line.ts @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import type { ExcelTemplateDef } from './types'; + +export const excelLineChartDef: ExcelTemplateDef = { + chart: 'Line Chart', + channels: ['x', 'y', 'color', 'strokeDash'], + typeMapping: { vertical: 'Line' }, + validate: ({ typeOf }) => { + if (typeOf('y') !== 'quantitative') { + return 'requires a quantitative y field for a native Excel line chart'; + } + if (typeOf('color') === 'quantitative' || typeOf('color') === 'temporal') { + return 'does not support continuous color on a native Excel line chart'; + } + return undefined; + }, +}; \ No newline at end of file diff --git a/packages/flint-js/src/excel/templates/pie.ts b/packages/flint-js/src/excel/templates/pie.ts new file mode 100644 index 00000000..38d71c14 --- /dev/null +++ b/packages/flint-js/src/excel/templates/pie.ts @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import type { ExcelTemplateDef } from './types'; + +export const excelPieChartDef: ExcelTemplateDef = { + chart: 'Pie Chart', + channels: ['color', 'size', 'theta'], + typeMapping: { vertical: 'Pie', noAxes: true }, +}; + +export const excelDonutChartDef: ExcelTemplateDef = { + chart: 'Donut Chart', + channels: ['color', 'size', 'theta'], + typeMapping: { vertical: 'Doughnut', noAxes: true }, +}; \ No newline at end of file diff --git a/packages/flint-js/src/excel/templates/pyramid.ts b/packages/flint-js/src/excel/templates/pyramid.ts new file mode 100644 index 00000000..33724f04 --- /dev/null +++ b/packages/flint-js/src/excel/templates/pyramid.ts @@ -0,0 +1,115 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { formatSpecToExcel } from '../chart-types'; +import type { ExcelTemplateDef } from './types'; + +function niceMaximum(value: number): { maximum: number; majorUnit: number } { + const roughStep = Math.max(value, 1) / 5; + const power = 10 ** Math.floor(Math.log10(roughStep)); + const fraction = roughStep / power; + const majorUnit = (fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 5 ? 5 : 10) * power; + return { maximum: Math.ceil(value / majorUnit) * majorUnit, majorUnit }; +} + +function absoluteNumberFormat(format: string | undefined): string { + const positive = !format || format === 'General' ? '#,##0' : format; + return `${positive};${positive};0`; +} + +export const excelPyramidChartDef: ExcelTemplateDef = { + chart: 'Pyramid Chart', + channels: ['x', 'y', 'color'], + typeMapping: { vertical: 'BarStacked', horizontal: 'BarStacked' }, + validate: ({ table, fieldOf, typeOf }) => { + const xIsMeasure = typeOf('x') === 'quantitative'; + const yIsMeasure = typeOf('y') === 'quantitative'; + if (xIsMeasure === yIsMeasure) { + return 'requires exactly one quantitative measure axis for a native Excel pyramid chart'; + } + const categoryChannel = xIsMeasure ? 'y' : 'x'; + if (!fieldOf(categoryChannel) || typeOf(categoryChannel) === 'quantitative') { + return 'requires a discrete category axis for a native Excel pyramid chart'; + } + const groupField = fieldOf('color'); + if (!groupField || ['quantitative', 'temporal'].includes(typeOf('color') ?? '')) { + return 'requires a discrete color field for a native Excel pyramid chart'; + } + const groups = [...new Set(table.map((row) => row[groupField]).filter((value) => value != null))]; + if (groups.length !== 2) { + return `requires exactly two groups for a native Excel pyramid chart (found ${groups.length})`; + } + const measureField = fieldOf(xIsMeasure ? 'x' : 'y')!; + if (table.some((row) => Number.isFinite(Number(row[measureField])) && Number(row[measureField]) < 0)) { + return 'requires non-negative values for a native Excel pyramid chart'; + } + return undefined; + }, + instantiate: ({ input, table, semantics, fieldOf, typeOf }) => { + const measureChannel = typeOf('x') === 'quantitative' ? 'x' : 'y'; + const categoryChannel = measureChannel === 'x' ? 'y' : 'x'; + const measureField = fieldOf(measureChannel)!; + const categoryField = fieldOf(categoryChannel)!; + const groupField = fieldOf('color')!; + const categories = [...new Set(table.map((row) => row[categoryField]).filter((value) => value != null))]; + const groups = [...new Set(table.map((row) => row[groupField]).filter((value) => value != null))]; + const totals = new Map(); + for (const row of table) { + const category = row[categoryField]; + const group = row[groupField]; + const value = Number(row[measureField]); + if (category == null || group == null || !Number.isFinite(value)) continue; + const key = `${String(category)}\u0000${String(group)}`; + totals.set(key, (totals.get(key) ?? 0) + value); + } + const valueAt = (category: unknown, group: unknown): number | null => { + const value = totals.get(`${String(category)}\u0000${String(group)}`); + return value === undefined ? null : value; + }; + const maximumValue = Math.max(0, ...totals.values()); + const { maximum, majorUnit } = niceMaximum(maximumValue); + const numberFormat = formatSpecToExcel(semantics[measureChannel]?.format); + const base = input.chart_spec.baseSize ?? { width: 560, height: 360 }; + + return { + schema: 'flint.excel.chart/v1', + kind: 'chart', + chartType: 'BarStacked', + title: `${measureField} by ${categoryField} and ${groupField}`, + seriesBy: 'Columns', + data: [ + [categoryField, ...groups.map(String)], + ...categories.map((category) => { + const leftValue = valueAt(category, groups[0]); + return [ + String(category), + leftValue === null ? null : -leftValue, + valueAt(category, groups[1]), + ]; + }), + ], + categoryAxis: { title: categoryField, reversePlotOrder: true }, + valueAxis: { + title: measureField, + numberFormat: absoluteNumberFormat(numberFormat), + minimumScale: -maximum, + maximumScale: maximum, + majorUnit, + }, + legend: { visible: true, position: 'Bottom' }, + seriesFormats: [{ color: '#4472C4' }, { color: '#C55A5A' }], + gapWidth: 45, + overlap: 100, + width: base.width, + height: base.height, + warnings: [], + _flint: { + flintType: 'Pyramid Chart', + categoryField, + measureField, + groupField, + groups: groups.map(String), + }, + }; + }, +}; \ No newline at end of file diff --git a/packages/flint-js/src/excel/templates/radar.ts b/packages/flint-js/src/excel/templates/radar.ts new file mode 100644 index 00000000..2be88dde --- /dev/null +++ b/packages/flint-js/src/excel/templates/radar.ts @@ -0,0 +1,111 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import type { ExcelTemplateDef } from './types'; + +function niceMaximum(value: number): number { + if (!(value > 0)) return 1; + const power = 10 ** Math.floor(Math.log10(value)); + const fraction = value / power; + const niceFraction = fraction <= 1 ? 1 + : fraction <= 2 ? 2 + : fraction <= 2.5 ? 2.5 + : fraction <= 5 ? 5 + : 10; + return niceFraction * power; +} + +export const excelRadarChartDef: ExcelTemplateDef = { + chart: 'Radar Chart', + channels: ['x', 'y', 'color'], + typeMapping: { vertical: 'RadarMarkers' }, + validate: ({ table, fieldOf, typeOf }) => { + if (!fieldOf('x') || typeOf('x') === 'quantitative' || typeOf('x') === 'temporal') { + return 'requires a categorical metric x field for a native Excel radar chart'; + } + if (!fieldOf('y') || typeOf('y') !== 'quantitative') { + return 'requires a quantitative y field for a native Excel radar chart'; + } + if (fieldOf('color') && (typeOf('color') === 'quantitative' || typeOf('color') === 'temporal')) { + return 'requires a discrete color field for native Excel radar series'; + } + if (fieldOf('column') || fieldOf('row')) { + return 'does not support faceting in one native Excel radar chart'; + } + const valueField = fieldOf('y')!; + if (table.some((row) => Number(row[valueField]) < 0)) { + return 'requires non-negative values for a native Excel radar chart'; + } + return undefined; + }, + instantiate: ({ input, table, fieldOf }) => { + const metricField = fieldOf('x')!; + const valueField = fieldOf('y')!; + const seriesField = fieldOf('color'); + const metrics = [...new Set(table.map((row) => String(row[metricField])))]; + if (metrics.length < 3) { + throw new Error('Excel radar chart requires at least three metric axes.'); + } + const seriesKeys = seriesField + ? [...new Set(table.map((row) => String(row[seriesField])))] + : [valueField]; + const metricMaximums = new Map(metrics.map((metric) => { + const values = table + .filter((row) => String(row[metricField]) === metric) + .map((row) => Number(row[valueField])) + .filter(Number.isFinite); + return [metric, niceMaximum(values.length > 0 ? Math.max(...values) : 1)] as const; + })); + const accumulators = new Map(); + for (const row of table) { + const metric = String(row[metricField]); + const series = seriesField ? String(row[seriesField]) : valueField; + const value = Number(row[valueField]); + if (!Number.isFinite(value)) continue; + const key = `${series}\u0000${metric}`; + const accumulator = accumulators.get(key) ?? { sum: 0, count: 0 }; + accumulator.sum += value; + accumulator.count += 1; + accumulators.set(key, accumulator); + } + const normalizedValue = (series: string, metric: string): number => { + const accumulator = accumulators.get(`${series}\u0000${metric}`); + if (!accumulator) return 0; + return (accumulator.sum / accumulator.count) / metricMaximums.get(metric)!; + }; + const base = input.chart_spec.baseSize ?? { width: 480, height: 400 }; + const filledRequested = input.chart_spec.chartProperties?.filled !== false; + return { + schema: 'flint.excel.chart/v1', + kind: 'chart', + chartType: 'RadarMarkers', + title: `${valueField} by ${metricField}`, + seriesBy: 'Columns', + data: [ + [metricField, ...seriesKeys], + ...metrics.map((metric) => [ + `${metric} (${metricMaximums.get(metric)})`, + ...seriesKeys.map((series) => normalizedValue(series, metric)), + ]), + ], + valueAxis: { minimumScale: 0, maximumScale: 1, majorUnit: 0.25 }, + legend: { visible: Boolean(seriesField), position: 'Bottom' }, + width: base.width, + height: base.height, + warnings: filledRequested ? [{ + severity: 'info', + code: 'excel-radar-fill-unsupported', + message: 'Excel Radar uses outlines and markers because Office.js does not expose translucent chart-series fills.', + }] : [], + _flint: { + flintType: 'Radar Chart', + metricField, + valueField, + seriesField, + metricMaximums: Object.fromEntries(metricMaximums), + normalized: true, + filledRequested, + }, + }; + }, +}; \ No newline at end of file diff --git a/packages/flint-js/src/excel/templates/scatter.ts b/packages/flint-js/src/excel/templates/scatter.ts new file mode 100644 index 00000000..62972b3e --- /dev/null +++ b/packages/flint-js/src/excel/templates/scatter.ts @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import type { ExcelTemplateDef } from './types'; +import { requireQuantitativeAxes } from './types'; + +export const excelScatterPlotDef: ExcelTemplateDef = { + chart: 'Scatter Plot', + channels: ['x', 'y', 'color', 'size'], + typeMapping: { vertical: 'XYScatter', xy: true }, + validate: (context) => requireQuantitativeAxes(context) + ?? (context.typeOf('color') === 'quantitative' || context.typeOf('color') === 'temporal' + ? 'does not support continuous color in a native Excel Scatter or Bubble chart' + : undefined), +}; + +export const excelConnectedScatterPlotDef: ExcelTemplateDef = { + chart: 'Connected Scatter Plot', + channels: ['x', 'y', 'order', 'color', 'detail'], + typeMapping: { vertical: 'XYScatterLines', xy: true }, + validate: (context) => requireQuantitativeAxes(context) + ?? (!context.fieldOf('order') + ? 'requires an explicit order field for a native Excel connected scatter chart' + : context.fieldOf('detail') + ? 'does not support an unlegended detail series in a native Excel connected scatter chart' + : context.typeOf('color') === 'quantitative' || context.typeOf('color') === 'temporal' + ? 'does not support continuous color in a native Excel connected scatter chart' + : undefined), +}; \ No newline at end of file diff --git a/packages/flint-js/src/excel/templates/sunburst.ts b/packages/flint-js/src/excel/templates/sunburst.ts new file mode 100644 index 00000000..57f18331 --- /dev/null +++ b/packages/flint-js/src/excel/templates/sunburst.ts @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import type { ExcelTemplateDef } from './types'; + +export const excelSunburstChartDef: ExcelTemplateDef = { + chart: 'Sunburst Chart', + channels: ['color', 'size', 'group', 'detail'], + typeMapping: { vertical: 'Sunburst', noAxes: true }, + validate: ({ table, fieldOf, typeOf }) => { + if (!fieldOf('color') || typeOf('color') === 'quantitative') { + return 'requires a categorical color field for a native Excel sunburst chart'; + } + if (typeOf('size') !== 'quantitative') { + return 'requires a quantitative size field for a native Excel sunburst chart'; + } + if (fieldOf('group') && typeOf('group') === 'quantitative') { + return 'requires a categorical group field for a native Excel sunburst hierarchy'; + } + if (fieldOf('detail') && !fieldOf('group')) { + return 'requires a group field before detail in a native Excel sunburst hierarchy'; + } + if (fieldOf('detail') && typeOf('detail') === 'quantitative') { + return 'requires a categorical detail field for a native Excel sunburst hierarchy'; + } + const valueField = fieldOf('size')!; + if (table.some((row) => Number.isFinite(Number(row[valueField])) && Number(row[valueField]) < 0)) { + return 'requires non-negative values for a native Excel sunburst chart'; + } + return undefined; + }, + instantiate: ({ input, table, fieldOf }) => { + const categoryField = fieldOf('color')!; + const groupField = fieldOf('group'); + const detailField = fieldOf('detail'); + const valueField = fieldOf('size')!; + const hierarchyFields = [categoryField, groupField, detailField].filter((field): field is string => Boolean(field)); + const leaves = new Map(); + for (const row of table) { + const path = hierarchyFields.map((field) => row[field]); + const value = Number(row[valueField]); + if (path.some((part) => part == null) || !Number.isFinite(value)) continue; + const labels = path.map(String); + const key = labels.join('\u0000'); + const existing = leaves.get(key); + leaves.set(key, { path: labels, value: (existing?.value ?? 0) + value }); + } + + const base = input.chart_spec.baseSize ?? { width: 480, height: 320 }; + return { + schema: 'flint.excel.chart/v1', + kind: 'chart', + chartType: 'Sunburst', + title: `${valueField} by ${hierarchyFields[hierarchyFields.length - 1]}`, + seriesBy: 'Columns', + data: [ + [...hierarchyFields, valueField], + ...[...leaves.values()].map((leaf) => [...leaf.path, leaf.value]), + ], + legend: { visible: false }, + width: base.width, + height: base.height, + warnings: [], + _flint: { flintType: 'Sunburst Chart', hierarchyFields, valueField }, + }; + }, +}; \ No newline at end of file diff --git a/packages/flint-js/src/excel/templates/treemap.ts b/packages/flint-js/src/excel/templates/treemap.ts new file mode 100644 index 00000000..d604a228 --- /dev/null +++ b/packages/flint-js/src/excel/templates/treemap.ts @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import type { ExcelTemplateDef } from './types'; + +export const excelTreemapDef: ExcelTemplateDef = { + chart: 'Treemap', + channels: ['color', 'size', 'detail'], + typeMapping: { vertical: 'Treemap', noAxes: true }, + validate: ({ table, fieldOf, typeOf }) => { + if (!fieldOf('color') || typeOf('color') === 'quantitative') { + return 'requires a categorical color field for a native Excel treemap'; + } + if (typeOf('size') !== 'quantitative') { + return 'requires a quantitative size field for a native Excel treemap'; + } + if (fieldOf('detail') && typeOf('detail') === 'quantitative') { + return 'requires a categorical detail field for a native Excel treemap hierarchy'; + } + const valueField = fieldOf('size')!; + if (table.some((row) => Number.isFinite(Number(row[valueField])) && Number(row[valueField]) < 0)) { + return 'requires non-negative values for a native Excel treemap'; + } + return undefined; + }, + instantiate: ({ input, table, fieldOf }) => { + const categoryField = fieldOf('color')!; + const detailField = fieldOf('detail'); + const valueField = fieldOf('size')!; + const leaves = new Map(); + for (const row of table) { + const category = row[categoryField]; + const detail = detailField ? row[detailField] : undefined; + const value = Number(row[valueField]); + if (category == null || (detailField && detail == null) || !Number.isFinite(value)) continue; + const categoryLabel = String(category); + const detailLabel = detailField ? String(detail) : undefined; + const key = `${categoryLabel}\u0000${detailLabel ?? ''}`; + const existing = leaves.get(key); + leaves.set(key, { + category: categoryLabel, + detail: detailLabel, + value: (existing?.value ?? 0) + value, + }); + } + + const rows = [...leaves.values()]; + const base = input.chart_spec.baseSize ?? { width: 480, height: 320 }; + return { + schema: 'flint.excel.chart/v1', + kind: 'chart', + chartType: 'Treemap', + title: `${valueField} by ${detailField ?? categoryField}`, + seriesBy: 'Columns', + data: detailField + ? [[categoryField, detailField, valueField], ...rows.map((row) => [row.category, row.detail!, row.value])] + : [[categoryField, valueField], ...rows.map((row) => [row.category, row.value])], + legend: { visible: false }, + width: base.width, + height: base.height, + warnings: [], + _flint: { flintType: 'Treemap', categoryField, detailField, valueField }, + }; + }, +}; \ No newline at end of file diff --git a/packages/flint-js/src/excel/templates/types.ts b/packages/flint-js/src/excel/templates/types.ts new file mode 100644 index 00000000..e7b5f0a4 --- /dev/null +++ b/packages/flint-js/src/excel/templates/types.ts @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import type { ChartAssemblyInput, SemanticResult } from '../../core/types'; +import type { ExcelTypeMapping } from '../chart-types'; +import type { ExcelNativeChartSpec } from '../types'; + +export interface ExcelTemplateContext { + input: ChartAssemblyInput; + table: any[]; + semantics: SemanticResult; + fieldOf: (channel: string) => string | undefined; + typeOf: (channel: string) => string | undefined; +} + +export interface ExcelTemplateDef { + chart: string; + channels: string[]; + typeMapping: ExcelTypeMapping; + validate?: (context: ExcelTemplateContext) => string | undefined; + instantiate?: (context: ExcelTemplateContext) => ExcelNativeChartSpec; +} + +export function requireQuantitativeAxes(context: ExcelTemplateContext): string | undefined { + if (context.typeOf('x') !== 'quantitative' || context.typeOf('y') !== 'quantitative') { + return 'requires quantitative x and y fields for a native Excel XY chart'; + } + if (context.fieldOf('shape')) { + return 'does not support a shape encoding in native Excel charts'; + } + return undefined; +} \ No newline at end of file diff --git a/packages/flint-js/src/excel/templates/waterfall.ts b/packages/flint-js/src/excel/templates/waterfall.ts new file mode 100644 index 00000000..f368565c --- /dev/null +++ b/packages/flint-js/src/excel/templates/waterfall.ts @@ -0,0 +1,68 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { resolveTotalsMode } from '../../chart-types/waterfall'; +import { formatSpecToExcel } from '../chart-types'; +import type { ExcelTemplateDef } from './types'; + +export const excelWaterfallChartDef: ExcelTemplateDef = { + chart: 'Waterfall Chart', + channels: ['x', 'y', 'color'], + typeMapping: { vertical: 'Waterfall' }, + validate: ({ input, table, fieldOf, typeOf }) => { + if (!fieldOf('x')) return 'requires a category x field for a native Excel waterfall chart'; + if (typeOf('y') !== 'quantitative') { + return 'requires a quantitative y field for a native Excel waterfall chart'; + } + if (fieldOf('color') && typeOf('color') === 'quantitative') { + return 'requires color to contain start/delta/end roles for a native Excel waterfall chart'; + } + const valueField = fieldOf('y')!; + const typeField = fieldOf('color'); + const values = table.map((row) => Number(row[valueField])).filter(Number.isFinite); + if (typeField) { + const unsupportedTotal = table.findIndex((row, index) => { + const role = String(row[typeField] ?? '').toLowerCase(); + return index > 0 && (role === 'start' || role === 'end' || role === 'total'); + }); + if (unsupportedTotal >= 0) { + return 'cannot mark non-initial total points because Office.js does not expose Waterfall total-point semantics'; + } + } else { + const totals = resolveTotalsMode(values, input.chart_spec.chartProperties?.totals); + if (totals === 'last' || totals === 'both') { + return 'cannot mark a final total because Office.js does not expose Waterfall total-point semantics'; + } + } + return undefined; + }, + instantiate: ({ input, table, semantics, fieldOf }) => { + const categoryField = fieldOf('x')!; + const valueField = fieldOf('y')!; + const rows = table.filter((row) => row[categoryField] != null && Number.isFinite(Number(row[valueField]))); + + const base = input.chart_spec.baseSize ?? { width: 480, height: 320 }; + return { + schema: 'flint.excel.chart/v1', + kind: 'chart', + chartType: 'Waterfall', + title: `${valueField} by ${categoryField}`, + seriesBy: 'Columns', + data: [ + [categoryField, valueField], + ...rows.map((row) => [String(row[categoryField]), Number(row[valueField])]), + ], + categoryAxis: { title: categoryField }, + valueAxis: { + title: valueField, + numberFormat: formatSpecToExcel(semantics.y?.format), + }, + legend: { visible: false }, + showConnectorLines: true, + width: base.width, + height: base.height, + warnings: [], + _flint: { flintType: 'Waterfall Chart', categoryField, valueField }, + }; + }, +}; \ No newline at end of file diff --git a/packages/flint-js/src/excel/types.ts b/packages/flint-js/src/excel/types.ts new file mode 100644 index 00000000..8d236eb5 --- /dev/null +++ b/packages/flint-js/src/excel/types.ts @@ -0,0 +1,140 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Excel backend types. + * + * The Excel "native spec" is a declarative description of an Office.js chart: + * a wide/matrix data range plus chart type, axes, legend, and series config. + * A host renders it imperatively via the Office.js Excel API + * (`sheet.charts.add(type, range, seriesBy)` + `chart.getImage()`). + * + * This mirrors how the other backends emit a native artifact (Vega-Lite spec, + * ECharts option, Chart.js config) — here the artifact targets Excel charts. + */ + +import type { ChartWarning } from '../core/types'; + +/** Excel `ChartSeriesBy` orientation. */ +export type ExcelSeriesBy = 'Columns' | 'Rows'; + +/** Excel `ChartLegendPosition` (subset we emit). */ +export type ExcelLegendPosition = 'Top' | 'Bottom' | 'Left' | 'Right'; + +export interface ExcelAxisSpec { + /** Axis title text (from the field display name). */ + title?: string; + /** Axis-label font size in points, used when dense categories need explicit sizing. */ + labelFontSize?: number; + /** Number of categories between displayed labels; underlying data stays intact. */ + tickLabelSpacing?: number; + /** Excel number format string, e.g. `"$#,##0"`, `"0.0%"`, `"#,##0"`. */ + numberFormat?: string; + /** Reverse Excel's native category plotting order (horizontal nominal bars). */ + reversePlotOrder?: boolean; + /** Explicit native-axis minimum, used for zero-anchored length/area charts. */ + minimumScale?: number; + /** Explicit native-axis maximum, used to avoid excessive automatic headroom. */ + maximumScale?: number; + /** Interval between major ticks on a numeric axis. */ + majorUnit?: number; +} + +export interface ExcelLegendSpec { + visible: boolean; + position?: ExcelLegendPosition; +} + +export interface ExcelDataLabelsSpec { + visible: boolean; + position?: 'BestFit' | 'Center' | 'InsideBase' | 'InsideEnd' | 'OutsideEnd'; + numberFormat?: string; + fontColor?: string; + fontSize?: number; +} + +export interface ExcelNativeSeriesSpec { + /** Legend/series name. */ + name: string; + /** Zero-based worksheet column containing X values, excluding the header row. */ + xColumn: number; + /** Zero-based worksheet column containing Y values, excluding the header row. */ + yColumn: number; + /** Number of populated worksheet rows in this series. */ + rowCount: number; + /** Optional zero-based worksheet column containing bubble sizes. */ + bubbleSizeColumn?: number; +} + +export interface ExcelNativeSeriesFormatSpec { + /** Native HTML color shared by related series segments. */ + color?: string; + /** Excel.ChartLineStyle string. */ + lineStyle?: 'Continuous' | 'Dash' | 'DashDot' | 'DashDotDot' | 'Dot' | 'RoundDot'; +} + +export interface ExcelBoxWhiskerOptionsSpec { + quartileCalculation?: 'Inclusive' | 'Exclusive'; + showInnerPoints?: boolean; + showMeanLine?: boolean; + showMeanMarker?: boolean; + showOutlierPoints?: boolean; +} + +interface ExcelRenderSpecBase { + /** Stable discriminator for serialized Flint Excel artifacts. */ + schema: 'flint.excel.chart/v1'; + /** Chart title. */ + title?: string; + /** Source values written to the worksheet. */ + data: Array>; + /** Target width/height in points (from Flint layout / baseSize). */ + width?: number; + height?: number; + /** Flint assembler warnings (overflow, etc.). */ + warnings?: ChartWarning[]; + /** Provenance for debugging (not consumed by the renderer). */ + _flint?: Record; +} + +/** A conventional native Excel chart rendered through `Chart.getImage()`. */ +export interface ExcelNativeChartSpec extends ExcelRenderSpecBase { + kind: 'chart'; + /** + * The Office.js `Excel.ChartType` enum string, e.g. `"ColumnClustered"`, + * `"BarStacked"`, `"Line"`, `"XYScatter"`, `"Pie"`. + */ + chartType: string; + /** Whether series run down columns or across rows of the data range. */ + seriesBy: ExcelSeriesBy; + /** Explicit bindings for XY/bubble series when Excel cannot infer grouped ranges. */ + series?: ExcelNativeSeriesSpec[]; + /** Formatting aligned with the rendered series order. */ + seriesFormats?: ExcelNativeSeriesFormatSpec[]; + /** Category (label) axis. Absent for pie/doughnut (no axes). */ + categoryAxis?: ExcelAxisSpec; + /** Value (measure) axis. Absent for pie/doughnut. */ + valueAxis?: ExcelAxisSpec; + /** Legend visibility + position. */ + legend?: ExcelLegendSpec; + /** Native chart data labels. */ + dataLabels?: ExcelDataLabelsSpec; + /** Bar/column gap width (%) — bar family only. */ + gapWidth?: number; + /** Bar/column series overlap (%) — 2-D bar family only. */ + overlap?: number; + /** Excel bubble-size percentage (0-300), applied to every bubble series. */ + bubbleScale?: number; + /** Doughnut hole size percentage (10-90), applied to every doughnut series. */ + doughnutHoleSize?: number; + /** Statistical options applied to every native box-and-whisker series. */ + boxWhiskerOptions?: ExcelBoxWhiskerOptionsSpec; + /** Display native connector lines between Waterfall points. */ + showConnectorLines?: boolean; +} + +/** A backend-native Excel chart artifact. */ +export type ExcelChartSpec = ExcelNativeChartSpec; + +/** Preferred name for the backend artifact; retained alongside ExcelChartSpec. */ +export type ExcelRenderSpec = ExcelChartSpec; diff --git a/packages/flint-js/src/gallery/bi-tests.ts b/packages/flint-js/src/gallery/bi-tests.ts index 5c702c20..98270f71 100644 --- a/packages/flint-js/src/gallery/bi-tests.ts +++ b/packages/flint-js/src/gallery/bi-tests.ts @@ -22,6 +22,7 @@ import { Type } from '../test-data/df-types'; import { TestCase, makeField, makeEncodingItem } from '../test-data/types'; +import { realKpiCases } from '../test-data/real-world-tests'; export function genGalleryKpiCardTests(): TestCase[] { return [ @@ -190,5 +191,6 @@ export function genGalleryKpiCardTests(): TestCase[] { }, chartProperties: { layout: 'vertical' }, }, + ...realKpiCases(), ]; } diff --git a/packages/flint-js/src/index.ts b/packages/flint-js/src/index.ts index 5f121268..824f9746 100644 --- a/packages/flint-js/src/index.ts +++ b/packages/flint-js/src/index.ts @@ -14,6 +14,7 @@ * vegalite/ — Vega-Lite backend: assembly, templates, spec instantiation * echarts/ — ECharts backend: assembly, templates, spec instantiation * chartjs/ — Chart.js backend: assembly, templates, spec instantiation + * plotly/ — Plotly backend: assembly, templates, spec instantiation * * Assembly functions: * assembleVegaLite(input) — Vega-Lite spec @@ -52,3 +53,7 @@ export * from './echarts'; // Chart.js backend: assembleChartjs, templates, spec instantiation export * from './chartjs'; +export * from './plotly'; + +// Excel backend: assembleExcel + Excel chart spec types +export * from './excel'; diff --git a/packages/flint-js/src/plotly/assemble.ts b/packages/flint-js/src/plotly/assemble.ts new file mode 100644 index 00000000..870037c5 --- /dev/null +++ b/packages/flint-js/src/plotly/assemble.ts @@ -0,0 +1,398 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly chart assembly — Two-Stage Pipeline Coordinator. + * + * Reuses the **same core analysis pipeline** as the other backends: + * Phase 0: resolveChannelSemantics → ChannelSemantics + * Step 0a: declareLayoutMode → LayoutDeclaration + * Step 0b: convertTemporalData → converted data + * Step 0c: filterOverflow → filtered data, nominalCounts + * Phase 1: computeLayout → LayoutResult + * + * Then diverges for Phase 2 (Plotly-specific): + * template.instantiate → builds the Plotly figure structure + * plApplyLayoutToSpec → applies layout decisions to the figure + * + * Key structural difference from the other backends' output: + * PL: { data: [{ type, x, y, … }], layout: { xaxis, yaxis, … } } + * Figures are pure JSON — no callback functions anywhere — so compiled + * specs survive serialization across process boundaries. + * + * column/row facets render as a subplot grid (see facet.ts), mirroring the + * Chart.js backend's facet decisions (shared nice y-domain, leftmost-only + * y labels, column wrapping). + * + * This module has NO React, Redux, or UI framework dependencies. + */ + +import { + ChartTemplateDef, + ChartAssemblyInput, + AssembleOptions, + LayoutDeclaration, + InstantiateContext, +} from '../core/types'; +import type { ChartWarning, ChartEncoding } from '../core/types'; +import { applyEncodingOverrides } from '../core/encoding-overrides'; +import { applyAggregation } from '../core/aggregate'; +import { plGetTemplateDef } from './templates'; +import { resolveChannelSemantics, convertTemporalData } from '../core/resolve-semantics'; +import { computeZeroDecision } from '../core/semantic-types'; +import { filterOverflow } from '../core/filter-overflow'; +import { computeLayout, computeChannelBudgets, deriveStretchCaps, resolveBaseSize, resolveFacetColumnsOption } from '../core/compute-layout'; +import { decideColorMaps } from '../core/color-decisions'; +import { plApplyCartesianAxisSpacing, plApplyLayoutToSpec, plApplyTooltips, plApplyAxisProperties } from './instantiate-spec'; +import { plCombineFacetPanels, niceBounds, type PlotlyFacetPanel } from './facet'; +import { normalizeStaticSeries } from '../core/static-series'; +import { normalizeChartProperties } from '../core/normalize-properties'; + +// --------------------------------------------------------------------------- +// Public API +// --------------------------------------------------------------------------- +/** + * Assemble a Plotly figure object (`{ data, layout }`). + * + * ```ts + * const figure = assemblePlotly({ + * data: { values: myRows }, + * semantic_types: { weight: 'Quantity' }, + * chart_spec: { chartType: 'Bar Chart', encodings: { x: { field: 'category' }, y: { field: 'value' } } }, + * }); + * ``` + * + * @returns A Plotly figure with optional `_warnings` and `_width`/`_height` hints + */ +export function assemblePlotly(input: ChartAssemblyInput): any { + const chartType = input.chart_spec.chartType; + const semanticTypes = input.semantic_types ?? {}; + const sizeCeiling = input.chart_spec.canvasSize; + const baseSize = resolveBaseSize(input.chart_spec.baseSize, sizeCeiling); + const canvasSize = baseSize; + const options = input.options ?? {}; + const chartTemplate = plGetTemplateDef(chartType) as ChartTemplateDef; + if (!chartTemplate) { + throw new Error(`Unknown Plotly chart type: ${chartType}. Use plAllTemplateDefs to see available types.`); + } + + const warnings: ChartWarning[] = []; + + const normalizedProps = normalizeChartProperties( + chartTemplate.properties, input.chart_spec.chartProperties, + ); + const chartProperties = normalizedProps.chartProperties; + warnings.push(...normalizedProps.warnings); + + // ═══════════════════════════════════════════════════════════════════════ + // PRE-PHASE: Static Series Normalization + // ═══════════════════════════════════════════════════════════════════════ + const rawData = input.data.values ?? []; + const normalized = normalizeStaticSeries( + input.chart_spec.encodings, rawData, semanticTypes, + ); + let data = normalized.data; + const staticSeries = normalized.staticSeries; + + // Enrich raw encodings with their resolved semantic `type` BEFORE applying + // encoding actions (Sort, …) — an action like Sort must know which position + // channel is the measure (quantitative), which lives in the resolved + // semantics, not the bare field binding. Mirrors the VL assembler's + // `typedRawEncodings` step (a cheap preliminary semantics pass). + const prelimConverted = convertTemporalData(data, semanticTypes); + const prelimSemantics = resolveChannelSemantics( + normalized.encodings, data, semanticTypes, prelimConverted, + ); + const typedRawEncodings: Record = {}; + for (const [ch, enc] of Object.entries(normalized.encodings)) { + typedRawEncodings[ch] = enc.type ? enc : { ...enc, type: prelimSemantics[ch]?.type }; + } + const encodings = applyEncodingOverrides(chartTemplate, typedRawEncodings, chartProperties); + + // Optional aggregation transform — see vegalite/assemble for rationale. + data = applyAggregation(encodings, data); + + // ═══════════════════════════════════════════════════════════════════════ + // PHASE 0: Resolve Semantics (shared — completely target-agnostic) + // ═══════════════════════════════════════════════════════════════════════ + + const tplMark = chartTemplate.template?.mark; + const templateMarkType = typeof tplMark === 'string' ? tplMark : tplMark?.type; + + const convertedData = convertTemporalData(data, semanticTypes); + + const channelSemantics = resolveChannelSemantics( + encodings, data, semanticTypes, convertedData, + ); + + // Finalize zero-baseline (requires template mark knowledge) + const effectiveMarkType = templateMarkType || 'point'; + for (const [channel, cs] of Object.entries(channelSemantics)) { + if ((channel === 'x' || channel === 'y') && cs.type === 'quantitative') { + const numericValues = data + .map(r => r[cs.field]) + .filter((v: any) => v != null && typeof v === 'number' && !isNaN(v)); + cs.zero = computeZeroDecision( + cs.semanticAnnotation.semanticType, channel, effectiveMarkType, numericValues, + ); + } + } + + // ═══════════════════════════════════════════════════════════════════════ + // STEP 0a: declareLayoutMode (shared hook) + // ═══════════════════════════════════════════════════════════════════════ + + const declaration: LayoutDeclaration = chartTemplate.declareLayoutMode + ? chartTemplate.declareLayoutMode(channelSemantics, data, chartProperties) + : {}; + + const effectiveOptions: AssembleOptions = { + // Plotly fills its plot area natively (bars sized by `bargap`), so sparse + // categories spread out. Allow bands to expand well past the base size, + // matching Plotly's official low-cardinality bar style, but cap it so one + // or two bars don't span the whole canvas. + maxBandSize: 100, + // Plotly native font defaults (ticks/legend 12, axis titles 14). + baseLabelFontSize: 12, + baseTitleFontSize: 14, + ...options, + ...(declaration.paramOverrides || {}), + }; + + Object.assign(effectiveOptions, deriveStretchCaps(baseSize, sizeCeiling, effectiveOptions)); + effectiveOptions.facetColumns = resolveFacetColumnsOption(input.chart_spec.chartProperties); + + const { + addTooltips: addTooltipsOpt = false, + } = effectiveOptions; + + // ═══════════════════════════════════════════════════════════════════════ + // STEP 0b: filterOverflow (shared) + // ═══════════════════════════════════════════════════════════════════════ + + const allMarkTypes = new Set(); + if (templateMarkType) allMarkTypes.add(templateMarkType); + + const budgets = computeChannelBudgets( + channelSemantics, declaration, convertedData, canvasSize, effectiveOptions, + ); + const facetGridResult = budgets.facetGrid; + + const overflowResult = filterOverflow( + channelSemantics, declaration, encodings, convertedData, + budgets, allMarkTypes, + ); + + const values = overflowResult.filteredData; + warnings.push(...overflowResult.warnings); + + // ═══════════════════════════════════════════════════════════════════════ + // PHASE 1: Compute Layout (shared — completely target-agnostic) + // ═══════════════════════════════════════════════════════════════════════ + + const layoutResult = computeLayout( + channelSemantics, + declaration, + values, + canvasSize, + effectiveOptions, + facetGridResult, + ); + + layoutResult.truncations = overflowResult.truncations; + + // ═══════════════════════════════════════════════════════════════════════ + // PHASE 2: Instantiate Plotly Figure (PL-specific) + // ═══════════════════════════════════════════════════════════════════════ + + const resolvedEncodings: Record = {}; + for (const [channel, encoding] of Object.entries(encodings)) { + const cs = channelSemantics[channel]; + if (cs) { + resolvedEncodings[channel] = { + field: cs.field, + type: cs.type, + aggregate: encoding.aggregate, + }; + } + } + + const instantiateContext: InstantiateContext = { + channelSemantics, + layout: layoutResult, + table: values, + fullTable: convertedData, + resolvedEncodings, + encodings, + chartProperties, + staticSeries, + canvasSize, + semanticTypes, + chartType, + assembleOptions: effectiveOptions, + colorDecisions: decideColorMaps({ + chartType, + encodings, + channelSemantics, + table: values, + background: 'light', + }), + }; + + const colField = channelSemantics.column?.field; + const rowField = channelSemantics.row?.field; + // Multi-panel faceting only applies to axis-based (cartesian) templates. + // Axis-less charts (Pie, Donut, Radar, Rose, Gauge, Funnel, KPI Card) use + // `column` (when they declare it at all) for their own internal grouping + // — e.g. one gauge dial per column value — and lay that out themselves, + // exactly mirroring the ECharts backend's `hasAxes` gate. + const hasAxes = chartTemplate.channels.includes('x') || chartTemplate.channels.includes('y'); + // A template can also opt out explicitly (`selfManagesFacets`) even though + // it DOES declare x/y — composite multi-panel layouts (Sparkline, Bar + // Table) already span several internal axis pairs of their own, so the + // generic single-axis-pair-per-panel combiner (`facet.ts`) cannot safely + // recombine N pre-split instantiations of them. These templates read + // `column`/`row` straight off `channelSemantics` themselves instead. + const hasFacet = !!(colField || rowField) && hasAxes && !chartTemplate.selfManagesFacets; + + let figure: any; + if (hasFacet) { + const colValues = colField ? [...new Set(values.map((r: any) => String(r[colField])))] : ['']; + const rowValues = rowField ? [...new Set(values.map((r: any) => String(r[rowField])))] : ['']; + + // Shared y-domain across panels (mirror the Chart.js backend): nice + // bounds so the shared top/bottom land on round tick values. + const yField = channelSemantics.y?.field; + let sharedYDomain: { min: number; max: number } | undefined; + if (yField) { + const nums = values + .map((r: any) => r[yField]) + .filter((v: any) => typeof v === 'number' && Number.isFinite(v)) as number[]; + if (nums.length > 0) { + const rawMin = Math.min(...nums); + const rawMax = Math.max(...nums); + const forceZero = !!channelSemantics.y?.zero?.zero; + const min = forceZero ? Math.min(0, rawMin) : rawMin; + const max = forceZero ? Math.max(0, rawMax) : rawMax; + sharedYDomain = niceBounds(min, max); + } + } + + // Column wrapping: a column-only facet with more categories than fit + // in one row wraps into a 2D grid (matching the other backends). The + // wrap width comes from the shared facet-grid budget. + const maxColsPerRow = (colField && !rowField) + ? (facetGridResult?.columns ?? colValues.length) + : colValues.length; + const wrapColumnOnly = !!colField && !rowField && maxColsPerRow < colValues.length; + + const gridRows: Array> = []; + if (wrapColumnOnly) { + for (let i = 0; i < colValues.length; i += maxColsPerRow) { + gridRows.push( + colValues.slice(i, i + maxColsPerRow).map((cv) => ({ colVal: cv, rowVal: '' })), + ); + } + } else { + for (let ri = 0; ri < rowValues.length; ri++) { + gridRows.push(colValues.map((cv) => ({ colVal: cv, rowVal: rowValues[ri] }))); + } + } + const gridCols = Math.max(1, ...gridRows.map(r => r.length)); + + // Panel plot size — same discrete/continuous rules as plApplyLayoutToSpec. + const xIsDiscrete = layoutResult.xNominalCount > 0 || layoutResult.xContinuousAsDiscrete > 0; + const yIsDiscrete = layoutResult.yNominalCount > 0 || layoutResult.yContinuousAsDiscrete > 0; + let panelWidth: number; + let panelHeight: number; + if (xIsDiscrete && layoutResult.xStepUnit !== 'group') { + const n = layoutResult.xNominalCount || layoutResult.xContinuousAsDiscrete || 0; + panelWidth = n > 0 ? layoutResult.xStep * n : (layoutResult.subplotWidth || canvasSize.width); + } else { + panelWidth = layoutResult.subplotWidth || canvasSize.width; + } + if (yIsDiscrete && layoutResult.yStepUnit !== 'group') { + const n = layoutResult.yNominalCount || layoutResult.yContinuousAsDiscrete || 0; + panelHeight = n > 0 ? layoutResult.yStep * n : (layoutResult.subplotHeight || canvasSize.height); + } else { + panelHeight = layoutResult.subplotHeight || canvasSize.height; + } + + const panels: PlotlyFacetPanel[] = []; + for (let ri = 0; ri < gridRows.length; ri++) { + const cells = gridRows[ri]; + for (let ci = 0; ci < cells.length; ci++) { + const { colVal, rowVal } = cells[ci]; + const panelData = values.filter((r: any) => { + if (colField && String(r[colField]) !== colVal) return false; + if (rowField && String(r[rowField]) !== rowVal) return false; + return true; + }); + + const panelFigure: any = structuredClone(chartTemplate.template); + const panelContext: InstantiateContext = { + ...instantiateContext, + table: panelData, + }; + chartTemplate.instantiate(panelFigure, panelContext); + if (chartTemplate.postProcess) chartTemplate.postProcess(panelFigure, panelContext); + + panels.push({ + rowIndex: ri, + colIndex: ci, + rowHeader: rowField ? rowVal : undefined, + colHeader: colField ? colVal : undefined, + figure: panelFigure, + }); + } + } + + figure = plCombineFacetPanels(panels, { + rows: gridRows.length, + cols: gridCols, + panelWidth, + panelHeight, + sharedYDomain, + hasColHeader: !!colField, + hasRowHeader: !!rowField, + colHeaderPerRow: wrapColumnOnly, + showLegend: !!channelSemantics.color?.field, + }); + + // Apply the shared x-label rotation / font decisions to every panel axis. + if (layoutResult.xLabel) { + for (const key of Object.keys(figure.layout)) { + if (!/^xaxis\d*$/.test(key)) continue; + const ax = figure.layout[key]; + if (layoutResult.xLabel.labelAngle) { + ax.tickangle = Math.abs(layoutResult.xLabel.labelAngle); + } + if (layoutResult.xLabel.fontSize) { + ax.tickfont = { ...(ax.tickfont || {}), size: layoutResult.xLabel.fontSize }; + } + } + } + plApplyCartesianAxisSpacing(figure); + plApplyAxisProperties(figure, instantiateContext); + if (addTooltipsOpt) plApplyTooltips(figure); + } else { + figure = structuredClone(chartTemplate.template); + chartTemplate.instantiate(figure, instantiateContext); + plApplyLayoutToSpec(figure, instantiateContext, warnings); + plApplyAxisProperties(figure, instantiateContext); + if (addTooltipsOpt) plApplyTooltips(figure); + if (chartTemplate.postProcess) chartTemplate.postProcess(figure, instantiateContext); + } + + // ═══════════════════════════════════════════════════════════════════════ + // RESULT + // ═══════════════════════════════════════════════════════════════════════ + + if (warnings.length > 0) { + figure._warnings = warnings; + } + + figure._dataLength = values.length; + + return figure; +} diff --git a/packages/flint-js/src/plotly/colormap.ts b/packages/flint-js/src/plotly/colormap.ts new file mode 100644 index 00000000..54afa6d3 --- /dev/null +++ b/packages/flint-js/src/plotly/colormap.ts @@ -0,0 +1,160 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// Plotly 专用调色板定义。 +// 承接 core/color-decisions.ts 中的抽象 colormap 信息(schemeType / schemeId / categoryCount), +// 但真正的颜色数组与选盘策略完全在 Plotly backend 本地实现,并尽量贴近 Plotly 默认配色。 + +import type { ColorDecision, ColorMapType } from '../core/color-decisions'; + +export type PlotlyPaletteId = 'plotly10' | 'light24' | 'viridis' | 'RdBu' | string; + +export interface PlotlyColorMapDef { + id: PlotlyPaletteId; + type: ColorMapType; + supportsDiscrete: boolean; + supportsContinuous: boolean; + background: 'light' | 'dark' | 'any'; + colorblindSafe?: boolean; + maxCategories?: number; + diverging?: boolean; + preferredMidpoint?: number; + colors: string[]; +} + +/** + * Plotly 常用的基础配色。plotly10 即 plotly.js 默认 `layout.colorway`; + * light24 对应 px.colors.qualitative.Light24 的前 20 色,用于高基数类别。 + */ +const PLOTLY_COLOR_MAPS: PlotlyColorMapDef[] = [ + { + id: 'plotly10', + type: 'categorical', + supportsDiscrete: true, + supportsContinuous: false, + background: 'any', + maxCategories: 10, + colorblindSafe: false, + colors: [ + '#636efa', // blue-violet + '#EF553B', // red-orange + '#00cc96', // green + '#ab63fa', // purple + '#FFA15A', // orange + '#19d3f3', // cyan + '#FF6692', // pink + '#B6E880', // light green + '#FF97FF', // magenta + '#FECB52', // yellow + ], + }, + { + id: 'light24', + type: 'categorical', + supportsDiscrete: true, + supportsContinuous: false, + background: 'light', + maxCategories: 24, + colorblindSafe: false, + colors: [ + '#FD3216', '#00FE35', '#6A76FC', '#FED4C4', '#FE00CE', + '#0DF9FF', '#F6F926', '#FF9616', '#479B55', '#EEA6FB', + '#DC587D', '#D626FF', '#6E899C', '#00B5F7', '#B68E00', + '#C9FBE5', '#FF0092', '#22FFA7', '#E3EE9E', '#86CE00', + '#BC7196', '#7E7DCD', '#FC6955', '#E48F72', + ], + }, + { + id: 'viridis', + type: 'sequential', + supportsDiscrete: true, + supportsContinuous: true, + background: 'any', + colorblindSafe: true, + colors: [ + '#440154', '#46327e', '#365c8d', '#277f8e', + '#1fa187', '#4ac16d', '#a0da39', '#fde725', + ], + }, + { + id: 'RdBu', + type: 'diverging', + supportsDiscrete: true, + supportsContinuous: true, + background: 'any', + diverging: true, + preferredMidpoint: 0, + colors: [ + '#b2182b', '#d6604d', '#f4a582', '#fddbc7', + '#f7f7f7', + '#d1e5f0', '#92c5de', '#4393c3', '#2166ac', + ], + }, +]; + +function getMapById(id: PlotlyPaletteId | undefined): PlotlyColorMapDef | undefined { + if (!id) return undefined; + const key = String(id).toLowerCase(); + return PLOTLY_COLOR_MAPS.find(m => m.id.toLowerCase() === key); +} + +export function getPaletteForScheme(id: PlotlyPaletteId): string[] | undefined { + const entry = getMapById(id); + return entry?.colors; +} + +/** + * Plotly 侧的「选盘」函数:等价于 chartjs/colormap.ts 的 pickChartJsPalette。 + * + * 策略: + * 1)若用户显式指定了 schemeId,则优先按该 id 取 palette。 + * 2)否则根据 schemeType + categoryCount 自动挑选合适的盘: + * - categorical:按类别数量在 plotly10 / light24 之间选; + * - sequential:优先 viridis; + * - diverging :优先 RdBu。 + * 3)若都无法命中,回退到 Plotly 默认 categorical palette(plotly10)。 + */ +export function pickPlotlyPalette(decision: ColorDecision | undefined): string[] { + if (!decision) { + const fallback = getPaletteForScheme('plotly10'); + return fallback && fallback.length ? fallback : []; + } + + const { schemeType, schemeId, categoryCount } = decision; + + if (schemeId) { + const fromId = getPaletteForScheme(schemeId); + if (fromId && fromId.length > 0) { + return fromId; + } + } + + const mapsOfType = PLOTLY_COLOR_MAPS.filter(m => m.type === schemeType); + + if (schemeType === 'categorical') { + const k = categoryCount ?? 0; + const candidates = mapsOfType.filter(m => m.supportsDiscrete); + if (candidates.length) { + const byCapacity = candidates + .filter(m => m.maxCategories == null || m.maxCategories >= k) + .sort((a, b) => (a.maxCategories ?? Infinity) - (b.maxCategories ?? Infinity)); + const picked = byCapacity[0] ?? candidates[0]; + if (picked.colors.length) { + return picked.colors; + } + } + } else if (schemeType === 'sequential') { + const seq = mapsOfType.find(m => m.supportsContinuous) ?? getMapById('viridis'); + if (seq && seq.colors.length) { + return seq.colors; + } + } else if (schemeType === 'diverging') { + const divergingFirst = mapsOfType.find(m => m.diverging) ?? getMapById('RdBu'); + if (divergingFirst && divergingFirst.colors.length) { + return divergingFirst.colors; + } + } + + const fallback = getPaletteForScheme('plotly10'); + return fallback && fallback.length ? fallback : []; +} diff --git a/packages/flint-js/src/plotly/facet.ts b/packages/flint-js/src/plotly/facet.ts new file mode 100644 index 00000000..fe2a6ebe --- /dev/null +++ b/packages/flint-js/src/plotly/facet.ts @@ -0,0 +1,216 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly facet grid assembly. + * + * Combines per-panel figures (one template instantiation per column/row cell) + * into a single Plotly figure using per-panel axis pairs (`xaxis`/`xaxis2`/…) + * with explicit domains — the Plotly-native equivalent of the Chart.js + * backend's facet panel grid (chartjs/assemble.ts), mirroring its decisions: + * - shared, nice-rounded y-domain across all panels + * - only the leftmost column draws y tick labels and the y-axis title + * - column-only facets wrap into a 2D grid using the shared facet budget + * - column headers above panels, row headers rotated on the left + * - one legend entry per series (deduped across panels via legendgroup) + */ + +/** One instantiated facet cell. */ +export interface PlotlyFacetPanel { + rowIndex: number; + colIndex: number; + rowHeader?: string; + colHeader?: string; + /** The per-panel figure produced by template.instantiate ({ data, layout }). */ + figure: any; +} + +/** + * Round a [min, max] interval outward to "nice" round numbers so the shared + * facet axis lands its endpoints on clean tick values (same rule as the + * Chart.js backend / Vega-Lite `nice: true`). + */ +export function niceBounds(min: number, max: number, targetTicks = 5): { min: number; max: number } { + if (!(Number.isFinite(min) && Number.isFinite(max)) || max <= min) { + return { min, max }; + } + const niceNum = (range: number, round: boolean): number => { + const exp = Math.floor(Math.log10(range)); + const frac = range / 10 ** exp; + let niceFrac: number; + if (round) { + niceFrac = frac < 1.5 ? 1 : frac < 3 ? 2 : frac < 7 ? 5 : 10; + } else { + niceFrac = frac <= 1 ? 1 : frac <= 2 ? 2 : frac <= 5 ? 5 : 10; + } + return niceFrac * 10 ** exp; + }; + const step = niceNum(niceNum(max - min, false) / Math.max(1, targetTicks - 1), true); + return { + min: Math.floor(min / step) * step, + max: Math.ceil(max / step) * step, + }; +} + +const FACET_GAP_PX = 16; +const COL_HEADER_H = 22; +const ROW_HEADER_W = 28; +const MARGIN = { l: 64, r: 24, t: 16, b: 48 }; +const LEGEND_GUTTER = 96; + +/** + * Combine instantiated facet panels into one Plotly figure. + * + * Each panel's own `layout.xaxis` / `layout.yaxis` (category arrays, titles, + * range modes) is copied onto that panel's axis pair; traces are re-pointed at + * the pair. Domains are computed from the designed pixel grid so the figure + * scales exactly like the other backends' facet output. + */ +export function plCombineFacetPanels( + panels: PlotlyFacetPanel[], + opts: { + rows: number; + cols: number; + panelWidth: number; + panelHeight: number; + sharedYDomain?: { min: number; max: number }; + hasColHeader: boolean; + hasRowHeader: boolean; + /** Wrapped column-only facets repeat the header band above every row. */ + colHeaderPerRow: boolean; + showLegend: boolean; + }, +): any { + const { + rows, cols, panelWidth, panelHeight, sharedYDomain, + hasColHeader, hasRowHeader, colHeaderPerRow, showLegend, + } = opts; + + // Row headers sit on the RIGHT (Vega-Lite style): the left edge is already + // occupied by y tick labels + the y-axis title, so a left-side header would + // collide with them in a single combined figure. + const rowHeaderW = hasRowHeader ? ROW_HEADER_W : 0; + const headerBands = colHeaderPerRow ? rows : (hasColHeader ? 1 : 0); + + const plotW = cols * panelWidth + (cols - 1) * FACET_GAP_PX; + const plotH = rows * panelHeight + (rows - 1) * FACET_GAP_PX + + headerBands * COL_HEADER_H; + const totalW = MARGIN.l + plotW + rowHeaderW + MARGIN.r + (showLegend ? LEGEND_GUTTER : 0); + const totalH = MARGIN.t + plotH + MARGIN.b; + + // Paper-fraction geometry (Plotly domains live inside the margins). + const paperW = plotW + rowHeaderW; + const paperH = plotH; + const xFrac = (px: number) => px / paperW; + const yFrac = (px: number) => px / paperH; + + const colX0 = (ci: number) => ci * (panelWidth + FACET_GAP_PX); + // Row band top (px from paper top), accounting for header bands. + const rowY0 = (ri: number) => (colHeaderPerRow + ? ri * (COL_HEADER_H + panelHeight + FACET_GAP_PX) + COL_HEADER_H + : (hasColHeader ? COL_HEADER_H : 0) + ri * (panelHeight + FACET_GAP_PX)); + + const figure: any = { + data: [], + layout: { + margin: { ...MARGIN }, + showlegend: showLegend, + annotations: [], + }, + _facet: true, + _facetRows: rows, + _facetCols: cols, + _width: totalW, + _height: totalH, + }; + figure.layout.width = totalW; + figure.layout.height = totalH; + + const seenLegend = new Set(); + + for (const panel of panels) { + const { rowIndex: ri, colIndex: ci } = panel; + const n = ri * cols + ci + 1; + const xName = n === 1 ? 'xaxis' : `xaxis${n}`; + const yName = n === 1 ? 'yaxis' : `yaxis${n}`; + const xRef = n === 1 ? 'x' : `x${n}`; + const yRef = n === 1 ? 'y' : `y${n}`; + + const x0 = xFrac(colX0(ci)); + const x1 = xFrac(colX0(ci) + panelWidth); + // Plotly y-domain runs bottom-up; our rows run top-down. + const yTopPx = rowY0(ri); + const y1 = 1 - yFrac(yTopPx); + const y0 = 1 - yFrac(yTopPx + panelHeight); + + const panelLayout = panel.figure?.layout ?? {}; + const xAxis: any = { ...(panelLayout.xaxis ?? {}), domain: [x0, x1], anchor: yRef }; + const yAxis: any = { ...(panelLayout.yaxis ?? {}), domain: [y0, y1], anchor: xRef }; + + // Shared y-domain across panels (mirror CJS: fixed nice range, no + // per-panel autorange). Rangemode would fight an explicit range. + if (sharedYDomain) { + yAxis.range = [sharedYDomain.min, sharedYDomain.max]; + delete yAxis.rangemode; + } + // Only the leftmost column shows y tick labels + title. + if (ci > 0) { + yAxis.showticklabels = false; + delete yAxis.title; + } + // X-axis titles only on the bottom row (a per-panel title would + // collide with the next row's column headers in a single figure). + if (ri < rows - 1) { + delete xAxis.title; + } + + figure.layout[xName] = xAxis; + figure.layout[yName] = yAxis; + + for (const trace of panel.figure?.data ?? []) { + const placed: any = { ...trace, xaxis: xRef, yaxis: yRef }; + const legendKey = String(placed.name ?? ''); + if (legendKey) { + placed.legendgroup = legendKey; + placed.showlegend = !seenLegend.has(legendKey); + seenLegend.add(legendKey); + } else { + placed.showlegend = false; + } + figure.data.push(placed); + } + + // Column header annotation (per wrapped row, or once on the top row). + if (panel.colHeader != null && (colHeaderPerRow || ri === 0)) { + figure.layout.annotations.push({ + text: String(panel.colHeader), + showarrow: false, + xref: 'paper', yref: 'paper', + x: (x0 + x1) / 2, + y: 1 - yFrac(yTopPx - COL_HEADER_H / 2), + xanchor: 'center', yanchor: 'middle', + font: { size: 12 }, + }); + } + + // Row header annotation (rightmost side, Vega-Lite style), rotated. + if (panel.rowHeader != null && ci === cols - 1) { + figure.layout.annotations.push({ + text: String(panel.rowHeader), + showarrow: false, + textangle: 90, + xref: 'paper', yref: 'paper', + x: xFrac(plotW + rowHeaderW / 2), + y: (y0 + y1) / 2, + xanchor: 'center', yanchor: 'middle', + font: { size: 12 }, + }); + } + } + + if (!showLegend) { + figure.layout.showlegend = false; + } + + return figure; +} diff --git a/packages/flint-js/src/plotly/index.ts b/packages/flint-js/src/plotly/index.ts new file mode 100644 index 00000000..9dd7d029 --- /dev/null +++ b/packages/flint-js/src/plotly/index.ts @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * @module flint-chart/plotly + * + * Plotly backend for flint-chart. + * + * Compiles the core semantic layer into Plotly figure objects. + * Contains PL-specific assembly, spec instantiation, and chart templates. + * + * Architecture contrast with other backends: + * VL: encoding-channel-based — { encoding: { x: { field, type }, y: ... } } + * EC: series-based — { series: [{ type, data }], xAxis, yAxis } + * CJS: dataset-based — { type, data: { labels, datasets[] }, options } + * PL: trace-based — { data: [{ type, x, y }], layout } + * + * Same core pipeline (Phase 0 + Phase 1), different Phase 2 output. + * Figures are pure JSON (no callback functions). + */ + +// PL assembly function +export { assemblePlotly } from './assemble'; + +// PL spec instantiation (Phase 2) +export { plApplyLayoutToSpec, plApplyTooltips } from './instantiate-spec'; + +// PL template registry +export { + plTemplateDefs, + plAllTemplateDefs, + plGetTemplateDef, + plGetTemplateChannels, +} from './templates'; diff --git a/packages/flint-js/src/plotly/instantiate-spec.ts b/packages/flint-js/src/plotly/instantiate-spec.ts new file mode 100644 index 00000000..2e9f88d7 --- /dev/null +++ b/packages/flint-js/src/plotly/instantiate-spec.ts @@ -0,0 +1,244 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * ============================================================================= + * PHASE 2: INSTANTIATE SPEC — Plotly backend + * ============================================================================= + * + * Translates semantic decisions (Phase 0) and layout dimensions (Phase 1) + * into Plotly-specific figure properties. + * + * Key differences from the other backends: + * - PL figures are `{ data: traces[], layout }` and stay pure JSON — axis + * tick formatting uses declarative `tickformat`/axis types, never + * callback functions + * - PL sizing via `layout.width` / `layout.height` + * - PL label rotation via `layout.xaxis.tickangle` + * + * PL dependency: **Yes — this is where Plotly-specific syntax lives** + * ============================================================================= + */ + +import type { + InstantiateContext, + ChartWarning, +} from '../core/types'; + +const AXIS_TITLE_STANDOFF = 16; +// Plotly places tick labels ~1px from the axis by default — much tighter than +// the other renderers (ECharts axisLabel.margin 8, Vega-Lite labelPadding+tick +// ~7). Nudge them out to a comparable, comfortable gap. `ticklabelstandoff` is +// the purpose-built property (Plotly ≥ 2.34 / 3.x); harmlessly ignored on older +// builds, which keeps the current behavior rather than regressing. +const TICK_LABEL_STANDOFF = 7; + +function reserveCartesianMargins(figure: any, context: InstantiateContext): void { + const { layout } = context; + const hasXAxis = !!figure.layout.xaxis; + const hasYAxis = !!figure.layout.yaxis; + if (!hasXAxis && !hasYAxis) return; + + const xCategories = figure.layout.xaxis?.categoryarray; + const xFontSize = layout.xLabel?.fontSize ?? 10; + const maxXLabelWidth = Array.isArray(xCategories) + ? Math.min(layout.xLabel?.labelLimit ?? 100, Math.max(0, ...xCategories.map((value: unknown) => String(value).length * xFontSize * 0.6))) + : 0; + const xBandWidth = Array.isArray(xCategories) && xCategories.length > 0 + ? layout.subplotWidth / xCategories.length + : Number.POSITIVE_INFINITY; + if (figure.layout.xaxis && Array.isArray(xCategories) && xCategories.length <= 6) { + figure.layout.xaxis.tickangle = 0; + const desiredPlotWidth = xCategories.length * Math.max(48, maxXLabelWidth + 16); + figure._width += Math.max(0, desiredPlotWidth - layout.subplotWidth); + } else if (figure.layout.xaxis && figure.layout.xaxis.tickangle == null && maxXLabelWidth > xBandWidth) { + figure.layout.xaxis.tickangle = 45; + } + const xAngle = Math.abs(figure.layout.xaxis?.tickangle ?? layout.xLabel?.labelAngle ?? 0) * Math.PI / 180; + const rotatedXDepth = Math.ceil(maxXLabelWidth * Math.sin(xAngle)); + const bottom = hasXAxis ? Math.max(xAngle > 0 ? 96 : 56, 40 + rotatedXDepth) : 24; + + const yCategories = figure.layout.yaxis?.categoryarray; + const yFontSize = layout.yLabel?.fontSize ?? 10; + const maxYLabelWidth = Array.isArray(yCategories) + ? Math.min(layout.yLabel?.labelLimit ?? 100, Math.max(0, ...yCategories.map((value: unknown) => String(value).length * yFontSize * 0.6))) + : 28; + const left = hasYAxis ? Math.max(64, 36 + maxYLabelWidth) : 24; + const hasColorbar = (figure.data ?? []).some((trace: any) => trace.colorbar || trace.marker?.colorbar); + const right = hasColorbar ? 96 : 32; + + figure.layout.margin = { t: 24, r: right, b: bottom, l: left }; +} + +export function plApplyCartesianAxisSpacing(figure: any): void { + for (const [key, axis] of Object.entries(figure.layout ?? {})) { + if (!/^[xy]axis\d*$/.test(key) || !axis || typeof axis !== 'object') continue; + const cartesianAxis = axis as any; + cartesianAxis.automargin = true; + if (cartesianAxis.ticklabelstandoff == null) { + cartesianAxis.ticklabelstandoff = TICK_LABEL_STANDOFF; + } + if (cartesianAxis.title?.text) { + cartesianAxis.title = { ...cartesianAxis.title, standoff: AXIS_TITLE_STANDOFF }; + } + } +} + +/** + * Apply the cross-cutting per-axis chart properties (`logScale_x/y`, + * `includeZero_x/y`) to every cartesian axis of the figure. These are surfaced + * on many charts by the shared VL option set; implementing them here lets ALL + * Plotly cartesian charts honor them natively (`axis.type: 'log'`, + * `axis.rangemode: 'tozero'`). A category axis is skipped (log/zero are + * meaningless there); a log axis never also forces zero (log 0 is undefined). + */ +export function plApplyAxisProperties(figure: any, context: InstantiateContext): void { + const cp = context.chartProperties; + if (!cp || !figure.layout) return; + const applyAxis = (re: RegExp, logKey: string, zeroKey: string) => { + const log = cp[logKey]; + const zero = cp[zeroKey]; + if (log == null && zero == null) return; + for (const [k, ax] of Object.entries(figure.layout)) { + if (!re.test(k) || !ax || typeof ax !== 'object') continue; + const a = ax as any; + if (a.type === 'category') continue; + if (log === true) { + a.type = 'log'; + if (a.rangemode === 'tozero') delete a.rangemode; + } else if (log === false && a.type === 'log') { + delete a.type; + } + if (a.type !== 'log') { + if (zero === true) a.rangemode = 'tozero'; + else if (zero === false && a.rangemode === 'tozero') a.rangemode = 'normal'; + } + } + }; + applyAxis(/^xaxis\d*$/, 'logScale_x', 'includeZero_x'); + applyAxis(/^yaxis\d*$/, 'logScale_y', 'includeZero_y'); +} + +/** + * Phase 2: Apply layout and semantic decisions to the Plotly figure. + * + * Handles common Plotly plumbing across all templates: + * - Figure sizing (_width, _height + layout.width/height) + * - Axis label rotation and font sizing + * - Overflow truncation warnings + */ +export function plApplyLayoutToSpec( + figure: any, + context: InstantiateContext, + warnings: ChartWarning[], +): void { + const { layout, canvasSize } = context; + + if (!figure.layout) figure.layout = {}; + + // ── Figure dimensions ──────────────────────────────────────────────── + let usedDefaultDimensions = false; + if (!figure._width) { + usedDefaultDimensions = true; + const PADDING = 80; // approximate space for axes, labels + + const xIsDiscrete = layout.xNominalCount > 0 || layout.xContinuousAsDiscrete > 0; + const yIsDiscrete = layout.yNominalCount > 0 || layout.yContinuousAsDiscrete > 0; + + let plotWidth: number; + let plotHeight: number; + + if (xIsDiscrete && layout.xStepUnit !== 'group') { + const xItemCount = layout.xNominalCount || layout.xContinuousAsDiscrete || 0; + plotWidth = xItemCount > 0 ? layout.xStep * xItemCount : (layout.subplotWidth || canvasSize.width); + } else { + plotWidth = layout.subplotWidth || canvasSize.width; + } + + if (yIsDiscrete && layout.yStepUnit !== 'group') { + const yItemCount = layout.yNominalCount || layout.yContinuousAsDiscrete || 0; + plotHeight = yItemCount > 0 ? layout.yStep * yItemCount : (layout.subplotHeight || canvasSize.height); + } else { + plotHeight = layout.subplotHeight || canvasSize.height; + } + + const legendGutter = figure.layout.showlegend ? 96 : 0; + figure._width = plotWidth + PADDING + legendGutter; + figure._height = plotHeight + PADDING; + } + + // ── X-axis label rotation and font sizing ──────────────────────────── + if (layout.xLabel) { + if (!figure.layout.xaxis) figure.layout.xaxis = {}; + if (layout.xLabel.labelAngle && layout.xLabel.labelAngle !== 0) { + figure.layout.xaxis.tickangle = Math.abs(layout.xLabel.labelAngle); + } + if (layout.xLabel.fontSize) { + figure.layout.xaxis.tickfont = { + ...(figure.layout.xaxis.tickfont || {}), + size: layout.xLabel.fontSize, + }; + } + } + + // ── Y-axis label font sizing ───────────────────────────────────────── + if (layout.yLabel?.fontSize) { + if (!figure.layout.yaxis) figure.layout.yaxis = {}; + figure.layout.yaxis.tickfont = { + ...(figure.layout.yaxis.tickfont || {}), + size: layout.yLabel.fontSize, + }; + } + + // ── Axis title + legend fonts — canvas-adaptive header sizes ───────── + for (const key of Object.keys(figure.layout)) { + if (!/^[xy]axis\d*$/.test(key)) continue; + const axis = figure.layout[key]; + if (axis?.title) { + axis.title = typeof axis.title === 'string' ? { text: axis.title } : axis.title; + axis.title.font = { ...(axis.title.font || {}), size: layout.titleFontSize }; + } + } + if (figure.layout.legend) { + figure.layout.legend.font = { + ...(figure.layout.legend.font || {}), + size: layout.legendFontSize, + }; + } + + if (figure.layout.margin == null) { + reserveCartesianMargins(figure, context); + if (usedDefaultDimensions) { + const margin = figure.layout.margin; + figure._width += Math.max(0, margin.l + margin.r - 80); + figure._height += Math.max(0, margin.t + margin.b - 80); + } + } + plApplyCartesianAxisSpacing(figure); + figure.layout.width = figure._width; + figure.layout.height = figure._height; + + // ── Overflow truncation warnings ───────────────────────────────────── + if (layout.truncations && layout.truncations.length > 0) { + for (const trunc of layout.truncations) { + warnings.push({ + severity: 'warning', + code: 'overflow', + message: trunc.message, + channel: trunc.channel, + field: trunc.field, + }); + } + } +} + +/** + * Apply tooltips to a Plotly figure. Plotly hover is on by default; this + * pins an explicit unified hover mode so tooltips read across series. + */ +export function plApplyTooltips(figure: any): void { + if (!figure.layout) figure.layout = {}; + if (figure.layout.hovermode == null) { + figure.layout.hovermode = 'closest'; + } +} diff --git a/packages/flint-js/src/plotly/templates/area.ts b/packages/flint-js/src/plotly/templates/area.ts new file mode 100644 index 00000000..5772528a --- /dev/null +++ b/packages/flint-js/src/plotly/templates/area.ts @@ -0,0 +1,151 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Area Chart template (single + multi-series). + * + * Mirrors the Chart.js Area template's decisions. Plotly renders areas as + * scatter traces with `fill`; multi-series stacking uses `stackgroup` + * (the Plotly-native equivalent of Chart.js `fill: 'stack'`). + */ + +import { ChartTemplateDef, ChartPropertyDef } from '../../core/types'; +import { + extractCategories, + groupBy, + buildCategoryAlignedData, + coerceIsoDateForPlotly, + getPlotlyPalette, + getSeriesColor, +} from './utils'; + +const isDiscrete = (type: string | undefined) => type === 'nominal' || type === 'ordinal'; + +/** Hex → rgba with alpha, for translucent area fills. */ +function fillColor(hex: string, alpha: number): string { + const m = /^#?([0-9a-f]{6})$/i.exec(hex.trim()); + if (!m) return hex; + const v = parseInt(m[1], 16); + const a = Math.max(0, Math.min(1, alpha)); + return `rgba(${(v >> 16) & 255}, ${(v >> 8) & 255}, ${v & 255}, ${a})`; +} + +export const plAreaChartDef: ChartTemplateDef = { + chart: 'Area Chart', + template: { mark: 'area', encoding: {} }, + channels: ['x', 'y', 'color', 'opacity', 'column', 'row'], + markCognitiveChannel: 'area', + declareLayoutMode: () => ({ + paramOverrides: { continuousMarkCrossSection: { x: 100, y: 20, seriesCountAxis: 'auto' }, facetAspectRatioResistance: 0.5 }, + }), + instantiate: (spec, ctx) => { + const { channelSemantics, table, chartProperties } = ctx; + const xCS = channelSemantics.x; + const yCS = channelSemantics.y; + const colorField = channelSemantics.color?.field; + + if (!xCS?.field || !yCS?.field) return; + const xField = xCS.field; + const yField = yCS.field; + + const xIsDiscrete = isDiscrete(xCS.type); + const xIsTemporal = xCS.type === 'temporal'; + const mapX = (raw: unknown) => (xIsTemporal ? coerceIsoDateForPlotly(raw) : raw); + + const categories = xIsDiscrete + ? extractCategories(table, xField, xCS.ordinalSortOrder) + : undefined; + + const opacity = Number(chartProperties?.opacity ?? 0.4); + const stackMode = chartProperties?.stackMode; + const stacked = stackMode !== 'layered'; + const smooth = chartProperties?.interpolate === 'monotone'; + + const palette = getPlotlyPalette(ctx, 'color'); + const traces: any[] = []; + const makeTrace = (name: string, rows: any[], colorIndex: number) => { + const xVals = xIsDiscrete ? categories! : rows.map(r => mapX(r[xField])); + const yVals = xIsDiscrete + ? buildCategoryAlignedData(rows, xField, yField, categories!) + : rows.map(r => (r[yField] == null ? null : r[yField])); + const color = getSeriesColor(palette, colorIndex); + const trace: any = { + type: 'scatter', + mode: 'lines', + name, + x: xVals, + y: yVals, + line: { color, shape: smooth ? 'spline' : 'linear' }, + fillcolor: fillColor(color, opacity), + }; + if (colorField && stacked) { + trace.stackgroup = 'one'; + } else { + trace.fill = 'tozeroy'; + } + return trace; + }; + + if (colorField) { + let i = 0; + for (const [name, rows] of groupBy(table, colorField)) { + traces.push(makeTrace(name, rows, i)); + i++; + } + } else { + traces.push(makeTrace(yField, table, 0)); + } + + // 100%-stacked: Plotly normalizes a stackgroup when the FIRST trace in + // the group carries `groupnorm: 'percent'`. + if (colorField && stacked && stackMode === 'normalize' && traces.length > 0) { + traces[0].groupnorm = 'percent'; + } + + const xAxisSpec: any = { title: { text: xField } }; + if (xIsDiscrete) { + xAxisSpec.type = 'category'; + xAxisSpec.categoryorder = 'array'; + xAxisSpec.categoryarray = categories; + } else if (xIsTemporal) { + xAxisSpec.type = 'date'; + } + + const yAxisSpec: any = { title: { text: yField } }; + if (yCS.zero) { + yAxisSpec.rangemode = yCS.zero.zero !== false ? 'tozero' : 'normal'; + } + + const figure: any = { + data: traces, + layout: { + xaxis: xAxisSpec, + yaxis: yAxisSpec, + showlegend: !!colorField, + }, + }; + + Object.assign(spec, figure); + delete spec.mark; + delete spec.encoding; + }, + properties: [ + { + key: 'interpolate', label: 'Curve', type: 'discrete', options: [ + { value: undefined, label: 'Default (linear)' }, + { value: 'linear', label: 'Linear' }, + { value: 'monotone', label: 'Monotone (smooth)' }, + ], + } as ChartPropertyDef, + { key: 'opacity', label: 'Opacity', type: 'continuous', min: 0.1, max: 1, step: 0.05, defaultValue: 0.4 } as ChartPropertyDef, + { + key: 'stackMode', label: 'Stack', type: 'discrete', + check: (ctx) => ({ applicable: !!ctx.encodings.color?.field }), + options: [ + { value: undefined, label: 'Stacked (default)' }, + { value: 'normalize', label: 'Normalize (100%)' }, + { value: 'layered', label: 'Layered (overlap)' }, + ], + } as ChartPropertyDef, + ], +}; diff --git a/packages/flint-js/src/plotly/templates/bar-table.ts b/packages/flint-js/src/plotly/templates/bar-table.ts new file mode 100644 index 00000000..c1bccb6a --- /dev/null +++ b/packages/flint-js/src/plotly/templates/bar-table.ts @@ -0,0 +1,514 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Bar Table template. + * + * A ranked horizontal "data bar table" (category | gradient bar | % share | + * value), matching the Vega-Lite Bar Table's visual pattern — common in + * Chinese BI dashboards (FineBI, Quick BI) and Excel/Power BI conditional- + * formatting "Data Bars". + * + * Composite layout, built directly on the Plotly figure rather than forced + * through the generic column/row facet combiner (`../facet.ts`, which only + * supports one cartesian axis pair per panel): each facet cell (or the whole + * table, when unfaceted) gets its own hidden-margin axis pair whose `xaxis` + * domain is narrowed to just the bar column; the category name comes for + * free from the axis's own (native) y tick labels, and the %/value columns + * are `layout.annotations` anchored to that SAME y-axis (so they line up + * with each bar's row) at a fixed paper-x position — the same domain-grid + + * mixed paper/data-axis annotation technique `sparkline.ts` and `kpi-card.ts` + * use for their own composite grids. `selfManagesFacets` keeps the assembler + * from pre-splitting this template by `column`/`row` (see `../assemble.ts`); + * facets are instead built as additional cells in the same hand-rolled grid. + */ + +import { ChartTemplateDef, ChartPropertyDef } from '../../core/types'; +import { getRegistryEntry } from '../../core/type-registry'; + +const HEADER_H = 16; +const FACET_HEADER_H = 20; +const INTER_GAP = 8; +const CELL_GAP_X = 28; +const CELL_GAP_Y = 20; +const OTHERS_GRAY = '#bdbdbd'; + +const isCJK = (ch: string): boolean => + /[\u3000-\u303F\u3400-\u9FFF\uF900-\uFAFF\uFF00-\uFFEF]/.test(ch); +const textWidth = (s: unknown): number => + [...String(s ?? '')].reduce((a, ch) => a + (isCJK(ch) ? 2 : 1), 0); + +/** + * Truncate to an ellipsis so the text fits within `maxUnits` character-width + * units (see `textWidth` — a CJK character counts as 2). Mirrors the effect + * of the Vega-Lite template's `axis.labelLimit`, which Plotly's category axis + * has no equivalent for — an over-length native tick label would otherwise + * overflow past the figure's own left edge instead of ellipsizing. + */ +function truncateToWidth(s: string, maxUnits: number): string { + if (textWidth(s) <= maxUnits) return s; + const chars = [...s]; + let out = ''; + let w = 1; // reserve 1 unit for the ellipsis + for (const ch of chars) { + const cw = isCJK(ch) ? 2 : 1; + if (w + cw > maxUnits) break; + out += ch; + w += cw; + } + return out.replace(/\s+$/, '') + '…'; +} + +/** Compact approximate number format — mirrors the Vega-Lite template's sizing/display helper. */ +function approxFormat(v: number, pctPattern?: string): string { + if (!Number.isFinite(v)) return ''; + if (pctPattern) return `${(v * 100).toFixed(1)}%`; + const a = Math.abs(v); + if (a >= 1e9) return (v / 1e9).toFixed(1) + 'B'; + if (a >= 1e6) return (v / 1e6).toFixed(1) + 'M'; + if (a >= 1e3) return (v / 1e3).toFixed(1) + 'K'; + if (Number.isInteger(v)) return String(v); + if (a > 0 && a < 1) { + // Adaptive precision for sub-1 magnitudes — a fixed 2-decimal round + // (e.g. toward "0.00") would silently collapse a genuinely tiny but + // meaningful value (0.0004) down to "0". Show enough significant + // digits to keep the value distinguishable from zero. + const decimals = Math.min(6, Math.max(2, -Math.floor(Math.log10(a)) + 1)); + return v.toFixed(decimals).replace(/0+$/, '').replace(/\.$/, ''); + } + return (Math.round(v * 100) / 100).toLocaleString('en-US'); +} + +/** Linear interpolation between two hex colors (sequential gradient-by-value). */ +function lerpHex(c0: string, c1: string, t: number): string { + const hex = (h: string) => { + const m = /^#?([0-9a-f]{6})$/i.exec(h.trim()); + const v = m ? parseInt(m[1], 16) : 0; + return [(v >> 16) & 255, (v >> 8) & 255, v & 255]; + }; + const [r0, g0, b0] = hex(c0); + const [r1, g1, b1] = hex(c1); + const clamp = Math.max(0, Math.min(1, t)); + const r = Math.round(r0 + (r1 - r0) * clamp); + const g = Math.round(g0 + (g1 - g0) * clamp); + const b = Math.round(b0 + (b1 - b0) * clamp); + return `rgb(${r}, ${g}, ${b})`; +} +const SEQ_LOW = '#cdebd3', SEQ_HIGH = '#41a25f'; +const DIV_LOW = '#c0392b', DIV_MID = '#f2f2f2', DIV_HIGH = '#2e7d46'; + +/** One aggregated row: category, its ranked value, and (optional) per-color-group breakdown. */ +interface AggRow { + cat: string; + value: number; + isOthers: boolean; + byColor?: Map; +} + +/** Aggregate raw rows into ranked-and-topN'd category rows for one facet scope. */ +function buildScopeRows( + rows: any[], yField: string, xField: string, colorField: string | undefined, + useMean: boolean, maxRows: number, reversed: boolean, +): AggRow[] { + const byCat = new Map }>(); + for (const r of rows) { + const v = Number(r[xField]); + if (!Number.isFinite(v)) continue; + const cat = String(r[yField] ?? ''); + const g = byCat.get(cat) ?? { sum: 0, n: 0, byColor: new Map() }; + g.sum += v; g.n += 1; + if (colorField) { + const cv = String(r[colorField] ?? ''); + g.byColor.set(cv, (g.byColor.get(cv) ?? 0) + v); + } + byCat.set(cat, g); + } + const agg = (g: { sum: number; n: number }) => useMean ? g.sum / Math.max(1, g.n) : g.sum; + const ranked = Array.from(byCat.entries()) + .map(([cat, g]) => ({ cat, value: agg(g), byColor: colorField ? g.byColor : undefined })) + .sort((a, b) => reversed ? a.value - b.value : b.value - a.value); + + if (maxRows <= 0 || ranked.length <= maxRows) { + return ranked.map(r => ({ ...r, isOthers: false })); + } + const keepN = Math.max(1, maxRows - 1); + const kept = ranked.slice(0, keepN).map(r => ({ ...r, isOthers: false })); + const rest = ranked.slice(keepN); + const restSum = rest.reduce((s, r) => s + r.value, 0); + const restValue = useMean && rest.length > 0 ? restSum / rest.length : restSum; + const restByColor = new Map(); + if (colorField) { + for (const r of rest) { + for (const [cv, v] of (r.byColor ?? new Map())) { + restByColor.set(cv, (restByColor.get(cv) ?? 0) + v); + } + } + } + kept.push({ + cat: `Others (+${rest.length})`, value: restValue, isOthers: true, + byColor: colorField ? restByColor : undefined, + }); + return kept; +} + +export const plBarTableDef: ChartTemplateDef = { + chart: 'Bar Table', + template: { mark: 'bar', encoding: {} }, + channels: ['y', 'x', 'color', 'column', 'row'], + markCognitiveChannel: 'length', + // See file docstring — a hand-built per-cell axis-pair grid (bar + %/value + // annotation columns), not a single cartesian panel the generic facet + // combiner could safely split/recombine; column/row facets are built as + // additional cells in this template's own grid instead. + selfManagesFacets: true, + instantiate: (spec, ctx) => { + const { channelSemantics, chartProperties, canvasSize } = ctx; + const yField = channelSemantics.y?.field; + const xField = channelSemantics.x?.field; + const colorField = channelSemantics.color?.field; + const colField = channelSemantics.column?.field; + const rowField = channelSemantics.row?.field; + if (!yField || !xField) return; + + const table = (ctx.fullTable ?? ctx.table ?? []) as any[]; + if (table.length === 0) return; + + const maxRows = Math.max(0, Number(chartProperties?.maxRows ?? 20)); + const showPercent = chartProperties?.showPercent === true; + const useMean = channelSemantics.x?.aggregationDefault === 'average'; + const reversed = !!channelSemantics.y?.reversed; + + const xEntry = getRegistryEntry(channelSemantics.x?.semanticAnnotation?.semanticType ?? 'Unknown'); + let hasNegative = false, hasPositive = false; + for (const r of table) { + const v = Number(r[xField]); + if (Number.isFinite(v)) { if (v < 0) hasNegative = true; else if (v > 0) hasPositive = true; } + } + const isDiverging = !colorField && ( + xEntry.diverging === 'inherent' + || (xEntry.diverging === 'conditional' && hasNegative && hasPositive) + ); + + // ── Facet grid: column/row values in first-appearance order. ───── + // + // Column-only facets wrap into a 2D grid when there are more panels + // than comfortably fit at this template's own (wider-than-usual, + // 3-sub-column) minimum panel width — the shared layout engine's + // facet-grid decision assumes a much narrower single-axis panel, so + // it under-wraps for this template; we make the wrap call ourselves + // from our own minimum-width estimate instead. + const colValues = colField ? [...new Set(table.map(r => String(r[colField])))] : ['']; + const rowValues = rowField ? [...new Set(table.map(r => String(r[rowField])))] : ['']; + const MIN_CELL_W = showPercent ? 280 : 230; + const maxStretchW = (canvasSize ?? { width: 480 }).width * 3; + const maxColsFit = Math.max(1, Math.floor(maxStretchW / MIN_CELL_W)); + const gridColsWanted = colField + ? (colValues.length <= maxColsFit + ? colValues.length + : Math.ceil(colValues.length / Math.ceil(colValues.length / maxColsFit))) + : 1; + const wrapColumnOnly = !!colField && !rowField && gridColsWanted < colValues.length; + + type Cell = { colVal: string; rowVal: string; rows: any[] }; + const cells: Cell[][] = []; + if (wrapColumnOnly) { + for (let i = 0; i < colValues.length; i += gridColsWanted) { + cells.push(colValues.slice(i, i + gridColsWanted).map(cv => ({ + colVal: cv, rowVal: '', + rows: table.filter(r => String(r[colField!]) === cv), + }))); + } + } else { + for (const rv of rowValues) { + cells.push(colValues.map(cv => ({ + colVal: cv, rowVal: rv, + rows: table.filter(r => + (!colField || String(r[colField]) === cv) && (!rowField || String(r[rowField]) === rv)), + }))); + } + } + const gridRows = cells.length; + const gridCols = Math.max(1, ...cells.map(r => r.length)); + const hasFacet = gridRows > 1 || gridCols > 1; + + // ── Per-cell aggregation (Top-N rollup within each facet scope). ── + const scoped = cells.map(row => row.map(cell => + buildScopeRows(cell.rows, yField, xField, colorField, useMean, maxRows, reversed))); + + const allColorValues = colorField + ? [...new Set(scoped.flat().flatMap(sr => sr.filter(r => !r.isOthers).flatMap(r => [...(r.byColor?.keys() ?? [])])))] + : []; + + // ── Sizing (manual — mirrors the Vega-Lite template's hand-rolled + // panel sizing; the shared layout engine's faceted sizing doesn't + // apply to a hand-built multi-axis grid). ───────────────────────── + const canvas = canvasSize ?? { width: 480, height: 320 }; + const maxRowsPerCell = Math.max(1, ...scoped.flat().map(sr => sr.length)); + const density = Math.min(1, Math.max(0, (maxRowsPerCell - 12) / 40)); + const lerp = (a: number, b: number) => Math.round(a + (b - a) * density); + const fontSize = Math.max(9, lerp(12, 10) - (hasFacet ? 2 : 0)); + const barPx = Math.max(6, lerp(16, 8)); + const gapPx = Math.max(2, Math.round(barPx * 0.2)); + const rowStep = barPx + gapPx; + + const allAggValues = scoped.flat().flatMap(sr => sr.map(r => r.value)); + const pctValuesForSizing = scoped.flat().flatMap(sr => { + const total = sr.reduce((s, r) => s + r.value, 0); + return Math.abs(total) > 1e-9 ? sr.map(r => r.value / total) : []; + }); + const pctPattern = showPercent ? '%' : undefined; + const measure = (strs: string[], minPx: number, maxPx: number) => { + const maxChars = strs.reduce((m, s) => Math.max(m, s.length), 0); + return Math.min(maxPx, Math.max(minPx, Math.round(maxChars * fontSize * 0.62 + 12))); + }; + const catW = Math.min(180, Math.max(50, Math.round( + Math.max(4, textWidth(yField), ...scoped.flat().flatMap(sr => sr.map(r => textWidth(r.cat)))) * fontSize * 0.6 + 12))); + const catMaxUnits = Math.max(4, Math.floor((catW - 12) / (fontSize * 0.6))); + const valW = measure([...allAggValues.map(v => approxFormat(v)), xField], 40, 110); + const pctW = showPercent ? measure([...pctValuesForSizing.map(v => approxFormat(v, pctPattern)), '%'], 40, 70) : 0; + const barMinW = 90; + const cellContentW = Math.max( + catW + barMinW + INTER_GAP + valW + (showPercent ? pctW + INTER_GAP : 0), + Math.round((canvas.width - (gridCols - 1) * CELL_GAP_X) / gridCols), + ); + const cellW = cellContentW; + const barW = Math.max(barMinW, cellW - catW - valW - (showPercent ? pctW + INTER_GAP : 0) - INTER_GAP); + + const facetColHeaderBand = colField ? FACET_HEADER_H : 0; + const facetRowHeaderW = rowField ? 18 : 0; + const cellHeights = cells.map((row, ri) => Math.max(1, ...row.map((_, ci) => { + const sr = scoped[ri][ci]; + return HEADER_H + (sr?.length ?? 1) * rowStep; + }))); + const rowTotalHeights = cellHeights.map(h => h + facetColHeaderBand); + const totalW = gridCols * cellW + (gridCols - 1) * CELL_GAP_X + facetRowHeaderW; + // Floor the figure height so a very small row count (e.g. a single + // row) still leaves enough vertical room for the header band and the + // row to render legibly — otherwise the (fixed-size) header/row text + // can visually collide in an unrealistically short image. + const MIN_TOTAL_H = 70; + const totalH = Math.max( + MIN_TOTAL_H, + rowTotalHeights.reduce((s, h) => s + h, 0) + (gridRows - 1) * CELL_GAP_Y, + ); + + const palette: string[] = ['#4C78A8', '#F58518', '#54A24B', '#B279A2', '#E45756', '#72B7B2', '#EECA3B', '#9D755D']; + const colorIdx = new Map(allColorValues.map((v, i) => [v, i])); + + const traces: any[] = []; + const annotations: any[] = []; + const layout: any = { showlegend: !!colorField, margin: { t: 8, b: 8, l: 8, r: 8 } }; + const legendSeen = new Set(); + + let yTop = 0; + for (let ri = 0; ri < gridRows; ri++) { + const row = cells[ri]; + const cellTop = yTop + facetColHeaderBand; + for (let ci = 0; ci < row.length; ci++) { + const cell = row[ci]; + const sr = scoped[ri][ci]; + const n = ri * gridCols + ci + 1; + const xName = n === 1 ? 'xaxis' : `xaxis${n}`; + const yName = n === 1 ? 'yaxis' : `yaxis${n}`; + const xRef = n === 1 ? 'x' : `x${n}`; + const yRef = n === 1 ? 'y' : `y${n}`; + + const cellLeft = ci * (cellW + CELL_GAP_X); + const barX0 = cellLeft + catW; + const barX1 = barX0 + barW; + const catNames = sr.map(r => r.cat); + const yDomainTop = cellTop + HEADER_H; + const yDomainBottom = yDomainTop + sr.length * rowStep; + + layout[xName] = { + domain: [barX0 / totalW, barX1 / totalW], + anchor: yRef, + rangemode: isDiverging ? 'normal' : 'tozero', + zeroline: true, zerolinecolor: '#ddd', + showgrid: false, showticklabels: false, + }; + layout[yName] = { + domain: [1 - yDomainBottom / totalH, 1 - yDomainTop / totalH], + anchor: xRef, + type: 'category', + categoryorder: 'array', categoryarray: catNames, + autorange: 'reversed', + showgrid: false, + tickfont: { size: fontSize }, + // Category names render as our OWN annotations (below), + // not native tick labels: Plotly's category axis has no + // `labelLimit`-style truncation, so a name longer than + // `catW` would just overflow past the figure's own left + // edge (clipped by the canvas) instead of ellipsizing — + // annotations let us truncate deterministically to fit. + showticklabels: false, + automargin: false, + ticklen: 0, + }; + + if (colorField && allColorValues.length > 0) { + for (const cv of allColorValues) { + const xs = sr.map(r => r.isOthers ? 0 : (r.byColor?.get(cv) ?? 0)); + if (xs.every(v => v === 0)) continue; + traces.push({ + type: 'bar', orientation: 'h', + xaxis: xRef, yaxis: yRef, + name: cv, + legendgroup: cv, + showlegend: !legendSeen.has(cv), + x: xs, y: catNames, + marker: { color: palette[(colorIdx.get(cv) ?? 0) % palette.length] }, + hovertemplate: `%{y}
${cv}: %{x}`, + }); + legendSeen.add(cv); + } + const othersXs = sr.map(r => r.isOthers ? r.value : 0); + if (othersXs.some(v => v !== 0)) { + traces.push({ + type: 'bar', orientation: 'h', + xaxis: xRef, yaxis: yRef, + name: 'Others', legendgroup: 'Others', showlegend: false, + x: othersXs, y: catNames, + marker: { color: OTHERS_GRAY }, + hoverinfo: 'skip', + }); + } + } else { + const vals = sr.map(r => r.value); + const finite = vals.filter(Number.isFinite); + const vmin = finite.length ? Math.min(...finite, 0) : 0; + const vmax = finite.length ? Math.max(...finite) : 1; + const colors = sr.map(r => { + if (r.isOthers) return OTHERS_GRAY; + if (isDiverging) { + const span = Math.max(Math.abs(vmin), Math.abs(vmax)) || 1; + const t = r.value / span; // -1..1 + return t >= 0 ? lerpHex(DIV_MID, DIV_HIGH, t) : lerpHex(DIV_MID, DIV_LOW, -t); + } + const t = (r.value - vmin) / ((vmax - vmin) || 1); + return lerpHex(SEQ_LOW, SEQ_HIGH, t); + }); + traces.push({ + type: 'bar', orientation: 'h', + xaxis: xRef, yaxis: yRef, + showlegend: false, + x: vals, y: catNames, + marker: { color: colors }, + hovertemplate: `%{y}
${xField}: %{x}`, + }); + } + + // ── Category / %/value text columns (annotations anchored + // to this cell's own category axis so each row lines up with + // its bar; see the `showticklabels: false` note above for + // why the category name is an annotation too). ── + const total = sr.reduce((s, r) => s + r.value, 0); + sr.forEach((r) => { + const color = r.isOthers ? OTHERS_GRAY : '#666'; + annotations.push({ + text: truncateToWidth(r.cat, catMaxUnits), + x: cellLeft / totalW, y: r.cat, + xref: 'paper', yref: yRef, + xanchor: 'left', yanchor: 'middle', showarrow: false, + font: { size: fontSize, color: r.isOthers ? OTHERS_GRAY : '#333' }, + }); + if (showPercent) { + const pct = Math.abs(total) > 1e-9 ? r.value / total : NaN; + annotations.push({ + text: Number.isFinite(pct) ? approxFormat(pct, '%') : '', + x: (barX1 + INTER_GAP + pctW) / totalW, y: r.cat, + xref: 'paper', yref: yRef, + xanchor: 'right', yanchor: 'middle', showarrow: false, + font: { size: fontSize, color: r.isOthers ? OTHERS_GRAY : '#41a25f' }, + }); + } + const valueX = showPercent ? barX1 + INTER_GAP + pctW + INTER_GAP + valW : barX1 + INTER_GAP + valW; + annotations.push({ + text: approxFormat(r.value), + x: valueX / totalW, y: r.cat, + xref: 'paper', yref: yRef, + xanchor: 'right', yanchor: 'middle', showarrow: false, + font: { size: fontSize, color }, + }); + }); + + // Sub-column headers (Category / % / Value), repeated per + // cell. `yanchor: 'top'` renders the label DOWNWARD from the + // cell's own top edge (into the reserved `HEADER_H` band) — + // `yanchor: 'bottom'` at the same y would need headroom above + // the plot area itself, clipping the very first row's headers + // against the image's top edge. + const headerY = 1 - cellTop / totalH; + annotations.push({ + text: yField, x: cellLeft / totalW, y: headerY, + xref: 'paper', yref: 'paper', xanchor: 'left', yanchor: 'top', showarrow: false, + font: { size: 10, color: '#999' }, + }); + if (showPercent) { + annotations.push({ + text: '%', x: (barX1 + INTER_GAP + pctW) / totalW, y: headerY, + xref: 'paper', yref: 'paper', xanchor: 'right', yanchor: 'top', showarrow: false, + font: { size: 10, color: '#999' }, + }); + } + annotations.push({ + text: xField, + x: (showPercent ? barX1 + INTER_GAP + pctW + INTER_GAP + valW : barX1 + INTER_GAP + valW) / totalW, + y: headerY, + xref: 'paper', yref: 'paper', xanchor: 'right', yanchor: 'top', showarrow: false, + font: { size: 10, color: '#999' }, + }); + + // Facet column header (top row of each grid row only). + if (colField && cell.colVal !== '') { + annotations.push({ + text: cell.colVal, + x: (cellLeft + cellW / 2) / totalW, y: 1 - yTop / totalH, + xref: 'paper', yref: 'paper', xanchor: 'center', yanchor: 'top', showarrow: false, + font: { size: 12, color: '#333' }, + }); + } + // Facet row header (rightmost cell in the row). + if (rowField && ci === row.length - 1 && cell.rowVal !== '') { + annotations.push({ + text: cell.rowVal, + x: (totalW - facetRowHeaderW / 2) / totalW, y: 1 - (cellTop + (yDomainBottom - yDomainTop) / 2) / totalH, + xref: 'paper', yref: 'paper', xanchor: 'center', yanchor: 'middle', textangle: 90, showarrow: false, + font: { size: 12, color: '#333' }, + }); + } + } + yTop += rowTotalHeights[ri] + CELL_GAP_Y; + } + + Object.assign(spec, { + data: traces, + layout: { ...layout, annotations, barmode: colorField ? 'stack' : undefined }, + _width: Math.round(totalW), + _height: Math.round(totalH), + }); + delete spec.mark; + delete spec.encoding; + }, + properties: [ + { key: 'maxRows', label: 'Max Rows', type: 'continuous', min: 5, max: 100, step: 1, defaultValue: 20 } as ChartPropertyDef, + { + key: 'showPercent', label: '% of total', type: 'binary', defaultValue: false, + check: (ctx) => { + const mcs = ctx.channelSemantics?.x; + if (!mcs?.field || mcs.type !== 'quantitative' || mcs.aggregationDefault === 'average') { + return { applicable: false }; + } + let sum = 0, hasNeg = false, hasPos = false, count = 0; + for (const row of ctx.data ?? []) { + const v = row[mcs.field]; + if (typeof v !== 'number' || !isFinite(v)) continue; + count++; + if (v < 0) hasNeg = true; else if (v > 0) hasPos = true; + sum += v; + } + return { applicable: count > 0 && !(hasNeg && hasPos) && Math.abs(sum) > 0 }; + }, + } as ChartPropertyDef, + ], +}; diff --git a/packages/flint-js/src/plotly/templates/bar.ts b/packages/flint-js/src/plotly/templates/bar.ts new file mode 100644 index 00000000..5f026123 --- /dev/null +++ b/packages/flint-js/src/plotly/templates/bar.ts @@ -0,0 +1,408 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Bar Chart template. + * + * Mirrors the Chart.js Bar template's decisions (category detection, + * ordinal sort order, zero baseline, horizontal transposition), expressed + * as a Plotly `bar` trace: + * CJS: { type: 'bar', data: { labels, datasets[] }, options: { indexAxis } } + * PL: { data: [{ type: 'bar', x, y, orientation }], layout: { xaxis, yaxis } } + */ + +import { ChartTemplateDef, ChartPropertyDef, EncodingActionDef } from '../../core/types'; +import { extractCategories, resolveCategoryOrder, buildCategoryAlignedData, detectAxes, groupBy, getPlotlyPalette, getSeriesColor } from './utils'; +import { detectBandedAxisFromSemantics, detectBandedAxisForceDiscrete } from '../../core/axis-detection'; +import { planBandDodge } from '../../core/band-dodge'; +import { makeSortAction } from '../../core/encoding-actions'; + +/** Corner-radius property shared by the Plotly bar templates (px, matches VL). */ +const BAR_CORNER_RADIUS: ChartPropertyDef = { + key: 'cornerRadius', label: 'Corners', type: 'continuous', + min: 0, max: 15, step: 1, defaultValue: 0, +}; + +export const plBarChartDef: ChartTemplateDef = { + chart: 'Bar Chart', + template: { mark: 'bar', encoding: {} }, + channels: ['x', 'y', 'color', 'opacity', 'column', 'row'], + markCognitiveChannel: 'length', + declareLayoutMode: (cs, table) => { + const result = detectBandedAxisFromSemantics(cs, table, { preferAxis: 'x' }); + return { + axisFlags: result ? { [result.axis]: { banded: true } } : { x: { banded: true } }, + resolvedTypes: result?.resolvedTypes, + }; + }, + instantiate: (spec, ctx) => { + const { channelSemantics, table, chartProperties } = ctx; + const { categoryAxis, valueAxis } = detectAxes(channelSemantics); + + const catField = channelSemantics[categoryAxis]?.field; + const valField = channelSemantics[valueAxis]?.field; + if (!catField || !valField) return; + + const catCS = channelSemantics[categoryAxis]; + const catEnc = ctx.encodings?.[categoryAxis]; + // `sortBy` from the Sort action is the measure CHANNEL ('x'|'y'); map it + // to its field so we can order categories by that measure. + const sortByField = catEnc?.sortBy ? channelSemantics[catEnc.sortBy]?.field : undefined; + const categories = resolveCategoryOrder(table, catField, { + ordinalSortOrder: catCS?.ordinalSortOrder, + sortBy: sortByField, + sortOrder: catEnc?.sortOrder, + }); + const values = buildCategoryAlignedData(table, catField, valField, categories); + + const isHorizontal = categoryAxis === 'y'; + const palette = getPlotlyPalette(ctx); + const cornerRadius = Number(chartProperties?.cornerRadius ?? 0); + + const catAxisSpec = { + type: 'category' as const, + categoryorder: 'array' as const, + categoryarray: categories, + title: { text: catField }, + }; + const valCS = channelSemantics[valueAxis]; + // Bars encode length — include zero unless the semantic decision says otherwise. + const includeZero = valCS?.zero ? valCS.zero.zero !== false : true; + const valAxisSpec = { + title: { text: valField }, + rangemode: (includeZero ? 'tozero' : 'normal') as 'tozero' | 'normal', + }; + + const figure: any = { + data: [{ + type: 'bar', + name: valField, + ...(isHorizontal + ? { x: values, y: categories, orientation: 'h' } + : { x: categories, y: values }), + marker: { + color: getSeriesColor(palette, 0), + ...(cornerRadius > 0 ? { cornerradius: cornerRadius } : {}), + }, + }], + layout: { + bargap: 0.2, + ...(isHorizontal + ? { xaxis: valAxisSpec, yaxis: catAxisSpec } + : { xaxis: catAxisSpec, yaxis: valAxisSpec }), + showlegend: false, + }, + }; + + Object.assign(spec, figure); + delete spec.mark; + delete spec.encoding; + }, + properties: [BAR_CORNER_RADIUS], + encodingActions: [makeSortAction()] as EncodingActionDef[], +}; + +// ─── Stacked Bar Chart ────────────────────────────────────────────────────── + +/** + * Plotly Stacked Bar Chart — one trace per `color` group, `layout.barmode: + * 'stack'`. Plotly stacks traces natively by matching x/category positions, + * so (unlike Chart.js/ECharts) no manual per-band accumulation is needed. + */ +export const plStackedBarChartDef: ChartTemplateDef = { + chart: 'Stacked Bar Chart', + template: { mark: 'bar', encoding: {} }, + channels: ['x', 'y', 'color', 'column', 'row'], + markCognitiveChannel: 'length', + declareLayoutMode: (cs, table) => { + const result = detectBandedAxisFromSemantics(cs, table, { preferAxis: 'x' }); + return { + axisFlags: result ? { [result.axis]: { banded: true } } : { x: { banded: true } }, + resolvedTypes: result?.resolvedTypes, + paramOverrides: { continuousMarkCrossSection: { x: 20, y: 20, seriesCountAxis: 'auto' } }, + }; + }, + instantiate: (spec, ctx) => { + const { channelSemantics, table, chartProperties } = ctx; + const { categoryAxis, valueAxis } = detectAxes(channelSemantics); + const colorField = channelSemantics.color?.field; + + const catField = channelSemantics[categoryAxis]?.field; + const valField = channelSemantics[valueAxis]?.field; + if (!catField || !valField) return; + + const catCS = channelSemantics[categoryAxis]; + const catEnc = ctx.encodings?.[categoryAxis]; + const sortByField = catEnc?.sortBy ? channelSemantics[catEnc.sortBy]?.field : undefined; + const categories = resolveCategoryOrder(table, catField, { + ordinalSortOrder: catCS?.ordinalSortOrder, sortBy: sortByField, sortOrder: catEnc?.sortOrder, + }); + const isHorizontal = categoryAxis === 'y'; + const palette = getPlotlyPalette(ctx, 'color'); + // 100%-stacked toggle (Stack property): Plotly normalizes each band to + // 100% via `barnorm: 'percent'`; the value-axis title then reflects %. + const normalize = colorField && chartProperties?.stackMode === 'normalize'; + + const traces: any[] = []; + if (colorField) { + let i = 0; + for (const [name, rows] of groupBy(table, colorField)) { + const values = buildCategoryAlignedData(rows, catField, valField, categories); + traces.push({ + type: 'bar', + name, + ...(isHorizontal ? { x: values, y: categories, orientation: 'h' } : { x: categories, y: values }), + marker: { color: getSeriesColor(palette, i) }, + }); + i++; + } + } else { + const values = buildCategoryAlignedData(table, catField, valField, categories); + traces.push({ + type: 'bar', + name: valField, + ...(isHorizontal ? { x: values, y: categories, orientation: 'h' } : { x: categories, y: values }), + marker: { color: getSeriesColor(palette, 0) }, + }); + } + + const catAxisSpec = { type: 'category' as const, categoryorder: 'array' as const, categoryarray: categories, title: { text: catField } }; + const valCS = channelSemantics[valueAxis]; + const includeZero = valCS?.zero ? valCS.zero.zero !== false : true; + const valAxisSpec = { title: { text: valField }, rangemode: (includeZero ? 'tozero' : 'normal') as 'tozero' | 'normal' }; + + Object.assign(spec, { + data: traces, + layout: { + barmode: 'stack', + ...(normalize ? { barnorm: 'percent' } : {}), + bargap: 0.2, + ...(isHorizontal ? { xaxis: valAxisSpec, yaxis: catAxisSpec } : { xaxis: catAxisSpec, yaxis: valAxisSpec }), + showlegend: !!colorField, + }, + }); + delete spec.mark; + delete spec.encoding; + }, + properties: [ + { key: 'stackMode', label: 'Stack', type: 'discrete', + check: (ctx) => ({ applicable: !!ctx.encodings.color?.field }), + options: [ + { value: undefined, label: 'Stacked (default)' }, + { value: 'normalize', label: 'Normalize (100%)' }, + ] } as ChartPropertyDef, + ], + encodingActions: [makeSortAction()] as EncodingActionDef[], +}; + +// ─── Grouped Bar Chart ────────────────────────────────────────────────────── + +/** + * Plotly Grouped Bar Chart — one trace per `group`/`color` value, + * `layout.barmode: 'group'`. Plotly dodges the bars natively within each + * category band (equal-width lanes), the native equivalent of the Chart.js/ + * ECharts manual band-dodge planner. + */ +export const plGroupedBarChartDef: ChartTemplateDef = { + chart: 'Grouped Bar Chart', + template: { mark: 'bar', encoding: {} }, + channels: ['x', 'y', 'group', 'color', 'column', 'row'], + markCognitiveChannel: 'length', + declareLayoutMode: (cs, table) => { + const result = detectBandedAxisForceDiscrete(cs, table, { preferAxis: 'x' }); + return { + axisFlags: result ? { [result.axis]: { banded: true } } : { x: { banded: true } }, + resolvedTypes: result?.resolvedTypes, + paramOverrides: { continuousMarkCrossSection: { x: 20, y: 20, seriesCountAxis: 'auto' } }, + }; + }, + instantiate: (spec, ctx) => { + const { channelSemantics, table } = ctx; + const { categoryAxis, valueAxis } = detectAxes(channelSemantics); + const groupField = channelSemantics.group?.field || channelSemantics.color?.field; + + const catField = channelSemantics[categoryAxis]?.field; + const valField = channelSemantics[valueAxis]?.field; + if (!catField || !valField) return; + + const catCS = channelSemantics[categoryAxis]; + const catEnc = ctx.encodings?.[categoryAxis]; + const sortByField = catEnc?.sortBy ? channelSemantics[catEnc.sortBy]?.field : undefined; + const categories = resolveCategoryOrder(table, catField, { + ordinalSortOrder: catCS?.ordinalSortOrder, sortBy: sortByField, sortOrder: catEnc?.sortOrder, + }); + const isHorizontal = categoryAxis === 'y'; + const palette = getPlotlyPalette(ctx, 'group'); + + // When the group is redundant/nested with the category axis (group == x, + // or a 1:1 pairing), no band holds more than one group value — there is + // nothing to dodge. Plotly's native `barmode: 'group'` would still + // reserve a lane per group and leave each real bar as a shifted sliver. + // Fall back to `barmode: 'overlay'` so each band shows one centered, + // full-width colored bar (like a colored bar chart), keeping the legend. + const degenerateGroup = !!groupField && planBandDodge(table, catField, groupField).maxPerBand <= 1; + + const traces: any[] = []; + if (groupField) { + let i = 0; + for (const [name, rows] of groupBy(table, groupField)) { + const values = buildCategoryAlignedData(rows, catField, valField, categories); + traces.push({ + type: 'bar', + name, + ...(isHorizontal ? { x: values, y: categories, orientation: 'h' } : { x: categories, y: values }), + marker: { color: getSeriesColor(palette, i) }, + }); + i++; + } + } else { + const values = buildCategoryAlignedData(table, catField, valField, categories); + traces.push({ + type: 'bar', + name: valField, + ...(isHorizontal ? { x: values, y: categories, orientation: 'h' } : { x: categories, y: values }), + marker: { color: getSeriesColor(palette, 0) }, + }); + } + + const catAxisSpec = { type: 'category' as const, categoryorder: 'array' as const, categoryarray: categories, title: { text: catField } }; + const valCS = channelSemantics[valueAxis]; + const includeZero = valCS?.zero ? valCS.zero.zero !== false : true; + const valAxisSpec = { title: { text: valField }, rangemode: (includeZero ? 'tozero' : 'normal') as 'tozero' | 'normal' }; + + Object.assign(spec, { + data: traces, + layout: { + barmode: degenerateGroup ? 'overlay' : 'group', + bargap: 0.2, + ...(isHorizontal ? { xaxis: valAxisSpec, yaxis: catAxisSpec } : { xaxis: catAxisSpec, yaxis: valAxisSpec }), + showlegend: !!groupField, + }, + }); + delete spec.mark; + delete spec.encoding; + }, + encodingActions: [makeSortAction()] as EncodingActionDef[], +}; + +// ─── Pyramid Chart ────────────────────────────────────────────────────────── + +/** + * Plotly Pyramid Chart (population pyramid) — two mirrored horizontal bar + * traces sharing one category axis, one side negated so the bars extend left + * and right from a shared zero (`barmode: 'overlay'`; `x` axis ticks show + * absolute values via `tickformat`/hover text so negative bars still read as + * positive magnitudes). + */ +export const plPyramidChartDef: ChartTemplateDef = { + chart: 'Pyramid Chart', + template: { mark: 'bar', encoding: {} }, + channels: ['x', 'y', 'color'], + markCognitiveChannel: 'length', + declareLayoutMode: () => ({ axisFlags: { y: { banded: true } } }), + instantiate: (spec, ctx) => { + const { channelSemantics, table } = ctx; + const xCS = channelSemantics.x; + const yCS = channelSemantics.y; + const xField = xCS?.field; + const yField = yCS?.field; + if (!xField || !yField) return; + + const yDiscrete = yCS?.type === 'nominal' || yCS?.type === 'ordinal'; + const catField = yDiscrete ? yField : xField; + const valField = yDiscrete ? xField : yField; + const colorField = channelSemantics.color?.field || channelSemantics.group?.field; + + const catCS = yDiscrete ? yCS : xCS; + const categories = extractCategories(table, catField!, catCS?.ordinalSortOrder); + + const sumPerCategory = (predicate?: (row: any) => boolean): number[] => { + const valueMap = new Map(); + for (const row of table) { + if (predicate && !predicate(row)) continue; + const cat = String(row[catField!] ?? ''); + const v = row[valField!]; + if (v != null && !isNaN(Number(v))) valueMap.set(cat, (valueMap.get(cat) ?? 0) + Number(v)); + } + return categories.map(cat => valueMap.get(cat) ?? 0); + }; + + let leftPos: number[]; + let rightPos: number[]; + let leftName: string | undefined; + let rightName: string | undefined; + + if (colorField && table.length > 0) { + const groups = [...new Set(table.map(r => r[colorField]))]; + const leftGroup = groups[0]; + const rightGroup = groups.length > 1 ? groups[1] : groups[0]; + leftPos = sumPerCategory(row => String(row[colorField] ?? '') === String(leftGroup ?? '')); + rightPos = sumPerCategory(row => String(row[colorField] ?? '') === String(rightGroup ?? '')); + leftName = String(leftGroup); + rightName = String(rightGroup); + } else { + const values = sumPerCategory(); + leftPos = values; + rightPos = values; + } + + const leftData = leftPos.map(v => -v); + const maxAbs = Math.max(0, ...leftPos, ...rightPos); + const palette = getPlotlyPalette(ctx, 'color'); + + Object.assign(spec, { + data: [ + { + type: 'bar', orientation: 'h', name: leftName, + x: leftData, y: categories, + customdata: leftPos, + hovertemplate: `%{y}
${leftName ?? catField}: %{customdata}`, + marker: { color: getSeriesColor(palette, 0) }, + }, + { + type: 'bar', orientation: 'h', name: rightName, + x: rightPos, y: categories, + hovertemplate: `%{y}
${rightName ?? catField}: %{x}`, + marker: { color: getSeriesColor(palette, 1) }, + }, + ], + layout: { + barmode: 'overlay', + bargap: 0.15, + xaxis: { + title: { text: valField }, + range: maxAbs > 0 ? [-maxAbs * 1.05, maxAbs * 1.05] : undefined, + tickformat: undefined, + // Show absolute values on the tick labels (both sides read as magnitude). + tickvals: undefined, + }, + yaxis: { type: 'category', categoryorder: 'array', categoryarray: categories, title: { text: catField } }, + showlegend: leftName !== rightName, + }, + }); + delete spec.mark; + delete spec.encoding; + }, + postProcess: (figure) => { + // Absolute-value tick labels: compute explicit tickvals/ticktext so the + // negated left side still reads as a positive magnitude. + const xaxis = figure.layout?.xaxis; + if (xaxis?.range) { + const maxAbs = Math.max(Math.abs(xaxis.range[0]), Math.abs(xaxis.range[1])); + const step = maxAbs > 0 ? niceStep(maxAbs) : 1; + const vals: number[] = []; + for (let v = -Math.floor(maxAbs / step) * step; v <= maxAbs + 1e-9; v += step) vals.push(Math.round(v * 1e6) / 1e6); + xaxis.tickvals = vals; + xaxis.ticktext = vals.map(v => String(Math.abs(v))); + } + }, + properties: [] as ChartPropertyDef[], +}; + +function niceStep(maxAbs: number): number { + const target = maxAbs / 4; + const pow = Math.pow(10, Math.floor(Math.log10(Math.max(target, 1e-9)))); + const frac = target / pow; + const nice = frac <= 1 ? 1 : frac <= 2 ? 2 : frac <= 5 ? 5 : 10; + return nice * pow; +} diff --git a/packages/flint-js/src/plotly/templates/boxplot.ts b/packages/flint-js/src/plotly/templates/boxplot.ts new file mode 100644 index 00000000..dbd5904e --- /dev/null +++ b/packages/flint-js/src/plotly/templates/boxplot.ts @@ -0,0 +1,113 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Boxplot template. + * + * Native `box` trace: pass raw y-values with a matching category `x` array + * and Plotly computes the five-number summary (quartiles, whiskers, outliers) + * itself — like Vega-Lite's `mark: "boxplot"`, unlike ECharts/Chart.js which + * must precompute the summary client-side. + * + * Grouped boxplots (a `color` field subdividing the category axis) use + * `layout.boxmode: 'group'` — Plotly's native per-category dodge, the + * equivalent of the other backends' manual band-dodge planner. + * + * NOTE: Plotly's box trace does not expose a native "extend whiskers to + * min/max" mode (only its quartile-computation algorithm is configurable); + * unlike the Vega-Lite/ECharts boxplot templates this template always uses + * Tukey (1.5×IQR) whiskers. `showOutliers` toggles the outlier points. + */ + +import { ChartTemplateDef, ChartPropertyDef } from '../../core/types'; +import { isDiscreteType, extractCategories, groupBy, getPlotlyPalette, getSeriesColor } from './utils'; +import { detectBandedAxisForceDiscrete } from '../../core/axis-detection'; +import { planBandDodge } from '../../core/band-dodge'; + +export const plBoxplotDef: ChartTemplateDef = { + chart: 'Boxplot', + template: { mark: 'boxplot', encoding: {} }, + channels: ['x', 'y', 'color', 'column', 'row'], + markCognitiveChannel: 'position', + declareLayoutMode: (cs, table) => { + if (!cs.x?.field || !cs.y?.field) return {}; + const result = detectBandedAxisForceDiscrete(cs, table, { preferAxis: 'x' }); + if (!result) return {}; + return { + axisFlags: { [result.axis]: { banded: true } }, + resolvedTypes: result.resolvedTypes, + paramOverrides: { defaultBandSize: 28 }, + }; + }, + instantiate: (spec, ctx) => { + const { channelSemantics, table, chartProperties } = ctx; + const xCS = channelSemantics.x; + const yCS = channelSemantics.y; + const colorField = channelSemantics.color?.field; + if (!xCS?.field || !yCS?.field) return; + + const xIsDiscrete = isDiscreteType(xCS.type); + const yIsDiscrete = isDiscreteType(yCS.type); + const catAxis: 'x' | 'y' = (yIsDiscrete && !xIsDiscrete) ? 'y' : 'x'; + const valAxis: 'x' | 'y' = catAxis === 'x' ? 'y' : 'x'; + const catField = channelSemantics[catAxis]!.field!; + const valField = channelSemantics[valAxis]!.field!; + const isHorizontal = catAxis === 'y'; + + const categories = extractCategories(table, catField, channelSemantics[catAxis]?.ordinalSortOrder); + const showOutliers = chartProperties?.showOutliers !== false; + const boxpoints = showOutliers ? 'outliers' : false; + const palette = getPlotlyPalette(ctx, 'color'); + + const makeTrace = (name: string | undefined, rows: any[], colorIdx: number) => { + const cats = rows.map((r: any) => String(r[catField] ?? '')); + const vals = rows.map((r: any) => Number(r[valField])); + return { + type: 'box', + ...(name != null ? { name } : {}), + ...(isHorizontal ? { y: cats, x: vals } : { x: cats, y: vals }), + boxpoints, + marker: { color: getSeriesColor(palette, colorIdx), size: 3 }, + line: { color: getSeriesColor(palette, colorIdx) }, + }; + }; + + const traces: any[] = []; + if (colorField) { + let i = 0; + for (const [name, rows] of groupBy(table, colorField)) { traces.push(makeTrace(name, rows, i)); i++; } + } else { + traces.push(makeTrace(undefined, table, 0)); + } + + // Degenerate color (color re-encodes the category axis, or a 1:1 / + // sparse mapping where every band holds at most one colour) must NOT + // dodge into per-lane slivers with a redundant legend — collapse to + // one full-width box per band. `boxmode: 'group'` reserves a lane per + // trace, so drop it (default overlay) and hide the redundant legend; + // the boxes stay colour-coded but sit one per band. Genuine sub-group + // colour (maxPerBand > 1) keeps the native grouped dodge. + const redundantColor = !!colorField + && planBandDodge(table, catField, colorField).maxPerBand <= 1; + // Collapsed boxes sit one per band, so widen them to fill the band + // (Plotly's default overlay box is only ~40% of the band). + if (redundantColor) for (const t of traces) t.width = 0.8; + + const catAxisSpec = { type: 'category' as const, categoryorder: 'array' as const, categoryarray: categories, title: { text: catField } }; + const valAxisSpec = { title: { text: valField }, zeroline: false }; + + Object.assign(spec, { + data: traces, + layout: { + boxmode: (colorField && !redundantColor) ? 'group' : undefined, + ...(isHorizontal ? { yaxis: catAxisSpec, xaxis: valAxisSpec } : { xaxis: catAxisSpec, yaxis: valAxisSpec }), + showlegend: !!colorField && !redundantColor, + }, + }); + delete spec.mark; + delete spec.encoding; + }, + properties: [ + { key: 'showOutliers', label: 'Outliers', type: 'binary', defaultValue: true } as ChartPropertyDef, + ], +}; diff --git a/packages/flint-js/src/plotly/templates/bullet.ts b/packages/flint-js/src/plotly/templates/bullet.ts new file mode 100644 index 00000000..018a8370 --- /dev/null +++ b/packages/flint-js/src/plotly/templates/bullet.ts @@ -0,0 +1,149 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Bullet Chart template. + * + * One row per KPI: qualitative gray zones (quarters of that row's own goal), + * a value bar colored by goal attainment, and a target tick. Plotly has no + * native bullet mark, so each element is drawn with an explicit `base` (the + * bar's start offset, independent of any stacking mode) and + * `layout.barmode: 'overlay'` so the zones and the value bar sit concentric + * rather than dodged — the target tick is a `scatter` trace with + * `marker.symbol: 'line-ns'`, Plotly's built-in vertical-tick glyph. + */ + +import { ChartTemplateDef } from '../../core/types'; +import { extractCategories } from './utils'; + +const ZONE_GRAYS = ['#e2e2e2', '#ececec', '#f5f5f5']; +// Plotly's native "good/bad" semantics: the indicator delta uses #3D9970 +// (positive) and #FF4136 (negative). Reusing that pair for bullet attainment +// keeps the value bar consistent with Plotly's own palette (and the waterfall). +const STATUS_COLORS = { below: '#FF4136', met: '#3D9970' }; + +export const plBulletChartDef: ChartTemplateDef = { + chart: 'Bullet Chart', + template: { mark: 'bar', encoding: {} }, + channels: ['y', 'x', 'goal', 'color', 'column', 'row'], + markCognitiveChannel: 'length', + declareLayoutMode: () => ({ axisFlags: { y: { banded: true } } }), + instantiate: (spec, ctx) => { + const { channelSemantics, table } = ctx; + const labelField = channelSemantics.y?.field; + const valueField = channelSemantics.x?.field; + const goalField = channelSemantics.goal?.field; + if (!labelField || !valueField || table.length === 0) return; + + const categories = extractCategories(table, labelField, channelSemantics.y?.ordinalSortOrder); + const byCat = new Map(); + for (const r of table) byCat.set(String(r[labelField] ?? ''), r); + const valueOf = (cat: string) => Number(byCat.get(cat)?.[valueField]); + const goalOf = (cat: string) => goalField != null ? Number(byCat.get(cat)?.[goalField]) : NaN; + + const quarter = categories.map(cat => { + const g = goalOf(cat); + return Number.isFinite(g) && g > 0 ? g / 4 : 0; + }); + + const zoneTraces = [0, 1, 2].map(i => ({ + type: 'bar', + name: `__zone${i}`, + orientation: 'h' as const, + showlegend: false, + hoverinfo: 'skip' as const, + base: quarter.map(q => q * i), + x: quarter, + y: categories, + width: 0.62, + marker: { color: ZONE_GRAYS[i] }, + })); + + const valueTrace = { + type: 'bar', + name: 'value', + orientation: 'h' as const, + showlegend: false, + base: categories.map(() => 0), + x: categories.map(cat => { const v = valueOf(cat); return Number.isFinite(v) ? v : 0; }), + y: categories, + width: 0.32, + marker: { + color: categories.map(cat => { + const v = valueOf(cat); const g = goalOf(cat); + const met = Number.isFinite(g) ? v >= g : true; + return met ? STATUS_COLORS.met : STATUS_COLORS.below; + }), + }, + hovertemplate: `%{y}
${valueField}: %{x}`, + }; + + const traces: any[] = [...zoneTraces, valueTrace]; + + if (goalField) { + // Target tick scales with the band height (yStep) so it stays + // proportional to the bars across canvas sizes, instead of a fixed + // 22px that looks tiny on a tall chart and huge on a short one. + const bandPx = ctx.layout.yStep || 30; + const tickSize = Math.max(14, Math.min(48, Math.round(bandPx * 0.4))); + traces.push({ + type: 'scatter', + mode: 'markers', + name: 'Target', + x: categories.map(cat => goalOf(cat)), + y: categories, + showlegend: false, + marker: { symbol: 'line-ns', size: tickSize, line: { color: '#1a1a1a', width: 2.5 } }, + hovertemplate: `%{y}
${goalField}: %{x}`, + }); + // No legend entry for the target tick: the mark itself is the + // universally understood bullet-chart target line, and its + // `line-ns` glyph renders as an oversized black bar in the legend + // regardless of marker size. Only the attainment colors below + // need explaining. + // Legend-only swatches for the value bar's attainment colors + // (the bar itself carries a per-point color array, which Plotly's + // legend cannot summarize on its own). A single zero-width, + // zero-opacity bar at an existing category — a truly empty trace + // (`x: []`) does not render a legend entry at all. + traces.push( + { type: 'bar', name: 'Meets target', x: [0], y: [categories[0]], width: 0, hoverinfo: 'skip', marker: { color: STATUS_COLORS.met } }, + { type: 'bar', name: 'Below target', x: [0], y: [categories[0]], width: 0, hoverinfo: 'skip', marker: { color: STATUS_COLORS.below } }, + ); + } + + Object.assign(spec, { + data: traces, + layout: { + barmode: 'overlay', + xaxis: { title: { text: valueField }, rangemode: 'tozero' }, + yaxis: { type: 'category', categoryorder: 'array', categoryarray: categories, title: { text: labelField } }, + showlegend: !!goalField, + // Vertical (default) legend layout needs plot-height room per + // entry; a bullet chart is often short and wide (few rows), so + // a horizontal legend below the plot fits these 3 longer + // labels ("Target" / "Meets target" / "Below target") more + // reliably than trying to widen a narrow side gutter. + legend: { orientation: 'h', font: { size: 11 }, x: 0.5, xanchor: 'center', y: -0.32, yanchor: 'top' }, + }, + }); + delete spec.mark; + delete spec.encoding; + }, + postProcess: (figure) => { + // Reserve room below the plot for the horizontal legend row instead of + // the shared side gutter (sized for a typical short color legend, + // too narrow for these longer labels). + if (figure.layout?.showlegend) { + if (typeof figure._width === 'number') { + figure._width = Math.max(figure._width - 60, 320); + figure.layout.width = figure._width; + } + if (typeof figure._height === 'number') { + figure._height += 72; + figure.layout.height = figure._height; + } + if (figure.layout.margin) figure.layout.margin.b = (figure.layout.margin.b ?? 0) + 72; + } + }, +}; diff --git a/packages/flint-js/src/plotly/templates/bump.ts b/packages/flint-js/src/plotly/templates/bump.ts new file mode 100644 index 00000000..2f655738 --- /dev/null +++ b/packages/flint-js/src/plotly/templates/bump.ts @@ -0,0 +1,97 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Bump Chart template. + * + * A rank-over-time line chart: one line per entity, y = rank (reversed so + * rank 1 sits at the top). Reuses the same trace-building shape as + * `plLineChartDef`; the only structural difference is the reversed rank axis. + */ + +import { ChartTemplateDef } from '../../core/types'; +import { + isDiscreteType, extractCategories, groupBy, buildCategoryAlignedData, + coerceIsoDateForPlotly, getPlotlyPalette, getSeriesColor, sortByOrder, +} from './utils'; +import { toTypeString } from '../../core/field-semantics'; + +const RANK_SEMANTIC_TYPES = new Set(['Rank', 'Score', 'Level']); + +export const plBumpChartDef: ChartTemplateDef = { + chart: 'Bump Chart', + template: { mark: 'line', encoding: {} }, + channels: ['x', 'y', 'color', 'detail', 'column', 'row'], + markCognitiveChannel: 'position', + declareLayoutMode: () => ({ + paramOverrides: { continuousMarkCrossSection: { x: 80, y: 20, seriesCountAxis: 'auto' }, facetAspectRatioResistance: 0.4 }, + }), + instantiate: (spec, ctx) => { + const { channelSemantics, table, semanticTypes } = ctx; + const xCS = channelSemantics.x; + const yCS = channelSemantics.y; + const groupField = channelSemantics.color?.field ?? channelSemantics.detail?.field; + if (!xCS?.field || !yCS?.field) return; + const xField = xCS.field; + const yField = yCS.field; + + const xSemType = (xField && toTypeString(semanticTypes?.[xField])) || ''; + const ySemType = (yField && toTypeString(semanticTypes?.[yField])) || ''; + const xIsRank = RANK_SEMANTIC_TYPES.has(xSemType); + const yIsRank = RANK_SEMANTIC_TYPES.has(ySemType); + let rankAxis: 'x' | 'y'; + if (yIsRank && !xIsRank) rankAxis = 'y'; + else if (xIsRank && !yIsRank) rankAxis = 'x'; + else if (isDiscreteType(xCS.type) && !isDiscreteType(yCS.type)) rankAxis = 'y'; + else if (isDiscreteType(yCS.type) && !isDiscreteType(xCS.type)) rankAxis = 'x'; + else rankAxis = 'y'; + + const xIsDiscrete = isDiscreteType(xCS.type); + const xIsTemporal = xCS.type === 'temporal'; + const mapX = (raw: unknown) => (xIsTemporal ? coerceIsoDateForPlotly(raw) : raw); + const categories = xIsDiscrete ? extractCategories(table, xField, xCS.ordinalSortOrder) : undefined; + + const palette = getPlotlyPalette(ctx, 'color'); + const traces: any[] = []; + const makeTrace = (name: string, rows: any[], idx: number) => { + // x is rank → the line must follow y's order, not x's raw order. + const orderedRows = (rankAxis === 'x') ? sortByOrder(rows, yField) : rows; + const xVals = xIsDiscrete ? categories! : orderedRows.map(r => mapX(r[xField])); + const yVals = xIsDiscrete + ? buildCategoryAlignedData(rows, xField, yField, categories!) + : orderedRows.map(r => (r[yField] == null ? null : r[yField])); + const color = getSeriesColor(palette, idx); + return { + type: 'scatter', + mode: 'lines+markers', + name, + x: xVals, y: yVals, + line: { color, shape: 'spline' as const, smoothing: 0.4 }, + marker: { color, size: 7 }, + }; + }; + + if (groupField) { + let i = 0; + for (const [name, rows] of groupBy(table, groupField)) { traces.push(makeTrace(name, rows, i)); i++; } + } else { + traces.push(makeTrace(yField, table, 0)); + } + + const xAxisSpec: any = { title: { text: xField } }; + if (xIsDiscrete) { xAxisSpec.type = 'category'; xAxisSpec.categoryorder = 'array'; xAxisSpec.categoryarray = categories; } + else if (xIsTemporal) xAxisSpec.type = 'date'; + + const yAxisSpec: any = { title: { text: yField } }; + if (rankAxis === 'y') yAxisSpec.autorange = 'reversed'; + + const figXAxis = rankAxis === 'x' ? { ...xAxisSpec, autorange: 'reversed' } : xAxisSpec; + + Object.assign(spec, { + data: traces, + layout: { xaxis: figXAxis, yaxis: yAxisSpec, showlegend: !!groupField }, + }); + delete spec.mark; + delete spec.encoding; + }, +}; diff --git a/packages/flint-js/src/plotly/templates/candlestick.ts b/packages/flint-js/src/plotly/templates/candlestick.ts new file mode 100644 index 00000000..a6f8097e --- /dev/null +++ b/packages/flint-js/src/plotly/templates/candlestick.ts @@ -0,0 +1,88 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Candlestick Chart template. + * + * Native `candlestick` trace: pass `x`, `open`, `high`, `low`, `close` and + * Plotly draws the OHLC bars with built-in up/down coloring — one of + * Plotly's strongest native chart types (the Vega-Lite equivalent is a + * layered rule+bar spec; ECharts needs a manual `[open, close, low, high]` + * reordering). + */ + +import { ChartTemplateDef, ChartPropertyDef } from '../../core/types'; +import { isDiscreteType } from './utils'; + +export const plCandlestickChartDef: ChartTemplateDef = { + chart: 'Candlestick Chart', + template: { mark: 'candlestick', encoding: {} }, + channels: ['x', 'open', 'high', 'low', 'close', 'column', 'row'], + markCognitiveChannel: 'position', + declareLayoutMode: () => ({ axisFlags: { x: { banded: true } } }), + instantiate: (spec, ctx) => { + const { channelSemantics, table, chartProperties } = ctx; + const xCS = channelSemantics.x; + const openField = channelSemantics.open?.field; + const highField = channelSemantics.high?.field; + const lowField = channelSemantics.low?.field; + const closeField = channelSemantics.close?.field; + if (!xCS?.field || !openField || !closeField) return; + const xField = xCS.field; + const xIsTemporal = xCS.type === 'temporal'; + const xIsDiscrete = isDiscreteType(xCS.type); + + const xVals = table.map((r: any) => r[xField]); + const open = table.map((r: any) => Number(r[openField])); + const close = table.map((r: any) => Number(r[closeField])); + const high = highField ? table.map((r: any) => Number(r[highField])) : open.map((o, i) => Math.max(o, close[i])); + const low = lowField ? table.map((r: any) => Number(r[lowField])) : open.map((o, i) => Math.min(o, close[i])); + + const traces: any[] = [{ + type: 'candlestick', + x: xVals, open, high, low, close, + increasing: { line: { color: '#06982d' } }, + decreasing: { line: { color: '#ae1325' } }, + }]; + + if (chartProperties?.showMA) { + const maWindow = Number(chartProperties.maWindow) || 5; + const ma = computeMA(close, maWindow); + traces.push({ + type: 'scatter', mode: 'lines', name: `MA${maWindow}`, + x: xVals, y: ma, + line: { width: 1.5, shape: 'spline' as const }, + }); + } + + const xAxisSpec: any = { title: { text: xField }, rangeslider: { visible: table.length > 60 } }; + if (xIsTemporal) xAxisSpec.type = 'date'; + else if (xIsDiscrete) { xAxisSpec.type = 'category'; } + + Object.assign(spec, { + data: traces, + layout: { + xaxis: xAxisSpec, + yaxis: { title: { text: 'Price' } }, + showlegend: !!chartProperties?.showMA, + }, + }); + delete spec.mark; + delete spec.encoding; + }, + properties: [ + { key: 'showMA', label: 'Moving average', type: 'binary', defaultValue: false } as ChartPropertyDef, + { key: 'maWindow', label: 'Average window', type: 'continuous', min: 3, max: 30, step: 1, defaultValue: 5 } as ChartPropertyDef, + ], +}; + +function computeMA(prices: number[], window: number): (number | null)[] { + const result: (number | null)[] = []; + for (let i = 0; i < prices.length; i++) { + if (i < window - 1) { result.push(null); continue; } + let sum = 0; + for (let j = i - window + 1; j <= i; j++) sum += prices[j]; + result.push(Math.round((sum / window) * 100) / 100); + } + return result; +} diff --git a/packages/flint-js/src/plotly/templates/choropleth.ts b/packages/flint-js/src/plotly/templates/choropleth.ts new file mode 100644 index 00000000..67745628 --- /dev/null +++ b/packages/flint-js/src/plotly/templates/choropleth.ts @@ -0,0 +1,135 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Choropleth template. + * + * Native `choropleth` trace: Plotly resolves `locations` through its own + * built-in atlas (US states / world countries) keyed by a short code + * (`locationmode`), so — unlike the Vega-Lite template, which joins the + * user's rows into a fetched TopoJSON via a `lookup` transform — no external + * geometry needs to be fetched or joined here. + * + * Data contract (unchanged from Vega-Lite): `id` carries the region name/ + * code, `color` the measure, optional `detail` a display label. Values are + * resolved through the SAME gazetteer as the Vega-Lite choropleth + * (`chart-types/geo.ts`) — just to a USPS/ISO-3 code instead of a numeric + * TopoJSON feature id — so a dataset that renders as a US or World map on + * one backend renders the same way on the other. + */ + +import { ChartTemplateDef, ChartPropertyDef } from '../../core/types'; +import { + resolveUsStateCode, resolveCountryCode, GeoCodeResolver, + inferChoroplethScope, semanticScope, pickMapScope, +} from '../../chart-types/geo'; +import { toTypeString } from '../../core/field-semantics'; + +// Plotly's own built-in named `'Blues'` colorscale runs dark→light as the +// value increases (z=0 → "rgb(5,10,172)" dark blue, z=1 → "rgb(220,220,220)" +// light gray) — the OPPOSITE of the light→dark sequential convention used +// everywhere else in this codebase (and by every other backend's default +// choropleth/heatmap ramp). For a choropleth that's actively misleading (the +// highest-value region reads as the *palest*), so this template uses an +// explicit ColorBrewer-style light→dark stop array instead of the `'Blues'` +// string. Plotly's stock `'RdBu'` (used for the diverging case below) is NOT +// affected — its low→mid→high stops already run blue→gray→red, matching the +// diverging convention — so it's used as-is. +const SEQUENTIAL_BLUES: Array<[number, string]> = [ + [0, '#eff3ff'], [0.25, '#bdd7e7'], [0.5, '#6baed6'], [0.75, '#3182bd'], [1, '#08519c'], +]; + +const regionProperty: ChartPropertyDef = { + key: 'region', + label: 'Region', + type: 'discrete', + options: [ + { value: 'auto', label: 'Auto-detect' }, + { value: 'us', label: 'United States' }, + { value: 'world', label: 'World' }, + ], + defaultValue: 'auto', +}; + +/** Configure `layout.geo` for the chosen scope (no projection controls — mirrors the VL Choropleth). */ +function buildGeoLayout(scope: 'us' | 'world'): any { + if (scope === 'us') { + return { + scope: 'usa', + projection: { type: 'albers usa' }, + showlakes: true, lakecolor: '#ffffff', + }; + } + return { + scope: 'world', + projection: { type: 'natural earth' }, + showframe: false, + showcoastlines: false, + showcountries: false, // borders drawn by the choropleth fill itself + }; +} + +export const plChoroplethDef: ChartTemplateDef = { + chart: 'Choropleth', + template: { mark: 'geoshape', encoding: {} }, + channels: ['id', 'color', 'detail'], + markCognitiveChannel: 'color', + instantiate: (spec, ctx) => { + const { channelSemantics, chartProperties, colorDecisions } = ctx; + const idField = channelSemantics.id?.field; + const colorField = channelSemantics.color?.field; + const labelField = channelSemantics.detail?.field ?? idField; + if (!idField) return; + + const rows = ctx.fullTable ?? ctx.table ?? []; + const semType = toTypeString(ctx.semanticTypes?.[idField]); + const semScope = semanticScope(semType); + const scope = pickMapScope(chartProperties, semScope, () => inferChoroplethScope(rows, idField)); + const codeResolver: GeoCodeResolver = scope === 'us' ? resolveUsStateCode : resolveCountryCode; + const locationmode = scope === 'us' ? 'USA-states' : 'ISO-3'; + + const locations: string[] = []; + const z: number[] = []; + const labels: string[] = []; + for (const r of rows) { + const code = codeResolver(r[idField]); + if (!code) continue; + const raw = colorField ? Number(r[colorField]) : undefined; + if (colorField && !Number.isFinite(raw)) continue; + locations.push(code); + z.push(colorField ? (raw as number) : 1); + labels.push(labelField ? String(r[labelField] ?? r[idField]) : String(r[idField])); + } + if (locations.length === 0) return; + + const decision = colorDecisions?.color ?? colorDecisions?.group; + const diverging = decision?.schemeType === 'diverging'; + + const geo = buildGeoLayout(scope); + const valueLabel = colorField ?? 'Value'; + + Object.assign(spec, { + data: [{ + type: 'choropleth', + locations, + locationmode, + z, + text: labels, + colorscale: diverging ? 'RdBu' : SEQUENTIAL_BLUES, + colorbar: { title: { text: valueLabel } }, + marker: { line: { color: '#ffffff', width: 0.5 } }, + hovertemplate: `%{text}
${valueLabel}: %{z}`, + }], + layout: { + geo, + showlegend: false, + margin: { t: 24, b: 24, l: 8, r: 8 }, + }, + _width: scope === 'us' ? 520 : 620, + _height: scope === 'us' ? 320 : 360, + }); + delete spec.mark; + delete spec.encoding; + }, + properties: [regionProperty], +}; diff --git a/packages/flint-js/src/plotly/templates/connected-scatter.ts b/packages/flint-js/src/plotly/templates/connected-scatter.ts new file mode 100644 index 00000000..060e1dff --- /dev/null +++ b/packages/flint-js/src/plotly/templates/connected-scatter.ts @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Connected Scatter Plot template. + * + * Points in 2-D (x, y both quantitative) connected by a straight line in a + * defined `order` — a trajectory, not a trend line. Mirrors + * `ecConnectedScatterDef`: one `scatter` trace per group, `mode: + * 'lines+markers'`, straight segments (never smoothed). + */ + +import { ChartTemplateDef } from '../../core/types'; +import { groupBy, getPlotlyPalette, getSeriesColor, sortByOrder } from './utils'; + +export const plConnectedScatterDef: ChartTemplateDef = { + chart: 'Connected Scatter Plot', + template: { mark: 'line', encoding: {} }, + channels: ['x', 'y', 'order', 'color', 'detail', 'column', 'row'], + markCognitiveChannel: 'position', + instantiate: (spec, ctx) => { + const { channelSemantics, table } = ctx; + const xField = channelSemantics.x?.field; + const yField = channelSemantics.y?.field; + const orderField = channelSemantics.order?.field; + const groupField = channelSemantics.color?.field ?? channelSemantics.detail?.field; + if (!xField || !yField) return; + + const palette = getPlotlyPalette(ctx, 'color'); + const makeTrace = (name: string | undefined, rows: any[], idx: number) => { + const sorted = sortByOrder(rows, orderField); + const color = getSeriesColor(palette, idx); + return { + type: 'scatter', + mode: 'lines+markers', + ...(name != null ? { name } : {}), + x: sorted.map((r: any) => r[xField]), + y: sorted.map((r: any) => r[yField]), + line: { color, shape: 'linear' as const }, + marker: { color, size: 7 }, + }; + }; + + const traces: any[] = []; + if (groupField) { + let i = 0; + for (const [name, rows] of groupBy(table, groupField)) { traces.push(makeTrace(name, rows, i)); i++; } + } else { + traces.push(makeTrace(undefined, table, 0)); + } + + const xAxisSpec: any = { title: { text: xField } }; + const yAxisSpec: any = { title: { text: yField } }; + // A trajectory reads its shape, not its distance from zero. + if (channelSemantics.x?.zero) xAxisSpec.rangemode = channelSemantics.x.zero.zero !== false ? 'tozero' : 'normal'; + if (channelSemantics.y?.zero) yAxisSpec.rangemode = channelSemantics.y.zero.zero !== false ? 'tozero' : 'normal'; + + Object.assign(spec, { + data: traces, + layout: { xaxis: xAxisSpec, yaxis: yAxisSpec, showlegend: !!groupField }, + }); + delete spec.mark; + delete spec.encoding; + }, +}; diff --git a/packages/flint-js/src/plotly/templates/density-contour.ts b/packages/flint-js/src/plotly/templates/density-contour.ts new file mode 100644 index 00000000..7fda0124 --- /dev/null +++ b/packages/flint-js/src/plotly/templates/density-contour.ts @@ -0,0 +1,100 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Density Contour (2D density) template. + * + * Native `histogram2dcontour` trace: bins two raw numeric arrays (`x`, `y`) and + * draws smoothed density contour lines. Vega-Lite has **no** contour mark, so + * this is a Plotly-only statistical chart. See design-docs/plotly-stats-charts.md. + */ + +import { ChartTemplateDef, ChartPropertyDef, EncodingActionDef } from '../../core/types'; + +const SCHEME_COLORSCALES: Record = { + viridis: 'Viridis', inferno: 'Hot', magma: 'Magma', plasma: 'Plasma', turbo: 'Turbo', + blues: 'Blues', reds: 'Reds', greens: 'Greens', oranges: 'Oranges', purples: 'Purples', greys: 'Greys', +}; +const DEFAULT_SCHEME = 'Blues'; + +export const plDensityContourDef: ChartTemplateDef = { + chart: 'Density Contour', + template: { mark: 'rect', encoding: {} }, + channels: ['x', 'y', 'column', 'row'], + markCognitiveChannel: 'color', + instantiate: (spec, ctx) => { + const { channelSemantics, table, chartProperties, encodings } = ctx; + const xField = channelSemantics.x?.field; + const yField = channelSemantics.y?.field; + if (!xField || !yField) return; + + const binCount = (chartProperties?.binCount as number) || 20; + const showPoints = chartProperties?.showPoints !== false; + const encScheme = (encodings?.color as any)?.scheme; + const userScheme = (encScheme && encScheme !== 'default') ? encScheme : undefined; + const colorscale = SCHEME_COLORSCALES[userScheme ?? DEFAULT_SCHEME.toLowerCase()] ?? DEFAULT_SCHEME; + + const xs: number[] = []; + const ys: number[] = []; + for (const r of table) { + const xv = Number(r[xField]); + const yv = Number(r[yField]); + if (isFinite(xv) && isFinite(yv)) { xs.push(xv); ys.push(yv); } + } + + const data: any[] = [{ + type: 'histogram2dcontour', + x: xs, y: ys, + nbinsx: binCount, nbinsy: binCount, + colorscale, + contours: { coloring: 'fill' }, + colorbar: { title: { text: 'Density' } }, + line: { width: 0.5 }, + }]; + if (showPoints) { + data.push({ + type: 'scatter', mode: 'markers', + x: xs, y: ys, + marker: { color: 'rgba(0,0,0,0.35)', size: 3 }, + hoverinfo: 'skip', showlegend: false, + }); + } + + Object.assign(spec, { + data, + layout: { + xaxis: { title: { text: xField } }, + yaxis: { title: { text: yField } }, + showlegend: false, + }, + }); + delete spec.mark; + delete spec.encoding; + }, + properties: [ + { key: 'binCount', label: 'Bins', type: 'continuous', min: 5, max: 50, step: 1, defaultValue: 20 } as ChartPropertyDef, + { key: 'showPoints', label: 'Show points', type: 'binary', defaultValue: true } as ChartPropertyDef, + ], + encodingActions: [ + { + key: 'colorScheme', + label: 'Scheme', + isApplicable: () => true, + dependencies: [], + control: { + type: 'discrete', options: [ + { value: undefined, label: 'Default (Blues)' }, + { value: 'viridis', label: 'Viridis' }, + { value: 'inferno', label: 'Inferno' }, + { value: 'magma', label: 'Magma' }, + { value: 'plasma', label: 'Plasma' }, + { value: 'turbo', label: 'Turbo' }, + { value: 'greens', label: 'Greens' }, + { value: 'reds', label: 'Reds' }, + ], + }, + get: (enc) => (enc.color as any)?.scheme, + set: (enc, value) => ({ ...enc, color: { ...(enc.color as any), scheme: value } }), + }, + ] as EncodingActionDef[], +}; diff --git a/packages/flint-js/src/plotly/templates/density.ts b/packages/flint-js/src/plotly/templates/density.ts new file mode 100644 index 00000000..fd6e0db6 --- /dev/null +++ b/packages/flint-js/src/plotly/templates/density.ts @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Density Plot template (KDE area). + * + * Plotly has no native density transform; the curve is computed here + * (Gaussian KDE, same bandwidth rule as the Vega-Lite/ECharts templates) and + * drawn as a filled `scatter` line — mirroring `ecDensityPlotDef`. + */ + +import { ChartTemplateDef, ChartPropertyDef } from '../../core/types'; +import { groupBy, getPlotlyPalette, getSeriesColor, fillColor, kde } from './utils'; + +export const plDensityPlotDef: ChartTemplateDef = { + chart: 'Density Plot', + template: { mark: 'area', encoding: {} }, + channels: ['x', 'color', 'column', 'row'], + markCognitiveChannel: 'area', + instantiate: (spec, ctx) => { + const { channelSemantics, table, chartProperties } = ctx; + const xField = channelSemantics.x?.field; + const colorField = channelSemantics.color?.field; + if (!xField) return; + + const steps = 200; + const bandwidthMultiplier = (chartProperties?.bandwidth != null && chartProperties.bandwidth > 0) + ? chartProperties.bandwidth : 1; + const palette = getPlotlyPalette(ctx, 'color'); + + const traces: any[] = []; + if (colorField) { + const allValues = table.map((r: any) => Number(r[xField])).filter((v: number) => !isNaN(v)); + const sharedExtent = allValues.length > 0 + ? { min: Math.min(...allValues), max: Math.max(...allValues) } : undefined; + let i = 0; + for (const [name, rows] of groupBy(table, colorField)) { + const values = rows.map((r: any) => Number(r[xField])).filter((v: number) => !isNaN(v)); + const { x, y } = kde(values, steps, bandwidthMultiplier, sharedExtent); + const color = getSeriesColor(palette, i); + traces.push({ + type: 'scatter', mode: 'lines', name, x, y, + line: { color }, fill: 'tozeroy', fillcolor: fillColor(color, 0.4), + }); + i++; + } + } else { + const values = table.map((r: any) => Number(r[xField])).filter((v: number) => !isNaN(v)); + const { x, y } = kde(values, steps, bandwidthMultiplier); + const color = getSeriesColor(palette, 0); + traces.push({ + type: 'scatter', mode: 'lines', x, y, + line: { color }, fill: 'tozeroy', fillcolor: fillColor(color, 0.4), + }); + } + + Object.assign(spec, { + data: traces, + layout: { + xaxis: { title: { text: xField } }, + yaxis: { title: { text: 'Density' }, rangemode: 'tozero' }, + showlegend: !!colorField, + }, + }); + delete spec.mark; + delete spec.encoding; + }, + properties: [ + { key: 'bandwidth', label: 'Bandwidth', type: 'continuous', min: 0.05, max: 2, step: 0.05, defaultValue: 0 } as ChartPropertyDef, + ], +}; diff --git a/packages/flint-js/src/plotly/templates/ecdf.ts b/packages/flint-js/src/plotly/templates/ecdf.ts new file mode 100644 index 00000000..8f59e157 --- /dev/null +++ b/packages/flint-js/src/plotly/templates/ecdf.ts @@ -0,0 +1,68 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly ECDF Plot template. + * + * Plotly has no cumulative-distribution transform; the step curve is + * precomputed (mirroring `ecEcdfPlotDef`) and drawn as a `scatter` trace with + * `line.shape: 'hv'` (step-after — Plotly's equivalent of ECharts' `step: + * 'end'`). + */ + +import { ChartTemplateDef, ChartPropertyDef } from '../../core/types'; +import { groupBy, getPlotlyPalette, getSeriesColor, ecdfPairs } from './utils'; + +export const plEcdfPlotDef: ChartTemplateDef = { + chart: 'ECDF Plot', + template: { mark: 'line', encoding: {} }, + channels: ['x', 'color', 'detail', 'column', 'row'], + markCognitiveChannel: 'position', + instantiate: (spec, ctx) => { + const { channelSemantics, table, chartProperties } = ctx; + const xField = channelSemantics.x?.field; + const groupField = channelSemantics.color?.field ?? channelSemantics.detail?.field; + if (!xField) return; + + const showPoints = !!chartProperties?.showPoints; + const palette = getPlotlyPalette(ctx, 'color'); + + const makeTrace = (name: string | undefined, values: number[], idx: number) => { + const pairs = ecdfPairs(values); + return { + type: 'scatter', + mode: showPoints ? 'lines+markers' as const : 'lines' as const, + ...(name != null ? { name } : {}), + x: pairs.map(p => p[0]), + y: pairs.map(p => p[1]), + line: { shape: 'hv' as const, color: getSeriesColor(palette, idx), width: 2 }, + marker: { size: 6 }, + }; + }; + + const traces: any[] = []; + if (groupField) { + let i = 0; + for (const [name, rows] of groupBy(table, groupField)) { + traces.push(makeTrace(name, rows.map((r: any) => Number(r[xField])).filter((v: number) => !isNaN(v)), i)); + i++; + } + } else { + traces.push(makeTrace(undefined, table.map((r: any) => Number(r[xField])).filter((v: number) => !isNaN(v)), 0)); + } + + Object.assign(spec, { + data: traces, + layout: { + xaxis: { title: { text: xField } }, + yaxis: { title: { text: 'Cumulative proportion' }, range: [0, 1] }, + showlegend: !!groupField, + }, + }); + delete spec.mark; + delete spec.encoding; + }, + properties: [ + { key: 'showPoints', label: 'Points', type: 'binary', defaultValue: false } as ChartPropertyDef, + ], +}; diff --git a/packages/flint-js/src/plotly/templates/funnel.ts b/packages/flint-js/src/plotly/templates/funnel.ts new file mode 100644 index 00000000..97363562 --- /dev/null +++ b/packages/flint-js/src/plotly/templates/funnel.ts @@ -0,0 +1,89 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Funnel Chart template — Plotly opportunity chart. + * + * Native `funnel` trace: Plotly draws the descending trapezoids, stage + * labels, and percent-of-initial/-previous annotations itself. Matches the + * ECharts-only `Funnel Chart` chart type (no Vega-Lite equivalent). + * + * Data model: + * y (nominal): stage name + * size (quantitative): value for each stage (rows aggregated by sum) + */ + +import { ChartTemplateDef, ChartPropertyDef } from '../../core/types'; +import { extractCategories, getPlotlyPalette } from './utils'; + +export const plFunnelChartDef: ChartTemplateDef = { + chart: 'Funnel Chart', + template: { mark: 'rect', encoding: {} }, + channels: ['y', 'size'], + markCognitiveChannel: 'area', + declareLayoutMode: () => ({ + axisFlags: { y: { banded: true } }, + paramOverrides: { defaultBandSize: 50 }, + }), + instantiate: (spec, ctx) => { + const { channelSemantics, table, chartProperties } = ctx; + const stageField = channelSemantics.y?.field; + const valField = channelSemantics.size?.field; + if (!stageField) return; + + const stages = extractCategories(table, stageField, channelSemantics.y?.ordinalSortOrder); + if (stages.length === 0) return; + + const values: number[] = []; + if (valField) { + const agg = new Map(); + for (const row of table) { + const s = String(row[stageField] ?? ''); + agg.set(s, (agg.get(s) ?? 0) + (Number(row[valField]) || 0)); + } + for (const s of stages) values.push(agg.get(s) ?? 0); + } else { + const counts = new Map(); + for (const row of table) { + const s = String(row[stageField] ?? ''); + counts.set(s, (counts.get(s) ?? 0) + 1); + } + for (const s of stages) values.push(counts.get(s) ?? 0); + } + + // Sort stages largest-first by default (a funnel reads top-down as a + // narrowing pipeline). + const sortOrder = chartProperties?.sort ?? 'descending'; + const order = stages.map((_s, i) => i); + if (sortOrder === 'descending') order.sort((a, b) => values[b] - values[a]); + else if (sortOrder === 'ascending') order.sort((a, b) => values[a] - values[b]); + const sortedStages = order.map(i => stages[i]); + const sortedValues = order.map(i => values[i]); + + const palette = getPlotlyPalette(ctx, 'color'); + + Object.assign(spec, { + data: [{ + type: 'funnel', + y: sortedStages, + x: sortedValues, + textinfo: 'value+percent initial', + marker: { color: palette.slice(0, sortedStages.length) }, + connector: { line: { color: '#e5e7eb', width: 1 } }, + }], + layout: { showlegend: false }, + }); + delete spec.mark; + delete spec.encoding; + }, + properties: [ + { + key: 'sort', label: 'Sort', type: 'discrete', defaultValue: 'descending', + options: [ + { value: 'descending', label: 'Descending (default)' }, + { value: 'ascending', label: 'Ascending' }, + { value: 'none', label: 'Original order' }, + ], + } as ChartPropertyDef, + ], +}; diff --git a/packages/flint-js/src/plotly/templates/gantt.ts b/packages/flint-js/src/plotly/templates/gantt.ts new file mode 100644 index 00000000..456e748d --- /dev/null +++ b/packages/flint-js/src/plotly/templates/gantt.ts @@ -0,0 +1,110 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Gantt Chart template. + * + * One horizontal bar per task, `base: start`, `x: end − start` — Plotly's + * `base` property natively floats a bar off zero, so no transparent-base + * trick (unlike the ECharts template, which must stack a silent base series + * to fake a floating interval bar). + */ + +import { ChartTemplateDef } from '../../core/types'; +import { + coerceGanttEndpoint, formatGanttLabel, GANTT_PROPERTIES, isGanttTemporal, sortGanttRows, +} from '../../chart-types/gantt'; +import { getPlotlyPalette, getSeriesColor } from './utils'; + +export const plGanttChartDef: ChartTemplateDef = { + chart: 'Gantt Chart', + template: { mark: 'bar', encoding: {} }, + channels: ['y', 'x', 'x2', 'color', 'detail', 'column', 'row'], + markCognitiveChannel: 'position', + declareLayoutMode: () => ({ axisFlags: { y: { banded: true } } }), + instantiate: (spec, ctx) => { + const { channelSemantics, table, chartProperties, semanticTypes } = ctx; + const taskField = channelSemantics.y?.field; + const startField = channelSemantics.x?.field; + const endField = channelSemantics.x2?.field; + const colorField = channelSemantics.color?.field; + if (!taskField || !startField || !endField || table.length === 0) return; + + const temporal = isGanttTemporal(channelSemantics.x?.type, semanticTypes[startField]); + const rows = sortGanttRows(table + .map((r: any, inputIndex: number) => ({ + task: String(r[taskField] ?? ''), + start: coerceGanttEndpoint(r[startField], temporal), + end: coerceGanttEndpoint(r[endField], temporal), + group: colorField != null ? String(r[colorField] ?? '') : undefined, + inputIndex, + })) + .filter((r) => r.task && Number.isFinite(r.start) && Number.isFinite(r.end))); + if (rows.length === 0) return; + + const taskHeight = Number(chartProperties?.taskHeight ?? 70) / 100; + const cornerRadius = Number(chartProperties?.cornerRadius ?? 2); + const intervalLabels = chartProperties?.intervalLabels === true; + const tasks = rows.map(r => r.task); + + const palette = getPlotlyPalette(ctx, 'color'); + const groups = colorField ? Array.from(new Set(rows.map(r => r.group ?? ''))) : []; + const groupColorIdx = new Map(groups.map((g, i) => [g, i])); + + const dateLabel = (ms: number) => temporal ? new Date(ms).toISOString().slice(0, 10) : String(ms); + + const traces: any[] = []; + if (colorField && groups.length > 0) { + for (const g of groups) { + const groupRows = rows.filter(r => (r.group ?? '') === g); + traces.push({ + type: 'bar', + name: g, + orientation: 'h', + base: groupRows.map(r => r.start), + x: groupRows.map(r => r.end - r.start), + y: groupRows.map(r => r.task), + width: taskHeight, + marker: { color: getSeriesColor(palette, groupColorIdx.get(g) ?? 0) }, + text: intervalLabels ? groupRows.map(r => formatGanttLabel(r.start, r.end, temporal)) : undefined, + textposition: intervalLabels ? 'outside' as const : undefined, + customdata: groupRows.map(r => [dateLabel(r.start), dateLabel(r.end)]), + }); + } + } else { + traces.push({ + type: 'bar', + orientation: 'h', + showlegend: false, + base: rows.map(r => r.start), + x: rows.map(r => r.end - r.start), + y: tasks, + width: taskHeight, + marker: { color: getSeriesColor(palette, 0) }, + text: intervalLabels ? rows.map(r => formatGanttLabel(r.start, r.end, temporal)) : undefined, + textposition: intervalLabels ? 'outside' as const : undefined, + customdata: rows.map(r => [dateLabel(r.start), dateLabel(r.end)]), + }); + } + for (const t of traces) { + t.hovertemplate = `%{y}
${startField}: %{customdata[0]}
${endField}: %{customdata[1]}`; + t.marker.line = { width: 0 }; + if (cornerRadius) t.marker.cornerradius = cornerRadius; + } + + const xAxisSpec: any = { title: { text: temporal ? '' : startField } }; + if (temporal) xAxisSpec.type = 'date'; + + Object.assign(spec, { + data: traces, + layout: { + xaxis: xAxisSpec, + yaxis: { type: 'category', categoryorder: 'array', categoryarray: tasks, autorange: 'reversed', title: { text: taskField } }, + showlegend: !!colorField && groups.length > 1, + }, + }); + delete spec.mark; + delete spec.encoding; + }, + properties: GANTT_PROPERTIES, +}; diff --git a/packages/flint-js/src/plotly/templates/gauge.ts b/packages/flint-js/src/plotly/templates/gauge.ts new file mode 100644 index 00000000..fbcd414d --- /dev/null +++ b/packages/flint-js/src/plotly/templates/gauge.ts @@ -0,0 +1,100 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Gauge Chart template — Plotly opportunity chart. + * + * Native `indicator` trace with `mode: 'gauge+number'`: Plotly draws the + * dial, needle, and colored range bands itself. Matches the ECharts-only + * `Gauge Chart` chart type (no Vega-Lite equivalent) with a genuinely + * native, purpose-built primitive (ECharts hand-computes dial geometry). + * + * Data model: + * size (quantitative): the value to display + * column (nominal, optional): one gauge per distinct value (grid layout) + */ + +import { ChartTemplateDef, ChartPropertyDef } from '../../core/types'; +import { extractCategories, groupBy, getPlotlyPalette, getSeriesColor, niceMax } from './utils'; + +export const plGaugeChartDef: ChartTemplateDef = { + chart: 'Gauge Chart', + template: { mark: 'point', encoding: {} }, + channels: ['size', 'column'], + markCognitiveChannel: 'position', + instantiate: (spec, ctx) => { + const { channelSemantics, table, chartProperties } = ctx; + const valueField = channelSemantics.size?.field; + const columnField = channelSemantics.column?.field; + if (!valueField) return; + + const allValues = table.map((r: any) => Number(r[valueField])).filter((v: number) => isFinite(v)); + const dataMax = allValues.length > 0 ? Math.max(...allValues) : 100; + const scaleMin = Number(chartProperties?.min ?? 0); + const scaleMax = Number(chartProperties?.max ?? niceMax(dataMax)); + const palette = getPlotlyPalette(ctx, 'color'); + + const items: { name: string; value: number }[] = []; + if (columnField) { + const categories = extractCategories(table, columnField, channelSemantics.column?.ordinalSortOrder); + const groups = groupBy(table, columnField); + for (const cat of categories) { + const vals = (groups.get(cat) ?? []).map((r: any) => Number(r[valueField])).filter((v: number) => isFinite(v)); + items.push({ name: cat, value: vals.length ? vals.reduce((a, b) => a + b, 0) / vals.length : 0 }); + } + } else { + const avg = allValues.length ? allValues.reduce((a, b) => a + b, 0) / allValues.length : 0; + items.push({ name: valueField, value: avg }); + } + + const n = items.length; + const cols = Math.ceil(Math.sqrt(n)); + const gridRows = Math.ceil(n / cols); + // A gauge's semicircular dial carries axis end-labels ("0"/"max") just + // beyond its left/right tips and a title above it. With a tiny gap the + // neighbouring dials' end-labels collide horizontally and a lower row's + // title crowds the row above. Reserve a generous gap on each axis — + // wider horizontally (end-labels) and taller vertically (title band). + const gapX = cols > 1 ? 0.14 : 0; + const gapY = gridRows > 1 ? 0.18 : 0; + const cellW = (1 - gapX * (cols - 1)) / cols; + const cellH = (1 - gapY * (gridRows - 1)) / gridRows; + + const traces = items.map((item, i) => { + const col = i % cols; + const row = Math.floor(i / cols); + const x0 = col * (cellW + gapX); + const y1 = 1 - row * (cellH + gapY); + const y0 = y1 - cellH; + const color = getSeriesColor(palette, i); + return { + type: 'indicator', + mode: 'gauge+number', + value: Math.round(item.value * 100) / 100, + title: { text: item.name, font: { size: 13 } }, + domain: { x: [x0, x0 + cellW], y: [y0, y1] }, + gauge: { + axis: { range: [scaleMin, scaleMax] }, + bar: { color }, + bgcolor: 'white', + borderwidth: 1, + bordercolor: '#d1d5db', + }, + }; + }); + + const canvas = ctx.canvasSize ?? { width: 400, height: 300 }; + Object.assign(spec, { + data: traces, + layout: {}, + _width: Math.max(canvas.width, cols * 240), + _height: Math.max(canvas.height, gridRows * 230), + }); + delete spec.mark; + delete spec.encoding; + }, + properties: [ + { key: 'min', label: 'Min', type: 'continuous', min: 0, max: 1000, step: 10, defaultValue: 0 } as ChartPropertyDef, + { key: 'max', label: 'Max', type: 'continuous', min: 0, max: 10000, step: 100, defaultValue: 100 } as ChartPropertyDef, + ], +}; diff --git a/packages/flint-js/src/plotly/templates/heatmap.ts b/packages/flint-js/src/plotly/templates/heatmap.ts new file mode 100644 index 00000000..641519ac --- /dev/null +++ b/packages/flint-js/src/plotly/templates/heatmap.ts @@ -0,0 +1,101 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Heatmap template. + * + * Native `heatmap` trace: pass `x`, `y` category arrays and a `z` matrix and + * Plotly draws the grid + colorbar itself — no manual index-mapping like the + * ECharts template (`data: [[xIdx, yIdx, value], ...]`) needs. + */ + +import { ChartTemplateDef, EncodingActionDef } from '../../core/types'; +import { extractCategories } from './utils'; + +const SCHEME_COLORSCALES: Record = { + viridis: 'Viridis', inferno: 'Hot', magma: 'Magma', plasma: 'Plasma', turbo: 'Turbo', + blues: 'Blues', reds: 'Reds', greens: 'Greens', oranges: 'Oranges', purples: 'Purples', greys: 'Greys', + blueorange: 'RdBu', redblue: 'RdBu', +}; +const DEFAULT_SCHEME = 'Blues'; + +export const plHeatmapDef: ChartTemplateDef = { + chart: 'Heatmap', + template: { mark: 'rect', encoding: {} }, + channels: ['x', 'y', 'color', 'column', 'row'], + markCognitiveChannel: 'color', + declareLayoutMode: () => ({ axisFlags: { x: { banded: true }, y: { banded: true } } }), + instantiate: (spec, ctx) => { + const { channelSemantics, table, colorDecisions, encodings } = ctx; + const xField = channelSemantics.x?.field; + const yField = channelSemantics.y?.field; + const colorField = channelSemantics.color?.field; + if (!xField || !yField) return; + + const xCategories = extractCategories(table, xField, channelSemantics.x?.ordinalSortOrder); + const yCategories = extractCategories(table, yField, channelSemantics.y?.ordinalSortOrder); + + const cellMap = new Map(); + for (const row of table) { + const key = `${row[xField]}\u0000${row[yField]}`; + const val = colorField ? (Number(row[colorField]) || 0) : 1; + cellMap.set(key, (cellMap.get(key) ?? 0) + val); + } + const z = yCategories.map(yc => xCategories.map(xc => { + const v = cellMap.get(`${xc}\u0000${yc}`); + return v ?? null; + })); + + const encScheme = (encodings?.color as any)?.scheme; + const userScheme = (encScheme && encScheme !== 'default') ? encScheme : undefined; + const decision = colorDecisions?.color ?? colorDecisions?.group; + const semanticIsDiverging = decision?.schemeType === 'diverging'; + const schemeName = userScheme || (semanticIsDiverging ? 'redblue' : DEFAULT_SCHEME.toLowerCase()); + const colorscale = SCHEME_COLORSCALES[schemeName] ?? DEFAULT_SCHEME; + + Object.assign(spec, { + data: [{ + type: 'heatmap', + x: xCategories, y: yCategories, z, + colorscale, + hoverongaps: false, + colorbar: { title: { text: colorField ?? 'Value' } }, + }], + layout: { + xaxis: { type: 'category', categoryorder: 'array', categoryarray: xCategories, title: { text: xField } }, + yaxis: { type: 'category', categoryorder: 'array', categoryarray: yCategories, title: { text: yField } }, + showlegend: false, + }, + }); + delete spec.mark; + delete spec.encoding; + }, + encodingActions: [ + { + key: 'colorScheme', + label: 'Scheme', + isApplicable: (c) => !!c.encodings.color?.field, + dependencies: ['color'], + control: { + type: 'discrete', options: [ + { value: undefined, label: 'Default (Blues)' }, + { value: 'viridis', label: 'Viridis' }, + { value: 'inferno', label: 'Inferno' }, + { value: 'magma', label: 'Magma' }, + { value: 'plasma', label: 'Plasma' }, + { value: 'turbo', label: 'Turbo' }, + { value: 'blues', label: 'Blues' }, + { value: 'reds', label: 'Reds' }, + { value: 'greens', label: 'Greens' }, + { value: 'oranges', label: 'Oranges' }, + { value: 'purples', label: 'Purples' }, + { value: 'greys', label: 'Greys' }, + { value: 'blueorange', label: 'Blue-Orange (diverging)' }, + { value: 'redblue', label: 'Red-Blue (diverging)' }, + ], + }, + get: (enc) => (enc.color as any)?.scheme, + set: (enc, value) => ({ ...enc, color: { ...(enc.color as any), scheme: value } }), + }, + ] as EncodingActionDef[], +}; diff --git a/packages/flint-js/src/plotly/templates/histogram.ts b/packages/flint-js/src/plotly/templates/histogram.ts new file mode 100644 index 00000000..b05d702b --- /dev/null +++ b/packages/flint-js/src/plotly/templates/histogram.ts @@ -0,0 +1,68 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Histogram template. + * + * Plotly has a native `histogram` trace: pass raw numeric values and + * `nbinsx` and Plotly computes the bins client-side (matching Vega-Lite's + * `bin: true` transform) — no manual bin-counting like Chart.js/ECharts need. + */ + +import { ChartTemplateDef, ChartPropertyDef } from '../../core/types'; +import { groupBy, getPlotlyPalette, getSeriesColor } from './utils'; + +export const plHistogramDef: ChartTemplateDef = { + chart: 'Histogram', + template: { mark: 'bar', encoding: {} }, + channels: ['x', 'color', 'column', 'row'], + markCognitiveChannel: 'length', + instantiate: (spec, ctx) => { + const { channelSemantics, table, chartProperties } = ctx; + const xField = channelSemantics.x?.field; + const colorField = channelSemantics.color?.field; + if (!xField) return; + + const binCount = chartProperties?.binCount || 10; + const palette = getPlotlyPalette(ctx, 'color'); + + const traces: any[] = []; + if (colorField) { + let i = 0; + for (const [name, rows] of groupBy(table, colorField)) { + traces.push({ + type: 'histogram', + name, + x: rows.map((r: any) => Number(r[xField])).filter((v: number) => isFinite(v)), + nbinsx: binCount, + marker: { color: getSeriesColor(palette, i) }, + opacity: 0.75, + }); + i++; + } + } else { + traces.push({ + type: 'histogram', + x: table.map((r: any) => Number(r[xField])).filter((v: number) => isFinite(v)), + nbinsx: binCount, + marker: { color: getSeriesColor(palette, 0) }, + }); + } + + Object.assign(spec, { + data: traces, + layout: { + barmode: colorField ? 'stack' : undefined, + bargap: 0.02, + xaxis: { title: { text: xField } }, + yaxis: { title: { text: 'Count' }, rangemode: 'tozero' }, + showlegend: !!colorField, + }, + }); + delete spec.mark; + delete spec.encoding; + }, + properties: [ + { key: 'binCount', label: 'Max Bins', type: 'continuous', min: 5, max: 50, step: 1, defaultValue: 10 } as ChartPropertyDef, + ], +}; diff --git a/packages/flint-js/src/plotly/templates/index.ts b/packages/flint-js/src/plotly/templates/index.ts new file mode 100644 index 00000000..366268e9 --- /dev/null +++ b/packages/flint-js/src/plotly/templates/index.ts @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly template registry. + * + * Mirrors the structure of chartjs/templates/index.ts, echarts/templates/index.ts + * and vegalite/templates/index.ts but with Plotly template definitions. + * + * Coverage: the four original acceptance templates (Bar, Line, Area, Scatter) + * plus an expressive tranche mirroring most of the Vega-Lite catalog (grouped/ + * stacked bar, distributions, circular charts, specialized native-trace charts), + * two Plotly opportunity charts (Funnel, Gauge) that showcase native + * `indicator`/`funnel` traces ECharts otherwise hand-builds, native geo charts + * (Map, Choropleth — Plotly's own `scattergeo`/`choropleth` built-in atlas, no + * TopoJSON fetch/join needed), and two composite table/strip layouts + * (Sparkline, Bar Table) built as self-contained Plotly figures (own axis + * grid + paper-anchored annotations) rather than forced through the generic + * cartesian column/row facet combiner (`facet.ts`), which only supports one + * axis pair per panel. See `sparkline.ts` / `bar-table.ts` for the composite + * layout technique and `selfManagesFacets` in `../assemble.ts`. + */ + +import { ChartTemplateDef } from '../../core/types'; +import { plBarChartDef, plGroupedBarChartDef, plStackedBarChartDef, plPyramidChartDef } from './bar'; +import { plLineChartDef } from './line'; +import { plAreaChartDef } from './area'; +import { plScatterPlotDef } from './scatter'; +import { plHistogramDef } from './histogram'; +import { plPieChartDef, plDonutChartDef } from './pie'; +import { plRadarChartDef } from './radar'; +import { plRoseChartDef } from './rose'; +import { plBoxplotDef } from './boxplot'; +import { plViolinPlotDef } from './violin'; +import { plDensityPlotDef } from './density'; +import { plEcdfPlotDef } from './ecdf'; +import { plStripPlotDef } from './jitter'; +import { plConnectedScatterDef } from './connected-scatter'; +import { plRangeAreaChartDef } from './range-area'; +import { plStreamgraphDef } from './streamgraph'; +import { plSlopeChartDef } from './slope'; +import { plBumpChartDef } from './bump'; +import { plWaterfallChartDef } from './waterfall'; +import { plCandlestickChartDef } from './candlestick'; +import { plHeatmapDef } from './heatmap'; +import { plLollipopChartDef } from './lollipop'; +import { plBulletChartDef } from './bullet'; +import { plGanttChartDef } from './gantt'; +import { plRangedDotPlotDef } from './ranged-dot'; +import { plRegressionDef } from './regression'; +import { plKpiCardDef } from './kpi-card'; +import { plFunnelChartDef } from './funnel'; +import { plGaugeChartDef } from './gauge'; +import { plMapDef } from './map'; +import { plChoroplethDef } from './choropleth'; +import { plSparklineDef } from './sparkline'; +import { plBarTableDef } from './bar-table'; +import { plDensityContourDef } from './density-contour'; + +/** + * Plotly chart template definitions, grouped by category. + */ +export const plTemplateDefs: { [key: string]: ChartTemplateDef[] } = { + 'Scatter & Point': [plScatterPlotDef, plRegressionDef, plConnectedScatterDef, plRangedDotPlotDef, plStripPlotDef], + 'Bar': [plBarChartDef, plGroupedBarChartDef, plStackedBarChartDef, plLollipopChartDef, plWaterfallChartDef, plPyramidChartDef], + 'Distributions': [plHistogramDef, plBoxplotDef, plViolinPlotDef, plDensityPlotDef, plEcdfPlotDef, plCandlestickChartDef, plDensityContourDef], + 'Line & Area': [plLineChartDef, plAreaChartDef, plBumpChartDef, plSlopeChartDef, plStreamgraphDef, plRangeAreaChartDef], + 'Circular': [plPieChartDef, plDonutChartDef, plRadarChartDef, plRoseChartDef], + 'Tables & KPIs': [plHeatmapDef, plGanttChartDef, plBulletChartDef, plKpiCardDef, plSparklineDef, plBarTableDef], + 'Maps': [plMapDef, plChoroplethDef], + 'Opportunity': [plFunnelChartDef, plGaugeChartDef], +}; + +/** + * Flat list of all Plotly chart template definitions. + */ +export const plAllTemplateDefs: ChartTemplateDef[] = Object.values(plTemplateDefs).flat(); + +/** + * Look up a Plotly chart template definition by chart type name. + */ +export function plGetTemplateDef(chartType: string): ChartTemplateDef | undefined { + return plAllTemplateDefs.find(t => t.chart === chartType); +} + +/** + * Get the available channels for a Plotly chart type. + */ +export function plGetTemplateChannels(chartType: string): string[] { + return plGetTemplateDef(chartType)?.channels || []; +} diff --git a/packages/flint-js/src/plotly/templates/jitter.ts b/packages/flint-js/src/plotly/templates/jitter.ts new file mode 100644 index 00000000..c915f326 --- /dev/null +++ b/packages/flint-js/src/plotly/templates/jitter.ts @@ -0,0 +1,123 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Strip Plot (categorical scatter with jitter) template. + * + * The jittered category axis is a numeric axis with explicit `tickvals` / + * `ticktext` at integer positions (Plotly has no native "jittered category" + * axis), so fractional jitter offsets can be plotted directly — mirroring + * `ecStripPlotDef`'s hidden-value-axis trick. + */ + +import { ChartTemplateDef } from '../../core/types'; +import { isDiscreteType, extractCategories, groupBy, getPlotlyPalette, getSeriesColor, seededJitter } from './utils'; + +export const plStripPlotDef: ChartTemplateDef = { + chart: 'Strip Plot', + template: { mark: 'circle', encoding: {} }, + channels: ['x', 'y', 'color', 'size', 'column', 'row'], + markCognitiveChannel: 'position', + declareLayoutMode: () => ({ + paramOverrides: { defaultBandSize: 50, minStep: 16 }, + }), + instantiate: (spec, ctx) => { + const { channelSemantics, table, colorDecisions } = ctx; + const xCS = channelSemantics.x; + const yCS = channelSemantics.y; + const xField = xCS?.field; + const yField = yCS?.field; + const colorField = channelSemantics.color?.field; + const colorType = channelSemantics.color?.type; + const isContinuousColor = !!colorField && (colorType === 'quantitative' || colorType === 'temporal'); + if (!xField || !yField) return; + + const xIsDiscrete = isDiscreteType(xCS?.type); + const yIsDiscrete = isDiscreteType(yCS?.type); + const catAxis: 'x' | 'y' = xIsDiscrete ? 'x' : yIsDiscrete ? 'y' : 'x'; + const catField = catAxis === 'x' ? xField : yField; + const contField = catAxis === 'x' ? yField : xField; + + const categories = extractCategories(table, catField!, channelSemantics[catAxis]?.ordinalSortOrder); + const catIndex = new Map(categories.map((c, i) => [c, i])); + const rand = seededJitter(42); + const jitterHalfWidth = 0.3; + + const catCoord = (row: any) => { + const idx = catIndex.get(String(row[catField!] ?? '')) ?? 0; + return idx + rand() * jitterHalfWidth; + }; + + const catAxisSpec = { + tickmode: 'array' as const, + tickvals: categories.map((_c, i) => i), + ticktext: categories, + range: [-0.5, categories.length - 0.5], + title: { text: catField }, + zeroline: false, + }; + const contAxisSpec = { title: { text: contField } }; + + const traces: any[] = []; + const buildXY = (row: any) => { + const cv = catCoord(row); + return catAxis === 'x' ? [cv, row[contField!]] : [row[contField!], cv]; + }; + + if (isContinuousColor && colorField) { + const colorVals = table.map((r: any) => Number(r[colorField])).filter((v: number) => isFinite(v)); + const cmin = colorVals.length ? Math.min(...colorVals) : 0; + const cmax = colorVals.length ? Math.max(...colorVals) : 1; + traces.push({ + type: 'scatter', + mode: 'markers', + name: colorField, + x: table.map((r: any) => buildXY(r)[0]), + y: table.map((r: any) => buildXY(r)[1]), + marker: { + color: table.map((r: any) => Number(r[colorField])), + colorscale: 'Viridis', + cmin, cmax, + showscale: true, + colorbar: { title: { text: colorField } }, + opacity: 0.75, + size: 8, + }, + }); + } else if (colorField) { + const palette = getPlotlyPalette(ctx, 'color'); + let i = 0; + for (const [name, rows] of groupBy(table, colorField)) { + traces.push({ + type: 'scatter', + mode: 'markers', + name, + x: rows.map((r: any) => buildXY(r)[0]), + y: rows.map((r: any) => buildXY(r)[1]), + marker: { color: getSeriesColor(palette, i), opacity: 0.75, size: 8 }, + }); + i++; + } + } else { + const palette = getPlotlyPalette(ctx, 'color'); + traces.push({ + type: 'scatter', + mode: 'markers', + x: table.map((r: any) => buildXY(r)[0]), + y: table.map((r: any) => buildXY(r)[1]), + marker: { color: getSeriesColor(palette, 0), opacity: 0.75, size: 8 }, + }); + } + void colorDecisions; + + Object.assign(spec, { + data: traces, + layout: { + ...(catAxis === 'x' ? { xaxis: catAxisSpec, yaxis: contAxisSpec } : { xaxis: contAxisSpec, yaxis: catAxisSpec }), + showlegend: !!colorField && !isContinuousColor, + }, + }); + delete spec.mark; + delete spec.encoding; + }, +}; diff --git a/packages/flint-js/src/plotly/templates/kpi-card.ts b/packages/flint-js/src/plotly/templates/kpi-card.ts new file mode 100644 index 00000000..e155ec23 --- /dev/null +++ b/packages/flint-js/src/plotly/templates/kpi-card.ts @@ -0,0 +1,134 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly KPI Card template. + * + * Native `indicator` trace (`mode: 'number+delta'`): Plotly renders the big + * number, the caption (`title`), and — when a `goal` is bound — a delta + * arrow/percentage against it, all natively. This is a much simpler mapping + * than the Vega-Lite template, which hand-draws each card (rect + text marks) + * because Vega-Lite has no indicator primitive. + */ + +import { ChartTemplateDef, ChartPropertyDef } from '../../core/types'; + +type Layout = 'horizontal' | 'vertical' | 'grid'; + +export const plKpiCardDef: ChartTemplateDef = { + chart: 'KPI Card', + template: { layer: [] }, + channels: ['metric', 'value', 'goal'], + markCognitiveChannel: 'position', + instantiate: (spec, ctx) => { + const { channelSemantics, table, chartProperties } = ctx; + const metricField = channelSemantics.metric?.field; + const valueField = channelSemantics.value?.field; + const goalField = channelSemantics.goal?.field; + if (!valueField) return; + + const rows = (ctx.fullTable ?? table ?? []).filter((r: any) => r && r[valueField] != null); + if (rows.length === 0) return; + + const layout: Layout = (chartProperties?.layout as Layout) ?? (rows.length > 4 ? 'grid' : 'horizontal'); + const n = rows.length; + let cols: number, gridRows: number; + if (layout === 'vertical') { cols = 1; gridRows = n; } + else if (layout === 'horizontal') { cols = n; gridRows = 1; } + else { cols = Math.ceil(Math.sqrt(n)); gridRows = Math.ceil(n / cols); } + + const gapFrac = 0.02; + const cellW = (1 - gapFrac * (cols - 1)) / cols; + const cellH = (1 - gapFrac * (gridRows - 1)) / gridRows; + + // KPI cards are content-sized tiles, NOT full-canvas charts — stretching + // a single card to the whole requested canvas width (e.g. 480px) strands + // the caption + number in a sea of whitespace. Size each tile to a + // compact fixed footprint and let the grid grow with the tile COUNT + // instead of filling the canvas. + const TILE_W = 220; + const TILE_H = 150; + const figWidth = Math.round(cols * TILE_W + gapFrac * (cols - 1) * TILE_W); + const figHeight = Math.round(gridRows * TILE_H + gapFrac * (gridRows - 1) * TILE_H); + // Font sizes scale with each cell's actual pixel height so a dense + // grid of many tiles doesn't overflow its row with fixed-size text. + const captionFontPx = Math.max(10, Math.min(14, cellH * figHeight * 0.16)); + const valueFontPx = Math.max(16, Math.min(30, cellH * figHeight * 0.32)); + const goalFontPx = Math.max(9, Math.min(12, cellH * figHeight * 0.12)); + + const traces: any[] = []; + const annotations: any[] = []; + rows.forEach((row: any, i: number) => { + const col = i % cols; + const gridRow = Math.floor(i / cols); + const x0 = col * (cellW + gapFrac); + const y1 = 1 - gridRow * (cellH + gapFrac); + const y0 = y1 - cellH; + const rawValue = row[valueField]; + const value = Number(rawValue); + const isNumeric = rawValue != null && rawValue !== '' && Number.isFinite(value); + const goal = goalField != null ? Number(row[goalField]) : undefined; + const hasGoal = goal != null && Number.isFinite(goal); + const caption = metricField ? String(row[metricField] ?? '') : valueField; + + if (isNumeric) { + const indicator: any = { + type: 'indicator', + mode: hasGoal ? 'number+delta' : 'number', + value, + title: { text: caption, font: { size: captionFontPx } }, + number: { font: { size: valueFontPx } }, + domain: { x: [x0, x0 + cellW], y: [y0, y1] }, + }; + if (hasGoal) { + indicator.delta = { reference: goal, relative: false, increasing: { color: '#2f855a' }, decreasing: { color: '#c44e52' } }; + } + traces.push(indicator); + } else { + // Plotly's `indicator` trace requires a numeric `value` — it has + // no text-display mode. A pre-formatted display string (e.g. + // "$1.2M", a unit already baked in upstream) is rendered as a + // plain annotation pair instead, positioned at the same + // fractional domain the numeric tiles use (offsets scaled by + // this cell's own height) so every tile still lines up in the + // grid regardless of row count. + const cx = (x0 + x0 + cellW) / 2; + const cy = (y0 + y1) / 2; + annotations.push( + { text: caption, x: cx, y: cy + cellH * 0.32, xref: 'paper', yref: 'paper', xanchor: 'center', yanchor: 'middle', showarrow: false, font: { size: captionFontPx, color: '#6b7280' } }, + { text: String(rawValue ?? ''), x: cx, y: cy - cellH * 0.06, xref: 'paper', yref: 'paper', xanchor: 'center', yanchor: 'middle', showarrow: false, font: { size: valueFontPx, color: '#111827' } }, + ...(hasGoal + ? [{ text: `Goal: ${goal}`, x: cx, y: cy - cellH * 0.36, xref: 'paper' as const, yref: 'paper' as const, xanchor: 'center' as const, yanchor: 'middle' as const, showarrow: false, font: { size: goalFontPx, color: '#9ca3af' } }] + : []), + ); + } + }); + + Object.assign(spec, { + data: traces, + layout: { + annotations, + // Indicator traces suppress Plotly's default cartesian axes on + // their own; a card row with only text annotations (a + // pre-formatted string value) has no trace to do that, so the + // axes must be hidden explicitly or a stray 0–1 grid shows + // through behind the text. + xaxis: { visible: false }, + yaxis: { visible: false }, + }, + _width: figWidth, + _height: figHeight, + }); + delete spec.layer; + }, + properties: [ + { + key: 'layout', label: 'Layout', type: 'discrete', + options: [ + { value: 'horizontal', label: 'Horizontal (default)' }, + { value: 'vertical', label: 'Vertical' }, + { value: 'grid', label: 'Grid' }, + ], + } as ChartPropertyDef, + ], +}; diff --git a/packages/flint-js/src/plotly/templates/line.ts b/packages/flint-js/src/plotly/templates/line.ts new file mode 100644 index 00000000..4109a7b1 --- /dev/null +++ b/packages/flint-js/src/plotly/templates/line.ts @@ -0,0 +1,144 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Line Chart template (single + multi-series). + * + * Mirrors the Chart.js Line template's decisions. Plotly differences: + * - temporal x uses Plotly's native `date` axis (ISO strings), no tick + * callback needed — figures stay pure JSON + * - one trace per series; the legend comes from trace `name`s + */ + +import { ChartTemplateDef, ChartPropertyDef } from '../../core/types'; +import { + extractCategories, + groupBy, + buildCategoryAlignedData, + coerceIsoDateForPlotly, + getPlotlyPalette, + getSeriesColor, +} from './utils'; + +const isDiscrete = (type: string | undefined) => type === 'nominal' || type === 'ordinal'; + +/** Map the shared `interpolate` property onto Plotly's `line.shape`. */ +function lineShape(interpolate: unknown): 'linear' | 'spline' | 'hv' | 'vh' | 'hvh' { + switch (interpolate) { + case 'monotone': + case 'basis': + case 'cardinal': + case 'catmull-rom': + return 'spline'; + case 'step': + return 'hvh'; + case 'step-before': + return 'vh'; + case 'step-after': + return 'hv'; + default: + return 'linear'; + } +} + +export const plLineChartDef: ChartTemplateDef = { + chart: 'Line Chart', + template: { mark: 'line', encoding: {} }, + channels: ['x', 'y', 'color', 'opacity', 'column', 'row'], + markCognitiveChannel: 'position', + declareLayoutMode: () => ({ + paramOverrides: { continuousMarkCrossSection: { x: 100, y: 20, seriesCountAxis: 'auto' }, facetAspectRatioResistance: 0.5 }, + }), + instantiate: (spec, ctx) => { + const { channelSemantics, table, chartProperties } = ctx; + const xCS = channelSemantics.x; + const yCS = channelSemantics.y; + const colorField = channelSemantics.color?.field; + + if (!xCS?.field || !yCS?.field) return; + const xField = xCS.field; + const yField = yCS.field; + + const xIsDiscrete = isDiscrete(xCS.type); + const xIsTemporal = xCS.type === 'temporal'; + + const mapX = (raw: unknown) => (xIsTemporal ? coerceIsoDateForPlotly(raw) : raw); + + const categories = xIsDiscrete + ? extractCategories(table, xField, xCS.ordinalSortOrder) + : undefined; + + const shape = lineShape(chartProperties?.interpolate); + const showPoints = chartProperties?.showPoints === true; + const mode = showPoints ? 'lines+markers' : 'lines'; + + const palette = getPlotlyPalette(ctx, 'color'); + const traces: any[] = []; + const makeTrace = (name: string, rows: any[], colorIndex: number) => { + const xVals = xIsDiscrete + ? categories! + : rows.map(r => mapX(r[xField])); + const yVals = xIsDiscrete + ? buildCategoryAlignedData(rows, xField, yField, categories!) + : rows.map(r => (r[yField] == null ? null : r[yField])); + return { + type: 'scatter', + mode, + name, + x: xVals, + y: yVals, + line: { color: getSeriesColor(palette, colorIndex), shape }, + }; + }; + + if (colorField) { + let i = 0; + for (const [name, rows] of groupBy(table, colorField)) { + traces.push(makeTrace(name, rows, i)); + i++; + } + } else { + traces.push(makeTrace(yField, table, 0)); + } + + const xAxisSpec: any = { title: { text: xField } }; + if (xIsDiscrete) { + xAxisSpec.type = 'category'; + xAxisSpec.categoryorder = 'array'; + xAxisSpec.categoryarray = categories; + } else if (xIsTemporal) { + xAxisSpec.type = 'date'; + } + + const yAxisSpec: any = { title: { text: yField } }; + if (yCS.zero) { + yAxisSpec.rangemode = yCS.zero.zero !== false ? 'tozero' : 'normal'; + } + + const figure: any = { + data: traces, + layout: { + xaxis: xAxisSpec, + yaxis: yAxisSpec, + showlegend: !!colorField, + }, + }; + + Object.assign(spec, figure); + delete spec.mark; + delete spec.encoding; + }, + properties: [ + { + key: 'interpolate', label: 'Curve', type: 'discrete', options: [ + { value: undefined, label: 'Default (linear)' }, + { value: 'linear', label: 'Linear' }, + { value: 'monotone', label: 'Monotone (smooth)' }, + { value: 'step', label: 'Step' }, + { value: 'step-before', label: 'Step Before' }, + { value: 'step-after', label: 'Step After' }, + ], + } as ChartPropertyDef, + { key: 'showPoints', label: 'Show points', type: 'binary', defaultValue: false } as ChartPropertyDef, + ], +}; diff --git a/packages/flint-js/src/plotly/templates/lollipop.ts b/packages/flint-js/src/plotly/templates/lollipop.ts new file mode 100644 index 00000000..4b9e606a --- /dev/null +++ b/packages/flint-js/src/plotly/templates/lollipop.ts @@ -0,0 +1,101 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Lollipop Chart template. + * + * A thin `bar` trace (the stem, zero → value) plus a `scatter` marker trace + * (the dot) sharing the same category axis — mirrors `ecLollipopChartDef`. + */ + +import { ChartTemplateDef, ChartPropertyDef, EncodingActionDef } from '../../core/types'; +import { resolveCategoryOrder, buildCategoryAlignedData, detectAxes, groupBy, getPlotlyPalette, getSeriesColor } from './utils'; +import { detectBandedAxisFromSemantics } from '../../core/axis-detection'; +import { makeSortAction } from '../../core/encoding-actions'; + +const STEM_COLOR = '#9aa0a6'; + +export const plLollipopChartDef: ChartTemplateDef = { + chart: 'Lollipop Chart', + template: { mark: 'bar', encoding: {} }, + channels: ['x', 'y', 'color', 'column', 'row'], + markCognitiveChannel: 'length', + declareLayoutMode: (cs, table) => { + const result = detectBandedAxisFromSemantics(cs, table, { preferAxis: 'x' }); + return { + axisFlags: result ? { [result.axis]: { banded: true } } : { x: { banded: true } }, + resolvedTypes: result?.resolvedTypes, + }; + }, + instantiate: (spec, ctx) => { + const { channelSemantics, table, chartProperties } = ctx; + const { categoryAxis, valueAxis } = detectAxes(channelSemantics); + const catField = channelSemantics[categoryAxis]?.field; + const valField = channelSemantics[valueAxis]?.field; + const colorField = channelSemantics.color?.field; + if (!catField || !valField) return; + + const catEnc = ctx.encodings?.[categoryAxis]; + const sortByField = catEnc?.sortBy ? channelSemantics[catEnc.sortBy]?.field : undefined; + const categories = resolveCategoryOrder(table, catField, { + ordinalSortOrder: channelSemantics[categoryAxis]?.ordinalSortOrder, + sortBy: sortByField, sortOrder: catEnc?.sortOrder, + }); + const values = buildCategoryAlignedData(table, catField, valField, categories); + const isHorizontal = categoryAxis === 'y'; + const dotSize = Number(chartProperties?.dotSize ?? 80); + const symbolSizePx = Math.max(6, Math.min(10 + (dotSize - 80) / 40, 16)); + const palette = getPlotlyPalette(ctx, 'color'); + + const stemTrace: any = { + type: 'bar', + name: '__stem', + showlegend: false, + hoverinfo: 'skip', + width: 0.06, + ...(isHorizontal ? { x: values, y: categories, orientation: 'h' } : { x: categories, y: values }), + marker: { color: STEM_COLOR }, + }; + + const dotTraces: any[] = []; + if (colorField) { + let i = 0; + for (const [name, rows] of groupBy(table, colorField)) { + const pts = categories.map(cat => rows.find((r: any) => String(r[catField] ?? '') === cat)); + dotTraces.push({ + type: 'scatter', mode: 'markers', name, + ...(isHorizontal + ? { x: pts.map(r => r?.[valField] ?? null), y: categories } + : { x: categories, y: pts.map(r => r?.[valField] ?? null) }), + marker: { color: getSeriesColor(palette, i), size: symbolSizePx, line: { color: '#fff', width: 1 } }, + }); + i++; + } + } else { + dotTraces.push({ + type: 'scatter', mode: 'markers', showlegend: false, + ...(isHorizontal ? { x: values, y: categories } : { x: categories, y: values }), + marker: { color: getSeriesColor(palette, 0), size: symbolSizePx, line: { color: '#fff', width: 1 } }, + }); + } + + const catAxisSpec = { type: 'category' as const, categoryorder: 'array' as const, categoryarray: categories, title: { text: catField } }; + const valCS = channelSemantics[valueAxis]; + const includeZero = valCS?.zero ? valCS.zero.zero !== false : true; + const valAxisSpec = { title: { text: valField }, rangemode: (includeZero ? 'tozero' : 'normal') as 'tozero' | 'normal' }; + + Object.assign(spec, { + data: [stemTrace, ...dotTraces], + layout: { + ...(isHorizontal ? { xaxis: valAxisSpec, yaxis: catAxisSpec } : { xaxis: catAxisSpec, yaxis: valAxisSpec }), + showlegend: !!colorField, + }, + }); + delete spec.mark; + delete spec.encoding; + }, + properties: [ + { key: 'dotSize', label: 'Dot Size', type: 'continuous', min: 20, max: 300, step: 10, defaultValue: 80 } as ChartPropertyDef, + ], + encodingActions: [makeSortAction()] as EncodingActionDef[], +}; diff --git a/packages/flint-js/src/plotly/templates/map.ts b/packages/flint-js/src/plotly/templates/map.ts new file mode 100644 index 00000000..477351eb --- /dev/null +++ b/packages/flint-js/src/plotly/templates/map.ts @@ -0,0 +1,295 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Map (bubble) template. + * + * Native `scattergeo` trace + `layout.geo`: Plotly ships its own built-in + * world/US basemap (land, country/state borders, oceans) so — unlike the + * Vega-Lite template, which layers a `geoshape` TopoJSON base under a + * `circle` mark — no external topology needs to be fetched or joined. + * + * Data contract (unchanged from Vega-Lite): `longitude`/`latitude` place each + * point; `size`/`color` optionally scale/hue it. Scope (US vs World) is + * decided the same way as the Vega-Lite Map — `region` property, else infer + * from whether every point falls inside the US bounding box + * (`chart-types/geo.ts`, shared by both backends so the same dataset picks + * the same base map regardless of backend). + */ + +import { ChartTemplateDef, ChartPropertyDef, OptionEvalContext } from '../../core/types'; +import { inferBubbleScope, pickMapScope } from '../../chart-types/geo'; +import { getPlotlyPalette, getSeriesColor, groupBy } from './utils'; + +// --------------------------------------------------------------------------- +// Projection mapping (Vega-Lite d3 projection name → Plotly geo projection type) +// --------------------------------------------------------------------------- + +const mapProjections = [ + { value: 'mercator', label: 'Mercator' }, + { value: 'equalEarth', label: 'Equal Earth' }, + { value: 'orthographic', label: 'Orthographic (Globe)' }, + { value: 'stereographic', label: 'Stereographic' }, + { value: 'conicEqualArea', label: 'Conic Equal Area' }, + { value: 'conicEquidistant', label: 'Conic Equidistant' }, + { value: 'azimuthalEquidistant', label: 'Azimuthal Equidistant' }, + { value: 'mollweide', label: 'Mollweide' }, +] as const; + +// Plotly has no exact "Equal Earth" projection; "natural earth" is the +// closest available compromise pseudo-cylindrical projection. +const PROJECTION_TYPE_MAP: Record = { + mercator: 'mercator', + equalEarth: 'natural earth', + orthographic: 'orthographic', + stereographic: 'stereographic', + conicEqualArea: 'conic equal area', + conicEquidistant: 'conic equidistant', + azimuthalEquidistant: 'azimuthal equidistant', + mollweide: 'mollweide', +}; + +function plotlyProjectionType(vlProjection: unknown): string { + if (typeof vlProjection === 'string' && PROJECTION_TYPE_MAP[vlProjection]) { + return PROJECTION_TYPE_MAP[vlProjection]; + } + return 'natural earth'; // default world projection (mirrors VL's equalEarth default) +} + +const projectionCenterPresets: { label: string; center: [number, number] }[] = [ + { label: 'World (Atlantic)', center: [0, 0] }, + { label: 'World (Pacific)', center: [150, 0] }, + { label: 'China', center: [105, 35] }, + { label: 'USA', center: [-98, 39] }, + { label: 'Europe', center: [10, 50] }, + { label: 'Japan', center: [138, 36] }, + { label: 'India', center: [78, 22] }, + { label: 'Brazil', center: [-52, -14] }, + { label: 'Australia', center: [134, -25] }, + { label: 'Russia', center: [100, 60] }, + { label: 'Africa', center: [20, 0] }, + { label: 'Middle East', center: [45, 28] }, + { label: 'Southeast Asia', center: [115, 5] }, + { label: 'South America', center: [-60, -15] }, + { label: 'North America', center: [-100, 45] }, + { label: 'UK', center: [-2, 54] }, + { label: 'Germany', center: [10, 51] }, + { label: 'France', center: [2, 47] }, + { label: 'Korea', center: [128, 36] }, +]; + +/** Would this spec render as a world map? (Drives world-only property gating.) */ +function wouldBeWorld(ctx: OptionEvalContext): boolean { + const choice = ctx.chartProperties?.region; + if (choice === 'us') return false; + if (choice === 'world') return true; + const rows = ctx.data ?? []; + const lonField = ctx.encodings?.longitude?.field; + const latField = ctx.encodings?.latitude?.field; + return inferBubbleScope(rows, lonField, latField) === 'world'; +} + +const regionProperty: ChartPropertyDef = { + key: 'region', + label: 'Region', + type: 'discrete', + options: [ + { value: 'auto', label: 'Auto-detect' }, + { value: 'us', label: 'United States' }, + { value: 'world', label: 'World' }, + ], + defaultValue: 'auto', +}; + +const projectionProperty: ChartPropertyDef = { + key: 'projection', + label: 'Projection', + type: 'discrete', + options: [ + { value: 'default', label: 'Default' }, + ...mapProjections.map(p => ({ value: p.value, label: p.label })), + ], + defaultValue: 'default', + check: (ctx) => ({ applicable: wouldBeWorld(ctx) }), +}; + +const projectionCenterProperty: ChartPropertyDef = { + key: 'projectionCenter', + label: 'Center', + type: 'discrete', + options: [ + { value: undefined, label: 'Default' }, + ...projectionCenterPresets.map(p => ({ + value: p.center, + label: `${p.label} [${p.center[0]}, ${p.center[1]}]`, + })), + ], + defaultValue: undefined, + check: (ctx) => ({ applicable: wouldBeWorld(ctx) }), +}; + +/** Configure `layout.geo` for the chosen scope + (world-only) projection/center. */ +function buildGeoLayout(scope: 'us' | 'world', chartProperties: any): any { + if (scope === 'us') { + return { + scope: 'usa', + projection: { type: 'albers usa' }, + showland: true, landcolor: '#eef0f2', + showlakes: true, lakecolor: '#ffffff', + subunitcolor: '#ffffff', + countrycolor: '#ffffff', + }; + } + const geo: any = { + scope: 'world', + projection: { type: plotlyProjectionType(chartProperties?.projection) }, + showland: true, landcolor: '#eef0f2', + showocean: true, oceancolor: '#ffffff', + showcountries: true, countrycolor: '#c7ccd1', + showcoastlines: false, + }; + const center = chartProperties?.projectionCenter; + if (Array.isArray(center) && center.length === 2) { + geo.projection.rotation = { lon: -Number(center[0]), lat: -Number(center[1]) }; + } + return geo; +} + +/** Sqrt (area-truth) scale from data values to marker pixel diameters. */ +function bubbleDiameters(values: number[], minPx = 6, maxPx = 34): number[] { + const finite = values.filter(v => Number.isFinite(v)); + const lo = finite.length ? Math.min(...finite, 0) : 0; + const hi = finite.length ? Math.max(...finite) : 1; + const sLo = Math.sqrt(Math.max(0, lo)); + const sHi = Math.sqrt(Math.max(sLo + 1e-9, hi)); + return values.map(v => { + if (!Number.isFinite(v)) return minPx; + const s = Math.sqrt(Math.max(0, v)); + const t = (s - sLo) / (sHi - sLo || 1); + return minPx + t * (maxPx - minPx); + }); +} + +export const plMapDef: ChartTemplateDef = { + chart: 'Map', + template: { mark: 'circle', encoding: {} }, + channels: ['longitude', 'latitude', 'color', 'size', 'opacity'], + markCognitiveChannel: 'position', + instantiate: (spec, ctx) => { + const { channelSemantics, chartProperties, colorDecisions } = ctx; + const lonField = channelSemantics.longitude?.field; + const latField = channelSemantics.latitude?.field; + const sizeField = channelSemantics.size?.field; + const colorField = channelSemantics.color?.field; + const colorType = channelSemantics.color?.type; + if (!lonField || !latField) return; + + const rows = (ctx.fullTable ?? ctx.table ?? []).filter((r: any) => + Number.isFinite(Number(r[lonField])) && Number.isFinite(Number(r[latField]))); + if (rows.length === 0) return; + + const scope = pickMapScope(chartProperties, undefined, () => inferBubbleScope(rows, lonField, latField)); + const geo = buildGeoLayout(scope, chartProperties); + + const isContinuousColor = !!colorField && (colorType === 'quantitative' || colorType === 'temporal'); + const sizeValues = sizeField ? rows.map((r: any) => Number(r[sizeField])) : undefined; + const diameters = sizeValues ? bubbleDiameters(sizeValues) : rows.map(() => 10); + + const opacity = 0.85; + const traces: any[] = []; + + if (isContinuousColor && colorField) { + const toColorVal = colorType === 'temporal' + ? (v: any) => (v != null ? new Date(v).getTime() : NaN) + : (v: any) => (v != null ? Number(v) : NaN); + const colorVals = rows.map((r: any) => toColorVal(r[colorField])).filter((v: number) => !isNaN(v)); + const cmin = colorVals.length ? Math.min(...colorVals) : 0; + const cmax = colorVals.length ? Math.max(...colorVals) : 1; + const decision = colorDecisions?.color ?? colorDecisions?.group; + const diverging = decision?.schemeType === 'diverging'; + traces.push({ + type: 'scattergeo', + mode: 'markers', + name: colorField, + lon: rows.map((r: any) => Number(r[lonField])), + lat: rows.map((r: any) => Number(r[latField])), + marker: { + size: diameters, + color: rows.map((r: any) => toColorVal(r[colorField])), + colorscale: diverging ? 'RdBu' : 'Viridis', + cmin, cmax, + showscale: true, + colorbar: { title: { text: colorField } }, + opacity, + line: { color: '#ffffff', width: 0.5 }, + }, + hovertemplate: `Lon: %{lon}
Lat: %{lat}
${colorField}: %{marker.color}` + + (sizeField ? `
${sizeField}: %{customdata}` : '') + '', + customdata: sizeField ? sizeValues : undefined, + }); + } else if (colorField) { + // Nominal/ordinal color: one trace per group (legend by group name). + // Bubble diameters come from the SAME global sqrt scale computed + // above (over every row) so sizes stay comparable across groups — + // index into `diameters` by each row's position in `rows`. + const palette = getPlotlyPalette(ctx, 'color'); + const idxByRow = new Map(rows.map((r: any, idx: number) => [r, idx])); + let i = 0; + for (const [name, groupRows] of groupBy(rows, colorField)) { + const groupSizes = sizeField ? groupRows.map((r: any) => Number(r[sizeField])) : undefined; + const sizesForGroup = groupRows.map((r: any) => diameters[idxByRow.get(r) ?? 0]); + traces.push({ + type: 'scattergeo', + mode: 'markers', + name, + lon: groupRows.map((r: any) => Number(r[lonField])), + lat: groupRows.map((r: any) => Number(r[latField])), + marker: { + size: sizesForGroup, + color: getSeriesColor(palette, i), + opacity, + line: { color: '#ffffff', width: 0.5 }, + }, + hovertemplate: `Lon: %{lon}
Lat: %{lat}
${colorField}: ${name}` + + (sizeField ? `
${sizeField}: %{customdata}` : '') + '', + customdata: groupSizes, + }); + i++; + } + } else { + traces.push({ + type: 'scattergeo', + mode: 'markers', + showlegend: false, + lon: rows.map((r: any) => Number(r[lonField])), + lat: rows.map((r: any) => Number(r[latField])), + marker: { + size: diameters, + color: getSeriesColor(getPlotlyPalette(ctx, 'color'), 0), + opacity, + line: { color: '#ffffff', width: 0.5 }, + }, + hovertemplate: 'Lon: %{lon}
Lat: %{lat}' + + (sizeField ? `
${sizeField}: %{customdata}` : '') + '', + customdata: sizeValues, + }); + } + + const width = scope === 'us' ? 520 : 620; + const height = scope === 'us' ? 320 : 360; + + Object.assign(spec, { + data: traces, + layout: { + geo, + showlegend: !!colorField && !isContinuousColor, + margin: { t: 24, b: 24, l: 8, r: 8 }, + }, + _width: width + (colorField ? 120 : 0), + _height: height, + }); + delete spec.mark; + delete spec.encoding; + }, + properties: [regionProperty, projectionProperty, projectionCenterProperty], +}; diff --git a/packages/flint-js/src/plotly/templates/pie.ts b/packages/flint-js/src/plotly/templates/pie.ts new file mode 100644 index 00000000..9c238065 --- /dev/null +++ b/packages/flint-js/src/plotly/templates/pie.ts @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Pie Chart + Donut Chart templates. + * + * Native `pie` trace: `hole` produces a donut with no extra geometry. + * Pie charts have no cartesian axes, so this template sets `figure._width` / + * `_height` itself and `plApplyLayoutToSpec` (which only fills in unset + * sizes) leaves them alone. + */ + +import { ChartTemplateDef, ChartPropertyDef } from '../../core/types'; +import { extractCategories, getPlotlyPalette } from './utils'; +import { computeCircumferencePressure, computeEffectiveBarCount } from '../../core/decisions'; + +function buildPieOption(spec: any, ctx: any, hole: number): void { + const { channelSemantics, table, chartProperties } = ctx; + const colorField = channelSemantics.color?.field; + const sizeField = channelSemantics.size?.field; + + const labels: string[] = []; + const values: number[] = []; + + if (colorField && sizeField) { + const agg = new Map(); + for (const row of table) { + const cat = String(row[colorField] ?? ''); + agg.set(cat, (agg.get(cat) ?? 0) + (Number(row[sizeField]) || 0)); + } + const categories = extractCategories(table, colorField, channelSemantics.color?.ordinalSortOrder); + for (const cat of categories) { labels.push(cat); values.push(agg.get(cat) ?? 0); } + } else if (colorField) { + const counts = new Map(); + for (const row of table) { + const cat = String(row[colorField] ?? ''); + counts.set(cat, (counts.get(cat) ?? 0) + 1); + } + const categories = extractCategories(table, colorField, channelSemantics.color?.ordinalSortOrder); + for (const cat of categories) { labels.push(cat); values.push(counts.get(cat) ?? 0); } + } else if (sizeField) { + for (const row of table) { + const v = Number(row[sizeField]) || 0; + labels.push(String(v)); + values.push(v); + } + } + if (labels.length === 0) return; + + const sortSlices = chartProperties?.sortSlices; + const order = labels.map((_l, i) => i); + if (sortSlices === 'descending') order.sort((a, b) => values[b] - values[a]); + else if (sortSlices === 'ascending') order.sort((a, b) => values[a] - values[b]); + const sortedLabels = order.map(i => labels[i]); + const sortedValues = order.map(i => values[i]); + + const labelType = chartProperties?.labelType ?? 'categoryPercent'; + const textinfo: Record = { + none: 'none', category: 'label', value: 'value', percent: 'percent', categoryPercent: 'label+percent', + }; + + const palette = getPlotlyPalette(ctx, 'color'); + + // Canvas sizing: a native Plotly pie fills the largest circle that fits + // in the canvas AND auto-reserves horizontal room for the legend on the + // right — so we deliberately DON'T pin an explicit `domain`. The previous + // centered domain (with an 80px radius margin) shrank the circle to ~half + // its natural size and wasted matching space on the left. We keep only the + // circumference-pressure model to GROW the canvas when a dense pie (many + // thin slices) needs a bigger circle to give each slice its minimum arc. + const effectiveCount = computeEffectiveBarCount(sortedValues); + const { canvasW, canvasH } = computeCircumferencePressure(effectiveCount, ctx.canvasSize, { + minArcPx: 45, + minRadius: 60, + maxStretch: ctx.assembleOptions?.maxStretch, + maxStretchX: ctx.assembleOptions?.maxStretchX, + maxStretchY: ctx.assembleOptions?.maxStretchY, + margin: 24, + }); + + // Symmetric margin leaves room for the outside slice callouts (thin slices + // draw their label + connector just beyond the ring); Plotly grows the + // legend within its own reserved right gutter, so no vertical padding hack + // is needed. + const n = sortedLabels.length; + const hasOutsideLabels = labelType !== 'none'; + const labelMargin = hasOutsideLabels ? Math.min(48, 20 + n) : 12; + + Object.assign(spec, { + data: [{ + type: 'pie', + labels: sortedLabels, + values: sortedValues, + hole, + textinfo: textinfo[labelType] ?? 'label+percent', + // Let outside slice labels push the margins so a cluster of thin + // slices (many tiny wedges crowded together) doesn't clip its + // stacked callouts against the canvas edge. + automargin: true, + marker: { colors: palette, line: { color: '#ffffff', width: 1 } }, + }], + layout: { + showlegend: true, + margin: { t: labelMargin, b: labelMargin, l: 12, r: 12 }, + }, + _width: canvasW, + _height: canvasH, + }); + delete spec.mark; + delete spec.encoding; +} + +const PIE_PROPERTIES: ChartPropertyDef[] = [ + { + key: 'sortSlices', label: 'Sort slices', type: 'discrete', + options: [ + { value: 'none', label: 'Data order' }, + { value: 'descending', label: 'Largest first' }, + { value: 'ascending', label: 'Smallest first' }, + ], + defaultValue: 'none', + }, + { + key: 'labelType', label: 'Labels', type: 'discrete', + options: [ + { value: 'categoryPercent', label: 'Name + %' }, + { value: 'category', label: 'Name' }, + { value: 'value', label: 'Value' }, + { value: 'percent', label: 'Percent' }, + { value: 'none', label: 'None' }, + ], + defaultValue: 'categoryPercent', + }, +]; + +export const plPieChartDef: ChartTemplateDef = { + chart: 'Pie Chart', + template: { mark: 'arc', encoding: {} }, + channels: ['size', 'color'], + markCognitiveChannel: 'area', + instantiate: (spec, ctx) => buildPieOption(spec, ctx, 0), + properties: PIE_PROPERTIES, +}; + +export const plDonutChartDef: ChartTemplateDef = { + chart: 'Donut Chart', + template: { mark: 'arc', encoding: {} }, + channels: ['size', 'color'], + markCognitiveChannel: 'area', + instantiate: (spec, ctx) => buildPieOption(spec, ctx, (ctx.chartProperties?.innerRadius ?? 55) / 100), + properties: [ + { key: 'innerRadius', label: 'Donut', type: 'continuous', min: 20, max: 80, step: 5, defaultValue: 55 } as ChartPropertyDef, + ...PIE_PROPERTIES, + ], +}; diff --git a/packages/flint-js/src/plotly/templates/radar.ts b/packages/flint-js/src/plotly/templates/radar.ts new file mode 100644 index 00000000..a72b6df3 --- /dev/null +++ b/packages/flint-js/src/plotly/templates/radar.ts @@ -0,0 +1,219 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Radar Chart template. + * + * Native `scatterpolar` trace with `fill: 'toself'` — Plotly handles the + * polar projection, axis spokes, and grid rings natively (no manual trig + * like the Vega-Lite template needs). + * + * Data model (long format): x = metric name, y = value, color = entity/group. + */ + +import { ChartTemplateDef, ChartPropertyDef } from '../../core/types'; +import { extractCategories, groupBy, getPlotlyPalette, getSeriesColor, fillColor, niceMax } from './utils'; +import { computeCircumferencePressure } from '../../core/decisions'; + +export const plRadarChartDef: ChartTemplateDef = { + chart: 'Radar Chart', + template: { mark: 'point', encoding: {} }, + channels: ['x', 'y', 'color', 'column', 'row'], + markCognitiveChannel: 'position', + // Radar is POLAR, not cartesian. The generic facet combiner (facet.ts) + // only stitches cartesian xaxis/yaxis panels, so it collapses every + // facet's `scatterpolar` traces into the single default `polar` subplot + // (all regions overlaid in one radar). Opt out and lay one polar subplot + // per facet cell out internally — mirrors the Gauge template. + selfManagesFacets: true, + instantiate: (spec, ctx) => { + const { channelSemantics, table, chartProperties } = ctx; + const axisField = channelSemantics.x?.field; + const valueField = channelSemantics.y?.field; + const groupField = channelSemantics.color?.field; + const columnField = channelSemantics.column?.field; + const rowField = channelSemantics.row?.field; + if (!axisField || !valueField) return; + + const metrics = extractCategories(table, axisField, channelSemantics.x?.ordinalSortOrder); + if (metrics.length < 2) return; + + // Close the loop: repeat the first metric at the end so the polygon closes. + const closedMetrics = [...metrics, metrics[0]]; + + const meanPerMetric = (rows: any[]) => { + const sums = new Map(); + for (const row of rows) { + const m = String(row[axisField] ?? ''); + const v = Number(row[valueField]) || 0; + const e = sums.get(m) ?? { sum: 0, count: 0 }; + e.sum += v; e.count++; + sums.set(m, e); + } + return metrics.map(m => { + const e = sums.get(m); + return e ? Math.round((e.sum / e.count) * 100) / 100 : 0; + }); + }; + + const filled = chartProperties?.filled !== false; + const fillOpacity = Number(chartProperties?.fillOpacity ?? 0.3); + const palette = getPlotlyPalette(ctx, 'color'); + + // Global radial max across ALL data so facets share one comparable + // scale (a per-facet max would make regions visually incomparable). + const allVals = table.map((r: any) => Number(r[valueField])).filter((v: number) => isFinite(v)); + const radialMax = niceMax(allVals.length > 0 ? Math.max(...allVals) : 1); + + // Consistent color per group across every facet cell. + const groupOrder = groupField + ? extractCategories(table, groupField, channelSemantics.color?.ordinalSortOrder) + : []; + const groupIdx = (name: string) => { + const k = groupOrder.indexOf(name); + return k >= 0 ? k : 0; + }; + + const makeTrace = ( + name: string | undefined, rows: any[], idx: number, + polarKey: string, showlegend: boolean, + ) => { + const values = meanPerMetric(rows); + const closedValues = [...values, values[0]]; + const color = getSeriesColor(palette, idx); + return { + type: 'scatterpolar', + mode: 'lines+markers', + ...(name != null ? { name, legendgroup: name } : {}), + showlegend, + r: closedValues, + theta: closedMetrics, + subplot: polarKey, + line: { color }, + marker: { color }, + fill: filled ? ('toself' as const) : undefined, + fillcolor: filled ? fillColor(color, fillOpacity) : undefined, + }; + }; + + // ── Facet grid ──────────────────────────────────────────────── + const colCats = columnField + ? extractCategories(table, columnField, channelSemantics.column?.ordinalSortOrder) + : ['']; + const rowCats = rowField + ? extractCategories(table, rowField, channelSemantics.row?.ordinalSortOrder) + : ['']; + const faceted = !!(columnField || rowField); + const cols = Math.max(1, colCats.length); + const gridRows = Math.max(1, rowCats.length); + + const traces: any[] = []; + const annotations: any[] = []; + const layout: any = { showlegend: !!groupField }; + + // Canvas size first — needed to convert fixed-px label margins into + // domain fractions below. + let width: number; + let height: number; + if (faceted) { + // One radar per cell; grow the canvas so each stays legible. + width = Math.max(ctx.canvasSize.width, cols * 240); + height = Math.max(ctx.canvasSize.height, gridRows * 250); + } else { + const p = computeCircumferencePressure(metrics.length, ctx.canvasSize, { + minArcPx: 60, + minRadius: 80, + maxStretch: ctx.assembleOptions?.maxStretch, + maxStretchX: ctx.assembleOptions?.maxStretchX, + maxStretchY: ctx.assembleOptions?.maxStretchY, + }); + width = p.canvasW; + height = p.canvasH; + } + + const gapFrac = faceted ? 0.05 : 0; + const cellW = (1 - gapFrac * (cols - 1)) / cols; + const cellH = (1 - gapFrac * (gridRows - 1)) / gridRows; + const titlePad = faceted ? 26 / height : 0; + // The angular (metric) labels sit just outside the circle on all four + // sides. Inset the polar domain inside each cell so a side label + // ("Retention"/"Profit") stays within its OWN cell instead of colliding + // with the neighbouring radar's label across the gap. + const insetXFrac = faceted ? 40 / width : 0; + const insetYFrac = faceted ? 16 / height : 0; + + const legendShown = new Set(); + let cellIndex = 0; + for (let r = 0; r < gridRows; r++) { + for (let c = 0; c < cols; c++) { + const x0 = c * (cellW + gapFrac); + const x1 = x0 + cellW; + const yTop = 1 - r * (cellH + gapFrac); + const y0 = yTop - cellH; + const polarKey = cellIndex === 0 ? 'polar' : `polar${cellIndex + 1}`; + + const cellRows = table.filter((row: any) => { + if (columnField && String(row[columnField] ?? '') !== colCats[c]) return false; + if (rowField && String(row[rowField] ?? '') !== rowCats[r]) return false; + return true; + }); + + if (faceted) { + const label = [columnField ? colCats[c] : null, rowField ? rowCats[r] : null] + .filter(Boolean).join(' · '); + annotations.push({ + text: label, xref: 'paper', yref: 'paper', + x: (x0 + x1) / 2, y: yTop, xanchor: 'center', yanchor: 'top', + showarrow: false, font: { size: 12, color: '#374151' }, + }); + } + + layout[polarKey] = { + domain: { + x: [x0 + insetXFrac, x1 - insetXFrac], + y: [y0 + insetYFrac, yTop - titlePad - insetYFrac], + }, + radialaxis: { + visible: true, range: [0, radialMax], + showticklabels: !faceted, tickfont: { size: 9 }, + }, + angularaxis: { + rotation: 90, direction: 'clockwise', + tickfont: { size: faceted ? 10 : 12 }, + }, + }; + + if (groupField) { + for (const [name, rows] of groupBy(cellRows, groupField)) { + const show = !legendShown.has(name); + legendShown.add(name); + traces.push(makeTrace(name, rows, groupIdx(name), polarKey, show)); + } + } else { + traces.push(makeTrace(undefined, cellRows, 0, polarKey, false)); + } + cellIndex++; + } + } + + if (faceted) layout.annotations = annotations; + + Object.assign(spec, { + data: traces, + layout, + _width: width, + _height: height, + }); + delete spec.mark; + delete spec.encoding; + }, + properties: [ + { + key: 'filled', label: 'Fill', type: 'discrete', options: [ + { value: true, label: 'Filled (default)' }, + { value: false, label: 'Outline only' }, + ], + } as ChartPropertyDef, + { key: 'fillOpacity', label: 'Opacity', type: 'continuous', min: 0.05, max: 0.8, step: 0.05, defaultValue: 0.3 } as ChartPropertyDef, + ], +}; diff --git a/packages/flint-js/src/plotly/templates/range-area.ts b/packages/flint-js/src/plotly/templates/range-area.ts new file mode 100644 index 00000000..0eb4f3af --- /dev/null +++ b/packages/flint-js/src/plotly/templates/range-area.ts @@ -0,0 +1,101 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Range Area Chart (band / high–low ribbon) template. + * + * A filled band between a lower (`y`) and upper (`y2`) bound at each x. + * Plotly's native `fill: 'tonexty'` fills the region between two + * consecutive traces sharing the same x — the idiomatic Plotly ribbon, + * simpler than the other backends' transparent-base + delta-stack trick. + */ + +import { ChartTemplateDef, ChartPropertyDef } from '../../core/types'; +import { isDiscreteType, extractCategories, groupBy, coerceIsoDateForPlotly, getPlotlyPalette, getSeriesColor, fillColor } from './utils'; + +export const plRangeAreaChartDef: ChartTemplateDef = { + chart: 'Range Area Chart', + template: { mark: 'area', encoding: {} }, + channels: ['x', 'y', 'y2', 'color', 'column', 'row'], + markCognitiveChannel: 'area', + declareLayoutMode: () => ({ + paramOverrides: { continuousMarkCrossSection: { x: 100, y: 20, seriesCountAxis: 'auto' } }, + }), + instantiate: (spec, ctx) => { + const { channelSemantics, table, chartProperties } = ctx; + const xCS = channelSemantics.x; + const yCS = channelSemantics.y; + const y2CS = channelSemantics.y2; + const colorField = channelSemantics.color?.field; + if (!xCS?.field || !yCS?.field || !y2CS?.field) return; + + const xField = xCS.field; + const lowField = yCS.field; + const highField = y2CS.field; + const xIsDiscrete = isDiscreteType(xCS.type); + const xIsTemporal = xCS.type === 'temporal'; + const mapX = (raw: unknown) => (xIsTemporal ? coerceIsoDateForPlotly(raw) : raw); + + const opacity = Number(chartProperties?.opacity ?? 0.35); + const palette = getPlotlyPalette(ctx, 'color'); + + // Sort each group by x so the polygon traces a clean band (unsorted + // data would zig-zag the fill). + const sortRows = (rows: any[]) => xIsDiscrete ? rows : [...rows].sort((a, b) => { + const av = xIsTemporal ? new Date(a[xField]).getTime() : Number(a[xField]); + const bv = xIsTemporal ? new Date(b[xField]).getTime() : Number(b[xField]); + return av - bv; + }); + + const makeBand = (name: string | undefined, rows: any[], idx: number) => { + const sorted = sortRows(rows); + const xs = xIsDiscrete ? sorted.map((r: any) => r[xField]) : sorted.map((r: any) => mapX(r[xField])); + const color = getSeriesColor(palette, idx); + return [ + { + type: 'scatter', mode: 'lines', showlegend: false, + name: name != null ? `${name} (low)` : 'low', + x: xs, y: sorted.map((r: any) => r[lowField]), + line: { width: 0, color }, + hoverinfo: 'skip' as const, + }, + { + type: 'scatter', mode: 'lines', + ...(name != null ? { name } : {}), + x: xs, y: sorted.map((r: any) => r[highField]), + line: { width: 1.5, color }, + fill: 'tonexty' as const, + fillcolor: fillColor(color, opacity), + }, + ]; + }; + + const traces: any[] = []; + if (colorField) { + let i = 0; + for (const [name, rows] of groupBy(table, colorField)) { traces.push(...makeBand(name, rows, i)); i++; } + } else { + traces.push(...makeBand(undefined, table, 0)); + } + + const xAxisSpec: any = { title: { text: xField } }; + if (xIsDiscrete) { + xAxisSpec.type = 'category'; + xAxisSpec.categoryorder = 'array'; + xAxisSpec.categoryarray = extractCategories(table, xField, xCS.ordinalSortOrder); + } else if (xIsTemporal) { + xAxisSpec.type = 'date'; + } + const valueTitle = lowField === highField ? lowField : `${lowField}, ${highField}`; + + Object.assign(spec, { + data: traces, + layout: { xaxis: xAxisSpec, yaxis: { title: { text: valueTitle } }, showlegend: !!colorField }, + }); + delete spec.mark; + delete spec.encoding; + }, + properties: [ + { key: 'opacity', label: 'Opacity', type: 'continuous', min: 0.1, max: 1, step: 0.05, defaultValue: 0.35 } as ChartPropertyDef, + ], +}; diff --git a/packages/flint-js/src/plotly/templates/ranged-dot.ts b/packages/flint-js/src/plotly/templates/ranged-dot.ts new file mode 100644 index 00000000..b58f989f --- /dev/null +++ b/packages/flint-js/src/plotly/templates/ranged-dot.ts @@ -0,0 +1,93 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Ranged Dot Plot template. + * + * A thin connector line per category plus colored point markers — typically + * used for min/max-style ranges (e.g. one line per country spanning its + * lowest to highest reading, with markers colored by reading type). Mirrors + * `ecRangedDotPlotDef`. + */ + +import { ChartTemplateDef } from '../../core/types'; +import { isDiscreteType, extractCategories, groupBy, getPlotlyPalette, getSeriesColor } from './utils'; + +export const plRangedDotPlotDef: ChartTemplateDef = { + chart: 'Ranged Dot Plot', + template: { mark: 'line', encoding: {} }, + channels: ['x', 'y', 'color'], + markCognitiveChannel: 'position', + instantiate: (spec, ctx) => { + const { channelSemantics, table } = ctx; + const xField = channelSemantics.x?.field; + const yField = channelSemantics.y?.field; + const colorField = channelSemantics.color?.field; + if (!xField || !yField) return; + + const xIsDiscrete = isDiscreteType(channelSemantics.x?.type); + const yIsDiscrete = isDiscreteType(channelSemantics.y?.type); + // The categorical axis carries one connector segment; the continuous + // axis carries the range extent. + const catAxis: 'x' | 'y' = yIsDiscrete ? 'y' : xIsDiscrete ? 'x' : 'y'; + const catField = catAxis === 'y' ? yField : xField; + const contField = catAxis === 'y' ? xField : yField; + + const categories = extractCategories(table, catField, channelSemantics[catAxis]?.ordinalSortOrder); + const byCat = groupBy(table, catField); + + // Connector segments: one [min, max] line per category, drawn behind the points. + const segX: (number | string | null)[] = []; + const segY: (number | string | null)[] = []; + for (const cat of categories) { + const rows = byCat.get(cat) ?? []; + const vals = rows.map((r: any) => Number(r[contField])).filter((v: number) => isFinite(v)); + if (vals.length === 0) continue; + const lo = Math.min(...vals); + const hi = Math.max(...vals); + if (catAxis === 'y') { segX.push(lo, hi, null); segY.push(cat, cat, null); } + else { segX.push(cat, cat, null); segY.push(lo, hi, null); } + } + + const traces: any[] = [{ + type: 'scatter', mode: 'lines', name: '', showlegend: false, + x: segX, y: segY, + line: { color: '#999', width: 2 }, + hoverinfo: 'skip', + }]; + + const palette = getPlotlyPalette(ctx, 'color'); + if (colorField) { + let i = 0; + for (const [name, rows] of groupBy(table, colorField)) { + traces.push({ + type: 'scatter', mode: 'markers', name, + x: catAxis === 'y' ? rows.map((r: any) => r[contField]) : rows.map((r: any) => r[catField]), + y: catAxis === 'y' ? rows.map((r: any) => r[catField]) : rows.map((r: any) => r[contField]), + marker: { color: getSeriesColor(palette, i), size: 9 }, + }); + i++; + } + } else { + traces.push({ + type: 'scatter', mode: 'markers', showlegend: false, + x: catAxis === 'y' ? table.map((r: any) => r[contField]) : table.map((r: any) => r[catField]), + y: catAxis === 'y' ? table.map((r: any) => r[catField]) : table.map((r: any) => r[contField]), + marker: { color: getSeriesColor(palette, 0), size: 9 }, + }); + } + + const catAxisSpec = { type: 'category' as const, categoryorder: 'array' as const, categoryarray: categories, title: { text: catField } }; + const contAxisSpec = { title: { text: contField } }; + + Object.assign(spec, { + data: traces, + layout: { + ...(catAxis === 'y' ? { yaxis: catAxisSpec, xaxis: contAxisSpec } : { xaxis: catAxisSpec, yaxis: contAxisSpec }), + showlegend: !!colorField, + }, + }); + delete spec.mark; + delete spec.encoding; + }, +}; diff --git a/packages/flint-js/src/plotly/templates/regression.ts b/packages/flint-js/src/plotly/templates/regression.ts new file mode 100644 index 00000000..37aed78b --- /dev/null +++ b/packages/flint-js/src/plotly/templates/regression.ts @@ -0,0 +1,191 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Regression template — scatter + fitted trend line. + * + * Plotly has no built-in regression transform (Vega-Lite's `transform: + * [{regression}]` runs in the Vega runtime); the fit is computed here, + * mirroring `ecRegressionDef`. + */ + +import { ChartTemplateDef, ChartPropertyDef } from '../../core/types'; +import { groupBy, getPlotlyPalette, getSeriesColor } from './utils'; + +/** Simple linear regression: slope and intercept. */ +function linearRegression(data: number[][]): { slope: number; intercept: number; xMin: number; xMax: number } { + const n = data.length; + if (n === 0) return { slope: 0, intercept: 0, xMin: 0, xMax: 0 }; + let sumX = 0, sumY = 0, sumXY = 0, sumXX = 0; + let xMin = data[0][0], xMax = data[0][0]; + for (const [x, y] of data) { + sumX += x; sumY += y; sumXY += x * y; sumXX += x * x; + if (x < xMin) xMin = x; + if (x > xMax) xMax = x; + } + const slope = (n * sumXY - sumX * sumY) / (n * sumXX - sumX * sumX) || 0; + const intercept = (sumY - slope * sumX) / n; + return { slope, intercept, xMin, xMax }; +} + +/** Polynomial regression via least-squares normal equations. */ +function polyRegression(data: number[][], order: number): { coeffs: number[]; xMin: number; xMax: number } { + const n = data.length; + if (n === 0) return { coeffs: [0], xMin: 0, xMax: 0 }; + let xMin = data[0][0], xMax = data[0][0]; + for (const [x] of data) { if (x < xMin) xMin = x; if (x > xMax) xMax = x; } + const k = order + 1; + const xtx: number[][] = Array.from({ length: k }, () => new Array(k).fill(0)); + const xty: number[] = new Array(k).fill(0); + for (const [x, y] of data) { + const xp: number[] = new Array(2 * order + 1); + xp[0] = 1; + for (let p = 1; p < xp.length; p++) xp[p] = xp[p - 1] * x; + for (let i = 0; i < k; i++) { + xty[i] += y * xp[i]; + for (let j = 0; j < k; j++) xtx[i][j] += xp[i + j]; + } + } + const aug: number[][] = xtx.map((row, i) => [...row, xty[i]]); + for (let col = 0; col < k; col++) { + let maxRow = col; + for (let row = col + 1; row < k; row++) if (Math.abs(aug[row][col]) > Math.abs(aug[maxRow][col])) maxRow = row; + if (maxRow !== col) [aug[col], aug[maxRow]] = [aug[maxRow], aug[col]]; + const pivot = aug[col][col]; + if (Math.abs(pivot) < 1e-12) continue; + for (let j = col; j <= k; j++) aug[col][j] /= pivot; + for (let row = 0; row < k; row++) { + if (row === col) continue; + const factor = aug[row][col]; + for (let j = col; j <= k; j++) aug[row][j] -= factor * aug[col][j]; + } + } + return { coeffs: aug.map(row => row[k]), xMin, xMax }; +} + +function polyEval(coeffs: number[], x: number): number { + let result = 0, xp = 1; + for (const c of coeffs) { result += c * xp; xp *= x; } + return result; +} + +/** Generate regression curve points for a given method. */ +function regressionCurvePoints(data: number[][], method: string, order: number, numPoints = 50): number[][] { + if (data.length === 0) return []; + if (method === 'linear' || !method) { + const reg = linearRegression(data); + return [[reg.xMin, reg.slope * reg.xMin + reg.intercept], [reg.xMax, reg.slope * reg.xMax + reg.intercept]]; + } + if (method === 'log') { + const filtered = data.filter(([x]) => x > 0); + if (filtered.length < 2) return []; + const reg = linearRegression(filtered.map(([x, y]) => [Math.log(x), y])); + let xMin = Infinity, xMax = -Infinity; + for (const [x] of filtered) { if (x < xMin) xMin = x; if (x > xMax) xMax = x; } + return Array.from({ length: numPoints }, (_v, i) => { + const x = xMin + (xMax - xMin) * i / (numPoints - 1); + return [x, reg.intercept + reg.slope * Math.log(x)]; + }); + } + if (method === 'exp') { + const filtered = data.filter(([, y]) => y > 0); + if (filtered.length < 2) return []; + const reg = linearRegression(filtered.map(([x, y]) => [x, Math.log(y)])); + let xMin = Infinity, xMax = -Infinity; + for (const [x] of filtered) { if (x < xMin) xMin = x; if (x > xMax) xMax = x; } + return Array.from({ length: numPoints }, (_v, i) => { + const x = xMin + (xMax - xMin) * i / (numPoints - 1); + return [x, Math.exp(reg.intercept + reg.slope * x)]; + }); + } + if (method === 'pow') { + const filtered = data.filter(([x, y]) => x > 0 && y > 0); + if (filtered.length < 2) return []; + const reg = linearRegression(filtered.map(([x, y]) => [Math.log(x), Math.log(y)])); + let xMin = Infinity, xMax = -Infinity; + for (const [x] of filtered) { if (x < xMin) xMin = x; if (x > xMax) xMax = x; } + return Array.from({ length: numPoints }, (_v, i) => { + const x = xMin + (xMax - xMin) * i / (numPoints - 1); + return [x, Math.exp(reg.intercept) * Math.pow(x, reg.slope)]; + }); + } + if (method === 'quad' || method === 'poly') { + const reg = polyRegression(data, method === 'quad' ? 2 : order); + return Array.from({ length: numPoints }, (_v, i) => { + const x = reg.xMin + (reg.xMax - reg.xMin) * i / (numPoints - 1); + return [x, polyEval(reg.coeffs, x)]; + }); + } + const reg = linearRegression(data); + return [[reg.xMin, reg.slope * reg.xMin + reg.intercept], [reg.xMax, reg.slope * reg.xMax + reg.intercept]]; +} + +export const plRegressionDef: ChartTemplateDef = { + chart: 'Regression', + template: { mark: 'circle', encoding: {} }, + channels: ['x', 'y', 'size', 'color', 'column', 'row'], + markCognitiveChannel: 'position', + instantiate: (spec, ctx) => { + const { channelSemantics, table, chartProperties } = ctx; + const xField = channelSemantics.x?.field; + const yField = channelSemantics.y?.field; + const colorField = channelSemantics.color?.field; + if (!xField || !yField) return; + + const method = String(chartProperties?.regressionMethod ?? 'linear'); + const polyOrder = Number(chartProperties?.polyOrder ?? 3); + const opacity = Number(chartProperties?.opacity ?? 1); + const palette = getPlotlyPalette(ctx, 'color'); + + const traces: any[] = []; + const pushGroup = (name: string | undefined, rows: any[], idx: number) => { + const data = rows.map((r: any) => [Number(r[xField]), Number(r[yField])]).filter(([x, y]) => isFinite(x) && isFinite(y)); + const lineData = regressionCurvePoints(data, method, polyOrder); + const color = getSeriesColor(palette, idx); + traces.push({ + type: 'scatter', mode: 'markers', + ...(name != null ? { name } : {}), + x: data.map(d => d[0]), y: data.map(d => d[1]), + marker: { color, opacity }, + }); + traces.push({ + type: 'scatter', mode: 'lines', + name: name != null ? `${name} (trend)` : 'Trend', + x: lineData.map(d => d[0]), y: lineData.map(d => d[1]), + line: { color: name != null ? color : '#ee6666', width: 2, shape: method !== 'linear' ? 'spline' : 'linear' }, + }); + }; + + if (colorField) { + let i = 0; + for (const [name, rows] of groupBy(table, colorField)) { pushGroup(name, rows, i); i++; } + } else { + pushGroup(undefined, table, 0); + } + + const xAxisSpec: any = { title: { text: xField } }; + const yAxisSpec: any = { title: { text: yField } }; + if (channelSemantics.x?.zero) xAxisSpec.rangemode = channelSemantics.x.zero.zero !== false ? 'tozero' : 'normal'; + if (channelSemantics.y?.zero) yAxisSpec.rangemode = channelSemantics.y.zero.zero !== false ? 'tozero' : 'normal'; + + Object.assign(spec, { data: traces, layout: { xaxis: xAxisSpec, yaxis: yAxisSpec, showlegend: !!colorField } }); + delete spec.mark; + delete spec.encoding; + }, + properties: [ + { + key: 'regressionMethod', label: 'Method', type: 'discrete', + options: [ + { value: 'linear', label: 'Linear' }, + { value: 'log', label: 'Logarithmic' }, + { value: 'exp', label: 'Exponential' }, + { value: 'pow', label: 'Power' }, + { value: 'quad', label: 'Quadratic' }, + { value: 'poly', label: 'Polynomial' }, + ], + defaultValue: 'linear', + } as ChartPropertyDef, + { key: 'polyOrder', label: 'Poly Order', type: 'continuous', min: 2, max: 10, step: 1, defaultValue: 3 } as ChartPropertyDef, + { key: 'opacity', label: 'Opacity', type: 'continuous', min: 0.1, max: 1, step: 0.05, defaultValue: 1 } as ChartPropertyDef, + ], +}; diff --git a/packages/flint-js/src/plotly/templates/rose.ts b/packages/flint-js/src/plotly/templates/rose.ts new file mode 100644 index 00000000..f841ca9a --- /dev/null +++ b/packages/flint-js/src/plotly/templates/rose.ts @@ -0,0 +1,116 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Rose Chart (Nightingale / Coxcomb) template. + * + * Native `barpolar` trace: bars in polar coordinates, one wedge per angular + * category. `layout.barmode: 'stack'` stacks color groups radially — Plotly + * handles the polar stacking natively. + * + * NOTE on area-truth: the Vega-Lite/ECharts Rose templates map value → sqrt(value) + * so wedge AREA is proportional to value (matching a true rose/Nightingale + * chart). Plotly's native polar bar stacking sums raw `r` values, and undoing + * that to preserve sqrt-area-truth under stacking would require reimplementing + * the stacking arithmetic by hand. This template uses linear radius (radius ∝ + * value, area not strictly ∝ value) to keep Plotly's native stacking — a + * documented behavioral difference from the other backends, flagged here for + * anyone who needs strict area-truth parity. + */ + +import { ChartTemplateDef, ChartPropertyDef } from '../../core/types'; +import { extractCategories, groupBy, getPlotlyPalette, getSeriesColor } from './utils'; +import { computeCircumferencePressure } from '../../core/decisions'; + +export const plRoseChartDef: ChartTemplateDef = { + chart: 'Rose Chart', + template: { mark: 'arc', encoding: {} }, + channels: ['x', 'y', 'color'], + markCognitiveChannel: 'area', + instantiate: (spec, ctx) => { + const { channelSemantics, table, chartProperties } = ctx; + const catField = channelSemantics.x?.field; + const valField = channelSemantics.y?.field; + const colorField = channelSemantics.color?.field; + if (!catField || !valField) return; + + let categories = extractCategories(table, catField, channelSemantics.x?.ordinalSortOrder); + if (categories.length === 0) return; + + const sortSlices = chartProperties?.sortSlices; + if (sortSlices === 'descending' || sortSlices === 'ascending') { + const totals = new Map(); + for (const c of categories) totals.set(c, 0); + for (const row of table) { + const c = String(row[catField] ?? ''); + if (totals.has(c)) totals.set(c, totals.get(c)! + (Number(row[valField]) || 0)); + } + categories = [...categories].sort((a, b) => + sortSlices === 'descending' ? (totals.get(b) ?? 0) - (totals.get(a) ?? 0) : (totals.get(a) ?? 0) - (totals.get(b) ?? 0)); + } + + const sumPerCategory = (rows: any[]) => { + const agg = new Map(); + for (const row of rows) { + const c = String(row[catField] ?? ''); + agg.set(c, (agg.get(c) ?? 0) + (Number(row[valField]) || 0)); + } + return categories.map(c => agg.get(c) ?? 0); + }; + + const palette = getPlotlyPalette(ctx, 'color'); + const traces: any[] = []; + if (colorField) { + let i = 0; + for (const [name, rows] of groupBy(table, colorField)) { + traces.push({ + type: 'barpolar', + name, + r: sumPerCategory(rows), + theta: categories, + marker: { color: getSeriesColor(palette, i) }, + }); + i++; + } + } else { + traces.push({ + type: 'barpolar', + r: sumPerCategory(table), + theta: categories, + marker: { color: categories.map((_c, i) => getSeriesColor(palette, i)) }, + showlegend: false, + }); + } + + const { canvasW, canvasH } = computeCircumferencePressure(categories.length, ctx.canvasSize, { + minArcPx: 45, + minRadius: 80, + maxStretch: ctx.assembleOptions?.maxStretch, + maxStretchX: ctx.assembleOptions?.maxStretchX, + maxStretchY: ctx.assembleOptions?.maxStretchY, + }); + + Object.assign(spec, { + data: traces, + layout: { + barmode: colorField ? 'stack' : undefined, + polar: { angularaxis: { rotation: 90, direction: 'clockwise' }, radialaxis: { rangemode: 'tozero' } }, + showlegend: !!colorField, + }, + _width: canvasW, + _height: canvasH, + }); + delete spec.mark; + delete spec.encoding; + }, + properties: [ + { + key: 'sortSlices', label: 'Sort slices', type: 'discrete', options: [ + { value: 'none', label: 'Data order' }, + { value: 'descending', label: 'Largest first' }, + { value: 'ascending', label: 'Smallest first' }, + ], + defaultValue: 'none', + } as ChartPropertyDef, + ], +}; diff --git a/packages/flint-js/src/plotly/templates/scatter.ts b/packages/flint-js/src/plotly/templates/scatter.ts new file mode 100644 index 00000000..d135e7b4 --- /dev/null +++ b/packages/flint-js/src/plotly/templates/scatter.ts @@ -0,0 +1,134 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Scatter Plot template. + * + * Mirrors the Chart.js Scatter template's decisions (color grouping, zero + * baseline per axis, canvas-aware point radius) as Plotly `scatter` traces + * in `markers` mode. + */ + +import { ChartTemplateDef, ChartPropertyDef } from '../../core/types'; +import { groupBy, getPlotlyPalette, getSeriesColor } from './utils'; + +/** Compute a reasonable marker diameter based on canvas area and point count. */ +function computeMarkerSize(width: number, height: number, pointCount: number): number { + const canvasArea = width * height; + const areaPerPoint = canvasArea / Math.max(1, pointCount); + const idealRadius = Math.sqrt(areaPerPoint * 0.05) / 2; + const radius = Math.max(2, Math.min(6, Math.round(idealRadius))); + return radius * 2; +} + +export const plScatterPlotDef: ChartTemplateDef = { + chart: 'Scatter Plot', + template: { mark: 'circle', encoding: {} }, + channels: ['x', 'y', 'color', 'size', 'opacity', 'column', 'row'], + markCognitiveChannel: 'position', + instantiate: (spec, ctx) => { + const { channelSemantics, table, chartProperties, colorDecisions } = ctx; + const xField = channelSemantics.x?.field; + const yField = channelSemantics.y?.field; + const colorField = channelSemantics.color?.field; + const colorType = channelSemantics.color?.type; + const isTemporalColor = colorType === 'temporal'; + const isContinuousColor = !!colorField && (colorType === 'quantitative' || isTemporalColor); + + if (!xField || !yField) return; + + const opacity = Number(chartProperties?.opacity ?? 1); + const traces: any[] = []; + + if (isContinuousColor && colorField) { + // A quantitative/temporal color channel is a numeric scale, not a + // set of legend groups — one trace with `marker.color` as a + // per-point array plus a native colorscale/colorbar (Plotly's + // built-in continuous-color support), not a group-by split. + const toColorVal = isTemporalColor + ? (v: any) => (v != null ? new Date(v).getTime() : NaN) + : (v: any) => (v != null ? Number(v) : NaN); + const colorVals = table.map((r: any) => toColorVal(r[colorField])).filter((v: number) => !isNaN(v)); + const cmin = colorVals.length ? Math.min(...colorVals) : 0; + const cmax = colorVals.length ? Math.max(...colorVals) : 1; + const decision = colorDecisions?.color ?? colorDecisions?.group; + const diverging = decision?.schemeType === 'diverging'; + traces.push({ + type: 'scatter', + mode: 'markers', + name: colorField, + x: table.map((r: any) => r[xField]), + y: table.map((r: any) => r[yField]), + marker: { + color: table.map((r: any) => toColorVal(r[colorField])), + colorscale: diverging ? 'RdBu' : 'Viridis', + cmin, cmax, + showscale: true, + colorbar: { title: { text: colorField } }, + opacity, + line: { color: '#ffffff', width: 0.5 }, + }, + }); + } else { + const palette = getPlotlyPalette(ctx, 'color'); + const makeTrace = (name: string | undefined, rows: any[], colorIndex: number) => ({ + type: 'scatter', + mode: 'markers', + ...(name != null ? { name } : {}), + x: rows.map(r => r[xField]), + y: rows.map(r => r[yField]), + marker: { + color: getSeriesColor(palette, colorIndex), + opacity, + line: { color: '#ffffff', width: 0.5 }, + }, + }); + + if (colorField) { + let i = 0; + for (const [name, rows] of groupBy(table, colorField)) { + traces.push(makeTrace(name, rows, i)); + i++; + } + } else { + traces.push(makeTrace(undefined, table, 0)); + } + } + + const xAxisSpec: any = { title: { text: xField } }; + const yAxisSpec: any = { title: { text: yField } }; + if (channelSemantics.x?.zero) { + xAxisSpec.rangemode = channelSemantics.x.zero.zero !== false ? 'tozero' : 'normal'; + } + if (channelSemantics.y?.zero) { + yAxisSpec.rangemode = channelSemantics.y.zero.zero !== false ? 'tozero' : 'normal'; + } + + const figure: any = { + data: traces, + layout: { + xaxis: xAxisSpec, + yaxis: yAxisSpec, + showlegend: !!colorField && !isContinuousColor, + }, + }; + + Object.assign(spec, figure); + delete spec.mark; + delete spec.encoding; + }, + properties: [ + { key: 'opacity', label: 'Opacity', type: 'continuous', min: 0.1, max: 1, step: 0.05, defaultValue: 1 } as ChartPropertyDef, + ], + postProcess: (figure, ctx) => { + if (!Array.isArray(figure.data)) return; + const w = figure._width || ctx.canvasSize.width; + const h = figure._height || ctx.canvasSize.height; + const size = computeMarkerSize(w, h, ctx.table.length); + for (const trace of figure.data) { + if (trace?.marker && trace.marker.size == null) { + trace.marker.size = size; + } + } + }, +}; diff --git a/packages/flint-js/src/plotly/templates/slope.ts b/packages/flint-js/src/plotly/templates/slope.ts new file mode 100644 index 00000000..bdecb850 --- /dev/null +++ b/packages/flint-js/src/plotly/templates/slope.ts @@ -0,0 +1,84 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Slope Chart (slopegraph) template. + * + * One straight line per category connecting its value at two periods, with + * markers at both ends. Mirrors `ecSlopeChartDef`: the period axis is always + * a two-band category axis; the value axis fits the data (a slope chart + * reads the *change*, not the distance from zero) unless the zero decision + * says otherwise. + */ + +import { ChartTemplateDef } from '../../core/types'; +import { extractCategories, groupBy, buildCategoryAlignedData, getPlotlyPalette, getSeriesColor } from './utils'; + +/** Order period categories naturally: numeric, then chronological, else data order. */ +function orderPeriods(categories: string[]): string[] { + if (categories.length <= 1) return categories; + if (categories.every(c => c.trim() !== '' && !isNaN(Number(c)))) { + return [...categories].sort((a, b) => Number(a) - Number(b)); + } + if (categories.every(c => !isNaN(Date.parse(c)))) { + return [...categories].sort((a, b) => Date.parse(a) - Date.parse(b)); + } + return categories; +} + +export const plSlopeChartDef: ChartTemplateDef = { + chart: 'Slope Chart', + template: { mark: 'line', encoding: {} }, + channels: ['x', 'y', 'color', 'detail', 'column', 'row'], + markCognitiveChannel: 'position', + declareLayoutMode: () => ({ + axisFlags: { x: { banded: true } }, + paramOverrides: { defaultBandSize: 120, continuousMarkCrossSection: { x: 0, y: 0, seriesCountAxis: 'auto' } }, + }), + instantiate: (spec, ctx) => { + const { channelSemantics, table } = ctx; + const xField = channelSemantics.x?.field; + const yField = channelSemantics.y?.field; + const groupField = channelSemantics.color?.field ?? channelSemantics.detail?.field; + if (!xField || !yField) return; + + const categories = orderPeriods(extractCategories(table, xField, undefined)); + const palette = getPlotlyPalette(ctx, 'color'); + + const makeTrace = (name: string | undefined, rows: any[], idx: number) => { + const values = buildCategoryAlignedData(rows, xField, yField, categories); + const color = getSeriesColor(palette, idx); + return { + type: 'scatter', + mode: 'lines+markers', + ...(name != null ? { name } : {}), + x: categories, y: values, + line: { color, shape: 'linear' as const }, + marker: { color, size: 7 }, + connectgaps: false, + }; + }; + + const traces: any[] = []; + if (groupField) { + let i = 0; + for (const [name, rows] of groupBy(table, groupField)) { traces.push(makeTrace(name, rows, i)); i++; } + } else { + traces.push(makeTrace(undefined, table, 0)); + } + + const yAxisSpec: any = { title: { text: yField } }; + if (channelSemantics.y?.zero) yAxisSpec.rangemode = channelSemantics.y.zero.zero !== false ? 'tozero' : 'normal'; + + Object.assign(spec, { + data: traces, + layout: { + xaxis: { type: 'category', categoryorder: 'array', categoryarray: categories, title: { text: xField } }, + yaxis: yAxisSpec, + showlegend: !!groupField, + }, + }); + delete spec.mark; + delete spec.encoding; + }, +}; diff --git a/packages/flint-js/src/plotly/templates/sparkline.ts b/packages/flint-js/src/plotly/templates/sparkline.ts new file mode 100644 index 00000000..a26c067d --- /dev/null +++ b/packages/flint-js/src/plotly/templates/sparkline.ts @@ -0,0 +1,236 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Sparkline template. + * + * A compact "sparkline table" — one row per series: its name, a small trend + * line with a dashed reference rule, and an aggregate value — mirroring the + * Vega-Lite Sparkline's visual pattern (Tufte's "dataword": drop the precise + * scale, keep shape-at-a-glance so dozens of series fit in one Line Chart's + * footprint). + * + * Composite layout, built directly on the Plotly figure rather than forced + * through the generic column/row facet combiner (`../facet.ts`, which only + * supports one cartesian axis pair per panel): each row gets its OWN hidden + * axis pair (`xaxis{n}`/`yaxis{n}`) domain-positioned as a horizontal strip, + * hosting the trend line + reference-rule traces; the category name and + * aggregate value are `layout.annotations` in paper coordinates alongside it + * — the same domain-grid + annotation technique `kpi-card.ts` uses for its + * own per-tile grid. `selfManagesFacets` keeps the assembler from pre- + * splitting this template by `column`/`row` (see `../assemble.ts`). + * + * The series field is the bound `color` (kept as the trend/value hue) or, + * failing that, `detail` (monochrome) — same remap rule as the Vega-Lite + * template's `normalizeEncodings`, applied here directly inside `instantiate` + * since Plotly doesn't yet wire that hook (see `ChartTemplateDef.normalizeEncodings`). + */ + +import { ChartTemplateDef, ChartPropertyDef } from '../../core/types'; +import { getPlotlyPalette, getSeriesColor } from './utils'; + +const DEFAULT_TREND_W = 240; + +const baselineProperty: ChartPropertyDef = { + key: 'baseline', label: 'Reference line', type: 'discrete', + defaultValue: 'mean', + options: [ + { value: 'mean', label: 'Average' }, + { value: 'zero', label: 'Zero' }, + { value: 'median', label: 'Median' }, + { value: 'none', label: 'None' }, + ], +}; + +const trendWidthProperty: ChartPropertyDef = { + key: 'trendWidth', label: 'Sparkline width', type: 'continuous', + min: 80, max: 600, step: 10, defaultValue: DEFAULT_TREND_W, +}; + +const isCJK = (ch: string): boolean => + /[\u3000-\u303F\u3400-\u9FFF\uF900-\uFAFF\uFF00-\uFFEF]/.test(ch); +const textWidth = (s: unknown): number => + [...String(s ?? '')].reduce((a, ch) => a + (isCJK(ch) ? 2 : 1), 0); +const mean = (a: number[]): number => (a.length ? a.reduce((s, x) => s + x, 0) / a.length : NaN); +const median = (a: number[]): number => { + if (!a.length) return NaN; + const s = [...a].sort((x, y) => x - y); + const n = s.length; + return n % 2 ? s[(n - 1) / 2] : (s[n / 2 - 1] + s[n / 2]) / 2; +}; +/** Compact "$1.2M"-style approximation — the display value AND the width budget. */ +function approxNum(v: number): string { + if (!Number.isFinite(v)) return ''; + const a = Math.abs(v); + if (a >= 1e9) return (v / 1e9).toFixed(1) + 'B'; + if (a >= 1e6) return (v / 1e6).toFixed(1) + 'M'; + if (a >= 1e3) return (v / 1e3).toFixed(1) + 'k'; + return String(Math.round(v * 10) / 10); +} + +export const plSparklineDef: ChartTemplateDef = { + chart: 'Sparkline', + template: { mark: 'line', encoding: {} }, + channels: ['x', 'y', 'color', 'detail'], + markCognitiveChannel: 'position', + // See file docstring — a hand-built multi-axis-pair grid, not a single + // cartesian panel the generic facet combiner could safely split/recombine. + selfManagesFacets: true, + instantiate: (spec, ctx) => { + const { channelSemantics, chartProperties, canvasSize } = ctx; + const xField = channelSemantics.x?.field; + const yField = channelSemantics.y?.field; + const hasColor = !!channelSemantics.color?.field; + const seriesField = channelSemantics.color?.field ?? channelSemantics.detail?.field; + if (!xField || !yField) return; + + const baseline = (chartProperties?.baseline as string) ?? 'mean'; + const useMedian = baseline === 'median'; + + const table = (ctx.fullTable ?? ctx.table ?? []) as Array>; + const facetField = seriesField ?? '__pl_spark_series'; + const rows = seriesField ? table : table.map(r => ({ ...r, [facetField]: '' })); + + // Row order = first appearance, stable. + const series: any[] = []; + const seen = new Set(); + for (const r of rows) { + const v = r[facetField]; + if (!seen.has(v)) { seen.add(v); series.push(v); } + } + if (series.length === 0) return; + + const bySeries = new Map>>(); + for (const r of rows) { + const k = r[facetField]; + const arr = bySeries.get(k); + if (arr) arr.push(r); else bySeries.set(k, [r]); + } + + const aggOf = (vals: number[]) => useMedian ? median(vals) : mean(vals); + + const categoryTitle = String(seriesField ?? ''); + const trendTitle = String(yField ?? ''); + const avgTitle = useMedian ? 'Median' : 'Average'; + + // ── Sizing (manual — mirrors the Vega-Lite template's hand-rolled + // hconcat sizing; the shared layout engine's faceted sizing doesn't + // apply to a hand-built multi-axis grid). ───────────────────────── + const canvas = canvasSize ?? { width: 480, height: 320 }; + const N = series.length; + const HEADER_H = 20; + const STRIP_GAP = 6; + const INTER_GAP = 10; + const CHAR_PX = 6.6; + const fontSize = N > 12 ? 10 : 11; + const stripH = Math.min(64, Math.max(16, + Math.floor((canvas.height - HEADER_H - (N - 1) * STRIP_GAP) / N))); + + const seriesAgg = new Map(); + for (const s of series) { + const vals = (bySeries.get(s) ?? []) + .map(r => Number(r[yField])).filter(v => Number.isFinite(v)); + seriesAgg.set(s, aggOf(vals)); + } + + const maxCatChars = Math.max(textWidth(categoryTitle), 4, ...series.map(s => textWidth(s))); + const maxAvgChars = Math.max(textWidth(avgTitle), 4, + ...Array.from(seriesAgg.values()).map(v => textWidth(approxNum(v)))); + const catW = Math.min(200, Math.max(40, Math.round(maxCatChars * CHAR_PX) + 10)); + const avgW = Math.min(96, Math.max(34, Math.round(maxAvgChars * CHAR_PX) + 8)); + const avail = canvas.width - catW - avgW - 2 * INTER_GAP; + const tunedTrendW = Number(chartProperties?.trendWidth) || DEFAULT_TREND_W; + const trendW = Math.max(90, Math.min(tunedTrendW, avail)); + + const totalW = catW + INTER_GAP + trendW + INTER_GAP + avgW; + const totalH = HEADER_H + N * stripH + (N - 1) * STRIP_GAP; + + const palette = getPlotlyPalette(ctx, 'color'); + const seriesColorIdx = new Map(series.map((s, i) => [s, i])); + + const traces: any[] = []; + const annotations: any[] = []; + const layout: any = { showlegend: false, margin: { t: 4, b: 4, l: 4, r: 4 } }; + + // Column headers. Anchored `yanchor: 'top'` at paper y=1 so the text + // renders DOWNWARD into the reserved `HEADER_H` band at the very top + // of the figure — an `yanchor: 'bottom'` anchor at y=1 needs headroom + // ABOVE the plot area (the figure's own top margin), which is too + // thin here to avoid clipping the label against the image edge. + const headerStyle = { size: 11, color: '#999' }; + annotations.push( + { text: categoryTitle, x: 0, y: 1, xref: 'paper', yref: 'paper', xanchor: 'left', yanchor: 'top', showarrow: false, font: headerStyle }, + { text: trendTitle, x: (catW + INTER_GAP + trendW / 2) / totalW, y: 1, xref: 'paper', yref: 'paper', xanchor: 'center', yanchor: 'top', showarrow: false, font: headerStyle }, + { text: avgTitle, x: 1, y: 1, xref: 'paper', yref: 'paper', xanchor: 'right', yanchor: 'top', showarrow: false, font: headerStyle }, + ); + + series.forEach((s, i) => { + const seriesRows = (bySeries.get(s) ?? []) + .map(r => ({ x: r[xField], y: Number(r[yField]) })) + .filter(p => p.y != null && Number.isFinite(p.y)); + const yVals = seriesRows.map(p => p.y); + const agg = seriesAgg.get(s); + + const rowTop = HEADER_H + i * (stripH + STRIP_GAP); + const rowMidYFrac = 1 - (rowTop + stripH / 2) / totalH; + + annotations.push( + { text: String(s), x: 0, y: rowMidYFrac, xref: 'paper', yref: 'paper', xanchor: 'left', yanchor: 'middle', showarrow: false, font: { size: fontSize, color: '#333' } }, + { + text: Number.isFinite(agg) ? approxNum(agg as number) : '', + x: 1, y: rowMidYFrac, xref: 'paper', yref: 'paper', xanchor: 'right', yanchor: 'middle', showarrow: false, + font: { size: fontSize, color: hasColor ? getSeriesColor(palette, seriesColorIdx.get(s) ?? 0) : '#333' }, + }, + ); + + if (yVals.length === 0) return; + + const n = i + 1; + const xName = n === 1 ? 'xaxis' : `xaxis${n}`; + const yName = n === 1 ? 'yaxis' : `yaxis${n}`; + const xRef = n === 1 ? 'x' : `x${n}`; + const yRef = n === 1 ? 'y' : `y${n}`; + + const x0 = (catW + INTER_GAP) / totalW; + const x1 = (catW + INTER_GAP + trendW) / totalW; + const y1 = 1 - rowTop / totalH; + const y0 = 1 - (rowTop + stripH) / totalH; + layout[xName] = { domain: [x0, x1], anchor: yRef, visible: false, showgrid: false, zeroline: false }; + layout[yName] = { domain: [y0, y1], anchor: xRef, visible: false, showgrid: false, zeroline: false }; + + traces.push({ + type: 'scatter', mode: 'lines', + xaxis: xRef, yaxis: yRef, + x: seriesRows.map(p => p.x), y: yVals, + line: { width: 1.5, color: hasColor ? getSeriesColor(palette, i) : '#555' }, + hoverinfo: 'x+y', + showlegend: false, + }); + + if (baseline !== 'none') { + const refY = baseline === 'zero' ? 0 : (Number.isFinite(agg) ? agg : undefined); + if (refY != null) { + traces.push({ + type: 'scatter', mode: 'lines', + xaxis: xRef, yaxis: yRef, + x: [seriesRows[0].x, seriesRows[seriesRows.length - 1].x], + y: [refY, refY], + line: { width: 1, color: '#9a9a9a', dash: 'dot' }, + hoverinfo: 'skip', + showlegend: false, + }); + } + } + }); + + Object.assign(spec, { + data: traces, + layout: { ...layout, annotations }, + _width: Math.round(totalW), + _height: Math.round(totalH), + }); + delete spec.mark; + delete spec.encoding; + }, + properties: [baselineProperty, trendWidthProperty], +}; diff --git a/packages/flint-js/src/plotly/templates/streamgraph.ts b/packages/flint-js/src/plotly/templates/streamgraph.ts new file mode 100644 index 00000000..60444609 --- /dev/null +++ b/packages/flint-js/src/plotly/templates/streamgraph.ts @@ -0,0 +1,102 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Streamgraph template. + * + * A "center-offset" stacked area (Vega-Lite's `y.stack: 'center'` / ECharts' + * native `themeRiver`). Plotly has no native wiggle/center stacking, so the + * baseline is precomputed here (silhouette offset: `-totalAtX / 2`) and each + * series is drawn as a cumulative line with `fill: 'tonexty'` against the + * previous series' cumulative line — the same successive-ribbon technique + * `plRangeAreaChartDef` uses for a single band, chained across N series. + */ + +import { ChartTemplateDef } from '../../core/types'; +import { extractCategories, coerceIsoDateForPlotly, getPlotlyPalette, getSeriesColor } from './utils'; + +export const plStreamgraphDef: ChartTemplateDef = { + chart: 'Streamgraph', + template: { mark: 'area', encoding: {} }, + channels: ['x', 'y', 'color', 'column', 'row'], + markCognitiveChannel: 'area', + declareLayoutMode: () => ({ + paramOverrides: { continuousMarkCrossSection: { x: 100, y: 20, seriesCountAxis: 'auto' } }, + }), + instantiate: (spec, ctx) => { + const { channelSemantics, table } = ctx; + const xCS = channelSemantics.x; + const yCS = channelSemantics.y; + const colorField = channelSemantics.color?.field; + if (!xCS?.field || !yCS?.field) return; + const xField = xCS.field; + const yField = yCS.field; + const xIsTemporal = xCS.type === 'temporal'; + const mapX = (raw: unknown) => (xIsTemporal ? coerceIsoDateForPlotly(raw) : raw); + + // Shared x categories across all series (temporal/ordinal x, sorted). + const xKeys = extractCategories(table, xField, xCS.ordinalSortOrder); + const orderedKeys = xIsTemporal + ? [...xKeys].sort((a, b) => new Date(a).getTime() - new Date(b).getTime()) + : (xCS.type === 'quantitative' ? [...xKeys].sort((a, b) => Number(a) - Number(b)) : xKeys); + + const seriesNames = colorField + ? [...new Set(table.map((r: any) => String(r[colorField] ?? '')))] + : [yField]; + + // value(seriesName, xKey) + const valMap = new Map(); + for (const row of table) { + const xk = String(row[xField]); + const sn = colorField ? String(row[colorField] ?? '') : yField; + const v = Number(row[yField]); + valMap.set(`${xk}\u0000${sn}`, (Number.isFinite(v) ? v : 0)); + } + + // Per-x total → silhouette baseline (centers the stack around zero). + const totals = orderedKeys.map(xk => + seriesNames.reduce((sum, sn) => sum + (valMap.get(`${xk}\u0000${sn}`) ?? 0), 0)); + const baseline = totals.map(t => -t / 2); + + const xVals = orderedKeys.map(k => (xIsTemporal ? mapX(k) : (xCS.type === 'quantitative' ? Number(k) : k))); + const palette = getPlotlyPalette(ctx, 'color'); + + const traces: any[] = [{ + type: 'scatter', mode: 'lines', showlegend: false, + x: xVals, y: baseline, + line: { width: 0 }, hoverinfo: 'skip', + }]; + let cumulative = [...baseline]; + seriesNames.forEach((sn, i) => { + cumulative = cumulative.map((c, xi) => c + (valMap.get(`${orderedKeys[xi]}\u0000${sn}`) ?? 0)); + const color = getSeriesColor(palette, i); + traces.push({ + type: 'scatter', mode: 'lines', + name: sn, + x: xVals, y: [...cumulative], + line: { width: 0.5, color }, + fill: 'tonexty', + fillcolor: color, + }); + }); + + const xAxisSpec: any = { title: { text: xField } }; + if (xIsTemporal) xAxisSpec.type = 'date'; + else if (xCS.type !== 'quantitative') { + xAxisSpec.type = 'category'; + xAxisSpec.categoryorder = 'array'; + xAxisSpec.categoryarray = orderedKeys; + } + + Object.assign(spec, { + data: traces, + layout: { + xaxis: xAxisSpec, + yaxis: { title: { text: yField }, showticklabels: false, zeroline: false }, + showlegend: !!colorField, + }, + }); + delete spec.mark; + delete spec.encoding; + }, +}; diff --git a/packages/flint-js/src/plotly/templates/utils.ts b/packages/flint-js/src/plotly/templates/utils.ts new file mode 100644 index 00000000..8128e4f0 --- /dev/null +++ b/packages/flint-js/src/plotly/templates/utils.ts @@ -0,0 +1,334 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Shared helper functions for Plotly template hooks. + * Pure logic — no UI dependencies. + */ + +import type { ChannelSemantics, InstantiateContext } from '../../core/types'; +import { pickPlotlyPalette } from '../colormap'; + +const isDiscrete = (type: string | undefined) => type === 'nominal' || type === 'ordinal'; + +/** Exported alias so templates can share the same discrete-type predicate. */ +export const isDiscreteType = isDiscrete; + +/** True if every category label parses as a number (used to decide label rotation). */ +export function areCategoriesNumeric(cats: string[]): boolean { + if (cats.length === 0) return true; + return cats.every((c) => { + const s = String(c).trim(); + if (s === '') return false; + const n = Number(s); + return !isNaN(n) && isFinite(n); + }); +} + +/** + * Extract unique category values from data for a given field, preserving order. + * If `ordinalSortOrder` is provided, returns values sorted in that canonical order. + */ +export function extractCategories(data: any[], field: string, ordinalSortOrder?: string[]): string[] { + const seen = new Set(); + const result: string[] = []; + for (const row of data) { + const val = row[field]; + if (val != null) { + const key = String(val); + if (!seen.has(key)) { + seen.add(key); + result.push(key); + } + } + } + + if (ordinalSortOrder && ordinalSortOrder.length > 0) { + const orderMap = new Map(ordinalSortOrder.map((v, i) => [v, i])); + result.sort((a, b) => { + const ia = orderMap.get(a); + const ib = orderMap.get(b); + if (ia !== undefined && ib !== undefined) return ia - ib; + if (ia !== undefined) return -1; + if (ib !== undefined) return 1; + return 0; + }); + } + + return result; +} + +/** + * Resolve the display order of a categorical axis, honoring either a canonical + * `ordinalSortOrder` (months, weekdays, …) or a sort-by-measure request + * (`sortBy` + `sortOrder` from the shared "Sort" control). Plotly has no native + * "order a categorical axis by another field" (Vega-Lite's `sort` op), so we + * aggregate the measure per category (sum) and order ascending/descending here. + */ +export function resolveCategoryOrder( + data: any[], + catField: string, + opts?: { ordinalSortOrder?: string[]; sortBy?: string; sortOrder?: 'ascending' | 'descending' }, +): string[] { + const base = extractCategories(data, catField, opts?.ordinalSortOrder); + if (!opts?.sortBy) return base; + const agg = new Map(); + for (const row of data) { + const cat = String(row[catField] ?? ''); + const v = Number(row[opts.sortBy]); + if (Number.isFinite(v)) agg.set(cat, (agg.get(cat) ?? 0) + v); + } + const dir = opts.sortOrder === 'ascending' ? 1 : -1; + return [...base].sort((a, b) => dir * ((agg.get(a) ?? 0) - (agg.get(b) ?? 0))); +} + +/** + * Group data by a categorical field. + * Returns a map: seriesName → rows[]. + */ +export function groupBy(data: any[], field: string): Map { + const groups = new Map(); + for (const row of data) { + const key = String(row[field] ?? ''); + if (!groups.has(key)) groups.set(key, []); + groups.get(key)!.push(row); + } + return groups; +} + +/** + * Build category-aligned value array for a subset of rows. + * Returns values indexed by category position (null for missing). + */ +export function buildCategoryAlignedData( + rows: any[], + catField: string, + valField: string, + categories: string[], +): (number | null)[] { + const map = new Map(); + for (const row of rows) { + const key = String(row[catField] ?? ''); + const val = row[valField]; + if (val != null && !isNaN(val)) { + map.set(key, (map.get(key) ?? 0) + Number(val)); + } + } + return categories.map(cat => map.get(cat) ?? null); +} + +/** + * Detect which axis is the category (banded) axis and which is the value axis. + * + * A bar's length is encoded on the **quantitative** axis; the band axis is the + * other one — which may be discrete (nominal/ordinal) *or* temporal (a bar over + * time is banded per period). Checking only for discreteness misses the temporal + * case and leaves dates on the value axis (→ empty bars). + */ +export function detectAxes( + channelSemantics: Record, +): { categoryAxis: 'x' | 'y'; valueAxis: 'x' | 'y' } { + const xCS = channelSemantics.x; + const yCS = channelSemantics.y; + const xQuant = !!xCS && xCS.type === 'quantitative'; + const yQuant = !!yCS && yCS.type === 'quantitative'; + + // Bar length lives on the quantitative axis; the band is the other axis. + if (yQuant && !xQuant) return { categoryAxis: 'x', valueAxis: 'y' }; // vertical + if (xQuant && !yQuant) return { categoryAxis: 'y', valueAxis: 'x' }; // horizontal + + // Fallbacks (both discrete, both quantitative, or missing): discrete-first. + if (xCS && isDiscrete(xCS.type)) { + return { categoryAxis: 'x', valueAxis: 'y' }; + } + if (yCS && isDiscrete(yCS.type)) { + return { categoryAxis: 'y', valueAxis: 'x' }; + } + return { categoryAxis: 'x', valueAxis: 'y' }; +} + +/** + * Coerce a temporal value to an ISO-8601 string for Plotly's native `date` + * axis. Numbers below 1e12 are treated as Unix seconds; strings and Dates are + * parsed directly. Returns null when unparseable. + */ +export function coerceIsoDateForPlotly(raw: unknown): string | null { + if (raw == null) return null; + let ms: number; + if (typeof raw === 'number' && Number.isFinite(raw)) { + ms = raw < 1e12 ? Math.round(raw * 1000) : raw; + } else if (raw instanceof Date) { + ms = raw.getTime(); + } else { + ms = new Date(String(raw)).getTime(); + } + return Number.isFinite(ms) ? new Date(ms).toISOString() : null; +} + +/** + * Plotly's default qualitative palette (plotly.js `layout.colorway` defaults). + * Fallback when no color decision is available; the decision-aware path lives + * in ../colormap.ts (mirroring chartjs/colormap.ts). + */ +export const PLOTLY_COLORS = [ + '#636efa', // blue-violet + '#EF553B', // red-orange + '#00cc96', // green + '#ab63fa', // purple + '#FFA15A', // orange + '#19d3f3', // cyan + '#FF6692', // pink + '#B6E880', // light green + '#FF97FF', // magenta + '#FECB52', // yellow +]; + +/** + * 从 color-decisions 解析调色板;若没有决策则回退到 Plotly 默认 plotly10。 + * (Mirror of chartjs/templates/utils.ts getChartJsPalette.) + */ +export function getPlotlyPalette(ctx: InstantiateContext, preferred: 'color' | 'group' = 'color'): string[] { + const decisions = ctx.colorDecisions; + const decision = + preferred === 'color' + ? decisions?.color ?? decisions?.group + : decisions?.group ?? decisions?.color; + + const palette = pickPlotlyPalette(decision); + if (palette.length > 0) { + return palette; + } + return PLOTLY_COLORS; +} + +/** Series color by index from a resolved palette. */ +export function getSeriesColor(palette: string[], index: number): string { + if (!palette.length) { + return PLOTLY_COLORS[index % PLOTLY_COLORS.length]; + } + return palette[index % palette.length]; +} + +/** Hex → rgba with alpha, for translucent fills (area/violin/density/range-area). */ +export function fillColor(hex: string, alpha: number): string { + const m = /^#?([0-9a-f]{6})$/i.exec(String(hex ?? '').trim()); + if (!m) return hex; + const v = parseInt(m[1], 16); + const a = Math.max(0, Math.min(1, alpha)); + return `rgba(${(v >> 16) & 255}, ${(v >> 8) & 255}, ${v & 255}, ${a})`; +} + +/** + * Bandwidth for Gaussian KDE — matches vega-statistics (bandwidth.js), shared + * with the equivalent Vega-Lite/ECharts density templates so curves line up. + */ +export function estimateBandwidth(values: number[]): number { + const n = values.length; + if (n < 2) return 1; + const sorted = [...values].sort((a, b) => a - b); + const mean = values.reduce((a, b) => a + b, 0) / n; + const variance = values.reduce((s, v) => s + (v - mean) ** 2, 0) / n; + const d = Math.sqrt(variance); + const q1 = sorted[Math.floor((n - 1) * 0.25)]; + const q3 = sorted[Math.floor((n - 1) * 0.75)]; + const iqr = (q3 != null && q1 != null) ? q3 - q1 : 0; + const h = iqr / 1.34; + const v = Math.min(d, h || d) || d || 1; + return 1.06 * v * Math.pow(n, -0.2); +} + +/** One-dimensional Gaussian KDE over an extent. */ +export function kde( + values: number[], steps: number, bandwidthMultiplier: number, + extent?: { min: number; max: number }, +): { x: number[]; y: number[] } { + if (values.length === 0) return { x: [], y: [] }; + const lo = extent ? extent.min : Math.min(...values); + const hi = extent ? extent.max : Math.max(...values); + const range = hi - lo || 1; + const h = estimateBandwidth(values) * bandwidthMultiplier; + const n = values.length; + const x: number[] = []; + const y: number[] = []; + for (let i = 0; i <= steps; i++) { + const t = lo + (i / steps) * (hi - lo || range); + let sum = 0; + for (const v of values) { + const z = (t - v) / h; + sum += Math.exp(-0.5 * z * z); + } + const density = sum / (n * h * Math.sqrt(2 * Math.PI)); + x.push(t); + y.push(density); + } + return { x, y }; +} + +/** + * Sorted distinct (value, cumulative-proportion) pairs for an ECDF, using the + * "≤ x" convention (ties collapse to the last occurrence's proportion). + */ +export function ecdfPairs(values: number[]): [number, number][] { + const sorted = values.filter(v => Number.isFinite(v)).sort((a, b) => a - b); + const n = sorted.length; + const pairs: [number, number][] = []; + if (n === 0) return pairs; + let i = 0; + while (i < n) { + let j = i; + while (j + 1 < n && sorted[j + 1] === sorted[i]) j++; + pairs.push([sorted[i], (j + 1) / n]); + i = j + 1; + } + return pairs; +} + +/** Deterministic pseudo-random generator (LCG) for reproducible jitter. */ +export function seededJitter(seed: number): () => number { + let s = seed; + return () => { + s = (s * 1103515245 + 12345) & 0x7fffffff; + return (s / 0x7fffffff) * 2 - 1; + }; +} + +/** Round up to a "nice" ceiling (radar/gauge axis maxima). */ +export function niceMax(v: number): number { + if (v <= 0) return 1; + const pow = Math.pow(10, Math.floor(Math.log10(v))); + const mantissa = v / pow; + const nice = mantissa <= 1 ? 1 + : mantissa <= 2 ? 2 + : mantissa <= 2.5 ? 2.5 + : mantissa <= 5 ? 5 + : 10; + return nice * pow; +} + +/** + * Stable sort of `rows` by a sequence field: numeric when every present value + * parses as a number, chronological when every value parses as a date, + * lexical otherwise. Ties keep their original row order. + */ +export function sortByOrder(rows: any[], field: string | undefined): any[] { + if (!field) return rows; + const tagged = rows.map((row, idx) => ({ row, idx, key: row[field] })); + const present = tagged.filter(t => t.key != null && t.key !== ''); + const allNumeric = present.length > 0 && + present.every(t => typeof t.key === 'number' || + (typeof t.key === 'string' && t.key.trim() !== '' && !isNaN(Number(t.key)))); + const allDates = !allNumeric && present.length > 0 && + present.every(t => !isNaN(Date.parse(String(t.key)))); + const rank = (k: any): number | string => { + if (allNumeric) return Number(k); + if (allDates) return Date.parse(String(k)); + return String(k); + }; + return [...tagged].sort((a, b) => { + const ra = rank(a.key); + const rb = rank(b.key); + if (ra < rb) return -1; + if (ra > rb) return 1; + return a.idx - b.idx; + }).map(t => t.row); +} diff --git a/packages/flint-js/src/plotly/templates/violin.ts b/packages/flint-js/src/plotly/templates/violin.ts new file mode 100644 index 00000000..245ed845 --- /dev/null +++ b/packages/flint-js/src/plotly/templates/violin.ts @@ -0,0 +1,96 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Violin Plot template. + * + * Native `violin` trace: pass raw y-values per category and Plotly computes + * the KDE + box overlay itself (matching Vega-Lite's `mark: "violin"` / + * density transform, unlike ECharts which has no native violin and needs a + * custom render item). + */ + +import { ChartTemplateDef, ChartPropertyDef } from '../../core/types'; +import { isDiscreteType, extractCategories, groupBy, getPlotlyPalette, getSeriesColor } from './utils'; +import { detectBandedAxisForceDiscrete } from '../../core/axis-detection'; + +export const plViolinPlotDef: ChartTemplateDef = { + chart: 'Violin Plot', + template: { mark: 'violin', encoding: {} }, + channels: ['x', 'y', 'color', 'column', 'row'], + markCognitiveChannel: 'area', + declareLayoutMode: (cs, table) => { + if (!cs.x?.field || !cs.y?.field) return {}; + const result = detectBandedAxisForceDiscrete(cs, table, { preferAxis: 'x' }); + if (!result) return {}; + return { + axisFlags: { [result.axis]: { banded: true } }, + resolvedTypes: result.resolvedTypes, + paramOverrides: { defaultBandSize: 40 }, + }; + }, + instantiate: (spec, ctx) => { + const { channelSemantics, table, chartProperties } = ctx; + const xCS = channelSemantics.x; + const yCS = channelSemantics.y; + const colorField = channelSemantics.color?.field; + if (!xCS?.field || !yCS?.field) return; + + const xIsDiscrete = isDiscreteType(xCS.type); + const yIsDiscrete = isDiscreteType(yCS.type); + const catAxis: 'x' | 'y' = (yIsDiscrete && !xIsDiscrete) ? 'y' : 'x'; + const valAxis: 'x' | 'y' = catAxis === 'x' ? 'y' : 'x'; + const catField = channelSemantics[catAxis]!.field!; + const valField = channelSemantics[valAxis]!.field!; + const isHorizontal = catAxis === 'y'; + + const categories = extractCategories(table, catField, channelSemantics[catAxis]?.ordinalSortOrder); + const showBox = chartProperties?.showBox !== false; + const showPoints = chartProperties?.showPoints === true; + const palette = getPlotlyPalette(ctx, 'color'); + + const makeTrace = (name: string | undefined, rows: any[], colorIdx: number) => { + const cats = rows.map((r: any) => String(r[catField] ?? '')); + const vals = rows.map((r: any) => Number(r[valField])); + const color = getSeriesColor(palette, colorIdx); + return { + type: 'violin', + ...(name != null ? { name } : {}), + ...(isHorizontal ? { y: cats, x: vals } : { x: cats, y: vals }), + orientation: isHorizontal ? 'h' as const : 'v' as const, + box: { visible: showBox }, + meanline: { visible: true }, + points: showPoints ? 'all' as const : false, + line: { color }, + fillcolor: color, + opacity: 0.6, + }; + }; + + const traces: any[] = []; + if (colorField) { + let i = 0; + for (const [name, rows] of groupBy(table, colorField)) { traces.push(makeTrace(name, rows, i)); i++; } + } else { + traces.push(makeTrace(undefined, table, 0)); + } + + const catAxisSpec = { type: 'category' as const, categoryorder: 'array' as const, categoryarray: categories, title: { text: catField } }; + const valAxisSpec = { title: { text: valField }, zeroline: false }; + + Object.assign(spec, { + data: traces, + layout: { + violinmode: colorField ? 'group' : undefined, + ...(isHorizontal ? { yaxis: catAxisSpec, xaxis: valAxisSpec } : { xaxis: catAxisSpec, yaxis: valAxisSpec }), + showlegend: !!colorField, + }, + }); + delete spec.mark; + delete spec.encoding; + }, + properties: [ + { key: 'showBox', label: 'Inner box', type: 'binary', defaultValue: true } as ChartPropertyDef, + { key: 'showPoints', label: 'Points', type: 'binary', defaultValue: false } as ChartPropertyDef, + ], +}; diff --git a/packages/flint-js/src/plotly/templates/waterfall.ts b/packages/flint-js/src/plotly/templates/waterfall.ts new file mode 100644 index 00000000..5753b9bb --- /dev/null +++ b/packages/flint-js/src/plotly/templates/waterfall.ts @@ -0,0 +1,117 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly Waterfall Chart template. + * + * Native `waterfall` trace: pass `x`, `y` (signed deltas) and a `measure` + * array (`'relative'` | `'total'`) and Plotly computes the floating bars, + * connector lines, and running totals itself — no manual cumulative-sum / + * custom-render-item bookkeeping like the ECharts template needs. + */ + +import { ChartTemplateDef, ChartPropertyDef } from '../../core/types'; +import { extractCategories } from './utils'; +import { resolveTotalsMode } from '../../chart-types/waterfall'; + +export const plWaterfallChartDef: ChartTemplateDef = { + chart: 'Waterfall Chart', + template: { mark: 'bar', encoding: {} }, + channels: ['x', 'y', 'color', 'column', 'row'], + markCognitiveChannel: 'length', + declareLayoutMode: () => ({ axisFlags: { x: { banded: true } } }), + instantiate: (spec, ctx) => { + const { channelSemantics, table, chartProperties } = ctx; + const xField = channelSemantics.x?.field || 'Category'; + const yField = channelSemantics.y?.field || 'Amount'; + const colorField = channelSemantics.color?.field; + + const categories = extractCategories(table, xField, undefined); + const rows = categories.map(cat => table.find((r: any) => String(r[xField]) === cat)).filter(Boolean); + const values = rows.map((r: any) => Number(r[yField]) || 0); + + const hasTypeCol = !!colorField; + const totalsMode = resolveTotalsMode(values, chartProperties?.totals); + const wantFirst = totalsMode === 'first' || totalsMode === 'both'; + const wantLast = totalsMode === 'last' || totalsMode === 'both'; + const types: string[] = hasTypeCol + ? rows.map((r: any) => String(r[colorField] ?? 'delta')) + : values.map((_v, i) => + wantFirst && i === 0 ? 'start' : wantLast && i === values.length - 1 ? 'end' : 'delta'); + // Plotly's native `measure: 'total'` does NOT anchor the bar at the + // row's own value — it re-derives the bar height as the cumulative + // sum of every 'relative' row since the previous checkpoint (or since + // the start, for the first checkpoint), ignoring the supplied `y`. + // That is exactly right for a genuine reconciling subtotal/end-total + // (its value was chosen — via `resolveTotalsMode`/`waterfallLastReconciles` + // — BECAUSE it already equals that running sum). But at row 0 there is + // no preceding cumulative to show (Plotly renders a zero-height bar), + // so a "start" anchor MUST be a 'relative' delta from the implicit + // zero baseline instead — numerically identical to the value the + // other backends draw, just colored increase/decrease rather than the + // dedicated "total" hue. + const measure = types.map((t, i) => { + if (i === 0) return 'relative'; + return (t === 'start' || t === 'end') ? 'total' : 'relative'; + }) as Array<'total' | 'relative'>; + + const showLabels = !!chartProperties?.showTextLabels; + + // Value labels sit OUTSIDE the bars (above a rise, below a fall). Plotly's + // auto-range only fits the bar extents, not the outside text, so the + // labels on the tallest/deepest bars get clipped at the plot edge. When + // labels are on, pad the y-range past the running-total envelope so the + // callouts have room, and set `cliponaxis: false` so a label that still + // reaches the edge is drawn into the margin rather than cut off. + let yRange: [number, number] | undefined; + if (showLabels) { + const extents = [0]; + let run = 0; + for (const v of values) { run += v; extents.push(run); } + const lo = Math.min(...extents); + const hi = Math.max(...extents); + const pad = (hi - lo || Math.abs(hi) || 1) * 0.15; + yRange = [lo - pad, hi + pad]; + } + + Object.assign(spec, { + data: [{ + type: 'waterfall', + x: categories, + y: values, + measure, + // Plotly's native waterfall palette (its default template): + // teal-green rises, red falls, blue totals, dark-grey + // connectors — rather than borrowing the ECharts hues, so the + // Plotly output looks native. + connector: { line: { color: '#444', width: 1 } }, + increasing: { marker: { color: '#3D9970' } }, + decreasing: { marker: { color: '#FF4136' } }, + totals: { marker: { color: '#4499FF' } }, + text: showLabels ? values.map(v => (v > 0 ? '+' : '') + v) : undefined, + textposition: showLabels ? 'outside' as const : undefined, + ...(showLabels ? { cliponaxis: false } : {}), + }], + layout: { + xaxis: { type: 'category', categoryorder: 'array', categoryarray: categories, title: { text: xField } }, + yaxis: { title: { text: yField }, ...(yRange ? { range: yRange } : {}) }, + showlegend: false, + }, + }); + delete spec.mark; + delete spec.encoding; + }, + properties: [ + { + key: 'totals', label: 'Totals', type: 'discrete', defaultValue: 'auto', + options: [ + { value: 'auto', label: 'Auto' }, + { value: 'none', label: 'None' }, + { value: 'first', label: 'First only' }, + { value: 'last', label: 'Last only' }, + { value: 'both', label: 'First and last' }, + ], + } as ChartPropertyDef, + { key: 'showTextLabels', label: 'Value labels', type: 'binary', defaultValue: false } as ChartPropertyDef, + ], +}; diff --git a/packages/flint-js/src/test-data/area-tests.ts b/packages/flint-js/src/test-data/area-tests.ts index 4f919be4..1bb22db5 100644 --- a/packages/flint-js/src/test-data/area-tests.ts +++ b/packages/flint-js/src/test-data/area-tests.ts @@ -3,6 +3,7 @@ import { Type } from './df-types'; import { TestCase, makeField, makeEncodingItem } from './types'; +import { realAreaCases, realStreamgraphCases } from './real-world-tests'; import { seededRandom, genDates, genCategories, genOrdinalLabels, ORDINAL_PREFIXES } from './generators'; // ============================================================================ @@ -92,11 +93,8 @@ const AREA_MATRIX: AreaMatrixEntry[] = [ const STREAMGRAPH_MATRIX: AreaMatrixEntry[] = [ { x: 'T', y: 'Q', n: 200, color: 'N', colorCard: 5, desc: '5 genres × 40 dates — basic streamgraph' }, - { x: 'T', y: 'Q', n: 800, color: 'N', colorCard: 10, desc: '10 industries × 80 dates — large' }, { x: 'T', y: 'Q', n: 3000, color: 'N', colorCard: 20, desc: '20 series × 150 dates — stress', extraTags: ['stress'] }, { x: 'T', y: 'Q', n: 200, color: 'N', colorCard: 5, sparse: true, desc: '5 series ~20% missing' }, - { x: 'O', y: 'Q', n: 60, xCard: 12, color: 'N', colorCard: 5, desc: 'Ordinal streamgraph — 12 cats × 5 series' }, - { x: 'Q', y: 'Q', n: 150, color: 'N', colorCard: 3, desc: 'Quant-x streamgraph — 3 series × 50 pts' }, ]; // ============================================================================ @@ -394,10 +392,10 @@ function areaMatrixToTestCase( export function genAreaTests(): TestCase[] { const rand = seededRandom(910); - return AREA_MATRIX.map(entry => areaMatrixToTestCase(entry, 'Area Chart', rand)); + return [...AREA_MATRIX.map(entry => areaMatrixToTestCase(entry, 'Area Chart', rand)), ...realAreaCases()]; } export function genStreamgraphTests(): TestCase[] { const rand = seededRandom(920); - return STREAMGRAPH_MATRIX.map(entry => areaMatrixToTestCase(entry, 'Streamgraph', rand)); + return [...STREAMGRAPH_MATRIX.map(entry => areaMatrixToTestCase(entry, 'Streamgraph', rand)), ...realStreamgraphCases()]; } diff --git a/packages/flint-js/src/test-data/bar-tests.ts b/packages/flint-js/src/test-data/bar-tests.ts index f83bbd33..6cab7313 100644 --- a/packages/flint-js/src/test-data/bar-tests.ts +++ b/packages/flint-js/src/test-data/bar-tests.ts @@ -3,6 +3,7 @@ import { Type } from './df-types'; import { TestCase, makeField, makeEncodingItem } from './types'; +import { realBarCases, realStackedBarCases, realGroupedBarCases } from './real-world-tests'; import { seededRandom, genDates, genCategories, genRandomNames } from './generators'; // ============================================================================ @@ -415,12 +416,43 @@ function barMatrixToTestCase( export function genBarTests(): TestCase[] { const rand = seededRandom(100); - return BAR_MATRIX.map(entry => barMatrixToTestCase(entry, 'Bar Chart', 'color', rand)); + return [...BAR_MATRIX.map(entry => barMatrixToTestCase(entry, 'Bar Chart', 'color', rand)), ...realBarCases()]; +} + +/** + * A curated synthetic gallery *showcase* (tagged `gallery-showcase`) — a dense + * single-series bar chart with many categories, so the wall demonstrates how + * Flint auto-sizes / shrinks bars to fit. Kept out of `genBarTests` (test suite) + * and appended only in the gallery generator, so it never shifts test indices. + */ +export function galleryBarSizingShowcase(): TestCase { + const rand = seededRandom(4210); + const hours = Array.from({ length: 24 }, (_, h) => `${String(h).padStart(2, '0')}:00`); + let level = 40; + const data = hours.map((Hour, i) => { + // Diurnal shape: low overnight, peaks late morning + evening. + const shape = 60 + 55 * Math.sin(((i - 6) / 24) * Math.PI * 2) + 30 * Math.sin(((i - 3) / 12) * Math.PI * 2); + level = Math.max(15, Math.round(shape + (rand() - 0.5) * 24)); + return { Hour, Views: level }; + }); + return { + title: 'Page views by hour of day (24 bars)', + description: 'A dense single-series bar chart — Flint shrinks the bars to fit all 24 hours.', + tags: ['bar', 'gallery-showcase', 'nominal', 'many-bars'], + chartType: 'Bar Chart', + data, + fields: [makeField('Hour'), makeField('Views')], + metadata: { + Hour: { type: Type.String, semanticType: 'Category', levels: hours }, + Views: { type: Type.Number, semanticType: 'Quantity', levels: [] }, + }, + encodingMap: { x: makeEncodingItem('Hour'), y: makeEncodingItem('Views') }, + }; } export function genStackedBarTests(): TestCase[] { const rand = seededRandom(200); - return STACKED_BAR_MATRIX.map(entry => barMatrixToTestCase(entry, 'Stacked Bar Chart', 'color', rand)); + return [...STACKED_BAR_MATRIX.map(entry => barMatrixToTestCase(entry, 'Stacked Bar Chart', 'color', rand)), ...realStackedBarCases()]; } export function genGroupedBarTests(): TestCase[] { @@ -530,5 +562,5 @@ export function genGroupedBarTests(): TestCase[] { } } - return tests; + return [...tests, ...realGroupedBarCases()]; } diff --git a/packages/flint-js/src/test-data/chartjs-tests.ts b/packages/flint-js/src/test-data/chartjs-tests.ts index 9acc6d23..fb4c3e2f 100644 --- a/packages/flint-js/src/test-data/chartjs-tests.ts +++ b/packages/flint-js/src/test-data/chartjs-tests.ts @@ -465,35 +465,6 @@ export function genChartJsAreaTests(): TestCase[] { }); } - // Global vs local dodge (sparse region × channel). - { - const regions = ['North', 'South', 'East', 'West', 'Central', 'Coast']; - const channels = ['Retail', 'Online', 'Wholesale', 'Direct']; - const subset: Record = { - North: ['Retail', 'Online'], South: ['Online', 'Wholesale', 'Direct'], East: ['Wholesale', 'Direct'], - West: ['Retail', 'Direct'], Central: ['Retail', 'Online', 'Wholesale'], Coast: ['Online', 'Direct'], - }; - for (const mode of ['global', 'local'] as const) { - const data: any[] = []; - regions.forEach((r, ri) => subset[r].forEach((ch, ci) => data.push({ Region: r, Channel: ch, Sales: Math.round(300 + ri * 40 + ci * 30) }))); - tests.push({ - title: mode === 'global' ? 'CJS: Grouped Bar — Dodge Global' : 'CJS: Grouped Bar — Dodge Local', - description: mode === 'global' ? 'fixed lane per channel (gaps where absent)' : 'compact maxPerBand lanes, left-aligned', - tags: ['chartjs', 'grouped-bar', 'sparse', `dodge-${mode}`], - chartType: 'Grouped Bar Chart', - data, - fields: [makeField('Region'), makeField('Sales'), makeField('Channel')], - metadata: { - Region: { type: Type.String, semanticType: 'Category', levels: regions }, - Sales: { type: Type.Number, semanticType: 'Quantity', levels: [] }, - Channel: { type: Type.String, semanticType: 'Category', levels: channels }, - }, - chartProperties: { dodge: mode }, - encodingMap: { x: makeEncodingItem('Region'), y: makeEncodingItem('Sales'), group: makeEncodingItem('Channel') }, - }); - } - } - return tests; } diff --git a/packages/flint-js/src/test-data/connected-scatter-tests.ts b/packages/flint-js/src/test-data/connected-scatter-tests.ts index 6d897e62..649c9160 100644 --- a/packages/flint-js/src/test-data/connected-scatter-tests.ts +++ b/packages/flint-js/src/test-data/connected-scatter-tests.ts @@ -22,6 +22,7 @@ import { Type } from './df-types'; import { TestCase, makeField, makeEncodingItem } from './types'; +import { realConnectedScatterCases } from './real-world-tests'; import { seededRandom, genCategories, genYears } from './generators'; export function genConnectedScatterTests(): TestCase[] { @@ -196,7 +197,7 @@ export function genConnectedScatterTests(): TestCase[] { tests.push({ title: 'Temperature vs Pressure × 2 trials + Color (index order)', description: 'Two experiment trajectories ordered by a numeric step index, grouped by color', - tags: ['quantitative', 'index-order', 'color', 'multi-series', 'small'], + tags: ['quantitative', 'index-order', 'color', 'multi-series', 'small', 'edge-case'], chartType: 'Connected Scatter Plot', data, fields: [makeField('Temperature'), makeField('Pressure'), makeField('Step'), makeField('Experiment')], @@ -226,7 +227,7 @@ export function genConnectedScatterTests(): TestCase[] { tests.push({ title: 'Cost vs Revenue over 4 quarters (low count)', description: 'A minimal 4-point trajectory ordered by quarter index — lowest useful connected scatter', - tags: ['quantitative', 'index-order', 'single', 'small'], + tags: ['quantitative', 'index-order', 'single', 'small', 'edge-case'], chartType: 'Connected Scatter Plot', data, fields: [makeField('Cost'), makeField('Revenue'), makeField('Quarter')], @@ -262,7 +263,7 @@ export function genConnectedScatterTests(): TestCase[] { tests.push({ title: 'Winding spiral × 36 steps (higher count)', description: 'A 36-point spiral trajectory ordered by step index — higher point count / density', - tags: ['quantitative', 'index-order', 'looping', 'single', 'large'], + tags: ['quantitative', 'index-order', 'looping', 'single', 'large', 'edge-case'], chartType: 'Connected Scatter Plot', data, fields: [makeField('X Position'), makeField('Y Position'), makeField('Step')], @@ -316,7 +317,7 @@ export function genConnectedScatterTests(): TestCase[] { }); } - return tests; + return [...tests, ...realConnectedScatterCases()]; } /** @@ -348,6 +349,6 @@ export function genChartJsConnectedScatterTests(): TestCase[] { pick('Unemployment vs Inflation over 10 years (basic)'), pick('GDP growth vs Inflation × 3 countries + Color (trajectories)'), pick('Self-crossing sensor loop × 24 steps (figure-eight)'), - pick('Temperature vs Pressure × 2 trials + Color (index order)'), + pick('Driving Shifts Into Reverse — miles vs gas price (US, 1956–2010)'), ]; } diff --git a/packages/flint-js/src/test-data/density-2d-tests.ts b/packages/flint-js/src/test-data/density-2d-tests.ts new file mode 100644 index 00000000..bff9e4d9 --- /dev/null +++ b/packages/flint-js/src/test-data/density-2d-tests.ts @@ -0,0 +1,74 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Test-data generators for the 2-D density contour chart — Density Contour + * (`histogram2dcontour`). A Plotly-only statistical chart: both axes are + * continuous measures, binned and smoothed into density iso-contours (Vega-Lite + * has no contour mark). See design-docs/plotly-stats-charts.md. + */ + +import { Type } from './df-types'; +import { TestCase, makeField, makeEncodingItem } from './types'; +import { seededRandom } from './generators'; + +/** Build a correlated bivariate cloud (roughly Gaussian) for 2-D density demos. */ +function bivariateCloud(n: number, seed: number, xLabel: string, yLabel: string, corr: number): any[] { + const rand = seededRandom(seed); + const gauss = () => (rand() + rand() + rand() + rand() - 2) * 1.5; // ~N(0, ~1) + const rows: any[] = []; + for (let i = 0; i < n; i++) { + const a = gauss(); + const b = corr * a + Math.sqrt(1 - corr * corr) * gauss(); + rows.push({ + [xLabel]: Math.round((50 + a * 12) * 10) / 10, + [yLabel]: Math.round((40 + b * 10) * 10) / 10, + }); + } + return rows; +} + +function density2dMeta(xLabel: string, yLabel: string) { + return { + [xLabel]: { type: Type.Number, semanticType: 'Quantity', levels: [] }, + [yLabel]: { type: Type.Number, semanticType: 'Quantity', levels: [] }, + }; +} + +export function genDensityContourTests(): TestCase[] { + const tests: TestCase[] = []; + + { + const data = bivariateCloud(700, 81, 'X', 'Y', 0.6); + tests.push({ + title: 'Correlated Cloud (700 pts)', + description: 'Smoothed 2-D density contours over a scatter of raw points', + tags: ['quantitative', 'density', 'medium'], + chartType: 'Density Contour', + data, + fields: [makeField('X'), makeField('Y')], + metadata: density2dMeta('X', 'Y'), + encodingMap: { x: makeEncodingItem('X'), y: makeEncodingItem('Y') }, + }); + } + + { + // Two overlapping clouds → visibly multi-modal density. + const a = bivariateCloud(400, 82, 'Feature 1', 'Feature 2', 0.5); + const b = bivariateCloud(400, 83, 'Feature 1', 'Feature 2', 0.5) + .map(r => ({ 'Feature 1': r['Feature 1'] + 35, 'Feature 2': r['Feature 2'] + 28 })); + const data = [...a, ...b]; + tests.push({ + title: 'Bimodal Density (800 pts)', + description: 'Two clusters — contour lines reveal both modes', + tags: ['quantitative', 'density', 'large'], + chartType: 'Density Contour', + data, + fields: [makeField('Feature 1'), makeField('Feature 2')], + metadata: density2dMeta('Feature 1', 'Feature 2'), + encodingMap: { x: makeEncodingItem('Feature 1'), y: makeEncodingItem('Feature 2') }, + }); + } + + return tests; +} diff --git a/packages/flint-js/src/test-data/distribution-tests.ts b/packages/flint-js/src/test-data/distribution-tests.ts index 1e90b6f8..fa2b5e89 100644 --- a/packages/flint-js/src/test-data/distribution-tests.ts +++ b/packages/flint-js/src/test-data/distribution-tests.ts @@ -3,6 +3,7 @@ import { Type } from './df-types'; import { TestCase, makeField, makeEncodingItem, buildMetadata } from './types'; +import { realHistogramCases, realDensityCases, realBoxplotCases, realStripCases } from './real-world-tests'; import { seededRandom, genCategories } from './generators'; // ------ Histogram ------ @@ -74,7 +75,7 @@ export function genHistogramTests(): TestCase[] { }); } - return tests; + return [...tests, ...realHistogramCases()]; } // ------ Boxplot ------ @@ -308,7 +309,7 @@ export function genBoxplotTests(): TestCase[] { } } - return tests; + return [...tests, ...realBoxplotCases()]; } // ------ Density Plot ------ @@ -418,7 +419,7 @@ export function genDensityTests(): TestCase[] { }); } - return tests; + return [...tests, ...realDensityCases()]; } // ------ Strip Plot (Jitter) ------ @@ -439,7 +440,7 @@ export function genStripPlotTests(): TestCase[] { tests.push({ title: 'Iris Petal Length (3 species, 60 pts)', description: 'Categorical x, quantitative y with jitter', - tags: ['jitter', 'nominal', 'small'], + tags: ['jitter', 'nominal', 'small', 'edge-case'], chartType: 'Strip Plot', data, fields: [makeField('Species'), makeField('PetalLength')], @@ -469,7 +470,7 @@ export function genStripPlotTests(): TestCase[] { tests.push({ title: 'Clinical Trial Scores (color = Gender)', description: 'Strip plot with color grouping', - tags: ['jitter', 'nominal', 'color'], + tags: ['jitter', 'nominal', 'color', 'edge-case'], chartType: 'Strip Plot', data, fields: [makeField('Group'), makeField('Score'), makeField('Gender')], @@ -503,5 +504,5 @@ export function genStripPlotTests(): TestCase[] { }); } - return tests; + return [...tests, ...realStripCases()]; } diff --git a/packages/flint-js/src/test-data/ecdf-tests.ts b/packages/flint-js/src/test-data/ecdf-tests.ts index 7194cc92..e1bf9bd3 100644 --- a/packages/flint-js/src/test-data/ecdf-tests.ts +++ b/packages/flint-js/src/test-data/ecdf-tests.ts @@ -21,6 +21,7 @@ import { Type } from './df-types'; import { TestCase, makeField, makeEncodingItem } from './types'; +import { realEcdfCases } from './real-world-tests'; import { seededRandom } from './generators'; /** Standard-normal sample via Box–Muller. */ @@ -232,7 +233,7 @@ export function genEcdfTests(): TestCase[] { }); } - return tests; + return [...tests, ...realEcdfCases()]; } /** diff --git a/packages/flint-js/src/test-data/echarts-tests.ts b/packages/flint-js/src/test-data/echarts-tests.ts index 2c4d1d44..5db91f9a 100644 --- a/packages/flint-js/src/test-data/echarts-tests.ts +++ b/packages/flint-js/src/test-data/echarts-tests.ts @@ -436,36 +436,6 @@ export function genEChartsGroupedBarTests(): TestCase[] { }); } - // Global vs local dodge (sparse region × channel). EC local = compact - // maxPerBand lane-series (left-aligned). - { - const regions = ['North', 'South', 'East', 'West', 'Central', 'Coast']; - const channels = ['Retail', 'Online', 'Wholesale', 'Direct']; - const subset: Record = { - North: ['Retail', 'Online'], South: ['Online', 'Wholesale', 'Direct'], East: ['Wholesale', 'Direct'], - West: ['Retail', 'Direct'], Central: ['Retail', 'Online', 'Wholesale'], Coast: ['Online', 'Direct'], - }; - for (const mode of ['global', 'local'] as const) { - const data: any[] = []; - regions.forEach((r, ri) => subset[r].forEach((ch, ci) => data.push({ Region: r, Channel: ch, Sales: Math.round(300 + ri * 40 + ci * 30) }))); - tests.push({ - title: mode === 'global' ? 'EC: Grouped Bar — Dodge Global' : 'EC: Grouped Bar — Dodge Local', - description: mode === 'global' ? 'fixed lane per channel (gaps where absent)' : 'compact maxPerBand lanes, left-aligned', - tags: ['echarts', 'grouped-bar', 'sparse', `dodge-${mode}`], - chartType: 'Grouped Bar Chart', - data, - fields: [makeField('Region'), makeField('Sales'), makeField('Channel')], - metadata: { - Region: { type: Type.String, semanticType: 'Category', levels: regions }, - Sales: { type: Type.Number, semanticType: 'Quantity', levels: [] }, - Channel: { type: Type.String, semanticType: 'Category', levels: channels }, - }, - chartProperties: { dodge: mode }, - encodingMap: { x: makeEncodingItem('Region'), y: makeEncodingItem('Sales'), group: makeEncodingItem('Channel') }, - }); - } - } - return tests; } @@ -946,37 +916,6 @@ export function genEChartsBoxplotTests(): TestCase[] { }); } - // Global vs local dodge (sparse dept × level). - { - const depts = ['Eng', 'Sales', 'HR', 'Ops', 'Legal', 'Finance']; - const levels = ['L1', 'L2', 'L3', 'L4', 'L5']; - const subset: Record = { - Eng: ['L1', 'L2'], Sales: ['L2', 'L3'], HR: ['L3', 'L4'], Ops: ['L4', 'L5'], Legal: ['L5', 'L1'], Finance: ['L1', 'L3'], - }; - const rand = seededRandom(880); - for (const mode of ['global', 'local'] as const) { - const data: any[] = []; - for (const dp of depts) for (const l of subset[dp]) for (let i = 0; i < 18; i++) { - data.push({ Department: dp, Level: l, Comp: Math.round(30000 + (l.charCodeAt(1) % 5) * 15000 + rand() * 90000) }); - } - tests.push({ - title: mode === 'global' ? 'EC: Boxplot — Dodge Global' : 'EC: Boxplot — Dodge Local', - description: mode === 'global' ? 'fixed lane per level (gaps where absent)' : 'compact maxPerBand lanes, left-aligned', - tags: ['echarts', 'boxplot', 'sparse', `dodge-${mode}`], - chartType: 'Boxplot', - data, - fields: [makeField('Department'), makeField('Comp'), makeField('Level')], - metadata: { - Department: { type: Type.String, semanticType: 'Category', levels: depts }, - Comp: { type: Type.Number, semanticType: 'Amount', levels: [] }, - Level: { type: Type.String, semanticType: 'Category', levels: levels }, - }, - chartProperties: { dodge: mode }, - encodingMap: { x: makeEncodingItem('Department'), y: makeEncodingItem('Comp'), color: makeEncodingItem('Level') }, - }); - } - } - return tests; } diff --git a/packages/flint-js/src/test-data/gallery-facet-tests.ts b/packages/flint-js/src/test-data/gallery-facet-tests.ts index 320c22e0..4d352112 100644 --- a/packages/flint-js/src/test-data/gallery-facet-tests.ts +++ b/packages/flint-js/src/test-data/gallery-facet-tests.ts @@ -25,11 +25,13 @@ function meta(type: Type, semanticType: string, levels: any[] = []) { /** * Column-faceted bar — sales by segment, one small panel per region. - * 3 panels × 4 bars: comfortably fits side-by-side as small multiples. + * Six regions laid out in a fixed 2-column grid (`facetColumns: 2`) → a 2×3 + * small-multiples grid, so the gallery advertises faceting *and* how Flint + * shrinks each sub-panel to fit. */ export function galleryFacetBarExample(): TestCase { const rand = seededRandom(4201); - const regions = ['North', 'Central', 'South']; + const regions = ['North', 'Central', 'South', 'East', 'West', 'Pacific']; const segments = ['Consumer', 'Corporate', 'Home Office', 'Reseller']; const data: any[] = []; for (const region of regions) { @@ -44,7 +46,7 @@ export function galleryFacetBarExample(): TestCase { }; return { title: 'Sales by segment, faceted by region', - description: 'Small-multiples bar chart — one panel per region (column facet).', + description: 'Small-multiples bar chart — one panel per region in a 2-column grid (column facet).', tags: [...FACET_TAGS, 'bar'], chartType: 'Bar Chart', data, @@ -55,6 +57,7 @@ export function galleryFacetBarExample(): TestCase { Region: meta(Type.String, 'Category', regions), }, encodingMap, + chartProperties: { facetColumns: 2 }, }; } diff --git a/packages/flint-js/src/test-data/gantt-bullet-tests.ts b/packages/flint-js/src/test-data/gantt-bullet-tests.ts index f584f389..34d9a210 100644 --- a/packages/flint-js/src/test-data/gantt-bullet-tests.ts +++ b/packages/flint-js/src/test-data/gantt-bullet-tests.ts @@ -13,6 +13,7 @@ import { Type } from './df-types'; import { TestCase, makeField, makeEncodingItem } from './types'; +import { realGanttCases, realBulletCases } from './real-world-tests'; // --------------------------------------------------------------------------- // Gantt — a software release schedule @@ -100,6 +101,7 @@ export function genGanttTests(): TestCase[] { color: makeEncodingItem('group'), }, }, + ...realGanttCases(), ]; } @@ -185,5 +187,6 @@ export function genBulletTests(): TestCase[] { goal: makeEncodingItem('target'), }, }, + ...realBulletCases(), ]; } diff --git a/packages/flint-js/src/test-data/index.ts b/packages/flint-js/src/test-data/index.ts index c6e19771..841f0f6f 100644 --- a/packages/flint-js/src/test-data/index.ts +++ b/packages/flint-js/src/test-data/index.ts @@ -19,6 +19,7 @@ export { seededRandom, genDates, genMonths, genYears, genNaturalDates, genCatego export { genScatterTests, genRegressionTests } from './scatter-tests'; export { genBarTests, genStackedBarTests, genGroupedBarTests } from './bar-tests'; export { genHistogramTests, genBoxplotTests, genDensityTests, genStripPlotTests } from './distribution-tests'; +export { genDensityContourTests } from './density-2d-tests'; export { genViolinTests } from './violin-tests'; export { genLineTests } from './line-tests'; export { genSparklineTests } from './sparkline-tests'; @@ -39,6 +40,7 @@ export { genGasPressureTests } from './gas-pressure-tests'; export { genLineAreaStretchTests } from './line-area-stretch-tests'; export { genEChartsScatterTests, genEChartsLineTests, genEChartsBarTests, genEChartsStackedBarTests, genEChartsGroupedBarTests, genEChartsStressTests, genEChartsAreaTests, genEChartsPieTests, genEChartsHeatmapTests, genEChartsHistogramTests, genEChartsBoxplotTests, genEChartsRadarTests, genEChartsCandlestickTests, genEChartsStreamgraphTests, genEChartsFacetSmallTests, genEChartsFacetWrapTests, genEChartsFacetClipTests, genEChartsRoseTests, genEChartsGaugeTests, genEChartsFunnelTests, genEChartsTreemapTests, genEChartsSunburstTests, genEChartsSankeyTests, genEChartsUniqueStressTests, genEChartsCalendarTests, genEChartsParallelTests, genEChartsGraphTests, genEChartsTreeTests } from './echarts-tests'; export { genChartJsScatterTests, genChartJsLineTests, genChartJsBarTests, genChartJsStackedBarTests, genChartJsGroupedBarTests, genChartJsAreaTests, genChartJsPieTests, genChartJsHistogramTests, genChartJsRadarTests, genChartJsStressTests, genChartJsRoseTests, genChartJsBubbleTests, genChartJsDoughnutTests, genChartJsComboTests } from './chartjs-tests'; +export { genPlotlyCoreTests, genPlotlyFacetTests } from './plotly-tests'; export { genDiscreteAxisTests } from './discrete-axis-tests'; export { genDateTests, genDateYearTests, genDateMonthTests, genDateYearMonthTests, genDateDecadeTests, genDateDateTimeTests, genDateHoursTests } from './date-tests'; export { genSemanticContextTests, genSnapToBoundTests } from './semantic-tests'; @@ -85,8 +87,9 @@ export { import { TestCase } from './types'; import { genScatterTests, genRegressionTests } from './scatter-tests'; -import { genBarTests, genStackedBarTests, genGroupedBarTests } from './bar-tests'; +import { genBarTests, genStackedBarTests, genGroupedBarTests, galleryBarSizingShowcase } from './bar-tests'; import { genHistogramTests, genBoxplotTests, genDensityTests, genStripPlotTests } from './distribution-tests'; +import { genDensityContourTests } from './density-2d-tests'; import { genViolinTests } from './violin-tests'; import { genMapTests, genChoroplethTests } from './map-tests'; import { genGanttTests, genBulletTests } from './gantt-bullet-tests'; @@ -99,7 +102,7 @@ import { genAreaTests, genStreamgraphTests } from './area-tests'; import { genRangeAreaTests, genEChartsRangeAreaTests, genChartJsRangeAreaTests } from './range-area-tests'; import { genEcdfTests, genEChartsEcdfTests, genChartJsEcdfTests } from './ecdf-tests'; import { - genHeatmapTests, genPieTests, genRangedDotPlotTests, genLollipopTests, + genHeatmapTests, genPieTests, genDonutTests, genRangedDotPlotTests, genLollipopTests, genWaterfallTests, genBarTableTests, genCandlestickTests, genRadarTests, genPyramidTests, genRoseTests, } from './specialized-tests'; @@ -112,6 +115,7 @@ import { genDateYearTests, genDateMonthTests, genDateYearMonthTests, genDateDeca import { genSemanticContextTests, genSnapToBoundTests } from './semantic-tests'; import { genEChartsScatterTests, genEChartsLineTests, genEChartsBarTests, genEChartsStackedBarTests, genEChartsGroupedBarTests, genEChartsStressTests, genEChartsAreaTests, genEChartsPieTests, genEChartsHeatmapTests, genEChartsHistogramTests, genEChartsBoxplotTests, genEChartsRadarTests, genEChartsCandlestickTests, genEChartsStreamgraphTests, genEChartsFacetSmallTests, genEChartsFacetWrapTests, genEChartsFacetClipTests, genEChartsRoseTests, genEChartsGaugeTests, genEChartsFunnelTests, genEChartsTreemapTests, genEChartsSunburstTests, genEChartsSankeyTests, genEChartsUniqueStressTests, genEChartsCalendarTests, genEChartsParallelTests, genEChartsGraphTests, genEChartsTreeTests } from './echarts-tests'; import { genChartJsScatterTests, genChartJsLineTests, genChartJsBarTests, genChartJsStackedBarTests, genChartJsGroupedBarTests, genChartJsAreaTests, genChartJsPieTests, genChartJsHistogramTests, genChartJsRadarTests, genChartJsStressTests, genChartJsRoseTests, genChartJsBubbleTests, genChartJsDoughnutTests, genChartJsComboTests } from './chartjs-tests'; +import { genPlotlyCoreTests, genPlotlyFacetTests } from './plotly-tests'; import { genGalleryRegionalSurveyScatterTests, genGalleryRegionalSurveyLineTests, @@ -143,7 +147,7 @@ import { export const TEST_GENERATORS: Record TestCase[]> = { 'Scatter Plot': () => [...genScatterTests(), galleryFacetScatterExample()], 'Regression': genRegressionTests, - 'Bar Chart': () => [...genBarTests(), galleryFacetBarExample()], + 'Bar Chart': () => [...genBarTests(), galleryBarSizingShowcase(), galleryFacetBarExample()], 'Stacked Bar Chart': genStackedBarTests, 'Grouped Bar Chart': genGroupedBarTests, 'Histogram': genHistogramTests, @@ -156,6 +160,7 @@ export const TEST_GENERATORS: Record TestCase[]> = { 'Boxplot': genBoxplotTests, 'Violin Plot': genViolinTests, 'Pie Chart': genPieTests, + 'Donut Chart': genDonutTests, 'Ranged Dot Plot': genRangedDotPlotTests, 'Area Chart': () => [...genAreaTests(), galleryFacetAreaExample()], 'Streamgraph': genStreamgraphTests, @@ -163,6 +168,7 @@ export const TEST_GENERATORS: Record TestCase[]> = { 'ECDF Plot': genEcdfTests, 'Lollipop Chart': genLollipopTests, 'Density Plot': genDensityTests, + 'Density Contour': genDensityContourTests, 'Candlestick Chart': genCandlestickTests, 'Waterfall Chart': genWaterfallTests, 'Bar Table': genBarTableTests, @@ -247,6 +253,8 @@ export const TEST_GENERATORS: Record TestCase[]> = { 'Chart.js: Doughnut *': genChartJsDoughnutTests, 'Chart.js: Combo *': genChartJsComboTests, 'Chart.js: Stress Tests': genChartJsStressTests, + 'Plotly: Core Templates': genPlotlyCoreTests, + 'Plotly: Facets': genPlotlyFacetTests, 'Gallery: Scatter': genGalleryRegionalSurveyScatterTests, 'Gallery: Line': genGalleryRegionalSurveyLineTests, 'Gallery: Bar': genGalleryRegionalSurveyBarTests, diff --git a/packages/flint-js/src/test-data/line-area-tests.ts b/packages/flint-js/src/test-data/line-area-tests.ts index a6cf09d7..aa6ccf09 100644 --- a/packages/flint-js/src/test-data/line-area-tests.ts +++ b/packages/flint-js/src/test-data/line-area-tests.ts @@ -3,6 +3,7 @@ import { Type } from './df-types'; import { TestCase, makeField, makeEncodingItem } from './types'; +import { realBumpCases } from './real-world-tests'; import { seededRandom, genDates, genYears, genMonths, genCategories } from './generators'; // Line Chart tests have been moved to line-tests.ts (matrix-driven). @@ -163,5 +164,5 @@ export function genBumpChartTests(): TestCase[] { }); } - return tests; + return [...tests, ...realBumpCases()]; } diff --git a/packages/flint-js/src/test-data/line-tests.ts b/packages/flint-js/src/test-data/line-tests.ts index 1d86b2cd..ef695138 100644 --- a/packages/flint-js/src/test-data/line-tests.ts +++ b/packages/flint-js/src/test-data/line-tests.ts @@ -3,6 +3,7 @@ import { Type } from './df-types'; import { TestCase, makeField, makeEncodingItem } from './types'; +import { realLineCases } from './real-world-tests'; import { seededRandom, genDates, genCategories, genOrdinalLabels, ORDINAL_PREFIXES } from './generators'; // ============================================================================ @@ -452,5 +453,5 @@ export function genLineTests(): TestCase[] { genForecastTestMultiSeries(forecastRand), ]; - return [...matrixTests, ...forecastTests]; + return [...matrixTests, ...forecastTests, ...realLineCases()]; } diff --git a/packages/flint-js/src/test-data/plotly-tests.ts b/packages/flint-js/src/test-data/plotly-tests.ts new file mode 100644 index 00000000..c58baa06 --- /dev/null +++ b/packages/flint-js/src/test-data/plotly-tests.ts @@ -0,0 +1,244 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Plotly backend tests. + * + * Exercises the Plotly backend's first-merge surface: the four acceptance + * templates (Bar, Line, Area, Scatter) with color on/off, and the facet + * grid path (column, row, column×row) that renders as Plotly subplot pairs. + */ + +import { Type } from './df-types'; +import { TestCase, makeField, makeEncodingItem } from './types'; +import { seededRandom } from './generators'; + +// --------------------------------------------------------------------------- +// Test data generators +// --------------------------------------------------------------------------- + +function genRegionSales(seed: number) { + const rand = seededRandom(seed); + const regions = ['East', 'South', 'North', 'West', 'Central']; + return regions.map(r => ({ + Region: r, + Revenue: Math.round(100 + rand() * 900), + })); +} + +function genMonthlySeries(seed: number, series: string[]) { + const rand = seededRandom(seed); + const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug']; + const data: any[] = []; + for (const m of months) { + for (const s of series) { + data.push({ + Month: m, + Value: Math.round(200 + rand() * 800), + Series: s, + }); + } + } + return data; +} + +function genScatterGroups(n: number, seed: number) { + const rand = seededRandom(seed); + const groups = ['Alpha', 'Beta', 'Gamma']; + return Array.from({ length: n }, (_, i) => ({ + X: Math.round(rand() * 100 * 10) / 10, + Y: Math.round(rand() * 100 * 10) / 10, + Group: groups[i % groups.length], + })); +} + +function genQuarterRegion(seed: number) { + const rand = seededRandom(seed); + const quarters = ['Q1', 'Q2', 'Q3', 'Q4']; + const regions = ['North', 'South']; + const data: any[] = []; + for (const q of quarters) { + for (const r of regions) { + data.push({ + Quarter: q, + Revenue: Math.round(200 + rand() * 800), + Region: r, + }); + } + } + return data; +} + +// --------------------------------------------------------------------------- +// Test case builders +// --------------------------------------------------------------------------- + +/** The four acceptance templates, single-series and color-grouped. */ +export function genPlotlyCoreTests(): TestCase[] { + const tests: TestCase[] = []; + + { + const data = genRegionSales(42); + tests.push({ + title: 'PL: Bar — Basic N×Q', + description: 'Single bar trace; category order preserved, zero baseline.', + tags: ['plotly', 'bar'], + chartType: 'Bar Chart', + data, + fields: [makeField('Region'), makeField('Revenue')], + metadata: { + Region: { type: Type.String, semanticType: 'Region', levels: [] }, + Revenue: { type: Type.Number, semanticType: 'Amount', levels: [] }, + }, + encodingMap: { x: makeEncodingItem('Region'), y: makeEncodingItem('Revenue') }, + }); + } + + { + const data = genRegionSales(43); + tests.push({ + title: 'PL: Bar — Horizontal', + description: 'Category on y → orientation "h" bar trace.', + tags: ['plotly', 'bar', 'horizontal'], + chartType: 'Bar Chart', + data, + fields: [makeField('Region'), makeField('Revenue')], + metadata: { + Region: { type: Type.String, semanticType: 'Region', levels: [] }, + Revenue: { type: Type.Number, semanticType: 'Amount', levels: [] }, + }, + encodingMap: { x: makeEncodingItem('Revenue'), y: makeEncodingItem('Region') }, + }); + } + + { + const data = genMonthlySeries(77, ['ProductA', 'ProductB', 'ProductC']); + tests.push({ + title: 'PL: Line — Color Groups', + description: 'One trace per series; legend from trace names.', + tags: ['plotly', 'line', 'color', 'multi-series'], + chartType: 'Line Chart', + data, + fields: [makeField('Month'), makeField('Value'), makeField('Series')], + metadata: { + Month: { type: Type.String, semanticType: 'Month', levels: [] }, + Value: { type: Type.Number, semanticType: 'Amount', levels: [] }, + Series: { type: Type.String, semanticType: 'Category', levels: [] }, + }, + encodingMap: { x: makeEncodingItem('Month'), y: makeEncodingItem('Value'), color: makeEncodingItem('Series') }, + }); + } + + { + const data = genMonthlySeries(88, ['Web', 'Mobile']); + tests.push({ + title: 'PL: Area — Stacked', + description: 'Color groups stack via stackgroup (Plotly-native stacking).', + tags: ['plotly', 'area', 'color', 'stacked'], + chartType: 'Area Chart', + data, + fields: [makeField('Month'), makeField('Value'), makeField('Series')], + metadata: { + Month: { type: Type.String, semanticType: 'Month', levels: [] }, + Value: { type: Type.Number, semanticType: 'Amount', levels: [] }, + Series: { type: Type.String, semanticType: 'Category', levels: [] }, + }, + encodingMap: { x: makeEncodingItem('Month'), y: makeEncodingItem('Value'), color: makeEncodingItem('Series') }, + }); + } + + { + const data = genScatterGroups(90, 99); + tests.push({ + title: 'PL: Scatter — Color Groups', + description: 'Markers mode, one trace per group, qualitative palette.', + tags: ['plotly', 'scatter', 'color', 'multi-series'], + chartType: 'Scatter Plot', + data, + fields: [makeField('X'), makeField('Y'), makeField('Group')], + metadata: { + X: { type: Type.Number, semanticType: 'Quantity', levels: [] }, + Y: { type: Type.Number, semanticType: 'Quantity', levels: [] }, + Group: { type: Type.String, semanticType: 'Category', levels: ['Alpha', 'Beta', 'Gamma'] }, + }, + encodingMap: { x: makeEncodingItem('X'), y: makeEncodingItem('Y'), color: makeEncodingItem('Group') }, + }); + } + + return tests; +} + +/** Facet grid path: column, row, and column×row subplot grids. */ +export function genPlotlyFacetTests(): TestCase[] { + const tests: TestCase[] = []; + + { + const data = genQuarterRegion(11); + tests.push({ + title: 'PL: Facet — Column', + description: 'Bar per Region column; shared nice y-domain, leftmost-only y labels.', + tags: ['plotly', 'facet', 'column', 'bar'], + chartType: 'Bar Chart', + data, + fields: [makeField('Quarter'), makeField('Revenue'), makeField('Region')], + metadata: { + Quarter: { type: Type.String, semanticType: 'Quarter', levels: [] }, + Revenue: { type: Type.Number, semanticType: 'Amount', levels: [] }, + Region: { type: Type.String, semanticType: 'Region', levels: [] }, + }, + encodingMap: { x: makeEncodingItem('Quarter'), y: makeEncodingItem('Revenue'), column: makeEncodingItem('Region') }, + }); + } + + { + const data = genQuarterRegion(22); + tests.push({ + title: 'PL: Facet — Row', + description: 'Line per Region row; rotated row headers, x title on bottom row only.', + tags: ['plotly', 'facet', 'row', 'line'], + chartType: 'Line Chart', + data, + fields: [makeField('Quarter'), makeField('Revenue'), makeField('Region')], + metadata: { + Quarter: { type: Type.String, semanticType: 'Quarter', levels: [] }, + Revenue: { type: Type.Number, semanticType: 'Amount', levels: [] }, + Region: { type: Type.String, semanticType: 'Region', levels: [] }, + }, + encodingMap: { x: makeEncodingItem('Quarter'), y: makeEncodingItem('Revenue'), row: makeEncodingItem('Region') }, + }); + } + + { + const rand = seededRandom(33); + const data: any[] = []; + for (const a of ['A', 'B']) { + for (const b of ['X', 'Y']) { + for (let i = 0; i < 12; i++) { + data.push({ + V: Math.round(rand() * 100), + W: Math.round(rand() * 100), + Col: a, + Row: b, + }); + } + } + } + tests.push({ + title: 'PL: Facet — Column × Row Grid', + description: 'Scatter 2×2 grid; one subplot axis pair per cell.', + tags: ['plotly', 'facet', 'grid', 'scatter'], + chartType: 'Scatter Plot', + data, + fields: [makeField('V'), makeField('W'), makeField('Col'), makeField('Row')], + metadata: { + V: { type: Type.Number, semanticType: 'Quantity', levels: [] }, + W: { type: Type.Number, semanticType: 'Quantity', levels: [] }, + Col: { type: Type.String, semanticType: 'Category', levels: [] }, + Row: { type: Type.String, semanticType: 'Category', levels: [] }, + }, + encodingMap: { x: makeEncodingItem('V'), y: makeEncodingItem('W'), column: makeEncodingItem('Col'), row: makeEncodingItem('Row') }, + }); + } + + return tests; +} diff --git a/packages/flint-js/src/test-data/range-area-tests.ts b/packages/flint-js/src/test-data/range-area-tests.ts index fb7bf694..63d3fb36 100644 --- a/packages/flint-js/src/test-data/range-area-tests.ts +++ b/packages/flint-js/src/test-data/range-area-tests.ts @@ -19,6 +19,7 @@ import { Type } from './df-types'; import { TestCase, makeField, makeEncodingItem } from './types'; +import { realRangeAreaCases } from './real-world-tests'; import { seededRandom, genYears } from './generators'; const MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; @@ -318,7 +319,7 @@ export function genRangeAreaTests(): TestCase[] { }); } - return tests; + return [...tests, ...realRangeAreaCases()]; } /** diff --git a/packages/flint-js/src/test-data/real-world-tests.ts b/packages/flint-js/src/test-data/real-world-tests.ts new file mode 100644 index 00000000..13f2f9d9 --- /dev/null +++ b/packages/flint-js/src/test-data/real-world-tests.ts @@ -0,0 +1,662 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Real-world gallery cases. + * + * A curated set of examples backed by **real, recognizable datasets** (public + * domain / CC-BY / government facts) rather than synthetic random numbers. They + * are appended into the per-chart-type gallery generators and tagged + * `gallery-pin` so `selectVariants` always surfaces them on the wall, alongside + * (or in place of) the synthetic coverage cases. + * + * Each case is built from a compact spec via {@link realCase}, which fills in + * the `fields` / `metadata` / `encodingMap` boilerplate (metadata is inferred + * with {@link buildMetadata}, then the given semantic types are applied). + * + * Provenance for every dataset is recorded in the case `description` and in + * design-docs/gallery-data-audit.md (§6 licensing). Numbers are real values + * transcribed from the cited source (small samples, re-keyed — facts are not + * copyrightable). + */ + +import { TestCase, makeField, makeEncodingItem, buildMetadata } from './types'; + +interface RealSpec { + chartType: string; + title: string; + description: string; + tags?: string[]; + /** field name → semantic type override (applied over inferred metadata). */ + semantic: Record; + /** channel → field name (bare-field encodings). */ + encodings: Record; + data: Record[]; + chartProperties?: Record; +} + +function realCase(spec: RealSpec): TestCase { + const keys = Object.keys(spec.data[0] ?? {}); + const metadata = buildMetadata(spec.data); + for (const [field, st] of Object.entries(spec.semantic)) { + if (metadata[field]) metadata[field].semanticType = st; + } + const encodingMap: TestCase['encodingMap'] = {}; + for (const [channel, field] of Object.entries(spec.encodings)) { + (encodingMap as any)[channel] = makeEncodingItem(field); + } + return { + title: spec.title, + description: spec.description, + tags: ['real', 'gallery-pin', ...(spec.tags ?? [])], + chartType: spec.chartType, + data: spec.data, + fields: keys.map((k) => makeField(k)), + metadata, + encodingMap, + ...(spec.chartProperties ? { chartProperties: spec.chartProperties } : {}), + }; +} + +// ── Shared datasets (reused across a few chart types) ────────────────────── + +const PENGUINS: [string, number, number][] = [ + ['Adelie', 181, 3750], ['Adelie', 186, 3800], ['Adelie', 195, 3250], ['Adelie', 193, 3450], + ['Adelie', 190, 3650], ['Adelie', 181, 3625], ['Adelie', 195, 4675], ['Adelie', 182, 3200], + ['Adelie', 191, 3800], ['Adelie', 198, 4400], ['Adelie', 185, 3700], + ['Chinstrap', 192, 3500], ['Chinstrap', 196, 3900], ['Chinstrap', 193, 3650], + ['Chinstrap', 188, 3525], ['Chinstrap', 197, 3950], ['Chinstrap', 198, 3800], + ['Chinstrap', 178, 3300], ['Chinstrap', 207, 4800], ['Chinstrap', 201, 4050], ['Chinstrap', 191, 3550], + ['Gentoo', 211, 4500], ['Gentoo', 230, 5700], ['Gentoo', 210, 4450], ['Gentoo', 218, 5700], + ['Gentoo', 215, 5400], ['Gentoo', 219, 5550], ['Gentoo', 209, 4800], ['Gentoo', 215, 5000], + ['Gentoo', 214, 4650], ['Gentoo', 216, 5550], ['Gentoo', 221, 5950], ['Gentoo', 217, 5250], +]; + +const FAITHFUL: number[] = [ + 3.6, 1.8, 3.333, 2.283, 4.533, 2.883, 4.7, 3.6, 1.95, 4.35, 1.833, 3.917, 4.2, 1.75, + 4.7, 2.167, 1.75, 4.8, 1.6, 4.25, 1.8, 1.75, 3.45, 3.067, 4.533, 3.6, 1.967, 4.083, + 3.85, 4.433, 4.3, 4.467, 3.367, 4.033, 3.833, 2.017, +]; + +const DRIVING: [number, number, number][] = [ + [1956, 3675, 2.38], [1957, 3706, 2.40], [1958, 3766, 2.26], [1959, 3905, 2.31], [1960, 3935, 2.27], + [1961, 3977, 2.25], [1962, 4085, 2.22], [1963, 4218, 2.12], [1964, 4369, 2.11], [1965, 4538, 2.14], + [1966, 4676, 2.14], [1967, 4827, 2.14], [1968, 5038, 2.13], [1969, 5207, 2.07], [1970, 5376, 2.01], + [1971, 5617, 1.93], [1972, 5973, 1.87], [1973, 6154, 1.90], [1974, 5943, 2.34], [1975, 6111, 2.31], + [1976, 6389, 2.32], [1977, 6630, 2.36], [1978, 6883, 2.23], [1979, 6744, 2.68], [1980, 6672, 3.30], + [1981, 6732, 3.30], [1982, 6835, 2.92], [1983, 6943, 2.66], [1984, 7130, 2.48], [1985, 7323, 2.36], + [1986, 7558, 1.76], [1987, 7770, 1.76], [1988, 8089, 1.68], [1989, 8397, 1.75], [1990, 8529, 1.88], + [1991, 8535, 1.78], [1992, 8662, 1.69], [1993, 8855, 1.60], [1994, 8909, 1.59], [1995, 9150, 1.60], + [1996, 9192, 1.67], [1997, 9416, 1.65], [1998, 9590, 1.39], [1999, 9687, 1.50], [2000, 9717, 1.89], + [2001, 9699, 1.77], [2002, 9814, 1.64], [2003, 9868, 1.86], [2004, 9994, 2.14], [2005, 10067, 2.53], + [2006, 10037, 2.79], [2007, 10025, 2.95], [2008, 9880, 3.31], [2009, 9657, 2.38], [2010, 9596, 2.61], +]; + +// ── Per-chart-type case builders ─────────────────────────────────────────── + +export function realConnectedScatterCases(): TestCase[] { + return [ + realCase({ + chartType: 'Connected Scatter Plot', + title: 'Driving Shifts Into Reverse — miles vs gas price (US, 1956–2010)', + description: 'Miles driven per capita vs the price of gas, connected in year order — the classic self-crossing connected scatterplot (NYT / Hannah Fairfield; FHWA + EIA data).', + tags: ['quantitative', 'temporal-order', 'self-crossing', 'large'], + semantic: { Year: 'Year', 'Miles/person': 'Quantity', 'Gas price': 'Quantity' }, + encodings: { x: 'Miles/person', y: 'Gas price', order: 'Year' }, + data: DRIVING.map(([Year, miles, gas]) => ({ Year, 'Miles/person': miles, 'Gas price': gas })), + }), + ]; +} + +export function realScatterCases(): TestCase[] { + return [ + realCase({ + chartType: 'Scatter Plot', + title: 'Palmer Penguins — flipper length vs body mass', + description: 'Three species form crisp clusters — the modern replacement for the iris dataset (Palmer Station LTER, CC0).', + tags: ['quantitative', 'color', 'clusters'], + semantic: { Species: 'Category', 'Flipper length (mm)': 'Quantity', 'Body mass (g)': 'Quantity' }, + encodings: { x: 'Flipper length (mm)', y: 'Body mass (g)', color: 'Species' }, + data: PENGUINS.map(([Species, flip, mass]) => ({ Species, 'Flipper length (mm)': flip, 'Body mass (g)': mass })), + }), + realCase({ + chartType: 'Scatter Plot', + title: 'Gapminder — life expectancy vs income per capita (2018)', + description: 'The Rosling bubble chart: wealth vs health, bubble size = population, colour = continent, on a log income axis (Gapminder / World Bank).', + tags: ['quantitative', 'color', 'size', 'log'], + semantic: { 'GDP per capita': 'Quantity', 'Life expectancy': 'Quantity', 'Population (M)': 'Quantity', Continent: 'Category' }, + encodings: { x: 'GDP per capita', y: 'Life expectancy', size: 'Population (M)', color: 'Continent' }, + chartProperties: { logScale_x: true }, + data: [ + ['Norway', 64800, 82.3, 5.3, 'Europe'], ['United States', 62600, 78.6, 327, 'Americas'], + ['Japan', 39300, 84.2, 127, 'Asia'], ['China', 16800, 76.7, 1393, 'Asia'], + ['India', 6900, 69.4, 1353, 'Asia'], ['Nigeria', 5300, 54.3, 196, 'Africa'], + ['Brazil', 15600, 75.7, 209, 'Americas'], ['Germany', 50900, 81.0, 83, 'Europe'], + ['Ethiopia', 2000, 66.2, 109, 'Africa'], ['Russia', 25800, 72.4, 145, 'Europe'], + ['Mexico', 19800, 75.0, 126, 'Americas'], ['Indonesia', 12400, 71.5, 268, 'Asia'], + ['Qatar', 116900, 80.1, 2.8, 'Asia'], ['South Africa', 13000, 63.9, 57, 'Africa'], + ['Bangladesh', 4200, 72.3, 161, 'Asia'], + ].map(([Country, gdp, life, pop, Continent]) => ({ Country, 'GDP per capita': gdp, 'Life expectancy': life, 'Population (M)': pop, Continent })), + }), + ]; +} + +export function realRegressionCases(): TestCase[] { + return [ + realCase({ + chartType: 'Regression', + title: 'Auto MPG — horsepower vs fuel economy', + description: 'The classic inverse relationship: more horsepower, fewer miles per gallon (UCI / StatLib Auto MPG sample).', + tags: ['quantitative', 'trend'], + semantic: { Horsepower: 'Quantity', MPG: 'Quantity' }, + encodings: { x: 'Horsepower', y: 'MPG' }, + data: [[130, 18], [165, 15], [150, 18], [150, 16], [140, 17], [198, 15], [220, 14], [215, 14], [97, 22], [85, 26], [88, 25], [46, 26], [90, 25], [95, 24], [68, 29], [70, 27], [52, 30], [65, 31], [67, 30], [48, 43], [66, 32], [100, 22]].map(([Horsepower, MPG]) => ({ Horsepower, MPG })), + }), + realCase({ + chartType: 'Regression', + title: "Anscombe's Quartet — same stats, different shapes", + description: 'Four datasets with identical means, variances and regression lines, but wildly different when plotted (Anscombe 1973).', + tags: ['quantitative', 'facet', 'teaching'], + semantic: { Dataset: 'Category', X: 'Quantity', Y: 'Quantity' }, + encodings: { x: 'X', y: 'Y', column: 'Dataset' }, + chartProperties: { facetColumns: 2 }, + data: (() => { + const x1 = [10, 8, 13, 9, 11, 14, 6, 4, 12, 7, 5]; + const sets: Record = { + I: { x: x1, y: [8.04, 6.95, 7.58, 8.81, 8.33, 9.96, 7.24, 4.26, 10.84, 4.82, 5.68] }, + II: { x: x1, y: [9.14, 8.14, 8.74, 8.77, 9.26, 8.10, 6.13, 3.10, 9.13, 7.26, 4.74] }, + III: { x: x1, y: [7.46, 6.77, 12.74, 7.11, 7.81, 8.84, 6.08, 5.39, 8.15, 6.42, 5.73] }, + IV: { x: [8, 8, 8, 8, 8, 8, 8, 19, 8, 8, 8], y: [6.58, 5.76, 7.71, 8.84, 8.47, 7.04, 5.25, 12.50, 5.56, 7.91, 6.89] }, + }; + const rows: Record[] = []; + for (const [Dataset, { x, y }] of Object.entries(sets)) x.forEach((X, i) => rows.push({ Dataset, X, Y: y[i] })); + return rows; + })(), + }), + ]; +} + +export function realLineCases(): TestCase[] { + return [ + realCase({ + chartType: 'Line Chart', + title: 'Keeling Curve — atmospheric CO₂ at Mauna Loa', + description: 'The defining climate record: annual-mean CO₂ rising from 316 ppm (1959) to 421 ppm (2023) (Scripps / NOAA).', + tags: ['temporal', 'single'], + semantic: { Year: 'Year', 'CO₂ (ppm)': 'Quantity' }, + encodings: { x: 'Year', y: 'CO₂ (ppm)' }, + data: [[1959, 315.98], [1965, 320.04], [1970, 325.68], [1975, 331.11], [1980, 338.80], [1985, 346.12], [1990, 354.45], [1995, 360.82], [2000, 369.71], [2005, 379.98], [2010, 389.90], [2015, 400.83], [2020, 414.24], [2023, 421.08]].map(([Year, ppm]) => ({ Year, 'CO₂ (ppm)': ppm })), + }), + realCase({ + chartType: 'Line Chart', + title: 'US unemployment rate, 2000–2023 (%)', + description: 'The 2009 financial-crisis plateau and the sharp 2020 pandemic spike (US Bureau of Labor Statistics).', + tags: ['temporal', 'single'], + semantic: { Year: 'Year', 'Unemployment (%)': 'Quantity' }, + encodings: { x: 'Year', y: 'Unemployment (%)' }, + data: [[2000, 4.0], [2001, 4.7], [2002, 5.8], [2003, 6.0], [2004, 5.5], [2005, 5.1], [2006, 4.6], [2007, 4.6], [2008, 5.8], [2009, 9.3], [2010, 9.6], [2011, 8.9], [2012, 8.1], [2013, 7.4], [2014, 6.2], [2015, 5.3], [2016, 4.9], [2017, 4.4], [2018, 3.9], [2019, 3.7], [2020, 8.1], [2021, 5.3], [2022, 3.6], [2023, 3.6]].map(([Year, v]) => ({ Year, 'Unemployment (%)': v })), + }), + ]; +} + +export function realAreaCases(): TestCase[] { + return [ + realCase({ + chartType: 'Area Chart', + title: 'Share of the world online, 1995–2023 (%)', + description: 'From ~1% to two-thirds of humanity in under three decades (Our World in Data / ITU).', + tags: ['temporal', 'single'], + semantic: { Year: 'Year', 'Internet users (%)': 'Quantity' }, + encodings: { x: 'Year', y: 'Internet users (%)' }, + data: [[1995, 1], [2000, 7], [2005, 16], [2010, 29], [2015, 43], [2018, 51], [2020, 60], [2023, 67]].map(([Year, v]) => ({ Year, 'Internet users (%)': v })), + }), + ]; +} + +export function realBarCases(): TestCase[] { + return [ + realCase({ + chartType: 'Bar Chart', + title: 'Most populous countries, 2023 (millions)', + description: 'The year India overtook China (UN World Population Prospects / World Bank).', + tags: ['nominal', 'single', 'horizontal'], + semantic: { Country: 'Country', Population: 'Quantity' }, + encodings: { y: 'Country', x: 'Population' }, + data: [['India', 1428.6], ['China', 1425.7], ['United States', 339.9], ['Indonesia', 277.5], ['Pakistan', 240.5], ['Nigeria', 223.8], ['Brazil', 216.4], ['Bangladesh', 173.0], ['Russia', 144.4], ['Mexico', 128.5]].map(([Country, Population]) => ({ Country, Population })), + }), + realCase({ + chartType: 'Bar Chart', + title: 'Global temperature anomaly by decade (°C vs 1951–1980)', + description: 'Bars cross zero — cool early decades below, rapid warming above (NASA GISTEMP).', + tags: ['nominal', 'diverging'], + semantic: { Decade: 'Category', 'Anomaly (°C)': 'Quantity' }, + encodings: { x: 'Decade', y: 'Anomaly (°C)' }, + data: [['1880s', -0.17], ['1900s', -0.16], ['1920s', -0.27], ['1940s', 0.12], ['1960s', -0.03], ['1980s', 0.26], ['2000s', 0.40], ['2010s', 0.72], ['2020s', 1.02]].map(([Decade, v]) => ({ Decade, 'Anomaly (°C)': v })), + }), + ]; +} + +export function realLollipopCases(): TestCase[] { + return [ + realCase({ + chartType: 'Lollipop Chart', + title: 'CO₂ emissions per capita, 2022 (tonnes)', + description: 'Per-person emissions vary ~20× across countries (Our World in Data / Global Carbon Project).', + tags: ['nominal', 'single'], + semantic: { Country: 'Country', 'Tonnes/person': 'Quantity' }, + encodings: { x: 'Country', y: 'Tonnes/person' }, + data: [['Qatar', 37], ['UAE', 22], ['United States', 15], ['Canada', 14], ['Russia', 11], ['Japan', 8.5], ['China', 8.0], ['Germany', 8.0], ['UK', 5.0], ['France', 4.6], ['Brazil', 2.3], ['India', 2.0]].map(([Country, v]) => ({ Country, 'Tonnes/person': v })), + }), + ]; +} + +export function realHistogramCases(): TestCase[] { + return [ + realCase({ + chartType: 'Histogram', + title: 'Old Faithful — distribution of eruption durations', + description: 'Two humps: short (~2 min) and long (~4.5 min) eruptions — a mean would hide this (R "faithful" sample).', + tags: ['quantitative', 'bimodal'], + semantic: { 'Duration (min)': 'Quantity' }, + encodings: { x: 'Duration (min)' }, + data: FAITHFUL.map((d) => ({ 'Duration (min)': d })), + }), + ]; +} + +export function realDensityCases(): TestCase[] { + return [ + realCase({ + chartType: 'Density Plot', + title: 'Old Faithful — eruption duration density', + description: 'The same bimodal shape as a smooth density curve (R "faithful" sample).', + tags: ['quantitative', 'bimodal'], + semantic: { 'Duration (min)': 'Quantity' }, + encodings: { x: 'Duration (min)' }, + data: FAITHFUL.map((d) => ({ 'Duration (min)': d })), + }), + ]; +} + +export function realBoxplotCases(): TestCase[] { + return [ + realCase({ + chartType: 'Boxplot', + title: 'Penguin body mass by species', + description: 'Gentoo penguins are markedly heavier than Adélie and Chinstrap (Palmer Station LTER, CC0).', + tags: ['quantitative', 'category'], + semantic: { Species: 'Category', 'Body mass (g)': 'Quantity' }, + encodings: { x: 'Species', y: 'Body mass (g)' }, + data: PENGUINS.map(([Species, , mass]) => ({ Species, 'Body mass (g)': mass })), + }), + ]; +} + +export function realStripCases(): TestCase[] { + return [ + realCase({ + chartType: 'Strip Plot', + title: 'Iris petal length by species', + description: 'Setosa petals are tiny and tightly clustered; the other two overlap more (Fisher 1936 sample).', + tags: ['quantitative', 'category'], + semantic: { Species: 'Category', 'Petal length (cm)': 'Quantity' }, + encodings: { x: 'Species', y: 'Petal length (cm)' }, + data: (() => { + const t: Record = { Setosa: [1.4, 1.4, 1.3, 1.5, 1.4, 1.7, 1.4, 1.5, 1.5, 1.6], Versicolor: [4.7, 4.5, 4.9, 4.0, 4.6, 4.5, 4.7, 3.3, 4.6, 3.9], Virginica: [6.0, 5.1, 5.9, 5.6, 5.8, 6.6, 4.5, 6.3, 5.8, 6.1] }; + const rows: Record[] = []; + for (const [Species, arr] of Object.entries(t)) for (const v of arr) rows.push({ Species, 'Petal length (cm)': v }); + return rows; + })(), + }), + ]; +} + +// ── More shared datasets ─────────────────────────────────────────────────── + +const MO = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + +const POP_REGION: Record> = { + 1950: { Asia: 1404, Africa: 227, Europe: 549, Americas: 339, Oceania: 13 }, + 1970: { Asia: 2142, Africa: 365, Europe: 657, Americas: 512, Oceania: 20 }, + 1990: { Asia: 3226, Africa: 630, Europe: 721, Americas: 724, Oceania: 27 }, + 2010: { Asia: 4194, Africa: 1039, Europe: 736, Americas: 934, Oceania: 37 }, + 2020: { Asia: 4641, Africa: 1361, Europe: 748, Americas: 1023, Oceania: 45 }, +}; + +export function realEcdfCases(): TestCase[] { + return [ + realCase({ + chartType: 'ECDF Plot', + title: 'Exam scores — cumulative distribution', + description: 'Read percentiles directly: the median is where the curve crosses 0.5.', + tags: ['quantitative'], + semantic: { Score: 'Quantity' }, + encodings: { x: 'Score' }, + data: [55, 62, 68, 71, 73, 74, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 85, 86, 87, 88, 88, 89, 90, 91, 92, 93, 94, 95, 97, 99].map((Score) => ({ Score })), + }), + ]; +} + +export function realGroupedBarCases(): TestCase[] { + return [ + realCase({ + chartType: 'Grouped Bar Chart', + title: 'Titanic survival rate by class and sex', + description: '"Women and children first" — and first class — are stark in the numbers (Encyclopedia Titanica).', + tags: ['nominal', 'group'], + semantic: { Class: 'Category', Sex: 'Category', 'Survival (%)': 'Quantity' }, + encodings: { x: 'Class', y: 'Survival (%)', group: 'Sex' }, + data: (() => { + const t: Record = { '1st': [97, 34], '2nd': [89, 15], '3rd': [49, 15] }; + const rows: Record[] = []; + for (const [Class, [fem, male]] of Object.entries(t)) { rows.push({ Class, Sex: 'Female', 'Survival (%)': fem }); rows.push({ Class, Sex: 'Male', 'Survival (%)': male }); } + return rows; + })(), + }), + ]; +} + +export function realStackedBarCases(): TestCase[] { + return [ + realCase({ + chartType: 'Stacked Bar Chart', + title: 'Electricity generation mix by country, 2023', + description: 'How each country splits generation across sources (Our World in Data / Ember).', + tags: ['nominal', 'color'], + semantic: { Country: 'Country', Source: 'Category', Share: 'Quantity' }, + encodings: { x: 'Country', y: 'Share', color: 'Source' }, + data: (() => { + const t: Record> = { France: { Nuclear: 65, Renewables: 27, Fossil: 8 }, Germany: { Renewables: 52, Fossil: 45, Nuclear: 3 }, 'United States': { Fossil: 60, Nuclear: 18, Renewables: 22 }, China: { Fossil: 62, Renewables: 33, Nuclear: 5 }, Brazil: { Renewables: 89, Fossil: 9, Nuclear: 2 } }; + const rows: Record[] = []; + for (const [Country, by] of Object.entries(t)) for (const [Source, Share] of Object.entries(by)) rows.push({ Country, Source, Share }); + return rows; + })(), + }), + ]; +} + +export function realStreamgraphCases(): TestCase[] { + const rows: Record[] = []; + for (const [yr, by] of Object.entries(POP_REGION)) for (const [Region, Population] of Object.entries(by)) rows.push({ Year: Number(yr), Region, Population }); + return [ + realCase({ + chartType: 'Streamgraph', + title: 'World population by region, 1950–2020', + description: "Asia's dominance and Africa's acceleration as a centre-stacked stream (UN World Population Prospects).", + tags: ['temporal', 'color'], + semantic: { Year: 'Year', Region: 'Category', Population: 'Quantity' }, + encodings: { x: 'Year', y: 'Population', color: 'Region' }, + data: rows, + }), + ]; +} + +export function realRangeAreaCases(): TestCase[] { + return [ + realCase({ + chartType: 'Range Area Chart', + title: 'Seattle average monthly temperature range', + description: 'The band spans the average daily low to high each month (NOAA climate normals).', + tags: ['temporal', 'band'], + semantic: { Month: 'Category', Low: 'Quantity', High: 'Quantity' }, + encodings: { x: 'Month', y: 'Low', y2: 'High' }, + data: (() => { const lo = [37, 37, 40, 43, 48, 53, 56, 57, 53, 46, 40, 36], hi = [47, 50, 54, 59, 65, 70, 76, 77, 71, 60, 51, 46]; return MO.map((Month, i) => ({ Month, Low: lo[i], High: hi[i] })); })(), + }), + ]; +} + +export function realBumpCases(): TestCase[] { + return [ + realCase({ + chartType: 'Bump Chart', + title: 'Olympic medal-table rank, 2012–2024', + description: 'Rank across four Summer Games (1 = top of the table) (IOC medal tables).', + tags: ['temporal', 'color', 'rank'], + semantic: { Games: 'Year', Country: 'Country', Rank: 'Quantity' }, + encodings: { x: 'Games', y: 'Rank', color: 'Country' }, + data: (() => { + const games = [2012, 2016, 2020, 2024]; + const t: Record = { 'United States': [1, 1, 1, 1], China: [2, 3, 2, 2], 'Great Britain': [3, 2, 4, 7], Japan: [6, 6, 5, 3] }; + const rows: Record[] = []; + for (const [Country, ranks] of Object.entries(t)) games.forEach((Games, i) => rows.push({ Games, Country, Rank: ranks[i] })); + return rows; + })(), + }), + ]; +} + +export function realSparklineCases(): TestCase[] { + return [ + realCase({ + chartType: 'Sparkline', + title: 'Monthly KPIs — revenue, users, churn', + description: 'Three business metrics as mini trend lines, one per row.', + tags: ['temporal', 'multi-series'], + semantic: { Month: 'Category', Metric: 'Category', Value: 'Quantity' }, + encodings: { x: 'Month', y: 'Value', color: 'Metric' }, + data: (() => { + const t: Record = { 'Revenue ($k)': [120, 125, 130, 128, 140, 145, 150, 148, 160, 165, 170, 180], 'Active users (k)': [40, 42, 45, 47, 50, 52, 55, 58, 60, 63, 66, 70], 'Churn (%)': [5.2, 5.0, 4.8, 4.9, 4.6, 4.5, 4.3, 4.4, 4.1, 4.0, 3.9, 3.8] }; + const rows: Record[] = []; + for (const [Metric, arr] of Object.entries(t)) arr.forEach((Value, i) => rows.push({ Month: MO[i], Metric, Value })); + return rows; + })(), + }), + ]; +} + +export function realPieCases(): TestCase[] { + return [ + realCase({ + chartType: 'Pie Chart', + title: 'Desktop browser market share, 2024', + description: 'Chrome dominates; Safari and Edge trail (StatCounter).', + tags: ['nominal'], + semantic: { Browser: 'Category', Share: 'Quantity' }, + encodings: { size: 'Share', color: 'Browser' }, + data: [['Chrome', 65], ['Safari', 12], ['Edge', 12], ['Firefox', 6], ['Other', 5]].map(([Browser, Share]) => ({ Browser, Share })), + }), + ]; +} + +export function realDonutCases(): TestCase[] { + return [ + realCase({ + chartType: 'Donut Chart', + title: 'Mobile OS market share, 2024', + description: 'Android vs iOS worldwide (StatCounter).', + tags: ['nominal'], + semantic: { OS: 'Category', Share: 'Quantity' }, + encodings: { size: 'Share', color: 'OS' }, + data: [['Android', 71], ['iOS', 28], ['Other', 1]].map(([OS, Share]) => ({ OS, Share })), + }), + ]; +} + +export function realRoseCases(): TestCase[] { + return [ + realCase({ + chartType: 'Rose Chart', + title: 'Seattle monthly rainfall', + description: 'Wet winters, dry midsummer — as polar bars around the year (NOAA climate normals).', + tags: ['nominal', 'cyclic'], + semantic: { Month: 'Category', 'Rainfall (mm)': 'Quantity' }, + encodings: { x: 'Month', y: 'Rainfall (mm)' }, + data: (() => { const r = [140, 90, 95, 70, 50, 40, 18, 25, 40, 100, 165, 155]; return MO.map((Month, i) => ({ Month, 'Rainfall (mm)': r[i] })); })(), + }), + ]; +} + +export function realRadarCases(): TestCase[] { + return [ + realCase({ + chartType: 'Radar Chart', + title: 'Nutrition profile per 100 g — almonds vs oats vs yogurt', + description: 'Compare three foods across five nutrients; each traces a distinct polygon (USDA FoodData Central).', + tags: ['nominal', 'color'], + semantic: { Nutrient: 'Category', Food: 'Category', 'Grams/100g': 'Quantity' }, + encodings: { x: 'Nutrient', y: 'Grams/100g', color: 'Food' }, + data: (() => { + const table: Record> = { Almonds: { Protein: 21, Fat: 50, Carbs: 22, Fiber: 12, Sugar: 4 }, Oats: { Protein: 17, Fat: 7, Carbs: 66, Fiber: 11, Sugar: 1 }, 'Greek yogurt': { Protein: 10, Fat: 5, Carbs: 4, Fiber: 0, Sugar: 4 } }; + const rows: Record[] = []; + for (const [Food, by] of Object.entries(table)) for (const [Nutrient, g] of Object.entries(by)) rows.push({ Food, Nutrient, 'Grams/100g': g }); + return rows; + })(), + }), + ]; +} + +export function realWaterfallCases(): TestCase[] { + return [ + realCase({ + chartType: 'Waterfall Chart', + title: 'World population growth 1950 → 2020, by region', + description: 'A bridge from 2.5B to ~7.8B people, broken down by each region\'s addition (UN World Population Prospects).', + tags: ['nominal', 'change'], + semantic: { Step: 'Category', 'Population (M)': 'Quantity' }, + encodings: { x: 'Step', y: 'Population (M)' }, + chartProperties: { totals: 'last' }, + data: [ + { Step: '1950', 'Population (M)': 2536 }, + { Step: 'Asia', 'Population (M)': 3237 }, + { Step: 'Africa', 'Population (M)': 1134 }, + { Step: 'Americas', 'Population (M)': 684 }, + { Step: 'Europe', 'Population (M)': 199 }, + { Step: 'Oceania', 'Population (M)': 32 }, + ], + }), + ]; +} + +export function realCandlestickCases(): TestCase[] { + return [ + realCase({ + chartType: 'Candlestick Chart', + title: 'Daily stock OHLC over two weeks', + description: 'Open-high-low-close candles over ~10 trading days.', + tags: ['temporal', 'ohlc'], + semantic: { Date: 'Date', Open: 'Quantity', High: 'Quantity', Low: 'Quantity', Close: 'Quantity' }, + encodings: { x: 'Date', open: 'Open', high: 'High', low: 'Low', close: 'Close' }, + data: [['2024-01-02', 187, 188, 183, 185], ['2024-01-03', 184, 185, 182, 184], ['2024-01-04', 182, 183, 180, 182], ['2024-01-05', 182, 182, 179, 181], ['2024-01-08', 182, 186, 182, 185], ['2024-01-09', 184, 185, 183, 185], ['2024-01-10', 184, 186, 183, 186], ['2024-01-11', 186, 187, 183, 186], ['2024-01-12', 186, 188, 185, 185]].map(([Date, Open, High, Low, Close]) => ({ Date, Open, High, Low, Close })), + }), + ]; +} + +export function realHeatmapCases(): TestCase[] { + return [ + realCase({ + chartType: 'Heatmap', + title: 'Average monthly temperature by city', + description: 'Warm bands for the tropics, cold winters for Moscow (climate normals).', + tags: ['grid'], + semantic: { Month: 'Category', City: 'Category', 'Temp (°C)': 'Quantity' }, + encodings: { x: 'Month', y: 'City', color: 'Temp (°C)' }, + data: (() => { + const t: Record = { Singapore: [26, 27, 28, 28, 28, 28, 27, 27, 27, 27, 26, 26], Cairo: [14, 15, 18, 22, 26, 28, 29, 29, 27, 24, 20, 16], Moscow: [-9, -7, -1, 7, 13, 17, 19, 17, 11, 5, -1, -6], Seattle: [5, 6, 8, 10, 13, 16, 19, 19, 16, 11, 7, 4] }; + const rows: Record[] = []; + for (const [City, arr] of Object.entries(t)) arr.forEach((v, i) => rows.push({ City, Month: MO[i], 'Temp (°C)': v })); + return rows; + })(), + }), + ]; +} + +export function realPyramidCases(): TestCase[] { + return [ + realCase({ + chartType: 'Pyramid Chart', + title: 'US population by age and sex, 2020', + description: 'A classic population pyramid — male vs female by age band (US Census 2020).', + tags: ['nominal', 'diverging'], + semantic: { Age: 'Category', Sex: 'Category', Population: 'Quantity' }, + encodings: { x: 'Population', y: 'Age', color: 'Sex' }, + data: (() => { + const ages = ['0–14', '15–29', '30–44', '45–59', '60–74', '75+']; + const m = [31, 34, 33, 30, 26, 10], f = [30, 32, 33, 31, 28, 15]; + const rows: Record[] = []; + ages.forEach((Age, i) => { rows.push({ Age, Sex: 'Male', Population: m[i] }); rows.push({ Age, Sex: 'Female', Population: f[i] }); }); + return rows; + })(), + }), + ]; +} + +export function realBarTableCases(): TestCase[] { + return [ + realCase({ + chartType: 'Bar Table', + title: 'GDP by country, 2023 (trillion USD)', + description: 'Compact ranked bars with value labels (IMF / World Bank 2023).', + tags: ['nominal'], + semantic: { Country: 'Country', 'GDP ($T)': 'Quantity' }, + encodings: { y: 'Country', x: 'GDP ($T)' }, + data: [['United States', 27.4], ['China', 17.8], ['Germany', 4.5], ['Japan', 4.2], ['India', 3.9], ['UK', 3.3], ['France', 3.0], ['Brazil', 2.2]].map(([Country, v]) => ({ Country, 'GDP ($T)': v })), + }), + ]; +} + +export function realRangedDotCases(): TestCase[] { + return [ + realCase({ + chartType: 'Ranged Dot Plot', + title: 'Life expectancy gap, male vs female (2021)', + description: 'The dumbbell length is the female–male gap in years (World Bank 2021).', + tags: ['nominal', 'color'], + semantic: { Country: 'Country', Sex: 'Category', 'Life expectancy': 'Quantity' }, + encodings: { x: 'Life expectancy', y: 'Country', color: 'Sex' }, + data: (() => { + const t: Record = { Japan: [81.5, 87.6], 'United States': [73.5, 79.3], India: [66.0, 69.0], Brazil: [69.0, 76.0], Nigeria: [51.0, 54.0], Germany: [78.5, 83.4] }; + const rows: Record[] = []; + for (const [Country, [mm, ff]] of Object.entries(t)) { rows.push({ Country, Sex: 'Male', 'Life expectancy': mm }); rows.push({ Country, Sex: 'Female', 'Life expectancy': ff }); } + return rows; + })(), + }), + ]; +} + +export function realGanttCases(): TestCase[] { + return [ + realCase({ + chartType: 'Gantt Chart', + title: 'Software release schedule', + description: 'Overlapping phases from planning to launch.', + tags: ['temporal', 'schedule'], + semantic: { Task: 'Category', Start: 'Date', End: 'Date' }, + encodings: { y: 'Task', x: 'Start', x2: 'End' }, + data: [['Planning', '2024-01-01', '2024-01-14'], ['Design', '2024-01-15', '2024-02-04'], ['Implementation', '2024-02-05', '2024-03-17'], ['Testing', '2024-03-11', '2024-04-07'], ['Launch', '2024-04-08', '2024-04-15']].map(([Task, Start, End]) => ({ Task, Start, End })), + }), + ]; +} + +export function realBulletCases(): TestCase[] { + return [ + realCase({ + chartType: 'Bullet Chart', + title: 'Renewable electricity share vs 2030 target', + description: 'Each bar is the current share; the tick marks the 2030 target (OWID / Ember).', + tags: ['nominal', 'target'], + semantic: { Country: 'Country', Share: 'Quantity', Target: 'Quantity' }, + encodings: { y: 'Country', x: 'Share', goal: 'Target' }, + data: [['Norway', 98.6, 100], ['Brazil', 89.2, 95], ['Germany', 51.6, 80], ['World', 30.3, 60], ['United States', 22.7, 50]].map(([Country, Share, Target]) => ({ Country, Share, Target })), + }), + ]; +} + +export function realKpiCases(): TestCase[] { + return [ + realCase({ + chartType: 'KPI Card', + title: 'Global clean-energy progress vs 2030 targets', + description: 'Headline climate & connectivity metrics against their 2030 targets, with progress bars (OWID / IEA / ITU).', + tags: ['bi', 'goal', 'progress'], + semantic: { Metric: 'Category', Value: 'Quantity', Goal: 'Quantity' }, + encodings: { metric: 'Metric', value: 'Value', goal: 'Goal' }, + chartProperties: { layout: 'horizontal' }, + data: [ + { Metric: 'Renewable electricity (%)', Value: 30.3, Goal: 45 }, + { Metric: 'EV share of car sales (%)', Value: 18, Goal: 40 }, + { Metric: 'World online (%)', Value: 67, Goal: 90 }, + { Metric: 'Electricity access (%)', Value: 91, Goal: 100 }, + ], + }), + ]; +} diff --git a/packages/flint-js/src/test-data/scatter-tests.ts b/packages/flint-js/src/test-data/scatter-tests.ts index c4943bda..bafa7268 100644 --- a/packages/flint-js/src/test-data/scatter-tests.ts +++ b/packages/flint-js/src/test-data/scatter-tests.ts @@ -3,6 +3,7 @@ import { Type } from './df-types'; import { TestCase, makeField, makeEncodingItem } from './types'; +import { realScatterCases, realRegressionCases } from './real-world-tests'; import { seededRandom, genDates, genCategories, genRandomNames } from './generators'; // ============================================================================ @@ -362,7 +363,7 @@ export function genScatterTests(): TestCase[] { }); } - return tests; + return [...tests, ...realScatterCases()]; } // ============================================================================ @@ -668,5 +669,5 @@ export function genRegressionTests(): TestCase[] { }); } - return tests; + return [...tests, ...realRegressionCases()]; } diff --git a/packages/flint-js/src/test-data/sparkline-tests.ts b/packages/flint-js/src/test-data/sparkline-tests.ts index 9ddefc27..ed7854a6 100644 --- a/packages/flint-js/src/test-data/sparkline-tests.ts +++ b/packages/flint-js/src/test-data/sparkline-tests.ts @@ -3,6 +3,7 @@ import { Type } from './df-types'; import { TestCase, makeField, makeEncodingItem } from './types'; +import { realSparklineCases } from './real-world-tests'; import { seededRandom, genDates, genCategories } from './generators'; // ============================================================================ @@ -135,5 +136,5 @@ function sparkMatrixToTestCase(e: SparkMatrixEntry, rand: () => number): TestCas export function genSparklineTests(): TestCase[] { const rand = seededRandom(0x5A8C); - return SPARK_MATRIX.map(e => sparkMatrixToTestCase(e, rand)); + return [...SPARK_MATRIX.map(e => sparkMatrixToTestCase(e, rand)), ...realSparklineCases()]; } diff --git a/packages/flint-js/src/test-data/specialized-tests.ts b/packages/flint-js/src/test-data/specialized-tests.ts index 4398df81..8b23d87b 100644 --- a/packages/flint-js/src/test-data/specialized-tests.ts +++ b/packages/flint-js/src/test-data/specialized-tests.ts @@ -3,6 +3,7 @@ import { Type } from './df-types'; import { TestCase, makeField, makeEncodingItem, buildMetadata } from './types'; +import { realLollipopCases, realPieCases, realDonutCases, realRoseCases, realRadarCases, realWaterfallCases, realCandlestickCases, realHeatmapCases, realPyramidCases, realBarTableCases, realRangedDotCases } from './real-world-tests'; import { seededRandom, genDates, genMonths, genCategories, genRandomNames } from './generators'; // ------ Heatmap ------ @@ -212,7 +213,7 @@ export function genHeatmapTests(): TestCase[] { }); } - return tests; + return [...tests, ...realHeatmapCases()]; } // ------ Pie Chart ------ @@ -297,7 +298,20 @@ export function genPieTests(): TestCase[] { }); } - return tests; + return [...tests, ...realPieCases()]; +} + +export function genDonutTests(): TestCase[] { + return [ + ...genPieTests().filter(t => !(t.tags ?? []).includes('real')).map(test => ({ + ...test, + title: test.title.replace('Pie', 'Donut'), + description: test.description.replace('Pie', 'Donut'), + chartType: 'Donut Chart', + chartProperties: { ...test.chartProperties, innerRadius: 50 }, + })), + ...realDonutCases(), + ]; } // ------ Ranged Dot Plot ------ @@ -328,7 +342,7 @@ export function genRangedDotPlotTests(): TestCase[] { }); } - return tests; + return [...tests, ...realRangedDotCases()]; } // ------ Lollipop Chart ------ @@ -435,7 +449,7 @@ export function genLollipopTests(): TestCase[] { }); } - return tests; + return [...tests, ...realLollipopCases()]; } // ------ Waterfall Chart ------ @@ -580,7 +594,7 @@ export function genWaterfallTests(): TestCase[] { }); } - return tests; + return [...tests, ...realWaterfallCases()]; } // ------ Bar Table ------ @@ -1121,7 +1135,7 @@ export function genBarTableTests(): TestCase[] { }); } - return tests; + return [...tests, ...realBarTableCases()]; } // ------ Candlestick Chart ------ @@ -1136,7 +1150,7 @@ export function genCandlestickTests(): TestCase[] { const baseDate = new Date('2024-01-02'); for (let i = 0; i < days; i++) { const date = new Date(baseDate); - date.setDate(baseDate.getDate() + i); + date.setUTCDate(baseDate.getUTCDate() + i); const change = (rand() - 0.48) * 4; // slight upward bias const open = Math.round(price * 100) / 100; const close = Math.round((price + change) * 100) / 100; @@ -1242,7 +1256,7 @@ export function genCandlestickTests(): TestCase[] { const baseDate = new Date('2024-03-01'); for (let i = 0; i < 20; i++) { const date = new Date(baseDate); - date.setDate(baseDate.getDate() + i); + date.setUTCDate(baseDate.getUTCDate() + i); const change = (rand() - 0.48) * 4; const open = Math.round(price * 100) / 100; const close = Math.round((price + change) * 100) / 100; @@ -1278,7 +1292,7 @@ export function genCandlestickTests(): TestCase[] { }); } - return tests; + return [...tests, ...realCandlestickCases()]; } // ------ Radar Chart ------ @@ -1469,7 +1483,7 @@ export function genRadarTests(): TestCase[] { }); } - return tests; + return [...tests, ...realRadarCases()]; } // ------ Pyramid Chart ------ @@ -1684,7 +1698,7 @@ export function genPyramidTests(): TestCase[] { }); } - return tests; + return [...tests, ...realPyramidCases()]; } // ------ Rose Chart (Nightingale / Coxcomb) ------ @@ -1911,5 +1925,5 @@ export function genRoseTests(): TestCase[] { }); } - return tests; + return [...tests, ...realRoseCases()]; } diff --git a/packages/flint-js/src/vegalite/assemble.ts b/packages/flint-js/src/vegalite/assemble.ts index 59a4c7a3..69e6ac0c 100644 --- a/packages/flint-js/src/vegalite/assemble.ts +++ b/packages/flint-js/src/vegalite/assemble.ts @@ -62,7 +62,7 @@ import { inferVisCategory, computeZeroDecision } from '../core/semantic-types'; import { resolveChannelSemantics, convertTemporalData } from '../core/resolve-semantics'; import { toTypeString, type SemanticAnnotation } from '../core/field-semantics'; import { filterOverflow } from '../core/filter-overflow'; -import { computeLayout, computeChannelBudgets, computeMinSubplotDimensions, deriveStretchCaps, resolveBaseSize } from '../core/compute-layout'; +import { computeLayout, computeChannelBudgets, computeMinSubplotDimensions, deriveStretchCaps, resolveBaseSize, resolveFacetColumnsOption } from '../core/compute-layout'; import { vlApplyLayoutToSpec, vlApplyTooltips } from './instantiate-spec'; import { normalizeStaticSeries } from '../core/static-series'; import { normalizeChartProperties } from '../core/normalize-properties'; @@ -340,6 +340,9 @@ export function assembleVegaLite(input: ChartAssemblyInput): any { // Merge paramOverrides into effective options const effectiveOptions: AssembleOptions = { + // Vega-Lite native font defaults (labels 10, titles 11). + baseLabelFontSize: 10, + baseTitleFontSize: 11, ...options, ...(declaration.paramOverrides || {}), }; @@ -370,6 +373,7 @@ export function assembleVegaLite(input: ChartAssemblyInput): any { const caps = deriveStretchCaps(baseSize, sizeCeiling, effectiveOptions); effectiveOptions.maxStretchX = caps.maxStretchX; effectiveOptions.maxStretchY = caps.maxStretchY; + effectiveOptions.facetColumns = resolveFacetColumnsOption(input.chart_spec.chartProperties); const facetFixW = effectiveOptions.facetFixedPadding.width; const facetFixH = effectiveOptions.facetFixedPadding.height; @@ -698,6 +702,28 @@ export function assembleVegaLite(input: ChartAssemblyInput): any { const { check, ...rest } = def; return { ...rest, applicable, value }; }); + // Layout-level facet-wrap control: offered whenever a column facet has + // enough panels to wrap. It's not a per-template MARK property, so it's + // injected centrally rather than declared on every faceted template. The + // value seeds from the raw user override, else the auto-computed grid + // column count (facetGridResult), else all panels in one row. + const colFacetField = channelSemantics.column?.field; + if (colFacetField) { + const colCount = new Set(data.map((r: any) => r[colFacetField])).size; + if (colCount > 2) { + const rawFacetCols = input.chart_spec.chartProperties?.facetColumns; + result._options.push({ + key: 'facetColumns', + label: 'Columns', + type: 'continuous', + min: 1, + max: colCount, + step: 1, + applicable: true, + value: rawFacetCols ?? facetGridResult?.columns ?? colCount, + } as ChartOption); + } + } // Pivot surface: the resolved set of alternative views (state ids + labels + // active index) for the current encodings + data. Hosts read this to render // a cyclic prev/next control and write the chosen id back to diff --git a/packages/flint-js/src/vegalite/instantiate-spec.ts b/packages/flint-js/src/vegalite/instantiate-spec.ts index 642d4faa..1b381f6f 100644 --- a/packages/flint-js/src/vegalite/instantiate-spec.ts +++ b/packages/flint-js/src/vegalite/instantiate-spec.ts @@ -217,13 +217,17 @@ export function vlApplyLayoutToSpec( const axisXConfig: Record = { labelLimit: layout.xLabel.labelLimit, labelFontSize: layout.xLabel.fontSize, + titleFontSize: layout.titleFontSize, }; if (layout.xLabel.labelAngle !== undefined) { axisXConfig.labelAngle = layout.xLabel.labelAngle; axisXConfig.labelAlign = layout.xLabel.labelAlign; axisXConfig.labelBaseline = layout.xLabel.labelBaseline; } - const axisYConfig: Record = { labelFontSize: layout.yLabel.fontSize }; + const axisYConfig: Record = { + labelFontSize: layout.yLabel.fontSize, + titleFontSize: layout.titleFontSize, + }; vgObj.config = { view: { @@ -233,6 +237,10 @@ export function vlApplyLayoutToSpec( }, axisX: axisXConfig, axisY: axisYConfig, + legend: { + labelFontSize: layout.legendFontSize, + titleFontSize: layout.titleFontSize, + }, }; // --- Step-based sizing for discrete axes --- diff --git a/packages/flint-js/src/vegalite/templates/connected-scatter.ts b/packages/flint-js/src/vegalite/templates/connected-scatter.ts index c17892cf..151a7ff4 100644 --- a/packages/flint-js/src/vegalite/templates/connected-scatter.ts +++ b/packages/flint-js/src/vegalite/templates/connected-scatter.ts @@ -88,13 +88,14 @@ export const connectedScatterDef: ChartTemplateDef = { delete spec.encoding.order; } - // Both position axes fit the data (a trajectory reads the shape, not the - // distance from zero), matching the Scatter Plot convention. The zero - // decision the engine attached to each axis still wins when it is set. - // A few pixels of scale padding keep the extreme points (and their - // markers) clear of the plot edges so a point that lands exactly on an - // axis bound is not clipped. - xEnc.scale = { ...xEnc.scale, nice: true, padding: 10 }; - yEnc.scale = { ...yEnc.scale, nice: true, padding: 10 }; + // Clean, data-fitting bounds via Vega-Lite's native `nice`. The + // zero-baseline is left to the engine (computeZeroDecision), same as any + // other position chart. IMPORTANT: no pixel `scale.padding` here — + // padding expands the domain symmetrically and, combined with `nice`, + // can round a zero-anchored axis *below* zero on strictly-positive data + // (e.g. gas price rounding to -0.5). `nice` alone gives clean, + // non-negative bounds. + xEnc.scale = { ...xEnc.scale, nice: true }; + yEnc.scale = { ...yEnc.scale, nice: true }; }, }; diff --git a/packages/flint-js/src/vegalite/templates/index.ts b/packages/flint-js/src/vegalite/templates/index.ts index 56c3c0a6..2fe6ace4 100644 --- a/packages/flint-js/src/vegalite/templates/index.ts +++ b/packages/flint-js/src/vegalite/templates/index.ts @@ -22,7 +22,7 @@ import { bumpChartDef } from './bump'; import { slopeChartDef } from './slope'; import { areaChartDef, streamgraphDef } from './area'; import { rangeAreaChartDef } from './range-area'; -import { pieChartDef } from './pie'; +import { donutChartDef, pieChartDef } from './pie'; import { lollipopChartDef } from './lollipop'; import { densityPlotDef } from './density'; import { violinPlotDef } from './violin'; @@ -250,7 +250,7 @@ export const vlTemplateDefs: { [key: string]: ChartTemplateDef[] } = Object.from "Bars": [barChartDef, groupedBarChartDef, stackedBarChartDef, lollipopChartDef, waterfallChartDef, ganttChartDef, bulletChartDef], "Distributions": [histogramDef, densityPlotDef, ecdfPlotDef, violinPlotDef, boxplotDef, pyramidChartDef, candlestickChartDef], "Lines & Areas": [lineChartDef, sparklineDef, bumpChartDef, slopeChartDef, areaChartDef, streamgraphDef, rangeAreaChartDef], - "Circular": [pieChartDef, roseChartDef, radarChartDef], + "Circular": [pieChartDef, donutChartDef, roseChartDef, radarChartDef], "Tables & Maps": [heatmapDef, barTableDef, kpiCardDef, mapDef, choroplethDef], }).map(([category, defs]) => [category, defs.map(withInjectedProperties)]), ); diff --git a/packages/flint-js/src/vegalite/templates/map.ts b/packages/flint-js/src/vegalite/templates/map.ts index 4229a6ad..de63983a 100644 --- a/packages/flint-js/src/vegalite/templates/map.ts +++ b/packages/flint-js/src/vegalite/templates/map.ts @@ -2,7 +2,10 @@ // Licensed under the MIT License. import { ChartTemplateDef, ChartPropertyDef, OptionEvalContext } from '../../core/types'; -import { resolveUsState, resolveCountry, GeoResolver } from './geo-lookup'; +import { + resolveUsState, resolveCountry, GeoResolver, + type MapScope, inferBubbleScope, inferChoroplethScope, semanticScope, pickMapScope, +} from '../../chart-types/geo'; import { toTypeString } from '../../core/field-semantics'; const mapProjections = [ @@ -44,10 +47,12 @@ const projectionCenterPresets: { label: string; center: [number, number] }[] = [ // Both map templates are generic: the geography (which base TopoJSON, // projection and frame size) is chosen by the `region` property, defaulting to // 'auto' — infer from the data, preferring the US whenever the data fits it. +// Scope *inference* (`MapScope`, `inferBubbleScope`, `inferChoroplethScope`, +// `semanticScope`, `pickMapScope`) is shared with the Plotly backend's Map / +// Choropleth templates via `chart-types/geo.ts`; only the base-layer geometry +// below (TopoJSON URLs/projections) is Vega-Lite-specific. // --------------------------------------------------------------------------- -type MapScope = 'us' | 'world'; - interface ScopeGeo { url: string; feature: string; @@ -76,73 +81,6 @@ const SCOPE_GEO: Record = { }, }; -// Generous bounding box for the United States (contiguous states + Alaska + -// Hawaii). Used only to *infer* scope: a dataset whose every point falls inside -// is treated as a US map; anything outside flips the whole map to world. -const US_LON: readonly [number, number] = [-170, -66]; -const US_LAT: readonly [number, number] = [18, 72]; - -function inUsBox(lon: number, lat: number): boolean { - return lon >= US_LON[0] && lon <= US_LON[1] && lat >= US_LAT[0] && lat <= US_LAT[1]; -} - -/** Infer scope for a bubble map from its longitude/latitude points. */ -function inferBubbleScope(rows: any[], lonField?: string, latField?: string): MapScope { - if (!lonField || !latField) return 'us'; - for (const r of rows) { - const lon = Number(r[lonField]); - const lat = Number(r[latField]); - if (!Number.isFinite(lon) || !Number.isFinite(lat)) continue; - if (!inUsBox(lon, lat)) return 'world'; - } - return 'us'; -} - -/** Infer scope for a choropleth from its region keys (names / codes / ids). */ -function inferChoroplethScope(rows: any[], idField?: string): MapScope { - if (!idField) return 'us'; - for (const r of rows) { - const v = r[idField]; - if (v == null || v === '') continue; - // A value that resolves as a US state (by name, USPS code, FIPS id, or a - // bare numeric that passes straight through) keeps us in the US; the - // first value that doesn't flips the whole map to world. - if (resolveUsState(v) === undefined) return 'world'; - } - return 'us'; -} - -/** - * Map the id field's *semantic type* to a map scope. This is the most reliable - * signal we have: a field declared 'State' should use the US states map and the - * US-state resolver, a field declared 'Country' the world map and country - * resolver. It disambiguates the codes that collide between the two namespaces - * — "CA" (California vs Canada), "IN" (Indiana vs India), "Georgia" (US state - * vs the country) — which value inference alone cannot. Geographic types that - * neither base layer can render (City, Region, Address, ZipCode) return - * undefined so we fall back to value inference. - */ -const SEMANTIC_SCOPE: Record = { State: 'us', Country: 'world' }; - -function semanticScope(semType: string | undefined): MapScope | undefined { - if (!semType) return undefined; - return Object.prototype.hasOwnProperty.call(SEMANTIC_SCOPE, semType) - ? SEMANTIC_SCOPE[semType] - : undefined; -} - -/** Honor an explicit `region` choice, else the id field's semantic type, else inference. */ -function pickScope( - chartProperties: any, - semScope: MapScope | undefined, - infer: () => MapScope, -): MapScope { - const choice = chartProperties?.region; - if (choice === 'us' || choice === 'world') return choice; - if (semScope) return semScope; - return infer(); -} - /** Would this spec render as a world map? (Drives world-only property gating.) */ function wouldBeWorld(ctx: OptionEvalContext): boolean { const choice = ctx.chartProperties?.region; @@ -224,7 +162,7 @@ export const mapDef: ChartTemplateDef = { const rows = ctx.fullTable ?? ctx.table ?? []; const lonField = ctx.resolvedEncodings.longitude?.field; const latField = ctx.resolvedEncodings.latitude?.field; - const scope = pickScope(ctx.chartProperties, undefined, () => inferBubbleScope(rows, lonField, latField)); + const scope = pickMapScope(ctx.chartProperties, undefined, () => inferBubbleScope(rows, lonField, latField)); configureBubble(spec, scope); applyPointEncodings(spec.layer[1], ctx.resolvedEncodings); @@ -343,7 +281,7 @@ export const choroplethDef: ChartTemplateDef = { const idField = ctx.resolvedEncodings.id?.field; const semType = idField ? toTypeString(ctx.semanticTypes?.[idField]) : ''; const semScope = semanticScope(semType); - const scope = pickScope( + const scope = pickMapScope( ctx.chartProperties, semScope, () => inferChoroplethScope(rows, idField), diff --git a/packages/flint-js/src/vegalite/templates/pie.ts b/packages/flint-js/src/vegalite/templates/pie.ts index b83a771f..d8eb4c3b 100644 --- a/packages/flint-js/src/vegalite/templates/pie.ts +++ b/packages/flint-js/src/vegalite/templates/pie.ts @@ -107,3 +107,8 @@ export const pieChartDef: ChartTemplateDef = { }, ] as ChartPropertyDef[], }; + +export const donutChartDef: ChartTemplateDef = { + ...pieChartDef, + chart: "Donut Chart", +}; diff --git a/packages/flint-js/tests/bump-chartjs.test.ts b/packages/flint-js/tests/bump-chartjs.test.ts new file mode 100644 index 00000000..adf91703 --- /dev/null +++ b/packages/flint-js/tests/bump-chartjs.test.ts @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { describe, it, expect } from 'vitest'; +import { assembleChartjs, assembleECharts, assembleVegaLite, cjsGetTemplateDef } from '../src'; + +const RANK_DATA = [ + { season: 'S1', rank: 1, team: 'Ferrari' }, + { season: 'S2', rank: 3, team: 'Ferrari' }, + { season: 'S3', rank: 2, team: 'Ferrari' }, + { season: 'S1', rank: 2, team: 'McLaren' }, + { season: 'S2', rank: 1, team: 'McLaren' }, + { season: 'S3', rank: 3, team: 'McLaren' }, + { season: 'S1', rank: 3, team: 'RedBull' }, + { season: 'S2', rank: 2, team: 'RedBull' }, + { season: 'S3', rank: 1, team: 'RedBull' }, +]; + +function rankInput() { + return { + data: { values: RANK_DATA }, + semantic_types: { season: 'Category', rank: 'Rank', team: 'Name' }, + chart_spec: { + chartType: 'Bump Chart', + encodings: { x: { field: 'season' }, y: { field: 'rank' }, color: { field: 'team' } }, + baseSize: { width: 420, height: 280 }, + }, + }; +} + +describe('Chart.js Bump Chart', () => { + it('is registered in the Chart.js template registry', () => { + expect(cjsGetTemplateDef('Bump Chart')).toBeDefined(); + }); + + it('builds one line dataset per series over the shared category axis', () => { + const config = assembleChartjs(rankInput()) as any; + expect(config.type).toBe('line'); + expect(config.data.labels).toEqual(['S1', 'S2', 'S3']); + expect(config.data.datasets).toHaveLength(3); + expect(config.data.datasets.map((d: any) => d.label)).toEqual(['Ferrari', 'McLaren', 'RedBull']); + expect(config.data.datasets[0].data).toEqual([1, 3, 2]); + expect(config.options.plugins.legend.display).toBe(true); + }); + + it('reverses the rank axis so rank 1 sits on top, pinned to [1, maxRank]', () => { + const config = assembleChartjs(rankInput()) as any; + const y = config.options.scales.y; + expect(y.reverse).toBe(true); + expect(y.min).toBe(1); + expect(y.max).toBe(3); + expect(y.beginAtZero).toBeUndefined(); + }); + + it('keeps a plain value axis when y is not rank-like', () => { + const config = assembleChartjs({ + data: { values: RANK_DATA.map(d => ({ ...d, points: d.rank * 10 })) }, + semantic_types: { season: 'Category', points: 'Quantity', team: 'Name' }, + chart_spec: { + chartType: 'Bump Chart', + encodings: { x: { field: 'season' }, y: { field: 'points' }, color: { field: 'team' } }, + baseSize: { width: 420, height: 280 }, + }, + }) as any; + expect(config.options.scales.y.reverse).toBeUndefined(); + expect(config.options.scales.y.min).toBeUndefined(); + }); + + it('stays pure JSON for the discrete-x rank case (no live functions)', () => { + const config = assembleChartjs(rankInput()) as any; + const roundTripped = JSON.parse(JSON.stringify(config)); + expect(roundTripped).toEqual(config); + }); + + it('compiles the same input on all three backends', () => { + const input = rankInput(); + expect(() => assembleVegaLite(input)).not.toThrow(); + expect(() => assembleECharts(input)).not.toThrow(); + expect(() => assembleChartjs(input)).not.toThrow(); + }); +}); diff --git a/packages/flint-js/tests/excel-codegen.test.ts b/packages/flint-js/tests/excel-codegen.test.ts new file mode 100644 index 00000000..36206977 --- /dev/null +++ b/packages/flint-js/tests/excel-codegen.test.ts @@ -0,0 +1,61 @@ +import { describe, expect, it } from 'vitest'; +import { generateOfficeJs, prepareExcelArtifact } from '../src/excel'; +import type { ExcelNativeChartSpec } from '../src/excel'; + +const funnelArtifact: ExcelNativeChartSpec = { + schema: 'flint.excel.chart/v1', + kind: 'chart', + chartType: 'Funnel', + seriesBy: 'Columns', + title: 'Amount by Stage', + data: [['Stage', 'Amount'], ['Prospects', 500], ['Qualified', 425]], + dataLabels: { + visible: true, + numberFormat: '#,##0', + fontColor: '#FFFFFF', + fontSize: 11, + }, + seriesFormats: [{ color: '#4472C4' }], + width: 480, + height: 320, +}; + +describe('Excel Office.js artifacts', () => { + it('prepares a versioned artifact without legacy coercion', () => { + expect(prepareExcelArtifact(funnelArtifact)).toMatchObject({ + chartType: 'Funnel', + rangeA1: 'A1:B3', + rows: 3, + columns: 2, + hasAxes: false, + }); + expect(() => prepareExcelArtifact({ ...funnelArtifact, chartType: 'funnel' })).toThrow( + 'Unsupported Excel chart type: funnel.', + ); + expect(() => prepareExcelArtifact({ ...funnelArtifact, schema: undefined })).toThrow( + 'Expected a flint.excel.chart/v1 chart artifact.', + ); + }); + + it('generates standalone Office.js with artifact formatting', () => { + const generated = generateOfficeJs(funnelArtifact, { scale: 2 }); + expect(generated.meta).toEqual({ + schema: 'flint.excel.chart/v1', + rangeA1: 'A1:B3', + chartType: 'Funnel', + rows: 3, + columns: 2, + }); + expect(generated.code).toContain('sheet.charts.add("Funnel", dataRange, "Columns")'); + expect(generated.code).toContain('chart.dataLabels.format.font.color = "#FFFFFF"'); + expect(generated.code).toContain('chart.series.getItemAt(index)'); + expect(generated.code).toContain('chart.getImage(1280, 853, Excel.ImageFittingMode.fit)'); + expect(() => new Function('Excel', `${generated.code}\nreturn main;`)).not.toThrow(); + }); + + it('keeps host options out of the serialized artifact', () => { + generateOfficeJs(funnelArtifact, { scale: 4, cleanWorksheet: true }); + expect(funnelArtifact).not.toHaveProperty('scale'); + expect(funnelArtifact).not.toHaveProperty('cleanWorksheet'); + }); +}); diff --git a/packages/flint-js/tests/excel-runtime.test.ts b/packages/flint-js/tests/excel-runtime.test.ts new file mode 100644 index 00000000..70b4efb4 --- /dev/null +++ b/packages/flint-js/tests/excel-runtime.test.ts @@ -0,0 +1,124 @@ +import { describe, expect, it, vi } from 'vitest'; +import { renderExcelChart, type OfficeJsExcelApi } from '../src/excel'; +import type { ExcelNativeChartSpec } from '../src/excel'; + +function createMockExcel() { + const calls = { + chartType: '', + seriesBy: '', + rangeAddress: '', + values: null as unknown, + numberFormat: null as unknown, + image: null as unknown, + labels: {} as Record, + fillColor: '', + clears: 0, + syncs: 0, + }; + const series = { + format: { + fill: { setSolidColor: (color: string) => { calls.fillColor = color; } }, + line: {}, + }, + }; + const chart = { + series: { getItemAt: () => series }, + title: {}, + legend: {}, + dataLabels: { + format: { font: {} }, + set visible(value: boolean) { calls.labels.visible = value; }, + set position(value: string) { calls.labels.position = value; }, + set numberFormat(value: string) { calls.labels.numberFormat = value; }, + }, + axes: {}, + getImage: (width: number, height: number, mode: unknown) => { + calls.image = { width, height, mode }; + return { value: 'iVBORw0KGgoMOCK' }; + }, + }; + Object.defineProperties(chart.dataLabels.format.font, { + color: { set: (value: string) => { calls.labels.fontColor = value; } }, + size: { set: (value: number) => { calls.labels.fontSize = value; } }, + }); + const range = { + set values(value: unknown) { calls.values = value; }, + set numberFormat(value: unknown) { calls.numberFormat = value; }, + }; + const sheet = { + charts: { + items: [], + load: vi.fn(), + add: (chartType: string, _range: unknown, seriesBy: string) => { + calls.chartType = chartType; + calls.seriesBy = seriesBy; + return chart; + }, + }, + getUsedRangeOrNullObject: () => ({ + isNullObject: false, + clear: () => { calls.clears += 1; }, + }), + getRange: (address: string) => { + calls.rangeAddress = address; + return range; + }, + }; + const run = vi.fn(async (callback: (context: unknown) => Promise) => callback({ + workbook: { worksheets: { getActiveWorksheet: () => sheet } }, + sync: async () => { calls.syncs += 1; }, + })); + const excel = { + run, + ImageFittingMode: { fit: 'fit' }, + } as OfficeJsExcelApi; + return { excel, calls, run }; +} + +const artifact: ExcelNativeChartSpec = { + schema: 'flint.excel.chart/v1', + kind: 'chart', + chartType: 'Funnel', + seriesBy: 'Columns', + title: 'Amount by Stage', + data: [['Stage', 'Amount'], ['Prospects', 500], ['Qualified', 425]], + dataLabels: { + visible: true, + numberFormat: '#,##0', + fontColor: '#FFFFFF', + fontSize: 11, + }, + seriesFormats: [{ color: '#4472C4' }], + width: 480, + height: 320, +}; + +describe('renderExcelChart', () => { + it('executes a Flint artifact against the Office.js object model', async () => { + const { excel, calls } = createMockExcel(); + const result = await renderExcelChart(excel, artifact, { scale: 2 }); + + expect(calls.rangeAddress).toBe('A1:B3'); + expect(calls.values).toEqual(artifact.data); + expect(calls.chartType).toBe('Funnel'); + expect(calls.seriesBy).toBe('Columns'); + expect(calls.labels).toEqual({ + visible: true, + numberFormat: '#,##0', + fontColor: '#FFFFFF', + fontSize: 11, + }); + expect(calls.fillColor).toBe('#4472C4'); + expect(calls.image).toEqual({ width: 1280, height: 853, mode: 'fit' }); + expect(calls.clears).toBe(1); + expect(result).toEqual({ pngBase64: 'iVBORw0KGgoMOCK', inspection: null }); + }); + + it('rejects invalid artifacts before entering Excel.run', async () => { + const { excel, run } = createMockExcel(); + await expect(renderExcelChart(excel, { ...artifact, chartType: 'funnel' })).rejects.toThrow( + 'Unsupported Excel chart type: funnel.', + ); + expect(run).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/flint-js/tests/facet-columns.test.ts b/packages/flint-js/tests/facet-columns.test.ts new file mode 100644 index 00000000..61e85236 --- /dev/null +++ b/packages/flint-js/tests/facet-columns.test.ts @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * The `facetColumns` chart property: an interactive control that overrides the + * auto-computed number of facet columns for a column-wrapped facet. It is a + * LAYOUT-level option (read raw off chart_spec.chartProperties, honored by + * every backend's assembler via effectiveOptions.facetColumns) rather than a + * per-template mark property. + */ + +import { describe, it, expect } from 'vitest'; +import { assembleVegaLite, assemblePlotly, getChartOptions } from '../src'; + +const REGIONS = ['N', 'S', 'E', 'W', 'C', 'Co', 'NE', 'SW']; +const MONTHS = ['Jan', 'Feb', 'Mar']; + +function facetedRows() { + const rows: any[] = []; + for (const r of REGIONS) for (const m of MONTHS) rows.push({ Region: r, Month: m, Sales: 50 }); + return rows; +} + +function makeInput(facetColumns?: number) { + return { + data: { values: facetedRows() }, + semantic_types: { Region: 'Category', Month: 'Category', Sales: 'Quantity' }, + chart_spec: { + chartType: 'Bar Chart', + encodings: { x: 'Month', y: 'Sales', column: 'Region' }, + baseSize: { width: 600, height: 400 }, + ...(facetColumns != null ? { chartProperties: { facetColumns } } : {}), + }, + } as any; +} + +/** Count the distinct facet-column positions in a Plotly figure's xaxis domains. */ +function plotlyColumnCount(spec: any): number { + const lefts = Object.keys(spec.layout) + .filter((k) => /^xaxis/.test(k)) + .map((k) => spec.layout[k].domain?.[0]) + .filter((v: any) => v != null) + .map((v: number) => +v.toFixed(3)); + return new Set(lefts).size; +} + +describe('facetColumns property', () => { + it('surfaces as a getChartOptions control for a column-wrapped facet', () => { + const opt = getChartOptions(makeInput()).find((o) => o.key === 'facetColumns'); + expect(opt).toBeTruthy(); + expect(opt!.applicable).toBe(true); + expect((opt as any).type).toBe('continuous'); + expect((opt as any).min).toBe(1); + expect((opt as any).max).toBe(REGIONS.length); + // Default (no override) seeds from the auto grid — all 8 fit in one row. + expect(opt!.value).toBe(REGIONS.length); + }); + + it('is NOT offered without a column facet', () => { + const noFacet = { + data: { values: [{ Month: 'Jan', Sales: 1 }, { Month: 'Feb', Sales: 2 }] }, + semantic_types: { Month: 'Category', Sales: 'Quantity' }, + chart_spec: { chartType: 'Bar Chart', encodings: { x: 'Month', y: 'Sales' } }, + } as any; + expect(getChartOptions(noFacet).find((o) => o.key === 'facetColumns')).toBeUndefined(); + }); + + it('overrides the Vega-Lite facet column count', () => { + const auto = assembleVegaLite(makeInput()) as any; + expect(auto.encoding.facet.columns).toBe(REGIONS.length); // one row + + expect((assembleVegaLite(makeInput(2)) as any).encoding.facet.columns).toBe(2); + expect((assembleVegaLite(makeInput(3)) as any).encoding.facet.columns).toBe(3); + // Clamped to the distinct column count. + expect((assembleVegaLite(makeInput(99)) as any).encoding.facet.columns).toBe(REGIONS.length); + }); + + it('overrides the Plotly facet grid column count (canvas grows with rows)', () => { + expect(plotlyColumnCount(assemblePlotly(makeInput()))).toBe(REGIONS.length); + expect(plotlyColumnCount(assemblePlotly(makeInput(2)))).toBe(2); + expect(plotlyColumnCount(assemblePlotly(makeInput(3)))).toBe(3); + }); +}); diff --git a/packages/flint-js/tests/filter-overflow.test.ts b/packages/flint-js/tests/filter-overflow.test.ts new file mode 100644 index 00000000..4f828c61 --- /dev/null +++ b/packages/flint-js/tests/filter-overflow.test.ts @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { describe, expect, it } from 'vitest'; +import { filterOverflow } from '../src/core/filter-overflow'; +import type { ChannelSemantics, ChartEncoding } from '../src/core/types'; + +const budgets = { maxValues: { x: 3 } }; +const marks = new Set(['bar']); +const annotation = { semanticType: 'Category' }; + +function keptCategories( + data: Array<{ Category: string; Value: number }>, + categorySemantics: Omit, + categoryEncoding: ChartEncoding, +): string[] { + const result = filterOverflow( + { + x: { semanticAnnotation: annotation, ...categorySemantics }, + y: { field: 'Value', type: 'quantitative', semanticAnnotation: { semanticType: 'Quantity' } }, + }, + { axisFlags: { x: { banded: true } } }, + { + x: categoryEncoding, + y: { field: 'Value' }, + }, + data, + budgets, + marks, + ); + return result.truncations[0].keptValues as string[]; +} + +describe('overflow category selection', () => { + it('preserves encounter order when no sort is selected', () => { + const data = [ + { Category: 'Delta', Value: 100 }, + { Category: 'Alpha', Value: 1 }, + { Category: 'Charlie', Value: 80 }, + { Category: 'Bravo', Value: 50 }, + ]; + + expect(keptCategories( + data, + { field: 'Category', type: 'nominal' }, + { field: 'Category' }, + )).toEqual(['Delta', 'Alpha', 'Charlie']); + }); + + it('uses canonical semantic order when available', () => { + const data = [ + { Category: 'Mar', Value: 100 }, + { Category: 'Jan', Value: 1 }, + { Category: 'Apr', Value: 80 }, + { Category: 'Feb', Value: 50 }, + ]; + + expect(keptCategories( + data, + { field: 'Category', type: 'ordinal', ordinalSortOrder: ['Jan', 'Feb', 'Mar', 'Apr'] }, + { field: 'Category' }, + )).toEqual(['Jan', 'Feb', 'Mar']); + }); + + it('uses an explicitly selected value sort', () => { + const data = [ + { Category: 'Delta', Value: 100 }, + { Category: 'Alpha', Value: 1 }, + { Category: 'Charlie', Value: 80 }, + { Category: 'Bravo', Value: 50 }, + ]; + + expect(keptCategories( + data, + { field: 'Category', type: 'nominal' }, + { field: 'Category', sortBy: 'y', sortOrder: 'descending' }, + )).toEqual(['Delta', 'Charlie', 'Bravo']); + }); +}); diff --git a/packages/flint-js/tests/heatmap-colors.test.ts b/packages/flint-js/tests/heatmap-colors.test.ts index 497cf4d2..0c29a623 100644 --- a/packages/flint-js/tests/heatmap-colors.test.ts +++ b/packages/flint-js/tests/heatmap-colors.test.ts @@ -2,7 +2,7 @@ // Licensed under the MIT License. import { describe, expect, it } from 'vitest'; -import { assembleECharts, assembleVegaLite } from '../src'; +import { assembleECharts, assembleExcel, assembleVegaLite } from '../src'; const HEATMAP_DATA = [ { day: 'Mon', hour: '09:00', value: 1 }, @@ -50,6 +50,18 @@ function divergingHeatmapInput() { } describe('heatmap color defaults', () => { + it('rejects heatmaps because Office.js has no native heatmap chart type', () => { + expect(() => assembleExcel(heatmapInput())).toThrow( + 'Excel backend does not support chart type "Heatmap" as a native Office.js chart.', + ); + }); + + it('also rejects diverging heatmaps rather than emulating a color scale', () => { + expect(() => assembleExcel(divergingHeatmapInput())).toThrow( + 'Excel backend does not support chart type "Heatmap" as a native Office.js chart.', + ); + }); + it('uses blues for non-diverging Vega-Lite heatmaps by default', () => { const spec = assembleVegaLite(heatmapInput()) as any; diff --git a/packages/flint-js/tests/plotly-backend.test.ts b/packages/flint-js/tests/plotly-backend.test.ts new file mode 100644 index 00000000..5c06a4f4 --- /dev/null +++ b/packages/flint-js/tests/plotly-backend.test.ts @@ -0,0 +1,226 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { describe, it, expect } from 'vitest'; +import { assemblePlotly, plGetTemplateDef, plAllTemplateDefs } from '../src'; +import { genPlotlyCoreTests, genPlotlyFacetTests } from '../src/test-data'; + +const SALES = [ + { region: 'East', revenue: 168 }, + { region: 'South', revenue: 167 }, + { region: 'North', revenue: 145 }, +]; + +const GROUPED = [ + { region: 'East', revenue: 168, year: '2024' }, + { region: 'South', revenue: 167, year: '2024' }, + { region: 'East', revenue: 120, year: '2025' }, + { region: 'South', revenue: 131, year: '2025' }, +]; + +const CARS = [ + { weight: 1.6, mpg: 32, origin: 'JP' }, + { weight: 2.1, mpg: 27, origin: 'US' }, + { weight: 1.9, mpg: 29, origin: 'EU' }, +]; + +const MONTHLY = [ + { month: '2025-01', value: 12 }, + { month: '2025-02', value: 18 }, + { month: '2025-03', value: 15 }, +]; + +function input(chartType: string, encodings: Record, values: any[], semantic_types: Record, chartProperties?: Record) { + return { + data: { values }, + semantic_types, + chart_spec: { chartType, encodings, baseSize: { width: 400, height: 300 }, ...(chartProperties ? { chartProperties } : {}) }, + } as any; +} + +/** Recursively assert a value contains no functions (pure JSON). */ +function assertNoFunctions(node: any, path = '$'): void { + if (typeof node === 'function') { + throw new Error(`function found at ${path}`); + } + if (node && typeof node === 'object') { + for (const [k, v] of Object.entries(node)) { + assertNoFunctions(v, `${path}.${k}`); + } + } +} + +describe('Plotly backend', () => { + it('registers the acceptance templates plus the expressive tranche', () => { + const charts = plAllTemplateDefs.map(t => t.chart).sort(); + expect(charts).toEqual([...new Set(charts)]); // no duplicate registrations + for (const acceptance of ['Area Chart', 'Bar Chart', 'Line Chart', 'Scatter Plot']) { + expect(charts).toContain(acceptance); + } + expect(charts.length).toBeGreaterThanOrEqual(30); + expect(plGetTemplateDef('Bar Chart')).toBeDefined(); + }); + + it('throws on an unregistered chart type', () => { + expect(() => + assemblePlotly(input('Sankey Diagram *', { x: { field: 'region' }, y: { field: 'revenue' } }, SALES, { region: 'Region', revenue: 'Amount' })), + ).toThrow(/Unknown Plotly chart type/); + }); + + it('bar: builds a bar trace with category order and zero baseline', () => { + const fig = assemblePlotly(input('Bar Chart', { x: { field: 'region' }, y: { field: 'revenue' } }, SALES, { region: 'Region', revenue: 'Amount' })); + expect(fig.data).toHaveLength(1); + expect(fig.data[0].type).toBe('bar'); + expect(fig.data[0].x).toEqual(['East', 'South', 'North']); + expect(fig.data[0].y).toEqual([168, 167, 145]); + expect(fig.layout.xaxis.type).toBe('category'); + expect(fig.layout.yaxis.rangemode).toBe('tozero'); + expect(fig.layout.bargap).toBe(0.2); + expect(fig.layout.xaxis.tickangle).toBe(0); + expect(fig.layout.width).toBeGreaterThan(0); + expect(fig.layout.height).toBeGreaterThan(0); + }); + + it('bar: transposes to horizontal when the category is on y', () => { + const fig = assemblePlotly(input('Bar Chart', { x: { field: 'revenue' }, y: { field: 'region' } }, SALES, { region: 'Region', revenue: 'Amount' })); + expect(fig.data[0].orientation).toBe('h'); + expect(fig.data[0].y).toEqual(['East', 'South', 'North']); + expect(fig.layout.xaxis.rangemode).toBe('tozero'); + }); + + it('bar: horizontal over time — quantitative x on the value axis, temporal y as the band', () => { + // Regression: a temporal y-axis is a band (bars per period), not the value + // axis. detectAxes must put the quantity on x, the dates on y — else the + // bars are null (empty chart). + const rows = [ + { amount: 166, when: '2024-01-15' }, + { amount: 268, when: '2024-02-15' }, + { amount: 128, when: '2024-03-15' }, + ]; + const fig = assemblePlotly(input('Bar Chart', { x: { field: 'amount' }, y: { field: 'when' } }, rows, { amount: 'Amount', when: 'Date' })); + expect(fig.data[0].orientation).toBe('h'); + expect(fig.data[0].x).toEqual([166, 268, 128]); + expect(fig.data[0].y.every((v: unknown) => v != null)).toBe(true); + }); + + it('line: one trace per color group with legend on', () => { + const fig = assemblePlotly(input('Line Chart', { x: { field: 'region' }, y: { field: 'revenue' }, color: { field: 'year' } }, GROUPED, { region: 'Region', revenue: 'Amount', year: 'Year' })); + expect(fig.data).toHaveLength(2); + expect(fig.data.map((t: any) => t.name)).toEqual(['2024', '2025']); + expect(fig.data[0].mode).toBe('lines'); + expect(fig.layout.showlegend).toBe(true); + }); + + it('line: temporal x uses a native date axis with ISO values', () => { + const fig = assemblePlotly(input('Line Chart', { x: { field: 'month' }, y: { field: 'value' } }, MONTHLY, { month: 'YearMonth', value: 'Amount' })); + expect(fig.layout.xaxis.type).toBe('date'); + expect(typeof fig.data[0].x[0]).toBe('string'); + expect(fig.data[0].x[0]).toMatch(/^\d{4}-\d{2}-\d{2}T/); + }); + + it('area: stacked color groups use stackgroup; single series fills to zero', () => { + const grouped = assemblePlotly(input('Area Chart', { x: { field: 'region' }, y: { field: 'revenue' }, color: { field: 'year' } }, GROUPED, { region: 'Region', revenue: 'Amount', year: 'Year' })); + expect(grouped.data.every((t: any) => t.stackgroup === 'one')).toBe(true); + + const single = assemblePlotly(input('Area Chart', { x: { field: 'region' }, y: { field: 'revenue' } }, SALES, { region: 'Region', revenue: 'Amount' })); + expect(single.data[0].fill).toBe('tozeroy'); + }); + + it('scatter: markers mode, per-group traces, no forced zero for open measures', () => { + const fig = assemblePlotly(input('Scatter Plot', { x: { field: 'weight' }, y: { field: 'mpg' }, color: { field: 'origin' } }, CARS, { weight: 'Quantity', mpg: 'Quantity', origin: 'Country' })); + expect(fig.data).toHaveLength(3); + expect(fig.data[0].mode).toBe('markers'); + expect(fig.data[0].marker.size).toBeGreaterThan(0); + }); + + it('column facet: one axis pair per panel, shared nice y-range, headers', () => { + const fig = assemblePlotly(input('Bar Chart', { x: { field: 'region' }, y: { field: 'revenue' }, column: { field: 'year' } }, GROUPED, { region: 'Region', revenue: 'Amount', year: 'Year' })); + expect(fig._facet).toBe(true); + expect(fig._facetCols).toBe(2); + expect(fig.layout.xaxis2).toBeDefined(); + expect(fig.layout.yaxis2).toBeDefined(); + expect(fig.layout.yaxis.range).toEqual(fig.layout.yaxis2.range); + expect(fig.layout.yaxis.range[0]).toBe(0); // Amount forces zero into the shared domain + expect(fig.layout.yaxis2.showticklabels).toBe(false); // leftmost-only y labels + const headerTexts = fig.layout.annotations.map((a: any) => a.text); + expect(headerTexts).toContain('2024'); + expect(headerTexts).toContain('2025'); + expect(fig.data.every((t: any) => t.xaxis && t.yaxis)).toBe(true); + }); + + it('row facet: stacked panels with rotated row headers', () => { + const fig = assemblePlotly(input('Line Chart', { x: { field: 'region' }, y: { field: 'revenue' }, row: { field: 'year' } }, GROUPED, { region: 'Region', revenue: 'Amount', year: 'Year' })); + expect(fig._facet).toBe(true); + expect(fig._facetRows).toBe(2); + expect(fig._facetCols).toBe(1); + const rowHeaders = fig.layout.annotations.filter((a: any) => a.textangle === 90); + expect(rowHeaders.map((a: any) => a.text)).toEqual(['2024', '2025']); + // x title only on the bottom row + expect(fig.layout.xaxis.title).toBeUndefined(); + expect(fig.layout.xaxis2.title).toBeDefined(); + }); + + it('column+row facet: full grid with one axis pair per cell', () => { + const CELLS = [ + { v: 1, w: 10, a: 'A', b: 'X' }, { v: 2, w: 20, a: 'B', b: 'X' }, + { v: 3, w: 30, a: 'A', b: 'Y' }, { v: 4, w: 40, a: 'B', b: 'Y' }, + ]; + const fig = assemblePlotly(input('Scatter Plot', { x: { field: 'v' }, y: { field: 'w' }, column: { field: 'a' }, row: { field: 'b' } }, CELLS, { v: 'Quantity', w: 'Quantity', a: 'Category', b: 'Category' })); + expect(fig._facetRows).toBe(2); + expect(fig._facetCols).toBe(2); + expect(fig.layout.xaxis4).toBeDefined(); + expect(fig.layout.yaxis4).toBeDefined(); + }); + + it('facet legend is deduped across panels via legendgroup', () => { + const fig = assemblePlotly(input('Line Chart', { x: { field: 'region' }, y: { field: 'revenue' }, color: { field: 'year' }, column: { field: 'year' } }, GROUPED, { region: 'Region', revenue: 'Amount', year: 'Year' })); + const shown = fig.data.filter((t: any) => t.showlegend); + const names = new Set(fig.data.map((t: any) => t.name)); + expect(shown.length).toBe(names.size); + expect(fig.data.every((t: any) => t.legendgroup === t.name)).toBe(true); + }); + + it('diverging vs categorical semantics pick different scheme families', () => { + const TEMP = [ + { city: 'Oslo', temp: -6 }, { city: 'Rome', temp: 14 }, { city: 'Cairo', temp: 24 }, + ]; + const diverging = assemblePlotly(input('Bar Chart', { x: { field: 'city' }, y: { field: 'temp' }, color: { field: 'temp' } }, TEMP, { city: 'City', temp: 'Temperature' })); + const categorical = assemblePlotly(input('Scatter Plot', { x: { field: 'weight' }, y: { field: 'mpg' }, color: { field: 'origin' } }, CARS, { weight: 'Quantity', mpg: 'Quantity', origin: 'Country' })); + // Categorical grouping draws from the plotly10 qualitative palette… + expect(categorical.data[0].marker.color).toBe('#636efa'); + // …while a diverging measure on color routes to the RdBu ramp. + expect(diverging.data[0].marker.color).toBe('#b2182b'); + }); + + it('every dedicated generator case assembles cleanly', () => { + for (const tc of [...genPlotlyCoreTests(), ...genPlotlyFacetTests()]) { + const encodings = Object.fromEntries( + Object.entries(tc.encodingMap).map(([ch, e]: [string, any]) => [ch, { field: e.fieldID }]), + ); + const semantic_types = Object.fromEntries( + Object.entries(tc.metadata).map(([f, m]: [string, any]) => [f, m.semanticType]), + ); + const fig = assemblePlotly({ + data: { values: tc.data }, + semantic_types, + chart_spec: { chartType: tc.chartType, encodings }, + } as any); + expect(Array.isArray(fig.data), tc.title).toBe(true); + expect(fig.data.length, tc.title).toBeGreaterThan(0); + } + }); + + it('figures are pure JSON for all four templates', () => { + const figures = [ + assemblePlotly(input('Bar Chart', { x: { field: 'region' }, y: { field: 'revenue' } }, SALES, { region: 'Region', revenue: 'Amount' })), + assemblePlotly(input('Line Chart', { x: { field: 'month' }, y: { field: 'value' } }, MONTHLY, { month: 'YearMonth', value: 'Amount' })), + assemblePlotly(input('Area Chart', { x: { field: 'region' }, y: { field: 'revenue' }, color: { field: 'year' } }, GROUPED, { region: 'Region', revenue: 'Amount', year: 'Year' })), + assemblePlotly(input('Scatter Plot', { x: { field: 'weight' }, y: { field: 'mpg' } }, CARS, { weight: 'Quantity', mpg: 'Quantity' })), + assemblePlotly(input('Bar Chart', { x: { field: 'region' }, y: { field: 'revenue' }, column: { field: 'year' } }, GROUPED, { region: 'Region', revenue: 'Amount', year: 'Year' })), + ]; + for (const fig of figures) { + assertNoFunctions(fig); + expect(JSON.parse(JSON.stringify(fig))).toEqual(fig); + } + }); +}); diff --git a/packages/flint-js/tests/plotly-expressive.test.ts b/packages/flint-js/tests/plotly-expressive.test.ts new file mode 100644 index 00000000..de631853 --- /dev/null +++ b/packages/flint-js/tests/plotly-expressive.test.ts @@ -0,0 +1,280 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Tests for the Plotly "expressive tranche" — the 29 chart types added beyond + * the four original acceptance templates (Bar, Line, Area, Scatter; see + * plotly-backend.test.ts). Covers native-trace shape assertions, grouping / + * stacking, facet-exemption for axis-less charts, and targeted regression + * tests for bugs found and fixed during visual (VLM) verification. + */ + +import { describe, it, expect } from 'vitest'; +import { assemblePlotly, plAllTemplateDefs, plGetTemplateDef } from '../src'; + +function input(chartType: string, encodings: Record, values: any[], semantic_types: Record, chartProperties?: Record) { + return { + data: { values }, + semantic_types, + chart_spec: { chartType, encodings, baseSize: { width: 400, height: 300 }, ...(chartProperties ? { chartProperties } : {}) }, + } as any; +} + +/** Recursively assert a value contains no functions (pure JSON, serializable). */ +function assertNoFunctions(node: any, path = '$'): void { + if (typeof node === 'function') throw new Error(`function found at ${path}`); + if (node && typeof node === 'object') { + for (const [k, v] of Object.entries(node)) assertNoFunctions(v, `${path}.${k}`); + } +} + +const SALES = [ + { region: 'East', revenue: 168, year: '2024' }, + { region: 'South', revenue: 167, year: '2024' }, + { region: 'East', revenue: 120, year: '2025' }, + { region: 'South', revenue: 131, year: '2025' }, +]; + +describe('Plotly expressive templates — registration', () => { + it('every registered template assembles a pure-JSON figure with at least one trace', () => { + const smokeInputs: Record = { + 'Grouped Bar Chart': input('Grouped Bar Chart', { x: { field: 'region' }, y: { field: 'revenue' }, color: { field: 'year' } }, SALES, { region: 'Region', revenue: 'Amount', year: 'Year' }), + 'Stacked Bar Chart': input('Stacked Bar Chart', { x: { field: 'region' }, y: { field: 'revenue' }, color: { field: 'year' } }, SALES, { region: 'Region', revenue: 'Amount', year: 'Year' }), + 'Pyramid Chart': input('Pyramid Chart', { x: { field: 'revenue' }, y: { field: 'region' }, color: { field: 'year' } }, SALES, { region: 'Region', revenue: 'Amount', year: 'Year' }), + 'Histogram': input('Histogram', { x: { field: 'revenue' } }, SALES, { revenue: 'Amount' }), + 'Boxplot': input('Boxplot', { x: { field: 'region' }, y: { field: 'revenue' } }, SALES, { region: 'Region', revenue: 'Amount' }), + 'Violin Plot': input('Violin Plot', { x: { field: 'region' }, y: { field: 'revenue' } }, SALES, { region: 'Region', revenue: 'Amount' }), + 'Density Plot': input('Density Plot', { x: { field: 'revenue' } }, SALES, { revenue: 'Amount' }), + 'ECDF Plot': input('ECDF Plot', { x: { field: 'revenue' } }, SALES, { revenue: 'Amount' }), + 'Strip Plot': input('Strip Plot', { x: { field: 'region' }, y: { field: 'revenue' } }, SALES, { region: 'Region', revenue: 'Amount' }), + 'Connected Scatter Plot': input('Connected Scatter Plot', { x: { field: 'revenue' }, y: { field: 'revenue' } }, SALES, { revenue: 'Amount' }), + 'Range Area Chart': input('Range Area Chart', { x: { field: 'region' }, y: { field: 'revenue' }, y2: { field: 'revenue' } }, SALES, { region: 'Region', revenue: 'Amount' }), + 'Streamgraph': input('Streamgraph', { x: { field: 'region' }, y: { field: 'revenue' }, color: { field: 'year' } }, SALES, { region: 'Region', revenue: 'Amount', year: 'Year' }), + 'Slope Chart': input('Slope Chart', { x: { field: 'year' }, y: { field: 'revenue' }, color: { field: 'region' } }, SALES, { year: 'Year', revenue: 'Amount', region: 'Region' }), + 'Bump Chart': input('Bump Chart', { x: { field: 'year' }, y: { field: 'revenue' }, color: { field: 'region' } }, SALES, { year: 'Year', revenue: 'Amount', region: 'Region' }), + 'Waterfall Chart': input('Waterfall Chart', { x: { field: 'region' }, y: { field: 'revenue' } }, SALES, { region: 'Region', revenue: 'Amount' }), + 'Candlestick Chart': input('Candlestick Chart', { x: { field: 'region' }, open: { field: 'revenue' }, close: { field: 'revenue' } }, SALES, { region: 'Region', revenue: 'Amount' }), + 'Heatmap': input('Heatmap', { x: { field: 'region' }, y: { field: 'year' }, color: { field: 'revenue' } }, SALES, { region: 'Region', year: 'Year', revenue: 'Amount' }), + 'Density Contour': input('Density Contour', { x: { field: 'revenue' }, y: { field: 'revenue' } }, SALES, { revenue: 'Amount' }), + 'Lollipop Chart': input('Lollipop Chart', { x: { field: 'region' }, y: { field: 'revenue' } }, SALES, { region: 'Region', revenue: 'Amount' }), + 'Bullet Chart': input('Bullet Chart', { y: { field: 'region' }, x: { field: 'revenue' } }, SALES, { region: 'Region', revenue: 'Amount' }), + 'Gantt Chart': input('Gantt Chart', { y: { field: 'region' }, x: { field: 'revenue' }, x2: { field: 'revenue' } }, SALES, { region: 'Region', revenue: 'Amount' }), + 'Ranged Dot Plot': input('Ranged Dot Plot', { x: { field: 'revenue' }, y: { field: 'region' } }, SALES, { region: 'Region', revenue: 'Amount' }), + 'Regression': input('Regression', { x: { field: 'revenue' }, y: { field: 'revenue' } }, SALES, { revenue: 'Amount' }), + 'Pie Chart': input('Pie Chart', { color: { field: 'region' }, size: { field: 'revenue' } }, SALES, { region: 'Region', revenue: 'Amount' }), + 'Donut Chart': input('Donut Chart', { color: { field: 'region' }, size: { field: 'revenue' } }, SALES, { region: 'Region', revenue: 'Amount' }), + 'Radar Chart': input('Radar Chart', { x: { field: 'region' }, y: { field: 'revenue' } }, SALES, { region: 'Region', revenue: 'Amount' }), + 'Rose Chart': input('Rose Chart', { x: { field: 'region' }, y: { field: 'revenue' } }, SALES, { region: 'Region', revenue: 'Amount' }), + 'Funnel Chart': input('Funnel Chart', { y: { field: 'region' }, size: { field: 'revenue' } }, SALES, { region: 'Region', revenue: 'Amount' }), + 'Gauge Chart': input('Gauge Chart', { size: { field: 'revenue' } }, SALES, { revenue: 'Amount' }), + 'KPI Card': input('KPI Card', { metric: { field: 'region' }, value: { field: 'revenue' } }, SALES, { region: 'Region', revenue: 'Amount' }), + 'Map': input('Map', { longitude: { field: 'lon' }, latitude: { field: 'lat' }, size: { field: 'revenue' } }, + [{ lon: -74.0, lat: 40.7, revenue: 168 }, { lon: -87.6, lat: 41.9, revenue: 120 }, { lon: -122.4, lat: 37.8, revenue: 90 }], + { lon: 'Longitude', lat: 'Latitude', revenue: 'Amount' }), + 'Choropleth': input('Choropleth', { id: { field: 'state' }, color: { field: 'revenue' } }, + [{ state: 'California', revenue: 168 }, { state: 'Texas', revenue: 120 }, { state: 'New York', revenue: 90 }], + { state: 'State', revenue: 'Amount' }), + 'Sparkline': input('Sparkline', { x: { field: 'year' }, y: { field: 'revenue' }, color: { field: 'region' } }, SALES, { year: 'Year', revenue: 'Amount', region: 'Region' }), + 'Bar Table': input('Bar Table', { y: { field: 'region' }, x: { field: 'revenue' } }, SALES, { region: 'Region', revenue: 'Amount' }), + }; + + for (const [chartType, tcInput] of Object.entries(smokeInputs)) { + expect(plGetTemplateDef(chartType), `${chartType} should be registered`).toBeDefined(); + const fig = assemblePlotly(tcInput); + expect(Array.isArray(fig.data), chartType).toBe(true); + expect(fig.data.length, chartType).toBeGreaterThan(0); + assertNoFunctions(fig, chartType); + expect(JSON.parse(JSON.stringify(fig)), chartType).toEqual(fig); + } + // Every input above is exercised; every registered template has coverage. + const covered = new Set(Object.keys(smokeInputs)); + for (const t of plAllTemplateDefs) { + if (['Bar Chart', 'Line Chart', 'Area Chart', 'Scatter Plot'].includes(t.chart)) continue; // covered in plotly-backend.test.ts + expect(covered.has(t.chart), `${t.chart} missing a smoke test above`).toBe(true); + } + }); +}); + +describe('Plotly expressive templates — native trace shapes', () => { + it('boxplot uses a native box trace (no manual quartile computation)', () => { + const fig = assemblePlotly(input('Boxplot', { x: { field: 'region' }, y: { field: 'revenue' } }, SALES, { region: 'Region', revenue: 'Amount' })); + expect(fig.data[0].type).toBe('box'); + expect(fig.data[0].y).toEqual([168, 167, 120, 131]); // raw values, not a precomputed 5-number summary + }); + + it('violin uses a native violin trace', () => { + const fig = assemblePlotly(input('Violin Plot', { x: { field: 'region' }, y: { field: 'revenue' } }, SALES, { region: 'Region', revenue: 'Amount' })); + expect(fig.data[0].type).toBe('violin'); + }); + + it('candlestick uses a native candlestick trace', () => { + const fig = assemblePlotly(input('Candlestick Chart', { x: { field: 'region' }, open: { field: 'revenue' }, close: { field: 'revenue' } }, SALES, { region: 'Region', revenue: 'Amount' })); + expect(fig.data[0].type).toBe('candlestick'); + }); + + it('heatmap uses a native heatmap trace with x/y category arrays + z matrix', () => { + const fig = assemblePlotly(input('Heatmap', { x: { field: 'region' }, y: { field: 'year' }, color: { field: 'revenue' } }, SALES, { region: 'Region', year: 'Year', revenue: 'Amount' })); + expect(fig.data[0].type).toBe('heatmap'); + expect(Array.isArray(fig.data[0].z)).toBe(true); + }); + + it('heatmap reserves margins for rotated labels, axis titles, and its colorbar', () => { + const rows = Array.from({ length: 24 }, (_, index) => ({ + start: `2020-${String(index % 12 + 1).padStart(2, '0')}-${String(index % 27 + 1).padStart(2, '0')}`, + end: `2022-${String(index % 12 + 1).padStart(2, '0')}-${String(index % 27 + 1).padStart(2, '0')}`, + correlation: index / 12 - 1, + })); + const fig = assemblePlotly(input('Heatmap', { x: { field: 'start' }, y: { field: 'end' }, color: { field: 'correlation' } }, rows, + { start: 'Date', end: 'Date', correlation: 'Correlation' })); + expect(fig.layout.xaxis.automargin).toBe(true); + expect(fig.layout.yaxis.automargin).toBe(true); + expect(fig.layout.xaxis.tickangle).toBe(45); + expect(fig.layout.xaxis.title.standoff).toBeGreaterThan(0); + expect(fig.layout.yaxis.title.standoff).toBeGreaterThan(0); + expect(fig.layout.margin.b).toBeGreaterThanOrEqual(90); + expect(fig.layout.margin.l).toBeGreaterThanOrEqual(90); + expect(fig.layout.margin.r).toBeGreaterThanOrEqual(90); + }); + + it('pie/donut use a native pie trace; donut sets a non-zero hole', () => { + const pie = assemblePlotly(input('Pie Chart', { color: { field: 'region' }, size: { field: 'revenue' } }, SALES, { region: 'Region', revenue: 'Amount' })); + expect(pie.data[0].type).toBe('pie'); + expect(pie.data[0].hole).toBe(0); + const donut = assemblePlotly(input('Donut Chart', { color: { field: 'region' }, size: { field: 'revenue' } }, SALES, { region: 'Region', revenue: 'Amount' })); + expect(donut.data[0].hole).toBeGreaterThan(0); + }); + + it('radar uses scatterpolar; rose uses barpolar', () => { + const radar = assemblePlotly(input('Radar Chart', { x: { field: 'region' }, y: { field: 'revenue' } }, SALES, { region: 'Region', revenue: 'Amount' })); + expect(radar.data[0].type).toBe('scatterpolar'); + const rose = assemblePlotly(input('Rose Chart', { x: { field: 'region' }, y: { field: 'revenue' } }, SALES, { region: 'Region', revenue: 'Amount' })); + expect(rose.data[0].type).toBe('barpolar'); + }); + + it('funnel uses a native funnel trace; gauge/kpi use indicator traces', () => { + const funnel = assemblePlotly(input('Funnel Chart', { y: { field: 'region' }, size: { field: 'revenue' } }, SALES, { region: 'Region', revenue: 'Amount' })); + expect(funnel.data[0].type).toBe('funnel'); + const gauge = assemblePlotly(input('Gauge Chart', { size: { field: 'revenue' } }, SALES, { revenue: 'Amount' })); + expect(gauge.data[0].type).toBe('indicator'); + expect(gauge.data[0].mode).toContain('gauge'); + const kpi = assemblePlotly(input('KPI Card', { metric: { field: 'region' }, value: { field: 'revenue' } }, SALES, { region: 'Region', revenue: 'Amount' })); + expect(kpi.data[0].type).toBe('indicator'); + }); +}); + +describe('Plotly expressive templates — grouping & stacking', () => { + it('grouped bar chart uses barmode "group" with one trace per group', () => { + const fig = assemblePlotly(input('Grouped Bar Chart', { x: { field: 'region' }, y: { field: 'revenue' }, color: { field: 'year' } }, SALES, { region: 'Region', revenue: 'Amount', year: 'Year' })); + expect(fig.layout.barmode).toBe('group'); + expect(fig.data).toHaveLength(2); + }); + + it('grouped bar collapses to one bar per band (barmode "overlay") when the group is redundant with x', () => { + // group == x: no band holds >1 group value → nothing to dodge. Must render + // one centered, full-width colored bar per band (like a colored bar chart), + // not shifted slivers in reserved lanes. + const rows = [ + { region: 'Electronics', amount: 300, seg: 'Electronics' }, + { region: 'Clothing', amount: 530, seg: 'Clothing' }, + { region: 'Food', amount: 975, seg: 'Food' }, + ]; + const fig = assemblePlotly(input('Grouped Bar Chart', { x: { field: 'region' }, y: { field: 'amount' }, group: { field: 'seg' } }, rows, { region: 'Region', amount: 'Amount', seg: 'Category' })); + expect(fig.layout.barmode).toBe('overlay'); + }); + + it('stacked bar chart uses barmode "stack" with one trace per group', () => { + const fig = assemblePlotly(input('Stacked Bar Chart', { x: { field: 'region' }, y: { field: 'revenue' }, color: { field: 'year' } }, SALES, { region: 'Region', revenue: 'Amount', year: 'Year' })); + expect(fig.layout.barmode).toBe('stack'); + expect(fig.data).toHaveLength(2); + }); +}); + +describe('Plotly expressive templates — axis-less charts skip generic faceting', () => { + // Regression test: a shared `column`/`row` faceting pass used to run for + // EVERY template (including axis-less ones), splitting the table into one + // 1-row panel per `column` value and calling `instantiate` once per panel — + // collapsing e.g. a 3-gauge grid into three all-identical, fully-overlapping + // [0,1]x[0,1] domains. Fixed by gating faceting on `hasAxes` (mirrors the + // ECharts backend), matching the multi-item grouping these templates do + // themselves via the (non-faceting) `column` channel. + const MULTI = [ + { device: 'CPU', pct: 65 }, + { device: 'Memory', pct: 82 }, + { device: 'Disk', pct: 43 }, + ]; + + it('gauge chart lays out one indicator per column value with distinct, non-overlapping domains', () => { + const fig = assemblePlotly(input('Gauge Chart', { size: { field: 'pct' }, column: { field: 'device' } }, MULTI, { device: 'Category', pct: 'Percentage' })); + expect(fig.data).toHaveLength(3); + expect(fig.data.map((d: any) => d.value)).toEqual([65, 82, 43]); + const domains = fig.data.map((d: any) => JSON.stringify(d.domain)); + expect(new Set(domains).size).toBe(3); // no two gauges share a domain + for (const d of fig.data) { + expect(d.domain.x[1] - d.domain.x[0]).toBeLessThan(1); + expect(d.domain.y[1] - d.domain.y[0]).toBeLessThan(1); + } + }); + + it('pie/donut/radar/rose/funnel ignore an incidental column binding (no facet split)', () => { + for (const chartType of ['Pie Chart', 'Donut Chart', 'Radar Chart', 'Rose Chart']) { + const fig = assemblePlotly(input(chartType, { color: { field: 'device' }, x: { field: 'device' }, y: { field: 'pct' }, size: { field: 'pct' } }, MULTI, { device: 'Category', pct: 'Percentage' })); + expect(fig._facet, chartType).toBeUndefined(); + } + }); +}); + +describe('Plotly expressive templates — regression fixes', () => { + it('KPI card falls back to a text annotation for a pre-formatted (non-numeric) value', () => { + const fig = assemblePlotly(input('KPI Card', { metric: { field: 'region' }, value: { field: 'label' } }, + [{ region: 'Revenue', label: '$1.2M' }], { region: 'Category', label: 'Amount' })); + expect(fig.data.length).toBe(0); // no numeric indicator trace + expect(fig.layout.annotations.some((a: any) => a.text === '$1.2M')).toBe(true); + expect(fig.layout.xaxis.visible).toBe(false); // no stray default cartesian axes + }); + + it('KPI card uses a native indicator for a numeric value', () => { + const fig = assemblePlotly(input('KPI Card', { metric: { field: 'region' }, value: { field: 'revenue' } }, + [{ region: 'Revenue', revenue: 118432 }], { region: 'Category', revenue: 'Amount' })); + expect(fig.data[0].type).toBe('indicator'); + expect(fig.data[0].value).toBe(118432); + }); + + it('waterfall: the first bar anchors at its own value (not a zero-height "total")', () => { + const PNL = [ + { category: 'Revenue', amount: 1000 }, + { category: 'COGS', amount: -400 }, + { category: 'Net Income', amount: 600 }, + ]; + const fig = assemblePlotly(input('Waterfall Chart', { x: { field: 'category' }, y: { field: 'amount' } }, PNL, { category: 'Category', amount: 'Amount' })); + expect(fig.data[0].type).toBe('waterfall'); + expect(fig.data[0].measure[0]).toBe('relative'); // never 'total' at index 0 + expect(fig.data[0].y[0]).toBe(1000); + }); + + it('bullet chart legend includes attainment swatches, not just the target tick', () => { + const fig = assemblePlotly(input('Bullet Chart', { y: { field: 'region' }, x: { field: 'revenue' }, goal: { field: 'revenue' } }, + SALES, { region: 'Region', revenue: 'Amount' })); + const names = fig.data.map((d: any) => d.name); + expect(names).toContain('Target'); + expect(names).toContain('Meets target'); + expect(names).toContain('Below target'); + expect(fig.layout.legend.y).toBeLessThanOrEqual(-0.3); + expect(fig.layout.margin.b).toBeGreaterThanOrEqual(72); + }); + + it('scatter plot uses a continuous colorscale (not a legend per distinct value) for quantitative color', () => { + const fig = assemblePlotly(input('Scatter Plot', { x: { field: 'revenue' }, y: { field: 'revenue' }, color: { field: 'revenue' } }, + SALES, { revenue: 'Amount' })); + expect(fig.data).toHaveLength(1); + expect(fig.data[0].marker.showscale).toBe(true); + expect(Array.isArray(fig.data[0].marker.color)).toBe(true); + expect(fig.layout.showlegend).toBe(false); + }); + + it('scatter plot still groups a nominal color into one legend trace per value', () => { + const fig = assemblePlotly(input('Scatter Plot', { x: { field: 'revenue' }, y: { field: 'revenue' }, color: { field: 'region' } }, + SALES, { region: 'Region', revenue: 'Amount' })); + expect(fig.data).toHaveLength(2); + expect(fig.layout.showlegend).toBe(true); + }); +}); diff --git a/packages/flint-js/tests/plotly-gap-charts.test.ts b/packages/flint-js/tests/plotly-gap-charts.test.ts new file mode 100644 index 00000000..f4292fa9 --- /dev/null +++ b/packages/flint-js/tests/plotly-gap-charts.test.ts @@ -0,0 +1,334 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Tests for the four Plotly "registry gap" chart types closed in this pass: + * Map, Choropleth, Sparkline, Bar Table. + * + * Map/Choropleth share their region-resolution gazetteer with the Vega-Lite + * backend (`chart-types/geo.ts`) but render through Plotly's own native geo + * traces (`scattergeo` / `choropleth`) rather than a fetched/joined TopoJSON. + * Sparkline/Bar Table are composite, self-contained Plotly figures (their own + * multi-axis-pair grid + paper-anchored annotations) that opt out of the + * generic column/row facet combiner via `selfManagesFacets`. + */ + +import { describe, it, expect } from 'vitest'; +import { assemblePlotly, plGetTemplateDef, plAllTemplateDefs } from '../src'; + +function input(chartType: string, encodings: Record, values: any[], semantic_types: Record, chartProperties?: Record) { + return { + data: { values }, + semantic_types, + chart_spec: { chartType, encodings, baseSize: { width: 480, height: 320 }, ...(chartProperties ? { chartProperties } : {}) }, + } as any; +} + +/** Recursively assert a value contains no functions (pure JSON, serializable). */ +function assertNoFunctions(node: any, path = '$'): void { + if (typeof node === 'function') throw new Error(`function found at ${path}`); + if (node && typeof node === 'object') { + for (const [k, v] of Object.entries(node)) assertNoFunctions(v, `${path}.${k}`); + } +} + +function assertSerializable(fig: any): void { + assertNoFunctions(fig); + expect(JSON.parse(JSON.stringify(fig))).toEqual(fig); +} + +describe('Plotly gap charts — registration', () => { + it('Map, Choropleth, Sparkline, Bar Table are registered', () => { + for (const chart of ['Map', 'Choropleth', 'Sparkline', 'Bar Table']) { + expect(plGetTemplateDef(chart), chart).toBeDefined(); + } + const charts = plAllTemplateDefs.map(t => t.chart); + expect(new Set(charts).size).toBe(charts.length); // no duplicate registrations + }); + + it('Sparkline and Bar Table opt out of the generic facet combiner', () => { + expect(plGetTemplateDef('Sparkline')?.selfManagesFacets).toBe(true); + expect(plGetTemplateDef('Bar Table')?.selfManagesFacets).toBe(true); + }); +}); + +// --------------------------------------------------------------------------- +// Map (bubble) +// --------------------------------------------------------------------------- + +const US_CITIES = [ + { city: 'New York', lon: -74.01, lat: 40.71, pop: 18.9 }, + { city: 'Chicago', lon: -87.63, lat: 41.88, pop: 9.3 }, + { city: 'Denver', lon: -104.99, lat: 39.74, pop: 2.9 }, +]; +const WORLD_CITIES = [ + { city: 'Tokyo', lon: 139.69, lat: 35.68, pop: 37.4 }, + { city: 'Paris', lon: 2.35, lat: 48.86, pop: 11.1 }, + { city: 'Sydney', lon: 151.21, lat: -33.87, pop: 5.3 }, +]; + +describe('Plotly Map', () => { + it('uses a native scattergeo trace and infers a US scope from in-bounds lon/lat', () => { + const fig = assemblePlotly(input('Map', { longitude: { field: 'lon' }, latitude: { field: 'lat' }, size: { field: 'pop' }, color: { field: 'pop' } }, + US_CITIES, { city: 'City', lon: 'Longitude', lat: 'Latitude', pop: 'Quantity' })); + expect(fig.data[0].type).toBe('scattergeo'); + expect(fig.layout.geo.scope).toBe('usa'); + expect(fig.data[0].lon).toEqual(US_CITIES.map(r => r.lon)); + assertSerializable(fig); + }); + + it('infers a World scope when a point falls outside the US bounding box', () => { + const fig = assemblePlotly(input('Map', { longitude: { field: 'lon' }, latitude: { field: 'lat' }, size: { field: 'pop' } }, + WORLD_CITIES, { city: 'City', lon: 'Longitude', lat: 'Latitude', pop: 'Quantity' })); + expect(fig.layout.geo.scope).toBe('world'); + }); + + it('an explicit `region` property overrides inference', () => { + const fig = assemblePlotly(input('Map', { longitude: { field: 'lon' }, latitude: { field: 'lat' } }, + US_CITIES, { lon: 'Longitude', lat: 'Latitude' }, { region: 'world' })); + expect(fig.layout.geo.scope).toBe('world'); + }); + + it('quantitative color uses a continuous colorscale (Viridis), not a per-value legend', () => { + const fig = assemblePlotly(input('Map', { longitude: { field: 'lon' }, latitude: { field: 'lat' }, color: { field: 'pop' } }, + US_CITIES, { lon: 'Longitude', lat: 'Latitude', pop: 'Quantity' })); + expect(fig.data).toHaveLength(1); + expect(fig.data[0].marker.showscale).toBe(true); + expect(fig.layout.showlegend).toBe(false); + }); + + it('nominal color groups into one trace per value with a legend', () => { + const rows = US_CITIES.map((r, i) => ({ ...r, region: i === 2 ? 'West' : 'East' })); + const fig = assemblePlotly(input('Map', { longitude: { field: 'lon' }, latitude: { field: 'lat' }, color: { field: 'region' } }, + rows, { lon: 'Longitude', lat: 'Latitude', region: 'Category' })); + expect(fig.data.length).toBe(2); + expect(fig.layout.showlegend).toBe(true); + expect(fig.data.map((d: any) => d.name).sort()).toEqual(['East', 'West']); + }); + + it('bubble diameters scale with `size` (sqrt/area-truth, not linear)', () => { + const rows = [{ lon: -74, lat: 40, v: 1 }, { lon: -87, lat: 41, v: 100 }]; + const fig = assemblePlotly(input('Map', { longitude: { field: 'lon' }, latitude: { field: 'lat' }, size: { field: 'v' } }, + rows, { lon: 'Longitude', lat: 'Latitude', v: 'Quantity' })); + const [d0, d1] = fig.data[0].marker.size; + // sqrt(100)/sqrt(1) = 10, so the diameter ratio should be well under 100/1. + expect(d1 / d0).toBeGreaterThan(1); + expect(d1 / d0).toBeLessThan(10); + }); +}); + +// --------------------------------------------------------------------------- +// Choropleth +// --------------------------------------------------------------------------- + +describe('Plotly Choropleth', () => { + it('uses a native choropleth trace with USPS codes + USA-states locationmode for US states', () => { + const rows = [{ state: 'California', pop: 39.5 }, { state: 'Texas', pop: 29.1 }, { state: 'NY', pop: 20.2 }]; + const fig = assemblePlotly(input('Choropleth', { id: { field: 'state' }, color: { field: 'pop' } }, + rows, { state: 'State', pop: 'Quantity' })); + expect(fig.data[0].type).toBe('choropleth'); + expect(fig.data[0].locationmode).toBe('USA-states'); + expect(fig.data[0].locations).toEqual(['CA', 'TX', 'NY']); + expect(fig.layout.geo.scope).toBe('usa'); + assertSerializable(fig); + }); + + it('uses ISO-3 codes + ISO-3 locationmode for world countries', () => { + const rows = [{ country: 'China', pop: 1410 }, { country: 'USA', pop: 339 }, { country: 'FR', pop: 68 }]; + const fig = assemblePlotly(input('Choropleth', { id: { field: 'country' }, color: { field: 'pop' } }, + rows, { country: 'Country', pop: 'Quantity' })); + expect(fig.data[0].locationmode).toBe('ISO-3'); + expect(fig.data[0].locations).toEqual(['CHN', 'USA', 'FRA']); + expect(fig.layout.geo.scope).toBe('world'); + }); + + it('disambiguates a colliding name ("Georgia") by the id field\'s semantic type', () => { + const usRows = [{ place: 'Georgia', pop: 10.7 }]; + const usFig = assemblePlotly(input('Choropleth', { id: { field: 'place' }, color: { field: 'pop' } }, usRows, { place: 'State', pop: 'Quantity' })); + expect(usFig.data[0].locationmode).toBe('USA-states'); + expect(usFig.data[0].locations).toEqual(['GA']); // Georgia (US state) + + const countryRows = [{ place: 'Georgia', pop: 3.7 }]; + const worldFig = assemblePlotly(input('Choropleth', { id: { field: 'place' }, color: { field: 'pop' } }, countryRows, { place: 'Country', pop: 'Quantity' })); + expect(worldFig.data[0].locationmode).toBe('ISO-3'); + expect(worldFig.data[0].locations).toEqual(['GEO']); // Georgia (the country) + }); + + it('uses an explicit light-to-dark sequential colorscale (not Plotly\'s inverted stock "Blues")', () => { + const rows = [{ state: 'California', pop: 39.5 }, { state: 'Texas', pop: 29.1 }]; + const fig = assemblePlotly(input('Choropleth', { id: { field: 'state' }, color: { field: 'pop' } }, rows, { state: 'State', pop: 'Quantity' })); + const scale = fig.data[0].colorscale; + expect(Array.isArray(scale)).toBe(true); // an explicit stop array, not the string 'Blues' + expect(scale[0][0]).toBe(0); + expect(scale[scale.length - 1][0]).toBe(1); + }); + + it('rows that fail to resolve to a code are dropped, not left as invalid locations', () => { + const rows = [{ state: 'California', pop: 39.5 }, { state: 'Not A Real Place', pop: 1 }]; + const fig = assemblePlotly(input('Choropleth', { id: { field: 'state' }, color: { field: 'pop' } }, rows, { state: 'State', pop: 'Quantity' })); + expect(fig.data[0].locations).toEqual(['CA']); + }); +}); + +// --------------------------------------------------------------------------- +// Sparkline +// --------------------------------------------------------------------------- + +const SPARK_ROWS = [ + { month: '2025-01', value: 10, metric: 'Electronics' }, + { month: '2025-02', value: 14, metric: 'Electronics' }, + { month: '2025-03', value: 12, metric: 'Electronics' }, + { month: '2025-01', value: 30, metric: 'Clothing' }, + { month: '2025-02', value: 28, metric: 'Clothing' }, + { month: '2025-03', value: 34, metric: 'Clothing' }, +]; + +describe('Plotly Sparkline', () => { + it('one strip (own hidden axis pair) per series, colored by the `color` field', () => { + const fig = assemblePlotly(input('Sparkline', { x: { field: 'month' }, y: { field: 'value' }, color: { field: 'metric' } }, + SPARK_ROWS, { month: 'Date', value: 'Quantity', metric: 'Category' })); + // 2 series x (1 line + 1 mean reference line) = 4 traces. + expect(fig.data.filter((d: any) => d.mode === 'lines' && d.line.dash == null)).toHaveLength(2); + expect(fig.layout.xaxis.visible).toBe(false); + expect(fig.layout.yaxis.visible).toBe(false); + expect(fig.layout.xaxis2.visible).toBe(false); + // Category name + aggregate value annotations, one pair per series, plus 3 column headers. + const seriesNameAnn = fig.layout.annotations.filter((a: any) => a.text === 'Electronics' || a.text === 'Clothing'); + expect(seriesNameAnn.length).toBe(2); + assertSerializable(fig); + }); + + it('is monochrome (no per-series hue) when only `detail` is bound', () => { + const fig = assemblePlotly(input('Sparkline', { x: { field: 'month' }, y: { field: 'value' }, detail: { field: 'metric' } }, + SPARK_ROWS, { month: 'Date', value: 'Quantity', metric: 'Category' })); + const lineTraces = fig.data.filter((d: any) => d.mode === 'lines' && d.line.dash == null); + expect(lineTraces).toHaveLength(2); + for (const t of lineTraces) expect(t.line.color).toBe('#555'); + }); + + it('baseline: "zero" draws a reference line at 0, "none" omits it', () => { + const zeroFig = assemblePlotly(input('Sparkline', { x: { field: 'month' }, y: { field: 'value' }, color: { field: 'metric' } }, + SPARK_ROWS, { month: 'Date', value: 'Quantity', metric: 'Category' }, { baseline: 'zero' })); + const dashed = zeroFig.data.filter((d: any) => d.line?.dash === 'dot'); + expect(dashed.length).toBe(2); + expect(dashed.every((d: any) => d.y[0] === 0 && d.y[1] === 0)).toBe(true); + + const noneFig = assemblePlotly(input('Sparkline', { x: { field: 'month' }, y: { field: 'value' }, color: { field: 'metric' } }, + SPARK_ROWS, { month: 'Date', value: 'Quantity', metric: 'Category' }, { baseline: 'none' })); + expect(noneFig.data.filter((d: any) => d.line?.dash === 'dot')).toHaveLength(0); + }); + + it('a single (unseriesed) sparkline renders one strip with no series column', () => { + const rows = SPARK_ROWS.filter(r => r.metric === 'Electronics').map(({ month, value }) => ({ month, value })); + const fig = assemblePlotly(input('Sparkline', { x: { field: 'month' }, y: { field: 'value' } }, rows, { month: 'Date', value: 'Quantity' })); + expect(fig.data.filter((d: any) => d.mode === 'lines' && d.line.dash == null)).toHaveLength(1); + }); + + it('does nothing destructive with an incidental column binding (self-managed facets)', () => { + // Sparkline doesn't declare `column` in its channels, but the pipeline + // resolves whatever encodings are supplied — this must not crash or be + // silently pre-split by the generic facet combiner. + const fig = assemblePlotly(input('Sparkline', + { x: { field: 'month' }, y: { field: 'value' }, color: { field: 'metric' }, column: { field: 'metric' } }, + SPARK_ROWS, { month: 'Date', value: 'Quantity', metric: 'Category' })); + expect(fig._facet).toBeUndefined(); + expect(Array.isArray(fig.data)).toBe(true); + expect(fig.data.length).toBeGreaterThan(0); + }); +}); + +// --------------------------------------------------------------------------- +// Bar Table +// --------------------------------------------------------------------------- + +const RANKED_ROWS = [ + { category: 'Electronics', value: 331200 }, + { category: 'Bicycles', value: 89800 }, + { category: 'Perfume', value: 57700 }, + { category: 'Apparel', value: 48200 }, + { category: 'Furniture', value: 32100 }, +]; + +describe('Plotly Bar Table', () => { + it('one horizontal bar trace, ranked by value, when there is no color field', () => { + const fig = assemblePlotly(input('Bar Table', { y: { field: 'category' }, x: { field: 'value' } }, RANKED_ROWS, { category: 'Category', value: 'Amount' })); + expect(fig.data).toHaveLength(1); + expect(fig.data[0].type).toBe('bar'); + expect(fig.data[0].orientation).toBe('h'); + expect(fig.data[0].y).toEqual(['Electronics', 'Bicycles', 'Perfume', 'Apparel', 'Furniture']); // sorted descending + assertSerializable(fig); + }); + + it('Top-N rollup buckets the tail into a single "Others (+N)" row', () => { + const fig = assemblePlotly(input('Bar Table', { y: { field: 'category' }, x: { field: 'value' } }, + RANKED_ROWS, { category: 'Category', value: 'Amount' }, { maxRows: 3 })); + expect(fig.data[0].y).toEqual(['Electronics', 'Bicycles', 'Others (+3)']); + }); + + it('maxRows: 0 disables the Top-N rollup', () => { + const fig = assemblePlotly(input('Bar Table', { y: { field: 'category' }, x: { field: 'value' } }, + RANKED_ROWS, { category: 'Category', value: 'Amount' }, { maxRows: 0 })); + expect(fig.data[0].y).toHaveLength(5); + }); + + it('showPercent adds a "%" annotation column', () => { + const withoutPct = assemblePlotly(input('Bar Table', { y: { field: 'category' }, x: { field: 'value' } }, RANKED_ROWS, { category: 'Category', value: 'Amount' })); + const withPct = assemblePlotly(input('Bar Table', { y: { field: 'category' }, x: { field: 'value' } }, RANKED_ROWS, { category: 'Category', value: 'Amount' }, { showPercent: true })); + expect(withPct.layout.annotations.some((a: any) => /%$/.test(a.text))).toBe(true); + expect(withoutPct.layout.annotations.some((a: any) => /%$/.test(a.text))).toBe(false); + }); + + it('a mixed-sign measure uses a diverging (not sequential) gradient', () => { + const rows = [{ dept: 'Engineering', variance: 120 }, { dept: 'Sales', variance: -45 }, { dept: 'HR', variance: -20 }]; + const fig = assemblePlotly(input('Bar Table', { y: { field: 'dept' }, x: { field: 'variance' } }, rows, { dept: 'Category', variance: 'Quantity' })); + const colors = new Set(fig.data[0].marker.color); + expect(colors.size).toBeGreaterThan(1); // gradient, not a flat color + }); + + it('a color field stacks one trace per group with a legend', () => { + const rows = [ + { sku: 'Home', region: 'East', revenue: 100 }, { sku: 'Home', region: 'West', revenue: 80 }, + { sku: 'Garden', region: 'East', revenue: 60 }, { sku: 'Garden', region: 'West', revenue: 40 }, + ]; + const fig = assemblePlotly(input('Bar Table', { y: { field: 'sku' }, x: { field: 'revenue' }, color: { field: 'region' } }, rows, { sku: 'Category', revenue: 'Amount', region: 'Category' })); + expect(fig.layout.barmode).toBe('stack'); + expect(fig.layout.showlegend).toBe(true); + expect(new Set(fig.data.map((d: any) => d.name))).toEqual(new Set(['East', 'West'])); + }); + + it('column facets lay out independent per-cell axis pairs, correctly anchored to each other', () => { + const rows = [ + { agency: 'SpaceX', type: 'private', launches: 65 }, { agency: 'ULA', type: 'private', launches: 12 }, + { agency: 'RVSN', type: 'state', launches: 40 }, { agency: 'NASA', type: 'state', launches: 20 }, + ]; + const fig = assemblePlotly(input('Bar Table', { y: { field: 'agency' }, x: { field: 'launches' }, column: { field: 'type' } }, + rows, { agency: 'Category', launches: 'Amount', type: 'Category' })); + // Regression test: each per-cell yaxis must anchor to ITS OWN xaxis (not + // all default to the same one), else every cell's category tick labels + // draw at the same horizontal position and visually collide (see + // bar-table.ts's docstring / the anchor fix in this pass). + expect(fig.layout.yaxis.anchor).toBe('x'); + expect(fig.layout.yaxis2.anchor).toBe('x2'); + expect(fig.layout.xaxis.anchor).toBe('y'); + expect(fig.layout.xaxis2.anchor).toBe('y2'); + // Two distinct, non-overlapping horizontal domains (side-by-side cells). + const [x0a, x1a] = fig.layout.xaxis.domain; + const [x0b] = fig.layout.xaxis2.domain; + expect(x1a).toBeLessThanOrEqual(x0b); + void x0a; + }); + + it('does not crash and produces pure-JSON output on a single-row table', () => { + const fig = assemblePlotly(input('Bar Table', { y: { field: 'region' }, x: { field: 'revenue' } }, [{ region: 'APAC', revenue: 4250000 }], { region: 'Region', revenue: 'Amount' })); + expect(fig.data).toHaveLength(1); + expect(fig._height).toBeGreaterThanOrEqual(70); + assertSerializable(fig); + }); + + it('very small (sub-1) values are not rounded away to "0"', () => { + const rows = [{ sensor: 'A', reading: 0.0023 }, { sensor: 'B', reading: 0.0011 }]; + const fig = assemblePlotly(input('Bar Table', { y: { field: 'sensor' }, x: { field: 'reading' } }, rows, { sensor: 'Category', reading: 'Quantity' })); + const valueAnn = fig.layout.annotations.filter((a: any) => /^0\.\d+$/.test(a.text)); + expect(valueAnn.length).toBe(2); + }); +}); diff --git a/packages/flint-js/tests/plotly-widgets.test.ts b/packages/flint-js/tests/plotly-widgets.test.ts new file mode 100644 index 00000000..85afb64c --- /dev/null +++ b/packages/flint-js/tests/plotly-widgets.test.ts @@ -0,0 +1,137 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * Regression coverage for Plotly dynamic-widget (chartProperties + encoding + * action) support. Many controls surfaced in the options bar (Sort, corner + * radius, stack mode, log scale, include-zero) previously did nothing on the + * Plotly backend because the templates never read/applied them, or the + * encoding actions weren't declared (so applyEncodingOverrides ignored them), + * or the raw encodings lacked resolved types (so Sort couldn't find the measure). + */ + +import { describe, it, expect } from 'vitest'; +import { assemblePlotly } from '../src'; + +const CATS = [{ Cat: 'A', Val: 30 }, { Cat: 'B', Val: 90 }, { Cat: 'C', Val: 50 }]; +const CAT_TYPES = { Cat: 'Category', Val: 'Quantity' } as const; + +function bandOrder(spec: any): string[] { + return spec.layout.xaxis?.categoryarray ?? spec.layout.yaxis?.categoryarray ?? []; +} + +describe('Plotly Sort encoding action', () => { + for (const chartType of ['Bar Chart', 'Stacked Bar Chart', 'Grouped Bar Chart', 'Lollipop Chart']) { + it(`reorders ${chartType} categories by value`, () => { + const mk = (sort?: string) => assemblePlotly({ + data: { values: CATS }, + semantic_types: CAT_TYPES, + chart_spec: { + chartType, encodings: { x: 'Cat', y: 'Val' }, + ...(sort ? { chartProperties: { sort } } : {}), + }, + } as any); + expect(bandOrder(mk())).toEqual(['A', 'B', 'C']); + expect(bandOrder(mk('value-desc'))).toEqual(['B', 'C', 'A']); + expect(bandOrder(mk('value-asc'))).toEqual(['A', 'C', 'B']); + }); + } + + it('sorts a HORIZONTAL bar by value too', () => { + const s = assemblePlotly({ + data: { values: CATS }, semantic_types: CAT_TYPES, + chart_spec: { chartType: 'Bar Chart', encodings: { y: 'Cat', x: 'Val' }, chartProperties: { sort: 'value-desc' } }, + } as any); + expect(s.layout.yaxis.categoryarray).toEqual(['B', 'C', 'A']); + }); +}); + +describe('Plotly bar cornerRadius', () => { + it('applies marker.cornerradius when set (and omits it at 0)', () => { + const at = (cr?: number) => assemblePlotly({ + data: { values: CATS }, semantic_types: CAT_TYPES, + chart_spec: { chartType: 'Bar Chart', encodings: { x: 'Cat', y: 'Val' }, ...(cr != null ? { chartProperties: { cornerRadius: cr } } : {}) }, + } as any).data[0].marker.cornerradius; + expect(at()).toBeUndefined(); + expect(at(10)).toBe(10); + }); +}); + +describe('Plotly stackMode', () => { + const S = [ + { Cat: 'A', Val: 30, Grp: 'x' }, { Cat: 'A', Val: 20, Grp: 'y' }, + { Cat: 'B', Val: 50, Grp: 'x' }, { Cat: 'B', Val: 40, Grp: 'y' }, + ]; + const T = { Cat: 'Category', Val: 'Quantity', Grp: 'Category' } as const; + + it('normalizes a stacked bar to 100% (barnorm percent)', () => { + const s = assemblePlotly({ + data: { values: S }, semantic_types: T, + chart_spec: { chartType: 'Stacked Bar Chart', encodings: { x: 'Cat', y: 'Val', color: 'Grp' }, chartProperties: { stackMode: 'normalize' } }, + } as any); + expect(s.layout.barnorm).toBe('percent'); + }); + + it('normalizes / layers a stacked area (groupnorm / no stackgroup)', () => { + const mk = (mode?: string) => assemblePlotly({ + data: { values: S.map((r) => ({ Month: r.Cat, ...r })) }, semantic_types: { ...T, Month: 'Month' }, + chart_spec: { chartType: 'Area Chart', encodings: { x: 'Month', y: 'Val', color: 'Grp' }, ...(mode ? { chartProperties: { stackMode: mode } } : {}) }, + } as any); + expect(mk('normalize').data[0].groupnorm).toBe('percent'); + expect(mk('normalize').data[0].stackgroup).toBe('one'); + expect(mk('layered').data[0].stackgroup).toBeUndefined(); + }); +}); + +describe('Plotly waterfall value labels', () => { + const WF = [ + { D: 'Engineering', V: 120 }, { D: 'Sales', V: -45 }, { D: 'Marketing', V: -80 }, + { D: 'Operations', V: 35 }, { D: 'HR', V: -20 }, { D: 'Finance', V: 15 }, { D: 'Support', V: -30 }, + ]; + const T = { D: 'Category', V: 'Quantity' } as const; + + it('pads the y-range and disables axis clipping so outside labels are not cropped', () => { + const withLabels = assemblePlotly({ + data: { values: WF }, semantic_types: T, + chart_spec: { chartType: 'Waterfall Chart', encodings: { x: 'D', y: 'V' }, chartProperties: { showTextLabels: true } }, + } as any); + // Running-total envelope is [-5, 120]; padded by 15% → below -5 and above 120. + expect(withLabels.layout.yaxis.range[0]).toBeLessThan(-5); + expect(withLabels.layout.yaxis.range[1]).toBeGreaterThan(120); + expect(withLabels.data[0].cliponaxis).toBe(false); + }); + + it('does not pin a range or clip setting when labels are off', () => { + const noLabels = assemblePlotly({ + data: { values: WF }, semantic_types: T, + chart_spec: { chartType: 'Waterfall Chart', encodings: { x: 'D', y: 'V' } }, + } as any); + expect(noLabels.layout.yaxis.range).toBeUndefined(); + expect(noLabels.data[0].cliponaxis).toBeUndefined(); + }); +}); + +describe('Plotly cross-cutting axis properties', () => { + const PTS = [ + { X: 1, Y: 5 }, { X: 10, Y: 50 }, { X: 100, Y: 500 }, + { X: 1000, Y: 5000 }, { X: 5, Y: 20 }, { X: 50, Y: 200 }, + ]; + const T = { X: 'Quantity', Y: 'Quantity' } as const; + + it('applies log scale to both axes', () => { + const s = assemblePlotly({ + data: { values: PTS }, semantic_types: T, + chart_spec: { chartType: 'Scatter Plot', encodings: { x: 'X', y: 'Y' }, chartProperties: { logScale_x: true, logScale_y: true } }, + } as any); + expect(s.layout.xaxis.type).toBe('log'); + expect(s.layout.yaxis.type).toBe('log'); + }); + + it('applies include-zero (rangemode tozero) and never on a category axis', () => { + const s = assemblePlotly({ + data: { values: PTS }, semantic_types: T, + chart_spec: { chartType: 'Scatter Plot', encodings: { x: 'X', y: 'Y' }, chartProperties: { includeZero_y: true } }, + } as any); + expect(s.layout.yaxis.rangemode).toBe('tozero'); + }); +}); diff --git a/packages/flint-js/tests/smoke.test.ts b/packages/flint-js/tests/smoke.test.ts index 1684754d..4e7977b8 100644 --- a/packages/flint-js/tests/smoke.test.ts +++ b/packages/flint-js/tests/smoke.test.ts @@ -6,6 +6,8 @@ import { assembleVegaLite, assembleECharts, assembleChartjs, + assemblePlotly, + assembleExcel, } from '../src'; const DATA = [ @@ -47,6 +49,865 @@ describe('public API smoke', () => { expect(config.type ?? config.data ?? config.options).toBeDefined(); }); + it('assembleExcel returns an Excel chart spec with a wide data matrix', () => { + const spec = assembleExcel(INPUT) as any; + expect(spec).toBeDefined(); + // XYScatter (both axes quantitative), wide matrix with a header row + expect(spec.chartType).toBe('XYScatter'); + expect(Array.isArray(spec.data)).toBe(true); + expect(spec.data[0]).toEqual([ + 'JP weight', 'JP mpg', + 'US weight', 'US mpg', + 'EU weight', 'EU mpg', + ]); + expect(spec.series).toEqual([ + { name: 'JP', xColumn: 0, yColumn: 1, rowCount: 1 }, + { name: 'US', xColumn: 2, yColumn: 3, rowCount: 1 }, + { name: 'EU', xColumn: 4, yColumn: 5, rowCount: 1 }, + ]); + expect(spec.seriesBy).toBe('Columns'); + }); + + it('assembleExcel preserves bar-template roles when both axes are quantitative', () => { + const spec = assembleExcel({ + data: { values: [{ X: 1, Value: 10 }, { X: 2, Value: 20 }] }, + semantic_types: { X: 'Quantity', Value: 'Quantity' }, + chart_spec: { chartType: 'Bar Chart', encodings: { x: 'X', y: 'Value' } }, + }) as any; + + expect(spec.kind).toBe('chart'); + expect(spec.chartType).toBe('ColumnClustered'); + expect(spec.data).toEqual([['X', 'Value'], ['1', 10], ['2', 20]]); + }); + + it('assembleExcel uses stacked charts for a colored Bar Chart', () => { + const spec = assembleExcel({ + data: { values: [ + { Category: 'A', Value: 3, Segment: 'US' }, + { Category: 'A', Value: 4, Segment: 'JP' }, + ] }, + semantic_types: { Category: 'Category', Value: 'Quantity', Segment: 'Category' }, + chart_spec: { chartType: 'Bar Chart', encodings: { x: 'Category', y: 'Value', color: 'Segment' } }, + }) as any; + + expect(spec.chartType).toBe('ColumnStacked'); + expect(spec.data[0]).toEqual(['Category', 'US', 'JP']); + }); + + it('assembleExcel emits native histogram data without requiring a category', () => { + const spec = assembleExcel({ + data: { values: [{ Value: 1 }, { Value: 2 }, { Value: 3 }] }, + semantic_types: { Value: 'Quantity' }, + chart_spec: { chartType: 'Histogram', encodings: { x: 'Value' } }, + }) as any; + + expect(spec.chartType).toBe('ColumnClustered'); + expect(spec.data[0]).toEqual(['Value', 'Count']); + expect(spec.data.slice(1).reduce((sum: number, row: any[]) => sum + row[1], 0)).toBe(3); + expect(spec.gapWidth).toBe(0); + }); + + it('assembleExcel emits a native delta Waterfall with connector lines', () => { + const spec = assembleExcel({ + data: { values: [ + { Department: 'Engineering', Variance: 120 }, + { Department: 'Sales', Variance: -45 }, + { Department: 'Marketing', Variance: -80 }, + ] }, + semantic_types: { Department: 'Category', Variance: 'Quantity' }, + chart_spec: { + chartType: 'Waterfall Chart', + encodings: { x: 'Department', y: 'Variance' }, + chartProperties: { totals: 'first' }, + }, + }) as any; + + expect(spec.kind).toBe('chart'); + expect(spec.chartType).toBe('Waterfall'); + expect(spec.data).toEqual([ + ['Department', 'Variance'], + ['Engineering', 120], + ['Sales', -45], + ['Marketing', -80], + ]); + expect(spec.showConnectorLines).toBe(true); + }); + + it('assembleExcel normalizes native Radar series by each metric maximum', () => { + const spec = assembleExcel({ + data: { values: [ + { Team: 'A', Metric: 'Speed', Value: 80 }, + { Team: 'B', Metric: 'Speed', Value: 100 }, + { Team: 'A', Metric: 'Cost', Value: 20 }, + { Team: 'B', Metric: 'Cost', Value: 40 }, + { Team: 'A', Metric: 'Quality', Value: 75 }, + { Team: 'B', Metric: 'Quality', Value: 50 }, + ] }, + semantic_types: { Team: 'Category', Metric: 'Category', Value: 'Quantity' }, + chart_spec: { + chartType: 'Radar Chart', + encodings: { x: 'Metric', y: 'Value', color: 'Team' }, + }, + }) as any; + + expect(spec.chartType).toBe('RadarMarkers'); + expect(spec.data).toEqual([ + ['Metric', 'A', 'B'], + ['Speed (100)', 0.8, 1], + ['Cost (50)', 0.4, 0.8], + ['Quality (100)', 0.75, 0.5], + ]); + expect(spec.valueAxis).toEqual({ minimumScale: 0, maximumScale: 1, majorUnit: 0.25 }); + expect(spec.legend).toEqual({ visible: true, position: 'Bottom' }); + expect(spec.warnings).toEqual([expect.objectContaining({ code: 'excel-radar-fill-unsupported' })]); + }); + + it('assembleExcel maps unfilled Radar to native markers and rejects facets', () => { + const input = { + data: { values: [ + { Metric: 'A', Value: 1, Region: 'North' }, + { Metric: 'B', Value: 2, Region: 'North' }, + { Metric: 'C', Value: 3, Region: 'North' }, + ] }, + semantic_types: { Metric: 'Category', Value: 'Quantity', Region: 'Category' }, + chart_spec: { + chartType: 'Radar Chart', + encodings: { x: 'Metric', y: 'Value' }, + chartProperties: { filled: false }, + }, + }; + expect((assembleExcel(input) as any).chartType).toBe('RadarMarkers'); + + expect(() => assembleExcel({ + ...input, + chart_spec: { + ...input.chart_spec, + encodings: { ...input.chart_spec.encodings, column: 'Region' }, + }, + } as any)).toThrow('does not support faceting'); + }); + + it('assembleExcel rejects generic chart facets instead of collapsing panels', () => { + expect(() => assembleExcel({ + data: { values: [ + { Region: 'North', Category: 'A', Value: 10 }, + { Region: 'South', Category: 'A', Value: 20 }, + ] }, + semantic_types: { Region: 'Category', Category: 'Category', Value: 'Quantity' }, + chart_spec: { + chartType: 'Bar Chart', + encodings: { x: 'Category', y: 'Value', column: 'Region' }, + }, + })).toThrow('does not support faceting in one native Excel chart'); + }); + + it('assembleExcel rejects Waterfalls requiring a non-initial total point', () => { + expect(() => assembleExcel({ + data: { values: [ + { Step: 'Opening', Value: 500, Type: 'start' }, + { Step: 'Sales', Value: 200, Type: 'delta' }, + { Step: 'Closing', Value: 700, Type: 'end' }, + ] }, + semantic_types: { Step: 'Category', Value: 'Quantity', Type: 'Category' }, + chart_spec: { + chartType: 'Waterfall Chart', + encodings: { x: 'Step', y: 'Value', color: 'Type' }, + }, + })).toThrow('Office.js does not expose Waterfall total-point semantics'); + }); + + it('assembleExcel preserves raw observations for native Boxplot quartiles', () => { + const spec = assembleExcel({ + data: { values: [ + { Group: 'A', Value: 1 }, + { Group: 'A', Value: 5 }, + { Group: 'B', Value: 2 }, + { Group: 'B', Value: 8 }, + ] }, + semantic_types: { Group: 'Category', Value: 'Quantity' }, + chart_spec: { chartType: 'Boxplot', encodings: { x: 'Group', y: 'Value' } }, + }) as any; + + expect(spec.chartType).toBe('BoxWhisker'); + expect(spec.data).toEqual([ + ['Group', 'Value'], + ['A', 1], + ['A', 5], + ['B', 2], + ['B', 8], + ]); + expect(spec.boxWhiskerOptions).toEqual({ + quartileCalculation: 'Inclusive', + showInnerPoints: false, + showMeanLine: false, + showMeanMarker: false, + showOutlierPoints: true, + }); + }); + + it('assembleExcel emits the native StockOHLC date-open-high-low-close range', () => { + const spec = assembleExcel({ + data: { values: [ + { Date: '2026-01-02', Open: 100, High: 108, Low: 98, Close: 105 }, + { Date: '2026-01-05', Open: 105, High: 110, Low: 101, Close: 103 }, + ] }, + semantic_types: { Date: 'Date', Open: 'Quantity', High: 'Quantity', Low: 'Quantity', Close: 'Quantity' }, + chart_spec: { + chartType: 'Candlestick Chart', + encodings: { x: 'Date', open: 'Open', high: 'High', low: 'Low', close: 'Close' }, + }, + }) as any; + + expect(spec.chartType).toBe('StockOHLC'); + expect(spec.seriesBy).toBe('Columns'); + expect(spec.data).toEqual([ + ['Date', 'Open', 'High', 'Low', 'Close'], + [46024, 100, 108, 98, 105], + [46027, 105, 110, 101, 103], + ]); + expect(spec.categoryAxis.numberFormat).toBe('yyyy-mm-dd'); + expect(spec.valueAxis).toEqual({ + title: 'Price', + numberFormat: undefined, + minimumScale: 95, + maximumScale: 115, + majorUnit: 5, + }); + expect(spec.legend).toEqual({ visible: false }); + }); + + it('assembleExcel rejects invalid native Candlestick rows and unsupported encodings', () => { + const input = { + data: { values: [ + { Date: '2026-01-02', Open: 100, High: 99, Low: 98, Close: 105, Ticker: 'A' }, + ] }, + semantic_types: { + Date: 'Date', Open: 'Quantity', High: 'Quantity', Low: 'Quantity', Close: 'Quantity', Ticker: 'Category', + }, + chart_spec: { + chartType: 'Candlestick Chart', + encodings: { x: 'Date', open: 'Open', high: 'High', low: 'Low', close: 'Close' }, + }, + }; + + expect(() => assembleExcel(input)).toThrow('requires coherent OHLC values at row 1'); + expect(() => assembleExcel({ + ...input, + data: { values: [ + { Date: '2026-01-05', Open: 100, High: 108, Low: 98, Close: 105, Ticker: 'A' }, + { Date: '2026-01-02', Open: 105, High: 110, Low: 101, Close: 103, Ticker: 'A' }, + ] }, + })).toThrow('sorted in strictly increasing chronological order'); + expect(() => assembleExcel({ + ...input, + data: { values: [{ Date: '2026-01-02', Open: 100, High: 108, Low: 98, Close: 105, Ticker: 'A' }] }, + chart_spec: { + ...input.chart_spec, + encodings: { ...input.chart_spec.encodings, color: 'Ticker' }, + }, + })).toThrow('does not support color, group, or detail encodings'); + expect(() => assembleExcel({ + ...input, + semantic_types: { ...input.semantic_types, Open: 'Category' }, + data: { values: [{ Date: '2026-01-02', Open: 'start', High: 108, Low: 98, Close: 105, Ticker: 'A' }] }, + })).toThrow('requires a quantitative open field'); + expect(() => assembleExcel({ + ...input, + data: { values: [{ Date: '2026-01-02', Open: 100, High: Number.POSITIVE_INFINITY, Low: 98, Close: 105, Ticker: 'A' }] }, + })).toThrow('requires finite open, high, low, and close values'); + }); + + it('assembleExcel accepts an explicitly ordered date-like Candlestick x field', () => { + const spec = assembleExcel({ + data: { values: [ + { Session: '2026-01-02', Open: 100, High: 108, Low: 98, Close: 105 }, + { Session: '2026-01-05', Open: 105, High: 110, Low: 101, Close: 103 }, + ] }, + semantic_types: { Session: 'Category', Open: 'Quantity', High: 'Quantity', Low: 'Quantity', Close: 'Quantity' }, + chart_spec: { + chartType: 'Candlestick Chart', + encodings: { + x: { field: 'Session', type: 'ordinal' }, + open: 'Open', high: 'High', low: 'Low', close: 'Close', + }, + }, + }) as any; + + expect(spec.chartType).toBe('StockOHLC'); + expect(spec.data.slice(1).map((row: any[]) => row[0])).toEqual([46024, 46027]); + }); + + it('assembleExcel thins dense Candlestick date labels without dropping OHLC rows', () => { + const values = Array.from({ length: 90 }, (_, index) => ({ + Date: new Date(Date.UTC(2026, 0, index + 1)).toISOString().slice(0, 10), + Open: 100 + index, + High: 103 + index, + Low: 98 + index, + Close: 101 + index, + })); + const spec = assembleExcel({ + data: { values }, + semantic_types: { Date: 'Date', Open: 'Quantity', High: 'Quantity', Low: 'Quantity', Close: 'Quantity' }, + chart_spec: { + chartType: 'Candlestick Chart', + encodings: { x: 'Date', open: 'Open', high: 'High', low: 'Low', close: 'Close' }, + baseSize: { width: 640, height: 380 }, + }, + }) as any; + + expect(spec.data).toHaveLength(91); + expect(spec.categoryAxis.tickLabelSpacing).toBe(3); + }); + + it('assembleExcel rejects color-grouped native Boxplots', () => { + expect(() => assembleExcel({ + data: { values: [{ Group: 'A', Value: 1, Segment: 'X' }] }, + semantic_types: { Group: 'Category', Value: 'Quantity', Segment: 'Category' }, + chart_spec: { chartType: 'Boxplot', encodings: { x: 'Group', y: 'Value', color: 'Segment' } }, + })).toThrow('does not yet support color-grouped'); + }); + + it('assembleExcel rejects Boxplot min-max whiskers', () => { + expect(() => assembleExcel({ + data: { values: [{ Group: 'A', Value: 1 }, { Group: 'A', Value: 2 }] }, + semantic_types: { Group: 'Category', Value: 'Quantity' }, + chart_spec: { + chartType: 'Boxplot', + encodings: { x: 'Group', y: 'Value' }, + chartProperties: { whiskerMethod: 'minmax' }, + }, + })).toThrow('does not support min-max whiskers'); + }); + + it('assembleExcel uses native numeric-x lines instead of row-index categories', () => { + const spec = assembleExcel({ + data: { values: [{ X: 0, Value: 2 }, { X: 10, Value: 5 }] }, + semantic_types: { X: 'Quantity', Value: 'Quantity' }, + chart_spec: { chartType: 'Line Chart', encodings: { x: 'X', y: 'Value' } }, + }) as any; + + expect(spec.chartType).toBe('XYScatterLines'); + expect(spec.data).toEqual([['X', 'Value'], [0, 2], [10, 5]]); + expect(spec.categoryAxis).toMatchObject({ minimumScale: 0, maximumScale: 10.5, majorUnit: 2 }); + expect(spec.valueAxis).toMatchObject({ minimumScale: 2, maximumScale: 5.3, majorUnit: 1 }); + }); + + it('assembleExcel binds grouped numeric-x lines as explicit XY series', () => { + const spec = assembleExcel({ + data: { values: [ + { X: 1, Value: 10, Series: 'A' }, + { X: 2, Value: 20, Series: 'A' }, + { X: 1, Value: 30, Series: 'B' }, + ] }, + semantic_types: { X: 'Quantity', Value: 'Quantity', Series: 'Category' }, + chart_spec: { chartType: 'Line Chart', encodings: { x: 'X', y: 'Value', color: 'Series' } }, + }) as any; + + expect(spec.chartType).toBe('XYScatterLines'); + expect(spec.series).toEqual([ + { name: 'A', xColumn: 0, yColumn: 1, rowCount: 2 }, + { name: 'B', xColumn: 2, yColumn: 3, rowCount: 1 }, + ]); + expect(spec.data[0]).toEqual(['A X', 'A Value', 'B X', 'B Value']); + }); + + it('assembleExcel thins dense temporal labels without dropping data points', () => { + const values = Array.from({ length: 60 }, (_value, index) => ({ + Date: new Date(Date.UTC(2026, 0, index + 1)).toISOString().slice(0, 10), + Value: index, + })); + const spec = assembleExcel({ + data: { values }, + semantic_types: { Date: 'Date', Value: 'Quantity' }, + chart_spec: { + chartType: 'Area Chart', + encodings: { x: 'Date', y: 'Value' }, + baseSize: { width: 550, height: 400 }, + }, + }) as any; + + expect(spec.data).toHaveLength(values.length + 1); + expect(spec.categoryAxis.tickLabelSpacing).toBe(2); + }); + + it('assembleExcel emits grouped bubble series with explicit size ranges', () => { + const spec = assembleExcel({ + data: { values: [ + { X: 1, Y: 10, Size: 5, Segment: 'A' }, + { X: 2, Y: 20, Size: 8, Segment: 'B' }, + ] }, + semantic_types: { X: 'Quantity', Y: 'Quantity', Size: 'Quantity', Segment: 'Category' }, + chart_spec: { chartType: 'Scatter Plot', encodings: { x: 'X', y: 'Y', size: 'Size', color: 'Segment' } }, + }) as any; + + expect(spec.kind).toBe('chart'); + expect(spec.chartType).toBe('Bubble'); + expect(spec.series).toEqual([ + { name: 'A', xColumn: 0, yColumn: 1, rowCount: 1, bubbleSizeColumn: 2 }, + { name: 'B', xColumn: 3, yColumn: 4, rowCount: 1, bubbleSizeColumn: 5 }, + ]); + expect(spec.data[0]).toEqual(['A X', 'A Y', 'A Size', 'B X', 'B Y', 'B Size']); + expect(spec.data[1].slice(0, 2)).toEqual([1, 10]); + expect(spec.data[1].slice(3, 5)).toEqual([2, 20]); + expect(spec.data[1][2]).toBeLessThan(spec.data[1][5]); + }); + + it('assembleExcel rejects categorical scatter positions instead of drawing worksheet shapes', () => { + expect(() => assembleExcel({ + data: { values: [ + { Category: 'A', Group: 'One', Size: 3 }, + { Category: 'B', Group: 'Two', Size: 8 }, + ] }, + semantic_types: { Category: 'Category', Group: 'Category', Size: 'Quantity' }, + chart_spec: { chartType: 'Scatter Plot', encodings: { x: 'Category', y: 'Group', size: 'Size' } }, + })).toThrow('requires quantitative x and y fields'); + }); + + it('assembleExcel rejects continuous-color scatter instead of dropping the color encoding', () => { + expect(() => assembleExcel({ + data: { values: [ + { X: 1, Y: 10, Color: 0.2 }, + { X: 2, Y: 20, Color: 0.8 }, + ] }, + semantic_types: { X: 'Quantity', Y: 'Quantity', Color: 'Quantity' }, + chart_spec: { chartType: 'Scatter Plot', encodings: { x: 'X', y: 'Y', color: 'Color' } }, + })).toThrow('does not support continuous color'); + }); + + it('assembleExcel rejects categorical-y lines instead of drawing worksheet geometry', () => { + expect(() => assembleExcel({ + data: { values: [ + { X: 0, Step: 'Stage 1' }, + { X: 50, Step: 'Stage 2' }, + { X: 100, Step: 'Stage 3' }, + ] }, + semantic_types: { X: 'Quantity', Step: 'Category' }, + chart_spec: { chartType: 'Line Chart', encodings: { x: 'X', y: 'Step' } }, + })).toThrow('requires a quantitative y field'); + }); + + it('assembleExcel rejects continuous-color lines instead of overlaying worksheet shapes', () => { + expect(() => assembleExcel({ + data: { values: [ + { Stage: 'Stage 1', Value: 10, Color: 0 }, + { Stage: 'Stage 2', Value: 20, Color: 5 }, + { Stage: 'Stage 3', Value: 15, Color: 10 }, + ] }, + semantic_types: { Stage: 'Category', Value: 'Quantity', Color: 'Quantity' }, + chart_spec: { chartType: 'Line Chart', encodings: { x: 'Stage', y: 'Value', color: 'Color' } }, + })).toThrow('does not support continuous color'); + }); + + it('assembleExcel maps ordinal bubble sizes to finite ordered areas', () => { + const spec = assembleExcel({ + data: { values: [ + { X: 1, Y: 10, Level: 'Low' }, + { X: 2, Y: 20, Level: 'Medium' }, + { X: 3, Y: 30, Level: 'High' }, + ] }, + semantic_types: { X: 'Quantity', Y: 'Quantity', Level: 'Rank' }, + chart_spec: { chartType: 'Scatter Plot', encodings: { x: 'X', y: 'Y', size: 'Level' } }, + }) as any; + + expect(spec.chartType).toBe('Bubble'); + expect(spec.series).toEqual([ + { name: 'Y', xColumn: 0, yColumn: 1, rowCount: 3, bubbleSizeColumn: 2 }, + ]); + const sizes = spec.data.slice(1).map((row: any[]) => row[2]); + expect(sizes.every(Number.isFinite)).toBe(true); + expect(sizes[0]).toBeLessThan(sizes[1]); + expect(sizes[1]).toBeLessThan(sizes[2]); + }); + + it('assembleExcel stacks multi-series areas and anchors them at zero', () => { + const spec = assembleExcel({ + data: { values: [ + { Date: '2026-01-01', Value: 2, Series: 'A' }, + { Date: '2026-01-01', Value: 3, Series: 'B' }, + ] }, + semantic_types: { Date: 'Date', Value: 'Quantity', Series: 'Category' }, + chart_spec: { chartType: 'Area Chart', encodings: { x: 'Date', y: 'Value', color: 'Series' } }, + }) as any; + + expect(spec.chartType).toBe('AreaStacked'); + expect(spec.valueAxis.minimumScale).toBe(0); + }); + + it('assembleExcel resamples quantitative-x areas onto a sparse-labeled numeric grid', () => { + const spec = assembleExcel({ + data: { values: [ + { X: 0, Value: 0 }, + { X: 1, Value: 1 }, + { X: 10, Value: 10 }, + ] }, + semantic_types: { X: 'Quantity', Value: 'Quantity' }, + chart_spec: { chartType: 'Area Chart', encodings: { x: 'X', y: 'Value' } }, + }) as any; + + expect(spec.chartType).toBe('Area'); + expect(spec.data).toHaveLength(50); + expect(spec.data[1]).toEqual(['0', 0]); + expect(spec.data[2][0]).toBe(''); + expect(spec.data[25]).toEqual(['5', 5]); + expect(spec.data[49]).toEqual(['10', 10]); + }); + + it('assembleExcel preserves semantic series and null gaps in sparse grouped bars', () => { + const spec = assembleExcel({ + data: { values: [ + { Region: 'North', Sales: 10, Channel: 'Retail' }, + { Region: 'North', Sales: 20, Channel: 'Online' }, + { Region: 'South', Sales: 30, Channel: 'Online' }, + { Region: 'South', Sales: 40, Channel: 'Direct' }, + ] }, + semantic_types: { Region: 'Category', Sales: 'Quantity', Channel: 'Category' }, + chart_spec: { chartType: 'Grouped Bar Chart', encodings: { x: 'Region', y: 'Sales', group: 'Channel' } }, + }) as any; + + expect(spec.data).toEqual([ + ['Region', 'Retail', 'Online', 'Direct'], + ['North', 10, 20, null], + ['South', null, 30, 40], + ]); + expect(spec.legend).toEqual({ visible: true, position: 'Bottom' }); + expect(spec.gapWidth).toBe(180); + expect(spec.overlap).toBe(0); + }); + + it('assembleExcel keeps horizontal grouped bars compact', () => { + const spec = assembleExcel({ + data: { values: [ + { Region: 'North', Sales: 10, Channel: 'Retail' }, + { Region: 'North', Sales: 20, Channel: 'Online' }, + { Region: 'South', Sales: 30, Channel: 'Direct' }, + ] }, + semantic_types: { Region: 'Category', Sales: 'Quantity', Channel: 'Category' }, + chart_spec: { chartType: 'Grouped Bar Chart', encodings: { x: 'Sales', y: 'Region', group: 'Channel' } }, + }) as any; + + expect(spec.chartType).toBe('BarClustered'); + expect(spec.gapWidth).toBe(120); + expect(spec.overlap).toBe(0); + }); + + it('assembleExcel emits a symmetric two-group native pyramid', () => { + const spec = assembleExcel({ + data: { values: [ + { Age: '0-17', Gender: 'Male', Population: 30 }, + { Age: '0-17', Gender: 'Female', Population: 28 }, + { Age: '18-34', Gender: 'Male', Population: 20 }, + { Age: '18-34', Gender: 'Female', Population: 22 }, + { Age: '18-34', Gender: 'Female', Population: 3 }, + { Age: '35-49', Gender: 'Female', Population: 12 }, + ] }, + semantic_types: { Age: 'Category', Gender: 'Category', Population: 'Quantity' }, + chart_spec: { chartType: 'Pyramid Chart', encodings: { y: 'Age', x: 'Population', color: 'Gender' } }, + }) as any; + + expect(spec.chartType).toBe('BarStacked'); + expect(spec.data).toEqual([ + ['Age', 'Male', 'Female'], + ['0-17', -30, 28], + ['18-34', -20, 25], + ['35-49', null, 12], + ]); + expect(spec.valueAxis).toEqual({ + title: 'Population', + numberFormat: '#,##0;#,##0;0', + minimumScale: -30, + maximumScale: 30, + majorUnit: 10, + }); + expect(spec.seriesFormats).toEqual([{ color: '#4472C4' }, { color: '#C55A5A' }]); + expect(spec.overlap).toBe(100); + }); + + it('assembleExcel rejects pyramids without exactly two groups', () => { + expect(() => assembleExcel({ + data: { values: [ + { Age: '0-17', Gender: 'Female', Population: 28 }, + { Age: '18-34', Gender: 'Female', Population: 22 }, + ] }, + semantic_types: { Age: 'Category', Gender: 'Category', Population: 'Quantity' }, + chart_spec: { chartType: 'Pyramid Chart', encodings: { y: 'Age', x: 'Population', color: 'Gender' } }, + })).toThrow('requires exactly two groups'); + }); + + it('assembleExcel emits a sorted native funnel and aggregates duplicate stages', () => { + const spec = assembleExcel({ + data: { values: [ + { Stage: 'Trial', Count: 20 }, + { Stage: 'Visit', Count: 70 }, + { Stage: 'Trial', Count: 10 }, + { Stage: 'Signup', Count: 50 }, + ] }, + semantic_types: { Stage: 'Category', Count: 'Quantity' }, + chart_spec: { chartType: 'Funnel Chart', encodings: { y: 'Stage', size: 'Count' } }, + }) as any; + + expect(spec.chartType).toBe('Funnel'); + expect(spec.data).toEqual([ + ['Stage', 'Count'], + ['Visit', 70], + ['Signup', 50], + ['Trial', 30], + ]); + expect(spec.legend).toEqual({ visible: false }); + expect(spec.dataLabels).toEqual({ + visible: true, + numberFormat: undefined, + fontColor: '#FFFFFF', + fontSize: 11, + }); + expect(spec.seriesFormats).toEqual([{ color: '#4472C4' }]); + }); + + it('assembleExcel rejects negative native funnel values', () => { + expect(() => assembleExcel({ + data: { values: [ + { Stage: 'Visit', Count: 70 }, + { Stage: 'Refund', Count: -5 }, + ] }, + semantic_types: { Stage: 'Category', Count: 'Quantity' }, + chart_spec: { chartType: 'Funnel Chart', encodings: { y: 'Stage', size: 'Count' } }, + })).toThrow('requires non-negative values'); + }); + + it('assembleExcel emits a two-level native treemap and aggregates duplicate leaves', () => { + const spec = assembleExcel({ + data: { values: [ + { Region: 'Americas', Country: 'USA', Revenue: 20 }, + { Region: 'Europe', Country: 'France', Revenue: 30 }, + { Region: 'Americas', Country: 'USA', Revenue: 10 }, + { Region: 'Americas', Country: 'Canada', Revenue: 15 }, + ] }, + semantic_types: { Region: 'Category', Country: 'Country', Revenue: 'Amount' }, + chart_spec: { chartType: 'Treemap', encodings: { color: 'Region', detail: 'Country', size: 'Revenue' } }, + }) as any; + + expect(spec.chartType).toBe('Treemap'); + expect(spec.data).toEqual([ + ['Region', 'Country', 'Revenue'], + ['Americas', 'USA', 30], + ['Europe', 'France', 30], + ['Americas', 'Canada', 15], + ]); + expect(spec.legend).toEqual({ visible: false }); + }); + + it('assembleExcel rejects negative native treemap values', () => { + expect(() => assembleExcel({ + data: { values: [{ Sector: 'Energy', Value: -10 }] }, + semantic_types: { Sector: 'Category', Value: 'Quantity' }, + chart_spec: { chartType: 'Treemap', encodings: { color: 'Sector', size: 'Value' } }, + })).toThrow('requires non-negative values'); + }); + + it('assembleExcel emits a two-level native sunburst and aggregates duplicate leaves', () => { + const spec = assembleExcel({ + data: { values: [ + { Department: 'Engineering', Team: 'Frontend', Headcount: 20 }, + { Department: 'Product', Team: 'Design', Headcount: 15 }, + { Department: 'Engineering', Team: 'Frontend', Headcount: 10 }, + { Department: 'Engineering', Team: 'Backend', Headcount: 25 }, + ] }, + semantic_types: { Department: 'Category', Team: 'Category', Headcount: 'Quantity' }, + chart_spec: { chartType: 'Sunburst Chart', encodings: { color: 'Department', group: 'Team', size: 'Headcount' } }, + }) as any; + + expect(spec.chartType).toBe('Sunburst'); + expect(spec.data).toEqual([ + ['Department', 'Team', 'Headcount'], + ['Engineering', 'Frontend', 30], + ['Product', 'Design', 15], + ['Engineering', 'Backend', 25], + ]); + expect(spec.legend).toEqual({ visible: false }); + }); + + it('assembleExcel rejects a sunburst detail field without a group level', () => { + expect(() => assembleExcel({ + data: { values: [{ Department: 'Engineering', Team: 'Frontend', Headcount: 20 }] }, + semantic_types: { Department: 'Category', Team: 'Category', Headcount: 'Quantity' }, + chart_spec: { chartType: 'Sunburst Chart', encodings: { color: 'Department', detail: 'Team', size: 'Headcount' } }, + })).toThrow('requires a group field before detail'); + }); + + it('assembleExcel emits connected scatter points in explicit path order', () => { + const spec = assembleExcel({ + data: { values: [ + { Step: 3, X: 0, Y: 1 }, + { Step: 1, X: 2, Y: 0 }, + { Step: 4, X: 1, Y: 0 }, + { Step: 2, X: 1, Y: 2 }, + ] }, + semantic_types: { Step: 'Quantity', X: 'Quantity', Y: 'Quantity' }, + chart_spec: { chartType: 'Connected Scatter Plot', encodings: { x: 'X', y: 'Y', order: 'Step' } }, + }) as any; + + expect(spec.chartType).toBe('XYScatterLines'); + expect(spec.data).toEqual([ + ['X', 'Y'], + [2, 0], + [1, 2], + [0, 1], + [1, 0], + ]); + }); + + it('assembleExcel requires connected scatter order', () => { + expect(() => assembleExcel({ + data: { values: [{ X: 1, Y: 2 }] }, + semantic_types: { X: 'Quantity', Y: 'Quantity' }, + chart_spec: { chartType: 'Connected Scatter Plot', encodings: { x: 'X', y: 'Y' } }, + })).toThrow('requires an explicit order field'); + }); + + it('assembleExcel keeps scatter axes close to the data extent', () => { + const spec = assembleExcel({ + data: { values: [ + { X: 0, Y: 0 }, + { X: 100, Y: 100 }, + ] }, + semantic_types: { X: 'Quantity', Y: 'Quantity' }, + chart_spec: { chartType: 'Scatter Plot', encodings: { x: 'X', y: 'Y' } }, + }) as any; + + expect(spec.categoryAxis).toMatchObject({ minimumScale: 0, maximumScale: 105, majorUnit: 20 }); + expect(spec.valueAxis).toMatchObject({ minimumScale: 0, maximumScale: 105, majorUnit: 20 }); + }); + + it('assembleExcel uses a sequential scale for ordered grouped-bar series', () => { + const spec = assembleExcel({ + data: { values: [ + { Category: 'A', Value: 10, Rank: 1 }, + { Category: 'A', Value: 20, Rank: 2 }, + { Category: 'B', Value: 30, Rank: 1 }, + { Category: 'B', Value: 40, Rank: 2 }, + ] }, + semantic_types: { Category: 'Category', Value: 'Quantity', Rank: 'Rank' }, + chart_spec: { chartType: 'Grouped Bar Chart', encodings: { x: 'Category', y: 'Value', group: 'Rank' } }, + }) as any; + + expect(spec.seriesFormats.map((format: any) => format.color)).toEqual(['#d9e2f3', '#2f5597']); + }); + + it('assembleExcel rejects occupancy matrices instead of drawing worksheet heatmaps', () => { + expect(() => assembleExcel({ + data: { values: [ + { Category: 'A', Group: 'North', Segment: 'Sales' }, + { Category: 'B', Group: 'South', Segment: 'Engineering' }, + ] }, + semantic_types: { Category: 'Category', Group: 'Category', Segment: 'Category' }, + chart_spec: { chartType: 'Grouped Bar Chart', encodings: { x: 'Category', y: 'Group', group: 'Segment' } }, + })).toThrow('requires one quantitative measure axis'); + }); + + it('assembleExcel caps dense categorical bars in the default display order', () => { + const values = Array.from({ length: 96 }, (_value, index) => ({ + Group: `Category ${index + 1}`, + Value: (index * 37) % 101, + })); + const input = { + data: { values }, + semantic_types: { Group: 'Category', Value: 'Quantity' }, + chart_spec: { + chartType: 'Bar Chart', + encodings: { x: 'Value', y: 'Group' }, + baseSize: { width: 560, height: 360 }, + }, + } as const; + + const excel = assembleExcel(input) as any; + const vegaLite = assembleVegaLite(input) as any; + const expectedOrder = vegaLite.encoding.y.scale.domain.filter((value: string) => + !value.includes('items omitted'), + ); + + expect(excel.data.slice(1).map((row: any[]) => row[0])).toEqual(expectedOrder); + expect(expectedOrder).toEqual(values.slice(0, expectedOrder.length).map((row) => row.Group)); + expect(excel.data.length).toBeLessThan(values.length + 1); + expect(excel.categoryAxis.labelFontSize).toBe(5); + }); + + it('assembleExcel caps dense bars using the selected value sort', () => { + const values = Array.from({ length: 96 }, (_value, index) => ({ + Group: `Category ${index + 1}`, + Value: index, + })); + const input = { + data: { values }, + semantic_types: { Group: 'Category', Value: 'Quantity' }, + chart_spec: { + chartType: 'Bar Chart', + encodings: { + x: 'Value', + y: { field: 'Group', sortBy: 'x', sortOrder: 'descending' as const }, + }, + baseSize: { width: 560, height: 360 }, + }, + }; + + const excel = assembleExcel(input as any) as any; + const kept = excel.data.slice(1).map((row: any[]) => row[0]); + + expect(kept).toEqual(values.slice(-kept.length).reverse().map((row) => row.Group)); + }); + + it('assembleExcel interpolates sparse connected series', () => { + const spec = assembleExcel({ + data: { values: [ + { Date: '2026-01-01', Value: 10, Series: 'A' }, + { Date: '2026-01-02', Value: 20, Series: 'B' }, + { Date: '2026-01-03', Value: 30, Series: 'A' }, + ] }, + semantic_types: { Date: 'Date', Value: 'Quantity', Series: 'Category' }, + chart_spec: { chartType: 'Area Chart', encodings: { x: 'Date', y: 'Value', color: 'Series' } }, + }) as any; + + expect(spec.data).toEqual([ + ['Date', 'A', 'B'], + ['2026-01-01', 10, null], + ['2026-01-02', 20, 20], + ['2026-01-03', 30, null], + ]); + }); + + it('assembleExcel rejects continuous-color lines as unsupported native charts', () => { + expect(() => assembleExcel({ + data: { values: [ + { Date: '2026-01-01', Value: 10, Color: 0.2 }, + { Date: '2026-01-02', Value: 12, Color: 0.8 }, + ] }, + semantic_types: { Date: 'Date', Value: 'Quantity', Color: 'Quantity' }, + chart_spec: { chartType: 'Line Chart', encodings: { x: 'Date', y: 'Value', color: 'Color' } }, + })).toThrow('does not support continuous color'); + }); + + it('assembleExcel preserves forecast handoffs as styled dash series', () => { + const spec = assembleExcel({ + data: { values: [ + { Date: '2026-01-01', Value: 10, Type: 'actual' }, + { Date: '2026-01-02', Value: 12, Type: 'actual' }, + { Date: '2026-01-02', Value: 12, Type: 'forecast' }, + { Date: '2026-01-03', Value: 15, Type: 'forecast' }, + ] }, + semantic_types: { Date: 'Date', Value: 'Quantity', Type: 'Category' }, + chart_spec: { chartType: 'Line Chart', encodings: { x: 'Date', y: 'Value', strokeDash: 'Type' } }, + }) as any; + + expect(spec.data).toEqual([ + ['Date', 'actual', 'forecast'], + ['2026-01-01', 10, null], + ['2026-01-02', 12, 12], + ['2026-01-03', null, 15], + ]); + expect(spec.seriesFormats).toEqual([ + { color: '#4472C4', lineStyle: 'Continuous' }, + { color: '#4472C4', lineStyle: 'Dash' }, + ]); + }); + it('line chart with quantitative color uses a line layer plus colored points', () => { const spec = assembleVegaLite({ data: { diff --git a/packages/flint-js/tsup.config.ts b/packages/flint-js/tsup.config.ts index 860a3862..519b97fa 100644 --- a/packages/flint-js/tsup.config.ts +++ b/packages/flint-js/tsup.config.ts @@ -7,6 +7,8 @@ export default defineConfig({ 'vegalite/index': 'src/vegalite/index.ts', 'echarts/index': 'src/echarts/index.ts', 'chartjs/index': 'src/chartjs/index.ts', + 'plotly/index': 'src/plotly/index.ts', + 'excel/index': 'src/excel/index.ts', 'test-data/index': 'src/test-data/index.ts', 'gallery/index': 'src/gallery/index.ts', }, @@ -17,5 +19,5 @@ export default defineConfig({ splitting: false, treeshake: true, target: 'es2020', - external: ['vega', 'vega-lite', 'echarts', 'chart.js'], + external: ['vega', 'vega-lite', 'echarts', 'chart.js', 'plotly.js'], }); diff --git a/packages/flint-mcp/assets/flint-chart-author.SKILL.md b/packages/flint-mcp/assets/flint-chart-author.SKILL.md index c05dee2d..3b3fbedc 100644 --- a/packages/flint-mcp/assets/flint-chart-author.SKILL.md +++ b/packages/flint-mcp/assets/flint-chart-author.SKILL.md @@ -250,8 +250,8 @@ support a subset (verify if targeting a non-VL backend): `"Funnel"`, `"Treemap"`, `"Sunburst"`, `"Sankey"`, `"Parallel Coordinates"`, `"Graph"`, `"Tree"`. - **Chart.js** supports: Scatter, Bubble, Bar, Grouped Bar, Stacked Bar, - Combo, Line, Area, Range Area, Pie, Doughnut, Histogram, Radar, Rose, Slope, - Connected Scatter. + Combo, Line, Bump, Area, Range Area, Pie, Doughnut, Histogram, Radar, Rose, + Slope, Connected Scatter. You do not need to call the library or inspect its source to author the input — pick from this table. diff --git a/packages/flint-mcp/package.json b/packages/flint-mcp/package.json index 73defe50..a2f2799d 100644 --- a/packages/flint-mcp/package.json +++ b/packages/flint-mcp/package.json @@ -1,7 +1,7 @@ { "name": "flint-chart-mcp", - "version": "0.3.0", - "description": "Model Context Protocol server for Flint — compile, validate, and render semantic chart specs to Vega-Lite, ECharts, or Chart.js artifacts (PNG/SVG) in-process.", + "version": "0.4.0", + "description": "Model Context Protocol server for Flint — compile, validate, and render semantic chart specs across supported backends.", "keywords": [ "mcp", "model-context-protocol", @@ -68,7 +68,7 @@ "@resvg/resvg-js": "^2.6.2", "chart.js": "^4.4.0", "echarts": "^6.0.0", - "flint-chart": "^0.3.0", + "flint-chart": "^0.4.0", "vega": "^6.0.0", "vega-interpreter": "^2.2.1", "vega-lite": "^6.0.0", diff --git a/packages/flint-py/flint/core/filter_overflow.py b/packages/flint-py/flint/core/filter_overflow.py index 142a0f4a..5cb7e3b4 100644 --- a/packages/flint-py/flint/core/filter_overflow.py +++ b/packages/flint-py/flint/core/filter_overflow.py @@ -90,13 +90,13 @@ def is_discrete_type(t: Optional[str]) -> bool: warnings.append({ "severity": "warning", "code": "overflow", - "message": f"{omitted_count} of {len(unique_values)} values in '{field_name}' were omitted (showing top {len(values_to_keep)}).", + "message": f"{omitted_count} of {len(unique_values)} values in '{field_name}' were omitted (showing first {len(values_to_keep)} in sort order).", "channel": channel, "field": field_name, }) truncations.append({ "severity": "warning", "code": "overflow", - "message": f"{omitted_count} of {len(unique_values)} values in '{field_name}' were omitted (showing top {len(values_to_keep)}).", + "message": f"{omitted_count} of {len(unique_values)} values in '{field_name}' were omitted (showing first {len(values_to_keep)} in sort order).", "channel": channel, "field": field_name, "keptValues": values_to_keep, "omittedCount": omitted_count, "placeholder": placeholder, @@ -133,15 +133,13 @@ def _default_overflow_strategy( encodings = context["encodings"] all_mark_types = context["allMarkTypes"] - has_connected_mark = ("line" in all_mark_types) or ("area" in all_mark_types) or ("trail" in all_mark_types) - encoding = encodings.get(channel) or {} sort_by = encoding.get("sortBy") sort_order = encoding.get("sortOrder") sort_field: Optional[str] = None sort_field_type: Optional[str] = None - is_descending = True + is_descending = False if sort_by: if sort_by in ("x", "y", "color"): @@ -158,40 +156,7 @@ def _default_overflow_strategy( except Exception: pass is_descending = sort_order == "descending" - else: - opposite_channel = "y" if channel == "x" else ("x" if channel == "y" else None) - color_cs = channel_semantics.get("color") - opposite_cs = channel_semantics.get(opposite_channel) if opposite_channel else None - - mark_type = "rect" if "rect" in all_mark_types else None - if mark_type != "rect" and color_cs and color_cs.get("type") == "quantitative": - sort_field = color_cs.get("field") - sort_field_type = color_cs.get("type") - elif opposite_cs and opposite_cs.get("type") == "quantitative": - sort_field = opposite_cs.get("field") - sort_field_type = opposite_cs.get("type") - else: - is_descending = False - - field_original_type = infer_vis_category([r.get(field_name) for r in data]) - if field_original_type == "quantitative" or channel == "color": - # JS sort: a - b; if values are strings of numbers, JS still treats them - # as numbers via -; preserve that - def numeric_key(v: Any) -> float: - try: - return float(v) - except (TypeError, ValueError): - return float("nan") - return sorted(unique_values, key=numeric_key)[:max_to_keep] - - if channel in ("column", "row"): - return unique_values[:max_to_keep] - - if has_connected_mark: - return unique_values[:max_to_keep] - if sort_field and sort_field_type == "quantitative": - # Bar charts: sum aggregate. Others: max. is_bar = ("bar" in all_mark_types) and ( sort_field != (channel_semantics.get("color", {}) or {}).get("field") ) @@ -203,7 +168,6 @@ def numeric_key(v: Any) -> float: initial_value = float("-inf") value_aggregates: dict[Any, float] = {} - seen_first: dict[Any, bool] = {} for row in data: field_value = row.get(field_name) sort_value = row.get(sort_field) or 0 @@ -216,7 +180,31 @@ def numeric_key(v: Any) -> float: entries.sort(key=lambda e: -e[1] if is_descending else e[1]) return [e[0] for e in entries[:max_to_keep]] + canonical_order = (channel_semantics.get(channel) or {}).get("ordinalSortOrder") + if not sort_by and not sort_order and canonical_order: + ordered = [value for value in canonical_order if value in unique_values] + ordered_set = set(ordered) + ordered.extend(value for value in unique_values if value not in ordered_set) + return ordered[:max_to_keep] + + field_original_type = infer_vis_category([r.get(field_name) for r in data]) + if field_original_type == "quantitative" or channel == "color": + # JS sort: a - b; if values are strings of numbers, JS still treats them + # as numbers via -; preserve that + def numeric_key(v: Any) -> float: + try: + return float(v) + except (TypeError, ValueError): + return float("nan") + return sorted(unique_values, key=numeric_key)[:max_to_keep] + + if channel in ("column", "row"): + return unique_values[:max_to_keep] + if sort_order == "descending": - return list(reversed(unique_values))[:max_to_keep] + return sorted(unique_values, key=_js_sort_key, reverse=True)[:max_to_keep] + + if sort_order == "ascending": + return sorted(unique_values, key=_js_sort_key)[:max_to_keep] return unique_values[:max_to_keep] diff --git a/packages/flint-py/tests/unit/test_filter_overflow.py b/packages/flint-py/tests/unit/test_filter_overflow.py new file mode 100644 index 00000000..1469d5f4 --- /dev/null +++ b/packages/flint-py/tests/unit/test_filter_overflow.py @@ -0,0 +1,74 @@ +from __future__ import annotations + +from flint.core.filter_overflow import filter_overflow + + +BUDGETS = {"maxValues": {"x": 3}} +MARKS = {"bar"} + + +def kept_categories(data, category_semantics, category_encoding): + result = filter_overflow( + { + "x": { + "field": "Category", + "semanticAnnotation": {"semanticType": "Category"}, + **category_semantics, + }, + "y": { + "field": "Value", + "type": "quantitative", + "semanticAnnotation": {"semanticType": "Quantity"}, + }, + }, + {"axisFlags": {"x": {"banded": True}}}, + { + "x": {"field": "Category", **category_encoding}, + "y": {"field": "Value"}, + }, + data, + BUDGETS, + MARKS, + ) + return result["truncations"][0]["keptValues"] + + +def test_preserves_encounter_order_when_no_sort_is_selected(): + data = [ + {"Category": "Delta", "Value": 100}, + {"Category": "Alpha", "Value": 1}, + {"Category": "Charlie", "Value": 80}, + {"Category": "Bravo", "Value": 50}, + ] + + assert kept_categories(data, {"type": "nominal"}, {}) == ["Delta", "Alpha", "Charlie"] + + +def test_uses_canonical_semantic_order_when_available(): + data = [ + {"Category": "Mar", "Value": 100}, + {"Category": "Jan", "Value": 1}, + {"Category": "Apr", "Value": 80}, + {"Category": "Feb", "Value": 50}, + ] + + assert kept_categories( + data, + {"type": "ordinal", "ordinalSortOrder": ["Jan", "Feb", "Mar", "Apr"]}, + {}, + ) == ["Jan", "Feb", "Mar"] + + +def test_uses_selected_value_sort(): + data = [ + {"Category": "Delta", "Value": 100}, + {"Category": "Alpha", "Value": 1}, + {"Category": "Charlie", "Value": 80}, + {"Category": "Bravo", "Value": 50}, + ] + + assert kept_categories( + data, + {"type": "nominal"}, + {"sortBy": "y", "sortOrder": "descending"}, + ) == ["Delta", "Charlie", "Bravo"] diff --git a/scripts/gen-chart-reference.ts b/scripts/gen-chart-reference.ts index 5b8f8e48..16e57c54 100644 --- a/scripts/gen-chart-reference.ts +++ b/scripts/gen-chart-reference.ts @@ -18,12 +18,16 @@ import { fileURLToPath } from 'node:url'; import { dirname, resolve } from 'node:path'; import type { ChartTemplateDef, ChartPropertyDef } from '../packages/flint-js/src/core/types'; +import type { ExcelTemplateDef } from '../packages/flint-js/src/excel/templates/types'; import { vlTemplateDefs } from '../packages/flint-js/src/vegalite/templates/index'; import { ecTemplateDefs } from '../packages/flint-js/src/echarts/templates/index'; import { cjsTemplateDefs } from '../packages/flint-js/src/chartjs/templates/index'; +import { plTemplateDefs } from '../packages/flint-js/src/plotly/templates/index'; +import { excelAllTemplateDefs } from '../packages/flint-js/src/excel/templates/index'; const __dirname = dirname(fileURLToPath(import.meta.url)); const DOCS_DIR = resolve(__dirname, '../docs'); +const ZH_DOCS_DIR = resolve(DOCS_DIR, 'zh-CN'); type CategorizedDefs = { [category: string]: ChartTemplateDef[] }; @@ -64,6 +68,19 @@ const BACKENDS: BackendSpec[] = [ 'The Chart.js backend is the lightweight embedding target for common chart families. It keeps the ' + 'parameter surface intentionally small.', }, + { + name: 'Plotly', + file: 'reference-plotly.md', + defs: plTemplateDefs, + blurb: + 'The Plotly backend compiles to a Plotly.js figure (`{ data, layout }`) and leans on Plotly-native ' + + 'trace types wherever one exists (candlestick, box, violin, heatmap, waterfall, `scatterpolar`/`barpolar`, ' + + '`indicator`, `scattergeo`/`choropleth`) instead of hand-building the mark. Funnel and Gauge have no ' + + 'Vega-Lite equivalent and showcase Plotly-specific native primitives. Map and Choropleth use Plotly\'s ' + + 'own built-in geo atlas (no external TopoJSON fetch/join needed). Sparkline and Bar Table are ' + + 'composite, self-contained figures (their own multi-axis-pair grid + annotations) rather than the ' + + 'generic column/row facet combiner.', + }, ]; /** @@ -111,6 +128,54 @@ const PARAM_DESCRIPTIONS: Record = { maWindow: 'Moving-average window size.', }; +const ZH_PARAM_DESCRIPTIONS: Record = { + opacity: '标记不透明度。', + fillOpacity: '区域填充不透明度。', + dotSize: '点标记大小。', + cornerRadius: '受支持标记的圆角半径。', + taskHeight: '任务条占每行高度的百分比。', + intervalLabels: '在任务区间上显示文本。', + interpolate: '线或区域的插值方式。', + showPoints: '在线上叠加点标记。', + showTextLabels: '在标记上显示数值标签。', + showPercent: '将数值显示为总量百分比。', + stackMode: '重叠系列的堆叠策略。', + binCount: '最大分箱数。', + bandwidth: '核密度带宽,0 表示自动。', + innerRadius: '内半径占外半径的百分比。', + filled: '填充雷达图围成的区域。', + maxRows: '最多显示的表格行数。', + regressionMethod: '回归拟合方法。', + polyOrder: '多项式回归阶数。', + showMA: '显示移动平均线。', + maWindow: '移动平均窗口大小。', + totals: '瀑布图总计标记。', + showOutliers: '显示离群点。', + showBox: '显示内部箱体。', + sortSlices: '扇区排序方式。', + labelType: '标签内容。', + layout: '布局方向。', + baseline: '参考基线。', + trendWidth: '迷你趋势图宽度。', + region: '地图区域。', + projection: '地图投影。', + projectionCenter: '地图投影中心。', + sort: '有序阶段或类别的排序方式。', + min: '最小值。', + max: '最大值。', +}; + +const ZH_CATEGORY_NAMES: Record = { + 'Scatter & Point': '散点与点图', + Bar: '条形图', + Distributions: '分布图', + 'Line & Area': '折线与区域图', + Circular: '圆形图', + 'Tables & KPIs': '表格与 KPI', + Maps: '地图', + Opportunity: 'Plotly 特有图表', +}; + /** * Chart-type name → icon SVG basename (under site/src/assets/chart-icons/). * Used to render a small glyph next to each chart heading. Names match the @@ -151,6 +216,7 @@ const ICON_BY_CHART: Record = { 'Range Area Chart': 'chart-icon-range-area.svg', 'Pie Chart': 'chart-icon-pie.svg', 'Doughnut Chart': 'chart-icon-doughnut.svg', + 'Donut Chart': 'chart-icon-doughnut.svg', 'Scatter Pie Chart': 'chart-icon-pie.svg', 'Rose Chart': 'chart-icon-rose.svg', 'Radar Chart': 'chart-icon-radar.svg', @@ -325,6 +391,132 @@ function renderBackend(spec: BackendSpec): string { return out.join('\n').replace(/\n{3,}/g, '\n\n').trimEnd() + '\n'; } +function renderChartZh(def: ChartTemplateDef): string { + const lines: string[] = []; + const icon = ICON_BY_CHART[def.chart]; + lines.push(`### ${icon ? `![](${icon}) ` : ''}${def.chart}`, ''); + const channels = (def.channels ?? []).map((channel) => `\`${channel}\``).join(', ') || '_无_'; + lines.push(`**编码通道:** ${channels}`, ''); + const props = def.properties ?? []; + if (props.length === 0) return [...lines, '_无模板专用参数。_', ''].join('\n'); + lines.push('| 参数 | 控件 | 取值范围 | 默认值 | 可用性 | 说明 |', '|---|---|---|---|---|---|'); + for (const property of props) { + lines.push( + `| \`${property.key}\` | ${controlLabel(property)} | ${domain(property)} | ${defaultValue(property)} | ${availability(property)} | ${ZH_PARAM_DESCRIPTIONS[property.key] ?? describe(property)} |`, + ); + } + lines.push(''); + return lines.join('\n'); +} + +function renderPlotlyZh(): string { + const out = [ + '# Plotly 图表参考', + '', + '> 本页由实时图表模板注册表生成(`scripts/gen-chart-reference.ts`)。请勿手动编辑;请运行 `npm run gen:reference`。', + '', + 'Plotly 后端编译为 Plotly.js `{ data, layout }` 图形,并优先使用原生 trace 类型。地图使用 Plotly 内置地理图集,无需外部 TopoJSON。', + '', + '## 本页内容', + '', + `本参考列出 Plotly 后端当前支持的 ${Object.values(plTemplateDefs).flat().length} 种图表,分为 ${Object.keys(plTemplateDefs).length} 类。图表名称必须与 \`chart_spec.chartType\` 中的值完全一致。`, + '', + '- **编码通道**:`chart_spec.encodings` 接受的视觉角色。', + '- **选项**:模板专用的 `chart_spec.chartProperties` 键及其取值范围、默认值和可用性。', + '', + '## 设置编码与选项', + '', + '```jsonc', + '{', + ' "chartType": "Bar Chart",', + ' "encodings": { "x": { "field": "category" }, "y": { "field": "value" } },', + ' "chartProperties": { "cornerRadius": 4, "stackMode": "normalize" }', + '}', + '```', + '', + '可用性为 `conditional` 的参数仅在数据和编码适用时生效;不适用的参数会被 assembler 忽略。', + '', + ]; + for (const [category, defs] of Object.entries(plTemplateDefs)) { + out.push(`## ${ZH_CATEGORY_NAMES[category] ?? category}`, ''); + for (const def of defs) out.push(renderChartZh(def)); + } + return out.join('\n').replace(/\n{3,}/g, '\n\n').trimEnd() + '\n'; +} + +function excelNativeTypes(def: ExcelTemplateDef): string { + const { vertical, horizontal } = def.typeMapping; + return horizontal && horizontal !== vertical ? `\`${vertical}\` / \`${horizontal}\`` : `\`${vertical}\``; +} + +function renderExcelReference(locale: 'en' | 'zh-CN'): string { + const zh = locale === 'zh-CN'; + const out = [ + `# ${zh ? 'Excel 图表参考' : 'Excel chart reference'}`, + '', + zh + ? '> 本页由实时 Excel 图表模板注册表生成(`scripts/gen-chart-reference.ts`)。请勿手动编辑;请运行 `npm run gen:reference`。' + : '> This page is generated from the live Excel chart-template registry (`scripts/gen-chart-reference.ts`). Do not edit it by hand — run `npm run gen:reference`.', + '', + zh + ? 'Excel 后端把 Flint 规范编译为带版本的原生图表工件,再由 Office.js 在 Excel 工作簿中创建可编辑图表。' + : 'The Excel backend compiles a Flint specification into a versioned native-chart artifact, which Office.js turns into an editable chart in an Excel workbook.', + '', + `## ${zh ? '支持的图表' : 'Supported charts'}`, + '', + zh + ? `当前支持 ${excelAllTemplateDefs.length} 种图表。请在 \`chart_spec.chartType\` 中使用下表所示的精确名称。` + : `The backend currently supports ${excelAllTemplateDefs.length} chart types. Use the exact name shown below in \`chart_spec.chartType\`.`, + '', + zh + ? '| Flint 图表类型 | 编码通道 | 原生 `Excel.ChartType` |' + : '| Flint chart type | Encoding channels | Native `Excel.ChartType` |', + '|---|---|---|', + ...excelAllTemplateDefs.map((def) => { + const channels = def.channels.map((channel) => `\`${channel}\``).join(', '); + return `| ${def.chart} | ${channels} | ${excelNativeTypes(def)} |`; + }), + '', + `## ${zh ? '编译与渲染' : 'Compile and render'}`, + '', + zh + ? '`assembleExcel(input)` 返回一个 `flint.excel.chart/v1` 工件。它描述工作表数据矩阵、原生图表类型、系列绑定、坐标轴、图例、标签及格式,但不会自行打开 Excel。' + : '`assembleExcel(input)` returns a `flint.excel.chart/v1` artifact. It describes the worksheet data matrix, native chart type, series bindings, axes, legend, labels, and formatting, but does not open Excel itself.', + '', + '```ts', + "import { assembleExcel, renderExcelChart } from 'flint-chart';", + '', + 'const artifact = assembleExcel(input);', + 'const result = await renderExcelChart(Excel, artifact);', + '```', + '', + zh + ? '`renderExcelChart` 必须在提供 Office.js `Excel.run` 和 `Excel.ImageFittingMode.fit` 的 Excel 宿主中运行。它会在活动工作表中创建原生图表,并返回由 `Chart.getImage()` 捕获的 PNG。' + : '`renderExcelChart` must run in an Excel host that provides Office.js `Excel.run` and `Excel.ImageFittingMode.fit`. It creates a native chart on the active worksheet and returns a PNG captured through `Chart.getImage()`.', + '', + zh + ? '若需要可移植的 Office.js 源码而不是立即执行,可调用 `generateOfficeJs(artifact)`。' + : 'Call `generateOfficeJs(artifact)` when you need portable Office.js source instead of immediate execution.', + '', + `## ${zh ? '限制' : 'Limitations'}`, + '', + zh + ? '- 一个原生 Excel 图表不支持 Flint 的 `column` 或 `row` 分面。' + : '- A single native Excel chart does not support Flint `column` or `row` facets.', + zh + ? '- 没有原生 Excel 对应类型的图表(例如 Heatmap)会在渲染前被拒绝。' + : '- Chart types without a native Excel equivalent, such as Heatmap, are rejected before rendering.', + zh + ? '- 部分图表有更严格的数据要求;例如散点图要求定量 `x` 和 `y`,蜡烛图要求 `open`、`high`、`low`、`close` 通道。Assembler 会返回具体的验证错误。' + : '- Some charts impose stricter data requirements. For example, scatter charts require quantitative `x` and `y`, while candlesticks require `open`, `high`, `low`, and `close`. The assembler reports a specific validation error.', + '', + zh + ? '可使用 `excelGetTemplateDef(chartType)` 或 `excelGetTemplateChannels(chartType)` 在编译前检查支持情况。' + : 'Use `excelGetTemplateDef(chartType)` or `excelGetTemplateChannels(chartType)` to check support before compiling.', + ]; + return out.join('\n') + '\n'; +} + for (const spec of BACKENDS) { const md = renderBackend(spec); const path = resolve(DOCS_DIR, spec.file); @@ -333,3 +525,14 @@ for (const spec of BACKENDS) { // eslint-disable-next-line no-console console.log(`Wrote ${spec.file} (${total} chart types)`); } + +for (const [locale, directory] of [['en', DOCS_DIR], ['zh-CN', ZH_DOCS_DIR]] as const) { + const file = 'reference-excel.md'; + writeFileSync(resolve(directory, file), renderExcelReference(locale), 'utf8'); + // eslint-disable-next-line no-console + console.log(`Wrote ${locale === 'en' ? file : `zh-CN/${file}`} (${excelAllTemplateDefs.length} chart types)`); +} + +writeFileSync(resolve(ZH_DOCS_DIR, 'reference-plotly.md'), renderPlotlyZh(), 'utf8'); +// eslint-disable-next-line no-console +console.log(`Wrote zh-CN/reference-plotly.md (${Object.values(plTemplateDefs).flat().length} chart types)`); diff --git a/site/package.json b/site/package.json index 72d39abd..c571b937 100644 --- a/site/package.json +++ b/site/package.json @@ -16,6 +16,7 @@ "@uiw/react-codemirror": "^4.23.0", "chart.js": "^4.5.1", "echarts": "^6.0.0", + "plotly.js-dist-min": "^2.35.2", "flint-chart": "*", "i18next": "^26.3.6", "katex": "^0.17.0", @@ -23,7 +24,7 @@ "react-dom": "^18.3.1", "react-i18next": "^17.0.10", "react-markdown": "^10.1.0", - "react-router-dom": "^6.30.4", + "react-router-dom": "^7.18.1", "react-syntax-highlighter": "^16.1.1", "rehype-katex": "^7.0.1", "remark-gfm": "^4.0.1", diff --git a/site/src/assets/excel-gallery/candlestick.png b/site/src/assets/excel-gallery/candlestick.png new file mode 100644 index 00000000..f6122948 Binary files /dev/null and b/site/src/assets/excel-gallery/candlestick.png differ diff --git a/site/src/assets/excel-gallery/grouped-bar.png b/site/src/assets/excel-gallery/grouped-bar.png new file mode 100644 index 00000000..3f0be9e2 Binary files /dev/null and b/site/src/assets/excel-gallery/grouped-bar.png differ diff --git a/site/src/assets/excel-gallery/multi-series-line.png b/site/src/assets/excel-gallery/multi-series-line.png new file mode 100644 index 00000000..a615c45d Binary files /dev/null and b/site/src/assets/excel-gallery/multi-series-line.png differ diff --git a/site/src/assets/excel-gallery/pyramid.png b/site/src/assets/excel-gallery/pyramid.png new file mode 100644 index 00000000..65094aa5 Binary files /dev/null and b/site/src/assets/excel-gallery/pyramid.png differ diff --git a/site/src/assets/excel-gallery/radar.png b/site/src/assets/excel-gallery/radar.png new file mode 100644 index 00000000..6d848425 Binary files /dev/null and b/site/src/assets/excel-gallery/radar.png differ diff --git a/site/src/assets/excel-gallery/stacked-area.png b/site/src/assets/excel-gallery/stacked-area.png new file mode 100644 index 00000000..4e713b46 Binary files /dev/null and b/site/src/assets/excel-gallery/stacked-area.png differ diff --git a/site/src/assets/excel-gallery/sunburst.png b/site/src/assets/excel-gallery/sunburst.png new file mode 100644 index 00000000..ca3511f9 Binary files /dev/null and b/site/src/assets/excel-gallery/sunburst.png differ diff --git a/site/src/assets/excel-gallery/treemap.png b/site/src/assets/excel-gallery/treemap.png new file mode 100644 index 00000000..99f4de7d Binary files /dev/null and b/site/src/assets/excel-gallery/treemap.png differ diff --git a/site/src/assets/excel-gallery/waterfall.png b/site/src/assets/excel-gallery/waterfall.png new file mode 100644 index 00000000..84deec80 Binary files /dev/null and b/site/src/assets/excel-gallery/waterfall.png differ diff --git a/site/src/components/ChartCodeModal.tsx b/site/src/components/ChartCodeModal.tsx index 2aac5c11..f110caa2 100644 --- a/site/src/components/ChartCodeModal.tsx +++ b/site/src/components/ChartCodeModal.tsx @@ -227,7 +227,7 @@ export function ChartCodeModal({ }} > {testCase && ( - + } {result.kind === 'echarts' && } {result.kind === 'chartjs' && } + {result.kind === 'plotly' && } ); diff --git a/site/src/components/GalleryOptionsBar.tsx b/site/src/components/GalleryOptionsBar.tsx index 5d90a356..612321cf 100644 --- a/site/src/components/GalleryOptionsBar.tsx +++ b/site/src/components/GalleryOptionsBar.tsx @@ -128,10 +128,18 @@ function ControlRow(props: { const step = spec.step ?? ((spec.max - spec.min) / 100 || 1); const num = typeof value === 'number' ? value : spec.min; const pct = spec.max > spec.min ? ((num - spec.min) / (spec.max - spec.min)) * 100 : 0; + // Reserve enough width for the widest value the slider can show so the + // readout never clips (e.g. "50") or reflows as digits change. + const readoutCh = Math.max( + 2, + spec.min.toLocaleString().length, + spec.max.toLocaleString().length, + ); control = ( onChange(Number(e.target.value))} /> - {Number(num).toLocaleString()} + + {Number(num).toLocaleString()} + ); } else { diff --git a/site/src/components/PlotlyView.tsx b/site/src/components/PlotlyView.tsx new file mode 100644 index 00000000..04261adb --- /dev/null +++ b/site/src/components/PlotlyView.tsx @@ -0,0 +1,57 @@ +import { useEffect, useRef } from 'react'; +import Plotly from 'plotly.js-dist-min'; + +const asFinite = (v: unknown): number | undefined => + typeof v === 'number' && Number.isFinite(v) ? v : undefined; + +/** + * Plotly renderer. + * + * The flint Plotly assembler computes a designed figure size (`_width`/`_height`, + * also written into `layout.width`/`layout.height`). Render into a wrapper sized + * to those dimensions so the plot keeps its designed proportions, the same way + * the other backend views render at their natural designed size. + */ +export function PlotlyView({ + figure, + height = 320, + constrain = true, +}: { + figure: any; + height?: number; + /** When false, render at the designed pixel size without clamping to the + * container width (used by the photo-wall, which scales charts to fit). */ + constrain?: boolean; +}) { + const ref = useRef(null); + + const designedWidth = asFinite(figure?._width); + const designedHeight = asFinite(figure?._height); + const renderHeight = designedHeight ?? height; + + useEffect(() => { + const el = ref.current; + if (!el) return; + Plotly.newPlot(el, figure?.data ?? [], figure?.layout ?? {}, { + displayModeBar: false, + responsive: false, + }); + return () => { + Plotly.purge(el); + }; + }, [figure]); + + return ( +
+
+
+ ); +} diff --git a/site/src/components/ScaleToFit.tsx b/site/src/components/ScaleToFit.tsx index 8ec5438b..219b5d8d 100644 --- a/site/src/components/ScaleToFit.tsx +++ b/site/src/components/ScaleToFit.tsx @@ -21,6 +21,7 @@ export function ScaleToFit({ padding = 0, adaptiveHeight = false, minHeight = 0, + fill = false, children, }: { /** Bounding-box height in px. With `adaptiveHeight` this is the *max* height. */ @@ -31,6 +32,14 @@ export function ScaleToFit({ adaptiveHeight?: boolean; /** Floor for the box height when `adaptiveHeight` is set. */ minHeight?: number; + /** + * Fill the parent (which must be `position: relative`) and shrink-to-fit its + * *measured* width AND height, instead of the fixed `height` prop. Use this + * when the available box is driven by a flex/grid container (e.g. a modal + * pane) so an oversized chart never overflows a container shorter than + * `height`. + */ + fill?: boolean; children: ReactNode; }) { const outerRef = useRef(null); @@ -48,7 +57,7 @@ export function ScaleToFit({ const natH = inner.offsetHeight; if (!natW || !natH) return; const boxW = outer.clientWidth - padding * 2; - const boxH = height - padding * 2; + const boxH = (fill ? outer.clientHeight : height) - padding * 2; const next = Math.min(boxW / natW, boxH / natH, 1); if (Number.isFinite(next) && next > 0) { setScale((prev) => (Math.abs(prev - next) > 0.005 ? next : prev)); @@ -64,15 +73,14 @@ export function ScaleToFit({ ro.observe(inner); ro.observe(outer); return () => ro.disconnect(); - }, [height, padding, adaptiveHeight, minHeight]); + }, [height, padding, adaptiveHeight, minHeight, fill]); return (
void; suffix?: string; }) { + const percent = max > min ? ((value - min) / (max - min)) * 100 : 0; + return ( ); diff --git a/site/src/components/TripleChart.tsx b/site/src/components/TripleChart.tsx index 582202dc..8cd17a5e 100644 --- a/site/src/components/TripleChart.tsx +++ b/site/src/components/TripleChart.tsx @@ -3,6 +3,7 @@ import type { TestCase } from 'flint-chart/test-data'; import { VegaLiteView } from './VegaLiteView'; import { EChartsView } from './EChartsView'; import { ChartjsView } from './ChartjsView'; +import { PlotlyView } from './PlotlyView'; import { testCaseToAssemblyInput } from '../shared/test-case-utils'; import { BACKENDS, @@ -130,6 +131,7 @@ export function TripleChart({ {backend === 'vegalite' && } {backend === 'echarts' && } {backend === 'chartjs' && } + {backend === 'plotly' && } ) : (
diff --git a/site/src/components/WallChart.tsx b/site/src/components/WallChart.tsx
index 66fd0368..178f6d55 100644
--- a/site/src/components/WallChart.tsx
+++ b/site/src/components/WallChart.tsx
@@ -3,6 +3,7 @@ import type { TestCase } from 'flint-chart/test-data';
 import { VegaLiteView } from './VegaLiteView';
 import { EChartsView } from './EChartsView';
 import { ChartjsView } from './ChartjsView';
+import { PlotlyView } from './PlotlyView';
 import { testCaseToAssemblyInput, thumbnailCanvasSize, type CanvasSize } from '../shared/test-case-utils';
 import { BACKENDS, type PreviewBackend } from '../shared/supported-backends';
 import { siteTheme } from '../shared/theme';
@@ -68,5 +69,6 @@ export function WallChart({
 
   if (backend === 'vegalite') return ;
   if (backend === 'echarts') return ;
+  if (backend === 'plotly') return ;
   return ;
 }
diff --git a/site/src/components/gallery-options-bar.css b/site/src/components/gallery-options-bar.css
index ae8a7d7b..d5113b52 100644
--- a/site/src/components/gallery-options-bar.css
+++ b/site/src/components/gallery-options-bar.css
@@ -153,64 +153,18 @@
 }
 
 .gopt-readout {
+  flex: none;
   text-align: left;
   color: #4b525a;
   font-size: 11px;
   font-variant-numeric: tabular-nums;
-  overflow: hidden;
   white-space: nowrap;
 }
 
-.gopt-bar input[type='range'] {
-  -webkit-appearance: none;
-  appearance: none;
-  width: 60px;
-  min-width: 0;
-  height: 12px;
-  margin: 0;
-  background: transparent;
-  cursor: pointer;
-}
-
-.gopt-bar input[type='range']::-webkit-slider-runnable-track {
-  height: 3px;
-  border-radius: 999px;
-  background: linear-gradient(
-    to right,
-    #0078d4 0 var(--pct, 50%),
-    rgba(0, 0, 0, 0.16) var(--pct, 50%) 100%
-  );
-}
-
-.gopt-bar input[type='range']::-webkit-slider-thumb {
-  -webkit-appearance: none;
-  appearance: none;
-  width: 10px;
-  height: 10px;
-  margin-top: -3.5px;
-  border: none;
-  border-radius: 50%;
-  background: #0078d4;
-}
-
-.gopt-bar input[type='range']::-moz-range-track {
-  height: 3px;
-  border-radius: 999px;
-  background: rgba(0, 0, 0, 0.16);
-}
-
-.gopt-bar input[type='range']::-moz-range-progress {
-  height: 3px;
-  border-radius: 999px;
-  background: #0078d4;
-}
-
-.gopt-bar input[type='range']::-moz-range-thumb {
-  width: 10px;
-  height: 10px;
-  border: none;
-  border-radius: 50%;
-  background: #0078d4;
+.gopt-bar input[type='range'].site-range {
+  flex: 0 0 48px;
+  width: 48px;
+  max-width: 48px;
 }
 
 /* Discrete property dropdown, matching the chart-type selector menu. */
diff --git a/site/src/global.css b/site/src/global.css
index 304128af..c2bec6c0 100644
--- a/site/src/global.css
+++ b/site/src/global.css
@@ -22,6 +22,76 @@
   text-decoration-color: currentColor !important;
 }
 
+/* Shared site slider. The explicit class prevents embedded MCP App styles from
+   changing site controls when documentation examples load their stylesheet. */
+input[type='range'].site-range {
+  -webkit-appearance: none;
+  appearance: none;
+  width: 100%;
+  min-width: 0;
+  height: 12px;
+  margin: 0;
+  background: transparent;
+  cursor: pointer;
+}
+
+input[type='range'].site-range::-webkit-slider-runnable-track {
+  height: 3px;
+  border-radius: 999px;
+  background: linear-gradient(
+    to right,
+    #0078d4 0 var(--pct, 50%),
+    rgba(0, 0, 0, 0.16) var(--pct, 50%) 100%
+  );
+}
+
+input[type='range'].site-range::-webkit-slider-thumb {
+  -webkit-appearance: none;
+  appearance: none;
+  width: 10px;
+  height: 10px;
+  margin-top: -3.5px;
+  border: 0;
+  border-radius: 50%;
+  background: #0078d4;
+}
+
+input[type='range'].site-range::-moz-range-track {
+  height: 3px;
+  border-radius: 999px;
+  background: rgba(0, 0, 0, 0.16);
+}
+
+input[type='range'].site-range::-moz-range-progress {
+  height: 3px;
+  border-radius: 999px;
+  background: #0078d4;
+}
+
+input[type='range'].site-range::-moz-range-thumb {
+  width: 10px;
+  height: 10px;
+  border: 0;
+  border-radius: 50%;
+  background: #0078d4;
+}
+
+input[type='range'].site-range:focus-visible {
+  outline: 2px solid #0078d4;
+  outline-offset: 3px;
+}
+
+@media (forced-colors: active) {
+  input[type='range'].site-range::-webkit-slider-runnable-track {
+    background: CanvasText;
+  }
+
+  input[type='range'].site-range::-webkit-slider-thumb,
+  input[type='range'].site-range::-moz-range-thumb {
+    background: Highlight;
+  }
+}
+
 @media (max-width: 640px) {
   .site-nav-bar {
     gap: 14px !important;
diff --git a/site/src/i18n/messages/en.json b/site/src/i18n/messages/en.json
index f87110b3..e40ad72d 100644
--- a/site/src/i18n/messages/en.json
+++ b/site/src/i18n/messages/en.json
@@ -164,6 +164,11 @@
     "ctaDocs": "Read the docs",
     "news": {
       "title": "Updates",
+      "release040": {
+        "date": "July 24, 2026",
+        "dateTime": "2026-07-24",
+        "text": "Flint 0.4.0 adds 38 Plotly chart types and 18 native, editable Excel chart templates."
+      },
       "dynamicWidgets": {
         "date": "July 19, 2026",
         "dateTime": "2026-07-19",
@@ -186,7 +191,8 @@
     "leadBefore": "Flint is a visualization intermediate language that lets",
     "leadHighlight1": "AI agents reliably create expressive, good-looking charts from simple, human-editable chart specs",
     "leadMiddle": ". Instead of requiring verbose low-level parameters such as scales, axes, spacing, and layout, the Flint compiler derives optimized chart settings from the data, semantic types, chart type, and encodings.",
-    "leadHighlight2": "Flint supports {{chartTypes}} chart types, and it supports rendering in Vega-Lite, ECharts, and Chart.js",
+    "leadHighlight2": "Flint supports {{chartTypes}} chart types across {{backends}} rendering backends through one unified interface",
+    "backendRosterLabel": "Backends",
     "flintSpec": "Flint spec",
     "compiledChart": "Compiled chart",
     "backendAria": "Rendering backend",
@@ -217,8 +223,8 @@
       },
       "backends": {
         "title": "Render with different backends",
-        "body": "Flint supports {{chartTypes}} chart types across Vega-Lite, ECharts, and Chart.js, with {{examples}} backend-specific examples in the gallery. Despite their different APIs and programming models, Flint hides them behind a unified interface. The user can easily switch to different backends and leverage their unique features.",
-        "example": "Vega-Lite has no native sunburst, but the user can easily switch to ECharts. The sunburst chart is a better alternative than the grouped bar chart for visualizing the hierarchy of region × gameType × game."
+        "body": "Flint supports {{chartTypes}} chart types across Vega-Lite, ECharts, Chart.js, and Plotly, with {{examples}} backend-specific examples in the gallery, and can emit native Excel charts through Office.js. Despite their different APIs and programming models, Flint hides them behind a unified interface.",
+        "example": "Switch backends to use their native strengths: ECharts for hierarchical sunbursts, Plotly for statistical and analytical traces, or Excel for editable charts embedded in a workbook."
       }
     },
     "examples": {
@@ -259,6 +265,10 @@
     "leadAfter": "server and your agent can create charts as an interactive MCP app. By default it opens an interactive Flint chart view; when you need artifacts, it can also return static images or backend-native specs.",
     "quickStart": "Quick start:",
     "quickStartBody": "paste this setup request into your agent and let it configure Flint for the current project. For manual setup, see",
+    "localSetupTitle": "Local server",
+    "localSetupBody": "Recommended if your client supports local MCP",
+    "remoteSetupTitle": "Remote server",
+    "remoteSetupBody": "Use if your client only supports remote MCP",
     "installConfigure": "install & configure",
     "orThe": "or the",
     "githubReadme": "GitHub README",
diff --git a/site/src/i18n/messages/zh-CN.json b/site/src/i18n/messages/zh-CN.json
index 2fb02683..71f19c4e 100644
--- a/site/src/i18n/messages/zh-CN.json
+++ b/site/src/i18n/messages/zh-CN.json
@@ -164,6 +164,11 @@
     "ctaDocs": "阅读文档",
     "news": {
       "title": "更新",
+      "release040": {
+        "date": "2026 年 7 月 24 日",
+        "dateTime": "2026-07-24",
+        "text": "Flint 0.4.0 新增 38 种 Plotly 图表和 18 种可编辑的原生 Excel 图表模板。"
+      },
       "dynamicWidgets": {
         "date": "2026 年 7 月 19 日",
         "dateTime": "2026-07-19",
@@ -186,7 +191,8 @@
     "leadBefore": "Flint 是一种可视化中间语言,帮助",
     "leadHighlight1": "AI 智能体从简洁、可人工编辑的图表规范出发,稳定生成表现力强、观感出色的图表",
     "leadMiddle": "。你不必手动编写比例尺、坐标轴、间距、布局等繁琐的底层参数;Flint 编译器会结合数据、语义类型、图表类型和编码,自动推导出更合适的图表配置。",
-    "leadHighlight2": "Flint 目前支持 {{chartTypes}} 种图表类型,可输出为 Vega-Lite、ECharts 和 Chart.js",
+    "leadHighlight2": "Flint 目前通过统一接口,在 {{backends}} 种渲染后端上支持 {{chartTypes}} 种图表类型",
+    "backendRosterLabel": "渲染后端",
     "flintSpec": "Flint 规范",
     "compiledChart": "编译结果",
     "backendAria": "渲染后端",
@@ -217,8 +223,8 @@
       },
       "backends": {
         "title": "一份规范,多种渲染后端",
-        "body": "Flint 支持通过 Vega-Lite、ECharts 和 Chart.js 渲染 {{chartTypes}} 种图表,图表示例中还收录了 {{examples}} 个针对不同后端的示例。三者的 API 和编程模型各不相同,Flint 则用统一接口抹平差异,让你可以按需切换后端、发挥各自所长。",
-        "example": "Vega-Lite 没有原生旭日图,但可以轻松切换到 ECharts。对于 region × gameType × game 这样的层级结构,旭日图通常比分组柱状图更合适。"
+        "body": "Flint 支持通过 Vega-Lite、ECharts、Chart.js 和 Plotly 渲染 {{chartTypes}} 种图表,图表示例中收录了 {{examples}} 个后端专属示例,还可通过 Office.js 生成原生 Excel 图表。不同后端的 API 和编程模型各不相同,Flint 则以统一接口抹平差异。",
+        "example": "按需切换后端以发挥其原生优势:ECharts 适合层级旭日图,Plotly 擅长统计和分析图表,Excel 则可生成工作簿中可继续编辑的原生图表。"
       }
     },
     "examples": {
@@ -259,6 +265,10 @@
     "leadAfter": "服务器后,智能体便能创建图表,并以交互式 MCP App 呈现结果。Flint 默认打开可交互的图表视图;需要导出结果时,也可以返回静态图片,或生成可供 Vega-Lite、ECharts 和 Chart.js 直接使用的规范。",
     "quickStart": "让 AI 智能体帮你配置:",
     "quickStartBody": "把下面这段请求发给智能体即可。若想手动配置,请参阅",
+    "localSetupTitle": "本地服务器",
+    "localSetupBody": "推荐:客户端支持本地 MCP 时使用",
+    "remoteSetupTitle": "远程服务器",
+    "remoteSetupBody": "客户端仅支持远程 MCP 时使用",
     "installConfigure": "安装与配置",
     "orThe": "或",
     "githubReadme": "GitHub README",
diff --git a/site/src/main.tsx b/site/src/main.tsx
index 20a84e91..afa714e7 100644
--- a/site/src/main.tsx
+++ b/site/src/main.tsx
@@ -3,16 +3,19 @@ import ReactDOM from 'react-dom/client';
 import '@fontsource-variable/inter/index.css';
 import './global.css';
 import './i18n';
-import { HashRouter, Routes, Route, Navigate, Outlet, useParams } from 'react-router-dom';
+import { HashRouter, Routes, Route, Navigate, useParams } from 'react-router-dom';
 import { Landing } from './routes/Landing';
 import { ChartWall } from './routes/ChartWall';
+import { ExcelGallery } from './routes/ExcelGallery';
 import { Editor } from './routes/Editor';
 import { McpServer } from './routes/McpServer';
 import { DocSectionPage } from './routes/DocSectionPage';
-import { DevShell } from './routes/dev/DevShell';
-import { DevIllustrations } from './routes/dev/DevIllustrations';
-import { DevMcpUi } from './routes/dev/DevMcpUi';
-import { DevLabs } from './routes/dev/DevLabs';
+import { PlaygroundShell } from './playground/PlaygroundShell';
+import { Illustrations } from './playground/Illustrations';
+import { McpUi } from './playground/McpUi';
+import { Labs } from './playground/Labs';
+import { DemoWall } from './playground/DemoWall';
+import { FullTestCases } from './playground/FullTestCases';
 import { LocaleProvider, useLocale } from './i18n/LocaleContext';
 import type { Locale } from './i18n/locales';
 import { localePath } from './i18n/paths';
@@ -33,20 +36,23 @@ function AppRoutes({ locale }: { locale: Locale }) {
     
       
         } />
+        } />
         } />
         {/* Keep old /wall links working; /gallery is canonical. */}
         } />
         } />
         } />
         } />
-        } />
-        }>
-          }>
-            } />
-            } />
-            } />
-            } />
-          
+        {/* Playground is public — poke around and play with the widgets. */}
+        } />
+        } />
+        }>
+          } />
+          } />
+          } />
+          } />
+          } />
+          } />
         
         {/* Tutorials merged into Documentation as the "Quick start" group. */}
         
-    : ;
-}
-
 /** Preserve old /tutorials/:slug links by redirecting into /documentation. */
 function TutorialRedirect() {
   const { slug } = useParams<{ slug?: string }>();
diff --git a/site/src/playground/BandExpansionFigure.tsx b/site/src/playground/BandExpansionFigure.tsx
new file mode 100644
index 00000000..46c700d6
--- /dev/null
+++ b/site/src/playground/BandExpansionFigure.tsx
@@ -0,0 +1,187 @@
+import { useMemo, useState, type CSSProperties } from 'react';
+import type { ChartAssemblyInput } from 'flint-chart';
+import { BACKENDS, ALL_BACKENDS, type PreviewBackend } from '../shared/supported-backends';
+import { VegaLiteView } from '../components/VegaLiteView';
+import { EChartsView } from '../components/EChartsView';
+import { ChartjsView } from '../components/ChartjsView';
+import { PlotlyView } from '../components/PlotlyView';
+import { siteTheme } from '../shared/theme';
+
+/**
+ * Interactive dev-labs panel for the band min/base/max sizing model.
+ *
+ * A single bar chart driven by a category-count slider (same widget pattern as
+ * the doc-page SizingPlayground). Drag it up and watch each band expand to fill
+ * the plot (sparse) then compress as categories crowd the axis (dense). Backend
+ * tabs switch renderers so the per-backend expansion ceilings are comparable.
+ */
+
+/** Deterministic RNG so the demo data is stable across re-renders. */
+function mulberry32(seed: number): () => number {
+  let a = seed >>> 0;
+  return () => {
+    a |= 0;
+    a = (a + 0x6d2b79f5) | 0;
+    let t = Math.imul(a ^ (a >>> 15), 1 | a);
+    t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
+    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
+  };
+}
+
+function categoryRows(n: number): { Category: string; Value: number }[] {
+  const rng = mulberry32(20260722);
+  return Array.from({ length: n }, (_, i) => ({
+    Category: `C${String(i + 1).padStart(2, '0')}`,
+    Value: Math.round(20 + rng() * 80),
+  }));
+}
+
+const BASE = { width: 560, height: 340 } as const;
+
+function buildInput(count: number): ChartAssemblyInput {
+  return {
+    data: { values: categoryRows(count) },
+    semantic_types: { Category: 'Category', Value: 'Quantity' },
+    chart_spec: { chartType: 'Bar Chart', encodings: { x: 'Category', y: 'Value' }, baseSize: BASE },
+  };
+}
+
+function BackendChart({ backend, spec }: { backend: PreviewBackend; spec: unknown }) {
+  if (backend === 'vegalite') return ;
+  if (backend === 'echarts') return ;
+  if (backend === 'chartjs') return ;
+  return ;
+}
+
+const labelStyle: CSSProperties = { fontSize: 13, color: siteTheme.textMuted, fontWeight: 500 };
+
+export function BandExpansionFigure() {
+  const [backend, setBackend] = useState('plotly');
+  const [count, setCount] = useState(5);
+
+  const { spec, width, error } = useMemo(() => {
+    try {
+      const s = BACKENDS[backend].assemble(buildInput(count)) as any;
+      return {
+        spec: s,
+        width: typeof s?._width === 'number' ? Math.round(s._width) : 0,
+        error: null as string | null,
+      };
+    } catch (err) {
+      return { spec: null, width: 0, error: String((err as Error)?.message ?? err) };
+    }
+  }, [backend, count]);
+
+  const pct = ((count - 2) / (40 - 2)) * 100;
+
+  return (
+    
+
+

Band expansion — min / base / max

+

+ Drag the slider to add categories. Sparse charts expand each band up to the backend's + {' '}maxBandSize; dense charts compress bands to fit. Vega-Lite keeps its + native step size; ECharts, Chart.js, and Plotly fill their plot area. +

+
+ +
+ {/* Controls toolbar */} +
+
+ {ALL_BACKENDS.map((id) => { + const active = id === backend; + return ( + + ); + })} +
+ + + + + plot {width}px + {' · '} + ~{Math.round(width / count)}px/band + +
+ + {/* Chart — fixed-size stage so the panel never reflows as N changes */} +
+ {error ? ( +
{error}
+ ) : ( + spec && + )} +
+
+
+ ); +} diff --git a/site/src/components/ChartRedesignFigure.tsx b/site/src/playground/ChartRedesignFigure.tsx similarity index 100% rename from site/src/components/ChartRedesignFigure.tsx rename to site/src/playground/ChartRedesignFigure.tsx diff --git a/site/src/playground/DemoWall.tsx b/site/src/playground/DemoWall.tsx new file mode 100644 index 00000000..051f86bd --- /dev/null +++ b/site/src/playground/DemoWall.tsx @@ -0,0 +1,153 @@ +import { useMemo } from 'react'; +import { BACKENDS } from '../shared/supported-backends'; +import { VegaLiteView } from '../components/VegaLiteView'; +import { PlotlyView } from '../components/PlotlyView'; +import { ScaleToFit } from '../components/ScaleToFit'; +import { siteTheme } from '../shared/theme'; +import { PREVIEW_CASES, type PreviewCase } from './new-case-preview-data'; + +/** VL if it has a template for the chart type, else fall back to Plotly. */ +function pickBackend(chartType: string): 'vegalite' | 'plotly' { + return BACKENDS.vegalite.getTemplateDef(chartType) ? 'vegalite' : 'plotly'; +} + +function buildInput(c: PreviewCase) { + return { + data: { values: c.data }, + semantic_types: c.semantic_types, + chart_spec: { + chartType: c.chartType, + encodings: c.encodings, + baseSize: { width: 300, height: 200 }, + ...(c.chartProperties ? { chartProperties: c.chartProperties } : {}), + }, + } as any; +} + +// Coarse families so related cases cluster for review. +const FAMILY_ORDER = [ + 'Points & correlation', + 'Distributions', + 'Bars & ranking', + 'Time & trends', + 'Parts & radial', + 'Single value & schedule', + 'Maps & matrices', +] as const; + +const FAMILY_OF: Record = { + 'Scatter Plot': 'Points & correlation', + 'Connected Scatter Plot': 'Points & correlation', + 'Regression': 'Points & correlation', + 'Ranged Dot Plot': 'Points & correlation', + 'Strip Plot': 'Points & correlation', + 'Histogram': 'Distributions', + 'Density Plot': 'Distributions', + 'Boxplot': 'Distributions', + 'Violin Plot': 'Distributions', + 'ECDF Plot': 'Distributions', + 'Bar Chart': 'Bars & ranking', + 'Grouped Bar Chart': 'Bars & ranking', + 'Stacked Bar Chart': 'Bars & ranking', + 'Lollipop Chart': 'Bars & ranking', + 'Pyramid Chart': 'Bars & ranking', + 'Bar Table': 'Bars & ranking', + 'Line Chart': 'Time & trends', + 'Area Chart': 'Time & trends', + 'Streamgraph': 'Time & trends', + 'Slope Chart': 'Time & trends', + 'Range Area Chart': 'Time & trends', + 'Bump Chart': 'Time & trends', + 'Sparkline': 'Time & trends', + 'Candlestick Chart': 'Time & trends', + 'Pie Chart': 'Parts & radial', + 'Donut Chart': 'Parts & radial', + 'Rose Chart': 'Parts & radial', + 'Radar Chart': 'Parts & radial', + 'Funnel Chart': 'Parts & radial', + 'Waterfall Chart': 'Parts & radial', + 'KPI Card': 'Single value & schedule', + 'Gauge Chart': 'Single value & schedule', + 'Bullet Chart': 'Single value & schedule', + 'Gantt Chart': 'Single value & schedule', + 'Map': 'Maps & matrices', + 'Choropleth': 'Maps & matrices', + 'Heatmap': 'Maps & matrices', +}; + +const familyOf = (chartType: string) => FAMILY_OF[chartType] ?? 'Points & correlation'; + +function CaseCard({ c }: { c: PreviewCase }) { + const backend = pickBackend(c.chartType); + const compiled = useMemo(() => { + try { + return { ok: true as const, value: BACKENDS[backend].assemble(buildInput(c)) }; + } catch (err) { + return { ok: false as const, err }; + } + }, [c, backend]); + + return ( +
(e.currentTarget.style.background = siteTheme.hover)} + onMouseLeave={(e) => (e.currentTarget.style.background = 'transparent')} + > + + {compiled.ok ? ( + backend === 'vegalite' + ? + : + ) : ( +
+                        {String((compiled.err as Error)?.message ?? compiled.err)}
+                    
+ )} +
+
{c.title}
+
+ {c.chartType}{backend === 'plotly' ? ' · plotly' : ''} · {c.source} +
+
+ ); +} + +export function DemoWall() { + const groups = useMemo(() => { + const byFamily = new Map(); + PREVIEW_CASES.forEach((c, index) => { + const fam = familyOf(c.chartType); + if (!byFamily.has(fam)) byFamily.set(fam, []); + byFamily.get(fam)!.push({ c, index }); + }); + return FAMILY_ORDER + .map((fam) => ({ fam, items: byFamily.get(fam) ?? [] })) + .filter((g) => g.items.length > 0); + }, []); + + return ( +
+
+

Demo wall ({PREVIEW_CASES.length} candidates)

+

+ Candidate real-world datasets, grouped by family. Rendered with Vega-Lite by + default, Plotly where the chart type isn't in Vega-Lite. Hover a tile for its + source, license and row count. +

+
+ {groups.map(({ fam, items }) => ( +
+

+ {fam} · {items.length} +

+
+ {items.map(({ c }) => ( + + ))} +
+
+ ))} +
+ ); +} diff --git a/site/src/components/DodgeToggleFigure.tsx b/site/src/playground/DodgeToggleFigure.tsx similarity index 99% rename from site/src/components/DodgeToggleFigure.tsx rename to site/src/playground/DodgeToggleFigure.tsx index e112ff01..2f3ac4d2 100644 --- a/site/src/components/DodgeToggleFigure.tsx +++ b/site/src/playground/DodgeToggleFigure.tsx @@ -1,6 +1,6 @@ import { useMemo, useState } from 'react'; import { assembleVegaLite } from 'flint-chart'; -import { VegaLiteView } from './VegaLiteView'; +import { VegaLiteView } from '../components/VegaLiteView'; import { siteTheme } from '../shared/theme'; /** diff --git a/site/src/playground/FullTestCases.tsx b/site/src/playground/FullTestCases.tsx new file mode 100644 index 00000000..607ccfce --- /dev/null +++ b/site/src/playground/FullTestCases.tsx @@ -0,0 +1,96 @@ +import { useMemo, useState } from 'react'; +import { TEST_GENERATORS, type TestCase } from 'flint-chart/test-data'; +import { WallChart } from '../components/WallChart'; +import { ScaleToFit } from '../components/ScaleToFit'; +import { BACKENDS, type PreviewBackend } from '../shared/supported-backends'; +import { siteTheme } from '../shared/theme'; + +/** First backend (in preference order) that has a template for this chart type. */ +const BACKEND_ORDER: PreviewBackend[] = ['vegalite', 'echarts', 'plotly', 'chartjs']; +function pickAnyBackend(chartType: string): PreviewBackend { + for (const b of BACKEND_ORDER) { + if (BACKENDS[b].getTemplateDef(chartType)) return b; + } + return 'vegalite'; +} + +function safeCases(gen: () => TestCase[]): TestCase[] { + try { + return gen(); + } catch { + return []; + } +} + +function TestCaseCard({ tc }: { tc: TestCase }) { + const backend = pickAnyBackend(tc.chartType); + return ( +
(e.currentTarget.style.background = siteTheme.hover)} + onMouseLeave={(e) => (e.currentTarget.style.background = 'transparent')} + > + + + +
+ {tc.title} +
+
+ {tc.chartType} · {backend} · {tc.data.length} rows +
+
+ ); +} + +/** One generator's cases, rendered lazily (only when the section is expanded). */ +function GeneratorSection({ name, gen }: { name: string; gen: () => TestCase[] }) { + const [open, setOpen] = useState(false); + const cases = useMemo(() => (open ? safeCases(gen) : []), [open, gen]); + + return ( +
+ + {open && ( +
+ {cases.map((tc, i) => ( + + ))} +
+ )} +
+ ); +} + +export function FullTestCases() { + const names = useMemo(() => Object.keys(TEST_GENERATORS).sort((a, b) => a.localeCompare(b)), []); + + return ( +
+
+

Full test cases ({names.length} generators)

+

+ Every case from every test-data generator — the complete reference set used for + regression and new-backend bring-up. Expand a generator to render its cases (on + the first backend that supports each chart type). Heavy, so sections render lazily. +

+
+ {names.map((name) => ( + + ))} +
+ ); +} diff --git a/site/src/routes/dev/DevIllustrations.tsx b/site/src/playground/Illustrations.tsx similarity index 57% rename from site/src/routes/dev/DevIllustrations.tsx rename to site/src/playground/Illustrations.tsx index 866b301a..d74adbcc 100644 --- a/site/src/routes/dev/DevIllustrations.tsx +++ b/site/src/playground/Illustrations.tsx @@ -1,8 +1,8 @@ -import { ChatMockup } from '../McpServer'; -import { ChartRedesignFigure } from '../../components/ChartRedesignFigure'; -import { SpecPipelineFigure } from '../../components/SpecPipelineFigure'; +import { ChatMockup } from '../routes/McpServer'; +import { ChartRedesignFigure } from './ChartRedesignFigure'; +import { SpecPipelineFigure } from '../components/SpecPipelineFigure'; -export function DevIllustrations() { +export function Illustrations() { return (
diff --git a/site/src/playground/Labs.tsx b/site/src/playground/Labs.tsx new file mode 100644 index 00000000..7b66debb --- /dev/null +++ b/site/src/playground/Labs.tsx @@ -0,0 +1,16 @@ +import { DodgeToggleFigure } from './DodgeToggleFigure'; +import { LocalDodgeFigure } from './LocalDodgeFigure'; +import { BandExpansionFigure } from './BandExpansionFigure'; + +export function Labs() { + return ( +
+
+

Labs

+
+ + + +
+ ); +} \ No newline at end of file diff --git a/site/src/components/LocalDodgeFigure.tsx b/site/src/playground/LocalDodgeFigure.tsx similarity index 98% rename from site/src/components/LocalDodgeFigure.tsx rename to site/src/playground/LocalDodgeFigure.tsx index 921b4a1b..71ef8f0c 100644 --- a/site/src/components/LocalDodgeFigure.tsx +++ b/site/src/playground/LocalDodgeFigure.tsx @@ -1,7 +1,7 @@ import { useMemo } from 'react'; -import { VegaLiteView } from './VegaLiteView'; -import { EChartsView } from './EChartsView'; -import { ChartjsView } from './ChartjsView'; +import { VegaLiteView } from '../components/VegaLiteView'; +import { EChartsView } from '../components/EChartsView'; +import { ChartjsView } from '../components/ChartjsView'; import { siteTheme } from '../shared/theme'; /** diff --git a/site/src/routes/dev/DevMcpUi.tsx b/site/src/playground/McpUi.tsx similarity index 65% rename from site/src/routes/dev/DevMcpUi.tsx rename to site/src/playground/McpUi.tsx index e2a9da5c..dc7be6c6 100644 --- a/site/src/routes/dev/DevMcpUi.tsx +++ b/site/src/playground/McpUi.tsx @@ -1,6 +1,6 @@ -import { McpAppMockup } from '../../components/McpAppMockup'; +import { McpAppMockup } from '../components/McpAppMockup'; -export function DevMcpUi() { +export function McpUi() { return (
diff --git a/site/src/routes/dev/DevShell.tsx b/site/src/playground/PlaygroundShell.tsx similarity index 63% rename from site/src/routes/dev/DevShell.tsx rename to site/src/playground/PlaygroundShell.tsx index 4e421d1f..755ee73f 100644 --- a/site/src/routes/dev/DevShell.tsx +++ b/site/src/playground/PlaygroundShell.tsx @@ -1,21 +1,22 @@ -import { NavLink, Outlet } from 'react-router-dom'; -import { siteTheme } from '../../shared/theme'; -import './dev.css'; +import { NavLink, Link, Outlet } from 'react-router-dom'; +import { siteTheme } from '../shared/theme'; +import './playground.css'; const pages = [ - { to: 'news', label: 'News' }, { to: 'illustrations', label: 'Illustrations' }, { to: 'mcp-ui', label: 'MCP UI test' }, { to: 'labs', label: 'Labs' }, + { to: 'demo-wall', label: 'Demo wall' }, + { to: 'full-test-cases', label: 'Full test cases' }, ]; -export function DevShell() { +export function PlaygroundShell() { return (
-
+ flint dev -
+
diff --git a/site/src/components/chart-redesign-figure.css b/site/src/playground/chart-redesign-figure.css similarity index 100% rename from site/src/components/chart-redesign-figure.css rename to site/src/playground/chart-redesign-figure.css diff --git a/site/src/playground/new-case-preview-data.ts b/site/src/playground/new-case-preview-data.ts new file mode 100644 index 00000000..a4a4b299 --- /dev/null +++ b/site/src/playground/new-case-preview-data.ts @@ -0,0 +1,885 @@ +// New-case preview data — a staging set of REAL-WORLD datasets we're evaluating +// before swapping any into the gallery/test-data generators. Nothing here is +// wired into flint-js test-data yet; this file only feeds the +// /playground/new-case-preview page so we can read the candidates one by one. +// +// Each case carries its provenance (source + license) so the licensing review +// in design-docs/gallery-data-audit.md can be applied case by case. Numbers are +// real values transcribed from the cited source (facts are not copyrightable; +// small samples are re-keyed here — see the audit doc §6). + +export interface PreviewCase { + id: string; + /** Flint chart type name (drives auto backend pick: VL if supported, else Plotly). */ + chartType: string; + title: string; + /** One-line "why this dataset is cool / what shape it shows". */ + blurb: string; + /** Human-readable data source. */ + source: string; + /** License basis for bundling into this MIT repo (see audit §6). */ + license: string; + semantic_types: Record; + encodings: Record; + chartProperties?: Record; + data: Record[]; +} + +// --------------------------------------------------------------------------- +// 1. Connected Scatter — "Driving Shifts Into Reverse" (miles vs gas price) +// The most famous connected scatterplot: US miles driven per capita vs the +// (inflation-adjusted) price of gas, 1956–2010. The path self-crosses. +// --------------------------------------------------------------------------- +const DRIVING: [number, number, number][] = [ + [1956, 3675, 2.38], [1957, 3706, 2.40], [1958, 3766, 2.26], [1959, 3905, 2.31], + [1960, 3935, 2.27], [1961, 3977, 2.25], [1962, 4085, 2.22], [1963, 4218, 2.12], + [1964, 4369, 2.11], [1965, 4538, 2.14], [1966, 4676, 2.14], [1967, 4827, 2.14], + [1968, 5038, 2.13], [1969, 5207, 2.07], [1970, 5376, 2.01], [1971, 5617, 1.93], + [1972, 5973, 1.87], [1973, 6154, 1.90], [1974, 5943, 2.34], [1975, 6111, 2.31], + [1976, 6389, 2.32], [1977, 6630, 2.36], [1978, 6883, 2.23], [1979, 6744, 2.68], + [1980, 6672, 3.30], [1981, 6732, 3.30], [1982, 6835, 2.92], [1983, 6943, 2.66], + [1984, 7130, 2.48], [1985, 7323, 2.36], [1986, 7558, 1.76], [1987, 7770, 1.76], + [1988, 8089, 1.68], [1989, 8397, 1.75], [1990, 8529, 1.88], [1991, 8535, 1.78], + [1992, 8662, 1.69], [1993, 8855, 1.60], [1994, 8909, 1.59], [1995, 9150, 1.60], + [1996, 9192, 1.67], [1997, 9416, 1.65], [1998, 9590, 1.39], [1999, 9687, 1.50], + [2000, 9717, 1.89], [2001, 9699, 1.77], [2002, 9814, 1.64], [2003, 9868, 1.86], + [2004, 9994, 2.14], [2005, 10067, 2.53], [2006, 10037, 2.79], [2007, 10025, 2.95], + [2008, 9880, 3.31], [2009, 9657, 2.38], [2010, 9596, 2.61], +]; + +// --------------------------------------------------------------------------- +// 2. Scatter — Palmer Penguins (flipper length vs body mass, by species) +// The modern "iris": three clean clusters. A re-keyed 33-row sample. +// --------------------------------------------------------------------------- +const PENGUINS: [string, number, number][] = [ + ['Adelie', 181, 3750], ['Adelie', 186, 3800], ['Adelie', 195, 3250], ['Adelie', 193, 3450], + ['Adelie', 190, 3650], ['Adelie', 181, 3625], ['Adelie', 195, 4675], ['Adelie', 182, 3200], + ['Adelie', 191, 3800], ['Adelie', 198, 4400], ['Adelie', 185, 3700], + ['Chinstrap', 192, 3500], ['Chinstrap', 196, 3900], ['Chinstrap', 193, 3650], + ['Chinstrap', 188, 3525], ['Chinstrap', 197, 3950], ['Chinstrap', 198, 3800], + ['Chinstrap', 178, 3300], ['Chinstrap', 207, 4800], ['Chinstrap', 201, 4050], + ['Chinstrap', 191, 3550], + ['Gentoo', 211, 4500], ['Gentoo', 230, 5700], ['Gentoo', 210, 4450], ['Gentoo', 218, 5700], + ['Gentoo', 215, 5400], ['Gentoo', 219, 5550], ['Gentoo', 209, 4800], ['Gentoo', 215, 5000], + ['Gentoo', 214, 4650], ['Gentoo', 216, 5550], ['Gentoo', 221, 5950], ['Gentoo', 217, 5250], +]; + +// --------------------------------------------------------------------------- +// 3. Line — Keeling Curve (annual mean atmospheric CO₂, Mauna Loa) +// The iconic climate-record rise. Real annual means (ppm). +// --------------------------------------------------------------------------- +const CO2: [number, number][] = [ + [1959, 315.98], [1965, 320.04], [1970, 325.68], [1975, 331.11], [1980, 338.80], + [1985, 346.12], [1990, 354.45], [1995, 360.82], [2000, 369.71], [2005, 379.98], + [2010, 389.90], [2015, 400.83], [2020, 414.24], [2023, 421.08], +]; + +// --------------------------------------------------------------------------- +// 5. Stacked Area — World population by region, 1950–2020 (UN WPP), millions +// --------------------------------------------------------------------------- +const POP_REGION: Record> = { + 1950: { Asia: 1404, Africa: 227, Europe: 549, Americas: 339, Oceania: 13 }, + 1970: { Asia: 2142, Africa: 365, Europe: 657, Americas: 512, Oceania: 20 }, + 1990: { Asia: 3226, Africa: 630, Europe: 721, Americas: 724, Oceania: 27 }, + 2010: { Asia: 4194, Africa: 1039, Europe: 736, Americas: 934, Oceania: 37 }, + 2020: { Asia: 4641, Africa: 1361, Europe: 748, Americas: 1023, Oceania: 45 }, +}; + +// --------------------------------------------------------------------------- +// 6. Scatter — Old Faithful eruptions (waiting vs duration): bimodal clusters +// Re-keyed 36-row sample of the classic geyser dataset. +// --------------------------------------------------------------------------- +const FAITHFUL: [number, number][] = [ + [3.6, 79], [1.8, 54], [3.333, 74], [2.283, 62], [4.533, 85], [2.883, 55], [4.7, 88], + [3.6, 85], [1.95, 51], [4.35, 85], [1.833, 54], [3.917, 84], [4.2, 78], [1.75, 47], + [4.7, 83], [2.167, 52], [1.75, 62], [4.8, 84], [1.6, 52], [4.25, 79], [1.8, 51], + [1.75, 47], [3.45, 78], [3.067, 69], [4.533, 74], [3.6, 83], [1.967, 55], [4.083, 76], + [3.85, 78], [4.433, 79], [4.3, 73], [4.467, 77], [3.367, 66], [4.033, 80], [3.833, 74], + [2.017, 52], +]; + +// --------------------------------------------------------------------------- +// 7. Slope — Life expectancy 2000 → 2021 (World Bank / OWID), years +// --------------------------------------------------------------------------- +const LIFE_EXP: Record = { + China: [72.0, 78.2], India: [62.5, 67.2], 'United States': [76.6, 76.3], + Nigeria: [46.6, 52.7], Japan: [81.1, 84.5], Russia: [65.5, 70.1], Brazil: [70.1, 72.8], +}; + +function buildCases(): PreviewCase[] { + const cases: PreviewCase[] = []; + + cases.push({ + id: 'driving', + chartType: 'Connected Scatter Plot', + title: 'Driving Shifts Into Reverse — miles vs gas price (US, 1956–2010)', + blurb: 'The most famous connected scatterplot: a self-crossing trajectory of miles driven per capita against the price of gas.', + source: 'NYT / Hannah Fairfield (2010), from US FHWA vehicle-miles + EIA/BLS gas prices; via vega-datasets driving.json', + license: 'US-gov facts (public domain) — courtesy citation', + semantic_types: { Year: 'Year', 'Miles/person': 'Quantity', 'Gas price': 'Quantity' }, + encodings: { x: 'Miles/person', y: 'Gas price', order: 'Year' }, + data: DRIVING.map(([Year, miles, gas]) => ({ Year, 'Miles/person': miles, 'Gas price': gas })), + }); + + cases.push({ + id: 'penguins', + chartType: 'Scatter Plot', + title: 'Palmer Penguins — flipper length vs body mass', + blurb: 'Three crisp species clusters; the modern replacement for the iris dataset.', + source: 'Horst, Hill & Gorman (2020), Palmer Station LTER — 33-row sample', + license: 'CC0 (public domain)', + semantic_types: { Species: 'Category', 'Flipper length (mm)': 'Quantity', 'Body mass (g)': 'Quantity' }, + encodings: { x: 'Flipper length (mm)', y: 'Body mass (g)', color: 'Species' }, + data: PENGUINS.map(([Species, flip, mass]) => ({ Species, 'Flipper length (mm)': flip, 'Body mass (g)': mass })), + }); + + cases.push({ + id: 'keeling', + chartType: 'Line Chart', + title: 'Keeling Curve — atmospheric CO₂ at Mauna Loa (annual mean)', + blurb: 'The defining climate record: a steady, accelerating rise from 316 ppm (1959) to 421 ppm (2023).', + source: 'Scripps CO₂ Program / NOAA GML, Mauna Loa Observatory', + license: 'NOAA gov data (PD); Scripps requests citation', + semantic_types: { Year: 'Year', 'CO₂ (ppm)': 'Quantity' }, + encodings: { x: 'Year', y: 'CO₂ (ppm)' }, + data: CO2.map(([Year, ppm]) => ({ Year, 'CO₂ (ppm)': ppm })), + }); + + cases.push({ + id: 'population', + chartType: 'Bar Chart', + title: 'Most populous countries, 2023 (millions)', + blurb: 'Instantly legible ranked bar; the year India overtook China.', + source: 'UN World Population Prospects 2022 / World Bank (2023)', + license: 'CC-BY 4.0 (attribute UN/World Bank)', + semantic_types: { Country: 'Country', Population: 'Quantity' }, + encodings: { x: 'Country', y: 'Population' }, + data: [ + ['India', 1428.6], ['China', 1425.7], ['United States', 339.9], ['Indonesia', 277.5], + ['Pakistan', 240.5], ['Nigeria', 223.8], ['Brazil', 216.4], ['Bangladesh', 173.0], + ['Russia', 144.4], ['Mexico', 128.5], + ].map(([Country, Population]) => ({ Country, Population })), + }); + + { + const rows: Record[] = []; + for (const [yr, byRegion] of Object.entries(POP_REGION)) { + for (const [region, pop] of Object.entries(byRegion)) { + rows.push({ Year: Number(yr), Region: region, Population: pop }); + } + } + cases.push({ + id: 'population-region', + chartType: 'Area Chart', + title: 'World population by region, 1950–2020 (stacked area, millions)', + blurb: "Asia's dominance and Africa's acceleration stacked over 70 years.", + source: 'UN World Population Prospects 2022', + license: 'CC-BY 4.0 (attribute UN)', + semantic_types: { Year: 'Year', Region: 'Category', Population: 'Quantity' }, + encodings: { x: 'Year', y: 'Population', color: 'Region' }, + chartProperties: { stackMode: 'stack' }, + data: rows, + }); + } + + cases.push({ + id: 'faithful', + chartType: 'Scatter Plot', + title: 'Old Faithful eruptions — waiting time vs duration', + blurb: 'A textbook bimodal relationship: short/long eruptions form two separated clouds.', + source: 'Härdle (1991) / R "faithful" dataset — 36-row sample', + license: 'Public domain (classic teaching set)', + semantic_types: { 'Duration (min)': 'Quantity', 'Waiting (min)': 'Quantity' }, + encodings: { x: 'Duration (min)', y: 'Waiting (min)' }, + data: FAITHFUL.map(([dur, wait]) => ({ 'Duration (min)': dur, 'Waiting (min)': wait })), + }); + + { + const rows: Record[] = []; + for (const [country, [y2000, y2021]] of Object.entries(LIFE_EXP)) { + rows.push({ Country: country, Year: 2000, 'Life expectancy': y2000 }); + rows.push({ Country: country, Year: 2021, 'Life expectancy': y2021 }); + } + cases.push({ + id: 'life-expectancy', + chartType: 'Slope Chart', + title: 'Life expectancy, 2000 → 2021', + blurb: 'Most countries rose; the US line dips (the COVID-era decline stands out).', + source: 'World Bank / Our World in Data', + license: 'CC-BY 4.0 (attribute OWID + World Bank)', + semantic_types: { Country: 'Country', Year: 'Year', 'Life expectancy': 'Quantity' }, + encodings: { x: 'Year', y: 'Life expectancy', color: 'Country' }, + data: rows, + }); + } + + // ----- More chart types (these still have Vega-Lite templates) ----- + + cases.push({ + id: 'population-waterfall', + chartType: 'Waterfall Chart', + title: 'World population growth 1950 → 2020, by region contribution', + blurb: 'A bridge from 2.5B to ~7.8B people, broken down by each region\'s addition.', + source: 'UN World Population Prospects 2022 (regional deltas)', + license: 'CC-BY 4.0 (attribute UN)', + semantic_types: { Step: 'Category', 'Population (M)': 'Quantity' }, + encodings: { x: 'Step', y: 'Population (M)' }, + data: [ + { Step: '1950', 'Population (M)': 2536 }, + { Step: 'Asia', 'Population (M)': 3237 }, + { Step: 'Africa', 'Population (M)': 1134 }, + { Step: 'Americas', 'Population (M)': 684 }, + { Step: 'Europe', 'Population (M)': 199 }, + { Step: 'Oceania', 'Population (M)': 32 }, + ], + chartProperties: { totals: 'last' }, + }); + + cases.push({ + id: 'nutrition-radar', + chartType: 'Radar Chart', + title: 'Nutrition profile per 100 g — Almonds vs Oats vs Greek yogurt', + blurb: 'Compare three foods across five nutrients; each food traces a distinct polygon.', + source: 'USDA FoodData Central (representative per-100g values)', + license: 'US-gov data (public domain)', + semantic_types: { Nutrient: 'Category', Food: 'Category', 'Grams/100g': 'Quantity' }, + encodings: { x: 'Nutrient', y: 'Grams/100g', color: 'Food' }, + data: (() => { + const table: Record> = { + Almonds: { Protein: 21, Fat: 50, Carbs: 22, Fiber: 12, Sugar: 4 }, + Oats: { Protein: 17, Fat: 7, Carbs: 66, Fiber: 11, Sugar: 1 }, + 'Greek yogurt': { Protein: 10, Fat: 5, Carbs: 4, Fiber: 0, Sugar: 4 }, + }; + const rows: Record[] = []; + for (const [food, byNutrient] of Object.entries(table)) { + for (const [nutrient, grams] of Object.entries(byNutrient)) { + rows.push({ Food: food, Nutrient: nutrient, 'Grams/100g': grams }); + } + } + return rows; + })(), + }); + + // Genuinely Plotly-only chart types (no Vega-Lite template) — these exercise + // the auto Plotly fallback. + cases.push({ + id: 'education-funnel', + chartType: 'Funnel Chart', + title: 'US educational attainment, age 25+ (2022)', + blurb: 'A real attainment funnel: of adults 25+, the share reaching each successive level. (Funnel → Plotly.)', + source: 'US Census Bureau, CPS 2022 educational attainment', + license: 'US-gov data (public domain)', + semantic_types: { Level: 'Category', 'Share (%)': 'Quantity' }, + encodings: { y: 'Level', size: 'Share (%)' }, + data: [ + { Level: 'High school or more', 'Share (%)': 91.1 }, + { Level: 'Some college or more', 'Share (%)': 61.3 }, + { Level: "Bachelor's or more", 'Share (%)': 37.7 }, + { Level: "Master's or more", 'Share (%)': 14.4 }, + { Level: 'Doctorate', 'Share (%)': 2.1 }, + ], + }); + + cases.push({ + id: 'renewables-gauge', + chartType: 'Gauge Chart', + title: 'Share of electricity from renewables, 2023', + blurb: 'Small-multiple gauges comparing a few countries against the global figure. (Gauge → Plotly.)', + source: 'Our World in Data / Ember (2023)', + license: 'CC-BY 4.0 (attribute OWID + Ember)', + semantic_types: { Country: 'Category', 'Renewable share (%)': 'Quantity' }, + encodings: { column: 'Country', size: 'Renewable share (%)' }, + data: [ + { Country: 'Norway', 'Renewable share (%)': 98.6 }, + { Country: 'Brazil', 'Renewable share (%)': 89.2 }, + { Country: 'Germany', 'Renewable share (%)': 51.6 }, + { Country: 'World', 'Renewable share (%)': 30.3 }, + { Country: 'United States', 'Renewable share (%)': 22.7 }, + ], + }); + // ───────────────────────────────────────────────────────────────────── + // Broader coverage — more chart types, real data (added for review). + // ───────────────────────────────────────────────────────────────────── + const MO = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + + // Regression — Auto MPG (horsepower vs mpg): classic downward relationship. + cases.push({ + id: 'auto-mpg', + chartType: 'Regression', + title: 'Auto MPG — horsepower vs fuel economy', + blurb: 'The classic inverse relationship: more horsepower, fewer miles per gallon.', + source: 'UCI / StatLib Auto MPG dataset (sample)', + license: 'UCI CC-BY / facts', + semantic_types: { Horsepower: 'Quantity', MPG: 'Quantity' }, + encodings: { x: 'Horsepower', y: 'MPG' }, + data: [[130, 18], [165, 15], [150, 18], [150, 16], [140, 17], [198, 15], [220, 14], [215, 14], [97, 22], [85, 26], [88, 25], [46, 26], [90, 25], [95, 24], [68, 29], [70, 27], [52, 30], [65, 31], [67, 30], [48, 43], [66, 32], [100, 22]].map(([Horsepower, MPG]) => ({ Horsepower, MPG })), + }); + + // Histogram — Old Faithful eruption durations (bimodal). + cases.push({ + id: 'faithful-hist', + chartType: 'Histogram', + title: 'Old Faithful — distribution of eruption durations', + blurb: 'Two humps: short (~2 min) and long (~4.5 min) eruptions. A mean would hide this.', + source: 'R "faithful" dataset (sample)', + license: 'Public domain', + semantic_types: { 'Duration (min)': 'Quantity' }, + encodings: { x: 'Duration (min)' }, + data: FAITHFUL.map(([dur]) => ({ 'Duration (min)': dur })), + }); + + // Density — Old Faithful durations. + cases.push({ + id: 'faithful-density', + chartType: 'Density Plot', + title: 'Old Faithful — eruption duration density', + blurb: 'The same bimodal shape as a smooth density curve.', + source: 'R "faithful" dataset (sample)', + license: 'Public domain', + semantic_types: { 'Duration (min)': 'Quantity' }, + encodings: { x: 'Duration (min)' }, + data: FAITHFUL.map(([dur]) => ({ 'Duration (min)': dur })), + }); + + // Boxplot — Penguin body mass by species. + cases.push({ + id: 'penguins-box', + chartType: 'Boxplot', + title: 'Penguin body mass by species', + blurb: 'Gentoo penguins are markedly heavier than Adélie and Chinstrap.', + source: 'Palmer Station LTER (sample)', + license: 'CC0', + semantic_types: { Species: 'Category', 'Body mass (g)': 'Quantity' }, + encodings: { x: 'Species', y: 'Body mass (g)' }, + data: PENGUINS.map(([Species, , mass]) => ({ Species, 'Body mass (g)': mass })), + }); + + // Violin — Penguin body mass by species (VL only). + cases.push({ + id: 'penguins-violin', + chartType: 'Violin Plot', + title: 'Penguin body mass by species (violin)', + blurb: 'Density shape per species — the Gentoo distribution sits clearly higher.', + source: 'Palmer Station LTER (sample)', + license: 'CC0', + semantic_types: { Species: 'Category', 'Body mass (g)': 'Quantity' }, + encodings: { x: 'Species', y: 'Body mass (g)' }, + data: PENGUINS.map(([Species, , mass]) => ({ Species, 'Body mass (g)': mass })), + }); + + // Strip — Iris petal length by species. + cases.push({ + id: 'iris-strip', + chartType: 'Strip Plot', + title: 'Iris petal length by species', + blurb: 'Setosa petals are tiny and tightly clustered; the other two overlap more.', + source: "Fisher's Iris (1936), sample", + license: 'Public domain', + semantic_types: { Species: 'Category', 'Petal length (cm)': 'Quantity' }, + encodings: { x: 'Species', y: 'Petal length (cm)' }, + data: (() => { + const t: Record = { Setosa: [1.4, 1.4, 1.3, 1.5, 1.4, 1.7, 1.4, 1.5, 1.5, 1.6], Versicolor: [4.7, 4.5, 4.9, 4.0, 4.6, 4.5, 4.7, 3.3, 4.6, 3.9], Virginica: [6.0, 5.1, 5.9, 5.6, 5.8, 6.6, 4.5, 6.3, 5.8, 6.1] }; + const rows: Record[] = []; + for (const [Species, arr] of Object.entries(t)) for (const v of arr) rows.push({ Species, 'Petal length (cm)': v }); + return rows; + })(), + }); + + // ECDF — exam scores. + cases.push({ + id: 'exam-ecdf', + chartType: 'ECDF Plot', + title: 'Exam scores — cumulative distribution', + blurb: 'Read percentiles directly: e.g. the median where the curve crosses 0.5.', + source: 'Illustrative class scores', + license: 'Illustrative', + semantic_types: { Score: 'Quantity' }, + encodings: { x: 'Score' }, + data: [55, 62, 68, 71, 73, 74, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 85, 86, 87, 88, 88, 89, 90, 91, 92, 93, 94, 95, 97, 99].map(Score => ({ Score })), + }); + + // Grouped Bar — Paris 2024 medals by country × type. + cases.push({ + id: 'medals-grouped', + chartType: 'Grouped Bar Chart', + title: 'Paris 2024 Olympic medals — top nations', + blurb: 'Gold / silver / bronze clustered per country.', + source: 'IOC, Paris 2024 medal table', + license: 'Facts (IOC)', + semantic_types: { Country: 'Country', Medal: 'Category', Count: 'Quantity' }, + encodings: { x: 'Country', y: 'Count', group: 'Medal' }, + data: (() => { + const t: Record = { 'United States': [40, 44, 42], China: [40, 27, 24], Japan: [20, 12, 13], Australia: [18, 19, 16], France: [16, 26, 22] }; + const kinds = ['Gold', 'Silver', 'Bronze']; + const rows: Record[] = []; + for (const [Country, arr] of Object.entries(t)) arr.forEach((Count, i) => rows.push({ Country, Medal: kinds[i], Count })); + return rows; + })(), + }); + + // Stacked Bar — electricity mix by country. + cases.push({ + id: 'electricity-stacked', + chartType: 'Stacked Bar Chart', + title: 'Electricity generation mix by country, 2023 (%)', + blurb: 'How each country splits generation across sources.', + source: 'Our World in Data / Ember (approx.)', + license: 'CC-BY (OWID/Ember)', + semantic_types: { Country: 'Country', Source: 'Category', Share: 'Quantity' }, + encodings: { x: 'Country', y: 'Share', color: 'Source' }, + data: (() => { + const t: Record> = { France: { Nuclear: 65, Renewables: 27, Fossil: 8 }, Germany: { Renewables: 52, Fossil: 45, Nuclear: 3 }, 'United States': { Fossil: 60, Nuclear: 18, Renewables: 22 }, China: { Fossil: 62, Renewables: 33, Nuclear: 5 }, Brazil: { Renewables: 89, Fossil: 9, Nuclear: 2 } }; + const rows: Record[] = []; + for (const [Country, by] of Object.entries(t)) for (const [Source, Share] of Object.entries(by)) rows.push({ Country, Source, Share }); + return rows; + })(), + }); + + // Lollipop — CO₂ per capita by country. + cases.push({ + id: 'co2-lollipop', + chartType: 'Lollipop Chart', + title: 'CO₂ emissions per capita, 2022 (tonnes)', + blurb: 'Per-person emissions vary ~20× across countries.', + source: 'Our World in Data (Global Carbon Project)', + license: 'CC-BY (OWID)', + semantic_types: { Country: 'Country', 'Tonnes/person': 'Quantity' }, + encodings: { x: 'Country', y: 'Tonnes/person' }, + data: [['Qatar', 37], ['UAE', 22], ['United States', 15], ['Canada', 14], ['Russia', 11], ['Japan', 8.5], ['China', 8.0], ['Germany', 8.0], ['UK', 5.0], ['France', 4.6], ['Brazil', 2.3], ['India', 2.0]].map(([Country, v]) => ({ Country, 'Tonnes/person': v })), + }); + + // Pyramid — US population by age & sex. + cases.push({ + id: 'us-pyramid', + chartType: 'Pyramid Chart', + title: 'US population by age and sex, 2020 (millions)', + blurb: 'A classic population pyramid — male vs female by age band.', + source: 'US Census 2020 (approx.)', + license: 'US-gov (PD)', + semantic_types: { Age: 'Category', Sex: 'Category', Population: 'Quantity' }, + encodings: { x: 'Population', y: 'Age', color: 'Sex' }, + data: (() => { + const ages = ['0–14', '15–29', '30–44', '45–59', '60–74', '75+']; + const m = [31, 34, 33, 30, 26, 10], f = [30, 32, 33, 31, 28, 15]; + const rows: Record[] = []; + ages.forEach((Age, i) => { rows.push({ Age, Sex: 'Male', Population: m[i] }); rows.push({ Age, Sex: 'Female', Population: f[i] }); }); + return rows; + })(), + }); + + // Bar Table — GDP by country. + cases.push({ + id: 'gdp-bartable', + chartType: 'Bar Table', + title: 'GDP by country, 2023 (trillion USD)', + blurb: 'Compact ranked bars with value labels.', + source: 'IMF / World Bank 2023', + license: 'CC-BY (IMF/WB)', + semantic_types: { Country: 'Country', 'GDP ($T)': 'Quantity' }, + encodings: { y: 'Country', x: 'GDP ($T)' }, + data: [['United States', 27.4], ['China', 17.8], ['Germany', 4.5], ['Japan', 4.2], ['India', 3.9], ['UK', 3.3], ['France', 3.0], ['Brazil', 2.2]].map(([Country, v]) => ({ Country, 'GDP ($T)': v })), + }); + + // Ranged Dot — male vs female life expectancy (dumbbell). + cases.push({ + id: 'lifeexp-dumbbell', + chartType: 'Ranged Dot Plot', + title: 'Life expectancy gap, male vs female (2021)', + blurb: 'The dumbbell length is the female–male gap in years.', + source: 'World Bank 2021', + license: 'CC-BY (WB)', + semantic_types: { Country: 'Country', Sex: 'Category', 'Life expectancy': 'Quantity' }, + encodings: { x: 'Life expectancy', y: 'Country', color: 'Sex' }, + data: (() => { + const t: Record = { Japan: [81.5, 87.6], 'United States': [73.5, 79.3], India: [66.0, 69.0], Brazil: [69.0, 76.0], Nigeria: [51.0, 54.0], Germany: [78.5, 83.4] }; + const rows: Record[] = []; + for (const [Country, [mm, ff]] of Object.entries(t)) { rows.push({ Country, Sex: 'Male', 'Life expectancy': mm }); rows.push({ Country, Sex: 'Female', 'Life expectancy': ff }); } + return rows; + })(), + }); + + // Range Area — Seattle monthly temp low/high. + cases.push({ + id: 'seattle-range', + chartType: 'Range Area Chart', + title: 'Seattle average monthly temperature range (°F)', + blurb: 'The band spans the average daily low to high each month.', + source: 'NOAA climate normals', + license: 'US-gov (PD)', + semantic_types: { Month: 'Category', Low: 'Quantity', High: 'Quantity' }, + encodings: { x: 'Month', y: 'Low', y2: 'High' }, + data: (() => { const lo = [37, 37, 40, 43, 48, 53, 56, 57, 53, 46, 40, 36], hi = [47, 50, 54, 59, 65, 70, 76, 77, 71, 60, 51, 46]; return MO.map((Month, i) => ({ Month, Low: lo[i], High: hi[i] })); })(), + }); + + // Bump — Olympic medal-table rank over four Games. + cases.push({ + id: 'olympic-bump', + chartType: 'Bump Chart', + title: 'Olympic medal-table rank, 2012–2024', + blurb: 'Rank over four Summer Games (1 = top of the table).', + source: 'IOC medal tables', + license: 'Facts (IOC)', + semantic_types: { Games: 'Year', Country: 'Country', Rank: 'Quantity' }, + encodings: { x: 'Games', y: 'Rank', color: 'Country' }, + data: (() => { + const games = [2012, 2016, 2020, 2024]; + const t: Record = { 'United States': [1, 1, 1, 1], China: [2, 3, 2, 2], 'Great Britain': [3, 2, 4, 7], Japan: [6, 6, 5, 3] }; + const rows: Record[] = []; + for (const [Country, ranks] of Object.entries(t)) games.forEach((Games, i) => rows.push({ Games, Country, Rank: ranks[i] })); + return rows; + })(), + }); + + // Streamgraph — world population by region (reuse POP_REGION). + (() => { + const rows: Record[] = []; + for (const [yr, by] of Object.entries(POP_REGION)) for (const [Region, Population] of Object.entries(by)) rows.push({ Year: Number(yr), Region, Population }); + cases.push({ + id: 'population-stream', + chartType: 'Streamgraph', + title: 'World population by region (streamgraph)', + blurb: 'The same regional totals as a centre-stacked stream.', + source: 'UN World Population Prospects 2022', + license: 'CC-BY (UN)', + semantic_types: { Year: 'Year', Region: 'Category', Population: 'Quantity' }, + encodings: { x: 'Year', y: 'Population', color: 'Region' }, + data: rows, + }); + })(); + + // Pie — desktop browser share. + cases.push({ + id: 'browser-pie', + chartType: 'Pie Chart', + title: 'Desktop browser market share, 2024', + blurb: 'Chrome dominates; Safari and Edge trail.', + source: 'StatCounter (approx. 2024)', + license: 'Illustrative (StatCounter)', + semantic_types: { Browser: 'Category', Share: 'Quantity' }, + encodings: { size: 'Share', color: 'Browser' }, + data: [['Chrome', 65], ['Safari', 12], ['Edge', 12], ['Firefox', 6], ['Other', 5]].map(([Browser, Share]) => ({ Browser, Share })), + }); + + // Donut — mobile OS share. + cases.push({ + id: 'mobile-donut', + chartType: 'Donut Chart', + title: 'Mobile OS market share, 2024', + blurb: 'Android vs iOS worldwide.', + source: 'StatCounter (approx. 2024)', + license: 'Illustrative (StatCounter)', + semantic_types: { OS: 'Category', Share: 'Quantity' }, + encodings: { size: 'Share', color: 'OS' }, + data: [['Android', 71], ['iOS', 28], ['Other', 1]].map(([OS, Share]) => ({ OS, Share })), + }); + + // Rose — Seattle monthly rainfall (polar bars). + cases.push({ + id: 'seattle-rose', + chartType: 'Rose Chart', + title: 'Seattle monthly rainfall (mm)', + blurb: 'Wet winters, dry midsummer — as polar bars around the year.', + source: 'NOAA climate normals', + license: 'US-gov (PD)', + semantic_types: { Month: 'Category', 'Rainfall (mm)': 'Quantity' }, + encodings: { x: 'Month', y: 'Rainfall (mm)' }, + data: (() => { const r = [140, 90, 95, 70, 50, 40, 18, 25, 40, 100, 165, 155]; return MO.map((Month, i) => ({ Month, 'Rainfall (mm)': r[i] })); })(), + }); + + // Candlestick — a couple of weeks of a stock's daily OHLC. + cases.push({ + id: 'stock-candle', + chartType: 'Candlestick Chart', + title: 'A stock, daily OHLC (two weeks)', + blurb: 'Open-high-low-close candles over ~10 trading days.', + source: 'Illustrative daily prices', + license: 'Illustrative', + semantic_types: { Date: 'Date', Open: 'Quantity', High: 'Quantity', Low: 'Quantity', Close: 'Quantity' }, + encodings: { x: 'Date', open: 'Open', high: 'High', low: 'Low', close: 'Close' }, + data: [['2024-01-02', 187, 188, 183, 185], ['2024-01-03', 184, 185, 182, 184], ['2024-01-04', 182, 183, 180, 182], ['2024-01-05', 182, 182, 179, 181], ['2024-01-08', 182, 186, 182, 185], ['2024-01-09', 184, 185, 183, 185], ['2024-01-10', 184, 186, 183, 186], ['2024-01-11', 186, 187, 183, 186], ['2024-01-12', 186, 188, 185, 185]].map(([Date, Open, High, Low, Close]) => ({ Date, Open, High, Low, Close })), + }); + + // Heatmap — city × month temperature. + cases.push({ + id: 'temp-heatmap', + chartType: 'Heatmap', + title: 'Average monthly temperature by city (°C)', + blurb: 'Warm bands for the tropics, cold winters for Moscow.', + source: 'Climate normals (approx.)', + license: 'Illustrative', + semantic_types: { Month: 'Category', City: 'Category', 'Temp (°C)': 'Quantity' }, + encodings: { x: 'Month', y: 'City', color: 'Temp (°C)' }, + data: (() => { + const t: Record = { Singapore: [26, 27, 28, 28, 28, 28, 27, 27, 27, 27, 26, 26], Cairo: [14, 15, 18, 22, 26, 28, 29, 29, 27, 24, 20, 16], Moscow: [-9, -7, -1, 7, 13, 17, 19, 17, 11, 5, -1, -6], Seattle: [5, 6, 8, 10, 13, 16, 19, 19, 16, 11, 7, 4] }; + const rows: Record[] = []; + for (const [City, arr] of Object.entries(t)) arr.forEach((v, i) => rows.push({ City, Month: MO[i], 'Temp (°C)': v })); + return rows; + })(), + }); + + // KPI Card — renewable share vs target. + cases.push({ + id: 'renewable-kpi', + chartType: 'KPI Card', + title: 'Global renewable electricity share (2023)', + blurb: 'A single headline number against its 2030 target.', + source: 'Our World in Data / Ember', + license: 'CC-BY (OWID/Ember)', + semantic_types: { Metric: 'Category', 'Share (%)': 'Quantity', Target: 'Quantity' }, + encodings: { metric: 'Metric', value: 'Share (%)', goal: 'Target' }, + data: [{ Metric: 'Renewable share', 'Share (%)': 30.3, Target: 45 }], + }); + + // Bullet — renewable share vs 2030 target by country. + cases.push({ + id: 'renewable-bullet', + chartType: 'Bullet Chart', + title: 'Renewable electricity share vs 2030 target', + blurb: 'Each bar is the current share; the tick marks the 2030 target.', + source: 'Our World in Data / Ember (targets illustrative)', + license: 'CC-BY (OWID/Ember)', + semantic_types: { Country: 'Country', Share: 'Quantity', Target: 'Quantity' }, + encodings: { y: 'Country', x: 'Share', goal: 'Target' }, + data: [['Norway', 98.6, 100], ['Brazil', 89.2, 95], ['Germany', 51.6, 80], ['World', 30.3, 60], ['United States', 22.7, 50]].map(([Country, Share, Target]) => ({ Country, Share, Target })), + }); + + // Map — world cities bubble. + cases.push({ + id: 'cities-map', + chartType: 'Map', + title: "World's largest cities (metro population)", + blurb: 'Bubble size = metro-area population.', + source: 'UN / city statistics (approx.)', + license: 'CC-BY / facts', + semantic_types: { City: 'City', Lon: 'Longitude', Lat: 'Latitude', 'Population (M)': 'Quantity' }, + encodings: { longitude: 'Lon', latitude: 'Lat', size: 'Population (M)' }, + data: [['Tokyo', 139.7, 35.7, 37.4], ['Delhi', 77.2, 28.6, 32.9], ['Shanghai', 121.5, 31.2, 29.2], ['São Paulo', -46.6, -23.5, 22.6], ['Mexico City', -99.1, 19.4, 22.1], ['Cairo', 31.2, 30.0, 21.3], ['New York', -74.0, 40.7, 18.9], ['Lagos', 3.4, 6.5, 15.4], ['London', -0.1, 51.5, 9.5], ['Los Angeles', -118.2, 34.1, 12.4]].map(([City, Lon, Lat, p]) => ({ City, Lon, Lat, 'Population (M)': p })), + }); + + // Gantt — a software release schedule. + cases.push({ + id: 'release-gantt', + chartType: 'Gantt Chart', + title: 'Software release schedule', + blurb: 'Overlapping phases from planning to launch.', + source: 'Illustrative project plan', + license: 'Illustrative', + semantic_types: { Task: 'Category', Start: 'Date', End: 'Date' }, + encodings: { y: 'Task', x: 'Start', x2: 'End' }, + data: [['Planning', '2024-01-01', '2024-01-14'], ['Design', '2024-01-15', '2024-02-04'], ['Implementation', '2024-02-05', '2024-03-17'], ['Testing', '2024-03-11', '2024-04-07'], ['Launch', '2024-04-08', '2024-04-15']].map(([Task, Start, End]) => ({ Task, Start, End })), + }); + + // Sparkline — monthly KPI small multiples. + cases.push({ + id: 'kpi-sparkline', + chartType: 'Sparkline', + title: 'Monthly KPIs (sparklines)', + blurb: 'Three metrics as mini trend lines, one per row.', + source: 'Illustrative company metrics', + license: 'Illustrative', + semantic_types: { Month: 'Category', Metric: 'Category', Value: 'Quantity' }, + encodings: { x: 'Month', y: 'Value', color: 'Metric' }, + data: (() => { + const t: Record = { 'Revenue ($k)': [120, 125, 130, 128, 140, 145, 150, 148, 160, 165, 170, 180], 'Active users (k)': [40, 42, 45, 47, 50, 52, 55, 58, 60, 63, 66, 70], 'Churn (%)': [5.2, 5.0, 4.8, 4.9, 4.6, 4.5, 4.3, 4.4, 4.1, 4.0, 3.9, 3.8] }; + const rows: Record[] = []; + for (const [Metric, arr] of Object.entries(t)) arr.forEach((Value, i) => rows.push({ Month: MO[i], Metric, Value })); + return rows; + })(), + }); + // ───────────────────────────────────────────────────────────────────── + // Iconic / high-interest datasets (variety + "wow" for the gallery). + // ───────────────────────────────────────────────────────────────────── + + // Gapminder bubble — life expectancy vs income, sized by population. + cases.push({ + id: 'gapminder-bubble', + chartType: 'Scatter Plot', + title: 'Gapminder — life expectancy vs income per capita (2018)', + blurb: 'The Rosling bubble chart: wealth vs health, bubble = population, colour = continent (log income axis).', + source: 'Gapminder / World Bank (2018)', + license: 'CC-BY (Gapminder)', + semantic_types: { 'GDP per capita': 'Quantity', 'Life expectancy': 'Quantity', 'Population (M)': 'Quantity', Continent: 'Category' }, + encodings: { x: 'GDP per capita', y: 'Life expectancy', size: 'Population (M)', color: 'Continent' }, + chartProperties: { logScale_x: true }, + data: [ + ['Norway', 64800, 82.3, 5.3, 'Europe'], ['United States', 62600, 78.6, 327, 'Americas'], + ['Japan', 39300, 84.2, 127, 'Asia'], ['China', 16800, 76.7, 1393, 'Asia'], + ['India', 6900, 69.4, 1353, 'Asia'], ['Nigeria', 5300, 54.3, 196, 'Africa'], + ['Brazil', 15600, 75.7, 209, 'Americas'], ['Germany', 50900, 81.0, 83, 'Europe'], + ['Ethiopia', 2000, 66.2, 109, 'Africa'], ['Russia', 25800, 72.4, 145, 'Europe'], + ['Mexico', 19800, 75.0, 126, 'Americas'], ['Indonesia', 12400, 71.5, 268, 'Asia'], + ['Qatar', 116900, 80.1, 2.8, 'Asia'], ['South Africa', 13000, 63.9, 57, 'Africa'], + ['Bangladesh', 4200, 72.3, 161, 'Asia'], + ].map(([Country, gdp, life, pop, Continent]) => ({ Country, 'GDP per capita': gdp, 'Life expectancy': life, 'Population (M)': pop, Continent })), + }); + + // Anscombe's Quartet — four datasets, identical stats, different shapes. + cases.push({ + id: 'anscombe', + chartType: 'Regression', + title: "Anscombe's Quartet — same stats, different shapes", + blurb: 'Four datasets with identical means, variances and regression lines — but wildly different when plotted.', + source: 'F. J. Anscombe (1973)', + license: 'Public domain', + semantic_types: { Dataset: 'Category', X: 'Quantity', Y: 'Quantity' }, + encodings: { x: 'X', y: 'Y', column: 'Dataset' }, + data: (() => { + const x1 = [10, 8, 13, 9, 11, 14, 6, 4, 12, 7, 5]; + const sets: Record = { + I: { x: x1, y: [8.04, 6.95, 7.58, 8.81, 8.33, 9.96, 7.24, 4.26, 10.84, 4.82, 5.68] }, + II: { x: x1, y: [9.14, 8.14, 8.74, 8.77, 9.26, 8.10, 6.13, 3.10, 9.13, 7.26, 4.74] }, + III: { x: x1, y: [7.46, 6.77, 12.74, 7.11, 7.81, 8.84, 6.08, 5.39, 8.15, 6.42, 5.73] }, + IV: { x: [8, 8, 8, 8, 8, 8, 8, 19, 8, 8, 8], y: [6.58, 5.76, 7.71, 8.84, 8.47, 7.04, 5.25, 12.50, 5.56, 7.91, 6.89] }, + }; + const rows: Record[] = []; + for (const [Dataset, { x, y }] of Object.entries(sets)) x.forEach((X, i) => rows.push({ Dataset, X, Y: y[i] })); + return rows; + })(), + }); + + // Temperature anomaly — diverging bars crossing zero (warming). + cases.push({ + id: 'temp-anomaly', + chartType: 'Bar Chart', + title: 'Global temperature anomaly by decade (°C vs 1951–1980)', + blurb: 'Bars cross zero — cool early decades below, rapid warming above.', + source: 'NASA GISTEMP (approx. decadal means)', + license: 'US-gov (PD)', + semantic_types: { Decade: 'Category', 'Anomaly (°C)': 'Quantity' }, + encodings: { x: 'Decade', y: 'Anomaly (°C)' }, + data: [['1880s', -0.17], ['1900s', -0.16], ['1920s', -0.27], ['1940s', 0.12], ['1960s', -0.03], ['1980s', 0.26], ['2000s', 0.40], ['2010s', 0.72], ['2020s', 1.02]].map(([Decade, v]) => ({ Decade, 'Anomaly (°C)': v })), + }); + + // US unemployment 2000–2023 — the recession spikes. + cases.push({ + id: 'us-unemployment', + chartType: 'Line Chart', + title: 'US unemployment rate, 2000–2023 (%)', + blurb: 'The 2009 financial-crisis plateau and the sharp 2020 pandemic spike.', + source: 'US Bureau of Labor Statistics', + license: 'US-gov (PD)', + semantic_types: { Year: 'Year', 'Unemployment (%)': 'Quantity' }, + encodings: { x: 'Year', y: 'Unemployment (%)' }, + data: [[2000, 4.0], [2001, 4.7], [2002, 5.8], [2003, 6.0], [2004, 5.5], [2005, 5.1], [2006, 4.6], [2007, 4.6], [2008, 5.8], [2009, 9.3], [2010, 9.6], [2011, 8.9], [2012, 8.1], [2013, 7.4], [2014, 6.2], [2015, 5.3], [2016, 4.9], [2017, 4.4], [2018, 3.9], [2019, 3.7], [2020, 8.1], [2021, 5.3], [2022, 3.6], [2023, 3.6]].map(([Year, v]) => ({ Year, 'Unemployment (%)': v })), + }); + + // Titanic survival by class & sex. + cases.push({ + id: 'titanic', + chartType: 'Grouped Bar Chart', + title: 'Titanic survival rate by class and sex', + blurb: '"Women and children first" — and first class — are stark in the numbers.', + source: 'Encyclopedia Titanica passenger records', + license: 'Facts (public)', + semantic_types: { Class: 'Category', Sex: 'Category', 'Survival (%)': 'Quantity' }, + encodings: { x: 'Class', y: 'Survival (%)', group: 'Sex' }, + data: (() => { + const t: Record = { '1st': [97, 34], '2nd': [89, 15], '3rd': [49, 15] }; + const rows: Record[] = []; + for (const [Class, [fem, male]] of Object.entries(t)) { rows.push({ Class, Sex: 'Female', 'Survival (%)': fem }); rows.push({ Class, Sex: 'Male', 'Survival (%)': male }); } + return rows; + })(), + }); + + // Diamonds — carat vs price. + cases.push({ + id: 'diamonds', + chartType: 'Scatter Plot', + title: 'Diamonds — carat vs price', + blurb: 'Price rises steeply and non-linearly with carat weight.', + source: 'ggplot2 "diamonds" (sample)', + license: 'Public domain (sample)', + semantic_types: { Carat: 'Quantity', 'Price (USD)': 'Quantity' }, + encodings: { x: 'Carat', y: 'Price (USD)' }, + data: [[0.23, 326], [0.21, 326], [0.29, 334], [0.31, 335], [0.24, 336], [0.4, 900], [0.5, 1500], [0.6, 1800], [0.7, 2500], [0.8, 3000], [0.9, 3900], [1.0, 5000], [1.01, 5200], [1.1, 6000], [1.2, 7200], [1.3, 8200], [1.5, 10000], [1.7, 13000], [2.0, 18000], [2.5, 25000]].map(([Carat, p]) => ({ Carat, 'Price (USD)': p })), + }); + + // World Happiness vs income. + cases.push({ + id: 'happiness', + chartType: 'Scatter Plot', + title: 'World Happiness vs income per capita (2023)', + blurb: 'Happiness rises with income — but with diminishing returns (log income axis).', + source: 'World Happiness Report 2023 / World Bank', + license: 'CC-BY', + semantic_types: { Country: 'Country', 'GDP per capita': 'Quantity', 'Happiness score': 'Quantity' }, + encodings: { x: 'GDP per capita', y: 'Happiness score' }, + chartProperties: { logScale_x: true }, + data: [['Finland', 54000, 7.8], ['Denmark', 68000, 7.6], ['United States', 76000, 6.9], ['Germany', 51000, 7.0], ['Japan', 34000, 6.1], ['Brazil', 9000, 6.1], ['China', 12800, 5.8], ['Mexico', 11000, 6.3], ['India', 2400, 4.0], ['Nigeria', 2200, 4.9], ['Kenya', 2100, 4.5], ['Costa Rica', 12500, 7.1]].map(([Country, gdp, h]) => ({ Country, 'GDP per capita': gdp, 'Happiness score': h })), + }); + + // Sunspot cycle — the ~11-year solar cycle. + cases.push({ + id: 'sunspots', + chartType: 'Line Chart', + title: 'Sunspot number, 2000–2023', + blurb: 'The ~11-year solar cycle: a deep minimum around 2008–2019, rising again by 2023.', + source: 'SILSO / Royal Observatory of Belgium (approx.)', + license: 'CC-BY (SILSO)', + semantic_types: { Year: 'Year', 'Sunspot number': 'Quantity' }, + encodings: { x: 'Year', y: 'Sunspot number' }, + data: [[2000, 120], [2001, 111], [2002, 104], [2003, 64], [2004, 40], [2005, 30], [2006, 15], [2007, 8], [2008, 3], [2009, 3], [2010, 16], [2011, 56], [2012, 58], [2013, 65], [2014, 79], [2015, 67], [2016, 40], [2017, 22], [2018, 7], [2019, 4], [2020, 9], [2021, 29], [2022, 83], [2023, 123]].map(([Year, v]) => ({ Year, 'Sunspot number': v })), + }); + + // Marathon world record progression. + cases.push({ + id: 'marathon-wr', + chartType: 'Line Chart', + title: "Men's marathon world record, 1908–2023 (minutes)", + blurb: 'A century of steady improvement — closing in on the two-hour barrier.', + source: 'World Athletics record progression', + license: 'Facts (public)', + semantic_types: { Year: 'Year', 'Record (min)': 'Quantity' }, + encodings: { x: 'Year', y: 'Record (min)' }, + data: [[1908, 175], [1925, 173], [1935, 166], [1947, 165], [1958, 155], [1967, 150], [1969, 148], [1988, 127], [1998, 126], [2003, 125], [2008, 124], [2011, 123.6], [2014, 122.9], [2018, 121.6], [2022, 121.1], [2023, 120.6]].map(([Year, v]) => ({ Year, 'Record (min)': v })), + }); + + // EV share of new car sales, multi-country. + cases.push({ + id: 'ev-share', + chartType: 'Line Chart', + title: 'Electric-vehicle share of new car sales (%)', + blurb: 'Norway is far ahead; China and Europe accelerating, the US catching up.', + source: 'Our World in Data / IEA (approx.)', + license: 'CC-BY (OWID/IEA)', + semantic_types: { Year: 'Year', Country: 'Country', 'EV share (%)': 'Quantity' }, + encodings: { x: 'Year', y: 'EV share (%)', color: 'Country' }, + data: (() => { + const years = [2018, 2020, 2022, 2023]; + const t: Record = { Norway: [49, 75, 88, 93], China: [4, 6, 29, 38], Germany: [2, 13, 31, 25], 'United States': [2, 2, 8, 10] }; + const rows: Record[] = []; + for (const [Country, arr] of Object.entries(t)) years.forEach((Year, i) => rows.push({ Year, Country, 'EV share (%)': arr[i] })); + return rows; + })(), + }); + + // Global internet users over time (adoption curve). + cases.push({ + id: 'internet-users', + chartType: 'Area Chart', + title: 'Share of the world online, 1995–2023 (%)', + blurb: 'From ~1% to two-thirds of humanity in under three decades.', + source: 'Our World in Data / ITU', + license: 'CC-BY (OWID/ITU)', + semantic_types: { Year: 'Year', 'Internet users (%)': 'Quantity' }, + encodings: { x: 'Year', y: 'Internet users (%)' }, + data: [[1995, 1], [2000, 7], [2005, 16], [2010, 29], [2015, 43], [2018, 51], [2020, 60], [2023, 67]].map(([Year, v]) => ({ Year, 'Internet users (%)': v })), + }); + + // Big Mac index — currency-value proxy. + cases.push({ + id: 'big-mac', + chartType: 'Bar Chart', + title: 'The Big Mac index, 2023 (price in USD)', + blurb: 'The Economist\'s tongue-in-cheek measure of purchasing power.', + source: 'The Economist Big Mac index (approx. 2023)', + license: 'Illustrative (The Economist)', + semantic_types: { Country: 'Country', 'Price (USD)': 'Quantity' }, + encodings: { x: 'Country', y: 'Price (USD)' }, + data: [['Switzerland', 8.1], ['Norway', 6.9], ['United States', 5.7], ['Euro area', 5.5], ['UK', 4.9], ['Brazil', 4.5], ['Mexico', 3.9], ['China', 3.5], ['Japan', 3.2], ['Egypt', 2.7], ['South Africa', 2.6], ['India', 2.5]].map(([Country, p]) => ({ Country, 'Price (USD)': p })), + }); + + return cases; +} + +export const PREVIEW_CASES: PreviewCase[] = buildCases(); diff --git a/site/src/routes/dev/dev.css b/site/src/playground/playground.css similarity index 100% rename from site/src/routes/dev/dev.css rename to site/src/playground/playground.css diff --git a/site/src/routes/ChartWall.tsx b/site/src/routes/ChartWall.tsx index 1b9aae3e..29c1eba4 100644 --- a/site/src/routes/ChartWall.tsx +++ b/site/src/routes/ChartWall.tsx @@ -41,6 +41,7 @@ const MAX_VARIANTS = 4; const TILE_CHART_HEIGHT = 190; const SCROLL_SPY_ACTIVATION_RATIO = 0.45; const SCROLL_SPY_VISIBLE_MARGIN = 24; +type GalleryBackend = PreviewBackend | 'excel'; function loadTests(generator: string): TestCase[] { const gen = TEST_GENERATORS[generator]; @@ -85,13 +86,29 @@ interface FamilyGroup { * under their gallery family so related chart types stay together while each * type keeps its own heading and sidebar entry. */ -function buildGroups(charts: ChartEntry[], locale: Locale): FamilyGroup[] { +function buildGroups( + charts: ChartEntry[], + locale: Locale, + backend: PreviewBackend, +): FamilyGroup[] { const sectionsByFamily = new Map(); for (const chart of charts) { const full = loadTests(chart.generator); - const variants = selectVariants(full, MAX_VARIANTS); + // Global vs. local dodge only produces a visibly distinct layout in + // Vega-Lite (centered lanes). Plotly reuses the generic generators, so + // drop the `dodge-*` demo cases everywhere except the Vega-Lite gallery. + const visible = + backend === 'vegalite' + ? full + : full.filter( + (tc) => + !tc.tags?.some((t) => t === 'dodge-global' || t === 'dodge-local'), + ); + const variants = selectVariants(visible, MAX_VARIANTS); if (variants.length === 0) continue; + // Indices must point into the FULL generator output (the editor resolves + // TEST_GENERATORS[generator][index]), not the filtered subset. const indices = variants.map((v) => full.indexOf(v)); const titles = humanizeVariants(variants, locale); const tiles = variants.map((testCase, pos) => ({ @@ -150,7 +167,7 @@ export function ChartWall() { } }, [backendParam, category.id, navigate, lp]); - const groups = useMemo(() => buildGroups(category.charts, locale), [category, locale]); + const groups = useMemo(() => buildGroups(category.charts, locale, category.id), [category, locale]); const sectionIds = useMemo( () => groups.flatMap((g) => g.sections.map((s) => s.chart.id)), [groups], @@ -213,7 +230,7 @@ export function ChartWall() { }; }, [sectionIds]); - const scrollToGallery = useCallback((id: PreviewBackend) => { + const scrollToGallery = useCallback((id: GalleryBackend) => { if (id !== category.id) { navigate(lp(`/gallery/${id}`)); return; @@ -298,9 +315,9 @@ export function ChartWall() {
-

+

{t('gallery.title')} - + {' '} {t('gallery.titleBackend', { backend: category.label })} @@ -402,7 +419,7 @@ function WallSidebar({ groups: FamilyGroup[]; activeChartId: string | null; onNavigate: (id: string) => void; - onSelectBackend: (id: PreviewBackend) => void; + onSelectBackend: (id: GalleryBackend) => void; }) { const { t } = useTranslation(); return ( @@ -417,6 +434,12 @@ function WallSidebar({ onClick={() => onSelectBackend(c.id)} /> ))} + onSelectBackend('excel')} + /> @@ -503,7 +526,7 @@ function MobileBackendTabs({ onSelectBackend, }: { category: ChartCategory; - onSelectBackend: (id: PreviewBackend) => void; + onSelectBackend: (id: GalleryBackend) => void; }) { const { t } = useTranslation(); return ( @@ -527,6 +550,13 @@ function MobileBackendTabs({ ); })} +

); } @@ -561,6 +591,7 @@ function BackendIntro({ vegalite: 'spec', echarts: 'option', chartjs: 'config', + plotly: 'figure', }; const snippet = `import { ${category.fn} } from 'flint-chart'; diff --git a/site/src/routes/Editor.tsx b/site/src/routes/Editor.tsx index a3317a92..f9306a22 100644 --- a/site/src/routes/Editor.tsx +++ b/site/src/routes/Editor.tsx @@ -318,6 +318,7 @@ const OUTPUT_LANG: Record = { vegalite: 'Vega-Lite JSON', echarts: 'ECharts option', chartjs: 'Chart.js config', + plotly: 'Plotly figure', }; /** diff --git a/site/src/routes/ExcelGallery.tsx b/site/src/routes/ExcelGallery.tsx new file mode 100644 index 00000000..caf22240 --- /dev/null +++ b/site/src/routes/ExcelGallery.tsx @@ -0,0 +1,263 @@ +import { useCallback, type CSSProperties } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { SiteShell } from '../components/SiteShell'; +import { SidebarNav, SidebarNavItem, SidebarNavSection } from '../components/SidebarNav'; +import { useLocale } from '../i18n/LocaleContext'; +import { CHART_CATEGORIES } from '../shared/chart-categories'; +import { CONTENT_MAX_WIDTH, GITHUB_REPO, siteTheme } from '../shared/theme'; +import groupedBar from '../assets/excel-gallery/grouped-bar.png'; +import multiSeriesLine from '../assets/excel-gallery/multi-series-line.png'; +import stackedArea from '../assets/excel-gallery/stacked-area.png'; +import treemap from '../assets/excel-gallery/treemap.png'; +import sunburst from '../assets/excel-gallery/sunburst.png'; +import waterfall from '../assets/excel-gallery/waterfall.png'; +import pyramid from '../assets/excel-gallery/pyramid.png'; +import radar from '../assets/excel-gallery/radar.png'; +import candlestick from '../assets/excel-gallery/candlestick.png'; + +const HARNESS_URL = `${GITHUB_REPO}/tree/main/test-harness/excel`; +const EXAMPLES_URL = `${GITHUB_REPO}/tree/main/test-harness/excel/evaluations/examples`; + +const EXAMPLES = [ + { id: 'grouped-bar', title: 'Grouped bar', image: groupedBar, nativeType: 'ColumnClustered' }, + { id: 'multi-series-line', title: 'Multi-series line', image: multiSeriesLine, nativeType: 'XYScatterLines' }, + { id: 'stacked-area', title: 'Stacked area', image: stackedArea, nativeType: 'AreaStacked' }, + { id: 'treemap', title: 'Treemap', image: treemap, nativeType: 'Treemap' }, + { id: 'sunburst', title: 'Sunburst', image: sunburst, nativeType: 'Sunburst' }, + { id: 'waterfall', title: 'Waterfall', image: waterfall, nativeType: 'Waterfall' }, + { id: 'pyramid', title: 'Population pyramid', image: pyramid, nativeType: 'BarStacked' }, + { id: 'radar', title: 'Radar', image: radar, nativeType: 'RadarMarkers' }, + { id: 'candlestick', title: 'Candlestick', image: candlestick, nativeType: 'StockOHLC' }, +]; + +const COPY = { + en: { + title: 'Chart gallery', + backend: 'Excel backend', + galleries: 'Galleries', + examples: 'Native chart examples', + intro: 'Flint compiles semantic chart specs into native, editable Excel charts through Office.js. Because Excel is the renderer, this gallery shows verified captures from the real Excel for Mac worker instead of a browser preview.', + provenance: 'These are unedited Chart.getImage() captures. The source data, titles, axes, formatting, and series remain editable in the workbook.', + harnessTitle: 'Render with the test harness', + steps: [ + 'Install the Office add-in development certificate and sideload the Flint Render manifest once.', + 'Start the supervised HTTPS worker from test-harness/excel.', + 'Open Flint Render in Excel, then run a gallery or targeted evaluation command.', + ], + harnessLink: 'Test harness guide', + examplesLink: 'Snapshot provenance', + }, + 'zh-CN': { + title: '图表示例', + backend: 'Excel 后端', + galleries: '示例库', + examples: '原生图表示例', + intro: 'Flint 通过 Office.js 将语义图表规范编译为可编辑的原生 Excel 图表。由于渲染器是 Excel,本页展示真实 Excel for Mac 工作进程生成并验证过的截图,而不是浏览器实时预览。', + provenance: '这些图片是未经编辑的 Chart.getImage() 输出;工作簿中的源数据、标题、坐标轴、格式和系列仍可继续编辑。', + harnessTitle: '使用测试工具渲染', + steps: [ + '安装 Office 加载项开发证书,并一次性旁加载 Flint Render manifest。', + '在 test-harness/excel 中启动受监控的 HTTPS 工作进程。', + '在 Excel 中打开 Flint Render,再运行示例库或指定图表的评估命令。', + ], + harnessLink: '测试工具指南', + examplesLink: '截图来源', + }, +} as const; + +export function ExcelGallery() { + const { locale, lp } = useLocale(); + const navigate = useNavigate(); + const copy = COPY[locale]; + const navigateToExample = useCallback((id: string) => { + document.getElementById(id)?.scrollIntoView({ behavior: 'smooth', block: 'start' }); + }, []); + + return ( + + +
+
+ + + {CHART_CATEGORIES.map((category) => ( + navigate(lp(`/gallery/${category.id}`))} + > + {category.label} + + ))} + window.scrollTo({ top: 0, behavior: 'smooth' })}> + Excel + + + + {EXAMPLES.map((example) => ( + navigateToExample(example.id)}> + {example.title} + + ))} + + + +
+
+

+ {copy.title} ({copy.backend}) +

+ +

{copy.intro}

+

{copy.provenance}

+
+ +
+ {EXAMPLES.map((example) => ( +
+
+ {`${example.title} +
+
+ {example.title} + {example.nativeType} +
+
+ ))} +
+ +
+

{copy.harnessTitle}

+
    + {copy.steps.map((step) =>
  1. {step}
  2. )} +
+ +
+
+
+
+
+ ); +} + +const scrollStyle: CSSProperties = { flex: 1, minHeight: 0, overflowY: 'auto', background: siteTheme.surface }; +const layoutStyle: CSSProperties = { display: 'flex', alignItems: 'flex-start', width: '100%', maxWidth: CONTENT_MAX_WIDTH, margin: '0 auto' }; +const mainStyle: CSSProperties = { flex: 1, minWidth: 0, maxWidth: 1100, margin: '0 auto', padding: '36px 40px 96px' }; +const headerStyle: CSSProperties = { maxWidth: 820, marginBottom: 32 }; +const titleStyle: CSSProperties = { margin: 0, color: siteTheme.text, fontSize: 28, fontWeight: 600, letterSpacing: 0 }; +const backendTitleStyle: CSSProperties = { color: siteTheme.textMuted, fontWeight: 400 }; +const introStyle: CSSProperties = { margin: '20px 0 0', color: siteTheme.text, fontSize: 17, lineHeight: 1.65 }; +const provenanceStyle: CSSProperties = { margin: '10px 0 0', color: siteTheme.textMuted, fontSize: 14, lineHeight: 1.6 }; +const cardStyle: CSSProperties = { margin: 0, minWidth: 0, scrollMarginTop: 16 }; +const imageFrameStyle: CSSProperties = { aspectRatio: '4 / 3', overflow: 'hidden', border: `1px solid ${siteTheme.border}`, background: '#fff' }; +const imageStyle: CSSProperties = { display: 'block', width: '100%', height: '100%', objectFit: 'contain' }; +const captionStyle: CSSProperties = { display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', gap: 12, paddingTop: 10 }; +const captionTitleStyle: CSSProperties = { color: siteTheme.text, fontSize: 14, fontWeight: 600 }; +const nativeTypeStyle: CSSProperties = { color: siteTheme.textMuted, fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace', fontSize: 11 }; +const harnessStyle: CSSProperties = { marginTop: 64, paddingTop: 28, borderTop: `1px solid ${siteTheme.border}`, maxWidth: 820 }; +const harnessTitleStyle: CSSProperties = { margin: 0, color: siteTheme.text, fontSize: 20, fontWeight: 600, letterSpacing: 0 }; +const stepsStyle: CSSProperties = { margin: '18px 0 0', paddingLeft: 22, color: siteTheme.text, fontSize: 14, lineHeight: 1.7 }; +const linkRowStyle: CSSProperties = { display: 'flex', flexWrap: 'wrap', gap: 10, marginTop: 22 }; + +const responsiveStyles = ` + .excel-gallery-action { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 210px; + min-height: 44px; + box-sizing: border-box; + padding: 11px 18px; + border: 1px solid transparent; + border-radius: ${siteTheme.radius}px; + color: ${siteTheme.text}; + background: ${siteTheme.surface}; + text-align: center; + text-decoration: none; + font-size: 14.5px; + font-weight: 600; + line-height: 1.2; + transform: translateY(0); + transition: background 120ms ease, border-color 120ms ease, transform 120ms ease; + } + .excel-gallery-action:hover, + .excel-gallery-action:focus-visible { + transform: translateY(-1px); + } + .excel-gallery-action:focus-visible { + outline: 2px solid ${siteTheme.accent}; + outline-offset: 2px; + } + .excel-gallery-action--primary { + color: #fff; + background: #217346; + } + .excel-gallery-action--primary:hover, + .excel-gallery-action--primary:focus-visible { + background: #185c37; + } + .excel-gallery-action--secondary { + border-color: rgba(0, 0, 0, 0.24); + } + .excel-gallery-action--secondary:hover, + .excel-gallery-action--secondary:focus-visible { + border-color: rgba(0, 0, 0, 0.42); + background: ${siteTheme.hover}; + } + .excel-gallery-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 34px 28px; + } + .excel-gallery-mobile-tabs { display: none; } + @media (max-width: 980px) { + .excel-gallery-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } + } + @media (max-width: 760px) { + .excel-gallery-layout > aside { display: none; } + .excel-gallery-main { padding: 24px 18px 64px !important; } + .excel-gallery-mobile-tabs { + display: flex; + gap: 6px; + overflow-x: auto; + margin-top: 16px; + padding-bottom: 4px; + } + .excel-gallery-mobile-tabs button { + flex: 0 0 auto; + padding: 7px 10px; + border: 1px solid ${siteTheme.border}; + background: ${siteTheme.surface}; + color: ${siteTheme.textMuted}; + font: inherit; + font-size: 12px; + } + .excel-gallery-mobile-tabs button.is-active { + border-color: #217346; + color: #217346; + font-weight: 600; + } + } + @media (max-width: 560px) { + .excel-gallery-grid { grid-template-columns: 1fr; gap: 28px; } + } +`; \ No newline at end of file diff --git a/site/src/routes/Landing.tsx b/site/src/routes/Landing.tsx index a0f6ec53..aaf02287 100644 --- a/site/src/routes/Landing.tsx +++ b/site/src/routes/Landing.tsx @@ -1,4 +1,4 @@ -import { useMemo, useState, type CSSProperties, type MouseEvent, type ReactNode } from 'react'; +import { useEffect, useMemo, useState, type CSSProperties, type MouseEvent, type ReactNode } from 'react'; import { useTranslation, Trans } from 'react-i18next'; import type { TFunction } from 'i18next'; import { LocaleLink } from '../i18n/LocaleLink'; @@ -8,9 +8,11 @@ import { TEST_GENERATORS, makeField, makeEncodingItem, buildMetadata, type TestC import { SiteNavBar, MicrosoftDisclosures, GitHubIcon } from '../components/SiteShell'; import { WallChart } from '../components/WallChart'; import { ScaleToFit } from '../components/ScaleToFit'; +import { GalleryOptionsBar } from '../components/GalleryOptionsBar'; import { SpecPipelineFigure } from '../components/SpecPipelineFigure'; import { testCaseToFlintSummary, testCaseToAssemblyInput } from '../shared/test-case-utils'; import { buildGalleryEditorHref, openEditorWithPayload } from '../shared/editor-payload'; +import { buildPanelModel } from '../shared/chart-options'; import { CHART_CATEGORIES } from '../shared/chart-categories'; import { MOVIE_RATINGS } from './movie-ratings-data'; import { @@ -49,11 +51,28 @@ export function Landing() { {t('landing.leadHighlight1')} {t('landing.leadMiddle')}{' '} - {t('landing.leadHighlight2', { chartTypes: CHART_FAMILY_COUNT })} + {t('landing.leadHighlight2', { + chartTypes: CHART_FAMILY_COUNT, + backends: BACKEND_ROSTER_LINKS.length, + })} .

+
+ + {t('landing.backendRosterLabel')} + + {BACKEND_ROSTER_LINKS.map((backend, index) => ( + + {index > 0 && + ))} +
+
>{' '} @@ -148,9 +167,9 @@ export function Landing() {

{t('landing.news.title')}

{([ + { key: 'release040', href: `${GITHUB_REPO}/releases/tag/0.4.0`, linkLabel: 'v0.4.0' }, { key: 'dynamicWidgets', href: `${GITHUB_REPO}/releases/tag/0.3.0`, linkLabel: 'v0.3.0' }, { key: 'release022', href: null, linkLabel: null }, - { key: 'release021', href: `${GITHUB_REPO}/releases/tag/0.2.1`, linkLabel: 'v0.2.1' }, ] as const).map((update) => (
- ); -} \ No newline at end of file diff --git a/site/src/shared/chart-categories.ts b/site/src/shared/chart-categories.ts index 9a4dabac..27f2407f 100644 --- a/site/src/shared/chart-categories.ts +++ b/site/src/shared/chart-categories.ts @@ -265,6 +265,77 @@ const config = assembleChartjs(input);`, createChart('chartjs', 'chartjs-gantt', 'Gantt Chart', 'Gantt Chart', ganttIcon), ], }, + { + id: 'plotly', + label: BACKEND_LABELS.plotly, + description: + 'Compiles a Flint spec into a Plotly.js figure (`{ data, layout }`) — ideal for ' + + 'analytics-native charts (candlesticks, box/violin, waterfalls, gauges) that keep ' + + "Plotly's own interactive hover, zoom, and legend behavior for free.", + fn: 'assemblePlotly', + snippet: `import { assemblePlotly } from 'flint-chart'; + +const input = { + data: { + values: [ + { weight: 2.6, mpg: 33, origin: 'Asia' }, + { weight: 3.4, mpg: 26, origin: 'Europe' }, + { weight: 4.1, mpg: 17, origin: 'USA' }, + ], + }, + semantic_types: { weight: 'Quantity', mpg: 'Quantity', origin: 'Region' }, + chart_spec: { + chartType: 'Scatter Plot', + encodings: { + x: { field: 'weight' }, + y: { field: 'mpg' }, + color: { field: 'origin' }, + }, + }, +}; + +const figure = assemblePlotly(input);`, + charts: [ + createChart('plotly', 'plotly-scatter', 'Scatter Plot', 'Scatter Plot', scatterIcon), + createChart('plotly', 'plotly-regression', 'Regression', 'Regression', regressionIcon), + createChart('plotly', 'plotly-connected-scatter', 'Connected Scatter Plot', 'Connected Scatter Plot', connectedScatterIcon), + createChart('plotly', 'plotly-ranged-dot-plot', 'Ranged Dot Plot', 'Ranged Dot Plot', rangedDotPlotIcon), + createChart('plotly', 'plotly-strip-plot', 'Strip Plot', 'Strip Plot', stripPlotIcon), + createChart('plotly', 'plotly-bar', 'Bar Chart', 'Bar Chart', barIcon), + createChart('plotly', 'plotly-grouped-bar', 'Grouped Bar Chart', 'Grouped Bar Chart', groupedBarIcon), + createChart('plotly', 'plotly-stacked-bar', 'Stacked Bar Chart', 'Stacked Bar Chart', stackedBarIcon), + createChart('plotly', 'plotly-lollipop', 'Lollipop Chart', 'Lollipop Chart', lollipopIcon), + createChart('plotly', 'plotly-pyramid', 'Pyramid Chart', 'Pyramid Chart', pyramidIcon), + createChart('plotly', 'plotly-waterfall', 'Waterfall Chart', 'Waterfall Chart', waterfallIcon), + createChart('plotly', 'plotly-histogram', 'Histogram', 'Histogram', histogramIcon), + createChart('plotly', 'plotly-boxplot', 'Boxplot', 'Boxplot', boxplotIcon), + createChart('plotly', 'plotly-violin', 'Violin Plot', 'Violin Plot', violinIcon), + createChart('plotly', 'plotly-density', 'Density Plot', 'Density Plot', densityIcon), + createChart('plotly', 'plotly-density-contour', 'Density Contour', 'Density Contour', densityIcon), + createChart('plotly', 'plotly-ecdf', 'ECDF Plot', 'ECDF Plot', ecdfIcon), + createChart('plotly', 'plotly-candlestick', 'Candlestick Chart', 'Candlestick Chart', candlestickIcon), + createChart('plotly', 'plotly-line', 'Line Chart', 'Line Chart', lineIcon), + createChart('plotly', 'plotly-area', 'Area Chart', 'Area Chart', areaIcon), + createChart('plotly', 'plotly-range-area', 'Range Area Chart', 'Range Area Chart', rangeAreaIcon), + createChart('plotly', 'plotly-streamgraph', 'Streamgraph', 'Streamgraph', streamgraphIcon), + createChart('plotly', 'plotly-slope', 'Slope Chart', 'Slope Chart', slopeIcon), + createChart('plotly', 'plotly-bump', 'Bump Chart', 'Bump Chart', bumpIcon), + createChart('plotly', 'plotly-pie', 'Pie Chart', 'Pie Chart', pieIcon), + createChart('plotly', 'plotly-donut', 'Donut Chart', 'Donut Chart', doughnutIcon), + createChart('plotly', 'plotly-radar', 'Radar Chart', 'Radar Chart', radarIcon), + createChart('plotly', 'plotly-rose', 'Rose Chart', 'Rose Chart', roseIcon), + createChart('plotly', 'plotly-heatmap', 'Heatmap', 'Heatmap', heatmapIcon), + createChart('plotly', 'plotly-gantt', 'Gantt Chart', 'Gantt Chart', ganttIcon), + createChart('plotly', 'plotly-bullet', 'Bullet Chart', 'Bullet Chart', bulletIcon), + createChart('plotly', 'plotly-kpi-card', 'KPI Card', 'Gallery: KPI Card', kpiCardIcon), + createChart('plotly', 'plotly-sparkline', 'Sparkline', 'Sparkline', sparklineIcon), + createChart('plotly', 'plotly-bar-table', 'Bar Table', 'Bar Table', barTableIcon), + createChart('plotly', 'plotly-map', 'Map', 'Map', worldMapIcon), + createChart('plotly', 'plotly-choropleth', 'Choropleth', 'Choropleth', usMapIcon), + createChart('plotly', 'plotly-funnel', 'Funnel Chart *', 'ECharts: Funnel', funnelIcon), + createChart('plotly', 'plotly-gauge', 'Gauge Chart *', 'ECharts: Gauge', gaugeIcon), + ], + }, ]; export const DEFAULT_CHART_ID = CHART_CATEGORIES[0]?.charts[0]?.id ?? 'scatter-plot'; diff --git a/site/src/shared/chart-options.ts b/site/src/shared/chart-options.ts index 972e1814..c92e7d31 100644 --- a/site/src/shared/chart-options.ts +++ b/site/src/shared/chart-options.ts @@ -161,10 +161,12 @@ export function buildPanelModel( // Non-Vega-Lite backends only honor a subset of the VL properties; drop the // controls the selected backend's template doesn't implement so the options - // bar never shows a knob that does nothing. + // bar never shows a knob that does nothing. `facetColumns` is exempt: it is a + // LAYOUT-level control (facet wrap) honored by every backend's assembler, not + // a per-template mark property, so it never appears in a template's own list. const supported = backendSupportedPropertyKeys(input.chart_spec.chartType, backend); if (supported) { - properties = properties.filter((o) => supported.has(o.key)); + properties = properties.filter((o) => o.key === 'facetColumns' || supported.has(o.key)); } const encodings = normalizeEncodings(input); diff --git a/site/src/shared/docs-catalog.ts b/site/src/shared/docs-catalog.ts index a62aba52..0c38e407 100644 --- a/site/src/shared/docs-catalog.ts +++ b/site/src/shared/docs-catalog.ts @@ -125,6 +125,18 @@ export const DOCUMENTATION_GROUPS: DocGroup[] = [ description: 'Every Chart.js chart type, its channels, and configurable parameters.', file: '../../../docs/reference-chartjs.md', }, + { + slug: 'reference-plotly', + title: 'Plotly charts', + description: 'Every Plotly chart type, its channels, and configurable parameters.', + file: '../../../docs/reference-plotly.md', + }, + { + slug: 'reference-excel', + title: 'Excel charts', + description: 'Every native Excel chart type, its channels, and Office.js mapping.', + file: '../../../docs/reference-excel.md', + }, ], }, { diff --git a/site/src/shared/supported-backends.ts b/site/src/shared/supported-backends.ts index f4c4ea1f..961e220f 100644 --- a/site/src/shared/supported-backends.ts +++ b/site/src/shared/supported-backends.ts @@ -2,13 +2,15 @@ import { assembleVegaLite, assembleECharts, assembleChartjs, + assemblePlotly, cjsGetTemplateDef, ecGetTemplateDef, vlGetTemplateDef, + plGetTemplateDef, type ChartAssemblyInput, } from 'flint-chart'; -export type PreviewBackend = 'vegalite' | 'echarts' | 'chartjs'; +export type PreviewBackend = 'vegalite' | 'echarts' | 'chartjs' | 'plotly'; /** A backend's template def (or `undefined` when it has no template for a type). */ type TemplateDef = ReturnType; @@ -51,6 +53,12 @@ export const BACKENDS: Record = { assemble: assembleChartjs, getTemplateDef: cjsGetTemplateDef, }, + plotly: { + id: 'plotly', + label: 'Plotly', + assemble: assemblePlotly, + getTemplateDef: plGetTemplateDef, + }, }; export const ALL_BACKENDS = Object.keys(BACKENDS) as PreviewBackend[]; diff --git a/site/src/shared/wall-title.ts b/site/src/shared/wall-title.ts index 32aa6742..bc3e706b 100644 --- a/site/src/shared/wall-title.ts +++ b/site/src/shared/wall-title.ts @@ -292,7 +292,16 @@ function cardQualifierKey(variants: TestCase[], idxs: number[]): CardKey { * are *always* annotated with that concrete count, collision or not. */ export function humanizeVariants(variants: TestCase[], locale: Locale = 'en'): string[] { - const out = variants.map(baseTitle); + // Real-world cases carry a descriptive, scenario-based title authored for the + // gallery (e.g. "Palmer Penguins — flipper length vs body mass"). Use it + // directly (dropping a trailing parenthetical qualifier for brevity) rather + // than the derived encoding caption. Their titles are unique, so the + // disambiguation passes below leave them untouched. + const realCaption = (t: TestCase): string => { + const raw = (localizeVariantTitle(t.title, locale) || t.title || '').trim(); + return raw.replace(/\s*\([^)]*\)\s*$/, '').trim() || raw; + }; + const out = variants.map((t) => ((t.tags ?? []).includes('real') ? realCaption(t) : baseTitle(t))); const hasParen = (s: string) => s.includes('('); const groupsOf = (): number[][] => { diff --git a/site/src/shared/wall-variants.ts b/site/src/shared/wall-variants.ts index f275f3e1..f1ab430a 100644 --- a/site/src/shared/wall-variants.ts +++ b/site/src/shared/wall-variants.ts @@ -15,31 +15,47 @@ function strideSample(pool: TestCase[], cap: number): TestCase[] { } /** - * Pick a small, diverse set of examples for one chart type. Drops stress/edge - * cases, then samples evenly across the remaining configs (different colors, - * orientations, sizes…) so each chart type shows a varied handful of tiles — - * mirroring the multiple-examples-per-type feel of the Vega-Lite gallery. + * Pick a small, diverse set of examples for one chart type, capped at `cap`. * - * A curated faceted (small-multiples) example, tagged `gallery-facet`, is always - * pinned as the last tile when present, so main chart types advertise faceting - * regardless of where the even sampling would otherwise land. + * Curation policy (gallery balance): **real, recognizable datasets come first** + * and are never dropped; a faceted small-multiples showcase (tagged + * `gallery-facet`) is pinned as the last tile when present; any remaining slots + * are filled with synthetic cases (even-sampled) whose job is to show off + * layout/stretch/sizing behaviour. Stress/edge cases are excluded up front. + * + * This keeps each chart type to a handful of tiles that lead with real data and + * only include synthetic examples for showcasing — rather than flooding the wall + * with synthetic coverage cases. */ export function selectVariants(tests: TestCase[], cap = 4): TestCase[] { const clean = tests.filter((t) => !(t.tags ?? []).some((tag) => SKIP_TAGS.has(tag))); const pool = clean.length > 0 ? clean : tests; - // Always-show examples (e.g. the color/group dodge demonstrations) are pinned - // and appended in addition to the sampled set, so they can't be dropped by the - // even sampling regardless of where they sit in the generator. - const isPinned = (t: TestCase) => (t.tags ?? []).includes('gallery-pin'); - const pinned = pool.filter(isPinned); - const rest = pool.filter((t) => !isPinned(t)); + const isReal = (t: TestCase) => (t.tags ?? []).includes('real'); + const isFacet = (t: TestCase) => (t.tags ?? []).includes('gallery-facet'); + const isShowcase = (t: TestCase) => (t.tags ?? []).includes('gallery-showcase'); + + const real = pool.filter(isReal); + const facet = pool.find(isFacet); + const showcase = pool.filter((t) => isShowcase(t) && !isReal(t) && !isFacet(t)); + const plain = pool.filter((t) => !isReal(t) && !isFacet(t) && !isShowcase(t)); - const facetIdx = rest.findIndex((t) => (t.tags ?? []).includes('gallery-facet')); - const sampled = facetIdx === -1 - ? strideSample(rest, cap) - // Pin the faceted example last; fill remaining slots from the rest. - : [...strideSample(rest.filter((_, i) => i !== facetIdx), Math.max(cap - 1, 0)), rest[facetIdx]]; + const out: TestCase[] = []; + // 1. Real datasets first (prioritized, never dropped). + for (const t of real) if (out.length < cap) out.push(t); + // 2. Reserve the last slot for the faceted showcase when present. + const reserve = facet ? 1 : 0; + let fill = Math.max(cap - out.length - reserve, 0); + // 3. Fill remaining slots with curated stretch/sizing showcases first, then + // even-sampled plain synthetic cases for variety. + if (fill > 0) { + const picks = showcase.slice(0, fill); + out.push(...picks); + fill -= picks.length; + if (fill > 0) out.push(...strideSample(plain, fill)); + } + // 4. Pin the faceted small-multiples example last. + if (facet && out.length < cap) out.push(facet); - return [...sampled, ...pinned]; + return out; } diff --git a/site/src/types/plotly.d.ts b/site/src/types/plotly.d.ts new file mode 100644 index 00000000..5116476f --- /dev/null +++ b/site/src/types/plotly.d.ts @@ -0,0 +1,7 @@ +declare module 'plotly.js-dist-min' { + const Plotly: { + newPlot: (el: HTMLElement, data: unknown[], layout?: unknown, config?: unknown) => Promise; + purge: (el: HTMLElement) => void; + }; + export default Plotly; +} diff --git a/test-harness/excel/.gitignore b/test-harness/excel/.gitignore new file mode 100644 index 00000000..94ab8fe2 --- /dev/null +++ b/test-harness/excel/.gitignore @@ -0,0 +1,6 @@ +evaluations/out/ +node_modules/ +*.log + +# Excel lock/temp files +~$* diff --git a/test-harness/excel/README.md b/test-harness/excel/README.md new file mode 100644 index 00000000..53a056a0 --- /dev/null +++ b/test-harness/excel/README.md @@ -0,0 +1,99 @@ +# Flint Excel test harness + +This test harness provides an Office.js transport plugin for rendering and evaluating artifacts from the Excel backend in `packages/flint-js/src/excel`. It does not interpret chart artifacts. + +The ownership boundary is: + +- `flint-chart/excel`: compiles semantic Flint input, validates the versioned Excel artifact, executes it through Office.js, and generates standalone Office.js source. +- `office-runner/`: builds and serves the backend bundle, transports jobs, and hosts the Office add-in worker. +- `evaluations/`: generates semantic inputs, renders comparisons, and records visual evaluation results. + +```text +test-harness/excel/ +├── office-runner/ HTTPS queue server and Office add-in +├── evaluations/ evaluation scripts, inputs, ledger, and ignored output +├── package.json harness commands +└── README.md +``` + +## Artifact flow + +```js +import { + assembleExcel, + renderExcelChart, +} from 'flint-chart/excel'; + +const artifact = assembleExcel(input); +const result = await renderExcelChart(Excel, artifact, { scale: 3 }); +``` + +Serialized artifacts have `schema: "flint.excel.chart/v1"`, `kind: "chart"`, a native Office.js chart type, a matrix data range, and declarative formatting. Image scale, worksheet cleanup, and native inspection are host options and are not artifact fields. Legacy neutral aliases such as `"column"` and unversioned hand-authored specs are rejected. + +## Start the worker + +One-time setup: + +```bash +npx office-addin-dev-certs install +cp office-runner/officejs/manifest.xml ~/Library/Containers/com.microsoft.Excel/Data/Documents/wef/ +``` + +Start the HTTPS transport from this directory: + +```bash +npm run server:supervised +``` + +Run the supervised server in a dedicated terminal. It builds `packages/flint-js`, serves its Excel backend to the taskpane, listens at `https://localhost:3000`, and restarts after an unexpected process exit. In Excel, open Home > Add-ins > My Add-ins > Flint Render once. Use `npm run server` only when debugging the server process without automatic restart. + +Active evaluations compile semantic Flint inputs with `assembleExcel` and submit this envelope: + +```json +{ + "artifact": { + "schema": "flint.excel.chart/v1", + "kind": "chart", + "chartType": "ColumnClustered", + "seriesBy": "Columns", + "data": [["Quarter", "Sales"], ["Q1", 120], ["Q2", 205]] + }, + "renderOptions": { + "scale": 3, + "cleanWorksheet": true, + "inspectNativeChart": false + } +} +``` + +Run backend-owned headless validation with: + +```bash +npm run test:mock +``` + +Generate or run visual evaluations with: + +```bash +npm run evaluate:inputs +npm run evaluate:gallery -- all +npm run evaluate:sheets +npm run evaluate:candlestick +npm run evaluate:layout +``` + +Generated images and summaries are written under `evaluations/out/` and are ignored by Git. + +## Native Excel examples + +The [curated example gallery](evaluations/examples/README.md) contains tracked snapshots of native Excel charts captured from the real Office.js worker. Bulk evaluation output stays ignored; after reviewing regenerated output, refresh the selected snapshots with: + +```bash +npm run evaluate:examples +``` + +## Worker safety + +Run only one worker server on port 3000. Render clients cancel abandoned jobs, the server expires queued jobs after two minutes, and the taskpane renders at most one job per polling interval. + +Native `Pareto` remains quarantined. Excel for Mac exits while creating it before Office.js can return a catchable error. The server, artifact validator, and taskpane guard reject Pareto before `Excel.run`. diff --git a/test-harness/excel/evaluations/candlestick-audit.mjs b/test-harness/excel/evaluations/candlestick-audit.mjs new file mode 100644 index 00000000..54e39684 --- /dev/null +++ b/test-harness/excel/evaluations/candlestick-audit.mjs @@ -0,0 +1,139 @@ +#!/usr/bin/env node +// @ts-nocheck + +import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { createCanvas, loadImage } from '@napi-rs/canvas'; +import { renderChart } from 'flint-chart-mcp/render'; +import { assembleExcel } from 'flint-chart/excel'; +import { TEST_GENERATORS } from 'flint-chart/test-data'; +import { renderExcelArtifact } from './render-client.mjs'; + +const here = dirname(fileURLToPath(import.meta.url)); +const root = join(here, '..', '..', '..'); +const outDir = join(here, 'out', 'candlestick-audit'); +const cases = [0, 1]; + +function loadEnvFile() { + const envPath = join(root, '.env'); + if (!existsSync(envPath)) return false; + for (const line of readFileSync(envPath, 'utf8').split(/\r?\n/)) { + const match = line.match(/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)\s*$/); + if (!match || process.env[match[1]] !== undefined) continue; + process.env[match[1]] = match[2].replace(/^(['"])(.*)\1$/, '$2'); + } + return true; +} + +function toAssemblyInput(test) { + const idToName = new Map(test.fields.map((field) => [field.id, field.name])); + const encodings = {}; + for (const [channel, encoding] of Object.entries(test.encodingMap || {})) { + if (encoding?.fieldID) encodings[channel] = idToName.get(encoding.fieldID) ?? encoding.fieldID; + } + return { + data: { values: test.data }, + semantic_types: Object.fromEntries(Object.entries(test.metadata).map(([field, metadata]) => [field, metadata.semanticType])), + chart_spec: { + chartType: test.chartType, + encodings, + baseSize: { width: 640, height: 380 }, + }, + }; +} + +async function sideBySide(referenceBuffer, excelBuffer, outputPath) { + const [reference, excel] = await Promise.all([loadImage(referenceBuffer), loadImage(excelBuffer)]); + const labelHeight = 42; + const gap = 20; + const canvas = createCanvas(reference.width + excel.width + gap, Math.max(reference.height, excel.height) + labelHeight); + const context = canvas.getContext('2d'); + context.fillStyle = '#ffffff'; + context.fillRect(0, 0, canvas.width, canvas.height); + context.fillStyle = '#222222'; + context.font = 'bold 20px sans-serif'; + context.fillText('Canonical Vega-Lite', 12, 28); + context.fillText('Native Excel StockOHLC', reference.width + gap + 12, 28); + context.drawImage(reference, 0, labelHeight); + context.drawImage(excel, reference.width + gap, labelHeight); + writeFileSync(outputPath, canvas.toBuffer('image/png')); +} + +async function reviewWithVlm(imagePaths) { + const envLoaded = loadEnvFile(); + const azureEndpoint = process.env.AZURE_OPENAI_ENDPOINT; + const deployment = process.env.AZURE_OPENAI_DEPLOYMENT; + const apiKey = process.env.AZURE_OPENAI_API_KEY; + const directEndpoint = process.env.VLM_ENDPOINT; + const model = process.env.VLM_MODEL; + const directKey = process.env.VLM_API_KEY; + if (!envLoaded || (!directEndpoint && !(azureEndpoint && deployment)) || (!apiKey && !directKey)) { + return { status: 'SKIP', reason: 'No configured VLM endpoint and credential were found in workspace .env.' }; + } + + const endpoint = directEndpoint ?? `${azureEndpoint.replace(/\/$/, '')}/openai/deployments/${deployment}/chat/completions?api-version=${process.env.AZURE_OPENAI_API_VERSION ?? '2024-10-21'}`; + const content = [{ + type: 'text', + text: 'Review these side-by-side candlestick charts. Check for blank or clipped marks, incorrect OHLC encoding, broken date or price axes, unreadable labels, misleading geometry, overlap, and whether native Excel preserves the canonical financial reading. Return concise JSON with status PASS or FAIL, findings, and per-image notes.', + }]; + for (const imagePath of imagePaths) { + content.push({ type: 'image_url', image_url: { url: `data:image/png;base64,${readFileSync(imagePath).toString('base64')}` } }); + } + const response = await fetch(endpoint, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + ...(apiKey ? { 'api-key': apiKey } : { Authorization: `Bearer ${directKey}` }), + }, + body: JSON.stringify({ model, messages: [{ role: 'user', content }], max_tokens: 1200 }), + }); + if (!response.ok) return { status: 'FAIL', reason: `VLM request failed with HTTP ${response.status}.` }; + const payload = await response.json(); + return { status: 'COMPLETE', review: payload.choices?.[0]?.message?.content ?? '' }; +} + +mkdirSync(outDir, { recursive: true }); +const fixtures = TEST_GENERATORS['Candlestick Chart'](); +const results = []; +const comparisons = []; + +for (const fixtureIndex of cases) { + const fixture = fixtures[fixtureIndex]; + const name = fixtureIndex === 0 ? 'basic-30-day' : 'advanced-90-day-dense'; + const referencePath = join(outDir, `${name}.vl.png`); + const excelPath = join(outDir, `${name}.excel.png`); + const comparisonPath = join(outDir, `${name}.comparison.png`); + const result = { name, title: fixture.title, status: 'FAIL' }; + try { + const input = toAssemblyInput(fixture); + const reference = await renderChart(input, 'vegalite', { format: 'png', scale: 3 }); + writeFileSync(referencePath, reference.buffer); + const spec = assembleExcel(input); + spec.width = Math.max(640, Math.min(1600, Math.round(reference.width || 640))); + spec.height = Math.max(380, Math.min(900, Math.round(reference.height || 380))); + const excel = await renderExcelArtifact(spec); + writeFileSync(excelPath, excel); + await sideBySide(reference.buffer, excel, comparisonPath); + Object.assign(result, { + status: 'RENDERED', + chartType: spec.chartType, + range: `A1:E${spec.data.length}`, + reference: referencePath, + excel: excelPath, + comparison: comparisonPath, + }); + comparisons.push(comparisonPath); + } catch (error) { + result.error = String(error.message || error); + } + results.push(result); +} + +const vlm = comparisons.length === cases.length + ? await reviewWithVlm(comparisons) + : { status: 'SKIP', reason: 'VLM review skipped because not all real-Excel cases rendered.' }; +const summary = { generatedAt: new Date().toISOString(), cases: results, vlm }; +writeFileSync(join(outDir, 'summary.json'), `${JSON.stringify(summary, null, 2)}\n`); +console.log(JSON.stringify(summary, null, 2)); +process.exit(results.some((result) => result.status === 'FAIL') || vlm.status === 'FAIL' ? 1 : 0); \ No newline at end of file diff --git a/test-harness/excel/evaluations/examples/README.md b/test-harness/excel/evaluations/examples/README.md new file mode 100644 index 00000000..e053b908 --- /dev/null +++ b/test-harness/excel/evaluations/examples/README.md @@ -0,0 +1,69 @@ + +# Native Excel chart examples + +Flint generates native Excel charts from semantic chart specs. These examples were rendered in Excel for Mac through Office.js and remain editable in Excel. + + + + + + + + + + + + + + + + + +
Grouped bar

Native Excel grouped column chart generated by Flint
Multi-series line

Native Excel multi-series line chart generated by Flint
Stacked area

Native Excel stacked area chart generated by Flint
Treemap

Native Excel treemap generated by Flint
Sunburst

Native Excel sunburst chart generated by Flint
Waterfall

Native Excel waterfall chart generated by Flint
Population pyramid

Native Excel population pyramid generated by Flint
Radar

Native Excel radar chart generated by Flint
Candlestick

Native Excel candlestick chart generated by Flint
+ +## About these charts + +- Each chart is a native Excel chart object, not a canvas overlay or pasted image. +- Data, formatting, titles, axes, and series can be edited in Excel. +- Flint compiles each semantic input into a versioned artifact for Office.js rendering or code generation. + +
+How these examples were produced + +These images are unedited captures from the real Excel for Mac Office.js worker using `Chart.getImage()`. Each chart was assembled from a Flint semantic input into a versioned `flint.excel.chart/v1` artifact, then rendered as a native Excel chart. + +| Example | Native Excel chart | Flint input | +| --- | --- | --- | +| Stacked area | `AreaStacked` | [View input](../inputs/area-chart/01-card24.flint.json) | +| Grouped bar | `ColumnClustered` | [View input](../inputs/grouped-bar-chart/00-card4.flint.json) | +| Multi-series line | `XYScatterLines` | [View input](../inputs/line-chart/14-card50.flint.json) | +| Treemap | `Treemap` | [View input](../inputs/treemap/01-card0.flint.json) | +| Sunburst | `Sunburst` | [View input](../inputs/sunburst-chart/02-card0.flint.json) | +| Waterfall | `Waterfall` | [View input](../inputs/waterfall-chart/02-card7.flint.json) | +| Population pyramid | `BarStacked` | [View input](../inputs/pyramid-chart/00-card18.flint.json) | +| Radar | `RadarMarkers` | [View input](../inputs/radar-chart/05-card8.flint.json) | +| Candlestick | `StockOHLC` | [View input](../inputs/candlestick-chart/01-card90.flint.json) | + +
+ +
+Refresh the snapshots + +With the Office runner and Excel task pane open, regenerate the selected cases: + +```bash +npm run evaluate:gallery -- waterfall-chart 3 +npm run evaluate:gallery -- pyramid-chart 1 +npm run evaluate:gallery -- grouped-bar-chart 1 +npm run evaluate:gallery -- line-chart 15 +npm run evaluate:gallery -- area-chart 2 +npm run evaluate:gallery -- radar-chart 6 +npm run evaluate:gallery -- treemap 2 +npm run evaluate:gallery -- sunburst-chart 3 +npm run evaluate:candlestick +npm run evaluate:examples +``` + +Review the images before committing refreshed snapshots. Native Excel rendering can vary slightly across Excel versions and platforms. + +
diff --git a/test-harness/excel/evaluations/examples/candlestick.png b/test-harness/excel/evaluations/examples/candlestick.png new file mode 100644 index 00000000..f6122948 Binary files /dev/null and b/test-harness/excel/evaluations/examples/candlestick.png differ diff --git a/test-harness/excel/evaluations/examples/grouped-bar.png b/test-harness/excel/evaluations/examples/grouped-bar.png new file mode 100644 index 00000000..3f0be9e2 Binary files /dev/null and b/test-harness/excel/evaluations/examples/grouped-bar.png differ diff --git a/test-harness/excel/evaluations/examples/multi-series-line.png b/test-harness/excel/evaluations/examples/multi-series-line.png new file mode 100644 index 00000000..a615c45d Binary files /dev/null and b/test-harness/excel/evaluations/examples/multi-series-line.png differ diff --git a/test-harness/excel/evaluations/examples/pyramid.png b/test-harness/excel/evaluations/examples/pyramid.png new file mode 100644 index 00000000..65094aa5 Binary files /dev/null and b/test-harness/excel/evaluations/examples/pyramid.png differ diff --git a/test-harness/excel/evaluations/examples/radar.png b/test-harness/excel/evaluations/examples/radar.png new file mode 100644 index 00000000..6d848425 Binary files /dev/null and b/test-harness/excel/evaluations/examples/radar.png differ diff --git a/test-harness/excel/evaluations/examples/stacked-area.png b/test-harness/excel/evaluations/examples/stacked-area.png new file mode 100644 index 00000000..4e713b46 Binary files /dev/null and b/test-harness/excel/evaluations/examples/stacked-area.png differ diff --git a/test-harness/excel/evaluations/examples/sunburst.png b/test-harness/excel/evaluations/examples/sunburst.png new file mode 100644 index 00000000..ca3511f9 Binary files /dev/null and b/test-harness/excel/evaluations/examples/sunburst.png differ diff --git a/test-harness/excel/evaluations/examples/treemap.png b/test-harness/excel/evaluations/examples/treemap.png new file mode 100644 index 00000000..99f4de7d Binary files /dev/null and b/test-harness/excel/evaluations/examples/treemap.png differ diff --git a/test-harness/excel/evaluations/examples/waterfall.png b/test-harness/excel/evaluations/examples/waterfall.png new file mode 100644 index 00000000..84deec80 Binary files /dev/null and b/test-harness/excel/evaluations/examples/waterfall.png differ diff --git a/test-harness/excel/evaluations/gallery-run.mjs b/test-harness/excel/evaluations/gallery-run.mjs new file mode 100644 index 00000000..3e12a855 --- /dev/null +++ b/test-harness/excel/evaluations/gallery-run.mjs @@ -0,0 +1,112 @@ +#!/usr/bin/env node +// @ts-nocheck +/** + * gallery-run.mjs — render each gallery Flint input as BOTH: + * • the Vega-Lite reference PNG — via Flint's own `renderChart(input, + * 'vegalite', …)`, and + * • the Excel PNG — via the LIBRARY backend `assembleExcel(input)` rendered + * through the Office.js worker. + * + * Flint's VL renderer also returns the layout width/height, which we use to + * size the Excel chart — so high-cardinality charts get the same + * cardinality-driven room Flint's layout computed. + * + * Requires the render server + Excel task pane running (`npm run server`). + * + * Usage: + * node gallery-run.mjs bar-chart # one type + * node gallery-run.mjs all # every type + * node gallery-run.mjs bar-chart 4 # first 4 cases + */ + +import { existsSync, readdirSync, readFileSync, writeFileSync, mkdirSync, rmSync } from 'node:fs'; +import { join, dirname, basename } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { renderChart } from 'flint-chart-mcp/render'; +import { assembleExcel } from 'flint-chart/excel'; +import { renderExcelArtifact } from './render-client.mjs'; + +const here = dirname(fileURLToPath(import.meta.url)); +const GALLERY = join(here, 'inputs'); +const OUT = join(here, 'out', 'gallery'); +const SCALE = 3; +const clamp = (v, lo, hi) => Math.max(lo, Math.min(hi, Math.round(v))); +const referenceBackendFor = (typeSlug) => ['funnel-chart', 'treemap', 'sunburst-chart'].includes(typeSlug) ? 'echarts' : 'vegalite'; + +async function runType(typeSlug, limit) { + const dir = join(GALLERY, typeSlug); + let files; + try { files = readdirSync(dir).filter((f) => f.endsWith('.flint.json')).sort(); } + catch { console.error(`no such gallery type: ${typeSlug}`); return []; } + if (limit) files = files.slice(0, limit); + const outDir = join(OUT, typeSlug); + mkdirSync(outDir, { recursive: true }); + + const results = []; + for (const file of files) { + const name = basename(file).replace(/\.flint\.json$/, ''); + const vlPath = join(outDir, `${name}.vl.png`); + const excelPath = join(outDir, `${name}.excel.png`); + rmSync(vlPath, { force: true }); + rmSync(excelPath, { force: true }); + const input = JSON.parse(readFileSync(join(dir, file), 'utf8')); + const rec = { type: typeSlug, name, ok: false, skipped: false }; + try { + // Flint reference rendering also provides the layout size used by Excel. + const referenceBackend = referenceBackendFor(typeSlug); + const vl = await renderChart(input, referenceBackend, { format: 'png', scale: SCALE }); + writeFileSync(vlPath, vl.buffer); + rec.vlSize = `${vl.width}x${vl.height}`; + rec.referenceBackend = referenceBackend; + + // Excel-equivalent via the LIBRARY backend, sized from Flint's layout + let spec; + try { + spec = assembleExcel(input); + } catch (error) { + const message = String(error.message || error); + if (!message.startsWith('Excel backend ')) throw error; + rec.skipped = true; + rec.skipReason = message; + console.log(` - ${typeSlug}/${name}: SKIP ${message}`); + results.push(rec); + continue; + } + if (vl.width) spec.width = clamp(vl.width, 320, 1600); + if (vl.height) spec.height = clamp(vl.height, 220, 900); + rec.excelType = spec.chartType; + + const excelPng = await renderExcelArtifact(spec, { scale: SCALE }); + writeFileSync(excelPath, excelPng); + rec.ok = true; + console.log(` ✓ ${typeSlug}/${name} (${rec.excelType}, VL ${rec.vlSize})`); + } catch (e) { + rec.error = String(e.message || e); + console.error(` ✗ ${typeSlug}/${name}: ${rec.error}`); + } + results.push(rec); + } + return results; +} + +const arg = process.argv[2] || 'all'; +const limit = process.argv[3] ? Number(process.argv[3]) : undefined; +const types = arg === 'all' + ? readdirSync(GALLERY).filter((d) => { try { return readdirSync(join(GALLERY, d)).length; } catch { return false; } }) + : [arg]; + +const all = []; +for (const t of types) all.push(...(await runType(t, limit))); +mkdirSync(OUT, { recursive: true }); +const summaryPath = join(OUT, 'summary.json'); +let summary = all; +if (arg !== 'all' && existsSync(summaryPath)) { + const previous = JSON.parse(readFileSync(summaryPath, 'utf8')); + const replacedCases = new Set(all.map((entry) => `${entry.type}/${entry.name}`)); + summary = [...previous.filter((entry) => !replacedCases.has(`${entry.type}/${entry.name}`)), ...all] + .sort((a, b) => a.type.localeCompare(b.type) || a.name.localeCompare(b.name)); +} +writeFileSync(summaryPath, JSON.stringify(summary, null, 2) + '\n'); +const rendered = all.filter((r) => r.ok).length; +const skipped = all.filter((r) => r.skipped).length; +console.log(`\n${rendered}/${all.length} pairs rendered, ${skipped} skipped → out/gallery/ (summary: ${summary.length} cases)`); diff --git a/test-harness/excel/evaluations/gen-gallery-inputs.mjs b/test-harness/excel/evaluations/gen-gallery-inputs.mjs new file mode 100644 index 00000000..6a5497d2 --- /dev/null +++ b/test-harness/excel/evaluations/gen-gallery-inputs.mjs @@ -0,0 +1,96 @@ +#!/usr/bin/env node +// @ts-nocheck (consumes loosely-typed gallery TestCase objects) +/** + * gen-gallery-inputs.mjs — export real Flint gallery examples as Flint inputs. + * + * Pulls curated TestCases from `flint-chart/test-data` (the fixtures the website + * gallery renders) and converts each to a flat ChartAssemblyInput, grouped into + * per-chart-type subfolders under inputs/. Primary-axis cardinality is + * encoded in the filename so we can target low/high cardinality. + * + * Usage: + * node gen-gallery-inputs.mjs + * node gen-gallery-inputs.mjs radar-chart + */ + +import { writeFileSync, mkdirSync, rmSync } from 'node:fs'; +import { join, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { TEST_GENERATORS } from 'flint-chart/test-data'; + +const here = dirname(fileURLToPath(import.meta.url)); +const OUT = join(here, 'inputs'); + +const MAJOR_TYPES = [ + 'Bar Chart', 'Grouped Bar Chart', 'Stacked Bar Chart', 'Line Chart', + 'Pyramid Chart', 'Area Chart', 'Scatter Plot', 'Pie Chart', 'Donut Chart', 'Histogram', 'Heatmap', + 'Boxplot', 'Radar Chart', 'Waterfall Chart', 'Funnel Chart', 'Treemap', 'Sunburst Chart', + 'Connected Scatter Plot', 'Candlestick Chart', +]; + +const GENERATOR_KEYS = { + 'Funnel Chart': 'ECharts: Funnel', + 'Treemap': 'ECharts: Treemap', + 'Sunburst Chart': 'ECharts: Sunburst', +}; + +const DEFAULT_CANVAS = { width: 560, height: 360 }; +const OVERRIDE_KEYS = ['type', 'aggregate', 'sortOrder', 'sortBy', 'scheme']; +const collapse = (e) => (e.field == null ? e : OVERRIDE_KEYS.some((k) => e[k] != null && e[k] !== '') ? e : e.field); + +function toAssemblyInput(t, canvas = DEFAULT_CANVAS) { + const idToName = new Map(t.fields.map((f) => [f.id, f.name])); + const encodings = {}; + for (const [channel, e] of Object.entries(t.encodingMap || {})) { + if (!e?.fieldID) continue; + const field = idToName.get(e.fieldID) ?? e.fieldID; + encodings[channel] = collapse({ + field, type: e.dtype, aggregate: e.aggregate, sortOrder: e.sortOrder, sortBy: e.sortBy, scheme: e.scheme, + }); + } + const semantic_types = {}; + for (const [k, m] of Object.entries(t.metadata || {})) semantic_types[k] = m.semanticType; + return { + semantic_types, + chart_spec: { chartType: t.chartType, encodings, baseSize: canvas, ...(t.chartProperties ? { chartProperties: t.chartProperties } : {}) }, + ...(t.assembleOptions ? { options: t.assembleOptions } : {}), + ...(t.semanticAnnotations ? { semantic_annotations: t.semanticAnnotations } : {}), + data: { values: t.data }, + }; +} + +const slug = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, ''); +function primaryCardinality(t) { + const enc = t.encodingMap?.x ?? t.encodingMap?.y; + const f = enc?.fieldID ? t.fields.find((x) => x.id === enc.fieldID) : null; + if (!f) return 0; + const seen = new Set(); + for (const row of t.data || []) seen.add(row[f.name]); + return seen.size; +} + +const familyFilter = process.argv[2]; +const selectedTypes = familyFilter + ? MAJOR_TYPES.filter((type) => slug(type) === familyFilter) + : MAJOR_TYPES; +if (familyFilter && selectedTypes.length === 0) { + throw new Error(`Unknown gallery family "${familyFilter}".`); +} +if (familyFilter) rmSync(join(OUT, familyFilter), { recursive: true, force: true }); +else rmSync(OUT, { recursive: true, force: true }); +let total = 0; +for (const type of selectedTypes) { + const gen = TEST_GENERATORS[GENERATOR_KEYS[type] ?? type]; + if (!gen) { console.warn(`(no generator for ${type})`); continue; } + const dir = join(OUT, slug(type)); + mkdirSync(dir, { recursive: true }); + let n = 0; + gen().forEach((t, i) => { + if (t.encodingMap?.column?.fieldID || t.encodingMap?.row?.fieldID) return; // skip facets + const card = primaryCardinality(t); + writeFileSync(join(dir, `${String(i).padStart(2, '0')}-card${card}.flint.json`), JSON.stringify(toAssemblyInput(t), null, 2) + '\n'); + total += 1; n += 1; + }); + console.log(`${type}: ${n} inputs`); +} +console.log(`\nwrote ${total} gallery inputs under evaluations/inputs/`); diff --git a/test-harness/excel/evaluations/inputs/area-chart/00-card30.flint.json b/test-harness/excel/evaluations/inputs/area-chart/00-card30.flint.json new file mode 100644 index 00000000..3826ed0b --- /dev/null +++ b/test-harness/excel/evaluations/inputs/area-chart/00-card30.flint.json @@ -0,0 +1,141 @@ +{ + "semantic_types": { + "Date": "Date", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Area Chart", + "encodings": { + "x": "Date", + "y": "Value" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Date": "2020-01-01", + "Value": 51 + }, + { + "Date": "2020-02-06", + "Value": 51 + }, + { + "Date": "2020-03-14", + "Value": 63 + }, + { + "Date": "2020-04-19", + "Value": 67 + }, + { + "Date": "2020-05-26", + "Value": 81 + }, + { + "Date": "2020-07-01", + "Value": 100 + }, + { + "Date": "2020-08-07", + "Value": 105 + }, + { + "Date": "2020-09-12", + "Value": 113 + }, + { + "Date": "2020-10-19", + "Value": 135 + }, + { + "Date": "2020-11-24", + "Value": 156 + }, + { + "Date": "2020-12-31", + "Value": 163 + }, + { + "Date": "2021-02-05", + "Value": 169 + }, + { + "Date": "2021-03-14", + "Value": 180 + }, + { + "Date": "2021-04-19", + "Value": 177 + }, + { + "Date": "2021-05-26", + "Value": 185 + }, + { + "Date": "2021-07-01", + "Value": 179 + }, + { + "Date": "2021-08-07", + "Value": 190 + }, + { + "Date": "2021-09-12", + "Value": 209 + }, + { + "Date": "2021-10-19", + "Value": 235 + }, + { + "Date": "2021-11-24", + "Value": 267 + }, + { + "Date": "2021-12-31", + "Value": 303 + }, + { + "Date": "2022-02-05", + "Value": 333 + }, + { + "Date": "2022-03-14", + "Value": 341 + }, + { + "Date": "2022-04-19", + "Value": 349 + }, + { + "Date": "2022-05-26", + "Value": 362 + }, + { + "Date": "2022-07-01", + "Value": 361 + }, + { + "Date": "2022-08-07", + "Value": 365 + }, + { + "Date": "2022-09-12", + "Value": 359 + }, + { + "Date": "2022-10-19", + "Value": 356 + }, + { + "Date": "2022-11-24", + "Value": 360 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/area-chart/01-card24.flint.json b/test-harness/excel/evaluations/inputs/area-chart/01-card24.flint.json new file mode 100644 index 00000000..59ac6678 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/area-chart/01-card24.flint.json @@ -0,0 +1,503 @@ +{ + "semantic_types": { + "Date": "Date", + "Value": "Quantity", + "Series": "Category" + }, + "chart_spec": { + "chartType": "Area Chart", + "encodings": { + "x": "Date", + "y": "Value", + "color": "Series" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Date": "2020-01-01", + "Value": 216, + "Series": "Electronics" + }, + { + "Date": "2020-02-15", + "Value": 225, + "Series": "Electronics" + }, + { + "Date": "2020-04-01", + "Value": 240, + "Series": "Electronics" + }, + { + "Date": "2020-05-16", + "Value": 246, + "Series": "Electronics" + }, + { + "Date": "2020-07-01", + "Value": 264, + "Series": "Electronics" + }, + { + "Date": "2020-08-16", + "Value": 276, + "Series": "Electronics" + }, + { + "Date": "2020-09-30", + "Value": 297, + "Series": "Electronics" + }, + { + "Date": "2020-11-15", + "Value": 299, + "Series": "Electronics" + }, + { + "Date": "2020-12-31", + "Value": 307, + "Series": "Electronics" + }, + { + "Date": "2021-02-14", + "Value": 316, + "Series": "Electronics" + }, + { + "Date": "2021-04-01", + "Value": 338, + "Series": "Electronics" + }, + { + "Date": "2021-05-16", + "Value": 341, + "Series": "Electronics" + }, + { + "Date": "2021-07-01", + "Value": 356, + "Series": "Electronics" + }, + { + "Date": "2021-08-16", + "Value": 353, + "Series": "Electronics" + }, + { + "Date": "2021-09-30", + "Value": 342, + "Series": "Electronics" + }, + { + "Date": "2021-11-15", + "Value": 325, + "Series": "Electronics" + }, + { + "Date": "2021-12-31", + "Value": 318, + "Series": "Electronics" + }, + { + "Date": "2022-02-14", + "Value": 325, + "Series": "Electronics" + }, + { + "Date": "2022-04-01", + "Value": 327, + "Series": "Electronics" + }, + { + "Date": "2022-05-16", + "Value": 319, + "Series": "Electronics" + }, + { + "Date": "2022-07-01", + "Value": 332, + "Series": "Electronics" + }, + { + "Date": "2022-08-16", + "Value": 343, + "Series": "Electronics" + }, + { + "Date": "2022-09-30", + "Value": 360, + "Series": "Electronics" + }, + { + "Date": "2022-11-15", + "Value": 386, + "Series": "Electronics" + }, + { + "Date": "2020-01-01", + "Value": 126, + "Series": "Clothing" + }, + { + "Date": "2020-02-15", + "Value": 121, + "Series": "Clothing" + }, + { + "Date": "2020-04-01", + "Value": 125, + "Series": "Clothing" + }, + { + "Date": "2020-05-16", + "Value": 126, + "Series": "Clothing" + }, + { + "Date": "2020-07-01", + "Value": 134, + "Series": "Clothing" + }, + { + "Date": "2020-08-16", + "Value": 141, + "Series": "Clothing" + }, + { + "Date": "2020-09-30", + "Value": 141, + "Series": "Clothing" + }, + { + "Date": "2020-11-15", + "Value": 144, + "Series": "Clothing" + }, + { + "Date": "2020-12-31", + "Value": 147, + "Series": "Clothing" + }, + { + "Date": "2021-02-14", + "Value": 144, + "Series": "Clothing" + }, + { + "Date": "2021-04-01", + "Value": 146, + "Series": "Clothing" + }, + { + "Date": "2021-05-16", + "Value": 150, + "Series": "Clothing" + }, + { + "Date": "2021-07-01", + "Value": 148, + "Series": "Clothing" + }, + { + "Date": "2021-08-16", + "Value": 150, + "Series": "Clothing" + }, + { + "Date": "2021-09-30", + "Value": 145, + "Series": "Clothing" + }, + { + "Date": "2021-11-15", + "Value": 146, + "Series": "Clothing" + }, + { + "Date": "2021-12-31", + "Value": 145, + "Series": "Clothing" + }, + { + "Date": "2022-02-14", + "Value": 147, + "Series": "Clothing" + }, + { + "Date": "2022-04-01", + "Value": 158, + "Series": "Clothing" + }, + { + "Date": "2022-05-16", + "Value": 173, + "Series": "Clothing" + }, + { + "Date": "2022-07-01", + "Value": 180, + "Series": "Clothing" + }, + { + "Date": "2022-08-16", + "Value": 179, + "Series": "Clothing" + }, + { + "Date": "2022-09-30", + "Value": 179, + "Series": "Clothing" + }, + { + "Date": "2022-11-15", + "Value": 180, + "Series": "Clothing" + }, + { + "Date": "2020-01-01", + "Value": 71, + "Series": "Food" + }, + { + "Date": "2020-02-15", + "Value": 61, + "Series": "Food" + }, + { + "Date": "2020-04-01", + "Value": 59, + "Series": "Food" + }, + { + "Date": "2020-05-16", + "Value": 66, + "Series": "Food" + }, + { + "Date": "2020-07-01", + "Value": 63, + "Series": "Food" + }, + { + "Date": "2020-08-16", + "Value": 75, + "Series": "Food" + }, + { + "Date": "2020-09-30", + "Value": 84, + "Series": "Food" + }, + { + "Date": "2020-11-15", + "Value": 77, + "Series": "Food" + }, + { + "Date": "2020-12-31", + "Value": 93, + "Series": "Food" + }, + { + "Date": "2021-02-14", + "Value": 120, + "Series": "Food" + }, + { + "Date": "2021-04-01", + "Value": 160, + "Series": "Food" + }, + { + "Date": "2021-05-16", + "Value": 199, + "Series": "Food" + }, + { + "Date": "2021-07-01", + "Value": 210, + "Series": "Food" + }, + { + "Date": "2021-08-16", + "Value": 202, + "Series": "Food" + }, + { + "Date": "2021-09-30", + "Value": 219, + "Series": "Food" + }, + { + "Date": "2021-11-15", + "Value": 245, + "Series": "Food" + }, + { + "Date": "2021-12-31", + "Value": 260, + "Series": "Food" + }, + { + "Date": "2022-02-14", + "Value": 264, + "Series": "Food" + }, + { + "Date": "2022-04-01", + "Value": 286, + "Series": "Food" + }, + { + "Date": "2022-05-16", + "Value": 292, + "Series": "Food" + }, + { + "Date": "2022-07-01", + "Value": 288, + "Series": "Food" + }, + { + "Date": "2022-08-16", + "Value": 273, + "Series": "Food" + }, + { + "Date": "2022-09-30", + "Value": 262, + "Series": "Food" + }, + { + "Date": "2022-11-15", + "Value": 264, + "Series": "Food" + }, + { + "Date": "2020-01-01", + "Value": 126, + "Series": "Books" + }, + { + "Date": "2020-02-15", + "Value": 132, + "Series": "Books" + }, + { + "Date": "2020-04-01", + "Value": 143, + "Series": "Books" + }, + { + "Date": "2020-05-16", + "Value": 146, + "Series": "Books" + }, + { + "Date": "2020-07-01", + "Value": 148, + "Series": "Books" + }, + { + "Date": "2020-08-16", + "Value": 156, + "Series": "Books" + }, + { + "Date": "2020-09-30", + "Value": 162, + "Series": "Books" + }, + { + "Date": "2020-11-15", + "Value": 175, + "Series": "Books" + }, + { + "Date": "2020-12-31", + "Value": 196, + "Series": "Books" + }, + { + "Date": "2021-02-14", + "Value": 224, + "Series": "Books" + }, + { + "Date": "2021-04-01", + "Value": 251, + "Series": "Books" + }, + { + "Date": "2021-05-16", + "Value": 256, + "Series": "Books" + }, + { + "Date": "2021-07-01", + "Value": 262, + "Series": "Books" + }, + { + "Date": "2021-08-16", + "Value": 283, + "Series": "Books" + }, + { + "Date": "2021-09-30", + "Value": 299, + "Series": "Books" + }, + { + "Date": "2021-11-15", + "Value": 307, + "Series": "Books" + }, + { + "Date": "2021-12-31", + "Value": 319, + "Series": "Books" + }, + { + "Date": "2022-02-14", + "Value": 344, + "Series": "Books" + }, + { + "Date": "2022-04-01", + "Value": 353, + "Series": "Books" + }, + { + "Date": "2022-05-16", + "Value": 358, + "Series": "Books" + }, + { + "Date": "2022-07-01", + "Value": 374, + "Series": "Books" + }, + { + "Date": "2022-08-16", + "Value": 373, + "Series": "Books" + }, + { + "Date": "2022-09-30", + "Value": 364, + "Series": "Books" + }, + { + "Date": "2022-11-15", + "Value": 373, + "Series": "Books" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/area-chart/02-card60.flint.json b/test-harness/excel/evaluations/inputs/area-chart/02-card60.flint.json new file mode 100644 index 00000000..368a2f35 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/area-chart/02-card60.flint.json @@ -0,0 +1,2423 @@ +{ + "semantic_types": { + "Date": "Date", + "Value": "Quantity", + "Series": "Category" + }, + "chart_spec": { + "chartType": "Area Chart", + "encodings": { + "x": "Date", + "y": "Value", + "color": "Series" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Date": "2020-01-01", + "Value": 203, + "Series": "Electronics" + }, + { + "Date": "2020-01-19", + "Value": 204, + "Series": "Electronics" + }, + { + "Date": "2020-02-06", + "Value": 217, + "Series": "Electronics" + }, + { + "Date": "2020-02-24", + "Value": 225, + "Series": "Electronics" + }, + { + "Date": "2020-03-14", + "Value": 224, + "Series": "Electronics" + }, + { + "Date": "2020-04-01", + "Value": 232, + "Series": "Electronics" + }, + { + "Date": "2020-04-19", + "Value": 245, + "Series": "Electronics" + }, + { + "Date": "2020-05-07", + "Value": 264, + "Series": "Electronics" + }, + { + "Date": "2020-05-26", + "Value": 269, + "Series": "Electronics" + }, + { + "Date": "2020-06-13", + "Value": 265, + "Series": "Electronics" + }, + { + "Date": "2020-07-01", + "Value": 263, + "Series": "Electronics" + }, + { + "Date": "2020-07-19", + "Value": 265, + "Series": "Electronics" + }, + { + "Date": "2020-08-07", + "Value": 263, + "Series": "Electronics" + }, + { + "Date": "2020-08-25", + "Value": 266, + "Series": "Electronics" + }, + { + "Date": "2020-09-12", + "Value": 274, + "Series": "Electronics" + }, + { + "Date": "2020-09-30", + "Value": 286, + "Series": "Electronics" + }, + { + "Date": "2020-10-19", + "Value": 296, + "Series": "Electronics" + }, + { + "Date": "2020-11-06", + "Value": 307, + "Series": "Electronics" + }, + { + "Date": "2020-11-24", + "Value": 311, + "Series": "Electronics" + }, + { + "Date": "2020-12-12", + "Value": 319, + "Series": "Electronics" + }, + { + "Date": "2020-12-31", + "Value": 329, + "Series": "Electronics" + }, + { + "Date": "2021-01-18", + "Value": 343, + "Series": "Electronics" + }, + { + "Date": "2021-02-05", + "Value": 354, + "Series": "Electronics" + }, + { + "Date": "2021-02-23", + "Value": 364, + "Series": "Electronics" + }, + { + "Date": "2021-03-14", + "Value": 367, + "Series": "Electronics" + }, + { + "Date": "2021-04-01", + "Value": 380, + "Series": "Electronics" + }, + { + "Date": "2021-04-19", + "Value": 396, + "Series": "Electronics" + }, + { + "Date": "2021-05-07", + "Value": 408, + "Series": "Electronics" + }, + { + "Date": "2021-05-26", + "Value": 410, + "Series": "Electronics" + }, + { + "Date": "2021-06-13", + "Value": 408, + "Series": "Electronics" + }, + { + "Date": "2021-07-01", + "Value": 403, + "Series": "Electronics" + }, + { + "Date": "2021-07-19", + "Value": 400, + "Series": "Electronics" + }, + { + "Date": "2021-08-07", + "Value": 398, + "Series": "Electronics" + }, + { + "Date": "2021-08-25", + "Value": 407, + "Series": "Electronics" + }, + { + "Date": "2021-09-12", + "Value": 422, + "Series": "Electronics" + }, + { + "Date": "2021-09-30", + "Value": 435, + "Series": "Electronics" + }, + { + "Date": "2021-10-19", + "Value": 448, + "Series": "Electronics" + }, + { + "Date": "2021-11-06", + "Value": 457, + "Series": "Electronics" + }, + { + "Date": "2021-11-24", + "Value": 460, + "Series": "Electronics" + }, + { + "Date": "2021-12-12", + "Value": 473, + "Series": "Electronics" + }, + { + "Date": "2021-12-31", + "Value": 486, + "Series": "Electronics" + }, + { + "Date": "2022-01-18", + "Value": 493, + "Series": "Electronics" + }, + { + "Date": "2022-02-05", + "Value": 490, + "Series": "Electronics" + }, + { + "Date": "2022-02-23", + "Value": 492, + "Series": "Electronics" + }, + { + "Date": "2022-03-14", + "Value": 488, + "Series": "Electronics" + }, + { + "Date": "2022-04-01", + "Value": 494, + "Series": "Electronics" + }, + { + "Date": "2022-04-19", + "Value": 510, + "Series": "Electronics" + }, + { + "Date": "2022-05-07", + "Value": 529, + "Series": "Electronics" + }, + { + "Date": "2022-05-26", + "Value": 541, + "Series": "Electronics" + }, + { + "Date": "2022-06-13", + "Value": 543, + "Series": "Electronics" + }, + { + "Date": "2022-07-01", + "Value": 548, + "Series": "Electronics" + }, + { + "Date": "2022-07-19", + "Value": 551, + "Series": "Electronics" + }, + { + "Date": "2022-08-07", + "Value": 562, + "Series": "Electronics" + }, + { + "Date": "2022-08-25", + "Value": 569, + "Series": "Electronics" + }, + { + "Date": "2022-09-12", + "Value": 572, + "Series": "Electronics" + }, + { + "Date": "2022-09-30", + "Value": 586, + "Series": "Electronics" + }, + { + "Date": "2022-10-19", + "Value": 603, + "Series": "Electronics" + }, + { + "Date": "2022-11-06", + "Value": 618, + "Series": "Electronics" + }, + { + "Date": "2022-11-24", + "Value": 634, + "Series": "Electronics" + }, + { + "Date": "2022-12-12", + "Value": 651, + "Series": "Electronics" + }, + { + "Date": "2020-01-01", + "Value": 208, + "Series": "Clothing" + }, + { + "Date": "2020-01-19", + "Value": 192, + "Series": "Clothing" + }, + { + "Date": "2020-02-06", + "Value": 178, + "Series": "Clothing" + }, + { + "Date": "2020-02-24", + "Value": 174, + "Series": "Clothing" + }, + { + "Date": "2020-03-14", + "Value": 181, + "Series": "Clothing" + }, + { + "Date": "2020-04-01", + "Value": 180, + "Series": "Clothing" + }, + { + "Date": "2020-04-19", + "Value": 165, + "Series": "Clothing" + }, + { + "Date": "2020-05-07", + "Value": 145, + "Series": "Clothing" + }, + { + "Date": "2020-05-26", + "Value": 122, + "Series": "Clothing" + }, + { + "Date": "2020-06-13", + "Value": 122, + "Series": "Clothing" + }, + { + "Date": "2020-07-01", + "Value": 138, + "Series": "Clothing" + }, + { + "Date": "2020-07-19", + "Value": 158, + "Series": "Clothing" + }, + { + "Date": "2020-08-07", + "Value": 171, + "Series": "Clothing" + }, + { + "Date": "2020-08-25", + "Value": 165, + "Series": "Clothing" + }, + { + "Date": "2020-09-12", + "Value": 146, + "Series": "Clothing" + }, + { + "Date": "2020-09-30", + "Value": 128, + "Series": "Clothing" + }, + { + "Date": "2020-10-19", + "Value": 127, + "Series": "Clothing" + }, + { + "Date": "2020-11-06", + "Value": 147, + "Series": "Clothing" + }, + { + "Date": "2020-11-24", + "Value": 181, + "Series": "Clothing" + }, + { + "Date": "2020-12-12", + "Value": 200, + "Series": "Clothing" + }, + { + "Date": "2020-12-31", + "Value": 206, + "Series": "Clothing" + }, + { + "Date": "2021-01-18", + "Value": 223, + "Series": "Clothing" + }, + { + "Date": "2021-02-05", + "Value": 241, + "Series": "Clothing" + }, + { + "Date": "2021-02-23", + "Value": 249, + "Series": "Clothing" + }, + { + "Date": "2021-03-14", + "Value": 246, + "Series": "Clothing" + }, + { + "Date": "2021-04-01", + "Value": 265, + "Series": "Clothing" + }, + { + "Date": "2021-04-19", + "Value": 283, + "Series": "Clothing" + }, + { + "Date": "2021-05-07", + "Value": 304, + "Series": "Clothing" + }, + { + "Date": "2021-05-26", + "Value": 324, + "Series": "Clothing" + }, + { + "Date": "2021-06-13", + "Value": 325, + "Series": "Clothing" + }, + { + "Date": "2021-07-01", + "Value": 347, + "Series": "Clothing" + }, + { + "Date": "2021-07-19", + "Value": 380, + "Series": "Clothing" + }, + { + "Date": "2021-08-07", + "Value": 422, + "Series": "Clothing" + }, + { + "Date": "2021-08-25", + "Value": 457, + "Series": "Clothing" + }, + { + "Date": "2021-09-12", + "Value": 494, + "Series": "Clothing" + }, + { + "Date": "2021-09-30", + "Value": 513, + "Series": "Clothing" + }, + { + "Date": "2021-10-19", + "Value": 513, + "Series": "Clothing" + }, + { + "Date": "2021-11-06", + "Value": 531, + "Series": "Clothing" + }, + { + "Date": "2021-11-24", + "Value": 538, + "Series": "Clothing" + }, + { + "Date": "2021-12-12", + "Value": 540, + "Series": "Clothing" + }, + { + "Date": "2021-12-31", + "Value": 531, + "Series": "Clothing" + }, + { + "Date": "2022-01-18", + "Value": 516, + "Series": "Clothing" + }, + { + "Date": "2022-02-05", + "Value": 508, + "Series": "Clothing" + }, + { + "Date": "2022-02-23", + "Value": 489, + "Series": "Clothing" + }, + { + "Date": "2022-03-14", + "Value": 473, + "Series": "Clothing" + }, + { + "Date": "2022-04-01", + "Value": 466, + "Series": "Clothing" + }, + { + "Date": "2022-04-19", + "Value": 453, + "Series": "Clothing" + }, + { + "Date": "2022-05-07", + "Value": 460, + "Series": "Clothing" + }, + { + "Date": "2022-05-26", + "Value": 477, + "Series": "Clothing" + }, + { + "Date": "2022-06-13", + "Value": 505, + "Series": "Clothing" + }, + { + "Date": "2022-07-01", + "Value": 527, + "Series": "Clothing" + }, + { + "Date": "2022-07-19", + "Value": 555, + "Series": "Clothing" + }, + { + "Date": "2022-08-07", + "Value": 585, + "Series": "Clothing" + }, + { + "Date": "2022-08-25", + "Value": 621, + "Series": "Clothing" + }, + { + "Date": "2022-09-12", + "Value": 644, + "Series": "Clothing" + }, + { + "Date": "2022-09-30", + "Value": 647, + "Series": "Clothing" + }, + { + "Date": "2022-10-19", + "Value": 635, + "Series": "Clothing" + }, + { + "Date": "2022-11-06", + "Value": 624, + "Series": "Clothing" + }, + { + "Date": "2022-11-24", + "Value": 632, + "Series": "Clothing" + }, + { + "Date": "2022-12-12", + "Value": 626, + "Series": "Clothing" + }, + { + "Date": "2020-01-01", + "Value": 74, + "Series": "Food" + }, + { + "Date": "2020-01-19", + "Value": 74, + "Series": "Food" + }, + { + "Date": "2020-02-06", + "Value": 72, + "Series": "Food" + }, + { + "Date": "2020-02-24", + "Value": 77, + "Series": "Food" + }, + { + "Date": "2020-03-14", + "Value": 82, + "Series": "Food" + }, + { + "Date": "2020-04-01", + "Value": 85, + "Series": "Food" + }, + { + "Date": "2020-04-19", + "Value": 91, + "Series": "Food" + }, + { + "Date": "2020-05-07", + "Value": 100, + "Series": "Food" + }, + { + "Date": "2020-05-26", + "Value": 106, + "Series": "Food" + }, + { + "Date": "2020-06-13", + "Value": 108, + "Series": "Food" + }, + { + "Date": "2020-07-01", + "Value": 114, + "Series": "Food" + }, + { + "Date": "2020-07-19", + "Value": 124, + "Series": "Food" + }, + { + "Date": "2020-08-07", + "Value": 136, + "Series": "Food" + }, + { + "Date": "2020-08-25", + "Value": 144, + "Series": "Food" + }, + { + "Date": "2020-09-12", + "Value": 155, + "Series": "Food" + }, + { + "Date": "2020-09-30", + "Value": 161, + "Series": "Food" + }, + { + "Date": "2020-10-19", + "Value": 165, + "Series": "Food" + }, + { + "Date": "2020-11-06", + "Value": 172, + "Series": "Food" + }, + { + "Date": "2020-11-24", + "Value": 177, + "Series": "Food" + }, + { + "Date": "2020-12-12", + "Value": 179, + "Series": "Food" + }, + { + "Date": "2020-12-31", + "Value": 182, + "Series": "Food" + }, + { + "Date": "2021-01-18", + "Value": 188, + "Series": "Food" + }, + { + "Date": "2021-02-05", + "Value": 188, + "Series": "Food" + }, + { + "Date": "2021-02-23", + "Value": 195, + "Series": "Food" + }, + { + "Date": "2021-03-14", + "Value": 197, + "Series": "Food" + }, + { + "Date": "2021-04-01", + "Value": 197, + "Series": "Food" + }, + { + "Date": "2021-04-19", + "Value": 203, + "Series": "Food" + }, + { + "Date": "2021-05-07", + "Value": 213, + "Series": "Food" + }, + { + "Date": "2021-05-26", + "Value": 224, + "Series": "Food" + }, + { + "Date": "2021-06-13", + "Value": 232, + "Series": "Food" + }, + { + "Date": "2021-07-01", + "Value": 233, + "Series": "Food" + }, + { + "Date": "2021-07-19", + "Value": 229, + "Series": "Food" + }, + { + "Date": "2021-08-07", + "Value": 229, + "Series": "Food" + }, + { + "Date": "2021-08-25", + "Value": 230, + "Series": "Food" + }, + { + "Date": "2021-09-12", + "Value": 234, + "Series": "Food" + }, + { + "Date": "2021-09-30", + "Value": 239, + "Series": "Food" + }, + { + "Date": "2021-10-19", + "Value": 242, + "Series": "Food" + }, + { + "Date": "2021-11-06", + "Value": 242, + "Series": "Food" + }, + { + "Date": "2021-11-24", + "Value": 244, + "Series": "Food" + }, + { + "Date": "2021-12-12", + "Value": 243, + "Series": "Food" + }, + { + "Date": "2021-12-31", + "Value": 241, + "Series": "Food" + }, + { + "Date": "2022-01-18", + "Value": 240, + "Series": "Food" + }, + { + "Date": "2022-02-05", + "Value": 239, + "Series": "Food" + }, + { + "Date": "2022-02-23", + "Value": 239, + "Series": "Food" + }, + { + "Date": "2022-03-14", + "Value": 241, + "Series": "Food" + }, + { + "Date": "2022-04-01", + "Value": 239, + "Series": "Food" + }, + { + "Date": "2022-04-19", + "Value": 243, + "Series": "Food" + }, + { + "Date": "2022-05-07", + "Value": 251, + "Series": "Food" + }, + { + "Date": "2022-05-26", + "Value": 262, + "Series": "Food" + }, + { + "Date": "2022-06-13", + "Value": 273, + "Series": "Food" + }, + { + "Date": "2022-07-01", + "Value": 276, + "Series": "Food" + }, + { + "Date": "2022-07-19", + "Value": 274, + "Series": "Food" + }, + { + "Date": "2022-08-07", + "Value": 280, + "Series": "Food" + }, + { + "Date": "2022-08-25", + "Value": 287, + "Series": "Food" + }, + { + "Date": "2022-09-12", + "Value": 289, + "Series": "Food" + }, + { + "Date": "2022-09-30", + "Value": 287, + "Series": "Food" + }, + { + "Date": "2022-10-19", + "Value": 289, + "Series": "Food" + }, + { + "Date": "2022-11-06", + "Value": 295, + "Series": "Food" + }, + { + "Date": "2022-11-24", + "Value": 295, + "Series": "Food" + }, + { + "Date": "2022-12-12", + "Value": 299, + "Series": "Food" + }, + { + "Date": "2020-01-01", + "Value": 147, + "Series": "Books" + }, + { + "Date": "2020-01-19", + "Value": 156, + "Series": "Books" + }, + { + "Date": "2020-02-06", + "Value": 168, + "Series": "Books" + }, + { + "Date": "2020-02-24", + "Value": 173, + "Series": "Books" + }, + { + "Date": "2020-03-14", + "Value": 178, + "Series": "Books" + }, + { + "Date": "2020-04-01", + "Value": 177, + "Series": "Books" + }, + { + "Date": "2020-04-19", + "Value": 179, + "Series": "Books" + }, + { + "Date": "2020-05-07", + "Value": 189, + "Series": "Books" + }, + { + "Date": "2020-05-26", + "Value": 199, + "Series": "Books" + }, + { + "Date": "2020-06-13", + "Value": 210, + "Series": "Books" + }, + { + "Date": "2020-07-01", + "Value": 212, + "Series": "Books" + }, + { + "Date": "2020-07-19", + "Value": 222, + "Series": "Books" + }, + { + "Date": "2020-08-07", + "Value": 225, + "Series": "Books" + }, + { + "Date": "2020-08-25", + "Value": 225, + "Series": "Books" + }, + { + "Date": "2020-09-12", + "Value": 227, + "Series": "Books" + }, + { + "Date": "2020-09-30", + "Value": 224, + "Series": "Books" + }, + { + "Date": "2020-10-19", + "Value": 222, + "Series": "Books" + }, + { + "Date": "2020-11-06", + "Value": 221, + "Series": "Books" + }, + { + "Date": "2020-11-24", + "Value": 226, + "Series": "Books" + }, + { + "Date": "2020-12-12", + "Value": 224, + "Series": "Books" + }, + { + "Date": "2020-12-31", + "Value": 231, + "Series": "Books" + }, + { + "Date": "2021-01-18", + "Value": 241, + "Series": "Books" + }, + { + "Date": "2021-02-05", + "Value": 245, + "Series": "Books" + }, + { + "Date": "2021-02-23", + "Value": 251, + "Series": "Books" + }, + { + "Date": "2021-03-14", + "Value": 259, + "Series": "Books" + }, + { + "Date": "2021-04-01", + "Value": 273, + "Series": "Books" + }, + { + "Date": "2021-04-19", + "Value": 285, + "Series": "Books" + }, + { + "Date": "2021-05-07", + "Value": 300, + "Series": "Books" + }, + { + "Date": "2021-05-26", + "Value": 314, + "Series": "Books" + }, + { + "Date": "2021-06-13", + "Value": 319, + "Series": "Books" + }, + { + "Date": "2021-07-01", + "Value": 328, + "Series": "Books" + }, + { + "Date": "2021-07-19", + "Value": 341, + "Series": "Books" + }, + { + "Date": "2021-08-07", + "Value": 355, + "Series": "Books" + }, + { + "Date": "2021-08-25", + "Value": 371, + "Series": "Books" + }, + { + "Date": "2021-09-12", + "Value": 390, + "Series": "Books" + }, + { + "Date": "2021-09-30", + "Value": 407, + "Series": "Books" + }, + { + "Date": "2021-10-19", + "Value": 421, + "Series": "Books" + }, + { + "Date": "2021-11-06", + "Value": 433, + "Series": "Books" + }, + { + "Date": "2021-11-24", + "Value": 443, + "Series": "Books" + }, + { + "Date": "2021-12-12", + "Value": 446, + "Series": "Books" + }, + { + "Date": "2021-12-31", + "Value": 457, + "Series": "Books" + }, + { + "Date": "2022-01-18", + "Value": 462, + "Series": "Books" + }, + { + "Date": "2022-02-05", + "Value": 469, + "Series": "Books" + }, + { + "Date": "2022-02-23", + "Value": 480, + "Series": "Books" + }, + { + "Date": "2022-03-14", + "Value": 489, + "Series": "Books" + }, + { + "Date": "2022-04-01", + "Value": 490, + "Series": "Books" + }, + { + "Date": "2022-04-19", + "Value": 494, + "Series": "Books" + }, + { + "Date": "2022-05-07", + "Value": 502, + "Series": "Books" + }, + { + "Date": "2022-05-26", + "Value": 510, + "Series": "Books" + }, + { + "Date": "2022-06-13", + "Value": 511, + "Series": "Books" + }, + { + "Date": "2022-07-01", + "Value": 511, + "Series": "Books" + }, + { + "Date": "2022-07-19", + "Value": 511, + "Series": "Books" + }, + { + "Date": "2022-08-07", + "Value": 508, + "Series": "Books" + }, + { + "Date": "2022-08-25", + "Value": 506, + "Series": "Books" + }, + { + "Date": "2022-09-12", + "Value": 500, + "Series": "Books" + }, + { + "Date": "2022-09-30", + "Value": 492, + "Series": "Books" + }, + { + "Date": "2022-10-19", + "Value": 487, + "Series": "Books" + }, + { + "Date": "2022-11-06", + "Value": 480, + "Series": "Books" + }, + { + "Date": "2022-11-24", + "Value": 476, + "Series": "Books" + }, + { + "Date": "2022-12-12", + "Value": 469, + "Series": "Books" + }, + { + "Date": "2020-01-01", + "Value": 205, + "Series": "Sports" + }, + { + "Date": "2020-01-19", + "Value": 211, + "Series": "Sports" + }, + { + "Date": "2020-02-06", + "Value": 216, + "Series": "Sports" + }, + { + "Date": "2020-02-24", + "Value": 216, + "Series": "Sports" + }, + { + "Date": "2020-03-14", + "Value": 219, + "Series": "Sports" + }, + { + "Date": "2020-04-01", + "Value": 223, + "Series": "Sports" + }, + { + "Date": "2020-04-19", + "Value": 224, + "Series": "Sports" + }, + { + "Date": "2020-05-07", + "Value": 231, + "Series": "Sports" + }, + { + "Date": "2020-05-26", + "Value": 234, + "Series": "Sports" + }, + { + "Date": "2020-06-13", + "Value": 242, + "Series": "Sports" + }, + { + "Date": "2020-07-01", + "Value": 254, + "Series": "Sports" + }, + { + "Date": "2020-07-19", + "Value": 259, + "Series": "Sports" + }, + { + "Date": "2020-08-07", + "Value": 267, + "Series": "Sports" + }, + { + "Date": "2020-08-25", + "Value": 273, + "Series": "Sports" + }, + { + "Date": "2020-09-12", + "Value": 274, + "Series": "Sports" + }, + { + "Date": "2020-09-30", + "Value": 277, + "Series": "Sports" + }, + { + "Date": "2020-10-19", + "Value": 284, + "Series": "Sports" + }, + { + "Date": "2020-11-06", + "Value": 291, + "Series": "Sports" + }, + { + "Date": "2020-11-24", + "Value": 294, + "Series": "Sports" + }, + { + "Date": "2020-12-12", + "Value": 293, + "Series": "Sports" + }, + { + "Date": "2020-12-31", + "Value": 295, + "Series": "Sports" + }, + { + "Date": "2021-01-18", + "Value": 299, + "Series": "Sports" + }, + { + "Date": "2021-02-05", + "Value": 302, + "Series": "Sports" + }, + { + "Date": "2021-02-23", + "Value": 304, + "Series": "Sports" + }, + { + "Date": "2021-03-14", + "Value": 308, + "Series": "Sports" + }, + { + "Date": "2021-04-01", + "Value": 313, + "Series": "Sports" + }, + { + "Date": "2021-04-19", + "Value": 313, + "Series": "Sports" + }, + { + "Date": "2021-05-07", + "Value": 311, + "Series": "Sports" + }, + { + "Date": "2021-05-26", + "Value": 316, + "Series": "Sports" + }, + { + "Date": "2021-06-13", + "Value": 320, + "Series": "Sports" + }, + { + "Date": "2021-07-01", + "Value": 322, + "Series": "Sports" + }, + { + "Date": "2021-07-19", + "Value": 331, + "Series": "Sports" + }, + { + "Date": "2021-08-07", + "Value": 341, + "Series": "Sports" + }, + { + "Date": "2021-08-25", + "Value": 347, + "Series": "Sports" + }, + { + "Date": "2021-09-12", + "Value": 348, + "Series": "Sports" + }, + { + "Date": "2021-09-30", + "Value": 355, + "Series": "Sports" + }, + { + "Date": "2021-10-19", + "Value": 356, + "Series": "Sports" + }, + { + "Date": "2021-11-06", + "Value": 356, + "Series": "Sports" + }, + { + "Date": "2021-11-24", + "Value": 356, + "Series": "Sports" + }, + { + "Date": "2021-12-12", + "Value": 363, + "Series": "Sports" + }, + { + "Date": "2021-12-31", + "Value": 366, + "Series": "Sports" + }, + { + "Date": "2022-01-18", + "Value": 373, + "Series": "Sports" + }, + { + "Date": "2022-02-05", + "Value": 374, + "Series": "Sports" + }, + { + "Date": "2022-02-23", + "Value": 381, + "Series": "Sports" + }, + { + "Date": "2022-03-14", + "Value": 392, + "Series": "Sports" + }, + { + "Date": "2022-04-01", + "Value": 400, + "Series": "Sports" + }, + { + "Date": "2022-04-19", + "Value": 405, + "Series": "Sports" + }, + { + "Date": "2022-05-07", + "Value": 406, + "Series": "Sports" + }, + { + "Date": "2022-05-26", + "Value": 410, + "Series": "Sports" + }, + { + "Date": "2022-06-13", + "Value": 415, + "Series": "Sports" + }, + { + "Date": "2022-07-01", + "Value": 417, + "Series": "Sports" + }, + { + "Date": "2022-07-19", + "Value": 423, + "Series": "Sports" + }, + { + "Date": "2022-08-07", + "Value": 431, + "Series": "Sports" + }, + { + "Date": "2022-08-25", + "Value": 439, + "Series": "Sports" + }, + { + "Date": "2022-09-12", + "Value": 445, + "Series": "Sports" + }, + { + "Date": "2022-09-30", + "Value": 451, + "Series": "Sports" + }, + { + "Date": "2022-10-19", + "Value": 453, + "Series": "Sports" + }, + { + "Date": "2022-11-06", + "Value": 451, + "Series": "Sports" + }, + { + "Date": "2022-11-24", + "Value": 451, + "Series": "Sports" + }, + { + "Date": "2022-12-12", + "Value": 454, + "Series": "Sports" + }, + { + "Date": "2020-01-01", + "Value": 201, + "Series": "Home" + }, + { + "Date": "2020-01-19", + "Value": 215, + "Series": "Home" + }, + { + "Date": "2020-02-06", + "Value": 239, + "Series": "Home" + }, + { + "Date": "2020-02-24", + "Value": 259, + "Series": "Home" + }, + { + "Date": "2020-03-14", + "Value": 262, + "Series": "Home" + }, + { + "Date": "2020-04-01", + "Value": 256, + "Series": "Home" + }, + { + "Date": "2020-04-19", + "Value": 264, + "Series": "Home" + }, + { + "Date": "2020-05-07", + "Value": 277, + "Series": "Home" + }, + { + "Date": "2020-05-26", + "Value": 290, + "Series": "Home" + }, + { + "Date": "2020-06-13", + "Value": 307, + "Series": "Home" + }, + { + "Date": "2020-07-01", + "Value": 332, + "Series": "Home" + }, + { + "Date": "2020-07-19", + "Value": 339, + "Series": "Home" + }, + { + "Date": "2020-08-07", + "Value": 357, + "Series": "Home" + }, + { + "Date": "2020-08-25", + "Value": 358, + "Series": "Home" + }, + { + "Date": "2020-09-12", + "Value": 364, + "Series": "Home" + }, + { + "Date": "2020-09-30", + "Value": 360, + "Series": "Home" + }, + { + "Date": "2020-10-19", + "Value": 355, + "Series": "Home" + }, + { + "Date": "2020-11-06", + "Value": 345, + "Series": "Home" + }, + { + "Date": "2020-11-24", + "Value": 354, + "Series": "Home" + }, + { + "Date": "2020-12-12", + "Value": 365, + "Series": "Home" + }, + { + "Date": "2020-12-31", + "Value": 361, + "Series": "Home" + }, + { + "Date": "2021-01-18", + "Value": 368, + "Series": "Home" + }, + { + "Date": "2021-02-05", + "Value": 373, + "Series": "Home" + }, + { + "Date": "2021-02-23", + "Value": 386, + "Series": "Home" + }, + { + "Date": "2021-03-14", + "Value": 398, + "Series": "Home" + }, + { + "Date": "2021-04-01", + "Value": 397, + "Series": "Home" + }, + { + "Date": "2021-04-19", + "Value": 396, + "Series": "Home" + }, + { + "Date": "2021-05-07", + "Value": 384, + "Series": "Home" + }, + { + "Date": "2021-05-26", + "Value": 366, + "Series": "Home" + }, + { + "Date": "2021-06-13", + "Value": 360, + "Series": "Home" + }, + { + "Date": "2021-07-01", + "Value": 360, + "Series": "Home" + }, + { + "Date": "2021-07-19", + "Value": 377, + "Series": "Home" + }, + { + "Date": "2021-08-07", + "Value": 390, + "Series": "Home" + }, + { + "Date": "2021-08-25", + "Value": 408, + "Series": "Home" + }, + { + "Date": "2021-09-12", + "Value": 436, + "Series": "Home" + }, + { + "Date": "2021-09-30", + "Value": 444, + "Series": "Home" + }, + { + "Date": "2021-10-19", + "Value": 460, + "Series": "Home" + }, + { + "Date": "2021-11-06", + "Value": 462, + "Series": "Home" + }, + { + "Date": "2021-11-24", + "Value": 481, + "Series": "Home" + }, + { + "Date": "2021-12-12", + "Value": 499, + "Series": "Home" + }, + { + "Date": "2021-12-31", + "Value": 506, + "Series": "Home" + }, + { + "Date": "2022-01-18", + "Value": 525, + "Series": "Home" + }, + { + "Date": "2022-02-05", + "Value": 553, + "Series": "Home" + }, + { + "Date": "2022-02-23", + "Value": 583, + "Series": "Home" + }, + { + "Date": "2022-03-14", + "Value": 601, + "Series": "Home" + }, + { + "Date": "2022-04-01", + "Value": 609, + "Series": "Home" + }, + { + "Date": "2022-04-19", + "Value": 622, + "Series": "Home" + }, + { + "Date": "2022-05-07", + "Value": 620, + "Series": "Home" + }, + { + "Date": "2022-05-26", + "Value": 631, + "Series": "Home" + }, + { + "Date": "2022-06-13", + "Value": 647, + "Series": "Home" + }, + { + "Date": "2022-07-01", + "Value": 674, + "Series": "Home" + }, + { + "Date": "2022-07-19", + "Value": 705, + "Series": "Home" + }, + { + "Date": "2022-08-07", + "Value": 714, + "Series": "Home" + }, + { + "Date": "2022-08-25", + "Value": 708, + "Series": "Home" + }, + { + "Date": "2022-09-12", + "Value": 709, + "Series": "Home" + }, + { + "Date": "2022-09-30", + "Value": 717, + "Series": "Home" + }, + { + "Date": "2022-10-19", + "Value": 717, + "Series": "Home" + }, + { + "Date": "2022-11-06", + "Value": 735, + "Series": "Home" + }, + { + "Date": "2022-11-24", + "Value": 737, + "Series": "Home" + }, + { + "Date": "2022-12-12", + "Value": 737, + "Series": "Home" + }, + { + "Date": "2020-01-01", + "Value": 120, + "Series": "Garden" + }, + { + "Date": "2020-01-19", + "Value": 130, + "Series": "Garden" + }, + { + "Date": "2020-02-06", + "Value": 142, + "Series": "Garden" + }, + { + "Date": "2020-02-24", + "Value": 141, + "Series": "Garden" + }, + { + "Date": "2020-03-14", + "Value": 152, + "Series": "Garden" + }, + { + "Date": "2020-04-01", + "Value": 156, + "Series": "Garden" + }, + { + "Date": "2020-04-19", + "Value": 150, + "Series": "Garden" + }, + { + "Date": "2020-05-07", + "Value": 162, + "Series": "Garden" + }, + { + "Date": "2020-05-26", + "Value": 184, + "Series": "Garden" + }, + { + "Date": "2020-06-13", + "Value": 211, + "Series": "Garden" + }, + { + "Date": "2020-07-01", + "Value": 242, + "Series": "Garden" + }, + { + "Date": "2020-07-19", + "Value": 262, + "Series": "Garden" + }, + { + "Date": "2020-08-07", + "Value": 276, + "Series": "Garden" + }, + { + "Date": "2020-08-25", + "Value": 286, + "Series": "Garden" + }, + { + "Date": "2020-09-12", + "Value": 309, + "Series": "Garden" + }, + { + "Date": "2020-09-30", + "Value": 317, + "Series": "Garden" + }, + { + "Date": "2020-10-19", + "Value": 329, + "Series": "Garden" + }, + { + "Date": "2020-11-06", + "Value": 337, + "Series": "Garden" + }, + { + "Date": "2020-11-24", + "Value": 354, + "Series": "Garden" + }, + { + "Date": "2020-12-12", + "Value": 363, + "Series": "Garden" + }, + { + "Date": "2020-12-31", + "Value": 383, + "Series": "Garden" + }, + { + "Date": "2021-01-18", + "Value": 412, + "Series": "Garden" + }, + { + "Date": "2021-02-05", + "Value": 447, + "Series": "Garden" + }, + { + "Date": "2021-02-23", + "Value": 460, + "Series": "Garden" + }, + { + "Date": "2021-03-14", + "Value": 456, + "Series": "Garden" + }, + { + "Date": "2021-04-01", + "Value": 441, + "Series": "Garden" + }, + { + "Date": "2021-04-19", + "Value": 420, + "Series": "Garden" + }, + { + "Date": "2021-05-07", + "Value": 416, + "Series": "Garden" + }, + { + "Date": "2021-05-26", + "Value": 431, + "Series": "Garden" + }, + { + "Date": "2021-06-13", + "Value": 448, + "Series": "Garden" + }, + { + "Date": "2021-07-01", + "Value": 449, + "Series": "Garden" + }, + { + "Date": "2021-07-19", + "Value": 459, + "Series": "Garden" + }, + { + "Date": "2021-08-07", + "Value": 479, + "Series": "Garden" + }, + { + "Date": "2021-08-25", + "Value": 490, + "Series": "Garden" + }, + { + "Date": "2021-09-12", + "Value": 507, + "Series": "Garden" + }, + { + "Date": "2021-09-30", + "Value": 529, + "Series": "Garden" + }, + { + "Date": "2021-10-19", + "Value": 540, + "Series": "Garden" + }, + { + "Date": "2021-11-06", + "Value": 561, + "Series": "Garden" + }, + { + "Date": "2021-11-24", + "Value": 574, + "Series": "Garden" + }, + { + "Date": "2021-12-12", + "Value": 569, + "Series": "Garden" + }, + { + "Date": "2021-12-31", + "Value": 563, + "Series": "Garden" + }, + { + "Date": "2022-01-18", + "Value": 572, + "Series": "Garden" + }, + { + "Date": "2022-02-05", + "Value": 566, + "Series": "Garden" + }, + { + "Date": "2022-02-23", + "Value": 552, + "Series": "Garden" + }, + { + "Date": "2022-03-14", + "Value": 534, + "Series": "Garden" + }, + { + "Date": "2022-04-01", + "Value": 526, + "Series": "Garden" + }, + { + "Date": "2022-04-19", + "Value": 538, + "Series": "Garden" + }, + { + "Date": "2022-05-07", + "Value": 536, + "Series": "Garden" + }, + { + "Date": "2022-05-26", + "Value": 539, + "Series": "Garden" + }, + { + "Date": "2022-06-13", + "Value": 553, + "Series": "Garden" + }, + { + "Date": "2022-07-01", + "Value": 568, + "Series": "Garden" + }, + { + "Date": "2022-07-19", + "Value": 584, + "Series": "Garden" + }, + { + "Date": "2022-08-07", + "Value": 608, + "Series": "Garden" + }, + { + "Date": "2022-08-25", + "Value": 631, + "Series": "Garden" + }, + { + "Date": "2022-09-12", + "Value": 648, + "Series": "Garden" + }, + { + "Date": "2022-09-30", + "Value": 674, + "Series": "Garden" + }, + { + "Date": "2022-10-19", + "Value": 703, + "Series": "Garden" + }, + { + "Date": "2022-11-06", + "Value": 738, + "Series": "Garden" + }, + { + "Date": "2022-11-24", + "Value": 766, + "Series": "Garden" + }, + { + "Date": "2022-12-12", + "Value": 798, + "Series": "Garden" + }, + { + "Date": "2020-01-01", + "Value": 213, + "Series": "Auto" + }, + { + "Date": "2020-01-19", + "Value": 211, + "Series": "Auto" + }, + { + "Date": "2020-02-06", + "Value": 222, + "Series": "Auto" + }, + { + "Date": "2020-02-24", + "Value": 227, + "Series": "Auto" + }, + { + "Date": "2020-03-14", + "Value": 249, + "Series": "Auto" + }, + { + "Date": "2020-04-01", + "Value": 276, + "Series": "Auto" + }, + { + "Date": "2020-04-19", + "Value": 281, + "Series": "Auto" + }, + { + "Date": "2020-05-07", + "Value": 304, + "Series": "Auto" + }, + { + "Date": "2020-05-26", + "Value": 309, + "Series": "Auto" + }, + { + "Date": "2020-06-13", + "Value": 329, + "Series": "Auto" + }, + { + "Date": "2020-07-01", + "Value": 361, + "Series": "Auto" + }, + { + "Date": "2020-07-19", + "Value": 365, + "Series": "Auto" + }, + { + "Date": "2020-08-07", + "Value": 381, + "Series": "Auto" + }, + { + "Date": "2020-08-25", + "Value": 412, + "Series": "Auto" + }, + { + "Date": "2020-09-12", + "Value": 424, + "Series": "Auto" + }, + { + "Date": "2020-09-30", + "Value": 450, + "Series": "Auto" + }, + { + "Date": "2020-10-19", + "Value": 478, + "Series": "Auto" + }, + { + "Date": "2020-11-06", + "Value": 497, + "Series": "Auto" + }, + { + "Date": "2020-11-24", + "Value": 495, + "Series": "Auto" + }, + { + "Date": "2020-12-12", + "Value": 487, + "Series": "Auto" + }, + { + "Date": "2020-12-31", + "Value": 472, + "Series": "Auto" + }, + { + "Date": "2021-01-18", + "Value": 477, + "Series": "Auto" + }, + { + "Date": "2021-02-05", + "Value": 484, + "Series": "Auto" + }, + { + "Date": "2021-02-23", + "Value": 482, + "Series": "Auto" + }, + { + "Date": "2021-03-14", + "Value": 468, + "Series": "Auto" + }, + { + "Date": "2021-04-01", + "Value": 474, + "Series": "Auto" + }, + { + "Date": "2021-04-19", + "Value": 496, + "Series": "Auto" + }, + { + "Date": "2021-05-07", + "Value": 528, + "Series": "Auto" + }, + { + "Date": "2021-05-26", + "Value": 542, + "Series": "Auto" + }, + { + "Date": "2021-06-13", + "Value": 561, + "Series": "Auto" + }, + { + "Date": "2021-07-01", + "Value": 576, + "Series": "Auto" + }, + { + "Date": "2021-07-19", + "Value": 571, + "Series": "Auto" + }, + { + "Date": "2021-08-07", + "Value": 559, + "Series": "Auto" + }, + { + "Date": "2021-08-25", + "Value": 558, + "Series": "Auto" + }, + { + "Date": "2021-09-12", + "Value": 562, + "Series": "Auto" + }, + { + "Date": "2021-09-30", + "Value": 574, + "Series": "Auto" + }, + { + "Date": "2021-10-19", + "Value": 571, + "Series": "Auto" + }, + { + "Date": "2021-11-06", + "Value": 591, + "Series": "Auto" + }, + { + "Date": "2021-11-24", + "Value": 615, + "Series": "Auto" + }, + { + "Date": "2021-12-12", + "Value": 647, + "Series": "Auto" + }, + { + "Date": "2021-12-31", + "Value": 655, + "Series": "Auto" + }, + { + "Date": "2022-01-18", + "Value": 653, + "Series": "Auto" + }, + { + "Date": "2022-02-05", + "Value": 656, + "Series": "Auto" + }, + { + "Date": "2022-02-23", + "Value": 654, + "Series": "Auto" + }, + { + "Date": "2022-03-14", + "Value": 660, + "Series": "Auto" + }, + { + "Date": "2022-04-01", + "Value": 673, + "Series": "Auto" + }, + { + "Date": "2022-04-19", + "Value": 698, + "Series": "Auto" + }, + { + "Date": "2022-05-07", + "Value": 707, + "Series": "Auto" + }, + { + "Date": "2022-05-26", + "Value": 722, + "Series": "Auto" + }, + { + "Date": "2022-06-13", + "Value": 727, + "Series": "Auto" + }, + { + "Date": "2022-07-01", + "Value": 734, + "Series": "Auto" + }, + { + "Date": "2022-07-19", + "Value": 729, + "Series": "Auto" + }, + { + "Date": "2022-08-07", + "Value": 734, + "Series": "Auto" + }, + { + "Date": "2022-08-25", + "Value": 752, + "Series": "Auto" + }, + { + "Date": "2022-09-12", + "Value": 762, + "Series": "Auto" + }, + { + "Date": "2022-09-30", + "Value": 765, + "Series": "Auto" + }, + { + "Date": "2022-10-19", + "Value": 783, + "Series": "Auto" + }, + { + "Date": "2022-11-06", + "Value": 813, + "Series": "Auto" + }, + { + "Date": "2022-11-24", + "Value": 823, + "Series": "Auto" + }, + { + "Date": "2022-12-12", + "Value": 822, + "Series": "Auto" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/area-chart/03-card120.flint.json b/test-harness/excel/evaluations/inputs/area-chart/03-card120.flint.json new file mode 100644 index 00000000..e2dd4d45 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/area-chart/03-card120.flint.json @@ -0,0 +1,9023 @@ +{ + "semantic_types": { + "Date": "Date", + "Value": "Quantity", + "Series": "Category" + }, + "chart_spec": { + "chartType": "Area Chart", + "encodings": { + "x": "Date", + "y": "Value", + "color": "Series" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Date": "2020-01-01", + "Value": 223, + "Series": "Electronics" + }, + { + "Date": "2020-01-10", + "Value": 235, + "Series": "Electronics" + }, + { + "Date": "2020-01-19", + "Value": 256, + "Series": "Electronics" + }, + { + "Date": "2020-01-28", + "Value": 269, + "Series": "Electronics" + }, + { + "Date": "2020-02-06", + "Value": 281, + "Series": "Electronics" + }, + { + "Date": "2020-02-15", + "Value": 279, + "Series": "Electronics" + }, + { + "Date": "2020-02-24", + "Value": 288, + "Series": "Electronics" + }, + { + "Date": "2020-03-04", + "Value": 307, + "Series": "Electronics" + }, + { + "Date": "2020-03-14", + "Value": 331, + "Series": "Electronics" + }, + { + "Date": "2020-03-23", + "Value": 337, + "Series": "Electronics" + }, + { + "Date": "2020-04-01", + "Value": 345, + "Series": "Electronics" + }, + { + "Date": "2020-04-10", + "Value": 341, + "Series": "Electronics" + }, + { + "Date": "2020-04-19", + "Value": 348, + "Series": "Electronics" + }, + { + "Date": "2020-04-28", + "Value": 348, + "Series": "Electronics" + }, + { + "Date": "2020-05-07", + "Value": 360, + "Series": "Electronics" + }, + { + "Date": "2020-05-16", + "Value": 361, + "Series": "Electronics" + }, + { + "Date": "2020-05-26", + "Value": 362, + "Series": "Electronics" + }, + { + "Date": "2020-06-04", + "Value": 363, + "Series": "Electronics" + }, + { + "Date": "2020-06-13", + "Value": 363, + "Series": "Electronics" + }, + { + "Date": "2020-06-22", + "Value": 370, + "Series": "Electronics" + }, + { + "Date": "2020-07-01", + "Value": 367, + "Series": "Electronics" + }, + { + "Date": "2020-07-10", + "Value": 376, + "Series": "Electronics" + }, + { + "Date": "2020-07-19", + "Value": 374, + "Series": "Electronics" + }, + { + "Date": "2020-07-28", + "Value": 372, + "Series": "Electronics" + }, + { + "Date": "2020-08-07", + "Value": 384, + "Series": "Electronics" + }, + { + "Date": "2020-08-16", + "Value": 399, + "Series": "Electronics" + }, + { + "Date": "2020-08-25", + "Value": 408, + "Series": "Electronics" + }, + { + "Date": "2020-09-03", + "Value": 423, + "Series": "Electronics" + }, + { + "Date": "2020-09-12", + "Value": 442, + "Series": "Electronics" + }, + { + "Date": "2020-09-21", + "Value": 458, + "Series": "Electronics" + }, + { + "Date": "2020-09-30", + "Value": 476, + "Series": "Electronics" + }, + { + "Date": "2020-10-09", + "Value": 494, + "Series": "Electronics" + }, + { + "Date": "2020-10-19", + "Value": 509, + "Series": "Electronics" + }, + { + "Date": "2020-10-28", + "Value": 526, + "Series": "Electronics" + }, + { + "Date": "2020-11-06", + "Value": 534, + "Series": "Electronics" + }, + { + "Date": "2020-11-15", + "Value": 530, + "Series": "Electronics" + }, + { + "Date": "2020-11-24", + "Value": 523, + "Series": "Electronics" + }, + { + "Date": "2020-12-03", + "Value": 526, + "Series": "Electronics" + }, + { + "Date": "2020-12-12", + "Value": 540, + "Series": "Electronics" + }, + { + "Date": "2020-12-21", + "Value": 545, + "Series": "Electronics" + }, + { + "Date": "2020-12-31", + "Value": 544, + "Series": "Electronics" + }, + { + "Date": "2021-01-09", + "Value": 557, + "Series": "Electronics" + }, + { + "Date": "2021-01-18", + "Value": 577, + "Series": "Electronics" + }, + { + "Date": "2021-01-27", + "Value": 597, + "Series": "Electronics" + }, + { + "Date": "2021-02-05", + "Value": 610, + "Series": "Electronics" + }, + { + "Date": "2021-02-14", + "Value": 617, + "Series": "Electronics" + }, + { + "Date": "2021-02-23", + "Value": 629, + "Series": "Electronics" + }, + { + "Date": "2021-03-04", + "Value": 631, + "Series": "Electronics" + }, + { + "Date": "2021-03-14", + "Value": 623, + "Series": "Electronics" + }, + { + "Date": "2021-03-23", + "Value": 625, + "Series": "Electronics" + }, + { + "Date": "2021-04-01", + "Value": 627, + "Series": "Electronics" + }, + { + "Date": "2021-04-10", + "Value": 629, + "Series": "Electronics" + }, + { + "Date": "2021-04-19", + "Value": 633, + "Series": "Electronics" + }, + { + "Date": "2021-04-28", + "Value": 637, + "Series": "Electronics" + }, + { + "Date": "2021-05-07", + "Value": 646, + "Series": "Electronics" + }, + { + "Date": "2021-05-16", + "Value": 656, + "Series": "Electronics" + }, + { + "Date": "2021-05-26", + "Value": 668, + "Series": "Electronics" + }, + { + "Date": "2021-06-04", + "Value": 687, + "Series": "Electronics" + }, + { + "Date": "2021-06-13", + "Value": 695, + "Series": "Electronics" + }, + { + "Date": "2021-06-22", + "Value": 706, + "Series": "Electronics" + }, + { + "Date": "2021-07-01", + "Value": 719, + "Series": "Electronics" + }, + { + "Date": "2021-07-10", + "Value": 731, + "Series": "Electronics" + }, + { + "Date": "2021-07-19", + "Value": 745, + "Series": "Electronics" + }, + { + "Date": "2021-07-28", + "Value": 744, + "Series": "Electronics" + }, + { + "Date": "2021-08-07", + "Value": 750, + "Series": "Electronics" + }, + { + "Date": "2021-08-16", + "Value": 752, + "Series": "Electronics" + }, + { + "Date": "2021-08-25", + "Value": 762, + "Series": "Electronics" + }, + { + "Date": "2021-09-03", + "Value": 778, + "Series": "Electronics" + }, + { + "Date": "2021-09-12", + "Value": 792, + "Series": "Electronics" + }, + { + "Date": "2021-09-21", + "Value": 794, + "Series": "Electronics" + }, + { + "Date": "2021-09-30", + "Value": 807, + "Series": "Electronics" + }, + { + "Date": "2021-10-09", + "Value": 819, + "Series": "Electronics" + }, + { + "Date": "2021-10-19", + "Value": 831, + "Series": "Electronics" + }, + { + "Date": "2021-10-28", + "Value": 830, + "Series": "Electronics" + }, + { + "Date": "2021-11-06", + "Value": 833, + "Series": "Electronics" + }, + { + "Date": "2021-11-15", + "Value": 844, + "Series": "Electronics" + }, + { + "Date": "2021-11-24", + "Value": 864, + "Series": "Electronics" + }, + { + "Date": "2021-12-03", + "Value": 868, + "Series": "Electronics" + }, + { + "Date": "2021-12-12", + "Value": 880, + "Series": "Electronics" + }, + { + "Date": "2021-12-21", + "Value": 899, + "Series": "Electronics" + }, + { + "Date": "2021-12-31", + "Value": 902, + "Series": "Electronics" + }, + { + "Date": "2022-01-09", + "Value": 907, + "Series": "Electronics" + }, + { + "Date": "2022-01-18", + "Value": 912, + "Series": "Electronics" + }, + { + "Date": "2022-01-27", + "Value": 909, + "Series": "Electronics" + }, + { + "Date": "2022-02-05", + "Value": 908, + "Series": "Electronics" + }, + { + "Date": "2022-02-14", + "Value": 900, + "Series": "Electronics" + }, + { + "Date": "2022-02-23", + "Value": 887, + "Series": "Electronics" + }, + { + "Date": "2022-03-04", + "Value": 883, + "Series": "Electronics" + }, + { + "Date": "2022-03-14", + "Value": 894, + "Series": "Electronics" + }, + { + "Date": "2022-03-23", + "Value": 912, + "Series": "Electronics" + }, + { + "Date": "2022-04-01", + "Value": 928, + "Series": "Electronics" + }, + { + "Date": "2022-04-10", + "Value": 934, + "Series": "Electronics" + }, + { + "Date": "2022-04-19", + "Value": 948, + "Series": "Electronics" + }, + { + "Date": "2022-04-28", + "Value": 948, + "Series": "Electronics" + }, + { + "Date": "2022-05-07", + "Value": 952, + "Series": "Electronics" + }, + { + "Date": "2022-05-16", + "Value": 957, + "Series": "Electronics" + }, + { + "Date": "2022-05-26", + "Value": 953, + "Series": "Electronics" + }, + { + "Date": "2022-06-04", + "Value": 959, + "Series": "Electronics" + }, + { + "Date": "2022-06-13", + "Value": 954, + "Series": "Electronics" + }, + { + "Date": "2022-06-22", + "Value": 963, + "Series": "Electronics" + }, + { + "Date": "2022-07-01", + "Value": 960, + "Series": "Electronics" + }, + { + "Date": "2022-07-10", + "Value": 966, + "Series": "Electronics" + }, + { + "Date": "2022-07-19", + "Value": 979, + "Series": "Electronics" + }, + { + "Date": "2022-07-28", + "Value": 982, + "Series": "Electronics" + }, + { + "Date": "2022-08-07", + "Value": 981, + "Series": "Electronics" + }, + { + "Date": "2022-08-16", + "Value": 988, + "Series": "Electronics" + }, + { + "Date": "2022-08-25", + "Value": 995, + "Series": "Electronics" + }, + { + "Date": "2022-09-03", + "Value": 1000, + "Series": "Electronics" + }, + { + "Date": "2022-09-12", + "Value": 997, + "Series": "Electronics" + }, + { + "Date": "2022-09-21", + "Value": 992, + "Series": "Electronics" + }, + { + "Date": "2022-09-30", + "Value": 1002, + "Series": "Electronics" + }, + { + "Date": "2022-10-09", + "Value": 1011, + "Series": "Electronics" + }, + { + "Date": "2022-10-19", + "Value": 1025, + "Series": "Electronics" + }, + { + "Date": "2022-10-28", + "Value": 1037, + "Series": "Electronics" + }, + { + "Date": "2022-11-06", + "Value": 1053, + "Series": "Electronics" + }, + { + "Date": "2022-11-15", + "Value": 1074, + "Series": "Electronics" + }, + { + "Date": "2022-11-24", + "Value": 1086, + "Series": "Electronics" + }, + { + "Date": "2022-12-03", + "Value": 1100, + "Series": "Electronics" + }, + { + "Date": "2022-12-12", + "Value": 1113, + "Series": "Electronics" + }, + { + "Date": "2022-12-21", + "Value": 1122, + "Series": "Electronics" + }, + { + "Date": "2020-01-01", + "Value": 215, + "Series": "Clothing" + }, + { + "Date": "2020-01-10", + "Value": 224, + "Series": "Clothing" + }, + { + "Date": "2020-01-19", + "Value": 240, + "Series": "Clothing" + }, + { + "Date": "2020-01-28", + "Value": 248, + "Series": "Clothing" + }, + { + "Date": "2020-02-06", + "Value": 251, + "Series": "Clothing" + }, + { + "Date": "2020-02-15", + "Value": 248, + "Series": "Clothing" + }, + { + "Date": "2020-02-24", + "Value": 244, + "Series": "Clothing" + }, + { + "Date": "2020-03-04", + "Value": 251, + "Series": "Clothing" + }, + { + "Date": "2020-03-14", + "Value": 259, + "Series": "Clothing" + }, + { + "Date": "2020-03-23", + "Value": 267, + "Series": "Clothing" + }, + { + "Date": "2020-04-01", + "Value": 272, + "Series": "Clothing" + }, + { + "Date": "2020-04-10", + "Value": 277, + "Series": "Clothing" + }, + { + "Date": "2020-04-19", + "Value": 275, + "Series": "Clothing" + }, + { + "Date": "2020-04-28", + "Value": 285, + "Series": "Clothing" + }, + { + "Date": "2020-05-07", + "Value": 295, + "Series": "Clothing" + }, + { + "Date": "2020-05-16", + "Value": 305, + "Series": "Clothing" + }, + { + "Date": "2020-05-26", + "Value": 316, + "Series": "Clothing" + }, + { + "Date": "2020-06-04", + "Value": 321, + "Series": "Clothing" + }, + { + "Date": "2020-06-13", + "Value": 322, + "Series": "Clothing" + }, + { + "Date": "2020-06-22", + "Value": 328, + "Series": "Clothing" + }, + { + "Date": "2020-07-01", + "Value": 339, + "Series": "Clothing" + }, + { + "Date": "2020-07-10", + "Value": 349, + "Series": "Clothing" + }, + { + "Date": "2020-07-19", + "Value": 355, + "Series": "Clothing" + }, + { + "Date": "2020-07-28", + "Value": 361, + "Series": "Clothing" + }, + { + "Date": "2020-08-07", + "Value": 369, + "Series": "Clothing" + }, + { + "Date": "2020-08-16", + "Value": 372, + "Series": "Clothing" + }, + { + "Date": "2020-08-25", + "Value": 377, + "Series": "Clothing" + }, + { + "Date": "2020-09-03", + "Value": 388, + "Series": "Clothing" + }, + { + "Date": "2020-09-12", + "Value": 405, + "Series": "Clothing" + }, + { + "Date": "2020-09-21", + "Value": 416, + "Series": "Clothing" + }, + { + "Date": "2020-09-30", + "Value": 420, + "Series": "Clothing" + }, + { + "Date": "2020-10-09", + "Value": 432, + "Series": "Clothing" + }, + { + "Date": "2020-10-19", + "Value": 436, + "Series": "Clothing" + }, + { + "Date": "2020-10-28", + "Value": 444, + "Series": "Clothing" + }, + { + "Date": "2020-11-06", + "Value": 453, + "Series": "Clothing" + }, + { + "Date": "2020-11-15", + "Value": 465, + "Series": "Clothing" + }, + { + "Date": "2020-11-24", + "Value": 469, + "Series": "Clothing" + }, + { + "Date": "2020-12-03", + "Value": 480, + "Series": "Clothing" + }, + { + "Date": "2020-12-12", + "Value": 493, + "Series": "Clothing" + }, + { + "Date": "2020-12-21", + "Value": 497, + "Series": "Clothing" + }, + { + "Date": "2020-12-31", + "Value": 506, + "Series": "Clothing" + }, + { + "Date": "2021-01-09", + "Value": 513, + "Series": "Clothing" + }, + { + "Date": "2021-01-18", + "Value": 527, + "Series": "Clothing" + }, + { + "Date": "2021-01-27", + "Value": 539, + "Series": "Clothing" + }, + { + "Date": "2021-02-05", + "Value": 557, + "Series": "Clothing" + }, + { + "Date": "2021-02-14", + "Value": 566, + "Series": "Clothing" + }, + { + "Date": "2021-02-23", + "Value": 567, + "Series": "Clothing" + }, + { + "Date": "2021-03-04", + "Value": 566, + "Series": "Clothing" + }, + { + "Date": "2021-03-14", + "Value": 564, + "Series": "Clothing" + }, + { + "Date": "2021-03-23", + "Value": 558, + "Series": "Clothing" + }, + { + "Date": "2021-04-01", + "Value": 552, + "Series": "Clothing" + }, + { + "Date": "2021-04-10", + "Value": 556, + "Series": "Clothing" + }, + { + "Date": "2021-04-19", + "Value": 559, + "Series": "Clothing" + }, + { + "Date": "2021-04-28", + "Value": 560, + "Series": "Clothing" + }, + { + "Date": "2021-05-07", + "Value": 559, + "Series": "Clothing" + }, + { + "Date": "2021-05-16", + "Value": 564, + "Series": "Clothing" + }, + { + "Date": "2021-05-26", + "Value": 573, + "Series": "Clothing" + }, + { + "Date": "2021-06-04", + "Value": 582, + "Series": "Clothing" + }, + { + "Date": "2021-06-13", + "Value": 592, + "Series": "Clothing" + }, + { + "Date": "2021-06-22", + "Value": 601, + "Series": "Clothing" + }, + { + "Date": "2021-07-01", + "Value": 605, + "Series": "Clothing" + }, + { + "Date": "2021-07-10", + "Value": 605, + "Series": "Clothing" + }, + { + "Date": "2021-07-19", + "Value": 601, + "Series": "Clothing" + }, + { + "Date": "2021-07-28", + "Value": 598, + "Series": "Clothing" + }, + { + "Date": "2021-08-07", + "Value": 594, + "Series": "Clothing" + }, + { + "Date": "2021-08-16", + "Value": 602, + "Series": "Clothing" + }, + { + "Date": "2021-08-25", + "Value": 602, + "Series": "Clothing" + }, + { + "Date": "2021-09-03", + "Value": 609, + "Series": "Clothing" + }, + { + "Date": "2021-09-12", + "Value": 616, + "Series": "Clothing" + }, + { + "Date": "2021-09-21", + "Value": 620, + "Series": "Clothing" + }, + { + "Date": "2021-09-30", + "Value": 629, + "Series": "Clothing" + }, + { + "Date": "2021-10-09", + "Value": 645, + "Series": "Clothing" + }, + { + "Date": "2021-10-19", + "Value": 665, + "Series": "Clothing" + }, + { + "Date": "2021-10-28", + "Value": 686, + "Series": "Clothing" + }, + { + "Date": "2021-11-06", + "Value": 696, + "Series": "Clothing" + }, + { + "Date": "2021-11-15", + "Value": 698, + "Series": "Clothing" + }, + { + "Date": "2021-11-24", + "Value": 695, + "Series": "Clothing" + }, + { + "Date": "2021-12-03", + "Value": 701, + "Series": "Clothing" + }, + { + "Date": "2021-12-12", + "Value": 705, + "Series": "Clothing" + }, + { + "Date": "2021-12-21", + "Value": 713, + "Series": "Clothing" + }, + { + "Date": "2021-12-31", + "Value": 727, + "Series": "Clothing" + }, + { + "Date": "2022-01-09", + "Value": 738, + "Series": "Clothing" + }, + { + "Date": "2022-01-18", + "Value": 742, + "Series": "Clothing" + }, + { + "Date": "2022-01-27", + "Value": 751, + "Series": "Clothing" + }, + { + "Date": "2022-02-05", + "Value": 763, + "Series": "Clothing" + }, + { + "Date": "2022-02-14", + "Value": 780, + "Series": "Clothing" + }, + { + "Date": "2022-02-23", + "Value": 791, + "Series": "Clothing" + }, + { + "Date": "2022-03-04", + "Value": 803, + "Series": "Clothing" + }, + { + "Date": "2022-03-14", + "Value": 818, + "Series": "Clothing" + }, + { + "Date": "2022-03-23", + "Value": 831, + "Series": "Clothing" + }, + { + "Date": "2022-04-01", + "Value": 846, + "Series": "Clothing" + }, + { + "Date": "2022-04-10", + "Value": 851, + "Series": "Clothing" + }, + { + "Date": "2022-04-19", + "Value": 851, + "Series": "Clothing" + }, + { + "Date": "2022-04-28", + "Value": 860, + "Series": "Clothing" + }, + { + "Date": "2022-05-07", + "Value": 875, + "Series": "Clothing" + }, + { + "Date": "2022-05-16", + "Value": 891, + "Series": "Clothing" + }, + { + "Date": "2022-05-26", + "Value": 910, + "Series": "Clothing" + }, + { + "Date": "2022-06-04", + "Value": 929, + "Series": "Clothing" + }, + { + "Date": "2022-06-13", + "Value": 939, + "Series": "Clothing" + }, + { + "Date": "2022-06-22", + "Value": 954, + "Series": "Clothing" + }, + { + "Date": "2022-07-01", + "Value": 970, + "Series": "Clothing" + }, + { + "Date": "2022-07-10", + "Value": 980, + "Series": "Clothing" + }, + { + "Date": "2022-07-19", + "Value": 983, + "Series": "Clothing" + }, + { + "Date": "2022-07-28", + "Value": 991, + "Series": "Clothing" + }, + { + "Date": "2022-08-07", + "Value": 992, + "Series": "Clothing" + }, + { + "Date": "2022-08-16", + "Value": 1001, + "Series": "Clothing" + }, + { + "Date": "2022-08-25", + "Value": 1003, + "Series": "Clothing" + }, + { + "Date": "2022-09-03", + "Value": 1000, + "Series": "Clothing" + }, + { + "Date": "2022-09-12", + "Value": 994, + "Series": "Clothing" + }, + { + "Date": "2022-09-21", + "Value": 987, + "Series": "Clothing" + }, + { + "Date": "2022-09-30", + "Value": 993, + "Series": "Clothing" + }, + { + "Date": "2022-10-09", + "Value": 998, + "Series": "Clothing" + }, + { + "Date": "2022-10-19", + "Value": 1011, + "Series": "Clothing" + }, + { + "Date": "2022-10-28", + "Value": 1021, + "Series": "Clothing" + }, + { + "Date": "2022-11-06", + "Value": 1029, + "Series": "Clothing" + }, + { + "Date": "2022-11-15", + "Value": 1033, + "Series": "Clothing" + }, + { + "Date": "2022-11-24", + "Value": 1043, + "Series": "Clothing" + }, + { + "Date": "2022-12-03", + "Value": 1054, + "Series": "Clothing" + }, + { + "Date": "2022-12-12", + "Value": 1065, + "Series": "Clothing" + }, + { + "Date": "2022-12-21", + "Value": 1080, + "Series": "Clothing" + }, + { + "Date": "2020-01-01", + "Value": 179, + "Series": "Food" + }, + { + "Date": "2020-01-10", + "Value": 167, + "Series": "Food" + }, + { + "Date": "2020-01-19", + "Value": 179, + "Series": "Food" + }, + { + "Date": "2020-01-28", + "Value": 177, + "Series": "Food" + }, + { + "Date": "2020-02-06", + "Value": 192, + "Series": "Food" + }, + { + "Date": "2020-02-15", + "Value": 201, + "Series": "Food" + }, + { + "Date": "2020-02-24", + "Value": 225, + "Series": "Food" + }, + { + "Date": "2020-03-04", + "Value": 256, + "Series": "Food" + }, + { + "Date": "2020-03-14", + "Value": 269, + "Series": "Food" + }, + { + "Date": "2020-03-23", + "Value": 281, + "Series": "Food" + }, + { + "Date": "2020-04-01", + "Value": 305, + "Series": "Food" + }, + { + "Date": "2020-04-10", + "Value": 334, + "Series": "Food" + }, + { + "Date": "2020-04-19", + "Value": 374, + "Series": "Food" + }, + { + "Date": "2020-04-28", + "Value": 405, + "Series": "Food" + }, + { + "Date": "2020-05-07", + "Value": 437, + "Series": "Food" + }, + { + "Date": "2020-05-16", + "Value": 464, + "Series": "Food" + }, + { + "Date": "2020-05-26", + "Value": 486, + "Series": "Food" + }, + { + "Date": "2020-06-04", + "Value": 496, + "Series": "Food" + }, + { + "Date": "2020-06-13", + "Value": 520, + "Series": "Food" + }, + { + "Date": "2020-06-22", + "Value": 525, + "Series": "Food" + }, + { + "Date": "2020-07-01", + "Value": 528, + "Series": "Food" + }, + { + "Date": "2020-07-10", + "Value": 534, + "Series": "Food" + }, + { + "Date": "2020-07-19", + "Value": 540, + "Series": "Food" + }, + { + "Date": "2020-07-28", + "Value": 537, + "Series": "Food" + }, + { + "Date": "2020-08-07", + "Value": 527, + "Series": "Food" + }, + { + "Date": "2020-08-16", + "Value": 539, + "Series": "Food" + }, + { + "Date": "2020-08-25", + "Value": 542, + "Series": "Food" + }, + { + "Date": "2020-09-03", + "Value": 561, + "Series": "Food" + }, + { + "Date": "2020-09-12", + "Value": 576, + "Series": "Food" + }, + { + "Date": "2020-09-21", + "Value": 584, + "Series": "Food" + }, + { + "Date": "2020-09-30", + "Value": 581, + "Series": "Food" + }, + { + "Date": "2020-10-09", + "Value": 566, + "Series": "Food" + }, + { + "Date": "2020-10-19", + "Value": 546, + "Series": "Food" + }, + { + "Date": "2020-10-28", + "Value": 555, + "Series": "Food" + }, + { + "Date": "2020-11-06", + "Value": 568, + "Series": "Food" + }, + { + "Date": "2020-11-15", + "Value": 563, + "Series": "Food" + }, + { + "Date": "2020-11-24", + "Value": 563, + "Series": "Food" + }, + { + "Date": "2020-12-03", + "Value": 562, + "Series": "Food" + }, + { + "Date": "2020-12-12", + "Value": 577, + "Series": "Food" + }, + { + "Date": "2020-12-21", + "Value": 595, + "Series": "Food" + }, + { + "Date": "2020-12-31", + "Value": 599, + "Series": "Food" + }, + { + "Date": "2021-01-09", + "Value": 606, + "Series": "Food" + }, + { + "Date": "2021-01-18", + "Value": 607, + "Series": "Food" + }, + { + "Date": "2021-01-27", + "Value": 624, + "Series": "Food" + }, + { + "Date": "2021-02-05", + "Value": 654, + "Series": "Food" + }, + { + "Date": "2021-02-14", + "Value": 689, + "Series": "Food" + }, + { + "Date": "2021-02-23", + "Value": 727, + "Series": "Food" + }, + { + "Date": "2021-03-04", + "Value": 736, + "Series": "Food" + }, + { + "Date": "2021-03-14", + "Value": 746, + "Series": "Food" + }, + { + "Date": "2021-03-23", + "Value": 750, + "Series": "Food" + }, + { + "Date": "2021-04-01", + "Value": 754, + "Series": "Food" + }, + { + "Date": "2021-04-10", + "Value": 767, + "Series": "Food" + }, + { + "Date": "2021-04-19", + "Value": 767, + "Series": "Food" + }, + { + "Date": "2021-04-28", + "Value": 781, + "Series": "Food" + }, + { + "Date": "2021-05-07", + "Value": 785, + "Series": "Food" + }, + { + "Date": "2021-05-16", + "Value": 789, + "Series": "Food" + }, + { + "Date": "2021-05-26", + "Value": 787, + "Series": "Food" + }, + { + "Date": "2021-06-04", + "Value": 772, + "Series": "Food" + }, + { + "Date": "2021-06-13", + "Value": 754, + "Series": "Food" + }, + { + "Date": "2021-06-22", + "Value": 757, + "Series": "Food" + }, + { + "Date": "2021-07-01", + "Value": 765, + "Series": "Food" + }, + { + "Date": "2021-07-10", + "Value": 763, + "Series": "Food" + }, + { + "Date": "2021-07-19", + "Value": 756, + "Series": "Food" + }, + { + "Date": "2021-07-28", + "Value": 746, + "Series": "Food" + }, + { + "Date": "2021-08-07", + "Value": 751, + "Series": "Food" + }, + { + "Date": "2021-08-16", + "Value": 759, + "Series": "Food" + }, + { + "Date": "2021-08-25", + "Value": 787, + "Series": "Food" + }, + { + "Date": "2021-09-03", + "Value": 814, + "Series": "Food" + }, + { + "Date": "2021-09-12", + "Value": 849, + "Series": "Food" + }, + { + "Date": "2021-09-21", + "Value": 869, + "Series": "Food" + }, + { + "Date": "2021-09-30", + "Value": 868, + "Series": "Food" + }, + { + "Date": "2021-10-09", + "Value": 867, + "Series": "Food" + }, + { + "Date": "2021-10-19", + "Value": 883, + "Series": "Food" + }, + { + "Date": "2021-10-28", + "Value": 892, + "Series": "Food" + }, + { + "Date": "2021-11-06", + "Value": 895, + "Series": "Food" + }, + { + "Date": "2021-11-15", + "Value": 900, + "Series": "Food" + }, + { + "Date": "2021-11-24", + "Value": 898, + "Series": "Food" + }, + { + "Date": "2021-12-03", + "Value": 918, + "Series": "Food" + }, + { + "Date": "2021-12-12", + "Value": 946, + "Series": "Food" + }, + { + "Date": "2021-12-21", + "Value": 959, + "Series": "Food" + }, + { + "Date": "2021-12-31", + "Value": 989, + "Series": "Food" + }, + { + "Date": "2022-01-09", + "Value": 1007, + "Series": "Food" + }, + { + "Date": "2022-01-18", + "Value": 1012, + "Series": "Food" + }, + { + "Date": "2022-01-27", + "Value": 1007, + "Series": "Food" + }, + { + "Date": "2022-02-05", + "Value": 1006, + "Series": "Food" + }, + { + "Date": "2022-02-14", + "Value": 1005, + "Series": "Food" + }, + { + "Date": "2022-02-23", + "Value": 1026, + "Series": "Food" + }, + { + "Date": "2022-03-04", + "Value": 1036, + "Series": "Food" + }, + { + "Date": "2022-03-14", + "Value": 1052, + "Series": "Food" + }, + { + "Date": "2022-03-23", + "Value": 1055, + "Series": "Food" + }, + { + "Date": "2022-04-01", + "Value": 1063, + "Series": "Food" + }, + { + "Date": "2022-04-10", + "Value": 1059, + "Series": "Food" + }, + { + "Date": "2022-04-19", + "Value": 1066, + "Series": "Food" + }, + { + "Date": "2022-04-28", + "Value": 1093, + "Series": "Food" + }, + { + "Date": "2022-05-07", + "Value": 1121, + "Series": "Food" + }, + { + "Date": "2022-05-16", + "Value": 1124, + "Series": "Food" + }, + { + "Date": "2022-05-26", + "Value": 1123, + "Series": "Food" + }, + { + "Date": "2022-06-04", + "Value": 1136, + "Series": "Food" + }, + { + "Date": "2022-06-13", + "Value": 1151, + "Series": "Food" + }, + { + "Date": "2022-06-22", + "Value": 1164, + "Series": "Food" + }, + { + "Date": "2022-07-01", + "Value": 1184, + "Series": "Food" + }, + { + "Date": "2022-07-10", + "Value": 1187, + "Series": "Food" + }, + { + "Date": "2022-07-19", + "Value": 1177, + "Series": "Food" + }, + { + "Date": "2022-07-28", + "Value": 1184, + "Series": "Food" + }, + { + "Date": "2022-08-07", + "Value": 1188, + "Series": "Food" + }, + { + "Date": "2022-08-16", + "Value": 1188, + "Series": "Food" + }, + { + "Date": "2022-08-25", + "Value": 1210, + "Series": "Food" + }, + { + "Date": "2022-09-03", + "Value": 1229, + "Series": "Food" + }, + { + "Date": "2022-09-12", + "Value": 1239, + "Series": "Food" + }, + { + "Date": "2022-09-21", + "Value": 1260, + "Series": "Food" + }, + { + "Date": "2022-09-30", + "Value": 1261, + "Series": "Food" + }, + { + "Date": "2022-10-09", + "Value": 1273, + "Series": "Food" + }, + { + "Date": "2022-10-19", + "Value": 1287, + "Series": "Food" + }, + { + "Date": "2022-10-28", + "Value": 1285, + "Series": "Food" + }, + { + "Date": "2022-11-06", + "Value": 1303, + "Series": "Food" + }, + { + "Date": "2022-11-15", + "Value": 1336, + "Series": "Food" + }, + { + "Date": "2022-11-24", + "Value": 1372, + "Series": "Food" + }, + { + "Date": "2022-12-03", + "Value": 1406, + "Series": "Food" + }, + { + "Date": "2022-12-12", + "Value": 1430, + "Series": "Food" + }, + { + "Date": "2022-12-21", + "Value": 1437, + "Series": "Food" + }, + { + "Date": "2020-01-01", + "Value": 97, + "Series": "Books" + }, + { + "Date": "2020-01-10", + "Value": 85, + "Series": "Books" + }, + { + "Date": "2020-01-19", + "Value": 86, + "Series": "Books" + }, + { + "Date": "2020-01-28", + "Value": 97, + "Series": "Books" + }, + { + "Date": "2020-02-06", + "Value": 119, + "Series": "Books" + }, + { + "Date": "2020-02-15", + "Value": 136, + "Series": "Books" + }, + { + "Date": "2020-02-24", + "Value": 142, + "Series": "Books" + }, + { + "Date": "2020-03-04", + "Value": 157, + "Series": "Books" + }, + { + "Date": "2020-03-14", + "Value": 159, + "Series": "Books" + }, + { + "Date": "2020-03-23", + "Value": 152, + "Series": "Books" + }, + { + "Date": "2020-04-01", + "Value": 141, + "Series": "Books" + }, + { + "Date": "2020-04-10", + "Value": 128, + "Series": "Books" + }, + { + "Date": "2020-04-19", + "Value": 117, + "Series": "Books" + }, + { + "Date": "2020-04-28", + "Value": 125, + "Series": "Books" + }, + { + "Date": "2020-05-07", + "Value": 126, + "Series": "Books" + }, + { + "Date": "2020-05-16", + "Value": 120, + "Series": "Books" + }, + { + "Date": "2020-05-26", + "Value": 105, + "Series": "Books" + }, + { + "Date": "2020-06-04", + "Value": 90, + "Series": "Books" + }, + { + "Date": "2020-06-13", + "Value": 73, + "Series": "Books" + }, + { + "Date": "2020-06-22", + "Value": 70, + "Series": "Books" + }, + { + "Date": "2020-07-01", + "Value": 76, + "Series": "Books" + }, + { + "Date": "2020-07-10", + "Value": 78, + "Series": "Books" + }, + { + "Date": "2020-07-19", + "Value": 90, + "Series": "Books" + }, + { + "Date": "2020-07-28", + "Value": 88, + "Series": "Books" + }, + { + "Date": "2020-08-07", + "Value": 89, + "Series": "Books" + }, + { + "Date": "2020-08-16", + "Value": 104, + "Series": "Books" + }, + { + "Date": "2020-08-25", + "Value": 118, + "Series": "Books" + }, + { + "Date": "2020-09-03", + "Value": 131, + "Series": "Books" + }, + { + "Date": "2020-09-12", + "Value": 140, + "Series": "Books" + }, + { + "Date": "2020-09-21", + "Value": 143, + "Series": "Books" + }, + { + "Date": "2020-09-30", + "Value": 157, + "Series": "Books" + }, + { + "Date": "2020-10-09", + "Value": 169, + "Series": "Books" + }, + { + "Date": "2020-10-19", + "Value": 180, + "Series": "Books" + }, + { + "Date": "2020-10-28", + "Value": 189, + "Series": "Books" + }, + { + "Date": "2020-11-06", + "Value": 185, + "Series": "Books" + }, + { + "Date": "2020-11-15", + "Value": 191, + "Series": "Books" + }, + { + "Date": "2020-11-24", + "Value": 183, + "Series": "Books" + }, + { + "Date": "2020-12-03", + "Value": 189, + "Series": "Books" + }, + { + "Date": "2020-12-12", + "Value": 191, + "Series": "Books" + }, + { + "Date": "2020-12-21", + "Value": 182, + "Series": "Books" + }, + { + "Date": "2020-12-31", + "Value": 167, + "Series": "Books" + }, + { + "Date": "2021-01-09", + "Value": 158, + "Series": "Books" + }, + { + "Date": "2021-01-18", + "Value": 159, + "Series": "Books" + }, + { + "Date": "2021-01-27", + "Value": 174, + "Series": "Books" + }, + { + "Date": "2021-02-05", + "Value": 181, + "Series": "Books" + }, + { + "Date": "2021-02-14", + "Value": 201, + "Series": "Books" + }, + { + "Date": "2021-02-23", + "Value": 228, + "Series": "Books" + }, + { + "Date": "2021-03-04", + "Value": 241, + "Series": "Books" + }, + { + "Date": "2021-03-14", + "Value": 251, + "Series": "Books" + }, + { + "Date": "2021-03-23", + "Value": 245, + "Series": "Books" + }, + { + "Date": "2021-04-01", + "Value": 249, + "Series": "Books" + }, + { + "Date": "2021-04-10", + "Value": 267, + "Series": "Books" + }, + { + "Date": "2021-04-19", + "Value": 265, + "Series": "Books" + }, + { + "Date": "2021-04-28", + "Value": 277, + "Series": "Books" + }, + { + "Date": "2021-05-07", + "Value": 283, + "Series": "Books" + }, + { + "Date": "2021-05-16", + "Value": 276, + "Series": "Books" + }, + { + "Date": "2021-05-26", + "Value": 285, + "Series": "Books" + }, + { + "Date": "2021-06-04", + "Value": 298, + "Series": "Books" + }, + { + "Date": "2021-06-13", + "Value": 313, + "Series": "Books" + }, + { + "Date": "2021-06-22", + "Value": 334, + "Series": "Books" + }, + { + "Date": "2021-07-01", + "Value": 357, + "Series": "Books" + }, + { + "Date": "2021-07-10", + "Value": 371, + "Series": "Books" + }, + { + "Date": "2021-07-19", + "Value": 380, + "Series": "Books" + }, + { + "Date": "2021-07-28", + "Value": 394, + "Series": "Books" + }, + { + "Date": "2021-08-07", + "Value": 416, + "Series": "Books" + }, + { + "Date": "2021-08-16", + "Value": 435, + "Series": "Books" + }, + { + "Date": "2021-08-25", + "Value": 436, + "Series": "Books" + }, + { + "Date": "2021-09-03", + "Value": 447, + "Series": "Books" + }, + { + "Date": "2021-09-12", + "Value": 465, + "Series": "Books" + }, + { + "Date": "2021-09-21", + "Value": 485, + "Series": "Books" + }, + { + "Date": "2021-09-30", + "Value": 503, + "Series": "Books" + }, + { + "Date": "2021-10-09", + "Value": 529, + "Series": "Books" + }, + { + "Date": "2021-10-19", + "Value": 540, + "Series": "Books" + }, + { + "Date": "2021-10-28", + "Value": 543, + "Series": "Books" + }, + { + "Date": "2021-11-06", + "Value": 536, + "Series": "Books" + }, + { + "Date": "2021-11-15", + "Value": 529, + "Series": "Books" + }, + { + "Date": "2021-11-24", + "Value": 536, + "Series": "Books" + }, + { + "Date": "2021-12-03", + "Value": 551, + "Series": "Books" + }, + { + "Date": "2021-12-12", + "Value": 550, + "Series": "Books" + }, + { + "Date": "2021-12-21", + "Value": 546, + "Series": "Books" + }, + { + "Date": "2021-12-31", + "Value": 547, + "Series": "Books" + }, + { + "Date": "2022-01-09", + "Value": 537, + "Series": "Books" + }, + { + "Date": "2022-01-18", + "Value": 520, + "Series": "Books" + }, + { + "Date": "2022-01-27", + "Value": 512, + "Series": "Books" + }, + { + "Date": "2022-02-05", + "Value": 510, + "Series": "Books" + }, + { + "Date": "2022-02-14", + "Value": 511, + "Series": "Books" + }, + { + "Date": "2022-02-23", + "Value": 511, + "Series": "Books" + }, + { + "Date": "2022-03-04", + "Value": 519, + "Series": "Books" + }, + { + "Date": "2022-03-14", + "Value": 529, + "Series": "Books" + }, + { + "Date": "2022-03-23", + "Value": 522, + "Series": "Books" + }, + { + "Date": "2022-04-01", + "Value": 530, + "Series": "Books" + }, + { + "Date": "2022-04-10", + "Value": 550, + "Series": "Books" + }, + { + "Date": "2022-04-19", + "Value": 567, + "Series": "Books" + }, + { + "Date": "2022-04-28", + "Value": 593, + "Series": "Books" + }, + { + "Date": "2022-05-07", + "Value": 606, + "Series": "Books" + }, + { + "Date": "2022-05-16", + "Value": 624, + "Series": "Books" + }, + { + "Date": "2022-05-26", + "Value": 629, + "Series": "Books" + }, + { + "Date": "2022-06-04", + "Value": 622, + "Series": "Books" + }, + { + "Date": "2022-06-13", + "Value": 632, + "Series": "Books" + }, + { + "Date": "2022-06-22", + "Value": 646, + "Series": "Books" + }, + { + "Date": "2022-07-01", + "Value": 648, + "Series": "Books" + }, + { + "Date": "2022-07-10", + "Value": 658, + "Series": "Books" + }, + { + "Date": "2022-07-19", + "Value": 672, + "Series": "Books" + }, + { + "Date": "2022-07-28", + "Value": 693, + "Series": "Books" + }, + { + "Date": "2022-08-07", + "Value": 719, + "Series": "Books" + }, + { + "Date": "2022-08-16", + "Value": 742, + "Series": "Books" + }, + { + "Date": "2022-08-25", + "Value": 759, + "Series": "Books" + }, + { + "Date": "2022-09-03", + "Value": 775, + "Series": "Books" + }, + { + "Date": "2022-09-12", + "Value": 798, + "Series": "Books" + }, + { + "Date": "2022-09-21", + "Value": 819, + "Series": "Books" + }, + { + "Date": "2022-09-30", + "Value": 826, + "Series": "Books" + }, + { + "Date": "2022-10-09", + "Value": 842, + "Series": "Books" + }, + { + "Date": "2022-10-19", + "Value": 865, + "Series": "Books" + }, + { + "Date": "2022-10-28", + "Value": 885, + "Series": "Books" + }, + { + "Date": "2022-11-06", + "Value": 895, + "Series": "Books" + }, + { + "Date": "2022-11-15", + "Value": 915, + "Series": "Books" + }, + { + "Date": "2022-11-24", + "Value": 918, + "Series": "Books" + }, + { + "Date": "2022-12-03", + "Value": 928, + "Series": "Books" + }, + { + "Date": "2022-12-12", + "Value": 937, + "Series": "Books" + }, + { + "Date": "2022-12-21", + "Value": 939, + "Series": "Books" + }, + { + "Date": "2020-01-01", + "Value": 183, + "Series": "Sports" + }, + { + "Date": "2020-01-10", + "Value": 189, + "Series": "Sports" + }, + { + "Date": "2020-01-19", + "Value": 185, + "Series": "Sports" + }, + { + "Date": "2020-01-28", + "Value": 183, + "Series": "Sports" + }, + { + "Date": "2020-02-06", + "Value": 182, + "Series": "Sports" + }, + { + "Date": "2020-02-15", + "Value": 193, + "Series": "Sports" + }, + { + "Date": "2020-02-24", + "Value": 198, + "Series": "Sports" + }, + { + "Date": "2020-03-04", + "Value": 195, + "Series": "Sports" + }, + { + "Date": "2020-03-14", + "Value": 186, + "Series": "Sports" + }, + { + "Date": "2020-03-23", + "Value": 178, + "Series": "Sports" + }, + { + "Date": "2020-04-01", + "Value": 168, + "Series": "Sports" + }, + { + "Date": "2020-04-10", + "Value": 156, + "Series": "Sports" + }, + { + "Date": "2020-04-19", + "Value": 158, + "Series": "Sports" + }, + { + "Date": "2020-04-28", + "Value": 171, + "Series": "Sports" + }, + { + "Date": "2020-05-07", + "Value": 177, + "Series": "Sports" + }, + { + "Date": "2020-05-16", + "Value": 185, + "Series": "Sports" + }, + { + "Date": "2020-05-26", + "Value": 196, + "Series": "Sports" + }, + { + "Date": "2020-06-04", + "Value": 199, + "Series": "Sports" + }, + { + "Date": "2020-06-13", + "Value": 202, + "Series": "Sports" + }, + { + "Date": "2020-06-22", + "Value": 210, + "Series": "Sports" + }, + { + "Date": "2020-07-01", + "Value": 223, + "Series": "Sports" + }, + { + "Date": "2020-07-10", + "Value": 243, + "Series": "Sports" + }, + { + "Date": "2020-07-19", + "Value": 261, + "Series": "Sports" + }, + { + "Date": "2020-07-28", + "Value": 274, + "Series": "Sports" + }, + { + "Date": "2020-08-07", + "Value": 278, + "Series": "Sports" + }, + { + "Date": "2020-08-16", + "Value": 274, + "Series": "Sports" + }, + { + "Date": "2020-08-25", + "Value": 280, + "Series": "Sports" + }, + { + "Date": "2020-09-03", + "Value": 276, + "Series": "Sports" + }, + { + "Date": "2020-09-12", + "Value": 272, + "Series": "Sports" + }, + { + "Date": "2020-09-21", + "Value": 276, + "Series": "Sports" + }, + { + "Date": "2020-09-30", + "Value": 287, + "Series": "Sports" + }, + { + "Date": "2020-10-09", + "Value": 305, + "Series": "Sports" + }, + { + "Date": "2020-10-19", + "Value": 319, + "Series": "Sports" + }, + { + "Date": "2020-10-28", + "Value": 325, + "Series": "Sports" + }, + { + "Date": "2020-11-06", + "Value": 333, + "Series": "Sports" + }, + { + "Date": "2020-11-15", + "Value": 338, + "Series": "Sports" + }, + { + "Date": "2020-11-24", + "Value": 341, + "Series": "Sports" + }, + { + "Date": "2020-12-03", + "Value": 344, + "Series": "Sports" + }, + { + "Date": "2020-12-12", + "Value": 348, + "Series": "Sports" + }, + { + "Date": "2020-12-21", + "Value": 347, + "Series": "Sports" + }, + { + "Date": "2020-12-31", + "Value": 357, + "Series": "Sports" + }, + { + "Date": "2021-01-09", + "Value": 371, + "Series": "Sports" + }, + { + "Date": "2021-01-18", + "Value": 390, + "Series": "Sports" + }, + { + "Date": "2021-01-27", + "Value": 397, + "Series": "Sports" + }, + { + "Date": "2021-02-05", + "Value": 406, + "Series": "Sports" + }, + { + "Date": "2021-02-14", + "Value": 418, + "Series": "Sports" + }, + { + "Date": "2021-02-23", + "Value": 422, + "Series": "Sports" + }, + { + "Date": "2021-03-04", + "Value": 425, + "Series": "Sports" + }, + { + "Date": "2021-03-14", + "Value": 435, + "Series": "Sports" + }, + { + "Date": "2021-03-23", + "Value": 445, + "Series": "Sports" + }, + { + "Date": "2021-04-01", + "Value": 450, + "Series": "Sports" + }, + { + "Date": "2021-04-10", + "Value": 456, + "Series": "Sports" + }, + { + "Date": "2021-04-19", + "Value": 458, + "Series": "Sports" + }, + { + "Date": "2021-04-28", + "Value": 471, + "Series": "Sports" + }, + { + "Date": "2021-05-07", + "Value": 485, + "Series": "Sports" + }, + { + "Date": "2021-05-16", + "Value": 492, + "Series": "Sports" + }, + { + "Date": "2021-05-26", + "Value": 502, + "Series": "Sports" + }, + { + "Date": "2021-06-04", + "Value": 512, + "Series": "Sports" + }, + { + "Date": "2021-06-13", + "Value": 511, + "Series": "Sports" + }, + { + "Date": "2021-06-22", + "Value": 509, + "Series": "Sports" + }, + { + "Date": "2021-07-01", + "Value": 506, + "Series": "Sports" + }, + { + "Date": "2021-07-10", + "Value": 510, + "Series": "Sports" + }, + { + "Date": "2021-07-19", + "Value": 516, + "Series": "Sports" + }, + { + "Date": "2021-07-28", + "Value": 532, + "Series": "Sports" + }, + { + "Date": "2021-08-07", + "Value": 545, + "Series": "Sports" + }, + { + "Date": "2021-08-16", + "Value": 558, + "Series": "Sports" + }, + { + "Date": "2021-08-25", + "Value": 569, + "Series": "Sports" + }, + { + "Date": "2021-09-03", + "Value": 579, + "Series": "Sports" + }, + { + "Date": "2021-09-12", + "Value": 592, + "Series": "Sports" + }, + { + "Date": "2021-09-21", + "Value": 600, + "Series": "Sports" + }, + { + "Date": "2021-09-30", + "Value": 597, + "Series": "Sports" + }, + { + "Date": "2021-10-09", + "Value": 595, + "Series": "Sports" + }, + { + "Date": "2021-10-19", + "Value": 603, + "Series": "Sports" + }, + { + "Date": "2021-10-28", + "Value": 607, + "Series": "Sports" + }, + { + "Date": "2021-11-06", + "Value": 608, + "Series": "Sports" + }, + { + "Date": "2021-11-15", + "Value": 605, + "Series": "Sports" + }, + { + "Date": "2021-11-24", + "Value": 604, + "Series": "Sports" + }, + { + "Date": "2021-12-03", + "Value": 613, + "Series": "Sports" + }, + { + "Date": "2021-12-12", + "Value": 611, + "Series": "Sports" + }, + { + "Date": "2021-12-21", + "Value": 612, + "Series": "Sports" + }, + { + "Date": "2021-12-31", + "Value": 606, + "Series": "Sports" + }, + { + "Date": "2022-01-09", + "Value": 595, + "Series": "Sports" + }, + { + "Date": "2022-01-18", + "Value": 586, + "Series": "Sports" + }, + { + "Date": "2022-01-27", + "Value": 578, + "Series": "Sports" + }, + { + "Date": "2022-02-05", + "Value": 570, + "Series": "Sports" + }, + { + "Date": "2022-02-14", + "Value": 576, + "Series": "Sports" + }, + { + "Date": "2022-02-23", + "Value": 584, + "Series": "Sports" + }, + { + "Date": "2022-03-04", + "Value": 585, + "Series": "Sports" + }, + { + "Date": "2022-03-14", + "Value": 585, + "Series": "Sports" + }, + { + "Date": "2022-03-23", + "Value": 597, + "Series": "Sports" + }, + { + "Date": "2022-04-01", + "Value": 603, + "Series": "Sports" + }, + { + "Date": "2022-04-10", + "Value": 614, + "Series": "Sports" + }, + { + "Date": "2022-04-19", + "Value": 615, + "Series": "Sports" + }, + { + "Date": "2022-04-28", + "Value": 621, + "Series": "Sports" + }, + { + "Date": "2022-05-07", + "Value": 623, + "Series": "Sports" + }, + { + "Date": "2022-05-16", + "Value": 632, + "Series": "Sports" + }, + { + "Date": "2022-05-26", + "Value": 638, + "Series": "Sports" + }, + { + "Date": "2022-06-04", + "Value": 647, + "Series": "Sports" + }, + { + "Date": "2022-06-13", + "Value": 655, + "Series": "Sports" + }, + { + "Date": "2022-06-22", + "Value": 657, + "Series": "Sports" + }, + { + "Date": "2022-07-01", + "Value": 659, + "Series": "Sports" + }, + { + "Date": "2022-07-10", + "Value": 663, + "Series": "Sports" + }, + { + "Date": "2022-07-19", + "Value": 676, + "Series": "Sports" + }, + { + "Date": "2022-07-28", + "Value": 676, + "Series": "Sports" + }, + { + "Date": "2022-08-07", + "Value": 677, + "Series": "Sports" + }, + { + "Date": "2022-08-16", + "Value": 676, + "Series": "Sports" + }, + { + "Date": "2022-08-25", + "Value": 680, + "Series": "Sports" + }, + { + "Date": "2022-09-03", + "Value": 678, + "Series": "Sports" + }, + { + "Date": "2022-09-12", + "Value": 677, + "Series": "Sports" + }, + { + "Date": "2022-09-21", + "Value": 681, + "Series": "Sports" + }, + { + "Date": "2022-09-30", + "Value": 695, + "Series": "Sports" + }, + { + "Date": "2022-10-09", + "Value": 713, + "Series": "Sports" + }, + { + "Date": "2022-10-19", + "Value": 716, + "Series": "Sports" + }, + { + "Date": "2022-10-28", + "Value": 718, + "Series": "Sports" + }, + { + "Date": "2022-11-06", + "Value": 728, + "Series": "Sports" + }, + { + "Date": "2022-11-15", + "Value": 740, + "Series": "Sports" + }, + { + "Date": "2022-11-24", + "Value": 743, + "Series": "Sports" + }, + { + "Date": "2022-12-03", + "Value": 738, + "Series": "Sports" + }, + { + "Date": "2022-12-12", + "Value": 738, + "Series": "Sports" + }, + { + "Date": "2022-12-21", + "Value": 748, + "Series": "Sports" + }, + { + "Date": "2020-01-01", + "Value": 52, + "Series": "Home" + }, + { + "Date": "2020-01-10", + "Value": 50, + "Series": "Home" + }, + { + "Date": "2020-01-19", + "Value": 40, + "Series": "Home" + }, + { + "Date": "2020-01-28", + "Value": 46, + "Series": "Home" + }, + { + "Date": "2020-02-06", + "Value": 40, + "Series": "Home" + }, + { + "Date": "2020-02-15", + "Value": 50, + "Series": "Home" + }, + { + "Date": "2020-02-24", + "Value": 52, + "Series": "Home" + }, + { + "Date": "2020-03-04", + "Value": 71, + "Series": "Home" + }, + { + "Date": "2020-03-14", + "Value": 93, + "Series": "Home" + }, + { + "Date": "2020-03-23", + "Value": 103, + "Series": "Home" + }, + { + "Date": "2020-04-01", + "Value": 126, + "Series": "Home" + }, + { + "Date": "2020-04-10", + "Value": 153, + "Series": "Home" + }, + { + "Date": "2020-04-19", + "Value": 171, + "Series": "Home" + }, + { + "Date": "2020-04-28", + "Value": 200, + "Series": "Home" + }, + { + "Date": "2020-05-07", + "Value": 208, + "Series": "Home" + }, + { + "Date": "2020-05-16", + "Value": 203, + "Series": "Home" + }, + { + "Date": "2020-05-26", + "Value": 195, + "Series": "Home" + }, + { + "Date": "2020-06-04", + "Value": 189, + "Series": "Home" + }, + { + "Date": "2020-06-13", + "Value": 183, + "Series": "Home" + }, + { + "Date": "2020-06-22", + "Value": 182, + "Series": "Home" + }, + { + "Date": "2020-07-01", + "Value": 180, + "Series": "Home" + }, + { + "Date": "2020-07-10", + "Value": 170, + "Series": "Home" + }, + { + "Date": "2020-07-19", + "Value": 158, + "Series": "Home" + }, + { + "Date": "2020-07-28", + "Value": 152, + "Series": "Home" + }, + { + "Date": "2020-08-07", + "Value": 164, + "Series": "Home" + }, + { + "Date": "2020-08-16", + "Value": 165, + "Series": "Home" + }, + { + "Date": "2020-08-25", + "Value": 166, + "Series": "Home" + }, + { + "Date": "2020-09-03", + "Value": 155, + "Series": "Home" + }, + { + "Date": "2020-09-12", + "Value": 145, + "Series": "Home" + }, + { + "Date": "2020-09-21", + "Value": 137, + "Series": "Home" + }, + { + "Date": "2020-09-30", + "Value": 125, + "Series": "Home" + }, + { + "Date": "2020-10-09", + "Value": 126, + "Series": "Home" + }, + { + "Date": "2020-10-19", + "Value": 122, + "Series": "Home" + }, + { + "Date": "2020-10-28", + "Value": 111, + "Series": "Home" + }, + { + "Date": "2020-11-06", + "Value": 121, + "Series": "Home" + }, + { + "Date": "2020-11-15", + "Value": 129, + "Series": "Home" + }, + { + "Date": "2020-11-24", + "Value": 132, + "Series": "Home" + }, + { + "Date": "2020-12-03", + "Value": 136, + "Series": "Home" + }, + { + "Date": "2020-12-12", + "Value": 144, + "Series": "Home" + }, + { + "Date": "2020-12-21", + "Value": 147, + "Series": "Home" + }, + { + "Date": "2020-12-31", + "Value": 137, + "Series": "Home" + }, + { + "Date": "2021-01-09", + "Value": 123, + "Series": "Home" + }, + { + "Date": "2021-01-18", + "Value": 108, + "Series": "Home" + }, + { + "Date": "2021-01-27", + "Value": 114, + "Series": "Home" + }, + { + "Date": "2021-02-05", + "Value": 118, + "Series": "Home" + }, + { + "Date": "2021-02-14", + "Value": 118, + "Series": "Home" + }, + { + "Date": "2021-02-23", + "Value": 110, + "Series": "Home" + }, + { + "Date": "2021-03-04", + "Value": 123, + "Series": "Home" + }, + { + "Date": "2021-03-14", + "Value": 142, + "Series": "Home" + }, + { + "Date": "2021-03-23", + "Value": 149, + "Series": "Home" + }, + { + "Date": "2021-04-01", + "Value": 151, + "Series": "Home" + }, + { + "Date": "2021-04-10", + "Value": 148, + "Series": "Home" + }, + { + "Date": "2021-04-19", + "Value": 147, + "Series": "Home" + }, + { + "Date": "2021-04-28", + "Value": 162, + "Series": "Home" + }, + { + "Date": "2021-05-07", + "Value": 189, + "Series": "Home" + }, + { + "Date": "2021-05-16", + "Value": 220, + "Series": "Home" + }, + { + "Date": "2021-05-26", + "Value": 249, + "Series": "Home" + }, + { + "Date": "2021-06-04", + "Value": 273, + "Series": "Home" + }, + { + "Date": "2021-06-13", + "Value": 282, + "Series": "Home" + }, + { + "Date": "2021-06-22", + "Value": 279, + "Series": "Home" + }, + { + "Date": "2021-07-01", + "Value": 273, + "Series": "Home" + }, + { + "Date": "2021-07-10", + "Value": 260, + "Series": "Home" + }, + { + "Date": "2021-07-19", + "Value": 264, + "Series": "Home" + }, + { + "Date": "2021-07-28", + "Value": 274, + "Series": "Home" + }, + { + "Date": "2021-08-07", + "Value": 274, + "Series": "Home" + }, + { + "Date": "2021-08-16", + "Value": 273, + "Series": "Home" + }, + { + "Date": "2021-08-25", + "Value": 291, + "Series": "Home" + }, + { + "Date": "2021-09-03", + "Value": 296, + "Series": "Home" + }, + { + "Date": "2021-09-12", + "Value": 314, + "Series": "Home" + }, + { + "Date": "2021-09-21", + "Value": 322, + "Series": "Home" + }, + { + "Date": "2021-09-30", + "Value": 343, + "Series": "Home" + }, + { + "Date": "2021-10-09", + "Value": 347, + "Series": "Home" + }, + { + "Date": "2021-10-19", + "Value": 358, + "Series": "Home" + }, + { + "Date": "2021-10-28", + "Value": 383, + "Series": "Home" + }, + { + "Date": "2021-11-06", + "Value": 387, + "Series": "Home" + }, + { + "Date": "2021-11-15", + "Value": 392, + "Series": "Home" + }, + { + "Date": "2021-11-24", + "Value": 409, + "Series": "Home" + }, + { + "Date": "2021-12-03", + "Value": 423, + "Series": "Home" + }, + { + "Date": "2021-12-12", + "Value": 432, + "Series": "Home" + }, + { + "Date": "2021-12-21", + "Value": 435, + "Series": "Home" + }, + { + "Date": "2021-12-31", + "Value": 443, + "Series": "Home" + }, + { + "Date": "2022-01-09", + "Value": 454, + "Series": "Home" + }, + { + "Date": "2022-01-18", + "Value": 475, + "Series": "Home" + }, + { + "Date": "2022-01-27", + "Value": 490, + "Series": "Home" + }, + { + "Date": "2022-02-05", + "Value": 499, + "Series": "Home" + }, + { + "Date": "2022-02-14", + "Value": 513, + "Series": "Home" + }, + { + "Date": "2022-02-23", + "Value": 514, + "Series": "Home" + }, + { + "Date": "2022-03-04", + "Value": 508, + "Series": "Home" + }, + { + "Date": "2022-03-14", + "Value": 501, + "Series": "Home" + }, + { + "Date": "2022-03-23", + "Value": 505, + "Series": "Home" + }, + { + "Date": "2022-04-01", + "Value": 499, + "Series": "Home" + }, + { + "Date": "2022-04-10", + "Value": 503, + "Series": "Home" + }, + { + "Date": "2022-04-19", + "Value": 506, + "Series": "Home" + }, + { + "Date": "2022-04-28", + "Value": 502, + "Series": "Home" + }, + { + "Date": "2022-05-07", + "Value": 498, + "Series": "Home" + }, + { + "Date": "2022-05-16", + "Value": 487, + "Series": "Home" + }, + { + "Date": "2022-05-26", + "Value": 479, + "Series": "Home" + }, + { + "Date": "2022-06-04", + "Value": 479, + "Series": "Home" + }, + { + "Date": "2022-06-13", + "Value": 479, + "Series": "Home" + }, + { + "Date": "2022-06-22", + "Value": 481, + "Series": "Home" + }, + { + "Date": "2022-07-01", + "Value": 491, + "Series": "Home" + }, + { + "Date": "2022-07-10", + "Value": 491, + "Series": "Home" + }, + { + "Date": "2022-07-19", + "Value": 498, + "Series": "Home" + }, + { + "Date": "2022-07-28", + "Value": 511, + "Series": "Home" + }, + { + "Date": "2022-08-07", + "Value": 517, + "Series": "Home" + }, + { + "Date": "2022-08-16", + "Value": 512, + "Series": "Home" + }, + { + "Date": "2022-08-25", + "Value": 523, + "Series": "Home" + }, + { + "Date": "2022-09-03", + "Value": 536, + "Series": "Home" + }, + { + "Date": "2022-09-12", + "Value": 562, + "Series": "Home" + }, + { + "Date": "2022-09-21", + "Value": 596, + "Series": "Home" + }, + { + "Date": "2022-09-30", + "Value": 628, + "Series": "Home" + }, + { + "Date": "2022-10-09", + "Value": 657, + "Series": "Home" + }, + { + "Date": "2022-10-19", + "Value": 671, + "Series": "Home" + }, + { + "Date": "2022-10-28", + "Value": 687, + "Series": "Home" + }, + { + "Date": "2022-11-06", + "Value": 695, + "Series": "Home" + }, + { + "Date": "2022-11-15", + "Value": 711, + "Series": "Home" + }, + { + "Date": "2022-11-24", + "Value": 721, + "Series": "Home" + }, + { + "Date": "2022-12-03", + "Value": 740, + "Series": "Home" + }, + { + "Date": "2022-12-12", + "Value": 759, + "Series": "Home" + }, + { + "Date": "2022-12-21", + "Value": 775, + "Series": "Home" + }, + { + "Date": "2020-01-01", + "Value": 217, + "Series": "Garden" + }, + { + "Date": "2020-01-10", + "Value": 214, + "Series": "Garden" + }, + { + "Date": "2020-01-19", + "Value": 213, + "Series": "Garden" + }, + { + "Date": "2020-01-28", + "Value": 229, + "Series": "Garden" + }, + { + "Date": "2020-02-06", + "Value": 250, + "Series": "Garden" + }, + { + "Date": "2020-02-15", + "Value": 275, + "Series": "Garden" + }, + { + "Date": "2020-02-24", + "Value": 295, + "Series": "Garden" + }, + { + "Date": "2020-03-04", + "Value": 304, + "Series": "Garden" + }, + { + "Date": "2020-03-14", + "Value": 323, + "Series": "Garden" + }, + { + "Date": "2020-03-23", + "Value": 327, + "Series": "Garden" + }, + { + "Date": "2020-04-01", + "Value": 341, + "Series": "Garden" + }, + { + "Date": "2020-04-10", + "Value": 360, + "Series": "Garden" + }, + { + "Date": "2020-04-19", + "Value": 369, + "Series": "Garden" + }, + { + "Date": "2020-04-28", + "Value": 366, + "Series": "Garden" + }, + { + "Date": "2020-05-07", + "Value": 356, + "Series": "Garden" + }, + { + "Date": "2020-05-16", + "Value": 350, + "Series": "Garden" + }, + { + "Date": "2020-05-26", + "Value": 362, + "Series": "Garden" + }, + { + "Date": "2020-06-04", + "Value": 366, + "Series": "Garden" + }, + { + "Date": "2020-06-13", + "Value": 371, + "Series": "Garden" + }, + { + "Date": "2020-06-22", + "Value": 387, + "Series": "Garden" + }, + { + "Date": "2020-07-01", + "Value": 390, + "Series": "Garden" + }, + { + "Date": "2020-07-10", + "Value": 387, + "Series": "Garden" + }, + { + "Date": "2020-07-19", + "Value": 380, + "Series": "Garden" + }, + { + "Date": "2020-07-28", + "Value": 381, + "Series": "Garden" + }, + { + "Date": "2020-08-07", + "Value": 378, + "Series": "Garden" + }, + { + "Date": "2020-08-16", + "Value": 383, + "Series": "Garden" + }, + { + "Date": "2020-08-25", + "Value": 388, + "Series": "Garden" + }, + { + "Date": "2020-09-03", + "Value": 382, + "Series": "Garden" + }, + { + "Date": "2020-09-12", + "Value": 386, + "Series": "Garden" + }, + { + "Date": "2020-09-21", + "Value": 401, + "Series": "Garden" + }, + { + "Date": "2020-09-30", + "Value": 411, + "Series": "Garden" + }, + { + "Date": "2020-10-09", + "Value": 412, + "Series": "Garden" + }, + { + "Date": "2020-10-19", + "Value": 416, + "Series": "Garden" + }, + { + "Date": "2020-10-28", + "Value": 416, + "Series": "Garden" + }, + { + "Date": "2020-11-06", + "Value": 415, + "Series": "Garden" + }, + { + "Date": "2020-11-15", + "Value": 429, + "Series": "Garden" + }, + { + "Date": "2020-11-24", + "Value": 445, + "Series": "Garden" + }, + { + "Date": "2020-12-03", + "Value": 467, + "Series": "Garden" + }, + { + "Date": "2020-12-12", + "Value": 492, + "Series": "Garden" + }, + { + "Date": "2020-12-21", + "Value": 500, + "Series": "Garden" + }, + { + "Date": "2020-12-31", + "Value": 500, + "Series": "Garden" + }, + { + "Date": "2021-01-09", + "Value": 510, + "Series": "Garden" + }, + { + "Date": "2021-01-18", + "Value": 511, + "Series": "Garden" + }, + { + "Date": "2021-01-27", + "Value": 524, + "Series": "Garden" + }, + { + "Date": "2021-02-05", + "Value": 547, + "Series": "Garden" + }, + { + "Date": "2021-02-14", + "Value": 557, + "Series": "Garden" + }, + { + "Date": "2021-02-23", + "Value": 570, + "Series": "Garden" + }, + { + "Date": "2021-03-04", + "Value": 591, + "Series": "Garden" + }, + { + "Date": "2021-03-14", + "Value": 613, + "Series": "Garden" + }, + { + "Date": "2021-03-23", + "Value": 625, + "Series": "Garden" + }, + { + "Date": "2021-04-01", + "Value": 627, + "Series": "Garden" + }, + { + "Date": "2021-04-10", + "Value": 620, + "Series": "Garden" + }, + { + "Date": "2021-04-19", + "Value": 628, + "Series": "Garden" + }, + { + "Date": "2021-04-28", + "Value": 636, + "Series": "Garden" + }, + { + "Date": "2021-05-07", + "Value": 643, + "Series": "Garden" + }, + { + "Date": "2021-05-16", + "Value": 641, + "Series": "Garden" + }, + { + "Date": "2021-05-26", + "Value": 637, + "Series": "Garden" + }, + { + "Date": "2021-06-04", + "Value": 629, + "Series": "Garden" + }, + { + "Date": "2021-06-13", + "Value": 634, + "Series": "Garden" + }, + { + "Date": "2021-06-22", + "Value": 651, + "Series": "Garden" + }, + { + "Date": "2021-07-01", + "Value": 660, + "Series": "Garden" + }, + { + "Date": "2021-07-10", + "Value": 680, + "Series": "Garden" + }, + { + "Date": "2021-07-19", + "Value": 707, + "Series": "Garden" + }, + { + "Date": "2021-07-28", + "Value": 720, + "Series": "Garden" + }, + { + "Date": "2021-08-07", + "Value": 721, + "Series": "Garden" + }, + { + "Date": "2021-08-16", + "Value": 715, + "Series": "Garden" + }, + { + "Date": "2021-08-25", + "Value": 714, + "Series": "Garden" + }, + { + "Date": "2021-09-03", + "Value": 714, + "Series": "Garden" + }, + { + "Date": "2021-09-12", + "Value": 710, + "Series": "Garden" + }, + { + "Date": "2021-09-21", + "Value": 722, + "Series": "Garden" + }, + { + "Date": "2021-09-30", + "Value": 732, + "Series": "Garden" + }, + { + "Date": "2021-10-09", + "Value": 743, + "Series": "Garden" + }, + { + "Date": "2021-10-19", + "Value": 741, + "Series": "Garden" + }, + { + "Date": "2021-10-28", + "Value": 747, + "Series": "Garden" + }, + { + "Date": "2021-11-06", + "Value": 755, + "Series": "Garden" + }, + { + "Date": "2021-11-15", + "Value": 758, + "Series": "Garden" + }, + { + "Date": "2021-11-24", + "Value": 768, + "Series": "Garden" + }, + { + "Date": "2021-12-03", + "Value": 781, + "Series": "Garden" + }, + { + "Date": "2021-12-12", + "Value": 782, + "Series": "Garden" + }, + { + "Date": "2021-12-21", + "Value": 784, + "Series": "Garden" + }, + { + "Date": "2021-12-31", + "Value": 794, + "Series": "Garden" + }, + { + "Date": "2022-01-09", + "Value": 800, + "Series": "Garden" + }, + { + "Date": "2022-01-18", + "Value": 805, + "Series": "Garden" + }, + { + "Date": "2022-01-27", + "Value": 814, + "Series": "Garden" + }, + { + "Date": "2022-02-05", + "Value": 811, + "Series": "Garden" + }, + { + "Date": "2022-02-14", + "Value": 804, + "Series": "Garden" + }, + { + "Date": "2022-02-23", + "Value": 792, + "Series": "Garden" + }, + { + "Date": "2022-03-04", + "Value": 781, + "Series": "Garden" + }, + { + "Date": "2022-03-14", + "Value": 769, + "Series": "Garden" + }, + { + "Date": "2022-03-23", + "Value": 761, + "Series": "Garden" + }, + { + "Date": "2022-04-01", + "Value": 762, + "Series": "Garden" + }, + { + "Date": "2022-04-10", + "Value": 766, + "Series": "Garden" + }, + { + "Date": "2022-04-19", + "Value": 767, + "Series": "Garden" + }, + { + "Date": "2022-04-28", + "Value": 772, + "Series": "Garden" + }, + { + "Date": "2022-05-07", + "Value": 777, + "Series": "Garden" + }, + { + "Date": "2022-05-16", + "Value": 794, + "Series": "Garden" + }, + { + "Date": "2022-05-26", + "Value": 816, + "Series": "Garden" + }, + { + "Date": "2022-06-04", + "Value": 825, + "Series": "Garden" + }, + { + "Date": "2022-06-13", + "Value": 837, + "Series": "Garden" + }, + { + "Date": "2022-06-22", + "Value": 836, + "Series": "Garden" + }, + { + "Date": "2022-07-01", + "Value": 835, + "Series": "Garden" + }, + { + "Date": "2022-07-10", + "Value": 832, + "Series": "Garden" + }, + { + "Date": "2022-07-19", + "Value": 838, + "Series": "Garden" + }, + { + "Date": "2022-07-28", + "Value": 841, + "Series": "Garden" + }, + { + "Date": "2022-08-07", + "Value": 849, + "Series": "Garden" + }, + { + "Date": "2022-08-16", + "Value": 866, + "Series": "Garden" + }, + { + "Date": "2022-08-25", + "Value": 889, + "Series": "Garden" + }, + { + "Date": "2022-09-03", + "Value": 919, + "Series": "Garden" + }, + { + "Date": "2022-09-12", + "Value": 950, + "Series": "Garden" + }, + { + "Date": "2022-09-21", + "Value": 978, + "Series": "Garden" + }, + { + "Date": "2022-09-30", + "Value": 995, + "Series": "Garden" + }, + { + "Date": "2022-10-09", + "Value": 1020, + "Series": "Garden" + }, + { + "Date": "2022-10-19", + "Value": 1032, + "Series": "Garden" + }, + { + "Date": "2022-10-28", + "Value": 1038, + "Series": "Garden" + }, + { + "Date": "2022-11-06", + "Value": 1042, + "Series": "Garden" + }, + { + "Date": "2022-11-15", + "Value": 1054, + "Series": "Garden" + }, + { + "Date": "2022-11-24", + "Value": 1076, + "Series": "Garden" + }, + { + "Date": "2022-12-03", + "Value": 1084, + "Series": "Garden" + }, + { + "Date": "2022-12-12", + "Value": 1088, + "Series": "Garden" + }, + { + "Date": "2022-12-21", + "Value": 1095, + "Series": "Garden" + }, + { + "Date": "2020-01-01", + "Value": 212, + "Series": "Auto" + }, + { + "Date": "2020-01-10", + "Value": 210, + "Series": "Auto" + }, + { + "Date": "2020-01-19", + "Value": 221, + "Series": "Auto" + }, + { + "Date": "2020-01-28", + "Value": 221, + "Series": "Auto" + }, + { + "Date": "2020-02-06", + "Value": 213, + "Series": "Auto" + }, + { + "Date": "2020-02-15", + "Value": 222, + "Series": "Auto" + }, + { + "Date": "2020-02-24", + "Value": 228, + "Series": "Auto" + }, + { + "Date": "2020-03-04", + "Value": 225, + "Series": "Auto" + }, + { + "Date": "2020-03-14", + "Value": 222, + "Series": "Auto" + }, + { + "Date": "2020-03-23", + "Value": 213, + "Series": "Auto" + }, + { + "Date": "2020-04-01", + "Value": 200, + "Series": "Auto" + }, + { + "Date": "2020-04-10", + "Value": 204, + "Series": "Auto" + }, + { + "Date": "2020-04-19", + "Value": 214, + "Series": "Auto" + }, + { + "Date": "2020-04-28", + "Value": 224, + "Series": "Auto" + }, + { + "Date": "2020-05-07", + "Value": 226, + "Series": "Auto" + }, + { + "Date": "2020-05-16", + "Value": 228, + "Series": "Auto" + }, + { + "Date": "2020-05-26", + "Value": 221, + "Series": "Auto" + }, + { + "Date": "2020-06-04", + "Value": 208, + "Series": "Auto" + }, + { + "Date": "2020-06-13", + "Value": 200, + "Series": "Auto" + }, + { + "Date": "2020-06-22", + "Value": 203, + "Series": "Auto" + }, + { + "Date": "2020-07-01", + "Value": 194, + "Series": "Auto" + }, + { + "Date": "2020-07-10", + "Value": 184, + "Series": "Auto" + }, + { + "Date": "2020-07-19", + "Value": 197, + "Series": "Auto" + }, + { + "Date": "2020-07-28", + "Value": 196, + "Series": "Auto" + }, + { + "Date": "2020-08-07", + "Value": 183, + "Series": "Auto" + }, + { + "Date": "2020-08-16", + "Value": 193, + "Series": "Auto" + }, + { + "Date": "2020-08-25", + "Value": 218, + "Series": "Auto" + }, + { + "Date": "2020-09-03", + "Value": 253, + "Series": "Auto" + }, + { + "Date": "2020-09-12", + "Value": 287, + "Series": "Auto" + }, + { + "Date": "2020-09-21", + "Value": 304, + "Series": "Auto" + }, + { + "Date": "2020-09-30", + "Value": 309, + "Series": "Auto" + }, + { + "Date": "2020-10-09", + "Value": 315, + "Series": "Auto" + }, + { + "Date": "2020-10-19", + "Value": 309, + "Series": "Auto" + }, + { + "Date": "2020-10-28", + "Value": 319, + "Series": "Auto" + }, + { + "Date": "2020-11-06", + "Value": 336, + "Series": "Auto" + }, + { + "Date": "2020-11-15", + "Value": 349, + "Series": "Auto" + }, + { + "Date": "2020-11-24", + "Value": 372, + "Series": "Auto" + }, + { + "Date": "2020-12-03", + "Value": 389, + "Series": "Auto" + }, + { + "Date": "2020-12-12", + "Value": 413, + "Series": "Auto" + }, + { + "Date": "2020-12-21", + "Value": 446, + "Series": "Auto" + }, + { + "Date": "2020-12-31", + "Value": 455, + "Series": "Auto" + }, + { + "Date": "2021-01-09", + "Value": 462, + "Series": "Auto" + }, + { + "Date": "2021-01-18", + "Value": 473, + "Series": "Auto" + }, + { + "Date": "2021-01-27", + "Value": 484, + "Series": "Auto" + }, + { + "Date": "2021-02-05", + "Value": 488, + "Series": "Auto" + }, + { + "Date": "2021-02-14", + "Value": 498, + "Series": "Auto" + }, + { + "Date": "2021-02-23", + "Value": 494, + "Series": "Auto" + }, + { + "Date": "2021-03-04", + "Value": 482, + "Series": "Auto" + }, + { + "Date": "2021-03-14", + "Value": 465, + "Series": "Auto" + }, + { + "Date": "2021-03-23", + "Value": 468, + "Series": "Auto" + }, + { + "Date": "2021-04-01", + "Value": 487, + "Series": "Auto" + }, + { + "Date": "2021-04-10", + "Value": 483, + "Series": "Auto" + }, + { + "Date": "2021-04-19", + "Value": 470, + "Series": "Auto" + }, + { + "Date": "2021-04-28", + "Value": 463, + "Series": "Auto" + }, + { + "Date": "2021-05-07", + "Value": 466, + "Series": "Auto" + }, + { + "Date": "2021-05-16", + "Value": 482, + "Series": "Auto" + }, + { + "Date": "2021-05-26", + "Value": 497, + "Series": "Auto" + }, + { + "Date": "2021-06-04", + "Value": 503, + "Series": "Auto" + }, + { + "Date": "2021-06-13", + "Value": 523, + "Series": "Auto" + }, + { + "Date": "2021-06-22", + "Value": 536, + "Series": "Auto" + }, + { + "Date": "2021-07-01", + "Value": 556, + "Series": "Auto" + }, + { + "Date": "2021-07-10", + "Value": 563, + "Series": "Auto" + }, + { + "Date": "2021-07-19", + "Value": 572, + "Series": "Auto" + }, + { + "Date": "2021-07-28", + "Value": 577, + "Series": "Auto" + }, + { + "Date": "2021-08-07", + "Value": 586, + "Series": "Auto" + }, + { + "Date": "2021-08-16", + "Value": 588, + "Series": "Auto" + }, + { + "Date": "2021-08-25", + "Value": 576, + "Series": "Auto" + }, + { + "Date": "2021-09-03", + "Value": 586, + "Series": "Auto" + }, + { + "Date": "2021-09-12", + "Value": 579, + "Series": "Auto" + }, + { + "Date": "2021-09-21", + "Value": 569, + "Series": "Auto" + }, + { + "Date": "2021-09-30", + "Value": 566, + "Series": "Auto" + }, + { + "Date": "2021-10-09", + "Value": 573, + "Series": "Auto" + }, + { + "Date": "2021-10-19", + "Value": 564, + "Series": "Auto" + }, + { + "Date": "2021-10-28", + "Value": 550, + "Series": "Auto" + }, + { + "Date": "2021-11-06", + "Value": 534, + "Series": "Auto" + }, + { + "Date": "2021-11-15", + "Value": 544, + "Series": "Auto" + }, + { + "Date": "2021-11-24", + "Value": 553, + "Series": "Auto" + }, + { + "Date": "2021-12-03", + "Value": 565, + "Series": "Auto" + }, + { + "Date": "2021-12-12", + "Value": 560, + "Series": "Auto" + }, + { + "Date": "2021-12-21", + "Value": 575, + "Series": "Auto" + }, + { + "Date": "2021-12-31", + "Value": 600, + "Series": "Auto" + }, + { + "Date": "2022-01-09", + "Value": 620, + "Series": "Auto" + }, + { + "Date": "2022-01-18", + "Value": 635, + "Series": "Auto" + }, + { + "Date": "2022-01-27", + "Value": 641, + "Series": "Auto" + }, + { + "Date": "2022-02-05", + "Value": 651, + "Series": "Auto" + }, + { + "Date": "2022-02-14", + "Value": 657, + "Series": "Auto" + }, + { + "Date": "2022-02-23", + "Value": 673, + "Series": "Auto" + }, + { + "Date": "2022-03-04", + "Value": 691, + "Series": "Auto" + }, + { + "Date": "2022-03-14", + "Value": 701, + "Series": "Auto" + }, + { + "Date": "2022-03-23", + "Value": 719, + "Series": "Auto" + }, + { + "Date": "2022-04-01", + "Value": 751, + "Series": "Auto" + }, + { + "Date": "2022-04-10", + "Value": 763, + "Series": "Auto" + }, + { + "Date": "2022-04-19", + "Value": 784, + "Series": "Auto" + }, + { + "Date": "2022-04-28", + "Value": 783, + "Series": "Auto" + }, + { + "Date": "2022-05-07", + "Value": 772, + "Series": "Auto" + }, + { + "Date": "2022-05-16", + "Value": 753, + "Series": "Auto" + }, + { + "Date": "2022-05-26", + "Value": 751, + "Series": "Auto" + }, + { + "Date": "2022-06-04", + "Value": 758, + "Series": "Auto" + }, + { + "Date": "2022-06-13", + "Value": 756, + "Series": "Auto" + }, + { + "Date": "2022-06-22", + "Value": 742, + "Series": "Auto" + }, + { + "Date": "2022-07-01", + "Value": 725, + "Series": "Auto" + }, + { + "Date": "2022-07-10", + "Value": 705, + "Series": "Auto" + }, + { + "Date": "2022-07-19", + "Value": 700, + "Series": "Auto" + }, + { + "Date": "2022-07-28", + "Value": 710, + "Series": "Auto" + }, + { + "Date": "2022-08-07", + "Value": 718, + "Series": "Auto" + }, + { + "Date": "2022-08-16", + "Value": 710, + "Series": "Auto" + }, + { + "Date": "2022-08-25", + "Value": 713, + "Series": "Auto" + }, + { + "Date": "2022-09-03", + "Value": 722, + "Series": "Auto" + }, + { + "Date": "2022-09-12", + "Value": 738, + "Series": "Auto" + }, + { + "Date": "2022-09-21", + "Value": 762, + "Series": "Auto" + }, + { + "Date": "2022-09-30", + "Value": 795, + "Series": "Auto" + }, + { + "Date": "2022-10-09", + "Value": 813, + "Series": "Auto" + }, + { + "Date": "2022-10-19", + "Value": 827, + "Series": "Auto" + }, + { + "Date": "2022-10-28", + "Value": 852, + "Series": "Auto" + }, + { + "Date": "2022-11-06", + "Value": 884, + "Series": "Auto" + }, + { + "Date": "2022-11-15", + "Value": 901, + "Series": "Auto" + }, + { + "Date": "2022-11-24", + "Value": 906, + "Series": "Auto" + }, + { + "Date": "2022-12-03", + "Value": 904, + "Series": "Auto" + }, + { + "Date": "2022-12-12", + "Value": 893, + "Series": "Auto" + }, + { + "Date": "2022-12-21", + "Value": 872, + "Series": "Auto" + }, + { + "Date": "2020-01-01", + "Value": 95, + "Series": "Health" + }, + { + "Date": "2020-01-10", + "Value": 98, + "Series": "Health" + }, + { + "Date": "2020-01-19", + "Value": 104, + "Series": "Health" + }, + { + "Date": "2020-01-28", + "Value": 108, + "Series": "Health" + }, + { + "Date": "2020-02-06", + "Value": 108, + "Series": "Health" + }, + { + "Date": "2020-02-15", + "Value": 105, + "Series": "Health" + }, + { + "Date": "2020-02-24", + "Value": 102, + "Series": "Health" + }, + { + "Date": "2020-03-04", + "Value": 97, + "Series": "Health" + }, + { + "Date": "2020-03-14", + "Value": 100, + "Series": "Health" + }, + { + "Date": "2020-03-23", + "Value": 104, + "Series": "Health" + }, + { + "Date": "2020-04-01", + "Value": 106, + "Series": "Health" + }, + { + "Date": "2020-04-10", + "Value": 103, + "Series": "Health" + }, + { + "Date": "2020-04-19", + "Value": 103, + "Series": "Health" + }, + { + "Date": "2020-04-28", + "Value": 100, + "Series": "Health" + }, + { + "Date": "2020-05-07", + "Value": 105, + "Series": "Health" + }, + { + "Date": "2020-05-16", + "Value": 109, + "Series": "Health" + }, + { + "Date": "2020-05-26", + "Value": 113, + "Series": "Health" + }, + { + "Date": "2020-06-04", + "Value": 113, + "Series": "Health" + }, + { + "Date": "2020-06-13", + "Value": 112, + "Series": "Health" + }, + { + "Date": "2020-06-22", + "Value": 108, + "Series": "Health" + }, + { + "Date": "2020-07-01", + "Value": 109, + "Series": "Health" + }, + { + "Date": "2020-07-10", + "Value": 114, + "Series": "Health" + }, + { + "Date": "2020-07-19", + "Value": 118, + "Series": "Health" + }, + { + "Date": "2020-07-28", + "Value": 123, + "Series": "Health" + }, + { + "Date": "2020-08-07", + "Value": 125, + "Series": "Health" + }, + { + "Date": "2020-08-16", + "Value": 126, + "Series": "Health" + }, + { + "Date": "2020-08-25", + "Value": 128, + "Series": "Health" + }, + { + "Date": "2020-09-03", + "Value": 130, + "Series": "Health" + }, + { + "Date": "2020-09-12", + "Value": 129, + "Series": "Health" + }, + { + "Date": "2020-09-21", + "Value": 125, + "Series": "Health" + }, + { + "Date": "2020-09-30", + "Value": 127, + "Series": "Health" + }, + { + "Date": "2020-10-09", + "Value": 131, + "Series": "Health" + }, + { + "Date": "2020-10-19", + "Value": 141, + "Series": "Health" + }, + { + "Date": "2020-10-28", + "Value": 143, + "Series": "Health" + }, + { + "Date": "2020-11-06", + "Value": 151, + "Series": "Health" + }, + { + "Date": "2020-11-15", + "Value": 156, + "Series": "Health" + }, + { + "Date": "2020-11-24", + "Value": 162, + "Series": "Health" + }, + { + "Date": "2020-12-03", + "Value": 172, + "Series": "Health" + }, + { + "Date": "2020-12-12", + "Value": 180, + "Series": "Health" + }, + { + "Date": "2020-12-21", + "Value": 181, + "Series": "Health" + }, + { + "Date": "2020-12-31", + "Value": 190, + "Series": "Health" + }, + { + "Date": "2021-01-09", + "Value": 197, + "Series": "Health" + }, + { + "Date": "2021-01-18", + "Value": 202, + "Series": "Health" + }, + { + "Date": "2021-01-27", + "Value": 212, + "Series": "Health" + }, + { + "Date": "2021-02-05", + "Value": 215, + "Series": "Health" + }, + { + "Date": "2021-02-14", + "Value": 222, + "Series": "Health" + }, + { + "Date": "2021-02-23", + "Value": 233, + "Series": "Health" + }, + { + "Date": "2021-03-04", + "Value": 246, + "Series": "Health" + }, + { + "Date": "2021-03-14", + "Value": 254, + "Series": "Health" + }, + { + "Date": "2021-03-23", + "Value": 256, + "Series": "Health" + }, + { + "Date": "2021-04-01", + "Value": 260, + "Series": "Health" + }, + { + "Date": "2021-04-10", + "Value": 260, + "Series": "Health" + }, + { + "Date": "2021-04-19", + "Value": 260, + "Series": "Health" + }, + { + "Date": "2021-04-28", + "Value": 262, + "Series": "Health" + }, + { + "Date": "2021-05-07", + "Value": 268, + "Series": "Health" + }, + { + "Date": "2021-05-16", + "Value": 277, + "Series": "Health" + }, + { + "Date": "2021-05-26", + "Value": 283, + "Series": "Health" + }, + { + "Date": "2021-06-04", + "Value": 288, + "Series": "Health" + }, + { + "Date": "2021-06-13", + "Value": 295, + "Series": "Health" + }, + { + "Date": "2021-06-22", + "Value": 295, + "Series": "Health" + }, + { + "Date": "2021-07-01", + "Value": 296, + "Series": "Health" + }, + { + "Date": "2021-07-10", + "Value": 300, + "Series": "Health" + }, + { + "Date": "2021-07-19", + "Value": 308, + "Series": "Health" + }, + { + "Date": "2021-07-28", + "Value": 314, + "Series": "Health" + }, + { + "Date": "2021-08-07", + "Value": 315, + "Series": "Health" + }, + { + "Date": "2021-08-16", + "Value": 322, + "Series": "Health" + }, + { + "Date": "2021-08-25", + "Value": 335, + "Series": "Health" + }, + { + "Date": "2021-09-03", + "Value": 342, + "Series": "Health" + }, + { + "Date": "2021-09-12", + "Value": 350, + "Series": "Health" + }, + { + "Date": "2021-09-21", + "Value": 362, + "Series": "Health" + }, + { + "Date": "2021-09-30", + "Value": 377, + "Series": "Health" + }, + { + "Date": "2021-10-09", + "Value": 393, + "Series": "Health" + }, + { + "Date": "2021-10-19", + "Value": 409, + "Series": "Health" + }, + { + "Date": "2021-10-28", + "Value": 424, + "Series": "Health" + }, + { + "Date": "2021-11-06", + "Value": 440, + "Series": "Health" + }, + { + "Date": "2021-11-15", + "Value": 450, + "Series": "Health" + }, + { + "Date": "2021-11-24", + "Value": 456, + "Series": "Health" + }, + { + "Date": "2021-12-03", + "Value": 466, + "Series": "Health" + }, + { + "Date": "2021-12-12", + "Value": 474, + "Series": "Health" + }, + { + "Date": "2021-12-21", + "Value": 482, + "Series": "Health" + }, + { + "Date": "2021-12-31", + "Value": 489, + "Series": "Health" + }, + { + "Date": "2022-01-09", + "Value": 499, + "Series": "Health" + }, + { + "Date": "2022-01-18", + "Value": 502, + "Series": "Health" + }, + { + "Date": "2022-01-27", + "Value": 509, + "Series": "Health" + }, + { + "Date": "2022-02-05", + "Value": 512, + "Series": "Health" + }, + { + "Date": "2022-02-14", + "Value": 514, + "Series": "Health" + }, + { + "Date": "2022-02-23", + "Value": 523, + "Series": "Health" + }, + { + "Date": "2022-03-04", + "Value": 535, + "Series": "Health" + }, + { + "Date": "2022-03-14", + "Value": 550, + "Series": "Health" + }, + { + "Date": "2022-03-23", + "Value": 557, + "Series": "Health" + }, + { + "Date": "2022-04-01", + "Value": 564, + "Series": "Health" + }, + { + "Date": "2022-04-10", + "Value": 568, + "Series": "Health" + }, + { + "Date": "2022-04-19", + "Value": 573, + "Series": "Health" + }, + { + "Date": "2022-04-28", + "Value": 584, + "Series": "Health" + }, + { + "Date": "2022-05-07", + "Value": 593, + "Series": "Health" + }, + { + "Date": "2022-05-16", + "Value": 605, + "Series": "Health" + }, + { + "Date": "2022-05-26", + "Value": 613, + "Series": "Health" + }, + { + "Date": "2022-06-04", + "Value": 618, + "Series": "Health" + }, + { + "Date": "2022-06-13", + "Value": 629, + "Series": "Health" + }, + { + "Date": "2022-06-22", + "Value": 644, + "Series": "Health" + }, + { + "Date": "2022-07-01", + "Value": 654, + "Series": "Health" + }, + { + "Date": "2022-07-10", + "Value": 658, + "Series": "Health" + }, + { + "Date": "2022-07-19", + "Value": 663, + "Series": "Health" + }, + { + "Date": "2022-07-28", + "Value": 666, + "Series": "Health" + }, + { + "Date": "2022-08-07", + "Value": 666, + "Series": "Health" + }, + { + "Date": "2022-08-16", + "Value": 673, + "Series": "Health" + }, + { + "Date": "2022-08-25", + "Value": 682, + "Series": "Health" + }, + { + "Date": "2022-09-03", + "Value": 686, + "Series": "Health" + }, + { + "Date": "2022-09-12", + "Value": 687, + "Series": "Health" + }, + { + "Date": "2022-09-21", + "Value": 684, + "Series": "Health" + }, + { + "Date": "2022-09-30", + "Value": 685, + "Series": "Health" + }, + { + "Date": "2022-10-09", + "Value": 685, + "Series": "Health" + }, + { + "Date": "2022-10-19", + "Value": 683, + "Series": "Health" + }, + { + "Date": "2022-10-28", + "Value": 683, + "Series": "Health" + }, + { + "Date": "2022-11-06", + "Value": 680, + "Series": "Health" + }, + { + "Date": "2022-11-15", + "Value": 680, + "Series": "Health" + }, + { + "Date": "2022-11-24", + "Value": 685, + "Series": "Health" + }, + { + "Date": "2022-12-03", + "Value": 694, + "Series": "Health" + }, + { + "Date": "2022-12-12", + "Value": 701, + "Series": "Health" + }, + { + "Date": "2022-12-21", + "Value": 707, + "Series": "Health" + }, + { + "Date": "2020-01-01", + "Value": 119, + "Series": "Beauty" + }, + { + "Date": "2020-01-10", + "Value": 142, + "Series": "Beauty" + }, + { + "Date": "2020-01-19", + "Value": 140, + "Series": "Beauty" + }, + { + "Date": "2020-01-28", + "Value": 144, + "Series": "Beauty" + }, + { + "Date": "2020-02-06", + "Value": 135, + "Series": "Beauty" + }, + { + "Date": "2020-02-15", + "Value": 149, + "Series": "Beauty" + }, + { + "Date": "2020-02-24", + "Value": 161, + "Series": "Beauty" + }, + { + "Date": "2020-03-04", + "Value": 172, + "Series": "Beauty" + }, + { + "Date": "2020-03-14", + "Value": 200, + "Series": "Beauty" + }, + { + "Date": "2020-03-23", + "Value": 212, + "Series": "Beauty" + }, + { + "Date": "2020-04-01", + "Value": 209, + "Series": "Beauty" + }, + { + "Date": "2020-04-10", + "Value": 227, + "Series": "Beauty" + }, + { + "Date": "2020-04-19", + "Value": 246, + "Series": "Beauty" + }, + { + "Date": "2020-04-28", + "Value": 280, + "Series": "Beauty" + }, + { + "Date": "2020-05-07", + "Value": 285, + "Series": "Beauty" + }, + { + "Date": "2020-05-16", + "Value": 284, + "Series": "Beauty" + }, + { + "Date": "2020-05-26", + "Value": 276, + "Series": "Beauty" + }, + { + "Date": "2020-06-04", + "Value": 286, + "Series": "Beauty" + }, + { + "Date": "2020-06-13", + "Value": 290, + "Series": "Beauty" + }, + { + "Date": "2020-06-22", + "Value": 283, + "Series": "Beauty" + }, + { + "Date": "2020-07-01", + "Value": 283, + "Series": "Beauty" + }, + { + "Date": "2020-07-10", + "Value": 294, + "Series": "Beauty" + }, + { + "Date": "2020-07-19", + "Value": 311, + "Series": "Beauty" + }, + { + "Date": "2020-07-28", + "Value": 319, + "Series": "Beauty" + }, + { + "Date": "2020-08-07", + "Value": 314, + "Series": "Beauty" + }, + { + "Date": "2020-08-16", + "Value": 317, + "Series": "Beauty" + }, + { + "Date": "2020-08-25", + "Value": 326, + "Series": "Beauty" + }, + { + "Date": "2020-09-03", + "Value": 346, + "Series": "Beauty" + }, + { + "Date": "2020-09-12", + "Value": 378, + "Series": "Beauty" + }, + { + "Date": "2020-09-21", + "Value": 402, + "Series": "Beauty" + }, + { + "Date": "2020-09-30", + "Value": 421, + "Series": "Beauty" + }, + { + "Date": "2020-10-09", + "Value": 450, + "Series": "Beauty" + }, + { + "Date": "2020-10-19", + "Value": 481, + "Series": "Beauty" + }, + { + "Date": "2020-10-28", + "Value": 522, + "Series": "Beauty" + }, + { + "Date": "2020-11-06", + "Value": 569, + "Series": "Beauty" + }, + { + "Date": "2020-11-15", + "Value": 617, + "Series": "Beauty" + }, + { + "Date": "2020-11-24", + "Value": 648, + "Series": "Beauty" + }, + { + "Date": "2020-12-03", + "Value": 679, + "Series": "Beauty" + }, + { + "Date": "2020-12-12", + "Value": 686, + "Series": "Beauty" + }, + { + "Date": "2020-12-21", + "Value": 699, + "Series": "Beauty" + }, + { + "Date": "2020-12-31", + "Value": 697, + "Series": "Beauty" + }, + { + "Date": "2021-01-09", + "Value": 698, + "Series": "Beauty" + }, + { + "Date": "2021-01-18", + "Value": 692, + "Series": "Beauty" + }, + { + "Date": "2021-01-27", + "Value": 709, + "Series": "Beauty" + }, + { + "Date": "2021-02-05", + "Value": 726, + "Series": "Beauty" + }, + { + "Date": "2021-02-14", + "Value": 730, + "Series": "Beauty" + }, + { + "Date": "2021-02-23", + "Value": 734, + "Series": "Beauty" + }, + { + "Date": "2021-03-04", + "Value": 750, + "Series": "Beauty" + }, + { + "Date": "2021-03-14", + "Value": 767, + "Series": "Beauty" + }, + { + "Date": "2021-03-23", + "Value": 776, + "Series": "Beauty" + }, + { + "Date": "2021-04-01", + "Value": 778, + "Series": "Beauty" + }, + { + "Date": "2021-04-10", + "Value": 773, + "Series": "Beauty" + }, + { + "Date": "2021-04-19", + "Value": 760, + "Series": "Beauty" + }, + { + "Date": "2021-04-28", + "Value": 761, + "Series": "Beauty" + }, + { + "Date": "2021-05-07", + "Value": 775, + "Series": "Beauty" + }, + { + "Date": "2021-05-16", + "Value": 791, + "Series": "Beauty" + }, + { + "Date": "2021-05-26", + "Value": 805, + "Series": "Beauty" + }, + { + "Date": "2021-06-04", + "Value": 807, + "Series": "Beauty" + }, + { + "Date": "2021-06-13", + "Value": 793, + "Series": "Beauty" + }, + { + "Date": "2021-06-22", + "Value": 801, + "Series": "Beauty" + }, + { + "Date": "2021-07-01", + "Value": 812, + "Series": "Beauty" + }, + { + "Date": "2021-07-10", + "Value": 830, + "Series": "Beauty" + }, + { + "Date": "2021-07-19", + "Value": 861, + "Series": "Beauty" + }, + { + "Date": "2021-07-28", + "Value": 884, + "Series": "Beauty" + }, + { + "Date": "2021-08-07", + "Value": 889, + "Series": "Beauty" + }, + { + "Date": "2021-08-16", + "Value": 905, + "Series": "Beauty" + }, + { + "Date": "2021-08-25", + "Value": 922, + "Series": "Beauty" + }, + { + "Date": "2021-09-03", + "Value": 936, + "Series": "Beauty" + }, + { + "Date": "2021-09-12", + "Value": 941, + "Series": "Beauty" + }, + { + "Date": "2021-09-21", + "Value": 956, + "Series": "Beauty" + }, + { + "Date": "2021-09-30", + "Value": 988, + "Series": "Beauty" + }, + { + "Date": "2021-10-09", + "Value": 1025, + "Series": "Beauty" + }, + { + "Date": "2021-10-19", + "Value": 1045, + "Series": "Beauty" + }, + { + "Date": "2021-10-28", + "Value": 1054, + "Series": "Beauty" + }, + { + "Date": "2021-11-06", + "Value": 1044, + "Series": "Beauty" + }, + { + "Date": "2021-11-15", + "Value": 1054, + "Series": "Beauty" + }, + { + "Date": "2021-11-24", + "Value": 1075, + "Series": "Beauty" + }, + { + "Date": "2021-12-03", + "Value": 1100, + "Series": "Beauty" + }, + { + "Date": "2021-12-12", + "Value": 1108, + "Series": "Beauty" + }, + { + "Date": "2021-12-21", + "Value": 1120, + "Series": "Beauty" + }, + { + "Date": "2021-12-31", + "Value": 1114, + "Series": "Beauty" + }, + { + "Date": "2022-01-09", + "Value": 1133, + "Series": "Beauty" + }, + { + "Date": "2022-01-18", + "Value": 1148, + "Series": "Beauty" + }, + { + "Date": "2022-01-27", + "Value": 1145, + "Series": "Beauty" + }, + { + "Date": "2022-02-05", + "Value": 1154, + "Series": "Beauty" + }, + { + "Date": "2022-02-14", + "Value": 1157, + "Series": "Beauty" + }, + { + "Date": "2022-02-23", + "Value": 1181, + "Series": "Beauty" + }, + { + "Date": "2022-03-04", + "Value": 1189, + "Series": "Beauty" + }, + { + "Date": "2022-03-14", + "Value": 1216, + "Series": "Beauty" + }, + { + "Date": "2022-03-23", + "Value": 1248, + "Series": "Beauty" + }, + { + "Date": "2022-04-01", + "Value": 1289, + "Series": "Beauty" + }, + { + "Date": "2022-04-10", + "Value": 1333, + "Series": "Beauty" + }, + { + "Date": "2022-04-19", + "Value": 1359, + "Series": "Beauty" + }, + { + "Date": "2022-04-28", + "Value": 1379, + "Series": "Beauty" + }, + { + "Date": "2022-05-07", + "Value": 1405, + "Series": "Beauty" + }, + { + "Date": "2022-05-16", + "Value": 1417, + "Series": "Beauty" + }, + { + "Date": "2022-05-26", + "Value": 1417, + "Series": "Beauty" + }, + { + "Date": "2022-06-04", + "Value": 1432, + "Series": "Beauty" + }, + { + "Date": "2022-06-13", + "Value": 1425, + "Series": "Beauty" + }, + { + "Date": "2022-06-22", + "Value": 1415, + "Series": "Beauty" + }, + { + "Date": "2022-07-01", + "Value": 1428, + "Series": "Beauty" + }, + { + "Date": "2022-07-10", + "Value": 1442, + "Series": "Beauty" + }, + { + "Date": "2022-07-19", + "Value": 1473, + "Series": "Beauty" + }, + { + "Date": "2022-07-28", + "Value": 1477, + "Series": "Beauty" + }, + { + "Date": "2022-08-07", + "Value": 1497, + "Series": "Beauty" + }, + { + "Date": "2022-08-16", + "Value": 1501, + "Series": "Beauty" + }, + { + "Date": "2022-08-25", + "Value": 1520, + "Series": "Beauty" + }, + { + "Date": "2022-09-03", + "Value": 1540, + "Series": "Beauty" + }, + { + "Date": "2022-09-12", + "Value": 1536, + "Series": "Beauty" + }, + { + "Date": "2022-09-21", + "Value": 1524, + "Series": "Beauty" + }, + { + "Date": "2022-09-30", + "Value": 1508, + "Series": "Beauty" + }, + { + "Date": "2022-10-09", + "Value": 1514, + "Series": "Beauty" + }, + { + "Date": "2022-10-19", + "Value": 1524, + "Series": "Beauty" + }, + { + "Date": "2022-10-28", + "Value": 1526, + "Series": "Beauty" + }, + { + "Date": "2022-11-06", + "Value": 1538, + "Series": "Beauty" + }, + { + "Date": "2022-11-15", + "Value": 1545, + "Series": "Beauty" + }, + { + "Date": "2022-11-24", + "Value": 1553, + "Series": "Beauty" + }, + { + "Date": "2022-12-03", + "Value": 1572, + "Series": "Beauty" + }, + { + "Date": "2022-12-12", + "Value": 1591, + "Series": "Beauty" + }, + { + "Date": "2022-12-21", + "Value": 1619, + "Series": "Beauty" + }, + { + "Date": "2020-01-01", + "Value": 188, + "Series": "Toys" + }, + { + "Date": "2020-01-10", + "Value": 180, + "Series": "Toys" + }, + { + "Date": "2020-01-19", + "Value": 187, + "Series": "Toys" + }, + { + "Date": "2020-01-28", + "Value": 181, + "Series": "Toys" + }, + { + "Date": "2020-02-06", + "Value": 181, + "Series": "Toys" + }, + { + "Date": "2020-02-15", + "Value": 194, + "Series": "Toys" + }, + { + "Date": "2020-02-24", + "Value": 206, + "Series": "Toys" + }, + { + "Date": "2020-03-04", + "Value": 222, + "Series": "Toys" + }, + { + "Date": "2020-03-14", + "Value": 222, + "Series": "Toys" + }, + { + "Date": "2020-03-23", + "Value": 232, + "Series": "Toys" + }, + { + "Date": "2020-04-01", + "Value": 251, + "Series": "Toys" + }, + { + "Date": "2020-04-10", + "Value": 268, + "Series": "Toys" + }, + { + "Date": "2020-04-19", + "Value": 279, + "Series": "Toys" + }, + { + "Date": "2020-04-28", + "Value": 299, + "Series": "Toys" + }, + { + "Date": "2020-05-07", + "Value": 315, + "Series": "Toys" + }, + { + "Date": "2020-05-16", + "Value": 323, + "Series": "Toys" + }, + { + "Date": "2020-05-26", + "Value": 319, + "Series": "Toys" + }, + { + "Date": "2020-06-04", + "Value": 318, + "Series": "Toys" + }, + { + "Date": "2020-06-13", + "Value": 311, + "Series": "Toys" + }, + { + "Date": "2020-06-22", + "Value": 311, + "Series": "Toys" + }, + { + "Date": "2020-07-01", + "Value": 306, + "Series": "Toys" + }, + { + "Date": "2020-07-10", + "Value": 304, + "Series": "Toys" + }, + { + "Date": "2020-07-19", + "Value": 299, + "Series": "Toys" + }, + { + "Date": "2020-07-28", + "Value": 310, + "Series": "Toys" + }, + { + "Date": "2020-08-07", + "Value": 320, + "Series": "Toys" + }, + { + "Date": "2020-08-16", + "Value": 323, + "Series": "Toys" + }, + { + "Date": "2020-08-25", + "Value": 337, + "Series": "Toys" + }, + { + "Date": "2020-09-03", + "Value": 354, + "Series": "Toys" + }, + { + "Date": "2020-09-12", + "Value": 360, + "Series": "Toys" + }, + { + "Date": "2020-09-21", + "Value": 372, + "Series": "Toys" + }, + { + "Date": "2020-09-30", + "Value": 378, + "Series": "Toys" + }, + { + "Date": "2020-10-09", + "Value": 372, + "Series": "Toys" + }, + { + "Date": "2020-10-19", + "Value": 369, + "Series": "Toys" + }, + { + "Date": "2020-10-28", + "Value": 371, + "Series": "Toys" + }, + { + "Date": "2020-11-06", + "Value": 377, + "Series": "Toys" + }, + { + "Date": "2020-11-15", + "Value": 392, + "Series": "Toys" + }, + { + "Date": "2020-11-24", + "Value": 394, + "Series": "Toys" + }, + { + "Date": "2020-12-03", + "Value": 397, + "Series": "Toys" + }, + { + "Date": "2020-12-12", + "Value": 399, + "Series": "Toys" + }, + { + "Date": "2020-12-21", + "Value": 412, + "Series": "Toys" + }, + { + "Date": "2020-12-31", + "Value": 430, + "Series": "Toys" + }, + { + "Date": "2021-01-09", + "Value": 443, + "Series": "Toys" + }, + { + "Date": "2021-01-18", + "Value": 462, + "Series": "Toys" + }, + { + "Date": "2021-01-27", + "Value": 475, + "Series": "Toys" + }, + { + "Date": "2021-02-05", + "Value": 486, + "Series": "Toys" + }, + { + "Date": "2021-02-14", + "Value": 505, + "Series": "Toys" + }, + { + "Date": "2021-02-23", + "Value": 519, + "Series": "Toys" + }, + { + "Date": "2021-03-04", + "Value": 540, + "Series": "Toys" + }, + { + "Date": "2021-03-14", + "Value": 563, + "Series": "Toys" + }, + { + "Date": "2021-03-23", + "Value": 567, + "Series": "Toys" + }, + { + "Date": "2021-04-01", + "Value": 571, + "Series": "Toys" + }, + { + "Date": "2021-04-10", + "Value": 581, + "Series": "Toys" + }, + { + "Date": "2021-04-19", + "Value": 582, + "Series": "Toys" + }, + { + "Date": "2021-04-28", + "Value": 590, + "Series": "Toys" + }, + { + "Date": "2021-05-07", + "Value": 608, + "Series": "Toys" + }, + { + "Date": "2021-05-16", + "Value": 634, + "Series": "Toys" + }, + { + "Date": "2021-05-26", + "Value": 640, + "Series": "Toys" + }, + { + "Date": "2021-06-04", + "Value": 655, + "Series": "Toys" + }, + { + "Date": "2021-06-13", + "Value": 671, + "Series": "Toys" + }, + { + "Date": "2021-06-22", + "Value": 671, + "Series": "Toys" + }, + { + "Date": "2021-07-01", + "Value": 676, + "Series": "Toys" + }, + { + "Date": "2021-07-10", + "Value": 685, + "Series": "Toys" + }, + { + "Date": "2021-07-19", + "Value": 689, + "Series": "Toys" + }, + { + "Date": "2021-07-28", + "Value": 706, + "Series": "Toys" + }, + { + "Date": "2021-08-07", + "Value": 715, + "Series": "Toys" + }, + { + "Date": "2021-08-16", + "Value": 718, + "Series": "Toys" + }, + { + "Date": "2021-08-25", + "Value": 734, + "Series": "Toys" + }, + { + "Date": "2021-09-03", + "Value": 749, + "Series": "Toys" + }, + { + "Date": "2021-09-12", + "Value": 773, + "Series": "Toys" + }, + { + "Date": "2021-09-21", + "Value": 797, + "Series": "Toys" + }, + { + "Date": "2021-09-30", + "Value": 818, + "Series": "Toys" + }, + { + "Date": "2021-10-09", + "Value": 834, + "Series": "Toys" + }, + { + "Date": "2021-10-19", + "Value": 850, + "Series": "Toys" + }, + { + "Date": "2021-10-28", + "Value": 875, + "Series": "Toys" + }, + { + "Date": "2021-11-06", + "Value": 904, + "Series": "Toys" + }, + { + "Date": "2021-11-15", + "Value": 929, + "Series": "Toys" + }, + { + "Date": "2021-11-24", + "Value": 953, + "Series": "Toys" + }, + { + "Date": "2021-12-03", + "Value": 957, + "Series": "Toys" + }, + { + "Date": "2021-12-12", + "Value": 968, + "Series": "Toys" + }, + { + "Date": "2021-12-21", + "Value": 978, + "Series": "Toys" + }, + { + "Date": "2021-12-31", + "Value": 981, + "Series": "Toys" + }, + { + "Date": "2022-01-09", + "Value": 989, + "Series": "Toys" + }, + { + "Date": "2022-01-18", + "Value": 988, + "Series": "Toys" + }, + { + "Date": "2022-01-27", + "Value": 1003, + "Series": "Toys" + }, + { + "Date": "2022-02-05", + "Value": 1027, + "Series": "Toys" + }, + { + "Date": "2022-02-14", + "Value": 1047, + "Series": "Toys" + }, + { + "Date": "2022-02-23", + "Value": 1066, + "Series": "Toys" + }, + { + "Date": "2022-03-04", + "Value": 1089, + "Series": "Toys" + }, + { + "Date": "2022-03-14", + "Value": 1093, + "Series": "Toys" + }, + { + "Date": "2022-03-23", + "Value": 1109, + "Series": "Toys" + }, + { + "Date": "2022-04-01", + "Value": 1134, + "Series": "Toys" + }, + { + "Date": "2022-04-10", + "Value": 1138, + "Series": "Toys" + }, + { + "Date": "2022-04-19", + "Value": 1129, + "Series": "Toys" + }, + { + "Date": "2022-04-28", + "Value": 1140, + "Series": "Toys" + }, + { + "Date": "2022-05-07", + "Value": 1140, + "Series": "Toys" + }, + { + "Date": "2022-05-16", + "Value": 1155, + "Series": "Toys" + }, + { + "Date": "2022-05-26", + "Value": 1178, + "Series": "Toys" + }, + { + "Date": "2022-06-04", + "Value": 1194, + "Series": "Toys" + }, + { + "Date": "2022-06-13", + "Value": 1217, + "Series": "Toys" + }, + { + "Date": "2022-06-22", + "Value": 1220, + "Series": "Toys" + }, + { + "Date": "2022-07-01", + "Value": 1213, + "Series": "Toys" + }, + { + "Date": "2022-07-10", + "Value": 1199, + "Series": "Toys" + }, + { + "Date": "2022-07-19", + "Value": 1197, + "Series": "Toys" + }, + { + "Date": "2022-07-28", + "Value": 1201, + "Series": "Toys" + }, + { + "Date": "2022-08-07", + "Value": 1207, + "Series": "Toys" + }, + { + "Date": "2022-08-16", + "Value": 1203, + "Series": "Toys" + }, + { + "Date": "2022-08-25", + "Value": 1200, + "Series": "Toys" + }, + { + "Date": "2022-09-03", + "Value": 1187, + "Series": "Toys" + }, + { + "Date": "2022-09-12", + "Value": 1182, + "Series": "Toys" + }, + { + "Date": "2022-09-21", + "Value": 1172, + "Series": "Toys" + }, + { + "Date": "2022-09-30", + "Value": 1159, + "Series": "Toys" + }, + { + "Date": "2022-10-09", + "Value": 1149, + "Series": "Toys" + }, + { + "Date": "2022-10-19", + "Value": 1143, + "Series": "Toys" + }, + { + "Date": "2022-10-28", + "Value": 1136, + "Series": "Toys" + }, + { + "Date": "2022-11-06", + "Value": 1146, + "Series": "Toys" + }, + { + "Date": "2022-11-15", + "Value": 1162, + "Series": "Toys" + }, + { + "Date": "2022-11-24", + "Value": 1165, + "Series": "Toys" + }, + { + "Date": "2022-12-03", + "Value": 1160, + "Series": "Toys" + }, + { + "Date": "2022-12-12", + "Value": 1150, + "Series": "Toys" + }, + { + "Date": "2022-12-21", + "Value": 1155, + "Series": "Toys" + }, + { + "Date": "2020-01-01", + "Value": 155, + "Series": "Music" + }, + { + "Date": "2020-01-10", + "Value": 152, + "Series": "Music" + }, + { + "Date": "2020-01-19", + "Value": 156, + "Series": "Music" + }, + { + "Date": "2020-01-28", + "Value": 159, + "Series": "Music" + }, + { + "Date": "2020-02-06", + "Value": 164, + "Series": "Music" + }, + { + "Date": "2020-02-15", + "Value": 174, + "Series": "Music" + }, + { + "Date": "2020-02-24", + "Value": 189, + "Series": "Music" + }, + { + "Date": "2020-03-04", + "Value": 194, + "Series": "Music" + }, + { + "Date": "2020-03-14", + "Value": 193, + "Series": "Music" + }, + { + "Date": "2020-03-23", + "Value": 194, + "Series": "Music" + }, + { + "Date": "2020-04-01", + "Value": 198, + "Series": "Music" + }, + { + "Date": "2020-04-10", + "Value": 205, + "Series": "Music" + }, + { + "Date": "2020-04-19", + "Value": 219, + "Series": "Music" + }, + { + "Date": "2020-04-28", + "Value": 226, + "Series": "Music" + }, + { + "Date": "2020-05-07", + "Value": 234, + "Series": "Music" + }, + { + "Date": "2020-05-16", + "Value": 245, + "Series": "Music" + }, + { + "Date": "2020-05-26", + "Value": 259, + "Series": "Music" + }, + { + "Date": "2020-06-04", + "Value": 263, + "Series": "Music" + }, + { + "Date": "2020-06-13", + "Value": 261, + "Series": "Music" + }, + { + "Date": "2020-06-22", + "Value": 267, + "Series": "Music" + }, + { + "Date": "2020-07-01", + "Value": 275, + "Series": "Music" + }, + { + "Date": "2020-07-10", + "Value": 280, + "Series": "Music" + }, + { + "Date": "2020-07-19", + "Value": 279, + "Series": "Music" + }, + { + "Date": "2020-07-28", + "Value": 286, + "Series": "Music" + }, + { + "Date": "2020-08-07", + "Value": 297, + "Series": "Music" + }, + { + "Date": "2020-08-16", + "Value": 303, + "Series": "Music" + }, + { + "Date": "2020-08-25", + "Value": 310, + "Series": "Music" + }, + { + "Date": "2020-09-03", + "Value": 312, + "Series": "Music" + }, + { + "Date": "2020-09-12", + "Value": 315, + "Series": "Music" + }, + { + "Date": "2020-09-21", + "Value": 321, + "Series": "Music" + }, + { + "Date": "2020-09-30", + "Value": 327, + "Series": "Music" + }, + { + "Date": "2020-10-09", + "Value": 328, + "Series": "Music" + }, + { + "Date": "2020-10-19", + "Value": 327, + "Series": "Music" + }, + { + "Date": "2020-10-28", + "Value": 320, + "Series": "Music" + }, + { + "Date": "2020-11-06", + "Value": 316, + "Series": "Music" + }, + { + "Date": "2020-11-15", + "Value": 316, + "Series": "Music" + }, + { + "Date": "2020-11-24", + "Value": 319, + "Series": "Music" + }, + { + "Date": "2020-12-03", + "Value": 324, + "Series": "Music" + }, + { + "Date": "2020-12-12", + "Value": 333, + "Series": "Music" + }, + { + "Date": "2020-12-21", + "Value": 348, + "Series": "Music" + }, + { + "Date": "2020-12-31", + "Value": 366, + "Series": "Music" + }, + { + "Date": "2021-01-09", + "Value": 379, + "Series": "Music" + }, + { + "Date": "2021-01-18", + "Value": 395, + "Series": "Music" + }, + { + "Date": "2021-01-27", + "Value": 402, + "Series": "Music" + }, + { + "Date": "2021-02-05", + "Value": 406, + "Series": "Music" + }, + { + "Date": "2021-02-14", + "Value": 407, + "Series": "Music" + }, + { + "Date": "2021-02-23", + "Value": 417, + "Series": "Music" + }, + { + "Date": "2021-03-04", + "Value": 433, + "Series": "Music" + }, + { + "Date": "2021-03-14", + "Value": 438, + "Series": "Music" + }, + { + "Date": "2021-03-23", + "Value": 447, + "Series": "Music" + }, + { + "Date": "2021-04-01", + "Value": 447, + "Series": "Music" + }, + { + "Date": "2021-04-10", + "Value": 454, + "Series": "Music" + }, + { + "Date": "2021-04-19", + "Value": 466, + "Series": "Music" + }, + { + "Date": "2021-04-28", + "Value": 481, + "Series": "Music" + }, + { + "Date": "2021-05-07", + "Value": 487, + "Series": "Music" + }, + { + "Date": "2021-05-16", + "Value": 498, + "Series": "Music" + }, + { + "Date": "2021-05-26", + "Value": 506, + "Series": "Music" + }, + { + "Date": "2021-06-04", + "Value": 506, + "Series": "Music" + }, + { + "Date": "2021-06-13", + "Value": 515, + "Series": "Music" + }, + { + "Date": "2021-06-22", + "Value": 522, + "Series": "Music" + }, + { + "Date": "2021-07-01", + "Value": 522, + "Series": "Music" + }, + { + "Date": "2021-07-10", + "Value": 521, + "Series": "Music" + }, + { + "Date": "2021-07-19", + "Value": 517, + "Series": "Music" + }, + { + "Date": "2021-07-28", + "Value": 510, + "Series": "Music" + }, + { + "Date": "2021-08-07", + "Value": 514, + "Series": "Music" + }, + { + "Date": "2021-08-16", + "Value": 526, + "Series": "Music" + }, + { + "Date": "2021-08-25", + "Value": 530, + "Series": "Music" + }, + { + "Date": "2021-09-03", + "Value": 532, + "Series": "Music" + }, + { + "Date": "2021-09-12", + "Value": 531, + "Series": "Music" + }, + { + "Date": "2021-09-21", + "Value": 530, + "Series": "Music" + }, + { + "Date": "2021-09-30", + "Value": 531, + "Series": "Music" + }, + { + "Date": "2021-10-09", + "Value": 540, + "Series": "Music" + }, + { + "Date": "2021-10-19", + "Value": 553, + "Series": "Music" + }, + { + "Date": "2021-10-28", + "Value": 564, + "Series": "Music" + }, + { + "Date": "2021-11-06", + "Value": 571, + "Series": "Music" + }, + { + "Date": "2021-11-15", + "Value": 573, + "Series": "Music" + }, + { + "Date": "2021-11-24", + "Value": 571, + "Series": "Music" + }, + { + "Date": "2021-12-03", + "Value": 576, + "Series": "Music" + }, + { + "Date": "2021-12-12", + "Value": 581, + "Series": "Music" + }, + { + "Date": "2021-12-21", + "Value": 583, + "Series": "Music" + }, + { + "Date": "2021-12-31", + "Value": 589, + "Series": "Music" + }, + { + "Date": "2022-01-09", + "Value": 598, + "Series": "Music" + }, + { + "Date": "2022-01-18", + "Value": 606, + "Series": "Music" + }, + { + "Date": "2022-01-27", + "Value": 619, + "Series": "Music" + }, + { + "Date": "2022-02-05", + "Value": 623, + "Series": "Music" + }, + { + "Date": "2022-02-14", + "Value": 630, + "Series": "Music" + }, + { + "Date": "2022-02-23", + "Value": 637, + "Series": "Music" + }, + { + "Date": "2022-03-04", + "Value": 647, + "Series": "Music" + }, + { + "Date": "2022-03-14", + "Value": 658, + "Series": "Music" + }, + { + "Date": "2022-03-23", + "Value": 663, + "Series": "Music" + }, + { + "Date": "2022-04-01", + "Value": 666, + "Series": "Music" + }, + { + "Date": "2022-04-10", + "Value": 663, + "Series": "Music" + }, + { + "Date": "2022-04-19", + "Value": 662, + "Series": "Music" + }, + { + "Date": "2022-04-28", + "Value": 669, + "Series": "Music" + }, + { + "Date": "2022-05-07", + "Value": 669, + "Series": "Music" + }, + { + "Date": "2022-05-16", + "Value": 679, + "Series": "Music" + }, + { + "Date": "2022-05-26", + "Value": 680, + "Series": "Music" + }, + { + "Date": "2022-06-04", + "Value": 684, + "Series": "Music" + }, + { + "Date": "2022-06-13", + "Value": 683, + "Series": "Music" + }, + { + "Date": "2022-06-22", + "Value": 677, + "Series": "Music" + }, + { + "Date": "2022-07-01", + "Value": 675, + "Series": "Music" + }, + { + "Date": "2022-07-10", + "Value": 682, + "Series": "Music" + }, + { + "Date": "2022-07-19", + "Value": 688, + "Series": "Music" + }, + { + "Date": "2022-07-28", + "Value": 700, + "Series": "Music" + }, + { + "Date": "2022-08-07", + "Value": 704, + "Series": "Music" + }, + { + "Date": "2022-08-16", + "Value": 704, + "Series": "Music" + }, + { + "Date": "2022-08-25", + "Value": 711, + "Series": "Music" + }, + { + "Date": "2022-09-03", + "Value": 712, + "Series": "Music" + }, + { + "Date": "2022-09-12", + "Value": 707, + "Series": "Music" + }, + { + "Date": "2022-09-21", + "Value": 699, + "Series": "Music" + }, + { + "Date": "2022-09-30", + "Value": 701, + "Series": "Music" + }, + { + "Date": "2022-10-09", + "Value": 709, + "Series": "Music" + }, + { + "Date": "2022-10-19", + "Value": 713, + "Series": "Music" + }, + { + "Date": "2022-10-28", + "Value": 722, + "Series": "Music" + }, + { + "Date": "2022-11-06", + "Value": 728, + "Series": "Music" + }, + { + "Date": "2022-11-15", + "Value": 738, + "Series": "Music" + }, + { + "Date": "2022-11-24", + "Value": 750, + "Series": "Music" + }, + { + "Date": "2022-12-03", + "Value": 763, + "Series": "Music" + }, + { + "Date": "2022-12-12", + "Value": 765, + "Series": "Music" + }, + { + "Date": "2022-12-21", + "Value": 764, + "Series": "Music" + }, + { + "Date": "2020-01-01", + "Value": 248, + "Series": "Movies" + }, + { + "Date": "2020-01-10", + "Value": 241, + "Series": "Movies" + }, + { + "Date": "2020-01-19", + "Value": 235, + "Series": "Movies" + }, + { + "Date": "2020-01-28", + "Value": 244, + "Series": "Movies" + }, + { + "Date": "2020-02-06", + "Value": 248, + "Series": "Movies" + }, + { + "Date": "2020-02-15", + "Value": 245, + "Series": "Movies" + }, + { + "Date": "2020-02-24", + "Value": 241, + "Series": "Movies" + }, + { + "Date": "2020-03-04", + "Value": 239, + "Series": "Movies" + }, + { + "Date": "2020-03-14", + "Value": 238, + "Series": "Movies" + }, + { + "Date": "2020-03-23", + "Value": 249, + "Series": "Movies" + }, + { + "Date": "2020-04-01", + "Value": 264, + "Series": "Movies" + }, + { + "Date": "2020-04-10", + "Value": 263, + "Series": "Movies" + }, + { + "Date": "2020-04-19", + "Value": 253, + "Series": "Movies" + }, + { + "Date": "2020-04-28", + "Value": 238, + "Series": "Movies" + }, + { + "Date": "2020-05-07", + "Value": 220, + "Series": "Movies" + }, + { + "Date": "2020-05-16", + "Value": 204, + "Series": "Movies" + }, + { + "Date": "2020-05-26", + "Value": 207, + "Series": "Movies" + }, + { + "Date": "2020-06-04", + "Value": 204, + "Series": "Movies" + }, + { + "Date": "2020-06-13", + "Value": 213, + "Series": "Movies" + }, + { + "Date": "2020-06-22", + "Value": 208, + "Series": "Movies" + }, + { + "Date": "2020-07-01", + "Value": 203, + "Series": "Movies" + }, + { + "Date": "2020-07-10", + "Value": 196, + "Series": "Movies" + }, + { + "Date": "2020-07-19", + "Value": 186, + "Series": "Movies" + }, + { + "Date": "2020-07-28", + "Value": 189, + "Series": "Movies" + }, + { + "Date": "2020-08-07", + "Value": 198, + "Series": "Movies" + }, + { + "Date": "2020-08-16", + "Value": 199, + "Series": "Movies" + }, + { + "Date": "2020-08-25", + "Value": 200, + "Series": "Movies" + }, + { + "Date": "2020-09-03", + "Value": 209, + "Series": "Movies" + }, + { + "Date": "2020-09-12", + "Value": 211, + "Series": "Movies" + }, + { + "Date": "2020-09-21", + "Value": 217, + "Series": "Movies" + }, + { + "Date": "2020-09-30", + "Value": 231, + "Series": "Movies" + }, + { + "Date": "2020-10-09", + "Value": 246, + "Series": "Movies" + }, + { + "Date": "2020-10-19", + "Value": 267, + "Series": "Movies" + }, + { + "Date": "2020-10-28", + "Value": 280, + "Series": "Movies" + }, + { + "Date": "2020-11-06", + "Value": 288, + "Series": "Movies" + }, + { + "Date": "2020-11-15", + "Value": 305, + "Series": "Movies" + }, + { + "Date": "2020-11-24", + "Value": 308, + "Series": "Movies" + }, + { + "Date": "2020-12-03", + "Value": 318, + "Series": "Movies" + }, + { + "Date": "2020-12-12", + "Value": 337, + "Series": "Movies" + }, + { + "Date": "2020-12-21", + "Value": 339, + "Series": "Movies" + }, + { + "Date": "2020-12-31", + "Value": 340, + "Series": "Movies" + }, + { + "Date": "2021-01-09", + "Value": 348, + "Series": "Movies" + }, + { + "Date": "2021-01-18", + "Value": 361, + "Series": "Movies" + }, + { + "Date": "2021-01-27", + "Value": 361, + "Series": "Movies" + }, + { + "Date": "2021-02-05", + "Value": 359, + "Series": "Movies" + }, + { + "Date": "2021-02-14", + "Value": 365, + "Series": "Movies" + }, + { + "Date": "2021-02-23", + "Value": 381, + "Series": "Movies" + }, + { + "Date": "2021-03-04", + "Value": 398, + "Series": "Movies" + }, + { + "Date": "2021-03-14", + "Value": 402, + "Series": "Movies" + }, + { + "Date": "2021-03-23", + "Value": 401, + "Series": "Movies" + }, + { + "Date": "2021-04-01", + "Value": 408, + "Series": "Movies" + }, + { + "Date": "2021-04-10", + "Value": 418, + "Series": "Movies" + }, + { + "Date": "2021-04-19", + "Value": 421, + "Series": "Movies" + }, + { + "Date": "2021-04-28", + "Value": 417, + "Series": "Movies" + }, + { + "Date": "2021-05-07", + "Value": 421, + "Series": "Movies" + }, + { + "Date": "2021-05-16", + "Value": 414, + "Series": "Movies" + }, + { + "Date": "2021-05-26", + "Value": 406, + "Series": "Movies" + }, + { + "Date": "2021-06-04", + "Value": 402, + "Series": "Movies" + }, + { + "Date": "2021-06-13", + "Value": 406, + "Series": "Movies" + }, + { + "Date": "2021-06-22", + "Value": 412, + "Series": "Movies" + }, + { + "Date": "2021-07-01", + "Value": 406, + "Series": "Movies" + }, + { + "Date": "2021-07-10", + "Value": 402, + "Series": "Movies" + }, + { + "Date": "2021-07-19", + "Value": 405, + "Series": "Movies" + }, + { + "Date": "2021-07-28", + "Value": 412, + "Series": "Movies" + }, + { + "Date": "2021-08-07", + "Value": 407, + "Series": "Movies" + }, + { + "Date": "2021-08-16", + "Value": 405, + "Series": "Movies" + }, + { + "Date": "2021-08-25", + "Value": 394, + "Series": "Movies" + }, + { + "Date": "2021-09-03", + "Value": 381, + "Series": "Movies" + }, + { + "Date": "2021-09-12", + "Value": 368, + "Series": "Movies" + }, + { + "Date": "2021-09-21", + "Value": 363, + "Series": "Movies" + }, + { + "Date": "2021-09-30", + "Value": 359, + "Series": "Movies" + }, + { + "Date": "2021-10-09", + "Value": 357, + "Series": "Movies" + }, + { + "Date": "2021-10-19", + "Value": 350, + "Series": "Movies" + }, + { + "Date": "2021-10-28", + "Value": 348, + "Series": "Movies" + }, + { + "Date": "2021-11-06", + "Value": 338, + "Series": "Movies" + }, + { + "Date": "2021-11-15", + "Value": 325, + "Series": "Movies" + }, + { + "Date": "2021-11-24", + "Value": 322, + "Series": "Movies" + }, + { + "Date": "2021-12-03", + "Value": 321, + "Series": "Movies" + }, + { + "Date": "2021-12-12", + "Value": 315, + "Series": "Movies" + }, + { + "Date": "2021-12-21", + "Value": 311, + "Series": "Movies" + }, + { + "Date": "2021-12-31", + "Value": 318, + "Series": "Movies" + }, + { + "Date": "2022-01-09", + "Value": 322, + "Series": "Movies" + }, + { + "Date": "2022-01-18", + "Value": 334, + "Series": "Movies" + }, + { + "Date": "2022-01-27", + "Value": 342, + "Series": "Movies" + }, + { + "Date": "2022-02-05", + "Value": 353, + "Series": "Movies" + }, + { + "Date": "2022-02-14", + "Value": 372, + "Series": "Movies" + }, + { + "Date": "2022-02-23", + "Value": 392, + "Series": "Movies" + }, + { + "Date": "2022-03-04", + "Value": 408, + "Series": "Movies" + }, + { + "Date": "2022-03-14", + "Value": 415, + "Series": "Movies" + }, + { + "Date": "2022-03-23", + "Value": 416, + "Series": "Movies" + }, + { + "Date": "2022-04-01", + "Value": 411, + "Series": "Movies" + }, + { + "Date": "2022-04-10", + "Value": 410, + "Series": "Movies" + }, + { + "Date": "2022-04-19", + "Value": 412, + "Series": "Movies" + }, + { + "Date": "2022-04-28", + "Value": 418, + "Series": "Movies" + }, + { + "Date": "2022-05-07", + "Value": 436, + "Series": "Movies" + }, + { + "Date": "2022-05-16", + "Value": 457, + "Series": "Movies" + }, + { + "Date": "2022-05-26", + "Value": 484, + "Series": "Movies" + }, + { + "Date": "2022-06-04", + "Value": 491, + "Series": "Movies" + }, + { + "Date": "2022-06-13", + "Value": 497, + "Series": "Movies" + }, + { + "Date": "2022-06-22", + "Value": 493, + "Series": "Movies" + }, + { + "Date": "2022-07-01", + "Value": 499, + "Series": "Movies" + }, + { + "Date": "2022-07-10", + "Value": 497, + "Series": "Movies" + }, + { + "Date": "2022-07-19", + "Value": 503, + "Series": "Movies" + }, + { + "Date": "2022-07-28", + "Value": 510, + "Series": "Movies" + }, + { + "Date": "2022-08-07", + "Value": 510, + "Series": "Movies" + }, + { + "Date": "2022-08-16", + "Value": 519, + "Series": "Movies" + }, + { + "Date": "2022-08-25", + "Value": 528, + "Series": "Movies" + }, + { + "Date": "2022-09-03", + "Value": 525, + "Series": "Movies" + }, + { + "Date": "2022-09-12", + "Value": 536, + "Series": "Movies" + }, + { + "Date": "2022-09-21", + "Value": 546, + "Series": "Movies" + }, + { + "Date": "2022-09-30", + "Value": 564, + "Series": "Movies" + }, + { + "Date": "2022-10-09", + "Value": 575, + "Series": "Movies" + }, + { + "Date": "2022-10-19", + "Value": 576, + "Series": "Movies" + }, + { + "Date": "2022-10-28", + "Value": 574, + "Series": "Movies" + }, + { + "Date": "2022-11-06", + "Value": 577, + "Series": "Movies" + }, + { + "Date": "2022-11-15", + "Value": 587, + "Series": "Movies" + }, + { + "Date": "2022-11-24", + "Value": 598, + "Series": "Movies" + }, + { + "Date": "2022-12-03", + "Value": 609, + "Series": "Movies" + }, + { + "Date": "2022-12-12", + "Value": 621, + "Series": "Movies" + }, + { + "Date": "2022-12-21", + "Value": 623, + "Series": "Movies" + }, + { + "Date": "2020-01-01", + "Value": 127, + "Series": "Software" + }, + { + "Date": "2020-01-10", + "Value": 119, + "Series": "Software" + }, + { + "Date": "2020-01-19", + "Value": 110, + "Series": "Software" + }, + { + "Date": "2020-01-28", + "Value": 116, + "Series": "Software" + }, + { + "Date": "2020-02-06", + "Value": 134, + "Series": "Software" + }, + { + "Date": "2020-02-15", + "Value": 141, + "Series": "Software" + }, + { + "Date": "2020-02-24", + "Value": 136, + "Series": "Software" + }, + { + "Date": "2020-03-04", + "Value": 124, + "Series": "Software" + }, + { + "Date": "2020-03-14", + "Value": 109, + "Series": "Software" + }, + { + "Date": "2020-03-23", + "Value": 97, + "Series": "Software" + }, + { + "Date": "2020-04-01", + "Value": 94, + "Series": "Software" + }, + { + "Date": "2020-04-10", + "Value": 95, + "Series": "Software" + }, + { + "Date": "2020-04-19", + "Value": 103, + "Series": "Software" + }, + { + "Date": "2020-04-28", + "Value": 103, + "Series": "Software" + }, + { + "Date": "2020-05-07", + "Value": 94, + "Series": "Software" + }, + { + "Date": "2020-05-16", + "Value": 101, + "Series": "Software" + }, + { + "Date": "2020-05-26", + "Value": 118, + "Series": "Software" + }, + { + "Date": "2020-06-04", + "Value": 139, + "Series": "Software" + }, + { + "Date": "2020-06-13", + "Value": 151, + "Series": "Software" + }, + { + "Date": "2020-06-22", + "Value": 171, + "Series": "Software" + }, + { + "Date": "2020-07-01", + "Value": 189, + "Series": "Software" + }, + { + "Date": "2020-07-10", + "Value": 201, + "Series": "Software" + }, + { + "Date": "2020-07-19", + "Value": 205, + "Series": "Software" + }, + { + "Date": "2020-07-28", + "Value": 219, + "Series": "Software" + }, + { + "Date": "2020-08-07", + "Value": 242, + "Series": "Software" + }, + { + "Date": "2020-08-16", + "Value": 268, + "Series": "Software" + }, + { + "Date": "2020-08-25", + "Value": 276, + "Series": "Software" + }, + { + "Date": "2020-09-03", + "Value": 293, + "Series": "Software" + }, + { + "Date": "2020-09-12", + "Value": 297, + "Series": "Software" + }, + { + "Date": "2020-09-21", + "Value": 301, + "Series": "Software" + }, + { + "Date": "2020-09-30", + "Value": 302, + "Series": "Software" + }, + { + "Date": "2020-10-09", + "Value": 304, + "Series": "Software" + }, + { + "Date": "2020-10-19", + "Value": 314, + "Series": "Software" + }, + { + "Date": "2020-10-28", + "Value": 318, + "Series": "Software" + }, + { + "Date": "2020-11-06", + "Value": 319, + "Series": "Software" + }, + { + "Date": "2020-11-15", + "Value": 316, + "Series": "Software" + }, + { + "Date": "2020-11-24", + "Value": 312, + "Series": "Software" + }, + { + "Date": "2020-12-03", + "Value": 325, + "Series": "Software" + }, + { + "Date": "2020-12-12", + "Value": 337, + "Series": "Software" + }, + { + "Date": "2020-12-21", + "Value": 342, + "Series": "Software" + }, + { + "Date": "2020-12-31", + "Value": 359, + "Series": "Software" + }, + { + "Date": "2021-01-09", + "Value": 360, + "Series": "Software" + }, + { + "Date": "2021-01-18", + "Value": 364, + "Series": "Software" + }, + { + "Date": "2021-01-27", + "Value": 362, + "Series": "Software" + }, + { + "Date": "2021-02-05", + "Value": 367, + "Series": "Software" + }, + { + "Date": "2021-02-14", + "Value": 364, + "Series": "Software" + }, + { + "Date": "2021-02-23", + "Value": 356, + "Series": "Software" + }, + { + "Date": "2021-03-04", + "Value": 357, + "Series": "Software" + }, + { + "Date": "2021-03-14", + "Value": 371, + "Series": "Software" + }, + { + "Date": "2021-03-23", + "Value": 376, + "Series": "Software" + }, + { + "Date": "2021-04-01", + "Value": 370, + "Series": "Software" + }, + { + "Date": "2021-04-10", + "Value": 361, + "Series": "Software" + }, + { + "Date": "2021-04-19", + "Value": 361, + "Series": "Software" + }, + { + "Date": "2021-04-28", + "Value": 352, + "Series": "Software" + }, + { + "Date": "2021-05-07", + "Value": 353, + "Series": "Software" + }, + { + "Date": "2021-05-16", + "Value": 357, + "Series": "Software" + }, + { + "Date": "2021-05-26", + "Value": 372, + "Series": "Software" + }, + { + "Date": "2021-06-04", + "Value": 387, + "Series": "Software" + }, + { + "Date": "2021-06-13", + "Value": 391, + "Series": "Software" + }, + { + "Date": "2021-06-22", + "Value": 391, + "Series": "Software" + }, + { + "Date": "2021-07-01", + "Value": 399, + "Series": "Software" + }, + { + "Date": "2021-07-10", + "Value": 397, + "Series": "Software" + }, + { + "Date": "2021-07-19", + "Value": 397, + "Series": "Software" + }, + { + "Date": "2021-07-28", + "Value": 395, + "Series": "Software" + }, + { + "Date": "2021-08-07", + "Value": 395, + "Series": "Software" + }, + { + "Date": "2021-08-16", + "Value": 390, + "Series": "Software" + }, + { + "Date": "2021-08-25", + "Value": 393, + "Series": "Software" + }, + { + "Date": "2021-09-03", + "Value": 410, + "Series": "Software" + }, + { + "Date": "2021-09-12", + "Value": 416, + "Series": "Software" + }, + { + "Date": "2021-09-21", + "Value": 433, + "Series": "Software" + }, + { + "Date": "2021-09-30", + "Value": 435, + "Series": "Software" + }, + { + "Date": "2021-10-09", + "Value": 444, + "Series": "Software" + }, + { + "Date": "2021-10-19", + "Value": 451, + "Series": "Software" + }, + { + "Date": "2021-10-28", + "Value": 461, + "Series": "Software" + }, + { + "Date": "2021-11-06", + "Value": 479, + "Series": "Software" + }, + { + "Date": "2021-11-15", + "Value": 492, + "Series": "Software" + }, + { + "Date": "2021-11-24", + "Value": 500, + "Series": "Software" + }, + { + "Date": "2021-12-03", + "Value": 504, + "Series": "Software" + }, + { + "Date": "2021-12-12", + "Value": 521, + "Series": "Software" + }, + { + "Date": "2021-12-21", + "Value": 545, + "Series": "Software" + }, + { + "Date": "2021-12-31", + "Value": 559, + "Series": "Software" + }, + { + "Date": "2022-01-09", + "Value": 563, + "Series": "Software" + }, + { + "Date": "2022-01-18", + "Value": 560, + "Series": "Software" + }, + { + "Date": "2022-01-27", + "Value": 568, + "Series": "Software" + }, + { + "Date": "2022-02-05", + "Value": 564, + "Series": "Software" + }, + { + "Date": "2022-02-14", + "Value": 558, + "Series": "Software" + }, + { + "Date": "2022-02-23", + "Value": 555, + "Series": "Software" + }, + { + "Date": "2022-03-04", + "Value": 558, + "Series": "Software" + }, + { + "Date": "2022-03-14", + "Value": 570, + "Series": "Software" + }, + { + "Date": "2022-03-23", + "Value": 567, + "Series": "Software" + }, + { + "Date": "2022-04-01", + "Value": 576, + "Series": "Software" + }, + { + "Date": "2022-04-10", + "Value": 591, + "Series": "Software" + }, + { + "Date": "2022-04-19", + "Value": 613, + "Series": "Software" + }, + { + "Date": "2022-04-28", + "Value": 639, + "Series": "Software" + }, + { + "Date": "2022-05-07", + "Value": 656, + "Series": "Software" + }, + { + "Date": "2022-05-16", + "Value": 662, + "Series": "Software" + }, + { + "Date": "2022-05-26", + "Value": 667, + "Series": "Software" + }, + { + "Date": "2022-06-04", + "Value": 663, + "Series": "Software" + }, + { + "Date": "2022-06-13", + "Value": 654, + "Series": "Software" + }, + { + "Date": "2022-06-22", + "Value": 641, + "Series": "Software" + }, + { + "Date": "2022-07-01", + "Value": 636, + "Series": "Software" + }, + { + "Date": "2022-07-10", + "Value": 624, + "Series": "Software" + }, + { + "Date": "2022-07-19", + "Value": 628, + "Series": "Software" + }, + { + "Date": "2022-07-28", + "Value": 630, + "Series": "Software" + }, + { + "Date": "2022-08-07", + "Value": 628, + "Series": "Software" + }, + { + "Date": "2022-08-16", + "Value": 636, + "Series": "Software" + }, + { + "Date": "2022-08-25", + "Value": 645, + "Series": "Software" + }, + { + "Date": "2022-09-03", + "Value": 660, + "Series": "Software" + }, + { + "Date": "2022-09-12", + "Value": 673, + "Series": "Software" + }, + { + "Date": "2022-09-21", + "Value": 691, + "Series": "Software" + }, + { + "Date": "2022-09-30", + "Value": 691, + "Series": "Software" + }, + { + "Date": "2022-10-09", + "Value": 681, + "Series": "Software" + }, + { + "Date": "2022-10-19", + "Value": 682, + "Series": "Software" + }, + { + "Date": "2022-10-28", + "Value": 698, + "Series": "Software" + }, + { + "Date": "2022-11-06", + "Value": 710, + "Series": "Software" + }, + { + "Date": "2022-11-15", + "Value": 718, + "Series": "Software" + }, + { + "Date": "2022-11-24", + "Value": 737, + "Series": "Software" + }, + { + "Date": "2022-12-03", + "Value": 739, + "Series": "Software" + }, + { + "Date": "2022-12-12", + "Value": 746, + "Series": "Software" + }, + { + "Date": "2022-12-21", + "Value": 764, + "Series": "Software" + }, + { + "Date": "2020-01-01", + "Value": 189, + "Series": "Games" + }, + { + "Date": "2020-01-10", + "Value": 191, + "Series": "Games" + }, + { + "Date": "2020-01-19", + "Value": 199, + "Series": "Games" + }, + { + "Date": "2020-01-28", + "Value": 203, + "Series": "Games" + }, + { + "Date": "2020-02-06", + "Value": 208, + "Series": "Games" + }, + { + "Date": "2020-02-15", + "Value": 209, + "Series": "Games" + }, + { + "Date": "2020-02-24", + "Value": 209, + "Series": "Games" + }, + { + "Date": "2020-03-04", + "Value": 217, + "Series": "Games" + }, + { + "Date": "2020-03-14", + "Value": 224, + "Series": "Games" + }, + { + "Date": "2020-03-23", + "Value": 229, + "Series": "Games" + }, + { + "Date": "2020-04-01", + "Value": 239, + "Series": "Games" + }, + { + "Date": "2020-04-10", + "Value": 254, + "Series": "Games" + }, + { + "Date": "2020-04-19", + "Value": 267, + "Series": "Games" + }, + { + "Date": "2020-04-28", + "Value": 279, + "Series": "Games" + }, + { + "Date": "2020-05-07", + "Value": 294, + "Series": "Games" + }, + { + "Date": "2020-05-16", + "Value": 299, + "Series": "Games" + }, + { + "Date": "2020-05-26", + "Value": 307, + "Series": "Games" + }, + { + "Date": "2020-06-04", + "Value": 316, + "Series": "Games" + }, + { + "Date": "2020-06-13", + "Value": 330, + "Series": "Games" + }, + { + "Date": "2020-06-22", + "Value": 343, + "Series": "Games" + }, + { + "Date": "2020-07-01", + "Value": 357, + "Series": "Games" + }, + { + "Date": "2020-07-10", + "Value": 370, + "Series": "Games" + }, + { + "Date": "2020-07-19", + "Value": 376, + "Series": "Games" + }, + { + "Date": "2020-07-28", + "Value": 379, + "Series": "Games" + }, + { + "Date": "2020-08-07", + "Value": 389, + "Series": "Games" + }, + { + "Date": "2020-08-16", + "Value": 397, + "Series": "Games" + }, + { + "Date": "2020-08-25", + "Value": 406, + "Series": "Games" + }, + { + "Date": "2020-09-03", + "Value": 415, + "Series": "Games" + }, + { + "Date": "2020-09-12", + "Value": 427, + "Series": "Games" + }, + { + "Date": "2020-09-21", + "Value": 436, + "Series": "Games" + }, + { + "Date": "2020-09-30", + "Value": 440, + "Series": "Games" + }, + { + "Date": "2020-10-09", + "Value": 444, + "Series": "Games" + }, + { + "Date": "2020-10-19", + "Value": 446, + "Series": "Games" + }, + { + "Date": "2020-10-28", + "Value": 450, + "Series": "Games" + }, + { + "Date": "2020-11-06", + "Value": 461, + "Series": "Games" + }, + { + "Date": "2020-11-15", + "Value": 470, + "Series": "Games" + }, + { + "Date": "2020-11-24", + "Value": 484, + "Series": "Games" + }, + { + "Date": "2020-12-03", + "Value": 493, + "Series": "Games" + }, + { + "Date": "2020-12-12", + "Value": 500, + "Series": "Games" + }, + { + "Date": "2020-12-21", + "Value": 501, + "Series": "Games" + }, + { + "Date": "2020-12-31", + "Value": 499, + "Series": "Games" + }, + { + "Date": "2021-01-09", + "Value": 506, + "Series": "Games" + }, + { + "Date": "2021-01-18", + "Value": 512, + "Series": "Games" + }, + { + "Date": "2021-01-27", + "Value": 522, + "Series": "Games" + }, + { + "Date": "2021-02-05", + "Value": 527, + "Series": "Games" + }, + { + "Date": "2021-02-14", + "Value": 538, + "Series": "Games" + }, + { + "Date": "2021-02-23", + "Value": 543, + "Series": "Games" + }, + { + "Date": "2021-03-04", + "Value": 549, + "Series": "Games" + }, + { + "Date": "2021-03-14", + "Value": 558, + "Series": "Games" + }, + { + "Date": "2021-03-23", + "Value": 572, + "Series": "Games" + }, + { + "Date": "2021-04-01", + "Value": 587, + "Series": "Games" + }, + { + "Date": "2021-04-10", + "Value": 604, + "Series": "Games" + }, + { + "Date": "2021-04-19", + "Value": 614, + "Series": "Games" + }, + { + "Date": "2021-04-28", + "Value": 619, + "Series": "Games" + }, + { + "Date": "2021-05-07", + "Value": 628, + "Series": "Games" + }, + { + "Date": "2021-05-16", + "Value": 637, + "Series": "Games" + }, + { + "Date": "2021-05-26", + "Value": 650, + "Series": "Games" + }, + { + "Date": "2021-06-04", + "Value": 657, + "Series": "Games" + }, + { + "Date": "2021-06-13", + "Value": 667, + "Series": "Games" + }, + { + "Date": "2021-06-22", + "Value": 681, + "Series": "Games" + }, + { + "Date": "2021-07-01", + "Value": 696, + "Series": "Games" + }, + { + "Date": "2021-07-10", + "Value": 708, + "Series": "Games" + }, + { + "Date": "2021-07-19", + "Value": 713, + "Series": "Games" + }, + { + "Date": "2021-07-28", + "Value": 725, + "Series": "Games" + }, + { + "Date": "2021-08-07", + "Value": 741, + "Series": "Games" + }, + { + "Date": "2021-08-16", + "Value": 753, + "Series": "Games" + }, + { + "Date": "2021-08-25", + "Value": 763, + "Series": "Games" + }, + { + "Date": "2021-09-03", + "Value": 777, + "Series": "Games" + }, + { + "Date": "2021-09-12", + "Value": 782, + "Series": "Games" + }, + { + "Date": "2021-09-21", + "Value": 783, + "Series": "Games" + }, + { + "Date": "2021-09-30", + "Value": 784, + "Series": "Games" + }, + { + "Date": "2021-10-09", + "Value": 786, + "Series": "Games" + }, + { + "Date": "2021-10-19", + "Value": 795, + "Series": "Games" + }, + { + "Date": "2021-10-28", + "Value": 800, + "Series": "Games" + }, + { + "Date": "2021-11-06", + "Value": 811, + "Series": "Games" + }, + { + "Date": "2021-11-15", + "Value": 818, + "Series": "Games" + }, + { + "Date": "2021-11-24", + "Value": 828, + "Series": "Games" + }, + { + "Date": "2021-12-03", + "Value": 836, + "Series": "Games" + }, + { + "Date": "2021-12-12", + "Value": 849, + "Series": "Games" + }, + { + "Date": "2021-12-21", + "Value": 858, + "Series": "Games" + }, + { + "Date": "2021-12-31", + "Value": 870, + "Series": "Games" + }, + { + "Date": "2022-01-09", + "Value": 883, + "Series": "Games" + }, + { + "Date": "2022-01-18", + "Value": 896, + "Series": "Games" + }, + { + "Date": "2022-01-27", + "Value": 910, + "Series": "Games" + }, + { + "Date": "2022-02-05", + "Value": 921, + "Series": "Games" + }, + { + "Date": "2022-02-14", + "Value": 928, + "Series": "Games" + }, + { + "Date": "2022-02-23", + "Value": 939, + "Series": "Games" + }, + { + "Date": "2022-03-04", + "Value": 943, + "Series": "Games" + }, + { + "Date": "2022-03-14", + "Value": 951, + "Series": "Games" + }, + { + "Date": "2022-03-23", + "Value": 964, + "Series": "Games" + }, + { + "Date": "2022-04-01", + "Value": 969, + "Series": "Games" + }, + { + "Date": "2022-04-10", + "Value": 977, + "Series": "Games" + }, + { + "Date": "2022-04-19", + "Value": 979, + "Series": "Games" + }, + { + "Date": "2022-04-28", + "Value": 977, + "Series": "Games" + }, + { + "Date": "2022-05-07", + "Value": 984, + "Series": "Games" + }, + { + "Date": "2022-05-16", + "Value": 991, + "Series": "Games" + }, + { + "Date": "2022-05-26", + "Value": 999, + "Series": "Games" + }, + { + "Date": "2022-06-04", + "Value": 1006, + "Series": "Games" + }, + { + "Date": "2022-06-13", + "Value": 1014, + "Series": "Games" + }, + { + "Date": "2022-06-22", + "Value": 1027, + "Series": "Games" + }, + { + "Date": "2022-07-01", + "Value": 1036, + "Series": "Games" + }, + { + "Date": "2022-07-10", + "Value": 1045, + "Series": "Games" + }, + { + "Date": "2022-07-19", + "Value": 1054, + "Series": "Games" + }, + { + "Date": "2022-07-28", + "Value": 1067, + "Series": "Games" + }, + { + "Date": "2022-08-07", + "Value": 1074, + "Series": "Games" + }, + { + "Date": "2022-08-16", + "Value": 1086, + "Series": "Games" + }, + { + "Date": "2022-08-25", + "Value": 1095, + "Series": "Games" + }, + { + "Date": "2022-09-03", + "Value": 1101, + "Series": "Games" + }, + { + "Date": "2022-09-12", + "Value": 1104, + "Series": "Games" + }, + { + "Date": "2022-09-21", + "Value": 1110, + "Series": "Games" + }, + { + "Date": "2022-09-30", + "Value": 1115, + "Series": "Games" + }, + { + "Date": "2022-10-09", + "Value": 1124, + "Series": "Games" + }, + { + "Date": "2022-10-19", + "Value": 1132, + "Series": "Games" + }, + { + "Date": "2022-10-28", + "Value": 1138, + "Series": "Games" + }, + { + "Date": "2022-11-06", + "Value": 1149, + "Series": "Games" + }, + { + "Date": "2022-11-15", + "Value": 1159, + "Series": "Games" + }, + { + "Date": "2022-11-24", + "Value": 1165, + "Series": "Games" + }, + { + "Date": "2022-12-03", + "Value": 1175, + "Series": "Games" + }, + { + "Date": "2022-12-12", + "Value": 1181, + "Series": "Games" + }, + { + "Date": "2022-12-21", + "Value": 1193, + "Series": "Games" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/area-chart/04-card40.flint.json b/test-harness/excel/evaluations/inputs/area-chart/04-card40.flint.json new file mode 100644 index 00000000..7ccea711 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/area-chart/04-card40.flint.json @@ -0,0 +1,623 @@ +{ + "semantic_types": { + "Date": "Date", + "Value": "Quantity", + "Series": "Category" + }, + "chart_spec": { + "chartType": "Area Chart", + "encodings": { + "x": "Date", + "y": "Value", + "color": "Series" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Date": "2020-01-01", + "Value": 145, + "Series": "Electronics" + }, + { + "Date": "2020-01-28", + "Value": 138, + "Series": "Electronics" + }, + { + "Date": "2020-02-24", + "Value": 129, + "Series": "Electronics" + }, + { + "Date": "2020-03-23", + "Value": 117, + "Series": "Electronics" + }, + { + "Date": "2020-04-19", + "Value": 113, + "Series": "Electronics" + }, + { + "Date": "2020-05-16", + "Value": 103, + "Series": "Electronics" + }, + { + "Date": "2020-06-13", + "Value": 92, + "Series": "Electronics" + }, + { + "Date": "2020-07-10", + "Value": 98, + "Series": "Electronics" + }, + { + "Date": "2020-08-07", + "Value": 96, + "Series": "Electronics" + }, + { + "Date": "2020-09-03", + "Value": 103, + "Series": "Electronics" + }, + { + "Date": "2020-09-30", + "Value": 100, + "Series": "Electronics" + }, + { + "Date": "2020-10-28", + "Value": 112, + "Series": "Electronics" + }, + { + "Date": "2020-11-24", + "Value": 129, + "Series": "Electronics" + }, + { + "Date": "2020-12-21", + "Value": 147, + "Series": "Electronics" + }, + { + "Date": "2021-01-18", + "Value": 172, + "Series": "Electronics" + }, + { + "Date": "2021-02-14", + "Value": 182, + "Series": "Electronics" + }, + { + "Date": "2021-03-14", + "Value": 199, + "Series": "Electronics" + }, + { + "Date": "2021-04-10", + "Value": 209, + "Series": "Electronics" + }, + { + "Date": "2021-05-07", + "Value": 210, + "Series": "Electronics" + }, + { + "Date": "2021-06-04", + "Value": 203, + "Series": "Electronics" + }, + { + "Date": "2021-07-01", + "Value": 199, + "Series": "Electronics" + }, + { + "Date": "2021-07-28", + "Value": 202, + "Series": "Electronics" + }, + { + "Date": "2021-08-25", + "Value": 200, + "Series": "Electronics" + }, + { + "Date": "2021-09-21", + "Value": 192, + "Series": "Electronics" + }, + { + "Date": "2021-10-19", + "Value": 180, + "Series": "Electronics" + }, + { + "Date": "2021-11-15", + "Value": 178, + "Series": "Electronics" + }, + { + "Date": "2021-12-12", + "Value": 184, + "Series": "Electronics" + }, + { + "Date": "2022-01-09", + "Value": 185, + "Series": "Electronics" + }, + { + "Date": "2022-02-05", + "Value": 190, + "Series": "Electronics" + }, + { + "Date": "2022-03-04", + "Value": 203, + "Series": "Electronics" + }, + { + "Date": "2022-04-01", + "Value": 206, + "Series": "Electronics" + }, + { + "Date": "2022-04-28", + "Value": 214, + "Series": "Electronics" + }, + { + "Date": "2022-05-26", + "Value": 224, + "Series": "Electronics" + }, + { + "Date": "2022-06-22", + "Value": 233, + "Series": "Electronics" + }, + { + "Date": "2022-07-19", + "Value": 232, + "Series": "Electronics" + }, + { + "Date": "2022-08-16", + "Value": 223, + "Series": "Electronics" + }, + { + "Date": "2022-09-12", + "Value": 223, + "Series": "Electronics" + }, + { + "Date": "2022-10-09", + "Value": 215, + "Series": "Electronics" + }, + { + "Date": "2022-11-06", + "Value": 217, + "Series": "Electronics" + }, + { + "Date": "2022-12-03", + "Value": 214, + "Series": "Electronics" + }, + { + "Date": "2020-01-01", + "Value": 209, + "Series": "Clothing" + }, + { + "Date": "2020-01-28", + "Value": 217, + "Series": "Clothing" + }, + { + "Date": "2020-02-24", + "Value": 217, + "Series": "Clothing" + }, + { + "Date": "2020-03-23", + "Value": 225, + "Series": "Clothing" + }, + { + "Date": "2020-04-19", + "Value": 235, + "Series": "Clothing" + }, + { + "Date": "2020-05-16", + "Value": 243, + "Series": "Clothing" + }, + { + "Date": "2020-06-13", + "Value": 245, + "Series": "Clothing" + }, + { + "Date": "2020-07-10", + "Value": 251, + "Series": "Clothing" + }, + { + "Date": "2020-08-07", + "Value": 254, + "Series": "Clothing" + }, + { + "Date": "2020-09-03", + "Value": 264, + "Series": "Clothing" + }, + { + "Date": "2020-09-30", + "Value": 266, + "Series": "Clothing" + }, + { + "Date": "2020-10-28", + "Value": 268, + "Series": "Clothing" + }, + { + "Date": "2020-11-24", + "Value": 273, + "Series": "Clothing" + }, + { + "Date": "2020-12-21", + "Value": 278, + "Series": "Clothing" + }, + { + "Date": "2021-01-18", + "Value": 277, + "Series": "Clothing" + }, + { + "Date": "2021-02-14", + "Value": 279, + "Series": "Clothing" + }, + { + "Date": "2021-03-14", + "Value": 277, + "Series": "Clothing" + }, + { + "Date": "2021-04-10", + "Value": 276, + "Series": "Clothing" + }, + { + "Date": "2021-05-07", + "Value": 274, + "Series": "Clothing" + }, + { + "Date": "2021-06-04", + "Value": 281, + "Series": "Clothing" + }, + { + "Date": "2021-07-01", + "Value": 292, + "Series": "Clothing" + }, + { + "Date": "2021-07-28", + "Value": 294, + "Series": "Clothing" + }, + { + "Date": "2021-08-25", + "Value": 302, + "Series": "Clothing" + }, + { + "Date": "2021-09-21", + "Value": 315, + "Series": "Clothing" + }, + { + "Date": "2021-10-19", + "Value": 324, + "Series": "Clothing" + }, + { + "Date": "2021-11-15", + "Value": 334, + "Series": "Clothing" + }, + { + "Date": "2021-12-12", + "Value": 341, + "Series": "Clothing" + }, + { + "Date": "2022-01-09", + "Value": 353, + "Series": "Clothing" + }, + { + "Date": "2022-02-05", + "Value": 366, + "Series": "Clothing" + }, + { + "Date": "2022-03-04", + "Value": 371, + "Series": "Clothing" + }, + { + "Date": "2022-04-01", + "Value": 383, + "Series": "Clothing" + }, + { + "Date": "2022-04-28", + "Value": 399, + "Series": "Clothing" + }, + { + "Date": "2022-05-26", + "Value": 404, + "Series": "Clothing" + }, + { + "Date": "2022-06-22", + "Value": 409, + "Series": "Clothing" + }, + { + "Date": "2022-07-19", + "Value": 408, + "Series": "Clothing" + }, + { + "Date": "2022-08-16", + "Value": 415, + "Series": "Clothing" + }, + { + "Date": "2022-09-12", + "Value": 422, + "Series": "Clothing" + }, + { + "Date": "2022-10-09", + "Value": 433, + "Series": "Clothing" + }, + { + "Date": "2022-11-06", + "Value": 435, + "Series": "Clothing" + }, + { + "Date": "2022-12-03", + "Value": 433, + "Series": "Clothing" + }, + { + "Date": "2020-01-01", + "Value": 93, + "Series": "Food" + }, + { + "Date": "2020-01-28", + "Value": 104, + "Series": "Food" + }, + { + "Date": "2020-02-24", + "Value": 124, + "Series": "Food" + }, + { + "Date": "2020-03-23", + "Value": 130, + "Series": "Food" + }, + { + "Date": "2020-04-19", + "Value": 128, + "Series": "Food" + }, + { + "Date": "2020-05-16", + "Value": 138, + "Series": "Food" + }, + { + "Date": "2020-06-13", + "Value": 155, + "Series": "Food" + }, + { + "Date": "2020-07-10", + "Value": 163, + "Series": "Food" + }, + { + "Date": "2020-08-07", + "Value": 175, + "Series": "Food" + }, + { + "Date": "2020-09-03", + "Value": 194, + "Series": "Food" + }, + { + "Date": "2020-09-30", + "Value": 199, + "Series": "Food" + }, + { + "Date": "2020-10-28", + "Value": 194, + "Series": "Food" + }, + { + "Date": "2020-11-24", + "Value": 194, + "Series": "Food" + }, + { + "Date": "2020-12-21", + "Value": 204, + "Series": "Food" + }, + { + "Date": "2021-01-18", + "Value": 217, + "Series": "Food" + }, + { + "Date": "2021-02-14", + "Value": 229, + "Series": "Food" + }, + { + "Date": "2021-03-14", + "Value": 233, + "Series": "Food" + }, + { + "Date": "2021-04-10", + "Value": 238, + "Series": "Food" + }, + { + "Date": "2021-05-07", + "Value": 243, + "Series": "Food" + }, + { + "Date": "2021-06-04", + "Value": 238, + "Series": "Food" + }, + { + "Date": "2021-07-01", + "Value": 232, + "Series": "Food" + }, + { + "Date": "2021-07-28", + "Value": 223, + "Series": "Food" + }, + { + "Date": "2021-08-25", + "Value": 222, + "Series": "Food" + }, + { + "Date": "2021-09-21", + "Value": 216, + "Series": "Food" + }, + { + "Date": "2021-10-19", + "Value": 205, + "Series": "Food" + }, + { + "Date": "2021-11-15", + "Value": 199, + "Series": "Food" + }, + { + "Date": "2021-12-12", + "Value": 190, + "Series": "Food" + }, + { + "Date": "2022-01-09", + "Value": 186, + "Series": "Food" + }, + { + "Date": "2022-02-05", + "Value": 193, + "Series": "Food" + }, + { + "Date": "2022-03-04", + "Value": 189, + "Series": "Food" + }, + { + "Date": "2022-04-01", + "Value": 197, + "Series": "Food" + }, + { + "Date": "2022-04-28", + "Value": 202, + "Series": "Food" + }, + { + "Date": "2022-05-26", + "Value": 206, + "Series": "Food" + }, + { + "Date": "2022-06-22", + "Value": 208, + "Series": "Food" + }, + { + "Date": "2022-07-19", + "Value": 214, + "Series": "Food" + }, + { + "Date": "2022-08-16", + "Value": 210, + "Series": "Food" + }, + { + "Date": "2022-09-12", + "Value": 206, + "Series": "Food" + }, + { + "Date": "2022-10-09", + "Value": 216, + "Series": "Food" + }, + { + "Date": "2022-11-06", + "Value": 233, + "Series": "Food" + }, + { + "Date": "2022-12-03", + "Value": 251, + "Series": "Food" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/area-chart/05-card60.flint.json b/test-harness/excel/evaluations/inputs/area-chart/05-card60.flint.json new file mode 100644 index 00000000..7c38068f --- /dev/null +++ b/test-harness/excel/evaluations/inputs/area-chart/05-card60.flint.json @@ -0,0 +1,808 @@ +{ + "semantic_types": { + "Date": "Date", + "Value": "Quantity", + "Series": "Category" + }, + "chart_spec": { + "chartType": "Area Chart", + "encodings": { + "x": "Date", + "y": "Value", + "color": "Series" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Date": "2020-01-01", + "Value": 248, + "Series": "Electronics" + }, + { + "Date": "2020-01-19", + "Value": 259, + "Series": "Electronics" + }, + { + "Date": "2020-02-24", + "Value": 296, + "Series": "Electronics" + }, + { + "Date": "2020-03-14", + "Value": 303, + "Series": "Electronics" + }, + { + "Date": "2020-04-19", + "Value": 336, + "Series": "Electronics" + }, + { + "Date": "2020-05-07", + "Value": 340, + "Series": "Electronics" + }, + { + "Date": "2020-05-26", + "Value": 342, + "Series": "Electronics" + }, + { + "Date": "2020-07-19", + "Value": 380, + "Series": "Electronics" + }, + { + "Date": "2020-08-07", + "Value": 377, + "Series": "Electronics" + }, + { + "Date": "2020-08-25", + "Value": 370, + "Series": "Electronics" + }, + { + "Date": "2020-09-12", + "Value": 380, + "Series": "Electronics" + }, + { + "Date": "2020-10-19", + "Value": 423, + "Series": "Electronics" + }, + { + "Date": "2020-11-06", + "Value": 447, + "Series": "Electronics" + }, + { + "Date": "2020-11-24", + "Value": 466, + "Series": "Electronics" + }, + { + "Date": "2020-12-12", + "Value": 475, + "Series": "Electronics" + }, + { + "Date": "2020-12-31", + "Value": 495, + "Series": "Electronics" + }, + { + "Date": "2021-01-18", + "Value": 509, + "Series": "Electronics" + }, + { + "Date": "2021-02-05", + "Value": 520, + "Series": "Electronics" + }, + { + "Date": "2021-02-23", + "Value": 529, + "Series": "Electronics" + }, + { + "Date": "2021-03-14", + "Value": 536, + "Series": "Electronics" + }, + { + "Date": "2021-04-01", + "Value": 533, + "Series": "Electronics" + }, + { + "Date": "2021-04-19", + "Value": 531, + "Series": "Electronics" + }, + { + "Date": "2021-05-26", + "Value": 550, + "Series": "Electronics" + }, + { + "Date": "2021-06-13", + "Value": 550, + "Series": "Electronics" + }, + { + "Date": "2021-07-01", + "Value": 556, + "Series": "Electronics" + }, + { + "Date": "2021-07-19", + "Value": 548, + "Series": "Electronics" + }, + { + "Date": "2021-08-07", + "Value": 555, + "Series": "Electronics" + }, + { + "Date": "2021-08-25", + "Value": 574, + "Series": "Electronics" + }, + { + "Date": "2021-09-12", + "Value": 600, + "Series": "Electronics" + }, + { + "Date": "2021-09-30", + "Value": 618, + "Series": "Electronics" + }, + { + "Date": "2021-11-06", + "Value": 641, + "Series": "Electronics" + }, + { + "Date": "2021-11-24", + "Value": 647, + "Series": "Electronics" + }, + { + "Date": "2021-12-12", + "Value": 648, + "Series": "Electronics" + }, + { + "Date": "2021-12-31", + "Value": 646, + "Series": "Electronics" + }, + { + "Date": "2022-01-18", + "Value": 636, + "Series": "Electronics" + }, + { + "Date": "2022-02-05", + "Value": 635, + "Series": "Electronics" + }, + { + "Date": "2022-02-23", + "Value": 642, + "Series": "Electronics" + }, + { + "Date": "2022-03-14", + "Value": 646, + "Series": "Electronics" + }, + { + "Date": "2022-04-19", + "Value": 641, + "Series": "Electronics" + }, + { + "Date": "2022-05-07", + "Value": 649, + "Series": "Electronics" + }, + { + "Date": "2022-05-26", + "Value": 652, + "Series": "Electronics" + }, + { + "Date": "2022-06-13", + "Value": 669, + "Series": "Electronics" + }, + { + "Date": "2022-07-01", + "Value": 676, + "Series": "Electronics" + }, + { + "Date": "2022-07-19", + "Value": 683, + "Series": "Electronics" + }, + { + "Date": "2022-08-07", + "Value": 677, + "Series": "Electronics" + }, + { + "Date": "2022-09-12", + "Value": 671, + "Series": "Electronics" + }, + { + "Date": "2022-09-30", + "Value": 676, + "Series": "Electronics" + }, + { + "Date": "2022-10-19", + "Value": 688, + "Series": "Electronics" + }, + { + "Date": "2022-11-06", + "Value": 706, + "Series": "Electronics" + }, + { + "Date": "2022-11-24", + "Value": 716, + "Series": "Electronics" + }, + { + "Date": "2022-12-12", + "Value": 725, + "Series": "Electronics" + }, + { + "Date": "2020-01-01", + "Value": 200, + "Series": "Clothing" + }, + { + "Date": "2020-01-19", + "Value": 206, + "Series": "Clothing" + }, + { + "Date": "2020-02-24", + "Value": 247, + "Series": "Clothing" + }, + { + "Date": "2020-03-14", + "Value": 254, + "Series": "Clothing" + }, + { + "Date": "2020-04-01", + "Value": 256, + "Series": "Clothing" + }, + { + "Date": "2020-04-19", + "Value": 262, + "Series": "Clothing" + }, + { + "Date": "2020-05-26", + "Value": 241, + "Series": "Clothing" + }, + { + "Date": "2020-06-13", + "Value": 234, + "Series": "Clothing" + }, + { + "Date": "2020-07-01", + "Value": 240, + "Series": "Clothing" + }, + { + "Date": "2020-07-19", + "Value": 245, + "Series": "Clothing" + }, + { + "Date": "2020-08-07", + "Value": 232, + "Series": "Clothing" + }, + { + "Date": "2020-08-25", + "Value": 231, + "Series": "Clothing" + }, + { + "Date": "2020-09-12", + "Value": 251, + "Series": "Clothing" + }, + { + "Date": "2020-09-30", + "Value": 258, + "Series": "Clothing" + }, + { + "Date": "2020-10-19", + "Value": 247, + "Series": "Clothing" + }, + { + "Date": "2020-11-06", + "Value": 259, + "Series": "Clothing" + }, + { + "Date": "2020-11-24", + "Value": 285, + "Series": "Clothing" + }, + { + "Date": "2020-12-12", + "Value": 289, + "Series": "Clothing" + }, + { + "Date": "2020-12-31", + "Value": 286, + "Series": "Clothing" + }, + { + "Date": "2021-01-18", + "Value": 290, + "Series": "Clothing" + }, + { + "Date": "2021-02-05", + "Value": 277, + "Series": "Clothing" + }, + { + "Date": "2021-02-23", + "Value": 285, + "Series": "Clothing" + }, + { + "Date": "2021-03-14", + "Value": 296, + "Series": "Clothing" + }, + { + "Date": "2021-04-01", + "Value": 300, + "Series": "Clothing" + }, + { + "Date": "2021-04-19", + "Value": 322, + "Series": "Clothing" + }, + { + "Date": "2021-05-07", + "Value": 349, + "Series": "Clothing" + }, + { + "Date": "2021-05-26", + "Value": 386, + "Series": "Clothing" + }, + { + "Date": "2021-06-13", + "Value": 415, + "Series": "Clothing" + }, + { + "Date": "2021-07-19", + "Value": 436, + "Series": "Clothing" + }, + { + "Date": "2021-08-25", + "Value": 491, + "Series": "Clothing" + }, + { + "Date": "2021-09-12", + "Value": 491, + "Series": "Clothing" + }, + { + "Date": "2021-09-30", + "Value": 495, + "Series": "Clothing" + }, + { + "Date": "2021-10-19", + "Value": 516, + "Series": "Clothing" + }, + { + "Date": "2021-11-24", + "Value": 513, + "Series": "Clothing" + }, + { + "Date": "2021-12-12", + "Value": 528, + "Series": "Clothing" + }, + { + "Date": "2021-12-31", + "Value": 527, + "Series": "Clothing" + }, + { + "Date": "2022-01-18", + "Value": 530, + "Series": "Clothing" + }, + { + "Date": "2022-02-05", + "Value": 546, + "Series": "Clothing" + }, + { + "Date": "2022-02-23", + "Value": 544, + "Series": "Clothing" + }, + { + "Date": "2022-03-14", + "Value": 550, + "Series": "Clothing" + }, + { + "Date": "2022-04-01", + "Value": 547, + "Series": "Clothing" + }, + { + "Date": "2022-04-19", + "Value": 565, + "Series": "Clothing" + }, + { + "Date": "2022-05-26", + "Value": 613, + "Series": "Clothing" + }, + { + "Date": "2022-06-13", + "Value": 616, + "Series": "Clothing" + }, + { + "Date": "2022-07-01", + "Value": 614, + "Series": "Clothing" + }, + { + "Date": "2022-07-19", + "Value": 630, + "Series": "Clothing" + }, + { + "Date": "2022-08-25", + "Value": 653, + "Series": "Clothing" + }, + { + "Date": "2022-09-30", + "Value": 698, + "Series": "Clothing" + }, + { + "Date": "2022-10-19", + "Value": 714, + "Series": "Clothing" + }, + { + "Date": "2022-11-06", + "Value": 736, + "Series": "Clothing" + }, + { + "Date": "2022-11-24", + "Value": 762, + "Series": "Clothing" + }, + { + "Date": "2022-12-12", + "Value": 766, + "Series": "Clothing" + }, + { + "Date": "2020-01-01", + "Value": 87, + "Series": "Food" + }, + { + "Date": "2020-01-19", + "Value": 78, + "Series": "Food" + }, + { + "Date": "2020-02-06", + "Value": 82, + "Series": "Food" + }, + { + "Date": "2020-02-24", + "Value": 96, + "Series": "Food" + }, + { + "Date": "2020-03-14", + "Value": 102, + "Series": "Food" + }, + { + "Date": "2020-04-19", + "Value": 121, + "Series": "Food" + }, + { + "Date": "2020-05-07", + "Value": 136, + "Series": "Food" + }, + { + "Date": "2020-05-26", + "Value": 151, + "Series": "Food" + }, + { + "Date": "2020-06-13", + "Value": 172, + "Series": "Food" + }, + { + "Date": "2020-07-01", + "Value": 182, + "Series": "Food" + }, + { + "Date": "2020-08-07", + "Value": 200, + "Series": "Food" + }, + { + "Date": "2020-08-25", + "Value": 209, + "Series": "Food" + }, + { + "Date": "2020-09-12", + "Value": 215, + "Series": "Food" + }, + { + "Date": "2020-09-30", + "Value": 211, + "Series": "Food" + }, + { + "Date": "2020-10-19", + "Value": 224, + "Series": "Food" + }, + { + "Date": "2020-11-24", + "Value": 242, + "Series": "Food" + }, + { + "Date": "2020-12-12", + "Value": 239, + "Series": "Food" + }, + { + "Date": "2021-01-18", + "Value": 220, + "Series": "Food" + }, + { + "Date": "2021-02-05", + "Value": 210, + "Series": "Food" + }, + { + "Date": "2021-02-23", + "Value": 198, + "Series": "Food" + }, + { + "Date": "2021-03-14", + "Value": 193, + "Series": "Food" + }, + { + "Date": "2021-04-01", + "Value": 176, + "Series": "Food" + }, + { + "Date": "2021-04-19", + "Value": 177, + "Series": "Food" + }, + { + "Date": "2021-05-07", + "Value": 179, + "Series": "Food" + }, + { + "Date": "2021-05-26", + "Value": 189, + "Series": "Food" + }, + { + "Date": "2021-06-13", + "Value": 212, + "Series": "Food" + }, + { + "Date": "2021-07-01", + "Value": 244, + "Series": "Food" + }, + { + "Date": "2021-07-19", + "Value": 281, + "Series": "Food" + }, + { + "Date": "2021-08-07", + "Value": 317, + "Series": "Food" + }, + { + "Date": "2021-08-25", + "Value": 330, + "Series": "Food" + }, + { + "Date": "2021-09-12", + "Value": 339, + "Series": "Food" + }, + { + "Date": "2021-09-30", + "Value": 354, + "Series": "Food" + }, + { + "Date": "2021-10-19", + "Value": 370, + "Series": "Food" + }, + { + "Date": "2021-11-06", + "Value": 385, + "Series": "Food" + }, + { + "Date": "2021-11-24", + "Value": 389, + "Series": "Food" + }, + { + "Date": "2021-12-12", + "Value": 388, + "Series": "Food" + }, + { + "Date": "2021-12-31", + "Value": 390, + "Series": "Food" + }, + { + "Date": "2022-01-18", + "Value": 406, + "Series": "Food" + }, + { + "Date": "2022-02-05", + "Value": 428, + "Series": "Food" + }, + { + "Date": "2022-02-23", + "Value": 433, + "Series": "Food" + }, + { + "Date": "2022-03-14", + "Value": 441, + "Series": "Food" + }, + { + "Date": "2022-04-01", + "Value": 441, + "Series": "Food" + }, + { + "Date": "2022-04-19", + "Value": 444, + "Series": "Food" + }, + { + "Date": "2022-05-07", + "Value": 464, + "Series": "Food" + }, + { + "Date": "2022-06-13", + "Value": 498, + "Series": "Food" + }, + { + "Date": "2022-07-01", + "Value": 506, + "Series": "Food" + }, + { + "Date": "2022-07-19", + "Value": 522, + "Series": "Food" + }, + { + "Date": "2022-08-07", + "Value": 546, + "Series": "Food" + }, + { + "Date": "2022-08-25", + "Value": 578, + "Series": "Food" + }, + { + "Date": "2022-09-12", + "Value": 595, + "Series": "Food" + }, + { + "Date": "2022-10-19", + "Value": 583, + "Series": "Food" + }, + { + "Date": "2022-11-06", + "Value": 597, + "Series": "Food" + }, + { + "Date": "2022-11-24", + "Value": 593, + "Series": "Food" + }, + { + "Date": "2022-12-12", + "Value": 589, + "Series": "Food" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/area-chart/06-card5.flint.json b/test-harness/excel/evaluations/inputs/area-chart/06-card5.flint.json new file mode 100644 index 00000000..723bd777 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/area-chart/06-card5.flint.json @@ -0,0 +1,41 @@ +{ + "semantic_types": { + "Stage": "Category", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Area Chart", + "encodings": { + "x": "Stage", + "y": "Value" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Stage": "Stage 1", + "Value": 217 + }, + { + "Stage": "Stage 2", + "Value": 224 + }, + { + "Stage": "Stage 3", + "Value": 226 + }, + { + "Stage": "Stage 4", + "Value": 235 + }, + { + "Stage": "Stage 5", + "Value": 236 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/area-chart/07-card12.flint.json b/test-harness/excel/evaluations/inputs/area-chart/07-card12.flint.json new file mode 100644 index 00000000..abf3a2cf --- /dev/null +++ b/test-harness/excel/evaluations/inputs/area-chart/07-card12.flint.json @@ -0,0 +1,263 @@ +{ + "semantic_types": { + "Stage": "Category", + "Value": "Quantity", + "Series": "Category" + }, + "chart_spec": { + "chartType": "Area Chart", + "encodings": { + "x": "Stage", + "y": "Value", + "color": "Series" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Stage": "Stage 1", + "Value": 86, + "Series": "Electronics" + }, + { + "Stage": "Stage 2", + "Value": 85, + "Series": "Electronics" + }, + { + "Stage": "Stage 3", + "Value": 83, + "Series": "Electronics" + }, + { + "Stage": "Stage 4", + "Value": 79, + "Series": "Electronics" + }, + { + "Stage": "Stage 5", + "Value": 78, + "Series": "Electronics" + }, + { + "Stage": "Stage 6", + "Value": 78, + "Series": "Electronics" + }, + { + "Stage": "Stage 7", + "Value": 83, + "Series": "Electronics" + }, + { + "Stage": "Stage 8", + "Value": 86, + "Series": "Electronics" + }, + { + "Stage": "Stage 9", + "Value": 84, + "Series": "Electronics" + }, + { + "Stage": "Stage 10", + "Value": 87, + "Series": "Electronics" + }, + { + "Stage": "Stage 11", + "Value": 91, + "Series": "Electronics" + }, + { + "Stage": "Stage 12", + "Value": 99, + "Series": "Electronics" + }, + { + "Stage": "Stage 1", + "Value": 240, + "Series": "Clothing" + }, + { + "Stage": "Stage 2", + "Value": 237, + "Series": "Clothing" + }, + { + "Stage": "Stage 3", + "Value": 234, + "Series": "Clothing" + }, + { + "Stage": "Stage 4", + "Value": 233, + "Series": "Clothing" + }, + { + "Stage": "Stage 5", + "Value": 236, + "Series": "Clothing" + }, + { + "Stage": "Stage 6", + "Value": 245, + "Series": "Clothing" + }, + { + "Stage": "Stage 7", + "Value": 247, + "Series": "Clothing" + }, + { + "Stage": "Stage 8", + "Value": 247, + "Series": "Clothing" + }, + { + "Stage": "Stage 9", + "Value": 253, + "Series": "Clothing" + }, + { + "Stage": "Stage 10", + "Value": 264, + "Series": "Clothing" + }, + { + "Stage": "Stage 11", + "Value": 275, + "Series": "Clothing" + }, + { + "Stage": "Stage 12", + "Value": 284, + "Series": "Clothing" + }, + { + "Stage": "Stage 1", + "Value": 154, + "Series": "Food" + }, + { + "Stage": "Stage 2", + "Value": 143, + "Series": "Food" + }, + { + "Stage": "Stage 3", + "Value": 127, + "Series": "Food" + }, + { + "Stage": "Stage 4", + "Value": 110, + "Series": "Food" + }, + { + "Stage": "Stage 5", + "Value": 89, + "Series": "Food" + }, + { + "Stage": "Stage 6", + "Value": 93, + "Series": "Food" + }, + { + "Stage": "Stage 7", + "Value": 109, + "Series": "Food" + }, + { + "Stage": "Stage 8", + "Value": 129, + "Series": "Food" + }, + { + "Stage": "Stage 9", + "Value": 139, + "Series": "Food" + }, + { + "Stage": "Stage 10", + "Value": 142, + "Series": "Food" + }, + { + "Stage": "Stage 11", + "Value": 133, + "Series": "Food" + }, + { + "Stage": "Stage 12", + "Value": 125, + "Series": "Food" + }, + { + "Stage": "Stage 1", + "Value": 128, + "Series": "Books" + }, + { + "Stage": "Stage 2", + "Value": 124, + "Series": "Books" + }, + { + "Stage": "Stage 3", + "Value": 117, + "Series": "Books" + }, + { + "Stage": "Stage 4", + "Value": 113, + "Series": "Books" + }, + { + "Stage": "Stage 5", + "Value": 105, + "Series": "Books" + }, + { + "Stage": "Stage 6", + "Value": 94, + "Series": "Books" + }, + { + "Stage": "Stage 7", + "Value": 95, + "Series": "Books" + }, + { + "Stage": "Stage 8", + "Value": 102, + "Series": "Books" + }, + { + "Stage": "Stage 9", + "Value": 104, + "Series": "Books" + }, + { + "Stage": "Stage 10", + "Value": 114, + "Series": "Books" + }, + { + "Stage": "Stage 11", + "Value": 125, + "Series": "Books" + }, + { + "Stage": "Stage 12", + "Value": 139, + "Series": "Books" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/area-chart/08-card30.flint.json b/test-harness/excel/evaluations/inputs/area-chart/08-card30.flint.json new file mode 100644 index 00000000..75f09982 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/area-chart/08-card30.flint.json @@ -0,0 +1,141 @@ +{ + "semantic_types": { + "Stage": "Category", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Area Chart", + "encodings": { + "x": "Stage", + "y": "Value" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Stage": "Stage 1", + "Value": 159 + }, + { + "Stage": "Stage 2", + "Value": 163 + }, + { + "Stage": "Stage 3", + "Value": 167 + }, + { + "Stage": "Stage 4", + "Value": 167 + }, + { + "Stage": "Stage 5", + "Value": 168 + }, + { + "Stage": "Stage 6", + "Value": 175 + }, + { + "Stage": "Stage 7", + "Value": 175 + }, + { + "Stage": "Stage 8", + "Value": 187 + }, + { + "Stage": "Stage 9", + "Value": 200 + }, + { + "Stage": "Stage 10", + "Value": 216 + }, + { + "Stage": "Stage 11", + "Value": 223 + }, + { + "Stage": "Stage 12", + "Value": 221 + }, + { + "Stage": "Stage 13", + "Value": 218 + }, + { + "Stage": "Stage 14", + "Value": 209 + }, + { + "Stage": "Stage 15", + "Value": 209 + }, + { + "Stage": "Stage 16", + "Value": 206 + }, + { + "Stage": "Stage 17", + "Value": 209 + }, + { + "Stage": "Stage 18", + "Value": 220 + }, + { + "Stage": "Stage 19", + "Value": 231 + }, + { + "Stage": "Stage 20", + "Value": 234 + }, + { + "Stage": "Stage 21", + "Value": 243 + }, + { + "Stage": "Stage 22", + "Value": 261 + }, + { + "Stage": "Stage 23", + "Value": 282 + }, + { + "Stage": "Stage 24", + "Value": 303 + }, + { + "Stage": "Stage 25", + "Value": 324 + }, + { + "Stage": "Stage 26", + "Value": 332 + }, + { + "Stage": "Stage 27", + "Value": 334 + }, + { + "Stage": "Stage 28", + "Value": 328 + }, + { + "Stage": "Stage 29", + "Value": 332 + }, + { + "Stage": "Stage 30", + "Value": 328 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/area-chart/09-card30.flint.json b/test-harness/excel/evaluations/inputs/area-chart/09-card30.flint.json new file mode 100644 index 00000000..ebbbd6c9 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/area-chart/09-card30.flint.json @@ -0,0 +1,141 @@ +{ + "semantic_types": { + "X": "Quantity", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Area Chart", + "encodings": { + "x": "X", + "y": "Value" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 0, + "Value": 128 + }, + { + "X": 3.4, + "Value": 136 + }, + { + "X": 6.9, + "Value": 127 + }, + { + "X": 10.3, + "Value": 120 + }, + { + "X": 13.8, + "Value": 127 + }, + { + "X": 17.2, + "Value": 131 + }, + { + "X": 20.7, + "Value": 155 + }, + { + "X": 24.1, + "Value": 167 + }, + { + "X": 27.6, + "Value": 184 + }, + { + "X": 31, + "Value": 201 + }, + { + "X": 34.5, + "Value": 215 + }, + { + "X": 37.9, + "Value": 240 + }, + { + "X": 41.4, + "Value": 241 + }, + { + "X": 44.8, + "Value": 248 + }, + { + "X": 48.3, + "Value": 241 + }, + { + "X": 51.7, + "Value": 258 + }, + { + "X": 55.2, + "Value": 252 + }, + { + "X": 58.6, + "Value": 267 + }, + { + "X": 62.1, + "Value": 283 + }, + { + "X": 65.5, + "Value": 313 + }, + { + "X": 69, + "Value": 331 + }, + { + "X": 72.4, + "Value": 329 + }, + { + "X": 75.9, + "Value": 323 + }, + { + "X": 79.3, + "Value": 335 + }, + { + "X": 82.8, + "Value": 355 + }, + { + "X": 86.2, + "Value": 353 + }, + { + "X": 89.7, + "Value": 337 + }, + { + "X": 93.1, + "Value": 345 + }, + { + "X": 96.6, + "Value": 350 + }, + { + "X": 100, + "Value": 351 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/area-chart/10-card50.flint.json b/test-harness/excel/evaluations/inputs/area-chart/10-card50.flint.json new file mode 100644 index 00000000..15b70510 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/area-chart/10-card50.flint.json @@ -0,0 +1,773 @@ +{ + "semantic_types": { + "X": "Quantity", + "Value": "Quantity", + "Series": "Category" + }, + "chart_spec": { + "chartType": "Area Chart", + "encodings": { + "x": "X", + "y": "Value", + "color": "Series" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 0, + "Value": 213, + "Series": "Electronics" + }, + { + "X": 2, + "Value": 216, + "Series": "Electronics" + }, + { + "X": 4.1, + "Value": 215, + "Series": "Electronics" + }, + { + "X": 6.1, + "Value": 201, + "Series": "Electronics" + }, + { + "X": 8.2, + "Value": 186, + "Series": "Electronics" + }, + { + "X": 10.2, + "Value": 176, + "Series": "Electronics" + }, + { + "X": 12.2, + "Value": 161, + "Series": "Electronics" + }, + { + "X": 14.3, + "Value": 166, + "Series": "Electronics" + }, + { + "X": 16.3, + "Value": 155, + "Series": "Electronics" + }, + { + "X": 18.4, + "Value": 134, + "Series": "Electronics" + }, + { + "X": 20.4, + "Value": 143, + "Series": "Electronics" + }, + { + "X": 22.4, + "Value": 157, + "Series": "Electronics" + }, + { + "X": 24.5, + "Value": 178, + "Series": "Electronics" + }, + { + "X": 26.5, + "Value": 204, + "Series": "Electronics" + }, + { + "X": 28.6, + "Value": 228, + "Series": "Electronics" + }, + { + "X": 30.6, + "Value": 237, + "Series": "Electronics" + }, + { + "X": 32.7, + "Value": 261, + "Series": "Electronics" + }, + { + "X": 34.7, + "Value": 286, + "Series": "Electronics" + }, + { + "X": 36.7, + "Value": 318, + "Series": "Electronics" + }, + { + "X": 38.8, + "Value": 348, + "Series": "Electronics" + }, + { + "X": 40.8, + "Value": 362, + "Series": "Electronics" + }, + { + "X": 42.9, + "Value": 391, + "Series": "Electronics" + }, + { + "X": 44.9, + "Value": 403, + "Series": "Electronics" + }, + { + "X": 46.9, + "Value": 420, + "Series": "Electronics" + }, + { + "X": 49, + "Value": 450, + "Series": "Electronics" + }, + { + "X": 51, + "Value": 481, + "Series": "Electronics" + }, + { + "X": 53.1, + "Value": 495, + "Series": "Electronics" + }, + { + "X": 55.1, + "Value": 515, + "Series": "Electronics" + }, + { + "X": 57.1, + "Value": 544, + "Series": "Electronics" + }, + { + "X": 59.2, + "Value": 547, + "Series": "Electronics" + }, + { + "X": 61.2, + "Value": 535, + "Series": "Electronics" + }, + { + "X": 63.3, + "Value": 518, + "Series": "Electronics" + }, + { + "X": 65.3, + "Value": 500, + "Series": "Electronics" + }, + { + "X": 67.3, + "Value": 494, + "Series": "Electronics" + }, + { + "X": 69.4, + "Value": 476, + "Series": "Electronics" + }, + { + "X": 71.4, + "Value": 469, + "Series": "Electronics" + }, + { + "X": 73.5, + "Value": 465, + "Series": "Electronics" + }, + { + "X": 75.5, + "Value": 469, + "Series": "Electronics" + }, + { + "X": 77.6, + "Value": 467, + "Series": "Electronics" + }, + { + "X": 79.6, + "Value": 451, + "Series": "Electronics" + }, + { + "X": 81.6, + "Value": 434, + "Series": "Electronics" + }, + { + "X": 83.7, + "Value": 432, + "Series": "Electronics" + }, + { + "X": 85.7, + "Value": 417, + "Series": "Electronics" + }, + { + "X": 87.8, + "Value": 426, + "Series": "Electronics" + }, + { + "X": 89.8, + "Value": 418, + "Series": "Electronics" + }, + { + "X": 91.8, + "Value": 416, + "Series": "Electronics" + }, + { + "X": 93.9, + "Value": 423, + "Series": "Electronics" + }, + { + "X": 95.9, + "Value": 441, + "Series": "Electronics" + }, + { + "X": 98, + "Value": 439, + "Series": "Electronics" + }, + { + "X": 100, + "Value": 439, + "Series": "Electronics" + }, + { + "X": 0, + "Value": 111, + "Series": "Clothing" + }, + { + "X": 2, + "Value": 110, + "Series": "Clothing" + }, + { + "X": 4.1, + "Value": 130, + "Series": "Clothing" + }, + { + "X": 6.1, + "Value": 159, + "Series": "Clothing" + }, + { + "X": 8.2, + "Value": 172, + "Series": "Clothing" + }, + { + "X": 10.2, + "Value": 192, + "Series": "Clothing" + }, + { + "X": 12.2, + "Value": 214, + "Series": "Clothing" + }, + { + "X": 14.3, + "Value": 234, + "Series": "Clothing" + }, + { + "X": 16.3, + "Value": 247, + "Series": "Clothing" + }, + { + "X": 18.4, + "Value": 248, + "Series": "Clothing" + }, + { + "X": 20.4, + "Value": 267, + "Series": "Clothing" + }, + { + "X": 22.4, + "Value": 300, + "Series": "Clothing" + }, + { + "X": 24.5, + "Value": 325, + "Series": "Clothing" + }, + { + "X": 26.5, + "Value": 334, + "Series": "Clothing" + }, + { + "X": 28.6, + "Value": 355, + "Series": "Clothing" + }, + { + "X": 30.6, + "Value": 366, + "Series": "Clothing" + }, + { + "X": 32.7, + "Value": 389, + "Series": "Clothing" + }, + { + "X": 34.7, + "Value": 391, + "Series": "Clothing" + }, + { + "X": 36.7, + "Value": 381, + "Series": "Clothing" + }, + { + "X": 38.8, + "Value": 384, + "Series": "Clothing" + }, + { + "X": 40.8, + "Value": 408, + "Series": "Clothing" + }, + { + "X": 42.9, + "Value": 444, + "Series": "Clothing" + }, + { + "X": 44.9, + "Value": 454, + "Series": "Clothing" + }, + { + "X": 46.9, + "Value": 476, + "Series": "Clothing" + }, + { + "X": 49, + "Value": 484, + "Series": "Clothing" + }, + { + "X": 51, + "Value": 504, + "Series": "Clothing" + }, + { + "X": 53.1, + "Value": 536, + "Series": "Clothing" + }, + { + "X": 55.1, + "Value": 545, + "Series": "Clothing" + }, + { + "X": 57.1, + "Value": 539, + "Series": "Clothing" + }, + { + "X": 59.2, + "Value": 558, + "Series": "Clothing" + }, + { + "X": 61.2, + "Value": 579, + "Series": "Clothing" + }, + { + "X": 63.3, + "Value": 612, + "Series": "Clothing" + }, + { + "X": 65.3, + "Value": 629, + "Series": "Clothing" + }, + { + "X": 67.3, + "Value": 658, + "Series": "Clothing" + }, + { + "X": 69.4, + "Value": 672, + "Series": "Clothing" + }, + { + "X": 71.4, + "Value": 684, + "Series": "Clothing" + }, + { + "X": 73.5, + "Value": 678, + "Series": "Clothing" + }, + { + "X": 75.5, + "Value": 658, + "Series": "Clothing" + }, + { + "X": 77.6, + "Value": 632, + "Series": "Clothing" + }, + { + "X": 79.6, + "Value": 636, + "Series": "Clothing" + }, + { + "X": 81.6, + "Value": 622, + "Series": "Clothing" + }, + { + "X": 83.7, + "Value": 598, + "Series": "Clothing" + }, + { + "X": 85.7, + "Value": 588, + "Series": "Clothing" + }, + { + "X": 87.8, + "Value": 572, + "Series": "Clothing" + }, + { + "X": 89.8, + "Value": 555, + "Series": "Clothing" + }, + { + "X": 91.8, + "Value": 554, + "Series": "Clothing" + }, + { + "X": 93.9, + "Value": 538, + "Series": "Clothing" + }, + { + "X": 95.9, + "Value": 521, + "Series": "Clothing" + }, + { + "X": 98, + "Value": 522, + "Series": "Clothing" + }, + { + "X": 100, + "Value": 528, + "Series": "Clothing" + }, + { + "X": 0, + "Value": 203, + "Series": "Food" + }, + { + "X": 2, + "Value": 200, + "Series": "Food" + }, + { + "X": 4.1, + "Value": 205, + "Series": "Food" + }, + { + "X": 6.1, + "Value": 210, + "Series": "Food" + }, + { + "X": 8.2, + "Value": 232, + "Series": "Food" + }, + { + "X": 10.2, + "Value": 261, + "Series": "Food" + }, + { + "X": 12.2, + "Value": 273, + "Series": "Food" + }, + { + "X": 14.3, + "Value": 300, + "Series": "Food" + }, + { + "X": 16.3, + "Value": 336, + "Series": "Food" + }, + { + "X": 18.4, + "Value": 357, + "Series": "Food" + }, + { + "X": 20.4, + "Value": 381, + "Series": "Food" + }, + { + "X": 22.4, + "Value": 411, + "Series": "Food" + }, + { + "X": 24.5, + "Value": 447, + "Series": "Food" + }, + { + "X": 26.5, + "Value": 470, + "Series": "Food" + }, + { + "X": 28.6, + "Value": 481, + "Series": "Food" + }, + { + "X": 30.6, + "Value": 490, + "Series": "Food" + }, + { + "X": 32.7, + "Value": 488, + "Series": "Food" + }, + { + "X": 34.7, + "Value": 475, + "Series": "Food" + }, + { + "X": 36.7, + "Value": 472, + "Series": "Food" + }, + { + "X": 38.8, + "Value": 488, + "Series": "Food" + }, + { + "X": 40.8, + "Value": 515, + "Series": "Food" + }, + { + "X": 42.9, + "Value": 542, + "Series": "Food" + }, + { + "X": 44.9, + "Value": 577, + "Series": "Food" + }, + { + "X": 46.9, + "Value": 618, + "Series": "Food" + }, + { + "X": 49, + "Value": 651, + "Series": "Food" + }, + { + "X": 51, + "Value": 685, + "Series": "Food" + }, + { + "X": 53.1, + "Value": 712, + "Series": "Food" + }, + { + "X": 55.1, + "Value": 747, + "Series": "Food" + }, + { + "X": 57.1, + "Value": 776, + "Series": "Food" + }, + { + "X": 59.2, + "Value": 785, + "Series": "Food" + }, + { + "X": 61.2, + "Value": 779, + "Series": "Food" + }, + { + "X": 63.3, + "Value": 792, + "Series": "Food" + }, + { + "X": 65.3, + "Value": 810, + "Series": "Food" + }, + { + "X": 67.3, + "Value": 836, + "Series": "Food" + }, + { + "X": 69.4, + "Value": 840, + "Series": "Food" + }, + { + "X": 71.4, + "Value": 839, + "Series": "Food" + }, + { + "X": 73.5, + "Value": 846, + "Series": "Food" + }, + { + "X": 75.5, + "Value": 851, + "Series": "Food" + }, + { + "X": 77.6, + "Value": 856, + "Series": "Food" + }, + { + "X": 79.6, + "Value": 856, + "Series": "Food" + }, + { + "X": 81.6, + "Value": 847, + "Series": "Food" + }, + { + "X": 83.7, + "Value": 830, + "Series": "Food" + }, + { + "X": 85.7, + "Value": 836, + "Series": "Food" + }, + { + "X": 87.8, + "Value": 852, + "Series": "Food" + }, + { + "X": 89.8, + "Value": 869, + "Series": "Food" + }, + { + "X": 91.8, + "Value": 873, + "Series": "Food" + }, + { + "X": 93.9, + "Value": 865, + "Series": "Food" + }, + { + "X": 95.9, + "Value": 872, + "Series": "Food" + }, + { + "X": 98, + "Value": 880, + "Series": "Food" + }, + { + "X": 100, + "Value": 898, + "Series": "Food" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/area-chart/11-card200.flint.json b/test-harness/excel/evaluations/inputs/area-chart/11-card200.flint.json new file mode 100644 index 00000000..53d408fc --- /dev/null +++ b/test-harness/excel/evaluations/inputs/area-chart/11-card200.flint.json @@ -0,0 +1,821 @@ +{ + "semantic_types": { + "X": "Quantity", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Area Chart", + "encodings": { + "x": "X", + "y": "Value" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 0, + "Value": 235 + }, + { + "X": 0.5, + "Value": 220 + }, + { + "X": 1, + "Value": 206 + }, + { + "X": 1.5, + "Value": 208 + }, + { + "X": 2, + "Value": 201 + }, + { + "X": 2.5, + "Value": 212 + }, + { + "X": 3, + "Value": 217 + }, + { + "X": 3.5, + "Value": 205 + }, + { + "X": 4, + "Value": 209 + }, + { + "X": 4.5, + "Value": 222 + }, + { + "X": 5, + "Value": 246 + }, + { + "X": 5.5, + "Value": 273 + }, + { + "X": 6, + "Value": 277 + }, + { + "X": 6.5, + "Value": 300 + }, + { + "X": 7, + "Value": 305 + }, + { + "X": 7.5, + "Value": 299 + }, + { + "X": 8, + "Value": 290 + }, + { + "X": 8.5, + "Value": 304 + }, + { + "X": 9, + "Value": 298 + }, + { + "X": 9.5, + "Value": 314 + }, + { + "X": 10.1, + "Value": 308 + }, + { + "X": 10.6, + "Value": 291 + }, + { + "X": 11.1, + "Value": 288 + }, + { + "X": 11.6, + "Value": 302 + }, + { + "X": 12.1, + "Value": 302 + }, + { + "X": 12.6, + "Value": 297 + }, + { + "X": 13.1, + "Value": 298 + }, + { + "X": 13.6, + "Value": 286 + }, + { + "X": 14.1, + "Value": 273 + }, + { + "X": 14.6, + "Value": 253 + }, + { + "X": 15.1, + "Value": 260 + }, + { + "X": 15.6, + "Value": 284 + }, + { + "X": 16.1, + "Value": 311 + }, + { + "X": 16.6, + "Value": 321 + }, + { + "X": 17.1, + "Value": 338 + }, + { + "X": 17.6, + "Value": 365 + }, + { + "X": 18.1, + "Value": 368 + }, + { + "X": 18.6, + "Value": 373 + }, + { + "X": 19.1, + "Value": 371 + }, + { + "X": 19.6, + "Value": 390 + }, + { + "X": 20.1, + "Value": 415 + }, + { + "X": 20.6, + "Value": 440 + }, + { + "X": 21.1, + "Value": 468 + }, + { + "X": 21.6, + "Value": 472 + }, + { + "X": 22.1, + "Value": 472 + }, + { + "X": 22.6, + "Value": 461 + }, + { + "X": 23.1, + "Value": 469 + }, + { + "X": 23.6, + "Value": 478 + }, + { + "X": 24.1, + "Value": 483 + }, + { + "X": 24.6, + "Value": 473 + }, + { + "X": 25.1, + "Value": 473 + }, + { + "X": 25.6, + "Value": 487 + }, + { + "X": 26.1, + "Value": 489 + }, + { + "X": 26.6, + "Value": 505 + }, + { + "X": 27.1, + "Value": 517 + }, + { + "X": 27.6, + "Value": 509 + }, + { + "X": 28.1, + "Value": 520 + }, + { + "X": 28.6, + "Value": 534 + }, + { + "X": 29.1, + "Value": 542 + }, + { + "X": 29.6, + "Value": 561 + }, + { + "X": 30.2, + "Value": 571 + }, + { + "X": 30.7, + "Value": 587 + }, + { + "X": 31.2, + "Value": 588 + }, + { + "X": 31.7, + "Value": 599 + }, + { + "X": 32.2, + "Value": 619 + }, + { + "X": 32.7, + "Value": 616 + }, + { + "X": 33.2, + "Value": 602 + }, + { + "X": 33.7, + "Value": 602 + }, + { + "X": 34.2, + "Value": 594 + }, + { + "X": 34.7, + "Value": 597 + }, + { + "X": 35.2, + "Value": 615 + }, + { + "X": 35.7, + "Value": 627 + }, + { + "X": 36.2, + "Value": 630 + }, + { + "X": 36.7, + "Value": 639 + }, + { + "X": 37.2, + "Value": 639 + }, + { + "X": 37.7, + "Value": 627 + }, + { + "X": 38.2, + "Value": 629 + }, + { + "X": 38.7, + "Value": 648 + }, + { + "X": 39.2, + "Value": 680 + }, + { + "X": 39.7, + "Value": 712 + }, + { + "X": 40.2, + "Value": 748 + }, + { + "X": 40.7, + "Value": 775 + }, + { + "X": 41.2, + "Value": 807 + }, + { + "X": 41.7, + "Value": 822 + }, + { + "X": 42.2, + "Value": 818 + }, + { + "X": 42.7, + "Value": 836 + }, + { + "X": 43.2, + "Value": 838 + }, + { + "X": 43.7, + "Value": 842 + }, + { + "X": 44.2, + "Value": 854 + }, + { + "X": 44.7, + "Value": 874 + }, + { + "X": 45.2, + "Value": 905 + }, + { + "X": 45.7, + "Value": 933 + }, + { + "X": 46.2, + "Value": 941 + }, + { + "X": 46.7, + "Value": 951 + }, + { + "X": 47.2, + "Value": 950 + }, + { + "X": 47.7, + "Value": 937 + }, + { + "X": 48.2, + "Value": 924 + }, + { + "X": 48.7, + "Value": 903 + }, + { + "X": 49.2, + "Value": 880 + }, + { + "X": 49.7, + "Value": 856 + }, + { + "X": 50.3, + "Value": 836 + }, + { + "X": 50.8, + "Value": 826 + }, + { + "X": 51.3, + "Value": 820 + }, + { + "X": 51.8, + "Value": 810 + }, + { + "X": 52.3, + "Value": 791 + }, + { + "X": 52.8, + "Value": 791 + }, + { + "X": 53.3, + "Value": 785 + }, + { + "X": 53.8, + "Value": 774 + }, + { + "X": 54.3, + "Value": 754 + }, + { + "X": 54.8, + "Value": 740 + }, + { + "X": 55.3, + "Value": 746 + }, + { + "X": 55.8, + "Value": 766 + }, + { + "X": 56.3, + "Value": 784 + }, + { + "X": 56.8, + "Value": 782 + }, + { + "X": 57.3, + "Value": 766 + }, + { + "X": 57.8, + "Value": 767 + }, + { + "X": 58.3, + "Value": 787 + }, + { + "X": 58.8, + "Value": 816 + }, + { + "X": 59.3, + "Value": 840 + }, + { + "X": 59.8, + "Value": 839 + }, + { + "X": 60.3, + "Value": 855 + }, + { + "X": 60.8, + "Value": 859 + }, + { + "X": 61.3, + "Value": 866 + }, + { + "X": 61.8, + "Value": 865 + }, + { + "X": 62.3, + "Value": 863 + }, + { + "X": 62.8, + "Value": 863 + }, + { + "X": 63.3, + "Value": 869 + }, + { + "X": 63.8, + "Value": 860 + }, + { + "X": 64.3, + "Value": 871 + }, + { + "X": 64.8, + "Value": 887 + }, + { + "X": 65.3, + "Value": 885 + }, + { + "X": 65.8, + "Value": 896 + }, + { + "X": 66.3, + "Value": 903 + }, + { + "X": 66.8, + "Value": 926 + }, + { + "X": 67.3, + "Value": 930 + }, + { + "X": 67.8, + "Value": 922 + }, + { + "X": 68.3, + "Value": 917 + }, + { + "X": 68.8, + "Value": 904 + }, + { + "X": 69.3, + "Value": 909 + }, + { + "X": 69.8, + "Value": 898 + }, + { + "X": 70.4, + "Value": 905 + }, + { + "X": 70.9, + "Value": 927 + }, + { + "X": 71.4, + "Value": 960 + }, + { + "X": 71.9, + "Value": 978 + }, + { + "X": 72.4, + "Value": 989 + }, + { + "X": 72.9, + "Value": 1008 + }, + { + "X": 73.4, + "Value": 1018 + }, + { + "X": 73.9, + "Value": 1044 + }, + { + "X": 74.4, + "Value": 1057 + }, + { + "X": 74.9, + "Value": 1084 + }, + { + "X": 75.4, + "Value": 1105 + }, + { + "X": 75.9, + "Value": 1119 + }, + { + "X": 76.4, + "Value": 1140 + }, + { + "X": 76.9, + "Value": 1157 + }, + { + "X": 77.4, + "Value": 1184 + }, + { + "X": 77.9, + "Value": 1190 + }, + { + "X": 78.4, + "Value": 1201 + }, + { + "X": 78.9, + "Value": 1218 + }, + { + "X": 79.4, + "Value": 1237 + }, + { + "X": 79.9, + "Value": 1259 + }, + { + "X": 80.4, + "Value": 1266 + }, + { + "X": 80.9, + "Value": 1255 + }, + { + "X": 81.4, + "Value": 1261 + }, + { + "X": 81.9, + "Value": 1259 + }, + { + "X": 82.4, + "Value": 1253 + }, + { + "X": 82.9, + "Value": 1268 + }, + { + "X": 83.4, + "Value": 1272 + }, + { + "X": 83.9, + "Value": 1266 + }, + { + "X": 84.4, + "Value": 1262 + }, + { + "X": 84.9, + "Value": 1250 + }, + { + "X": 85.4, + "Value": 1232 + }, + { + "X": 85.9, + "Value": 1229 + }, + { + "X": 86.4, + "Value": 1224 + }, + { + "X": 86.9, + "Value": 1234 + }, + { + "X": 87.4, + "Value": 1228 + }, + { + "X": 87.9, + "Value": 1214 + }, + { + "X": 88.4, + "Value": 1220 + }, + { + "X": 88.9, + "Value": 1214 + }, + { + "X": 89.4, + "Value": 1221 + }, + { + "X": 89.9, + "Value": 1212 + }, + { + "X": 90.5, + "Value": 1197 + }, + { + "X": 91, + "Value": 1189 + }, + { + "X": 91.5, + "Value": 1205 + }, + { + "X": 92, + "Value": 1210 + }, + { + "X": 92.5, + "Value": 1216 + }, + { + "X": 93, + "Value": 1211 + }, + { + "X": 93.5, + "Value": 1207 + }, + { + "X": 94, + "Value": 1194 + }, + { + "X": 94.5, + "Value": 1184 + }, + { + "X": 95, + "Value": 1170 + }, + { + "X": 95.5, + "Value": 1163 + }, + { + "X": 96, + "Value": 1150 + }, + { + "X": 96.5, + "Value": 1153 + }, + { + "X": 97, + "Value": 1153 + }, + { + "X": 97.5, + "Value": 1145 + }, + { + "X": 98, + "Value": 1129 + }, + { + "X": 98.5, + "Value": 1136 + }, + { + "X": 99, + "Value": 1147 + }, + { + "X": 99.5, + "Value": 1170 + }, + { + "X": 100, + "Value": 1180 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/bar-chart/00-card5.flint.json b/test-harness/excel/evaluations/inputs/bar-chart/00-card5.flint.json new file mode 100644 index 00000000..425701d8 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/bar-chart/00-card5.flint.json @@ -0,0 +1,41 @@ +{ + "semantic_types": { + "Category": "Category", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Bar Chart", + "encodings": { + "x": "Category", + "y": "Value" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Laptop", + "Value": 11 + }, + { + "Category": "Phone", + "Value": 162 + }, + { + "Category": "Tablet", + "Value": 565 + }, + { + "Category": "Desktop", + "Value": 866 + }, + { + "Category": "Monitor", + "Value": 284 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/bar-chart/01-card20.flint.json b/test-harness/excel/evaluations/inputs/bar-chart/01-card20.flint.json new file mode 100644 index 00000000..ed57611f --- /dev/null +++ b/test-harness/excel/evaluations/inputs/bar-chart/01-card20.flint.json @@ -0,0 +1,101 @@ +{ + "semantic_types": { + "Category": "Category", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Bar Chart", + "encodings": { + "x": "Category", + "y": "Value" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Laptop", + "Value": 897 + }, + { + "Category": "Phone", + "Value": 707 + }, + { + "Category": "Tablet", + "Value": 888 + }, + { + "Category": "Desktop", + "Value": 930 + }, + { + "Category": "Monitor", + "Value": 475 + }, + { + "Category": "Keyboard", + "Value": 357 + }, + { + "Category": "Mouse", + "Value": 942 + }, + { + "Category": "Headphones", + "Value": 106 + }, + { + "Category": "Speaker", + "Value": 463 + }, + { + "Category": "Camera", + "Value": 353 + }, + { + "Category": "TV", + "Value": 970 + }, + { + "Category": "Router", + "Value": 124 + }, + { + "Category": "Printer", + "Value": 772 + }, + { + "Category": "Scanner", + "Value": 348 + }, + { + "Category": "SSD", + "Value": 687 + }, + { + "Category": "HDD", + "Value": 751 + }, + { + "Category": "RAM", + "Value": 680 + }, + { + "Category": "GPU", + "Value": 899 + }, + { + "Category": "CPU", + "Value": 53 + }, + { + "Category": "Motherboard", + "Value": 621 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/bar-chart/02-card20.flint.json b/test-harness/excel/evaluations/inputs/bar-chart/02-card20.flint.json new file mode 100644 index 00000000..ee5c4716 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/bar-chart/02-card20.flint.json @@ -0,0 +1,101 @@ +{ + "semantic_types": { + "Category": "Category", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Bar Chart", + "encodings": { + "x": "Category", + "y": "Value" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Laptop", + "Value": 696 + }, + { + "Category": "Phone", + "Value": 205 + }, + { + "Category": "Tablet", + "Value": 398 + }, + { + "Category": "Desktop", + "Value": 604 + }, + { + "Category": "Monitor", + "Value": 128 + }, + { + "Category": "Keyboard", + "Value": 42 + }, + { + "Category": "Mouse", + "Value": 228 + }, + { + "Category": "Headphones", + "Value": 253 + }, + { + "Category": "Speaker", + "Value": 749 + }, + { + "Category": "Camera", + "Value": 612 + }, + { + "Category": "TV", + "Value": 825 + }, + { + "Category": "Router", + "Value": 271 + }, + { + "Category": "Printer", + "Value": 645 + }, + { + "Category": "Scanner", + "Value": 113 + }, + { + "Category": "SSD", + "Value": 539 + }, + { + "Category": "HDD", + "Value": 707 + }, + { + "Category": "RAM", + "Value": 262 + }, + { + "Category": "GPU", + "Value": 273 + }, + { + "Category": "CPU", + "Value": 342 + }, + { + "Category": "Motherboard", + "Value": 160 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/bar-chart/03-card100.flint.json b/test-harness/excel/evaluations/inputs/bar-chart/03-card100.flint.json new file mode 100644 index 00000000..eb40f30e --- /dev/null +++ b/test-harness/excel/evaluations/inputs/bar-chart/03-card100.flint.json @@ -0,0 +1,421 @@ +{ + "semantic_types": { + "Category": "Category", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Bar Chart", + "encodings": { + "x": "Category", + "y": "Value" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "James Walker", + "Value": 276 + }, + { + "Category": "Paul Wilson", + "Value": 172 + }, + { + "Category": "Jessica Martin", + "Value": 476 + }, + { + "Category": "Christopher Moore", + "Value": 278 + }, + { + "Category": "Betty Wilson", + "Value": 645 + }, + { + "Category": "Steven Lewis", + "Value": 653 + }, + { + "Category": "Karen Lopez", + "Value": 775 + }, + { + "Category": "Sandra Wright", + "Value": 780 + }, + { + "Category": "Daniel King", + "Value": 496 + }, + { + "Category": "Mark Taylor", + "Value": 927 + }, + { + "Category": "Sandra Thomas", + "Value": 654 + }, + { + "Category": "Karen Rodriguez", + "Value": 655 + }, + { + "Category": "Patricia Jackson", + "Value": 768 + }, + { + "Category": "Donna Hill", + "Value": 922 + }, + { + "Category": "Donna White", + "Value": 66 + }, + { + "Category": "Michael Brown", + "Value": 471 + }, + { + "Category": "Elizabeth Robinson", + "Value": 458 + }, + { + "Category": "Mary Jones", + "Value": 633 + }, + { + "Category": "Richard Rodriguez", + "Value": 904 + }, + { + "Category": "Christopher Clark", + "Value": 668 + }, + { + "Category": "Christopher Lopez", + "Value": 404 + }, + { + "Category": "Susan Ramirez", + "Value": 618 + }, + { + "Category": "Steven Wilson", + "Value": 83 + }, + { + "Category": "Paul Anderson", + "Value": 779 + }, + { + "Category": "Joseph Rodriguez", + "Value": 381 + }, + { + "Category": "Elizabeth Wright", + "Value": 80 + }, + { + "Category": "Kimberly Jackson", + "Value": 420 + }, + { + "Category": "Betty Hernandez", + "Value": 711 + }, + { + "Category": "David King", + "Value": 388 + }, + { + "Category": "Matthew Lopez", + "Value": 975 + }, + { + "Category": "Susan Hernandez", + "Value": 450 + }, + { + "Category": "Jennifer Lee", + "Value": 107 + }, + { + "Category": "Richard Flores", + "Value": 18 + }, + { + "Category": "John Anderson", + "Value": 160 + }, + { + "Category": "Kimberly Wright", + "Value": 30 + }, + { + "Category": "Joseph Williams", + "Value": 784 + }, + { + "Category": "Lisa Torres", + "Value": 541 + }, + { + "Category": "Andrew Rodriguez", + "Value": 591 + }, + { + "Category": "Karen Johnson", + "Value": 847 + }, + { + "Category": "Steven Jones", + "Value": 826 + }, + { + "Category": "Joshua Ramirez", + "Value": 955 + }, + { + "Category": "Emily Martinez", + "Value": 626 + }, + { + "Category": "Robert Walker", + "Value": 546 + }, + { + "Category": "Robert Lewis", + "Value": 946 + }, + { + "Category": "Sandra Lopez", + "Value": 859 + }, + { + "Category": "Nancy Miller", + "Value": 326 + }, + { + "Category": "Christopher Sanchez", + "Value": 636 + }, + { + "Category": "Daniel Flores", + "Value": 111 + }, + { + "Category": "Mary Walker", + "Value": 334 + }, + { + "Category": "Anthony Ramirez", + "Value": 120 + }, + { + "Category": "Anthony Hill", + "Value": 602 + }, + { + "Category": "Matthew Miller", + "Value": 216 + }, + { + "Category": "Andrew King", + "Value": 160 + }, + { + "Category": "William Perez", + "Value": 932 + }, + { + "Category": "William Martinez", + "Value": 544 + }, + { + "Category": "Margaret Garcia", + "Value": 733 + }, + { + "Category": "Barbara Anderson", + "Value": 794 + }, + { + "Category": "Thomas Smith", + "Value": 724 + }, + { + "Category": "Kimberly Thomas", + "Value": 834 + }, + { + "Category": "Karen Garcia", + "Value": 378 + }, + { + "Category": "Sarah Torres", + "Value": 174 + }, + { + "Category": "Emily Hill", + "Value": 248 + }, + { + "Category": "Sarah Walker", + "Value": 312 + }, + { + "Category": "Michael Clark", + "Value": 451 + }, + { + "Category": "Joshua Wright", + "Value": 850 + }, + { + "Category": "Andrew Walker", + "Value": 541 + }, + { + "Category": "Nancy Young", + "Value": 831 + }, + { + "Category": "John Lewis", + "Value": 464 + }, + { + "Category": "John Brown", + "Value": 83 + }, + { + "Category": "Anthony Thomas", + "Value": 490 + }, + { + "Category": "Joshua Moore", + "Value": 212 + }, + { + "Category": "John Hernandez", + "Value": 977 + }, + { + "Category": "James Perez", + "Value": 282 + }, + { + "Category": "James Scott", + "Value": 476 + }, + { + "Category": "Matthew Sanchez", + "Value": 52 + }, + { + "Category": "Joseph Sanchez", + "Value": 108 + }, + { + "Category": "Paul Perez", + "Value": 464 + }, + { + "Category": "Joshua Rodriguez", + "Value": 307 + }, + { + "Category": "Anthony Sanchez", + "Value": 435 + }, + { + "Category": "Linda King", + "Value": 691 + }, + { + "Category": "Elizabeth Smith", + "Value": 982 + }, + { + "Category": "Sandra Miller", + "Value": 792 + }, + { + "Category": "Nancy Allen", + "Value": 991 + }, + { + "Category": "Patricia Brown", + "Value": 99 + }, + { + "Category": "Lisa Clark", + "Value": 756 + }, + { + "Category": "Lisa Thompson", + "Value": 702 + }, + { + "Category": "Nancy Clark", + "Value": 214 + }, + { + "Category": "Steven Miller", + "Value": 43 + }, + { + "Category": "Charles King", + "Value": 143 + }, + { + "Category": "Paul Harris", + "Value": 586 + }, + { + "Category": "Ashley Jackson", + "Value": 775 + }, + { + "Category": "John Moore", + "Value": 974 + }, + { + "Category": "Betty Flores", + "Value": 756 + }, + { + "Category": "Linda Young", + "Value": 721 + }, + { + "Category": "Joshua Jones", + "Value": 562 + }, + { + "Category": "Margaret Anderson", + "Value": 21 + }, + { + "Category": "Anthony Wilson", + "Value": 545 + }, + { + "Category": "Karen Jones", + "Value": 618 + }, + { + "Category": "Daniel Rodriguez", + "Value": 817 + }, + { + "Category": "Betty Clark", + "Value": 337 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/bar-chart/04-card5.flint.json b/test-harness/excel/evaluations/inputs/bar-chart/04-card5.flint.json new file mode 100644 index 00000000..100b7d51 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/bar-chart/04-card5.flint.json @@ -0,0 +1,98 @@ +{ + "semantic_types": { + "Category": "Category", + "Value": "Quantity", + "Segment": "Category" + }, + "chart_spec": { + "chartType": "Bar Chart", + "encodings": { + "x": "Category", + "y": "Value", + "color": "Segment" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Laptop", + "Value": 878, + "Segment": "USA" + }, + { + "Category": "Laptop", + "Value": 190, + "Segment": "China" + }, + { + "Category": "Laptop", + "Value": 495, + "Segment": "Japan" + }, + { + "Category": "Phone", + "Value": 221, + "Segment": "USA" + }, + { + "Category": "Phone", + "Value": 853, + "Segment": "China" + }, + { + "Category": "Phone", + "Value": 409, + "Segment": "Japan" + }, + { + "Category": "Tablet", + "Value": 118, + "Segment": "USA" + }, + { + "Category": "Tablet", + "Value": 607, + "Segment": "China" + }, + { + "Category": "Tablet", + "Value": 976, + "Segment": "Japan" + }, + { + "Category": "Desktop", + "Value": 926, + "Segment": "USA" + }, + { + "Category": "Desktop", + "Value": 928, + "Segment": "China" + }, + { + "Category": "Desktop", + "Value": 675, + "Segment": "Japan" + }, + { + "Category": "Monitor", + "Value": 134, + "Segment": "USA" + }, + { + "Category": "Monitor", + "Value": 172, + "Segment": "China" + }, + { + "Category": "Monitor", + "Value": 314, + "Segment": "Japan" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/bar-chart/05-card5.flint.json b/test-harness/excel/evaluations/inputs/bar-chart/05-card5.flint.json new file mode 100644 index 00000000..ec70014f --- /dev/null +++ b/test-harness/excel/evaluations/inputs/bar-chart/05-card5.flint.json @@ -0,0 +1,523 @@ +{ + "semantic_types": { + "Category": "Category", + "Value": "Quantity", + "Segment": "Category" + }, + "chart_spec": { + "chartType": "Bar Chart", + "encodings": { + "x": "Category", + "y": "Value", + "color": "Segment" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Laptop", + "Value": 786, + "Segment": "USA" + }, + { + "Category": "Laptop", + "Value": 647, + "Segment": "China" + }, + { + "Category": "Laptop", + "Value": 932, + "Segment": "Japan" + }, + { + "Category": "Laptop", + "Value": 332, + "Segment": "Germany" + }, + { + "Category": "Laptop", + "Value": 839, + "Segment": "UK" + }, + { + "Category": "Laptop", + "Value": 176, + "Segment": "France" + }, + { + "Category": "Laptop", + "Value": 653, + "Segment": "India" + }, + { + "Category": "Laptop", + "Value": 210, + "Segment": "Brazil" + }, + { + "Category": "Laptop", + "Value": 751, + "Segment": "Canada" + }, + { + "Category": "Laptop", + "Value": 41, + "Segment": "Australia" + }, + { + "Category": "Laptop", + "Value": 128, + "Segment": "South Korea" + }, + { + "Category": "Laptop", + "Value": 569, + "Segment": "Mexico" + }, + { + "Category": "Laptop", + "Value": 225, + "Segment": "Italy" + }, + { + "Category": "Laptop", + "Value": 228, + "Segment": "Spain" + }, + { + "Category": "Laptop", + "Value": 115, + "Segment": "Russia" + }, + { + "Category": "Laptop", + "Value": 539, + "Segment": "Netherlands" + }, + { + "Category": "Laptop", + "Value": 313, + "Segment": "Sweden" + }, + { + "Category": "Laptop", + "Value": 516, + "Segment": "Norway" + }, + { + "Category": "Laptop", + "Value": 322, + "Segment": "Denmark" + }, + { + "Category": "Laptop", + "Value": 535, + "Segment": "Finland" + }, + { + "Category": "Phone", + "Value": 953, + "Segment": "USA" + }, + { + "Category": "Phone", + "Value": 238, + "Segment": "China" + }, + { + "Category": "Phone", + "Value": 896, + "Segment": "Japan" + }, + { + "Category": "Phone", + "Value": 176, + "Segment": "Germany" + }, + { + "Category": "Phone", + "Value": 173, + "Segment": "UK" + }, + { + "Category": "Phone", + "Value": 530, + "Segment": "France" + }, + { + "Category": "Phone", + "Value": 960, + "Segment": "India" + }, + { + "Category": "Phone", + "Value": 893, + "Segment": "Brazil" + }, + { + "Category": "Phone", + "Value": 22, + "Segment": "Canada" + }, + { + "Category": "Phone", + "Value": 95, + "Segment": "Australia" + }, + { + "Category": "Phone", + "Value": 135, + "Segment": "South Korea" + }, + { + "Category": "Phone", + "Value": 600, + "Segment": "Mexico" + }, + { + "Category": "Phone", + "Value": 49, + "Segment": "Italy" + }, + { + "Category": "Phone", + "Value": 759, + "Segment": "Spain" + }, + { + "Category": "Phone", + "Value": 589, + "Segment": "Russia" + }, + { + "Category": "Phone", + "Value": 232, + "Segment": "Netherlands" + }, + { + "Category": "Phone", + "Value": 145, + "Segment": "Sweden" + }, + { + "Category": "Phone", + "Value": 281, + "Segment": "Norway" + }, + { + "Category": "Phone", + "Value": 934, + "Segment": "Denmark" + }, + { + "Category": "Phone", + "Value": 475, + "Segment": "Finland" + }, + { + "Category": "Tablet", + "Value": 899, + "Segment": "USA" + }, + { + "Category": "Tablet", + "Value": 228, + "Segment": "China" + }, + { + "Category": "Tablet", + "Value": 717, + "Segment": "Japan" + }, + { + "Category": "Tablet", + "Value": 447, + "Segment": "Germany" + }, + { + "Category": "Tablet", + "Value": 136, + "Segment": "UK" + }, + { + "Category": "Tablet", + "Value": 932, + "Segment": "France" + }, + { + "Category": "Tablet", + "Value": 745, + "Segment": "India" + }, + { + "Category": "Tablet", + "Value": 449, + "Segment": "Brazil" + }, + { + "Category": "Tablet", + "Value": 350, + "Segment": "Canada" + }, + { + "Category": "Tablet", + "Value": 409, + "Segment": "Australia" + }, + { + "Category": "Tablet", + "Value": 675, + "Segment": "South Korea" + }, + { + "Category": "Tablet", + "Value": 660, + "Segment": "Mexico" + }, + { + "Category": "Tablet", + "Value": 14, + "Segment": "Italy" + }, + { + "Category": "Tablet", + "Value": 975, + "Segment": "Spain" + }, + { + "Category": "Tablet", + "Value": 927, + "Segment": "Russia" + }, + { + "Category": "Tablet", + "Value": 569, + "Segment": "Netherlands" + }, + { + "Category": "Tablet", + "Value": 81, + "Segment": "Sweden" + }, + { + "Category": "Tablet", + "Value": 657, + "Segment": "Norway" + }, + { + "Category": "Tablet", + "Value": 180, + "Segment": "Denmark" + }, + { + "Category": "Tablet", + "Value": 910, + "Segment": "Finland" + }, + { + "Category": "Desktop", + "Value": 607, + "Segment": "USA" + }, + { + "Category": "Desktop", + "Value": 504, + "Segment": "China" + }, + { + "Category": "Desktop", + "Value": 339, + "Segment": "Japan" + }, + { + "Category": "Desktop", + "Value": 524, + "Segment": "Germany" + }, + { + "Category": "Desktop", + "Value": 349, + "Segment": "UK" + }, + { + "Category": "Desktop", + "Value": 895, + "Segment": "France" + }, + { + "Category": "Desktop", + "Value": 770, + "Segment": "India" + }, + { + "Category": "Desktop", + "Value": 213, + "Segment": "Brazil" + }, + { + "Category": "Desktop", + "Value": 956, + "Segment": "Canada" + }, + { + "Category": "Desktop", + "Value": 667, + "Segment": "Australia" + }, + { + "Category": "Desktop", + "Value": 592, + "Segment": "South Korea" + }, + { + "Category": "Desktop", + "Value": 12, + "Segment": "Mexico" + }, + { + "Category": "Desktop", + "Value": 401, + "Segment": "Italy" + }, + { + "Category": "Desktop", + "Value": 920, + "Segment": "Spain" + }, + { + "Category": "Desktop", + "Value": 44, + "Segment": "Russia" + }, + { + "Category": "Desktop", + "Value": 937, + "Segment": "Netherlands" + }, + { + "Category": "Desktop", + "Value": 558, + "Segment": "Sweden" + }, + { + "Category": "Desktop", + "Value": 606, + "Segment": "Norway" + }, + { + "Category": "Desktop", + "Value": 578, + "Segment": "Denmark" + }, + { + "Category": "Desktop", + "Value": 471, + "Segment": "Finland" + }, + { + "Category": "Monitor", + "Value": 159, + "Segment": "USA" + }, + { + "Category": "Monitor", + "Value": 973, + "Segment": "China" + }, + { + "Category": "Monitor", + "Value": 756, + "Segment": "Japan" + }, + { + "Category": "Monitor", + "Value": 668, + "Segment": "Germany" + }, + { + "Category": "Monitor", + "Value": 521, + "Segment": "UK" + }, + { + "Category": "Monitor", + "Value": 160, + "Segment": "France" + }, + { + "Category": "Monitor", + "Value": 913, + "Segment": "India" + }, + { + "Category": "Monitor", + "Value": 367, + "Segment": "Brazil" + }, + { + "Category": "Monitor", + "Value": 58, + "Segment": "Canada" + }, + { + "Category": "Monitor", + "Value": 639, + "Segment": "Australia" + }, + { + "Category": "Monitor", + "Value": 69, + "Segment": "South Korea" + }, + { + "Category": "Monitor", + "Value": 97, + "Segment": "Mexico" + }, + { + "Category": "Monitor", + "Value": 342, + "Segment": "Italy" + }, + { + "Category": "Monitor", + "Value": 736, + "Segment": "Spain" + }, + { + "Category": "Monitor", + "Value": 919, + "Segment": "Russia" + }, + { + "Category": "Monitor", + "Value": 775, + "Segment": "Netherlands" + }, + { + "Category": "Monitor", + "Value": 257, + "Segment": "Sweden" + }, + { + "Category": "Monitor", + "Value": 66, + "Segment": "Norway" + }, + { + "Category": "Monitor", + "Value": 531, + "Segment": "Denmark" + }, + { + "Category": "Monitor", + "Value": 646, + "Segment": "Finland" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/bar-chart/06-card10.flint.json b/test-harness/excel/evaluations/inputs/bar-chart/06-card10.flint.json new file mode 100644 index 00000000..6af11afa --- /dev/null +++ b/test-harness/excel/evaluations/inputs/bar-chart/06-card10.flint.json @@ -0,0 +1,61 @@ +{ + "semantic_types": { + "X": "Quantity", + "Group": "Category" + }, + "chart_spec": { + "chartType": "Bar Chart", + "encodings": { + "x": "X", + "y": "Group" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Group": "Laptop", + "X": 893 + }, + { + "Group": "Phone", + "X": 872 + }, + { + "Group": "Tablet", + "X": 460 + }, + { + "Group": "Desktop", + "X": 182 + }, + { + "Group": "Monitor", + "X": 406 + }, + { + "Group": "Keyboard", + "X": 958 + }, + { + "Group": "Mouse", + "X": 391 + }, + { + "Group": "Headphones", + "X": 361 + }, + { + "Group": "Speaker", + "X": 115 + }, + { + "Group": "Camera", + "X": 884 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/bar-chart/07-card96.flint.json b/test-harness/excel/evaluations/inputs/bar-chart/07-card96.flint.json new file mode 100644 index 00000000..000f554f --- /dev/null +++ b/test-harness/excel/evaluations/inputs/bar-chart/07-card96.flint.json @@ -0,0 +1,421 @@ +{ + "semantic_types": { + "X": "Quantity", + "Group": "Category" + }, + "chart_spec": { + "chartType": "Bar Chart", + "encodings": { + "x": "X", + "y": "Group" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Group": "James Walker", + "X": 224 + }, + { + "Group": "Paul Wilson", + "X": 757 + }, + { + "Group": "Jessica Martin", + "X": 986 + }, + { + "Group": "Christopher Moore", + "X": 922 + }, + { + "Group": "Betty Wilson", + "X": 225 + }, + { + "Group": "Steven Lewis", + "X": 409 + }, + { + "Group": "Karen Lopez", + "X": 690 + }, + { + "Group": "Sandra Wright", + "X": 393 + }, + { + "Group": "Daniel King", + "X": 254 + }, + { + "Group": "Mark Taylor", + "X": 223 + }, + { + "Group": "Sandra Thomas", + "X": 403 + }, + { + "Group": "Karen Rodriguez", + "X": 140 + }, + { + "Group": "Patricia Jackson", + "X": 191 + }, + { + "Group": "Donna Hill", + "X": 330 + }, + { + "Group": "Donna White", + "X": 411 + }, + { + "Group": "Michael Brown", + "X": 973 + }, + { + "Group": "Elizabeth Robinson", + "X": 649 + }, + { + "Group": "Mary Jones", + "X": 816 + }, + { + "Group": "Richard Rodriguez", + "X": 110 + }, + { + "Group": "Christopher Clark", + "X": 691 + }, + { + "Group": "Christopher Lopez", + "X": 837 + }, + { + "Group": "Susan Ramirez", + "X": 775 + }, + { + "Group": "Steven Wilson", + "X": 796 + }, + { + "Group": "Paul Anderson", + "X": 720 + }, + { + "Group": "Joseph Rodriguez", + "X": 366 + }, + { + "Group": "Elizabeth Wright", + "X": 172 + }, + { + "Group": "Kimberly Jackson", + "X": 942 + }, + { + "Group": "Betty Hernandez", + "X": 477 + }, + { + "Group": "David King", + "X": 605 + }, + { + "Group": "Matthew Lopez", + "X": 482 + }, + { + "Group": "Susan Hernandez", + "X": 628 + }, + { + "Group": "Jennifer Lee", + "X": 301 + }, + { + "Group": "Richard Flores", + "X": 953 + }, + { + "Group": "John Anderson", + "X": 350 + }, + { + "Group": "Kimberly Wright", + "X": 648 + }, + { + "Group": "Joseph Williams", + "X": 823 + }, + { + "Group": "Lisa Torres", + "X": 704 + }, + { + "Group": "Andrew Rodriguez", + "X": 879 + }, + { + "Group": "Karen Johnson", + "X": 984 + }, + { + "Group": "Steven Jones", + "X": 746 + }, + { + "Group": "Joshua Ramirez", + "X": 265 + }, + { + "Group": "Emily Martinez", + "X": 616 + }, + { + "Group": "Robert Walker", + "X": 397 + }, + { + "Group": "Robert Lewis", + "X": 801 + }, + { + "Group": "Sandra Lopez", + "X": 967 + }, + { + "Group": "Nancy Miller", + "X": 306 + }, + { + "Group": "Christopher Sanchez", + "X": 311 + }, + { + "Group": "Daniel Flores", + "X": 177 + }, + { + "Group": "Mary Walker", + "X": 537 + }, + { + "Group": "Anthony Ramirez", + "X": 32 + }, + { + "Group": "Anthony Hill", + "X": 333 + }, + { + "Group": "Matthew Miller", + "X": 687 + }, + { + "Group": "Andrew King", + "X": 901 + }, + { + "Group": "William Perez", + "X": 605 + }, + { + "Group": "William Martinez", + "X": 538 + }, + { + "Group": "Margaret Garcia", + "X": 856 + }, + { + "Group": "Barbara Anderson", + "X": 83 + }, + { + "Group": "Thomas Smith", + "X": 814 + }, + { + "Group": "Kimberly Thomas", + "X": 810 + }, + { + "Group": "Karen Garcia", + "X": 94 + }, + { + "Group": "Sarah Torres", + "X": 885 + }, + { + "Group": "Emily Hill", + "X": 32 + }, + { + "Group": "Sarah Walker", + "X": 309 + }, + { + "Group": "Michael Clark", + "X": 690 + }, + { + "Group": "Joshua Wright", + "X": 594 + }, + { + "Group": "Andrew Walker", + "X": 785 + }, + { + "Group": "Nancy Young", + "X": 930 + }, + { + "Group": "John Lewis", + "X": 828 + }, + { + "Group": "John Brown", + "X": 974 + }, + { + "Group": "Anthony Thomas", + "X": 398 + }, + { + "Group": "Joshua Moore", + "X": 187 + }, + { + "Group": "John Hernandez", + "X": 627 + }, + { + "Group": "James Perez", + "X": 400 + }, + { + "Group": "James Scott", + "X": 862 + }, + { + "Group": "Matthew Sanchez", + "X": 86 + }, + { + "Group": "Joseph Sanchez", + "X": 481 + }, + { + "Group": "Paul Perez", + "X": 79 + }, + { + "Group": "Joshua Rodriguez", + "X": 26 + }, + { + "Group": "Anthony Sanchez", + "X": 164 + }, + { + "Group": "Linda King", + "X": 53 + }, + { + "Group": "Elizabeth Smith", + "X": 717 + }, + { + "Group": "Sandra Miller", + "X": 144 + }, + { + "Group": "Nancy Allen", + "X": 191 + }, + { + "Group": "Patricia Brown", + "X": 568 + }, + { + "Group": "Lisa Clark", + "X": 654 + }, + { + "Group": "Lisa Thompson", + "X": 49 + }, + { + "Group": "Nancy Clark", + "X": 20 + }, + { + "Group": "Steven Miller", + "X": 388 + }, + { + "Group": "Charles King", + "X": 179 + }, + { + "Group": "Paul Harris", + "X": 288 + }, + { + "Group": "Ashley Jackson", + "X": 925 + }, + { + "Group": "John Moore", + "X": 500 + }, + { + "Group": "Betty Flores", + "X": 427 + }, + { + "Group": "Linda Young", + "X": 305 + }, + { + "Group": "Joshua Jones", + "X": 618 + }, + { + "Group": "Margaret Anderson", + "X": 787 + }, + { + "Group": "Anthony Wilson", + "X": 665 + }, + { + "Group": "Karen Jones", + "X": 19 + }, + { + "Group": "Daniel Rodriguez", + "X": 677 + }, + { + "Group": "Betty Clark", + "X": 404 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/bar-chart/08-card29.flint.json b/test-harness/excel/evaluations/inputs/bar-chart/08-card29.flint.json new file mode 100644 index 00000000..f3b5b906 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/bar-chart/08-card29.flint.json @@ -0,0 +1,173 @@ +{ + "semantic_types": { + "X": "Quantity", + "Group": "Category", + "Segment": "Category" + }, + "chart_spec": { + "chartType": "Bar Chart", + "encodings": { + "x": "X", + "y": "Group", + "color": "Segment" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Group": "Laptop", + "X": 408, + "Segment": "USA" + }, + { + "Group": "Laptop", + "X": 579, + "Segment": "China" + }, + { + "Group": "Laptop", + "X": 713, + "Segment": "Japan" + }, + { + "Group": "Phone", + "X": 216, + "Segment": "USA" + }, + { + "Group": "Phone", + "X": 84, + "Segment": "China" + }, + { + "Group": "Phone", + "X": 698, + "Segment": "Japan" + }, + { + "Group": "Tablet", + "X": 785, + "Segment": "USA" + }, + { + "Group": "Tablet", + "X": 667, + "Segment": "China" + }, + { + "Group": "Tablet", + "X": 250, + "Segment": "Japan" + }, + { + "Group": "Desktop", + "X": 179, + "Segment": "USA" + }, + { + "Group": "Desktop", + "X": 162, + "Segment": "China" + }, + { + "Group": "Desktop", + "X": 572, + "Segment": "Japan" + }, + { + "Group": "Monitor", + "X": 952, + "Segment": "USA" + }, + { + "Group": "Monitor", + "X": 392, + "Segment": "China" + }, + { + "Group": "Monitor", + "X": 127, + "Segment": "Japan" + }, + { + "Group": "Keyboard", + "X": 431, + "Segment": "USA" + }, + { + "Group": "Keyboard", + "X": 573, + "Segment": "China" + }, + { + "Group": "Keyboard", + "X": 992, + "Segment": "Japan" + }, + { + "Group": "Mouse", + "X": 315, + "Segment": "USA" + }, + { + "Group": "Mouse", + "X": 337, + "Segment": "China" + }, + { + "Group": "Mouse", + "X": 306, + "Segment": "Japan" + }, + { + "Group": "Headphones", + "X": 671, + "Segment": "USA" + }, + { + "Group": "Headphones", + "X": 646, + "Segment": "China" + }, + { + "Group": "Headphones", + "X": 638, + "Segment": "Japan" + }, + { + "Group": "Speaker", + "X": 484, + "Segment": "USA" + }, + { + "Group": "Speaker", + "X": 849, + "Segment": "China" + }, + { + "Group": "Speaker", + "X": 688, + "Segment": "Japan" + }, + { + "Group": "Camera", + "X": 408, + "Segment": "USA" + }, + { + "Group": "Camera", + "X": 973, + "Segment": "China" + }, + { + "Group": "Camera", + "X": 587, + "Segment": "Japan" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/bar-chart/09-card24.flint.json b/test-harness/excel/evaluations/inputs/bar-chart/09-card24.flint.json new file mode 100644 index 00000000..f684d3ed --- /dev/null +++ b/test-harness/excel/evaluations/inputs/bar-chart/09-card24.flint.json @@ -0,0 +1,117 @@ +{ + "semantic_types": { + "Date": "Date", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Bar Chart", + "encodings": { + "x": "Date", + "y": "Value" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Date": "2020-01-01", + "Value": 581 + }, + { + "Date": "2020-02-15", + "Value": 689 + }, + { + "Date": "2020-04-01", + "Value": 906 + }, + { + "Date": "2020-05-16", + "Value": 933 + }, + { + "Date": "2020-07-01", + "Value": 867 + }, + { + "Date": "2020-08-16", + "Value": 39 + }, + { + "Date": "2020-09-30", + "Value": 597 + }, + { + "Date": "2020-11-15", + "Value": 199 + }, + { + "Date": "2020-12-31", + "Value": 614 + }, + { + "Date": "2021-02-14", + "Value": 27 + }, + { + "Date": "2021-04-01", + "Value": 935 + }, + { + "Date": "2021-05-16", + "Value": 386 + }, + { + "Date": "2021-07-01", + "Value": 105 + }, + { + "Date": "2021-08-16", + "Value": 592 + }, + { + "Date": "2021-09-30", + "Value": 78 + }, + { + "Date": "2021-11-15", + "Value": 533 + }, + { + "Date": "2021-12-31", + "Value": 73 + }, + { + "Date": "2022-02-14", + "Value": 37 + }, + { + "Date": "2022-04-01", + "Value": 383 + }, + { + "Date": "2022-05-16", + "Value": 705 + }, + { + "Date": "2022-07-01", + "Value": 70 + }, + { + "Date": "2022-08-16", + "Value": 783 + }, + { + "Date": "2022-09-30", + "Value": 719 + }, + { + "Date": "2022-11-15", + "Value": 999 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/bar-chart/10-card100.flint.json b/test-harness/excel/evaluations/inputs/bar-chart/10-card100.flint.json new file mode 100644 index 00000000..cd8430bf --- /dev/null +++ b/test-harness/excel/evaluations/inputs/bar-chart/10-card100.flint.json @@ -0,0 +1,421 @@ +{ + "semantic_types": { + "Date": "Date", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Bar Chart", + "encodings": { + "x": "Date", + "y": "Value" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Date": "2020-01-01", + "Value": 652 + }, + { + "Date": "2020-01-11", + "Value": 41 + }, + { + "Date": "2020-01-22", + "Value": 598 + }, + { + "Date": "2020-02-02", + "Value": 375 + }, + { + "Date": "2020-02-13", + "Value": 568 + }, + { + "Date": "2020-02-24", + "Value": 780 + }, + { + "Date": "2020-03-06", + "Value": 125 + }, + { + "Date": "2020-03-17", + "Value": 126 + }, + { + "Date": "2020-03-28", + "Value": 750 + }, + { + "Date": "2020-04-08", + "Value": 691 + }, + { + "Date": "2020-04-19", + "Value": 247 + }, + { + "Date": "2020-04-30", + "Value": 174 + }, + { + "Date": "2020-05-11", + "Value": 623 + }, + { + "Date": "2020-05-22", + "Value": 936 + }, + { + "Date": "2020-06-02", + "Value": 757 + }, + { + "Date": "2020-06-13", + "Value": 966 + }, + { + "Date": "2020-06-24", + "Value": 621 + }, + { + "Date": "2020-07-05", + "Value": 897 + }, + { + "Date": "2020-07-16", + "Value": 934 + }, + { + "Date": "2020-07-27", + "Value": 630 + }, + { + "Date": "2020-08-07", + "Value": 563 + }, + { + "Date": "2020-08-17", + "Value": 258 + }, + { + "Date": "2020-08-28", + "Value": 342 + }, + { + "Date": "2020-09-08", + "Value": 829 + }, + { + "Date": "2020-09-19", + "Value": 141 + }, + { + "Date": "2020-09-30", + "Value": 418 + }, + { + "Date": "2020-10-11", + "Value": 764 + }, + { + "Date": "2020-10-22", + "Value": 597 + }, + { + "Date": "2020-11-02", + "Value": 293 + }, + { + "Date": "2020-11-13", + "Value": 409 + }, + { + "Date": "2020-11-24", + "Value": 696 + }, + { + "Date": "2020-12-05", + "Value": 812 + }, + { + "Date": "2020-12-16", + "Value": 431 + }, + { + "Date": "2020-12-27", + "Value": 902 + }, + { + "Date": "2021-01-07", + "Value": 161 + }, + { + "Date": "2021-01-18", + "Value": 439 + }, + { + "Date": "2021-01-29", + "Value": 312 + }, + { + "Date": "2021-02-09", + "Value": 794 + }, + { + "Date": "2021-02-20", + "Value": 464 + }, + { + "Date": "2021-03-03", + "Value": 71 + }, + { + "Date": "2021-03-14", + "Value": 491 + }, + { + "Date": "2021-03-24", + "Value": 193 + }, + { + "Date": "2021-04-04", + "Value": 368 + }, + { + "Date": "2021-04-15", + "Value": 555 + }, + { + "Date": "2021-04-26", + "Value": 661 + }, + { + "Date": "2021-05-07", + "Value": 957 + }, + { + "Date": "2021-05-18", + "Value": 374 + }, + { + "Date": "2021-05-29", + "Value": 701 + }, + { + "Date": "2021-06-09", + "Value": 612 + }, + { + "Date": "2021-06-20", + "Value": 601 + }, + { + "Date": "2021-07-01", + "Value": 937 + }, + { + "Date": "2021-07-12", + "Value": 199 + }, + { + "Date": "2021-07-23", + "Value": 258 + }, + { + "Date": "2021-08-03", + "Value": 744 + }, + { + "Date": "2021-08-14", + "Value": 536 + }, + { + "Date": "2021-08-25", + "Value": 624 + }, + { + "Date": "2021-09-05", + "Value": 370 + }, + { + "Date": "2021-09-16", + "Value": 341 + }, + { + "Date": "2021-09-27", + "Value": 964 + }, + { + "Date": "2021-10-08", + "Value": 45 + }, + { + "Date": "2021-10-19", + "Value": 430 + }, + { + "Date": "2021-10-29", + "Value": 944 + }, + { + "Date": "2021-11-09", + "Value": 409 + }, + { + "Date": "2021-11-20", + "Value": 25 + }, + { + "Date": "2021-12-01", + "Value": 966 + }, + { + "Date": "2021-12-12", + "Value": 912 + }, + { + "Date": "2021-12-23", + "Value": 996 + }, + { + "Date": "2022-01-03", + "Value": 926 + }, + { + "Date": "2022-01-14", + "Value": 198 + }, + { + "Date": "2022-01-25", + "Value": 175 + }, + { + "Date": "2022-02-05", + "Value": 680 + }, + { + "Date": "2022-02-16", + "Value": 640 + }, + { + "Date": "2022-02-27", + "Value": 67 + }, + { + "Date": "2022-03-10", + "Value": 175 + }, + { + "Date": "2022-03-21", + "Value": 268 + }, + { + "Date": "2022-04-01", + "Value": 270 + }, + { + "Date": "2022-04-12", + "Value": 664 + }, + { + "Date": "2022-04-23", + "Value": 155 + }, + { + "Date": "2022-05-04", + "Value": 485 + }, + { + "Date": "2022-05-15", + "Value": 375 + }, + { + "Date": "2022-05-26", + "Value": 308 + }, + { + "Date": "2022-06-05", + "Value": 597 + }, + { + "Date": "2022-06-16", + "Value": 416 + }, + { + "Date": "2022-06-27", + "Value": 976 + }, + { + "Date": "2022-07-08", + "Value": 766 + }, + { + "Date": "2022-07-19", + "Value": 207 + }, + { + "Date": "2022-07-30", + "Value": 500 + }, + { + "Date": "2022-08-10", + "Value": 917 + }, + { + "Date": "2022-08-21", + "Value": 424 + }, + { + "Date": "2022-09-01", + "Value": 114 + }, + { + "Date": "2022-09-12", + "Value": 408 + }, + { + "Date": "2022-09-23", + "Value": 797 + }, + { + "Date": "2022-10-04", + "Value": 361 + }, + { + "Date": "2022-10-15", + "Value": 195 + }, + { + "Date": "2022-10-26", + "Value": 662 + }, + { + "Date": "2022-11-06", + "Value": 376 + }, + { + "Date": "2022-11-17", + "Value": 172 + }, + { + "Date": "2022-11-28", + "Value": 918 + }, + { + "Date": "2022-12-09", + "Value": 202 + }, + { + "Date": "2022-12-20", + "Value": 540 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/bar-chart/11-card24.flint.json b/test-harness/excel/evaluations/inputs/bar-chart/11-card24.flint.json new file mode 100644 index 00000000..8176107f --- /dev/null +++ b/test-harness/excel/evaluations/inputs/bar-chart/11-card24.flint.json @@ -0,0 +1,383 @@ +{ + "semantic_types": { + "Date": "Date", + "Value": "Quantity", + "Segment": "Category" + }, + "chart_spec": { + "chartType": "Bar Chart", + "encodings": { + "x": "Date", + "y": "Value", + "color": "Segment" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Date": "2020-01-01", + "Value": 286, + "Segment": "Laptop" + }, + { + "Date": "2020-01-01", + "Value": 721, + "Segment": "Phone" + }, + { + "Date": "2020-01-01", + "Value": 776, + "Segment": "Tablet" + }, + { + "Date": "2020-02-15", + "Value": 907, + "Segment": "Laptop" + }, + { + "Date": "2020-02-15", + "Value": 597, + "Segment": "Phone" + }, + { + "Date": "2020-02-15", + "Value": 334, + "Segment": "Tablet" + }, + { + "Date": "2020-04-01", + "Value": 539, + "Segment": "Laptop" + }, + { + "Date": "2020-04-01", + "Value": 147, + "Segment": "Phone" + }, + { + "Date": "2020-04-01", + "Value": 259, + "Segment": "Tablet" + }, + { + "Date": "2020-05-16", + "Value": 973, + "Segment": "Laptop" + }, + { + "Date": "2020-05-16", + "Value": 490, + "Segment": "Phone" + }, + { + "Date": "2020-05-16", + "Value": 501, + "Segment": "Tablet" + }, + { + "Date": "2020-07-01", + "Value": 43, + "Segment": "Laptop" + }, + { + "Date": "2020-07-01", + "Value": 391, + "Segment": "Phone" + }, + { + "Date": "2020-07-01", + "Value": 637, + "Segment": "Tablet" + }, + { + "Date": "2020-08-16", + "Value": 18, + "Segment": "Laptop" + }, + { + "Date": "2020-08-16", + "Value": 773, + "Segment": "Phone" + }, + { + "Date": "2020-08-16", + "Value": 523, + "Segment": "Tablet" + }, + { + "Date": "2020-09-30", + "Value": 166, + "Segment": "Laptop" + }, + { + "Date": "2020-09-30", + "Value": 858, + "Segment": "Phone" + }, + { + "Date": "2020-09-30", + "Value": 395, + "Segment": "Tablet" + }, + { + "Date": "2020-11-15", + "Value": 726, + "Segment": "Laptop" + }, + { + "Date": "2020-11-15", + "Value": 361, + "Segment": "Phone" + }, + { + "Date": "2020-11-15", + "Value": 681, + "Segment": "Tablet" + }, + { + "Date": "2020-12-31", + "Value": 197, + "Segment": "Laptop" + }, + { + "Date": "2020-12-31", + "Value": 826, + "Segment": "Phone" + }, + { + "Date": "2020-12-31", + "Value": 663, + "Segment": "Tablet" + }, + { + "Date": "2021-02-14", + "Value": 979, + "Segment": "Laptop" + }, + { + "Date": "2021-02-14", + "Value": 907, + "Segment": "Phone" + }, + { + "Date": "2021-02-14", + "Value": 529, + "Segment": "Tablet" + }, + { + "Date": "2021-04-01", + "Value": 565, + "Segment": "Laptop" + }, + { + "Date": "2021-04-01", + "Value": 216, + "Segment": "Phone" + }, + { + "Date": "2021-04-01", + "Value": 951, + "Segment": "Tablet" + }, + { + "Date": "2021-05-16", + "Value": 512, + "Segment": "Laptop" + }, + { + "Date": "2021-05-16", + "Value": 178, + "Segment": "Phone" + }, + { + "Date": "2021-05-16", + "Value": 54, + "Segment": "Tablet" + }, + { + "Date": "2021-07-01", + "Value": 315, + "Segment": "Laptop" + }, + { + "Date": "2021-07-01", + "Value": 166, + "Segment": "Phone" + }, + { + "Date": "2021-07-01", + "Value": 246, + "Segment": "Tablet" + }, + { + "Date": "2021-08-16", + "Value": 977, + "Segment": "Laptop" + }, + { + "Date": "2021-08-16", + "Value": 502, + "Segment": "Phone" + }, + { + "Date": "2021-08-16", + "Value": 642, + "Segment": "Tablet" + }, + { + "Date": "2021-09-30", + "Value": 210, + "Segment": "Laptop" + }, + { + "Date": "2021-09-30", + "Value": 746, + "Segment": "Phone" + }, + { + "Date": "2021-09-30", + "Value": 883, + "Segment": "Tablet" + }, + { + "Date": "2021-11-15", + "Value": 371, + "Segment": "Laptop" + }, + { + "Date": "2021-11-15", + "Value": 381, + "Segment": "Phone" + }, + { + "Date": "2021-11-15", + "Value": 165, + "Segment": "Tablet" + }, + { + "Date": "2021-12-31", + "Value": 373, + "Segment": "Laptop" + }, + { + "Date": "2021-12-31", + "Value": 289, + "Segment": "Phone" + }, + { + "Date": "2021-12-31", + "Value": 110, + "Segment": "Tablet" + }, + { + "Date": "2022-02-14", + "Value": 977, + "Segment": "Laptop" + }, + { + "Date": "2022-02-14", + "Value": 294, + "Segment": "Phone" + }, + { + "Date": "2022-02-14", + "Value": 540, + "Segment": "Tablet" + }, + { + "Date": "2022-04-01", + "Value": 143, + "Segment": "Laptop" + }, + { + "Date": "2022-04-01", + "Value": 330, + "Segment": "Phone" + }, + { + "Date": "2022-04-01", + "Value": 616, + "Segment": "Tablet" + }, + { + "Date": "2022-05-16", + "Value": 474, + "Segment": "Laptop" + }, + { + "Date": "2022-05-16", + "Value": 524, + "Segment": "Phone" + }, + { + "Date": "2022-05-16", + "Value": 686, + "Segment": "Tablet" + }, + { + "Date": "2022-07-01", + "Value": 354, + "Segment": "Laptop" + }, + { + "Date": "2022-07-01", + "Value": 410, + "Segment": "Phone" + }, + { + "Date": "2022-07-01", + "Value": 590, + "Segment": "Tablet" + }, + { + "Date": "2022-08-16", + "Value": 608, + "Segment": "Laptop" + }, + { + "Date": "2022-08-16", + "Value": 124, + "Segment": "Phone" + }, + { + "Date": "2022-08-16", + "Value": 604, + "Segment": "Tablet" + }, + { + "Date": "2022-09-30", + "Value": 387, + "Segment": "Laptop" + }, + { + "Date": "2022-09-30", + "Value": 752, + "Segment": "Phone" + }, + { + "Date": "2022-09-30", + "Value": 254, + "Segment": "Tablet" + }, + { + "Date": "2022-11-15", + "Value": 966, + "Segment": "Laptop" + }, + { + "Date": "2022-11-15", + "Value": 588, + "Segment": "Phone" + }, + { + "Date": "2022-11-15", + "Value": 440, + "Segment": "Tablet" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/bar-chart/12-card18.flint.json b/test-harness/excel/evaluations/inputs/bar-chart/12-card18.flint.json new file mode 100644 index 00000000..89fa95ea --- /dev/null +++ b/test-harness/excel/evaluations/inputs/bar-chart/12-card18.flint.json @@ -0,0 +1,93 @@ +{ + "semantic_types": { + "X": "Quantity", + "EndDate": "Date" + }, + "chart_spec": { + "chartType": "Bar Chart", + "encodings": { + "x": "X", + "y": "EndDate" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "EndDate": "2020-01-01", + "X": 648 + }, + { + "EndDate": "2020-03-01", + "X": 944 + }, + { + "EndDate": "2020-05-01", + "X": 216 + }, + { + "EndDate": "2020-07-01", + "X": 185 + }, + { + "EndDate": "2020-08-31", + "X": 539 + }, + { + "EndDate": "2020-10-31", + "X": 151 + }, + { + "EndDate": "2020-12-31", + "X": 338 + }, + { + "EndDate": "2021-03-01", + "X": 709 + }, + { + "EndDate": "2021-05-01", + "X": 181 + }, + { + "EndDate": "2021-07-01", + "X": 931 + }, + { + "EndDate": "2021-08-31", + "X": 916 + }, + { + "EndDate": "2021-10-31", + "X": 61 + }, + { + "EndDate": "2021-12-31", + "X": 462 + }, + { + "EndDate": "2022-03-01", + "X": 900 + }, + { + "EndDate": "2022-05-01", + "X": 969 + }, + { + "EndDate": "2022-07-01", + "X": 650 + }, + { + "EndDate": "2022-08-31", + "X": 468 + }, + { + "EndDate": "2022-10-31", + "X": 186 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/bar-chart/13-card53.flint.json b/test-harness/excel/evaluations/inputs/bar-chart/13-card53.flint.json new file mode 100644 index 00000000..4d230211 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/bar-chart/13-card53.flint.json @@ -0,0 +1,293 @@ +{ + "semantic_types": { + "X": "Quantity", + "EndDate": "Date", + "Segment": "Category" + }, + "chart_spec": { + "chartType": "Bar Chart", + "encodings": { + "x": "X", + "y": "EndDate", + "color": "Segment" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "EndDate": "2020-01-01", + "X": 166, + "Segment": "Laptop" + }, + { + "EndDate": "2020-01-01", + "X": 838, + "Segment": "Phone" + }, + { + "EndDate": "2020-01-01", + "X": 74, + "Segment": "Tablet" + }, + { + "EndDate": "2020-03-01", + "X": 268, + "Segment": "Laptop" + }, + { + "EndDate": "2020-03-01", + "X": 614, + "Segment": "Phone" + }, + { + "EndDate": "2020-03-01", + "X": 950, + "Segment": "Tablet" + }, + { + "EndDate": "2020-05-01", + "X": 128, + "Segment": "Laptop" + }, + { + "EndDate": "2020-05-01", + "X": 727, + "Segment": "Phone" + }, + { + "EndDate": "2020-05-01", + "X": 457, + "Segment": "Tablet" + }, + { + "EndDate": "2020-07-01", + "X": 430, + "Segment": "Laptop" + }, + { + "EndDate": "2020-07-01", + "X": 383, + "Segment": "Phone" + }, + { + "EndDate": "2020-07-01", + "X": 172, + "Segment": "Tablet" + }, + { + "EndDate": "2020-08-31", + "X": 324, + "Segment": "Laptop" + }, + { + "EndDate": "2020-08-31", + "X": 167, + "Segment": "Phone" + }, + { + "EndDate": "2020-08-31", + "X": 296, + "Segment": "Tablet" + }, + { + "EndDate": "2020-10-31", + "X": 958, + "Segment": "Laptop" + }, + { + "EndDate": "2020-10-31", + "X": 216, + "Segment": "Phone" + }, + { + "EndDate": "2020-10-31", + "X": 656, + "Segment": "Tablet" + }, + { + "EndDate": "2020-12-31", + "X": 71, + "Segment": "Laptop" + }, + { + "EndDate": "2020-12-31", + "X": 365, + "Segment": "Phone" + }, + { + "EndDate": "2020-12-31", + "X": 735, + "Segment": "Tablet" + }, + { + "EndDate": "2021-03-01", + "X": 694, + "Segment": "Laptop" + }, + { + "EndDate": "2021-03-01", + "X": 63, + "Segment": "Phone" + }, + { + "EndDate": "2021-03-01", + "X": 754, + "Segment": "Tablet" + }, + { + "EndDate": "2021-05-01", + "X": 169, + "Segment": "Laptop" + }, + { + "EndDate": "2021-05-01", + "X": 841, + "Segment": "Phone" + }, + { + "EndDate": "2021-05-01", + "X": 762, + "Segment": "Tablet" + }, + { + "EndDate": "2021-07-01", + "X": 953, + "Segment": "Laptop" + }, + { + "EndDate": "2021-07-01", + "X": 809, + "Segment": "Phone" + }, + { + "EndDate": "2021-07-01", + "X": 200, + "Segment": "Tablet" + }, + { + "EndDate": "2021-08-31", + "X": 86, + "Segment": "Laptop" + }, + { + "EndDate": "2021-08-31", + "X": 545, + "Segment": "Phone" + }, + { + "EndDate": "2021-08-31", + "X": 162, + "Segment": "Tablet" + }, + { + "EndDate": "2021-10-31", + "X": 288, + "Segment": "Laptop" + }, + { + "EndDate": "2021-10-31", + "X": 922, + "Segment": "Phone" + }, + { + "EndDate": "2021-10-31", + "X": 530, + "Segment": "Tablet" + }, + { + "EndDate": "2021-12-31", + "X": 142, + "Segment": "Laptop" + }, + { + "EndDate": "2021-12-31", + "X": 546, + "Segment": "Phone" + }, + { + "EndDate": "2021-12-31", + "X": 116, + "Segment": "Tablet" + }, + { + "EndDate": "2022-03-01", + "X": 368, + "Segment": "Laptop" + }, + { + "EndDate": "2022-03-01", + "X": 12, + "Segment": "Phone" + }, + { + "EndDate": "2022-03-01", + "X": 657, + "Segment": "Tablet" + }, + { + "EndDate": "2022-05-01", + "X": 879, + "Segment": "Laptop" + }, + { + "EndDate": "2022-05-01", + "X": 248, + "Segment": "Phone" + }, + { + "EndDate": "2022-05-01", + "X": 157, + "Segment": "Tablet" + }, + { + "EndDate": "2022-07-01", + "X": 691, + "Segment": "Laptop" + }, + { + "EndDate": "2022-07-01", + "X": 694, + "Segment": "Phone" + }, + { + "EndDate": "2022-07-01", + "X": 458, + "Segment": "Tablet" + }, + { + "EndDate": "2022-08-31", + "X": 720, + "Segment": "Laptop" + }, + { + "EndDate": "2022-08-31", + "X": 848, + "Segment": "Phone" + }, + { + "EndDate": "2022-08-31", + "X": 287, + "Segment": "Tablet" + }, + { + "EndDate": "2022-10-31", + "X": 206, + "Segment": "Laptop" + }, + { + "EndDate": "2022-10-31", + "X": 108, + "Segment": "Phone" + }, + { + "EndDate": "2022-10-31", + "X": 591, + "Segment": "Tablet" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/bar-chart/14-card20.flint.json b/test-harness/excel/evaluations/inputs/bar-chart/14-card20.flint.json new file mode 100644 index 00000000..88a2e82e --- /dev/null +++ b/test-harness/excel/evaluations/inputs/bar-chart/14-card20.flint.json @@ -0,0 +1,101 @@ +{ + "semantic_types": { + "X": "Quantity", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Bar Chart", + "encodings": { + "x": "X", + "y": "Value" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 1, + "Value": 633 + }, + { + "X": 2, + "Value": 80 + }, + { + "X": 3, + "Value": 121 + }, + { + "X": 4, + "Value": 174 + }, + { + "X": 5, + "Value": 21 + }, + { + "X": 6, + "Value": 606 + }, + { + "X": 7, + "Value": 734 + }, + { + "X": 8, + "Value": 638 + }, + { + "X": 9, + "Value": 122 + }, + { + "X": 10, + "Value": 242 + }, + { + "X": 11, + "Value": 376 + }, + { + "X": 12, + "Value": 735 + }, + { + "X": 13, + "Value": 981 + }, + { + "X": 14, + "Value": 555 + }, + { + "X": 15, + "Value": 970 + }, + { + "X": 16, + "Value": 54 + }, + { + "X": 17, + "Value": 601 + }, + { + "X": 18, + "Value": 134 + }, + { + "X": 19, + "Value": 924 + }, + { + "X": 20, + "Value": 172 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/bar-chart/15-card30.flint.json b/test-harness/excel/evaluations/inputs/bar-chart/15-card30.flint.json new file mode 100644 index 00000000..5541613c --- /dev/null +++ b/test-harness/excel/evaluations/inputs/bar-chart/15-card30.flint.json @@ -0,0 +1,141 @@ +{ + "semantic_types": { + "X": "Quantity", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Bar Chart", + "encodings": { + "x": "X", + "y": "Value" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 1, + "Value": 390 + }, + { + "X": 2, + "Value": 934 + }, + { + "X": 3, + "Value": 91 + }, + { + "X": 4, + "Value": 151 + }, + { + "X": 5, + "Value": 615 + }, + { + "X": 6, + "Value": 442 + }, + { + "X": 7, + "Value": 332 + }, + { + "X": 8, + "Value": 151 + }, + { + "X": 9, + "Value": 857 + }, + { + "X": 10, + "Value": 708 + }, + { + "X": 11, + "Value": 746 + }, + { + "X": 12, + "Value": 875 + }, + { + "X": 13, + "Value": 83 + }, + { + "X": 14, + "Value": 799 + }, + { + "X": 15, + "Value": 517 + }, + { + "X": 16, + "Value": 167 + }, + { + "X": 17, + "Value": 890 + }, + { + "X": 18, + "Value": 140 + }, + { + "X": 19, + "Value": 130 + }, + { + "X": 20, + "Value": 235 + }, + { + "X": 21, + "Value": 145 + }, + { + "X": 22, + "Value": 174 + }, + { + "X": 23, + "Value": 170 + }, + { + "X": 24, + "Value": 214 + }, + { + "X": 25, + "Value": 74 + }, + { + "X": 26, + "Value": 511 + }, + { + "X": 27, + "Value": 519 + }, + { + "X": 28, + "Value": 721 + }, + { + "X": 29, + "Value": 304 + }, + { + "X": 30, + "Value": 191 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/bar-chart/16-card5.flint.json b/test-harness/excel/evaluations/inputs/bar-chart/16-card5.flint.json new file mode 100644 index 00000000..82dd90cd --- /dev/null +++ b/test-harness/excel/evaluations/inputs/bar-chart/16-card5.flint.json @@ -0,0 +1,89 @@ +{ + "semantic_types": { + "Category": "Category", + "Group": "Category" + }, + "chart_spec": { + "chartType": "Bar Chart", + "encodings": { + "x": "Category", + "y": "Group" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Laptop", + "Group": "USA" + }, + { + "Category": "Laptop", + "Group": "Japan" + }, + { + "Category": "Laptop", + "Group": "UK" + }, + { + "Category": "Phone", + "Group": "USA" + }, + { + "Category": "Phone", + "Group": "Japan" + }, + { + "Category": "Phone", + "Group": "Germany" + }, + { + "Category": "Phone", + "Group": "UK" + }, + { + "Category": "Tablet", + "Group": "USA" + }, + { + "Category": "Tablet", + "Group": "Japan" + }, + { + "Category": "Tablet", + "Group": "Germany" + }, + { + "Category": "Tablet", + "Group": "UK" + }, + { + "Category": "Desktop", + "Group": "China" + }, + { + "Category": "Desktop", + "Group": "Germany" + }, + { + "Category": "Desktop", + "Group": "UK" + }, + { + "Category": "Monitor", + "Group": "USA" + }, + { + "Category": "Monitor", + "Group": "China" + }, + { + "Category": "Monitor", + "Group": "Japan" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/bar-chart/17-card25.flint.json b/test-harness/excel/evaluations/inputs/bar-chart/17-card25.flint.json new file mode 100644 index 00000000..a934f537 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/bar-chart/17-card25.flint.json @@ -0,0 +1,121 @@ +{ + "semantic_types": { + "Date": "Date", + "Group": "Category" + }, + "chart_spec": { + "chartType": "Bar Chart", + "encodings": { + "x": "Date", + "y": "Group" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Date": "2020-01-01", + "Group": "Laptop" + }, + { + "Date": "2020-02-13", + "Group": "Desktop" + }, + { + "Date": "2020-03-28", + "Group": "Laptop" + }, + { + "Date": "2020-05-11", + "Group": "Phone" + }, + { + "Date": "2020-06-24", + "Group": "Monitor" + }, + { + "Date": "2020-08-07", + "Group": "Laptop" + }, + { + "Date": "2020-09-19", + "Group": "Laptop" + }, + { + "Date": "2020-11-02", + "Group": "Tablet" + }, + { + "Date": "2020-12-16", + "Group": "Tablet" + }, + { + "Date": "2021-01-29", + "Group": "Tablet" + }, + { + "Date": "2021-03-14", + "Group": "Monitor" + }, + { + "Date": "2021-04-26", + "Group": "Monitor" + }, + { + "Date": "2021-06-09", + "Group": "Phone" + }, + { + "Date": "2021-07-23", + "Group": "Desktop" + }, + { + "Date": "2021-09-05", + "Group": "Phone" + }, + { + "Date": "2021-10-19", + "Group": "Desktop" + }, + { + "Date": "2021-12-01", + "Group": "Phone" + }, + { + "Date": "2022-01-14", + "Group": "Desktop" + }, + { + "Date": "2022-02-27", + "Group": "Desktop" + }, + { + "Date": "2022-04-12", + "Group": "Desktop" + }, + { + "Date": "2022-05-26", + "Group": "Monitor" + }, + { + "Date": "2022-07-08", + "Group": "Laptop" + }, + { + "Date": "2022-08-21", + "Group": "Tablet" + }, + { + "Date": "2022-10-04", + "Group": "Desktop" + }, + { + "Date": "2022-11-17", + "Group": "Desktop" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/bar-chart/18-card5.flint.json b/test-harness/excel/evaluations/inputs/bar-chart/18-card5.flint.json new file mode 100644 index 00000000..29779751 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/bar-chart/18-card5.flint.json @@ -0,0 +1,41 @@ +{ + "semantic_types": { + "Category": "Category", + "EndDate": "Date" + }, + "chart_spec": { + "chartType": "Bar Chart", + "encodings": { + "x": "Category", + "y": "EndDate" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Laptop", + "EndDate": "2023-11-07" + }, + { + "Category": "Phone", + "EndDate": "2023-01-28" + }, + { + "Category": "Tablet", + "EndDate": "2023-07-24" + }, + { + "Category": "Desktop", + "EndDate": "2023-04-27" + }, + { + "Category": "Monitor", + "EndDate": "2023-07-12" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/boxplot/00-card5.flint.json b/test-harness/excel/evaluations/inputs/boxplot/00-card5.flint.json new file mode 100644 index 00000000..ca0d1961 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/boxplot/00-card5.flint.json @@ -0,0 +1,621 @@ +{ + "semantic_types": { + "Group": "Category", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Boxplot", + "encodings": { + "x": "Group", + "y": "Value" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Group": "Electronics", + "Value": 1 + }, + { + "Group": "Electronics", + "Value": 8 + }, + { + "Group": "Electronics", + "Value": 92 + }, + { + "Group": "Electronics", + "Value": 6 + }, + { + "Group": "Electronics", + "Value": 94 + }, + { + "Group": "Electronics", + "Value": 27 + }, + { + "Group": "Electronics", + "Value": 93 + }, + { + "Group": "Electronics", + "Value": 21 + }, + { + "Group": "Electronics", + "Value": 51 + }, + { + "Group": "Electronics", + "Value": 29 + }, + { + "Group": "Electronics", + "Value": 45 + }, + { + "Group": "Electronics", + "Value": 59 + }, + { + "Group": "Electronics", + "Value": 68 + }, + { + "Group": "Electronics", + "Value": 20 + }, + { + "Group": "Electronics", + "Value": 42 + }, + { + "Group": "Electronics", + "Value": 79 + }, + { + "Group": "Electronics", + "Value": 80 + }, + { + "Group": "Electronics", + "Value": 39 + }, + { + "Group": "Electronics", + "Value": 39 + }, + { + "Group": "Electronics", + "Value": 79 + }, + { + "Group": "Electronics", + "Value": 24 + }, + { + "Group": "Electronics", + "Value": 74 + }, + { + "Group": "Electronics", + "Value": 28 + }, + { + "Group": "Electronics", + "Value": 31 + }, + { + "Group": "Electronics", + "Value": 32 + }, + { + "Group": "Electronics", + "Value": 85 + }, + { + "Group": "Electronics", + "Value": 38 + }, + { + "Group": "Electronics", + "Value": 74 + }, + { + "Group": "Electronics", + "Value": 20 + }, + { + "Group": "Electronics", + "Value": 83 + }, + { + "Group": "Clothing", + "Value": 22 + }, + { + "Group": "Clothing", + "Value": 54 + }, + { + "Group": "Clothing", + "Value": 72 + }, + { + "Group": "Clothing", + "Value": 23 + }, + { + "Group": "Clothing", + "Value": 26 + }, + { + "Group": "Clothing", + "Value": 76 + }, + { + "Group": "Clothing", + "Value": 85 + }, + { + "Group": "Clothing", + "Value": 49 + }, + { + "Group": "Clothing", + "Value": 73 + }, + { + "Group": "Clothing", + "Value": 74 + }, + { + "Group": "Clothing", + "Value": 93 + }, + { + "Group": "Clothing", + "Value": 79 + }, + { + "Group": "Clothing", + "Value": 86 + }, + { + "Group": "Clothing", + "Value": 35 + }, + { + "Group": "Clothing", + "Value": 6 + }, + { + "Group": "Clothing", + "Value": 88 + }, + { + "Group": "Clothing", + "Value": 14 + }, + { + "Group": "Clothing", + "Value": 29 + }, + { + "Group": "Clothing", + "Value": 90 + }, + { + "Group": "Clothing", + "Value": 49 + }, + { + "Group": "Clothing", + "Value": 55 + }, + { + "Group": "Clothing", + "Value": 41 + }, + { + "Group": "Clothing", + "Value": 44 + }, + { + "Group": "Clothing", + "Value": 43 + }, + { + "Group": "Clothing", + "Value": 49 + }, + { + "Group": "Clothing", + "Value": 56 + }, + { + "Group": "Clothing", + "Value": 56 + }, + { + "Group": "Clothing", + "Value": 36 + }, + { + "Group": "Clothing", + "Value": 45 + }, + { + "Group": "Clothing", + "Value": 40 + }, + { + "Group": "Food", + "Value": 26 + }, + { + "Group": "Food", + "Value": 17 + }, + { + "Group": "Food", + "Value": 40 + }, + { + "Group": "Food", + "Value": 32 + }, + { + "Group": "Food", + "Value": 65 + }, + { + "Group": "Food", + "Value": 78 + }, + { + "Group": "Food", + "Value": 30 + }, + { + "Group": "Food", + "Value": 51 + }, + { + "Group": "Food", + "Value": 43 + }, + { + "Group": "Food", + "Value": 62 + }, + { + "Group": "Food", + "Value": 49 + }, + { + "Group": "Food", + "Value": 90 + }, + { + "Group": "Food", + "Value": 96 + }, + { + "Group": "Food", + "Value": 67 + }, + { + "Group": "Food", + "Value": 82 + }, + { + "Group": "Food", + "Value": 11 + }, + { + "Group": "Food", + "Value": 69 + }, + { + "Group": "Food", + "Value": 6 + }, + { + "Group": "Food", + "Value": 6 + }, + { + "Group": "Food", + "Value": 14 + }, + { + "Group": "Food", + "Value": 47 + }, + { + "Group": "Food", + "Value": 76 + }, + { + "Group": "Food", + "Value": 11 + }, + { + "Group": "Food", + "Value": 92 + }, + { + "Group": "Food", + "Value": 77 + }, + { + "Group": "Food", + "Value": 68 + }, + { + "Group": "Food", + "Value": 36 + }, + { + "Group": "Food", + "Value": 79 + }, + { + "Group": "Food", + "Value": 62 + }, + { + "Group": "Food", + "Value": 0 + }, + { + "Group": "Books", + "Value": 24 + }, + { + "Group": "Books", + "Value": 43 + }, + { + "Group": "Books", + "Value": 71 + }, + { + "Group": "Books", + "Value": 29 + }, + { + "Group": "Books", + "Value": 78 + }, + { + "Group": "Books", + "Value": 19 + }, + { + "Group": "Books", + "Value": 46 + }, + { + "Group": "Books", + "Value": 6 + }, + { + "Group": "Books", + "Value": 52 + }, + { + "Group": "Books", + "Value": 78 + }, + { + "Group": "Books", + "Value": 11 + }, + { + "Group": "Books", + "Value": 54 + }, + { + "Group": "Books", + "Value": 5 + }, + { + "Group": "Books", + "Value": 83 + }, + { + "Group": "Books", + "Value": 60 + }, + { + "Group": "Books", + "Value": 16 + }, + { + "Group": "Books", + "Value": 68 + }, + { + "Group": "Books", + "Value": 14 + }, + { + "Group": "Books", + "Value": 11 + }, + { + "Group": "Books", + "Value": 94 + }, + { + "Group": "Books", + "Value": 75 + }, + { + "Group": "Books", + "Value": 80 + }, + { + "Group": "Books", + "Value": 21 + }, + { + "Group": "Books", + "Value": 52 + }, + { + "Group": "Books", + "Value": 39 + }, + { + "Group": "Books", + "Value": 43 + }, + { + "Group": "Books", + "Value": 84 + }, + { + "Group": "Books", + "Value": 93 + }, + { + "Group": "Books", + "Value": 30 + }, + { + "Group": "Books", + "Value": 30 + }, + { + "Group": "Sports", + "Value": 69 + }, + { + "Group": "Sports", + "Value": 21 + }, + { + "Group": "Sports", + "Value": 10 + }, + { + "Group": "Sports", + "Value": 1 + }, + { + "Group": "Sports", + "Value": 81 + }, + { + "Group": "Sports", + "Value": 87 + }, + { + "Group": "Sports", + "Value": 53 + }, + { + "Group": "Sports", + "Value": 94 + }, + { + "Group": "Sports", + "Value": 63 + }, + { + "Group": "Sports", + "Value": 28 + }, + { + "Group": "Sports", + "Value": 89 + }, + { + "Group": "Sports", + "Value": 44 + }, + { + "Group": "Sports", + "Value": 23 + }, + { + "Group": "Sports", + "Value": 94 + }, + { + "Group": "Sports", + "Value": 7 + }, + { + "Group": "Sports", + "Value": 41 + }, + { + "Group": "Sports", + "Value": 82 + }, + { + "Group": "Sports", + "Value": 27 + }, + { + "Group": "Sports", + "Value": 3 + }, + { + "Group": "Sports", + "Value": 90 + }, + { + "Group": "Sports", + "Value": 8 + }, + { + "Group": "Sports", + "Value": 79 + }, + { + "Group": "Sports", + "Value": 30 + }, + { + "Group": "Sports", + "Value": 71 + }, + { + "Group": "Sports", + "Value": 31 + }, + { + "Group": "Sports", + "Value": 14 + }, + { + "Group": "Sports", + "Value": 27 + }, + { + "Group": "Sports", + "Value": 43 + }, + { + "Group": "Sports", + "Value": 49 + }, + { + "Group": "Sports", + "Value": 96 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/boxplot/01-card5.flint.json b/test-harness/excel/evaluations/inputs/boxplot/01-card5.flint.json new file mode 100644 index 00000000..4c37a009 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/boxplot/01-card5.flint.json @@ -0,0 +1,421 @@ +{ + "semantic_types": { + "Level": "Rank", + "Score": "Score" + }, + "chart_spec": { + "chartType": "Boxplot", + "encodings": { + "x": "Level", + "y": "Score" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Level": 1, + "Score": 43 + }, + { + "Level": 1, + "Score": 41 + }, + { + "Level": 1, + "Score": 19 + }, + { + "Level": 1, + "Score": 43 + }, + { + "Level": 1, + "Score": 29 + }, + { + "Level": 1, + "Score": 30 + }, + { + "Level": 1, + "Score": 38 + }, + { + "Level": 1, + "Score": 45 + }, + { + "Level": 1, + "Score": 16 + }, + { + "Level": 1, + "Score": 16 + }, + { + "Level": 1, + "Score": 30 + }, + { + "Level": 1, + "Score": 30 + }, + { + "Level": 1, + "Score": 31 + }, + { + "Level": 1, + "Score": 21 + }, + { + "Level": 1, + "Score": 45 + }, + { + "Level": 1, + "Score": 17 + }, + { + "Level": 1, + "Score": 32 + }, + { + "Level": 1, + "Score": 27 + }, + { + "Level": 1, + "Score": 20 + }, + { + "Level": 1, + "Score": 19 + }, + { + "Level": 2, + "Score": 53 + }, + { + "Level": 2, + "Score": 58 + }, + { + "Level": 2, + "Score": 41 + }, + { + "Level": 2, + "Score": 42 + }, + { + "Level": 2, + "Score": 50 + }, + { + "Level": 2, + "Score": 49 + }, + { + "Level": 2, + "Score": 26 + }, + { + "Level": 2, + "Score": 43 + }, + { + "Level": 2, + "Score": 28 + }, + { + "Level": 2, + "Score": 49 + }, + { + "Level": 2, + "Score": 47 + }, + { + "Level": 2, + "Score": 44 + }, + { + "Level": 2, + "Score": 30 + }, + { + "Level": 2, + "Score": 27 + }, + { + "Level": 2, + "Score": 26 + }, + { + "Level": 2, + "Score": 47 + }, + { + "Level": 2, + "Score": 49 + }, + { + "Level": 2, + "Score": 30 + }, + { + "Level": 2, + "Score": 24 + }, + { + "Level": 2, + "Score": 44 + }, + { + "Level": 3, + "Score": 65 + }, + { + "Level": 3, + "Score": 37 + }, + { + "Level": 3, + "Score": 41 + }, + { + "Level": 3, + "Score": 42 + }, + { + "Level": 3, + "Score": 34 + }, + { + "Level": 3, + "Score": 53 + }, + { + "Level": 3, + "Score": 68 + }, + { + "Level": 3, + "Score": 67 + }, + { + "Level": 3, + "Score": 51 + }, + { + "Level": 3, + "Score": 42 + }, + { + "Level": 3, + "Score": 41 + }, + { + "Level": 3, + "Score": 52 + }, + { + "Level": 3, + "Score": 30 + }, + { + "Level": 3, + "Score": 34 + }, + { + "Level": 3, + "Score": 66 + }, + { + "Level": 3, + "Score": 51 + }, + { + "Level": 3, + "Score": 38 + }, + { + "Level": 3, + "Score": 34 + }, + { + "Level": 3, + "Score": 46 + }, + { + "Level": 3, + "Score": 63 + }, + { + "Level": 4, + "Score": 68 + }, + { + "Level": 4, + "Score": 64 + }, + { + "Level": 4, + "Score": 41 + }, + { + "Level": 4, + "Score": 73 + }, + { + "Level": 4, + "Score": 59 + }, + { + "Level": 4, + "Score": 78 + }, + { + "Level": 4, + "Score": 60 + }, + { + "Level": 4, + "Score": 63 + }, + { + "Level": 4, + "Score": 48 + }, + { + "Level": 4, + "Score": 55 + }, + { + "Level": 4, + "Score": 49 + }, + { + "Level": 4, + "Score": 60 + }, + { + "Level": 4, + "Score": 53 + }, + { + "Level": 4, + "Score": 65 + }, + { + "Level": 4, + "Score": 56 + }, + { + "Level": 4, + "Score": 50 + }, + { + "Level": 4, + "Score": 55 + }, + { + "Level": 4, + "Score": 57 + }, + { + "Level": 4, + "Score": 68 + }, + { + "Level": 4, + "Score": 66 + }, + { + "Level": 5, + "Score": 55 + }, + { + "Level": 5, + "Score": 51 + }, + { + "Level": 5, + "Score": 81 + }, + { + "Level": 5, + "Score": 67 + }, + { + "Level": 5, + "Score": 60 + }, + { + "Level": 5, + "Score": 72 + }, + { + "Level": 5, + "Score": 85 + }, + { + "Level": 5, + "Score": 59 + }, + { + "Level": 5, + "Score": 51 + }, + { + "Level": 5, + "Score": 60 + }, + { + "Level": 5, + "Score": 52 + }, + { + "Level": 5, + "Score": 82 + }, + { + "Level": 5, + "Score": 61 + }, + { + "Level": 5, + "Score": 76 + }, + { + "Level": 5, + "Score": 74 + }, + { + "Level": 5, + "Score": 53 + }, + { + "Level": 5, + "Score": 65 + }, + { + "Level": 5, + "Score": 71 + }, + { + "Level": 5, + "Score": 64 + }, + { + "Level": 5, + "Score": 68 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/boxplot/02-card12.flint.json b/test-harness/excel/evaluations/inputs/boxplot/02-card12.flint.json new file mode 100644 index 00000000..e99b2960 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/boxplot/02-card12.flint.json @@ -0,0 +1,2421 @@ +{ + "semantic_types": { + "Department": "Department", + "Salary": "Amount" + }, + "chart_spec": { + "chartType": "Boxplot", + "encodings": { + "x": "Department", + "y": "Salary" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Department": "Engineering", + "Salary": 79984 + }, + { + "Department": "Engineering", + "Salary": 103836 + }, + { + "Department": "Engineering", + "Salary": 71569 + }, + { + "Department": "Engineering", + "Salary": 46139 + }, + { + "Department": "Engineering", + "Salary": 80917 + }, + { + "Department": "Engineering", + "Salary": 78792 + }, + { + "Department": "Engineering", + "Salary": 119516 + }, + { + "Department": "Engineering", + "Salary": 77207 + }, + { + "Department": "Engineering", + "Salary": 111998 + }, + { + "Department": "Engineering", + "Salary": 89270 + }, + { + "Department": "Engineering", + "Salary": 59331 + }, + { + "Department": "Engineering", + "Salary": 41468 + }, + { + "Department": "Engineering", + "Salary": 52099 + }, + { + "Department": "Engineering", + "Salary": 55959 + }, + { + "Department": "Engineering", + "Salary": 126408 + }, + { + "Department": "Engineering", + "Salary": 114034 + }, + { + "Department": "Engineering", + "Salary": 113583 + }, + { + "Department": "Engineering", + "Salary": 87931 + }, + { + "Department": "Engineering", + "Salary": 119107 + }, + { + "Department": "Engineering", + "Salary": 51152 + }, + { + "Department": "Engineering", + "Salary": 91412 + }, + { + "Department": "Engineering", + "Salary": 63785 + }, + { + "Department": "Engineering", + "Salary": 137701 + }, + { + "Department": "Engineering", + "Salary": 84038 + }, + { + "Department": "Engineering", + "Salary": 92194 + }, + { + "Department": "Engineering", + "Salary": 128943 + }, + { + "Department": "Engineering", + "Salary": 126729 + }, + { + "Department": "Engineering", + "Salary": 114677 + }, + { + "Department": "Engineering", + "Salary": 116625 + }, + { + "Department": "Engineering", + "Salary": 91094 + }, + { + "Department": "Engineering", + "Salary": 123268 + }, + { + "Department": "Engineering", + "Salary": 140563 + }, + { + "Department": "Engineering", + "Salary": 63202 + }, + { + "Department": "Engineering", + "Salary": 61807 + }, + { + "Department": "Engineering", + "Salary": 130557 + }, + { + "Department": "Engineering", + "Salary": 126992 + }, + { + "Department": "Engineering", + "Salary": 92215 + }, + { + "Department": "Engineering", + "Salary": 114070 + }, + { + "Department": "Engineering", + "Salary": 114849 + }, + { + "Department": "Engineering", + "Salary": 127951 + }, + { + "Department": "Engineering", + "Salary": 131796 + }, + { + "Department": "Engineering", + "Salary": 79419 + }, + { + "Department": "Engineering", + "Salary": 96708 + }, + { + "Department": "Engineering", + "Salary": 32167 + }, + { + "Department": "Engineering", + "Salary": 92332 + }, + { + "Department": "Engineering", + "Salary": 47540 + }, + { + "Department": "Engineering", + "Salary": 100494 + }, + { + "Department": "Engineering", + "Salary": 66265 + }, + { + "Department": "Engineering", + "Salary": 54614 + }, + { + "Department": "Engineering", + "Salary": 70664 + }, + { + "Department": "Sales", + "Salary": 74396 + }, + { + "Department": "Sales", + "Salary": 36995 + }, + { + "Department": "Sales", + "Salary": 109734 + }, + { + "Department": "Sales", + "Salary": 78112 + }, + { + "Department": "Sales", + "Salary": 91016 + }, + { + "Department": "Sales", + "Salary": 120197 + }, + { + "Department": "Sales", + "Salary": 138649 + }, + { + "Department": "Sales", + "Salary": 47342 + }, + { + "Department": "Sales", + "Salary": 136093 + }, + { + "Department": "Sales", + "Salary": 54703 + }, + { + "Department": "Sales", + "Salary": 125941 + }, + { + "Department": "Sales", + "Salary": 64355 + }, + { + "Department": "Sales", + "Salary": 118553 + }, + { + "Department": "Sales", + "Salary": 101069 + }, + { + "Department": "Sales", + "Salary": 121977 + }, + { + "Department": "Sales", + "Salary": 41111 + }, + { + "Department": "Sales", + "Salary": 45802 + }, + { + "Department": "Sales", + "Salary": 51768 + }, + { + "Department": "Sales", + "Salary": 117315 + }, + { + "Department": "Sales", + "Salary": 48958 + }, + { + "Department": "Sales", + "Salary": 64320 + }, + { + "Department": "Sales", + "Salary": 124206 + }, + { + "Department": "Sales", + "Salary": 65715 + }, + { + "Department": "Sales", + "Salary": 54616 + }, + { + "Department": "Sales", + "Salary": 117906 + }, + { + "Department": "Sales", + "Salary": 148055 + }, + { + "Department": "Sales", + "Salary": 92065 + }, + { + "Department": "Sales", + "Salary": 112006 + }, + { + "Department": "Sales", + "Salary": 109021 + }, + { + "Department": "Sales", + "Salary": 101215 + }, + { + "Department": "Sales", + "Salary": 52792 + }, + { + "Department": "Sales", + "Salary": 49007 + }, + { + "Department": "Sales", + "Salary": 43479 + }, + { + "Department": "Sales", + "Salary": 126739 + }, + { + "Department": "Sales", + "Salary": 45283 + }, + { + "Department": "Sales", + "Salary": 87822 + }, + { + "Department": "Sales", + "Salary": 90616 + }, + { + "Department": "Sales", + "Salary": 124109 + }, + { + "Department": "Sales", + "Salary": 128329 + }, + { + "Department": "Sales", + "Salary": 119472 + }, + { + "Department": "Sales", + "Salary": 59869 + }, + { + "Department": "Sales", + "Salary": 73901 + }, + { + "Department": "Sales", + "Salary": 120655 + }, + { + "Department": "Sales", + "Salary": 33103 + }, + { + "Department": "Sales", + "Salary": 94497 + }, + { + "Department": "Sales", + "Salary": 69237 + }, + { + "Department": "Sales", + "Salary": 88576 + }, + { + "Department": "Sales", + "Salary": 43702 + }, + { + "Department": "Sales", + "Salary": 41048 + }, + { + "Department": "Sales", + "Salary": 66471 + }, + { + "Department": "Marketing", + "Salary": 30207 + }, + { + "Department": "Marketing", + "Salary": 143862 + }, + { + "Department": "Marketing", + "Salary": 63964 + }, + { + "Department": "Marketing", + "Salary": 143735 + }, + { + "Department": "Marketing", + "Salary": 96224 + }, + { + "Department": "Marketing", + "Salary": 63087 + }, + { + "Department": "Marketing", + "Salary": 38266 + }, + { + "Department": "Marketing", + "Salary": 110675 + }, + { + "Department": "Marketing", + "Salary": 53654 + }, + { + "Department": "Marketing", + "Salary": 145848 + }, + { + "Department": "Marketing", + "Salary": 86051 + }, + { + "Department": "Marketing", + "Salary": 85848 + }, + { + "Department": "Marketing", + "Salary": 143618 + }, + { + "Department": "Marketing", + "Salary": 40226 + }, + { + "Department": "Marketing", + "Salary": 65474 + }, + { + "Department": "Marketing", + "Salary": 89208 + }, + { + "Department": "Marketing", + "Salary": 105519 + }, + { + "Department": "Marketing", + "Salary": 37281 + }, + { + "Department": "Marketing", + "Salary": 115584 + }, + { + "Department": "Marketing", + "Salary": 123931 + }, + { + "Department": "Marketing", + "Salary": 127988 + }, + { + "Department": "Marketing", + "Salary": 33134 + }, + { + "Department": "Marketing", + "Salary": 146512 + }, + { + "Department": "Marketing", + "Salary": 85031 + }, + { + "Department": "Marketing", + "Salary": 92909 + }, + { + "Department": "Marketing", + "Salary": 133796 + }, + { + "Department": "Marketing", + "Salary": 87409 + }, + { + "Department": "Marketing", + "Salary": 107630 + }, + { + "Department": "Marketing", + "Salary": 113374 + }, + { + "Department": "Marketing", + "Salary": 53648 + }, + { + "Department": "Marketing", + "Salary": 38775 + }, + { + "Department": "Marketing", + "Salary": 147049 + }, + { + "Department": "Marketing", + "Salary": 108986 + }, + { + "Department": "Marketing", + "Salary": 114471 + }, + { + "Department": "Marketing", + "Salary": 129030 + }, + { + "Department": "Marketing", + "Salary": 147330 + }, + { + "Department": "Marketing", + "Salary": 148050 + }, + { + "Department": "Marketing", + "Salary": 143018 + }, + { + "Department": "Marketing", + "Salary": 48809 + }, + { + "Department": "Marketing", + "Salary": 67299 + }, + { + "Department": "Marketing", + "Salary": 41329 + }, + { + "Department": "Marketing", + "Salary": 111048 + }, + { + "Department": "Marketing", + "Salary": 89757 + }, + { + "Department": "Marketing", + "Salary": 82702 + }, + { + "Department": "Marketing", + "Salary": 72125 + }, + { + "Department": "Marketing", + "Salary": 142188 + }, + { + "Department": "Marketing", + "Salary": 125380 + }, + { + "Department": "Marketing", + "Salary": 127908 + }, + { + "Department": "Marketing", + "Salary": 127439 + }, + { + "Department": "Marketing", + "Salary": 39375 + }, + { + "Department": "HR", + "Salary": 34632 + }, + { + "Department": "HR", + "Salary": 126355 + }, + { + "Department": "HR", + "Salary": 70480 + }, + { + "Department": "HR", + "Salary": 92867 + }, + { + "Department": "HR", + "Salary": 37548 + }, + { + "Department": "HR", + "Salary": 54270 + }, + { + "Department": "HR", + "Salary": 48302 + }, + { + "Department": "HR", + "Salary": 70414 + }, + { + "Department": "HR", + "Salary": 62537 + }, + { + "Department": "HR", + "Salary": 44191 + }, + { + "Department": "HR", + "Salary": 95192 + }, + { + "Department": "HR", + "Salary": 108972 + }, + { + "Department": "HR", + "Salary": 110646 + }, + { + "Department": "HR", + "Salary": 43948 + }, + { + "Department": "HR", + "Salary": 87552 + }, + { + "Department": "HR", + "Salary": 113418 + }, + { + "Department": "HR", + "Salary": 83329 + }, + { + "Department": "HR", + "Salary": 53009 + }, + { + "Department": "HR", + "Salary": 106153 + }, + { + "Department": "HR", + "Salary": 139857 + }, + { + "Department": "HR", + "Salary": 80618 + }, + { + "Department": "HR", + "Salary": 85563 + }, + { + "Department": "HR", + "Salary": 31599 + }, + { + "Department": "HR", + "Salary": 149033 + }, + { + "Department": "HR", + "Salary": 95124 + }, + { + "Department": "HR", + "Salary": 56169 + }, + { + "Department": "HR", + "Salary": 49160 + }, + { + "Department": "HR", + "Salary": 99299 + }, + { + "Department": "HR", + "Salary": 143542 + }, + { + "Department": "HR", + "Salary": 83184 + }, + { + "Department": "HR", + "Salary": 127815 + }, + { + "Department": "HR", + "Salary": 128696 + }, + { + "Department": "HR", + "Salary": 57923 + }, + { + "Department": "HR", + "Salary": 128171 + }, + { + "Department": "HR", + "Salary": 111025 + }, + { + "Department": "HR", + "Salary": 49223 + }, + { + "Department": "HR", + "Salary": 70180 + }, + { + "Department": "HR", + "Salary": 95860 + }, + { + "Department": "HR", + "Salary": 64234 + }, + { + "Department": "HR", + "Salary": 120743 + }, + { + "Department": "HR", + "Salary": 68529 + }, + { + "Department": "HR", + "Salary": 62533 + }, + { + "Department": "HR", + "Salary": 93905 + }, + { + "Department": "HR", + "Salary": 76409 + }, + { + "Department": "HR", + "Salary": 139367 + }, + { + "Department": "HR", + "Salary": 120579 + }, + { + "Department": "HR", + "Salary": 71874 + }, + { + "Department": "HR", + "Salary": 125167 + }, + { + "Department": "HR", + "Salary": 140774 + }, + { + "Department": "HR", + "Salary": 136544 + }, + { + "Department": "Finance", + "Salary": 69363 + }, + { + "Department": "Finance", + "Salary": 48357 + }, + { + "Department": "Finance", + "Salary": 30420 + }, + { + "Department": "Finance", + "Salary": 128394 + }, + { + "Department": "Finance", + "Salary": 131698 + }, + { + "Department": "Finance", + "Salary": 110538 + }, + { + "Department": "Finance", + "Salary": 147196 + }, + { + "Department": "Finance", + "Salary": 67192 + }, + { + "Department": "Finance", + "Salary": 38318 + }, + { + "Department": "Finance", + "Salary": 34213 + }, + { + "Department": "Finance", + "Salary": 46033 + }, + { + "Department": "Finance", + "Salary": 94796 + }, + { + "Department": "Finance", + "Salary": 55243 + }, + { + "Department": "Finance", + "Salary": 81853 + }, + { + "Department": "Finance", + "Salary": 77939 + }, + { + "Department": "Finance", + "Salary": 65503 + }, + { + "Department": "Finance", + "Salary": 94101 + }, + { + "Department": "Finance", + "Salary": 132290 + }, + { + "Department": "Finance", + "Salary": 101968 + }, + { + "Department": "Finance", + "Salary": 113234 + }, + { + "Department": "Finance", + "Salary": 98756 + }, + { + "Department": "Finance", + "Salary": 135886 + }, + { + "Department": "Finance", + "Salary": 60667 + }, + { + "Department": "Finance", + "Salary": 51838 + }, + { + "Department": "Finance", + "Salary": 96182 + }, + { + "Department": "Finance", + "Salary": 70296 + }, + { + "Department": "Finance", + "Salary": 120549 + }, + { + "Department": "Finance", + "Salary": 52817 + }, + { + "Department": "Finance", + "Salary": 116045 + }, + { + "Department": "Finance", + "Salary": 71351 + }, + { + "Department": "Finance", + "Salary": 95539 + }, + { + "Department": "Finance", + "Salary": 71081 + }, + { + "Department": "Finance", + "Salary": 119365 + }, + { + "Department": "Finance", + "Salary": 59659 + }, + { + "Department": "Finance", + "Salary": 146549 + }, + { + "Department": "Finance", + "Salary": 102740 + }, + { + "Department": "Finance", + "Salary": 128560 + }, + { + "Department": "Finance", + "Salary": 43043 + }, + { + "Department": "Finance", + "Salary": 121258 + }, + { + "Department": "Finance", + "Salary": 75581 + }, + { + "Department": "Finance", + "Salary": 146248 + }, + { + "Department": "Finance", + "Salary": 87136 + }, + { + "Department": "Finance", + "Salary": 69892 + }, + { + "Department": "Finance", + "Salary": 49926 + }, + { + "Department": "Finance", + "Salary": 118695 + }, + { + "Department": "Finance", + "Salary": 84880 + }, + { + "Department": "Finance", + "Salary": 78038 + }, + { + "Department": "Finance", + "Salary": 50055 + }, + { + "Department": "Finance", + "Salary": 128572 + }, + { + "Department": "Finance", + "Salary": 130241 + }, + { + "Department": "Legal", + "Salary": 105276 + }, + { + "Department": "Legal", + "Salary": 33123 + }, + { + "Department": "Legal", + "Salary": 73300 + }, + { + "Department": "Legal", + "Salary": 100086 + }, + { + "Department": "Legal", + "Salary": 42974 + }, + { + "Department": "Legal", + "Salary": 47913 + }, + { + "Department": "Legal", + "Salary": 134755 + }, + { + "Department": "Legal", + "Salary": 129647 + }, + { + "Department": "Legal", + "Salary": 71643 + }, + { + "Department": "Legal", + "Salary": 77455 + }, + { + "Department": "Legal", + "Salary": 85373 + }, + { + "Department": "Legal", + "Salary": 79200 + }, + { + "Department": "Legal", + "Salary": 141159 + }, + { + "Department": "Legal", + "Salary": 117834 + }, + { + "Department": "Legal", + "Salary": 128099 + }, + { + "Department": "Legal", + "Salary": 97340 + }, + { + "Department": "Legal", + "Salary": 87835 + }, + { + "Department": "Legal", + "Salary": 67217 + }, + { + "Department": "Legal", + "Salary": 102888 + }, + { + "Department": "Legal", + "Salary": 100329 + }, + { + "Department": "Legal", + "Salary": 47139 + }, + { + "Department": "Legal", + "Salary": 80689 + }, + { + "Department": "Legal", + "Salary": 73309 + }, + { + "Department": "Legal", + "Salary": 119926 + }, + { + "Department": "Legal", + "Salary": 144388 + }, + { + "Department": "Legal", + "Salary": 33137 + }, + { + "Department": "Legal", + "Salary": 80274 + }, + { + "Department": "Legal", + "Salary": 70713 + }, + { + "Department": "Legal", + "Salary": 48109 + }, + { + "Department": "Legal", + "Salary": 65012 + }, + { + "Department": "Legal", + "Salary": 118670 + }, + { + "Department": "Legal", + "Salary": 145864 + }, + { + "Department": "Legal", + "Salary": 121660 + }, + { + "Department": "Legal", + "Salary": 126934 + }, + { + "Department": "Legal", + "Salary": 77505 + }, + { + "Department": "Legal", + "Salary": 86428 + }, + { + "Department": "Legal", + "Salary": 58158 + }, + { + "Department": "Legal", + "Salary": 113297 + }, + { + "Department": "Legal", + "Salary": 82379 + }, + { + "Department": "Legal", + "Salary": 36986 + }, + { + "Department": "Legal", + "Salary": 77406 + }, + { + "Department": "Legal", + "Salary": 105526 + }, + { + "Department": "Legal", + "Salary": 42388 + }, + { + "Department": "Legal", + "Salary": 149220 + }, + { + "Department": "Legal", + "Salary": 116800 + }, + { + "Department": "Legal", + "Salary": 37115 + }, + { + "Department": "Legal", + "Salary": 87910 + }, + { + "Department": "Legal", + "Salary": 119172 + }, + { + "Department": "Legal", + "Salary": 68275 + }, + { + "Department": "Legal", + "Salary": 122644 + }, + { + "Department": "Operations", + "Salary": 104218 + }, + { + "Department": "Operations", + "Salary": 132453 + }, + { + "Department": "Operations", + "Salary": 71059 + }, + { + "Department": "Operations", + "Salary": 110295 + }, + { + "Department": "Operations", + "Salary": 140614 + }, + { + "Department": "Operations", + "Salary": 85025 + }, + { + "Department": "Operations", + "Salary": 108393 + }, + { + "Department": "Operations", + "Salary": 96081 + }, + { + "Department": "Operations", + "Salary": 52143 + }, + { + "Department": "Operations", + "Salary": 67000 + }, + { + "Department": "Operations", + "Salary": 49200 + }, + { + "Department": "Operations", + "Salary": 42607 + }, + { + "Department": "Operations", + "Salary": 109916 + }, + { + "Department": "Operations", + "Salary": 130383 + }, + { + "Department": "Operations", + "Salary": 87408 + }, + { + "Department": "Operations", + "Salary": 86437 + }, + { + "Department": "Operations", + "Salary": 79567 + }, + { + "Department": "Operations", + "Salary": 54884 + }, + { + "Department": "Operations", + "Salary": 50910 + }, + { + "Department": "Operations", + "Salary": 95991 + }, + { + "Department": "Operations", + "Salary": 105027 + }, + { + "Department": "Operations", + "Salary": 41414 + }, + { + "Department": "Operations", + "Salary": 97686 + }, + { + "Department": "Operations", + "Salary": 147006 + }, + { + "Department": "Operations", + "Salary": 114464 + }, + { + "Department": "Operations", + "Salary": 130073 + }, + { + "Department": "Operations", + "Salary": 30826 + }, + { + "Department": "Operations", + "Salary": 119619 + }, + { + "Department": "Operations", + "Salary": 142819 + }, + { + "Department": "Operations", + "Salary": 61218 + }, + { + "Department": "Operations", + "Salary": 64009 + }, + { + "Department": "Operations", + "Salary": 63862 + }, + { + "Department": "Operations", + "Salary": 106052 + }, + { + "Department": "Operations", + "Salary": 123279 + }, + { + "Department": "Operations", + "Salary": 81949 + }, + { + "Department": "Operations", + "Salary": 129288 + }, + { + "Department": "Operations", + "Salary": 41875 + }, + { + "Department": "Operations", + "Salary": 57744 + }, + { + "Department": "Operations", + "Salary": 127040 + }, + { + "Department": "Operations", + "Salary": 54109 + }, + { + "Department": "Operations", + "Salary": 109504 + }, + { + "Department": "Operations", + "Salary": 59300 + }, + { + "Department": "Operations", + "Salary": 117312 + }, + { + "Department": "Operations", + "Salary": 121291 + }, + { + "Department": "Operations", + "Salary": 40267 + }, + { + "Department": "Operations", + "Salary": 34430 + }, + { + "Department": "Operations", + "Salary": 91222 + }, + { + "Department": "Operations", + "Salary": 102480 + }, + { + "Department": "Operations", + "Salary": 85086 + }, + { + "Department": "Operations", + "Salary": 58115 + }, + { + "Department": "Support", + "Salary": 118620 + }, + { + "Department": "Support", + "Salary": 149317 + }, + { + "Department": "Support", + "Salary": 68469 + }, + { + "Department": "Support", + "Salary": 143461 + }, + { + "Department": "Support", + "Salary": 55436 + }, + { + "Department": "Support", + "Salary": 91470 + }, + { + "Department": "Support", + "Salary": 78582 + }, + { + "Department": "Support", + "Salary": 73305 + }, + { + "Department": "Support", + "Salary": 53285 + }, + { + "Department": "Support", + "Salary": 65384 + }, + { + "Department": "Support", + "Salary": 124043 + }, + { + "Department": "Support", + "Salary": 92747 + }, + { + "Department": "Support", + "Salary": 58997 + }, + { + "Department": "Support", + "Salary": 59396 + }, + { + "Department": "Support", + "Salary": 41987 + }, + { + "Department": "Support", + "Salary": 132760 + }, + { + "Department": "Support", + "Salary": 84140 + }, + { + "Department": "Support", + "Salary": 129039 + }, + { + "Department": "Support", + "Salary": 62084 + }, + { + "Department": "Support", + "Salary": 107873 + }, + { + "Department": "Support", + "Salary": 129745 + }, + { + "Department": "Support", + "Salary": 38019 + }, + { + "Department": "Support", + "Salary": 49613 + }, + { + "Department": "Support", + "Salary": 146420 + }, + { + "Department": "Support", + "Salary": 106826 + }, + { + "Department": "Support", + "Salary": 47659 + }, + { + "Department": "Support", + "Salary": 56597 + }, + { + "Department": "Support", + "Salary": 43409 + }, + { + "Department": "Support", + "Salary": 32847 + }, + { + "Department": "Support", + "Salary": 114625 + }, + { + "Department": "Support", + "Salary": 84560 + }, + { + "Department": "Support", + "Salary": 98375 + }, + { + "Department": "Support", + "Salary": 81946 + }, + { + "Department": "Support", + "Salary": 90811 + }, + { + "Department": "Support", + "Salary": 45278 + }, + { + "Department": "Support", + "Salary": 130411 + }, + { + "Department": "Support", + "Salary": 74569 + }, + { + "Department": "Support", + "Salary": 61195 + }, + { + "Department": "Support", + "Salary": 44836 + }, + { + "Department": "Support", + "Salary": 134794 + }, + { + "Department": "Support", + "Salary": 68282 + }, + { + "Department": "Support", + "Salary": 109957 + }, + { + "Department": "Support", + "Salary": 108277 + }, + { + "Department": "Support", + "Salary": 70837 + }, + { + "Department": "Support", + "Salary": 94900 + }, + { + "Department": "Support", + "Salary": 124168 + }, + { + "Department": "Support", + "Salary": 38910 + }, + { + "Department": "Support", + "Salary": 145748 + }, + { + "Department": "Support", + "Salary": 84154 + }, + { + "Department": "Support", + "Salary": 111023 + }, + { + "Department": "Design", + "Salary": 142030 + }, + { + "Department": "Design", + "Salary": 124766 + }, + { + "Department": "Design", + "Salary": 120280 + }, + { + "Department": "Design", + "Salary": 93524 + }, + { + "Department": "Design", + "Salary": 31632 + }, + { + "Department": "Design", + "Salary": 99215 + }, + { + "Department": "Design", + "Salary": 46955 + }, + { + "Department": "Design", + "Salary": 112023 + }, + { + "Department": "Design", + "Salary": 34632 + }, + { + "Department": "Design", + "Salary": 127594 + }, + { + "Department": "Design", + "Salary": 130281 + }, + { + "Department": "Design", + "Salary": 50078 + }, + { + "Department": "Design", + "Salary": 32691 + }, + { + "Department": "Design", + "Salary": 140668 + }, + { + "Department": "Design", + "Salary": 145162 + }, + { + "Department": "Design", + "Salary": 76636 + }, + { + "Department": "Design", + "Salary": 113245 + }, + { + "Department": "Design", + "Salary": 43226 + }, + { + "Department": "Design", + "Salary": 78383 + }, + { + "Department": "Design", + "Salary": 89681 + }, + { + "Department": "Design", + "Salary": 123869 + }, + { + "Department": "Design", + "Salary": 49143 + }, + { + "Department": "Design", + "Salary": 39626 + }, + { + "Department": "Design", + "Salary": 55326 + }, + { + "Department": "Design", + "Salary": 44276 + }, + { + "Department": "Design", + "Salary": 82534 + }, + { + "Department": "Design", + "Salary": 124622 + }, + { + "Department": "Design", + "Salary": 106886 + }, + { + "Department": "Design", + "Salary": 100407 + }, + { + "Department": "Design", + "Salary": 45243 + }, + { + "Department": "Design", + "Salary": 133984 + }, + { + "Department": "Design", + "Salary": 132256 + }, + { + "Department": "Design", + "Salary": 124613 + }, + { + "Department": "Design", + "Salary": 67464 + }, + { + "Department": "Design", + "Salary": 51447 + }, + { + "Department": "Design", + "Salary": 135502 + }, + { + "Department": "Design", + "Salary": 85835 + }, + { + "Department": "Design", + "Salary": 47562 + }, + { + "Department": "Design", + "Salary": 112262 + }, + { + "Department": "Design", + "Salary": 94277 + }, + { + "Department": "Design", + "Salary": 98629 + }, + { + "Department": "Design", + "Salary": 149231 + }, + { + "Department": "Design", + "Salary": 63708 + }, + { + "Department": "Design", + "Salary": 36264 + }, + { + "Department": "Design", + "Salary": 63093 + }, + { + "Department": "Design", + "Salary": 149893 + }, + { + "Department": "Design", + "Salary": 148886 + }, + { + "Department": "Design", + "Salary": 142140 + }, + { + "Department": "Design", + "Salary": 54334 + }, + { + "Department": "Design", + "Salary": 43848 + }, + { + "Department": "Research", + "Salary": 91964 + }, + { + "Department": "Research", + "Salary": 99097 + }, + { + "Department": "Research", + "Salary": 100529 + }, + { + "Department": "Research", + "Salary": 42939 + }, + { + "Department": "Research", + "Salary": 56595 + }, + { + "Department": "Research", + "Salary": 140310 + }, + { + "Department": "Research", + "Salary": 132219 + }, + { + "Department": "Research", + "Salary": 101077 + }, + { + "Department": "Research", + "Salary": 144561 + }, + { + "Department": "Research", + "Salary": 49150 + }, + { + "Department": "Research", + "Salary": 45804 + }, + { + "Department": "Research", + "Salary": 83331 + }, + { + "Department": "Research", + "Salary": 83953 + }, + { + "Department": "Research", + "Salary": 94999 + }, + { + "Department": "Research", + "Salary": 101956 + }, + { + "Department": "Research", + "Salary": 33164 + }, + { + "Department": "Research", + "Salary": 39355 + }, + { + "Department": "Research", + "Salary": 63672 + }, + { + "Department": "Research", + "Salary": 32155 + }, + { + "Department": "Research", + "Salary": 123287 + }, + { + "Department": "Research", + "Salary": 111126 + }, + { + "Department": "Research", + "Salary": 80545 + }, + { + "Department": "Research", + "Salary": 54473 + }, + { + "Department": "Research", + "Salary": 111217 + }, + { + "Department": "Research", + "Salary": 40731 + }, + { + "Department": "Research", + "Salary": 137643 + }, + { + "Department": "Research", + "Salary": 63170 + }, + { + "Department": "Research", + "Salary": 125359 + }, + { + "Department": "Research", + "Salary": 131760 + }, + { + "Department": "Research", + "Salary": 67805 + }, + { + "Department": "Research", + "Salary": 142686 + }, + { + "Department": "Research", + "Salary": 108345 + }, + { + "Department": "Research", + "Salary": 135207 + }, + { + "Department": "Research", + "Salary": 38713 + }, + { + "Department": "Research", + "Salary": 73035 + }, + { + "Department": "Research", + "Salary": 71124 + }, + { + "Department": "Research", + "Salary": 123338 + }, + { + "Department": "Research", + "Salary": 123828 + }, + { + "Department": "Research", + "Salary": 83515 + }, + { + "Department": "Research", + "Salary": 58003 + }, + { + "Department": "Research", + "Salary": 42196 + }, + { + "Department": "Research", + "Salary": 51199 + }, + { + "Department": "Research", + "Salary": 35254 + }, + { + "Department": "Research", + "Salary": 128896 + }, + { + "Department": "Research", + "Salary": 52692 + }, + { + "Department": "Research", + "Salary": 52659 + }, + { + "Department": "Research", + "Salary": 99469 + }, + { + "Department": "Research", + "Salary": 109774 + }, + { + "Department": "Research", + "Salary": 149458 + }, + { + "Department": "Research", + "Salary": 37221 + }, + { + "Department": "QA", + "Salary": 74511 + }, + { + "Department": "QA", + "Salary": 48619 + }, + { + "Department": "QA", + "Salary": 119656 + }, + { + "Department": "QA", + "Salary": 46338 + }, + { + "Department": "QA", + "Salary": 60000 + }, + { + "Department": "QA", + "Salary": 114199 + }, + { + "Department": "QA", + "Salary": 122876 + }, + { + "Department": "QA", + "Salary": 37779 + }, + { + "Department": "QA", + "Salary": 93936 + }, + { + "Department": "QA", + "Salary": 117596 + }, + { + "Department": "QA", + "Salary": 95262 + }, + { + "Department": "QA", + "Salary": 80060 + }, + { + "Department": "QA", + "Salary": 68683 + }, + { + "Department": "QA", + "Salary": 138711 + }, + { + "Department": "QA", + "Salary": 136279 + }, + { + "Department": "QA", + "Salary": 54425 + }, + { + "Department": "QA", + "Salary": 143391 + }, + { + "Department": "QA", + "Salary": 70176 + }, + { + "Department": "QA", + "Salary": 144806 + }, + { + "Department": "QA", + "Salary": 93701 + }, + { + "Department": "QA", + "Salary": 140920 + }, + { + "Department": "QA", + "Salary": 57365 + }, + { + "Department": "QA", + "Salary": 114027 + }, + { + "Department": "QA", + "Salary": 118486 + }, + { + "Department": "QA", + "Salary": 45865 + }, + { + "Department": "QA", + "Salary": 35221 + }, + { + "Department": "QA", + "Salary": 57198 + }, + { + "Department": "QA", + "Salary": 64623 + }, + { + "Department": "QA", + "Salary": 51166 + }, + { + "Department": "QA", + "Salary": 82639 + }, + { + "Department": "QA", + "Salary": 95121 + }, + { + "Department": "QA", + "Salary": 114703 + }, + { + "Department": "QA", + "Salary": 78726 + }, + { + "Department": "QA", + "Salary": 87117 + }, + { + "Department": "QA", + "Salary": 110519 + }, + { + "Department": "QA", + "Salary": 81097 + }, + { + "Department": "QA", + "Salary": 101191 + }, + { + "Department": "QA", + "Salary": 137217 + }, + { + "Department": "QA", + "Salary": 98828 + }, + { + "Department": "QA", + "Salary": 138746 + }, + { + "Department": "QA", + "Salary": 129509 + }, + { + "Department": "QA", + "Salary": 41967 + }, + { + "Department": "QA", + "Salary": 40984 + }, + { + "Department": "QA", + "Salary": 73179 + }, + { + "Department": "QA", + "Salary": 107324 + }, + { + "Department": "QA", + "Salary": 132308 + }, + { + "Department": "QA", + "Salary": 33902 + }, + { + "Department": "QA", + "Salary": 96884 + }, + { + "Department": "QA", + "Salary": 115122 + }, + { + "Department": "QA", + "Salary": 147917 + }, + { + "Department": "DevOps", + "Salary": 64497 + }, + { + "Department": "DevOps", + "Salary": 96031 + }, + { + "Department": "DevOps", + "Salary": 46229 + }, + { + "Department": "DevOps", + "Salary": 34646 + }, + { + "Department": "DevOps", + "Salary": 107502 + }, + { + "Department": "DevOps", + "Salary": 126406 + }, + { + "Department": "DevOps", + "Salary": 80438 + }, + { + "Department": "DevOps", + "Salary": 69212 + }, + { + "Department": "DevOps", + "Salary": 146301 + }, + { + "Department": "DevOps", + "Salary": 139205 + }, + { + "Department": "DevOps", + "Salary": 33198 + }, + { + "Department": "DevOps", + "Salary": 138451 + }, + { + "Department": "DevOps", + "Salary": 78184 + }, + { + "Department": "DevOps", + "Salary": 95863 + }, + { + "Department": "DevOps", + "Salary": 109115 + }, + { + "Department": "DevOps", + "Salary": 112081 + }, + { + "Department": "DevOps", + "Salary": 52585 + }, + { + "Department": "DevOps", + "Salary": 59234 + }, + { + "Department": "DevOps", + "Salary": 79594 + }, + { + "Department": "DevOps", + "Salary": 31000 + }, + { + "Department": "DevOps", + "Salary": 39541 + }, + { + "Department": "DevOps", + "Salary": 71030 + }, + { + "Department": "DevOps", + "Salary": 97871 + }, + { + "Department": "DevOps", + "Salary": 137660 + }, + { + "Department": "DevOps", + "Salary": 116448 + }, + { + "Department": "DevOps", + "Salary": 120894 + }, + { + "Department": "DevOps", + "Salary": 89998 + }, + { + "Department": "DevOps", + "Salary": 64199 + }, + { + "Department": "DevOps", + "Salary": 129374 + }, + { + "Department": "DevOps", + "Salary": 45934 + }, + { + "Department": "DevOps", + "Salary": 118110 + }, + { + "Department": "DevOps", + "Salary": 96248 + }, + { + "Department": "DevOps", + "Salary": 107250 + }, + { + "Department": "DevOps", + "Salary": 98014 + }, + { + "Department": "DevOps", + "Salary": 136688 + }, + { + "Department": "DevOps", + "Salary": 93539 + }, + { + "Department": "DevOps", + "Salary": 47930 + }, + { + "Department": "DevOps", + "Salary": 58701 + }, + { + "Department": "DevOps", + "Salary": 130046 + }, + { + "Department": "DevOps", + "Salary": 66543 + }, + { + "Department": "DevOps", + "Salary": 56123 + }, + { + "Department": "DevOps", + "Salary": 123028 + }, + { + "Department": "DevOps", + "Salary": 67373 + }, + { + "Department": "DevOps", + "Salary": 71826 + }, + { + "Department": "DevOps", + "Salary": 31390 + }, + { + "Department": "DevOps", + "Salary": 103624 + }, + { + "Department": "DevOps", + "Salary": 111196 + }, + { + "Department": "DevOps", + "Salary": 43988 + }, + { + "Department": "DevOps", + "Salary": 46399 + }, + { + "Department": "DevOps", + "Salary": 130701 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/boxplot/03-card4.flint.json b/test-harness/excel/evaluations/inputs/boxplot/03-card4.flint.json new file mode 100644 index 00000000..d96ac0f8 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/boxplot/03-card4.flint.json @@ -0,0 +1,1023 @@ +{ + "semantic_types": { + "Group": "Category", + "Score": "Score", + "Gender": "Category" + }, + "chart_spec": { + "chartType": "Boxplot", + "encodings": { + "x": "Group", + "y": "Score", + "color": "Gender" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Group": "Electronics", + "Gender": "Male", + "Score": 27 + }, + { + "Group": "Electronics", + "Gender": "Male", + "Score": 74 + }, + { + "Group": "Electronics", + "Gender": "Male", + "Score": 56 + }, + { + "Group": "Electronics", + "Gender": "Male", + "Score": 100 + }, + { + "Group": "Electronics", + "Gender": "Male", + "Score": 37 + }, + { + "Group": "Electronics", + "Gender": "Male", + "Score": 57 + }, + { + "Group": "Electronics", + "Gender": "Male", + "Score": 23 + }, + { + "Group": "Electronics", + "Gender": "Male", + "Score": 77 + }, + { + "Group": "Electronics", + "Gender": "Male", + "Score": 61 + }, + { + "Group": "Electronics", + "Gender": "Male", + "Score": 81 + }, + { + "Group": "Electronics", + "Gender": "Male", + "Score": 62 + }, + { + "Group": "Electronics", + "Gender": "Male", + "Score": 99 + }, + { + "Group": "Electronics", + "Gender": "Male", + "Score": 27 + }, + { + "Group": "Electronics", + "Gender": "Male", + "Score": 47 + }, + { + "Group": "Electronics", + "Gender": "Male", + "Score": 21 + }, + { + "Group": "Electronics", + "Gender": "Male", + "Score": 38 + }, + { + "Group": "Electronics", + "Gender": "Male", + "Score": 79 + }, + { + "Group": "Electronics", + "Gender": "Male", + "Score": 78 + }, + { + "Group": "Electronics", + "Gender": "Male", + "Score": 91 + }, + { + "Group": "Electronics", + "Gender": "Male", + "Score": 37 + }, + { + "Group": "Electronics", + "Gender": "Male", + "Score": 55 + }, + { + "Group": "Electronics", + "Gender": "Male", + "Score": 72 + }, + { + "Group": "Electronics", + "Gender": "Male", + "Score": 71 + }, + { + "Group": "Electronics", + "Gender": "Male", + "Score": 53 + }, + { + "Group": "Electronics", + "Gender": "Male", + "Score": 51 + }, + { + "Group": "Electronics", + "Gender": "Female", + "Score": 98 + }, + { + "Group": "Electronics", + "Gender": "Female", + "Score": 35 + }, + { + "Group": "Electronics", + "Gender": "Female", + "Score": 98 + }, + { + "Group": "Electronics", + "Gender": "Female", + "Score": 21 + }, + { + "Group": "Electronics", + "Gender": "Female", + "Score": 79 + }, + { + "Group": "Electronics", + "Gender": "Female", + "Score": 70 + }, + { + "Group": "Electronics", + "Gender": "Female", + "Score": 27 + }, + { + "Group": "Electronics", + "Gender": "Female", + "Score": 70 + }, + { + "Group": "Electronics", + "Gender": "Female", + "Score": 32 + }, + { + "Group": "Electronics", + "Gender": "Female", + "Score": 31 + }, + { + "Group": "Electronics", + "Gender": "Female", + "Score": 82 + }, + { + "Group": "Electronics", + "Gender": "Female", + "Score": 72 + }, + { + "Group": "Electronics", + "Gender": "Female", + "Score": 93 + }, + { + "Group": "Electronics", + "Gender": "Female", + "Score": 60 + }, + { + "Group": "Electronics", + "Gender": "Female", + "Score": 74 + }, + { + "Group": "Electronics", + "Gender": "Female", + "Score": 49 + }, + { + "Group": "Electronics", + "Gender": "Female", + "Score": 98 + }, + { + "Group": "Electronics", + "Gender": "Female", + "Score": 78 + }, + { + "Group": "Electronics", + "Gender": "Female", + "Score": 88 + }, + { + "Group": "Electronics", + "Gender": "Female", + "Score": 47 + }, + { + "Group": "Electronics", + "Gender": "Female", + "Score": 64 + }, + { + "Group": "Electronics", + "Gender": "Female", + "Score": 54 + }, + { + "Group": "Electronics", + "Gender": "Female", + "Score": 46 + }, + { + "Group": "Electronics", + "Gender": "Female", + "Score": 32 + }, + { + "Group": "Electronics", + "Gender": "Female", + "Score": 50 + }, + { + "Group": "Clothing", + "Gender": "Male", + "Score": 72 + }, + { + "Group": "Clothing", + "Gender": "Male", + "Score": 21 + }, + { + "Group": "Clothing", + "Gender": "Male", + "Score": 61 + }, + { + "Group": "Clothing", + "Gender": "Male", + "Score": 54 + }, + { + "Group": "Clothing", + "Gender": "Male", + "Score": 25 + }, + { + "Group": "Clothing", + "Gender": "Male", + "Score": 84 + }, + { + "Group": "Clothing", + "Gender": "Male", + "Score": 24 + }, + { + "Group": "Clothing", + "Gender": "Male", + "Score": 43 + }, + { + "Group": "Clothing", + "Gender": "Male", + "Score": 92 + }, + { + "Group": "Clothing", + "Gender": "Male", + "Score": 66 + }, + { + "Group": "Clothing", + "Gender": "Male", + "Score": 93 + }, + { + "Group": "Clothing", + "Gender": "Male", + "Score": 66 + }, + { + "Group": "Clothing", + "Gender": "Male", + "Score": 49 + }, + { + "Group": "Clothing", + "Gender": "Male", + "Score": 66 + }, + { + "Group": "Clothing", + "Gender": "Male", + "Score": 30 + }, + { + "Group": "Clothing", + "Gender": "Male", + "Score": 91 + }, + { + "Group": "Clothing", + "Gender": "Male", + "Score": 76 + }, + { + "Group": "Clothing", + "Gender": "Male", + "Score": 64 + }, + { + "Group": "Clothing", + "Gender": "Male", + "Score": 26 + }, + { + "Group": "Clothing", + "Gender": "Male", + "Score": 39 + }, + { + "Group": "Clothing", + "Gender": "Male", + "Score": 27 + }, + { + "Group": "Clothing", + "Gender": "Male", + "Score": 71 + }, + { + "Group": "Clothing", + "Gender": "Male", + "Score": 82 + }, + { + "Group": "Clothing", + "Gender": "Male", + "Score": 29 + }, + { + "Group": "Clothing", + "Gender": "Male", + "Score": 28 + }, + { + "Group": "Clothing", + "Gender": "Female", + "Score": 34 + }, + { + "Group": "Clothing", + "Gender": "Female", + "Score": 26 + }, + { + "Group": "Clothing", + "Gender": "Female", + "Score": 53 + }, + { + "Group": "Clothing", + "Gender": "Female", + "Score": 71 + }, + { + "Group": "Clothing", + "Gender": "Female", + "Score": 25 + }, + { + "Group": "Clothing", + "Gender": "Female", + "Score": 91 + }, + { + "Group": "Clothing", + "Gender": "Female", + "Score": 54 + }, + { + "Group": "Clothing", + "Gender": "Female", + "Score": 37 + }, + { + "Group": "Clothing", + "Gender": "Female", + "Score": 53 + }, + { + "Group": "Clothing", + "Gender": "Female", + "Score": 54 + }, + { + "Group": "Clothing", + "Gender": "Female", + "Score": 46 + }, + { + "Group": "Clothing", + "Gender": "Female", + "Score": 60 + }, + { + "Group": "Clothing", + "Gender": "Female", + "Score": 48 + }, + { + "Group": "Clothing", + "Gender": "Female", + "Score": 22 + }, + { + "Group": "Clothing", + "Gender": "Female", + "Score": 76 + }, + { + "Group": "Clothing", + "Gender": "Female", + "Score": 77 + }, + { + "Group": "Clothing", + "Gender": "Female", + "Score": 46 + }, + { + "Group": "Clothing", + "Gender": "Female", + "Score": 25 + }, + { + "Group": "Clothing", + "Gender": "Female", + "Score": 83 + }, + { + "Group": "Clothing", + "Gender": "Female", + "Score": 75 + }, + { + "Group": "Clothing", + "Gender": "Female", + "Score": 30 + }, + { + "Group": "Clothing", + "Gender": "Female", + "Score": 87 + }, + { + "Group": "Clothing", + "Gender": "Female", + "Score": 41 + }, + { + "Group": "Clothing", + "Gender": "Female", + "Score": 90 + }, + { + "Group": "Clothing", + "Gender": "Female", + "Score": 67 + }, + { + "Group": "Food", + "Gender": "Male", + "Score": 46 + }, + { + "Group": "Food", + "Gender": "Male", + "Score": 31 + }, + { + "Group": "Food", + "Gender": "Male", + "Score": 58 + }, + { + "Group": "Food", + "Gender": "Male", + "Score": 29 + }, + { + "Group": "Food", + "Gender": "Male", + "Score": 24 + }, + { + "Group": "Food", + "Gender": "Male", + "Score": 47 + }, + { + "Group": "Food", + "Gender": "Male", + "Score": 52 + }, + { + "Group": "Food", + "Gender": "Male", + "Score": 32 + }, + { + "Group": "Food", + "Gender": "Male", + "Score": 85 + }, + { + "Group": "Food", + "Gender": "Male", + "Score": 94 + }, + { + "Group": "Food", + "Gender": "Male", + "Score": 77 + }, + { + "Group": "Food", + "Gender": "Male", + "Score": 36 + }, + { + "Group": "Food", + "Gender": "Male", + "Score": 77 + }, + { + "Group": "Food", + "Gender": "Male", + "Score": 49 + }, + { + "Group": "Food", + "Gender": "Male", + "Score": 92 + }, + { + "Group": "Food", + "Gender": "Male", + "Score": 21 + }, + { + "Group": "Food", + "Gender": "Male", + "Score": 54 + }, + { + "Group": "Food", + "Gender": "Male", + "Score": 39 + }, + { + "Group": "Food", + "Gender": "Male", + "Score": 22 + }, + { + "Group": "Food", + "Gender": "Male", + "Score": 42 + }, + { + "Group": "Food", + "Gender": "Male", + "Score": 52 + }, + { + "Group": "Food", + "Gender": "Male", + "Score": 32 + }, + { + "Group": "Food", + "Gender": "Male", + "Score": 33 + }, + { + "Group": "Food", + "Gender": "Male", + "Score": 89 + }, + { + "Group": "Food", + "Gender": "Male", + "Score": 46 + }, + { + "Group": "Food", + "Gender": "Female", + "Score": 97 + }, + { + "Group": "Food", + "Gender": "Female", + "Score": 43 + }, + { + "Group": "Food", + "Gender": "Female", + "Score": 94 + }, + { + "Group": "Food", + "Gender": "Female", + "Score": 45 + }, + { + "Group": "Food", + "Gender": "Female", + "Score": 29 + }, + { + "Group": "Food", + "Gender": "Female", + "Score": 74 + }, + { + "Group": "Food", + "Gender": "Female", + "Score": 53 + }, + { + "Group": "Food", + "Gender": "Female", + "Score": 92 + }, + { + "Group": "Food", + "Gender": "Female", + "Score": 52 + }, + { + "Group": "Food", + "Gender": "Female", + "Score": 55 + }, + { + "Group": "Food", + "Gender": "Female", + "Score": 73 + }, + { + "Group": "Food", + "Gender": "Female", + "Score": 66 + }, + { + "Group": "Food", + "Gender": "Female", + "Score": 73 + }, + { + "Group": "Food", + "Gender": "Female", + "Score": 38 + }, + { + "Group": "Food", + "Gender": "Female", + "Score": 25 + }, + { + "Group": "Food", + "Gender": "Female", + "Score": 36 + }, + { + "Group": "Food", + "Gender": "Female", + "Score": 57 + }, + { + "Group": "Food", + "Gender": "Female", + "Score": 82 + }, + { + "Group": "Food", + "Gender": "Female", + "Score": 24 + }, + { + "Group": "Food", + "Gender": "Female", + "Score": 46 + }, + { + "Group": "Food", + "Gender": "Female", + "Score": 34 + }, + { + "Group": "Food", + "Gender": "Female", + "Score": 74 + }, + { + "Group": "Food", + "Gender": "Female", + "Score": 94 + }, + { + "Group": "Food", + "Gender": "Female", + "Score": 22 + }, + { + "Group": "Food", + "Gender": "Female", + "Score": 41 + }, + { + "Group": "Books", + "Gender": "Male", + "Score": 20 + }, + { + "Group": "Books", + "Gender": "Male", + "Score": 76 + }, + { + "Group": "Books", + "Gender": "Male", + "Score": 38 + }, + { + "Group": "Books", + "Gender": "Male", + "Score": 91 + }, + { + "Group": "Books", + "Gender": "Male", + "Score": 77 + }, + { + "Group": "Books", + "Gender": "Male", + "Score": 46 + }, + { + "Group": "Books", + "Gender": "Male", + "Score": 26 + }, + { + "Group": "Books", + "Gender": "Male", + "Score": 36 + }, + { + "Group": "Books", + "Gender": "Male", + "Score": 75 + }, + { + "Group": "Books", + "Gender": "Male", + "Score": 42 + }, + { + "Group": "Books", + "Gender": "Male", + "Score": 26 + }, + { + "Group": "Books", + "Gender": "Male", + "Score": 32 + }, + { + "Group": "Books", + "Gender": "Male", + "Score": 27 + }, + { + "Group": "Books", + "Gender": "Male", + "Score": 92 + }, + { + "Group": "Books", + "Gender": "Male", + "Score": 31 + }, + { + "Group": "Books", + "Gender": "Male", + "Score": 94 + }, + { + "Group": "Books", + "Gender": "Male", + "Score": 22 + }, + { + "Group": "Books", + "Gender": "Male", + "Score": 40 + }, + { + "Group": "Books", + "Gender": "Male", + "Score": 30 + }, + { + "Group": "Books", + "Gender": "Male", + "Score": 35 + }, + { + "Group": "Books", + "Gender": "Male", + "Score": 23 + }, + { + "Group": "Books", + "Gender": "Male", + "Score": 67 + }, + { + "Group": "Books", + "Gender": "Male", + "Score": 98 + }, + { + "Group": "Books", + "Gender": "Male", + "Score": 65 + }, + { + "Group": "Books", + "Gender": "Male", + "Score": 67 + }, + { + "Group": "Books", + "Gender": "Female", + "Score": 100 + }, + { + "Group": "Books", + "Gender": "Female", + "Score": 60 + }, + { + "Group": "Books", + "Gender": "Female", + "Score": 98 + }, + { + "Group": "Books", + "Gender": "Female", + "Score": 30 + }, + { + "Group": "Books", + "Gender": "Female", + "Score": 72 + }, + { + "Group": "Books", + "Gender": "Female", + "Score": 87 + }, + { + "Group": "Books", + "Gender": "Female", + "Score": 60 + }, + { + "Group": "Books", + "Gender": "Female", + "Score": 41 + }, + { + "Group": "Books", + "Gender": "Female", + "Score": 26 + }, + { + "Group": "Books", + "Gender": "Female", + "Score": 75 + }, + { + "Group": "Books", + "Gender": "Female", + "Score": 93 + }, + { + "Group": "Books", + "Gender": "Female", + "Score": 28 + }, + { + "Group": "Books", + "Gender": "Female", + "Score": 72 + }, + { + "Group": "Books", + "Gender": "Female", + "Score": 24 + }, + { + "Group": "Books", + "Gender": "Female", + "Score": 63 + }, + { + "Group": "Books", + "Gender": "Female", + "Score": 21 + }, + { + "Group": "Books", + "Gender": "Female", + "Score": 32 + }, + { + "Group": "Books", + "Gender": "Female", + "Score": 21 + }, + { + "Group": "Books", + "Gender": "Female", + "Score": 37 + }, + { + "Group": "Books", + "Gender": "Female", + "Score": 36 + }, + { + "Group": "Books", + "Gender": "Female", + "Score": 77 + }, + { + "Group": "Books", + "Gender": "Female", + "Score": 99 + }, + { + "Group": "Books", + "Gender": "Female", + "Score": 21 + }, + { + "Group": "Books", + "Gender": "Female", + "Score": 43 + }, + { + "Group": "Books", + "Gender": "Female", + "Score": 89 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/boxplot/04-card6.flint.json b/test-harness/excel/evaluations/inputs/boxplot/04-card6.flint.json new file mode 100644 index 00000000..974c1fcb --- /dev/null +++ b/test-harness/excel/evaluations/inputs/boxplot/04-card6.flint.json @@ -0,0 +1,2423 @@ +{ + "semantic_types": { + "Country": "Country", + "Revenue": "Amount", + "Quarter": "Category" + }, + "chart_spec": { + "chartType": "Boxplot", + "encodings": { + "x": "Country", + "y": "Revenue", + "color": "Quarter" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Country": "USA", + "Quarter": "Q1", + "Revenue": 5307 + }, + { + "Country": "USA", + "Quarter": "Q1", + "Revenue": 526 + }, + { + "Country": "USA", + "Quarter": "Q1", + "Revenue": 545 + }, + { + "Country": "USA", + "Quarter": "Q1", + "Revenue": 1434 + }, + { + "Country": "USA", + "Quarter": "Q1", + "Revenue": 5028 + }, + { + "Country": "USA", + "Quarter": "Q1", + "Revenue": 4161 + }, + { + "Country": "USA", + "Quarter": "Q1", + "Revenue": 1877 + }, + { + "Country": "USA", + "Quarter": "Q1", + "Revenue": 692 + }, + { + "Country": "USA", + "Quarter": "Q1", + "Revenue": 5309 + }, + { + "Country": "USA", + "Quarter": "Q1", + "Revenue": 2401 + }, + { + "Country": "USA", + "Quarter": "Q1", + "Revenue": 5327 + }, + { + "Country": "USA", + "Quarter": "Q1", + "Revenue": 2150 + }, + { + "Country": "USA", + "Quarter": "Q1", + "Revenue": 1694 + }, + { + "Country": "USA", + "Quarter": "Q1", + "Revenue": 1988 + }, + { + "Country": "USA", + "Quarter": "Q1", + "Revenue": 1107 + }, + { + "Country": "USA", + "Quarter": "Q1", + "Revenue": 3206 + }, + { + "Country": "USA", + "Quarter": "Q1", + "Revenue": 3090 + }, + { + "Country": "USA", + "Quarter": "Q1", + "Revenue": 4890 + }, + { + "Country": "USA", + "Quarter": "Q1", + "Revenue": 1197 + }, + { + "Country": "USA", + "Quarter": "Q1", + "Revenue": 1666 + }, + { + "Country": "USA", + "Quarter": "Q2", + "Revenue": 2051 + }, + { + "Country": "USA", + "Quarter": "Q2", + "Revenue": 3976 + }, + { + "Country": "USA", + "Quarter": "Q2", + "Revenue": 727 + }, + { + "Country": "USA", + "Quarter": "Q2", + "Revenue": 4339 + }, + { + "Country": "USA", + "Quarter": "Q2", + "Revenue": 1005 + }, + { + "Country": "USA", + "Quarter": "Q2", + "Revenue": 2555 + }, + { + "Country": "USA", + "Quarter": "Q2", + "Revenue": 4573 + }, + { + "Country": "USA", + "Quarter": "Q2", + "Revenue": 3763 + }, + { + "Country": "USA", + "Quarter": "Q2", + "Revenue": 4758 + }, + { + "Country": "USA", + "Quarter": "Q2", + "Revenue": 934 + }, + { + "Country": "USA", + "Quarter": "Q2", + "Revenue": 4447 + }, + { + "Country": "USA", + "Quarter": "Q2", + "Revenue": 4969 + }, + { + "Country": "USA", + "Quarter": "Q2", + "Revenue": 3426 + }, + { + "Country": "USA", + "Quarter": "Q2", + "Revenue": 3886 + }, + { + "Country": "USA", + "Quarter": "Q2", + "Revenue": 4304 + }, + { + "Country": "USA", + "Quarter": "Q2", + "Revenue": 2715 + }, + { + "Country": "USA", + "Quarter": "Q2", + "Revenue": 2774 + }, + { + "Country": "USA", + "Quarter": "Q2", + "Revenue": 3893 + }, + { + "Country": "USA", + "Quarter": "Q2", + "Revenue": 4604 + }, + { + "Country": "USA", + "Quarter": "Q2", + "Revenue": 540 + }, + { + "Country": "USA", + "Quarter": "Q3", + "Revenue": 2818 + }, + { + "Country": "USA", + "Quarter": "Q3", + "Revenue": 2383 + }, + { + "Country": "USA", + "Quarter": "Q3", + "Revenue": 3439 + }, + { + "Country": "USA", + "Quarter": "Q3", + "Revenue": 5230 + }, + { + "Country": "USA", + "Quarter": "Q3", + "Revenue": 2178 + }, + { + "Country": "USA", + "Quarter": "Q3", + "Revenue": 3286 + }, + { + "Country": "USA", + "Quarter": "Q3", + "Revenue": 3268 + }, + { + "Country": "USA", + "Quarter": "Q3", + "Revenue": 1968 + }, + { + "Country": "USA", + "Quarter": "Q3", + "Revenue": 841 + }, + { + "Country": "USA", + "Quarter": "Q3", + "Revenue": 4237 + }, + { + "Country": "USA", + "Quarter": "Q3", + "Revenue": 5490 + }, + { + "Country": "USA", + "Quarter": "Q3", + "Revenue": 2439 + }, + { + "Country": "USA", + "Quarter": "Q3", + "Revenue": 2237 + }, + { + "Country": "USA", + "Quarter": "Q3", + "Revenue": 3269 + }, + { + "Country": "USA", + "Quarter": "Q3", + "Revenue": 1816 + }, + { + "Country": "USA", + "Quarter": "Q3", + "Revenue": 5363 + }, + { + "Country": "USA", + "Quarter": "Q3", + "Revenue": 2862 + }, + { + "Country": "USA", + "Quarter": "Q3", + "Revenue": 1643 + }, + { + "Country": "USA", + "Quarter": "Q3", + "Revenue": 1075 + }, + { + "Country": "USA", + "Quarter": "Q3", + "Revenue": 1098 + }, + { + "Country": "USA", + "Quarter": "Q4", + "Revenue": 3273 + }, + { + "Country": "USA", + "Quarter": "Q4", + "Revenue": 1599 + }, + { + "Country": "USA", + "Quarter": "Q4", + "Revenue": 3374 + }, + { + "Country": "USA", + "Quarter": "Q4", + "Revenue": 1709 + }, + { + "Country": "USA", + "Quarter": "Q4", + "Revenue": 2987 + }, + { + "Country": "USA", + "Quarter": "Q4", + "Revenue": 4249 + }, + { + "Country": "USA", + "Quarter": "Q4", + "Revenue": 1270 + }, + { + "Country": "USA", + "Quarter": "Q4", + "Revenue": 3125 + }, + { + "Country": "USA", + "Quarter": "Q4", + "Revenue": 1651 + }, + { + "Country": "USA", + "Quarter": "Q4", + "Revenue": 2504 + }, + { + "Country": "USA", + "Quarter": "Q4", + "Revenue": 2671 + }, + { + "Country": "USA", + "Quarter": "Q4", + "Revenue": 5231 + }, + { + "Country": "USA", + "Quarter": "Q4", + "Revenue": 1836 + }, + { + "Country": "USA", + "Quarter": "Q4", + "Revenue": 4205 + }, + { + "Country": "USA", + "Quarter": "Q4", + "Revenue": 4126 + }, + { + "Country": "USA", + "Quarter": "Q4", + "Revenue": 2697 + }, + { + "Country": "USA", + "Quarter": "Q4", + "Revenue": 3932 + }, + { + "Country": "USA", + "Quarter": "Q4", + "Revenue": 5347 + }, + { + "Country": "USA", + "Quarter": "Q4", + "Revenue": 4723 + }, + { + "Country": "USA", + "Quarter": "Q4", + "Revenue": 3471 + }, + { + "Country": "China", + "Quarter": "Q1", + "Revenue": 984 + }, + { + "Country": "China", + "Quarter": "Q1", + "Revenue": 2669 + }, + { + "Country": "China", + "Quarter": "Q1", + "Revenue": 2967 + }, + { + "Country": "China", + "Quarter": "Q1", + "Revenue": 3152 + }, + { + "Country": "China", + "Quarter": "Q1", + "Revenue": 4873 + }, + { + "Country": "China", + "Quarter": "Q1", + "Revenue": 4492 + }, + { + "Country": "China", + "Quarter": "Q1", + "Revenue": 4069 + }, + { + "Country": "China", + "Quarter": "Q1", + "Revenue": 4379 + }, + { + "Country": "China", + "Quarter": "Q1", + "Revenue": 3391 + }, + { + "Country": "China", + "Quarter": "Q1", + "Revenue": 1353 + }, + { + "Country": "China", + "Quarter": "Q1", + "Revenue": 2873 + }, + { + "Country": "China", + "Quarter": "Q1", + "Revenue": 1701 + }, + { + "Country": "China", + "Quarter": "Q1", + "Revenue": 1117 + }, + { + "Country": "China", + "Quarter": "Q1", + "Revenue": 3945 + }, + { + "Country": "China", + "Quarter": "Q1", + "Revenue": 3172 + }, + { + "Country": "China", + "Quarter": "Q1", + "Revenue": 5021 + }, + { + "Country": "China", + "Quarter": "Q1", + "Revenue": 2748 + }, + { + "Country": "China", + "Quarter": "Q1", + "Revenue": 789 + }, + { + "Country": "China", + "Quarter": "Q1", + "Revenue": 4645 + }, + { + "Country": "China", + "Quarter": "Q1", + "Revenue": 2578 + }, + { + "Country": "China", + "Quarter": "Q2", + "Revenue": 5442 + }, + { + "Country": "China", + "Quarter": "Q2", + "Revenue": 929 + }, + { + "Country": "China", + "Quarter": "Q2", + "Revenue": 2789 + }, + { + "Country": "China", + "Quarter": "Q2", + "Revenue": 4133 + }, + { + "Country": "China", + "Quarter": "Q2", + "Revenue": 2487 + }, + { + "Country": "China", + "Quarter": "Q2", + "Revenue": 2743 + }, + { + "Country": "China", + "Quarter": "Q2", + "Revenue": 3170 + }, + { + "Country": "China", + "Quarter": "Q2", + "Revenue": 2712 + }, + { + "Country": "China", + "Quarter": "Q2", + "Revenue": 2793 + }, + { + "Country": "China", + "Quarter": "Q2", + "Revenue": 2119 + }, + { + "Country": "China", + "Quarter": "Q2", + "Revenue": 2877 + }, + { + "Country": "China", + "Quarter": "Q2", + "Revenue": 5205 + }, + { + "Country": "China", + "Quarter": "Q2", + "Revenue": 2034 + }, + { + "Country": "China", + "Quarter": "Q2", + "Revenue": 1109 + }, + { + "Country": "China", + "Quarter": "Q2", + "Revenue": 5070 + }, + { + "Country": "China", + "Quarter": "Q2", + "Revenue": 4313 + }, + { + "Country": "China", + "Quarter": "Q2", + "Revenue": 3601 + }, + { + "Country": "China", + "Quarter": "Q2", + "Revenue": 2549 + }, + { + "Country": "China", + "Quarter": "Q2", + "Revenue": 906 + }, + { + "Country": "China", + "Quarter": "Q2", + "Revenue": 2415 + }, + { + "Country": "China", + "Quarter": "Q3", + "Revenue": 2034 + }, + { + "Country": "China", + "Quarter": "Q3", + "Revenue": 1530 + }, + { + "Country": "China", + "Quarter": "Q3", + "Revenue": 1890 + }, + { + "Country": "China", + "Quarter": "Q3", + "Revenue": 2962 + }, + { + "Country": "China", + "Quarter": "Q3", + "Revenue": 2343 + }, + { + "Country": "China", + "Quarter": "Q3", + "Revenue": 2702 + }, + { + "Country": "China", + "Quarter": "Q3", + "Revenue": 1611 + }, + { + "Country": "China", + "Quarter": "Q3", + "Revenue": 1626 + }, + { + "Country": "China", + "Quarter": "Q3", + "Revenue": 5056 + }, + { + "Country": "China", + "Quarter": "Q3", + "Revenue": 1228 + }, + { + "Country": "China", + "Quarter": "Q3", + "Revenue": 3316 + }, + { + "Country": "China", + "Quarter": "Q3", + "Revenue": 2027 + }, + { + "Country": "China", + "Quarter": "Q3", + "Revenue": 2019 + }, + { + "Country": "China", + "Quarter": "Q3", + "Revenue": 1608 + }, + { + "Country": "China", + "Quarter": "Q3", + "Revenue": 5361 + }, + { + "Country": "China", + "Quarter": "Q3", + "Revenue": 2337 + }, + { + "Country": "China", + "Quarter": "Q3", + "Revenue": 3825 + }, + { + "Country": "China", + "Quarter": "Q3", + "Revenue": 1698 + }, + { + "Country": "China", + "Quarter": "Q3", + "Revenue": 1852 + }, + { + "Country": "China", + "Quarter": "Q3", + "Revenue": 1866 + }, + { + "Country": "China", + "Quarter": "Q4", + "Revenue": 1813 + }, + { + "Country": "China", + "Quarter": "Q4", + "Revenue": 4311 + }, + { + "Country": "China", + "Quarter": "Q4", + "Revenue": 5143 + }, + { + "Country": "China", + "Quarter": "Q4", + "Revenue": 5328 + }, + { + "Country": "China", + "Quarter": "Q4", + "Revenue": 4469 + }, + { + "Country": "China", + "Quarter": "Q4", + "Revenue": 1118 + }, + { + "Country": "China", + "Quarter": "Q4", + "Revenue": 2433 + }, + { + "Country": "China", + "Quarter": "Q4", + "Revenue": 5174 + }, + { + "Country": "China", + "Quarter": "Q4", + "Revenue": 4821 + }, + { + "Country": "China", + "Quarter": "Q4", + "Revenue": 1418 + }, + { + "Country": "China", + "Quarter": "Q4", + "Revenue": 4528 + }, + { + "Country": "China", + "Quarter": "Q4", + "Revenue": 4628 + }, + { + "Country": "China", + "Quarter": "Q4", + "Revenue": 4587 + }, + { + "Country": "China", + "Quarter": "Q4", + "Revenue": 1710 + }, + { + "Country": "China", + "Quarter": "Q4", + "Revenue": 2751 + }, + { + "Country": "China", + "Quarter": "Q4", + "Revenue": 2679 + }, + { + "Country": "China", + "Quarter": "Q4", + "Revenue": 3722 + }, + { + "Country": "China", + "Quarter": "Q4", + "Revenue": 3544 + }, + { + "Country": "China", + "Quarter": "Q4", + "Revenue": 2772 + }, + { + "Country": "China", + "Quarter": "Q4", + "Revenue": 3568 + }, + { + "Country": "Japan", + "Quarter": "Q1", + "Revenue": 3028 + }, + { + "Country": "Japan", + "Quarter": "Q1", + "Revenue": 1934 + }, + { + "Country": "Japan", + "Quarter": "Q1", + "Revenue": 3670 + }, + { + "Country": "Japan", + "Quarter": "Q1", + "Revenue": 1135 + }, + { + "Country": "Japan", + "Quarter": "Q1", + "Revenue": 5417 + }, + { + "Country": "Japan", + "Quarter": "Q1", + "Revenue": 4279 + }, + { + "Country": "Japan", + "Quarter": "Q1", + "Revenue": 791 + }, + { + "Country": "Japan", + "Quarter": "Q1", + "Revenue": 4260 + }, + { + "Country": "Japan", + "Quarter": "Q1", + "Revenue": 4786 + }, + { + "Country": "Japan", + "Quarter": "Q1", + "Revenue": 4478 + }, + { + "Country": "Japan", + "Quarter": "Q1", + "Revenue": 4390 + }, + { + "Country": "Japan", + "Quarter": "Q1", + "Revenue": 2668 + }, + { + "Country": "Japan", + "Quarter": "Q1", + "Revenue": 1008 + }, + { + "Country": "Japan", + "Quarter": "Q1", + "Revenue": 2849 + }, + { + "Country": "Japan", + "Quarter": "Q1", + "Revenue": 4680 + }, + { + "Country": "Japan", + "Quarter": "Q1", + "Revenue": 1019 + }, + { + "Country": "Japan", + "Quarter": "Q1", + "Revenue": 4116 + }, + { + "Country": "Japan", + "Quarter": "Q1", + "Revenue": 2746 + }, + { + "Country": "Japan", + "Quarter": "Q1", + "Revenue": 3255 + }, + { + "Country": "Japan", + "Quarter": "Q1", + "Revenue": 3787 + }, + { + "Country": "Japan", + "Quarter": "Q2", + "Revenue": 4053 + }, + { + "Country": "Japan", + "Quarter": "Q2", + "Revenue": 3639 + }, + { + "Country": "Japan", + "Quarter": "Q2", + "Revenue": 1813 + }, + { + "Country": "Japan", + "Quarter": "Q2", + "Revenue": 4518 + }, + { + "Country": "Japan", + "Quarter": "Q2", + "Revenue": 4056 + }, + { + "Country": "Japan", + "Quarter": "Q2", + "Revenue": 864 + }, + { + "Country": "Japan", + "Quarter": "Q2", + "Revenue": 2419 + }, + { + "Country": "Japan", + "Quarter": "Q2", + "Revenue": 1501 + }, + { + "Country": "Japan", + "Quarter": "Q2", + "Revenue": 5146 + }, + { + "Country": "Japan", + "Quarter": "Q2", + "Revenue": 2623 + }, + { + "Country": "Japan", + "Quarter": "Q2", + "Revenue": 3638 + }, + { + "Country": "Japan", + "Quarter": "Q2", + "Revenue": 1636 + }, + { + "Country": "Japan", + "Quarter": "Q2", + "Revenue": 4767 + }, + { + "Country": "Japan", + "Quarter": "Q2", + "Revenue": 2918 + }, + { + "Country": "Japan", + "Quarter": "Q2", + "Revenue": 2374 + }, + { + "Country": "Japan", + "Quarter": "Q2", + "Revenue": 2505 + }, + { + "Country": "Japan", + "Quarter": "Q2", + "Revenue": 800 + }, + { + "Country": "Japan", + "Quarter": "Q2", + "Revenue": 4601 + }, + { + "Country": "Japan", + "Quarter": "Q2", + "Revenue": 3104 + }, + { + "Country": "Japan", + "Quarter": "Q2", + "Revenue": 3599 + }, + { + "Country": "Japan", + "Quarter": "Q3", + "Revenue": 1082 + }, + { + "Country": "Japan", + "Quarter": "Q3", + "Revenue": 4576 + }, + { + "Country": "Japan", + "Quarter": "Q3", + "Revenue": 3332 + }, + { + "Country": "Japan", + "Quarter": "Q3", + "Revenue": 2739 + }, + { + "Country": "Japan", + "Quarter": "Q3", + "Revenue": 1338 + }, + { + "Country": "Japan", + "Quarter": "Q3", + "Revenue": 1008 + }, + { + "Country": "Japan", + "Quarter": "Q3", + "Revenue": 3245 + }, + { + "Country": "Japan", + "Quarter": "Q3", + "Revenue": 1546 + }, + { + "Country": "Japan", + "Quarter": "Q3", + "Revenue": 1980 + }, + { + "Country": "Japan", + "Quarter": "Q3", + "Revenue": 3053 + }, + { + "Country": "Japan", + "Quarter": "Q3", + "Revenue": 4785 + }, + { + "Country": "Japan", + "Quarter": "Q3", + "Revenue": 1021 + }, + { + "Country": "Japan", + "Quarter": "Q3", + "Revenue": 2833 + }, + { + "Country": "Japan", + "Quarter": "Q3", + "Revenue": 4241 + }, + { + "Country": "Japan", + "Quarter": "Q3", + "Revenue": 658 + }, + { + "Country": "Japan", + "Quarter": "Q3", + "Revenue": 4233 + }, + { + "Country": "Japan", + "Quarter": "Q3", + "Revenue": 3218 + }, + { + "Country": "Japan", + "Quarter": "Q3", + "Revenue": 942 + }, + { + "Country": "Japan", + "Quarter": "Q3", + "Revenue": 2782 + }, + { + "Country": "Japan", + "Quarter": "Q3", + "Revenue": 731 + }, + { + "Country": "Japan", + "Quarter": "Q4", + "Revenue": 5056 + }, + { + "Country": "Japan", + "Quarter": "Q4", + "Revenue": 2084 + }, + { + "Country": "Japan", + "Quarter": "Q4", + "Revenue": 2647 + }, + { + "Country": "Japan", + "Quarter": "Q4", + "Revenue": 2936 + }, + { + "Country": "Japan", + "Quarter": "Q4", + "Revenue": 966 + }, + { + "Country": "Japan", + "Quarter": "Q4", + "Revenue": 4979 + }, + { + "Country": "Japan", + "Quarter": "Q4", + "Revenue": 5183 + }, + { + "Country": "Japan", + "Quarter": "Q4", + "Revenue": 2470 + }, + { + "Country": "Japan", + "Quarter": "Q4", + "Revenue": 2053 + }, + { + "Country": "Japan", + "Quarter": "Q4", + "Revenue": 2974 + }, + { + "Country": "Japan", + "Quarter": "Q4", + "Revenue": 5261 + }, + { + "Country": "Japan", + "Quarter": "Q4", + "Revenue": 4893 + }, + { + "Country": "Japan", + "Quarter": "Q4", + "Revenue": 4264 + }, + { + "Country": "Japan", + "Quarter": "Q4", + "Revenue": 4763 + }, + { + "Country": "Japan", + "Quarter": "Q4", + "Revenue": 1663 + }, + { + "Country": "Japan", + "Quarter": "Q4", + "Revenue": 2540 + }, + { + "Country": "Japan", + "Quarter": "Q4", + "Revenue": 2663 + }, + { + "Country": "Japan", + "Quarter": "Q4", + "Revenue": 693 + }, + { + "Country": "Japan", + "Quarter": "Q4", + "Revenue": 3256 + }, + { + "Country": "Japan", + "Quarter": "Q4", + "Revenue": 3525 + }, + { + "Country": "Germany", + "Quarter": "Q1", + "Revenue": 5207 + }, + { + "Country": "Germany", + "Quarter": "Q1", + "Revenue": 785 + }, + { + "Country": "Germany", + "Quarter": "Q1", + "Revenue": 585 + }, + { + "Country": "Germany", + "Quarter": "Q1", + "Revenue": 1464 + }, + { + "Country": "Germany", + "Quarter": "Q1", + "Revenue": 2782 + }, + { + "Country": "Germany", + "Quarter": "Q1", + "Revenue": 3010 + }, + { + "Country": "Germany", + "Quarter": "Q1", + "Revenue": 1998 + }, + { + "Country": "Germany", + "Quarter": "Q1", + "Revenue": 3226 + }, + { + "Country": "Germany", + "Quarter": "Q1", + "Revenue": 4169 + }, + { + "Country": "Germany", + "Quarter": "Q1", + "Revenue": 5423 + }, + { + "Country": "Germany", + "Quarter": "Q1", + "Revenue": 3236 + }, + { + "Country": "Germany", + "Quarter": "Q1", + "Revenue": 3507 + }, + { + "Country": "Germany", + "Quarter": "Q1", + "Revenue": 2499 + }, + { + "Country": "Germany", + "Quarter": "Q1", + "Revenue": 4695 + }, + { + "Country": "Germany", + "Quarter": "Q1", + "Revenue": 3027 + }, + { + "Country": "Germany", + "Quarter": "Q1", + "Revenue": 1972 + }, + { + "Country": "Germany", + "Quarter": "Q1", + "Revenue": 4577 + }, + { + "Country": "Germany", + "Quarter": "Q1", + "Revenue": 4861 + }, + { + "Country": "Germany", + "Quarter": "Q1", + "Revenue": 4232 + }, + { + "Country": "Germany", + "Quarter": "Q1", + "Revenue": 2222 + }, + { + "Country": "Germany", + "Quarter": "Q2", + "Revenue": 5500 + }, + { + "Country": "Germany", + "Quarter": "Q2", + "Revenue": 2322 + }, + { + "Country": "Germany", + "Quarter": "Q2", + "Revenue": 1158 + }, + { + "Country": "Germany", + "Quarter": "Q2", + "Revenue": 4739 + }, + { + "Country": "Germany", + "Quarter": "Q2", + "Revenue": 3546 + }, + { + "Country": "Germany", + "Quarter": "Q2", + "Revenue": 2002 + }, + { + "Country": "Germany", + "Quarter": "Q2", + "Revenue": 3070 + }, + { + "Country": "Germany", + "Quarter": "Q2", + "Revenue": 5386 + }, + { + "Country": "Germany", + "Quarter": "Q2", + "Revenue": 1425 + }, + { + "Country": "Germany", + "Quarter": "Q2", + "Revenue": 1159 + }, + { + "Country": "Germany", + "Quarter": "Q2", + "Revenue": 5184 + }, + { + "Country": "Germany", + "Quarter": "Q2", + "Revenue": 3657 + }, + { + "Country": "Germany", + "Quarter": "Q2", + "Revenue": 2453 + }, + { + "Country": "Germany", + "Quarter": "Q2", + "Revenue": 3569 + }, + { + "Country": "Germany", + "Quarter": "Q2", + "Revenue": 4223 + }, + { + "Country": "Germany", + "Quarter": "Q2", + "Revenue": 5076 + }, + { + "Country": "Germany", + "Quarter": "Q2", + "Revenue": 2222 + }, + { + "Country": "Germany", + "Quarter": "Q2", + "Revenue": 3850 + }, + { + "Country": "Germany", + "Quarter": "Q2", + "Revenue": 5036 + }, + { + "Country": "Germany", + "Quarter": "Q2", + "Revenue": 3746 + }, + { + "Country": "Germany", + "Quarter": "Q3", + "Revenue": 2552 + }, + { + "Country": "Germany", + "Quarter": "Q3", + "Revenue": 1194 + }, + { + "Country": "Germany", + "Quarter": "Q3", + "Revenue": 779 + }, + { + "Country": "Germany", + "Quarter": "Q3", + "Revenue": 983 + }, + { + "Country": "Germany", + "Quarter": "Q3", + "Revenue": 3283 + }, + { + "Country": "Germany", + "Quarter": "Q3", + "Revenue": 1742 + }, + { + "Country": "Germany", + "Quarter": "Q3", + "Revenue": 2416 + }, + { + "Country": "Germany", + "Quarter": "Q3", + "Revenue": 2754 + }, + { + "Country": "Germany", + "Quarter": "Q3", + "Revenue": 4401 + }, + { + "Country": "Germany", + "Quarter": "Q3", + "Revenue": 4761 + }, + { + "Country": "Germany", + "Quarter": "Q3", + "Revenue": 2119 + }, + { + "Country": "Germany", + "Quarter": "Q3", + "Revenue": 5243 + }, + { + "Country": "Germany", + "Quarter": "Q3", + "Revenue": 3096 + }, + { + "Country": "Germany", + "Quarter": "Q3", + "Revenue": 4585 + }, + { + "Country": "Germany", + "Quarter": "Q3", + "Revenue": 4907 + }, + { + "Country": "Germany", + "Quarter": "Q3", + "Revenue": 1255 + }, + { + "Country": "Germany", + "Quarter": "Q3", + "Revenue": 2404 + }, + { + "Country": "Germany", + "Quarter": "Q3", + "Revenue": 4241 + }, + { + "Country": "Germany", + "Quarter": "Q3", + "Revenue": 2843 + }, + { + "Country": "Germany", + "Quarter": "Q3", + "Revenue": 4321 + }, + { + "Country": "Germany", + "Quarter": "Q4", + "Revenue": 3000 + }, + { + "Country": "Germany", + "Quarter": "Q4", + "Revenue": 2712 + }, + { + "Country": "Germany", + "Quarter": "Q4", + "Revenue": 5084 + }, + { + "Country": "Germany", + "Quarter": "Q4", + "Revenue": 5377 + }, + { + "Country": "Germany", + "Quarter": "Q4", + "Revenue": 3031 + }, + { + "Country": "Germany", + "Quarter": "Q4", + "Revenue": 3959 + }, + { + "Country": "Germany", + "Quarter": "Q4", + "Revenue": 5032 + }, + { + "Country": "Germany", + "Quarter": "Q4", + "Revenue": 1804 + }, + { + "Country": "Germany", + "Quarter": "Q4", + "Revenue": 4406 + }, + { + "Country": "Germany", + "Quarter": "Q4", + "Revenue": 5253 + }, + { + "Country": "Germany", + "Quarter": "Q4", + "Revenue": 2469 + }, + { + "Country": "Germany", + "Quarter": "Q4", + "Revenue": 3620 + }, + { + "Country": "Germany", + "Quarter": "Q4", + "Revenue": 1403 + }, + { + "Country": "Germany", + "Quarter": "Q4", + "Revenue": 4080 + }, + { + "Country": "Germany", + "Quarter": "Q4", + "Revenue": 3323 + }, + { + "Country": "Germany", + "Quarter": "Q4", + "Revenue": 3918 + }, + { + "Country": "Germany", + "Quarter": "Q4", + "Revenue": 3577 + }, + { + "Country": "Germany", + "Quarter": "Q4", + "Revenue": 4442 + }, + { + "Country": "Germany", + "Quarter": "Q4", + "Revenue": 2048 + }, + { + "Country": "Germany", + "Quarter": "Q4", + "Revenue": 2011 + }, + { + "Country": "UK", + "Quarter": "Q1", + "Revenue": 1383 + }, + { + "Country": "UK", + "Quarter": "Q1", + "Revenue": 1345 + }, + { + "Country": "UK", + "Quarter": "Q1", + "Revenue": 4205 + }, + { + "Country": "UK", + "Quarter": "Q1", + "Revenue": 963 + }, + { + "Country": "UK", + "Quarter": "Q1", + "Revenue": 3126 + }, + { + "Country": "UK", + "Quarter": "Q1", + "Revenue": 3803 + }, + { + "Country": "UK", + "Quarter": "Q1", + "Revenue": 966 + }, + { + "Country": "UK", + "Quarter": "Q1", + "Revenue": 830 + }, + { + "Country": "UK", + "Quarter": "Q1", + "Revenue": 2945 + }, + { + "Country": "UK", + "Quarter": "Q1", + "Revenue": 3215 + }, + { + "Country": "UK", + "Quarter": "Q1", + "Revenue": 3375 + }, + { + "Country": "UK", + "Quarter": "Q1", + "Revenue": 3420 + }, + { + "Country": "UK", + "Quarter": "Q1", + "Revenue": 3788 + }, + { + "Country": "UK", + "Quarter": "Q1", + "Revenue": 5289 + }, + { + "Country": "UK", + "Quarter": "Q1", + "Revenue": 619 + }, + { + "Country": "UK", + "Quarter": "Q1", + "Revenue": 3058 + }, + { + "Country": "UK", + "Quarter": "Q1", + "Revenue": 5495 + }, + { + "Country": "UK", + "Quarter": "Q1", + "Revenue": 2639 + }, + { + "Country": "UK", + "Quarter": "Q1", + "Revenue": 1403 + }, + { + "Country": "UK", + "Quarter": "Q1", + "Revenue": 710 + }, + { + "Country": "UK", + "Quarter": "Q2", + "Revenue": 2454 + }, + { + "Country": "UK", + "Quarter": "Q2", + "Revenue": 1676 + }, + { + "Country": "UK", + "Quarter": "Q2", + "Revenue": 2158 + }, + { + "Country": "UK", + "Quarter": "Q2", + "Revenue": 3213 + }, + { + "Country": "UK", + "Quarter": "Q2", + "Revenue": 2648 + }, + { + "Country": "UK", + "Quarter": "Q2", + "Revenue": 2165 + }, + { + "Country": "UK", + "Quarter": "Q2", + "Revenue": 872 + }, + { + "Country": "UK", + "Quarter": "Q2", + "Revenue": 3347 + }, + { + "Country": "UK", + "Quarter": "Q2", + "Revenue": 3229 + }, + { + "Country": "UK", + "Quarter": "Q2", + "Revenue": 601 + }, + { + "Country": "UK", + "Quarter": "Q2", + "Revenue": 5181 + }, + { + "Country": "UK", + "Quarter": "Q2", + "Revenue": 3379 + }, + { + "Country": "UK", + "Quarter": "Q2", + "Revenue": 3837 + }, + { + "Country": "UK", + "Quarter": "Q2", + "Revenue": 3309 + }, + { + "Country": "UK", + "Quarter": "Q2", + "Revenue": 1377 + }, + { + "Country": "UK", + "Quarter": "Q2", + "Revenue": 3385 + }, + { + "Country": "UK", + "Quarter": "Q2", + "Revenue": 1987 + }, + { + "Country": "UK", + "Quarter": "Q2", + "Revenue": 707 + }, + { + "Country": "UK", + "Quarter": "Q2", + "Revenue": 2180 + }, + { + "Country": "UK", + "Quarter": "Q2", + "Revenue": 2687 + }, + { + "Country": "UK", + "Quarter": "Q3", + "Revenue": 5286 + }, + { + "Country": "UK", + "Quarter": "Q3", + "Revenue": 5086 + }, + { + "Country": "UK", + "Quarter": "Q3", + "Revenue": 1048 + }, + { + "Country": "UK", + "Quarter": "Q3", + "Revenue": 2277 + }, + { + "Country": "UK", + "Quarter": "Q3", + "Revenue": 4452 + }, + { + "Country": "UK", + "Quarter": "Q3", + "Revenue": 5189 + }, + { + "Country": "UK", + "Quarter": "Q3", + "Revenue": 3647 + }, + { + "Country": "UK", + "Quarter": "Q3", + "Revenue": 3775 + }, + { + "Country": "UK", + "Quarter": "Q3", + "Revenue": 676 + }, + { + "Country": "UK", + "Quarter": "Q3", + "Revenue": 3864 + }, + { + "Country": "UK", + "Quarter": "Q3", + "Revenue": 2572 + }, + { + "Country": "UK", + "Quarter": "Q3", + "Revenue": 4031 + }, + { + "Country": "UK", + "Quarter": "Q3", + "Revenue": 3684 + }, + { + "Country": "UK", + "Quarter": "Q3", + "Revenue": 4458 + }, + { + "Country": "UK", + "Quarter": "Q3", + "Revenue": 1083 + }, + { + "Country": "UK", + "Quarter": "Q3", + "Revenue": 1688 + }, + { + "Country": "UK", + "Quarter": "Q3", + "Revenue": 2417 + }, + { + "Country": "UK", + "Quarter": "Q3", + "Revenue": 4886 + }, + { + "Country": "UK", + "Quarter": "Q3", + "Revenue": 3385 + }, + { + "Country": "UK", + "Quarter": "Q3", + "Revenue": 3253 + }, + { + "Country": "UK", + "Quarter": "Q4", + "Revenue": 2032 + }, + { + "Country": "UK", + "Quarter": "Q4", + "Revenue": 3423 + }, + { + "Country": "UK", + "Quarter": "Q4", + "Revenue": 2712 + }, + { + "Country": "UK", + "Quarter": "Q4", + "Revenue": 2662 + }, + { + "Country": "UK", + "Quarter": "Q4", + "Revenue": 2435 + }, + { + "Country": "UK", + "Quarter": "Q4", + "Revenue": 3726 + }, + { + "Country": "UK", + "Quarter": "Q4", + "Revenue": 3745 + }, + { + "Country": "UK", + "Quarter": "Q4", + "Revenue": 4196 + }, + { + "Country": "UK", + "Quarter": "Q4", + "Revenue": 1713 + }, + { + "Country": "UK", + "Quarter": "Q4", + "Revenue": 1761 + }, + { + "Country": "UK", + "Quarter": "Q4", + "Revenue": 4448 + }, + { + "Country": "UK", + "Quarter": "Q4", + "Revenue": 2291 + }, + { + "Country": "UK", + "Quarter": "Q4", + "Revenue": 4673 + }, + { + "Country": "UK", + "Quarter": "Q4", + "Revenue": 4466 + }, + { + "Country": "UK", + "Quarter": "Q4", + "Revenue": 3937 + }, + { + "Country": "UK", + "Quarter": "Q4", + "Revenue": 4730 + }, + { + "Country": "UK", + "Quarter": "Q4", + "Revenue": 4013 + }, + { + "Country": "UK", + "Quarter": "Q4", + "Revenue": 641 + }, + { + "Country": "UK", + "Quarter": "Q4", + "Revenue": 2101 + }, + { + "Country": "UK", + "Quarter": "Q4", + "Revenue": 2731 + }, + { + "Country": "France", + "Quarter": "Q1", + "Revenue": 1782 + }, + { + "Country": "France", + "Quarter": "Q1", + "Revenue": 1404 + }, + { + "Country": "France", + "Quarter": "Q1", + "Revenue": 4516 + }, + { + "Country": "France", + "Quarter": "Q1", + "Revenue": 5168 + }, + { + "Country": "France", + "Quarter": "Q1", + "Revenue": 966 + }, + { + "Country": "France", + "Quarter": "Q1", + "Revenue": 3631 + }, + { + "Country": "France", + "Quarter": "Q1", + "Revenue": 1222 + }, + { + "Country": "France", + "Quarter": "Q1", + "Revenue": 1673 + }, + { + "Country": "France", + "Quarter": "Q1", + "Revenue": 1636 + }, + { + "Country": "France", + "Quarter": "Q1", + "Revenue": 2179 + }, + { + "Country": "France", + "Quarter": "Q1", + "Revenue": 3593 + }, + { + "Country": "France", + "Quarter": "Q1", + "Revenue": 4105 + }, + { + "Country": "France", + "Quarter": "Q1", + "Revenue": 873 + }, + { + "Country": "France", + "Quarter": "Q1", + "Revenue": 1993 + }, + { + "Country": "France", + "Quarter": "Q1", + "Revenue": 4077 + }, + { + "Country": "France", + "Quarter": "Q1", + "Revenue": 5132 + }, + { + "Country": "France", + "Quarter": "Q1", + "Revenue": 2222 + }, + { + "Country": "France", + "Quarter": "Q1", + "Revenue": 5364 + }, + { + "Country": "France", + "Quarter": "Q1", + "Revenue": 1481 + }, + { + "Country": "France", + "Quarter": "Q1", + "Revenue": 2085 + }, + { + "Country": "France", + "Quarter": "Q2", + "Revenue": 2864 + }, + { + "Country": "France", + "Quarter": "Q2", + "Revenue": 1746 + }, + { + "Country": "France", + "Quarter": "Q2", + "Revenue": 4188 + }, + { + "Country": "France", + "Quarter": "Q2", + "Revenue": 3947 + }, + { + "Country": "France", + "Quarter": "Q2", + "Revenue": 864 + }, + { + "Country": "France", + "Quarter": "Q2", + "Revenue": 5176 + }, + { + "Country": "France", + "Quarter": "Q2", + "Revenue": 1059 + }, + { + "Country": "France", + "Quarter": "Q2", + "Revenue": 2550 + }, + { + "Country": "France", + "Quarter": "Q2", + "Revenue": 4961 + }, + { + "Country": "France", + "Quarter": "Q2", + "Revenue": 867 + }, + { + "Country": "France", + "Quarter": "Q2", + "Revenue": 3408 + }, + { + "Country": "France", + "Quarter": "Q2", + "Revenue": 2956 + }, + { + "Country": "France", + "Quarter": "Q2", + "Revenue": 2261 + }, + { + "Country": "France", + "Quarter": "Q2", + "Revenue": 3006 + }, + { + "Country": "France", + "Quarter": "Q2", + "Revenue": 2888 + }, + { + "Country": "France", + "Quarter": "Q2", + "Revenue": 3693 + }, + { + "Country": "France", + "Quarter": "Q2", + "Revenue": 2854 + }, + { + "Country": "France", + "Quarter": "Q2", + "Revenue": 4210 + }, + { + "Country": "France", + "Quarter": "Q2", + "Revenue": 1096 + }, + { + "Country": "France", + "Quarter": "Q2", + "Revenue": 5313 + }, + { + "Country": "France", + "Quarter": "Q3", + "Revenue": 743 + }, + { + "Country": "France", + "Quarter": "Q3", + "Revenue": 3697 + }, + { + "Country": "France", + "Quarter": "Q3", + "Revenue": 1631 + }, + { + "Country": "France", + "Quarter": "Q3", + "Revenue": 3998 + }, + { + "Country": "France", + "Quarter": "Q3", + "Revenue": 693 + }, + { + "Country": "France", + "Quarter": "Q3", + "Revenue": 2202 + }, + { + "Country": "France", + "Quarter": "Q3", + "Revenue": 4656 + }, + { + "Country": "France", + "Quarter": "Q3", + "Revenue": 999 + }, + { + "Country": "France", + "Quarter": "Q3", + "Revenue": 3215 + }, + { + "Country": "France", + "Quarter": "Q3", + "Revenue": 4509 + }, + { + "Country": "France", + "Quarter": "Q3", + "Revenue": 1407 + }, + { + "Country": "France", + "Quarter": "Q3", + "Revenue": 2995 + }, + { + "Country": "France", + "Quarter": "Q3", + "Revenue": 2415 + }, + { + "Country": "France", + "Quarter": "Q3", + "Revenue": 642 + }, + { + "Country": "France", + "Quarter": "Q3", + "Revenue": 538 + }, + { + "Country": "France", + "Quarter": "Q3", + "Revenue": 3026 + }, + { + "Country": "France", + "Quarter": "Q3", + "Revenue": 4038 + }, + { + "Country": "France", + "Quarter": "Q3", + "Revenue": 5315 + }, + { + "Country": "France", + "Quarter": "Q3", + "Revenue": 3588 + }, + { + "Country": "France", + "Quarter": "Q3", + "Revenue": 2390 + }, + { + "Country": "France", + "Quarter": "Q4", + "Revenue": 3361 + }, + { + "Country": "France", + "Quarter": "Q4", + "Revenue": 4249 + }, + { + "Country": "France", + "Quarter": "Q4", + "Revenue": 4601 + }, + { + "Country": "France", + "Quarter": "Q4", + "Revenue": 4427 + }, + { + "Country": "France", + "Quarter": "Q4", + "Revenue": 3050 + }, + { + "Country": "France", + "Quarter": "Q4", + "Revenue": 5015 + }, + { + "Country": "France", + "Quarter": "Q4", + "Revenue": 3122 + }, + { + "Country": "France", + "Quarter": "Q4", + "Revenue": 649 + }, + { + "Country": "France", + "Quarter": "Q4", + "Revenue": 5026 + }, + { + "Country": "France", + "Quarter": "Q4", + "Revenue": 1325 + }, + { + "Country": "France", + "Quarter": "Q4", + "Revenue": 4936 + }, + { + "Country": "France", + "Quarter": "Q4", + "Revenue": 3544 + }, + { + "Country": "France", + "Quarter": "Q4", + "Revenue": 4818 + }, + { + "Country": "France", + "Quarter": "Q4", + "Revenue": 4804 + }, + { + "Country": "France", + "Quarter": "Q4", + "Revenue": 2942 + }, + { + "Country": "France", + "Quarter": "Q4", + "Revenue": 4422 + }, + { + "Country": "France", + "Quarter": "Q4", + "Revenue": 4712 + }, + { + "Country": "France", + "Quarter": "Q4", + "Revenue": 3047 + }, + { + "Country": "France", + "Quarter": "Q4", + "Revenue": 2097 + }, + { + "Country": "France", + "Quarter": "Q4", + "Revenue": 3846 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/boxplot/05-card8.flint.json b/test-harness/excel/evaluations/inputs/boxplot/05-card8.flint.json new file mode 100644 index 00000000..351401a9 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/boxplot/05-card8.flint.json @@ -0,0 +1,3023 @@ +{ + "semantic_types": { + "Department": "Department", + "Compensation": "Amount", + "Level": "Category" + }, + "chart_spec": { + "chartType": "Boxplot", + "encodings": { + "x": "Department", + "y": "Compensation", + "color": "Level" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Department": "Engineering", + "Level": "Intern", + "Compensation": 146942 + }, + { + "Department": "Engineering", + "Level": "Intern", + "Compensation": 72824 + }, + { + "Department": "Engineering", + "Level": "Intern", + "Compensation": 28969 + }, + { + "Department": "Engineering", + "Level": "Intern", + "Compensation": 58947 + }, + { + "Department": "Engineering", + "Level": "Intern", + "Compensation": 70066 + }, + { + "Department": "Engineering", + "Level": "Intern", + "Compensation": 43824 + }, + { + "Department": "Engineering", + "Level": "Intern", + "Compensation": 167706 + }, + { + "Department": "Engineering", + "Level": "Intern", + "Compensation": 105483 + }, + { + "Department": "Engineering", + "Level": "Intern", + "Compensation": 132009 + }, + { + "Department": "Engineering", + "Level": "Intern", + "Compensation": 52044 + }, + { + "Department": "Engineering", + "Level": "Intern", + "Compensation": 82344 + }, + { + "Department": "Engineering", + "Level": "Intern", + "Compensation": 82273 + }, + { + "Department": "Engineering", + "Level": "Intern", + "Compensation": 109563 + }, + { + "Department": "Engineering", + "Level": "Intern", + "Compensation": 94558 + }, + { + "Department": "Engineering", + "Level": "Intern", + "Compensation": 89065 + }, + { + "Department": "Engineering", + "Level": "Junior", + "Compensation": 162930 + }, + { + "Department": "Engineering", + "Level": "Junior", + "Compensation": 158880 + }, + { + "Department": "Engineering", + "Level": "Junior", + "Compensation": 165534 + }, + { + "Department": "Engineering", + "Level": "Junior", + "Compensation": 182107 + }, + { + "Department": "Engineering", + "Level": "Junior", + "Compensation": 117416 + }, + { + "Department": "Engineering", + "Level": "Junior", + "Compensation": 139107 + }, + { + "Department": "Engineering", + "Level": "Junior", + "Compensation": 176471 + }, + { + "Department": "Engineering", + "Level": "Junior", + "Compensation": 74754 + }, + { + "Department": "Engineering", + "Level": "Junior", + "Compensation": 98386 + }, + { + "Department": "Engineering", + "Level": "Junior", + "Compensation": 29677 + }, + { + "Department": "Engineering", + "Level": "Junior", + "Compensation": 53964 + }, + { + "Department": "Engineering", + "Level": "Junior", + "Compensation": 140616 + }, + { + "Department": "Engineering", + "Level": "Junior", + "Compensation": 152346 + }, + { + "Department": "Engineering", + "Level": "Junior", + "Compensation": 80345 + }, + { + "Department": "Engineering", + "Level": "Junior", + "Compensation": 86686 + }, + { + "Department": "Engineering", + "Level": "Mid", + "Compensation": 86304 + }, + { + "Department": "Engineering", + "Level": "Mid", + "Compensation": 144446 + }, + { + "Department": "Engineering", + "Level": "Mid", + "Compensation": 134411 + }, + { + "Department": "Engineering", + "Level": "Mid", + "Compensation": 167851 + }, + { + "Department": "Engineering", + "Level": "Mid", + "Compensation": 94792 + }, + { + "Department": "Engineering", + "Level": "Mid", + "Compensation": 161473 + }, + { + "Department": "Engineering", + "Level": "Mid", + "Compensation": 170996 + }, + { + "Department": "Engineering", + "Level": "Mid", + "Compensation": 106959 + }, + { + "Department": "Engineering", + "Level": "Mid", + "Compensation": 89210 + }, + { + "Department": "Engineering", + "Level": "Mid", + "Compensation": 153683 + }, + { + "Department": "Engineering", + "Level": "Mid", + "Compensation": 148507 + }, + { + "Department": "Engineering", + "Level": "Mid", + "Compensation": 138119 + }, + { + "Department": "Engineering", + "Level": "Mid", + "Compensation": 185002 + }, + { + "Department": "Engineering", + "Level": "Mid", + "Compensation": 136505 + }, + { + "Department": "Engineering", + "Level": "Mid", + "Compensation": 183567 + }, + { + "Department": "Engineering", + "Level": "Senior", + "Compensation": 166033 + }, + { + "Department": "Engineering", + "Level": "Senior", + "Compensation": 159207 + }, + { + "Department": "Engineering", + "Level": "Senior", + "Compensation": 60558 + }, + { + "Department": "Engineering", + "Level": "Senior", + "Compensation": 199978 + }, + { + "Department": "Engineering", + "Level": "Senior", + "Compensation": 176068 + }, + { + "Department": "Engineering", + "Level": "Senior", + "Compensation": 121789 + }, + { + "Department": "Engineering", + "Level": "Senior", + "Compensation": 136114 + }, + { + "Department": "Engineering", + "Level": "Senior", + "Compensation": 84672 + }, + { + "Department": "Engineering", + "Level": "Senior", + "Compensation": 180547 + }, + { + "Department": "Engineering", + "Level": "Senior", + "Compensation": 158516 + }, + { + "Department": "Engineering", + "Level": "Senior", + "Compensation": 178804 + }, + { + "Department": "Engineering", + "Level": "Senior", + "Compensation": 87125 + }, + { + "Department": "Engineering", + "Level": "Senior", + "Compensation": 111674 + }, + { + "Department": "Engineering", + "Level": "Senior", + "Compensation": 50471 + }, + { + "Department": "Engineering", + "Level": "Senior", + "Compensation": 70991 + }, + { + "Department": "Engineering", + "Level": "Lead", + "Compensation": 189867 + }, + { + "Department": "Engineering", + "Level": "Lead", + "Compensation": 172211 + }, + { + "Department": "Engineering", + "Level": "Lead", + "Compensation": 46417 + }, + { + "Department": "Engineering", + "Level": "Lead", + "Compensation": 183270 + }, + { + "Department": "Engineering", + "Level": "Lead", + "Compensation": 69313 + }, + { + "Department": "Engineering", + "Level": "Lead", + "Compensation": 164153 + }, + { + "Department": "Engineering", + "Level": "Lead", + "Compensation": 67210 + }, + { + "Department": "Engineering", + "Level": "Lead", + "Compensation": 175330 + }, + { + "Department": "Engineering", + "Level": "Lead", + "Compensation": 153155 + }, + { + "Department": "Engineering", + "Level": "Lead", + "Compensation": 196369 + }, + { + "Department": "Engineering", + "Level": "Lead", + "Compensation": 79962 + }, + { + "Department": "Engineering", + "Level": "Lead", + "Compensation": 129469 + }, + { + "Department": "Engineering", + "Level": "Lead", + "Compensation": 64937 + }, + { + "Department": "Engineering", + "Level": "Lead", + "Compensation": 115222 + }, + { + "Department": "Engineering", + "Level": "Lead", + "Compensation": 183400 + }, + { + "Department": "Sales", + "Level": "Intern", + "Compensation": 155467 + }, + { + "Department": "Sales", + "Level": "Intern", + "Compensation": 32860 + }, + { + "Department": "Sales", + "Level": "Intern", + "Compensation": 174729 + }, + { + "Department": "Sales", + "Level": "Intern", + "Compensation": 190183 + }, + { + "Department": "Sales", + "Level": "Intern", + "Compensation": 61200 + }, + { + "Department": "Sales", + "Level": "Intern", + "Compensation": 145961 + }, + { + "Department": "Sales", + "Level": "Intern", + "Compensation": 39642 + }, + { + "Department": "Sales", + "Level": "Intern", + "Compensation": 66732 + }, + { + "Department": "Sales", + "Level": "Intern", + "Compensation": 186677 + }, + { + "Department": "Sales", + "Level": "Intern", + "Compensation": 111027 + }, + { + "Department": "Sales", + "Level": "Intern", + "Compensation": 28184 + }, + { + "Department": "Sales", + "Level": "Intern", + "Compensation": 166597 + }, + { + "Department": "Sales", + "Level": "Intern", + "Compensation": 195275 + }, + { + "Department": "Sales", + "Level": "Intern", + "Compensation": 66321 + }, + { + "Department": "Sales", + "Level": "Intern", + "Compensation": 102604 + }, + { + "Department": "Sales", + "Level": "Junior", + "Compensation": 46150 + }, + { + "Department": "Sales", + "Level": "Junior", + "Compensation": 70042 + }, + { + "Department": "Sales", + "Level": "Junior", + "Compensation": 163238 + }, + { + "Department": "Sales", + "Level": "Junior", + "Compensation": 94776 + }, + { + "Department": "Sales", + "Level": "Junior", + "Compensation": 77542 + }, + { + "Department": "Sales", + "Level": "Junior", + "Compensation": 40621 + }, + { + "Department": "Sales", + "Level": "Junior", + "Compensation": 70457 + }, + { + "Department": "Sales", + "Level": "Junior", + "Compensation": 151853 + }, + { + "Department": "Sales", + "Level": "Junior", + "Compensation": 192655 + }, + { + "Department": "Sales", + "Level": "Junior", + "Compensation": 129255 + }, + { + "Department": "Sales", + "Level": "Junior", + "Compensation": 142866 + }, + { + "Department": "Sales", + "Level": "Junior", + "Compensation": 169220 + }, + { + "Department": "Sales", + "Level": "Junior", + "Compensation": 188531 + }, + { + "Department": "Sales", + "Level": "Junior", + "Compensation": 108186 + }, + { + "Department": "Sales", + "Level": "Junior", + "Compensation": 60725 + }, + { + "Department": "Sales", + "Level": "Mid", + "Compensation": 29216 + }, + { + "Department": "Sales", + "Level": "Mid", + "Compensation": 179113 + }, + { + "Department": "Sales", + "Level": "Mid", + "Compensation": 25716 + }, + { + "Department": "Sales", + "Level": "Mid", + "Compensation": 152276 + }, + { + "Department": "Sales", + "Level": "Mid", + "Compensation": 132228 + }, + { + "Department": "Sales", + "Level": "Mid", + "Compensation": 52873 + }, + { + "Department": "Sales", + "Level": "Mid", + "Compensation": 194415 + }, + { + "Department": "Sales", + "Level": "Mid", + "Compensation": 134621 + }, + { + "Department": "Sales", + "Level": "Mid", + "Compensation": 194851 + }, + { + "Department": "Sales", + "Level": "Mid", + "Compensation": 109957 + }, + { + "Department": "Sales", + "Level": "Mid", + "Compensation": 64662 + }, + { + "Department": "Sales", + "Level": "Mid", + "Compensation": 43382 + }, + { + "Department": "Sales", + "Level": "Mid", + "Compensation": 95783 + }, + { + "Department": "Sales", + "Level": "Mid", + "Compensation": 29810 + }, + { + "Department": "Sales", + "Level": "Mid", + "Compensation": 191072 + }, + { + "Department": "Sales", + "Level": "Senior", + "Compensation": 114381 + }, + { + "Department": "Sales", + "Level": "Senior", + "Compensation": 47205 + }, + { + "Department": "Sales", + "Level": "Senior", + "Compensation": 123348 + }, + { + "Department": "Sales", + "Level": "Senior", + "Compensation": 89150 + }, + { + "Department": "Sales", + "Level": "Senior", + "Compensation": 25153 + }, + { + "Department": "Sales", + "Level": "Senior", + "Compensation": 139276 + }, + { + "Department": "Sales", + "Level": "Senior", + "Compensation": 37384 + }, + { + "Department": "Sales", + "Level": "Senior", + "Compensation": 90824 + }, + { + "Department": "Sales", + "Level": "Senior", + "Compensation": 157063 + }, + { + "Department": "Sales", + "Level": "Senior", + "Compensation": 81120 + }, + { + "Department": "Sales", + "Level": "Senior", + "Compensation": 155402 + }, + { + "Department": "Sales", + "Level": "Senior", + "Compensation": 165035 + }, + { + "Department": "Sales", + "Level": "Senior", + "Compensation": 188392 + }, + { + "Department": "Sales", + "Level": "Senior", + "Compensation": 54415 + }, + { + "Department": "Sales", + "Level": "Senior", + "Compensation": 34808 + }, + { + "Department": "Sales", + "Level": "Lead", + "Compensation": 197043 + }, + { + "Department": "Sales", + "Level": "Lead", + "Compensation": 27832 + }, + { + "Department": "Sales", + "Level": "Lead", + "Compensation": 26729 + }, + { + "Department": "Sales", + "Level": "Lead", + "Compensation": 27490 + }, + { + "Department": "Sales", + "Level": "Lead", + "Compensation": 48501 + }, + { + "Department": "Sales", + "Level": "Lead", + "Compensation": 27393 + }, + { + "Department": "Sales", + "Level": "Lead", + "Compensation": 167972 + }, + { + "Department": "Sales", + "Level": "Lead", + "Compensation": 27417 + }, + { + "Department": "Sales", + "Level": "Lead", + "Compensation": 54697 + }, + { + "Department": "Sales", + "Level": "Lead", + "Compensation": 45030 + }, + { + "Department": "Sales", + "Level": "Lead", + "Compensation": 148904 + }, + { + "Department": "Sales", + "Level": "Lead", + "Compensation": 158913 + }, + { + "Department": "Sales", + "Level": "Lead", + "Compensation": 199708 + }, + { + "Department": "Sales", + "Level": "Lead", + "Compensation": 193360 + }, + { + "Department": "Sales", + "Level": "Lead", + "Compensation": 72003 + }, + { + "Department": "Marketing", + "Level": "Intern", + "Compensation": 60009 + }, + { + "Department": "Marketing", + "Level": "Intern", + "Compensation": 73709 + }, + { + "Department": "Marketing", + "Level": "Intern", + "Compensation": 194798 + }, + { + "Department": "Marketing", + "Level": "Intern", + "Compensation": 90075 + }, + { + "Department": "Marketing", + "Level": "Intern", + "Compensation": 165620 + }, + { + "Department": "Marketing", + "Level": "Intern", + "Compensation": 57972 + }, + { + "Department": "Marketing", + "Level": "Intern", + "Compensation": 141196 + }, + { + "Department": "Marketing", + "Level": "Intern", + "Compensation": 113265 + }, + { + "Department": "Marketing", + "Level": "Intern", + "Compensation": 192632 + }, + { + "Department": "Marketing", + "Level": "Intern", + "Compensation": 95930 + }, + { + "Department": "Marketing", + "Level": "Intern", + "Compensation": 49578 + }, + { + "Department": "Marketing", + "Level": "Intern", + "Compensation": 115607 + }, + { + "Department": "Marketing", + "Level": "Intern", + "Compensation": 174247 + }, + { + "Department": "Marketing", + "Level": "Intern", + "Compensation": 138134 + }, + { + "Department": "Marketing", + "Level": "Intern", + "Compensation": 85374 + }, + { + "Department": "Marketing", + "Level": "Junior", + "Compensation": 72424 + }, + { + "Department": "Marketing", + "Level": "Junior", + "Compensation": 126748 + }, + { + "Department": "Marketing", + "Level": "Junior", + "Compensation": 179808 + }, + { + "Department": "Marketing", + "Level": "Junior", + "Compensation": 156068 + }, + { + "Department": "Marketing", + "Level": "Junior", + "Compensation": 168200 + }, + { + "Department": "Marketing", + "Level": "Junior", + "Compensation": 190182 + }, + { + "Department": "Marketing", + "Level": "Junior", + "Compensation": 33566 + }, + { + "Department": "Marketing", + "Level": "Junior", + "Compensation": 139319 + }, + { + "Department": "Marketing", + "Level": "Junior", + "Compensation": 66140 + }, + { + "Department": "Marketing", + "Level": "Junior", + "Compensation": 34582 + }, + { + "Department": "Marketing", + "Level": "Junior", + "Compensation": 73881 + }, + { + "Department": "Marketing", + "Level": "Junior", + "Compensation": 121614 + }, + { + "Department": "Marketing", + "Level": "Junior", + "Compensation": 164820 + }, + { + "Department": "Marketing", + "Level": "Junior", + "Compensation": 87253 + }, + { + "Department": "Marketing", + "Level": "Junior", + "Compensation": 166649 + }, + { + "Department": "Marketing", + "Level": "Mid", + "Compensation": 189072 + }, + { + "Department": "Marketing", + "Level": "Mid", + "Compensation": 116356 + }, + { + "Department": "Marketing", + "Level": "Mid", + "Compensation": 174926 + }, + { + "Department": "Marketing", + "Level": "Mid", + "Compensation": 177179 + }, + { + "Department": "Marketing", + "Level": "Mid", + "Compensation": 64980 + }, + { + "Department": "Marketing", + "Level": "Mid", + "Compensation": 148079 + }, + { + "Department": "Marketing", + "Level": "Mid", + "Compensation": 119401 + }, + { + "Department": "Marketing", + "Level": "Mid", + "Compensation": 78925 + }, + { + "Department": "Marketing", + "Level": "Mid", + "Compensation": 188354 + }, + { + "Department": "Marketing", + "Level": "Mid", + "Compensation": 120776 + }, + { + "Department": "Marketing", + "Level": "Mid", + "Compensation": 74385 + }, + { + "Department": "Marketing", + "Level": "Mid", + "Compensation": 196717 + }, + { + "Department": "Marketing", + "Level": "Mid", + "Compensation": 140588 + }, + { + "Department": "Marketing", + "Level": "Mid", + "Compensation": 32419 + }, + { + "Department": "Marketing", + "Level": "Mid", + "Compensation": 115529 + }, + { + "Department": "Marketing", + "Level": "Senior", + "Compensation": 89050 + }, + { + "Department": "Marketing", + "Level": "Senior", + "Compensation": 88385 + }, + { + "Department": "Marketing", + "Level": "Senior", + "Compensation": 103486 + }, + { + "Department": "Marketing", + "Level": "Senior", + "Compensation": 157605 + }, + { + "Department": "Marketing", + "Level": "Senior", + "Compensation": 92387 + }, + { + "Department": "Marketing", + "Level": "Senior", + "Compensation": 165817 + }, + { + "Department": "Marketing", + "Level": "Senior", + "Compensation": 37133 + }, + { + "Department": "Marketing", + "Level": "Senior", + "Compensation": 75650 + }, + { + "Department": "Marketing", + "Level": "Senior", + "Compensation": 104456 + }, + { + "Department": "Marketing", + "Level": "Senior", + "Compensation": 188609 + }, + { + "Department": "Marketing", + "Level": "Senior", + "Compensation": 33119 + }, + { + "Department": "Marketing", + "Level": "Senior", + "Compensation": 148110 + }, + { + "Department": "Marketing", + "Level": "Senior", + "Compensation": 108694 + }, + { + "Department": "Marketing", + "Level": "Senior", + "Compensation": 26866 + }, + { + "Department": "Marketing", + "Level": "Senior", + "Compensation": 67551 + }, + { + "Department": "Marketing", + "Level": "Lead", + "Compensation": 128097 + }, + { + "Department": "Marketing", + "Level": "Lead", + "Compensation": 102942 + }, + { + "Department": "Marketing", + "Level": "Lead", + "Compensation": 128884 + }, + { + "Department": "Marketing", + "Level": "Lead", + "Compensation": 26396 + }, + { + "Department": "Marketing", + "Level": "Lead", + "Compensation": 42729 + }, + { + "Department": "Marketing", + "Level": "Lead", + "Compensation": 143351 + }, + { + "Department": "Marketing", + "Level": "Lead", + "Compensation": 98117 + }, + { + "Department": "Marketing", + "Level": "Lead", + "Compensation": 52877 + }, + { + "Department": "Marketing", + "Level": "Lead", + "Compensation": 83631 + }, + { + "Department": "Marketing", + "Level": "Lead", + "Compensation": 183749 + }, + { + "Department": "Marketing", + "Level": "Lead", + "Compensation": 74300 + }, + { + "Department": "Marketing", + "Level": "Lead", + "Compensation": 157221 + }, + { + "Department": "Marketing", + "Level": "Lead", + "Compensation": 121483 + }, + { + "Department": "Marketing", + "Level": "Lead", + "Compensation": 64454 + }, + { + "Department": "Marketing", + "Level": "Lead", + "Compensation": 49212 + }, + { + "Department": "HR", + "Level": "Intern", + "Compensation": 73755 + }, + { + "Department": "HR", + "Level": "Intern", + "Compensation": 102046 + }, + { + "Department": "HR", + "Level": "Intern", + "Compensation": 116327 + }, + { + "Department": "HR", + "Level": "Intern", + "Compensation": 25926 + }, + { + "Department": "HR", + "Level": "Intern", + "Compensation": 185652 + }, + { + "Department": "HR", + "Level": "Intern", + "Compensation": 26363 + }, + { + "Department": "HR", + "Level": "Intern", + "Compensation": 191048 + }, + { + "Department": "HR", + "Level": "Intern", + "Compensation": 69665 + }, + { + "Department": "HR", + "Level": "Intern", + "Compensation": 128955 + }, + { + "Department": "HR", + "Level": "Intern", + "Compensation": 180078 + }, + { + "Department": "HR", + "Level": "Intern", + "Compensation": 146066 + }, + { + "Department": "HR", + "Level": "Intern", + "Compensation": 50705 + }, + { + "Department": "HR", + "Level": "Intern", + "Compensation": 149303 + }, + { + "Department": "HR", + "Level": "Intern", + "Compensation": 33329 + }, + { + "Department": "HR", + "Level": "Intern", + "Compensation": 192836 + }, + { + "Department": "HR", + "Level": "Junior", + "Compensation": 187219 + }, + { + "Department": "HR", + "Level": "Junior", + "Compensation": 112769 + }, + { + "Department": "HR", + "Level": "Junior", + "Compensation": 88688 + }, + { + "Department": "HR", + "Level": "Junior", + "Compensation": 129799 + }, + { + "Department": "HR", + "Level": "Junior", + "Compensation": 178256 + }, + { + "Department": "HR", + "Level": "Junior", + "Compensation": 140272 + }, + { + "Department": "HR", + "Level": "Junior", + "Compensation": 144024 + }, + { + "Department": "HR", + "Level": "Junior", + "Compensation": 31280 + }, + { + "Department": "HR", + "Level": "Junior", + "Compensation": 45902 + }, + { + "Department": "HR", + "Level": "Junior", + "Compensation": 100443 + }, + { + "Department": "HR", + "Level": "Junior", + "Compensation": 119633 + }, + { + "Department": "HR", + "Level": "Junior", + "Compensation": 118738 + }, + { + "Department": "HR", + "Level": "Junior", + "Compensation": 137571 + }, + { + "Department": "HR", + "Level": "Junior", + "Compensation": 87150 + }, + { + "Department": "HR", + "Level": "Junior", + "Compensation": 180790 + }, + { + "Department": "HR", + "Level": "Mid", + "Compensation": 29217 + }, + { + "Department": "HR", + "Level": "Mid", + "Compensation": 33304 + }, + { + "Department": "HR", + "Level": "Mid", + "Compensation": 107069 + }, + { + "Department": "HR", + "Level": "Mid", + "Compensation": 190117 + }, + { + "Department": "HR", + "Level": "Mid", + "Compensation": 169024 + }, + { + "Department": "HR", + "Level": "Mid", + "Compensation": 29796 + }, + { + "Department": "HR", + "Level": "Mid", + "Compensation": 137914 + }, + { + "Department": "HR", + "Level": "Mid", + "Compensation": 75454 + }, + { + "Department": "HR", + "Level": "Mid", + "Compensation": 132500 + }, + { + "Department": "HR", + "Level": "Mid", + "Compensation": 82709 + }, + { + "Department": "HR", + "Level": "Mid", + "Compensation": 83858 + }, + { + "Department": "HR", + "Level": "Mid", + "Compensation": 144843 + }, + { + "Department": "HR", + "Level": "Mid", + "Compensation": 151982 + }, + { + "Department": "HR", + "Level": "Mid", + "Compensation": 93584 + }, + { + "Department": "HR", + "Level": "Mid", + "Compensation": 162265 + }, + { + "Department": "HR", + "Level": "Senior", + "Compensation": 189251 + }, + { + "Department": "HR", + "Level": "Senior", + "Compensation": 134744 + }, + { + "Department": "HR", + "Level": "Senior", + "Compensation": 159542 + }, + { + "Department": "HR", + "Level": "Senior", + "Compensation": 101653 + }, + { + "Department": "HR", + "Level": "Senior", + "Compensation": 154261 + }, + { + "Department": "HR", + "Level": "Senior", + "Compensation": 70782 + }, + { + "Department": "HR", + "Level": "Senior", + "Compensation": 191135 + }, + { + "Department": "HR", + "Level": "Senior", + "Compensation": 123517 + }, + { + "Department": "HR", + "Level": "Senior", + "Compensation": 132421 + }, + { + "Department": "HR", + "Level": "Senior", + "Compensation": 149897 + }, + { + "Department": "HR", + "Level": "Senior", + "Compensation": 42516 + }, + { + "Department": "HR", + "Level": "Senior", + "Compensation": 65816 + }, + { + "Department": "HR", + "Level": "Senior", + "Compensation": 196742 + }, + { + "Department": "HR", + "Level": "Senior", + "Compensation": 50013 + }, + { + "Department": "HR", + "Level": "Senior", + "Compensation": 68809 + }, + { + "Department": "HR", + "Level": "Lead", + "Compensation": 105192 + }, + { + "Department": "HR", + "Level": "Lead", + "Compensation": 144708 + }, + { + "Department": "HR", + "Level": "Lead", + "Compensation": 153922 + }, + { + "Department": "HR", + "Level": "Lead", + "Compensation": 143104 + }, + { + "Department": "HR", + "Level": "Lead", + "Compensation": 155457 + }, + { + "Department": "HR", + "Level": "Lead", + "Compensation": 47204 + }, + { + "Department": "HR", + "Level": "Lead", + "Compensation": 107783 + }, + { + "Department": "HR", + "Level": "Lead", + "Compensation": 101932 + }, + { + "Department": "HR", + "Level": "Lead", + "Compensation": 120617 + }, + { + "Department": "HR", + "Level": "Lead", + "Compensation": 41495 + }, + { + "Department": "HR", + "Level": "Lead", + "Compensation": 54945 + }, + { + "Department": "HR", + "Level": "Lead", + "Compensation": 183372 + }, + { + "Department": "HR", + "Level": "Lead", + "Compensation": 41202 + }, + { + "Department": "HR", + "Level": "Lead", + "Compensation": 29056 + }, + { + "Department": "HR", + "Level": "Lead", + "Compensation": 119763 + }, + { + "Department": "Finance", + "Level": "Intern", + "Compensation": 27701 + }, + { + "Department": "Finance", + "Level": "Intern", + "Compensation": 100698 + }, + { + "Department": "Finance", + "Level": "Intern", + "Compensation": 25178 + }, + { + "Department": "Finance", + "Level": "Intern", + "Compensation": 48605 + }, + { + "Department": "Finance", + "Level": "Intern", + "Compensation": 37437 + }, + { + "Department": "Finance", + "Level": "Intern", + "Compensation": 99323 + }, + { + "Department": "Finance", + "Level": "Intern", + "Compensation": 194257 + }, + { + "Department": "Finance", + "Level": "Intern", + "Compensation": 95259 + }, + { + "Department": "Finance", + "Level": "Intern", + "Compensation": 137771 + }, + { + "Department": "Finance", + "Level": "Intern", + "Compensation": 111591 + }, + { + "Department": "Finance", + "Level": "Intern", + "Compensation": 52117 + }, + { + "Department": "Finance", + "Level": "Intern", + "Compensation": 75000 + }, + { + "Department": "Finance", + "Level": "Intern", + "Compensation": 199619 + }, + { + "Department": "Finance", + "Level": "Intern", + "Compensation": 94110 + }, + { + "Department": "Finance", + "Level": "Intern", + "Compensation": 77021 + }, + { + "Department": "Finance", + "Level": "Junior", + "Compensation": 38739 + }, + { + "Department": "Finance", + "Level": "Junior", + "Compensation": 104236 + }, + { + "Department": "Finance", + "Level": "Junior", + "Compensation": 161688 + }, + { + "Department": "Finance", + "Level": "Junior", + "Compensation": 108927 + }, + { + "Department": "Finance", + "Level": "Junior", + "Compensation": 89288 + }, + { + "Department": "Finance", + "Level": "Junior", + "Compensation": 68265 + }, + { + "Department": "Finance", + "Level": "Junior", + "Compensation": 55456 + }, + { + "Department": "Finance", + "Level": "Junior", + "Compensation": 198449 + }, + { + "Department": "Finance", + "Level": "Junior", + "Compensation": 29423 + }, + { + "Department": "Finance", + "Level": "Junior", + "Compensation": 156988 + }, + { + "Department": "Finance", + "Level": "Junior", + "Compensation": 41338 + }, + { + "Department": "Finance", + "Level": "Junior", + "Compensation": 46418 + }, + { + "Department": "Finance", + "Level": "Junior", + "Compensation": 28601 + }, + { + "Department": "Finance", + "Level": "Junior", + "Compensation": 165025 + }, + { + "Department": "Finance", + "Level": "Junior", + "Compensation": 25098 + }, + { + "Department": "Finance", + "Level": "Mid", + "Compensation": 102658 + }, + { + "Department": "Finance", + "Level": "Mid", + "Compensation": 69783 + }, + { + "Department": "Finance", + "Level": "Mid", + "Compensation": 193433 + }, + { + "Department": "Finance", + "Level": "Mid", + "Compensation": 79169 + }, + { + "Department": "Finance", + "Level": "Mid", + "Compensation": 91837 + }, + { + "Department": "Finance", + "Level": "Mid", + "Compensation": 37743 + }, + { + "Department": "Finance", + "Level": "Mid", + "Compensation": 166672 + }, + { + "Department": "Finance", + "Level": "Mid", + "Compensation": 63569 + }, + { + "Department": "Finance", + "Level": "Mid", + "Compensation": 46310 + }, + { + "Department": "Finance", + "Level": "Mid", + "Compensation": 129147 + }, + { + "Department": "Finance", + "Level": "Mid", + "Compensation": 65831 + }, + { + "Department": "Finance", + "Level": "Mid", + "Compensation": 102018 + }, + { + "Department": "Finance", + "Level": "Mid", + "Compensation": 167376 + }, + { + "Department": "Finance", + "Level": "Mid", + "Compensation": 155955 + }, + { + "Department": "Finance", + "Level": "Mid", + "Compensation": 193539 + }, + { + "Department": "Finance", + "Level": "Senior", + "Compensation": 113478 + }, + { + "Department": "Finance", + "Level": "Senior", + "Compensation": 102812 + }, + { + "Department": "Finance", + "Level": "Senior", + "Compensation": 39993 + }, + { + "Department": "Finance", + "Level": "Senior", + "Compensation": 190502 + }, + { + "Department": "Finance", + "Level": "Senior", + "Compensation": 162809 + }, + { + "Department": "Finance", + "Level": "Senior", + "Compensation": 61479 + }, + { + "Department": "Finance", + "Level": "Senior", + "Compensation": 108007 + }, + { + "Department": "Finance", + "Level": "Senior", + "Compensation": 194206 + }, + { + "Department": "Finance", + "Level": "Senior", + "Compensation": 124801 + }, + { + "Department": "Finance", + "Level": "Senior", + "Compensation": 181438 + }, + { + "Department": "Finance", + "Level": "Senior", + "Compensation": 86571 + }, + { + "Department": "Finance", + "Level": "Senior", + "Compensation": 71045 + }, + { + "Department": "Finance", + "Level": "Senior", + "Compensation": 60198 + }, + { + "Department": "Finance", + "Level": "Senior", + "Compensation": 89389 + }, + { + "Department": "Finance", + "Level": "Senior", + "Compensation": 189763 + }, + { + "Department": "Finance", + "Level": "Lead", + "Compensation": 169025 + }, + { + "Department": "Finance", + "Level": "Lead", + "Compensation": 46765 + }, + { + "Department": "Finance", + "Level": "Lead", + "Compensation": 71704 + }, + { + "Department": "Finance", + "Level": "Lead", + "Compensation": 109463 + }, + { + "Department": "Finance", + "Level": "Lead", + "Compensation": 170385 + }, + { + "Department": "Finance", + "Level": "Lead", + "Compensation": 162037 + }, + { + "Department": "Finance", + "Level": "Lead", + "Compensation": 28796 + }, + { + "Department": "Finance", + "Level": "Lead", + "Compensation": 116099 + }, + { + "Department": "Finance", + "Level": "Lead", + "Compensation": 56603 + }, + { + "Department": "Finance", + "Level": "Lead", + "Compensation": 59139 + }, + { + "Department": "Finance", + "Level": "Lead", + "Compensation": 146565 + }, + { + "Department": "Finance", + "Level": "Lead", + "Compensation": 50517 + }, + { + "Department": "Finance", + "Level": "Lead", + "Compensation": 143394 + }, + { + "Department": "Finance", + "Level": "Lead", + "Compensation": 129735 + }, + { + "Department": "Finance", + "Level": "Lead", + "Compensation": 156581 + }, + { + "Department": "Legal", + "Level": "Intern", + "Compensation": 38096 + }, + { + "Department": "Legal", + "Level": "Intern", + "Compensation": 150529 + }, + { + "Department": "Legal", + "Level": "Intern", + "Compensation": 168335 + }, + { + "Department": "Legal", + "Level": "Intern", + "Compensation": 188762 + }, + { + "Department": "Legal", + "Level": "Intern", + "Compensation": 156308 + }, + { + "Department": "Legal", + "Level": "Intern", + "Compensation": 168881 + }, + { + "Department": "Legal", + "Level": "Intern", + "Compensation": 83420 + }, + { + "Department": "Legal", + "Level": "Intern", + "Compensation": 140564 + }, + { + "Department": "Legal", + "Level": "Intern", + "Compensation": 167277 + }, + { + "Department": "Legal", + "Level": "Intern", + "Compensation": 81116 + }, + { + "Department": "Legal", + "Level": "Intern", + "Compensation": 97091 + }, + { + "Department": "Legal", + "Level": "Intern", + "Compensation": 126302 + }, + { + "Department": "Legal", + "Level": "Intern", + "Compensation": 31488 + }, + { + "Department": "Legal", + "Level": "Intern", + "Compensation": 49276 + }, + { + "Department": "Legal", + "Level": "Intern", + "Compensation": 110910 + }, + { + "Department": "Legal", + "Level": "Junior", + "Compensation": 164255 + }, + { + "Department": "Legal", + "Level": "Junior", + "Compensation": 41039 + }, + { + "Department": "Legal", + "Level": "Junior", + "Compensation": 85297 + }, + { + "Department": "Legal", + "Level": "Junior", + "Compensation": 194706 + }, + { + "Department": "Legal", + "Level": "Junior", + "Compensation": 127243 + }, + { + "Department": "Legal", + "Level": "Junior", + "Compensation": 97227 + }, + { + "Department": "Legal", + "Level": "Junior", + "Compensation": 141365 + }, + { + "Department": "Legal", + "Level": "Junior", + "Compensation": 141236 + }, + { + "Department": "Legal", + "Level": "Junior", + "Compensation": 70866 + }, + { + "Department": "Legal", + "Level": "Junior", + "Compensation": 197436 + }, + { + "Department": "Legal", + "Level": "Junior", + "Compensation": 151401 + }, + { + "Department": "Legal", + "Level": "Junior", + "Compensation": 126533 + }, + { + "Department": "Legal", + "Level": "Junior", + "Compensation": 68409 + }, + { + "Department": "Legal", + "Level": "Junior", + "Compensation": 32127 + }, + { + "Department": "Legal", + "Level": "Junior", + "Compensation": 105557 + }, + { + "Department": "Legal", + "Level": "Mid", + "Compensation": 153571 + }, + { + "Department": "Legal", + "Level": "Mid", + "Compensation": 187769 + }, + { + "Department": "Legal", + "Level": "Mid", + "Compensation": 75698 + }, + { + "Department": "Legal", + "Level": "Mid", + "Compensation": 31666 + }, + { + "Department": "Legal", + "Level": "Mid", + "Compensation": 68432 + }, + { + "Department": "Legal", + "Level": "Mid", + "Compensation": 59249 + }, + { + "Department": "Legal", + "Level": "Mid", + "Compensation": 70282 + }, + { + "Department": "Legal", + "Level": "Mid", + "Compensation": 183296 + }, + { + "Department": "Legal", + "Level": "Mid", + "Compensation": 162424 + }, + { + "Department": "Legal", + "Level": "Mid", + "Compensation": 62758 + }, + { + "Department": "Legal", + "Level": "Mid", + "Compensation": 65441 + }, + { + "Department": "Legal", + "Level": "Mid", + "Compensation": 188837 + }, + { + "Department": "Legal", + "Level": "Mid", + "Compensation": 185411 + }, + { + "Department": "Legal", + "Level": "Mid", + "Compensation": 172841 + }, + { + "Department": "Legal", + "Level": "Mid", + "Compensation": 140282 + }, + { + "Department": "Legal", + "Level": "Senior", + "Compensation": 147293 + }, + { + "Department": "Legal", + "Level": "Senior", + "Compensation": 199018 + }, + { + "Department": "Legal", + "Level": "Senior", + "Compensation": 148931 + }, + { + "Department": "Legal", + "Level": "Senior", + "Compensation": 83148 + }, + { + "Department": "Legal", + "Level": "Senior", + "Compensation": 116767 + }, + { + "Department": "Legal", + "Level": "Senior", + "Compensation": 71085 + }, + { + "Department": "Legal", + "Level": "Senior", + "Compensation": 194840 + }, + { + "Department": "Legal", + "Level": "Senior", + "Compensation": 92671 + }, + { + "Department": "Legal", + "Level": "Senior", + "Compensation": 44322 + }, + { + "Department": "Legal", + "Level": "Senior", + "Compensation": 139001 + }, + { + "Department": "Legal", + "Level": "Senior", + "Compensation": 143625 + }, + { + "Department": "Legal", + "Level": "Senior", + "Compensation": 148192 + }, + { + "Department": "Legal", + "Level": "Senior", + "Compensation": 93771 + }, + { + "Department": "Legal", + "Level": "Senior", + "Compensation": 152557 + }, + { + "Department": "Legal", + "Level": "Senior", + "Compensation": 128919 + }, + { + "Department": "Legal", + "Level": "Lead", + "Compensation": 98918 + }, + { + "Department": "Legal", + "Level": "Lead", + "Compensation": 41125 + }, + { + "Department": "Legal", + "Level": "Lead", + "Compensation": 131786 + }, + { + "Department": "Legal", + "Level": "Lead", + "Compensation": 149402 + }, + { + "Department": "Legal", + "Level": "Lead", + "Compensation": 116344 + }, + { + "Department": "Legal", + "Level": "Lead", + "Compensation": 140369 + }, + { + "Department": "Legal", + "Level": "Lead", + "Compensation": 35825 + }, + { + "Department": "Legal", + "Level": "Lead", + "Compensation": 128555 + }, + { + "Department": "Legal", + "Level": "Lead", + "Compensation": 94742 + }, + { + "Department": "Legal", + "Level": "Lead", + "Compensation": 28683 + }, + { + "Department": "Legal", + "Level": "Lead", + "Compensation": 143439 + }, + { + "Department": "Legal", + "Level": "Lead", + "Compensation": 185824 + }, + { + "Department": "Legal", + "Level": "Lead", + "Compensation": 117776 + }, + { + "Department": "Legal", + "Level": "Lead", + "Compensation": 62612 + }, + { + "Department": "Legal", + "Level": "Lead", + "Compensation": 65143 + }, + { + "Department": "Operations", + "Level": "Intern", + "Compensation": 79011 + }, + { + "Department": "Operations", + "Level": "Intern", + "Compensation": 70465 + }, + { + "Department": "Operations", + "Level": "Intern", + "Compensation": 111711 + }, + { + "Department": "Operations", + "Level": "Intern", + "Compensation": 146590 + }, + { + "Department": "Operations", + "Level": "Intern", + "Compensation": 115683 + }, + { + "Department": "Operations", + "Level": "Intern", + "Compensation": 60019 + }, + { + "Department": "Operations", + "Level": "Intern", + "Compensation": 63042 + }, + { + "Department": "Operations", + "Level": "Intern", + "Compensation": 118062 + }, + { + "Department": "Operations", + "Level": "Intern", + "Compensation": 143377 + }, + { + "Department": "Operations", + "Level": "Intern", + "Compensation": 189434 + }, + { + "Department": "Operations", + "Level": "Intern", + "Compensation": 71444 + }, + { + "Department": "Operations", + "Level": "Intern", + "Compensation": 109341 + }, + { + "Department": "Operations", + "Level": "Intern", + "Compensation": 51713 + }, + { + "Department": "Operations", + "Level": "Intern", + "Compensation": 119667 + }, + { + "Department": "Operations", + "Level": "Intern", + "Compensation": 162300 + }, + { + "Department": "Operations", + "Level": "Junior", + "Compensation": 71824 + }, + { + "Department": "Operations", + "Level": "Junior", + "Compensation": 27541 + }, + { + "Department": "Operations", + "Level": "Junior", + "Compensation": 29592 + }, + { + "Department": "Operations", + "Level": "Junior", + "Compensation": 29118 + }, + { + "Department": "Operations", + "Level": "Junior", + "Compensation": 108943 + }, + { + "Department": "Operations", + "Level": "Junior", + "Compensation": 176423 + }, + { + "Department": "Operations", + "Level": "Junior", + "Compensation": 140345 + }, + { + "Department": "Operations", + "Level": "Junior", + "Compensation": 155106 + }, + { + "Department": "Operations", + "Level": "Junior", + "Compensation": 97771 + }, + { + "Department": "Operations", + "Level": "Junior", + "Compensation": 190400 + }, + { + "Department": "Operations", + "Level": "Junior", + "Compensation": 26709 + }, + { + "Department": "Operations", + "Level": "Junior", + "Compensation": 43129 + }, + { + "Department": "Operations", + "Level": "Junior", + "Compensation": 38501 + }, + { + "Department": "Operations", + "Level": "Junior", + "Compensation": 129576 + }, + { + "Department": "Operations", + "Level": "Junior", + "Compensation": 108576 + }, + { + "Department": "Operations", + "Level": "Mid", + "Compensation": 132394 + }, + { + "Department": "Operations", + "Level": "Mid", + "Compensation": 42755 + }, + { + "Department": "Operations", + "Level": "Mid", + "Compensation": 61119 + }, + { + "Department": "Operations", + "Level": "Mid", + "Compensation": 168924 + }, + { + "Department": "Operations", + "Level": "Mid", + "Compensation": 111144 + }, + { + "Department": "Operations", + "Level": "Mid", + "Compensation": 75931 + }, + { + "Department": "Operations", + "Level": "Mid", + "Compensation": 89204 + }, + { + "Department": "Operations", + "Level": "Mid", + "Compensation": 57989 + }, + { + "Department": "Operations", + "Level": "Mid", + "Compensation": 76106 + }, + { + "Department": "Operations", + "Level": "Mid", + "Compensation": 70174 + }, + { + "Department": "Operations", + "Level": "Mid", + "Compensation": 110441 + }, + { + "Department": "Operations", + "Level": "Mid", + "Compensation": 151535 + }, + { + "Department": "Operations", + "Level": "Mid", + "Compensation": 103174 + }, + { + "Department": "Operations", + "Level": "Mid", + "Compensation": 172982 + }, + { + "Department": "Operations", + "Level": "Mid", + "Compensation": 54399 + }, + { + "Department": "Operations", + "Level": "Senior", + "Compensation": 102457 + }, + { + "Department": "Operations", + "Level": "Senior", + "Compensation": 189837 + }, + { + "Department": "Operations", + "Level": "Senior", + "Compensation": 192404 + }, + { + "Department": "Operations", + "Level": "Senior", + "Compensation": 103852 + }, + { + "Department": "Operations", + "Level": "Senior", + "Compensation": 185504 + }, + { + "Department": "Operations", + "Level": "Senior", + "Compensation": 168884 + }, + { + "Department": "Operations", + "Level": "Senior", + "Compensation": 126126 + }, + { + "Department": "Operations", + "Level": "Senior", + "Compensation": 49525 + }, + { + "Department": "Operations", + "Level": "Senior", + "Compensation": 84949 + }, + { + "Department": "Operations", + "Level": "Senior", + "Compensation": 110825 + }, + { + "Department": "Operations", + "Level": "Senior", + "Compensation": 134756 + }, + { + "Department": "Operations", + "Level": "Senior", + "Compensation": 190420 + }, + { + "Department": "Operations", + "Level": "Senior", + "Compensation": 188670 + }, + { + "Department": "Operations", + "Level": "Senior", + "Compensation": 168405 + }, + { + "Department": "Operations", + "Level": "Senior", + "Compensation": 135625 + }, + { + "Department": "Operations", + "Level": "Lead", + "Compensation": 104613 + }, + { + "Department": "Operations", + "Level": "Lead", + "Compensation": 37237 + }, + { + "Department": "Operations", + "Level": "Lead", + "Compensation": 71630 + }, + { + "Department": "Operations", + "Level": "Lead", + "Compensation": 77536 + }, + { + "Department": "Operations", + "Level": "Lead", + "Compensation": 126014 + }, + { + "Department": "Operations", + "Level": "Lead", + "Compensation": 94994 + }, + { + "Department": "Operations", + "Level": "Lead", + "Compensation": 68167 + }, + { + "Department": "Operations", + "Level": "Lead", + "Compensation": 160301 + }, + { + "Department": "Operations", + "Level": "Lead", + "Compensation": 77366 + }, + { + "Department": "Operations", + "Level": "Lead", + "Compensation": 72032 + }, + { + "Department": "Operations", + "Level": "Lead", + "Compensation": 187768 + }, + { + "Department": "Operations", + "Level": "Lead", + "Compensation": 61813 + }, + { + "Department": "Operations", + "Level": "Lead", + "Compensation": 113900 + }, + { + "Department": "Operations", + "Level": "Lead", + "Compensation": 186249 + }, + { + "Department": "Operations", + "Level": "Lead", + "Compensation": 95117 + }, + { + "Department": "Support", + "Level": "Intern", + "Compensation": 36288 + }, + { + "Department": "Support", + "Level": "Intern", + "Compensation": 41856 + }, + { + "Department": "Support", + "Level": "Intern", + "Compensation": 173218 + }, + { + "Department": "Support", + "Level": "Intern", + "Compensation": 179920 + }, + { + "Department": "Support", + "Level": "Intern", + "Compensation": 116722 + }, + { + "Department": "Support", + "Level": "Intern", + "Compensation": 28436 + }, + { + "Department": "Support", + "Level": "Intern", + "Compensation": 195200 + }, + { + "Department": "Support", + "Level": "Intern", + "Compensation": 25285 + }, + { + "Department": "Support", + "Level": "Intern", + "Compensation": 83113 + }, + { + "Department": "Support", + "Level": "Intern", + "Compensation": 61183 + }, + { + "Department": "Support", + "Level": "Intern", + "Compensation": 25058 + }, + { + "Department": "Support", + "Level": "Intern", + "Compensation": 131333 + }, + { + "Department": "Support", + "Level": "Intern", + "Compensation": 63468 + }, + { + "Department": "Support", + "Level": "Intern", + "Compensation": 109030 + }, + { + "Department": "Support", + "Level": "Intern", + "Compensation": 59208 + }, + { + "Department": "Support", + "Level": "Junior", + "Compensation": 81684 + }, + { + "Department": "Support", + "Level": "Junior", + "Compensation": 184929 + }, + { + "Department": "Support", + "Level": "Junior", + "Compensation": 131514 + }, + { + "Department": "Support", + "Level": "Junior", + "Compensation": 131090 + }, + { + "Department": "Support", + "Level": "Junior", + "Compensation": 184717 + }, + { + "Department": "Support", + "Level": "Junior", + "Compensation": 71204 + }, + { + "Department": "Support", + "Level": "Junior", + "Compensation": 93080 + }, + { + "Department": "Support", + "Level": "Junior", + "Compensation": 93046 + }, + { + "Department": "Support", + "Level": "Junior", + "Compensation": 53592 + }, + { + "Department": "Support", + "Level": "Junior", + "Compensation": 28659 + }, + { + "Department": "Support", + "Level": "Junior", + "Compensation": 98832 + }, + { + "Department": "Support", + "Level": "Junior", + "Compensation": 161084 + }, + { + "Department": "Support", + "Level": "Junior", + "Compensation": 120749 + }, + { + "Department": "Support", + "Level": "Junior", + "Compensation": 160365 + }, + { + "Department": "Support", + "Level": "Junior", + "Compensation": 106202 + }, + { + "Department": "Support", + "Level": "Mid", + "Compensation": 141149 + }, + { + "Department": "Support", + "Level": "Mid", + "Compensation": 191802 + }, + { + "Department": "Support", + "Level": "Mid", + "Compensation": 149027 + }, + { + "Department": "Support", + "Level": "Mid", + "Compensation": 118019 + }, + { + "Department": "Support", + "Level": "Mid", + "Compensation": 119462 + }, + { + "Department": "Support", + "Level": "Mid", + "Compensation": 45221 + }, + { + "Department": "Support", + "Level": "Mid", + "Compensation": 33737 + }, + { + "Department": "Support", + "Level": "Mid", + "Compensation": 46021 + }, + { + "Department": "Support", + "Level": "Mid", + "Compensation": 182193 + }, + { + "Department": "Support", + "Level": "Mid", + "Compensation": 162757 + }, + { + "Department": "Support", + "Level": "Mid", + "Compensation": 53786 + }, + { + "Department": "Support", + "Level": "Mid", + "Compensation": 131051 + }, + { + "Department": "Support", + "Level": "Mid", + "Compensation": 56855 + }, + { + "Department": "Support", + "Level": "Mid", + "Compensation": 87531 + }, + { + "Department": "Support", + "Level": "Mid", + "Compensation": 106631 + }, + { + "Department": "Support", + "Level": "Senior", + "Compensation": 178746 + }, + { + "Department": "Support", + "Level": "Senior", + "Compensation": 166352 + }, + { + "Department": "Support", + "Level": "Senior", + "Compensation": 100566 + }, + { + "Department": "Support", + "Level": "Senior", + "Compensation": 91923 + }, + { + "Department": "Support", + "Level": "Senior", + "Compensation": 70473 + }, + { + "Department": "Support", + "Level": "Senior", + "Compensation": 69378 + }, + { + "Department": "Support", + "Level": "Senior", + "Compensation": 42964 + }, + { + "Department": "Support", + "Level": "Senior", + "Compensation": 64852 + }, + { + "Department": "Support", + "Level": "Senior", + "Compensation": 85399 + }, + { + "Department": "Support", + "Level": "Senior", + "Compensation": 150271 + }, + { + "Department": "Support", + "Level": "Senior", + "Compensation": 27339 + }, + { + "Department": "Support", + "Level": "Senior", + "Compensation": 139308 + }, + { + "Department": "Support", + "Level": "Senior", + "Compensation": 54824 + }, + { + "Department": "Support", + "Level": "Senior", + "Compensation": 79555 + }, + { + "Department": "Support", + "Level": "Senior", + "Compensation": 114130 + }, + { + "Department": "Support", + "Level": "Lead", + "Compensation": 39242 + }, + { + "Department": "Support", + "Level": "Lead", + "Compensation": 166371 + }, + { + "Department": "Support", + "Level": "Lead", + "Compensation": 67494 + }, + { + "Department": "Support", + "Level": "Lead", + "Compensation": 41634 + }, + { + "Department": "Support", + "Level": "Lead", + "Compensation": 125765 + }, + { + "Department": "Support", + "Level": "Lead", + "Compensation": 101207 + }, + { + "Department": "Support", + "Level": "Lead", + "Compensation": 184008 + }, + { + "Department": "Support", + "Level": "Lead", + "Compensation": 53784 + }, + { + "Department": "Support", + "Level": "Lead", + "Compensation": 98900 + }, + { + "Department": "Support", + "Level": "Lead", + "Compensation": 83179 + }, + { + "Department": "Support", + "Level": "Lead", + "Compensation": 116417 + }, + { + "Department": "Support", + "Level": "Lead", + "Compensation": 139558 + }, + { + "Department": "Support", + "Level": "Lead", + "Compensation": 54339 + }, + { + "Department": "Support", + "Level": "Lead", + "Compensation": 154645 + }, + { + "Department": "Support", + "Level": "Lead", + "Compensation": 35402 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/boxplot/06-card6.flint.json b/test-harness/excel/evaluations/inputs/boxplot/06-card6.flint.json new file mode 100644 index 00000000..45bfc67d --- /dev/null +++ b/test-harness/excel/evaluations/inputs/boxplot/06-card6.flint.json @@ -0,0 +1,742 @@ +{ + "semantic_types": { + "Rating": "Category", + "ROI": "Quantity" + }, + "chart_spec": { + "chartType": "Boxplot", + "encodings": { + "x": "Rating", + "y": "ROI", + "color": "Rating" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Rating": "G", + "ROI": 10 + }, + { + "Rating": "G", + "ROI": 233 + }, + { + "Rating": "G", + "ROI": 101 + }, + { + "Rating": "G", + "ROI": 117 + }, + { + "Rating": "G", + "ROI": 279 + }, + { + "Rating": "G", + "ROI": 130 + }, + { + "Rating": "G", + "ROI": 41 + }, + { + "Rating": "G", + "ROI": 0 + }, + { + "Rating": "G", + "ROI": 282 + }, + { + "Rating": "G", + "ROI": 282 + }, + { + "Rating": "G", + "ROI": 179 + }, + { + "Rating": "G", + "ROI": 248 + }, + { + "Rating": "G", + "ROI": 288 + }, + { + "Rating": "G", + "ROI": 97 + }, + { + "Rating": "G", + "ROI": 76 + }, + { + "Rating": "G", + "ROI": 261 + }, + { + "Rating": "G", + "ROI": 174 + }, + { + "Rating": "G", + "ROI": 200 + }, + { + "Rating": "G", + "ROI": 77 + }, + { + "Rating": "G", + "ROI": 87 + }, + { + "Rating": "G", + "ROI": 202 + }, + { + "Rating": "G", + "ROI": 224 + }, + { + "Rating": "G", + "ROI": 22 + }, + { + "Rating": "G", + "ROI": 262 + }, + { + "Rating": "G", + "ROI": 171 + }, + { + "Rating": "G", + "ROI": 197 + }, + { + "Rating": "G", + "ROI": 249 + }, + { + "Rating": "G", + "ROI": 153 + }, + { + "Rating": "G", + "ROI": 143 + }, + { + "Rating": "G", + "ROI": 44 + }, + { + "Rating": "PG", + "ROI": 197 + }, + { + "Rating": "PG", + "ROI": 98 + }, + { + "Rating": "PG", + "ROI": 33 + }, + { + "Rating": "PG", + "ROI": 269 + }, + { + "Rating": "PG", + "ROI": 190 + }, + { + "Rating": "PG", + "ROI": 146 + }, + { + "Rating": "PG", + "ROI": 273 + }, + { + "Rating": "PG", + "ROI": 59 + }, + { + "Rating": "PG", + "ROI": 158 + }, + { + "Rating": "PG", + "ROI": 100 + }, + { + "Rating": "PG", + "ROI": 247 + }, + { + "Rating": "PG", + "ROI": 116 + }, + { + "Rating": "PG", + "ROI": 33 + }, + { + "Rating": "PG", + "ROI": 34 + }, + { + "Rating": "PG", + "ROI": 274 + }, + { + "Rating": "PG", + "ROI": 150 + }, + { + "Rating": "PG", + "ROI": 255 + }, + { + "Rating": "PG", + "ROI": 279 + }, + { + "Rating": "PG", + "ROI": 297 + }, + { + "Rating": "PG", + "ROI": 23 + }, + { + "Rating": "PG", + "ROI": 118 + }, + { + "Rating": "PG", + "ROI": 273 + }, + { + "Rating": "PG", + "ROI": 273 + }, + { + "Rating": "PG", + "ROI": 30 + }, + { + "Rating": "PG", + "ROI": 251 + }, + { + "Rating": "PG", + "ROI": 157 + }, + { + "Rating": "PG", + "ROI": 255 + }, + { + "Rating": "PG", + "ROI": 69 + }, + { + "Rating": "PG", + "ROI": 67 + }, + { + "Rating": "PG", + "ROI": 110 + }, + { + "Rating": "PG-13", + "ROI": 283 + }, + { + "Rating": "PG-13", + "ROI": 260 + }, + { + "Rating": "PG-13", + "ROI": 69 + }, + { + "Rating": "PG-13", + "ROI": 243 + }, + { + "Rating": "PG-13", + "ROI": 138 + }, + { + "Rating": "PG-13", + "ROI": 9 + }, + { + "Rating": "PG-13", + "ROI": 141 + }, + { + "Rating": "PG-13", + "ROI": 1 + }, + { + "Rating": "PG-13", + "ROI": 156 + }, + { + "Rating": "PG-13", + "ROI": 182 + }, + { + "Rating": "PG-13", + "ROI": 118 + }, + { + "Rating": "PG-13", + "ROI": 110 + }, + { + "Rating": "PG-13", + "ROI": 285 + }, + { + "Rating": "PG-13", + "ROI": 252 + }, + { + "Rating": "PG-13", + "ROI": 293 + }, + { + "Rating": "PG-13", + "ROI": 149 + }, + { + "Rating": "PG-13", + "ROI": 177 + }, + { + "Rating": "PG-13", + "ROI": 87 + }, + { + "Rating": "PG-13", + "ROI": 113 + }, + { + "Rating": "PG-13", + "ROI": 12 + }, + { + "Rating": "PG-13", + "ROI": 16 + }, + { + "Rating": "PG-13", + "ROI": 169 + }, + { + "Rating": "PG-13", + "ROI": 88 + }, + { + "Rating": "PG-13", + "ROI": 180 + }, + { + "Rating": "PG-13", + "ROI": 98 + }, + { + "Rating": "PG-13", + "ROI": 42 + }, + { + "Rating": "PG-13", + "ROI": 80 + }, + { + "Rating": "PG-13", + "ROI": 165 + }, + { + "Rating": "PG-13", + "ROI": 135 + }, + { + "Rating": "PG-13", + "ROI": 190 + }, + { + "Rating": "R", + "ROI": 105 + }, + { + "Rating": "R", + "ROI": 72 + }, + { + "Rating": "R", + "ROI": 193 + }, + { + "Rating": "R", + "ROI": 78 + }, + { + "Rating": "R", + "ROI": 193 + }, + { + "Rating": "R", + "ROI": 63 + }, + { + "Rating": "R", + "ROI": 109 + }, + { + "Rating": "R", + "ROI": 245 + }, + { + "Rating": "R", + "ROI": 231 + }, + { + "Rating": "R", + "ROI": 142 + }, + { + "Rating": "R", + "ROI": 271 + }, + { + "Rating": "R", + "ROI": 230 + }, + { + "Rating": "R", + "ROI": 203 + }, + { + "Rating": "R", + "ROI": 149 + }, + { + "Rating": "R", + "ROI": 36 + }, + { + "Rating": "R", + "ROI": 156 + }, + { + "Rating": "R", + "ROI": 293 + }, + { + "Rating": "R", + "ROI": 214 + }, + { + "Rating": "R", + "ROI": 205 + }, + { + "Rating": "R", + "ROI": 225 + }, + { + "Rating": "R", + "ROI": 77 + }, + { + "Rating": "R", + "ROI": 153 + }, + { + "Rating": "R", + "ROI": 108 + }, + { + "Rating": "R", + "ROI": 80 + }, + { + "Rating": "R", + "ROI": 178 + }, + { + "Rating": "R", + "ROI": 10 + }, + { + "Rating": "R", + "ROI": 29 + }, + { + "Rating": "R", + "ROI": 128 + }, + { + "Rating": "R", + "ROI": 67 + }, + { + "Rating": "R", + "ROI": 151 + }, + { + "Rating": "NC-17", + "ROI": 106 + }, + { + "Rating": "NC-17", + "ROI": 34 + }, + { + "Rating": "NC-17", + "ROI": 291 + }, + { + "Rating": "NC-17", + "ROI": 77 + }, + { + "Rating": "NC-17", + "ROI": 222 + }, + { + "Rating": "NC-17", + "ROI": 197 + }, + { + "Rating": "NC-17", + "ROI": 262 + }, + { + "Rating": "NC-17", + "ROI": 271 + }, + { + "Rating": "NC-17", + "ROI": 274 + }, + { + "Rating": "NC-17", + "ROI": 77 + }, + { + "Rating": "NC-17", + "ROI": 47 + }, + { + "Rating": "NC-17", + "ROI": 274 + }, + { + "Rating": "NC-17", + "ROI": 190 + }, + { + "Rating": "NC-17", + "ROI": 53 + }, + { + "Rating": "NC-17", + "ROI": 148 + }, + { + "Rating": "NC-17", + "ROI": 46 + }, + { + "Rating": "NC-17", + "ROI": 267 + }, + { + "Rating": "NC-17", + "ROI": 51 + }, + { + "Rating": "NC-17", + "ROI": 214 + }, + { + "Rating": "NC-17", + "ROI": 42 + }, + { + "Rating": "NC-17", + "ROI": 81 + }, + { + "Rating": "NC-17", + "ROI": 278 + }, + { + "Rating": "NC-17", + "ROI": 47 + }, + { + "Rating": "NC-17", + "ROI": 294 + }, + { + "Rating": "NC-17", + "ROI": 216 + }, + { + "Rating": "NC-17", + "ROI": 195 + }, + { + "Rating": "NC-17", + "ROI": 61 + }, + { + "Rating": "NC-17", + "ROI": 290 + }, + { + "Rating": "NC-17", + "ROI": 6 + }, + { + "Rating": "NC-17", + "ROI": 121 + }, + { + "Rating": "Unrated", + "ROI": 23 + }, + { + "Rating": "Unrated", + "ROI": 264 + }, + { + "Rating": "Unrated", + "ROI": 155 + }, + { + "Rating": "Unrated", + "ROI": 236 + }, + { + "Rating": "Unrated", + "ROI": 200 + }, + { + "Rating": "Unrated", + "ROI": 229 + }, + { + "Rating": "Unrated", + "ROI": 286 + }, + { + "Rating": "Unrated", + "ROI": 15 + }, + { + "Rating": "Unrated", + "ROI": 39 + }, + { + "Rating": "Unrated", + "ROI": 182 + }, + { + "Rating": "Unrated", + "ROI": 70 + }, + { + "Rating": "Unrated", + "ROI": 72 + }, + { + "Rating": "Unrated", + "ROI": 16 + }, + { + "Rating": "Unrated", + "ROI": 72 + }, + { + "Rating": "Unrated", + "ROI": 172 + }, + { + "Rating": "Unrated", + "ROI": 281 + }, + { + "Rating": "Unrated", + "ROI": 159 + }, + { + "Rating": "Unrated", + "ROI": 16 + }, + { + "Rating": "Unrated", + "ROI": 178 + }, + { + "Rating": "Unrated", + "ROI": 190 + }, + { + "Rating": "Unrated", + "ROI": 87 + }, + { + "Rating": "Unrated", + "ROI": 60 + }, + { + "Rating": "Unrated", + "ROI": 94 + }, + { + "Rating": "Unrated", + "ROI": 37 + }, + { + "Rating": "Unrated", + "ROI": 66 + }, + { + "Rating": "Unrated", + "ROI": 14 + }, + { + "Rating": "Unrated", + "ROI": 104 + }, + { + "Rating": "Unrated", + "ROI": 205 + }, + { + "Rating": "Unrated", + "ROI": 277 + }, + { + "Rating": "Unrated", + "ROI": 26 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/boxplot/07-card6.flint.json b/test-harness/excel/evaluations/inputs/boxplot/07-card6.flint.json new file mode 100644 index 00000000..cc7a72cd --- /dev/null +++ b/test-harness/excel/evaluations/inputs/boxplot/07-card6.flint.json @@ -0,0 +1,1103 @@ +{ + "semantic_types": { + "Department": "Department", + "Comp": "Amount", + "Level": "Category" + }, + "chart_spec": { + "chartType": "Boxplot", + "encodings": { + "x": "Department", + "y": "Comp", + "color": "Level" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Department": "Eng", + "Level": "L1", + "Comp": 131479 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 146102 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 39597 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 38452 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 118412 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 136322 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 71967 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 126731 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 34753 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 114284 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 113931 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 65479 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 49790 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 114370 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 120351 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 72381 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 119339 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 118045 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 90148 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 59101 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 122341 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 43128 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 117206 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 140706 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 66549 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 31972 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 61058 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 135529 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 61645 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 50435 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 48021 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 144729 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 113021 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 122310 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 117210 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 94611 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 63144 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 43254 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 72599 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 77863 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 102000 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 54628 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 74697 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 47861 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 95425 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 67767 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 106788 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 133613 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 128967 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 43612 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 92713 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 88343 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 76280 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 143955 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 68619 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 144617 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 37619 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 37765 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 95826 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 81406 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 138491 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 31754 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 115631 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 66909 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 87111 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 139970 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 55196 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 138734 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 46920 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 128444 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 144752 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 32709 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 72966 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 117427 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 143312 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 64988 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 68766 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 91041 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 64480 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 54696 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 142620 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 80353 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 69556 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 43833 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 83326 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 118275 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 103478 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 58476 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 65055 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 124611 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 38634 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 57805 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 66841 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 128825 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 60923 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 39170 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 73202 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 123939 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 144303 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 39405 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 66651 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 57839 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 32989 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 113528 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 122308 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 85949 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 50593 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 53694 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 87859 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 109768 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 44806 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 110749 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 91712 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 67477 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 145333 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 65407 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 32564 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 45287 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 41540 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 66089 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 91536 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 107305 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 59324 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 31478 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 34669 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 136042 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 34637 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 76435 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 96665 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 34492 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 39252 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 121288 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 110165 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 121080 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 87294 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 94412 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 77096 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 53954 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 30278 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 140327 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 55910 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 143868 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 47176 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 112516 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 37868 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 30950 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 44728 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 131874 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 66762 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 130806 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 124020 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 71433 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 36975 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 138681 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 117027 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 137905 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 144731 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 36302 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 112586 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 125763 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 81570 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 132520 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 131346 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 78736 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 135520 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 146984 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 93281 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 37886 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 84282 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 99982 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 98453 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 80323 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 41622 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 119291 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 136122 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 57945 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 139285 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 57216 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 134409 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 67250 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 44520 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 109757 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 99291 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 120065 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 64052 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 58134 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 75980 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 131888 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 54509 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 104657 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 68224 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 95234 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 99652 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 64728 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 149714 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 139702 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 108625 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 47411 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 97020 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 119860 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 113426 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 96788 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 58511 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 50798 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 142059 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 123279 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 82708 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 58976 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 76040 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 63499 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 128083 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 70667 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 116596 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 83487 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 63407 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 141277 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/boxplot/08-card6.flint.json b/test-harness/excel/evaluations/inputs/boxplot/08-card6.flint.json new file mode 100644 index 00000000..b75d2cdd --- /dev/null +++ b/test-harness/excel/evaluations/inputs/boxplot/08-card6.flint.json @@ -0,0 +1,1106 @@ +{ + "semantic_types": { + "Department": "Department", + "Comp": "Amount", + "Level": "Category" + }, + "chart_spec": { + "chartType": "Boxplot", + "encodings": { + "x": "Department", + "y": "Comp", + "color": "Level" + }, + "baseSize": { + "width": 560, + "height": 360 + }, + "chartProperties": { + "dodge": "global" + } + }, + "data": { + "values": [ + { + "Department": "Eng", + "Level": "L1", + "Comp": 120487 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 112029 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 158503 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 141556 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 153856 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 158557 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 152852 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 109993 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 135346 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 91879 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 176231 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 100024 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 169826 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 97560 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 156875 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 142222 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 106496 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 138900 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 100661 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 75734 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 79450 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 72710 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 99808 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 50171 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 98185 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 47139 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 87223 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 30262 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 112142 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 77624 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 74521 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 32730 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 106851 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 81895 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 39202 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 75728 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 70244 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 56807 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 34972 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 80723 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 49943 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 58958 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 95783 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 89363 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 99210 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 81985 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 112042 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 108322 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 48150 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 60316 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 66467 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 114938 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 97901 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 35599 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 103027 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 72210 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 67004 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 62336 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 89425 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 62313 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 52708 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 76301 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 72042 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 131565 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 99382 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 94496 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 52961 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 106673 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 52872 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 46594 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 104749 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 117830 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 92761 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 51350 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 118361 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 116817 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 79909 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 46605 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 102748 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 50937 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 114626 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 67693 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 113387 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 124123 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 116785 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 92349 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 66589 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 102082 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 104950 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 77980 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 137188 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 98190 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 133809 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 97212 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 64048 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 60395 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 124632 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 126067 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 118574 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 89035 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 74637 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 93108 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 118414 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 108701 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 123527 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 89290 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 129146 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 122260 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 130929 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 116113 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 134953 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 65496 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 85065 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 128000 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 122783 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 96327 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 140155 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 107904 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 131496 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 98803 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 75757 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 108766 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 122912 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 104072 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 72785 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 100247 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 161989 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 144786 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 96413 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 142276 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 118856 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 149049 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 92878 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 133435 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 105764 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 75657 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 135412 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 134032 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 151229 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 100279 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 143339 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 153180 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 141307 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 109693 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 139705 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 103090 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 130059 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 78684 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 160114 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 120917 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 137377 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 130994 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 123066 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 83487 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 160590 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 121263 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 111660 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 79516 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 98755 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 82145 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 109337 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 92207 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 120819 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 115511 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 92090 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 116032 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 114053 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 154858 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 170395 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 112457 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 148562 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 100294 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 124299 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 95345 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 102454 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 150011 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 154310 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 139126 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 94665 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 105569 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 124509 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 122563 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 175066 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 152618 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 148842 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 125536 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 107905 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 143232 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 164185 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 149054 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 95090 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 135989 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 107457 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 91361 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 112565 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 176672 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 144600 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 114963 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 114262 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 72798 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 63731 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 134481 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 47142 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 128092 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 129934 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 129356 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 51320 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 57371 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 61506 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 88602 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 85052 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 91637 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 67357 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 51175 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 56505 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 86855 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/boxplot/09-card6.flint.json b/test-harness/excel/evaluations/inputs/boxplot/09-card6.flint.json new file mode 100644 index 00000000..29b4d9a9 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/boxplot/09-card6.flint.json @@ -0,0 +1,1106 @@ +{ + "semantic_types": { + "Department": "Department", + "Comp": "Amount", + "Level": "Category" + }, + "chart_spec": { + "chartType": "Boxplot", + "encodings": { + "x": "Department", + "y": "Comp", + "color": "Level" + }, + "baseSize": { + "width": 560, + "height": 360 + }, + "chartProperties": { + "dodge": "local" + } + }, + "data": { + "values": [ + { + "Department": "Eng", + "Level": "L1", + "Comp": 106111 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 151334 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 165719 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 99511 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 104253 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 153821 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 111815 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 166713 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 156992 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 126234 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 130040 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 105738 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 179380 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 113100 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 167151 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 134589 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 155988 + }, + { + "Department": "Eng", + "Level": "L1", + "Comp": 167830 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 51689 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 52646 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 31766 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 103628 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 93789 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 47480 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 63341 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 51654 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 101208 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 88786 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 34355 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 51871 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 61997 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 61489 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 63147 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 31101 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 77552 + }, + { + "Department": "Eng", + "Level": "L2", + "Comp": 33444 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 44995 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 51806 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 49493 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 44652 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 38083 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 69552 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 32461 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 79728 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 75763 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 31946 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 68965 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 75514 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 73115 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 79003 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 31404 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 42364 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 106969 + }, + { + "Department": "Sales", + "Level": "L2", + "Comp": 84095 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 128935 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 79223 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 127697 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 59578 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 74443 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 78349 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 119148 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 112878 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 121883 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 91028 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 92014 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 97197 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 83582 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 46949 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 134625 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 131986 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 56254 + }, + { + "Department": "Sales", + "Level": "L3", + "Comp": 97134 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 108076 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 55798 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 80829 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 126830 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 70984 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 77644 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 58974 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 101366 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 46509 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 122929 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 125243 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 121636 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 68423 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 61234 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 93853 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 45663 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 121945 + }, + { + "Department": "HR", + "Level": "L3", + "Comp": 52981 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 93655 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 133807 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 72613 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 91573 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 149975 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 85162 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 141346 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 144524 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 94513 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 75311 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 86953 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 93214 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 104827 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 71511 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 107040 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 96583 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 118599 + }, + { + "Department": "HR", + "Level": "L4", + "Comp": 66142 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 66619 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 149015 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 63266 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 145234 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 140359 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 108074 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 111510 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 83122 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 136135 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 137463 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 126713 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 92684 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 113667 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 61790 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 91979 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 140992 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 132117 + }, + { + "Department": "Ops", + "Level": "L4", + "Comp": 92700 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 127897 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 103264 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 84973 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 107750 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 149173 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 117862 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 102924 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 141436 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 123431 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 95288 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 135545 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 114411 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 138146 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 86904 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 76665 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 159710 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 82951 + }, + { + "Department": "Ops", + "Level": "L5", + "Comp": 155326 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 121401 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 78617 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 113705 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 76327 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 152726 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 150833 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 106286 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 115145 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 155492 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 119816 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 79481 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 148794 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 124293 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 85456 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 121329 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 139497 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 112826 + }, + { + "Department": "Legal", + "Level": "L5", + "Comp": 147313 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 98062 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 146429 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 158538 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 91865 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 121717 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 94656 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 126593 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 141095 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 157662 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 137494 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 107623 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 90303 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 136715 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 161107 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 157614 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 135635 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 90385 + }, + { + "Department": "Legal", + "Level": "L1", + "Comp": 163819 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 116487 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 120399 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 164792 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 177884 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 170041 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 102729 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 101864 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 144923 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 140347 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 178244 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 102950 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 123103 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 157355 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 105522 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 148084 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 168144 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 172315 + }, + { + "Department": "Finance", + "Level": "L1", + "Comp": 168176 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 125430 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 123468 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 81218 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 99234 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 122348 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 73752 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 63500 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 121064 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 92309 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 102062 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 128095 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 92148 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 108179 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 75343 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 82177 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 106735 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 108899 + }, + { + "Department": "Finance", + "Level": "L3", + "Comp": 118384 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/candlestick-chart/00-card30.flint.json b/test-harness/excel/evaluations/inputs/candlestick-chart/00-card30.flint.json new file mode 100644 index 00000000..ee1590f0 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/candlestick-chart/00-card30.flint.json @@ -0,0 +1,237 @@ +{ + "semantic_types": { + "Date": "Date", + "Open": "Quantity", + "High": "Quantity", + "Low": "Quantity", + "Close": "Quantity" + }, + "chart_spec": { + "chartType": "Candlestick Chart", + "encodings": { + "x": "Date", + "open": "Open", + "high": "High", + "low": "Low", + "close": "Close" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Date": "2024-01-02", + "Open": 150, + "High": 151.92, + "Low": 146.46, + "Close": 148.11 + }, + { + "Date": "2024-01-03", + "Open": 148.11, + "High": 149.32, + "Low": 148.09, + "Close": 149.06 + }, + { + "Date": "2024-01-04", + "Open": 149.06, + "High": 151.75, + "Low": 148.4, + "Close": 149.91 + }, + { + "Date": "2024-01-05", + "Open": 149.91, + "High": 152.47, + "Low": 149.02, + "Close": 151.82 + }, + { + "Date": "2024-01-06", + "Open": 151.82, + "High": 153.51, + "Low": 149.99, + "Close": 151.57 + }, + { + "Date": "2024-01-07", + "Open": 151.57, + "High": 152.75, + "Low": 149.88, + "Close": 150.51 + }, + { + "Date": "2024-01-08", + "Open": 150.51, + "High": 151.51, + "Low": 148.35, + "Close": 149.57 + }, + { + "Date": "2024-01-09", + "Open": 149.57, + "High": 150.63, + "Low": 147.56, + "Close": 149.39 + }, + { + "Date": "2024-01-10", + "Open": 149.39, + "High": 152.06, + "Low": 148.66, + "Close": 150.9 + }, + { + "Date": "2024-01-11", + "Open": 150.9, + "High": 151.3, + "Low": 149.61, + "Close": 149.87 + }, + { + "Date": "2024-01-12", + "Open": 149.87, + "High": 151.35, + "Low": 149.21, + "Close": 151.17 + }, + { + "Date": "2024-01-13", + "Open": 151.17, + "High": 151.73, + "Low": 147.97, + "Close": 149.62 + }, + { + "Date": "2024-01-14", + "Open": 149.62, + "High": 150.8, + "Low": 146.76, + "Close": 147.73 + }, + { + "Date": "2024-01-15", + "Open": 147.73, + "High": 149.1, + "Low": 145.25, + "Close": 146.1 + }, + { + "Date": "2024-01-16", + "Open": 146.1, + "High": 147.67, + "Low": 144.21, + "Close": 146.29 + }, + { + "Date": "2024-01-17", + "Open": 146.29, + "High": 146.4, + "Low": 143.64, + "Close": 144.58 + }, + { + "Date": "2024-01-18", + "Open": 144.58, + "High": 145.76, + "Low": 142.62, + "Close": 142.96 + }, + { + "Date": "2024-01-19", + "Open": 142.96, + "High": 146.19, + "Low": 142.64, + "Close": 144.42 + }, + { + "Date": "2024-01-20", + "Open": 144.42, + "High": 144.78, + "Low": 143.33, + "Close": 143.71 + }, + { + "Date": "2024-01-21", + "Open": 143.71, + "High": 146.38, + "Low": 142.64, + "Close": 144.88 + }, + { + "Date": "2024-01-22", + "Open": 144.88, + "High": 145.47, + "Low": 143.69, + "Close": 144.64 + }, + { + "Date": "2024-01-23", + "Open": 144.64, + "High": 145.26, + "Low": 142.49, + "Close": 143.05 + }, + { + "Date": "2024-01-24", + "Open": 143.05, + "High": 144.87, + "Low": 142.3, + "Close": 144.48 + }, + { + "Date": "2024-01-25", + "Open": 144.48, + "High": 145.82, + "Low": 140.94, + "Close": 142.81 + }, + { + "Date": "2024-01-26", + "Open": 142.81, + "High": 143.06, + "Low": 141.28, + "Close": 141.8 + }, + { + "Date": "2024-01-27", + "Open": 141.8, + "High": 143.66, + "Low": 139.61, + "Close": 140.77 + }, + { + "Date": "2024-01-28", + "Open": 140.77, + "High": 142.16, + "Low": 139.75, + "Close": 140.6 + }, + { + "Date": "2024-01-29", + "Open": 140.6, + "High": 140.75, + "Low": 139, + "Close": 139.07 + }, + { + "Date": "2024-01-30", + "Open": 139.07, + "High": 140.62, + "Low": 138.24, + "Close": 140.49 + }, + { + "Date": "2024-01-31", + "Open": 140.49, + "High": 141.46, + "Low": 138.85, + "Close": 139.14 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/candlestick-chart/01-card90.flint.json b/test-harness/excel/evaluations/inputs/candlestick-chart/01-card90.flint.json new file mode 100644 index 00000000..1a5daf6a --- /dev/null +++ b/test-harness/excel/evaluations/inputs/candlestick-chart/01-card90.flint.json @@ -0,0 +1,657 @@ +{ + "semantic_types": { + "Date": "Date", + "Open": "Quantity", + "High": "Quantity", + "Low": "Quantity", + "Close": "Quantity" + }, + "chart_spec": { + "chartType": "Candlestick Chart", + "encodings": { + "x": "Date", + "open": "Open", + "high": "High", + "low": "Low", + "close": "Close" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Date": "2024-01-02", + "Open": 50, + "High": 50.23, + "Low": 49.07, + "Close": 50.22 + }, + { + "Date": "2024-01-03", + "Open": 50.22, + "High": 51.86, + "Low": 48.86, + "Close": 50.74 + }, + { + "Date": "2024-01-04", + "Open": 50.74, + "High": 51.61, + "Low": 49.03, + "Close": 50.73 + }, + { + "Date": "2024-01-05", + "Open": 50.73, + "High": 52.19, + "Low": 49.69, + "Close": 51.31 + }, + { + "Date": "2024-01-06", + "Open": 51.31, + "High": 53.62, + "Low": 51.24, + "Close": 52.8 + }, + { + "Date": "2024-01-07", + "Open": 52.8, + "High": 53.37, + "Low": 50.37, + "Close": 51.17 + }, + { + "Date": "2024-01-08", + "Open": 51.17, + "High": 53.27, + "Low": 49.98, + "Close": 52.16 + }, + { + "Date": "2024-01-09", + "Open": 52.16, + "High": 55.46, + "Low": 51.76, + "Close": 53.75 + }, + { + "Date": "2024-01-10", + "Open": 53.75, + "High": 56.14, + "Low": 52.19, + "Close": 54.26 + }, + { + "Date": "2024-01-11", + "Open": 54.26, + "High": 56.21, + "Low": 50.99, + "Close": 52.8 + }, + { + "Date": "2024-01-12", + "Open": 52.8, + "High": 54.52, + "Low": 50.94, + "Close": 52.64 + }, + { + "Date": "2024-01-13", + "Open": 52.64, + "High": 54.09, + "Low": 51.98, + "Close": 53.03 + }, + { + "Date": "2024-01-14", + "Open": 53.03, + "High": 54.86, + "Low": 49.42, + "Close": 51.12 + }, + { + "Date": "2024-01-15", + "Open": 51.12, + "High": 53.13, + "Low": 50.21, + "Close": 51.85 + }, + { + "Date": "2024-01-16", + "Open": 51.85, + "High": 53.76, + "Low": 50.8, + "Close": 53.2 + }, + { + "Date": "2024-01-17", + "Open": 53.2, + "High": 54.71, + "Low": 52.33, + "Close": 52.64 + }, + { + "Date": "2024-01-18", + "Open": 52.64, + "High": 54.62, + "Low": 51.43, + "Close": 54.03 + }, + { + "Date": "2024-01-19", + "Open": 54.03, + "High": 55.34, + "Low": 52.54, + "Close": 54.66 + }, + { + "Date": "2024-01-20", + "Open": 54.66, + "High": 55.32, + "Low": 51.84, + "Close": 53.3 + }, + { + "Date": "2024-01-21", + "Open": 53.3, + "High": 55.03, + "Low": 53.12, + "Close": 53.99 + }, + { + "Date": "2024-01-22", + "Open": 53.99, + "High": 55.47, + "Low": 52.53, + "Close": 55.39 + }, + { + "Date": "2024-01-23", + "Open": 55.39, + "High": 57.12, + "Low": 53.78, + "Close": 56.55 + }, + { + "Date": "2024-01-24", + "Open": 56.55, + "High": 57.93, + "Low": 55.04, + "Close": 56.14 + }, + { + "Date": "2024-01-25", + "Open": 56.14, + "High": 58.8, + "Low": 54.92, + "Close": 57.9 + }, + { + "Date": "2024-01-26", + "Open": 57.9, + "High": 59.55, + "Low": 55.99, + "Close": 59.37 + }, + { + "Date": "2024-01-27", + "Open": 59.37, + "High": 60.16, + "Low": 57.53, + "Close": 59.81 + }, + { + "Date": "2024-01-28", + "Open": 59.81, + "High": 61.4, + "Low": 57.08, + "Close": 58.34 + }, + { + "Date": "2024-01-29", + "Open": 58.34, + "High": 59.47, + "Low": 57.7, + "Close": 57.88 + }, + { + "Date": "2024-01-30", + "Open": 57.88, + "High": 58.14, + "Low": 57.07, + "Close": 58 + }, + { + "Date": "2024-01-31", + "Open": 58, + "High": 59.99, + "Low": 56.42, + "Close": 57.5 + }, + { + "Date": "2024-02-01", + "Open": 57.5, + "High": 58.87, + "Low": 54.78, + "Close": 55.77 + }, + { + "Date": "2024-02-02", + "Open": 55.77, + "High": 55.9, + "Low": 53.24, + "Close": 54.21 + }, + { + "Date": "2024-02-03", + "Open": 54.21, + "High": 55.69, + "Low": 52.97, + "Close": 54.74 + }, + { + "Date": "2024-02-04", + "Open": 54.74, + "High": 57.49, + "Low": 53.42, + "Close": 56.09 + }, + { + "Date": "2024-02-05", + "Open": 56.09, + "High": 57.46, + "Low": 55.57, + "Close": 55.67 + }, + { + "Date": "2024-02-06", + "Open": 55.67, + "High": 57.27, + "Low": 54.08, + "Close": 54.28 + }, + { + "Date": "2024-02-07", + "Open": 54.28, + "High": 55.21, + "Low": 52.76, + "Close": 53.82 + }, + { + "Date": "2024-02-08", + "Open": 53.82, + "High": 55.4, + "Low": 50.9, + "Close": 52.29 + }, + { + "Date": "2024-02-09", + "Open": 52.29, + "High": 54.89, + "Low": 51.18, + "Close": 53.19 + }, + { + "Date": "2024-02-10", + "Open": 53.19, + "High": 54.64, + "Low": 52.54, + "Close": 54.12 + }, + { + "Date": "2024-02-11", + "Open": 54.12, + "High": 57.19, + "Low": 54.05, + "Close": 55.72 + }, + { + "Date": "2024-02-12", + "Open": 55.72, + "High": 57.32, + "Low": 53.12, + "Close": 54.84 + }, + { + "Date": "2024-02-13", + "Open": 54.84, + "High": 56.08, + "Low": 53.58, + "Close": 55.66 + }, + { + "Date": "2024-02-14", + "Open": 55.66, + "High": 57.12, + "Low": 52.81, + "Close": 54.29 + }, + { + "Date": "2024-02-15", + "Open": 54.29, + "High": 56.16, + "Low": 51.5, + "Close": 53 + }, + { + "Date": "2024-02-16", + "Open": 53, + "High": 53.65, + "Low": 51.11, + "Close": 53.06 + }, + { + "Date": "2024-02-17", + "Open": 53.06, + "High": 55.05, + "Low": 51.88, + "Close": 53.45 + }, + { + "Date": "2024-02-18", + "Open": 53.45, + "High": 55.1, + "Low": 52.98, + "Close": 53.6 + }, + { + "Date": "2024-02-19", + "Open": 53.6, + "High": 56.79, + "Low": 52.09, + "Close": 55 + }, + { + "Date": "2024-02-20", + "Open": 55, + "High": 57.86, + "Low": 53.15, + "Close": 55.97 + }, + { + "Date": "2024-02-21", + "Open": 55.97, + "High": 57.45, + "Low": 55.46, + "Close": 55.77 + }, + { + "Date": "2024-02-22", + "Open": 55.77, + "High": 57.57, + "Low": 53.23, + "Close": 55.12 + }, + { + "Date": "2024-02-23", + "Open": 55.12, + "High": 56.97, + "Low": 51.91, + "Close": 53.84 + }, + { + "Date": "2024-02-24", + "Open": 53.84, + "High": 55.18, + "Low": 52.17, + "Close": 54.05 + }, + { + "Date": "2024-02-25", + "Open": 54.05, + "High": 56.81, + "Low": 53.61, + "Close": 54.87 + }, + { + "Date": "2024-02-26", + "Open": 54.87, + "High": 57.04, + "Low": 53.8, + "Close": 56.3 + }, + { + "Date": "2024-02-27", + "Open": 56.3, + "High": 59.58, + "Low": 55.35, + "Close": 58.38 + }, + { + "Date": "2024-02-28", + "Open": 58.38, + "High": 60.02, + "Low": 56.25, + "Close": 57.55 + }, + { + "Date": "2024-02-29", + "Open": 57.55, + "High": 59.04, + "Low": 57.23, + "Close": 58.85 + }, + { + "Date": "2024-03-01", + "Open": 58.85, + "High": 60.43, + "Low": 58.09, + "Close": 60.41 + }, + { + "Date": "2024-03-02", + "Open": 60.41, + "High": 61.04, + "Low": 59.69, + "Close": 60.7 + }, + { + "Date": "2024-03-03", + "Open": 60.7, + "High": 62.92, + "Low": 59.03, + "Close": 61.8 + }, + { + "Date": "2024-03-04", + "Open": 61.8, + "High": 63.14, + "Low": 59.3, + "Close": 59.97 + }, + { + "Date": "2024-03-05", + "Open": 59.97, + "High": 60.51, + "Low": 56.74, + "Close": 58.24 + }, + { + "Date": "2024-03-06", + "Open": 58.24, + "High": 58.39, + "Low": 55.55, + "Close": 57.25 + }, + { + "Date": "2024-03-07", + "Open": 57.25, + "High": 59.55, + "Low": 56.78, + "Close": 58.29 + }, + { + "Date": "2024-03-08", + "Open": 58.29, + "High": 60.28, + "Low": 56.42, + "Close": 60.21 + }, + { + "Date": "2024-03-09", + "Open": 60.21, + "High": 62.75, + "Low": 59.59, + "Close": 61.67 + }, + { + "Date": "2024-03-10", + "Open": 61.67, + "High": 64.54, + "Low": 60.79, + "Close": 63.43 + }, + { + "Date": "2024-03-11", + "Open": 63.43, + "High": 65.85, + "Low": 63.37, + "Close": 65.44 + }, + { + "Date": "2024-03-12", + "Open": 65.44, + "High": 66.03, + "Low": 65.15, + "Close": 65.24 + }, + { + "Date": "2024-03-13", + "Open": 65.24, + "High": 67.59, + "Low": 64.63, + "Close": 66.35 + }, + { + "Date": "2024-03-14", + "Open": 66.35, + "High": 68.74, + "Low": 64.66, + "Close": 67.06 + }, + { + "Date": "2024-03-15", + "Open": 67.06, + "High": 68.28, + "Low": 65.43, + "Close": 67.4 + }, + { + "Date": "2024-03-16", + "Open": 67.4, + "High": 68.58, + "Low": 65.97, + "Close": 66.34 + }, + { + "Date": "2024-03-17", + "Open": 66.34, + "High": 69.57, + "Low": 65.13, + "Close": 67.78 + }, + { + "Date": "2024-03-18", + "Open": 67.78, + "High": 68.21, + "Low": 64.9, + "Close": 66.1 + }, + { + "Date": "2024-03-19", + "Open": 66.1, + "High": 68.25, + "Low": 65.69, + "Close": 68.16 + }, + { + "Date": "2024-03-20", + "Open": 68.16, + "High": 68.74, + "Low": 67.76, + "Close": 68.5 + }, + { + "Date": "2024-03-21", + "Open": 68.5, + "High": 69.79, + "Low": 67.89, + "Close": 69.43 + }, + { + "Date": "2024-03-22", + "Open": 69.43, + "High": 72.54, + "Low": 68.7, + "Close": 71.11 + }, + { + "Date": "2024-03-23", + "Open": 71.11, + "High": 71.48, + "Low": 70.23, + "Close": 71.28 + }, + { + "Date": "2024-03-24", + "Open": 71.28, + "High": 71.98, + "Low": 70.16, + "Close": 70.67 + }, + { + "Date": "2024-03-25", + "Open": 70.67, + "High": 71.06, + "Low": 68.8, + "Close": 69.65 + }, + { + "Date": "2024-03-26", + "Open": 69.65, + "High": 70.01, + "Low": 67.23, + "Close": 68.69 + }, + { + "Date": "2024-03-27", + "Open": 68.69, + "High": 70.15, + "Low": 68.38, + "Close": 68.83 + }, + { + "Date": "2024-03-28", + "Open": 68.83, + "High": 69.66, + "Low": 68.25, + "Close": 68.84 + }, + { + "Date": "2024-03-29", + "Open": 68.84, + "High": 70.32, + "Low": 67.35, + "Close": 68.07 + }, + { + "Date": "2024-03-30", + "Open": 68.07, + "High": 69.82, + "Low": 65.67, + "Close": 66.86 + }, + { + "Date": "2024-03-31", + "Open": 66.86, + "High": 68.7, + "Low": 65.53, + "Close": 67.45 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/candlestick-chart/02-card20.flint.json b/test-harness/excel/evaluations/inputs/candlestick-chart/02-card20.flint.json new file mode 100644 index 00000000..35e392a0 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/candlestick-chart/02-card20.flint.json @@ -0,0 +1,167 @@ +{ + "semantic_types": { + "Date": "Date", + "Open": "Quantity", + "High": "Quantity", + "Low": "Quantity", + "Close": "Quantity" + }, + "chart_spec": { + "chartType": "Candlestick Chart", + "encodings": { + "x": "Date", + "open": "Open", + "high": "High", + "low": "Low", + "close": "Close" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Date": "2024-01-02", + "Open": 3, + "High": 4.6, + "Low": 2, + "Close": 4.19 + }, + { + "Date": "2024-01-03", + "Open": 4.19, + "High": 7.25, + "Low": 2.28, + "Close": 5.59 + }, + { + "Date": "2024-01-04", + "Open": 5.59, + "High": 6.75, + "Low": 4.01, + "Close": 4.8 + }, + { + "Date": "2024-01-05", + "Open": 4.8, + "High": 6.63, + "Low": 2.87, + "Close": 5.99 + }, + { + "Date": "2024-01-06", + "Open": 5.99, + "High": 7.95, + "Low": 3.64, + "Close": 5.06 + }, + { + "Date": "2024-01-07", + "Open": 5.06, + "High": 6.42, + "Low": 3.45, + "Close": 5.55 + }, + { + "Date": "2024-01-08", + "Open": 5.55, + "High": 5.8, + "Low": 2.92, + "Close": 4.83 + }, + { + "Date": "2024-01-09", + "Open": 4.83, + "High": 7.56, + "Low": 4.49, + "Close": 6.49 + }, + { + "Date": "2024-01-10", + "Open": 6.49, + "High": 7.13, + "Low": 4.68, + "Close": 7.05 + }, + { + "Date": "2024-01-11", + "Open": 7.05, + "High": 10.66, + "Low": 6.78, + "Close": 8.81 + }, + { + "Date": "2024-01-12", + "Open": 8.81, + "High": 10.95, + "Low": 7.6, + "Close": 10.26 + }, + { + "Date": "2024-01-13", + "Open": 10.26, + "High": 11.36, + "Low": 7.33, + "Close": 8.44 + }, + { + "Date": "2024-01-14", + "Open": 8.44, + "High": 10.19, + "Low": 7.95, + "Close": 8.55 + }, + { + "Date": "2024-01-15", + "Open": 8.55, + "High": 9.51, + "Low": 5.73, + "Close": 6.77 + }, + { + "Date": "2024-01-16", + "Open": 6.77, + "High": 8.48, + "Low": 3.79, + "Close": 5.25 + }, + { + "Date": "2024-01-17", + "Open": 5.25, + "High": 5.52, + "Low": 3.8, + "Close": 4.43 + }, + { + "Date": "2024-01-18", + "Open": 4.43, + "High": 7.02, + "Low": 2.67, + "Close": 5.7 + }, + { + "Date": "2024-01-19", + "Open": 5.7, + "High": 8.03, + "Low": 5.53, + "Close": 6.21 + }, + { + "Date": "2024-01-20", + "Open": 6.21, + "High": 7.92, + "Low": 6, + "Close": 6.89 + }, + { + "Date": "2024-01-21", + "Open": 6.89, + "High": 8.04, + "Low": 5.67, + "Close": 6.01 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/connected-scatter-plot/00-card9.flint.json b/test-harness/excel/evaluations/inputs/connected-scatter-plot/00-card9.flint.json new file mode 100644 index 00000000..357f80b9 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/connected-scatter-plot/00-card9.flint.json @@ -0,0 +1,73 @@ +{ + "semantic_types": { + "Unemployment Rate": "Quantity", + "Inflation Rate": "Quantity", + "Year": "Year" + }, + "chart_spec": { + "chartType": "Connected Scatter Plot", + "encodings": { + "x": "Unemployment Rate", + "y": "Inflation Rate", + "order": "Year" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Year": 2014, + "Unemployment Rate": 6.2, + "Inflation Rate": 1.6 + }, + { + "Year": 2015, + "Unemployment Rate": 5.3, + "Inflation Rate": 0.1 + }, + { + "Year": 2016, + "Unemployment Rate": 4.9, + "Inflation Rate": 1.3 + }, + { + "Year": 2017, + "Unemployment Rate": 4.4, + "Inflation Rate": 2.1 + }, + { + "Year": 2018, + "Unemployment Rate": 3.9, + "Inflation Rate": 2.4 + }, + { + "Year": 2019, + "Unemployment Rate": 3.7, + "Inflation Rate": 1.8 + }, + { + "Year": 2020, + "Unemployment Rate": 8.1, + "Inflation Rate": 1.2 + }, + { + "Year": 2021, + "Unemployment Rate": 5.4, + "Inflation Rate": 4.7 + }, + { + "Year": 2022, + "Unemployment Rate": 3.6, + "Inflation Rate": 8 + }, + { + "Year": 2023, + "Unemployment Rate": 3.7, + "Inflation Rate": 4.1 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/connected-scatter-plot/01-card21.flint.json b/test-harness/excel/evaluations/inputs/connected-scatter-plot/01-card21.flint.json new file mode 100644 index 00000000..6843ada9 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/connected-scatter-plot/01-card21.flint.json @@ -0,0 +1,169 @@ +{ + "semantic_types": { + "GDP Growth": "Quantity", + "Inflation": "Quantity", + "Year": "Year", + "Country": "Country" + }, + "chart_spec": { + "chartType": "Connected Scatter Plot", + "encodings": { + "x": "GDP Growth", + "y": "Inflation", + "order": "Year", + "color": "Country" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Country": "USA", + "Year": 2016, + "GDP Growth": 1.7, + "Inflation": 1.3 + }, + { + "Country": "USA", + "Year": 2017, + "GDP Growth": 2.3, + "Inflation": 2.1 + }, + { + "Country": "USA", + "Year": 2018, + "GDP Growth": 2.9, + "Inflation": 2.4 + }, + { + "Country": "USA", + "Year": 2019, + "GDP Growth": 2.3, + "Inflation": 1.8 + }, + { + "Country": "USA", + "Year": 2020, + "GDP Growth": -3.4, + "Inflation": 1.2 + }, + { + "Country": "USA", + "Year": 2021, + "GDP Growth": 5.9, + "Inflation": 4.7 + }, + { + "Country": "USA", + "Year": 2022, + "GDP Growth": 2.1, + "Inflation": 8 + }, + { + "Country": "USA", + "Year": 2023, + "GDP Growth": 2.5, + "Inflation": 4.1 + }, + { + "Country": "China", + "Year": 2016, + "GDP Growth": 6.8, + "Inflation": 2 + }, + { + "Country": "China", + "Year": 2017, + "GDP Growth": 6.9, + "Inflation": 1.6 + }, + { + "Country": "China", + "Year": 2018, + "GDP Growth": 6.7, + "Inflation": 2.1 + }, + { + "Country": "China", + "Year": 2019, + "GDP Growth": 6, + "Inflation": 2.9 + }, + { + "Country": "China", + "Year": 2020, + "GDP Growth": 2.2, + "Inflation": 2.4 + }, + { + "Country": "China", + "Year": 2021, + "GDP Growth": 8.4, + "Inflation": 0.9 + }, + { + "Country": "China", + "Year": 2022, + "GDP Growth": 3, + "Inflation": 2 + }, + { + "Country": "China", + "Year": 2023, + "GDP Growth": 5.2, + "Inflation": 0.2 + }, + { + "Country": "Japan", + "Year": 2016, + "GDP Growth": 0.8, + "Inflation": -0.1 + }, + { + "Country": "Japan", + "Year": 2017, + "GDP Growth": 1.7, + "Inflation": 0.5 + }, + { + "Country": "Japan", + "Year": 2018, + "GDP Growth": 0.6, + "Inflation": 1 + }, + { + "Country": "Japan", + "Year": 2019, + "GDP Growth": -0.4, + "Inflation": 0.5 + }, + { + "Country": "Japan", + "Year": 2020, + "GDP Growth": -4.3, + "Inflation": 0 + }, + { + "Country": "Japan", + "Year": 2021, + "GDP Growth": 2.1, + "Inflation": -0.2 + }, + { + "Country": "Japan", + "Year": 2022, + "GDP Growth": 1, + "Inflation": 2.5 + }, + { + "Country": "Japan", + "Year": 2023, + "GDP Growth": 1.9, + "Inflation": 3.3 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/connected-scatter-plot/02-card12.flint.json b/test-harness/excel/evaluations/inputs/connected-scatter-plot/02-card12.flint.json new file mode 100644 index 00000000..7166f1d1 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/connected-scatter-plot/02-card12.flint.json @@ -0,0 +1,83 @@ +{ + "semantic_types": { + "Trade Volume": "Quantity", + "Share Price": "Quantity", + "Date": "Date" + }, + "chart_spec": { + "chartType": "Connected Scatter Plot", + "encodings": { + "x": "Trade Volume", + "y": "Share Price", + "order": "Date" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Date": "2023-01-03", + "Trade Volume": 58, + "Share Price": 142 + }, + { + "Date": "2023-02-01", + "Trade Volume": 47, + "Share Price": 151 + }, + { + "Date": "2023-03-01", + "Trade Volume": 63, + "Share Price": 148 + }, + { + "Date": "2023-04-03", + "Trade Volume": 41, + "Share Price": 165 + }, + { + "Date": "2023-05-01", + "Trade Volume": 38, + "Share Price": 172 + }, + { + "Date": "2023-06-01", + "Trade Volume": 52, + "Share Price": 180 + }, + { + "Date": "2023-07-03", + "Trade Volume": 35, + "Share Price": 193 + }, + { + "Date": "2023-08-01", + "Trade Volume": 44, + "Share Price": 188 + }, + { + "Date": "2023-09-01", + "Trade Volume": 71, + "Share Price": 171 + }, + { + "Date": "2023-10-02", + "Trade Volume": 66, + "Share Price": 170 + }, + { + "Date": "2023-11-01", + "Trade Volume": 49, + "Share Price": 189 + }, + { + "Date": "2023-12-01", + "Trade Volume": 40, + "Share Price": 192 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/connected-scatter-plot/03-card12.flint.json b/test-harness/excel/evaluations/inputs/connected-scatter-plot/03-card12.flint.json new file mode 100644 index 00000000..f9b5db86 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/connected-scatter-plot/03-card12.flint.json @@ -0,0 +1,143 @@ +{ + "semantic_types": { + "Signal A": "Quantity", + "Signal B": "Quantity", + "Step": "Quantity" + }, + "chart_spec": { + "chartType": "Connected Scatter Plot", + "encodings": { + "x": "Signal A", + "y": "Signal B", + "order": "Step" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Step": 0, + "Signal A": 90, + "Signal B": 50 + }, + { + "Step": 1, + "Signal A": 88.5, + "Signal B": 60.4 + }, + { + "Step": 2, + "Signal A": 84.2, + "Signal B": 67.8 + }, + { + "Step": 3, + "Signal A": 77.3, + "Signal B": 70 + }, + { + "Step": 4, + "Signal A": 68.4, + "Signal B": 66.3 + }, + { + "Step": 5, + "Signal A": 58.1, + "Signal B": 58 + }, + { + "Step": 6, + "Signal A": 47.3, + "Signal B": 47.3 + }, + { + "Step": 7, + "Signal A": 36.6, + "Signal B": 37.4 + }, + { + "Step": 8, + "Signal A": 26.9, + "Signal B": 31.2 + }, + { + "Step": 9, + "Signal A": 19, + "Signal B": 30.4 + }, + { + "Step": 10, + "Signal A": 13.3, + "Signal B": 35.4 + }, + { + "Step": 11, + "Signal A": 10.4, + "Signal B": 44.6 + }, + { + "Step": 12, + "Signal A": 10.4, + "Signal B": 55.4 + }, + { + "Step": 13, + "Signal A": 13.3, + "Signal B": 64.6 + }, + { + "Step": 14, + "Signal A": 19, + "Signal B": 69.6 + }, + { + "Step": 15, + "Signal A": 26.9, + "Signal B": 68.8 + }, + { + "Step": 16, + "Signal A": 36.6, + "Signal B": 62.6 + }, + { + "Step": 17, + "Signal A": 47.3, + "Signal B": 52.7 + }, + { + "Step": 18, + "Signal A": 58.1, + "Signal B": 42 + }, + { + "Step": 19, + "Signal A": 68.4, + "Signal B": 33.7 + }, + { + "Step": 20, + "Signal A": 77.3, + "Signal B": 30 + }, + { + "Step": 21, + "Signal A": 84.2, + "Signal B": 32.2 + }, + { + "Step": 22, + "Signal A": 88.5, + "Signal B": 39.6 + }, + { + "Step": 23, + "Signal A": 90, + "Signal B": 50 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/connected-scatter-plot/04-card15.flint.json b/test-harness/excel/evaluations/inputs/connected-scatter-plot/04-card15.flint.json new file mode 100644 index 00000000..b585a0b1 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/connected-scatter-plot/04-card15.flint.json @@ -0,0 +1,121 @@ +{ + "semantic_types": { + "Temperature": "Quantity", + "Pressure": "Quantity", + "Step": "Quantity", + "Experiment": "Category" + }, + "chart_spec": { + "chartType": "Connected Scatter Plot", + "encodings": { + "x": "Temperature", + "y": "Pressure", + "order": "Step", + "color": "Experiment" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Experiment": "Trial A", + "Step": 1, + "Temperature": 20, + "Pressure": 1 + }, + { + "Experiment": "Trial A", + "Step": 2, + "Temperature": 35, + "Pressure": 1.4 + }, + { + "Experiment": "Trial A", + "Step": 3, + "Temperature": 55, + "Pressure": 2.1 + }, + { + "Experiment": "Trial A", + "Step": 4, + "Temperature": 70, + "Pressure": 3 + }, + { + "Experiment": "Trial A", + "Step": 5, + "Temperature": 60, + "Pressure": 2.6 + }, + { + "Experiment": "Trial A", + "Step": 6, + "Temperature": 45, + "Pressure": 1.9 + }, + { + "Experiment": "Trial A", + "Step": 7, + "Temperature": 30, + "Pressure": 1.3 + }, + { + "Experiment": "Trial A", + "Step": 8, + "Temperature": 22, + "Pressure": 1.05 + }, + { + "Experiment": "Trial B", + "Step": 1, + "Temperature": 25, + "Pressure": 1.1 + }, + { + "Experiment": "Trial B", + "Step": 2, + "Temperature": 30, + "Pressure": 1.2 + }, + { + "Experiment": "Trial B", + "Step": 3, + "Temperature": 48, + "Pressure": 1.8 + }, + { + "Experiment": "Trial B", + "Step": 4, + "Temperature": 68, + "Pressure": 2.7 + }, + { + "Experiment": "Trial B", + "Step": 5, + "Temperature": 80, + "Pressure": 3.4 + }, + { + "Experiment": "Trial B", + "Step": 6, + "Temperature": 62, + "Pressure": 2.4 + }, + { + "Experiment": "Trial B", + "Step": 7, + "Temperature": 40, + "Pressure": 1.5 + }, + { + "Experiment": "Trial B", + "Step": 8, + "Temperature": 28, + "Pressure": 1.15 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/connected-scatter-plot/05-card4.flint.json b/test-harness/excel/evaluations/inputs/connected-scatter-plot/05-card4.flint.json new file mode 100644 index 00000000..7f187ede --- /dev/null +++ b/test-harness/excel/evaluations/inputs/connected-scatter-plot/05-card4.flint.json @@ -0,0 +1,43 @@ +{ + "semantic_types": { + "Cost": "Quantity", + "Revenue": "Quantity", + "Quarter": "Quantity" + }, + "chart_spec": { + "chartType": "Connected Scatter Plot", + "encodings": { + "x": "Cost", + "y": "Revenue", + "order": "Quarter" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Quarter": 1, + "Cost": 12, + "Revenue": 18 + }, + { + "Quarter": 2, + "Cost": 20, + "Revenue": 26 + }, + { + "Quarter": 3, + "Cost": 17, + "Revenue": 35 + }, + { + "Quarter": 4, + "Cost": 24, + "Revenue": 30 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/connected-scatter-plot/06-card35.flint.json b/test-harness/excel/evaluations/inputs/connected-scatter-plot/06-card35.flint.json new file mode 100644 index 00000000..ea2d93c4 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/connected-scatter-plot/06-card35.flint.json @@ -0,0 +1,203 @@ +{ + "semantic_types": { + "X Position": "Quantity", + "Y Position": "Quantity", + "Step": "Quantity" + }, + "chart_spec": { + "chartType": "Connected Scatter Plot", + "encodings": { + "x": "X Position", + "y": "Y Position", + "order": "Step" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Step": 0, + "X Position": 68.1, + "Y Position": 60 + }, + { + "Step": 1, + "X Position": 72.6, + "Y Position": 62 + }, + { + "Step": 2, + "X Position": 70.9, + "Y Position": 67.2 + }, + { + "Step": 3, + "X Position": 69.5, + "Y Position": 70.2 + }, + { + "Step": 4, + "X Position": 66.8, + "Y Position": 75.2 + }, + { + "Step": 5, + "X Position": 65.9, + "Y Position": 76.9 + }, + { + "Step": 6, + "X Position": 59.3, + "Y Position": 77.8 + }, + { + "Step": 7, + "X Position": 52.7, + "Y Position": 78.9 + }, + { + "Step": 8, + "X Position": 48.4, + "Y Position": 79.4 + }, + { + "Step": 9, + "X Position": 42.8, + "Y Position": 75.7 + }, + { + "Step": 10, + "X Position": 37.9, + "Y Position": 70.9 + }, + { + "Step": 11, + "X Position": 31.9, + "Y Position": 63.2 + }, + { + "Step": 12, + "X Position": 30.3, + "Y Position": 57.6 + }, + { + "Step": 13, + "X Position": 30.4, + "Y Position": 50.5 + }, + { + "Step": 14, + "X Position": 35, + "Y Position": 41.4 + }, + { + "Step": 15, + "X Position": 38, + "Y Position": 32.3 + }, + { + "Step": 16, + "X Position": 46.9, + "Y Position": 25.9 + }, + { + "Step": 17, + "X Position": 54.2, + "Y Position": 21.1 + }, + { + "Step": 18, + "X Position": 66.1, + "Y Position": 21.5 + }, + { + "Step": 19, + "X Position": 77.2, + "Y Position": 21.6 + }, + { + "Step": 20, + "X Position": 86.2, + "Y Position": 27.8 + }, + { + "Step": 21, + "X Position": 93.7, + "Y Position": 33.6 + }, + { + "Step": 22, + "X Position": 104.2, + "Y Position": 43.2 + }, + { + "Step": 23, + "X Position": 107.4, + "Y Position": 55.5 + }, + { + "Step": 24, + "X Position": 107.7, + "Y Position": 67.3 + }, + { + "Step": 25, + "X Position": 106.7, + "Y Position": 83.2 + }, + { + "Step": 26, + "X Position": 99.8, + "Y Position": 95.8 + }, + { + "Step": 27, + "X Position": 90.8, + "Y Position": 103.8 + }, + { + "Step": 28, + "X Position": 77.7, + "Y Position": 112.7 + }, + { + "Step": 29, + "X Position": 60.8, + "Y Position": 117.2 + }, + { + "Step": 30, + "X Position": 48.4, + "Y Position": 115.2 + }, + { + "Step": 31, + "X Position": 29.8, + "Y Position": 111.9 + }, + { + "Step": 32, + "X Position": 19.5, + "Y Position": 105.4 + }, + { + "Step": 33, + "X Position": 4.9, + "Y Position": 93.5 + }, + { + "Step": 34, + "X Position": -3.4, + "Y Position": 76.8 + }, + { + "Step": 35, + "X Position": -6.3, + "Y Position": 59.1 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/connected-scatter-plot/07-card24.flint.json b/test-harness/excel/evaluations/inputs/connected-scatter-plot/07-card24.flint.json new file mode 100644 index 00000000..1976fe43 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/connected-scatter-plot/07-card24.flint.json @@ -0,0 +1,169 @@ +{ + "semantic_types": { + "Drift": "Quantity", + "Noise": "Quantity", + "Step": "Quantity", + "Sensor": "Category" + }, + "chart_spec": { + "chartType": "Connected Scatter Plot", + "encodings": { + "x": "Drift", + "y": "Noise", + "order": "Step", + "detail": "Sensor" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Sensor": "Laptop", + "Step": 1, + "Drift": 19.5, + "Noise": 37.6 + }, + { + "Sensor": "Laptop", + "Step": 2, + "Drift": 29.7, + "Noise": 36.4 + }, + { + "Sensor": "Laptop", + "Step": 3, + "Drift": 36.8, + "Noise": 25.4 + }, + { + "Sensor": "Laptop", + "Step": 4, + "Drift": 38.4, + "Noise": 14.2 + }, + { + "Sensor": "Laptop", + "Step": 5, + "Drift": 29.2, + "Noise": 7.4 + }, + { + "Sensor": "Laptop", + "Step": 6, + "Drift": 18.6, + "Noise": 3.2 + }, + { + "Sensor": "Phone", + "Step": 1, + "Drift": 30.3, + "Noise": 49.8 + }, + { + "Sensor": "Phone", + "Step": 2, + "Drift": 42.9, + "Noise": 47.3 + }, + { + "Sensor": "Phone", + "Step": 3, + "Drift": 50.7, + "Noise": 36.6 + }, + { + "Sensor": "Phone", + "Step": 4, + "Drift": 48.9, + "Noise": 26.9 + }, + { + "Sensor": "Phone", + "Step": 5, + "Drift": 41.2, + "Noise": 19 + }, + { + "Sensor": "Phone", + "Step": 6, + "Drift": 32.4, + "Noise": 15.8 + }, + { + "Sensor": "Tablet", + "Step": 1, + "Drift": 45.5, + "Noise": 63.6 + }, + { + "Sensor": "Tablet", + "Step": 2, + "Drift": 55.1, + "Noise": 58.9 + }, + { + "Sensor": "Tablet", + "Step": 3, + "Drift": 61.4, + "Noise": 47.6 + }, + { + "Sensor": "Tablet", + "Step": 4, + "Drift": 62.7, + "Noise": 37.6 + }, + { + "Sensor": "Tablet", + "Step": 5, + "Drift": 54.3, + "Noise": 28.1 + }, + { + "Sensor": "Tablet", + "Step": 6, + "Drift": 44.7, + "Noise": 27.9 + }, + { + "Sensor": "Desktop", + "Step": 1, + "Drift": 57.2, + "Noise": 75.7 + }, + { + "Sensor": "Desktop", + "Step": 2, + "Drift": 66.8, + "Noise": 68.7 + }, + { + "Sensor": "Desktop", + "Step": 3, + "Drift": 73.5, + "Noise": 62.1 + }, + { + "Sensor": "Desktop", + "Step": 4, + "Drift": 74.9, + "Noise": 52.3 + }, + { + "Sensor": "Desktop", + "Step": 5, + "Drift": 67.3, + "Noise": 39.6 + }, + { + "Sensor": "Desktop", + "Step": 6, + "Drift": 54, + "Noise": 37 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/donut-chart/00-card0.flint.json b/test-harness/excel/evaluations/inputs/donut-chart/00-card0.flint.json new file mode 100644 index 00000000..2f318305 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/donut-chart/00-card0.flint.json @@ -0,0 +1,40 @@ +{ + "semantic_types": { + "Category": "Category", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Donut Chart", + "encodings": { + "size": "Value", + "color": "Category" + }, + "baseSize": { + "width": 560, + "height": 360 + }, + "chartProperties": { + "innerRadius": 50 + } + }, + "data": { + "values": [ + { + "Category": "Electronics", + "Value": 103 + }, + { + "Category": "Clothing", + "Value": 215 + }, + { + "Category": "Food", + "Value": 342 + }, + { + "Category": "Books", + "Value": 560 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/donut-chart/01-card0.flint.json b/test-harness/excel/evaluations/inputs/donut-chart/01-card0.flint.json new file mode 100644 index 00000000..d6ded0b8 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/donut-chart/01-card0.flint.json @@ -0,0 +1,64 @@ +{ + "semantic_types": { + "Product": "Product", + "Revenue": "Amount" + }, + "chart_spec": { + "chartType": "Donut Chart", + "encodings": { + "size": "Revenue", + "color": "Product" + }, + "baseSize": { + "width": 560, + "height": 360 + }, + "chartProperties": { + "innerRadius": 50 + } + }, + "data": { + "values": [ + { + "Product": "Laptop", + "Revenue": 2924 + }, + { + "Product": "Phone", + "Revenue": 2506 + }, + { + "Product": "Tablet", + "Revenue": 6721 + }, + { + "Product": "Desktop", + "Revenue": 1826 + }, + { + "Product": "Monitor", + "Revenue": 4934 + }, + { + "Product": "Keyboard", + "Revenue": 7789 + }, + { + "Product": "Mouse", + "Revenue": 8215 + }, + { + "Product": "Headphones", + "Revenue": 5798 + }, + { + "Product": "Speaker", + "Revenue": 7950 + }, + { + "Product": "Camera", + "Revenue": 6919 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/donut-chart/02-card0.flint.json b/test-harness/excel/evaluations/inputs/donut-chart/02-card0.flint.json new file mode 100644 index 00000000..7abc3480 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/donut-chart/02-card0.flint.json @@ -0,0 +1,104 @@ +{ + "semantic_types": { + "Region": "Category", + "Sales": "Quantity" + }, + "chart_spec": { + "chartType": "Donut Chart", + "encodings": { + "size": "Sales", + "color": "Region" + }, + "baseSize": { + "width": 560, + "height": 360 + }, + "chartProperties": { + "innerRadius": 50 + } + }, + "data": { + "values": [ + { + "Region": "Electronics", + "Sales": 4347 + }, + { + "Region": "Clothing", + "Sales": 4301 + }, + { + "Region": "Food", + "Sales": 5098 + }, + { + "Region": "Books", + "Sales": 1293 + }, + { + "Region": "Sports", + "Sales": 4163 + }, + { + "Region": "Home", + "Sales": 2869 + }, + { + "Region": "Garden", + "Sales": 5444 + }, + { + "Region": "Auto", + "Sales": 2591 + }, + { + "Region": "Health", + "Sales": 1407 + }, + { + "Region": "Beauty", + "Sales": 2246 + }, + { + "Region": "Toys", + "Sales": 5168 + }, + { + "Region": "Music", + "Sales": 3215 + }, + { + "Region": "Movies", + "Sales": 3360 + }, + { + "Region": "Software", + "Sales": 1176 + }, + { + "Region": "Games", + "Sales": 4497 + }, + { + "Region": "Office", + "Sales": 5262 + }, + { + "Region": "Pet", + "Sales": 1783 + }, + { + "Region": "Baby", + "Sales": 4292 + }, + { + "Region": "Tools", + "Sales": 5312 + }, + { + "Region": "Crafts", + "Sales": 5358 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/donut-chart/03-card0.flint.json b/test-harness/excel/evaluations/inputs/donut-chart/03-card0.flint.json new file mode 100644 index 00000000..b79a0a86 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/donut-chart/03-card0.flint.json @@ -0,0 +1,48 @@ +{ + "semantic_types": { + "Category": "Category", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Donut Chart", + "encodings": { + "size": "Value", + "color": "Category" + }, + "baseSize": { + "width": 560, + "height": 360 + }, + "chartProperties": { + "innerRadius": 50 + } + }, + "data": { + "values": [ + { + "Category": "Dominant", + "Value": 5000 + }, + { + "Category": "Small-A", + "Value": 200 + }, + { + "Category": "Small-B", + "Value": 180 + }, + { + "Category": "Small-C", + "Value": 150 + }, + { + "Category": "Tiny-1", + "Value": 30 + }, + { + "Category": "Tiny-2", + "Value": 20 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/funnel-chart/00-card5.flint.json b/test-harness/excel/evaluations/inputs/funnel-chart/00-card5.flint.json new file mode 100644 index 00000000..a560df96 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/funnel-chart/00-card5.flint.json @@ -0,0 +1,41 @@ +{ + "semantic_types": { + "Stage": "Category", + "Count": "Quantity" + }, + "chart_spec": { + "chartType": "Funnel Chart", + "encodings": { + "y": "Stage", + "size": "Count" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Stage": "Visits", + "Count": 10006 + }, + { + "Stage": "Signups", + "Count": 5230 + }, + { + "Stage": "Trials", + "Count": 2984 + }, + { + "Stage": "Purchases", + "Count": 1670 + }, + { + "Stage": "Renewals", + "Count": 839 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/funnel-chart/01-card5.flint.json b/test-harness/excel/evaluations/inputs/funnel-chart/01-card5.flint.json new file mode 100644 index 00000000..23a12323 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/funnel-chart/01-card5.flint.json @@ -0,0 +1,44 @@ +{ + "semantic_types": { + "Step": "Category", + "Candidates": "Quantity" + }, + "chart_spec": { + "chartType": "Funnel Chart", + "encodings": { + "y": "Step", + "size": "Candidates" + }, + "baseSize": { + "width": 560, + "height": 360 + }, + "chartProperties": { + "sort": "ascending" + } + }, + "data": { + "values": [ + { + "Step": "Applied", + "Candidates": 510 + }, + { + "Step": "Screened", + "Candidates": 286 + }, + { + "Step": "Interviewed", + "Candidates": 160 + }, + { + "Step": "Offered", + "Candidates": 112 + }, + { + "Step": "Hired", + "Candidates": 63 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/funnel-chart/02-card8.flint.json b/test-harness/excel/evaluations/inputs/funnel-chart/02-card8.flint.json new file mode 100644 index 00000000..7538c61d --- /dev/null +++ b/test-harness/excel/evaluations/inputs/funnel-chart/02-card8.flint.json @@ -0,0 +1,53 @@ +{ + "semantic_types": { + "Phase": "Category", + "Users": "Quantity" + }, + "chart_spec": { + "chartType": "Funnel Chart", + "encodings": { + "y": "Phase", + "size": "Users" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Phase": "Awareness", + "Users": 50603 + }, + { + "Phase": "Interest", + "Users": 33400 + }, + { + "Phase": "Consideration", + "Users": 22767 + }, + { + "Phase": "Intent", + "Users": 15130 + }, + { + "Phase": "Evaluation", + "Users": 10415 + }, + { + "Phase": "Trial", + "Users": 7105 + }, + { + "Phase": "Purchase", + "Users": 5229 + }, + { + "Phase": "Loyalty", + "Users": 3243 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/grouped-bar-chart/00-card4.flint.json b/test-harness/excel/evaluations/inputs/grouped-bar-chart/00-card4.flint.json new file mode 100644 index 00000000..6553c049 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/grouped-bar-chart/00-card4.flint.json @@ -0,0 +1,83 @@ +{ + "semantic_types": { + "Category": "Category", + "Value": "Quantity", + "Segment": "Category" + }, + "chart_spec": { + "chartType": "Grouped Bar Chart", + "encodings": { + "x": "Category", + "y": "Value", + "group": "Segment" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Laptop", + "Value": 12, + "Segment": "USA" + }, + { + "Category": "Laptop", + "Value": 467, + "Segment": "China" + }, + { + "Category": "Laptop", + "Value": 685, + "Segment": "Japan" + }, + { + "Category": "Phone", + "Value": 599, + "Segment": "USA" + }, + { + "Category": "Phone", + "Value": 832, + "Segment": "China" + }, + { + "Category": "Phone", + "Value": 691, + "Segment": "Japan" + }, + { + "Category": "Tablet", + "Value": 122, + "Segment": "USA" + }, + { + "Category": "Tablet", + "Value": 663, + "Segment": "China" + }, + { + "Category": "Tablet", + "Value": 791, + "Segment": "Japan" + }, + { + "Category": "Desktop", + "Value": 414, + "Segment": "USA" + }, + { + "Category": "Desktop", + "Value": 60, + "Segment": "China" + }, + { + "Category": "Desktop", + "Value": 827, + "Segment": "Japan" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/grouped-bar-chart/01-card8.flint.json b/test-harness/excel/evaluations/inputs/grouped-bar-chart/01-card8.flint.json new file mode 100644 index 00000000..eae3bab3 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/grouped-bar-chart/01-card8.flint.json @@ -0,0 +1,53 @@ +{ + "semantic_types": { + "Category": "Category", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Grouped Bar Chart", + "encodings": { + "x": "Category", + "y": "Value" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Laptop", + "Value": 297 + }, + { + "Category": "Phone", + "Value": 378 + }, + { + "Category": "Tablet", + "Value": 48 + }, + { + "Category": "Desktop", + "Value": 911 + }, + { + "Category": "Monitor", + "Value": 351 + }, + { + "Category": "Keyboard", + "Value": 316 + }, + { + "Category": "Mouse", + "Value": 34 + }, + { + "Category": "Headphones", + "Value": 62 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/grouped-bar-chart/02-card90.flint.json b/test-harness/excel/evaluations/inputs/grouped-bar-chart/02-card90.flint.json new file mode 100644 index 00000000..3fefd6c5 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/grouped-bar-chart/02-card90.flint.json @@ -0,0 +1,1373 @@ +{ + "semantic_types": { + "Category": "Category", + "Value": "Quantity", + "Segment": "Category" + }, + "chart_spec": { + "chartType": "Grouped Bar Chart", + "encodings": { + "x": "Category", + "y": "Value", + "group": "Segment" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "James Walker", + "Value": 253, + "Segment": "USA" + }, + { + "Category": "James Walker", + "Value": 41, + "Segment": "China" + }, + { + "Category": "James Walker", + "Value": 696, + "Segment": "Japan" + }, + { + "Category": "Paul Wilson", + "Value": 140, + "Segment": "USA" + }, + { + "Category": "Paul Wilson", + "Value": 852, + "Segment": "China" + }, + { + "Category": "Paul Wilson", + "Value": 88, + "Segment": "Japan" + }, + { + "Category": "Jessica Martin", + "Value": 594, + "Segment": "USA" + }, + { + "Category": "Jessica Martin", + "Value": 184, + "Segment": "China" + }, + { + "Category": "Jessica Martin", + "Value": 802, + "Segment": "Japan" + }, + { + "Category": "Christopher Moore", + "Value": 364, + "Segment": "USA" + }, + { + "Category": "Christopher Moore", + "Value": 105, + "Segment": "China" + }, + { + "Category": "Christopher Moore", + "Value": 663, + "Segment": "Japan" + }, + { + "Category": "Betty Wilson", + "Value": 739, + "Segment": "USA" + }, + { + "Category": "Betty Wilson", + "Value": 247, + "Segment": "China" + }, + { + "Category": "Betty Wilson", + "Value": 826, + "Segment": "Japan" + }, + { + "Category": "Steven Lewis", + "Value": 476, + "Segment": "USA" + }, + { + "Category": "Steven Lewis", + "Value": 794, + "Segment": "China" + }, + { + "Category": "Steven Lewis", + "Value": 924, + "Segment": "Japan" + }, + { + "Category": "Karen Lopez", + "Value": 318, + "Segment": "USA" + }, + { + "Category": "Karen Lopez", + "Value": 606, + "Segment": "China" + }, + { + "Category": "Karen Lopez", + "Value": 121, + "Segment": "Japan" + }, + { + "Category": "Sandra Wright", + "Value": 767, + "Segment": "USA" + }, + { + "Category": "Sandra Wright", + "Value": 800, + "Segment": "China" + }, + { + "Category": "Sandra Wright", + "Value": 17, + "Segment": "Japan" + }, + { + "Category": "Daniel King", + "Value": 461, + "Segment": "USA" + }, + { + "Category": "Daniel King", + "Value": 808, + "Segment": "China" + }, + { + "Category": "Daniel King", + "Value": 496, + "Segment": "Japan" + }, + { + "Category": "Mark Taylor", + "Value": 418, + "Segment": "USA" + }, + { + "Category": "Mark Taylor", + "Value": 815, + "Segment": "China" + }, + { + "Category": "Mark Taylor", + "Value": 924, + "Segment": "Japan" + }, + { + "Category": "Sandra Thomas", + "Value": 949, + "Segment": "USA" + }, + { + "Category": "Sandra Thomas", + "Value": 326, + "Segment": "China" + }, + { + "Category": "Sandra Thomas", + "Value": 339, + "Segment": "Japan" + }, + { + "Category": "Karen Rodriguez", + "Value": 477, + "Segment": "USA" + }, + { + "Category": "Karen Rodriguez", + "Value": 782, + "Segment": "China" + }, + { + "Category": "Karen Rodriguez", + "Value": 953, + "Segment": "Japan" + }, + { + "Category": "Patricia Jackson", + "Value": 956, + "Segment": "USA" + }, + { + "Category": "Patricia Jackson", + "Value": 304, + "Segment": "China" + }, + { + "Category": "Patricia Jackson", + "Value": 765, + "Segment": "Japan" + }, + { + "Category": "Donna Hill", + "Value": 178, + "Segment": "USA" + }, + { + "Category": "Donna Hill", + "Value": 402, + "Segment": "China" + }, + { + "Category": "Donna Hill", + "Value": 363, + "Segment": "Japan" + }, + { + "Category": "Donna White", + "Value": 889, + "Segment": "USA" + }, + { + "Category": "Donna White", + "Value": 713, + "Segment": "China" + }, + { + "Category": "Donna White", + "Value": 993, + "Segment": "Japan" + }, + { + "Category": "Michael Brown", + "Value": 201, + "Segment": "USA" + }, + { + "Category": "Michael Brown", + "Value": 845, + "Segment": "China" + }, + { + "Category": "Michael Brown", + "Value": 228, + "Segment": "Japan" + }, + { + "Category": "Elizabeth Robinson", + "Value": 336, + "Segment": "USA" + }, + { + "Category": "Elizabeth Robinson", + "Value": 133, + "Segment": "China" + }, + { + "Category": "Elizabeth Robinson", + "Value": 220, + "Segment": "Japan" + }, + { + "Category": "Mary Jones", + "Value": 250, + "Segment": "USA" + }, + { + "Category": "Mary Jones", + "Value": 133, + "Segment": "China" + }, + { + "Category": "Mary Jones", + "Value": 154, + "Segment": "Japan" + }, + { + "Category": "Richard Rodriguez", + "Value": 925, + "Segment": "USA" + }, + { + "Category": "Richard Rodriguez", + "Value": 340, + "Segment": "China" + }, + { + "Category": "Richard Rodriguez", + "Value": 301, + "Segment": "Japan" + }, + { + "Category": "Christopher Clark", + "Value": 35, + "Segment": "USA" + }, + { + "Category": "Christopher Clark", + "Value": 460, + "Segment": "China" + }, + { + "Category": "Christopher Clark", + "Value": 71, + "Segment": "Japan" + }, + { + "Category": "Christopher Lopez", + "Value": 352, + "Segment": "USA" + }, + { + "Category": "Christopher Lopez", + "Value": 614, + "Segment": "China" + }, + { + "Category": "Christopher Lopez", + "Value": 763, + "Segment": "Japan" + }, + { + "Category": "Susan Ramirez", + "Value": 541, + "Segment": "USA" + }, + { + "Category": "Susan Ramirez", + "Value": 479, + "Segment": "China" + }, + { + "Category": "Susan Ramirez", + "Value": 864, + "Segment": "Japan" + }, + { + "Category": "Steven Wilson", + "Value": 869, + "Segment": "USA" + }, + { + "Category": "Steven Wilson", + "Value": 627, + "Segment": "China" + }, + { + "Category": "Steven Wilson", + "Value": 839, + "Segment": "Japan" + }, + { + "Category": "Paul Anderson", + "Value": 576, + "Segment": "USA" + }, + { + "Category": "Paul Anderson", + "Value": 959, + "Segment": "China" + }, + { + "Category": "Paul Anderson", + "Value": 898, + "Segment": "Japan" + }, + { + "Category": "Joseph Rodriguez", + "Value": 312, + "Segment": "USA" + }, + { + "Category": "Joseph Rodriguez", + "Value": 982, + "Segment": "China" + }, + { + "Category": "Joseph Rodriguez", + "Value": 341, + "Segment": "Japan" + }, + { + "Category": "Elizabeth Wright", + "Value": 797, + "Segment": "USA" + }, + { + "Category": "Elizabeth Wright", + "Value": 628, + "Segment": "China" + }, + { + "Category": "Elizabeth Wright", + "Value": 459, + "Segment": "Japan" + }, + { + "Category": "Kimberly Jackson", + "Value": 797, + "Segment": "USA" + }, + { + "Category": "Kimberly Jackson", + "Value": 622, + "Segment": "China" + }, + { + "Category": "Kimberly Jackson", + "Value": 199, + "Segment": "Japan" + }, + { + "Category": "Betty Hernandez", + "Value": 381, + "Segment": "USA" + }, + { + "Category": "Betty Hernandez", + "Value": 172, + "Segment": "China" + }, + { + "Category": "Betty Hernandez", + "Value": 503, + "Segment": "Japan" + }, + { + "Category": "David King", + "Value": 125, + "Segment": "USA" + }, + { + "Category": "David King", + "Value": 501, + "Segment": "China" + }, + { + "Category": "David King", + "Value": 725, + "Segment": "Japan" + }, + { + "Category": "Matthew Lopez", + "Value": 917, + "Segment": "USA" + }, + { + "Category": "Matthew Lopez", + "Value": 342, + "Segment": "China" + }, + { + "Category": "Matthew Lopez", + "Value": 549, + "Segment": "Japan" + }, + { + "Category": "Susan Hernandez", + "Value": 612, + "Segment": "USA" + }, + { + "Category": "Susan Hernandez", + "Value": 493, + "Segment": "China" + }, + { + "Category": "Susan Hernandez", + "Value": 381, + "Segment": "Japan" + }, + { + "Category": "Jennifer Lee", + "Value": 229, + "Segment": "USA" + }, + { + "Category": "Jennifer Lee", + "Value": 460, + "Segment": "China" + }, + { + "Category": "Jennifer Lee", + "Value": 616, + "Segment": "Japan" + }, + { + "Category": "Richard Flores", + "Value": 931, + "Segment": "USA" + }, + { + "Category": "Richard Flores", + "Value": 827, + "Segment": "China" + }, + { + "Category": "Richard Flores", + "Value": 419, + "Segment": "Japan" + }, + { + "Category": "John Anderson", + "Value": 137, + "Segment": "USA" + }, + { + "Category": "John Anderson", + "Value": 304, + "Segment": "China" + }, + { + "Category": "John Anderson", + "Value": 383, + "Segment": "Japan" + }, + { + "Category": "Kimberly Wright", + "Value": 901, + "Segment": "USA" + }, + { + "Category": "Kimberly Wright", + "Value": 295, + "Segment": "China" + }, + { + "Category": "Kimberly Wright", + "Value": 72, + "Segment": "Japan" + }, + { + "Category": "Joseph Williams", + "Value": 946, + "Segment": "USA" + }, + { + "Category": "Joseph Williams", + "Value": 375, + "Segment": "China" + }, + { + "Category": "Joseph Williams", + "Value": 974, + "Segment": "Japan" + }, + { + "Category": "Lisa Torres", + "Value": 276, + "Segment": "USA" + }, + { + "Category": "Lisa Torres", + "Value": 269, + "Segment": "China" + }, + { + "Category": "Lisa Torres", + "Value": 106, + "Segment": "Japan" + }, + { + "Category": "Andrew Rodriguez", + "Value": 621, + "Segment": "USA" + }, + { + "Category": "Andrew Rodriguez", + "Value": 110, + "Segment": "China" + }, + { + "Category": "Andrew Rodriguez", + "Value": 410, + "Segment": "Japan" + }, + { + "Category": "Karen Johnson", + "Value": 747, + "Segment": "USA" + }, + { + "Category": "Karen Johnson", + "Value": 324, + "Segment": "China" + }, + { + "Category": "Karen Johnson", + "Value": 923, + "Segment": "Japan" + }, + { + "Category": "Steven Jones", + "Value": 267, + "Segment": "USA" + }, + { + "Category": "Steven Jones", + "Value": 164, + "Segment": "China" + }, + { + "Category": "Steven Jones", + "Value": 676, + "Segment": "Japan" + }, + { + "Category": "Joshua Ramirez", + "Value": 42, + "Segment": "USA" + }, + { + "Category": "Joshua Ramirez", + "Value": 626, + "Segment": "China" + }, + { + "Category": "Joshua Ramirez", + "Value": 845, + "Segment": "Japan" + }, + { + "Category": "Emily Martinez", + "Value": 451, + "Segment": "USA" + }, + { + "Category": "Emily Martinez", + "Value": 992, + "Segment": "China" + }, + { + "Category": "Emily Martinez", + "Value": 634, + "Segment": "Japan" + }, + { + "Category": "Robert Walker", + "Value": 550, + "Segment": "USA" + }, + { + "Category": "Robert Walker", + "Value": 475, + "Segment": "China" + }, + { + "Category": "Robert Walker", + "Value": 642, + "Segment": "Japan" + }, + { + "Category": "Robert Lewis", + "Value": 559, + "Segment": "USA" + }, + { + "Category": "Robert Lewis", + "Value": 217, + "Segment": "China" + }, + { + "Category": "Robert Lewis", + "Value": 335, + "Segment": "Japan" + }, + { + "Category": "Sandra Lopez", + "Value": 811, + "Segment": "USA" + }, + { + "Category": "Sandra Lopez", + "Value": 928, + "Segment": "China" + }, + { + "Category": "Sandra Lopez", + "Value": 777, + "Segment": "Japan" + }, + { + "Category": "Nancy Miller", + "Value": 783, + "Segment": "USA" + }, + { + "Category": "Nancy Miller", + "Value": 24, + "Segment": "China" + }, + { + "Category": "Nancy Miller", + "Value": 382, + "Segment": "Japan" + }, + { + "Category": "Christopher Sanchez", + "Value": 495, + "Segment": "USA" + }, + { + "Category": "Christopher Sanchez", + "Value": 923, + "Segment": "China" + }, + { + "Category": "Christopher Sanchez", + "Value": 359, + "Segment": "Japan" + }, + { + "Category": "Daniel Flores", + "Value": 930, + "Segment": "USA" + }, + { + "Category": "Daniel Flores", + "Value": 796, + "Segment": "China" + }, + { + "Category": "Daniel Flores", + "Value": 975, + "Segment": "Japan" + }, + { + "Category": "Mary Walker", + "Value": 517, + "Segment": "USA" + }, + { + "Category": "Mary Walker", + "Value": 507, + "Segment": "China" + }, + { + "Category": "Mary Walker", + "Value": 950, + "Segment": "Japan" + }, + { + "Category": "Anthony Ramirez", + "Value": 610, + "Segment": "USA" + }, + { + "Category": "Anthony Ramirez", + "Value": 254, + "Segment": "China" + }, + { + "Category": "Anthony Ramirez", + "Value": 103, + "Segment": "Japan" + }, + { + "Category": "Anthony Hill", + "Value": 363, + "Segment": "USA" + }, + { + "Category": "Anthony Hill", + "Value": 698, + "Segment": "China" + }, + { + "Category": "Anthony Hill", + "Value": 656, + "Segment": "Japan" + }, + { + "Category": "Matthew Miller", + "Value": 663, + "Segment": "USA" + }, + { + "Category": "Matthew Miller", + "Value": 326, + "Segment": "China" + }, + { + "Category": "Matthew Miller", + "Value": 606, + "Segment": "Japan" + }, + { + "Category": "Andrew King", + "Value": 918, + "Segment": "USA" + }, + { + "Category": "Andrew King", + "Value": 537, + "Segment": "China" + }, + { + "Category": "Andrew King", + "Value": 946, + "Segment": "Japan" + }, + { + "Category": "William Perez", + "Value": 596, + "Segment": "USA" + }, + { + "Category": "William Perez", + "Value": 859, + "Segment": "China" + }, + { + "Category": "William Perez", + "Value": 693, + "Segment": "Japan" + }, + { + "Category": "William Martinez", + "Value": 687, + "Segment": "USA" + }, + { + "Category": "William Martinez", + "Value": 507, + "Segment": "China" + }, + { + "Category": "William Martinez", + "Value": 499, + "Segment": "Japan" + }, + { + "Category": "Margaret Garcia", + "Value": 579, + "Segment": "USA" + }, + { + "Category": "Margaret Garcia", + "Value": 879, + "Segment": "China" + }, + { + "Category": "Margaret Garcia", + "Value": 680, + "Segment": "Japan" + }, + { + "Category": "Barbara Anderson", + "Value": 47, + "Segment": "USA" + }, + { + "Category": "Barbara Anderson", + "Value": 265, + "Segment": "China" + }, + { + "Category": "Barbara Anderson", + "Value": 385, + "Segment": "Japan" + }, + { + "Category": "Thomas Smith", + "Value": 789, + "Segment": "USA" + }, + { + "Category": "Thomas Smith", + "Value": 127, + "Segment": "China" + }, + { + "Category": "Thomas Smith", + "Value": 276, + "Segment": "Japan" + }, + { + "Category": "Kimberly Thomas", + "Value": 756, + "Segment": "USA" + }, + { + "Category": "Kimberly Thomas", + "Value": 677, + "Segment": "China" + }, + { + "Category": "Kimberly Thomas", + "Value": 416, + "Segment": "Japan" + }, + { + "Category": "Karen Garcia", + "Value": 823, + "Segment": "USA" + }, + { + "Category": "Karen Garcia", + "Value": 801, + "Segment": "China" + }, + { + "Category": "Karen Garcia", + "Value": 415, + "Segment": "Japan" + }, + { + "Category": "Sarah Torres", + "Value": 697, + "Segment": "USA" + }, + { + "Category": "Sarah Torres", + "Value": 665, + "Segment": "China" + }, + { + "Category": "Sarah Torres", + "Value": 152, + "Segment": "Japan" + }, + { + "Category": "Emily Hill", + "Value": 331, + "Segment": "USA" + }, + { + "Category": "Emily Hill", + "Value": 387, + "Segment": "China" + }, + { + "Category": "Emily Hill", + "Value": 797, + "Segment": "Japan" + }, + { + "Category": "Sarah Walker", + "Value": 235, + "Segment": "USA" + }, + { + "Category": "Sarah Walker", + "Value": 337, + "Segment": "China" + }, + { + "Category": "Sarah Walker", + "Value": 40, + "Segment": "Japan" + }, + { + "Category": "Michael Clark", + "Value": 216, + "Segment": "USA" + }, + { + "Category": "Michael Clark", + "Value": 25, + "Segment": "China" + }, + { + "Category": "Michael Clark", + "Value": 970, + "Segment": "Japan" + }, + { + "Category": "Joshua Wright", + "Value": 21, + "Segment": "USA" + }, + { + "Category": "Joshua Wright", + "Value": 925, + "Segment": "China" + }, + { + "Category": "Joshua Wright", + "Value": 781, + "Segment": "Japan" + }, + { + "Category": "Andrew Walker", + "Value": 696, + "Segment": "USA" + }, + { + "Category": "Andrew Walker", + "Value": 224, + "Segment": "China" + }, + { + "Category": "Andrew Walker", + "Value": 961, + "Segment": "Japan" + }, + { + "Category": "Nancy Young", + "Value": 520, + "Segment": "USA" + }, + { + "Category": "Nancy Young", + "Value": 730, + "Segment": "China" + }, + { + "Category": "Nancy Young", + "Value": 811, + "Segment": "Japan" + }, + { + "Category": "John Lewis", + "Value": 501, + "Segment": "USA" + }, + { + "Category": "John Lewis", + "Value": 997, + "Segment": "China" + }, + { + "Category": "John Lewis", + "Value": 563, + "Segment": "Japan" + }, + { + "Category": "John Brown", + "Value": 36, + "Segment": "USA" + }, + { + "Category": "John Brown", + "Value": 686, + "Segment": "China" + }, + { + "Category": "John Brown", + "Value": 311, + "Segment": "Japan" + }, + { + "Category": "Anthony Thomas", + "Value": 619, + "Segment": "USA" + }, + { + "Category": "Anthony Thomas", + "Value": 868, + "Segment": "China" + }, + { + "Category": "Anthony Thomas", + "Value": 990, + "Segment": "Japan" + }, + { + "Category": "Joshua Moore", + "Value": 767, + "Segment": "USA" + }, + { + "Category": "Joshua Moore", + "Value": 16, + "Segment": "China" + }, + { + "Category": "Joshua Moore", + "Value": 193, + "Segment": "Japan" + }, + { + "Category": "John Hernandez", + "Value": 761, + "Segment": "USA" + }, + { + "Category": "John Hernandez", + "Value": 113, + "Segment": "China" + }, + { + "Category": "John Hernandez", + "Value": 811, + "Segment": "Japan" + }, + { + "Category": "James Perez", + "Value": 663, + "Segment": "USA" + }, + { + "Category": "James Perez", + "Value": 809, + "Segment": "China" + }, + { + "Category": "James Perez", + "Value": 723, + "Segment": "Japan" + }, + { + "Category": "James Scott", + "Value": 404, + "Segment": "USA" + }, + { + "Category": "James Scott", + "Value": 457, + "Segment": "China" + }, + { + "Category": "James Scott", + "Value": 918, + "Segment": "Japan" + }, + { + "Category": "Matthew Sanchez", + "Value": 267, + "Segment": "USA" + }, + { + "Category": "Matthew Sanchez", + "Value": 995, + "Segment": "China" + }, + { + "Category": "Matthew Sanchez", + "Value": 552, + "Segment": "Japan" + }, + { + "Category": "Joseph Sanchez", + "Value": 461, + "Segment": "USA" + }, + { + "Category": "Joseph Sanchez", + "Value": 738, + "Segment": "China" + }, + { + "Category": "Joseph Sanchez", + "Value": 91, + "Segment": "Japan" + }, + { + "Category": "Paul Perez", + "Value": 155, + "Segment": "USA" + }, + { + "Category": "Paul Perez", + "Value": 906, + "Segment": "China" + }, + { + "Category": "Paul Perez", + "Value": 187, + "Segment": "Japan" + }, + { + "Category": "Joshua Rodriguez", + "Value": 271, + "Segment": "USA" + }, + { + "Category": "Joshua Rodriguez", + "Value": 16, + "Segment": "China" + }, + { + "Category": "Joshua Rodriguez", + "Value": 208, + "Segment": "Japan" + }, + { + "Category": "Anthony Sanchez", + "Value": 756, + "Segment": "USA" + }, + { + "Category": "Anthony Sanchez", + "Value": 324, + "Segment": "China" + }, + { + "Category": "Anthony Sanchez", + "Value": 751, + "Segment": "Japan" + }, + { + "Category": "Linda King", + "Value": 177, + "Segment": "USA" + }, + { + "Category": "Linda King", + "Value": 583, + "Segment": "China" + }, + { + "Category": "Linda King", + "Value": 927, + "Segment": "Japan" + }, + { + "Category": "Elizabeth Smith", + "Value": 679, + "Segment": "USA" + }, + { + "Category": "Elizabeth Smith", + "Value": 616, + "Segment": "China" + }, + { + "Category": "Elizabeth Smith", + "Value": 371, + "Segment": "Japan" + }, + { + "Category": "Sandra Miller", + "Value": 526, + "Segment": "USA" + }, + { + "Category": "Sandra Miller", + "Value": 209, + "Segment": "China" + }, + { + "Category": "Sandra Miller", + "Value": 873, + "Segment": "Japan" + }, + { + "Category": "Nancy Allen", + "Value": 164, + "Segment": "USA" + }, + { + "Category": "Nancy Allen", + "Value": 73, + "Segment": "China" + }, + { + "Category": "Nancy Allen", + "Value": 325, + "Segment": "Japan" + }, + { + "Category": "Patricia Brown", + "Value": 651, + "Segment": "USA" + }, + { + "Category": "Patricia Brown", + "Value": 651, + "Segment": "China" + }, + { + "Category": "Patricia Brown", + "Value": 271, + "Segment": "Japan" + }, + { + "Category": "Lisa Clark", + "Value": 957, + "Segment": "USA" + }, + { + "Category": "Lisa Clark", + "Value": 767, + "Segment": "China" + }, + { + "Category": "Lisa Clark", + "Value": 654, + "Segment": "Japan" + }, + { + "Category": "Lisa Thompson", + "Value": 218, + "Segment": "USA" + }, + { + "Category": "Lisa Thompson", + "Value": 69, + "Segment": "China" + }, + { + "Category": "Lisa Thompson", + "Value": 168, + "Segment": "Japan" + }, + { + "Category": "Nancy Clark", + "Value": 741, + "Segment": "USA" + }, + { + "Category": "Nancy Clark", + "Value": 650, + "Segment": "China" + }, + { + "Category": "Nancy Clark", + "Value": 198, + "Segment": "Japan" + }, + { + "Category": "Steven Miller", + "Value": 401, + "Segment": "USA" + }, + { + "Category": "Steven Miller", + "Value": 552, + "Segment": "China" + }, + { + "Category": "Steven Miller", + "Value": 971, + "Segment": "Japan" + }, + { + "Category": "Charles King", + "Value": 224, + "Segment": "USA" + }, + { + "Category": "Charles King", + "Value": 919, + "Segment": "China" + }, + { + "Category": "Charles King", + "Value": 937, + "Segment": "Japan" + }, + { + "Category": "Paul Harris", + "Value": 449, + "Segment": "USA" + }, + { + "Category": "Paul Harris", + "Value": 310, + "Segment": "China" + }, + { + "Category": "Paul Harris", + "Value": 73, + "Segment": "Japan" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/grouped-bar-chart/03-card6.flint.json b/test-harness/excel/evaluations/inputs/grouped-bar-chart/03-card6.flint.json new file mode 100644 index 00000000..09dd72a9 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/grouped-bar-chart/03-card6.flint.json @@ -0,0 +1,173 @@ +{ + "semantic_types": { + "Category": "Category", + "Value": "Quantity", + "ColorVal": "Rank" + }, + "chart_spec": { + "chartType": "Grouped Bar Chart", + "encodings": { + "x": "Category", + "y": "Value", + "group": "ColorVal" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Laptop", + "Value": 511, + "ColorVal": 1 + }, + { + "Category": "Laptop", + "Value": 326, + "ColorVal": 2 + }, + { + "Category": "Laptop", + "Value": 387, + "ColorVal": 3 + }, + { + "Category": "Laptop", + "Value": 159, + "ColorVal": 4 + }, + { + "Category": "Laptop", + "Value": 89, + "ColorVal": 5 + }, + { + "Category": "Phone", + "Value": 496, + "ColorVal": 1 + }, + { + "Category": "Phone", + "Value": 825, + "ColorVal": 2 + }, + { + "Category": "Phone", + "Value": 421, + "ColorVal": 3 + }, + { + "Category": "Phone", + "Value": 804, + "ColorVal": 4 + }, + { + "Category": "Phone", + "Value": 437, + "ColorVal": 5 + }, + { + "Category": "Tablet", + "Value": 874, + "ColorVal": 1 + }, + { + "Category": "Tablet", + "Value": 883, + "ColorVal": 2 + }, + { + "Category": "Tablet", + "Value": 858, + "ColorVal": 3 + }, + { + "Category": "Tablet", + "Value": 39, + "ColorVal": 4 + }, + { + "Category": "Tablet", + "Value": 933, + "ColorVal": 5 + }, + { + "Category": "Desktop", + "Value": 470, + "ColorVal": 1 + }, + { + "Category": "Desktop", + "Value": 111, + "ColorVal": 2 + }, + { + "Category": "Desktop", + "Value": 637, + "ColorVal": 3 + }, + { + "Category": "Desktop", + "Value": 951, + "ColorVal": 4 + }, + { + "Category": "Desktop", + "Value": 239, + "ColorVal": 5 + }, + { + "Category": "Monitor", + "Value": 774, + "ColorVal": 1 + }, + { + "Category": "Monitor", + "Value": 839, + "ColorVal": 2 + }, + { + "Category": "Monitor", + "Value": 182, + "ColorVal": 3 + }, + { + "Category": "Monitor", + "Value": 403, + "ColorVal": 4 + }, + { + "Category": "Monitor", + "Value": 901, + "ColorVal": 5 + }, + { + "Category": "Keyboard", + "Value": 898, + "ColorVal": 1 + }, + { + "Category": "Keyboard", + "Value": 914, + "ColorVal": 2 + }, + { + "Category": "Keyboard", + "Value": 511, + "ColorVal": 3 + }, + { + "Category": "Keyboard", + "Value": 602, + "ColorVal": 4 + }, + { + "Category": "Keyboard", + "Value": 77, + "ColorVal": 5 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/grouped-bar-chart/04-card12.flint.json b/test-harness/excel/evaluations/inputs/grouped-bar-chart/04-card12.flint.json new file mode 100644 index 00000000..12ff785c --- /dev/null +++ b/test-harness/excel/evaluations/inputs/grouped-bar-chart/04-card12.flint.json @@ -0,0 +1,203 @@ +{ + "semantic_types": { + "Date": "Date", + "Value": "Quantity", + "Segment": "Category" + }, + "chart_spec": { + "chartType": "Grouped Bar Chart", + "encodings": { + "x": "Date", + "y": "Value", + "group": "Segment" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Date": "2020-01-01", + "Value": 980, + "Segment": "Laptop" + }, + { + "Date": "2020-01-01", + "Value": 60, + "Segment": "Phone" + }, + { + "Date": "2020-01-01", + "Value": 702, + "Segment": "Tablet" + }, + { + "Date": "2020-04-01", + "Value": 804, + "Segment": "Laptop" + }, + { + "Date": "2020-04-01", + "Value": 604, + "Segment": "Phone" + }, + { + "Date": "2020-04-01", + "Value": 569, + "Segment": "Tablet" + }, + { + "Date": "2020-07-01", + "Value": 229, + "Segment": "Laptop" + }, + { + "Date": "2020-07-01", + "Value": 441, + "Segment": "Phone" + }, + { + "Date": "2020-07-01", + "Value": 431, + "Segment": "Tablet" + }, + { + "Date": "2020-09-30", + "Value": 262, + "Segment": "Laptop" + }, + { + "Date": "2020-09-30", + "Value": 656, + "Segment": "Phone" + }, + { + "Date": "2020-09-30", + "Value": 77, + "Segment": "Tablet" + }, + { + "Date": "2020-12-31", + "Value": 906, + "Segment": "Laptop" + }, + { + "Date": "2020-12-31", + "Value": 69, + "Segment": "Phone" + }, + { + "Date": "2020-12-31", + "Value": 771, + "Segment": "Tablet" + }, + { + "Date": "2021-04-01", + "Value": 356, + "Segment": "Laptop" + }, + { + "Date": "2021-04-01", + "Value": 790, + "Segment": "Phone" + }, + { + "Date": "2021-04-01", + "Value": 484, + "Segment": "Tablet" + }, + { + "Date": "2021-07-01", + "Value": 923, + "Segment": "Laptop" + }, + { + "Date": "2021-07-01", + "Value": 185, + "Segment": "Phone" + }, + { + "Date": "2021-07-01", + "Value": 540, + "Segment": "Tablet" + }, + { + "Date": "2021-09-30", + "Value": 872, + "Segment": "Laptop" + }, + { + "Date": "2021-09-30", + "Value": 189, + "Segment": "Phone" + }, + { + "Date": "2021-09-30", + "Value": 587, + "Segment": "Tablet" + }, + { + "Date": "2021-12-31", + "Value": 238, + "Segment": "Laptop" + }, + { + "Date": "2021-12-31", + "Value": 432, + "Segment": "Phone" + }, + { + "Date": "2021-12-31", + "Value": 217, + "Segment": "Tablet" + }, + { + "Date": "2022-04-01", + "Value": 58, + "Segment": "Laptop" + }, + { + "Date": "2022-04-01", + "Value": 473, + "Segment": "Phone" + }, + { + "Date": "2022-04-01", + "Value": 139, + "Segment": "Tablet" + }, + { + "Date": "2022-07-01", + "Value": 152, + "Segment": "Laptop" + }, + { + "Date": "2022-07-01", + "Value": 413, + "Segment": "Phone" + }, + { + "Date": "2022-07-01", + "Value": 554, + "Segment": "Tablet" + }, + { + "Date": "2022-09-30", + "Value": 695, + "Segment": "Laptop" + }, + { + "Date": "2022-09-30", + "Value": 951, + "Segment": "Phone" + }, + { + "Date": "2022-09-30", + "Value": 127, + "Segment": "Tablet" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/grouped-bar-chart/05-card5.flint.json b/test-harness/excel/evaluations/inputs/grouped-bar-chart/05-card5.flint.json new file mode 100644 index 00000000..e3b3dd52 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/grouped-bar-chart/05-card5.flint.json @@ -0,0 +1,123 @@ +{ + "semantic_types": { + "X": "Quantity", + "Value": "Quantity", + "Segment": "Category" + }, + "chart_spec": { + "chartType": "Grouped Bar Chart", + "encodings": { + "x": "X", + "y": "Value", + "group": "Segment" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 1, + "Value": 39, + "Segment": "Laptop" + }, + { + "X": 1, + "Value": 154, + "Segment": "Phone" + }, + { + "X": 1, + "Value": 518, + "Segment": "Tablet" + }, + { + "X": 1, + "Value": 844, + "Segment": "Desktop" + }, + { + "X": 2, + "Value": 774, + "Segment": "Laptop" + }, + { + "X": 2, + "Value": 490, + "Segment": "Phone" + }, + { + "X": 2, + "Value": 270, + "Segment": "Tablet" + }, + { + "X": 2, + "Value": 895, + "Segment": "Desktop" + }, + { + "X": 3, + "Value": 843, + "Segment": "Laptop" + }, + { + "X": 3, + "Value": 361, + "Segment": "Phone" + }, + { + "X": 3, + "Value": 984, + "Segment": "Tablet" + }, + { + "X": 3, + "Value": 36, + "Segment": "Desktop" + }, + { + "X": 4, + "Value": 30, + "Segment": "Laptop" + }, + { + "X": 4, + "Value": 201, + "Segment": "Phone" + }, + { + "X": 4, + "Value": 215, + "Segment": "Tablet" + }, + { + "X": 4, + "Value": 728, + "Segment": "Desktop" + }, + { + "X": 5, + "Value": 139, + "Segment": "Laptop" + }, + { + "X": 5, + "Value": 629, + "Segment": "Phone" + }, + { + "X": 5, + "Value": 232, + "Segment": "Tablet" + }, + { + "X": 5, + "Value": 94, + "Segment": "Desktop" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/grouped-bar-chart/06-card24.flint.json b/test-harness/excel/evaluations/inputs/grouped-bar-chart/06-card24.flint.json new file mode 100644 index 00000000..2031d434 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/grouped-bar-chart/06-card24.flint.json @@ -0,0 +1,143 @@ +{ + "semantic_types": { + "X": "Quantity", + "Group": "Category", + "Segment": "Category" + }, + "chart_spec": { + "chartType": "Grouped Bar Chart", + "encodings": { + "x": "X", + "y": "Group", + "group": "Segment" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Group": "Laptop", + "X": 354, + "Segment": "USA" + }, + { + "Group": "Laptop", + "X": 992, + "Segment": "China" + }, + { + "Group": "Laptop", + "X": 729, + "Segment": "Japan" + }, + { + "Group": "Laptop", + "X": 518, + "Segment": "Germany" + }, + { + "Group": "Phone", + "X": 465, + "Segment": "USA" + }, + { + "Group": "Phone", + "X": 707, + "Segment": "China" + }, + { + "Group": "Phone", + "X": 855, + "Segment": "Japan" + }, + { + "Group": "Phone", + "X": 167, + "Segment": "Germany" + }, + { + "Group": "Tablet", + "X": 360, + "Segment": "USA" + }, + { + "Group": "Tablet", + "X": 283, + "Segment": "China" + }, + { + "Group": "Tablet", + "X": 710, + "Segment": "Japan" + }, + { + "Group": "Tablet", + "X": 975, + "Segment": "Germany" + }, + { + "Group": "Desktop", + "X": 925, + "Segment": "USA" + }, + { + "Group": "Desktop", + "X": 990, + "Segment": "China" + }, + { + "Group": "Desktop", + "X": 899, + "Segment": "Japan" + }, + { + "Group": "Desktop", + "X": 14, + "Segment": "Germany" + }, + { + "Group": "Monitor", + "X": 928, + "Segment": "USA" + }, + { + "Group": "Monitor", + "X": 903, + "Segment": "China" + }, + { + "Group": "Monitor", + "X": 442, + "Segment": "Japan" + }, + { + "Group": "Monitor", + "X": 548, + "Segment": "Germany" + }, + { + "Group": "Keyboard", + "X": 64, + "Segment": "USA" + }, + { + "Group": "Keyboard", + "X": 215, + "Segment": "China" + }, + { + "Group": "Keyboard", + "X": 920, + "Segment": "Japan" + }, + { + "Group": "Keyboard", + "X": 750, + "Segment": "Germany" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/grouped-bar-chart/07-card30.flint.json b/test-harness/excel/evaluations/inputs/grouped-bar-chart/07-card30.flint.json new file mode 100644 index 00000000..937a2c2e --- /dev/null +++ b/test-harness/excel/evaluations/inputs/grouped-bar-chart/07-card30.flint.json @@ -0,0 +1,173 @@ +{ + "semantic_types": { + "X": "Quantity", + "EndDate": "Date", + "Segment": "Category" + }, + "chart_spec": { + "chartType": "Grouped Bar Chart", + "encodings": { + "x": "X", + "y": "EndDate", + "group": "Segment" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "EndDate": "2020-01-01", + "X": 734, + "Segment": "Laptop" + }, + { + "EndDate": "2020-01-01", + "X": 68, + "Segment": "Phone" + }, + { + "EndDate": "2020-01-01", + "X": 719, + "Segment": "Tablet" + }, + { + "EndDate": "2020-04-19", + "X": 798, + "Segment": "Laptop" + }, + { + "EndDate": "2020-04-19", + "X": 602, + "Segment": "Phone" + }, + { + "EndDate": "2020-04-19", + "X": 96, + "Segment": "Tablet" + }, + { + "EndDate": "2020-08-07", + "X": 782, + "Segment": "Laptop" + }, + { + "EndDate": "2020-08-07", + "X": 577, + "Segment": "Phone" + }, + { + "EndDate": "2020-08-07", + "X": 832, + "Segment": "Tablet" + }, + { + "EndDate": "2020-11-24", + "X": 60, + "Segment": "Laptop" + }, + { + "EndDate": "2020-11-24", + "X": 806, + "Segment": "Phone" + }, + { + "EndDate": "2020-11-24", + "X": 148, + "Segment": "Tablet" + }, + { + "EndDate": "2021-03-14", + "X": 295, + "Segment": "Laptop" + }, + { + "EndDate": "2021-03-14", + "X": 766, + "Segment": "Phone" + }, + { + "EndDate": "2021-03-14", + "X": 213, + "Segment": "Tablet" + }, + { + "EndDate": "2021-07-01", + "X": 588, + "Segment": "Laptop" + }, + { + "EndDate": "2021-07-01", + "X": 199, + "Segment": "Phone" + }, + { + "EndDate": "2021-07-01", + "X": 91, + "Segment": "Tablet" + }, + { + "EndDate": "2021-10-19", + "X": 138, + "Segment": "Laptop" + }, + { + "EndDate": "2021-10-19", + "X": 116, + "Segment": "Phone" + }, + { + "EndDate": "2021-10-19", + "X": 189, + "Segment": "Tablet" + }, + { + "EndDate": "2022-02-05", + "X": 348, + "Segment": "Laptop" + }, + { + "EndDate": "2022-02-05", + "X": 157, + "Segment": "Phone" + }, + { + "EndDate": "2022-02-05", + "X": 997, + "Segment": "Tablet" + }, + { + "EndDate": "2022-05-26", + "X": 947, + "Segment": "Laptop" + }, + { + "EndDate": "2022-05-26", + "X": 103, + "Segment": "Phone" + }, + { + "EndDate": "2022-05-26", + "X": 785, + "Segment": "Tablet" + }, + { + "EndDate": "2022-09-12", + "X": 114, + "Segment": "Laptop" + }, + { + "EndDate": "2022-09-12", + "X": 694, + "Segment": "Phone" + }, + { + "EndDate": "2022-09-12", + "X": 339, + "Segment": "Tablet" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/grouped-bar-chart/08-card8.flint.json b/test-harness/excel/evaluations/inputs/grouped-bar-chart/08-card8.flint.json new file mode 100644 index 00000000..d871d376 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/grouped-bar-chart/08-card8.flint.json @@ -0,0 +1,2023 @@ +{ + "semantic_types": { + "Category": "Category", + "Value": "Quantity", + "ColorVal": "Rank" + }, + "chart_spec": { + "chartType": "Grouped Bar Chart", + "encodings": { + "x": "Category", + "y": "Value", + "group": "ColorVal" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Laptop", + "Value": 356, + "ColorVal": 1 + }, + { + "Category": "Laptop", + "Value": 359, + "ColorVal": 2 + }, + { + "Category": "Laptop", + "Value": 250, + "ColorVal": 3 + }, + { + "Category": "Laptop", + "Value": 74, + "ColorVal": 4 + }, + { + "Category": "Laptop", + "Value": 721, + "ColorVal": 5 + }, + { + "Category": "Laptop", + "Value": 502, + "ColorVal": 6 + }, + { + "Category": "Laptop", + "Value": 859, + "ColorVal": 7 + }, + { + "Category": "Laptop", + "Value": 809, + "ColorVal": 8 + }, + { + "Category": "Laptop", + "Value": 272, + "ColorVal": 9 + }, + { + "Category": "Laptop", + "Value": 897, + "ColorVal": 10 + }, + { + "Category": "Laptop", + "Value": 853, + "ColorVal": 11 + }, + { + "Category": "Laptop", + "Value": 691, + "ColorVal": 12 + }, + { + "Category": "Laptop", + "Value": 802, + "ColorVal": 13 + }, + { + "Category": "Laptop", + "Value": 881, + "ColorVal": 14 + }, + { + "Category": "Laptop", + "Value": 680, + "ColorVal": 15 + }, + { + "Category": "Laptop", + "Value": 755, + "ColorVal": 16 + }, + { + "Category": "Laptop", + "Value": 17, + "ColorVal": 17 + }, + { + "Category": "Laptop", + "Value": 488, + "ColorVal": 18 + }, + { + "Category": "Laptop", + "Value": 402, + "ColorVal": 19 + }, + { + "Category": "Laptop", + "Value": 245, + "ColorVal": 20 + }, + { + "Category": "Laptop", + "Value": 291, + "ColorVal": 21 + }, + { + "Category": "Laptop", + "Value": 782, + "ColorVal": 22 + }, + { + "Category": "Laptop", + "Value": 860, + "ColorVal": 23 + }, + { + "Category": "Laptop", + "Value": 216, + "ColorVal": 24 + }, + { + "Category": "Laptop", + "Value": 87, + "ColorVal": 25 + }, + { + "Category": "Laptop", + "Value": 436, + "ColorVal": 26 + }, + { + "Category": "Laptop", + "Value": 283, + "ColorVal": 27 + }, + { + "Category": "Laptop", + "Value": 707, + "ColorVal": 28 + }, + { + "Category": "Laptop", + "Value": 464, + "ColorVal": 29 + }, + { + "Category": "Laptop", + "Value": 308, + "ColorVal": 30 + }, + { + "Category": "Laptop", + "Value": 915, + "ColorVal": 31 + }, + { + "Category": "Laptop", + "Value": 381, + "ColorVal": 32 + }, + { + "Category": "Laptop", + "Value": 382, + "ColorVal": 33 + }, + { + "Category": "Laptop", + "Value": 193, + "ColorVal": 34 + }, + { + "Category": "Laptop", + "Value": 462, + "ColorVal": 35 + }, + { + "Category": "Laptop", + "Value": 560, + "ColorVal": 36 + }, + { + "Category": "Laptop", + "Value": 95, + "ColorVal": 37 + }, + { + "Category": "Laptop", + "Value": 655, + "ColorVal": 38 + }, + { + "Category": "Laptop", + "Value": 972, + "ColorVal": 39 + }, + { + "Category": "Laptop", + "Value": 870, + "ColorVal": 40 + }, + { + "Category": "Laptop", + "Value": 112, + "ColorVal": 41 + }, + { + "Category": "Laptop", + "Value": 102, + "ColorVal": 42 + }, + { + "Category": "Laptop", + "Value": 826, + "ColorVal": 43 + }, + { + "Category": "Laptop", + "Value": 794, + "ColorVal": 44 + }, + { + "Category": "Laptop", + "Value": 810, + "ColorVal": 45 + }, + { + "Category": "Laptop", + "Value": 577, + "ColorVal": 46 + }, + { + "Category": "Laptop", + "Value": 754, + "ColorVal": 47 + }, + { + "Category": "Laptop", + "Value": 232, + "ColorVal": 48 + }, + { + "Category": "Laptop", + "Value": 597, + "ColorVal": 49 + }, + { + "Category": "Laptop", + "Value": 863, + "ColorVal": 50 + }, + { + "Category": "Phone", + "Value": 100, + "ColorVal": 1 + }, + { + "Category": "Phone", + "Value": 14, + "ColorVal": 2 + }, + { + "Category": "Phone", + "Value": 892, + "ColorVal": 3 + }, + { + "Category": "Phone", + "Value": 115, + "ColorVal": 4 + }, + { + "Category": "Phone", + "Value": 281, + "ColorVal": 5 + }, + { + "Category": "Phone", + "Value": 833, + "ColorVal": 6 + }, + { + "Category": "Phone", + "Value": 217, + "ColorVal": 7 + }, + { + "Category": "Phone", + "Value": 56, + "ColorVal": 8 + }, + { + "Category": "Phone", + "Value": 898, + "ColorVal": 9 + }, + { + "Category": "Phone", + "Value": 737, + "ColorVal": 10 + }, + { + "Category": "Phone", + "Value": 987, + "ColorVal": 11 + }, + { + "Category": "Phone", + "Value": 778, + "ColorVal": 12 + }, + { + "Category": "Phone", + "Value": 575, + "ColorVal": 13 + }, + { + "Category": "Phone", + "Value": 505, + "ColorVal": 14 + }, + { + "Category": "Phone", + "Value": 41, + "ColorVal": 15 + }, + { + "Category": "Phone", + "Value": 911, + "ColorVal": 16 + }, + { + "Category": "Phone", + "Value": 180, + "ColorVal": 17 + }, + { + "Category": "Phone", + "Value": 505, + "ColorVal": 18 + }, + { + "Category": "Phone", + "Value": 783, + "ColorVal": 19 + }, + { + "Category": "Phone", + "Value": 789, + "ColorVal": 20 + }, + { + "Category": "Phone", + "Value": 983, + "ColorVal": 21 + }, + { + "Category": "Phone", + "Value": 445, + "ColorVal": 22 + }, + { + "Category": "Phone", + "Value": 446, + "ColorVal": 23 + }, + { + "Category": "Phone", + "Value": 116, + "ColorVal": 24 + }, + { + "Category": "Phone", + "Value": 904, + "ColorVal": 25 + }, + { + "Category": "Phone", + "Value": 780, + "ColorVal": 26 + }, + { + "Category": "Phone", + "Value": 239, + "ColorVal": 27 + }, + { + "Category": "Phone", + "Value": 928, + "ColorVal": 28 + }, + { + "Category": "Phone", + "Value": 299, + "ColorVal": 29 + }, + { + "Category": "Phone", + "Value": 602, + "ColorVal": 30 + }, + { + "Category": "Phone", + "Value": 489, + "ColorVal": 31 + }, + { + "Category": "Phone", + "Value": 750, + "ColorVal": 32 + }, + { + "Category": "Phone", + "Value": 262, + "ColorVal": 33 + }, + { + "Category": "Phone", + "Value": 321, + "ColorVal": 34 + }, + { + "Category": "Phone", + "Value": 215, + "ColorVal": 35 + }, + { + "Category": "Phone", + "Value": 390, + "ColorVal": 36 + }, + { + "Category": "Phone", + "Value": 73, + "ColorVal": 37 + }, + { + "Category": "Phone", + "Value": 566, + "ColorVal": 38 + }, + { + "Category": "Phone", + "Value": 975, + "ColorVal": 39 + }, + { + "Category": "Phone", + "Value": 117, + "ColorVal": 40 + }, + { + "Category": "Phone", + "Value": 495, + "ColorVal": 41 + }, + { + "Category": "Phone", + "Value": 755, + "ColorVal": 42 + }, + { + "Category": "Phone", + "Value": 587, + "ColorVal": 43 + }, + { + "Category": "Phone", + "Value": 611, + "ColorVal": 44 + }, + { + "Category": "Phone", + "Value": 839, + "ColorVal": 45 + }, + { + "Category": "Phone", + "Value": 163, + "ColorVal": 46 + }, + { + "Category": "Phone", + "Value": 329, + "ColorVal": 47 + }, + { + "Category": "Phone", + "Value": 720, + "ColorVal": 48 + }, + { + "Category": "Phone", + "Value": 781, + "ColorVal": 49 + }, + { + "Category": "Phone", + "Value": 982, + "ColorVal": 50 + }, + { + "Category": "Tablet", + "Value": 606, + "ColorVal": 1 + }, + { + "Category": "Tablet", + "Value": 420, + "ColorVal": 2 + }, + { + "Category": "Tablet", + "Value": 758, + "ColorVal": 3 + }, + { + "Category": "Tablet", + "Value": 918, + "ColorVal": 4 + }, + { + "Category": "Tablet", + "Value": 461, + "ColorVal": 5 + }, + { + "Category": "Tablet", + "Value": 492, + "ColorVal": 6 + }, + { + "Category": "Tablet", + "Value": 110, + "ColorVal": 7 + }, + { + "Category": "Tablet", + "Value": 163, + "ColorVal": 8 + }, + { + "Category": "Tablet", + "Value": 902, + "ColorVal": 9 + }, + { + "Category": "Tablet", + "Value": 35, + "ColorVal": 10 + }, + { + "Category": "Tablet", + "Value": 319, + "ColorVal": 11 + }, + { + "Category": "Tablet", + "Value": 560, + "ColorVal": 12 + }, + { + "Category": "Tablet", + "Value": 478, + "ColorVal": 13 + }, + { + "Category": "Tablet", + "Value": 573, + "ColorVal": 14 + }, + { + "Category": "Tablet", + "Value": 175, + "ColorVal": 15 + }, + { + "Category": "Tablet", + "Value": 177, + "ColorVal": 16 + }, + { + "Category": "Tablet", + "Value": 73, + "ColorVal": 17 + }, + { + "Category": "Tablet", + "Value": 42, + "ColorVal": 18 + }, + { + "Category": "Tablet", + "Value": 570, + "ColorVal": 19 + }, + { + "Category": "Tablet", + "Value": 479, + "ColorVal": 20 + }, + { + "Category": "Tablet", + "Value": 980, + "ColorVal": 21 + }, + { + "Category": "Tablet", + "Value": 938, + "ColorVal": 22 + }, + { + "Category": "Tablet", + "Value": 721, + "ColorVal": 23 + }, + { + "Category": "Tablet", + "Value": 577, + "ColorVal": 24 + }, + { + "Category": "Tablet", + "Value": 684, + "ColorVal": 25 + }, + { + "Category": "Tablet", + "Value": 629, + "ColorVal": 26 + }, + { + "Category": "Tablet", + "Value": 853, + "ColorVal": 27 + }, + { + "Category": "Tablet", + "Value": 527, + "ColorVal": 28 + }, + { + "Category": "Tablet", + "Value": 513, + "ColorVal": 29 + }, + { + "Category": "Tablet", + "Value": 141, + "ColorVal": 30 + }, + { + "Category": "Tablet", + "Value": 926, + "ColorVal": 31 + }, + { + "Category": "Tablet", + "Value": 479, + "ColorVal": 32 + }, + { + "Category": "Tablet", + "Value": 717, + "ColorVal": 33 + }, + { + "Category": "Tablet", + "Value": 931, + "ColorVal": 34 + }, + { + "Category": "Tablet", + "Value": 496, + "ColorVal": 35 + }, + { + "Category": "Tablet", + "Value": 917, + "ColorVal": 36 + }, + { + "Category": "Tablet", + "Value": 610, + "ColorVal": 37 + }, + { + "Category": "Tablet", + "Value": 239, + "ColorVal": 38 + }, + { + "Category": "Tablet", + "Value": 650, + "ColorVal": 39 + }, + { + "Category": "Tablet", + "Value": 102, + "ColorVal": 40 + }, + { + "Category": "Tablet", + "Value": 134, + "ColorVal": 41 + }, + { + "Category": "Tablet", + "Value": 475, + "ColorVal": 42 + }, + { + "Category": "Tablet", + "Value": 108, + "ColorVal": 43 + }, + { + "Category": "Tablet", + "Value": 848, + "ColorVal": 44 + }, + { + "Category": "Tablet", + "Value": 309, + "ColorVal": 45 + }, + { + "Category": "Tablet", + "Value": 930, + "ColorVal": 46 + }, + { + "Category": "Tablet", + "Value": 861, + "ColorVal": 47 + }, + { + "Category": "Tablet", + "Value": 610, + "ColorVal": 48 + }, + { + "Category": "Tablet", + "Value": 409, + "ColorVal": 49 + }, + { + "Category": "Tablet", + "Value": 969, + "ColorVal": 50 + }, + { + "Category": "Desktop", + "Value": 837, + "ColorVal": 1 + }, + { + "Category": "Desktop", + "Value": 413, + "ColorVal": 2 + }, + { + "Category": "Desktop", + "Value": 562, + "ColorVal": 3 + }, + { + "Category": "Desktop", + "Value": 57, + "ColorVal": 4 + }, + { + "Category": "Desktop", + "Value": 52, + "ColorVal": 5 + }, + { + "Category": "Desktop", + "Value": 220, + "ColorVal": 6 + }, + { + "Category": "Desktop", + "Value": 759, + "ColorVal": 7 + }, + { + "Category": "Desktop", + "Value": 815, + "ColorVal": 8 + }, + { + "Category": "Desktop", + "Value": 353, + "ColorVal": 9 + }, + { + "Category": "Desktop", + "Value": 802, + "ColorVal": 10 + }, + { + "Category": "Desktop", + "Value": 150, + "ColorVal": 11 + }, + { + "Category": "Desktop", + "Value": 255, + "ColorVal": 12 + }, + { + "Category": "Desktop", + "Value": 743, + "ColorVal": 13 + }, + { + "Category": "Desktop", + "Value": 898, + "ColorVal": 14 + }, + { + "Category": "Desktop", + "Value": 753, + "ColorVal": 15 + }, + { + "Category": "Desktop", + "Value": 309, + "ColorVal": 16 + }, + { + "Category": "Desktop", + "Value": 934, + "ColorVal": 17 + }, + { + "Category": "Desktop", + "Value": 832, + "ColorVal": 18 + }, + { + "Category": "Desktop", + "Value": 629, + "ColorVal": 19 + }, + { + "Category": "Desktop", + "Value": 534, + "ColorVal": 20 + }, + { + "Category": "Desktop", + "Value": 606, + "ColorVal": 21 + }, + { + "Category": "Desktop", + "Value": 432, + "ColorVal": 22 + }, + { + "Category": "Desktop", + "Value": 995, + "ColorVal": 23 + }, + { + "Category": "Desktop", + "Value": 128, + "ColorVal": 24 + }, + { + "Category": "Desktop", + "Value": 524, + "ColorVal": 25 + }, + { + "Category": "Desktop", + "Value": 793, + "ColorVal": 26 + }, + { + "Category": "Desktop", + "Value": 747, + "ColorVal": 27 + }, + { + "Category": "Desktop", + "Value": 163, + "ColorVal": 28 + }, + { + "Category": "Desktop", + "Value": 375, + "ColorVal": 29 + }, + { + "Category": "Desktop", + "Value": 701, + "ColorVal": 30 + }, + { + "Category": "Desktop", + "Value": 908, + "ColorVal": 31 + }, + { + "Category": "Desktop", + "Value": 939, + "ColorVal": 32 + }, + { + "Category": "Desktop", + "Value": 395, + "ColorVal": 33 + }, + { + "Category": "Desktop", + "Value": 538, + "ColorVal": 34 + }, + { + "Category": "Desktop", + "Value": 477, + "ColorVal": 35 + }, + { + "Category": "Desktop", + "Value": 515, + "ColorVal": 36 + }, + { + "Category": "Desktop", + "Value": 201, + "ColorVal": 37 + }, + { + "Category": "Desktop", + "Value": 784, + "ColorVal": 38 + }, + { + "Category": "Desktop", + "Value": 831, + "ColorVal": 39 + }, + { + "Category": "Desktop", + "Value": 851, + "ColorVal": 40 + }, + { + "Category": "Desktop", + "Value": 363, + "ColorVal": 41 + }, + { + "Category": "Desktop", + "Value": 180, + "ColorVal": 42 + }, + { + "Category": "Desktop", + "Value": 362, + "ColorVal": 43 + }, + { + "Category": "Desktop", + "Value": 280, + "ColorVal": 44 + }, + { + "Category": "Desktop", + "Value": 140, + "ColorVal": 45 + }, + { + "Category": "Desktop", + "Value": 497, + "ColorVal": 46 + }, + { + "Category": "Desktop", + "Value": 953, + "ColorVal": 47 + }, + { + "Category": "Desktop", + "Value": 482, + "ColorVal": 48 + }, + { + "Category": "Desktop", + "Value": 869, + "ColorVal": 49 + }, + { + "Category": "Desktop", + "Value": 875, + "ColorVal": 50 + }, + { + "Category": "Monitor", + "Value": 627, + "ColorVal": 1 + }, + { + "Category": "Monitor", + "Value": 959, + "ColorVal": 2 + }, + { + "Category": "Monitor", + "Value": 194, + "ColorVal": 3 + }, + { + "Category": "Monitor", + "Value": 84, + "ColorVal": 4 + }, + { + "Category": "Monitor", + "Value": 205, + "ColorVal": 5 + }, + { + "Category": "Monitor", + "Value": 82, + "ColorVal": 6 + }, + { + "Category": "Monitor", + "Value": 168, + "ColorVal": 7 + }, + { + "Category": "Monitor", + "Value": 262, + "ColorVal": 8 + }, + { + "Category": "Monitor", + "Value": 487, + "ColorVal": 9 + }, + { + "Category": "Monitor", + "Value": 522, + "ColorVal": 10 + }, + { + "Category": "Monitor", + "Value": 287, + "ColorVal": 11 + }, + { + "Category": "Monitor", + "Value": 858, + "ColorVal": 12 + }, + { + "Category": "Monitor", + "Value": 428, + "ColorVal": 13 + }, + { + "Category": "Monitor", + "Value": 579, + "ColorVal": 14 + }, + { + "Category": "Monitor", + "Value": 239, + "ColorVal": 15 + }, + { + "Category": "Monitor", + "Value": 626, + "ColorVal": 16 + }, + { + "Category": "Monitor", + "Value": 466, + "ColorVal": 17 + }, + { + "Category": "Monitor", + "Value": 844, + "ColorVal": 18 + }, + { + "Category": "Monitor", + "Value": 767, + "ColorVal": 19 + }, + { + "Category": "Monitor", + "Value": 579, + "ColorVal": 20 + }, + { + "Category": "Monitor", + "Value": 406, + "ColorVal": 21 + }, + { + "Category": "Monitor", + "Value": 628, + "ColorVal": 22 + }, + { + "Category": "Monitor", + "Value": 329, + "ColorVal": 23 + }, + { + "Category": "Monitor", + "Value": 93, + "ColorVal": 24 + }, + { + "Category": "Monitor", + "Value": 16, + "ColorVal": 25 + }, + { + "Category": "Monitor", + "Value": 962, + "ColorVal": 26 + }, + { + "Category": "Monitor", + "Value": 636, + "ColorVal": 27 + }, + { + "Category": "Monitor", + "Value": 724, + "ColorVal": 28 + }, + { + "Category": "Monitor", + "Value": 451, + "ColorVal": 29 + }, + { + "Category": "Monitor", + "Value": 72, + "ColorVal": 30 + }, + { + "Category": "Monitor", + "Value": 82, + "ColorVal": 31 + }, + { + "Category": "Monitor", + "Value": 364, + "ColorVal": 32 + }, + { + "Category": "Monitor", + "Value": 161, + "ColorVal": 33 + }, + { + "Category": "Monitor", + "Value": 543, + "ColorVal": 34 + }, + { + "Category": "Monitor", + "Value": 841, + "ColorVal": 35 + }, + { + "Category": "Monitor", + "Value": 599, + "ColorVal": 36 + }, + { + "Category": "Monitor", + "Value": 304, + "ColorVal": 37 + }, + { + "Category": "Monitor", + "Value": 764, + "ColorVal": 38 + }, + { + "Category": "Monitor", + "Value": 888, + "ColorVal": 39 + }, + { + "Category": "Monitor", + "Value": 221, + "ColorVal": 40 + }, + { + "Category": "Monitor", + "Value": 342, + "ColorVal": 41 + }, + { + "Category": "Monitor", + "Value": 502, + "ColorVal": 42 + }, + { + "Category": "Monitor", + "Value": 44, + "ColorVal": 43 + }, + { + "Category": "Monitor", + "Value": 807, + "ColorVal": 44 + }, + { + "Category": "Monitor", + "Value": 202, + "ColorVal": 45 + }, + { + "Category": "Monitor", + "Value": 903, + "ColorVal": 46 + }, + { + "Category": "Monitor", + "Value": 345, + "ColorVal": 47 + }, + { + "Category": "Monitor", + "Value": 706, + "ColorVal": 48 + }, + { + "Category": "Monitor", + "Value": 118, + "ColorVal": 49 + }, + { + "Category": "Monitor", + "Value": 205, + "ColorVal": 50 + }, + { + "Category": "Keyboard", + "Value": 943, + "ColorVal": 1 + }, + { + "Category": "Keyboard", + "Value": 654, + "ColorVal": 2 + }, + { + "Category": "Keyboard", + "Value": 910, + "ColorVal": 3 + }, + { + "Category": "Keyboard", + "Value": 142, + "ColorVal": 4 + }, + { + "Category": "Keyboard", + "Value": 793, + "ColorVal": 5 + }, + { + "Category": "Keyboard", + "Value": 383, + "ColorVal": 6 + }, + { + "Category": "Keyboard", + "Value": 773, + "ColorVal": 7 + }, + { + "Category": "Keyboard", + "Value": 496, + "ColorVal": 8 + }, + { + "Category": "Keyboard", + "Value": 159, + "ColorVal": 9 + }, + { + "Category": "Keyboard", + "Value": 803, + "ColorVal": 10 + }, + { + "Category": "Keyboard", + "Value": 253, + "ColorVal": 11 + }, + { + "Category": "Keyboard", + "Value": 432, + "ColorVal": 12 + }, + { + "Category": "Keyboard", + "Value": 836, + "ColorVal": 13 + }, + { + "Category": "Keyboard", + "Value": 315, + "ColorVal": 14 + }, + { + "Category": "Keyboard", + "Value": 976, + "ColorVal": 15 + }, + { + "Category": "Keyboard", + "Value": 434, + "ColorVal": 16 + }, + { + "Category": "Keyboard", + "Value": 572, + "ColorVal": 17 + }, + { + "Category": "Keyboard", + "Value": 124, + "ColorVal": 18 + }, + { + "Category": "Keyboard", + "Value": 237, + "ColorVal": 19 + }, + { + "Category": "Keyboard", + "Value": 625, + "ColorVal": 20 + }, + { + "Category": "Keyboard", + "Value": 229, + "ColorVal": 21 + }, + { + "Category": "Keyboard", + "Value": 396, + "ColorVal": 22 + }, + { + "Category": "Keyboard", + "Value": 542, + "ColorVal": 23 + }, + { + "Category": "Keyboard", + "Value": 480, + "ColorVal": 24 + }, + { + "Category": "Keyboard", + "Value": 670, + "ColorVal": 25 + }, + { + "Category": "Keyboard", + "Value": 400, + "ColorVal": 26 + }, + { + "Category": "Keyboard", + "Value": 371, + "ColorVal": 27 + }, + { + "Category": "Keyboard", + "Value": 686, + "ColorVal": 28 + }, + { + "Category": "Keyboard", + "Value": 415, + "ColorVal": 29 + }, + { + "Category": "Keyboard", + "Value": 502, + "ColorVal": 30 + }, + { + "Category": "Keyboard", + "Value": 490, + "ColorVal": 31 + }, + { + "Category": "Keyboard", + "Value": 623, + "ColorVal": 32 + }, + { + "Category": "Keyboard", + "Value": 201, + "ColorVal": 33 + }, + { + "Category": "Keyboard", + "Value": 523, + "ColorVal": 34 + }, + { + "Category": "Keyboard", + "Value": 547, + "ColorVal": 35 + }, + { + "Category": "Keyboard", + "Value": 163, + "ColorVal": 36 + }, + { + "Category": "Keyboard", + "Value": 892, + "ColorVal": 37 + }, + { + "Category": "Keyboard", + "Value": 553, + "ColorVal": 38 + }, + { + "Category": "Keyboard", + "Value": 159, + "ColorVal": 39 + }, + { + "Category": "Keyboard", + "Value": 340, + "ColorVal": 40 + }, + { + "Category": "Keyboard", + "Value": 580, + "ColorVal": 41 + }, + { + "Category": "Keyboard", + "Value": 613, + "ColorVal": 42 + }, + { + "Category": "Keyboard", + "Value": 945, + "ColorVal": 43 + }, + { + "Category": "Keyboard", + "Value": 14, + "ColorVal": 44 + }, + { + "Category": "Keyboard", + "Value": 48, + "ColorVal": 45 + }, + { + "Category": "Keyboard", + "Value": 108, + "ColorVal": 46 + }, + { + "Category": "Keyboard", + "Value": 269, + "ColorVal": 47 + }, + { + "Category": "Keyboard", + "Value": 64, + "ColorVal": 48 + }, + { + "Category": "Keyboard", + "Value": 936, + "ColorVal": 49 + }, + { + "Category": "Keyboard", + "Value": 144, + "ColorVal": 50 + }, + { + "Category": "Mouse", + "Value": 267, + "ColorVal": 1 + }, + { + "Category": "Mouse", + "Value": 994, + "ColorVal": 2 + }, + { + "Category": "Mouse", + "Value": 665, + "ColorVal": 3 + }, + { + "Category": "Mouse", + "Value": 41, + "ColorVal": 4 + }, + { + "Category": "Mouse", + "Value": 21, + "ColorVal": 5 + }, + { + "Category": "Mouse", + "Value": 155, + "ColorVal": 6 + }, + { + "Category": "Mouse", + "Value": 481, + "ColorVal": 7 + }, + { + "Category": "Mouse", + "Value": 625, + "ColorVal": 8 + }, + { + "Category": "Mouse", + "Value": 58, + "ColorVal": 9 + }, + { + "Category": "Mouse", + "Value": 250, + "ColorVal": 10 + }, + { + "Category": "Mouse", + "Value": 902, + "ColorVal": 11 + }, + { + "Category": "Mouse", + "Value": 85, + "ColorVal": 12 + }, + { + "Category": "Mouse", + "Value": 453, + "ColorVal": 13 + }, + { + "Category": "Mouse", + "Value": 360, + "ColorVal": 14 + }, + { + "Category": "Mouse", + "Value": 232, + "ColorVal": 15 + }, + { + "Category": "Mouse", + "Value": 90, + "ColorVal": 16 + }, + { + "Category": "Mouse", + "Value": 114, + "ColorVal": 17 + }, + { + "Category": "Mouse", + "Value": 858, + "ColorVal": 18 + }, + { + "Category": "Mouse", + "Value": 432, + "ColorVal": 19 + }, + { + "Category": "Mouse", + "Value": 460, + "ColorVal": 20 + }, + { + "Category": "Mouse", + "Value": 450, + "ColorVal": 21 + }, + { + "Category": "Mouse", + "Value": 783, + "ColorVal": 22 + }, + { + "Category": "Mouse", + "Value": 610, + "ColorVal": 23 + }, + { + "Category": "Mouse", + "Value": 633, + "ColorVal": 24 + }, + { + "Category": "Mouse", + "Value": 682, + "ColorVal": 25 + }, + { + "Category": "Mouse", + "Value": 732, + "ColorVal": 26 + }, + { + "Category": "Mouse", + "Value": 56, + "ColorVal": 27 + }, + { + "Category": "Mouse", + "Value": 886, + "ColorVal": 28 + }, + { + "Category": "Mouse", + "Value": 943, + "ColorVal": 29 + }, + { + "Category": "Mouse", + "Value": 744, + "ColorVal": 30 + }, + { + "Category": "Mouse", + "Value": 948, + "ColorVal": 31 + }, + { + "Category": "Mouse", + "Value": 328, + "ColorVal": 32 + }, + { + "Category": "Mouse", + "Value": 854, + "ColorVal": 33 + }, + { + "Category": "Mouse", + "Value": 960, + "ColorVal": 34 + }, + { + "Category": "Mouse", + "Value": 386, + "ColorVal": 35 + }, + { + "Category": "Mouse", + "Value": 379, + "ColorVal": 36 + }, + { + "Category": "Mouse", + "Value": 128, + "ColorVal": 37 + }, + { + "Category": "Mouse", + "Value": 293, + "ColorVal": 38 + }, + { + "Category": "Mouse", + "Value": 557, + "ColorVal": 39 + }, + { + "Category": "Mouse", + "Value": 235, + "ColorVal": 40 + }, + { + "Category": "Mouse", + "Value": 685, + "ColorVal": 41 + }, + { + "Category": "Mouse", + "Value": 955, + "ColorVal": 42 + }, + { + "Category": "Mouse", + "Value": 590, + "ColorVal": 43 + }, + { + "Category": "Mouse", + "Value": 747, + "ColorVal": 44 + }, + { + "Category": "Mouse", + "Value": 349, + "ColorVal": 45 + }, + { + "Category": "Mouse", + "Value": 311, + "ColorVal": 46 + }, + { + "Category": "Mouse", + "Value": 389, + "ColorVal": 47 + }, + { + "Category": "Mouse", + "Value": 557, + "ColorVal": 48 + }, + { + "Category": "Mouse", + "Value": 226, + "ColorVal": 49 + }, + { + "Category": "Mouse", + "Value": 479, + "ColorVal": 50 + }, + { + "Category": "Headphones", + "Value": 665, + "ColorVal": 1 + }, + { + "Category": "Headphones", + "Value": 875, + "ColorVal": 2 + }, + { + "Category": "Headphones", + "Value": 324, + "ColorVal": 3 + }, + { + "Category": "Headphones", + "Value": 778, + "ColorVal": 4 + }, + { + "Category": "Headphones", + "Value": 436, + "ColorVal": 5 + }, + { + "Category": "Headphones", + "Value": 191, + "ColorVal": 6 + }, + { + "Category": "Headphones", + "Value": 120, + "ColorVal": 7 + }, + { + "Category": "Headphones", + "Value": 248, + "ColorVal": 8 + }, + { + "Category": "Headphones", + "Value": 678, + "ColorVal": 9 + }, + { + "Category": "Headphones", + "Value": 394, + "ColorVal": 10 + }, + { + "Category": "Headphones", + "Value": 503, + "ColorVal": 11 + }, + { + "Category": "Headphones", + "Value": 52, + "ColorVal": 12 + }, + { + "Category": "Headphones", + "Value": 332, + "ColorVal": 13 + }, + { + "Category": "Headphones", + "Value": 304, + "ColorVal": 14 + }, + { + "Category": "Headphones", + "Value": 849, + "ColorVal": 15 + }, + { + "Category": "Headphones", + "Value": 372, + "ColorVal": 16 + }, + { + "Category": "Headphones", + "Value": 24, + "ColorVal": 17 + }, + { + "Category": "Headphones", + "Value": 246, + "ColorVal": 18 + }, + { + "Category": "Headphones", + "Value": 735, + "ColorVal": 19 + }, + { + "Category": "Headphones", + "Value": 427, + "ColorVal": 20 + }, + { + "Category": "Headphones", + "Value": 981, + "ColorVal": 21 + }, + { + "Category": "Headphones", + "Value": 668, + "ColorVal": 22 + }, + { + "Category": "Headphones", + "Value": 492, + "ColorVal": 23 + }, + { + "Category": "Headphones", + "Value": 168, + "ColorVal": 24 + }, + { + "Category": "Headphones", + "Value": 850, + "ColorVal": 25 + }, + { + "Category": "Headphones", + "Value": 68, + "ColorVal": 26 + }, + { + "Category": "Headphones", + "Value": 754, + "ColorVal": 27 + }, + { + "Category": "Headphones", + "Value": 573, + "ColorVal": 28 + }, + { + "Category": "Headphones", + "Value": 704, + "ColorVal": 29 + }, + { + "Category": "Headphones", + "Value": 962, + "ColorVal": 30 + }, + { + "Category": "Headphones", + "Value": 21, + "ColorVal": 31 + }, + { + "Category": "Headphones", + "Value": 959, + "ColorVal": 32 + }, + { + "Category": "Headphones", + "Value": 746, + "ColorVal": 33 + }, + { + "Category": "Headphones", + "Value": 243, + "ColorVal": 34 + }, + { + "Category": "Headphones", + "Value": 431, + "ColorVal": 35 + }, + { + "Category": "Headphones", + "Value": 866, + "ColorVal": 36 + }, + { + "Category": "Headphones", + "Value": 938, + "ColorVal": 37 + }, + { + "Category": "Headphones", + "Value": 679, + "ColorVal": 38 + }, + { + "Category": "Headphones", + "Value": 751, + "ColorVal": 39 + }, + { + "Category": "Headphones", + "Value": 862, + "ColorVal": 40 + }, + { + "Category": "Headphones", + "Value": 44, + "ColorVal": 41 + }, + { + "Category": "Headphones", + "Value": 721, + "ColorVal": 42 + }, + { + "Category": "Headphones", + "Value": 816, + "ColorVal": 43 + }, + { + "Category": "Headphones", + "Value": 956, + "ColorVal": 44 + }, + { + "Category": "Headphones", + "Value": 316, + "ColorVal": 45 + }, + { + "Category": "Headphones", + "Value": 49, + "ColorVal": 46 + }, + { + "Category": "Headphones", + "Value": 929, + "ColorVal": 47 + }, + { + "Category": "Headphones", + "Value": 414, + "ColorVal": 48 + }, + { + "Category": "Headphones", + "Value": 786, + "ColorVal": 49 + }, + { + "Category": "Headphones", + "Value": 915, + "ColorVal": 50 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/grouped-bar-chart/09-card5.flint.json b/test-harness/excel/evaluations/inputs/grouped-bar-chart/09-card5.flint.json new file mode 100644 index 00000000..f7dfa563 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/grouped-bar-chart/09-card5.flint.json @@ -0,0 +1,273 @@ +{ + "semantic_types": { + "Category": "Category", + "Value": "Quantity", + "ColorVal": "Quantity" + }, + "chart_spec": { + "chartType": "Grouped Bar Chart", + "encodings": { + "x": "Category", + "y": "Value", + "group": "ColorVal" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Laptop", + "Value": 463, + "ColorVal": 32.32 + }, + { + "Category": "Laptop", + "Value": 566, + "ColorVal": 38.29 + }, + { + "Category": "Laptop", + "Value": 529, + "ColorVal": 37.65 + }, + { + "Category": "Laptop", + "Value": 922, + "ColorVal": 9.81 + }, + { + "Category": "Laptop", + "Value": 788, + "ColorVal": 10.93 + }, + { + "Category": "Laptop", + "Value": 527, + "ColorVal": 1.86 + }, + { + "Category": "Laptop", + "Value": 991, + "ColorVal": 11.69 + }, + { + "Category": "Laptop", + "Value": 581, + "ColorVal": 16.23 + }, + { + "Category": "Laptop", + "Value": 297, + "ColorVal": 30.57 + }, + { + "Category": "Laptop", + "Value": 634, + "ColorVal": 14.39 + }, + { + "Category": "Phone", + "Value": 611, + "ColorVal": 28.8 + }, + { + "Category": "Phone", + "Value": 766, + "ColorVal": 11.33 + }, + { + "Category": "Phone", + "Value": 665, + "ColorVal": 2.13 + }, + { + "Category": "Phone", + "Value": 593, + "ColorVal": 6.47 + }, + { + "Category": "Phone", + "Value": 228, + "ColorVal": 35.89 + }, + { + "Category": "Phone", + "Value": 235, + "ColorVal": 34.12 + }, + { + "Category": "Phone", + "Value": 46, + "ColorVal": 34.35 + }, + { + "Category": "Phone", + "Value": 15, + "ColorVal": 3.86 + }, + { + "Category": "Phone", + "Value": 745, + "ColorVal": 18.13 + }, + { + "Category": "Phone", + "Value": 528, + "ColorVal": 37.92 + }, + { + "Category": "Tablet", + "Value": 52, + "ColorVal": 16.96 + }, + { + "Category": "Tablet", + "Value": 846, + "ColorVal": 35.69 + }, + { + "Category": "Tablet", + "Value": 738, + "ColorVal": 28.15 + }, + { + "Category": "Tablet", + "Value": 90, + "ColorVal": 28.1 + }, + { + "Category": "Tablet", + "Value": 865, + "ColorVal": 18.43 + }, + { + "Category": "Tablet", + "Value": 698, + "ColorVal": 1.59 + }, + { + "Category": "Tablet", + "Value": 843, + "ColorVal": 25.45 + }, + { + "Category": "Tablet", + "Value": 68, + "ColorVal": 24.81 + }, + { + "Category": "Tablet", + "Value": 426, + "ColorVal": 32.88 + }, + { + "Category": "Tablet", + "Value": 786, + "ColorVal": 34.33 + }, + { + "Category": "Desktop", + "Value": 25, + "ColorVal": 10.99 + }, + { + "Category": "Desktop", + "Value": 884, + "ColorVal": 37.34 + }, + { + "Category": "Desktop", + "Value": 720, + "ColorVal": 37.94 + }, + { + "Category": "Desktop", + "Value": 475, + "ColorVal": 28.42 + }, + { + "Category": "Desktop", + "Value": 217, + "ColorVal": 12.06 + }, + { + "Category": "Desktop", + "Value": 852, + "ColorVal": 11.68 + }, + { + "Category": "Desktop", + "Value": 86, + "ColorVal": 18.77 + }, + { + "Category": "Desktop", + "Value": 463, + "ColorVal": 2.28 + }, + { + "Category": "Desktop", + "Value": 316, + "ColorVal": 16.39 + }, + { + "Category": "Desktop", + "Value": 250, + "ColorVal": 26.99 + }, + { + "Category": "Monitor", + "Value": 680, + "ColorVal": 9.95 + }, + { + "Category": "Monitor", + "Value": 591, + "ColorVal": 38.38 + }, + { + "Category": "Monitor", + "Value": 343, + "ColorVal": 9.6 + }, + { + "Category": "Monitor", + "Value": 307, + "ColorVal": 3.78 + }, + { + "Category": "Monitor", + "Value": 324, + "ColorVal": 15.43 + }, + { + "Category": "Monitor", + "Value": 613, + "ColorVal": 16.55 + }, + { + "Category": "Monitor", + "Value": 55, + "ColorVal": 30.47 + }, + { + "Category": "Monitor", + "Value": 759, + "ColorVal": 31.68 + }, + { + "Category": "Monitor", + "Value": 465, + "ColorVal": 18.57 + }, + { + "Category": "Monitor", + "Value": 282, + "ColorVal": 23.85 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/grouped-bar-chart/10-card5.flint.json b/test-harness/excel/evaluations/inputs/grouped-bar-chart/10-card5.flint.json new file mode 100644 index 00000000..b6e65f8c --- /dev/null +++ b/test-harness/excel/evaluations/inputs/grouped-bar-chart/10-card5.flint.json @@ -0,0 +1,123 @@ +{ + "semantic_types": { + "Category": "Category", + "Group": "Category", + "Segment": "Category" + }, + "chart_spec": { + "chartType": "Grouped Bar Chart", + "encodings": { + "x": "Category", + "y": "Group", + "group": "Segment" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Laptop", + "Group": "USA", + "Segment": "Engineering" + }, + { + "Category": "Laptop", + "Group": "China", + "Segment": "Marketing" + }, + { + "Category": "Laptop", + "Group": "Japan", + "Segment": "Sales" + }, + { + "Category": "Laptop", + "Group": "Germany", + "Segment": "Engineering" + }, + { + "Category": "Phone", + "Group": "China", + "Segment": "Marketing" + }, + { + "Category": "Phone", + "Group": "Japan", + "Segment": "Marketing" + }, + { + "Category": "Phone", + "Group": "Germany", + "Segment": "Marketing" + }, + { + "Category": "Phone", + "Group": "UK", + "Segment": "Engineering" + }, + { + "Category": "Tablet", + "Group": "China", + "Segment": "Marketing" + }, + { + "Category": "Tablet", + "Group": "Japan", + "Segment": "Sales" + }, + { + "Category": "Tablet", + "Group": "Germany", + "Segment": "Marketing" + }, + { + "Category": "Desktop", + "Group": "USA", + "Segment": "Marketing" + }, + { + "Category": "Desktop", + "Group": "China", + "Segment": "Engineering" + }, + { + "Category": "Desktop", + "Group": "Japan", + "Segment": "Sales" + }, + { + "Category": "Desktop", + "Group": "Germany", + "Segment": "Engineering" + }, + { + "Category": "Desktop", + "Group": "UK", + "Segment": "Sales" + }, + { + "Category": "Monitor", + "Group": "USA", + "Segment": "Marketing" + }, + { + "Category": "Monitor", + "Group": "China", + "Segment": "Sales" + }, + { + "Category": "Monitor", + "Group": "Japan", + "Segment": "Marketing" + }, + { + "Category": "Monitor", + "Group": "Germany", + "Segment": "Marketing" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/grouped-bar-chart/11-card5.flint.json b/test-harness/excel/evaluations/inputs/grouped-bar-chart/11-card5.flint.json new file mode 100644 index 00000000..162de392 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/grouped-bar-chart/11-card5.flint.json @@ -0,0 +1,42 @@ +{ + "semantic_types": { + "Region": "Category", + "Sales": "Quantity" + }, + "chart_spec": { + "chartType": "Grouped Bar Chart", + "encodings": { + "x": "Region", + "y": "Sales", + "group": "Region" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Region": "Electronics", + "Sales": 300 + }, + { + "Region": "Clothing", + "Sales": 527 + }, + { + "Region": "Food", + "Sales": 975 + }, + { + "Region": "Books", + "Sales": 311 + }, + { + "Region": "Sports", + "Sales": 930 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/grouped-bar-chart/12-card6.flint.json b/test-harness/excel/evaluations/inputs/grouped-bar-chart/12-card6.flint.json new file mode 100644 index 00000000..c8a3829b --- /dev/null +++ b/test-harness/excel/evaluations/inputs/grouped-bar-chart/12-card6.flint.json @@ -0,0 +1,93 @@ +{ + "semantic_types": { + "Region": "Category", + "Sales": "Quantity", + "Channel": "Category" + }, + "chart_spec": { + "chartType": "Grouped Bar Chart", + "encodings": { + "x": "Region", + "y": "Sales", + "group": "Channel" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Region": "North", + "Channel": "Retail", + "Sales": 901 + }, + { + "Region": "North", + "Channel": "Online", + "Sales": 625 + }, + { + "Region": "South", + "Channel": "Online", + "Sales": 481 + }, + { + "Region": "South", + "Channel": "Wholesale", + "Sales": 331 + }, + { + "Region": "South", + "Channel": "Direct", + "Sales": 841 + }, + { + "Region": "East", + "Channel": "Wholesale", + "Sales": 818 + }, + { + "Region": "East", + "Channel": "Direct", + "Sales": 594 + }, + { + "Region": "West", + "Channel": "Retail", + "Sales": 330 + }, + { + "Region": "West", + "Channel": "Direct", + "Sales": 699 + }, + { + "Region": "Central", + "Channel": "Retail", + "Sales": 460 + }, + { + "Region": "Central", + "Channel": "Online", + "Sales": 903 + }, + { + "Region": "Central", + "Channel": "Wholesale", + "Sales": 981 + }, + { + "Region": "Coast", + "Channel": "Online", + "Sales": 882 + }, + { + "Region": "Coast", + "Channel": "Direct", + "Sales": 966 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/grouped-bar-chart/13-card6.flint.json b/test-harness/excel/evaluations/inputs/grouped-bar-chart/13-card6.flint.json new file mode 100644 index 00000000..6bee1735 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/grouped-bar-chart/13-card6.flint.json @@ -0,0 +1,96 @@ +{ + "semantic_types": { + "Region": "Category", + "Sales": "Quantity", + "Channel": "Category" + }, + "chart_spec": { + "chartType": "Grouped Bar Chart", + "encodings": { + "x": "Region", + "y": "Sales", + "group": "Channel" + }, + "baseSize": { + "width": 560, + "height": 360 + }, + "chartProperties": { + "dodge": "global" + } + }, + "data": { + "values": [ + { + "Region": "North", + "Channel": "Retail", + "Sales": 300 + }, + { + "Region": "North", + "Channel": "Online", + "Sales": 330 + }, + { + "Region": "South", + "Channel": "Online", + "Sales": 340 + }, + { + "Region": "South", + "Channel": "Wholesale", + "Sales": 370 + }, + { + "Region": "South", + "Channel": "Direct", + "Sales": 400 + }, + { + "Region": "East", + "Channel": "Wholesale", + "Sales": 380 + }, + { + "Region": "East", + "Channel": "Direct", + "Sales": 410 + }, + { + "Region": "West", + "Channel": "Retail", + "Sales": 420 + }, + { + "Region": "West", + "Channel": "Direct", + "Sales": 450 + }, + { + "Region": "Central", + "Channel": "Retail", + "Sales": 460 + }, + { + "Region": "Central", + "Channel": "Online", + "Sales": 490 + }, + { + "Region": "Central", + "Channel": "Wholesale", + "Sales": 520 + }, + { + "Region": "Coast", + "Channel": "Online", + "Sales": 500 + }, + { + "Region": "Coast", + "Channel": "Direct", + "Sales": 530 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/grouped-bar-chart/14-card6.flint.json b/test-harness/excel/evaluations/inputs/grouped-bar-chart/14-card6.flint.json new file mode 100644 index 00000000..589da374 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/grouped-bar-chart/14-card6.flint.json @@ -0,0 +1,96 @@ +{ + "semantic_types": { + "Region": "Category", + "Sales": "Quantity", + "Channel": "Category" + }, + "chart_spec": { + "chartType": "Grouped Bar Chart", + "encodings": { + "x": "Region", + "y": "Sales", + "group": "Channel" + }, + "baseSize": { + "width": 560, + "height": 360 + }, + "chartProperties": { + "dodge": "local" + } + }, + "data": { + "values": [ + { + "Region": "North", + "Channel": "Retail", + "Sales": 300 + }, + { + "Region": "North", + "Channel": "Online", + "Sales": 330 + }, + { + "Region": "South", + "Channel": "Online", + "Sales": 340 + }, + { + "Region": "South", + "Channel": "Wholesale", + "Sales": 370 + }, + { + "Region": "South", + "Channel": "Direct", + "Sales": 400 + }, + { + "Region": "East", + "Channel": "Wholesale", + "Sales": 380 + }, + { + "Region": "East", + "Channel": "Direct", + "Sales": 410 + }, + { + "Region": "West", + "Channel": "Retail", + "Sales": 420 + }, + { + "Region": "West", + "Channel": "Direct", + "Sales": 450 + }, + { + "Region": "Central", + "Channel": "Retail", + "Sales": 460 + }, + { + "Region": "Central", + "Channel": "Online", + "Sales": 490 + }, + { + "Region": "Central", + "Channel": "Wholesale", + "Sales": 520 + }, + { + "Region": "Coast", + "Channel": "Online", + "Sales": 500 + }, + { + "Region": "Coast", + "Channel": "Direct", + "Sales": 530 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/heatmap/00-card5.flint.json b/test-harness/excel/evaluations/inputs/heatmap/00-card5.flint.json new file mode 100644 index 00000000..357d9725 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/heatmap/00-card5.flint.json @@ -0,0 +1,173 @@ +{ + "semantic_types": { + "Category": "Category", + "Month": "Month", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Heatmap", + "encodings": { + "x": "Category", + "y": "Month", + "color": "Value" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Electronics", + "Month": "Jan", + "Value": 0 + }, + { + "Category": "Electronics", + "Month": "Feb", + "Value": 77 + }, + { + "Category": "Electronics", + "Month": "Mar", + "Value": 80 + }, + { + "Category": "Electronics", + "Month": "Apr", + "Value": 33 + }, + { + "Category": "Electronics", + "Month": "May", + "Value": 38 + }, + { + "Category": "Electronics", + "Month": "Jun", + "Value": 48 + }, + { + "Category": "Clothing", + "Month": "Jan", + "Value": 52 + }, + { + "Category": "Clothing", + "Month": "Feb", + "Value": 43 + }, + { + "Category": "Clothing", + "Month": "Mar", + "Value": 65 + }, + { + "Category": "Clothing", + "Month": "Apr", + "Value": 35 + }, + { + "Category": "Clothing", + "Month": "May", + "Value": 75 + }, + { + "Category": "Clothing", + "Month": "Jun", + "Value": 71 + }, + { + "Category": "Food", + "Month": "Jan", + "Value": 48 + }, + { + "Category": "Food", + "Month": "Feb", + "Value": 29 + }, + { + "Category": "Food", + "Month": "Mar", + "Value": 73 + }, + { + "Category": "Food", + "Month": "Apr", + "Value": 85 + }, + { + "Category": "Food", + "Month": "May", + "Value": 57 + }, + { + "Category": "Food", + "Month": "Jun", + "Value": 85 + }, + { + "Category": "Books", + "Month": "Jan", + "Value": 71 + }, + { + "Category": "Books", + "Month": "Feb", + "Value": 42 + }, + { + "Category": "Books", + "Month": "Mar", + "Value": 74 + }, + { + "Category": "Books", + "Month": "Apr", + "Value": 39 + }, + { + "Category": "Books", + "Month": "May", + "Value": 49 + }, + { + "Category": "Books", + "Month": "Jun", + "Value": 22 + }, + { + "Category": "Sports", + "Month": "Jan", + "Value": 8 + }, + { + "Category": "Sports", + "Month": "Feb", + "Value": 46 + }, + { + "Category": "Sports", + "Month": "Mar", + "Value": 98 + }, + { + "Category": "Sports", + "Month": "Apr", + "Value": 96 + }, + { + "Category": "Sports", + "Month": "May", + "Value": 100 + }, + { + "Category": "Sports", + "Month": "Jun", + "Value": 60 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/heatmap/01-card10.flint.json b/test-harness/excel/evaluations/inputs/heatmap/01-card10.flint.json new file mode 100644 index 00000000..df9d3793 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/heatmap/01-card10.flint.json @@ -0,0 +1,423 @@ +{ + "semantic_types": { + "X": "Quantity", + "Y": "Quantity", + "Density": "Quantity" + }, + "chart_spec": { + "chartType": "Heatmap", + "encodings": { + "x": "X", + "y": "Y", + "color": "Density" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 0, + "Y": 0, + "Density": 16 + }, + { + "X": 0, + "Y": 5, + "Density": 10 + }, + { + "X": 0, + "Y": 10, + "Density": 23 + }, + { + "X": 0, + "Y": 15, + "Density": 73 + }, + { + "X": 0, + "Y": 20, + "Density": 4 + }, + { + "X": 0, + "Y": 25, + "Density": 12 + }, + { + "X": 0, + "Y": 30, + "Density": 32 + }, + { + "X": 0, + "Y": 35, + "Density": 21 + }, + { + "X": 10, + "Y": 0, + "Density": 52 + }, + { + "X": 10, + "Y": 5, + "Density": 67 + }, + { + "X": 10, + "Y": 10, + "Density": 52 + }, + { + "X": 10, + "Y": 15, + "Density": 28 + }, + { + "X": 10, + "Y": 20, + "Density": 33 + }, + { + "X": 10, + "Y": 25, + "Density": 68 + }, + { + "X": 10, + "Y": 30, + "Density": 76 + }, + { + "X": 10, + "Y": 35, + "Density": 34 + }, + { + "X": 20, + "Y": 0, + "Density": 82 + }, + { + "X": 20, + "Y": 5, + "Density": 35 + }, + { + "X": 20, + "Y": 10, + "Density": 35 + }, + { + "X": 20, + "Y": 15, + "Density": 21 + }, + { + "X": 20, + "Y": 20, + "Density": 25 + }, + { + "X": 20, + "Y": 25, + "Density": 87 + }, + { + "X": 20, + "Y": 30, + "Density": 89 + }, + { + "X": 20, + "Y": 35, + "Density": 45 + }, + { + "X": 30, + "Y": 0, + "Density": 63 + }, + { + "X": 30, + "Y": 5, + "Density": 25 + }, + { + "X": 30, + "Y": 10, + "Density": 26 + }, + { + "X": 30, + "Y": 15, + "Density": 83 + }, + { + "X": 30, + "Y": 20, + "Density": 60 + }, + { + "X": 30, + "Y": 25, + "Density": 28 + }, + { + "X": 30, + "Y": 30, + "Density": 33 + }, + { + "X": 30, + "Y": 35, + "Density": 26 + }, + { + "X": 40, + "Y": 0, + "Density": 15 + }, + { + "X": 40, + "Y": 5, + "Density": 52 + }, + { + "X": 40, + "Y": 10, + "Density": 32 + }, + { + "X": 40, + "Y": 15, + "Density": 99 + }, + { + "X": 40, + "Y": 20, + "Density": 7 + }, + { + "X": 40, + "Y": 25, + "Density": 37 + }, + { + "X": 40, + "Y": 30, + "Density": 88 + }, + { + "X": 40, + "Y": 35, + "Density": 87 + }, + { + "X": 50, + "Y": 0, + "Density": 35 + }, + { + "X": 50, + "Y": 5, + "Density": 7 + }, + { + "X": 50, + "Y": 10, + "Density": 54 + }, + { + "X": 50, + "Y": 15, + "Density": 91 + }, + { + "X": 50, + "Y": 20, + "Density": 87 + }, + { + "X": 50, + "Y": 25, + "Density": 22 + }, + { + "X": 50, + "Y": 30, + "Density": 49 + }, + { + "X": 50, + "Y": 35, + "Density": 4 + }, + { + "X": 60, + "Y": 0, + "Density": 76 + }, + { + "X": 60, + "Y": 5, + "Density": 10 + }, + { + "X": 60, + "Y": 10, + "Density": 91 + }, + { + "X": 60, + "Y": 15, + "Density": 68 + }, + { + "X": 60, + "Y": 20, + "Density": 93 + }, + { + "X": 60, + "Y": 25, + "Density": 23 + }, + { + "X": 60, + "Y": 30, + "Density": 12 + }, + { + "X": 60, + "Y": 35, + "Density": 77 + }, + { + "X": 70, + "Y": 0, + "Density": 11 + }, + { + "X": 70, + "Y": 5, + "Density": 71 + }, + { + "X": 70, + "Y": 10, + "Density": 73 + }, + { + "X": 70, + "Y": 15, + "Density": 29 + }, + { + "X": 70, + "Y": 20, + "Density": 60 + }, + { + "X": 70, + "Y": 25, + "Density": 16 + }, + { + "X": 70, + "Y": 30, + "Density": 51 + }, + { + "X": 70, + "Y": 35, + "Density": 64 + }, + { + "X": 80, + "Y": 0, + "Density": 56 + }, + { + "X": 80, + "Y": 5, + "Density": 99 + }, + { + "X": 80, + "Y": 10, + "Density": 4 + }, + { + "X": 80, + "Y": 15, + "Density": 76 + }, + { + "X": 80, + "Y": 20, + "Density": 66 + }, + { + "X": 80, + "Y": 25, + "Density": 70 + }, + { + "X": 80, + "Y": 30, + "Density": 65 + }, + { + "X": 80, + "Y": 35, + "Density": 96 + }, + { + "X": 90, + "Y": 0, + "Density": 61 + }, + { + "X": 90, + "Y": 5, + "Density": 16 + }, + { + "X": 90, + "Y": 10, + "Density": 86 + }, + { + "X": 90, + "Y": 15, + "Density": 83 + }, + { + "X": 90, + "Y": 20, + "Density": 20 + }, + { + "X": 90, + "Y": 25, + "Density": 53 + }, + { + "X": 90, + "Y": 30, + "Density": 22 + }, + { + "X": 90, + "Y": 35, + "Density": 24 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/heatmap/02-card50.flint.json b/test-harness/excel/evaluations/inputs/heatmap/02-card50.flint.json new file mode 100644 index 00000000..c3f7777a --- /dev/null +++ b/test-harness/excel/evaluations/inputs/heatmap/02-card50.flint.json @@ -0,0 +1,7523 @@ +{ + "semantic_types": { + "Hour": "Quantity", + "Day": "Quantity", + "Activity": "Quantity" + }, + "chart_spec": { + "chartType": "Heatmap", + "encodings": { + "x": "Hour", + "y": "Day", + "color": "Activity" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Hour": 0, + "Day": 0, + "Activity": 68 + }, + { + "Hour": 0, + "Day": 1, + "Activity": 15 + }, + { + "Hour": 0, + "Day": 2, + "Activity": 29 + }, + { + "Hour": 0, + "Day": 3, + "Activity": 37 + }, + { + "Hour": 0, + "Day": 4, + "Activity": 42 + }, + { + "Hour": 0, + "Day": 5, + "Activity": 2 + }, + { + "Hour": 0, + "Day": 6, + "Activity": 88 + }, + { + "Hour": 0, + "Day": 7, + "Activity": 38 + }, + { + "Hour": 0, + "Day": 8, + "Activity": 35 + }, + { + "Hour": 0, + "Day": 9, + "Activity": 21 + }, + { + "Hour": 0, + "Day": 10, + "Activity": 50 + }, + { + "Hour": 0, + "Day": 11, + "Activity": 29 + }, + { + "Hour": 0, + "Day": 12, + "Activity": 50 + }, + { + "Hour": 0, + "Day": 13, + "Activity": 15 + }, + { + "Hour": 0, + "Day": 14, + "Activity": 44 + }, + { + "Hour": 0, + "Day": 15, + "Activity": 91 + }, + { + "Hour": 0, + "Day": 16, + "Activity": 95 + }, + { + "Hour": 0, + "Day": 17, + "Activity": 96 + }, + { + "Hour": 0, + "Day": 18, + "Activity": 45 + }, + { + "Hour": 0, + "Day": 19, + "Activity": 77 + }, + { + "Hour": 0, + "Day": 20, + "Activity": 50 + }, + { + "Hour": 0, + "Day": 21, + "Activity": 3 + }, + { + "Hour": 0, + "Day": 22, + "Activity": 17 + }, + { + "Hour": 0, + "Day": 23, + "Activity": 67 + }, + { + "Hour": 0, + "Day": 24, + "Activity": 91 + }, + { + "Hour": 0, + "Day": 25, + "Activity": 86 + }, + { + "Hour": 0, + "Day": 26, + "Activity": 87 + }, + { + "Hour": 0, + "Day": 27, + "Activity": 77 + }, + { + "Hour": 0, + "Day": 28, + "Activity": 59 + }, + { + "Hour": 0, + "Day": 29, + "Activity": 79 + }, + { + "Hour": 1, + "Day": 0, + "Activity": 5 + }, + { + "Hour": 1, + "Day": 1, + "Activity": 70 + }, + { + "Hour": 1, + "Day": 2, + "Activity": 7 + }, + { + "Hour": 1, + "Day": 3, + "Activity": 8 + }, + { + "Hour": 1, + "Day": 4, + "Activity": 65 + }, + { + "Hour": 1, + "Day": 5, + "Activity": 38 + }, + { + "Hour": 1, + "Day": 6, + "Activity": 91 + }, + { + "Hour": 1, + "Day": 7, + "Activity": 45 + }, + { + "Hour": 1, + "Day": 8, + "Activity": 6 + }, + { + "Hour": 1, + "Day": 9, + "Activity": 26 + }, + { + "Hour": 1, + "Day": 10, + "Activity": 2 + }, + { + "Hour": 1, + "Day": 11, + "Activity": 55 + }, + { + "Hour": 1, + "Day": 12, + "Activity": 2 + }, + { + "Hour": 1, + "Day": 13, + "Activity": 88 + }, + { + "Hour": 1, + "Day": 14, + "Activity": 62 + }, + { + "Hour": 1, + "Day": 15, + "Activity": 63 + }, + { + "Hour": 1, + "Day": 16, + "Activity": 36 + }, + { + "Hour": 1, + "Day": 17, + "Activity": 63 + }, + { + "Hour": 1, + "Day": 18, + "Activity": 82 + }, + { + "Hour": 1, + "Day": 19, + "Activity": 54 + }, + { + "Hour": 1, + "Day": 20, + "Activity": 92 + }, + { + "Hour": 1, + "Day": 21, + "Activity": 22 + }, + { + "Hour": 1, + "Day": 22, + "Activity": 66 + }, + { + "Hour": 1, + "Day": 23, + "Activity": 63 + }, + { + "Hour": 1, + "Day": 24, + "Activity": 19 + }, + { + "Hour": 1, + "Day": 25, + "Activity": 84 + }, + { + "Hour": 1, + "Day": 26, + "Activity": 25 + }, + { + "Hour": 1, + "Day": 27, + "Activity": 1 + }, + { + "Hour": 1, + "Day": 28, + "Activity": 74 + }, + { + "Hour": 1, + "Day": 29, + "Activity": 16 + }, + { + "Hour": 2, + "Day": 0, + "Activity": 59 + }, + { + "Hour": 2, + "Day": 1, + "Activity": 82 + }, + { + "Hour": 2, + "Day": 2, + "Activity": 9 + }, + { + "Hour": 2, + "Day": 3, + "Activity": 10 + }, + { + "Hour": 2, + "Day": 4, + "Activity": 53 + }, + { + "Hour": 2, + "Day": 5, + "Activity": 67 + }, + { + "Hour": 2, + "Day": 6, + "Activity": 53 + }, + { + "Hour": 2, + "Day": 7, + "Activity": 55 + }, + { + "Hour": 2, + "Day": 8, + "Activity": 58 + }, + { + "Hour": 2, + "Day": 9, + "Activity": 65 + }, + { + "Hour": 2, + "Day": 10, + "Activity": 76 + }, + { + "Hour": 2, + "Day": 11, + "Activity": 15 + }, + { + "Hour": 2, + "Day": 12, + "Activity": 47 + }, + { + "Hour": 2, + "Day": 13, + "Activity": 84 + }, + { + "Hour": 2, + "Day": 14, + "Activity": 82 + }, + { + "Hour": 2, + "Day": 15, + "Activity": 62 + }, + { + "Hour": 2, + "Day": 16, + "Activity": 80 + }, + { + "Hour": 2, + "Day": 17, + "Activity": 46 + }, + { + "Hour": 2, + "Day": 18, + "Activity": 6 + }, + { + "Hour": 2, + "Day": 19, + "Activity": 43 + }, + { + "Hour": 2, + "Day": 20, + "Activity": 63 + }, + { + "Hour": 2, + "Day": 21, + "Activity": 98 + }, + { + "Hour": 2, + "Day": 22, + "Activity": 20 + }, + { + "Hour": 2, + "Day": 23, + "Activity": 78 + }, + { + "Hour": 2, + "Day": 24, + "Activity": 92 + }, + { + "Hour": 2, + "Day": 25, + "Activity": 12 + }, + { + "Hour": 2, + "Day": 26, + "Activity": 68 + }, + { + "Hour": 2, + "Day": 27, + "Activity": 37 + }, + { + "Hour": 2, + "Day": 28, + "Activity": 67 + }, + { + "Hour": 2, + "Day": 29, + "Activity": 35 + }, + { + "Hour": 3, + "Day": 0, + "Activity": 49 + }, + { + "Hour": 3, + "Day": 1, + "Activity": 10 + }, + { + "Hour": 3, + "Day": 2, + "Activity": 57 + }, + { + "Hour": 3, + "Day": 3, + "Activity": 21 + }, + { + "Hour": 3, + "Day": 4, + "Activity": 63 + }, + { + "Hour": 3, + "Day": 5, + "Activity": 66 + }, + { + "Hour": 3, + "Day": 6, + "Activity": 71 + }, + { + "Hour": 3, + "Day": 7, + "Activity": 22 + }, + { + "Hour": 3, + "Day": 8, + "Activity": 72 + }, + { + "Hour": 3, + "Day": 9, + "Activity": 1 + }, + { + "Hour": 3, + "Day": 10, + "Activity": 36 + }, + { + "Hour": 3, + "Day": 11, + "Activity": 28 + }, + { + "Hour": 3, + "Day": 12, + "Activity": 2 + }, + { + "Hour": 3, + "Day": 13, + "Activity": 87 + }, + { + "Hour": 3, + "Day": 14, + "Activity": 63 + }, + { + "Hour": 3, + "Day": 15, + "Activity": 82 + }, + { + "Hour": 3, + "Day": 16, + "Activity": 36 + }, + { + "Hour": 3, + "Day": 17, + "Activity": 27 + }, + { + "Hour": 3, + "Day": 18, + "Activity": 86 + }, + { + "Hour": 3, + "Day": 19, + "Activity": 55 + }, + { + "Hour": 3, + "Day": 20, + "Activity": 2 + }, + { + "Hour": 3, + "Day": 21, + "Activity": 49 + }, + { + "Hour": 3, + "Day": 22, + "Activity": 66 + }, + { + "Hour": 3, + "Day": 23, + "Activity": 60 + }, + { + "Hour": 3, + "Day": 24, + "Activity": 71 + }, + { + "Hour": 3, + "Day": 25, + "Activity": 47 + }, + { + "Hour": 3, + "Day": 26, + "Activity": 84 + }, + { + "Hour": 3, + "Day": 27, + "Activity": 2 + }, + { + "Hour": 3, + "Day": 28, + "Activity": 78 + }, + { + "Hour": 3, + "Day": 29, + "Activity": 32 + }, + { + "Hour": 4, + "Day": 0, + "Activity": 94 + }, + { + "Hour": 4, + "Day": 1, + "Activity": 1 + }, + { + "Hour": 4, + "Day": 2, + "Activity": 97 + }, + { + "Hour": 4, + "Day": 3, + "Activity": 60 + }, + { + "Hour": 4, + "Day": 4, + "Activity": 17 + }, + { + "Hour": 4, + "Day": 5, + "Activity": 68 + }, + { + "Hour": 4, + "Day": 6, + "Activity": 77 + }, + { + "Hour": 4, + "Day": 7, + "Activity": 1 + }, + { + "Hour": 4, + "Day": 8, + "Activity": 87 + }, + { + "Hour": 4, + "Day": 9, + "Activity": 33 + }, + { + "Hour": 4, + "Day": 10, + "Activity": 75 + }, + { + "Hour": 4, + "Day": 11, + "Activity": 86 + }, + { + "Hour": 4, + "Day": 12, + "Activity": 77 + }, + { + "Hour": 4, + "Day": 13, + "Activity": 32 + }, + { + "Hour": 4, + "Day": 14, + "Activity": 58 + }, + { + "Hour": 4, + "Day": 15, + "Activity": 76 + }, + { + "Hour": 4, + "Day": 16, + "Activity": 56 + }, + { + "Hour": 4, + "Day": 17, + "Activity": 80 + }, + { + "Hour": 4, + "Day": 18, + "Activity": 24 + }, + { + "Hour": 4, + "Day": 19, + "Activity": 18 + }, + { + "Hour": 4, + "Day": 20, + "Activity": 30 + }, + { + "Hour": 4, + "Day": 21, + "Activity": 44 + }, + { + "Hour": 4, + "Day": 22, + "Activity": 68 + }, + { + "Hour": 4, + "Day": 23, + "Activity": 67 + }, + { + "Hour": 4, + "Day": 24, + "Activity": 59 + }, + { + "Hour": 4, + "Day": 25, + "Activity": 86 + }, + { + "Hour": 4, + "Day": 26, + "Activity": 25 + }, + { + "Hour": 4, + "Day": 27, + "Activity": 28 + }, + { + "Hour": 4, + "Day": 28, + "Activity": 63 + }, + { + "Hour": 4, + "Day": 29, + "Activity": 21 + }, + { + "Hour": 5, + "Day": 0, + "Activity": 46 + }, + { + "Hour": 5, + "Day": 1, + "Activity": 35 + }, + { + "Hour": 5, + "Day": 2, + "Activity": 27 + }, + { + "Hour": 5, + "Day": 3, + "Activity": 87 + }, + { + "Hour": 5, + "Day": 4, + "Activity": 0 + }, + { + "Hour": 5, + "Day": 5, + "Activity": 79 + }, + { + "Hour": 5, + "Day": 6, + "Activity": 93 + }, + { + "Hour": 5, + "Day": 7, + "Activity": 77 + }, + { + "Hour": 5, + "Day": 8, + "Activity": 53 + }, + { + "Hour": 5, + "Day": 9, + "Activity": 41 + }, + { + "Hour": 5, + "Day": 10, + "Activity": 8 + }, + { + "Hour": 5, + "Day": 11, + "Activity": 77 + }, + { + "Hour": 5, + "Day": 12, + "Activity": 93 + }, + { + "Hour": 5, + "Day": 13, + "Activity": 61 + }, + { + "Hour": 5, + "Day": 14, + "Activity": 8 + }, + { + "Hour": 5, + "Day": 15, + "Activity": 2 + }, + { + "Hour": 5, + "Day": 16, + "Activity": 43 + }, + { + "Hour": 5, + "Day": 17, + "Activity": 93 + }, + { + "Hour": 5, + "Day": 18, + "Activity": 23 + }, + { + "Hour": 5, + "Day": 19, + "Activity": 8 + }, + { + "Hour": 5, + "Day": 20, + "Activity": 98 + }, + { + "Hour": 5, + "Day": 21, + "Activity": 66 + }, + { + "Hour": 5, + "Day": 22, + "Activity": 91 + }, + { + "Hour": 5, + "Day": 23, + "Activity": 62 + }, + { + "Hour": 5, + "Day": 24, + "Activity": 3 + }, + { + "Hour": 5, + "Day": 25, + "Activity": 86 + }, + { + "Hour": 5, + "Day": 26, + "Activity": 23 + }, + { + "Hour": 5, + "Day": 27, + "Activity": 7 + }, + { + "Hour": 5, + "Day": 28, + "Activity": 51 + }, + { + "Hour": 5, + "Day": 29, + "Activity": 44 + }, + { + "Hour": 6, + "Day": 0, + "Activity": 18 + }, + { + "Hour": 6, + "Day": 1, + "Activity": 87 + }, + { + "Hour": 6, + "Day": 2, + "Activity": 97 + }, + { + "Hour": 6, + "Day": 3, + "Activity": 58 + }, + { + "Hour": 6, + "Day": 4, + "Activity": 80 + }, + { + "Hour": 6, + "Day": 5, + "Activity": 82 + }, + { + "Hour": 6, + "Day": 6, + "Activity": 71 + }, + { + "Hour": 6, + "Day": 7, + "Activity": 36 + }, + { + "Hour": 6, + "Day": 8, + "Activity": 0 + }, + { + "Hour": 6, + "Day": 9, + "Activity": 38 + }, + { + "Hour": 6, + "Day": 10, + "Activity": 12 + }, + { + "Hour": 6, + "Day": 11, + "Activity": 47 + }, + { + "Hour": 6, + "Day": 12, + "Activity": 76 + }, + { + "Hour": 6, + "Day": 13, + "Activity": 71 + }, + { + "Hour": 6, + "Day": 14, + "Activity": 22 + }, + { + "Hour": 6, + "Day": 15, + "Activity": 11 + }, + { + "Hour": 6, + "Day": 16, + "Activity": 50 + }, + { + "Hour": 6, + "Day": 17, + "Activity": 39 + }, + { + "Hour": 6, + "Day": 18, + "Activity": 92 + }, + { + "Hour": 6, + "Day": 19, + "Activity": 72 + }, + { + "Hour": 6, + "Day": 20, + "Activity": 29 + }, + { + "Hour": 6, + "Day": 21, + "Activity": 6 + }, + { + "Hour": 6, + "Day": 22, + "Activity": 96 + }, + { + "Hour": 6, + "Day": 23, + "Activity": 99 + }, + { + "Hour": 6, + "Day": 24, + "Activity": 83 + }, + { + "Hour": 6, + "Day": 25, + "Activity": 49 + }, + { + "Hour": 6, + "Day": 26, + "Activity": 52 + }, + { + "Hour": 6, + "Day": 27, + "Activity": 84 + }, + { + "Hour": 6, + "Day": 28, + "Activity": 66 + }, + { + "Hour": 6, + "Day": 29, + "Activity": 11 + }, + { + "Hour": 7, + "Day": 0, + "Activity": 63 + }, + { + "Hour": 7, + "Day": 1, + "Activity": 42 + }, + { + "Hour": 7, + "Day": 2, + "Activity": 50 + }, + { + "Hour": 7, + "Day": 3, + "Activity": 0 + }, + { + "Hour": 7, + "Day": 4, + "Activity": 67 + }, + { + "Hour": 7, + "Day": 5, + "Activity": 27 + }, + { + "Hour": 7, + "Day": 6, + "Activity": 37 + }, + { + "Hour": 7, + "Day": 7, + "Activity": 6 + }, + { + "Hour": 7, + "Day": 8, + "Activity": 4 + }, + { + "Hour": 7, + "Day": 9, + "Activity": 42 + }, + { + "Hour": 7, + "Day": 10, + "Activity": 42 + }, + { + "Hour": 7, + "Day": 11, + "Activity": 11 + }, + { + "Hour": 7, + "Day": 12, + "Activity": 51 + }, + { + "Hour": 7, + "Day": 13, + "Activity": 43 + }, + { + "Hour": 7, + "Day": 14, + "Activity": 95 + }, + { + "Hour": 7, + "Day": 15, + "Activity": 92 + }, + { + "Hour": 7, + "Day": 16, + "Activity": 65 + }, + { + "Hour": 7, + "Day": 17, + "Activity": 13 + }, + { + "Hour": 7, + "Day": 18, + "Activity": 87 + }, + { + "Hour": 7, + "Day": 19, + "Activity": 96 + }, + { + "Hour": 7, + "Day": 20, + "Activity": 89 + }, + { + "Hour": 7, + "Day": 21, + "Activity": 12 + }, + { + "Hour": 7, + "Day": 22, + "Activity": 97 + }, + { + "Hour": 7, + "Day": 23, + "Activity": 30 + }, + { + "Hour": 7, + "Day": 24, + "Activity": 38 + }, + { + "Hour": 7, + "Day": 25, + "Activity": 38 + }, + { + "Hour": 7, + "Day": 26, + "Activity": 35 + }, + { + "Hour": 7, + "Day": 27, + "Activity": 8 + }, + { + "Hour": 7, + "Day": 28, + "Activity": 78 + }, + { + "Hour": 7, + "Day": 29, + "Activity": 22 + }, + { + "Hour": 8, + "Day": 0, + "Activity": 57 + }, + { + "Hour": 8, + "Day": 1, + "Activity": 68 + }, + { + "Hour": 8, + "Day": 2, + "Activity": 92 + }, + { + "Hour": 8, + "Day": 3, + "Activity": 82 + }, + { + "Hour": 8, + "Day": 4, + "Activity": 25 + }, + { + "Hour": 8, + "Day": 5, + "Activity": 20 + }, + { + "Hour": 8, + "Day": 6, + "Activity": 5 + }, + { + "Hour": 8, + "Day": 7, + "Activity": 91 + }, + { + "Hour": 8, + "Day": 8, + "Activity": 86 + }, + { + "Hour": 8, + "Day": 9, + "Activity": 40 + }, + { + "Hour": 8, + "Day": 10, + "Activity": 62 + }, + { + "Hour": 8, + "Day": 11, + "Activity": 48 + }, + { + "Hour": 8, + "Day": 12, + "Activity": 10 + }, + { + "Hour": 8, + "Day": 13, + "Activity": 49 + }, + { + "Hour": 8, + "Day": 14, + "Activity": 7 + }, + { + "Hour": 8, + "Day": 15, + "Activity": 92 + }, + { + "Hour": 8, + "Day": 16, + "Activity": 31 + }, + { + "Hour": 8, + "Day": 17, + "Activity": 4 + }, + { + "Hour": 8, + "Day": 18, + "Activity": 37 + }, + { + "Hour": 8, + "Day": 19, + "Activity": 99 + }, + { + "Hour": 8, + "Day": 20, + "Activity": 1 + }, + { + "Hour": 8, + "Day": 21, + "Activity": 88 + }, + { + "Hour": 8, + "Day": 22, + "Activity": 55 + }, + { + "Hour": 8, + "Day": 23, + "Activity": 4 + }, + { + "Hour": 8, + "Day": 24, + "Activity": 37 + }, + { + "Hour": 8, + "Day": 25, + "Activity": 47 + }, + { + "Hour": 8, + "Day": 26, + "Activity": 91 + }, + { + "Hour": 8, + "Day": 27, + "Activity": 32 + }, + { + "Hour": 8, + "Day": 28, + "Activity": 21 + }, + { + "Hour": 8, + "Day": 29, + "Activity": 86 + }, + { + "Hour": 9, + "Day": 0, + "Activity": 77 + }, + { + "Hour": 9, + "Day": 1, + "Activity": 84 + }, + { + "Hour": 9, + "Day": 2, + "Activity": 76 + }, + { + "Hour": 9, + "Day": 3, + "Activity": 93 + }, + { + "Hour": 9, + "Day": 4, + "Activity": 59 + }, + { + "Hour": 9, + "Day": 5, + "Activity": 13 + }, + { + "Hour": 9, + "Day": 6, + "Activity": 85 + }, + { + "Hour": 9, + "Day": 7, + "Activity": 96 + }, + { + "Hour": 9, + "Day": 8, + "Activity": 54 + }, + { + "Hour": 9, + "Day": 9, + "Activity": 65 + }, + { + "Hour": 9, + "Day": 10, + "Activity": 50 + }, + { + "Hour": 9, + "Day": 11, + "Activity": 34 + }, + { + "Hour": 9, + "Day": 12, + "Activity": 21 + }, + { + "Hour": 9, + "Day": 13, + "Activity": 17 + }, + { + "Hour": 9, + "Day": 14, + "Activity": 39 + }, + { + "Hour": 9, + "Day": 15, + "Activity": 24 + }, + { + "Hour": 9, + "Day": 16, + "Activity": 42 + }, + { + "Hour": 9, + "Day": 17, + "Activity": 1 + }, + { + "Hour": 9, + "Day": 18, + "Activity": 87 + }, + { + "Hour": 9, + "Day": 19, + "Activity": 91 + }, + { + "Hour": 9, + "Day": 20, + "Activity": 88 + }, + { + "Hour": 9, + "Day": 21, + "Activity": 43 + }, + { + "Hour": 9, + "Day": 22, + "Activity": 53 + }, + { + "Hour": 9, + "Day": 23, + "Activity": 66 + }, + { + "Hour": 9, + "Day": 24, + "Activity": 33 + }, + { + "Hour": 9, + "Day": 25, + "Activity": 14 + }, + { + "Hour": 9, + "Day": 26, + "Activity": 97 + }, + { + "Hour": 9, + "Day": 27, + "Activity": 95 + }, + { + "Hour": 9, + "Day": 28, + "Activity": 5 + }, + { + "Hour": 9, + "Day": 29, + "Activity": 8 + }, + { + "Hour": 10, + "Day": 0, + "Activity": 67 + }, + { + "Hour": 10, + "Day": 1, + "Activity": 90 + }, + { + "Hour": 10, + "Day": 2, + "Activity": 48 + }, + { + "Hour": 10, + "Day": 3, + "Activity": 94 + }, + { + "Hour": 10, + "Day": 4, + "Activity": 34 + }, + { + "Hour": 10, + "Day": 5, + "Activity": 64 + }, + { + "Hour": 10, + "Day": 6, + "Activity": 32 + }, + { + "Hour": 10, + "Day": 7, + "Activity": 14 + }, + { + "Hour": 10, + "Day": 8, + "Activity": 88 + }, + { + "Hour": 10, + "Day": 9, + "Activity": 51 + }, + { + "Hour": 10, + "Day": 10, + "Activity": 30 + }, + { + "Hour": 10, + "Day": 11, + "Activity": 90 + }, + { + "Hour": 10, + "Day": 12, + "Activity": 58 + }, + { + "Hour": 10, + "Day": 13, + "Activity": 99 + }, + { + "Hour": 10, + "Day": 14, + "Activity": 24 + }, + { + "Hour": 10, + "Day": 15, + "Activity": 16 + }, + { + "Hour": 10, + "Day": 16, + "Activity": 97 + }, + { + "Hour": 10, + "Day": 17, + "Activity": 84 + }, + { + "Hour": 10, + "Day": 18, + "Activity": 82 + }, + { + "Hour": 10, + "Day": 19, + "Activity": 89 + }, + { + "Hour": 10, + "Day": 20, + "Activity": 58 + }, + { + "Hour": 10, + "Day": 21, + "Activity": 59 + }, + { + "Hour": 10, + "Day": 22, + "Activity": 74 + }, + { + "Hour": 10, + "Day": 23, + "Activity": 44 + }, + { + "Hour": 10, + "Day": 24, + "Activity": 20 + }, + { + "Hour": 10, + "Day": 25, + "Activity": 83 + }, + { + "Hour": 10, + "Day": 26, + "Activity": 10 + }, + { + "Hour": 10, + "Day": 27, + "Activity": 68 + }, + { + "Hour": 10, + "Day": 28, + "Activity": 78 + }, + { + "Hour": 10, + "Day": 29, + "Activity": 83 + }, + { + "Hour": 11, + "Day": 0, + "Activity": 9 + }, + { + "Hour": 11, + "Day": 1, + "Activity": 48 + }, + { + "Hour": 11, + "Day": 2, + "Activity": 67 + }, + { + "Hour": 11, + "Day": 3, + "Activity": 13 + }, + { + "Hour": 11, + "Day": 4, + "Activity": 79 + }, + { + "Hour": 11, + "Day": 5, + "Activity": 25 + }, + { + "Hour": 11, + "Day": 6, + "Activity": 68 + }, + { + "Hour": 11, + "Day": 7, + "Activity": 14 + }, + { + "Hour": 11, + "Day": 8, + "Activity": 66 + }, + { + "Hour": 11, + "Day": 9, + "Activity": 6 + }, + { + "Hour": 11, + "Day": 10, + "Activity": 81 + }, + { + "Hour": 11, + "Day": 11, + "Activity": 97 + }, + { + "Hour": 11, + "Day": 12, + "Activity": 43 + }, + { + "Hour": 11, + "Day": 13, + "Activity": 1 + }, + { + "Hour": 11, + "Day": 14, + "Activity": 46 + }, + { + "Hour": 11, + "Day": 15, + "Activity": 5 + }, + { + "Hour": 11, + "Day": 16, + "Activity": 13 + }, + { + "Hour": 11, + "Day": 17, + "Activity": 51 + }, + { + "Hour": 11, + "Day": 18, + "Activity": 76 + }, + { + "Hour": 11, + "Day": 19, + "Activity": 17 + }, + { + "Hour": 11, + "Day": 20, + "Activity": 52 + }, + { + "Hour": 11, + "Day": 21, + "Activity": 96 + }, + { + "Hour": 11, + "Day": 22, + "Activity": 29 + }, + { + "Hour": 11, + "Day": 23, + "Activity": 31 + }, + { + "Hour": 11, + "Day": 24, + "Activity": 43 + }, + { + "Hour": 11, + "Day": 25, + "Activity": 93 + }, + { + "Hour": 11, + "Day": 26, + "Activity": 81 + }, + { + "Hour": 11, + "Day": 27, + "Activity": 75 + }, + { + "Hour": 11, + "Day": 28, + "Activity": 29 + }, + { + "Hour": 11, + "Day": 29, + "Activity": 78 + }, + { + "Hour": 12, + "Day": 0, + "Activity": 84 + }, + { + "Hour": 12, + "Day": 1, + "Activity": 49 + }, + { + "Hour": 12, + "Day": 2, + "Activity": 4 + }, + { + "Hour": 12, + "Day": 3, + "Activity": 99 + }, + { + "Hour": 12, + "Day": 4, + "Activity": 68 + }, + { + "Hour": 12, + "Day": 5, + "Activity": 95 + }, + { + "Hour": 12, + "Day": 6, + "Activity": 25 + }, + { + "Hour": 12, + "Day": 7, + "Activity": 71 + }, + { + "Hour": 12, + "Day": 8, + "Activity": 66 + }, + { + "Hour": 12, + "Day": 9, + "Activity": 10 + }, + { + "Hour": 12, + "Day": 10, + "Activity": 82 + }, + { + "Hour": 12, + "Day": 11, + "Activity": 67 + }, + { + "Hour": 12, + "Day": 12, + "Activity": 82 + }, + { + "Hour": 12, + "Day": 13, + "Activity": 18 + }, + { + "Hour": 12, + "Day": 14, + "Activity": 12 + }, + { + "Hour": 12, + "Day": 15, + "Activity": 72 + }, + { + "Hour": 12, + "Day": 16, + "Activity": 2 + }, + { + "Hour": 12, + "Day": 17, + "Activity": 8 + }, + { + "Hour": 12, + "Day": 18, + "Activity": 83 + }, + { + "Hour": 12, + "Day": 19, + "Activity": 56 + }, + { + "Hour": 12, + "Day": 20, + "Activity": 98 + }, + { + "Hour": 12, + "Day": 21, + "Activity": 63 + }, + { + "Hour": 12, + "Day": 22, + "Activity": 95 + }, + { + "Hour": 12, + "Day": 23, + "Activity": 83 + }, + { + "Hour": 12, + "Day": 24, + "Activity": 39 + }, + { + "Hour": 12, + "Day": 25, + "Activity": 18 + }, + { + "Hour": 12, + "Day": 26, + "Activity": 29 + }, + { + "Hour": 12, + "Day": 27, + "Activity": 83 + }, + { + "Hour": 12, + "Day": 28, + "Activity": 30 + }, + { + "Hour": 12, + "Day": 29, + "Activity": 31 + }, + { + "Hour": 13, + "Day": 0, + "Activity": 31 + }, + { + "Hour": 13, + "Day": 1, + "Activity": 73 + }, + { + "Hour": 13, + "Day": 2, + "Activity": 40 + }, + { + "Hour": 13, + "Day": 3, + "Activity": 85 + }, + { + "Hour": 13, + "Day": 4, + "Activity": 51 + }, + { + "Hour": 13, + "Day": 5, + "Activity": 96 + }, + { + "Hour": 13, + "Day": 6, + "Activity": 5 + }, + { + "Hour": 13, + "Day": 7, + "Activity": 88 + }, + { + "Hour": 13, + "Day": 8, + "Activity": 82 + }, + { + "Hour": 13, + "Day": 9, + "Activity": 100 + }, + { + "Hour": 13, + "Day": 10, + "Activity": 47 + }, + { + "Hour": 13, + "Day": 11, + "Activity": 58 + }, + { + "Hour": 13, + "Day": 12, + "Activity": 9 + }, + { + "Hour": 13, + "Day": 13, + "Activity": 52 + }, + { + "Hour": 13, + "Day": 14, + "Activity": 1 + }, + { + "Hour": 13, + "Day": 15, + "Activity": 97 + }, + { + "Hour": 13, + "Day": 16, + "Activity": 77 + }, + { + "Hour": 13, + "Day": 17, + "Activity": 94 + }, + { + "Hour": 13, + "Day": 18, + "Activity": 29 + }, + { + "Hour": 13, + "Day": 19, + "Activity": 85 + }, + { + "Hour": 13, + "Day": 20, + "Activity": 82 + }, + { + "Hour": 13, + "Day": 21, + "Activity": 59 + }, + { + "Hour": 13, + "Day": 22, + "Activity": 97 + }, + { + "Hour": 13, + "Day": 23, + "Activity": 68 + }, + { + "Hour": 13, + "Day": 24, + "Activity": 40 + }, + { + "Hour": 13, + "Day": 25, + "Activity": 59 + }, + { + "Hour": 13, + "Day": 26, + "Activity": 87 + }, + { + "Hour": 13, + "Day": 27, + "Activity": 53 + }, + { + "Hour": 13, + "Day": 28, + "Activity": 96 + }, + { + "Hour": 13, + "Day": 29, + "Activity": 64 + }, + { + "Hour": 14, + "Day": 0, + "Activity": 67 + }, + { + "Hour": 14, + "Day": 1, + "Activity": 69 + }, + { + "Hour": 14, + "Day": 2, + "Activity": 26 + }, + { + "Hour": 14, + "Day": 3, + "Activity": 86 + }, + { + "Hour": 14, + "Day": 4, + "Activity": 43 + }, + { + "Hour": 14, + "Day": 5, + "Activity": 48 + }, + { + "Hour": 14, + "Day": 6, + "Activity": 17 + }, + { + "Hour": 14, + "Day": 7, + "Activity": 92 + }, + { + "Hour": 14, + "Day": 8, + "Activity": 17 + }, + { + "Hour": 14, + "Day": 9, + "Activity": 4 + }, + { + "Hour": 14, + "Day": 10, + "Activity": 85 + }, + { + "Hour": 14, + "Day": 11, + "Activity": 59 + }, + { + "Hour": 14, + "Day": 12, + "Activity": 79 + }, + { + "Hour": 14, + "Day": 13, + "Activity": 28 + }, + { + "Hour": 14, + "Day": 14, + "Activity": 95 + }, + { + "Hour": 14, + "Day": 15, + "Activity": 61 + }, + { + "Hour": 14, + "Day": 16, + "Activity": 77 + }, + { + "Hour": 14, + "Day": 17, + "Activity": 39 + }, + { + "Hour": 14, + "Day": 18, + "Activity": 94 + }, + { + "Hour": 14, + "Day": 19, + "Activity": 12 + }, + { + "Hour": 14, + "Day": 20, + "Activity": 30 + }, + { + "Hour": 14, + "Day": 21, + "Activity": 90 + }, + { + "Hour": 14, + "Day": 22, + "Activity": 53 + }, + { + "Hour": 14, + "Day": 23, + "Activity": 62 + }, + { + "Hour": 14, + "Day": 24, + "Activity": 80 + }, + { + "Hour": 14, + "Day": 25, + "Activity": 4 + }, + { + "Hour": 14, + "Day": 26, + "Activity": 75 + }, + { + "Hour": 14, + "Day": 27, + "Activity": 54 + }, + { + "Hour": 14, + "Day": 28, + "Activity": 85 + }, + { + "Hour": 14, + "Day": 29, + "Activity": 22 + }, + { + "Hour": 15, + "Day": 0, + "Activity": 54 + }, + { + "Hour": 15, + "Day": 1, + "Activity": 79 + }, + { + "Hour": 15, + "Day": 2, + "Activity": 19 + }, + { + "Hour": 15, + "Day": 3, + "Activity": 88 + }, + { + "Hour": 15, + "Day": 4, + "Activity": 48 + }, + { + "Hour": 15, + "Day": 5, + "Activity": 19 + }, + { + "Hour": 15, + "Day": 6, + "Activity": 1 + }, + { + "Hour": 15, + "Day": 7, + "Activity": 72 + }, + { + "Hour": 15, + "Day": 8, + "Activity": 41 + }, + { + "Hour": 15, + "Day": 9, + "Activity": 82 + }, + { + "Hour": 15, + "Day": 10, + "Activity": 88 + }, + { + "Hour": 15, + "Day": 11, + "Activity": 78 + }, + { + "Hour": 15, + "Day": 12, + "Activity": 83 + }, + { + "Hour": 15, + "Day": 13, + "Activity": 41 + }, + { + "Hour": 15, + "Day": 14, + "Activity": 50 + }, + { + "Hour": 15, + "Day": 15, + "Activity": 88 + }, + { + "Hour": 15, + "Day": 16, + "Activity": 43 + }, + { + "Hour": 15, + "Day": 17, + "Activity": 68 + }, + { + "Hour": 15, + "Day": 18, + "Activity": 67 + }, + { + "Hour": 15, + "Day": 19, + "Activity": 61 + }, + { + "Hour": 15, + "Day": 20, + "Activity": 6 + }, + { + "Hour": 15, + "Day": 21, + "Activity": 34 + }, + { + "Hour": 15, + "Day": 22, + "Activity": 60 + }, + { + "Hour": 15, + "Day": 23, + "Activity": 41 + }, + { + "Hour": 15, + "Day": 24, + "Activity": 74 + }, + { + "Hour": 15, + "Day": 25, + "Activity": 2 + }, + { + "Hour": 15, + "Day": 26, + "Activity": 93 + }, + { + "Hour": 15, + "Day": 27, + "Activity": 2 + }, + { + "Hour": 15, + "Day": 28, + "Activity": 58 + }, + { + "Hour": 15, + "Day": 29, + "Activity": 0 + }, + { + "Hour": 16, + "Day": 0, + "Activity": 90 + }, + { + "Hour": 16, + "Day": 1, + "Activity": 75 + }, + { + "Hour": 16, + "Day": 2, + "Activity": 23 + }, + { + "Hour": 16, + "Day": 3, + "Activity": 83 + }, + { + "Hour": 16, + "Day": 4, + "Activity": 92 + }, + { + "Hour": 16, + "Day": 5, + "Activity": 17 + }, + { + "Hour": 16, + "Day": 6, + "Activity": 22 + }, + { + "Hour": 16, + "Day": 7, + "Activity": 72 + }, + { + "Hour": 16, + "Day": 8, + "Activity": 4 + }, + { + "Hour": 16, + "Day": 9, + "Activity": 88 + }, + { + "Hour": 16, + "Day": 10, + "Activity": 67 + }, + { + "Hour": 16, + "Day": 11, + "Activity": 71 + }, + { + "Hour": 16, + "Day": 12, + "Activity": 66 + }, + { + "Hour": 16, + "Day": 13, + "Activity": 53 + }, + { + "Hour": 16, + "Day": 14, + "Activity": 87 + }, + { + "Hour": 16, + "Day": 15, + "Activity": 65 + }, + { + "Hour": 16, + "Day": 16, + "Activity": 57 + }, + { + "Hour": 16, + "Day": 17, + "Activity": 26 + }, + { + "Hour": 16, + "Day": 18, + "Activity": 28 + }, + { + "Hour": 16, + "Day": 19, + "Activity": 50 + }, + { + "Hour": 16, + "Day": 20, + "Activity": 85 + }, + { + "Hour": 16, + "Day": 21, + "Activity": 23 + }, + { + "Hour": 16, + "Day": 22, + "Activity": 32 + }, + { + "Hour": 16, + "Day": 23, + "Activity": 89 + }, + { + "Hour": 16, + "Day": 24, + "Activity": 79 + }, + { + "Hour": 16, + "Day": 25, + "Activity": 18 + }, + { + "Hour": 16, + "Day": 26, + "Activity": 32 + }, + { + "Hour": 16, + "Day": 27, + "Activity": 30 + }, + { + "Hour": 16, + "Day": 28, + "Activity": 5 + }, + { + "Hour": 16, + "Day": 29, + "Activity": 75 + }, + { + "Hour": 17, + "Day": 0, + "Activity": 59 + }, + { + "Hour": 17, + "Day": 1, + "Activity": 62 + }, + { + "Hour": 17, + "Day": 2, + "Activity": 26 + }, + { + "Hour": 17, + "Day": 3, + "Activity": 12 + }, + { + "Hour": 17, + "Day": 4, + "Activity": 89 + }, + { + "Hour": 17, + "Day": 5, + "Activity": 82 + }, + { + "Hour": 17, + "Day": 6, + "Activity": 59 + }, + { + "Hour": 17, + "Day": 7, + "Activity": 79 + }, + { + "Hour": 17, + "Day": 8, + "Activity": 45 + }, + { + "Hour": 17, + "Day": 9, + "Activity": 79 + }, + { + "Hour": 17, + "Day": 10, + "Activity": 4 + }, + { + "Hour": 17, + "Day": 11, + "Activity": 26 + }, + { + "Hour": 17, + "Day": 12, + "Activity": 31 + }, + { + "Hour": 17, + "Day": 13, + "Activity": 79 + }, + { + "Hour": 17, + "Day": 14, + "Activity": 66 + }, + { + "Hour": 17, + "Day": 15, + "Activity": 45 + }, + { + "Hour": 17, + "Day": 16, + "Activity": 27 + }, + { + "Hour": 17, + "Day": 17, + "Activity": 76 + }, + { + "Hour": 17, + "Day": 18, + "Activity": 80 + }, + { + "Hour": 17, + "Day": 19, + "Activity": 20 + }, + { + "Hour": 17, + "Day": 20, + "Activity": 80 + }, + { + "Hour": 17, + "Day": 21, + "Activity": 76 + }, + { + "Hour": 17, + "Day": 22, + "Activity": 4 + }, + { + "Hour": 17, + "Day": 23, + "Activity": 96 + }, + { + "Hour": 17, + "Day": 24, + "Activity": 39 + }, + { + "Hour": 17, + "Day": 25, + "Activity": 70 + }, + { + "Hour": 17, + "Day": 26, + "Activity": 77 + }, + { + "Hour": 17, + "Day": 27, + "Activity": 40 + }, + { + "Hour": 17, + "Day": 28, + "Activity": 61 + }, + { + "Hour": 17, + "Day": 29, + "Activity": 63 + }, + { + "Hour": 18, + "Day": 0, + "Activity": 67 + }, + { + "Hour": 18, + "Day": 1, + "Activity": 71 + }, + { + "Hour": 18, + "Day": 2, + "Activity": 54 + }, + { + "Hour": 18, + "Day": 3, + "Activity": 81 + }, + { + "Hour": 18, + "Day": 4, + "Activity": 1 + }, + { + "Hour": 18, + "Day": 5, + "Activity": 27 + }, + { + "Hour": 18, + "Day": 6, + "Activity": 39 + }, + { + "Hour": 18, + "Day": 7, + "Activity": 20 + }, + { + "Hour": 18, + "Day": 8, + "Activity": 74 + }, + { + "Hour": 18, + "Day": 9, + "Activity": 44 + }, + { + "Hour": 18, + "Day": 10, + "Activity": 45 + }, + { + "Hour": 18, + "Day": 11, + "Activity": 26 + }, + { + "Hour": 18, + "Day": 12, + "Activity": 59 + }, + { + "Hour": 18, + "Day": 13, + "Activity": 23 + }, + { + "Hour": 18, + "Day": 14, + "Activity": 40 + }, + { + "Hour": 18, + "Day": 15, + "Activity": 99 + }, + { + "Hour": 18, + "Day": 16, + "Activity": 50 + }, + { + "Hour": 18, + "Day": 17, + "Activity": 94 + }, + { + "Hour": 18, + "Day": 18, + "Activity": 15 + }, + { + "Hour": 18, + "Day": 19, + "Activity": 36 + }, + { + "Hour": 18, + "Day": 20, + "Activity": 56 + }, + { + "Hour": 18, + "Day": 21, + "Activity": 83 + }, + { + "Hour": 18, + "Day": 22, + "Activity": 6 + }, + { + "Hour": 18, + "Day": 23, + "Activity": 1 + }, + { + "Hour": 18, + "Day": 24, + "Activity": 66 + }, + { + "Hour": 18, + "Day": 25, + "Activity": 17 + }, + { + "Hour": 18, + "Day": 26, + "Activity": 56 + }, + { + "Hour": 18, + "Day": 27, + "Activity": 17 + }, + { + "Hour": 18, + "Day": 28, + "Activity": 85 + }, + { + "Hour": 18, + "Day": 29, + "Activity": 66 + }, + { + "Hour": 19, + "Day": 0, + "Activity": 90 + }, + { + "Hour": 19, + "Day": 1, + "Activity": 75 + }, + { + "Hour": 19, + "Day": 2, + "Activity": 85 + }, + { + "Hour": 19, + "Day": 3, + "Activity": 22 + }, + { + "Hour": 19, + "Day": 4, + "Activity": 98 + }, + { + "Hour": 19, + "Day": 5, + "Activity": 63 + }, + { + "Hour": 19, + "Day": 6, + "Activity": 62 + }, + { + "Hour": 19, + "Day": 7, + "Activity": 82 + }, + { + "Hour": 19, + "Day": 8, + "Activity": 92 + }, + { + "Hour": 19, + "Day": 9, + "Activity": 67 + }, + { + "Hour": 19, + "Day": 10, + "Activity": 41 + }, + { + "Hour": 19, + "Day": 11, + "Activity": 71 + }, + { + "Hour": 19, + "Day": 12, + "Activity": 6 + }, + { + "Hour": 19, + "Day": 13, + "Activity": 18 + }, + { + "Hour": 19, + "Day": 14, + "Activity": 63 + }, + { + "Hour": 19, + "Day": 15, + "Activity": 71 + }, + { + "Hour": 19, + "Day": 16, + "Activity": 28 + }, + { + "Hour": 19, + "Day": 17, + "Activity": 52 + }, + { + "Hour": 19, + "Day": 18, + "Activity": 72 + }, + { + "Hour": 19, + "Day": 19, + "Activity": 37 + }, + { + "Hour": 19, + "Day": 20, + "Activity": 37 + }, + { + "Hour": 19, + "Day": 21, + "Activity": 98 + }, + { + "Hour": 19, + "Day": 22, + "Activity": 56 + }, + { + "Hour": 19, + "Day": 23, + "Activity": 79 + }, + { + "Hour": 19, + "Day": 24, + "Activity": 44 + }, + { + "Hour": 19, + "Day": 25, + "Activity": 66 + }, + { + "Hour": 19, + "Day": 26, + "Activity": 61 + }, + { + "Hour": 19, + "Day": 27, + "Activity": 14 + }, + { + "Hour": 19, + "Day": 28, + "Activity": 68 + }, + { + "Hour": 19, + "Day": 29, + "Activity": 83 + }, + { + "Hour": 20, + "Day": 0, + "Activity": 81 + }, + { + "Hour": 20, + "Day": 1, + "Activity": 3 + }, + { + "Hour": 20, + "Day": 2, + "Activity": 32 + }, + { + "Hour": 20, + "Day": 3, + "Activity": 53 + }, + { + "Hour": 20, + "Day": 4, + "Activity": 57 + }, + { + "Hour": 20, + "Day": 5, + "Activity": 59 + }, + { + "Hour": 20, + "Day": 6, + "Activity": 48 + }, + { + "Hour": 20, + "Day": 7, + "Activity": 91 + }, + { + "Hour": 20, + "Day": 8, + "Activity": 58 + }, + { + "Hour": 20, + "Day": 9, + "Activity": 56 + }, + { + "Hour": 20, + "Day": 10, + "Activity": 63 + }, + { + "Hour": 20, + "Day": 11, + "Activity": 2 + }, + { + "Hour": 20, + "Day": 12, + "Activity": 57 + }, + { + "Hour": 20, + "Day": 13, + "Activity": 34 + }, + { + "Hour": 20, + "Day": 14, + "Activity": 6 + }, + { + "Hour": 20, + "Day": 15, + "Activity": 50 + }, + { + "Hour": 20, + "Day": 16, + "Activity": 77 + }, + { + "Hour": 20, + "Day": 17, + "Activity": 42 + }, + { + "Hour": 20, + "Day": 18, + "Activity": 89 + }, + { + "Hour": 20, + "Day": 19, + "Activity": 23 + }, + { + "Hour": 20, + "Day": 20, + "Activity": 10 + }, + { + "Hour": 20, + "Day": 21, + "Activity": 32 + }, + { + "Hour": 20, + "Day": 22, + "Activity": 77 + }, + { + "Hour": 20, + "Day": 23, + "Activity": 5 + }, + { + "Hour": 20, + "Day": 24, + "Activity": 68 + }, + { + "Hour": 20, + "Day": 25, + "Activity": 24 + }, + { + "Hour": 20, + "Day": 26, + "Activity": 13 + }, + { + "Hour": 20, + "Day": 27, + "Activity": 70 + }, + { + "Hour": 20, + "Day": 28, + "Activity": 75 + }, + { + "Hour": 20, + "Day": 29, + "Activity": 74 + }, + { + "Hour": 21, + "Day": 0, + "Activity": 50 + }, + { + "Hour": 21, + "Day": 1, + "Activity": 13 + }, + { + "Hour": 21, + "Day": 2, + "Activity": 75 + }, + { + "Hour": 21, + "Day": 3, + "Activity": 59 + }, + { + "Hour": 21, + "Day": 4, + "Activity": 71 + }, + { + "Hour": 21, + "Day": 5, + "Activity": 13 + }, + { + "Hour": 21, + "Day": 6, + "Activity": 84 + }, + { + "Hour": 21, + "Day": 7, + "Activity": 76 + }, + { + "Hour": 21, + "Day": 8, + "Activity": 71 + }, + { + "Hour": 21, + "Day": 9, + "Activity": 76 + }, + { + "Hour": 21, + "Day": 10, + "Activity": 41 + }, + { + "Hour": 21, + "Day": 11, + "Activity": 97 + }, + { + "Hour": 21, + "Day": 12, + "Activity": 68 + }, + { + "Hour": 21, + "Day": 13, + "Activity": 38 + }, + { + "Hour": 21, + "Day": 14, + "Activity": 46 + }, + { + "Hour": 21, + "Day": 15, + "Activity": 22 + }, + { + "Hour": 21, + "Day": 16, + "Activity": 41 + }, + { + "Hour": 21, + "Day": 17, + "Activity": 47 + }, + { + "Hour": 21, + "Day": 18, + "Activity": 24 + }, + { + "Hour": 21, + "Day": 19, + "Activity": 24 + }, + { + "Hour": 21, + "Day": 20, + "Activity": 25 + }, + { + "Hour": 21, + "Day": 21, + "Activity": 87 + }, + { + "Hour": 21, + "Day": 22, + "Activity": 9 + }, + { + "Hour": 21, + "Day": 23, + "Activity": 93 + }, + { + "Hour": 21, + "Day": 24, + "Activity": 63 + }, + { + "Hour": 21, + "Day": 25, + "Activity": 29 + }, + { + "Hour": 21, + "Day": 26, + "Activity": 53 + }, + { + "Hour": 21, + "Day": 27, + "Activity": 81 + }, + { + "Hour": 21, + "Day": 28, + "Activity": 25 + }, + { + "Hour": 21, + "Day": 29, + "Activity": 38 + }, + { + "Hour": 22, + "Day": 0, + "Activity": 80 + }, + { + "Hour": 22, + "Day": 1, + "Activity": 59 + }, + { + "Hour": 22, + "Day": 2, + "Activity": 64 + }, + { + "Hour": 22, + "Day": 3, + "Activity": 24 + }, + { + "Hour": 22, + "Day": 4, + "Activity": 24 + }, + { + "Hour": 22, + "Day": 5, + "Activity": 17 + }, + { + "Hour": 22, + "Day": 6, + "Activity": 30 + }, + { + "Hour": 22, + "Day": 7, + "Activity": 92 + }, + { + "Hour": 22, + "Day": 8, + "Activity": 70 + }, + { + "Hour": 22, + "Day": 9, + "Activity": 46 + }, + { + "Hour": 22, + "Day": 10, + "Activity": 10 + }, + { + "Hour": 22, + "Day": 11, + "Activity": 79 + }, + { + "Hour": 22, + "Day": 12, + "Activity": 86 + }, + { + "Hour": 22, + "Day": 13, + "Activity": 63 + }, + { + "Hour": 22, + "Day": 14, + "Activity": 5 + }, + { + "Hour": 22, + "Day": 15, + "Activity": 30 + }, + { + "Hour": 22, + "Day": 16, + "Activity": 85 + }, + { + "Hour": 22, + "Day": 17, + "Activity": 7 + }, + { + "Hour": 22, + "Day": 18, + "Activity": 12 + }, + { + "Hour": 22, + "Day": 19, + "Activity": 65 + }, + { + "Hour": 22, + "Day": 20, + "Activity": 16 + }, + { + "Hour": 22, + "Day": 21, + "Activity": 7 + }, + { + "Hour": 22, + "Day": 22, + "Activity": 21 + }, + { + "Hour": 22, + "Day": 23, + "Activity": 83 + }, + { + "Hour": 22, + "Day": 24, + "Activity": 75 + }, + { + "Hour": 22, + "Day": 25, + "Activity": 61 + }, + { + "Hour": 22, + "Day": 26, + "Activity": 2 + }, + { + "Hour": 22, + "Day": 27, + "Activity": 40 + }, + { + "Hour": 22, + "Day": 28, + "Activity": 22 + }, + { + "Hour": 22, + "Day": 29, + "Activity": 70 + }, + { + "Hour": 23, + "Day": 0, + "Activity": 63 + }, + { + "Hour": 23, + "Day": 1, + "Activity": 11 + }, + { + "Hour": 23, + "Day": 2, + "Activity": 81 + }, + { + "Hour": 23, + "Day": 3, + "Activity": 60 + }, + { + "Hour": 23, + "Day": 4, + "Activity": 75 + }, + { + "Hour": 23, + "Day": 5, + "Activity": 43 + }, + { + "Hour": 23, + "Day": 6, + "Activity": 59 + }, + { + "Hour": 23, + "Day": 7, + "Activity": 95 + }, + { + "Hour": 23, + "Day": 8, + "Activity": 84 + }, + { + "Hour": 23, + "Day": 9, + "Activity": 94 + }, + { + "Hour": 23, + "Day": 10, + "Activity": 2 + }, + { + "Hour": 23, + "Day": 11, + "Activity": 93 + }, + { + "Hour": 23, + "Day": 12, + "Activity": 57 + }, + { + "Hour": 23, + "Day": 13, + "Activity": 39 + }, + { + "Hour": 23, + "Day": 14, + "Activity": 4 + }, + { + "Hour": 23, + "Day": 15, + "Activity": 77 + }, + { + "Hour": 23, + "Day": 16, + "Activity": 56 + }, + { + "Hour": 23, + "Day": 17, + "Activity": 46 + }, + { + "Hour": 23, + "Day": 18, + "Activity": 58 + }, + { + "Hour": 23, + "Day": 19, + "Activity": 43 + }, + { + "Hour": 23, + "Day": 20, + "Activity": 6 + }, + { + "Hour": 23, + "Day": 21, + "Activity": 53 + }, + { + "Hour": 23, + "Day": 22, + "Activity": 69 + }, + { + "Hour": 23, + "Day": 23, + "Activity": 93 + }, + { + "Hour": 23, + "Day": 24, + "Activity": 51 + }, + { + "Hour": 23, + "Day": 25, + "Activity": 40 + }, + { + "Hour": 23, + "Day": 26, + "Activity": 21 + }, + { + "Hour": 23, + "Day": 27, + "Activity": 35 + }, + { + "Hour": 23, + "Day": 28, + "Activity": 31 + }, + { + "Hour": 23, + "Day": 29, + "Activity": 52 + }, + { + "Hour": 24, + "Day": 0, + "Activity": 10 + }, + { + "Hour": 24, + "Day": 1, + "Activity": 68 + }, + { + "Hour": 24, + "Day": 2, + "Activity": 60 + }, + { + "Hour": 24, + "Day": 3, + "Activity": 26 + }, + { + "Hour": 24, + "Day": 4, + "Activity": 21 + }, + { + "Hour": 24, + "Day": 5, + "Activity": 24 + }, + { + "Hour": 24, + "Day": 6, + "Activity": 54 + }, + { + "Hour": 24, + "Day": 7, + "Activity": 74 + }, + { + "Hour": 24, + "Day": 8, + "Activity": 31 + }, + { + "Hour": 24, + "Day": 9, + "Activity": 79 + }, + { + "Hour": 24, + "Day": 10, + "Activity": 87 + }, + { + "Hour": 24, + "Day": 11, + "Activity": 41 + }, + { + "Hour": 24, + "Day": 12, + "Activity": 65 + }, + { + "Hour": 24, + "Day": 13, + "Activity": 82 + }, + { + "Hour": 24, + "Day": 14, + "Activity": 29 + }, + { + "Hour": 24, + "Day": 15, + "Activity": 1 + }, + { + "Hour": 24, + "Day": 16, + "Activity": 48 + }, + { + "Hour": 24, + "Day": 17, + "Activity": 94 + }, + { + "Hour": 24, + "Day": 18, + "Activity": 38 + }, + { + "Hour": 24, + "Day": 19, + "Activity": 60 + }, + { + "Hour": 24, + "Day": 20, + "Activity": 35 + }, + { + "Hour": 24, + "Day": 21, + "Activity": 20 + }, + { + "Hour": 24, + "Day": 22, + "Activity": 61 + }, + { + "Hour": 24, + "Day": 23, + "Activity": 14 + }, + { + "Hour": 24, + "Day": 24, + "Activity": 44 + }, + { + "Hour": 24, + "Day": 25, + "Activity": 76 + }, + { + "Hour": 24, + "Day": 26, + "Activity": 32 + }, + { + "Hour": 24, + "Day": 27, + "Activity": 94 + }, + { + "Hour": 24, + "Day": 28, + "Activity": 37 + }, + { + "Hour": 24, + "Day": 29, + "Activity": 83 + }, + { + "Hour": 25, + "Day": 0, + "Activity": 38 + }, + { + "Hour": 25, + "Day": 1, + "Activity": 42 + }, + { + "Hour": 25, + "Day": 2, + "Activity": 6 + }, + { + "Hour": 25, + "Day": 3, + "Activity": 10 + }, + { + "Hour": 25, + "Day": 4, + "Activity": 1 + }, + { + "Hour": 25, + "Day": 5, + "Activity": 16 + }, + { + "Hour": 25, + "Day": 6, + "Activity": 24 + }, + { + "Hour": 25, + "Day": 7, + "Activity": 9 + }, + { + "Hour": 25, + "Day": 8, + "Activity": 21 + }, + { + "Hour": 25, + "Day": 9, + "Activity": 58 + }, + { + "Hour": 25, + "Day": 10, + "Activity": 74 + }, + { + "Hour": 25, + "Day": 11, + "Activity": 4 + }, + { + "Hour": 25, + "Day": 12, + "Activity": 74 + }, + { + "Hour": 25, + "Day": 13, + "Activity": 15 + }, + { + "Hour": 25, + "Day": 14, + "Activity": 56 + }, + { + "Hour": 25, + "Day": 15, + "Activity": 84 + }, + { + "Hour": 25, + "Day": 16, + "Activity": 13 + }, + { + "Hour": 25, + "Day": 17, + "Activity": 84 + }, + { + "Hour": 25, + "Day": 18, + "Activity": 44 + }, + { + "Hour": 25, + "Day": 19, + "Activity": 10 + }, + { + "Hour": 25, + "Day": 20, + "Activity": 16 + }, + { + "Hour": 25, + "Day": 21, + "Activity": 7 + }, + { + "Hour": 25, + "Day": 22, + "Activity": 74 + }, + { + "Hour": 25, + "Day": 23, + "Activity": 39 + }, + { + "Hour": 25, + "Day": 24, + "Activity": 10 + }, + { + "Hour": 25, + "Day": 25, + "Activity": 70 + }, + { + "Hour": 25, + "Day": 26, + "Activity": 3 + }, + { + "Hour": 25, + "Day": 27, + "Activity": 37 + }, + { + "Hour": 25, + "Day": 28, + "Activity": 64 + }, + { + "Hour": 25, + "Day": 29, + "Activity": 76 + }, + { + "Hour": 26, + "Day": 0, + "Activity": 69 + }, + { + "Hour": 26, + "Day": 1, + "Activity": 12 + }, + { + "Hour": 26, + "Day": 2, + "Activity": 80 + }, + { + "Hour": 26, + "Day": 3, + "Activity": 89 + }, + { + "Hour": 26, + "Day": 4, + "Activity": 53 + }, + { + "Hour": 26, + "Day": 5, + "Activity": 25 + }, + { + "Hour": 26, + "Day": 6, + "Activity": 45 + }, + { + "Hour": 26, + "Day": 7, + "Activity": 52 + }, + { + "Hour": 26, + "Day": 8, + "Activity": 68 + }, + { + "Hour": 26, + "Day": 9, + "Activity": 84 + }, + { + "Hour": 26, + "Day": 10, + "Activity": 75 + }, + { + "Hour": 26, + "Day": 11, + "Activity": 15 + }, + { + "Hour": 26, + "Day": 12, + "Activity": 79 + }, + { + "Hour": 26, + "Day": 13, + "Activity": 45 + }, + { + "Hour": 26, + "Day": 14, + "Activity": 76 + }, + { + "Hour": 26, + "Day": 15, + "Activity": 43 + }, + { + "Hour": 26, + "Day": 16, + "Activity": 18 + }, + { + "Hour": 26, + "Day": 17, + "Activity": 35 + }, + { + "Hour": 26, + "Day": 18, + "Activity": 7 + }, + { + "Hour": 26, + "Day": 19, + "Activity": 12 + }, + { + "Hour": 26, + "Day": 20, + "Activity": 79 + }, + { + "Hour": 26, + "Day": 21, + "Activity": 41 + }, + { + "Hour": 26, + "Day": 22, + "Activity": 98 + }, + { + "Hour": 26, + "Day": 23, + "Activity": 27 + }, + { + "Hour": 26, + "Day": 24, + "Activity": 23 + }, + { + "Hour": 26, + "Day": 25, + "Activity": 7 + }, + { + "Hour": 26, + "Day": 26, + "Activity": 50 + }, + { + "Hour": 26, + "Day": 27, + "Activity": 82 + }, + { + "Hour": 26, + "Day": 28, + "Activity": 20 + }, + { + "Hour": 26, + "Day": 29, + "Activity": 31 + }, + { + "Hour": 27, + "Day": 0, + "Activity": 35 + }, + { + "Hour": 27, + "Day": 1, + "Activity": 2 + }, + { + "Hour": 27, + "Day": 2, + "Activity": 41 + }, + { + "Hour": 27, + "Day": 3, + "Activity": 94 + }, + { + "Hour": 27, + "Day": 4, + "Activity": 93 + }, + { + "Hour": 27, + "Day": 5, + "Activity": 99 + }, + { + "Hour": 27, + "Day": 6, + "Activity": 77 + }, + { + "Hour": 27, + "Day": 7, + "Activity": 44 + }, + { + "Hour": 27, + "Day": 8, + "Activity": 46 + }, + { + "Hour": 27, + "Day": 9, + "Activity": 33 + }, + { + "Hour": 27, + "Day": 10, + "Activity": 78 + }, + { + "Hour": 27, + "Day": 11, + "Activity": 31 + }, + { + "Hour": 27, + "Day": 12, + "Activity": 30 + }, + { + "Hour": 27, + "Day": 13, + "Activity": 58 + }, + { + "Hour": 27, + "Day": 14, + "Activity": 2 + }, + { + "Hour": 27, + "Day": 15, + "Activity": 95 + }, + { + "Hour": 27, + "Day": 16, + "Activity": 50 + }, + { + "Hour": 27, + "Day": 17, + "Activity": 68 + }, + { + "Hour": 27, + "Day": 18, + "Activity": 2 + }, + { + "Hour": 27, + "Day": 19, + "Activity": 93 + }, + { + "Hour": 27, + "Day": 20, + "Activity": 22 + }, + { + "Hour": 27, + "Day": 21, + "Activity": 9 + }, + { + "Hour": 27, + "Day": 22, + "Activity": 76 + }, + { + "Hour": 27, + "Day": 23, + "Activity": 28 + }, + { + "Hour": 27, + "Day": 24, + "Activity": 77 + }, + { + "Hour": 27, + "Day": 25, + "Activity": 52 + }, + { + "Hour": 27, + "Day": 26, + "Activity": 60 + }, + { + "Hour": 27, + "Day": 27, + "Activity": 76 + }, + { + "Hour": 27, + "Day": 28, + "Activity": 6 + }, + { + "Hour": 27, + "Day": 29, + "Activity": 71 + }, + { + "Hour": 28, + "Day": 0, + "Activity": 52 + }, + { + "Hour": 28, + "Day": 1, + "Activity": 53 + }, + { + "Hour": 28, + "Day": 2, + "Activity": 92 + }, + { + "Hour": 28, + "Day": 3, + "Activity": 23 + }, + { + "Hour": 28, + "Day": 4, + "Activity": 89 + }, + { + "Hour": 28, + "Day": 5, + "Activity": 24 + }, + { + "Hour": 28, + "Day": 6, + "Activity": 43 + }, + { + "Hour": 28, + "Day": 7, + "Activity": 96 + }, + { + "Hour": 28, + "Day": 8, + "Activity": 16 + }, + { + "Hour": 28, + "Day": 9, + "Activity": 9 + }, + { + "Hour": 28, + "Day": 10, + "Activity": 51 + }, + { + "Hour": 28, + "Day": 11, + "Activity": 29 + }, + { + "Hour": 28, + "Day": 12, + "Activity": 65 + }, + { + "Hour": 28, + "Day": 13, + "Activity": 69 + }, + { + "Hour": 28, + "Day": 14, + "Activity": 64 + }, + { + "Hour": 28, + "Day": 15, + "Activity": 30 + }, + { + "Hour": 28, + "Day": 16, + "Activity": 2 + }, + { + "Hour": 28, + "Day": 17, + "Activity": 46 + }, + { + "Hour": 28, + "Day": 18, + "Activity": 74 + }, + { + "Hour": 28, + "Day": 19, + "Activity": 34 + }, + { + "Hour": 28, + "Day": 20, + "Activity": 86 + }, + { + "Hour": 28, + "Day": 21, + "Activity": 54 + }, + { + "Hour": 28, + "Day": 22, + "Activity": 40 + }, + { + "Hour": 28, + "Day": 23, + "Activity": 90 + }, + { + "Hour": 28, + "Day": 24, + "Activity": 23 + }, + { + "Hour": 28, + "Day": 25, + "Activity": 54 + }, + { + "Hour": 28, + "Day": 26, + "Activity": 35 + }, + { + "Hour": 28, + "Day": 27, + "Activity": 94 + }, + { + "Hour": 28, + "Day": 28, + "Activity": 22 + }, + { + "Hour": 28, + "Day": 29, + "Activity": 51 + }, + { + "Hour": 29, + "Day": 0, + "Activity": 76 + }, + { + "Hour": 29, + "Day": 1, + "Activity": 44 + }, + { + "Hour": 29, + "Day": 2, + "Activity": 7 + }, + { + "Hour": 29, + "Day": 3, + "Activity": 71 + }, + { + "Hour": 29, + "Day": 4, + "Activity": 59 + }, + { + "Hour": 29, + "Day": 5, + "Activity": 19 + }, + { + "Hour": 29, + "Day": 6, + "Activity": 98 + }, + { + "Hour": 29, + "Day": 7, + "Activity": 33 + }, + { + "Hour": 29, + "Day": 8, + "Activity": 88 + }, + { + "Hour": 29, + "Day": 9, + "Activity": 62 + }, + { + "Hour": 29, + "Day": 10, + "Activity": 0 + }, + { + "Hour": 29, + "Day": 11, + "Activity": 19 + }, + { + "Hour": 29, + "Day": 12, + "Activity": 27 + }, + { + "Hour": 29, + "Day": 13, + "Activity": 46 + }, + { + "Hour": 29, + "Day": 14, + "Activity": 9 + }, + { + "Hour": 29, + "Day": 15, + "Activity": 98 + }, + { + "Hour": 29, + "Day": 16, + "Activity": 5 + }, + { + "Hour": 29, + "Day": 17, + "Activity": 95 + }, + { + "Hour": 29, + "Day": 18, + "Activity": 45 + }, + { + "Hour": 29, + "Day": 19, + "Activity": 61 + }, + { + "Hour": 29, + "Day": 20, + "Activity": 71 + }, + { + "Hour": 29, + "Day": 21, + "Activity": 36 + }, + { + "Hour": 29, + "Day": 22, + "Activity": 2 + }, + { + "Hour": 29, + "Day": 23, + "Activity": 49 + }, + { + "Hour": 29, + "Day": 24, + "Activity": 36 + }, + { + "Hour": 29, + "Day": 25, + "Activity": 9 + }, + { + "Hour": 29, + "Day": 26, + "Activity": 48 + }, + { + "Hour": 29, + "Day": 27, + "Activity": 100 + }, + { + "Hour": 29, + "Day": 28, + "Activity": 20 + }, + { + "Hour": 29, + "Day": 29, + "Activity": 62 + }, + { + "Hour": 30, + "Day": 0, + "Activity": 34 + }, + { + "Hour": 30, + "Day": 1, + "Activity": 82 + }, + { + "Hour": 30, + "Day": 2, + "Activity": 78 + }, + { + "Hour": 30, + "Day": 3, + "Activity": 64 + }, + { + "Hour": 30, + "Day": 4, + "Activity": 67 + }, + { + "Hour": 30, + "Day": 5, + "Activity": 80 + }, + { + "Hour": 30, + "Day": 6, + "Activity": 2 + }, + { + "Hour": 30, + "Day": 7, + "Activity": 3 + }, + { + "Hour": 30, + "Day": 8, + "Activity": 38 + }, + { + "Hour": 30, + "Day": 9, + "Activity": 27 + }, + { + "Hour": 30, + "Day": 10, + "Activity": 17 + }, + { + "Hour": 30, + "Day": 11, + "Activity": 13 + }, + { + "Hour": 30, + "Day": 12, + "Activity": 70 + }, + { + "Hour": 30, + "Day": 13, + "Activity": 54 + }, + { + "Hour": 30, + "Day": 14, + "Activity": 42 + }, + { + "Hour": 30, + "Day": 15, + "Activity": 71 + }, + { + "Hour": 30, + "Day": 16, + "Activity": 22 + }, + { + "Hour": 30, + "Day": 17, + "Activity": 98 + }, + { + "Hour": 30, + "Day": 18, + "Activity": 23 + }, + { + "Hour": 30, + "Day": 19, + "Activity": 75 + }, + { + "Hour": 30, + "Day": 20, + "Activity": 31 + }, + { + "Hour": 30, + "Day": 21, + "Activity": 21 + }, + { + "Hour": 30, + "Day": 22, + "Activity": 90 + }, + { + "Hour": 30, + "Day": 23, + "Activity": 62 + }, + { + "Hour": 30, + "Day": 24, + "Activity": 21 + }, + { + "Hour": 30, + "Day": 25, + "Activity": 8 + }, + { + "Hour": 30, + "Day": 26, + "Activity": 50 + }, + { + "Hour": 30, + "Day": 27, + "Activity": 47 + }, + { + "Hour": 30, + "Day": 28, + "Activity": 61 + }, + { + "Hour": 30, + "Day": 29, + "Activity": 67 + }, + { + "Hour": 31, + "Day": 0, + "Activity": 86 + }, + { + "Hour": 31, + "Day": 1, + "Activity": 25 + }, + { + "Hour": 31, + "Day": 2, + "Activity": 30 + }, + { + "Hour": 31, + "Day": 3, + "Activity": 58 + }, + { + "Hour": 31, + "Day": 4, + "Activity": 86 + }, + { + "Hour": 31, + "Day": 5, + "Activity": 22 + }, + { + "Hour": 31, + "Day": 6, + "Activity": 56 + }, + { + "Hour": 31, + "Day": 7, + "Activity": 15 + }, + { + "Hour": 31, + "Day": 8, + "Activity": 63 + }, + { + "Hour": 31, + "Day": 9, + "Activity": 48 + }, + { + "Hour": 31, + "Day": 10, + "Activity": 54 + }, + { + "Hour": 31, + "Day": 11, + "Activity": 72 + }, + { + "Hour": 31, + "Day": 12, + "Activity": 58 + }, + { + "Hour": 31, + "Day": 13, + "Activity": 70 + }, + { + "Hour": 31, + "Day": 14, + "Activity": 50 + }, + { + "Hour": 31, + "Day": 15, + "Activity": 24 + }, + { + "Hour": 31, + "Day": 16, + "Activity": 20 + }, + { + "Hour": 31, + "Day": 17, + "Activity": 3 + }, + { + "Hour": 31, + "Day": 18, + "Activity": 69 + }, + { + "Hour": 31, + "Day": 19, + "Activity": 70 + }, + { + "Hour": 31, + "Day": 20, + "Activity": 55 + }, + { + "Hour": 31, + "Day": 21, + "Activity": 52 + }, + { + "Hour": 31, + "Day": 22, + "Activity": 31 + }, + { + "Hour": 31, + "Day": 23, + "Activity": 93 + }, + { + "Hour": 31, + "Day": 24, + "Activity": 94 + }, + { + "Hour": 31, + "Day": 25, + "Activity": 53 + }, + { + "Hour": 31, + "Day": 26, + "Activity": 23 + }, + { + "Hour": 31, + "Day": 27, + "Activity": 20 + }, + { + "Hour": 31, + "Day": 28, + "Activity": 53 + }, + { + "Hour": 31, + "Day": 29, + "Activity": 45 + }, + { + "Hour": 32, + "Day": 0, + "Activity": 79 + }, + { + "Hour": 32, + "Day": 1, + "Activity": 35 + }, + { + "Hour": 32, + "Day": 2, + "Activity": 75 + }, + { + "Hour": 32, + "Day": 3, + "Activity": 55 + }, + { + "Hour": 32, + "Day": 4, + "Activity": 50 + }, + { + "Hour": 32, + "Day": 5, + "Activity": 72 + }, + { + "Hour": 32, + "Day": 6, + "Activity": 15 + }, + { + "Hour": 32, + "Day": 7, + "Activity": 4 + }, + { + "Hour": 32, + "Day": 8, + "Activity": 61 + }, + { + "Hour": 32, + "Day": 9, + "Activity": 35 + }, + { + "Hour": 32, + "Day": 10, + "Activity": 28 + }, + { + "Hour": 32, + "Day": 11, + "Activity": 78 + }, + { + "Hour": 32, + "Day": 12, + "Activity": 99 + }, + { + "Hour": 32, + "Day": 13, + "Activity": 48 + }, + { + "Hour": 32, + "Day": 14, + "Activity": 83 + }, + { + "Hour": 32, + "Day": 15, + "Activity": 60 + }, + { + "Hour": 32, + "Day": 16, + "Activity": 18 + }, + { + "Hour": 32, + "Day": 17, + "Activity": 48 + }, + { + "Hour": 32, + "Day": 18, + "Activity": 59 + }, + { + "Hour": 32, + "Day": 19, + "Activity": 58 + }, + { + "Hour": 32, + "Day": 20, + "Activity": 5 + }, + { + "Hour": 32, + "Day": 21, + "Activity": 55 + }, + { + "Hour": 32, + "Day": 22, + "Activity": 85 + }, + { + "Hour": 32, + "Day": 23, + "Activity": 68 + }, + { + "Hour": 32, + "Day": 24, + "Activity": 38 + }, + { + "Hour": 32, + "Day": 25, + "Activity": 26 + }, + { + "Hour": 32, + "Day": 26, + "Activity": 68 + }, + { + "Hour": 32, + "Day": 27, + "Activity": 92 + }, + { + "Hour": 32, + "Day": 28, + "Activity": 62 + }, + { + "Hour": 32, + "Day": 29, + "Activity": 82 + }, + { + "Hour": 33, + "Day": 0, + "Activity": 14 + }, + { + "Hour": 33, + "Day": 1, + "Activity": 99 + }, + { + "Hour": 33, + "Day": 2, + "Activity": 53 + }, + { + "Hour": 33, + "Day": 3, + "Activity": 11 + }, + { + "Hour": 33, + "Day": 4, + "Activity": 33 + }, + { + "Hour": 33, + "Day": 5, + "Activity": 98 + }, + { + "Hour": 33, + "Day": 6, + "Activity": 77 + }, + { + "Hour": 33, + "Day": 7, + "Activity": 59 + }, + { + "Hour": 33, + "Day": 8, + "Activity": 37 + }, + { + "Hour": 33, + "Day": 9, + "Activity": 9 + }, + { + "Hour": 33, + "Day": 10, + "Activity": 11 + }, + { + "Hour": 33, + "Day": 11, + "Activity": 30 + }, + { + "Hour": 33, + "Day": 12, + "Activity": 55 + }, + { + "Hour": 33, + "Day": 13, + "Activity": 60 + }, + { + "Hour": 33, + "Day": 14, + "Activity": 78 + }, + { + "Hour": 33, + "Day": 15, + "Activity": 96 + }, + { + "Hour": 33, + "Day": 16, + "Activity": 54 + }, + { + "Hour": 33, + "Day": 17, + "Activity": 66 + }, + { + "Hour": 33, + "Day": 18, + "Activity": 2 + }, + { + "Hour": 33, + "Day": 19, + "Activity": 14 + }, + { + "Hour": 33, + "Day": 20, + "Activity": 2 + }, + { + "Hour": 33, + "Day": 21, + "Activity": 39 + }, + { + "Hour": 33, + "Day": 22, + "Activity": 76 + }, + { + "Hour": 33, + "Day": 23, + "Activity": 96 + }, + { + "Hour": 33, + "Day": 24, + "Activity": 23 + }, + { + "Hour": 33, + "Day": 25, + "Activity": 31 + }, + { + "Hour": 33, + "Day": 26, + "Activity": 6 + }, + { + "Hour": 33, + "Day": 27, + "Activity": 26 + }, + { + "Hour": 33, + "Day": 28, + "Activity": 3 + }, + { + "Hour": 33, + "Day": 29, + "Activity": 28 + }, + { + "Hour": 34, + "Day": 0, + "Activity": 93 + }, + { + "Hour": 34, + "Day": 1, + "Activity": 17 + }, + { + "Hour": 34, + "Day": 2, + "Activity": 92 + }, + { + "Hour": 34, + "Day": 3, + "Activity": 95 + }, + { + "Hour": 34, + "Day": 4, + "Activity": 5 + }, + { + "Hour": 34, + "Day": 5, + "Activity": 57 + }, + { + "Hour": 34, + "Day": 6, + "Activity": 8 + }, + { + "Hour": 34, + "Day": 7, + "Activity": 13 + }, + { + "Hour": 34, + "Day": 8, + "Activity": 98 + }, + { + "Hour": 34, + "Day": 9, + "Activity": 26 + }, + { + "Hour": 34, + "Day": 10, + "Activity": 48 + }, + { + "Hour": 34, + "Day": 11, + "Activity": 31 + }, + { + "Hour": 34, + "Day": 12, + "Activity": 95 + }, + { + "Hour": 34, + "Day": 13, + "Activity": 21 + }, + { + "Hour": 34, + "Day": 14, + "Activity": 52 + }, + { + "Hour": 34, + "Day": 15, + "Activity": 65 + }, + { + "Hour": 34, + "Day": 16, + "Activity": 89 + }, + { + "Hour": 34, + "Day": 17, + "Activity": 18 + }, + { + "Hour": 34, + "Day": 18, + "Activity": 73 + }, + { + "Hour": 34, + "Day": 19, + "Activity": 73 + }, + { + "Hour": 34, + "Day": 20, + "Activity": 99 + }, + { + "Hour": 34, + "Day": 21, + "Activity": 78 + }, + { + "Hour": 34, + "Day": 22, + "Activity": 90 + }, + { + "Hour": 34, + "Day": 23, + "Activity": 80 + }, + { + "Hour": 34, + "Day": 24, + "Activity": 71 + }, + { + "Hour": 34, + "Day": 25, + "Activity": 3 + }, + { + "Hour": 34, + "Day": 26, + "Activity": 10 + }, + { + "Hour": 34, + "Day": 27, + "Activity": 3 + }, + { + "Hour": 34, + "Day": 28, + "Activity": 33 + }, + { + "Hour": 34, + "Day": 29, + "Activity": 95 + }, + { + "Hour": 35, + "Day": 0, + "Activity": 20 + }, + { + "Hour": 35, + "Day": 1, + "Activity": 10 + }, + { + "Hour": 35, + "Day": 2, + "Activity": 65 + }, + { + "Hour": 35, + "Day": 3, + "Activity": 66 + }, + { + "Hour": 35, + "Day": 4, + "Activity": 37 + }, + { + "Hour": 35, + "Day": 5, + "Activity": 69 + }, + { + "Hour": 35, + "Day": 6, + "Activity": 16 + }, + { + "Hour": 35, + "Day": 7, + "Activity": 58 + }, + { + "Hour": 35, + "Day": 8, + "Activity": 77 + }, + { + "Hour": 35, + "Day": 9, + "Activity": 56 + }, + { + "Hour": 35, + "Day": 10, + "Activity": 8 + }, + { + "Hour": 35, + "Day": 11, + "Activity": 29 + }, + { + "Hour": 35, + "Day": 12, + "Activity": 77 + }, + { + "Hour": 35, + "Day": 13, + "Activity": 21 + }, + { + "Hour": 35, + "Day": 14, + "Activity": 98 + }, + { + "Hour": 35, + "Day": 15, + "Activity": 3 + }, + { + "Hour": 35, + "Day": 16, + "Activity": 30 + }, + { + "Hour": 35, + "Day": 17, + "Activity": 30 + }, + { + "Hour": 35, + "Day": 18, + "Activity": 22 + }, + { + "Hour": 35, + "Day": 19, + "Activity": 96 + }, + { + "Hour": 35, + "Day": 20, + "Activity": 83 + }, + { + "Hour": 35, + "Day": 21, + "Activity": 65 + }, + { + "Hour": 35, + "Day": 22, + "Activity": 93 + }, + { + "Hour": 35, + "Day": 23, + "Activity": 2 + }, + { + "Hour": 35, + "Day": 24, + "Activity": 41 + }, + { + "Hour": 35, + "Day": 25, + "Activity": 26 + }, + { + "Hour": 35, + "Day": 26, + "Activity": 48 + }, + { + "Hour": 35, + "Day": 27, + "Activity": 46 + }, + { + "Hour": 35, + "Day": 28, + "Activity": 62 + }, + { + "Hour": 35, + "Day": 29, + "Activity": 34 + }, + { + "Hour": 36, + "Day": 0, + "Activity": 76 + }, + { + "Hour": 36, + "Day": 1, + "Activity": 97 + }, + { + "Hour": 36, + "Day": 2, + "Activity": 66 + }, + { + "Hour": 36, + "Day": 3, + "Activity": 12 + }, + { + "Hour": 36, + "Day": 4, + "Activity": 28 + }, + { + "Hour": 36, + "Day": 5, + "Activity": 9 + }, + { + "Hour": 36, + "Day": 6, + "Activity": 56 + }, + { + "Hour": 36, + "Day": 7, + "Activity": 10 + }, + { + "Hour": 36, + "Day": 8, + "Activity": 76 + }, + { + "Hour": 36, + "Day": 9, + "Activity": 13 + }, + { + "Hour": 36, + "Day": 10, + "Activity": 86 + }, + { + "Hour": 36, + "Day": 11, + "Activity": 59 + }, + { + "Hour": 36, + "Day": 12, + "Activity": 58 + }, + { + "Hour": 36, + "Day": 13, + "Activity": 74 + }, + { + "Hour": 36, + "Day": 14, + "Activity": 61 + }, + { + "Hour": 36, + "Day": 15, + "Activity": 60 + }, + { + "Hour": 36, + "Day": 16, + "Activity": 60 + }, + { + "Hour": 36, + "Day": 17, + "Activity": 86 + }, + { + "Hour": 36, + "Day": 18, + "Activity": 18 + }, + { + "Hour": 36, + "Day": 19, + "Activity": 15 + }, + { + "Hour": 36, + "Day": 20, + "Activity": 79 + }, + { + "Hour": 36, + "Day": 21, + "Activity": 92 + }, + { + "Hour": 36, + "Day": 22, + "Activity": 2 + }, + { + "Hour": 36, + "Day": 23, + "Activity": 23 + }, + { + "Hour": 36, + "Day": 24, + "Activity": 56 + }, + { + "Hour": 36, + "Day": 25, + "Activity": 54 + }, + { + "Hour": 36, + "Day": 26, + "Activity": 18 + }, + { + "Hour": 36, + "Day": 27, + "Activity": 11 + }, + { + "Hour": 36, + "Day": 28, + "Activity": 47 + }, + { + "Hour": 36, + "Day": 29, + "Activity": 85 + }, + { + "Hour": 37, + "Day": 0, + "Activity": 27 + }, + { + "Hour": 37, + "Day": 1, + "Activity": 88 + }, + { + "Hour": 37, + "Day": 2, + "Activity": 79 + }, + { + "Hour": 37, + "Day": 3, + "Activity": 91 + }, + { + "Hour": 37, + "Day": 4, + "Activity": 88 + }, + { + "Hour": 37, + "Day": 5, + "Activity": 50 + }, + { + "Hour": 37, + "Day": 6, + "Activity": 23 + }, + { + "Hour": 37, + "Day": 7, + "Activity": 75 + }, + { + "Hour": 37, + "Day": 8, + "Activity": 25 + }, + { + "Hour": 37, + "Day": 9, + "Activity": 76 + }, + { + "Hour": 37, + "Day": 10, + "Activity": 94 + }, + { + "Hour": 37, + "Day": 11, + "Activity": 73 + }, + { + "Hour": 37, + "Day": 12, + "Activity": 90 + }, + { + "Hour": 37, + "Day": 13, + "Activity": 0 + }, + { + "Hour": 37, + "Day": 14, + "Activity": 94 + }, + { + "Hour": 37, + "Day": 15, + "Activity": 19 + }, + { + "Hour": 37, + "Day": 16, + "Activity": 56 + }, + { + "Hour": 37, + "Day": 17, + "Activity": 0 + }, + { + "Hour": 37, + "Day": 18, + "Activity": 52 + }, + { + "Hour": 37, + "Day": 19, + "Activity": 87 + }, + { + "Hour": 37, + "Day": 20, + "Activity": 16 + }, + { + "Hour": 37, + "Day": 21, + "Activity": 16 + }, + { + "Hour": 37, + "Day": 22, + "Activity": 47 + }, + { + "Hour": 37, + "Day": 23, + "Activity": 35 + }, + { + "Hour": 37, + "Day": 24, + "Activity": 55 + }, + { + "Hour": 37, + "Day": 25, + "Activity": 86 + }, + { + "Hour": 37, + "Day": 26, + "Activity": 90 + }, + { + "Hour": 37, + "Day": 27, + "Activity": 30 + }, + { + "Hour": 37, + "Day": 28, + "Activity": 80 + }, + { + "Hour": 37, + "Day": 29, + "Activity": 30 + }, + { + "Hour": 38, + "Day": 0, + "Activity": 80 + }, + { + "Hour": 38, + "Day": 1, + "Activity": 30 + }, + { + "Hour": 38, + "Day": 2, + "Activity": 40 + }, + { + "Hour": 38, + "Day": 3, + "Activity": 61 + }, + { + "Hour": 38, + "Day": 4, + "Activity": 83 + }, + { + "Hour": 38, + "Day": 5, + "Activity": 50 + }, + { + "Hour": 38, + "Day": 6, + "Activity": 96 + }, + { + "Hour": 38, + "Day": 7, + "Activity": 15 + }, + { + "Hour": 38, + "Day": 8, + "Activity": 64 + }, + { + "Hour": 38, + "Day": 9, + "Activity": 94 + }, + { + "Hour": 38, + "Day": 10, + "Activity": 90 + }, + { + "Hour": 38, + "Day": 11, + "Activity": 36 + }, + { + "Hour": 38, + "Day": 12, + "Activity": 5 + }, + { + "Hour": 38, + "Day": 13, + "Activity": 96 + }, + { + "Hour": 38, + "Day": 14, + "Activity": 88 + }, + { + "Hour": 38, + "Day": 15, + "Activity": 10 + }, + { + "Hour": 38, + "Day": 16, + "Activity": 82 + }, + { + "Hour": 38, + "Day": 17, + "Activity": 78 + }, + { + "Hour": 38, + "Day": 18, + "Activity": 33 + }, + { + "Hour": 38, + "Day": 19, + "Activity": 60 + }, + { + "Hour": 38, + "Day": 20, + "Activity": 22 + }, + { + "Hour": 38, + "Day": 21, + "Activity": 80 + }, + { + "Hour": 38, + "Day": 22, + "Activity": 88 + }, + { + "Hour": 38, + "Day": 23, + "Activity": 63 + }, + { + "Hour": 38, + "Day": 24, + "Activity": 92 + }, + { + "Hour": 38, + "Day": 25, + "Activity": 50 + }, + { + "Hour": 38, + "Day": 26, + "Activity": 24 + }, + { + "Hour": 38, + "Day": 27, + "Activity": 57 + }, + { + "Hour": 38, + "Day": 28, + "Activity": 51 + }, + { + "Hour": 38, + "Day": 29, + "Activity": 64 + }, + { + "Hour": 39, + "Day": 0, + "Activity": 97 + }, + { + "Hour": 39, + "Day": 1, + "Activity": 63 + }, + { + "Hour": 39, + "Day": 2, + "Activity": 97 + }, + { + "Hour": 39, + "Day": 3, + "Activity": 32 + }, + { + "Hour": 39, + "Day": 4, + "Activity": 59 + }, + { + "Hour": 39, + "Day": 5, + "Activity": 43 + }, + { + "Hour": 39, + "Day": 6, + "Activity": 88 + }, + { + "Hour": 39, + "Day": 7, + "Activity": 31 + }, + { + "Hour": 39, + "Day": 8, + "Activity": 54 + }, + { + "Hour": 39, + "Day": 9, + "Activity": 15 + }, + { + "Hour": 39, + "Day": 10, + "Activity": 53 + }, + { + "Hour": 39, + "Day": 11, + "Activity": 47 + }, + { + "Hour": 39, + "Day": 12, + "Activity": 30 + }, + { + "Hour": 39, + "Day": 13, + "Activity": 14 + }, + { + "Hour": 39, + "Day": 14, + "Activity": 90 + }, + { + "Hour": 39, + "Day": 15, + "Activity": 22 + }, + { + "Hour": 39, + "Day": 16, + "Activity": 93 + }, + { + "Hour": 39, + "Day": 17, + "Activity": 10 + }, + { + "Hour": 39, + "Day": 18, + "Activity": 81 + }, + { + "Hour": 39, + "Day": 19, + "Activity": 27 + }, + { + "Hour": 39, + "Day": 20, + "Activity": 96 + }, + { + "Hour": 39, + "Day": 21, + "Activity": 0 + }, + { + "Hour": 39, + "Day": 22, + "Activity": 57 + }, + { + "Hour": 39, + "Day": 23, + "Activity": 46 + }, + { + "Hour": 39, + "Day": 24, + "Activity": 22 + }, + { + "Hour": 39, + "Day": 25, + "Activity": 7 + }, + { + "Hour": 39, + "Day": 26, + "Activity": 44 + }, + { + "Hour": 39, + "Day": 27, + "Activity": 77 + }, + { + "Hour": 39, + "Day": 28, + "Activity": 25 + }, + { + "Hour": 39, + "Day": 29, + "Activity": 96 + }, + { + "Hour": 40, + "Day": 0, + "Activity": 100 + }, + { + "Hour": 40, + "Day": 1, + "Activity": 55 + }, + { + "Hour": 40, + "Day": 2, + "Activity": 81 + }, + { + "Hour": 40, + "Day": 3, + "Activity": 89 + }, + { + "Hour": 40, + "Day": 4, + "Activity": 29 + }, + { + "Hour": 40, + "Day": 5, + "Activity": 50 + }, + { + "Hour": 40, + "Day": 6, + "Activity": 37 + }, + { + "Hour": 40, + "Day": 7, + "Activity": 41 + }, + { + "Hour": 40, + "Day": 8, + "Activity": 85 + }, + { + "Hour": 40, + "Day": 9, + "Activity": 81 + }, + { + "Hour": 40, + "Day": 10, + "Activity": 81 + }, + { + "Hour": 40, + "Day": 11, + "Activity": 88 + }, + { + "Hour": 40, + "Day": 12, + "Activity": 85 + }, + { + "Hour": 40, + "Day": 13, + "Activity": 1 + }, + { + "Hour": 40, + "Day": 14, + "Activity": 82 + }, + { + "Hour": 40, + "Day": 15, + "Activity": 23 + }, + { + "Hour": 40, + "Day": 16, + "Activity": 39 + }, + { + "Hour": 40, + "Day": 17, + "Activity": 34 + }, + { + "Hour": 40, + "Day": 18, + "Activity": 51 + }, + { + "Hour": 40, + "Day": 19, + "Activity": 89 + }, + { + "Hour": 40, + "Day": 20, + "Activity": 15 + }, + { + "Hour": 40, + "Day": 21, + "Activity": 81 + }, + { + "Hour": 40, + "Day": 22, + "Activity": 18 + }, + { + "Hour": 40, + "Day": 23, + "Activity": 35 + }, + { + "Hour": 40, + "Day": 24, + "Activity": 68 + }, + { + "Hour": 40, + "Day": 25, + "Activity": 32 + }, + { + "Hour": 40, + "Day": 26, + "Activity": 13 + }, + { + "Hour": 40, + "Day": 27, + "Activity": 4 + }, + { + "Hour": 40, + "Day": 28, + "Activity": 70 + }, + { + "Hour": 40, + "Day": 29, + "Activity": 4 + }, + { + "Hour": 41, + "Day": 0, + "Activity": 95 + }, + { + "Hour": 41, + "Day": 1, + "Activity": 39 + }, + { + "Hour": 41, + "Day": 2, + "Activity": 51 + }, + { + "Hour": 41, + "Day": 3, + "Activity": 73 + }, + { + "Hour": 41, + "Day": 4, + "Activity": 6 + }, + { + "Hour": 41, + "Day": 5, + "Activity": 25 + }, + { + "Hour": 41, + "Day": 6, + "Activity": 41 + }, + { + "Hour": 41, + "Day": 7, + "Activity": 96 + }, + { + "Hour": 41, + "Day": 8, + "Activity": 19 + }, + { + "Hour": 41, + "Day": 9, + "Activity": 83 + }, + { + "Hour": 41, + "Day": 10, + "Activity": 36 + }, + { + "Hour": 41, + "Day": 11, + "Activity": 74 + }, + { + "Hour": 41, + "Day": 12, + "Activity": 8 + }, + { + "Hour": 41, + "Day": 13, + "Activity": 70 + }, + { + "Hour": 41, + "Day": 14, + "Activity": 36 + }, + { + "Hour": 41, + "Day": 15, + "Activity": 92 + }, + { + "Hour": 41, + "Day": 16, + "Activity": 22 + }, + { + "Hour": 41, + "Day": 17, + "Activity": 19 + }, + { + "Hour": 41, + "Day": 18, + "Activity": 99 + }, + { + "Hour": 41, + "Day": 19, + "Activity": 82 + }, + { + "Hour": 41, + "Day": 20, + "Activity": 14 + }, + { + "Hour": 41, + "Day": 21, + "Activity": 30 + }, + { + "Hour": 41, + "Day": 22, + "Activity": 56 + }, + { + "Hour": 41, + "Day": 23, + "Activity": 8 + }, + { + "Hour": 41, + "Day": 24, + "Activity": 40 + }, + { + "Hour": 41, + "Day": 25, + "Activity": 63 + }, + { + "Hour": 41, + "Day": 26, + "Activity": 58 + }, + { + "Hour": 41, + "Day": 27, + "Activity": 99 + }, + { + "Hour": 41, + "Day": 28, + "Activity": 94 + }, + { + "Hour": 41, + "Day": 29, + "Activity": 93 + }, + { + "Hour": 42, + "Day": 0, + "Activity": 27 + }, + { + "Hour": 42, + "Day": 1, + "Activity": 12 + }, + { + "Hour": 42, + "Day": 2, + "Activity": 67 + }, + { + "Hour": 42, + "Day": 3, + "Activity": 7 + }, + { + "Hour": 42, + "Day": 4, + "Activity": 9 + }, + { + "Hour": 42, + "Day": 5, + "Activity": 76 + }, + { + "Hour": 42, + "Day": 6, + "Activity": 35 + }, + { + "Hour": 42, + "Day": 7, + "Activity": 62 + }, + { + "Hour": 42, + "Day": 8, + "Activity": 49 + }, + { + "Hour": 42, + "Day": 9, + "Activity": 67 + }, + { + "Hour": 42, + "Day": 10, + "Activity": 55 + }, + { + "Hour": 42, + "Day": 11, + "Activity": 99 + }, + { + "Hour": 42, + "Day": 12, + "Activity": 76 + }, + { + "Hour": 42, + "Day": 13, + "Activity": 26 + }, + { + "Hour": 42, + "Day": 14, + "Activity": 59 + }, + { + "Hour": 42, + "Day": 15, + "Activity": 65 + }, + { + "Hour": 42, + "Day": 16, + "Activity": 14 + }, + { + "Hour": 42, + "Day": 17, + "Activity": 16 + }, + { + "Hour": 42, + "Day": 18, + "Activity": 13 + }, + { + "Hour": 42, + "Day": 19, + "Activity": 17 + }, + { + "Hour": 42, + "Day": 20, + "Activity": 14 + }, + { + "Hour": 42, + "Day": 21, + "Activity": 60 + }, + { + "Hour": 42, + "Day": 22, + "Activity": 81 + }, + { + "Hour": 42, + "Day": 23, + "Activity": 67 + }, + { + "Hour": 42, + "Day": 24, + "Activity": 59 + }, + { + "Hour": 42, + "Day": 25, + "Activity": 67 + }, + { + "Hour": 42, + "Day": 26, + "Activity": 48 + }, + { + "Hour": 42, + "Day": 27, + "Activity": 98 + }, + { + "Hour": 42, + "Day": 28, + "Activity": 10 + }, + { + "Hour": 42, + "Day": 29, + "Activity": 44 + }, + { + "Hour": 43, + "Day": 0, + "Activity": 81 + }, + { + "Hour": 43, + "Day": 1, + "Activity": 70 + }, + { + "Hour": 43, + "Day": 2, + "Activity": 33 + }, + { + "Hour": 43, + "Day": 3, + "Activity": 12 + }, + { + "Hour": 43, + "Day": 4, + "Activity": 13 + }, + { + "Hour": 43, + "Day": 5, + "Activity": 41 + }, + { + "Hour": 43, + "Day": 6, + "Activity": 7 + }, + { + "Hour": 43, + "Day": 7, + "Activity": 32 + }, + { + "Hour": 43, + "Day": 8, + "Activity": 38 + }, + { + "Hour": 43, + "Day": 9, + "Activity": 60 + }, + { + "Hour": 43, + "Day": 10, + "Activity": 11 + }, + { + "Hour": 43, + "Day": 11, + "Activity": 37 + }, + { + "Hour": 43, + "Day": 12, + "Activity": 79 + }, + { + "Hour": 43, + "Day": 13, + "Activity": 68 + }, + { + "Hour": 43, + "Day": 14, + "Activity": 99 + }, + { + "Hour": 43, + "Day": 15, + "Activity": 24 + }, + { + "Hour": 43, + "Day": 16, + "Activity": 2 + }, + { + "Hour": 43, + "Day": 17, + "Activity": 47 + }, + { + "Hour": 43, + "Day": 18, + "Activity": 88 + }, + { + "Hour": 43, + "Day": 19, + "Activity": 91 + }, + { + "Hour": 43, + "Day": 20, + "Activity": 15 + }, + { + "Hour": 43, + "Day": 21, + "Activity": 8 + }, + { + "Hour": 43, + "Day": 22, + "Activity": 3 + }, + { + "Hour": 43, + "Day": 23, + "Activity": 14 + }, + { + "Hour": 43, + "Day": 24, + "Activity": 23 + }, + { + "Hour": 43, + "Day": 25, + "Activity": 74 + }, + { + "Hour": 43, + "Day": 26, + "Activity": 70 + }, + { + "Hour": 43, + "Day": 27, + "Activity": 48 + }, + { + "Hour": 43, + "Day": 28, + "Activity": 41 + }, + { + "Hour": 43, + "Day": 29, + "Activity": 82 + }, + { + "Hour": 44, + "Day": 0, + "Activity": 22 + }, + { + "Hour": 44, + "Day": 1, + "Activity": 56 + }, + { + "Hour": 44, + "Day": 2, + "Activity": 89 + }, + { + "Hour": 44, + "Day": 3, + "Activity": 2 + }, + { + "Hour": 44, + "Day": 4, + "Activity": 99 + }, + { + "Hour": 44, + "Day": 5, + "Activity": 18 + }, + { + "Hour": 44, + "Day": 6, + "Activity": 46 + }, + { + "Hour": 44, + "Day": 7, + "Activity": 96 + }, + { + "Hour": 44, + "Day": 8, + "Activity": 17 + }, + { + "Hour": 44, + "Day": 9, + "Activity": 4 + }, + { + "Hour": 44, + "Day": 10, + "Activity": 71 + }, + { + "Hour": 44, + "Day": 11, + "Activity": 54 + }, + { + "Hour": 44, + "Day": 12, + "Activity": 60 + }, + { + "Hour": 44, + "Day": 13, + "Activity": 57 + }, + { + "Hour": 44, + "Day": 14, + "Activity": 92 + }, + { + "Hour": 44, + "Day": 15, + "Activity": 75 + }, + { + "Hour": 44, + "Day": 16, + "Activity": 93 + }, + { + "Hour": 44, + "Day": 17, + "Activity": 2 + }, + { + "Hour": 44, + "Day": 18, + "Activity": 9 + }, + { + "Hour": 44, + "Day": 19, + "Activity": 18 + }, + { + "Hour": 44, + "Day": 20, + "Activity": 61 + }, + { + "Hour": 44, + "Day": 21, + "Activity": 70 + }, + { + "Hour": 44, + "Day": 22, + "Activity": 29 + }, + { + "Hour": 44, + "Day": 23, + "Activity": 52 + }, + { + "Hour": 44, + "Day": 24, + "Activity": 21 + }, + { + "Hour": 44, + "Day": 25, + "Activity": 30 + }, + { + "Hour": 44, + "Day": 26, + "Activity": 53 + }, + { + "Hour": 44, + "Day": 27, + "Activity": 45 + }, + { + "Hour": 44, + "Day": 28, + "Activity": 88 + }, + { + "Hour": 44, + "Day": 29, + "Activity": 67 + }, + { + "Hour": 45, + "Day": 0, + "Activity": 16 + }, + { + "Hour": 45, + "Day": 1, + "Activity": 23 + }, + { + "Hour": 45, + "Day": 2, + "Activity": 48 + }, + { + "Hour": 45, + "Day": 3, + "Activity": 21 + }, + { + "Hour": 45, + "Day": 4, + "Activity": 8 + }, + { + "Hour": 45, + "Day": 5, + "Activity": 52 + }, + { + "Hour": 45, + "Day": 6, + "Activity": 39 + }, + { + "Hour": 45, + "Day": 7, + "Activity": 69 + }, + { + "Hour": 45, + "Day": 8, + "Activity": 28 + }, + { + "Hour": 45, + "Day": 9, + "Activity": 23 + }, + { + "Hour": 45, + "Day": 10, + "Activity": 77 + }, + { + "Hour": 45, + "Day": 11, + "Activity": 18 + }, + { + "Hour": 45, + "Day": 12, + "Activity": 96 + }, + { + "Hour": 45, + "Day": 13, + "Activity": 78 + }, + { + "Hour": 45, + "Day": 14, + "Activity": 48 + }, + { + "Hour": 45, + "Day": 15, + "Activity": 24 + }, + { + "Hour": 45, + "Day": 16, + "Activity": 94 + }, + { + "Hour": 45, + "Day": 17, + "Activity": 15 + }, + { + "Hour": 45, + "Day": 18, + "Activity": 78 + }, + { + "Hour": 45, + "Day": 19, + "Activity": 77 + }, + { + "Hour": 45, + "Day": 20, + "Activity": 84 + }, + { + "Hour": 45, + "Day": 21, + "Activity": 7 + }, + { + "Hour": 45, + "Day": 22, + "Activity": 39 + }, + { + "Hour": 45, + "Day": 23, + "Activity": 93 + }, + { + "Hour": 45, + "Day": 24, + "Activity": 48 + }, + { + "Hour": 45, + "Day": 25, + "Activity": 31 + }, + { + "Hour": 45, + "Day": 26, + "Activity": 34 + }, + { + "Hour": 45, + "Day": 27, + "Activity": 67 + }, + { + "Hour": 45, + "Day": 28, + "Activity": 66 + }, + { + "Hour": 45, + "Day": 29, + "Activity": 12 + }, + { + "Hour": 46, + "Day": 0, + "Activity": 18 + }, + { + "Hour": 46, + "Day": 1, + "Activity": 60 + }, + { + "Hour": 46, + "Day": 2, + "Activity": 59 + }, + { + "Hour": 46, + "Day": 3, + "Activity": 21 + }, + { + "Hour": 46, + "Day": 4, + "Activity": 88 + }, + { + "Hour": 46, + "Day": 5, + "Activity": 53 + }, + { + "Hour": 46, + "Day": 6, + "Activity": 59 + }, + { + "Hour": 46, + "Day": 7, + "Activity": 64 + }, + { + "Hour": 46, + "Day": 8, + "Activity": 53 + }, + { + "Hour": 46, + "Day": 9, + "Activity": 72 + }, + { + "Hour": 46, + "Day": 10, + "Activity": 13 + }, + { + "Hour": 46, + "Day": 11, + "Activity": 78 + }, + { + "Hour": 46, + "Day": 12, + "Activity": 56 + }, + { + "Hour": 46, + "Day": 13, + "Activity": 16 + }, + { + "Hour": 46, + "Day": 14, + "Activity": 43 + }, + { + "Hour": 46, + "Day": 15, + "Activity": 8 + }, + { + "Hour": 46, + "Day": 16, + "Activity": 79 + }, + { + "Hour": 46, + "Day": 17, + "Activity": 69 + }, + { + "Hour": 46, + "Day": 18, + "Activity": 16 + }, + { + "Hour": 46, + "Day": 19, + "Activity": 84 + }, + { + "Hour": 46, + "Day": 20, + "Activity": 55 + }, + { + "Hour": 46, + "Day": 21, + "Activity": 11 + }, + { + "Hour": 46, + "Day": 22, + "Activity": 1 + }, + { + "Hour": 46, + "Day": 23, + "Activity": 56 + }, + { + "Hour": 46, + "Day": 24, + "Activity": 94 + }, + { + "Hour": 46, + "Day": 25, + "Activity": 36 + }, + { + "Hour": 46, + "Day": 26, + "Activity": 66 + }, + { + "Hour": 46, + "Day": 27, + "Activity": 31 + }, + { + "Hour": 46, + "Day": 28, + "Activity": 79 + }, + { + "Hour": 46, + "Day": 29, + "Activity": 83 + }, + { + "Hour": 47, + "Day": 0, + "Activity": 35 + }, + { + "Hour": 47, + "Day": 1, + "Activity": 43 + }, + { + "Hour": 47, + "Day": 2, + "Activity": 19 + }, + { + "Hour": 47, + "Day": 3, + "Activity": 76 + }, + { + "Hour": 47, + "Day": 4, + "Activity": 63 + }, + { + "Hour": 47, + "Day": 5, + "Activity": 70 + }, + { + "Hour": 47, + "Day": 6, + "Activity": 74 + }, + { + "Hour": 47, + "Day": 7, + "Activity": 22 + }, + { + "Hour": 47, + "Day": 8, + "Activity": 94 + }, + { + "Hour": 47, + "Day": 9, + "Activity": 48 + }, + { + "Hour": 47, + "Day": 10, + "Activity": 64 + }, + { + "Hour": 47, + "Day": 11, + "Activity": 20 + }, + { + "Hour": 47, + "Day": 12, + "Activity": 73 + }, + { + "Hour": 47, + "Day": 13, + "Activity": 28 + }, + { + "Hour": 47, + "Day": 14, + "Activity": 76 + }, + { + "Hour": 47, + "Day": 15, + "Activity": 51 + }, + { + "Hour": 47, + "Day": 16, + "Activity": 30 + }, + { + "Hour": 47, + "Day": 17, + "Activity": 61 + }, + { + "Hour": 47, + "Day": 18, + "Activity": 15 + }, + { + "Hour": 47, + "Day": 19, + "Activity": 82 + }, + { + "Hour": 47, + "Day": 20, + "Activity": 23 + }, + { + "Hour": 47, + "Day": 21, + "Activity": 81 + }, + { + "Hour": 47, + "Day": 22, + "Activity": 92 + }, + { + "Hour": 47, + "Day": 23, + "Activity": 100 + }, + { + "Hour": 47, + "Day": 24, + "Activity": 69 + }, + { + "Hour": 47, + "Day": 25, + "Activity": 85 + }, + { + "Hour": 47, + "Day": 26, + "Activity": 98 + }, + { + "Hour": 47, + "Day": 27, + "Activity": 15 + }, + { + "Hour": 47, + "Day": 28, + "Activity": 64 + }, + { + "Hour": 47, + "Day": 29, + "Activity": 52 + }, + { + "Hour": 48, + "Day": 0, + "Activity": 75 + }, + { + "Hour": 48, + "Day": 1, + "Activity": 76 + }, + { + "Hour": 48, + "Day": 2, + "Activity": 92 + }, + { + "Hour": 48, + "Day": 3, + "Activity": 16 + }, + { + "Hour": 48, + "Day": 4, + "Activity": 30 + }, + { + "Hour": 48, + "Day": 5, + "Activity": 83 + }, + { + "Hour": 48, + "Day": 6, + "Activity": 90 + }, + { + "Hour": 48, + "Day": 7, + "Activity": 23 + }, + { + "Hour": 48, + "Day": 8, + "Activity": 94 + }, + { + "Hour": 48, + "Day": 9, + "Activity": 68 + }, + { + "Hour": 48, + "Day": 10, + "Activity": 68 + }, + { + "Hour": 48, + "Day": 11, + "Activity": 49 + }, + { + "Hour": 48, + "Day": 12, + "Activity": 2 + }, + { + "Hour": 48, + "Day": 13, + "Activity": 58 + }, + { + "Hour": 48, + "Day": 14, + "Activity": 57 + }, + { + "Hour": 48, + "Day": 15, + "Activity": 70 + }, + { + "Hour": 48, + "Day": 16, + "Activity": 2 + }, + { + "Hour": 48, + "Day": 17, + "Activity": 33 + }, + { + "Hour": 48, + "Day": 18, + "Activity": 40 + }, + { + "Hour": 48, + "Day": 19, + "Activity": 81 + }, + { + "Hour": 48, + "Day": 20, + "Activity": 65 + }, + { + "Hour": 48, + "Day": 21, + "Activity": 60 + }, + { + "Hour": 48, + "Day": 22, + "Activity": 94 + }, + { + "Hour": 48, + "Day": 23, + "Activity": 17 + }, + { + "Hour": 48, + "Day": 24, + "Activity": 22 + }, + { + "Hour": 48, + "Day": 25, + "Activity": 72 + }, + { + "Hour": 48, + "Day": 26, + "Activity": 83 + }, + { + "Hour": 48, + "Day": 27, + "Activity": 57 + }, + { + "Hour": 48, + "Day": 28, + "Activity": 29 + }, + { + "Hour": 48, + "Day": 29, + "Activity": 47 + }, + { + "Hour": 49, + "Day": 0, + "Activity": 25 + }, + { + "Hour": 49, + "Day": 1, + "Activity": 74 + }, + { + "Hour": 49, + "Day": 2, + "Activity": 39 + }, + { + "Hour": 49, + "Day": 3, + "Activity": 49 + }, + { + "Hour": 49, + "Day": 4, + "Activity": 54 + }, + { + "Hour": 49, + "Day": 5, + "Activity": 20 + }, + { + "Hour": 49, + "Day": 6, + "Activity": 97 + }, + { + "Hour": 49, + "Day": 7, + "Activity": 78 + }, + { + "Hour": 49, + "Day": 8, + "Activity": 82 + }, + { + "Hour": 49, + "Day": 9, + "Activity": 33 + }, + { + "Hour": 49, + "Day": 10, + "Activity": 96 + }, + { + "Hour": 49, + "Day": 11, + "Activity": 89 + }, + { + "Hour": 49, + "Day": 12, + "Activity": 66 + }, + { + "Hour": 49, + "Day": 13, + "Activity": 22 + }, + { + "Hour": 49, + "Day": 14, + "Activity": 32 + }, + { + "Hour": 49, + "Day": 15, + "Activity": 85 + }, + { + "Hour": 49, + "Day": 16, + "Activity": 89 + }, + { + "Hour": 49, + "Day": 17, + "Activity": 61 + }, + { + "Hour": 49, + "Day": 18, + "Activity": 67 + }, + { + "Hour": 49, + "Day": 19, + "Activity": 41 + }, + { + "Hour": 49, + "Day": 20, + "Activity": 94 + }, + { + "Hour": 49, + "Day": 21, + "Activity": 43 + }, + { + "Hour": 49, + "Day": 22, + "Activity": 59 + }, + { + "Hour": 49, + "Day": 23, + "Activity": 65 + }, + { + "Hour": 49, + "Day": 24, + "Activity": 22 + }, + { + "Hour": 49, + "Day": 25, + "Activity": 25 + }, + { + "Hour": 49, + "Day": 26, + "Activity": 3 + }, + { + "Hour": 49, + "Day": 27, + "Activity": 18 + }, + { + "Hour": 49, + "Day": 28, + "Activity": 39 + }, + { + "Hour": 49, + "Day": 29, + "Activity": 58 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/heatmap/03-card12.flint.json b/test-harness/excel/evaluations/inputs/heatmap/03-card12.flint.json new file mode 100644 index 00000000..3714b735 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/heatmap/03-card12.flint.json @@ -0,0 +1,383 @@ +{ + "semantic_types": { + "Month": "Month", + "Product": "Product", + "Sales": "Amount" + }, + "chart_spec": { + "chartType": "Heatmap", + "encodings": { + "x": "Month", + "y": "Product", + "color": "Sales" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Month": "Jan", + "Product": "Laptop", + "Sales": 351 + }, + { + "Month": "Jan", + "Product": "Phone", + "Sales": 917 + }, + { + "Month": "Jan", + "Product": "Tablet", + "Sales": 456 + }, + { + "Month": "Jan", + "Product": "Desktop", + "Sales": 803 + }, + { + "Month": "Jan", + "Product": "Monitor", + "Sales": 65 + }, + { + "Month": "Jan", + "Product": "Keyboard", + "Sales": 442 + }, + { + "Month": "Feb", + "Product": "Laptop", + "Sales": 435 + }, + { + "Month": "Feb", + "Product": "Phone", + "Sales": 552 + }, + { + "Month": "Feb", + "Product": "Tablet", + "Sales": 883 + }, + { + "Month": "Feb", + "Product": "Desktop", + "Sales": 602 + }, + { + "Month": "Feb", + "Product": "Monitor", + "Sales": 658 + }, + { + "Month": "Feb", + "Product": "Keyboard", + "Sales": 898 + }, + { + "Month": "Mar", + "Product": "Laptop", + "Sales": 850 + }, + { + "Month": "Mar", + "Product": "Phone", + "Sales": 142 + }, + { + "Month": "Mar", + "Product": "Tablet", + "Sales": 643 + }, + { + "Month": "Mar", + "Product": "Desktop", + "Sales": 349 + }, + { + "Month": "Mar", + "Product": "Monitor", + "Sales": 614 + }, + { + "Month": "Mar", + "Product": "Keyboard", + "Sales": 375 + }, + { + "Month": "Apr", + "Product": "Laptop", + "Sales": 113 + }, + { + "Month": "Apr", + "Product": "Phone", + "Sales": 140 + }, + { + "Month": "Apr", + "Product": "Tablet", + "Sales": 910 + }, + { + "Month": "Apr", + "Product": "Desktop", + "Sales": 589 + }, + { + "Month": "Apr", + "Product": "Monitor", + "Sales": 525 + }, + { + "Month": "Apr", + "Product": "Keyboard", + "Sales": 197 + }, + { + "Month": "May", + "Product": "Laptop", + "Sales": 574 + }, + { + "Month": "May", + "Product": "Phone", + "Sales": 731 + }, + { + "Month": "May", + "Product": "Tablet", + "Sales": 200 + }, + { + "Month": "May", + "Product": "Desktop", + "Sales": 146 + }, + { + "Month": "May", + "Product": "Monitor", + "Sales": 91 + }, + { + "Month": "May", + "Product": "Keyboard", + "Sales": 152 + }, + { + "Month": "Jun", + "Product": "Laptop", + "Sales": 828 + }, + { + "Month": "Jun", + "Product": "Phone", + "Sales": 120 + }, + { + "Month": "Jun", + "Product": "Tablet", + "Sales": 876 + }, + { + "Month": "Jun", + "Product": "Desktop", + "Sales": 979 + }, + { + "Month": "Jun", + "Product": "Monitor", + "Sales": 775 + }, + { + "Month": "Jun", + "Product": "Keyboard", + "Sales": 19 + }, + { + "Month": "Jul", + "Product": "Laptop", + "Sales": 789 + }, + { + "Month": "Jul", + "Product": "Phone", + "Sales": 3 + }, + { + "Month": "Jul", + "Product": "Tablet", + "Sales": 734 + }, + { + "Month": "Jul", + "Product": "Desktop", + "Sales": 964 + }, + { + "Month": "Jul", + "Product": "Monitor", + "Sales": 508 + }, + { + "Month": "Jul", + "Product": "Keyboard", + "Sales": 519 + }, + { + "Month": "Aug", + "Product": "Laptop", + "Sales": 259 + }, + { + "Month": "Aug", + "Product": "Phone", + "Sales": 690 + }, + { + "Month": "Aug", + "Product": "Tablet", + "Sales": 715 + }, + { + "Month": "Aug", + "Product": "Desktop", + "Sales": 466 + }, + { + "Month": "Aug", + "Product": "Monitor", + "Sales": 336 + }, + { + "Month": "Aug", + "Product": "Keyboard", + "Sales": 554 + }, + { + "Month": "Sep", + "Product": "Laptop", + "Sales": 539 + }, + { + "Month": "Sep", + "Product": "Phone", + "Sales": 515 + }, + { + "Month": "Sep", + "Product": "Tablet", + "Sales": 818 + }, + { + "Month": "Sep", + "Product": "Desktop", + "Sales": 572 + }, + { + "Month": "Sep", + "Product": "Monitor", + "Sales": 381 + }, + { + "Month": "Sep", + "Product": "Keyboard", + "Sales": 691 + }, + { + "Month": "Oct", + "Product": "Laptop", + "Sales": 897 + }, + { + "Month": "Oct", + "Product": "Phone", + "Sales": 845 + }, + { + "Month": "Oct", + "Product": "Tablet", + "Sales": 154 + }, + { + "Month": "Oct", + "Product": "Desktop", + "Sales": 293 + }, + { + "Month": "Oct", + "Product": "Monitor", + "Sales": 582 + }, + { + "Month": "Oct", + "Product": "Keyboard", + "Sales": 810 + }, + { + "Month": "Nov", + "Product": "Laptop", + "Sales": 153 + }, + { + "Month": "Nov", + "Product": "Phone", + "Sales": 155 + }, + { + "Month": "Nov", + "Product": "Tablet", + "Sales": 867 + }, + { + "Month": "Nov", + "Product": "Desktop", + "Sales": 835 + }, + { + "Month": "Nov", + "Product": "Monitor", + "Sales": 225 + }, + { + "Month": "Nov", + "Product": "Keyboard", + "Sales": 77 + }, + { + "Month": "Dec", + "Product": "Laptop", + "Sales": 832 + }, + { + "Month": "Dec", + "Product": "Phone", + "Sales": 427 + }, + { + "Month": "Dec", + "Product": "Tablet", + "Sales": 973 + }, + { + "Month": "Dec", + "Product": "Desktop", + "Sales": 478 + }, + { + "Month": "Dec", + "Product": "Monitor", + "Sales": 429 + }, + { + "Month": "Dec", + "Product": "Keyboard", + "Sales": 627 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/heatmap/04-card80.flint.json b/test-harness/excel/evaluations/inputs/heatmap/04-card80.flint.json new file mode 100644 index 00000000..45213aa2 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/heatmap/04-card80.flint.json @@ -0,0 +1,2023 @@ +{ + "semantic_types": { + "Date": "Date", + "Category": "Category", + "Intensity": "Quantity" + }, + "chart_spec": { + "chartType": "Heatmap", + "encodings": { + "x": "Date", + "y": "Category", + "color": "Intensity" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Date": "2016-01-01", + "Category": "Electronics", + "Intensity": 41 + }, + { + "Date": "2016-01-01", + "Category": "Clothing", + "Intensity": 12 + }, + { + "Date": "2016-01-01", + "Category": "Food", + "Intensity": 15 + }, + { + "Date": "2016-01-01", + "Category": "Books", + "Intensity": 56 + }, + { + "Date": "2016-01-01", + "Category": "Sports", + "Intensity": 90 + }, + { + "Date": "2016-01-14", + "Category": "Electronics", + "Intensity": 7 + }, + { + "Date": "2016-01-14", + "Category": "Clothing", + "Intensity": 97 + }, + { + "Date": "2016-01-14", + "Category": "Food", + "Intensity": 58 + }, + { + "Date": "2016-01-14", + "Category": "Books", + "Intensity": 81 + }, + { + "Date": "2016-01-14", + "Category": "Sports", + "Intensity": 8 + }, + { + "Date": "2016-01-28", + "Category": "Electronics", + "Intensity": 61 + }, + { + "Date": "2016-01-28", + "Category": "Clothing", + "Intensity": 32 + }, + { + "Date": "2016-01-28", + "Category": "Food", + "Intensity": 96 + }, + { + "Date": "2016-01-28", + "Category": "Books", + "Intensity": 62 + }, + { + "Date": "2016-01-28", + "Category": "Sports", + "Intensity": 27 + }, + { + "Date": "2016-02-11", + "Category": "Electronics", + "Intensity": 92 + }, + { + "Date": "2016-02-11", + "Category": "Clothing", + "Intensity": 82 + }, + { + "Date": "2016-02-11", + "Category": "Food", + "Intensity": 30 + }, + { + "Date": "2016-02-11", + "Category": "Books", + "Intensity": 53 + }, + { + "Date": "2016-02-11", + "Category": "Sports", + "Intensity": 46 + }, + { + "Date": "2016-02-24", + "Category": "Electronics", + "Intensity": 61 + }, + { + "Date": "2016-02-24", + "Category": "Clothing", + "Intensity": 31 + }, + { + "Date": "2016-02-24", + "Category": "Food", + "Intensity": 18 + }, + { + "Date": "2016-02-24", + "Category": "Books", + "Intensity": 34 + }, + { + "Date": "2016-02-24", + "Category": "Sports", + "Intensity": 25 + }, + { + "Date": "2016-03-09", + "Category": "Electronics", + "Intensity": 71 + }, + { + "Date": "2016-03-09", + "Category": "Clothing", + "Intensity": 68 + }, + { + "Date": "2016-03-09", + "Category": "Food", + "Intensity": 58 + }, + { + "Date": "2016-03-09", + "Category": "Books", + "Intensity": 10 + }, + { + "Date": "2016-03-09", + "Category": "Sports", + "Intensity": 37 + }, + { + "Date": "2016-03-23", + "Category": "Electronics", + "Intensity": 4 + }, + { + "Date": "2016-03-23", + "Category": "Clothing", + "Intensity": 91 + }, + { + "Date": "2016-03-23", + "Category": "Food", + "Intensity": 45 + }, + { + "Date": "2016-03-23", + "Category": "Books", + "Intensity": 65 + }, + { + "Date": "2016-03-23", + "Category": "Sports", + "Intensity": 24 + }, + { + "Date": "2016-04-05", + "Category": "Electronics", + "Intensity": 93 + }, + { + "Date": "2016-04-05", + "Category": "Clothing", + "Intensity": 24 + }, + { + "Date": "2016-04-05", + "Category": "Food", + "Intensity": 11 + }, + { + "Date": "2016-04-05", + "Category": "Books", + "Intensity": 20 + }, + { + "Date": "2016-04-05", + "Category": "Sports", + "Intensity": 84 + }, + { + "Date": "2016-04-19", + "Category": "Electronics", + "Intensity": 76 + }, + { + "Date": "2016-04-19", + "Category": "Clothing", + "Intensity": 32 + }, + { + "Date": "2016-04-19", + "Category": "Food", + "Intensity": 94 + }, + { + "Date": "2016-04-19", + "Category": "Books", + "Intensity": 26 + }, + { + "Date": "2016-04-19", + "Category": "Sports", + "Intensity": 83 + }, + { + "Date": "2016-05-03", + "Category": "Electronics", + "Intensity": 18 + }, + { + "Date": "2016-05-03", + "Category": "Clothing", + "Intensity": 11 + }, + { + "Date": "2016-05-03", + "Category": "Food", + "Intensity": 70 + }, + { + "Date": "2016-05-03", + "Category": "Books", + "Intensity": 72 + }, + { + "Date": "2016-05-03", + "Category": "Sports", + "Intensity": 5 + }, + { + "Date": "2016-05-16", + "Category": "Electronics", + "Intensity": 35 + }, + { + "Date": "2016-05-16", + "Category": "Clothing", + "Intensity": 61 + }, + { + "Date": "2016-05-16", + "Category": "Food", + "Intensity": 67 + }, + { + "Date": "2016-05-16", + "Category": "Books", + "Intensity": 60 + }, + { + "Date": "2016-05-16", + "Category": "Sports", + "Intensity": 93 + }, + { + "Date": "2016-05-30", + "Category": "Electronics", + "Intensity": 34 + }, + { + "Date": "2016-05-30", + "Category": "Clothing", + "Intensity": 44 + }, + { + "Date": "2016-05-30", + "Category": "Food", + "Intensity": 3 + }, + { + "Date": "2016-05-30", + "Category": "Books", + "Intensity": 99 + }, + { + "Date": "2016-05-30", + "Category": "Sports", + "Intensity": 46 + }, + { + "Date": "2016-06-13", + "Category": "Electronics", + "Intensity": 85 + }, + { + "Date": "2016-06-13", + "Category": "Clothing", + "Intensity": 43 + }, + { + "Date": "2016-06-13", + "Category": "Food", + "Intensity": 79 + }, + { + "Date": "2016-06-13", + "Category": "Books", + "Intensity": 20 + }, + { + "Date": "2016-06-13", + "Category": "Sports", + "Intensity": 87 + }, + { + "Date": "2016-06-26", + "Category": "Electronics", + "Intensity": 83 + }, + { + "Date": "2016-06-26", + "Category": "Clothing", + "Intensity": 38 + }, + { + "Date": "2016-06-26", + "Category": "Food", + "Intensity": 8 + }, + { + "Date": "2016-06-26", + "Category": "Books", + "Intensity": 20 + }, + { + "Date": "2016-06-26", + "Category": "Sports", + "Intensity": 97 + }, + { + "Date": "2016-07-10", + "Category": "Electronics", + "Intensity": 39 + }, + { + "Date": "2016-07-10", + "Category": "Clothing", + "Intensity": 73 + }, + { + "Date": "2016-07-10", + "Category": "Food", + "Intensity": 53 + }, + { + "Date": "2016-07-10", + "Category": "Books", + "Intensity": 91 + }, + { + "Date": "2016-07-10", + "Category": "Sports", + "Intensity": 60 + }, + { + "Date": "2016-07-24", + "Category": "Electronics", + "Intensity": 37 + }, + { + "Date": "2016-07-24", + "Category": "Clothing", + "Intensity": 0 + }, + { + "Date": "2016-07-24", + "Category": "Food", + "Intensity": 51 + }, + { + "Date": "2016-07-24", + "Category": "Books", + "Intensity": 72 + }, + { + "Date": "2016-07-24", + "Category": "Sports", + "Intensity": 53 + }, + { + "Date": "2016-08-07", + "Category": "Electronics", + "Intensity": 90 + }, + { + "Date": "2016-08-07", + "Category": "Clothing", + "Intensity": 100 + }, + { + "Date": "2016-08-07", + "Category": "Food", + "Intensity": 35 + }, + { + "Date": "2016-08-07", + "Category": "Books", + "Intensity": 35 + }, + { + "Date": "2016-08-07", + "Category": "Sports", + "Intensity": 10 + }, + { + "Date": "2016-08-20", + "Category": "Electronics", + "Intensity": 36 + }, + { + "Date": "2016-08-20", + "Category": "Clothing", + "Intensity": 18 + }, + { + "Date": "2016-08-20", + "Category": "Food", + "Intensity": 40 + }, + { + "Date": "2016-08-20", + "Category": "Books", + "Intensity": 52 + }, + { + "Date": "2016-08-20", + "Category": "Sports", + "Intensity": 22 + }, + { + "Date": "2016-09-03", + "Category": "Electronics", + "Intensity": 97 + }, + { + "Date": "2016-09-03", + "Category": "Clothing", + "Intensity": 100 + }, + { + "Date": "2016-09-03", + "Category": "Food", + "Intensity": 20 + }, + { + "Date": "2016-09-03", + "Category": "Books", + "Intensity": 33 + }, + { + "Date": "2016-09-03", + "Category": "Sports", + "Intensity": 63 + }, + { + "Date": "2016-09-17", + "Category": "Electronics", + "Intensity": 3 + }, + { + "Date": "2016-09-17", + "Category": "Clothing", + "Intensity": 80 + }, + { + "Date": "2016-09-17", + "Category": "Food", + "Intensity": 88 + }, + { + "Date": "2016-09-17", + "Category": "Books", + "Intensity": 39 + }, + { + "Date": "2016-09-17", + "Category": "Sports", + "Intensity": 81 + }, + { + "Date": "2016-09-30", + "Category": "Electronics", + "Intensity": 46 + }, + { + "Date": "2016-09-30", + "Category": "Clothing", + "Intensity": 40 + }, + { + "Date": "2016-09-30", + "Category": "Food", + "Intensity": 49 + }, + { + "Date": "2016-09-30", + "Category": "Books", + "Intensity": 16 + }, + { + "Date": "2016-09-30", + "Category": "Sports", + "Intensity": 32 + }, + { + "Date": "2016-10-14", + "Category": "Electronics", + "Intensity": 62 + }, + { + "Date": "2016-10-14", + "Category": "Clothing", + "Intensity": 96 + }, + { + "Date": "2016-10-14", + "Category": "Food", + "Intensity": 2 + }, + { + "Date": "2016-10-14", + "Category": "Books", + "Intensity": 2 + }, + { + "Date": "2016-10-14", + "Category": "Sports", + "Intensity": 3 + }, + { + "Date": "2016-10-28", + "Category": "Electronics", + "Intensity": 92 + }, + { + "Date": "2016-10-28", + "Category": "Clothing", + "Intensity": 15 + }, + { + "Date": "2016-10-28", + "Category": "Food", + "Intensity": 52 + }, + { + "Date": "2016-10-28", + "Category": "Books", + "Intensity": 81 + }, + { + "Date": "2016-10-28", + "Category": "Sports", + "Intensity": 63 + }, + { + "Date": "2016-11-10", + "Category": "Electronics", + "Intensity": 23 + }, + { + "Date": "2016-11-10", + "Category": "Clothing", + "Intensity": 99 + }, + { + "Date": "2016-11-10", + "Category": "Food", + "Intensity": 85 + }, + { + "Date": "2016-11-10", + "Category": "Books", + "Intensity": 38 + }, + { + "Date": "2016-11-10", + "Category": "Sports", + "Intensity": 59 + }, + { + "Date": "2016-11-24", + "Category": "Electronics", + "Intensity": 41 + }, + { + "Date": "2016-11-24", + "Category": "Clothing", + "Intensity": 60 + }, + { + "Date": "2016-11-24", + "Category": "Food", + "Intensity": 38 + }, + { + "Date": "2016-11-24", + "Category": "Books", + "Intensity": 33 + }, + { + "Date": "2016-11-24", + "Category": "Sports", + "Intensity": 68 + }, + { + "Date": "2016-12-08", + "Category": "Electronics", + "Intensity": 83 + }, + { + "Date": "2016-12-08", + "Category": "Clothing", + "Intensity": 30 + }, + { + "Date": "2016-12-08", + "Category": "Food", + "Intensity": 8 + }, + { + "Date": "2016-12-08", + "Category": "Books", + "Intensity": 93 + }, + { + "Date": "2016-12-08", + "Category": "Sports", + "Intensity": 60 + }, + { + "Date": "2016-12-21", + "Category": "Electronics", + "Intensity": 99 + }, + { + "Date": "2016-12-21", + "Category": "Clothing", + "Intensity": 53 + }, + { + "Date": "2016-12-21", + "Category": "Food", + "Intensity": 89 + }, + { + "Date": "2016-12-21", + "Category": "Books", + "Intensity": 33 + }, + { + "Date": "2016-12-21", + "Category": "Sports", + "Intensity": 20 + }, + { + "Date": "2017-01-04", + "Category": "Electronics", + "Intensity": 95 + }, + { + "Date": "2017-01-04", + "Category": "Clothing", + "Intensity": 5 + }, + { + "Date": "2017-01-04", + "Category": "Food", + "Intensity": 96 + }, + { + "Date": "2017-01-04", + "Category": "Books", + "Intensity": 38 + }, + { + "Date": "2017-01-04", + "Category": "Sports", + "Intensity": 20 + }, + { + "Date": "2017-01-18", + "Category": "Electronics", + "Intensity": 89 + }, + { + "Date": "2017-01-18", + "Category": "Clothing", + "Intensity": 53 + }, + { + "Date": "2017-01-18", + "Category": "Food", + "Intensity": 35 + }, + { + "Date": "2017-01-18", + "Category": "Books", + "Intensity": 55 + }, + { + "Date": "2017-01-18", + "Category": "Sports", + "Intensity": 22 + }, + { + "Date": "2017-01-31", + "Category": "Electronics", + "Intensity": 35 + }, + { + "Date": "2017-01-31", + "Category": "Clothing", + "Intensity": 45 + }, + { + "Date": "2017-01-31", + "Category": "Food", + "Intensity": 24 + }, + { + "Date": "2017-01-31", + "Category": "Books", + "Intensity": 73 + }, + { + "Date": "2017-01-31", + "Category": "Sports", + "Intensity": 31 + }, + { + "Date": "2017-02-14", + "Category": "Electronics", + "Intensity": 86 + }, + { + "Date": "2017-02-14", + "Category": "Clothing", + "Intensity": 24 + }, + { + "Date": "2017-02-14", + "Category": "Food", + "Intensity": 34 + }, + { + "Date": "2017-02-14", + "Category": "Books", + "Intensity": 16 + }, + { + "Date": "2017-02-14", + "Category": "Sports", + "Intensity": 55 + }, + { + "Date": "2017-02-28", + "Category": "Electronics", + "Intensity": 0 + }, + { + "Date": "2017-02-28", + "Category": "Clothing", + "Intensity": 75 + }, + { + "Date": "2017-02-28", + "Category": "Food", + "Intensity": 7 + }, + { + "Date": "2017-02-28", + "Category": "Books", + "Intensity": 11 + }, + { + "Date": "2017-02-28", + "Category": "Sports", + "Intensity": 20 + }, + { + "Date": "2017-03-14", + "Category": "Electronics", + "Intensity": 100 + }, + { + "Date": "2017-03-14", + "Category": "Clothing", + "Intensity": 85 + }, + { + "Date": "2017-03-14", + "Category": "Food", + "Intensity": 93 + }, + { + "Date": "2017-03-14", + "Category": "Books", + "Intensity": 63 + }, + { + "Date": "2017-03-14", + "Category": "Sports", + "Intensity": 47 + }, + { + "Date": "2017-03-27", + "Category": "Electronics", + "Intensity": 56 + }, + { + "Date": "2017-03-27", + "Category": "Clothing", + "Intensity": 77 + }, + { + "Date": "2017-03-27", + "Category": "Food", + "Intensity": 41 + }, + { + "Date": "2017-03-27", + "Category": "Books", + "Intensity": 18 + }, + { + "Date": "2017-03-27", + "Category": "Sports", + "Intensity": 98 + }, + { + "Date": "2017-04-10", + "Category": "Electronics", + "Intensity": 28 + }, + { + "Date": "2017-04-10", + "Category": "Clothing", + "Intensity": 59 + }, + { + "Date": "2017-04-10", + "Category": "Food", + "Intensity": 40 + }, + { + "Date": "2017-04-10", + "Category": "Books", + "Intensity": 35 + }, + { + "Date": "2017-04-10", + "Category": "Sports", + "Intensity": 80 + }, + { + "Date": "2017-04-24", + "Category": "Electronics", + "Intensity": 30 + }, + { + "Date": "2017-04-24", + "Category": "Clothing", + "Intensity": 0 + }, + { + "Date": "2017-04-24", + "Category": "Food", + "Intensity": 71 + }, + { + "Date": "2017-04-24", + "Category": "Books", + "Intensity": 75 + }, + { + "Date": "2017-04-24", + "Category": "Sports", + "Intensity": 33 + }, + { + "Date": "2017-05-07", + "Category": "Electronics", + "Intensity": 12 + }, + { + "Date": "2017-05-07", + "Category": "Clothing", + "Intensity": 51 + }, + { + "Date": "2017-05-07", + "Category": "Food", + "Intensity": 99 + }, + { + "Date": "2017-05-07", + "Category": "Books", + "Intensity": 5 + }, + { + "Date": "2017-05-07", + "Category": "Sports", + "Intensity": 15 + }, + { + "Date": "2017-05-21", + "Category": "Electronics", + "Intensity": 73 + }, + { + "Date": "2017-05-21", + "Category": "Clothing", + "Intensity": 80 + }, + { + "Date": "2017-05-21", + "Category": "Food", + "Intensity": 85 + }, + { + "Date": "2017-05-21", + "Category": "Books", + "Intensity": 45 + }, + { + "Date": "2017-05-21", + "Category": "Sports", + "Intensity": 3 + }, + { + "Date": "2017-06-04", + "Category": "Electronics", + "Intensity": 44 + }, + { + "Date": "2017-06-04", + "Category": "Clothing", + "Intensity": 96 + }, + { + "Date": "2017-06-04", + "Category": "Food", + "Intensity": 55 + }, + { + "Date": "2017-06-04", + "Category": "Books", + "Intensity": 79 + }, + { + "Date": "2017-06-04", + "Category": "Sports", + "Intensity": 60 + }, + { + "Date": "2017-06-17", + "Category": "Electronics", + "Intensity": 92 + }, + { + "Date": "2017-06-17", + "Category": "Clothing", + "Intensity": 53 + }, + { + "Date": "2017-06-17", + "Category": "Food", + "Intensity": 42 + }, + { + "Date": "2017-06-17", + "Category": "Books", + "Intensity": 72 + }, + { + "Date": "2017-06-17", + "Category": "Sports", + "Intensity": 48 + }, + { + "Date": "2017-07-01", + "Category": "Electronics", + "Intensity": 26 + }, + { + "Date": "2017-07-01", + "Category": "Clothing", + "Intensity": 55 + }, + { + "Date": "2017-07-01", + "Category": "Food", + "Intensity": 35 + }, + { + "Date": "2017-07-01", + "Category": "Books", + "Intensity": 68 + }, + { + "Date": "2017-07-01", + "Category": "Sports", + "Intensity": 76 + }, + { + "Date": "2017-07-15", + "Category": "Electronics", + "Intensity": 72 + }, + { + "Date": "2017-07-15", + "Category": "Clothing", + "Intensity": 55 + }, + { + "Date": "2017-07-15", + "Category": "Food", + "Intensity": 10 + }, + { + "Date": "2017-07-15", + "Category": "Books", + "Intensity": 73 + }, + { + "Date": "2017-07-15", + "Category": "Sports", + "Intensity": 9 + }, + { + "Date": "2017-07-28", + "Category": "Electronics", + "Intensity": 5 + }, + { + "Date": "2017-07-28", + "Category": "Clothing", + "Intensity": 92 + }, + { + "Date": "2017-07-28", + "Category": "Food", + "Intensity": 16 + }, + { + "Date": "2017-07-28", + "Category": "Books", + "Intensity": 42 + }, + { + "Date": "2017-07-28", + "Category": "Sports", + "Intensity": 73 + }, + { + "Date": "2017-08-11", + "Category": "Electronics", + "Intensity": 37 + }, + { + "Date": "2017-08-11", + "Category": "Clothing", + "Intensity": 41 + }, + { + "Date": "2017-08-11", + "Category": "Food", + "Intensity": 100 + }, + { + "Date": "2017-08-11", + "Category": "Books", + "Intensity": 92 + }, + { + "Date": "2017-08-11", + "Category": "Sports", + "Intensity": 39 + }, + { + "Date": "2017-08-25", + "Category": "Electronics", + "Intensity": 48 + }, + { + "Date": "2017-08-25", + "Category": "Clothing", + "Intensity": 86 + }, + { + "Date": "2017-08-25", + "Category": "Food", + "Intensity": 82 + }, + { + "Date": "2017-08-25", + "Category": "Books", + "Intensity": 48 + }, + { + "Date": "2017-08-25", + "Category": "Sports", + "Intensity": 37 + }, + { + "Date": "2017-09-07", + "Category": "Electronics", + "Intensity": 30 + }, + { + "Date": "2017-09-07", + "Category": "Clothing", + "Intensity": 81 + }, + { + "Date": "2017-09-07", + "Category": "Food", + "Intensity": 11 + }, + { + "Date": "2017-09-07", + "Category": "Books", + "Intensity": 73 + }, + { + "Date": "2017-09-07", + "Category": "Sports", + "Intensity": 24 + }, + { + "Date": "2017-09-21", + "Category": "Electronics", + "Intensity": 61 + }, + { + "Date": "2017-09-21", + "Category": "Clothing", + "Intensity": 72 + }, + { + "Date": "2017-09-21", + "Category": "Food", + "Intensity": 23 + }, + { + "Date": "2017-09-21", + "Category": "Books", + "Intensity": 58 + }, + { + "Date": "2017-09-21", + "Category": "Sports", + "Intensity": 41 + }, + { + "Date": "2017-10-05", + "Category": "Electronics", + "Intensity": 31 + }, + { + "Date": "2017-10-05", + "Category": "Clothing", + "Intensity": 10 + }, + { + "Date": "2017-10-05", + "Category": "Food", + "Intensity": 35 + }, + { + "Date": "2017-10-05", + "Category": "Books", + "Intensity": 43 + }, + { + "Date": "2017-10-05", + "Category": "Sports", + "Intensity": 92 + }, + { + "Date": "2017-10-19", + "Category": "Electronics", + "Intensity": 25 + }, + { + "Date": "2017-10-19", + "Category": "Clothing", + "Intensity": 41 + }, + { + "Date": "2017-10-19", + "Category": "Food", + "Intensity": 85 + }, + { + "Date": "2017-10-19", + "Category": "Books", + "Intensity": 87 + }, + { + "Date": "2017-10-19", + "Category": "Sports", + "Intensity": 76 + }, + { + "Date": "2017-11-01", + "Category": "Electronics", + "Intensity": 62 + }, + { + "Date": "2017-11-01", + "Category": "Clothing", + "Intensity": 76 + }, + { + "Date": "2017-11-01", + "Category": "Food", + "Intensity": 42 + }, + { + "Date": "2017-11-01", + "Category": "Books", + "Intensity": 9 + }, + { + "Date": "2017-11-01", + "Category": "Sports", + "Intensity": 13 + }, + { + "Date": "2017-11-15", + "Category": "Electronics", + "Intensity": 18 + }, + { + "Date": "2017-11-15", + "Category": "Clothing", + "Intensity": 89 + }, + { + "Date": "2017-11-15", + "Category": "Food", + "Intensity": 90 + }, + { + "Date": "2017-11-15", + "Category": "Books", + "Intensity": 24 + }, + { + "Date": "2017-11-15", + "Category": "Sports", + "Intensity": 95 + }, + { + "Date": "2017-11-29", + "Category": "Electronics", + "Intensity": 92 + }, + { + "Date": "2017-11-29", + "Category": "Clothing", + "Intensity": 88 + }, + { + "Date": "2017-11-29", + "Category": "Food", + "Intensity": 32 + }, + { + "Date": "2017-11-29", + "Category": "Books", + "Intensity": 43 + }, + { + "Date": "2017-11-29", + "Category": "Sports", + "Intensity": 47 + }, + { + "Date": "2017-12-12", + "Category": "Electronics", + "Intensity": 36 + }, + { + "Date": "2017-12-12", + "Category": "Clothing", + "Intensity": 13 + }, + { + "Date": "2017-12-12", + "Category": "Food", + "Intensity": 30 + }, + { + "Date": "2017-12-12", + "Category": "Books", + "Intensity": 17 + }, + { + "Date": "2017-12-12", + "Category": "Sports", + "Intensity": 24 + }, + { + "Date": "2017-12-26", + "Category": "Electronics", + "Intensity": 23 + }, + { + "Date": "2017-12-26", + "Category": "Clothing", + "Intensity": 17 + }, + { + "Date": "2017-12-26", + "Category": "Food", + "Intensity": 90 + }, + { + "Date": "2017-12-26", + "Category": "Books", + "Intensity": 36 + }, + { + "Date": "2017-12-26", + "Category": "Sports", + "Intensity": 28 + }, + { + "Date": "2018-01-09", + "Category": "Electronics", + "Intensity": 65 + }, + { + "Date": "2018-01-09", + "Category": "Clothing", + "Intensity": 67 + }, + { + "Date": "2018-01-09", + "Category": "Food", + "Intensity": 95 + }, + { + "Date": "2018-01-09", + "Category": "Books", + "Intensity": 19 + }, + { + "Date": "2018-01-09", + "Category": "Sports", + "Intensity": 41 + }, + { + "Date": "2018-01-22", + "Category": "Electronics", + "Intensity": 99 + }, + { + "Date": "2018-01-22", + "Category": "Clothing", + "Intensity": 22 + }, + { + "Date": "2018-01-22", + "Category": "Food", + "Intensity": 47 + }, + { + "Date": "2018-01-22", + "Category": "Books", + "Intensity": 48 + }, + { + "Date": "2018-01-22", + "Category": "Sports", + "Intensity": 65 + }, + { + "Date": "2018-02-05", + "Category": "Electronics", + "Intensity": 99 + }, + { + "Date": "2018-02-05", + "Category": "Clothing", + "Intensity": 66 + }, + { + "Date": "2018-02-05", + "Category": "Food", + "Intensity": 42 + }, + { + "Date": "2018-02-05", + "Category": "Books", + "Intensity": 87 + }, + { + "Date": "2018-02-05", + "Category": "Sports", + "Intensity": 78 + }, + { + "Date": "2018-02-19", + "Category": "Electronics", + "Intensity": 15 + }, + { + "Date": "2018-02-19", + "Category": "Clothing", + "Intensity": 51 + }, + { + "Date": "2018-02-19", + "Category": "Food", + "Intensity": 94 + }, + { + "Date": "2018-02-19", + "Category": "Books", + "Intensity": 19 + }, + { + "Date": "2018-02-19", + "Category": "Sports", + "Intensity": 33 + }, + { + "Date": "2018-03-04", + "Category": "Electronics", + "Intensity": 57 + }, + { + "Date": "2018-03-04", + "Category": "Clothing", + "Intensity": 86 + }, + { + "Date": "2018-03-04", + "Category": "Food", + "Intensity": 30 + }, + { + "Date": "2018-03-04", + "Category": "Books", + "Intensity": 63 + }, + { + "Date": "2018-03-04", + "Category": "Sports", + "Intensity": 94 + }, + { + "Date": "2018-03-18", + "Category": "Electronics", + "Intensity": 52 + }, + { + "Date": "2018-03-18", + "Category": "Clothing", + "Intensity": 44 + }, + { + "Date": "2018-03-18", + "Category": "Food", + "Intensity": 16 + }, + { + "Date": "2018-03-18", + "Category": "Books", + "Intensity": 79 + }, + { + "Date": "2018-03-18", + "Category": "Sports", + "Intensity": 19 + }, + { + "Date": "2018-04-01", + "Category": "Electronics", + "Intensity": 93 + }, + { + "Date": "2018-04-01", + "Category": "Clothing", + "Intensity": 35 + }, + { + "Date": "2018-04-01", + "Category": "Food", + "Intensity": 8 + }, + { + "Date": "2018-04-01", + "Category": "Books", + "Intensity": 86 + }, + { + "Date": "2018-04-01", + "Category": "Sports", + "Intensity": 30 + }, + { + "Date": "2018-04-14", + "Category": "Electronics", + "Intensity": 67 + }, + { + "Date": "2018-04-14", + "Category": "Clothing", + "Intensity": 5 + }, + { + "Date": "2018-04-14", + "Category": "Food", + "Intensity": 67 + }, + { + "Date": "2018-04-14", + "Category": "Books", + "Intensity": 19 + }, + { + "Date": "2018-04-14", + "Category": "Sports", + "Intensity": 6 + }, + { + "Date": "2018-04-28", + "Category": "Electronics", + "Intensity": 82 + }, + { + "Date": "2018-04-28", + "Category": "Clothing", + "Intensity": 53 + }, + { + "Date": "2018-04-28", + "Category": "Food", + "Intensity": 13 + }, + { + "Date": "2018-04-28", + "Category": "Books", + "Intensity": 76 + }, + { + "Date": "2018-04-28", + "Category": "Sports", + "Intensity": 15 + }, + { + "Date": "2018-05-12", + "Category": "Electronics", + "Intensity": 30 + }, + { + "Date": "2018-05-12", + "Category": "Clothing", + "Intensity": 2 + }, + { + "Date": "2018-05-12", + "Category": "Food", + "Intensity": 49 + }, + { + "Date": "2018-05-12", + "Category": "Books", + "Intensity": 48 + }, + { + "Date": "2018-05-12", + "Category": "Sports", + "Intensity": 61 + }, + { + "Date": "2018-05-26", + "Category": "Electronics", + "Intensity": 67 + }, + { + "Date": "2018-05-26", + "Category": "Clothing", + "Intensity": 30 + }, + { + "Date": "2018-05-26", + "Category": "Food", + "Intensity": 10 + }, + { + "Date": "2018-05-26", + "Category": "Books", + "Intensity": 44 + }, + { + "Date": "2018-05-26", + "Category": "Sports", + "Intensity": 22 + }, + { + "Date": "2018-06-08", + "Category": "Electronics", + "Intensity": 63 + }, + { + "Date": "2018-06-08", + "Category": "Clothing", + "Intensity": 14 + }, + { + "Date": "2018-06-08", + "Category": "Food", + "Intensity": 91 + }, + { + "Date": "2018-06-08", + "Category": "Books", + "Intensity": 30 + }, + { + "Date": "2018-06-08", + "Category": "Sports", + "Intensity": 22 + }, + { + "Date": "2018-06-22", + "Category": "Electronics", + "Intensity": 0 + }, + { + "Date": "2018-06-22", + "Category": "Clothing", + "Intensity": 73 + }, + { + "Date": "2018-06-22", + "Category": "Food", + "Intensity": 21 + }, + { + "Date": "2018-06-22", + "Category": "Books", + "Intensity": 49 + }, + { + "Date": "2018-06-22", + "Category": "Sports", + "Intensity": 83 + }, + { + "Date": "2018-07-06", + "Category": "Electronics", + "Intensity": 42 + }, + { + "Date": "2018-07-06", + "Category": "Clothing", + "Intensity": 7 + }, + { + "Date": "2018-07-06", + "Category": "Food", + "Intensity": 90 + }, + { + "Date": "2018-07-06", + "Category": "Books", + "Intensity": 92 + }, + { + "Date": "2018-07-06", + "Category": "Sports", + "Intensity": 23 + }, + { + "Date": "2018-07-19", + "Category": "Electronics", + "Intensity": 32 + }, + { + "Date": "2018-07-19", + "Category": "Clothing", + "Intensity": 75 + }, + { + "Date": "2018-07-19", + "Category": "Food", + "Intensity": 55 + }, + { + "Date": "2018-07-19", + "Category": "Books", + "Intensity": 74 + }, + { + "Date": "2018-07-19", + "Category": "Sports", + "Intensity": 53 + }, + { + "Date": "2018-08-02", + "Category": "Electronics", + "Intensity": 83 + }, + { + "Date": "2018-08-02", + "Category": "Clothing", + "Intensity": 89 + }, + { + "Date": "2018-08-02", + "Category": "Food", + "Intensity": 23 + }, + { + "Date": "2018-08-02", + "Category": "Books", + "Intensity": 59 + }, + { + "Date": "2018-08-02", + "Category": "Sports", + "Intensity": 41 + }, + { + "Date": "2018-08-16", + "Category": "Electronics", + "Intensity": 24 + }, + { + "Date": "2018-08-16", + "Category": "Clothing", + "Intensity": 39 + }, + { + "Date": "2018-08-16", + "Category": "Food", + "Intensity": 49 + }, + { + "Date": "2018-08-16", + "Category": "Books", + "Intensity": 59 + }, + { + "Date": "2018-08-16", + "Category": "Sports", + "Intensity": 25 + }, + { + "Date": "2018-08-29", + "Category": "Electronics", + "Intensity": 81 + }, + { + "Date": "2018-08-29", + "Category": "Clothing", + "Intensity": 73 + }, + { + "Date": "2018-08-29", + "Category": "Food", + "Intensity": 59 + }, + { + "Date": "2018-08-29", + "Category": "Books", + "Intensity": 90 + }, + { + "Date": "2018-08-29", + "Category": "Sports", + "Intensity": 48 + }, + { + "Date": "2018-09-12", + "Category": "Electronics", + "Intensity": 48 + }, + { + "Date": "2018-09-12", + "Category": "Clothing", + "Intensity": 79 + }, + { + "Date": "2018-09-12", + "Category": "Food", + "Intensity": 98 + }, + { + "Date": "2018-09-12", + "Category": "Books", + "Intensity": 57 + }, + { + "Date": "2018-09-12", + "Category": "Sports", + "Intensity": 60 + }, + { + "Date": "2018-09-26", + "Category": "Electronics", + "Intensity": 27 + }, + { + "Date": "2018-09-26", + "Category": "Clothing", + "Intensity": 64 + }, + { + "Date": "2018-09-26", + "Category": "Food", + "Intensity": 33 + }, + { + "Date": "2018-09-26", + "Category": "Books", + "Intensity": 38 + }, + { + "Date": "2018-09-26", + "Category": "Sports", + "Intensity": 86 + }, + { + "Date": "2018-10-09", + "Category": "Electronics", + "Intensity": 36 + }, + { + "Date": "2018-10-09", + "Category": "Clothing", + "Intensity": 52 + }, + { + "Date": "2018-10-09", + "Category": "Food", + "Intensity": 71 + }, + { + "Date": "2018-10-09", + "Category": "Books", + "Intensity": 5 + }, + { + "Date": "2018-10-09", + "Category": "Sports", + "Intensity": 35 + }, + { + "Date": "2018-10-23", + "Category": "Electronics", + "Intensity": 32 + }, + { + "Date": "2018-10-23", + "Category": "Clothing", + "Intensity": 78 + }, + { + "Date": "2018-10-23", + "Category": "Food", + "Intensity": 52 + }, + { + "Date": "2018-10-23", + "Category": "Books", + "Intensity": 16 + }, + { + "Date": "2018-10-23", + "Category": "Sports", + "Intensity": 69 + }, + { + "Date": "2018-11-06", + "Category": "Electronics", + "Intensity": 72 + }, + { + "Date": "2018-11-06", + "Category": "Clothing", + "Intensity": 52 + }, + { + "Date": "2018-11-06", + "Category": "Food", + "Intensity": 58 + }, + { + "Date": "2018-11-06", + "Category": "Books", + "Intensity": 14 + }, + { + "Date": "2018-11-06", + "Category": "Sports", + "Intensity": 1 + }, + { + "Date": "2018-11-19", + "Category": "Electronics", + "Intensity": 44 + }, + { + "Date": "2018-11-19", + "Category": "Clothing", + "Intensity": 91 + }, + { + "Date": "2018-11-19", + "Category": "Food", + "Intensity": 43 + }, + { + "Date": "2018-11-19", + "Category": "Books", + "Intensity": 66 + }, + { + "Date": "2018-11-19", + "Category": "Sports", + "Intensity": 51 + }, + { + "Date": "2018-12-03", + "Category": "Electronics", + "Intensity": 15 + }, + { + "Date": "2018-12-03", + "Category": "Clothing", + "Intensity": 86 + }, + { + "Date": "2018-12-03", + "Category": "Food", + "Intensity": 79 + }, + { + "Date": "2018-12-03", + "Category": "Books", + "Intensity": 62 + }, + { + "Date": "2018-12-03", + "Category": "Sports", + "Intensity": 56 + }, + { + "Date": "2018-12-17", + "Category": "Electronics", + "Intensity": 28 + }, + { + "Date": "2018-12-17", + "Category": "Clothing", + "Intensity": 97 + }, + { + "Date": "2018-12-17", + "Category": "Food", + "Intensity": 44 + }, + { + "Date": "2018-12-17", + "Category": "Books", + "Intensity": 2 + }, + { + "Date": "2018-12-17", + "Category": "Sports", + "Intensity": 84 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/heatmap/05-card5.flint.json b/test-harness/excel/evaluations/inputs/heatmap/05-card5.flint.json new file mode 100644 index 00000000..24322504 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/heatmap/05-card5.flint.json @@ -0,0 +1,2023 @@ +{ + "semantic_types": { + "Product": "Product", + "Date": "Date", + "Score": "Score" + }, + "chart_spec": { + "chartType": "Heatmap", + "encodings": { + "x": "Product", + "y": "Date", + "color": "Score" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Product": "Laptop", + "Date": "2016-01-01", + "Score": 39 + }, + { + "Product": "Laptop", + "Date": "2016-01-14", + "Score": 41 + }, + { + "Product": "Laptop", + "Date": "2016-01-28", + "Score": 5 + }, + { + "Product": "Laptop", + "Date": "2016-02-11", + "Score": 47 + }, + { + "Product": "Laptop", + "Date": "2016-02-24", + "Score": 82 + }, + { + "Product": "Laptop", + "Date": "2016-03-09", + "Score": 65 + }, + { + "Product": "Laptop", + "Date": "2016-03-23", + "Score": 24 + }, + { + "Product": "Laptop", + "Date": "2016-04-05", + "Score": 10 + }, + { + "Product": "Laptop", + "Date": "2016-04-19", + "Score": 8 + }, + { + "Product": "Laptop", + "Date": "2016-05-03", + "Score": 18 + }, + { + "Product": "Laptop", + "Date": "2016-05-16", + "Score": 37 + }, + { + "Product": "Laptop", + "Date": "2016-05-30", + "Score": 7 + }, + { + "Product": "Laptop", + "Date": "2016-06-13", + "Score": 42 + }, + { + "Product": "Laptop", + "Date": "2016-06-26", + "Score": 12 + }, + { + "Product": "Laptop", + "Date": "2016-07-10", + "Score": 72 + }, + { + "Product": "Laptop", + "Date": "2016-07-24", + "Score": 13 + }, + { + "Product": "Laptop", + "Date": "2016-08-07", + "Score": 26 + }, + { + "Product": "Laptop", + "Date": "2016-08-20", + "Score": 62 + }, + { + "Product": "Laptop", + "Date": "2016-09-03", + "Score": 91 + }, + { + "Product": "Laptop", + "Date": "2016-09-17", + "Score": 1 + }, + { + "Product": "Laptop", + "Date": "2016-09-30", + "Score": 74 + }, + { + "Product": "Laptop", + "Date": "2016-10-14", + "Score": 84 + }, + { + "Product": "Laptop", + "Date": "2016-10-28", + "Score": 90 + }, + { + "Product": "Laptop", + "Date": "2016-11-10", + "Score": 47 + }, + { + "Product": "Laptop", + "Date": "2016-11-24", + "Score": 36 + }, + { + "Product": "Laptop", + "Date": "2016-12-08", + "Score": 31 + }, + { + "Product": "Laptop", + "Date": "2016-12-21", + "Score": 82 + }, + { + "Product": "Laptop", + "Date": "2017-01-04", + "Score": 37 + }, + { + "Product": "Laptop", + "Date": "2017-01-18", + "Score": 58 + }, + { + "Product": "Laptop", + "Date": "2017-01-31", + "Score": 47 + }, + { + "Product": "Laptop", + "Date": "2017-02-14", + "Score": 55 + }, + { + "Product": "Laptop", + "Date": "2017-02-28", + "Score": 94 + }, + { + "Product": "Laptop", + "Date": "2017-03-14", + "Score": 51 + }, + { + "Product": "Laptop", + "Date": "2017-03-27", + "Score": 34 + }, + { + "Product": "Laptop", + "Date": "2017-04-10", + "Score": 1 + }, + { + "Product": "Laptop", + "Date": "2017-04-24", + "Score": 3 + }, + { + "Product": "Laptop", + "Date": "2017-05-07", + "Score": 7 + }, + { + "Product": "Laptop", + "Date": "2017-05-21", + "Score": 13 + }, + { + "Product": "Laptop", + "Date": "2017-06-04", + "Score": 45 + }, + { + "Product": "Laptop", + "Date": "2017-06-17", + "Score": 79 + }, + { + "Product": "Laptop", + "Date": "2017-07-01", + "Score": 97 + }, + { + "Product": "Laptop", + "Date": "2017-07-15", + "Score": 59 + }, + { + "Product": "Laptop", + "Date": "2017-07-28", + "Score": 52 + }, + { + "Product": "Laptop", + "Date": "2017-08-11", + "Score": 9 + }, + { + "Product": "Laptop", + "Date": "2017-08-25", + "Score": 18 + }, + { + "Product": "Laptop", + "Date": "2017-09-07", + "Score": 69 + }, + { + "Product": "Laptop", + "Date": "2017-09-21", + "Score": 67 + }, + { + "Product": "Laptop", + "Date": "2017-10-05", + "Score": 61 + }, + { + "Product": "Laptop", + "Date": "2017-10-19", + "Score": 60 + }, + { + "Product": "Laptop", + "Date": "2017-11-01", + "Score": 41 + }, + { + "Product": "Laptop", + "Date": "2017-11-15", + "Score": 53 + }, + { + "Product": "Laptop", + "Date": "2017-11-29", + "Score": 99 + }, + { + "Product": "Laptop", + "Date": "2017-12-12", + "Score": 52 + }, + { + "Product": "Laptop", + "Date": "2017-12-26", + "Score": 31 + }, + { + "Product": "Laptop", + "Date": "2018-01-09", + "Score": 81 + }, + { + "Product": "Laptop", + "Date": "2018-01-22", + "Score": 14 + }, + { + "Product": "Laptop", + "Date": "2018-02-05", + "Score": 82 + }, + { + "Product": "Laptop", + "Date": "2018-02-19", + "Score": 53 + }, + { + "Product": "Laptop", + "Date": "2018-03-04", + "Score": 28 + }, + { + "Product": "Laptop", + "Date": "2018-03-18", + "Score": 88 + }, + { + "Product": "Laptop", + "Date": "2018-04-01", + "Score": 11 + }, + { + "Product": "Laptop", + "Date": "2018-04-14", + "Score": 9 + }, + { + "Product": "Laptop", + "Date": "2018-04-28", + "Score": 61 + }, + { + "Product": "Laptop", + "Date": "2018-05-12", + "Score": 5 + }, + { + "Product": "Laptop", + "Date": "2018-05-26", + "Score": 70 + }, + { + "Product": "Laptop", + "Date": "2018-06-08", + "Score": 91 + }, + { + "Product": "Laptop", + "Date": "2018-06-22", + "Score": 90 + }, + { + "Product": "Laptop", + "Date": "2018-07-06", + "Score": 6 + }, + { + "Product": "Laptop", + "Date": "2018-07-19", + "Score": 48 + }, + { + "Product": "Laptop", + "Date": "2018-08-02", + "Score": 11 + }, + { + "Product": "Laptop", + "Date": "2018-08-16", + "Score": 34 + }, + { + "Product": "Laptop", + "Date": "2018-08-29", + "Score": 48 + }, + { + "Product": "Laptop", + "Date": "2018-09-12", + "Score": 83 + }, + { + "Product": "Laptop", + "Date": "2018-09-26", + "Score": 90 + }, + { + "Product": "Laptop", + "Date": "2018-10-09", + "Score": 88 + }, + { + "Product": "Laptop", + "Date": "2018-10-23", + "Score": 94 + }, + { + "Product": "Laptop", + "Date": "2018-11-06", + "Score": 91 + }, + { + "Product": "Laptop", + "Date": "2018-11-19", + "Score": 53 + }, + { + "Product": "Laptop", + "Date": "2018-12-03", + "Score": 47 + }, + { + "Product": "Laptop", + "Date": "2018-12-17", + "Score": 95 + }, + { + "Product": "Phone", + "Date": "2016-01-01", + "Score": 79 + }, + { + "Product": "Phone", + "Date": "2016-01-14", + "Score": 64 + }, + { + "Product": "Phone", + "Date": "2016-01-28", + "Score": 88 + }, + { + "Product": "Phone", + "Date": "2016-02-11", + "Score": 35 + }, + { + "Product": "Phone", + "Date": "2016-02-24", + "Score": 36 + }, + { + "Product": "Phone", + "Date": "2016-03-09", + "Score": 43 + }, + { + "Product": "Phone", + "Date": "2016-03-23", + "Score": 38 + }, + { + "Product": "Phone", + "Date": "2016-04-05", + "Score": 38 + }, + { + "Product": "Phone", + "Date": "2016-04-19", + "Score": 87 + }, + { + "Product": "Phone", + "Date": "2016-05-03", + "Score": 99 + }, + { + "Product": "Phone", + "Date": "2016-05-16", + "Score": 8 + }, + { + "Product": "Phone", + "Date": "2016-05-30", + "Score": 94 + }, + { + "Product": "Phone", + "Date": "2016-06-13", + "Score": 65 + }, + { + "Product": "Phone", + "Date": "2016-06-26", + "Score": 93 + }, + { + "Product": "Phone", + "Date": "2016-07-10", + "Score": 32 + }, + { + "Product": "Phone", + "Date": "2016-07-24", + "Score": 38 + }, + { + "Product": "Phone", + "Date": "2016-08-07", + "Score": 71 + }, + { + "Product": "Phone", + "Date": "2016-08-20", + "Score": 20 + }, + { + "Product": "Phone", + "Date": "2016-09-03", + "Score": 71 + }, + { + "Product": "Phone", + "Date": "2016-09-17", + "Score": 51 + }, + { + "Product": "Phone", + "Date": "2016-09-30", + "Score": 36 + }, + { + "Product": "Phone", + "Date": "2016-10-14", + "Score": 7 + }, + { + "Product": "Phone", + "Date": "2016-10-28", + "Score": 17 + }, + { + "Product": "Phone", + "Date": "2016-11-10", + "Score": 9 + }, + { + "Product": "Phone", + "Date": "2016-11-24", + "Score": 61 + }, + { + "Product": "Phone", + "Date": "2016-12-08", + "Score": 45 + }, + { + "Product": "Phone", + "Date": "2016-12-21", + "Score": 87 + }, + { + "Product": "Phone", + "Date": "2017-01-04", + "Score": 12 + }, + { + "Product": "Phone", + "Date": "2017-01-18", + "Score": 24 + }, + { + "Product": "Phone", + "Date": "2017-01-31", + "Score": 62 + }, + { + "Product": "Phone", + "Date": "2017-02-14", + "Score": 31 + }, + { + "Product": "Phone", + "Date": "2017-02-28", + "Score": 58 + }, + { + "Product": "Phone", + "Date": "2017-03-14", + "Score": 33 + }, + { + "Product": "Phone", + "Date": "2017-03-27", + "Score": 59 + }, + { + "Product": "Phone", + "Date": "2017-04-10", + "Score": 76 + }, + { + "Product": "Phone", + "Date": "2017-04-24", + "Score": 15 + }, + { + "Product": "Phone", + "Date": "2017-05-07", + "Score": 9 + }, + { + "Product": "Phone", + "Date": "2017-05-21", + "Score": 86 + }, + { + "Product": "Phone", + "Date": "2017-06-04", + "Score": 42 + }, + { + "Product": "Phone", + "Date": "2017-06-17", + "Score": 83 + }, + { + "Product": "Phone", + "Date": "2017-07-01", + "Score": 53 + }, + { + "Product": "Phone", + "Date": "2017-07-15", + "Score": 74 + }, + { + "Product": "Phone", + "Date": "2017-07-28", + "Score": 84 + }, + { + "Product": "Phone", + "Date": "2017-08-11", + "Score": 64 + }, + { + "Product": "Phone", + "Date": "2017-08-25", + "Score": 28 + }, + { + "Product": "Phone", + "Date": "2017-09-07", + "Score": 92 + }, + { + "Product": "Phone", + "Date": "2017-09-21", + "Score": 98 + }, + { + "Product": "Phone", + "Date": "2017-10-05", + "Score": 88 + }, + { + "Product": "Phone", + "Date": "2017-10-19", + "Score": 4 + }, + { + "Product": "Phone", + "Date": "2017-11-01", + "Score": 97 + }, + { + "Product": "Phone", + "Date": "2017-11-15", + "Score": 21 + }, + { + "Product": "Phone", + "Date": "2017-11-29", + "Score": 86 + }, + { + "Product": "Phone", + "Date": "2017-12-12", + "Score": 95 + }, + { + "Product": "Phone", + "Date": "2017-12-26", + "Score": 53 + }, + { + "Product": "Phone", + "Date": "2018-01-09", + "Score": 33 + }, + { + "Product": "Phone", + "Date": "2018-01-22", + "Score": 82 + }, + { + "Product": "Phone", + "Date": "2018-02-05", + "Score": 46 + }, + { + "Product": "Phone", + "Date": "2018-02-19", + "Score": 74 + }, + { + "Product": "Phone", + "Date": "2018-03-04", + "Score": 54 + }, + { + "Product": "Phone", + "Date": "2018-03-18", + "Score": 88 + }, + { + "Product": "Phone", + "Date": "2018-04-01", + "Score": 89 + }, + { + "Product": "Phone", + "Date": "2018-04-14", + "Score": 61 + }, + { + "Product": "Phone", + "Date": "2018-04-28", + "Score": 17 + }, + { + "Product": "Phone", + "Date": "2018-05-12", + "Score": 58 + }, + { + "Product": "Phone", + "Date": "2018-05-26", + "Score": 26 + }, + { + "Product": "Phone", + "Date": "2018-06-08", + "Score": 1 + }, + { + "Product": "Phone", + "Date": "2018-06-22", + "Score": 41 + }, + { + "Product": "Phone", + "Date": "2018-07-06", + "Score": 34 + }, + { + "Product": "Phone", + "Date": "2018-07-19", + "Score": 7 + }, + { + "Product": "Phone", + "Date": "2018-08-02", + "Score": 55 + }, + { + "Product": "Phone", + "Date": "2018-08-16", + "Score": 34 + }, + { + "Product": "Phone", + "Date": "2018-08-29", + "Score": 64 + }, + { + "Product": "Phone", + "Date": "2018-09-12", + "Score": 37 + }, + { + "Product": "Phone", + "Date": "2018-09-26", + "Score": 37 + }, + { + "Product": "Phone", + "Date": "2018-10-09", + "Score": 55 + }, + { + "Product": "Phone", + "Date": "2018-10-23", + "Score": 22 + }, + { + "Product": "Phone", + "Date": "2018-11-06", + "Score": 92 + }, + { + "Product": "Phone", + "Date": "2018-11-19", + "Score": 96 + }, + { + "Product": "Phone", + "Date": "2018-12-03", + "Score": 4 + }, + { + "Product": "Phone", + "Date": "2018-12-17", + "Score": 51 + }, + { + "Product": "Tablet", + "Date": "2016-01-01", + "Score": 54 + }, + { + "Product": "Tablet", + "Date": "2016-01-14", + "Score": 76 + }, + { + "Product": "Tablet", + "Date": "2016-01-28", + "Score": 100 + }, + { + "Product": "Tablet", + "Date": "2016-02-11", + "Score": 45 + }, + { + "Product": "Tablet", + "Date": "2016-02-24", + "Score": 7 + }, + { + "Product": "Tablet", + "Date": "2016-03-09", + "Score": 59 + }, + { + "Product": "Tablet", + "Date": "2016-03-23", + "Score": 16 + }, + { + "Product": "Tablet", + "Date": "2016-04-05", + "Score": 50 + }, + { + "Product": "Tablet", + "Date": "2016-04-19", + "Score": 68 + }, + { + "Product": "Tablet", + "Date": "2016-05-03", + "Score": 94 + }, + { + "Product": "Tablet", + "Date": "2016-05-16", + "Score": 41 + }, + { + "Product": "Tablet", + "Date": "2016-05-30", + "Score": 61 + }, + { + "Product": "Tablet", + "Date": "2016-06-13", + "Score": 96 + }, + { + "Product": "Tablet", + "Date": "2016-06-26", + "Score": 18 + }, + { + "Product": "Tablet", + "Date": "2016-07-10", + "Score": 48 + }, + { + "Product": "Tablet", + "Date": "2016-07-24", + "Score": 64 + }, + { + "Product": "Tablet", + "Date": "2016-08-07", + "Score": 51 + }, + { + "Product": "Tablet", + "Date": "2016-08-20", + "Score": 61 + }, + { + "Product": "Tablet", + "Date": "2016-09-03", + "Score": 68 + }, + { + "Product": "Tablet", + "Date": "2016-09-17", + "Score": 65 + }, + { + "Product": "Tablet", + "Date": "2016-09-30", + "Score": 59 + }, + { + "Product": "Tablet", + "Date": "2016-10-14", + "Score": 84 + }, + { + "Product": "Tablet", + "Date": "2016-10-28", + "Score": 78 + }, + { + "Product": "Tablet", + "Date": "2016-11-10", + "Score": 39 + }, + { + "Product": "Tablet", + "Date": "2016-11-24", + "Score": 7 + }, + { + "Product": "Tablet", + "Date": "2016-12-08", + "Score": 69 + }, + { + "Product": "Tablet", + "Date": "2016-12-21", + "Score": 22 + }, + { + "Product": "Tablet", + "Date": "2017-01-04", + "Score": 96 + }, + { + "Product": "Tablet", + "Date": "2017-01-18", + "Score": 5 + }, + { + "Product": "Tablet", + "Date": "2017-01-31", + "Score": 66 + }, + { + "Product": "Tablet", + "Date": "2017-02-14", + "Score": 40 + }, + { + "Product": "Tablet", + "Date": "2017-02-28", + "Score": 13 + }, + { + "Product": "Tablet", + "Date": "2017-03-14", + "Score": 9 + }, + { + "Product": "Tablet", + "Date": "2017-03-27", + "Score": 46 + }, + { + "Product": "Tablet", + "Date": "2017-04-10", + "Score": 57 + }, + { + "Product": "Tablet", + "Date": "2017-04-24", + "Score": 12 + }, + { + "Product": "Tablet", + "Date": "2017-05-07", + "Score": 87 + }, + { + "Product": "Tablet", + "Date": "2017-05-21", + "Score": 57 + }, + { + "Product": "Tablet", + "Date": "2017-06-04", + "Score": 63 + }, + { + "Product": "Tablet", + "Date": "2017-06-17", + "Score": 6 + }, + { + "Product": "Tablet", + "Date": "2017-07-01", + "Score": 80 + }, + { + "Product": "Tablet", + "Date": "2017-07-15", + "Score": 85 + }, + { + "Product": "Tablet", + "Date": "2017-07-28", + "Score": 90 + }, + { + "Product": "Tablet", + "Date": "2017-08-11", + "Score": 40 + }, + { + "Product": "Tablet", + "Date": "2017-08-25", + "Score": 25 + }, + { + "Product": "Tablet", + "Date": "2017-09-07", + "Score": 89 + }, + { + "Product": "Tablet", + "Date": "2017-09-21", + "Score": 52 + }, + { + "Product": "Tablet", + "Date": "2017-10-05", + "Score": 0 + }, + { + "Product": "Tablet", + "Date": "2017-10-19", + "Score": 45 + }, + { + "Product": "Tablet", + "Date": "2017-11-01", + "Score": 31 + }, + { + "Product": "Tablet", + "Date": "2017-11-15", + "Score": 18 + }, + { + "Product": "Tablet", + "Date": "2017-11-29", + "Score": 46 + }, + { + "Product": "Tablet", + "Date": "2017-12-12", + "Score": 12 + }, + { + "Product": "Tablet", + "Date": "2017-12-26", + "Score": 10 + }, + { + "Product": "Tablet", + "Date": "2018-01-09", + "Score": 52 + }, + { + "Product": "Tablet", + "Date": "2018-01-22", + "Score": 90 + }, + { + "Product": "Tablet", + "Date": "2018-02-05", + "Score": 28 + }, + { + "Product": "Tablet", + "Date": "2018-02-19", + "Score": 31 + }, + { + "Product": "Tablet", + "Date": "2018-03-04", + "Score": 21 + }, + { + "Product": "Tablet", + "Date": "2018-03-18", + "Score": 57 + }, + { + "Product": "Tablet", + "Date": "2018-04-01", + "Score": 22 + }, + { + "Product": "Tablet", + "Date": "2018-04-14", + "Score": 95 + }, + { + "Product": "Tablet", + "Date": "2018-04-28", + "Score": 16 + }, + { + "Product": "Tablet", + "Date": "2018-05-12", + "Score": 46 + }, + { + "Product": "Tablet", + "Date": "2018-05-26", + "Score": 53 + }, + { + "Product": "Tablet", + "Date": "2018-06-08", + "Score": 77 + }, + { + "Product": "Tablet", + "Date": "2018-06-22", + "Score": 37 + }, + { + "Product": "Tablet", + "Date": "2018-07-06", + "Score": 20 + }, + { + "Product": "Tablet", + "Date": "2018-07-19", + "Score": 75 + }, + { + "Product": "Tablet", + "Date": "2018-08-02", + "Score": 12 + }, + { + "Product": "Tablet", + "Date": "2018-08-16", + "Score": 6 + }, + { + "Product": "Tablet", + "Date": "2018-08-29", + "Score": 5 + }, + { + "Product": "Tablet", + "Date": "2018-09-12", + "Score": 53 + }, + { + "Product": "Tablet", + "Date": "2018-09-26", + "Score": 92 + }, + { + "Product": "Tablet", + "Date": "2018-10-09", + "Score": 68 + }, + { + "Product": "Tablet", + "Date": "2018-10-23", + "Score": 43 + }, + { + "Product": "Tablet", + "Date": "2018-11-06", + "Score": 17 + }, + { + "Product": "Tablet", + "Date": "2018-11-19", + "Score": 50 + }, + { + "Product": "Tablet", + "Date": "2018-12-03", + "Score": 93 + }, + { + "Product": "Tablet", + "Date": "2018-12-17", + "Score": 64 + }, + { + "Product": "Desktop", + "Date": "2016-01-01", + "Score": 40 + }, + { + "Product": "Desktop", + "Date": "2016-01-14", + "Score": 79 + }, + { + "Product": "Desktop", + "Date": "2016-01-28", + "Score": 54 + }, + { + "Product": "Desktop", + "Date": "2016-02-11", + "Score": 82 + }, + { + "Product": "Desktop", + "Date": "2016-02-24", + "Score": 82 + }, + { + "Product": "Desktop", + "Date": "2016-03-09", + "Score": 67 + }, + { + "Product": "Desktop", + "Date": "2016-03-23", + "Score": 22 + }, + { + "Product": "Desktop", + "Date": "2016-04-05", + "Score": 32 + }, + { + "Product": "Desktop", + "Date": "2016-04-19", + "Score": 26 + }, + { + "Product": "Desktop", + "Date": "2016-05-03", + "Score": 94 + }, + { + "Product": "Desktop", + "Date": "2016-05-16", + "Score": 38 + }, + { + "Product": "Desktop", + "Date": "2016-05-30", + "Score": 23 + }, + { + "Product": "Desktop", + "Date": "2016-06-13", + "Score": 22 + }, + { + "Product": "Desktop", + "Date": "2016-06-26", + "Score": 44 + }, + { + "Product": "Desktop", + "Date": "2016-07-10", + "Score": 33 + }, + { + "Product": "Desktop", + "Date": "2016-07-24", + "Score": 6 + }, + { + "Product": "Desktop", + "Date": "2016-08-07", + "Score": 33 + }, + { + "Product": "Desktop", + "Date": "2016-08-20", + "Score": 84 + }, + { + "Product": "Desktop", + "Date": "2016-09-03", + "Score": 39 + }, + { + "Product": "Desktop", + "Date": "2016-09-17", + "Score": 83 + }, + { + "Product": "Desktop", + "Date": "2016-09-30", + "Score": 64 + }, + { + "Product": "Desktop", + "Date": "2016-10-14", + "Score": 55 + }, + { + "Product": "Desktop", + "Date": "2016-10-28", + "Score": 80 + }, + { + "Product": "Desktop", + "Date": "2016-11-10", + "Score": 67 + }, + { + "Product": "Desktop", + "Date": "2016-11-24", + "Score": 77 + }, + { + "Product": "Desktop", + "Date": "2016-12-08", + "Score": 79 + }, + { + "Product": "Desktop", + "Date": "2016-12-21", + "Score": 97 + }, + { + "Product": "Desktop", + "Date": "2017-01-04", + "Score": 71 + }, + { + "Product": "Desktop", + "Date": "2017-01-18", + "Score": 29 + }, + { + "Product": "Desktop", + "Date": "2017-01-31", + "Score": 0 + }, + { + "Product": "Desktop", + "Date": "2017-02-14", + "Score": 84 + }, + { + "Product": "Desktop", + "Date": "2017-02-28", + "Score": 53 + }, + { + "Product": "Desktop", + "Date": "2017-03-14", + "Score": 82 + }, + { + "Product": "Desktop", + "Date": "2017-03-27", + "Score": 22 + }, + { + "Product": "Desktop", + "Date": "2017-04-10", + "Score": 31 + }, + { + "Product": "Desktop", + "Date": "2017-04-24", + "Score": 5 + }, + { + "Product": "Desktop", + "Date": "2017-05-07", + "Score": 59 + }, + { + "Product": "Desktop", + "Date": "2017-05-21", + "Score": 80 + }, + { + "Product": "Desktop", + "Date": "2017-06-04", + "Score": 80 + }, + { + "Product": "Desktop", + "Date": "2017-06-17", + "Score": 92 + }, + { + "Product": "Desktop", + "Date": "2017-07-01", + "Score": 70 + }, + { + "Product": "Desktop", + "Date": "2017-07-15", + "Score": 96 + }, + { + "Product": "Desktop", + "Date": "2017-07-28", + "Score": 23 + }, + { + "Product": "Desktop", + "Date": "2017-08-11", + "Score": 54 + }, + { + "Product": "Desktop", + "Date": "2017-08-25", + "Score": 47 + }, + { + "Product": "Desktop", + "Date": "2017-09-07", + "Score": 19 + }, + { + "Product": "Desktop", + "Date": "2017-09-21", + "Score": 82 + }, + { + "Product": "Desktop", + "Date": "2017-10-05", + "Score": 31 + }, + { + "Product": "Desktop", + "Date": "2017-10-19", + "Score": 79 + }, + { + "Product": "Desktop", + "Date": "2017-11-01", + "Score": 58 + }, + { + "Product": "Desktop", + "Date": "2017-11-15", + "Score": 51 + }, + { + "Product": "Desktop", + "Date": "2017-11-29", + "Score": 65 + }, + { + "Product": "Desktop", + "Date": "2017-12-12", + "Score": 48 + }, + { + "Product": "Desktop", + "Date": "2017-12-26", + "Score": 51 + }, + { + "Product": "Desktop", + "Date": "2018-01-09", + "Score": 58 + }, + { + "Product": "Desktop", + "Date": "2018-01-22", + "Score": 65 + }, + { + "Product": "Desktop", + "Date": "2018-02-05", + "Score": 96 + }, + { + "Product": "Desktop", + "Date": "2018-02-19", + "Score": 73 + }, + { + "Product": "Desktop", + "Date": "2018-03-04", + "Score": 54 + }, + { + "Product": "Desktop", + "Date": "2018-03-18", + "Score": 2 + }, + { + "Product": "Desktop", + "Date": "2018-04-01", + "Score": 97 + }, + { + "Product": "Desktop", + "Date": "2018-04-14", + "Score": 38 + }, + { + "Product": "Desktop", + "Date": "2018-04-28", + "Score": 39 + }, + { + "Product": "Desktop", + "Date": "2018-05-12", + "Score": 92 + }, + { + "Product": "Desktop", + "Date": "2018-05-26", + "Score": 23 + }, + { + "Product": "Desktop", + "Date": "2018-06-08", + "Score": 22 + }, + { + "Product": "Desktop", + "Date": "2018-06-22", + "Score": 63 + }, + { + "Product": "Desktop", + "Date": "2018-07-06", + "Score": 43 + }, + { + "Product": "Desktop", + "Date": "2018-07-19", + "Score": 67 + }, + { + "Product": "Desktop", + "Date": "2018-08-02", + "Score": 73 + }, + { + "Product": "Desktop", + "Date": "2018-08-16", + "Score": 38 + }, + { + "Product": "Desktop", + "Date": "2018-08-29", + "Score": 23 + }, + { + "Product": "Desktop", + "Date": "2018-09-12", + "Score": 89 + }, + { + "Product": "Desktop", + "Date": "2018-09-26", + "Score": 81 + }, + { + "Product": "Desktop", + "Date": "2018-10-09", + "Score": 15 + }, + { + "Product": "Desktop", + "Date": "2018-10-23", + "Score": 88 + }, + { + "Product": "Desktop", + "Date": "2018-11-06", + "Score": 78 + }, + { + "Product": "Desktop", + "Date": "2018-11-19", + "Score": 99 + }, + { + "Product": "Desktop", + "Date": "2018-12-03", + "Score": 5 + }, + { + "Product": "Desktop", + "Date": "2018-12-17", + "Score": 74 + }, + { + "Product": "Monitor", + "Date": "2016-01-01", + "Score": 65 + }, + { + "Product": "Monitor", + "Date": "2016-01-14", + "Score": 59 + }, + { + "Product": "Monitor", + "Date": "2016-01-28", + "Score": 61 + }, + { + "Product": "Monitor", + "Date": "2016-02-11", + "Score": 63 + }, + { + "Product": "Monitor", + "Date": "2016-02-24", + "Score": 40 + }, + { + "Product": "Monitor", + "Date": "2016-03-09", + "Score": 99 + }, + { + "Product": "Monitor", + "Date": "2016-03-23", + "Score": 82 + }, + { + "Product": "Monitor", + "Date": "2016-04-05", + "Score": 6 + }, + { + "Product": "Monitor", + "Date": "2016-04-19", + "Score": 93 + }, + { + "Product": "Monitor", + "Date": "2016-05-03", + "Score": 59 + }, + { + "Product": "Monitor", + "Date": "2016-05-16", + "Score": 2 + }, + { + "Product": "Monitor", + "Date": "2016-05-30", + "Score": 7 + }, + { + "Product": "Monitor", + "Date": "2016-06-13", + "Score": 26 + }, + { + "Product": "Monitor", + "Date": "2016-06-26", + "Score": 62 + }, + { + "Product": "Monitor", + "Date": "2016-07-10", + "Score": 27 + }, + { + "Product": "Monitor", + "Date": "2016-07-24", + "Score": 14 + }, + { + "Product": "Monitor", + "Date": "2016-08-07", + "Score": 34 + }, + { + "Product": "Monitor", + "Date": "2016-08-20", + "Score": 33 + }, + { + "Product": "Monitor", + "Date": "2016-09-03", + "Score": 9 + }, + { + "Product": "Monitor", + "Date": "2016-09-17", + "Score": 19 + }, + { + "Product": "Monitor", + "Date": "2016-09-30", + "Score": 22 + }, + { + "Product": "Monitor", + "Date": "2016-10-14", + "Score": 79 + }, + { + "Product": "Monitor", + "Date": "2016-10-28", + "Score": 26 + }, + { + "Product": "Monitor", + "Date": "2016-11-10", + "Score": 7 + }, + { + "Product": "Monitor", + "Date": "2016-11-24", + "Score": 16 + }, + { + "Product": "Monitor", + "Date": "2016-12-08", + "Score": 52 + }, + { + "Product": "Monitor", + "Date": "2016-12-21", + "Score": 35 + }, + { + "Product": "Monitor", + "Date": "2017-01-04", + "Score": 50 + }, + { + "Product": "Monitor", + "Date": "2017-01-18", + "Score": 37 + }, + { + "Product": "Monitor", + "Date": "2017-01-31", + "Score": 17 + }, + { + "Product": "Monitor", + "Date": "2017-02-14", + "Score": 75 + }, + { + "Product": "Monitor", + "Date": "2017-02-28", + "Score": 58 + }, + { + "Product": "Monitor", + "Date": "2017-03-14", + "Score": 88 + }, + { + "Product": "Monitor", + "Date": "2017-03-27", + "Score": 6 + }, + { + "Product": "Monitor", + "Date": "2017-04-10", + "Score": 60 + }, + { + "Product": "Monitor", + "Date": "2017-04-24", + "Score": 85 + }, + { + "Product": "Monitor", + "Date": "2017-05-07", + "Score": 40 + }, + { + "Product": "Monitor", + "Date": "2017-05-21", + "Score": 31 + }, + { + "Product": "Monitor", + "Date": "2017-06-04", + "Score": 34 + }, + { + "Product": "Monitor", + "Date": "2017-06-17", + "Score": 54 + }, + { + "Product": "Monitor", + "Date": "2017-07-01", + "Score": 62 + }, + { + "Product": "Monitor", + "Date": "2017-07-15", + "Score": 83 + }, + { + "Product": "Monitor", + "Date": "2017-07-28", + "Score": 77 + }, + { + "Product": "Monitor", + "Date": "2017-08-11", + "Score": 81 + }, + { + "Product": "Monitor", + "Date": "2017-08-25", + "Score": 85 + }, + { + "Product": "Monitor", + "Date": "2017-09-07", + "Score": 57 + }, + { + "Product": "Monitor", + "Date": "2017-09-21", + "Score": 43 + }, + { + "Product": "Monitor", + "Date": "2017-10-05", + "Score": 80 + }, + { + "Product": "Monitor", + "Date": "2017-10-19", + "Score": 30 + }, + { + "Product": "Monitor", + "Date": "2017-11-01", + "Score": 11 + }, + { + "Product": "Monitor", + "Date": "2017-11-15", + "Score": 53 + }, + { + "Product": "Monitor", + "Date": "2017-11-29", + "Score": 35 + }, + { + "Product": "Monitor", + "Date": "2017-12-12", + "Score": 5 + }, + { + "Product": "Monitor", + "Date": "2017-12-26", + "Score": 15 + }, + { + "Product": "Monitor", + "Date": "2018-01-09", + "Score": 9 + }, + { + "Product": "Monitor", + "Date": "2018-01-22", + "Score": 46 + }, + { + "Product": "Monitor", + "Date": "2018-02-05", + "Score": 65 + }, + { + "Product": "Monitor", + "Date": "2018-02-19", + "Score": 74 + }, + { + "Product": "Monitor", + "Date": "2018-03-04", + "Score": 85 + }, + { + "Product": "Monitor", + "Date": "2018-03-18", + "Score": 96 + }, + { + "Product": "Monitor", + "Date": "2018-04-01", + "Score": 4 + }, + { + "Product": "Monitor", + "Date": "2018-04-14", + "Score": 79 + }, + { + "Product": "Monitor", + "Date": "2018-04-28", + "Score": 66 + }, + { + "Product": "Monitor", + "Date": "2018-05-12", + "Score": 36 + }, + { + "Product": "Monitor", + "Date": "2018-05-26", + "Score": 97 + }, + { + "Product": "Monitor", + "Date": "2018-06-08", + "Score": 89 + }, + { + "Product": "Monitor", + "Date": "2018-06-22", + "Score": 49 + }, + { + "Product": "Monitor", + "Date": "2018-07-06", + "Score": 100 + }, + { + "Product": "Monitor", + "Date": "2018-07-19", + "Score": 31 + }, + { + "Product": "Monitor", + "Date": "2018-08-02", + "Score": 18 + }, + { + "Product": "Monitor", + "Date": "2018-08-16", + "Score": 32 + }, + { + "Product": "Monitor", + "Date": "2018-08-29", + "Score": 86 + }, + { + "Product": "Monitor", + "Date": "2018-09-12", + "Score": 63 + }, + { + "Product": "Monitor", + "Date": "2018-09-26", + "Score": 41 + }, + { + "Product": "Monitor", + "Date": "2018-10-09", + "Score": 23 + }, + { + "Product": "Monitor", + "Date": "2018-10-23", + "Score": 76 + }, + { + "Product": "Monitor", + "Date": "2018-11-06", + "Score": 89 + }, + { + "Product": "Monitor", + "Date": "2018-11-19", + "Score": 42 + }, + { + "Product": "Monitor", + "Date": "2018-12-03", + "Score": 12 + }, + { + "Product": "Monitor", + "Date": "2018-12-17", + "Score": 16 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/heatmap/06-card60.flint.json b/test-harness/excel/evaluations/inputs/heatmap/06-card60.flint.json new file mode 100644 index 00000000..a2a68837 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/heatmap/06-card60.flint.json @@ -0,0 +1,12023 @@ +{ + "semantic_types": { + "StartDate": "Date", + "EndDate": "Date", + "Correlation": "Quantity" + }, + "chart_spec": { + "chartType": "Heatmap", + "encodings": { + "x": "StartDate", + "y": "EndDate", + "color": "Correlation" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "StartDate": "2018-01-01", + "EndDate": "2020-01-01", + "Correlation": -0.29 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2020-01-28", + "Correlation": 0.35 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2020-02-24", + "Correlation": 0.55 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2020-03-23", + "Correlation": 0.19 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2020-04-19", + "Correlation": 0.3 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2020-05-16", + "Correlation": -0.96 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2020-06-13", + "Correlation": 0.53 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2020-07-10", + "Correlation": -0.56 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2020-08-07", + "Correlation": 0.03 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2020-09-03", + "Correlation": 0.24 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2020-09-30", + "Correlation": 0.97 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2020-10-28", + "Correlation": 0.93 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2020-11-24", + "Correlation": -0.59 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2020-12-21", + "Correlation": 0.19 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2021-01-18", + "Correlation": 0.12 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2021-02-14", + "Correlation": 0.78 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2021-03-14", + "Correlation": -0.99 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2021-04-10", + "Correlation": 0.75 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2021-05-07", + "Correlation": 0.6 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2021-06-04", + "Correlation": 0.92 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2021-07-01", + "Correlation": -0.74 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2021-07-28", + "Correlation": -0.87 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2021-08-25", + "Correlation": -0.43 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2021-09-21", + "Correlation": -0.27 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2021-10-19", + "Correlation": 0.51 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2021-11-15", + "Correlation": 0.64 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2021-12-12", + "Correlation": 0.66 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2022-01-09", + "Correlation": 0.64 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2022-02-05", + "Correlation": 0.56 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2022-03-04", + "Correlation": -0.78 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2022-04-01", + "Correlation": 0.2 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2022-04-28", + "Correlation": -0.47 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2022-05-26", + "Correlation": 0.33 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2022-06-22", + "Correlation": 0.11 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2022-07-19", + "Correlation": 0.48 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2022-08-16", + "Correlation": -0.94 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2022-09-12", + "Correlation": 0.69 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2022-10-09", + "Correlation": 0.83 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2022-11-06", + "Correlation": -0.4 + }, + { + "StartDate": "2018-01-01", + "EndDate": "2022-12-03", + "Correlation": -0.23 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2020-01-01", + "Correlation": -0.25 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2020-01-28", + "Correlation": -0.65 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2020-02-24", + "Correlation": 0.83 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2020-03-23", + "Correlation": -0.82 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2020-04-19", + "Correlation": -0.23 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2020-05-16", + "Correlation": 0.21 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2020-06-13", + "Correlation": -0.2 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2020-07-10", + "Correlation": 0.1 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2020-08-07", + "Correlation": 0.87 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2020-09-03", + "Correlation": 0.37 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2020-09-30", + "Correlation": 0.57 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2020-10-28", + "Correlation": 0.46 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2020-11-24", + "Correlation": 0.58 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2020-12-21", + "Correlation": 0.17 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2021-01-18", + "Correlation": 0.37 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2021-02-14", + "Correlation": -0.56 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2021-03-14", + "Correlation": -0.88 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2021-04-10", + "Correlation": 0.83 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2021-05-07", + "Correlation": -0.22 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2021-06-04", + "Correlation": -0.17 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2021-07-01", + "Correlation": 0.69 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2021-07-28", + "Correlation": -0.22 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2021-08-25", + "Correlation": 0.41 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2021-09-21", + "Correlation": -0.27 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2021-10-19", + "Correlation": -0.22 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2021-11-15", + "Correlation": -0.89 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2021-12-12", + "Correlation": 0.97 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2022-01-09", + "Correlation": 0.18 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2022-02-05", + "Correlation": 0.08 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2022-03-04", + "Correlation": -0.73 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2022-04-01", + "Correlation": -0.66 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2022-04-28", + "Correlation": 0.72 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2022-05-26", + "Correlation": 0.88 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2022-06-22", + "Correlation": 0.61 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2022-07-19", + "Correlation": -0.01 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2022-08-16", + "Correlation": 0.19 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2022-09-12", + "Correlation": -0.64 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2022-10-09", + "Correlation": -0.75 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2022-11-06", + "Correlation": -0.57 + }, + { + "StartDate": "2018-01-19", + "EndDate": "2022-12-03", + "Correlation": 0.01 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2020-01-01", + "Correlation": 0.21 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2020-01-28", + "Correlation": -0.86 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2020-02-24", + "Correlation": 0.51 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2020-03-23", + "Correlation": -0.48 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2020-04-19", + "Correlation": 0.75 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2020-05-16", + "Correlation": -0.54 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2020-06-13", + "Correlation": 0.33 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2020-07-10", + "Correlation": 0.51 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2020-08-07", + "Correlation": -0.19 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2020-09-03", + "Correlation": 0.68 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2020-09-30", + "Correlation": -0.55 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2020-10-28", + "Correlation": -0.04 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2020-11-24", + "Correlation": -0.43 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2020-12-21", + "Correlation": 0.91 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2021-01-18", + "Correlation": 0.72 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2021-02-14", + "Correlation": -0.51 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2021-03-14", + "Correlation": 0.65 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2021-04-10", + "Correlation": -0.63 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2021-05-07", + "Correlation": 0.78 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2021-06-04", + "Correlation": -0.57 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2021-07-01", + "Correlation": -0.08 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2021-07-28", + "Correlation": -0.72 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2021-08-25", + "Correlation": -0.01 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2021-09-21", + "Correlation": 0.7 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2021-10-19", + "Correlation": -0.31 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2021-11-15", + "Correlation": -0.79 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2021-12-12", + "Correlation": -0.57 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2022-01-09", + "Correlation": -0.77 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2022-02-05", + "Correlation": 0.72 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2022-03-04", + "Correlation": 0.93 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2022-04-01", + "Correlation": -0.59 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2022-04-28", + "Correlation": 0.84 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2022-05-26", + "Correlation": -0.02 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2022-06-22", + "Correlation": -0.97 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2022-07-19", + "Correlation": 0.23 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2022-08-16", + "Correlation": 0.73 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2022-09-12", + "Correlation": 0.33 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2022-10-09", + "Correlation": 0.53 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2022-11-06", + "Correlation": -0.98 + }, + { + "StartDate": "2018-02-06", + "EndDate": "2022-12-03", + "Correlation": 0.14 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2020-01-01", + "Correlation": 0.13 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2020-01-28", + "Correlation": -0.12 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2020-02-24", + "Correlation": -0.94 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2020-03-23", + "Correlation": 0.81 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2020-04-19", + "Correlation": 0.96 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2020-05-16", + "Correlation": -0.35 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2020-06-13", + "Correlation": 0.94 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2020-07-10", + "Correlation": -0.89 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2020-08-07", + "Correlation": -0.72 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2020-09-03", + "Correlation": -0.25 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2020-09-30", + "Correlation": 0.77 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2020-10-28", + "Correlation": 0.48 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2020-11-24", + "Correlation": -0.91 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2020-12-21", + "Correlation": 0.38 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2021-01-18", + "Correlation": -0.63 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2021-02-14", + "Correlation": -0.97 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2021-03-14", + "Correlation": -0.69 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2021-04-10", + "Correlation": -0.41 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2021-05-07", + "Correlation": 0.21 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2021-06-04", + "Correlation": -0.99 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2021-07-01", + "Correlation": 0.31 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2021-07-28", + "Correlation": -0.52 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2021-08-25", + "Correlation": 0.22 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2021-09-21", + "Correlation": -0.82 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2021-10-19", + "Correlation": 0.95 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2021-11-15", + "Correlation": -0.19 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2021-12-12", + "Correlation": -0.64 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2022-01-09", + "Correlation": 0.63 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2022-02-05", + "Correlation": -0.56 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2022-03-04", + "Correlation": 0.61 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2022-04-01", + "Correlation": 0.95 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2022-04-28", + "Correlation": -0.3 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2022-05-26", + "Correlation": 0.7 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2022-06-22", + "Correlation": -0.68 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2022-07-19", + "Correlation": 0.76 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2022-08-16", + "Correlation": 0.8 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2022-09-12", + "Correlation": -0.89 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2022-10-09", + "Correlation": -0.21 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2022-11-06", + "Correlation": 0 + }, + { + "StartDate": "2018-02-24", + "EndDate": "2022-12-03", + "Correlation": 0.15 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2020-01-01", + "Correlation": 0.27 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2020-01-28", + "Correlation": 0.62 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2020-02-24", + "Correlation": 0.71 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2020-03-23", + "Correlation": 0.47 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2020-04-19", + "Correlation": 0.68 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2020-05-16", + "Correlation": 0.63 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2020-06-13", + "Correlation": 0.57 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2020-07-10", + "Correlation": 0.56 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2020-08-07", + "Correlation": 0.35 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2020-09-03", + "Correlation": -0.36 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2020-09-30", + "Correlation": 0.1 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2020-10-28", + "Correlation": -0.18 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2020-11-24", + "Correlation": 0.48 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2020-12-21", + "Correlation": -0.5 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2021-01-18", + "Correlation": 0.84 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2021-02-14", + "Correlation": 0.75 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2021-03-14", + "Correlation": -0.43 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2021-04-10", + "Correlation": 0.5 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2021-05-07", + "Correlation": 0.06 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2021-06-04", + "Correlation": 0.15 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2021-07-01", + "Correlation": 0.24 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2021-07-28", + "Correlation": -0.35 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2021-08-25", + "Correlation": -0.65 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2021-09-21", + "Correlation": -0.88 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2021-10-19", + "Correlation": 0.94 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2021-11-15", + "Correlation": 0.24 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2021-12-12", + "Correlation": -0.23 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2022-01-09", + "Correlation": 0.12 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2022-02-05", + "Correlation": 0.31 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2022-03-04", + "Correlation": 0.87 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2022-04-01", + "Correlation": 0.73 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2022-04-28", + "Correlation": -0.37 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2022-05-26", + "Correlation": -0.22 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2022-06-22", + "Correlation": -0.56 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2022-07-19", + "Correlation": 0.56 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2022-08-16", + "Correlation": -0.11 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2022-09-12", + "Correlation": 0.91 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2022-10-09", + "Correlation": -0.01 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2022-11-06", + "Correlation": -0.78 + }, + { + "StartDate": "2018-03-15", + "EndDate": "2022-12-03", + "Correlation": 0.59 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2020-01-01", + "Correlation": -0.99 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2020-01-28", + "Correlation": -0.93 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2020-02-24", + "Correlation": -0.34 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2020-03-23", + "Correlation": 0.26 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2020-04-19", + "Correlation": -0.74 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2020-05-16", + "Correlation": -0.73 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2020-06-13", + "Correlation": -0.51 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2020-07-10", + "Correlation": 0.83 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2020-08-07", + "Correlation": 0.75 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2020-09-03", + "Correlation": 0.56 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2020-09-30", + "Correlation": -0.33 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2020-10-28", + "Correlation": -0.26 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2020-11-24", + "Correlation": -0.3 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2020-12-21", + "Correlation": 0.5 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2021-01-18", + "Correlation": -0.07 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2021-02-14", + "Correlation": 0.02 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2021-03-14", + "Correlation": -0.74 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2021-04-10", + "Correlation": -0.92 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2021-05-07", + "Correlation": 0.91 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2021-06-04", + "Correlation": -0.62 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2021-07-01", + "Correlation": 0.59 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2021-07-28", + "Correlation": -0.51 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2021-08-25", + "Correlation": 0.79 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2021-09-21", + "Correlation": -0.47 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2021-10-19", + "Correlation": 0.4 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2021-11-15", + "Correlation": -0.77 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2021-12-12", + "Correlation": 0.06 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2022-01-09", + "Correlation": 0.85 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2022-02-05", + "Correlation": 0.22 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2022-03-04", + "Correlation": 0.71 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2022-04-01", + "Correlation": -0.72 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2022-04-28", + "Correlation": -0.44 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2022-05-26", + "Correlation": 0.18 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2022-06-22", + "Correlation": -0.06 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2022-07-19", + "Correlation": -0.63 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2022-08-16", + "Correlation": 0.87 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2022-09-12", + "Correlation": -0.15 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2022-10-09", + "Correlation": 0.16 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2022-11-06", + "Correlation": 0.22 + }, + { + "StartDate": "2018-04-02", + "EndDate": "2022-12-03", + "Correlation": 0.95 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2020-01-01", + "Correlation": -0.7 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2020-01-28", + "Correlation": -0.89 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2020-02-24", + "Correlation": 0.67 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2020-03-23", + "Correlation": 0.58 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2020-04-19", + "Correlation": -0.99 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2020-05-16", + "Correlation": 0.13 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2020-06-13", + "Correlation": 0.46 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2020-07-10", + "Correlation": 0.32 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2020-08-07", + "Correlation": 0.06 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2020-09-03", + "Correlation": -0.52 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2020-09-30", + "Correlation": -0.61 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2020-10-28", + "Correlation": 0.91 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2020-11-24", + "Correlation": -0.74 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2020-12-21", + "Correlation": 0.55 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2021-01-18", + "Correlation": -0.94 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2021-02-14", + "Correlation": 0.03 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2021-03-14", + "Correlation": 0.78 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2021-04-10", + "Correlation": -0.62 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2021-05-07", + "Correlation": 0.33 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2021-06-04", + "Correlation": 0.24 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2021-07-01", + "Correlation": 0.97 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2021-07-28", + "Correlation": -0.88 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2021-08-25", + "Correlation": -0.37 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2021-09-21", + "Correlation": -0.85 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2021-10-19", + "Correlation": 0.37 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2021-11-15", + "Correlation": -0.56 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2021-12-12", + "Correlation": -0.94 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2022-01-09", + "Correlation": 0.79 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2022-02-05", + "Correlation": 0.35 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2022-03-04", + "Correlation": -1 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2022-04-01", + "Correlation": -0.65 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2022-04-28", + "Correlation": 0.68 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2022-05-26", + "Correlation": -0.44 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2022-06-22", + "Correlation": -0.35 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2022-07-19", + "Correlation": -0.35 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2022-08-16", + "Correlation": -0.86 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2022-09-12", + "Correlation": 0.33 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2022-10-09", + "Correlation": -0.91 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2022-11-06", + "Correlation": 0.2 + }, + { + "StartDate": "2018-04-20", + "EndDate": "2022-12-03", + "Correlation": -0.93 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2020-01-01", + "Correlation": 0.46 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2020-01-28", + "Correlation": 0.17 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2020-02-24", + "Correlation": -0.56 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2020-03-23", + "Correlation": 0.42 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2020-04-19", + "Correlation": 0.39 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2020-05-16", + "Correlation": -0.37 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2020-06-13", + "Correlation": -0.16 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2020-07-10", + "Correlation": -0.35 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2020-08-07", + "Correlation": -0.07 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2020-09-03", + "Correlation": 0.78 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2020-09-30", + "Correlation": -0.21 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2020-10-28", + "Correlation": -0.79 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2020-11-24", + "Correlation": -0.47 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2020-12-21", + "Correlation": -0.13 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2021-01-18", + "Correlation": 0.61 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2021-02-14", + "Correlation": 0.77 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2021-03-14", + "Correlation": -0.19 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2021-04-10", + "Correlation": -0.65 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2021-05-07", + "Correlation": 0.45 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2021-06-04", + "Correlation": -0.77 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2021-07-01", + "Correlation": -0.3 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2021-07-28", + "Correlation": -0.66 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2021-08-25", + "Correlation": 0.47 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2021-09-21", + "Correlation": -0.5 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2021-10-19", + "Correlation": -0.56 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2021-11-15", + "Correlation": -0.4 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2021-12-12", + "Correlation": 0.19 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2022-01-09", + "Correlation": 0.01 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2022-02-05", + "Correlation": -0.89 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2022-03-04", + "Correlation": -0.79 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2022-04-01", + "Correlation": -0.12 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2022-04-28", + "Correlation": -0.52 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2022-05-26", + "Correlation": -0.64 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2022-06-22", + "Correlation": 0.72 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2022-07-19", + "Correlation": 0.33 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2022-08-16", + "Correlation": 0.97 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2022-09-12", + "Correlation": 0.88 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2022-10-09", + "Correlation": 0.66 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2022-11-06", + "Correlation": 0.04 + }, + { + "StartDate": "2018-05-08", + "EndDate": "2022-12-03", + "Correlation": -0.18 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2020-01-01", + "Correlation": -0.11 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2020-01-28", + "Correlation": 0.08 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2020-02-24", + "Correlation": -0.64 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2020-03-23", + "Correlation": -0.27 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2020-04-19", + "Correlation": 0.32 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2020-05-16", + "Correlation": -0.74 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2020-06-13", + "Correlation": -0.1 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2020-07-10", + "Correlation": -0.11 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2020-08-07", + "Correlation": 0.99 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2020-09-03", + "Correlation": 0.95 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2020-09-30", + "Correlation": 0.89 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2020-10-28", + "Correlation": -0.74 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2020-11-24", + "Correlation": -0.86 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2020-12-21", + "Correlation": 0.31 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2021-01-18", + "Correlation": -0.43 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2021-02-14", + "Correlation": -0.56 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2021-03-14", + "Correlation": -0.59 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2021-04-10", + "Correlation": 0.95 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2021-05-07", + "Correlation": -0.21 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2021-06-04", + "Correlation": -0.96 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2021-07-01", + "Correlation": 0.17 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2021-07-28", + "Correlation": -0.33 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2021-08-25", + "Correlation": 0.85 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2021-09-21", + "Correlation": -0.07 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2021-10-19", + "Correlation": -0.34 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2021-11-15", + "Correlation": -0.17 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2021-12-12", + "Correlation": -0.22 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2022-01-09", + "Correlation": -0.13 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2022-02-05", + "Correlation": -0.06 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2022-03-04", + "Correlation": 0.27 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2022-04-01", + "Correlation": 0.11 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2022-04-28", + "Correlation": -0.69 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2022-05-26", + "Correlation": -0.8 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2022-06-22", + "Correlation": -0.21 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2022-07-19", + "Correlation": -0.14 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2022-08-16", + "Correlation": 0.26 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2022-09-12", + "Correlation": -0.28 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2022-10-09", + "Correlation": 0.34 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2022-11-06", + "Correlation": 0.12 + }, + { + "StartDate": "2018-05-27", + "EndDate": "2022-12-03", + "Correlation": 0.39 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2020-01-01", + "Correlation": -0.29 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2020-01-28", + "Correlation": -0.47 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2020-02-24", + "Correlation": -0.29 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2020-03-23", + "Correlation": -0.25 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2020-04-19", + "Correlation": -0.25 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2020-05-16", + "Correlation": 0.15 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2020-06-13", + "Correlation": 0.5 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2020-07-10", + "Correlation": -0.05 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2020-08-07", + "Correlation": -0.32 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2020-09-03", + "Correlation": 0.7 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2020-09-30", + "Correlation": 0.19 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2020-10-28", + "Correlation": 0.35 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2020-11-24", + "Correlation": -0.58 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2020-12-21", + "Correlation": 0.91 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2021-01-18", + "Correlation": 0.1 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2021-02-14", + "Correlation": 0.8 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2021-03-14", + "Correlation": -0.65 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2021-04-10", + "Correlation": 0.23 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2021-05-07", + "Correlation": 0.34 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2021-06-04", + "Correlation": 0.66 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2021-07-01", + "Correlation": 0.42 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2021-07-28", + "Correlation": 0.17 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2021-08-25", + "Correlation": 0.65 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2021-09-21", + "Correlation": 0.29 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2021-10-19", + "Correlation": -0.14 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2021-11-15", + "Correlation": 0.09 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2021-12-12", + "Correlation": 0.7 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2022-01-09", + "Correlation": 0.88 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2022-02-05", + "Correlation": -0.84 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2022-03-04", + "Correlation": -0.48 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2022-04-01", + "Correlation": -0.11 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2022-04-28", + "Correlation": 0.82 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2022-05-26", + "Correlation": -0.27 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2022-06-22", + "Correlation": 0.63 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2022-07-19", + "Correlation": 0.63 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2022-08-16", + "Correlation": -0.68 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2022-09-12", + "Correlation": -0.61 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2022-10-09", + "Correlation": -0.95 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2022-11-06", + "Correlation": 0.86 + }, + { + "StartDate": "2018-06-14", + "EndDate": "2022-12-03", + "Correlation": 0.9 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2020-01-01", + "Correlation": 0.74 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2020-01-28", + "Correlation": -0.8 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2020-02-24", + "Correlation": -0.3 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2020-03-23", + "Correlation": 0.28 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2020-04-19", + "Correlation": 0.31 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2020-05-16", + "Correlation": -0.37 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2020-06-13", + "Correlation": -0.1 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2020-07-10", + "Correlation": 0.74 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2020-08-07", + "Correlation": -0.91 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2020-09-03", + "Correlation": 0.49 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2020-09-30", + "Correlation": -0.5 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2020-10-28", + "Correlation": -0.65 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2020-11-24", + "Correlation": 0.85 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2020-12-21", + "Correlation": 0.57 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2021-01-18", + "Correlation": 0.79 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2021-02-14", + "Correlation": 0.46 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2021-03-14", + "Correlation": -0.5 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2021-04-10", + "Correlation": -0.83 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2021-05-07", + "Correlation": 0.31 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2021-06-04", + "Correlation": 0.6 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2021-07-01", + "Correlation": -0.69 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2021-07-28", + "Correlation": 0.15 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2021-08-25", + "Correlation": 0.56 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2021-09-21", + "Correlation": -0.1 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2021-10-19", + "Correlation": 0.95 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2021-11-15", + "Correlation": -0.68 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2021-12-12", + "Correlation": 0.65 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2022-01-09", + "Correlation": 0.5 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2022-02-05", + "Correlation": -0.99 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2022-03-04", + "Correlation": -0.76 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2022-04-01", + "Correlation": 0.07 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2022-04-28", + "Correlation": -0.25 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2022-05-26", + "Correlation": -0.72 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2022-06-22", + "Correlation": 0.43 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2022-07-19", + "Correlation": -0.26 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2022-08-16", + "Correlation": -0.44 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2022-09-12", + "Correlation": 0.64 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2022-10-09", + "Correlation": 0.87 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2022-11-06", + "Correlation": -0.71 + }, + { + "StartDate": "2018-07-02", + "EndDate": "2022-12-03", + "Correlation": -0.4 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2020-01-01", + "Correlation": 0.28 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2020-01-28", + "Correlation": -0.8 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2020-02-24", + "Correlation": 0.76 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2020-03-23", + "Correlation": -0.18 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2020-04-19", + "Correlation": 0.56 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2020-05-16", + "Correlation": 0.06 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2020-06-13", + "Correlation": 0.9 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2020-07-10", + "Correlation": 0.16 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2020-08-07", + "Correlation": -0.77 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2020-09-03", + "Correlation": 0.4 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2020-09-30", + "Correlation": 0.63 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2020-10-28", + "Correlation": -0.19 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2020-11-24", + "Correlation": 0.07 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2020-12-21", + "Correlation": -0.18 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2021-01-18", + "Correlation": -0.08 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2021-02-14", + "Correlation": 0.53 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2021-03-14", + "Correlation": 0.02 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2021-04-10", + "Correlation": 0.81 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2021-05-07", + "Correlation": 0.56 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2021-06-04", + "Correlation": -0.04 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2021-07-01", + "Correlation": 0.43 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2021-07-28", + "Correlation": -0.71 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2021-08-25", + "Correlation": -0.63 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2021-09-21", + "Correlation": -0.26 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2021-10-19", + "Correlation": -0.71 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2021-11-15", + "Correlation": 0.49 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2021-12-12", + "Correlation": -0.82 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2022-01-09", + "Correlation": -0.09 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2022-02-05", + "Correlation": -0.25 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2022-03-04", + "Correlation": 0.89 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2022-04-01", + "Correlation": -0.85 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2022-04-28", + "Correlation": -0.23 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2022-05-26", + "Correlation": -0.12 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2022-06-22", + "Correlation": -0.88 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2022-07-19", + "Correlation": 0.59 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2022-08-16", + "Correlation": -0.12 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2022-09-12", + "Correlation": 0.26 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2022-10-09", + "Correlation": 0.73 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2022-11-06", + "Correlation": -0.55 + }, + { + "StartDate": "2018-07-20", + "EndDate": "2022-12-03", + "Correlation": -0.78 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2020-01-01", + "Correlation": 0.54 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2020-01-28", + "Correlation": -0.99 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2020-02-24", + "Correlation": 0.82 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2020-03-23", + "Correlation": -0.86 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2020-04-19", + "Correlation": 0.79 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2020-05-16", + "Correlation": 0.99 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2020-06-13", + "Correlation": 0.38 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2020-07-10", + "Correlation": -0.06 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2020-08-07", + "Correlation": -0.43 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2020-09-03", + "Correlation": -0.77 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2020-09-30", + "Correlation": 0.4 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2020-10-28", + "Correlation": 0.56 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2020-11-24", + "Correlation": 0.57 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2020-12-21", + "Correlation": 0.86 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2021-01-18", + "Correlation": 0.94 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2021-02-14", + "Correlation": -0.82 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2021-03-14", + "Correlation": -0.92 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2021-04-10", + "Correlation": 0.07 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2021-05-07", + "Correlation": -0.97 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2021-06-04", + "Correlation": -0.41 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2021-07-01", + "Correlation": -0.96 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2021-07-28", + "Correlation": -0.15 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2021-08-25", + "Correlation": -0.84 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2021-09-21", + "Correlation": 0.89 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2021-10-19", + "Correlation": -0.9 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2021-11-15", + "Correlation": -0.09 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2021-12-12", + "Correlation": -0.15 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2022-01-09", + "Correlation": -0.71 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2022-02-05", + "Correlation": 0.21 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2022-03-04", + "Correlation": -0.44 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2022-04-01", + "Correlation": -0.55 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2022-04-28", + "Correlation": 0.5 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2022-05-26", + "Correlation": 0.52 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2022-06-22", + "Correlation": -0.73 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2022-07-19", + "Correlation": 0.35 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2022-08-16", + "Correlation": -0.46 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2022-09-12", + "Correlation": -0.3 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2022-10-09", + "Correlation": -0.02 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2022-11-06", + "Correlation": -0.45 + }, + { + "StartDate": "2018-08-08", + "EndDate": "2022-12-03", + "Correlation": 0.01 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2020-01-01", + "Correlation": -0.51 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2020-01-28", + "Correlation": -0.33 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2020-02-24", + "Correlation": -0.99 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2020-03-23", + "Correlation": 0.12 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2020-04-19", + "Correlation": 0.66 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2020-05-16", + "Correlation": -0.21 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2020-06-13", + "Correlation": 0.12 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2020-07-10", + "Correlation": 0.6 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2020-08-07", + "Correlation": -0.32 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2020-09-03", + "Correlation": -0.27 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2020-09-30", + "Correlation": -0.54 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2020-10-28", + "Correlation": -0.4 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2020-11-24", + "Correlation": 0.9 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2020-12-21", + "Correlation": 0.78 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2021-01-18", + "Correlation": -0.43 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2021-02-14", + "Correlation": 0.66 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2021-03-14", + "Correlation": -0.54 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2021-04-10", + "Correlation": 0.62 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2021-05-07", + "Correlation": 0.87 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2021-06-04", + "Correlation": 0.2 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2021-07-01", + "Correlation": 0.49 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2021-07-28", + "Correlation": -0.4 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2021-08-25", + "Correlation": 0.61 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2021-09-21", + "Correlation": 0.86 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2021-10-19", + "Correlation": -0.69 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2021-11-15", + "Correlation": 0.75 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2021-12-12", + "Correlation": 0.22 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2022-01-09", + "Correlation": -0.26 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2022-02-05", + "Correlation": 0.59 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2022-03-04", + "Correlation": 0.23 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2022-04-01", + "Correlation": -0.75 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2022-04-28", + "Correlation": -0.74 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2022-05-26", + "Correlation": -0.31 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2022-06-22", + "Correlation": 0.7 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2022-07-19", + "Correlation": 0.35 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2022-08-16", + "Correlation": 0.41 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2022-09-12", + "Correlation": -0.18 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2022-10-09", + "Correlation": 0.86 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2022-11-06", + "Correlation": -0.24 + }, + { + "StartDate": "2018-08-26", + "EndDate": "2022-12-03", + "Correlation": 0.51 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2020-01-01", + "Correlation": -0.49 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2020-01-28", + "Correlation": -0.11 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2020-02-24", + "Correlation": -0.53 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2020-03-23", + "Correlation": 0.07 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2020-04-19", + "Correlation": 0.74 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2020-05-16", + "Correlation": 0.99 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2020-06-13", + "Correlation": -0.25 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2020-07-10", + "Correlation": -0.2 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2020-08-07", + "Correlation": -0.15 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2020-09-03", + "Correlation": 0.8 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2020-09-30", + "Correlation": 0.05 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2020-10-28", + "Correlation": -0.8 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2020-11-24", + "Correlation": 0.25 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2020-12-21", + "Correlation": 0.5 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2021-01-18", + "Correlation": -0.79 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2021-02-14", + "Correlation": -0.81 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2021-03-14", + "Correlation": 0.89 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2021-04-10", + "Correlation": 0.34 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2021-05-07", + "Correlation": -0.75 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2021-06-04", + "Correlation": 0.32 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2021-07-01", + "Correlation": 0.37 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2021-07-28", + "Correlation": -0.36 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2021-08-25", + "Correlation": -0.93 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2021-09-21", + "Correlation": 0.64 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2021-10-19", + "Correlation": -0.88 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2021-11-15", + "Correlation": -0.24 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2021-12-12", + "Correlation": 0.52 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2022-01-09", + "Correlation": 0.12 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2022-02-05", + "Correlation": 0.02 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2022-03-04", + "Correlation": -0.01 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2022-04-01", + "Correlation": 0.91 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2022-04-28", + "Correlation": 0.99 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2022-05-26", + "Correlation": -0.01 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2022-06-22", + "Correlation": 0.44 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2022-07-19", + "Correlation": -0.5 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2022-08-16", + "Correlation": 0.66 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2022-09-12", + "Correlation": 0.44 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2022-10-09", + "Correlation": -0.03 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2022-11-06", + "Correlation": 0.36 + }, + { + "StartDate": "2018-09-13", + "EndDate": "2022-12-03", + "Correlation": 0.53 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2020-01-01", + "Correlation": -0.97 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2020-01-28", + "Correlation": 0.98 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2020-02-24", + "Correlation": -0.81 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2020-03-23", + "Correlation": -0.7 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2020-04-19", + "Correlation": 0.99 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2020-05-16", + "Correlation": -0.85 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2020-06-13", + "Correlation": -0.95 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2020-07-10", + "Correlation": -0.51 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2020-08-07", + "Correlation": 0.99 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2020-09-03", + "Correlation": -0.61 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2020-09-30", + "Correlation": 0.81 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2020-10-28", + "Correlation": 0.4 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2020-11-24", + "Correlation": -1 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2020-12-21", + "Correlation": 0.62 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2021-01-18", + "Correlation": -0.14 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2021-02-14", + "Correlation": 0.85 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2021-03-14", + "Correlation": 1 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2021-04-10", + "Correlation": 0.36 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2021-05-07", + "Correlation": -0.81 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2021-06-04", + "Correlation": 0.46 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2021-07-01", + "Correlation": -0.49 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2021-07-28", + "Correlation": -0.49 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2021-08-25", + "Correlation": -0.51 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2021-09-21", + "Correlation": 0.07 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2021-10-19", + "Correlation": 0.69 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2021-11-15", + "Correlation": 0.37 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2021-12-12", + "Correlation": -0.96 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2022-01-09", + "Correlation": 0.34 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2022-02-05", + "Correlation": 0.73 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2022-03-04", + "Correlation": -0.25 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2022-04-01", + "Correlation": -0.06 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2022-04-28", + "Correlation": 0.74 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2022-05-26", + "Correlation": 0.13 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2022-06-22", + "Correlation": -0.26 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2022-07-19", + "Correlation": 0.5 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2022-08-16", + "Correlation": -0.32 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2022-09-12", + "Correlation": 0.28 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2022-10-09", + "Correlation": 0.42 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2022-11-06", + "Correlation": 0.16 + }, + { + "StartDate": "2018-10-01", + "EndDate": "2022-12-03", + "Correlation": -0.44 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2020-01-01", + "Correlation": 0.92 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2020-01-28", + "Correlation": 0.08 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2020-02-24", + "Correlation": -0.11 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2020-03-23", + "Correlation": -0.2 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2020-04-19", + "Correlation": -0.94 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2020-05-16", + "Correlation": -0.07 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2020-06-13", + "Correlation": -0.51 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2020-07-10", + "Correlation": 0.59 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2020-08-07", + "Correlation": 0.04 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2020-09-03", + "Correlation": -0.31 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2020-09-30", + "Correlation": -0.25 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2020-10-28", + "Correlation": -0.42 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2020-11-24", + "Correlation": -0.69 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2020-12-21", + "Correlation": -0.91 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2021-01-18", + "Correlation": -0.78 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2021-02-14", + "Correlation": 0.46 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2021-03-14", + "Correlation": -0.63 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2021-04-10", + "Correlation": -0.27 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2021-05-07", + "Correlation": 0.41 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2021-06-04", + "Correlation": 0.73 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2021-07-01", + "Correlation": -0.68 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2021-07-28", + "Correlation": -0.03 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2021-08-25", + "Correlation": -0.5 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2021-09-21", + "Correlation": 0.94 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2021-10-19", + "Correlation": -0.24 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2021-11-15", + "Correlation": -0.13 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2021-12-12", + "Correlation": 0.76 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2022-01-09", + "Correlation": -0.07 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2022-02-05", + "Correlation": -0.71 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2022-03-04", + "Correlation": -0.68 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2022-04-01", + "Correlation": -0.35 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2022-04-28", + "Correlation": -0.64 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2022-05-26", + "Correlation": 0.99 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2022-06-22", + "Correlation": 0.03 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2022-07-19", + "Correlation": -0.58 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2022-08-16", + "Correlation": 0.83 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2022-09-12", + "Correlation": -0.43 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2022-10-09", + "Correlation": 0.1 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2022-11-06", + "Correlation": 0.98 + }, + { + "StartDate": "2018-10-20", + "EndDate": "2022-12-03", + "Correlation": 0.03 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2020-01-01", + "Correlation": -0.7 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2020-01-28", + "Correlation": 0.18 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2020-02-24", + "Correlation": 0.24 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2020-03-23", + "Correlation": -0.84 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2020-04-19", + "Correlation": -0.76 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2020-05-16", + "Correlation": -1 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2020-06-13", + "Correlation": -0.7 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2020-07-10", + "Correlation": 0.98 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2020-08-07", + "Correlation": -0.81 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2020-09-03", + "Correlation": 0.03 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2020-09-30", + "Correlation": -0.55 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2020-10-28", + "Correlation": 0.08 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2020-11-24", + "Correlation": -0.58 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2020-12-21", + "Correlation": -0.01 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2021-01-18", + "Correlation": 0.93 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2021-02-14", + "Correlation": 0.27 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2021-03-14", + "Correlation": -0.09 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2021-04-10", + "Correlation": -0.89 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2021-05-07", + "Correlation": 0.95 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2021-06-04", + "Correlation": 0.05 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2021-07-01", + "Correlation": 0.35 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2021-07-28", + "Correlation": -0.68 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2021-08-25", + "Correlation": -0.44 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2021-09-21", + "Correlation": 0.55 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2021-10-19", + "Correlation": -0.21 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2021-11-15", + "Correlation": -0.97 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2021-12-12", + "Correlation": -0.05 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2022-01-09", + "Correlation": -0.58 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2022-02-05", + "Correlation": -0.35 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2022-03-04", + "Correlation": -0.12 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2022-04-01", + "Correlation": -0.75 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2022-04-28", + "Correlation": 0.2 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2022-05-26", + "Correlation": -0.65 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2022-06-22", + "Correlation": -0.85 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2022-07-19", + "Correlation": -0.73 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2022-08-16", + "Correlation": 0.83 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2022-09-12", + "Correlation": -0.9 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2022-10-09", + "Correlation": -0.26 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2022-11-06", + "Correlation": -0.45 + }, + { + "StartDate": "2018-11-07", + "EndDate": "2022-12-03", + "Correlation": -0.53 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2020-01-01", + "Correlation": 0.39 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2020-01-28", + "Correlation": -0.08 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2020-02-24", + "Correlation": 0.45 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2020-03-23", + "Correlation": 0.76 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2020-04-19", + "Correlation": 0.38 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2020-05-16", + "Correlation": -0.31 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2020-06-13", + "Correlation": 0.73 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2020-07-10", + "Correlation": 0.79 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2020-08-07", + "Correlation": -0.18 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2020-09-03", + "Correlation": 0.46 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2020-09-30", + "Correlation": 0.55 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2020-10-28", + "Correlation": 0.89 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2020-11-24", + "Correlation": 0.39 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2020-12-21", + "Correlation": 0.11 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2021-01-18", + "Correlation": -0.83 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2021-02-14", + "Correlation": -0.73 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2021-03-14", + "Correlation": -0.44 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2021-04-10", + "Correlation": 0.78 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2021-05-07", + "Correlation": 0.09 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2021-06-04", + "Correlation": -0.39 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2021-07-01", + "Correlation": -0.32 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2021-07-28", + "Correlation": 0.42 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2021-08-25", + "Correlation": -0.87 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2021-09-21", + "Correlation": -0.14 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2021-10-19", + "Correlation": 0.45 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2021-11-15", + "Correlation": -0.93 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2021-12-12", + "Correlation": 0.57 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2022-01-09", + "Correlation": 0.01 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2022-02-05", + "Correlation": -0.35 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2022-03-04", + "Correlation": 0.28 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2022-04-01", + "Correlation": 0.96 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2022-04-28", + "Correlation": -0.1 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2022-05-26", + "Correlation": 0.58 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2022-06-22", + "Correlation": 0.75 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2022-07-19", + "Correlation": 0.03 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2022-08-16", + "Correlation": 0.52 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2022-09-12", + "Correlation": -0.21 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2022-10-09", + "Correlation": 1 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2022-11-06", + "Correlation": 0 + }, + { + "StartDate": "2018-11-25", + "EndDate": "2022-12-03", + "Correlation": 0.73 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2020-01-01", + "Correlation": -0.86 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2020-01-28", + "Correlation": -0.11 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2020-02-24", + "Correlation": -0.61 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2020-03-23", + "Correlation": 0.15 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2020-04-19", + "Correlation": -0.46 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2020-05-16", + "Correlation": 0.58 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2020-06-13", + "Correlation": -0.72 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2020-07-10", + "Correlation": -0.17 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2020-08-07", + "Correlation": 0.73 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2020-09-03", + "Correlation": 0.28 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2020-09-30", + "Correlation": -0.17 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2020-10-28", + "Correlation": -0.61 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2020-11-24", + "Correlation": 0.3 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2020-12-21", + "Correlation": 0.1 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2021-01-18", + "Correlation": 0.71 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2021-02-14", + "Correlation": -0.72 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2021-03-14", + "Correlation": 0.53 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2021-04-10", + "Correlation": 0.43 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2021-05-07", + "Correlation": 0.41 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2021-06-04", + "Correlation": 0.34 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2021-07-01", + "Correlation": -0.36 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2021-07-28", + "Correlation": 0.5 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2021-08-25", + "Correlation": 0.51 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2021-09-21", + "Correlation": -0.47 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2021-10-19", + "Correlation": -0.64 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2021-11-15", + "Correlation": 0.46 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2021-12-12", + "Correlation": -0.79 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2022-01-09", + "Correlation": -0.44 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2022-02-05", + "Correlation": -0.95 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2022-03-04", + "Correlation": 0.67 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2022-04-01", + "Correlation": -0.8 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2022-04-28", + "Correlation": 0.16 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2022-05-26", + "Correlation": -0.93 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2022-06-22", + "Correlation": 0.59 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2022-07-19", + "Correlation": 0.43 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2022-08-16", + "Correlation": 0.02 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2022-09-12", + "Correlation": 0.17 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2022-10-09", + "Correlation": -0.8 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2022-11-06", + "Correlation": -0.07 + }, + { + "StartDate": "2018-12-13", + "EndDate": "2022-12-03", + "Correlation": 0.04 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2020-01-01", + "Correlation": 0.46 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2020-01-28", + "Correlation": -0.2 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2020-02-24", + "Correlation": 0.39 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2020-03-23", + "Correlation": -0.77 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2020-04-19", + "Correlation": -0.3 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2020-05-16", + "Correlation": 0.42 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2020-06-13", + "Correlation": 0 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2020-07-10", + "Correlation": -0.9 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2020-08-07", + "Correlation": 0.99 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2020-09-03", + "Correlation": -0.72 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2020-09-30", + "Correlation": -0.05 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2020-10-28", + "Correlation": 0.32 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2020-11-24", + "Correlation": -1 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2020-12-21", + "Correlation": -0.59 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2021-01-18", + "Correlation": 0.12 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2021-02-14", + "Correlation": -0.17 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2021-03-14", + "Correlation": 0.59 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2021-04-10", + "Correlation": 0.33 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2021-05-07", + "Correlation": -0.71 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2021-06-04", + "Correlation": -0.98 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2021-07-01", + "Correlation": -0.58 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2021-07-28", + "Correlation": -0.01 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2021-08-25", + "Correlation": 0.21 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2021-09-21", + "Correlation": 0.41 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2021-10-19", + "Correlation": 0.09 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2021-11-15", + "Correlation": -0.55 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2021-12-12", + "Correlation": 0.37 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2022-01-09", + "Correlation": -0.9 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2022-02-05", + "Correlation": 0.37 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2022-03-04", + "Correlation": 0.75 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2022-04-01", + "Correlation": 0.63 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2022-04-28", + "Correlation": 0.65 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2022-05-26", + "Correlation": 0.09 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2022-06-22", + "Correlation": 0.95 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2022-07-19", + "Correlation": -0.05 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2022-08-16", + "Correlation": 0.69 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2022-09-12", + "Correlation": -0.36 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2022-10-09", + "Correlation": 0.26 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2022-11-06", + "Correlation": -0.71 + }, + { + "StartDate": "2019-01-01", + "EndDate": "2022-12-03", + "Correlation": 0.45 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2020-01-01", + "Correlation": -0.96 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2020-01-28", + "Correlation": -0.06 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2020-02-24", + "Correlation": -0.43 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2020-03-23", + "Correlation": 0.57 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2020-04-19", + "Correlation": 0.49 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2020-05-16", + "Correlation": -0.37 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2020-06-13", + "Correlation": -0.52 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2020-07-10", + "Correlation": -0.25 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2020-08-07", + "Correlation": 0.51 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2020-09-03", + "Correlation": -0.48 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2020-09-30", + "Correlation": -0.54 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2020-10-28", + "Correlation": 0.97 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2020-11-24", + "Correlation": -0.27 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2020-12-21", + "Correlation": -0.27 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2021-01-18", + "Correlation": 0.22 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2021-02-14", + "Correlation": 0.05 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2021-03-14", + "Correlation": -0.66 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2021-04-10", + "Correlation": -0.24 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2021-05-07", + "Correlation": 0.44 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2021-06-04", + "Correlation": 0.75 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2021-07-01", + "Correlation": -0.76 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2021-07-28", + "Correlation": 0.63 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2021-08-25", + "Correlation": -0.91 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2021-09-21", + "Correlation": 0.59 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2021-10-19", + "Correlation": -0.07 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2021-11-15", + "Correlation": -0.21 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2021-12-12", + "Correlation": 0.87 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2022-01-09", + "Correlation": 0.06 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2022-02-05", + "Correlation": -0.9 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2022-03-04", + "Correlation": -0.96 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2022-04-01", + "Correlation": -0.02 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2022-04-28", + "Correlation": 0.56 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2022-05-26", + "Correlation": 0.68 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2022-06-22", + "Correlation": 0.77 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2022-07-19", + "Correlation": 0.43 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2022-08-16", + "Correlation": 0.69 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2022-09-12", + "Correlation": -0.84 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2022-10-09", + "Correlation": -0.02 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2022-11-06", + "Correlation": -0.68 + }, + { + "StartDate": "2019-01-19", + "EndDate": "2022-12-03", + "Correlation": -0.85 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2020-01-01", + "Correlation": 0.43 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2020-01-28", + "Correlation": 0.82 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2020-02-24", + "Correlation": -0.55 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2020-03-23", + "Correlation": -0.83 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2020-04-19", + "Correlation": 0.31 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2020-05-16", + "Correlation": 0.75 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2020-06-13", + "Correlation": 0.93 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2020-07-10", + "Correlation": -0.84 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2020-08-07", + "Correlation": -1 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2020-09-03", + "Correlation": 0.6 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2020-09-30", + "Correlation": -0.17 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2020-10-28", + "Correlation": -0.98 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2020-11-24", + "Correlation": -0.32 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2020-12-21", + "Correlation": -0.69 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2021-01-18", + "Correlation": -0.2 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2021-02-14", + "Correlation": -0.26 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2021-03-14", + "Correlation": 0.29 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2021-04-10", + "Correlation": 0.86 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2021-05-07", + "Correlation": 0.32 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2021-06-04", + "Correlation": -0.1 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2021-07-01", + "Correlation": 0.7 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2021-07-28", + "Correlation": 0.42 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2021-08-25", + "Correlation": -0.89 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2021-09-21", + "Correlation": 0.61 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2021-10-19", + "Correlation": -0.18 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2021-11-15", + "Correlation": 0.25 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2021-12-12", + "Correlation": 0.56 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2022-01-09", + "Correlation": -0.93 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2022-02-05", + "Correlation": 0.11 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2022-03-04", + "Correlation": -0.63 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2022-04-01", + "Correlation": -0.15 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2022-04-28", + "Correlation": 0.33 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2022-05-26", + "Correlation": -0.04 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2022-06-22", + "Correlation": 0.39 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2022-07-19", + "Correlation": -0.99 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2022-08-16", + "Correlation": -0.09 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2022-09-12", + "Correlation": 0.41 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2022-10-09", + "Correlation": 0.06 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2022-11-06", + "Correlation": -0.16 + }, + { + "StartDate": "2019-02-06", + "EndDate": "2022-12-03", + "Correlation": -0.15 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2020-01-01", + "Correlation": -0.42 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2020-01-28", + "Correlation": 0.81 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2020-02-24", + "Correlation": 0.72 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2020-03-23", + "Correlation": -0.3 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2020-04-19", + "Correlation": -0.26 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2020-05-16", + "Correlation": 0.29 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2020-06-13", + "Correlation": 0.84 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2020-07-10", + "Correlation": -0.21 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2020-08-07", + "Correlation": -0.59 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2020-09-03", + "Correlation": -0.87 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2020-09-30", + "Correlation": -0.28 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2020-10-28", + "Correlation": 0.01 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2020-11-24", + "Correlation": -0.94 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2020-12-21", + "Correlation": 0.23 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2021-01-18", + "Correlation": 0.69 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2021-02-14", + "Correlation": -0.3 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2021-03-14", + "Correlation": 0.12 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2021-04-10", + "Correlation": -0.77 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2021-05-07", + "Correlation": -0.48 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2021-06-04", + "Correlation": 0.21 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2021-07-01", + "Correlation": 0.76 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2021-07-28", + "Correlation": -0.67 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2021-08-25", + "Correlation": -0.37 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2021-09-21", + "Correlation": -0.54 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2021-10-19", + "Correlation": -0.77 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2021-11-15", + "Correlation": -0.3 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2021-12-12", + "Correlation": -0.1 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2022-01-09", + "Correlation": -0.75 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2022-02-05", + "Correlation": -0.13 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2022-03-04", + "Correlation": -0.31 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2022-04-01", + "Correlation": -0.71 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2022-04-28", + "Correlation": 0.89 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2022-05-26", + "Correlation": 0.74 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2022-06-22", + "Correlation": -0.38 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2022-07-19", + "Correlation": 0.72 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2022-08-16", + "Correlation": 0.81 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2022-09-12", + "Correlation": 0.65 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2022-10-09", + "Correlation": -0.91 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2022-11-06", + "Correlation": 0.58 + }, + { + "StartDate": "2019-02-24", + "EndDate": "2022-12-03", + "Correlation": 0.93 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2020-01-01", + "Correlation": -0.57 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2020-01-28", + "Correlation": 0.73 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2020-02-24", + "Correlation": 0.43 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2020-03-23", + "Correlation": 0.3 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2020-04-19", + "Correlation": -0.86 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2020-05-16", + "Correlation": 0.82 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2020-06-13", + "Correlation": -0.39 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2020-07-10", + "Correlation": -0.11 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2020-08-07", + "Correlation": 0.6 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2020-09-03", + "Correlation": -0.76 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2020-09-30", + "Correlation": -0.32 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2020-10-28", + "Correlation": 0.51 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2020-11-24", + "Correlation": 0.35 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2020-12-21", + "Correlation": -0.42 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2021-01-18", + "Correlation": -0.33 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2021-02-14", + "Correlation": 0.75 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2021-03-14", + "Correlation": 0.92 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2021-04-10", + "Correlation": 0.93 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2021-05-07", + "Correlation": 0.31 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2021-06-04", + "Correlation": -0.8 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2021-07-01", + "Correlation": 0.55 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2021-07-28", + "Correlation": 0.59 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2021-08-25", + "Correlation": -0.55 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2021-09-21", + "Correlation": -0.67 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2021-10-19", + "Correlation": 0.73 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2021-11-15", + "Correlation": -0.83 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2021-12-12", + "Correlation": -0.24 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2022-01-09", + "Correlation": -0.83 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2022-02-05", + "Correlation": -0.87 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2022-03-04", + "Correlation": 0.42 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2022-04-01", + "Correlation": -0.7 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2022-04-28", + "Correlation": -0.67 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2022-05-26", + "Correlation": 0.24 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2022-06-22", + "Correlation": 0.59 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2022-07-19", + "Correlation": 0.09 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2022-08-16", + "Correlation": 0.42 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2022-09-12", + "Correlation": -0.14 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2022-10-09", + "Correlation": -0.13 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2022-11-06", + "Correlation": 0.37 + }, + { + "StartDate": "2019-03-15", + "EndDate": "2022-12-03", + "Correlation": 0.04 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2020-01-01", + "Correlation": -0.83 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2020-01-28", + "Correlation": 0.67 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2020-02-24", + "Correlation": -0.78 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2020-03-23", + "Correlation": -0.55 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2020-04-19", + "Correlation": -0.55 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2020-05-16", + "Correlation": 0.33 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2020-06-13", + "Correlation": -0.71 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2020-07-10", + "Correlation": 0.77 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2020-08-07", + "Correlation": 1 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2020-09-03", + "Correlation": 0.65 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2020-09-30", + "Correlation": -0.41 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2020-10-28", + "Correlation": 0.62 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2020-11-24", + "Correlation": 0.65 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2020-12-21", + "Correlation": -0.11 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2021-01-18", + "Correlation": 0.38 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2021-02-14", + "Correlation": 0.28 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2021-03-14", + "Correlation": 0.33 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2021-04-10", + "Correlation": 0.32 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2021-05-07", + "Correlation": -0.51 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2021-06-04", + "Correlation": 0.16 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2021-07-01", + "Correlation": -0.8 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2021-07-28", + "Correlation": -0.04 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2021-08-25", + "Correlation": 0.55 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2021-09-21", + "Correlation": 0.55 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2021-10-19", + "Correlation": -0.63 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2021-11-15", + "Correlation": -0.38 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2021-12-12", + "Correlation": -0.92 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2022-01-09", + "Correlation": 0.92 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2022-02-05", + "Correlation": -0.88 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2022-03-04", + "Correlation": 0.79 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2022-04-01", + "Correlation": -0.43 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2022-04-28", + "Correlation": 0.88 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2022-05-26", + "Correlation": 0.74 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2022-06-22", + "Correlation": -0.06 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2022-07-19", + "Correlation": 0.4 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2022-08-16", + "Correlation": 0.47 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2022-09-12", + "Correlation": -0.83 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2022-10-09", + "Correlation": 0.85 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2022-11-06", + "Correlation": -0.28 + }, + { + "StartDate": "2019-04-02", + "EndDate": "2022-12-03", + "Correlation": 0.39 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2020-01-01", + "Correlation": -0.75 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2020-01-28", + "Correlation": 0.66 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2020-02-24", + "Correlation": 0.24 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2020-03-23", + "Correlation": -0.85 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2020-04-19", + "Correlation": 0.35 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2020-05-16", + "Correlation": -0.2 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2020-06-13", + "Correlation": 0.16 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2020-07-10", + "Correlation": -0.82 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2020-08-07", + "Correlation": -0.12 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2020-09-03", + "Correlation": 0.86 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2020-09-30", + "Correlation": -0.22 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2020-10-28", + "Correlation": -0.81 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2020-11-24", + "Correlation": 0.56 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2020-12-21", + "Correlation": 0.49 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2021-01-18", + "Correlation": 0.64 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2021-02-14", + "Correlation": 0.79 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2021-03-14", + "Correlation": 0.32 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2021-04-10", + "Correlation": 0.45 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2021-05-07", + "Correlation": 0.36 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2021-06-04", + "Correlation": 0 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2021-07-01", + "Correlation": -0.11 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2021-07-28", + "Correlation": 0.13 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2021-08-25", + "Correlation": 0.59 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2021-09-21", + "Correlation": 0.76 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2021-10-19", + "Correlation": 0.68 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2021-11-15", + "Correlation": 0.35 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2021-12-12", + "Correlation": 0.82 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2022-01-09", + "Correlation": 0.49 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2022-02-05", + "Correlation": -0.57 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2022-03-04", + "Correlation": -0.55 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2022-04-01", + "Correlation": -0.68 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2022-04-28", + "Correlation": -0.97 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2022-05-26", + "Correlation": 0.06 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2022-06-22", + "Correlation": -0.15 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2022-07-19", + "Correlation": -0.23 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2022-08-16", + "Correlation": 0.72 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2022-09-12", + "Correlation": -0.24 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2022-10-09", + "Correlation": -0.03 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2022-11-06", + "Correlation": 0.53 + }, + { + "StartDate": "2019-04-20", + "EndDate": "2022-12-03", + "Correlation": -1 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2020-01-01", + "Correlation": -0.58 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2020-01-28", + "Correlation": 0.52 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2020-02-24", + "Correlation": 0.89 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2020-03-23", + "Correlation": -0.82 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2020-04-19", + "Correlation": 0.74 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2020-05-16", + "Correlation": -0.39 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2020-06-13", + "Correlation": -0.54 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2020-07-10", + "Correlation": 0.56 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2020-08-07", + "Correlation": -0.72 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2020-09-03", + "Correlation": 0.19 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2020-09-30", + "Correlation": -0.53 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2020-10-28", + "Correlation": -0.93 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2020-11-24", + "Correlation": 0 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2020-12-21", + "Correlation": -0.07 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2021-01-18", + "Correlation": -0.44 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2021-02-14", + "Correlation": -0.11 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2021-03-14", + "Correlation": 0.18 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2021-04-10", + "Correlation": -0.71 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2021-05-07", + "Correlation": 0.77 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2021-06-04", + "Correlation": -0.8 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2021-07-01", + "Correlation": -0.7 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2021-07-28", + "Correlation": 0.87 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2021-08-25", + "Correlation": 0.91 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2021-09-21", + "Correlation": -0.84 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2021-10-19", + "Correlation": -0.76 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2021-11-15", + "Correlation": 0 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2021-12-12", + "Correlation": -0.73 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2022-01-09", + "Correlation": 0.9 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2022-02-05", + "Correlation": 0.06 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2022-03-04", + "Correlation": -0.16 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2022-04-01", + "Correlation": -0.22 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2022-04-28", + "Correlation": -0.01 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2022-05-26", + "Correlation": 0.31 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2022-06-22", + "Correlation": -0.77 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2022-07-19", + "Correlation": -0.57 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2022-08-16", + "Correlation": 0.4 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2022-09-12", + "Correlation": -0.3 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2022-10-09", + "Correlation": 0.19 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2022-11-06", + "Correlation": 0.08 + }, + { + "StartDate": "2019-05-08", + "EndDate": "2022-12-03", + "Correlation": 0.1 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2020-01-01", + "Correlation": 0 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2020-01-28", + "Correlation": -0.97 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2020-02-24", + "Correlation": 0.87 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2020-03-23", + "Correlation": 0.01 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2020-04-19", + "Correlation": 0.45 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2020-05-16", + "Correlation": 0.03 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2020-06-13", + "Correlation": -0.81 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2020-07-10", + "Correlation": -0.25 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2020-08-07", + "Correlation": -0.98 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2020-09-03", + "Correlation": -0.92 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2020-09-30", + "Correlation": 0.58 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2020-10-28", + "Correlation": -0.67 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2020-11-24", + "Correlation": -0.29 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2020-12-21", + "Correlation": 0.4 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2021-01-18", + "Correlation": 0.05 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2021-02-14", + "Correlation": -0.57 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2021-03-14", + "Correlation": -0.77 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2021-04-10", + "Correlation": 0.17 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2021-05-07", + "Correlation": -0.33 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2021-06-04", + "Correlation": -0.28 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2021-07-01", + "Correlation": -0.76 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2021-07-28", + "Correlation": -0.25 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2021-08-25", + "Correlation": -0.67 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2021-09-21", + "Correlation": 0.91 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2021-10-19", + "Correlation": -0.11 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2021-11-15", + "Correlation": -0.38 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2021-12-12", + "Correlation": 0.56 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2022-01-09", + "Correlation": -0.71 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2022-02-05", + "Correlation": 0.61 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2022-03-04", + "Correlation": -0.33 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2022-04-01", + "Correlation": 0.58 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2022-04-28", + "Correlation": -0.61 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2022-05-26", + "Correlation": 0.2 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2022-06-22", + "Correlation": 0.23 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2022-07-19", + "Correlation": -0.1 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2022-08-16", + "Correlation": -0.66 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2022-09-12", + "Correlation": 0.27 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2022-10-09", + "Correlation": -0.92 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2022-11-06", + "Correlation": -0.33 + }, + { + "StartDate": "2019-05-27", + "EndDate": "2022-12-03", + "Correlation": -0.23 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2020-01-01", + "Correlation": 0.01 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2020-01-28", + "Correlation": -0.28 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2020-02-24", + "Correlation": -0.45 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2020-03-23", + "Correlation": 0.53 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2020-04-19", + "Correlation": 0.85 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2020-05-16", + "Correlation": 0.97 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2020-06-13", + "Correlation": -0.16 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2020-07-10", + "Correlation": 0.16 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2020-08-07", + "Correlation": -0.93 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2020-09-03", + "Correlation": -0.17 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2020-09-30", + "Correlation": -0.58 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2020-10-28", + "Correlation": -0.79 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2020-11-24", + "Correlation": -0.48 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2020-12-21", + "Correlation": 0.28 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2021-01-18", + "Correlation": -0.51 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2021-02-14", + "Correlation": 0.66 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2021-03-14", + "Correlation": 0.98 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2021-04-10", + "Correlation": 0.46 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2021-05-07", + "Correlation": -0.52 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2021-06-04", + "Correlation": 0.71 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2021-07-01", + "Correlation": 0.13 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2021-07-28", + "Correlation": 0.7 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2021-08-25", + "Correlation": 0.91 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2021-09-21", + "Correlation": -0.78 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2021-10-19", + "Correlation": 0.85 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2021-11-15", + "Correlation": 0.1 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2021-12-12", + "Correlation": 0.49 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2022-01-09", + "Correlation": 0.33 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2022-02-05", + "Correlation": 0.49 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2022-03-04", + "Correlation": 0.97 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2022-04-01", + "Correlation": -0.14 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2022-04-28", + "Correlation": -0.34 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2022-05-26", + "Correlation": -0.65 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2022-06-22", + "Correlation": -0.33 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2022-07-19", + "Correlation": -0.14 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2022-08-16", + "Correlation": -0.95 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2022-09-12", + "Correlation": -0.87 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2022-10-09", + "Correlation": 0.67 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2022-11-06", + "Correlation": 0.01 + }, + { + "StartDate": "2019-06-14", + "EndDate": "2022-12-03", + "Correlation": 0.04 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2020-01-01", + "Correlation": 0.01 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2020-01-28", + "Correlation": 0.75 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2020-02-24", + "Correlation": 0.6 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2020-03-23", + "Correlation": 0.99 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2020-04-19", + "Correlation": 0.28 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2020-05-16", + "Correlation": 0.78 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2020-06-13", + "Correlation": 0.84 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2020-07-10", + "Correlation": 0.78 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2020-08-07", + "Correlation": -0.09 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2020-09-03", + "Correlation": -0.32 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2020-09-30", + "Correlation": -0.74 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2020-10-28", + "Correlation": -0.05 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2020-11-24", + "Correlation": -0.59 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2020-12-21", + "Correlation": 0.81 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2021-01-18", + "Correlation": 0.97 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2021-02-14", + "Correlation": -0.53 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2021-03-14", + "Correlation": -0.15 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2021-04-10", + "Correlation": -0.04 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2021-05-07", + "Correlation": 0.61 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2021-06-04", + "Correlation": -0.52 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2021-07-01", + "Correlation": 0.04 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2021-07-28", + "Correlation": -0.77 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2021-08-25", + "Correlation": 0.75 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2021-09-21", + "Correlation": 0.79 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2021-10-19", + "Correlation": 0.81 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2021-11-15", + "Correlation": -0.18 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2021-12-12", + "Correlation": -0.04 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2022-01-09", + "Correlation": 0.02 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2022-02-05", + "Correlation": 0.92 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2022-03-04", + "Correlation": -0.92 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2022-04-01", + "Correlation": 0.03 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2022-04-28", + "Correlation": 0.7 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2022-05-26", + "Correlation": 0.53 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2022-06-22", + "Correlation": 0.87 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2022-07-19", + "Correlation": -0.24 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2022-08-16", + "Correlation": 0.2 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2022-09-12", + "Correlation": -0.15 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2022-10-09", + "Correlation": 0.01 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2022-11-06", + "Correlation": 0.01 + }, + { + "StartDate": "2019-07-02", + "EndDate": "2022-12-03", + "Correlation": 0.67 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2020-01-01", + "Correlation": -0.87 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2020-01-28", + "Correlation": 0.87 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2020-02-24", + "Correlation": -0.92 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2020-03-23", + "Correlation": -0.19 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2020-04-19", + "Correlation": -0.55 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2020-05-16", + "Correlation": -0.58 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2020-06-13", + "Correlation": 0.28 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2020-07-10", + "Correlation": -0.9 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2020-08-07", + "Correlation": -0.01 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2020-09-03", + "Correlation": 0.55 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2020-09-30", + "Correlation": -0.22 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2020-10-28", + "Correlation": 0.92 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2020-11-24", + "Correlation": 0.67 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2020-12-21", + "Correlation": -0.84 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2021-01-18", + "Correlation": -0.75 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2021-02-14", + "Correlation": 0.32 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2021-03-14", + "Correlation": 0.46 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2021-04-10", + "Correlation": 0.78 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2021-05-07", + "Correlation": 0.88 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2021-06-04", + "Correlation": 0.02 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2021-07-01", + "Correlation": 0.53 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2021-07-28", + "Correlation": -0.07 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2021-08-25", + "Correlation": 0.39 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2021-09-21", + "Correlation": -0.3 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2021-10-19", + "Correlation": -0.87 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2021-11-15", + "Correlation": 0.03 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2021-12-12", + "Correlation": 0.3 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2022-01-09", + "Correlation": 0.94 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2022-02-05", + "Correlation": 0.51 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2022-03-04", + "Correlation": -0.06 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2022-04-01", + "Correlation": 0.94 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2022-04-28", + "Correlation": -0.85 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2022-05-26", + "Correlation": 0.94 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2022-06-22", + "Correlation": 0.45 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2022-07-19", + "Correlation": 0.62 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2022-08-16", + "Correlation": -0.61 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2022-09-12", + "Correlation": 0.49 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2022-10-09", + "Correlation": -0.81 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2022-11-06", + "Correlation": -0.5 + }, + { + "StartDate": "2019-07-20", + "EndDate": "2022-12-03", + "Correlation": 0.08 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2020-01-01", + "Correlation": 0.33 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2020-01-28", + "Correlation": -0.15 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2020-02-24", + "Correlation": 0.19 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2020-03-23", + "Correlation": 0.13 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2020-04-19", + "Correlation": 0.54 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2020-05-16", + "Correlation": 0.66 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2020-06-13", + "Correlation": -0.54 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2020-07-10", + "Correlation": 0.8 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2020-08-07", + "Correlation": 0.65 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2020-09-03", + "Correlation": 0.88 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2020-09-30", + "Correlation": 0.07 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2020-10-28", + "Correlation": -0.63 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2020-11-24", + "Correlation": -0.23 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2020-12-21", + "Correlation": -0.32 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2021-01-18", + "Correlation": 0.27 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2021-02-14", + "Correlation": 0.28 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2021-03-14", + "Correlation": -0.56 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2021-04-10", + "Correlation": 0.95 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2021-05-07", + "Correlation": -0.67 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2021-06-04", + "Correlation": -0.22 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2021-07-01", + "Correlation": 0.85 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2021-07-28", + "Correlation": -0.67 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2021-08-25", + "Correlation": -0.87 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2021-09-21", + "Correlation": -0.72 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2021-10-19", + "Correlation": -0.26 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2021-11-15", + "Correlation": 0.75 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2021-12-12", + "Correlation": 0.4 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2022-01-09", + "Correlation": -0.53 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2022-02-05", + "Correlation": 0.36 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2022-03-04", + "Correlation": 0.76 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2022-04-01", + "Correlation": 0.65 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2022-04-28", + "Correlation": 0.66 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2022-05-26", + "Correlation": 0.55 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2022-06-22", + "Correlation": -0.69 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2022-07-19", + "Correlation": 0.98 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2022-08-16", + "Correlation": 0.08 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2022-09-12", + "Correlation": 0.56 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2022-10-09", + "Correlation": -0.33 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2022-11-06", + "Correlation": -0.44 + }, + { + "StartDate": "2019-08-08", + "EndDate": "2022-12-03", + "Correlation": -0.48 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2020-01-01", + "Correlation": -0.28 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2020-01-28", + "Correlation": 0.74 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2020-02-24", + "Correlation": -0.8 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2020-03-23", + "Correlation": -0.02 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2020-04-19", + "Correlation": 0.72 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2020-05-16", + "Correlation": -0.78 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2020-06-13", + "Correlation": 0.01 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2020-07-10", + "Correlation": 0.3 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2020-08-07", + "Correlation": 0.47 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2020-09-03", + "Correlation": -0.36 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2020-09-30", + "Correlation": 0.34 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2020-10-28", + "Correlation": -0.9 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2020-11-24", + "Correlation": 0.18 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2020-12-21", + "Correlation": -0.89 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2021-01-18", + "Correlation": -0.21 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2021-02-14", + "Correlation": 0.14 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2021-03-14", + "Correlation": -0.76 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2021-04-10", + "Correlation": -0.98 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2021-05-07", + "Correlation": 0.62 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2021-06-04", + "Correlation": -0.49 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2021-07-01", + "Correlation": -0.95 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2021-07-28", + "Correlation": 0.2 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2021-08-25", + "Correlation": -0.86 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2021-09-21", + "Correlation": 0.25 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2021-10-19", + "Correlation": 0.19 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2021-11-15", + "Correlation": 0.78 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2021-12-12", + "Correlation": 0.13 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2022-01-09", + "Correlation": 0.85 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2022-02-05", + "Correlation": -0.97 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2022-03-04", + "Correlation": -0.16 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2022-04-01", + "Correlation": -0.3 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2022-04-28", + "Correlation": 0.56 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2022-05-26", + "Correlation": 0.28 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2022-06-22", + "Correlation": -0.85 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2022-07-19", + "Correlation": -0.1 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2022-08-16", + "Correlation": -0.28 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2022-09-12", + "Correlation": -0.99 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2022-10-09", + "Correlation": 0.01 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2022-11-06", + "Correlation": 0.93 + }, + { + "StartDate": "2019-08-26", + "EndDate": "2022-12-03", + "Correlation": 0 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2020-01-01", + "Correlation": -0.38 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2020-01-28", + "Correlation": 0.99 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2020-02-24", + "Correlation": -0.38 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2020-03-23", + "Correlation": 0.08 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2020-04-19", + "Correlation": 0.97 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2020-05-16", + "Correlation": 0.23 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2020-06-13", + "Correlation": -0.6 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2020-07-10", + "Correlation": 0.59 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2020-08-07", + "Correlation": 0.22 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2020-09-03", + "Correlation": -0.99 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2020-09-30", + "Correlation": 0.85 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2020-10-28", + "Correlation": 0.91 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2020-11-24", + "Correlation": 0.96 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2020-12-21", + "Correlation": -0.25 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2021-01-18", + "Correlation": 0.79 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2021-02-14", + "Correlation": -0.05 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2021-03-14", + "Correlation": 0.65 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2021-04-10", + "Correlation": -0.96 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2021-05-07", + "Correlation": 0.43 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2021-06-04", + "Correlation": -0.55 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2021-07-01", + "Correlation": -0.56 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2021-07-28", + "Correlation": -0.08 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2021-08-25", + "Correlation": -0.34 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2021-09-21", + "Correlation": -0.53 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2021-10-19", + "Correlation": -0.12 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2021-11-15", + "Correlation": -0.12 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2021-12-12", + "Correlation": -0.6 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2022-01-09", + "Correlation": 0.92 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2022-02-05", + "Correlation": -0.27 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2022-03-04", + "Correlation": 0.91 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2022-04-01", + "Correlation": -0.34 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2022-04-28", + "Correlation": 0.61 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2022-05-26", + "Correlation": 0.78 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2022-06-22", + "Correlation": 0.13 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2022-07-19", + "Correlation": 0.75 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2022-08-16", + "Correlation": 0.56 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2022-09-12", + "Correlation": -0.32 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2022-10-09", + "Correlation": 0.73 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2022-11-06", + "Correlation": -0.59 + }, + { + "StartDate": "2019-09-13", + "EndDate": "2022-12-03", + "Correlation": 0.71 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2020-01-01", + "Correlation": -0.15 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2020-01-28", + "Correlation": -0.63 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2020-02-24", + "Correlation": -0.07 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2020-03-23", + "Correlation": 0.44 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2020-04-19", + "Correlation": -0.53 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2020-05-16", + "Correlation": -0.72 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2020-06-13", + "Correlation": 0.03 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2020-07-10", + "Correlation": -0.31 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2020-08-07", + "Correlation": -0.45 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2020-09-03", + "Correlation": 0.73 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2020-09-30", + "Correlation": 0.9 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2020-10-28", + "Correlation": 0.2 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2020-11-24", + "Correlation": -0.92 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2020-12-21", + "Correlation": 0.06 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2021-01-18", + "Correlation": -0.59 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2021-02-14", + "Correlation": 0.52 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2021-03-14", + "Correlation": 0.51 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2021-04-10", + "Correlation": -0.79 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2021-05-07", + "Correlation": 0.18 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2021-06-04", + "Correlation": -0.56 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2021-07-01", + "Correlation": -0.71 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2021-07-28", + "Correlation": -0.8 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2021-08-25", + "Correlation": 0.01 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2021-09-21", + "Correlation": -0.92 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2021-10-19", + "Correlation": 0.07 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2021-11-15", + "Correlation": -0.16 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2021-12-12", + "Correlation": 0.62 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2022-01-09", + "Correlation": 0.77 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2022-02-05", + "Correlation": -0.41 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2022-03-04", + "Correlation": 0.49 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2022-04-01", + "Correlation": 0.77 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2022-04-28", + "Correlation": 0.44 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2022-05-26", + "Correlation": 0.62 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2022-06-22", + "Correlation": 0.1 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2022-07-19", + "Correlation": -0.79 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2022-08-16", + "Correlation": -0.63 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2022-09-12", + "Correlation": 0.07 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2022-10-09", + "Correlation": -0.35 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2022-11-06", + "Correlation": -0.12 + }, + { + "StartDate": "2019-10-01", + "EndDate": "2022-12-03", + "Correlation": 0.25 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2020-01-01", + "Correlation": -0.18 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2020-01-28", + "Correlation": -0.47 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2020-02-24", + "Correlation": -0.39 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2020-03-23", + "Correlation": 0.04 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2020-04-19", + "Correlation": 0.85 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2020-05-16", + "Correlation": 0.3 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2020-06-13", + "Correlation": 0.97 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2020-07-10", + "Correlation": 0.53 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2020-08-07", + "Correlation": 0.48 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2020-09-03", + "Correlation": 0.97 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2020-09-30", + "Correlation": 0.27 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2020-10-28", + "Correlation": 0.85 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2020-11-24", + "Correlation": -0.36 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2020-12-21", + "Correlation": 0.01 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2021-01-18", + "Correlation": 0.68 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2021-02-14", + "Correlation": -0.81 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2021-03-14", + "Correlation": 0.9 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2021-04-10", + "Correlation": -0.27 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2021-05-07", + "Correlation": -0.1 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2021-06-04", + "Correlation": 0.32 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2021-07-01", + "Correlation": 0.5 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2021-07-28", + "Correlation": 0.25 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2021-08-25", + "Correlation": -0.5 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2021-09-21", + "Correlation": 0.11 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2021-10-19", + "Correlation": -0.03 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2021-11-15", + "Correlation": 0.71 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2021-12-12", + "Correlation": 0.02 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2022-01-09", + "Correlation": -0.01 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2022-02-05", + "Correlation": 0.94 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2022-03-04", + "Correlation": -0.6 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2022-04-01", + "Correlation": -0.17 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2022-04-28", + "Correlation": -0.59 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2022-05-26", + "Correlation": -0.63 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2022-06-22", + "Correlation": -0.93 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2022-07-19", + "Correlation": 0.13 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2022-08-16", + "Correlation": 0.27 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2022-09-12", + "Correlation": -0.22 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2022-10-09", + "Correlation": 0.88 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2022-11-06", + "Correlation": 0.42 + }, + { + "StartDate": "2019-10-20", + "EndDate": "2022-12-03", + "Correlation": 0.89 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2020-01-01", + "Correlation": 0.89 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2020-01-28", + "Correlation": -0.03 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2020-02-24", + "Correlation": -0.35 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2020-03-23", + "Correlation": -1 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2020-04-19", + "Correlation": -0.59 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2020-05-16", + "Correlation": -0.32 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2020-06-13", + "Correlation": 0.37 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2020-07-10", + "Correlation": 0.94 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2020-08-07", + "Correlation": -0.88 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2020-09-03", + "Correlation": 0.07 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2020-09-30", + "Correlation": -0.78 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2020-10-28", + "Correlation": 0.62 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2020-11-24", + "Correlation": -0.55 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2020-12-21", + "Correlation": 0.07 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2021-01-18", + "Correlation": -0.4 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2021-02-14", + "Correlation": -0.26 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2021-03-14", + "Correlation": -0.95 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2021-04-10", + "Correlation": 0.05 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2021-05-07", + "Correlation": 0.84 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2021-06-04", + "Correlation": 0.72 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2021-07-01", + "Correlation": -0.44 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2021-07-28", + "Correlation": 0.19 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2021-08-25", + "Correlation": -0.07 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2021-09-21", + "Correlation": 0.57 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2021-10-19", + "Correlation": -0.4 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2021-11-15", + "Correlation": -0.14 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2021-12-12", + "Correlation": -0.1 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2022-01-09", + "Correlation": -0.07 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2022-02-05", + "Correlation": -0.06 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2022-03-04", + "Correlation": -0.02 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2022-04-01", + "Correlation": 0.39 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2022-04-28", + "Correlation": -0.22 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2022-05-26", + "Correlation": 0.69 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2022-06-22", + "Correlation": 0.12 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2022-07-19", + "Correlation": -0.73 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2022-08-16", + "Correlation": 0.92 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2022-09-12", + "Correlation": -0.68 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2022-10-09", + "Correlation": 0.25 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2022-11-06", + "Correlation": 0.31 + }, + { + "StartDate": "2019-11-07", + "EndDate": "2022-12-03", + "Correlation": 0.29 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2020-01-01", + "Correlation": 0.5 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2020-01-28", + "Correlation": -0.43 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2020-02-24", + "Correlation": 0.72 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2020-03-23", + "Correlation": -0.74 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2020-04-19", + "Correlation": -0.92 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2020-05-16", + "Correlation": -0.83 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2020-06-13", + "Correlation": 0.62 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2020-07-10", + "Correlation": 0.99 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2020-08-07", + "Correlation": -0.84 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2020-09-03", + "Correlation": -0.79 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2020-09-30", + "Correlation": 0.79 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2020-10-28", + "Correlation": 0.3 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2020-11-24", + "Correlation": -0.31 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2020-12-21", + "Correlation": -0.45 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2021-01-18", + "Correlation": -0.81 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2021-02-14", + "Correlation": 0.03 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2021-03-14", + "Correlation": 0.19 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2021-04-10", + "Correlation": -0.49 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2021-05-07", + "Correlation": 0.27 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2021-06-04", + "Correlation": -0.49 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2021-07-01", + "Correlation": 1 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2021-07-28", + "Correlation": 0.03 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2021-08-25", + "Correlation": 0.13 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2021-09-21", + "Correlation": 0.41 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2021-10-19", + "Correlation": 0.27 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2021-11-15", + "Correlation": 0.49 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2021-12-12", + "Correlation": -0.25 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2022-01-09", + "Correlation": 0.57 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2022-02-05", + "Correlation": -0.08 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2022-03-04", + "Correlation": 0.02 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2022-04-01", + "Correlation": -0.87 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2022-04-28", + "Correlation": 0.75 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2022-05-26", + "Correlation": 0.18 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2022-06-22", + "Correlation": -0.82 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2022-07-19", + "Correlation": -0.76 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2022-08-16", + "Correlation": -0.35 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2022-09-12", + "Correlation": -0.62 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2022-10-09", + "Correlation": -0.66 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2022-11-06", + "Correlation": 0.01 + }, + { + "StartDate": "2019-11-25", + "EndDate": "2022-12-03", + "Correlation": -0.24 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2020-01-01", + "Correlation": -0.89 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2020-01-28", + "Correlation": 0.22 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2020-02-24", + "Correlation": -0.64 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2020-03-23", + "Correlation": 0.61 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2020-04-19", + "Correlation": -0.71 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2020-05-16", + "Correlation": -0.46 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2020-06-13", + "Correlation": -0.01 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2020-07-10", + "Correlation": 0.12 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2020-08-07", + "Correlation": 0.49 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2020-09-03", + "Correlation": -0.75 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2020-09-30", + "Correlation": -0.35 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2020-10-28", + "Correlation": 0.48 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2020-11-24", + "Correlation": -0.5 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2020-12-21", + "Correlation": -0.13 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2021-01-18", + "Correlation": -0.51 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2021-02-14", + "Correlation": 0.18 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2021-03-14", + "Correlation": -0.23 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2021-04-10", + "Correlation": -0.02 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2021-05-07", + "Correlation": -0.54 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2021-06-04", + "Correlation": 0.51 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2021-07-01", + "Correlation": 0.57 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2021-07-28", + "Correlation": 0.42 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2021-08-25", + "Correlation": 0.31 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2021-09-21", + "Correlation": -0.14 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2021-10-19", + "Correlation": -0.68 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2021-11-15", + "Correlation": -0.77 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2021-12-12", + "Correlation": -0.81 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2022-01-09", + "Correlation": 0.36 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2022-02-05", + "Correlation": 0.27 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2022-03-04", + "Correlation": -0.36 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2022-04-01", + "Correlation": 0.45 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2022-04-28", + "Correlation": 0.03 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2022-05-26", + "Correlation": -0.57 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2022-06-22", + "Correlation": -0.17 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2022-07-19", + "Correlation": 0.24 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2022-08-16", + "Correlation": 0.18 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2022-09-12", + "Correlation": -0.01 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2022-10-09", + "Correlation": -0.97 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2022-11-06", + "Correlation": -0.1 + }, + { + "StartDate": "2019-12-13", + "EndDate": "2022-12-03", + "Correlation": -0.45 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2020-01-01", + "Correlation": -0.99 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2020-01-28", + "Correlation": 0.94 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2020-02-24", + "Correlation": 0.16 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2020-03-23", + "Correlation": -0.03 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2020-04-19", + "Correlation": -0.46 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2020-05-16", + "Correlation": 0.02 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2020-06-13", + "Correlation": -0.2 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2020-07-10", + "Correlation": -0.9 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2020-08-07", + "Correlation": 0.85 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2020-09-03", + "Correlation": 0.54 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2020-09-30", + "Correlation": 0.02 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2020-10-28", + "Correlation": -0.17 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2020-11-24", + "Correlation": -0.68 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2020-12-21", + "Correlation": 0.75 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2021-01-18", + "Correlation": 0.58 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2021-02-14", + "Correlation": -0.12 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2021-03-14", + "Correlation": -0.87 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2021-04-10", + "Correlation": 0.97 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2021-05-07", + "Correlation": 0.05 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2021-06-04", + "Correlation": -0.1 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2021-07-01", + "Correlation": -0.94 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2021-07-28", + "Correlation": 0.99 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2021-08-25", + "Correlation": -0.91 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2021-09-21", + "Correlation": 0.71 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2021-10-19", + "Correlation": -0.03 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2021-11-15", + "Correlation": 0.45 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2021-12-12", + "Correlation": 0.27 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2022-01-09", + "Correlation": 0.45 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2022-02-05", + "Correlation": 0.44 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2022-03-04", + "Correlation": 0.5 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2022-04-01", + "Correlation": 0.45 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2022-04-28", + "Correlation": -0.38 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2022-05-26", + "Correlation": 0.02 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2022-06-22", + "Correlation": 0.87 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2022-07-19", + "Correlation": 0.25 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2022-08-16", + "Correlation": 0.15 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2022-09-12", + "Correlation": -0.82 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2022-10-09", + "Correlation": 0.82 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2022-11-06", + "Correlation": -0.02 + }, + { + "StartDate": "2020-01-01", + "EndDate": "2022-12-03", + "Correlation": -0.31 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2020-01-01", + "Correlation": 0.55 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2020-01-28", + "Correlation": -0.58 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2020-02-24", + "Correlation": -0.71 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2020-03-23", + "Correlation": 0.29 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2020-04-19", + "Correlation": 0.55 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2020-05-16", + "Correlation": -0.97 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2020-06-13", + "Correlation": -0.24 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2020-07-10", + "Correlation": -0.84 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2020-08-07", + "Correlation": -0.82 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2020-09-03", + "Correlation": 0.98 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2020-09-30", + "Correlation": 0.64 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2020-10-28", + "Correlation": -0.35 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2020-11-24", + "Correlation": -0.2 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2020-12-21", + "Correlation": 0.97 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2021-01-18", + "Correlation": -0.96 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2021-02-14", + "Correlation": 0.73 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2021-03-14", + "Correlation": 0.82 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2021-04-10", + "Correlation": -0.95 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2021-05-07", + "Correlation": 0.35 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2021-06-04", + "Correlation": 0.47 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2021-07-01", + "Correlation": -0.27 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2021-07-28", + "Correlation": 0.75 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2021-08-25", + "Correlation": 0.53 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2021-09-21", + "Correlation": -0.22 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2021-10-19", + "Correlation": -0.28 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2021-11-15", + "Correlation": -0.38 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2021-12-12", + "Correlation": -0.76 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2022-01-09", + "Correlation": -0.49 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2022-02-05", + "Correlation": -0.63 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2022-03-04", + "Correlation": -0.83 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2022-04-01", + "Correlation": 0.24 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2022-04-28", + "Correlation": 0.23 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2022-05-26", + "Correlation": -0.16 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2022-06-22", + "Correlation": 0.46 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2022-07-19", + "Correlation": -0.48 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2022-08-16", + "Correlation": 0.39 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2022-09-12", + "Correlation": -0.64 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2022-10-09", + "Correlation": 0.82 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2022-11-06", + "Correlation": 0.26 + }, + { + "StartDate": "2020-01-19", + "EndDate": "2022-12-03", + "Correlation": 0.53 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2020-01-01", + "Correlation": -0.04 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2020-01-28", + "Correlation": 0.41 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2020-02-24", + "Correlation": 0.06 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2020-03-23", + "Correlation": 0.47 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2020-04-19", + "Correlation": -0.09 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2020-05-16", + "Correlation": -0.99 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2020-06-13", + "Correlation": 0.71 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2020-07-10", + "Correlation": 0.24 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2020-08-07", + "Correlation": 0.37 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2020-09-03", + "Correlation": -0.98 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2020-09-30", + "Correlation": 0.25 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2020-10-28", + "Correlation": -0.1 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2020-11-24", + "Correlation": -0.87 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2020-12-21", + "Correlation": -0.45 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2021-01-18", + "Correlation": -0.13 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2021-02-14", + "Correlation": -0.64 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2021-03-14", + "Correlation": 0.5 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2021-04-10", + "Correlation": 0.17 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2021-05-07", + "Correlation": -0.76 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2021-06-04", + "Correlation": 0.64 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2021-07-01", + "Correlation": 0.7 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2021-07-28", + "Correlation": -0.43 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2021-08-25", + "Correlation": -0.49 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2021-09-21", + "Correlation": 0.44 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2021-10-19", + "Correlation": 0.39 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2021-11-15", + "Correlation": 0.4 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2021-12-12", + "Correlation": -0.36 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2022-01-09", + "Correlation": -0.19 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2022-02-05", + "Correlation": 0.72 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2022-03-04", + "Correlation": -0.7 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2022-04-01", + "Correlation": 0.22 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2022-04-28", + "Correlation": -0.92 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2022-05-26", + "Correlation": -0.4 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2022-06-22", + "Correlation": 0.07 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2022-07-19", + "Correlation": -0.9 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2022-08-16", + "Correlation": -0.72 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2022-09-12", + "Correlation": 0.05 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2022-10-09", + "Correlation": 0.59 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2022-11-06", + "Correlation": -0.3 + }, + { + "StartDate": "2020-02-06", + "EndDate": "2022-12-03", + "Correlation": 0.46 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2020-01-01", + "Correlation": 0.23 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2020-01-28", + "Correlation": -0.61 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2020-02-24", + "Correlation": 0.22 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2020-03-23", + "Correlation": 0.51 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2020-04-19", + "Correlation": -0.95 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2020-05-16", + "Correlation": -0.11 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2020-06-13", + "Correlation": -0.02 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2020-07-10", + "Correlation": -0.62 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2020-08-07", + "Correlation": -0.25 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2020-09-03", + "Correlation": -0.59 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2020-09-30", + "Correlation": -0.04 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2020-10-28", + "Correlation": 0.49 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2020-11-24", + "Correlation": -0.15 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2020-12-21", + "Correlation": 0.44 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2021-01-18", + "Correlation": -0.9 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2021-02-14", + "Correlation": -0.62 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2021-03-14", + "Correlation": 0.42 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2021-04-10", + "Correlation": 0.03 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2021-05-07", + "Correlation": 0.71 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2021-06-04", + "Correlation": -0.09 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2021-07-01", + "Correlation": -0.79 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2021-07-28", + "Correlation": 0.42 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2021-08-25", + "Correlation": -0.45 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2021-09-21", + "Correlation": 0.55 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2021-10-19", + "Correlation": 0.73 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2021-11-15", + "Correlation": 0.98 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2021-12-12", + "Correlation": 0.36 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2022-01-09", + "Correlation": 0.22 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2022-02-05", + "Correlation": 0.4 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2022-03-04", + "Correlation": -0.85 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2022-04-01", + "Correlation": -0.64 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2022-04-28", + "Correlation": 0.8 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2022-05-26", + "Correlation": 0.17 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2022-06-22", + "Correlation": -1 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2022-07-19", + "Correlation": -0.53 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2022-08-16", + "Correlation": 0.48 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2022-09-12", + "Correlation": 0.13 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2022-10-09", + "Correlation": 0.3 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2022-11-06", + "Correlation": 0.73 + }, + { + "StartDate": "2020-02-24", + "EndDate": "2022-12-03", + "Correlation": 0.58 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2020-01-01", + "Correlation": 0.52 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2020-01-28", + "Correlation": -0.56 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2020-02-24", + "Correlation": 0.91 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2020-03-23", + "Correlation": 0.98 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2020-04-19", + "Correlation": 0.13 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2020-05-16", + "Correlation": 0.05 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2020-06-13", + "Correlation": -0.03 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2020-07-10", + "Correlation": 0.58 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2020-08-07", + "Correlation": 0.77 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2020-09-03", + "Correlation": -0.24 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2020-09-30", + "Correlation": -0.34 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2020-10-28", + "Correlation": 0.88 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2020-11-24", + "Correlation": -0.57 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2020-12-21", + "Correlation": 0.01 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2021-01-18", + "Correlation": 0.92 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2021-02-14", + "Correlation": 0.94 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2021-03-14", + "Correlation": -0.2 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2021-04-10", + "Correlation": 0.18 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2021-05-07", + "Correlation": -0.07 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2021-06-04", + "Correlation": 0.29 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2021-07-01", + "Correlation": -0.38 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2021-07-28", + "Correlation": 0.1 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2021-08-25", + "Correlation": -0.01 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2021-09-21", + "Correlation": -0.6 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2021-10-19", + "Correlation": 0.76 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2021-11-15", + "Correlation": -0.94 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2021-12-12", + "Correlation": -0.98 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2022-01-09", + "Correlation": -0.96 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2022-02-05", + "Correlation": 0.21 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2022-03-04", + "Correlation": 0.25 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2022-04-01", + "Correlation": -0.41 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2022-04-28", + "Correlation": -0.19 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2022-05-26", + "Correlation": -0.52 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2022-06-22", + "Correlation": -0.7 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2022-07-19", + "Correlation": 0.62 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2022-08-16", + "Correlation": -0.36 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2022-09-12", + "Correlation": 0.48 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2022-10-09", + "Correlation": 0.59 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2022-11-06", + "Correlation": -0.56 + }, + { + "StartDate": "2020-03-14", + "EndDate": "2022-12-03", + "Correlation": 0.62 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2020-01-01", + "Correlation": 0.13 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2020-01-28", + "Correlation": -0.9 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2020-02-24", + "Correlation": -0.36 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2020-03-23", + "Correlation": 0.42 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2020-04-19", + "Correlation": -0.19 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2020-05-16", + "Correlation": -0.38 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2020-06-13", + "Correlation": 0.68 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2020-07-10", + "Correlation": 0.02 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2020-08-07", + "Correlation": 0.79 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2020-09-03", + "Correlation": -0.7 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2020-09-30", + "Correlation": 0.42 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2020-10-28", + "Correlation": 0.01 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2020-11-24", + "Correlation": -0.03 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2020-12-21", + "Correlation": -0.06 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2021-01-18", + "Correlation": -0.2 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2021-02-14", + "Correlation": -0.46 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2021-03-14", + "Correlation": -0.2 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2021-04-10", + "Correlation": 0.65 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2021-05-07", + "Correlation": -0.4 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2021-06-04", + "Correlation": -0.78 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2021-07-01", + "Correlation": -0.28 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2021-07-28", + "Correlation": -0.9 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2021-08-25", + "Correlation": -0.73 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2021-09-21", + "Correlation": 0.59 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2021-10-19", + "Correlation": -0.27 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2021-11-15", + "Correlation": 0.56 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2021-12-12", + "Correlation": 0.3 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2022-01-09", + "Correlation": -0.7 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2022-02-05", + "Correlation": -0.31 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2022-03-04", + "Correlation": -0.53 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2022-04-01", + "Correlation": -0.32 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2022-04-28", + "Correlation": 0.52 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2022-05-26", + "Correlation": 0.98 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2022-06-22", + "Correlation": -0.43 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2022-07-19", + "Correlation": -0.42 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2022-08-16", + "Correlation": -0.02 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2022-09-12", + "Correlation": 0.93 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2022-10-09", + "Correlation": 1 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2022-11-06", + "Correlation": -0.65 + }, + { + "StartDate": "2020-04-01", + "EndDate": "2022-12-03", + "Correlation": -0.34 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2020-01-01", + "Correlation": 0.79 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2020-01-28", + "Correlation": -0.38 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2020-02-24", + "Correlation": 0.97 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2020-03-23", + "Correlation": 0.56 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2020-04-19", + "Correlation": 0.13 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2020-05-16", + "Correlation": 0.92 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2020-06-13", + "Correlation": 0.97 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2020-07-10", + "Correlation": 0.13 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2020-08-07", + "Correlation": 0.92 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2020-09-03", + "Correlation": 0.38 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2020-09-30", + "Correlation": -0.76 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2020-10-28", + "Correlation": 0.02 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2020-11-24", + "Correlation": -0.71 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2020-12-21", + "Correlation": 0.18 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2021-01-18", + "Correlation": -0.23 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2021-02-14", + "Correlation": -0.79 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2021-03-14", + "Correlation": -0.06 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2021-04-10", + "Correlation": -0.78 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2021-05-07", + "Correlation": 0.92 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2021-06-04", + "Correlation": 0.31 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2021-07-01", + "Correlation": -0.26 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2021-07-28", + "Correlation": -0.24 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2021-08-25", + "Correlation": 0.86 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2021-09-21", + "Correlation": -0.92 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2021-10-19", + "Correlation": -0.61 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2021-11-15", + "Correlation": 0.57 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2021-12-12", + "Correlation": -0.25 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2022-01-09", + "Correlation": -0.33 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2022-02-05", + "Correlation": -0.73 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2022-03-04", + "Correlation": 0.78 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2022-04-01", + "Correlation": -0.39 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2022-04-28", + "Correlation": -0.21 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2022-05-26", + "Correlation": -0.75 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2022-06-22", + "Correlation": -0.04 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2022-07-19", + "Correlation": 0.66 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2022-08-16", + "Correlation": -0.94 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2022-09-12", + "Correlation": -0.29 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2022-10-09", + "Correlation": 0.4 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2022-11-06", + "Correlation": -0.28 + }, + { + "StartDate": "2020-04-19", + "EndDate": "2022-12-03", + "Correlation": 0.43 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2020-01-01", + "Correlation": -0.02 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2020-01-28", + "Correlation": -0.85 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2020-02-24", + "Correlation": -0.17 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2020-03-23", + "Correlation": 0.09 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2020-04-19", + "Correlation": -0.72 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2020-05-16", + "Correlation": 0.1 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2020-06-13", + "Correlation": 0.82 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2020-07-10", + "Correlation": 0.04 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2020-08-07", + "Correlation": -0.13 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2020-09-03", + "Correlation": 0.51 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2020-09-30", + "Correlation": 0.33 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2020-10-28", + "Correlation": 0.57 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2020-11-24", + "Correlation": -0.84 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2020-12-21", + "Correlation": -0.92 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2021-01-18", + "Correlation": 0.23 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2021-02-14", + "Correlation": -0.64 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2021-03-14", + "Correlation": -0.72 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2021-04-10", + "Correlation": 0.76 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2021-05-07", + "Correlation": 0.7 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2021-06-04", + "Correlation": -0.78 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2021-07-01", + "Correlation": -0.37 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2021-07-28", + "Correlation": -0.04 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2021-08-25", + "Correlation": 0.04 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2021-09-21", + "Correlation": 0.27 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2021-10-19", + "Correlation": 0.39 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2021-11-15", + "Correlation": 0.87 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2021-12-12", + "Correlation": 0.57 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2022-01-09", + "Correlation": 0.46 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2022-02-05", + "Correlation": 0.52 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2022-03-04", + "Correlation": -0.26 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2022-04-01", + "Correlation": -0.65 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2022-04-28", + "Correlation": -0.56 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2022-05-26", + "Correlation": -0.34 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2022-06-22", + "Correlation": 0.9 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2022-07-19", + "Correlation": -0.38 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2022-08-16", + "Correlation": 0.42 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2022-09-12", + "Correlation": -0.28 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2022-10-09", + "Correlation": 0.81 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2022-11-06", + "Correlation": -0.16 + }, + { + "StartDate": "2020-05-07", + "EndDate": "2022-12-03", + "Correlation": 0.31 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2020-01-01", + "Correlation": -0.07 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2020-01-28", + "Correlation": -0.59 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2020-02-24", + "Correlation": 0.39 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2020-03-23", + "Correlation": 0.44 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2020-04-19", + "Correlation": -0.89 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2020-05-16", + "Correlation": 0.84 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2020-06-13", + "Correlation": 0.24 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2020-07-10", + "Correlation": -0.95 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2020-08-07", + "Correlation": -0.61 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2020-09-03", + "Correlation": 0.97 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2020-09-30", + "Correlation": -0.14 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2020-10-28", + "Correlation": 0.34 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2020-11-24", + "Correlation": -0.01 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2020-12-21", + "Correlation": 0.22 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2021-01-18", + "Correlation": -0.86 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2021-02-14", + "Correlation": 0.49 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2021-03-14", + "Correlation": -0.28 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2021-04-10", + "Correlation": 0.23 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2021-05-07", + "Correlation": -0.57 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2021-06-04", + "Correlation": 0.01 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2021-07-01", + "Correlation": -0.05 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2021-07-28", + "Correlation": 0.34 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2021-08-25", + "Correlation": -0.79 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2021-09-21", + "Correlation": 0.07 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2021-10-19", + "Correlation": -0.87 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2021-11-15", + "Correlation": 0.54 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2021-12-12", + "Correlation": 0.03 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2022-01-09", + "Correlation": 0.35 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2022-02-05", + "Correlation": 0.08 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2022-03-04", + "Correlation": 0.58 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2022-04-01", + "Correlation": 0.47 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2022-04-28", + "Correlation": 0.16 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2022-05-26", + "Correlation": -0.83 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2022-06-22", + "Correlation": 0.27 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2022-07-19", + "Correlation": 0.1 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2022-08-16", + "Correlation": -0.27 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2022-09-12", + "Correlation": -0.85 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2022-10-09", + "Correlation": 0.15 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2022-11-06", + "Correlation": 0.45 + }, + { + "StartDate": "2020-05-26", + "EndDate": "2022-12-03", + "Correlation": 0.79 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2020-01-01", + "Correlation": -0.86 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2020-01-28", + "Correlation": -0.33 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2020-02-24", + "Correlation": -0.13 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2020-03-23", + "Correlation": 0.65 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2020-04-19", + "Correlation": 0.02 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2020-05-16", + "Correlation": 0.01 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2020-06-13", + "Correlation": -0.31 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2020-07-10", + "Correlation": -0.17 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2020-08-07", + "Correlation": 0.25 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2020-09-03", + "Correlation": -0.37 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2020-09-30", + "Correlation": 0.58 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2020-10-28", + "Correlation": 0 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2020-11-24", + "Correlation": 0.03 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2020-12-21", + "Correlation": 0.51 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2021-01-18", + "Correlation": 0.26 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2021-02-14", + "Correlation": 0.42 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2021-03-14", + "Correlation": 0.4 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2021-04-10", + "Correlation": -0.58 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2021-05-07", + "Correlation": -0.57 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2021-06-04", + "Correlation": -0.61 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2021-07-01", + "Correlation": -0.37 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2021-07-28", + "Correlation": -0.76 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2021-08-25", + "Correlation": -0.87 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2021-09-21", + "Correlation": 0.64 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2021-10-19", + "Correlation": 0.08 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2021-11-15", + "Correlation": 0.4 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2021-12-12", + "Correlation": -0.81 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2022-01-09", + "Correlation": -0.56 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2022-02-05", + "Correlation": -0.31 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2022-03-04", + "Correlation": -0.69 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2022-04-01", + "Correlation": -0.56 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2022-04-28", + "Correlation": -0.14 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2022-05-26", + "Correlation": -0.25 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2022-06-22", + "Correlation": -0.91 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2022-07-19", + "Correlation": 0.6 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2022-08-16", + "Correlation": 0.81 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2022-09-12", + "Correlation": 0.56 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2022-10-09", + "Correlation": -0.35 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2022-11-06", + "Correlation": -0.25 + }, + { + "StartDate": "2020-06-13", + "EndDate": "2022-12-03", + "Correlation": 0.66 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2020-01-01", + "Correlation": -0.97 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2020-01-28", + "Correlation": 0.76 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2020-02-24", + "Correlation": 0.22 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2020-03-23", + "Correlation": 0.32 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2020-04-19", + "Correlation": -0.39 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2020-05-16", + "Correlation": 0.72 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2020-06-13", + "Correlation": -0.72 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2020-07-10", + "Correlation": -0.16 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2020-08-07", + "Correlation": 0.63 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2020-09-03", + "Correlation": 0.68 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2020-09-30", + "Correlation": -0.74 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2020-10-28", + "Correlation": -0.1 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2020-11-24", + "Correlation": -0.34 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2020-12-21", + "Correlation": -0.5 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2021-01-18", + "Correlation": -0.4 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2021-02-14", + "Correlation": -0.41 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2021-03-14", + "Correlation": -0.58 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2021-04-10", + "Correlation": -0.65 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2021-05-07", + "Correlation": -0.05 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2021-06-04", + "Correlation": 0.08 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2021-07-01", + "Correlation": 0.35 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2021-07-28", + "Correlation": -0.56 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2021-08-25", + "Correlation": -0.27 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2021-09-21", + "Correlation": 0.21 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2021-10-19", + "Correlation": -0.17 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2021-11-15", + "Correlation": -0.04 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2021-12-12", + "Correlation": -0.86 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2022-01-09", + "Correlation": -0.45 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2022-02-05", + "Correlation": 0.97 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2022-03-04", + "Correlation": -0.93 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2022-04-01", + "Correlation": -0.06 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2022-04-28", + "Correlation": -0.28 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2022-05-26", + "Correlation": 0.66 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2022-06-22", + "Correlation": -0.88 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2022-07-19", + "Correlation": -0.91 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2022-08-16", + "Correlation": -0.77 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2022-09-12", + "Correlation": 0.77 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2022-10-09", + "Correlation": -0.2 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2022-11-06", + "Correlation": -0.38 + }, + { + "StartDate": "2020-07-01", + "EndDate": "2022-12-03", + "Correlation": 0.41 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2020-01-01", + "Correlation": 0.06 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2020-01-28", + "Correlation": -0.92 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2020-02-24", + "Correlation": 0.02 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2020-03-23", + "Correlation": -0.68 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2020-04-19", + "Correlation": -0.31 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2020-05-16", + "Correlation": -0.78 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2020-06-13", + "Correlation": -0.84 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2020-07-10", + "Correlation": 0.52 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2020-08-07", + "Correlation": 0.05 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2020-09-03", + "Correlation": 0.8 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2020-09-30", + "Correlation": 0.17 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2020-10-28", + "Correlation": 0.14 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2020-11-24", + "Correlation": -0.26 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2020-12-21", + "Correlation": 0.02 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2021-01-18", + "Correlation": -0.91 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2021-02-14", + "Correlation": 0.92 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2021-03-14", + "Correlation": 0.5 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2021-04-10", + "Correlation": 0.85 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2021-05-07", + "Correlation": -0.38 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2021-06-04", + "Correlation": -0.23 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2021-07-01", + "Correlation": 0.93 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2021-07-28", + "Correlation": 0.18 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2021-08-25", + "Correlation": 0.37 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2021-09-21", + "Correlation": -0.78 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2021-10-19", + "Correlation": -0.42 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2021-11-15", + "Correlation": -0.97 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2021-12-12", + "Correlation": 0.21 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2022-01-09", + "Correlation": -0.55 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2022-02-05", + "Correlation": -0.55 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2022-03-04", + "Correlation": -0.96 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2022-04-01", + "Correlation": -0.18 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2022-04-28", + "Correlation": 0.76 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2022-05-26", + "Correlation": -0.7 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2022-06-22", + "Correlation": -0.73 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2022-07-19", + "Correlation": 0.11 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2022-08-16", + "Correlation": 0.69 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2022-09-12", + "Correlation": -0.56 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2022-10-09", + "Correlation": 0.78 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2022-11-06", + "Correlation": 0.71 + }, + { + "StartDate": "2020-07-19", + "EndDate": "2022-12-03", + "Correlation": 0.34 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2020-01-01", + "Correlation": 0.2 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2020-01-28", + "Correlation": 0.16 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2020-02-24", + "Correlation": -0.09 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2020-03-23", + "Correlation": 0.63 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2020-04-19", + "Correlation": -0.96 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2020-05-16", + "Correlation": -0.78 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2020-06-13", + "Correlation": -0.04 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2020-07-10", + "Correlation": -0.42 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2020-08-07", + "Correlation": 0.88 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2020-09-03", + "Correlation": -0.13 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2020-09-30", + "Correlation": -0.34 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2020-10-28", + "Correlation": 0.3 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2020-11-24", + "Correlation": 0.76 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2020-12-21", + "Correlation": -0.04 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2021-01-18", + "Correlation": -0.62 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2021-02-14", + "Correlation": -0.84 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2021-03-14", + "Correlation": -0.14 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2021-04-10", + "Correlation": -0.84 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2021-05-07", + "Correlation": -0.04 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2021-06-04", + "Correlation": -0.55 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2021-07-01", + "Correlation": -0.7 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2021-07-28", + "Correlation": -0.38 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2021-08-25", + "Correlation": -0.04 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2021-09-21", + "Correlation": -0.92 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2021-10-19", + "Correlation": 0.02 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2021-11-15", + "Correlation": 0.81 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2021-12-12", + "Correlation": -0.93 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2022-01-09", + "Correlation": -0.26 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2022-02-05", + "Correlation": -0.13 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2022-03-04", + "Correlation": 0.94 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2022-04-01", + "Correlation": 0.58 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2022-04-28", + "Correlation": -0.83 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2022-05-26", + "Correlation": 0.53 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2022-06-22", + "Correlation": 0.09 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2022-07-19", + "Correlation": 0.66 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2022-08-16", + "Correlation": -0.47 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2022-09-12", + "Correlation": -0.17 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2022-10-09", + "Correlation": 0.55 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2022-11-06", + "Correlation": -0.4 + }, + { + "StartDate": "2020-08-07", + "EndDate": "2022-12-03", + "Correlation": 0.48 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2020-01-01", + "Correlation": 0.17 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2020-01-28", + "Correlation": -0.86 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2020-02-24", + "Correlation": 0.01 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2020-03-23", + "Correlation": 0.49 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2020-04-19", + "Correlation": 0.93 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2020-05-16", + "Correlation": 0.51 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2020-06-13", + "Correlation": 0.27 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2020-07-10", + "Correlation": 0.53 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2020-08-07", + "Correlation": 0.41 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2020-09-03", + "Correlation": -0.74 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2020-09-30", + "Correlation": 0.64 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2020-10-28", + "Correlation": 0.33 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2020-11-24", + "Correlation": 0.17 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2020-12-21", + "Correlation": 0.22 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2021-01-18", + "Correlation": 0.96 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2021-02-14", + "Correlation": 0.71 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2021-03-14", + "Correlation": 0.67 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2021-04-10", + "Correlation": 0.56 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2021-05-07", + "Correlation": -0.67 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2021-06-04", + "Correlation": 0.26 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2021-07-01", + "Correlation": -0.53 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2021-07-28", + "Correlation": -0.36 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2021-08-25", + "Correlation": -0.91 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2021-09-21", + "Correlation": 0.54 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2021-10-19", + "Correlation": -0.95 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2021-11-15", + "Correlation": 0.41 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2021-12-12", + "Correlation": 0.91 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2022-01-09", + "Correlation": 0.26 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2022-02-05", + "Correlation": 1 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2022-03-04", + "Correlation": -0.35 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2022-04-01", + "Correlation": -0.91 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2022-04-28", + "Correlation": -0.11 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2022-05-26", + "Correlation": -0.14 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2022-06-22", + "Correlation": 0.92 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2022-07-19", + "Correlation": 0.93 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2022-08-16", + "Correlation": 0.6 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2022-09-12", + "Correlation": -0.19 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2022-10-09", + "Correlation": -0.15 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2022-11-06", + "Correlation": 0.21 + }, + { + "StartDate": "2020-08-25", + "EndDate": "2022-12-03", + "Correlation": -0.04 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2020-01-01", + "Correlation": 0.51 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2020-01-28", + "Correlation": -0.89 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2020-02-24", + "Correlation": 0.03 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2020-03-23", + "Correlation": 0.61 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2020-04-19", + "Correlation": 0 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2020-05-16", + "Correlation": 0.94 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2020-06-13", + "Correlation": 0.94 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2020-07-10", + "Correlation": 0.01 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2020-08-07", + "Correlation": 0.74 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2020-09-03", + "Correlation": -0.15 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2020-09-30", + "Correlation": -0.12 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2020-10-28", + "Correlation": -0.83 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2020-11-24", + "Correlation": -0.53 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2020-12-21", + "Correlation": 0.65 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2021-01-18", + "Correlation": -1 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2021-02-14", + "Correlation": -0.32 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2021-03-14", + "Correlation": -0.17 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2021-04-10", + "Correlation": -0.17 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2021-05-07", + "Correlation": -0.1 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2021-06-04", + "Correlation": -0.8 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2021-07-01", + "Correlation": 0.41 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2021-07-28", + "Correlation": 0.91 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2021-08-25", + "Correlation": 0.16 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2021-09-21", + "Correlation": 0.12 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2021-10-19", + "Correlation": -0.82 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2021-11-15", + "Correlation": 0.65 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2021-12-12", + "Correlation": 0.41 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2022-01-09", + "Correlation": -0.03 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2022-02-05", + "Correlation": 0.9 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2022-03-04", + "Correlation": -0.23 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2022-04-01", + "Correlation": -0.94 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2022-04-28", + "Correlation": -0.44 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2022-05-26", + "Correlation": 0.17 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2022-06-22", + "Correlation": 0.86 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2022-07-19", + "Correlation": 0.74 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2022-08-16", + "Correlation": 0.93 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2022-09-12", + "Correlation": -0.32 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2022-10-09", + "Correlation": 0.88 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2022-11-06", + "Correlation": 0.75 + }, + { + "StartDate": "2020-09-12", + "EndDate": "2022-12-03", + "Correlation": 0.81 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2020-01-01", + "Correlation": 0.97 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2020-01-28", + "Correlation": 0.59 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2020-02-24", + "Correlation": -0.88 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2020-03-23", + "Correlation": -0.4 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2020-04-19", + "Correlation": -0.78 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2020-05-16", + "Correlation": -0.01 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2020-06-13", + "Correlation": -0.58 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2020-07-10", + "Correlation": -0.33 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2020-08-07", + "Correlation": -0.5 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2020-09-03", + "Correlation": -0.3 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2020-09-30", + "Correlation": -0.86 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2020-10-28", + "Correlation": -0.16 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2020-11-24", + "Correlation": -0.12 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2020-12-21", + "Correlation": 0.19 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2021-01-18", + "Correlation": -0.28 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2021-02-14", + "Correlation": -0.06 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2021-03-14", + "Correlation": 0.37 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2021-04-10", + "Correlation": -0.46 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2021-05-07", + "Correlation": -0.83 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2021-06-04", + "Correlation": 0.65 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2021-07-01", + "Correlation": -0.13 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2021-07-28", + "Correlation": 0.32 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2021-08-25", + "Correlation": 0.58 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2021-09-21", + "Correlation": -0.41 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2021-10-19", + "Correlation": -0.49 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2021-11-15", + "Correlation": -0.62 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2021-12-12", + "Correlation": -0.03 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2022-01-09", + "Correlation": -0.72 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2022-02-05", + "Correlation": 0.09 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2022-03-04", + "Correlation": 0.01 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2022-04-01", + "Correlation": 0.2 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2022-04-28", + "Correlation": -0.69 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2022-05-26", + "Correlation": -0.76 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2022-06-22", + "Correlation": -0.47 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2022-07-19", + "Correlation": 0.31 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2022-08-16", + "Correlation": 0.99 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2022-09-12", + "Correlation": -0.65 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2022-10-09", + "Correlation": 0.11 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2022-11-06", + "Correlation": -0.3 + }, + { + "StartDate": "2020-09-30", + "EndDate": "2022-12-03", + "Correlation": 0.93 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2020-01-01", + "Correlation": 0.4 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2020-01-28", + "Correlation": -0.51 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2020-02-24", + "Correlation": -0.72 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2020-03-23", + "Correlation": 0.41 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2020-04-19", + "Correlation": 0.86 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2020-05-16", + "Correlation": 0.88 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2020-06-13", + "Correlation": -0.64 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2020-07-10", + "Correlation": -0.94 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2020-08-07", + "Correlation": -0.2 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2020-09-03", + "Correlation": 0.79 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2020-09-30", + "Correlation": 0.23 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2020-10-28", + "Correlation": -0.81 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2020-11-24", + "Correlation": 0.75 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2020-12-21", + "Correlation": 0.5 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2021-01-18", + "Correlation": 0.09 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2021-02-14", + "Correlation": 0.56 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2021-03-14", + "Correlation": -0.43 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2021-04-10", + "Correlation": 0.14 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2021-05-07", + "Correlation": 0.21 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2021-06-04", + "Correlation": 0.34 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2021-07-01", + "Correlation": 0.51 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2021-07-28", + "Correlation": -0.17 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2021-08-25", + "Correlation": 0.21 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2021-09-21", + "Correlation": -0.35 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2021-10-19", + "Correlation": 0.82 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2021-11-15", + "Correlation": -0.49 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2021-12-12", + "Correlation": -0.51 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2022-01-09", + "Correlation": 0.05 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2022-02-05", + "Correlation": 0.36 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2022-03-04", + "Correlation": -0.08 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2022-04-01", + "Correlation": -0.76 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2022-04-28", + "Correlation": -0.79 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2022-05-26", + "Correlation": 0.75 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2022-06-22", + "Correlation": -0.7 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2022-07-19", + "Correlation": 0.72 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2022-08-16", + "Correlation": 0.74 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2022-09-12", + "Correlation": -0.7 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2022-10-09", + "Correlation": 0.1 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2022-11-06", + "Correlation": -0.8 + }, + { + "StartDate": "2020-10-19", + "EndDate": "2022-12-03", + "Correlation": -0.37 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2020-01-01", + "Correlation": -0.9 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2020-01-28", + "Correlation": -0.19 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2020-02-24", + "Correlation": -0.08 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2020-03-23", + "Correlation": -0.17 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2020-04-19", + "Correlation": -0.24 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2020-05-16", + "Correlation": -0.87 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2020-06-13", + "Correlation": -0.2 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2020-07-10", + "Correlation": 0.07 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2020-08-07", + "Correlation": 0.56 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2020-09-03", + "Correlation": -0.51 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2020-09-30", + "Correlation": -0.41 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2020-10-28", + "Correlation": -0.67 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2020-11-24", + "Correlation": 0.8 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2020-12-21", + "Correlation": 0.34 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2021-01-18", + "Correlation": 0.2 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2021-02-14", + "Correlation": 0.28 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2021-03-14", + "Correlation": 0.77 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2021-04-10", + "Correlation": -0.86 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2021-05-07", + "Correlation": 0.85 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2021-06-04", + "Correlation": -0.35 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2021-07-01", + "Correlation": 0.25 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2021-07-28", + "Correlation": -0.04 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2021-08-25", + "Correlation": 0.49 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2021-09-21", + "Correlation": -0.65 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2021-10-19", + "Correlation": 0.68 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2021-11-15", + "Correlation": 0.44 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2021-12-12", + "Correlation": 0.47 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2022-01-09", + "Correlation": -0.31 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2022-02-05", + "Correlation": 0.62 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2022-03-04", + "Correlation": 0.35 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2022-04-01", + "Correlation": -0.02 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2022-04-28", + "Correlation": -0.27 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2022-05-26", + "Correlation": -0.65 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2022-06-22", + "Correlation": -0.83 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2022-07-19", + "Correlation": 0.87 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2022-08-16", + "Correlation": 0.84 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2022-09-12", + "Correlation": 0.7 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2022-10-09", + "Correlation": 0.8 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2022-11-06", + "Correlation": -0.76 + }, + { + "StartDate": "2020-11-06", + "EndDate": "2022-12-03", + "Correlation": -0.54 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2020-01-01", + "Correlation": 0.14 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2020-01-28", + "Correlation": 0.11 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2020-02-24", + "Correlation": -0.52 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2020-03-23", + "Correlation": -0.86 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2020-04-19", + "Correlation": -0.55 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2020-05-16", + "Correlation": 0.62 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2020-06-13", + "Correlation": 0.74 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2020-07-10", + "Correlation": 0.98 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2020-08-07", + "Correlation": 0.16 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2020-09-03", + "Correlation": 0.66 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2020-09-30", + "Correlation": 0.29 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2020-10-28", + "Correlation": -0.42 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2020-11-24", + "Correlation": -0.1 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2020-12-21", + "Correlation": -0.42 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2021-01-18", + "Correlation": -0.4 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2021-02-14", + "Correlation": 0.56 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2021-03-14", + "Correlation": -0.86 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2021-04-10", + "Correlation": -0.62 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2021-05-07", + "Correlation": 0.58 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2021-06-04", + "Correlation": -0.4 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2021-07-01", + "Correlation": -0.46 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2021-07-28", + "Correlation": 0.4 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2021-08-25", + "Correlation": 0.92 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2021-09-21", + "Correlation": 0.59 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2021-10-19", + "Correlation": -0.49 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2021-11-15", + "Correlation": 0.77 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2021-12-12", + "Correlation": 0.66 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2022-01-09", + "Correlation": -0.26 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2022-02-05", + "Correlation": 0.07 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2022-03-04", + "Correlation": -0.94 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2022-04-01", + "Correlation": 0.13 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2022-04-28", + "Correlation": -0.03 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2022-05-26", + "Correlation": 0.3 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2022-06-22", + "Correlation": -0.86 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2022-07-19", + "Correlation": -0.84 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2022-08-16", + "Correlation": 0.53 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2022-09-12", + "Correlation": 0.44 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2022-10-09", + "Correlation": 0.85 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2022-11-06", + "Correlation": -0.15 + }, + { + "StartDate": "2020-11-24", + "EndDate": "2022-12-03", + "Correlation": 0.8 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2020-01-01", + "Correlation": 0.74 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2020-01-28", + "Correlation": 0.42 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2020-02-24", + "Correlation": 0.83 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2020-03-23", + "Correlation": 0.45 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2020-04-19", + "Correlation": -0.04 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2020-05-16", + "Correlation": 0.26 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2020-06-13", + "Correlation": -0.38 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2020-07-10", + "Correlation": 0.29 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2020-08-07", + "Correlation": 0.42 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2020-09-03", + "Correlation": -0.63 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2020-09-30", + "Correlation": -1 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2020-10-28", + "Correlation": -0.26 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2020-11-24", + "Correlation": -0.11 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2020-12-21", + "Correlation": 0.5 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2021-01-18", + "Correlation": 0.53 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2021-02-14", + "Correlation": 0.43 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2021-03-14", + "Correlation": 0.89 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2021-04-10", + "Correlation": -0.46 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2021-05-07", + "Correlation": -0.01 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2021-06-04", + "Correlation": 0.71 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2021-07-01", + "Correlation": 0.27 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2021-07-28", + "Correlation": 0.42 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2021-08-25", + "Correlation": -0.49 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2021-09-21", + "Correlation": -0.34 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2021-10-19", + "Correlation": 0.45 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2021-11-15", + "Correlation": -0.65 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2021-12-12", + "Correlation": -0.19 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2022-01-09", + "Correlation": 0.76 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2022-02-05", + "Correlation": 0.32 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2022-03-04", + "Correlation": -0.27 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2022-04-01", + "Correlation": 0.67 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2022-04-28", + "Correlation": 0.36 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2022-05-26", + "Correlation": 0.85 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2022-06-22", + "Correlation": -0.33 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2022-07-19", + "Correlation": -0.42 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2022-08-16", + "Correlation": -0.84 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2022-09-12", + "Correlation": 0.42 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2022-10-09", + "Correlation": 0.02 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2022-11-06", + "Correlation": 0.6 + }, + { + "StartDate": "2020-12-12", + "EndDate": "2022-12-03", + "Correlation": 0.4 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/heatmap/07-card80.flint.json b/test-harness/excel/evaluations/inputs/heatmap/07-card80.flint.json new file mode 100644 index 00000000..f6a56785 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/heatmap/07-card80.flint.json @@ -0,0 +1,2023 @@ +{ + "semantic_types": { + "Category": "Category", + "Group": "Category", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Heatmap", + "encodings": { + "x": "Category", + "y": "Group", + "color": "Value" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "C01", + "Group": "Electronics", + "Value": 84 + }, + { + "Category": "C01", + "Group": "Clothing", + "Value": 87 + }, + { + "Category": "C01", + "Group": "Food", + "Value": 66 + }, + { + "Category": "C01", + "Group": "Books", + "Value": 17 + }, + { + "Category": "C01", + "Group": "Sports", + "Value": 3 + }, + { + "Category": "C02", + "Group": "Electronics", + "Value": 35 + }, + { + "Category": "C02", + "Group": "Clothing", + "Value": 43 + }, + { + "Category": "C02", + "Group": "Food", + "Value": 39 + }, + { + "Category": "C02", + "Group": "Books", + "Value": 8 + }, + { + "Category": "C02", + "Group": "Sports", + "Value": 20 + }, + { + "Category": "C03", + "Group": "Electronics", + "Value": 26 + }, + { + "Category": "C03", + "Group": "Clothing", + "Value": 41 + }, + { + "Category": "C03", + "Group": "Food", + "Value": 43 + }, + { + "Category": "C03", + "Group": "Books", + "Value": 42 + }, + { + "Category": "C03", + "Group": "Sports", + "Value": 86 + }, + { + "Category": "C04", + "Group": "Electronics", + "Value": 9 + }, + { + "Category": "C04", + "Group": "Clothing", + "Value": 6 + }, + { + "Category": "C04", + "Group": "Food", + "Value": 34 + }, + { + "Category": "C04", + "Group": "Books", + "Value": 52 + }, + { + "Category": "C04", + "Group": "Sports", + "Value": 46 + }, + { + "Category": "C05", + "Group": "Electronics", + "Value": 35 + }, + { + "Category": "C05", + "Group": "Clothing", + "Value": 83 + }, + { + "Category": "C05", + "Group": "Food", + "Value": 57 + }, + { + "Category": "C05", + "Group": "Books", + "Value": 94 + }, + { + "Category": "C05", + "Group": "Sports", + "Value": 53 + }, + { + "Category": "C06", + "Group": "Electronics", + "Value": 80 + }, + { + "Category": "C06", + "Group": "Clothing", + "Value": 54 + }, + { + "Category": "C06", + "Group": "Food", + "Value": 31 + }, + { + "Category": "C06", + "Group": "Books", + "Value": 2 + }, + { + "Category": "C06", + "Group": "Sports", + "Value": 20 + }, + { + "Category": "C07", + "Group": "Electronics", + "Value": 15 + }, + { + "Category": "C07", + "Group": "Clothing", + "Value": 82 + }, + { + "Category": "C07", + "Group": "Food", + "Value": 25 + }, + { + "Category": "C07", + "Group": "Books", + "Value": 26 + }, + { + "Category": "C07", + "Group": "Sports", + "Value": 38 + }, + { + "Category": "C08", + "Group": "Electronics", + "Value": 83 + }, + { + "Category": "C08", + "Group": "Clothing", + "Value": 54 + }, + { + "Category": "C08", + "Group": "Food", + "Value": 74 + }, + { + "Category": "C08", + "Group": "Books", + "Value": 77 + }, + { + "Category": "C08", + "Group": "Sports", + "Value": 59 + }, + { + "Category": "C09", + "Group": "Electronics", + "Value": 40 + }, + { + "Category": "C09", + "Group": "Clothing", + "Value": 51 + }, + { + "Category": "C09", + "Group": "Food", + "Value": 67 + }, + { + "Category": "C09", + "Group": "Books", + "Value": 76 + }, + { + "Category": "C09", + "Group": "Sports", + "Value": 81 + }, + { + "Category": "C10", + "Group": "Electronics", + "Value": 82 + }, + { + "Category": "C10", + "Group": "Clothing", + "Value": 96 + }, + { + "Category": "C10", + "Group": "Food", + "Value": 76 + }, + { + "Category": "C10", + "Group": "Books", + "Value": 6 + }, + { + "Category": "C10", + "Group": "Sports", + "Value": 12 + }, + { + "Category": "C11", + "Group": "Electronics", + "Value": 26 + }, + { + "Category": "C11", + "Group": "Clothing", + "Value": 9 + }, + { + "Category": "C11", + "Group": "Food", + "Value": 63 + }, + { + "Category": "C11", + "Group": "Books", + "Value": 94 + }, + { + "Category": "C11", + "Group": "Sports", + "Value": 41 + }, + { + "Category": "C12", + "Group": "Electronics", + "Value": 50 + }, + { + "Category": "C12", + "Group": "Clothing", + "Value": 20 + }, + { + "Category": "C12", + "Group": "Food", + "Value": 44 + }, + { + "Category": "C12", + "Group": "Books", + "Value": 98 + }, + { + "Category": "C12", + "Group": "Sports", + "Value": 76 + }, + { + "Category": "C13", + "Group": "Electronics", + "Value": 36 + }, + { + "Category": "C13", + "Group": "Clothing", + "Value": 58 + }, + { + "Category": "C13", + "Group": "Food", + "Value": 63 + }, + { + "Category": "C13", + "Group": "Books", + "Value": 22 + }, + { + "Category": "C13", + "Group": "Sports", + "Value": 65 + }, + { + "Category": "C14", + "Group": "Electronics", + "Value": 62 + }, + { + "Category": "C14", + "Group": "Clothing", + "Value": 24 + }, + { + "Category": "C14", + "Group": "Food", + "Value": 31 + }, + { + "Category": "C14", + "Group": "Books", + "Value": 29 + }, + { + "Category": "C14", + "Group": "Sports", + "Value": 10 + }, + { + "Category": "C15", + "Group": "Electronics", + "Value": 49 + }, + { + "Category": "C15", + "Group": "Clothing", + "Value": 23 + }, + { + "Category": "C15", + "Group": "Food", + "Value": 50 + }, + { + "Category": "C15", + "Group": "Books", + "Value": 17 + }, + { + "Category": "C15", + "Group": "Sports", + "Value": 41 + }, + { + "Category": "C16", + "Group": "Electronics", + "Value": 84 + }, + { + "Category": "C16", + "Group": "Clothing", + "Value": 85 + }, + { + "Category": "C16", + "Group": "Food", + "Value": 25 + }, + { + "Category": "C16", + "Group": "Books", + "Value": 91 + }, + { + "Category": "C16", + "Group": "Sports", + "Value": 21 + }, + { + "Category": "C17", + "Group": "Electronics", + "Value": 95 + }, + { + "Category": "C17", + "Group": "Clothing", + "Value": 50 + }, + { + "Category": "C17", + "Group": "Food", + "Value": 86 + }, + { + "Category": "C17", + "Group": "Books", + "Value": 56 + }, + { + "Category": "C17", + "Group": "Sports", + "Value": 71 + }, + { + "Category": "C18", + "Group": "Electronics", + "Value": 59 + }, + { + "Category": "C18", + "Group": "Clothing", + "Value": 83 + }, + { + "Category": "C18", + "Group": "Food", + "Value": 2 + }, + { + "Category": "C18", + "Group": "Books", + "Value": 44 + }, + { + "Category": "C18", + "Group": "Sports", + "Value": 45 + }, + { + "Category": "C19", + "Group": "Electronics", + "Value": 57 + }, + { + "Category": "C19", + "Group": "Clothing", + "Value": 31 + }, + { + "Category": "C19", + "Group": "Food", + "Value": 14 + }, + { + "Category": "C19", + "Group": "Books", + "Value": 42 + }, + { + "Category": "C19", + "Group": "Sports", + "Value": 9 + }, + { + "Category": "C20", + "Group": "Electronics", + "Value": 99 + }, + { + "Category": "C20", + "Group": "Clothing", + "Value": 10 + }, + { + "Category": "C20", + "Group": "Food", + "Value": 74 + }, + { + "Category": "C20", + "Group": "Books", + "Value": 76 + }, + { + "Category": "C20", + "Group": "Sports", + "Value": 71 + }, + { + "Category": "C21", + "Group": "Electronics", + "Value": 87 + }, + { + "Category": "C21", + "Group": "Clothing", + "Value": 12 + }, + { + "Category": "C21", + "Group": "Food", + "Value": 69 + }, + { + "Category": "C21", + "Group": "Books", + "Value": 81 + }, + { + "Category": "C21", + "Group": "Sports", + "Value": 22 + }, + { + "Category": "C22", + "Group": "Electronics", + "Value": 99 + }, + { + "Category": "C22", + "Group": "Clothing", + "Value": 8 + }, + { + "Category": "C22", + "Group": "Food", + "Value": 22 + }, + { + "Category": "C22", + "Group": "Books", + "Value": 18 + }, + { + "Category": "C22", + "Group": "Sports", + "Value": 41 + }, + { + "Category": "C23", + "Group": "Electronics", + "Value": 87 + }, + { + "Category": "C23", + "Group": "Clothing", + "Value": 66 + }, + { + "Category": "C23", + "Group": "Food", + "Value": 62 + }, + { + "Category": "C23", + "Group": "Books", + "Value": 13 + }, + { + "Category": "C23", + "Group": "Sports", + "Value": 63 + }, + { + "Category": "C24", + "Group": "Electronics", + "Value": 78 + }, + { + "Category": "C24", + "Group": "Clothing", + "Value": 93 + }, + { + "Category": "C24", + "Group": "Food", + "Value": 10 + }, + { + "Category": "C24", + "Group": "Books", + "Value": 94 + }, + { + "Category": "C24", + "Group": "Sports", + "Value": 21 + }, + { + "Category": "C25", + "Group": "Electronics", + "Value": 83 + }, + { + "Category": "C25", + "Group": "Clothing", + "Value": 94 + }, + { + "Category": "C25", + "Group": "Food", + "Value": 79 + }, + { + "Category": "C25", + "Group": "Books", + "Value": 24 + }, + { + "Category": "C25", + "Group": "Sports", + "Value": 18 + }, + { + "Category": "C26", + "Group": "Electronics", + "Value": 78 + }, + { + "Category": "C26", + "Group": "Clothing", + "Value": 98 + }, + { + "Category": "C26", + "Group": "Food", + "Value": 80 + }, + { + "Category": "C26", + "Group": "Books", + "Value": 54 + }, + { + "Category": "C26", + "Group": "Sports", + "Value": 64 + }, + { + "Category": "C27", + "Group": "Electronics", + "Value": 35 + }, + { + "Category": "C27", + "Group": "Clothing", + "Value": 88 + }, + { + "Category": "C27", + "Group": "Food", + "Value": 51 + }, + { + "Category": "C27", + "Group": "Books", + "Value": 25 + }, + { + "Category": "C27", + "Group": "Sports", + "Value": 29 + }, + { + "Category": "C28", + "Group": "Electronics", + "Value": 96 + }, + { + "Category": "C28", + "Group": "Clothing", + "Value": 68 + }, + { + "Category": "C28", + "Group": "Food", + "Value": 22 + }, + { + "Category": "C28", + "Group": "Books", + "Value": 91 + }, + { + "Category": "C28", + "Group": "Sports", + "Value": 76 + }, + { + "Category": "C29", + "Group": "Electronics", + "Value": 52 + }, + { + "Category": "C29", + "Group": "Clothing", + "Value": 18 + }, + { + "Category": "C29", + "Group": "Food", + "Value": 61 + }, + { + "Category": "C29", + "Group": "Books", + "Value": 41 + }, + { + "Category": "C29", + "Group": "Sports", + "Value": 67 + }, + { + "Category": "C30", + "Group": "Electronics", + "Value": 63 + }, + { + "Category": "C30", + "Group": "Clothing", + "Value": 55 + }, + { + "Category": "C30", + "Group": "Food", + "Value": 93 + }, + { + "Category": "C30", + "Group": "Books", + "Value": 41 + }, + { + "Category": "C30", + "Group": "Sports", + "Value": 33 + }, + { + "Category": "C31", + "Group": "Electronics", + "Value": 97 + }, + { + "Category": "C31", + "Group": "Clothing", + "Value": 59 + }, + { + "Category": "C31", + "Group": "Food", + "Value": 44 + }, + { + "Category": "C31", + "Group": "Books", + "Value": 32 + }, + { + "Category": "C31", + "Group": "Sports", + "Value": 84 + }, + { + "Category": "C32", + "Group": "Electronics", + "Value": 85 + }, + { + "Category": "C32", + "Group": "Clothing", + "Value": 67 + }, + { + "Category": "C32", + "Group": "Food", + "Value": 74 + }, + { + "Category": "C32", + "Group": "Books", + "Value": 25 + }, + { + "Category": "C32", + "Group": "Sports", + "Value": 72 + }, + { + "Category": "C33", + "Group": "Electronics", + "Value": 87 + }, + { + "Category": "C33", + "Group": "Clothing", + "Value": 1 + }, + { + "Category": "C33", + "Group": "Food", + "Value": 57 + }, + { + "Category": "C33", + "Group": "Books", + "Value": 87 + }, + { + "Category": "C33", + "Group": "Sports", + "Value": 74 + }, + { + "Category": "C34", + "Group": "Electronics", + "Value": 63 + }, + { + "Category": "C34", + "Group": "Clothing", + "Value": 66 + }, + { + "Category": "C34", + "Group": "Food", + "Value": 29 + }, + { + "Category": "C34", + "Group": "Books", + "Value": 89 + }, + { + "Category": "C34", + "Group": "Sports", + "Value": 10 + }, + { + "Category": "C35", + "Group": "Electronics", + "Value": 75 + }, + { + "Category": "C35", + "Group": "Clothing", + "Value": 21 + }, + { + "Category": "C35", + "Group": "Food", + "Value": 82 + }, + { + "Category": "C35", + "Group": "Books", + "Value": 54 + }, + { + "Category": "C35", + "Group": "Sports", + "Value": 65 + }, + { + "Category": "C36", + "Group": "Electronics", + "Value": 30 + }, + { + "Category": "C36", + "Group": "Clothing", + "Value": 51 + }, + { + "Category": "C36", + "Group": "Food", + "Value": 33 + }, + { + "Category": "C36", + "Group": "Books", + "Value": 58 + }, + { + "Category": "C36", + "Group": "Sports", + "Value": 32 + }, + { + "Category": "C37", + "Group": "Electronics", + "Value": 58 + }, + { + "Category": "C37", + "Group": "Clothing", + "Value": 75 + }, + { + "Category": "C37", + "Group": "Food", + "Value": 11 + }, + { + "Category": "C37", + "Group": "Books", + "Value": 63 + }, + { + "Category": "C37", + "Group": "Sports", + "Value": 85 + }, + { + "Category": "C38", + "Group": "Electronics", + "Value": 93 + }, + { + "Category": "C38", + "Group": "Clothing", + "Value": 32 + }, + { + "Category": "C38", + "Group": "Food", + "Value": 48 + }, + { + "Category": "C38", + "Group": "Books", + "Value": 11 + }, + { + "Category": "C38", + "Group": "Sports", + "Value": 95 + }, + { + "Category": "C39", + "Group": "Electronics", + "Value": 57 + }, + { + "Category": "C39", + "Group": "Clothing", + "Value": 13 + }, + { + "Category": "C39", + "Group": "Food", + "Value": 60 + }, + { + "Category": "C39", + "Group": "Books", + "Value": 86 + }, + { + "Category": "C39", + "Group": "Sports", + "Value": 21 + }, + { + "Category": "C40", + "Group": "Electronics", + "Value": 41 + }, + { + "Category": "C40", + "Group": "Clothing", + "Value": 68 + }, + { + "Category": "C40", + "Group": "Food", + "Value": 34 + }, + { + "Category": "C40", + "Group": "Books", + "Value": 33 + }, + { + "Category": "C40", + "Group": "Sports", + "Value": 40 + }, + { + "Category": "C41", + "Group": "Electronics", + "Value": 16 + }, + { + "Category": "C41", + "Group": "Clothing", + "Value": 3 + }, + { + "Category": "C41", + "Group": "Food", + "Value": 66 + }, + { + "Category": "C41", + "Group": "Books", + "Value": 14 + }, + { + "Category": "C41", + "Group": "Sports", + "Value": 76 + }, + { + "Category": "C42", + "Group": "Electronics", + "Value": 8 + }, + { + "Category": "C42", + "Group": "Clothing", + "Value": 99 + }, + { + "Category": "C42", + "Group": "Food", + "Value": 50 + }, + { + "Category": "C42", + "Group": "Books", + "Value": 71 + }, + { + "Category": "C42", + "Group": "Sports", + "Value": 3 + }, + { + "Category": "C43", + "Group": "Electronics", + "Value": 54 + }, + { + "Category": "C43", + "Group": "Clothing", + "Value": 54 + }, + { + "Category": "C43", + "Group": "Food", + "Value": 79 + }, + { + "Category": "C43", + "Group": "Books", + "Value": 66 + }, + { + "Category": "C43", + "Group": "Sports", + "Value": 66 + }, + { + "Category": "C44", + "Group": "Electronics", + "Value": 26 + }, + { + "Category": "C44", + "Group": "Clothing", + "Value": 24 + }, + { + "Category": "C44", + "Group": "Food", + "Value": 3 + }, + { + "Category": "C44", + "Group": "Books", + "Value": 84 + }, + { + "Category": "C44", + "Group": "Sports", + "Value": 23 + }, + { + "Category": "C45", + "Group": "Electronics", + "Value": 19 + }, + { + "Category": "C45", + "Group": "Clothing", + "Value": 31 + }, + { + "Category": "C45", + "Group": "Food", + "Value": 43 + }, + { + "Category": "C45", + "Group": "Books", + "Value": 3 + }, + { + "Category": "C45", + "Group": "Sports", + "Value": 13 + }, + { + "Category": "C46", + "Group": "Electronics", + "Value": 11 + }, + { + "Category": "C46", + "Group": "Clothing", + "Value": 18 + }, + { + "Category": "C46", + "Group": "Food", + "Value": 61 + }, + { + "Category": "C46", + "Group": "Books", + "Value": 93 + }, + { + "Category": "C46", + "Group": "Sports", + "Value": 52 + }, + { + "Category": "C47", + "Group": "Electronics", + "Value": 85 + }, + { + "Category": "C47", + "Group": "Clothing", + "Value": 41 + }, + { + "Category": "C47", + "Group": "Food", + "Value": 0 + }, + { + "Category": "C47", + "Group": "Books", + "Value": 59 + }, + { + "Category": "C47", + "Group": "Sports", + "Value": 38 + }, + { + "Category": "C48", + "Group": "Electronics", + "Value": 25 + }, + { + "Category": "C48", + "Group": "Clothing", + "Value": 33 + }, + { + "Category": "C48", + "Group": "Food", + "Value": 28 + }, + { + "Category": "C48", + "Group": "Books", + "Value": 73 + }, + { + "Category": "C48", + "Group": "Sports", + "Value": 52 + }, + { + "Category": "C49", + "Group": "Electronics", + "Value": 68 + }, + { + "Category": "C49", + "Group": "Clothing", + "Value": 8 + }, + { + "Category": "C49", + "Group": "Food", + "Value": 19 + }, + { + "Category": "C49", + "Group": "Books", + "Value": 29 + }, + { + "Category": "C49", + "Group": "Sports", + "Value": 65 + }, + { + "Category": "C50", + "Group": "Electronics", + "Value": 2 + }, + { + "Category": "C50", + "Group": "Clothing", + "Value": 9 + }, + { + "Category": "C50", + "Group": "Food", + "Value": 97 + }, + { + "Category": "C50", + "Group": "Books", + "Value": 86 + }, + { + "Category": "C50", + "Group": "Sports", + "Value": 96 + }, + { + "Category": "C51", + "Group": "Electronics", + "Value": 63 + }, + { + "Category": "C51", + "Group": "Clothing", + "Value": 84 + }, + { + "Category": "C51", + "Group": "Food", + "Value": 44 + }, + { + "Category": "C51", + "Group": "Books", + "Value": 11 + }, + { + "Category": "C51", + "Group": "Sports", + "Value": 38 + }, + { + "Category": "C52", + "Group": "Electronics", + "Value": 17 + }, + { + "Category": "C52", + "Group": "Clothing", + "Value": 54 + }, + { + "Category": "C52", + "Group": "Food", + "Value": 58 + }, + { + "Category": "C52", + "Group": "Books", + "Value": 72 + }, + { + "Category": "C52", + "Group": "Sports", + "Value": 54 + }, + { + "Category": "C53", + "Group": "Electronics", + "Value": 41 + }, + { + "Category": "C53", + "Group": "Clothing", + "Value": 50 + }, + { + "Category": "C53", + "Group": "Food", + "Value": 62 + }, + { + "Category": "C53", + "Group": "Books", + "Value": 76 + }, + { + "Category": "C53", + "Group": "Sports", + "Value": 17 + }, + { + "Category": "C54", + "Group": "Electronics", + "Value": 65 + }, + { + "Category": "C54", + "Group": "Clothing", + "Value": 8 + }, + { + "Category": "C54", + "Group": "Food", + "Value": 40 + }, + { + "Category": "C54", + "Group": "Books", + "Value": 41 + }, + { + "Category": "C54", + "Group": "Sports", + "Value": 9 + }, + { + "Category": "C55", + "Group": "Electronics", + "Value": 28 + }, + { + "Category": "C55", + "Group": "Clothing", + "Value": 77 + }, + { + "Category": "C55", + "Group": "Food", + "Value": 74 + }, + { + "Category": "C55", + "Group": "Books", + "Value": 22 + }, + { + "Category": "C55", + "Group": "Sports", + "Value": 47 + }, + { + "Category": "C56", + "Group": "Electronics", + "Value": 85 + }, + { + "Category": "C56", + "Group": "Clothing", + "Value": 90 + }, + { + "Category": "C56", + "Group": "Food", + "Value": 76 + }, + { + "Category": "C56", + "Group": "Books", + "Value": 78 + }, + { + "Category": "C56", + "Group": "Sports", + "Value": 5 + }, + { + "Category": "C57", + "Group": "Electronics", + "Value": 57 + }, + { + "Category": "C57", + "Group": "Clothing", + "Value": 99 + }, + { + "Category": "C57", + "Group": "Food", + "Value": 10 + }, + { + "Category": "C57", + "Group": "Books", + "Value": 20 + }, + { + "Category": "C57", + "Group": "Sports", + "Value": 41 + }, + { + "Category": "C58", + "Group": "Electronics", + "Value": 9 + }, + { + "Category": "C58", + "Group": "Clothing", + "Value": 92 + }, + { + "Category": "C58", + "Group": "Food", + "Value": 54 + }, + { + "Category": "C58", + "Group": "Books", + "Value": 89 + }, + { + "Category": "C58", + "Group": "Sports", + "Value": 95 + }, + { + "Category": "C59", + "Group": "Electronics", + "Value": 74 + }, + { + "Category": "C59", + "Group": "Clothing", + "Value": 35 + }, + { + "Category": "C59", + "Group": "Food", + "Value": 44 + }, + { + "Category": "C59", + "Group": "Books", + "Value": 69 + }, + { + "Category": "C59", + "Group": "Sports", + "Value": 80 + }, + { + "Category": "C60", + "Group": "Electronics", + "Value": 78 + }, + { + "Category": "C60", + "Group": "Clothing", + "Value": 83 + }, + { + "Category": "C60", + "Group": "Food", + "Value": 71 + }, + { + "Category": "C60", + "Group": "Books", + "Value": 39 + }, + { + "Category": "C60", + "Group": "Sports", + "Value": 48 + }, + { + "Category": "C61", + "Group": "Electronics", + "Value": 5 + }, + { + "Category": "C61", + "Group": "Clothing", + "Value": 74 + }, + { + "Category": "C61", + "Group": "Food", + "Value": 35 + }, + { + "Category": "C61", + "Group": "Books", + "Value": 53 + }, + { + "Category": "C61", + "Group": "Sports", + "Value": 45 + }, + { + "Category": "C62", + "Group": "Electronics", + "Value": 60 + }, + { + "Category": "C62", + "Group": "Clothing", + "Value": 26 + }, + { + "Category": "C62", + "Group": "Food", + "Value": 52 + }, + { + "Category": "C62", + "Group": "Books", + "Value": 52 + }, + { + "Category": "C62", + "Group": "Sports", + "Value": 20 + }, + { + "Category": "C63", + "Group": "Electronics", + "Value": 90 + }, + { + "Category": "C63", + "Group": "Clothing", + "Value": 53 + }, + { + "Category": "C63", + "Group": "Food", + "Value": 70 + }, + { + "Category": "C63", + "Group": "Books", + "Value": 1 + }, + { + "Category": "C63", + "Group": "Sports", + "Value": 55 + }, + { + "Category": "C64", + "Group": "Electronics", + "Value": 2 + }, + { + "Category": "C64", + "Group": "Clothing", + "Value": 55 + }, + { + "Category": "C64", + "Group": "Food", + "Value": 1 + }, + { + "Category": "C64", + "Group": "Books", + "Value": 93 + }, + { + "Category": "C64", + "Group": "Sports", + "Value": 26 + }, + { + "Category": "C65", + "Group": "Electronics", + "Value": 82 + }, + { + "Category": "C65", + "Group": "Clothing", + "Value": 81 + }, + { + "Category": "C65", + "Group": "Food", + "Value": 50 + }, + { + "Category": "C65", + "Group": "Books", + "Value": 43 + }, + { + "Category": "C65", + "Group": "Sports", + "Value": 63 + }, + { + "Category": "C66", + "Group": "Electronics", + "Value": 34 + }, + { + "Category": "C66", + "Group": "Clothing", + "Value": 69 + }, + { + "Category": "C66", + "Group": "Food", + "Value": 47 + }, + { + "Category": "C66", + "Group": "Books", + "Value": 92 + }, + { + "Category": "C66", + "Group": "Sports", + "Value": 49 + }, + { + "Category": "C67", + "Group": "Electronics", + "Value": 52 + }, + { + "Category": "C67", + "Group": "Clothing", + "Value": 99 + }, + { + "Category": "C67", + "Group": "Food", + "Value": 48 + }, + { + "Category": "C67", + "Group": "Books", + "Value": 14 + }, + { + "Category": "C67", + "Group": "Sports", + "Value": 52 + }, + { + "Category": "C68", + "Group": "Electronics", + "Value": 23 + }, + { + "Category": "C68", + "Group": "Clothing", + "Value": 11 + }, + { + "Category": "C68", + "Group": "Food", + "Value": 31 + }, + { + "Category": "C68", + "Group": "Books", + "Value": 13 + }, + { + "Category": "C68", + "Group": "Sports", + "Value": 56 + }, + { + "Category": "C69", + "Group": "Electronics", + "Value": 37 + }, + { + "Category": "C69", + "Group": "Clothing", + "Value": 58 + }, + { + "Category": "C69", + "Group": "Food", + "Value": 61 + }, + { + "Category": "C69", + "Group": "Books", + "Value": 21 + }, + { + "Category": "C69", + "Group": "Sports", + "Value": 23 + }, + { + "Category": "C70", + "Group": "Electronics", + "Value": 79 + }, + { + "Category": "C70", + "Group": "Clothing", + "Value": 46 + }, + { + "Category": "C70", + "Group": "Food", + "Value": 74 + }, + { + "Category": "C70", + "Group": "Books", + "Value": 15 + }, + { + "Category": "C70", + "Group": "Sports", + "Value": 70 + }, + { + "Category": "C71", + "Group": "Electronics", + "Value": 37 + }, + { + "Category": "C71", + "Group": "Clothing", + "Value": 62 + }, + { + "Category": "C71", + "Group": "Food", + "Value": 0 + }, + { + "Category": "C71", + "Group": "Books", + "Value": 52 + }, + { + "Category": "C71", + "Group": "Sports", + "Value": 44 + }, + { + "Category": "C72", + "Group": "Electronics", + "Value": 93 + }, + { + "Category": "C72", + "Group": "Clothing", + "Value": 33 + }, + { + "Category": "C72", + "Group": "Food", + "Value": 91 + }, + { + "Category": "C72", + "Group": "Books", + "Value": 47 + }, + { + "Category": "C72", + "Group": "Sports", + "Value": 95 + }, + { + "Category": "C73", + "Group": "Electronics", + "Value": 48 + }, + { + "Category": "C73", + "Group": "Clothing", + "Value": 16 + }, + { + "Category": "C73", + "Group": "Food", + "Value": 61 + }, + { + "Category": "C73", + "Group": "Books", + "Value": 97 + }, + { + "Category": "C73", + "Group": "Sports", + "Value": 59 + }, + { + "Category": "C74", + "Group": "Electronics", + "Value": 49 + }, + { + "Category": "C74", + "Group": "Clothing", + "Value": 85 + }, + { + "Category": "C74", + "Group": "Food", + "Value": 96 + }, + { + "Category": "C74", + "Group": "Books", + "Value": 70 + }, + { + "Category": "C74", + "Group": "Sports", + "Value": 85 + }, + { + "Category": "C75", + "Group": "Electronics", + "Value": 72 + }, + { + "Category": "C75", + "Group": "Clothing", + "Value": 14 + }, + { + "Category": "C75", + "Group": "Food", + "Value": 25 + }, + { + "Category": "C75", + "Group": "Books", + "Value": 73 + }, + { + "Category": "C75", + "Group": "Sports", + "Value": 35 + }, + { + "Category": "C76", + "Group": "Electronics", + "Value": 96 + }, + { + "Category": "C76", + "Group": "Clothing", + "Value": 8 + }, + { + "Category": "C76", + "Group": "Food", + "Value": 61 + }, + { + "Category": "C76", + "Group": "Books", + "Value": 50 + }, + { + "Category": "C76", + "Group": "Sports", + "Value": 73 + }, + { + "Category": "C77", + "Group": "Electronics", + "Value": 84 + }, + { + "Category": "C77", + "Group": "Clothing", + "Value": 8 + }, + { + "Category": "C77", + "Group": "Food", + "Value": 6 + }, + { + "Category": "C77", + "Group": "Books", + "Value": 69 + }, + { + "Category": "C77", + "Group": "Sports", + "Value": 86 + }, + { + "Category": "C78", + "Group": "Electronics", + "Value": 73 + }, + { + "Category": "C78", + "Group": "Clothing", + "Value": 18 + }, + { + "Category": "C78", + "Group": "Food", + "Value": 71 + }, + { + "Category": "C78", + "Group": "Books", + "Value": 19 + }, + { + "Category": "C78", + "Group": "Sports", + "Value": 43 + }, + { + "Category": "C79", + "Group": "Electronics", + "Value": 45 + }, + { + "Category": "C79", + "Group": "Clothing", + "Value": 16 + }, + { + "Category": "C79", + "Group": "Food", + "Value": 62 + }, + { + "Category": "C79", + "Group": "Books", + "Value": 47 + }, + { + "Category": "C79", + "Group": "Sports", + "Value": 91 + }, + { + "Category": "C80", + "Group": "Electronics", + "Value": 12 + }, + { + "Category": "C80", + "Group": "Clothing", + "Value": 66 + }, + { + "Category": "C80", + "Group": "Food", + "Value": 51 + }, + { + "Category": "C80", + "Group": "Books", + "Value": 56 + }, + { + "Category": "C80", + "Group": "Sports", + "Value": 2 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/heatmap/08-card5.flint.json b/test-harness/excel/evaluations/inputs/heatmap/08-card5.flint.json new file mode 100644 index 00000000..a28d63dc --- /dev/null +++ b/test-harness/excel/evaluations/inputs/heatmap/08-card5.flint.json @@ -0,0 +1,2023 @@ +{ + "semantic_types": { + "Group": "Category", + "Category": "Category", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Heatmap", + "encodings": { + "x": "Group", + "y": "Category", + "color": "Value" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Group": "Electronics", + "Category": "C01", + "Value": 97 + }, + { + "Group": "Electronics", + "Category": "C02", + "Value": 29 + }, + { + "Group": "Electronics", + "Category": "C03", + "Value": 93 + }, + { + "Group": "Electronics", + "Category": "C04", + "Value": 93 + }, + { + "Group": "Electronics", + "Category": "C05", + "Value": 88 + }, + { + "Group": "Electronics", + "Category": "C06", + "Value": 38 + }, + { + "Group": "Electronics", + "Category": "C07", + "Value": 99 + }, + { + "Group": "Electronics", + "Category": "C08", + "Value": 16 + }, + { + "Group": "Electronics", + "Category": "C09", + "Value": 84 + }, + { + "Group": "Electronics", + "Category": "C10", + "Value": 56 + }, + { + "Group": "Electronics", + "Category": "C11", + "Value": 38 + }, + { + "Group": "Electronics", + "Category": "C12", + "Value": 24 + }, + { + "Group": "Electronics", + "Category": "C13", + "Value": 85 + }, + { + "Group": "Electronics", + "Category": "C14", + "Value": 99 + }, + { + "Group": "Electronics", + "Category": "C15", + "Value": 3 + }, + { + "Group": "Electronics", + "Category": "C16", + "Value": 33 + }, + { + "Group": "Electronics", + "Category": "C17", + "Value": 8 + }, + { + "Group": "Electronics", + "Category": "C18", + "Value": 78 + }, + { + "Group": "Electronics", + "Category": "C19", + "Value": 31 + }, + { + "Group": "Electronics", + "Category": "C20", + "Value": 24 + }, + { + "Group": "Electronics", + "Category": "C21", + "Value": 36 + }, + { + "Group": "Electronics", + "Category": "C22", + "Value": 48 + }, + { + "Group": "Electronics", + "Category": "C23", + "Value": 48 + }, + { + "Group": "Electronics", + "Category": "C24", + "Value": 24 + }, + { + "Group": "Electronics", + "Category": "C25", + "Value": 15 + }, + { + "Group": "Electronics", + "Category": "C26", + "Value": 24 + }, + { + "Group": "Electronics", + "Category": "C27", + "Value": 66 + }, + { + "Group": "Electronics", + "Category": "C28", + "Value": 62 + }, + { + "Group": "Electronics", + "Category": "C29", + "Value": 28 + }, + { + "Group": "Electronics", + "Category": "C30", + "Value": 83 + }, + { + "Group": "Electronics", + "Category": "C31", + "Value": 91 + }, + { + "Group": "Electronics", + "Category": "C32", + "Value": 16 + }, + { + "Group": "Electronics", + "Category": "C33", + "Value": 97 + }, + { + "Group": "Electronics", + "Category": "C34", + "Value": 15 + }, + { + "Group": "Electronics", + "Category": "C35", + "Value": 6 + }, + { + "Group": "Electronics", + "Category": "C36", + "Value": 37 + }, + { + "Group": "Electronics", + "Category": "C37", + "Value": 4 + }, + { + "Group": "Electronics", + "Category": "C38", + "Value": 21 + }, + { + "Group": "Electronics", + "Category": "C39", + "Value": 58 + }, + { + "Group": "Electronics", + "Category": "C40", + "Value": 81 + }, + { + "Group": "Electronics", + "Category": "C41", + "Value": 69 + }, + { + "Group": "Electronics", + "Category": "C42", + "Value": 22 + }, + { + "Group": "Electronics", + "Category": "C43", + "Value": 48 + }, + { + "Group": "Electronics", + "Category": "C44", + "Value": 8 + }, + { + "Group": "Electronics", + "Category": "C45", + "Value": 91 + }, + { + "Group": "Electronics", + "Category": "C46", + "Value": 93 + }, + { + "Group": "Electronics", + "Category": "C47", + "Value": 20 + }, + { + "Group": "Electronics", + "Category": "C48", + "Value": 23 + }, + { + "Group": "Electronics", + "Category": "C49", + "Value": 28 + }, + { + "Group": "Electronics", + "Category": "C50", + "Value": 11 + }, + { + "Group": "Electronics", + "Category": "C51", + "Value": 23 + }, + { + "Group": "Electronics", + "Category": "C52", + "Value": 19 + }, + { + "Group": "Electronics", + "Category": "C53", + "Value": 10 + }, + { + "Group": "Electronics", + "Category": "C54", + "Value": 58 + }, + { + "Group": "Electronics", + "Category": "C55", + "Value": 50 + }, + { + "Group": "Electronics", + "Category": "C56", + "Value": 62 + }, + { + "Group": "Electronics", + "Category": "C57", + "Value": 85 + }, + { + "Group": "Electronics", + "Category": "C58", + "Value": 48 + }, + { + "Group": "Electronics", + "Category": "C59", + "Value": 88 + }, + { + "Group": "Electronics", + "Category": "C60", + "Value": 54 + }, + { + "Group": "Electronics", + "Category": "C61", + "Value": 70 + }, + { + "Group": "Electronics", + "Category": "C62", + "Value": 64 + }, + { + "Group": "Electronics", + "Category": "C63", + "Value": 38 + }, + { + "Group": "Electronics", + "Category": "C64", + "Value": 64 + }, + { + "Group": "Electronics", + "Category": "C65", + "Value": 32 + }, + { + "Group": "Electronics", + "Category": "C66", + "Value": 84 + }, + { + "Group": "Electronics", + "Category": "C67", + "Value": 11 + }, + { + "Group": "Electronics", + "Category": "C68", + "Value": 69 + }, + { + "Group": "Electronics", + "Category": "C69", + "Value": 13 + }, + { + "Group": "Electronics", + "Category": "C70", + "Value": 68 + }, + { + "Group": "Electronics", + "Category": "C71", + "Value": 12 + }, + { + "Group": "Electronics", + "Category": "C72", + "Value": 86 + }, + { + "Group": "Electronics", + "Category": "C73", + "Value": 17 + }, + { + "Group": "Electronics", + "Category": "C74", + "Value": 84 + }, + { + "Group": "Electronics", + "Category": "C75", + "Value": 78 + }, + { + "Group": "Electronics", + "Category": "C76", + "Value": 28 + }, + { + "Group": "Electronics", + "Category": "C77", + "Value": 74 + }, + { + "Group": "Electronics", + "Category": "C78", + "Value": 85 + }, + { + "Group": "Electronics", + "Category": "C79", + "Value": 3 + }, + { + "Group": "Electronics", + "Category": "C80", + "Value": 73 + }, + { + "Group": "Clothing", + "Category": "C01", + "Value": 79 + }, + { + "Group": "Clothing", + "Category": "C02", + "Value": 41 + }, + { + "Group": "Clothing", + "Category": "C03", + "Value": 29 + }, + { + "Group": "Clothing", + "Category": "C04", + "Value": 26 + }, + { + "Group": "Clothing", + "Category": "C05", + "Value": 74 + }, + { + "Group": "Clothing", + "Category": "C06", + "Value": 73 + }, + { + "Group": "Clothing", + "Category": "C07", + "Value": 30 + }, + { + "Group": "Clothing", + "Category": "C08", + "Value": 12 + }, + { + "Group": "Clothing", + "Category": "C09", + "Value": 43 + }, + { + "Group": "Clothing", + "Category": "C10", + "Value": 4 + }, + { + "Group": "Clothing", + "Category": "C11", + "Value": 62 + }, + { + "Group": "Clothing", + "Category": "C12", + "Value": 96 + }, + { + "Group": "Clothing", + "Category": "C13", + "Value": 69 + }, + { + "Group": "Clothing", + "Category": "C14", + "Value": 15 + }, + { + "Group": "Clothing", + "Category": "C15", + "Value": 38 + }, + { + "Group": "Clothing", + "Category": "C16", + "Value": 25 + }, + { + "Group": "Clothing", + "Category": "C17", + "Value": 65 + }, + { + "Group": "Clothing", + "Category": "C18", + "Value": 24 + }, + { + "Group": "Clothing", + "Category": "C19", + "Value": 37 + }, + { + "Group": "Clothing", + "Category": "C20", + "Value": 56 + }, + { + "Group": "Clothing", + "Category": "C21", + "Value": 8 + }, + { + "Group": "Clothing", + "Category": "C22", + "Value": 17 + }, + { + "Group": "Clothing", + "Category": "C23", + "Value": 4 + }, + { + "Group": "Clothing", + "Category": "C24", + "Value": 5 + }, + { + "Group": "Clothing", + "Category": "C25", + "Value": 66 + }, + { + "Group": "Clothing", + "Category": "C26", + "Value": 94 + }, + { + "Group": "Clothing", + "Category": "C27", + "Value": 46 + }, + { + "Group": "Clothing", + "Category": "C28", + "Value": 81 + }, + { + "Group": "Clothing", + "Category": "C29", + "Value": 25 + }, + { + "Group": "Clothing", + "Category": "C30", + "Value": 74 + }, + { + "Group": "Clothing", + "Category": "C31", + "Value": 93 + }, + { + "Group": "Clothing", + "Category": "C32", + "Value": 15 + }, + { + "Group": "Clothing", + "Category": "C33", + "Value": 41 + }, + { + "Group": "Clothing", + "Category": "C34", + "Value": 52 + }, + { + "Group": "Clothing", + "Category": "C35", + "Value": 89 + }, + { + "Group": "Clothing", + "Category": "C36", + "Value": 39 + }, + { + "Group": "Clothing", + "Category": "C37", + "Value": 9 + }, + { + "Group": "Clothing", + "Category": "C38", + "Value": 52 + }, + { + "Group": "Clothing", + "Category": "C39", + "Value": 95 + }, + { + "Group": "Clothing", + "Category": "C40", + "Value": 78 + }, + { + "Group": "Clothing", + "Category": "C41", + "Value": 84 + }, + { + "Group": "Clothing", + "Category": "C42", + "Value": 69 + }, + { + "Group": "Clothing", + "Category": "C43", + "Value": 78 + }, + { + "Group": "Clothing", + "Category": "C44", + "Value": 57 + }, + { + "Group": "Clothing", + "Category": "C45", + "Value": 23 + }, + { + "Group": "Clothing", + "Category": "C46", + "Value": 40 + }, + { + "Group": "Clothing", + "Category": "C47", + "Value": 93 + }, + { + "Group": "Clothing", + "Category": "C48", + "Value": 41 + }, + { + "Group": "Clothing", + "Category": "C49", + "Value": 79 + }, + { + "Group": "Clothing", + "Category": "C50", + "Value": 89 + }, + { + "Group": "Clothing", + "Category": "C51", + "Value": 87 + }, + { + "Group": "Clothing", + "Category": "C52", + "Value": 63 + }, + { + "Group": "Clothing", + "Category": "C53", + "Value": 77 + }, + { + "Group": "Clothing", + "Category": "C54", + "Value": 65 + }, + { + "Group": "Clothing", + "Category": "C55", + "Value": 98 + }, + { + "Group": "Clothing", + "Category": "C56", + "Value": 86 + }, + { + "Group": "Clothing", + "Category": "C57", + "Value": 72 + }, + { + "Group": "Clothing", + "Category": "C58", + "Value": 21 + }, + { + "Group": "Clothing", + "Category": "C59", + "Value": 6 + }, + { + "Group": "Clothing", + "Category": "C60", + "Value": 25 + }, + { + "Group": "Clothing", + "Category": "C61", + "Value": 93 + }, + { + "Group": "Clothing", + "Category": "C62", + "Value": 79 + }, + { + "Group": "Clothing", + "Category": "C63", + "Value": 27 + }, + { + "Group": "Clothing", + "Category": "C64", + "Value": 95 + }, + { + "Group": "Clothing", + "Category": "C65", + "Value": 78 + }, + { + "Group": "Clothing", + "Category": "C66", + "Value": 53 + }, + { + "Group": "Clothing", + "Category": "C67", + "Value": 35 + }, + { + "Group": "Clothing", + "Category": "C68", + "Value": 70 + }, + { + "Group": "Clothing", + "Category": "C69", + "Value": 63 + }, + { + "Group": "Clothing", + "Category": "C70", + "Value": 2 + }, + { + "Group": "Clothing", + "Category": "C71", + "Value": 95 + }, + { + "Group": "Clothing", + "Category": "C72", + "Value": 11 + }, + { + "Group": "Clothing", + "Category": "C73", + "Value": 55 + }, + { + "Group": "Clothing", + "Category": "C74", + "Value": 99 + }, + { + "Group": "Clothing", + "Category": "C75", + "Value": 27 + }, + { + "Group": "Clothing", + "Category": "C76", + "Value": 26 + }, + { + "Group": "Clothing", + "Category": "C77", + "Value": 33 + }, + { + "Group": "Clothing", + "Category": "C78", + "Value": 6 + }, + { + "Group": "Clothing", + "Category": "C79", + "Value": 92 + }, + { + "Group": "Clothing", + "Category": "C80", + "Value": 64 + }, + { + "Group": "Food", + "Category": "C01", + "Value": 94 + }, + { + "Group": "Food", + "Category": "C02", + "Value": 66 + }, + { + "Group": "Food", + "Category": "C03", + "Value": 33 + }, + { + "Group": "Food", + "Category": "C04", + "Value": 80 + }, + { + "Group": "Food", + "Category": "C05", + "Value": 97 + }, + { + "Group": "Food", + "Category": "C06", + "Value": 90 + }, + { + "Group": "Food", + "Category": "C07", + "Value": 75 + }, + { + "Group": "Food", + "Category": "C08", + "Value": 22 + }, + { + "Group": "Food", + "Category": "C09", + "Value": 18 + }, + { + "Group": "Food", + "Category": "C10", + "Value": 69 + }, + { + "Group": "Food", + "Category": "C11", + "Value": 97 + }, + { + "Group": "Food", + "Category": "C12", + "Value": 44 + }, + { + "Group": "Food", + "Category": "C13", + "Value": 68 + }, + { + "Group": "Food", + "Category": "C14", + "Value": 31 + }, + { + "Group": "Food", + "Category": "C15", + "Value": 96 + }, + { + "Group": "Food", + "Category": "C16", + "Value": 3 + }, + { + "Group": "Food", + "Category": "C17", + "Value": 16 + }, + { + "Group": "Food", + "Category": "C18", + "Value": 2 + }, + { + "Group": "Food", + "Category": "C19", + "Value": 68 + }, + { + "Group": "Food", + "Category": "C20", + "Value": 62 + }, + { + "Group": "Food", + "Category": "C21", + "Value": 37 + }, + { + "Group": "Food", + "Category": "C22", + "Value": 29 + }, + { + "Group": "Food", + "Category": "C23", + "Value": 72 + }, + { + "Group": "Food", + "Category": "C24", + "Value": 3 + }, + { + "Group": "Food", + "Category": "C25", + "Value": 20 + }, + { + "Group": "Food", + "Category": "C26", + "Value": 82 + }, + { + "Group": "Food", + "Category": "C27", + "Value": 54 + }, + { + "Group": "Food", + "Category": "C28", + "Value": 39 + }, + { + "Group": "Food", + "Category": "C29", + "Value": 59 + }, + { + "Group": "Food", + "Category": "C30", + "Value": 83 + }, + { + "Group": "Food", + "Category": "C31", + "Value": 40 + }, + { + "Group": "Food", + "Category": "C32", + "Value": 51 + }, + { + "Group": "Food", + "Category": "C33", + "Value": 95 + }, + { + "Group": "Food", + "Category": "C34", + "Value": 40 + }, + { + "Group": "Food", + "Category": "C35", + "Value": 94 + }, + { + "Group": "Food", + "Category": "C36", + "Value": 15 + }, + { + "Group": "Food", + "Category": "C37", + "Value": 26 + }, + { + "Group": "Food", + "Category": "C38", + "Value": 68 + }, + { + "Group": "Food", + "Category": "C39", + "Value": 92 + }, + { + "Group": "Food", + "Category": "C40", + "Value": 53 + }, + { + "Group": "Food", + "Category": "C41", + "Value": 86 + }, + { + "Group": "Food", + "Category": "C42", + "Value": 61 + }, + { + "Group": "Food", + "Category": "C43", + "Value": 87 + }, + { + "Group": "Food", + "Category": "C44", + "Value": 35 + }, + { + "Group": "Food", + "Category": "C45", + "Value": 30 + }, + { + "Group": "Food", + "Category": "C46", + "Value": 43 + }, + { + "Group": "Food", + "Category": "C47", + "Value": 30 + }, + { + "Group": "Food", + "Category": "C48", + "Value": 75 + }, + { + "Group": "Food", + "Category": "C49", + "Value": 97 + }, + { + "Group": "Food", + "Category": "C50", + "Value": 82 + }, + { + "Group": "Food", + "Category": "C51", + "Value": 3 + }, + { + "Group": "Food", + "Category": "C52", + "Value": 46 + }, + { + "Group": "Food", + "Category": "C53", + "Value": 97 + }, + { + "Group": "Food", + "Category": "C54", + "Value": 57 + }, + { + "Group": "Food", + "Category": "C55", + "Value": 44 + }, + { + "Group": "Food", + "Category": "C56", + "Value": 51 + }, + { + "Group": "Food", + "Category": "C57", + "Value": 98 + }, + { + "Group": "Food", + "Category": "C58", + "Value": 63 + }, + { + "Group": "Food", + "Category": "C59", + "Value": 25 + }, + { + "Group": "Food", + "Category": "C60", + "Value": 23 + }, + { + "Group": "Food", + "Category": "C61", + "Value": 43 + }, + { + "Group": "Food", + "Category": "C62", + "Value": 99 + }, + { + "Group": "Food", + "Category": "C63", + "Value": 53 + }, + { + "Group": "Food", + "Category": "C64", + "Value": 33 + }, + { + "Group": "Food", + "Category": "C65", + "Value": 74 + }, + { + "Group": "Food", + "Category": "C66", + "Value": 35 + }, + { + "Group": "Food", + "Category": "C67", + "Value": 85 + }, + { + "Group": "Food", + "Category": "C68", + "Value": 83 + }, + { + "Group": "Food", + "Category": "C69", + "Value": 77 + }, + { + "Group": "Food", + "Category": "C70", + "Value": 46 + }, + { + "Group": "Food", + "Category": "C71", + "Value": 47 + }, + { + "Group": "Food", + "Category": "C72", + "Value": 74 + }, + { + "Group": "Food", + "Category": "C73", + "Value": 12 + }, + { + "Group": "Food", + "Category": "C74", + "Value": 97 + }, + { + "Group": "Food", + "Category": "C75", + "Value": 64 + }, + { + "Group": "Food", + "Category": "C76", + "Value": 87 + }, + { + "Group": "Food", + "Category": "C77", + "Value": 27 + }, + { + "Group": "Food", + "Category": "C78", + "Value": 98 + }, + { + "Group": "Food", + "Category": "C79", + "Value": 85 + }, + { + "Group": "Food", + "Category": "C80", + "Value": 59 + }, + { + "Group": "Books", + "Category": "C01", + "Value": 23 + }, + { + "Group": "Books", + "Category": "C02", + "Value": 42 + }, + { + "Group": "Books", + "Category": "C03", + "Value": 30 + }, + { + "Group": "Books", + "Category": "C04", + "Value": 59 + }, + { + "Group": "Books", + "Category": "C05", + "Value": 45 + }, + { + "Group": "Books", + "Category": "C06", + "Value": 24 + }, + { + "Group": "Books", + "Category": "C07", + "Value": 24 + }, + { + "Group": "Books", + "Category": "C08", + "Value": 50 + }, + { + "Group": "Books", + "Category": "C09", + "Value": 36 + }, + { + "Group": "Books", + "Category": "C10", + "Value": 62 + }, + { + "Group": "Books", + "Category": "C11", + "Value": 34 + }, + { + "Group": "Books", + "Category": "C12", + "Value": 8 + }, + { + "Group": "Books", + "Category": "C13", + "Value": 89 + }, + { + "Group": "Books", + "Category": "C14", + "Value": 3 + }, + { + "Group": "Books", + "Category": "C15", + "Value": 3 + }, + { + "Group": "Books", + "Category": "C16", + "Value": 75 + }, + { + "Group": "Books", + "Category": "C17", + "Value": 88 + }, + { + "Group": "Books", + "Category": "C18", + "Value": 16 + }, + { + "Group": "Books", + "Category": "C19", + "Value": 30 + }, + { + "Group": "Books", + "Category": "C20", + "Value": 63 + }, + { + "Group": "Books", + "Category": "C21", + "Value": 36 + }, + { + "Group": "Books", + "Category": "C22", + "Value": 83 + }, + { + "Group": "Books", + "Category": "C23", + "Value": 52 + }, + { + "Group": "Books", + "Category": "C24", + "Value": 13 + }, + { + "Group": "Books", + "Category": "C25", + "Value": 87 + }, + { + "Group": "Books", + "Category": "C26", + "Value": 90 + }, + { + "Group": "Books", + "Category": "C27", + "Value": 12 + }, + { + "Group": "Books", + "Category": "C28", + "Value": 27 + }, + { + "Group": "Books", + "Category": "C29", + "Value": 76 + }, + { + "Group": "Books", + "Category": "C30", + "Value": 71 + }, + { + "Group": "Books", + "Category": "C31", + "Value": 14 + }, + { + "Group": "Books", + "Category": "C32", + "Value": 94 + }, + { + "Group": "Books", + "Category": "C33", + "Value": 42 + }, + { + "Group": "Books", + "Category": "C34", + "Value": 45 + }, + { + "Group": "Books", + "Category": "C35", + "Value": 9 + }, + { + "Group": "Books", + "Category": "C36", + "Value": 22 + }, + { + "Group": "Books", + "Category": "C37", + "Value": 0 + }, + { + "Group": "Books", + "Category": "C38", + "Value": 54 + }, + { + "Group": "Books", + "Category": "C39", + "Value": 43 + }, + { + "Group": "Books", + "Category": "C40", + "Value": 25 + }, + { + "Group": "Books", + "Category": "C41", + "Value": 71 + }, + { + "Group": "Books", + "Category": "C42", + "Value": 56 + }, + { + "Group": "Books", + "Category": "C43", + "Value": 76 + }, + { + "Group": "Books", + "Category": "C44", + "Value": 25 + }, + { + "Group": "Books", + "Category": "C45", + "Value": 42 + }, + { + "Group": "Books", + "Category": "C46", + "Value": 78 + }, + { + "Group": "Books", + "Category": "C47", + "Value": 72 + }, + { + "Group": "Books", + "Category": "C48", + "Value": 44 + }, + { + "Group": "Books", + "Category": "C49", + "Value": 70 + }, + { + "Group": "Books", + "Category": "C50", + "Value": 81 + }, + { + "Group": "Books", + "Category": "C51", + "Value": 44 + }, + { + "Group": "Books", + "Category": "C52", + "Value": 29 + }, + { + "Group": "Books", + "Category": "C53", + "Value": 26 + }, + { + "Group": "Books", + "Category": "C54", + "Value": 74 + }, + { + "Group": "Books", + "Category": "C55", + "Value": 60 + }, + { + "Group": "Books", + "Category": "C56", + "Value": 7 + }, + { + "Group": "Books", + "Category": "C57", + "Value": 60 + }, + { + "Group": "Books", + "Category": "C58", + "Value": 67 + }, + { + "Group": "Books", + "Category": "C59", + "Value": 64 + }, + { + "Group": "Books", + "Category": "C60", + "Value": 98 + }, + { + "Group": "Books", + "Category": "C61", + "Value": 25 + }, + { + "Group": "Books", + "Category": "C62", + "Value": 76 + }, + { + "Group": "Books", + "Category": "C63", + "Value": 84 + }, + { + "Group": "Books", + "Category": "C64", + "Value": 100 + }, + { + "Group": "Books", + "Category": "C65", + "Value": 35 + }, + { + "Group": "Books", + "Category": "C66", + "Value": 25 + }, + { + "Group": "Books", + "Category": "C67", + "Value": 89 + }, + { + "Group": "Books", + "Category": "C68", + "Value": 9 + }, + { + "Group": "Books", + "Category": "C69", + "Value": 57 + }, + { + "Group": "Books", + "Category": "C70", + "Value": 74 + }, + { + "Group": "Books", + "Category": "C71", + "Value": 27 + }, + { + "Group": "Books", + "Category": "C72", + "Value": 56 + }, + { + "Group": "Books", + "Category": "C73", + "Value": 28 + }, + { + "Group": "Books", + "Category": "C74", + "Value": 16 + }, + { + "Group": "Books", + "Category": "C75", + "Value": 73 + }, + { + "Group": "Books", + "Category": "C76", + "Value": 82 + }, + { + "Group": "Books", + "Category": "C77", + "Value": 77 + }, + { + "Group": "Books", + "Category": "C78", + "Value": 54 + }, + { + "Group": "Books", + "Category": "C79", + "Value": 83 + }, + { + "Group": "Books", + "Category": "C80", + "Value": 98 + }, + { + "Group": "Sports", + "Category": "C01", + "Value": 80 + }, + { + "Group": "Sports", + "Category": "C02", + "Value": 49 + }, + { + "Group": "Sports", + "Category": "C03", + "Value": 37 + }, + { + "Group": "Sports", + "Category": "C04", + "Value": 70 + }, + { + "Group": "Sports", + "Category": "C05", + "Value": 61 + }, + { + "Group": "Sports", + "Category": "C06", + "Value": 87 + }, + { + "Group": "Sports", + "Category": "C07", + "Value": 88 + }, + { + "Group": "Sports", + "Category": "C08", + "Value": 86 + }, + { + "Group": "Sports", + "Category": "C09", + "Value": 52 + }, + { + "Group": "Sports", + "Category": "C10", + "Value": 18 + }, + { + "Group": "Sports", + "Category": "C11", + "Value": 29 + }, + { + "Group": "Sports", + "Category": "C12", + "Value": 31 + }, + { + "Group": "Sports", + "Category": "C13", + "Value": 13 + }, + { + "Group": "Sports", + "Category": "C14", + "Value": 40 + }, + { + "Group": "Sports", + "Category": "C15", + "Value": 2 + }, + { + "Group": "Sports", + "Category": "C16", + "Value": 94 + }, + { + "Group": "Sports", + "Category": "C17", + "Value": 63 + }, + { + "Group": "Sports", + "Category": "C18", + "Value": 69 + }, + { + "Group": "Sports", + "Category": "C19", + "Value": 45 + }, + { + "Group": "Sports", + "Category": "C20", + "Value": 70 + }, + { + "Group": "Sports", + "Category": "C21", + "Value": 85 + }, + { + "Group": "Sports", + "Category": "C22", + "Value": 65 + }, + { + "Group": "Sports", + "Category": "C23", + "Value": 60 + }, + { + "Group": "Sports", + "Category": "C24", + "Value": 10 + }, + { + "Group": "Sports", + "Category": "C25", + "Value": 91 + }, + { + "Group": "Sports", + "Category": "C26", + "Value": 47 + }, + { + "Group": "Sports", + "Category": "C27", + "Value": 37 + }, + { + "Group": "Sports", + "Category": "C28", + "Value": 78 + }, + { + "Group": "Sports", + "Category": "C29", + "Value": 7 + }, + { + "Group": "Sports", + "Category": "C30", + "Value": 80 + }, + { + "Group": "Sports", + "Category": "C31", + "Value": 45 + }, + { + "Group": "Sports", + "Category": "C32", + "Value": 96 + }, + { + "Group": "Sports", + "Category": "C33", + "Value": 23 + }, + { + "Group": "Sports", + "Category": "C34", + "Value": 50 + }, + { + "Group": "Sports", + "Category": "C35", + "Value": 80 + }, + { + "Group": "Sports", + "Category": "C36", + "Value": 30 + }, + { + "Group": "Sports", + "Category": "C37", + "Value": 42 + }, + { + "Group": "Sports", + "Category": "C38", + "Value": 59 + }, + { + "Group": "Sports", + "Category": "C39", + "Value": 22 + }, + { + "Group": "Sports", + "Category": "C40", + "Value": 38 + }, + { + "Group": "Sports", + "Category": "C41", + "Value": 79 + }, + { + "Group": "Sports", + "Category": "C42", + "Value": 6 + }, + { + "Group": "Sports", + "Category": "C43", + "Value": 79 + }, + { + "Group": "Sports", + "Category": "C44", + "Value": 97 + }, + { + "Group": "Sports", + "Category": "C45", + "Value": 52 + }, + { + "Group": "Sports", + "Category": "C46", + "Value": 37 + }, + { + "Group": "Sports", + "Category": "C47", + "Value": 90 + }, + { + "Group": "Sports", + "Category": "C48", + "Value": 59 + }, + { + "Group": "Sports", + "Category": "C49", + "Value": 45 + }, + { + "Group": "Sports", + "Category": "C50", + "Value": 50 + }, + { + "Group": "Sports", + "Category": "C51", + "Value": 97 + }, + { + "Group": "Sports", + "Category": "C52", + "Value": 92 + }, + { + "Group": "Sports", + "Category": "C53", + "Value": 81 + }, + { + "Group": "Sports", + "Category": "C54", + "Value": 3 + }, + { + "Group": "Sports", + "Category": "C55", + "Value": 46 + }, + { + "Group": "Sports", + "Category": "C56", + "Value": 40 + }, + { + "Group": "Sports", + "Category": "C57", + "Value": 18 + }, + { + "Group": "Sports", + "Category": "C58", + "Value": 45 + }, + { + "Group": "Sports", + "Category": "C59", + "Value": 2 + }, + { + "Group": "Sports", + "Category": "C60", + "Value": 37 + }, + { + "Group": "Sports", + "Category": "C61", + "Value": 56 + }, + { + "Group": "Sports", + "Category": "C62", + "Value": 87 + }, + { + "Group": "Sports", + "Category": "C63", + "Value": 21 + }, + { + "Group": "Sports", + "Category": "C64", + "Value": 64 + }, + { + "Group": "Sports", + "Category": "C65", + "Value": 50 + }, + { + "Group": "Sports", + "Category": "C66", + "Value": 87 + }, + { + "Group": "Sports", + "Category": "C67", + "Value": 25 + }, + { + "Group": "Sports", + "Category": "C68", + "Value": 67 + }, + { + "Group": "Sports", + "Category": "C69", + "Value": 60 + }, + { + "Group": "Sports", + "Category": "C70", + "Value": 12 + }, + { + "Group": "Sports", + "Category": "C71", + "Value": 14 + }, + { + "Group": "Sports", + "Category": "C72", + "Value": 39 + }, + { + "Group": "Sports", + "Category": "C73", + "Value": 14 + }, + { + "Group": "Sports", + "Category": "C74", + "Value": 94 + }, + { + "Group": "Sports", + "Category": "C75", + "Value": 69 + }, + { + "Group": "Sports", + "Category": "C76", + "Value": 87 + }, + { + "Group": "Sports", + "Category": "C77", + "Value": 39 + }, + { + "Group": "Sports", + "Category": "C78", + "Value": 55 + }, + { + "Group": "Sports", + "Category": "C79", + "Value": 95 + }, + { + "Group": "Sports", + "Category": "C80", + "Value": 45 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/histogram/00-card49.flint.json b/test-harness/excel/evaluations/inputs/histogram/00-card49.flint.json new file mode 100644 index 00000000..90f06ac9 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/histogram/00-card49.flint.json @@ -0,0 +1,319 @@ +{ + "semantic_types": { + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Histogram", + "encodings": { + "x": "Value" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Value": 12 + }, + { + "Value": 26 + }, + { + "Value": 23 + }, + { + "Value": 41 + }, + { + "Value": 59 + }, + { + "Value": 52 + }, + { + "Value": 60 + }, + { + "Value": 65 + }, + { + "Value": 66 + }, + { + "Value": 48 + }, + { + "Value": 50 + }, + { + "Value": 57 + }, + { + "Value": 52 + }, + { + "Value": 41 + }, + { + "Value": 30 + }, + { + "Value": 72 + }, + { + "Value": 53 + }, + { + "Value": 45 + }, + { + "Value": 17 + }, + { + "Value": 63 + }, + { + "Value": 60 + }, + { + "Value": 31 + }, + { + "Value": 63 + }, + { + "Value": 60 + }, + { + "Value": 19 + }, + { + "Value": 63 + }, + { + "Value": 81 + }, + { + "Value": 40 + }, + { + "Value": 64 + }, + { + "Value": 52 + }, + { + "Value": 53 + }, + { + "Value": 37 + }, + { + "Value": 38 + }, + { + "Value": 45 + }, + { + "Value": 18 + }, + { + "Value": 37 + }, + { + "Value": 41 + }, + { + "Value": 51 + }, + { + "Value": 70 + }, + { + "Value": 63 + }, + { + "Value": 69 + }, + { + "Value": 34 + }, + { + "Value": 60 + }, + { + "Value": 59 + }, + { + "Value": 41 + }, + { + "Value": 26 + }, + { + "Value": 43 + }, + { + "Value": 35 + }, + { + "Value": 43 + }, + { + "Value": 57 + }, + { + "Value": 53 + }, + { + "Value": 46 + }, + { + "Value": 41 + }, + { + "Value": 51 + }, + { + "Value": 42 + }, + { + "Value": 38 + }, + { + "Value": 47 + }, + { + "Value": 52 + }, + { + "Value": 55 + }, + { + "Value": 54 + }, + { + "Value": 60 + }, + { + "Value": 45 + }, + { + "Value": 60 + }, + { + "Value": 78 + }, + { + "Value": 71 + }, + { + "Value": 55 + }, + { + "Value": 21 + }, + { + "Value": 69 + }, + { + "Value": 57 + }, + { + "Value": 51 + }, + { + "Value": 69 + }, + { + "Value": 49 + }, + { + "Value": 27 + }, + { + "Value": 62 + }, + { + "Value": 43 + }, + { + "Value": 36 + }, + { + "Value": 66 + }, + { + "Value": 47 + }, + { + "Value": 37 + }, + { + "Value": 52 + }, + { + "Value": 23 + }, + { + "Value": 46 + }, + { + "Value": 39 + }, + { + "Value": 55 + }, + { + "Value": 51 + }, + { + "Value": 49 + }, + { + "Value": 56 + }, + { + "Value": 63 + }, + { + "Value": 75 + }, + { + "Value": 68 + }, + { + "Value": 59 + }, + { + "Value": 42 + }, + { + "Value": 61 + }, + { + "Value": 42 + }, + { + "Value": 30 + }, + { + "Value": 37 + }, + { + "Value": 78 + }, + { + "Value": 68 + }, + { + "Value": 64 + }, + { + "Value": 59 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/histogram/01-card42.flint.json b/test-harness/excel/evaluations/inputs/histogram/01-card42.flint.json new file mode 100644 index 00000000..2015b206 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/histogram/01-card42.flint.json @@ -0,0 +1,821 @@ +{ + "semantic_types": { + "Height": "Quantity", + "Gender": "Category" + }, + "chart_spec": { + "chartType": "Histogram", + "encodings": { + "x": "Height", + "color": "Gender" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Height": 176, + "Gender": "Male" + }, + { + "Height": 160, + "Gender": "Female" + }, + { + "Height": 169, + "Gender": "Male" + }, + { + "Height": 160, + "Gender": "Female" + }, + { + "Height": 161, + "Gender": "Male" + }, + { + "Height": 155, + "Gender": "Female" + }, + { + "Height": 189, + "Gender": "Male" + }, + { + "Height": 160, + "Gender": "Female" + }, + { + "Height": 160, + "Gender": "Male" + }, + { + "Height": 155, + "Gender": "Female" + }, + { + "Height": 181, + "Gender": "Male" + }, + { + "Height": 171, + "Gender": "Female" + }, + { + "Height": 160, + "Gender": "Male" + }, + { + "Height": 168, + "Gender": "Female" + }, + { + "Height": 167, + "Gender": "Male" + }, + { + "Height": 172, + "Gender": "Female" + }, + { + "Height": 166, + "Gender": "Male" + }, + { + "Height": 160, + "Gender": "Female" + }, + { + "Height": 158, + "Gender": "Male" + }, + { + "Height": 168, + "Gender": "Female" + }, + { + "Height": 176, + "Gender": "Male" + }, + { + "Height": 147, + "Gender": "Female" + }, + { + "Height": 155, + "Gender": "Male" + }, + { + "Height": 153, + "Gender": "Female" + }, + { + "Height": 156, + "Gender": "Male" + }, + { + "Height": 152, + "Gender": "Female" + }, + { + "Height": 181, + "Gender": "Male" + }, + { + "Height": 166, + "Gender": "Female" + }, + { + "Height": 170, + "Gender": "Male" + }, + { + "Height": 145, + "Gender": "Female" + }, + { + "Height": 162, + "Gender": "Male" + }, + { + "Height": 158, + "Gender": "Female" + }, + { + "Height": 174, + "Gender": "Male" + }, + { + "Height": 152, + "Gender": "Female" + }, + { + "Height": 160, + "Gender": "Male" + }, + { + "Height": 164, + "Gender": "Female" + }, + { + "Height": 169, + "Gender": "Male" + }, + { + "Height": 157, + "Gender": "Female" + }, + { + "Height": 164, + "Gender": "Male" + }, + { + "Height": 161, + "Gender": "Female" + }, + { + "Height": 162, + "Gender": "Male" + }, + { + "Height": 158, + "Gender": "Female" + }, + { + "Height": 176, + "Gender": "Male" + }, + { + "Height": 160, + "Gender": "Female" + }, + { + "Height": 170, + "Gender": "Male" + }, + { + "Height": 170, + "Gender": "Female" + }, + { + "Height": 180, + "Gender": "Male" + }, + { + "Height": 154, + "Gender": "Female" + }, + { + "Height": 174, + "Gender": "Male" + }, + { + "Height": 169, + "Gender": "Female" + }, + { + "Height": 174, + "Gender": "Male" + }, + { + "Height": 156, + "Gender": "Female" + }, + { + "Height": 168, + "Gender": "Male" + }, + { + "Height": 155, + "Gender": "Female" + }, + { + "Height": 173, + "Gender": "Male" + }, + { + "Height": 140, + "Gender": "Female" + }, + { + "Height": 173, + "Gender": "Male" + }, + { + "Height": 161, + "Gender": "Female" + }, + { + "Height": 164, + "Gender": "Male" + }, + { + "Height": 174, + "Gender": "Female" + }, + { + "Height": 169, + "Gender": "Male" + }, + { + "Height": 153, + "Gender": "Female" + }, + { + "Height": 156, + "Gender": "Male" + }, + { + "Height": 160, + "Gender": "Female" + }, + { + "Height": 163, + "Gender": "Male" + }, + { + "Height": 168, + "Gender": "Female" + }, + { + "Height": 170, + "Gender": "Male" + }, + { + "Height": 168, + "Gender": "Female" + }, + { + "Height": 168, + "Gender": "Male" + }, + { + "Height": 157, + "Gender": "Female" + }, + { + "Height": 163, + "Gender": "Male" + }, + { + "Height": 152, + "Gender": "Female" + }, + { + "Height": 180, + "Gender": "Male" + }, + { + "Height": 172, + "Gender": "Female" + }, + { + "Height": 174, + "Gender": "Male" + }, + { + "Height": 156, + "Gender": "Female" + }, + { + "Height": 170, + "Gender": "Male" + }, + { + "Height": 164, + "Gender": "Female" + }, + { + "Height": 150, + "Gender": "Male" + }, + { + "Height": 165, + "Gender": "Female" + }, + { + "Height": 177, + "Gender": "Male" + }, + { + "Height": 163, + "Gender": "Female" + }, + { + "Height": 176, + "Gender": "Male" + }, + { + "Height": 167, + "Gender": "Female" + }, + { + "Height": 164, + "Gender": "Male" + }, + { + "Height": 158, + "Gender": "Female" + }, + { + "Height": 172, + "Gender": "Male" + }, + { + "Height": 162, + "Gender": "Female" + }, + { + "Height": 161, + "Gender": "Male" + }, + { + "Height": 159, + "Gender": "Female" + }, + { + "Height": 169, + "Gender": "Male" + }, + { + "Height": 155, + "Gender": "Female" + }, + { + "Height": 167, + "Gender": "Male" + }, + { + "Height": 173, + "Gender": "Female" + }, + { + "Height": 164, + "Gender": "Male" + }, + { + "Height": 153, + "Gender": "Female" + }, + { + "Height": 162, + "Gender": "Male" + }, + { + "Height": 157, + "Gender": "Female" + }, + { + "Height": 165, + "Gender": "Male" + }, + { + "Height": 158, + "Gender": "Female" + }, + { + "Height": 170, + "Gender": "Male" + }, + { + "Height": 159, + "Gender": "Female" + }, + { + "Height": 177, + "Gender": "Male" + }, + { + "Height": 161, + "Gender": "Female" + }, + { + "Height": 179, + "Gender": "Male" + }, + { + "Height": 154, + "Gender": "Female" + }, + { + "Height": 163, + "Gender": "Male" + }, + { + "Height": 170, + "Gender": "Female" + }, + { + "Height": 180, + "Gender": "Male" + }, + { + "Height": 163, + "Gender": "Female" + }, + { + "Height": 180, + "Gender": "Male" + }, + { + "Height": 164, + "Gender": "Female" + }, + { + "Height": 176, + "Gender": "Male" + }, + { + "Height": 149, + "Gender": "Female" + }, + { + "Height": 180, + "Gender": "Male" + }, + { + "Height": 150, + "Gender": "Female" + }, + { + "Height": 170, + "Gender": "Male" + }, + { + "Height": 159, + "Gender": "Female" + }, + { + "Height": 170, + "Gender": "Male" + }, + { + "Height": 174, + "Gender": "Female" + }, + { + "Height": 161, + "Gender": "Male" + }, + { + "Height": 154, + "Gender": "Female" + }, + { + "Height": 184, + "Gender": "Male" + }, + { + "Height": 156, + "Gender": "Female" + }, + { + "Height": 165, + "Gender": "Male" + }, + { + "Height": 146, + "Gender": "Female" + }, + { + "Height": 158, + "Gender": "Male" + }, + { + "Height": 160, + "Gender": "Female" + }, + { + "Height": 165, + "Gender": "Male" + }, + { + "Height": 159, + "Gender": "Female" + }, + { + "Height": 177, + "Gender": "Male" + }, + { + "Height": 160, + "Gender": "Female" + }, + { + "Height": 170, + "Gender": "Male" + }, + { + "Height": 163, + "Gender": "Female" + }, + { + "Height": 173, + "Gender": "Male" + }, + { + "Height": 162, + "Gender": "Female" + }, + { + "Height": 162, + "Gender": "Male" + }, + { + "Height": 161, + "Gender": "Female" + }, + { + "Height": 197, + "Gender": "Male" + }, + { + "Height": 144, + "Gender": "Female" + }, + { + "Height": 165, + "Gender": "Male" + }, + { + "Height": 163, + "Gender": "Female" + }, + { + "Height": 171, + "Gender": "Male" + }, + { + "Height": 167, + "Gender": "Female" + }, + { + "Height": 167, + "Gender": "Male" + }, + { + "Height": 160, + "Gender": "Female" + }, + { + "Height": 167, + "Gender": "Male" + }, + { + "Height": 154, + "Gender": "Female" + }, + { + "Height": 163, + "Gender": "Male" + }, + { + "Height": 179, + "Gender": "Female" + }, + { + "Height": 164, + "Gender": "Male" + }, + { + "Height": 157, + "Gender": "Female" + }, + { + "Height": 160, + "Gender": "Male" + }, + { + "Height": 166, + "Gender": "Female" + }, + { + "Height": 176, + "Gender": "Male" + }, + { + "Height": 159, + "Gender": "Female" + }, + { + "Height": 164, + "Gender": "Male" + }, + { + "Height": 163, + "Gender": "Female" + }, + { + "Height": 170, + "Gender": "Male" + }, + { + "Height": 152, + "Gender": "Female" + }, + { + "Height": 166, + "Gender": "Male" + }, + { + "Height": 164, + "Gender": "Female" + }, + { + "Height": 182, + "Gender": "Male" + }, + { + "Height": 148, + "Gender": "Female" + }, + { + "Height": 166, + "Gender": "Male" + }, + { + "Height": 145, + "Gender": "Female" + }, + { + "Height": 189, + "Gender": "Male" + }, + { + "Height": 163, + "Gender": "Female" + }, + { + "Height": 154, + "Gender": "Male" + }, + { + "Height": 169, + "Gender": "Female" + }, + { + "Height": 186, + "Gender": "Male" + }, + { + "Height": 153, + "Gender": "Female" + }, + { + "Height": 177, + "Gender": "Male" + }, + { + "Height": 157, + "Gender": "Female" + }, + { + "Height": 168, + "Gender": "Male" + }, + { + "Height": 167, + "Gender": "Female" + }, + { + "Height": 176, + "Gender": "Male" + }, + { + "Height": 167, + "Gender": "Female" + }, + { + "Height": 175, + "Gender": "Male" + }, + { + "Height": 163, + "Gender": "Female" + }, + { + "Height": 161, + "Gender": "Male" + }, + { + "Height": 162, + "Gender": "Female" + }, + { + "Height": 169, + "Gender": "Male" + }, + { + "Height": 165, + "Gender": "Female" + }, + { + "Height": 161, + "Gender": "Male" + }, + { + "Height": 153, + "Gender": "Female" + }, + { + "Height": 177, + "Gender": "Male" + }, + { + "Height": 169, + "Gender": "Female" + }, + { + "Height": 180, + "Gender": "Male" + }, + { + "Height": 158, + "Gender": "Female" + }, + { + "Height": 177, + "Gender": "Male" + }, + { + "Height": 158, + "Gender": "Female" + }, + { + "Height": 162, + "Gender": "Male" + }, + { + "Height": 150, + "Gender": "Female" + }, + { + "Height": 162, + "Gender": "Male" + }, + { + "Height": 169, + "Gender": "Female" + }, + { + "Height": 171, + "Gender": "Male" + }, + { + "Height": 159, + "Gender": "Female" + }, + { + "Height": 171, + "Gender": "Male" + }, + { + "Height": 159, + "Gender": "Female" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/histogram/02-card997.flint.json b/test-harness/excel/evaluations/inputs/histogram/02-card997.flint.json new file mode 100644 index 00000000..1f1d92d6 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/histogram/02-card997.flint.json @@ -0,0 +1,3019 @@ +{ + "semantic_types": { + "Income": "Amount" + }, + "chart_spec": { + "chartType": "Histogram", + "encodings": { + "x": "Income" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Income": 44532 + }, + { + "Income": 122272 + }, + { + "Income": 78688 + }, + { + "Income": 168681 + }, + { + "Income": 144659 + }, + { + "Income": 149832 + }, + { + "Income": 138785 + }, + { + "Income": 57118 + }, + { + "Income": 168530 + }, + { + "Income": 127472 + }, + { + "Income": 177751 + }, + { + "Income": 125212 + }, + { + "Income": 173426 + }, + { + "Income": 148053 + }, + { + "Income": 133132 + }, + { + "Income": 82366 + }, + { + "Income": 66406 + }, + { + "Income": 27748 + }, + { + "Income": 98929 + }, + { + "Income": 163892 + }, + { + "Income": 105495 + }, + { + "Income": 181159 + }, + { + "Income": 165383 + }, + { + "Income": 145503 + }, + { + "Income": 111565 + }, + { + "Income": 137993 + }, + { + "Income": 68512 + }, + { + "Income": 134350 + }, + { + "Income": 48154 + }, + { + "Income": 169679 + }, + { + "Income": 169623 + }, + { + "Income": 130035 + }, + { + "Income": 64525 + }, + { + "Income": 97838 + }, + { + "Income": 187381 + }, + { + "Income": 157495 + }, + { + "Income": 58202 + }, + { + "Income": 21024 + }, + { + "Income": 135574 + }, + { + "Income": 84109 + }, + { + "Income": 27099 + }, + { + "Income": 165677 + }, + { + "Income": 61380 + }, + { + "Income": 157860 + }, + { + "Income": 75629 + }, + { + "Income": 49287 + }, + { + "Income": 130495 + }, + { + "Income": 42070 + }, + { + "Income": 143560 + }, + { + "Income": 38020 + }, + { + "Income": 116026 + }, + { + "Income": 49799 + }, + { + "Income": 97383 + }, + { + "Income": 100163 + }, + { + "Income": 21399 + }, + { + "Income": 130756 + }, + { + "Income": 111676 + }, + { + "Income": 193163 + }, + { + "Income": 126828 + }, + { + "Income": 155080 + }, + { + "Income": 157384 + }, + { + "Income": 165781 + }, + { + "Income": 176592 + }, + { + "Income": 89144 + }, + { + "Income": 41567 + }, + { + "Income": 162830 + }, + { + "Income": 91353 + }, + { + "Income": 82765 + }, + { + "Income": 112900 + }, + { + "Income": 71155 + }, + { + "Income": 100459 + }, + { + "Income": 139265 + }, + { + "Income": 28251 + }, + { + "Income": 93137 + }, + { + "Income": 186522 + }, + { + "Income": 116457 + }, + { + "Income": 101105 + }, + { + "Income": 188760 + }, + { + "Income": 106063 + }, + { + "Income": 187351 + }, + { + "Income": 186272 + }, + { + "Income": 56219 + }, + { + "Income": 178240 + }, + { + "Income": 52112 + }, + { + "Income": 89812 + }, + { + "Income": 110430 + }, + { + "Income": 145001 + }, + { + "Income": 137910 + }, + { + "Income": 116225 + }, + { + "Income": 152238 + }, + { + "Income": 78824 + }, + { + "Income": 122198 + }, + { + "Income": 100321 + }, + { + "Income": 153940 + }, + { + "Income": 74080 + }, + { + "Income": 122765 + }, + { + "Income": 96188 + }, + { + "Income": 167549 + }, + { + "Income": 195143 + }, + { + "Income": 109013 + }, + { + "Income": 73112 + }, + { + "Income": 53512 + }, + { + "Income": 29024 + }, + { + "Income": 133948 + }, + { + "Income": 119939 + }, + { + "Income": 114552 + }, + { + "Income": 107616 + }, + { + "Income": 183780 + }, + { + "Income": 118195 + }, + { + "Income": 139272 + }, + { + "Income": 136403 + }, + { + "Income": 168569 + }, + { + "Income": 66245 + }, + { + "Income": 24285 + }, + { + "Income": 30248 + }, + { + "Income": 176997 + }, + { + "Income": 53733 + }, + { + "Income": 151719 + }, + { + "Income": 176133 + }, + { + "Income": 99961 + }, + { + "Income": 38108 + }, + { + "Income": 166181 + }, + { + "Income": 66691 + }, + { + "Income": 141043 + }, + { + "Income": 29198 + }, + { + "Income": 163694 + }, + { + "Income": 22718 + }, + { + "Income": 153165 + }, + { + "Income": 184366 + }, + { + "Income": 52404 + }, + { + "Income": 142303 + }, + { + "Income": 138581 + }, + { + "Income": 58749 + }, + { + "Income": 27468 + }, + { + "Income": 82601 + }, + { + "Income": 55249 + }, + { + "Income": 74290 + }, + { + "Income": 48996 + }, + { + "Income": 91584 + }, + { + "Income": 198289 + }, + { + "Income": 56168 + }, + { + "Income": 38170 + }, + { + "Income": 127360 + }, + { + "Income": 104768 + }, + { + "Income": 193736 + }, + { + "Income": 39422 + }, + { + "Income": 105259 + }, + { + "Income": 165520 + }, + { + "Income": 122392 + }, + { + "Income": 129047 + }, + { + "Income": 186724 + }, + { + "Income": 87388 + }, + { + "Income": 45420 + }, + { + "Income": 111147 + }, + { + "Income": 122857 + }, + { + "Income": 195028 + }, + { + "Income": 151037 + }, + { + "Income": 52382 + }, + { + "Income": 126231 + }, + { + "Income": 197939 + }, + { + "Income": 127367 + }, + { + "Income": 37194 + }, + { + "Income": 104586 + }, + { + "Income": 190324 + }, + { + "Income": 111096 + }, + { + "Income": 169507 + }, + { + "Income": 168621 + }, + { + "Income": 28722 + }, + { + "Income": 92691 + }, + { + "Income": 74601 + }, + { + "Income": 63645 + }, + { + "Income": 69170 + }, + { + "Income": 40595 + }, + { + "Income": 198702 + }, + { + "Income": 162170 + }, + { + "Income": 153046 + }, + { + "Income": 171884 + }, + { + "Income": 152534 + }, + { + "Income": 192428 + }, + { + "Income": 193691 + }, + { + "Income": 178675 + }, + { + "Income": 169746 + }, + { + "Income": 36051 + }, + { + "Income": 146100 + }, + { + "Income": 63302 + }, + { + "Income": 63798 + }, + { + "Income": 106735 + }, + { + "Income": 137614 + }, + { + "Income": 181852 + }, + { + "Income": 113211 + }, + { + "Income": 79579 + }, + { + "Income": 30258 + }, + { + "Income": 157986 + }, + { + "Income": 31297 + }, + { + "Income": 163420 + }, + { + "Income": 107692 + }, + { + "Income": 23345 + }, + { + "Income": 77329 + }, + { + "Income": 195818 + }, + { + "Income": 121072 + }, + { + "Income": 75283 + }, + { + "Income": 179455 + }, + { + "Income": 136768 + }, + { + "Income": 178268 + }, + { + "Income": 163573 + }, + { + "Income": 154062 + }, + { + "Income": 140376 + }, + { + "Income": 156467 + }, + { + "Income": 68258 + }, + { + "Income": 190747 + }, + { + "Income": 22741 + }, + { + "Income": 190100 + }, + { + "Income": 138443 + }, + { + "Income": 76454 + }, + { + "Income": 62098 + }, + { + "Income": 167498 + }, + { + "Income": 65073 + }, + { + "Income": 122200 + }, + { + "Income": 139652 + }, + { + "Income": 46572 + }, + { + "Income": 28178 + }, + { + "Income": 132311 + }, + { + "Income": 155318 + }, + { + "Income": 189423 + }, + { + "Income": 94098 + }, + { + "Income": 149338 + }, + { + "Income": 122856 + }, + { + "Income": 177885 + }, + { + "Income": 28035 + }, + { + "Income": 59372 + }, + { + "Income": 69809 + }, + { + "Income": 153927 + }, + { + "Income": 34786 + }, + { + "Income": 129726 + }, + { + "Income": 85732 + }, + { + "Income": 125890 + }, + { + "Income": 61083 + }, + { + "Income": 198887 + }, + { + "Income": 28611 + }, + { + "Income": 25609 + }, + { + "Income": 145248 + }, + { + "Income": 151167 + }, + { + "Income": 77748 + }, + { + "Income": 30136 + }, + { + "Income": 98334 + }, + { + "Income": 57392 + }, + { + "Income": 89596 + }, + { + "Income": 83418 + }, + { + "Income": 111199 + }, + { + "Income": 106316 + }, + { + "Income": 105721 + }, + { + "Income": 192810 + }, + { + "Income": 143342 + }, + { + "Income": 148010 + }, + { + "Income": 118877 + }, + { + "Income": 92789 + }, + { + "Income": 101401 + }, + { + "Income": 118844 + }, + { + "Income": 72905 + }, + { + "Income": 175328 + }, + { + "Income": 74632 + }, + { + "Income": 44730 + }, + { + "Income": 28766 + }, + { + "Income": 106086 + }, + { + "Income": 21329 + }, + { + "Income": 43187 + }, + { + "Income": 198289 + }, + { + "Income": 68776 + }, + { + "Income": 85547 + }, + { + "Income": 67534 + }, + { + "Income": 90130 + }, + { + "Income": 61755 + }, + { + "Income": 162671 + }, + { + "Income": 114136 + }, + { + "Income": 136579 + }, + { + "Income": 68902 + }, + { + "Income": 39302 + }, + { + "Income": 68571 + }, + { + "Income": 47163 + }, + { + "Income": 70592 + }, + { + "Income": 186817 + }, + { + "Income": 29551 + }, + { + "Income": 162039 + }, + { + "Income": 112694 + }, + { + "Income": 34160 + }, + { + "Income": 48844 + }, + { + "Income": 60784 + }, + { + "Income": 37272 + }, + { + "Income": 148034 + }, + { + "Income": 165957 + }, + { + "Income": 83517 + }, + { + "Income": 145957 + }, + { + "Income": 171768 + }, + { + "Income": 184060 + }, + { + "Income": 132170 + }, + { + "Income": 127655 + }, + { + "Income": 192649 + }, + { + "Income": 130503 + }, + { + "Income": 190212 + }, + { + "Income": 32368 + }, + { + "Income": 164033 + }, + { + "Income": 150086 + }, + { + "Income": 98385 + }, + { + "Income": 192617 + }, + { + "Income": 129826 + }, + { + "Income": 153656 + }, + { + "Income": 154289 + }, + { + "Income": 178320 + }, + { + "Income": 138257 + }, + { + "Income": 181956 + }, + { + "Income": 62350 + }, + { + "Income": 79726 + }, + { + "Income": 160755 + }, + { + "Income": 130266 + }, + { + "Income": 160798 + }, + { + "Income": 137609 + }, + { + "Income": 91986 + }, + { + "Income": 102667 + }, + { + "Income": 156131 + }, + { + "Income": 172599 + }, + { + "Income": 106216 + }, + { + "Income": 59302 + }, + { + "Income": 150792 + }, + { + "Income": 82849 + }, + { + "Income": 81607 + }, + { + "Income": 90070 + }, + { + "Income": 130204 + }, + { + "Income": 191415 + }, + { + "Income": 85838 + }, + { + "Income": 103121 + }, + { + "Income": 60336 + }, + { + "Income": 64016 + }, + { + "Income": 170502 + }, + { + "Income": 139177 + }, + { + "Income": 167161 + }, + { + "Income": 156465 + }, + { + "Income": 20507 + }, + { + "Income": 81871 + }, + { + "Income": 23101 + }, + { + "Income": 117224 + }, + { + "Income": 196353 + }, + { + "Income": 105150 + }, + { + "Income": 129722 + }, + { + "Income": 23779 + }, + { + "Income": 167498 + }, + { + "Income": 59128 + }, + { + "Income": 106096 + }, + { + "Income": 21849 + }, + { + "Income": 135931 + }, + { + "Income": 158185 + }, + { + "Income": 130913 + }, + { + "Income": 60228 + }, + { + "Income": 43784 + }, + { + "Income": 160548 + }, + { + "Income": 76614 + }, + { + "Income": 54678 + }, + { + "Income": 189208 + }, + { + "Income": 86758 + }, + { + "Income": 78397 + }, + { + "Income": 140351 + }, + { + "Income": 93660 + }, + { + "Income": 169714 + }, + { + "Income": 42184 + }, + { + "Income": 83204 + }, + { + "Income": 112527 + }, + { + "Income": 98737 + }, + { + "Income": 166334 + }, + { + "Income": 121953 + }, + { + "Income": 126047 + }, + { + "Income": 176878 + }, + { + "Income": 36067 + }, + { + "Income": 61217 + }, + { + "Income": 113292 + }, + { + "Income": 185222 + }, + { + "Income": 53017 + }, + { + "Income": 169893 + }, + { + "Income": 177787 + }, + { + "Income": 191905 + }, + { + "Income": 52271 + }, + { + "Income": 57921 + }, + { + "Income": 166092 + }, + { + "Income": 191086 + }, + { + "Income": 138605 + }, + { + "Income": 86879 + }, + { + "Income": 141535 + }, + { + "Income": 190663 + }, + { + "Income": 53647 + }, + { + "Income": 140065 + }, + { + "Income": 146236 + }, + { + "Income": 181123 + }, + { + "Income": 92533 + }, + { + "Income": 119034 + }, + { + "Income": 22551 + }, + { + "Income": 50839 + }, + { + "Income": 105083 + }, + { + "Income": 88856 + }, + { + "Income": 63728 + }, + { + "Income": 192087 + }, + { + "Income": 48298 + }, + { + "Income": 72452 + }, + { + "Income": 122886 + }, + { + "Income": 144067 + }, + { + "Income": 94420 + }, + { + "Income": 162105 + }, + { + "Income": 144239 + }, + { + "Income": 104813 + }, + { + "Income": 52980 + }, + { + "Income": 91788 + }, + { + "Income": 193170 + }, + { + "Income": 73468 + }, + { + "Income": 104861 + }, + { + "Income": 138672 + }, + { + "Income": 131987 + }, + { + "Income": 112436 + }, + { + "Income": 189046 + }, + { + "Income": 63675 + }, + { + "Income": 22896 + }, + { + "Income": 96698 + }, + { + "Income": 110228 + }, + { + "Income": 167396 + }, + { + "Income": 152908 + }, + { + "Income": 183395 + }, + { + "Income": 120266 + }, + { + "Income": 25937 + }, + { + "Income": 80281 + }, + { + "Income": 122628 + }, + { + "Income": 122964 + }, + { + "Income": 197106 + }, + { + "Income": 161721 + }, + { + "Income": 163512 + }, + { + "Income": 28906 + }, + { + "Income": 122244 + }, + { + "Income": 149663 + }, + { + "Income": 181622 + }, + { + "Income": 194202 + }, + { + "Income": 139460 + }, + { + "Income": 56257 + }, + { + "Income": 87074 + }, + { + "Income": 179252 + }, + { + "Income": 152473 + }, + { + "Income": 72133 + }, + { + "Income": 164202 + }, + { + "Income": 98784 + }, + { + "Income": 67398 + }, + { + "Income": 143859 + }, + { + "Income": 195886 + }, + { + "Income": 172633 + }, + { + "Income": 149614 + }, + { + "Income": 74875 + }, + { + "Income": 160522 + }, + { + "Income": 170308 + }, + { + "Income": 123402 + }, + { + "Income": 175217 + }, + { + "Income": 193508 + }, + { + "Income": 164572 + }, + { + "Income": 198170 + }, + { + "Income": 48317 + }, + { + "Income": 23947 + }, + { + "Income": 118930 + }, + { + "Income": 84814 + }, + { + "Income": 170726 + }, + { + "Income": 131091 + }, + { + "Income": 173126 + }, + { + "Income": 153470 + }, + { + "Income": 83916 + }, + { + "Income": 24247 + }, + { + "Income": 124714 + }, + { + "Income": 84604 + }, + { + "Income": 60061 + }, + { + "Income": 121123 + }, + { + "Income": 26187 + }, + { + "Income": 142934 + }, + { + "Income": 127531 + }, + { + "Income": 98966 + }, + { + "Income": 56096 + }, + { + "Income": 87989 + }, + { + "Income": 78071 + }, + { + "Income": 61420 + }, + { + "Income": 107601 + }, + { + "Income": 106064 + }, + { + "Income": 24061 + }, + { + "Income": 60496 + }, + { + "Income": 54479 + }, + { + "Income": 89655 + }, + { + "Income": 175407 + }, + { + "Income": 142708 + }, + { + "Income": 118213 + }, + { + "Income": 89790 + }, + { + "Income": 104424 + }, + { + "Income": 175109 + }, + { + "Income": 170533 + }, + { + "Income": 135885 + }, + { + "Income": 106166 + }, + { + "Income": 117308 + }, + { + "Income": 183085 + }, + { + "Income": 128745 + }, + { + "Income": 154084 + }, + { + "Income": 153047 + }, + { + "Income": 181310 + }, + { + "Income": 174015 + }, + { + "Income": 148366 + }, + { + "Income": 162737 + }, + { + "Income": 132880 + }, + { + "Income": 179811 + }, + { + "Income": 175646 + }, + { + "Income": 197188 + }, + { + "Income": 94308 + }, + { + "Income": 69228 + }, + { + "Income": 108967 + }, + { + "Income": 32304 + }, + { + "Income": 179896 + }, + { + "Income": 171170 + }, + { + "Income": 27703 + }, + { + "Income": 70576 + }, + { + "Income": 96881 + }, + { + "Income": 122838 + }, + { + "Income": 61562 + }, + { + "Income": 151146 + }, + { + "Income": 95103 + }, + { + "Income": 112649 + }, + { + "Income": 167508 + }, + { + "Income": 40177 + }, + { + "Income": 21762 + }, + { + "Income": 121936 + }, + { + "Income": 197443 + }, + { + "Income": 65187 + }, + { + "Income": 64879 + }, + { + "Income": 93990 + }, + { + "Income": 132578 + }, + { + "Income": 132542 + }, + { + "Income": 81394 + }, + { + "Income": 116058 + }, + { + "Income": 45041 + }, + { + "Income": 48838 + }, + { + "Income": 135682 + }, + { + "Income": 102115 + }, + { + "Income": 67705 + }, + { + "Income": 74087 + }, + { + "Income": 53766 + }, + { + "Income": 166114 + }, + { + "Income": 197385 + }, + { + "Income": 173272 + }, + { + "Income": 84119 + }, + { + "Income": 193735 + }, + { + "Income": 23540 + }, + { + "Income": 112995 + }, + { + "Income": 40528 + }, + { + "Income": 154507 + }, + { + "Income": 53836 + }, + { + "Income": 88468 + }, + { + "Income": 198807 + }, + { + "Income": 131673 + }, + { + "Income": 41364 + }, + { + "Income": 171869 + }, + { + "Income": 86592 + }, + { + "Income": 169004 + }, + { + "Income": 177786 + }, + { + "Income": 168355 + }, + { + "Income": 67174 + }, + { + "Income": 156171 + }, + { + "Income": 120326 + }, + { + "Income": 142502 + }, + { + "Income": 77275 + }, + { + "Income": 186807 + }, + { + "Income": 36870 + }, + { + "Income": 47020 + }, + { + "Income": 186641 + }, + { + "Income": 139303 + }, + { + "Income": 131207 + }, + { + "Income": 136539 + }, + { + "Income": 102978 + }, + { + "Income": 169766 + }, + { + "Income": 22887 + }, + { + "Income": 122073 + }, + { + "Income": 160779 + }, + { + "Income": 168158 + }, + { + "Income": 171425 + }, + { + "Income": 171741 + }, + { + "Income": 88001 + }, + { + "Income": 86395 + }, + { + "Income": 103647 + }, + { + "Income": 77123 + }, + { + "Income": 154113 + }, + { + "Income": 94231 + }, + { + "Income": 42846 + }, + { + "Income": 57788 + }, + { + "Income": 88410 + }, + { + "Income": 121789 + }, + { + "Income": 73537 + }, + { + "Income": 176663 + }, + { + "Income": 21291 + }, + { + "Income": 124116 + }, + { + "Income": 115507 + }, + { + "Income": 145027 + }, + { + "Income": 24510 + }, + { + "Income": 32720 + }, + { + "Income": 136916 + }, + { + "Income": 141869 + }, + { + "Income": 57464 + }, + { + "Income": 38891 + }, + { + "Income": 179999 + }, + { + "Income": 104912 + }, + { + "Income": 104083 + }, + { + "Income": 199172 + }, + { + "Income": 143449 + }, + { + "Income": 141975 + }, + { + "Income": 34860 + }, + { + "Income": 108330 + }, + { + "Income": 118176 + }, + { + "Income": 185975 + }, + { + "Income": 97729 + }, + { + "Income": 152365 + }, + { + "Income": 59506 + }, + { + "Income": 161625 + }, + { + "Income": 172577 + }, + { + "Income": 97729 + }, + { + "Income": 154561 + }, + { + "Income": 71640 + }, + { + "Income": 159591 + }, + { + "Income": 178977 + }, + { + "Income": 22871 + }, + { + "Income": 38888 + }, + { + "Income": 133301 + }, + { + "Income": 42607 + }, + { + "Income": 183134 + }, + { + "Income": 56392 + }, + { + "Income": 197241 + }, + { + "Income": 91923 + }, + { + "Income": 128103 + }, + { + "Income": 164760 + }, + { + "Income": 118796 + }, + { + "Income": 161709 + }, + { + "Income": 149863 + }, + { + "Income": 128368 + }, + { + "Income": 118860 + }, + { + "Income": 156065 + }, + { + "Income": 136624 + }, + { + "Income": 92022 + }, + { + "Income": 166993 + }, + { + "Income": 37949 + }, + { + "Income": 187417 + }, + { + "Income": 43377 + }, + { + "Income": 159209 + }, + { + "Income": 69733 + }, + { + "Income": 135688 + }, + { + "Income": 35522 + }, + { + "Income": 77609 + }, + { + "Income": 27223 + }, + { + "Income": 99292 + }, + { + "Income": 135180 + }, + { + "Income": 134820 + }, + { + "Income": 26697 + }, + { + "Income": 78258 + }, + { + "Income": 143202 + }, + { + "Income": 140091 + }, + { + "Income": 56158 + }, + { + "Income": 50749 + }, + { + "Income": 41519 + }, + { + "Income": 76164 + }, + { + "Income": 46806 + }, + { + "Income": 185301 + }, + { + "Income": 107862 + }, + { + "Income": 170854 + }, + { + "Income": 122678 + }, + { + "Income": 74677 + }, + { + "Income": 71069 + }, + { + "Income": 101626 + }, + { + "Income": 131942 + }, + { + "Income": 66940 + }, + { + "Income": 179034 + }, + { + "Income": 88008 + }, + { + "Income": 26877 + }, + { + "Income": 38450 + }, + { + "Income": 147247 + }, + { + "Income": 81012 + }, + { + "Income": 163569 + }, + { + "Income": 90628 + }, + { + "Income": 137665 + }, + { + "Income": 129098 + }, + { + "Income": 148036 + }, + { + "Income": 195079 + }, + { + "Income": 110365 + }, + { + "Income": 123136 + }, + { + "Income": 30563 + }, + { + "Income": 69639 + }, + { + "Income": 190544 + }, + { + "Income": 38790 + }, + { + "Income": 101106 + }, + { + "Income": 25258 + }, + { + "Income": 185090 + }, + { + "Income": 168258 + }, + { + "Income": 51577 + }, + { + "Income": 98900 + }, + { + "Income": 39825 + }, + { + "Income": 41222 + }, + { + "Income": 123058 + }, + { + "Income": 153668 + }, + { + "Income": 178932 + }, + { + "Income": 172619 + }, + { + "Income": 95549 + }, + { + "Income": 50568 + }, + { + "Income": 56142 + }, + { + "Income": 138255 + }, + { + "Income": 157734 + }, + { + "Income": 123419 + }, + { + "Income": 101703 + }, + { + "Income": 155289 + }, + { + "Income": 58288 + }, + { + "Income": 199633 + }, + { + "Income": 158285 + }, + { + "Income": 199996 + }, + { + "Income": 134634 + }, + { + "Income": 136393 + }, + { + "Income": 184349 + }, + { + "Income": 134098 + }, + { + "Income": 128033 + }, + { + "Income": 72876 + }, + { + "Income": 43365 + }, + { + "Income": 141885 + }, + { + "Income": 136418 + }, + { + "Income": 64933 + }, + { + "Income": 110649 + }, + { + "Income": 34460 + }, + { + "Income": 57429 + }, + { + "Income": 173733 + }, + { + "Income": 88424 + }, + { + "Income": 183985 + }, + { + "Income": 140344 + }, + { + "Income": 164749 + }, + { + "Income": 112485 + }, + { + "Income": 113632 + }, + { + "Income": 137141 + }, + { + "Income": 154306 + }, + { + "Income": 107079 + }, + { + "Income": 154396 + }, + { + "Income": 174130 + }, + { + "Income": 110850 + }, + { + "Income": 169232 + }, + { + "Income": 48827 + }, + { + "Income": 133372 + }, + { + "Income": 156155 + }, + { + "Income": 40424 + }, + { + "Income": 21973 + }, + { + "Income": 52597 + }, + { + "Income": 136382 + }, + { + "Income": 164100 + }, + { + "Income": 187743 + }, + { + "Income": 122681 + }, + { + "Income": 119621 + }, + { + "Income": 175756 + }, + { + "Income": 71422 + }, + { + "Income": 91227 + }, + { + "Income": 140010 + }, + { + "Income": 120333 + }, + { + "Income": 72066 + }, + { + "Income": 116864 + }, + { + "Income": 87506 + }, + { + "Income": 46834 + }, + { + "Income": 126062 + }, + { + "Income": 66358 + }, + { + "Income": 111940 + }, + { + "Income": 135615 + }, + { + "Income": 64299 + }, + { + "Income": 67930 + }, + { + "Income": 78070 + }, + { + "Income": 38893 + }, + { + "Income": 31862 + }, + { + "Income": 126817 + }, + { + "Income": 154695 + }, + { + "Income": 153935 + }, + { + "Income": 166736 + }, + { + "Income": 37373 + }, + { + "Income": 44783 + }, + { + "Income": 29520 + }, + { + "Income": 176875 + }, + { + "Income": 165080 + }, + { + "Income": 106727 + }, + { + "Income": 181076 + }, + { + "Income": 198862 + }, + { + "Income": 152984 + }, + { + "Income": 27724 + }, + { + "Income": 54344 + }, + { + "Income": 164780 + }, + { + "Income": 92804 + }, + { + "Income": 176725 + }, + { + "Income": 149768 + }, + { + "Income": 148470 + }, + { + "Income": 115426 + }, + { + "Income": 38568 + }, + { + "Income": 152882 + }, + { + "Income": 111626 + }, + { + "Income": 69908 + }, + { + "Income": 28383 + }, + { + "Income": 152959 + }, + { + "Income": 141324 + }, + { + "Income": 79956 + }, + { + "Income": 53374 + }, + { + "Income": 52856 + }, + { + "Income": 178989 + }, + { + "Income": 47795 + }, + { + "Income": 64872 + }, + { + "Income": 156375 + }, + { + "Income": 140067 + }, + { + "Income": 180648 + }, + { + "Income": 38039 + }, + { + "Income": 79359 + }, + { + "Income": 102010 + }, + { + "Income": 101404 + }, + { + "Income": 183139 + }, + { + "Income": 142142 + }, + { + "Income": 144171 + }, + { + "Income": 37196 + }, + { + "Income": 134138 + }, + { + "Income": 82273 + }, + { + "Income": 127017 + }, + { + "Income": 90751 + }, + { + "Income": 59020 + }, + { + "Income": 87368 + }, + { + "Income": 75043 + }, + { + "Income": 114927 + }, + { + "Income": 114046 + }, + { + "Income": 66933 + }, + { + "Income": 59780 + }, + { + "Income": 75699 + }, + { + "Income": 160556 + }, + { + "Income": 198719 + }, + { + "Income": 85156 + }, + { + "Income": 161652 + }, + { + "Income": 79348 + }, + { + "Income": 102350 + }, + { + "Income": 51509 + }, + { + "Income": 28708 + }, + { + "Income": 39790 + }, + { + "Income": 167333 + }, + { + "Income": 162665 + }, + { + "Income": 189219 + }, + { + "Income": 86760 + }, + { + "Income": 121756 + }, + { + "Income": 44958 + }, + { + "Income": 97370 + }, + { + "Income": 49791 + }, + { + "Income": 133990 + }, + { + "Income": 105855 + }, + { + "Income": 101582 + }, + { + "Income": 116423 + }, + { + "Income": 55595 + }, + { + "Income": 117984 + }, + { + "Income": 22897 + }, + { + "Income": 104356 + }, + { + "Income": 117323 + }, + { + "Income": 72092 + }, + { + "Income": 192889 + }, + { + "Income": 25481 + }, + { + "Income": 167450 + }, + { + "Income": 158153 + }, + { + "Income": 135829 + }, + { + "Income": 60575 + }, + { + "Income": 121269 + }, + { + "Income": 146219 + }, + { + "Income": 80253 + }, + { + "Income": 186484 + }, + { + "Income": 197025 + }, + { + "Income": 53384 + }, + { + "Income": 50708 + }, + { + "Income": 67871 + }, + { + "Income": 166724 + }, + { + "Income": 184005 + }, + { + "Income": 120049 + }, + { + "Income": 168751 + }, + { + "Income": 52616 + }, + { + "Income": 94338 + }, + { + "Income": 45635 + }, + { + "Income": 121581 + }, + { + "Income": 168055 + }, + { + "Income": 53205 + }, + { + "Income": 90485 + }, + { + "Income": 82936 + }, + { + "Income": 113606 + }, + { + "Income": 60340 + }, + { + "Income": 130413 + }, + { + "Income": 105527 + }, + { + "Income": 173385 + }, + { + "Income": 184804 + }, + { + "Income": 45843 + }, + { + "Income": 197694 + }, + { + "Income": 137104 + }, + { + "Income": 68431 + }, + { + "Income": 44900 + }, + { + "Income": 186556 + }, + { + "Income": 144735 + }, + { + "Income": 153563 + }, + { + "Income": 34343 + }, + { + "Income": 68986 + }, + { + "Income": 194809 + }, + { + "Income": 75409 + }, + { + "Income": 132148 + }, + { + "Income": 105496 + }, + { + "Income": 184546 + }, + { + "Income": 24414 + }, + { + "Income": 51038 + }, + { + "Income": 38650 + }, + { + "Income": 97032 + }, + { + "Income": 136531 + }, + { + "Income": 151497 + }, + { + "Income": 46495 + }, + { + "Income": 174819 + }, + { + "Income": 169933 + }, + { + "Income": 119054 + }, + { + "Income": 186378 + }, + { + "Income": 33163 + }, + { + "Income": 27425 + }, + { + "Income": 71414 + }, + { + "Income": 130070 + }, + { + "Income": 100786 + }, + { + "Income": 46733 + }, + { + "Income": 35730 + }, + { + "Income": 151072 + }, + { + "Income": 100208 + }, + { + "Income": 61668 + }, + { + "Income": 139833 + }, + { + "Income": 34109 + }, + { + "Income": 82624 + }, + { + "Income": 83115 + }, + { + "Income": 57117 + }, + { + "Income": 147374 + }, + { + "Income": 49261 + }, + { + "Income": 55220 + }, + { + "Income": 123829 + }, + { + "Income": 155719 + }, + { + "Income": 88823 + }, + { + "Income": 40243 + }, + { + "Income": 48109 + }, + { + "Income": 125190 + }, + { + "Income": 168524 + }, + { + "Income": 20773 + }, + { + "Income": 56778 + }, + { + "Income": 26733 + }, + { + "Income": 144447 + }, + { + "Income": 185752 + }, + { + "Income": 138753 + }, + { + "Income": 53704 + }, + { + "Income": 27948 + }, + { + "Income": 43988 + }, + { + "Income": 163740 + }, + { + "Income": 83369 + }, + { + "Income": 178212 + }, + { + "Income": 124403 + }, + { + "Income": 76885 + }, + { + "Income": 112340 + }, + { + "Income": 22890 + }, + { + "Income": 164210 + }, + { + "Income": 57599 + }, + { + "Income": 152101 + }, + { + "Income": 114562 + }, + { + "Income": 99892 + }, + { + "Income": 139881 + }, + { + "Income": 113668 + }, + { + "Income": 197705 + }, + { + "Income": 155387 + }, + { + "Income": 81971 + }, + { + "Income": 81746 + }, + { + "Income": 90205 + }, + { + "Income": 58592 + }, + { + "Income": 103961 + }, + { + "Income": 138163 + }, + { + "Income": 48784 + }, + { + "Income": 131524 + }, + { + "Income": 68172 + }, + { + "Income": 186311 + }, + { + "Income": 172777 + }, + { + "Income": 41164 + }, + { + "Income": 35057 + }, + { + "Income": 191185 + }, + { + "Income": 188395 + }, + { + "Income": 87484 + }, + { + "Income": 51464 + }, + { + "Income": 176023 + }, + { + "Income": 66614 + }, + { + "Income": 97130 + }, + { + "Income": 160219 + }, + { + "Income": 128317 + }, + { + "Income": 162450 + }, + { + "Income": 183644 + }, + { + "Income": 162852 + }, + { + "Income": 98475 + }, + { + "Income": 84685 + }, + { + "Income": 159371 + }, + { + "Income": 96657 + }, + { + "Income": 137828 + }, + { + "Income": 175603 + }, + { + "Income": 194044 + }, + { + "Income": 183667 + }, + { + "Income": 186874 + }, + { + "Income": 87310 + }, + { + "Income": 174616 + }, + { + "Income": 178931 + }, + { + "Income": 147666 + }, + { + "Income": 108357 + }, + { + "Income": 43895 + }, + { + "Income": 43580 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/line-chart/00-card30.flint.json b/test-harness/excel/evaluations/inputs/line-chart/00-card30.flint.json new file mode 100644 index 00000000..d029f8ac --- /dev/null +++ b/test-harness/excel/evaluations/inputs/line-chart/00-card30.flint.json @@ -0,0 +1,141 @@ +{ + "semantic_types": { + "Date": "Date", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Line Chart", + "encodings": { + "x": "Date", + "y": "Value" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Date": "2020-01-01", + "Value": 51 + }, + { + "Date": "2020-02-06", + "Value": 46 + }, + { + "Date": "2020-03-14", + "Value": 31 + }, + { + "Date": "2020-04-19", + "Value": 26 + }, + { + "Date": "2020-05-26", + "Value": 18 + }, + { + "Date": "2020-07-01", + "Value": 2 + }, + { + "Date": "2020-08-07", + "Value": 0 + }, + { + "Date": "2020-09-12", + "Value": 0 + }, + { + "Date": "2020-10-19", + "Value": 5 + }, + { + "Date": "2020-11-24", + "Value": 0 + }, + { + "Date": "2020-12-31", + "Value": 0 + }, + { + "Date": "2021-02-05", + "Value": 1 + }, + { + "Date": "2021-03-14", + "Value": 11 + }, + { + "Date": "2021-04-19", + "Value": 2 + }, + { + "Date": "2021-05-26", + "Value": 8 + }, + { + "Date": "2021-07-01", + "Value": 19 + }, + { + "Date": "2021-08-07", + "Value": 31 + }, + { + "Date": "2021-09-12", + "Value": 23 + }, + { + "Date": "2021-10-19", + "Value": 2 + }, + { + "Date": "2021-11-24", + "Value": 0 + }, + { + "Date": "2021-12-31", + "Value": 0 + }, + { + "Date": "2022-02-05", + "Value": 0 + }, + { + "Date": "2022-03-14", + "Value": 0 + }, + { + "Date": "2022-04-19", + "Value": 0 + }, + { + "Date": "2022-05-26", + "Value": 0 + }, + { + "Date": "2022-07-01", + "Value": 0 + }, + { + "Date": "2022-08-07", + "Value": 0 + }, + { + "Date": "2022-09-12", + "Value": 0 + }, + { + "Date": "2022-10-19", + "Value": 0 + }, + { + "Date": "2022-11-24", + "Value": 0 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/line-chart/01-card50.flint.json b/test-harness/excel/evaluations/inputs/line-chart/01-card50.flint.json new file mode 100644 index 00000000..b88d0a4d --- /dev/null +++ b/test-harness/excel/evaluations/inputs/line-chart/01-card50.flint.json @@ -0,0 +1,1023 @@ +{ + "semantic_types": { + "Date": "Date", + "Value": "Quantity", + "Series": "Category" + }, + "chart_spec": { + "chartType": "Line Chart", + "encodings": { + "x": "Date", + "y": "Value", + "color": "Series" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Date": "2020-01-01", + "Value": 114, + "Series": "Electronics" + }, + { + "Date": "2020-01-22", + "Value": 113, + "Series": "Electronics" + }, + { + "Date": "2020-02-13", + "Value": 116, + "Series": "Electronics" + }, + { + "Date": "2020-03-06", + "Value": 129, + "Series": "Electronics" + }, + { + "Date": "2020-03-28", + "Value": 140, + "Series": "Electronics" + }, + { + "Date": "2020-04-19", + "Value": 156, + "Series": "Electronics" + }, + { + "Date": "2020-05-11", + "Value": 170, + "Series": "Electronics" + }, + { + "Date": "2020-06-02", + "Value": 173, + "Series": "Electronics" + }, + { + "Date": "2020-06-24", + "Value": 168, + "Series": "Electronics" + }, + { + "Date": "2020-07-16", + "Value": 165, + "Series": "Electronics" + }, + { + "Date": "2020-08-07", + "Value": 166, + "Series": "Electronics" + }, + { + "Date": "2020-08-28", + "Value": 155, + "Series": "Electronics" + }, + { + "Date": "2020-09-19", + "Value": 157, + "Series": "Electronics" + }, + { + "Date": "2020-10-11", + "Value": 161, + "Series": "Electronics" + }, + { + "Date": "2020-11-02", + "Value": 175, + "Series": "Electronics" + }, + { + "Date": "2020-11-24", + "Value": 193, + "Series": "Electronics" + }, + { + "Date": "2020-12-16", + "Value": 209, + "Series": "Electronics" + }, + { + "Date": "2021-01-07", + "Value": 228, + "Series": "Electronics" + }, + { + "Date": "2021-01-29", + "Value": 251, + "Series": "Electronics" + }, + { + "Date": "2021-02-20", + "Value": 271, + "Series": "Electronics" + }, + { + "Date": "2021-03-14", + "Value": 289, + "Series": "Electronics" + }, + { + "Date": "2021-04-04", + "Value": 312, + "Series": "Electronics" + }, + { + "Date": "2021-04-26", + "Value": 330, + "Series": "Electronics" + }, + { + "Date": "2021-05-18", + "Value": 352, + "Series": "Electronics" + }, + { + "Date": "2021-06-09", + "Value": 377, + "Series": "Electronics" + }, + { + "Date": "2021-07-01", + "Value": 397, + "Series": "Electronics" + }, + { + "Date": "2021-07-23", + "Value": 412, + "Series": "Electronics" + }, + { + "Date": "2021-08-14", + "Value": 418, + "Series": "Electronics" + }, + { + "Date": "2021-09-05", + "Value": 429, + "Series": "Electronics" + }, + { + "Date": "2021-09-27", + "Value": 442, + "Series": "Electronics" + }, + { + "Date": "2021-10-19", + "Value": 458, + "Series": "Electronics" + }, + { + "Date": "2021-11-09", + "Value": 467, + "Series": "Electronics" + }, + { + "Date": "2021-12-01", + "Value": 485, + "Series": "Electronics" + }, + { + "Date": "2021-12-23", + "Value": 495, + "Series": "Electronics" + }, + { + "Date": "2022-01-14", + "Value": 506, + "Series": "Electronics" + }, + { + "Date": "2022-02-05", + "Value": 513, + "Series": "Electronics" + }, + { + "Date": "2022-02-27", + "Value": 521, + "Series": "Electronics" + }, + { + "Date": "2022-03-21", + "Value": 521, + "Series": "Electronics" + }, + { + "Date": "2022-04-12", + "Value": 519, + "Series": "Electronics" + }, + { + "Date": "2022-05-04", + "Value": 517, + "Series": "Electronics" + }, + { + "Date": "2022-05-26", + "Value": 510, + "Series": "Electronics" + }, + { + "Date": "2022-06-16", + "Value": 500, + "Series": "Electronics" + }, + { + "Date": "2022-07-08", + "Value": 501, + "Series": "Electronics" + }, + { + "Date": "2022-07-30", + "Value": 506, + "Series": "Electronics" + }, + { + "Date": "2022-08-21", + "Value": 512, + "Series": "Electronics" + }, + { + "Date": "2022-09-12", + "Value": 505, + "Series": "Electronics" + }, + { + "Date": "2022-10-04", + "Value": 510, + "Series": "Electronics" + }, + { + "Date": "2022-10-26", + "Value": 504, + "Series": "Electronics" + }, + { + "Date": "2022-11-17", + "Value": 505, + "Series": "Electronics" + }, + { + "Date": "2022-12-09", + "Value": 499, + "Series": "Electronics" + }, + { + "Date": "2020-01-01", + "Value": 154, + "Series": "Clothing" + }, + { + "Date": "2020-01-22", + "Value": 159, + "Series": "Clothing" + }, + { + "Date": "2020-02-13", + "Value": 166, + "Series": "Clothing" + }, + { + "Date": "2020-03-06", + "Value": 173, + "Series": "Clothing" + }, + { + "Date": "2020-03-28", + "Value": 175, + "Series": "Clothing" + }, + { + "Date": "2020-04-19", + "Value": 179, + "Series": "Clothing" + }, + { + "Date": "2020-05-11", + "Value": 177, + "Series": "Clothing" + }, + { + "Date": "2020-06-02", + "Value": 181, + "Series": "Clothing" + }, + { + "Date": "2020-06-24", + "Value": 187, + "Series": "Clothing" + }, + { + "Date": "2020-07-16", + "Value": 193, + "Series": "Clothing" + }, + { + "Date": "2020-08-07", + "Value": 203, + "Series": "Clothing" + }, + { + "Date": "2020-08-28", + "Value": 212, + "Series": "Clothing" + }, + { + "Date": "2020-09-19", + "Value": 219, + "Series": "Clothing" + }, + { + "Date": "2020-10-11", + "Value": 221, + "Series": "Clothing" + }, + { + "Date": "2020-11-02", + "Value": 227, + "Series": "Clothing" + }, + { + "Date": "2020-11-24", + "Value": 233, + "Series": "Clothing" + }, + { + "Date": "2020-12-16", + "Value": 234, + "Series": "Clothing" + }, + { + "Date": "2021-01-07", + "Value": 233, + "Series": "Clothing" + }, + { + "Date": "2021-01-29", + "Value": 235, + "Series": "Clothing" + }, + { + "Date": "2021-02-20", + "Value": 235, + "Series": "Clothing" + }, + { + "Date": "2021-03-14", + "Value": 241, + "Series": "Clothing" + }, + { + "Date": "2021-04-04", + "Value": 242, + "Series": "Clothing" + }, + { + "Date": "2021-04-26", + "Value": 249, + "Series": "Clothing" + }, + { + "Date": "2021-05-18", + "Value": 253, + "Series": "Clothing" + }, + { + "Date": "2021-06-09", + "Value": 260, + "Series": "Clothing" + }, + { + "Date": "2021-07-01", + "Value": 267, + "Series": "Clothing" + }, + { + "Date": "2021-07-23", + "Value": 267, + "Series": "Clothing" + }, + { + "Date": "2021-08-14", + "Value": 263, + "Series": "Clothing" + }, + { + "Date": "2021-09-05", + "Value": 266, + "Series": "Clothing" + }, + { + "Date": "2021-09-27", + "Value": 271, + "Series": "Clothing" + }, + { + "Date": "2021-10-19", + "Value": 274, + "Series": "Clothing" + }, + { + "Date": "2021-11-09", + "Value": 281, + "Series": "Clothing" + }, + { + "Date": "2021-12-01", + "Value": 283, + "Series": "Clothing" + }, + { + "Date": "2021-12-23", + "Value": 289, + "Series": "Clothing" + }, + { + "Date": "2022-01-14", + "Value": 295, + "Series": "Clothing" + }, + { + "Date": "2022-02-05", + "Value": 303, + "Series": "Clothing" + }, + { + "Date": "2022-02-27", + "Value": 306, + "Series": "Clothing" + }, + { + "Date": "2022-03-21", + "Value": 309, + "Series": "Clothing" + }, + { + "Date": "2022-04-12", + "Value": 314, + "Series": "Clothing" + }, + { + "Date": "2022-05-04", + "Value": 321, + "Series": "Clothing" + }, + { + "Date": "2022-05-26", + "Value": 327, + "Series": "Clothing" + }, + { + "Date": "2022-06-16", + "Value": 327, + "Series": "Clothing" + }, + { + "Date": "2022-07-08", + "Value": 332, + "Series": "Clothing" + }, + { + "Date": "2022-07-30", + "Value": 338, + "Series": "Clothing" + }, + { + "Date": "2022-08-21", + "Value": 348, + "Series": "Clothing" + }, + { + "Date": "2022-09-12", + "Value": 355, + "Series": "Clothing" + }, + { + "Date": "2022-10-04", + "Value": 360, + "Series": "Clothing" + }, + { + "Date": "2022-10-26", + "Value": 360, + "Series": "Clothing" + }, + { + "Date": "2022-11-17", + "Value": 357, + "Series": "Clothing" + }, + { + "Date": "2022-12-09", + "Value": 351, + "Series": "Clothing" + }, + { + "Date": "2020-01-01", + "Value": 212, + "Series": "Food" + }, + { + "Date": "2020-01-22", + "Value": 215, + "Series": "Food" + }, + { + "Date": "2020-02-13", + "Value": 226, + "Series": "Food" + }, + { + "Date": "2020-03-06", + "Value": 234, + "Series": "Food" + }, + { + "Date": "2020-03-28", + "Value": 235, + "Series": "Food" + }, + { + "Date": "2020-04-19", + "Value": 232, + "Series": "Food" + }, + { + "Date": "2020-05-11", + "Value": 219, + "Series": "Food" + }, + { + "Date": "2020-06-02", + "Value": 204, + "Series": "Food" + }, + { + "Date": "2020-06-24", + "Value": 198, + "Series": "Food" + }, + { + "Date": "2020-07-16", + "Value": 203, + "Series": "Food" + }, + { + "Date": "2020-08-07", + "Value": 219, + "Series": "Food" + }, + { + "Date": "2020-08-28", + "Value": 224, + "Series": "Food" + }, + { + "Date": "2020-09-19", + "Value": 217, + "Series": "Food" + }, + { + "Date": "2020-10-11", + "Value": 223, + "Series": "Food" + }, + { + "Date": "2020-11-02", + "Value": 222, + "Series": "Food" + }, + { + "Date": "2020-11-24", + "Value": 212, + "Series": "Food" + }, + { + "Date": "2020-12-16", + "Value": 203, + "Series": "Food" + }, + { + "Date": "2021-01-07", + "Value": 200, + "Series": "Food" + }, + { + "Date": "2021-01-29", + "Value": 201, + "Series": "Food" + }, + { + "Date": "2021-02-20", + "Value": 210, + "Series": "Food" + }, + { + "Date": "2021-03-14", + "Value": 218, + "Series": "Food" + }, + { + "Date": "2021-04-04", + "Value": 225, + "Series": "Food" + }, + { + "Date": "2021-04-26", + "Value": 218, + "Series": "Food" + }, + { + "Date": "2021-05-18", + "Value": 220, + "Series": "Food" + }, + { + "Date": "2021-06-09", + "Value": 233, + "Series": "Food" + }, + { + "Date": "2021-07-01", + "Value": 251, + "Series": "Food" + }, + { + "Date": "2021-07-23", + "Value": 268, + "Series": "Food" + }, + { + "Date": "2021-08-14", + "Value": 289, + "Series": "Food" + }, + { + "Date": "2021-09-05", + "Value": 306, + "Series": "Food" + }, + { + "Date": "2021-09-27", + "Value": 329, + "Series": "Food" + }, + { + "Date": "2021-10-19", + "Value": 333, + "Series": "Food" + }, + { + "Date": "2021-11-09", + "Value": 324, + "Series": "Food" + }, + { + "Date": "2021-12-01", + "Value": 327, + "Series": "Food" + }, + { + "Date": "2021-12-23", + "Value": 322, + "Series": "Food" + }, + { + "Date": "2022-01-14", + "Value": 319, + "Series": "Food" + }, + { + "Date": "2022-02-05", + "Value": 309, + "Series": "Food" + }, + { + "Date": "2022-02-27", + "Value": 307, + "Series": "Food" + }, + { + "Date": "2022-03-21", + "Value": 303, + "Series": "Food" + }, + { + "Date": "2022-04-12", + "Value": 295, + "Series": "Food" + }, + { + "Date": "2022-05-04", + "Value": 285, + "Series": "Food" + }, + { + "Date": "2022-05-26", + "Value": 282, + "Series": "Food" + }, + { + "Date": "2022-06-16", + "Value": 272, + "Series": "Food" + }, + { + "Date": "2022-07-08", + "Value": 273, + "Series": "Food" + }, + { + "Date": "2022-07-30", + "Value": 263, + "Series": "Food" + }, + { + "Date": "2022-08-21", + "Value": 266, + "Series": "Food" + }, + { + "Date": "2022-09-12", + "Value": 260, + "Series": "Food" + }, + { + "Date": "2022-10-04", + "Value": 261, + "Series": "Food" + }, + { + "Date": "2022-10-26", + "Value": 259, + "Series": "Food" + }, + { + "Date": "2022-11-17", + "Value": 254, + "Series": "Food" + }, + { + "Date": "2022-12-09", + "Value": 238, + "Series": "Food" + }, + { + "Date": "2020-01-01", + "Value": 248, + "Series": "Books" + }, + { + "Date": "2020-01-22", + "Value": 252, + "Series": "Books" + }, + { + "Date": "2020-02-13", + "Value": 252, + "Series": "Books" + }, + { + "Date": "2020-03-06", + "Value": 246, + "Series": "Books" + }, + { + "Date": "2020-03-28", + "Value": 242, + "Series": "Books" + }, + { + "Date": "2020-04-19", + "Value": 243, + "Series": "Books" + }, + { + "Date": "2020-05-11", + "Value": 245, + "Series": "Books" + }, + { + "Date": "2020-06-02", + "Value": 242, + "Series": "Books" + }, + { + "Date": "2020-06-24", + "Value": 241, + "Series": "Books" + }, + { + "Date": "2020-07-16", + "Value": 240, + "Series": "Books" + }, + { + "Date": "2020-08-07", + "Value": 237, + "Series": "Books" + }, + { + "Date": "2020-08-28", + "Value": 240, + "Series": "Books" + }, + { + "Date": "2020-09-19", + "Value": 244, + "Series": "Books" + }, + { + "Date": "2020-10-11", + "Value": 248, + "Series": "Books" + }, + { + "Date": "2020-11-02", + "Value": 256, + "Series": "Books" + }, + { + "Date": "2020-11-24", + "Value": 260, + "Series": "Books" + }, + { + "Date": "2020-12-16", + "Value": 260, + "Series": "Books" + }, + { + "Date": "2021-01-07", + "Value": 257, + "Series": "Books" + }, + { + "Date": "2021-01-29", + "Value": 257, + "Series": "Books" + }, + { + "Date": "2021-02-20", + "Value": 261, + "Series": "Books" + }, + { + "Date": "2021-03-14", + "Value": 265, + "Series": "Books" + }, + { + "Date": "2021-04-04", + "Value": 267, + "Series": "Books" + }, + { + "Date": "2021-04-26", + "Value": 271, + "Series": "Books" + }, + { + "Date": "2021-05-18", + "Value": 267, + "Series": "Books" + }, + { + "Date": "2021-06-09", + "Value": 263, + "Series": "Books" + }, + { + "Date": "2021-07-01", + "Value": 254, + "Series": "Books" + }, + { + "Date": "2021-07-23", + "Value": 254, + "Series": "Books" + }, + { + "Date": "2021-08-14", + "Value": 247, + "Series": "Books" + }, + { + "Date": "2021-09-05", + "Value": 247, + "Series": "Books" + }, + { + "Date": "2021-09-27", + "Value": 248, + "Series": "Books" + }, + { + "Date": "2021-10-19", + "Value": 247, + "Series": "Books" + }, + { + "Date": "2021-11-09", + "Value": 245, + "Series": "Books" + }, + { + "Date": "2021-12-01", + "Value": 250, + "Series": "Books" + }, + { + "Date": "2021-12-23", + "Value": 247, + "Series": "Books" + }, + { + "Date": "2022-01-14", + "Value": 244, + "Series": "Books" + }, + { + "Date": "2022-02-05", + "Value": 244, + "Series": "Books" + }, + { + "Date": "2022-02-27", + "Value": 251, + "Series": "Books" + }, + { + "Date": "2022-03-21", + "Value": 263, + "Series": "Books" + }, + { + "Date": "2022-04-12", + "Value": 266, + "Series": "Books" + }, + { + "Date": "2022-05-04", + "Value": 262, + "Series": "Books" + }, + { + "Date": "2022-05-26", + "Value": 257, + "Series": "Books" + }, + { + "Date": "2022-06-16", + "Value": 255, + "Series": "Books" + }, + { + "Date": "2022-07-08", + "Value": 250, + "Series": "Books" + }, + { + "Date": "2022-07-30", + "Value": 250, + "Series": "Books" + }, + { + "Date": "2022-08-21", + "Value": 257, + "Series": "Books" + }, + { + "Date": "2022-09-12", + "Value": 262, + "Series": "Books" + }, + { + "Date": "2022-10-04", + "Value": 259, + "Series": "Books" + }, + { + "Date": "2022-10-26", + "Value": 255, + "Series": "Books" + }, + { + "Date": "2022-11-17", + "Value": 252, + "Series": "Books" + }, + { + "Date": "2022-12-09", + "Value": 246, + "Series": "Books" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/line-chart/02-card100.flint.json b/test-harness/excel/evaluations/inputs/line-chart/02-card100.flint.json new file mode 100644 index 00000000..59ed80e7 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/line-chart/02-card100.flint.json @@ -0,0 +1,4023 @@ +{ + "semantic_types": { + "Date": "Date", + "Value": "Quantity", + "Series": "Category" + }, + "chart_spec": { + "chartType": "Line Chart", + "encodings": { + "x": "Date", + "y": "Value", + "color": "Series" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Date": "2020-01-01", + "Value": 173, + "Series": "Electronics" + }, + { + "Date": "2020-01-11", + "Value": 175, + "Series": "Electronics" + }, + { + "Date": "2020-01-22", + "Value": 175, + "Series": "Electronics" + }, + { + "Date": "2020-02-02", + "Value": 181, + "Series": "Electronics" + }, + { + "Date": "2020-02-13", + "Value": 193, + "Series": "Electronics" + }, + { + "Date": "2020-02-24", + "Value": 208, + "Series": "Electronics" + }, + { + "Date": "2020-03-06", + "Value": 219, + "Series": "Electronics" + }, + { + "Date": "2020-03-17", + "Value": 236, + "Series": "Electronics" + }, + { + "Date": "2020-03-28", + "Value": 240, + "Series": "Electronics" + }, + { + "Date": "2020-04-08", + "Value": 251, + "Series": "Electronics" + }, + { + "Date": "2020-04-19", + "Value": 258, + "Series": "Electronics" + }, + { + "Date": "2020-04-30", + "Value": 256, + "Series": "Electronics" + }, + { + "Date": "2020-05-11", + "Value": 251, + "Series": "Electronics" + }, + { + "Date": "2020-05-22", + "Value": 253, + "Series": "Electronics" + }, + { + "Date": "2020-06-02", + "Value": 252, + "Series": "Electronics" + }, + { + "Date": "2020-06-13", + "Value": 252, + "Series": "Electronics" + }, + { + "Date": "2020-06-24", + "Value": 242, + "Series": "Electronics" + }, + { + "Date": "2020-07-05", + "Value": 233, + "Series": "Electronics" + }, + { + "Date": "2020-07-16", + "Value": 227, + "Series": "Electronics" + }, + { + "Date": "2020-07-27", + "Value": 225, + "Series": "Electronics" + }, + { + "Date": "2020-08-07", + "Value": 224, + "Series": "Electronics" + }, + { + "Date": "2020-08-17", + "Value": 220, + "Series": "Electronics" + }, + { + "Date": "2020-08-28", + "Value": 210, + "Series": "Electronics" + }, + { + "Date": "2020-09-08", + "Value": 210, + "Series": "Electronics" + }, + { + "Date": "2020-09-19", + "Value": 207, + "Series": "Electronics" + }, + { + "Date": "2020-09-30", + "Value": 200, + "Series": "Electronics" + }, + { + "Date": "2020-10-11", + "Value": 199, + "Series": "Electronics" + }, + { + "Date": "2020-10-22", + "Value": 190, + "Series": "Electronics" + }, + { + "Date": "2020-11-02", + "Value": 182, + "Series": "Electronics" + }, + { + "Date": "2020-11-13", + "Value": 181, + "Series": "Electronics" + }, + { + "Date": "2020-11-24", + "Value": 176, + "Series": "Electronics" + }, + { + "Date": "2020-12-05", + "Value": 166, + "Series": "Electronics" + }, + { + "Date": "2020-12-16", + "Value": 161, + "Series": "Electronics" + }, + { + "Date": "2020-12-27", + "Value": 154, + "Series": "Electronics" + }, + { + "Date": "2021-01-07", + "Value": 145, + "Series": "Electronics" + }, + { + "Date": "2021-01-18", + "Value": 139, + "Series": "Electronics" + }, + { + "Date": "2021-01-29", + "Value": 143, + "Series": "Electronics" + }, + { + "Date": "2021-02-09", + "Value": 146, + "Series": "Electronics" + }, + { + "Date": "2021-02-20", + "Value": 144, + "Series": "Electronics" + }, + { + "Date": "2021-03-03", + "Value": 141, + "Series": "Electronics" + }, + { + "Date": "2021-03-14", + "Value": 132, + "Series": "Electronics" + }, + { + "Date": "2021-03-24", + "Value": 122, + "Series": "Electronics" + }, + { + "Date": "2021-04-04", + "Value": 114, + "Series": "Electronics" + }, + { + "Date": "2021-04-15", + "Value": 105, + "Series": "Electronics" + }, + { + "Date": "2021-04-26", + "Value": 96, + "Series": "Electronics" + }, + { + "Date": "2021-05-07", + "Value": 95, + "Series": "Electronics" + }, + { + "Date": "2021-05-18", + "Value": 87, + "Series": "Electronics" + }, + { + "Date": "2021-05-29", + "Value": 90, + "Series": "Electronics" + }, + { + "Date": "2021-06-09", + "Value": 91, + "Series": "Electronics" + }, + { + "Date": "2021-06-20", + "Value": 98, + "Series": "Electronics" + }, + { + "Date": "2021-07-01", + "Value": 110, + "Series": "Electronics" + }, + { + "Date": "2021-07-12", + "Value": 126, + "Series": "Electronics" + }, + { + "Date": "2021-07-23", + "Value": 139, + "Series": "Electronics" + }, + { + "Date": "2021-08-03", + "Value": 141, + "Series": "Electronics" + }, + { + "Date": "2021-08-14", + "Value": 133, + "Series": "Electronics" + }, + { + "Date": "2021-08-25", + "Value": 130, + "Series": "Electronics" + }, + { + "Date": "2021-09-05", + "Value": 133, + "Series": "Electronics" + }, + { + "Date": "2021-09-16", + "Value": 131, + "Series": "Electronics" + }, + { + "Date": "2021-09-27", + "Value": 123, + "Series": "Electronics" + }, + { + "Date": "2021-10-08", + "Value": 127, + "Series": "Electronics" + }, + { + "Date": "2021-10-19", + "Value": 133, + "Series": "Electronics" + }, + { + "Date": "2021-10-29", + "Value": 143, + "Series": "Electronics" + }, + { + "Date": "2021-11-09", + "Value": 152, + "Series": "Electronics" + }, + { + "Date": "2021-11-20", + "Value": 166, + "Series": "Electronics" + }, + { + "Date": "2021-12-01", + "Value": 180, + "Series": "Electronics" + }, + { + "Date": "2021-12-12", + "Value": 195, + "Series": "Electronics" + }, + { + "Date": "2021-12-23", + "Value": 210, + "Series": "Electronics" + }, + { + "Date": "2022-01-03", + "Value": 212, + "Series": "Electronics" + }, + { + "Date": "2022-01-14", + "Value": 220, + "Series": "Electronics" + }, + { + "Date": "2022-01-25", + "Value": 234, + "Series": "Electronics" + }, + { + "Date": "2022-02-05", + "Value": 238, + "Series": "Electronics" + }, + { + "Date": "2022-02-16", + "Value": 236, + "Series": "Electronics" + }, + { + "Date": "2022-02-27", + "Value": 243, + "Series": "Electronics" + }, + { + "Date": "2022-03-10", + "Value": 247, + "Series": "Electronics" + }, + { + "Date": "2022-03-21", + "Value": 251, + "Series": "Electronics" + }, + { + "Date": "2022-04-01", + "Value": 257, + "Series": "Electronics" + }, + { + "Date": "2022-04-12", + "Value": 258, + "Series": "Electronics" + }, + { + "Date": "2022-04-23", + "Value": 265, + "Series": "Electronics" + }, + { + "Date": "2022-05-04", + "Value": 275, + "Series": "Electronics" + }, + { + "Date": "2022-05-15", + "Value": 288, + "Series": "Electronics" + }, + { + "Date": "2022-05-26", + "Value": 304, + "Series": "Electronics" + }, + { + "Date": "2022-06-05", + "Value": 305, + "Series": "Electronics" + }, + { + "Date": "2022-06-16", + "Value": 300, + "Series": "Electronics" + }, + { + "Date": "2022-06-27", + "Value": 289, + "Series": "Electronics" + }, + { + "Date": "2022-07-08", + "Value": 291, + "Series": "Electronics" + }, + { + "Date": "2022-07-19", + "Value": 284, + "Series": "Electronics" + }, + { + "Date": "2022-07-30", + "Value": 277, + "Series": "Electronics" + }, + { + "Date": "2022-08-10", + "Value": 274, + "Series": "Electronics" + }, + { + "Date": "2022-08-21", + "Value": 266, + "Series": "Electronics" + }, + { + "Date": "2022-09-01", + "Value": 253, + "Series": "Electronics" + }, + { + "Date": "2022-09-12", + "Value": 243, + "Series": "Electronics" + }, + { + "Date": "2022-09-23", + "Value": 243, + "Series": "Electronics" + }, + { + "Date": "2022-10-04", + "Value": 250, + "Series": "Electronics" + }, + { + "Date": "2022-10-15", + "Value": 255, + "Series": "Electronics" + }, + { + "Date": "2022-10-26", + "Value": 255, + "Series": "Electronics" + }, + { + "Date": "2022-11-06", + "Value": 248, + "Series": "Electronics" + }, + { + "Date": "2022-11-17", + "Value": 249, + "Series": "Electronics" + }, + { + "Date": "2022-11-28", + "Value": 242, + "Series": "Electronics" + }, + { + "Date": "2022-12-09", + "Value": 238, + "Series": "Electronics" + }, + { + "Date": "2022-12-20", + "Value": 239, + "Series": "Electronics" + }, + { + "Date": "2020-01-01", + "Value": 165, + "Series": "Clothing" + }, + { + "Date": "2020-01-11", + "Value": 178, + "Series": "Clothing" + }, + { + "Date": "2020-01-22", + "Value": 182, + "Series": "Clothing" + }, + { + "Date": "2020-02-02", + "Value": 168, + "Series": "Clothing" + }, + { + "Date": "2020-02-13", + "Value": 168, + "Series": "Clothing" + }, + { + "Date": "2020-02-24", + "Value": 162, + "Series": "Clothing" + }, + { + "Date": "2020-03-06", + "Value": 145, + "Series": "Clothing" + }, + { + "Date": "2020-03-17", + "Value": 132, + "Series": "Clothing" + }, + { + "Date": "2020-03-28", + "Value": 136, + "Series": "Clothing" + }, + { + "Date": "2020-04-08", + "Value": 136, + "Series": "Clothing" + }, + { + "Date": "2020-04-19", + "Value": 120, + "Series": "Clothing" + }, + { + "Date": "2020-04-30", + "Value": 126, + "Series": "Clothing" + }, + { + "Date": "2020-05-11", + "Value": 121, + "Series": "Clothing" + }, + { + "Date": "2020-05-22", + "Value": 109, + "Series": "Clothing" + }, + { + "Date": "2020-06-02", + "Value": 113, + "Series": "Clothing" + }, + { + "Date": "2020-06-13", + "Value": 100, + "Series": "Clothing" + }, + { + "Date": "2020-06-24", + "Value": 87, + "Series": "Clothing" + }, + { + "Date": "2020-07-05", + "Value": 93, + "Series": "Clothing" + }, + { + "Date": "2020-07-16", + "Value": 87, + "Series": "Clothing" + }, + { + "Date": "2020-07-27", + "Value": 66, + "Series": "Clothing" + }, + { + "Date": "2020-08-07", + "Value": 43, + "Series": "Clothing" + }, + { + "Date": "2020-08-17", + "Value": 9, + "Series": "Clothing" + }, + { + "Date": "2020-08-28", + "Value": 0, + "Series": "Clothing" + }, + { + "Date": "2020-09-08", + "Value": 0, + "Series": "Clothing" + }, + { + "Date": "2020-09-19", + "Value": 11, + "Series": "Clothing" + }, + { + "Date": "2020-09-30", + "Value": 20, + "Series": "Clothing" + }, + { + "Date": "2020-10-11", + "Value": 37, + "Series": "Clothing" + }, + { + "Date": "2020-10-22", + "Value": 56, + "Series": "Clothing" + }, + { + "Date": "2020-11-02", + "Value": 77, + "Series": "Clothing" + }, + { + "Date": "2020-11-13", + "Value": 110, + "Series": "Clothing" + }, + { + "Date": "2020-11-24", + "Value": 116, + "Series": "Clothing" + }, + { + "Date": "2020-12-05", + "Value": 102, + "Series": "Clothing" + }, + { + "Date": "2020-12-16", + "Value": 88, + "Series": "Clothing" + }, + { + "Date": "2020-12-27", + "Value": 75, + "Series": "Clothing" + }, + { + "Date": "2021-01-07", + "Value": 64, + "Series": "Clothing" + }, + { + "Date": "2021-01-18", + "Value": 47, + "Series": "Clothing" + }, + { + "Date": "2021-01-29", + "Value": 25, + "Series": "Clothing" + }, + { + "Date": "2021-02-09", + "Value": 8, + "Series": "Clothing" + }, + { + "Date": "2021-02-20", + "Value": 0, + "Series": "Clothing" + }, + { + "Date": "2021-03-03", + "Value": 0, + "Series": "Clothing" + }, + { + "Date": "2021-03-14", + "Value": 12, + "Series": "Clothing" + }, + { + "Date": "2021-03-24", + "Value": 18, + "Series": "Clothing" + }, + { + "Date": "2021-04-04", + "Value": 4, + "Series": "Clothing" + }, + { + "Date": "2021-04-15", + "Value": 11, + "Series": "Clothing" + }, + { + "Date": "2021-04-26", + "Value": 12, + "Series": "Clothing" + }, + { + "Date": "2021-05-07", + "Value": 21, + "Series": "Clothing" + }, + { + "Date": "2021-05-18", + "Value": 20, + "Series": "Clothing" + }, + { + "Date": "2021-05-29", + "Value": 27, + "Series": "Clothing" + }, + { + "Date": "2021-06-09", + "Value": 34, + "Series": "Clothing" + }, + { + "Date": "2021-06-20", + "Value": 36, + "Series": "Clothing" + }, + { + "Date": "2021-07-01", + "Value": 55, + "Series": "Clothing" + }, + { + "Date": "2021-07-12", + "Value": 82, + "Series": "Clothing" + }, + { + "Date": "2021-07-23", + "Value": 119, + "Series": "Clothing" + }, + { + "Date": "2021-08-03", + "Value": 156, + "Series": "Clothing" + }, + { + "Date": "2021-08-14", + "Value": 163, + "Series": "Clothing" + }, + { + "Date": "2021-08-25", + "Value": 182, + "Series": "Clothing" + }, + { + "Date": "2021-09-05", + "Value": 207, + "Series": "Clothing" + }, + { + "Date": "2021-09-16", + "Value": 239, + "Series": "Clothing" + }, + { + "Date": "2021-09-27", + "Value": 245, + "Series": "Clothing" + }, + { + "Date": "2021-10-08", + "Value": 234, + "Series": "Clothing" + }, + { + "Date": "2021-10-19", + "Value": 223, + "Series": "Clothing" + }, + { + "Date": "2021-10-29", + "Value": 229, + "Series": "Clothing" + }, + { + "Date": "2021-11-09", + "Value": 233, + "Series": "Clothing" + }, + { + "Date": "2021-11-20", + "Value": 234, + "Series": "Clothing" + }, + { + "Date": "2021-12-01", + "Value": 220, + "Series": "Clothing" + }, + { + "Date": "2021-12-12", + "Value": 208, + "Series": "Clothing" + }, + { + "Date": "2021-12-23", + "Value": 203, + "Series": "Clothing" + }, + { + "Date": "2022-01-03", + "Value": 188, + "Series": "Clothing" + }, + { + "Date": "2022-01-14", + "Value": 165, + "Series": "Clothing" + }, + { + "Date": "2022-01-25", + "Value": 151, + "Series": "Clothing" + }, + { + "Date": "2022-02-05", + "Value": 127, + "Series": "Clothing" + }, + { + "Date": "2022-02-16", + "Value": 117, + "Series": "Clothing" + }, + { + "Date": "2022-02-27", + "Value": 94, + "Series": "Clothing" + }, + { + "Date": "2022-03-10", + "Value": 82, + "Series": "Clothing" + }, + { + "Date": "2022-03-21", + "Value": 65, + "Series": "Clothing" + }, + { + "Date": "2022-04-01", + "Value": 56, + "Series": "Clothing" + }, + { + "Date": "2022-04-12", + "Value": 51, + "Series": "Clothing" + }, + { + "Date": "2022-04-23", + "Value": 44, + "Series": "Clothing" + }, + { + "Date": "2022-05-04", + "Value": 26, + "Series": "Clothing" + }, + { + "Date": "2022-05-15", + "Value": 9, + "Series": "Clothing" + }, + { + "Date": "2022-05-26", + "Value": 0, + "Series": "Clothing" + }, + { + "Date": "2022-06-05", + "Value": 0, + "Series": "Clothing" + }, + { + "Date": "2022-06-16", + "Value": 0, + "Series": "Clothing" + }, + { + "Date": "2022-06-27", + "Value": 0, + "Series": "Clothing" + }, + { + "Date": "2022-07-08", + "Value": 0, + "Series": "Clothing" + }, + { + "Date": "2022-07-19", + "Value": 0, + "Series": "Clothing" + }, + { + "Date": "2022-07-30", + "Value": 8, + "Series": "Clothing" + }, + { + "Date": "2022-08-10", + "Value": 29, + "Series": "Clothing" + }, + { + "Date": "2022-08-21", + "Value": 31, + "Series": "Clothing" + }, + { + "Date": "2022-09-01", + "Value": 35, + "Series": "Clothing" + }, + { + "Date": "2022-09-12", + "Value": 27, + "Series": "Clothing" + }, + { + "Date": "2022-09-23", + "Value": 17, + "Series": "Clothing" + }, + { + "Date": "2022-10-04", + "Value": 16, + "Series": "Clothing" + }, + { + "Date": "2022-10-15", + "Value": 23, + "Series": "Clothing" + }, + { + "Date": "2022-10-26", + "Value": 36, + "Series": "Clothing" + }, + { + "Date": "2022-11-06", + "Value": 44, + "Series": "Clothing" + }, + { + "Date": "2022-11-17", + "Value": 36, + "Series": "Clothing" + }, + { + "Date": "2022-11-28", + "Value": 28, + "Series": "Clothing" + }, + { + "Date": "2022-12-09", + "Value": 41, + "Series": "Clothing" + }, + { + "Date": "2022-12-20", + "Value": 59, + "Series": "Clothing" + }, + { + "Date": "2020-01-01", + "Value": 173, + "Series": "Food" + }, + { + "Date": "2020-01-11", + "Value": 181, + "Series": "Food" + }, + { + "Date": "2020-01-22", + "Value": 192, + "Series": "Food" + }, + { + "Date": "2020-02-02", + "Value": 196, + "Series": "Food" + }, + { + "Date": "2020-02-13", + "Value": 201, + "Series": "Food" + }, + { + "Date": "2020-02-24", + "Value": 212, + "Series": "Food" + }, + { + "Date": "2020-03-06", + "Value": 216, + "Series": "Food" + }, + { + "Date": "2020-03-17", + "Value": 219, + "Series": "Food" + }, + { + "Date": "2020-03-28", + "Value": 208, + "Series": "Food" + }, + { + "Date": "2020-04-08", + "Value": 213, + "Series": "Food" + }, + { + "Date": "2020-04-19", + "Value": 224, + "Series": "Food" + }, + { + "Date": "2020-04-30", + "Value": 231, + "Series": "Food" + }, + { + "Date": "2020-05-11", + "Value": 238, + "Series": "Food" + }, + { + "Date": "2020-05-22", + "Value": 244, + "Series": "Food" + }, + { + "Date": "2020-06-02", + "Value": 254, + "Series": "Food" + }, + { + "Date": "2020-06-13", + "Value": 259, + "Series": "Food" + }, + { + "Date": "2020-06-24", + "Value": 253, + "Series": "Food" + }, + { + "Date": "2020-07-05", + "Value": 258, + "Series": "Food" + }, + { + "Date": "2020-07-16", + "Value": 263, + "Series": "Food" + }, + { + "Date": "2020-07-27", + "Value": 264, + "Series": "Food" + }, + { + "Date": "2020-08-07", + "Value": 276, + "Series": "Food" + }, + { + "Date": "2020-08-17", + "Value": 287, + "Series": "Food" + }, + { + "Date": "2020-08-28", + "Value": 303, + "Series": "Food" + }, + { + "Date": "2020-09-08", + "Value": 321, + "Series": "Food" + }, + { + "Date": "2020-09-19", + "Value": 340, + "Series": "Food" + }, + { + "Date": "2020-09-30", + "Value": 350, + "Series": "Food" + }, + { + "Date": "2020-10-11", + "Value": 368, + "Series": "Food" + }, + { + "Date": "2020-10-22", + "Value": 370, + "Series": "Food" + }, + { + "Date": "2020-11-02", + "Value": 363, + "Series": "Food" + }, + { + "Date": "2020-11-13", + "Value": 353, + "Series": "Food" + }, + { + "Date": "2020-11-24", + "Value": 357, + "Series": "Food" + }, + { + "Date": "2020-12-05", + "Value": 366, + "Series": "Food" + }, + { + "Date": "2020-12-16", + "Value": 365, + "Series": "Food" + }, + { + "Date": "2020-12-27", + "Value": 356, + "Series": "Food" + }, + { + "Date": "2021-01-07", + "Value": 354, + "Series": "Food" + }, + { + "Date": "2021-01-18", + "Value": 354, + "Series": "Food" + }, + { + "Date": "2021-01-29", + "Value": 357, + "Series": "Food" + }, + { + "Date": "2021-02-09", + "Value": 350, + "Series": "Food" + }, + { + "Date": "2021-02-20", + "Value": 345, + "Series": "Food" + }, + { + "Date": "2021-03-03", + "Value": 340, + "Series": "Food" + }, + { + "Date": "2021-03-14", + "Value": 329, + "Series": "Food" + }, + { + "Date": "2021-03-24", + "Value": 327, + "Series": "Food" + }, + { + "Date": "2021-04-04", + "Value": 317, + "Series": "Food" + }, + { + "Date": "2021-04-15", + "Value": 297, + "Series": "Food" + }, + { + "Date": "2021-04-26", + "Value": 291, + "Series": "Food" + }, + { + "Date": "2021-05-07", + "Value": 279, + "Series": "Food" + }, + { + "Date": "2021-05-18", + "Value": 272, + "Series": "Food" + }, + { + "Date": "2021-05-29", + "Value": 271, + "Series": "Food" + }, + { + "Date": "2021-06-09", + "Value": 268, + "Series": "Food" + }, + { + "Date": "2021-06-20", + "Value": 256, + "Series": "Food" + }, + { + "Date": "2021-07-01", + "Value": 255, + "Series": "Food" + }, + { + "Date": "2021-07-12", + "Value": 253, + "Series": "Food" + }, + { + "Date": "2021-07-23", + "Value": 264, + "Series": "Food" + }, + { + "Date": "2021-08-03", + "Value": 273, + "Series": "Food" + }, + { + "Date": "2021-08-14", + "Value": 270, + "Series": "Food" + }, + { + "Date": "2021-08-25", + "Value": 281, + "Series": "Food" + }, + { + "Date": "2021-09-05", + "Value": 277, + "Series": "Food" + }, + { + "Date": "2021-09-16", + "Value": 283, + "Series": "Food" + }, + { + "Date": "2021-09-27", + "Value": 283, + "Series": "Food" + }, + { + "Date": "2021-10-08", + "Value": 270, + "Series": "Food" + }, + { + "Date": "2021-10-19", + "Value": 262, + "Series": "Food" + }, + { + "Date": "2021-10-29", + "Value": 259, + "Series": "Food" + }, + { + "Date": "2021-11-09", + "Value": 269, + "Series": "Food" + }, + { + "Date": "2021-11-20", + "Value": 286, + "Series": "Food" + }, + { + "Date": "2021-12-01", + "Value": 308, + "Series": "Food" + }, + { + "Date": "2021-12-12", + "Value": 316, + "Series": "Food" + }, + { + "Date": "2021-12-23", + "Value": 329, + "Series": "Food" + }, + { + "Date": "2022-01-03", + "Value": 340, + "Series": "Food" + }, + { + "Date": "2022-01-14", + "Value": 347, + "Series": "Food" + }, + { + "Date": "2022-01-25", + "Value": 361, + "Series": "Food" + }, + { + "Date": "2022-02-05", + "Value": 373, + "Series": "Food" + }, + { + "Date": "2022-02-16", + "Value": 373, + "Series": "Food" + }, + { + "Date": "2022-02-27", + "Value": 385, + "Series": "Food" + }, + { + "Date": "2022-03-10", + "Value": 394, + "Series": "Food" + }, + { + "Date": "2022-03-21", + "Value": 400, + "Series": "Food" + }, + { + "Date": "2022-04-01", + "Value": 408, + "Series": "Food" + }, + { + "Date": "2022-04-12", + "Value": 411, + "Series": "Food" + }, + { + "Date": "2022-04-23", + "Value": 420, + "Series": "Food" + }, + { + "Date": "2022-05-04", + "Value": 417, + "Series": "Food" + }, + { + "Date": "2022-05-15", + "Value": 405, + "Series": "Food" + }, + { + "Date": "2022-05-26", + "Value": 408, + "Series": "Food" + }, + { + "Date": "2022-06-05", + "Value": 403, + "Series": "Food" + }, + { + "Date": "2022-06-16", + "Value": 412, + "Series": "Food" + }, + { + "Date": "2022-06-27", + "Value": 418, + "Series": "Food" + }, + { + "Date": "2022-07-08", + "Value": 414, + "Series": "Food" + }, + { + "Date": "2022-07-19", + "Value": 404, + "Series": "Food" + }, + { + "Date": "2022-07-30", + "Value": 401, + "Series": "Food" + }, + { + "Date": "2022-08-10", + "Value": 394, + "Series": "Food" + }, + { + "Date": "2022-08-21", + "Value": 393, + "Series": "Food" + }, + { + "Date": "2022-09-01", + "Value": 391, + "Series": "Food" + }, + { + "Date": "2022-09-12", + "Value": 391, + "Series": "Food" + }, + { + "Date": "2022-09-23", + "Value": 403, + "Series": "Food" + }, + { + "Date": "2022-10-04", + "Value": 404, + "Series": "Food" + }, + { + "Date": "2022-10-15", + "Value": 413, + "Series": "Food" + }, + { + "Date": "2022-10-26", + "Value": 420, + "Series": "Food" + }, + { + "Date": "2022-11-06", + "Value": 433, + "Series": "Food" + }, + { + "Date": "2022-11-17", + "Value": 453, + "Series": "Food" + }, + { + "Date": "2022-11-28", + "Value": 479, + "Series": "Food" + }, + { + "Date": "2022-12-09", + "Value": 490, + "Series": "Food" + }, + { + "Date": "2022-12-20", + "Value": 493, + "Series": "Food" + }, + { + "Date": "2020-01-01", + "Value": 211, + "Series": "Books" + }, + { + "Date": "2020-01-11", + "Value": 212, + "Series": "Books" + }, + { + "Date": "2020-01-22", + "Value": 209, + "Series": "Books" + }, + { + "Date": "2020-02-02", + "Value": 212, + "Series": "Books" + }, + { + "Date": "2020-02-13", + "Value": 210, + "Series": "Books" + }, + { + "Date": "2020-02-24", + "Value": 206, + "Series": "Books" + }, + { + "Date": "2020-03-06", + "Value": 202, + "Series": "Books" + }, + { + "Date": "2020-03-17", + "Value": 195, + "Series": "Books" + }, + { + "Date": "2020-03-28", + "Value": 185, + "Series": "Books" + }, + { + "Date": "2020-04-08", + "Value": 174, + "Series": "Books" + }, + { + "Date": "2020-04-19", + "Value": 171, + "Series": "Books" + }, + { + "Date": "2020-04-30", + "Value": 174, + "Series": "Books" + }, + { + "Date": "2020-05-11", + "Value": 181, + "Series": "Books" + }, + { + "Date": "2020-05-22", + "Value": 185, + "Series": "Books" + }, + { + "Date": "2020-06-02", + "Value": 184, + "Series": "Books" + }, + { + "Date": "2020-06-13", + "Value": 181, + "Series": "Books" + }, + { + "Date": "2020-06-24", + "Value": 176, + "Series": "Books" + }, + { + "Date": "2020-07-05", + "Value": 175, + "Series": "Books" + }, + { + "Date": "2020-07-16", + "Value": 169, + "Series": "Books" + }, + { + "Date": "2020-07-27", + "Value": 159, + "Series": "Books" + }, + { + "Date": "2020-08-07", + "Value": 150, + "Series": "Books" + }, + { + "Date": "2020-08-17", + "Value": 147, + "Series": "Books" + }, + { + "Date": "2020-08-28", + "Value": 150, + "Series": "Books" + }, + { + "Date": "2020-09-08", + "Value": 151, + "Series": "Books" + }, + { + "Date": "2020-09-19", + "Value": 156, + "Series": "Books" + }, + { + "Date": "2020-09-30", + "Value": 165, + "Series": "Books" + }, + { + "Date": "2020-10-11", + "Value": 175, + "Series": "Books" + }, + { + "Date": "2020-10-22", + "Value": 179, + "Series": "Books" + }, + { + "Date": "2020-11-02", + "Value": 181, + "Series": "Books" + }, + { + "Date": "2020-11-13", + "Value": 180, + "Series": "Books" + }, + { + "Date": "2020-11-24", + "Value": 176, + "Series": "Books" + }, + { + "Date": "2020-12-05", + "Value": 170, + "Series": "Books" + }, + { + "Date": "2020-12-16", + "Value": 171, + "Series": "Books" + }, + { + "Date": "2020-12-27", + "Value": 168, + "Series": "Books" + }, + { + "Date": "2021-01-07", + "Value": 168, + "Series": "Books" + }, + { + "Date": "2021-01-18", + "Value": 169, + "Series": "Books" + }, + { + "Date": "2021-01-29", + "Value": 174, + "Series": "Books" + }, + { + "Date": "2021-02-09", + "Value": 180, + "Series": "Books" + }, + { + "Date": "2021-02-20", + "Value": 181, + "Series": "Books" + }, + { + "Date": "2021-03-03", + "Value": 185, + "Series": "Books" + }, + { + "Date": "2021-03-14", + "Value": 193, + "Series": "Books" + }, + { + "Date": "2021-03-24", + "Value": 201, + "Series": "Books" + }, + { + "Date": "2021-04-04", + "Value": 210, + "Series": "Books" + }, + { + "Date": "2021-04-15", + "Value": 212, + "Series": "Books" + }, + { + "Date": "2021-04-26", + "Value": 209, + "Series": "Books" + }, + { + "Date": "2021-05-07", + "Value": 202, + "Series": "Books" + }, + { + "Date": "2021-05-18", + "Value": 196, + "Series": "Books" + }, + { + "Date": "2021-05-29", + "Value": 192, + "Series": "Books" + }, + { + "Date": "2021-06-09", + "Value": 191, + "Series": "Books" + }, + { + "Date": "2021-06-20", + "Value": 192, + "Series": "Books" + }, + { + "Date": "2021-07-01", + "Value": 194, + "Series": "Books" + }, + { + "Date": "2021-07-12", + "Value": 193, + "Series": "Books" + }, + { + "Date": "2021-07-23", + "Value": 192, + "Series": "Books" + }, + { + "Date": "2021-08-03", + "Value": 191, + "Series": "Books" + }, + { + "Date": "2021-08-14", + "Value": 194, + "Series": "Books" + }, + { + "Date": "2021-08-25", + "Value": 196, + "Series": "Books" + }, + { + "Date": "2021-09-05", + "Value": 199, + "Series": "Books" + }, + { + "Date": "2021-09-16", + "Value": 205, + "Series": "Books" + }, + { + "Date": "2021-09-27", + "Value": 211, + "Series": "Books" + }, + { + "Date": "2021-10-08", + "Value": 212, + "Series": "Books" + }, + { + "Date": "2021-10-19", + "Value": 208, + "Series": "Books" + }, + { + "Date": "2021-10-29", + "Value": 202, + "Series": "Books" + }, + { + "Date": "2021-11-09", + "Value": 202, + "Series": "Books" + }, + { + "Date": "2021-11-20", + "Value": 207, + "Series": "Books" + }, + { + "Date": "2021-12-01", + "Value": 208, + "Series": "Books" + }, + { + "Date": "2021-12-12", + "Value": 203, + "Series": "Books" + }, + { + "Date": "2021-12-23", + "Value": 201, + "Series": "Books" + }, + { + "Date": "2022-01-03", + "Value": 199, + "Series": "Books" + }, + { + "Date": "2022-01-14", + "Value": 196, + "Series": "Books" + }, + { + "Date": "2022-01-25", + "Value": 196, + "Series": "Books" + }, + { + "Date": "2022-02-05", + "Value": 195, + "Series": "Books" + }, + { + "Date": "2022-02-16", + "Value": 198, + "Series": "Books" + }, + { + "Date": "2022-02-27", + "Value": 204, + "Series": "Books" + }, + { + "Date": "2022-03-10", + "Value": 212, + "Series": "Books" + }, + { + "Date": "2022-03-21", + "Value": 212, + "Series": "Books" + }, + { + "Date": "2022-04-01", + "Value": 217, + "Series": "Books" + }, + { + "Date": "2022-04-12", + "Value": 215, + "Series": "Books" + }, + { + "Date": "2022-04-23", + "Value": 212, + "Series": "Books" + }, + { + "Date": "2022-05-04", + "Value": 211, + "Series": "Books" + }, + { + "Date": "2022-05-15", + "Value": 212, + "Series": "Books" + }, + { + "Date": "2022-05-26", + "Value": 215, + "Series": "Books" + }, + { + "Date": "2022-06-05", + "Value": 220, + "Series": "Books" + }, + { + "Date": "2022-06-16", + "Value": 221, + "Series": "Books" + }, + { + "Date": "2022-06-27", + "Value": 224, + "Series": "Books" + }, + { + "Date": "2022-07-08", + "Value": 227, + "Series": "Books" + }, + { + "Date": "2022-07-19", + "Value": 226, + "Series": "Books" + }, + { + "Date": "2022-07-30", + "Value": 231, + "Series": "Books" + }, + { + "Date": "2022-08-10", + "Value": 239, + "Series": "Books" + }, + { + "Date": "2022-08-21", + "Value": 250, + "Series": "Books" + }, + { + "Date": "2022-09-01", + "Value": 260, + "Series": "Books" + }, + { + "Date": "2022-09-12", + "Value": 270, + "Series": "Books" + }, + { + "Date": "2022-09-23", + "Value": 274, + "Series": "Books" + }, + { + "Date": "2022-10-04", + "Value": 282, + "Series": "Books" + }, + { + "Date": "2022-10-15", + "Value": 286, + "Series": "Books" + }, + { + "Date": "2022-10-26", + "Value": 285, + "Series": "Books" + }, + { + "Date": "2022-11-06", + "Value": 283, + "Series": "Books" + }, + { + "Date": "2022-11-17", + "Value": 277, + "Series": "Books" + }, + { + "Date": "2022-11-28", + "Value": 271, + "Series": "Books" + }, + { + "Date": "2022-12-09", + "Value": 267, + "Series": "Books" + }, + { + "Date": "2022-12-20", + "Value": 269, + "Series": "Books" + }, + { + "Date": "2020-01-01", + "Value": 57, + "Series": "Sports" + }, + { + "Date": "2020-01-11", + "Value": 63, + "Series": "Sports" + }, + { + "Date": "2020-01-22", + "Value": 76, + "Series": "Sports" + }, + { + "Date": "2020-02-02", + "Value": 76, + "Series": "Sports" + }, + { + "Date": "2020-02-13", + "Value": 75, + "Series": "Sports" + }, + { + "Date": "2020-02-24", + "Value": 67, + "Series": "Sports" + }, + { + "Date": "2020-03-06", + "Value": 73, + "Series": "Sports" + }, + { + "Date": "2020-03-17", + "Value": 82, + "Series": "Sports" + }, + { + "Date": "2020-03-28", + "Value": 89, + "Series": "Sports" + }, + { + "Date": "2020-04-08", + "Value": 85, + "Series": "Sports" + }, + { + "Date": "2020-04-19", + "Value": 90, + "Series": "Sports" + }, + { + "Date": "2020-04-30", + "Value": 87, + "Series": "Sports" + }, + { + "Date": "2020-05-11", + "Value": 89, + "Series": "Sports" + }, + { + "Date": "2020-05-22", + "Value": 81, + "Series": "Sports" + }, + { + "Date": "2020-06-02", + "Value": 62, + "Series": "Sports" + }, + { + "Date": "2020-06-13", + "Value": 60, + "Series": "Sports" + }, + { + "Date": "2020-06-24", + "Value": 53, + "Series": "Sports" + }, + { + "Date": "2020-07-05", + "Value": 46, + "Series": "Sports" + }, + { + "Date": "2020-07-16", + "Value": 52, + "Series": "Sports" + }, + { + "Date": "2020-07-27", + "Value": 46, + "Series": "Sports" + }, + { + "Date": "2020-08-07", + "Value": 32, + "Series": "Sports" + }, + { + "Date": "2020-08-17", + "Value": 28, + "Series": "Sports" + }, + { + "Date": "2020-08-28", + "Value": 20, + "Series": "Sports" + }, + { + "Date": "2020-09-08", + "Value": 3, + "Series": "Sports" + }, + { + "Date": "2020-09-19", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2020-09-30", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2020-10-11", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2020-10-22", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2020-11-02", + "Value": 4, + "Series": "Sports" + }, + { + "Date": "2020-11-13", + "Value": 5, + "Series": "Sports" + }, + { + "Date": "2020-11-24", + "Value": 10, + "Series": "Sports" + }, + { + "Date": "2020-12-05", + "Value": 27, + "Series": "Sports" + }, + { + "Date": "2020-12-16", + "Value": 27, + "Series": "Sports" + }, + { + "Date": "2020-12-27", + "Value": 30, + "Series": "Sports" + }, + { + "Date": "2021-01-07", + "Value": 29, + "Series": "Sports" + }, + { + "Date": "2021-01-18", + "Value": 37, + "Series": "Sports" + }, + { + "Date": "2021-01-29", + "Value": 47, + "Series": "Sports" + }, + { + "Date": "2021-02-09", + "Value": 52, + "Series": "Sports" + }, + { + "Date": "2021-02-20", + "Value": 48, + "Series": "Sports" + }, + { + "Date": "2021-03-03", + "Value": 42, + "Series": "Sports" + }, + { + "Date": "2021-03-14", + "Value": 48, + "Series": "Sports" + }, + { + "Date": "2021-03-24", + "Value": 47, + "Series": "Sports" + }, + { + "Date": "2021-04-04", + "Value": 55, + "Series": "Sports" + }, + { + "Date": "2021-04-15", + "Value": 54, + "Series": "Sports" + }, + { + "Date": "2021-04-26", + "Value": 56, + "Series": "Sports" + }, + { + "Date": "2021-05-07", + "Value": 64, + "Series": "Sports" + }, + { + "Date": "2021-05-18", + "Value": 71, + "Series": "Sports" + }, + { + "Date": "2021-05-29", + "Value": 89, + "Series": "Sports" + }, + { + "Date": "2021-06-09", + "Value": 96, + "Series": "Sports" + }, + { + "Date": "2021-06-20", + "Value": 104, + "Series": "Sports" + }, + { + "Date": "2021-07-01", + "Value": 109, + "Series": "Sports" + }, + { + "Date": "2021-07-12", + "Value": 122, + "Series": "Sports" + }, + { + "Date": "2021-07-23", + "Value": 136, + "Series": "Sports" + }, + { + "Date": "2021-08-03", + "Value": 149, + "Series": "Sports" + }, + { + "Date": "2021-08-14", + "Value": 170, + "Series": "Sports" + }, + { + "Date": "2021-08-25", + "Value": 194, + "Series": "Sports" + }, + { + "Date": "2021-09-05", + "Value": 201, + "Series": "Sports" + }, + { + "Date": "2021-09-16", + "Value": 199, + "Series": "Sports" + }, + { + "Date": "2021-09-27", + "Value": 196, + "Series": "Sports" + }, + { + "Date": "2021-10-08", + "Value": 187, + "Series": "Sports" + }, + { + "Date": "2021-10-19", + "Value": 179, + "Series": "Sports" + }, + { + "Date": "2021-10-29", + "Value": 181, + "Series": "Sports" + }, + { + "Date": "2021-11-09", + "Value": 171, + "Series": "Sports" + }, + { + "Date": "2021-11-20", + "Value": 176, + "Series": "Sports" + }, + { + "Date": "2021-12-01", + "Value": 175, + "Series": "Sports" + }, + { + "Date": "2021-12-12", + "Value": 182, + "Series": "Sports" + }, + { + "Date": "2021-12-23", + "Value": 193, + "Series": "Sports" + }, + { + "Date": "2022-01-03", + "Value": 197, + "Series": "Sports" + }, + { + "Date": "2022-01-14", + "Value": 208, + "Series": "Sports" + }, + { + "Date": "2022-01-25", + "Value": 229, + "Series": "Sports" + }, + { + "Date": "2022-02-05", + "Value": 256, + "Series": "Sports" + }, + { + "Date": "2022-02-16", + "Value": 268, + "Series": "Sports" + }, + { + "Date": "2022-02-27", + "Value": 273, + "Series": "Sports" + }, + { + "Date": "2022-03-10", + "Value": 264, + "Series": "Sports" + }, + { + "Date": "2022-03-21", + "Value": 247, + "Series": "Sports" + }, + { + "Date": "2022-04-01", + "Value": 230, + "Series": "Sports" + }, + { + "Date": "2022-04-12", + "Value": 226, + "Series": "Sports" + }, + { + "Date": "2022-04-23", + "Value": 212, + "Series": "Sports" + }, + { + "Date": "2022-05-04", + "Value": 197, + "Series": "Sports" + }, + { + "Date": "2022-05-15", + "Value": 191, + "Series": "Sports" + }, + { + "Date": "2022-05-26", + "Value": 177, + "Series": "Sports" + }, + { + "Date": "2022-06-05", + "Value": 160, + "Series": "Sports" + }, + { + "Date": "2022-06-16", + "Value": 158, + "Series": "Sports" + }, + { + "Date": "2022-06-27", + "Value": 144, + "Series": "Sports" + }, + { + "Date": "2022-07-08", + "Value": 123, + "Series": "Sports" + }, + { + "Date": "2022-07-19", + "Value": 100, + "Series": "Sports" + }, + { + "Date": "2022-07-30", + "Value": 85, + "Series": "Sports" + }, + { + "Date": "2022-08-10", + "Value": 64, + "Series": "Sports" + }, + { + "Date": "2022-08-21", + "Value": 59, + "Series": "Sports" + }, + { + "Date": "2022-09-01", + "Value": 49, + "Series": "Sports" + }, + { + "Date": "2022-09-12", + "Value": 43, + "Series": "Sports" + }, + { + "Date": "2022-09-23", + "Value": 52, + "Series": "Sports" + }, + { + "Date": "2022-10-04", + "Value": 53, + "Series": "Sports" + }, + { + "Date": "2022-10-15", + "Value": 42, + "Series": "Sports" + }, + { + "Date": "2022-10-26", + "Value": 22, + "Series": "Sports" + }, + { + "Date": "2022-11-06", + "Value": 2, + "Series": "Sports" + }, + { + "Date": "2022-11-17", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2022-11-28", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2022-12-09", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2022-12-20", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2020-01-01", + "Value": 210, + "Series": "Home" + }, + { + "Date": "2020-01-11", + "Value": 216, + "Series": "Home" + }, + { + "Date": "2020-01-22", + "Value": 223, + "Series": "Home" + }, + { + "Date": "2020-02-02", + "Value": 227, + "Series": "Home" + }, + { + "Date": "2020-02-13", + "Value": 225, + "Series": "Home" + }, + { + "Date": "2020-02-24", + "Value": 219, + "Series": "Home" + }, + { + "Date": "2020-03-06", + "Value": 218, + "Series": "Home" + }, + { + "Date": "2020-03-17", + "Value": 223, + "Series": "Home" + }, + { + "Date": "2020-03-28", + "Value": 232, + "Series": "Home" + }, + { + "Date": "2020-04-08", + "Value": 244, + "Series": "Home" + }, + { + "Date": "2020-04-19", + "Value": 253, + "Series": "Home" + }, + { + "Date": "2020-04-30", + "Value": 255, + "Series": "Home" + }, + { + "Date": "2020-05-11", + "Value": 253, + "Series": "Home" + }, + { + "Date": "2020-05-22", + "Value": 250, + "Series": "Home" + }, + { + "Date": "2020-06-02", + "Value": 247, + "Series": "Home" + }, + { + "Date": "2020-06-13", + "Value": 239, + "Series": "Home" + }, + { + "Date": "2020-06-24", + "Value": 237, + "Series": "Home" + }, + { + "Date": "2020-07-05", + "Value": 241, + "Series": "Home" + }, + { + "Date": "2020-07-16", + "Value": 244, + "Series": "Home" + }, + { + "Date": "2020-07-27", + "Value": 252, + "Series": "Home" + }, + { + "Date": "2020-08-07", + "Value": 259, + "Series": "Home" + }, + { + "Date": "2020-08-17", + "Value": 267, + "Series": "Home" + }, + { + "Date": "2020-08-28", + "Value": 279, + "Series": "Home" + }, + { + "Date": "2020-09-08", + "Value": 291, + "Series": "Home" + }, + { + "Date": "2020-09-19", + "Value": 303, + "Series": "Home" + }, + { + "Date": "2020-09-30", + "Value": 308, + "Series": "Home" + }, + { + "Date": "2020-10-11", + "Value": 312, + "Series": "Home" + }, + { + "Date": "2020-10-22", + "Value": 309, + "Series": "Home" + }, + { + "Date": "2020-11-02", + "Value": 306, + "Series": "Home" + }, + { + "Date": "2020-11-13", + "Value": 302, + "Series": "Home" + }, + { + "Date": "2020-11-24", + "Value": 305, + "Series": "Home" + }, + { + "Date": "2020-12-05", + "Value": 303, + "Series": "Home" + }, + { + "Date": "2020-12-16", + "Value": 301, + "Series": "Home" + }, + { + "Date": "2020-12-27", + "Value": 302, + "Series": "Home" + }, + { + "Date": "2021-01-07", + "Value": 305, + "Series": "Home" + }, + { + "Date": "2021-01-18", + "Value": 311, + "Series": "Home" + }, + { + "Date": "2021-01-29", + "Value": 309, + "Series": "Home" + }, + { + "Date": "2021-02-09", + "Value": 307, + "Series": "Home" + }, + { + "Date": "2021-02-20", + "Value": 312, + "Series": "Home" + }, + { + "Date": "2021-03-03", + "Value": 313, + "Series": "Home" + }, + { + "Date": "2021-03-14", + "Value": 317, + "Series": "Home" + }, + { + "Date": "2021-03-24", + "Value": 322, + "Series": "Home" + }, + { + "Date": "2021-04-04", + "Value": 326, + "Series": "Home" + }, + { + "Date": "2021-04-15", + "Value": 334, + "Series": "Home" + }, + { + "Date": "2021-04-26", + "Value": 338, + "Series": "Home" + }, + { + "Date": "2021-05-07", + "Value": 337, + "Series": "Home" + }, + { + "Date": "2021-05-18", + "Value": 336, + "Series": "Home" + }, + { + "Date": "2021-05-29", + "Value": 333, + "Series": "Home" + }, + { + "Date": "2021-06-09", + "Value": 335, + "Series": "Home" + }, + { + "Date": "2021-06-20", + "Value": 344, + "Series": "Home" + }, + { + "Date": "2021-07-01", + "Value": 344, + "Series": "Home" + }, + { + "Date": "2021-07-12", + "Value": 346, + "Series": "Home" + }, + { + "Date": "2021-07-23", + "Value": 349, + "Series": "Home" + }, + { + "Date": "2021-08-03", + "Value": 354, + "Series": "Home" + }, + { + "Date": "2021-08-14", + "Value": 361, + "Series": "Home" + }, + { + "Date": "2021-08-25", + "Value": 359, + "Series": "Home" + }, + { + "Date": "2021-09-05", + "Value": 357, + "Series": "Home" + }, + { + "Date": "2021-09-16", + "Value": 355, + "Series": "Home" + }, + { + "Date": "2021-09-27", + "Value": 359, + "Series": "Home" + }, + { + "Date": "2021-10-08", + "Value": 368, + "Series": "Home" + }, + { + "Date": "2021-10-19", + "Value": 372, + "Series": "Home" + }, + { + "Date": "2021-10-29", + "Value": 382, + "Series": "Home" + }, + { + "Date": "2021-11-09", + "Value": 386, + "Series": "Home" + }, + { + "Date": "2021-11-20", + "Value": 392, + "Series": "Home" + }, + { + "Date": "2021-12-01", + "Value": 390, + "Series": "Home" + }, + { + "Date": "2021-12-12", + "Value": 389, + "Series": "Home" + }, + { + "Date": "2021-12-23", + "Value": 383, + "Series": "Home" + }, + { + "Date": "2022-01-03", + "Value": 377, + "Series": "Home" + }, + { + "Date": "2022-01-14", + "Value": 379, + "Series": "Home" + }, + { + "Date": "2022-01-25", + "Value": 374, + "Series": "Home" + }, + { + "Date": "2022-02-05", + "Value": 376, + "Series": "Home" + }, + { + "Date": "2022-02-16", + "Value": 377, + "Series": "Home" + }, + { + "Date": "2022-02-27", + "Value": 378, + "Series": "Home" + }, + { + "Date": "2022-03-10", + "Value": 383, + "Series": "Home" + }, + { + "Date": "2022-03-21", + "Value": 390, + "Series": "Home" + }, + { + "Date": "2022-04-01", + "Value": 400, + "Series": "Home" + }, + { + "Date": "2022-04-12", + "Value": 405, + "Series": "Home" + }, + { + "Date": "2022-04-23", + "Value": 409, + "Series": "Home" + }, + { + "Date": "2022-05-04", + "Value": 415, + "Series": "Home" + }, + { + "Date": "2022-05-15", + "Value": 413, + "Series": "Home" + }, + { + "Date": "2022-05-26", + "Value": 410, + "Series": "Home" + }, + { + "Date": "2022-06-05", + "Value": 410, + "Series": "Home" + }, + { + "Date": "2022-06-16", + "Value": 416, + "Series": "Home" + }, + { + "Date": "2022-06-27", + "Value": 422, + "Series": "Home" + }, + { + "Date": "2022-07-08", + "Value": 420, + "Series": "Home" + }, + { + "Date": "2022-07-19", + "Value": 424, + "Series": "Home" + }, + { + "Date": "2022-07-30", + "Value": 431, + "Series": "Home" + }, + { + "Date": "2022-08-10", + "Value": 437, + "Series": "Home" + }, + { + "Date": "2022-08-21", + "Value": 446, + "Series": "Home" + }, + { + "Date": "2022-09-01", + "Value": 458, + "Series": "Home" + }, + { + "Date": "2022-09-12", + "Value": 468, + "Series": "Home" + }, + { + "Date": "2022-09-23", + "Value": 470, + "Series": "Home" + }, + { + "Date": "2022-10-04", + "Value": 477, + "Series": "Home" + }, + { + "Date": "2022-10-15", + "Value": 475, + "Series": "Home" + }, + { + "Date": "2022-10-26", + "Value": 480, + "Series": "Home" + }, + { + "Date": "2022-11-06", + "Value": 488, + "Series": "Home" + }, + { + "Date": "2022-11-17", + "Value": 494, + "Series": "Home" + }, + { + "Date": "2022-11-28", + "Value": 499, + "Series": "Home" + }, + { + "Date": "2022-12-09", + "Value": 503, + "Series": "Home" + }, + { + "Date": "2022-12-20", + "Value": 499, + "Series": "Home" + }, + { + "Date": "2020-01-01", + "Value": 69, + "Series": "Garden" + }, + { + "Date": "2020-01-11", + "Value": 72, + "Series": "Garden" + }, + { + "Date": "2020-01-22", + "Value": 61, + "Series": "Garden" + }, + { + "Date": "2020-02-02", + "Value": 65, + "Series": "Garden" + }, + { + "Date": "2020-02-13", + "Value": 71, + "Series": "Garden" + }, + { + "Date": "2020-02-24", + "Value": 76, + "Series": "Garden" + }, + { + "Date": "2020-03-06", + "Value": 70, + "Series": "Garden" + }, + { + "Date": "2020-03-17", + "Value": 75, + "Series": "Garden" + }, + { + "Date": "2020-03-28", + "Value": 67, + "Series": "Garden" + }, + { + "Date": "2020-04-08", + "Value": 59, + "Series": "Garden" + }, + { + "Date": "2020-04-19", + "Value": 55, + "Series": "Garden" + }, + { + "Date": "2020-04-30", + "Value": 55, + "Series": "Garden" + }, + { + "Date": "2020-05-11", + "Value": 48, + "Series": "Garden" + }, + { + "Date": "2020-05-22", + "Value": 27, + "Series": "Garden" + }, + { + "Date": "2020-06-02", + "Value": 0, + "Series": "Garden" + }, + { + "Date": "2020-06-13", + "Value": 0, + "Series": "Garden" + }, + { + "Date": "2020-06-24", + "Value": 0, + "Series": "Garden" + }, + { + "Date": "2020-07-05", + "Value": 0, + "Series": "Garden" + }, + { + "Date": "2020-07-16", + "Value": 0, + "Series": "Garden" + }, + { + "Date": "2020-07-27", + "Value": 6, + "Series": "Garden" + }, + { + "Date": "2020-08-07", + "Value": 0, + "Series": "Garden" + }, + { + "Date": "2020-08-17", + "Value": 0, + "Series": "Garden" + }, + { + "Date": "2020-08-28", + "Value": 0, + "Series": "Garden" + }, + { + "Date": "2020-09-08", + "Value": 0, + "Series": "Garden" + }, + { + "Date": "2020-09-19", + "Value": 0, + "Series": "Garden" + }, + { + "Date": "2020-09-30", + "Value": 3, + "Series": "Garden" + }, + { + "Date": "2020-10-11", + "Value": 0, + "Series": "Garden" + }, + { + "Date": "2020-10-22", + "Value": 5, + "Series": "Garden" + }, + { + "Date": "2020-11-02", + "Value": 0, + "Series": "Garden" + }, + { + "Date": "2020-11-13", + "Value": 4, + "Series": "Garden" + }, + { + "Date": "2020-11-24", + "Value": 15, + "Series": "Garden" + }, + { + "Date": "2020-12-05", + "Value": 34, + "Series": "Garden" + }, + { + "Date": "2020-12-16", + "Value": 46, + "Series": "Garden" + }, + { + "Date": "2020-12-27", + "Value": 51, + "Series": "Garden" + }, + { + "Date": "2021-01-07", + "Value": 41, + "Series": "Garden" + }, + { + "Date": "2021-01-18", + "Value": 30, + "Series": "Garden" + }, + { + "Date": "2021-01-29", + "Value": 31, + "Series": "Garden" + }, + { + "Date": "2021-02-09", + "Value": 49, + "Series": "Garden" + }, + { + "Date": "2021-02-20", + "Value": 57, + "Series": "Garden" + }, + { + "Date": "2021-03-03", + "Value": 46, + "Series": "Garden" + }, + { + "Date": "2021-03-14", + "Value": 46, + "Series": "Garden" + }, + { + "Date": "2021-03-24", + "Value": 37, + "Series": "Garden" + }, + { + "Date": "2021-04-04", + "Value": 15, + "Series": "Garden" + }, + { + "Date": "2021-04-15", + "Value": 0, + "Series": "Garden" + }, + { + "Date": "2021-04-26", + "Value": 0, + "Series": "Garden" + }, + { + "Date": "2021-05-07", + "Value": 3, + "Series": "Garden" + }, + { + "Date": "2021-05-18", + "Value": 7, + "Series": "Garden" + }, + { + "Date": "2021-05-29", + "Value": 19, + "Series": "Garden" + }, + { + "Date": "2021-06-09", + "Value": 9, + "Series": "Garden" + }, + { + "Date": "2021-06-20", + "Value": 4, + "Series": "Garden" + }, + { + "Date": "2021-07-01", + "Value": 11, + "Series": "Garden" + }, + { + "Date": "2021-07-12", + "Value": 30, + "Series": "Garden" + }, + { + "Date": "2021-07-23", + "Value": 41, + "Series": "Garden" + }, + { + "Date": "2021-08-03", + "Value": 64, + "Series": "Garden" + }, + { + "Date": "2021-08-14", + "Value": 98, + "Series": "Garden" + }, + { + "Date": "2021-08-25", + "Value": 118, + "Series": "Garden" + }, + { + "Date": "2021-09-05", + "Value": 129, + "Series": "Garden" + }, + { + "Date": "2021-09-16", + "Value": 141, + "Series": "Garden" + }, + { + "Date": "2021-09-27", + "Value": 157, + "Series": "Garden" + }, + { + "Date": "2021-10-08", + "Value": 172, + "Series": "Garden" + }, + { + "Date": "2021-10-19", + "Value": 169, + "Series": "Garden" + }, + { + "Date": "2021-10-29", + "Value": 184, + "Series": "Garden" + }, + { + "Date": "2021-11-09", + "Value": 211, + "Series": "Garden" + }, + { + "Date": "2021-11-20", + "Value": 215, + "Series": "Garden" + }, + { + "Date": "2021-12-01", + "Value": 222, + "Series": "Garden" + }, + { + "Date": "2021-12-12", + "Value": 240, + "Series": "Garden" + }, + { + "Date": "2021-12-23", + "Value": 252, + "Series": "Garden" + }, + { + "Date": "2022-01-03", + "Value": 254, + "Series": "Garden" + }, + { + "Date": "2022-01-14", + "Value": 250, + "Series": "Garden" + }, + { + "Date": "2022-01-25", + "Value": 247, + "Series": "Garden" + }, + { + "Date": "2022-02-05", + "Value": 232, + "Series": "Garden" + }, + { + "Date": "2022-02-16", + "Value": 238, + "Series": "Garden" + }, + { + "Date": "2022-02-27", + "Value": 249, + "Series": "Garden" + }, + { + "Date": "2022-03-10", + "Value": 256, + "Series": "Garden" + }, + { + "Date": "2022-03-21", + "Value": 265, + "Series": "Garden" + }, + { + "Date": "2022-04-01", + "Value": 259, + "Series": "Garden" + }, + { + "Date": "2022-04-12", + "Value": 260, + "Series": "Garden" + }, + { + "Date": "2022-04-23", + "Value": 271, + "Series": "Garden" + }, + { + "Date": "2022-05-04", + "Value": 268, + "Series": "Garden" + }, + { + "Date": "2022-05-15", + "Value": 279, + "Series": "Garden" + }, + { + "Date": "2022-05-26", + "Value": 270, + "Series": "Garden" + }, + { + "Date": "2022-06-05", + "Value": 265, + "Series": "Garden" + }, + { + "Date": "2022-06-16", + "Value": 262, + "Series": "Garden" + }, + { + "Date": "2022-06-27", + "Value": 263, + "Series": "Garden" + }, + { + "Date": "2022-07-08", + "Value": 280, + "Series": "Garden" + }, + { + "Date": "2022-07-19", + "Value": 309, + "Series": "Garden" + }, + { + "Date": "2022-07-30", + "Value": 331, + "Series": "Garden" + }, + { + "Date": "2022-08-10", + "Value": 334, + "Series": "Garden" + }, + { + "Date": "2022-08-21", + "Value": 330, + "Series": "Garden" + }, + { + "Date": "2022-09-01", + "Value": 322, + "Series": "Garden" + }, + { + "Date": "2022-09-12", + "Value": 326, + "Series": "Garden" + }, + { + "Date": "2022-09-23", + "Value": 329, + "Series": "Garden" + }, + { + "Date": "2022-10-04", + "Value": 320, + "Series": "Garden" + }, + { + "Date": "2022-10-15", + "Value": 300, + "Series": "Garden" + }, + { + "Date": "2022-10-26", + "Value": 266, + "Series": "Garden" + }, + { + "Date": "2022-11-06", + "Value": 223, + "Series": "Garden" + }, + { + "Date": "2022-11-17", + "Value": 174, + "Series": "Garden" + }, + { + "Date": "2022-11-28", + "Value": 132, + "Series": "Garden" + }, + { + "Date": "2022-12-09", + "Value": 102, + "Series": "Garden" + }, + { + "Date": "2022-12-20", + "Value": 89, + "Series": "Garden" + }, + { + "Date": "2020-01-01", + "Value": 233, + "Series": "Auto" + }, + { + "Date": "2020-01-11", + "Value": 239, + "Series": "Auto" + }, + { + "Date": "2020-01-22", + "Value": 252, + "Series": "Auto" + }, + { + "Date": "2020-02-02", + "Value": 266, + "Series": "Auto" + }, + { + "Date": "2020-02-13", + "Value": 277, + "Series": "Auto" + }, + { + "Date": "2020-02-24", + "Value": 283, + "Series": "Auto" + }, + { + "Date": "2020-03-06", + "Value": 291, + "Series": "Auto" + }, + { + "Date": "2020-03-17", + "Value": 295, + "Series": "Auto" + }, + { + "Date": "2020-03-28", + "Value": 306, + "Series": "Auto" + }, + { + "Date": "2020-04-08", + "Value": 319, + "Series": "Auto" + }, + { + "Date": "2020-04-19", + "Value": 333, + "Series": "Auto" + }, + { + "Date": "2020-04-30", + "Value": 342, + "Series": "Auto" + }, + { + "Date": "2020-05-11", + "Value": 343, + "Series": "Auto" + }, + { + "Date": "2020-05-22", + "Value": 354, + "Series": "Auto" + }, + { + "Date": "2020-06-02", + "Value": 363, + "Series": "Auto" + }, + { + "Date": "2020-06-13", + "Value": 382, + "Series": "Auto" + }, + { + "Date": "2020-06-24", + "Value": 395, + "Series": "Auto" + }, + { + "Date": "2020-07-05", + "Value": 407, + "Series": "Auto" + }, + { + "Date": "2020-07-16", + "Value": 422, + "Series": "Auto" + }, + { + "Date": "2020-07-27", + "Value": 424, + "Series": "Auto" + }, + { + "Date": "2020-08-07", + "Value": 413, + "Series": "Auto" + }, + { + "Date": "2020-08-17", + "Value": 413, + "Series": "Auto" + }, + { + "Date": "2020-08-28", + "Value": 404, + "Series": "Auto" + }, + { + "Date": "2020-09-08", + "Value": 390, + "Series": "Auto" + }, + { + "Date": "2020-09-19", + "Value": 376, + "Series": "Auto" + }, + { + "Date": "2020-09-30", + "Value": 377, + "Series": "Auto" + }, + { + "Date": "2020-10-11", + "Value": 385, + "Series": "Auto" + }, + { + "Date": "2020-10-22", + "Value": 394, + "Series": "Auto" + }, + { + "Date": "2020-11-02", + "Value": 409, + "Series": "Auto" + }, + { + "Date": "2020-11-13", + "Value": 414, + "Series": "Auto" + }, + { + "Date": "2020-11-24", + "Value": 427, + "Series": "Auto" + }, + { + "Date": "2020-12-05", + "Value": 430, + "Series": "Auto" + }, + { + "Date": "2020-12-16", + "Value": 426, + "Series": "Auto" + }, + { + "Date": "2020-12-27", + "Value": 431, + "Series": "Auto" + }, + { + "Date": "2021-01-07", + "Value": 446, + "Series": "Auto" + }, + { + "Date": "2021-01-18", + "Value": 450, + "Series": "Auto" + }, + { + "Date": "2021-01-29", + "Value": 461, + "Series": "Auto" + }, + { + "Date": "2021-02-09", + "Value": 475, + "Series": "Auto" + }, + { + "Date": "2021-02-20", + "Value": 496, + "Series": "Auto" + }, + { + "Date": "2021-03-03", + "Value": 510, + "Series": "Auto" + }, + { + "Date": "2021-03-14", + "Value": 508, + "Series": "Auto" + }, + { + "Date": "2021-03-24", + "Value": 507, + "Series": "Auto" + }, + { + "Date": "2021-04-04", + "Value": 504, + "Series": "Auto" + }, + { + "Date": "2021-04-15", + "Value": 509, + "Series": "Auto" + }, + { + "Date": "2021-04-26", + "Value": 500, + "Series": "Auto" + }, + { + "Date": "2021-05-07", + "Value": 482, + "Series": "Auto" + }, + { + "Date": "2021-05-18", + "Value": 465, + "Series": "Auto" + }, + { + "Date": "2021-05-29", + "Value": 456, + "Series": "Auto" + }, + { + "Date": "2021-06-09", + "Value": 458, + "Series": "Auto" + }, + { + "Date": "2021-06-20", + "Value": 460, + "Series": "Auto" + }, + { + "Date": "2021-07-01", + "Value": 468, + "Series": "Auto" + }, + { + "Date": "2021-07-12", + "Value": 479, + "Series": "Auto" + }, + { + "Date": "2021-07-23", + "Value": 489, + "Series": "Auto" + }, + { + "Date": "2021-08-03", + "Value": 505, + "Series": "Auto" + }, + { + "Date": "2021-08-14", + "Value": 528, + "Series": "Auto" + }, + { + "Date": "2021-08-25", + "Value": 550, + "Series": "Auto" + }, + { + "Date": "2021-09-05", + "Value": 577, + "Series": "Auto" + }, + { + "Date": "2021-09-16", + "Value": 605, + "Series": "Auto" + }, + { + "Date": "2021-09-27", + "Value": 612, + "Series": "Auto" + }, + { + "Date": "2021-10-08", + "Value": 620, + "Series": "Auto" + }, + { + "Date": "2021-10-19", + "Value": 618, + "Series": "Auto" + }, + { + "Date": "2021-10-29", + "Value": 604, + "Series": "Auto" + }, + { + "Date": "2021-11-09", + "Value": 600, + "Series": "Auto" + }, + { + "Date": "2021-11-20", + "Value": 604, + "Series": "Auto" + }, + { + "Date": "2021-12-01", + "Value": 609, + "Series": "Auto" + }, + { + "Date": "2021-12-12", + "Value": 611, + "Series": "Auto" + }, + { + "Date": "2021-12-23", + "Value": 624, + "Series": "Auto" + }, + { + "Date": "2022-01-03", + "Value": 626, + "Series": "Auto" + }, + { + "Date": "2022-01-14", + "Value": 640, + "Series": "Auto" + }, + { + "Date": "2022-01-25", + "Value": 661, + "Series": "Auto" + }, + { + "Date": "2022-02-05", + "Value": 683, + "Series": "Auto" + }, + { + "Date": "2022-02-16", + "Value": 696, + "Series": "Auto" + }, + { + "Date": "2022-02-27", + "Value": 701, + "Series": "Auto" + }, + { + "Date": "2022-03-10", + "Value": 692, + "Series": "Auto" + }, + { + "Date": "2022-03-21", + "Value": 690, + "Series": "Auto" + }, + { + "Date": "2022-04-01", + "Value": 682, + "Series": "Auto" + }, + { + "Date": "2022-04-12", + "Value": 682, + "Series": "Auto" + }, + { + "Date": "2022-04-23", + "Value": 685, + "Series": "Auto" + }, + { + "Date": "2022-05-04", + "Value": 683, + "Series": "Auto" + }, + { + "Date": "2022-05-15", + "Value": 691, + "Series": "Auto" + }, + { + "Date": "2022-05-26", + "Value": 685, + "Series": "Auto" + }, + { + "Date": "2022-06-05", + "Value": 681, + "Series": "Auto" + }, + { + "Date": "2022-06-16", + "Value": 687, + "Series": "Auto" + }, + { + "Date": "2022-06-27", + "Value": 701, + "Series": "Auto" + }, + { + "Date": "2022-07-08", + "Value": 723, + "Series": "Auto" + }, + { + "Date": "2022-07-19", + "Value": 743, + "Series": "Auto" + }, + { + "Date": "2022-07-30", + "Value": 762, + "Series": "Auto" + }, + { + "Date": "2022-08-10", + "Value": 777, + "Series": "Auto" + }, + { + "Date": "2022-08-21", + "Value": 797, + "Series": "Auto" + }, + { + "Date": "2022-09-01", + "Value": 800, + "Series": "Auto" + }, + { + "Date": "2022-09-12", + "Value": 798, + "Series": "Auto" + }, + { + "Date": "2022-09-23", + "Value": 795, + "Series": "Auto" + }, + { + "Date": "2022-10-04", + "Value": 793, + "Series": "Auto" + }, + { + "Date": "2022-10-15", + "Value": 800, + "Series": "Auto" + }, + { + "Date": "2022-10-26", + "Value": 806, + "Series": "Auto" + }, + { + "Date": "2022-11-06", + "Value": 806, + "Series": "Auto" + }, + { + "Date": "2022-11-17", + "Value": 809, + "Series": "Auto" + }, + { + "Date": "2022-11-28", + "Value": 809, + "Series": "Auto" + }, + { + "Date": "2022-12-09", + "Value": 814, + "Series": "Auto" + }, + { + "Date": "2022-12-20", + "Value": 809, + "Series": "Auto" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/line-chart/03-card200.flint.json b/test-harness/excel/evaluations/inputs/line-chart/03-card200.flint.json new file mode 100644 index 00000000..ce4f874e --- /dev/null +++ b/test-harness/excel/evaluations/inputs/line-chart/03-card200.flint.json @@ -0,0 +1,20023 @@ +{ + "semantic_types": { + "Date": "Date", + "Value": "Quantity", + "Series": "Category" + }, + "chart_spec": { + "chartType": "Line Chart", + "encodings": { + "x": "Date", + "y": "Value", + "color": "Series" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Date": "2020-01-01", + "Value": 229, + "Series": "Electronics" + }, + { + "Date": "2020-01-06", + "Value": 229, + "Series": "Electronics" + }, + { + "Date": "2020-01-11", + "Value": 226, + "Series": "Electronics" + }, + { + "Date": "2020-01-17", + "Value": 225, + "Series": "Electronics" + }, + { + "Date": "2020-01-22", + "Value": 229, + "Series": "Electronics" + }, + { + "Date": "2020-01-28", + "Value": 228, + "Series": "Electronics" + }, + { + "Date": "2020-02-02", + "Value": 225, + "Series": "Electronics" + }, + { + "Date": "2020-02-08", + "Value": 227, + "Series": "Electronics" + }, + { + "Date": "2020-02-13", + "Value": 226, + "Series": "Electronics" + }, + { + "Date": "2020-02-19", + "Value": 225, + "Series": "Electronics" + }, + { + "Date": "2020-02-24", + "Value": 221, + "Series": "Electronics" + }, + { + "Date": "2020-03-01", + "Value": 218, + "Series": "Electronics" + }, + { + "Date": "2020-03-06", + "Value": 213, + "Series": "Electronics" + }, + { + "Date": "2020-03-12", + "Value": 204, + "Series": "Electronics" + }, + { + "Date": "2020-03-17", + "Value": 201, + "Series": "Electronics" + }, + { + "Date": "2020-03-23", + "Value": 194, + "Series": "Electronics" + }, + { + "Date": "2020-03-28", + "Value": 187, + "Series": "Electronics" + }, + { + "Date": "2020-04-03", + "Value": 181, + "Series": "Electronics" + }, + { + "Date": "2020-04-08", + "Value": 180, + "Series": "Electronics" + }, + { + "Date": "2020-04-14", + "Value": 175, + "Series": "Electronics" + }, + { + "Date": "2020-04-19", + "Value": 172, + "Series": "Electronics" + }, + { + "Date": "2020-04-24", + "Value": 165, + "Series": "Electronics" + }, + { + "Date": "2020-04-30", + "Value": 164, + "Series": "Electronics" + }, + { + "Date": "2020-05-05", + "Value": 158, + "Series": "Electronics" + }, + { + "Date": "2020-05-11", + "Value": 158, + "Series": "Electronics" + }, + { + "Date": "2020-05-16", + "Value": 156, + "Series": "Electronics" + }, + { + "Date": "2020-05-22", + "Value": 155, + "Series": "Electronics" + }, + { + "Date": "2020-05-27", + "Value": 149, + "Series": "Electronics" + }, + { + "Date": "2020-06-02", + "Value": 149, + "Series": "Electronics" + }, + { + "Date": "2020-06-07", + "Value": 151, + "Series": "Electronics" + }, + { + "Date": "2020-06-13", + "Value": 156, + "Series": "Electronics" + }, + { + "Date": "2020-06-18", + "Value": 155, + "Series": "Electronics" + }, + { + "Date": "2020-06-24", + "Value": 159, + "Series": "Electronics" + }, + { + "Date": "2020-06-29", + "Value": 166, + "Series": "Electronics" + }, + { + "Date": "2020-07-05", + "Value": 173, + "Series": "Electronics" + }, + { + "Date": "2020-07-10", + "Value": 175, + "Series": "Electronics" + }, + { + "Date": "2020-07-16", + "Value": 177, + "Series": "Electronics" + }, + { + "Date": "2020-07-21", + "Value": 176, + "Series": "Electronics" + }, + { + "Date": "2020-07-27", + "Value": 179, + "Series": "Electronics" + }, + { + "Date": "2020-08-01", + "Value": 182, + "Series": "Electronics" + }, + { + "Date": "2020-08-07", + "Value": 187, + "Series": "Electronics" + }, + { + "Date": "2020-08-12", + "Value": 191, + "Series": "Electronics" + }, + { + "Date": "2020-08-17", + "Value": 197, + "Series": "Electronics" + }, + { + "Date": "2020-08-23", + "Value": 202, + "Series": "Electronics" + }, + { + "Date": "2020-08-28", + "Value": 208, + "Series": "Electronics" + }, + { + "Date": "2020-09-03", + "Value": 210, + "Series": "Electronics" + }, + { + "Date": "2020-09-08", + "Value": 209, + "Series": "Electronics" + }, + { + "Date": "2020-09-14", + "Value": 208, + "Series": "Electronics" + }, + { + "Date": "2020-09-19", + "Value": 204, + "Series": "Electronics" + }, + { + "Date": "2020-09-25", + "Value": 205, + "Series": "Electronics" + }, + { + "Date": "2020-09-30", + "Value": 209, + "Series": "Electronics" + }, + { + "Date": "2020-10-06", + "Value": 216, + "Series": "Electronics" + }, + { + "Date": "2020-10-11", + "Value": 223, + "Series": "Electronics" + }, + { + "Date": "2020-10-17", + "Value": 223, + "Series": "Electronics" + }, + { + "Date": "2020-10-22", + "Value": 221, + "Series": "Electronics" + }, + { + "Date": "2020-10-28", + "Value": 223, + "Series": "Electronics" + }, + { + "Date": "2020-11-02", + "Value": 225, + "Series": "Electronics" + }, + { + "Date": "2020-11-08", + "Value": 223, + "Series": "Electronics" + }, + { + "Date": "2020-11-13", + "Value": 221, + "Series": "Electronics" + }, + { + "Date": "2020-11-19", + "Value": 218, + "Series": "Electronics" + }, + { + "Date": "2020-11-24", + "Value": 219, + "Series": "Electronics" + }, + { + "Date": "2020-11-29", + "Value": 225, + "Series": "Electronics" + }, + { + "Date": "2020-12-05", + "Value": 225, + "Series": "Electronics" + }, + { + "Date": "2020-12-10", + "Value": 229, + "Series": "Electronics" + }, + { + "Date": "2020-12-16", + "Value": 229, + "Series": "Electronics" + }, + { + "Date": "2020-12-21", + "Value": 225, + "Series": "Electronics" + }, + { + "Date": "2020-12-27", + "Value": 220, + "Series": "Electronics" + }, + { + "Date": "2021-01-01", + "Value": 220, + "Series": "Electronics" + }, + { + "Date": "2021-01-07", + "Value": 215, + "Series": "Electronics" + }, + { + "Date": "2021-01-12", + "Value": 216, + "Series": "Electronics" + }, + { + "Date": "2021-01-18", + "Value": 213, + "Series": "Electronics" + }, + { + "Date": "2021-01-23", + "Value": 209, + "Series": "Electronics" + }, + { + "Date": "2021-01-29", + "Value": 210, + "Series": "Electronics" + }, + { + "Date": "2021-02-03", + "Value": 212, + "Series": "Electronics" + }, + { + "Date": "2021-02-09", + "Value": 215, + "Series": "Electronics" + }, + { + "Date": "2021-02-14", + "Value": 220, + "Series": "Electronics" + }, + { + "Date": "2021-02-20", + "Value": 220, + "Series": "Electronics" + }, + { + "Date": "2021-02-25", + "Value": 222, + "Series": "Electronics" + }, + { + "Date": "2021-03-03", + "Value": 224, + "Series": "Electronics" + }, + { + "Date": "2021-03-08", + "Value": 224, + "Series": "Electronics" + }, + { + "Date": "2021-03-14", + "Value": 223, + "Series": "Electronics" + }, + { + "Date": "2021-03-19", + "Value": 221, + "Series": "Electronics" + }, + { + "Date": "2021-03-24", + "Value": 224, + "Series": "Electronics" + }, + { + "Date": "2021-03-30", + "Value": 222, + "Series": "Electronics" + }, + { + "Date": "2021-04-04", + "Value": 220, + "Series": "Electronics" + }, + { + "Date": "2021-04-10", + "Value": 223, + "Series": "Electronics" + }, + { + "Date": "2021-04-15", + "Value": 225, + "Series": "Electronics" + }, + { + "Date": "2021-04-21", + "Value": 230, + "Series": "Electronics" + }, + { + "Date": "2021-04-26", + "Value": 236, + "Series": "Electronics" + }, + { + "Date": "2021-05-02", + "Value": 243, + "Series": "Electronics" + }, + { + "Date": "2021-05-07", + "Value": 247, + "Series": "Electronics" + }, + { + "Date": "2021-05-13", + "Value": 252, + "Series": "Electronics" + }, + { + "Date": "2021-05-18", + "Value": 260, + "Series": "Electronics" + }, + { + "Date": "2021-05-24", + "Value": 270, + "Series": "Electronics" + }, + { + "Date": "2021-05-29", + "Value": 280, + "Series": "Electronics" + }, + { + "Date": "2021-06-04", + "Value": 290, + "Series": "Electronics" + }, + { + "Date": "2021-06-09", + "Value": 302, + "Series": "Electronics" + }, + { + "Date": "2021-06-15", + "Value": 313, + "Series": "Electronics" + }, + { + "Date": "2021-06-20", + "Value": 321, + "Series": "Electronics" + }, + { + "Date": "2021-06-26", + "Value": 326, + "Series": "Electronics" + }, + { + "Date": "2021-07-01", + "Value": 325, + "Series": "Electronics" + }, + { + "Date": "2021-07-06", + "Value": 327, + "Series": "Electronics" + }, + { + "Date": "2021-07-12", + "Value": 330, + "Series": "Electronics" + }, + { + "Date": "2021-07-17", + "Value": 334, + "Series": "Electronics" + }, + { + "Date": "2021-07-23", + "Value": 334, + "Series": "Electronics" + }, + { + "Date": "2021-07-28", + "Value": 329, + "Series": "Electronics" + }, + { + "Date": "2021-08-03", + "Value": 331, + "Series": "Electronics" + }, + { + "Date": "2021-08-08", + "Value": 337, + "Series": "Electronics" + }, + { + "Date": "2021-08-14", + "Value": 343, + "Series": "Electronics" + }, + { + "Date": "2021-08-19", + "Value": 350, + "Series": "Electronics" + }, + { + "Date": "2021-08-25", + "Value": 350, + "Series": "Electronics" + }, + { + "Date": "2021-08-30", + "Value": 347, + "Series": "Electronics" + }, + { + "Date": "2021-09-05", + "Value": 343, + "Series": "Electronics" + }, + { + "Date": "2021-09-10", + "Value": 337, + "Series": "Electronics" + }, + { + "Date": "2021-09-16", + "Value": 332, + "Series": "Electronics" + }, + { + "Date": "2021-09-21", + "Value": 324, + "Series": "Electronics" + }, + { + "Date": "2021-09-27", + "Value": 322, + "Series": "Electronics" + }, + { + "Date": "2021-10-02", + "Value": 321, + "Series": "Electronics" + }, + { + "Date": "2021-10-08", + "Value": 326, + "Series": "Electronics" + }, + { + "Date": "2021-10-13", + "Value": 328, + "Series": "Electronics" + }, + { + "Date": "2021-10-19", + "Value": 331, + "Series": "Electronics" + }, + { + "Date": "2021-10-24", + "Value": 330, + "Series": "Electronics" + }, + { + "Date": "2021-10-29", + "Value": 328, + "Series": "Electronics" + }, + { + "Date": "2021-11-04", + "Value": 327, + "Series": "Electronics" + }, + { + "Date": "2021-11-09", + "Value": 331, + "Series": "Electronics" + }, + { + "Date": "2021-11-15", + "Value": 333, + "Series": "Electronics" + }, + { + "Date": "2021-11-20", + "Value": 337, + "Series": "Electronics" + }, + { + "Date": "2021-11-26", + "Value": 342, + "Series": "Electronics" + }, + { + "Date": "2021-12-01", + "Value": 346, + "Series": "Electronics" + }, + { + "Date": "2021-12-07", + "Value": 353, + "Series": "Electronics" + }, + { + "Date": "2021-12-12", + "Value": 354, + "Series": "Electronics" + }, + { + "Date": "2021-12-18", + "Value": 352, + "Series": "Electronics" + }, + { + "Date": "2021-12-23", + "Value": 353, + "Series": "Electronics" + }, + { + "Date": "2021-12-29", + "Value": 357, + "Series": "Electronics" + }, + { + "Date": "2022-01-03", + "Value": 355, + "Series": "Electronics" + }, + { + "Date": "2022-01-09", + "Value": 354, + "Series": "Electronics" + }, + { + "Date": "2022-01-14", + "Value": 350, + "Series": "Electronics" + }, + { + "Date": "2022-01-20", + "Value": 352, + "Series": "Electronics" + }, + { + "Date": "2022-01-25", + "Value": 350, + "Series": "Electronics" + }, + { + "Date": "2022-01-31", + "Value": 350, + "Series": "Electronics" + }, + { + "Date": "2022-02-05", + "Value": 352, + "Series": "Electronics" + }, + { + "Date": "2022-02-10", + "Value": 351, + "Series": "Electronics" + }, + { + "Date": "2022-02-16", + "Value": 351, + "Series": "Electronics" + }, + { + "Date": "2022-02-21", + "Value": 349, + "Series": "Electronics" + }, + { + "Date": "2022-02-27", + "Value": 353, + "Series": "Electronics" + }, + { + "Date": "2022-03-04", + "Value": 359, + "Series": "Electronics" + }, + { + "Date": "2022-03-10", + "Value": 363, + "Series": "Electronics" + }, + { + "Date": "2022-03-15", + "Value": 365, + "Series": "Electronics" + }, + { + "Date": "2022-03-21", + "Value": 369, + "Series": "Electronics" + }, + { + "Date": "2022-03-26", + "Value": 373, + "Series": "Electronics" + }, + { + "Date": "2022-04-01", + "Value": 376, + "Series": "Electronics" + }, + { + "Date": "2022-04-06", + "Value": 374, + "Series": "Electronics" + }, + { + "Date": "2022-04-12", + "Value": 372, + "Series": "Electronics" + }, + { + "Date": "2022-04-17", + "Value": 371, + "Series": "Electronics" + }, + { + "Date": "2022-04-23", + "Value": 368, + "Series": "Electronics" + }, + { + "Date": "2022-04-28", + "Value": 362, + "Series": "Electronics" + }, + { + "Date": "2022-05-04", + "Value": 362, + "Series": "Electronics" + }, + { + "Date": "2022-05-09", + "Value": 364, + "Series": "Electronics" + }, + { + "Date": "2022-05-15", + "Value": 368, + "Series": "Electronics" + }, + { + "Date": "2022-05-20", + "Value": 370, + "Series": "Electronics" + }, + { + "Date": "2022-05-26", + "Value": 372, + "Series": "Electronics" + }, + { + "Date": "2022-05-31", + "Value": 374, + "Series": "Electronics" + }, + { + "Date": "2022-06-05", + "Value": 371, + "Series": "Electronics" + }, + { + "Date": "2022-06-11", + "Value": 366, + "Series": "Electronics" + }, + { + "Date": "2022-06-16", + "Value": 366, + "Series": "Electronics" + }, + { + "Date": "2022-06-22", + "Value": 365, + "Series": "Electronics" + }, + { + "Date": "2022-06-27", + "Value": 360, + "Series": "Electronics" + }, + { + "Date": "2022-07-03", + "Value": 352, + "Series": "Electronics" + }, + { + "Date": "2022-07-08", + "Value": 350, + "Series": "Electronics" + }, + { + "Date": "2022-07-14", + "Value": 351, + "Series": "Electronics" + }, + { + "Date": "2022-07-19", + "Value": 349, + "Series": "Electronics" + }, + { + "Date": "2022-07-25", + "Value": 349, + "Series": "Electronics" + }, + { + "Date": "2022-07-30", + "Value": 350, + "Series": "Electronics" + }, + { + "Date": "2022-08-05", + "Value": 356, + "Series": "Electronics" + }, + { + "Date": "2022-08-10", + "Value": 356, + "Series": "Electronics" + }, + { + "Date": "2022-08-16", + "Value": 360, + "Series": "Electronics" + }, + { + "Date": "2022-08-21", + "Value": 363, + "Series": "Electronics" + }, + { + "Date": "2022-08-27", + "Value": 367, + "Series": "Electronics" + }, + { + "Date": "2022-09-01", + "Value": 375, + "Series": "Electronics" + }, + { + "Date": "2022-09-07", + "Value": 382, + "Series": "Electronics" + }, + { + "Date": "2022-09-12", + "Value": 391, + "Series": "Electronics" + }, + { + "Date": "2022-09-17", + "Value": 401, + "Series": "Electronics" + }, + { + "Date": "2022-09-23", + "Value": 408, + "Series": "Electronics" + }, + { + "Date": "2022-09-28", + "Value": 408, + "Series": "Electronics" + }, + { + "Date": "2022-10-04", + "Value": 413, + "Series": "Electronics" + }, + { + "Date": "2022-10-09", + "Value": 418, + "Series": "Electronics" + }, + { + "Date": "2022-10-15", + "Value": 420, + "Series": "Electronics" + }, + { + "Date": "2022-10-20", + "Value": 423, + "Series": "Electronics" + }, + { + "Date": "2022-10-26", + "Value": 421, + "Series": "Electronics" + }, + { + "Date": "2022-10-31", + "Value": 418, + "Series": "Electronics" + }, + { + "Date": "2022-11-06", + "Value": 414, + "Series": "Electronics" + }, + { + "Date": "2022-11-11", + "Value": 413, + "Series": "Electronics" + }, + { + "Date": "2022-11-17", + "Value": 412, + "Series": "Electronics" + }, + { + "Date": "2022-11-22", + "Value": 412, + "Series": "Electronics" + }, + { + "Date": "2022-11-28", + "Value": 409, + "Series": "Electronics" + }, + { + "Date": "2022-12-03", + "Value": 409, + "Series": "Electronics" + }, + { + "Date": "2022-12-09", + "Value": 408, + "Series": "Electronics" + }, + { + "Date": "2022-12-14", + "Value": 404, + "Series": "Electronics" + }, + { + "Date": "2022-12-20", + "Value": 397, + "Series": "Electronics" + }, + { + "Date": "2022-12-25", + "Value": 391, + "Series": "Electronics" + }, + { + "Date": "2020-01-01", + "Value": 143, + "Series": "Clothing" + }, + { + "Date": "2020-01-06", + "Value": 142, + "Series": "Clothing" + }, + { + "Date": "2020-01-11", + "Value": 143, + "Series": "Clothing" + }, + { + "Date": "2020-01-17", + "Value": 134, + "Series": "Clothing" + }, + { + "Date": "2020-01-22", + "Value": 141, + "Series": "Clothing" + }, + { + "Date": "2020-01-28", + "Value": 159, + "Series": "Clothing" + }, + { + "Date": "2020-02-02", + "Value": 173, + "Series": "Clothing" + }, + { + "Date": "2020-02-08", + "Value": 183, + "Series": "Clothing" + }, + { + "Date": "2020-02-13", + "Value": 190, + "Series": "Clothing" + }, + { + "Date": "2020-02-19", + "Value": 181, + "Series": "Clothing" + }, + { + "Date": "2020-02-24", + "Value": 183, + "Series": "Clothing" + }, + { + "Date": "2020-03-01", + "Value": 192, + "Series": "Clothing" + }, + { + "Date": "2020-03-06", + "Value": 189, + "Series": "Clothing" + }, + { + "Date": "2020-03-12", + "Value": 200, + "Series": "Clothing" + }, + { + "Date": "2020-03-17", + "Value": 214, + "Series": "Clothing" + }, + { + "Date": "2020-03-23", + "Value": 235, + "Series": "Clothing" + }, + { + "Date": "2020-03-28", + "Value": 242, + "Series": "Clothing" + }, + { + "Date": "2020-04-03", + "Value": 240, + "Series": "Clothing" + }, + { + "Date": "2020-04-08", + "Value": 234, + "Series": "Clothing" + }, + { + "Date": "2020-04-14", + "Value": 229, + "Series": "Clothing" + }, + { + "Date": "2020-04-19", + "Value": 238, + "Series": "Clothing" + }, + { + "Date": "2020-04-24", + "Value": 235, + "Series": "Clothing" + }, + { + "Date": "2020-04-30", + "Value": 245, + "Series": "Clothing" + }, + { + "Date": "2020-05-05", + "Value": 249, + "Series": "Clothing" + }, + { + "Date": "2020-05-11", + "Value": 247, + "Series": "Clothing" + }, + { + "Date": "2020-05-16", + "Value": 233, + "Series": "Clothing" + }, + { + "Date": "2020-05-22", + "Value": 225, + "Series": "Clothing" + }, + { + "Date": "2020-05-27", + "Value": 224, + "Series": "Clothing" + }, + { + "Date": "2020-06-02", + "Value": 225, + "Series": "Clothing" + }, + { + "Date": "2020-06-07", + "Value": 226, + "Series": "Clothing" + }, + { + "Date": "2020-06-13", + "Value": 218, + "Series": "Clothing" + }, + { + "Date": "2020-06-18", + "Value": 200, + "Series": "Clothing" + }, + { + "Date": "2020-06-24", + "Value": 187, + "Series": "Clothing" + }, + { + "Date": "2020-06-29", + "Value": 175, + "Series": "Clothing" + }, + { + "Date": "2020-07-05", + "Value": 169, + "Series": "Clothing" + }, + { + "Date": "2020-07-10", + "Value": 178, + "Series": "Clothing" + }, + { + "Date": "2020-07-16", + "Value": 192, + "Series": "Clothing" + }, + { + "Date": "2020-07-21", + "Value": 197, + "Series": "Clothing" + }, + { + "Date": "2020-07-27", + "Value": 203, + "Series": "Clothing" + }, + { + "Date": "2020-08-01", + "Value": 219, + "Series": "Clothing" + }, + { + "Date": "2020-08-07", + "Value": 243, + "Series": "Clothing" + }, + { + "Date": "2020-08-12", + "Value": 264, + "Series": "Clothing" + }, + { + "Date": "2020-08-17", + "Value": 269, + "Series": "Clothing" + }, + { + "Date": "2020-08-23", + "Value": 260, + "Series": "Clothing" + }, + { + "Date": "2020-08-28", + "Value": 250, + "Series": "Clothing" + }, + { + "Date": "2020-09-03", + "Value": 235, + "Series": "Clothing" + }, + { + "Date": "2020-09-08", + "Value": 232, + "Series": "Clothing" + }, + { + "Date": "2020-09-14", + "Value": 220, + "Series": "Clothing" + }, + { + "Date": "2020-09-19", + "Value": 202, + "Series": "Clothing" + }, + { + "Date": "2020-09-25", + "Value": 195, + "Series": "Clothing" + }, + { + "Date": "2020-09-30", + "Value": 200, + "Series": "Clothing" + }, + { + "Date": "2020-10-06", + "Value": 192, + "Series": "Clothing" + }, + { + "Date": "2020-10-11", + "Value": 182, + "Series": "Clothing" + }, + { + "Date": "2020-10-17", + "Value": 183, + "Series": "Clothing" + }, + { + "Date": "2020-10-22", + "Value": 173, + "Series": "Clothing" + }, + { + "Date": "2020-10-28", + "Value": 173, + "Series": "Clothing" + }, + { + "Date": "2020-11-02", + "Value": 182, + "Series": "Clothing" + }, + { + "Date": "2020-11-08", + "Value": 188, + "Series": "Clothing" + }, + { + "Date": "2020-11-13", + "Value": 182, + "Series": "Clothing" + }, + { + "Date": "2020-11-19", + "Value": 188, + "Series": "Clothing" + }, + { + "Date": "2020-11-24", + "Value": 198, + "Series": "Clothing" + }, + { + "Date": "2020-11-29", + "Value": 194, + "Series": "Clothing" + }, + { + "Date": "2020-12-05", + "Value": 186, + "Series": "Clothing" + }, + { + "Date": "2020-12-10", + "Value": 180, + "Series": "Clothing" + }, + { + "Date": "2020-12-16", + "Value": 166, + "Series": "Clothing" + }, + { + "Date": "2020-12-21", + "Value": 171, + "Series": "Clothing" + }, + { + "Date": "2020-12-27", + "Value": 173, + "Series": "Clothing" + }, + { + "Date": "2021-01-01", + "Value": 188, + "Series": "Clothing" + }, + { + "Date": "2021-01-07", + "Value": 209, + "Series": "Clothing" + }, + { + "Date": "2021-01-12", + "Value": 237, + "Series": "Clothing" + }, + { + "Date": "2021-01-18", + "Value": 254, + "Series": "Clothing" + }, + { + "Date": "2021-01-23", + "Value": 264, + "Series": "Clothing" + }, + { + "Date": "2021-01-29", + "Value": 277, + "Series": "Clothing" + }, + { + "Date": "2021-02-03", + "Value": 272, + "Series": "Clothing" + }, + { + "Date": "2021-02-09", + "Value": 282, + "Series": "Clothing" + }, + { + "Date": "2021-02-14", + "Value": 285, + "Series": "Clothing" + }, + { + "Date": "2021-02-20", + "Value": 280, + "Series": "Clothing" + }, + { + "Date": "2021-02-25", + "Value": 280, + "Series": "Clothing" + }, + { + "Date": "2021-03-03", + "Value": 289, + "Series": "Clothing" + }, + { + "Date": "2021-03-08", + "Value": 304, + "Series": "Clothing" + }, + { + "Date": "2021-03-14", + "Value": 302, + "Series": "Clothing" + }, + { + "Date": "2021-03-19", + "Value": 311, + "Series": "Clothing" + }, + { + "Date": "2021-03-24", + "Value": 303, + "Series": "Clothing" + }, + { + "Date": "2021-03-30", + "Value": 289, + "Series": "Clothing" + }, + { + "Date": "2021-04-04", + "Value": 272, + "Series": "Clothing" + }, + { + "Date": "2021-04-10", + "Value": 269, + "Series": "Clothing" + }, + { + "Date": "2021-04-15", + "Value": 280, + "Series": "Clothing" + }, + { + "Date": "2021-04-21", + "Value": 291, + "Series": "Clothing" + }, + { + "Date": "2021-04-26", + "Value": 291, + "Series": "Clothing" + }, + { + "Date": "2021-05-02", + "Value": 294, + "Series": "Clothing" + }, + { + "Date": "2021-05-07", + "Value": 305, + "Series": "Clothing" + }, + { + "Date": "2021-05-13", + "Value": 320, + "Series": "Clothing" + }, + { + "Date": "2021-05-18", + "Value": 323, + "Series": "Clothing" + }, + { + "Date": "2021-05-24", + "Value": 318, + "Series": "Clothing" + }, + { + "Date": "2021-05-29", + "Value": 313, + "Series": "Clothing" + }, + { + "Date": "2021-06-04", + "Value": 299, + "Series": "Clothing" + }, + { + "Date": "2021-06-09", + "Value": 294, + "Series": "Clothing" + }, + { + "Date": "2021-06-15", + "Value": 276, + "Series": "Clothing" + }, + { + "Date": "2021-06-20", + "Value": 257, + "Series": "Clothing" + }, + { + "Date": "2021-06-26", + "Value": 243, + "Series": "Clothing" + }, + { + "Date": "2021-07-01", + "Value": 239, + "Series": "Clothing" + }, + { + "Date": "2021-07-06", + "Value": 248, + "Series": "Clothing" + }, + { + "Date": "2021-07-12", + "Value": 250, + "Series": "Clothing" + }, + { + "Date": "2021-07-17", + "Value": 261, + "Series": "Clothing" + }, + { + "Date": "2021-07-23", + "Value": 277, + "Series": "Clothing" + }, + { + "Date": "2021-07-28", + "Value": 286, + "Series": "Clothing" + }, + { + "Date": "2021-08-03", + "Value": 281, + "Series": "Clothing" + }, + { + "Date": "2021-08-08", + "Value": 277, + "Series": "Clothing" + }, + { + "Date": "2021-08-14", + "Value": 284, + "Series": "Clothing" + }, + { + "Date": "2021-08-19", + "Value": 287, + "Series": "Clothing" + }, + { + "Date": "2021-08-25", + "Value": 284, + "Series": "Clothing" + }, + { + "Date": "2021-08-30", + "Value": 269, + "Series": "Clothing" + }, + { + "Date": "2021-09-05", + "Value": 251, + "Series": "Clothing" + }, + { + "Date": "2021-09-10", + "Value": 235, + "Series": "Clothing" + }, + { + "Date": "2021-09-16", + "Value": 220, + "Series": "Clothing" + }, + { + "Date": "2021-09-21", + "Value": 217, + "Series": "Clothing" + }, + { + "Date": "2021-09-27", + "Value": 229, + "Series": "Clothing" + }, + { + "Date": "2021-10-02", + "Value": 248, + "Series": "Clothing" + }, + { + "Date": "2021-10-08", + "Value": 273, + "Series": "Clothing" + }, + { + "Date": "2021-10-13", + "Value": 290, + "Series": "Clothing" + }, + { + "Date": "2021-10-19", + "Value": 292, + "Series": "Clothing" + }, + { + "Date": "2021-10-24", + "Value": 282, + "Series": "Clothing" + }, + { + "Date": "2021-10-29", + "Value": 272, + "Series": "Clothing" + }, + { + "Date": "2021-11-04", + "Value": 254, + "Series": "Clothing" + }, + { + "Date": "2021-11-09", + "Value": 230, + "Series": "Clothing" + }, + { + "Date": "2021-11-15", + "Value": 220, + "Series": "Clothing" + }, + { + "Date": "2021-11-20", + "Value": 203, + "Series": "Clothing" + }, + { + "Date": "2021-11-26", + "Value": 182, + "Series": "Clothing" + }, + { + "Date": "2021-12-01", + "Value": 155, + "Series": "Clothing" + }, + { + "Date": "2021-12-07", + "Value": 131, + "Series": "Clothing" + }, + { + "Date": "2021-12-12", + "Value": 120, + "Series": "Clothing" + }, + { + "Date": "2021-12-18", + "Value": 104, + "Series": "Clothing" + }, + { + "Date": "2021-12-23", + "Value": 88, + "Series": "Clothing" + }, + { + "Date": "2021-12-29", + "Value": 91, + "Series": "Clothing" + }, + { + "Date": "2022-01-03", + "Value": 96, + "Series": "Clothing" + }, + { + "Date": "2022-01-09", + "Value": 87, + "Series": "Clothing" + }, + { + "Date": "2022-01-14", + "Value": 89, + "Series": "Clothing" + }, + { + "Date": "2022-01-20", + "Value": 96, + "Series": "Clothing" + }, + { + "Date": "2022-01-25", + "Value": 90, + "Series": "Clothing" + }, + { + "Date": "2022-01-31", + "Value": 80, + "Series": "Clothing" + }, + { + "Date": "2022-02-05", + "Value": 75, + "Series": "Clothing" + }, + { + "Date": "2022-02-10", + "Value": 74, + "Series": "Clothing" + }, + { + "Date": "2022-02-16", + "Value": 82, + "Series": "Clothing" + }, + { + "Date": "2022-02-21", + "Value": 77, + "Series": "Clothing" + }, + { + "Date": "2022-02-27", + "Value": 77, + "Series": "Clothing" + }, + { + "Date": "2022-03-04", + "Value": 85, + "Series": "Clothing" + }, + { + "Date": "2022-03-10", + "Value": 102, + "Series": "Clothing" + }, + { + "Date": "2022-03-15", + "Value": 116, + "Series": "Clothing" + }, + { + "Date": "2022-03-21", + "Value": 129, + "Series": "Clothing" + }, + { + "Date": "2022-03-26", + "Value": 138, + "Series": "Clothing" + }, + { + "Date": "2022-04-01", + "Value": 159, + "Series": "Clothing" + }, + { + "Date": "2022-04-06", + "Value": 182, + "Series": "Clothing" + }, + { + "Date": "2022-04-12", + "Value": 206, + "Series": "Clothing" + }, + { + "Date": "2022-04-17", + "Value": 218, + "Series": "Clothing" + }, + { + "Date": "2022-04-23", + "Value": 233, + "Series": "Clothing" + }, + { + "Date": "2022-04-28", + "Value": 240, + "Series": "Clothing" + }, + { + "Date": "2022-05-04", + "Value": 249, + "Series": "Clothing" + }, + { + "Date": "2022-05-09", + "Value": 241, + "Series": "Clothing" + }, + { + "Date": "2022-05-15", + "Value": 230, + "Series": "Clothing" + }, + { + "Date": "2022-05-20", + "Value": 213, + "Series": "Clothing" + }, + { + "Date": "2022-05-26", + "Value": 201, + "Series": "Clothing" + }, + { + "Date": "2022-05-31", + "Value": 198, + "Series": "Clothing" + }, + { + "Date": "2022-06-05", + "Value": 186, + "Series": "Clothing" + }, + { + "Date": "2022-06-11", + "Value": 188, + "Series": "Clothing" + }, + { + "Date": "2022-06-16", + "Value": 190, + "Series": "Clothing" + }, + { + "Date": "2022-06-22", + "Value": 192, + "Series": "Clothing" + }, + { + "Date": "2022-06-27", + "Value": 198, + "Series": "Clothing" + }, + { + "Date": "2022-07-03", + "Value": 215, + "Series": "Clothing" + }, + { + "Date": "2022-07-08", + "Value": 213, + "Series": "Clothing" + }, + { + "Date": "2022-07-14", + "Value": 209, + "Series": "Clothing" + }, + { + "Date": "2022-07-19", + "Value": 194, + "Series": "Clothing" + }, + { + "Date": "2022-07-25", + "Value": 193, + "Series": "Clothing" + }, + { + "Date": "2022-07-30", + "Value": 194, + "Series": "Clothing" + }, + { + "Date": "2022-08-05", + "Value": 194, + "Series": "Clothing" + }, + { + "Date": "2022-08-10", + "Value": 188, + "Series": "Clothing" + }, + { + "Date": "2022-08-16", + "Value": 192, + "Series": "Clothing" + }, + { + "Date": "2022-08-21", + "Value": 206, + "Series": "Clothing" + }, + { + "Date": "2022-08-27", + "Value": 225, + "Series": "Clothing" + }, + { + "Date": "2022-09-01", + "Value": 252, + "Series": "Clothing" + }, + { + "Date": "2022-09-07", + "Value": 276, + "Series": "Clothing" + }, + { + "Date": "2022-09-12", + "Value": 292, + "Series": "Clothing" + }, + { + "Date": "2022-09-17", + "Value": 290, + "Series": "Clothing" + }, + { + "Date": "2022-09-23", + "Value": 280, + "Series": "Clothing" + }, + { + "Date": "2022-09-28", + "Value": 273, + "Series": "Clothing" + }, + { + "Date": "2022-10-04", + "Value": 259, + "Series": "Clothing" + }, + { + "Date": "2022-10-09", + "Value": 242, + "Series": "Clothing" + }, + { + "Date": "2022-10-15", + "Value": 218, + "Series": "Clothing" + }, + { + "Date": "2022-10-20", + "Value": 206, + "Series": "Clothing" + }, + { + "Date": "2022-10-26", + "Value": 190, + "Series": "Clothing" + }, + { + "Date": "2022-10-31", + "Value": 170, + "Series": "Clothing" + }, + { + "Date": "2022-11-06", + "Value": 153, + "Series": "Clothing" + }, + { + "Date": "2022-11-11", + "Value": 143, + "Series": "Clothing" + }, + { + "Date": "2022-11-17", + "Value": 131, + "Series": "Clothing" + }, + { + "Date": "2022-11-22", + "Value": 114, + "Series": "Clothing" + }, + { + "Date": "2022-11-28", + "Value": 107, + "Series": "Clothing" + }, + { + "Date": "2022-12-03", + "Value": 95, + "Series": "Clothing" + }, + { + "Date": "2022-12-09", + "Value": 85, + "Series": "Clothing" + }, + { + "Date": "2022-12-14", + "Value": 84, + "Series": "Clothing" + }, + { + "Date": "2022-12-20", + "Value": 89, + "Series": "Clothing" + }, + { + "Date": "2022-12-25", + "Value": 87, + "Series": "Clothing" + }, + { + "Date": "2020-01-01", + "Value": 109, + "Series": "Food" + }, + { + "Date": "2020-01-06", + "Value": 100, + "Series": "Food" + }, + { + "Date": "2020-01-11", + "Value": 97, + "Series": "Food" + }, + { + "Date": "2020-01-17", + "Value": 101, + "Series": "Food" + }, + { + "Date": "2020-01-22", + "Value": 112, + "Series": "Food" + }, + { + "Date": "2020-01-28", + "Value": 119, + "Series": "Food" + }, + { + "Date": "2020-02-02", + "Value": 125, + "Series": "Food" + }, + { + "Date": "2020-02-08", + "Value": 124, + "Series": "Food" + }, + { + "Date": "2020-02-13", + "Value": 126, + "Series": "Food" + }, + { + "Date": "2020-02-19", + "Value": 136, + "Series": "Food" + }, + { + "Date": "2020-02-24", + "Value": 150, + "Series": "Food" + }, + { + "Date": "2020-03-01", + "Value": 157, + "Series": "Food" + }, + { + "Date": "2020-03-06", + "Value": 153, + "Series": "Food" + }, + { + "Date": "2020-03-12", + "Value": 140, + "Series": "Food" + }, + { + "Date": "2020-03-17", + "Value": 129, + "Series": "Food" + }, + { + "Date": "2020-03-23", + "Value": 121, + "Series": "Food" + }, + { + "Date": "2020-03-28", + "Value": 121, + "Series": "Food" + }, + { + "Date": "2020-04-03", + "Value": 116, + "Series": "Food" + }, + { + "Date": "2020-04-08", + "Value": 120, + "Series": "Food" + }, + { + "Date": "2020-04-14", + "Value": 118, + "Series": "Food" + }, + { + "Date": "2020-04-19", + "Value": 123, + "Series": "Food" + }, + { + "Date": "2020-04-24", + "Value": 133, + "Series": "Food" + }, + { + "Date": "2020-04-30", + "Value": 145, + "Series": "Food" + }, + { + "Date": "2020-05-05", + "Value": 149, + "Series": "Food" + }, + { + "Date": "2020-05-11", + "Value": 144, + "Series": "Food" + }, + { + "Date": "2020-05-16", + "Value": 135, + "Series": "Food" + }, + { + "Date": "2020-05-22", + "Value": 126, + "Series": "Food" + }, + { + "Date": "2020-05-27", + "Value": 124, + "Series": "Food" + }, + { + "Date": "2020-06-02", + "Value": 128, + "Series": "Food" + }, + { + "Date": "2020-06-07", + "Value": 123, + "Series": "Food" + }, + { + "Date": "2020-06-13", + "Value": 120, + "Series": "Food" + }, + { + "Date": "2020-06-18", + "Value": 123, + "Series": "Food" + }, + { + "Date": "2020-06-24", + "Value": 122, + "Series": "Food" + }, + { + "Date": "2020-06-29", + "Value": 130, + "Series": "Food" + }, + { + "Date": "2020-07-05", + "Value": 130, + "Series": "Food" + }, + { + "Date": "2020-07-10", + "Value": 125, + "Series": "Food" + }, + { + "Date": "2020-07-16", + "Value": 129, + "Series": "Food" + }, + { + "Date": "2020-07-21", + "Value": 136, + "Series": "Food" + }, + { + "Date": "2020-07-27", + "Value": 150, + "Series": "Food" + }, + { + "Date": "2020-08-01", + "Value": 169, + "Series": "Food" + }, + { + "Date": "2020-08-07", + "Value": 181, + "Series": "Food" + }, + { + "Date": "2020-08-12", + "Value": 183, + "Series": "Food" + }, + { + "Date": "2020-08-17", + "Value": 183, + "Series": "Food" + }, + { + "Date": "2020-08-23", + "Value": 183, + "Series": "Food" + }, + { + "Date": "2020-08-28", + "Value": 186, + "Series": "Food" + }, + { + "Date": "2020-09-03", + "Value": 180, + "Series": "Food" + }, + { + "Date": "2020-09-08", + "Value": 184, + "Series": "Food" + }, + { + "Date": "2020-09-14", + "Value": 186, + "Series": "Food" + }, + { + "Date": "2020-09-19", + "Value": 187, + "Series": "Food" + }, + { + "Date": "2020-09-25", + "Value": 186, + "Series": "Food" + }, + { + "Date": "2020-09-30", + "Value": 190, + "Series": "Food" + }, + { + "Date": "2020-10-06", + "Value": 190, + "Series": "Food" + }, + { + "Date": "2020-10-11", + "Value": 181, + "Series": "Food" + }, + { + "Date": "2020-10-17", + "Value": 170, + "Series": "Food" + }, + { + "Date": "2020-10-22", + "Value": 156, + "Series": "Food" + }, + { + "Date": "2020-10-28", + "Value": 139, + "Series": "Food" + }, + { + "Date": "2020-11-02", + "Value": 126, + "Series": "Food" + }, + { + "Date": "2020-11-08", + "Value": 119, + "Series": "Food" + }, + { + "Date": "2020-11-13", + "Value": 118, + "Series": "Food" + }, + { + "Date": "2020-11-19", + "Value": 114, + "Series": "Food" + }, + { + "Date": "2020-11-24", + "Value": 116, + "Series": "Food" + }, + { + "Date": "2020-11-29", + "Value": 124, + "Series": "Food" + }, + { + "Date": "2020-12-05", + "Value": 127, + "Series": "Food" + }, + { + "Date": "2020-12-10", + "Value": 131, + "Series": "Food" + }, + { + "Date": "2020-12-16", + "Value": 125, + "Series": "Food" + }, + { + "Date": "2020-12-21", + "Value": 129, + "Series": "Food" + }, + { + "Date": "2020-12-27", + "Value": 131, + "Series": "Food" + }, + { + "Date": "2021-01-01", + "Value": 135, + "Series": "Food" + }, + { + "Date": "2021-01-07", + "Value": 142, + "Series": "Food" + }, + { + "Date": "2021-01-12", + "Value": 150, + "Series": "Food" + }, + { + "Date": "2021-01-18", + "Value": 157, + "Series": "Food" + }, + { + "Date": "2021-01-23", + "Value": 156, + "Series": "Food" + }, + { + "Date": "2021-01-29", + "Value": 152, + "Series": "Food" + }, + { + "Date": "2021-02-03", + "Value": 159, + "Series": "Food" + }, + { + "Date": "2021-02-09", + "Value": 166, + "Series": "Food" + }, + { + "Date": "2021-02-14", + "Value": 171, + "Series": "Food" + }, + { + "Date": "2021-02-20", + "Value": 166, + "Series": "Food" + }, + { + "Date": "2021-02-25", + "Value": 158, + "Series": "Food" + }, + { + "Date": "2021-03-03", + "Value": 154, + "Series": "Food" + }, + { + "Date": "2021-03-08", + "Value": 146, + "Series": "Food" + }, + { + "Date": "2021-03-14", + "Value": 136, + "Series": "Food" + }, + { + "Date": "2021-03-19", + "Value": 136, + "Series": "Food" + }, + { + "Date": "2021-03-24", + "Value": 129, + "Series": "Food" + }, + { + "Date": "2021-03-30", + "Value": 126, + "Series": "Food" + }, + { + "Date": "2021-04-04", + "Value": 117, + "Series": "Food" + }, + { + "Date": "2021-04-10", + "Value": 106, + "Series": "Food" + }, + { + "Date": "2021-04-15", + "Value": 105, + "Series": "Food" + }, + { + "Date": "2021-04-21", + "Value": 109, + "Series": "Food" + }, + { + "Date": "2021-04-26", + "Value": 112, + "Series": "Food" + }, + { + "Date": "2021-05-02", + "Value": 120, + "Series": "Food" + }, + { + "Date": "2021-05-07", + "Value": 127, + "Series": "Food" + }, + { + "Date": "2021-05-13", + "Value": 132, + "Series": "Food" + }, + { + "Date": "2021-05-18", + "Value": 134, + "Series": "Food" + }, + { + "Date": "2021-05-24", + "Value": 145, + "Series": "Food" + }, + { + "Date": "2021-05-29", + "Value": 148, + "Series": "Food" + }, + { + "Date": "2021-06-04", + "Value": 151, + "Series": "Food" + }, + { + "Date": "2021-06-09", + "Value": 157, + "Series": "Food" + }, + { + "Date": "2021-06-15", + "Value": 156, + "Series": "Food" + }, + { + "Date": "2021-06-20", + "Value": 146, + "Series": "Food" + }, + { + "Date": "2021-06-26", + "Value": 145, + "Series": "Food" + }, + { + "Date": "2021-07-01", + "Value": 142, + "Series": "Food" + }, + { + "Date": "2021-07-06", + "Value": 149, + "Series": "Food" + }, + { + "Date": "2021-07-12", + "Value": 159, + "Series": "Food" + }, + { + "Date": "2021-07-17", + "Value": 157, + "Series": "Food" + }, + { + "Date": "2021-07-23", + "Value": 159, + "Series": "Food" + }, + { + "Date": "2021-07-28", + "Value": 157, + "Series": "Food" + }, + { + "Date": "2021-08-03", + "Value": 148, + "Series": "Food" + }, + { + "Date": "2021-08-08", + "Value": 147, + "Series": "Food" + }, + { + "Date": "2021-08-14", + "Value": 140, + "Series": "Food" + }, + { + "Date": "2021-08-19", + "Value": 145, + "Series": "Food" + }, + { + "Date": "2021-08-25", + "Value": 144, + "Series": "Food" + }, + { + "Date": "2021-08-30", + "Value": 143, + "Series": "Food" + }, + { + "Date": "2021-09-05", + "Value": 135, + "Series": "Food" + }, + { + "Date": "2021-09-10", + "Value": 120, + "Series": "Food" + }, + { + "Date": "2021-09-16", + "Value": 100, + "Series": "Food" + }, + { + "Date": "2021-09-21", + "Value": 88, + "Series": "Food" + }, + { + "Date": "2021-09-27", + "Value": 86, + "Series": "Food" + }, + { + "Date": "2021-10-02", + "Value": 88, + "Series": "Food" + }, + { + "Date": "2021-10-08", + "Value": 89, + "Series": "Food" + }, + { + "Date": "2021-10-13", + "Value": 85, + "Series": "Food" + }, + { + "Date": "2021-10-19", + "Value": 81, + "Series": "Food" + }, + { + "Date": "2021-10-24", + "Value": 76, + "Series": "Food" + }, + { + "Date": "2021-10-29", + "Value": 80, + "Series": "Food" + }, + { + "Date": "2021-11-04", + "Value": 88, + "Series": "Food" + }, + { + "Date": "2021-11-09", + "Value": 87, + "Series": "Food" + }, + { + "Date": "2021-11-15", + "Value": 79, + "Series": "Food" + }, + { + "Date": "2021-11-20", + "Value": 82, + "Series": "Food" + }, + { + "Date": "2021-11-26", + "Value": 82, + "Series": "Food" + }, + { + "Date": "2021-12-01", + "Value": 74, + "Series": "Food" + }, + { + "Date": "2021-12-07", + "Value": 63, + "Series": "Food" + }, + { + "Date": "2021-12-12", + "Value": 61, + "Series": "Food" + }, + { + "Date": "2021-12-18", + "Value": 68, + "Series": "Food" + }, + { + "Date": "2021-12-23", + "Value": 66, + "Series": "Food" + }, + { + "Date": "2021-12-29", + "Value": 58, + "Series": "Food" + }, + { + "Date": "2022-01-03", + "Value": 60, + "Series": "Food" + }, + { + "Date": "2022-01-09", + "Value": 65, + "Series": "Food" + }, + { + "Date": "2022-01-14", + "Value": 76, + "Series": "Food" + }, + { + "Date": "2022-01-20", + "Value": 77, + "Series": "Food" + }, + { + "Date": "2022-01-25", + "Value": 81, + "Series": "Food" + }, + { + "Date": "2022-01-31", + "Value": 75, + "Series": "Food" + }, + { + "Date": "2022-02-05", + "Value": 64, + "Series": "Food" + }, + { + "Date": "2022-02-10", + "Value": 49, + "Series": "Food" + }, + { + "Date": "2022-02-16", + "Value": 48, + "Series": "Food" + }, + { + "Date": "2022-02-21", + "Value": 53, + "Series": "Food" + }, + { + "Date": "2022-02-27", + "Value": 65, + "Series": "Food" + }, + { + "Date": "2022-03-04", + "Value": 81, + "Series": "Food" + }, + { + "Date": "2022-03-10", + "Value": 90, + "Series": "Food" + }, + { + "Date": "2022-03-15", + "Value": 88, + "Series": "Food" + }, + { + "Date": "2022-03-21", + "Value": 92, + "Series": "Food" + }, + { + "Date": "2022-03-26", + "Value": 101, + "Series": "Food" + }, + { + "Date": "2022-04-01", + "Value": 99, + "Series": "Food" + }, + { + "Date": "2022-04-06", + "Value": 102, + "Series": "Food" + }, + { + "Date": "2022-04-12", + "Value": 98, + "Series": "Food" + }, + { + "Date": "2022-04-17", + "Value": 99, + "Series": "Food" + }, + { + "Date": "2022-04-23", + "Value": 93, + "Series": "Food" + }, + { + "Date": "2022-04-28", + "Value": 89, + "Series": "Food" + }, + { + "Date": "2022-05-04", + "Value": 94, + "Series": "Food" + }, + { + "Date": "2022-05-09", + "Value": 99, + "Series": "Food" + }, + { + "Date": "2022-05-15", + "Value": 94, + "Series": "Food" + }, + { + "Date": "2022-05-20", + "Value": 90, + "Series": "Food" + }, + { + "Date": "2022-05-26", + "Value": 79, + "Series": "Food" + }, + { + "Date": "2022-05-31", + "Value": 62, + "Series": "Food" + }, + { + "Date": "2022-06-05", + "Value": 53, + "Series": "Food" + }, + { + "Date": "2022-06-11", + "Value": 54, + "Series": "Food" + }, + { + "Date": "2022-06-16", + "Value": 46, + "Series": "Food" + }, + { + "Date": "2022-06-22", + "Value": 40, + "Series": "Food" + }, + { + "Date": "2022-06-27", + "Value": 33, + "Series": "Food" + }, + { + "Date": "2022-07-03", + "Value": 25, + "Series": "Food" + }, + { + "Date": "2022-07-08", + "Value": 15, + "Series": "Food" + }, + { + "Date": "2022-07-14", + "Value": 13, + "Series": "Food" + }, + { + "Date": "2022-07-19", + "Value": 4, + "Series": "Food" + }, + { + "Date": "2022-07-25", + "Value": 0, + "Series": "Food" + }, + { + "Date": "2022-07-30", + "Value": 0, + "Series": "Food" + }, + { + "Date": "2022-08-05", + "Value": 0, + "Series": "Food" + }, + { + "Date": "2022-08-10", + "Value": 0, + "Series": "Food" + }, + { + "Date": "2022-08-16", + "Value": 0, + "Series": "Food" + }, + { + "Date": "2022-08-21", + "Value": 0, + "Series": "Food" + }, + { + "Date": "2022-08-27", + "Value": 2, + "Series": "Food" + }, + { + "Date": "2022-09-01", + "Value": 13, + "Series": "Food" + }, + { + "Date": "2022-09-07", + "Value": 15, + "Series": "Food" + }, + { + "Date": "2022-09-12", + "Value": 25, + "Series": "Food" + }, + { + "Date": "2022-09-17", + "Value": 23, + "Series": "Food" + }, + { + "Date": "2022-09-23", + "Value": 22, + "Series": "Food" + }, + { + "Date": "2022-09-28", + "Value": 19, + "Series": "Food" + }, + { + "Date": "2022-10-04", + "Value": 13, + "Series": "Food" + }, + { + "Date": "2022-10-09", + "Value": 13, + "Series": "Food" + }, + { + "Date": "2022-10-15", + "Value": 8, + "Series": "Food" + }, + { + "Date": "2022-10-20", + "Value": 11, + "Series": "Food" + }, + { + "Date": "2022-10-26", + "Value": 20, + "Series": "Food" + }, + { + "Date": "2022-10-31", + "Value": 34, + "Series": "Food" + }, + { + "Date": "2022-11-06", + "Value": 35, + "Series": "Food" + }, + { + "Date": "2022-11-11", + "Value": 37, + "Series": "Food" + }, + { + "Date": "2022-11-17", + "Value": 46, + "Series": "Food" + }, + { + "Date": "2022-11-22", + "Value": 50, + "Series": "Food" + }, + { + "Date": "2022-11-28", + "Value": 63, + "Series": "Food" + }, + { + "Date": "2022-12-03", + "Value": 73, + "Series": "Food" + }, + { + "Date": "2022-12-09", + "Value": 75, + "Series": "Food" + }, + { + "Date": "2022-12-14", + "Value": 86, + "Series": "Food" + }, + { + "Date": "2022-12-20", + "Value": 86, + "Series": "Food" + }, + { + "Date": "2022-12-25", + "Value": 89, + "Series": "Food" + }, + { + "Date": "2020-01-01", + "Value": 239, + "Series": "Books" + }, + { + "Date": "2020-01-06", + "Value": 245, + "Series": "Books" + }, + { + "Date": "2020-01-11", + "Value": 257, + "Series": "Books" + }, + { + "Date": "2020-01-17", + "Value": 257, + "Series": "Books" + }, + { + "Date": "2020-01-22", + "Value": 262, + "Series": "Books" + }, + { + "Date": "2020-01-28", + "Value": 272, + "Series": "Books" + }, + { + "Date": "2020-02-02", + "Value": 272, + "Series": "Books" + }, + { + "Date": "2020-02-08", + "Value": 278, + "Series": "Books" + }, + { + "Date": "2020-02-13", + "Value": 283, + "Series": "Books" + }, + { + "Date": "2020-02-19", + "Value": 282, + "Series": "Books" + }, + { + "Date": "2020-02-24", + "Value": 280, + "Series": "Books" + }, + { + "Date": "2020-03-01", + "Value": 281, + "Series": "Books" + }, + { + "Date": "2020-03-06", + "Value": 281, + "Series": "Books" + }, + { + "Date": "2020-03-12", + "Value": 285, + "Series": "Books" + }, + { + "Date": "2020-03-17", + "Value": 291, + "Series": "Books" + }, + { + "Date": "2020-03-23", + "Value": 298, + "Series": "Books" + }, + { + "Date": "2020-03-28", + "Value": 302, + "Series": "Books" + }, + { + "Date": "2020-04-03", + "Value": 304, + "Series": "Books" + }, + { + "Date": "2020-04-08", + "Value": 304, + "Series": "Books" + }, + { + "Date": "2020-04-14", + "Value": 305, + "Series": "Books" + }, + { + "Date": "2020-04-19", + "Value": 300, + "Series": "Books" + }, + { + "Date": "2020-04-24", + "Value": 294, + "Series": "Books" + }, + { + "Date": "2020-04-30", + "Value": 297, + "Series": "Books" + }, + { + "Date": "2020-05-05", + "Value": 300, + "Series": "Books" + }, + { + "Date": "2020-05-11", + "Value": 310, + "Series": "Books" + }, + { + "Date": "2020-05-16", + "Value": 316, + "Series": "Books" + }, + { + "Date": "2020-05-22", + "Value": 312, + "Series": "Books" + }, + { + "Date": "2020-05-27", + "Value": 312, + "Series": "Books" + }, + { + "Date": "2020-06-02", + "Value": 318, + "Series": "Books" + }, + { + "Date": "2020-06-07", + "Value": 327, + "Series": "Books" + }, + { + "Date": "2020-06-13", + "Value": 337, + "Series": "Books" + }, + { + "Date": "2020-06-18", + "Value": 352, + "Series": "Books" + }, + { + "Date": "2020-06-24", + "Value": 360, + "Series": "Books" + }, + { + "Date": "2020-06-29", + "Value": 363, + "Series": "Books" + }, + { + "Date": "2020-07-05", + "Value": 372, + "Series": "Books" + }, + { + "Date": "2020-07-10", + "Value": 381, + "Series": "Books" + }, + { + "Date": "2020-07-16", + "Value": 392, + "Series": "Books" + }, + { + "Date": "2020-07-21", + "Value": 407, + "Series": "Books" + }, + { + "Date": "2020-07-27", + "Value": 424, + "Series": "Books" + }, + { + "Date": "2020-08-01", + "Value": 432, + "Series": "Books" + }, + { + "Date": "2020-08-07", + "Value": 434, + "Series": "Books" + }, + { + "Date": "2020-08-12", + "Value": 443, + "Series": "Books" + }, + { + "Date": "2020-08-17", + "Value": 449, + "Series": "Books" + }, + { + "Date": "2020-08-23", + "Value": 461, + "Series": "Books" + }, + { + "Date": "2020-08-28", + "Value": 466, + "Series": "Books" + }, + { + "Date": "2020-09-03", + "Value": 473, + "Series": "Books" + }, + { + "Date": "2020-09-08", + "Value": 486, + "Series": "Books" + }, + { + "Date": "2020-09-14", + "Value": 489, + "Series": "Books" + }, + { + "Date": "2020-09-19", + "Value": 499, + "Series": "Books" + }, + { + "Date": "2020-09-25", + "Value": 513, + "Series": "Books" + }, + { + "Date": "2020-09-30", + "Value": 529, + "Series": "Books" + }, + { + "Date": "2020-10-06", + "Value": 545, + "Series": "Books" + }, + { + "Date": "2020-10-11", + "Value": 557, + "Series": "Books" + }, + { + "Date": "2020-10-17", + "Value": 561, + "Series": "Books" + }, + { + "Date": "2020-10-22", + "Value": 568, + "Series": "Books" + }, + { + "Date": "2020-10-28", + "Value": 567, + "Series": "Books" + }, + { + "Date": "2020-11-02", + "Value": 571, + "Series": "Books" + }, + { + "Date": "2020-11-08", + "Value": 575, + "Series": "Books" + }, + { + "Date": "2020-11-13", + "Value": 583, + "Series": "Books" + }, + { + "Date": "2020-11-19", + "Value": 595, + "Series": "Books" + }, + { + "Date": "2020-11-24", + "Value": 600, + "Series": "Books" + }, + { + "Date": "2020-11-29", + "Value": 595, + "Series": "Books" + }, + { + "Date": "2020-12-05", + "Value": 595, + "Series": "Books" + }, + { + "Date": "2020-12-10", + "Value": 595, + "Series": "Books" + }, + { + "Date": "2020-12-16", + "Value": 594, + "Series": "Books" + }, + { + "Date": "2020-12-21", + "Value": 593, + "Series": "Books" + }, + { + "Date": "2020-12-27", + "Value": 598, + "Series": "Books" + }, + { + "Date": "2021-01-01", + "Value": 599, + "Series": "Books" + }, + { + "Date": "2021-01-07", + "Value": 595, + "Series": "Books" + }, + { + "Date": "2021-01-12", + "Value": 598, + "Series": "Books" + }, + { + "Date": "2021-01-18", + "Value": 594, + "Series": "Books" + }, + { + "Date": "2021-01-23", + "Value": 585, + "Series": "Books" + }, + { + "Date": "2021-01-29", + "Value": 576, + "Series": "Books" + }, + { + "Date": "2021-02-03", + "Value": 565, + "Series": "Books" + }, + { + "Date": "2021-02-09", + "Value": 556, + "Series": "Books" + }, + { + "Date": "2021-02-14", + "Value": 553, + "Series": "Books" + }, + { + "Date": "2021-02-20", + "Value": 546, + "Series": "Books" + }, + { + "Date": "2021-02-25", + "Value": 545, + "Series": "Books" + }, + { + "Date": "2021-03-03", + "Value": 541, + "Series": "Books" + }, + { + "Date": "2021-03-08", + "Value": 540, + "Series": "Books" + }, + { + "Date": "2021-03-14", + "Value": 544, + "Series": "Books" + }, + { + "Date": "2021-03-19", + "Value": 554, + "Series": "Books" + }, + { + "Date": "2021-03-24", + "Value": 554, + "Series": "Books" + }, + { + "Date": "2021-03-30", + "Value": 550, + "Series": "Books" + }, + { + "Date": "2021-04-04", + "Value": 540, + "Series": "Books" + }, + { + "Date": "2021-04-10", + "Value": 538, + "Series": "Books" + }, + { + "Date": "2021-04-15", + "Value": 537, + "Series": "Books" + }, + { + "Date": "2021-04-21", + "Value": 541, + "Series": "Books" + }, + { + "Date": "2021-04-26", + "Value": 541, + "Series": "Books" + }, + { + "Date": "2021-05-02", + "Value": 538, + "Series": "Books" + }, + { + "Date": "2021-05-07", + "Value": 535, + "Series": "Books" + }, + { + "Date": "2021-05-13", + "Value": 536, + "Series": "Books" + }, + { + "Date": "2021-05-18", + "Value": 539, + "Series": "Books" + }, + { + "Date": "2021-05-24", + "Value": 546, + "Series": "Books" + }, + { + "Date": "2021-05-29", + "Value": 558, + "Series": "Books" + }, + { + "Date": "2021-06-04", + "Value": 562, + "Series": "Books" + }, + { + "Date": "2021-06-09", + "Value": 568, + "Series": "Books" + }, + { + "Date": "2021-06-15", + "Value": 580, + "Series": "Books" + }, + { + "Date": "2021-06-20", + "Value": 587, + "Series": "Books" + }, + { + "Date": "2021-06-26", + "Value": 594, + "Series": "Books" + }, + { + "Date": "2021-07-01", + "Value": 607, + "Series": "Books" + }, + { + "Date": "2021-07-06", + "Value": 622, + "Series": "Books" + }, + { + "Date": "2021-07-12", + "Value": 632, + "Series": "Books" + }, + { + "Date": "2021-07-17", + "Value": 635, + "Series": "Books" + }, + { + "Date": "2021-07-23", + "Value": 635, + "Series": "Books" + }, + { + "Date": "2021-07-28", + "Value": 634, + "Series": "Books" + }, + { + "Date": "2021-08-03", + "Value": 633, + "Series": "Books" + }, + { + "Date": "2021-08-08", + "Value": 638, + "Series": "Books" + }, + { + "Date": "2021-08-14", + "Value": 635, + "Series": "Books" + }, + { + "Date": "2021-08-19", + "Value": 633, + "Series": "Books" + }, + { + "Date": "2021-08-25", + "Value": 631, + "Series": "Books" + }, + { + "Date": "2021-08-30", + "Value": 622, + "Series": "Books" + }, + { + "Date": "2021-09-05", + "Value": 611, + "Series": "Books" + }, + { + "Date": "2021-09-10", + "Value": 609, + "Series": "Books" + }, + { + "Date": "2021-09-16", + "Value": 603, + "Series": "Books" + }, + { + "Date": "2021-09-21", + "Value": 592, + "Series": "Books" + }, + { + "Date": "2021-09-27", + "Value": 589, + "Series": "Books" + }, + { + "Date": "2021-10-02", + "Value": 589, + "Series": "Books" + }, + { + "Date": "2021-10-08", + "Value": 581, + "Series": "Books" + }, + { + "Date": "2021-10-13", + "Value": 570, + "Series": "Books" + }, + { + "Date": "2021-10-19", + "Value": 555, + "Series": "Books" + }, + { + "Date": "2021-10-24", + "Value": 546, + "Series": "Books" + }, + { + "Date": "2021-10-29", + "Value": 543, + "Series": "Books" + }, + { + "Date": "2021-11-04", + "Value": 536, + "Series": "Books" + }, + { + "Date": "2021-11-09", + "Value": 537, + "Series": "Books" + }, + { + "Date": "2021-11-15", + "Value": 532, + "Series": "Books" + }, + { + "Date": "2021-11-20", + "Value": 534, + "Series": "Books" + }, + { + "Date": "2021-11-26", + "Value": 528, + "Series": "Books" + }, + { + "Date": "2021-12-01", + "Value": 531, + "Series": "Books" + }, + { + "Date": "2021-12-07", + "Value": 528, + "Series": "Books" + }, + { + "Date": "2021-12-12", + "Value": 518, + "Series": "Books" + }, + { + "Date": "2021-12-18", + "Value": 519, + "Series": "Books" + }, + { + "Date": "2021-12-23", + "Value": 522, + "Series": "Books" + }, + { + "Date": "2021-12-29", + "Value": 523, + "Series": "Books" + }, + { + "Date": "2022-01-03", + "Value": 519, + "Series": "Books" + }, + { + "Date": "2022-01-09", + "Value": 517, + "Series": "Books" + }, + { + "Date": "2022-01-14", + "Value": 522, + "Series": "Books" + }, + { + "Date": "2022-01-20", + "Value": 520, + "Series": "Books" + }, + { + "Date": "2022-01-25", + "Value": 520, + "Series": "Books" + }, + { + "Date": "2022-01-31", + "Value": 515, + "Series": "Books" + }, + { + "Date": "2022-02-05", + "Value": 512, + "Series": "Books" + }, + { + "Date": "2022-02-10", + "Value": 517, + "Series": "Books" + }, + { + "Date": "2022-02-16", + "Value": 519, + "Series": "Books" + }, + { + "Date": "2022-02-21", + "Value": 513, + "Series": "Books" + }, + { + "Date": "2022-02-27", + "Value": 514, + "Series": "Books" + }, + { + "Date": "2022-03-04", + "Value": 509, + "Series": "Books" + }, + { + "Date": "2022-03-10", + "Value": 503, + "Series": "Books" + }, + { + "Date": "2022-03-15", + "Value": 498, + "Series": "Books" + }, + { + "Date": "2022-03-21", + "Value": 496, + "Series": "Books" + }, + { + "Date": "2022-03-26", + "Value": 489, + "Series": "Books" + }, + { + "Date": "2022-04-01", + "Value": 484, + "Series": "Books" + }, + { + "Date": "2022-04-06", + "Value": 475, + "Series": "Books" + }, + { + "Date": "2022-04-12", + "Value": 474, + "Series": "Books" + }, + { + "Date": "2022-04-17", + "Value": 476, + "Series": "Books" + }, + { + "Date": "2022-04-23", + "Value": 471, + "Series": "Books" + }, + { + "Date": "2022-04-28", + "Value": 461, + "Series": "Books" + }, + { + "Date": "2022-05-04", + "Value": 454, + "Series": "Books" + }, + { + "Date": "2022-05-09", + "Value": 442, + "Series": "Books" + }, + { + "Date": "2022-05-15", + "Value": 438, + "Series": "Books" + }, + { + "Date": "2022-05-20", + "Value": 441, + "Series": "Books" + }, + { + "Date": "2022-05-26", + "Value": 438, + "Series": "Books" + }, + { + "Date": "2022-05-31", + "Value": 443, + "Series": "Books" + }, + { + "Date": "2022-06-05", + "Value": 453, + "Series": "Books" + }, + { + "Date": "2022-06-11", + "Value": 460, + "Series": "Books" + }, + { + "Date": "2022-06-16", + "Value": 472, + "Series": "Books" + }, + { + "Date": "2022-06-22", + "Value": 488, + "Series": "Books" + }, + { + "Date": "2022-06-27", + "Value": 505, + "Series": "Books" + }, + { + "Date": "2022-07-03", + "Value": 510, + "Series": "Books" + }, + { + "Date": "2022-07-08", + "Value": 512, + "Series": "Books" + }, + { + "Date": "2022-07-14", + "Value": 512, + "Series": "Books" + }, + { + "Date": "2022-07-19", + "Value": 510, + "Series": "Books" + }, + { + "Date": "2022-07-25", + "Value": 514, + "Series": "Books" + }, + { + "Date": "2022-07-30", + "Value": 515, + "Series": "Books" + }, + { + "Date": "2022-08-05", + "Value": 511, + "Series": "Books" + }, + { + "Date": "2022-08-10", + "Value": 514, + "Series": "Books" + }, + { + "Date": "2022-08-16", + "Value": 519, + "Series": "Books" + }, + { + "Date": "2022-08-21", + "Value": 515, + "Series": "Books" + }, + { + "Date": "2022-08-27", + "Value": 508, + "Series": "Books" + }, + { + "Date": "2022-09-01", + "Value": 509, + "Series": "Books" + }, + { + "Date": "2022-09-07", + "Value": 502, + "Series": "Books" + }, + { + "Date": "2022-09-12", + "Value": 493, + "Series": "Books" + }, + { + "Date": "2022-09-17", + "Value": 490, + "Series": "Books" + }, + { + "Date": "2022-09-23", + "Value": 495, + "Series": "Books" + }, + { + "Date": "2022-09-28", + "Value": 504, + "Series": "Books" + }, + { + "Date": "2022-10-04", + "Value": 508, + "Series": "Books" + }, + { + "Date": "2022-10-09", + "Value": 510, + "Series": "Books" + }, + { + "Date": "2022-10-15", + "Value": 514, + "Series": "Books" + }, + { + "Date": "2022-10-20", + "Value": 512, + "Series": "Books" + }, + { + "Date": "2022-10-26", + "Value": 515, + "Series": "Books" + }, + { + "Date": "2022-10-31", + "Value": 514, + "Series": "Books" + }, + { + "Date": "2022-11-06", + "Value": 508, + "Series": "Books" + }, + { + "Date": "2022-11-11", + "Value": 507, + "Series": "Books" + }, + { + "Date": "2022-11-17", + "Value": 503, + "Series": "Books" + }, + { + "Date": "2022-11-22", + "Value": 494, + "Series": "Books" + }, + { + "Date": "2022-11-28", + "Value": 484, + "Series": "Books" + }, + { + "Date": "2022-12-03", + "Value": 485, + "Series": "Books" + }, + { + "Date": "2022-12-09", + "Value": 488, + "Series": "Books" + }, + { + "Date": "2022-12-14", + "Value": 484, + "Series": "Books" + }, + { + "Date": "2022-12-20", + "Value": 479, + "Series": "Books" + }, + { + "Date": "2022-12-25", + "Value": 483, + "Series": "Books" + }, + { + "Date": "2020-01-01", + "Value": 184, + "Series": "Sports" + }, + { + "Date": "2020-01-06", + "Value": 189, + "Series": "Sports" + }, + { + "Date": "2020-01-11", + "Value": 189, + "Series": "Sports" + }, + { + "Date": "2020-01-17", + "Value": 190, + "Series": "Sports" + }, + { + "Date": "2020-01-22", + "Value": 186, + "Series": "Sports" + }, + { + "Date": "2020-01-28", + "Value": 180, + "Series": "Sports" + }, + { + "Date": "2020-02-02", + "Value": 170, + "Series": "Sports" + }, + { + "Date": "2020-02-08", + "Value": 159, + "Series": "Sports" + }, + { + "Date": "2020-02-13", + "Value": 158, + "Series": "Sports" + }, + { + "Date": "2020-02-19", + "Value": 153, + "Series": "Sports" + }, + { + "Date": "2020-02-24", + "Value": 148, + "Series": "Sports" + }, + { + "Date": "2020-03-01", + "Value": 149, + "Series": "Sports" + }, + { + "Date": "2020-03-06", + "Value": 144, + "Series": "Sports" + }, + { + "Date": "2020-03-12", + "Value": 145, + "Series": "Sports" + }, + { + "Date": "2020-03-17", + "Value": 146, + "Series": "Sports" + }, + { + "Date": "2020-03-23", + "Value": 145, + "Series": "Sports" + }, + { + "Date": "2020-03-28", + "Value": 140, + "Series": "Sports" + }, + { + "Date": "2020-04-03", + "Value": 131, + "Series": "Sports" + }, + { + "Date": "2020-04-08", + "Value": 131, + "Series": "Sports" + }, + { + "Date": "2020-04-14", + "Value": 131, + "Series": "Sports" + }, + { + "Date": "2020-04-19", + "Value": 137, + "Series": "Sports" + }, + { + "Date": "2020-04-24", + "Value": 138, + "Series": "Sports" + }, + { + "Date": "2020-04-30", + "Value": 136, + "Series": "Sports" + }, + { + "Date": "2020-05-05", + "Value": 131, + "Series": "Sports" + }, + { + "Date": "2020-05-11", + "Value": 122, + "Series": "Sports" + }, + { + "Date": "2020-05-16", + "Value": 114, + "Series": "Sports" + }, + { + "Date": "2020-05-22", + "Value": 105, + "Series": "Sports" + }, + { + "Date": "2020-05-27", + "Value": 94, + "Series": "Sports" + }, + { + "Date": "2020-06-02", + "Value": 87, + "Series": "Sports" + }, + { + "Date": "2020-06-07", + "Value": 82, + "Series": "Sports" + }, + { + "Date": "2020-06-13", + "Value": 75, + "Series": "Sports" + }, + { + "Date": "2020-06-18", + "Value": 64, + "Series": "Sports" + }, + { + "Date": "2020-06-24", + "Value": 56, + "Series": "Sports" + }, + { + "Date": "2020-06-29", + "Value": 57, + "Series": "Sports" + }, + { + "Date": "2020-07-05", + "Value": 52, + "Series": "Sports" + }, + { + "Date": "2020-07-10", + "Value": 43, + "Series": "Sports" + }, + { + "Date": "2020-07-16", + "Value": 38, + "Series": "Sports" + }, + { + "Date": "2020-07-21", + "Value": 28, + "Series": "Sports" + }, + { + "Date": "2020-07-27", + "Value": 21, + "Series": "Sports" + }, + { + "Date": "2020-08-01", + "Value": 16, + "Series": "Sports" + }, + { + "Date": "2020-08-07", + "Value": 12, + "Series": "Sports" + }, + { + "Date": "2020-08-12", + "Value": 9, + "Series": "Sports" + }, + { + "Date": "2020-08-17", + "Value": 4, + "Series": "Sports" + }, + { + "Date": "2020-08-23", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2020-08-28", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2020-09-03", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2020-09-08", + "Value": 7, + "Series": "Sports" + }, + { + "Date": "2020-09-14", + "Value": 6, + "Series": "Sports" + }, + { + "Date": "2020-09-19", + "Value": 11, + "Series": "Sports" + }, + { + "Date": "2020-09-25", + "Value": 14, + "Series": "Sports" + }, + { + "Date": "2020-09-30", + "Value": 13, + "Series": "Sports" + }, + { + "Date": "2020-10-06", + "Value": 14, + "Series": "Sports" + }, + { + "Date": "2020-10-11", + "Value": 12, + "Series": "Sports" + }, + { + "Date": "2020-10-17", + "Value": 7, + "Series": "Sports" + }, + { + "Date": "2020-10-22", + "Value": 5, + "Series": "Sports" + }, + { + "Date": "2020-10-28", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2020-11-02", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2020-11-08", + "Value": 4, + "Series": "Sports" + }, + { + "Date": "2020-11-13", + "Value": 1, + "Series": "Sports" + }, + { + "Date": "2020-11-19", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2020-11-24", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2020-11-29", + "Value": 4, + "Series": "Sports" + }, + { + "Date": "2020-12-05", + "Value": 4, + "Series": "Sports" + }, + { + "Date": "2020-12-10", + "Value": 1, + "Series": "Sports" + }, + { + "Date": "2020-12-16", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2020-12-21", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2020-12-27", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-01-01", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-01-07", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-01-12", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-01-18", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-01-23", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-01-29", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-02-03", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-02-09", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-02-14", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-02-20", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-02-25", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-03-03", + "Value": 1, + "Series": "Sports" + }, + { + "Date": "2021-03-08", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-03-14", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-03-19", + "Value": 1, + "Series": "Sports" + }, + { + "Date": "2021-03-24", + "Value": 7, + "Series": "Sports" + }, + { + "Date": "2021-03-30", + "Value": 9, + "Series": "Sports" + }, + { + "Date": "2021-04-04", + "Value": 7, + "Series": "Sports" + }, + { + "Date": "2021-04-10", + "Value": 5, + "Series": "Sports" + }, + { + "Date": "2021-04-15", + "Value": 6, + "Series": "Sports" + }, + { + "Date": "2021-04-21", + "Value": 7, + "Series": "Sports" + }, + { + "Date": "2021-04-26", + "Value": 13, + "Series": "Sports" + }, + { + "Date": "2021-05-02", + "Value": 12, + "Series": "Sports" + }, + { + "Date": "2021-05-07", + "Value": 11, + "Series": "Sports" + }, + { + "Date": "2021-05-13", + "Value": 14, + "Series": "Sports" + }, + { + "Date": "2021-05-18", + "Value": 14, + "Series": "Sports" + }, + { + "Date": "2021-05-24", + "Value": 12, + "Series": "Sports" + }, + { + "Date": "2021-05-29", + "Value": 12, + "Series": "Sports" + }, + { + "Date": "2021-06-04", + "Value": 19, + "Series": "Sports" + }, + { + "Date": "2021-06-09", + "Value": 27, + "Series": "Sports" + }, + { + "Date": "2021-06-15", + "Value": 29, + "Series": "Sports" + }, + { + "Date": "2021-06-20", + "Value": 24, + "Series": "Sports" + }, + { + "Date": "2021-06-26", + "Value": 15, + "Series": "Sports" + }, + { + "Date": "2021-07-01", + "Value": 2, + "Series": "Sports" + }, + { + "Date": "2021-07-06", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-07-12", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-07-17", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-07-23", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-07-28", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-08-03", + "Value": 1, + "Series": "Sports" + }, + { + "Date": "2021-08-08", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-08-14", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-08-19", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-08-25", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-08-30", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-09-05", + "Value": 1, + "Series": "Sports" + }, + { + "Date": "2021-09-10", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-09-16", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-09-21", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-09-27", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-10-02", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-10-08", + "Value": 4, + "Series": "Sports" + }, + { + "Date": "2021-10-13", + "Value": 5, + "Series": "Sports" + }, + { + "Date": "2021-10-19", + "Value": 8, + "Series": "Sports" + }, + { + "Date": "2021-10-24", + "Value": 13, + "Series": "Sports" + }, + { + "Date": "2021-10-29", + "Value": 15, + "Series": "Sports" + }, + { + "Date": "2021-11-04", + "Value": 13, + "Series": "Sports" + }, + { + "Date": "2021-11-09", + "Value": 5, + "Series": "Sports" + }, + { + "Date": "2021-11-15", + "Value": 1, + "Series": "Sports" + }, + { + "Date": "2021-11-20", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-11-26", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-12-01", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-12-07", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-12-12", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-12-18", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-12-23", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2021-12-29", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2022-01-03", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2022-01-09", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2022-01-14", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2022-01-20", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2022-01-25", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2022-01-31", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2022-02-05", + "Value": 3, + "Series": "Sports" + }, + { + "Date": "2022-02-10", + "Value": 10, + "Series": "Sports" + }, + { + "Date": "2022-02-16", + "Value": 11, + "Series": "Sports" + }, + { + "Date": "2022-02-21", + "Value": 8, + "Series": "Sports" + }, + { + "Date": "2022-02-27", + "Value": 13, + "Series": "Sports" + }, + { + "Date": "2022-03-04", + "Value": 10, + "Series": "Sports" + }, + { + "Date": "2022-03-10", + "Value": 14, + "Series": "Sports" + }, + { + "Date": "2022-03-15", + "Value": 17, + "Series": "Sports" + }, + { + "Date": "2022-03-21", + "Value": 20, + "Series": "Sports" + }, + { + "Date": "2022-03-26", + "Value": 18, + "Series": "Sports" + }, + { + "Date": "2022-04-01", + "Value": 10, + "Series": "Sports" + }, + { + "Date": "2022-04-06", + "Value": 11, + "Series": "Sports" + }, + { + "Date": "2022-04-12", + "Value": 7, + "Series": "Sports" + }, + { + "Date": "2022-04-17", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2022-04-23", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2022-04-28", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2022-05-04", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2022-05-09", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2022-05-15", + "Value": 2, + "Series": "Sports" + }, + { + "Date": "2022-05-20", + "Value": 1, + "Series": "Sports" + }, + { + "Date": "2022-05-26", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2022-05-31", + "Value": 1, + "Series": "Sports" + }, + { + "Date": "2022-06-05", + "Value": 8, + "Series": "Sports" + }, + { + "Date": "2022-06-11", + "Value": 15, + "Series": "Sports" + }, + { + "Date": "2022-06-16", + "Value": 21, + "Series": "Sports" + }, + { + "Date": "2022-06-22", + "Value": 22, + "Series": "Sports" + }, + { + "Date": "2022-06-27", + "Value": 28, + "Series": "Sports" + }, + { + "Date": "2022-07-03", + "Value": 31, + "Series": "Sports" + }, + { + "Date": "2022-07-08", + "Value": 34, + "Series": "Sports" + }, + { + "Date": "2022-07-14", + "Value": 34, + "Series": "Sports" + }, + { + "Date": "2022-07-19", + "Value": 36, + "Series": "Sports" + }, + { + "Date": "2022-07-25", + "Value": 32, + "Series": "Sports" + }, + { + "Date": "2022-07-30", + "Value": 32, + "Series": "Sports" + }, + { + "Date": "2022-08-05", + "Value": 32, + "Series": "Sports" + }, + { + "Date": "2022-08-10", + "Value": 30, + "Series": "Sports" + }, + { + "Date": "2022-08-16", + "Value": 26, + "Series": "Sports" + }, + { + "Date": "2022-08-21", + "Value": 28, + "Series": "Sports" + }, + { + "Date": "2022-08-27", + "Value": 24, + "Series": "Sports" + }, + { + "Date": "2022-09-01", + "Value": 17, + "Series": "Sports" + }, + { + "Date": "2022-09-07", + "Value": 11, + "Series": "Sports" + }, + { + "Date": "2022-09-12", + "Value": 9, + "Series": "Sports" + }, + { + "Date": "2022-09-17", + "Value": 2, + "Series": "Sports" + }, + { + "Date": "2022-09-23", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2022-09-28", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2022-10-04", + "Value": 1, + "Series": "Sports" + }, + { + "Date": "2022-10-09", + "Value": 7, + "Series": "Sports" + }, + { + "Date": "2022-10-15", + "Value": 18, + "Series": "Sports" + }, + { + "Date": "2022-10-20", + "Value": 20, + "Series": "Sports" + }, + { + "Date": "2022-10-26", + "Value": 16, + "Series": "Sports" + }, + { + "Date": "2022-10-31", + "Value": 12, + "Series": "Sports" + }, + { + "Date": "2022-11-06", + "Value": 6, + "Series": "Sports" + }, + { + "Date": "2022-11-11", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2022-11-17", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2022-11-22", + "Value": 1, + "Series": "Sports" + }, + { + "Date": "2022-11-28", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2022-12-03", + "Value": 0, + "Series": "Sports" + }, + { + "Date": "2022-12-09", + "Value": 4, + "Series": "Sports" + }, + { + "Date": "2022-12-14", + "Value": 6, + "Series": "Sports" + }, + { + "Date": "2022-12-20", + "Value": 14, + "Series": "Sports" + }, + { + "Date": "2022-12-25", + "Value": 20, + "Series": "Sports" + }, + { + "Date": "2020-01-01", + "Value": 244, + "Series": "Home" + }, + { + "Date": "2020-01-06", + "Value": 249, + "Series": "Home" + }, + { + "Date": "2020-01-11", + "Value": 237, + "Series": "Home" + }, + { + "Date": "2020-01-17", + "Value": 226, + "Series": "Home" + }, + { + "Date": "2020-01-22", + "Value": 209, + "Series": "Home" + }, + { + "Date": "2020-01-28", + "Value": 182, + "Series": "Home" + }, + { + "Date": "2020-02-02", + "Value": 148, + "Series": "Home" + }, + { + "Date": "2020-02-08", + "Value": 115, + "Series": "Home" + }, + { + "Date": "2020-02-13", + "Value": 95, + "Series": "Home" + }, + { + "Date": "2020-02-19", + "Value": 75, + "Series": "Home" + }, + { + "Date": "2020-02-24", + "Value": 45, + "Series": "Home" + }, + { + "Date": "2020-03-01", + "Value": 27, + "Series": "Home" + }, + { + "Date": "2020-03-06", + "Value": 26, + "Series": "Home" + }, + { + "Date": "2020-03-12", + "Value": 37, + "Series": "Home" + }, + { + "Date": "2020-03-17", + "Value": 42, + "Series": "Home" + }, + { + "Date": "2020-03-23", + "Value": 59, + "Series": "Home" + }, + { + "Date": "2020-03-28", + "Value": 73, + "Series": "Home" + }, + { + "Date": "2020-04-03", + "Value": 94, + "Series": "Home" + }, + { + "Date": "2020-04-08", + "Value": 103, + "Series": "Home" + }, + { + "Date": "2020-04-14", + "Value": 116, + "Series": "Home" + }, + { + "Date": "2020-04-19", + "Value": 118, + "Series": "Home" + }, + { + "Date": "2020-04-24", + "Value": 136, + "Series": "Home" + }, + { + "Date": "2020-04-30", + "Value": 139, + "Series": "Home" + }, + { + "Date": "2020-05-05", + "Value": 137, + "Series": "Home" + }, + { + "Date": "2020-05-11", + "Value": 127, + "Series": "Home" + }, + { + "Date": "2020-05-16", + "Value": 115, + "Series": "Home" + }, + { + "Date": "2020-05-22", + "Value": 121, + "Series": "Home" + }, + { + "Date": "2020-05-27", + "Value": 125, + "Series": "Home" + }, + { + "Date": "2020-06-02", + "Value": 122, + "Series": "Home" + }, + { + "Date": "2020-06-07", + "Value": 122, + "Series": "Home" + }, + { + "Date": "2020-06-13", + "Value": 130, + "Series": "Home" + }, + { + "Date": "2020-06-18", + "Value": 126, + "Series": "Home" + }, + { + "Date": "2020-06-24", + "Value": 134, + "Series": "Home" + }, + { + "Date": "2020-06-29", + "Value": 138, + "Series": "Home" + }, + { + "Date": "2020-07-05", + "Value": 127, + "Series": "Home" + }, + { + "Date": "2020-07-10", + "Value": 111, + "Series": "Home" + }, + { + "Date": "2020-07-16", + "Value": 102, + "Series": "Home" + }, + { + "Date": "2020-07-21", + "Value": 92, + "Series": "Home" + }, + { + "Date": "2020-07-27", + "Value": 74, + "Series": "Home" + }, + { + "Date": "2020-08-01", + "Value": 75, + "Series": "Home" + }, + { + "Date": "2020-08-07", + "Value": 69, + "Series": "Home" + }, + { + "Date": "2020-08-12", + "Value": 51, + "Series": "Home" + }, + { + "Date": "2020-08-17", + "Value": 43, + "Series": "Home" + }, + { + "Date": "2020-08-23", + "Value": 28, + "Series": "Home" + }, + { + "Date": "2020-08-28", + "Value": 17, + "Series": "Home" + }, + { + "Date": "2020-09-03", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2020-09-08", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2020-09-14", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2020-09-19", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2020-09-25", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2020-09-30", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2020-10-06", + "Value": 4, + "Series": "Home" + }, + { + "Date": "2020-10-11", + "Value": 4, + "Series": "Home" + }, + { + "Date": "2020-10-17", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2020-10-22", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2020-10-28", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2020-11-02", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2020-11-08", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2020-11-13", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2020-11-19", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2020-11-24", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2020-11-29", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2020-12-05", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2020-12-10", + "Value": 5, + "Series": "Home" + }, + { + "Date": "2020-12-16", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2020-12-21", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2020-12-27", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2021-01-01", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2021-01-07", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2021-01-12", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2021-01-18", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2021-01-23", + "Value": 1, + "Series": "Home" + }, + { + "Date": "2021-01-29", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2021-02-03", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2021-02-09", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2021-02-14", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2021-02-20", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2021-02-25", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2021-03-03", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2021-03-08", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2021-03-14", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2021-03-19", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2021-03-24", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2021-03-30", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2021-04-04", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2021-04-10", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2021-04-15", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2021-04-21", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2021-04-26", + "Value": 2, + "Series": "Home" + }, + { + "Date": "2021-05-02", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2021-05-07", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2021-05-13", + "Value": 7, + "Series": "Home" + }, + { + "Date": "2021-05-18", + "Value": 24, + "Series": "Home" + }, + { + "Date": "2021-05-24", + "Value": 37, + "Series": "Home" + }, + { + "Date": "2021-05-29", + "Value": 53, + "Series": "Home" + }, + { + "Date": "2021-06-04", + "Value": 79, + "Series": "Home" + }, + { + "Date": "2021-06-09", + "Value": 96, + "Series": "Home" + }, + { + "Date": "2021-06-15", + "Value": 113, + "Series": "Home" + }, + { + "Date": "2021-06-20", + "Value": 117, + "Series": "Home" + }, + { + "Date": "2021-06-26", + "Value": 106, + "Series": "Home" + }, + { + "Date": "2021-07-01", + "Value": 104, + "Series": "Home" + }, + { + "Date": "2021-07-06", + "Value": 105, + "Series": "Home" + }, + { + "Date": "2021-07-12", + "Value": 120, + "Series": "Home" + }, + { + "Date": "2021-07-17", + "Value": 121, + "Series": "Home" + }, + { + "Date": "2021-07-23", + "Value": 111, + "Series": "Home" + }, + { + "Date": "2021-07-28", + "Value": 94, + "Series": "Home" + }, + { + "Date": "2021-08-03", + "Value": 74, + "Series": "Home" + }, + { + "Date": "2021-08-08", + "Value": 72, + "Series": "Home" + }, + { + "Date": "2021-08-14", + "Value": 78, + "Series": "Home" + }, + { + "Date": "2021-08-19", + "Value": 89, + "Series": "Home" + }, + { + "Date": "2021-08-25", + "Value": 108, + "Series": "Home" + }, + { + "Date": "2021-08-30", + "Value": 124, + "Series": "Home" + }, + { + "Date": "2021-09-05", + "Value": 123, + "Series": "Home" + }, + { + "Date": "2021-09-10", + "Value": 137, + "Series": "Home" + }, + { + "Date": "2021-09-16", + "Value": 156, + "Series": "Home" + }, + { + "Date": "2021-09-21", + "Value": 161, + "Series": "Home" + }, + { + "Date": "2021-09-27", + "Value": 162, + "Series": "Home" + }, + { + "Date": "2021-10-02", + "Value": 167, + "Series": "Home" + }, + { + "Date": "2021-10-08", + "Value": 164, + "Series": "Home" + }, + { + "Date": "2021-10-13", + "Value": 160, + "Series": "Home" + }, + { + "Date": "2021-10-19", + "Value": 170, + "Series": "Home" + }, + { + "Date": "2021-10-24", + "Value": 189, + "Series": "Home" + }, + { + "Date": "2021-10-29", + "Value": 192, + "Series": "Home" + }, + { + "Date": "2021-11-04", + "Value": 180, + "Series": "Home" + }, + { + "Date": "2021-11-09", + "Value": 172, + "Series": "Home" + }, + { + "Date": "2021-11-15", + "Value": 176, + "Series": "Home" + }, + { + "Date": "2021-11-20", + "Value": 186, + "Series": "Home" + }, + { + "Date": "2021-11-26", + "Value": 196, + "Series": "Home" + }, + { + "Date": "2021-12-01", + "Value": 208, + "Series": "Home" + }, + { + "Date": "2021-12-07", + "Value": 229, + "Series": "Home" + }, + { + "Date": "2021-12-12", + "Value": 248, + "Series": "Home" + }, + { + "Date": "2021-12-18", + "Value": 246, + "Series": "Home" + }, + { + "Date": "2021-12-23", + "Value": 235, + "Series": "Home" + }, + { + "Date": "2021-12-29", + "Value": 232, + "Series": "Home" + }, + { + "Date": "2022-01-03", + "Value": 216, + "Series": "Home" + }, + { + "Date": "2022-01-09", + "Value": 188, + "Series": "Home" + }, + { + "Date": "2022-01-14", + "Value": 161, + "Series": "Home" + }, + { + "Date": "2022-01-20", + "Value": 150, + "Series": "Home" + }, + { + "Date": "2022-01-25", + "Value": 137, + "Series": "Home" + }, + { + "Date": "2022-01-31", + "Value": 113, + "Series": "Home" + }, + { + "Date": "2022-02-05", + "Value": 104, + "Series": "Home" + }, + { + "Date": "2022-02-10", + "Value": 84, + "Series": "Home" + }, + { + "Date": "2022-02-16", + "Value": 78, + "Series": "Home" + }, + { + "Date": "2022-02-21", + "Value": 83, + "Series": "Home" + }, + { + "Date": "2022-02-27", + "Value": 93, + "Series": "Home" + }, + { + "Date": "2022-03-04", + "Value": 97, + "Series": "Home" + }, + { + "Date": "2022-03-10", + "Value": 93, + "Series": "Home" + }, + { + "Date": "2022-03-15", + "Value": 77, + "Series": "Home" + }, + { + "Date": "2022-03-21", + "Value": 69, + "Series": "Home" + }, + { + "Date": "2022-03-26", + "Value": 56, + "Series": "Home" + }, + { + "Date": "2022-04-01", + "Value": 38, + "Series": "Home" + }, + { + "Date": "2022-04-06", + "Value": 39, + "Series": "Home" + }, + { + "Date": "2022-04-12", + "Value": 43, + "Series": "Home" + }, + { + "Date": "2022-04-17", + "Value": 37, + "Series": "Home" + }, + { + "Date": "2022-04-23", + "Value": 26, + "Series": "Home" + }, + { + "Date": "2022-04-28", + "Value": 15, + "Series": "Home" + }, + { + "Date": "2022-05-04", + "Value": 10, + "Series": "Home" + }, + { + "Date": "2022-05-09", + "Value": 21, + "Series": "Home" + }, + { + "Date": "2022-05-15", + "Value": 15, + "Series": "Home" + }, + { + "Date": "2022-05-20", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2022-05-26", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2022-05-31", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2022-06-05", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2022-06-11", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2022-06-16", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2022-06-22", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2022-06-27", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2022-07-03", + "Value": 6, + "Series": "Home" + }, + { + "Date": "2022-07-08", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2022-07-14", + "Value": 11, + "Series": "Home" + }, + { + "Date": "2022-07-19", + "Value": 25, + "Series": "Home" + }, + { + "Date": "2022-07-25", + "Value": 33, + "Series": "Home" + }, + { + "Date": "2022-07-30", + "Value": 24, + "Series": "Home" + }, + { + "Date": "2022-08-05", + "Value": 9, + "Series": "Home" + }, + { + "Date": "2022-08-10", + "Value": 14, + "Series": "Home" + }, + { + "Date": "2022-08-16", + "Value": 14, + "Series": "Home" + }, + { + "Date": "2022-08-21", + "Value": 28, + "Series": "Home" + }, + { + "Date": "2022-08-27", + "Value": 31, + "Series": "Home" + }, + { + "Date": "2022-09-01", + "Value": 30, + "Series": "Home" + }, + { + "Date": "2022-09-07", + "Value": 15, + "Series": "Home" + }, + { + "Date": "2022-09-12", + "Value": 2, + "Series": "Home" + }, + { + "Date": "2022-09-17", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2022-09-23", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2022-09-28", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2022-10-04", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2022-10-09", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2022-10-15", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2022-10-20", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2022-10-26", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2022-10-31", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2022-11-06", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2022-11-11", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2022-11-17", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2022-11-22", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2022-11-28", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2022-12-03", + "Value": 2, + "Series": "Home" + }, + { + "Date": "2022-12-09", + "Value": 12, + "Series": "Home" + }, + { + "Date": "2022-12-14", + "Value": 5, + "Series": "Home" + }, + { + "Date": "2022-12-20", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2022-12-25", + "Value": 0, + "Series": "Home" + }, + { + "Date": "2020-01-01", + "Value": 50, + "Series": "Garden" + }, + { + "Date": "2020-01-06", + "Value": 50, + "Series": "Garden" + }, + { + "Date": "2020-01-11", + "Value": 52, + "Series": "Garden" + }, + { + "Date": "2020-01-17", + "Value": 58, + "Series": "Garden" + }, + { + "Date": "2020-01-22", + "Value": 61, + "Series": "Garden" + }, + { + "Date": "2020-01-28", + "Value": 62, + "Series": "Garden" + }, + { + "Date": "2020-02-02", + "Value": 59, + "Series": "Garden" + }, + { + "Date": "2020-02-08", + "Value": 60, + "Series": "Garden" + }, + { + "Date": "2020-02-13", + "Value": 58, + "Series": "Garden" + }, + { + "Date": "2020-02-19", + "Value": 61, + "Series": "Garden" + }, + { + "Date": "2020-02-24", + "Value": 62, + "Series": "Garden" + }, + { + "Date": "2020-03-01", + "Value": 66, + "Series": "Garden" + }, + { + "Date": "2020-03-06", + "Value": 65, + "Series": "Garden" + }, + { + "Date": "2020-03-12", + "Value": 59, + "Series": "Garden" + }, + { + "Date": "2020-03-17", + "Value": 51, + "Series": "Garden" + }, + { + "Date": "2020-03-23", + "Value": 43, + "Series": "Garden" + }, + { + "Date": "2020-03-28", + "Value": 37, + "Series": "Garden" + }, + { + "Date": "2020-04-03", + "Value": 32, + "Series": "Garden" + }, + { + "Date": "2020-04-08", + "Value": 28, + "Series": "Garden" + }, + { + "Date": "2020-04-14", + "Value": 26, + "Series": "Garden" + }, + { + "Date": "2020-04-19", + "Value": 26, + "Series": "Garden" + }, + { + "Date": "2020-04-24", + "Value": 29, + "Series": "Garden" + }, + { + "Date": "2020-04-30", + "Value": 29, + "Series": "Garden" + }, + { + "Date": "2020-05-05", + "Value": 30, + "Series": "Garden" + }, + { + "Date": "2020-05-11", + "Value": 35, + "Series": "Garden" + }, + { + "Date": "2020-05-16", + "Value": 39, + "Series": "Garden" + }, + { + "Date": "2020-05-22", + "Value": 46, + "Series": "Garden" + }, + { + "Date": "2020-05-27", + "Value": 51, + "Series": "Garden" + }, + { + "Date": "2020-06-02", + "Value": 54, + "Series": "Garden" + }, + { + "Date": "2020-06-07", + "Value": 56, + "Series": "Garden" + }, + { + "Date": "2020-06-13", + "Value": 56, + "Series": "Garden" + }, + { + "Date": "2020-06-18", + "Value": 56, + "Series": "Garden" + }, + { + "Date": "2020-06-24", + "Value": 52, + "Series": "Garden" + }, + { + "Date": "2020-06-29", + "Value": 53, + "Series": "Garden" + }, + { + "Date": "2020-07-05", + "Value": 51, + "Series": "Garden" + }, + { + "Date": "2020-07-10", + "Value": 45, + "Series": "Garden" + }, + { + "Date": "2020-07-16", + "Value": 37, + "Series": "Garden" + }, + { + "Date": "2020-07-21", + "Value": 31, + "Series": "Garden" + }, + { + "Date": "2020-07-27", + "Value": 30, + "Series": "Garden" + }, + { + "Date": "2020-08-01", + "Value": 33, + "Series": "Garden" + }, + { + "Date": "2020-08-07", + "Value": 33, + "Series": "Garden" + }, + { + "Date": "2020-08-12", + "Value": 36, + "Series": "Garden" + }, + { + "Date": "2020-08-17", + "Value": 39, + "Series": "Garden" + }, + { + "Date": "2020-08-23", + "Value": 40, + "Series": "Garden" + }, + { + "Date": "2020-08-28", + "Value": 39, + "Series": "Garden" + }, + { + "Date": "2020-09-03", + "Value": 38, + "Series": "Garden" + }, + { + "Date": "2020-09-08", + "Value": 33, + "Series": "Garden" + }, + { + "Date": "2020-09-14", + "Value": 29, + "Series": "Garden" + }, + { + "Date": "2020-09-19", + "Value": 31, + "Series": "Garden" + }, + { + "Date": "2020-09-25", + "Value": 37, + "Series": "Garden" + }, + { + "Date": "2020-09-30", + "Value": 39, + "Series": "Garden" + }, + { + "Date": "2020-10-06", + "Value": 44, + "Series": "Garden" + }, + { + "Date": "2020-10-11", + "Value": 45, + "Series": "Garden" + }, + { + "Date": "2020-10-17", + "Value": 46, + "Series": "Garden" + }, + { + "Date": "2020-10-22", + "Value": 44, + "Series": "Garden" + }, + { + "Date": "2020-10-28", + "Value": 45, + "Series": "Garden" + }, + { + "Date": "2020-11-02", + "Value": 45, + "Series": "Garden" + }, + { + "Date": "2020-11-08", + "Value": 47, + "Series": "Garden" + }, + { + "Date": "2020-11-13", + "Value": 50, + "Series": "Garden" + }, + { + "Date": "2020-11-19", + "Value": 54, + "Series": "Garden" + }, + { + "Date": "2020-11-24", + "Value": 55, + "Series": "Garden" + }, + { + "Date": "2020-11-29", + "Value": 56, + "Series": "Garden" + }, + { + "Date": "2020-12-05", + "Value": 52, + "Series": "Garden" + }, + { + "Date": "2020-12-10", + "Value": 45, + "Series": "Garden" + }, + { + "Date": "2020-12-16", + "Value": 41, + "Series": "Garden" + }, + { + "Date": "2020-12-21", + "Value": 43, + "Series": "Garden" + }, + { + "Date": "2020-12-27", + "Value": 39, + "Series": "Garden" + }, + { + "Date": "2021-01-01", + "Value": 32, + "Series": "Garden" + }, + { + "Date": "2021-01-07", + "Value": 28, + "Series": "Garden" + }, + { + "Date": "2021-01-12", + "Value": 27, + "Series": "Garden" + }, + { + "Date": "2021-01-18", + "Value": 24, + "Series": "Garden" + }, + { + "Date": "2021-01-23", + "Value": 27, + "Series": "Garden" + }, + { + "Date": "2021-01-29", + "Value": 27, + "Series": "Garden" + }, + { + "Date": "2021-02-03", + "Value": 29, + "Series": "Garden" + }, + { + "Date": "2021-02-09", + "Value": 32, + "Series": "Garden" + }, + { + "Date": "2021-02-14", + "Value": 35, + "Series": "Garden" + }, + { + "Date": "2021-02-20", + "Value": 40, + "Series": "Garden" + }, + { + "Date": "2021-02-25", + "Value": 40, + "Series": "Garden" + }, + { + "Date": "2021-03-03", + "Value": 44, + "Series": "Garden" + }, + { + "Date": "2021-03-08", + "Value": 50, + "Series": "Garden" + }, + { + "Date": "2021-03-14", + "Value": 54, + "Series": "Garden" + }, + { + "Date": "2021-03-19", + "Value": 57, + "Series": "Garden" + }, + { + "Date": "2021-03-24", + "Value": 55, + "Series": "Garden" + }, + { + "Date": "2021-03-30", + "Value": 49, + "Series": "Garden" + }, + { + "Date": "2021-04-04", + "Value": 42, + "Series": "Garden" + }, + { + "Date": "2021-04-10", + "Value": 40, + "Series": "Garden" + }, + { + "Date": "2021-04-15", + "Value": 41, + "Series": "Garden" + }, + { + "Date": "2021-04-21", + "Value": 42, + "Series": "Garden" + }, + { + "Date": "2021-04-26", + "Value": 46, + "Series": "Garden" + }, + { + "Date": "2021-05-02", + "Value": 43, + "Series": "Garden" + }, + { + "Date": "2021-05-07", + "Value": 39, + "Series": "Garden" + }, + { + "Date": "2021-05-13", + "Value": 35, + "Series": "Garden" + }, + { + "Date": "2021-05-18", + "Value": 29, + "Series": "Garden" + }, + { + "Date": "2021-05-24", + "Value": 26, + "Series": "Garden" + }, + { + "Date": "2021-05-29", + "Value": 27, + "Series": "Garden" + }, + { + "Date": "2021-06-04", + "Value": 29, + "Series": "Garden" + }, + { + "Date": "2021-06-09", + "Value": 30, + "Series": "Garden" + }, + { + "Date": "2021-06-15", + "Value": 36, + "Series": "Garden" + }, + { + "Date": "2021-06-20", + "Value": 36, + "Series": "Garden" + }, + { + "Date": "2021-06-26", + "Value": 32, + "Series": "Garden" + }, + { + "Date": "2021-07-01", + "Value": 34, + "Series": "Garden" + }, + { + "Date": "2021-07-06", + "Value": 36, + "Series": "Garden" + }, + { + "Date": "2021-07-12", + "Value": 39, + "Series": "Garden" + }, + { + "Date": "2021-07-17", + "Value": 44, + "Series": "Garden" + }, + { + "Date": "2021-07-23", + "Value": 44, + "Series": "Garden" + }, + { + "Date": "2021-07-28", + "Value": 42, + "Series": "Garden" + }, + { + "Date": "2021-08-03", + "Value": 46, + "Series": "Garden" + }, + { + "Date": "2021-08-08", + "Value": 48, + "Series": "Garden" + }, + { + "Date": "2021-08-14", + "Value": 52, + "Series": "Garden" + }, + { + "Date": "2021-08-19", + "Value": 59, + "Series": "Garden" + }, + { + "Date": "2021-08-25", + "Value": 61, + "Series": "Garden" + }, + { + "Date": "2021-08-30", + "Value": 64, + "Series": "Garden" + }, + { + "Date": "2021-09-05", + "Value": 61, + "Series": "Garden" + }, + { + "Date": "2021-09-10", + "Value": 64, + "Series": "Garden" + }, + { + "Date": "2021-09-16", + "Value": 64, + "Series": "Garden" + }, + { + "Date": "2021-09-21", + "Value": 61, + "Series": "Garden" + }, + { + "Date": "2021-09-27", + "Value": 62, + "Series": "Garden" + }, + { + "Date": "2021-10-02", + "Value": 64, + "Series": "Garden" + }, + { + "Date": "2021-10-08", + "Value": 62, + "Series": "Garden" + }, + { + "Date": "2021-10-13", + "Value": 59, + "Series": "Garden" + }, + { + "Date": "2021-10-19", + "Value": 55, + "Series": "Garden" + }, + { + "Date": "2021-10-24", + "Value": 50, + "Series": "Garden" + }, + { + "Date": "2021-10-29", + "Value": 48, + "Series": "Garden" + }, + { + "Date": "2021-11-04", + "Value": 52, + "Series": "Garden" + }, + { + "Date": "2021-11-09", + "Value": 60, + "Series": "Garden" + }, + { + "Date": "2021-11-15", + "Value": 62, + "Series": "Garden" + }, + { + "Date": "2021-11-20", + "Value": 68, + "Series": "Garden" + }, + { + "Date": "2021-11-26", + "Value": 75, + "Series": "Garden" + }, + { + "Date": "2021-12-01", + "Value": 80, + "Series": "Garden" + }, + { + "Date": "2021-12-07", + "Value": 81, + "Series": "Garden" + }, + { + "Date": "2021-12-12", + "Value": 79, + "Series": "Garden" + }, + { + "Date": "2021-12-18", + "Value": 73, + "Series": "Garden" + }, + { + "Date": "2021-12-23", + "Value": 65, + "Series": "Garden" + }, + { + "Date": "2021-12-29", + "Value": 55, + "Series": "Garden" + }, + { + "Date": "2022-01-03", + "Value": 50, + "Series": "Garden" + }, + { + "Date": "2022-01-09", + "Value": 42, + "Series": "Garden" + }, + { + "Date": "2022-01-14", + "Value": 34, + "Series": "Garden" + }, + { + "Date": "2022-01-20", + "Value": 32, + "Series": "Garden" + }, + { + "Date": "2022-01-25", + "Value": 36, + "Series": "Garden" + }, + { + "Date": "2022-01-31", + "Value": 37, + "Series": "Garden" + }, + { + "Date": "2022-02-05", + "Value": 41, + "Series": "Garden" + }, + { + "Date": "2022-02-10", + "Value": 39, + "Series": "Garden" + }, + { + "Date": "2022-02-16", + "Value": 41, + "Series": "Garden" + }, + { + "Date": "2022-02-21", + "Value": 44, + "Series": "Garden" + }, + { + "Date": "2022-02-27", + "Value": 48, + "Series": "Garden" + }, + { + "Date": "2022-03-04", + "Value": 54, + "Series": "Garden" + }, + { + "Date": "2022-03-10", + "Value": 57, + "Series": "Garden" + }, + { + "Date": "2022-03-15", + "Value": 54, + "Series": "Garden" + }, + { + "Date": "2022-03-21", + "Value": 53, + "Series": "Garden" + }, + { + "Date": "2022-03-26", + "Value": 51, + "Series": "Garden" + }, + { + "Date": "2022-04-01", + "Value": 45, + "Series": "Garden" + }, + { + "Date": "2022-04-06", + "Value": 41, + "Series": "Garden" + }, + { + "Date": "2022-04-12", + "Value": 43, + "Series": "Garden" + }, + { + "Date": "2022-04-17", + "Value": 46, + "Series": "Garden" + }, + { + "Date": "2022-04-23", + "Value": 53, + "Series": "Garden" + }, + { + "Date": "2022-04-28", + "Value": 56, + "Series": "Garden" + }, + { + "Date": "2022-05-04", + "Value": 62, + "Series": "Garden" + }, + { + "Date": "2022-05-09", + "Value": 65, + "Series": "Garden" + }, + { + "Date": "2022-05-15", + "Value": 66, + "Series": "Garden" + }, + { + "Date": "2022-05-20", + "Value": 62, + "Series": "Garden" + }, + { + "Date": "2022-05-26", + "Value": 55, + "Series": "Garden" + }, + { + "Date": "2022-05-31", + "Value": 55, + "Series": "Garden" + }, + { + "Date": "2022-06-05", + "Value": 50, + "Series": "Garden" + }, + { + "Date": "2022-06-11", + "Value": 50, + "Series": "Garden" + }, + { + "Date": "2022-06-16", + "Value": 50, + "Series": "Garden" + }, + { + "Date": "2022-06-22", + "Value": 51, + "Series": "Garden" + }, + { + "Date": "2022-06-27", + "Value": 54, + "Series": "Garden" + }, + { + "Date": "2022-07-03", + "Value": 52, + "Series": "Garden" + }, + { + "Date": "2022-07-08", + "Value": 50, + "Series": "Garden" + }, + { + "Date": "2022-07-14", + "Value": 54, + "Series": "Garden" + }, + { + "Date": "2022-07-19", + "Value": 53, + "Series": "Garden" + }, + { + "Date": "2022-07-25", + "Value": 51, + "Series": "Garden" + }, + { + "Date": "2022-07-30", + "Value": 54, + "Series": "Garden" + }, + { + "Date": "2022-08-05", + "Value": 56, + "Series": "Garden" + }, + { + "Date": "2022-08-10", + "Value": 54, + "Series": "Garden" + }, + { + "Date": "2022-08-16", + "Value": 54, + "Series": "Garden" + }, + { + "Date": "2022-08-21", + "Value": 55, + "Series": "Garden" + }, + { + "Date": "2022-08-27", + "Value": 59, + "Series": "Garden" + }, + { + "Date": "2022-09-01", + "Value": 59, + "Series": "Garden" + }, + { + "Date": "2022-09-07", + "Value": 58, + "Series": "Garden" + }, + { + "Date": "2022-09-12", + "Value": 57, + "Series": "Garden" + }, + { + "Date": "2022-09-17", + "Value": 55, + "Series": "Garden" + }, + { + "Date": "2022-09-23", + "Value": 54, + "Series": "Garden" + }, + { + "Date": "2022-09-28", + "Value": 51, + "Series": "Garden" + }, + { + "Date": "2022-10-04", + "Value": 48, + "Series": "Garden" + }, + { + "Date": "2022-10-09", + "Value": 46, + "Series": "Garden" + }, + { + "Date": "2022-10-15", + "Value": 43, + "Series": "Garden" + }, + { + "Date": "2022-10-20", + "Value": 42, + "Series": "Garden" + }, + { + "Date": "2022-10-26", + "Value": 41, + "Series": "Garden" + }, + { + "Date": "2022-10-31", + "Value": 37, + "Series": "Garden" + }, + { + "Date": "2022-11-06", + "Value": 31, + "Series": "Garden" + }, + { + "Date": "2022-11-11", + "Value": 28, + "Series": "Garden" + }, + { + "Date": "2022-11-17", + "Value": 22, + "Series": "Garden" + }, + { + "Date": "2022-11-22", + "Value": 21, + "Series": "Garden" + }, + { + "Date": "2022-11-28", + "Value": 16, + "Series": "Garden" + }, + { + "Date": "2022-12-03", + "Value": 9, + "Series": "Garden" + }, + { + "Date": "2022-12-09", + "Value": 6, + "Series": "Garden" + }, + { + "Date": "2022-12-14", + "Value": 8, + "Series": "Garden" + }, + { + "Date": "2022-12-20", + "Value": 11, + "Series": "Garden" + }, + { + "Date": "2022-12-25", + "Value": 12, + "Series": "Garden" + }, + { + "Date": "2020-01-01", + "Value": 201, + "Series": "Auto" + }, + { + "Date": "2020-01-06", + "Value": 210, + "Series": "Auto" + }, + { + "Date": "2020-01-11", + "Value": 204, + "Series": "Auto" + }, + { + "Date": "2020-01-17", + "Value": 188, + "Series": "Auto" + }, + { + "Date": "2020-01-22", + "Value": 179, + "Series": "Auto" + }, + { + "Date": "2020-01-28", + "Value": 162, + "Series": "Auto" + }, + { + "Date": "2020-02-02", + "Value": 142, + "Series": "Auto" + }, + { + "Date": "2020-02-08", + "Value": 140, + "Series": "Auto" + }, + { + "Date": "2020-02-13", + "Value": 133, + "Series": "Auto" + }, + { + "Date": "2020-02-19", + "Value": 136, + "Series": "Auto" + }, + { + "Date": "2020-02-24", + "Value": 129, + "Series": "Auto" + }, + { + "Date": "2020-03-01", + "Value": 113, + "Series": "Auto" + }, + { + "Date": "2020-03-06", + "Value": 98, + "Series": "Auto" + }, + { + "Date": "2020-03-12", + "Value": 79, + "Series": "Auto" + }, + { + "Date": "2020-03-17", + "Value": 69, + "Series": "Auto" + }, + { + "Date": "2020-03-23", + "Value": 74, + "Series": "Auto" + }, + { + "Date": "2020-03-28", + "Value": 77, + "Series": "Auto" + }, + { + "Date": "2020-04-03", + "Value": 81, + "Series": "Auto" + }, + { + "Date": "2020-04-08", + "Value": 81, + "Series": "Auto" + }, + { + "Date": "2020-04-14", + "Value": 78, + "Series": "Auto" + }, + { + "Date": "2020-04-19", + "Value": 63, + "Series": "Auto" + }, + { + "Date": "2020-04-24", + "Value": 55, + "Series": "Auto" + }, + { + "Date": "2020-04-30", + "Value": 53, + "Series": "Auto" + }, + { + "Date": "2020-05-05", + "Value": 58, + "Series": "Auto" + }, + { + "Date": "2020-05-11", + "Value": 66, + "Series": "Auto" + }, + { + "Date": "2020-05-16", + "Value": 82, + "Series": "Auto" + }, + { + "Date": "2020-05-22", + "Value": 104, + "Series": "Auto" + }, + { + "Date": "2020-05-27", + "Value": 124, + "Series": "Auto" + }, + { + "Date": "2020-06-02", + "Value": 138, + "Series": "Auto" + }, + { + "Date": "2020-06-07", + "Value": 144, + "Series": "Auto" + }, + { + "Date": "2020-06-13", + "Value": 155, + "Series": "Auto" + }, + { + "Date": "2020-06-18", + "Value": 156, + "Series": "Auto" + }, + { + "Date": "2020-06-24", + "Value": 149, + "Series": "Auto" + }, + { + "Date": "2020-06-29", + "Value": 140, + "Series": "Auto" + }, + { + "Date": "2020-07-05", + "Value": 144, + "Series": "Auto" + }, + { + "Date": "2020-07-10", + "Value": 154, + "Series": "Auto" + }, + { + "Date": "2020-07-16", + "Value": 164, + "Series": "Auto" + }, + { + "Date": "2020-07-21", + "Value": 167, + "Series": "Auto" + }, + { + "Date": "2020-07-27", + "Value": 163, + "Series": "Auto" + }, + { + "Date": "2020-08-01", + "Value": 168, + "Series": "Auto" + }, + { + "Date": "2020-08-07", + "Value": 162, + "Series": "Auto" + }, + { + "Date": "2020-08-12", + "Value": 165, + "Series": "Auto" + }, + { + "Date": "2020-08-17", + "Value": 164, + "Series": "Auto" + }, + { + "Date": "2020-08-23", + "Value": 156, + "Series": "Auto" + }, + { + "Date": "2020-08-28", + "Value": 161, + "Series": "Auto" + }, + { + "Date": "2020-09-03", + "Value": 164, + "Series": "Auto" + }, + { + "Date": "2020-09-08", + "Value": 176, + "Series": "Auto" + }, + { + "Date": "2020-09-14", + "Value": 187, + "Series": "Auto" + }, + { + "Date": "2020-09-19", + "Value": 188, + "Series": "Auto" + }, + { + "Date": "2020-09-25", + "Value": 190, + "Series": "Auto" + }, + { + "Date": "2020-09-30", + "Value": 198, + "Series": "Auto" + }, + { + "Date": "2020-10-06", + "Value": 200, + "Series": "Auto" + }, + { + "Date": "2020-10-11", + "Value": 206, + "Series": "Auto" + }, + { + "Date": "2020-10-17", + "Value": 201, + "Series": "Auto" + }, + { + "Date": "2020-10-22", + "Value": 201, + "Series": "Auto" + }, + { + "Date": "2020-10-28", + "Value": 206, + "Series": "Auto" + }, + { + "Date": "2020-11-02", + "Value": 222, + "Series": "Auto" + }, + { + "Date": "2020-11-08", + "Value": 225, + "Series": "Auto" + }, + { + "Date": "2020-11-13", + "Value": 235, + "Series": "Auto" + }, + { + "Date": "2020-11-19", + "Value": 248, + "Series": "Auto" + }, + { + "Date": "2020-11-24", + "Value": 253, + "Series": "Auto" + }, + { + "Date": "2020-11-29", + "Value": 267, + "Series": "Auto" + }, + { + "Date": "2020-12-05", + "Value": 283, + "Series": "Auto" + }, + { + "Date": "2020-12-10", + "Value": 302, + "Series": "Auto" + }, + { + "Date": "2020-12-16", + "Value": 319, + "Series": "Auto" + }, + { + "Date": "2020-12-21", + "Value": 321, + "Series": "Auto" + }, + { + "Date": "2020-12-27", + "Value": 326, + "Series": "Auto" + }, + { + "Date": "2021-01-01", + "Value": 332, + "Series": "Auto" + }, + { + "Date": "2021-01-07", + "Value": 326, + "Series": "Auto" + }, + { + "Date": "2021-01-12", + "Value": 323, + "Series": "Auto" + }, + { + "Date": "2021-01-18", + "Value": 330, + "Series": "Auto" + }, + { + "Date": "2021-01-23", + "Value": 323, + "Series": "Auto" + }, + { + "Date": "2021-01-29", + "Value": 326, + "Series": "Auto" + }, + { + "Date": "2021-02-03", + "Value": 318, + "Series": "Auto" + }, + { + "Date": "2021-02-09", + "Value": 313, + "Series": "Auto" + }, + { + "Date": "2021-02-14", + "Value": 319, + "Series": "Auto" + }, + { + "Date": "2021-02-20", + "Value": 334, + "Series": "Auto" + }, + { + "Date": "2021-02-25", + "Value": 334, + "Series": "Auto" + }, + { + "Date": "2021-03-03", + "Value": 322, + "Series": "Auto" + }, + { + "Date": "2021-03-08", + "Value": 309, + "Series": "Auto" + }, + { + "Date": "2021-03-14", + "Value": 293, + "Series": "Auto" + }, + { + "Date": "2021-03-19", + "Value": 288, + "Series": "Auto" + }, + { + "Date": "2021-03-24", + "Value": 284, + "Series": "Auto" + }, + { + "Date": "2021-03-30", + "Value": 272, + "Series": "Auto" + }, + { + "Date": "2021-04-04", + "Value": 259, + "Series": "Auto" + }, + { + "Date": "2021-04-10", + "Value": 258, + "Series": "Auto" + }, + { + "Date": "2021-04-15", + "Value": 262, + "Series": "Auto" + }, + { + "Date": "2021-04-21", + "Value": 264, + "Series": "Auto" + }, + { + "Date": "2021-04-26", + "Value": 265, + "Series": "Auto" + }, + { + "Date": "2021-05-02", + "Value": 255, + "Series": "Auto" + }, + { + "Date": "2021-05-07", + "Value": 248, + "Series": "Auto" + }, + { + "Date": "2021-05-13", + "Value": 230, + "Series": "Auto" + }, + { + "Date": "2021-05-18", + "Value": 217, + "Series": "Auto" + }, + { + "Date": "2021-05-24", + "Value": 201, + "Series": "Auto" + }, + { + "Date": "2021-05-29", + "Value": 188, + "Series": "Auto" + }, + { + "Date": "2021-06-04", + "Value": 178, + "Series": "Auto" + }, + { + "Date": "2021-06-09", + "Value": 165, + "Series": "Auto" + }, + { + "Date": "2021-06-15", + "Value": 153, + "Series": "Auto" + }, + { + "Date": "2021-06-20", + "Value": 155, + "Series": "Auto" + }, + { + "Date": "2021-06-26", + "Value": 160, + "Series": "Auto" + }, + { + "Date": "2021-07-01", + "Value": 155, + "Series": "Auto" + }, + { + "Date": "2021-07-06", + "Value": 149, + "Series": "Auto" + }, + { + "Date": "2021-07-12", + "Value": 143, + "Series": "Auto" + }, + { + "Date": "2021-07-17", + "Value": 150, + "Series": "Auto" + }, + { + "Date": "2021-07-23", + "Value": 146, + "Series": "Auto" + }, + { + "Date": "2021-07-28", + "Value": 156, + "Series": "Auto" + }, + { + "Date": "2021-08-03", + "Value": 158, + "Series": "Auto" + }, + { + "Date": "2021-08-08", + "Value": 147, + "Series": "Auto" + }, + { + "Date": "2021-08-14", + "Value": 136, + "Series": "Auto" + }, + { + "Date": "2021-08-19", + "Value": 132, + "Series": "Auto" + }, + { + "Date": "2021-08-25", + "Value": 117, + "Series": "Auto" + }, + { + "Date": "2021-08-30", + "Value": 107, + "Series": "Auto" + }, + { + "Date": "2021-09-05", + "Value": 105, + "Series": "Auto" + }, + { + "Date": "2021-09-10", + "Value": 114, + "Series": "Auto" + }, + { + "Date": "2021-09-16", + "Value": 131, + "Series": "Auto" + }, + { + "Date": "2021-09-21", + "Value": 131, + "Series": "Auto" + }, + { + "Date": "2021-09-27", + "Value": 125, + "Series": "Auto" + }, + { + "Date": "2021-10-02", + "Value": 113, + "Series": "Auto" + }, + { + "Date": "2021-10-08", + "Value": 110, + "Series": "Auto" + }, + { + "Date": "2021-10-13", + "Value": 97, + "Series": "Auto" + }, + { + "Date": "2021-10-19", + "Value": 81, + "Series": "Auto" + }, + { + "Date": "2021-10-24", + "Value": 58, + "Series": "Auto" + }, + { + "Date": "2021-10-29", + "Value": 34, + "Series": "Auto" + }, + { + "Date": "2021-11-04", + "Value": 23, + "Series": "Auto" + }, + { + "Date": "2021-11-09", + "Value": 6, + "Series": "Auto" + }, + { + "Date": "2021-11-15", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2021-11-20", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2021-11-26", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2021-12-01", + "Value": 1, + "Series": "Auto" + }, + { + "Date": "2021-12-07", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2021-12-12", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2021-12-18", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2021-12-23", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2021-12-29", + "Value": 1, + "Series": "Auto" + }, + { + "Date": "2022-01-03", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2022-01-09", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2022-01-14", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2022-01-20", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2022-01-25", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2022-01-31", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2022-02-05", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2022-02-10", + "Value": 3, + "Series": "Auto" + }, + { + "Date": "2022-02-16", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2022-02-21", + "Value": 5, + "Series": "Auto" + }, + { + "Date": "2022-02-27", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2022-03-04", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2022-03-10", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2022-03-15", + "Value": 1, + "Series": "Auto" + }, + { + "Date": "2022-03-21", + "Value": 13, + "Series": "Auto" + }, + { + "Date": "2022-03-26", + "Value": 19, + "Series": "Auto" + }, + { + "Date": "2022-04-01", + "Value": 28, + "Series": "Auto" + }, + { + "Date": "2022-04-06", + "Value": 34, + "Series": "Auto" + }, + { + "Date": "2022-04-12", + "Value": 44, + "Series": "Auto" + }, + { + "Date": "2022-04-17", + "Value": 60, + "Series": "Auto" + }, + { + "Date": "2022-04-23", + "Value": 70, + "Series": "Auto" + }, + { + "Date": "2022-04-28", + "Value": 74, + "Series": "Auto" + }, + { + "Date": "2022-05-04", + "Value": 84, + "Series": "Auto" + }, + { + "Date": "2022-05-09", + "Value": 88, + "Series": "Auto" + }, + { + "Date": "2022-05-15", + "Value": 90, + "Series": "Auto" + }, + { + "Date": "2022-05-20", + "Value": 103, + "Series": "Auto" + }, + { + "Date": "2022-05-26", + "Value": 111, + "Series": "Auto" + }, + { + "Date": "2022-05-31", + "Value": 105, + "Series": "Auto" + }, + { + "Date": "2022-06-05", + "Value": 106, + "Series": "Auto" + }, + { + "Date": "2022-06-11", + "Value": 116, + "Series": "Auto" + }, + { + "Date": "2022-06-16", + "Value": 111, + "Series": "Auto" + }, + { + "Date": "2022-06-22", + "Value": 95, + "Series": "Auto" + }, + { + "Date": "2022-06-27", + "Value": 77, + "Series": "Auto" + }, + { + "Date": "2022-07-03", + "Value": 77, + "Series": "Auto" + }, + { + "Date": "2022-07-08", + "Value": 73, + "Series": "Auto" + }, + { + "Date": "2022-07-14", + "Value": 66, + "Series": "Auto" + }, + { + "Date": "2022-07-19", + "Value": 48, + "Series": "Auto" + }, + { + "Date": "2022-07-25", + "Value": 27, + "Series": "Auto" + }, + { + "Date": "2022-07-30", + "Value": 12, + "Series": "Auto" + }, + { + "Date": "2022-08-05", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2022-08-10", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2022-08-16", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2022-08-21", + "Value": 7, + "Series": "Auto" + }, + { + "Date": "2022-08-27", + "Value": 10, + "Series": "Auto" + }, + { + "Date": "2022-09-01", + "Value": 4, + "Series": "Auto" + }, + { + "Date": "2022-09-07", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2022-09-12", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2022-09-17", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2022-09-23", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2022-09-28", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2022-10-04", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2022-10-09", + "Value": 6, + "Series": "Auto" + }, + { + "Date": "2022-10-15", + "Value": 10, + "Series": "Auto" + }, + { + "Date": "2022-10-20", + "Value": 17, + "Series": "Auto" + }, + { + "Date": "2022-10-26", + "Value": 11, + "Series": "Auto" + }, + { + "Date": "2022-10-31", + "Value": 9, + "Series": "Auto" + }, + { + "Date": "2022-11-06", + "Value": 7, + "Series": "Auto" + }, + { + "Date": "2022-11-11", + "Value": 13, + "Series": "Auto" + }, + { + "Date": "2022-11-17", + "Value": 9, + "Series": "Auto" + }, + { + "Date": "2022-11-22", + "Value": 14, + "Series": "Auto" + }, + { + "Date": "2022-11-28", + "Value": 7, + "Series": "Auto" + }, + { + "Date": "2022-12-03", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2022-12-09", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2022-12-14", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2022-12-20", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2022-12-25", + "Value": 0, + "Series": "Auto" + }, + { + "Date": "2020-01-01", + "Value": 127, + "Series": "Health" + }, + { + "Date": "2020-01-06", + "Value": 120, + "Series": "Health" + }, + { + "Date": "2020-01-11", + "Value": 115, + "Series": "Health" + }, + { + "Date": "2020-01-17", + "Value": 111, + "Series": "Health" + }, + { + "Date": "2020-01-22", + "Value": 112, + "Series": "Health" + }, + { + "Date": "2020-01-28", + "Value": 119, + "Series": "Health" + }, + { + "Date": "2020-02-02", + "Value": 128, + "Series": "Health" + }, + { + "Date": "2020-02-08", + "Value": 138, + "Series": "Health" + }, + { + "Date": "2020-02-13", + "Value": 144, + "Series": "Health" + }, + { + "Date": "2020-02-19", + "Value": 144, + "Series": "Health" + }, + { + "Date": "2020-02-24", + "Value": 138, + "Series": "Health" + }, + { + "Date": "2020-03-01", + "Value": 142, + "Series": "Health" + }, + { + "Date": "2020-03-06", + "Value": 136, + "Series": "Health" + }, + { + "Date": "2020-03-12", + "Value": 135, + "Series": "Health" + }, + { + "Date": "2020-03-17", + "Value": 132, + "Series": "Health" + }, + { + "Date": "2020-03-23", + "Value": 134, + "Series": "Health" + }, + { + "Date": "2020-03-28", + "Value": 128, + "Series": "Health" + }, + { + "Date": "2020-04-03", + "Value": 123, + "Series": "Health" + }, + { + "Date": "2020-04-08", + "Value": 114, + "Series": "Health" + }, + { + "Date": "2020-04-14", + "Value": 101, + "Series": "Health" + }, + { + "Date": "2020-04-19", + "Value": 87, + "Series": "Health" + }, + { + "Date": "2020-04-24", + "Value": 72, + "Series": "Health" + }, + { + "Date": "2020-04-30", + "Value": 64, + "Series": "Health" + }, + { + "Date": "2020-05-05", + "Value": 65, + "Series": "Health" + }, + { + "Date": "2020-05-11", + "Value": 70, + "Series": "Health" + }, + { + "Date": "2020-05-16", + "Value": 74, + "Series": "Health" + }, + { + "Date": "2020-05-22", + "Value": 81, + "Series": "Health" + }, + { + "Date": "2020-05-27", + "Value": 91, + "Series": "Health" + }, + { + "Date": "2020-06-02", + "Value": 99, + "Series": "Health" + }, + { + "Date": "2020-06-07", + "Value": 98, + "Series": "Health" + }, + { + "Date": "2020-06-13", + "Value": 92, + "Series": "Health" + }, + { + "Date": "2020-06-18", + "Value": 80, + "Series": "Health" + }, + { + "Date": "2020-06-24", + "Value": 77, + "Series": "Health" + }, + { + "Date": "2020-06-29", + "Value": 72, + "Series": "Health" + }, + { + "Date": "2020-07-05", + "Value": 73, + "Series": "Health" + }, + { + "Date": "2020-07-10", + "Value": 68, + "Series": "Health" + }, + { + "Date": "2020-07-16", + "Value": 61, + "Series": "Health" + }, + { + "Date": "2020-07-21", + "Value": 49, + "Series": "Health" + }, + { + "Date": "2020-07-27", + "Value": 40, + "Series": "Health" + }, + { + "Date": "2020-08-01", + "Value": 34, + "Series": "Health" + }, + { + "Date": "2020-08-07", + "Value": 35, + "Series": "Health" + }, + { + "Date": "2020-08-12", + "Value": 28, + "Series": "Health" + }, + { + "Date": "2020-08-17", + "Value": 25, + "Series": "Health" + }, + { + "Date": "2020-08-23", + "Value": 23, + "Series": "Health" + }, + { + "Date": "2020-08-28", + "Value": 23, + "Series": "Health" + }, + { + "Date": "2020-09-03", + "Value": 28, + "Series": "Health" + }, + { + "Date": "2020-09-08", + "Value": 36, + "Series": "Health" + }, + { + "Date": "2020-09-14", + "Value": 34, + "Series": "Health" + }, + { + "Date": "2020-09-19", + "Value": 33, + "Series": "Health" + }, + { + "Date": "2020-09-25", + "Value": 31, + "Series": "Health" + }, + { + "Date": "2020-09-30", + "Value": 34, + "Series": "Health" + }, + { + "Date": "2020-10-06", + "Value": 43, + "Series": "Health" + }, + { + "Date": "2020-10-11", + "Value": 49, + "Series": "Health" + }, + { + "Date": "2020-10-17", + "Value": 57, + "Series": "Health" + }, + { + "Date": "2020-10-22", + "Value": 55, + "Series": "Health" + }, + { + "Date": "2020-10-28", + "Value": 58, + "Series": "Health" + }, + { + "Date": "2020-11-02", + "Value": 55, + "Series": "Health" + }, + { + "Date": "2020-11-08", + "Value": 50, + "Series": "Health" + }, + { + "Date": "2020-11-13", + "Value": 40, + "Series": "Health" + }, + { + "Date": "2020-11-19", + "Value": 35, + "Series": "Health" + }, + { + "Date": "2020-11-24", + "Value": 26, + "Series": "Health" + }, + { + "Date": "2020-11-29", + "Value": 27, + "Series": "Health" + }, + { + "Date": "2020-12-05", + "Value": 31, + "Series": "Health" + }, + { + "Date": "2020-12-10", + "Value": 35, + "Series": "Health" + }, + { + "Date": "2020-12-16", + "Value": 40, + "Series": "Health" + }, + { + "Date": "2020-12-21", + "Value": 48, + "Series": "Health" + }, + { + "Date": "2020-12-27", + "Value": 50, + "Series": "Health" + }, + { + "Date": "2021-01-01", + "Value": 48, + "Series": "Health" + }, + { + "Date": "2021-01-07", + "Value": 54, + "Series": "Health" + }, + { + "Date": "2021-01-12", + "Value": 67, + "Series": "Health" + }, + { + "Date": "2021-01-18", + "Value": 74, + "Series": "Health" + }, + { + "Date": "2021-01-23", + "Value": 82, + "Series": "Health" + }, + { + "Date": "2021-01-29", + "Value": 93, + "Series": "Health" + }, + { + "Date": "2021-02-03", + "Value": 101, + "Series": "Health" + }, + { + "Date": "2021-02-09", + "Value": 109, + "Series": "Health" + }, + { + "Date": "2021-02-14", + "Value": 111, + "Series": "Health" + }, + { + "Date": "2021-02-20", + "Value": 119, + "Series": "Health" + }, + { + "Date": "2021-02-25", + "Value": 130, + "Series": "Health" + }, + { + "Date": "2021-03-03", + "Value": 133, + "Series": "Health" + }, + { + "Date": "2021-03-08", + "Value": 128, + "Series": "Health" + }, + { + "Date": "2021-03-14", + "Value": 127, + "Series": "Health" + }, + { + "Date": "2021-03-19", + "Value": 127, + "Series": "Health" + }, + { + "Date": "2021-03-24", + "Value": 121, + "Series": "Health" + }, + { + "Date": "2021-03-30", + "Value": 110, + "Series": "Health" + }, + { + "Date": "2021-04-04", + "Value": 98, + "Series": "Health" + }, + { + "Date": "2021-04-10", + "Value": 81, + "Series": "Health" + }, + { + "Date": "2021-04-15", + "Value": 61, + "Series": "Health" + }, + { + "Date": "2021-04-21", + "Value": 50, + "Series": "Health" + }, + { + "Date": "2021-04-26", + "Value": 40, + "Series": "Health" + }, + { + "Date": "2021-05-02", + "Value": 34, + "Series": "Health" + }, + { + "Date": "2021-05-07", + "Value": 31, + "Series": "Health" + }, + { + "Date": "2021-05-13", + "Value": 36, + "Series": "Health" + }, + { + "Date": "2021-05-18", + "Value": 41, + "Series": "Health" + }, + { + "Date": "2021-05-24", + "Value": 37, + "Series": "Health" + }, + { + "Date": "2021-05-29", + "Value": 33, + "Series": "Health" + }, + { + "Date": "2021-06-04", + "Value": 29, + "Series": "Health" + }, + { + "Date": "2021-06-09", + "Value": 29, + "Series": "Health" + }, + { + "Date": "2021-06-15", + "Value": 36, + "Series": "Health" + }, + { + "Date": "2021-06-20", + "Value": 35, + "Series": "Health" + }, + { + "Date": "2021-06-26", + "Value": 29, + "Series": "Health" + }, + { + "Date": "2021-07-01", + "Value": 31, + "Series": "Health" + }, + { + "Date": "2021-07-06", + "Value": 23, + "Series": "Health" + }, + { + "Date": "2021-07-12", + "Value": 11, + "Series": "Health" + }, + { + "Date": "2021-07-17", + "Value": 8, + "Series": "Health" + }, + { + "Date": "2021-07-23", + "Value": 7, + "Series": "Health" + }, + { + "Date": "2021-07-28", + "Value": 3, + "Series": "Health" + }, + { + "Date": "2021-08-03", + "Value": 0, + "Series": "Health" + }, + { + "Date": "2021-08-08", + "Value": 0, + "Series": "Health" + }, + { + "Date": "2021-08-14", + "Value": 3, + "Series": "Health" + }, + { + "Date": "2021-08-19", + "Value": 8, + "Series": "Health" + }, + { + "Date": "2021-08-25", + "Value": 18, + "Series": "Health" + }, + { + "Date": "2021-08-30", + "Value": 28, + "Series": "Health" + }, + { + "Date": "2021-09-05", + "Value": 35, + "Series": "Health" + }, + { + "Date": "2021-09-10", + "Value": 39, + "Series": "Health" + }, + { + "Date": "2021-09-16", + "Value": 33, + "Series": "Health" + }, + { + "Date": "2021-09-21", + "Value": 34, + "Series": "Health" + }, + { + "Date": "2021-09-27", + "Value": 28, + "Series": "Health" + }, + { + "Date": "2021-10-02", + "Value": 32, + "Series": "Health" + }, + { + "Date": "2021-10-08", + "Value": 40, + "Series": "Health" + }, + { + "Date": "2021-10-13", + "Value": 38, + "Series": "Health" + }, + { + "Date": "2021-10-19", + "Value": 43, + "Series": "Health" + }, + { + "Date": "2021-10-24", + "Value": 51, + "Series": "Health" + }, + { + "Date": "2021-10-29", + "Value": 53, + "Series": "Health" + }, + { + "Date": "2021-11-04", + "Value": 58, + "Series": "Health" + }, + { + "Date": "2021-11-09", + "Value": 56, + "Series": "Health" + }, + { + "Date": "2021-11-15", + "Value": 54, + "Series": "Health" + }, + { + "Date": "2021-11-20", + "Value": 49, + "Series": "Health" + }, + { + "Date": "2021-11-26", + "Value": 40, + "Series": "Health" + }, + { + "Date": "2021-12-01", + "Value": 33, + "Series": "Health" + }, + { + "Date": "2021-12-07", + "Value": 22, + "Series": "Health" + }, + { + "Date": "2021-12-12", + "Value": 9, + "Series": "Health" + }, + { + "Date": "2021-12-18", + "Value": 5, + "Series": "Health" + }, + { + "Date": "2021-12-23", + "Value": 9, + "Series": "Health" + }, + { + "Date": "2021-12-29", + "Value": 19, + "Series": "Health" + }, + { + "Date": "2022-01-03", + "Value": 33, + "Series": "Health" + }, + { + "Date": "2022-01-09", + "Value": 36, + "Series": "Health" + }, + { + "Date": "2022-01-14", + "Value": 39, + "Series": "Health" + }, + { + "Date": "2022-01-20", + "Value": 32, + "Series": "Health" + }, + { + "Date": "2022-01-25", + "Value": 23, + "Series": "Health" + }, + { + "Date": "2022-01-31", + "Value": 14, + "Series": "Health" + }, + { + "Date": "2022-02-05", + "Value": 11, + "Series": "Health" + }, + { + "Date": "2022-02-10", + "Value": 13, + "Series": "Health" + }, + { + "Date": "2022-02-16", + "Value": 6, + "Series": "Health" + }, + { + "Date": "2022-02-21", + "Value": 0, + "Series": "Health" + }, + { + "Date": "2022-02-27", + "Value": 0, + "Series": "Health" + }, + { + "Date": "2022-03-04", + "Value": 0, + "Series": "Health" + }, + { + "Date": "2022-03-10", + "Value": 3, + "Series": "Health" + }, + { + "Date": "2022-03-15", + "Value": 14, + "Series": "Health" + }, + { + "Date": "2022-03-21", + "Value": 20, + "Series": "Health" + }, + { + "Date": "2022-03-26", + "Value": 31, + "Series": "Health" + }, + { + "Date": "2022-04-01", + "Value": 32, + "Series": "Health" + }, + { + "Date": "2022-04-06", + "Value": 36, + "Series": "Health" + }, + { + "Date": "2022-04-12", + "Value": 30, + "Series": "Health" + }, + { + "Date": "2022-04-17", + "Value": 25, + "Series": "Health" + }, + { + "Date": "2022-04-23", + "Value": 23, + "Series": "Health" + }, + { + "Date": "2022-04-28", + "Value": 19, + "Series": "Health" + }, + { + "Date": "2022-05-04", + "Value": 24, + "Series": "Health" + }, + { + "Date": "2022-05-09", + "Value": 32, + "Series": "Health" + }, + { + "Date": "2022-05-15", + "Value": 46, + "Series": "Health" + }, + { + "Date": "2022-05-20", + "Value": 64, + "Series": "Health" + }, + { + "Date": "2022-05-26", + "Value": 77, + "Series": "Health" + }, + { + "Date": "2022-05-31", + "Value": 84, + "Series": "Health" + }, + { + "Date": "2022-06-05", + "Value": 96, + "Series": "Health" + }, + { + "Date": "2022-06-11", + "Value": 102, + "Series": "Health" + }, + { + "Date": "2022-06-16", + "Value": 103, + "Series": "Health" + }, + { + "Date": "2022-06-22", + "Value": 96, + "Series": "Health" + }, + { + "Date": "2022-06-27", + "Value": 87, + "Series": "Health" + }, + { + "Date": "2022-07-03", + "Value": 75, + "Series": "Health" + }, + { + "Date": "2022-07-08", + "Value": 62, + "Series": "Health" + }, + { + "Date": "2022-07-14", + "Value": 59, + "Series": "Health" + }, + { + "Date": "2022-07-19", + "Value": 53, + "Series": "Health" + }, + { + "Date": "2022-07-25", + "Value": 51, + "Series": "Health" + }, + { + "Date": "2022-07-30", + "Value": 57, + "Series": "Health" + }, + { + "Date": "2022-08-05", + "Value": 55, + "Series": "Health" + }, + { + "Date": "2022-08-10", + "Value": 59, + "Series": "Health" + }, + { + "Date": "2022-08-16", + "Value": 58, + "Series": "Health" + }, + { + "Date": "2022-08-21", + "Value": 57, + "Series": "Health" + }, + { + "Date": "2022-08-27", + "Value": 60, + "Series": "Health" + }, + { + "Date": "2022-09-01", + "Value": 56, + "Series": "Health" + }, + { + "Date": "2022-09-07", + "Value": 51, + "Series": "Health" + }, + { + "Date": "2022-09-12", + "Value": 47, + "Series": "Health" + }, + { + "Date": "2022-09-17", + "Value": 53, + "Series": "Health" + }, + { + "Date": "2022-09-23", + "Value": 50, + "Series": "Health" + }, + { + "Date": "2022-09-28", + "Value": 55, + "Series": "Health" + }, + { + "Date": "2022-10-04", + "Value": 62, + "Series": "Health" + }, + { + "Date": "2022-10-09", + "Value": 75, + "Series": "Health" + }, + { + "Date": "2022-10-15", + "Value": 86, + "Series": "Health" + }, + { + "Date": "2022-10-20", + "Value": 99, + "Series": "Health" + }, + { + "Date": "2022-10-26", + "Value": 108, + "Series": "Health" + }, + { + "Date": "2022-10-31", + "Value": 113, + "Series": "Health" + }, + { + "Date": "2022-11-06", + "Value": 122, + "Series": "Health" + }, + { + "Date": "2022-11-11", + "Value": 125, + "Series": "Health" + }, + { + "Date": "2022-11-17", + "Value": 126, + "Series": "Health" + }, + { + "Date": "2022-11-22", + "Value": 122, + "Series": "Health" + }, + { + "Date": "2022-11-28", + "Value": 118, + "Series": "Health" + }, + { + "Date": "2022-12-03", + "Value": 115, + "Series": "Health" + }, + { + "Date": "2022-12-09", + "Value": 117, + "Series": "Health" + }, + { + "Date": "2022-12-14", + "Value": 123, + "Series": "Health" + }, + { + "Date": "2022-12-20", + "Value": 122, + "Series": "Health" + }, + { + "Date": "2022-12-25", + "Value": 120, + "Series": "Health" + }, + { + "Date": "2020-01-01", + "Value": 113, + "Series": "Beauty" + }, + { + "Date": "2020-01-06", + "Value": 98, + "Series": "Beauty" + }, + { + "Date": "2020-01-11", + "Value": 96, + "Series": "Beauty" + }, + { + "Date": "2020-01-17", + "Value": 79, + "Series": "Beauty" + }, + { + "Date": "2020-01-22", + "Value": 53, + "Series": "Beauty" + }, + { + "Date": "2020-01-28", + "Value": 18, + "Series": "Beauty" + }, + { + "Date": "2020-02-02", + "Value": 2, + "Series": "Beauty" + }, + { + "Date": "2020-02-08", + "Value": 0, + "Series": "Beauty" + }, + { + "Date": "2020-02-13", + "Value": 0, + "Series": "Beauty" + }, + { + "Date": "2020-02-19", + "Value": 0, + "Series": "Beauty" + }, + { + "Date": "2020-02-24", + "Value": 0, + "Series": "Beauty" + }, + { + "Date": "2020-03-01", + "Value": 0, + "Series": "Beauty" + }, + { + "Date": "2020-03-06", + "Value": 7, + "Series": "Beauty" + }, + { + "Date": "2020-03-12", + "Value": 0, + "Series": "Beauty" + }, + { + "Date": "2020-03-17", + "Value": 0, + "Series": "Beauty" + }, + { + "Date": "2020-03-23", + "Value": 0, + "Series": "Beauty" + }, + { + "Date": "2020-03-28", + "Value": 0, + "Series": "Beauty" + }, + { + "Date": "2020-04-03", + "Value": 0, + "Series": "Beauty" + }, + { + "Date": "2020-04-08", + "Value": 0, + "Series": "Beauty" + }, + { + "Date": "2020-04-14", + "Value": 0, + "Series": "Beauty" + }, + { + "Date": "2020-04-19", + "Value": 0, + "Series": "Beauty" + }, + { + "Date": "2020-04-24", + "Value": 1, + "Series": "Beauty" + }, + { + "Date": "2020-04-30", + "Value": 11, + "Series": "Beauty" + }, + { + "Date": "2020-05-05", + "Value": 7, + "Series": "Beauty" + }, + { + "Date": "2020-05-11", + "Value": 0, + "Series": "Beauty" + }, + { + "Date": "2020-05-16", + "Value": 0, + "Series": "Beauty" + }, + { + "Date": "2020-05-22", + "Value": 0, + "Series": "Beauty" + }, + { + "Date": "2020-05-27", + "Value": 0, + "Series": "Beauty" + }, + { + "Date": "2020-06-02", + "Value": 0, + "Series": "Beauty" + }, + { + "Date": "2020-06-07", + "Value": 0, + "Series": "Beauty" + }, + { + "Date": "2020-06-13", + "Value": 0, + "Series": "Beauty" + }, + { + "Date": "2020-06-18", + "Value": 0, + "Series": "Beauty" + }, + { + "Date": "2020-06-24", + "Value": 0, + "Series": "Beauty" + }, + { + "Date": "2020-06-29", + "Value": 2, + "Series": "Beauty" + }, + { + "Date": "2020-07-05", + "Value": 0, + "Series": "Beauty" + }, + { + "Date": "2020-07-10", + "Value": 9, + "Series": "Beauty" + }, + { + "Date": "2020-07-16", + "Value": 13, + "Series": "Beauty" + }, + { + "Date": "2020-07-21", + "Value": 14, + "Series": "Beauty" + }, + { + "Date": "2020-07-27", + "Value": 8, + "Series": "Beauty" + }, + { + "Date": "2020-08-01", + "Value": 0, + "Series": "Beauty" + }, + { + "Date": "2020-08-07", + "Value": 3, + "Series": "Beauty" + }, + { + "Date": "2020-08-12", + "Value": 19, + "Series": "Beauty" + }, + { + "Date": "2020-08-17", + "Value": 18, + "Series": "Beauty" + }, + { + "Date": "2020-08-23", + "Value": 16, + "Series": "Beauty" + }, + { + "Date": "2020-08-28", + "Value": 7, + "Series": "Beauty" + }, + { + "Date": "2020-09-03", + "Value": 14, + "Series": "Beauty" + }, + { + "Date": "2020-09-08", + "Value": 5, + "Series": "Beauty" + }, + { + "Date": "2020-09-14", + "Value": 2, + "Series": "Beauty" + }, + { + "Date": "2020-09-19", + "Value": 9, + "Series": "Beauty" + }, + { + "Date": "2020-09-25", + "Value": 24, + "Series": "Beauty" + }, + { + "Date": "2020-09-30", + "Value": 41, + "Series": "Beauty" + }, + { + "Date": "2020-10-06", + "Value": 68, + "Series": "Beauty" + }, + { + "Date": "2020-10-11", + "Value": 88, + "Series": "Beauty" + }, + { + "Date": "2020-10-17", + "Value": 97, + "Series": "Beauty" + }, + { + "Date": "2020-10-22", + "Value": 107, + "Series": "Beauty" + }, + { + "Date": "2020-10-28", + "Value": 117, + "Series": "Beauty" + }, + { + "Date": "2020-11-02", + "Value": 138, + "Series": "Beauty" + }, + { + "Date": "2020-11-08", + "Value": 142, + "Series": "Beauty" + }, + { + "Date": "2020-11-13", + "Value": 140, + "Series": "Beauty" + }, + { + "Date": "2020-11-19", + "Value": 143, + "Series": "Beauty" + }, + { + "Date": "2020-11-24", + "Value": 144, + "Series": "Beauty" + }, + { + "Date": "2020-11-29", + "Value": 133, + "Series": "Beauty" + }, + { + "Date": "2020-12-05", + "Value": 138, + "Series": "Beauty" + }, + { + "Date": "2020-12-10", + "Value": 139, + "Series": "Beauty" + }, + { + "Date": "2020-12-16", + "Value": 141, + "Series": "Beauty" + }, + { + "Date": "2020-12-21", + "Value": 152, + "Series": "Beauty" + }, + { + "Date": "2020-12-27", + "Value": 168, + "Series": "Beauty" + }, + { + "Date": "2021-01-01", + "Value": 181, + "Series": "Beauty" + }, + { + "Date": "2021-01-07", + "Value": 192, + "Series": "Beauty" + }, + { + "Date": "2021-01-12", + "Value": 216, + "Series": "Beauty" + }, + { + "Date": "2021-01-18", + "Value": 240, + "Series": "Beauty" + }, + { + "Date": "2021-01-23", + "Value": 269, + "Series": "Beauty" + }, + { + "Date": "2021-01-29", + "Value": 296, + "Series": "Beauty" + }, + { + "Date": "2021-02-03", + "Value": 309, + "Series": "Beauty" + }, + { + "Date": "2021-02-09", + "Value": 330, + "Series": "Beauty" + }, + { + "Date": "2021-02-14", + "Value": 346, + "Series": "Beauty" + }, + { + "Date": "2021-02-20", + "Value": 343, + "Series": "Beauty" + }, + { + "Date": "2021-02-25", + "Value": 335, + "Series": "Beauty" + }, + { + "Date": "2021-03-03", + "Value": 341, + "Series": "Beauty" + }, + { + "Date": "2021-03-08", + "Value": 362, + "Series": "Beauty" + }, + { + "Date": "2021-03-14", + "Value": 390, + "Series": "Beauty" + }, + { + "Date": "2021-03-19", + "Value": 414, + "Series": "Beauty" + }, + { + "Date": "2021-03-24", + "Value": 424, + "Series": "Beauty" + }, + { + "Date": "2021-03-30", + "Value": 433, + "Series": "Beauty" + }, + { + "Date": "2021-04-04", + "Value": 433, + "Series": "Beauty" + }, + { + "Date": "2021-04-10", + "Value": 423, + "Series": "Beauty" + }, + { + "Date": "2021-04-15", + "Value": 429, + "Series": "Beauty" + }, + { + "Date": "2021-04-21", + "Value": 428, + "Series": "Beauty" + }, + { + "Date": "2021-04-26", + "Value": 416, + "Series": "Beauty" + }, + { + "Date": "2021-05-02", + "Value": 392, + "Series": "Beauty" + }, + { + "Date": "2021-05-07", + "Value": 371, + "Series": "Beauty" + }, + { + "Date": "2021-05-13", + "Value": 340, + "Series": "Beauty" + }, + { + "Date": "2021-05-18", + "Value": 330, + "Series": "Beauty" + }, + { + "Date": "2021-05-24", + "Value": 312, + "Series": "Beauty" + }, + { + "Date": "2021-05-29", + "Value": 292, + "Series": "Beauty" + }, + { + "Date": "2021-06-04", + "Value": 272, + "Series": "Beauty" + }, + { + "Date": "2021-06-09", + "Value": 259, + "Series": "Beauty" + }, + { + "Date": "2021-06-15", + "Value": 255, + "Series": "Beauty" + }, + { + "Date": "2021-06-20", + "Value": 260, + "Series": "Beauty" + }, + { + "Date": "2021-06-26", + "Value": 277, + "Series": "Beauty" + }, + { + "Date": "2021-07-01", + "Value": 301, + "Series": "Beauty" + }, + { + "Date": "2021-07-06", + "Value": 333, + "Series": "Beauty" + }, + { + "Date": "2021-07-12", + "Value": 368, + "Series": "Beauty" + }, + { + "Date": "2021-07-17", + "Value": 401, + "Series": "Beauty" + }, + { + "Date": "2021-07-23", + "Value": 411, + "Series": "Beauty" + }, + { + "Date": "2021-07-28", + "Value": 413, + "Series": "Beauty" + }, + { + "Date": "2021-08-03", + "Value": 426, + "Series": "Beauty" + }, + { + "Date": "2021-08-08", + "Value": 421, + "Series": "Beauty" + }, + { + "Date": "2021-08-14", + "Value": 432, + "Series": "Beauty" + }, + { + "Date": "2021-08-19", + "Value": 441, + "Series": "Beauty" + }, + { + "Date": "2021-08-25", + "Value": 444, + "Series": "Beauty" + }, + { + "Date": "2021-08-30", + "Value": 453, + "Series": "Beauty" + }, + { + "Date": "2021-09-05", + "Value": 459, + "Series": "Beauty" + }, + { + "Date": "2021-09-10", + "Value": 448, + "Series": "Beauty" + }, + { + "Date": "2021-09-16", + "Value": 437, + "Series": "Beauty" + }, + { + "Date": "2021-09-21", + "Value": 413, + "Series": "Beauty" + }, + { + "Date": "2021-09-27", + "Value": 412, + "Series": "Beauty" + }, + { + "Date": "2021-10-02", + "Value": 413, + "Series": "Beauty" + }, + { + "Date": "2021-10-08", + "Value": 408, + "Series": "Beauty" + }, + { + "Date": "2021-10-13", + "Value": 402, + "Series": "Beauty" + }, + { + "Date": "2021-10-19", + "Value": 406, + "Series": "Beauty" + }, + { + "Date": "2021-10-24", + "Value": 397, + "Series": "Beauty" + }, + { + "Date": "2021-10-29", + "Value": 398, + "Series": "Beauty" + }, + { + "Date": "2021-11-04", + "Value": 415, + "Series": "Beauty" + }, + { + "Date": "2021-11-09", + "Value": 413, + "Series": "Beauty" + }, + { + "Date": "2021-11-15", + "Value": 410, + "Series": "Beauty" + }, + { + "Date": "2021-11-20", + "Value": 406, + "Series": "Beauty" + }, + { + "Date": "2021-11-26", + "Value": 393, + "Series": "Beauty" + }, + { + "Date": "2021-12-01", + "Value": 379, + "Series": "Beauty" + }, + { + "Date": "2021-12-07", + "Value": 374, + "Series": "Beauty" + }, + { + "Date": "2021-12-12", + "Value": 384, + "Series": "Beauty" + }, + { + "Date": "2021-12-18", + "Value": 398, + "Series": "Beauty" + }, + { + "Date": "2021-12-23", + "Value": 402, + "Series": "Beauty" + }, + { + "Date": "2021-12-29", + "Value": 404, + "Series": "Beauty" + }, + { + "Date": "2022-01-03", + "Value": 400, + "Series": "Beauty" + }, + { + "Date": "2022-01-09", + "Value": 390, + "Series": "Beauty" + }, + { + "Date": "2022-01-14", + "Value": 393, + "Series": "Beauty" + }, + { + "Date": "2022-01-20", + "Value": 403, + "Series": "Beauty" + }, + { + "Date": "2022-01-25", + "Value": 411, + "Series": "Beauty" + }, + { + "Date": "2022-01-31", + "Value": 415, + "Series": "Beauty" + }, + { + "Date": "2022-02-05", + "Value": 404, + "Series": "Beauty" + }, + { + "Date": "2022-02-10", + "Value": 390, + "Series": "Beauty" + }, + { + "Date": "2022-02-16", + "Value": 396, + "Series": "Beauty" + }, + { + "Date": "2022-02-21", + "Value": 397, + "Series": "Beauty" + }, + { + "Date": "2022-02-27", + "Value": 385, + "Series": "Beauty" + }, + { + "Date": "2022-03-04", + "Value": 374, + "Series": "Beauty" + }, + { + "Date": "2022-03-10", + "Value": 355, + "Series": "Beauty" + }, + { + "Date": "2022-03-15", + "Value": 329, + "Series": "Beauty" + }, + { + "Date": "2022-03-21", + "Value": 315, + "Series": "Beauty" + }, + { + "Date": "2022-03-26", + "Value": 291, + "Series": "Beauty" + }, + { + "Date": "2022-04-01", + "Value": 264, + "Series": "Beauty" + }, + { + "Date": "2022-04-06", + "Value": 228, + "Series": "Beauty" + }, + { + "Date": "2022-04-12", + "Value": 195, + "Series": "Beauty" + }, + { + "Date": "2022-04-17", + "Value": 162, + "Series": "Beauty" + }, + { + "Date": "2022-04-23", + "Value": 138, + "Series": "Beauty" + }, + { + "Date": "2022-04-28", + "Value": 120, + "Series": "Beauty" + }, + { + "Date": "2022-05-04", + "Value": 123, + "Series": "Beauty" + }, + { + "Date": "2022-05-09", + "Value": 115, + "Series": "Beauty" + }, + { + "Date": "2022-05-15", + "Value": 107, + "Series": "Beauty" + }, + { + "Date": "2022-05-20", + "Value": 94, + "Series": "Beauty" + }, + { + "Date": "2022-05-26", + "Value": 94, + "Series": "Beauty" + }, + { + "Date": "2022-05-31", + "Value": 88, + "Series": "Beauty" + }, + { + "Date": "2022-06-05", + "Value": 76, + "Series": "Beauty" + }, + { + "Date": "2022-06-11", + "Value": 83, + "Series": "Beauty" + }, + { + "Date": "2022-06-16", + "Value": 84, + "Series": "Beauty" + }, + { + "Date": "2022-06-22", + "Value": 77, + "Series": "Beauty" + }, + { + "Date": "2022-06-27", + "Value": 82, + "Series": "Beauty" + }, + { + "Date": "2022-07-03", + "Value": 86, + "Series": "Beauty" + }, + { + "Date": "2022-07-08", + "Value": 103, + "Series": "Beauty" + }, + { + "Date": "2022-07-14", + "Value": 101, + "Series": "Beauty" + }, + { + "Date": "2022-07-19", + "Value": 116, + "Series": "Beauty" + }, + { + "Date": "2022-07-25", + "Value": 142, + "Series": "Beauty" + }, + { + "Date": "2022-07-30", + "Value": 168, + "Series": "Beauty" + }, + { + "Date": "2022-08-05", + "Value": 196, + "Series": "Beauty" + }, + { + "Date": "2022-08-10", + "Value": 221, + "Series": "Beauty" + }, + { + "Date": "2022-08-16", + "Value": 253, + "Series": "Beauty" + }, + { + "Date": "2022-08-21", + "Value": 260, + "Series": "Beauty" + }, + { + "Date": "2022-08-27", + "Value": 253, + "Series": "Beauty" + }, + { + "Date": "2022-09-01", + "Value": 263, + "Series": "Beauty" + }, + { + "Date": "2022-09-07", + "Value": 258, + "Series": "Beauty" + }, + { + "Date": "2022-09-12", + "Value": 263, + "Series": "Beauty" + }, + { + "Date": "2022-09-17", + "Value": 257, + "Series": "Beauty" + }, + { + "Date": "2022-09-23", + "Value": 250, + "Series": "Beauty" + }, + { + "Date": "2022-09-28", + "Value": 249, + "Series": "Beauty" + }, + { + "Date": "2022-10-04", + "Value": 260, + "Series": "Beauty" + }, + { + "Date": "2022-10-09", + "Value": 274, + "Series": "Beauty" + }, + { + "Date": "2022-10-15", + "Value": 285, + "Series": "Beauty" + }, + { + "Date": "2022-10-20", + "Value": 305, + "Series": "Beauty" + }, + { + "Date": "2022-10-26", + "Value": 326, + "Series": "Beauty" + }, + { + "Date": "2022-10-31", + "Value": 327, + "Series": "Beauty" + }, + { + "Date": "2022-11-06", + "Value": 343, + "Series": "Beauty" + }, + { + "Date": "2022-11-11", + "Value": 347, + "Series": "Beauty" + }, + { + "Date": "2022-11-17", + "Value": 334, + "Series": "Beauty" + }, + { + "Date": "2022-11-22", + "Value": 316, + "Series": "Beauty" + }, + { + "Date": "2022-11-28", + "Value": 293, + "Series": "Beauty" + }, + { + "Date": "2022-12-03", + "Value": 275, + "Series": "Beauty" + }, + { + "Date": "2022-12-09", + "Value": 248, + "Series": "Beauty" + }, + { + "Date": "2022-12-14", + "Value": 216, + "Series": "Beauty" + }, + { + "Date": "2022-12-20", + "Value": 186, + "Series": "Beauty" + }, + { + "Date": "2022-12-25", + "Value": 163, + "Series": "Beauty" + }, + { + "Date": "2020-01-01", + "Value": 74, + "Series": "Toys" + }, + { + "Date": "2020-01-06", + "Value": 74, + "Series": "Toys" + }, + { + "Date": "2020-01-11", + "Value": 70, + "Series": "Toys" + }, + { + "Date": "2020-01-17", + "Value": 64, + "Series": "Toys" + }, + { + "Date": "2020-01-22", + "Value": 64, + "Series": "Toys" + }, + { + "Date": "2020-01-28", + "Value": 62, + "Series": "Toys" + }, + { + "Date": "2020-02-02", + "Value": 70, + "Series": "Toys" + }, + { + "Date": "2020-02-08", + "Value": 86, + "Series": "Toys" + }, + { + "Date": "2020-02-13", + "Value": 87, + "Series": "Toys" + }, + { + "Date": "2020-02-19", + "Value": 81, + "Series": "Toys" + }, + { + "Date": "2020-02-24", + "Value": 76, + "Series": "Toys" + }, + { + "Date": "2020-03-01", + "Value": 70, + "Series": "Toys" + }, + { + "Date": "2020-03-06", + "Value": 73, + "Series": "Toys" + }, + { + "Date": "2020-03-12", + "Value": 79, + "Series": "Toys" + }, + { + "Date": "2020-03-17", + "Value": 75, + "Series": "Toys" + }, + { + "Date": "2020-03-23", + "Value": 72, + "Series": "Toys" + }, + { + "Date": "2020-03-28", + "Value": 60, + "Series": "Toys" + }, + { + "Date": "2020-04-03", + "Value": 57, + "Series": "Toys" + }, + { + "Date": "2020-04-08", + "Value": 64, + "Series": "Toys" + }, + { + "Date": "2020-04-14", + "Value": 63, + "Series": "Toys" + }, + { + "Date": "2020-04-19", + "Value": 68, + "Series": "Toys" + }, + { + "Date": "2020-04-24", + "Value": 71, + "Series": "Toys" + }, + { + "Date": "2020-04-30", + "Value": 73, + "Series": "Toys" + }, + { + "Date": "2020-05-05", + "Value": 72, + "Series": "Toys" + }, + { + "Date": "2020-05-11", + "Value": 75, + "Series": "Toys" + }, + { + "Date": "2020-05-16", + "Value": 87, + "Series": "Toys" + }, + { + "Date": "2020-05-22", + "Value": 89, + "Series": "Toys" + }, + { + "Date": "2020-05-27", + "Value": 83, + "Series": "Toys" + }, + { + "Date": "2020-06-02", + "Value": 77, + "Series": "Toys" + }, + { + "Date": "2020-06-07", + "Value": 70, + "Series": "Toys" + }, + { + "Date": "2020-06-13", + "Value": 62, + "Series": "Toys" + }, + { + "Date": "2020-06-18", + "Value": 62, + "Series": "Toys" + }, + { + "Date": "2020-06-24", + "Value": 68, + "Series": "Toys" + }, + { + "Date": "2020-06-29", + "Value": 64, + "Series": "Toys" + }, + { + "Date": "2020-07-05", + "Value": 60, + "Series": "Toys" + }, + { + "Date": "2020-07-10", + "Value": 61, + "Series": "Toys" + }, + { + "Date": "2020-07-16", + "Value": 72, + "Series": "Toys" + }, + { + "Date": "2020-07-21", + "Value": 74, + "Series": "Toys" + }, + { + "Date": "2020-07-27", + "Value": 83, + "Series": "Toys" + }, + { + "Date": "2020-08-01", + "Value": 80, + "Series": "Toys" + }, + { + "Date": "2020-08-07", + "Value": 76, + "Series": "Toys" + }, + { + "Date": "2020-08-12", + "Value": 79, + "Series": "Toys" + }, + { + "Date": "2020-08-17", + "Value": 77, + "Series": "Toys" + }, + { + "Date": "2020-08-23", + "Value": 80, + "Series": "Toys" + }, + { + "Date": "2020-08-28", + "Value": 88, + "Series": "Toys" + }, + { + "Date": "2020-09-03", + "Value": 96, + "Series": "Toys" + }, + { + "Date": "2020-09-08", + "Value": 98, + "Series": "Toys" + }, + { + "Date": "2020-09-14", + "Value": 95, + "Series": "Toys" + }, + { + "Date": "2020-09-19", + "Value": 97, + "Series": "Toys" + }, + { + "Date": "2020-09-25", + "Value": 107, + "Series": "Toys" + }, + { + "Date": "2020-09-30", + "Value": 114, + "Series": "Toys" + }, + { + "Date": "2020-10-06", + "Value": 122, + "Series": "Toys" + }, + { + "Date": "2020-10-11", + "Value": 126, + "Series": "Toys" + }, + { + "Date": "2020-10-17", + "Value": 131, + "Series": "Toys" + }, + { + "Date": "2020-10-22", + "Value": 133, + "Series": "Toys" + }, + { + "Date": "2020-10-28", + "Value": 137, + "Series": "Toys" + }, + { + "Date": "2020-11-02", + "Value": 138, + "Series": "Toys" + }, + { + "Date": "2020-11-08", + "Value": 134, + "Series": "Toys" + }, + { + "Date": "2020-11-13", + "Value": 128, + "Series": "Toys" + }, + { + "Date": "2020-11-19", + "Value": 131, + "Series": "Toys" + }, + { + "Date": "2020-11-24", + "Value": 141, + "Series": "Toys" + }, + { + "Date": "2020-11-29", + "Value": 155, + "Series": "Toys" + }, + { + "Date": "2020-12-05", + "Value": 169, + "Series": "Toys" + }, + { + "Date": "2020-12-10", + "Value": 181, + "Series": "Toys" + }, + { + "Date": "2020-12-16", + "Value": 183, + "Series": "Toys" + }, + { + "Date": "2020-12-21", + "Value": 179, + "Series": "Toys" + }, + { + "Date": "2020-12-27", + "Value": 184, + "Series": "Toys" + }, + { + "Date": "2021-01-01", + "Value": 184, + "Series": "Toys" + }, + { + "Date": "2021-01-07", + "Value": 194, + "Series": "Toys" + }, + { + "Date": "2021-01-12", + "Value": 208, + "Series": "Toys" + }, + { + "Date": "2021-01-18", + "Value": 227, + "Series": "Toys" + }, + { + "Date": "2021-01-23", + "Value": 244, + "Series": "Toys" + }, + { + "Date": "2021-01-29", + "Value": 254, + "Series": "Toys" + }, + { + "Date": "2021-02-03", + "Value": 262, + "Series": "Toys" + }, + { + "Date": "2021-02-09", + "Value": 276, + "Series": "Toys" + }, + { + "Date": "2021-02-14", + "Value": 291, + "Series": "Toys" + }, + { + "Date": "2021-02-20", + "Value": 292, + "Series": "Toys" + }, + { + "Date": "2021-02-25", + "Value": 299, + "Series": "Toys" + }, + { + "Date": "2021-03-03", + "Value": 299, + "Series": "Toys" + }, + { + "Date": "2021-03-08", + "Value": 292, + "Series": "Toys" + }, + { + "Date": "2021-03-14", + "Value": 285, + "Series": "Toys" + }, + { + "Date": "2021-03-19", + "Value": 271, + "Series": "Toys" + }, + { + "Date": "2021-03-24", + "Value": 253, + "Series": "Toys" + }, + { + "Date": "2021-03-30", + "Value": 248, + "Series": "Toys" + }, + { + "Date": "2021-04-04", + "Value": 239, + "Series": "Toys" + }, + { + "Date": "2021-04-10", + "Value": 240, + "Series": "Toys" + }, + { + "Date": "2021-04-15", + "Value": 239, + "Series": "Toys" + }, + { + "Date": "2021-04-21", + "Value": 229, + "Series": "Toys" + }, + { + "Date": "2021-04-26", + "Value": 232, + "Series": "Toys" + }, + { + "Date": "2021-05-02", + "Value": 228, + "Series": "Toys" + }, + { + "Date": "2021-05-07", + "Value": 221, + "Series": "Toys" + }, + { + "Date": "2021-05-13", + "Value": 213, + "Series": "Toys" + }, + { + "Date": "2021-05-18", + "Value": 199, + "Series": "Toys" + }, + { + "Date": "2021-05-24", + "Value": 181, + "Series": "Toys" + }, + { + "Date": "2021-05-29", + "Value": 172, + "Series": "Toys" + }, + { + "Date": "2021-06-04", + "Value": 162, + "Series": "Toys" + }, + { + "Date": "2021-06-09", + "Value": 153, + "Series": "Toys" + }, + { + "Date": "2021-06-15", + "Value": 148, + "Series": "Toys" + }, + { + "Date": "2021-06-20", + "Value": 147, + "Series": "Toys" + }, + { + "Date": "2021-06-26", + "Value": 140, + "Series": "Toys" + }, + { + "Date": "2021-07-01", + "Value": 137, + "Series": "Toys" + }, + { + "Date": "2021-07-06", + "Value": 125, + "Series": "Toys" + }, + { + "Date": "2021-07-12", + "Value": 107, + "Series": "Toys" + }, + { + "Date": "2021-07-17", + "Value": 99, + "Series": "Toys" + }, + { + "Date": "2021-07-23", + "Value": 90, + "Series": "Toys" + }, + { + "Date": "2021-07-28", + "Value": 83, + "Series": "Toys" + }, + { + "Date": "2021-08-03", + "Value": 72, + "Series": "Toys" + }, + { + "Date": "2021-08-08", + "Value": 62, + "Series": "Toys" + }, + { + "Date": "2021-08-14", + "Value": 65, + "Series": "Toys" + }, + { + "Date": "2021-08-19", + "Value": 63, + "Series": "Toys" + }, + { + "Date": "2021-08-25", + "Value": 59, + "Series": "Toys" + }, + { + "Date": "2021-08-30", + "Value": 52, + "Series": "Toys" + }, + { + "Date": "2021-09-05", + "Value": 40, + "Series": "Toys" + }, + { + "Date": "2021-09-10", + "Value": 29, + "Series": "Toys" + }, + { + "Date": "2021-09-16", + "Value": 19, + "Series": "Toys" + }, + { + "Date": "2021-09-21", + "Value": 14, + "Series": "Toys" + }, + { + "Date": "2021-09-27", + "Value": 11, + "Series": "Toys" + }, + { + "Date": "2021-10-02", + "Value": 0, + "Series": "Toys" + }, + { + "Date": "2021-10-08", + "Value": 0, + "Series": "Toys" + }, + { + "Date": "2021-10-13", + "Value": 0, + "Series": "Toys" + }, + { + "Date": "2021-10-19", + "Value": 0, + "Series": "Toys" + }, + { + "Date": "2021-10-24", + "Value": 0, + "Series": "Toys" + }, + { + "Date": "2021-10-29", + "Value": 5, + "Series": "Toys" + }, + { + "Date": "2021-11-04", + "Value": 5, + "Series": "Toys" + }, + { + "Date": "2021-11-09", + "Value": 14, + "Series": "Toys" + }, + { + "Date": "2021-11-15", + "Value": 20, + "Series": "Toys" + }, + { + "Date": "2021-11-20", + "Value": 34, + "Series": "Toys" + }, + { + "Date": "2021-11-26", + "Value": 38, + "Series": "Toys" + }, + { + "Date": "2021-12-01", + "Value": 47, + "Series": "Toys" + }, + { + "Date": "2021-12-07", + "Value": 51, + "Series": "Toys" + }, + { + "Date": "2021-12-12", + "Value": 59, + "Series": "Toys" + }, + { + "Date": "2021-12-18", + "Value": 65, + "Series": "Toys" + }, + { + "Date": "2021-12-23", + "Value": 77, + "Series": "Toys" + }, + { + "Date": "2021-12-29", + "Value": 80, + "Series": "Toys" + }, + { + "Date": "2022-01-03", + "Value": 87, + "Series": "Toys" + }, + { + "Date": "2022-01-09", + "Value": 87, + "Series": "Toys" + }, + { + "Date": "2022-01-14", + "Value": 97, + "Series": "Toys" + }, + { + "Date": "2022-01-20", + "Value": 96, + "Series": "Toys" + }, + { + "Date": "2022-01-25", + "Value": 97, + "Series": "Toys" + }, + { + "Date": "2022-01-31", + "Value": 102, + "Series": "Toys" + }, + { + "Date": "2022-02-05", + "Value": 95, + "Series": "Toys" + }, + { + "Date": "2022-02-10", + "Value": 94, + "Series": "Toys" + }, + { + "Date": "2022-02-16", + "Value": 87, + "Series": "Toys" + }, + { + "Date": "2022-02-21", + "Value": 86, + "Series": "Toys" + }, + { + "Date": "2022-02-27", + "Value": 93, + "Series": "Toys" + }, + { + "Date": "2022-03-04", + "Value": 105, + "Series": "Toys" + }, + { + "Date": "2022-03-10", + "Value": 114, + "Series": "Toys" + }, + { + "Date": "2022-03-15", + "Value": 128, + "Series": "Toys" + }, + { + "Date": "2022-03-21", + "Value": 141, + "Series": "Toys" + }, + { + "Date": "2022-03-26", + "Value": 155, + "Series": "Toys" + }, + { + "Date": "2022-04-01", + "Value": 172, + "Series": "Toys" + }, + { + "Date": "2022-04-06", + "Value": 179, + "Series": "Toys" + }, + { + "Date": "2022-04-12", + "Value": 182, + "Series": "Toys" + }, + { + "Date": "2022-04-17", + "Value": 183, + "Series": "Toys" + }, + { + "Date": "2022-04-23", + "Value": 178, + "Series": "Toys" + }, + { + "Date": "2022-04-28", + "Value": 174, + "Series": "Toys" + }, + { + "Date": "2022-05-04", + "Value": 179, + "Series": "Toys" + }, + { + "Date": "2022-05-09", + "Value": 174, + "Series": "Toys" + }, + { + "Date": "2022-05-15", + "Value": 179, + "Series": "Toys" + }, + { + "Date": "2022-05-20", + "Value": 187, + "Series": "Toys" + }, + { + "Date": "2022-05-26", + "Value": 196, + "Series": "Toys" + }, + { + "Date": "2022-05-31", + "Value": 206, + "Series": "Toys" + }, + { + "Date": "2022-06-05", + "Value": 217, + "Series": "Toys" + }, + { + "Date": "2022-06-11", + "Value": 234, + "Series": "Toys" + }, + { + "Date": "2022-06-16", + "Value": 238, + "Series": "Toys" + }, + { + "Date": "2022-06-22", + "Value": 245, + "Series": "Toys" + }, + { + "Date": "2022-06-27", + "Value": 245, + "Series": "Toys" + }, + { + "Date": "2022-07-03", + "Value": 254, + "Series": "Toys" + }, + { + "Date": "2022-07-08", + "Value": 267, + "Series": "Toys" + }, + { + "Date": "2022-07-14", + "Value": 267, + "Series": "Toys" + }, + { + "Date": "2022-07-19", + "Value": 275, + "Series": "Toys" + }, + { + "Date": "2022-07-25", + "Value": 272, + "Series": "Toys" + }, + { + "Date": "2022-07-30", + "Value": 270, + "Series": "Toys" + }, + { + "Date": "2022-08-05", + "Value": 267, + "Series": "Toys" + }, + { + "Date": "2022-08-10", + "Value": 270, + "Series": "Toys" + }, + { + "Date": "2022-08-16", + "Value": 266, + "Series": "Toys" + }, + { + "Date": "2022-08-21", + "Value": 257, + "Series": "Toys" + }, + { + "Date": "2022-08-27", + "Value": 244, + "Series": "Toys" + }, + { + "Date": "2022-09-01", + "Value": 228, + "Series": "Toys" + }, + { + "Date": "2022-09-07", + "Value": 222, + "Series": "Toys" + }, + { + "Date": "2022-09-12", + "Value": 210, + "Series": "Toys" + }, + { + "Date": "2022-09-17", + "Value": 193, + "Series": "Toys" + }, + { + "Date": "2022-09-23", + "Value": 188, + "Series": "Toys" + }, + { + "Date": "2022-09-28", + "Value": 180, + "Series": "Toys" + }, + { + "Date": "2022-10-04", + "Value": 178, + "Series": "Toys" + }, + { + "Date": "2022-10-09", + "Value": 183, + "Series": "Toys" + }, + { + "Date": "2022-10-15", + "Value": 188, + "Series": "Toys" + }, + { + "Date": "2022-10-20", + "Value": 182, + "Series": "Toys" + }, + { + "Date": "2022-10-26", + "Value": 186, + "Series": "Toys" + }, + { + "Date": "2022-10-31", + "Value": 185, + "Series": "Toys" + }, + { + "Date": "2022-11-06", + "Value": 179, + "Series": "Toys" + }, + { + "Date": "2022-11-11", + "Value": 166, + "Series": "Toys" + }, + { + "Date": "2022-11-17", + "Value": 158, + "Series": "Toys" + }, + { + "Date": "2022-11-22", + "Value": 161, + "Series": "Toys" + }, + { + "Date": "2022-11-28", + "Value": 169, + "Series": "Toys" + }, + { + "Date": "2022-12-03", + "Value": 174, + "Series": "Toys" + }, + { + "Date": "2022-12-09", + "Value": 168, + "Series": "Toys" + }, + { + "Date": "2022-12-14", + "Value": 174, + "Series": "Toys" + }, + { + "Date": "2022-12-20", + "Value": 182, + "Series": "Toys" + }, + { + "Date": "2022-12-25", + "Value": 190, + "Series": "Toys" + }, + { + "Date": "2020-01-01", + "Value": 206, + "Series": "Music" + }, + { + "Date": "2020-01-06", + "Value": 197, + "Series": "Music" + }, + { + "Date": "2020-01-11", + "Value": 196, + "Series": "Music" + }, + { + "Date": "2020-01-17", + "Value": 199, + "Series": "Music" + }, + { + "Date": "2020-01-22", + "Value": 208, + "Series": "Music" + }, + { + "Date": "2020-01-28", + "Value": 217, + "Series": "Music" + }, + { + "Date": "2020-02-02", + "Value": 228, + "Series": "Music" + }, + { + "Date": "2020-02-08", + "Value": 245, + "Series": "Music" + }, + { + "Date": "2020-02-13", + "Value": 253, + "Series": "Music" + }, + { + "Date": "2020-02-19", + "Value": 252, + "Series": "Music" + }, + { + "Date": "2020-02-24", + "Value": 255, + "Series": "Music" + }, + { + "Date": "2020-03-01", + "Value": 263, + "Series": "Music" + }, + { + "Date": "2020-03-06", + "Value": 261, + "Series": "Music" + }, + { + "Date": "2020-03-12", + "Value": 253, + "Series": "Music" + }, + { + "Date": "2020-03-17", + "Value": 251, + "Series": "Music" + }, + { + "Date": "2020-03-23", + "Value": 245, + "Series": "Music" + }, + { + "Date": "2020-03-28", + "Value": 243, + "Series": "Music" + }, + { + "Date": "2020-04-03", + "Value": 245, + "Series": "Music" + }, + { + "Date": "2020-04-08", + "Value": 247, + "Series": "Music" + }, + { + "Date": "2020-04-14", + "Value": 243, + "Series": "Music" + }, + { + "Date": "2020-04-19", + "Value": 249, + "Series": "Music" + }, + { + "Date": "2020-04-24", + "Value": 259, + "Series": "Music" + }, + { + "Date": "2020-04-30", + "Value": 265, + "Series": "Music" + }, + { + "Date": "2020-05-05", + "Value": 276, + "Series": "Music" + }, + { + "Date": "2020-05-11", + "Value": 281, + "Series": "Music" + }, + { + "Date": "2020-05-16", + "Value": 292, + "Series": "Music" + }, + { + "Date": "2020-05-22", + "Value": 291, + "Series": "Music" + }, + { + "Date": "2020-05-27", + "Value": 287, + "Series": "Music" + }, + { + "Date": "2020-06-02", + "Value": 291, + "Series": "Music" + }, + { + "Date": "2020-06-07", + "Value": 289, + "Series": "Music" + }, + { + "Date": "2020-06-13", + "Value": 285, + "Series": "Music" + }, + { + "Date": "2020-06-18", + "Value": 280, + "Series": "Music" + }, + { + "Date": "2020-06-24", + "Value": 269, + "Series": "Music" + }, + { + "Date": "2020-06-29", + "Value": 252, + "Series": "Music" + }, + { + "Date": "2020-07-05", + "Value": 232, + "Series": "Music" + }, + { + "Date": "2020-07-10", + "Value": 213, + "Series": "Music" + }, + { + "Date": "2020-07-16", + "Value": 194, + "Series": "Music" + }, + { + "Date": "2020-07-21", + "Value": 175, + "Series": "Music" + }, + { + "Date": "2020-07-27", + "Value": 163, + "Series": "Music" + }, + { + "Date": "2020-08-01", + "Value": 149, + "Series": "Music" + }, + { + "Date": "2020-08-07", + "Value": 131, + "Series": "Music" + }, + { + "Date": "2020-08-12", + "Value": 122, + "Series": "Music" + }, + { + "Date": "2020-08-17", + "Value": 108, + "Series": "Music" + }, + { + "Date": "2020-08-23", + "Value": 99, + "Series": "Music" + }, + { + "Date": "2020-08-28", + "Value": 95, + "Series": "Music" + }, + { + "Date": "2020-09-03", + "Value": 93, + "Series": "Music" + }, + { + "Date": "2020-09-08", + "Value": 94, + "Series": "Music" + }, + { + "Date": "2020-09-14", + "Value": 97, + "Series": "Music" + }, + { + "Date": "2020-09-19", + "Value": 97, + "Series": "Music" + }, + { + "Date": "2020-09-25", + "Value": 105, + "Series": "Music" + }, + { + "Date": "2020-09-30", + "Value": 117, + "Series": "Music" + }, + { + "Date": "2020-10-06", + "Value": 121, + "Series": "Music" + }, + { + "Date": "2020-10-11", + "Value": 120, + "Series": "Music" + }, + { + "Date": "2020-10-17", + "Value": 125, + "Series": "Music" + }, + { + "Date": "2020-10-22", + "Value": 131, + "Series": "Music" + }, + { + "Date": "2020-10-28", + "Value": 127, + "Series": "Music" + }, + { + "Date": "2020-11-02", + "Value": 120, + "Series": "Music" + }, + { + "Date": "2020-11-08", + "Value": 109, + "Series": "Music" + }, + { + "Date": "2020-11-13", + "Value": 107, + "Series": "Music" + }, + { + "Date": "2020-11-19", + "Value": 108, + "Series": "Music" + }, + { + "Date": "2020-11-24", + "Value": 103, + "Series": "Music" + }, + { + "Date": "2020-11-29", + "Value": 94, + "Series": "Music" + }, + { + "Date": "2020-12-05", + "Value": 86, + "Series": "Music" + }, + { + "Date": "2020-12-10", + "Value": 75, + "Series": "Music" + }, + { + "Date": "2020-12-16", + "Value": 61, + "Series": "Music" + }, + { + "Date": "2020-12-21", + "Value": 49, + "Series": "Music" + }, + { + "Date": "2020-12-27", + "Value": 36, + "Series": "Music" + }, + { + "Date": "2021-01-01", + "Value": 29, + "Series": "Music" + }, + { + "Date": "2021-01-07", + "Value": 29, + "Series": "Music" + }, + { + "Date": "2021-01-12", + "Value": 37, + "Series": "Music" + }, + { + "Date": "2021-01-18", + "Value": 40, + "Series": "Music" + }, + { + "Date": "2021-01-23", + "Value": 42, + "Series": "Music" + }, + { + "Date": "2021-01-29", + "Value": 41, + "Series": "Music" + }, + { + "Date": "2021-02-03", + "Value": 44, + "Series": "Music" + }, + { + "Date": "2021-02-09", + "Value": 41, + "Series": "Music" + }, + { + "Date": "2021-02-14", + "Value": 46, + "Series": "Music" + }, + { + "Date": "2021-02-20", + "Value": 46, + "Series": "Music" + }, + { + "Date": "2021-02-25", + "Value": 50, + "Series": "Music" + }, + { + "Date": "2021-03-03", + "Value": 54, + "Series": "Music" + }, + { + "Date": "2021-03-08", + "Value": 59, + "Series": "Music" + }, + { + "Date": "2021-03-14", + "Value": 62, + "Series": "Music" + }, + { + "Date": "2021-03-19", + "Value": 57, + "Series": "Music" + }, + { + "Date": "2021-03-24", + "Value": 56, + "Series": "Music" + }, + { + "Date": "2021-03-30", + "Value": 57, + "Series": "Music" + }, + { + "Date": "2021-04-04", + "Value": 50, + "Series": "Music" + }, + { + "Date": "2021-04-10", + "Value": 48, + "Series": "Music" + }, + { + "Date": "2021-04-15", + "Value": 42, + "Series": "Music" + }, + { + "Date": "2021-04-21", + "Value": 39, + "Series": "Music" + }, + { + "Date": "2021-04-26", + "Value": 42, + "Series": "Music" + }, + { + "Date": "2021-05-02", + "Value": 47, + "Series": "Music" + }, + { + "Date": "2021-05-07", + "Value": 58, + "Series": "Music" + }, + { + "Date": "2021-05-13", + "Value": 63, + "Series": "Music" + }, + { + "Date": "2021-05-18", + "Value": 73, + "Series": "Music" + }, + { + "Date": "2021-05-24", + "Value": 84, + "Series": "Music" + }, + { + "Date": "2021-05-29", + "Value": 87, + "Series": "Music" + }, + { + "Date": "2021-06-04", + "Value": 96, + "Series": "Music" + }, + { + "Date": "2021-06-09", + "Value": 104, + "Series": "Music" + }, + { + "Date": "2021-06-15", + "Value": 104, + "Series": "Music" + }, + { + "Date": "2021-06-20", + "Value": 112, + "Series": "Music" + }, + { + "Date": "2021-06-26", + "Value": 109, + "Series": "Music" + }, + { + "Date": "2021-07-01", + "Value": 106, + "Series": "Music" + }, + { + "Date": "2021-07-06", + "Value": 107, + "Series": "Music" + }, + { + "Date": "2021-07-12", + "Value": 110, + "Series": "Music" + }, + { + "Date": "2021-07-17", + "Value": 115, + "Series": "Music" + }, + { + "Date": "2021-07-23", + "Value": 117, + "Series": "Music" + }, + { + "Date": "2021-07-28", + "Value": 127, + "Series": "Music" + }, + { + "Date": "2021-08-03", + "Value": 127, + "Series": "Music" + }, + { + "Date": "2021-08-08", + "Value": 130, + "Series": "Music" + }, + { + "Date": "2021-08-14", + "Value": 132, + "Series": "Music" + }, + { + "Date": "2021-08-19", + "Value": 136, + "Series": "Music" + }, + { + "Date": "2021-08-25", + "Value": 135, + "Series": "Music" + }, + { + "Date": "2021-08-30", + "Value": 136, + "Series": "Music" + }, + { + "Date": "2021-09-05", + "Value": 143, + "Series": "Music" + }, + { + "Date": "2021-09-10", + "Value": 145, + "Series": "Music" + }, + { + "Date": "2021-09-16", + "Value": 150, + "Series": "Music" + }, + { + "Date": "2021-09-21", + "Value": 155, + "Series": "Music" + }, + { + "Date": "2021-09-27", + "Value": 163, + "Series": "Music" + }, + { + "Date": "2021-10-02", + "Value": 165, + "Series": "Music" + }, + { + "Date": "2021-10-08", + "Value": 165, + "Series": "Music" + }, + { + "Date": "2021-10-13", + "Value": 163, + "Series": "Music" + }, + { + "Date": "2021-10-19", + "Value": 163, + "Series": "Music" + }, + { + "Date": "2021-10-24", + "Value": 167, + "Series": "Music" + }, + { + "Date": "2021-10-29", + "Value": 168, + "Series": "Music" + }, + { + "Date": "2021-11-04", + "Value": 170, + "Series": "Music" + }, + { + "Date": "2021-11-09", + "Value": 165, + "Series": "Music" + }, + { + "Date": "2021-11-15", + "Value": 170, + "Series": "Music" + }, + { + "Date": "2021-11-20", + "Value": 181, + "Series": "Music" + }, + { + "Date": "2021-11-26", + "Value": 188, + "Series": "Music" + }, + { + "Date": "2021-12-01", + "Value": 185, + "Series": "Music" + }, + { + "Date": "2021-12-07", + "Value": 189, + "Series": "Music" + }, + { + "Date": "2021-12-12", + "Value": 200, + "Series": "Music" + }, + { + "Date": "2021-12-18", + "Value": 215, + "Series": "Music" + }, + { + "Date": "2021-12-23", + "Value": 230, + "Series": "Music" + }, + { + "Date": "2021-12-29", + "Value": 238, + "Series": "Music" + }, + { + "Date": "2022-01-03", + "Value": 235, + "Series": "Music" + }, + { + "Date": "2022-01-09", + "Value": 225, + "Series": "Music" + }, + { + "Date": "2022-01-14", + "Value": 220, + "Series": "Music" + }, + { + "Date": "2022-01-20", + "Value": 210, + "Series": "Music" + }, + { + "Date": "2022-01-25", + "Value": 205, + "Series": "Music" + }, + { + "Date": "2022-01-31", + "Value": 199, + "Series": "Music" + }, + { + "Date": "2022-02-05", + "Value": 194, + "Series": "Music" + }, + { + "Date": "2022-02-10", + "Value": 181, + "Series": "Music" + }, + { + "Date": "2022-02-16", + "Value": 180, + "Series": "Music" + }, + { + "Date": "2022-02-21", + "Value": 175, + "Series": "Music" + }, + { + "Date": "2022-02-27", + "Value": 170, + "Series": "Music" + }, + { + "Date": "2022-03-04", + "Value": 174, + "Series": "Music" + }, + { + "Date": "2022-03-10", + "Value": 177, + "Series": "Music" + }, + { + "Date": "2022-03-15", + "Value": 183, + "Series": "Music" + }, + { + "Date": "2022-03-21", + "Value": 187, + "Series": "Music" + }, + { + "Date": "2022-03-26", + "Value": 196, + "Series": "Music" + }, + { + "Date": "2022-04-01", + "Value": 194, + "Series": "Music" + }, + { + "Date": "2022-04-06", + "Value": 195, + "Series": "Music" + }, + { + "Date": "2022-04-12", + "Value": 190, + "Series": "Music" + }, + { + "Date": "2022-04-17", + "Value": 194, + "Series": "Music" + }, + { + "Date": "2022-04-23", + "Value": 196, + "Series": "Music" + }, + { + "Date": "2022-04-28", + "Value": 189, + "Series": "Music" + }, + { + "Date": "2022-05-04", + "Value": 177, + "Series": "Music" + }, + { + "Date": "2022-05-09", + "Value": 174, + "Series": "Music" + }, + { + "Date": "2022-05-15", + "Value": 167, + "Series": "Music" + }, + { + "Date": "2022-05-20", + "Value": 168, + "Series": "Music" + }, + { + "Date": "2022-05-26", + "Value": 173, + "Series": "Music" + }, + { + "Date": "2022-05-31", + "Value": 171, + "Series": "Music" + }, + { + "Date": "2022-06-05", + "Value": 165, + "Series": "Music" + }, + { + "Date": "2022-06-11", + "Value": 153, + "Series": "Music" + }, + { + "Date": "2022-06-16", + "Value": 145, + "Series": "Music" + }, + { + "Date": "2022-06-22", + "Value": 133, + "Series": "Music" + }, + { + "Date": "2022-06-27", + "Value": 125, + "Series": "Music" + }, + { + "Date": "2022-07-03", + "Value": 111, + "Series": "Music" + }, + { + "Date": "2022-07-08", + "Value": 96, + "Series": "Music" + }, + { + "Date": "2022-07-14", + "Value": 87, + "Series": "Music" + }, + { + "Date": "2022-07-19", + "Value": 73, + "Series": "Music" + }, + { + "Date": "2022-07-25", + "Value": 60, + "Series": "Music" + }, + { + "Date": "2022-07-30", + "Value": 57, + "Series": "Music" + }, + { + "Date": "2022-08-05", + "Value": 48, + "Series": "Music" + }, + { + "Date": "2022-08-10", + "Value": 43, + "Series": "Music" + }, + { + "Date": "2022-08-16", + "Value": 36, + "Series": "Music" + }, + { + "Date": "2022-08-21", + "Value": 30, + "Series": "Music" + }, + { + "Date": "2022-08-27", + "Value": 23, + "Series": "Music" + }, + { + "Date": "2022-09-01", + "Value": 26, + "Series": "Music" + }, + { + "Date": "2022-09-07", + "Value": 27, + "Series": "Music" + }, + { + "Date": "2022-09-12", + "Value": 25, + "Series": "Music" + }, + { + "Date": "2022-09-17", + "Value": 26, + "Series": "Music" + }, + { + "Date": "2022-09-23", + "Value": 27, + "Series": "Music" + }, + { + "Date": "2022-09-28", + "Value": 22, + "Series": "Music" + }, + { + "Date": "2022-10-04", + "Value": 10, + "Series": "Music" + }, + { + "Date": "2022-10-09", + "Value": 10, + "Series": "Music" + }, + { + "Date": "2022-10-15", + "Value": 11, + "Series": "Music" + }, + { + "Date": "2022-10-20", + "Value": 4, + "Series": "Music" + }, + { + "Date": "2022-10-26", + "Value": 5, + "Series": "Music" + }, + { + "Date": "2022-10-31", + "Value": 8, + "Series": "Music" + }, + { + "Date": "2022-11-06", + "Value": 19, + "Series": "Music" + }, + { + "Date": "2022-11-11", + "Value": 34, + "Series": "Music" + }, + { + "Date": "2022-11-17", + "Value": 37, + "Series": "Music" + }, + { + "Date": "2022-11-22", + "Value": 40, + "Series": "Music" + }, + { + "Date": "2022-11-28", + "Value": 36, + "Series": "Music" + }, + { + "Date": "2022-12-03", + "Value": 41, + "Series": "Music" + }, + { + "Date": "2022-12-09", + "Value": 53, + "Series": "Music" + }, + { + "Date": "2022-12-14", + "Value": 56, + "Series": "Music" + }, + { + "Date": "2022-12-20", + "Value": 62, + "Series": "Music" + }, + { + "Date": "2022-12-25", + "Value": 57, + "Series": "Music" + }, + { + "Date": "2020-01-01", + "Value": 240, + "Series": "Movies" + }, + { + "Date": "2020-01-06", + "Value": 252, + "Series": "Movies" + }, + { + "Date": "2020-01-11", + "Value": 269, + "Series": "Movies" + }, + { + "Date": "2020-01-17", + "Value": 269, + "Series": "Movies" + }, + { + "Date": "2020-01-22", + "Value": 272, + "Series": "Movies" + }, + { + "Date": "2020-01-28", + "Value": 289, + "Series": "Movies" + }, + { + "Date": "2020-02-02", + "Value": 302, + "Series": "Movies" + }, + { + "Date": "2020-02-08", + "Value": 299, + "Series": "Movies" + }, + { + "Date": "2020-02-13", + "Value": 296, + "Series": "Movies" + }, + { + "Date": "2020-02-19", + "Value": 297, + "Series": "Movies" + }, + { + "Date": "2020-02-24", + "Value": 309, + "Series": "Movies" + }, + { + "Date": "2020-03-01", + "Value": 331, + "Series": "Movies" + }, + { + "Date": "2020-03-06", + "Value": 332, + "Series": "Movies" + }, + { + "Date": "2020-03-12", + "Value": 326, + "Series": "Movies" + }, + { + "Date": "2020-03-17", + "Value": 321, + "Series": "Movies" + }, + { + "Date": "2020-03-23", + "Value": 329, + "Series": "Movies" + }, + { + "Date": "2020-03-28", + "Value": 324, + "Series": "Movies" + }, + { + "Date": "2020-04-03", + "Value": 331, + "Series": "Movies" + }, + { + "Date": "2020-04-08", + "Value": 344, + "Series": "Movies" + }, + { + "Date": "2020-04-14", + "Value": 341, + "Series": "Movies" + }, + { + "Date": "2020-04-19", + "Value": 338, + "Series": "Movies" + }, + { + "Date": "2020-04-24", + "Value": 320, + "Series": "Movies" + }, + { + "Date": "2020-04-30", + "Value": 315, + "Series": "Movies" + }, + { + "Date": "2020-05-05", + "Value": 319, + "Series": "Movies" + }, + { + "Date": "2020-05-11", + "Value": 319, + "Series": "Movies" + }, + { + "Date": "2020-05-16", + "Value": 316, + "Series": "Movies" + }, + { + "Date": "2020-05-22", + "Value": 301, + "Series": "Movies" + }, + { + "Date": "2020-05-27", + "Value": 273, + "Series": "Movies" + }, + { + "Date": "2020-06-02", + "Value": 268, + "Series": "Movies" + }, + { + "Date": "2020-06-07", + "Value": 250, + "Series": "Movies" + }, + { + "Date": "2020-06-13", + "Value": 223, + "Series": "Movies" + }, + { + "Date": "2020-06-18", + "Value": 221, + "Series": "Movies" + }, + { + "Date": "2020-06-24", + "Value": 209, + "Series": "Movies" + }, + { + "Date": "2020-06-29", + "Value": 199, + "Series": "Movies" + }, + { + "Date": "2020-07-05", + "Value": 209, + "Series": "Movies" + }, + { + "Date": "2020-07-10", + "Value": 205, + "Series": "Movies" + }, + { + "Date": "2020-07-16", + "Value": 218, + "Series": "Movies" + }, + { + "Date": "2020-07-21", + "Value": 216, + "Series": "Movies" + }, + { + "Date": "2020-07-27", + "Value": 204, + "Series": "Movies" + }, + { + "Date": "2020-08-01", + "Value": 204, + "Series": "Movies" + }, + { + "Date": "2020-08-07", + "Value": 201, + "Series": "Movies" + }, + { + "Date": "2020-08-12", + "Value": 201, + "Series": "Movies" + }, + { + "Date": "2020-08-17", + "Value": 198, + "Series": "Movies" + }, + { + "Date": "2020-08-23", + "Value": 192, + "Series": "Movies" + }, + { + "Date": "2020-08-28", + "Value": 201, + "Series": "Movies" + }, + { + "Date": "2020-09-03", + "Value": 194, + "Series": "Movies" + }, + { + "Date": "2020-09-08", + "Value": 196, + "Series": "Movies" + }, + { + "Date": "2020-09-14", + "Value": 214, + "Series": "Movies" + }, + { + "Date": "2020-09-19", + "Value": 221, + "Series": "Movies" + }, + { + "Date": "2020-09-25", + "Value": 213, + "Series": "Movies" + }, + { + "Date": "2020-09-30", + "Value": 218, + "Series": "Movies" + }, + { + "Date": "2020-10-06", + "Value": 217, + "Series": "Movies" + }, + { + "Date": "2020-10-11", + "Value": 208, + "Series": "Movies" + }, + { + "Date": "2020-10-17", + "Value": 210, + "Series": "Movies" + }, + { + "Date": "2020-10-22", + "Value": 224, + "Series": "Movies" + }, + { + "Date": "2020-10-28", + "Value": 240, + "Series": "Movies" + }, + { + "Date": "2020-11-02", + "Value": 246, + "Series": "Movies" + }, + { + "Date": "2020-11-08", + "Value": 265, + "Series": "Movies" + }, + { + "Date": "2020-11-13", + "Value": 269, + "Series": "Movies" + }, + { + "Date": "2020-11-19", + "Value": 274, + "Series": "Movies" + }, + { + "Date": "2020-11-24", + "Value": 262, + "Series": "Movies" + }, + { + "Date": "2020-11-29", + "Value": 260, + "Series": "Movies" + }, + { + "Date": "2020-12-05", + "Value": 265, + "Series": "Movies" + }, + { + "Date": "2020-12-10", + "Value": 255, + "Series": "Movies" + }, + { + "Date": "2020-12-16", + "Value": 246, + "Series": "Movies" + }, + { + "Date": "2020-12-21", + "Value": 251, + "Series": "Movies" + }, + { + "Date": "2020-12-27", + "Value": 270, + "Series": "Movies" + }, + { + "Date": "2021-01-01", + "Value": 300, + "Series": "Movies" + }, + { + "Date": "2021-01-07", + "Value": 323, + "Series": "Movies" + }, + { + "Date": "2021-01-12", + "Value": 325, + "Series": "Movies" + }, + { + "Date": "2021-01-18", + "Value": 316, + "Series": "Movies" + }, + { + "Date": "2021-01-23", + "Value": 302, + "Series": "Movies" + }, + { + "Date": "2021-01-29", + "Value": 286, + "Series": "Movies" + }, + { + "Date": "2021-02-03", + "Value": 288, + "Series": "Movies" + }, + { + "Date": "2021-02-09", + "Value": 291, + "Series": "Movies" + }, + { + "Date": "2021-02-14", + "Value": 300, + "Series": "Movies" + }, + { + "Date": "2021-02-20", + "Value": 319, + "Series": "Movies" + }, + { + "Date": "2021-02-25", + "Value": 326, + "Series": "Movies" + }, + { + "Date": "2021-03-03", + "Value": 325, + "Series": "Movies" + }, + { + "Date": "2021-03-08", + "Value": 324, + "Series": "Movies" + }, + { + "Date": "2021-03-14", + "Value": 313, + "Series": "Movies" + }, + { + "Date": "2021-03-19", + "Value": 318, + "Series": "Movies" + }, + { + "Date": "2021-03-24", + "Value": 338, + "Series": "Movies" + }, + { + "Date": "2021-03-30", + "Value": 358, + "Series": "Movies" + }, + { + "Date": "2021-04-04", + "Value": 383, + "Series": "Movies" + }, + { + "Date": "2021-04-10", + "Value": 397, + "Series": "Movies" + }, + { + "Date": "2021-04-15", + "Value": 415, + "Series": "Movies" + }, + { + "Date": "2021-04-21", + "Value": 413, + "Series": "Movies" + }, + { + "Date": "2021-04-26", + "Value": 400, + "Series": "Movies" + }, + { + "Date": "2021-05-02", + "Value": 389, + "Series": "Movies" + }, + { + "Date": "2021-05-07", + "Value": 372, + "Series": "Movies" + }, + { + "Date": "2021-05-13", + "Value": 350, + "Series": "Movies" + }, + { + "Date": "2021-05-18", + "Value": 334, + "Series": "Movies" + }, + { + "Date": "2021-05-24", + "Value": 316, + "Series": "Movies" + }, + { + "Date": "2021-05-29", + "Value": 309, + "Series": "Movies" + }, + { + "Date": "2021-06-04", + "Value": 310, + "Series": "Movies" + }, + { + "Date": "2021-06-09", + "Value": 327, + "Series": "Movies" + }, + { + "Date": "2021-06-15", + "Value": 343, + "Series": "Movies" + }, + { + "Date": "2021-06-20", + "Value": 345, + "Series": "Movies" + }, + { + "Date": "2021-06-26", + "Value": 354, + "Series": "Movies" + }, + { + "Date": "2021-07-01", + "Value": 366, + "Series": "Movies" + }, + { + "Date": "2021-07-06", + "Value": 365, + "Series": "Movies" + }, + { + "Date": "2021-07-12", + "Value": 376, + "Series": "Movies" + }, + { + "Date": "2021-07-17", + "Value": 394, + "Series": "Movies" + }, + { + "Date": "2021-07-23", + "Value": 414, + "Series": "Movies" + }, + { + "Date": "2021-07-28", + "Value": 411, + "Series": "Movies" + }, + { + "Date": "2021-08-03", + "Value": 394, + "Series": "Movies" + }, + { + "Date": "2021-08-08", + "Value": 369, + "Series": "Movies" + }, + { + "Date": "2021-08-14", + "Value": 352, + "Series": "Movies" + }, + { + "Date": "2021-08-19", + "Value": 348, + "Series": "Movies" + }, + { + "Date": "2021-08-25", + "Value": 343, + "Series": "Movies" + }, + { + "Date": "2021-08-30", + "Value": 342, + "Series": "Movies" + }, + { + "Date": "2021-09-05", + "Value": 333, + "Series": "Movies" + }, + { + "Date": "2021-09-10", + "Value": 321, + "Series": "Movies" + }, + { + "Date": "2021-09-16", + "Value": 322, + "Series": "Movies" + }, + { + "Date": "2021-09-21", + "Value": 310, + "Series": "Movies" + }, + { + "Date": "2021-09-27", + "Value": 287, + "Series": "Movies" + }, + { + "Date": "2021-10-02", + "Value": 283, + "Series": "Movies" + }, + { + "Date": "2021-10-08", + "Value": 297, + "Series": "Movies" + }, + { + "Date": "2021-10-13", + "Value": 295, + "Series": "Movies" + }, + { + "Date": "2021-10-19", + "Value": 288, + "Series": "Movies" + }, + { + "Date": "2021-10-24", + "Value": 284, + "Series": "Movies" + }, + { + "Date": "2021-10-29", + "Value": 295, + "Series": "Movies" + }, + { + "Date": "2021-11-04", + "Value": 312, + "Series": "Movies" + }, + { + "Date": "2021-11-09", + "Value": 316, + "Series": "Movies" + }, + { + "Date": "2021-11-15", + "Value": 313, + "Series": "Movies" + }, + { + "Date": "2021-11-20", + "Value": 320, + "Series": "Movies" + }, + { + "Date": "2021-11-26", + "Value": 340, + "Series": "Movies" + }, + { + "Date": "2021-12-01", + "Value": 355, + "Series": "Movies" + }, + { + "Date": "2021-12-07", + "Value": 359, + "Series": "Movies" + }, + { + "Date": "2021-12-12", + "Value": 356, + "Series": "Movies" + }, + { + "Date": "2021-12-18", + "Value": 371, + "Series": "Movies" + }, + { + "Date": "2021-12-23", + "Value": 397, + "Series": "Movies" + }, + { + "Date": "2021-12-29", + "Value": 410, + "Series": "Movies" + }, + { + "Date": "2022-01-03", + "Value": 417, + "Series": "Movies" + }, + { + "Date": "2022-01-09", + "Value": 415, + "Series": "Movies" + }, + { + "Date": "2022-01-14", + "Value": 419, + "Series": "Movies" + }, + { + "Date": "2022-01-20", + "Value": 432, + "Series": "Movies" + }, + { + "Date": "2022-01-25", + "Value": 431, + "Series": "Movies" + }, + { + "Date": "2022-01-31", + "Value": 445, + "Series": "Movies" + }, + { + "Date": "2022-02-05", + "Value": 447, + "Series": "Movies" + }, + { + "Date": "2022-02-10", + "Value": 433, + "Series": "Movies" + }, + { + "Date": "2022-02-16", + "Value": 413, + "Series": "Movies" + }, + { + "Date": "2022-02-21", + "Value": 393, + "Series": "Movies" + }, + { + "Date": "2022-02-27", + "Value": 384, + "Series": "Movies" + }, + { + "Date": "2022-03-04", + "Value": 370, + "Series": "Movies" + }, + { + "Date": "2022-03-10", + "Value": 370, + "Series": "Movies" + }, + { + "Date": "2022-03-15", + "Value": 367, + "Series": "Movies" + }, + { + "Date": "2022-03-21", + "Value": 366, + "Series": "Movies" + }, + { + "Date": "2022-03-26", + "Value": 362, + "Series": "Movies" + }, + { + "Date": "2022-04-01", + "Value": 345, + "Series": "Movies" + }, + { + "Date": "2022-04-06", + "Value": 316, + "Series": "Movies" + }, + { + "Date": "2022-04-12", + "Value": 310, + "Series": "Movies" + }, + { + "Date": "2022-04-17", + "Value": 297, + "Series": "Movies" + }, + { + "Date": "2022-04-23", + "Value": 278, + "Series": "Movies" + }, + { + "Date": "2022-04-28", + "Value": 256, + "Series": "Movies" + }, + { + "Date": "2022-05-04", + "Value": 236, + "Series": "Movies" + }, + { + "Date": "2022-05-09", + "Value": 239, + "Series": "Movies" + }, + { + "Date": "2022-05-15", + "Value": 225, + "Series": "Movies" + }, + { + "Date": "2022-05-20", + "Value": 199, + "Series": "Movies" + }, + { + "Date": "2022-05-26", + "Value": 186, + "Series": "Movies" + }, + { + "Date": "2022-05-31", + "Value": 162, + "Series": "Movies" + }, + { + "Date": "2022-06-05", + "Value": 139, + "Series": "Movies" + }, + { + "Date": "2022-06-11", + "Value": 130, + "Series": "Movies" + }, + { + "Date": "2022-06-16", + "Value": 114, + "Series": "Movies" + }, + { + "Date": "2022-06-22", + "Value": 107, + "Series": "Movies" + }, + { + "Date": "2022-06-27", + "Value": 117, + "Series": "Movies" + }, + { + "Date": "2022-07-03", + "Value": 109, + "Series": "Movies" + }, + { + "Date": "2022-07-08", + "Value": 120, + "Series": "Movies" + }, + { + "Date": "2022-07-14", + "Value": 136, + "Series": "Movies" + }, + { + "Date": "2022-07-19", + "Value": 142, + "Series": "Movies" + }, + { + "Date": "2022-07-25", + "Value": 142, + "Series": "Movies" + }, + { + "Date": "2022-07-30", + "Value": 129, + "Series": "Movies" + }, + { + "Date": "2022-08-05", + "Value": 130, + "Series": "Movies" + }, + { + "Date": "2022-08-10", + "Value": 119, + "Series": "Movies" + }, + { + "Date": "2022-08-16", + "Value": 115, + "Series": "Movies" + }, + { + "Date": "2022-08-21", + "Value": 120, + "Series": "Movies" + }, + { + "Date": "2022-08-27", + "Value": 108, + "Series": "Movies" + }, + { + "Date": "2022-09-01", + "Value": 100, + "Series": "Movies" + }, + { + "Date": "2022-09-07", + "Value": 82, + "Series": "Movies" + }, + { + "Date": "2022-09-12", + "Value": 78, + "Series": "Movies" + }, + { + "Date": "2022-09-17", + "Value": 72, + "Series": "Movies" + }, + { + "Date": "2022-09-23", + "Value": 77, + "Series": "Movies" + }, + { + "Date": "2022-09-28", + "Value": 78, + "Series": "Movies" + }, + { + "Date": "2022-10-04", + "Value": 83, + "Series": "Movies" + }, + { + "Date": "2022-10-09", + "Value": 71, + "Series": "Movies" + }, + { + "Date": "2022-10-15", + "Value": 60, + "Series": "Movies" + }, + { + "Date": "2022-10-20", + "Value": 36, + "Series": "Movies" + }, + { + "Date": "2022-10-26", + "Value": 7, + "Series": "Movies" + }, + { + "Date": "2022-10-31", + "Value": 0, + "Series": "Movies" + }, + { + "Date": "2022-11-06", + "Value": 0, + "Series": "Movies" + }, + { + "Date": "2022-11-11", + "Value": 10, + "Series": "Movies" + }, + { + "Date": "2022-11-17", + "Value": 24, + "Series": "Movies" + }, + { + "Date": "2022-11-22", + "Value": 34, + "Series": "Movies" + }, + { + "Date": "2022-11-28", + "Value": 45, + "Series": "Movies" + }, + { + "Date": "2022-12-03", + "Value": 53, + "Series": "Movies" + }, + { + "Date": "2022-12-09", + "Value": 64, + "Series": "Movies" + }, + { + "Date": "2022-12-14", + "Value": 86, + "Series": "Movies" + }, + { + "Date": "2022-12-20", + "Value": 102, + "Series": "Movies" + }, + { + "Date": "2022-12-25", + "Value": 102, + "Series": "Movies" + }, + { + "Date": "2020-01-01", + "Value": 229, + "Series": "Software" + }, + { + "Date": "2020-01-06", + "Value": 231, + "Series": "Software" + }, + { + "Date": "2020-01-11", + "Value": 227, + "Series": "Software" + }, + { + "Date": "2020-01-17", + "Value": 224, + "Series": "Software" + }, + { + "Date": "2020-01-22", + "Value": 225, + "Series": "Software" + }, + { + "Date": "2020-01-28", + "Value": 234, + "Series": "Software" + }, + { + "Date": "2020-02-02", + "Value": 247, + "Series": "Software" + }, + { + "Date": "2020-02-08", + "Value": 253, + "Series": "Software" + }, + { + "Date": "2020-02-13", + "Value": 267, + "Series": "Software" + }, + { + "Date": "2020-02-19", + "Value": 281, + "Series": "Software" + }, + { + "Date": "2020-02-24", + "Value": 294, + "Series": "Software" + }, + { + "Date": "2020-03-01", + "Value": 299, + "Series": "Software" + }, + { + "Date": "2020-03-06", + "Value": 313, + "Series": "Software" + }, + { + "Date": "2020-03-12", + "Value": 318, + "Series": "Software" + }, + { + "Date": "2020-03-17", + "Value": 315, + "Series": "Software" + }, + { + "Date": "2020-03-23", + "Value": 313, + "Series": "Software" + }, + { + "Date": "2020-03-28", + "Value": 318, + "Series": "Software" + }, + { + "Date": "2020-04-03", + "Value": 311, + "Series": "Software" + }, + { + "Date": "2020-04-08", + "Value": 295, + "Series": "Software" + }, + { + "Date": "2020-04-14", + "Value": 280, + "Series": "Software" + }, + { + "Date": "2020-04-19", + "Value": 277, + "Series": "Software" + }, + { + "Date": "2020-04-24", + "Value": 270, + "Series": "Software" + }, + { + "Date": "2020-04-30", + "Value": 267, + "Series": "Software" + }, + { + "Date": "2020-05-05", + "Value": 263, + "Series": "Software" + }, + { + "Date": "2020-05-11", + "Value": 267, + "Series": "Software" + }, + { + "Date": "2020-05-16", + "Value": 268, + "Series": "Software" + }, + { + "Date": "2020-05-22", + "Value": 259, + "Series": "Software" + }, + { + "Date": "2020-05-27", + "Value": 254, + "Series": "Software" + }, + { + "Date": "2020-06-02", + "Value": 248, + "Series": "Software" + }, + { + "Date": "2020-06-07", + "Value": 237, + "Series": "Software" + }, + { + "Date": "2020-06-13", + "Value": 224, + "Series": "Software" + }, + { + "Date": "2020-06-18", + "Value": 224, + "Series": "Software" + }, + { + "Date": "2020-06-24", + "Value": 219, + "Series": "Software" + }, + { + "Date": "2020-06-29", + "Value": 208, + "Series": "Software" + }, + { + "Date": "2020-07-05", + "Value": 194, + "Series": "Software" + }, + { + "Date": "2020-07-10", + "Value": 189, + "Series": "Software" + }, + { + "Date": "2020-07-16", + "Value": 196, + "Series": "Software" + }, + { + "Date": "2020-07-21", + "Value": 209, + "Series": "Software" + }, + { + "Date": "2020-07-27", + "Value": 222, + "Series": "Software" + }, + { + "Date": "2020-08-01", + "Value": 233, + "Series": "Software" + }, + { + "Date": "2020-08-07", + "Value": 249, + "Series": "Software" + }, + { + "Date": "2020-08-12", + "Value": 265, + "Series": "Software" + }, + { + "Date": "2020-08-17", + "Value": 278, + "Series": "Software" + }, + { + "Date": "2020-08-23", + "Value": 297, + "Series": "Software" + }, + { + "Date": "2020-08-28", + "Value": 314, + "Series": "Software" + }, + { + "Date": "2020-09-03", + "Value": 324, + "Series": "Software" + }, + { + "Date": "2020-09-08", + "Value": 341, + "Series": "Software" + }, + { + "Date": "2020-09-14", + "Value": 347, + "Series": "Software" + }, + { + "Date": "2020-09-19", + "Value": 355, + "Series": "Software" + }, + { + "Date": "2020-09-25", + "Value": 356, + "Series": "Software" + }, + { + "Date": "2020-09-30", + "Value": 361, + "Series": "Software" + }, + { + "Date": "2020-10-06", + "Value": 375, + "Series": "Software" + }, + { + "Date": "2020-10-11", + "Value": 392, + "Series": "Software" + }, + { + "Date": "2020-10-17", + "Value": 409, + "Series": "Software" + }, + { + "Date": "2020-10-22", + "Value": 428, + "Series": "Software" + }, + { + "Date": "2020-10-28", + "Value": 449, + "Series": "Software" + }, + { + "Date": "2020-11-02", + "Value": 466, + "Series": "Software" + }, + { + "Date": "2020-11-08", + "Value": 470, + "Series": "Software" + }, + { + "Date": "2020-11-13", + "Value": 473, + "Series": "Software" + }, + { + "Date": "2020-11-19", + "Value": 470, + "Series": "Software" + }, + { + "Date": "2020-11-24", + "Value": 477, + "Series": "Software" + }, + { + "Date": "2020-11-29", + "Value": 478, + "Series": "Software" + }, + { + "Date": "2020-12-05", + "Value": 468, + "Series": "Software" + }, + { + "Date": "2020-12-10", + "Value": 454, + "Series": "Software" + }, + { + "Date": "2020-12-16", + "Value": 438, + "Series": "Software" + }, + { + "Date": "2020-12-21", + "Value": 418, + "Series": "Software" + }, + { + "Date": "2020-12-27", + "Value": 404, + "Series": "Software" + }, + { + "Date": "2021-01-01", + "Value": 398, + "Series": "Software" + }, + { + "Date": "2021-01-07", + "Value": 384, + "Series": "Software" + }, + { + "Date": "2021-01-12", + "Value": 365, + "Series": "Software" + }, + { + "Date": "2021-01-18", + "Value": 355, + "Series": "Software" + }, + { + "Date": "2021-01-23", + "Value": 345, + "Series": "Software" + }, + { + "Date": "2021-01-29", + "Value": 329, + "Series": "Software" + }, + { + "Date": "2021-02-03", + "Value": 311, + "Series": "Software" + }, + { + "Date": "2021-02-09", + "Value": 303, + "Series": "Software" + }, + { + "Date": "2021-02-14", + "Value": 301, + "Series": "Software" + }, + { + "Date": "2021-02-20", + "Value": 292, + "Series": "Software" + }, + { + "Date": "2021-02-25", + "Value": 292, + "Series": "Software" + }, + { + "Date": "2021-03-03", + "Value": 288, + "Series": "Software" + }, + { + "Date": "2021-03-08", + "Value": 295, + "Series": "Software" + }, + { + "Date": "2021-03-14", + "Value": 302, + "Series": "Software" + }, + { + "Date": "2021-03-19", + "Value": 306, + "Series": "Software" + }, + { + "Date": "2021-03-24", + "Value": 317, + "Series": "Software" + }, + { + "Date": "2021-03-30", + "Value": 325, + "Series": "Software" + }, + { + "Date": "2021-04-04", + "Value": 320, + "Series": "Software" + }, + { + "Date": "2021-04-10", + "Value": 317, + "Series": "Software" + }, + { + "Date": "2021-04-15", + "Value": 316, + "Series": "Software" + }, + { + "Date": "2021-04-21", + "Value": 318, + "Series": "Software" + }, + { + "Date": "2021-04-26", + "Value": 318, + "Series": "Software" + }, + { + "Date": "2021-05-02", + "Value": 313, + "Series": "Software" + }, + { + "Date": "2021-05-07", + "Value": 299, + "Series": "Software" + }, + { + "Date": "2021-05-13", + "Value": 287, + "Series": "Software" + }, + { + "Date": "2021-05-18", + "Value": 284, + "Series": "Software" + }, + { + "Date": "2021-05-24", + "Value": 286, + "Series": "Software" + }, + { + "Date": "2021-05-29", + "Value": 293, + "Series": "Software" + }, + { + "Date": "2021-06-04", + "Value": 295, + "Series": "Software" + }, + { + "Date": "2021-06-09", + "Value": 292, + "Series": "Software" + }, + { + "Date": "2021-06-15", + "Value": 300, + "Series": "Software" + }, + { + "Date": "2021-06-20", + "Value": 309, + "Series": "Software" + }, + { + "Date": "2021-06-26", + "Value": 321, + "Series": "Software" + }, + { + "Date": "2021-07-01", + "Value": 337, + "Series": "Software" + }, + { + "Date": "2021-07-06", + "Value": 344, + "Series": "Software" + }, + { + "Date": "2021-07-12", + "Value": 358, + "Series": "Software" + }, + { + "Date": "2021-07-17", + "Value": 363, + "Series": "Software" + }, + { + "Date": "2021-07-23", + "Value": 361, + "Series": "Software" + }, + { + "Date": "2021-07-28", + "Value": 366, + "Series": "Software" + }, + { + "Date": "2021-08-03", + "Value": 379, + "Series": "Software" + }, + { + "Date": "2021-08-08", + "Value": 397, + "Series": "Software" + }, + { + "Date": "2021-08-14", + "Value": 409, + "Series": "Software" + }, + { + "Date": "2021-08-19", + "Value": 427, + "Series": "Software" + }, + { + "Date": "2021-08-25", + "Value": 446, + "Series": "Software" + }, + { + "Date": "2021-08-30", + "Value": 467, + "Series": "Software" + }, + { + "Date": "2021-09-05", + "Value": 486, + "Series": "Software" + }, + { + "Date": "2021-09-10", + "Value": 493, + "Series": "Software" + }, + { + "Date": "2021-09-16", + "Value": 498, + "Series": "Software" + }, + { + "Date": "2021-09-21", + "Value": 496, + "Series": "Software" + }, + { + "Date": "2021-09-27", + "Value": 488, + "Series": "Software" + }, + { + "Date": "2021-10-02", + "Value": 486, + "Series": "Software" + }, + { + "Date": "2021-10-08", + "Value": 487, + "Series": "Software" + }, + { + "Date": "2021-10-13", + "Value": 480, + "Series": "Software" + }, + { + "Date": "2021-10-19", + "Value": 472, + "Series": "Software" + }, + { + "Date": "2021-10-24", + "Value": 457, + "Series": "Software" + }, + { + "Date": "2021-10-29", + "Value": 448, + "Series": "Software" + }, + { + "Date": "2021-11-04", + "Value": 448, + "Series": "Software" + }, + { + "Date": "2021-11-09", + "Value": 443, + "Series": "Software" + }, + { + "Date": "2021-11-15", + "Value": 449, + "Series": "Software" + }, + { + "Date": "2021-11-20", + "Value": 455, + "Series": "Software" + }, + { + "Date": "2021-11-26", + "Value": 459, + "Series": "Software" + }, + { + "Date": "2021-12-01", + "Value": 463, + "Series": "Software" + }, + { + "Date": "2021-12-07", + "Value": 469, + "Series": "Software" + }, + { + "Date": "2021-12-12", + "Value": 481, + "Series": "Software" + }, + { + "Date": "2021-12-18", + "Value": 479, + "Series": "Software" + }, + { + "Date": "2021-12-23", + "Value": 486, + "Series": "Software" + }, + { + "Date": "2021-12-29", + "Value": 480, + "Series": "Software" + }, + { + "Date": "2022-01-03", + "Value": 484, + "Series": "Software" + }, + { + "Date": "2022-01-09", + "Value": 489, + "Series": "Software" + }, + { + "Date": "2022-01-14", + "Value": 499, + "Series": "Software" + }, + { + "Date": "2022-01-20", + "Value": 511, + "Series": "Software" + }, + { + "Date": "2022-01-25", + "Value": 526, + "Series": "Software" + }, + { + "Date": "2022-01-31", + "Value": 547, + "Series": "Software" + }, + { + "Date": "2022-02-05", + "Value": 560, + "Series": "Software" + }, + { + "Date": "2022-02-10", + "Value": 575, + "Series": "Software" + }, + { + "Date": "2022-02-16", + "Value": 579, + "Series": "Software" + }, + { + "Date": "2022-02-21", + "Value": 574, + "Series": "Software" + }, + { + "Date": "2022-02-27", + "Value": 562, + "Series": "Software" + }, + { + "Date": "2022-03-04", + "Value": 556, + "Series": "Software" + }, + { + "Date": "2022-03-10", + "Value": 551, + "Series": "Software" + }, + { + "Date": "2022-03-15", + "Value": 548, + "Series": "Software" + }, + { + "Date": "2022-03-21", + "Value": 552, + "Series": "Software" + }, + { + "Date": "2022-03-26", + "Value": 562, + "Series": "Software" + }, + { + "Date": "2022-04-01", + "Value": 565, + "Series": "Software" + }, + { + "Date": "2022-04-06", + "Value": 557, + "Series": "Software" + }, + { + "Date": "2022-04-12", + "Value": 562, + "Series": "Software" + }, + { + "Date": "2022-04-17", + "Value": 560, + "Series": "Software" + }, + { + "Date": "2022-04-23", + "Value": 552, + "Series": "Software" + }, + { + "Date": "2022-04-28", + "Value": 553, + "Series": "Software" + }, + { + "Date": "2022-05-04", + "Value": 562, + "Series": "Software" + }, + { + "Date": "2022-05-09", + "Value": 568, + "Series": "Software" + }, + { + "Date": "2022-05-15", + "Value": 576, + "Series": "Software" + }, + { + "Date": "2022-05-20", + "Value": 585, + "Series": "Software" + }, + { + "Date": "2022-05-26", + "Value": 587, + "Series": "Software" + }, + { + "Date": "2022-05-31", + "Value": 581, + "Series": "Software" + }, + { + "Date": "2022-06-05", + "Value": 579, + "Series": "Software" + }, + { + "Date": "2022-06-11", + "Value": 588, + "Series": "Software" + }, + { + "Date": "2022-06-16", + "Value": 590, + "Series": "Software" + }, + { + "Date": "2022-06-22", + "Value": 586, + "Series": "Software" + }, + { + "Date": "2022-06-27", + "Value": 583, + "Series": "Software" + }, + { + "Date": "2022-07-03", + "Value": 581, + "Series": "Software" + }, + { + "Date": "2022-07-08", + "Value": 572, + "Series": "Software" + }, + { + "Date": "2022-07-14", + "Value": 570, + "Series": "Software" + }, + { + "Date": "2022-07-19", + "Value": 568, + "Series": "Software" + }, + { + "Date": "2022-07-25", + "Value": 562, + "Series": "Software" + }, + { + "Date": "2022-07-30", + "Value": 562, + "Series": "Software" + }, + { + "Date": "2022-08-05", + "Value": 569, + "Series": "Software" + }, + { + "Date": "2022-08-10", + "Value": 570, + "Series": "Software" + }, + { + "Date": "2022-08-16", + "Value": 560, + "Series": "Software" + }, + { + "Date": "2022-08-21", + "Value": 554, + "Series": "Software" + }, + { + "Date": "2022-08-27", + "Value": 560, + "Series": "Software" + }, + { + "Date": "2022-09-01", + "Value": 573, + "Series": "Software" + }, + { + "Date": "2022-09-07", + "Value": 591, + "Series": "Software" + }, + { + "Date": "2022-09-12", + "Value": 594, + "Series": "Software" + }, + { + "Date": "2022-09-17", + "Value": 603, + "Series": "Software" + }, + { + "Date": "2022-09-23", + "Value": 611, + "Series": "Software" + }, + { + "Date": "2022-09-28", + "Value": 622, + "Series": "Software" + }, + { + "Date": "2022-10-04", + "Value": 632, + "Series": "Software" + }, + { + "Date": "2022-10-09", + "Value": 649, + "Series": "Software" + }, + { + "Date": "2022-10-15", + "Value": 672, + "Series": "Software" + }, + { + "Date": "2022-10-20", + "Value": 694, + "Series": "Software" + }, + { + "Date": "2022-10-26", + "Value": 699, + "Series": "Software" + }, + { + "Date": "2022-10-31", + "Value": 709, + "Series": "Software" + }, + { + "Date": "2022-11-06", + "Value": 721, + "Series": "Software" + }, + { + "Date": "2022-11-11", + "Value": 733, + "Series": "Software" + }, + { + "Date": "2022-11-17", + "Value": 751, + "Series": "Software" + }, + { + "Date": "2022-11-22", + "Value": 773, + "Series": "Software" + }, + { + "Date": "2022-11-28", + "Value": 786, + "Series": "Software" + }, + { + "Date": "2022-12-03", + "Value": 791, + "Series": "Software" + }, + { + "Date": "2022-12-09", + "Value": 791, + "Series": "Software" + }, + { + "Date": "2022-12-14", + "Value": 802, + "Series": "Software" + }, + { + "Date": "2022-12-20", + "Value": 813, + "Series": "Software" + }, + { + "Date": "2022-12-25", + "Value": 820, + "Series": "Software" + }, + { + "Date": "2020-01-01", + "Value": 124, + "Series": "Games" + }, + { + "Date": "2020-01-06", + "Value": 114, + "Series": "Games" + }, + { + "Date": "2020-01-11", + "Value": 115, + "Series": "Games" + }, + { + "Date": "2020-01-17", + "Value": 119, + "Series": "Games" + }, + { + "Date": "2020-01-22", + "Value": 112, + "Series": "Games" + }, + { + "Date": "2020-01-28", + "Value": 104, + "Series": "Games" + }, + { + "Date": "2020-02-02", + "Value": 109, + "Series": "Games" + }, + { + "Date": "2020-02-08", + "Value": 117, + "Series": "Games" + }, + { + "Date": "2020-02-13", + "Value": 123, + "Series": "Games" + }, + { + "Date": "2020-02-19", + "Value": 128, + "Series": "Games" + }, + { + "Date": "2020-02-24", + "Value": 139, + "Series": "Games" + }, + { + "Date": "2020-03-01", + "Value": 156, + "Series": "Games" + }, + { + "Date": "2020-03-06", + "Value": 163, + "Series": "Games" + }, + { + "Date": "2020-03-12", + "Value": 169, + "Series": "Games" + }, + { + "Date": "2020-03-17", + "Value": 166, + "Series": "Games" + }, + { + "Date": "2020-03-23", + "Value": 174, + "Series": "Games" + }, + { + "Date": "2020-03-28", + "Value": 183, + "Series": "Games" + }, + { + "Date": "2020-04-03", + "Value": 181, + "Series": "Games" + }, + { + "Date": "2020-04-08", + "Value": 174, + "Series": "Games" + }, + { + "Date": "2020-04-14", + "Value": 170, + "Series": "Games" + }, + { + "Date": "2020-04-19", + "Value": 156, + "Series": "Games" + }, + { + "Date": "2020-04-24", + "Value": 137, + "Series": "Games" + }, + { + "Date": "2020-04-30", + "Value": 131, + "Series": "Games" + }, + { + "Date": "2020-05-05", + "Value": 134, + "Series": "Games" + }, + { + "Date": "2020-05-11", + "Value": 141, + "Series": "Games" + }, + { + "Date": "2020-05-16", + "Value": 140, + "Series": "Games" + }, + { + "Date": "2020-05-22", + "Value": 145, + "Series": "Games" + }, + { + "Date": "2020-05-27", + "Value": 152, + "Series": "Games" + }, + { + "Date": "2020-06-02", + "Value": 148, + "Series": "Games" + }, + { + "Date": "2020-06-07", + "Value": 146, + "Series": "Games" + }, + { + "Date": "2020-06-13", + "Value": 135, + "Series": "Games" + }, + { + "Date": "2020-06-18", + "Value": 125, + "Series": "Games" + }, + { + "Date": "2020-06-24", + "Value": 119, + "Series": "Games" + }, + { + "Date": "2020-06-29", + "Value": 105, + "Series": "Games" + }, + { + "Date": "2020-07-05", + "Value": 104, + "Series": "Games" + }, + { + "Date": "2020-07-10", + "Value": 95, + "Series": "Games" + }, + { + "Date": "2020-07-16", + "Value": 96, + "Series": "Games" + }, + { + "Date": "2020-07-21", + "Value": 100, + "Series": "Games" + }, + { + "Date": "2020-07-27", + "Value": 102, + "Series": "Games" + }, + { + "Date": "2020-08-01", + "Value": 112, + "Series": "Games" + }, + { + "Date": "2020-08-07", + "Value": 123, + "Series": "Games" + }, + { + "Date": "2020-08-12", + "Value": 123, + "Series": "Games" + }, + { + "Date": "2020-08-17", + "Value": 123, + "Series": "Games" + }, + { + "Date": "2020-08-23", + "Value": 114, + "Series": "Games" + }, + { + "Date": "2020-08-28", + "Value": 100, + "Series": "Games" + }, + { + "Date": "2020-09-03", + "Value": 100, + "Series": "Games" + }, + { + "Date": "2020-09-08", + "Value": 89, + "Series": "Games" + }, + { + "Date": "2020-09-14", + "Value": 80, + "Series": "Games" + }, + { + "Date": "2020-09-19", + "Value": 68, + "Series": "Games" + }, + { + "Date": "2020-09-25", + "Value": 64, + "Series": "Games" + }, + { + "Date": "2020-09-30", + "Value": 71, + "Series": "Games" + }, + { + "Date": "2020-10-06", + "Value": 80, + "Series": "Games" + }, + { + "Date": "2020-10-11", + "Value": 87, + "Series": "Games" + }, + { + "Date": "2020-10-17", + "Value": 83, + "Series": "Games" + }, + { + "Date": "2020-10-22", + "Value": 84, + "Series": "Games" + }, + { + "Date": "2020-10-28", + "Value": 93, + "Series": "Games" + }, + { + "Date": "2020-11-02", + "Value": 96, + "Series": "Games" + }, + { + "Date": "2020-11-08", + "Value": 89, + "Series": "Games" + }, + { + "Date": "2020-11-13", + "Value": 89, + "Series": "Games" + }, + { + "Date": "2020-11-19", + "Value": 83, + "Series": "Games" + }, + { + "Date": "2020-11-24", + "Value": 82, + "Series": "Games" + }, + { + "Date": "2020-11-29", + "Value": 83, + "Series": "Games" + }, + { + "Date": "2020-12-05", + "Value": 89, + "Series": "Games" + }, + { + "Date": "2020-12-10", + "Value": 94, + "Series": "Games" + }, + { + "Date": "2020-12-16", + "Value": 102, + "Series": "Games" + }, + { + "Date": "2020-12-21", + "Value": 112, + "Series": "Games" + }, + { + "Date": "2020-12-27", + "Value": 116, + "Series": "Games" + }, + { + "Date": "2021-01-01", + "Value": 122, + "Series": "Games" + }, + { + "Date": "2021-01-07", + "Value": 130, + "Series": "Games" + }, + { + "Date": "2021-01-12", + "Value": 138, + "Series": "Games" + }, + { + "Date": "2021-01-18", + "Value": 141, + "Series": "Games" + }, + { + "Date": "2021-01-23", + "Value": 139, + "Series": "Games" + }, + { + "Date": "2021-01-29", + "Value": 146, + "Series": "Games" + }, + { + "Date": "2021-02-03", + "Value": 148, + "Series": "Games" + }, + { + "Date": "2021-02-09", + "Value": 151, + "Series": "Games" + }, + { + "Date": "2021-02-14", + "Value": 149, + "Series": "Games" + }, + { + "Date": "2021-02-20", + "Value": 149, + "Series": "Games" + }, + { + "Date": "2021-02-25", + "Value": 139, + "Series": "Games" + }, + { + "Date": "2021-03-03", + "Value": 125, + "Series": "Games" + }, + { + "Date": "2021-03-08", + "Value": 107, + "Series": "Games" + }, + { + "Date": "2021-03-14", + "Value": 87, + "Series": "Games" + }, + { + "Date": "2021-03-19", + "Value": 63, + "Series": "Games" + }, + { + "Date": "2021-03-24", + "Value": 43, + "Series": "Games" + }, + { + "Date": "2021-03-30", + "Value": 26, + "Series": "Games" + }, + { + "Date": "2021-04-04", + "Value": 14, + "Series": "Games" + }, + { + "Date": "2021-04-10", + "Value": 11, + "Series": "Games" + }, + { + "Date": "2021-04-15", + "Value": 9, + "Series": "Games" + }, + { + "Date": "2021-04-21", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-04-26", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-05-02", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-05-07", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-05-13", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-05-18", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-05-24", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-05-29", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-06-04", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-06-09", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-06-15", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-06-20", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-06-26", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-07-01", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-07-06", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-07-12", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-07-17", + "Value": 4, + "Series": "Games" + }, + { + "Date": "2021-07-23", + "Value": 7, + "Series": "Games" + }, + { + "Date": "2021-07-28", + "Value": 2, + "Series": "Games" + }, + { + "Date": "2021-08-03", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-08-08", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-08-14", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-08-19", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-08-25", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-08-30", + "Value": 6, + "Series": "Games" + }, + { + "Date": "2021-09-05", + "Value": 18, + "Series": "Games" + }, + { + "Date": "2021-09-10", + "Value": 25, + "Series": "Games" + }, + { + "Date": "2021-09-16", + "Value": 22, + "Series": "Games" + }, + { + "Date": "2021-09-21", + "Value": 30, + "Series": "Games" + }, + { + "Date": "2021-09-27", + "Value": 26, + "Series": "Games" + }, + { + "Date": "2021-10-02", + "Value": 27, + "Series": "Games" + }, + { + "Date": "2021-10-08", + "Value": 24, + "Series": "Games" + }, + { + "Date": "2021-10-13", + "Value": 25, + "Series": "Games" + }, + { + "Date": "2021-10-19", + "Value": 29, + "Series": "Games" + }, + { + "Date": "2021-10-24", + "Value": 21, + "Series": "Games" + }, + { + "Date": "2021-10-29", + "Value": 7, + "Series": "Games" + }, + { + "Date": "2021-11-04", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-11-09", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-11-15", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-11-20", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-11-26", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-12-01", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-12-07", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-12-12", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-12-18", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2021-12-23", + "Value": 5, + "Series": "Games" + }, + { + "Date": "2021-12-29", + "Value": 10, + "Series": "Games" + }, + { + "Date": "2022-01-03", + "Value": 4, + "Series": "Games" + }, + { + "Date": "2022-01-09", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2022-01-14", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2022-01-20", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2022-01-25", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2022-01-31", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2022-02-05", + "Value": 8, + "Series": "Games" + }, + { + "Date": "2022-02-10", + "Value": 24, + "Series": "Games" + }, + { + "Date": "2022-02-16", + "Value": 32, + "Series": "Games" + }, + { + "Date": "2022-02-21", + "Value": 48, + "Series": "Games" + }, + { + "Date": "2022-02-27", + "Value": 51, + "Series": "Games" + }, + { + "Date": "2022-03-04", + "Value": 45, + "Series": "Games" + }, + { + "Date": "2022-03-10", + "Value": 44, + "Series": "Games" + }, + { + "Date": "2022-03-15", + "Value": 49, + "Series": "Games" + }, + { + "Date": "2022-03-21", + "Value": 42, + "Series": "Games" + }, + { + "Date": "2022-03-26", + "Value": 33, + "Series": "Games" + }, + { + "Date": "2022-04-01", + "Value": 33, + "Series": "Games" + }, + { + "Date": "2022-04-06", + "Value": 30, + "Series": "Games" + }, + { + "Date": "2022-04-12", + "Value": 19, + "Series": "Games" + }, + { + "Date": "2022-04-17", + "Value": 12, + "Series": "Games" + }, + { + "Date": "2022-04-23", + "Value": 2, + "Series": "Games" + }, + { + "Date": "2022-04-28", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2022-05-04", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2022-05-09", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2022-05-15", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2022-05-20", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2022-05-26", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2022-05-31", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2022-06-05", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2022-06-11", + "Value": 3, + "Series": "Games" + }, + { + "Date": "2022-06-16", + "Value": 7, + "Series": "Games" + }, + { + "Date": "2022-06-22", + "Value": 4, + "Series": "Games" + }, + { + "Date": "2022-06-27", + "Value": 1, + "Series": "Games" + }, + { + "Date": "2022-07-03", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2022-07-08", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2022-07-14", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2022-07-19", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2022-07-25", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2022-07-30", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2022-08-05", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2022-08-10", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2022-08-16", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2022-08-21", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2022-08-27", + "Value": 6, + "Series": "Games" + }, + { + "Date": "2022-09-01", + "Value": 3, + "Series": "Games" + }, + { + "Date": "2022-09-07", + "Value": 3, + "Series": "Games" + }, + { + "Date": "2022-09-12", + "Value": 1, + "Series": "Games" + }, + { + "Date": "2022-09-17", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2022-09-23", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2022-09-28", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2022-10-04", + "Value": 0, + "Series": "Games" + }, + { + "Date": "2022-10-09", + "Value": 3, + "Series": "Games" + }, + { + "Date": "2022-10-15", + "Value": 8, + "Series": "Games" + }, + { + "Date": "2022-10-20", + "Value": 17, + "Series": "Games" + }, + { + "Date": "2022-10-26", + "Value": 34, + "Series": "Games" + }, + { + "Date": "2022-10-31", + "Value": 42, + "Series": "Games" + }, + { + "Date": "2022-11-06", + "Value": 41, + "Series": "Games" + }, + { + "Date": "2022-11-11", + "Value": 48, + "Series": "Games" + }, + { + "Date": "2022-11-17", + "Value": 62, + "Series": "Games" + }, + { + "Date": "2022-11-22", + "Value": 64, + "Series": "Games" + }, + { + "Date": "2022-11-28", + "Value": 59, + "Series": "Games" + }, + { + "Date": "2022-12-03", + "Value": 55, + "Series": "Games" + }, + { + "Date": "2022-12-09", + "Value": 43, + "Series": "Games" + }, + { + "Date": "2022-12-14", + "Value": 44, + "Series": "Games" + }, + { + "Date": "2022-12-20", + "Value": 45, + "Series": "Games" + }, + { + "Date": "2022-12-25", + "Value": 37, + "Series": "Games" + }, + { + "Date": "2020-01-01", + "Value": 63, + "Series": "Office" + }, + { + "Date": "2020-01-06", + "Value": 66, + "Series": "Office" + }, + { + "Date": "2020-01-11", + "Value": 71, + "Series": "Office" + }, + { + "Date": "2020-01-17", + "Value": 75, + "Series": "Office" + }, + { + "Date": "2020-01-22", + "Value": 71, + "Series": "Office" + }, + { + "Date": "2020-01-28", + "Value": 63, + "Series": "Office" + }, + { + "Date": "2020-02-02", + "Value": 52, + "Series": "Office" + }, + { + "Date": "2020-02-08", + "Value": 39, + "Series": "Office" + }, + { + "Date": "2020-02-13", + "Value": 28, + "Series": "Office" + }, + { + "Date": "2020-02-19", + "Value": 17, + "Series": "Office" + }, + { + "Date": "2020-02-24", + "Value": 14, + "Series": "Office" + }, + { + "Date": "2020-03-01", + "Value": 7, + "Series": "Office" + }, + { + "Date": "2020-03-06", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2020-03-12", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2020-03-17", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2020-03-23", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2020-03-28", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2020-04-03", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2020-04-08", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2020-04-14", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2020-04-19", + "Value": 2, + "Series": "Office" + }, + { + "Date": "2020-04-24", + "Value": 1, + "Series": "Office" + }, + { + "Date": "2020-04-30", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2020-05-05", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2020-05-11", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2020-05-16", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2020-05-22", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2020-05-27", + "Value": 4, + "Series": "Office" + }, + { + "Date": "2020-06-02", + "Value": 8, + "Series": "Office" + }, + { + "Date": "2020-06-07", + "Value": 11, + "Series": "Office" + }, + { + "Date": "2020-06-13", + "Value": 19, + "Series": "Office" + }, + { + "Date": "2020-06-18", + "Value": 31, + "Series": "Office" + }, + { + "Date": "2020-06-24", + "Value": 36, + "Series": "Office" + }, + { + "Date": "2020-06-29", + "Value": 45, + "Series": "Office" + }, + { + "Date": "2020-07-05", + "Value": 51, + "Series": "Office" + }, + { + "Date": "2020-07-10", + "Value": 57, + "Series": "Office" + }, + { + "Date": "2020-07-16", + "Value": 66, + "Series": "Office" + }, + { + "Date": "2020-07-21", + "Value": 70, + "Series": "Office" + }, + { + "Date": "2020-07-27", + "Value": 77, + "Series": "Office" + }, + { + "Date": "2020-08-01", + "Value": 78, + "Series": "Office" + }, + { + "Date": "2020-08-07", + "Value": 77, + "Series": "Office" + }, + { + "Date": "2020-08-12", + "Value": 75, + "Series": "Office" + }, + { + "Date": "2020-08-17", + "Value": 81, + "Series": "Office" + }, + { + "Date": "2020-08-23", + "Value": 84, + "Series": "Office" + }, + { + "Date": "2020-08-28", + "Value": 87, + "Series": "Office" + }, + { + "Date": "2020-09-03", + "Value": 83, + "Series": "Office" + }, + { + "Date": "2020-09-08", + "Value": 85, + "Series": "Office" + }, + { + "Date": "2020-09-14", + "Value": 84, + "Series": "Office" + }, + { + "Date": "2020-09-19", + "Value": 80, + "Series": "Office" + }, + { + "Date": "2020-09-25", + "Value": 81, + "Series": "Office" + }, + { + "Date": "2020-09-30", + "Value": 75, + "Series": "Office" + }, + { + "Date": "2020-10-06", + "Value": 70, + "Series": "Office" + }, + { + "Date": "2020-10-11", + "Value": 73, + "Series": "Office" + }, + { + "Date": "2020-10-17", + "Value": 81, + "Series": "Office" + }, + { + "Date": "2020-10-22", + "Value": 85, + "Series": "Office" + }, + { + "Date": "2020-10-28", + "Value": 80, + "Series": "Office" + }, + { + "Date": "2020-11-02", + "Value": 83, + "Series": "Office" + }, + { + "Date": "2020-11-08", + "Value": 80, + "Series": "Office" + }, + { + "Date": "2020-11-13", + "Value": 77, + "Series": "Office" + }, + { + "Date": "2020-11-19", + "Value": 82, + "Series": "Office" + }, + { + "Date": "2020-11-24", + "Value": 79, + "Series": "Office" + }, + { + "Date": "2020-11-29", + "Value": 84, + "Series": "Office" + }, + { + "Date": "2020-12-05", + "Value": 86, + "Series": "Office" + }, + { + "Date": "2020-12-10", + "Value": 85, + "Series": "Office" + }, + { + "Date": "2020-12-16", + "Value": 90, + "Series": "Office" + }, + { + "Date": "2020-12-21", + "Value": 101, + "Series": "Office" + }, + { + "Date": "2020-12-27", + "Value": 103, + "Series": "Office" + }, + { + "Date": "2021-01-01", + "Value": 111, + "Series": "Office" + }, + { + "Date": "2021-01-07", + "Value": 116, + "Series": "Office" + }, + { + "Date": "2021-01-12", + "Value": 119, + "Series": "Office" + }, + { + "Date": "2021-01-18", + "Value": 118, + "Series": "Office" + }, + { + "Date": "2021-01-23", + "Value": 117, + "Series": "Office" + }, + { + "Date": "2021-01-29", + "Value": 124, + "Series": "Office" + }, + { + "Date": "2021-02-03", + "Value": 130, + "Series": "Office" + }, + { + "Date": "2021-02-09", + "Value": 130, + "Series": "Office" + }, + { + "Date": "2021-02-14", + "Value": 129, + "Series": "Office" + }, + { + "Date": "2021-02-20", + "Value": 133, + "Series": "Office" + }, + { + "Date": "2021-02-25", + "Value": 138, + "Series": "Office" + }, + { + "Date": "2021-03-03", + "Value": 146, + "Series": "Office" + }, + { + "Date": "2021-03-08", + "Value": 152, + "Series": "Office" + }, + { + "Date": "2021-03-14", + "Value": 149, + "Series": "Office" + }, + { + "Date": "2021-03-19", + "Value": 145, + "Series": "Office" + }, + { + "Date": "2021-03-24", + "Value": 139, + "Series": "Office" + }, + { + "Date": "2021-03-30", + "Value": 128, + "Series": "Office" + }, + { + "Date": "2021-04-04", + "Value": 116, + "Series": "Office" + }, + { + "Date": "2021-04-10", + "Value": 105, + "Series": "Office" + }, + { + "Date": "2021-04-15", + "Value": 90, + "Series": "Office" + }, + { + "Date": "2021-04-21", + "Value": 85, + "Series": "Office" + }, + { + "Date": "2021-04-26", + "Value": 76, + "Series": "Office" + }, + { + "Date": "2021-05-02", + "Value": 68, + "Series": "Office" + }, + { + "Date": "2021-05-07", + "Value": 65, + "Series": "Office" + }, + { + "Date": "2021-05-13", + "Value": 65, + "Series": "Office" + }, + { + "Date": "2021-05-18", + "Value": 62, + "Series": "Office" + }, + { + "Date": "2021-05-24", + "Value": 67, + "Series": "Office" + }, + { + "Date": "2021-05-29", + "Value": 77, + "Series": "Office" + }, + { + "Date": "2021-06-04", + "Value": 81, + "Series": "Office" + }, + { + "Date": "2021-06-09", + "Value": 83, + "Series": "Office" + }, + { + "Date": "2021-06-15", + "Value": 88, + "Series": "Office" + }, + { + "Date": "2021-06-20", + "Value": 84, + "Series": "Office" + }, + { + "Date": "2021-06-26", + "Value": 74, + "Series": "Office" + }, + { + "Date": "2021-07-01", + "Value": 70, + "Series": "Office" + }, + { + "Date": "2021-07-06", + "Value": 65, + "Series": "Office" + }, + { + "Date": "2021-07-12", + "Value": 55, + "Series": "Office" + }, + { + "Date": "2021-07-17", + "Value": 46, + "Series": "Office" + }, + { + "Date": "2021-07-23", + "Value": 36, + "Series": "Office" + }, + { + "Date": "2021-07-28", + "Value": 34, + "Series": "Office" + }, + { + "Date": "2021-08-03", + "Value": 26, + "Series": "Office" + }, + { + "Date": "2021-08-08", + "Value": 24, + "Series": "Office" + }, + { + "Date": "2021-08-14", + "Value": 28, + "Series": "Office" + }, + { + "Date": "2021-08-19", + "Value": 23, + "Series": "Office" + }, + { + "Date": "2021-08-25", + "Value": 23, + "Series": "Office" + }, + { + "Date": "2021-08-30", + "Value": 22, + "Series": "Office" + }, + { + "Date": "2021-09-05", + "Value": 14, + "Series": "Office" + }, + { + "Date": "2021-09-10", + "Value": 12, + "Series": "Office" + }, + { + "Date": "2021-09-16", + "Value": 5, + "Series": "Office" + }, + { + "Date": "2021-09-21", + "Value": 6, + "Series": "Office" + }, + { + "Date": "2021-09-27", + "Value": 7, + "Series": "Office" + }, + { + "Date": "2021-10-02", + "Value": 8, + "Series": "Office" + }, + { + "Date": "2021-10-08", + "Value": 11, + "Series": "Office" + }, + { + "Date": "2021-10-13", + "Value": 10, + "Series": "Office" + }, + { + "Date": "2021-10-19", + "Value": 12, + "Series": "Office" + }, + { + "Date": "2021-10-24", + "Value": 11, + "Series": "Office" + }, + { + "Date": "2021-10-29", + "Value": 18, + "Series": "Office" + }, + { + "Date": "2021-11-04", + "Value": 28, + "Series": "Office" + }, + { + "Date": "2021-11-09", + "Value": 32, + "Series": "Office" + }, + { + "Date": "2021-11-15", + "Value": 35, + "Series": "Office" + }, + { + "Date": "2021-11-20", + "Value": 43, + "Series": "Office" + }, + { + "Date": "2021-11-26", + "Value": 41, + "Series": "Office" + }, + { + "Date": "2021-12-01", + "Value": 42, + "Series": "Office" + }, + { + "Date": "2021-12-07", + "Value": 44, + "Series": "Office" + }, + { + "Date": "2021-12-12", + "Value": 48, + "Series": "Office" + }, + { + "Date": "2021-12-18", + "Value": 44, + "Series": "Office" + }, + { + "Date": "2021-12-23", + "Value": 39, + "Series": "Office" + }, + { + "Date": "2021-12-29", + "Value": 30, + "Series": "Office" + }, + { + "Date": "2022-01-03", + "Value": 23, + "Series": "Office" + }, + { + "Date": "2022-01-09", + "Value": 19, + "Series": "Office" + }, + { + "Date": "2022-01-14", + "Value": 18, + "Series": "Office" + }, + { + "Date": "2022-01-20", + "Value": 14, + "Series": "Office" + }, + { + "Date": "2022-01-25", + "Value": 6, + "Series": "Office" + }, + { + "Date": "2022-01-31", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2022-02-05", + "Value": 2, + "Series": "Office" + }, + { + "Date": "2022-02-10", + "Value": 9, + "Series": "Office" + }, + { + "Date": "2022-02-16", + "Value": 10, + "Series": "Office" + }, + { + "Date": "2022-02-21", + "Value": 18, + "Series": "Office" + }, + { + "Date": "2022-02-27", + "Value": 22, + "Series": "Office" + }, + { + "Date": "2022-03-04", + "Value": 32, + "Series": "Office" + }, + { + "Date": "2022-03-10", + "Value": 39, + "Series": "Office" + }, + { + "Date": "2022-03-15", + "Value": 46, + "Series": "Office" + }, + { + "Date": "2022-03-21", + "Value": 48, + "Series": "Office" + }, + { + "Date": "2022-03-26", + "Value": 45, + "Series": "Office" + }, + { + "Date": "2022-04-01", + "Value": 48, + "Series": "Office" + }, + { + "Date": "2022-04-06", + "Value": 49, + "Series": "Office" + }, + { + "Date": "2022-04-12", + "Value": 46, + "Series": "Office" + }, + { + "Date": "2022-04-17", + "Value": 39, + "Series": "Office" + }, + { + "Date": "2022-04-23", + "Value": 34, + "Series": "Office" + }, + { + "Date": "2022-04-28", + "Value": 24, + "Series": "Office" + }, + { + "Date": "2022-05-04", + "Value": 20, + "Series": "Office" + }, + { + "Date": "2022-05-09", + "Value": 20, + "Series": "Office" + }, + { + "Date": "2022-05-15", + "Value": 19, + "Series": "Office" + }, + { + "Date": "2022-05-20", + "Value": 20, + "Series": "Office" + }, + { + "Date": "2022-05-26", + "Value": 26, + "Series": "Office" + }, + { + "Date": "2022-05-31", + "Value": 29, + "Series": "Office" + }, + { + "Date": "2022-06-05", + "Value": 26, + "Series": "Office" + }, + { + "Date": "2022-06-11", + "Value": 18, + "Series": "Office" + }, + { + "Date": "2022-06-16", + "Value": 8, + "Series": "Office" + }, + { + "Date": "2022-06-22", + "Value": 2, + "Series": "Office" + }, + { + "Date": "2022-06-27", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2022-07-03", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2022-07-08", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2022-07-14", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2022-07-19", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2022-07-25", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2022-07-30", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2022-08-05", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2022-08-10", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2022-08-16", + "Value": 1, + "Series": "Office" + }, + { + "Date": "2022-08-21", + "Value": 7, + "Series": "Office" + }, + { + "Date": "2022-08-27", + "Value": 11, + "Series": "Office" + }, + { + "Date": "2022-09-01", + "Value": 10, + "Series": "Office" + }, + { + "Date": "2022-09-07", + "Value": 3, + "Series": "Office" + }, + { + "Date": "2022-09-12", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2022-09-17", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2022-09-23", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2022-09-28", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2022-10-04", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2022-10-09", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2022-10-15", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2022-10-20", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2022-10-26", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2022-10-31", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2022-11-06", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2022-11-11", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2022-11-17", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2022-11-22", + "Value": 1, + "Series": "Office" + }, + { + "Date": "2022-11-28", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2022-12-03", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2022-12-09", + "Value": 0, + "Series": "Office" + }, + { + "Date": "2022-12-14", + "Value": 5, + "Series": "Office" + }, + { + "Date": "2022-12-20", + "Value": 10, + "Series": "Office" + }, + { + "Date": "2022-12-25", + "Value": 16, + "Series": "Office" + }, + { + "Date": "2020-01-01", + "Value": 111, + "Series": "Pet" + }, + { + "Date": "2020-01-06", + "Value": 122, + "Series": "Pet" + }, + { + "Date": "2020-01-11", + "Value": 140, + "Series": "Pet" + }, + { + "Date": "2020-01-17", + "Value": 135, + "Series": "Pet" + }, + { + "Date": "2020-01-22", + "Value": 120, + "Series": "Pet" + }, + { + "Date": "2020-01-28", + "Value": 115, + "Series": "Pet" + }, + { + "Date": "2020-02-02", + "Value": 117, + "Series": "Pet" + }, + { + "Date": "2020-02-08", + "Value": 132, + "Series": "Pet" + }, + { + "Date": "2020-02-13", + "Value": 131, + "Series": "Pet" + }, + { + "Date": "2020-02-19", + "Value": 143, + "Series": "Pet" + }, + { + "Date": "2020-02-24", + "Value": 160, + "Series": "Pet" + }, + { + "Date": "2020-03-01", + "Value": 174, + "Series": "Pet" + }, + { + "Date": "2020-03-06", + "Value": 201, + "Series": "Pet" + }, + { + "Date": "2020-03-12", + "Value": 235, + "Series": "Pet" + }, + { + "Date": "2020-03-17", + "Value": 266, + "Series": "Pet" + }, + { + "Date": "2020-03-23", + "Value": 283, + "Series": "Pet" + }, + { + "Date": "2020-03-28", + "Value": 306, + "Series": "Pet" + }, + { + "Date": "2020-04-03", + "Value": 325, + "Series": "Pet" + }, + { + "Date": "2020-04-08", + "Value": 338, + "Series": "Pet" + }, + { + "Date": "2020-04-14", + "Value": 349, + "Series": "Pet" + }, + { + "Date": "2020-04-19", + "Value": 371, + "Series": "Pet" + }, + { + "Date": "2020-04-24", + "Value": 405, + "Series": "Pet" + }, + { + "Date": "2020-04-30", + "Value": 435, + "Series": "Pet" + }, + { + "Date": "2020-05-05", + "Value": 447, + "Series": "Pet" + }, + { + "Date": "2020-05-11", + "Value": 451, + "Series": "Pet" + }, + { + "Date": "2020-05-16", + "Value": 444, + "Series": "Pet" + }, + { + "Date": "2020-05-22", + "Value": 431, + "Series": "Pet" + }, + { + "Date": "2020-05-27", + "Value": 440, + "Series": "Pet" + }, + { + "Date": "2020-06-02", + "Value": 458, + "Series": "Pet" + }, + { + "Date": "2020-06-07", + "Value": 460, + "Series": "Pet" + }, + { + "Date": "2020-06-13", + "Value": 468, + "Series": "Pet" + }, + { + "Date": "2020-06-18", + "Value": 477, + "Series": "Pet" + }, + { + "Date": "2020-06-24", + "Value": 497, + "Series": "Pet" + }, + { + "Date": "2020-06-29", + "Value": 507, + "Series": "Pet" + }, + { + "Date": "2020-07-05", + "Value": 502, + "Series": "Pet" + }, + { + "Date": "2020-07-10", + "Value": 516, + "Series": "Pet" + }, + { + "Date": "2020-07-16", + "Value": 517, + "Series": "Pet" + }, + { + "Date": "2020-07-21", + "Value": 527, + "Series": "Pet" + }, + { + "Date": "2020-07-27", + "Value": 517, + "Series": "Pet" + }, + { + "Date": "2020-08-01", + "Value": 498, + "Series": "Pet" + }, + { + "Date": "2020-08-07", + "Value": 479, + "Series": "Pet" + }, + { + "Date": "2020-08-12", + "Value": 452, + "Series": "Pet" + }, + { + "Date": "2020-08-17", + "Value": 438, + "Series": "Pet" + }, + { + "Date": "2020-08-23", + "Value": 434, + "Series": "Pet" + }, + { + "Date": "2020-08-28", + "Value": 434, + "Series": "Pet" + }, + { + "Date": "2020-09-03", + "Value": 444, + "Series": "Pet" + }, + { + "Date": "2020-09-08", + "Value": 448, + "Series": "Pet" + }, + { + "Date": "2020-09-14", + "Value": 452, + "Series": "Pet" + }, + { + "Date": "2020-09-19", + "Value": 458, + "Series": "Pet" + }, + { + "Date": "2020-09-25", + "Value": 481, + "Series": "Pet" + }, + { + "Date": "2020-09-30", + "Value": 494, + "Series": "Pet" + }, + { + "Date": "2020-10-06", + "Value": 487, + "Series": "Pet" + }, + { + "Date": "2020-10-11", + "Value": 486, + "Series": "Pet" + }, + { + "Date": "2020-10-17", + "Value": 478, + "Series": "Pet" + }, + { + "Date": "2020-10-22", + "Value": 468, + "Series": "Pet" + }, + { + "Date": "2020-10-28", + "Value": 447, + "Series": "Pet" + }, + { + "Date": "2020-11-02", + "Value": 442, + "Series": "Pet" + }, + { + "Date": "2020-11-08", + "Value": 457, + "Series": "Pet" + }, + { + "Date": "2020-11-13", + "Value": 478, + "Series": "Pet" + }, + { + "Date": "2020-11-19", + "Value": 481, + "Series": "Pet" + }, + { + "Date": "2020-11-24", + "Value": 487, + "Series": "Pet" + }, + { + "Date": "2020-11-29", + "Value": 495, + "Series": "Pet" + }, + { + "Date": "2020-12-05", + "Value": 500, + "Series": "Pet" + }, + { + "Date": "2020-12-10", + "Value": 522, + "Series": "Pet" + }, + { + "Date": "2020-12-16", + "Value": 540, + "Series": "Pet" + }, + { + "Date": "2020-12-21", + "Value": 554, + "Series": "Pet" + }, + { + "Date": "2020-12-27", + "Value": 571, + "Series": "Pet" + }, + { + "Date": "2021-01-01", + "Value": 593, + "Series": "Pet" + }, + { + "Date": "2021-01-07", + "Value": 604, + "Series": "Pet" + }, + { + "Date": "2021-01-12", + "Value": 603, + "Series": "Pet" + }, + { + "Date": "2021-01-18", + "Value": 597, + "Series": "Pet" + }, + { + "Date": "2021-01-23", + "Value": 598, + "Series": "Pet" + }, + { + "Date": "2021-01-29", + "Value": 616, + "Series": "Pet" + }, + { + "Date": "2021-02-03", + "Value": 609, + "Series": "Pet" + }, + { + "Date": "2021-02-09", + "Value": 607, + "Series": "Pet" + }, + { + "Date": "2021-02-14", + "Value": 622, + "Series": "Pet" + }, + { + "Date": "2021-02-20", + "Value": 623, + "Series": "Pet" + }, + { + "Date": "2021-02-25", + "Value": 640, + "Series": "Pet" + }, + { + "Date": "2021-03-03", + "Value": 655, + "Series": "Pet" + }, + { + "Date": "2021-03-08", + "Value": 674, + "Series": "Pet" + }, + { + "Date": "2021-03-14", + "Value": 697, + "Series": "Pet" + }, + { + "Date": "2021-03-19", + "Value": 732, + "Series": "Pet" + }, + { + "Date": "2021-03-24", + "Value": 770, + "Series": "Pet" + }, + { + "Date": "2021-03-30", + "Value": 795, + "Series": "Pet" + }, + { + "Date": "2021-04-04", + "Value": 805, + "Series": "Pet" + }, + { + "Date": "2021-04-10", + "Value": 802, + "Series": "Pet" + }, + { + "Date": "2021-04-15", + "Value": 782, + "Series": "Pet" + }, + { + "Date": "2021-04-21", + "Value": 762, + "Series": "Pet" + }, + { + "Date": "2021-04-26", + "Value": 730, + "Series": "Pet" + }, + { + "Date": "2021-05-02", + "Value": 712, + "Series": "Pet" + }, + { + "Date": "2021-05-07", + "Value": 686, + "Series": "Pet" + }, + { + "Date": "2021-05-13", + "Value": 675, + "Series": "Pet" + }, + { + "Date": "2021-05-18", + "Value": 685, + "Series": "Pet" + }, + { + "Date": "2021-05-24", + "Value": 699, + "Series": "Pet" + }, + { + "Date": "2021-05-29", + "Value": 703, + "Series": "Pet" + }, + { + "Date": "2021-06-04", + "Value": 724, + "Series": "Pet" + }, + { + "Date": "2021-06-09", + "Value": 758, + "Series": "Pet" + }, + { + "Date": "2021-06-15", + "Value": 787, + "Series": "Pet" + }, + { + "Date": "2021-06-20", + "Value": 797, + "Series": "Pet" + }, + { + "Date": "2021-06-26", + "Value": 786, + "Series": "Pet" + }, + { + "Date": "2021-07-01", + "Value": 776, + "Series": "Pet" + }, + { + "Date": "2021-07-06", + "Value": 759, + "Series": "Pet" + }, + { + "Date": "2021-07-12", + "Value": 743, + "Series": "Pet" + }, + { + "Date": "2021-07-17", + "Value": 716, + "Series": "Pet" + }, + { + "Date": "2021-07-23", + "Value": 681, + "Series": "Pet" + }, + { + "Date": "2021-07-28", + "Value": 655, + "Series": "Pet" + }, + { + "Date": "2021-08-03", + "Value": 624, + "Series": "Pet" + }, + { + "Date": "2021-08-08", + "Value": 616, + "Series": "Pet" + }, + { + "Date": "2021-08-14", + "Value": 610, + "Series": "Pet" + }, + { + "Date": "2021-08-19", + "Value": 587, + "Series": "Pet" + }, + { + "Date": "2021-08-25", + "Value": 564, + "Series": "Pet" + }, + { + "Date": "2021-08-30", + "Value": 533, + "Series": "Pet" + }, + { + "Date": "2021-09-05", + "Value": 500, + "Series": "Pet" + }, + { + "Date": "2021-09-10", + "Value": 486, + "Series": "Pet" + }, + { + "Date": "2021-09-16", + "Value": 492, + "Series": "Pet" + }, + { + "Date": "2021-09-21", + "Value": 509, + "Series": "Pet" + }, + { + "Date": "2021-09-27", + "Value": 507, + "Series": "Pet" + }, + { + "Date": "2021-10-02", + "Value": 487, + "Series": "Pet" + }, + { + "Date": "2021-10-08", + "Value": 460, + "Series": "Pet" + }, + { + "Date": "2021-10-13", + "Value": 424, + "Series": "Pet" + }, + { + "Date": "2021-10-19", + "Value": 380, + "Series": "Pet" + }, + { + "Date": "2021-10-24", + "Value": 366, + "Series": "Pet" + }, + { + "Date": "2021-10-29", + "Value": 359, + "Series": "Pet" + }, + { + "Date": "2021-11-04", + "Value": 357, + "Series": "Pet" + }, + { + "Date": "2021-11-09", + "Value": 353, + "Series": "Pet" + }, + { + "Date": "2021-11-15", + "Value": 368, + "Series": "Pet" + }, + { + "Date": "2021-11-20", + "Value": 376, + "Series": "Pet" + }, + { + "Date": "2021-11-26", + "Value": 398, + "Series": "Pet" + }, + { + "Date": "2021-12-01", + "Value": 399, + "Series": "Pet" + }, + { + "Date": "2021-12-07", + "Value": 391, + "Series": "Pet" + }, + { + "Date": "2021-12-12", + "Value": 371, + "Series": "Pet" + }, + { + "Date": "2021-12-18", + "Value": 347, + "Series": "Pet" + }, + { + "Date": "2021-12-23", + "Value": 319, + "Series": "Pet" + }, + { + "Date": "2021-12-29", + "Value": 298, + "Series": "Pet" + }, + { + "Date": "2022-01-03", + "Value": 271, + "Series": "Pet" + }, + { + "Date": "2022-01-09", + "Value": 254, + "Series": "Pet" + }, + { + "Date": "2022-01-14", + "Value": 229, + "Series": "Pet" + }, + { + "Date": "2022-01-20", + "Value": 194, + "Series": "Pet" + }, + { + "Date": "2022-01-25", + "Value": 175, + "Series": "Pet" + }, + { + "Date": "2022-01-31", + "Value": 177, + "Series": "Pet" + }, + { + "Date": "2022-02-05", + "Value": 170, + "Series": "Pet" + }, + { + "Date": "2022-02-10", + "Value": 177, + "Series": "Pet" + }, + { + "Date": "2022-02-16", + "Value": 199, + "Series": "Pet" + }, + { + "Date": "2022-02-21", + "Value": 213, + "Series": "Pet" + }, + { + "Date": "2022-02-27", + "Value": 212, + "Series": "Pet" + }, + { + "Date": "2022-03-04", + "Value": 202, + "Series": "Pet" + }, + { + "Date": "2022-03-10", + "Value": 194, + "Series": "Pet" + }, + { + "Date": "2022-03-15", + "Value": 173, + "Series": "Pet" + }, + { + "Date": "2022-03-21", + "Value": 160, + "Series": "Pet" + }, + { + "Date": "2022-03-26", + "Value": 140, + "Series": "Pet" + }, + { + "Date": "2022-04-01", + "Value": 131, + "Series": "Pet" + }, + { + "Date": "2022-04-06", + "Value": 128, + "Series": "Pet" + }, + { + "Date": "2022-04-12", + "Value": 111, + "Series": "Pet" + }, + { + "Date": "2022-04-17", + "Value": 96, + "Series": "Pet" + }, + { + "Date": "2022-04-23", + "Value": 104, + "Series": "Pet" + }, + { + "Date": "2022-04-28", + "Value": 119, + "Series": "Pet" + }, + { + "Date": "2022-05-04", + "Value": 136, + "Series": "Pet" + }, + { + "Date": "2022-05-09", + "Value": 156, + "Series": "Pet" + }, + { + "Date": "2022-05-15", + "Value": 175, + "Series": "Pet" + }, + { + "Date": "2022-05-20", + "Value": 197, + "Series": "Pet" + }, + { + "Date": "2022-05-26", + "Value": 227, + "Series": "Pet" + }, + { + "Date": "2022-05-31", + "Value": 229, + "Series": "Pet" + }, + { + "Date": "2022-06-05", + "Value": 248, + "Series": "Pet" + }, + { + "Date": "2022-06-11", + "Value": 242, + "Series": "Pet" + }, + { + "Date": "2022-06-16", + "Value": 223, + "Series": "Pet" + }, + { + "Date": "2022-06-22", + "Value": 200, + "Series": "Pet" + }, + { + "Date": "2022-06-27", + "Value": 167, + "Series": "Pet" + }, + { + "Date": "2022-07-03", + "Value": 145, + "Series": "Pet" + }, + { + "Date": "2022-07-08", + "Value": 127, + "Series": "Pet" + }, + { + "Date": "2022-07-14", + "Value": 111, + "Series": "Pet" + }, + { + "Date": "2022-07-19", + "Value": 105, + "Series": "Pet" + }, + { + "Date": "2022-07-25", + "Value": 87, + "Series": "Pet" + }, + { + "Date": "2022-07-30", + "Value": 66, + "Series": "Pet" + }, + { + "Date": "2022-08-05", + "Value": 51, + "Series": "Pet" + }, + { + "Date": "2022-08-10", + "Value": 33, + "Series": "Pet" + }, + { + "Date": "2022-08-16", + "Value": 38, + "Series": "Pet" + }, + { + "Date": "2022-08-21", + "Value": 25, + "Series": "Pet" + }, + { + "Date": "2022-08-27", + "Value": 6, + "Series": "Pet" + }, + { + "Date": "2022-09-01", + "Value": 0, + "Series": "Pet" + }, + { + "Date": "2022-09-07", + "Value": 0, + "Series": "Pet" + }, + { + "Date": "2022-09-12", + "Value": 0, + "Series": "Pet" + }, + { + "Date": "2022-09-17", + "Value": 0, + "Series": "Pet" + }, + { + "Date": "2022-09-23", + "Value": 0, + "Series": "Pet" + }, + { + "Date": "2022-09-28", + "Value": 10, + "Series": "Pet" + }, + { + "Date": "2022-10-04", + "Value": 34, + "Series": "Pet" + }, + { + "Date": "2022-10-09", + "Value": 70, + "Series": "Pet" + }, + { + "Date": "2022-10-15", + "Value": 92, + "Series": "Pet" + }, + { + "Date": "2022-10-20", + "Value": 88, + "Series": "Pet" + }, + { + "Date": "2022-10-26", + "Value": 82, + "Series": "Pet" + }, + { + "Date": "2022-10-31", + "Value": 62, + "Series": "Pet" + }, + { + "Date": "2022-11-06", + "Value": 58, + "Series": "Pet" + }, + { + "Date": "2022-11-11", + "Value": 50, + "Series": "Pet" + }, + { + "Date": "2022-11-17", + "Value": 54, + "Series": "Pet" + }, + { + "Date": "2022-11-22", + "Value": 76, + "Series": "Pet" + }, + { + "Date": "2022-11-28", + "Value": 96, + "Series": "Pet" + }, + { + "Date": "2022-12-03", + "Value": 126, + "Series": "Pet" + }, + { + "Date": "2022-12-09", + "Value": 165, + "Series": "Pet" + }, + { + "Date": "2022-12-14", + "Value": 182, + "Series": "Pet" + }, + { + "Date": "2022-12-20", + "Value": 176, + "Series": "Pet" + }, + { + "Date": "2022-12-25", + "Value": 162, + "Series": "Pet" + }, + { + "Date": "2020-01-01", + "Value": 181, + "Series": "Baby" + }, + { + "Date": "2020-01-06", + "Value": 172, + "Series": "Baby" + }, + { + "Date": "2020-01-11", + "Value": 161, + "Series": "Baby" + }, + { + "Date": "2020-01-17", + "Value": 164, + "Series": "Baby" + }, + { + "Date": "2020-01-22", + "Value": 163, + "Series": "Baby" + }, + { + "Date": "2020-01-28", + "Value": 155, + "Series": "Baby" + }, + { + "Date": "2020-02-02", + "Value": 136, + "Series": "Baby" + }, + { + "Date": "2020-02-08", + "Value": 117, + "Series": "Baby" + }, + { + "Date": "2020-02-13", + "Value": 109, + "Series": "Baby" + }, + { + "Date": "2020-02-19", + "Value": 112, + "Series": "Baby" + }, + { + "Date": "2020-02-24", + "Value": 105, + "Series": "Baby" + }, + { + "Date": "2020-03-01", + "Value": 99, + "Series": "Baby" + }, + { + "Date": "2020-03-06", + "Value": 84, + "Series": "Baby" + }, + { + "Date": "2020-03-12", + "Value": 60, + "Series": "Baby" + }, + { + "Date": "2020-03-17", + "Value": 31, + "Series": "Baby" + }, + { + "Date": "2020-03-23", + "Value": 18, + "Series": "Baby" + }, + { + "Date": "2020-03-28", + "Value": 0, + "Series": "Baby" + }, + { + "Date": "2020-04-03", + "Value": 0, + "Series": "Baby" + }, + { + "Date": "2020-04-08", + "Value": 0, + "Series": "Baby" + }, + { + "Date": "2020-04-14", + "Value": 0, + "Series": "Baby" + }, + { + "Date": "2020-04-19", + "Value": 0, + "Series": "Baby" + }, + { + "Date": "2020-04-24", + "Value": 0, + "Series": "Baby" + }, + { + "Date": "2020-04-30", + "Value": 0, + "Series": "Baby" + }, + { + "Date": "2020-05-05", + "Value": 0, + "Series": "Baby" + }, + { + "Date": "2020-05-11", + "Value": 0, + "Series": "Baby" + }, + { + "Date": "2020-05-16", + "Value": 2, + "Series": "Baby" + }, + { + "Date": "2020-05-22", + "Value": 13, + "Series": "Baby" + }, + { + "Date": "2020-05-27", + "Value": 28, + "Series": "Baby" + }, + { + "Date": "2020-06-02", + "Value": 39, + "Series": "Baby" + }, + { + "Date": "2020-06-07", + "Value": 37, + "Series": "Baby" + }, + { + "Date": "2020-06-13", + "Value": 33, + "Series": "Baby" + }, + { + "Date": "2020-06-18", + "Value": 26, + "Series": "Baby" + }, + { + "Date": "2020-06-24", + "Value": 28, + "Series": "Baby" + }, + { + "Date": "2020-06-29", + "Value": 26, + "Series": "Baby" + }, + { + "Date": "2020-07-05", + "Value": 19, + "Series": "Baby" + }, + { + "Date": "2020-07-10", + "Value": 22, + "Series": "Baby" + }, + { + "Date": "2020-07-16", + "Value": 31, + "Series": "Baby" + }, + { + "Date": "2020-07-21", + "Value": 42, + "Series": "Baby" + }, + { + "Date": "2020-07-27", + "Value": 35, + "Series": "Baby" + }, + { + "Date": "2020-08-01", + "Value": 32, + "Series": "Baby" + }, + { + "Date": "2020-08-07", + "Value": 29, + "Series": "Baby" + }, + { + "Date": "2020-08-12", + "Value": 36, + "Series": "Baby" + }, + { + "Date": "2020-08-17", + "Value": 51, + "Series": "Baby" + }, + { + "Date": "2020-08-23", + "Value": 60, + "Series": "Baby" + }, + { + "Date": "2020-08-28", + "Value": 73, + "Series": "Baby" + }, + { + "Date": "2020-09-03", + "Value": 70, + "Series": "Baby" + }, + { + "Date": "2020-09-08", + "Value": 64, + "Series": "Baby" + }, + { + "Date": "2020-09-14", + "Value": 54, + "Series": "Baby" + }, + { + "Date": "2020-09-19", + "Value": 42, + "Series": "Baby" + }, + { + "Date": "2020-09-25", + "Value": 48, + "Series": "Baby" + }, + { + "Date": "2020-09-30", + "Value": 50, + "Series": "Baby" + }, + { + "Date": "2020-10-06", + "Value": 48, + "Series": "Baby" + }, + { + "Date": "2020-10-11", + "Value": 44, + "Series": "Baby" + }, + { + "Date": "2020-10-17", + "Value": 56, + "Series": "Baby" + }, + { + "Date": "2020-10-22", + "Value": 58, + "Series": "Baby" + }, + { + "Date": "2020-10-28", + "Value": 58, + "Series": "Baby" + }, + { + "Date": "2020-11-02", + "Value": 59, + "Series": "Baby" + }, + { + "Date": "2020-11-08", + "Value": 70, + "Series": "Baby" + }, + { + "Date": "2020-11-13", + "Value": 66, + "Series": "Baby" + }, + { + "Date": "2020-11-19", + "Value": 54, + "Series": "Baby" + }, + { + "Date": "2020-11-24", + "Value": 55, + "Series": "Baby" + }, + { + "Date": "2020-11-29", + "Value": 54, + "Series": "Baby" + }, + { + "Date": "2020-12-05", + "Value": 40, + "Series": "Baby" + }, + { + "Date": "2020-12-10", + "Value": 16, + "Series": "Baby" + }, + { + "Date": "2020-12-16", + "Value": 0, + "Series": "Baby" + }, + { + "Date": "2020-12-21", + "Value": 0, + "Series": "Baby" + }, + { + "Date": "2020-12-27", + "Value": 0, + "Series": "Baby" + }, + { + "Date": "2021-01-01", + "Value": 0, + "Series": "Baby" + }, + { + "Date": "2021-01-07", + "Value": 0, + "Series": "Baby" + }, + { + "Date": "2021-01-12", + "Value": 0, + "Series": "Baby" + }, + { + "Date": "2021-01-18", + "Value": 0, + "Series": "Baby" + }, + { + "Date": "2021-01-23", + "Value": 7, + "Series": "Baby" + }, + { + "Date": "2021-01-29", + "Value": 5, + "Series": "Baby" + }, + { + "Date": "2021-02-03", + "Value": 8, + "Series": "Baby" + }, + { + "Date": "2021-02-09", + "Value": 2, + "Series": "Baby" + }, + { + "Date": "2021-02-14", + "Value": 0, + "Series": "Baby" + }, + { + "Date": "2021-02-20", + "Value": 0, + "Series": "Baby" + }, + { + "Date": "2021-02-25", + "Value": 0, + "Series": "Baby" + }, + { + "Date": "2021-03-03", + "Value": 11, + "Series": "Baby" + }, + { + "Date": "2021-03-08", + "Value": 32, + "Series": "Baby" + }, + { + "Date": "2021-03-14", + "Value": 34, + "Series": "Baby" + }, + { + "Date": "2021-03-19", + "Value": 43, + "Series": "Baby" + }, + { + "Date": "2021-03-24", + "Value": 61, + "Series": "Baby" + }, + { + "Date": "2021-03-30", + "Value": 60, + "Series": "Baby" + }, + { + "Date": "2021-04-04", + "Value": 60, + "Series": "Baby" + }, + { + "Date": "2021-04-10", + "Value": 73, + "Series": "Baby" + }, + { + "Date": "2021-04-15", + "Value": 91, + "Series": "Baby" + }, + { + "Date": "2021-04-21", + "Value": 105, + "Series": "Baby" + }, + { + "Date": "2021-04-26", + "Value": 125, + "Series": "Baby" + }, + { + "Date": "2021-05-02", + "Value": 138, + "Series": "Baby" + }, + { + "Date": "2021-05-07", + "Value": 145, + "Series": "Baby" + }, + { + "Date": "2021-05-13", + "Value": 144, + "Series": "Baby" + }, + { + "Date": "2021-05-18", + "Value": 142, + "Series": "Baby" + }, + { + "Date": "2021-05-24", + "Value": 155, + "Series": "Baby" + }, + { + "Date": "2021-05-29", + "Value": 166, + "Series": "Baby" + }, + { + "Date": "2021-06-04", + "Value": 184, + "Series": "Baby" + }, + { + "Date": "2021-06-09", + "Value": 194, + "Series": "Baby" + }, + { + "Date": "2021-06-15", + "Value": 212, + "Series": "Baby" + }, + { + "Date": "2021-06-20", + "Value": 212, + "Series": "Baby" + }, + { + "Date": "2021-06-26", + "Value": 204, + "Series": "Baby" + }, + { + "Date": "2021-07-01", + "Value": 201, + "Series": "Baby" + }, + { + "Date": "2021-07-06", + "Value": 200, + "Series": "Baby" + }, + { + "Date": "2021-07-12", + "Value": 205, + "Series": "Baby" + }, + { + "Date": "2021-07-17", + "Value": 210, + "Series": "Baby" + }, + { + "Date": "2021-07-23", + "Value": 221, + "Series": "Baby" + }, + { + "Date": "2021-07-28", + "Value": 233, + "Series": "Baby" + }, + { + "Date": "2021-08-03", + "Value": 236, + "Series": "Baby" + }, + { + "Date": "2021-08-08", + "Value": 240, + "Series": "Baby" + }, + { + "Date": "2021-08-14", + "Value": 250, + "Series": "Baby" + }, + { + "Date": "2021-08-19", + "Value": 252, + "Series": "Baby" + }, + { + "Date": "2021-08-25", + "Value": 248, + "Series": "Baby" + }, + { + "Date": "2021-08-30", + "Value": 254, + "Series": "Baby" + }, + { + "Date": "2021-09-05", + "Value": 261, + "Series": "Baby" + }, + { + "Date": "2021-09-10", + "Value": 253, + "Series": "Baby" + }, + { + "Date": "2021-09-16", + "Value": 255, + "Series": "Baby" + }, + { + "Date": "2021-09-21", + "Value": 260, + "Series": "Baby" + }, + { + "Date": "2021-09-27", + "Value": 258, + "Series": "Baby" + }, + { + "Date": "2021-10-02", + "Value": 251, + "Series": "Baby" + }, + { + "Date": "2021-10-08", + "Value": 252, + "Series": "Baby" + }, + { + "Date": "2021-10-13", + "Value": 255, + "Series": "Baby" + }, + { + "Date": "2021-10-19", + "Value": 256, + "Series": "Baby" + }, + { + "Date": "2021-10-24", + "Value": 248, + "Series": "Baby" + }, + { + "Date": "2021-10-29", + "Value": 238, + "Series": "Baby" + }, + { + "Date": "2021-11-04", + "Value": 222, + "Series": "Baby" + }, + { + "Date": "2021-11-09", + "Value": 198, + "Series": "Baby" + }, + { + "Date": "2021-11-15", + "Value": 167, + "Series": "Baby" + }, + { + "Date": "2021-11-20", + "Value": 139, + "Series": "Baby" + }, + { + "Date": "2021-11-26", + "Value": 118, + "Series": "Baby" + }, + { + "Date": "2021-12-01", + "Value": 107, + "Series": "Baby" + }, + { + "Date": "2021-12-07", + "Value": 112, + "Series": "Baby" + }, + { + "Date": "2021-12-12", + "Value": 123, + "Series": "Baby" + }, + { + "Date": "2021-12-18", + "Value": 126, + "Series": "Baby" + }, + { + "Date": "2021-12-23", + "Value": 134, + "Series": "Baby" + }, + { + "Date": "2021-12-29", + "Value": 129, + "Series": "Baby" + }, + { + "Date": "2022-01-03", + "Value": 112, + "Series": "Baby" + }, + { + "Date": "2022-01-09", + "Value": 115, + "Series": "Baby" + }, + { + "Date": "2022-01-14", + "Value": 106, + "Series": "Baby" + }, + { + "Date": "2022-01-20", + "Value": 105, + "Series": "Baby" + }, + { + "Date": "2022-01-25", + "Value": 111, + "Series": "Baby" + }, + { + "Date": "2022-01-31", + "Value": 105, + "Series": "Baby" + }, + { + "Date": "2022-02-05", + "Value": 106, + "Series": "Baby" + }, + { + "Date": "2022-02-10", + "Value": 101, + "Series": "Baby" + }, + { + "Date": "2022-02-16", + "Value": 97, + "Series": "Baby" + }, + { + "Date": "2022-02-21", + "Value": 92, + "Series": "Baby" + }, + { + "Date": "2022-02-27", + "Value": 88, + "Series": "Baby" + }, + { + "Date": "2022-03-04", + "Value": 81, + "Series": "Baby" + }, + { + "Date": "2022-03-10", + "Value": 82, + "Series": "Baby" + }, + { + "Date": "2022-03-15", + "Value": 79, + "Series": "Baby" + }, + { + "Date": "2022-03-21", + "Value": 83, + "Series": "Baby" + }, + { + "Date": "2022-03-26", + "Value": 84, + "Series": "Baby" + }, + { + "Date": "2022-04-01", + "Value": 81, + "Series": "Baby" + }, + { + "Date": "2022-04-06", + "Value": 93, + "Series": "Baby" + }, + { + "Date": "2022-04-12", + "Value": 98, + "Series": "Baby" + }, + { + "Date": "2022-04-17", + "Value": 96, + "Series": "Baby" + }, + { + "Date": "2022-04-23", + "Value": 90, + "Series": "Baby" + }, + { + "Date": "2022-04-28", + "Value": 88, + "Series": "Baby" + }, + { + "Date": "2022-05-04", + "Value": 90, + "Series": "Baby" + }, + { + "Date": "2022-05-09", + "Value": 94, + "Series": "Baby" + }, + { + "Date": "2022-05-15", + "Value": 110, + "Series": "Baby" + }, + { + "Date": "2022-05-20", + "Value": 118, + "Series": "Baby" + }, + { + "Date": "2022-05-26", + "Value": 125, + "Series": "Baby" + }, + { + "Date": "2022-05-31", + "Value": 135, + "Series": "Baby" + }, + { + "Date": "2022-06-05", + "Value": 133, + "Series": "Baby" + }, + { + "Date": "2022-06-11", + "Value": 119, + "Series": "Baby" + }, + { + "Date": "2022-06-16", + "Value": 98, + "Series": "Baby" + }, + { + "Date": "2022-06-22", + "Value": 81, + "Series": "Baby" + }, + { + "Date": "2022-06-27", + "Value": 56, + "Series": "Baby" + }, + { + "Date": "2022-07-03", + "Value": 52, + "Series": "Baby" + }, + { + "Date": "2022-07-08", + "Value": 45, + "Series": "Baby" + }, + { + "Date": "2022-07-14", + "Value": 54, + "Series": "Baby" + }, + { + "Date": "2022-07-19", + "Value": 69, + "Series": "Baby" + }, + { + "Date": "2022-07-25", + "Value": 90, + "Series": "Baby" + }, + { + "Date": "2022-07-30", + "Value": 100, + "Series": "Baby" + }, + { + "Date": "2022-08-05", + "Value": 101, + "Series": "Baby" + }, + { + "Date": "2022-08-10", + "Value": 109, + "Series": "Baby" + }, + { + "Date": "2022-08-16", + "Value": 111, + "Series": "Baby" + }, + { + "Date": "2022-08-21", + "Value": 126, + "Series": "Baby" + }, + { + "Date": "2022-08-27", + "Value": 124, + "Series": "Baby" + }, + { + "Date": "2022-09-01", + "Value": 123, + "Series": "Baby" + }, + { + "Date": "2022-09-07", + "Value": 111, + "Series": "Baby" + }, + { + "Date": "2022-09-12", + "Value": 117, + "Series": "Baby" + }, + { + "Date": "2022-09-17", + "Value": 127, + "Series": "Baby" + }, + { + "Date": "2022-09-23", + "Value": 127, + "Series": "Baby" + }, + { + "Date": "2022-09-28", + "Value": 119, + "Series": "Baby" + }, + { + "Date": "2022-10-04", + "Value": 104, + "Series": "Baby" + }, + { + "Date": "2022-10-09", + "Value": 79, + "Series": "Baby" + }, + { + "Date": "2022-10-15", + "Value": 57, + "Series": "Baby" + }, + { + "Date": "2022-10-20", + "Value": 50, + "Series": "Baby" + }, + { + "Date": "2022-10-26", + "Value": 36, + "Series": "Baby" + }, + { + "Date": "2022-10-31", + "Value": 25, + "Series": "Baby" + }, + { + "Date": "2022-11-06", + "Value": 29, + "Series": "Baby" + }, + { + "Date": "2022-11-11", + "Value": 44, + "Series": "Baby" + }, + { + "Date": "2022-11-17", + "Value": 66, + "Series": "Baby" + }, + { + "Date": "2022-11-22", + "Value": 81, + "Series": "Baby" + }, + { + "Date": "2022-11-28", + "Value": 83, + "Series": "Baby" + }, + { + "Date": "2022-12-03", + "Value": 87, + "Series": "Baby" + }, + { + "Date": "2022-12-09", + "Value": 99, + "Series": "Baby" + }, + { + "Date": "2022-12-14", + "Value": 119, + "Series": "Baby" + }, + { + "Date": "2022-12-20", + "Value": 121, + "Series": "Baby" + }, + { + "Date": "2022-12-25", + "Value": 124, + "Series": "Baby" + }, + { + "Date": "2020-01-01", + "Value": 74, + "Series": "Tools" + }, + { + "Date": "2020-01-06", + "Value": 87, + "Series": "Tools" + }, + { + "Date": "2020-01-11", + "Value": 96, + "Series": "Tools" + }, + { + "Date": "2020-01-17", + "Value": 90, + "Series": "Tools" + }, + { + "Date": "2020-01-22", + "Value": 74, + "Series": "Tools" + }, + { + "Date": "2020-01-28", + "Value": 60, + "Series": "Tools" + }, + { + "Date": "2020-02-02", + "Value": 48, + "Series": "Tools" + }, + { + "Date": "2020-02-08", + "Value": 54, + "Series": "Tools" + }, + { + "Date": "2020-02-13", + "Value": 65, + "Series": "Tools" + }, + { + "Date": "2020-02-19", + "Value": 83, + "Series": "Tools" + }, + { + "Date": "2020-02-24", + "Value": 88, + "Series": "Tools" + }, + { + "Date": "2020-03-01", + "Value": 104, + "Series": "Tools" + }, + { + "Date": "2020-03-06", + "Value": 104, + "Series": "Tools" + }, + { + "Date": "2020-03-12", + "Value": 99, + "Series": "Tools" + }, + { + "Date": "2020-03-17", + "Value": 99, + "Series": "Tools" + }, + { + "Date": "2020-03-23", + "Value": 113, + "Series": "Tools" + }, + { + "Date": "2020-03-28", + "Value": 114, + "Series": "Tools" + }, + { + "Date": "2020-04-03", + "Value": 110, + "Series": "Tools" + }, + { + "Date": "2020-04-08", + "Value": 106, + "Series": "Tools" + }, + { + "Date": "2020-04-14", + "Value": 97, + "Series": "Tools" + }, + { + "Date": "2020-04-19", + "Value": 93, + "Series": "Tools" + }, + { + "Date": "2020-04-24", + "Value": 86, + "Series": "Tools" + }, + { + "Date": "2020-04-30", + "Value": 80, + "Series": "Tools" + }, + { + "Date": "2020-05-05", + "Value": 72, + "Series": "Tools" + }, + { + "Date": "2020-05-11", + "Value": 55, + "Series": "Tools" + }, + { + "Date": "2020-05-16", + "Value": 58, + "Series": "Tools" + }, + { + "Date": "2020-05-22", + "Value": 64, + "Series": "Tools" + }, + { + "Date": "2020-05-27", + "Value": 72, + "Series": "Tools" + }, + { + "Date": "2020-06-02", + "Value": 83, + "Series": "Tools" + }, + { + "Date": "2020-06-07", + "Value": 100, + "Series": "Tools" + }, + { + "Date": "2020-06-13", + "Value": 106, + "Series": "Tools" + }, + { + "Date": "2020-06-18", + "Value": 104, + "Series": "Tools" + }, + { + "Date": "2020-06-24", + "Value": 110, + "Series": "Tools" + }, + { + "Date": "2020-06-29", + "Value": 114, + "Series": "Tools" + }, + { + "Date": "2020-07-05", + "Value": 121, + "Series": "Tools" + }, + { + "Date": "2020-07-10", + "Value": 128, + "Series": "Tools" + }, + { + "Date": "2020-07-16", + "Value": 124, + "Series": "Tools" + }, + { + "Date": "2020-07-21", + "Value": 128, + "Series": "Tools" + }, + { + "Date": "2020-07-27", + "Value": 125, + "Series": "Tools" + }, + { + "Date": "2020-08-01", + "Value": 125, + "Series": "Tools" + }, + { + "Date": "2020-08-07", + "Value": 132, + "Series": "Tools" + }, + { + "Date": "2020-08-12", + "Value": 128, + "Series": "Tools" + }, + { + "Date": "2020-08-17", + "Value": 127, + "Series": "Tools" + }, + { + "Date": "2020-08-23", + "Value": 122, + "Series": "Tools" + }, + { + "Date": "2020-08-28", + "Value": 119, + "Series": "Tools" + }, + { + "Date": "2020-09-03", + "Value": 103, + "Series": "Tools" + }, + { + "Date": "2020-09-08", + "Value": 94, + "Series": "Tools" + }, + { + "Date": "2020-09-14", + "Value": 84, + "Series": "Tools" + }, + { + "Date": "2020-09-19", + "Value": 75, + "Series": "Tools" + }, + { + "Date": "2020-09-25", + "Value": 66, + "Series": "Tools" + }, + { + "Date": "2020-09-30", + "Value": 66, + "Series": "Tools" + }, + { + "Date": "2020-10-06", + "Value": 80, + "Series": "Tools" + }, + { + "Date": "2020-10-11", + "Value": 97, + "Series": "Tools" + }, + { + "Date": "2020-10-17", + "Value": 110, + "Series": "Tools" + }, + { + "Date": "2020-10-22", + "Value": 133, + "Series": "Tools" + }, + { + "Date": "2020-10-28", + "Value": 140, + "Series": "Tools" + }, + { + "Date": "2020-11-02", + "Value": 154, + "Series": "Tools" + }, + { + "Date": "2020-11-08", + "Value": 163, + "Series": "Tools" + }, + { + "Date": "2020-11-13", + "Value": 161, + "Series": "Tools" + }, + { + "Date": "2020-11-19", + "Value": 156, + "Series": "Tools" + }, + { + "Date": "2020-11-24", + "Value": 145, + "Series": "Tools" + }, + { + "Date": "2020-11-29", + "Value": 137, + "Series": "Tools" + }, + { + "Date": "2020-12-05", + "Value": 139, + "Series": "Tools" + }, + { + "Date": "2020-12-10", + "Value": 133, + "Series": "Tools" + }, + { + "Date": "2020-12-16", + "Value": 135, + "Series": "Tools" + }, + { + "Date": "2020-12-21", + "Value": 126, + "Series": "Tools" + }, + { + "Date": "2020-12-27", + "Value": 111, + "Series": "Tools" + }, + { + "Date": "2021-01-01", + "Value": 105, + "Series": "Tools" + }, + { + "Date": "2021-01-07", + "Value": 94, + "Series": "Tools" + }, + { + "Date": "2021-01-12", + "Value": 74, + "Series": "Tools" + }, + { + "Date": "2021-01-18", + "Value": 67, + "Series": "Tools" + }, + { + "Date": "2021-01-23", + "Value": 68, + "Series": "Tools" + }, + { + "Date": "2021-01-29", + "Value": 56, + "Series": "Tools" + }, + { + "Date": "2021-02-03", + "Value": 41, + "Series": "Tools" + }, + { + "Date": "2021-02-09", + "Value": 29, + "Series": "Tools" + }, + { + "Date": "2021-02-14", + "Value": 34, + "Series": "Tools" + }, + { + "Date": "2021-02-20", + "Value": 44, + "Series": "Tools" + }, + { + "Date": "2021-02-25", + "Value": 51, + "Series": "Tools" + }, + { + "Date": "2021-03-03", + "Value": 51, + "Series": "Tools" + }, + { + "Date": "2021-03-08", + "Value": 60, + "Series": "Tools" + }, + { + "Date": "2021-03-14", + "Value": 72, + "Series": "Tools" + }, + { + "Date": "2021-03-19", + "Value": 92, + "Series": "Tools" + }, + { + "Date": "2021-03-24", + "Value": 119, + "Series": "Tools" + }, + { + "Date": "2021-03-30", + "Value": 146, + "Series": "Tools" + }, + { + "Date": "2021-04-04", + "Value": 171, + "Series": "Tools" + }, + { + "Date": "2021-04-10", + "Value": 194, + "Series": "Tools" + }, + { + "Date": "2021-04-15", + "Value": 222, + "Series": "Tools" + }, + { + "Date": "2021-04-21", + "Value": 234, + "Series": "Tools" + }, + { + "Date": "2021-04-26", + "Value": 246, + "Series": "Tools" + }, + { + "Date": "2021-05-02", + "Value": 244, + "Series": "Tools" + }, + { + "Date": "2021-05-07", + "Value": 238, + "Series": "Tools" + }, + { + "Date": "2021-05-13", + "Value": 229, + "Series": "Tools" + }, + { + "Date": "2021-05-18", + "Value": 209, + "Series": "Tools" + }, + { + "Date": "2021-05-24", + "Value": 203, + "Series": "Tools" + }, + { + "Date": "2021-05-29", + "Value": 203, + "Series": "Tools" + }, + { + "Date": "2021-06-04", + "Value": 201, + "Series": "Tools" + }, + { + "Date": "2021-06-09", + "Value": 214, + "Series": "Tools" + }, + { + "Date": "2021-06-15", + "Value": 216, + "Series": "Tools" + }, + { + "Date": "2021-06-20", + "Value": 206, + "Series": "Tools" + }, + { + "Date": "2021-06-26", + "Value": 207, + "Series": "Tools" + }, + { + "Date": "2021-07-01", + "Value": 207, + "Series": "Tools" + }, + { + "Date": "2021-07-06", + "Value": 212, + "Series": "Tools" + }, + { + "Date": "2021-07-12", + "Value": 205, + "Series": "Tools" + }, + { + "Date": "2021-07-17", + "Value": 200, + "Series": "Tools" + }, + { + "Date": "2021-07-23", + "Value": 184, + "Series": "Tools" + }, + { + "Date": "2021-07-28", + "Value": 184, + "Series": "Tools" + }, + { + "Date": "2021-08-03", + "Value": 177, + "Series": "Tools" + }, + { + "Date": "2021-08-08", + "Value": 176, + "Series": "Tools" + }, + { + "Date": "2021-08-14", + "Value": 171, + "Series": "Tools" + }, + { + "Date": "2021-08-19", + "Value": 161, + "Series": "Tools" + }, + { + "Date": "2021-08-25", + "Value": 144, + "Series": "Tools" + }, + { + "Date": "2021-08-30", + "Value": 135, + "Series": "Tools" + }, + { + "Date": "2021-09-05", + "Value": 122, + "Series": "Tools" + }, + { + "Date": "2021-09-10", + "Value": 104, + "Series": "Tools" + }, + { + "Date": "2021-09-16", + "Value": 86, + "Series": "Tools" + }, + { + "Date": "2021-09-21", + "Value": 81, + "Series": "Tools" + }, + { + "Date": "2021-09-27", + "Value": 65, + "Series": "Tools" + }, + { + "Date": "2021-10-02", + "Value": 59, + "Series": "Tools" + }, + { + "Date": "2021-10-08", + "Value": 61, + "Series": "Tools" + }, + { + "Date": "2021-10-13", + "Value": 59, + "Series": "Tools" + }, + { + "Date": "2021-10-19", + "Value": 47, + "Series": "Tools" + }, + { + "Date": "2021-10-24", + "Value": 53, + "Series": "Tools" + }, + { + "Date": "2021-10-29", + "Value": 51, + "Series": "Tools" + }, + { + "Date": "2021-11-04", + "Value": 59, + "Series": "Tools" + }, + { + "Date": "2021-11-09", + "Value": 56, + "Series": "Tools" + }, + { + "Date": "2021-11-15", + "Value": 47, + "Series": "Tools" + }, + { + "Date": "2021-11-20", + "Value": 28, + "Series": "Tools" + }, + { + "Date": "2021-11-26", + "Value": 6, + "Series": "Tools" + }, + { + "Date": "2021-12-01", + "Value": 0, + "Series": "Tools" + }, + { + "Date": "2021-12-07", + "Value": 0, + "Series": "Tools" + }, + { + "Date": "2021-12-12", + "Value": 0, + "Series": "Tools" + }, + { + "Date": "2021-12-18", + "Value": 0, + "Series": "Tools" + }, + { + "Date": "2021-12-23", + "Value": 3, + "Series": "Tools" + }, + { + "Date": "2021-12-29", + "Value": 11, + "Series": "Tools" + }, + { + "Date": "2022-01-03", + "Value": 29, + "Series": "Tools" + }, + { + "Date": "2022-01-09", + "Value": 54, + "Series": "Tools" + }, + { + "Date": "2022-01-14", + "Value": 63, + "Series": "Tools" + }, + { + "Date": "2022-01-20", + "Value": 69, + "Series": "Tools" + }, + { + "Date": "2022-01-25", + "Value": 62, + "Series": "Tools" + }, + { + "Date": "2022-01-31", + "Value": 51, + "Series": "Tools" + }, + { + "Date": "2022-02-05", + "Value": 37, + "Series": "Tools" + }, + { + "Date": "2022-02-10", + "Value": 14, + "Series": "Tools" + }, + { + "Date": "2022-02-16", + "Value": 0, + "Series": "Tools" + }, + { + "Date": "2022-02-21", + "Value": 0, + "Series": "Tools" + }, + { + "Date": "2022-02-27", + "Value": 0, + "Series": "Tools" + }, + { + "Date": "2022-03-04", + "Value": 0, + "Series": "Tools" + }, + { + "Date": "2022-03-10", + "Value": 0, + "Series": "Tools" + }, + { + "Date": "2022-03-15", + "Value": 4, + "Series": "Tools" + }, + { + "Date": "2022-03-21", + "Value": 12, + "Series": "Tools" + }, + { + "Date": "2022-03-26", + "Value": 21, + "Series": "Tools" + }, + { + "Date": "2022-04-01", + "Value": 35, + "Series": "Tools" + }, + { + "Date": "2022-04-06", + "Value": 40, + "Series": "Tools" + }, + { + "Date": "2022-04-12", + "Value": 57, + "Series": "Tools" + }, + { + "Date": "2022-04-17", + "Value": 82, + "Series": "Tools" + }, + { + "Date": "2022-04-23", + "Value": 89, + "Series": "Tools" + }, + { + "Date": "2022-04-28", + "Value": 107, + "Series": "Tools" + }, + { + "Date": "2022-05-04", + "Value": 131, + "Series": "Tools" + }, + { + "Date": "2022-05-09", + "Value": 134, + "Series": "Tools" + }, + { + "Date": "2022-05-15", + "Value": 149, + "Series": "Tools" + }, + { + "Date": "2022-05-20", + "Value": 150, + "Series": "Tools" + }, + { + "Date": "2022-05-26", + "Value": 163, + "Series": "Tools" + }, + { + "Date": "2022-05-31", + "Value": 158, + "Series": "Tools" + }, + { + "Date": "2022-06-05", + "Value": 150, + "Series": "Tools" + }, + { + "Date": "2022-06-11", + "Value": 140, + "Series": "Tools" + }, + { + "Date": "2022-06-16", + "Value": 128, + "Series": "Tools" + }, + { + "Date": "2022-06-22", + "Value": 118, + "Series": "Tools" + }, + { + "Date": "2022-06-27", + "Value": 126, + "Series": "Tools" + }, + { + "Date": "2022-07-03", + "Value": 142, + "Series": "Tools" + }, + { + "Date": "2022-07-08", + "Value": 139, + "Series": "Tools" + }, + { + "Date": "2022-07-14", + "Value": 141, + "Series": "Tools" + }, + { + "Date": "2022-07-19", + "Value": 142, + "Series": "Tools" + }, + { + "Date": "2022-07-25", + "Value": 151, + "Series": "Tools" + }, + { + "Date": "2022-07-30", + "Value": 154, + "Series": "Tools" + }, + { + "Date": "2022-08-05", + "Value": 167, + "Series": "Tools" + }, + { + "Date": "2022-08-10", + "Value": 170, + "Series": "Tools" + }, + { + "Date": "2022-08-16", + "Value": 179, + "Series": "Tools" + }, + { + "Date": "2022-08-21", + "Value": 190, + "Series": "Tools" + }, + { + "Date": "2022-08-27", + "Value": 210, + "Series": "Tools" + }, + { + "Date": "2022-09-01", + "Value": 224, + "Series": "Tools" + }, + { + "Date": "2022-09-07", + "Value": 239, + "Series": "Tools" + }, + { + "Date": "2022-09-12", + "Value": 254, + "Series": "Tools" + }, + { + "Date": "2022-09-17", + "Value": 257, + "Series": "Tools" + }, + { + "Date": "2022-09-23", + "Value": 259, + "Series": "Tools" + }, + { + "Date": "2022-09-28", + "Value": 254, + "Series": "Tools" + }, + { + "Date": "2022-10-04", + "Value": 253, + "Series": "Tools" + }, + { + "Date": "2022-10-09", + "Value": 248, + "Series": "Tools" + }, + { + "Date": "2022-10-15", + "Value": 252, + "Series": "Tools" + }, + { + "Date": "2022-10-20", + "Value": 245, + "Series": "Tools" + }, + { + "Date": "2022-10-26", + "Value": 227, + "Series": "Tools" + }, + { + "Date": "2022-10-31", + "Value": 212, + "Series": "Tools" + }, + { + "Date": "2022-11-06", + "Value": 205, + "Series": "Tools" + }, + { + "Date": "2022-11-11", + "Value": 210, + "Series": "Tools" + }, + { + "Date": "2022-11-17", + "Value": 226, + "Series": "Tools" + }, + { + "Date": "2022-11-22", + "Value": 226, + "Series": "Tools" + }, + { + "Date": "2022-11-28", + "Value": 238, + "Series": "Tools" + }, + { + "Date": "2022-12-03", + "Value": 233, + "Series": "Tools" + }, + { + "Date": "2022-12-09", + "Value": 243, + "Series": "Tools" + }, + { + "Date": "2022-12-14", + "Value": 256, + "Series": "Tools" + }, + { + "Date": "2022-12-20", + "Value": 274, + "Series": "Tools" + }, + { + "Date": "2022-12-25", + "Value": 284, + "Series": "Tools" + }, + { + "Date": "2020-01-01", + "Value": 242, + "Series": "Crafts" + }, + { + "Date": "2020-01-06", + "Value": 239, + "Series": "Crafts" + }, + { + "Date": "2020-01-11", + "Value": 235, + "Series": "Crafts" + }, + { + "Date": "2020-01-17", + "Value": 235, + "Series": "Crafts" + }, + { + "Date": "2020-01-22", + "Value": 226, + "Series": "Crafts" + }, + { + "Date": "2020-01-28", + "Value": 216, + "Series": "Crafts" + }, + { + "Date": "2020-02-02", + "Value": 212, + "Series": "Crafts" + }, + { + "Date": "2020-02-08", + "Value": 204, + "Series": "Crafts" + }, + { + "Date": "2020-02-13", + "Value": 204, + "Series": "Crafts" + }, + { + "Date": "2020-02-19", + "Value": 209, + "Series": "Crafts" + }, + { + "Date": "2020-02-24", + "Value": 204, + "Series": "Crafts" + }, + { + "Date": "2020-03-01", + "Value": 194, + "Series": "Crafts" + }, + { + "Date": "2020-03-06", + "Value": 178, + "Series": "Crafts" + }, + { + "Date": "2020-03-12", + "Value": 168, + "Series": "Crafts" + }, + { + "Date": "2020-03-17", + "Value": 161, + "Series": "Crafts" + }, + { + "Date": "2020-03-23", + "Value": 155, + "Series": "Crafts" + }, + { + "Date": "2020-03-28", + "Value": 146, + "Series": "Crafts" + }, + { + "Date": "2020-04-03", + "Value": 137, + "Series": "Crafts" + }, + { + "Date": "2020-04-08", + "Value": 137, + "Series": "Crafts" + }, + { + "Date": "2020-04-14", + "Value": 139, + "Series": "Crafts" + }, + { + "Date": "2020-04-19", + "Value": 143, + "Series": "Crafts" + }, + { + "Date": "2020-04-24", + "Value": 154, + "Series": "Crafts" + }, + { + "Date": "2020-04-30", + "Value": 157, + "Series": "Crafts" + }, + { + "Date": "2020-05-05", + "Value": 161, + "Series": "Crafts" + }, + { + "Date": "2020-05-11", + "Value": 170, + "Series": "Crafts" + }, + { + "Date": "2020-05-16", + "Value": 169, + "Series": "Crafts" + }, + { + "Date": "2020-05-22", + "Value": 168, + "Series": "Crafts" + }, + { + "Date": "2020-05-27", + "Value": 160, + "Series": "Crafts" + }, + { + "Date": "2020-06-02", + "Value": 154, + "Series": "Crafts" + }, + { + "Date": "2020-06-07", + "Value": 153, + "Series": "Crafts" + }, + { + "Date": "2020-06-13", + "Value": 149, + "Series": "Crafts" + }, + { + "Date": "2020-06-18", + "Value": 153, + "Series": "Crafts" + }, + { + "Date": "2020-06-24", + "Value": 163, + "Series": "Crafts" + }, + { + "Date": "2020-06-29", + "Value": 176, + "Series": "Crafts" + }, + { + "Date": "2020-07-05", + "Value": 178, + "Series": "Crafts" + }, + { + "Date": "2020-07-10", + "Value": 172, + "Series": "Crafts" + }, + { + "Date": "2020-07-16", + "Value": 166, + "Series": "Crafts" + }, + { + "Date": "2020-07-21", + "Value": 157, + "Series": "Crafts" + }, + { + "Date": "2020-07-27", + "Value": 148, + "Series": "Crafts" + }, + { + "Date": "2020-08-01", + "Value": 147, + "Series": "Crafts" + }, + { + "Date": "2020-08-07", + "Value": 148, + "Series": "Crafts" + }, + { + "Date": "2020-08-12", + "Value": 156, + "Series": "Crafts" + }, + { + "Date": "2020-08-17", + "Value": 158, + "Series": "Crafts" + }, + { + "Date": "2020-08-23", + "Value": 151, + "Series": "Crafts" + }, + { + "Date": "2020-08-28", + "Value": 151, + "Series": "Crafts" + }, + { + "Date": "2020-09-03", + "Value": 143, + "Series": "Crafts" + }, + { + "Date": "2020-09-08", + "Value": 135, + "Series": "Crafts" + }, + { + "Date": "2020-09-14", + "Value": 132, + "Series": "Crafts" + }, + { + "Date": "2020-09-19", + "Value": 132, + "Series": "Crafts" + }, + { + "Date": "2020-09-25", + "Value": 137, + "Series": "Crafts" + }, + { + "Date": "2020-09-30", + "Value": 149, + "Series": "Crafts" + }, + { + "Date": "2020-10-06", + "Value": 157, + "Series": "Crafts" + }, + { + "Date": "2020-10-11", + "Value": 156, + "Series": "Crafts" + }, + { + "Date": "2020-10-17", + "Value": 161, + "Series": "Crafts" + }, + { + "Date": "2020-10-22", + "Value": 170, + "Series": "Crafts" + }, + { + "Date": "2020-10-28", + "Value": 172, + "Series": "Crafts" + }, + { + "Date": "2020-11-02", + "Value": 177, + "Series": "Crafts" + }, + { + "Date": "2020-11-08", + "Value": 177, + "Series": "Crafts" + }, + { + "Date": "2020-11-13", + "Value": 170, + "Series": "Crafts" + }, + { + "Date": "2020-11-19", + "Value": 162, + "Series": "Crafts" + }, + { + "Date": "2020-11-24", + "Value": 162, + "Series": "Crafts" + }, + { + "Date": "2020-11-29", + "Value": 153, + "Series": "Crafts" + }, + { + "Date": "2020-12-05", + "Value": 154, + "Series": "Crafts" + }, + { + "Date": "2020-12-10", + "Value": 152, + "Series": "Crafts" + }, + { + "Date": "2020-12-16", + "Value": 152, + "Series": "Crafts" + }, + { + "Date": "2020-12-21", + "Value": 146, + "Series": "Crafts" + }, + { + "Date": "2020-12-27", + "Value": 149, + "Series": "Crafts" + }, + { + "Date": "2021-01-01", + "Value": 151, + "Series": "Crafts" + }, + { + "Date": "2021-01-07", + "Value": 153, + "Series": "Crafts" + }, + { + "Date": "2021-01-12", + "Value": 158, + "Series": "Crafts" + }, + { + "Date": "2021-01-18", + "Value": 162, + "Series": "Crafts" + }, + { + "Date": "2021-01-23", + "Value": 162, + "Series": "Crafts" + }, + { + "Date": "2021-01-29", + "Value": 159, + "Series": "Crafts" + }, + { + "Date": "2021-02-03", + "Value": 160, + "Series": "Crafts" + }, + { + "Date": "2021-02-09", + "Value": 159, + "Series": "Crafts" + }, + { + "Date": "2021-02-14", + "Value": 150, + "Series": "Crafts" + }, + { + "Date": "2021-02-20", + "Value": 137, + "Series": "Crafts" + }, + { + "Date": "2021-02-25", + "Value": 137, + "Series": "Crafts" + }, + { + "Date": "2021-03-03", + "Value": 144, + "Series": "Crafts" + }, + { + "Date": "2021-03-08", + "Value": 148, + "Series": "Crafts" + }, + { + "Date": "2021-03-14", + "Value": 150, + "Series": "Crafts" + }, + { + "Date": "2021-03-19", + "Value": 149, + "Series": "Crafts" + }, + { + "Date": "2021-03-24", + "Value": 148, + "Series": "Crafts" + }, + { + "Date": "2021-03-30", + "Value": 156, + "Series": "Crafts" + }, + { + "Date": "2021-04-04", + "Value": 169, + "Series": "Crafts" + }, + { + "Date": "2021-04-10", + "Value": 171, + "Series": "Crafts" + }, + { + "Date": "2021-04-15", + "Value": 174, + "Series": "Crafts" + }, + { + "Date": "2021-04-21", + "Value": 184, + "Series": "Crafts" + }, + { + "Date": "2021-04-26", + "Value": 184, + "Series": "Crafts" + }, + { + "Date": "2021-05-02", + "Value": 193, + "Series": "Crafts" + }, + { + "Date": "2021-05-07", + "Value": 202, + "Series": "Crafts" + }, + { + "Date": "2021-05-13", + "Value": 210, + "Series": "Crafts" + }, + { + "Date": "2021-05-18", + "Value": 207, + "Series": "Crafts" + }, + { + "Date": "2021-05-24", + "Value": 212, + "Series": "Crafts" + }, + { + "Date": "2021-05-29", + "Value": 207, + "Series": "Crafts" + }, + { + "Date": "2021-06-04", + "Value": 199, + "Series": "Crafts" + }, + { + "Date": "2021-06-09", + "Value": 190, + "Series": "Crafts" + }, + { + "Date": "2021-06-15", + "Value": 187, + "Series": "Crafts" + }, + { + "Date": "2021-06-20", + "Value": 191, + "Series": "Crafts" + }, + { + "Date": "2021-06-26", + "Value": 191, + "Series": "Crafts" + }, + { + "Date": "2021-07-01", + "Value": 186, + "Series": "Crafts" + }, + { + "Date": "2021-07-06", + "Value": 185, + "Series": "Crafts" + }, + { + "Date": "2021-07-12", + "Value": 180, + "Series": "Crafts" + }, + { + "Date": "2021-07-17", + "Value": 176, + "Series": "Crafts" + }, + { + "Date": "2021-07-23", + "Value": 169, + "Series": "Crafts" + }, + { + "Date": "2021-07-28", + "Value": 159, + "Series": "Crafts" + }, + { + "Date": "2021-08-03", + "Value": 154, + "Series": "Crafts" + }, + { + "Date": "2021-08-08", + "Value": 144, + "Series": "Crafts" + }, + { + "Date": "2021-08-14", + "Value": 141, + "Series": "Crafts" + }, + { + "Date": "2021-08-19", + "Value": 132, + "Series": "Crafts" + }, + { + "Date": "2021-08-25", + "Value": 134, + "Series": "Crafts" + }, + { + "Date": "2021-08-30", + "Value": 136, + "Series": "Crafts" + }, + { + "Date": "2021-09-05", + "Value": 131, + "Series": "Crafts" + }, + { + "Date": "2021-09-10", + "Value": 131, + "Series": "Crafts" + }, + { + "Date": "2021-09-16", + "Value": 139, + "Series": "Crafts" + }, + { + "Date": "2021-09-21", + "Value": 142, + "Series": "Crafts" + }, + { + "Date": "2021-09-27", + "Value": 137, + "Series": "Crafts" + }, + { + "Date": "2021-10-02", + "Value": 127, + "Series": "Crafts" + }, + { + "Date": "2021-10-08", + "Value": 112, + "Series": "Crafts" + }, + { + "Date": "2021-10-13", + "Value": 94, + "Series": "Crafts" + }, + { + "Date": "2021-10-19", + "Value": 75, + "Series": "Crafts" + }, + { + "Date": "2021-10-24", + "Value": 64, + "Series": "Crafts" + }, + { + "Date": "2021-10-29", + "Value": 64, + "Series": "Crafts" + }, + { + "Date": "2021-11-04", + "Value": 71, + "Series": "Crafts" + }, + { + "Date": "2021-11-09", + "Value": 70, + "Series": "Crafts" + }, + { + "Date": "2021-11-15", + "Value": 73, + "Series": "Crafts" + }, + { + "Date": "2021-11-20", + "Value": 74, + "Series": "Crafts" + }, + { + "Date": "2021-11-26", + "Value": 70, + "Series": "Crafts" + }, + { + "Date": "2021-12-01", + "Value": 74, + "Series": "Crafts" + }, + { + "Date": "2021-12-07", + "Value": 79, + "Series": "Crafts" + }, + { + "Date": "2021-12-12", + "Value": 77, + "Series": "Crafts" + }, + { + "Date": "2021-12-18", + "Value": 73, + "Series": "Crafts" + }, + { + "Date": "2021-12-23", + "Value": 78, + "Series": "Crafts" + }, + { + "Date": "2021-12-29", + "Value": 79, + "Series": "Crafts" + }, + { + "Date": "2022-01-03", + "Value": 81, + "Series": "Crafts" + }, + { + "Date": "2022-01-09", + "Value": 75, + "Series": "Crafts" + }, + { + "Date": "2022-01-14", + "Value": 78, + "Series": "Crafts" + }, + { + "Date": "2022-01-20", + "Value": 74, + "Series": "Crafts" + }, + { + "Date": "2022-01-25", + "Value": 63, + "Series": "Crafts" + }, + { + "Date": "2022-01-31", + "Value": 50, + "Series": "Crafts" + }, + { + "Date": "2022-02-05", + "Value": 38, + "Series": "Crafts" + }, + { + "Date": "2022-02-10", + "Value": 27, + "Series": "Crafts" + }, + { + "Date": "2022-02-16", + "Value": 26, + "Series": "Crafts" + }, + { + "Date": "2022-02-21", + "Value": 27, + "Series": "Crafts" + }, + { + "Date": "2022-02-27", + "Value": 29, + "Series": "Crafts" + }, + { + "Date": "2022-03-04", + "Value": 38, + "Series": "Crafts" + }, + { + "Date": "2022-03-10", + "Value": 49, + "Series": "Crafts" + }, + { + "Date": "2022-03-15", + "Value": 56, + "Series": "Crafts" + }, + { + "Date": "2022-03-21", + "Value": 69, + "Series": "Crafts" + }, + { + "Date": "2022-03-26", + "Value": 77, + "Series": "Crafts" + }, + { + "Date": "2022-04-01", + "Value": 75, + "Series": "Crafts" + }, + { + "Date": "2022-04-06", + "Value": 65, + "Series": "Crafts" + }, + { + "Date": "2022-04-12", + "Value": 61, + "Series": "Crafts" + }, + { + "Date": "2022-04-17", + "Value": 66, + "Series": "Crafts" + }, + { + "Date": "2022-04-23", + "Value": 74, + "Series": "Crafts" + }, + { + "Date": "2022-04-28", + "Value": 71, + "Series": "Crafts" + }, + { + "Date": "2022-05-04", + "Value": 72, + "Series": "Crafts" + }, + { + "Date": "2022-05-09", + "Value": 79, + "Series": "Crafts" + }, + { + "Date": "2022-05-15", + "Value": 91, + "Series": "Crafts" + }, + { + "Date": "2022-05-20", + "Value": 105, + "Series": "Crafts" + }, + { + "Date": "2022-05-26", + "Value": 107, + "Series": "Crafts" + }, + { + "Date": "2022-05-31", + "Value": 105, + "Series": "Crafts" + }, + { + "Date": "2022-06-05", + "Value": 104, + "Series": "Crafts" + }, + { + "Date": "2022-06-11", + "Value": 105, + "Series": "Crafts" + }, + { + "Date": "2022-06-16", + "Value": 114, + "Series": "Crafts" + }, + { + "Date": "2022-06-22", + "Value": 119, + "Series": "Crafts" + }, + { + "Date": "2022-06-27", + "Value": 120, + "Series": "Crafts" + }, + { + "Date": "2022-07-03", + "Value": 117, + "Series": "Crafts" + }, + { + "Date": "2022-07-08", + "Value": 123, + "Series": "Crafts" + }, + { + "Date": "2022-07-14", + "Value": 125, + "Series": "Crafts" + }, + { + "Date": "2022-07-19", + "Value": 120, + "Series": "Crafts" + }, + { + "Date": "2022-07-25", + "Value": 113, + "Series": "Crafts" + }, + { + "Date": "2022-07-30", + "Value": 113, + "Series": "Crafts" + }, + { + "Date": "2022-08-05", + "Value": 119, + "Series": "Crafts" + }, + { + "Date": "2022-08-10", + "Value": 128, + "Series": "Crafts" + }, + { + "Date": "2022-08-16", + "Value": 133, + "Series": "Crafts" + }, + { + "Date": "2022-08-21", + "Value": 133, + "Series": "Crafts" + }, + { + "Date": "2022-08-27", + "Value": 126, + "Series": "Crafts" + }, + { + "Date": "2022-09-01", + "Value": 124, + "Series": "Crafts" + }, + { + "Date": "2022-09-07", + "Value": 115, + "Series": "Crafts" + }, + { + "Date": "2022-09-12", + "Value": 114, + "Series": "Crafts" + }, + { + "Date": "2022-09-17", + "Value": 109, + "Series": "Crafts" + }, + { + "Date": "2022-09-23", + "Value": 108, + "Series": "Crafts" + }, + { + "Date": "2022-09-28", + "Value": 111, + "Series": "Crafts" + }, + { + "Date": "2022-10-04", + "Value": 121, + "Series": "Crafts" + }, + { + "Date": "2022-10-09", + "Value": 130, + "Series": "Crafts" + }, + { + "Date": "2022-10-15", + "Value": 140, + "Series": "Crafts" + }, + { + "Date": "2022-10-20", + "Value": 147, + "Series": "Crafts" + }, + { + "Date": "2022-10-26", + "Value": 159, + "Series": "Crafts" + }, + { + "Date": "2022-10-31", + "Value": 167, + "Series": "Crafts" + }, + { + "Date": "2022-11-06", + "Value": 179, + "Series": "Crafts" + }, + { + "Date": "2022-11-11", + "Value": 196, + "Series": "Crafts" + }, + { + "Date": "2022-11-17", + "Value": 211, + "Series": "Crafts" + }, + { + "Date": "2022-11-22", + "Value": 223, + "Series": "Crafts" + }, + { + "Date": "2022-11-28", + "Value": 232, + "Series": "Crafts" + }, + { + "Date": "2022-12-03", + "Value": 233, + "Series": "Crafts" + }, + { + "Date": "2022-12-09", + "Value": 236, + "Series": "Crafts" + }, + { + "Date": "2022-12-14", + "Value": 238, + "Series": "Crafts" + }, + { + "Date": "2022-12-20", + "Value": 248, + "Series": "Crafts" + }, + { + "Date": "2022-12-25", + "Value": 255, + "Series": "Crafts" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/line-chart/04-card60.flint.json b/test-harness/excel/evaluations/inputs/line-chart/04-card60.flint.json new file mode 100644 index 00000000..4b4d4c31 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/line-chart/04-card60.flint.json @@ -0,0 +1,733 @@ +{ + "semantic_types": { + "Date": "Date", + "Value": "Quantity", + "Series": "Category" + }, + "chart_spec": { + "chartType": "Line Chart", + "encodings": { + "x": "Date", + "y": "Value", + "color": "Series" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Date": "2020-01-01", + "Value": 69, + "Series": "Electronics" + }, + { + "Date": "2020-01-19", + "Value": 67, + "Series": "Electronics" + }, + { + "Date": "2020-02-06", + "Value": 62, + "Series": "Electronics" + }, + { + "Date": "2020-02-24", + "Value": 56, + "Series": "Electronics" + }, + { + "Date": "2020-03-14", + "Value": 47, + "Series": "Electronics" + }, + { + "Date": "2020-05-26", + "Value": 21, + "Series": "Electronics" + }, + { + "Date": "2020-07-01", + "Value": 17, + "Series": "Electronics" + }, + { + "Date": "2020-08-07", + "Value": 17, + "Series": "Electronics" + }, + { + "Date": "2020-08-25", + "Value": 16, + "Series": "Electronics" + }, + { + "Date": "2020-09-12", + "Value": 17, + "Series": "Electronics" + }, + { + "Date": "2020-09-30", + "Value": 16, + "Series": "Electronics" + }, + { + "Date": "2020-10-19", + "Value": 20, + "Series": "Electronics" + }, + { + "Date": "2020-11-06", + "Value": 17, + "Series": "Electronics" + }, + { + "Date": "2020-11-24", + "Value": 22, + "Series": "Electronics" + }, + { + "Date": "2020-12-12", + "Value": 19, + "Series": "Electronics" + }, + { + "Date": "2020-12-31", + "Value": 15, + "Series": "Electronics" + }, + { + "Date": "2021-01-18", + "Value": 19, + "Series": "Electronics" + }, + { + "Date": "2021-02-05", + "Value": 25, + "Series": "Electronics" + }, + { + "Date": "2021-02-23", + "Value": 35, + "Series": "Electronics" + }, + { + "Date": "2021-04-01", + "Value": 50, + "Series": "Electronics" + }, + { + "Date": "2021-04-19", + "Value": 57, + "Series": "Electronics" + }, + { + "Date": "2021-05-26", + "Value": 71, + "Series": "Electronics" + }, + { + "Date": "2021-06-13", + "Value": 72, + "Series": "Electronics" + }, + { + "Date": "2021-07-01", + "Value": 74, + "Series": "Electronics" + }, + { + "Date": "2021-07-19", + "Value": 79, + "Series": "Electronics" + }, + { + "Date": "2021-08-07", + "Value": 90, + "Series": "Electronics" + }, + { + "Date": "2021-08-25", + "Value": 98, + "Series": "Electronics" + }, + { + "Date": "2021-09-12", + "Value": 98, + "Series": "Electronics" + }, + { + "Date": "2021-09-30", + "Value": 100, + "Series": "Electronics" + }, + { + "Date": "2021-10-19", + "Value": 105, + "Series": "Electronics" + }, + { + "Date": "2021-11-06", + "Value": 106, + "Series": "Electronics" + }, + { + "Date": "2021-12-12", + "Value": 97, + "Series": "Electronics" + }, + { + "Date": "2021-12-31", + "Value": 92, + "Series": "Electronics" + }, + { + "Date": "2022-01-18", + "Value": 85, + "Series": "Electronics" + }, + { + "Date": "2022-02-05", + "Value": 86, + "Series": "Electronics" + }, + { + "Date": "2022-02-23", + "Value": 85, + "Series": "Electronics" + }, + { + "Date": "2022-04-19", + "Value": 95, + "Series": "Electronics" + }, + { + "Date": "2022-05-07", + "Value": 92, + "Series": "Electronics" + }, + { + "Date": "2022-06-13", + "Value": 82, + "Series": "Electronics" + }, + { + "Date": "2022-07-01", + "Value": 80, + "Series": "Electronics" + }, + { + "Date": "2022-07-19", + "Value": 85, + "Series": "Electronics" + }, + { + "Date": "2022-08-07", + "Value": 93, + "Series": "Electronics" + }, + { + "Date": "2022-08-25", + "Value": 99, + "Series": "Electronics" + }, + { + "Date": "2022-09-12", + "Value": 104, + "Series": "Electronics" + }, + { + "Date": "2022-09-30", + "Value": 103, + "Series": "Electronics" + }, + { + "Date": "2022-10-19", + "Value": 102, + "Series": "Electronics" + }, + { + "Date": "2022-11-24", + "Value": 87, + "Series": "Electronics" + }, + { + "Date": "2022-12-12", + "Value": 82, + "Series": "Electronics" + }, + { + "Date": "2020-01-01", + "Value": 174, + "Series": "Clothing" + }, + { + "Date": "2020-01-19", + "Value": 181, + "Series": "Clothing" + }, + { + "Date": "2020-02-06", + "Value": 180, + "Series": "Clothing" + }, + { + "Date": "2020-02-24", + "Value": 179, + "Series": "Clothing" + }, + { + "Date": "2020-03-14", + "Value": 170, + "Series": "Clothing" + }, + { + "Date": "2020-04-01", + "Value": 163, + "Series": "Clothing" + }, + { + "Date": "2020-04-19", + "Value": 164, + "Series": "Clothing" + }, + { + "Date": "2020-05-07", + "Value": 161, + "Series": "Clothing" + }, + { + "Date": "2020-06-13", + "Value": 153, + "Series": "Clothing" + }, + { + "Date": "2020-07-01", + "Value": 142, + "Series": "Clothing" + }, + { + "Date": "2020-08-07", + "Value": 122, + "Series": "Clothing" + }, + { + "Date": "2020-08-25", + "Value": 125, + "Series": "Clothing" + }, + { + "Date": "2020-10-19", + "Value": 149, + "Series": "Clothing" + }, + { + "Date": "2020-11-06", + "Value": 161, + "Series": "Clothing" + }, + { + "Date": "2020-11-24", + "Value": 178, + "Series": "Clothing" + }, + { + "Date": "2020-12-31", + "Value": 192, + "Series": "Clothing" + }, + { + "Date": "2021-01-18", + "Value": 195, + "Series": "Clothing" + }, + { + "Date": "2021-03-14", + "Value": 177, + "Series": "Clothing" + }, + { + "Date": "2021-04-01", + "Value": 169, + "Series": "Clothing" + }, + { + "Date": "2021-04-19", + "Value": 172, + "Series": "Clothing" + }, + { + "Date": "2021-05-07", + "Value": 176, + "Series": "Clothing" + }, + { + "Date": "2021-05-26", + "Value": 181, + "Series": "Clothing" + }, + { + "Date": "2021-06-13", + "Value": 182, + "Series": "Clothing" + }, + { + "Date": "2021-07-19", + "Value": 192, + "Series": "Clothing" + }, + { + "Date": "2021-08-07", + "Value": 189, + "Series": "Clothing" + }, + { + "Date": "2021-08-25", + "Value": 181, + "Series": "Clothing" + }, + { + "Date": "2021-09-12", + "Value": 176, + "Series": "Clothing" + }, + { + "Date": "2021-09-30", + "Value": 180, + "Series": "Clothing" + }, + { + "Date": "2021-10-19", + "Value": 183, + "Series": "Clothing" + }, + { + "Date": "2021-11-06", + "Value": 191, + "Series": "Clothing" + }, + { + "Date": "2021-11-24", + "Value": 196, + "Series": "Clothing" + }, + { + "Date": "2021-12-31", + "Value": 207, + "Series": "Clothing" + }, + { + "Date": "2022-01-18", + "Value": 200, + "Series": "Clothing" + }, + { + "Date": "2022-02-05", + "Value": 199, + "Series": "Clothing" + }, + { + "Date": "2022-03-14", + "Value": 185, + "Series": "Clothing" + }, + { + "Date": "2022-04-01", + "Value": 177, + "Series": "Clothing" + }, + { + "Date": "2022-04-19", + "Value": 167, + "Series": "Clothing" + }, + { + "Date": "2022-05-07", + "Value": 152, + "Series": "Clothing" + }, + { + "Date": "2022-05-26", + "Value": 149, + "Series": "Clothing" + }, + { + "Date": "2022-06-13", + "Value": 145, + "Series": "Clothing" + }, + { + "Date": "2022-07-01", + "Value": 141, + "Series": "Clothing" + }, + { + "Date": "2022-07-19", + "Value": 135, + "Series": "Clothing" + }, + { + "Date": "2022-09-12", + "Value": 145, + "Series": "Clothing" + }, + { + "Date": "2022-09-30", + "Value": 148, + "Series": "Clothing" + }, + { + "Date": "2022-12-12", + "Value": 168, + "Series": "Clothing" + }, + { + "Date": "2020-01-01", + "Value": 187, + "Series": "Food" + }, + { + "Date": "2020-01-19", + "Value": 182, + "Series": "Food" + }, + { + "Date": "2020-02-24", + "Value": 157, + "Series": "Food" + }, + { + "Date": "2020-03-14", + "Value": 147, + "Series": "Food" + }, + { + "Date": "2020-04-01", + "Value": 151, + "Series": "Food" + }, + { + "Date": "2020-04-19", + "Value": 158, + "Series": "Food" + }, + { + "Date": "2020-06-13", + "Value": 177, + "Series": "Food" + }, + { + "Date": "2020-07-01", + "Value": 181, + "Series": "Food" + }, + { + "Date": "2020-07-19", + "Value": 182, + "Series": "Food" + }, + { + "Date": "2020-08-07", + "Value": 190, + "Series": "Food" + }, + { + "Date": "2020-08-25", + "Value": 199, + "Series": "Food" + }, + { + "Date": "2020-09-12", + "Value": 201, + "Series": "Food" + }, + { + "Date": "2020-09-30", + "Value": 212, + "Series": "Food" + }, + { + "Date": "2020-10-19", + "Value": 227, + "Series": "Food" + }, + { + "Date": "2020-11-06", + "Value": 232, + "Series": "Food" + }, + { + "Date": "2020-12-12", + "Value": 249, + "Series": "Food" + }, + { + "Date": "2020-12-31", + "Value": 258, + "Series": "Food" + }, + { + "Date": "2021-01-18", + "Value": 260, + "Series": "Food" + }, + { + "Date": "2021-03-14", + "Value": 289, + "Series": "Food" + }, + { + "Date": "2021-04-01", + "Value": 286, + "Series": "Food" + }, + { + "Date": "2021-04-19", + "Value": 292, + "Series": "Food" + }, + { + "Date": "2021-05-07", + "Value": 299, + "Series": "Food" + }, + { + "Date": "2021-05-26", + "Value": 304, + "Series": "Food" + }, + { + "Date": "2021-06-13", + "Value": 312, + "Series": "Food" + }, + { + "Date": "2021-07-01", + "Value": 328, + "Series": "Food" + }, + { + "Date": "2021-07-19", + "Value": 349, + "Series": "Food" + }, + { + "Date": "2021-08-07", + "Value": 362, + "Series": "Food" + }, + { + "Date": "2021-08-25", + "Value": 364, + "Series": "Food" + }, + { + "Date": "2021-09-12", + "Value": 364, + "Series": "Food" + }, + { + "Date": "2021-09-30", + "Value": 355, + "Series": "Food" + }, + { + "Date": "2021-10-19", + "Value": 343, + "Series": "Food" + }, + { + "Date": "2021-11-06", + "Value": 336, + "Series": "Food" + }, + { + "Date": "2021-12-12", + "Value": 351, + "Series": "Food" + }, + { + "Date": "2022-01-18", + "Value": 351, + "Series": "Food" + }, + { + "Date": "2022-02-05", + "Value": 343, + "Series": "Food" + }, + { + "Date": "2022-02-23", + "Value": 327, + "Series": "Food" + }, + { + "Date": "2022-03-14", + "Value": 309, + "Series": "Food" + }, + { + "Date": "2022-04-01", + "Value": 294, + "Series": "Food" + }, + { + "Date": "2022-05-07", + "Value": 261, + "Series": "Food" + }, + { + "Date": "2022-05-26", + "Value": 237, + "Series": "Food" + }, + { + "Date": "2022-06-13", + "Value": 214, + "Series": "Food" + }, + { + "Date": "2022-07-01", + "Value": 194, + "Series": "Food" + }, + { + "Date": "2022-07-19", + "Value": 173, + "Series": "Food" + }, + { + "Date": "2022-08-07", + "Value": 158, + "Series": "Food" + }, + { + "Date": "2022-08-25", + "Value": 154, + "Series": "Food" + }, + { + "Date": "2022-09-30", + "Value": 160, + "Series": "Food" + }, + { + "Date": "2022-10-19", + "Value": 171, + "Series": "Food" + }, + { + "Date": "2022-11-06", + "Value": 170, + "Series": "Food" + }, + { + "Date": "2022-12-12", + "Value": 176, + "Series": "Food" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/line-chart/05-card30.flint.json b/test-harness/excel/evaluations/inputs/line-chart/05-card30.flint.json new file mode 100644 index 00000000..0852761d --- /dev/null +++ b/test-harness/excel/evaluations/inputs/line-chart/05-card30.flint.json @@ -0,0 +1,173 @@ +{ + "semantic_types": { + "Date": "Date", + "Value": "Quantity", + "ColorVal": "Quantity" + }, + "chart_spec": { + "chartType": "Line Chart", + "encodings": { + "x": "Date", + "y": "Value", + "color": "ColorVal" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Date": "2020-01-01", + "Value": 117, + "ColorVal": 2.4 + }, + { + "Date": "2020-02-06", + "Value": 109, + "ColorVal": 1.9 + }, + { + "Date": "2020-03-14", + "Value": 113, + "ColorVal": 0.3 + }, + { + "Date": "2020-04-19", + "Value": 117, + "ColorVal": 4.2 + }, + { + "Date": "2020-05-26", + "Value": 112, + "ColorVal": 9.5 + }, + { + "Date": "2020-07-01", + "Value": 121, + "ColorVal": 2.5 + }, + { + "Date": "2020-08-07", + "Value": 134, + "ColorVal": 7.5 + }, + { + "Date": "2020-09-12", + "Value": 130, + "ColorVal": 2.7 + }, + { + "Date": "2020-10-19", + "Value": 136, + "ColorVal": 4.3 + }, + { + "Date": "2020-11-24", + "Value": 152, + "ColorVal": 6.4 + }, + { + "Date": "2020-12-31", + "Value": 158, + "ColorVal": 3.8 + }, + { + "Date": "2021-02-05", + "Value": 165, + "ColorVal": 2.5 + }, + { + "Date": "2021-03-14", + "Value": 164, + "ColorVal": 4.7 + }, + { + "Date": "2021-04-19", + "Value": 175, + "ColorVal": 9.1 + }, + { + "Date": "2021-05-26", + "Value": 173, + "ColorVal": 6 + }, + { + "Date": "2021-07-01", + "Value": 161, + "ColorVal": 4.8 + }, + { + "Date": "2021-08-07", + "Value": 167, + "ColorVal": 6.1 + }, + { + "Date": "2021-09-12", + "Value": 157, + "ColorVal": 1.4 + }, + { + "Date": "2021-10-19", + "Value": 151, + "ColorVal": 8.8 + }, + { + "Date": "2021-11-24", + "Value": 149, + "ColorVal": 7.3 + }, + { + "Date": "2021-12-31", + "Value": 159, + "ColorVal": 3.8 + }, + { + "Date": "2022-02-05", + "Value": 177, + "ColorVal": 3.1 + }, + { + "Date": "2022-03-14", + "Value": 195, + "ColorVal": 8.1 + }, + { + "Date": "2022-04-19", + "Value": 211, + "ColorVal": 5 + }, + { + "Date": "2022-05-26", + "Value": 220, + "ColorVal": 0.4 + }, + { + "Date": "2022-07-01", + "Value": 228, + "ColorVal": 6.3 + }, + { + "Date": "2022-08-07", + "Value": 229, + "ColorVal": 1.3 + }, + { + "Date": "2022-09-12", + "Value": 221, + "ColorVal": 8.4 + }, + { + "Date": "2022-10-19", + "Value": 206, + "ColorVal": 0.2 + }, + { + "Date": "2022-11-24", + "Value": 191, + "ColorVal": 7.6 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/line-chart/06-card5.flint.json b/test-harness/excel/evaluations/inputs/line-chart/06-card5.flint.json new file mode 100644 index 00000000..fbf85b11 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/line-chart/06-card5.flint.json @@ -0,0 +1,41 @@ +{ + "semantic_types": { + "Stage": "Category", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Line Chart", + "encodings": { + "x": "Stage", + "y": "Value" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Stage": "Stage 1", + "Value": 113 + }, + { + "Stage": "Stage 2", + "Value": 126 + }, + { + "Stage": "Stage 3", + "Value": 131 + }, + { + "Stage": "Stage 4", + "Value": 144 + }, + { + "Stage": "Stage 5", + "Value": 138 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/line-chart/07-card12.flint.json b/test-harness/excel/evaluations/inputs/line-chart/07-card12.flint.json new file mode 100644 index 00000000..042e1a85 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/line-chart/07-card12.flint.json @@ -0,0 +1,263 @@ +{ + "semantic_types": { + "Stage": "Category", + "Value": "Quantity", + "Series": "Category" + }, + "chart_spec": { + "chartType": "Line Chart", + "encodings": { + "x": "Stage", + "y": "Value", + "color": "Series" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Stage": "Stage 1", + "Value": 240, + "Series": "Electronics" + }, + { + "Stage": "Stage 2", + "Value": 240, + "Series": "Electronics" + }, + { + "Stage": "Stage 3", + "Value": 245, + "Series": "Electronics" + }, + { + "Stage": "Stage 4", + "Value": 242, + "Series": "Electronics" + }, + { + "Stage": "Stage 5", + "Value": 250, + "Series": "Electronics" + }, + { + "Stage": "Stage 6", + "Value": 265, + "Series": "Electronics" + }, + { + "Stage": "Stage 7", + "Value": 280, + "Series": "Electronics" + }, + { + "Stage": "Stage 8", + "Value": 285, + "Series": "Electronics" + }, + { + "Stage": "Stage 9", + "Value": 293, + "Series": "Electronics" + }, + { + "Stage": "Stage 10", + "Value": 297, + "Series": "Electronics" + }, + { + "Stage": "Stage 11", + "Value": 294, + "Series": "Electronics" + }, + { + "Stage": "Stage 12", + "Value": 286, + "Series": "Electronics" + }, + { + "Stage": "Stage 1", + "Value": 107, + "Series": "Clothing" + }, + { + "Stage": "Stage 2", + "Value": 108, + "Series": "Clothing" + }, + { + "Stage": "Stage 3", + "Value": 112, + "Series": "Clothing" + }, + { + "Stage": "Stage 4", + "Value": 113, + "Series": "Clothing" + }, + { + "Stage": "Stage 5", + "Value": 119, + "Series": "Clothing" + }, + { + "Stage": "Stage 6", + "Value": 119, + "Series": "Clothing" + }, + { + "Stage": "Stage 7", + "Value": 117, + "Series": "Clothing" + }, + { + "Stage": "Stage 8", + "Value": 114, + "Series": "Clothing" + }, + { + "Stage": "Stage 9", + "Value": 113, + "Series": "Clothing" + }, + { + "Stage": "Stage 10", + "Value": 113, + "Series": "Clothing" + }, + { + "Stage": "Stage 11", + "Value": 114, + "Series": "Clothing" + }, + { + "Stage": "Stage 12", + "Value": 111, + "Series": "Clothing" + }, + { + "Stage": "Stage 1", + "Value": 244, + "Series": "Food" + }, + { + "Stage": "Stage 2", + "Value": 258, + "Series": "Food" + }, + { + "Stage": "Stage 3", + "Value": 267, + "Series": "Food" + }, + { + "Stage": "Stage 4", + "Value": 280, + "Series": "Food" + }, + { + "Stage": "Stage 5", + "Value": 284, + "Series": "Food" + }, + { + "Stage": "Stage 6", + "Value": 274, + "Series": "Food" + }, + { + "Stage": "Stage 7", + "Value": 282, + "Series": "Food" + }, + { + "Stage": "Stage 8", + "Value": 287, + "Series": "Food" + }, + { + "Stage": "Stage 9", + "Value": 297, + "Series": "Food" + }, + { + "Stage": "Stage 10", + "Value": 294, + "Series": "Food" + }, + { + "Stage": "Stage 11", + "Value": 282, + "Series": "Food" + }, + { + "Stage": "Stage 12", + "Value": 268, + "Series": "Food" + }, + { + "Stage": "Stage 1", + "Value": 93, + "Series": "Books" + }, + { + "Stage": "Stage 2", + "Value": 80, + "Series": "Books" + }, + { + "Stage": "Stage 3", + "Value": 69, + "Series": "Books" + }, + { + "Stage": "Stage 4", + "Value": 59, + "Series": "Books" + }, + { + "Stage": "Stage 5", + "Value": 52, + "Series": "Books" + }, + { + "Stage": "Stage 6", + "Value": 52, + "Series": "Books" + }, + { + "Stage": "Stage 7", + "Value": 42, + "Series": "Books" + }, + { + "Stage": "Stage 8", + "Value": 25, + "Series": "Books" + }, + { + "Stage": "Stage 9", + "Value": 21, + "Series": "Books" + }, + { + "Stage": "Stage 10", + "Value": 16, + "Series": "Books" + }, + { + "Stage": "Stage 11", + "Value": 22, + "Series": "Books" + }, + { + "Stage": "Stage 12", + "Value": 36, + "Series": "Books" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/line-chart/08-card30.flint.json b/test-harness/excel/evaluations/inputs/line-chart/08-card30.flint.json new file mode 100644 index 00000000..2dbe044e --- /dev/null +++ b/test-harness/excel/evaluations/inputs/line-chart/08-card30.flint.json @@ -0,0 +1,141 @@ +{ + "semantic_types": { + "Stage": "Category", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Line Chart", + "encodings": { + "x": "Stage", + "y": "Value" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Stage": "Stage 1", + "Value": 160 + }, + { + "Stage": "Stage 2", + "Value": 158 + }, + { + "Stage": "Stage 3", + "Value": 157 + }, + { + "Stage": "Stage 4", + "Value": 159 + }, + { + "Stage": "Stage 5", + "Value": 158 + }, + { + "Stage": "Stage 6", + "Value": 159 + }, + { + "Stage": "Stage 7", + "Value": 163 + }, + { + "Stage": "Stage 8", + "Value": 168 + }, + { + "Stage": "Stage 9", + "Value": 169 + }, + { + "Stage": "Stage 10", + "Value": 168 + }, + { + "Stage": "Stage 11", + "Value": 170 + }, + { + "Stage": "Stage 12", + "Value": 171 + }, + { + "Stage": "Stage 13", + "Value": 173 + }, + { + "Stage": "Stage 14", + "Value": 174 + }, + { + "Stage": "Stage 15", + "Value": 177 + }, + { + "Stage": "Stage 16", + "Value": 181 + }, + { + "Stage": "Stage 17", + "Value": 184 + }, + { + "Stage": "Stage 18", + "Value": 188 + }, + { + "Stage": "Stage 19", + "Value": 195 + }, + { + "Stage": "Stage 20", + "Value": 205 + }, + { + "Stage": "Stage 21", + "Value": 217 + }, + { + "Stage": "Stage 22", + "Value": 228 + }, + { + "Stage": "Stage 23", + "Value": 240 + }, + { + "Stage": "Stage 24", + "Value": 253 + }, + { + "Stage": "Stage 25", + "Value": 261 + }, + { + "Stage": "Stage 26", + "Value": 268 + }, + { + "Stage": "Stage 27", + "Value": 273 + }, + { + "Stage": "Stage 28", + "Value": 279 + }, + { + "Stage": "Stage 29", + "Value": 279 + }, + { + "Stage": "Stage 30", + "Value": 281 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/line-chart/09-card5.flint.json b/test-harness/excel/evaluations/inputs/line-chart/09-card5.flint.json new file mode 100644 index 00000000..a79a3388 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/line-chart/09-card5.flint.json @@ -0,0 +1,48 @@ +{ + "semantic_types": { + "Stage": "Category", + "Value": "Quantity", + "ColorVal": "Quantity" + }, + "chart_spec": { + "chartType": "Line Chart", + "encodings": { + "x": "Stage", + "y": "Value", + "color": "ColorVal" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Stage": "Stage 1", + "Value": 155, + "ColorVal": 9 + }, + { + "Stage": "Stage 2", + "Value": 150, + "ColorVal": 3.1 + }, + { + "Stage": "Stage 3", + "Value": 143, + "ColorVal": 0.1 + }, + { + "Stage": "Stage 4", + "Value": 136, + "ColorVal": 10 + }, + { + "Stage": "Stage 5", + "Value": 137, + "ColorVal": 6.2 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/line-chart/10-card5.flint.json b/test-harness/excel/evaluations/inputs/line-chart/10-card5.flint.json new file mode 100644 index 00000000..d7f2fd8a --- /dev/null +++ b/test-harness/excel/evaluations/inputs/line-chart/10-card5.flint.json @@ -0,0 +1,41 @@ +{ + "semantic_types": { + "X": "Quantity", + "Step": "Category" + }, + "chart_spec": { + "chartType": "Line Chart", + "encodings": { + "x": "X", + "y": "Step" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 0, + "Step": "Stage 1" + }, + { + "X": 25, + "Step": "Stage 2" + }, + { + "X": 50, + "Step": "Stage 3" + }, + { + "X": 75, + "Step": "Stage 4" + }, + { + "X": 100, + "Step": "Stage 5" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/line-chart/11-card12.flint.json b/test-harness/excel/evaluations/inputs/line-chart/11-card12.flint.json new file mode 100644 index 00000000..325b2500 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/line-chart/11-card12.flint.json @@ -0,0 +1,263 @@ +{ + "semantic_types": { + "X": "Quantity", + "Step": "Category", + "Series": "Category" + }, + "chart_spec": { + "chartType": "Line Chart", + "encodings": { + "x": "X", + "y": "Step", + "color": "Series" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 0, + "Step": "Stage 1", + "Series": "Electronics" + }, + { + "X": 9.1, + "Step": "Stage 2", + "Series": "Electronics" + }, + { + "X": 18.2, + "Step": "Stage 3", + "Series": "Electronics" + }, + { + "X": 27.3, + "Step": "Stage 4", + "Series": "Electronics" + }, + { + "X": 36.4, + "Step": "Stage 5", + "Series": "Electronics" + }, + { + "X": 45.5, + "Step": "Stage 6", + "Series": "Electronics" + }, + { + "X": 54.5, + "Step": "Stage 7", + "Series": "Electronics" + }, + { + "X": 63.6, + "Step": "Stage 8", + "Series": "Electronics" + }, + { + "X": 72.7, + "Step": "Stage 9", + "Series": "Electronics" + }, + { + "X": 81.8, + "Step": "Stage 10", + "Series": "Electronics" + }, + { + "X": 90.9, + "Step": "Stage 11", + "Series": "Electronics" + }, + { + "X": 100, + "Step": "Stage 12", + "Series": "Electronics" + }, + { + "X": 0, + "Step": "Stage 1", + "Series": "Clothing" + }, + { + "X": 9.1, + "Step": "Stage 2", + "Series": "Clothing" + }, + { + "X": 18.2, + "Step": "Stage 3", + "Series": "Clothing" + }, + { + "X": 27.3, + "Step": "Stage 4", + "Series": "Clothing" + }, + { + "X": 36.4, + "Step": "Stage 5", + "Series": "Clothing" + }, + { + "X": 45.5, + "Step": "Stage 6", + "Series": "Clothing" + }, + { + "X": 54.5, + "Step": "Stage 7", + "Series": "Clothing" + }, + { + "X": 63.6, + "Step": "Stage 8", + "Series": "Clothing" + }, + { + "X": 72.7, + "Step": "Stage 9", + "Series": "Clothing" + }, + { + "X": 81.8, + "Step": "Stage 10", + "Series": "Clothing" + }, + { + "X": 90.9, + "Step": "Stage 11", + "Series": "Clothing" + }, + { + "X": 100, + "Step": "Stage 12", + "Series": "Clothing" + }, + { + "X": 0, + "Step": "Stage 1", + "Series": "Food" + }, + { + "X": 9.1, + "Step": "Stage 2", + "Series": "Food" + }, + { + "X": 18.2, + "Step": "Stage 3", + "Series": "Food" + }, + { + "X": 27.3, + "Step": "Stage 4", + "Series": "Food" + }, + { + "X": 36.4, + "Step": "Stage 5", + "Series": "Food" + }, + { + "X": 45.5, + "Step": "Stage 6", + "Series": "Food" + }, + { + "X": 54.5, + "Step": "Stage 7", + "Series": "Food" + }, + { + "X": 63.6, + "Step": "Stage 8", + "Series": "Food" + }, + { + "X": 72.7, + "Step": "Stage 9", + "Series": "Food" + }, + { + "X": 81.8, + "Step": "Stage 10", + "Series": "Food" + }, + { + "X": 90.9, + "Step": "Stage 11", + "Series": "Food" + }, + { + "X": 100, + "Step": "Stage 12", + "Series": "Food" + }, + { + "X": 0, + "Step": "Stage 1", + "Series": "Books" + }, + { + "X": 9.1, + "Step": "Stage 2", + "Series": "Books" + }, + { + "X": 18.2, + "Step": "Stage 3", + "Series": "Books" + }, + { + "X": 27.3, + "Step": "Stage 4", + "Series": "Books" + }, + { + "X": 36.4, + "Step": "Stage 5", + "Series": "Books" + }, + { + "X": 45.5, + "Step": "Stage 6", + "Series": "Books" + }, + { + "X": 54.5, + "Step": "Stage 7", + "Series": "Books" + }, + { + "X": 63.6, + "Step": "Stage 8", + "Series": "Books" + }, + { + "X": 72.7, + "Step": "Stage 9", + "Series": "Books" + }, + { + "X": 81.8, + "Step": "Stage 10", + "Series": "Books" + }, + { + "X": 90.9, + "Step": "Stage 11", + "Series": "Books" + }, + { + "X": 100, + "Step": "Stage 12", + "Series": "Books" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/line-chart/12-card30.flint.json b/test-harness/excel/evaluations/inputs/line-chart/12-card30.flint.json new file mode 100644 index 00000000..242ff18d --- /dev/null +++ b/test-harness/excel/evaluations/inputs/line-chart/12-card30.flint.json @@ -0,0 +1,141 @@ +{ + "semantic_types": { + "X": "Quantity", + "Step": "Category" + }, + "chart_spec": { + "chartType": "Line Chart", + "encodings": { + "x": "X", + "y": "Step" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 0, + "Step": "Stage 1" + }, + { + "X": 3.4, + "Step": "Stage 2" + }, + { + "X": 6.9, + "Step": "Stage 3" + }, + { + "X": 10.3, + "Step": "Stage 4" + }, + { + "X": 13.8, + "Step": "Stage 5" + }, + { + "X": 17.2, + "Step": "Stage 6" + }, + { + "X": 20.7, + "Step": "Stage 7" + }, + { + "X": 24.1, + "Step": "Stage 8" + }, + { + "X": 27.6, + "Step": "Stage 9" + }, + { + "X": 31, + "Step": "Stage 10" + }, + { + "X": 34.5, + "Step": "Stage 11" + }, + { + "X": 37.9, + "Step": "Stage 12" + }, + { + "X": 41.4, + "Step": "Stage 13" + }, + { + "X": 44.8, + "Step": "Stage 14" + }, + { + "X": 48.3, + "Step": "Stage 15" + }, + { + "X": 51.7, + "Step": "Stage 16" + }, + { + "X": 55.2, + "Step": "Stage 17" + }, + { + "X": 58.6, + "Step": "Stage 18" + }, + { + "X": 62.1, + "Step": "Stage 19" + }, + { + "X": 65.5, + "Step": "Stage 20" + }, + { + "X": 69, + "Step": "Stage 21" + }, + { + "X": 72.4, + "Step": "Stage 22" + }, + { + "X": 75.9, + "Step": "Stage 23" + }, + { + "X": 79.3, + "Step": "Stage 24" + }, + { + "X": 82.8, + "Step": "Stage 25" + }, + { + "X": 86.2, + "Step": "Stage 26" + }, + { + "X": 89.7, + "Step": "Stage 27" + }, + { + "X": 93.1, + "Step": "Stage 28" + }, + { + "X": 96.6, + "Step": "Stage 29" + }, + { + "X": 100, + "Step": "Stage 30" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/line-chart/13-card30.flint.json b/test-harness/excel/evaluations/inputs/line-chart/13-card30.flint.json new file mode 100644 index 00000000..8d2d955b --- /dev/null +++ b/test-harness/excel/evaluations/inputs/line-chart/13-card30.flint.json @@ -0,0 +1,141 @@ +{ + "semantic_types": { + "X": "Quantity", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Line Chart", + "encodings": { + "x": "X", + "y": "Value" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 0, + "Value": 100 + }, + { + "X": 3.4, + "Value": 102 + }, + { + "X": 6.9, + "Value": 113 + }, + { + "X": 10.3, + "Value": 132 + }, + { + "X": 13.8, + "Value": 152 + }, + { + "X": 17.2, + "Value": 174 + }, + { + "X": 20.7, + "Value": 186 + }, + { + "X": 24.1, + "Value": 202 + }, + { + "X": 27.6, + "Value": 207 + }, + { + "X": 31, + "Value": 200 + }, + { + "X": 34.5, + "Value": 189 + }, + { + "X": 37.9, + "Value": 175 + }, + { + "X": 41.4, + "Value": 171 + }, + { + "X": 44.8, + "Value": 174 + }, + { + "X": 48.3, + "Value": 173 + }, + { + "X": 51.7, + "Value": 180 + }, + { + "X": 55.2, + "Value": 192 + }, + { + "X": 58.6, + "Value": 201 + }, + { + "X": 62.1, + "Value": 217 + }, + { + "X": 65.5, + "Value": 236 + }, + { + "X": 69, + "Value": 241 + }, + { + "X": 72.4, + "Value": 248 + }, + { + "X": 75.9, + "Value": 255 + }, + { + "X": 79.3, + "Value": 262 + }, + { + "X": 82.8, + "Value": 267 + }, + { + "X": 86.2, + "Value": 280 + }, + { + "X": 89.7, + "Value": 289 + }, + { + "X": 93.1, + "Value": 292 + }, + { + "X": 96.6, + "Value": 297 + }, + { + "X": 100, + "Value": 306 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/line-chart/14-card50.flint.json b/test-harness/excel/evaluations/inputs/line-chart/14-card50.flint.json new file mode 100644 index 00000000..652b0e65 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/line-chart/14-card50.flint.json @@ -0,0 +1,773 @@ +{ + "semantic_types": { + "X": "Quantity", + "Value": "Quantity", + "Series": "Category" + }, + "chart_spec": { + "chartType": "Line Chart", + "encodings": { + "x": "X", + "y": "Value", + "color": "Series" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 0, + "Value": 226, + "Series": "Electronics" + }, + { + "X": 2, + "Value": 227, + "Series": "Electronics" + }, + { + "X": 4.1, + "Value": 233, + "Series": "Electronics" + }, + { + "X": 6.1, + "Value": 237, + "Series": "Electronics" + }, + { + "X": 8.2, + "Value": 233, + "Series": "Electronics" + }, + { + "X": 10.2, + "Value": 223, + "Series": "Electronics" + }, + { + "X": 12.2, + "Value": 209, + "Series": "Electronics" + }, + { + "X": 14.3, + "Value": 200, + "Series": "Electronics" + }, + { + "X": 16.3, + "Value": 194, + "Series": "Electronics" + }, + { + "X": 18.4, + "Value": 189, + "Series": "Electronics" + }, + { + "X": 20.4, + "Value": 193, + "Series": "Electronics" + }, + { + "X": 22.4, + "Value": 205, + "Series": "Electronics" + }, + { + "X": 24.5, + "Value": 213, + "Series": "Electronics" + }, + { + "X": 26.5, + "Value": 220, + "Series": "Electronics" + }, + { + "X": 28.6, + "Value": 218, + "Series": "Electronics" + }, + { + "X": 30.6, + "Value": 219, + "Series": "Electronics" + }, + { + "X": 32.7, + "Value": 223, + "Series": "Electronics" + }, + { + "X": 34.7, + "Value": 229, + "Series": "Electronics" + }, + { + "X": 36.7, + "Value": 238, + "Series": "Electronics" + }, + { + "X": 38.8, + "Value": 241, + "Series": "Electronics" + }, + { + "X": 40.8, + "Value": 245, + "Series": "Electronics" + }, + { + "X": 42.9, + "Value": 249, + "Series": "Electronics" + }, + { + "X": 44.9, + "Value": 260, + "Series": "Electronics" + }, + { + "X": 46.9, + "Value": 278, + "Series": "Electronics" + }, + { + "X": 49, + "Value": 285, + "Series": "Electronics" + }, + { + "X": 51, + "Value": 287, + "Series": "Electronics" + }, + { + "X": 53.1, + "Value": 280, + "Series": "Electronics" + }, + { + "X": 55.1, + "Value": 277, + "Series": "Electronics" + }, + { + "X": 57.1, + "Value": 267, + "Series": "Electronics" + }, + { + "X": 59.2, + "Value": 250, + "Series": "Electronics" + }, + { + "X": 61.2, + "Value": 233, + "Series": "Electronics" + }, + { + "X": 63.3, + "Value": 217, + "Series": "Electronics" + }, + { + "X": 65.3, + "Value": 200, + "Series": "Electronics" + }, + { + "X": 67.3, + "Value": 195, + "Series": "Electronics" + }, + { + "X": 69.4, + "Value": 193, + "Series": "Electronics" + }, + { + "X": 71.4, + "Value": 202, + "Series": "Electronics" + }, + { + "X": 73.5, + "Value": 211, + "Series": "Electronics" + }, + { + "X": 75.5, + "Value": 226, + "Series": "Electronics" + }, + { + "X": 77.6, + "Value": 238, + "Series": "Electronics" + }, + { + "X": 79.6, + "Value": 239, + "Series": "Electronics" + }, + { + "X": 81.6, + "Value": 245, + "Series": "Electronics" + }, + { + "X": 83.7, + "Value": 242, + "Series": "Electronics" + }, + { + "X": 85.7, + "Value": 235, + "Series": "Electronics" + }, + { + "X": 87.8, + "Value": 228, + "Series": "Electronics" + }, + { + "X": 89.8, + "Value": 227, + "Series": "Electronics" + }, + { + "X": 91.8, + "Value": 221, + "Series": "Electronics" + }, + { + "X": 93.9, + "Value": 220, + "Series": "Electronics" + }, + { + "X": 95.9, + "Value": 219, + "Series": "Electronics" + }, + { + "X": 98, + "Value": 209, + "Series": "Electronics" + }, + { + "X": 100, + "Value": 203, + "Series": "Electronics" + }, + { + "X": 0, + "Value": 159, + "Series": "Clothing" + }, + { + "X": 2, + "Value": 164, + "Series": "Clothing" + }, + { + "X": 4.1, + "Value": 178, + "Series": "Clothing" + }, + { + "X": 6.1, + "Value": 196, + "Series": "Clothing" + }, + { + "X": 8.2, + "Value": 213, + "Series": "Clothing" + }, + { + "X": 10.2, + "Value": 235, + "Series": "Clothing" + }, + { + "X": 12.2, + "Value": 247, + "Series": "Clothing" + }, + { + "X": 14.3, + "Value": 255, + "Series": "Clothing" + }, + { + "X": 16.3, + "Value": 262, + "Series": "Clothing" + }, + { + "X": 18.4, + "Value": 272, + "Series": "Clothing" + }, + { + "X": 20.4, + "Value": 289, + "Series": "Clothing" + }, + { + "X": 22.4, + "Value": 290, + "Series": "Clothing" + }, + { + "X": 24.5, + "Value": 283, + "Series": "Clothing" + }, + { + "X": 26.5, + "Value": 282, + "Series": "Clothing" + }, + { + "X": 28.6, + "Value": 284, + "Series": "Clothing" + }, + { + "X": 30.6, + "Value": 274, + "Series": "Clothing" + }, + { + "X": 32.7, + "Value": 272, + "Series": "Clothing" + }, + { + "X": 34.7, + "Value": 279, + "Series": "Clothing" + }, + { + "X": 36.7, + "Value": 287, + "Series": "Clothing" + }, + { + "X": 38.8, + "Value": 285, + "Series": "Clothing" + }, + { + "X": 40.8, + "Value": 294, + "Series": "Clothing" + }, + { + "X": 42.9, + "Value": 311, + "Series": "Clothing" + }, + { + "X": 44.9, + "Value": 317, + "Series": "Clothing" + }, + { + "X": 46.9, + "Value": 311, + "Series": "Clothing" + }, + { + "X": 49, + "Value": 307, + "Series": "Clothing" + }, + { + "X": 51, + "Value": 315, + "Series": "Clothing" + }, + { + "X": 53.1, + "Value": 330, + "Series": "Clothing" + }, + { + "X": 55.1, + "Value": 350, + "Series": "Clothing" + }, + { + "X": 57.1, + "Value": 353, + "Series": "Clothing" + }, + { + "X": 59.2, + "Value": 363, + "Series": "Clothing" + }, + { + "X": 61.2, + "Value": 380, + "Series": "Clothing" + }, + { + "X": 63.3, + "Value": 397, + "Series": "Clothing" + }, + { + "X": 65.3, + "Value": 407, + "Series": "Clothing" + }, + { + "X": 67.3, + "Value": 420, + "Series": "Clothing" + }, + { + "X": 69.4, + "Value": 432, + "Series": "Clothing" + }, + { + "X": 71.4, + "Value": 449, + "Series": "Clothing" + }, + { + "X": 73.5, + "Value": 470, + "Series": "Clothing" + }, + { + "X": 75.5, + "Value": 492, + "Series": "Clothing" + }, + { + "X": 77.6, + "Value": 510, + "Series": "Clothing" + }, + { + "X": 79.6, + "Value": 526, + "Series": "Clothing" + }, + { + "X": 81.6, + "Value": 532, + "Series": "Clothing" + }, + { + "X": 83.7, + "Value": 539, + "Series": "Clothing" + }, + { + "X": 85.7, + "Value": 552, + "Series": "Clothing" + }, + { + "X": 87.8, + "Value": 550, + "Series": "Clothing" + }, + { + "X": 89.8, + "Value": 542, + "Series": "Clothing" + }, + { + "X": 91.8, + "Value": 539, + "Series": "Clothing" + }, + { + "X": 93.9, + "Value": 531, + "Series": "Clothing" + }, + { + "X": 95.9, + "Value": 533, + "Series": "Clothing" + }, + { + "X": 98, + "Value": 534, + "Series": "Clothing" + }, + { + "X": 100, + "Value": 529, + "Series": "Clothing" + }, + { + "X": 0, + "Value": 84, + "Series": "Food" + }, + { + "X": 2, + "Value": 88, + "Series": "Food" + }, + { + "X": 4.1, + "Value": 90, + "Series": "Food" + }, + { + "X": 6.1, + "Value": 82, + "Series": "Food" + }, + { + "X": 8.2, + "Value": 90, + "Series": "Food" + }, + { + "X": 10.2, + "Value": 111, + "Series": "Food" + }, + { + "X": 12.2, + "Value": 118, + "Series": "Food" + }, + { + "X": 14.3, + "Value": 119, + "Series": "Food" + }, + { + "X": 16.3, + "Value": 133, + "Series": "Food" + }, + { + "X": 18.4, + "Value": 133, + "Series": "Food" + }, + { + "X": 20.4, + "Value": 131, + "Series": "Food" + }, + { + "X": 22.4, + "Value": 132, + "Series": "Food" + }, + { + "X": 24.5, + "Value": 142, + "Series": "Food" + }, + { + "X": 26.5, + "Value": 153, + "Series": "Food" + }, + { + "X": 28.6, + "Value": 146, + "Series": "Food" + }, + { + "X": 30.6, + "Value": 132, + "Series": "Food" + }, + { + "X": 32.7, + "Value": 123, + "Series": "Food" + }, + { + "X": 34.7, + "Value": 123, + "Series": "Food" + }, + { + "X": 36.7, + "Value": 122, + "Series": "Food" + }, + { + "X": 38.8, + "Value": 133, + "Series": "Food" + }, + { + "X": 40.8, + "Value": 145, + "Series": "Food" + }, + { + "X": 42.9, + "Value": 161, + "Series": "Food" + }, + { + "X": 44.9, + "Value": 158, + "Series": "Food" + }, + { + "X": 46.9, + "Value": 168, + "Series": "Food" + }, + { + "X": 49, + "Value": 187, + "Series": "Food" + }, + { + "X": 51, + "Value": 205, + "Series": "Food" + }, + { + "X": 53.1, + "Value": 223, + "Series": "Food" + }, + { + "X": 55.1, + "Value": 239, + "Series": "Food" + }, + { + "X": 57.1, + "Value": 237, + "Series": "Food" + }, + { + "X": 59.2, + "Value": 246, + "Series": "Food" + }, + { + "X": 61.2, + "Value": 243, + "Series": "Food" + }, + { + "X": 63.3, + "Value": 227, + "Series": "Food" + }, + { + "X": 65.3, + "Value": 218, + "Series": "Food" + }, + { + "X": 67.3, + "Value": 216, + "Series": "Food" + }, + { + "X": 69.4, + "Value": 212, + "Series": "Food" + }, + { + "X": 71.4, + "Value": 197, + "Series": "Food" + }, + { + "X": 73.5, + "Value": 182, + "Series": "Food" + }, + { + "X": 75.5, + "Value": 159, + "Series": "Food" + }, + { + "X": 77.6, + "Value": 128, + "Series": "Food" + }, + { + "X": 79.6, + "Value": 114, + "Series": "Food" + }, + { + "X": 81.6, + "Value": 103, + "Series": "Food" + }, + { + "X": 83.7, + "Value": 108, + "Series": "Food" + }, + { + "X": 85.7, + "Value": 125, + "Series": "Food" + }, + { + "X": 87.8, + "Value": 145, + "Series": "Food" + }, + { + "X": 89.8, + "Value": 156, + "Series": "Food" + }, + { + "X": 91.8, + "Value": 163, + "Series": "Food" + }, + { + "X": 93.9, + "Value": 168, + "Series": "Food" + }, + { + "X": 95.9, + "Value": 159, + "Series": "Food" + }, + { + "X": 98, + "Value": 160, + "Series": "Food" + }, + { + "X": 100, + "Value": 154, + "Series": "Food" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/line-chart/15-card200.flint.json b/test-harness/excel/evaluations/inputs/line-chart/15-card200.flint.json new file mode 100644 index 00000000..b74db5fe --- /dev/null +++ b/test-harness/excel/evaluations/inputs/line-chart/15-card200.flint.json @@ -0,0 +1,821 @@ +{ + "semantic_types": { + "X": "Quantity", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Line Chart", + "encodings": { + "x": "X", + "y": "Value" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 0, + "Value": 237 + }, + { + "X": 0.5, + "Value": 246 + }, + { + "X": 1, + "Value": 251 + }, + { + "X": 1.5, + "Value": 266 + }, + { + "X": 2, + "Value": 284 + }, + { + "X": 2.5, + "Value": 292 + }, + { + "X": 3, + "Value": 301 + }, + { + "X": 3.5, + "Value": 307 + }, + { + "X": 4, + "Value": 309 + }, + { + "X": 4.5, + "Value": 308 + }, + { + "X": 5, + "Value": 319 + }, + { + "X": 5.5, + "Value": 318 + }, + { + "X": 6, + "Value": 316 + }, + { + "X": 6.5, + "Value": 322 + }, + { + "X": 7, + "Value": 324 + }, + { + "X": 7.5, + "Value": 336 + }, + { + "X": 8, + "Value": 342 + }, + { + "X": 8.5, + "Value": 339 + }, + { + "X": 9, + "Value": 341 + }, + { + "X": 9.5, + "Value": 331 + }, + { + "X": 10.1, + "Value": 321 + }, + { + "X": 10.6, + "Value": 309 + }, + { + "X": 11.1, + "Value": 310 + }, + { + "X": 11.6, + "Value": 318 + }, + { + "X": 12.1, + "Value": 322 + }, + { + "X": 12.6, + "Value": 325 + }, + { + "X": 13.1, + "Value": 329 + }, + { + "X": 13.6, + "Value": 339 + }, + { + "X": 14.1, + "Value": 358 + }, + { + "X": 14.6, + "Value": 378 + }, + { + "X": 15.1, + "Value": 402 + }, + { + "X": 15.6, + "Value": 410 + }, + { + "X": 16.1, + "Value": 424 + }, + { + "X": 16.6, + "Value": 443 + }, + { + "X": 17.1, + "Value": 459 + }, + { + "X": 17.6, + "Value": 462 + }, + { + "X": 18.1, + "Value": 466 + }, + { + "X": 18.6, + "Value": 458 + }, + { + "X": 19.1, + "Value": 455 + }, + { + "X": 19.6, + "Value": 458 + }, + { + "X": 20.1, + "Value": 462 + }, + { + "X": 20.6, + "Value": 465 + }, + { + "X": 21.1, + "Value": 465 + }, + { + "X": 21.6, + "Value": 477 + }, + { + "X": 22.1, + "Value": 487 + }, + { + "X": 22.6, + "Value": 499 + }, + { + "X": 23.1, + "Value": 516 + }, + { + "X": 23.6, + "Value": 517 + }, + { + "X": 24.1, + "Value": 508 + }, + { + "X": 24.6, + "Value": 502 + }, + { + "X": 25.1, + "Value": 492 + }, + { + "X": 25.6, + "Value": 486 + }, + { + "X": 26.1, + "Value": 483 + }, + { + "X": 26.6, + "Value": 477 + }, + { + "X": 27.1, + "Value": 472 + }, + { + "X": 27.6, + "Value": 469 + }, + { + "X": 28.1, + "Value": 463 + }, + { + "X": 28.6, + "Value": 461 + }, + { + "X": 29.1, + "Value": 447 + }, + { + "X": 29.6, + "Value": 437 + }, + { + "X": 30.2, + "Value": 439 + }, + { + "X": 30.7, + "Value": 435 + }, + { + "X": 31.2, + "Value": 435 + }, + { + "X": 31.7, + "Value": 427 + }, + { + "X": 32.2, + "Value": 425 + }, + { + "X": 32.7, + "Value": 412 + }, + { + "X": 33.2, + "Value": 398 + }, + { + "X": 33.7, + "Value": 379 + }, + { + "X": 34.2, + "Value": 365 + }, + { + "X": 34.7, + "Value": 350 + }, + { + "X": 35.2, + "Value": 337 + }, + { + "X": 35.7, + "Value": 326 + }, + { + "X": 36.2, + "Value": 316 + }, + { + "X": 36.7, + "Value": 321 + }, + { + "X": 37.2, + "Value": 331 + }, + { + "X": 37.7, + "Value": 327 + }, + { + "X": 38.2, + "Value": 332 + }, + { + "X": 38.7, + "Value": 337 + }, + { + "X": 39.2, + "Value": 331 + }, + { + "X": 39.7, + "Value": 337 + }, + { + "X": 40.2, + "Value": 331 + }, + { + "X": 40.7, + "Value": 317 + }, + { + "X": 41.2, + "Value": 308 + }, + { + "X": 41.7, + "Value": 307 + }, + { + "X": 42.2, + "Value": 313 + }, + { + "X": 42.7, + "Value": 307 + }, + { + "X": 43.2, + "Value": 300 + }, + { + "X": 43.7, + "Value": 284 + }, + { + "X": 44.2, + "Value": 284 + }, + { + "X": 44.7, + "Value": 282 + }, + { + "X": 45.2, + "Value": 293 + }, + { + "X": 45.7, + "Value": 308 + }, + { + "X": 46.2, + "Value": 328 + }, + { + "X": 46.7, + "Value": 343 + }, + { + "X": 47.2, + "Value": 357 + }, + { + "X": 47.7, + "Value": 364 + }, + { + "X": 48.2, + "Value": 380 + }, + { + "X": 48.7, + "Value": 385 + }, + { + "X": 49.2, + "Value": 390 + }, + { + "X": 49.7, + "Value": 394 + }, + { + "X": 50.3, + "Value": 406 + }, + { + "X": 50.8, + "Value": 418 + }, + { + "X": 51.3, + "Value": 430 + }, + { + "X": 51.8, + "Value": 434 + }, + { + "X": 52.3, + "Value": 434 + }, + { + "X": 52.8, + "Value": 428 + }, + { + "X": 53.3, + "Value": 423 + }, + { + "X": 53.8, + "Value": 418 + }, + { + "X": 54.3, + "Value": 409 + }, + { + "X": 54.8, + "Value": 411 + }, + { + "X": 55.3, + "Value": 417 + }, + { + "X": 55.8, + "Value": 428 + }, + { + "X": 56.3, + "Value": 435 + }, + { + "X": 56.8, + "Value": 443 + }, + { + "X": 57.3, + "Value": 457 + }, + { + "X": 57.8, + "Value": 479 + }, + { + "X": 58.3, + "Value": 497 + }, + { + "X": 58.8, + "Value": 519 + }, + { + "X": 59.3, + "Value": 536 + }, + { + "X": 59.8, + "Value": 552 + }, + { + "X": 60.3, + "Value": 570 + }, + { + "X": 60.8, + "Value": 574 + }, + { + "X": 61.3, + "Value": 586 + }, + { + "X": 61.8, + "Value": 597 + }, + { + "X": 62.3, + "Value": 594 + }, + { + "X": 62.8, + "Value": 603 + }, + { + "X": 63.3, + "Value": 604 + }, + { + "X": 63.8, + "Value": 606 + }, + { + "X": 64.3, + "Value": 608 + }, + { + "X": 64.8, + "Value": 600 + }, + { + "X": 65.3, + "Value": 602 + }, + { + "X": 65.8, + "Value": 609 + }, + { + "X": 66.3, + "Value": 624 + }, + { + "X": 66.8, + "Value": 638 + }, + { + "X": 67.3, + "Value": 643 + }, + { + "X": 67.8, + "Value": 642 + }, + { + "X": 68.3, + "Value": 644 + }, + { + "X": 68.8, + "Value": 641 + }, + { + "X": 69.3, + "Value": 638 + }, + { + "X": 69.8, + "Value": 626 + }, + { + "X": 70.4, + "Value": 617 + }, + { + "X": 70.9, + "Value": 619 + }, + { + "X": 71.4, + "Value": 621 + }, + { + "X": 71.9, + "Value": 611 + }, + { + "X": 72.4, + "Value": 608 + }, + { + "X": 72.9, + "Value": 615 + }, + { + "X": 73.4, + "Value": 618 + }, + { + "X": 73.9, + "Value": 611 + }, + { + "X": 74.4, + "Value": 609 + }, + { + "X": 74.9, + "Value": 600 + }, + { + "X": 75.4, + "Value": 593 + }, + { + "X": 75.9, + "Value": 590 + }, + { + "X": 76.4, + "Value": 584 + }, + { + "X": 76.9, + "Value": 589 + }, + { + "X": 77.4, + "Value": 603 + }, + { + "X": 77.9, + "Value": 602 + }, + { + "X": 78.4, + "Value": 610 + }, + { + "X": 78.9, + "Value": 611 + }, + { + "X": 79.4, + "Value": 602 + }, + { + "X": 79.9, + "Value": 605 + }, + { + "X": 80.4, + "Value": 608 + }, + { + "X": 80.9, + "Value": 601 + }, + { + "X": 81.4, + "Value": 595 + }, + { + "X": 81.9, + "Value": 587 + }, + { + "X": 82.4, + "Value": 584 + }, + { + "X": 82.9, + "Value": 572 + }, + { + "X": 83.4, + "Value": 574 + }, + { + "X": 83.9, + "Value": 580 + }, + { + "X": 84.4, + "Value": 584 + }, + { + "X": 84.9, + "Value": 579 + }, + { + "X": 85.4, + "Value": 567 + }, + { + "X": 85.9, + "Value": 561 + }, + { + "X": 86.4, + "Value": 558 + }, + { + "X": 86.9, + "Value": 565 + }, + { + "X": 87.4, + "Value": 580 + }, + { + "X": 87.9, + "Value": 579 + }, + { + "X": 88.4, + "Value": 588 + }, + { + "X": 88.9, + "Value": 590 + }, + { + "X": 89.4, + "Value": 587 + }, + { + "X": 89.9, + "Value": 588 + }, + { + "X": 90.5, + "Value": 579 + }, + { + "X": 91, + "Value": 581 + }, + { + "X": 91.5, + "Value": 593 + }, + { + "X": 92, + "Value": 594 + }, + { + "X": 92.5, + "Value": 606 + }, + { + "X": 93, + "Value": 604 + }, + { + "X": 93.5, + "Value": 603 + }, + { + "X": 94, + "Value": 603 + }, + { + "X": 94.5, + "Value": 597 + }, + { + "X": 95, + "Value": 582 + }, + { + "X": 95.5, + "Value": 582 + }, + { + "X": 96, + "Value": 583 + }, + { + "X": 96.5, + "Value": 587 + }, + { + "X": 97, + "Value": 596 + }, + { + "X": 97.5, + "Value": 604 + }, + { + "X": 98, + "Value": 611 + }, + { + "X": 98.5, + "Value": 627 + }, + { + "X": 99, + "Value": 637 + }, + { + "X": 99.5, + "Value": 656 + }, + { + "X": 100, + "Value": 674 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/line-chart/16-card16.flint.json b/test-harness/excel/evaluations/inputs/line-chart/16-card16.flint.json new file mode 100644 index 00000000..4a960e80 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/line-chart/16-card16.flint.json @@ -0,0 +1,108 @@ +{ + "semantic_types": { + "Date": "Date", + "Revenue": "Quantity", + "Type": "Category" + }, + "chart_spec": { + "chartType": "Line Chart", + "encodings": { + "x": "Date", + "y": "Revenue", + "strokeDash": "Type" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Date": "2024-01-01", + "Revenue": 94, + "Type": "actual" + }, + { + "Date": "2024-03-09", + "Revenue": 89, + "Type": "actual" + }, + { + "Date": "2024-05-16", + "Revenue": 97, + "Type": "actual" + }, + { + "Date": "2024-07-24", + "Revenue": 92, + "Type": "actual" + }, + { + "Date": "2024-09-30", + "Revenue": 100, + "Type": "actual" + }, + { + "Date": "2024-12-08", + "Revenue": 98, + "Type": "actual" + }, + { + "Date": "2025-02-14", + "Revenue": 106, + "Type": "actual" + }, + { + "Date": "2025-04-24", + "Revenue": 103, + "Type": "actual" + }, + { + "Date": "2025-07-01", + "Revenue": 105, + "Type": "actual" + }, + { + "Date": "2025-09-07", + "Revenue": 103, + "Type": "actual" + }, + { + "Date": "2025-11-15", + "Revenue": 104, + "Type": "actual" + }, + { + "Date": "2026-01-22", + "Revenue": 107, + "Type": "actual" + }, + { + "Date": "2026-01-22", + "Revenue": 107, + "Type": "forecast" + }, + { + "Date": "2026-04-01", + "Revenue": 118, + "Type": "forecast" + }, + { + "Date": "2026-06-08", + "Revenue": 123, + "Type": "forecast" + }, + { + "Date": "2026-08-16", + "Revenue": 131, + "Type": "forecast" + }, + { + "Date": "2026-10-23", + "Revenue": 143, + "Type": "forecast" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/line-chart/17-card13.flint.json b/test-harness/excel/evaluations/inputs/line-chart/17-card13.flint.json new file mode 100644 index 00000000..4ff315e8 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/line-chart/17-card13.flint.json @@ -0,0 +1,277 @@ +{ + "semantic_types": { + "Date": "Date", + "Sales": "Quantity", + "Product": "Category", + "Type": "Category" + }, + "chart_spec": { + "chartType": "Line Chart", + "encodings": { + "x": "Date", + "y": "Sales", + "color": "Product", + "strokeDash": "Type" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Date": "2024-01-01", + "Sales": 129, + "Product": "Widget A", + "Type": "actual" + }, + { + "Date": "2024-03-25", + "Sales": 133, + "Product": "Widget A", + "Type": "actual" + }, + { + "Date": "2024-06-17", + "Sales": 131, + "Product": "Widget A", + "Type": "actual" + }, + { + "Date": "2024-09-09", + "Sales": 134, + "Product": "Widget A", + "Type": "actual" + }, + { + "Date": "2024-12-02", + "Sales": 132, + "Product": "Widget A", + "Type": "actual" + }, + { + "Date": "2025-02-25", + "Sales": 130, + "Product": "Widget A", + "Type": "actual" + }, + { + "Date": "2025-05-20", + "Sales": 129, + "Product": "Widget A", + "Type": "actual" + }, + { + "Date": "2025-08-12", + "Sales": 133, + "Product": "Widget A", + "Type": "actual" + }, + { + "Date": "2025-11-04", + "Sales": 132, + "Product": "Widget A", + "Type": "actual" + }, + { + "Date": "2026-01-28", + "Sales": 135, + "Product": "Widget A", + "Type": "actual" + }, + { + "Date": "2026-01-28", + "Sales": 135, + "Product": "Widget A", + "Type": "forecast" + }, + { + "Date": "2026-04-22", + "Sales": 139, + "Product": "Widget A", + "Type": "forecast" + }, + { + "Date": "2026-07-15", + "Sales": 149, + "Product": "Widget A", + "Type": "forecast" + }, + { + "Date": "2026-10-07", + "Sales": 153, + "Product": "Widget A", + "Type": "forecast" + }, + { + "Date": "2024-01-01", + "Sales": 100, + "Product": "Widget B", + "Type": "actual" + }, + { + "Date": "2024-03-25", + "Sales": 97, + "Product": "Widget B", + "Type": "actual" + }, + { + "Date": "2024-06-17", + "Sales": 102, + "Product": "Widget B", + "Type": "actual" + }, + { + "Date": "2024-09-09", + "Sales": 108, + "Product": "Widget B", + "Type": "actual" + }, + { + "Date": "2024-12-02", + "Sales": 109, + "Product": "Widget B", + "Type": "actual" + }, + { + "Date": "2025-02-25", + "Sales": 113, + "Product": "Widget B", + "Type": "actual" + }, + { + "Date": "2025-05-20", + "Sales": 118, + "Product": "Widget B", + "Type": "actual" + }, + { + "Date": "2025-08-12", + "Sales": 126, + "Product": "Widget B", + "Type": "actual" + }, + { + "Date": "2025-11-04", + "Sales": 131, + "Product": "Widget B", + "Type": "actual" + }, + { + "Date": "2026-01-28", + "Sales": 137, + "Product": "Widget B", + "Type": "actual" + }, + { + "Date": "2026-01-28", + "Sales": 137, + "Product": "Widget B", + "Type": "forecast" + }, + { + "Date": "2026-04-22", + "Sales": 142, + "Product": "Widget B", + "Type": "forecast" + }, + { + "Date": "2026-07-15", + "Sales": 145, + "Product": "Widget B", + "Type": "forecast" + }, + { + "Date": "2026-10-07", + "Sales": 156, + "Product": "Widget B", + "Type": "forecast" + }, + { + "Date": "2024-01-01", + "Sales": 68, + "Product": "Widget C", + "Type": "actual" + }, + { + "Date": "2024-03-25", + "Sales": 68, + "Product": "Widget C", + "Type": "actual" + }, + { + "Date": "2024-06-17", + "Sales": 69, + "Product": "Widget C", + "Type": "actual" + }, + { + "Date": "2024-09-09", + "Sales": 69, + "Product": "Widget C", + "Type": "actual" + }, + { + "Date": "2024-12-02", + "Sales": 69, + "Product": "Widget C", + "Type": "actual" + }, + { + "Date": "2025-02-25", + "Sales": 69, + "Product": "Widget C", + "Type": "actual" + }, + { + "Date": "2025-05-20", + "Sales": 69, + "Product": "Widget C", + "Type": "actual" + }, + { + "Date": "2025-08-12", + "Sales": 70, + "Product": "Widget C", + "Type": "actual" + }, + { + "Date": "2025-11-04", + "Sales": 71, + "Product": "Widget C", + "Type": "actual" + }, + { + "Date": "2026-01-28", + "Sales": 70, + "Product": "Widget C", + "Type": "actual" + }, + { + "Date": "2026-01-28", + "Sales": 70, + "Product": "Widget C", + "Type": "forecast" + }, + { + "Date": "2026-04-22", + "Sales": 76, + "Product": "Widget C", + "Type": "forecast" + }, + { + "Date": "2026-07-15", + "Sales": 82, + "Product": "Widget C", + "Type": "forecast" + }, + { + "Date": "2026-10-07", + "Sales": 87, + "Product": "Widget C", + "Type": "forecast" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/pie-chart/00-card0.flint.json b/test-harness/excel/evaluations/inputs/pie-chart/00-card0.flint.json new file mode 100644 index 00000000..e222d764 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/pie-chart/00-card0.flint.json @@ -0,0 +1,37 @@ +{ + "semantic_types": { + "Category": "Category", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Pie Chart", + "encodings": { + "size": "Value", + "color": "Category" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Electronics", + "Value": 103 + }, + { + "Category": "Clothing", + "Value": 215 + }, + { + "Category": "Food", + "Value": 342 + }, + { + "Category": "Books", + "Value": 560 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/pie-chart/01-card0.flint.json b/test-harness/excel/evaluations/inputs/pie-chart/01-card0.flint.json new file mode 100644 index 00000000..ea0b281c --- /dev/null +++ b/test-harness/excel/evaluations/inputs/pie-chart/01-card0.flint.json @@ -0,0 +1,61 @@ +{ + "semantic_types": { + "Product": "Product", + "Revenue": "Amount" + }, + "chart_spec": { + "chartType": "Pie Chart", + "encodings": { + "size": "Revenue", + "color": "Product" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Product": "Laptop", + "Revenue": 2924 + }, + { + "Product": "Phone", + "Revenue": 2506 + }, + { + "Product": "Tablet", + "Revenue": 6721 + }, + { + "Product": "Desktop", + "Revenue": 1826 + }, + { + "Product": "Monitor", + "Revenue": 4934 + }, + { + "Product": "Keyboard", + "Revenue": 7789 + }, + { + "Product": "Mouse", + "Revenue": 8215 + }, + { + "Product": "Headphones", + "Revenue": 5798 + }, + { + "Product": "Speaker", + "Revenue": 7950 + }, + { + "Product": "Camera", + "Revenue": 6919 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/pie-chart/02-card0.flint.json b/test-harness/excel/evaluations/inputs/pie-chart/02-card0.flint.json new file mode 100644 index 00000000..552d5daf --- /dev/null +++ b/test-harness/excel/evaluations/inputs/pie-chart/02-card0.flint.json @@ -0,0 +1,101 @@ +{ + "semantic_types": { + "Region": "Category", + "Sales": "Quantity" + }, + "chart_spec": { + "chartType": "Pie Chart", + "encodings": { + "size": "Sales", + "color": "Region" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Region": "Electronics", + "Sales": 4347 + }, + { + "Region": "Clothing", + "Sales": 4301 + }, + { + "Region": "Food", + "Sales": 5098 + }, + { + "Region": "Books", + "Sales": 1293 + }, + { + "Region": "Sports", + "Sales": 4163 + }, + { + "Region": "Home", + "Sales": 2869 + }, + { + "Region": "Garden", + "Sales": 5444 + }, + { + "Region": "Auto", + "Sales": 2591 + }, + { + "Region": "Health", + "Sales": 1407 + }, + { + "Region": "Beauty", + "Sales": 2246 + }, + { + "Region": "Toys", + "Sales": 5168 + }, + { + "Region": "Music", + "Sales": 3215 + }, + { + "Region": "Movies", + "Sales": 3360 + }, + { + "Region": "Software", + "Sales": 1176 + }, + { + "Region": "Games", + "Sales": 4497 + }, + { + "Region": "Office", + "Sales": 5262 + }, + { + "Region": "Pet", + "Sales": 1783 + }, + { + "Region": "Baby", + "Sales": 4292 + }, + { + "Region": "Tools", + "Sales": 5312 + }, + { + "Region": "Crafts", + "Sales": 5358 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/pie-chart/03-card0.flint.json b/test-harness/excel/evaluations/inputs/pie-chart/03-card0.flint.json new file mode 100644 index 00000000..135404a9 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/pie-chart/03-card0.flint.json @@ -0,0 +1,45 @@ +{ + "semantic_types": { + "Category": "Category", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Pie Chart", + "encodings": { + "size": "Value", + "color": "Category" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Dominant", + "Value": 5000 + }, + { + "Category": "Small-A", + "Value": 200 + }, + { + "Category": "Small-B", + "Value": 180 + }, + { + "Category": "Small-C", + "Value": 150 + }, + { + "Category": "Tiny-1", + "Value": 30 + }, + { + "Category": "Tiny-2", + "Value": 20 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/pyramid-chart/00-card18.flint.json b/test-harness/excel/evaluations/inputs/pyramid-chart/00-card18.flint.json new file mode 100644 index 00000000..0ac8cd77 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/pyramid-chart/00-card18.flint.json @@ -0,0 +1,113 @@ +{ + "semantic_types": { + "Age Group": "Category", + "Population": "Quantity", + "Gender": "Category" + }, + "chart_spec": { + "chartType": "Pyramid Chart", + "encodings": { + "y": "Age Group", + "x": "Population", + "color": "Gender" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Age Group": "0-9", + "Gender": "Male", + "Population": 527 + }, + { + "Age Group": "0-9", + "Gender": "Female", + "Population": 1422 + }, + { + "Age Group": "10-19", + "Gender": "Male", + "Population": 974 + }, + { + "Age Group": "10-19", + "Gender": "Female", + "Population": 2170 + }, + { + "Age Group": "20-29", + "Gender": "Male", + "Population": 4821 + }, + { + "Age Group": "20-29", + "Gender": "Female", + "Population": 1091 + }, + { + "Age Group": "30-39", + "Gender": "Male", + "Population": 2992 + }, + { + "Age Group": "30-39", + "Gender": "Female", + "Population": 2650 + }, + { + "Age Group": "40-49", + "Gender": "Male", + "Population": 4160 + }, + { + "Age Group": "40-49", + "Gender": "Female", + "Population": 1654 + }, + { + "Age Group": "50-59", + "Gender": "Male", + "Population": 4915 + }, + { + "Age Group": "50-59", + "Gender": "Female", + "Population": 3139 + }, + { + "Age Group": "60-69", + "Gender": "Male", + "Population": 3470 + }, + { + "Age Group": "60-69", + "Gender": "Female", + "Population": 4381 + }, + { + "Age Group": "70-79", + "Gender": "Male", + "Population": 2929 + }, + { + "Age Group": "70-79", + "Gender": "Female", + "Population": 3097 + }, + { + "Age Group": "80+", + "Gender": "Male", + "Population": 2674 + }, + { + "Age Group": "80+", + "Gender": "Female", + "Population": 4917 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/pyramid-chart/01-card12.flint.json b/test-harness/excel/evaluations/inputs/pyramid-chart/01-card12.flint.json new file mode 100644 index 00000000..f35621c1 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/pyramid-chart/01-card12.flint.json @@ -0,0 +1,83 @@ +{ + "semantic_types": { + "Grade": "Category", + "Count": "Count", + "Type": "Category" + }, + "chart_spec": { + "chartType": "Pyramid Chart", + "encodings": { + "y": "Grade", + "x": "Count", + "color": "Type" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Grade": "Junior", + "Type": "Full-Time", + "Count": 203 + }, + { + "Grade": "Junior", + "Type": "Part-Time", + "Count": 85 + }, + { + "Grade": "Mid-level", + "Type": "Full-Time", + "Count": 97 + }, + { + "Grade": "Mid-level", + "Type": "Part-Time", + "Count": 60 + }, + { + "Grade": "Senior", + "Type": "Full-Time", + "Count": 147 + }, + { + "Grade": "Senior", + "Type": "Part-Time", + "Count": 86 + }, + { + "Grade": "Lead", + "Type": "Full-Time", + "Count": 114 + }, + { + "Grade": "Lead", + "Type": "Part-Time", + "Count": 44 + }, + { + "Grade": "Manager", + "Type": "Full-Time", + "Count": 111 + }, + { + "Grade": "Manager", + "Type": "Part-Time", + "Count": 18 + }, + { + "Grade": "Director", + "Type": "Full-Time", + "Count": 66 + }, + { + "Grade": "Director", + "Type": "Part-Time", + "Count": 76 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/pyramid-chart/02-card10.flint.json b/test-harness/excel/evaluations/inputs/pyramid-chart/02-card10.flint.json new file mode 100644 index 00000000..ce03f066 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/pyramid-chart/02-card10.flint.json @@ -0,0 +1,73 @@ +{ + "semantic_types": { + "Satisfaction Level": "Category", + "Count": "Count", + "Response": "Category" + }, + "chart_spec": { + "chartType": "Pyramid Chart", + "encodings": { + "y": "Satisfaction Level", + "x": "Count", + "color": "Response" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Satisfaction Level": "Very Low", + "Response": "Agree", + "Count": 146 + }, + { + "Satisfaction Level": "Very Low", + "Response": "Disagree", + "Count": 87 + }, + { + "Satisfaction Level": "Low", + "Response": "Agree", + "Count": 328 + }, + { + "Satisfaction Level": "Low", + "Response": "Disagree", + "Count": 250 + }, + { + "Satisfaction Level": "Medium", + "Response": "Agree", + "Count": 331 + }, + { + "Satisfaction Level": "Medium", + "Response": "Disagree", + "Count": 39 + }, + { + "Satisfaction Level": "High", + "Response": "Agree", + "Count": 218 + }, + { + "Satisfaction Level": "High", + "Response": "Disagree", + "Count": 213 + }, + { + "Satisfaction Level": "Very High", + "Response": "Agree", + "Count": 61 + }, + { + "Satisfaction Level": "Very High", + "Response": "Disagree", + "Count": 247 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/pyramid-chart/03-card24.flint.json b/test-harness/excel/evaluations/inputs/pyramid-chart/03-card24.flint.json new file mode 100644 index 00000000..c8755ebe --- /dev/null +++ b/test-harness/excel/evaluations/inputs/pyramid-chart/03-card24.flint.json @@ -0,0 +1,143 @@ +{ + "semantic_types": { + "Income Bracket": "Category", + "Count": "Count", + "Area": "Category" + }, + "chart_spec": { + "chartType": "Pyramid Chart", + "encodings": { + "y": "Income Bracket", + "x": "Count", + "color": "Area" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Income Bracket": "<$20K", + "Area": "Urban", + "Count": 2948 + }, + { + "Income Bracket": "<$20K", + "Area": "Rural", + "Count": 963 + }, + { + "Income Bracket": "$20-30K", + "Area": "Urban", + "Count": 1621 + }, + { + "Income Bracket": "$20-30K", + "Area": "Rural", + "Count": 795 + }, + { + "Income Bracket": "$30-40K", + "Area": "Urban", + "Count": 790 + }, + { + "Income Bracket": "$30-40K", + "Area": "Rural", + "Count": 1034 + }, + { + "Income Bracket": "$40-50K", + "Area": "Urban", + "Count": 2441 + }, + { + "Income Bracket": "$40-50K", + "Area": "Rural", + "Count": 915 + }, + { + "Income Bracket": "$50-60K", + "Area": "Urban", + "Count": 2787 + }, + { + "Income Bracket": "$50-60K", + "Area": "Rural", + "Count": 263 + }, + { + "Income Bracket": "$60-70K", + "Area": "Urban", + "Count": 1799 + }, + { + "Income Bracket": "$60-70K", + "Area": "Rural", + "Count": 475 + }, + { + "Income Bracket": "$70-80K", + "Area": "Urban", + "Count": 2352 + }, + { + "Income Bracket": "$70-80K", + "Area": "Rural", + "Count": 1285 + }, + { + "Income Bracket": "$80-90K", + "Area": "Urban", + "Count": 547 + }, + { + "Income Bracket": "$80-90K", + "Area": "Rural", + "Count": 832 + }, + { + "Income Bracket": "$90-100K", + "Area": "Urban", + "Count": 172 + }, + { + "Income Bracket": "$90-100K", + "Area": "Rural", + "Count": 1038 + }, + { + "Income Bracket": "$100-120K", + "Area": "Urban", + "Count": 1464 + }, + { + "Income Bracket": "$100-120K", + "Area": "Rural", + "Count": 197 + }, + { + "Income Bracket": "$120-150K", + "Area": "Urban", + "Count": 2846 + }, + { + "Income Bracket": "$120-150K", + "Area": "Rural", + "Count": 109 + }, + { + "Income Bracket": "$150K+", + "Area": "Urban", + "Count": 577 + }, + { + "Income Bracket": "$150K+", + "Area": "Rural", + "Count": 1857 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/pyramid-chart/04-card10.flint.json b/test-harness/excel/evaluations/inputs/pyramid-chart/04-card10.flint.json new file mode 100644 index 00000000..6f67c702 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/pyramid-chart/04-card10.flint.json @@ -0,0 +1,73 @@ +{ + "semantic_types": { + "Degree Level": "Category", + "Count": "Count", + "Outcome": "Category" + }, + "chart_spec": { + "chartType": "Pyramid Chart", + "encodings": { + "y": "Degree Level", + "x": "Count", + "color": "Outcome" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Degree Level": "High School", + "Outcome": "Admitted", + "Count": 3305 + }, + { + "Degree Level": "High School", + "Outcome": "Rejected", + "Count": 2560 + }, + { + "Degree Level": "Associate", + "Outcome": "Admitted", + "Count": 4171 + }, + { + "Degree Level": "Associate", + "Outcome": "Rejected", + "Count": 1598 + }, + { + "Degree Level": "Bachelor", + "Outcome": "Admitted", + "Count": 2264 + }, + { + "Degree Level": "Bachelor", + "Outcome": "Rejected", + "Count": 1009 + }, + { + "Degree Level": "Master", + "Outcome": "Admitted", + "Count": 447 + }, + { + "Degree Level": "Master", + "Outcome": "Rejected", + "Count": 1535 + }, + { + "Degree Level": "Doctorate", + "Outcome": "Admitted", + "Count": 1663 + }, + { + "Degree Level": "Doctorate", + "Outcome": "Rejected", + "Count": 208 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/pyramid-chart/05-card20.flint.json b/test-harness/excel/evaluations/inputs/pyramid-chart/05-card20.flint.json new file mode 100644 index 00000000..33e56e8a --- /dev/null +++ b/test-harness/excel/evaluations/inputs/pyramid-chart/05-card20.flint.json @@ -0,0 +1,123 @@ +{ + "semantic_types": { + "Country": "Country", + "Value": "Amount", + "Direction": "Category" + }, + "chart_spec": { + "chartType": "Pyramid Chart", + "encodings": { + "y": "Country", + "x": "Value", + "color": "Direction" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Country": "USA", + "Direction": "Import", + "Value": 31686 + }, + { + "Country": "USA", + "Direction": "Export", + "Value": 44720 + }, + { + "Country": "China", + "Direction": "Import", + "Value": 8071 + }, + { + "Country": "China", + "Direction": "Export", + "Value": 46763 + }, + { + "Country": "Japan", + "Direction": "Import", + "Value": 35829 + }, + { + "Country": "Japan", + "Direction": "Export", + "Value": 23447 + }, + { + "Country": "Germany", + "Direction": "Import", + "Value": 11702 + }, + { + "Country": "Germany", + "Direction": "Export", + "Value": 21445 + }, + { + "Country": "UK", + "Direction": "Import", + "Value": 17460 + }, + { + "Country": "UK", + "Direction": "Export", + "Value": 47488 + }, + { + "Country": "France", + "Direction": "Import", + "Value": 32401 + }, + { + "Country": "France", + "Direction": "Export", + "Value": 8762 + }, + { + "Country": "India", + "Direction": "Import", + "Value": 3322 + }, + { + "Country": "India", + "Direction": "Export", + "Value": 33256 + }, + { + "Country": "Brazil", + "Direction": "Import", + "Value": 29939 + }, + { + "Country": "Brazil", + "Direction": "Export", + "Value": 22031 + }, + { + "Country": "Canada", + "Direction": "Import", + "Value": 10621 + }, + { + "Country": "Canada", + "Direction": "Export", + "Value": 1603 + }, + { + "Country": "Australia", + "Direction": "Import", + "Value": 37942 + }, + { + "Country": "Australia", + "Direction": "Export", + "Value": 41683 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/pyramid-chart/06-card40.flint.json b/test-harness/excel/evaluations/inputs/pyramid-chart/06-card40.flint.json new file mode 100644 index 00000000..cdb0f397 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/pyramid-chart/06-card40.flint.json @@ -0,0 +1,223 @@ +{ + "semantic_types": { + "Age Band": "Category", + "Population": "Quantity", + "Gender": "Category" + }, + "chart_spec": { + "chartType": "Pyramid Chart", + "encodings": { + "y": "Age Band", + "x": "Population", + "color": "Gender" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Age Band": "0-4", + "Gender": "Male", + "Population": 2562 + }, + { + "Age Band": "0-4", + "Gender": "Female", + "Population": 2821 + }, + { + "Age Band": "5-9", + "Gender": "Male", + "Population": 1694 + }, + { + "Age Band": "5-9", + "Gender": "Female", + "Population": 7030 + }, + { + "Age Band": "10-14", + "Gender": "Male", + "Population": 2276 + }, + { + "Age Band": "10-14", + "Gender": "Female", + "Population": 6293 + }, + { + "Age Band": "15-19", + "Gender": "Male", + "Population": 4082 + }, + { + "Age Band": "15-19", + "Gender": "Female", + "Population": 4774 + }, + { + "Age Band": "20-24", + "Gender": "Male", + "Population": 1512 + }, + { + "Age Band": "20-24", + "Gender": "Female", + "Population": 4685 + }, + { + "Age Band": "25-29", + "Gender": "Male", + "Population": 3723 + }, + { + "Age Band": "25-29", + "Gender": "Female", + "Population": 1606 + }, + { + "Age Band": "30-34", + "Gender": "Male", + "Population": 3954 + }, + { + "Age Band": "30-34", + "Gender": "Female", + "Population": 5662 + }, + { + "Age Band": "35-39", + "Gender": "Male", + "Population": 2340 + }, + { + "Age Band": "35-39", + "Gender": "Female", + "Population": 2752 + }, + { + "Age Band": "40-44", + "Gender": "Male", + "Population": 2722 + }, + { + "Age Band": "40-44", + "Gender": "Female", + "Population": 3587 + }, + { + "Age Band": "45-49", + "Gender": "Male", + "Population": 7493 + }, + { + "Age Band": "45-49", + "Gender": "Female", + "Population": 1024 + }, + { + "Age Band": "50-54", + "Gender": "Male", + "Population": 4263 + }, + { + "Age Band": "50-54", + "Gender": "Female", + "Population": 2318 + }, + { + "Age Band": "55-59", + "Gender": "Male", + "Population": 1315 + }, + { + "Age Band": "55-59", + "Gender": "Female", + "Population": 2663 + }, + { + "Age Band": "60-64", + "Gender": "Male", + "Population": 2837 + }, + { + "Age Band": "60-64", + "Gender": "Female", + "Population": 2936 + }, + { + "Age Band": "65-69", + "Gender": "Male", + "Population": 5796 + }, + { + "Age Band": "65-69", + "Gender": "Female", + "Population": 3040 + }, + { + "Age Band": "70-74", + "Gender": "Male", + "Population": 2846 + }, + { + "Age Band": "70-74", + "Gender": "Female", + "Population": 7447 + }, + { + "Age Band": "75-79", + "Gender": "Male", + "Population": 7263 + }, + { + "Age Band": "75-79", + "Gender": "Female", + "Population": 4439 + }, + { + "Age Band": "80-84", + "Gender": "Male", + "Population": 6170 + }, + { + "Age Band": "80-84", + "Gender": "Female", + "Population": 3486 + }, + { + "Age Band": "85-89", + "Gender": "Male", + "Population": 4649 + }, + { + "Age Band": "85-89", + "Gender": "Female", + "Population": 6026 + }, + { + "Age Band": "90-94", + "Gender": "Male", + "Population": 1734 + }, + { + "Age Band": "90-94", + "Gender": "Female", + "Population": 5397 + }, + { + "Age Band": "95-99", + "Gender": "Male", + "Population": 6683 + }, + { + "Age Band": "95-99", + "Gender": "Female", + "Population": 3448 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/pyramid-chart/07-card12.flint.json b/test-harness/excel/evaluations/inputs/pyramid-chart/07-card12.flint.json new file mode 100644 index 00000000..68ed2b33 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/pyramid-chart/07-card12.flint.json @@ -0,0 +1,83 @@ +{ + "semantic_types": { + "Age Group": "Category", + "Population": "Quantity", + "Gender": "Category" + }, + "chart_spec": { + "chartType": "Pyramid Chart", + "encodings": { + "y": "Age Group", + "x": "Population", + "color": "Gender" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Age Group": "0-14", + "Gender": "Male", + "Population": 2612 + }, + { + "Age Group": "0-14", + "Gender": "Female", + "Population": 619 + }, + { + "Age Group": "15-29", + "Gender": "Male", + "Population": 695 + }, + { + "Age Group": "15-29", + "Gender": "Female", + "Population": 1916 + }, + { + "Age Group": "30-44", + "Gender": "Male", + "Population": 476 + }, + { + "Age Group": "30-44", + "Gender": "Female", + "Population": -257 + }, + { + "Age Group": "45-59", + "Gender": "Male", + "Population": 1558 + }, + { + "Age Group": "45-59", + "Gender": "Female", + "Population": 934 + }, + { + "Age Group": "60-74", + "Gender": "Male", + "Population": 2 + }, + { + "Age Group": "60-74", + "Gender": "Female", + "Population": 98 + }, + { + "Age Group": "75+", + "Gender": "Male", + "Population": -388 + }, + { + "Age Group": "75+", + "Gender": "Female", + "Population": 1841 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/radar-chart/00-card5.flint.json b/test-harness/excel/evaluations/inputs/radar-chart/00-card5.flint.json new file mode 100644 index 00000000..577fd9a8 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/radar-chart/00-card5.flint.json @@ -0,0 +1,48 @@ +{ + "semantic_types": { + "Player": "Category", + "Metric": "Category", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Radar Chart", + "encodings": { + "x": "Metric", + "y": "Value", + "color": "Player" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Player": "Player A", + "Metric": "Speed", + "Value": 85 + }, + { + "Player": "Player A", + "Metric": "Shooting", + "Value": 70 + }, + { + "Player": "Player A", + "Metric": "Passing", + "Value": 90 + }, + { + "Player": "Player A", + "Metric": "Dribbling", + "Value": 80 + }, + { + "Player": "Player A", + "Metric": "Defense", + "Value": 60 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/radar-chart/01-card6.flint.json b/test-harness/excel/evaluations/inputs/radar-chart/01-card6.flint.json new file mode 100644 index 00000000..20c379a0 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/radar-chart/01-card6.flint.json @@ -0,0 +1,83 @@ +{ + "semantic_types": { + "Team": "Category", + "Metric": "Category", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Radar Chart", + "encodings": { + "x": "Metric", + "y": "Value", + "color": "Team" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Team": "Team A", + "Metric": "Attack", + "Value": 85 + }, + { + "Team": "Team A", + "Metric": "Defense", + "Value": 70 + }, + { + "Team": "Team A", + "Metric": "Midfield", + "Value": 78 + }, + { + "Team": "Team A", + "Metric": "Speed", + "Value": 90 + }, + { + "Team": "Team A", + "Metric": "Stamina", + "Value": 65 + }, + { + "Team": "Team A", + "Metric": "Tactics", + "Value": 80 + }, + { + "Team": "Team B", + "Metric": "Attack", + "Value": 72 + }, + { + "Team": "Team B", + "Metric": "Defense", + "Value": 88 + }, + { + "Team": "Team B", + "Metric": "Midfield", + "Value": 82 + }, + { + "Team": "Team B", + "Metric": "Speed", + "Value": 68 + }, + { + "Team": "Team B", + "Metric": "Stamina", + "Value": 85 + }, + { + "Team": "Team B", + "Metric": "Tactics", + "Value": 75 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/radar-chart/02-card5.flint.json b/test-harness/excel/evaluations/inputs/radar-chart/02-card5.flint.json new file mode 100644 index 00000000..8cb22580 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/radar-chart/02-card5.flint.json @@ -0,0 +1,101 @@ +{ + "semantic_types": { + "Product": "Category", + "Metric": "Category", + "Value": "Quantity" + }, + "chart_spec": { + "chartType": "Radar Chart", + "encodings": { + "x": "Metric", + "y": "Value", + "color": "Product" + }, + "baseSize": { + "width": 560, + "height": 360 + }, + "chartProperties": { + "filled": false + } + }, + "data": { + "values": [ + { + "Product": "Widget", + "Metric": "Quality", + "Value": 90 + }, + { + "Product": "Widget", + "Metric": "Price", + "Value": 60 + }, + { + "Product": "Widget", + "Metric": "Durability", + "Value": 80 + }, + { + "Product": "Widget", + "Metric": "Design", + "Value": 75 + }, + { + "Product": "Widget", + "Metric": "Support", + "Value": 85 + }, + { + "Product": "Gadget", + "Metric": "Quality", + "Value": 70 + }, + { + "Product": "Gadget", + "Metric": "Price", + "Value": 85 + }, + { + "Product": "Gadget", + "Metric": "Durability", + "Value": 65 + }, + { + "Product": "Gadget", + "Metric": "Design", + "Value": 90 + }, + { + "Product": "Gadget", + "Metric": "Support", + "Value": 50 + }, + { + "Product": "Doohickey", + "Metric": "Quality", + "Value": 80 + }, + { + "Product": "Doohickey", + "Metric": "Price", + "Value": 70 + }, + { + "Product": "Doohickey", + "Metric": "Durability", + "Value": 90 + }, + { + "Product": "Doohickey", + "Metric": "Design", + "Value": 60 + }, + { + "Product": "Doohickey", + "Metric": "Support", + "Value": 70 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/radar-chart/04-card5.flint.json b/test-harness/excel/evaluations/inputs/radar-chart/04-card5.flint.json new file mode 100644 index 00000000..022dec3e --- /dev/null +++ b/test-harness/excel/evaluations/inputs/radar-chart/04-card5.flint.json @@ -0,0 +1,73 @@ +{ + "semantic_types": { + "Category": "Category", + "Assessment": "Category", + "Score": "Quantity" + }, + "chart_spec": { + "chartType": "Radar Chart", + "encodings": { + "x": "Category", + "y": "Score", + "color": "Assessment" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Customer Satisfaction Score", + "Assessment": "Product A", + "Score": 82 + }, + { + "Category": "Annual Revenue Growth Rate", + "Assessment": "Product A", + "Score": 91 + }, + { + "Category": "Employee Retention", + "Assessment": "Product A", + "Score": 74 + }, + { + "Category": "Market Share Percentage", + "Assessment": "Product A", + "Score": 68 + }, + { + "Category": "Net Promoter Score", + "Assessment": "Product A", + "Score": 88 + }, + { + "Category": "Customer Satisfaction Score", + "Assessment": "Product B", + "Score": 70 + }, + { + "Category": "Annual Revenue Growth Rate", + "Assessment": "Product B", + "Score": 65 + }, + { + "Category": "Employee Retention", + "Assessment": "Product B", + "Score": 85 + }, + { + "Category": "Market Share Percentage", + "Assessment": "Product B", + "Score": 78 + }, + { + "Category": "Net Promoter Score", + "Assessment": "Product B", + "Score": 60 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/radar-chart/05-card8.flint.json b/test-harness/excel/evaluations/inputs/radar-chart/05-card8.flint.json new file mode 100644 index 00000000..0fd99b23 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/radar-chart/05-card8.flint.json @@ -0,0 +1,103 @@ +{ + "semantic_types": { + "App": "Category", + "KPI": "Category", + "Rating": "Quantity" + }, + "chart_spec": { + "chartType": "Radar Chart", + "encodings": { + "x": "KPI", + "y": "Rating", + "color": "App" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "App": "Frontend", + "KPI": "Overall User Experience", + "Rating": 56 + }, + { + "App": "Backend", + "KPI": "Overall User Experience", + "Rating": 87 + }, + { + "App": "Frontend", + "KPI": "First Contentful Paint", + "Rating": 76 + }, + { + "App": "Backend", + "KPI": "First Contentful Paint", + "Rating": 50 + }, + { + "App": "Frontend", + "KPI": "Time to Interactive", + "Rating": 72 + }, + { + "App": "Backend", + "KPI": "Time to Interactive", + "Rating": 100 + }, + { + "App": "Frontend", + "KPI": "Cumulative Layout Shift", + "Rating": 99 + }, + { + "App": "Backend", + "KPI": "Cumulative Layout Shift", + "Rating": 68 + }, + { + "App": "Frontend", + "KPI": "Server Response Time", + "Rating": 53 + }, + { + "App": "Backend", + "KPI": "Server Response Time", + "Rating": 87 + }, + { + "App": "Frontend", + "KPI": "Error Rate per Minute", + "Rating": 57 + }, + { + "App": "Backend", + "KPI": "Error Rate per Minute", + "Rating": 89 + }, + { + "App": "Frontend", + "KPI": "Database Query Latency", + "Rating": 51 + }, + { + "App": "Backend", + "KPI": "Database Query Latency", + "Rating": 76 + }, + { + "App": "Frontend", + "KPI": "API Throughput", + "Rating": 93 + }, + { + "App": "Backend", + "KPI": "API Throughput", + "Rating": 53 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/radar-chart/06-card12.flint.json b/test-harness/excel/evaluations/inputs/radar-chart/06-card12.flint.json new file mode 100644 index 00000000..75eaad1a --- /dev/null +++ b/test-harness/excel/evaluations/inputs/radar-chart/06-card12.flint.json @@ -0,0 +1,203 @@ +{ + "semantic_types": { + "Division": "Category", + "Factor": "Category", + "Score": "Quantity" + }, + "chart_spec": { + "chartType": "Radar Chart", + "encodings": { + "x": "Factor", + "y": "Score", + "color": "Division" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Division": "Americas", + "Factor": "Revenue", + "Score": 40 + }, + { + "Division": "EMEA", + "Factor": "Revenue", + "Score": 36 + }, + { + "Division": "APAC", + "Factor": "Revenue", + "Score": 38 + }, + { + "Division": "Americas", + "Factor": "Profit Margin", + "Score": 67 + }, + { + "Division": "EMEA", + "Factor": "Profit Margin", + "Score": 47 + }, + { + "Division": "APAC", + "Factor": "Profit Margin", + "Score": 38 + }, + { + "Division": "Americas", + "Factor": "Customer Retention", + "Score": 83 + }, + { + "Division": "EMEA", + "Factor": "Customer Retention", + "Score": 87 + }, + { + "Division": "APAC", + "Factor": "Customer Retention", + "Score": 92 + }, + { + "Division": "Americas", + "Factor": "Brand Awareness", + "Score": 42 + }, + { + "Division": "EMEA", + "Factor": "Brand Awareness", + "Score": 48 + }, + { + "Division": "APAC", + "Factor": "Brand Awareness", + "Score": 58 + }, + { + "Division": "Americas", + "Factor": "Market Penetration", + "Score": 56 + }, + { + "Division": "EMEA", + "Factor": "Market Penetration", + "Score": 33 + }, + { + "Division": "APAC", + "Factor": "Market Penetration", + "Score": 70 + }, + { + "Division": "Americas", + "Factor": "Product Quality", + "Score": 88 + }, + { + "Division": "EMEA", + "Factor": "Product Quality", + "Score": 84 + }, + { + "Division": "APAC", + "Factor": "Product Quality", + "Score": 45 + }, + { + "Division": "Americas", + "Factor": "Employee Engagement", + "Score": 64 + }, + { + "Division": "EMEA", + "Factor": "Employee Engagement", + "Score": 90 + }, + { + "Division": "APAC", + "Factor": "Employee Engagement", + "Score": 76 + }, + { + "Division": "Americas", + "Factor": "Innovation Index", + "Score": 73 + }, + { + "Division": "EMEA", + "Factor": "Innovation Index", + "Score": 46 + }, + { + "Division": "APAC", + "Factor": "Innovation Index", + "Score": 50 + }, + { + "Division": "Americas", + "Factor": "Supply Chain Efficiency", + "Score": 44 + }, + { + "Division": "EMEA", + "Factor": "Supply Chain Efficiency", + "Score": 80 + }, + { + "Division": "APAC", + "Factor": "Supply Chain Efficiency", + "Score": 90 + }, + { + "Division": "Americas", + "Factor": "Digital Transformation", + "Score": 44 + }, + { + "Division": "EMEA", + "Factor": "Digital Transformation", + "Score": 53 + }, + { + "Division": "APAC", + "Factor": "Digital Transformation", + "Score": 77 + }, + { + "Division": "Americas", + "Factor": "Sustainability Rating", + "Score": 100 + }, + { + "Division": "EMEA", + "Factor": "Sustainability Rating", + "Score": 77 + }, + { + "Division": "APAC", + "Factor": "Sustainability Rating", + "Score": 44 + }, + { + "Division": "Americas", + "Factor": "Compliance Score", + "Score": 89 + }, + { + "Division": "EMEA", + "Factor": "Compliance Score", + "Score": 31 + }, + { + "Division": "APAC", + "Factor": "Compliance Score", + "Score": 30 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/scatter-plot/00-card20.flint.json b/test-harness/excel/evaluations/inputs/scatter-plot/00-card20.flint.json new file mode 100644 index 00000000..c7f41caa --- /dev/null +++ b/test-harness/excel/evaluations/inputs/scatter-plot/00-card20.flint.json @@ -0,0 +1,101 @@ +{ + "semantic_types": { + "X": "Quantity", + "Y": "Quantity" + }, + "chart_spec": { + "chartType": "Scatter Plot", + "encodings": { + "x": "X", + "y": "Y" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 0, + "Y": 52.5 + }, + { + "X": 73.5, + "Y": 26.3 + }, + { + "X": 37.6, + "Y": 19.6 + }, + { + "X": 97.6, + "Y": 51.2 + }, + { + "X": 53, + "Y": 25.7 + }, + { + "X": 10.7, + "Y": 81.5 + }, + { + "X": 90.1, + "Y": 45.2 + }, + { + "X": 24.5, + "Y": 24.7 + }, + { + "X": 18.8, + "Y": 32.3 + }, + { + "X": 10.3, + "Y": 80.7 + }, + { + "X": 53.4, + "Y": 84.4 + }, + { + "X": 73.7, + "Y": 7.8 + }, + { + "X": 53.9, + "Y": 13.1 + }, + { + "X": 86.3, + "Y": 46.5 + }, + { + "X": 47.2, + "Y": 45 + }, + { + "X": 23.3, + "Y": 1.2 + }, + { + "X": 2.3, + "Y": 99.4 + }, + { + "X": 91.5, + "Y": 78.6 + }, + { + "X": 57.1, + "Y": 76.9 + }, + { + "X": 62.4, + "Y": 34.4 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/scatter-plot/01-card20.flint.json b/test-harness/excel/evaluations/inputs/scatter-plot/01-card20.flint.json new file mode 100644 index 00000000..796b4995 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/scatter-plot/01-card20.flint.json @@ -0,0 +1,123 @@ +{ + "semantic_types": { + "X": "Quantity", + "Y": "Quantity", + "Segment": "Category" + }, + "chart_spec": { + "chartType": "Scatter Plot", + "encodings": { + "x": "X", + "y": "Y", + "color": "Segment" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 37.6, + "Y": 26.7, + "Segment": "Electronics" + }, + { + "X": 35.2, + "Y": 64.1, + "Segment": "Clothing" + }, + { + "X": 36.4, + "Y": 5.3, + "Segment": "Food" + }, + { + "X": 52.9, + "Y": 15.8, + "Segment": "Electronics" + }, + { + "X": 45.4, + "Y": 32.9, + "Segment": "Clothing" + }, + { + "X": 19.3, + "Y": 6.5, + "Segment": "Food" + }, + { + "X": 98.7, + "Y": 54.6, + "Segment": "Electronics" + }, + { + "X": 8.9, + "Y": 99.3, + "Segment": "Clothing" + }, + { + "X": 43.4, + "Y": 70.2, + "Segment": "Food" + }, + { + "X": 18.7, + "Y": 54.4, + "Segment": "Electronics" + }, + { + "X": 99.5, + "Y": 19, + "Segment": "Clothing" + }, + { + "X": 68.4, + "Y": 39.9, + "Segment": "Food" + }, + { + "X": 43.9, + "Y": 74.7, + "Segment": "Electronics" + }, + { + "X": 17.8, + "Y": 81.1, + "Segment": "Clothing" + }, + { + "X": 80.6, + "Y": 9.7, + "Segment": "Food" + }, + { + "X": 3, + "Y": 13.4, + "Segment": "Electronics" + }, + { + "X": 63.7, + "Y": 38, + "Segment": "Clothing" + }, + { + "X": 24.9, + "Y": 50.7, + "Segment": "Food" + }, + { + "X": 52.1, + "Y": 10.4, + "Segment": "Electronics" + }, + { + "X": 98.4, + "Y": 34.9, + "Segment": "Clothing" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/scatter-plot/02-card20.flint.json b/test-harness/excel/evaluations/inputs/scatter-plot/02-card20.flint.json new file mode 100644 index 00000000..8e81c7f2 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/scatter-plot/02-card20.flint.json @@ -0,0 +1,123 @@ +{ + "semantic_types": { + "X": "Quantity", + "Y": "Quantity", + "ColorVal": "Quantity" + }, + "chart_spec": { + "chartType": "Scatter Plot", + "encodings": { + "x": "X", + "y": "Y", + "color": "ColorVal" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 76.8, + "Y": 26.5, + "ColorVal": 66.6 + }, + { + "X": 91.5, + "Y": 46.6, + "ColorVal": 44.1 + }, + { + "X": 92.1, + "Y": 46.7, + "ColorVal": 97.7 + }, + { + "X": 32, + "Y": 79.4, + "ColorVal": 86.6 + }, + { + "X": 74.3, + "Y": 55.7, + "ColorVal": 82.7 + }, + { + "X": 53.1, + "Y": 30.7, + "ColorVal": 34.3 + }, + { + "X": 31.1, + "Y": 44.7, + "ColorVal": 56.7 + }, + { + "X": 65.3, + "Y": 6.3, + "ColorVal": 49 + }, + { + "X": 45.6, + "Y": 1, + "ColorVal": 70.1 + }, + { + "X": 38.8, + "Y": 44.7, + "ColorVal": 93.6 + }, + { + "X": 12.5, + "Y": 42.8, + "ColorVal": 29.3 + }, + { + "X": 41.1, + "Y": 24.4, + "ColorVal": 36.6 + }, + { + "X": 71, + "Y": 93.6, + "ColorVal": 1.8 + }, + { + "X": 47.8, + "Y": 82.2, + "ColorVal": 53.3 + }, + { + "X": 12.6, + "Y": 40, + "ColorVal": 12.9 + }, + { + "X": 81.2, + "Y": 39.2, + "ColorVal": 7.6 + }, + { + "X": 59.8, + "Y": 33.7, + "ColorVal": 25.4 + }, + { + "X": 38.6, + "Y": 31.4, + "ColorVal": 61.7 + }, + { + "X": 20.4, + "Y": 28.4, + "ColorVal": 98.9 + }, + { + "X": 19.6, + "Y": 66.2, + "ColorVal": 51.4 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/scatter-plot/03-card30.flint.json b/test-harness/excel/evaluations/inputs/scatter-plot/03-card30.flint.json new file mode 100644 index 00000000..7513f0b4 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/scatter-plot/03-card30.flint.json @@ -0,0 +1,173 @@ +{ + "semantic_types": { + "X": "Quantity", + "Y": "Quantity", + "Timestamp": "Date" + }, + "chart_spec": { + "chartType": "Scatter Plot", + "encodings": { + "x": "X", + "y": "Y", + "color": "Timestamp" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 78.5, + "Y": 12.7, + "Timestamp": "2020-01-01" + }, + { + "X": 35.8, + "Y": 22.2, + "Timestamp": "2020-02-06" + }, + { + "X": 29.9, + "Y": 16.8, + "Timestamp": "2020-03-14" + }, + { + "X": 95.6, + "Y": 72.6, + "Timestamp": "2020-04-19" + }, + { + "X": 58.9, + "Y": 51.8, + "Timestamp": "2020-05-26" + }, + { + "X": 48.9, + "Y": 36.6, + "Timestamp": "2020-07-01" + }, + { + "X": 29.3, + "Y": 39, + "Timestamp": "2020-08-07" + }, + { + "X": 40.8, + "Y": 42.9, + "Timestamp": "2020-09-12" + }, + { + "X": 32.2, + "Y": 35.3, + "Timestamp": "2020-10-19" + }, + { + "X": 10.9, + "Y": 72.9, + "Timestamp": "2020-11-24" + }, + { + "X": 40.9, + "Y": 1, + "Timestamp": "2020-12-31" + }, + { + "X": 35.1, + "Y": 53.7, + "Timestamp": "2021-02-05" + }, + { + "X": 19.2, + "Y": 87, + "Timestamp": "2021-03-14" + }, + { + "X": 91.3, + "Y": 96.5, + "Timestamp": "2021-04-19" + }, + { + "X": 79.4, + "Y": 23.3, + "Timestamp": "2021-05-26" + }, + { + "X": 51, + "Y": 19.7, + "Timestamp": "2021-07-01" + }, + { + "X": 87.1, + "Y": 81.2, + "Timestamp": "2021-08-07" + }, + { + "X": 98.5, + "Y": 34.4, + "Timestamp": "2021-09-12" + }, + { + "X": 62.8, + "Y": 67.5, + "Timestamp": "2021-10-19" + }, + { + "X": 89.2, + "Y": 12.3, + "Timestamp": "2021-11-24" + }, + { + "X": 68, + "Y": 99.7, + "Timestamp": "2021-12-31" + }, + { + "X": 97.6, + "Y": 13, + "Timestamp": "2022-02-05" + }, + { + "X": 36.9, + "Y": 4, + "Timestamp": "2022-03-14" + }, + { + "X": 54.3, + "Y": 17.5, + "Timestamp": "2022-04-19" + }, + { + "X": 50.5, + "Y": 15.6, + "Timestamp": "2022-05-26" + }, + { + "X": 79.3, + "Y": 25, + "Timestamp": "2022-07-01" + }, + { + "X": 21.7, + "Y": 33.8, + "Timestamp": "2022-08-07" + }, + { + "X": 74.5, + "Y": 41.4, + "Timestamp": "2022-09-12" + }, + { + "X": 95.7, + "Y": 57.5, + "Timestamp": "2022-10-19" + }, + { + "X": 45.2, + "Y": 63.7, + "Timestamp": "2022-11-24" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/scatter-plot/04-card47.flint.json b/test-harness/excel/evaluations/inputs/scatter-plot/04-card47.flint.json new file mode 100644 index 00000000..fa3fa857 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/scatter-plot/04-card47.flint.json @@ -0,0 +1,273 @@ +{ + "semantic_types": { + "X": "Quantity", + "Y": "Quantity", + "Size": "Quantity" + }, + "chart_spec": { + "chartType": "Scatter Plot", + "encodings": { + "x": "X", + "y": "Y", + "size": "Size" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 93.7, + "Y": 49.3, + "Size": 46 + }, + { + "X": 8.5, + "Y": 75.3, + "Size": 15.1 + }, + { + "X": 57.2, + "Y": 60.6, + "Size": 34.4 + }, + { + "X": 38.9, + "Y": 22.2, + "Size": 81.6 + }, + { + "X": 48.2, + "Y": 64.9, + "Size": 50.9 + }, + { + "X": 5.7, + "Y": 63, + "Size": 67.4 + }, + { + "X": 15.2, + "Y": 80.2, + "Size": 21.3 + }, + { + "X": 4.9, + "Y": 46, + "Size": 73.8 + }, + { + "X": 96.4, + "Y": 53.6, + "Size": 4.3 + }, + { + "X": 64.6, + "Y": 38.1, + "Size": 49.9 + }, + { + "X": 36.7, + "Y": 38.1, + "Size": 84.6 + }, + { + "X": 84.6, + "Y": 91.5, + "Size": 55.3 + }, + { + "X": 5.2, + "Y": 73.3, + "Size": 26.1 + }, + { + "X": 61.6, + "Y": 2.3, + "Size": 46.8 + }, + { + "X": 63.6, + "Y": 87.9, + "Size": 33.7 + }, + { + "X": 88.4, + "Y": 96.3, + "Size": 45.1 + }, + { + "X": 48.1, + "Y": 88.7, + "Size": 2.5 + }, + { + "X": 3.7, + "Y": 48.1, + "Size": 54.8 + }, + { + "X": 40.5, + "Y": 54.4, + "Size": 66.5 + }, + { + "X": 58.4, + "Y": 62.1, + "Size": 13 + }, + { + "X": 77.5, + "Y": 80.6, + "Size": 97.1 + }, + { + "X": 43.3, + "Y": 8.8, + "Size": 44.2 + }, + { + "X": 98.2, + "Y": 96.9, + "Size": 40.5 + }, + { + "X": 33.1, + "Y": 99.1, + "Size": 79.7 + }, + { + "X": 37.4, + "Y": 30.7, + "Size": 7.1 + }, + { + "X": 92.9, + "Y": 62.8, + "Size": 92.2 + }, + { + "X": 74.3, + "Y": 85.1, + "Size": 14.7 + }, + { + "X": 47.5, + "Y": 5.7, + "Size": 29.6 + }, + { + "X": 25, + "Y": 42.8, + "Size": 73.1 + }, + { + "X": 72.2, + "Y": 24.2, + "Size": 42.9 + }, + { + "X": 79.1, + "Y": 62.5, + "Size": 49.3 + }, + { + "X": 80.1, + "Y": 81.1, + "Size": 26.9 + }, + { + "X": 21.5, + "Y": 65.8, + "Size": 23.2 + }, + { + "X": 38, + "Y": 24.2, + "Size": 62.3 + }, + { + "X": 12, + "Y": 60.4, + "Size": 37.1 + }, + { + "X": 12.5, + "Y": 53.4, + "Size": 38.9 + }, + { + "X": 39.3, + "Y": 93.2, + "Size": 2.8 + }, + { + "X": 9.7, + "Y": 26.4, + "Size": 69.6 + }, + { + "X": 84.6, + "Y": 52.6, + "Size": 0.8 + }, + { + "X": 79.1, + "Y": 38.4, + "Size": 12.9 + }, + { + "X": 15.7, + "Y": 38.7, + "Size": 3.8 + }, + { + "X": 27.2, + "Y": 68.4, + "Size": 19.9 + }, + { + "X": 5.1, + "Y": 70.1, + "Size": 76 + }, + { + "X": 9.6, + "Y": 87.1, + "Size": 55 + }, + { + "X": 50.7, + "Y": 76.8, + "Size": 98.8 + }, + { + "X": 28.9, + "Y": 73, + "Size": 28.7 + }, + { + "X": 52.9, + "Y": 66.5, + "Size": 21.5 + }, + { + "X": 40.2, + "Y": 58.5, + "Size": 60.2 + }, + { + "X": 27.2, + "Y": 68, + "Size": 34.9 + }, + { + "X": 48.7, + "Y": 50.6, + "Size": 33.8 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/scatter-plot/05-card20.flint.json b/test-harness/excel/evaluations/inputs/scatter-plot/05-card20.flint.json new file mode 100644 index 00000000..ad18f944 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/scatter-plot/05-card20.flint.json @@ -0,0 +1,123 @@ +{ + "semantic_types": { + "X": "Quantity", + "Y": "Quantity", + "Level": "Rank" + }, + "chart_spec": { + "chartType": "Scatter Plot", + "encodings": { + "x": "X", + "y": "Y", + "size": "Level" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 72, + "Y": 77.7, + "Level": "Low" + }, + { + "X": 87.7, + "Y": 43.7, + "Level": "Medium" + }, + { + "X": 43.3, + "Y": 31.7, + "Level": "High" + }, + { + "X": 14.4, + "Y": 44, + "Level": "Critical" + }, + { + "X": 75.2, + "Y": 95.8, + "Level": "Low" + }, + { + "X": 82.8, + "Y": 62.8, + "Level": "Medium" + }, + { + "X": 51.7, + "Y": 0.5, + "Level": "High" + }, + { + "X": 93.8, + "Y": 55, + "Level": "Critical" + }, + { + "X": 19.8, + "Y": 74.4, + "Level": "Low" + }, + { + "X": 36.3, + "Y": 44.7, + "Level": "Medium" + }, + { + "X": 14.9, + "Y": 14.2, + "Level": "High" + }, + { + "X": 31.8, + "Y": 92.8, + "Level": "Critical" + }, + { + "X": 75.1, + "Y": 69.2, + "Level": "Low" + }, + { + "X": 72.9, + "Y": 33.9, + "Level": "Medium" + }, + { + "X": 46.2, + "Y": 57.2, + "Level": "High" + }, + { + "X": 64.4, + "Y": 21.9, + "Level": "Critical" + }, + { + "X": 73.9, + "Y": 66.2, + "Level": "Low" + }, + { + "X": 19, + "Y": 17.9, + "Level": "Medium" + }, + { + "X": 81.9, + "Y": 35.7, + "Level": "High" + }, + { + "X": 84.9, + "Y": 93.9, + "Level": "Critical" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/scatter-plot/06-card15.flint.json b/test-harness/excel/evaluations/inputs/scatter-plot/06-card15.flint.json new file mode 100644 index 00000000..a65f0684 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/scatter-plot/06-card15.flint.json @@ -0,0 +1,115 @@ +{ + "semantic_types": { + "X": "Quantity", + "Y": "Quantity", + "Segment": "Category", + "Size": "Quantity" + }, + "chart_spec": { + "chartType": "Scatter Plot", + "encodings": { + "x": "X", + "y": "Y", + "color": "Segment", + "size": "Size" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 88.6, + "Y": 36.1, + "Segment": "Electronics", + "Size": 33 + }, + { + "X": 26.6, + "Y": 56.1, + "Segment": "Clothing", + "Size": 77.6 + }, + { + "X": 80.8, + "Y": 84.9, + "Segment": "Food", + "Size": 36.9 + }, + { + "X": 6.5, + "Y": 20.2, + "Segment": "Electronics", + "Size": 32.8 + }, + { + "X": 68, + "Y": 79.1, + "Segment": "Clothing", + "Size": 62.4 + }, + { + "X": 77.2, + "Y": 26.9, + "Segment": "Food", + "Size": 62 + }, + { + "X": 81.6, + "Y": 2.7, + "Segment": "Electronics", + "Size": 39.3 + }, + { + "X": 35.9, + "Y": 88, + "Segment": "Clothing", + "Size": 58.7 + }, + { + "X": 26.9, + "Y": 32.2, + "Segment": "Food", + "Size": 96.7 + }, + { + "X": 73.2, + "Y": 39.8, + "Segment": "Electronics", + "Size": 47.5 + }, + { + "X": 12.5, + "Y": 6.8, + "Segment": "Clothing", + "Size": 20.1 + }, + { + "X": 84, + "Y": 75.3, + "Segment": "Food", + "Size": 31.3 + }, + { + "X": 1, + "Y": 1.5, + "Segment": "Electronics", + "Size": 21.7 + }, + { + "X": 26.7, + "Y": 60.9, + "Segment": "Clothing", + "Size": 90.9 + }, + { + "X": 41.4, + "Y": 44.9, + "Segment": "Food", + "Size": 78.1 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/scatter-plot/07-card30.flint.json b/test-harness/excel/evaluations/inputs/scatter-plot/07-card30.flint.json new file mode 100644 index 00000000..2f840973 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/scatter-plot/07-card30.flint.json @@ -0,0 +1,205 @@ +{ + "semantic_types": { + "X": "Quantity", + "Y": "Quantity", + "ColorVal": "Quantity", + "Size": "Quantity" + }, + "chart_spec": { + "chartType": "Scatter Plot", + "encodings": { + "x": "X", + "y": "Y", + "color": "ColorVal", + "size": "Size" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 7, + "Y": 96, + "ColorVal": 23.3, + "Size": 85.7 + }, + { + "X": 56.5, + "Y": 19.9, + "ColorVal": 3.6, + "Size": 53.2 + }, + { + "X": 52.3, + "Y": 49.5, + "ColorVal": 14.5, + "Size": 88.1 + }, + { + "X": 90.8, + "Y": 75.5, + "ColorVal": 79.3, + "Size": 52 + }, + { + "X": 28.9, + "Y": 22, + "ColorVal": 6.9, + "Size": 99.1 + }, + { + "X": 20, + "Y": 91.9, + "ColorVal": 87.9, + "Size": 56.4 + }, + { + "X": 82.2, + "Y": 14.8, + "ColorVal": 71.2, + "Size": 27.3 + }, + { + "X": 94.6, + "Y": 18.4, + "ColorVal": 97.8, + "Size": 7.2 + }, + { + "X": 95.1, + "Y": 89.6, + "ColorVal": 80.2, + "Size": 77.4 + }, + { + "X": 97.3, + "Y": 25.5, + "ColorVal": 39.1, + "Size": 17.3 + }, + { + "X": 14, + "Y": 46.5, + "ColorVal": 87.1, + "Size": 76.3 + }, + { + "X": 12.1, + "Y": 19.3, + "ColorVal": 88.1, + "Size": 24.5 + }, + { + "X": 37.5, + "Y": 75.8, + "ColorVal": 31.6, + "Size": 22.9 + }, + { + "X": 50.7, + "Y": 10.6, + "ColorVal": 30.3, + "Size": 99.8 + }, + { + "X": 46.9, + "Y": 22, + "ColorVal": 63, + "Size": 78.4 + }, + { + "X": 52.7, + "Y": 68.4, + "ColorVal": 31, + "Size": 62.9 + }, + { + "X": 41, + "Y": 89.8, + "ColorVal": 60.2, + "Size": 44.2 + }, + { + "X": 81.5, + "Y": 42.6, + "ColorVal": 96.9, + "Size": 25.2 + }, + { + "X": 71, + "Y": 0.1, + "ColorVal": 80.4, + "Size": 24.8 + }, + { + "X": 86.5, + "Y": 33.6, + "ColorVal": 8.4, + "Size": 38.9 + }, + { + "X": 75.4, + "Y": 92.9, + "ColorVal": 31.9, + "Size": 85.6 + }, + { + "X": 25.5, + "Y": 54.9, + "ColorVal": 80.5, + "Size": 42.2 + }, + { + "X": 74.5, + "Y": 59.7, + "ColorVal": 4.2, + "Size": 64.5 + }, + { + "X": 82, + "Y": 72.9, + "ColorVal": 21.8, + "Size": 62.4 + }, + { + "X": 19.8, + "Y": 64.6, + "ColorVal": 46.8, + "Size": 52.4 + }, + { + "X": 70.8, + "Y": 95.4, + "ColorVal": 20.2, + "Size": 10.6 + }, + { + "X": 72.3, + "Y": 74.4, + "ColorVal": 41.8, + "Size": 34.6 + }, + { + "X": 48, + "Y": 80.3, + "ColorVal": 74.4, + "Size": 96.9 + }, + { + "X": 22.5, + "Y": 61.9, + "ColorVal": 84.6, + "Size": 13.7 + }, + { + "X": 39.1, + "Y": 34.1, + "ColorVal": 28, + "Size": 43.5 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/scatter-plot/08-card20.flint.json b/test-harness/excel/evaluations/inputs/scatter-plot/08-card20.flint.json new file mode 100644 index 00000000..1be156c3 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/scatter-plot/08-card20.flint.json @@ -0,0 +1,145 @@ +{ + "semantic_types": { + "X": "Quantity", + "Y": "Quantity", + "Segment": "Category", + "Size": "Quantity" + }, + "chart_spec": { + "chartType": "Scatter Plot", + "encodings": { + "x": "X", + "y": "Y", + "color": "Segment", + "size": "Size" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 20.8, + "Y": 65.9, + "Segment": "Electronics", + "Size": 113041463 + }, + { + "X": 87.1, + "Y": 9.9, + "Segment": "Clothing", + "Size": 489600946 + }, + { + "X": 70.6, + "Y": 84, + "Segment": "Food", + "Size": 170192509 + }, + { + "X": 40.9, + "Y": 8.8, + "Segment": "Books", + "Size": 684784271 + }, + { + "X": 15.2, + "Y": 9, + "Segment": "Sports", + "Size": 272996627 + }, + { + "X": 23.8, + "Y": 88.6, + "Segment": "Home", + "Size": 73843952 + }, + { + "X": 7.9, + "Y": 40.2, + "Segment": "Garden", + "Size": 310037319 + }, + { + "X": 78, + "Y": 40.5, + "Segment": "Auto", + "Size": 636410568 + }, + { + "X": 13.6, + "Y": 17.7, + "Segment": "Health", + "Size": 916931923 + }, + { + "X": 85.8, + "Y": 84.7, + "Segment": "Beauty", + "Size": 465975275 + }, + { + "X": 63, + "Y": 42.6, + "Segment": "Toys", + "Size": 733873108 + }, + { + "X": 18.9, + "Y": 45.2, + "Segment": "Music", + "Size": 679753166 + }, + { + "X": 59.5, + "Y": 28.4, + "Segment": "Movies", + "Size": 405646572 + }, + { + "X": 68.5, + "Y": 4.2, + "Segment": "Software", + "Size": 510611831 + }, + { + "X": 83.6, + "Y": 68.8, + "Segment": "Games", + "Size": 534058494 + }, + { + "X": 90.4, + "Y": 74, + "Segment": "Office", + "Size": 439235648 + }, + { + "X": 21.7, + "Y": 59.3, + "Segment": "Pet", + "Size": 810736068 + }, + { + "X": 2.4, + "Y": 26.2, + "Segment": "Baby", + "Size": 591643630 + }, + { + "X": 73.8, + "Y": 38.7, + "Segment": "Tools", + "Size": 671374505 + }, + { + "X": 77.4, + "Y": 99.5, + "Segment": "Crafts", + "Size": 885994418 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/scatter-plot/09-card91.flint.json b/test-harness/excel/evaluations/inputs/scatter-plot/09-card91.flint.json new file mode 100644 index 00000000..20f806ff --- /dev/null +++ b/test-harness/excel/evaluations/inputs/scatter-plot/09-card91.flint.json @@ -0,0 +1,421 @@ +{ + "semantic_types": { + "X": "Quantity", + "Y": "Quantity" + }, + "chart_spec": { + "chartType": "Scatter Plot", + "encodings": { + "x": "X", + "y": "Y" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 89.1, + "Y": 42.7 + }, + { + "X": 77, + "Y": 31.6 + }, + { + "X": 71.9, + "Y": 17 + }, + { + "X": 4.4, + "Y": 67 + }, + { + "X": 43.8, + "Y": 99.8 + }, + { + "X": 32.9, + "Y": 63.3 + }, + { + "X": 84.7, + "Y": 56.1 + }, + { + "X": 84.2, + "Y": 74.7 + }, + { + "X": 53.4, + "Y": 8.6 + }, + { + "X": 95, + "Y": 46.8 + }, + { + "X": 61, + "Y": 72.2 + }, + { + "X": 43.6, + "Y": 8.7 + }, + { + "X": 23.2, + "Y": 89.9 + }, + { + "X": 86, + "Y": 65.9 + }, + { + "X": 14, + "Y": 1.2 + }, + { + "X": 24.7, + "Y": 74.4 + }, + { + "X": 5.8, + "Y": 68.7 + }, + { + "X": 70.1, + "Y": 49.6 + }, + { + "X": 52.7, + "Y": 72.5 + }, + { + "X": 43.2, + "Y": 62.1 + }, + { + "X": 5.5, + "Y": 78.8 + }, + { + "X": 94.1, + "Y": 58.2 + }, + { + "X": 98.9, + "Y": 71 + }, + { + "X": 33, + "Y": 96.1 + }, + { + "X": 33.5, + "Y": 95.8 + }, + { + "X": 6.3, + "Y": 18.2 + }, + { + "X": 52.7, + "Y": 78.4 + }, + { + "X": 91, + "Y": 68.7 + }, + { + "X": 31, + "Y": 96.5 + }, + { + "X": 61.3, + "Y": 2.7 + }, + { + "X": 10.6, + "Y": 2.7 + }, + { + "X": 1.8, + "Y": 97.5 + }, + { + "X": 24.8, + "Y": 77.2 + }, + { + "X": 87.1, + "Y": 4.7 + }, + { + "X": 7.9, + "Y": 25.1 + }, + { + "X": 91.3, + "Y": 60.8 + }, + { + "X": 26.9, + "Y": 40.1 + }, + { + "X": 81.2, + "Y": 61.4 + }, + { + "X": 78, + "Y": 99.7 + }, + { + "X": 12.3, + "Y": 47.7 + }, + { + "X": 32, + "Y": 33.9 + }, + { + "X": 1.6, + "Y": 9.2 + }, + { + "X": 4.7, + "Y": 65.1 + }, + { + "X": 5.5, + "Y": 79.5 + }, + { + "X": 0.6, + "Y": 73.3 + }, + { + "X": 53.5, + "Y": 35.1 + }, + { + "X": 9.6, + "Y": 71.7 + }, + { + "X": 33, + "Y": 16.8 + }, + { + "X": 92.7, + "Y": 46.7 + }, + { + "X": 47.2, + "Y": 29.6 + }, + { + "X": 50.2, + "Y": 8.5 + }, + { + "X": 17.7, + "Y": 8.1 + }, + { + "X": 66.7, + "Y": 28.1 + }, + { + "X": 42.5, + "Y": 55.2 + }, + { + "X": 44.1, + "Y": 30.5 + }, + { + "X": 27.4, + "Y": 11.7 + }, + { + "X": 44.8, + "Y": 15.1 + }, + { + "X": 83.9, + "Y": 43.6 + }, + { + "X": 61.9, + "Y": 43.3 + }, + { + "X": 76.4, + "Y": 54.2 + }, + { + "X": 28.1, + "Y": 40.7 + }, + { + "X": 88.7, + "Y": 36.7 + }, + { + "X": 9.4, + "Y": 88.6 + }, + { + "X": 65.1, + "Y": 62.3 + }, + { + "X": 48.9, + "Y": 15.1 + }, + { + "X": 67.1, + "Y": 3.5 + }, + { + "X": 78, + "Y": 56 + }, + { + "X": 36.4, + "Y": 20.2 + }, + { + "X": 30.9, + "Y": 56.5 + }, + { + "X": 6.8, + "Y": 71.5 + }, + { + "X": 0.2, + "Y": 28.6 + }, + { + "X": 16.4, + "Y": 49.2 + }, + { + "X": 50.4, + "Y": 33.3 + }, + { + "X": 52.5, + "Y": 17.9 + }, + { + "X": 19.4, + "Y": 53.3 + }, + { + "X": 47.2, + "Y": 47.7 + }, + { + "X": 82, + "Y": 21.7 + }, + { + "X": 89.2, + "Y": 33.5 + }, + { + "X": 7.4, + "Y": 38.2 + }, + { + "X": 50.4, + "Y": 80.8 + }, + { + "X": 92.3, + "Y": 31.4 + }, + { + "X": 65.7, + "Y": 43.1 + }, + { + "X": 80.6, + "Y": 81.3 + }, + { + "X": 70.2, + "Y": 42.4 + }, + { + "X": 26.9, + "Y": 66 + }, + { + "X": 98.6, + "Y": 11.6 + }, + { + "X": 81.4, + "Y": 31.4 + }, + { + "X": 35.4, + "Y": 95 + }, + { + "X": 52.6, + "Y": 20.5 + }, + { + "X": 70.2, + "Y": 61.9 + }, + { + "X": 85.1, + "Y": 34.2 + }, + { + "X": 17.3, + "Y": 4.3 + }, + { + "X": 31.9, + "Y": 73.7 + }, + { + "X": 93.3, + "Y": 18.8 + }, + { + "X": 64.2, + "Y": 51.9 + }, + { + "X": 64.8, + "Y": 34.5 + }, + { + "X": 10, + "Y": 7.8 + }, + { + "X": 47.5, + "Y": 64.2 + }, + { + "X": 35.4, + "Y": 46.4 + }, + { + "X": 99.3, + "Y": 20 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/scatter-plot/10-card395.flint.json b/test-harness/excel/evaluations/inputs/scatter-plot/10-card395.flint.json new file mode 100644 index 00000000..56c4cfe0 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/scatter-plot/10-card395.flint.json @@ -0,0 +1,2021 @@ +{ + "semantic_types": { + "X": "Quantity", + "Y": "Quantity" + }, + "chart_spec": { + "chartType": "Scatter Plot", + "encodings": { + "x": "X", + "y": "Y" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 96.1, + "Y": 21.1 + }, + { + "X": 19.5, + "Y": 92.5 + }, + { + "X": 6.1, + "Y": 82.5 + }, + { + "X": 92.1, + "Y": 9.4 + }, + { + "X": 77.4, + "Y": 76.3 + }, + { + "X": 50.5, + "Y": 5 + }, + { + "X": 33.7, + "Y": 63 + }, + { + "X": 14.8, + "Y": 88.4 + }, + { + "X": 31.3, + "Y": 67.9 + }, + { + "X": 65.4, + "Y": 89.3 + }, + { + "X": 43.2, + "Y": 74.9 + }, + { + "X": 85.4, + "Y": 7 + }, + { + "X": 87.8, + "Y": 11.3 + }, + { + "X": 22.7, + "Y": 1.9 + }, + { + "X": 6.1, + "Y": 76.1 + }, + { + "X": 99.7, + "Y": 42.1 + }, + { + "X": 98.7, + "Y": 40.8 + }, + { + "X": 61, + "Y": 16.5 + }, + { + "X": 22.1, + "Y": 8.7 + }, + { + "X": 36, + "Y": 1.3 + }, + { + "X": 8.7, + "Y": 94.2 + }, + { + "X": 32.3, + "Y": 93.1 + }, + { + "X": 98.6, + "Y": 11.2 + }, + { + "X": 17.9, + "Y": 60.5 + }, + { + "X": 14, + "Y": 62.1 + }, + { + "X": 37.4, + "Y": 84.4 + }, + { + "X": 14.3, + "Y": 1.3 + }, + { + "X": 45.3, + "Y": 0.6 + }, + { + "X": 31.9, + "Y": 43.8 + }, + { + "X": 24.5, + "Y": 24.3 + }, + { + "X": 17.9, + "Y": 49.1 + }, + { + "X": 59.8, + "Y": 18.1 + }, + { + "X": 46.5, + "Y": 5.7 + }, + { + "X": 20.6, + "Y": 3.8 + }, + { + "X": 24.9, + "Y": 14.8 + }, + { + "X": 80.7, + "Y": 31.9 + }, + { + "X": 91.5, + "Y": 67 + }, + { + "X": 42, + "Y": 32.2 + }, + { + "X": 71.8, + "Y": 40.4 + }, + { + "X": 15.1, + "Y": 84 + }, + { + "X": 15.3, + "Y": 8.6 + }, + { + "X": 55.9, + "Y": 84.9 + }, + { + "X": 2.2, + "Y": 35.9 + }, + { + "X": 4.1, + "Y": 13.1 + }, + { + "X": 8.6, + "Y": 24.4 + }, + { + "X": 0.8, + "Y": 88.3 + }, + { + "X": 21.7, + "Y": 5.4 + }, + { + "X": 29.4, + "Y": 23.5 + }, + { + "X": 67.5, + "Y": 4.2 + }, + { + "X": 69.4, + "Y": 46.7 + }, + { + "X": 9.4, + "Y": 22.2 + }, + { + "X": 1.3, + "Y": 22.4 + }, + { + "X": 65.4, + "Y": 4.5 + }, + { + "X": 23.8, + "Y": 82.6 + }, + { + "X": 54.7, + "Y": 74.6 + }, + { + "X": 97.1, + "Y": 48.4 + }, + { + "X": 38.5, + "Y": 55.8 + }, + { + "X": 12.3, + "Y": 45.4 + }, + { + "X": 46.6, + "Y": 61.3 + }, + { + "X": 20.5, + "Y": 36.6 + }, + { + "X": 74, + "Y": 53 + }, + { + "X": 68.1, + "Y": 10.2 + }, + { + "X": 10.2, + "Y": 50.3 + }, + { + "X": 78, + "Y": 92.4 + }, + { + "X": 74.7, + "Y": 26.1 + }, + { + "X": 30.8, + "Y": 61 + }, + { + "X": 1.6, + "Y": 23.3 + }, + { + "X": 75.6, + "Y": 50 + }, + { + "X": 44.8, + "Y": 36.9 + }, + { + "X": 66.7, + "Y": 4.3 + }, + { + "X": 12, + "Y": 68.4 + }, + { + "X": 2.9, + "Y": 42.9 + }, + { + "X": 29.5, + "Y": 50.3 + }, + { + "X": 39.2, + "Y": 94.3 + }, + { + "X": 0.2, + "Y": 41.4 + }, + { + "X": 66.1, + "Y": 24.5 + }, + { + "X": 79.4, + "Y": 70.2 + }, + { + "X": 17.7, + "Y": 64.4 + }, + { + "X": 96.9, + "Y": 70.9 + }, + { + "X": 23.1, + "Y": 79.9 + }, + { + "X": 15.7, + "Y": 5.7 + }, + { + "X": 71.5, + "Y": 67.9 + }, + { + "X": 0.7, + "Y": 68 + }, + { + "X": 46.5, + "Y": 89.4 + }, + { + "X": 58.4, + "Y": 50.6 + }, + { + "X": 58, + "Y": 55.5 + }, + { + "X": 62, + "Y": 97.4 + }, + { + "X": 92.4, + "Y": 47.2 + }, + { + "X": 12.8, + "Y": 42.6 + }, + { + "X": 98.3, + "Y": 10 + }, + { + "X": 51, + "Y": 36.1 + }, + { + "X": 5.5, + "Y": 84.2 + }, + { + "X": 21.6, + "Y": 54 + }, + { + "X": 6.2, + "Y": 29.3 + }, + { + "X": 37.3, + "Y": 24.2 + }, + { + "X": 23.9, + "Y": 84.4 + }, + { + "X": 11.2, + "Y": 30.1 + }, + { + "X": 17.6, + "Y": 22.5 + }, + { + "X": 20.9, + "Y": 44.5 + }, + { + "X": 59.4, + "Y": 2.9 + }, + { + "X": 85.5, + "Y": 0.2 + }, + { + "X": 39.5, + "Y": 40.8 + }, + { + "X": 9.1, + "Y": 12.3 + }, + { + "X": 35.5, + "Y": 75.8 + }, + { + "X": 91.3, + "Y": 57.5 + }, + { + "X": 78, + "Y": 21 + }, + { + "X": 51.8, + "Y": 26.8 + }, + { + "X": 73.9, + "Y": 59 + }, + { + "X": 41, + "Y": 85.6 + }, + { + "X": 68.4, + "Y": 68.2 + }, + { + "X": 95.5, + "Y": 38.6 + }, + { + "X": 1.9, + "Y": 46.3 + }, + { + "X": 91.2, + "Y": 62 + }, + { + "X": 24.9, + "Y": 92.1 + }, + { + "X": 53.3, + "Y": 23.2 + }, + { + "X": 44.3, + "Y": 77.9 + }, + { + "X": 26.1, + "Y": 3.7 + }, + { + "X": 3.2, + "Y": 33.8 + }, + { + "X": 38, + "Y": 0.1 + }, + { + "X": 13.1, + "Y": 29.4 + }, + { + "X": 86.4, + "Y": 11.7 + }, + { + "X": 32.2, + "Y": 93.8 + }, + { + "X": 8.3, + "Y": 75.8 + }, + { + "X": 42, + "Y": 63.4 + }, + { + "X": 7.8, + "Y": 54.7 + }, + { + "X": 21.2, + "Y": 11.1 + }, + { + "X": 97.3, + "Y": 92.8 + }, + { + "X": 9.4, + "Y": 65.9 + }, + { + "X": 24.2, + "Y": 44.3 + }, + { + "X": 90.6, + "Y": 20.6 + }, + { + "X": 18.5, + "Y": 58.9 + }, + { + "X": 21.9, + "Y": 45.1 + }, + { + "X": 64.5, + "Y": 94.7 + }, + { + "X": 43.4, + "Y": 89.5 + }, + { + "X": 16.1, + "Y": 74.6 + }, + { + "X": 20.7, + "Y": 98.7 + }, + { + "X": 40.1, + "Y": 74.9 + }, + { + "X": 60, + "Y": 26.8 + }, + { + "X": 10.3, + "Y": 39.5 + }, + { + "X": 19.7, + "Y": 0 + }, + { + "X": 23.3, + "Y": 33.3 + }, + { + "X": 35.8, + "Y": 36.4 + }, + { + "X": 38.5, + "Y": 4 + }, + { + "X": 26.3, + "Y": 66.1 + }, + { + "X": 85.3, + "Y": 11.6 + }, + { + "X": 13.8, + "Y": 40.8 + }, + { + "X": 7.4, + "Y": 94.7 + }, + { + "X": 50.7, + "Y": 13.3 + }, + { + "X": 91.3, + "Y": 85.4 + }, + { + "X": 47.5, + "Y": 97 + }, + { + "X": 22.5, + "Y": 38.9 + }, + { + "X": 3.2, + "Y": 45.4 + }, + { + "X": 18.4, + "Y": 24.6 + }, + { + "X": 29.7, + "Y": 81.6 + }, + { + "X": 98.4, + "Y": 86.4 + }, + { + "X": 98.6, + "Y": 74.1 + }, + { + "X": 99.8, + "Y": 9.1 + }, + { + "X": 89.6, + "Y": 18.6 + }, + { + "X": 96.6, + "Y": 13 + }, + { + "X": 31.2, + "Y": 79.2 + }, + { + "X": 22.8, + "Y": 32.3 + }, + { + "X": 76.7, + "Y": 41.5 + }, + { + "X": 81, + "Y": 58.8 + }, + { + "X": 49.4, + "Y": 52.7 + }, + { + "X": 6.1, + "Y": 3.2 + }, + { + "X": 91.4, + "Y": 74.7 + }, + { + "X": 40.3, + "Y": 99 + }, + { + "X": 52.5, + "Y": 65.9 + }, + { + "X": 92.5, + "Y": 86.7 + }, + { + "X": 44.4, + "Y": 42.4 + }, + { + "X": 56.7, + "Y": 21.2 + }, + { + "X": 78.7, + "Y": 38.8 + }, + { + "X": 1.9, + "Y": 60.9 + }, + { + "X": 45.6, + "Y": 71.8 + }, + { + "X": 32.7, + "Y": 99.5 + }, + { + "X": 28.6, + "Y": 79.7 + }, + { + "X": 66.5, + "Y": 82.5 + }, + { + "X": 60.3, + "Y": 29.8 + }, + { + "X": 27.2, + "Y": 61.7 + }, + { + "X": 61, + "Y": 58.2 + }, + { + "X": 70.6, + "Y": 89.3 + }, + { + "X": 21.4, + "Y": 55.5 + }, + { + "X": 28.9, + "Y": 69.4 + }, + { + "X": 59.8, + "Y": 99.8 + }, + { + "X": 29.3, + "Y": 51.8 + }, + { + "X": 52.2, + "Y": 98 + }, + { + "X": 27.4, + "Y": 45.6 + }, + { + "X": 85.6, + "Y": 29.6 + }, + { + "X": 72.6, + "Y": 41.6 + }, + { + "X": 87.8, + "Y": 40.8 + }, + { + "X": 4.7, + "Y": 98.3 + }, + { + "X": 65.6, + "Y": 91.2 + }, + { + "X": 53.1, + "Y": 84.8 + }, + { + "X": 93, + "Y": 64.9 + }, + { + "X": 55.5, + "Y": 76.7 + }, + { + "X": 16.6, + "Y": 51.9 + }, + { + "X": 25.7, + "Y": 42.7 + }, + { + "X": 11.7, + "Y": 37 + }, + { + "X": 33.7, + "Y": 53.8 + }, + { + "X": 92.8, + "Y": 41.9 + }, + { + "X": 18.5, + "Y": 4.3 + }, + { + "X": 0.5, + "Y": 11.1 + }, + { + "X": 76.8, + "Y": 34.7 + }, + { + "X": 56.6, + "Y": 6.6 + }, + { + "X": 80.8, + "Y": 21 + }, + { + "X": 18.6, + "Y": 94.3 + }, + { + "X": 56.7, + "Y": 81.3 + }, + { + "X": 9.9, + "Y": 34.3 + }, + { + "X": 59.8, + "Y": 93.6 + }, + { + "X": 20.8, + "Y": 46.3 + }, + { + "X": 6.4, + "Y": 88.3 + }, + { + "X": 9.2, + "Y": 45.6 + }, + { + "X": 72.5, + "Y": 97.8 + }, + { + "X": 53.4, + "Y": 83.1 + }, + { + "X": 6.9, + "Y": 86.2 + }, + { + "X": 78.4, + "Y": 60.4 + }, + { + "X": 78.9, + "Y": 31.1 + }, + { + "X": 23.7, + "Y": 42.7 + }, + { + "X": 22.9, + "Y": 23.4 + }, + { + "X": 56.7, + "Y": 35 + }, + { + "X": 34.6, + "Y": 77.3 + }, + { + "X": 75.3, + "Y": 15.8 + }, + { + "X": 51.1, + "Y": 27.1 + }, + { + "X": 84.6, + "Y": 96.8 + }, + { + "X": 14.5, + "Y": 26.2 + }, + { + "X": 66.5, + "Y": 13.3 + }, + { + "X": 86.5, + "Y": 8.7 + }, + { + "X": 62.3, + "Y": 89.5 + }, + { + "X": 73.9, + "Y": 56.6 + }, + { + "X": 76.9, + "Y": 40.6 + }, + { + "X": 75.4, + "Y": 25.6 + }, + { + "X": 94.4, + "Y": 71.9 + }, + { + "X": 19, + "Y": 7.7 + }, + { + "X": 31.3, + "Y": 76.5 + }, + { + "X": 9.1, + "Y": 15.4 + }, + { + "X": 54.4, + "Y": 14.6 + }, + { + "X": 16.2, + "Y": 97.3 + }, + { + "X": 33.6, + "Y": 23.6 + }, + { + "X": 58.3, + "Y": 54.1 + }, + { + "X": 1.2, + "Y": 36.7 + }, + { + "X": 55, + "Y": 81.8 + }, + { + "X": 67.3, + "Y": 24.4 + }, + { + "X": 37.9, + "Y": 3.3 + }, + { + "X": 79.6, + "Y": 76.4 + }, + { + "X": 25, + "Y": 55 + }, + { + "X": 35.8, + "Y": 18.9 + }, + { + "X": 15.2, + "Y": 28.5 + }, + { + "X": 40.1, + "Y": 100 + }, + { + "X": 96.2, + "Y": 14.8 + }, + { + "X": 69.1, + "Y": 45.7 + }, + { + "X": 35.8, + "Y": 23.1 + }, + { + "X": 79.9, + "Y": 57.1 + }, + { + "X": 46.8, + "Y": 17.6 + }, + { + "X": 57.8, + "Y": 40.3 + }, + { + "X": 53.7, + "Y": 56.5 + }, + { + "X": 53.5, + "Y": 30.1 + }, + { + "X": 16, + "Y": 49.4 + }, + { + "X": 99.9, + "Y": 34.5 + }, + { + "X": 0.8, + "Y": 4.3 + }, + { + "X": 50.6, + "Y": 91.3 + }, + { + "X": 47.5, + "Y": 80.3 + }, + { + "X": 94.7, + "Y": 10.7 + }, + { + "X": 25.1, + "Y": 79.9 + }, + { + "X": 91.7, + "Y": 57.1 + }, + { + "X": 32.9, + "Y": 75.3 + }, + { + "X": 80.9, + "Y": 84.3 + }, + { + "X": 78.5, + "Y": 76.8 + }, + { + "X": 66.6, + "Y": 7 + }, + { + "X": 42.7, + "Y": 1.5 + }, + { + "X": 19.9, + "Y": 65 + }, + { + "X": 80.2, + "Y": 87.4 + }, + { + "X": 67.6, + "Y": 70.7 + }, + { + "X": 35.7, + "Y": 80.4 + }, + { + "X": 63.7, + "Y": 49.1 + }, + { + "X": 56.3, + "Y": 65.4 + }, + { + "X": 66.1, + "Y": 77.7 + }, + { + "X": 68.7, + "Y": 61.9 + }, + { + "X": 33.8, + "Y": 93.1 + }, + { + "X": 53, + "Y": 96.4 + }, + { + "X": 62.6, + "Y": 67.2 + }, + { + "X": 8, + "Y": 34.6 + }, + { + "X": 34.4, + "Y": 94.9 + }, + { + "X": 49.3, + "Y": 69.5 + }, + { + "X": 55.5, + "Y": 45.9 + }, + { + "X": 5.7, + "Y": 88.1 + }, + { + "X": 7.1, + "Y": 22 + }, + { + "X": 54.6, + "Y": 99.1 + }, + { + "X": 90.3, + "Y": 56.3 + }, + { + "X": 87.4, + "Y": 22 + }, + { + "X": 69.3, + "Y": 84.6 + }, + { + "X": 90, + "Y": 86.4 + }, + { + "X": 11.4, + "Y": 79.3 + }, + { + "X": 64.1, + "Y": 87.6 + }, + { + "X": 87.5, + "Y": 60 + }, + { + "X": 85.4, + "Y": 33.1 + }, + { + "X": 9.5, + "Y": 37.8 + }, + { + "X": 34.2, + "Y": 16 + }, + { + "X": 88.6, + "Y": 19.7 + }, + { + "X": 25.5, + "Y": 30.7 + }, + { + "X": 70.1, + "Y": 18.7 + }, + { + "X": 7.6, + "Y": 89.8 + }, + { + "X": 67.9, + "Y": 96.2 + }, + { + "X": 16, + "Y": 40.5 + }, + { + "X": 48.2, + "Y": 31.8 + }, + { + "X": 6.7, + "Y": 32.7 + }, + { + "X": 73.4, + "Y": 58.3 + }, + { + "X": 61.3, + "Y": 47.5 + }, + { + "X": 93.3, + "Y": 55.8 + }, + { + "X": 69.5, + "Y": 20.7 + }, + { + "X": 38.6, + "Y": 56.3 + }, + { + "X": 5.9, + "Y": 75.9 + }, + { + "X": 56.4, + "Y": 15.5 + }, + { + "X": 67.5, + "Y": 94.7 + }, + { + "X": 58.1, + "Y": 17 + }, + { + "X": 56.8, + "Y": 48.1 + }, + { + "X": 31.1, + "Y": 0.2 + }, + { + "X": 26.2, + "Y": 21.9 + }, + { + "X": 22.7, + "Y": 35.5 + }, + { + "X": 99.1, + "Y": 24.8 + }, + { + "X": 45.6, + "Y": 20.6 + }, + { + "X": 33.8, + "Y": 48.9 + }, + { + "X": 5.4, + "Y": 81.4 + }, + { + "X": 64, + "Y": 95.7 + }, + { + "X": 24.3, + "Y": 54.4 + }, + { + "X": 97.8, + "Y": 78.3 + }, + { + "X": 61.6, + "Y": 20.1 + }, + { + "X": 65.8, + "Y": 9.2 + }, + { + "X": 39.9, + "Y": 42.8 + }, + { + "X": 51.5, + "Y": 82.4 + }, + { + "X": 26.1, + "Y": 76.4 + }, + { + "X": 75.6, + "Y": 4.7 + }, + { + "X": 10.5, + "Y": 7.4 + }, + { + "X": 84.4, + "Y": 95.5 + }, + { + "X": 84.9, + "Y": 12.1 + }, + { + "X": 93, + "Y": 76.9 + }, + { + "X": 77.8, + "Y": 6.8 + }, + { + "X": 10.5, + "Y": 74.7 + }, + { + "X": 47.8, + "Y": 74.3 + }, + { + "X": 11.8, + "Y": 39.4 + }, + { + "X": 82.2, + "Y": 88.2 + }, + { + "X": 18, + "Y": 31 + }, + { + "X": 2.6, + "Y": 73.3 + }, + { + "X": 38.8, + "Y": 89.1 + }, + { + "X": 1, + "Y": 98.3 + }, + { + "X": 88.2, + "Y": 84 + }, + { + "X": 53, + "Y": 94.2 + }, + { + "X": 93.8, + "Y": 29.7 + }, + { + "X": 58.3, + "Y": 7.4 + }, + { + "X": 28.5, + "Y": 84.9 + }, + { + "X": 62.7, + "Y": 9.1 + }, + { + "X": 61.4, + "Y": 45.1 + }, + { + "X": 66.2, + "Y": 67.4 + }, + { + "X": 7, + "Y": 85.3 + }, + { + "X": 23.7, + "Y": 37.2 + }, + { + "X": 13.2, + "Y": 66.9 + }, + { + "X": 94.7, + "Y": 39.1 + }, + { + "X": 89.1, + "Y": 75.9 + }, + { + "X": 36, + "Y": 98.2 + }, + { + "X": 25.6, + "Y": 26.1 + }, + { + "X": 69.2, + "Y": 37.5 + }, + { + "X": 20.6, + "Y": 86.9 + }, + { + "X": 6.8, + "Y": 5.7 + }, + { + "X": 76.9, + "Y": 16 + }, + { + "X": 42, + "Y": 82.9 + }, + { + "X": 88.4, + "Y": 84.2 + }, + { + "X": 90.7, + "Y": 82.6 + }, + { + "X": 92.8, + "Y": 97.4 + }, + { + "X": 75.2, + "Y": 57.9 + }, + { + "X": 31.2, + "Y": 65.7 + }, + { + "X": 18.5, + "Y": 0.2 + }, + { + "X": 95, + "Y": 48 + }, + { + "X": 30.4, + "Y": 63.9 + }, + { + "X": 26.1, + "Y": 14.1 + }, + { + "X": 10.1, + "Y": 71.8 + }, + { + "X": 22.9, + "Y": 42.4 + }, + { + "X": 96.7, + "Y": 85 + }, + { + "X": 88.8, + "Y": 30.2 + }, + { + "X": 96.4, + "Y": 96.2 + }, + { + "X": 13.9, + "Y": 53.5 + }, + { + "X": 35.8, + "Y": 77.4 + }, + { + "X": 76.8, + "Y": 72.6 + }, + { + "X": 11.2, + "Y": 60 + }, + { + "X": 7.2, + "Y": 65.3 + }, + { + "X": 7.8, + "Y": 56 + }, + { + "X": 63.3, + "Y": 38.6 + }, + { + "X": 75.3, + "Y": 18.1 + }, + { + "X": 11, + "Y": 0.9 + }, + { + "X": 77.6, + "Y": 33.7 + }, + { + "X": 99, + "Y": 86.7 + }, + { + "X": 43.4, + "Y": 67.5 + }, + { + "X": 96.8, + "Y": 29.4 + }, + { + "X": 19.2, + "Y": 24.4 + }, + { + "X": 87.9, + "Y": 23.9 + }, + { + "X": 25.6, + "Y": 53.4 + }, + { + "X": 77.1, + "Y": 7.4 + }, + { + "X": 90.5, + "Y": 82.3 + }, + { + "X": 3.1, + "Y": 65.7 + }, + { + "X": 5.2, + "Y": 88.1 + }, + { + "X": 90.5, + "Y": 67.4 + }, + { + "X": 9.5, + "Y": 92.9 + }, + { + "X": 2.1, + "Y": 48.9 + }, + { + "X": 1.8, + "Y": 91.4 + }, + { + "X": 40.7, + "Y": 84.7 + }, + { + "X": 75.5, + "Y": 72.7 + }, + { + "X": 34.4, + "Y": 31.8 + }, + { + "X": 86.5, + "Y": 3.6 + }, + { + "X": 8.3, + "Y": 25.7 + }, + { + "X": 49.6, + "Y": 98 + }, + { + "X": 76.9, + "Y": 9.6 + }, + { + "X": 60.9, + "Y": 41.2 + }, + { + "X": 66.1, + "Y": 91.3 + }, + { + "X": 8, + "Y": 68.4 + }, + { + "X": 89.7, + "Y": 91 + }, + { + "X": 91.8, + "Y": 25.8 + }, + { + "X": 21.8, + "Y": 86.9 + }, + { + "X": 43.4, + "Y": 48.6 + }, + { + "X": 28.4, + "Y": 70.2 + }, + { + "X": 61.7, + "Y": 89.1 + }, + { + "X": 6.8, + "Y": 37.4 + }, + { + "X": 10.2, + "Y": 22 + }, + { + "X": 41.9, + "Y": 16.4 + }, + { + "X": 48.3, + "Y": 52.5 + }, + { + "X": 35.9, + "Y": 76.5 + }, + { + "X": 46.8, + "Y": 87.6 + }, + { + "X": 27, + "Y": 32.3 + }, + { + "X": 75.9, + "Y": 28.1 + }, + { + "X": 28.1, + "Y": 92.1 + }, + { + "X": 78.8, + "Y": 88.1 + }, + { + "X": 94.9, + "Y": 16.1 + }, + { + "X": 5, + "Y": 40.7 + }, + { + "X": 22.2, + "Y": 24.6 + }, + { + "X": 6, + "Y": 73.8 + }, + { + "X": 91.6, + "Y": 15.2 + }, + { + "X": 71.7, + "Y": 57.8 + }, + { + "X": 8.2, + "Y": 40.8 + }, + { + "X": 83.1, + "Y": 74 + }, + { + "X": 47, + "Y": 69.7 + }, + { + "X": 44.4, + "Y": 66.8 + }, + { + "X": 25.1, + "Y": 65.1 + }, + { + "X": 21.9, + "Y": 18.1 + }, + { + "X": 1.6, + "Y": 27.5 + }, + { + "X": 99.3, + "Y": 64.5 + }, + { + "X": 46.9, + "Y": 11.7 + }, + { + "X": 26.3, + "Y": 17.9 + }, + { + "X": 73.4, + "Y": 10.3 + }, + { + "X": 91.7, + "Y": 97.3 + }, + { + "X": 30.8, + "Y": 52.1 + }, + { + "X": 22.9, + "Y": 49.6 + }, + { + "X": 53.1, + "Y": 93.1 + }, + { + "X": 9.2, + "Y": 19.4 + }, + { + "X": 64.2, + "Y": 43.2 + }, + { + "X": 77.8, + "Y": 5.6 + }, + { + "X": 31.3, + "Y": 85.7 + }, + { + "X": 45.9, + "Y": 30 + }, + { + "X": 88.3, + "Y": 91.1 + }, + { + "X": 82.2, + "Y": 68.2 + }, + { + "X": 86.7, + "Y": 14.5 + }, + { + "X": 82.3, + "Y": 90.8 + }, + { + "X": 46.4, + "Y": 13.7 + }, + { + "X": 70.7, + "Y": 61.6 + }, + { + "X": 70.3, + "Y": 68.2 + }, + { + "X": 88.9, + "Y": 30.1 + }, + { + "X": 85.5, + "Y": 7.5 + }, + { + "X": 36.7, + "Y": 51.6 + }, + { + "X": 98, + "Y": 90.6 + }, + { + "X": 46.1, + "Y": 92.5 + }, + { + "X": 63, + "Y": 98 + }, + { + "X": 57.4, + "Y": 41.7 + }, + { + "X": 88.5, + "Y": 79.3 + }, + { + "X": 29.4, + "Y": 30.8 + }, + { + "X": 61.7, + "Y": 14.6 + }, + { + "X": 81.1, + "Y": 72 + }, + { + "X": 37.5, + "Y": 98 + }, + { + "X": 71.7, + "Y": 45.5 + }, + { + "X": 45.6, + "Y": 97.3 + }, + { + "X": 6.2, + "Y": 76.9 + }, + { + "X": 44.3, + "Y": 8.3 + }, + { + "X": 55.8, + "Y": 63.6 + }, + { + "X": 83, + "Y": 36.2 + }, + { + "X": 37.6, + "Y": 27.3 + }, + { + "X": 66, + "Y": 58.1 + }, + { + "X": 64.2, + "Y": 66.7 + }, + { + "X": 6.6, + "Y": 1.2 + }, + { + "X": 17.2, + "Y": 13.9 + }, + { + "X": 38.1, + "Y": 65.3 + }, + { + "X": 92.1, + "Y": 74.3 + }, + { + "X": 2.8, + "Y": 91.7 + }, + { + "X": 48.9, + "Y": 0.2 + }, + { + "X": 63.9, + "Y": 85.7 + }, + { + "X": 61.7, + "Y": 52 + }, + { + "X": 4, + "Y": 30.1 + }, + { + "X": 40.4, + "Y": 24.4 + }, + { + "X": 74.7, + "Y": 87.6 + }, + { + "X": 21.8, + "Y": 64.6 + }, + { + "X": 48.6, + "Y": 92.4 + }, + { + "X": 1.6, + "Y": 81.7 + }, + { + "X": 65.4, + "Y": 3.7 + }, + { + "X": 0.3, + "Y": 42.6 + }, + { + "X": 87.4, + "Y": 21.9 + }, + { + "X": 76.9, + "Y": 45.5 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/scatter-plot/11-card182.flint.json b/test-harness/excel/evaluations/inputs/scatter-plot/11-card182.flint.json new file mode 100644 index 00000000..539c4519 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/scatter-plot/11-card182.flint.json @@ -0,0 +1,1023 @@ +{ + "semantic_types": { + "X": "Quantity", + "Y": "Quantity", + "Segment": "Category" + }, + "chart_spec": { + "chartType": "Scatter Plot", + "encodings": { + "x": "X", + "y": "Y", + "color": "Segment" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 52.7, + "Y": 60.1, + "Segment": "Electronics" + }, + { + "X": 72.4, + "Y": 66, + "Segment": "Clothing" + }, + { + "X": 90.5, + "Y": 76.8, + "Segment": "Food" + }, + { + "X": 26.8, + "Y": 70.6, + "Segment": "Books" + }, + { + "X": 7.3, + "Y": 26.6, + "Segment": "Sports" + }, + { + "X": 87, + "Y": 57.4, + "Segment": "Home" + }, + { + "X": 24.6, + "Y": 4.1, + "Segment": "Garden" + }, + { + "X": 65.2, + "Y": 40.1, + "Segment": "Auto" + }, + { + "X": 36.6, + "Y": 58, + "Segment": "Health" + }, + { + "X": 8.8, + "Y": 58.4, + "Segment": "Beauty" + }, + { + "X": 72.5, + "Y": 17.8, + "Segment": "Toys" + }, + { + "X": 16.4, + "Y": 83.9, + "Segment": "Music" + }, + { + "X": 43, + "Y": 76.9, + "Segment": "Movies" + }, + { + "X": 57.7, + "Y": 4, + "Segment": "Software" + }, + { + "X": 8.4, + "Y": 65.8, + "Segment": "Games" + }, + { + "X": 24.5, + "Y": 84.7, + "Segment": "Office" + }, + { + "X": 32.7, + "Y": 60.9, + "Segment": "Pet" + }, + { + "X": 68.2, + "Y": 7.5, + "Segment": "Baby" + }, + { + "X": 73, + "Y": 53.9, + "Segment": "Tools" + }, + { + "X": 84.2, + "Y": 36.5, + "Segment": "Crafts" + }, + { + "X": 80.6, + "Y": 74.7, + "Segment": "Electronics" + }, + { + "X": 60.1, + "Y": 94.8, + "Segment": "Clothing" + }, + { + "X": 18, + "Y": 82.7, + "Segment": "Food" + }, + { + "X": 9.5, + "Y": 61.8, + "Segment": "Books" + }, + { + "X": 49.9, + "Y": 50.3, + "Segment": "Sports" + }, + { + "X": 50.4, + "Y": 92.9, + "Segment": "Home" + }, + { + "X": 53.3, + "Y": 88.7, + "Segment": "Garden" + }, + { + "X": 95.6, + "Y": 57.4, + "Segment": "Auto" + }, + { + "X": 20.6, + "Y": 6.9, + "Segment": "Health" + }, + { + "X": 56.5, + "Y": 25.8, + "Segment": "Beauty" + }, + { + "X": 59, + "Y": 76.7, + "Segment": "Toys" + }, + { + "X": 56.5, + "Y": 31.7, + "Segment": "Music" + }, + { + "X": 50.7, + "Y": 33.3, + "Segment": "Movies" + }, + { + "X": 44.8, + "Y": 25.8, + "Segment": "Software" + }, + { + "X": 43.4, + "Y": 89.4, + "Segment": "Games" + }, + { + "X": 34.1, + "Y": 3.6, + "Segment": "Office" + }, + { + "X": 47.2, + "Y": 4.2, + "Segment": "Pet" + }, + { + "X": 17.6, + "Y": 26.9, + "Segment": "Baby" + }, + { + "X": 46.7, + "Y": 63.6, + "Segment": "Tools" + }, + { + "X": 46.9, + "Y": 79, + "Segment": "Crafts" + }, + { + "X": 94.7, + "Y": 96.1, + "Segment": "Electronics" + }, + { + "X": 59.1, + "Y": 87.1, + "Segment": "Clothing" + }, + { + "X": 13.2, + "Y": 56.2, + "Segment": "Food" + }, + { + "X": 14.9, + "Y": 2.1, + "Segment": "Books" + }, + { + "X": 9.6, + "Y": 94.5, + "Segment": "Sports" + }, + { + "X": 52.4, + "Y": 10.3, + "Segment": "Home" + }, + { + "X": 76.9, + "Y": 99.6, + "Segment": "Garden" + }, + { + "X": 24.5, + "Y": 4.9, + "Segment": "Auto" + }, + { + "X": 10, + "Y": 20, + "Segment": "Health" + }, + { + "X": 4.9, + "Y": 85.9, + "Segment": "Beauty" + }, + { + "X": 24.5, + "Y": 95.5, + "Segment": "Toys" + }, + { + "X": 18.2, + "Y": 64.8, + "Segment": "Music" + }, + { + "X": 36.9, + "Y": 42.8, + "Segment": "Movies" + }, + { + "X": 10.5, + "Y": 12.1, + "Segment": "Software" + }, + { + "X": 15.8, + "Y": 61.5, + "Segment": "Games" + }, + { + "X": 22.5, + "Y": 60, + "Segment": "Office" + }, + { + "X": 46, + "Y": 73.6, + "Segment": "Pet" + }, + { + "X": 33.9, + "Y": 60.3, + "Segment": "Baby" + }, + { + "X": 29.5, + "Y": 89.5, + "Segment": "Tools" + }, + { + "X": 30.2, + "Y": 16.8, + "Segment": "Crafts" + }, + { + "X": 18.4, + "Y": 85.6, + "Segment": "Electronics" + }, + { + "X": 53.7, + "Y": 78.2, + "Segment": "Clothing" + }, + { + "X": 87.5, + "Y": 29.2, + "Segment": "Food" + }, + { + "X": 31.6, + "Y": 3.4, + "Segment": "Books" + }, + { + "X": 2.7, + "Y": 75.3, + "Segment": "Sports" + }, + { + "X": 75.4, + "Y": 21.6, + "Segment": "Home" + }, + { + "X": 21.5, + "Y": 47.1, + "Segment": "Garden" + }, + { + "X": 86, + "Y": 4.2, + "Segment": "Auto" + }, + { + "X": 70, + "Y": 24.2, + "Segment": "Health" + }, + { + "X": 54, + "Y": 71.1, + "Segment": "Beauty" + }, + { + "X": 55.6, + "Y": 33.8, + "Segment": "Toys" + }, + { + "X": 64.3, + "Y": 28.7, + "Segment": "Music" + }, + { + "X": 29.9, + "Y": 74.1, + "Segment": "Movies" + }, + { + "X": 46.2, + "Y": 82.4, + "Segment": "Software" + }, + { + "X": 88.4, + "Y": 91.6, + "Segment": "Games" + }, + { + "X": 98.5, + "Y": 66.6, + "Segment": "Office" + }, + { + "X": 53.7, + "Y": 84.3, + "Segment": "Pet" + }, + { + "X": 45.1, + "Y": 30, + "Segment": "Baby" + }, + { + "X": 62.4, + "Y": 71.6, + "Segment": "Tools" + }, + { + "X": 48.4, + "Y": 10.1, + "Segment": "Crafts" + }, + { + "X": 92.1, + "Y": 65.5, + "Segment": "Electronics" + }, + { + "X": 93.2, + "Y": 91.3, + "Segment": "Clothing" + }, + { + "X": 3.4, + "Y": 45.9, + "Segment": "Food" + }, + { + "X": 31.6, + "Y": 9, + "Segment": "Books" + }, + { + "X": 8.2, + "Y": 93.1, + "Segment": "Sports" + }, + { + "X": 85.2, + "Y": 67.3, + "Segment": "Home" + }, + { + "X": 83.2, + "Y": 86.1, + "Segment": "Garden" + }, + { + "X": 87.6, + "Y": 27.6, + "Segment": "Auto" + }, + { + "X": 44.9, + "Y": 94.9, + "Segment": "Health" + }, + { + "X": 51.2, + "Y": 86.7, + "Segment": "Beauty" + }, + { + "X": 91.6, + "Y": 12.1, + "Segment": "Toys" + }, + { + "X": 48.2, + "Y": 82.1, + "Segment": "Music" + }, + { + "X": 46.9, + "Y": 79.2, + "Segment": "Movies" + }, + { + "X": 74, + "Y": 56.5, + "Segment": "Software" + }, + { + "X": 36.5, + "Y": 71.7, + "Segment": "Games" + }, + { + "X": 72.1, + "Y": 88.6, + "Segment": "Office" + }, + { + "X": 62.5, + "Y": 13.6, + "Segment": "Pet" + }, + { + "X": 30.9, + "Y": 55.7, + "Segment": "Baby" + }, + { + "X": 48.6, + "Y": 67.2, + "Segment": "Tools" + }, + { + "X": 74.9, + "Y": 25, + "Segment": "Crafts" + }, + { + "X": 93.7, + "Y": 92.2, + "Segment": "Electronics" + }, + { + "X": 27.1, + "Y": 91.8, + "Segment": "Clothing" + }, + { + "X": 79.5, + "Y": 76.9, + "Segment": "Food" + }, + { + "X": 52.3, + "Y": 50.7, + "Segment": "Books" + }, + { + "X": 83.1, + "Y": 19, + "Segment": "Sports" + }, + { + "X": 66.7, + "Y": 81.7, + "Segment": "Home" + }, + { + "X": 17.7, + "Y": 48.7, + "Segment": "Garden" + }, + { + "X": 59.5, + "Y": 66.9, + "Segment": "Auto" + }, + { + "X": 45.5, + "Y": 66.8, + "Segment": "Health" + }, + { + "X": 94.1, + "Y": 88.9, + "Segment": "Beauty" + }, + { + "X": 57.8, + "Y": 23.7, + "Segment": "Toys" + }, + { + "X": 47.6, + "Y": 6.9, + "Segment": "Music" + }, + { + "X": 49.8, + "Y": 68.7, + "Segment": "Movies" + }, + { + "X": 38.4, + "Y": 17.6, + "Segment": "Software" + }, + { + "X": 81.8, + "Y": 33.5, + "Segment": "Games" + }, + { + "X": 18.4, + "Y": 45.5, + "Segment": "Office" + }, + { + "X": 82.6, + "Y": 11.8, + "Segment": "Pet" + }, + { + "X": 45.6, + "Y": 9.6, + "Segment": "Baby" + }, + { + "X": 21.3, + "Y": 53, + "Segment": "Tools" + }, + { + "X": 77.5, + "Y": 22.4, + "Segment": "Crafts" + }, + { + "X": 44.4, + "Y": 12.6, + "Segment": "Electronics" + }, + { + "X": 97.1, + "Y": 53.3, + "Segment": "Clothing" + }, + { + "X": 7.1, + "Y": 82.1, + "Segment": "Food" + }, + { + "X": 53.8, + "Y": 12, + "Segment": "Books" + }, + { + "X": 48, + "Y": 9.2, + "Segment": "Sports" + }, + { + "X": 6, + "Y": 75.6, + "Segment": "Home" + }, + { + "X": 77.3, + "Y": 98.9, + "Segment": "Garden" + }, + { + "X": 93.2, + "Y": 55.9, + "Segment": "Auto" + }, + { + "X": 41.5, + "Y": 9.7, + "Segment": "Health" + }, + { + "X": 19.6, + "Y": 45.5, + "Segment": "Beauty" + }, + { + "X": 15.6, + "Y": 22.3, + "Segment": "Toys" + }, + { + "X": 70.3, + "Y": 87, + "Segment": "Music" + }, + { + "X": 78.1, + "Y": 54.5, + "Segment": "Movies" + }, + { + "X": 8.7, + "Y": 45.3, + "Segment": "Software" + }, + { + "X": 68.6, + "Y": 50.8, + "Segment": "Games" + }, + { + "X": 28, + "Y": 97.7, + "Segment": "Office" + }, + { + "X": 62.3, + "Y": 75.2, + "Segment": "Pet" + }, + { + "X": 5.2, + "Y": 46.7, + "Segment": "Baby" + }, + { + "X": 74.3, + "Y": 52.7, + "Segment": "Tools" + }, + { + "X": 77.4, + "Y": 84.7, + "Segment": "Crafts" + }, + { + "X": 41, + "Y": 67.6, + "Segment": "Electronics" + }, + { + "X": 59.1, + "Y": 62.1, + "Segment": "Clothing" + }, + { + "X": 52.8, + "Y": 89.3, + "Segment": "Food" + }, + { + "X": 82.8, + "Y": 98.6, + "Segment": "Books" + }, + { + "X": 16.3, + "Y": 61.6, + "Segment": "Sports" + }, + { + "X": 23.5, + "Y": 26.6, + "Segment": "Home" + }, + { + "X": 33.4, + "Y": 88.1, + "Segment": "Garden" + }, + { + "X": 6.3, + "Y": 0.1, + "Segment": "Auto" + }, + { + "X": 47.9, + "Y": 77, + "Segment": "Health" + }, + { + "X": 17.9, + "Y": 49.1, + "Segment": "Beauty" + }, + { + "X": 82.5, + "Y": 80.8, + "Segment": "Toys" + }, + { + "X": 95.5, + "Y": 44.6, + "Segment": "Music" + }, + { + "X": 93.5, + "Y": 94.6, + "Segment": "Movies" + }, + { + "X": 57.5, + "Y": 91, + "Segment": "Software" + }, + { + "X": 16.5, + "Y": 82, + "Segment": "Games" + }, + { + "X": 85.1, + "Y": 51.9, + "Segment": "Office" + }, + { + "X": 49, + "Y": 42.4, + "Segment": "Pet" + }, + { + "X": 72.4, + "Y": 98.2, + "Segment": "Baby" + }, + { + "X": 32.7, + "Y": 22, + "Segment": "Tools" + }, + { + "X": 10.3, + "Y": 23.6, + "Segment": "Crafts" + }, + { + "X": 46.6, + "Y": 36.8, + "Segment": "Electronics" + }, + { + "X": 20, + "Y": 89.6, + "Segment": "Clothing" + }, + { + "X": 95.6, + "Y": 83.6, + "Segment": "Food" + }, + { + "X": 45, + "Y": 67.8, + "Segment": "Books" + }, + { + "X": 27.9, + "Y": 13.5, + "Segment": "Sports" + }, + { + "X": 37.2, + "Y": 91.5, + "Segment": "Home" + }, + { + "X": 12, + "Y": 89.5, + "Segment": "Garden" + }, + { + "X": 87.7, + "Y": 12, + "Segment": "Auto" + }, + { + "X": 88.5, + "Y": 72.4, + "Segment": "Health" + }, + { + "X": 83.2, + "Y": 93.4, + "Segment": "Beauty" + }, + { + "X": 75.9, + "Y": 37, + "Segment": "Toys" + }, + { + "X": 21.1, + "Y": 50.9, + "Segment": "Music" + }, + { + "X": 64.9, + "Y": 19.9, + "Segment": "Movies" + }, + { + "X": 86, + "Y": 38.7, + "Segment": "Software" + }, + { + "X": 91.4, + "Y": 27.8, + "Segment": "Games" + }, + { + "X": 52.9, + "Y": 85.5, + "Segment": "Office" + }, + { + "X": 67.2, + "Y": 57.2, + "Segment": "Pet" + }, + { + "X": 2, + "Y": 66.9, + "Segment": "Baby" + }, + { + "X": 2.3, + "Y": 18.7, + "Segment": "Tools" + }, + { + "X": 80.7, + "Y": 73.5, + "Segment": "Crafts" + }, + { + "X": 99, + "Y": 67.1, + "Segment": "Electronics" + }, + { + "X": 9.6, + "Y": 35.9, + "Segment": "Clothing" + }, + { + "X": 46.5, + "Y": 48.4, + "Segment": "Food" + }, + { + "X": 31.5, + "Y": 95.5, + "Segment": "Books" + }, + { + "X": 16.6, + "Y": 59, + "Segment": "Sports" + }, + { + "X": 81.1, + "Y": 29.1, + "Segment": "Home" + }, + { + "X": 1.4, + "Y": 59.3, + "Segment": "Garden" + }, + { + "X": 2.2, + "Y": 11.7, + "Segment": "Auto" + }, + { + "X": 35.2, + "Y": 15.4, + "Segment": "Health" + }, + { + "X": 60.9, + "Y": 10.8, + "Segment": "Beauty" + }, + { + "X": 80.2, + "Y": 40.8, + "Segment": "Toys" + }, + { + "X": 2, + "Y": 85.1, + "Segment": "Music" + }, + { + "X": 31.6, + "Y": 26.4, + "Segment": "Movies" + }, + { + "X": 64.2, + "Y": 65.7, + "Segment": "Software" + }, + { + "X": 19, + "Y": 51.9, + "Segment": "Games" + }, + { + "X": 51, + "Y": 27.5, + "Segment": "Office" + }, + { + "X": 5.7, + "Y": 10.3, + "Segment": "Pet" + }, + { + "X": 48.2, + "Y": 42.3, + "Segment": "Baby" + }, + { + "X": 35.4, + "Y": 25.8, + "Segment": "Tools" + }, + { + "X": 83.6, + "Y": 6, + "Segment": "Crafts" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/scatter-plot/12-card96.flint.json b/test-harness/excel/evaluations/inputs/scatter-plot/12-card96.flint.json new file mode 100644 index 00000000..0cd56cb6 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/scatter-plot/12-card96.flint.json @@ -0,0 +1,523 @@ +{ + "semantic_types": { + "X": "Quantity", + "Y": "Quantity", + "Segment": "Category" + }, + "chart_spec": { + "chartType": "Scatter Plot", + "encodings": { + "x": "X", + "y": "Y", + "color": "Segment" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 68.8, + "Y": 7.6, + "Segment": "James Walker" + }, + { + "X": 53.3, + "Y": 78.7, + "Segment": "Paul Wilson" + }, + { + "X": 73.8, + "Y": 84.1, + "Segment": "Jessica Martin" + }, + { + "X": 77.4, + "Y": 71.9, + "Segment": "Christopher Moore" + }, + { + "X": 11.6, + "Y": 45.9, + "Segment": "Betty Wilson" + }, + { + "X": 81.3, + "Y": 14.2, + "Segment": "Steven Lewis" + }, + { + "X": 24.9, + "Y": 46.6, + "Segment": "Karen Lopez" + }, + { + "X": 96.8, + "Y": 13.4, + "Segment": "Sandra Wright" + }, + { + "X": 74.6, + "Y": 40.1, + "Segment": "Daniel King" + }, + { + "X": 15, + "Y": 58.7, + "Segment": "Mark Taylor" + }, + { + "X": 47.1, + "Y": 37.9, + "Segment": "Sandra Thomas" + }, + { + "X": 82.3, + "Y": 34.1, + "Segment": "Karen Rodriguez" + }, + { + "X": 22.5, + "Y": 67.5, + "Segment": "Patricia Jackson" + }, + { + "X": 39.1, + "Y": 98.2, + "Segment": "Donna Hill" + }, + { + "X": 91.6, + "Y": 27.6, + "Segment": "Donna White" + }, + { + "X": 56.2, + "Y": 20.6, + "Segment": "Michael Brown" + }, + { + "X": 48.6, + "Y": 99.3, + "Segment": "Elizabeth Robinson" + }, + { + "X": 19, + "Y": 20.1, + "Segment": "Mary Jones" + }, + { + "X": 66.7, + "Y": 55.8, + "Segment": "Richard Rodriguez" + }, + { + "X": 81.5, + "Y": 32.4, + "Segment": "Christopher Clark" + }, + { + "X": 71.9, + "Y": 29.2, + "Segment": "Christopher Lopez" + }, + { + "X": 21.4, + "Y": 13.5, + "Segment": "Susan Ramirez" + }, + { + "X": 1.5, + "Y": 34.9, + "Segment": "Steven Wilson" + }, + { + "X": 3.5, + "Y": 97.8, + "Segment": "Paul Anderson" + }, + { + "X": 21.1, + "Y": 63, + "Segment": "Joseph Rodriguez" + }, + { + "X": 0.9, + "Y": 5.3, + "Segment": "Elizabeth Wright" + }, + { + "X": 69, + "Y": 64.3, + "Segment": "Kimberly Jackson" + }, + { + "X": 22.8, + "Y": 75.6, + "Segment": "Betty Hernandez" + }, + { + "X": 65.6, + "Y": 48.9, + "Segment": "David King" + }, + { + "X": 61.9, + "Y": 78.3, + "Segment": "Matthew Lopez" + }, + { + "X": 97.9, + "Y": 33.2, + "Segment": "Susan Hernandez" + }, + { + "X": 53.8, + "Y": 84.1, + "Segment": "Jennifer Lee" + }, + { + "X": 58.4, + "Y": 52.5, + "Segment": "Richard Flores" + }, + { + "X": 25.3, + "Y": 59.1, + "Segment": "John Anderson" + }, + { + "X": 70.7, + "Y": 16, + "Segment": "Kimberly Wright" + }, + { + "X": 28.6, + "Y": 73.7, + "Segment": "Joseph Williams" + }, + { + "X": 38.3, + "Y": 2.8, + "Segment": "Lisa Torres" + }, + { + "X": 25.6, + "Y": 17.4, + "Segment": "Andrew Rodriguez" + }, + { + "X": 9.4, + "Y": 8.3, + "Segment": "Karen Johnson" + }, + { + "X": 27.4, + "Y": 25.4, + "Segment": "Steven Jones" + }, + { + "X": 31.6, + "Y": 77.2, + "Segment": "Joshua Ramirez" + }, + { + "X": 66.3, + "Y": 7.6, + "Segment": "Emily Martinez" + }, + { + "X": 5.8, + "Y": 81.7, + "Segment": "Robert Walker" + }, + { + "X": 21.2, + "Y": 17.9, + "Segment": "Robert Lewis" + }, + { + "X": 52.7, + "Y": 97.3, + "Segment": "Sandra Lopez" + }, + { + "X": 44.3, + "Y": 82.1, + "Segment": "Nancy Miller" + }, + { + "X": 18.1, + "Y": 57.5, + "Segment": "Christopher Sanchez" + }, + { + "X": 38.5, + "Y": 99.1, + "Segment": "Daniel Flores" + }, + { + "X": 35.8, + "Y": 76.5, + "Segment": "Mary Walker" + }, + { + "X": 96.4, + "Y": 74.4, + "Segment": "Anthony Ramirez" + }, + { + "X": 87.3, + "Y": 22.1, + "Segment": "James Walker" + }, + { + "X": 6.8, + "Y": 2.2, + "Segment": "Paul Wilson" + }, + { + "X": 8.2, + "Y": 56.2, + "Segment": "Jessica Martin" + }, + { + "X": 95.8, + "Y": 73, + "Segment": "Christopher Moore" + }, + { + "X": 34.2, + "Y": 10.5, + "Segment": "Betty Wilson" + }, + { + "X": 68.1, + "Y": 76.5, + "Segment": "Steven Lewis" + }, + { + "X": 80.4, + "Y": 21, + "Segment": "Karen Lopez" + }, + { + "X": 71.5, + "Y": 44.6, + "Segment": "Sandra Wright" + }, + { + "X": 78.7, + "Y": 78.4, + "Segment": "Daniel King" + }, + { + "X": 1.5, + "Y": 3.8, + "Segment": "Mark Taylor" + }, + { + "X": 28.1, + "Y": 53.6, + "Segment": "Sandra Thomas" + }, + { + "X": 63.3, + "Y": 87.6, + "Segment": "Karen Rodriguez" + }, + { + "X": 95, + "Y": 30.9, + "Segment": "Patricia Jackson" + }, + { + "X": 53.7, + "Y": 48.2, + "Segment": "Donna Hill" + }, + { + "X": 74.6, + "Y": 62.4, + "Segment": "Donna White" + }, + { + "X": 93.2, + "Y": 25.7, + "Segment": "Michael Brown" + }, + { + "X": 20.7, + "Y": 78.1, + "Segment": "Elizabeth Robinson" + }, + { + "X": 30.4, + "Y": 17.6, + "Segment": "Mary Jones" + }, + { + "X": 3.2, + "Y": 10.2, + "Segment": "Richard Rodriguez" + }, + { + "X": 16.9, + "Y": 21.3, + "Segment": "Christopher Clark" + }, + { + "X": 5.9, + "Y": 65.8, + "Segment": "Christopher Lopez" + }, + { + "X": 63.2, + "Y": 76.9, + "Segment": "Susan Ramirez" + }, + { + "X": 70.7, + "Y": 29.1, + "Segment": "Steven Wilson" + }, + { + "X": 82.9, + "Y": 88.3, + "Segment": "Paul Anderson" + }, + { + "X": 93.7, + "Y": 77.9, + "Segment": "Joseph Rodriguez" + }, + { + "X": 85.7, + "Y": 78.4, + "Segment": "Elizabeth Wright" + }, + { + "X": 48.4, + "Y": 61.3, + "Segment": "Kimberly Jackson" + }, + { + "X": 22.6, + "Y": 39.4, + "Segment": "Betty Hernandez" + }, + { + "X": 8.1, + "Y": 30.3, + "Segment": "David King" + }, + { + "X": 41.8, + "Y": 96.9, + "Segment": "Matthew Lopez" + }, + { + "X": 51.5, + "Y": 35.3, + "Segment": "Susan Hernandez" + }, + { + "X": 11.4, + "Y": 16.8, + "Segment": "Jennifer Lee" + }, + { + "X": 30.9, + "Y": 9.7, + "Segment": "Richard Flores" + }, + { + "X": 60.1, + "Y": 96.1, + "Segment": "John Anderson" + }, + { + "X": 64.4, + "Y": 89.7, + "Segment": "Kimberly Wright" + }, + { + "X": 9.7, + "Y": 57.9, + "Segment": "Joseph Williams" + }, + { + "X": 69.1, + "Y": 57.7, + "Segment": "Lisa Torres" + }, + { + "X": 67.2, + "Y": 15.6, + "Segment": "Andrew Rodriguez" + }, + { + "X": 10.5, + "Y": 70, + "Segment": "Karen Johnson" + }, + { + "X": 16.7, + "Y": 36.7, + "Segment": "Steven Jones" + }, + { + "X": 50.4, + "Y": 3.7, + "Segment": "Joshua Ramirez" + }, + { + "X": 47.4, + "Y": 51.8, + "Segment": "Emily Martinez" + }, + { + "X": 8.7, + "Y": 34.4, + "Segment": "Robert Walker" + }, + { + "X": 93.4, + "Y": 9.8, + "Segment": "Robert Lewis" + }, + { + "X": 14.9, + "Y": 17.5, + "Segment": "Sandra Lopez" + }, + { + "X": 98.5, + "Y": 92.2, + "Segment": "Nancy Miller" + }, + { + "X": 34.7, + "Y": 51.7, + "Segment": "Christopher Sanchez" + }, + { + "X": 76.5, + "Y": 35.8, + "Segment": "Daniel Flores" + }, + { + "X": 37.4, + "Y": 46.1, + "Segment": "Mary Walker" + }, + { + "X": 34.2, + "Y": 2.6, + "Segment": "Anthony Ramirez" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/scatter-plot/13-card10.flint.json b/test-harness/excel/evaluations/inputs/scatter-plot/13-card10.flint.json new file mode 100644 index 00000000..c4102d5e --- /dev/null +++ b/test-harness/excel/evaluations/inputs/scatter-plot/13-card10.flint.json @@ -0,0 +1,73 @@ +{ + "semantic_types": { + "X": "Quantity", + "Y": "Quantity", + "Size": "Quantity" + }, + "chart_spec": { + "chartType": "Scatter Plot", + "encodings": { + "x": "X", + "y": "Y", + "size": "Size" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 56.8, + "Y": 95, + "Size": 63.2 + }, + { + "X": 44.9, + "Y": 16, + "Size": 16.7 + }, + { + "X": 54, + "Y": 7.1, + "Size": 87.9 + }, + { + "X": 95.8, + "Y": 49.8, + "Size": 90.1 + }, + { + "X": 84.8, + "Y": 34.6, + "Size": 35.8 + }, + { + "X": 65.1, + "Y": 45.9, + "Size": 57.5 + }, + { + "X": 34.1, + "Y": 80.2, + "Size": 83.3 + }, + { + "X": 58.2, + "Y": 2.3, + "Size": 21.3 + }, + { + "X": 48.2, + "Y": 10.5, + "Size": 44.6 + }, + { + "X": 94, + "Y": 96.6, + "Size": 82.9 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/scatter-plot/14-card187.flint.json b/test-harness/excel/evaluations/inputs/scatter-plot/14-card187.flint.json new file mode 100644 index 00000000..ace73d8a --- /dev/null +++ b/test-harness/excel/evaluations/inputs/scatter-plot/14-card187.flint.json @@ -0,0 +1,1023 @@ +{ + "semantic_types": { + "X": "Quantity", + "Y": "Quantity", + "Size": "Quantity" + }, + "chart_spec": { + "chartType": "Scatter Plot", + "encodings": { + "x": "X", + "y": "Y", + "size": "Size" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 7.2, + "Y": 56.4, + "Size": 55.2 + }, + { + "X": 8, + "Y": 89.5, + "Size": 1.3 + }, + { + "X": 73.7, + "Y": 64.9, + "Size": 82.1 + }, + { + "X": 88.4, + "Y": 28, + "Size": 94.7 + }, + { + "X": 35.1, + "Y": 19.8, + "Size": 19 + }, + { + "X": 10.7, + "Y": 52.1, + "Size": 68.3 + }, + { + "X": 37.4, + "Y": 54.4, + "Size": 83.4 + }, + { + "X": 23.7, + "Y": 40.3, + "Size": 76.1 + }, + { + "X": 4.8, + "Y": 74.6, + "Size": 41.1 + }, + { + "X": 5.1, + "Y": 66.4, + "Size": 3.3 + }, + { + "X": 59.8, + "Y": 85.2, + "Size": 52.4 + }, + { + "X": 90.7, + "Y": 31.5, + "Size": 5.4 + }, + { + "X": 38.5, + "Y": 40.6, + "Size": 46.5 + }, + { + "X": 29.3, + "Y": 47.4, + "Size": 5.5 + }, + { + "X": 37.4, + "Y": 23.2, + "Size": 65.9 + }, + { + "X": 50.7, + "Y": 52, + "Size": 59.5 + }, + { + "X": 20.5, + "Y": 97.7, + "Size": 87.4 + }, + { + "X": 44.3, + "Y": 33.1, + "Size": 17.2 + }, + { + "X": 7.7, + "Y": 65.9, + "Size": 69.3 + }, + { + "X": 81.5, + "Y": 77.7, + "Size": 16 + }, + { + "X": 71.5, + "Y": 49.9, + "Size": 94.9 + }, + { + "X": 89.4, + "Y": 22.5, + "Size": 40.2 + }, + { + "X": 59.3, + "Y": 17.4, + "Size": 71 + }, + { + "X": 67.6, + "Y": 2.7, + "Size": 72.6 + }, + { + "X": 83.4, + "Y": 24.3, + "Size": 43.7 + }, + { + "X": 44.9, + "Y": 4, + "Size": 88.3 + }, + { + "X": 58.7, + "Y": 39.7, + "Size": 39.6 + }, + { + "X": 50, + "Y": 95.5, + "Size": 40.6 + }, + { + "X": 7.4, + "Y": 94.3, + "Size": 78.6 + }, + { + "X": 34.2, + "Y": 33.3, + "Size": 25 + }, + { + "X": 62.1, + "Y": 39.7, + "Size": 56.7 + }, + { + "X": 23.3, + "Y": 68.5, + "Size": 46.5 + }, + { + "X": 25.5, + "Y": 67.1, + "Size": 45.3 + }, + { + "X": 84.7, + "Y": 33, + "Size": 53.3 + }, + { + "X": 56.8, + "Y": 32.7, + "Size": 13.3 + }, + { + "X": 84.5, + "Y": 59.1, + "Size": 9.8 + }, + { + "X": 58, + "Y": 99.5, + "Size": 95.2 + }, + { + "X": 5, + "Y": 98.2, + "Size": 45.1 + }, + { + "X": 89.5, + "Y": 48.6, + "Size": 47 + }, + { + "X": 44.7, + "Y": 85.8, + "Size": 24.3 + }, + { + "X": 39.4, + "Y": 85.3, + "Size": 33.9 + }, + { + "X": 70.4, + "Y": 70, + "Size": 76.6 + }, + { + "X": 51.5, + "Y": 83.5, + "Size": 71.2 + }, + { + "X": 19.2, + "Y": 62, + "Size": 88.4 + }, + { + "X": 61.7, + "Y": 62.5, + "Size": 86.4 + }, + { + "X": 75.9, + "Y": 21.8, + "Size": 27.5 + }, + { + "X": 37.2, + "Y": 77, + "Size": 95.2 + }, + { + "X": 56.5, + "Y": 28.1, + "Size": 53.8 + }, + { + "X": 63.8, + "Y": 99.6, + "Size": 5.3 + }, + { + "X": 72.5, + "Y": 24.1, + "Size": 42.5 + }, + { + "X": 14.1, + "Y": 84, + "Size": 6.9 + }, + { + "X": 17.2, + "Y": 12.4, + "Size": 98.9 + }, + { + "X": 56.8, + "Y": 32.3, + "Size": 24.1 + }, + { + "X": 65.8, + "Y": 38.4, + "Size": 18.6 + }, + { + "X": 11.5, + "Y": 96.6, + "Size": 69.3 + }, + { + "X": 2.8, + "Y": 19.2, + "Size": 65.4 + }, + { + "X": 37.8, + "Y": 96, + "Size": 16.2 + }, + { + "X": 51.1, + "Y": 8.5, + "Size": 32.9 + }, + { + "X": 96.5, + "Y": 52.3, + "Size": 0 + }, + { + "X": 42.3, + "Y": 84.4, + "Size": 85.9 + }, + { + "X": 3.9, + "Y": 47, + "Size": 22.2 + }, + { + "X": 35.9, + "Y": 75.2, + "Size": 72.2 + }, + { + "X": 56, + "Y": 96.6, + "Size": 20.2 + }, + { + "X": 72.7, + "Y": 49.7, + "Size": 95 + }, + { + "X": 12.4, + "Y": 41.7, + "Size": 64.5 + }, + { + "X": 12.2, + "Y": 2.4, + "Size": 3.3 + }, + { + "X": 97.2, + "Y": 32.8, + "Size": 4.6 + }, + { + "X": 91.1, + "Y": 85.3, + "Size": 14.2 + }, + { + "X": 60.9, + "Y": 86.9, + "Size": 26.7 + }, + { + "X": 63.8, + "Y": 74.7, + "Size": 83.4 + }, + { + "X": 66.5, + "Y": 14.9, + "Size": 22.9 + }, + { + "X": 95.2, + "Y": 89.9, + "Size": 76.1 + }, + { + "X": 88, + "Y": 52, + "Size": 25.9 + }, + { + "X": 97.1, + "Y": 55.7, + "Size": 2.6 + }, + { + "X": 57.2, + "Y": 62.4, + "Size": 0.3 + }, + { + "X": 58.3, + "Y": 77.9, + "Size": 5.7 + }, + { + "X": 6.2, + "Y": 69.7, + "Size": 15.1 + }, + { + "X": 32.2, + "Y": 87.7, + "Size": 27.2 + }, + { + "X": 24.6, + "Y": 77.7, + "Size": 5.1 + }, + { + "X": 50.4, + "Y": 12.3, + "Size": 43.6 + }, + { + "X": 10.5, + "Y": 76.3, + "Size": 91.1 + }, + { + "X": 10.1, + "Y": 87.7, + "Size": 86.1 + }, + { + "X": 43.7, + "Y": 61.6, + "Size": 70.3 + }, + { + "X": 33.4, + "Y": 75.5, + "Size": 79.9 + }, + { + "X": 48.7, + "Y": 70.3, + "Size": 6.4 + }, + { + "X": 30.8, + "Y": 64, + "Size": 60.3 + }, + { + "X": 49.3, + "Y": 66.3, + "Size": 89 + }, + { + "X": 60.3, + "Y": 72.2, + "Size": 75.7 + }, + { + "X": 4.2, + "Y": 61.9, + "Size": 36.4 + }, + { + "X": 55.2, + "Y": 39.5, + "Size": 96.9 + }, + { + "X": 65.9, + "Y": 2.3, + "Size": 17.1 + }, + { + "X": 27.2, + "Y": 42.1, + "Size": 19.5 + }, + { + "X": 9.8, + "Y": 41.6, + "Size": 43.7 + }, + { + "X": 64.6, + "Y": 25.9, + "Size": 15.2 + }, + { + "X": 86, + "Y": 20.1, + "Size": 39.5 + }, + { + "X": 39.7, + "Y": 3.6, + "Size": 4.4 + }, + { + "X": 8.8, + "Y": 17.1, + "Size": 6.9 + }, + { + "X": 82.7, + "Y": 37.1, + "Size": 93.5 + }, + { + "X": 94.4, + "Y": 76.8, + "Size": 22.8 + }, + { + "X": 37.1, + "Y": 4.1, + "Size": 23 + }, + { + "X": 66.6, + "Y": 19, + "Size": 96.3 + }, + { + "X": 53.5, + "Y": 7.1, + "Size": 68.5 + }, + { + "X": 10.4, + "Y": 54.7, + "Size": 27 + }, + { + "X": 16, + "Y": 17.5, + "Size": 95.1 + }, + { + "X": 75, + "Y": 64.4, + "Size": 57.2 + }, + { + "X": 69.4, + "Y": 77.5, + "Size": 6.1 + }, + { + "X": 20.9, + "Y": 10.3, + "Size": 15.2 + }, + { + "X": 84.2, + "Y": 31.4, + "Size": 72.7 + }, + { + "X": 61.9, + "Y": 74.3, + "Size": 97.5 + }, + { + "X": 78.1, + "Y": 84.1, + "Size": 56.2 + }, + { + "X": 18.1, + "Y": 59.2, + "Size": 72.2 + }, + { + "X": 63, + "Y": 35.5, + "Size": 71.3 + }, + { + "X": 31, + "Y": 26.5, + "Size": 38.6 + }, + { + "X": 68.2, + "Y": 33.3, + "Size": 29.1 + }, + { + "X": 58.1, + "Y": 86.6, + "Size": 47 + }, + { + "X": 4.9, + "Y": 23.3, + "Size": 46.1 + }, + { + "X": 94.8, + "Y": 11.1, + "Size": 83.6 + }, + { + "X": 71.6, + "Y": 8.3, + "Size": 87.5 + }, + { + "X": 33, + "Y": 58, + "Size": 82.2 + }, + { + "X": 26.9, + "Y": 34.5, + "Size": 65.1 + }, + { + "X": 65.1, + "Y": 7.1, + "Size": 5.5 + }, + { + "X": 98.6, + "Y": 2.1, + "Size": 98 + }, + { + "X": 65.8, + "Y": 84.8, + "Size": 97.5 + }, + { + "X": 72.2, + "Y": 50.7, + "Size": 48.4 + }, + { + "X": 67.5, + "Y": 21.7, + "Size": 54.2 + }, + { + "X": 40.9, + "Y": 37.8, + "Size": 94.1 + }, + { + "X": 49.2, + "Y": 25.3, + "Size": 49.1 + }, + { + "X": 75.6, + "Y": 63.1, + "Size": 23.3 + }, + { + "X": 78, + "Y": 89.1, + "Size": 2.5 + }, + { + "X": 56.2, + "Y": 86.9, + "Size": 72.8 + }, + { + "X": 36.1, + "Y": 14, + "Size": 69.7 + }, + { + "X": 69.4, + "Y": 93.6, + "Size": 22.3 + }, + { + "X": 11, + "Y": 25.8, + "Size": 68.2 + }, + { + "X": 77, + "Y": 44.8, + "Size": 5.1 + }, + { + "X": 20.4, + "Y": 15.9, + "Size": 42.4 + }, + { + "X": 76.4, + "Y": 47.9, + "Size": 32.2 + }, + { + "X": 83.7, + "Y": 47.4, + "Size": 33.2 + }, + { + "X": 75.4, + "Y": 19.5, + "Size": 33.1 + }, + { + "X": 3.2, + "Y": 80.4, + "Size": 82.2 + }, + { + "X": 81.6, + "Y": 78.1, + "Size": 52.1 + }, + { + "X": 81.4, + "Y": 80.8, + "Size": 36.2 + }, + { + "X": 77.5, + "Y": 87.9, + "Size": 70.7 + }, + { + "X": 64.2, + "Y": 28.9, + "Size": 76.9 + }, + { + "X": 43.9, + "Y": 82.4, + "Size": 85.2 + }, + { + "X": 39.4, + "Y": 98, + "Size": 96.6 + }, + { + "X": 16.2, + "Y": 36.8, + "Size": 90.1 + }, + { + "X": 95.6, + "Y": 44.5, + "Size": 17.4 + }, + { + "X": 87.1, + "Y": 78.2, + "Size": 98.6 + }, + { + "X": 40.1, + "Y": 67.2, + "Size": 23.1 + }, + { + "X": 94.1, + "Y": 98.7, + "Size": 53.4 + }, + { + "X": 25, + "Y": 68.3, + "Size": 96.9 + }, + { + "X": 27.3, + "Y": 98.7, + "Size": 1.1 + }, + { + "X": 96.3, + "Y": 10.5, + "Size": 38.8 + }, + { + "X": 62.5, + "Y": 67.8, + "Size": 74.6 + }, + { + "X": 84.1, + "Y": 78.1, + "Size": 70.3 + }, + { + "X": 6.4, + "Y": 29.4, + "Size": 32.5 + }, + { + "X": 9.2, + "Y": 57.2, + "Size": 38 + }, + { + "X": 5.1, + "Y": 56.7, + "Size": 36.5 + }, + { + "X": 83, + "Y": 92, + "Size": 74.9 + }, + { + "X": 1.8, + "Y": 78, + "Size": 93 + }, + { + "X": 17.9, + "Y": 55.3, + "Size": 32.8 + }, + { + "X": 86.8, + "Y": 95.7, + "Size": 83.4 + }, + { + "X": 71.9, + "Y": 36.9, + "Size": 62.2 + }, + { + "X": 10.5, + "Y": 11, + "Size": 61.9 + }, + { + "X": 87.2, + "Y": 31.5, + "Size": 13.2 + }, + { + "X": 49.4, + "Y": 27.2, + "Size": 74.4 + }, + { + "X": 85.6, + "Y": 41.2, + "Size": 17.9 + }, + { + "X": 27.2, + "Y": 11.1, + "Size": 69.2 + }, + { + "X": 69.8, + "Y": 97.5, + "Size": 49.1 + }, + { + "X": 50.2, + "Y": 12, + "Size": 68.5 + }, + { + "X": 18.1, + "Y": 70.3, + "Size": 58.9 + }, + { + "X": 2.5, + "Y": 60.9, + "Size": 43.5 + }, + { + "X": 68.5, + "Y": 15.7, + "Size": 64.9 + }, + { + "X": 16.9, + "Y": 47.4, + "Size": 37.5 + }, + { + "X": 94.7, + "Y": 2.2, + "Size": 6.8 + }, + { + "X": 32.8, + "Y": 29.4, + "Size": 71.1 + }, + { + "X": 38.2, + "Y": 67, + "Size": 49 + }, + { + "X": 95.8, + "Y": 40.7, + "Size": 45.1 + }, + { + "X": 18.1, + "Y": 58.5, + "Size": 82.5 + }, + { + "X": 91.4, + "Y": 34.4, + "Size": 17.9 + }, + { + "X": 80.3, + "Y": 19.2, + "Size": 47.4 + }, + { + "X": 5.2, + "Y": 42.4, + "Size": 73.1 + }, + { + "X": 36.8, + "Y": 86.3, + "Size": 92.7 + }, + { + "X": 45.2, + "Y": 64.7, + "Size": 56.9 + }, + { + "X": 17.9, + "Y": 45, + "Size": 9.3 + }, + { + "X": 45.9, + "Y": 46.2, + "Size": 87.6 + }, + { + "X": 46.4, + "Y": 62.1, + "Size": 3.9 + }, + { + "X": 11.4, + "Y": 11.3, + "Size": 80.3 + }, + { + "X": 18.7, + "Y": 58.5, + "Size": 47 + }, + { + "X": 49.9, + "Y": 21.3, + "Size": 84.4 + }, + { + "X": 1.9, + "Y": 65.6, + "Size": 11.8 + }, + { + "X": 27.9, + "Y": 52.4, + "Size": 48.6 + }, + { + "X": 43.5, + "Y": 36.7, + "Size": 95.7 + }, + { + "X": 30.8, + "Y": 53, + "Size": 50.5 + }, + { + "X": 84.6, + "Y": 69.5, + "Size": 50.3 + }, + { + "X": 71.1, + "Y": 59.6, + "Size": 77.1 + }, + { + "X": 24.3, + "Y": 62.5, + "Size": 32 + }, + { + "X": 65.3, + "Y": 91.9, + "Size": 43.9 + }, + { + "X": 12.6, + "Y": 52, + "Size": 64 + }, + { + "X": 15.7, + "Y": 6.6, + "Size": 96 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/scatter-plot/15-card5.flint.json b/test-harness/excel/evaluations/inputs/scatter-plot/15-card5.flint.json new file mode 100644 index 00000000..c9a43959 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/scatter-plot/15-card5.flint.json @@ -0,0 +1,148 @@ +{ + "semantic_types": { + "Category": "Category", + "Y": "Quantity", + "ColorVal": "Quantity" + }, + "chart_spec": { + "chartType": "Scatter Plot", + "encodings": { + "x": "Category", + "y": "Y", + "color": "ColorVal" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Electronics", + "Y": 53.3, + "ColorVal": 47.7 + }, + { + "Category": "Clothing", + "Y": 86.4, + "ColorVal": 91.1 + }, + { + "Category": "Food", + "Y": 12.6, + "ColorVal": 86.8 + }, + { + "Category": "Books", + "Y": 26, + "ColorVal": 46 + }, + { + "Category": "Sports", + "Y": 18.8, + "ColorVal": 26.4 + }, + { + "Category": "Electronics", + "Y": 89.5, + "ColorVal": 57.3 + }, + { + "Category": "Clothing", + "Y": 69.2, + "ColorVal": 97.1 + }, + { + "Category": "Food", + "Y": 30.8, + "ColorVal": 36.6 + }, + { + "Category": "Books", + "Y": 63.9, + "ColorVal": 30.1 + }, + { + "Category": "Sports", + "Y": 0.3, + "ColorVal": 95.1 + }, + { + "Category": "Electronics", + "Y": 23.7, + "ColorVal": 46.1 + }, + { + "Category": "Clothing", + "Y": 1.6, + "ColorVal": 88.8 + }, + { + "Category": "Food", + "Y": 44.3, + "ColorVal": 49.1 + }, + { + "Category": "Books", + "Y": 26.6, + "ColorVal": 83.6 + }, + { + "Category": "Sports", + "Y": 18.4, + "ColorVal": 14.6 + }, + { + "Category": "Electronics", + "Y": 11.2, + "ColorVal": 86.5 + }, + { + "Category": "Clothing", + "Y": 81.8, + "ColorVal": 65.6 + }, + { + "Category": "Food", + "Y": 38.9, + "ColorVal": 32.5 + }, + { + "Category": "Books", + "Y": 26.8, + "ColorVal": 70.9 + }, + { + "Category": "Sports", + "Y": 2.7, + "ColorVal": 39.2 + }, + { + "Category": "Electronics", + "Y": 38.5, + "ColorVal": 49.5 + }, + { + "Category": "Clothing", + "Y": 62.6, + "ColorVal": 51 + }, + { + "Category": "Food", + "Y": 60.9, + "ColorVal": 36 + }, + { + "Category": "Books", + "Y": 55.6, + "ColorVal": 3.2 + }, + { + "Category": "Sports", + "Y": 92.3, + "ColorVal": 76.8 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/scatter-plot/16-card5.flint.json b/test-harness/excel/evaluations/inputs/scatter-plot/16-card5.flint.json new file mode 100644 index 00000000..5bef9c8d --- /dev/null +++ b/test-harness/excel/evaluations/inputs/scatter-plot/16-card5.flint.json @@ -0,0 +1,148 @@ +{ + "semantic_types": { + "Category": "Category", + "Y": "Quantity", + "Size": "Quantity" + }, + "chart_spec": { + "chartType": "Scatter Plot", + "encodings": { + "x": "Category", + "y": "Y", + "size": "Size" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Electronics", + "Y": 20.4, + "Size": 11.2 + }, + { + "Category": "Clothing", + "Y": 83, + "Size": 73.6 + }, + { + "Category": "Food", + "Y": 67.3, + "Size": 23.2 + }, + { + "Category": "Books", + "Y": 80.9, + "Size": 90.9 + }, + { + "Category": "Sports", + "Y": 55.3, + "Size": 44.5 + }, + { + "Category": "Electronics", + "Y": 70.5, + "Size": 33.9 + }, + { + "Category": "Clothing", + "Y": 7.4, + "Size": 19 + }, + { + "Category": "Food", + "Y": 75.2, + "Size": 34.1 + }, + { + "Category": "Books", + "Y": 34.8, + "Size": 75.5 + }, + { + "Category": "Sports", + "Y": 4.9, + "Size": 59.1 + }, + { + "Category": "Electronics", + "Y": 77.9, + "Size": 17.9 + }, + { + "Category": "Clothing", + "Y": 23.3, + "Size": 16.2 + }, + { + "Category": "Food", + "Y": 72.8, + "Size": 67.3 + }, + { + "Category": "Books", + "Y": 58.3, + "Size": 61.7 + }, + { + "Category": "Sports", + "Y": 61, + "Size": 84.5 + }, + { + "Category": "Electronics", + "Y": 21.8, + "Size": 81.1 + }, + { + "Category": "Clothing", + "Y": 27.9, + "Size": 99.3 + }, + { + "Category": "Food", + "Y": 38.3, + "Size": 5.2 + }, + { + "Category": "Books", + "Y": 95.7, + "Size": 86.8 + }, + { + "Category": "Sports", + "Y": 6, + "Size": 55.7 + }, + { + "Category": "Electronics", + "Y": 18.4, + "Size": 4.9 + }, + { + "Category": "Clothing", + "Y": 38.1, + "Size": 51.6 + }, + { + "Category": "Food", + "Y": 19.9, + "Size": 31.1 + }, + { + "Category": "Books", + "Y": 49.3, + "Size": 54.9 + }, + { + "Category": "Sports", + "Y": 71.3, + "Size": 78.1 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/scatter-plot/17-card2.flint.json b/test-harness/excel/evaluations/inputs/scatter-plot/17-card2.flint.json new file mode 100644 index 00000000..1343e4ca --- /dev/null +++ b/test-harness/excel/evaluations/inputs/scatter-plot/17-card2.flint.json @@ -0,0 +1,141 @@ +{ + "semantic_types": { + "Category": "Category", + "Y": "Quantity" + }, + "chart_spec": { + "chartType": "Scatter Plot", + "encodings": { + "x": "Category", + "y": "Y" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Electronics", + "Y": 22.5 + }, + { + "Category": "Clothing", + "Y": 84.4 + }, + { + "Category": "Electronics", + "Y": 34.8 + }, + { + "Category": "Clothing", + "Y": 96.6 + }, + { + "Category": "Electronics", + "Y": 71.5 + }, + { + "Category": "Clothing", + "Y": 15.6 + }, + { + "Category": "Electronics", + "Y": 76.2 + }, + { + "Category": "Clothing", + "Y": 5.1 + }, + { + "Category": "Electronics", + "Y": 37.5 + }, + { + "Category": "Clothing", + "Y": 29.1 + }, + { + "Category": "Electronics", + "Y": 69.1 + }, + { + "Category": "Clothing", + "Y": 61.4 + }, + { + "Category": "Electronics", + "Y": 72.9 + }, + { + "Category": "Clothing", + "Y": 8.4 + }, + { + "Category": "Electronics", + "Y": 38.2 + }, + { + "Category": "Clothing", + "Y": 88.3 + }, + { + "Category": "Electronics", + "Y": 31.9 + }, + { + "Category": "Clothing", + "Y": 26.9 + }, + { + "Category": "Electronics", + "Y": 42.2 + }, + { + "Category": "Clothing", + "Y": 38.4 + }, + { + "Category": "Electronics", + "Y": 63.1 + }, + { + "Category": "Clothing", + "Y": 55 + }, + { + "Category": "Electronics", + "Y": 30.8 + }, + { + "Category": "Clothing", + "Y": 25.7 + }, + { + "Category": "Electronics", + "Y": 3.1 + }, + { + "Category": "Clothing", + "Y": 11.6 + }, + { + "Category": "Electronics", + "Y": 11.1 + }, + { + "Category": "Clothing", + "Y": 93.9 + }, + { + "Category": "Electronics", + "Y": 34.1 + }, + { + "Category": "Clothing", + "Y": 16.6 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/scatter-plot/18-card60.flint.json b/test-harness/excel/evaluations/inputs/scatter-plot/18-card60.flint.json new file mode 100644 index 00000000..c00c3545 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/scatter-plot/18-card60.flint.json @@ -0,0 +1,261 @@ +{ + "semantic_types": { + "Category": "Category", + "Y": "Quantity" + }, + "chart_spec": { + "chartType": "Scatter Plot", + "encodings": { + "x": "Category", + "y": "Y" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "James Walker", + "Y": 66.2 + }, + { + "Category": "Paul Wilson", + "Y": 49.3 + }, + { + "Category": "Jessica Martin", + "Y": 28.5 + }, + { + "Category": "Christopher Moore", + "Y": 14.6 + }, + { + "Category": "Betty Wilson", + "Y": 7.2 + }, + { + "Category": "Steven Lewis", + "Y": 13.8 + }, + { + "Category": "Karen Lopez", + "Y": 41.6 + }, + { + "Category": "Sandra Wright", + "Y": 5.7 + }, + { + "Category": "Daniel King", + "Y": 1.8 + }, + { + "Category": "Mark Taylor", + "Y": 47.2 + }, + { + "Category": "Sandra Thomas", + "Y": 9.7 + }, + { + "Category": "Karen Rodriguez", + "Y": 52.1 + }, + { + "Category": "Patricia Jackson", + "Y": 6.5 + }, + { + "Category": "Donna Hill", + "Y": 44.4 + }, + { + "Category": "Donna White", + "Y": 25.8 + }, + { + "Category": "Michael Brown", + "Y": 15.9 + }, + { + "Category": "Elizabeth Robinson", + "Y": 42.9 + }, + { + "Category": "Mary Jones", + "Y": 97.9 + }, + { + "Category": "Richard Rodriguez", + "Y": 7 + }, + { + "Category": "Christopher Clark", + "Y": 63.1 + }, + { + "Category": "Christopher Lopez", + "Y": 33.8 + }, + { + "Category": "Susan Ramirez", + "Y": 43.1 + }, + { + "Category": "Steven Wilson", + "Y": 84.9 + }, + { + "Category": "Paul Anderson", + "Y": 24 + }, + { + "Category": "Joseph Rodriguez", + "Y": 11.9 + }, + { + "Category": "Elizabeth Wright", + "Y": 52.7 + }, + { + "Category": "Kimberly Jackson", + "Y": 75.2 + }, + { + "Category": "Betty Hernandez", + "Y": 77.4 + }, + { + "Category": "David King", + "Y": 22.3 + }, + { + "Category": "Matthew Lopez", + "Y": 60.1 + }, + { + "Category": "Susan Hernandez", + "Y": 37.8 + }, + { + "Category": "Jennifer Lee", + "Y": 15 + }, + { + "Category": "Richard Flores", + "Y": 48.9 + }, + { + "Category": "John Anderson", + "Y": 41.7 + }, + { + "Category": "Kimberly Wright", + "Y": 98.3 + }, + { + "Category": "Joseph Williams", + "Y": 72.2 + }, + { + "Category": "Lisa Torres", + "Y": 84.5 + }, + { + "Category": "Andrew Rodriguez", + "Y": 74.5 + }, + { + "Category": "Karen Johnson", + "Y": 61.1 + }, + { + "Category": "Steven Jones", + "Y": 87.5 + }, + { + "Category": "Joshua Ramirez", + "Y": 36.7 + }, + { + "Category": "Emily Martinez", + "Y": 15.9 + }, + { + "Category": "Robert Walker", + "Y": 4.8 + }, + { + "Category": "Robert Lewis", + "Y": 77.9 + }, + { + "Category": "Sandra Lopez", + "Y": 44.7 + }, + { + "Category": "Nancy Miller", + "Y": 57.8 + }, + { + "Category": "Christopher Sanchez", + "Y": 27.8 + }, + { + "Category": "Daniel Flores", + "Y": 39.7 + }, + { + "Category": "Mary Walker", + "Y": 84.4 + }, + { + "Category": "Anthony Ramirez", + "Y": 34.1 + }, + { + "Category": "Anthony Hill", + "Y": 32.8 + }, + { + "Category": "Matthew Miller", + "Y": 61.3 + }, + { + "Category": "Andrew King", + "Y": 25.1 + }, + { + "Category": "William Perez", + "Y": 86.2 + }, + { + "Category": "William Martinez", + "Y": 79.4 + }, + { + "Category": "Margaret Garcia", + "Y": 14.3 + }, + { + "Category": "Barbara Anderson", + "Y": 38.2 + }, + { + "Category": "Thomas Smith", + "Y": 76.2 + }, + { + "Category": "Kimberly Thomas", + "Y": 0.2 + }, + { + "Category": "Karen Garcia", + "Y": 65.1 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/scatter-plot/19-card24.flint.json b/test-harness/excel/evaluations/inputs/scatter-plot/19-card24.flint.json new file mode 100644 index 00000000..a85cf9f4 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/scatter-plot/19-card24.flint.json @@ -0,0 +1,148 @@ +{ + "semantic_types": { + "X": "Quantity", + "Group": "Category", + "ColorVal": "Quantity" + }, + "chart_spec": { + "chartType": "Scatter Plot", + "encodings": { + "x": "X", + "y": "Group", + "color": "ColorVal" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 65.4, + "Group": "Electronics", + "ColorVal": 92.7 + }, + { + "X": 41.2, + "Group": "Clothing", + "ColorVal": 65.7 + }, + { + "X": 65.6, + "Group": "Food", + "ColorVal": 66.2 + }, + { + "X": 1.3, + "Group": "Books", + "ColorVal": 80.2 + }, + { + "X": 19.4, + "Group": "Sports", + "ColorVal": 91.7 + }, + { + "X": 55.6, + "Group": "Electronics", + "ColorVal": 64.7 + }, + { + "X": 72.6, + "Group": "Clothing", + "ColorVal": 66.4 + }, + { + "X": 25.5, + "Group": "Food", + "ColorVal": 51.3 + }, + { + "X": 15.8, + "Group": "Books", + "ColorVal": 39.9 + }, + { + "X": 2.4, + "Group": "Sports", + "ColorVal": 85.4 + }, + { + "X": 65.8, + "Group": "Electronics", + "ColorVal": 55.2 + }, + { + "X": 92.4, + "Group": "Clothing", + "ColorVal": 6 + }, + { + "X": 40, + "Group": "Food", + "ColorVal": 29.5 + }, + { + "X": 13.6, + "Group": "Books", + "ColorVal": 83.9 + }, + { + "X": 87.1, + "Group": "Sports", + "ColorVal": 36.7 + }, + { + "X": 47, + "Group": "Electronics", + "ColorVal": 52.7 + }, + { + "X": 76.5, + "Group": "Clothing", + "ColorVal": 38.9 + }, + { + "X": 75.2, + "Group": "Food", + "ColorVal": 30.6 + }, + { + "X": 8.2, + "Group": "Books", + "ColorVal": 38 + }, + { + "X": 46.5, + "Group": "Sports", + "ColorVal": 48.7 + }, + { + "X": 78.7, + "Group": "Electronics", + "ColorVal": 70 + }, + { + "X": 79.9, + "Group": "Clothing", + "ColorVal": 75.3 + }, + { + "X": 25.2, + "Group": "Food", + "ColorVal": 64.7 + }, + { + "X": 25.2, + "Group": "Books", + "ColorVal": 64.9 + }, + { + "X": 0.1, + "Group": "Sports", + "ColorVal": 86.6 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/scatter-plot/20-card23.flint.json b/test-harness/excel/evaluations/inputs/scatter-plot/20-card23.flint.json new file mode 100644 index 00000000..6005dc74 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/scatter-plot/20-card23.flint.json @@ -0,0 +1,148 @@ +{ + "semantic_types": { + "X": "Quantity", + "Group": "Category", + "Size": "Quantity" + }, + "chart_spec": { + "chartType": "Scatter Plot", + "encodings": { + "x": "X", + "y": "Group", + "size": "Size" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 25.4, + "Group": "Electronics", + "Size": 20.9 + }, + { + "X": 0.4, + "Group": "Clothing", + "Size": 91 + }, + { + "X": 10.4, + "Group": "Food", + "Size": 8.3 + }, + { + "X": 81.2, + "Group": "Books", + "Size": 39.2 + }, + { + "X": 59.1, + "Group": "Sports", + "Size": 52.4 + }, + { + "X": 99.3, + "Group": "Electronics", + "Size": 16.7 + }, + { + "X": 92.7, + "Group": "Clothing", + "Size": 49.9 + }, + { + "X": 17.2, + "Group": "Food", + "Size": 34 + }, + { + "X": 99.3, + "Group": "Books", + "Size": 92.6 + }, + { + "X": 89.8, + "Group": "Sports", + "Size": 55.5 + }, + { + "X": 41.9, + "Group": "Electronics", + "Size": 73.8 + }, + { + "X": 97.9, + "Group": "Clothing", + "Size": 13.7 + }, + { + "X": 71.6, + "Group": "Food", + "Size": 62.1 + }, + { + "X": 13.8, + "Group": "Books", + "Size": 21.3 + }, + { + "X": 50.5, + "Group": "Sports", + "Size": 66.6 + }, + { + "X": 86.2, + "Group": "Electronics", + "Size": 41.2 + }, + { + "X": 19.9, + "Group": "Clothing", + "Size": 54.3 + }, + { + "X": 24.1, + "Group": "Food", + "Size": 19.6 + }, + { + "X": 40.9, + "Group": "Books", + "Size": 61.4 + }, + { + "X": 0.4, + "Group": "Sports", + "Size": 7.6 + }, + { + "X": 5.4, + "Group": "Electronics", + "Size": 25.4 + }, + { + "X": 4.7, + "Group": "Clothing", + "Size": 52.8 + }, + { + "X": 56.7, + "Group": "Food", + "Size": 72.3 + }, + { + "X": 76.2, + "Group": "Books", + "Size": 28.8 + }, + { + "X": 21.1, + "Group": "Sports", + "Size": 63.5 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/scatter-plot/21-card59.flint.json b/test-harness/excel/evaluations/inputs/scatter-plot/21-card59.flint.json new file mode 100644 index 00000000..3257df90 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/scatter-plot/21-card59.flint.json @@ -0,0 +1,261 @@ +{ + "semantic_types": { + "X": "Quantity", + "Group": "Category" + }, + "chart_spec": { + "chartType": "Scatter Plot", + "encodings": { + "x": "X", + "y": "Group" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 95.1, + "Group": "James Walker" + }, + { + "X": 67.9, + "Group": "Paul Wilson" + }, + { + "X": 28.4, + "Group": "Jessica Martin" + }, + { + "X": 42.2, + "Group": "Christopher Moore" + }, + { + "X": 50.4, + "Group": "Betty Wilson" + }, + { + "X": 97.7, + "Group": "Steven Lewis" + }, + { + "X": 35.8, + "Group": "Karen Lopez" + }, + { + "X": 25.8, + "Group": "Sandra Wright" + }, + { + "X": 46.5, + "Group": "Daniel King" + }, + { + "X": 89.6, + "Group": "Mark Taylor" + }, + { + "X": 82.7, + "Group": "Sandra Thomas" + }, + { + "X": 99.5, + "Group": "Karen Rodriguez" + }, + { + "X": 54.1, + "Group": "Patricia Jackson" + }, + { + "X": 77.1, + "Group": "Donna Hill" + }, + { + "X": 97.7, + "Group": "Donna White" + }, + { + "X": 24, + "Group": "Michael Brown" + }, + { + "X": 27.4, + "Group": "Elizabeth Robinson" + }, + { + "X": 43.3, + "Group": "Mary Jones" + }, + { + "X": 58.5, + "Group": "Richard Rodriguez" + }, + { + "X": 11.1, + "Group": "Christopher Clark" + }, + { + "X": 18.3, + "Group": "Christopher Lopez" + }, + { + "X": 65.6, + "Group": "Susan Ramirez" + }, + { + "X": 24.3, + "Group": "Steven Wilson" + }, + { + "X": 13.9, + "Group": "Paul Anderson" + }, + { + "X": 31.7, + "Group": "Joseph Rodriguez" + }, + { + "X": 8.9, + "Group": "Elizabeth Wright" + }, + { + "X": 88.6, + "Group": "Kimberly Jackson" + }, + { + "X": 33.6, + "Group": "Betty Hernandez" + }, + { + "X": 46.4, + "Group": "David King" + }, + { + "X": 6.7, + "Group": "Matthew Lopez" + }, + { + "X": 1.1, + "Group": "Susan Hernandez" + }, + { + "X": 51.1, + "Group": "Jennifer Lee" + }, + { + "X": 41, + "Group": "Richard Flores" + }, + { + "X": 38.5, + "Group": "John Anderson" + }, + { + "X": 15.9, + "Group": "Kimberly Wright" + }, + { + "X": 71.2, + "Group": "Joseph Williams" + }, + { + "X": 74.3, + "Group": "Lisa Torres" + }, + { + "X": 55.1, + "Group": "Andrew Rodriguez" + }, + { + "X": 6.9, + "Group": "Karen Johnson" + }, + { + "X": 32.9, + "Group": "Steven Jones" + }, + { + "X": 28.1, + "Group": "Joshua Ramirez" + }, + { + "X": 3.8, + "Group": "Emily Martinez" + }, + { + "X": 25.1, + "Group": "Robert Walker" + }, + { + "X": 31, + "Group": "Robert Lewis" + }, + { + "X": 29.8, + "Group": "Sandra Lopez" + }, + { + "X": 92, + "Group": "Nancy Miller" + }, + { + "X": 10.6, + "Group": "Christopher Sanchez" + }, + { + "X": 87.9, + "Group": "Daniel Flores" + }, + { + "X": 80.4, + "Group": "Mary Walker" + }, + { + "X": 22.1, + "Group": "Anthony Ramirez" + }, + { + "X": 24.8, + "Group": "Anthony Hill" + }, + { + "X": 92.2, + "Group": "Matthew Miller" + }, + { + "X": 9.2, + "Group": "Andrew King" + }, + { + "X": 41.4, + "Group": "William Perez" + }, + { + "X": 10.3, + "Group": "William Martinez" + }, + { + "X": 37.4, + "Group": "Margaret Garcia" + }, + { + "X": 74.4, + "Group": "Barbara Anderson" + }, + { + "X": 94.8, + "Group": "Thomas Smith" + }, + { + "X": 47.2, + "Group": "Kimberly Thomas" + }, + { + "X": 37.6, + "Group": "Karen Garcia" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/scatter-plot/22-card5.flint.json b/test-harness/excel/evaluations/inputs/scatter-plot/22-card5.flint.json new file mode 100644 index 00000000..001853dc --- /dev/null +++ b/test-harness/excel/evaluations/inputs/scatter-plot/22-card5.flint.json @@ -0,0 +1,123 @@ +{ + "semantic_types": { + "Category": "Category", + "Group": "Category", + "Size": "Quantity" + }, + "chart_spec": { + "chartType": "Scatter Plot", + "encodings": { + "x": "Category", + "y": "Group", + "size": "Size" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Electronics", + "Group": "China", + "Size": 681 + }, + { + "Category": "Electronics", + "Group": "Japan", + "Size": 802 + }, + { + "Category": "Electronics", + "Group": "Germany", + "Size": 852 + }, + { + "Category": "Electronics", + "Group": "UK", + "Size": 860 + }, + { + "Category": "Clothing", + "Group": "USA", + "Size": 510 + }, + { + "Category": "Clothing", + "Group": "China", + "Size": 508 + }, + { + "Category": "Clothing", + "Group": "Japan", + "Size": 778 + }, + { + "Category": "Clothing", + "Group": "Germany", + "Size": 908 + }, + { + "Category": "Clothing", + "Group": "UK", + "Size": 189 + }, + { + "Category": "Clothing", + "Group": "France", + "Size": 744 + }, + { + "Category": "Food", + "Group": "Japan", + "Size": 728 + }, + { + "Category": "Food", + "Group": "Germany", + "Size": 472 + }, + { + "Category": "Food", + "Group": "UK", + "Size": 343 + }, + { + "Category": "Books", + "Group": "USA", + "Size": 296 + }, + { + "Category": "Books", + "Group": "Germany", + "Size": 324 + }, + { + "Category": "Books", + "Group": "UK", + "Size": 510 + }, + { + "Category": "Books", + "Group": "France", + "Size": 898 + }, + { + "Category": "Sports", + "Group": "China", + "Size": 238 + }, + { + "Category": "Sports", + "Group": "Japan", + "Size": 160 + }, + { + "Category": "Sports", + "Group": "France", + "Size": 996 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/scatter-plot/23-card4.flint.json b/test-harness/excel/evaluations/inputs/scatter-plot/23-card4.flint.json new file mode 100644 index 00000000..ffc4e3e8 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/scatter-plot/23-card4.flint.json @@ -0,0 +1,78 @@ +{ + "semantic_types": { + "Category": "Category", + "Group": "Category", + "ColorVal": "Quantity" + }, + "chart_spec": { + "chartType": "Scatter Plot", + "encodings": { + "x": "Category", + "y": "Group", + "color": "ColorVal" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Electronics", + "Group": "USA", + "ColorVal": 948 + }, + { + "Category": "Electronics", + "Group": "Japan", + "ColorVal": 109 + }, + { + "Category": "Clothing", + "Group": "China", + "ColorVal": 459 + }, + { + "Category": "Clothing", + "Group": "Japan", + "ColorVal": 385 + }, + { + "Category": "Clothing", + "Group": "Germany", + "ColorVal": 901 + }, + { + "Category": "Books", + "Group": "USA", + "ColorVal": 974 + }, + { + "Category": "Books", + "Group": "China", + "ColorVal": 678 + }, + { + "Category": "Books", + "Group": "Japan", + "ColorVal": 193 + }, + { + "Category": "Books", + "Group": "Germany", + "ColorVal": 992 + }, + { + "Category": "Sports", + "Group": "USA", + "ColorVal": 892 + }, + { + "Category": "Sports", + "Group": "Germany", + "ColorVal": 776 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/scatter-plot/24-card15.flint.json b/test-harness/excel/evaluations/inputs/scatter-plot/24-card15.flint.json new file mode 100644 index 00000000..f36b61a9 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/scatter-plot/24-card15.flint.json @@ -0,0 +1,688 @@ +{ + "semantic_types": { + "Category": "Category", + "Group": "Category", + "Size": "Quantity" + }, + "chart_spec": { + "chartType": "Scatter Plot", + "encodings": { + "x": "Category", + "y": "Group", + "size": "Size" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Electronics", + "Group": "USA", + "Size": 877 + }, + { + "Category": "Electronics", + "Group": "Japan", + "Size": 702 + }, + { + "Category": "Electronics", + "Group": "Germany", + "Size": 376 + }, + { + "Category": "Electronics", + "Group": "UK", + "Size": 465 + }, + { + "Category": "Electronics", + "Group": "France", + "Size": 239 + }, + { + "Category": "Electronics", + "Group": "Brazil", + "Size": 372 + }, + { + "Category": "Electronics", + "Group": "Australia", + "Size": 565 + }, + { + "Category": "Electronics", + "Group": "Mexico", + "Size": 587 + }, + { + "Category": "Clothing", + "Group": "USA", + "Size": 325 + }, + { + "Category": "Clothing", + "Group": "China", + "Size": 251 + }, + { + "Category": "Clothing", + "Group": "Japan", + "Size": 529 + }, + { + "Category": "Clothing", + "Group": "France", + "Size": 558 + }, + { + "Category": "Clothing", + "Group": "India", + "Size": 681 + }, + { + "Category": "Clothing", + "Group": "Brazil", + "Size": 327 + }, + { + "Category": "Clothing", + "Group": "Canada", + "Size": 484 + }, + { + "Category": "Clothing", + "Group": "Australia", + "Size": 815 + }, + { + "Category": "Clothing", + "Group": "South Korea", + "Size": 856 + }, + { + "Category": "Clothing", + "Group": "Mexico", + "Size": 152 + }, + { + "Category": "Food", + "Group": "USA", + "Size": 188 + }, + { + "Category": "Food", + "Group": "Japan", + "Size": 970 + }, + { + "Category": "Food", + "Group": "Australia", + "Size": 457 + }, + { + "Category": "Food", + "Group": "South Korea", + "Size": 263 + }, + { + "Category": "Food", + "Group": "Mexico", + "Size": 634 + }, + { + "Category": "Books", + "Group": "USA", + "Size": 760 + }, + { + "Category": "Books", + "Group": "China", + "Size": 207 + }, + { + "Category": "Books", + "Group": "Japan", + "Size": 691 + }, + { + "Category": "Books", + "Group": "Germany", + "Size": 515 + }, + { + "Category": "Books", + "Group": "UK", + "Size": 668 + }, + { + "Category": "Books", + "Group": "France", + "Size": 401 + }, + { + "Category": "Books", + "Group": "Brazil", + "Size": 506 + }, + { + "Category": "Books", + "Group": "Canada", + "Size": 682 + }, + { + "Category": "Books", + "Group": "Australia", + "Size": 220 + }, + { + "Category": "Books", + "Group": "South Korea", + "Size": 118 + }, + { + "Category": "Books", + "Group": "Mexico", + "Size": 205 + }, + { + "Category": "Sports", + "Group": "USA", + "Size": 788 + }, + { + "Category": "Sports", + "Group": "China", + "Size": 694 + }, + { + "Category": "Sports", + "Group": "Japan", + "Size": 323 + }, + { + "Category": "Sports", + "Group": "Germany", + "Size": 442 + }, + { + "Category": "Sports", + "Group": "UK", + "Size": 181 + }, + { + "Category": "Sports", + "Group": "India", + "Size": 301 + }, + { + "Category": "Sports", + "Group": "Brazil", + "Size": 960 + }, + { + "Category": "Sports", + "Group": "Canada", + "Size": 613 + }, + { + "Category": "Sports", + "Group": "Australia", + "Size": 949 + }, + { + "Category": "Sports", + "Group": "South Korea", + "Size": 940 + }, + { + "Category": "Sports", + "Group": "Mexico", + "Size": 549 + }, + { + "Category": "Home", + "Group": "China", + "Size": 311 + }, + { + "Category": "Home", + "Group": "UK", + "Size": 523 + }, + { + "Category": "Home", + "Group": "France", + "Size": 482 + }, + { + "Category": "Home", + "Group": "Canada", + "Size": 501 + }, + { + "Category": "Home", + "Group": "Australia", + "Size": 501 + }, + { + "Category": "Home", + "Group": "South Korea", + "Size": 535 + }, + { + "Category": "Home", + "Group": "Mexico", + "Size": 804 + }, + { + "Category": "Garden", + "Group": "China", + "Size": 142 + }, + { + "Category": "Garden", + "Group": "Japan", + "Size": 250 + }, + { + "Category": "Garden", + "Group": "Germany", + "Size": 392 + }, + { + "Category": "Garden", + "Group": "UK", + "Size": 158 + }, + { + "Category": "Garden", + "Group": "Canada", + "Size": 343 + }, + { + "Category": "Garden", + "Group": "Australia", + "Size": 193 + }, + { + "Category": "Garden", + "Group": "South Korea", + "Size": 815 + }, + { + "Category": "Garden", + "Group": "Mexico", + "Size": 324 + }, + { + "Category": "Auto", + "Group": "USA", + "Size": 167 + }, + { + "Category": "Auto", + "Group": "China", + "Size": 355 + }, + { + "Category": "Auto", + "Group": "Germany", + "Size": 742 + }, + { + "Category": "Auto", + "Group": "UK", + "Size": 163 + }, + { + "Category": "Auto", + "Group": "France", + "Size": 524 + }, + { + "Category": "Auto", + "Group": "India", + "Size": 912 + }, + { + "Category": "Auto", + "Group": "Brazil", + "Size": 376 + }, + { + "Category": "Auto", + "Group": "Canada", + "Size": 984 + }, + { + "Category": "Auto", + "Group": "South Korea", + "Size": 668 + }, + { + "Category": "Health", + "Group": "China", + "Size": 192 + }, + { + "Category": "Health", + "Group": "Germany", + "Size": 465 + }, + { + "Category": "Health", + "Group": "UK", + "Size": 639 + }, + { + "Category": "Health", + "Group": "France", + "Size": 797 + }, + { + "Category": "Health", + "Group": "Brazil", + "Size": 230 + }, + { + "Category": "Health", + "Group": "Canada", + "Size": 696 + }, + { + "Category": "Health", + "Group": "Australia", + "Size": 314 + }, + { + "Category": "Health", + "Group": "Mexico", + "Size": 770 + }, + { + "Category": "Beauty", + "Group": "USA", + "Size": 326 + }, + { + "Category": "Beauty", + "Group": "Japan", + "Size": 393 + }, + { + "Category": "Beauty", + "Group": "UK", + "Size": 739 + }, + { + "Category": "Beauty", + "Group": "France", + "Size": 109 + }, + { + "Category": "Beauty", + "Group": "Brazil", + "Size": 600 + }, + { + "Category": "Beauty", + "Group": "Canada", + "Size": 640 + }, + { + "Category": "Beauty", + "Group": "Australia", + "Size": 170 + }, + { + "Category": "Beauty", + "Group": "South Korea", + "Size": 912 + }, + { + "Category": "Beauty", + "Group": "Mexico", + "Size": 341 + }, + { + "Category": "Toys", + "Group": "USA", + "Size": 886 + }, + { + "Category": "Toys", + "Group": "China", + "Size": 683 + }, + { + "Category": "Toys", + "Group": "UK", + "Size": 513 + }, + { + "Category": "Toys", + "Group": "India", + "Size": 319 + }, + { + "Category": "Toys", + "Group": "Brazil", + "Size": 396 + }, + { + "Category": "Toys", + "Group": "Canada", + "Size": 722 + }, + { + "Category": "Toys", + "Group": "Australia", + "Size": 910 + }, + { + "Category": "Music", + "Group": "USA", + "Size": 820 + }, + { + "Category": "Music", + "Group": "China", + "Size": 674 + }, + { + "Category": "Music", + "Group": "Japan", + "Size": 568 + }, + { + "Category": "Music", + "Group": "Germany", + "Size": 990 + }, + { + "Category": "Music", + "Group": "UK", + "Size": 885 + }, + { + "Category": "Music", + "Group": "India", + "Size": 625 + }, + { + "Category": "Music", + "Group": "Brazil", + "Size": 682 + }, + { + "Category": "Music", + "Group": "Canada", + "Size": 185 + }, + { + "Category": "Music", + "Group": "Australia", + "Size": 109 + }, + { + "Category": "Music", + "Group": "Mexico", + "Size": 663 + }, + { + "Category": "Movies", + "Group": "USA", + "Size": 420 + }, + { + "Category": "Movies", + "Group": "China", + "Size": 203 + }, + { + "Category": "Movies", + "Group": "Japan", + "Size": 735 + }, + { + "Category": "Movies", + "Group": "Germany", + "Size": 508 + }, + { + "Category": "Movies", + "Group": "UK", + "Size": 385 + }, + { + "Category": "Movies", + "Group": "France", + "Size": 160 + }, + { + "Category": "Movies", + "Group": "India", + "Size": 340 + }, + { + "Category": "Movies", + "Group": "Brazil", + "Size": 706 + }, + { + "Category": "Movies", + "Group": "Canada", + "Size": 520 + }, + { + "Category": "Movies", + "Group": "Australia", + "Size": 817 + }, + { + "Category": "Movies", + "Group": "South Korea", + "Size": 527 + }, + { + "Category": "Movies", + "Group": "Mexico", + "Size": 433 + }, + { + "Category": "Software", + "Group": "USA", + "Size": 376 + }, + { + "Category": "Software", + "Group": "Germany", + "Size": 375 + }, + { + "Category": "Software", + "Group": "UK", + "Size": 998 + }, + { + "Category": "Software", + "Group": "France", + "Size": 662 + }, + { + "Category": "Software", + "Group": "India", + "Size": 974 + }, + { + "Category": "Software", + "Group": "Brazil", + "Size": 245 + }, + { + "Category": "Software", + "Group": "Canada", + "Size": 564 + }, + { + "Category": "Software", + "Group": "Australia", + "Size": 761 + }, + { + "Category": "Software", + "Group": "South Korea", + "Size": 518 + }, + { + "Category": "Games", + "Group": "China", + "Size": 922 + }, + { + "Category": "Games", + "Group": "Japan", + "Size": 637 + }, + { + "Category": "Games", + "Group": "Germany", + "Size": 619 + }, + { + "Category": "Games", + "Group": "UK", + "Size": 335 + }, + { + "Category": "Games", + "Group": "France", + "Size": 311 + }, + { + "Category": "Games", + "Group": "India", + "Size": 501 + }, + { + "Category": "Games", + "Group": "Brazil", + "Size": 364 + }, + { + "Category": "Games", + "Group": "Australia", + "Size": 280 + }, + { + "Category": "Games", + "Group": "South Korea", + "Size": 289 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/scatter-plot/25-card40.flint.json b/test-harness/excel/evaluations/inputs/scatter-plot/25-card40.flint.json new file mode 100644 index 00000000..0e40a8ea --- /dev/null +++ b/test-harness/excel/evaluations/inputs/scatter-plot/25-card40.flint.json @@ -0,0 +1,223 @@ +{ + "semantic_types": { + "X": "Quantity", + "Y": "Quantity", + "Group": "Category" + }, + "chart_spec": { + "chartType": "Scatter Plot", + "encodings": { + "x": "X", + "y": "Y", + "shape": "Group" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 77.2, + "Y": 46.1, + "Group": "Electronics" + }, + { + "X": 71, + "Y": 32.1, + "Group": "Clothing" + }, + { + "X": 92.6, + "Y": 10.1, + "Group": "Food" + }, + { + "X": 0.5, + "Y": 1.9, + "Group": "Books" + }, + { + "X": 66.1, + "Y": 66.1, + "Group": "Electronics" + }, + { + "X": 6.4, + "Y": 60, + "Group": "Clothing" + }, + { + "X": 15.8, + "Y": 69.4, + "Group": "Food" + }, + { + "X": 2.1, + "Y": 21.6, + "Group": "Books" + }, + { + "X": 66.5, + "Y": 60.8, + "Group": "Electronics" + }, + { + "X": 61.3, + "Y": 61.1, + "Group": "Clothing" + }, + { + "X": 1.9, + "Y": 3, + "Group": "Food" + }, + { + "X": 54.3, + "Y": 65.6, + "Group": "Books" + }, + { + "X": 48, + "Y": 82.6, + "Group": "Electronics" + }, + { + "X": 45.7, + "Y": 7.7, + "Group": "Clothing" + }, + { + "X": 8, + "Y": 95, + "Group": "Food" + }, + { + "X": 35.3, + "Y": 90.8, + "Group": "Books" + }, + { + "X": 40.1, + "Y": 16.6, + "Group": "Electronics" + }, + { + "X": 78.6, + "Y": 59.4, + "Group": "Clothing" + }, + { + "X": 58.1, + "Y": 91, + "Group": "Food" + }, + { + "X": 74.3, + "Y": 19.9, + "Group": "Books" + }, + { + "X": 81, + "Y": 33.7, + "Group": "Electronics" + }, + { + "X": 91.1, + "Y": 32.1, + "Group": "Clothing" + }, + { + "X": 53.7, + "Y": 93.8, + "Group": "Food" + }, + { + "X": 98.2, + "Y": 10.6, + "Group": "Books" + }, + { + "X": 96.2, + "Y": 25.6, + "Group": "Electronics" + }, + { + "X": 94.2, + "Y": 37.3, + "Group": "Clothing" + }, + { + "X": 66.2, + "Y": 85.8, + "Group": "Food" + }, + { + "X": 33.9, + "Y": 33.4, + "Group": "Books" + }, + { + "X": 97.3, + "Y": 93.5, + "Group": "Electronics" + }, + { + "X": 89.1, + "Y": 26.5, + "Group": "Clothing" + }, + { + "X": 94.7, + "Y": 53.5, + "Group": "Food" + }, + { + "X": 10.8, + "Y": 44.1, + "Group": "Books" + }, + { + "X": 16.4, + "Y": 49.8, + "Group": "Electronics" + }, + { + "X": 73.6, + "Y": 66.3, + "Group": "Clothing" + }, + { + "X": 17.6, + "Y": 5.7, + "Group": "Food" + }, + { + "X": 12.2, + "Y": 52, + "Group": "Books" + }, + { + "X": 92.7, + "Y": 39.5, + "Group": "Electronics" + }, + { + "X": 61.5, + "Y": 70, + "Group": "Clothing" + }, + { + "X": 60.8, + "Y": 59.7, + "Group": "Food" + }, + { + "X": 23.7, + "Y": 10.9, + "Group": "Books" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/stacked-bar-chart/00-card4.flint.json b/test-harness/excel/evaluations/inputs/stacked-bar-chart/00-card4.flint.json new file mode 100644 index 00000000..a89a6522 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/stacked-bar-chart/00-card4.flint.json @@ -0,0 +1,83 @@ +{ + "semantic_types": { + "Category": "Category", + "Value": "Quantity", + "Segment": "Category" + }, + "chart_spec": { + "chartType": "Stacked Bar Chart", + "encodings": { + "x": "Category", + "y": "Value", + "color": "Segment" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Laptop", + "Value": 12, + "Segment": "USA" + }, + { + "Category": "Laptop", + "Value": 314, + "Segment": "China" + }, + { + "Category": "Laptop", + "Value": 130, + "Segment": "Japan" + }, + { + "Category": "Phone", + "Value": 733, + "Segment": "USA" + }, + { + "Category": "Phone", + "Value": 558, + "Segment": "China" + }, + { + "Category": "Phone", + "Value": 794, + "Segment": "Japan" + }, + { + "Category": "Tablet", + "Value": 415, + "Segment": "USA" + }, + { + "Category": "Tablet", + "Value": 775, + "Segment": "China" + }, + { + "Category": "Tablet", + "Value": 861, + "Segment": "Japan" + }, + { + "Category": "Desktop", + "Value": 939, + "Segment": "USA" + }, + { + "Category": "Desktop", + "Value": 703, + "Segment": "China" + }, + { + "Category": "Desktop", + "Value": 884, + "Segment": "Japan" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/stacked-bar-chart/01-card15.flint.json b/test-harness/excel/evaluations/inputs/stacked-bar-chart/01-card15.flint.json new file mode 100644 index 00000000..2fce7d56 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/stacked-bar-chart/01-card15.flint.json @@ -0,0 +1,398 @@ +{ + "semantic_types": { + "Category": "Category", + "Value": "Quantity", + "Segment": "Category" + }, + "chart_spec": { + "chartType": "Stacked Bar Chart", + "encodings": { + "x": "Category", + "y": "Value", + "color": "Segment" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Laptop", + "Value": 201, + "Segment": "USA" + }, + { + "Category": "Laptop", + "Value": 915, + "Segment": "China" + }, + { + "Category": "Laptop", + "Value": 695, + "Segment": "Japan" + }, + { + "Category": "Laptop", + "Value": 941, + "Segment": "Germany" + }, + { + "Category": "Laptop", + "Value": 238, + "Segment": "UK" + }, + { + "Category": "Phone", + "Value": 544, + "Segment": "USA" + }, + { + "Category": "Phone", + "Value": 686, + "Segment": "China" + }, + { + "Category": "Phone", + "Value": 375, + "Segment": "Japan" + }, + { + "Category": "Phone", + "Value": 502, + "Segment": "Germany" + }, + { + "Category": "Phone", + "Value": 361, + "Segment": "UK" + }, + { + "Category": "Tablet", + "Value": 797, + "Segment": "USA" + }, + { + "Category": "Tablet", + "Value": 96, + "Segment": "China" + }, + { + "Category": "Tablet", + "Value": 241, + "Segment": "Japan" + }, + { + "Category": "Tablet", + "Value": 392, + "Segment": "Germany" + }, + { + "Category": "Tablet", + "Value": 399, + "Segment": "UK" + }, + { + "Category": "Desktop", + "Value": 786, + "Segment": "USA" + }, + { + "Category": "Desktop", + "Value": 208, + "Segment": "China" + }, + { + "Category": "Desktop", + "Value": 246, + "Segment": "Japan" + }, + { + "Category": "Desktop", + "Value": 74, + "Segment": "Germany" + }, + { + "Category": "Desktop", + "Value": 445, + "Segment": "UK" + }, + { + "Category": "Monitor", + "Value": 496, + "Segment": "USA" + }, + { + "Category": "Monitor", + "Value": 498, + "Segment": "China" + }, + { + "Category": "Monitor", + "Value": 224, + "Segment": "Japan" + }, + { + "Category": "Monitor", + "Value": 650, + "Segment": "Germany" + }, + { + "Category": "Monitor", + "Value": 532, + "Segment": "UK" + }, + { + "Category": "Keyboard", + "Value": 289, + "Segment": "USA" + }, + { + "Category": "Keyboard", + "Value": 215, + "Segment": "China" + }, + { + "Category": "Keyboard", + "Value": 77, + "Segment": "Japan" + }, + { + "Category": "Keyboard", + "Value": 414, + "Segment": "Germany" + }, + { + "Category": "Keyboard", + "Value": 515, + "Segment": "UK" + }, + { + "Category": "Mouse", + "Value": 537, + "Segment": "USA" + }, + { + "Category": "Mouse", + "Value": 674, + "Segment": "China" + }, + { + "Category": "Mouse", + "Value": 311, + "Segment": "Japan" + }, + { + "Category": "Mouse", + "Value": 542, + "Segment": "Germany" + }, + { + "Category": "Mouse", + "Value": 334, + "Segment": "UK" + }, + { + "Category": "Headphones", + "Value": 942, + "Segment": "USA" + }, + { + "Category": "Headphones", + "Value": 547, + "Segment": "China" + }, + { + "Category": "Headphones", + "Value": 289, + "Segment": "Japan" + }, + { + "Category": "Headphones", + "Value": 306, + "Segment": "Germany" + }, + { + "Category": "Headphones", + "Value": 551, + "Segment": "UK" + }, + { + "Category": "Speaker", + "Value": 559, + "Segment": "USA" + }, + { + "Category": "Speaker", + "Value": 982, + "Segment": "China" + }, + { + "Category": "Speaker", + "Value": 854, + "Segment": "Japan" + }, + { + "Category": "Speaker", + "Value": 308, + "Segment": "Germany" + }, + { + "Category": "Speaker", + "Value": 310, + "Segment": "UK" + }, + { + "Category": "Camera", + "Value": 536, + "Segment": "USA" + }, + { + "Category": "Camera", + "Value": 843, + "Segment": "China" + }, + { + "Category": "Camera", + "Value": 122, + "Segment": "Japan" + }, + { + "Category": "Camera", + "Value": 931, + "Segment": "Germany" + }, + { + "Category": "Camera", + "Value": 906, + "Segment": "UK" + }, + { + "Category": "TV", + "Value": 266, + "Segment": "USA" + }, + { + "Category": "TV", + "Value": 809, + "Segment": "China" + }, + { + "Category": "TV", + "Value": 335, + "Segment": "Japan" + }, + { + "Category": "TV", + "Value": 797, + "Segment": "Germany" + }, + { + "Category": "TV", + "Value": 237, + "Segment": "UK" + }, + { + "Category": "Router", + "Value": 155, + "Segment": "USA" + }, + { + "Category": "Router", + "Value": 557, + "Segment": "China" + }, + { + "Category": "Router", + "Value": 752, + "Segment": "Japan" + }, + { + "Category": "Router", + "Value": 150, + "Segment": "Germany" + }, + { + "Category": "Router", + "Value": 830, + "Segment": "UK" + }, + { + "Category": "Printer", + "Value": 422, + "Segment": "USA" + }, + { + "Category": "Printer", + "Value": 766, + "Segment": "China" + }, + { + "Category": "Printer", + "Value": 950, + "Segment": "Japan" + }, + { + "Category": "Printer", + "Value": 890, + "Segment": "Germany" + }, + { + "Category": "Printer", + "Value": 204, + "Segment": "UK" + }, + { + "Category": "Scanner", + "Value": 27, + "Segment": "USA" + }, + { + "Category": "Scanner", + "Value": 310, + "Segment": "China" + }, + { + "Category": "Scanner", + "Value": 51, + "Segment": "Japan" + }, + { + "Category": "Scanner", + "Value": 568, + "Segment": "Germany" + }, + { + "Category": "Scanner", + "Value": 82, + "Segment": "UK" + }, + { + "Category": "SSD", + "Value": 182, + "Segment": "USA" + }, + { + "Category": "SSD", + "Value": 694, + "Segment": "China" + }, + { + "Category": "SSD", + "Value": 653, + "Segment": "Japan" + }, + { + "Category": "SSD", + "Value": 910, + "Segment": "Germany" + }, + { + "Category": "SSD", + "Value": 252, + "Segment": "UK" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/stacked-bar-chart/02-card80.flint.json b/test-harness/excel/evaluations/inputs/stacked-bar-chart/02-card80.flint.json new file mode 100644 index 00000000..dc732429 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/stacked-bar-chart/02-card80.flint.json @@ -0,0 +1,1223 @@ +{ + "semantic_types": { + "Category": "Category", + "Value": "Quantity", + "Segment": "Category" + }, + "chart_spec": { + "chartType": "Stacked Bar Chart", + "encodings": { + "x": "Category", + "y": "Value", + "color": "Segment" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "James Walker", + "Value": 92, + "Segment": "USA" + }, + { + "Category": "James Walker", + "Value": 893, + "Segment": "China" + }, + { + "Category": "James Walker", + "Value": 717, + "Segment": "Japan" + }, + { + "Category": "Paul Wilson", + "Value": 643, + "Segment": "USA" + }, + { + "Category": "Paul Wilson", + "Value": 272, + "Segment": "China" + }, + { + "Category": "Paul Wilson", + "Value": 211, + "Segment": "Japan" + }, + { + "Category": "Jessica Martin", + "Value": 658, + "Segment": "USA" + }, + { + "Category": "Jessica Martin", + "Value": 230, + "Segment": "China" + }, + { + "Category": "Jessica Martin", + "Value": 204, + "Segment": "Japan" + }, + { + "Category": "Christopher Moore", + "Value": 422, + "Segment": "USA" + }, + { + "Category": "Christopher Moore", + "Value": 309, + "Segment": "China" + }, + { + "Category": "Christopher Moore", + "Value": 865, + "Segment": "Japan" + }, + { + "Category": "Betty Wilson", + "Value": 88, + "Segment": "USA" + }, + { + "Category": "Betty Wilson", + "Value": 466, + "Segment": "China" + }, + { + "Category": "Betty Wilson", + "Value": 588, + "Segment": "Japan" + }, + { + "Category": "Steven Lewis", + "Value": 448, + "Segment": "USA" + }, + { + "Category": "Steven Lewis", + "Value": 669, + "Segment": "China" + }, + { + "Category": "Steven Lewis", + "Value": 747, + "Segment": "Japan" + }, + { + "Category": "Karen Lopez", + "Value": 338, + "Segment": "USA" + }, + { + "Category": "Karen Lopez", + "Value": 486, + "Segment": "China" + }, + { + "Category": "Karen Lopez", + "Value": 615, + "Segment": "Japan" + }, + { + "Category": "Sandra Wright", + "Value": 891, + "Segment": "USA" + }, + { + "Category": "Sandra Wright", + "Value": 699, + "Segment": "China" + }, + { + "Category": "Sandra Wright", + "Value": 81, + "Segment": "Japan" + }, + { + "Category": "Daniel King", + "Value": 662, + "Segment": "USA" + }, + { + "Category": "Daniel King", + "Value": 918, + "Segment": "China" + }, + { + "Category": "Daniel King", + "Value": 156, + "Segment": "Japan" + }, + { + "Category": "Mark Taylor", + "Value": 970, + "Segment": "USA" + }, + { + "Category": "Mark Taylor", + "Value": 414, + "Segment": "China" + }, + { + "Category": "Mark Taylor", + "Value": 954, + "Segment": "Japan" + }, + { + "Category": "Sandra Thomas", + "Value": 555, + "Segment": "USA" + }, + { + "Category": "Sandra Thomas", + "Value": 943, + "Segment": "China" + }, + { + "Category": "Sandra Thomas", + "Value": 95, + "Segment": "Japan" + }, + { + "Category": "Karen Rodriguez", + "Value": 206, + "Segment": "USA" + }, + { + "Category": "Karen Rodriguez", + "Value": 918, + "Segment": "China" + }, + { + "Category": "Karen Rodriguez", + "Value": 604, + "Segment": "Japan" + }, + { + "Category": "Patricia Jackson", + "Value": 860, + "Segment": "USA" + }, + { + "Category": "Patricia Jackson", + "Value": 382, + "Segment": "China" + }, + { + "Category": "Patricia Jackson", + "Value": 964, + "Segment": "Japan" + }, + { + "Category": "Donna Hill", + "Value": 584, + "Segment": "USA" + }, + { + "Category": "Donna Hill", + "Value": 982, + "Segment": "China" + }, + { + "Category": "Donna Hill", + "Value": 187, + "Segment": "Japan" + }, + { + "Category": "Donna White", + "Value": 513, + "Segment": "USA" + }, + { + "Category": "Donna White", + "Value": 404, + "Segment": "China" + }, + { + "Category": "Donna White", + "Value": 418, + "Segment": "Japan" + }, + { + "Category": "Michael Brown", + "Value": 76, + "Segment": "USA" + }, + { + "Category": "Michael Brown", + "Value": 277, + "Segment": "China" + }, + { + "Category": "Michael Brown", + "Value": 171, + "Segment": "Japan" + }, + { + "Category": "Elizabeth Robinson", + "Value": 550, + "Segment": "USA" + }, + { + "Category": "Elizabeth Robinson", + "Value": 949, + "Segment": "China" + }, + { + "Category": "Elizabeth Robinson", + "Value": 512, + "Segment": "Japan" + }, + { + "Category": "Mary Jones", + "Value": 443, + "Segment": "USA" + }, + { + "Category": "Mary Jones", + "Value": 124, + "Segment": "China" + }, + { + "Category": "Mary Jones", + "Value": 32, + "Segment": "Japan" + }, + { + "Category": "Richard Rodriguez", + "Value": 91, + "Segment": "USA" + }, + { + "Category": "Richard Rodriguez", + "Value": 237, + "Segment": "China" + }, + { + "Category": "Richard Rodriguez", + "Value": 634, + "Segment": "Japan" + }, + { + "Category": "Christopher Clark", + "Value": 664, + "Segment": "USA" + }, + { + "Category": "Christopher Clark", + "Value": 756, + "Segment": "China" + }, + { + "Category": "Christopher Clark", + "Value": 370, + "Segment": "Japan" + }, + { + "Category": "Christopher Lopez", + "Value": 980, + "Segment": "USA" + }, + { + "Category": "Christopher Lopez", + "Value": 431, + "Segment": "China" + }, + { + "Category": "Christopher Lopez", + "Value": 706, + "Segment": "Japan" + }, + { + "Category": "Susan Ramirez", + "Value": 808, + "Segment": "USA" + }, + { + "Category": "Susan Ramirez", + "Value": 227, + "Segment": "China" + }, + { + "Category": "Susan Ramirez", + "Value": 214, + "Segment": "Japan" + }, + { + "Category": "Steven Wilson", + "Value": 952, + "Segment": "USA" + }, + { + "Category": "Steven Wilson", + "Value": 851, + "Segment": "China" + }, + { + "Category": "Steven Wilson", + "Value": 855, + "Segment": "Japan" + }, + { + "Category": "Paul Anderson", + "Value": 349, + "Segment": "USA" + }, + { + "Category": "Paul Anderson", + "Value": 258, + "Segment": "China" + }, + { + "Category": "Paul Anderson", + "Value": 334, + "Segment": "Japan" + }, + { + "Category": "Joseph Rodriguez", + "Value": 618, + "Segment": "USA" + }, + { + "Category": "Joseph Rodriguez", + "Value": 573, + "Segment": "China" + }, + { + "Category": "Joseph Rodriguez", + "Value": 293, + "Segment": "Japan" + }, + { + "Category": "Elizabeth Wright", + "Value": 864, + "Segment": "USA" + }, + { + "Category": "Elizabeth Wright", + "Value": 654, + "Segment": "China" + }, + { + "Category": "Elizabeth Wright", + "Value": 678, + "Segment": "Japan" + }, + { + "Category": "Kimberly Jackson", + "Value": 341, + "Segment": "USA" + }, + { + "Category": "Kimberly Jackson", + "Value": 306, + "Segment": "China" + }, + { + "Category": "Kimberly Jackson", + "Value": 410, + "Segment": "Japan" + }, + { + "Category": "Betty Hernandez", + "Value": 502, + "Segment": "USA" + }, + { + "Category": "Betty Hernandez", + "Value": 72, + "Segment": "China" + }, + { + "Category": "Betty Hernandez", + "Value": 245, + "Segment": "Japan" + }, + { + "Category": "David King", + "Value": 138, + "Segment": "USA" + }, + { + "Category": "David King", + "Value": 440, + "Segment": "China" + }, + { + "Category": "David King", + "Value": 445, + "Segment": "Japan" + }, + { + "Category": "Matthew Lopez", + "Value": 221, + "Segment": "USA" + }, + { + "Category": "Matthew Lopez", + "Value": 77, + "Segment": "China" + }, + { + "Category": "Matthew Lopez", + "Value": 615, + "Segment": "Japan" + }, + { + "Category": "Susan Hernandez", + "Value": 32, + "Segment": "USA" + }, + { + "Category": "Susan Hernandez", + "Value": 634, + "Segment": "China" + }, + { + "Category": "Susan Hernandez", + "Value": 71, + "Segment": "Japan" + }, + { + "Category": "Jennifer Lee", + "Value": 906, + "Segment": "USA" + }, + { + "Category": "Jennifer Lee", + "Value": 465, + "Segment": "China" + }, + { + "Category": "Jennifer Lee", + "Value": 791, + "Segment": "Japan" + }, + { + "Category": "Richard Flores", + "Value": 342, + "Segment": "USA" + }, + { + "Category": "Richard Flores", + "Value": 336, + "Segment": "China" + }, + { + "Category": "Richard Flores", + "Value": 59, + "Segment": "Japan" + }, + { + "Category": "John Anderson", + "Value": 919, + "Segment": "USA" + }, + { + "Category": "John Anderson", + "Value": 787, + "Segment": "China" + }, + { + "Category": "John Anderson", + "Value": 35, + "Segment": "Japan" + }, + { + "Category": "Kimberly Wright", + "Value": 180, + "Segment": "USA" + }, + { + "Category": "Kimberly Wright", + "Value": 260, + "Segment": "China" + }, + { + "Category": "Kimberly Wright", + "Value": 199, + "Segment": "Japan" + }, + { + "Category": "Joseph Williams", + "Value": 88, + "Segment": "USA" + }, + { + "Category": "Joseph Williams", + "Value": 517, + "Segment": "China" + }, + { + "Category": "Joseph Williams", + "Value": 177, + "Segment": "Japan" + }, + { + "Category": "Lisa Torres", + "Value": 455, + "Segment": "USA" + }, + { + "Category": "Lisa Torres", + "Value": 281, + "Segment": "China" + }, + { + "Category": "Lisa Torres", + "Value": 552, + "Segment": "Japan" + }, + { + "Category": "Andrew Rodriguez", + "Value": 867, + "Segment": "USA" + }, + { + "Category": "Andrew Rodriguez", + "Value": 940, + "Segment": "China" + }, + { + "Category": "Andrew Rodriguez", + "Value": 798, + "Segment": "Japan" + }, + { + "Category": "Karen Johnson", + "Value": 447, + "Segment": "USA" + }, + { + "Category": "Karen Johnson", + "Value": 435, + "Segment": "China" + }, + { + "Category": "Karen Johnson", + "Value": 884, + "Segment": "Japan" + }, + { + "Category": "Steven Jones", + "Value": 261, + "Segment": "USA" + }, + { + "Category": "Steven Jones", + "Value": 865, + "Segment": "China" + }, + { + "Category": "Steven Jones", + "Value": 490, + "Segment": "Japan" + }, + { + "Category": "Joshua Ramirez", + "Value": 888, + "Segment": "USA" + }, + { + "Category": "Joshua Ramirez", + "Value": 690, + "Segment": "China" + }, + { + "Category": "Joshua Ramirez", + "Value": 808, + "Segment": "Japan" + }, + { + "Category": "Emily Martinez", + "Value": 350, + "Segment": "USA" + }, + { + "Category": "Emily Martinez", + "Value": 320, + "Segment": "China" + }, + { + "Category": "Emily Martinez", + "Value": 18, + "Segment": "Japan" + }, + { + "Category": "Robert Walker", + "Value": 950, + "Segment": "USA" + }, + { + "Category": "Robert Walker", + "Value": 854, + "Segment": "China" + }, + { + "Category": "Robert Walker", + "Value": 137, + "Segment": "Japan" + }, + { + "Category": "Robert Lewis", + "Value": 153, + "Segment": "USA" + }, + { + "Category": "Robert Lewis", + "Value": 314, + "Segment": "China" + }, + { + "Category": "Robert Lewis", + "Value": 350, + "Segment": "Japan" + }, + { + "Category": "Sandra Lopez", + "Value": 820, + "Segment": "USA" + }, + { + "Category": "Sandra Lopez", + "Value": 214, + "Segment": "China" + }, + { + "Category": "Sandra Lopez", + "Value": 998, + "Segment": "Japan" + }, + { + "Category": "Nancy Miller", + "Value": 668, + "Segment": "USA" + }, + { + "Category": "Nancy Miller", + "Value": 48, + "Segment": "China" + }, + { + "Category": "Nancy Miller", + "Value": 688, + "Segment": "Japan" + }, + { + "Category": "Christopher Sanchez", + "Value": 791, + "Segment": "USA" + }, + { + "Category": "Christopher Sanchez", + "Value": 540, + "Segment": "China" + }, + { + "Category": "Christopher Sanchez", + "Value": 416, + "Segment": "Japan" + }, + { + "Category": "Daniel Flores", + "Value": 912, + "Segment": "USA" + }, + { + "Category": "Daniel Flores", + "Value": 334, + "Segment": "China" + }, + { + "Category": "Daniel Flores", + "Value": 185, + "Segment": "Japan" + }, + { + "Category": "Mary Walker", + "Value": 14, + "Segment": "USA" + }, + { + "Category": "Mary Walker", + "Value": 792, + "Segment": "China" + }, + { + "Category": "Mary Walker", + "Value": 841, + "Segment": "Japan" + }, + { + "Category": "Anthony Ramirez", + "Value": 79, + "Segment": "USA" + }, + { + "Category": "Anthony Ramirez", + "Value": 874, + "Segment": "China" + }, + { + "Category": "Anthony Ramirez", + "Value": 115, + "Segment": "Japan" + }, + { + "Category": "Anthony Hill", + "Value": 213, + "Segment": "USA" + }, + { + "Category": "Anthony Hill", + "Value": 155, + "Segment": "China" + }, + { + "Category": "Anthony Hill", + "Value": 933, + "Segment": "Japan" + }, + { + "Category": "Matthew Miller", + "Value": 308, + "Segment": "USA" + }, + { + "Category": "Matthew Miller", + "Value": 946, + "Segment": "China" + }, + { + "Category": "Matthew Miller", + "Value": 511, + "Segment": "Japan" + }, + { + "Category": "Andrew King", + "Value": 337, + "Segment": "USA" + }, + { + "Category": "Andrew King", + "Value": 41, + "Segment": "China" + }, + { + "Category": "Andrew King", + "Value": 311, + "Segment": "Japan" + }, + { + "Category": "William Perez", + "Value": 825, + "Segment": "USA" + }, + { + "Category": "William Perez", + "Value": 724, + "Segment": "China" + }, + { + "Category": "William Perez", + "Value": 107, + "Segment": "Japan" + }, + { + "Category": "William Martinez", + "Value": 277, + "Segment": "USA" + }, + { + "Category": "William Martinez", + "Value": 128, + "Segment": "China" + }, + { + "Category": "William Martinez", + "Value": 184, + "Segment": "Japan" + }, + { + "Category": "Margaret Garcia", + "Value": 674, + "Segment": "USA" + }, + { + "Category": "Margaret Garcia", + "Value": 472, + "Segment": "China" + }, + { + "Category": "Margaret Garcia", + "Value": 837, + "Segment": "Japan" + }, + { + "Category": "Barbara Anderson", + "Value": 549, + "Segment": "USA" + }, + { + "Category": "Barbara Anderson", + "Value": 504, + "Segment": "China" + }, + { + "Category": "Barbara Anderson", + "Value": 121, + "Segment": "Japan" + }, + { + "Category": "Thomas Smith", + "Value": 62, + "Segment": "USA" + }, + { + "Category": "Thomas Smith", + "Value": 291, + "Segment": "China" + }, + { + "Category": "Thomas Smith", + "Value": 786, + "Segment": "Japan" + }, + { + "Category": "Kimberly Thomas", + "Value": 744, + "Segment": "USA" + }, + { + "Category": "Kimberly Thomas", + "Value": 911, + "Segment": "China" + }, + { + "Category": "Kimberly Thomas", + "Value": 354, + "Segment": "Japan" + }, + { + "Category": "Karen Garcia", + "Value": 803, + "Segment": "USA" + }, + { + "Category": "Karen Garcia", + "Value": 915, + "Segment": "China" + }, + { + "Category": "Karen Garcia", + "Value": 773, + "Segment": "Japan" + }, + { + "Category": "Sarah Torres", + "Value": 712, + "Segment": "USA" + }, + { + "Category": "Sarah Torres", + "Value": 220, + "Segment": "China" + }, + { + "Category": "Sarah Torres", + "Value": 767, + "Segment": "Japan" + }, + { + "Category": "Emily Hill", + "Value": 438, + "Segment": "USA" + }, + { + "Category": "Emily Hill", + "Value": 514, + "Segment": "China" + }, + { + "Category": "Emily Hill", + "Value": 971, + "Segment": "Japan" + }, + { + "Category": "Sarah Walker", + "Value": 845, + "Segment": "USA" + }, + { + "Category": "Sarah Walker", + "Value": 439, + "Segment": "China" + }, + { + "Category": "Sarah Walker", + "Value": 809, + "Segment": "Japan" + }, + { + "Category": "Michael Clark", + "Value": 379, + "Segment": "USA" + }, + { + "Category": "Michael Clark", + "Value": 775, + "Segment": "China" + }, + { + "Category": "Michael Clark", + "Value": 497, + "Segment": "Japan" + }, + { + "Category": "Joshua Wright", + "Value": 437, + "Segment": "USA" + }, + { + "Category": "Joshua Wright", + "Value": 796, + "Segment": "China" + }, + { + "Category": "Joshua Wright", + "Value": 271, + "Segment": "Japan" + }, + { + "Category": "Andrew Walker", + "Value": 371, + "Segment": "USA" + }, + { + "Category": "Andrew Walker", + "Value": 651, + "Segment": "China" + }, + { + "Category": "Andrew Walker", + "Value": 813, + "Segment": "Japan" + }, + { + "Category": "Nancy Young", + "Value": 946, + "Segment": "USA" + }, + { + "Category": "Nancy Young", + "Value": 298, + "Segment": "China" + }, + { + "Category": "Nancy Young", + "Value": 632, + "Segment": "Japan" + }, + { + "Category": "John Lewis", + "Value": 210, + "Segment": "USA" + }, + { + "Category": "John Lewis", + "Value": 382, + "Segment": "China" + }, + { + "Category": "John Lewis", + "Value": 674, + "Segment": "Japan" + }, + { + "Category": "John Brown", + "Value": 551, + "Segment": "USA" + }, + { + "Category": "John Brown", + "Value": 592, + "Segment": "China" + }, + { + "Category": "John Brown", + "Value": 439, + "Segment": "Japan" + }, + { + "Category": "Anthony Thomas", + "Value": 723, + "Segment": "USA" + }, + { + "Category": "Anthony Thomas", + "Value": 334, + "Segment": "China" + }, + { + "Category": "Anthony Thomas", + "Value": 883, + "Segment": "Japan" + }, + { + "Category": "Joshua Moore", + "Value": 944, + "Segment": "USA" + }, + { + "Category": "Joshua Moore", + "Value": 209, + "Segment": "China" + }, + { + "Category": "Joshua Moore", + "Value": 954, + "Segment": "Japan" + }, + { + "Category": "John Hernandez", + "Value": 256, + "Segment": "USA" + }, + { + "Category": "John Hernandez", + "Value": 592, + "Segment": "China" + }, + { + "Category": "John Hernandez", + "Value": 905, + "Segment": "Japan" + }, + { + "Category": "James Perez", + "Value": 689, + "Segment": "USA" + }, + { + "Category": "James Perez", + "Value": 295, + "Segment": "China" + }, + { + "Category": "James Perez", + "Value": 647, + "Segment": "Japan" + }, + { + "Category": "James Scott", + "Value": 408, + "Segment": "USA" + }, + { + "Category": "James Scott", + "Value": 758, + "Segment": "China" + }, + { + "Category": "James Scott", + "Value": 967, + "Segment": "Japan" + }, + { + "Category": "Matthew Sanchez", + "Value": 493, + "Segment": "USA" + }, + { + "Category": "Matthew Sanchez", + "Value": 519, + "Segment": "China" + }, + { + "Category": "Matthew Sanchez", + "Value": 232, + "Segment": "Japan" + }, + { + "Category": "Joseph Sanchez", + "Value": 784, + "Segment": "USA" + }, + { + "Category": "Joseph Sanchez", + "Value": 602, + "Segment": "China" + }, + { + "Category": "Joseph Sanchez", + "Value": 934, + "Segment": "Japan" + }, + { + "Category": "Paul Perez", + "Value": 602, + "Segment": "USA" + }, + { + "Category": "Paul Perez", + "Value": 613, + "Segment": "China" + }, + { + "Category": "Paul Perez", + "Value": 344, + "Segment": "Japan" + }, + { + "Category": "Joshua Rodriguez", + "Value": 74, + "Segment": "USA" + }, + { + "Category": "Joshua Rodriguez", + "Value": 55, + "Segment": "China" + }, + { + "Category": "Joshua Rodriguez", + "Value": 657, + "Segment": "Japan" + }, + { + "Category": "Anthony Sanchez", + "Value": 373, + "Segment": "USA" + }, + { + "Category": "Anthony Sanchez", + "Value": 801, + "Segment": "China" + }, + { + "Category": "Anthony Sanchez", + "Value": 209, + "Segment": "Japan" + }, + { + "Category": "Linda King", + "Value": 76, + "Segment": "USA" + }, + { + "Category": "Linda King", + "Value": 713, + "Segment": "China" + }, + { + "Category": "Linda King", + "Value": 156, + "Segment": "Japan" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/stacked-bar-chart/03-card6.flint.json b/test-harness/excel/evaluations/inputs/stacked-bar-chart/03-card6.flint.json new file mode 100644 index 00000000..43493965 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/stacked-bar-chart/03-card6.flint.json @@ -0,0 +1,143 @@ +{ + "semantic_types": { + "Category": "Category", + "Value": "Quantity", + "ColorVal": "Rank" + }, + "chart_spec": { + "chartType": "Stacked Bar Chart", + "encodings": { + "x": "Category", + "y": "Value", + "color": "ColorVal" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Laptop", + "Value": 628, + "ColorVal": 1 + }, + { + "Category": "Laptop", + "Value": 621, + "ColorVal": 2 + }, + { + "Category": "Laptop", + "Value": 178, + "ColorVal": 3 + }, + { + "Category": "Laptop", + "Value": 771, + "ColorVal": 4 + }, + { + "Category": "Phone", + "Value": 55, + "ColorVal": 1 + }, + { + "Category": "Phone", + "Value": 607, + "ColorVal": 2 + }, + { + "Category": "Phone", + "Value": 379, + "ColorVal": 3 + }, + { + "Category": "Phone", + "Value": 187, + "ColorVal": 4 + }, + { + "Category": "Tablet", + "Value": 571, + "ColorVal": 1 + }, + { + "Category": "Tablet", + "Value": 860, + "ColorVal": 2 + }, + { + "Category": "Tablet", + "Value": 656, + "ColorVal": 3 + }, + { + "Category": "Tablet", + "Value": 949, + "ColorVal": 4 + }, + { + "Category": "Desktop", + "Value": 787, + "ColorVal": 1 + }, + { + "Category": "Desktop", + "Value": 363, + "ColorVal": 2 + }, + { + "Category": "Desktop", + "Value": 255, + "ColorVal": 3 + }, + { + "Category": "Desktop", + "Value": 789, + "ColorVal": 4 + }, + { + "Category": "Monitor", + "Value": 724, + "ColorVal": 1 + }, + { + "Category": "Monitor", + "Value": 162, + "ColorVal": 2 + }, + { + "Category": "Monitor", + "Value": 951, + "ColorVal": 3 + }, + { + "Category": "Monitor", + "Value": 148, + "ColorVal": 4 + }, + { + "Category": "Keyboard", + "Value": 42, + "ColorVal": 1 + }, + { + "Category": "Keyboard", + "Value": 319, + "ColorVal": 2 + }, + { + "Category": "Keyboard", + "Value": 96, + "ColorVal": 3 + }, + { + "Category": "Keyboard", + "Value": 435, + "ColorVal": 4 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/stacked-bar-chart/04-card5.flint.json b/test-harness/excel/evaluations/inputs/stacked-bar-chart/04-card5.flint.json new file mode 100644 index 00000000..f54c635d --- /dev/null +++ b/test-harness/excel/evaluations/inputs/stacked-bar-chart/04-card5.flint.json @@ -0,0 +1,773 @@ +{ + "semantic_types": { + "Category": "Category", + "Value": "Quantity", + "ColorVal": "Rank" + }, + "chart_spec": { + "chartType": "Stacked Bar Chart", + "encodings": { + "x": "Category", + "y": "Value", + "color": "ColorVal" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Laptop", + "Value": 278, + "ColorVal": 1 + }, + { + "Category": "Laptop", + "Value": 373, + "ColorVal": 2 + }, + { + "Category": "Laptop", + "Value": 137, + "ColorVal": 3 + }, + { + "Category": "Laptop", + "Value": 308, + "ColorVal": 4 + }, + { + "Category": "Laptop", + "Value": 88, + "ColorVal": 5 + }, + { + "Category": "Laptop", + "Value": 29, + "ColorVal": 6 + }, + { + "Category": "Laptop", + "Value": 766, + "ColorVal": 7 + }, + { + "Category": "Laptop", + "Value": 349, + "ColorVal": 8 + }, + { + "Category": "Laptop", + "Value": 566, + "ColorVal": 9 + }, + { + "Category": "Laptop", + "Value": 849, + "ColorVal": 10 + }, + { + "Category": "Laptop", + "Value": 990, + "ColorVal": 11 + }, + { + "Category": "Laptop", + "Value": 844, + "ColorVal": 12 + }, + { + "Category": "Laptop", + "Value": 600, + "ColorVal": 13 + }, + { + "Category": "Laptop", + "Value": 235, + "ColorVal": 14 + }, + { + "Category": "Laptop", + "Value": 574, + "ColorVal": 15 + }, + { + "Category": "Laptop", + "Value": 329, + "ColorVal": 16 + }, + { + "Category": "Laptop", + "Value": 27, + "ColorVal": 17 + }, + { + "Category": "Laptop", + "Value": 353, + "ColorVal": 18 + }, + { + "Category": "Laptop", + "Value": 797, + "ColorVal": 19 + }, + { + "Category": "Laptop", + "Value": 807, + "ColorVal": 20 + }, + { + "Category": "Laptop", + "Value": 159, + "ColorVal": 21 + }, + { + "Category": "Laptop", + "Value": 426, + "ColorVal": 22 + }, + { + "Category": "Laptop", + "Value": 423, + "ColorVal": 23 + }, + { + "Category": "Laptop", + "Value": 158, + "ColorVal": 24 + }, + { + "Category": "Laptop", + "Value": 396, + "ColorVal": 25 + }, + { + "Category": "Laptop", + "Value": 570, + "ColorVal": 26 + }, + { + "Category": "Laptop", + "Value": 334, + "ColorVal": 27 + }, + { + "Category": "Laptop", + "Value": 489, + "ColorVal": 28 + }, + { + "Category": "Laptop", + "Value": 349, + "ColorVal": 29 + }, + { + "Category": "Laptop", + "Value": 314, + "ColorVal": 30 + }, + { + "Category": "Phone", + "Value": 144, + "ColorVal": 1 + }, + { + "Category": "Phone", + "Value": 903, + "ColorVal": 2 + }, + { + "Category": "Phone", + "Value": 775, + "ColorVal": 3 + }, + { + "Category": "Phone", + "Value": 243, + "ColorVal": 4 + }, + { + "Category": "Phone", + "Value": 852, + "ColorVal": 5 + }, + { + "Category": "Phone", + "Value": 147, + "ColorVal": 6 + }, + { + "Category": "Phone", + "Value": 984, + "ColorVal": 7 + }, + { + "Category": "Phone", + "Value": 620, + "ColorVal": 8 + }, + { + "Category": "Phone", + "Value": 664, + "ColorVal": 9 + }, + { + "Category": "Phone", + "Value": 602, + "ColorVal": 10 + }, + { + "Category": "Phone", + "Value": 342, + "ColorVal": 11 + }, + { + "Category": "Phone", + "Value": 292, + "ColorVal": 12 + }, + { + "Category": "Phone", + "Value": 276, + "ColorVal": 13 + }, + { + "Category": "Phone", + "Value": 958, + "ColorVal": 14 + }, + { + "Category": "Phone", + "Value": 699, + "ColorVal": 15 + }, + { + "Category": "Phone", + "Value": 376, + "ColorVal": 16 + }, + { + "Category": "Phone", + "Value": 806, + "ColorVal": 17 + }, + { + "Category": "Phone", + "Value": 947, + "ColorVal": 18 + }, + { + "Category": "Phone", + "Value": 174, + "ColorVal": 19 + }, + { + "Category": "Phone", + "Value": 162, + "ColorVal": 20 + }, + { + "Category": "Phone", + "Value": 379, + "ColorVal": 21 + }, + { + "Category": "Phone", + "Value": 813, + "ColorVal": 22 + }, + { + "Category": "Phone", + "Value": 865, + "ColorVal": 23 + }, + { + "Category": "Phone", + "Value": 735, + "ColorVal": 24 + }, + { + "Category": "Phone", + "Value": 67, + "ColorVal": 25 + }, + { + "Category": "Phone", + "Value": 195, + "ColorVal": 26 + }, + { + "Category": "Phone", + "Value": 388, + "ColorVal": 27 + }, + { + "Category": "Phone", + "Value": 228, + "ColorVal": 28 + }, + { + "Category": "Phone", + "Value": 43, + "ColorVal": 29 + }, + { + "Category": "Phone", + "Value": 871, + "ColorVal": 30 + }, + { + "Category": "Tablet", + "Value": 762, + "ColorVal": 1 + }, + { + "Category": "Tablet", + "Value": 200, + "ColorVal": 2 + }, + { + "Category": "Tablet", + "Value": 184, + "ColorVal": 3 + }, + { + "Category": "Tablet", + "Value": 146, + "ColorVal": 4 + }, + { + "Category": "Tablet", + "Value": 65, + "ColorVal": 5 + }, + { + "Category": "Tablet", + "Value": 136, + "ColorVal": 6 + }, + { + "Category": "Tablet", + "Value": 64, + "ColorVal": 7 + }, + { + "Category": "Tablet", + "Value": 755, + "ColorVal": 8 + }, + { + "Category": "Tablet", + "Value": 410, + "ColorVal": 9 + }, + { + "Category": "Tablet", + "Value": 129, + "ColorVal": 10 + }, + { + "Category": "Tablet", + "Value": 565, + "ColorVal": 11 + }, + { + "Category": "Tablet", + "Value": 438, + "ColorVal": 12 + }, + { + "Category": "Tablet", + "Value": 998, + "ColorVal": 13 + }, + { + "Category": "Tablet", + "Value": 305, + "ColorVal": 14 + }, + { + "Category": "Tablet", + "Value": 72, + "ColorVal": 15 + }, + { + "Category": "Tablet", + "Value": 197, + "ColorVal": 16 + }, + { + "Category": "Tablet", + "Value": 739, + "ColorVal": 17 + }, + { + "Category": "Tablet", + "Value": 136, + "ColorVal": 18 + }, + { + "Category": "Tablet", + "Value": 560, + "ColorVal": 19 + }, + { + "Category": "Tablet", + "Value": 241, + "ColorVal": 20 + }, + { + "Category": "Tablet", + "Value": 243, + "ColorVal": 21 + }, + { + "Category": "Tablet", + "Value": 500, + "ColorVal": 22 + }, + { + "Category": "Tablet", + "Value": 383, + "ColorVal": 23 + }, + { + "Category": "Tablet", + "Value": 484, + "ColorVal": 24 + }, + { + "Category": "Tablet", + "Value": 338, + "ColorVal": 25 + }, + { + "Category": "Tablet", + "Value": 246, + "ColorVal": 26 + }, + { + "Category": "Tablet", + "Value": 872, + "ColorVal": 27 + }, + { + "Category": "Tablet", + "Value": 515, + "ColorVal": 28 + }, + { + "Category": "Tablet", + "Value": 931, + "ColorVal": 29 + }, + { + "Category": "Tablet", + "Value": 242, + "ColorVal": 30 + }, + { + "Category": "Desktop", + "Value": 794, + "ColorVal": 1 + }, + { + "Category": "Desktop", + "Value": 868, + "ColorVal": 2 + }, + { + "Category": "Desktop", + "Value": 261, + "ColorVal": 3 + }, + { + "Category": "Desktop", + "Value": 126, + "ColorVal": 4 + }, + { + "Category": "Desktop", + "Value": 506, + "ColorVal": 5 + }, + { + "Category": "Desktop", + "Value": 674, + "ColorVal": 6 + }, + { + "Category": "Desktop", + "Value": 659, + "ColorVal": 7 + }, + { + "Category": "Desktop", + "Value": 271, + "ColorVal": 8 + }, + { + "Category": "Desktop", + "Value": 827, + "ColorVal": 9 + }, + { + "Category": "Desktop", + "Value": 527, + "ColorVal": 10 + }, + { + "Category": "Desktop", + "Value": 195, + "ColorVal": 11 + }, + { + "Category": "Desktop", + "Value": 577, + "ColorVal": 12 + }, + { + "Category": "Desktop", + "Value": 808, + "ColorVal": 13 + }, + { + "Category": "Desktop", + "Value": 391, + "ColorVal": 14 + }, + { + "Category": "Desktop", + "Value": 624, + "ColorVal": 15 + }, + { + "Category": "Desktop", + "Value": 852, + "ColorVal": 16 + }, + { + "Category": "Desktop", + "Value": 805, + "ColorVal": 17 + }, + { + "Category": "Desktop", + "Value": 312, + "ColorVal": 18 + }, + { + "Category": "Desktop", + "Value": 869, + "ColorVal": 19 + }, + { + "Category": "Desktop", + "Value": 614, + "ColorVal": 20 + }, + { + "Category": "Desktop", + "Value": 587, + "ColorVal": 21 + }, + { + "Category": "Desktop", + "Value": 918, + "ColorVal": 22 + }, + { + "Category": "Desktop", + "Value": 132, + "ColorVal": 23 + }, + { + "Category": "Desktop", + "Value": 972, + "ColorVal": 24 + }, + { + "Category": "Desktop", + "Value": 377, + "ColorVal": 25 + }, + { + "Category": "Desktop", + "Value": 727, + "ColorVal": 26 + }, + { + "Category": "Desktop", + "Value": 110, + "ColorVal": 27 + }, + { + "Category": "Desktop", + "Value": 321, + "ColorVal": 28 + }, + { + "Category": "Desktop", + "Value": 913, + "ColorVal": 29 + }, + { + "Category": "Desktop", + "Value": 738, + "ColorVal": 30 + }, + { + "Category": "Monitor", + "Value": 401, + "ColorVal": 1 + }, + { + "Category": "Monitor", + "Value": 224, + "ColorVal": 2 + }, + { + "Category": "Monitor", + "Value": 203, + "ColorVal": 3 + }, + { + "Category": "Monitor", + "Value": 873, + "ColorVal": 4 + }, + { + "Category": "Monitor", + "Value": 388, + "ColorVal": 5 + }, + { + "Category": "Monitor", + "Value": 506, + "ColorVal": 6 + }, + { + "Category": "Monitor", + "Value": 488, + "ColorVal": 7 + }, + { + "Category": "Monitor", + "Value": 71, + "ColorVal": 8 + }, + { + "Category": "Monitor", + "Value": 249, + "ColorVal": 9 + }, + { + "Category": "Monitor", + "Value": 730, + "ColorVal": 10 + }, + { + "Category": "Monitor", + "Value": 673, + "ColorVal": 11 + }, + { + "Category": "Monitor", + "Value": 928, + "ColorVal": 12 + }, + { + "Category": "Monitor", + "Value": 80, + "ColorVal": 13 + }, + { + "Category": "Monitor", + "Value": 850, + "ColorVal": 14 + }, + { + "Category": "Monitor", + "Value": 889, + "ColorVal": 15 + }, + { + "Category": "Monitor", + "Value": 808, + "ColorVal": 16 + }, + { + "Category": "Monitor", + "Value": 41, + "ColorVal": 17 + }, + { + "Category": "Monitor", + "Value": 932, + "ColorVal": 18 + }, + { + "Category": "Monitor", + "Value": 825, + "ColorVal": 19 + }, + { + "Category": "Monitor", + "Value": 991, + "ColorVal": 20 + }, + { + "Category": "Monitor", + "Value": 852, + "ColorVal": 21 + }, + { + "Category": "Monitor", + "Value": 387, + "ColorVal": 22 + }, + { + "Category": "Monitor", + "Value": 340, + "ColorVal": 23 + }, + { + "Category": "Monitor", + "Value": 360, + "ColorVal": 24 + }, + { + "Category": "Monitor", + "Value": 281, + "ColorVal": 25 + }, + { + "Category": "Monitor", + "Value": 123, + "ColorVal": 26 + }, + { + "Category": "Monitor", + "Value": 340, + "ColorVal": 27 + }, + { + "Category": "Monitor", + "Value": 525, + "ColorVal": 28 + }, + { + "Category": "Monitor", + "Value": 529, + "ColorVal": 29 + }, + { + "Category": "Monitor", + "Value": 329, + "ColorVal": 30 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/stacked-bar-chart/05-card10.flint.json b/test-harness/excel/evaluations/inputs/stacked-bar-chart/05-card10.flint.json new file mode 100644 index 00000000..41ae8c30 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/stacked-bar-chart/05-card10.flint.json @@ -0,0 +1,173 @@ +{ + "semantic_types": { + "Date": "Date", + "Value": "Quantity", + "Segment": "Category" + }, + "chart_spec": { + "chartType": "Stacked Bar Chart", + "encodings": { + "x": "Date", + "y": "Value", + "color": "Segment" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Date": "2020-01-01", + "Value": 300, + "Segment": "Laptop" + }, + { + "Date": "2020-01-01", + "Value": 961, + "Segment": "Phone" + }, + { + "Date": "2020-01-01", + "Value": 741, + "Segment": "Tablet" + }, + { + "Date": "2020-04-19", + "Value": 606, + "Segment": "Laptop" + }, + { + "Date": "2020-04-19", + "Value": 194, + "Segment": "Phone" + }, + { + "Date": "2020-04-19", + "Value": 823, + "Segment": "Tablet" + }, + { + "Date": "2020-08-07", + "Value": 952, + "Segment": "Laptop" + }, + { + "Date": "2020-08-07", + "Value": 532, + "Segment": "Phone" + }, + { + "Date": "2020-08-07", + "Value": 405, + "Segment": "Tablet" + }, + { + "Date": "2020-11-24", + "Value": 989, + "Segment": "Laptop" + }, + { + "Date": "2020-11-24", + "Value": 833, + "Segment": "Phone" + }, + { + "Date": "2020-11-24", + "Value": 838, + "Segment": "Tablet" + }, + { + "Date": "2021-03-14", + "Value": 217, + "Segment": "Laptop" + }, + { + "Date": "2021-03-14", + "Value": 807, + "Segment": "Phone" + }, + { + "Date": "2021-03-14", + "Value": 593, + "Segment": "Tablet" + }, + { + "Date": "2021-07-01", + "Value": 712, + "Segment": "Laptop" + }, + { + "Date": "2021-07-01", + "Value": 381, + "Segment": "Phone" + }, + { + "Date": "2021-07-01", + "Value": 323, + "Segment": "Tablet" + }, + { + "Date": "2021-10-19", + "Value": 741, + "Segment": "Laptop" + }, + { + "Date": "2021-10-19", + "Value": 333, + "Segment": "Phone" + }, + { + "Date": "2021-10-19", + "Value": 837, + "Segment": "Tablet" + }, + { + "Date": "2022-02-05", + "Value": 395, + "Segment": "Laptop" + }, + { + "Date": "2022-02-05", + "Value": 81, + "Segment": "Phone" + }, + { + "Date": "2022-02-05", + "Value": 562, + "Segment": "Tablet" + }, + { + "Date": "2022-05-26", + "Value": 442, + "Segment": "Laptop" + }, + { + "Date": "2022-05-26", + "Value": 553, + "Segment": "Phone" + }, + { + "Date": "2022-05-26", + "Value": 813, + "Segment": "Tablet" + }, + { + "Date": "2022-09-12", + "Value": 194, + "Segment": "Laptop" + }, + { + "Date": "2022-09-12", + "Value": 658, + "Segment": "Phone" + }, + { + "Date": "2022-09-12", + "Value": 78, + "Segment": "Tablet" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/stacked-bar-chart/06-card20.flint.json b/test-harness/excel/evaluations/inputs/stacked-bar-chart/06-card20.flint.json new file mode 100644 index 00000000..b2d887f9 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/stacked-bar-chart/06-card20.flint.json @@ -0,0 +1,423 @@ +{ + "semantic_types": { + "Date": "Date", + "Value": "Quantity", + "Segment": "Category" + }, + "chart_spec": { + "chartType": "Stacked Bar Chart", + "encodings": { + "x": "Date", + "y": "Value", + "color": "Segment" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Date": "2020-01-01", + "Value": 283, + "Segment": "Laptop" + }, + { + "Date": "2020-01-01", + "Value": 509, + "Segment": "Phone" + }, + { + "Date": "2020-01-01", + "Value": 946, + "Segment": "Tablet" + }, + { + "Date": "2020-01-01", + "Value": 971, + "Segment": "Desktop" + }, + { + "Date": "2020-02-24", + "Value": 992, + "Segment": "Laptop" + }, + { + "Date": "2020-02-24", + "Value": 76, + "Segment": "Phone" + }, + { + "Date": "2020-02-24", + "Value": 772, + "Segment": "Tablet" + }, + { + "Date": "2020-02-24", + "Value": 275, + "Segment": "Desktop" + }, + { + "Date": "2020-04-19", + "Value": 26, + "Segment": "Laptop" + }, + { + "Date": "2020-04-19", + "Value": 546, + "Segment": "Phone" + }, + { + "Date": "2020-04-19", + "Value": 47, + "Segment": "Tablet" + }, + { + "Date": "2020-04-19", + "Value": 322, + "Segment": "Desktop" + }, + { + "Date": "2020-06-13", + "Value": 715, + "Segment": "Laptop" + }, + { + "Date": "2020-06-13", + "Value": 780, + "Segment": "Phone" + }, + { + "Date": "2020-06-13", + "Value": 451, + "Segment": "Tablet" + }, + { + "Date": "2020-06-13", + "Value": 712, + "Segment": "Desktop" + }, + { + "Date": "2020-08-07", + "Value": 362, + "Segment": "Laptop" + }, + { + "Date": "2020-08-07", + "Value": 383, + "Segment": "Phone" + }, + { + "Date": "2020-08-07", + "Value": 653, + "Segment": "Tablet" + }, + { + "Date": "2020-08-07", + "Value": 326, + "Segment": "Desktop" + }, + { + "Date": "2020-09-30", + "Value": 959, + "Segment": "Laptop" + }, + { + "Date": "2020-09-30", + "Value": 814, + "Segment": "Phone" + }, + { + "Date": "2020-09-30", + "Value": 58, + "Segment": "Tablet" + }, + { + "Date": "2020-09-30", + "Value": 129, + "Segment": "Desktop" + }, + { + "Date": "2020-11-24", + "Value": 423, + "Segment": "Laptop" + }, + { + "Date": "2020-11-24", + "Value": 902, + "Segment": "Phone" + }, + { + "Date": "2020-11-24", + "Value": 24, + "Segment": "Tablet" + }, + { + "Date": "2020-11-24", + "Value": 345, + "Segment": "Desktop" + }, + { + "Date": "2021-01-18", + "Value": 97, + "Segment": "Laptop" + }, + { + "Date": "2021-01-18", + "Value": 621, + "Segment": "Phone" + }, + { + "Date": "2021-01-18", + "Value": 323, + "Segment": "Tablet" + }, + { + "Date": "2021-01-18", + "Value": 481, + "Segment": "Desktop" + }, + { + "Date": "2021-03-14", + "Value": 954, + "Segment": "Laptop" + }, + { + "Date": "2021-03-14", + "Value": 994, + "Segment": "Phone" + }, + { + "Date": "2021-03-14", + "Value": 284, + "Segment": "Tablet" + }, + { + "Date": "2021-03-14", + "Value": 410, + "Segment": "Desktop" + }, + { + "Date": "2021-05-07", + "Value": 493, + "Segment": "Laptop" + }, + { + "Date": "2021-05-07", + "Value": 766, + "Segment": "Phone" + }, + { + "Date": "2021-05-07", + "Value": 731, + "Segment": "Tablet" + }, + { + "Date": "2021-05-07", + "Value": 753, + "Segment": "Desktop" + }, + { + "Date": "2021-07-01", + "Value": 320, + "Segment": "Laptop" + }, + { + "Date": "2021-07-01", + "Value": 735, + "Segment": "Phone" + }, + { + "Date": "2021-07-01", + "Value": 569, + "Segment": "Tablet" + }, + { + "Date": "2021-07-01", + "Value": 209, + "Segment": "Desktop" + }, + { + "Date": "2021-08-25", + "Value": 953, + "Segment": "Laptop" + }, + { + "Date": "2021-08-25", + "Value": 578, + "Segment": "Phone" + }, + { + "Date": "2021-08-25", + "Value": 80, + "Segment": "Tablet" + }, + { + "Date": "2021-08-25", + "Value": 276, + "Segment": "Desktop" + }, + { + "Date": "2021-10-19", + "Value": 649, + "Segment": "Laptop" + }, + { + "Date": "2021-10-19", + "Value": 232, + "Segment": "Phone" + }, + { + "Date": "2021-10-19", + "Value": 938, + "Segment": "Tablet" + }, + { + "Date": "2021-10-19", + "Value": 48, + "Segment": "Desktop" + }, + { + "Date": "2021-12-12", + "Value": 371, + "Segment": "Laptop" + }, + { + "Date": "2021-12-12", + "Value": 698, + "Segment": "Phone" + }, + { + "Date": "2021-12-12", + "Value": 810, + "Segment": "Tablet" + }, + { + "Date": "2021-12-12", + "Value": 179, + "Segment": "Desktop" + }, + { + "Date": "2022-02-05", + "Value": 217, + "Segment": "Laptop" + }, + { + "Date": "2022-02-05", + "Value": 239, + "Segment": "Phone" + }, + { + "Date": "2022-02-05", + "Value": 208, + "Segment": "Tablet" + }, + { + "Date": "2022-02-05", + "Value": 763, + "Segment": "Desktop" + }, + { + "Date": "2022-04-01", + "Value": 503, + "Segment": "Laptop" + }, + { + "Date": "2022-04-01", + "Value": 499, + "Segment": "Phone" + }, + { + "Date": "2022-04-01", + "Value": 932, + "Segment": "Tablet" + }, + { + "Date": "2022-04-01", + "Value": 176, + "Segment": "Desktop" + }, + { + "Date": "2022-05-26", + "Value": 869, + "Segment": "Laptop" + }, + { + "Date": "2022-05-26", + "Value": 296, + "Segment": "Phone" + }, + { + "Date": "2022-05-26", + "Value": 888, + "Segment": "Tablet" + }, + { + "Date": "2022-05-26", + "Value": 423, + "Segment": "Desktop" + }, + { + "Date": "2022-07-19", + "Value": 359, + "Segment": "Laptop" + }, + { + "Date": "2022-07-19", + "Value": 77, + "Segment": "Phone" + }, + { + "Date": "2022-07-19", + "Value": 291, + "Segment": "Tablet" + }, + { + "Date": "2022-07-19", + "Value": 666, + "Segment": "Desktop" + }, + { + "Date": "2022-09-12", + "Value": 419, + "Segment": "Laptop" + }, + { + "Date": "2022-09-12", + "Value": 353, + "Segment": "Phone" + }, + { + "Date": "2022-09-12", + "Value": 862, + "Segment": "Tablet" + }, + { + "Date": "2022-09-12", + "Value": 832, + "Segment": "Desktop" + }, + { + "Date": "2022-11-06", + "Value": 112, + "Segment": "Laptop" + }, + { + "Date": "2022-11-06", + "Value": 913, + "Segment": "Phone" + }, + { + "Date": "2022-11-06", + "Value": 801, + "Segment": "Tablet" + }, + { + "Date": "2022-11-06", + "Value": 939, + "Segment": "Desktop" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/stacked-bar-chart/07-card10.flint.json b/test-harness/excel/evaluations/inputs/stacked-bar-chart/07-card10.flint.json new file mode 100644 index 00000000..87e89390 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/stacked-bar-chart/07-card10.flint.json @@ -0,0 +1,173 @@ +{ + "semantic_types": { + "X": "Quantity", + "Value": "Quantity", + "Segment": "Category" + }, + "chart_spec": { + "chartType": "Stacked Bar Chart", + "encodings": { + "x": "X", + "y": "Value", + "color": "Segment" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "X": 1, + "Value": 299, + "Segment": "Laptop" + }, + { + "X": 1, + "Value": 927, + "Segment": "Phone" + }, + { + "X": 1, + "Value": 362, + "Segment": "Tablet" + }, + { + "X": 2, + "Value": 321, + "Segment": "Laptop" + }, + { + "X": 2, + "Value": 677, + "Segment": "Phone" + }, + { + "X": 2, + "Value": 138, + "Segment": "Tablet" + }, + { + "X": 3, + "Value": 526, + "Segment": "Laptop" + }, + { + "X": 3, + "Value": 227, + "Segment": "Phone" + }, + { + "X": 3, + "Value": 901, + "Segment": "Tablet" + }, + { + "X": 4, + "Value": 245, + "Segment": "Laptop" + }, + { + "X": 4, + "Value": 453, + "Segment": "Phone" + }, + { + "X": 4, + "Value": 905, + "Segment": "Tablet" + }, + { + "X": 5, + "Value": 850, + "Segment": "Laptop" + }, + { + "X": 5, + "Value": 757, + "Segment": "Phone" + }, + { + "X": 5, + "Value": 334, + "Segment": "Tablet" + }, + { + "X": 6, + "Value": 638, + "Segment": "Laptop" + }, + { + "X": 6, + "Value": 324, + "Segment": "Phone" + }, + { + "X": 6, + "Value": 582, + "Segment": "Tablet" + }, + { + "X": 7, + "Value": 917, + "Segment": "Laptop" + }, + { + "X": 7, + "Value": 421, + "Segment": "Phone" + }, + { + "X": 7, + "Value": 313, + "Segment": "Tablet" + }, + { + "X": 8, + "Value": 132, + "Segment": "Laptop" + }, + { + "X": 8, + "Value": 719, + "Segment": "Phone" + }, + { + "X": 8, + "Value": 470, + "Segment": "Tablet" + }, + { + "X": 9, + "Value": 388, + "Segment": "Laptop" + }, + { + "X": 9, + "Value": 115, + "Segment": "Phone" + }, + { + "X": 9, + "Value": 508, + "Segment": "Tablet" + }, + { + "X": 10, + "Value": 328, + "Segment": "Laptop" + }, + { + "X": 10, + "Value": 681, + "Segment": "Phone" + }, + { + "X": 10, + "Value": 525, + "Segment": "Tablet" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/stacked-bar-chart/08-card23.flint.json b/test-harness/excel/evaluations/inputs/stacked-bar-chart/08-card23.flint.json new file mode 100644 index 00000000..15ddd710 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/stacked-bar-chart/08-card23.flint.json @@ -0,0 +1,143 @@ +{ + "semantic_types": { + "X": "Quantity", + "Group": "Category", + "Segment": "Category" + }, + "chart_spec": { + "chartType": "Stacked Bar Chart", + "encodings": { + "x": "X", + "y": "Group", + "color": "Segment" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Group": "Laptop", + "X": 906, + "Segment": "USA" + }, + { + "Group": "Laptop", + "X": 619, + "Segment": "China" + }, + { + "Group": "Laptop", + "X": 389, + "Segment": "Japan" + }, + { + "Group": "Phone", + "X": 163, + "Segment": "USA" + }, + { + "Group": "Phone", + "X": 91, + "Segment": "China" + }, + { + "Group": "Phone", + "X": 314, + "Segment": "Japan" + }, + { + "Group": "Tablet", + "X": 566, + "Segment": "USA" + }, + { + "Group": "Tablet", + "X": 845, + "Segment": "China" + }, + { + "Group": "Tablet", + "X": 60, + "Segment": "Japan" + }, + { + "Group": "Desktop", + "X": 274, + "Segment": "USA" + }, + { + "Group": "Desktop", + "X": 92, + "Segment": "China" + }, + { + "Group": "Desktop", + "X": 223, + "Segment": "Japan" + }, + { + "Group": "Monitor", + "X": 725, + "Segment": "USA" + }, + { + "Group": "Monitor", + "X": 14, + "Segment": "China" + }, + { + "Group": "Monitor", + "X": 315, + "Segment": "Japan" + }, + { + "Group": "Keyboard", + "X": 757, + "Segment": "USA" + }, + { + "Group": "Keyboard", + "X": 486, + "Segment": "China" + }, + { + "Group": "Keyboard", + "X": 304, + "Segment": "Japan" + }, + { + "Group": "Mouse", + "X": 381, + "Segment": "USA" + }, + { + "Group": "Mouse", + "X": 388, + "Segment": "China" + }, + { + "Group": "Mouse", + "X": 906, + "Segment": "Japan" + }, + { + "Group": "Headphones", + "X": 441, + "Segment": "USA" + }, + { + "Group": "Headphones", + "X": 695, + "Segment": "China" + }, + { + "Group": "Headphones", + "X": 564, + "Segment": "Japan" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/stacked-bar-chart/09-card43.flint.json b/test-harness/excel/evaluations/inputs/stacked-bar-chart/09-card43.flint.json new file mode 100644 index 00000000..71a562a5 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/stacked-bar-chart/09-card43.flint.json @@ -0,0 +1,248 @@ +{ + "semantic_types": { + "X": "Quantity", + "EndDate": "Date", + "Segment": "Category" + }, + "chart_spec": { + "chartType": "Stacked Bar Chart", + "encodings": { + "x": "X", + "y": "EndDate", + "color": "Segment" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "EndDate": "2020-01-01", + "X": 403, + "Segment": "Laptop" + }, + { + "EndDate": "2020-01-01", + "X": 206, + "Segment": "Phone" + }, + { + "EndDate": "2020-01-01", + "X": 183, + "Segment": "Tablet" + }, + { + "EndDate": "2020-03-14", + "X": 265, + "Segment": "Laptop" + }, + { + "EndDate": "2020-03-14", + "X": 151, + "Segment": "Phone" + }, + { + "EndDate": "2020-03-14", + "X": 231, + "Segment": "Tablet" + }, + { + "EndDate": "2020-05-26", + "X": 338, + "Segment": "Laptop" + }, + { + "EndDate": "2020-05-26", + "X": 33, + "Segment": "Phone" + }, + { + "EndDate": "2020-05-26", + "X": 211, + "Segment": "Tablet" + }, + { + "EndDate": "2020-08-07", + "X": 468, + "Segment": "Laptop" + }, + { + "EndDate": "2020-08-07", + "X": 275, + "Segment": "Phone" + }, + { + "EndDate": "2020-08-07", + "X": 233, + "Segment": "Tablet" + }, + { + "EndDate": "2020-10-19", + "X": 474, + "Segment": "Laptop" + }, + { + "EndDate": "2020-10-19", + "X": 742, + "Segment": "Phone" + }, + { + "EndDate": "2020-10-19", + "X": 470, + "Segment": "Tablet" + }, + { + "EndDate": "2020-12-31", + "X": 962, + "Segment": "Laptop" + }, + { + "EndDate": "2020-12-31", + "X": 110, + "Segment": "Phone" + }, + { + "EndDate": "2020-12-31", + "X": 940, + "Segment": "Tablet" + }, + { + "EndDate": "2021-03-14", + "X": 98, + "Segment": "Laptop" + }, + { + "EndDate": "2021-03-14", + "X": 202, + "Segment": "Phone" + }, + { + "EndDate": "2021-03-14", + "X": 259, + "Segment": "Tablet" + }, + { + "EndDate": "2021-05-26", + "X": 849, + "Segment": "Laptop" + }, + { + "EndDate": "2021-05-26", + "X": 334, + "Segment": "Phone" + }, + { + "EndDate": "2021-05-26", + "X": 770, + "Segment": "Tablet" + }, + { + "EndDate": "2021-08-07", + "X": 869, + "Segment": "Laptop" + }, + { + "EndDate": "2021-08-07", + "X": 172, + "Segment": "Phone" + }, + { + "EndDate": "2021-08-07", + "X": 291, + "Segment": "Tablet" + }, + { + "EndDate": "2021-10-19", + "X": 231, + "Segment": "Laptop" + }, + { + "EndDate": "2021-10-19", + "X": 873, + "Segment": "Phone" + }, + { + "EndDate": "2021-10-19", + "X": 654, + "Segment": "Tablet" + }, + { + "EndDate": "2021-12-31", + "X": 293, + "Segment": "Laptop" + }, + { + "EndDate": "2021-12-31", + "X": 715, + "Segment": "Phone" + }, + { + "EndDate": "2021-12-31", + "X": 416, + "Segment": "Tablet" + }, + { + "EndDate": "2022-03-14", + "X": 492, + "Segment": "Laptop" + }, + { + "EndDate": "2022-03-14", + "X": 750, + "Segment": "Phone" + }, + { + "EndDate": "2022-03-14", + "X": 156, + "Segment": "Tablet" + }, + { + "EndDate": "2022-05-26", + "X": 597, + "Segment": "Laptop" + }, + { + "EndDate": "2022-05-26", + "X": 35, + "Segment": "Phone" + }, + { + "EndDate": "2022-05-26", + "X": 323, + "Segment": "Tablet" + }, + { + "EndDate": "2022-08-07", + "X": 780, + "Segment": "Laptop" + }, + { + "EndDate": "2022-08-07", + "X": 270, + "Segment": "Phone" + }, + { + "EndDate": "2022-08-07", + "X": 251, + "Segment": "Tablet" + }, + { + "EndDate": "2022-10-19", + "X": 460, + "Segment": "Laptop" + }, + { + "EndDate": "2022-10-19", + "X": 280, + "Segment": "Phone" + }, + { + "EndDate": "2022-10-19", + "X": 338, + "Segment": "Tablet" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/stacked-bar-chart/10-card5.flint.json b/test-harness/excel/evaluations/inputs/stacked-bar-chart/10-card5.flint.json new file mode 100644 index 00000000..95e39781 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/stacked-bar-chart/10-card5.flint.json @@ -0,0 +1,93 @@ +{ + "semantic_types": { + "Category": "Category", + "Group": "Category", + "Segment": "Category" + }, + "chart_spec": { + "chartType": "Stacked Bar Chart", + "encodings": { + "x": "Category", + "y": "Group", + "color": "Segment" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Laptop", + "Group": "USA", + "Segment": "Sales" + }, + { + "Category": "Laptop", + "Group": "UK", + "Segment": "Sales" + }, + { + "Category": "Phone", + "Group": "USA", + "Segment": "Sales" + }, + { + "Category": "Phone", + "Group": "Germany", + "Segment": "Sales" + }, + { + "Category": "Phone", + "Group": "UK", + "Segment": "Engineering" + }, + { + "Category": "Tablet", + "Group": "USA", + "Segment": "Sales" + }, + { + "Category": "Tablet", + "Group": "China", + "Segment": "Marketing" + }, + { + "Category": "Tablet", + "Group": "Germany", + "Segment": "Engineering" + }, + { + "Category": "Desktop", + "Group": "China", + "Segment": "Engineering" + }, + { + "Category": "Desktop", + "Group": "Japan", + "Segment": "Engineering" + }, + { + "Category": "Desktop", + "Group": "Germany", + "Segment": "Sales" + }, + { + "Category": "Desktop", + "Group": "UK", + "Segment": "Engineering" + }, + { + "Category": "Monitor", + "Group": "Japan", + "Segment": "Engineering" + }, + { + "Category": "Monitor", + "Group": "Germany", + "Segment": "Marketing" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/sunburst-chart/00-card0.flint.json b/test-harness/excel/evaluations/inputs/sunburst-chart/00-card0.flint.json new file mode 100644 index 00000000..e6485227 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/sunburst-chart/00-card0.flint.json @@ -0,0 +1,45 @@ +{ + "semantic_types": { + "Category": "Category", + "Amount": "Quantity" + }, + "chart_spec": { + "chartType": "Sunburst Chart", + "encodings": { + "color": "Category", + "size": "Amount" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Housing", + "Amount": 228 + }, + { + "Category": "Food", + "Amount": 1736 + }, + { + "Category": "Transport", + "Amount": 379 + }, + { + "Category": "Entertainment", + "Amount": 1340 + }, + { + "Category": "Savings", + "Amount": 2162 + }, + { + "Category": "Healthcare", + "Amount": 453 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/sunburst-chart/01-card0.flint.json b/test-harness/excel/evaluations/inputs/sunburst-chart/01-card0.flint.json new file mode 100644 index 00000000..bb63ebc1 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/sunburst-chart/01-card0.flint.json @@ -0,0 +1,73 @@ +{ + "semantic_types": { + "Department": "Category", + "Team": "Category", + "Headcount": "Quantity" + }, + "chart_spec": { + "chartType": "Sunburst Chart", + "encodings": { + "color": "Department", + "group": "Team", + "size": "Headcount" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Department": "Engineering", + "Team": "Frontend", + "Headcount": 39 + }, + { + "Department": "Engineering", + "Team": "Backend", + "Headcount": 53 + }, + { + "Department": "Engineering", + "Team": "Infra", + "Headcount": 42 + }, + { + "Department": "Engineering", + "Team": "QA", + "Headcount": 27 + }, + { + "Department": "Product", + "Team": "Design", + "Headcount": 20 + }, + { + "Department": "Product", + "Team": "PM", + "Headcount": 52 + }, + { + "Department": "Product", + "Team": "Research", + "Headcount": 42 + }, + { + "Department": "Operations", + "Team": "HR", + "Headcount": 16 + }, + { + "Department": "Operations", + "Team": "Finance", + "Headcount": 17 + }, + { + "Department": "Operations", + "Team": "Legal", + "Headcount": 28 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/sunburst-chart/02-card0.flint.json b/test-harness/excel/evaluations/inputs/sunburst-chart/02-card0.flint.json new file mode 100644 index 00000000..35a388d3 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/sunburst-chart/02-card0.flint.json @@ -0,0 +1,103 @@ +{ + "semantic_types": { + "Continent": "Category", + "Country": "Country", + "Population": "Quantity" + }, + "chart_spec": { + "chartType": "Sunburst Chart", + "encodings": { + "color": "Continent", + "group": "Country", + "size": "Population" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Continent": "North America", + "Country": "USA", + "Population": 106 + }, + { + "Continent": "North America", + "Country": "Canada", + "Population": 1209 + }, + { + "Continent": "North America", + "Country": "Mexico", + "Population": 217 + }, + { + "Continent": "Europe", + "Country": "UK", + "Population": 452 + }, + { + "Continent": "Europe", + "Country": "France", + "Population": 675 + }, + { + "Continent": "Europe", + "Country": "Germany", + "Population": 277 + }, + { + "Continent": "Europe", + "Country": "Spain", + "Population": 231 + }, + { + "Continent": "Europe", + "Country": "Italy", + "Population": 1110 + }, + { + "Continent": "Asia", + "Country": "China", + "Population": 151 + }, + { + "Continent": "Asia", + "Country": "Japan", + "Population": 671 + }, + { + "Continent": "Asia", + "Country": "India", + "Population": 762 + }, + { + "Continent": "Asia", + "Country": "Korea", + "Population": 86 + }, + { + "Continent": "Asia", + "Country": "Thailand", + "Population": 1128 + }, + { + "Continent": "South America", + "Country": "Brazil", + "Population": 210 + }, + { + "Continent": "South America", + "Country": "Argentina", + "Population": 818 + }, + { + "Continent": "South America", + "Country": "Chile", + "Population": 1349 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/treemap/00-card0.flint.json b/test-harness/excel/evaluations/inputs/treemap/00-card0.flint.json new file mode 100644 index 00000000..23cb1729 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/treemap/00-card0.flint.json @@ -0,0 +1,45 @@ +{ + "semantic_types": { + "Sector": "Category", + "MarketCap": "Quantity" + }, + "chart_spec": { + "chartType": "Treemap", + "encodings": { + "color": "Sector", + "size": "MarketCap" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Sector": "Technology", + "MarketCap": 560 + }, + { + "Sector": "Healthcare", + "MarketCap": 3264 + }, + { + "Sector": "Finance", + "MarketCap": 2881 + }, + { + "Sector": "Energy", + "MarketCap": 3674 + }, + { + "Sector": "Consumer", + "MarketCap": 3669 + }, + { + "Sector": "Industrials", + "MarketCap": 1538 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/treemap/01-card0.flint.json b/test-harness/excel/evaluations/inputs/treemap/01-card0.flint.json new file mode 100644 index 00000000..5fad82a9 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/treemap/01-card0.flint.json @@ -0,0 +1,83 @@ +{ + "semantic_types": { + "Region": "Category", + "Country": "Country", + "Revenue": "Amount" + }, + "chart_spec": { + "chartType": "Treemap", + "encodings": { + "color": "Region", + "detail": "Country", + "size": "Revenue" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Region": "Americas", + "Country": "USA", + "Revenue": 2052 + }, + { + "Region": "Americas", + "Country": "Canada", + "Revenue": 240 + }, + { + "Region": "Americas", + "Country": "Brazil", + "Revenue": 1708 + }, + { + "Region": "Americas", + "Country": "Mexico", + "Revenue": 2056 + }, + { + "Region": "Europe", + "Country": "UK", + "Revenue": 2007 + }, + { + "Region": "Europe", + "Country": "Germany", + "Revenue": 116 + }, + { + "Region": "Europe", + "Country": "France", + "Revenue": 1382 + }, + { + "Region": "Europe", + "Country": "Italy", + "Revenue": 1645 + }, + { + "Region": "Asia", + "Country": "China", + "Revenue": 1870 + }, + { + "Region": "Asia", + "Country": "Japan", + "Revenue": 1081 + }, + { + "Region": "Asia", + "Country": "India", + "Revenue": 2008 + }, + { + "Region": "Asia", + "Country": "Korea", + "Revenue": 274 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/treemap/02-card0.flint.json b/test-harness/excel/evaluations/inputs/treemap/02-card0.flint.json new file mode 100644 index 00000000..56db1fa9 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/treemap/02-card0.flint.json @@ -0,0 +1,81 @@ +{ + "semantic_types": { + "Item": "Category", + "Size": "Quantity" + }, + "chart_spec": { + "chartType": "Treemap", + "encodings": { + "color": "Item", + "size": "Size" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Item": "Electronics", + "Size": 453 + }, + { + "Item": "Clothing", + "Size": 366 + }, + { + "Item": "Food", + "Size": 413 + }, + { + "Item": "Books", + "Size": 307 + }, + { + "Item": "Sports", + "Size": 180 + }, + { + "Item": "Home", + "Size": 421 + }, + { + "Item": "Garden", + "Size": 292 + }, + { + "Item": "Auto", + "Size": 439 + }, + { + "Item": "Health", + "Size": 220 + }, + { + "Item": "Beauty", + "Size": 381 + }, + { + "Item": "Toys", + "Size": 149 + }, + { + "Item": "Music", + "Size": 62 + }, + { + "Item": "Movies", + "Size": 323 + }, + { + "Item": "Software", + "Size": 418 + }, + { + "Item": "Games", + "Size": 135 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/waterfall-chart/00-card6.flint.json b/test-harness/excel/evaluations/inputs/waterfall-chart/00-card6.flint.json new file mode 100644 index 00000000..5039168c --- /dev/null +++ b/test-harness/excel/evaluations/inputs/waterfall-chart/00-card6.flint.json @@ -0,0 +1,45 @@ +{ + "semantic_types": { + "Category": "Category", + "Amount": "Quantity" + }, + "chart_spec": { + "chartType": "Waterfall Chart", + "encodings": { + "x": "Category", + "y": "Amount" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Category": "Revenue", + "Amount": 1000 + }, + { + "Category": "COGS", + "Amount": -400 + }, + { + "Category": "Gross Profit", + "Amount": -150 + }, + { + "Category": "Operating Exp", + "Amount": -200 + }, + { + "Category": "Tax", + "Amount": -80 + }, + { + "Category": "Net Income", + "Amount": 170 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/waterfall-chart/01-card7.flint.json b/test-harness/excel/evaluations/inputs/waterfall-chart/01-card7.flint.json new file mode 100644 index 00000000..e09f3162 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/waterfall-chart/01-card7.flint.json @@ -0,0 +1,58 @@ +{ + "semantic_types": { + "Step": "Category", + "Value": "Quantity", + "Type": "Category" + }, + "chart_spec": { + "chartType": "Waterfall Chart", + "encodings": { + "x": "Step", + "y": "Value", + "color": "Type" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Step": "Starting Balance", + "Value": 5000, + "Type": "start" + }, + { + "Step": "Sales", + "Value": 2200, + "Type": "delta" + }, + { + "Step": "Returns", + "Value": -350, + "Type": "delta" + }, + { + "Step": "Payroll", + "Value": -1800, + "Type": "delta" + }, + { + "Step": "Rent", + "Value": -600, + "Type": "delta" + }, + { + "Step": "Marketing", + "Value": -400, + "Type": "delta" + }, + { + "Step": "Ending Balance", + "Value": 4050, + "Type": "end" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/waterfall-chart/02-card7.flint.json b/test-harness/excel/evaluations/inputs/waterfall-chart/02-card7.flint.json new file mode 100644 index 00000000..4d3d8122 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/waterfall-chart/02-card7.flint.json @@ -0,0 +1,49 @@ +{ + "semantic_types": { + "Department": "Category", + "Variance": "Quantity" + }, + "chart_spec": { + "chartType": "Waterfall Chart", + "encodings": { + "x": "Department", + "y": "Variance" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Department": "Engineering", + "Variance": 120 + }, + { + "Department": "Sales", + "Variance": -45 + }, + { + "Department": "Marketing", + "Variance": -80 + }, + { + "Department": "Operations", + "Variance": 35 + }, + { + "Department": "HR", + "Variance": -20 + }, + { + "Department": "Finance", + "Variance": 15 + }, + { + "Department": "Support", + "Variance": -30 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/waterfall-chart/03-card14.flint.json b/test-harness/excel/evaluations/inputs/waterfall-chart/03-card14.flint.json new file mode 100644 index 00000000..0e5e8802 --- /dev/null +++ b/test-harness/excel/evaluations/inputs/waterfall-chart/03-card14.flint.json @@ -0,0 +1,93 @@ +{ + "semantic_types": { + "Month": "Category", + "Amount": "Quantity", + "Type": "Category" + }, + "chart_spec": { + "chartType": "Waterfall Chart", + "encodings": { + "x": "Month", + "y": "Amount", + "color": "Type" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Month": "Opening", + "Amount": 10000, + "Type": "start" + }, + { + "Month": "Jan", + "Amount": 500, + "Type": "delta" + }, + { + "Month": "Feb", + "Amount": 200, + "Type": "delta" + }, + { + "Month": "Mar", + "Amount": -150, + "Type": "delta" + }, + { + "Month": "Apr", + "Amount": 300, + "Type": "delta" + }, + { + "Month": "May", + "Amount": -100, + "Type": "delta" + }, + { + "Month": "Jun", + "Amount": -250, + "Type": "delta" + }, + { + "Month": "Jul", + "Amount": 400, + "Type": "delta" + }, + { + "Month": "Aug", + "Amount": 150, + "Type": "delta" + }, + { + "Month": "Sep", + "Amount": -300, + "Type": "delta" + }, + { + "Month": "Oct", + "Amount": 200, + "Type": "delta" + }, + { + "Month": "Nov", + "Amount": -50, + "Type": "delta" + }, + { + "Month": "Dec", + "Amount": 100, + "Type": "delta" + }, + { + "Month": "Closing", + "Amount": 11000, + "Type": "end" + } + ] + } +} diff --git a/test-harness/excel/evaluations/inputs/waterfall-chart/04-card4.flint.json b/test-harness/excel/evaluations/inputs/waterfall-chart/04-card4.flint.json new file mode 100644 index 00000000..cc157a7c --- /dev/null +++ b/test-harness/excel/evaluations/inputs/waterfall-chart/04-card4.flint.json @@ -0,0 +1,37 @@ +{ + "semantic_types": { + "Quarter": "Category", + "Change": "Quantity" + }, + "chart_spec": { + "chartType": "Waterfall Chart", + "encodings": { + "x": "Quarter", + "y": "Change" + }, + "baseSize": { + "width": 560, + "height": 360 + } + }, + "data": { + "values": [ + { + "Quarter": "Q1", + "Change": 300 + }, + { + "Quarter": "Q2", + "Change": 150 + }, + { + "Quarter": "Q3", + "Change": -100 + }, + { + "Quarter": "Q4", + "Change": 200 + } + ] + } +} diff --git a/test-harness/excel/evaluations/inspection-list.md b/test-harness/excel/evaluations/inspection-list.md new file mode 100644 index 00000000..3decc3f5 --- /dev/null +++ b/test-harness/excel/evaluations/inspection-list.md @@ -0,0 +1,332 @@ +# Excel backend inspection list + +This is the case-by-case visual audit for the native Excel backend. Each row compares the Office.js PNG with Flint's canonical rendering: Vega-Lite where available, otherwise the chart's ECharts implementation. + +Status: + +- `PENDING`: not yet visually inspected. +- `PASS`: rendered and visually acceptable in Excel's native design language. +- `FIXED`: a mismatch was repaired and the output passed a second visual inspection. +- `FAIL`: defect reproduced; repair is in progress. +- `SKIP`: unsupported by native Office.js charts, or still unresolved after 10 focused repair attempts; the blocker is recorded. + +A transport success alone is not a pass. Inspection covers field roles, orientation, grouping/stacking, aggregation, category order, labels, axes, legend, cardinality, and whether the Excel-native construction preserves the same reading as the Vega-Lite reference. + +## Progress + +| Chart type | Cases | Inspected | Passed/fixed | Failed | Skipped | +| --- | ---: | ---: | ---: | ---: | ---: | +| Bar Chart | 19 | 19 | 16 | 0 | 3 | +| Grouped Bar Chart | 15 | 15 | 12 | 0 | 3 | +| Stacked Bar Chart | 11 | 11 | 9 | 0 | 2 | +| Line Chart | 18 | 18 | 13 | 0 | 5 | +| Area Chart | 12 | 12 | 12 | 0 | 0 | +| Scatter Plot | 26 | 26 | 12 | 0 | 14 | +| Pie Chart | 4 | 4 | 4 | 0 | 0 | +| Donut Chart | 4 | 4 | 4 | 0 | 0 | +| Histogram | 3 | 3 | 3 | 0 | 0 | +| Boxplot | 10 | 10 | 3 | 0 | 7 | +| Heatmap | 9 | 9 | 0 | 0 | 9 | +| Radar Chart | 6 | 6 | 6 | 0 | 0 | +| Waterfall Chart | 5 | 5 | 2 | 0 | 3 | +| Funnel Chart | 3 | 3 | 3 | 0 | 0 | +| Treemap | 3 | 3 | 3 | 0 | 0 | +| Sunburst Chart | 3 | 3 | 3 | 0 | 0 | +| Connected Scatter Plot | 8 | 8 | 7 | 0 | 1 | +| **Total** | **159** | **159** | **112** | **0** | **47** | + +## Candlestick Chart (dedicated audit) + +These cases were rendered after the main catalog audit and do not change the +progress totals above. Both use native `StockOHLC` through `sheet.charts.add`. +Configured VLM review was skipped because no workspace `.env` provided a VLM +endpoint and credential; the generated side-by-side images were inspected +directly. + +| Case | Status | Attempts | Finding / fix | +| --- | --- | ---: | --- | +| basic-30-day | FIXED | 2 | Native `A1:E31` Date/Open/High/Low/Close range preserves all bodies, wicks, chronology, and the price trajectory. Excel serial dates render as a true date axis. A focused Low-to-High value scale removed native zero anchoring. | +| advanced-90-day-dense | FIXED | 3 | Native `A1:E91` preserves all 90 OHLC rows and the canonical trend. UTC fixture generation removed a DST duplicate; native tick spacing keeps the dense date axis readable, and the focused price scale prevents vertical compression. | + +Artifacts and the reproducible runner are under +`test-harness/excel/evaluations/out/candlestick-audit` and +`test-harness/excel/evaluations/candlestick-audit.mjs`. + +## Bar Chart + +| Case | Status | Attempts | Finding / fix | +| --- | --- | ---: | --- | +| 00-card5 | PASS | 1 | Five-category vertical bar preserves category order and values. | +| 01-card20 | PASS | 1 | Twenty nominal categories remain readable in the expanded native layout. | +| 02-card20 | PASS | 1 | Alternate 20-category value sequence preserves all bars and labels. | +| 03-card100 | PASS | 1 | Dense 100-category column chart preserves cardinality and value pattern with native sparse labeling. | +| 04-card5 | PASS | 1 | Three-series stacked columns preserve category totals and segment composition. | +| 05-card5 | PASS | 1 | Twenty-series stack preserves every segment and exposes a complete wrapped legend. | +| 06-card10 | PASS | 1 | Horizontal bars retain source category order, values, and zero baseline. | +| 07-card96 | FIXED | 4 | Reused Flint overflow ranking, retained its kept-value order, and emitted a density-aware 5 pt category-axis font; all 81 retained labels are visible. | +| 08-card29 | PASS | 1 | Horizontal three-segment stacks preserve category totals and composition. | +| 09-card24 | PASS | 1 | Temporal bars retain chronological order and all 24 values. | +| 10-card100 | PASS | 1 | Dense temporal bars preserve chronological progression and value pattern. | +| 11-card24 | PASS | 1 | Temporal three-series stacks preserve dates, totals, and segment identities. | +| 12-card18 | PASS | 1 | Horizontal temporal bars preserve the continuous-time ordering in native category form. | +| 13-card53 | PASS | 1 | Horizontal temporal stacks preserve date order, totals, and three segment identities. | +| 14-card20 | PASS | 1 | Quantitative X treated as ordered categories preserves all 20 positions and values. | +| 15-card30 | PASS | 1 | Transposed quantitative categories preserve the 30-position sequence and values. | +| 16-card5 | SKIP | 1 | No quantitative measure axis; the former occupancy matrix required a worksheet heatmap rather than a native chart. | +| 17-card25 | SKIP | 1 | No quantitative measure axis; the former date/group occupancy matrix required worksheet rendering. | +| 18-card5 | SKIP | 1 | No quantitative measure axis; native Excel bars cannot encode category-by-end-date occupancy. | + +## Grouped Bar Chart + +| Case | Status | Attempts | Finding / fix | +| --- | --- | ---: | --- | +| 00-card4 | PASS | 1 | Three native semantic series preserve all category/group/value tuples. | +| 01-card8 | PASS | 1 | Group-equals-category degenerates cleanly to one value per category. | +| 02-card90 | PASS | 1 | Dense three-series grouping preserves the retained categories, values, and complete legend. | +| 03-card6 | PASS | 1 | Ordered groups retain five light-to-dark native series and all values. | +| 04-card12 | FIXED | 3 | Temporal categories remain chronological; a balanced native gap clearly separates adjacent three-bar groups without isolating them. | +| 05-card5 | FIXED | 3 | Quantitative categories remain ordered; four bars stay adjacent within each group while a moderate gap separates groups. | +| 06-card24 | PASS | 1 | Horizontal grouped bars preserve category order, four series, and values. | +| 07-card30 | PASS | 1 | Horizontal temporal grouping preserves chronology, series identities, and values. | +| 08-card8 | SKIP | 0 | Continuous grouping is not a native clustered-bar series role. | +| 09-card5 | SKIP | 0 | Continuous grouping is not a native clustered-bar series role. | +| 10-card5 | SKIP | 0 | No quantitative measure axis for a native clustered bar chart. | +| 11-card5 | PASS | 1 | Group-equals-category degenerates to one semantic-colored bar per category; order and values match the reference. | +| 12-card6 | FIXED | 5 | Native clustered chart preserves all 14 region/channel values as four semantic series with null gaps and a complete Excel legend. | +| 13-card6 | FIXED | 3 | Native semantic series with null gaps preserve sparse channel identities, order, and values. | +| 14-card6 | FIXED | 3 | Alternate sparse ordering preserves all semantic series and values with the complete native legend. | + +## Stacked Bar Chart + +| Case | Status | Attempts | Finding / fix | +| --- | --- | ---: | --- | +| 00-card4 | PASS | 1 | Three native series preserve segment values and category totals. | +| 01-card15 | PASS | 1 | Five-series stacks preserve all segment identities, values, and totals. | +| 02-card80 | PASS | 1 | Dense three-series stacks retain the kept categories and complete legend. | +| 03-card6 | PASS | 1 | Ordered stack groups preserve sequential colors, values, and totals. | +| 04-card5 | SKIP | 0 | Continuous color cannot be represented as native stacked-bar series. | +| 05-card10 | PASS | 1 | Temporal stacks remain chronological with three semantic series. | +| 06-card20 | PASS | 1 | Dense temporal four-series stacks preserve chronology and totals. | +| 07-card10 | PASS | 1 | Quantitative category stacks preserve ordered positions and three series. | +| 08-card23 | PASS | 1 | Horizontal three-series stacks preserve category order and totals. | +| 09-card43 | PASS | 1 | Horizontal temporal stacks preserve chronological order and segment composition. | +| 10-card5 | SKIP | 0 | No quantitative measure axis for a native stacked bar chart. | + +## Line Chart + +| Case | Status | Attempts | Finding / fix | +| --- | --- | ---: | --- | +| 00-card30 | PASS | 1 | Native temporal line preserves the trajectory and chronological order. | +| 01-card50 | PASS | 1 | Four temporal series preserve their trajectories, identities, and legend. | +| 02-card100 | PASS | 1 | Eight temporal series preserve all trajectories and legend identities. | +| 03-card200 | PASS | 1 | Dense twenty-series temporal chart remains semantically complete in native Excel. | +| 04-card60 | PASS | 1 | Three temporal series preserve values, chronology, and identities. | +| 05-card30 | SKIP | 3 | Continuous color required a worksheet overlay; native Excel line series cannot encode it. | +| 06-card5 | PASS | 1 | Five ordinal stages preserve order and values in a native line. | +| 07-card12 | PASS | 1 | Four ordinal-stage series preserve trajectories and legend identities. | +| 08-card30 | PASS | 1 | Dense ordinal stages preserve order and the full trajectory. | +| 09-card5 | SKIP | 2 | Continuous color required worksheet markers; native Excel line series cannot encode it. | +| 10-card5 | SKIP | 2 | Categorical Y requires worksheet band geometry; native Excel line charts require quantitative Y. | +| 11-card12 | SKIP | 2 | Categorical Y cannot be represented by a native Excel line value axis. | +| 12-card30 | SKIP | 2 | Quantitative X with ordinal Y cannot be represented by a native Excel XY line chart. | +| 13-card30 | PASS | 1 | Native XY line preserves quantitative-X spacing, values, and trajectory. | +| 14-card50 | PASS | 1 | Three native XY series preserve quantitative-X trajectories and identities. | +| 15-card200 | PASS | 1 | Dense native XY series preserves all points and trajectory. | +| 16-card16 | PASS | 1 | Actual-to-forecast handoff remains continuous with solid and dashed native series. | +| 17-card13 | PASS | 1 | Three product trajectories preserve distinct actual/forecast dash handoffs. | + +## Area Chart + +| Case | Status | Attempts | Finding / fix | +| --- | --- | ---: | --- | +| 00-card30 | PASS | 1 | Native temporal area preserves the trajectory, chronology, and zero baseline. | +| 01-card24 | PASS | 1 | Four stacked temporal areas preserve series composition and totals. | +| 02-card60 | PASS | 1 | Eight stacked temporal areas preserve composition, chronology, and legend identities. | +| 03-card120 | PASS | 1 | Dense fifteen-series area preserves all stacked contributions and total progression. | +| 04-card40 | PASS | 1 | Three stacked temporal series preserve shape, composition, and totals. | +| 05-card60 | PASS | 1 | Alternate three-series temporal stack preserves all trajectories and totals. | +| 06-card5 | PASS | 1 | Five ordinal stages preserve order and area values. | +| 07-card12 | PASS | 1 | Four ordinal-stage areas preserve stack composition and totals. | +| 08-card30 | PASS | 1 | Dense ordinal stages preserve order and full area trajectory. | +| 09-card30 | FIXED | 2 | Resampled quantitative X onto a uniform native-Area grid and reduced the category axis to exact domain quartiles. | +| 10-card50 | FIXED | 3 | Uniform numeric resampling preserves three stacked series while replacing dense inferred labels with `0, 25, 50, 75, 100`. | +| 11-card200 | FIXED | 2 | Dense 200-point Area now preserves continuous-X spacing and readable quartile labels through bounded interpolation. | + +## Scatter Plot + +| Case | Status | Attempts | Finding / fix | +| --- | --- | ---: | --- | +| 00-card20 | PASS | 1 | Native Scatter preserves all quantitative X/Y positions. | +| 01-card20 | PASS | 1 | Three discrete segment series preserve positions and identities. | +| 02-card20 | SKIP | 1 | Quantitative color was dropped by the native chart; Office.js Scatter has no continuous color scale. | +| 03-card30 | SKIP | 1 | Temporal color became one series per timestamp; Office.js Scatter has no continuous color scale. | +| 04-card47 | PASS | 4 | Native Bubble preserves all positions and quantitative size ordering. | +| 05-card20 | PASS | 4 | Native Bubble preserves positions and four ordinal size levels. | +| 06-card15 | FIXED | 4 | Native Bubble preserves all 15 X/Y positions, three segment series, and quantitative size ordering without worksheet shapes. | +| 07-card30 | SKIP | 1 | Native Bubble preserves size but cannot also encode the continuous color scale. | +| 08-card20 | PASS | 5 | Twenty discrete Bubble series preserve positions, relative sizes, identities, and native legend entries. | +| 09-card91 | PASS | 1 | Native Scatter preserves the full 91-point distribution. | +| 10-card395 | PASS | 1 | Dense native Scatter preserves the full distribution without visible loss. | +| 11-card182 | PASS | 1 | Twenty discrete series preserve positions, colors, and legend identities. | +| 12-card96 | PASS | 1 | High-cardinality discrete series preserve positions and identity assignment in the expanded native legend. | +| 13-card10 | FIXED | 5 | Current native rerender applies focused X `20–100` and Y `0–100` bounds, removing the stale automatic `-20–120` margins while preserving positions and size ordering. | +| 14-card187 | FIXED | 5 | Current native rerender applies focused `0–100` bounds on both axes and preserves all positions and relative bubble sizes without worksheet shapes. | +| 15-card5 | SKIP | 0 | Native Excel Scatter requires quantitative X and Y axes. | +| 16-card5 | SKIP | 0 | Native Excel Scatter requires quantitative X and Y axes. | +| 17-card2 | SKIP | 0 | Native Excel Scatter requires quantitative X and Y axes. | +| 18-card60 | SKIP | 0 | Native Excel Scatter requires quantitative X and Y axes. | +| 19-card24 | SKIP | 0 | Native Excel Scatter requires quantitative X and Y axes. | +| 20-card23 | SKIP | 3 | Categorical Y required worksheet geometry; native Excel Bubble requires quantitative X and Y. | +| 21-card59 | SKIP | 0 | Native Excel Scatter requires quantitative X and Y axes. | +| 22-card5 | SKIP | 0 | Native Excel Scatter requires quantitative X and Y axes. | +| 23-card4 | SKIP | 0 | Native Excel Scatter requires quantitative X and Y axes. | +| 24-card15 | SKIP | 0 | Native Excel Scatter requires quantitative X and Y axes. | +| 25-card40 | SKIP | 0 | Office.js native charts do not expose Flint's shape encoding. | + +## Pie Chart + +| Case | Status | Attempts | Finding / fix | +| --- | --- | ---: | --- | +| 00-card0 | PASS | 1 | Native Pie preserves all four category proportions and identities. | +| 01-card0 | PASS | 1 | Ten-category Pie preserves proportions and legend identities. | +| 02-card0 | PASS | 1 | Twenty-category Pie remains complete with readable native legend entries. | +| 03-card0 | PASS | 1 | Dominant and tiny slices preserve their strong proportional contrast. | + +## Donut Chart + +| Case | Status | Attempts | Finding / fix | +| --- | --- | ---: | --- | +| 00-card0 | PASS | 1 | Native Doughnut preserves all four category proportions, identities, and the annular reading. | +| 01-card0 | PASS | 1 | Ten-category Doughnut preserves proportions and complete native legend identities. | +| 02-card0 | PASS | 1 | Twenty-category Doughnut remains complete with readable native legend entries. | +| 03-card0 | PASS | 1 | Dominant and tiny slices preserve their strong proportional contrast in the native ring. | + +## Histogram + +| Case | Status | Attempts | Finding / fix | +| --- | --- | ---: | --- | +| 00-card49 | PASS | 1 | Native columns preserve all bin boundaries and record counts. | +| 01-card42 | PASS | 1 | Stacked native columns preserve gender contributions and total counts per bin. | +| 02-card997 | PASS | 1 | Dense histogram preserves all ten bins and their count distribution. | + +## Boxplot + +| Case | Status | Attempts | Finding / fix | +| --- | --- | ---: | --- | +| 00-card5 | PASS | 1 | Five native boxes preserve all 150 raw observations, category order, medians, inclusive quartiles, and whiskers. | +| 01-card5 | PASS | 1 | Quantitative rank values are retained as five category labels with their complete score distributions. | +| 02-card12 | PASS | 1 | Twelve native boxes preserve all 600 salary observations and remain readable at the expanded width. | +| 03-card4 | SKIP | 1 | Flattened pair labels emit all eight boxes and separator gaps, but lose subgroup legend/color identity and native hierarchy; indexed point fills leave boxes uniform. | +| 04-card6 | SKIP | 1 | Four-subgroup distributions have the same native pooling/inversion blocker; multi-level headers become concatenated series names, not grouped category labels. | +| 05-card8 | SKIP | 1 | Five-subgroup distributions have the same native blocker; no one-chart range preserves both category boundaries and subgroup identity. | +| 06-card6 | SKIP | 1 | Redundant color still cannot be mapped to reliable native per-category coloring without changing the BoxWhisker range reading. | +| 07-card6 | SKIP | 1 | Nested color groups remain rejected: pair-per-column ranges create series of single-value ticks instead of one distribution per occupied pair. | +| 08-card6 | SKIP | 1 | Sparse 6x5: flattened labels emit exactly fourteen occupied boxes with gaps but no subgroup identity/hierarchy; point fills have no visible effect and full null padding exposes thirty identities. | +| 09-card6 | SKIP | 1 | Alternate nested groups share the proven native limitation and remain rejected rather than flattened or pooled. | + +The seven production gallery cases remain skipped, so the 159-case audit totals +are unchanged. + +## Heatmap + +| Case | Status | Attempts | Finding / fix | +| --- | --- | ---: | --- | +| 00-card5 | SKIP | 2 | Office.js has no native Heatmap chart type; worksheet conditional formatting is outside the backend contract. | +| 01-card10 | SKIP | 1 | Office.js has no native Heatmap chart type. | +| 02-card50 | SKIP | 1 | Office.js has no native Heatmap chart type. | +| 03-card12 | SKIP | 1 | Office.js has no native Heatmap chart type. | +| 04-card80 | SKIP | 2 | Office.js has no native Heatmap chart type. | +| 05-card5 | SKIP | 1 | Office.js has no native Heatmap chart type. | +| 06-card60 | SKIP | 2 | Office.js has no native Heatmap chart type. | +| 07-card80 | SKIP | 1 | Office.js has no native Heatmap chart type. | +| 08-card5 | SKIP | 1 | Office.js has no native Heatmap chart type. | + +## Radar Chart + +| Case | Status | Attempts | Finding / fix | +| --- | --- | ---: | --- | +| 00-card5 | FIXED | 2 | Replaced opaque `RadarFilled` with native `RadarMarkers`; the single-series profile and vertices remain clear. | +| 01-card6 | FIXED | 2 | Native outline series preserve both team profiles without the later series hiding the earlier polygon. | +| 02-card5 | PASS | 1 | Three native marker series preserve all product profiles, intersections, and legend identities. | +| 04-card5 | FIXED | 2 | Native outline series preserve both product profiles and keep all long metric labels visible. | +| 05-card8 | FIXED | 2 | Eight-axis outlines preserve both contrasting KPI profiles without solid-fill occlusion. | +| 06-card12 | FIXED | 2 | Twelve-axis outlines keep all three dense series distinguishable and retain complete labels and legend identities. | + +## Waterfall Chart + +| Case | Status | Attempts | Finding / fix | +| --- | --- | ---: | --- | +| 00-card6 | SKIP | 1 | The income-statement sequence requires a final total; Office.js does not expose Waterfall total-point semantics. | +| 01-card7 | SKIP | 1 | Explicit start/delta/end roles require a non-initial total point, which Office.js cannot mark. | +| 02-card7 | PASS | 1 | Native Waterfall preserves department order, positive and negative variances, cumulative levels, value labels, and connector lines. | +| 03-card14 | SKIP | 1 | The opening-to-closing monthly flow requires a closing total point, which Office.js cannot mark. | +| 04-card4 | PASS | 1 | Native Waterfall preserves quarterly order, signed changes, cumulative levels, value labels, and connector lines. | + +## Funnel Chart + +| Case | Status | Attempts | Finding / fix | +| --- | --- | ---: | --- | +| 00-card5 | PASS | 1 | Native Funnel preserves the descending sales-pipeline stage order, values, labels, and relative widths. | +| 01-card5 | PASS | 1 | Pre-sorted ascending values produce the intended inverted recruitment funnel with all stages and values preserved. | +| 02-card8 | PASS | 1 | Eight native stages remain legible and preserve the full marketing sequence and relative widths. | + +Funnel now explicitly emits centered white 11-point value labels over a single +Office blue series fill. The existing real-Excel cases already demonstrate that +this placement remains readable on both wide and narrow stages; a refreshed +render is pending taskpane availability to verify the explicit font properties. + +## Pyramid Chart (audit pending) + +The compiler emits Flint's two-group population pyramid as a native 2D +`BarStacked` chart with one mirrored series, one positive series, symmetric +numeric bounds, absolute-value tick labels, and stable blue/red group colors. +Seven valid gallery fixtures and one intentional negative-value rejection case +are generated under `evaluations/inputs/pyramid-chart`. Compiler, type, build, and +Office.js generator tests pass. Real-Excel visual qualification remains pending +because the macOS add-in taskpane did not resume polling during this audit run. + +## Treemap + +| Case | Status | Attempts | Finding / fix | +| --- | --- | ---: | --- | +| 00-card0 | PASS | 1 | Flat native Treemap preserves all sector labels and market-cap area relationships with Excel-native packing. | +| 01-card0 | FIXED | 2 | Hierarchy columns now count as category levels rather than series; Region parents, Country leaves, and revenue areas all render natively. | +| 02-card0 | PASS | 1 | Fifteen native leaves preserve labels and relative areas without crowding failures. | + +## Sunburst Chart + +| Case | Status | Attempts | Finding / fix | +| --- | --- | ---: | --- | +| 00-card0 | PASS | 1 | Flat native Sunburst preserves every budget category and proportional allocation. | +| 01-card0 | PASS | 1 | Department parents and Team leaves occupy the correct two native rings with preserved values and labels. | +| 02-card0 | PASS | 1 | Four continent parents and sixteen country leaves retain hierarchy, values, and readable ring geometry. | + +## Connected Scatter Plot + +| Case | Status | Attempts | Finding / fix | +| --- | --- | ---: | --- | +| 00-card9 | PASS | 1 | Native XY lines preserve the ten-year non-monotonic unemployment/inflation trajectory in explicit Year order. | +| 01-card21 | PASS | 1 | Three native color series preserve country identities, all points, and independent ordered trajectories. | +| 02-card12 | PASS | 1 | ISO-date ordering preserves the complete monthly price/volume trajectory instead of sorting by X. | +| 03-card12 | PASS | 1 | The defining self-crossing figure-eight follows Step order and retains its central crossing. | +| 04-card15 | PASS | 1 | Two experiment series preserve numeric Step order, values, markers, and legend identities. | +| 05-card4 | PASS | 1 | The minimal four-point trajectory preserves its explicit non-monotonic sequence. | +| 06-card35 | PASS | 1 | The dense 35-point spiral preserves every marker and the complete inward path. | +| 07-card24 | SKIP | 0 | Native Excel can render multiple color series, but Flint's unlegended detail trajectory role is intentionally rejected rather than promoted to a visible legend. | + +## Audit notes + +- Excel-native styling is allowed to differ from Vega-Lite palettes, but semantic roles and the visual reading must agree. +- Every successful output must be created by `sheet.charts.add(...)` and captured by `chart.getImage()`; ranges, shapes, and composite images are not backend output. +- Native Bubble charts replace the former worksheet point composites. The current Scatter rerender confirms explicit focused axis bounds are applied in real Excel. +- Native BoxWhisker consumes Flint's raw category/value observations and computes inclusive quartiles in Excel. Color-grouped subgroup boxes remain explicitly unsupported pending a faithful native range mapping. +- Native Waterfall is supported for delta sequences and an initial total. Office.js does not expose Excel's “Set as Total” point command, so later/final totals are rejected. +- Native Doughnut preserves part-to-whole semantics and applies Flint's inner radius through `ChartSeries.doughnutHoleSize`. +- Native Radar normalizes each metric by its Flint-compatible nice maximum because Excel exposes one shared radial scale. The category labels retain those maxima so the resulting polygon preserves Flint's per-metric geometry without hiding the original scale. Excel's UI and OOXML can store transparent series fills, but the direct Office.js `ChartFill` API exposes only solid-color operations. Flint therefore renders filled Radar requests as `RadarMarkers` to prevent series occlusion. A proof workbook with DrawingML `` confirmed the native capability; importing generated OOXML worksheets is deferred because it would be a separate rendering path from the current `charts.add()` architecture. +- Native Funnel, Treemap, and Sunburst use Flint's ECharts implementations as audit references because those chart identities have no Vega-Lite template. Native geometry, packing, and palette may differ while order, hierarchy, labels, and value/area readings must agree. +- Native Connected Scatter sorts each trajectory by its explicit order field before binding `XYScatterLines`; sorting by X would corrupt loops and backtracking paths. Discrete color is supported as native series, while unlegended detail remains an explicit gap. +- Native Pareto is not supported. The first bounded `Pareto` probe caused Excel for Mac to exit before Office.js returned a PNG or catchable error. Its executable probe and renderer aliases were removed; the server and taskpane retain only a pre-render quarantine for stale or external jobs. +- Bullet remains deferred after a bounded Office.js probe: a faithful target tick needs a mixed bar/scatter chart with secondary-axis alignment and custom marker geometry, which is not a modest extension of the current one-family native renderer. +- Dynamic-layout audit: six real Excel charts confirm that the host applies Flint's optimized dimensions within a 320×220 to 1600×900 render envelope. All tested rows survive; Bar sizing changes regime between 24 and 80 categories rather than growing monotonically, while the tested Line date/series matrix grows steadily. +- Facet audit: production `assembleExcel` rejects `column` and `row` centrally. An experimental 20-chart Office.js composition successfully reproduced column, row, 2×2, and wrapped 5×2 grids after imposing shared global numeric scales. Faceting therefore remains a future worksheet-level multi-chart artifact, not one native chart. +- Any row still failing after 10 focused repair attempts becomes `SKIP` with its blocker recorded here. diff --git a/test-harness/excel/evaluations/layout-facet-audit.mjs b/test-harness/excel/evaluations/layout-facet-audit.mjs new file mode 100644 index 00000000..5cda460b --- /dev/null +++ b/test-harness/excel/evaluations/layout-facet-audit.mjs @@ -0,0 +1,337 @@ +#!/usr/bin/env node +// @ts-nocheck + +import { execFileSync } from 'node:child_process'; +import { mkdirSync, rmSync, writeFileSync } from 'node:fs'; +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { renderChart } from 'flint-chart-mcp/render'; +import { assembleExcel } from 'flint-chart/excel'; +import { renderExcelArtifact } from './render-client.mjs'; + +const here = dirname(fileURLToPath(import.meta.url)); +const outDir = join(here, 'out', 'layout-facet-audit'); +const tempDir = join(outDir, 'temp'); +const scale = 3; +const clamp = (value, minimum, maximum) => Math.max(minimum, Math.min(maximum, Math.round(value))); + +rmSync(outDir, { recursive: true, force: true }); +mkdirSync(tempDir, { recursive: true }); + +function runMagick(args) { + execFileSync('magick', args, { stdio: 'pipe' }); +} + +function barInput(count) { + return { + data: { + values: Array.from({ length: count }, (_value, index) => ({ + Category: `Category ${index + 1}`, + Value: 40 + ((index * 37) % 180), + })), + }, + semantic_types: { Category: 'Category', Value: 'Quantity' }, + chart_spec: { + chartType: 'Bar Chart', + encodings: { x: 'Category', y: 'Value' }, + baseSize: { width: 400, height: 300 }, + }, + }; +} + +function lineInput(dateCount, seriesCount) { + const values = []; + for (let seriesIndex = 0; seriesIndex < seriesCount; seriesIndex += 1) { + for (let dateIndex = 0; dateIndex < dateCount; dateIndex += 1) { + const date = new Date(Date.UTC(2020, 0, 1 + dateIndex)); + values.push({ + Date: date.toISOString().slice(0, 10), + Series: `Series ${seriesIndex + 1}`, + Value: Math.round(100 + seriesIndex * 18 + dateIndex * 1.7 + Math.sin((dateIndex + seriesIndex) / 4) * 24), + }); + } + } + return { + data: { values }, + semantic_types: { Date: 'Date', Series: 'Category', Value: 'Quantity' }, + chart_spec: { + chartType: 'Line Chart', + encodings: { x: 'Date', y: 'Value', color: 'Series' }, + baseSize: { width: 400, height: 300 }, + }, + }; +} + +const dynamicCases = [ + { name: 'bar-04', label: 'Bar · 4 categories', family: 'bar', input: barInput(4) }, + { name: 'bar-24', label: 'Bar · 24 categories', family: 'bar', input: barInput(24) }, + { name: 'bar-80', label: 'Bar · 80 categories', family: 'bar', input: barInput(80) }, + { name: 'line-12x1', label: 'Line · 12 dates × 1 series', family: 'line', input: lineInput(12, 1) }, + { name: 'line-60x8', label: 'Line · 60 dates × 8 series', family: 'line', input: lineInput(60, 8) }, + { name: 'line-120x20', label: 'Line · 120 dates × 20 series', family: 'line', input: lineInput(120, 20) }, +]; + +async function runDynamicAudit() { + const results = []; + for (const item of dynamicCases) { + const reference = await renderChart(item.input, 'vegalite', { format: 'png', scale }); + const spec = assembleExcel(item.input); + const authoredSize = { width: spec.width, height: spec.height }; + spec.width = clamp(reference.width, 320, 1600); + spec.height = clamp(reference.height, 220, 900); + const excel = await renderExcelArtifact(spec, { scale }); + const referencePath = join(outDir, `${item.name}.reference.png`); + const excelPath = join(outDir, `${item.name}.excel.png`); + writeFileSync(referencePath, reference.buffer); + writeFileSync(excelPath, excel); + results.push({ + name: item.name, + label: item.label, + family: item.family, + authoredSize, + optimizedSize: { width: reference.width, height: reference.height }, + appliedExcelSize: { width: spec.width, height: spec.height }, + excelType: spec.chartType, + retainedRows: spec.data.length - 1, + }); + console.log(` ✓ ${item.label}: ${reference.width}×${reference.height} → Excel ${spec.width}×${spec.height}`); + } + + const barCases = results.filter((result) => result.family === 'bar'); + if (barCases[1].optimizedSize.width <= barCases[0].optimizedSize.width) { + throw new Error('bar layout did not stretch for the moderate-cardinality case'); + } + if (barCases.some((result, index) => result.retainedRows !== [4, 24, 80][index])) { + throw new Error('bar layout dropped data while changing cardinality regimes'); + } + for (const result of results) { + if (result.appliedExcelSize.width < 320 || result.appliedExcelSize.width > 1600 + || result.appliedExcelSize.height < 220 || result.appliedExcelSize.height > 900) { + throw new Error(`${result.name} escaped the Excel audit size bounds`); + } + } + const lineCases = results.filter((result) => result.family === 'line'); + for (let index = 1; index < lineCases.length; index += 1) { + const previous = lineCases[index - 1].optimizedSize; + const current = lineCases[index].optimizedSize; + if (current.width * current.height < previous.width * previous.height) { + throw new Error(`line optimized area decreased from ${lineCases[index - 1].name} to ${lineCases[index].name}`); + } + } + + for (let page = 0; page < 2; page += 1) { + const pageCases = results.slice(page * 3, page * 3 + 3); + const rows = []; + const header = join(tempDir, `dynamic-header-${page}.png`); + runMagick(['-size', '2000x100', '-background', 'white', '-fill', 'black', '-font', 'Helvetica-Bold', '-pointsize', '26', '-gravity', 'center', `label:Dynamic layout audit · page ${page + 1}`, header]); + rows.push(header); + for (const result of pageCases) { + const label = join(tempDir, `dynamic-${result.name}-label.png`); + const reference = join(tempDir, `dynamic-${result.name}-reference.png`); + const excel = join(tempDir, `dynamic-${result.name}-excel.png`); + const row = join(tempDir, `dynamic-${result.name}-row.png`); + const sizeLabel = `${result.label}\nFlint ${result.optimizedSize.width}×${result.optimizedSize.height}\nExcel ${result.appliedExcelSize.width}×${result.appliedExcelSize.height}`; + runMagick(['-size', '300x600', '-background', 'white', '-fill', 'black', '-font', 'Helvetica', '-pointsize', '20', '-gravity', 'center', `label:${sizeLabel}`, label]); + runMagick([join(outDir, `${result.name}.reference.png`), '-resize', '850x580', '-background', 'white', '-gravity', 'center', '-extent', '850x600', reference]); + runMagick([join(outDir, `${result.name}.excel.png`), '-resize', '850x580', '-background', 'white', '-gravity', 'center', '-extent', '850x600', excel]); + runMagick([label, reference, excel, '+append', row]); + rows.push(row); + } + runMagick([...rows, '-append', join(outDir, `dynamic-layout-${page + 1}.png`)]); + } + return results; +} + +function facetInput(name) { + if (name === 'column-bar') { + const values = []; + for (const region of ['North', 'Central', 'South']) { + for (const category of ['Consumer', 'Corporate', 'Home Office', 'Reseller']) { + values.push({ Region: region, Category: category, Value: 60 + ((values.length * 47) % 320) }); + } + } + return { + data: { values }, + semantic_types: { Region: 'Category', Category: 'Category', Value: 'Amount' }, + chart_spec: { chartType: 'Bar Chart', encodings: { x: 'Category', y: 'Value', column: 'Region' }, baseSize: { width: 400, height: 300 } }, + }; + } + if (name === 'row-scatter') { + const values = []; + for (const group of ['Group A', 'Group B', 'Group C']) { + for (let index = 0; index < 18; index += 1) { + values.push({ Group: group, X: 20 + index * 4 + group.length, Y: 30 + ((index * 17 + group.charCodeAt(6)) % 70) }); + } + } + return { + data: { values }, + semantic_types: { Group: 'Category', X: 'Quantity', Y: 'Quantity' }, + chart_spec: { chartType: 'Scatter Plot', encodings: { x: 'X', y: 'Y', row: 'Group' }, baseSize: { width: 400, height: 300 } }, + }; + } + if (name === 'grid-bar') { + const values = []; + for (const region of ['North', 'South']) { + for (const channel of ['Online', 'Retail']) { + for (const category of ['A', 'B', 'C', 'D']) { + values.push({ Region: region, Channel: channel, Category: category, Value: 50 + ((values.length * 31) % 240) }); + } + } + } + return { + data: { values }, + semantic_types: { Region: 'Category', Channel: 'Category', Category: 'Category', Value: 'Amount' }, + chart_spec: { chartType: 'Bar Chart', encodings: { x: 'Category', y: 'Value', column: 'Region', row: 'Channel' }, baseSize: { width: 400, height: 300 } }, + }; + } + + const values = []; + for (const region of ['North', 'South', 'East', 'West', 'Central', 'Pacific', 'Mountain', 'Atlantic', 'Gulf', 'Midwest']) { + for (let month = 0; month < 12; month += 1) { + values.push({ Region: region, Month: `M${month + 1}`, Value: 80 + ((month * 23 + region.length * 17) % 170) }); + } + } + return { + data: { values }, + semantic_types: { Region: 'Category', Month: 'Month', Value: 'Quantity' }, + chart_spec: { chartType: 'Line Chart', encodings: { x: 'Month', y: 'Value', column: 'Region' }, baseSize: { width: 400, height: 300 } }, + options: { minSubplotSize: 180 }, + }; +} + +const facetCases = [ + { name: 'column-bar', label: 'Column facet · 3 bar panels' }, + { name: 'row-scatter', label: 'Row facet · 3 scatter panels' }, + { name: 'grid-bar', label: 'Column × row facet · 2×2 bar panels' }, + { name: 'wrapped-line', label: 'Wrapped column facet · 10 line panels' }, +]; + +function distinct(values, field) { + return [...new Set(values.map((row) => String(row[field])))]; +} + +function sharedNumericAxis(values, zero = false) { + const finite = values.map(Number).filter(Number.isFinite); + if (finite.length === 0) return {}; + const minimum = zero ? 0 : Math.min(...finite); + const maximum = Math.max(...finite); + const span = Math.max(1, maximum - minimum); + const rough = span / 5; + const power = 10 ** Math.floor(Math.log10(rough)); + const fraction = rough / power; + const step = (fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 5 ? 5 : 10) * power; + const lower = zero ? 0 : Math.floor(minimum / step) * step; + const upperTick = Math.ceil(maximum / step) * step; + return { + minimumScale: lower, + maximumScale: Math.abs(upperTick - maximum) < 1e-9 ? maximum + step * 0.25 : upperTick, + majorUnit: step, + }; +} + +async function runFacetAudit() { + const results = []; + for (const item of facetCases) { + const input = facetInput(item.name); + const reference = await renderChart(input, 'vegalite', { format: 'png', scale }); + const referencePath = join(outDir, `${item.name}.reference.png`); + writeFileSync(referencePath, reference.buffer); + + let rejection; + try { + assembleExcel(input); + throw new Error('faceted input unexpectedly assembled as one native chart'); + } catch (error) { + rejection = String(error.message || error); + if (!rejection.includes('does not support faceting')) throw error; + } + + const columnField = typeof input.chart_spec.encodings.column === 'string' ? input.chart_spec.encodings.column : input.chart_spec.encodings.column?.field; + const rowField = typeof input.chart_spec.encodings.row === 'string' ? input.chart_spec.encodings.row : input.chart_spec.encodings.row?.field; + const xField = typeof input.chart_spec.encodings.x === 'string' ? input.chart_spec.encodings.x : input.chart_spec.encodings.x?.field; + const yField = typeof input.chart_spec.encodings.y === 'string' ? input.chart_spec.encodings.y : input.chart_spec.encodings.y?.field; + const sharedCategoryAxis = input.chart_spec.chartType === 'Scatter Plot' + ? sharedNumericAxis(input.data.values.map((row) => row[xField])) + : undefined; + const sharedValueAxis = sharedNumericAxis( + input.data.values.map((row) => row[yField]), + input.chart_spec.chartType === 'Bar Chart', + ); + const columns = columnField ? distinct(input.data.values, columnField) : [null]; + const rows = rowField ? distinct(input.data.values, rowField) : [null]; + const panels = []; + for (const rowValue of rows) { + for (const columnValue of columns) { + const panelRows = input.data.values.filter((record) => + (!columnField || String(record[columnField]) === columnValue) + && (!rowField || String(record[rowField]) === rowValue), + ); + const encodings = { ...input.chart_spec.encodings }; + delete encodings.column; + delete encodings.row; + const child = { + ...input, + data: { values: panelRows }, + chart_spec: { ...input.chart_spec, encodings, baseSize: { width: 300, height: 220 } }, + }; + const childReference = await renderChart(child, 'vegalite', { format: 'png', scale: 1 }); + const spec = assembleExcel(child); + if (sharedCategoryAxis) spec.categoryAxis = { ...spec.categoryAxis, ...sharedCategoryAxis }; + spec.valueAxis = { ...spec.valueAxis, ...sharedValueAxis }; + spec.width = clamp(childReference.width, 280, 420); + spec.height = clamp(childReference.height, 200, 300); + const facetLabel = [rowValue, columnValue].filter(Boolean).join(' · '); + spec.title = `${facetLabel} — ${spec.title}`; + const path = join(tempDir, `${item.name}-panel-${panels.length}.png`); + writeFileSync(path, await renderExcelArtifact(spec, { scale })); + panels.push(path); + } + } + + const gridColumns = item.name === 'row-scatter' ? 1 : item.name === 'wrapped-line' ? 5 : columns.length; + const gridRows = Math.ceil(panels.length / gridColumns); + const compositionPath = join(outDir, `${item.name}.excel-composition.png`); + runMagick(['montage', ...panels, '-tile', `${gridColumns}x${gridRows}`, '-geometry', '900x650+16+16', '-background', 'white', compositionPath]); + results.push({ + name: item.name, + label: item.label, + referenceSize: { width: reference.width, height: reference.height }, + panelCount: panels.length, + grid: `${gridColumns}x${gridRows}`, + productionResult: 'rejected', + rejection, + sharedCategoryAxis, + sharedValueAxis, + }); + console.log(` ✓ ${item.label}: production rejected; experimental ${gridColumns}×${gridRows} composition rendered`); + } + + for (let page = 0; page < 2; page += 1) { + const pageCases = results.slice(page * 2, page * 2 + 2); + const rows = []; + const header = join(tempDir, `facet-header-${page}.png`); + runMagick(['-size', '2000x100', '-background', 'white', '-fill', 'black', '-font', 'Helvetica-Bold', '-pointsize', '26', '-gravity', 'center', `label:Facet audit · canonical Flint vs experimental native-chart composition · page ${page + 1}`, header]); + rows.push(header); + for (const result of pageCases) { + const label = join(tempDir, `facet-${result.name}-label.png`); + const reference = join(tempDir, `facet-${result.name}-reference.png`); + const excel = join(tempDir, `facet-${result.name}-excel.png`); + const row = join(tempDir, `facet-${result.name}-row.png`); + runMagick(['-size', '300x700', '-background', 'white', '-fill', 'black', '-font', 'Helvetica', '-pointsize', '19', '-gravity', 'center', `label:${result.label}\n${result.panelCount} native charts · ${result.grid}\nProduction: explicit rejection`, label]); + runMagick([join(outDir, `${result.name}.reference.png`), '-resize', '850x680', '-background', 'white', '-gravity', 'center', '-extent', '850x700', reference]); + runMagick([join(outDir, `${result.name}.excel-composition.png`), '-resize', '850x680', '-background', 'white', '-gravity', 'center', '-extent', '850x700', excel]); + runMagick([label, reference, excel, '+append', row]); + rows.push(row); + } + runMagick([...rows, '-append', join(outDir, `facet-layout-${page + 1}.png`)]); + } + return results; +} + +console.log('Dynamic layout audit'); +const dynamic = await runDynamicAudit(); +console.log('Facet audit'); +const facets = await runFacetAudit(); +writeFileSync(join(outDir, 'summary.json'), JSON.stringify({ dynamic, facets }, null, 2) + '\n'); +rmSync(tempDir, { recursive: true, force: true }); +console.log(`\nWrote ${dynamic.length} dynamic cases and ${facets.length} facet cases to ${outDir}`); \ No newline at end of file diff --git a/test-harness/excel/evaluations/make-audit-sheets.mjs b/test-harness/excel/evaluations/make-audit-sheets.mjs new file mode 100644 index 00000000..fc89004f --- /dev/null +++ b/test-harness/excel/evaluations/make-audit-sheets.mjs @@ -0,0 +1,185 @@ +import fs from 'fs'; +import path, { dirname } from 'path'; +import { execFileSync } from 'child_process'; +import { fileURLToPath } from 'url'; + +/** @typedef {{ type: string, name: string, ok: boolean, skipped?: boolean, referenceBackend?: string }} GalleryResult */ + +const here = dirname(fileURLToPath(import.meta.url)); +const summaryPath = path.join(here, 'out', 'gallery', 'summary.json'); +const outDir = path.join(here, 'out', 'audit-sheets'); +const familyFilter = process.argv[2]; + +if (!familyFilter) fs.rmSync(outDir, { recursive: true, force: true }); +fs.mkdirSync(outDir, { recursive: true }); + +const summary = /** @type {GalleryResult[]} */ (JSON.parse(fs.readFileSync(summaryPath, 'utf8'))); +const allOkEntries = summary.filter(e => e.ok === true && !e.skipped); +const okEntries = familyFilter + ? allOkEntries.filter(e => e.type === familyFilter) + : allOkEntries; +if (familyFilter && okEntries.length === 0) { + throw new Error(`No successful gallery entries for family "${familyFilter}".`); +} + +console.log(`Total OK entries loaded from summary: ${okEntries.length}`); + +// Group by family (type) +/** @type {Record} */ +const groups = {}; +for (const entry of okEntries) { + if (!groups[entry.type]) { + groups[entry.type] = []; + } + groups[entry.type].push(entry); +} + +// Print and track verification +let totalPairsProcessed = 0; +const allSeenCases = new Set(); +/** @type {Array<{ name: string, cases: string[] }>} */ +const allSheets = []; + +// Helper function to run magick with arguments array +/** @param {string[]} args */ +function runMagick(args) { + try { + execFileSync('magick', args, { stdio: 'pipe' }); + } catch (error) { + const err = /** @type {Error & { stderr?: Buffer }} */ (error); + console.error(`Error running magick with args: ${args.join(' ')}`); + console.error(err.stderr ? err.stderr.toString() : err.message); + throw err; + } +} + +// Ensure temp directory exists +const tempDir = path.join(here, 'out', 'temp-sheets'); +fs.rmSync(tempDir, { recursive: true, force: true }); +fs.mkdirSync(tempDir, { recursive: true }); + +// Process each family +for (const [family, cases] of Object.entries(groups)) { + console.log(`\nFamily: ${family} (${cases.length} cases)`); + + // Sort cases to have standard ordering + cases.sort((a, b) => a.name.localeCompare(b.name)); + + // Chunk cases into groups of at most 4 + const chunkSize = 4; + const chunks = []; + for (let i = 0; i < cases.length; i += chunkSize) { + chunks.push(cases.slice(i, i + chunkSize)); + } + + for (let chunkIdx = 0; chunkIdx < chunks.length; chunkIdx++) { + const chunk = chunks[chunkIdx]; + const sheetNum = String(chunkIdx + 1).padStart(2, '0'); + const sheetName = `${family}-${sheetNum}.png`; + const sheetPath = path.join(outDir, sheetName); + allSheets.push({ name: sheetName, cases: chunk.map(c => c.name) }); + + console.log(` Generating sheet ${sheetName} with ${chunk.length} cases:`); + const rowPaths = []; + + // Generate Column Headers + const col0HeaderPath = path.join(tempDir, `header_col0.png`); + const col1HeaderPath = path.join(tempDir, `header_col1.png`); + const col2HeaderPath = path.join(tempDir, `header_col2.png`); + const headerRowPath = path.join(tempDir, `header_row.png`); + + runMagick(['-size', '200x100', '-background', 'white', '-fill', 'black', '-font', 'Helvetica-Bold', '-pointsize', '24', '-gravity', 'center', 'label:Case', col0HeaderPath]); + const referenceLabel = cases[0]?.referenceBackend === 'echarts' ? 'ECharts' : 'Vega-Lite'; + runMagick(['-size', '900x100', '-background', 'white', '-fill', 'black', '-font', 'Helvetica-Bold', '-pointsize', '28', '-gravity', 'center', `label:${referenceLabel}`, col1HeaderPath]); + runMagick(['-size', '900x100', '-background', 'white', '-fill', 'black', '-font', 'Helvetica-Bold', '-pointsize', '28', '-gravity', 'center', 'label:Excel', col2HeaderPath]); + + runMagick([col0HeaderPath, col1HeaderPath, col2HeaderPath, '+append', headerRowPath]); + rowPaths.push(headerRowPath); + + for (let i = 0; i < chunk.length; i++) { + const entry = chunk[i]; + const caseName = entry.name; + + if (allSeenCases.has(`${family}/${caseName}`)) { + console.error(`Duplicate case detected: ${family}/${caseName}`); + process.exit(1); + } + allSeenCases.add(`${family}/${caseName}`); + totalPairsProcessed++; + + console.log(` - ${caseName}`); + + const vlSrc = path.join(here, 'out', 'gallery', family, `${caseName}.vl.png`); + const excelSrc = path.join(here, 'out', 'gallery', family, `${caseName}.excel.png`); + + const labelDest = path.join(tempDir, `label_${i}.png`); + const vlDest = path.join(tempDir, `vl_${i}.png`); + const excelDest = path.join(tempDir, `excel_${i}.png`); + const rowDest = path.join(tempDir, `row_${i}.png`); + + // 1. Create label + runMagick(['-size', '200x600', '-background', 'white', '-fill', 'black', '-font', 'Helvetica-Bold', '-pointsize', '18', '-gravity', 'center', `label:${caseName}`, labelDest]); + + // 2. Normalize Vega-Lite + runMagick([vlSrc, '-resize', '900x600', '-background', 'white', '-gravity', 'center', '-extent', '900x600', vlDest]); + + // 3. Normalize Excel + runMagick([excelSrc, '-resize', '900x600', '-background', 'white', '-gravity', 'center', '-extent', '900x600', excelDest]); + + // 4. Combine into single row + runMagick([labelDest, vlDest, excelDest, '+append', rowDest]); + rowPaths.push(rowDest); + } + + // Combine header and rows vertically + runMagick([...rowPaths, '-append', sheetPath]); + } +} + +// Clean up temp dir +try { + fs.rmSync(tempDir, { recursive: true, force: true }); +} catch (e) { + // Ignore cleanup errors +} + +console.log('\n--- VERIFICATION REPORT ---'); +console.log(`Total sheets generated: ${allSheets.length}`); +console.log(`Total cases processed and verified: ${totalPairsProcessed}`); +if (totalPairsProcessed === okEntries.length) { + console.log(`SUCCESS: Exactly ${okEntries.length} supported case pairs were included!`); +} else { + console.error(`ERROR: Found ${totalPairsProcessed} cases instead of ${okEntries.length}.`); + process.exit(1); +} + +// Double check to make sure no omissions or duplicates relative to summary ok:true cases +const okCaseKeys = new Set(okEntries.map(e => `${e.type}/${e.name}`)); +let mismatchFound = false; + +for (const key of okCaseKeys) { + if (!allSeenCases.has(key)) { + console.error(`MISSING: ${key} was not included in any sheet.`); + mismatchFound = true; + } +} + +for (const key of allSeenCases) { + if (!okCaseKeys.has(key)) { + console.error(`EXTRA: ${key} was included but not marked as OK in summary.`); + mismatchFound = true; + } +} + +if (!mismatchFound) { + console.log('SUCCESS: Perfect 1-to-1 matching with ok=true entries in summary.json with zero duplicates/omissions!'); +} else { + console.error('ERROR: Mismatch found in included cases.'); + process.exit(1); +} + +// Print full detailed list of sheets and cases for easy auditing +console.log('\n--- FULL SHEETS AND CASES LIST ---'); +for (const s of allSheets) { + console.log(`Sheet: ${s.name} (${s.cases.length} cases): [${s.cases.join(', ')}]`); +} diff --git a/test-harness/excel/evaluations/render-client.mjs b/test-harness/excel/evaluations/render-client.mjs new file mode 100644 index 00000000..d7586ac1 --- /dev/null +++ b/test-harness/excel/evaluations/render-client.mjs @@ -0,0 +1,158 @@ +// @ts-check + +const DEFAULT_SERVER = 'https://localhost:3000'; +const HEALTH_CHECK_INTERVAL_MS = 2_000; + +/** @param {number} milliseconds */ +function wait(milliseconds) { + return new Promise((resolve) => setTimeout(resolve, milliseconds)); +} + +/** + * @param {string} server + * @returns {Promise<{ instance_id: string, worker_ready: boolean }>} + */ +async function readHealth(server) { + const response = await fetch(`${server}/health`); + if (!response.ok) throw new Error(`Office runner health check failed with HTTP ${response.status}.`); + const health = /** @type {{ instance_id?: unknown, worker_ready?: unknown }} */ (await response.json()); + if (typeof health.instance_id !== 'string' || typeof health.worker_ready !== 'boolean') { + throw new Error('Office runner returned an invalid health response.'); + } + return { instance_id: health.instance_id, worker_ready: health.worker_ready }; +} + +/** + * @param {string} path + * @param {unknown} body + * @param {{ server?: string, timeoutMs?: number, retries?: number }} options + * @returns {Promise<{ png: Buffer, inspection: unknown | null }>} + */ +async function enqueueAndCollect(path, body, options) { + const server = options.server ?? DEFAULT_SERVER; + const timeoutMs = options.timeoutMs ?? 60_000; + const retries = options.retries ?? 3; + let initialHealth; + try { + initialHealth = await readHealth(server); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Excel worker is unreachable at ${server}: ${message}`); + } + if (!initialHealth.worker_ready) { + throw new Error('Excel task pane is not connected; open the Flint Render add-in before rendering.'); + } + let enqueue; + + for (let attempt = 1; attempt <= retries; attempt += 1) { + try { + enqueue = await fetch(`${server}${path}`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(body), + }); + break; + } catch (error) { + if (attempt === retries) throw error; + await wait(500 * attempt); + } + } + + if (!enqueue) throw new Error(`Excel worker is unreachable at ${server}.`); + if (!enqueue.ok) { + const message = await enqueue.text(); + throw new Error(`Excel worker rejected the job (${enqueue.status}): ${message}`); + } + const payload = /** @type {{ id?: unknown }} */ (await enqueue.json()); + if (!Number.isInteger(payload.id)) throw new Error('Excel worker returned an invalid job id.'); + const id = /** @type {number} */ (payload.id); + const deadline = Date.now() + timeoutMs; + let nextHealthCheckAt = Date.now() + HEALTH_CHECK_INTERVAL_MS; + + while (Date.now() < deadline) { + let response; + try { + response = await fetch(`${server}/result?id=${id}`); + } catch (error) { + if (Date.now() + 500 >= deadline) throw error; + await wait(300); + continue; + } + if (response.status === 200) { + const result = /** @type {{ pngBase64?: unknown, inspection?: unknown, error?: unknown }} */ (await response.json()); + if (result.error) throw new Error(String(result.error)); + if (typeof result.pngBase64 !== 'string' || result.pngBase64.length === 0) { + throw new Error('Excel worker returned no PNG payload.'); + } + return { + png: Buffer.from(result.pngBase64, 'base64'), + inspection: result.inspection ?? null, + }; + } + if (response.status !== 204) { + throw new Error(`Excel worker result polling failed with HTTP ${response.status}.`); + } + if (Date.now() >= nextHealthCheckAt) { + const health = await readHealth(server); + if (health.instance_id !== initialHealth.instance_id) { + throw new Error('Office runner restarted while rendering; the queued job was lost and must be retried.'); + } + if (!health.worker_ready) { + await fetch(`${server}/cancel?id=${id}`, { method: 'POST' }).catch(() => {}); + throw new Error('Excel task pane disconnected while rendering.'); + } + nextHealthCheckAt = Date.now() + HEALTH_CHECK_INTERVAL_MS; + } + await wait(300); + } + + await fetch(`${server}/cancel?id=${id}`, { method: 'POST' }).catch(() => {}); + throw new Error('Timed out waiting for the Excel Office.js worker.'); +} + +/** + * Render one versioned Excel artifact through the running Office add-in worker. + * + * @param {unknown} artifact + * @param {{ server?: string, scale?: number, timeoutMs?: number, retries?: number, inspectNativeChart?: boolean }} [options] + * @returns {Promise<{ png: Buffer, inspection: unknown | null }>} + */ +export async function renderExcelArtifactDetailed(artifact, options = {}) { + return enqueueAndCollect('/enqueue', { + artifact, + renderOptions: { + scale: options.scale ?? 3, + inspectNativeChart: options.inspectNativeChart ?? false, + }, + }, options); +} + +/** + * Render one evaluation-only Office.js program over transformed rows. + * + * @param {string} officejsCode + * @param {Array>} data + * @param {{ server?: string, scale?: number, timeoutMs?: number, retries?: number, inspectNativeChart?: boolean }} [options] + * @returns {Promise<{ png: Buffer, inspection: unknown | null }>} + */ +export async function renderOfficeJsProgramDetailed(officejsCode, data, options = {}) { + return enqueueAndCollect('/enqueue-program', { + officejsCode, + data, + renderOptions: { + scale: options.scale ?? 2, + inspectNativeChart: options.inspectNativeChart ?? false, + }, + }, options); +} + +/** + * Render one artifact and return only its PNG bytes. + * + * @param {unknown} artifact + * @param {{ server?: string, scale?: number, timeoutMs?: number, retries?: number, inspectNativeChart?: boolean }} [options] + * @returns {Promise} + */ +export async function renderExcelArtifact(artifact, options = {}) { + return (await renderExcelArtifactDetailed(artifact, options)).png; +} diff --git a/test-harness/excel/evaluations/update-examples.mjs b/test-harness/excel/evaluations/update-examples.mjs new file mode 100644 index 00000000..c645f647 --- /dev/null +++ b/test-harness/excel/evaluations/update-examples.mjs @@ -0,0 +1,30 @@ +// @ts-check + +import { copyFileSync, existsSync, mkdirSync } from 'node:fs'; +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const here = dirname(fileURLToPath(import.meta.url)); +const examplesDir = join(here, 'examples'); + +const snapshots = [ + ['out/gallery/waterfall-chart/02-card7.excel.png', 'waterfall.png'], + ['out/gallery/pyramid-chart/00-card18.excel.png', 'pyramid.png'], + ['out/gallery/grouped-bar-chart/00-card4.excel.png', 'grouped-bar.png'], + ['out/gallery/line-chart/14-card50.excel.png', 'multi-series-line.png'], + ['out/gallery/area-chart/01-card24.excel.png', 'stacked-area.png'], + ['out/gallery/radar-chart/05-card8.excel.png', 'radar.png'], + ['out/gallery/treemap/01-card0.excel.png', 'treemap.png'], + ['out/gallery/sunburst-chart/02-card0.excel.png', 'sunburst.png'], + ['out/candlestick-audit/advanced-90-day-dense.excel.png', 'candlestick.png'], +]; + +mkdirSync(examplesDir, { recursive: true }); +for (const [sourceRelative, destinationName] of snapshots) { + const source = join(here, sourceRelative); + if (!existsSync(source)) { + throw new Error(`Missing evaluation output: ${sourceRelative}`); + } + copyFileSync(source, join(examplesDir, destinationName)); + console.log(`updated examples/${destinationName}`); +} diff --git a/test-harness/excel/office-runner/officejs/icon-16.png b/test-harness/excel/office-runner/officejs/icon-16.png new file mode 100644 index 00000000..8665db76 Binary files /dev/null and b/test-harness/excel/office-runner/officejs/icon-16.png differ diff --git a/test-harness/excel/office-runner/officejs/icon-32.png b/test-harness/excel/office-runner/officejs/icon-32.png new file mode 100644 index 00000000..776dfe27 Binary files /dev/null and b/test-harness/excel/office-runner/officejs/icon-32.png differ diff --git a/test-harness/excel/office-runner/officejs/icon-80.png b/test-harness/excel/office-runner/officejs/icon-80.png new file mode 100644 index 00000000..c38979c4 Binary files /dev/null and b/test-harness/excel/office-runner/officejs/icon-80.png differ diff --git a/test-harness/excel/office-runner/officejs/icon.svg b/test-harness/excel/office-runner/officejs/icon.svg new file mode 100644 index 00000000..49fe1007 --- /dev/null +++ b/test-harness/excel/office-runner/officejs/icon.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/test-harness/excel/office-runner/officejs/manifest.xml b/test-harness/excel/office-runner/officejs/manifest.xml new file mode 100644 index 00000000..c933cb0e --- /dev/null +++ b/test-harness/excel/office-runner/officejs/manifest.xml @@ -0,0 +1,93 @@ + + + + 2e3cb77a-afbe-499c-9c60-9b0dca994868 + 1.0.0.0 + Flint + en-US + + + + + + + https://localhost:3000 + + + + + + + + + + + + + ReadWriteDocument + + + + + + + +