本記事はStreamlit入門の5回目です。レイアウトについて説明します。Streamlitは簡単に使えるように設計されているため、見た目を細かく設定できるようにはなっていません。ざっくりとしたレイアウトを素早く構築する、そんなスタンスで進めてみてください。
本記事はFuture Coders独自教材からの抜粋です。
Streamlit入門 – 5)レイアウト 目次
https://docs.streamlit.io/library/api-reference/layout
ここまでウィジェットなどを使って、単一ページ(レイアウト無指定)のアプリを作成してきました。
Streamlit入門 – 3)Widget – Future Coders (future-coders.net)
以下のような要素が用意されています。
- sidebar = サイドバー
- columns = カラム(複数列)
- tabs = タブで表示する内容を切替
- expander = 複数の要素を含む入れ物で開いたり、畳んだりする入れ物
- container = 複数の要素を含む入れ物
- empty = 単一の要素を含む入れ物
サイドバー
画面を分割してサイドバーを作成することができます。サイドバーに要素を配置するには、今までstモジュールに対して行っていた操作をst.sidebarに行うだけです。
import streamlit as st
st.title("main title")
st.sidebar.title("sidebar title")
with構文を使って、以下のようにサイドバーに要素を追加してゆくこともできます。
import streamlit as st
st.title("main title")
with st.sidebar:
st.title("sidebar title")
st.button("hello")
st.text("hello world")
st.divider()
st.radio("fruits",["apple","orange","melon"])
カラム
カラムは列のことです。画面を縦方向に何列かに分割してレイアウトしてゆくことができます。以下は3列に分割した例です。
st.columnsの引数で列数を指定します。st.columnsの戻り値がそれぞれの列のオブジェクトです。with構文を使って、それらのオブジェクトにheaderとimageを書き込んでいます。
import streamlit as st
col1, col2, col3 = st.columns(3)
with col1:
st.header("A cat")
st.image("https://static.streamlit.io/examples/cat.jpg")
with col2:
st.header("A dog")
st.image("https://static.streamlit.io/examples/dog.jpg")
with col3:
st.header("An owl")
st.image("https://static.streamlit.io/examples/owl.jpg")
カラムの幅を変えたいときには、st.columnsの引数に幅の比率を示すリストを指定します。戻り値で得られたのがそれぞれの列のオブジェクトとなります。そこに書き込んでゆきます。
import streamlit as st
import numpy as np
col1, col2 = st.columns([3, 1])
data = np.random.randn(6, 1)
col1.subheader("A wide column with a chart")
col1.line_chart(data)
col2.subheader("A narrow column with the data")
col2.write(data)
タブ
見出しでコンテンツを切り替える部品です。
import streamlit as st
tab1, tab2, tab3 = st.tabs(["Cat", "Dog", "Owl"])
with tab1:
st.header("A cat")
st.image("https://static.streamlit.io/examples/cat.jpg", width=200)
with tab2:
st.header("A dog")
st.image("https://static.streamlit.io/examples/dog.jpg", width=200)
with tab3:
st.header("An owl")
st.image("https://static.streamlit.io/examples/owl.jpg", width=200)
エキスパンダー
クリックすることで閉じたり開いたりする部品です。
import streamlit as st
st.bar_chart({"data": [1, 5, 2, 6, 2, 1]})
with st.expander("See explanation"):
st.write("""
The chart above shows some numbers I picked for you.
I rolled actual dice for these, so they're *guaranteed* to
be random.
""")
st.image("https://static.streamlit.io/examples/dice.jpg")
コンテナー
タブやエキスパンダーを使うときには複数の要素を1つの入れ物にまとめたいときがあるかもしれません。そのようなときはcontainerを使用します。
import streamlit as st
import numpy as np
with st.container():
st.write("This is inside the container")
st.bar_chart(np.random.randn(50, 3))
st.button("update")
st.divider()
st.write("This is outside the container")
ページ設定
デフォールトのページ設定が可能です。
以下のような引数が用意されています。
- page_title = ページのタイトル
- page_icon = favicon、絵文字も利用可能
- layout = “centered”か”wide”
- menu_items = 画面右上のハンバーガーメニューの項目と内容(リンクやマークダウン)
import streamlit as st
st.set_page_config(
page_title="Ex-stream-ly Cool App",
page_icon="🧊",
layout="wide",
initial_sidebar_state="expanded",
menu_items={
'Get Help': 'https://www.extremelycoolapp.com/help',
'Report a bug': "https://www.extremelycoolapp.com/bug",
'About': "# This is a header. This is an *extremely* cool app!"
}
)
演習
ex-layout1.py
サイドバーに3つの項目を配置し、選択状態が変わると右側の写真が切り替わるページを作成してください。
ex-layout2.py
ボタンを横にならべて、当たりのボタンを押したら風船を描画してください。横一列に並べるのにst.columnsを使用します。当たりはボタンを押下する度に変化してもよいものとします。
ex-layout3.py
ボタンを押してはずれたら、その旨を下に表示してください。押したかどうか状態を覚えておくためにst.session_stateを使用します。ページの再読み込みで再ゲームとします。
ex-layout4.py
タブを使って、iris, taxis, titanicと3つのデータフレームを切り替えて表示するページを作成してください。
ex-layout5.py
サイドバーに郵便番号を入力して、検索ボタンを押下するとその住所を表示するページを作成してください。
郵便番号の検索にはzipcloudのWebAPIを使用してください。
r = requests.get(f"https://zipcloud.ibsnet.co.jp/api/search?zipcode={zip}")
data = r.json()
解答例{.answer}
ex-layout1.py
import streamlit as st
pages = ["page1", "page2", "page3"]
page = st.sidebar.radio("image", pages)
if page == "page1":
st.header("A cat")
st.image("https://static.streamlit.io/examples/cat.jpg")
elif page == "page2":
st.header("A dog")
st.image("https://static.streamlit.io/examples/dog.jpg")
else:
st.header("An owl")
st.image("https://static.streamlit.io/examples/owl.jpg")
ex-layout2.py
import streamlit as st
from random import randint
atari = randint(0,4)
cols = st.columns(5)
for i in range(5):
with cols[i]:
if st.button(f"button:{i}"):
if i == atari:
st.write(f"当たり!!")
st.balloons()
else:
st.write(f"当たりは{atari}でした")
ex-layout3.py
import streamlit as st
from random import randint
if "atari" not in st.session_state:
st.session_state.atari = randint(0,4)
st.session_state.open = [False for _ in range(5)]
cols = st.columns(5)
for i in range(5):
with cols[i]:
if st.button(f"button:{i}"):
if i == st.session_state.atari:
st.write(f"当たり!!")
st.balloons()
else:
st.session_state.open[i] = True
cols = st.columns(5)
for i in range(5):
with cols[i]:
if st.session_state.open[i]:
st.write("はずれ")
ex-layout4.py
import streamlit as st
import seaborn as sns
iris, taxis, titanic = st.tabs(["iris", "taxis", "titanic"])
with iris:
df = sns.load_dataset("iris")
st.dataframe(df)
with taxis:
df = sns.load_dataset("taxis")
st.dataframe(df)
with titanic:
df = sns.load_dataset("titanic")
st.dataframe(df)
ex-layout5.py
import streamlit as st
import requests
zip = st.sidebar.text_input("郵便番号")
if st.sidebar.button("検索"):
r = requests.get(f"https://zipcloud.ibsnet.co.jp/api/search?zipcode={zip}")
data = r.json()
addr = data["results"][0]["address1"] \
+ data["results"][0]["address2"] \
+ data["results"][0]["address3"]
st.write(addr)