@@ -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