如何创建优雅的 Streamlit 数据框,第一部分:使用 Pandas Styler

原文:towardsdatascience.com/how-to-create-well-styled-streamlit-dataframes-part-1-using-the-pandas-styler-e239c0fbe145

我一直是 pandas 中的 styler 方法 的粉丝。当我开始构建 Streamlit 应用程序时,对我来说很清楚,我想样式化我的数据框以帮助可视化数据框,但…惊喜!截至写作时,Streamlit st.dataframe() 不支持 Styler 对象,只支持数据框对象。好吧,更正一下,它确实支持它们,但 UI 显示非常糟糕!

这就是为什么我想与你分享我在 Streamlit 中构建优雅数据框的工作方法和想法。我们将涵盖:

  1. 如何为数字添加千位分隔符。

  2. 如何将数字显示为百分比 (从数据中的 0.24 到 UI 中的 24%)

  3. 如何添加货币符号。

  4. 如何为单元格添加颜色。 更好的是,我将与你分享我最喜欢的颜色分级函数。

  5. 如何添加表情符号! 是的,我们不能没有表情符号 😊 !

st.dataframe() 的默认视图

Streamlit 实际上非常擅长根据数据类型推断最佳显示。想象以下数据框:

mock_data = {
"Country": ["US", "IN", "BR", "ES", "AR", "IT"],
"Period_1": [50_000, 30_000, 17_000, 14_000, 22_000, 16_000], 
"Period_2": [52_000, 37_000, 16_000, 12_000, 21_000, 19_000], 
} 

df = pd.DataFrame(mock_data) 
df['Difference'] = df['Period_2'] - df['Period_1'] 
df['Percentage Change'] = np.round(((df['Period_2'] - df['Period_1']) / df['Period_1']), 2) 
df['Percentage Change rank'] = df['Percentage Change'].rank(method='dense', ascending=False).astype(int)

默认的 st.dataframe() 视图已经很不错了。例如,千位分隔符被正确推断。

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

图片由作者提供

但是,我们知道我们可以使用 Styler 函数来让它变得更好!

如果我们使用 st.dataframe() 一个 Styler 对象会发生什么?

在深入探讨如何样式化数据框之前,让我们简单地将 pandas 数据框转换为 Styler 对象,并检查当我们尝试使用 st.dataframe() 方法渲染 Styler 对象时会发生什么。

# Creating the styler object
df.copy().style

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

图片由作者提供

显示现在有点混乱。例如:

  • 大数字没有逗号分隔符

  • 小数点后 6 位的小数。

这只发生因为我们从“数据框”类型对象转换到了“样式化”类型对象。

格式化千位分隔符和百分比

我们希望一眼就能直观地理解数量级(即千位分隔符)。而且我们不想在心理上乘以小数点 100 来理解百分比(即弄清楚 0.24 是 24%)。

下面的函数将帮助您格式化数字,以便在样式化的数据框中更好地显示。

def _format_with_thousands_commas(val): 
  return f'{val:,.0f}' 

def _format_as_percentage(val, prec=0): 
  return f'{val:.{prec}%}' 

thousands_cols = ['Period_1', 'Period_2', 'Difference'] 
perct_cols = ['Percentage Change'] 

styler_with_thousands_commas = (
  raw_styler
  .format(_format_with_thousands_commas, subset=thousands_cols) 
  .format(lambda x: _format_as_percentage(x, 2), subset=perct_cols) 
  )

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

图片由作者提供

看起来更好了。

  • _ 周期1,_ 周期2差异 列现在与 *st.dataframe()* 显示相同。所以,我们至少匹配了默认显示。

  • 但现在,百分比变化 列比默认的小数点格式更易于理解 😊。

添加带有渐变的背景着色

带有颜色的 dataframe => Streamlit 中的良好样式化 dataframe(吉米·克里克特说:颜色过多可能有害)。

我们的下一步是添加一些颜色来帮助我们的视觉分析。我们可以使用简单的 cmap 应用单元格背景渐变。默认情况下,cmap 会根据序列中的数字创建渐变(即,取序列的最小值和最大值)。如果你的数字都是正数或负数,这很完美,但以下情况怎么办?

  • 仅对正值使用绿色渐变色

  • 仅对负值使用红色渐变色。

