
Webアプリ作成 -Streamlit③-
今回はレイアウトについてです。
sidebar
オブジェクト表記法
Streamlitでは、簡単にサイドバーを作成し、ページのメイン部分と分けることができます。条件設定をサイドバーで行い、その結果をメインに表示するというような使い方ができます。
書き方は簡単で、
st.sidebar.[element_name] と書くだけです。
[element_name]には配置したいウィジェット名(buttonやselectbox等)が入ります。
前回の投稿時に書いたコードを少し修正し、サイドバーにselectboxを配置してみます。
import streamlit as st
import datetime
from zoneinfo import ZoneInfo
zone = st.sidebar.selectbox('地域を選択', ['東京', 'ロサンゼルス', 'ニューヨーク', 'ロンドン', 'パリ'])
dict_timezone = {
'東京': 'Asia/Tokyo',
'ロサンゼルス': 'America/Los_Angeles',
'ニューヨーク': 'America/New_York',
'ロンドン': 'Europe/London',
'パリ': 'Europe/Paris'
}
timezone = dict_timezone[zone]
btn = st.button('Now!')
if btn:
today = datetime.datetime.now(ZoneInfo(timezone))
today = today.strftime('%m月%d日 %H時%M分')
st.write(f'現在の{zone}は、{today}です')

selectboxの前に"sidebar"を挿入するだけで、地域を選択するセレクトボックスがサイドバーに表示されるようになりました。
withを使った表記法
サイドバーの中にウィジェットをたくさん配置する場合は、withを使用した方がスッキリ表記できます。withを使用して、セレクトボックスとボタンの2つのウィジェットをサイドバーに表示してみます。
import streamlit as st
import datetime
from zoneinfo import ZoneInfo
with st.sidebar:
zone = st.selectbox('地域を選択', ['東京', 'ロサンゼルス', 'ニューヨーク', 'ロンドン', 'パリ'])
dict_timezone = {
'東京': 'Asia/Tokyo',
'ロサンゼルス': 'America/Los_Angeles',
'ニューヨーク': 'America/New_York',
'ロンドン': 'Europe/London',
'パリ': 'Europe/Paris'
}
timezone = dict_timezone[zone]
btn = st.button('Now!')
if btn:
today = datetime.datetime.now(ZoneInfo(timezone))
today = today.strftime('%m月%d日 %H時%M分')
st.write(f'現在の{zone}は、{today}です')
with st.sidebar: の後にサイドバーに配置したいウィジェットをインデントを1つ下げて書くだけです。今回はst.selectbox()からst.button()までがwithの中に入っています。

columns
Webアプリ上では、基本的にはコードで記載した順番に上から下の方向に表示されますが、横に配置したいときもあります。そんな時に使えるのがcolumnsです。
columnsでは、その名の通り"列"を作成し、それぞれの列にコンテンツを配置できます。
st.columns(spec, *, gap="small", vertical_alignment="top")
spec: 挿入する列の数と幅を設定
gap: 列と列の間のサイズ("small", "medium", "large"から選択。デフォルトは"small")
vertical_alignment: 列内のコンテンツの垂直方向の位置("top", "center", "bottom"から選択。デフォルトは"top")
st.columns(3)とすれば、3つの均等な列を作ることができ、サイドバーと同じようにwithを使ってコンテンツを各列に挿入することができます。
import streamlit as st
col1, col2, col3 = st.columns(3)
with col1:
st.write('左の列')
st.write('左の列')
st.write('左の列')
with col2:
st.write('真ん中の列')
st.write('真ん中の列')
with col3:
st.write('右の列')

垂直方向の位置調整
垂直方向の位置はデフォルトの"top"になっているので、上端が揃っています。vertical_alignmentの設定を変えれば、縦の位置も変更できます。
col1, col2, col3 = st.columns(3, vertical_alignment='center')

縦位置を中央揃えにすることができました。
列幅の調整
列を不均等に分割することも出来ます。
st.columns([0.7, 0.3])とすれば7:3の割合に、
st.columns([1, 2, 3])とすれば1:2:3の割合に分割されます。
import streamlit as st
col1, col2, col3 = st.columns(3) # 均等な3分割
with col1:
st.write('あああああ')
with col2:
st.write('あああああ')
with col3:
st.write('あああああ')
colA, colB, colC = st.columns([1, 2, 3]) # 1:2:3に分割
with colA:
st.write('あああああ')
with colB:
st.write('あああああ')
with colC:
st.write('あああああ')

streamlitでは、文字列の先頭のスペースは無視され詰められてしまいます。
import streamlit as st
st.write('あああああ')
st.write(' あああああ')

ウィジェットも左端が揃ってしまうので見栄えが悪い時があります。columnsを使用すれば、横位置の調整をすることも出来ます。
import streamlit as st
import datetime
from zoneinfo import ZoneInfo
zone = st.selectbox('地域を選択', ['東京', 'ロサンゼルス', 'ニューヨーク', 'ロンドン', 'パリ'])
dict_timezone = {
'東京': 'Asia/Tokyo',
'ロサンゼルス': 'America/Los_Angeles',
'ニューヨーク': 'America/New_York',
'ロンドン': 'Europe/London',
'パリ': 'Europe/Paris'
}
timezone = dict_timezone[zone]
col1, col2 = st.columns([6, 1])
with col2:
btn = st.button('Now!')
if btn:
today = datetime.datetime.now(ZoneInfo(timezone))
today = today.strftime('%m月%d日 %H時%M分')
st.write(f'現在の{zone}は、{today}です')
