280 lines
9.5 KiB
Python
280 lines
9.5 KiB
Python
#!/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']
|
|
velxAct = np.diff(rec[:, 1])/tb
|
|
velxDes = np.diff(rec[:, 4])/tb
|
|
velyAct = np.diff(rec[:, 2])/tb
|
|
velyDes = np.diff(rec[:, 5])/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
|
|
len = 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(len-x, len + 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()
|