为了这个,我创建了一个简单的函数,我在多个情况下都重新使用了它:

def _format_positive_negative_background_colour(val, min_value, max_value): 
  if val > 0: 
    # Normalize positive values to a scale of 0 to 1 
    normalized_val = (val - 0) / (max_value - 0) 
    # Create a gradient of green colors 
    color = plt.cm.Greens(normalized_val * 0.7) 
    color_hex = mcolors.to_hex(color) 
  elif val < 0: 
    # Normalize negative values to a scale of 0 to -1 
    normalized_val = (val - min_value) / (0 - min_value) 
    # Create a gradient of red colors 
    color = plt.cm.Reds_r(normalized_val * 0.7) 
    color_hex = mcolors.to_hex(color) 
  else: color_hex = 'white' # For zero values, set the background color to white 

  # Determine text color based on the darkness of the background color 
  r, g, b = mcolors.hex2color(color_hex) 
   if (r * 299 + g * 587 + b * 114) / 1000 > 0.5: # Use the formula for perceived brightness 
    text_color = 'black' 
   else: 
    text_color = 'white' 

  return f'background-color: {color_hex}; color: {text_color}' 

min_value_abs_diff = df['Difference'].min() 
max_value_abs_diff = df['Difference'].max() 

min_value_perct_diff = df['Percentage Change'].min() 
max_value_perct_diff = df['Percentage Change'].max() 

styler_with_colour_gradients = (
  df.copy().style 
  .map(lambda x: _format_positive_negative_background_colour(x, min_value_abs_diff, max_value_abs_diff), subset=['Difference']) 
  .map(lambda x: _format_positive_negative_background_colour(x, min_value_perct_diff, max_value_perct_diff), subset=['Percentage Change']) 
)

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

作者图片

你可以看到所有正数都着色为绿色,并且从最低(浅色)到最高(深色)有一个阴影。相反,负数着色为红色,但最低的是最深色的颜色。

此外,该函数还确定文本颜色应该是白色还是黑色,这取决于它与单元格背景颜色的对比度。

添加货币符号

如果你知道你正在处理货币,为什么不将货币符号添加到数据中呢?这正是 Excel 所做的,而且嘿,Excel 是一个了不起的产品。老实说,这里没有讽刺。

def _format_with_dollar_sign(val, prec=0): 
  return f'${val:,.{prec}f}' 

styler_with_dollar_sign = (
  df.copy().style 
  .format(_format_with_dollar_sign, subset=['Period_1', 'Period_2', 'Difference']) 
)

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

作者图片

💲 检查 _Period__1, _Period__2 和 _Differenc_e 列 💲

添加表情符号的函数

我们生活在表情符号的世界里,所以你的应用程序在 Streamlit 中没有表情符号的样式化数据框是不可能的。开个玩笑,表情符号也可以帮助我们进行视觉分析。在这个例子中,我使用了金牌、银牌和铜牌表情符号来突出显示最高的正百分比变化。

def _add_medal_emoji(val): 
  if val == 1: 
    return f"{val} 🥇" 
  elif val == 2: 
    return f"{val} 🥈" 
  elif val == 3: 
    return f"{val} 🥉" 
  else: return val 

styler_with_medal_emoji = (
  df.copy().style 
  .format(_add_medal_emoji, subset=['Percentage Change rank']) 
)

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

作者图片

一眼就能看出,哪些国家在 Period 1 和 Period 2 之间有最大的正变化,使用了奖牌表情符号。

目前不支持:添加条形

你是否在 Styler 对象的单元格背景中使用了条形图?遗憾的是,它们在 st.dataframe() 方法中不受支持。您 可以 使用带有 HTML 对象的 st.write() 方法来显示它们,但我 不推荐这样做。下面你可以看到它的样子。

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

作者图片

不仅用户界面令人震惊……你完全失去了所有 st.dataframe() 功能,例如排序和格式化单元格的能力。

摘要

如果 Streamlit 支持 Styler 对象,生活将会容易得多。但直到那时,我希望这些想法能帮助您在创建 Streamlit 应用程序的优秀可视化过程中。 我将接着使用 AgGrid 构建等效的漂亮数据框。请保持关注,因为 AgGrid 比 Styler 对象酷多了!

代码在哪里可以找到?

在我的仓库和实时 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、付费专栏及课程。

余额充值