diff --git a/packages/backend/README.md b/packages/backend/README.md index 8f48979..b07ba02 100644 --- a/packages/backend/README.md +++ b/packages/backend/README.md @@ -65,3 +65,7 @@ embedding-atlas path_to_dataset.parquet --x projection_x --y projection_y --neig The `neighbors` column should have values in the following format: `{"ids": [id1, id2, ...], "distances": [d1, d2, ...]}`. If this column is specified, you'll be able to see nearest neighbors for a selected point in the tool. + +## Local Development + +Launch Embedding Altas with a wine reviews dataset with `./start.sh` and the MNIST dataset with `./start_image.sh`. diff --git a/packages/viewer/README.md b/packages/viewer/README.md index 147dd13..24dfc1f 100644 --- a/packages/viewer/README.md +++ b/packages/viewer/README.md @@ -13,3 +13,5 @@ Start development server: ```bash npm run dev ``` + +This will serve Embedding Atlas UI at http://localhost:5173. Note that the UI requires a backend server to provide data to it. You can start one via the `./start.sh` mentioned above. Without a backend server, you can still go to http://localhost:5173/#/test to view a test dataset. diff --git a/packages/viewer/src/EmbeddingAtlas.svelte b/packages/viewer/src/EmbeddingAtlas.svelte index b5e3c4b..e34aba7 100644 --- a/packages/viewer/src/EmbeddingAtlas.svelte +++ b/packages/viewer/src/EmbeddingAtlas.svelte @@ -20,6 +20,7 @@ import Spinner from "./widgets/Spinner.svelte"; import { + IconClose, IconDarkMode, IconDashboardLayout, IconDownload, @@ -370,19 +371,60 @@ {/if} -
+
-
+
+ + {#if onExportSelection} + + {#snippet button({ visible, toggle })} + + {/snippet} +
+
+ onExportSelection(currentPredicate(), exportFormat)} + /> + (exportFormat = v)} - options={[ - { value: "parquet", label: "Parquet" }, - { value: "jsonl", label: "JSONL" }, - { value: "json", label: "JSON" }, - { value: "csv", label: "CSV" }, - ]} - /> -
- {/if} - {#if onExportApplication} - - {/if} +
{/if}

About

diff --git a/packages/viewer/src/app/Test.svelte b/packages/viewer/src/app/Test.svelte index 8da93a6..6ea0795 100644 --- a/packages/viewer/src/app/Test.svelte +++ b/packages/viewer/src/app/Test.svelte @@ -6,11 +6,15 @@ import type { EmbeddingAtlasProps } from "../api.js"; import { initializeDatabase } from "../utils/database.js"; + import { downloadBuffer } from "../utils/download.js"; + import { exportMosaicSelection, type ExportFormat } from "../utils/mosaic_exporter.js"; import type { DataSource } from "./data_source.js"; export class TestDataSource implements DataSource { private count: number; + downloadSelection: ((predicate: string | null, format: ExportFormat) => Promise) | undefined = undefined; + constructor(count: number) { this.count = count; } @@ -55,6 +59,11 @@ UPDATE ${table} SET y = y + 5 * floor(floor(var_uniform * 24 + random()) / 5); `); + this.downloadSelection = async (predicate, format) => { + let [bytes, name] = await exportMosaicSelection(coordinator, table, predicate, format); + downloadBuffer(bytes, name); + }; + return { data: { table: table, diff --git a/packages/viewer/src/widgets/PopupButton.svelte b/packages/viewer/src/widgets/PopupButton.svelte index f2b09b5..367e6d9 100644 --- a/packages/viewer/src/widgets/PopupButton.svelte +++ b/packages/viewer/src/widgets/PopupButton.svelte @@ -11,12 +11,17 @@ label?: string | null; icon?: any | null; anchor?: "left" | "right"; + button?: Snippet<[{ visible: boolean; toggle: () => void }]>; children?: Snippet; } - let { title = "", label = null, icon = null, anchor = "right", children }: Props = $props(); + let { title = "", label = null, icon = null, anchor = "right", children, button }: Props = $props(); let visible: boolean = $state(false); + + function toggle() { + visible = !visible; + } let container: HTMLDivElement; function onKeyDown(e: KeyboardEvent) { @@ -50,7 +55,11 @@
- + {#if button} + {@render button({ visible, toggle })} + {:else} + + {/if}