Repository: nltk/nltk

Issue:
GhostScript error when displaying inline Tree structure for Jupyter notebook
I just reinstalled my system including Jupyter notebook and nltk, and found out that the inline display of tree as png file which used to work like a charm is now broken.

First, relevant installation info
nltk (3.2.1)
jupyter (1.0.0)
jupyter-client (4.2.2)
jupyter-console (4.1.1)
jupyter-core (4.1.0)

Also
GPL Ghostscript 9.18 (2015-10-05)

I experimented on both python3.5 and python2.7, but this shouldn't be relevant.

The error message is as follows

```
---------------------------------------------------------------------------
IOError                                   Traceback (most recent call last)
/home/nykh/Documents/cs224u/program/local/lib/python2.7/site-packages/IPython/core/formatters.pyc in __call__(self, obj)
    341             method = _safe_get_formatter_method(obj, self.print_method)
    342             if method is not None:
--> 343                 return method()
    344             return None
    345         else:

/home/nykh/Documents/cs224u/program/local/lib/python2.7/site-packages/nltk/tree.pyc in _repr_png_(self)
    727                             '-q -dEPSCrop -sDEVICE=png16m -r90 -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -dSAFER -dBATCH -dNOPAUSE -sOutputFile={0:} {1:}'
    728                             .format(out_path, in_path).split())
--> 729             with open(out_path, 'rb') as sr:
    730                 res = sr.read()
    731             os.remove(in_path)

IOError: [Errno 2] No such file or directory: u'/tmp/tmppncGPb.png'
```

Apparently, the temp png file is not emitted by GhostScript, which complains

```
Error: /undefinedresult in --stringwidth--
Operand stack:
   --nostringval--   0   12   67   0   0   (test)
Execution stack:
   %interp_exit   .runexec2   --nostringval--   --nostringval--   --nostringval--   2   %stopped_push   --nostringval--   --nostringval--   --nostringval--   false   1   %stopped_push   1977   1   3   %oparray_pop   1976   1   3   %oparray_pop   --nostringval--   1960   1   3   %oparray_pop   1852   1   3   %oparray_pop   --nostringval--   %errorexec_pop   .runexec2   --nostringval--   --nostringval--   --nostringval--   2   %stopped_push   --nostringval--   --nostringval--   --nostringval--   --nostringval--   %array_continue   --nostringval--   --nostringval--   --nostringval--   %array_continue   --nostringval--
Dictionary stack:
   --dict:1201/1684(ro)(G)--   --dict:0/20(G)--   --dict:83/200(L)--   --dict:23/50(L)--
Current allocation mode is local
Current file position is 7312
GPL Ghostscript 9.18: Unrecoverable error, exit code 1
```

I wonder whether it's the way that `_repr_png` calls GS that causes the GhostScript error

``` python
subprocess.call([find_binary('gs', binary_names=['gswin32c.exe', 'gswin64c.exe'], env_vars=['PATH'], verbose=False)] +
                            '-q -dEPSCrop -sDEVICE=png16m -r90 -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -dSAFER -dBATCH -dNOPAUSE -sOutputFile={0:} {1:}'
                            .format(out_path, in_path).split())
```



Discussion:
Hi @alvations
It can be reproduced as below
(in ipython notebook)

import nltk

nltk.tree.Tree.fromstring("(test (this tree))")


So GhostScript is updated! Interesting...

On Mon, May 2, 2016 at 7:48 PM, alvations notifications@github.com wrote:

> Seems like the latest version of GPL Ghostscript causes the conversion
> from .ps -> .png to fail.
> 
> —
> You are receiving this because you were mentioned.
> Reply to this email directly or view it on GitHub
> https://github.com/nltk/nltk/issues/1387#issuecomment-216423409

I just checked on converting a `.ps -> .png` with Ghostscript 9.18. It works with:

``` bash
$ wget www.d.umn.edu/~tpederse/Pubs/cicling2003-3.ps
$ gs -q -dEPSCrop -sDEVICE=png16m -r90 -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -dSAFER -dBATCH -dNOPAUSE -sOutputFile=output.png cicling2003-3.ps
```

I think the problem might be deeper in with the latest version of `Tkinter`. All the [previously working examples](http://stackoverflow.com/questions/23429117/saving-nltk-drawn-parse-tree-to-image-file) are failing when saving into `.ps` files. They do show fine on the canvas editor though.

Interesting, I confirm I can generate output.png on my system... So maybe
the problem is with how the .ps is generated?? oh no :(

On Mon, May 2, 2016 at 8:25 PM, alvations notifications@github.com wrote:

> I just checked on converting a .ps -> .png with Ghostscript 9.18. It
> works with:
> 
> $ wget www.d.umn.edu/~tpederse/Pubs/cicling2003-3.ps
> $ gs -q -dEPSCrop -sDEVICE=png16m -r90 -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -dSAFER -dBATCH -dNOPAUSE -sOutputFile=output.png cicling2003-3.ps
> 
> I think the problem might be deeper in with the latest version of Tkinter.
> 
> —
> You are receiving this because you were mentioned.
> Reply to this email directly or view it on GitHub
> https://github.com/nltk/nltk/issues/1387#issuecomment-216426691

Hi there,

I see that this issue has been open since May of last year. Has there been any progress since?

By the way, I confirm that the issue is in generating the `ps` file from the tree object.

Thanks,
Kris

Resolving patch:
diff --git a/nltk/draw/util.py b/nltk/draw/util.py
--- a/nltk/draw/util.py
+++ b/nltk/draw/util.py
@@ -1712,11 +1712,15 @@ def print_to_file(self, filename=None):
                                          defaultextension='.ps')
             if not filename: return
         (x0, y0, w, h) = self.scrollregion()
-        self._canvas.postscript(file=filename, x=x0, y=y0,
+        postscript = self._canvas.postscript(x=x0, y=y0,
                                 width=w+2, height=h+2,
                                 pagewidth=w+2, # points = 1/72 inch
                                 pageheight=h+2, # points = 1/72 inch
                                 pagex=0, pagey=0)
+        # workaround for bug in Tk font handling
+        postscript = postscript.replace(' 0 scalefont ', ' 9 scalefont ')
+        with open(filename, 'w') as f:
+            f.write(postscript.encode('utf8'))
 
     def scrollregion(self):
         """


Test patch: