chore: import upstream snapshot with attribution
publish / version_or_publish (push) Has been cancelled
storybook-build / changes (push) Has been cancelled
storybook-build / :storybook-build (push) Has been cancelled
Sync Gradio Skills to Hugging Face / sync-skills (push) Has been cancelled
functional / changes (push) Has been cancelled
functional / build-frontend (push) Has been cancelled
functional / functional-test-SSR=false (push) Has been cancelled
functional / functional-reload (push) Has been cancelled
js / changes (push) Has been cancelled
js / js-test (push) Has been cancelled
docs-build / changes (push) Has been cancelled
docs-build / docs-build (push) Has been cancelled
docs-build / website-build (push) Has been cancelled
functional / functional-test-SSR=true (push) Has been cancelled
hygiene / hygiene-test (push) Has been cancelled
python / changes (push) Has been cancelled
python / build (push) Has been cancelled
python / test-ubuntu-latest-flaky (push) Has been cancelled
python / test-ubuntu-latest-not-flaky (push) Has been cancelled
python / test-windows-latest-flaky (push) Has been cancelled
python / test-windows-latest-not-flaky (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:17:32 +08:00
commit adf0d17497
3085 changed files with 456962 additions and 0 deletions
+644
View File
@@ -0,0 +1,644 @@
# @gradio/nativeplot
## 0.12.1
### Dependency updates
- @gradio/statustracker@0.15.1
- @gradio/icons@0.16.0
- @gradio/atoms@0.26.0
## 0.12.0
### Features
- [#13526](https://github.com/gradio-app/gradio/pull/13526) [`53cb4ca`](https://github.com/gradio-app/gradio/commit/53cb4cae1ec3521e9170d12867253516413ba37a) - Run `pnpm lint` and `pnpm ts:check` on CI. Thanks @abidlabs!
### Fixes
- [#13533](https://github.com/gradio-app/gradio/pull/13533) [`e5ec1ca`](https://github.com/gradio-app/gradio/commit/e5ec1ca66c45e7e3a057b75ac2b8b86660b2827b) - Fix fullscreen button not working in ImageSlider, interactive Image, native plots, and AnnotatedImage. Thanks @hysts!
### Dependency updates
- @gradio/atoms@0.25.0
- @gradio/statustracker@0.15.0
- @gradio/utils@0.13.0
- @gradio/theme@0.6.2
## 0.11.0
### Features
- [#13502](https://github.com/gradio-app/gradio/pull/13502) [`429faeb`](https://github.com/gradio-app/gradio/commit/429faeb643fb1afc1722c0f63fafa11603f2c87f) - Ensure every component dispatches a `change` event when its value changes. Thanks @abidlabs!
### Fixes
- [#13523](https://github.com/gradio-app/gradio/pull/13523) [`1b611f8`](https://github.com/gradio-app/gradio/commit/1b611f89fb85016a7879020098bd0faedf80ae5e) - Fixes grouped accordion borders and empty plot legends. Thanks @dawoodkhan82!
## 0.10.7
### Dependency updates
- @gradio/atoms@0.24.0
- @gradio/statustracker@0.14.1
## 0.10.6
### Dependency updates
- @gradio/atoms@0.23.1
- @gradio/statustracker@0.14.0
## 0.10.5
### Dependency updates
- @gradio/utils@0.12.2
- @gradio/atoms@0.23.0
- @gradio/statustracker@0.13.1
## 0.10.4
### Dependency updates
- @gradio/utils@0.12.1
- @gradio/statustracker@0.13.0
## 0.10.3
### Dependency updates
- @gradio/statustracker@0.12.5
- @gradio/utils@0.12.0
- @gradio/atoms@0.22.2
## 0.10.2
### Dependency updates
- @gradio/utils@0.11.3
- @gradio/atoms@0.22.0
- @gradio/statustracker@0.12.4
## 0.10.1
### Dependency updates
- @gradio/atoms@0.21.0
- @gradio/statustracker@0.12.3
## 0.10.0
### Features
- [#12801](https://github.com/gradio-app/gradio/pull/12801) [`07c5280`](https://github.com/gradio-app/gradio/commit/07c5280ecea8cef2326ab6fff910ad7bee3d5132) - Add `axis_format` parameters for native plots, and fix SSR mode. Thanks @abidlabs!
### Fixes
- [#12800](https://github.com/gradio-app/gradio/pull/12800) [`7a1c321`](https://github.com/gradio-app/gradio/commit/7a1c321b6546ba05a353488f5133e8262c4a8a39) - Bump svelte/kit for security reasons. Thanks @freddyaboulton!
- [#12779](https://github.com/gradio-app/gradio/pull/12779) [`ea2d3e9`](https://github.com/gradio-app/gradio/commit/ea2d3e985a8b42d188e551f517c5825c00790628) - Migrate Audio + Upload + Atoms to Svelte 5. Thanks @dawoodkhan82!
### Dependency updates
- @gradio/statustracker@0.12.2
- @gradio/atoms@0.20.1
- @gradio/utils@0.11.2
- @gradio/icons@0.15.1
- @gradio/theme@0.6.1
## 0.9.3
### Fixes
- [#12627](https://github.com/gradio-app/gradio/pull/12627) [`fa75712`](https://github.com/gradio-app/gradio/commit/fa75712a3257e0e09bfce7abbd4f40fa54f6db98) - Add custom buttons to `gr.Dropdown(multiselect=True)` and `gr.LinePlot` and other native plots. Thanks @abidlabs!
### Dependency updates
- @gradio/utils@0.11.1
- @gradio/theme@0.6.0
## 0.9.2
### Dependency updates
- @gradio/atoms@0.20.0
- @gradio/utils@0.11.0
- @gradio/statustracker@0.12.1
## 0.9.1
### Fixes
- [#12515](https://github.com/gradio-app/gradio/pull/12515) [`0892c29`](https://github.com/gradio-app/gradio/commit/0892c297b35742ed5cabf64d0846fd36ae02ecea) - Fix plot Rendering + visibility bug. Thanks @freddyaboulton!
## 0.9.0
### Dependency updates
- @gradio/utils@0.10.4
## 0.9.0
### Features
- [#11908](https://github.com/gradio-app/gradio/pull/11908) [`029034f`](https://github.com/gradio-app/gradio/commit/029034f7853ea018d110efe9b7e2ef7d1407091c) - Fix some plot issues in 6.0
- [#11908](https://github.com/gradio-app/gradio/pull/11908) [`029034f`](https://github.com/gradio-app/gradio/commit/029034f7853ea018d110efe9b7e2ef7d1407091c) - Clear Error statuses
- [#11908](https://github.com/gradio-app/gradio/pull/11908) [`029034f`](https://github.com/gradio-app/gradio/commit/029034f7853ea018d110efe9b7e2ef7d1407091c) - Fixes for long legends in native plots
- [#11908](https://github.com/gradio-app/gradio/pull/11908) [`029034f`](https://github.com/gradio-app/gradio/commit/029034f7853ea018d110efe9b7e2ef7d1407091c) - Handle special characters in native plot column names
- [#11908](https://github.com/gradio-app/gradio/pull/11908) [`029034f`](https://github.com/gradio-app/gradio/commit/029034f7853ea018d110efe9b7e2ef7d1407091c) - Allow setting x limits independently in native plots
- [#12438](https://github.com/gradio-app/gradio/pull/12438) [`25ffc03`](https://github.com/gradio-app/gradio/commit/25ffc0398f8feb43d817c02b2ab970c16de6d797) - Svelte5 migration and bugfix
### Dependencies
- @gradio/atoms@0.19.0
- @gradio/icons@0.15.0
- @gradio/statustracker@0.12.0
- @gradio/theme@0.5.0
- @gradio/utils@0.10.3
## 0.9.0-dev.2
### Dependency updates
- @gradio/atoms@0.19.0-dev.1
- @gradio/statustracker@0.12.0-dev.1
## 0.9.0-dev.1
### Features
- [#12100](https://github.com/gradio-app/gradio/pull/12100) [`75cfe0e`](https://github.com/gradio-app/gradio/commit/75cfe0efea3cbfe04b3f587609db03d01831e2dd) - Fixes for long legends in native plots. Thanks @abidlabs!
### Dependency updates
- @gradio/atoms@0.18.2-dev.0
- @gradio/utils@0.10.3-dev.0
- @gradio/statustracker@0.12.0-dev.0
- @gradio/icons@0.15.0-dev.0
- @gradio/theme@0.5.0-dev.0
## 0.9.0-dev.0
### Features
- [#12064](https://github.com/gradio-app/gradio/pull/12064) [`90dfb44`](https://github.com/gradio-app/gradio/commit/90dfb446876f3aa2c135e2c58f2f088eb5185311) - Handle special characters in native plot column names. Thanks @abidlabs!
- [#12096](https://github.com/gradio-app/gradio/pull/12096) [`ed08086`](https://github.com/gradio-app/gradio/commit/ed08086f90909438551c3b841dff2e757d9b09d2) - Allow setting x limits independently in native plots. Thanks @abidlabs!
## 0.8.0
### Features
- [#12003](https://github.com/gradio-app/gradio/pull/12003) [`abc4dbe`](https://github.com/gradio-app/gradio/commit/abc4dbe95d45f82cd8eaa0e6d53d26183eb283d6) - Add export button to native plot components. Thanks @abidlabs!
## 0.7.6
### Dependency updates
- @gradio/atoms@0.18.1
## 0.7.6
### Fixes
- [#11784](https://github.com/gradio-app/gradio/pull/11784) [`d9dd3f5`](https://github.com/gradio-app/gradio/commit/d9dd3f54b7fb34cf7118e549d39fc63937ca3489) - Add "hidden" option to component's `visible` kwarg to render but visually hide the component. Thanks @pngwn!
### Dependency updates
- @gradio/statustracker@0.11.1
- @gradio/atoms@0.18.0
## 0.7.5
### Features
- [#11843](https://github.com/gradio-app/gradio/pull/11843) [`a30f485`](https://github.com/gradio-app/gradio/commit/a30f485e1d906f97c64b578ca4570405bc50542e) - Fix native plots with long y-axis titles. Thanks @abidlabs!
### Dependency updates
- @gradio/icons@0.14.0
- @gradio/atoms@0.17.0
- @gradio/statustracker@0.11.0
## 0.7.4
### Dependency updates
- @gradio/statustracker@0.10.18
## 0.7.4
### Dependency updates
- @gradio/icons@0.13.1
## 0.7.4
### Dependency updates
- @gradio/statustracker@0.10.17
- @gradio/atoms@0.16.5
- @gradio/icons@0.13.0
## 0.7.3
### Dependency updates
- @gradio/statustracker@0.10.16
- @gradio/atoms@0.16.4
## 0.7.2
### Dependency updates
- @gradio/statustracker@0.10.15
## 0.7.1
### Dependency updates
- @gradio/atoms@0.16.3
- @gradio/statustracker@0.10.14
## 0.7.0
### Features
- [#11442](https://github.com/gradio-app/gradio/pull/11442) [`f114f7f`](https://github.com/gradio-app/gradio/commit/f114f7f56b50b0176526a13ad3fcf2a81c077491) - Downsample heavy line plots. Thanks @aliabid94!
## 0.6.3
### Features
- [#11418](https://github.com/gradio-app/gradio/pull/11418) [`e398c51`](https://github.com/gradio-app/gradio/commit/e398c51e610713d7dc1ed0a1ee43d7d313b8ca6a) - Full screen plots take full height. Thanks @aliabid94!
## 0.6.2
### Fixes
- [#11387](https://github.com/gradio-app/gradio/pull/11387) [`8245afc`](https://github.com/gradio-app/gradio/commit/8245afc669501e1e5f0d619f452455f68a3b7667) - Define root URL in frontend. Thanks @aliabid94!
### Dependency updates
- @gradio/statustracker@0.10.13
- @gradio/atoms@0.16.2
## 0.6.1
### Dependency updates
- @gradio/statustracker@0.10.12
## 0.6.1
### Features
- [#11372](https://github.com/gradio-app/gradio/pull/11372) [`7282c9e`](https://github.com/gradio-app/gradio/commit/7282c9eb1ed0ce8608f9a1157f3243e8c1b0f597) - Plot re-render fixes. Thanks @aliabid94!
## 0.6.0
### Features
- [#11306](https://github.com/gradio-app/gradio/pull/11306) [`6cd608d`](https://github.com/gradio-app/gradio/commit/6cd608d8f9b1a142c58f0d2db861845ec267f705) - Improvements for plots and event listeners in re-renders. Thanks @aliabid94!
## 0.5.17
### Dependency updates
- @gradio/statustracker@0.10.12
## 0.5.17
### Dependency updates
- @gradio/statustracker@0.10.12
## 0.5.16
### Features
- [#11177](https://github.com/gradio-app/gradio/pull/11177) [`3068196`](https://github.com/gradio-app/gradio/commit/3068196d47234fd1c1634f33b9ddfc089f5cbbe0) - Improved, smoother fullscreen mode for components. Thanks @aliabid94!
### Dependency updates
- @gradio/statustracker@0.10.11
- @gradio/atoms@0.16.1
## 0.5.15
### Features
- [#11183](https://github.com/gradio-app/gradio/pull/11183) [`ab0fbb3`](https://github.com/gradio-app/gradio/commit/ab0fbb32cdee752673313b5536c04eecadc1071e) - Plot brushing prevents chart refresh. Thanks @aliabid94!
## 0.5.14
### Dependency updates
- @gradio/statustracker@0.10.10
- @gradio/atoms@0.16.0
## 0.5.13
### Dependency updates
- @gradio/statustracker@0.10.9
- @gradio/atoms@0.15.2
- @gradio/utils@0.10.2
## 0.5.12
### Dependency updates
- @gradio/atoms@0.15.1
- @gradio/statustracker@0.10.8
- @gradio/icons@0.12.0
## 0.5.11
### Fixes
- [#10953](https://github.com/gradio-app/gradio/pull/10953) [`ede7428`](https://github.com/gradio-app/gradio/commit/ede74283d738f55e032a98fb1875605cb0b65d8a) - Fix gr.NativePlot sorting of labels as default behaviour. Thanks @Rafalex04!
### Dependency updates
- @gradio/statustracker@0.10.7
- @gradio/atoms@0.15.0
- @gradio/icons@0.11.0
## 0.5.10
### Dependency updates
- @gradio/atoms@0.14.1
- @gradio/statustracker@0.10.6
## 0.5.9
### Dependency updates
- @gradio/statustracker@0.10.5
- @gradio/atoms@0.14.0
## 0.5.8
### Dependency updates
- @gradio/statustracker@0.10.4
- @gradio/atoms@0.13.3
## 0.5.7
### Fixes
- [#10546](https://github.com/gradio-app/gradio/pull/10546) [`27155cf`](https://github.com/gradio-app/gradio/commit/27155cfc0ca49b8d2727f3271ff413105b4da59e) - Native Plot respects the height parameters. Thanks @freddyaboulton!
- [#10531](https://github.com/gradio-app/gradio/pull/10531) [`a18ac9c`](https://github.com/gradio-app/gradio/commit/a18ac9c56a67dbc0a1d0fb464fa12f531998b170) - Fix bug where plots wouldn't load when initial value provided. Thanks @freddyaboulton!
### Dependency updates
- @gradio/statustracker@0.10.3
- @gradio/atoms@0.13.2
- @gradio/utils@0.10.1
- @gradio/theme@0.4.0
## 0.5.6
### Dependency updates
- @gradio/statustracker@0.10.2
## 0.5.5
### Dependency updates
- @gradio/atoms@0.13.1
- @gradio/statustracker@0.10.1
- @gradio/icons@0.10.0
## 0.5.4
### Dependency updates
- @gradio/atoms@0.13.0
- @gradio/utils@0.10.0
- @gradio/icons@0.9.0
- @gradio/statustracker@0.10.0
## 0.5.3
### Dependency updates
- @gradio/statustracker@0.9.7
- @gradio/atoms@0.12.0
## 0.5.2
### Dependency updates
- @gradio/atoms@0.11.2
- @gradio/utils@0.9.0
- @gradio/statustracker@0.9.6
## 0.5.1
### Dependency updates
- @gradio/atoms@0.11.1
- @gradio/utils@0.8.0
- @gradio/statustracker@0.9.5
## 0.5.0
### Features
- [#9800](https://github.com/gradio-app/gradio/pull/9800) [`d1cfe1e`](https://github.com/gradio-app/gradio/commit/d1cfe1e9defa06f927aec2671656fe77514dd0fa) - Allow plot tooltip to show extra columns. Thanks @aliabid94!
### Dependency updates
- @gradio/statustracker@0.9.4
- @gradio/atoms@0.11.0
## 0.4.5
### Dependency updates
- @gradio/statustracker@0.9.3
- @gradio/atoms@0.10.1
## 0.4.4
### Dependency updates
- @gradio/statustracker@0.9.2
- @gradio/atoms@0.10.0
- @gradio/icons@0.8.1
## 0.4.3
### Dependency updates
- @gradio/statustracker@0.9.1
- @gradio/atoms@0.9.2
## 0.4.2
### Dependency updates
- @gradio/atoms@0.9.1
- @gradio/statustracker@0.9.0
## 0.4.1
### Dependency updates
- @gradio/statustracker@0.8.1
## 0.4.0
### Features
- [#8843](https://github.com/gradio-app/gradio/pull/8843) [`6f95286`](https://github.com/gradio-app/gradio/commit/6f95286337459efbccb95c9cfac63355669df9ee) - Allow `info=` to render markdown
- [#8843](https://github.com/gradio-app/gradio/pull/8843) [`6f95286`](https://github.com/gradio-app/gradio/commit/6f95286337459efbccb95c9cfac63355669df9ee) - Hide x axis labels
- [#8843](https://github.com/gradio-app/gradio/pull/8843) [`6f95286`](https://github.com/gradio-app/gradio/commit/6f95286337459efbccb95c9cfac63355669df9ee) - Fix plots
- [#8843](https://github.com/gradio-app/gradio/pull/8843) [`6f95286`](https://github.com/gradio-app/gradio/commit/6f95286337459efbccb95c9cfac63355669df9ee) - Ssr part 2
### Dependencies
- @gradio/atoms@0.9.0
- @gradio/icons@0.8.0
- @gradio/statustracker@0.8.0
- @gradio/utils@0.7.0
- @gradio/theme@0.3.0
## 0.4.0-beta.7
### Dependency updates
- @gradio/statustracker@0.8.0-beta.5
- @gradio/icons@0.8.0-beta.4
- @gradio/atoms@0.9.0-beta.5
## 0.4.0-beta.6
### Features
- [#9521](https://github.com/gradio-app/gradio/pull/9521) [`06ef22e`](https://github.com/gradio-app/gradio/commit/06ef22e83cdd27e7afb381396d153d9db3dea16e) - Allow `info=` to render markdown. Thanks @dawoodkhan82!
### Dependency updates
- @gradio/statustracker@0.8.0-beta.4
- @gradio/atoms@0.9.0-beta.4
## 0.4.0-beta.5
### Features
- [#9497](https://github.com/gradio-app/gradio/pull/9497) [`d826faa`](https://github.com/gradio-app/gradio/commit/d826faa8c2584cf0772d4e66b4073e33b83f3a00) - Hide x axis labels. Thanks @aliabid94!
## 0.4.0-beta.4
### Dependency updates
- @gradio/statustracker@0.8.0-beta.3
- @gradio/icons@0.8.0-beta.3
- @gradio/atoms@0.9.0-beta.3
## 0.4.0-beta.3
### Features
- [#9464](https://github.com/gradio-app/gradio/pull/9464) [`3ac5d9c`](https://github.com/gradio-app/gradio/commit/3ac5d9c972576d82bc365a6532e6e12f55441a30) - Fix plots. Thanks @pngwn!
### Dependency updates
- @gradio/statustracker@0.8.0-beta.2
## 0.4.0-beta.2
### Features
- [#9339](https://github.com/gradio-app/gradio/pull/9339) [`4c8c6f2`](https://github.com/gradio-app/gradio/commit/4c8c6f2fe603081941c5fdc43f48a0632b9f31ad) - Ssr part 2. Thanks @pngwn!
### Dependency updates
- @gradio/atoms@0.9.0-beta.2
- @gradio/icons@0.8.0-beta.2
- @gradio/statustracker@0.8.0-beta.2
- @gradio/utils@0.7.0-beta.2
## 0.3.2-beta.1
### Features
- [#9187](https://github.com/gradio-app/gradio/pull/9187) [`5bf00b7`](https://github.com/gradio-app/gradio/commit/5bf00b7524ebf399b48719120a49d15bb21bd65c) - make all component SSR compatible. Thanks @pngwn!
### Dependency updates
- @gradio/atoms@0.8.1-beta.1
- @gradio/icons@0.8.0-beta.1
- @gradio/statustracker@0.8.0-beta.1
- @gradio/utils@0.7.0-beta.1
- @gradio/theme@0.3.0-beta.1
## 0.3.2
### Fixes
- [#9163](https://github.com/gradio-app/gradio/pull/9163) [`2b6cbf2`](https://github.com/gradio-app/gradio/commit/2b6cbf25908e42cf027324e54ef2cc0baad11a91) - fix exports and generate types. Thanks @pngwn!
### Dependency updates
- @gradio/utils@0.6.1
- @gradio/statustracker@0.7.6
- @gradio/atoms@0.8.1
- @gradio/icons@0.7.2
- @gradio/theme@0.2.5
## 0.3.1
### Features
- [#9118](https://github.com/gradio-app/gradio/pull/9118) [`e1c404d`](https://github.com/gradio-app/gradio/commit/e1c404da1143fb52b659d03e028bdba1badf443d) - setup npm-previews of all packages. Thanks @pngwn!
### Dependency updates
- @gradio/utils@0.6.0
- @gradio/atoms@0.8.0
- @gradio/statustracker@0.7.5
- @gradio/theme@0.2.4
- @gradio/icons@0.7.1
## 0.3.0
### Features
- [#9064](https://github.com/gradio-app/gradio/pull/9064) [`4ba7b23`](https://github.com/gradio-app/gradio/commit/4ba7b238e22ac042de14a6b69aa9d61536ddffba) - Improve plot guide, add double clicking to plots. Thanks @aliabid94!
### Dependency updates
- @gradio/atoms@0.7.9
- @gradio/statustracker@0.7.4
- @gradio/icons@0.7.0
## 0.2.0
### Features
- [#8947](https://github.com/gradio-app/gradio/pull/8947) [`96d36d7`](https://github.com/gradio-app/gradio/commit/96d36d70ad3bee048027cfbf89533020a8aa6e63) - Restore plot label angles. Thanks @aliabid94!
- [#8907](https://github.com/gradio-app/gradio/pull/8907) [`9b42ba8`](https://github.com/gradio-app/gradio/commit/9b42ba8f1006c05d60a62450d3036ce0d6784f86) - Update guides esp plots. Thanks @aliabid94!
### Dependency updates
- @gradio/atoms@0.7.8
- @gradio/icons@0.6.1
- @gradio/utils@0.5.2
- @gradio/statustracker@0.7.3
## 0.1.0
### Features
- [#8807](https://github.com/gradio-app/gradio/pull/8807) [`a238af4`](https://github.com/gradio-app/gradio/commit/a238af4d688c4e030e37c2ef01d5c80d6d940912) - Refactor plots to drop `altair` and use `vega.js` directly. Thanks @aliabid94!
### Dependency updates
- @gradio/statustracker@0.7.2
- @gradio/atoms@0.7.7
+11
View File
@@ -0,0 +1,11 @@
<script lang="ts">
export let title: string | null;
export let x: string;
export let y: string;
</script>
{#if title}
{title}
{:else}
{x} x {y}
{/if}
+867
View File
@@ -0,0 +1,867 @@
<script lang="ts">
import { Gradio } from "@gradio/utils";
import { BlockTitle } from "@gradio/atoms";
import { Block } from "@gradio/atoms";
import {
FullscreenButton,
IconButtonWrapper,
IconButton
} from "@gradio/atoms";
import { StatusTracker } from "@gradio/statustracker";
import { onMount, untrack } from "svelte";
import { Download } from "@gradio/icons";
import type { TopLevelSpec as Spec } from "vega-lite";
import type { View } from "vega";
import { LineChart as LabelIcon } from "@gradio/icons";
import { Empty } from "@gradio/atoms";
import type { NativePlotProps, NativePlotEvents, PlotData } from "./types";
let props = $props();
const gradio = new Gradio<NativePlotEvents, NativePlotProps>(props);
gradio.watch_for_change();
let unique_colors = $derived.by(() => {
if (
!gradio.props.color ||
!gradio.props.value ||
gradio.props.value.datatypes[gradio.props.color] !== "nominal"
) {
return [];
}
const color_index = gradio.props.value.columns.indexOf(gradio.props.color);
if (color_index === -1) return [];
return Array.from(
new Set(gradio.props.value.data.map((row) => row[color_index]))
);
});
let x_lim = $derived(gradio.props.x_lim || null); // for some unknown reason, x_lim was getting set to undefined when used in re-render, so this line is needed
let y_lim = $derived(gradio.props.y_lim || null);
let x_start = $derived(x_lim?.[0] !== null ? x_lim?.[0] : undefined);
let x_end = $derived(x_lim?.[1] !== null ? x_lim?.[1] : undefined);
let y_start = $derived(y_lim?.[0] !== null ? y_lim?.[0] : undefined);
let y_end = $derived(y_lim?.[1] !== null ? y_lim?.[1] : undefined);
let fullscreen = $state(false);
function reformat_sort(
_sort: NativePlotProps["sort"]
):
| string
| "ascending"
| "descending"
| { field: string; order: "ascending" | "descending" }
| string[]
| null
| undefined {
if (_sort === "x") {
return "ascending";
} else if (_sort === "-x") {
return "descending";
} else if (_sort === "y") {
return { field: gradio.props.y, order: "ascending" };
} else if (_sort === "-y") {
return { field: gradio.props.y, order: "descending" };
} else if (_sort === null) {
return null;
} else if (Array.isArray(_sort)) {
return _sort;
}
}
let _sort = $derived(reformat_sort(gradio.props.sort));
let _data: {
[x: string]: string | number;
}[] = $state([]);
function escape_field_name(fieldName: string): string {
// Escape special characters in field names according to Vega-Lite spec:
// https://vega.github.io/vega-lite/docs/field.html
return fieldName
.replace(/\./g, "\\.")
.replace(/\[/g, "\\[")
.replace(/\]/g, "\\]");
}
let x_temporal = $derived(
gradio.props.value &&
gradio.props.value.datatypes[gradio.props.x] === "temporal"
);
let _x_lim = $derived(
x_temporal
? [
x_start !== undefined ? x_start * 1000 : null,
x_end !== undefined ? x_end * 1000 : null
]
: x_lim
);
let mouse_down_on_chart = $state(false);
const SUFFIX_DURATION: Record<string, number> = {
s: 1,
m: 60,
h: 60 * 60,
d: 24 * 60 * 60
};
let _x_bin = $derived(
gradio.props.x_bin
? typeof gradio.props.x_bin === "string"
? 1000 *
parseInt(
gradio.props.x_bin.substring(0, gradio.props.x_bin.length - 1)
) *
SUFFIX_DURATION[gradio.props.x_bin[gradio.props.x_bin.length - 1]]
: gradio.props.x_bin
: undefined
);
let _y_aggregate = $derived.by(() => {
if (gradio.props.value) {
if (gradio.props.value.mark === "point") {
const aggregating = _x_bin !== undefined;
return gradio.props.y_aggregate || aggregating ? "sum" : undefined;
} else {
return gradio.props.y_aggregate ? gradio.props.y_aggregate : "sum";
}
}
return undefined;
});
let aggregating = $derived.by(() => {
if (gradio.props.value) {
if (gradio.props.value.mark === "point") {
return _x_bin !== undefined;
} else {
return (
_x_bin !== undefined ||
gradio.props.value.datatypes[gradio.props.x] === "nominal"
);
}
}
return false;
});
function downsample(
data: PlotData["data"],
x_index: number,
y_index: number,
color_index: number | null,
x_start: number | undefined,
x_end: number | undefined
): PlotData["data"] {
if (
data.length < 1000 ||
gradio.props.x_bin !== null ||
gradio.props.value?.mark !== "line" ||
gradio.props.value?.datatypes[gradio.props.x] === "nominal"
) {
return data;
}
const bin_count = 250;
let min_max_bins_per_color: Record<
string,
[number | null, number, number | null, number][]
> = {};
if (x_start === undefined || x_end === undefined) {
data.forEach((row) => {
let x_value = row[x_index] as number;
if (x_start === undefined || x_value < x_start) {
x_start = x_value;
}
if (x_end === undefined || x_value > x_end) {
x_end = x_value;
}
});
}
if (x_start === undefined || x_end === undefined) {
return data;
}
const x_range = x_end - x_start;
const bin_size = x_range / bin_count;
data.forEach((row, i) => {
const x_value = row[x_index] as number;
const y_value = row[y_index] as number;
const color_value =
color_index !== null ? (row[color_index] as string) : "any";
const bin_index = Math.floor((x_value - (x_start as number)) / bin_size);
if (min_max_bins_per_color[color_value] === undefined) {
min_max_bins_per_color[color_value] = [];
}
min_max_bins_per_color[color_value][bin_index] = min_max_bins_per_color[
color_value
][bin_index] || [
null,
Number.POSITIVE_INFINITY,
null,
Number.NEGATIVE_INFINITY
];
if (y_value < min_max_bins_per_color[color_value][bin_index][1]) {
min_max_bins_per_color[color_value][bin_index][0] = i;
min_max_bins_per_color[color_value][bin_index][1] = y_value;
}
if (y_value > min_max_bins_per_color[color_value][bin_index][3]) {
min_max_bins_per_color[color_value][bin_index][2] = i;
min_max_bins_per_color[color_value][bin_index][3] = y_value;
}
});
const downsampled_data: PlotData["data"] = [];
Object.values(min_max_bins_per_color).forEach((bins) => {
bins.forEach(([min_index, _, max_index, __]) => {
let indices: number[] = [];
if (min_index !== null && max_index !== null) {
indices = [
Math.min(min_index, max_index),
Math.max(min_index, max_index)
];
} else if (min_index !== null) {
indices = [min_index];
} else if (max_index !== null) {
indices = [max_index];
}
indices.forEach((index) => {
downsampled_data.push(data[index]);
});
});
});
return downsampled_data;
}
function reformat_data(
data: PlotData,
x_start: number | undefined,
x_end: number | undefined
): {
[x: string]: string | number;
}[] {
let x_index = data.columns.indexOf(gradio.props.x);
let y_index = data.columns.indexOf(gradio.props.y);
let color_index = gradio.props.color
? data.columns.indexOf(gradio.props.color)
: null;
let datatable = data.data;
if (x_start !== undefined && x_end !== undefined) {
const time_factor =
data.datatypes[gradio.props.x] === "temporal" ? 1000 : 1;
const _x_start = x_start * time_factor;
const _x_end = x_end * time_factor;
let largest_before_start: Record<string, [number, number]> = {};
let smallest_after_end: Record<string, [number, number]> = {};
const _datatable = datatable.filter((row, i) => {
const x_value = row[x_index] as number;
const color_value =
color_index !== null ? (row[color_index] as string) : "any";
if (
x_value < _x_start &&
(largest_before_start[color_value] === undefined ||
x_value > largest_before_start[color_value][1])
) {
largest_before_start[color_value] = [i, x_value];
}
if (
x_value > _x_end &&
(smallest_after_end[color_value] === undefined ||
x_value < smallest_after_end[color_value][1])
) {
smallest_after_end[color_value] = [i, x_value];
}
return x_value >= _x_start && x_value <= _x_end;
});
datatable = [
...Object.values(largest_before_start).map(([i, _]) => datatable[i]),
...downsample(
_datatable,
x_index,
y_index,
color_index,
_x_start,
_x_end
),
...Object.values(smallest_after_end).map(([i, _]) => datatable[i])
];
} else {
datatable = downsample(
datatable,
x_index,
y_index,
color_index,
undefined,
undefined
);
}
if (gradio.props.tooltip == "all" || Array.isArray(gradio.props.tooltip)) {
return datatable.map((row) => {
const obj: { [x: string]: string | number } = {};
data.columns.forEach((col, i) => {
obj[col] = row[i];
});
return obj;
});
}
return datatable.map((row) => {
const obj = {
[gradio.props.x]: row[x_index],
[gradio.props.y]: row[y_index]
};
if (gradio.props.color && color_index !== null) {
obj[gradio.props.color] = row[color_index];
}
return obj;
});
}
$effect(() => {
_data = gradio.props.value
? reformat_data(gradio.props.value, x_start, x_end)
: [];
});
let old_value = $state<PlotData | null>(gradio.props.value);
$effect(() => {
if (old_value !== gradio.props.value && view) {
old_value = gradio.props.value;
view.data("data", _data).runAsync();
}
});
const is_browser = typeof window !== "undefined";
let chart_element = $state<HTMLDivElement>();
let computed_style = $derived(
chart_element ? window.getComputedStyle(chart_element) : null
);
let view = $state<View>();
let mounted = $state(false);
let old_width = $state<number>(0);
let old_height = $state<number>(0);
let resizeObserver = $state<ResizeObserver>();
let vegaEmbed: typeof import("vega-embed").default;
async function load_chart(): Promise<void> {
if (mouse_down_on_chart) {
refresh_pending = true;
return;
}
if (view) {
view.finalize();
}
if (!gradio.props.value || !chart_element) return;
old_width = chart_element.offsetWidth;
old_height = chart_element.offsetHeight;
const spec = create_vega_lite_spec();
if (!spec) return;
resizeObserver = new ResizeObserver((el) => {
if (!el[0].target || !(el[0].target instanceof HTMLElement)) return;
if (
old_width === 0 &&
chart_element!.offsetWidth !== 0 &&
gradio.props.value!.datatypes[gradio.props.x] === "nominal"
) {
// a bug where when a nominal chart is first loaded, the width is 0, it doesn't resize
load_chart();
} else {
const width_change = Math.abs(old_width - el[0].target.offsetWidth);
const height_change = Math.abs(old_height - el[0].target.offsetHeight);
if (width_change > 100 || height_change > 100) {
old_width = el[0].target.offsetWidth;
old_height = el[0].target.offsetHeight;
load_chart();
} else if (view) {
view.signal("width", el[0].target.offsetWidth).run();
if (fullscreen) {
view.signal("height", el[0].target.offsetHeight).run();
}
}
}
});
if (!vegaEmbed) {
vegaEmbed = (await import("vega-embed")).default;
}
if (!chart_element) return;
vegaEmbed(chart_element, spec, { actions: false, renderer: "svg" }).then(
function (result) {
view = result.view;
resizeObserver!.observe(chart_element!);
var debounceTimeout: NodeJS.Timeout;
var lastSelectTime = 0;
view.addEventListener("dblclick", () => {
gradio.dispatch("double_click");
});
// prevent double-clicks from highlighting text
chart_element!.addEventListener(
"mousedown",
function (e) {
if (e.detail > 1) {
e.preventDefault();
}
},
false
);
if (gradio.props._selectable) {
view.addSignalListener("brush", function (_, value) {
if (Date.now() - lastSelectTime < 1000) return;
mouse_down_on_chart = true;
if (Object.keys(value).length === 0) return;
clearTimeout(debounceTimeout);
let range: [number, number] = value[Object.keys(value)[0]];
if (x_temporal) {
range = [range[0] / 1000, range[1] / 1000];
}
debounceTimeout = setTimeout(function () {
mouse_down_on_chart = false;
lastSelectTime = Date.now();
gradio.dispatch("select", {
value: range,
index: range,
selected: true
});
if (refresh_pending) {
refresh_pending = false;
load_chart();
}
}, 250);
});
}
}
);
}
let refresh_pending = $state(false);
onMount(() => {
mounted = true;
return () => {
mounted = false;
if (view) {
view.finalize();
}
if (resizeObserver) {
resizeObserver.disconnect();
}
};
});
function export_chart(): void {
if (!view || !computed_style) return;
const current_view = view;
const block_background = computed_style.getPropertyValue(
"--block-background-fill"
);
const export_background = block_background || "white";
current_view.background(export_background).run();
current_view
.toImageURL("png", 2)
.then(function (url) {
current_view.background("transparent").run();
const link = document.createElement("a");
link.setAttribute("href", url);
link.setAttribute("download", "chart.png");
link.style.display = "none";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
})
.catch(function (err) {
console.error("Export failed:", err);
current_view.background("transparent").run();
});
}
let _color_map = $derived(JSON.stringify(gradio.props.color_map));
$effect(() => {
// Track dependencies to trigger chart reload
void gradio.props.title;
void gradio.props.x_title;
void gradio.props.y_title;
void gradio.props.color_title;
void gradio.props.x;
void gradio.props.y;
void gradio.props.color;
void gradio.props.x_bin;
void _y_aggregate;
void _color_map;
void gradio.props.colors_in_legend;
void x_start;
void x_end;
void y_start;
void y_end;
void gradio.props.caption;
void gradio.props.sort;
void mounted;
void chart_element;
void fullscreen;
void computed_style;
if (mounted && chart_element) {
untrack(() => {
load_chart();
});
}
});
function create_vega_lite_spec(): Spec | null {
if (!gradio.props.value || !computed_style) return null;
let accent_color = computed_style.getPropertyValue("--color-accent");
let body_text_color = computed_style.getPropertyValue("--body-text-color");
let borderColorPrimary = computed_style.getPropertyValue(
"--border-color-primary"
);
let font_family = computed_style.fontFamily;
let title_weight = computed_style.getPropertyValue(
"--block-title-text-weight"
) as
| "bold"
| "normal"
| 100
| 200
| 300
| 400
| 500
| 600
| 700
| 800
| 900;
const font_to_px_val = (font: string): number => {
return font.endsWith("px") ? parseFloat(font.slice(0, -2)) : 12;
};
let text_size_md = font_to_px_val(
computed_style.getPropertyValue("--text-md")
);
let text_size_sm = font_to_px_val(
computed_style.getPropertyValue("--text-sm")
);
return {
$schema: "https://vega.github.io/schema/vega-lite/v5.17.0.json",
background: "transparent",
config: {
autosize: { type: "fit", contains: "padding" },
axis: {
labelFont: font_family,
labelColor: body_text_color,
titleFont: font_family,
titleColor: body_text_color,
titlePadding: 8,
tickColor: borderColorPrimary,
labelFontSize: text_size_sm,
gridColor: borderColorPrimary,
titleFontWeight: "normal",
titleFontSize: text_size_sm,
labelFontWeight: "normal",
domain: false,
labelAngle: 0,
titleLimit: (chart_element?.offsetHeight ?? 0) * 0.8
},
legend: {
labelColor: body_text_color,
labelFont: font_family,
titleColor: body_text_color,
titleFont: font_family,
titleFontWeight: "normal",
titleFontSize: text_size_sm,
labelFontWeight: "normal",
offset: 2
},
title: {
color: body_text_color,
font: font_family,
fontSize: text_size_md,
fontWeight: title_weight,
anchor: "middle"
},
view: { stroke: borderColorPrimary },
mark: {
stroke: gradio.props.value.mark !== "bar" ? accent_color : undefined,
fill: gradio.props.value.mark === "bar" ? accent_color : undefined,
cursor: "crosshair"
}
},
data: { name: "data" },
datasets: {
data: _data
},
layer: [
"plot",
...(gradio.props.value.mark === "line" ? ["hover"] : [])
].map((mode) => {
return {
encoding: {
size:
gradio.props.value!.mark === "line"
? mode == "plot"
? {
condition: {
empty: false,
param: "hoverPlot",
value: 3
},
value: 2
}
: {
condition: { empty: false, param: "hover", value: 100 },
value: 0
}
: undefined,
opacity:
mode === "plot"
? undefined
: {
condition: { empty: false, param: "hover", value: 1 },
value: 0
},
x: {
axis: {
...(gradio.props.x_label_angle !== null && {
labelAngle: gradio.props.x_label_angle
}),
labels: gradio.props.x_axis_labels_visible,
ticks: gradio.props.x_axis_labels_visible,
...(gradio.props.x_axis_format !== null && {
format: gradio.props.x_axis_format
})
},
field: escape_field_name(gradio.props.x),
title: gradio.props.x_title || gradio.props.x,
type: gradio.props.value!.datatypes[gradio.props.x],
scale: {
zero: false,
domainMin: _x_lim?.[0] !== null ? _x_lim?.[0] : undefined,
domainMax: _x_lim?.[1] !== null ? _x_lim?.[1] : undefined
},
bin: _x_bin ? { step: _x_bin } : undefined,
sort: _sort
},
y: {
axis: {
...(gradio.props.y_label_angle && {
labelAngle: gradio.props.y_label_angle
}),
...(gradio.props.y_axis_format !== null && {
format: gradio.props.y_axis_format
})
},
field: escape_field_name(gradio.props.y),
title: gradio.props.y_title || gradio.props.y,
type: gradio.props.value!.datatypes[gradio.props.y],
scale: {
zero: false,
domainMin: y_start ?? undefined,
domainMax: y_end ?? undefined
},
aggregate: aggregating ? _y_aggregate : undefined
},
color: gradio.props.color
? {
field: escape_field_name(gradio.props.color),
legend:
gradio.props.colors_in_legend?.length === 0
? null
: {
orient: "bottom",
title: gradio.props.color_title,
values: gradio.props.colors_in_legend
? [...gradio.props.colors_in_legend]
: undefined
},
scale:
gradio.props.value!.datatypes[gradio.props.color] ===
"nominal"
? {
domain: unique_colors,
range: gradio.props.color_map
? unique_colors.map(
(c) => gradio.props.color_map![c]
)
: undefined
}
: {
range: [
100, 200, 300, 400, 500, 600, 700, 800, 900
].map((n) =>
computed_style!.getPropertyValue("--primary-" + n)
),
interpolate: "hsl"
},
type: gradio.props.value!.datatypes[gradio.props.color]
}
: undefined,
tooltip:
gradio.props.tooltip == "none"
? undefined
: [
{
field: escape_field_name(gradio.props.y),
type: gradio.props.value!.datatypes[gradio.props.y],
aggregate: aggregating ? _y_aggregate : undefined,
title: gradio.props.y_title || gradio.props.y
},
{
field: escape_field_name(gradio.props.x),
type: gradio.props.value!.datatypes[gradio.props.x],
title: gradio.props.x_title || gradio.props.x,
format: x_temporal ? "%Y-%m-%d %H:%M:%S" : undefined,
bin: _x_bin ? { step: _x_bin } : undefined
},
...(gradio.props.color
? [
{
field: gradio.props.color,
type: gradio.props.value!.datatypes[
gradio.props.color
]
}
]
: []),
...(gradio.props.tooltip === "axis"
? []
: (gradio.props.value?.columns ?? [])
.filter(
(col) =>
col !== gradio.props.x &&
col !== gradio.props.y &&
col !== gradio.props.color &&
(gradio.props.tooltip === "all" ||
gradio.props.tooltip.includes(col))
)
.map((column) => ({
field: column,
type: gradio.props.value!.datatypes[column]
})))
]
},
strokeDash: {},
mark: {
clip: true,
type: mode === "hover" ? "point" : gradio.props.value!.mark
},
name: mode
};
}),
// @ts-ignore
params: [
...(gradio.props.value!.mark === "line"
? [
{
name: "hoverPlot",
select: {
clear: "mouseout",
fields: gradio.props.color ? [gradio.props.color] : [],
nearest: true,
on: "mouseover",
type: "point" as "point"
},
views: ["hover"]
},
{
name: "hover",
select: {
clear: "mouseout",
nearest: true,
on: "mouseover",
type: "point" as "point"
},
views: ["hover"]
}
]
: []),
...(gradio.props._selectable
? [
{
name: "brush",
select: {
encodings: ["x"],
mark: { fill: "gray", fillOpacity: 0.3, stroke: "none" },
type: "interval" as "interval"
},
views: ["plot"]
}
]
: [])
],
width: chart_element!.offsetWidth,
height: gradio.props.height || fullscreen ? "container" : undefined,
title: gradio.props.title || undefined
} as Spec;
}
$inspect("visible", gradio.shared.visible);
</script>
<Block
visible={gradio.shared.visible}
elem_id={gradio.shared.elem_id}
elem_classes={gradio.shared.elem_classes}
scale={gradio.shared.scale}
min_width={gradio.shared.min_width}
allow_overflow={false}
padding={true}
height={gradio.props.height}
bind:fullscreen
>
{#if gradio.shared.loading_status}
<StatusTracker
autoscroll={gradio.shared.autoscroll}
i18n={gradio.i18n}
{...gradio.shared.loading_status}
on_clear_status={() =>
gradio.dispatch("clear_status", gradio.shared.loading_status)}
/>
{/if}
{#if gradio.props.buttons?.length}
<IconButtonWrapper
buttons={gradio.props.buttons}
on_custom_button_click={(id) => {
gradio.dispatch("custom_button_click", { id });
}}
>
{#if gradio.props.buttons?.some((btn) => typeof btn === "string" && btn === "export")}
<IconButton Icon={Download} label="Export" onclick={export_chart} />
{/if}
{#if gradio.props.buttons?.some((btn) => typeof btn === "string" && btn === "fullscreen")}
<FullscreenButton {fullscreen} onclick={(fs) => (fullscreen = fs)} />
{/if}
</IconButtonWrapper>
{/if}
<BlockTitle show_label={gradio.shared.show_label} info={undefined}
>{gradio.shared.label}</BlockTitle
>
{#if gradio.props.value && is_browser}
<div bind:this={chart_element}></div>
{#if gradio.props.caption}
<p class="caption">{gradio.props.caption}</p>
{/if}
{:else}
<Empty unpadded_box={true}><LabelIcon /></Empty>
{/if}
</Block>
<style>
div {
width: 100%;
height: 100%;
}
:global(#vg-tooltip-element) {
font-family: var(--font) !important;
font-size: var(--text-xs) !important;
box-shadow: none !important;
background-color: var(--block-background-fill) !important;
border: 1px solid var(--border-color-primary) !important;
color: var(--body-text-color) !important;
}
:global(#vg-tooltip-element .key) {
color: var(--body-text-color-subdued) !important;
}
.caption {
padding: 0 4px;
margin: 0;
text-align: center;
}
</style>
+144
View File
@@ -0,0 +1,144 @@
<script module>
import { defineMeta } from "@storybook/addon-svelte-csf";
import NativePlot from "./Index.svelte";
import { wrapProps } from "../storybook/wrapProps";
const { Story } = defineMeta({
title: "Components/NativePlot",
component: NativePlot,
parameters: {
chromatic: { delay: 500 }
}
});
</script>
<Story
name="Scatter Plot"
args={{
value: {
columns: ["x", "y", "category"],
data: [
[1, 2, "A"],
[2, 4, "A"],
[3, 1, "B"],
[4, 5, "B"],
[5, 3, "C"],
[6, 6, "C"]
],
datatypes: {
x: "quantitative",
y: "quantitative",
category: "nominal"
},
mark: "point"
},
x: "x",
y: "y",
color: "category",
title: "Sample Scatter Plot",
x_title: "X Axis",
y_title: "Y Axis",
color_title: "Categories",
label: "Scatter Plot",
show_label: true,
tooltip: "all"
}}
>
{#snippet template(args)}
<div style="width: 600px; height: 400px;">
<NativePlot {...wrapProps(args)} />
</div>
{/snippet}
</Story>
<Story
name="Line Plot"
args={{
value: {
columns: ["time", "value"],
data: [
[1, 10],
[2, 15],
[3, 13],
[4, 17],
[5, 14],
[6, 20]
],
datatypes: {
time: "quantitative",
value: "quantitative"
},
mark: "line"
},
x: "time",
y: "value",
title: "Sample Line Plot",
x_title: "Time",
y_title: "Value",
label: "Line Plot",
show_label: true
}}
>
{#snippet template(args)}
<div style="width: 600px; height: 400px;">
<NativePlot {...wrapProps(args)} />
</div>
{/snippet}
</Story>
<Story
name="Colors In Legend Test"
args={{
value: {
columns: ["x", "y", "category"],
data: [
[1, 2, "A"],
[2, 4, "A"],
[3, 1, "B"],
[4, 5, "B"],
[5, 3, "C"],
[6, 6, "C"],
[7, 4, "D"],
[8, 7, "D"]
],
datatypes: {
x: "quantitative",
y: "quantitative",
category: "nominal"
},
mark: "point"
},
x: "x",
y: "y",
color: "category",
colors_in_legend: ["A", "C"],
title: "Plot with Filtered Legend (only A and C shown)",
x_title: "X Axis",
y_title: "Y Axis",
color_title: "Categories",
label: "Filtered Legend Plot",
show_label: true,
tooltip: "all"
}}
>
{#snippet template(args)}
<div style="width: 600px; height: 400px;">
<NativePlot {...wrapProps(args)} />
</div>
{/snippet}
</Story>
<Story
name="Empty Plot"
args={{
value: null,
label: "Empty Plot",
show_label: true
}}
>
{#snippet template(args)}
<div style="width: 600px; height: 400px;">
<NativePlot {...wrapProps(args)} />
</div>
{/snippet}
</Story>
+123
View File
@@ -0,0 +1,123 @@
import { test, describe, afterEach, expect } from "vitest";
import { cleanup, render, fireEvent, waitFor } from "@self/tootils/render";
import { run_shared_prop_tests } from "@self/tootils/shared-prop-tests";
import NativePlot from "./Index.svelte";
import type { NativePlotProps } from "./types";
const plot_value = {
columns: ["x", "y", "series"],
data: [
[1, 4, "alpha"],
[2, 5, "alpha"],
[1, 7, "beta"],
[2, 8, "beta"]
],
datatypes: {
x: "quantitative",
y: "quantitative",
series: "nominal"
},
mark: "line"
} satisfies NativePlotProps["value"];
const default_props = {
value: plot_value,
x: "x",
y: "y",
color: null,
title: null,
x_title: null,
y_title: null,
color_title: null,
x_bin: null,
y_aggregate: undefined,
color_map: null,
colors_in_legend: null,
x_lim: null,
y_lim: null,
x_label_angle: 0,
y_label_angle: 0,
x_axis_format: null,
y_axis_format: null,
x_axis_labels_visible: true,
caption: null,
sort: null,
tooltip: "axis" as const,
buttons: null,
_selectable: false,
label: "Native Plot",
show_label: false,
scale: null,
min_width: 160,
loading_status: undefined,
height: 260
};
run_shared_prop_tests({
component: NativePlot,
name: "NativePlot",
base_props: { ...default_props, value: null },
has_label: false
});
async function waitForChart(container: HTMLElement): Promise<void> {
await waitFor(() => {
expect(container.querySelector("svg")).toBeInTheDocument();
});
}
describe("Props: colors_in_legend", () => {
afterEach(() => cleanup());
test("colors_in_legend: [] hides all color legend entries", async () => {
const { container } = await render(NativePlot, {
...default_props,
color: "series",
colors_in_legend: []
});
await waitForChart(container);
expect(container).not.toHaveTextContent("alpha");
expect(container).not.toHaveTextContent("beta");
expect(container).not.toHaveTextContent("series");
});
test("colors_in_legend limits visible color legend entries", async () => {
const { container } = await render(NativePlot, {
...default_props,
color: "series",
colors_in_legend: ["alpha"]
});
await waitForChart(container);
expect(container).toHaveTextContent("alpha");
expect(container).not.toHaveTextContent("beta");
});
});
describe("Props: buttons", () => {
afterEach(() => cleanup());
test("clicking the fullscreen button toggles fullscreen mode", async () => {
const { container, getByLabelText } = await render(NativePlot, {
...default_props,
buttons: ["fullscreen"]
});
await waitForChart(container);
await fireEvent.click(getByLabelText("Fullscreen"));
await waitFor(() => {
expect(getByLabelText("Exit fullscreen mode")).toBeVisible();
});
await fireEvent.click(getByLabelText("Exit fullscreen mode"));
await waitFor(() => {
expect(getByLabelText("Fullscreen")).toBeVisible();
});
await waitForChart(container);
});
});
+44
View File
@@ -0,0 +1,44 @@
{
"name": "@gradio/nativeplot",
"version": "0.12.1",
"description": "Gradio UI packages",
"type": "module",
"author": "",
"license": "ISC",
"private": false,
"main_changeset": true,
"exports": {
".": {
"gradio": "./Index.svelte",
"svelte": "./dist/Index.svelte",
"types": "./dist/Index.svelte.d.ts"
},
"./example": {
"gradio": "./Example.svelte",
"svelte": "./dist/Example.svelte",
"types": "./dist/Example.svelte.d.ts"
},
"./package.json": "./package.json"
},
"dependencies": {
"@gradio/atoms": "workspace:^",
"@gradio/icons": "workspace:^",
"@gradio/statustracker": "workspace:^",
"@gradio/theme": "workspace:^",
"@gradio/utils": "workspace:^",
"vega": "^6.2.0",
"vega-embed": "^7.0.2",
"vega-lite": "^6.4.1"
},
"devDependencies": {
"@gradio/preview": "workspace:^"
},
"peerDependencies": {
"svelte": "^5.48.0"
},
"repository": {
"type": "git",
"url": "git+https://github.com/gradio-app/gradio.git",
"directory": "js/nativeplot"
}
}
+53
View File
@@ -0,0 +1,53 @@
import type { Gradio, SelectData, CustomButton } from "@gradio/utils";
import type { ILoadingStatus as LoadingStatus } from "@gradio/statustracker";
export interface PlotData {
columns: string[];
data: (string | number)[][];
datatypes: Record<string, "quantitative" | "temporal" | "nominal">;
mark: "line" | "point" | "bar";
}
export interface NativePlotProps {
value: PlotData | null;
x: string;
y: string;
color: string | null;
title: string | null;
x_title: string | null;
y_title: string | null;
color_title: string | null;
x_bin: string | number | null;
y_aggregate: "sum" | "mean" | "median" | "min" | "max" | undefined;
color_map: Record<string, string> | null;
colors_in_legend: string[] | null;
x_lim: [number | null, number | null] | null;
y_lim: [number | null, number | null] | null;
x_label_angle: number | null;
y_label_angle: number | null;
x_axis_format: string | null;
y_axis_format: string | null;
x_axis_labels_visible: boolean;
caption: string | null;
sort: "x" | "y" | "-x" | "-y" | string[] | null;
tooltip: "axis" | "none" | "all" | string[];
buttons: (string | CustomButton)[] | null;
_selectable: boolean;
label: string;
elem_id: string;
elem_classes: string[];
visible: boolean | "hidden";
show_label: boolean;
scale: number | null;
min_width: number | undefined;
loading_status: LoadingStatus | undefined;
height: number | undefined;
}
export interface NativePlotEvents {
change: never;
select: SelectData;
double_click: undefined;
clear_status: LoadingStatus;
custom_button_click: { id: number };
}