first full functional MAxyPlot
This commit is contained in:
442
python/MAError.py
Normal file
442
python/MAError.py
Normal file
@@ -0,0 +1,442 @@
|
||||
#!/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 MPLCanvasErr(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,pts,rec):
|
||||
|
||||
fig=self.fig
|
||||
ax=self.ax
|
||||
|
||||
err=np.sqrt((rec[:,1]-rec[:,4])**2+(rec[:,1]-rec[:,4])**2)
|
||||
hl = ax.plot(err, 'r-')
|
||||
ax.xaxis.set_label_text('time (10x servo cycle)')
|
||||
ax.yaxis.set_label_text('pos-error um')
|
||||
self.ax = ax
|
||||
self.hl = hl
|
||||
|
||||
def OnMotion(self,event):
|
||||
print event,event.x,event.y,event.inaxes,event.xdata,event.ydata
|
||||
return
|
||||
if event.inaxes==self.ax:
|
||||
x=int(round(event.xdata))
|
||||
y=int(round(event.ydata))
|
||||
try:
|
||||
v=self.img.get_array()[y,x]
|
||||
except IndexError as e:
|
||||
pass
|
||||
else:
|
||||
#print x,y,v
|
||||
self.SetStatusCB(self.Parent,0,(x,y,v))
|
||||
elif event.inaxes==self.colBar.ax:
|
||||
colBar=self.colBar
|
||||
pt=colBar.ax.bbox.get_points()[:,1]
|
||||
nrm=colBar.norm
|
||||
vmin,vmax,p0,p1,pS = (nrm.vmin,nrm.vmax,pt[0],pt[1],event.y)
|
||||
if isinstance(colBar.norm,mpl.colors.LogNorm):#type(colBar.norm)==mpl.colors.LogNorm does not work...
|
||||
vS=0
|
||||
else:#scale around point
|
||||
vS=vmin+(vmax-vmin)/(p1-p0)*(pS-p0)
|
||||
self.SetStatusCB(self.Parent,1,vS)
|
||||
try:
|
||||
vmin,vmax,p0,p1,pS=self.colBarPressed
|
||||
except AttributeError:
|
||||
return
|
||||
#if event.inaxes != self.cbar.ax: return
|
||||
colBar=self.colBar
|
||||
#print vmin,vmax,p0,p1,pS,type(colBar.norm)
|
||||
#print 'x0=%f, xpress=%f, event.xdata=%f, dx=%f, x0+dx=%f'%(x0, xpress, event.xdata, dx, x0+dx)
|
||||
|
||||
if isinstance(colBar.norm,mpl.colors.LogNorm):#type(colBar.norm)==mpl.colors.LogNorm does not work...
|
||||
if event.button==1:
|
||||
#colBar.norm.vmin=.1
|
||||
colBar.norm.vmax=vmax*np.exp((pS-event.y)/100)
|
||||
#scale= np.exp((event.y-pS)/100)
|
||||
elif event.button==1:#move top,bottom,both
|
||||
pD = event.y - pS
|
||||
vD=(vmax-vmin)/(p1-p0)*(pS-event.y)
|
||||
colBar.norm.vmin = vmin+vD
|
||||
colBar.norm.vmax = vmax+vD
|
||||
elif event.button==3:#scale around point
|
||||
scale= np.exp((pS-event.y)/100)
|
||||
vS=vmin+(vmax-vmin)/(p1-p0)*(pS-p0)
|
||||
#print scale,vS
|
||||
colBar.norm.vmin = vS-scale*(vS-vmin)
|
||||
colBar.norm.vmax = vS-scale*(vS-vmax)
|
||||
self.img.set_norm(colBar.norm)#force image to redraw
|
||||
colBar.patch.figure.canvas.draw()
|
||||
|
||||
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
|
||||
if event.inaxes == self.colBar.ax:
|
||||
#if event.guiEvent.LeftDClick()==True:
|
||||
# print dlg
|
||||
pt=self.colBar.ax.bbox.get_points()[:,1]
|
||||
nrm=self.colBar.norm
|
||||
self.colBarPressed = (nrm.vmin,nrm.vmax,pt[0],pt[1],event.y)
|
||||
#self.colBarPressed = event.x, event.y
|
||||
#print self.colBarPressed
|
||||
#self.OnMouse(event)
|
||||
pass
|
||||
|
||||
def OnBtnRelease(self, event):
|
||||
"""on release we reset the press data"""
|
||||
#self.OnMouse(event)
|
||||
return
|
||||
try: del self.colBarPressed
|
||||
except AttributeError: pass
|
||||
|
||||
def OnBtnScroll(self, event):
|
||||
return
|
||||
#self.OnMouse(event)
|
||||
colBar=self.colBar
|
||||
if event.inaxes==colBar.ax:
|
||||
pt=colBar.ax.bbox.get_points()[:,1]
|
||||
nrm=colBar.norm
|
||||
vmin,vmax,p0,p1,pS = (nrm.vmin,nrm.vmax,pt[0],pt[1],event.y)
|
||||
if isinstance(colBar.norm,mpl.colors.LogNorm):#type(colBar.norm)==mpl.colors.LogNorm does not work...
|
||||
scale= np.exp((-event.step)/10)
|
||||
colBar.norm.vmax=vmax*scale
|
||||
else:#scale around point
|
||||
scale= np.exp((-event.step)/10)
|
||||
vS=vmin+(vmax-vmin)/(p1-p0)*(pS-p0)
|
||||
#print scale,vS
|
||||
colBar.norm.vmin = vS-scale*(vS-vmin)
|
||||
colBar.norm.vmax = vS-scale*(vS-vmax)
|
||||
self.img.set_norm(colBar.norm)#force image to redraw
|
||||
colBar.patch.figure.canvas.draw()
|
||||
|
||||
def OnKeyPress(self, event):
|
||||
return
|
||||
colCycle=self.colCycle
|
||||
colBar=self.colBar
|
||||
if event.key=='down':
|
||||
self.colIndex += 1
|
||||
elif event.key=='up':
|
||||
self.colIndex -= 1
|
||||
self.colIndex%=len(colCycle)
|
||||
cmap = colCycle[self.colIndex]
|
||||
colBar.set_cmap(cmap)
|
||||
colBar.draw_all()
|
||||
self.img.set_cmap(cmap)
|
||||
self.img.get_axes().set_title(cmap)
|
||||
colBar.patch.figure.canvas.draw()
|
||||
|
||||
def OnMouse(self, event):
|
||||
return
|
||||
for k in dir(event):
|
||||
if k[0]!='_':
|
||||
print k,getattr(event,k)
|
||||
|
||||
class MAErrorFrame(wx.Frame):
|
||||
def __init__(self, parent,doc):
|
||||
wx.Frame.__init__(self, parent, title='xy-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 = MPLCanvasErr(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)
|
||||
canvas.InitChild(doc.fh['pts'],doc.fh['rec'])
|
||||
|
||||
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
|
||||
|
||||
def SetIdxXY(self,x,y):
|
||||
self.idxXY=(x,y)
|
||||
|
||||
@staticmethod
|
||||
def SetStatusCB(obj,mode,v):
|
||||
if mode==0:
|
||||
obj.SetStatusText( "x= %d y=%d val=%g"%v,0)
|
||||
elif mode==1:
|
||||
obj.SetStatusText( "Colormap Value %d (drag to scale)"%v,0)
|
||||
else:
|
||||
raise KeyError('wrong mode')
|
||||
|
||||
|
||||
def OnShowMoments(self,event):
|
||||
if event.IsChecked():
|
||||
dlg = wx.FileDialog(self, "Choose valid mask file (e.g. pilatus_valid_mask.mat)", os.getcwd(), '','MATLAB files (*.mat)|*.mat|all (*.*)|*.*', wx.OPEN|wx.FD_CHANGE_DIR)
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
fnMatMsk = dlg.GetPath()
|
||||
print 'OnOpen',fnMatMsk
|
||||
dlg.Destroy()
|
||||
if not fnMatMsk:
|
||||
return
|
||||
#fnMatMsk='/scratch/detectorData/cSAXS_2013_10_e14608_georgiadis_3D_for_Marianne/analysis/data/pilatus_valid_mask.mat'
|
||||
self.procMoment=pm=ProcMoment()
|
||||
pm.SetMskMat(fnMatMsk,False)
|
||||
#roi=[603, 826, 200, 200]
|
||||
#pm.roi=(slice(roi[1],roi[1]+roi[3]),slice(roi[0],roi[0]+roi[2]))
|
||||
#pm.shape=(roi[3],roi[2])
|
||||
|
||||
#pm.SetProcess('python')
|
||||
#pm.SetProcess('pyFast')
|
||||
pm.SetProcess('c')
|
||||
self.PlotMoments()
|
||||
#self.canvas.img.draw()
|
||||
data=self.canvas.img.get_array()
|
||||
self.canvas.img.set_array(data)
|
||||
fig, ax = plt.subplots(2)
|
||||
v=data.sum(axis=0); x=np.arange(v.size); x0=x.sum(); m0=v.sum(); m1=(v*x).sum(); m2=(v*x*x).sum()
|
||||
ax[0].plot(v);
|
||||
m=m1/m0
|
||||
s=np.sqrt( (m2-(m1**2/m0))/m0)
|
||||
xx=1/(s*np.sqrt(2*np.pi))*np.exp(-.5*((x-m)/s)**2)
|
||||
ax[0].set_title('%g | %g | %g | %g | %g'%(m0,m1,m2,m,s))
|
||||
ax[0].hold(True);ax[0].plot(xx*m0)
|
||||
|
||||
v=data.sum(axis=1);
|
||||
ax[1].plot(v);
|
||||
|
||||
|
||||
plt.show()
|
||||
#print pm.resArr[0:3],pm.resArr[1]/pm.resArr[0],pm.resArr[2]/pm.resArr[0]
|
||||
else:
|
||||
for o in self.goMoment:
|
||||
o.remove()
|
||||
del self.goMoment
|
||||
del self.procMoment
|
||||
self.canvas.draw()
|
||||
|
||||
def PlotMoments(self):
|
||||
data=self.canvas.img.get_array()
|
||||
pm=self.procMoment
|
||||
|
||||
#data=ndi.median_filter(data, 3)
|
||||
try:
|
||||
data.ravel()[pm.mskIdx]=0
|
||||
except AttributeError as e:
|
||||
print e
|
||||
try:
|
||||
data=data[pm.roi]
|
||||
except AttributeError as e:
|
||||
print e
|
||||
#data=np.log(data+1)
|
||||
#data[100:110,500:510]=1000 #y,x
|
||||
#data[650:850,700:850]=0 #y,x
|
||||
#pm.Process(np.log(data+1))
|
||||
pm.Process(data)
|
||||
xbar, ybar, cov=pm.GetIntertialAxis()
|
||||
|
||||
m=pm.resArr
|
||||
m00=m[0];m01=m[1];m10=m[2];m11=m[3];m02=m[4];m20=m[5]
|
||||
|
||||
xm = m10 / m00
|
||||
ym = m01 / m00
|
||||
u11 = (m11 - xm * m01) / m00
|
||||
#u11[u11<0.]=0. #processing rounding error
|
||||
u20 = (m20 - xm * m10) / m00
|
||||
u02 = (m02 - ym * m01) / m00
|
||||
a=(u20+u02)/2
|
||||
b=np.sqrt(4*u11**2+(u20-u02)**2)/2
|
||||
l0=a+b
|
||||
l1=a-b
|
||||
ang=0.5*np.arctan2(2*u11,(u20-u02))/(2*np.pi)*360. #orientation value 0..1
|
||||
exc=np.sqrt(1-l1/l0) #eccentricity :circle=0: http://en.wikipedia.org/wiki/Eccentricity_%28mathematics%29
|
||||
|
||||
print 'xb:%g yb:%g cov:%g %g %g %g ang:%g exc:%g'%((xm, ym)+tuple(cov.ravel())+(ang,exc))
|
||||
#fig, ax = plt.subplots()
|
||||
#ax.imshow(data,vmax=100,interpolation='nearest')
|
||||
#plt.show()
|
||||
ax=self.canvas.img.get_axes()
|
||||
try:
|
||||
for o in self.goMoment:
|
||||
o.remove()
|
||||
except AttributeError: pass
|
||||
|
||||
self.goMoment=ProcMoment.PlotMoments(ax, xbar, ybar, cov)
|
||||
ax.axis('image')
|
||||
|
||||
def OnTomoNormalize(self,event):
|
||||
if event.IsChecked():
|
||||
#try to find white image
|
||||
#calculate average
|
||||
#show white normalize factors
|
||||
white=self.data.parent['data_white']
|
||||
tomoNorm=white[1,:,:]
|
||||
#tomoNorm=white[:,:,:].mean(axis=0)
|
||||
#np.iinfo(tomoNorm.dtype).max
|
||||
#tomoNorm=float(np.iinfo(tomoNorm.dtype).max/2)/tomoNorm
|
||||
tomoNorm=tomoNorm.mean()/tomoNorm
|
||||
#tomoNorm=tomoNorm/float(np.iinfo(tomoNorm.dtype).max)
|
||||
data=self.canvas.img.get_array()
|
||||
data*=tomoNorm
|
||||
#data/=tomoNorm
|
||||
self.tomoNorm=tomoNorm
|
||||
self.canvas.img.set_array(data)
|
||||
else:
|
||||
tomoNorm=self.tomoNorm
|
||||
data=self.canvas.img.get_array()
|
||||
data/=tomoNorm
|
||||
self.canvas.img.set_array(data)
|
||||
del self.tomoNorm
|
||||
self.canvas.draw()
|
||||
|
||||
def OnSetComplexData(self, event):
|
||||
if event.IsChecked():
|
||||
data=np.angle(self.canvas.dataRaw)
|
||||
else:
|
||||
data=np.absolute(self.canvas.dataRaw)
|
||||
self.canvas.img.set_array(data)
|
||||
self.canvas.draw()
|
||||
|
||||
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()
|
||||
|
||||
def OnColmapSetup(self,event):
|
||||
dlg=DlgColBarSetup(self)
|
||||
if dlg.ShowModal()==wx.ID_OK:
|
||||
pass
|
||||
dlg.Destroy()
|
||||
|
||||
def OnInvertAxis(self,event):
|
||||
ax=self.canvas.ax
|
||||
#event.Checked()
|
||||
if self.mnIDxAxis==event.GetId():
|
||||
ax.invert_xaxis()
|
||||
else:
|
||||
ax.invert_yaxis()
|
||||
self.canvas.draw()
|
||||
pass
|
||||
|
||||
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()
|
||||
Reference in New Issue
Block a user