组件工坊: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_pyplot.pyplot官方文档
工坊订单
请把实验室里用的 matplotlib 绘图代码原样搬到网页上,选择产品时图随之切换。
pyplot 是在 Reflex 页面上显示 Matplotlib 图的组件,位于单独的 reflex-pyplot 包中。把用 matplotlib.pyplot 画出的 Figure 传进去,它就会在浏览器中绘制出来,不再需要 Flask 路由或把图片转成 base64 之类的工作。
本页的示例只展示代码。因为本站没有安装 matplotlib 和 reflex-pyplot。要在自己的应用里运行下面的代码,需要先安装这两个包(部分示例还需要 numpy)。
matplotlib.pyplot 是一组让你像用 MATLAB 一样使用 Matplotlib 的函数。plt.plot、plt.scatter、plt.bar 这些调用会一项项往图里添加线条、柱子、文字和图例。在脚本里,最后用 plt.show() 弹出窗口;而在 Reflex 应用里,是把 Figure 传给 pyplot 组件,State 变化时就会重新绘制。
如果 Jupyter 笔记本、研究脚本或数据管道里已经有 matplotlib 代码,就不必迁移到别的图表库,直接用在 Web 应用里。
柱形、折线、饼图这类常规业务图表更适合用 Reflex 自带的 Recharts 图表(rx.recharts);可缩放、可旋转的交互式图和 3D 图则更适合用 rx.plotly。
安装 reflex-pyplot 时还需要 matplotlib。下面有几个示例还会用到 numpy。
pip install reflex-pyplot
# in a project that uses uv
uv add reflex-pyplot用 from reflex_pyplot import pyplot 导入,把图(Figure)作为第一个子元素传入。它在页面上以图片形式绘制,所以要一并设上 alt(替代文字)、loading、decoding 等图片属性以及 width、height。
import matplotlib.pyplot as plt
import numpy as np
import reflex as rx
from reflex_pyplot import pyplot
def create_contour_plot():
X, Y = np.meshgrid(np.linspace(-3, 3, 256), np.linspace(-3, 3, 256))
Z = (1 - X / 2 + X**5 + Y**3) * np.exp(-(X**2) - Y**2)
levels = np.linspace(Z.min(), Z.max(), 7)
fig, ax = plt.subplots()
ax.contourf(X, Y, Z, levels=levels)
plt.close(fig)
return fig
def pyplot_simple_example():
return rx.card(
pyplot(
create_contour_plot(),
alt="Filled contour plot of a two-dimensional function",
loading="lazy",
decoding="async",
width="100%",
height="400px",
),
bg_color="#ffffff",
width="100%",
)画完图后一定要用 plt.close(fig) 关闭。不关闭的话,服务器会一直占着这张图,内存会不断增加。图的颜色由 Matplotlib 决定,所以为了在深色主题下也显示白色背景,外面包了一层 rx.card(bg_color="#ffffff")。
最常见的图。和写脚本时一样,用 plt.subplots() 和 ax.plot() 画好,再把图传给 pyplot。
import matplotlib.pyplot as plt
import numpy as np
import reflex as rx
from reflex_pyplot import pyplot
def create_line_plot():
x = np.linspace(0, 10, 100)
fig, ax = plt.subplots()
ax.plot(x, np.sin(x), label="sin(x)")
ax.plot(x, np.cos(x), label="cos(x)")
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.legend()
plt.close(fig)
return fig
def pyplot_line_example():
return rx.card(
pyplot(
create_line_plot(),
alt="Sine and cosine curves from zero to ten",
loading="lazy",
decoding="async",
width="100%",
height="400px",
),
bg_color="#ffffff",
width="100%",
)除了给 ax.bar() 传入类别和数值之外,做法完全相同。
import matplotlib.pyplot as plt
import reflex as rx
from reflex_pyplot import pyplot
def create_bar_chart():
fruits = ["apples", "oranges", "bananas", "pears"]
counts = [23, 17, 35, 29]
fig, ax = plt.subplots()
ax.bar(fruits, counts, color="#4e79a7")
ax.set_ylabel("count")
ax.set_title("Fruit inventory")
plt.close(fig)
return fig
def pyplot_bar_example():
return rx.card(
pyplot(
create_bar_chart(),
alt="Fruit inventory: apples 23, oranges 17, bananas 35, pears 29",
loading="lazy",
decoding="async",
width="100%",
height="400px",
),
bg_color="#ffffff",
width="100%",
)在随机打点的散点图上,加一个重新打乱的按钮和一个控制点数的滑块。图由 @rx.var 计算值生成,所以 State 值一变就会重新绘制。给事件设了 throttle=500,让它每 0.5 秒最多重绘一次。
Matplotlib 图的颜色不会跟随应用主题。所以浅色图和深色图都画一份,再用 rx.color_mode_cond 显示与当前模式相符的那张。
import random
import matplotlib.pyplot as plt
import numpy as np
import reflex as rx
from matplotlib.figure import Figure
from reflex_pyplot import pyplot
def create_plot(theme: str, plot_data: tuple, scale: list):
bg_color, text_color = ("#1e1e1e", "white") if theme == "dark" else ("white", "black")
grid_color = "#555555" if theme == "dark" else "#cccccc"
fig, ax = plt.subplots(facecolor=bg_color)
ax.set_facecolor(bg_color)
for (x, y), color in zip(plot_data, ["#4e79a7", "#f28e2b"]):
ax.scatter(x, y, c=color, s=scale, label=color, alpha=0.6, edgecolors="none")
ax.legend(loc="upper right", facecolor=bg_color, edgecolor="none", labelcolor=text_color)
ax.grid(True, color=grid_color)
ax.tick_params(colors=text_color)
for spine in ax.spines.values():
spine.set_edgecolor(text_color)
for item in [ax.xaxis.label, ax.yaxis.label, ax.title]:
item.set_color(text_color)
plt.close(fig)
return fig
class PyplotState(rx.State):
num_points: int = 25
plot_data: tuple = tuple(np.random.rand(2, 25) for _ in range(2))
scale: list = [random.uniform(0, 100) for _ in range(25)]
@rx.event(temporal=True, throttle=500)
def randomize(self):
self.plot_data = tuple(np.random.rand(2, self.num_points) for _ in range(2))
self.scale = [random.uniform(0, 100) for _ in range(self.num_points)]
@rx.event(temporal=True, throttle=500)
def set_num_points(self, num_points: list[int | float]):
self.num_points = int(num_points[0])
yield PyplotState.randomize()
@rx.var
def fig_light(self) -> Figure:
return create_plot("light", self.plot_data, self.scale)
@rx.var
def fig_dark(self) -> Figure:
return create_plot("dark", self.plot_data, self.scale)
def pyplot_example():
return rx.vstack(
rx.card(
rx.color_mode_cond(
pyplot(PyplotState.fig_light, alt="Scatter plot of the current randomized points", width="100%", height="100%"),
pyplot(PyplotState.fig_dark, alt="Scatter plot of the current randomized points", width="100%", height="100%"),
),
rx.hstack(
rx.button("Randomize", on_click=PyplotState.randomize),
rx.text("Number of Points:"),
rx.slider(default_value=25, min=10, max=100, on_value_commit=PyplotState.set_num_points),
width="100%",
),
width="100%",
),
justify_content="center",
align_items="center",
width="100%",
)官方文档示例里的滑块写的是 min_=10,但在 Reflex 0.10 的 rx.slider 中,这个名字不会被当成最小值,而是作为 CSS 样式传进去。上面的代码已改成 min=10。另外,这个示例把 numpy 数组存进了 State;在实际应用中,更稳妥的做法是在 State 里放列表这类简单的值,画图时再转成数组。
怎样在网页上显示 Matplotlib 图?照常画图,然后把那个 Figure 传给 pyplot 组件即可。不需要 Flask、REST 路由或 base64 转换。
能让 Matplotlib 图变成可交互的吗?可以。在依赖 State 的 rx.var 里画图,再通过按钮、滑块等事件改变 State,图就会自动重绘(见上面的 State 示例)。
需要调用 plt.show() 吗?不需要。plt.show() 是弹出桌面窗口的函数,Web 应用里用不到。返回图对象,再用 plt.close(fig) 关闭即可。
pyplot 显示一张 Matplotlib 图。它没有单独定义的属性或事件,只接受所有组件都有的基础事件(on_click、on_mount 等)。
| 参数 | 取值 | 用途 |
|---|---|---|
| 第一个子元素 | matplotlib.figure.Figure 或返回它的 State 值 | 要显示的图 |
alt · loading · decoding | 字符串 | 图片替代文字、延迟加载、异步解码 |
width · height | CSS 尺寸 | 图所占的尺寸 |
State 里只放选中的产品名,由计算值画出该产品的柱形图。这段代码同样要在安装了 reflex-pyplot 和 matplotlib 的应用中运行。
import matplotlib.pyplot as plt
import reflex as rx
from matplotlib.figure import Figure
from reflex_pyplot import pyplot
MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]
SALES = {"Chairs": [32, 41, 38, 52, 61, 58], "Tables": [12, 15, 21, 19, 24, 30]}
class PyplotReportState(rx.State):
product: str = "Chairs"
@rx.event
def set_product(self, value: str):
self.product = value
@rx.var
def figure(self) -> Figure:
fig, ax = plt.subplots(figsize=(6, 3))
ax.bar(MONTHS, SALES[self.product], color="#4e79a7")
ax.set_title(f"{self.product} sales")
ax.set_ylabel("units")
fig.tight_layout()
plt.close(fig)
return fig
def pyplot_report():
return rx.vstack(
rx.select(["Chairs", "Tables"], value=PyplotReportState.product, on_change=PyplotReportState.set_product),
rx.card(
pyplot(PyplotReportState.figure, alt="Monthly sales of the selected product", width="100%"),
bg_color="#ffffff",
width="100%",
),
width="100%",
)工坊笔记
pip install reflex-pyplot(需要 matplotlib)。from reflex_pyplot import pyplot。
像 pyplot(fig, alt=…, width=…) 这样把 Figure 作为第一个子元素传入。不使用 plt.show()。
画完图后一定要用 plt.close(fig) 关闭。
让 @rx.var 计算值返回 Figure,State 变化时就会重新绘制。
颜色不跟随主题,所以用 color_mode_cond 分别准备浅色图和深色图。
订阅新课时和新课程通知
本课程新增课时或推出后续课程时,我们会发邮件通知你。
问答
关于本课有任何疑问都可以在这里留言。所有语言版本页面的提问会汇集在一起。