How to Embed Cartopy in a Python Tkinter GUI?

2.2k views Asked by At

I'd like to embed a Cartopy module map in a Python (2.7) Tkinter GUI app (on a Windows 7 PC), but I need help figuring out how.

As far as I understand, the Cartopy module simply enables matplotlib to treat its "plots" or drawings as coordinates and projects these to real world geographic projections. Now I've seen questions and guides on how to embed matplotlib into Tkinter, but these always involve creating a matplotlib Figure() and then using the show() method and FigureCanvasTkAgg() on that figure, whereas the instructions to create a cartopy map is usually to simply use the pyplot's axes() method while providing a cartopy projection object and then using show() with the pyplot module (instead of the Figure object). I've tried some different things but I just can't make sense of how to reconcile these two approaches (creating a cartopy matplotlib and embedding matplotlib in Tkinter). I have experience with cartography, Python, and Tkinter, but I'm new to matplotlib and cartopy so it might be that I just don't understand these modules enough yet.

It would be most helpful if someone could suggest a concrete code example along with their answer. It would also be nice to see an example of how I can draw lines or points in the new embedded cartopy map, e.g. which object do I use the .plot() method on?

In the long run the hope is to be able to interact with the cartopy map through the Tkinter GUI app. Btw, has anyone ever done such cartopy Tkinter embedding before?

---> Answer: Thanks @Pelson for your answer, and for providing a code example. For others with the same problem the crucial steps as I understand it are to 1) create a matplot figure, 2) add an axes to the figure by including a projection argument (thus making it a Cartopy axes), and 3) converting the figure to a Tkinter widget by using the FigureCanvasTkAgg function on it and then using its show() and get_tk_widget() method to pack or place the widget in the Tkinter window.

1

There are 1 answers

0
pelson On BEST ANSWER

There is nothing special about Cartopy and pyplot - everything will work with matplotlib's OO interface too. This means that embedding a Cartopy axes is as difficult as embedding a matplotlib axes in any of the GUI toolkits.

In this case, I've taken the example from http://matplotlib.org/examples/user_interfaces/embedding_in_tk2.html and simply added the following lines:

# Use add_axes or add_subplot.
ax = fig.add_axes([0.01, 0.01, 0.98, 0.98],
                   projection=ccrs.InterruptedGoodeHomolosine())

# ax = fig.add_subplot(1, 1, 1, projection=ccrs.InterruptedGoodeHomolosine())

ax.set_global()
ax.stock_img()
ax.coastlines()

My full application then looks like:

from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure

import cartopy.crs as ccrs

import sys
import Tkinter as Tk

root = Tk.Tk()
root.wm_title("Cartopy in TK")


fig = Figure(figsize=(8,4), dpi=100)

ax = fig.add_axes([0.01, 0.01, 0.98, 0.98], 
                   projection=ccrs.InterruptedGoodeHomolosine())
ax.set_global()
ax.stock_img()
ax.coastlines()

ax.set_title('Cartopy and Tkinter')

# a tk.DrawingArea
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.show()
canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)

canvas._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)

button = Tk.Button(master=root, text='Quit', command=sys.exit)
button.pack(side=Tk.BOTTOM)

Tk.mainloop()

To result in a Tkinter GUI application that looks like: Tkinter screenshot