#!/usr/bin/env python #*-----------------------------------------------------------------------* #| | #| Copyright (c) 2013 by Paul Scherrer Institute (http://www.psi.ch) | #| | #| Author Thierry Zamofing (thierry.zamofing@psi.ch) | #*-----------------------------------------------------------------------* ''' implements an image view to show a colored image of a hdf5 dataset. ''' if __name__ == '__main__': #Used to guarantee to use at least Wx2.8 import wxversion wxversion.ensureMinimal('2.8') import wx import matplotlib as mpl if __name__ == '__main__': mpl.use('WXAgg') #or mpl.use('WX') #matplotlib.get_backend() import wxutils as ut import os import numpy as np from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas import pylab as plt #used for the colormaps #or from matplotlib.backends.backend_wx import FigureCanvasWx as FigureCanvas #The source of the DraggableColorbar is from: #http://www.ster.kuleuven.be/~pieterd/python/html/plotting/interactive_colorbar.html class MPLCanvasVelo(FigureCanvas): def __init__(self,parent,SetStatusCB=None): if SetStatusCB: self.SetStatusCB=SetStatusCB fig = mpl.figure.Figure() ax = fig.add_axes([0.075,0.075,0.85,0.85]) FigureCanvas.__init__(self,parent, -1, fig) self.mpl_connect('motion_notify_event', self.OnMotion) self.mpl_connect('button_press_event', self.OnBtnPress) self.mpl_connect('button_release_event', self.OnBtnRelease) self.mpl_connect('scroll_event', self.OnBtnScroll) self.mpl_connect('key_press_event',self.OnKeyPress) self.fig=fig self.ax=ax def InitChild(self,meta,vel): fig=self.fig ax=self.ax velxAct,velxDes,velyAct,velyDes,velAct,velDes=vel l=velxAct.shape[0] hl = [] hl += ax.plot(velxAct, 'b-',label='vel x act') hl += ax.plot(velxDes, 'b--',label='vel x des') hl += ax.plot(velyAct, 'g-',label='vel y act') hl += ax.plot(velyDes, 'g--',label='vel y des') hl += ax.plot(velAct, 'r-',label='vel act') hl += ax.plot(velDes, 'r--',label='vel des') ax.xaxis.set_label_text('datapoint (timebase: %g ms per data point)'%meta['timebase']) ax.yaxis.set_label_text('um/ms') legend = ax.legend(loc='upper right', shadow=True) #axvline(linewidth=4, color='r') #mpl.axvline(linewidth=4, color='r') #l = plt.axhline(y=.5, xmin=0.25, xmax=0.75) #circ = mpl.patches.Circle((0.5, 0.5), 0.25, transform=ax.transAxes, # facecolor='yellow', alpha=0.5) #ax.add_patch(circ) ax.plot([.5,.5],[0.01, 0.99],'k',transform=ax.transAxes) self.ax = ax self.hl = hl def OnMotion(self, event): # print event,event.x,event.y,event.inaxes,event.xdata,event.ydata if event.inaxes == self.ax: x = int(round(event.xdata)) #y = int(round(event.ydata)) y = event.ydata s = [] for h in self.ax.get_lines(): # to get also the ellipses: self.ax.get_children() c = h.contains(event) if c[0]: # s = str(h)+str(c[1]) # print "over %s" % s if type(h) == mpl.lines.Line2D: lbl = h.get_label() arr = h.get_data() idx = c[1]['ind'][0] #s += '%s[%d] = [%.2f, %.2f]' % (lbl, idx, arr[0][idx], arr[1][idx]) s.append('%s=%.2f' % (lbl, arr[1][idx])) else: s += str(h) + str(c[1]) s=', '.join(s) self.SetStatusCB(self.Parent, 0, (x, y, s)) def OnBtnPress(self, event): """on button press we will see if the mouse is over us and store some data""" print dir(event.guiEvent) return def OnBtnRelease(self, event): """on release we reset the press data""" print dir(event.guiEvent) #self.OnMouse(event) return def OnBtnScroll(self, event): return def OnKeyPress(self, event): return def OnMouse(self, event): return class MAVelocityFrame(wx.Frame): def __del__(self): self.doc.view.remove(self) def __init__(self, parent,doc): wx.Frame.__init__(self, parent, title='velocity-Plot', size=wx.Size(850, 650)) self.doc=doc;doc.view.append(self) imgDir=ut.Path.GetImage() icon = wx.Icon(os.path.join(imgDir,'PBMA.ico'), wx.BITMAP_TYPE_ICO) self.SetIcon(icon) canvas = MPLCanvasVelo(self,self.SetStatusCB) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(canvas, 1, wx.LEFT | wx.TOP | wx.GROW) self.SetSizer(sizer) toolbar=ut.AddToolbar(canvas,sizer) meta = doc.fh['meta'].item() try: vel=doc.vel except AttributeError: tb=meta['timebase'] #data points are um #datapoint timebase: 2 ms () per data point #velocity: um/ms (deltatau desVel= motor units per serco cycle) rec=doc.fh['rec'] velyAct = np.diff(rec[:, 0])/tb velxAct = np.diff(rec[:, 1])/tb velyDes = np.diff(rec[:, 2])/tb velxDes = np.diff(rec[:, 3])/tb velAct = np.sqrt(velxAct**2+velyAct**2) velDes = np.sqrt(velxDes**2+velyDes**2) doc.vel = vel = (velxAct,velxDes,velyAct,velyDes,velAct,velDes) canvas.InitChild(meta,vel) self.Centre() self.BuildMenu() self.canvas=canvas self.sizer=sizer self.toolbar=toolbar def BuildMenu(self): mnBar = wx.MenuBar() #-------- Edit Menu -------- mn = wx.Menu() #mnItem=mn.Append(wx.ID_ANY, 'Setup Colormap', 'Setup the color mapping ');self.Bind(wx.EVT_MENU, self.OnColmapSetup, mnItem) #mnItem=mn.Append(wx.ID_ANY, 'Invert X-Axis', kind=wx.ITEM_CHECK);self.Bind(wx.EVT_MENU, self.OnInvertAxis, mnItem) #self.mnIDxAxis=mnItem.GetId() #mnItem=mn.Append(wx.ID_ANY, 'Invert Y-Axis', kind=wx.ITEM_CHECK);self.Bind(wx.EVT_MENU, self.OnInvertAxis, mnItem) #mnItem=mn.Append(wx.ID_ANY, 'Show Moments', 'Show image moments ', kind=wx.ITEM_CHECK);self.Bind(wx.EVT_MENU, self.OnShowMoments, mnItem) #self.mnItemShowMoment=mnItem #mnItem=mn.Append(wx.ID_ANY, 'Tomo Normalize', 'Multiplies each pixel with a normalization factor. Assumes there exist an array exchange/data_white', kind=wx.ITEM_CHECK);self.Bind(wx.EVT_MENU, self.OnTomoNormalize, mnItem) #self.mnItemTomoNormalize=mnItem mnBar.Append(mn, '&Edit') mn = wx.Menu() mnItem=mn.Append(wx.ID_ANY, 'Help', 'How to use the image viewer');self.Bind(wx.EVT_MENU, self.OnHelp, mnItem) mnBar.Append(mn, '&Help') self.SetMenuBar(mnBar) self.CreateStatusBar() def OnUpdate(self, msg, usrData): # this is the model-view-control update function #print 'OnUpdate',self, msg, usrData # for message description s.a. class MADoc if msg == 0: canvas = self.canvas ax = canvas.ax idx = usrData hl = canvas.hl #hl[0].set_data(rec[:len, 4], rec[:len, 5]) #hl[3].set_data(rec[:len, 1], rec[:len, 2]) # ax.draw_artist(hl[2]) x = ax.get_xlim(); x = (x[1] - x[0]) / 2; #y = ax.get_ylim(); #y = (y[1] - y[0]) / 2; ax.set_xlim(idx-x, idx + x,emit=True) #ax.set_ylim(rec[len, 2] - y, rec[len, 2] + y) canvas.draw() @staticmethod def SetStatusCB(obj,mode,v): if mode==0: #obj.SetStatusText( "x= %d y=%d val=%s"%v,0) obj.SetStatusText("x(%d,%.2f): %s" % v, 0) else: raise KeyError('wrong mode') def OnHelp(self,event): msg='''to change the image selection: use the toolbar at the bottom to pan and zoom the image use the scrollbars at the bottom (if present) to select an other slice to change the colorscale: drag with left mouse button to move the colorbar up and down drag with right mouse button to zoom in/out the colorbar at a given point use mouse weel to zoom in/out the colorbar at a given point double click left mouse button to set maximum and minimun colorbar values use cursor up and down to use a different colormap''' dlg = wx.MessageDialog(self, msg, 'Help', wx.OK|wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() if __name__ == '__main__': import os,sys,argparse #since python 2.7 def GetParser(required=True): fnHDF='/scratch/detectorData/e14472_00033.hdf5' #lbl='mcs' lbl='pilatus_1' #lbl='spec' elem='/entry/dataScan00033/'+lbl exampleCmd='--hdfFile='+fnHDF+' --elem='+elem parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter, description=__doc__, epilog='Example:\n'+os.path.basename(sys.argv[0])+' '+exampleCmd+'\n ') parser.add_argument('--hdfFile', required=required, default=fnHDF, help='the hdf5 to show') parser.add_argument('--elem', required=required, default=elem, help='the path to the element in the hdf5 file') return parser args = parser.parse_args() return args class App(wx.App): def OnInit(self): parser=GetParser() #parser=GetParser(False) # debug with exampleCmd args = parser.parse_args() try: self.fid=fid=h5py.h5f.open(args.hdfFile) except IOError as e: sys.stderr.write('Unable to open File: '+args.hdfFile+'\n') parser.print_usage(sys.stderr) return True try: hid = h5py.h5o.open(fid,args.elem) except KeyError as e: sys.stderr.write('Unable to open Object: '+args.elem+'\n') parser.print_usage(sys.stderr) return True frame = HdfImageFrame(None,args.elem,hid) frame.Show() self.SetTopWindow(frame) return True def OnExit(self): self.fid.close() ut.StopWatch.Start() app = App() app.MainLoop()