Skip to content

Zoom plots in editor #8126

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Jun 25, 2025
Merged

Zoom plots in editor #8126

merged 13 commits into from
Jun 25, 2025

Conversation

timtmok
Copy link
Contributor

@timtmok timtmok commented Jun 16, 2025

Address #4359

Adds the zoom level to the plot metadata. This is used to set the button text in the Plots pane and to set the zoom prop when rendering in the pane and editor.

An editor zoom action has been added as a menu button for the zoom levels. The currently selected zoom level is checked when opening the menu.

The actions have been moved to the left side.

The plot metadata has been updated to include the zoom level. The zoom level is restored for the editor and view when reloading the UI.

image

Release Notes

New Features

Bug Fixes

  • N/A

QA Notes

@timtmok timtmok requested a review from Copilot June 16, 2025 16:43
Copy link

github-actions bot commented Jun 16, 2025

E2E Tests 🚀
This PR will run tests tagged with: @:critical

readme  valid tags

Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Adds zoom functionality for Positron plots in editor views, wiring zoom state through services, clients, and UI.

  • Introduce ZoomLevel enum and IZoomablePlotClient interface
  • Extend plot services and clients to store, emit, and persist zoom level
  • Update browser components and actions to render zoom controls and apply zoom

Reviewed Changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
test/common/testPositronPlotsService.ts Add zoom-level map, getter/setter, and event emitter to test service
test/common/testPositronPlotClient.ts & test/common/testPlotsServiceHelper.ts Initialize default zoom_level in test metadata
common/staticPlotClient.ts Implement IZoomablePlotClient, zoom-level emitter, and setters/getters
common/positronPlots.ts Define ZoomLevel enum, IZoomablePlotClient, and type guard
common/languageRuntimePlotClient.ts Extend runtime plot client with zoom-level state and events
contrib/positronPlotsEditor/browser/editorPlotsContainer.tsx Subscribe to plot-client zoom events and apply zoom in editor
contrib/positronPlots/browser/positronPlotsService.ts Add setEditorPlotZoom/getEditorPlotZoom, persist metadata on zoom
contrib/positronPlots/browser/positronPlotsActions.ts Register zoom submenu and individual zoom actions
contrib/positronPlots/browser/components/zoomPlotMenuButton.tsx Switch to shared ZoomLevel import
contrib/positronPlots/browser/components/*Instance.tsx Pass instance zoomLevel into PanZoomImage
contrib/positronPlots/browser/components/panZoomImage.tsx Update zoom logic to consume optional prop
Comments suppressed due to low confidence (1)

src/vs/workbench/services/positronPlots/common/positronPlots.ts:341

  • The method signature uses a plain number for zoom, but consumers will pass a ZoomLevel. Consider changing this parameter to zoom: ZoomLevel for type safety and consistency.
setEditorPlotZoom(plotId: string, zoom: number): void;

@timtmok timtmok force-pushed the 4359-zoom-editor-plot branch from cc725b7 to 0c860cd Compare June 16, 2025 19:10
@timtmok timtmok marked this pull request as ready for review June 17, 2025 21:23
@timtmok timtmok requested review from seeM and sharon-wang June 17, 2025 21:23
Copy link
Member

@sharon-wang sharon-wang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are all working for me:

  • upon reloading positron via Developer: Reload Window, the plot zoom in the editor and Plots pane were both restored
  • able to adjust zoom for plot in Editor and Editor in separate window, same behaviour as Plots pane
  • when plot size is larger than the plot area, can pan up/down/left/right with trackpad or scrollwheel (scrollwheel to move up/down; Shift+scrollwheel to move left/right)

@@ -180,12 +180,12 @@ export const PlotsContainer = (props: PlotContainerProps) => {
height={plotHeight}
plotClient={plotInstance}
width={plotWidth}
zoom={props.zoom} />;
zoom={plotInstance.zoomLevel} />;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we still need this separate prop now that zoomLevel is part of the plotInstance?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch!

Comment on lines 914 to 921
this._register(plot.onDidChangeZoomLevel((zoomLevel) => {
// Store the zoom level in the plot metadata
this.storePlotMetadata(plot.metadata);
}));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the zoomLevel already reflected in plot.metadata, or should the metadata be updated with the zoom level before storing it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the plot client updates the metadata when the zoom changes. I should fix up the comment though since this is updating the stored metadata.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, it makes sense to update it before storing. It'll move the responsibility of updating the metadata to the service and future plot clients won't have to worry about it.

@@ -62,6 +62,7 @@ export class PositronPlotsEditor extends EditorPane implements IPositronPlotsEdi

private readonly _onFocusedEmitter = this._register(new Emitter<void>());
private _plotClient: IPositronPlotClient | undefined;
_zoomContextKey: IContextKey<string>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: should this be private?

Suggested change
_zoomContextKey: IContextKey<string>;
private _zoomContextKey: IContextKey<string>;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should!


export enum ZoomLevel {
Fit = 0,
Fifty = 0.5,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An observation I think unrelated to the changes in this PR:

50% zoom level seemed to be equivalent to Fit for me, in the Plots pane, Editor and new window. I also expected 75% zoom to be 75% of Fit, but I think there is an intrinsic size of the plot image which these percentages correspond to?

I wonder if the zoom percentages should be relative to the Fit rather than an intrinsic size (if that is the case)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The level affects the image scaling, which depends on the rendered size. When the plot is shown in the editor, the rendered size is different because of the available space. It's the same plot comm underneath but with a proxy on top so that the editor and view can have their own render options.

The Plots pane may have 350x300 pixels while the editor may have 700x600. Unless the plot size is set to intrinsic, the plot is going to render to fill the space. The zooming changes the scaling when displayed by changing the width and height via CSS. So the final size might be the same or similar when the view is at 100% and the editor is at 50% zoom. I think it's just the coincidence that the Plots pane width and height are about half the size of the editor that causes this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still seeing Fit and 50% be the same in the Editor, and now in the Plots pane the Zoom seems to be the same with every zoom option. This was recorded on a larger, more square monitor, but I'm seeing the same behaviour on the 16" Macbook screen as well.

plots_zoom.mp4

Maybe this is a separate enhancement / docs change to describe how the zoom level works? I had expected that the Zoom percentage is relative to the initial "Fit" image size, so I expected 50% and 75% to scale the image down, but then 100% and Fit would be equivalent in this case...I'm not sure the best path forward, maybe just awaiting some user feedback!

For the Plots pane, could you check if you see the same behaviour? The Zoom control isn't re-scaling the image, even if I modify how large the Plots pane is.

}));
this._zoomContextKey.set(this._plotClient.metadata.zoom_level?.toString() ?? '');
}

this.renderContainer(this._plotClient);
this.onSizeChanged((event: ISize) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure the right spot for this, but I am seeing a leaked disposable when I have the plot open qa-example-content/workspaces/r-plots/ggplot-example.R in an editor:

lifecycle.ts:50 [LEAKED DISPOSABLE] Error: CREATED via:
    at GCBasedDisposableTracker.trackDisposable (vscode-file://vscode-app/Users/sashimi/dev/positron-dev/out/vs/base/common/lifecycle.js:27:23)
    at trackDisposable (vscode-file://vscode-app/Users/sashimi/dev/positron-dev/out/vs/base/common/lifecycle.js:198:24)
    at toDisposable (vscode-file://vscode-app/Users/sashimi/dev/positron-dev/out/vs/base/common/lifecycle.js:276:18)
    at PositronPlotsEditor._event [as onSizeChanged] (vscode-file://vscode-app/Users/sashimi/dev/positron-dev/out/vs/base/common/event.js:876:28)
    at PositronPlotsEditor.setInput (vscode-file://vscode-app/Users/sashimi/dev/positron-dev/out/vs/workbench/contrib/positronPlotsEditor/browser/positronPlotsEditor.js:119:14)
    at async EditorPanes.doSetInput (vscode-file://vscode-app/Users/sashimi/dev/positron-dev/out/vs/workbench/browser/parts/editor/editorPanes.js:343:13)
    at async EditorPanes.doOpenEditor (vscode-file://vscode-app/Users/sashimi/dev/positron-dev/out/vs/workbench/browser/parts/editor/editorPanes.js:183:40)
    at async EditorPanes.openEditor (vscode-file://vscode-app/Users/sashimi/dev/positron-dev/out/vs/workbench/browser/parts/editor/editorPanes.js:82:20)
    at async vscode-file://vscode-app/Users/sashimi/dev/positron-dev/out/vs/workbench/browser/parts/editor/editorGroupView.js:1057:61
2

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! I couldn't reproduce it but looking at the code it's obvious why the disposable is leaking.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not seeing this anymore! 👍

@timtmok timtmok force-pushed the 4359-zoom-editor-plot branch from 065342d to 4903d33 Compare June 20, 2025 18:22
@timtmok timtmok requested a review from sharon-wang June 20, 2025 18:22
Copy link
Member

@sharon-wang sharon-wang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe separately, but would it be possible to use the same component as the Plots pane, so that the current zoom percentage shows in the Editor as well?

Editor

image

Plots pane

image

@timtmok
Copy link
Contributor Author

timtmok commented Jun 25, 2025

Maybe separately, but would it be possible to use the same component as the Plots pane, so that the current zoom percentage shows in the Editor as well?

Not without changing how the editor action bar contribution is processed. I'm not even sure how easy it is to update the contribution dynamically and it would also need to support extensions contributing to this, which would likely be through their extensions package.json.

@timtmok timtmok force-pushed the 4359-zoom-editor-plot branch from 7f343cd to 587878b Compare June 25, 2025 18:47
@timtmok timtmok requested a review from sharon-wang June 25, 2025 18:49
Copy link
Member

@sharon-wang sharon-wang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the unit test failures seem related to this PR, but otherwise LGTM and zooming in the Plots pane is working again 👌

@timtmok timtmok merged commit 248c709 into main Jun 25, 2025
8 checks passed
@timtmok timtmok deleted the 4359-zoom-editor-plot branch June 25, 2025 21:59
@github-actions github-actions bot locked and limited conversation to collaborators Jun 25, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants