Python PDF Reports in Python/v3
How to make PDF reports with Python and Plotly Graphs.
See our Version 4 Migration Guide for information about how to upgrade.
Creating PDF Reports with Plotly Graphs and Python¶
Since Plotly graphs can be embedded in HTML or exported as a static image, you can embed Plotly graphs in reports suited for print and for the web.
This notebook is a primer on creating PDF reports with Python from HTML with Plotly graphs. This notebook uses:
- Plotly for interactive, web native graphs
- IPython Notebook to create this notebook, combining text, HTML, and Python code
- xhtml2pdf to convert HTML to PDF in Python
! pip install xhtml2pdf
Part 1 - Create the HTML Template¶
# The public plotly graphs to include in the report. These can also be generated with `py.plot(figure, filename)`
graphs = [
'https://plotly.com/~christopherp/308',
'https://plotly.com/~christopherp/306',
'https://plotly.com/~christopherp/300',
'https://plotly.com/~christopherp/296'
]
from IPython.display import display, HTML
def report_block_template(report_type, graph_url, caption=''):
if report_type == 'interactive':
graph_block = '<iframe style="border: none;" src="{graph_url}.embed" width="100%" height="600px"></iframe>'
elif report_type == 'static':
graph_block = (''
'<a href="{graph_url}" target="_blank">' # Open the interactive graph when you click on the image
'<img style="height: 400px;" src="{graph_url}.png">'
'</a>')
report_block = ('' +
graph_block +
'{caption}' + # Optional caption to include below the graph
'<br>' + # Line break
'<a href="{graph_url}" style="color: rgb(190,190,190); text-decoration: none; font-weight: 200;" target="_blank">'+
'Click to comment and see the interactive graph' + # Direct readers to Plotly for commenting, interactive graph
'</a>' +
'<br>' +
'<hr>') # horizontal line
return report_block.format(graph_url=graph_url, caption=caption)
interactive_report = ''
static_report = ''
for graph_url in graphs:
_static_block = report_block_template('static', graph_url, caption='')
_interactive_block = report_block_template('interactive', graph_url, caption='')
static_report += _static_block
interactive_report += _interactive_block
Display the interactive report, suited for the web¶
This version contains the interactive version of the Plotly graphs, served from Plotly's server
display(HTML(interactive_report))
Display the static report, to be converted to PDF¶
This version contains the static version of the Plotly graphs, also served from Plotly's server
display(HTML(static_report))
Looks good!
Part 2 - Convert the HTML to PDF with xhtml2pdf
¶
from xhtml2pdf import pisa # import python module
# Utility function
def convert_html_to_pdf(source_html, output_filename):
# open output file for writing (truncated binary)
result_file = open(output_filename, "w+b")
# convert HTML to PDF
pisa_status = pisa.CreatePDF(
source_html, # the HTML to convert
dest=result_file) # file handle to recieve result
# close output file
result_file.close() # close output file
# return True on success and False on errors
return pisa_status.err
convert_html_to_pdf(static_report, 'report.pdf')
! open report.pdf
Generating Images on the fly¶
The static report in the example above uses graphs that were already created in Plotly. Sometimes it's helpful to use graph images that are created on-the-fly. For example, if you're using plotly.js to create the web-reports you might not be saving the graphs to accounts on plot.ly.
To create static images of graphs on-the-fly, use the plotly.plotly.image
class. This class generates images by making a request to the Plotly image server.
Here's an alternative template that uses py.image.get
to generate the images and template them into an HTML and PDF report.
import plotly.plotly as py
import base64
width = 600
height = 600
template = (''
'<img style="width: {width}; height: {height}" src="data:image/png;base64,{image}">'
'{caption}' # Optional caption to include below the graph
'<br>'
'<hr>'
'')
# A collection of Plotly graphs
figures = [
{'data': [{'x': [1,2,3], 'y': [3,1,6]}], 'layout': {'title': 'the first graph'}},
{'data': [{'x': [1,2,3], 'y': [3,7,6], 'type': 'bar'}], 'layout': {'title': 'the second graph'}}
]
# Generate their images using `py.image.get`
images = [base64.b64encode(py.image.get(figure, width=width, height=height)).decode('utf-8') for figure in figures]
report_html = ''
for image in images:
_ = template
_ = _.format(image=image, caption='', width=width, height=height)
report_html += _
display(HTML(report_html))
convert_html_to_pdf(report_html, 'report-2.pdf')