Skip to content

Add static image export (PNG/SVG) with dimension control for Bokeh plots #132

@jayhesselberth

Description

@jayhesselberth

Summary

Add functionality to export Bokeh plots as static images (PNG/SVG) with configurable dimensions, in addition to the current HTML export.

Current State

Currently, Squiggy only supports HTML export:

  • squiggy-plot-panel.ts:94-104 has exportPlot() method
  • HTML export works by writing the Bokeh HTML to disk
  • PNG/SVG export shows error: "PNG/SVG export not yet implemented"
  • No UI for controlling export dimensions or format

Requested Features

1. Static Image Export

Support exporting plots as:

  • PNG - Raster format for presentations/reports
  • SVG - Vector format for publications/scalable graphics

2. Dimension Control

Allow users to specify:

  • Width (pixels or inches)
  • Height (pixels or inches)
  • DPI/resolution (for PNG)
  • Aspect ratio lock option

3. Current View Export

Option to export the current zoom level/pan state, not just the full plot extent

Implementation Approach

Python Backend (squiggy/)

Bokeh provides built-in export functions:

from bokeh.io import export_png, export_svgs
from bokeh.models import Plot

def export_plot_image(
    plot: Plot,
    output_path: str,
    width: int = None,
    height: int = None,
    format: str = 'png'
) -> None:
    """Export Bokeh plot as static image."""
    if format == 'png':
        export_png(plot, filename=output_path, width=width, height=height)
    elif format == 'svg':
        plot.output_backend = 'svg'
        export_svgs(plot, filename=output_path)

Dependencies: Requires selenium + geckodriver/chromedriver for PNG export (or playwright as alternative)

TypeScript Extension

  1. Add export command to package.json:

    {
      "command": "squiggy.exportPlot",
      "title": "Export Plot as Image",
      "category": "Squiggy",
      "icon": "$(save-as)"
    }
  2. Update squiggy-plot-panel.ts:

    • Add UI for export options (format, dimensions)
    • Call Python backend with parameters
    • Handle export via PositronRuntime
  3. Export dialog (using React or QuickPick):

    • Format selection (PNG/SVG/HTML)
    • Dimension inputs (width/height)
    • "Use current zoom" checkbox
    • File picker for output path

UI Options

Option A: Add toolbar button to plot panel

// Add button to webview with postMessage to extension
<button onclick="exportPlot()">Export</button>

Option B: Context menu on plot panel

"menus": {
  "view/title": [
    {
      "command": "squiggy.exportPlot",
      "when": "view == squigglePlot",
      "group": "navigation"
    }
  ]
}

Option C: Command palette only

  • Keep it simple, no UI changes
  • Use vscode.window.showQuickPick() for format selection
  • Use vscode.window.showInputBox() for dimensions

Technical Considerations

Dependencies

  • PNG: Requires headless browser (Selenium WebDriver or Playwright)
  • SVG: Native Bokeh support, no extra dependencies
  • May need to update pyproject.toml with optional dependencies

Zoom-Level Export

  • Bokeh plots maintain current view state in JavaScript
  • Need to capture x_range/y_range from webview and pass to Python
  • Alternative: Screenshot the webview (easier but lower quality)

File Size

  • PNG: Depends on dimensions/DPI (typically 100KB-5MB)
  • SVG: Can be large with many data points (consider simplification options)

References

Priority

Medium - Users can currently export HTML and screenshot manually, but proper static image export would improve publication/presentation workflows.

Related Issues

None currently

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions