Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pygmt does not display images using show() #366

Closed
MarkWieczorek opened this issue Nov 4, 2019 · 7 comments · Fixed by #529
Closed

pygmt does not display images using show() #366

MarkWieczorek opened this issue Nov 4, 2019 · 7 comments · Fixed by #529
Labels
bug Something isn't working
Milestone

Comments

@MarkWieczorek
Copy link
Contributor

gmt version = 6.0.0 (macOS, installed via brew)

pygmt does not display newly created figures using show().

In [4]: fig = pygmt.Figure()
   ...: fig.coast(shorelines=True, region=[-90, -70, 0, 20], projection="M8i", frame=True)
   ...: fig.show()
pygmt-session [ERROR]: GMT_COMPATIBILITY: Expects values from 6 to 6; reset to 6.
pygmt-session [ERROR]: GMT_COMPATIBILITY: Expects values from 6 to 6; reset to 6.
pygmt-session [ERROR]: GMT_COMPATIBILITY: Expects values from 6 to 6; reset to 6.
pygmt-session [ERROR]: GMT_COMPATIBILITY: Expects values from 6 to 6; reset to 6.
pygmt-session [ERROR]: GMT_COMPATIBILITY: Expects values from 6 to 6; reset to 6.
Out[4]: <IPython.core.display.Image object>
@MarkWieczorek
Copy link
Contributor Author

I note that this does in fact work in a jupyter notebook, but not in a standard terminal session.

@seisman
Copy link
Member

seisman commented Nov 4, 2019

In an IPython terminal, you need to call fig.show(method="external") to display the figure.

@MarkWieczorek
Copy link
Contributor Author

That appears to save the figure as a temporary file, and then opens it with an external application.

Would it be possible to

  1. use a syntax that is compatible with matplotlib, or
  2. plot the pygmt figure inside of a matplotlib figure or axis?

What I would really like to do is have a simple way of choosing to plot something using either standard matplotlib or gmt, such as:

fig, ax = plt.subplots(1,1)
myplot(data, ax=ax, format='gmt')
myplot(data, ax=ax, format='mpl')

@weiji14
Copy link
Member

weiji14 commented Nov 5, 2019

Hi @MarkWieczorek, I'm not sure if there's a way to put pygmt figures inside matplotlib (point 2), but in regard to a matplolib compatible syntax (point 1), @leouieda definitely put some thought before on how to make the display mechanisms better at #269.

If it's subplots you're interested in, the modern mode in GMT 6 does have a subplot feature, but that's not wrapped yet. I actually have some local code to implement that but it'll take time to get into PyGMT properly.

Could you describe in a bit more detail what you're trying to plot? If I'm reading this correctly, are you interested in showing the figure inline inside of an IPython terminal?

@weiji14 weiji14 added the triage Unsure where this issue fits label Nov 5, 2019
@MarkWieczorek
Copy link
Contributor Author

What I would like to do is create a custom plotting method for use with pyshtools. The idea would be to take an instance of a grid and then do

fig = grid.plot_gmt(projection='...', ..., show=True)

The show=True would show the image if you are in a terminal or in a notebook.

You seem to be saying that this is impossible, so the alternative would be to return a figure, and then manually specify to show it, like

fig = grid.plot_gmt()
fig.show()

@weiji14
Copy link
Member

weiji14 commented Nov 5, 2019

Right, so you want to make a plot_gmt function that has a show flag which will automatically display the figure when called! I can see where you're going here (I've written a similar thing before with matplotlib). So yes, the problem is that PyGMT's fig.show() doesn't quite work that way (yet?)...

Could you point me to some sample code on what that plot_ function looks like (a non-gmt one will suffice). I can see you've opened a GMT milestone at https://github.com/SHTOOLS/SHTOOLS/milestone/1

@leouieda
Copy link
Member

@MarkWieczorek I started a branch for implementing #269 (PR coming soon) and here is what I have working:

  1. Calling Figure.show() will open an external viewer and return something that Jupyter knows how to embed in the notebook. There is no need for method="enternal".
  2. Calling pygmt.enable_notebook() will disable the external viewer. This can also be set with an environment variable. I don't really like this but I don't think there is another way that is always reliable. matplotlib does this by deep integration with Jupyter (i.e., jupyter has code to handle matplotlib figures) which I don't think we can mirror yet.

So you could have fig = grid.plot_gmt(projection='...', ..., show=True) and things should work the way you expect.

Regarding inserting plots in matplotlib, the problem is that the figure would be a raster. We could get a PNG returned by PyGMT and insert that as matplotlib axis. The problem is that it looks bad when exporting the figure later on. This was my original idea for the display mechanism but I gave up on it at the time. The "best" way to do this would be to translate postscript to matplotlib's vector format but I doubt anyone would be willing to do it. I'm not even sure it's possible since GMT does a lot of coding in the postscript itself.

If anyone is can find a way of inserting raster into matplotlib in a way that it looks good, I'd be happy to implement this in PyGMT. Mixing GMT and matplotlib in the same figure would be a dream!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
4 participants