【Streamlit】モーダル内にページネーションを実装してみる

記事タイトルとURLをコピーする

こんにちは。AWS CLIが好きな福島です。

前回、Streamlitでページネーションを実装する例をご紹介いたしましたが、 今回はモーダル内でページネーションを実装する例を紹介いたします。

完成イメージ

完成イメージは以下の通りで猫の画像を1ページ、3行、6列で画像を表示させています。 また画像はAWSのサンプルアプリで使われている猫の画像を使わせてもらいました。

初回アクセス

拡大ボタン押下時

>ボタン押下時

<ボタン押下時

プログラム

import streamlit as st
 
ss = st.session_state 
 
#### セッション管理 ####
 
 
def init_session_state():
    """セッションステートの初期化"""
 
    if "page_index" not in ss:
        ss["page_index"] = 0
 
    if "data" not in ss:
        ss["data"] = get_data()
 
    if "modal_page_index" not in ss:
        ss["modal_page_index"] = 0
 
 
#### アプリケーションロジック ####
 
 
def get_data():
    """3次元配列で画像を格納"""
    pages = []
    rows = []
    cols = []
 
    for i in range(228):
        cols.append(f"./images/image_{i:03}.jpg")
        if len(cols) >= 6:
            rows.append(cols)
            cols = []
        if len(rows) >= 3:
            pages.append(rows)
            rows = []
 
    return pages
 
 
def update_index(session_key, num, max_val=None):
    """ページネーションのインデックスを更新"""
    if max_val:
        if ss[session_key] < max_val - num:
            ss[session_key] += num
    else:
        if ss[session_key] >= num:
            ss[session_key] -= num
 
 
#### 画面描画 ####
 
 
def display_images():
    """10行,6列で画像の表示"""
    for row_index, data_per_page in enumerate(ss["data"][ss["page_index"]]):
        for col_index, col_ph in enumerate(st.columns(6)):
            col_ph.image(data_per_page[col_index])
            if col_ph.button("拡大", key=f"{row_index}-{col_index}", use_container_width=True):
                ss["modal_page_index"] = col_index
                display_image_modal(row_index)
 
 
def pagination():
    """ページネーションボタンの表示"""
    col1, col2, col3 = st.columns([1, 8, 1])
 
    col1.button("前へ" * 1, on_click=update_index, args=("page_index", 1))
    col3.button("次へ" * 1, on_click=update_index, args=("page_index", 1, len(ss["data"])))
 
    col2.markdown(
        f"""
        <div style='text-align: center;'>
            {ss["page_index"] + 1} / {len(ss["data"])}
        </div>
        """,
        unsafe_allow_html=True,
    )
 
 
@st.dialog("拡大", width="small")
def display_image_modal(row_index):
 
    image_ph = st.empty()
 
    col1, col2, col3 = st.columns([1, 8, 1])
 
    col1.button("&lt;", on_click=update_index, args=("modal_page_index", 1))
    col3.button("&gt;", on_click=update_index, args=("modal_page_index", 1, 6))
 
    col2.html(
        f"""
        <div style='text-align: center;'>
        {ss["modal_page_index"] + 1} / {len(ss["data"][ss["page_index"]][row_index])}
        </div>
        """
    )
 
    image_ph.image(ss["data"][ss["page_index"]][row_index][ss["modal_page_index"]], width=450)
 
 
#### メイン処理 ####
 
 
def main():
    """メイン処理"""
    init_session_state()
    display_images()
    pagination()
 
 
main()

解説

基本的な部分は前回のプログラムがベースになっているため、追加した点だけ解説します。

セッション管理

モーダル内のページインデックスを管理するキー(modal_page_index)を追加しました。

#### セッション管理 ####
 
 
def init_session_state():
    """セッションステートの初期化"""
 
    if "page_index" not in ss:
        ss["page_index"] = 0
 
    if "data" not in ss:
        ss["data"] = get_data()
 
    if "modal_page_index" not in ss: # 追加
        ss["modal_page_index"] = 0 # 追加

画面描画

画像を表示する関数

画像の下に拡大ボタンを描画するコードを追加しました。 また、ボタンが押下された場合、モーダル内のページインデックスを更新し、モーダルを描画する関数を呼び出します。

def display_images():
    """10行,6列で画像の表示"""
    for row_index, data_per_page in enumerate(ss["data"][ss["page_index"]]):
        for col_index, col_ph in enumerate(st.columns(6)):
            col_ph.image(data_per_page[col_index])
            if col_ph.button("拡大", key=f"{row_index}-{col_index}", use_container_width=True): ## 追加
                ss["modal_page_index"] = col_index ## 追加
                display_image_modal(row_index) ## 追加

モーダルを描画する関数

この関数は新規に追加しました。st.dialogというデコレーターを使うことで簡単にモーダルを実装することができます。 また、モーダル内には、前へボタン、次へボタン、ページ数、画像を表示します。

@st.dialog("拡大", width="small")
def display_image_modal(row_index):
 
    st.image(ss["data"][ss["page_index"]][row_index][ss["modal_page_index"]], width=450)
 
    col1, col2, col3 = st.columns([1, 8, 1])
 
    col1.button("&lt;", on_click=update_index, args=("modal_page_index", 1))
    col3.button("&gt;", on_click=update_index, args=("modal_page_index", 1, 6))
 
    col2.html(
        f"""
        <div style='text-align: center;'>
        {ss["modal_page_index"] + 1} / {len(ss["data"][ss["page_index"]][row_index])}
        </div>
        """
    )

終わりに

今回はモーダル内にページネーションを実装する例をご紹介しました。 どなたかのお役に立てれば幸いです。

福島 和弥 (記事一覧)

2019/10 入社

AWS CLIが好きです。