14장. Streamlit 화면과 Docker 컨테이너
위젯과 배치
식당 주문서에는 메뉴를 고르는 칸, 수량을 적는 칸, 요청 사항을 쓰는 칸이 있고, 칸들이 보기 좋게 놓여 있습니다. Streamlit 은 위젯 함수 한 줄이 칸 하나이고, 칸을 놓는 곳은 열, 사이드바, 폼으로 정합니다.
네 카드는 화면을 이루는 요소의 갈래입니다. 위젯은 값을 받고, 배치는 위젯을 놓을 자리를 정하고, 출력은 결과를 글과 숫자와 표로 보여 주고, 채팅은 대화를 말풍선으로 그립니다. 여기서 주문서의 칸이 위젯, 칸의 자리가 배치입니다.
자주 쓰는 함수
| 갈래 | 함수 | 돌려주는 것 |
|---|---|---|
| 위젯 | st.selectbox("지역", [...]) | 고른 값 |
| 위젯 | st.slider("주문시각", 0, 23, 14) | 정수 |
| 위젯 | st.number_input("거리km", 0.5, 1000.0, 20.0) | 실수 |
| 위젯 | st.text_input, st.text_area | 글 |
| 위젯 | st.button("예측하기") | 누른 그 실행에서만 True |
| 배치 | st.columns(2), st.sidebar, st.form | 칸을 놓을 자리 |
| 출력 | st.write, st.metric, st.dataframe | 화면에 그린다 |
| 알림 | st.success, st.warning, st.error | 색이 다른 알림 상자 |
| 채팅 | st.chat_message, st.chat_input | 말풍선, 아래쪽 입력 칸 |
위젯에 이름표(key) 붙이기
같은 이름의 위젯이 둘이면 Streamlit 이 구별하지 못합니다. key= 로 이름표를 붙이면 구별되고, 시험 코드에서도 그 이름표로 위젯을 찾습니다.
# 위젯마다 key 를 정하는 규칙을 미리 표로 만들어 둔다(설명용)
widgets = [("selectbox", "지역"), ("selectbox", "택배사"), ("slider", "주문시각")]
keys = {f"{kind}:{label}": label for kind, label in widgets}
print(keys)
print("겹치는 key:", len(keys) != len(set(keys.values())))코드에 나오는 함수
| 코드 | 쉬운 뜻 |
|---|---|
widgets = [("selectbox", "지역"), ...] | 위젯마다 (종류, 이름표) 짝을 적은 목록이다 |
{f"{kind}:{label}": label for kind, label in widgets} | 사전을 한 줄로 만드는 꼴이다. "종류:이름표" 를 key 로, 이름표를 값으로 담는다 |
set(keys.values()) | set(집합)은 같은 것을 하나로 합친다. 서로 다른 이름표가 몇 개인지 세려고 쓴다 |
len(keys) != len(...) | key 수와 서로 다른 이름표 수가 다르면 True 다. 같은 이름표를 두 위젯이 쓴다는 뜻이다 |
이 코드가 뜻하는 것
도서관의 청구기호에 견줄 수 있습니다. 제목이 같은 책이 두 권 있어도 청구기호가 다르면 사서가 헷갈리지 않습니다. 여기서 책 제목이 위젯의 이름표(label), 청구기호가 key 입니다.
| 줄 | 하는 일 | 쉽게 말하면 |
|---|---|---|
widgets = [...] | 화면에 둘 위젯 셋을 적는다 | 꽂을 책 목록 |
keys = {...} | 종류와 이름표를 붙여 key 를 만든다 | 책마다 청구기호를 붙인다 |
print(keys) | key 와 이름표를 찍는다 | 청구기호 목록을 본다 |
print("겹치는 key:", ...) | 이름표가 겹치는지 본다 | 제목이 같은 책이 있는지 본다 |
결과의 겹치는 key: False 는 세 위젯의 이름표가 모두 달라 헷갈릴 일이 없다는 뜻입니다. 이 예에서는 key 를 따로 붙이지 않아도 되지만, 시험 코드에서 찾기 쉽도록 붙여 둡니다.
작게 줄여서 눈으로 보기
같은 이름표 "지역" 을 선택 상자와 글 입력 칸 둘에 붙였다고 쳐 봅니다. 이 목록은 설명을 위해 지어낸 것입니다.
# 같은 이름표 "지역" 을 두 위젯에 붙였다고 치자(설명용)
widgets = [("selectbox", "지역"), ("text_input", "지역"), ("slider", "주문시각")]
keys = {f"{kind}:{label}": label for kind, label in widgets}
print(list(keys))
print("key 수:", len(keys), "· 서로 다른 이름표 수:", len(set(keys.values())))
print("겹치는 key:", len(keys) != len(set(keys.values())))['selectbox:지역', 'text_input:지역', 'slider:주문시각']
key 수: 3 · 서로 다른 이름표 수: 2
겹치는 key: True| 결과 | 읽는 법 |
|---|---|
['selectbox:지역', 'text_input:지역', ...] | 이름표는 같아도 종류를 앞에 붙인 key 는 셋 다 다르다 |
key 수: 3 · 서로 다른 이름표 수: 2 | 위젯은 셋인데 이름표는 둘뿐이다. "지역" 이 두 번 쓰였다 |
겹치는 key: True | 이름표가 겹친다는 알림이다. 이럴 때 key= 를 꼭 붙여야 Streamlit 이 두 위젯을 구별한다 |
주의할 점
st.button은 누른 그 실행에서만 True 이고, 다음 실행에서는 다시 False 입니다. "눌렀다"는 사실을 남기려면 세션 상태에 적습니다.- 선택 상자의 보기는 모델이 학습한 값으로 채웁니다. 손으로 적으면 모델과 어긋나기 쉽습니다. 실습 3은 API 의 명세에서 보기를 읽어 옵니다.