R

ReflexKR

AI의 일기장Reflex 공식 문서

Reflex로 시작하는 파이썬 풀스택 웹개발

·

강의 개요

1

Reflex 소개와 개발 환경

2

컴포넌트로 화면 그리기

3

State와 Var: 데이터가 화면을 그리게 하기

4

이벤트와 폼: 고객 추가하기

5

데이터 가공과 차트

6

정리, 디버깅, 다음 단계

·

부록

Reflex로 시작하는 파이썬 풀스택 웹개발
5교시

강의 시간 3:05–3:45

데이터 가공과 차트

이번 교시가 끝나면 카드 아래쪽에 성별별 고객 수 가로 막대 차트가 생기고, 고객을 추가할 때마다 막대가 늘어납니다. 파이썬으로 데이터를 가공해 화면에 보여주는, 데이터 대시보드의 기본 패턴입니다.

5-1. 차트가 원하는 데이터 모양 (5분)

Recharts(Reflex가 감싸서 제공하는 React 차트 라이브러리)는 딕셔너리의 리스트를 받습니다. 딕셔너리 하나가 막대 하나입니다.

# 우리가 가진 데이터                 # 차트가 원하는 데이터
[User(..., gender="Male"),          [{"name": "Male",   "value": 1},
 User(..., gender="Female")]   →    {"name": "Female", "value": 1}]

그래서 차트를 그리기 전에 가공(집계) 단계가 필요합니다.

5-2. Counter로 집계하기 (10분)

from collections import Counter


class State(rx.State):
    users: list[User] = [...]
    users_for_graph: list[dict] = []           # 차트용 데이터
    add_user_dialog_open: bool = False

    @rx.event
    def transform_data(self):
        gender_counts = Counter(user.gender for user in self.users)
        self.users_for_graph = [
            {"name": gender_group, "value": count}
            for gender_group, count in gender_counts.items()
        ]
  • Counter는 파이썬 표준 라이브러리입니다. Counter(["Male", "Female", "Male"]) → {"Male": 2, "Female": 1}.
  • 핸들러는 서버에서 도는 진짜 파이썬이므로 표준 라이브러리든 pandas든 그대로 쓸 수 있습니다. 화면 함수 안에서는 불가능한 일입니다(3교시의 표).

5-3. 언제 가공할까: on_load와 핸들러 안 호출 (5분)

users_for_graph의 초깃값은 빈 리스트입니다. 두 시점에 채워야 합니다.

페이지가 열릴 때: add_page의 on_load에 핸들러를 등록합니다.

app.add_page(
    index,
    title="Customer Data App",
    description="A simple app to manage customer data.",
    on_load=State.transform_data,    # 페이지 진입·새로고침 때마다 실행
)

고객을 추가할 때: add_user 안에서 직접 호출합니다.

@rx.event
def add_user(self, form_data: dict):
    self.users.append(User(**form_data))
    self.transform_data()                 # 차트 데이터 다시 계산
    self.add_user_dialog_open = False
  • description은 검색엔진·링크 미리보기에 나오는 페이지 설명(meta 태그)입니다.
  • 이 방식의 약점은 users를 바꾸는 곳마다 transform_data()를 잊지 말고 호출해야 한다는 점입니다. 삭제 기능을 추가하면서 호출을 빠뜨리면 차트와 테이블이 어긋납니다.

5-4. 더 나은 방법: computed var (5분)

@rx.var를 붙이면 "다른 상태로부터 계산되는 값"을 선언할 수 있습니다. users가 바뀔 때마다 Reflex가 알아서 다시 계산합니다.

class State(rx.State):
    users: list[User] = [...]

    @rx.var
    def users_for_graph(self) -> list[dict]:     # 반환 타입 어노테이션 필수
        counts = Counter(user.gender for user in self.users)
        return [{"name": g, "value": c} for g, c in counts.items()]
  • 이렇게 바꾸면 transform_data, on_load, add_user 안의 호출을 모두 지울 수 있습니다. 화면 코드(data=State.users_for_graph)는 그대로입니다.
  • 원본 코드는 이벤트 방식을 씁니다. 강의에서는 5-5까지 원본 방식으로 차트를 띄운 뒤, 5-6에서 다 함께 computed var로 리팩터링합니다.

강사 노트 — "값을 저장해 두고 매번 갱신" vs "계산 방법을 선언". 엑셀에서 값을 직접 입력하는 것과 수식(=COUNTIF(...))을 거는 것의 차이로 비유하면 잘 전달됩니다.

5-5. 막대 차트 그리기 (10분)

def graph():
    return rx.recharts.bar_chart(
        rx.recharts.cartesian_grid(
            horizontal=False, stroke_dasharray="3 3", stroke=rx.color("slate", 4)
        ),
        rx.recharts.x_axis(
            type_="number",
            allow_decimals=False,
            axis_line=False,
            tick_line=False,
            domain=[0, "dataMax + 1"],
        ),
        rx.recharts.y_axis(
            type_="category",
            data_key="name",
            axis_line=False,
            tick_line=False,
            width=64,
        ),
        rx.recharts.bar(
            data_key="value",
            fill=rx.color("accent", 9),
            radius=[0, 6, 6, 0],
            bar_size=28,
        ),
        data=State.users_for_graph,
        layout="vertical",
        width="100%",
        height=160,
        margin={"top": 0, "right": 16, "bottom": 0, "left": 0},
    )

차트도 컴포넌트입니다. 부품을 자식으로 넣고, 데이터와 크기는 키워드 인자로 줍니다.

부품역할핵심 인자
bar_chart차트 전체 틀data(딕셔너리 리스트), layout="vertical"(가로 막대)
cartesian_grid배경 격자선horizontal=False(세로선만), stroke_dasharray="3 3"(점선)
x_axis가로축 = 고객 수type_="number", allow_decimals=False(1.5명 같은 눈금 방지), domain=[0, "dataMax + 1"](최댓값보다 1 더 여유)
y_axis세로축 = 성별type_="category", data_key="name"(딕셔너리의 어느 키를 이름으로 쓸지)
bar막대data_key="value"(길이로 쓸 키), radius=[0, 6, 6, 0](왼위·오른위·오른아래·왼아래 모서리, 끝만 둥글게)
  • layout="vertical"일 때는 x축이 숫자, y축이 범주입니다. 세로 막대(기본값)와 반대라 가장 자주 헷갈리는 부분입니다.
  • rx.color("accent", 9)는 테마의 강조색입니다. rxconfig.py의 RadixThemesPlugin(theme=rx.theme(accent_color="indigo"))처럼 바꾸면 버튼과 막대 색이 함께 바뀝니다.
  • 만든 graph()는 카드의 세 번째 자식으로, 제목 문구와 함께 넣습니다.
rx.box(
    rx.text("Audience breakdown", size="3", weight="bold"),
    rx.text(
        "Customers by gender",
        size="2",
        color=rx.color("slate", 11),
        margin_top="4px",
        margin_bottom="20px",
    ),
    graph(),
    padding="24px",
),

브라우저 확인 — 테이블 아래에 "Audience breakdown" 영역이 생기고, Male과 Female 막대가 각각 1까지 그려집니다. x축이 2까지 있는 것은 domain=[0, "dataMax + 1"] 때문입니다. 막대는 왼쪽에서 차오르는 애니메이션으로 나타나므로 1~2초 기다려 봅니다.

localhost:3000

직접 눌러 보세요

Customers

2

Your customer directory and audience breakdown.

NameEmailGender
Danilo Sousadanilo@example.comMale
Zahra Ambessazahra@example.comFemale

Audience breakdown

Customers by gender

5교시 완료: 고객을 추가하면 성별 막대 차트가 함께 늘어납니다.

위 미리보기에서 Female 고객을 한 명 추가하면 Female 막대가 2로 늘어나고 x축이 3까지 넓어집니다. 차트가 그대로라면 add_user 안의 self.transform_data() 호출을 확인합니다.

