在 Python GUI 中使用底图作为图形
Using basemap as a figure in a Python GUI
我有生成底图的代码片段,以及 GUI 的(非常粗糙的)开始部分。但是,我找不到 "one-liner" 允许我在 GUI 中将地图显示为图形。代码片段如下;理想情况下,我希望发生一些事情:
- 一张 'basemap' 的图像,用于替代
sin(2*pi*t)
的情节
- 如果我点击显示的图(希望您可以点击地图上的任意位置,脚本将记录您点击的位置的纬度和经度)。
关于第一步,我试过设置图形变量f等于底图;这完全杀死了 GUI 部分,并在另一个 window.
中简单地显示了地图的图像
我试图通过尝试实现我在 stackexchange 上找到的几个例程来解决 #2,但从未让它完全工作。
底图:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
## User-chosen datapoint
#lons = [10]; lats = [20];
# Define map projection
m = Basemap(projection='cyl',llcrnrlat=-90,urcrnrlat=90,\
llcrnrlon=-180,urcrnrlon=180,resolution='c')
m.drawcoastlines()
粗略的 GUI:
import matplotlib
matplotlib.use('TkAgg')
from numpy import arange, sin, pi
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
# implement the default mpl key bindings
from matplotlib.backend_bases import key_press_handler
from Tkinter import *
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
from mpl_toolkits.basemap import Basemap
from matplotlib.figure import Figure
import sys
if sys.version_info[0] < 3:
import Tkinter as Tk
else:
import tkinter as Tk
root = Tk.Tk()
root.wm_title("Embedding in TK")
f = Figure(figsize=(5, 4), dpi=100)
a = f.add_subplot(111)
t = arange(0.0, 3.0, 0.01)
s = sin(2*pi*t)
a.plot(t, s)
# a tk.DrawingArea
canvas = FigureCanvasTkAgg(f, master=root)
canvas.show()
canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
toolbar = NavigationToolbar2TkAgg(canvas, root)
toolbar.update()
canvas._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
def on_key_event(event):
print('you pressed %s' % event.key)
key_press_handler(event, canvas, toolbar)
canvas.mpl_connect('key_press_event', on_key_event)
def _quit():
root.quit() # stops mainloop
root.destroy() # this is necessary on Windows to prevent
# Fatal Python Error: PyEval_RestoreThread: NULL tstate
button = Tk.Button(master=root, text='Quit', command=_quit)
button.pack(side=Tk.BOTTOM)
Tk.mainloop()
一个简单的技术是定义一个 on_click
函数,显示图像,然后覆盖该图像。尽管图像发生变化,on_click
函数仍会读取鼠标点击位置。
示例代码如下,演示如下所示:
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
def on_click(event):
if event.inaxes is not None:
print event.xdata, event.ydata
else:
print 'Clicked ouside axes bounds but inside plot window'
fig, ax = plt.subplots()
fig.canvas.callbacks.connect('button_press_event', on_click)
plt.show()
#Define map projection
m = Basemap(projection='cyl', llcrnrlat=-90, urcrnrlat=90,
llcrnrlon=-180, urcrnrlon=180, resolution='c')
m.drawcoastlines()
如何将底图绘图包含到 Tkinter 中的问题实际上尚未得到解答。所以想法是在图中创建一个轴 ax
并将底图添加到轴。这是通过 ax
参数完成的,
m = Basemap(..., ax=ax)
然后以通常的方式将数字添加到 canvas;下面是一个完整的例子。
from mpl_toolkits.basemap import Basemap
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import sys
if sys.version_info[0] < 3:
import Tkinter as Tk
else:
import tkinter as Tk
root = Tk.Tk()
root.wm_title("Embedding in TK")
fig = Figure(figsize=(5, 4), dpi=100)
ax = fig.add_subplot(111)
m = Basemap(projection='cyl',llcrnrlat=-90,urcrnrlat=90,\
llcrnrlon=-180,urcrnrlon=180,resolution='c', ax=ax)
m.drawcoastlines()
# a tk.DrawingArea
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.show()
canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
toolbar = NavigationToolbar2TkAgg(canvas, root)
toolbar.update()
canvas._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
def _quit():
root.quit() # stops mainloop
root.destroy() # this is necessary on Windows to prevent
# Fatal Python Error: PyEval_RestoreThread: NULL tstate
button = Tk.Button(master=root, text='Quit', command=_quit)
button.pack(side=Tk.BOTTOM)
Tk.mainloop()
注意:在较新版本的 matplotlib 中,您应该使用 NavigationToolbar2Tk
而不是 NavigationToolbar2TkAgg
。
我有生成底图的代码片段,以及 GUI 的(非常粗糙的)开始部分。但是,我找不到 "one-liner" 允许我在 GUI 中将地图显示为图形。代码片段如下;理想情况下,我希望发生一些事情:
- 一张 'basemap' 的图像,用于替代
sin(2*pi*t)
的情节
- 如果我点击显示的图(希望您可以点击地图上的任意位置,脚本将记录您点击的位置的纬度和经度)。
关于第一步,我试过设置图形变量f等于底图;这完全杀死了 GUI 部分,并在另一个 window.
中简单地显示了地图的图像我试图通过尝试实现我在 stackexchange 上找到的几个例程来解决 #2,但从未让它完全工作。
底图:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
## User-chosen datapoint
#lons = [10]; lats = [20];
# Define map projection
m = Basemap(projection='cyl',llcrnrlat=-90,urcrnrlat=90,\
llcrnrlon=-180,urcrnrlon=180,resolution='c')
m.drawcoastlines()
粗略的 GUI:
import matplotlib
matplotlib.use('TkAgg')
from numpy import arange, sin, pi
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
# implement the default mpl key bindings
from matplotlib.backend_bases import key_press_handler
from Tkinter import *
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
from mpl_toolkits.basemap import Basemap
from matplotlib.figure import Figure
import sys
if sys.version_info[0] < 3:
import Tkinter as Tk
else:
import tkinter as Tk
root = Tk.Tk()
root.wm_title("Embedding in TK")
f = Figure(figsize=(5, 4), dpi=100)
a = f.add_subplot(111)
t = arange(0.0, 3.0, 0.01)
s = sin(2*pi*t)
a.plot(t, s)
# a tk.DrawingArea
canvas = FigureCanvasTkAgg(f, master=root)
canvas.show()
canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
toolbar = NavigationToolbar2TkAgg(canvas, root)
toolbar.update()
canvas._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
def on_key_event(event):
print('you pressed %s' % event.key)
key_press_handler(event, canvas, toolbar)
canvas.mpl_connect('key_press_event', on_key_event)
def _quit():
root.quit() # stops mainloop
root.destroy() # this is necessary on Windows to prevent
# Fatal Python Error: PyEval_RestoreThread: NULL tstate
button = Tk.Button(master=root, text='Quit', command=_quit)
button.pack(side=Tk.BOTTOM)
Tk.mainloop()
一个简单的技术是定义一个 on_click
函数,显示图像,然后覆盖该图像。尽管图像发生变化,on_click
函数仍会读取鼠标点击位置。
示例代码如下,演示如下所示:
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
def on_click(event):
if event.inaxes is not None:
print event.xdata, event.ydata
else:
print 'Clicked ouside axes bounds but inside plot window'
fig, ax = plt.subplots()
fig.canvas.callbacks.connect('button_press_event', on_click)
plt.show()
#Define map projection
m = Basemap(projection='cyl', llcrnrlat=-90, urcrnrlat=90,
llcrnrlon=-180, urcrnrlon=180, resolution='c')
m.drawcoastlines()
如何将底图绘图包含到 Tkinter 中的问题实际上尚未得到解答。所以想法是在图中创建一个轴 ax
并将底图添加到轴。这是通过 ax
参数完成的,
m = Basemap(..., ax=ax)
然后以通常的方式将数字添加到 canvas;下面是一个完整的例子。
from mpl_toolkits.basemap import Basemap
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import sys
if sys.version_info[0] < 3:
import Tkinter as Tk
else:
import tkinter as Tk
root = Tk.Tk()
root.wm_title("Embedding in TK")
fig = Figure(figsize=(5, 4), dpi=100)
ax = fig.add_subplot(111)
m = Basemap(projection='cyl',llcrnrlat=-90,urcrnrlat=90,\
llcrnrlon=-180,urcrnrlon=180,resolution='c', ax=ax)
m.drawcoastlines()
# a tk.DrawingArea
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.show()
canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
toolbar = NavigationToolbar2TkAgg(canvas, root)
toolbar.update()
canvas._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
def _quit():
root.quit() # stops mainloop
root.destroy() # this is necessary on Windows to prevent
# Fatal Python Error: PyEval_RestoreThread: NULL tstate
button = Tk.Button(master=root, text='Quit', command=_quit)
button.pack(side=Tk.BOTTOM)
Tk.mainloop()
注意:在较新版本的 matplotlib 中,您应该使用 NavigationToolbar2Tk
而不是 NavigationToolbar2TkAgg
。