{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "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:\n", "- [Plotly](https://plotly.com/python/) for interactive, web native graphs\n", "- [IPython Notebook](https://plotly.com/ipython-notebooks) to create this notebook, combining text, HTML, and Python code\n", "- [xhtml2pdf](https://github.com/chrisglass/xhtml2pdf/tree/master/doc) to convert HTML to PDF in Python\n", "\n", "Run `! pip install xhtml2pdf` in the Terminal to install the `xhtml2pdf` package." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Create the HTML Template\n", "First choose the plots that you'd like to add to the report." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": true }, "outputs": [], "source": [ "graphs = ['https://plotly.com/~christopherp/308',\n", " 'https://plotly.com/~christopherp/306',\n", " 'https://plotly.com/~christopherp/300',\n", " 'https://plotly.com/~christopherp/296']" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "from IPython.display import display, HTML\n", "\n", "def report_block_template(report_type, graph_url, caption=''):\n", " if report_type == 'interactive':\n", " graph_block = ''\n", " elif report_type == 'static':\n", " graph_block = (''\n", " '' # Open the interactive graph when you click on the image\n", " ''\n", " '')\n", "\n", " report_block = ('' +\n", " graph_block + \n", " '{caption}' + # Optional caption to include below the graph\n", " '
' + # Line break\n", " ''+ \n", " 'Click to comment and see the interactive graph' + # Direct readers to Plotly for commenting, interactive graph\n", " '' + \n", " '
' + \n", " '
') # horizontal line \n", "\n", " return report_block.format(graph_url=graph_url, caption=caption)\n", "\n", "\n", "interactive_report = ''\n", "static_report = ''\n", "\n", "for graph_url in graphs:\n", " _static_block = report_block_template('static', graph_url, caption='')\n", " _interactive_block = report_block_template('interactive', graph_url, caption='')\n", "\n", " static_report += _static_block\n", " interactive_report += _interactive_block" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Display the Interactive Report \n", "\n", "This version, suited for the web, contains the interactive version of the Plotly graphs, served from Plotly's server." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "scrolled": false }, "outputs": [ { "data": { "text/html": [ "
Click to comment and see the interactive graph


Click to comment and see the interactive graph


Click to comment and see the interactive graph


Click to comment and see the interactive graph

" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display(HTML(interactive_report))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Display the Static Report\n", "This version is easy to convert to PDF. It contains the static version of the Plotly graphs, also served from Plotly's server." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
Click to comment and see the interactive graph


Click to comment and see the interactive graph


Click to comment and see the interactive graph


Click to comment and see the interactive graph

" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display(HTML(static_report))" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "ename": "ImportError", "evalue": "cannot import name inputstream", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mImportError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mxhtml2pdf\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mxhtml2pdf\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mpisa\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;32m/Users/chelsea/venv/venv2.7/lib/python2.7/site-packages/xhtml2pdf/pisa.py\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# -*- coding: utf-8 -*-\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mxhtml2pdf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdefault\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mDEFAULT_CSS\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mxhtml2pdf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdocument\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mpisaDocument\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mxhtml2pdf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mutil\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mgetFile\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mxhtml2pdf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mversion\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mVERSION\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mVERSION_STR\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/Users/chelsea/venv/venv2.7/lib/python2.7/site-packages/xhtml2pdf/document.py\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# -*- coding: utf-8 -*-\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mxhtml2pdf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcontext\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mpisaContext\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mxhtml2pdf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdefault\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mDEFAULT_CSS\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mxhtml2pdf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mparser\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mpisaParser\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mreportlab\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mplatypus\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mflowables\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mSpacer\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/Users/chelsea/venv/venv2.7/lib/python2.7/site-packages/xhtml2pdf/context.py\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 21\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0murlparse\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 22\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mxhtml2pdf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdefault\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 23\u001b[0;31m \u001b[0;32mimport\u001b[0m \u001b[0mxhtml2pdf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mparser\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 24\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 25\u001b[0m \u001b[0;31m# Copyright 2010 Dirk Holtwick, holtwick.it\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/Users/chelsea/venv/venv2.7/lib/python2.7/site-packages/xhtml2pdf/parser.py\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0;31m# limitations under the License.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 16\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 17\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mhtml5lib\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mtreebuilders\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minputstream\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 18\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mxhtml2pdf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdefault\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mTAGS\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mSTRING\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mINT\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mBOOL\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mSIZE\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mCOLOR\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mFILE\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mxhtml2pdf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdefault\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mBOX\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mPOS\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mMUST\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mFONT\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mImportError\u001b[0m: cannot import name inputstream" ] } ], "source": [ "import xhtml2pdf\n", "from xhtml2pdf import pisa" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Part 2 - Convert the HTML to PDF with `xhtml2pdf`" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "ename": "ImportError", "evalue": "cannot import name inputstream", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mImportError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mxhtml2pdf\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mpisa\u001b[0m \u001b[0;31m# import python module\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;31m# Utility function\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mconvert_html_to_pdf\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msource_html\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moutput_filename\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;31m# open output file for writing (truncated binary)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/xhtml2pdf/pisa.py\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# -*- coding: utf-8 -*-\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mxhtml2pdf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdefault\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mDEFAULT_CSS\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mxhtml2pdf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdocument\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mpisaDocument\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mxhtml2pdf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mutil\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mgetFile\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mxhtml2pdf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mversion\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mVERSION\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mVERSION_STR\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/xhtml2pdf/document.py\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# -*- coding: utf-8 -*-\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mxhtml2pdf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcontext\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mpisaContext\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mxhtml2pdf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdefault\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mDEFAULT_CSS\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mxhtml2pdf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mparser\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mpisaParser\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mreportlab\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mplatypus\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mflowables\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mSpacer\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/xhtml2pdf/context.py\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 21\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0murlparse\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 22\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mxhtml2pdf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdefault\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 23\u001b[0;31m \u001b[0;32mimport\u001b[0m \u001b[0mxhtml2pdf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mparser\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 24\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 25\u001b[0m \u001b[0;31m# Copyright 2010 Dirk Holtwick, holtwick.it\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/xhtml2pdf/parser.py\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0;31m# limitations under the License.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 16\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 17\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mhtml5lib\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mtreebuilders\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minputstream\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 18\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mxhtml2pdf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdefault\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mTAGS\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mSTRING\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mINT\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mBOOL\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mSIZE\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mCOLOR\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mFILE\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mxhtml2pdf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdefault\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mBOX\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mPOS\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mMUST\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mFONT\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mImportError\u001b[0m: cannot import name inputstream" ] } ], "source": [ "from xhtml2pdf import pisa\n", "\n", "# Utility function\n", "def convert_html_to_pdf(source_html, output_filename):\n", " # open output file for writing (truncated binary)\n", " result_file = open(output_filename, \"w+b\")\n", "\n", " # convert HTML to PDF\n", " pisa_status = pisa.CreatePDF(\n", " source_html, # the HTML to convert\n", " dest=result_file) # file handle to recieve result\n", "\n", " # close output file\n", " result_file.close() # close output file\n", "\n", " # return True on success and False on errors\n", " return pisa_status.err\n", "\n", "convert_html_to_pdf(static_report, 'report.pdf')\n", "\n", "! open report.pdf" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Generating Images *on the fly*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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](https://plotly.com/javascript-graphing-library) to create the web-reports you might not be saving the graphs to accounts on [plot.ly](https://plotly.com).\n", "\n", "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.\n", "\n", "Here's an alternative template that uses `py.image.get` to generate the images and template them into an HTML and PDF report." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/html": [ "



" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "0" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import plotly.plotly as py\n", "import base64\n", "\n", "width = 600\n", "height = 600\n", "\n", "template = (''\n", " '' \n", " '{caption}' # Optional caption to include below the graph\n", " '
'\n", " '
'\n", "'')\n", "\n", "# A collection of Plotly graphs\n", "figures = [\n", " {'data': [{'x': [1,2,3], 'y': [3,1,6]}], 'layout': {'title': 'the first graph'}},\n", " {'data': [{'x': [1,2,3], 'y': [3,7,6], 'type': 'bar'}], 'layout': {'title': 'the second graph'}}\n", "]\n", "\n", "# Generate their images using `py.image.get`\n", "images = [base64.b64encode(py.image.get(figure, width=width, height=height)).decode('utf-8') for figure in figures]\n", "\n", "report_html = ''\n", "for image in images:\n", " _ = template\n", " _ = _.format(image=image, caption='', width=width, height=height)\n", " report_html += _\n", "\n", "display(HTML(report_html))\n", "convert_html_to_pdf(report_html, 'report-2.pdf')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Learn more\n", "- Questions? \n", "- [Getting started with Plotly and Python](https://plotly.com/python/getting-started)\n", "- [Updating Plotly graphs with Python and cron jobs](http://moderndata.plot.ly/update-plotly-charts-with-cron-jobs-and-python/)\n", "- [Using Plotly offline in IPython notebooks](https://plotly.com/python/offline)\n", "- [Generate HTML reports with Python, Pandas, and Plotly](http://moderndata.plot.ly/generate-html-reports-with-python-pandas-and-plotly/)\n", "- [Emailing Plotly graphs with Python](https://plotly.com/python/email-reports/)\n", "- [Edit this tutorial](https://github.com/plotly/documentation/tree/gh-pages)" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Requirement already up-to-date: publisher in /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages\r\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "! pip install publisher --upgrade\n", "\n", "from IPython.display import HTML, display\n", "\n", "display(HTML(''))\n", "display(HTML(''))\n", "\n", "! pip install git+https://github.com/plotly/publisher.git --upgrade\n", "import publisher\n", "publisher.publish('pdf-reports.ipynb', 'python/pdf-reports/', 'PDF Reports'\n", " 'How to make PDF reports with Python and Plotly Graphs.',\n", " title = 'Python PDF Reports | plotly',\n", " name = 'PDF Reports',\n", " has_thumbnail='true', thumbnail='thumbnail/ipython_10_pdf_report.jpg', \n", " language='python', page_type='example_index',\n", " display_as='report_generation', order=1)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 2", "language": "python", "name": "python2" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.10" } }, "nbformat": 4, "nbformat_minor": 1 }