R

ReflexKR

Reflex 官方文档

组件工坊:Reflex 组件库 100 例

·

课程概览

布局

·

Box

·

Flex

·

Stack

·

Grid

·

Container

·

Section

·

Center

·

Spacer

·

Separator

·

Card

·

Inset

·

Aspect Ratio

·

Fragment

排版

·

Text

·

Heading

·

Link

·

Code

·

Markdown

·

Blockquote

·

Quote

·

Strong

·

Em

·

Kbd

表单

·

Button

·

Input

·

Text Area

·

Checkbox

·

Switch

·

Radio Group

·

Select

·

Slider

·

Form

·

Upload

数据展示

·

Badge

·

Avatar

·

Icon

·

Callout

·

List

·

Data List

·

Code Block

·

Progress

·

Spinner

·

Scroll Area

·

Moment

展开与切换

·

Tabs

·

Accordion

·

Segmented Control

浮层

·

Tooltip

·

Popover

·

Hover Card

·

Dialog

·

Alert Dialog

·

Drawer

·

Dropdown Menu

·

Context Menu

·

Toast

动态渲染

·

Cond

·

Match

·

Foreach

·

Auto Scroll

媒体

·

Image

·

Audio

·

Video

表格与数据网格

·

Table

·

Data Table

·

Data Editor

图表

·

Area Chart

·

Bar Chart

·

Line Chart

·

Composed Chart

·

Pie Chart

·

Radar Chart

·

Radial Bar Chart

·

Scatter Chart

·

Funnel Chart

·

Treemap

·

Sankey Chart

·

Error Bar

图表部件

·

Axis

·

Cartesian Grid

·

Chart Tooltip

·

Legend

·

Label

·

Reference

·

Brush

其他图表库

·

Plotly

·

Pyplot

HTML 元素

·

HTML

·

HTML Text

·

HTML Layout

·

HTML Forms

·

HTML Media

·

HTML Tables

·

SVG

其他工具

·

Theme

·

Skeleton

·

Clipboard

·

Html Embed

·

Script

·

Memo

组件工坊:Reflex 组件库 100 例
图表

Pie Chart

rx.recharts.pie_chartrx.recharts.pierx.recharts.cell

官方文档

工坊订单

请用环形图展示上个月访客的浏览器占比,并让每一块都显示名称和数值。

rx.recharts.pie_chart 把整体看作 100,把各部分所占的份额切成扇区来展示。扇区不超过五六个、"占整体多少"最重要时就用它。和其他图表不同,data 不是交给图表容器,而是交给 rx.recharts.pie。data_key 是扇区的大小,name_key 是扇区的名称。

在数据的某个 dict 里写上 "fill",只有那一块会用这个颜色;没写的则使用 pie 的 fill。

rx.recharts.pie_chart(
    rx.recharts.pie(
        data=[
            {"name": "Group A", "value": 400},
            {"name": "Group B", "value": 300, "fill": rx.color("teal", 9)},
            {"name": "Group C", "value": 300, "fill": rx.color("orange", 9)},
            {"name": "Group D", "value": 200, "fill": rx.color("plum", 9)},
        ],
        data_key="value",
        name_key="name",
        fill=rx.color("accent", 9),
        label=True,
    ),
    width="100%",
    height=300,
)

试着改属性

把 inner_radius 设得大于 0,中间就会空出来,变成环形图。半径可以用数字(像素)或百分比字符串。

试着改属性

inner_radius

outer_radius

color

label

label_line

legend_type

