Interactive Widgets
Currently, visualization in SageMath is mostly not interactive. However, there are approaches to build interactive widgets for the Jupyter notebook:
@interact creates configurable widgets.
ipyμvue can be used to write Jupyter widgets in Python that work with SageMath.
- matplotlib plots can be made interactive.
Example: Interactive matplotlib Plots
1 # Enable interactive matplotlib output in Jupyter.
2 %matplotlib nbagg
3
4 # Better, sage -pip install ipympl and then
5 # %matplotlib ipympl
6
7 class DynamicPlot(sage.plot.primitive.GraphicPrimitive):
8 r"""
9 A dynamic 2D plot that redraws when it is dragged around.
10
11 INPUT:
12
13 - ``create_plot`` -- a callable that creates a plot for given ``xmin``, ``ymin``, ``xmax``, ``ymax`` bounds.
14
15 - ``xmin``, ``ymin``, ``xmax``, ``ymax`` -- initial bounds of the 2D plot.
16
17 """
18 def __init__(self, create_plot, xmin=-1, xmax=1, ymin=-1, ymax=1, options={}):
19 self._create_plot = create_plot
20
21 self._xmin = xmin
22 self._xmax = xmax
23 self._ymin = ymin
24 self._ymax = ymax
25
26 super().__init__(options)
27
28 def _render_on_subplot(self, subplot):
29 def redraw(_=None):
30 try:
31 # Clear the subplot before redrawing. Otherwise, we would pile up lots
32 # of identical plots that take more and more time to draw.
33 # Note that this will also clear other primitives from this subplot.
34 subplot._children = []
35
36 xlim = subplot.axes.get_xlim()
37 ylim = subplot.axes.get_ylim()
38
39 import sage.misc.verbose
40 verbose = sage.misc.verbose.get_verbose()
41 # Silence warnings about undefined values in the plotted function.
42 sage.misc.verbose.set_verbose(-1)
43 try:
44 # Plot all the objects produced by create_plot().
45 for object in self._create_plot(xmin=xlim[0], xmax=xlim[1], ymin=ylim[0], ymax=ylim[1])._objects:
46 object._render_on_subplot(subplot)
47 finally:
48 sage.misc.verbose.set_verbose(verbose)
49 except Exception:
50 # Unfortunately, there is no easy way to display an error message in a matplotlib callback.
51 # Errors are shown in the terminal where Jupyter was started.
52 subplot.clear()
53 raise
54
55 # Redraw when the plot is dragged around.
56 subplot.axes.callbacks.connect("ylim_changed", redraw)
57 subplot.axes.callbacks.connect("xlim_changed", redraw)
58
59 # Draw the plot in the initial bounds.
60 redraw()
61
62 def get_minmax_data(self):
63 r"""
64 Return the initial bounds of this plot to focus the camera here.
65 """
66 return dict(xmin=self._xmin, ymin=self._ymin, xmax=self._xmax, ymax=self._ymax)
67
68 def show(self):
69 r"""
70 Create a matplotlib figure and show this plot.
71 """
72 g = Graphics()
73 g.add_primitive(self)
74
75 import matplotlib.pyplot as plt
76 figure = plt.figure()
77 g.matplotlib(figure=figure)
1 # We plot a parabola
2 def create_plot(*, xmin, ymin, xmax, ymax):
3 return plot(x^2, alpha=.5, xmin=xmin, ymin=ymin, xmax=xmax, ymax=ymax,
4 # Adaptive recursion slows down the plotting when we zoom out a lot, so we disable
5 # it for this simple function.
6 adaptive_recursion=0)
7
8 DynamicPlot(create_plot).show()