如何在Python中基于Pandas DataFrame正确动态生成包含<thead>与<tbody>的完整HTML表格?
如何在Python中基于Pandas DataFrame正确动态生成包含与的完整HTML表格?
嘿,我看了你的问题和代码,理论上你的拼接逻辑方向是对的,但可能是字符串拼接时的格式细节或者索引匹配问题,导致<tr>没有被正确包裹在<tbody>标签里。给你两个实用的调整方案,帮你解决这个问题:
方案一:优化字符串拼接逻辑,避免索引匹配错误
原来的代码里用enumerate(subjects)再通过iloc[i]取统计值,万一subjects和统计序列的索引顺序不匹配,就可能导致行内容异常;另外用列表收集行内容再合并,比逐段拼接字符串更清晰,不容易出现格式漏洞。
修改后的函数如下:
import pandas as pd import streamlit as st def Analyse(df_multiselect): # 定义固定的表头部分 thead_html = """ <thead> <tr> <th colspan="1">المواد</th> <th colspan="1">الحاضرون</th> <th colspan="1">المتوسط الحسابي</th> <th colspan="1">الانحراف المعياري</th> <th colspan="1">التباين</th> <th colspan="1">أعلى نقطة</th> <th colspan="1">الوسيط</th> <th colspan="1">أدنى نقطة</th> <th colspan="1">المدى</th> </tr> </thead> """ # 动态选择科目列 subjects = df_multiselect.columns[11:26] columns = df_multiselect.iloc[:, 11:26] # 把统计量整理成字典,直接用科目名索引更可靠 stats = { "count": columns.count(), "mean": round(columns.mean(), 2), "std": round(columns.std(), 2), "var": round(columns.var(), 2), "max": columns.max(), "min": columns.min(), "range": round(columns.max() - columns.min(), 2), "median": round(columns.median(), 2) } # 用列表收集所有tbody行,避免逐段拼接的格式问题 tbody_rows = [] for subject in subjects: row = f""" <tr> <td>{subject}</td> <td>{stats['count'][subject]}</td> <td>{stats['mean'][subject]:.2f}</td> <td>{stats['std'][subject]:.2f}</td> <td>{stats['var'][subject]:.2f}</td> <td>{stats['min'][subject]}</td> <td>{stats['median'][subject]}</td> <td>{stats['max'][subject]}</td> <td>{stats['range'][subject]:.2f}</td> </tr> """ tbody_rows.append(row) # 组合tbody部分 tbody_html = f"<tbody>{''.join(tbody_rows)}</tbody>" # 拼接完整表格 table_html = f""" <table id="data-table" class="table display nowrap" width="auto"> {thead_html} {tbody_html} </table> """ return table_html # 调用函数生成表格 table_html = Analyse(df_multiselect) # 生成完整HTML页面 full_html = f""" <section> <div class="container"> <div class="row g-5 align-items-center"> <a id="titleElement" class="btn btn-primary-soft">تحليل النتائج </a> <div class="about-image-gallery"> <div class="scroll-container"> {table_html} </div> </div> </div> </div> </section> """ # 在Streamlit中渲染 st.markdown(full_html, unsafe_allow_html=True)
方案二:利用Pandas内置的to_html方法,减少手动拼接工作量
Pandas的DataFrame.to_html方法可以自动生成带<thead>和<tbody>的标准HTML表格,我们只需要先把统计量整理成新的DataFrame,再生成表格即可,这样几乎不会出现手动拼接的格式错误:
import pandas as pd import streamlit as st def Analyse(df_multiselect): # 动态选择目标列 columns = df_multiselect.iloc[:, 11:26] # 把所有统计量整理成一个新的DataFrame stats_df = pd.DataFrame({ "المواد": columns.columns, "الحاضرون": columns.count(), "المتوسط الحسابي": round(columns.mean(), 2), "الانحراف المعياري": round(columns.std(), 2), "التباين": round(columns.var(), 2), "أعلى نقطة": columns.max(), "الوسيط": round(columns.median(), 2), "أدنى نقطة": columns.min(), "المدى": round(columns.max() - columns.min(), 2) }) # 直接生成标准HTML表格,设置参数指定样式和ID table_html = stats_df.to_html( index=False, # 去掉默认的索引列 classes="table display nowrap", table_id="data-table", col_space="auto" ) # 如果需要更自定义的表头(比如调整colspan),可以替换默认的thead部分 custom_thead = """ <thead> <tr> <th colspan="1">المواد</th> <th colspan="1">الحاضرون</th> <th colspan="1">المتوسط الحسابي</th> <th colspan="1">الانحراف المعياري</th> <th colspan="1">التباين</th> <th colspan="1">أعلى نقطة</th> <th colspan="1">الوسيط</th> <th colspan="1">أدنى نقطة</th> <th colspan="1">المدى</th> </tr> </thead> """ # 替换原有的thead start_idx = table_html.find("<thead>") end_idx = table_html.find("</thead>") + 8 table_html = table_html.replace(table_html[start_idx:end_idx], custom_thead) return table_html # 后续调用和渲染代码和方案一一致 table_html = Analyse(df_multiselect) full_html = f""" <section> <div class="container"> <div class="row g-5 align-items-center"> <a id="titleElement" class="btn btn-primary-soft">تحليل النتائج </a> <div class="about-image-gallery"> <div class="scroll-container"> {table_html} </div> </div> </div> </div> </section> """ st.markdown(full_html, unsafe_allow_html=True)
额外检查建议
你可以先打印table_html的完整内容,确认<tbody>标签是否正确包裹了所有<tr>行。如果打印出来的HTML是标准正确的,但Streamlit显示有异常,可能是容器的CSS样式导致视觉上的错觉,你可以给scroll-container添加合适的溢出样式,比如:
.scroll-container { overflow-x: auto; white-space: nowrap; }
备注:内容来源于stack exchange,提问作者Haddadi Abdraouf
相关产品推荐
相关产品推荐

