有没有办法在 python 的 streamlit 包的多选小部件中添加“全选”选项?

Posted

技术标签:

【中文标题】有没有办法在 python 的 streamlit 包的多选小部件中添加“全选”选项?【英文标题】:Is there a way to add the "select all" option in the multiselect widget of python's streamlit package? 【发布时间】:2020-11-13 12:17:47 【问题描述】:

我正在开发一个 streamlit 应用程序,其中包含一个带有 10 个选项的多选小部件。是否有替代方法可以添加一个选择所有选项的按钮以避免一一选择?

我尝试向多选添加上一个按钮,但使用另一个小部件会重置选择。这是一个示例代码:

import streamlit as st

if st.sidebar.button('Add all years'):
    year_filter = st.sidebar.multiselect('Select a year',[2000,2001,2002,2003,2004], default=[2000,2001,2002,2003,2004])
else:
    year_filter = st.sidebar.multiselect('Select a year',[2000,2001,2002,2003,2004], default=[2000])

type_filter = st.sidebar.multiselect('Choose a type',['Control','Experimental'], default=['Experimental'])

st.write(year_filter, type_filter)

【问题讨论】:

【参考方案1】:

有一种方法可以使用state

import streamlit as st
from streamlit.ReportThread import get_report_ctx
from streamlit.hashing import _CodeHasher
from streamlit.server.Server import Server


class _SessionState:
    def __init__(self, session, hash_funcs):
        """Initialize SessionState instance."""
        self.__dict__["_state"] = 
            "data": ,
            "hash": None,
            "hasher": _CodeHasher(hash_funcs),
            "is_rerun": False,
            "session": session,
        

    def __call__(self, **kwargs):
        """Initialize state data once."""
        for item, value in kwargs.items():
            if item not in self._state["data"]:
                self._state["data"][item] = value

    def __getitem__(self, item):
        """Return a saved state value, None if item is undefined."""
        return self._state["data"].get(item, None)
        
    def __getattr__(self, item):
        """Return a saved state value, None if item is undefined."""
        return self._state["data"].get(item, None)

    def __setitem__(self, item, value):
        """Set state value."""
        self._state["data"][item] = value

    def __setattr__(self, item, value):
        """Set state value."""
        self._state["data"][item] = value
    
    def clear(self):
        """Clear session state and request a rerun."""
        self._state["data"].clear()
        self._state["session"].request_rerun()
    
    def sync(self):
        """Rerun the app with all state values up to date from the beginning to fix rollbacks."""

        # Ensure to rerun only once to avoid infinite loops
        # caused by a constantly changing state value at each run.
        #
        # Example: state.value += 1
        if self._state["is_rerun"]:
            self._state["is_rerun"] = False
        
        elif self._state["hash"] is not None:
            if self._state["hash"] != self._state["hasher"].to_bytes(self._state["data"], None):
                self._state["is_rerun"] = True
                self._state["session"].request_rerun()

        self._state["hash"] = self._state["hasher"].to_bytes(self._state["data"], None)


def _get_session():
    session_id = get_report_ctx().session_id
    session_info = Server.get_current()._get_session_info(session_id)

    if session_info is None:
        raise RuntimeError("Couldn't get your Streamlit Session object.")
    
    return session_info.session


def _get_state(hash_funcs=None):
    session = _get_session()

    if not hasattr(session, "_custom_session_state"):
        session._custom_session_state = _SessionState(session, hash_funcs)

    return session._custom_session_state


def main():
    state = _get_state()

    if state.previous_years_selected is None:
        state.previous_years_selected = [2000]
    
    if st.sidebar.button('Add all years'):
        year_filter = st.sidebar.multiselect('Select a year', [2000,2001,2002,2003,2004], default=[2000,2001,2002,2003,2004])
    else:
        year_filter = st.sidebar.multiselect('Select a year', [2000,2001,2002,2003,2004], default=state.previous_years_selected)

    # The next default (in case no one clicks on "Add all years")
    # will be the current years selected
    state.previous_years_selected = year_filter

    state.sync()


if __name__ == "__main__":
    main()

_StateSession 对象在 Streamlit 的重新加载过程中保留数据,这意味着如果您与小部件交互,页面会重新加载,但 state 保留信息。 在这里,我们保留上次与“年份选择器”交互期间选择的年份信息,并将其作为下次重新加载的默认值 (default=state.previous_years_selected)。

您可以将任何您想要的数据添加到state 对象。在修改它之前确保它确实存在:

if state.previous_years_selected is None:
    state.previous_years_selected = [2000]

【讨论】:

非常有帮助,谢谢!我只需要调整导入以使其在 streamlit 0.72 下工作:from streamlit.server.server import Serverfrom streamlit.report_thread import get_report_ctx

以上是关于有没有办法在 python 的 streamlit 包的多选小部件中添加“全选”选项?的主要内容,如果未能解决你的问题,请参考以下文章

Streamlit:修改多选标签背景颜色

如何让 Plotly 根据 Streamlit 应用程序中的屏幕分辨率调整绘图大小?

如何使用python在streamlit和plotly中创建列?

streamlit pyplot 子图失真

streamlit—让交互网页的搭建无比简单

Plotly,streamlit:如何保持全屏视图