我正在开发一个 Python Pyramid 应用程序,我打算在其中创建多个 SVG 图像来使用饼图绘制统计数据。在我的测试中,我发现一个 SVG 视图可以正常工作,并且只要我添加第二个 SVG 输出视图,并且加载第二个 SVG 图像(SVG 图像加载的顺序无关紧要),无论是直接通过其视图还是通过引用此视图的另一个视图,SVG 图像在任何其他进一步调用中“组合”以加载 SVG 文件。这似乎是 Python 堆栈中的一个错误,因为它似乎没有正确清除内存(主要是在多个 SVG 文件的情况下,请参阅下面的更多详细信息)。下面还要注意,在加载足够多的图像/页面后会遇到 TclError。
由于我在具有更多视图的更详细的应用程序中使用 SVG,因此我在最小化/简化的应用程序中复制它以表明它不是我正在做的额外事情,并且此代码是直接从 Pyramid alchemy模板和数据库生成的不涉及通话。该数据库在我的更多详细信息应用程序中得到了积极利用。此应用程序只有 3 个视图,其中第一个视图是原始模板的一部分。我还添加了 DEBUG 日志记录,以明确没有迹象表明存在对其他 SVG 视图的任何内部调用。
一些视图代码基于Matplotlib svg 作为字符串,而不是主要用于StringIO
. 请注意,由于需要饼图,这就是我的代码与引用问题中的代码不同的主要原因。我发现无论我使用StringIO
还是cStringIO
. 在我的代码中,我正在使用cStringIO
.
完整的应用程序代码位于:https ://github.com/danielpronych/pyramidapp
PyPlot 文档:: pyplot api
更新:来自第一个 SVG 视图的代码(图形句柄和关闭命令):
@view_config(route_name='view_test_svg')
def test_svg_view(request):
# Full module import is not allowed by Pyramid
#from pylab import *
# Do individual required imports instead
from pylab import close, figure, axes, pie, title, savefig
# For clarity, note that the above, and below, function the same
#from matplotlib.pyplot import close, figure, axes, pie, title, savefig
log.debug('In test_svg_view')
fig = figure(1, figsize=(6,6))
ax = axes([0.1, 0.1, 0.8, 0.8])
labels = ['Frogs', 'Hogs', 'Dogs', 'Logs']
fracs = [15, 30, 45, 10]
explode=(0, 0.05, 0, 0)
pie(fracs, explode=explode, labels=labels,
autopct='%1.1f%%', shadow=True, startangle=90)
title('Raining Hogs and Dogs', bbox={'facecolor':'0.8', 'pad':5})
imgdata = cStringIO.StringIO()
fig.savefig(imgdata, format='svg')
imgdata.seek(0)
svg_dta = imgdata.getvalue()
# Close the StringIO buffer
imgdata.close()
close('all')
return Response(svg_dta, content_type='image/svg+xml')
此代码的步骤:
- 加载http://localhost:6543/test.svg
- 加载http://localhost:6543/test2.svg
- 再次加载 (1) 或 (2)。将
pserve
在命令窗口中没有任何迹象的情况下连续“旋转”为什么。
注意:使用此代码加载相同的 SVG 视图 3 次也具有与上述步骤相同的结果,而下面的代码不会发生。
另请注意,pyplot pie确实有回报;然而,它本身并不是一个“手柄”。
pserve
即使等待超过一分钟(特别是在执行上述步骤之后),窗口也不响应 Control+C 命令。
来自第一个 SVG 视图的代码(原始,以下步骤来自此代码):
@view_config(route_name='view_test_svg')
def test_svg_view(request):
# Full module import is not allowed by Pyramid
#from pylab import *
# Do individual required imports instead
from pylab import figure, axes, pie, title, savefig
# For clarity, note that the above, and below, function the same
#from matplotlib.pyplot import figure, axes, pie, title, savefig
log.debug('In test_svg_view')
figure(1, figsize=(6,6))
ax = axes([0.1, 0.1, 0.8, 0.8])
labels = ['Frogs', 'Hogs', 'Dogs', 'Logs']
fracs = [15, 30, 45, 10]
explode=(0, 0.05, 0, 0)
pie(fracs, explode=explode, labels=labels,
autopct='%1.1f%%', shadow=True, startangle=90)
title('Raining Hogs and Dogs', bbox={'facecolor':'0.8', 'pad':5})
imgdata = cStringIO.StringIO()
savefig(imgdata, format='svg')
imgdata.seek(0)
svg_dta = imgdata.getvalue()
# Close the StringIO buffer
imgdata.close()
return Response(svg_dta, content_type='image/svg+xml')
Python 版本: Python 2.7.5
Python 包配置(仅限主包)
- 金字塔-1.6a1-py2.7
- matplotlib-1.4.3-py2.7-win32
重现步骤:
- 保护金字塔应用程序。
命令:pserve development.ini --reload
Starting server in PID 4912.
serving on http://0.0.0.0:6543
请注意,这可以正常工作
DEBUG [pyramidapp.views:22][Dummy-2] In test_svg_view
请注意,这会将两个 SVG 文件“组合”在一起
DEBUG [pyramidapp.views:45][Dummy-3] In test2_svg_view
请注意,这与 test2.svg 完全相同,具有正确的标题,因为它们的长度也相似,现在图像也在此视图中合并
DEBUG [pyramidapp.views:22][Dummy-4] In test_svg_view
- 重新托管应用程序并仅加载http://localhost:6543/test2.svg
请注意,这适用于首次加载,因为此视图是在 test.svg 这次之前加载的
DEBUG [pyramidapp.views:45][Dummy-2] In test2_svg_view
使用 Control+C 终止 pserve 进程时的跟踪日志
Error in sys.exitfunc:
Traceback (most recent call last):
File "--python_path--\lib\atexit.py", line 24, in _run_exitfuncs
func(*targs, **kargs)
File "--python_path--\lib\site-packages\matplotlib-1.4.3-py2.7-win32.egg\ma
tplotlib\_pylab_helpers.py", line 89, in destroy_all
manager.destroy()
File "--python_path--\lib\site-packages\matplotlib-1.4.3-py2.7-win32.egg\ma
tplotlib\backends\backend_tkagg.py", line 588, in destroy
self.window.destroy()
File "--python_path--\lib\lib-tk\Tkinter.py", line 1789, in destroy
for c in self.children.values(): c.destroy()
File "--python_path--\lib\lib-tk\Tkinter.py", line 2042, in destroy
self.tk.call('destroy', self._w)
_tkinter.TclError: out of stack space (infinite loop?)
^C caught in monitor process
重要提示:加载足够多的 SVG 图像后,会遇到以下情况:
目前解决此问题的唯一方法是重新启动pserve
。还要注意,my_view
只要 SVG 图像未被此类视图引用或使用,视图(例如加载)就可以正确加载。
另一个重要的注意事项,只要只加载一个 SVG 文件,即http://localhost:6543/test.svg,整个时间pserve
似乎可以无限次重新加载/刷新图像而没有任何明显的问题,或遇到以下情况:
_tkinter.TclError
TclError: out of stack space (infinite loop?)
Traceback (most recent call last)
File "--python_path--\lib\site-packages\pyramid_debugtoolbar-2.0.2-py2.7.egg\pyramid_debugtoolbar\panels
\performance.py", line 69, in noresource_timer_handler
Display the sourcecode for this frameOpen an interactive python shell in this frameresult = handler(request)
File "--python_path--\lib\site-packages\pyramid-1.6a1-py2.7.egg\pyramid\tweens.py", line 20, in excview_tween
Display the sourcecode for this frameOpen an interactive python shell in this frameresponse = handler(request)
File "--python_path--\lib\site-packages\pyramid_tm-0.11-py2.7.egg\pyramid_tm\__init__.py", line 94, in tm_tween
Display the sourcecode for this frameOpen an interactive python shell in this framereraise(*exc_info)
File "--python_path--\lib\site-packages\pyramid_tm-0.11-py2.7.egg\pyramid_tm\__init__.py", line 75, in tm_tween
Display the sourcecode for this frameOpen an interactive python shell in this frameresponse = handler(request)
File "--python_path--\lib\site-packages\pyramid-1.6a1-py2.7.egg\pyramid\router.py", line 145, in handle_request
Display the sourcecode for this frameOpen an interactive python shell in this frameview_name
File "--python_path--\lib\site-packages\pyramid-1.6a1-py2.7.egg\pyramid\view.py", line 527, in _call_view
Display the sourcecode for this frameOpen an interactive python shell in this frameresponse = view_callable
(context, request)
File "--python_path--\lib\site-packages\pyramid-1.6a1-py2.7.egg\pyramid\config\views.py", line 384, in
viewresult_to_response
Display the sourcecode for this frameOpen an interactive python shell in this frameresult = view(context,
request)
File "--python_path--\lib\site-packages\pyramid-1.6a1-py2.7.egg\pyramid\config\views.py", line 506, in
_requestonly_view
Display the sourcecode for this frameOpen an interactive python shell in this frameresponse = view(request)
File "c:\projects\python\pyramid\pyramidapp\pyramidapp\views.py", line 55, in test2_svg_view
Display the sourcecode for this frameOpen an interactive python shell in this framesavefig(imgdata,
format='svg')
File "--python_path--\lib\site-packages\matplotlib-1.4.3-py2.7-win32.egg\matplotlib\pyplot.py", line 578, in
savefig
Display the sourcecode for this frameOpen an interactive python shell in this framedraw() # need this if
'transparent=True' to reset colors
File "--python_path--\lib\site-packages\matplotlib-1.4.3-py2.7-win32.egg\matplotlib\pyplot.py", line 571, in
draw
Display the sourcecode for this frameOpen an interactive python shell in this frameget_current_fig_manager
().canvas.draw()
File "--python_path--\lib\site-packages\matplotlib-1.4.3-py2.7-win32.egg\matplotlib\backends\backend_tkagg.py",
line 350, in draw
Display the sourcecode for this frameOpen an interactive python shell in this frametkagg.blit(self._tkphoto,
self.renderer._renderer, colormode=2)
File "--python_path--\lib\site-packages\matplotlib-1.4.3-py2.7-win32.egg\matplotlib\backends\tkagg.py", line
24, in blit
Display the sourcecode for this frameOpen an interactive python shell in this frametk.call("PyAggImagePhoto",
photoimage, id(aggimage), colormode, id(bbox_array))
TclError: out of stack space (infinite loop?)
更新(2015 年 9 月):我希望看到 Sergey 的进一步更新,因为他建议的解决方案一开始似乎确实有所帮助;但是,他的解决方案并没有解决这个问题,因为即使我等待了相当长的时间也没有发生任何事情,我发现只有我的解决方案才能真正解决这个问题。最后,需要明确的是,我的解决方案适用于基于 Web 的实现和批处理,因为这个问题也出现在批处理中。