In pandas 1.3.0 and newer, the most appropriate way is to use the pandas Table Visualization and create a Subclass
Create a folder "templates" and two files "myhtml.tpl" and "mystyles.tpl"
In myhtml.tpl put any additional HTML code needed:
{% extends "html_table.tpl" %}
{% block table %}
<p style="font-family:verdana">Hi,</p>
<p style="font-family:verdana">sometext</p>
{{ super() }}
<p style="font-family:verdana">sometext</p>
<p style="font-family:verdana">Regards</p>
<p style="font-family:verdana">someme</p>
{% endblock table %}
In mystyles.tpl add any additional styles:
{% extends "html_style.tpl" %}
{% block style %}
{{ super() }}
<style>
table, th, td {
border: 1px solid black;
border-collapse: collapse;
}
th, td {
padding: 5px;
}
</style>
{% endblock style %}
(Code to generate this file structure is at the end of this answer)
We can now generate a Styler
subclass with from_custom_template
import numpy as np
import pandas as pd
from pandas.io.formats.style import Styler
# Build Styler Subclass from templates
MyStyler = Styler.from_custom_template(
"templates", # Folder to Search
html_table="myhtml.tpl", # HTML Template
html_style='mystyles.tpl' # CSS Template
)
# trim extra whitespace from HTML
MyStyler.env.trim_blocks = True
# Read in CSV
df = pd.read_csv('files/file.csv')
# Add styles using Styler apply and render to_html
html = MyStyler(df).apply(
lambda s: np.where(s >= 80, 'color: red', None), subset='Usage in %'
).format(
# Apply format string (remove insignificant zeros)
formatter='{:g}', subset='Usage in %'
).hide_index().to_html(doctype_html=True)
print(html)
The resulting html string is something like:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style type="text/css">
#T_22fdb_row2_col3,
#T_22fdb_row3_col3 {
color: red;
}
</style>
<style>
table,
th,
td {
border: 1px solid black;
border-collapse: collapse;
}
th,
td {
padding: 5px;
}
</style>
</head>
<body>
<p style="font-family:verdana">Hi,</p>
<p style="font-family:verdana">sometext</p>
<table id="T_22fdb_">
<thead>
<tr>
<th class="col_heading level0 col0">Server</th>
<th class="col_heading level0 col1">Total size</th>
<th class="col_heading level0 col2">Total Data in</th>
<th class="col_heading level0 col3">Usage in %</th>
</tr>
</thead>
<tbody>
<tr>
<td id="T_22fdb_row0_col0" class="data row0 col0">A</td>
<td id="T_22fdb_row0_col1" class="data row0 col1">100</td>
<td id="T_22fdb_row0_col2" class="data row0 col2">25</td>
<td id="T_22fdb_row0_col3" class="data row0 col3">25</td>
</tr>
<tr>
<td id="T_22fdb_row1_col0" class="data row1 col0">B</td>
<td id="T_22fdb_row1_col1" class="data row1 col1">100</td>
<td id="T_22fdb_row1_col2" class="data row1 col2">20</td>
<td id="T_22fdb_row1_col3" class="data row1 col3">20</td>
</tr>
<tr>
<td id="T_22fdb_row2_col0" class="data row2 col0">C</td>
<td id="T_22fdb_row2_col1" class="data row2 col1">100</td>
<td id="T_22fdb_row2_col2" class="data row2 col2">85</td>
<td id="T_22fdb_row2_col3" class="data row2 col3">85.6</td>
</tr>
<tr>
<td id="T_22fdb_row3_col0" class="data row3 col0">D</td>
<td id="T_22fdb_row3_col1" class="data row3 col1">100</td>
<td id="T_22fdb_row3_col2" class="data row3 col2">90</td>
<td id="T_22fdb_row3_col3" class="data row3 col3">90.8</td>
</tr>
</tbody>
</table>
<p style="font-family:verdana">sometext</p>
<p style="font-family:verdana">Regards</p>
<p style="font-family:verdana">someme</p>
</body>
</html>
The more naïve way to solve this problem would be to manipulate html strings directly with formatting, however, this can lead to poorly formed html:
import numpy as np
import pandas as pd
html = """
<html>
<head>
<style>
table, th, td {{ border: 1px solid black; border-collapse: collapse; }}
th, td {{ padding: 5px; }}
</style>
</head>
<body><p style="font-family:verdana">Hi,</p>
<p style="font-family:verdana">sometext</p>
{table}
<p style="font-family:verdana">sometext</p>
<p style="font-family:verdana">Regards</p>
<p style="font-family:verdana">someme</p>
</body></html>
"""
# Read in CSV
df = pd.read_csv('files/file.csv')
# Add styles using Styler apply and render to_html
table_html = df.style.apply(
lambda s: np.where(s >= 80, 'color: red', None), subset='Usage in %'
).format(
# Apply format string (remove insignificant zeros)
formatter='{:g}', subset=['Total Data in', 'Usage in %']
).hide_index().to_html()
html = html.format(table=table_html)
print(html)
Which results in the following html (notice the misplaced style element):
<html>
<head>
<style>
table, th, td { border: 1px solid black; border-collapse: collapse; }
th, td { padding: 5px; }
</style>
</head>
<body><p style="font-family:verdana">Hi,</p>
<p style="font-family:verdana">sometext</p>
<style type="text/css">
#T_139a3_row2_col3, #T_139a3_row3_col3 {
color: red;
}
</style>
<table id="T_139a3_">
<thead>
<tr>
<th class="col_heading level0 col0" >Server</th>
<th class="col_heading level0 col1" >Total size</th>
<th class="col_heading level0 col2" >Total Data in</th>
<th class="col_heading level0 col3" >Usage in %</th>
</tr>
</thead>
<tbody>
<tr>
<td id="T_139a3_row0_col0" class="data row0 col0" >A</td>
<td id="T_139a3_row0_col1" class="data row0 col1" >100</td>
<td id="T_139a3_row0_col2" class="data row0 col2" >25</td>
<td id="T_139a3_row0_col3" class="data row0 col3" >25</td>
</tr>
<tr>
<td id="T_139a3_row1_col0" class="data row1 col0" >B</td>
<td id="T_139a3_row1_col1" class="data row1 col1" >100</td>
<td id="T_139a3_row1_col2" class="data row1 col2" >20</td>
<td id="T_139a3_row1_col3" class="data row1 col3" >20</td>
</tr>
<tr>
<td id="T_139a3_row2_col0" class="data row2 col0" >C</td>
<td id="T_139a3_row2_col1" class="data row2 col1" >100</td>
<td id="T_139a3_row2_col2" class="data row2 col2" >85</td>
<td id="T_139a3_row2_col3" class="data row2 col3" >85.6</td>
</tr>
<tr>
<td id="T_139a3_row3_col0" class="data row3 col0" >D</td>
<td id="T_139a3_row3_col1" class="data row3 col1" >100</td>
<td id="T_139a3_row3_col2" class="data row3 col2" >90</td>
<td id="T_139a3_row3_col3" class="data row3 col3" >90.8</td>
</tr>
</tbody>
</table>
<p style="font-family:verdana">sometext</p>
<p style="font-family:verdana">Regards</p>
<p style="font-family:verdana">someme</p>
</body></html>
Simple script to build the templates folder and the two template files:
import pathlib
# Code to generate the Templates and folder
pathlib.Path('./templates').mkdir(exist_ok=True)
with open('./templates/myhtml.tpl', 'w') as f:
f.write('''
{% extends "html_table.tpl" %}
{% block table %}
<p style="font-family:verdana">Hi,</p>
<p style="font-family:verdana">sometext</p>
{{ super() }}
<p style="font-family:verdana">sometext</p>
<p style="font-family:verdana">Regards</p>
<p style="font-family:verdana">someme</p>
{% endblock table %}
'''.strip())
with open('./templates/mystyles.tpl', 'w') as f:
f.write('''
{% extends "html_style.tpl" %}
{% block style %}
{{ super() }}
<style>
table, th, td {
border: 1px solid black;
border-collapse: collapse;
}
th, td {
padding: 5px;
}
</style>
{% endblock style %}
'''.strip())
The files/file.csv
content:
Server,Total size,Total Data in,Usage in %
A,100,25,25
B,100,20,20
C,100,85,85.6
D,100,90,90.8