今回も機械学習関連の記事である。
nltk.TreeのデータをPNG画像として出力したかったのですが、Docker環境で開発を行なっていた関係でちょっと手こずってしまった。
Docker環境でPNGを出力させる方法がなかなか見つからなかったので、記事としてまとめておく。
結論としては、以下のstackoverflowの回答でうまくいった。
stackoverflow.com
よくみる回答
nltk.TreeをPNG画像として出力する方法は、以下の解答がよく見つかる。
stackoverflow.com
コードとしては以下の通り。
from nltk.tree import Tree from nltk.draw.tree import TreeView import os t = Tree.fromstring('(S (NP this tree) (VP (V is) (AdjP pretty)))') TreeView(t)._cframe.print_to_file('output.ps') os.system('convert output.ps output.png')
発生したエラー
上記のコードを実際に試すと、以下のエラーが発生した。
TclErrorTraceback (most recent call last) Input In [2], in <cell line: 6>() 3 import os 5 t = Tree.fromstring('(S (NP this tree) (VP (V is) (AdjP pretty)))') ----> 6 TreeView(t)._cframe.print_to_file('output.ps') File /opt/conda/lib/python3.9/site-packages/nltk/draw/tree.py:859, in TreeView.__init__(self, *trees) 855 from math import ceil, sqrt 857 self._trees = trees --> 859 self._top = Tk() 860 self._top.title("NLTK") 861 self._top.bind("<Control-x>", self.destroy) File /opt/conda/lib/python3.9/tkinter/__init__.py:2270, in Tk.__init__(self, screenName, baseName, className, useTk, sync, use) 2268 baseName = baseName + ext 2269 interactive = False -> 2270 self.tk = _tkinter.create(screenName, baseName, className, interactive, wantobjects, useTk, sync, use) 2271 if useTk: 2272 self._loadtk() TclError: no display name and no $DISPLAY environment variable
エラーの原因
このエラーの原因としては、PNG画像生成に使っているtkinterライブラリに起因する。
このライブラリは(詳しくはわかってないが)canvasを生成する際にXWindowをコールする。
今回はDocker上にanaconda環境を用意したため、もちろんX11が入っていない。そのため上記エラーが発生した。
解決方法
記事冒頭で紹介した通り、svglingとcairosvgを利用することで解決できる。
stackoverflow.com
必要なライブラリは、pip3でインストールできる。
pip3 install svgling cairosvg
matplotlibを用いた解決方法もあるらしい。自分はmatplotlibがそもそもインストールされていなかった目、試していないが紹介しておく。
python - _tkinter.TclError: no display name and no $DISPLAY environment variable - Stack Overflow
余談:pngの背景を白に変更する方法
stackoverflowの回答通りにpng画像を生成すると、背景が透過された画像が生成される。
背景を白にしたい場合は、以下の様にbackground_colorオプションを指定すれば良い。
t = Tree.fromstring('(S (NP this tree) (VP (V is) (AdjP pretty)))') # convert tree to svg sv = tree2svg(t) # write the svg as an image cairosvg.svg2png(sv.tostring(), write_to="image.png", background_color="white")