Differences between revisions 2 and 4 (spanning 2 versions)
Revision 2 as of 2022-08-12 10:04:12
Size: 4020
Editor: saraedum
Comment: Fix layout
Revision 4 as of 2022-08-23 18:33:47
Size: 4085
Editor: saraedum
Comment: Fix typo
Deletions are marked like this. Additions are marked like this.
Line 13: Line 13:
%matplotlib notebook %matplotlib nbagg

# Better, sage -pip install ipympl and then
# %matplotlib ipympl
Line 64: Line 67:
        subplot.axes.callbaacks.connect("ylim_changed", redraw)         subplot.axes.callbacks.connect("ylim_changed", redraw)

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 an infinite ray from the origin.
   2 def create_plot(*, xmin, ymin, xmax, ymax):
   3     def ray(x):
   4         if x > 0:
   5             return x + sin(x)
   6 
   7     return plot(ray, alpha=.5, xmin=xmin, ymin=ymin, xmax=xmax, ymax=ymax)
   8 
   9 DynamicPlot(create_plot).show()

   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()

interactive (last edited 2022-08-23 18:33:47 by saraedum)