The Component Workshop: Reflex's 100 Library Components
·
Course overview
Layout
·
Box
·
Flex
·
Stack
·
Grid
·
Container
·
Section
·
Center
·
Spacer
·
Separator
·
Card
·
Inset
·
Aspect Ratio
·
Fragment
Typography
·
Text
·
Heading
·
Link
·
Code
·
Markdown
·
Blockquote
·
Quote
·
Strong
·
Em
·
Kbd
Forms
·
Button
·
Input
·
Text Area
·
Checkbox
·
Switch
·
Radio Group
·
Select
·
Slider
·
Form
·
Upload
Data display
·
Badge
·
Avatar
·
Icon
·
Callout
·
List
·
Data List
·
Code Block
·
Progress
·
Spinner
·
Scroll Area
·
Moment
Disclosure
·
Tabs
·
Accordion
·
Segmented Control
Overlay
·
Tooltip
·
Popover
·
Hover Card
·
Dialog
·
Alert Dialog
·
Drawer
·
Dropdown Menu
·
Context Menu
·
Toast
Dynamic rendering
·
Cond
·
Match
·
Foreach
·
Auto Scroll
Media
·
Image
·
Audio
·
Video
Tables and data grids
·
Table
·
Data Table
·
Data Editor
Charts
·
Area Chart
·
Bar Chart
·
Line Chart
·
Composed Chart
·
Pie Chart
·
Radar Chart
·
Radial Bar Chart
·
Scatter Chart
·
Funnel Chart
·
Treemap
·
Sankey Chart
·
Error Bar
Chart parts
·
Axis
·
Cartesian Grid
·
Chart Tooltip
·
Legend
·
Label
·
Reference
·
Brush
Other chart libraries
·
Plotly
·
Pyplot
HTML elements
·
HTML
·
HTML Text
·
HTML Layout
·
HTML Forms
·
HTML Media
·
HTML Tables
·
SVG
Other tools
·
Theme
·
Skeleton
·
Clipboard
·
Html Embed
·
Script
·
Memo
reflex_pyplot.pyplotOfficial docs
Workshop order
Put the matplotlib plotting code from the lab on a web page as is, and make the figure change when a product is picked.
pyplot is a component that shows Matplotlib figures on a Reflex page. It lives in a separate package, reflex-pyplot. Pass it a Figure made with matplotlib.pyplot and it draws it in the browser, so you need no Flask routes or base64 image conversion.
The examples on this page are shown as code only. That is because matplotlib and reflex-pyplot are not installed on this site. To run the code below in your own app, first install both packages (and numpy for some examples).
matplotlib.pyplot is a collection of functions that lets you use Matplotlib the way you would use MATLAB. Calls such as plt.plot, plt.scatter and plt.bar add lines, bars, text and legends to the figure one by one. A script ends with plt.show() to open a window, but in a Reflex app you pass the Figure to the pyplot component, and it is redrawn when State changes.
If you already have matplotlib code in Jupyter notebooks, research scripts or data pipelines, use it in a web app as is instead of porting it to another chart library.
For everyday business charts such as bars, lines and pies, Reflex's built-in Recharts charts (rx.recharts) fit better; for interactive and 3D figures you can zoom and rotate, rx.plotly does.
Installing reflex-pyplot also requires matplotlib. Some of the examples below use numpy too.
pip install reflex-pyplot
# in a project that uses uv
uv add reflex-pyplotImport it with from reflex_pyplot import pyplot and pass the figure (Figure) as the first child. It is drawn on screen as an image, so give it image attributes such as alt (alternative text), loading and decoding, along with width and 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%",
)Always close the figure with plt.close(fig) after creating it. Otherwise the server keeps holding on to the figure and memory grows. Matplotlib decides the figure's colors, so it is wrapped in rx.card(bg_color="#ffffff") to keep a white background even in a dark theme.
The most common figure. Build it with plt.subplots() and ax.plot() as in a script, and pass the figure to 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%",
)The same approach, except that you pass categories and values to 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%",
)A scatter plot of random points gets a reshuffle button and a slider for the number of points. An @rx.var computed value builds the figure, so it is redrawn when State values change. The event has throttle=500 so it redraws at most once every 0.5 seconds.
Matplotlib figure colors do not follow the app theme. So both a light and a dark figure are built, and rx.color_mode_cond shows the one that matches the current mode.
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%",
)The slider in the official docs example says min_=10, but in Reflex 0.10's rx.slider that name is passed as a CSS style, not as the minimum value. The code above corrects it to min=10. Also, this example stores numpy arrays in State; in a real app it is safer to keep simple values such as lists in State and convert them to arrays when building the figure.
How do I show a Matplotlib figure on a web page? Build the figure as usual and pass that Figure to the pyplot component. No Flask, REST routes or base64 conversion needed.
Can Matplotlib figures be interactive? Yes. Build the figure inside an rx.var that depends on State, change State with events from buttons, sliders and the like, and the figure redraws by itself (see the State example above).
Do I need to call plt.show()? No. plt.show() opens a desktop window, so it is not used in web apps. Return the figure and close it with plt.close(fig).
pyplot shows one Matplotlib figure. It defines no props or events of its own and takes the standard events every component has (on_click, on_mount and so on).
| Argument | Values | Use |
|---|---|---|
| first child | matplotlib.figure.Figure or a State value that returns one | The figure to show |
alt · loading · decoding | string | Image alternative text, lazy loading, asynchronous decoding |
width · height | CSS size | Size the figure takes up |
State holds only the selected product name, and a computed value builds that product's bar chart. This code, too, runs in an app with reflex-pyplot and matplotlib installed.
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%",
)Workshop notes
pip install reflex-pyplot (needs matplotlib). from reflex_pyplot import pyplot.
Pass the Figure as the first child, as in pyplot(fig, alt=…, width=…). Do not use plt.show().
Always close the figure with plt.close(fig) after creating it.
When an @rx.var computed value returns a Figure, it redraws whenever State changes.
Colors do not follow the theme, so split light and dark figures with color_mode_cond.
Get news about new lessons
We'll email you when this course gets new lessons or a follow-up course opens.
R
ReflexKR
Learn Python and Reflex by doing. Every example was run and verified on Reflex 0.10.0.
ReflexKR is free, with no banner ads. If it helped you, you can support it with a coffee. ☕ Buy us a coffee
Affiliate disclosure© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0
Questions & answers
Ask anything about this lesson. Questions from every language version of this page appear together.