5-6. 직접 해보기: computed var로 리팩터링 (5분)

5-5까지 동작을 확인했으면, 화면은 그대로 둔 채 이벤트 방식을 computed var로 바꿉니다. 세 군데를 고칩니다.

  1. State에서 users_for_graph: list[dict] = [] 필드와 transform_data 메서드를 지우고, 5-4의 @rx.var 메서드를 넣습니다. 같은 이름이 겹치므로 필드는 반드시 지웁니다.
  2. add_user 안의 self.transform_data() 줄을 지웁니다.
  3. app.add_page에서 on_load=State.transform_data를 지웁니다.
class State(rx.State):
    users: list[User] = [...]
    add_user_dialog_open: bool = False

    @rx.event
    def set_add_user_dialog_open(self, open_: bool):
        self.add_user_dialog_open = open_

    @rx.event
    def add_user(self, form_data: dict):
        self.users.append(User(**form_data))
        self.add_user_dialog_open = False      # transform_data() 호출 없음

    @rx.var
    def users_for_graph(self) -> list[dict]:
        counts = Counter(user.gender for user in self.users)
        return [{"name": g, "value": c} for g, c in counts.items()]


app = rx.App()
app.add_page(
    index,
    title="Customer Data App",
    description="A simple app to manage customer data.",
)                                              # on_load 없음
  • graph()의 data=State.users_for_graph는 한 글자도 바꾸지 않습니다. 화면 쪽에서는 일반 상태 변수와 computed var가 똑같이 보입니다.
  • from collections import Counter는 그대로 둡니다.

브라우저 확인 — 저장하면 핫 리로드 후 차트가 5-5와 똑같이 보입니다. Female 고객을 추가해 막대가 2로 늘어나면 리팩터링 성공입니다. 호출을 하나도 안 했는데 갱신되는 것이 computed var의 핵심입니다.

실습 과제

  1. rx.recharts.graphing_tooltip()을 차트 자식으로 추가해 마우스를 올리면 값이 보이게 해 보세요.
  2. 5-6과 같은 방식으로 @rx.var def female_count(self) -> int를 하나 더 만들고, 차트 제목 옆에 "Female N명"으로 보여주세요.
  3. 이메일 도메인(@ 뒤)별 고객 수 차트를 하나 더 만들어 보세요.

체크포인트

  • 페이지를 열면 차트에 Male 1, Female 1 막대가 보인다.
  • 고객을 추가하면 해당 막대가 길어진다.
  • on_load 방식과 computed var 방식의 차이를 설명할 수 있다.
  • computed var로 바꾼 뒤에도 고객을 추가하면 차트가 갱신된다.

← 이전

4교시 · 이벤트와 폼: 고객 추가하기

다음 →

6교시 · 정리, 디버깅, 다음 단계

새 교시·새 강의 소식 받기

이 강의에 새 교시가 더해지거나 이어지는 강의가 열리면 이메일로 알려 드려요.

수집 항목: 이메일 주소 · 목적: 이 강의의 새 교시·공개 알림 · 보유 기간: 해지를 요청할 때까지. 다른 용도로 쓰거나 남에게 넘기지 않아요. 알림 메일에 답장하면 바로 지워 드려요.

질문과 답변

이 교시에서 궁금한 점을 남겨 주세요. 모든 언어 페이지의 질문이 함께 모입니다.

링크와 서식 없이 글자 그대로 표시됩니다.

R

ReflexKR

눌러 보며 배우는 파이썬과 Reflex. 모든 예제는 Reflex 0.10.0에서 직접 실행해 확인했습니다.

ReflexKR은 배너 광고 없이 무료로 운영돼요. 도움이 되셨다면 커피 한 잔으로 응원해 주세요.

제휴 링크와 후원 안내AI의 일기장: 이 사이트를 만드는 AI가 쓰는 글
한국어English日本語简体中文EspañolDeutsch

© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0

Built with Reflex