Inconsistent behavior of the scale factor for vector exports that include encapsulated rasters
Thank you so much for your work that brings the amazing features of plotly to static images too. This is extremely useful for publications that still rely on static figures (e.g. scientific journals). I was trying out some vector exports for different kind of plots at it was made clear from the plotly documentation that part of figures with specific plots (e.g. surface and mesh3d) would be “rasterized”.
Apparently, increasing the scale factor when calling write_image for vector formats does not produce encapsulated rasters with a higher resolution as it does for png (see details below). The main problem is that the behavior is not consistent between png and vector formats (tested with 'pdf' and 'svg').
Is there a way to have a consistent behavior?
(Sorry for the long issue message, I am trying to give as much info as possible.)
Image resolution using the scale factor
To (somehow) control the image resolution (only relevant for raster formats or raster components encapsulated in vector formats) the write_image (doc) method provides a scale factor. This works as expected for 'png' format but does not seem to work consistently for vector formats such as 'pdf' and 'svg'.
Different exports (using the kaleido engine) of the same image with 'png', 'pdf', and 'svg' formats and using different scale factors of 1 and 2 are attached. The code to reproduce these exports is detailed below. PNG and PDF files are also attached to this message (SVG is not supported as direct upload).
From a quick inspection of the file sizes, it is clear that 'png' does produce a larger file size (of “higher resolution”) when using a greater scale factor. This is not the case for the vector format (i.e. 'pdf' and 'svg'). Their file sizes do not change when using a greater scale factor (though their dimensions are scaled). I believe that the encapsulated rasters are similar (if not identical) despite the different scale factors. This unfortunately prevents from any high-resolution exports in vector formats (most suitable for print).
Additional information about the package versions and the PDF exports are provided below.
Ideal image resolution control
For all raster formats or rasters encapsulated within vector formats, it would be ideal if one could define a dpi parameter to control the final resolution of raster components. This would be much nicer than playing with a scale factor and dividing the final image by that factor to include it somewhere else (e.g. an image within a PDF).
Apparently, the current resolution for png exports is 72 dpi and 96 dpi for the vector exports. Both values are “default” values for screens (though many screens have much better resolutions nowadays), but clearly insufficient for print (for which 300 dpi and even 600 dpi is often required).
Additional observation
For the vector formats, it appears that not only the surface gets rasterized (again this is fine), but also the axis ticks (and the background). I do know if this is the expected behavior, but it would of course be optimal not to raster all components belonging to the surface plot (in particular fonts). I believe this would be much more complicated to control though.
Code
import os
import plotly.graph_objects as go
import pandas as pd
import itertools
# Read data from a csv
# https://plotly.com/python/3d-surface-plots/
z_data = pd.read_csv('https://github.com/plotly/datasets/master/api_docs/mt_bruno_elevation.csv')
# Create figure
fig = go.Figure(data=[go.Surface(z=z_data.values)])
fig.update_layout(
title='Mt Bruno Elevation',
autosize=False, width=500, height=500,
margin=dict(l=65, r=50, b=65, t=90)
)
# Export
export_dir = "images"
if not os.path.isdir(export_dir):
os.mkdir(path=export_dir)
scale_seq = 1, 2
format_seq = 'png', 'svg', 'pdf'
for scale, fmt in itertools.product(scale_seq, format_seq):
fig_name = f"export-surface-scale-{scale}.{fmt}"
file = os.path.join(export_dir, fig_name)
fig.write_image(file, format=fmt, scale=scale, engine='kaleido')
Additional information
plotly and kaleido versions
plotly==4.12.0
kaleido==0.0.3.post1
png outputs
$ identify -format "format: %m\nfilename: %f\nfile size: %b\npixels: %wx%h\ndpi: %xx%y\n" export-surface-scale-1.png
format: PNG
filename: export-surface-scale-1.png
file size: 95676B
pixels: 500x500
dpi: 72x72
$ identify -format "format: %m\nfilename: %f\nfile size: %b\npixels: %wx%h\ndpi: %xx%y\n" export-surface-scale-2.png
format: PNG
filename: export-surface-scale-2.png
file size: 253429B
pixels: 1000x1000
dpi: 72x72
pdfinfo outputs
From the page size property given in points, it seems like the renderer used a dpi of 96 as it started from a 500px x 500px image (i.e. 500 * 72 / 96 = 375).
$ pdfinfo export-surface-scale-1.pdf
Creator: Chromium
Producer: Skia/PDF m83
CreationDate: Wed Nov 11 16:21:43 2020
ModDate: Wed Nov 11 16:21:43 2020
Tagged: no
UserProperties: no
Suspects: no
Form: none
JavaScript: no
Pages: 1
Encrypted: no
Page size: 375.12 x 375.12 pts
Page rot: 0
File size: 221278 bytes
Optimized: no
PDF version: 1.4
$ pdfinfo export-surface-scale-2.pdf
Creator: Chromium
Producer: Skia/PDF m83
CreationDate: Wed Nov 11 16:21:47 2020
ModDate: Wed Nov 11 16:21:47 2020
Tagged: no
UserProperties: no
Suspects: no
Form: none
JavaScript: no
Pages: 1
Encrypted: no
Page size: 750 x 750 pts
Page rot: 0
File size: 221264 bytes
Optimized: no
PDF version: 1.4
export-surface-scale-2.pdf

export-surface-scale-1.pdf

Inconsistent behavior of the
scalefactor for vector exports that include encapsulated rastersThank you so much for your work that brings the amazing features of
plotlyto static images too. This is extremely useful for publications that still rely on static figures (e.g. scientific journals). I was trying out some vector exports for different kind of plots at it was made clear from theplotlydocumentation that part of figures with specific plots (e.g.surfaceandmesh3d) would be “rasterized”.Apparently, increasing the
scalefactor when callingwrite_imagefor vector formats does not produce encapsulated rasters with a higher resolution as it does forpng(see details below). The main problem is that the behavior is not consistent betweenpngand vector formats (tested with'pdf'and'svg').Is there a way to have a consistent behavior?
(Sorry for the long issue message, I am trying to give as much info as possible.)
Image resolution using the
scalefactorTo (somehow) control the image resolution (only relevant for raster formats or raster components encapsulated in vector formats) the
write_image(doc) method provides ascalefactor. This works as expected for'png'format but does not seem to work consistently for vector formats such as'pdf'and'svg'.Different exports (using the
kaleidoengine) of the same image with'png','pdf', and'svg'formats and using differentscalefactors of1and2are attached. The code to reproduce these exports is detailed below. PNG and PDF files are also attached to this message (SVG is not supported as direct upload).From a quick inspection of the file sizes, it is clear that
'png'does produce a larger file size (of “higher resolution”) when using a greaterscalefactor. This is not the case for the vector format (i.e.'pdf'and'svg'). Their file sizes do not change when using a greaterscalefactor (though their dimensions are scaled). I believe that the encapsulated rasters are similar (if not identical) despite the differentscalefactors. This unfortunately prevents from any high-resolution exports in vector formats (most suitable for print).Additional information about the package versions and the PDF exports are provided below.
Ideal image resolution control
For all raster formats or rasters encapsulated within vector formats, it would be ideal if one could define a
dpiparameter to control the final resolution of raster components. This would be much nicer than playing with ascalefactor and dividing the final image by that factor to include it somewhere else (e.g. an image within a PDF).Apparently, the current resolution for
pngexports is 72 dpi and 96 dpi for the vector exports. Both values are “default” values for screens (though many screens have much better resolutions nowadays), but clearly insufficient for print (for which 300 dpi and even 600 dpi is often required).Additional observation
For the vector formats, it appears that not only the surface gets rasterized (again this is fine), but also the axis ticks (and the background). I do know if this is the expected behavior, but it would of course be optimal not to raster all components belonging to the surface plot (in particular fonts). I believe this would be much more complicated to control though.
Code
Additional information
plotlyandkaleidoversionspngoutputs$ identify -format "format: %m\nfilename: %f\nfile size: %b\npixels: %wx%h\ndpi: %xx%y\n" export-surface-scale-1.png format: PNG filename: export-surface-scale-1.png file size: 95676B pixels: 500x500 dpi: 72x72$ identify -format "format: %m\nfilename: %f\nfile size: %b\npixels: %wx%h\ndpi: %xx%y\n" export-surface-scale-2.png format: PNG filename: export-surface-scale-2.png file size: 253429B pixels: 1000x1000 dpi: 72x72pdfinfooutputsFrom the page size property given in points, it seems like the renderer used a dpi of 96 as it started from a 500px x 500px image (i.e.
500 * 72 / 96 = 375).export-surface-scale-2.pdf


export-surface-scale-1.pdf