Skip to content

Commit 44f1470

Browse files
committed
Improved matplotlib docs using @hd.cached
1 parent 2d3e860 commit 44f1470

File tree

1 file changed

+78
-63
lines changed

1 file changed

+78
-63
lines changed

hyperdiv_docs/pages/guide/matplotlib_charts.py

Lines changed: 78 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ def main():
5252
5353
# Render the image bytes in the UI:
5454
hd.image(get_chart_image(fig), width=20)
55+
56+
hd.run(main)
5557
```
5658
5759
Note that `matplotlib.use("Agg")` is important. It tells
@@ -64,115 +66,128 @@ def main():
6466
"""
6567
)
6668

67-
p.heading("## Asynchronous Chart Creation with `task`")
69+
p.heading("## Responding to Theme Mode")
6870

6971
docs_markdown(
7072
"""
7173
72-
In the example above, The chart is re-created on every run
73-
of the app function. We can use a @component(task) to
74-
create the chart only once and cache its result:
74+
By default, Matplotlib chart images are rendered on white
75+
background. There's currently no easy way to match the
76+
chart's color scheme to Hyperdiv's theme exactly, but
77+
Matplotlib provides a basic way to render a chart in dark
78+
or light mode. We can then sync the chart's theme mode to
79+
Hyperdiv's theme mode.
7580
7681
```py-nodemo
77-
def get_chart():
78-
fig, ax = plt.subplots()
79-
ax.plot([1, 2, 3, 4], [10, 11, 12, 13])
82+
def main():
83+
theme = hd.theme()
8084
81-
return get_chart_image(fig)
85+
line_data = ([1, 2, 3, 4], [10, 11, 12, 13])
8286
83-
def main():
84-
task = hd.task()
85-
task.run(get_chart)
86-
if task.result:
87-
hd.image(task.result, width=20)
88-
```
87+
if theme.is_dark:
88+
# Render the matplotlib chart in dark mode:
89+
with plt.style.context("dark_background"):
90+
fig, ax = plt.subplots()
91+
ax.plot(*line_data)
92+
else:
93+
# Render it in light mode:
94+
fig, ax = plt.subplots()
95+
ax.plot(*line_data)
8996
90-
In this example, the function `get_chart` is called only
91-
once and the image bytes are cached in `task.result`.
97+
# Render the image bytes in the UI:
98+
hd.image(get_chart_image(fig), width=20)
99+
```
92100
93101
"""
94102
)
95103

96-
p.heading("## Dynamically Updating Charts")
104+
p.heading("## Caching Chart Components with `@cached`")
97105

98106
docs_markdown(
99107
"""
100108
101-
We can also re-create a chart on demand, with new data.
109+
Using the pattern above, the chart will be re-created on
110+
every unrelated run of the app function. We can use the
111+
@component(cached) decorator to avoid re-creating the
112+
chart on every run.
102113
103114
```py-nodemo
104-
def get_chart(data):
105-
fig, ax = plt.subplots()
106-
ax.plot(*data)
115+
@hd.cached
116+
def chart():
117+
theme = hd.theme()
107118
108-
return get_chart_image(fig)
119+
line_data = ([1, 2, 3, 4], [10, 11, 12, 13])
109120
110-
def main():
111-
state = hd.state(
112-
chart_data=([1, 2, 3, 4], [10, 11, 12, 13])
113-
)
121+
if theme.is_dark:
122+
with plt.style.context("dark_background"):
123+
fig, ax = plt.subplots()
124+
ax.plot(*line_data)
125+
else:
126+
fig, ax = plt.subplots()
127+
ax.plot(*line_data)
114128
115-
task = hd.task()
116-
task.run(get_chart, state.chart_data)
117-
if task.result:
118-
hd.image(task.result, width=20)
129+
hd.image(get_chart_image(fig), width=20)
119130
120-
if hd.button("Update Chart").clicked:
121-
state.chart_data = ([1, 2, 3, 4], [5, 20, 8, 10])
122-
task.clear()
131+
def main():
132+
chart()
133+
134+
state = hd.state(count=0)
135+
if hd.button("Click Me").clicked:
136+
state.count += 1
137+
hd.text(state.count)
123138
```
124139
125-
In this example, we store the chart's line data in
126-
@component(state). When the `Update Chart` button is
127-
clicked, we update the chart data and clear the task. The
128-
task will then re-run with the new chart data, and an
129-
updated chart will be rendered.
140+
In this example, when the app first loads, `chart()` is
141+
called and its resulting virtual DOM is cached.
142+
143+
For demonstration, there's an unrelated click counter on
144+
the page. When we click the `Click Me` button, the app
145+
re-runs but the call to `chart()` does not re-run the
146+
`chart` function, and instead uses its cached virtual DOM.
147+
148+
Also, when the theme mode is switched between light and
149+
dark, the `chart` function's dependency on theme mode will
150+
be invalidated and the function will re-run, rendering the
151+
chart in the new theme mode.
130152
131153
"""
132154
)
133155

134-
p.heading("## Responding to Theme Mode")
156+
p.heading("## Dynamically Updating Charts")
135157

136158
docs_markdown(
137159
"""
138160
139-
By default, Matplotlib chart images are rendered on white
140-
background. There's currently no easy way to match the
141-
chart's color scheme to Hyperdiv's theme exactly, but
142-
Matplotlib provides a basic way to render a chart in dark
143-
or light mode. We can then sync the chart's theme mode to
144-
Hyperdiv's theme mode.
161+
We can re-create the chart on demand, with new data:
145162
146163
```py-nodemo
147-
def get_chart(data, is_dark):
148-
if is_dark:
164+
@hd.cached
165+
def chart(state):
166+
theme = hd.theme()
167+
168+
if theme.is_dark:
149169
with plt.style.context("dark_background"):
150170
fig, ax = plt.subplots()
151-
ax.plot(*data)
171+
ax.plot(*state.line_data)
152172
else:
153173
fig, ax = plt.subplots()
154-
ax.plot(*data)
174+
ax.plot(*state.line_data)
155175
156-
return get_chart_image(fig)
176+
hd.image(get_chart_image(fig), width=20)
157177
158178
def main():
159-
theme = hd.theme()
160-
task = hd.task()
161-
task.run(
162-
get_chart,
163-
([1, 2, 3, 4], [5, 20, 8, 10]),
164-
# Pass the current theme mode to the task:
165-
theme.is_dark
179+
state = hd.state(
180+
line_data=([1, 2, 3, 4], [10, 11, 12, 13])
166181
)
167182
168-
if task.result:
169-
hd.image(task.result, width=20)
183+
chart(state)
170184
171-
# When the Hyperdiv theme changes, re-render the chart
172-
# in the new theme mode:
173-
if theme.changed:
174-
task.clear()
185+
if hd.button("Update Chart").clicked:
186+
state.line_data = ([1, 2, 3, 4], [5, 20, 8, 10])
175187
```
176188
189+
In this example, we store the chart's line data in
190+
@component(state). When the `Update Chart` button is
191+
clicked, an updated chart will be rendered.
177192
"""
178193
)

0 commit comments

Comments
 (0)