4

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

令我惊讶的是,我没有找到一个简单的方法来做到这一点。要么(a)在多个点评估 SymPy 表达式并获得一个我可以与 matplotlib 一起使用的 numpy 数组,要么(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))

有任何想法吗?

4

3 回答 3

6

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

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

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

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

  1. plot就像 in一样打电话p = plot(expression, (var, start, stop))。如果你有matplotlib它会直接使用它。
  2. 如果您想要一些花哨的东西,请提取matplotlib图形:f = p._backend.fig.
  3. 别再关心 SymPy,你剩下的工作都在matplotlib. 你想做什么,就可以做什么。

SymPy 的绘图模块背后的想法是能够评估任何可能的表达式,而不是重新实现像 matplotlib 这样的绘图库。所以只需sympy.plotting.plot用于评估并在 matplotlib 中进行花哨的子图转换。

与 hackish 解决方案相比,使用 sympy 绘图模块具有其他优势:检测不连续性和自适应采样、根据函数着色、评估病理上复杂的符号表达式(尽管速度很慢)。

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

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

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

  2. 为了在 matplotlib 中从两个不同的 sympy 图创建一个带有两个子图的图形(这是一个丑陋的 hack,因为 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不是两个子图,而是一个具有两个表达式的图)的图。

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

于 2013-04-05T13:05:46.277 回答
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)
于 2013-04-05T12:14:30.700 回答
1

第二部分的答案可能是使用 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 的下一个版本中提供。您可以在SymPy的当前开发版本中找到它。

于 2019-07-30T08:37:12.857 回答