我使用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字符串。有人知道如何解决这个任务吗?
1条答案
按热度按时间k4emjkb11#
我就是那个模块的开发者。
该错误是由以下事实引起的:当您使用
MatplotlibBackend
和show=False
创建绘图时,未创建图形(太长,无法解释原因);此行为特定于MatplotlibBackend
,其他后端不应受其影响。因此,p1.fig
是None
。然而,绘图函数公开了
save
方法,它只不过是一个特定绘图库“保存”功能的 Package 器。如果查看源代码,您会发现MatplotlibBackend.save
调用matplotlib的savefig
,但首先它会检查图形是否已经创建。如果没有,它会强制创建。所以你要做的就是:
最后要注意的是,如果可能的话,不要使用以
_
(下划线)开头的属性或方法。它们代表私有属性,名称可能会随版本的不同而改变。如果你真的需要检索matplotlib图,请使用p1.fig
。EDIT回答评论中关于性能的问题:
由于向后兼容的原因,新模块默认使用adaptive algorithm进行线图,这与SymPy上使用的adaptive algorithm不同。一方面,它可以轻松地应用于更广泛的应用程序集,另一方面,它的速度较慢。
您有两个选项:无论哪种方式,您都可能希望更改模块的配置文件。
选项1:自适应算法最小化某个损失函数(
loss_fn
),并在达到阈值(adaptive_goal
)时停止。我们可以增加此阈值(默认设置为0.01),从而提高性能,但牺牲了线条的平滑质量。选项2:不要使用自适应算法,切换到使用Numpy和矢量化的均匀网格算法(通常使用
adaptive=False
完成,并可能设置适当数量的离散点n=something
)!与自适应算法相比,这是非常非常快的。想一想:通常,我们的绘图与屏幕尺寸相比相对较小。每行1000个点(或您决定使用的任何数量)应创建足够平滑的线条。
因此,您可以逐个图形地禁用自适应算法(使用
adaptive=False
),或者您可以将模块设置为始终使用统一网格算法(这是我在我的机器上使用的设置)。然后,当您创建一个绘图时,如果您觉得它应该更平滑,只需通过设置
n=something
(默认值为1000)来增加离散化点的数量。您可以在this documentation page上找到更多自定义选项。