如何创建样式优美的 Streamlit Dataframes,第二部分:使用 AgGrid

原文:towardsdatascience.com/how-to-create-well-styled-streamlit-dataframes-part-2-using-aggrid-dbff2d52f6a2

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/8d687f292355e8adb944c7b0f24d5d4e.png

在我之前的文章中,我们介绍了如何使用 pandas Styler 对象创建美观的样式化数据框。在这篇文章中,我想向大家介绍第二种选择:Streamlit AgGrid。我将分享如何构建类似上面显示的数据框。阅读完这篇文章后,你将了解:

  1. AgGrid 内部的关键组件。这些是 gridOptions()configure_column()configure_default_column()configure_side_bar().

  2. 启用 通过直接 UI 过滤和聚合表格 的主要选项。不再需要为简单的转换构建临时查询!

  3. 使用 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 方法有很多选项……请查看下面的截图。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/76395afe91d81e57687780625d10e186.png

图片来自文档并由作者编辑

实际上,你只需要两个参数dataframegridOptions(黄色突出显示)。就是这样。只需传递 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.

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/3717036988d491e4f4cb1b9e48ebbfed.png

AgGrid 默认将允许你排序、筛选移动列。与默认的 Streamlit *st.dataframe()*方法相比,这是一个很好的补充。下面是一系列 GIF,展示了默认 AgGrid 在功能方面为你提供了什么。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/74c211d2b744e4cb5ded0ab2a95e41e3.png

这就是如何选择和取消选择列

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/1088a37d9f4df8f27b349b57b0fb29e1.png

这就是如何重新排序列

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/addf67e46e048cf2722f8cea78ba4e4b.png

这就是如何筛选数据

valueGetter 与 valueFormatter

要开始为我们的 dataframe 添加一些漂亮的格式,我们首先需要了解valueGettervalueFormatter的作用。我将在稍后解释基本理论并展示示例。

  • 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_gettervalue_formatter


configure_column()是格式化魔法发生的地方

默认的 AgGrid 视图有一些很好的开箱即用的功能(排序、筛选、列选择和拖动列)。然而,输出有点单调… 🥱

要让它更好,我们需要结合一个value_gettervalue_formatterJavaScript 函数集,并在configure_column()中使用它们。

不幸的是,文档不是很详细,但我将向你展示如何完成这些操作。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/f7facbf1436e65884d8bc284489fb2ab.png

图片来自官方文档。关于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,
                       )

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/963ab76f865c349c296a1528d4fa67be.png

将"Period_1"重命名为"Period 1"

货币格式化

你想在数字前添加货币符号,分隔千位并强制使用一定数量的小数点吗?让我们第一次使用value_gettervalue_formatterJsCode

下面的代码执行以下操作:

  1. 定义单元格将使用哪个值。 currency_getter将使用我们传递给它的字段中的值。

  2. 定义你希望在单元格中显示的值。 currency_formatter将返回一个currency_symbol + formattedNumber

  3. 将变量传递到我们的JsCode公式中。 使用cellRendererParams。例如,currency_formatter将如何知道使用哪个符号和多少小数点?cellRendererParams允许我们将变量传递到我们的 JavaScript 函数中。

  4. 启用 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*、Period2Difference*,我们得到以下结果

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/64d4ee1e3d323b1f486bac3c45ff58a2.png

货币格式化

百分比变化格式化

如果你已经理解了上面的代码片段,那么下一个将很容易理解。

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,},
  )

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/33d4d3044746527b881720fb2368b7a5.png

百分比变化格式化

突出显示单元格背景

我们如何重新创建我们在使用Styler对象时显示的绿色和红色渐变?

  1. 到现在为止,你应该知道我们首先需要创建一个JsCode函数。这个函数比较长,所以最好查看我的仓库

  2. 但我们没有看到如何传递这个 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
)

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/d864791e39621c392da30bda6d6cab99.png

突出显示单元格背景

添加表情符号

因为表情符号只是单元格中的额外字符,所以我们不需要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,
)

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/f2855f6b1bf5216dbffbecdec39a161c.png

添加表情符号

添加条形图

