15
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

streamlitで別ページ(タブ)にデータを持ち越す

Last updated at Posted at 2020-10-10

1.最初に

データ分析結果をすばやくwebappとして可視化できるstreamlit
色々公式サイトにサンプルがあるので楽しい。最近見たのはhuggingfaceが公開済のDatasetを見るのに使っていたもの。

streamlitをとても便利に使わせてもらっているが、下のページのようにラジオボタンなどで別のページ(タブ)に移動すると、変数やdataframeがすべて消えてしまう。
「入力データ」ページでデータをアップロードして「データ加工」ページへ行くとアップロードしてdataframeに入れたデータが参照できない。

image.png

データアップロードページ→データ加工ページ→データ可視化ページなど。
複数ページにまたがってデータを処理したい場合に困った。
1つのページ内で完結させようとすると、今のstreamlitの仕様上すごく縦に長くなってしまう。

2.まとめ

色々ネット上をさまよって、最後にsessionを使って中継するという方法が良かったので書いておく。
肝の部分↓

sessionの部分
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


3.具体的例

上記のをコードに入れておけば、

def main():
    state = _get_state()
    pages = {
        "入力データ":in_page,
        "データ加工":tran_page,
        "データ可視化":out_page
    }

    #st.sidebar.title(":floppy_disk: Page states")
    page = st.sidebar.radio("ページ選択", tuple(pages.keys()))

    # Display the selected page with the session state
    pages[page](state)

    # Mandatory to avoid rollbacks with widgets, must be called at the end of your app
    state.sync()

でメインページを作っておいて、
受け渡したいページと受け入れたいページとをstate.~~でつなげばいい。
当然ながらdataframeも受け渡しできた。

def in_page(state):
    ~~~
    
    #受け渡したい変数をstate.~~で入れて、
    state.dataframe1 = dataframe1
    state.var1 = var1

def tran_page(state):
    """
   #受け入れたい変数を ~~=state.~~ で受付る。
    dataframe1 = state.dataframe1
    var1 = state.var1
    ~~~
    またはそのままstate.dataframe1
    state.var1
  で使う。
    """

def out_page(state):
    ~~~

#最後にmain()を入れて実行する。
main()

20201203追加。
st.experimental_set_query_params
st.experimental_get_query_params
で同等の事ができそう!
↓参照
https://link.medium.com/sz1bpLvyUbb

4.参照

15
13
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?