Skip to content

feat: Export and Sharing #11

Description

@aGallea

Problem

Visualizations are ephemeral. Once you close the browser, the computed plot is gone. There is no way to share a specific view, save cluster assignments for downstream analysis, or export results. Insights die when the session ends.

Proposed Solution

Three export capabilities:

  1. Export cluster assignments as CSV — Download a CSV mapping each item ID to its cluster ID and cluster name. Useful for downstream analysis in notebooks, spreadsheets, or other tools.
  2. Save/load plot configurations — Persist plot settings (collection, num_clusters, display fields, algorithm, etc.) as named presets so you don't have to re-configure each time.
  3. Screenshot — Export the current 3D view as a PNG image.

Implementation Details

Backend

New file: embedding_cluster/server/routes/export.py

  • GET /api/export/{job_id}/csv — Export cluster assignments
    • Returns CSV with columns: id, cluster_id, cluster_name, metadata_field_1, ...
    • Uses the computed plot data (already in memory after plot computation)
    • Set Content-Disposition: attachment; filename="clusters_{collection}_{timestamp}.csv"
    • Stream as CSV response using StreamingResponse
  • POST /api/presets — Save a plot preset
    • Request: { name: str, config: PlotPreset } where PlotPreset includes collection_name, num_clusters, reduction_algorithm, display_fields, etc.
    • Store in a JSON file at ./presets/ directory (or SQLite for robustness)
  • GET /api/presets — List all saved presets
  • GET /api/presets/{name} — Load a specific preset
  • DELETE /api/presets/{name} — Delete a preset

New file: embedding_cluster/presets.py

  • PresetManager class handling CRUD for plot configuration presets
  • File-based storage (JSON) — simple and portable
  • Thread-safe read/write operations

Modify: embedding_cluster/server/models.py

  • Add PlotPreset model (all plot configuration fields)
  • Add PresetListResponse model
  • Add ExportFormat enum if supporting multiple formats later

Modify: embedding_cluster/server/app.py

  • Register the export router

Modify: embedding_cluster/server/routes/plot.py

  • Ensure computed plot data (cluster assignments per item) is accessible for export
  • Store job results in a way that the export endpoint can retrieve them

Frontend

New file: frontend/src/components/plot/ExportToolbar.tsx

  • Export button group in the plot view toolbar
  • "Export CSV" button — triggers download of cluster assignments
  • "Screenshot" button — captures the Three.js canvas as PNG
  • "Save Preset" button — opens modal to name and save current config
  • "Load Preset" dropdown — lists saved presets, applies on selection

New file: frontend/src/components/plot/PresetModal.tsx

  • Modal for saving presets (name input + save button)
  • Shows current configuration summary
  • Validates preset name (no duplicates, no empty)

Modify: frontend/src/components/plot/ScatterPlot.tsx

  • Expose canvas ref for screenshot functionality
  • Screenshot via gl.domElement.toDataURL('image/png')

Modify: frontend/src/stores/plotStore.ts

  • Add presets state and CRUD actions
  • Add exportCsv() action
  • Add takeScreenshot() action

Modify: frontend/src/api/plot.ts

  • Add exportCsv(jobId), listPresets(), savePreset(), loadPreset(), deletePreset() API functions

Screenshot Implementation

  • Use Three.js renderer.domElement.toDataURL('image/png')
  • Trigger download via creating a temporary <a> element with download attribute
  • Ensure the canvas preserveDrawingBuffer: true is set on the WebGLRenderer

Testing Requirements

Full-coverage tests are required for all new code.

Backend Tests

New file: tests/test_export.py

  • Test CSV export endpoint returns valid CSV with correct columns
  • Test CSV contains all items from the plot with cluster assignments
  • Test CSV filename includes collection name and timestamp
  • Test export with missing job_id returns 404
  • Test Content-Type is text/csv

New file: tests/test_presets.py

  • Test PresetManager CRUD operations (create, read, list, delete)
  • Test saving a preset creates a JSON file
  • Test loading a preset returns correct configuration
  • Test listing presets returns all saved presets
  • Test deleting a preset removes the file
  • Test duplicate preset name handling (overwrite or error)
  • Test preset name validation (no empty names, no path traversal)
  • Test preset API endpoints (POST, GET, DELETE)
  • Test thread safety of file operations

Frontend Tests

  • ExportToolbar: all buttons render, click handlers fire correct actions
  • PresetModal: name validation, save triggers API call, cancel closes modal
  • Store: export and preset actions work correctly

Acceptance Criteria

  • User can export cluster assignments as a downloadable CSV
  • CSV includes item ID, cluster ID, cluster name, and metadata
  • User can save current plot configuration as a named preset
  • User can load a saved preset to restore plot configuration
  • User can delete presets
  • User can take a screenshot of the current 3D view as PNG
  • All new backend code has full test coverage
  • All new frontend components have tests

Notes

  • After implementation, update README.md to document export and preset features
  • Presets should be stored in a gitignored directory (e.g., ./presets/)
  • Consider adding export formats (JSON, Parquet) in a future iteration
  • Screenshot should capture the current camera angle and zoom level

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions