plotly.py icon indicating copy to clipboard operation
plotly.py copied to clipboard

add PDF as modebar "Download Plot" file format option

Open HyrumDickinson opened this issue 3 years ago • 3 comments

Plotly's static image export options via Kaleido are png, jpeg, webp, svg, and pdf. Plotly's modebar "Download Plot" button can be customized to export to all of those file types except pdf. Could we add a configuation option to "Download Plot" button to let it export an image of the post-interaction plot as a pdf?

This would be helpful for use cases where it's desirable to download a static image of an interactive plot post-interaction (perhaps to show highlighting of selected points), where PDF is the standard image format needed (perhaps for academic papers).

HyrumDickinson avatar Jul 12 '22 22:07 HyrumDickinson

Unfortunately PDFs aren't really available from inside JavaScript. Kaleido does this by calling Chromium's PrintToPdf method from the C++ side. We could presumably make the browser print the plot, then you could save it as a PDF, but that would be a bit hacky.

If you're doing this from jupyter, you can use go.FigureWidget. Make the figure:

import plotly.graph_objects as go
import plotly.express as px

fig = px.line(y=[4,2,5])
fw = go.FigureWidget(fig)
fw

Then after interacting with it, write it with Kaleido and the updates should be reflected:

fw.write_image("fig.pdf")

alexcjohnson avatar Jul 12 '22 23:07 alexcjohnson

I'm working on a Dash app that displays in the browser. Is there something similar I can do to export to PDF that doesn't require using Jupyter?

HyrumDickinson avatar Jul 14 '22 13:07 HyrumDickinson

The options that occur to me are:

  • Download as SVG and use a separate program to convert to PDF (mostly works, but occasionally inserts the wrong fonts, which can cause clipping )
  • Write a clientside callback that pulls out the figure and sends it to a dcc.Store, then a serverside callback that reads this store and feeds that figure to Kaleido to turn into a pdf, returning the output to a dcc.Download. You've noticed that the "live figure" post-interaction isn't what you see in the figure prop, but you can get it by doing (in JavaScript, as a clientside callback triggered by a button or something):
function getFigure() {
    var gd = document.getElementById('your-graph-id');
    var figure = {data: gd.data, layout: gd.layout};
    return figure;
}
  • There is a library I see svg2pdf.js. It's based on jsPDF though, which I looked into several years ago and found it didn't do a very good job; but maybe it's better now, at least if used via the svg2pdf wrapper?

alexcjohnson avatar Jul 14 '22 14:07 alexcjohnson