Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sympy: generate figure with multiple subplots

I'm using sympy and matplotlib, and wish to generate a figure with multiple plots, similarly to how it's done using pylab.subplot when using numpy. This should be trivial, or so I thought...

To my surprise I didn't find a simple way to do it. Either (a) evaluate a SymPy expression at multiple points and get a numpy array which I can use with matplotlib or (b) use a mechanism similar to pylab.subplot in sympy.plotting.

Sample code:

import sympy.plotting.plot as symplot
import sympy as sym
x = sym.Symbol('x')
# This opens two different figures...
symplot(x*x, (x, -10, 10))
symplot(x, (x, -10, 10))

Any ideas?

like image 398
Uri Cohen Avatar asked Feb 17 '23 21:02

Uri Cohen


1 Answers

It depends on the version of SymPy that you are using.

In the latest version (0.7.2) you already have a plotting module that is guaranteed to be able to plot anything and that can use as a backend matplotlib.

In older versions you have the option to use lambdify which is a hackish, mostly broken helper function that returns a fast numerical function to be used with numpy. However it breaks for non-trivial expressions.

Below I explain how to use the plotting module in 0.7.2:

  1. Just call plot like in p = plot(expression, (var, start, stop)). If you have matplotlib it will use it directly.
  2. If you want something fancy, extract the matplotlib figure: f = p._backend.fig.
  3. Stop caring about SymPy, the rest of your work is in matplotlib. You can do whatever you want.

The idea behind SymPy's plotting module is to be able to evaluate any possible expression, not to reimplement a plotting library like matplotlib. So just use sympy.plotting.plot for evaluation and do the fancy subplot transformations in matplotlib.

Using the sympy plotting module has other advantages over hackish solutions: detection of discontinuities and adaptive sampling, coloring depending on a function, evaluation of pathologically complicated symbolic expressions (although slow).

And obviously, check the docs. While they are not great, many questions are answered there: http://docs.sympy.org/0.7.2/modules/plotting.html Check also the notebooks in the example folder of sympy.

EDIT to address some additional questions:

  1. There is no notion of subplots in the SymPy's plotting module, and hopefully there will never be one. As I mentioned above, SymPy is not trying to reimplement modules like matplotlib, rather it is trying to give the tools necessary for good easy use within another module (interfaces between modules are better than big project with many small submodules).

  2. In order to create one figure with two subplots in matplotlib from two different sympy plots do (this is an ugly hack, as matplotlib does not support merges of figures):

    sympy_p1 = sympy.plot(foo)
    sympy_p2 = sympy.plot(bar)
    matplotlib_fig = plt.figure()
    sp1 = matplotlib_fig.add_subplot(121)
    sp2 = matplotlib_fig.add_subplot(122)
    sp1.add_collection(sympy_p1._backend.ax.get_children()[appropriate_index])
    sp2.add_collection(sympy_p2._backend.ax.get_children()[appropriate_index])
    matplotlib_fig.show()
    
  3. In order to update sympy plot (not creation of a subplot, just adding a new expression) use sympy_p1.append(sympy_p2). This will result in sympy_p1 containing the plots of both foo and bar (NOT two subplots, rather one plot with both expressions).

  4. You might want to use sympy.plot(..., show=False) in some cases.

like image 123
Krastanov Avatar answered Feb 19 '23 09:02

Krastanov