Scriptone Scriptone

Streamlit 시작하기 (텍스트 출력 등)

blog-image

개요

Tauri나 웹도 다룰 수 있지만, 간편하게 Python만으로 앱을 만들어보고 싶은 마음이 생겼습니다. Gradio 등의 선택지도 있지만, 저는 Tauri나 웹도 일부러 사용할 정도로 까다로운 성격이라 Gradio만큼 간편하지는 않지만 Python의 다양한 라이브러리와 호환성이 있는 Streamlit에 흥미가 생겼습니다. 조금씩 만들어가겠습니다.

설치

Python은 3.9부터 3.13이어야 합니다. 2025년 11월 21일 시점에서는 Python 3.14는 권장되지 않는 것으로 보이니 주의하세요. Python 라이브러리이므로 pip 등으로 설치할 수 있습니다.

pip install streamlit

uv나 가상 환경을 사용하는 경우에는 설치 후 streamlit hello 명령을 실행하면 브라우저에서 데모가 열립니다. 다만 데모 코드를 갑자기 봐도 이해하기 어려워서 일단 Document를 확인하면서 작성법을 배워가겠습니다.

Hello World

정석적인 Hello World를 Streamlit 방식으로 작성해봅니다. projects/hello_world/app.py에 다음을 작성합니다.

import streamlit as st

st.write("Hello World")

그 후 streamlit run projects/hello_world/app.py를 실행하면 브라우저에 Hello World가 표시됩니다. st.writest.title로 바꾸면 큰 글자로 출력할 수 있습니다.

import streamlit as st

# st.write("Hello world")
st.title("Hello world")

타이핑되는 것처럼 문자 표시하기

제너레이터와 st.write_stream을 조합하면 타이핑되는 문자처럼 표시할 수 있습니다. 문자열 외에 Pandas의 DataFrame이나 Markdown의 자동 파싱에도 대응하고 있습니다.

import time

import numpy as np
import pandas as pd
import streamlit as st


def stream_data(*itrs, sleep_time: float = 0.025):
    def inner():
        for itr in itrs:
            if isinstance(itr, str):
                for char in itr:
                    yield char
                    time.sleep(sleep_time)
            else:
                yield itr
                time.sleep(sleep_time)

    return inner


text = "Streamlit is convenient because you can develop both the backend and frontend using only Python!"
df = pd.DataFrame(
    np.random.randn(5, 10),
    columns=["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"],
)
additional_text = "You can also display **Pandas DataFrames** in a **tabular format** like the one above."
if st.button("Stream data"):
    st.write_stream(stream_data(text, df, additional_text))

실제로 작동하는 모습은 https://rmc8-streamlit-practice-projectstyperwritter-effectapp-zwmnbe.streamlit.app/에 앱을 배포하고 있습니다. 버튼을 누르면 생성 AI의 응답처럼 문자가 순서대로 표시되는 모습을 확인할 수 있습니다. 생성 AI의 답변을 스트림으로 받아 실시간으로 표시하는 용도로 사용할 수 있어 사용자에게도 실시간으로 답변을 표시하는 인상을 주므로 편리할 것 같습니다.

magic

변수나 값만 기술하면 그대로 표시됩니다. 대화식 Python 처리나 Jupyter Lab에서 변수를 print를 사용하지 않고 그대로 출력하는 처리와 비슷하지만, 여러 변수나 값을 한 번에 표시할 수 있습니다.

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

df = pd.DataFrame({"col1": [1, 2, 3]})
df

x = 10
"x", x

arr = np.random.normal(1, 1, size=100)
fig, ax = plt.subplots()
ax.hist(arr, bins=20)
fig

그대로 Python으로 실행해도 아무 일도 일어나지 않지만, streamlit run app.py 실행을 통해 변수 내용이 출력되는 것을 확인할 수 있습니다. 또한 .streamlit/config.toml에서 이 magic 기능을 끌 수도 있습니다.

[runner]
magic = false

텍스트 관련 요소

텍스트 관련 처리가 많이 있으므로 하나씩 확인합니다.

Markdown

정형화된 상태로 Markdown을 표시하려면 st.markdown을 사용합니다.

import streamlit as st

st.markdown("*Streamlit* is **really** ***cool***.")
st.markdown('''
    :red[Streamlit] :orange[can] :green[write] :blue[text] :violet[in]
    :gray[pretty] :rainbow[colors] and :blue-background[highlight] text.''')
st.markdown("Here's a bouquet —\
            :tulip::cherry_blossom::rose::hibiscus::sunflower::blossom:")

multi = '''If you end a line with two spaces,
a soft return is used for the next line.

Two (or more) newline characters in a row will result in a hard return.
'''
st.markdown(multi)

st.markdown(body, unsafe_allow_html=False, *, help=None, width="stretch")의 구성으로 사용할 수 있는 것 같지만 기본적으로는 width를 사용하는 정도일 것 같습니다. HTML을 사용하는 경우에는 unsafe_allow_html을 True로 하면 가능하지만, st.html의 사용을 먼저 검토하면서 가능한 한 이 옵션은 True로 하지 않는 것이 좋을 것 같습니다.

width는 레이아웃에 맞춰서 넓히는 stretch, 텍스트 너비에 맞춰 너비를 정하는 content, 픽셀 지정 수치 입력(int)의 3종류가 있습니다. 엄밀하게 너비를 정할 수도 있지만 간편하게 사용하는 프레임워크로서는 stretchcontent가 첫 번째 선택지가 될 것 같습니다. 다른 text 계열의 처리에서도 사용할 수 있으므로 기억해두면 좋을 것입니다.

