Last active
February 17, 2023 04:04
-
-
Save nathancooperjones/cbee3ee7421f14d1b9fd1a56ec4f9874 to your computer and use it in GitHub Desktop.
df_to_html - ShopRunner's open-sourced helper function to convert Pandas DataFrame's to HTML.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import pandas as pd | |
def df_to_html(df: pd.DataFrame, | |
image_cols: List[str] = [], | |
hyperlink_cols: List[str] = [], | |
html_tags: Dict[str, Union[str, List[str]]] = dict(), | |
transpose: bool = False, | |
image_width: Optional[int] = None, | |
max_num_rows: int = 200, | |
**kwargs) -> str: | |
""" | |
Convert a Pandas DataFrame to HTML. | |
Parameters | |
------------- | |
df: DataFrame | |
DataFrame to convert to HTML | |
image_cols: str or list | |
Column names that contain image urls or file paths. Columns specified as images will make | |
all other transformations to those columns be ignored. Local files will display correctly in | |
Jupyter if specified using relative paths but not if specified using absolute paths (see | |
https://github.com/jupyter/notebook/issues/3810). | |
hyperlink_cols: str or list | |
Column names that contain hyperlinks to open in a new tab | |
html_tags: dictionary | |
A transformation to be inserted directly into the HTML tag. | |
Ex: ``{'col_name_1': 'strong'}`` becomes ``<strong>col_name_1</strong>`` | |
Ex: ``{'col_name_2': 'mark'}`` becomes ``<mark>col_name_2</mark>`` | |
Ex: ``{'col_name_3': 'h2'}`` becomes ``<h2>col_name_3</h2>`` | |
Ex: ``{'col_name_4': ['em', 'strong']}`` becomes ``<em><strong>col_name_4</strong></em>`` | |
transpose: bool | |
Transpose the DataFrame before converting to HTML | |
image_width: int | |
Set image width for each image generated | |
max_num_rows: int | |
Maximum number of rows to display | |
**kwargs: keyword arguments | |
Additional arguments sent to ``pandas.DataFrame.to_html``, as listed in: | |
https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.to_html.html | |
Returns | |
------------- | |
df_html: HTML | |
DataFrame converted to a HTML string, ready for displaying | |
Examples | |
------------- | |
In a Jupyter notebook: | |
.. code-block:: python | |
from IPython.core.display import display, HTML | |
import pandas as pd | |
df = pd.DataFrame({ | |
'item': ['Beefy Fritos® Burrito'], | |
'price': ['1.00'], | |
'image_url': ['https://www.tacobell.com/images/22480_beefy_fritos_burrito_269x269.jpg'], | |
}) | |
display( | |
HTML( | |
df_to_html( | |
df, | |
image_cols='image_url', | |
html_tags={'item': 'strong', 'price': 'em'}, | |
image_width=200, | |
) | |
) | |
) | |
Notes | |
------------- | |
Converted table will have CSS class 'dataframe', unless otherwise specified. | |
""" | |
def _wrap_cols_if_needed(cols: [str, List[str]]) -> List[str]: | |
"""Necessary for columns named with integers.""" | |
try: | |
iter(cols) | |
except TypeError: | |
cols = [cols] | |
if isinstance(cols, str): | |
cols = [cols] | |
return cols | |
if max_num_rows is None or len(df) <= max_num_rows: | |
df = df.copy() # copy the dataframe so we don't edit the original! | |
else: | |
# explicit copy eliminates a warning we don't need | |
df = df.head(max_num_rows).copy() | |
image_cols = _wrap_cols_if_needed(image_cols) | |
for image_col in image_cols: | |
if image_col not in df.columns: | |
raise ValueError('{} not a column in df!'.format(image_col)) | |
if not image_width: | |
df[image_col] = df[image_col].map(lambda x: f'<img src="{x}">') | |
else: | |
df[image_col] = df[image_col].map(lambda x: f'<img src="{x}" width={image_width}>') | |
hyperlink_cols = _wrap_cols_if_needed(hyperlink_cols) | |
for hyperlink_col in hyperlink_cols: | |
if hyperlink_col not in df.columns: | |
raise ValueError('{} not a column in df!'.format(hyperlink_col)) | |
if hyperlink_col in image_cols: | |
continue | |
df[hyperlink_col] = ( | |
df[hyperlink_col].map(lambda x: f'<a target="_blank" href="{x}">{x}</a>') | |
) | |
for col, transformations in html_tags.items(): | |
if col not in df.columns: | |
raise ValueError(f'{col} not a column in df!') | |
if col in image_cols: | |
continue | |
if isinstance(transformations, str): | |
transformations = [transformations] | |
opening_tag = '' | |
for extra in transformations: | |
opening_tag += f'<{extra}>' | |
closing_tag = '' | |
for extra in transformations[::-1]: | |
closing_tag += f'</{extra}>' | |
df[col] = df[col].map(lambda x: f'{opening_tag}{x}{closing_tag}') | |
max_colwidth = pd.get_option('display.max_colwidth') | |
if pd.__version__ != '0': | |
# this option is not backwards compatible with Pandas v1.0.0 | |
pd.set_option('display.max_colwidth', None) | |
else: | |
pd.set_option('display.max_colwidth', -1) | |
if transpose: | |
df = df.T | |
df_html = df.to_html(escape=False, **kwargs) | |
pd.set_option('display.max_colwidth', max_colwidth) | |
return df_html |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment