Layout - 1

루까까·2024년 11월 2일

Streamlit

목록 보기
5/8
post-thumbnail

저번 시간에는 Input widgets에 알아보았다. 이번에는 widgets을 배치할 수있는 layout에 대해서 알아보자.

Layouts and Containers

widgets 이나 text을 배치할 수 있게 해주는 기능이다.
기본적으로 맨 우측과 좌측을 제외한 중앙 화면 기준으로 layout을 구성할 수 있다.
(물론 config를 바꾸면 전체화면을 활용할 수 있다.)

st.columns

st.columns(spec, *, gap="small", vertical_alignment="top")

화면을 세로 방향으로 비율대로 나누어 text나 widgets을 배치할 수있게 해준다.
예를들어 내가 웹페이지 화면에서 1대1비율로 버튼을 배치하고자 한다면 아래 사진과 같이 배열을 할 수 있다.

spec

  • columns의 비율을 조절해주는 값이다
  • 허용 인자로는 int or Iterable of numbers이다.
    • ex) [1, 1], [0.3, 0.7 , 1]
    • 예를들어 [1, 1]이면 1:1 비율로 배치를 한다.

gap

  • columns사이의 크기를 조절하는 인자이다.
  • 기본적으로 small값이다.

vertical_alignment

  • columns의 기준을 의미한다.
  • 값이 top이면 위를 기준으로 배열한다

기본적으로 코드는

import streamlit as st

col1, col2 = st.columns([1,1])


with col1:
    st.button('test1')

col2.button('test2')

이런식으로 사용이 가능하다.

기본적으로 streamlit의 경우 오른쪽으 widgets이 배치가 되어진다.
예를들어 button을 양옆 끝으로 배치하고 싶다고 한다면

import streamlit as st
col1, *_, col2 = st.columns([1, 7, 1])
with col1:
    st.button('test1')
col2.button('test2')
with st.expander(label='test'):
    ...


이렇게 표현이 되는데 살짝 오른쪽으로 치우쳐짐을 확인 할 수 있다.
이때 비율을 조절하면 완전히 끝으로 붙일수는 있지만

import streamlit as st
col1, *_, col2 = st.columns([1, 8, 1])
with col1:
    st.button('test1')
col2.button('test2')
with st.expander(label='test'):
    ...


비율조절이 실패하면

이렇게 된다.
이것을 해결하기 위해 button의 use_container_width을 True로 설정해도 같은 결과가 나온다..
개인적으로 느끼기에 안쓸수는 없는 기능이지만 비율조절이 힘든 매울 짜증나는 기능이다.

st.container

st.container(*, height=None, border=None, key=None)


화면을 가로 방향으로 나누어 text나 widgets을 배치할 수있게 해준다.
colums와는 다르게 비율을 정하는게 아닌 위에서부터 컨테이너처럼 쌓듯이 배치해준다.

height

  • container의 높이를 결정하는 인자이다.

boder

  • 경계면을 표시할건지 선택하는 인자이다. border가 True일 경우, 위에 사진과 같이
    경계면을 나타내준다.

key

  • container의 key값이다. 말 그대로 key이기 때문에 여러개의 container를 사용할 경우, streamlit이 각 container를 구분할 수 있는 key값을 반드시 지정해줘야 한다.

st.dialog

st.dialog(title, *, width="small")

modal창과 같은 기능이다.

어떤 특정 버튼이나 셀렉트박스를 선택하는 등의 상호작용을 통해서 보여진다.
(이게 왜 Layouts에 있는지 모르겟다.)
특정 함수위에 decorated를 통해서 정해진다.
예를들어 사진과 같은 dialog창을 나타내고싶으면

import streamlit as st

@st.dialog(title='Hello Dialog')
def a():
    st.write('Hello')

if st.button('Dialog Button'):
    a()

처럼 표현할 수있는데 a라는 함수위에 데코레이터 st.dialog를 통해서 dialog창을 나타낸다.
또한, 해당 a함수를 실행시키기 위해서 st.button을 삽입한 것도 볼 수 있다.

title

  • dialog의 제목을 나타낸다.

width

  • dialog의 크기를 나타낸다.
  • large,small을 지원하지만 기본적으로 small을 지원한다.
    • large일 경우 다음과 같다.

dialog의 경우, 위와같이 단순 text만 표현할 수 있지만 특정 input을 받아서 제출하는 용도로 활용할 수 있다.
이때, 어떤 버튼(예를 들면 submit)을 눌럿을 때, 자동으로 dialog창이 꺼지기를 원한다면 반드시 st.rerun을 넣어줘야 알아서 dialog창이 꺼지게 된다.
이때, st.rerun을 통해 dialog창을 꺼지게 한다면 dialog의 함수는 return값을 받을 수 없기에(기본적으로 st.rerun이후의 코드는 retrun코드처럼 실행이 되지않는다.) dialog의 input값을 받고 그 값을 활용하기 위해서는 꼭 st.sesstion_state을 통해 값을 전달 받아야 한다.

dialog창 끄기

import streamlit as st
@st.dialog(title='Hello Dialog', width='small')
def a():
    test = st.text_input(label='test')
    if st.button(label='Submit'):
        ...
if st.button('Dialog Button'):
    a()

test라는 text input을 받는 dialog창을 만들었다. 하지만 해당 dialog의 경우, Submit버튼을 눌러도 dialog창이 꺼지지 않게 된다. 여기서 만약 dialog창을 버튼을 누름과 동시에 꺼지게 하고 싶다면

import streamlit as st
@st.dialog(title='Hello Dialog', width='small')
def a():
    test = st.text_input(label='test')
    if st.button(label='Submit'):
        st.rerun()
if st.button('Dialog Button'):
    a()

을 하면 된다.

값 주고 받기

위에서 dialog를 끄는법에 대해서 알았다. 그럼 이제 값을 주고받는 것에 대해서 알아보면

import streamlit as st
@st.dialog(title='Hello Dialog', width='small')
def a():
    test = st.text_input(label='test')
    if st.button(label='Submit'):
        st.rerun()
        return test
if st.button('Dialog Button'):
    test = a()
print(test)

이렇게 코드를 구성할 수 있을 것이다. dialog의 경우 함수 데코레이터처럼 쓰니 return을 통해서 값을 전달받으면 편하다. 하지만 해당 코드를 실행하면,

라는 오류 메세지를 볼 수 있게 된다. 왜냐하면 처음 실행할때, test라는 변수가 없기에 이런 오류가 생기는 것이다.
그렇다면 여기서 Dialog Button을 눌러서 test값을 정의하면 될 것 같지만,


같은 결과가 나옴을 알 수 있다. 원인은 위에서 서술한 것과 같은 이유이다.
따라서 위에 문제를 해결하기 위해서는 st.session_state를 써서 값을 전달받아야한다.

import streamlit as st
if 'test' not in st.session_state:
    st.session_state['test'] = None
@st.dialog(title='Hello Dialog', width='small')
def a():
    test = st.text_input(label='test')
    if st.button(label='Submit'):
        st.session_state['test'] = test
        st.rerun()
if st.button('Dialog Button'):
    a()
print(st.session_state['test'])

해당 코드를 실행하면 정상적으로 input값을 받을 수 있음을 확인 할 수 있다.

profile
기타치는 개발자

0개의 댓글