헤더

st.header로 헤더를 표시할 수 있습니다. 헤더는 HTML의 h2에 해당합니다. 앞부분에 나온 st.title은 h1에 해당합니다. 그래서 페이지 내의 소항목에는 st.header를 사용하여 제목이나 목차용 앵커를 만들고, divider 인수를 사용하여 목차 밑줄을 만드는 등의 장식을 할 수 있습니다.

import streamlit as st

st.header("_Streamlit_ is :blue[cool] :sunglasses:")
st.header("This is a header with a divider", divider="gray")
st.header("These headers have rotating dividers", divider=True)
st.header("One", divider=True)
st.header("Two", divider=True)
st.header("Three", divider=True)
st.header("Four", divider=True)

서브헤더

st.subheader로 서브헤더를 표시할 수 있습니다. h3h6에 해당합니다. 그래서 헤더와 사용법은 거의 같지만, h4h6도 묶여 있으므로 대규모 구조를 1개의 페이지 내에 구축하는 것에는 적합하지 않을 것 같습니다. 반대로 심플한 페이지를 만드는 것에 적합하며, 앱을 빠르고 알기 쉽게 만들 수 있다는 점에서 장점이 있습니다.

배지

배경색을 동반한 텍스트를 표시하려면 st.badge를 사용합니다. 또는 markdown용으로도 전용 표기법이 준비되어 있습니다.

import streamlit as st

st.badge("1.0.0", width="content")
st.badge("Success", icon=":material/check:", color="green")
st.markdown(
    ":violet-badge[:material/star: Favorite] Streamlit is :blue[cool] :sunglasses:"
)

그대로 요소를 표시하면 줄바꿈되므로, 배지 뒤에 텍스트를 표시할 필요가 있는 경우에는 markdown을 사용하게 됩니다.

캡션

도표 설명, UI 컴포넌트의 보충 정보, 면책 사항이나 주의사항 기재 등에 사용합니다.

import streamlit as st

st.caption("This is a string that explains something above.")
st.caption("A caption with _italics_ :blue[colors] and emojis :sunglasses:")

코드 블록

코드 블록을 표시하려면 st.code를 사용합니다. 구문 강조 표시도 언어를 지정하면 가능합니다.

import streamlit as st

code = """
function hello() {
    console.log("Hello Streamlit!");
}
"""
st.code(
    code,
    language="javascript",
    line_numbers=True,
)

echo

이것은 직관적으로 메서드 이름만으로는 알기 어렵지만, with st.echo():를 사용했을 때 블록 내의 코드를 출력하는 메서드입니다.

import streamlit as st

with st.echo():
    def hello():
        return "Hello Streamlit!"
    st.write(hello())

with 블록 내의 코드가 코드 블록으로 표시됩니다. 안에 st.write 등의 처리가 있으면 코드 블록 아래에 처리가 표시됩니다. 코드 튜토리얼이나 데모 용도, 디버그 등의 정보 공유 등에 사용할 수 있을 것 같지만, 다른 메서드와 비교하면 사용하는 장면이 제한적일 것 같습니다.

text

markdown이나 html의 파싱을 동반하지 않고 순수한 텍스트로서의 출력에 사용합니다.

import streamlit as st

st.text("This is text\n[and more text](that's not a Markdown link).")

LaTeX

LaTeX를 사용한 수식을 표시하는 데 사용합니다.

import streamlit as st

st.latex(r'''
    a + ar + a r^2 + a r^3 + \cdots + a r^{n-1} =
    \sum_{k=0}^{n-1} ar^k =
    a \left(\frac{1-r^{n}}{1-r}\right)
    ''')

divider

페이지 내에 구분선을 표시하기 위해 사용합니다.

import streamlit as st

st.divider()

help

객체의 도움말을 간단하게 표시할 수 있습니다.

import streamlit as st


class Dog:
    """A typical dog."""

    def __init__(self, breed, color):
        self.breed = breed
        self.color = color

    def bark(self):
        return "Woof!"


dog = Dog(breed="Golden Retriever", color="Brown")
st.help(dog)
st.help(dict)

객체의 상태나 메서드 등 상태를 표시할 수 있으므로 교육이나 데모, 디버그 등에 활용할 수 있을 것 같습니다.

html

st.html로 HTML을 표시할 수 있습니다. HTML은 신뢰할 수 있는 것을 표시하는 것이 바람직합니다.

import streamlit as st

st.html(
    "<p><span style='text-decoration: line-through double red;'>Oops</span>!</p>"
)

여기까지의 Streamlit 소감

HTML이나 Markdown의 Parse 기능은 있지만 Python만으로도 웹 애플리케이션을 만들 수 있으며, DataFrame이나 help의 표시 등 Python과 통합된 형태로 처리를 간결하게 기술할 수 있다는 점에서 TypeScript 등에는 없는 Python용의 독자적인 강점이 있어 매우 편리해 보입니다. Text 관련 처리만으로도 여기까지의 종류가 있으므로 목적의 앱을 충분히 만들 수 있을 것 같습니다. 또한 Text뿐만 아니라 Pandas에 의한 표 표시나, Polars 등에서의 인터랙티브한 도표 표시, 지도 표시, JSON이나 dict의 취급 등 아직 게재하지 않은 기능이 많이 있습니다. 페이지 링크나 체크박스 등 웹 폼의 기능도 있으므로 또 별도로 기사를 작성하여 계속 Streamlit 학습을 해나가겠습니다.

comment

댓글을 불러오는 중...