使用to_html将CSS类应用于Pandas DataFrame

59
我在使用Pandas的“to_html”方法时遇到麻烦,无法应用“classes”参数来为DataFrame设置样式。
“classes:str或list或tuple,默认值为None。要应用于生成的HTML表格的CSS类。”
从:https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.to_html.html 例如,我可以这样呈现一个样式化的DataFrame:
df = pd.DataFrame([[1, 2], [1, 3], [4, 6]], columns=['A', 'B'])

myhtml = df.style.set_properties(**{'font-size': '11pt', 'font-family': 'Calibri','border-collapse': 'collapse','border': '1px solid black'}).render()

with open('myhtml.html','w') as f:
    f.write(myhtml)        

我该如何使用“类”和“to_html”样式化来自DataFrame的HTML输出,例如:

df.to_html('myhtml.html',classes=<something here>)

2
你想要 HTML 文件看起来怎么样? - U13-Forward
我想应用在示例中“set_properties”方法中给出的相同属性。 - sparrow
1
创建一个字符串 "<style type='text/css'>" + myStyles + "</style>" 并将其附加到 df.to_html() 给出的字符串中。 - user8745435
8个回答

101
Pandas的to_html函数会输出一个大字符串,其中包含HTML表格标记。classes参数是一个方便的处理器,可以给<table>添加class属性,在之前创建的CSS文档中引用它。因此,将to_html纳入引用外部CSS的更广泛的HTML文档构建中。
有趣的是,to_html会添加双重类<table class="dataframe mystyle">,这些类可以在CSS中单独引用,例如:.dataframe {...} .mystyle{...}或者同时使用.dataframe.mystyle {...}。下面展示了使用随机数据的示例。 Data
import pandas as pd
import numpy as np

pd.set_option('display.width', 1000)
pd.set_option('colheader_justify', 'center')

np.random.seed(6182018)
demo_df = pd.DataFrame({'date': np.random.choice(pd.date_range('2018-01-01', '2018-06-18', freq='D'), 50),
                        'analysis_tool': np.random.choice(['pandas', 'r', 'julia', 'sas', 'stata', 'spss'],50),              
                        'database': np.random.choice(['postgres', 'mysql', 'sqlite', 'oracle', 'sql server', 'db2'],50), 
                        'os': np.random.choice(['windows 10', 'ubuntu', 'mac os', 'android', 'ios', 'windows 7', 'debian'],50), 
                        'num1': np.random.randn(50)*100,
                        'num2': np.random.uniform(0,1,50),                   
                        'num3': np.random.randint(100, size=50),
                        'bool': np.random.choice([True, False], 50)
                       },
                        columns=['date', 'analysis_tool', 'num1', 'database', 'num2', 'os', 'num3', 'bool']
          )


print(demo_df.head(10))
#      date    analysis_tool     num1      database     num2        os      num3  bool 
# 0 2018-04-21     pandas     153.474246       mysql  0.658533         ios   74    True
# 1 2018-04-13        sas     199.461669      sqlite  0.656985   windows 7   11   False
# 2 2018-06-09      stata      12.918608      oracle  0.495707     android   25   False
# 3 2018-04-24       spss      88.562111  sql server  0.113580   windows 7   42   False
# 4 2018-05-05       spss     110.231277      oracle  0.660977  windows 10   76    True
# 5 2018-04-05        sas     -68.140295  sql server  0.346894  windows 10    0    True
# 6 2018-05-07      julia      12.874660    postgres  0.195217         ios   79    True
# 7 2018-01-22          r     189.410928       mysql  0.234815  windows 10   56   False
# 8 2018-01-12     pandas    -111.412564  sql server  0.580253      debian   30   False
# 9 2018-04-12          r      38.963967    postgres  0.266604   windows 7   46   False

CSS (保存为df_style.css)

/* includes alternating gray and white with on-hover color */

.mystyle {
    font-size: 11pt; 
    font-family: Arial;
    border-collapse: collapse; 
    border: 1px solid silver;

}

.mystyle td, th {
    padding: 5px;
}

.mystyle tr:nth-child(even) {
    background: #E0E0E0;
}

.mystyle tr:hover {
    background: silver;
    cursor: pointer;
}

Pandas

pd.set_option('colheader_justify', 'center')   # FOR TABLE <th>

html_string = '''
<html>
  <head><title>HTML Pandas Dataframe with CSS</title></head>
  <link rel="stylesheet" type="text/css" href="df_style.css"/>
  <body>
    {table}
  </body>
</html>.
'''

# OUTPUT AN HTML FILE
with open('myhtml.html', 'w') as f:
    f.write(html_string.format(table=demo_df.to_html(classes='mystyle')))

