1.最初に
データ分析結果をすばやくwebappとして可視化できるstreamlit。
色々公式サイトにサンプルがあるので楽しい。最近見たのはhuggingfaceが公開済のDatasetを見るのに使っていたもの。
streamlitをとても便利に使わせてもらっているが、下のページのようにラジオボタンなどで別のページ(タブ)に移動すると、変数やdataframeがすべて消えてしまう。
「入力データ」ページでデータをアップロードして「データ加工」ページへ行くとアップロードしてdataframeに入れたデータが参照できない。
データアップロードページ→データ加工ページ→データ可視化ページなど。
複数ページにまたがってデータを処理したい場合に困った。
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