"""Utilities for report generation.
The module contains in particular routines the creation of tables, plots, etc.
inside the templates. Functions in this module are available from inside the
templates under the domain name ``pdf_tools``. For instance
``pdf_tools.dataframe_to_html()``.
"""
from bs4 import BeautifulSoup
import base64
import pandas
from io import BytesIO
import datetime
import textwrap
[docs]def dataframe_to_html(
dataframe,
extra_classes=(),
index=False,
header=True,
use_default_classes=True,
escape_html=False,
):
"""Return a HTML version of a dataframe with Semantic UI CSS style classes.
By default it applies the following Semantic UI classes:
'ui', 'compact', 'celled', 'striped', 'table', 'groups'
Parameters
----------
dataframe
The pandas dataframe to convert to PDF
extra_classes
Classes to add to the default, which are 'ui', 'compact', 'celled',
'striped', 'table', 'groups', selected to create nicely-formatted
Semantic UI tables. For instance 'definition' can be added to add
special emphasis on the first column. See Semantic UI documentation.
index
Whether to display the dataframe's index.
header
Whether to display the dataframe's headers.
escape_html
Whether the content of the dataframe should be html-escaped. Leave to
false if your dataframe contains images or any kind of HTML formatting.
"""
default_classes = ()
if use_default_classes:
default_classes = (
"ui",
"compact",
"celled",
"striped",
"table",
"groups",
)
classes = default_classes + tuple(extra_classes)
current_colwidth = pandas.get_option("display.max_colwidth")
pandas.set_option("display.max_colwidth", -1)
result = dataframe.to_html(
classes=classes, index=index, header=header, escape=escape_html
)
pandas.set_option("display.max_colwidth", current_colwidth)
return result
[docs]def style_table_rows(table_html, tr_modifier):
"""Return a new HTML string of the table, with rows modified.
Parameters
----------
table_html
A string "<table>...</table>" of an HTML table.
tr_modifier
A function that takes a BeautifulSoup ``tr`` element as argument
and changes its attributes inplace. for instance with
``tr.text = new_text``, or with the ``add_css_class`` method.
"""
soup = BeautifulSoup(table_html, "html.parser")
for tr in soup.find_all("tr"):
tr_modifier(tr)
return str(soup)
[docs]def add_css_class(element, cls):
"""Add a given class to the given BeautifulSoup HTML element."""
attrs = element.attrs
new_class = (attrs["class"] + " " if "class" in attrs else "") + cls
element.attrs["class"] = new_class
[docs]class JupyterPDF(object):
"""Class to display PDFs in a Jupyter / IPython notebook.
Just write this at the end of a code Cell to get in-browser PDF preview:
>>> from pdf_reports import JupyterPDF
>>> JupyterPDF("path_to_some.pdf")
Credits to StackOverflow's Jakob: https://stackoverflow.com/a/19470377
"""
def __init__(self, url, width=600, height=800):
self.url = url
self.width = width
self.height = height
def _repr_html_(self):
return """
<center>
<iframe src={self.url} width={self.width} height={self.height}>
</iframe>
</center>
""".format(
self=self
)
def now(fmt="%Y-%m-%d %H:%M"):
now = datetime.datetime.now()
if fmt is not None:
now = now.strftime(fmt)
return now
def wrap(text, col_width):
return "\n".join(textwrap.wrap(text, col_width))