输出

HTML (引用了df_style.css,在同一目录下;表格中的class参数参见)

<html>
  <head><title>HTML Pandas Dataframe with CSS</title></head>
  <link rel="stylesheet" type="text/css" href="df_style.css"/>
  <body>
    <table border="1" class="dataframe mystyle">
  <thead>
    <tr style="text-align: center;">
      <th></th>
      <th>date</th>
      <th>analysis_tool</th>
      <th>num1</th>
      <th>database</th>
      <th>num2</th>
      <th>os</th>
      <th>num3</th>
      <th>bool</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>2018-04-21</td>
      <td>pandas</td>
      <td>153.474246</td>
      <td>mysql</td>
      <td>0.658533</td>
      <td>ios</td>
      <td>74</td>
      <td>True</td>
    </tr>
    <tr>
      <th>1</th>
      <td>2018-04-13</td>
      <td>sas</td>
      <td>199.461669</td>
      <td>sqlite</td>
      <td>0.656985</td>
      <td>windows 7</td>
      <td>11</td>
      <td>False</td>
    </tr>
    <tr>
      <th>2</th>
      <td>2018-06-09</td>
      <td>stata</td>
      <td>12.918608</td>
      <td>oracle</td>
      <td>0.495707</td>
      <td>android</td>
      <td>25</td>
      <td>False</td>
    </tr>
    <tr>
      <th>3</th>
      <td>2018-04-24</td>
      <td>spss</td>
      <td>88.562111</td>
      <td>sql server</td>
      <td>0.113580</td>
      <td>windows 7</td>
      <td>42</td>
      <td>False</td>
    </tr>
    <tr>
      <th>4</th>
      <td>2018-05-05</td>
      <td>spss</td>
      <td>110.231277</td>
      <td>oracle</td>
      <td>0.660977</td>
      <td>windows 10</td>
      <td>76</td>
      <td>True</td>
    </tr>
    ...
  </tbody>
</table>
  </body>
</html>

HTML Output


2
谢谢,这很令人困惑,因为在使用“to_html”之前需要在“html_string”中引用“.css”文件的类。似乎应该有一种直接从参数指定“.css”文件的方法。 - sparrow
9
我认为混淆实际上是由于pandas的作者将方法标记为 to_html(),而实际上应该标记为 to_html_table_string()。这个方法不会生成完整的HTML文档,并且class 是在 <table> 输出中创建的一个特殊属性。另外,class 不仅仅适用于CSS,还可以在Javascript / JQuery和其他方面使用。 - Parfait
3
不是这样的。查看页面源代码,你会发现即使你的浏览器渲染了一个表格,仍然缺少<html><body>和其他标签。 - Parfait
有没有办法在从数据框打印的表格中添加标题? - Lost1
自2018年以来,pandas.Styler在添加CSS样式和构造HTML输出方面发生了许多变化。请查看文档,因为现在可能不再需要本回答中的许多内容。 - Attack68
显示剩余6条评论

14

实际上,pandas.to_html() 只是导出一个普通的 HTML 表格。您可以将表格插入到正文中的任何位置,并通过样式部分中的 CSS 控制样式。

<html>
<head>
<style> 
  table, th, td {{font-size:10pt; border:1px solid black; border-collapse:collapse; text-align:left;}}
  th, td {{padding: 5px;}}
</style>
</head>
<body>
{
  pandas.to_html()
}
</body>
</html>

这种方法对我来说最有效,因为我使用imgkit生成PNG格式的PDF报告。 - beep_check
样式部分在哪里? - liang

8
我发现最准确、最简单的方法是跳过样式、to_html()等,使用df.to_dict()方法将DF转换为字典。
具体让我遇到麻烦的是在Outlook邮件中显示样式化的pandas html,因为它只会以pandas产生的css混乱形式呈现。
迭代字典并生成所需标签的键/值,添加类等,然后将所有内容连接成一个字符串。然后将此字符串粘贴到预先定义好的带有预定义的CSS的模板中。
为了方便起见,我发现两次导出相同的df非常有用,先使用.to_dict()填充列,然后逐行处理。或者只使用相关列名的列表。
dict_data = [df.to_dict(), df.to_dict('index')]

return_str = '<table><tr>'

for key in dict_data[0].keys():
    return_str = return_str + '<th class="header">' + key + '</th>'

return_str = return_str + '</tr>'

for key in dict_data[1].keys():
    return_str = return_str + '<tr><th class="index">' + key + '</th>'
    for subkey in dict_data[1][key]:
        return_str = return_str + '<td>' + dict_data[1][key][subkey] + '</td>'