rx.recharts.pie_chart(
    rx.recharts.pie(
        data=[
            {"name": "Chrome", "value": 275},
            {"name": "Safari", "value": 150},
            {"name": "Firefox", "value": 100},
            {"name": "Edge", "value": 130},
        ],
        data_key="value",
        name_key="name",
        inner_radius="0%",
        outer_radius="80%",
        fill=rx.color("indigo", 8),
        stroke=rx.color("gray", 1),
        label=True,
        label_line=True,
        legend_type="rect",
    ),
    rx.recharts.graphing_tooltip(),
    rx.recharts.legend(),
    width="100%",
    height=300,
)
打开 label,扇区外侧会显示数值;label_line 是连接扇区和数值的线。legend_type 是图例图标的形状。
属性取值默认值用途
pie_chart(width=, height=, margin=)数字或百分比 / dict"100%"图表尺寸和留白。data 不在这里
pie(data=)dict 的列表无扇区数据
pie(data_key=, name_key=)字符串无 / "name"扇区大小和名称的键
pie(cx=, cy=)数字或百分比"50%"圆心位置
pie(inner_radius=, outer_radius=)数字或百分比0 / "80%"内半径和外半径。内半径大于 0 即为环形
pie(start_angle=, end_angle=)数字(度)0 / 360绘制的角度范围。180 和 0 为半圆
pie(padding_angle=, min_angle=)数字(度)0扇区之间的空隙、小扇区的最小角度
pie(fill=, stroke=)颜色accent 3 / accent 9扇区颜色和边框颜色
pie(label=, label_line=)True / False / dictFalse数值显示和连接线
pie(legend_type=)"rect" "circle" … "none""rect"图例图标
pie(is_animation_active=, animation_begin=, animation_duration=, animation_easing=)True / 400 / 1500 / "ease"入场动画
cell(fill=, stroke=)颜色在 pie 中设定单个扇区的颜色
事件on_click on_mouse_enter on_mouse_leave …pie_chart、pie、cell 都能接收

叠放两个饼

放两个 pie,它们会以同一个圆心叠在一起。内层饼用 outer_radius="50%" 缩小,外环用 inner_radius="60%" 空出中间,就能在一张图里比较两组数据。padding_angle 让扇区之间按角度隔开。

rx.recharts.pie_chart(
    rx.recharts.pie(
        data=[
            {"name": "Q1", "value": 400},
            {"name": "Q2", "value": 300},
            {"name": "Q3", "value": 300},
            {"name": "Q4", "value": 200},
        ],
        data_key="value",
        name_key="name",
        fill=rx.color("teal", 8),
        inner_radius="60%",
        padding_angle=5,
    ),
    rx.recharts.pie(
        data=[
            {"name": "Q1", "value": 2400},
            {"name": "Q2", "value": 4567},
            {"name": "Q3", "value": 1398},
            {"name": "Q4", "value": 9800},
        ],
        data_key="value",
        name_key="name",
        fill=rx.color("accent", 8),
        outer_radius="50%",
    ),
    rx.recharts.graphing_tooltip(),
    width="100%",
    height=300,
)

给每块上色(cell)

即使数据里没写颜色,也可以在 pie 里放入与扇区数量相同的 rx.recharts.cell 来定颜色。用 rx.foreach 遍历数据生成 cell,从颜色列表中取第 index 个颜色。cell 的顺序就是扇区的顺序。把 stroke 设为背景色并加粗边框,扇区之间就会出现缝隙。

piechart_data = [
    {"name": "Chrome", "value": 275},
    {"name": "Safari", "value": 150},
    {"name": "Firefox", "value": 100},
    {"name": "Edge", "value": 130},
    {"name": "Other", "value": 60},
]


rx.recharts.pie_chart(
    rx.recharts.pie(
        rx.foreach(
            piechart_data,
            lambda item, index: rx.recharts.cell(
                fill=rx.Var.create(["#6366F1", "#8B5CF6", "#A855F7", "#D946EF", "#EC4899"])[index % 5],
            ),
        ),
        data=piechart_data,
        data_key="value",
        name_key="name",
        inner_radius="40%",
        outer_radius="80%",
        padding_angle=2,
        stroke="#fff",
        custom_attrs={"strokeWidth": 2},
    ),
    rx.recharts.graphing_tooltip(),
    width="100%",
    height=300,
)

渐变填充

