matplotlib 如何在sympy绘图后端库中以svg字符串形式获取绘图?

plupiseo  于 2022-11-30  发布在  其他
关注(0)|答案(1)|浏览(239)

我使用sympy plotting backends library直接从sympy表达式创建绘图。我选择这个库是因为它提供了比标准sympy绘图模块更多的绘图微调选项。作为选择库的后端,我使用matplotlib。
我的目标是将结果图作为svg字符串,以便稍后将其插入到网页中。我需要通过编程来完成。我使用以下代码:

from spb import plot, MB
import io
from sympy import symbols, sin, cos

x = symbols("x")

# create plot
p1 = plot(
    (sin(x), "a", dict(color="k", linestyle=":")),
    (cos(x), "b"),
    backend=MB, show=False)

# buffer:
f = io.StringIO()

# save plot in buffer as svg string:
p1._fig.savefig(f, format = "svg")

# return result as svg string to insert it in web page later:
return f.getvalue()

问题是我得到了一个异常:

'NoneType' object has no attribute 'savefig'
 p1._fig.savefig(f, format = "svg")

但是如果我稍微修改一下代码:

...
# buffer:
f = io.StringIO()

# show plot:
p1.show()

# save plot in buffer as svg string:
p1._fig.savefig(f, format = "svg")
...

一切都很好。但问题是,我不想显示情节,我需要保存为svg字符串。有人知道如何解决这个任务吗?

k4emjkb1

k4emjkb11#

我就是那个模块的开发者。
该错误是由以下事实引起的:当您使用MatplotlibBackendshow=False创建绘图时,未创建图形(太长,无法解释原因);此行为特定于MatplotlibBackend,其他后端不应受其影响。因此,p1.figNone
然而,绘图函数公开了save方法,它只不过是一个特定绘图库“保存”功能的 Package 器。如果查看源代码,您会发现MatplotlibBackend.save调用matplotlib的savefig,但首先它会检查图形是否已经创建。如果没有,它会强制创建。
所以你要做的就是:

p1.save(f, format = "svg")

最后要注意的是,如果可能的话,不要使用以_(下划线)开头的属性或方法。它们代表私有属性,名称可能会随版本的不同而改变。如果你真的需要检索matplotlib图,请使用p1.fig

EDIT回答评论中关于性能的问题:

由于向后兼容的原因,新模块默认使用adaptive algorithm进行线图,这与SymPy上使用的adaptive algorithm不同。一方面,它可以轻松地应用于更广泛的应用程序集,另一方面,它的速度较慢。
您有两个选项:无论哪种方式,您都可能希望更改模块的配置文件。

选项1:自适应算法最小化某个损失函数(loss_fn),并在达到阈值(adaptive_goal)时停止。我们可以增加此阈值(默认设置为0.01),从而提高性能,但牺牲了线条的平滑质量。

from spb.defaults import cfg, set_defaults

# it requires a few tries to find an appropriate value
cfg["adaptive"]["goal"] = 0.02
set_defaults(cfg)

# restart the kernel to load the new configuration

选项2:不要使用自适应算法,切换到使用Numpy和矢量化的均匀网格算法(通常使用adaptive=False完成,并可能设置适当数量的离散点n=something)!与自适应算法相比,这是非常非常快的。

想一想:通常,我们的绘图与屏幕尺寸相比相对较小。每行1000个点(或您决定使用的任何数量)应创建足够平滑的线条。
因此,您可以逐个图形地禁用自适应算法(使用adaptive=False),或者您可以将模块设置为始终使用统一网格算法(这是我在我的机器上使用的设置)。

from spb.defaults import cfg, set_defaults

# disable adaptive algorithm
cfg["adaptive"]["used_by_default"] = False
set_defaults(cfg)

# restart the kernel to load the new configuration

然后,当您创建一个绘图时,如果您觉得它应该更平滑,只需通过设置n=something(默认值为1000)来增加离散化点的数量。
您可以在this documentation page上找到更多自定义选项。

相关问题