I have a script which opens a file and plots it via a matplotlib figure embedded in Tkinter. I would like to be able to select an area in this figure and retrieve the corner values. I have my script which is working to open the file and plot the data, and a working example (taken from this question) where you can select an area on a graph but I am struggling to combine them.
My script to read and plot data:
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()
The working example:
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()
In what part of my script should I introduce the selection functions and how? I have tried defining the on_press function etc within my function plot but I get various AttributeErrors. I also tried to define them globally outside the class but that also didn't work.
Aucun commentaire:
Enregistrer un commentaire