return_str = return_str + '</tr></table>'

然后return_str进入模板。


昨天和今天我经过了很多使用jQuery来进行样式设置、添加属性和类的努力,终于达成了目标。同意。 - imbr

4

感谢Ku Tang Pan的回答 - 我能够将他们的解决方案定制为更精确的内容。我个人喜欢根据某些值有条件地格式化我的表格。

我发现自己生成HTML是最精确的方法,并且可以完全控制。

##note how any row that has the drop alert flag set to "Y" will be formatted yellow:

dict_data = [df.to_dict(), df.to_dict('index')]

htmldf = '<table><tr>'

for key in dict_data[0].keys():
    htmldf = htmldf + '<th class="header">' + key + '</th>'

htmldf = htmldf + '</tr>'

for key in dict_data[1].keys():
    htmldf = htmldf + '<tr '
    htmldf = htmldf + 'style="font-weight: bold; background-color: yellow">' if dict_data[1][key]['drop_alert'] == 'Y' else htmldf + '>'
    for subkey in dict_data[1][key]:
        htmldf = htmldf + '<td>' + str(dict_data[1][key][subkey]) + '</td>'
    htmldf = htmldf + '</tr>'

htmldf = htmldf + '</tr></table>'

# Write html object to a file (adjust file path; Windows path is used here)
with open('C:\\Users\\Documents\\test.html','wb') as f:
    f.write(htmldf.encode("UTF-8"))

结果: 整洁的条件格式化表格

enter image description here


3

以下是我是如何做到的:

创建一个文本文件,用于存放CSS代码,并在其中编写您的CSS代码,例如css_style.txt。 现在在Python文件中将此txt文件作为字符串读取。

with open('css_style.txt', 'r') as myfile: style = myfile.read()

现在,在HTML代码中使用此样式:

"""<html><head>Something Something</head>{1}<div>{0}</div></html>""".format(some_panda_dataframe.to_html,style)

在我的情况下,css_style.txt文件是

<style>
table {
  border-collapse: collapse;
  width: 100%;
}

th {
  text-align: center;
  padding: 8px;
}

td {
  text-align: left;
  padding: 8px;
}

