Skip to content

Fail to open images in external viewer programs if running PyGMT in a Python script #1061

Closed
@seisman

Description

@seisman

Description of the problem

Here is a simple Python script to reproduce the issue.

import pygmt

fig = pygmt.Figure()
fig.basemap(region=[0, 10, 0, 10], projection="X10c/10c", frame="+tFigure1")
print("Openning Figure1")
fig.show(method="external")

When I run the codes in a Python/IPython interpreter, it works well and can open the preview image. However, if I save it in a Python script and run it using python test.py, sometimes it can open the image but sometimes it fails and gives an error like (I'm using macOS):

image

The reason is simple, on macOS, we call the open program to open the image. Because we can't detect the status of the external viewer, the Python script continues to execute the code and exit. When the script exits, Python will call the destructor of the Figure class (i.e., Figure.__del__ method), which deletes the preview directory and also the preview image.

So, the preview image will show if the open program opens the image before Python deletes it, and will fail to open the image if it's already deleted.


The following script is similar to the above one, but instead, it plots and opens two images.

import pygmt

fig = pygmt.Figure()
fig.basemap(region=[0, 10, 0, 10], projection="X10c/10c", frame="+tFigure1")
print("Openning Figure1")
fig.show(method="external")

fig = pygmt.Figure()
fig.basemap(region=[0, 10, 0, 10], projection="X10c/10c", frame="+tFigure2")
print("Openning Figure2")
fig.show(method="external")

Again, the script works well in a Python/IPython interpreter, but usually can open Figure1 and can't open Figure2 when running a script. Figure1 can be successfully opened because plotting the second figure take some time, so the first Figure.show() call can open Figure1 before the program exits.


The only solution I can figure out is adding a short pause after calling the external viewer, i.e.,
adding time.sleep(0.5) at the end of the launch_external_viewer(fname) function.

def launch_external_viewer(fname):

It works well for me, and should also work for Linux, but I'm not sure about Windows. The 0.5 second pause time is empirical, and may not work for slow computers.

I opened the PR #1062 with the above solution, so that anyone can test it with/without the pause.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinghelp wantedHelping hands are appreciated

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions