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
)。
Applied concepts
- 使用数据框行选择来过滤数据框。
Prerequisites
-
您的Python环境中必须安装以下内容:
streamlit>=1.35.0
-
你应该有一个干净的工作目录,名为
your-repository
。 -
你应该对缓存和
st.dataframe
有一个基本的理解。
Summary
在这个例子中,你将构建一个应用程序,显示一个虚构组织的成员及其活动的表格。在表格中,用户可以选择一行或多行来创建过滤视图。你的应用程序将显示一个组合图表,比较所选员工。
以下是您将构建的内容:
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.")
Build the example
Initialize your app
-
在
your_repository
中,创建一个名为app.py
的文件。 -
在终端中,将目录更改为
your_repository
并启动您的应用程序。streamlit run app.py
由于您仍然需要添加代码,您的应用程序将是空白的。
-
在
app.py
中,编写以下内容:import numpy as np import pandas as pd import streamlit as st from faker import Faker
你将按以下方式使用这些库:
- 你将使用
faker
生成随机成员名称。 - 你将使用
numpy
生成随机活动数据。 - 你将使用
pandas
处理数据。
- 你将使用
-
保存您的
app.py
文件并查看正在运行的应用程序。 -
点击“始终重新运行”或在运行的应用中按下“A”键。
当您保存对
app.py
的更改时,您的运行预览将自动更新。您的预览仍然会是空白的。返回您的代码。
Build a function to create random member data
首先,您将定义一个函数来随机生成一些成员数据。如果您只想复制函数,可以跳过此部分。
@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
-
使用
@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
。 -
初始化一个空列表来存储数据。
new_data = []
-
初始化随机生成器。
fake = Faker() 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), } )
对于
daily_activity
,您正在生成长度为25的数组。这些值是区间[0,1)
中的浮点数。对于activity
,您正在生成长度为12的数组。这些值是区间[2,90)
中的整数。 -
将你的字典列表转换为一个单一的
pandas.DataFrame
并返回它。profile_df = pd.DataFrame(new_data) return profile_df
-
可选:通过调用并显示数据来测试您的函数。
st.dataframe(get_profile_dataset())
保存您的
app.py
文件以查看预览。在继续之前删除此行。
Display your data with multi-row selections enabled
-
定义您的列配置以格式化您的数据。
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, ), }
对于您的数据框的每一列,这定义了格式良好的列名、工具提示和列宽。您将使用折线图显示年度活动,并使用条形图显示每日活动。
-
插入一个标题来标识您将要显示的数据。
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", )
通过设置
on_selection="rerun"
,您已激活了数据框的选择功能。selection_mode="multi_row"
指定了允许的选择类型(多行,无列)。event
存储了用户的选择数据。选择数据可以通过event.selection
属性访问。
Display the selected data
-
插入一个标题来标识你将显示的数据子集。
st.header("Selected members")
-
获取所选行的列表并过滤您的数据框。
people = event.selection.rows filtered_df = df.iloc[people]
行选择通过位置索引返回。您应该使用 pandas 方法
.iloc[]
或.iat[]
来检索行。 -
在新的数据框中显示选定的行。
st.dataframe( filtered_df, column_config=column_configuration, use_container_width=True, )
为了保持一致性,重用现有的列配置。
-
可选:保存您的文件并进行测试。尝试在您的应用程序中选择一些行,然后返回到您的代码。
Combine activity data for the selected rows
-
创建一个空字典来存储(年度)活动数据。
activity_df = {}
-
遍历选定的行,并将每个成员的活动保存在以他们名字为索引的字典中。
for person in people: activity_df[df.iloc[person]["name"]] = df.iloc[person]["activity"]
-
将活动字典转换为
pandas.DataFrame
。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)
-
可选:通过显示来测试你的组合数据。
st.dataframe(activity_df) st.dataframe(daily_activity_df)
保存你的
app.py
文件以查看预览。在继续之前删除这两行。
Use charts to visualize the activity comparison
-
启动一个条件块来检查当前是否有人被选中。
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.")
Make it pretty
此时,您应该已经有一个可以正常运行的应用程序。现在,您可以美化它。在本节中,您将使用st.tabs
将选择UI与比较部分分开。
-
在列配置定义之后,立即插入两个标签。
select, compare = st.tabs(["Select members", "Compare selected"])
-
将上一步骤中的代码缩进,并将其分组到两个新标签中。
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("未选择任何成员。")
-
保存您的文件并尝试您完成的示例。
还有问题吗?
我们的 论坛 充满了有用的信息和Streamlit专家。