tr:nth-child(even){background-color: #FFD5D5}

th {
  background-color: #0000FF;
  color: white;
}
</style>

2

除了我早期的 to_html 答案,新的 Pandas 1.3.0+ to_xml 可以仅使用样式表(即 CSS 和 XSLT)渲染 HTML 文档,而无需进行任何字符串格式化。

虽然复制相同的 HTML 表格设计需要涉及一些复杂的 XSLT,但用户可以自定义更改。

数据

import pandas as pd
import numpy as np

np.random.seed(1032022)
demo_df = pd.DataFrame({
    'date': np.random.choice(pd.date_range('2021-01-01', '2021-12-31', freq='D'), 50),
    'analysis_tool': np.random.choice(['pandas', 'r', 'julia', 'sas', 'stata', 'spss'],50),
    'num1': np.random.randn(50)*100,
    'database': np.random.choice(['postgres', 'mysql', 'sqlite', 'oracle', 'sql server', 'db2'],50),
    'num2': np.random.uniform(0,1,50),
    'os': np.random.choice(['windows 10', 'ubuntu', 'mac os', 'android', 'ios', 'windows 7', 'debian'],50),                    
    'num3': np.random.randint(100, size=50),
    'bool': np.random.choice([True, False], 50)
})

print(demo_df.head(10))
#         date analysis_tool        num1  ...          os  num3   bool
# 0 2021-05-02         stata   52.370960  ...  windows 10    36  False
# 1 2021-03-16        pandas -135.411727  ...     android    74  False
# 2 2021-12-17           sas  -56.823191  ...      debian    75  False
# 3 2021-11-11        pandas  -32.575253  ...      debian    33  False
# 4 2021-11-19         julia  176.464891  ...      mac os    63   True
# 5 2021-12-30             r  -82.874595  ...      ubuntu    52   True
# 6 2021-03-27             r   63.897578  ...     android    56  False
# 7 2021-03-14         julia  -75.117220  ...      mac os     6  False
# 8 2021-04-09          spss -302.664890  ...         ios    97   True
# 9 2021-03-15          spss  -12.014122  ...         ios    27   True

CSS (save as DataFrameStyle.css)

/* includes alternating gray and white with on-hover color */

.mystyle {
    font-size: 11pt; 
    font-family: Arial;
    border-collapse: collapse; 
    border: 1px solid silver;

}

.mystyle td, th {
    padding: 5px;
}

.mystyle tr:nth-child(even) {
    background: #E0E0E0;
}

.mystyle tr:hover {
    background: silver;
    cursor: pointer;
}

XSLT (保存为DataFrameStyle.xsl;引用.css)

XSLT是一种用于转换XML文档的语言。在这里,我们将保存一个名为DataFrameStyle.xsl的文件,并引用一个名为.css的样式表文件。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" omit-xml-declaration="no" indent="yes"/>

    <xsl:template match="/data">
      <html>
        <head><title>HTML Pandas Dataframe with CSS</title></head>
        <link rel="stylesheet" type="text/css" href="DataFrameStyle.css"/>
        <body>
          <table border="1" class="dataframe mystyle">
            <thead>
                <tr style="text-align: center;">
                    <xsl:apply-templates select="row[1]/*" mode="headers"/>
                </tr>
            </thead>
            <tbody>
                <xsl:apply-templates select="row"/>
            </tbody>
          </table>
        </body>
      </html>
    </xsl:template>

    <xsl:template match="row[1]/*" mode="headers">
        <th><xsl:value-of select="local-name()"/></th>
    </xsl:template>

    <xsl:template match="row">
        <tr><xsl:apply-templates select="*"/></tr>
    </xsl:template>
    
    <xsl:template match="row/*">
       <td><xsl:value-of select="."/></td>
    </xsl:template>

</xsl:stylesheet>

Pandas

demo_df.to_xml(
    "/path/to/Output.html",
    stylesheet = "DataFrameStyle.xsl"
)

输出

HTML表格输出


1

由于pandas的to_html功能不足

使用下面的代码,您可以将列重复作为<tr>属性,这对于静态、写入事件等非常重要。

参数

  • row_attrs(列表,可选):要写入为行<tr>元素中的属性的列列表。默认为无。
  • row_cols(列表,可选):要写入为行元素的子元素(即<td>元素)的列列表。默认为所有列。
import xml.etree.ElementTree as etree

def dataframe_to_html(df, row_attrs=[], row_cols=None):
    """
    Converts dataframe to an html <table> as an ElementTree class.  
        * df (pandas.DataFrame): table
        * row_attrs (list, optional): List of columns to write as attributes in <tr> row element. Defaults to [] none.
        * row_cols (list, optional): List of columns to write as children in row <td> element. Defaults to all columns.               
    - returns: ElementTree class containing an html <table>      
    Note: generate a string with `etree.tostring(dataframe_to_html(...), encoding='unicode', method='xml')`
    """
    if not row_cols: # default to use all columns as sub-elements of row
        row_cols = df.columns.to_list()   
    table = df.astype(str) # turns everything on str
    table_dict = table.to_dict('split')
    col2index = { v:i for i, v in enumerate(table_dict['columns']) }    
    def add_rows(root, table_dict, row_attrs_, row_cols_, tag_row='tr', tag_col='td'):            
        for row in table_dict:
            # row attrs names and values in lower-case (key:value)
            row_attrs = { key.lower(): row[col2index[key]].lower() for key in row_attrs_ } 
            erow = etree.SubElement(root, tag_row, attrib=row_attrs) 
            for col in row_cols_:
                ecol = etree.SubElement(erow, tag_col)
                ecol.text = str(row[col2index[col]])
    etable = etree.Element('table')
    thead = etree.SubElement(etable, 'thead') 
    add_rows(thead, [table_dict['columns']], [], row_cols, 'tr', 'th')
    tbody = etree.SubElement(etable, 'tbody')     
    add_rows(tbody, table_dict['data'], row_attrs, row_cols)
    return etable   

使用方法

...
# manipulate your dataframe and create `row_attrs` and `row_cols`
html_table = dataframe_to_html(table, row_attrs, row_cols)
# then convert your etree to string to use on flask template for example
html_table = etree.tostring(html_table, encoding='unicode', method='xml')
render_template('index.html', pandas_table=html_table...) # your template variables

注意:<tr> 行属性名称应使用小写字母。

进一步建议:仍可以使用etree包中的ElementTree对表格进行额外的自定义。


0
"table_id"是一个参数,允许在df.to-html()中包含CSS id。
示例:
df.to_html(df_html_path,table_id = ".df #tableFormat" )

现在必须将css_id(.df #tableFormat)连接到main_html文件,然后可以将导出的df.to_html文件作为iframe导入。 < p > < em >示例(包括以下代码行):

df_css.css

.df #tableFormat{
    show_dimensions : True;
    bold_rows : True;
    justify:center;}

main_html.html(将 df_css 链接到 main_html):

<link rel="stylesheet" href="df_css.css"/>  

main_html.html(将df_html链接到main_html):

<iframe  src="df_html_path"></iframe >

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接