在我之前的文章中,我们介绍了如何使用 pandas Styler 对象创建美观的样式化数据框。在这篇文章中,我想向大家介绍第二种选择:Streamlit AgGrid。我将分享如何构建类似上面显示的数据框。阅读完这篇文章后,你将了解:
-
AgGrid 内部的关键组件。这些是
gridOptions()、configure_column()、configure_default_column()和configure_side_bar(). -
启用 通过直接 UI 过滤和聚合表格 的主要选项。不再需要为简单的转换构建临时查询!
-
使用 JavaScript 函数使数据框更美观。如果你想要,你可以将它们复制粘贴到你的代码中。或者查看我的 Git 仓库。
免责声明 1:我与 AgGrid 没有任何关联或合作关系。我只是发现这个开源产品非常有价值。AgGrid 确实有一个付费的分层产品,但本博客将仅使用 AgGrid 的免费组件。
免责声明 2:所有图像和 GIF 都是我自己创作的,除非另有说明。
什么是 AgGrid
AgGrid 是一个强大且可定制的表格组件,你可以在 Web 应用程序中使用它以表格格式显示和操作大量数据。我找到的最佳类比是,它是 Web 应用版本的 Excel。想象一下,它是一个超级增强的表格,不仅显示数据,还允许用户以多种方式与之交互,例如编辑单元格、聚合和旋转,甚至与图表集成。它实际上被许多企业使用。
现在,AgGrid 是使用 JavaScript 构建的 😱😱😱。所以,是的,有一些学习要做。但,你不需要成为 JavaScript 专家!这要归功于 Pablo Fonseca,他将 JavaScript AgGrid 组件的功能迁移到了 Streamlit 应用程序中。
理解 AgGrid 的基本组件
我开始我的 AgGrid 之旅是通过阅读 Ahmed Besbes 的文章:7 个理由说明为什么你应该使用 Streamlit AgGrid 组件 [2]。这是一个很好的起点,让我理解了 为什么 我想使用 AgGrid。然而,我缺少一个全面的教程来了解 如何 使用 AgGrid。在本节中,我将尝试涵盖使 AgGrid 在我脑海中变得清晰的概念。
基本 AgGrid:你只需要一个 dataframe 和 gridOptions 对象
AgGrid 方法有很多选项……请查看下面的截图。
图片来自文档并由作者编辑
实际上,你只需要两个参数:dataframe和gridOptions(黄色突出显示)。就是这样。只需传递 dataframe,AgGrid 就会自带一些酷炫的功能。
standard_AgGrid = AgGrid(
df,
gridOptions=GridOptionsBuilder.from_dataframe(df).build()
)
# You can see how you don't even need the st.dataframe() Streamlit method.
# Just by calling AgGrid, the rendering will automatically happen.
AgGrid 默认将允许你排序、筛选和移动列。与默认的 Streamlit *st.dataframe()*方法相比,这是一个很好的补充。下面是一系列 GIF,展示了默认 AgGrid 在功能方面为你提供了什么。
这就是如何选择和取消选择列
这就是如何重新排序列
这就是如何筛选数据
valueGetter 与 valueFormatter
要开始为我们的 dataframe 添加一些漂亮的格式,我们首先需要了解valueGetter和valueFormatter的作用。我将在稍后解释基本理论并展示示例。
-
valueGetter用于检索或计算应在单元格中显示的值。它可以用来操作或合并来自不同列的数据或执行计算。但不涉及格式化。 -
valueFormatter用于格式化单元格中的值以供显示。它不会改变实际值,只是改变显示时的外观。
// Imagine you have a table where you store product prices,
// but you want to display the price including tax (10%)
// You can use valueGetter to calculate the price including tax:
valueGetter: function(params) {
return params.data.price * 1.10; // Add 10% tax to the original price
}
// Instead of having 4 decimal points, you might want to DISPLAY only
// 1 decimal point and add a currency symbol.
// This what valueFormatter is for.
valueFormatter: function(params) {
return '$' + params.value.toFixed(1); // Display value as currency
}
但如何将这段 JavaScript 代码注入我们的 Python & Streamlit 代码中?
使用st_agrid包内提供的JsCode。请查看下面的代码示例:
from st_aggrid import AgGrid, GridOptionsBuilder, JsCode
# Define JsCode for valueGetter (convert cents to dollars)
value_getter = JsCode('''
function(params) {
return params.data.price_cents / 100; // Convert cents to dollars
}
''')
# Define JsCode for valueFormatter (format as currency)
value_formatter = JsCode('''
function(params) {
return '$' + params.value.toFixed(2); // Format the value as currency
}
''')
当我们使用configure_column()时,你将学习如何使用这些value_getter和value_formatter。
configure_column()是格式化魔法发生的地方
默认的 AgGrid 视图有一些很好的开箱即用的功能(排序、筛选、列选择和拖动列)。然而,输出有点单调… 🥱
要让它更好,我们需要结合一个value_getter和value_formatterJavaScript 函数集,并在configure_column()中使用它们。
不幸的是,文档不是很详细,但我将向你展示如何完成这些操作。
图片来自官方文档。关于configure_column的文档很少。只有一个other_column_properties 参数。
清理列标题
如果你只想以不同的方式显示列名,你不需要在数据框中重命名列。你可以通过header_name参数直接将其传递给configure_column()函数。
from st_aggrid import AgGrid, GridOptionsBuilder
grid_builder = GridOptionsBuilder.from_dataframe(df)
# Renaming "Period_1" to "Period 1"
grid_builder.configure_column('Period_1', header_name='Period 1')
# Build grid options
gridOptions = grid_builder.build()
grid_response = AgGrid(df,
gridOptions=gridOptions,
)
将"Period_1"重命名为"Period 1"
货币格式化
你想在数字前添加货币符号,分隔千位并强制使用一定数量的小数点吗?让我们第一次使用value_getter、value_formatter和JsCode。
下面的代码执行以下操作:
-
定义单元格将使用哪个值。
currency_getter将使用我们传递给它的字段中的值。 -
定义你希望在单元格中显示的值。
currency_formatter将返回一个currency_symbol + formattedNumber。 -
将变量传递到我们的
JsCode公式中。 使用cellRendererParams。例如,currency_formatter将如何知道使用哪个符号和多少小数点?cellRendererParams允许我们将变量传递到我们的 JavaScript 函数中。 -
启用 Streamlit 渲染自定义 JavaScript 代码。 在
AgGrid()中使用allow_unsafe_jscode=True。
currency_formatter = JsCode("""
function(params) {
if (params.value == null || params.value === undefined) {
return '';
}
var decimalPoints = params.column.colDef.cellRendererParams.decimalPoints || 0;
var currencySymbol = params.column.colDef.cellRendererParams.currencySymbol || '€';
var value = params.value;
// Format the number with thousand separators and decimal points
var formattedNumber = value.toLocaleString('en-US', {
minimumFractionDigits: decimalPoints,
maximumFractionDigits: decimalPoints
});
return currencySymbol + formattedNumber;
}
""")
currency_getter = JsCode("""
function(params) {
return params.data[params.colDef.field];
}
""")
grid_builder = GridOptionsBuilder.from_dataframe(df)
grid_builder.configure_column(
'Period_1',
header_name='Period 1',
type=['numericColumn', 'numberColumnFilter', 'customNumericFormat'],
valueGetter=currency_getter,
valueFormatter=currency_formatter,
cellRendererParams={
'decimalPoints': 0,
'currencySymbol': '€',
}
)
# Build grid options
gridOptions = grid_builder.build()
grid_response = AgGrid(df,
gridOptions=gridOptions,
allow_unsafe_jscode=True,
)
使用这个来表示Period1*、Period2和Difference*,我们得到以下结果
货币格式化
百分比变化格式化
如果你已经理解了上面的代码片段,那么下一个将很容易理解。
percentage_formatter = JsCode("""
function(params) {
if (params.value == null) {
return '';
}
var decimalPoints = params.column.colDef.cellRendererParams.decimalPoints || 2;
return (params.value * 100).toFixed(decimalPoints) + '%';
}
""")
percentage_getter = JsCode("""
function(params) {
return params.data[params.colDef.field];
}
""")
# jumping directly to configure_column()
grid_builder.configure_column(
'Percentage Change',
header_name='Percentage Change (%)',
type=['numericColumn', 'numberColumnFilter', 'customNumericFormat'],
valueGetter=percentage_getter,
valueFormatter=percentage_formatter,
cellRendererParams={'decimalPoints': 1,},
)
百分比变化格式化
突出显示单元格背景
我们如何重新创建我们在使用Styler对象时显示的绿色和红色渐变?
-
到现在为止,你应该知道我们首先需要创建一个
JsCode函数。这个函数比较长,所以最好查看我的仓库。 -
但我们没有看到如何传递这个 UI 自定义格式化。这是通过
configure_column()中的cellStyle参数完成的。
# Check my git repo for the function details
cellStyle = JsCode(
"""function(params) {...}"""
)
grid_builder.configure_column(
'Percentage Change',
header_name='Percentage Change (%)',
type=['numericColumn', 'numberColumnFilter', 'customNumericFormat'],
valueGetter=percentage_getter,
valueFormatter=percentage_formatter,
cellRendererParams={'decimalPoints': 1,
'minValue': df['Percentage Change'].min(),
'maxValue': df['Percentage Change'].max()
},
cellStyle=cellStyle, # here is where we format the UI appearance of a cell
)
突出显示单元格背景
添加表情符号
因为表情符号只是单元格中的额外字符,所以我们不需要value_getter,只需要value_formatter。记住,只有当你需要value_formatter对单元格执行操作(乘以 100、四舍五入等)时,你才需要value_getter。在这种情况下,不需要对表情符号进行操作。函数很简单。
# Define JsCode for emoji formatting
medalFormatter = JsCode("""
function(params) {
if (params.value == null || params.value === undefined) {
return '';
}
var val = params.value;
if (val === 1) {
return val + ' 🥇';
} else if (val === 2) {
return val + ' 🥈';
} else if (val === 3) {
return val + ' 🥉';
} else {
return val;
}
}
""")
# Define JsCode for country formatting
countryFormatter = JsCode("""
function(params) {
if (params.value == null || params.value === undefined) {
return '';
}
var countryEmojis = {
"US": "🇺🇸 ",
"IN": "🇮🇳 ",
"BR": "🇧🇷 ",
"ES": "🇪🇸 ",
"AR": "🇦🇷 ",
"IT": "🇮🇹 ",
"EG": "🇪🇬 "
// Add more countries as needed
};
var countryCode = params.value;
var emoji = countryEmojis[countryCode] || '';
return emoji + ' ' + countryCode;
}
""")
# jumping directly to configure_column()
grid_builder.configure_column(
'Percentage Change rank',
header_name='Percentage Change rank',
type=['numericColumn', 'numberColumnFilter', 'customNumericFormat'],
valueFormatter=medalFormatter,
)
grid_builder.configure_column(
'Country',
header_name='Country',
type=['textColumn', 'stringColumnFilter'],
valueFormatter=countryFormatter,
)
添加表情符号
添加条形图
在 Excel 中,我们多次看到单元格的格式化,其中单元格背景有条纹。我们可以在 AgGrid 中实现相同的效果(类似于突出单元格背景部分,请检查我的仓库中的代码。这里粘贴太长了](https://github.com/JoseParrenoGarcia/Streamlit-pretty-dataframes/blob/5497afa74c46a88b95d00f163561ab57e78f7b4c/utils/aggrid_styling.py#L90))。
在第 1 期和差异中添加条形图。注意,当存在负数(差异列)时,条形图使用单元格的中间作为锚点渲染。
改变整体表格 UI 显示
到目前为止,我们确实使数据框的单元格变得更漂亮了。AgGrid 还允许控制与整个表格相关的功能。例如:
-
手动设置表格的整体高度和/或宽度
-
改变表格的主题
让我们看看一些这些示例:
手动设置表格的整体高度
默认情况下,AgGrid 将在表格末尾添加空白。请查看下面的截图:
要控制表格的高度,非常简单;只需使用height参数。在下面的代码片段中,我决定使用每行 60px,这仍然会添加空白,但您可以将其更改为您方便的值。
grid_response = AgGrid(
df,
gridOptions=gridOptions,
allow_unsafe_jscode=True,
height=min(2000, (len(df)) * 60), # 60px per row or 2000px
)
改变表格的主题
在 Streamlit AgGrid 中,您只有 4 个选项可以更改主题:streamlit、balham、alpine 和 material。我的默认主题是 balham,因为它是最密集的表格。但下面您可以看到每个主题的列和行的宽度。
grid_response = AgGrid(
df,
gridOptions=gridOptions,
allow_unsafe_jscode=True,
height=min(2000, (len(df)) * 60), # 60px per row or 2000px
fit_columns_on_grid_load=False,
theme='balham', # options: streamlit, alpine, balham, material
)
主题:streamlit
主题 alpine
主题 material
添加分页
分页对于处理大数据集是必不可少的。本博客文章中使用的数据只有 7 行长,但如果我们配置分页以每 3 行创建一页,它看起来会是这样。
# Enable pagination
grid_builder.configure_pagination(
paginationAutoPageSize=False,
paginationPageSize=3
)
3 行分页
将 AgGrid 对象传递以供以后使用
记得 AgGrid 提供的过滤行为有多酷吗?那么,如果我们能将过滤后的数据框传递以供以后使用会怎样?为此,我们需要启用两个参数:data_return_mode 和 update_mode。我们还需要创建一个新的数据框,包含网格响应数据。
grid_response = AgGrid(
df,
gridOptions=gridOptions,
allow_unsafe_jscode=True,
height=min(2000, (len(df)) * 60), # 60px per row or 2000px
fit_columns_on_grid_load=False,
theme='balham', # options: streamlit, alpine, balham, material
data_return_mode='FILTERED_AND_SORTED', # there are other options, read the docs
update_mode='MODEL_CHANGED' # there are other options, read the docs
)
# https://streamlit-aggrid.readthedocs.io/en/docs/AgGrid.html
# Create filtered dataframe
filtered_df = pd.DataFrame(grid_response['data'])
return grid_response, filtered_df
检查 Streamlit 中的行为。
如何将(上方)过滤后的数据框(DataFrame)作为新的输出(下方)传递的示例。GIF 有点长,请等待大约 30 秒以完全渲染。
在 UI 中允许聚合
每当我创建 Streamlit 应用时,我通常需要手动创建聚合功能。例如,添加一个“按…聚合”的st.selectbox并链接到一个聚合函数。AgGrid 提供了无需编写这些小部件和函数的选项。下面是如何做到这一点:
-
在
configure_default_column()中强制聚合配置 -
对于每一列,指定您想要执行哪种聚合函数。
grid_builder = GridOptionsBuilder.from_dataframe(df)
grid_builder.configure_side_bar()
grid_builder.configure_default_column(
filter=True,
groupable=True,
value=True,
enableRowGroup=True,
aggFunc="sum" # sum would be applied to all columns
)
grid_builder.configure_column(
'Month',
header_name='Month',
type=['numericColumn', 'numberColumnFilter'],
aggFunc=None, # If you dont want month to be passed to the "sum" aggregation, use None
)
grid_builder.configure_column(
'Percentage Change',
header_name='Percentage Change (%)',
type=['numericColumn', 'numberColumnFilter', 'customNumericFormat'],
aggFunc="avg", # you can specify the average for % change
valueGetter=percentage_getter,
valueFormatter=percentage_formatter,
cellRendererParams={'decimalPoints': 1,
},
)
AgGrid 显示聚合的方式很棒,它还允许您对“按列分组”进行深入分析。
通过 UI 实时运行聚合的示例。
摘要
如果您已经看到这里,请接受我的敬意 🙇 .我知道这是一篇很长的帖子,但我想要写一些有用的详细示例。我在其他地方没有找到教程,希望这能提供类似的内容。
总结我们已涵盖的内容:
-
AgGrid 的基本组件。
-
格式化表格单元格的函数。
-
如何格式化整个数据框。
-
如何将数据框作为输出对象传递
-
如何使用 UI 进行聚合。
您在哪里可以找到代码?
在我的仓库和实时 Streamlit 应用中:
-
Github 仓库:
github.com/JoseParrenoGarcia/Streamlit-pretty-dataframes -
Streamlit 应用:
app-pretty-dataframes-in2ilkxjw2hgby4uqj9bq2.streamlit.app(当链接打开时,点击按钮以启动应用)。
致谢
-
[1] Pablo Fonseca,JavaSript AgGrid 组件.
进一步阅读
感谢阅读这篇文章!如果您对我的其他书面内容感兴趣,这里有一篇文章收集了我所有其他博客文章,按主题组织:数据科学团队和项目管理、数据故事讲述、营销与投标科学以及机器学习与建模。
请保持关注!
如果您想在我发布新的书面内容时获得通知,请随意在 Medium 上关注我或订阅我的 Substack 通讯。此外,我很乐意在领英上与您聊天!

被折叠的 条评论
为什么被折叠?