先在尺寸为 0 的 rx.el.svg 里定义 radial_gradient,再在每个 cell 的 fill 中用 url(#id) 引用。渐变定义即使在图表之外,只要在同一页面内就能找到。id 在页面中不要重复。

piechart_data = [
    {"name": "Chrome", "value": 275},
    {"name": "Safari", "value": 150},
    {"name": "Firefox", "value": 100},
    {"name": "Edge", "value": 130},
    {"name": "Other", "value": 60},
]


rx.box(
    rx.el.svg(
        rx.el.svg.defs(
            *[
                rx.el.svg.radial_gradient(
                    rx.el.svg.stop(offset="10%", stop_color=color, stop_opacity=1),
                    rx.el.svg.stop(offset="95%", stop_color=color, stop_opacity=0.6),
                    id=f"piechart_grad_{i}",
                    cx="50%",
                    cy="50%",
                    r="50%",
                )
                for i, color in enumerate(["#6366F1", "#8B5CF6", "#EC4899", "#F59E0B"])
            ],
        ),
        width=0,
        height=0,
    ),
    rx.recharts.pie_chart(
        rx.recharts.pie(
            *[rx.recharts.cell(fill=f"url(#piechart_grad_{i})") for i in range(4)],
            data=piechart_data[:4],
            data_key="value",
            name_key="name",
            inner_radius="60%",
            outer_radius="80%",
            padding_angle=5,
            stroke="#fff",
            custom_attrs={"strokeWidth": 2},
        ),
        rx.recharts.graphing_tooltip(),
        width="100%",
        height=300,
    ),
    width="100%",
)

随 State 变化的数据

把 State 的值交给 pie 的 data,数字每次变化,扇区大小都会跟着变。这里用 start_angle=180、end_angle=0 做成半圆图,并把圆心下移(cy="80%")。

Wood 3

Stone 2

Gold 1

Food 4

from typing import Any


class PieChartStockState(rx.State):
    stock: list[dict[str, Any]] = [
        {"item": "Wood", "count": 3},
        {"item": "Stone", "count": 2},
        {"item": "Gold", "count": 1},
        {"item": "Food", "count": 4},
    ]

    @rx.event
    def change(self, item: str, delta: int):
        self.stock = [
            {**row, "count": max(0, row["count"] + delta)} if row["item"] == item else row
            for row in self.stock
        ]


rx.vstack(
    rx.recharts.pie_chart(
        rx.recharts.pie(
            data=PieChartStockState.stock,
            data_key="count",
            name_key="item",
            cx="50%",
            cy="80%",
            start_angle=180,
            end_angle=0,
            fill=rx.color("accent", 8),
            label=True,
        ),
        rx.recharts.graphing_tooltip(),
        width="100%",
        height=240,
    ),
    rx.flex(
        rx.foreach(
            PieChartStockState.stock,
            lambda row: rx.hstack(
                rx.button("-", size="1", variant="soft", on_click=PieChartStockState.change(row["item"].to(str), -1)),
                rx.text(row["item"], " ", row["count"], size="2"),
                rx.button("+", size="1", variant="soft", on_click=PieChartStockState.change(row["item"].to(str), 1)),
                align="center",
            ),
        ),
        spacing="4",
        wrap="wrap",
    ),
    align="center",
    width="100%",
)

鼠标悬停(hover 事件)

把扇区的 index 传给 cell 的 on_mouse_enter,在 on_mouse_leave 里清除。选中扇区的数值和名称用叠在环形中央的文字显示。给文字容器设置 pointer_events="none",让鼠标能碰到扇区。

Hover a slice

class PieChartHoverState(rx.State):
    languages: list[dict[str, str | int]] = [
        {"name": "Python", "value": 35},
        {"name": "JavaScript", "value": 25},
        {"name": "Java", "value": 20},
        {"name": "C++", "value": 15},
        {"name": "Ruby", "value": 5},
    ]
    hovered_name: str = ""
    hovered_value: int = 0

    @rx.event
    def enter(self, index: int):
        self.hovered_name = str(self.languages[index]["name"])
        self.hovered_value = int(self.languages[index]["value"])

    @rx.event
    def leave(self):
        self.hovered_name, self.hovered_value = "", 0


rx.box(
    rx.vstack(
        rx.cond(
            PieChartHoverState.hovered_name != "",
            rx.fragment(
                rx.heading(PieChartHoverState.hovered_value, "%", size="7"),
                rx.text(PieChartHoverState.hovered_name, size="2"),
            ),
            rx.text("Hover a slice", size="2", color_scheme="gray"),
        ),
        align="center",
        spacing="1",
        position="absolute",
        top="50%",
        left="50%",
        transform="translate(-50%, -50%)",
        pointer_events="none",
    ),
    rx.recharts.pie_chart(
        rx.recharts.pie(
            rx.foreach(
                PieChartHoverState.languages,
                lambda item, index: rx.recharts.cell(
                    fill=rx.Var.create(["#2B79D1", "#2469B3", "#1E5AA1", "#3D8EE1", "#61A9E4"])[index % 5],
                    on_mouse_enter=PieChartHoverState.enter(index),
                    on_mouse_leave=PieChartHoverState.leave,
                ),
            ),
            data=PieChartHoverState.languages,
            data_key="value",
            name_key="name",
            inner_radius=90,
            stroke="0",
        ),
        width="100%",
        height=300,
    ),
    position="relative",
    width="100%",
)

完成订单

把五种浏览器画成环形图,用 cell 按固定顺序给每块上色。最后的 "Other" 用灰色淡化处理。数值看 label,名称看图例和提示框。

piechart_data = [
    {"name": "Chrome", "value": 275},
    {"name": "Safari", "value": 150},
    {"name": "Firefox", "value": 100},
    {"name": "Edge", "value": 130},
    {"name": "Other", "value": 60},
]


rx.recharts.pie_chart(
    rx.recharts.pie(
        rx.foreach(
            piechart_data,
            lambda item, index: rx.recharts.cell(
                fill=rx.Var.create([
                    rx.color("indigo", 9), rx.color("teal", 9), rx.color("orange", 9),
                    rx.color("plum", 9), rx.color("gray", 8),
                ])[index],
            ),
        ),
        data=piechart_data,
        data_key="value",
        name_key="name",
        inner_radius="55%",
        outer_radius="80%",
        padding_angle=2,
        stroke=rx.color("gray", 1),
        label=True,
    ),
    rx.recharts.graphing_tooltip(),
    rx.recharts.legend(),
    width="100%",
    height=320,
)

工坊笔记

  • data 不交给 pie_chart,而是交给 pie。data_key 是大小,name_key 是名称。

  • inner_radius > 0 即为环形图,用 start_angle、end_angle 做半圆。

  • 扇区颜色由数据中的 "fill" 键,或在 pie 里用 foreach 放入的 rx.recharts.cell 决定。

  • 放两个 pie 会以同一圆心叠放,用 outer_radius、inner_radius 划分位置。

  • 用 cell 的 on_mouse_enter(index) 可以把选中的扇区存进 State。

← 上一课

图表 · Composed Chart

下一课 →

图表 · Radar Chart

订阅新课时和新课程通知

本课程新增课时或推出后续课程时,我们会发邮件通知你。

收集项目:电子邮箱 · 用途:本课程的新课时和上线通知 · 保存期限:直到你要求删除。不会用于其他用途,也不会提供给他人。回复任意通知邮件,我们会立即删除。

问答

关于本课有任何疑问都可以在这里留言。所有语言版本页面的提问会汇集在一起。

以纯文本显示,不支持链接和格式。

R

ReflexKR

动手学 Python 和 Reflex。所有示例均已在 Reflex 0.10.0 上实际运行验证。

ReflexKR 免费,没有横幅广告。如果对你有帮助,欢迎请我们喝杯咖啡。 ☕ 请我们喝杯咖啡

联盟链接与赞助说明
한국어English日本語简体中文EspañolDeutsch

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

Built with Reflex