在 Excel 中,我们多次看到单元格的格式化,其中单元格背景有条纹。我们可以在 AgGrid 中实现相同的效果(类似于突出单元格背景部分,请检查我的仓库中的代码。这里粘贴太长了](https://github.com/JoseParrenoGarcia/Streamlit-pretty-dataframes/blob/5497afa74c46a88b95d00f163561ab57e78f7b4c/utils/aggrid_styling.py#L90))。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/adfd6d79751d28532197b251aa438761.png

在第 1 期和差异中添加条形图。注意,当存在负数(差异列)时,条形图使用单元格的中间作为锚点渲染。


改变整体表格 UI 显示

到目前为止,我们确实使数据框的单元格变得更漂亮了。AgGrid 还允许控制与整个表格相关的功能。例如:

  • 手动设置表格的整体高度和/或宽度

  • 改变表格的主题

让我们看看一些这些示例:

手动设置表格的整体高度

默认情况下,AgGrid 将在表格末尾添加空白。请查看下面的截图:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/8c3718db353679dbf9d23d8a60c1bfec.png

要控制表格的高度,非常简单;只需使用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 个选项可以更改主题:streamlitbalhamalpinematerial。我的默认主题是 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
)

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/66caa4b3b403aba8aa5d7a0c75b929f4.png

主题:streamlit

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/c5097eb82737d2c263b2d78df1dfa632.png

主题 alpine

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/130e5a60ebc6a0da4709f441f8b5df1e.png

主题 material

添加分页

分页对于处理大数据集是必不可少的。本博客文章中使用的数据只有 7 行长,但如果我们配置分页以每 3 行创建一页,它看起来会是这样。

# Enable pagination
grid_builder.configure_pagination(
  paginationAutoPageSize=False, 
  paginationPageSize=3
)

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/4dc75cb1c1a8e924196dfdafd884c06b.png

3 行分页


将 AgGrid 对象传递以供以后使用

记得 AgGrid 提供的过滤行为有多酷吗?那么,如果我们能将过滤后的数据框传递以供以后使用会怎样?为此,我们需要启用两个参数:data_return_modeupdate_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 中的行为。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/7ec7ce28c8b7a82d82509378a8e009e6.png

如何将(上方)过滤后的数据框(DataFrame)作为新的输出(下方)传递的示例。GIF 有点长,请等待大约 30 秒以完全渲染。


在 UI 中允许聚合

每当我创建 Streamlit 应用时,我通常需要手动创建聚合功能。例如,添加一个“按…聚合”的st.selectbox并链接到一个聚合函数。AgGrid 提供了无需编写这些小部件和函数的选项。下面是如何做到这一点:

  1. configure_default_column()中强制聚合配置

  2. 对于每一列,指定您想要执行哪种聚合函数。

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 显示聚合的方式很棒,它还允许您对“按列分组”进行深入分析。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/449a63d43da15a21392550c67fd0edbe.png

通过 UI 实时运行聚合的示例。


摘要

如果您已经看到这里,请接受我的敬意 🙇 .我知道这是一篇很长的帖子,但我想要写一些有用的详细示例。我在其他地方没有找到教程,希望这能提供类似的内容。

总结我们已涵盖的内容:

  1. AgGrid 的基本组件。

  2. 格式化表格单元格的函数。

  3. 如何格式化整个数据框。

  4. 如何将数据框作为输出对象传递

  5. 如何使用 UI 进行聚合。

您在哪里可以找到代码?

在我的仓库和实时 Streamlit 应用中:

致谢

进一步阅读

感谢阅读这篇文章!如果您对我的其他书面内容感兴趣,这里有一篇文章收集了我所有其他博客文章,按主题组织:数据科学团队和项目管理、数据故事讲述、营销与投标科学以及机器学习与建模。

所有我的书面文章都在一个地方

请保持关注!

如果您想在我发布新的书面内容时获得通知,请随意在 Medium 上关注我或订阅我的 Substack 通讯。此外,我很乐意在领英上与您聊天!

获取关于数据科学最新撰写内容的通知

Jose 的 Substack | Jose Parreño Garcia | Substack

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值