前回の記事で、VS CodeでPythonを使用する準備ができました。
ここからはVS Codeにコードを入力していきます。
ウェブアプリの完成形はこちらになります。
streamlitをインストールする
今回ウェブアプリに使用する「streamlit」はPythonに最初からインストールされているパッケージではありません。そのため、新たにインストールする必要があります。
新たにパッケージをインストールするにはpip
を使います。ターミナルにcmdが起動していることを確認し、ターミナルにpip install streamlit
と入力しEnter
キーで決定してください。するとstreamlitのインストールが始まります。
また、今回のグラフを描くのに使う「plotly」も新たにインストールする必要があります。同様にターミナルにpip install plotly
と入力しEnter
キーで決定してください。
ウェブアプリを作る際、通常ウェブフレームワークを使います。フレームワークは「枠組み」のことです。家を建てる際にも、まず枠組みを作った後に、個別の床や壁、窓などの部品を作った方がと効率的に作業が行えます。ウェブアプリも同じで、ウェブフレームワークの「枠組み」を使うことで効率的にアプリを作ることができます。
Pythonでよく使われるフレームワークには「Django」、「Flask」、「streamlit」などがあります。streamlitはこれらの中でも、コードが直感的で学習コストが低いため、初学者にも取り組みやすいフレームワークです。ただし、簡単に作れる一方、複雑なウェブアプリには向きません。
streamlitを使ってみる
streamlitとplotlyのインストールが終わったら、app.py
ファイルのprint('Hello World!')
は削除し、新たに以下のコードを入力します。
import streamlit as st
import pandas as pd
import plotly.express as px
st.title('食品安全文化の計測アプリ')
実際の画面は下のようになります。最初の3行で、必要なライブラリを呼び出しています。
Ctrl
+S
でファイルを保存します。
そしてターミナルに、streamlit run app.py
と入力しEnter
キーで決定します。
すると以下のように表示され、ウェブブラウザに新しいタブが作られます。
以下のような画面が開いていれば、成功です。誤ってブラウザの画面を消してしまったとしても、ターミナルのhttp://localhost:8501
のリンクをキーボードのCtrl
を押しながらクリックすれば、再びページを開くことができます。
なんとこれだけのコードで、ブラウザ上にウェブアプリが起動します。
5行目に書いたst.title('食品安全文化の計測アプリ')
の内容が表示されています。st
は「streamlit」の略で、title
は「タイトル」のことです。
つまり先程のコードは、タイトルのようなフォントで「食品安全文化の計測アプリ」と表示してくださいという命令です。
streamlitのコードは、このように直感的でわかりやすいです。
下に今回使用するstreamlitの部品(ウィジットとも言います。)を紹介します。
ウィジット | 意味 |
---|---|
st.title( ) | タイトルのフォントで表示 |
st.write( ) | 通常フォントで文字を表示 文字の修飾もできる。例:アスタリスクで文字を囲めば(**文字**)、文字が太字に表示される。 |
st.radio( ) | ラジオボタンを表示 複数の中から選択してもらう時に使用する。 |
st.button( ) | ボタンを表示 起動装置のように、ボタンを押すと別のアクションが起きるようにできる。 |
この他にもいろいろなウィジットがあります。英語ですが、公式HPのAPI Referenceで解説されています。また、インターネットで「streamlit ウィジット」と検索すると、日本語の記事も多く出てきます。
ウィジットの使い方に迷ったら、他の記事も参考にしてみてください。
ラジオボタンを表示する
それではコードを追記していきます。
import streamlit as st
import pandas as pd
import numpy as np
answer = ["そう思わない",
"あまりそう思わない",
"どちらとも言えない",
"ややそう思う",
"そう思う"]
st.title('食品安全文化の計測アプリ')
q1 = st.radio("1.誰も見ていない時でも、従業員は食品安全のルールを守っている。",
[1,2,3,4,5],
captions = answer, index=2, horizontal=True)
5行目について。回答の選択肢(そう思わない/あまりそう思わない/どちらとも言えない/ややそう思う/そう思う)は今後何度も同じ内容を使うため、あらかじめ準備し、answer
に入れておきます。
13行目はst.radio
を使ってラジオボタンを作っています。実際の画面を見たほうが何をしているか理解しやすいので、見てみましょう。
app.pyを保存してから、ブラウザの再読み込みを行ってください。
すると先ほど追加した部分が、ブラウザでも追加されたのが分かります。
比較すると、コードのどの部分が、画面でどのように表示されているかがわかります。streamlitの強みとして、コードを変更した結果をすぐに確認できる点があります。
少しわかりにくいコードを解説します。
index=2
は選択されるボタンの初期配置です。index=2を削除すると一番左があらかじめ選択されます。2なのに3番目が選択されている理由は、ご存じのようにPythonは0から数えるからです。
horizontal=True
は回答を横並びにします。英語のhorizontalが「水平の、横並びの」という意味ですね。これを削除すると回答が縦に並びます。
q1 = st.radio( )
としています。これは、ラジオボタンで選択された結果をq1
に格納するということです。例えば「1 そう思わない」を選択すると、数値の1がq1
に格納されます。この数値は後で回答を集計する際に使用します。
このように、まず1つ質問を作り、うまくいくことを確認してから他の質問に拡大した方が、いきなりすべてを作るより作業が効率的に行えます。
他の質問項目も同じように作っていってみてください。
なお、streamlitを停止したい場合は、VS Codeのターミナル上で、キーボードのCtrl
+C
を押します。
またstreamlitを起動したい場合は、ターミナルにstreamlit run app.py
と入力しEnter
キーを押します。
完成形のコード
1つの質問で問題なく動くことが確認できました。
みなさんも、完成形を見ながら、どのようなコードを書けばいいか試してみてください。
ここでコードの完成形をお見せします。
import streamlit as st
import pandas as pd
import plotly.express as px
answer = ["そう思わない",
"あまりそう思わない",
"どちらとも言えない",
"ややそう思う",
"そう思う"]
#ここからアプリ開始
st.title('食品安全文化の計測アプリ')
st.write('この施設における食品安全対策について、意見を聞かせてください。')
st.write('この施設で経験したことのうち、もっとも当てはまる欄にチェックしてください。匿名のため、名前は記入しないでください。')
st.write('**この飲食店では...**')
#4つのエリアの質問を作る
# 従業員のコミットメント
q1 = st.radio("1.誰も見ていない時でも、従業員は食品安全のルールを守っている。",
[1,2,3,4,5],
captions = answer, index=2, horizontal=True)
q2 = st.radio("2.従業員同士が食品安全のルールを守るよう励まし合っている。",
[1,2,3,4,5],
captions = answer, index=2, horizontal=True)
q3 = st.radio("3.従業員はそれぞれの役割における食品安全に責任を持っている。",
[1,2,3,4,5],
captions = answer, index=2, horizontal=True)
q4 = st.radio("4.従業員はルールに従い手を洗っている。",
[1,2,3,4,5],
captions = answer, index=2, horizontal=True)
# 資源
q5 = st.radio("5.素手で食品に触れないように、手袋や器具が十分に用意されている。",
[1,2,3,4,5],
captions = answer, index=2, horizontal=True)
q6 = st.radio("6.近くに手洗いシンクがあり、手洗いを行いやすい。",
[1,2,3,4,5],
captions = answer, index=2, horizontal=True)
q7 = st.radio("7.手洗いシンクは、お湯が出て、石鹸、ペーパータオルなどがある。",
[1,2,3,4,5],
captions = answer, index=2, horizontal=True)
# 責任者のコミットメント
q8 = st.radio("8.忙しい時、責任者は食品安全のルールを守ることよりも、料理を出すことを優先する。",
[1,2,3,4,5],
captions = answer, index=2, horizontal=True)
q9 = st.radio("9.仕事が多すぎるため、従業員は手を抜かざるを得ない。",
[1,2,3,4,5],
captions = answer, index=2, horizontal=True)
q10 = st.radio("10.従業員が食品安全のルールを守っていない時、責任者は見て見ぬふりをする。",
[1,2,3,4,5],
captions = answer, index=2, horizontal=True)
# リーダーシップ
q11 = st.radio("11. 私が仕事をする上で十分な食品安全に関するトレーニングを提供してくれる。",
[1,2,3,4,5],
captions = answer, index=2, horizontal=True)
q12 = st.radio("12.責任者は従業員からフィードバックを得て、食品安全を改善している。",
[1,2,3,4,5],
captions = answer, index=2, horizontal=True)
q13 = st.radio("13.食品安全は、掲示物、ポスター、シフトミーティングなどで強調されている。",
[1,2,3,4,5],
captions = answer, index=2, horizontal=True)
q14 = st.radio("14.従業員が食品安全のルールを守ることが積極的に評価されている。",
[1,2,3,4,5],
captions = answer, index=2, horizontal=True)
q15 = st.radio("15.責任者は私の役割、責任を説明してくれる。",
[1,2,3,4,5],
captions = answer, index=2, horizontal=True)
q16 = st.radio("16.従業員は、この施設で従業員に求められる食品安全のレベルを理解している。",
[1,2,3,4,5],
captions = answer, index=2, horizontal=True)
#質問8~10は逆転項目のため、変換する
q8t = 6 - q8
q9t = 6 - q9
q10t = 6 - q10
#それぞれのエリアの平均を出す
m1 = round((q1 + q2 + q3 + q4) / 4 ,2)
m2 = round((q5 + q6 + q7) / 3, 2)
m3 = round((q8t + q9t + q10t) / 3, 2)
m4 = round((q11 + q12 + q13 + q14 + q15 + q16) / 6, 2)
#ボタンが押されたら、グラフを描画+それぞれのエリアの平均値を表示する
if st.button('提出'):
df = pd.DataFrame(dict(
r=[m1, m2, m3, m4],
theta=['従業員のコミットメント','資源','責任者のコミットメント', 'リーダーシップ']))
fig = px.line_polar(df, r='r', theta='theta', line_close=True)
st.plotly_chart(fig)
st.write('従業員のコミットメント:', m1)
st.write('資源:', m2)
st.write('責任者のコミットメント:', m3)
st.write('リーダーシップ:', m4)
私自身も何度もトライ&エラーを繰り返し、この最終コードができました。
一見すると長いコードに見えますが、書いてあることは繰り返しが多いです。
21~74行目は質問1~16になります。先ほどのコードをコピーし、一部修正しただけです。
77~79行目は、質問8~10が「逆転項目」のため、他と合わせるために変換しています。
測定の向きが逆になる質問のことです。他の質問は「5 そう思う」が良い意味なのに対し、質問8~10は「5 そう思う」が悪い意味になります。回答者がきちんと考えて回答してくれることを期待してアンケートに忍び込ませておきます。
82~85行目は4つのエリアの平均値を出しています。「round関数」を使い、引数を2とすることで、小数点第二位以下で四捨五入しています。
88行目のif st.button('提出'):
では、提出
というボタンを作り、もし提出ボタンが押されたら:より後の処理を行うという命令です。
89行目からは、ボタンが押された後の処理です。グラフの描写と、それぞれのエリアの点数を表示しています。グラフ描画のコードはこちらの記事を参考に書きました。
実際に完成したアプリをいろいろ試して、不具合がないかを確認してみてください。
100行のコードと聞くととてもボリュームがあるように感じます。
しかし、重複部分を考慮すると、実際は30~40行くらいの内容です。
streamlitを使って、たった30~40行のコードで作りたいウェブアプリを開発することができました。
今はアプリが自分のブラウザだけで表示されています。
次回の記事では、アプリを外部に公開し、誰でもインターネットからアクセスできるようにします。
コメント