我有一个打开文件的脚本,并通过嵌入在Tkinter中的matplotlib图形绘制它。 我希望能够在该图中选择一个区域并检索角点值。 我的脚本正在打开文件并绘制数据,还有一个工作示例(taken from this question),您可以在其中选择图表上的某个区域但我正在努力将它们组合起来。
我的脚本阅读和绘制数据:
import numpy as np
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.figure import *
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
from matplotlib.ticker import LogFormatter
from matplotlib import gridspec
from matplotlib.ticker import MultipleLocator, FormatStrFormatter
import tkFileDialog
import tkMessageBox
import Tkinter as tk
from ncdump_file import ncdump
from netCDF4 import Dataset
class CustomToolbar(NavigationToolbar2TkAgg):
def __init__(self,canvas_,parent_):
NavigationToolbar2TkAgg.__init__(self,canvas_,parent_)
class simpleapp_tk(tk.Tk):
def __init__(self, parent):
tk.Tk.__init__(self, parent)
self.parent=parent
self.initialize()
def initialize(self):
button = tk.Button(self, text="Open file", command=self.onOpen)
button.pack()
button = tk.Button(self, text="Plot data", command=self.plot)
button.pack()
button = tk.Button(self, text="Quit", command=self.quit)
button.pack()
self.labelVariable = tk.StringVar()
label = tk.Label(self, textvariable=self.labelVariable, anchor = "w", fg = 'white', bg = 'blue')
label.pack()
self.labelVariable.set("Data Browser")
self.resizable(True, True)
def onOpen(self):
ftypes = [('Netcdf files', '*.nc'), ('All files', '*.*')]
dlg = tkFileDialog.Open(filetypes = ftypes)
fl = dlg.show()
if fl != '': # Reading ncfile and dumping data
nc_file = Dataset(fl, 'r')
global time_bnds
global para_beta
global perp_beta
global altitude
time_bnds = nc_file.variables['time_bnds'][:]
altitude = nc_file.variables['altitude'][:]
para_beta = np.swapaxes((nc_file.variables['para_beta'][:]), 0, 1)
perp_beta = np.swapaxes((nc_file.variables['perp_beta'][:]), 0, 1)
para_beta[np.isnan(para_beta)]=0
perp_beta[np.isnan(perp_beta)]=0
#ncdump(nc_file)
def plot (self):
try:
fig = plt.figure('Input para+perp ATB')
gs = gridspec.GridSpec(4, 6)
lvls = np.logspace(-5,5,num=20) # sets range and frequency of tick labels
l_f = LogFormatter(10, labelOnlyBase=False)
xaxis_majorLocator = MultipleLocator(2.0)
xaxis_majorFormatter = FormatStrFormatter('%1.1f')
xaxis_minorLocator = MultipleLocator(1.0)
ax1 = fig.add_subplot(gs[0:4, 0:5])
ax1.plot([10, 12, 14, 16], [0, 1, 2, 3]) # added so that it can run without netcdf file
#im = ax1.imshow(para_beta, extent =(time_bnds.min(), time_bnds.max(), altitude.min(), altitude.max()), aspect = 'auto', cmap = 'jet', interpolation = 'none', origin = 'lowest', norm=LogNorm(vmin=1e-5, vmax = None))
ax1.set_ylim([0, 10])
ax1.set_ylabel('Height (km)')
ax1.xaxis.set_major_locator(xaxis_majorLocator)
ax1.xaxis.set_major_formatter(plt.NullFormatter())
ax1.xaxis.set_minor_locator(xaxis_minorLocator)
plt.title('Parallel')
#cax = fig.add_subplot(gs[1:3, 5:6])
#fig.colorbar(im, label = 'Atten Beta [$km^{-1}\,sr^{-1}$]', cax = cax, format=l_f, ticks = lvls)
#im.set_clim(1e-5, 1e-1) # changes the bounds of the colour bar, irrespective of ticks
plt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=0.5)
canvas = FigureCanvasTkAgg(fig, master=self)
canvas.show()
canvas.get_tk_widget().pack()
toolbar = NavigationToolbar2TkAgg(canvas, self)
toolbar.update()
canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
except SyntaxError:
tkMessageBox.showinfo("No file selected", "Please select a file")
def quit():
root.destroy()
if __name__ == "__main__":
app = simpleapp_tk(None)
app.title('Data Browser')
app.mainloop()
工作示例:
from Tkinter import *
from matplotlib.figure import *
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
root = Tk()
graph = Figure(figsize=(5,4), dpi=100)
ax = graph.add_subplot(111)
plot = ax.plot([1,2,3,4],[5,6,2,8])
canvas = FigureCanvasTkAgg(graph, master=root)
canvas.show()
canvas.get_tk_widget().grid(column=2, row=1, rowspan=2, sticky=(N, S, E, W))
class Zoom(object):
def __init__(self):
self.graph = Figure(figsize=(5,4), dpi=100)
self.ax = graph.add_subplot(111)
# should be Rectangle((0,0),0,0)
self.rect = Rectangle((10,10),100,100)
self.ax.add_patch(self.rect)
self.ax.plot([1,2,3,4],[5,6,2,8])
self.is_pressed = False
self.x0 = 0.0
self.y0 = 0.0
self.x1 = 0.0
self.y1 = 0.0
self.aid = graph.canvas.mpl_connect('button_press_event', self.on_press)
self.bid = graph.canvas.mpl_connect('button_release_event', self.on_release)
self.cid = graph.canvas.mpl_connect('motion_notify_event', self.on_motion)
def on_press(self, event):
self.is_pressed = True
if event.xdata is not None and event.ydata is not None:
self.x0, self.y0 = event.xdata, event.ydata
print 'press:', self.x0, self.y0
# only remove old rectangle
self.rect.set_width(0)
self.rect.set_height(0)
self.rect.set_xy((self.x0, self.y0))
self.ax.figure.canvas.draw()
# color and linestyle for future motion
self.rect.set_facecolor('red')
self.rect.set_linestyle('dashed')
def on_motion(self, event):
if self.is_pressed:
if event.xdata is not None and event.ydata is not None:
self.x1, self.y1 = event.xdata, event.ydata
self.rect.set_width(self.x1 - self.x0)
self.rect.set_height(self.y1 - self.y0)
self.rect.set_xy((self.x0, self.y0))
self.ax.figure.canvas.draw()
print 'rect:', self.x0, self.y0, self.x1, self.y1, (self.x1-self.x0), (self.y1-self.y0)
def on_release(self, event):
self.is_pressed = False
print 'release:', event.xdata, event.ydata
# change only color and linestyle
#self.rect.set_width(self.x1 - self.x0)
#self.rect.set_height(self.y1 - self.y0)
#self.rect.set_xy((self.x0, self.y0))
self.rect.set_facecolor('blue')
self.rect.set_linestyle('solid')
self.ax.figure.canvas.draw()
my_object = Zoom()
root.mainloop()
我应该在脚本的哪个部分介绍选择功能以及如何?我已经尝试在我的函数图中定义on_press函数等,但我得到了各种AttributeErrors。我也尝试在课堂外全局定义它们,但这也没有用。
答案 0 :(得分:-1)
要合并脚本,我将事件管理器(即aid = self.fig.canvas.mpl_connect('button_press_event', self.on_press)
)添加到我的plot
函数中,然后在主要内部定义了与这些事件管理器相关的函数(即on_press
)类,和其他正常函数一样。
请参阅以下完整代码:
class simpleapp_tk(tk.Tk):
def __init__(self, parent):
tk.Tk.__init__(self, parent)
self.parent=parent
self.initialize()
def initialize(self):
button = tk.Button(self, text="Open file", command=self.onOpen)
button.pack()
button = tk.Button(self, text="Plot data", command=self.plot)
button.pack()
button = tk.Button(self, text="Quit", command=self.quit)
button.pack()
self.labelVariable = tk.StringVar()
label = tk.Label(self, textvariable=self.labelVariable, anchor = "w", fg = 'white', bg = 'blue')
label.pack()
self.labelVariable.set("Data Browser")
self.resizable(True, True)
def onOpen(self):
ftypes = [('Netcdf files', '*.nc'), ('All files', '*.*')]
dlg = tkFileDialog.Open(filetypes = ftypes)
fl = dlg.show()
if fl != '': # Reading ncfile and dumping data
nc_file = Dataset(fl, 'r')
global time_bnds
global para_beta
global perp_beta
global altitude
time_bnds = nc_file.variables['time_bnds'][:]
altitude = nc_file.variables['altitude'][:]
para_beta = np.swapaxes((nc_file.variables['para_beta'][:]), 0, 1)
perp_beta = np.swapaxes((nc_file.variables['perp_beta'][:]), 0, 1)
para_beta[np.isnan(para_beta)]=0
perp_beta[np.isnan(perp_beta)]=0
def plot (self):
try:
self.fig = plt.figure('Input para+perp ATB')
gs = gridspec.GridSpec(4, 6)
lvls = np.logspace(-5,5,num=20) # sets range and frequency of tick labels
l_f = LogFormatter(10, labelOnlyBase=False)
self.ax1 = self.fig.add_subplot(gs[0:4, 0:5])
im = self.ax1.imshow(para_beta, extent =(time_bnds.min(), time_bnds.max(), altitude.min(), altitude.max()), aspect = 'auto', cmap = 'jet', interpolation = 'none', origin = 'lowest', norm=LogNorm(vmin=1e-5, vmax = None))
self.rect = Rectangle((0, 0), 0, 0)
self.ax1.add_patch(self.rect)
cax = self.fig.add_subplot(gs[1:3, 5:6])
self.fig.colorbar(im, label = 'Atten Beta [$km^{-1}\,sr^{-1}$]', cax = cax, format=l_f, ticks = lvls)
im.set_clim(1e-5, 1e-1) # changes the bounds of the colour bar, irrespective of ticks
plt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=0.5)
canvas = FigureCanvasTkAgg(self.fig, master=self)
canvas.show()
canvas.get_tk_widget().pack()
toolbar = NavigationToolbar2TkAgg(canvas, self)
toolbar.update()
canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
aid = self.fig.canvas.mpl_connect('button_press_event', self.on_press)
bid = self.fig.canvas.mpl_connect('button_release_event', self.on_release)
cid = self.fig.canvas.mpl_connect('motion_notify_event', self.on_motion)
except NameError:
tkMessageBox.showinfo("No file selected", "Please select a file")
def on_press(self, event):
self.is_pressed = True
if event.xdata is not None and event.ydata is not None:
self.x0, self.y0 = event.xdata, event.ydata
#print 'press:', self.x0, self.y0
self.rect.set_width(0)
self.rect.set_height(0)
self.rect.set_xy((self.x0, self.y0))
self.fig.canvas.draw()
self.rect.set_edgecolor('red')
self.rect.set_linestyle('solid')
self.rect.set_facecolor('none')
self.rect.set_linewidth('5')
def on_motion(self, event):
try:
if self.is_pressed:
if event.xdata is not None and event.ydata is not None:
self.x1, self.y1 = event.xdata, event.ydata
self.rect.set_width(self.x1 - self.x0)
self.rect.set_height(self.y1 - self.y0)
self.rect.set_xy((self.x0, self.y0))
self.fig.canvas.draw()
#print 'rect:', self.x0, self.y0, self.x1, self.y1, (self.x1-self.x0), (self.y1-self.y0)
except AttributeError:
pass
def on_release(self, event):
self.is_pressed = False
self.x1, self.y1 = event.xdata, event.ydata
self.rect.set_xy((self.x0, self.y0))
print 'rect:', self.x0, self.y0, self.x1, self.y1
self.fig.canvas.draw()
def quit():
root.destroy()
if __name__ == "__main__":
app = simpleapp_tk(None)
app.title('Data Browser')
app.mainloop()