diff --git a/news/2 Fixes/6344.md b/news/2 Fixes/6344.md new file mode 100644 index 000000000000..cba8947b076a --- /dev/null +++ b/news/2 Fixes/6344.md @@ -0,0 +1 @@ +Fix png scaling on non standard DPI. Add 'enablePlotViewer' setting to allow user to render pngs instead of svg files. diff --git a/package.json b/package.json index 61ce7ad1f223..6fbf8ef41357 100644 --- a/package.json +++ b/package.json @@ -1338,6 +1338,12 @@ "description": "Allow for connecting the Python Interactive window to a https Jupyter server that does not have valid certificates. This can be a security risk, so only use for known and trusted servers.", "scope": "resource" }, + "python.dataScience.enablePlotViewer": { + "type": "boolean", + "default": true, + "description": "Modify plot output so that it can be expanded into a plot viewer window.", + "scope": "resource" + }, "python.dataScience.enableDebugging": { "type": "boolean", "default": false, diff --git a/src/client/common/types.ts b/src/client/common/types.ts index 9987a74d475e..541568cfec37 100644 --- a/src/client/common/types.ts +++ b/src/client/common/types.ts @@ -319,6 +319,7 @@ export interface IDataScienceSettings { autoPreviewNotebooksInInteractivePane?: boolean; allowUnauthorizedRemoteConnection?: boolean; askForKernelRestart?: boolean; + enablePlotViewer?: boolean; enableDebugging?: boolean; } diff --git a/src/client/datascience/constants.ts b/src/client/datascience/constants.ts index 9ea63059d5da..5bd1085c2e52 100644 --- a/src/client/datascience/constants.ts +++ b/src/client/datascience/constants.ts @@ -167,7 +167,8 @@ export namespace Identifiers { export namespace CodeSnippits { export const ChangeDirectory = ['{0}', '{1}', 'import os', 'try:', '\tos.chdir(os.path.join(os.getcwd(), \'{2}\'))', '\tprint(os.getcwd())', 'except:', '\tpass', '']; export const ChangeDirectoryCommentIdentifier = '# ms-python.python added'; // Not translated so can compare. - export const MatplotLibInit = `import matplotlib\n%matplotlib inline\n${Identifiers.MatplotLibDefaultParams} = dict(matplotlib.rcParams)\n%config InlineBackend.figure_format = 'svg'`; + export const MatplotLibInitSvg = `import matplotlib\n%matplotlib inline\n${Identifiers.MatplotLibDefaultParams} = dict(matplotlib.rcParams)\n%config InlineBackend.figure_format = 'svg'`; + export const MatplotLibInitPng = `import matplotlib\n%matplotlib inline\n${Identifiers.MatplotLibDefaultParams} = dict(matplotlib.rcParams)\n%config InlineBackend.figure_format = 'png'`; } export namespace JupyterCommands { diff --git a/src/client/datascience/jupyter/jupyterServer.ts b/src/client/datascience/jupyter/jupyterServer.ts index 3598e6ec19c4..fa4da462be43 100644 --- a/src/client/datascience/jupyter/jupyterServer.ts +++ b/src/client/datascience/jupyter/jupyterServer.ts @@ -568,10 +568,13 @@ export class JupyterServerBase implements INotebookServer { await this.changeDirectoryIfPossible(this.launchInfo.workingDir); } + const settings = this.configService.getSettings().datascience; + const matplobInit = !settings || settings.enablePlotViewer ? CodeSnippits.MatplotLibInitSvg : CodeSnippits.MatplotLibInitPng; + // Force matplotlib to inline and save the default style. We'll use this later if we // get a request to update style await this.executeSilently( - CodeSnippits.MatplotLibInit, + matplobInit, cancelToken ); } catch (e) { diff --git a/src/datascience-ui/plot/mainPanel.tsx b/src/datascience-ui/plot/mainPanel.tsx index 975ff8d16b21..5605a62f992b 100644 --- a/src/datascience-ui/plot/mainPanel.tsx +++ b/src/datascience-ui/plot/mainPanel.tsx @@ -316,14 +316,6 @@ export class MainPanel extends React.Component this.postOffice.sendMessage(type, payload); } - private convertSizeToPixels(size: string) : number { - let multiplier = 1; - if (size.endsWith('pt')) { - multiplier = window.devicePixelRatio * 0.8866666; - } - return parseInt(size, 10) * multiplier; - } - private exportCurrent = async () => { // In order to export, we need the png and the svg. Generate // a png by drawing to a canvas and then turning the canvas into a dataurl. @@ -332,16 +324,16 @@ export class MainPanel extends React.Component if (doc) { const canvas = doc.createElement('canvas'); if (canvas) { - canvas.width = this.convertSizeToPixels(this.state.sizes[this.state.currentImage].width); - canvas.height = this.convertSizeToPixels(this.state.sizes[this.state.currentImage].height); const ctx = canvas.getContext('2d'); if (ctx) { const waitable = createDeferred(); - ctx.clearRect(0, 0, canvas.width, canvas.height); const svgBlob = new Blob([this.state.images[this.state.currentImage]], { type: 'image/svg+xml;charset=utf-8' }); const img = new Image(); const url = window.URL.createObjectURL(svgBlob); img.onload = () => { + canvas.width = img.width; + canvas.height = img.height; + ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.drawImage(img, 0, 0); waitable.resolve(); }; diff --git a/src/test/datascience/mockJupyterManager.ts b/src/test/datascience/mockJupyterManager.ts index a004878839bf..bc19b6840d03 100644 --- a/src/test/datascience/mockJupyterManager.ts +++ b/src/test/datascience/mockJupyterManager.ts @@ -100,7 +100,7 @@ export class MockJupyterManager implements IJupyterSessionManager { this.kernelSpecs.push({name: '0e8519db-0895-416c-96df-fa80131ecea0', dir: 'C:\\Users\\rchiodo\\AppData\\Roaming\\jupyter\\kernels\\0e8519db-0895-416c-96df-fa80131ecea0'}); // Setup our default cells that happen for everything - this.addCell(CodeSnippits.MatplotLibInit); + this.addCell(CodeSnippits.MatplotLibInitSvg); this.addCell('matplotlib.style.use(\'dark_background\')'); this.addCell(`matplotlib.rcParams.update(${Identifiers.MatplotLibDefaultParams})`); this.addCell(`%cd "${path.join(EXTENSION_ROOT_DIR, 'src', 'test', 'datascience')}"`);