3

円グラフを使用して統計をグラフ化するために複数の SVG イメージを作成する予定の Python Pyramid アプリケーションを開発しています。私のテストでは、1 つの SVG ビューが正しく機能し、2 番目の SVG 出力ビューを追加するとすぐに、2 番目の 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')

このコードの手順:

  1. http://localhost:6543/test.svg を読み込む
  2. http://localhost:6543/test2.svg を読み込む
  3. (1)または(2)のいずれかを再度ロードしてください。pserveコマンドウィンドウからの兆候なしに連続して「スピン」するのはなぜですか。

注:このコードで同じ SVG ビューを 3 回ロードすると、上記の手順と同じ結果になりますが、以下のコードでは発生しません。

また、pyplot パイにはリターンがあることに注意してください。ただし、それ自体は「ハンドル」ではありません。

  • pserve1分以上待っても(特に上記の手順を実行した後)、ウィンドウが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

再現するために取られた手順:

  1. ピラミッドアプリを保存します。

指示:pserve development.ini --reload

Starting server in PID 4912.
serving on http://0.0.0.0:6543
  1. http://localhost:6543/test.svg を読み込む

これは正しく機能することに注意してください

DEBUG [pyramidapp.views:22][Dummy-2] In test_svg_view

ステップ 2 の画像

  1. http://localhost:6543/test2.svg を読み込む

これにより、両方の SVG ファイルが「結合」されることに注意してください。

DEBUG [pyramidapp.views:45][Dummy-3] In test2_svg_view

ステップ 3 の画像

  1. http://localhost:6543/test.svg を読み込む

これは test2.svg とまったく同じように機能することに注意してください。タイトルも同じで、同じ長さであり、画像もこのビューで結合されます。

DEBUG [pyramidapp.views:22][Dummy-4] In test_svg_view

ステップ 4 の画像

  1. アプリケーションを再ホストし、 http://localhost:6543/test2.svgのみを読み込みます

今回は test.svg の前にこのビューがロードされたため、これは最初のロードで適切に機能することに注意してください。

DEBUG [pyramidapp.views:45][Dummy-2] In test2_svg_view

ステップ 5 の画像

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 画像がそのようなビューによって参照または利用されない限り、ロードなどのビューが適切に読み込まれることにも注意してください。

もう 1 つの重要な注意点は、SVG ファイルが 1 つだけ、つまりhttp://localhost:6543/test.svgが常にロードされているpserve限り、明らかな問題なしにイメージを (潜在的に) 無限に再ロード/更新できるように見えることです。または以下に遭遇:

_tkinter ヘッダー

_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 ベースの実装とバッチ処理で機能します。

4

2 に答える 2

3
于 2015-05-29T12:08:15.703 に答える
1

セルゲイが提供した答えは間違いなく役に立ちました。この例のステートメントを含む部分に基づいて、コードにさらにいくつかの部分を追加するとmatplotlib.use、メモリの問題が解決されるように見えることがわかりました。これは、テスト アプリケーション (上記の SVG ファイルを生成する 2 つのビュー) と、現在 3 つの SVG ビューを持つプライマリ アプリケーションの両方でテストしました。

私の主なアプリケーションでは、このコードの以前のバージョンで見つかったSVG 画像を結合することなく、3 つの既存のビューすべての間で複数回更新できます。この設定は、この問題を引き起こしている他の何かを見つけることができない限り、他のSOの質問がこの問題を反映していないように見える理由である可能性がある、より多くの同時使用に必要なようです。これが最良の答えかどうかはわかりません。ただし、これは今のところ正しく機能しているように見えます。他の問題が見つからないか監視する予定です。

@view_config(route_name='view_test_svg')
def test_svg_view(request):
    from matplotlib import use as matplotlib_use
    matplotlib_use("Svg")
    from matplotlib.pyplot import close, figure, axes, pie, title, savefig
    log.debug('In test_svg_view')
    fig = figure(1, figsize=(6,6))
    ax = fig.add_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()
    close('all')
    return Response(svg_dta, content_type='image/svg+xml')
于 2015-05-30T01:07:47.910 に答える