Get dataframe row-selections from users

Streamlit 提供了两个命令,用于在您的应用程序中呈现美观、交互式的数据框。如果用户需要编辑数据、添加行或删除行,请使用 st.data_editor。如果您不希望用户更改数据框中的数据,请使用 st.dataframe。用户可以对使用 st.dataframe 呈现的数据进行排序和搜索。此外,您可以激活选择功能,以处理用户的行和列选择。

本教程使用了在Streamlit版本1.35.0中引入的行选择功能。对于使用st.data_editor的旧版解决方法,请参见获取数据框行选择(streamlit<1.35.0

  • 使用数据框行选择来过滤数据框。
  • 您的Python环境中必须安装以下内容:

    streamlit>=1.35.0
  • 你应该有一个干净的工作目录,名为 your-repository

  • 你应该对缓存和st.dataframe有一个基本的理解。

在这个例子中,你将构建一个应用程序,显示一个虚构组织的成员及其活动的表格。在表格中,用户可以选择一行或多行来创建过滤视图。你的应用程序将显示一个组合图表,比较所选员工。

以下是您将构建的内容:

Complete codeexpand_more
import numpy as np import pandas as pd import streamlit as st from faker import Faker @st.cache_data def get_profile_dataset(number_of_items: int = 20, seed: int = 0) -> pd.DataFrame: new_data = [] fake = Faker() np.random.seed(seed) Faker.seed(seed) for i in range(number_of_items): profile = fake.profile() new_data.append( { "name": profile["name"], "daily_activity": np.random.rand(25), "activity": np.random.randint(2, 90, size=12), } ) profile_df = pd.DataFrame(new_data) return profile_df column_configuration = { "name": st.column_config.TextColumn( "Name", help="The name of the user", max_chars=100, width="medium" ), "activity": st.column_config.LineChartColumn( "Activity (1 year)", help="The user's activity over the last 1 year", width="large", y_min=0, y_max=100, ), "daily_activity": st.column_config.BarChartColumn( "Activity (daily)", help="The user's activity in the last 25 days", width="medium", y_min=0, y_max=1, ), } select, compare = st.tabs(["Select members", "Compare selected"]) with select: st.header("All members") df = get_profile_dataset() event = st.dataframe( df, column_config=column_configuration, use_container_width=True, hide_index=True, on_select="rerun", selection_mode="multi-row", ) st.header("Selected members") people = event.selection.rows filtered_df = df.iloc[people] st.dataframe( filtered_df, column_config=column_configuration, use_container_width=True, ) with compare: activity_df = {} for person in people: activity_df[df.iloc[person]["name"]] = df.iloc[person]["activity"] activity_df = pd.DataFrame(activity_df) daily_activity_df = {} for person in people: daily_activity_df[df.iloc[person]["name"]] = df.iloc[person]["daily_activity"] daily_activity_df = pd.DataFrame(daily_activity_df) if len(people) > 0: st.header("Daily activity comparison") st.bar_chart(daily_activity_df) st.header("Yearly activity comparison") st.line_chart(activity_df) else: st.markdown("No members selected.")
  1. your_repository 中,创建一个名为 app.py 的文件。

  2. 在终端中,将目录更改为 your_repository 并启动您的应用程序。

    streamlit run app.py

    由于您仍然需要添加代码,您的应用程序将是空白的。

  3. app.py 中,编写以下内容:

    import numpy as np import pandas as pd import streamlit as st from faker import Faker

    你将按以下方式使用这些库:

    • 你将使用 faker 生成随机成员名称。
    • 你将使用 numpy 生成随机活动数据。
    • 你将使用 pandas 处理数据。
  4. 保存您的app.py文件并查看正在运行的应用程序。

  5. 点击“始终重新运行”或在运行的应用中按下“A”键。

    当您保存对app.py的更改时,您的运行预览将自动更新。您的预览仍然会是空白的。返回您的代码。

首先,您将定义一个函数来随机生成一些成员数据。如果您只想复制函数,可以跳过此部分。

Complete function to randomly generate member dataexpand_more
@st.cache_data def get_profile_dataset(number_of_items: int = 20, seed: int = 0) -> pd.DataFrame: new_data = [] fake = Faker() np.random.seed(seed) Faker.seed(seed) for i in range(number_of_items): profile = fake.profile() new_data.append( { "name": profile["name"], "daily_activity": np.random.rand(25), "activity": np.random.randint(2, 90, size=12), } ) profile_df = pd.DataFrame(new_data) return profile_df
  1. 使用@st.cache_data装饰器并开始你的函数定义。

    @st.cache_data def get_profile_dataset(number_of_items: int = 20, seed: int = 0) -> pd.DataFrame:

    @st.cache_data装饰器将get_profile_dataset()转换为一个缓存函数。Streamlit会保存缓存函数的输出,以便在再次使用相同输入调用缓存函数时重用。这在作为Streamlit执行模型的一部分重新运行时保持应用程序的性能。更多信息,请参见Caching

    get_profile_dataset函数有两个参数来配置数据集的大小和随机生成的种子。此示例将使用默认值(集合中的20个成员,种子为0)。该函数将返回一个pandas.DataFrame

  2. 初始化一个空列表来存储数据。

    new_data = []
  3. 初始化随机生成器。

    fake = Faker() random.seed(seed) Faker.seed(seed)
  4. 遍历一个范围以生成新的成员数据作为字典,并将其附加到您的列表中。

    for i in range(number_of_items): profile = fake.profile() new_data.append( { "name": profile["name"], "daily_activity": np.random.rand(25), "activity": np.random.randint(2, 90, size=12), } )

    对于daily_activity,您正在生成长度为25的数组。这些值是区间[0,1)中的浮点数。对于activity,您正在生成长度为12的数组。这些值是区间[2,90)中的整数。

  5. 将你的字典列表转换为一个单一的pandas.DataFrame并返回它。

    profile_df = pd.DataFrame(new_data) return profile_df
  6. 可选:通过调用并显示数据来测试您的函数。

    st.dataframe(get_profile_dataset())

    保存您的app.py文件以查看预览。在继续之前删除此行。

  1. 定义您的列配置以格式化您的数据。

    column_configuration = { "name": st.column_config.TextColumn( "Name", help="用户的名字", max_chars=100, width="medium" ), "activity": st.column_config.LineChartColumn( "Activity (1 year)", help="用户过去1年的活动", width="large", y_min=0, y_max=100, ), "daily_activity": st.column_config.BarChartColumn( "Activity (daily)", help="用户过去25天的活动", width="medium", y_min=0, y_max=1, ), }

    对于您的数据框的每一列,这定义了格式良好的列名、工具提示和列宽。您将使用折线图显示年度活动,并使用条形图显示每日活动。

  2. 插入一个标题来标识您将要显示的数据。

    st.header("All members")
  3. 将您的数据存储在一个方便的变量中。

    df = get_profile_dataset()
  4. 显示已激活选择功能的数据框。

    event = st.dataframe( df, column_config=column_configuration, use_container_width=True, hide_index=True, on_select="rerun", selection_mode="multi-row", )

    通过设置 on_selection="rerun",您已激活了数据框的选择功能。selection_mode="multi_row" 指定了允许的选择类型(多行,无列)。event 存储了用户的选择数据。选择数据可以通过 event.selection 属性访问。

  1. 插入一个标题来标识你将显示的数据子集。

    st.header("Selected members")
  2. 获取所选行的列表并过滤您的数据框。

    people = event.selection.rows filtered_df = df.iloc[people]

    行选择通过位置索引返回。您应该使用 pandas 方法 .iloc[].iat[] 来检索行。

  3. 在新的数据框中显示选定的行。

    st.dataframe( filtered_df, column_config=column_configuration, use_container_width=True, )

    为了保持一致性,重用现有的列配置。

  4. 可选:保存您的文件并进行测试。尝试在您的应用程序中选择一些行,然后返回到您的代码。

  1. 创建一个空字典来存储(年度)活动数据。

    activity_df = {}
  2. 遍历选定的行,并将每个成员的活动保存在以他们名字为索引的字典中。

    for person in people: activity_df[df.iloc[person]["name"]] = df.iloc[person]["activity"]
  3. 将活动字典转换为pandas.DataFrame

    activity_df = pd.DataFrame(activity_df)
  4. 同样地,重复前三个步骤以处理日常活动。

    daily_activity_df = {} for person in people: daily_activity_df[df.iloc[person]["name"]] = df.iloc[person]["daily_activity"] daily_activity_df = pd.DataFrame(daily_activity_df)
  5. 可选:通过显示来测试你的组合数据。

    st.dataframe(activity_df) st.dataframe(daily_activity_df)

    保存你的app.py文件以查看预览。在继续之前删除这两行。

  1. 启动一个条件块来检查当前是否有人被选中。

    if len(people) > 0:

    由于应用加载时没有成员被选中,此检查将防止显示空图表。

  2. 添加一个标题来标识您的第一个图表。

    st.header("Daily activity comparison")
  3. 在条形图中显示每日活动比较。

    st.bar_chart(daily_activity_df)
  4. 同样地,对于年度活动,添加一个标题和折线图。

    st.header("Yearly activity comparison") st.line_chart(activity_df)
  5. 完成条件块,当没有成员被选中时显示默认消息。

    else: st.markdown("No members selected.")

此时,您应该已经有一个可以正常运行的应用程序。现在,您可以美化它。在本节中,您将使用st.tabs将选择UI与比较部分分开。

  1. 在列配置定义之后,立即插入两个标签。

    select, compare = st.tabs(["Select members", "Compare selected"])
  2. 将上一步骤中的代码缩进,并将其分组到两个新标签中。

    with select: # 添加选择标签 ############################################# st.header("所有成员") df = get_profile_dataset() event = st.dataframe( df, column_config=column_configuration, use_container_width=True, hide_index=True, on_select="rerun", selection_mode="multi-row", ) st.header("选定的成员") people = event.selection.rows filtered_df = df.iloc[people] st.dataframe( filtered_df, column_config=column_configuration, use_container_width=True, ) with compare: # 添加比较标签 ########################################### activity_df = {} for person in people: activity_df[df.iloc[person]["name"]] = df.iloc[person]["activity"] activity_df = pd.DataFrame(activity_df) daily_activity_df = {} for person in people: daily_activity_df[df.iloc[person]["name"]] = df.iloc[person]["daily_activity"] daily_activity_df = pd.DataFrame(daily_activity_df) if len(people) > 0: st.header("每日活动比较") st.bar_chart(daily_activity_df) st.header("年度活动比较") st.line_chart(activity_df) else: st.markdown("未选择任何成员。")
  3. 保存您的文件并尝试您完成的示例。

forum

还有问题吗?

我们的 论坛 充满了有用的信息和Streamlit专家。