【Streamlit】ページネーションを実装してみる

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

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

今回はStreamlitを使って、ページネーションを実装する方法をご紹介します。

完成イメージ

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

初回アクセス時

次へボタンを押下時

前へボタンを押下時

プログラム

pagenation.py

import streamlit as st
 
ss = st.session_state
 
   
#### セッション管理 ####
 
 
def init_session_state():
    """セッションステートの初期化"""
 
    if "data" not in ss:
        ss["data"] = get_data()
  
   if "page_index" not in ss:
        ss["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) >= 5:
            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 data_per_page in ss["data"][ss["page_index"]]:
        for col_index, col_ph in enumerate(st.columns(6)):
            col_ph.image(data_per_page[col_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,
    )
 
 
#### メイン処理 ####
 
 
def main():
    """メイン処理"""
    init_session_state()
    display_images()
    pagination()
 
 
main()
 

実行方法

wget https://d1.awsstatic.com/Developer%20Marketing/jp/magazine/sample/2024/images.2dd13d52369e3b347b9450315d69d7e819e55834.zip \
-O images.zip
unzip images.zip
streamlit run main.py

解説

セッション管理

描画する猫の画像とページ数をStreamlitのセッションで管理します。 詳細はアプリケーションロジックの部分で解説しますが、描画する猫の画像のパスはページネーションしやすいように3次元配列で管理します。

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

アプリケーションロジック

アプリケーションロジックには、以下の2つの関数があります。

  • 3次元配列で猫の画像パスを格納する関数
  • ページのインデックスを更新する関数

3次元配列で猫の画像パスを格納

3次元配列で猫の画像パスを格納します。

  • 1次元: ページ数
  • 2次元: 行数
  • 3次元: 列数
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) >= 5:
            pages.append(rows)
            rows = []
 
    return pages

pages変数には以下のように画像パスが格納されます。

[
    [
        [画像パス1,画像パス,画像パス,画像パス,画像パス,画像パス],
        [画像パス,画像パス,画像パス,画像パス,画像パス,画像パス],
        :
        [画像パス,画像パス,画像パス,画像パス,画像パス,画像30]
    ],
    [
        [画像パス31,画像パス,画像パス,画像パス,画像パス,画像パス],
        [画像パス,画像パス,画像パス,画像パス,画像パス,画像パス],
        :
        [画像パス,画像パス,画像パス,画像パス,画像パス,画像60]
    ],
    :
]

ページのインデックスを更新する関数

セッション管理に記載した通り、現在のページ数をセッションで管理します。

  • 前へボタンを押した場合
    ページ数が1以上である場合のみ、ページ数を-1します。

  • 次へボタンを押す場合
    現在のページに+1しても、ページ数の最大未満の場合にのみ、ページ数を+1します。 ※以下ではなく未満である理由は、リストのインデックスが0始まりのためです。

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

画面描画

画面描画には、以下の2つの関数があります。

  • 画像を描画する関数
  • ページネーションボタンを描画する関数

画像を描画する関数

セッションに格納されている猫の画像パスと現在のページ数を基に描画する猫の画像を描画します。 また、st.columsを使い、横並びで画像を描画します。

def display_images():
    """10行,6列で画像の表示"""
    for data_per_page in ss["data"][ss["page_index"]]:
        for col_index, col_ph in enumerate(st.columns(6)):
            col_ph.image(data_per_page[col_index])

ページネーションボタンを描画する関数

st.columnsを使い、1行に1対8対1の間隔でボタンやページ数を描画します。 ボタンを押下すると、アプリケーションロジックで説明したページのインデックスを更新する関数が呼ばれます。

また、真ん中に表示するページ数は、中央揃えにしたいため、HTMLを書いています。

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,
    )

終わりに

今回は、Streamlitを使ってページネーションを実装してみました。 どなたかのお役に立てれば幸いです。

福島 和弥 (記事一覧)

2019/10 入社

AWS CLIが好きです。