use tkinter for nltk draw inside of jupyter notebo

2019-08-27 23:16发布

问题:

I'm trying to draw graph (inline) of nltk inside of jupyter-notebook. But got error:

TclError: no display name and no $DISPLAY environment variable

I have tried to set $DISPLAY to different values:

$env DISPLAY=0.0
# or
$env DISPLAY=inline
# or
$env DISPLAY=

but got error (or similar):

TclError: couldn't connect to display "0.0"

here is my code https://github.com/hyzhak/nltk-experiments/blob/master/main.ipynb the last cell.

Environment: official anaconda3 docker -- continuumio/anaconda3:4.4.0 https://github.com/ContinuumIO/docker-images. With nltk==3.2.3 inside.

Python 3.6.1 |Anaconda 4.4.0 (64-bit)| (default, May 11 2017, 13:09:58) 
Type "copyright", "credits" or "license" for more information.

IPython 5.3.0 -- An enhanced Interactive Python.

How could I solve this error and inline nltk graph inside of jupyter notebook?

Update 1

http://www.nltk.org/_modules/nltk/draw/tree.html#draw_trees according to the sources of nltk tree draw it uses tkinter.

Update 2

I have asked the same question in official nltk github repository https://github.com/nltk/nltk/issues/1765

Update 3

I think the reason of error could be the headless host (docker). I have installed xvfb but seems it is note enough.

RUN apt-get install -y xvfb

Solution

I thought that xvfb is launched by default but It should be run explicitly. So after I have launched it I could make screenshots of nltk tree graph.

回答1:

import os
import nltk
from IPython.display import Image

chunkGram = r"""Chunk: {<RB.?>*<VB.?>*<NNP>+<NN>?}"""
chunkParser = nltk.RegexpParser(chunkGram)

tagged = [('Tonight', 'NN'), ('we', 'PRP'), ('are', 'VBP'), ('comforted', 'VBN'), ('by', 'IN'), ('the', 'DT'), ('hope', 'NN'), ('of', 'IN'), ('a', 'DT'), ('glad', 'JJ'), ('reunion', 'NN'), ('with', 'IN'), ('the', 'DT'), ('husband', 'NN'), ('who', 'WP'), ('was', 'VBD'), ('taken', 'VBN'), ('so', 'RB'), ('long', 'RB'), ('ago', 'RB'), (',', ','), ('and', 'CC'), ('we', 'PRP'), ('are', 'VBP'), ('grateful', 'JJ'), ('for', 'IN'), ('the', 'DT'), ('good', 'JJ'), ('life', 'NN'), ('of', 'IN'), ('Coretta', 'NNP'), ('Scott', 'NNP'), ('King', 'NNP'), ('.', '.')]
chunked = chunkParser.parse(tagged)
nltk.draw.tree.TreeView(chunked)._cframe.print_to_file('output.ps')
os.system('convert output.ps output.png')

Image(filename='output.png') 

[out]:



回答2:

Try incorporating the following snippet in your code

import os
import matplotlib as mpl
if os.environ.get('DISPLAY','') == '':
    print('no display found. Using non-interactive Agg backend')
    mpl.use('Agg')
import matplotlib.pyplot as plt

Regardless. Your problem is that Matplotlib's default call to an x-using backend is apparently causing a problem. This answer is by no means the only possible solution, but I think this will solve your problem. Remember that it is important to switch backend before importing pyplot.

Alternatively, you could try IPython.core.display.display(chunked)

Make sure that your notebook server is started with the -X flag set..

def jupyter_draw_nltk_tree(tree):
    from IPython.display import Image, display
    from nltk.draw import TreeWidget
    from nltk.draw.util import CanvasFrame
    import subprocess
    cf = CanvasFrame()
    tc = TreeWidget(cf.canvas(), tree)
    tc['node_font'] = 'arial 13 bold'
    tc['leaf_font'] = 'arial 14'
    tc['node_color'] = '#005990'
    tc['leaf_color'] = '#3F8F57'
    tc['line_color'] = '#175252'
    cf.add_widget(tc, 10, 10)
    cf.print_to_file('tmp_tree_output.ps')
    cf.destroy()

    args = (['convert', 'tmp_tree_output.ps', 'tmp_tree_output.png'])
    subprocess.call(args)
    display(Image(filename='tmp_tree_output.png'))
    os.system('rm tmp_tree_output.ps tmp_tree_output.png')

jupyter_draw_nltk_tree(chunked)