2

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.

Eugene Krevenets
  • 1,791
  • 2
  • 20
  • 35

2 Answers2

2
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]:

enter image description here

alvas
  • 115,346
  • 109
  • 446
  • 738
  • the same error because `nltk.draw.tree.TreeView` create `tkinter` instance `self._top = Tk()` (http://www.nltk.org/_modules/nltk/draw/tree.html#TreeView) – Eugene Krevenets Jul 04 '17 at 10:11
  • ok, interesting, did you run jupyter on your local host system or inside of docker or remote host? Could it be the problem of Anaconda docker? – Eugene Krevenets Jul 04 '17 at 22:35
  • I would think it is the conda docker. I ran jupyter on local. – alvas Jul 04 '17 at 23:13
  • Can you print any image on jupyter notebook inside the docker? If so, simply saving to post-script -> png and displaying an image would work. Otherwise, it's a bug downstream on conda docker's side – alvas Jul 04 '17 at 23:14
  • Nonono, not matplotlib, just simple image printing onto Jupyter console =). I.e. Does this work? `from IPython.display import Image; Image(filename='output.png') `. – alvas Jul 05 '17 at 07:49
  • 1
    yes, it works as well. I think problem with virtual display itself. I have `x11vnc` and `xvfb` to have virtual display there (docker doesn't have display it is completely virtual environment) but seems it is not enough. – Eugene Krevenets Jul 05 '17 at 08:24
  • ok, it was problem with `xvfb` I have forgot to launch it. Latter – Eugene Krevenets Jul 05 '17 at 10:28
0

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)
Uvar
  • 3,372
  • 12
  • 25
  • I've got the same error. As I understand `nltk` uses `tkinter` direct, and ignore `matplotlib`. Maybe there other way to draw graph of `nltk` without using inner (nltk) graph method? – Eugene Krevenets Jul 03 '17 at 08:34
  • http://www.nltk.org/_modules/nltk/draw/tree.html#draw_trees I've just taken a look in the sources of graph draw and found that really it doesn't use matplotlib for drawing graph. Very strange :( – Eugene Krevenets Jul 03 '17 at 08:39
  • second solution doesn't work as well because `CanvasFrame()` tries to create tkinter widget. Did you draw nltk tree graph inside of jupyter notebook? – Eugene Krevenets Jul 03 '17 at 13:52