Sympy:生成包含多个子图的图

时间:2013-04-05 11:48:49

标签: python numpy matplotlib sympy

我正在使用sympy和matplotlib,并希望生成一个包含多个图的图形,类似于使用numpy时使​​用pylab.subplot完成的图形。这应该是微不足道的,或者我认为......

令我惊讶的是,我没有找到一个简单的方法来做到这一点。 (a)在多个点评估SymPy表达式并得到一个numpy数组,我可以使用matplotlib或(b)在sympy.plotting中使用类似于pylab.subplot的机制。

示例代码:

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

有什么想法吗?

3 个答案:

答案 0 :(得分:6)

这取决于您使用的SymPy版本。

在最新版本(0.7.2)中,您已经有一个绘图模块,可以保证能够绘制任何,并且可以用作后端matplotlib。

在旧版本中,您可以选择使用lambdify这是一个hackish,多数是破坏的帮助函数,它返回一个快速数值函数以与numpy一起使用。然而,它打破了非平凡的表达。

下面我将解释如何使用0.7.2中的绘图模块:

  1. 只需在plot中拨打p = plot(expression, (var, start, stop))即可。如果你有matplotlib,它会直接使用它。
  2. 如果您想要一些花哨的东西,请提取matplotlib数字:f = p._backend.fig
  3. 停止关心SymPy,你的其余工作都在matplotlib。你可以做任何你想做的事。
  4. SymPy绘图模块背后的想法是能够评估任何可能的表达式,而不是重新实现像matplotlib这样的绘图库。所以只需使用sympy.plotting.plot进行评估,并在matplotlib中进行精美的子图变换。

    使用sympy绘图模块比hackish解决方案还有其他优势:检测不连续性和自适应采样,根据功能着色,评估病态复杂的符号表达式(虽然速度慢)。

    显然,检查文档。虽然它们不是很好,但很多问题都在那里得到解答:http://docs.sympy.org/0.7.2/modules/plotting.html还要查看sympy示例文件夹中的笔记本。

    编辑以解决其他一些问题:

    1. SymPy的绘图模块中没有子图的概念,希望永远不会有一个。正如我上面提到的,SymPy并没有尝试重新实现像matplotlib这样的模块,而是试图提供在另一个模块中易于使用所需的工具(模块之间的接口比具有许多小子模块的大项目更好)。

    2. 为了在matplotlib中创建一个带有两个不同情节图的子图(这是一个丑陋的黑客,因为matplotlib不支持图的合并):

      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. 为了更新sympy情节(不创建子情节,只添加新表达式),请使用sympy_p1.append(sympy_p2)。这将导致sympy_p1包含foobar两个子图,而是包含两个表达式的一个图)的图。

      < / LI>
    4. 在某些情况下,您可能希望使用sympy.plot(..., show=False)

答案 1 :(得分:1)

对于第一个问题,您可以使用lambdify()将表达式转换为函数:

import numpy as np
from sympy import *

x, y = symbols("x, y")
eq = sqrt(x**2 + y**2)

xa = np.random.rand(10)
ya = np.random.rand(10)
f = lambdify((x, y),eq,'numpy')

print f(xa, ya)
print np.sqrt(xa**2 + ya**2)

答案 2 :(得分:0)

第二部分的答案可能是使用PlotGrid类:

>>> p1 = plot(x*x, (x, -10, 10), show=False)
>>> p2 = plot(x, (x, -10, 10), show=False)   
>>> PlotGrid(2, 1 , p1, p2)     # grid size or subplot size: 2x1
PlotGrid object containing:
Plot[0]:Plot object containing:
[0]: cartesian line: x*x for x over (x, -10, 10)
Plot[1]:Plot object containing:
[0]: cartesian line: x for x over (x, -10, 10)

此功能不是最新版本的一部分,但可能会在下一版SymPy中使用。您可以在当前development version的SymPy中找到它。