Beispiel #1
0
	def applyGraphConfig(self, conf):
		if not self.plotColors:
			GraphFSR.applyConfig(self.graph, conf, True)
		else:
			GraphFSR.applyConfig(self.graph, conf, False)
			self.graph.plots={}
			self.plotColors=self.graph.nextcolor(len(self.plotColors))
			self.display()
Beispiel #2
0
	def __init__(self, parent=None, **kwargs):
		nchans=kwargs.get('nchans', 2) 
		returnData=kwargs.get('returnData')
 		BaseGui.__init__(self, parent, title="Waveform Generator", menus = ["File", "Control"], pycommand=True,height=4)

		commands=[["File","New" , lambda x: self.new()],
				  ["File","Change Domain" ,self.resize],
 				  ["File","Play" , self.play],
 				  ["File","Save" ,lambda x: self.save(0)],
 				  ["File","Save As" , lambda x:self.save(1)],
				  ["File","----"],
				  ["File","Load Parameters" , self.load_params],
				  ["File","----"],
				  ["File", "Quit", lambda x:self.Destroy()],
				  ["Control", "Smoothing Points", self.set_smooth_points],
				  ["Control", "Fill dcl with silence", self.set_silent_fill],
				  ["Control","Refresh Display",lambda x: self.make_change()],
				  ["Control","Plot trajectory",self.trajectoryplot]]
		
		if returnData:
			self.returnDataMono=lambda x:returnData(self.dataExport(1))
			self.returnDataStereo=lambda x:returnData(self.dataExport(2))
			commands.insert(2, ["File", "Export Data (Mono)", self.returnDataMono])
			commands.insert(2, ["File", "Export Data (Stereo)", self.returnDataStereo])
			
		self.fillMenus(commands)
		id = wx.NewId()
		self.menus["Control"].AppendCheckItem(id, "Smooth Transitions")
		wx.EVT_MENU(self, id, self.change_smoothing)

		self.mainSizer = wx.BoxSizer(wx.HORIZONTAL)
		self.main.SetSizer(self.mainSizer)
		self.main.SetAutoLayout(True)
	
		self.graph=GraphFSR(self.main,-1)		
		self.mainSizer.Add(self.graph,1, wx.GROW|wx.ALIGN_CENTRE|wx.ALL, 5)
		
	   	self.display=self.display_cart
		
		vsizer2 = wx.BoxSizer(wx.VERTICAL)
		self.channels=[]
		self.controls=[]

		for s in range(nchans):
			control=ChannelControls(self.main,self, "Channel %i" % s)
			vsizer2.Add(control, 1, wx.GROW|wx.ALIGN_CENTRE|wx.ALL, 5)
			control.report=self.report
			control.make_change=self.make_change
			self.controls.append(control)
			self.channels.append(None)
		self.mainSizer.Add(vsizer2,1, wx.GROW|wx.ALIGN_CENTRE|wx.ALL, 5)
		
		self.filename=None
		self.savetype = None
		self.smoothpoints=50
		self.silent_fill=(0,0)
	   		
		self.mainSizer.Fit(self.main)
		self.SetSize(wx.Size(800,600))
		self.new(1.0, .00005)
Beispiel #3
0
	def __init__(self, master=None, **kwargs):
		tty=kwargs.get('tty', None)
		title=kwargs.get('title',"Data Viewer")
		returnData=kwargs.get('returnData')
		BaseGui.__init__(self, master, title=title, menus=["File", "Edit", "Display", "Extensions", "Dsp"], pycommand=True,height=4, TTY=tty, showframe=False)
		
		controls=[["File","Open Part of a File", lambda x:self.load(select=True)],
				  ["File","Create Blank (all zeros) Data", self.blank],
				  ["File", "Load SubData", self.loadSub],
				  ["File", "Switch Viewed Data", self.changedat],
				  ["File", "Combine Data", self.combinedat],
				  ["Edit","Undo",self.undo],
				  ["Edit","Redo",self.redo],
				  ["Edit","Save Checkpoint",self.setcheck],
				  ["Edit","Load Checkpoint",self.getcheck],
				  ["Edit","Crop",self.crop],
				  ["Edit","Data Editor",self.launchEditor],
				  ["Edit","Delete Channels",self.delChan],
				  ["Display","Marker Locations",self.markLoc],
				  ["Display","Marker Difference",self.markDiff],
				  ["Display","Set Mark",self.addMark],
				  ["Display","Width 4",self.w4],
				  ["Display","Redraw",lambda x:self.onNewData()],
				  ['Display', 'Global Equalize', lambda x:self.equalize('g')],
				  ['Display', 'Local Equalize', lambda x:self.equalize('l')],
				  ['Display', 'Raw Amplitudes', lambda x:self.equalize('n')],
				  ['Display', 'Show Contrast Controls', self.launchContrast]
				  ]

		
		if returnData:
			self.returnData = lambda x:returnData(self.data)
			controls.insert(2, ["File", "Export Data", self.returnData])
		self.fillMenus(controls)
		#self.bounceST()
		self.modes = {"Separate": self.makeYSep,
					  "Quick Sep": self.makeQSep,
					  "Local Sep": self.makeLSep,
					  "Y Overlay": self.makeYover,
					  "Raw":self.zeroOffset,
					  "Image":self.asImage }
		self.preferenceInfo=[{"Name":"Use image mode for more than X channels",
			"Value":30},
			{"Name":"Image Contrast",
			"Type":"Choice",
			"Value":{"local":[],
				"global":[],
				"Manual":[{"Name":"Min", "Value":-70.0},
					{"Name":"Max", "Value":30.0}]}},
			{"Name":"Display Range",
			'Type':'List',
			'Value':['global', 'local', 'manual']},
			{"Name":"Processing Tools Act On",
			'Type':'List',
			'Value':['All Data', 'Current View', 'Marked Range']},
			{"Name":'Save referenced data files when saving xml',
			'Type':'List',
			'Value':['Yes', 'No']},
			{"Name":'Ensemble display mode',
			'Type':'List',
			'Value':['Stats', 'Mean', 'Overlay', 'Sequential', 'MeanAndCov', 'Hide']},
			{"Name":"On Multiple Open",
			"Type":"List",
			"Value":["Merge", "Nest", "Ignore"]},
			{"Name":"Default View Mode",
			"Type":"List",
			"Value":self.modes.keys()},
			{"Name":"Always Reload Extensions",
			"Type":"List",
			"Value":[True, False]},
			{"Name":'Show Only Same Length Data',
			"Type":"List",
			"Value":[True, False]},
			{"Name":"Simple Subsample",
			"Type":"List",
			"Value":["No", "Yes"]},
			{"Name":"defaultPlotStyle",
			"Type":"List",
			"Value":["envelope", "points", "line"]},
			{"Name":"Checkpoint Directory",
			"Type":str,
			"Browser":FileBrowse},
			{"Name":"Save Multiple Data as",
			"Type":"List",
			"Value":["Directory", "Automatic File Names"]}]
		
		self.preferences={"Use image mode for more than X channels":30,
			"Image Contrast":"global",
			"Processing Tools Act On":"Marked Range",
			'Ensemble display mode':'Stats',
			"defaultPlotStyle":'envelope',
			"Number of Undo Steps":3,
			"Display Nested Data to Depth":4,
			"Display Range":"global",
			"Simple Subsample":'No',
			'Show Only Same Length Data':False,
			"Default View Mode":'Quick Sep',
			"Always Reload Extensions":False,
			"Checkpoint Directory":os.path.expanduser('~/.dvcheckpoints'),
			"On Multiple Open":'Nest', #"Merge", #"Ignore",
			'Save referenced data files when saving xml':'Yes',
			"Save Multiple Data as":"Automatic File Names",
			"Hide Data In":["hidden"]}
		self.mainSizer = wx.BoxSizer(wx.VERTICAL)
		self.main.SetSizer(self.mainSizer)
		self.main.SetAutoLayout(True)
		
		self.graph=GraphFSR(self.main, -1)
		self.graph.applyConfig=self.applyGraphConfig
		
		self.mainSizer.Add(self.graph, 1, wx.GROW|wx.ALIGN_CENTRE|wx.ALL, 5)
		
		cbox = wx.BoxSizer(wx.HORIZONTAL)

		
		self.chooseChan = wx.Choice(self.main, -1, choices=["No channels loaded"])
		cbox.Add(self.chooseChan, 1, wx.GROW|wx.ALL, 5)
		wx.EVT_CHOICE(self.main, self.chooseChan.GetId(), self.doSelectChannel)
		cbox.Add(wx.StaticText(self.main, -1, "Y off:"), 0, wx.ALIGN_CENTRE|wx.ALL, 5)
		self.setYOff = wx.TextCtrl(self.main, -1, "-", style=wx.TE_PROCESS_ENTER, size=(12,-1))
		wx.EVT_TEXT_ENTER(self.main, self.setYOff.GetId(), self.doApplyOff)
		cbox.Add(self.setYOff, 1, wx.GROW|wx.ALIGN_CENTRE|wx.ALL, 5)
		cbox.Add(wx.StaticText(self.main, -1, "X off:"), 0, wx.ALIGN_CENTRE|wx.ALL, 5)
		self.setXOff = wx.TextCtrl(self.main, -1, "-", style=wx.TE_PROCESS_ENTER, size=(12,-1))
		wx.EVT_TEXT_ENTER(self.main, self.setXOff.GetId(), self.doApplyOff)
		cbox.Add(self.setXOff, 1, wx.GROW|wx.ALIGN_CENTRE|wx.ALL, 5)
		cbox.Add(wx.StaticText(self.main, -1, "Y sca:"), 0, wx.ALIGN_CENTRE|wx.ALL, 5)
		self.setYscale = wx.TextCtrl(self.main, -1, "-", style=wx.TE_PROCESS_ENTER, size=(12,-1))
		wx.EVT_TEXT_ENTER(self.main, self.setYscale.GetId(), self.doApplyOff)
		cbox.Add(self.setYscale, 1, wx.GROW|wx.ALIGN_CENTRE|wx.ALL, 5)
		#self.applyOff = wx.Button(self.main, -1, " Apply ")
		#cbox.Add(self.applyOff, 1, wx.GROW|wx.ALIGN_CENTRE|wx.ALL, 5)
		#wx.EVT_BUTTON(self.main, self.applyOff.GetId(), self.doApplyOff)
		modes = self.modes.keys()
		self.chooseMode = wx.Choice(self.main, -1, choices=modes)
		self.load_saved_prefs()
		dvm=self.preferences["Default View Mode"]
		self.chooseMode.SetSelection(modes.index(dvm))
		self.inMode = dvm
		
		cbox.Add(self.chooseMode, 1, wx.GROW|wx.ALIGN_CENTRE|wx.ALL, 5)
		wx.EVT_CHOICE(self.main, self.chooseMode.GetId(), self.doSelectMode)
		
		
		self.mainSizer.Add(cbox, 0, wx.GROW|wx.ALIGN_CENTRE|wx.ALL, 5)
		#self.mainSizer.Fit(self.main) - segv in 2.5, seems unneeded and slow
		self.SetSize(wx.Size(800,600))
		
		self.graph.SetDropTarget(self.dropLoader)
		self.clear_attributes()
 		self.stdFileMenu()
		
		self.spm = mien.datafiles.dataproc.DVSignalMod(self)
		self.datapath="/"
		self.spm.makeMenus()
		self.load_saved_prefs()
Beispiel #4
0
class Dataviewer(BaseGui):
	
	def __init__(self, master=None, **kwargs):
		tty=kwargs.get('tty', None)
		title=kwargs.get('title',"Data Viewer")
		returnData=kwargs.get('returnData')
		BaseGui.__init__(self, master, title=title, menus=["File", "Edit", "Display", "Extensions", "Dsp"], pycommand=True,height=4, TTY=tty, showframe=False)
		
		controls=[["File","Open Part of a File", lambda x:self.load(select=True)],
				  ["File","Create Blank (all zeros) Data", self.blank],
				  ["File", "Load SubData", self.loadSub],
				  ["File", "Switch Viewed Data", self.changedat],
				  ["File", "Combine Data", self.combinedat],
				  ["Edit","Undo",self.undo],
				  ["Edit","Redo",self.redo],
				  ["Edit","Save Checkpoint",self.setcheck],
				  ["Edit","Load Checkpoint",self.getcheck],
				  ["Edit","Crop",self.crop],
				  ["Edit","Data Editor",self.launchEditor],
				  ["Edit","Delete Channels",self.delChan],
				  ["Display","Marker Locations",self.markLoc],
				  ["Display","Marker Difference",self.markDiff],
				  ["Display","Set Mark",self.addMark],
				  ["Display","Width 4",self.w4],
				  ["Display","Redraw",lambda x:self.onNewData()],
				  ['Display', 'Global Equalize', lambda x:self.equalize('g')],
				  ['Display', 'Local Equalize', lambda x:self.equalize('l')],
				  ['Display', 'Raw Amplitudes', lambda x:self.equalize('n')],
				  ['Display', 'Show Contrast Controls', self.launchContrast]
				  ]

		
		if returnData:
			self.returnData = lambda x:returnData(self.data)
			controls.insert(2, ["File", "Export Data", self.returnData])
		self.fillMenus(controls)
		#self.bounceST()
		self.modes = {"Separate": self.makeYSep,
					  "Quick Sep": self.makeQSep,
					  "Local Sep": self.makeLSep,
					  "Y Overlay": self.makeYover,
					  "Raw":self.zeroOffset,
					  "Image":self.asImage }
		self.preferenceInfo=[{"Name":"Use image mode for more than X channels",
			"Value":30},
			{"Name":"Image Contrast",
			"Type":"Choice",
			"Value":{"local":[],
				"global":[],
				"Manual":[{"Name":"Min", "Value":-70.0},
					{"Name":"Max", "Value":30.0}]}},
			{"Name":"Display Range",
			'Type':'List',
			'Value':['global', 'local', 'manual']},
			{"Name":"Processing Tools Act On",
			'Type':'List',
			'Value':['All Data', 'Current View', 'Marked Range']},
			{"Name":'Save referenced data files when saving xml',
			'Type':'List',
			'Value':['Yes', 'No']},
			{"Name":'Ensemble display mode',
			'Type':'List',
			'Value':['Stats', 'Mean', 'Overlay', 'Sequential', 'MeanAndCov', 'Hide']},
			{"Name":"On Multiple Open",
			"Type":"List",
			"Value":["Merge", "Nest", "Ignore"]},
			{"Name":"Default View Mode",
			"Type":"List",
			"Value":self.modes.keys()},
			{"Name":"Always Reload Extensions",
			"Type":"List",
			"Value":[True, False]},
			{"Name":'Show Only Same Length Data',
			"Type":"List",
			"Value":[True, False]},
			{"Name":"Simple Subsample",
			"Type":"List",
			"Value":["No", "Yes"]},
			{"Name":"defaultPlotStyle",
			"Type":"List",
			"Value":["envelope", "points", "line"]},
			{"Name":"Checkpoint Directory",
			"Type":str,
			"Browser":FileBrowse},
			{"Name":"Save Multiple Data as",
			"Type":"List",
			"Value":["Directory", "Automatic File Names"]}]
		
		self.preferences={"Use image mode for more than X channels":30,
			"Image Contrast":"global",
			"Processing Tools Act On":"Marked Range",
			'Ensemble display mode':'Stats',
			"defaultPlotStyle":'envelope',
			"Number of Undo Steps":3,
			"Display Nested Data to Depth":4,
			"Display Range":"global",
			"Simple Subsample":'No',
			'Show Only Same Length Data':False,
			"Default View Mode":'Quick Sep',
			"Always Reload Extensions":False,
			"Checkpoint Directory":os.path.expanduser('~/.dvcheckpoints'),
			"On Multiple Open":'Nest', #"Merge", #"Ignore",
			'Save referenced data files when saving xml':'Yes',
			"Save Multiple Data as":"Automatic File Names",
			"Hide Data In":["hidden"]}
		self.mainSizer = wx.BoxSizer(wx.VERTICAL)
		self.main.SetSizer(self.mainSizer)
		self.main.SetAutoLayout(True)
		
		self.graph=GraphFSR(self.main, -1)
		self.graph.applyConfig=self.applyGraphConfig
		
		self.mainSizer.Add(self.graph, 1, wx.GROW|wx.ALIGN_CENTRE|wx.ALL, 5)
		
		cbox = wx.BoxSizer(wx.HORIZONTAL)

		
		self.chooseChan = wx.Choice(self.main, -1, choices=["No channels loaded"])
		cbox.Add(self.chooseChan, 1, wx.GROW|wx.ALL, 5)
		wx.EVT_CHOICE(self.main, self.chooseChan.GetId(), self.doSelectChannel)
		cbox.Add(wx.StaticText(self.main, -1, "Y off:"), 0, wx.ALIGN_CENTRE|wx.ALL, 5)
		self.setYOff = wx.TextCtrl(self.main, -1, "-", style=wx.TE_PROCESS_ENTER, size=(12,-1))
		wx.EVT_TEXT_ENTER(self.main, self.setYOff.GetId(), self.doApplyOff)
		cbox.Add(self.setYOff, 1, wx.GROW|wx.ALIGN_CENTRE|wx.ALL, 5)
		cbox.Add(wx.StaticText(self.main, -1, "X off:"), 0, wx.ALIGN_CENTRE|wx.ALL, 5)
		self.setXOff = wx.TextCtrl(self.main, -1, "-", style=wx.TE_PROCESS_ENTER, size=(12,-1))
		wx.EVT_TEXT_ENTER(self.main, self.setXOff.GetId(), self.doApplyOff)
		cbox.Add(self.setXOff, 1, wx.GROW|wx.ALIGN_CENTRE|wx.ALL, 5)
		cbox.Add(wx.StaticText(self.main, -1, "Y sca:"), 0, wx.ALIGN_CENTRE|wx.ALL, 5)
		self.setYscale = wx.TextCtrl(self.main, -1, "-", style=wx.TE_PROCESS_ENTER, size=(12,-1))
		wx.EVT_TEXT_ENTER(self.main, self.setYscale.GetId(), self.doApplyOff)
		cbox.Add(self.setYscale, 1, wx.GROW|wx.ALIGN_CENTRE|wx.ALL, 5)
		#self.applyOff = wx.Button(self.main, -1, " Apply ")
		#cbox.Add(self.applyOff, 1, wx.GROW|wx.ALIGN_CENTRE|wx.ALL, 5)
		#wx.EVT_BUTTON(self.main, self.applyOff.GetId(), self.doApplyOff)
		modes = self.modes.keys()
		self.chooseMode = wx.Choice(self.main, -1, choices=modes)
		self.load_saved_prefs()
		dvm=self.preferences["Default View Mode"]
		self.chooseMode.SetSelection(modes.index(dvm))
		self.inMode = dvm
		
		cbox.Add(self.chooseMode, 1, wx.GROW|wx.ALIGN_CENTRE|wx.ALL, 5)
		wx.EVT_CHOICE(self.main, self.chooseMode.GetId(), self.doSelectMode)
		
		
		self.mainSizer.Add(cbox, 0, wx.GROW|wx.ALIGN_CENTRE|wx.ALL, 5)
		#self.mainSizer.Fit(self.main) - segv in 2.5, seems unneeded and slow
		self.SetSize(wx.Size(800,600))
		
		self.graph.SetDropTarget(self.dropLoader)
		self.clear_attributes()
 		self.stdFileMenu()
		
		self.spm = mien.datafiles.dataproc.DVSignalMod(self)
		self.datapath="/"
		self.spm.makeMenus()
		self.load_saved_prefs()
	
	def has_nested_data(self):
		if self.preferences["Display Nested Data to Depth"]<1:
			return False
		if self.data.stype()=='group':
			return True
		nc=self.data.shape()[1]
		toomany=self.preferences.get("Use image mode for more than X channels", 60)
		if nc>toomany:
			return False
		dats=self.data.getElements('Data', depth=1)
		dats=[d for d in dats if not "hidden" in d.name()]
		if dats:
			return True
		return False
	
	def w4(self, event=None):
		for p in self.graph.plots:
			self.graph.plots[p]['width']=4
		self.graph.DrawAll()
		
	def applyGraphConfig(self, conf):
		if not self.plotColors:
			GraphFSR.applyConfig(self.graph, conf, True)
		else:
			GraphFSR.applyConfig(self.graph, conf, False)
			self.graph.plots={}
			self.plotColors=self.graph.nextcolor(len(self.plotColors))
			self.display()
			
	
	def launchContrast(self, event):
		#reload(mien.datafiles.dataproc)
		x=mien.datafiles.dataproc.ContrastControl(self)
		x.Show(True)
	
	def loadSub(self, event=None):
		doc = self.load(returndoc=True)
		dat=doc.getElements('Data', depth=1)
		if not dat:
			self.report("No data instances in this document")
			return
		dat=dat[0]
		pl=[{"Name":"Name", "Value":dat.name()}]
		dp=self.data.getHierarchy().keys()
		if len(dp)>1:
			pl.append({"Name":"Add To Path", "Type":"List", "Value":dp})
		d=self.askParam(pl)
		if not d:
			return
		if len(d)==1:
			par=self.data
		else:
			par=self.data.getSubData(d[0])
		if d[0]!=dat.name():
			dat.setName(d[0])
		par.newElement(dat)
		q=dat.dpath()
		self.report('Added data with path %s' % q)
		self.onNewData()
	
	def addMark(self, event=None):
		d=self.askParam([{'Name':"Coordinate", 'Value':0.0},
				{'Name':'Orientation','Type':'List','Value':['X (Vertical)','Y (Horizontal)']},
				{'Name':'Use Index (not time. X only)', 'Type':'List', 'Value':['No', 'Yes']}])
		if not d:
			return
		color = self.graph.marker_color
		if d[1].startswith('Y'):
			self.graph.ymarkers.append({"loc":float(d[0]), "color":color})
		else:
			if d[2].startswith('N'):
				loc = float(d[0])
			else:
				loc = int(round(d[0]/self.data.fs()))
			self.graph.xmarkers.append({"loc":loc, "color":color})
		self.graph.drawMarkers()
	
	def onSetPreferences(self):
		if self.data:
			self.data.setUndoLength(self.preferences["Number of Undo Steps"], True)
		ic=self.preferences['Image Contrast']
		if type(ic)==list:
			if str(ic[0])=='Manual':
				self.preferences['Image Contrast']=tuple(ic[1:])
			elif str(ic[0]) in ["local", "global"]:
				self.preferences['Image Contrast']=str(ic[0])
		#if logical_xor(bool([x for x in self._channels if x[2][0]!='/']), self.has_nested_data()):
		self.onNewData()
		#else:
		#	self.display()
		self.report("Set Preferences")
	
	def clear_attributes(self, event=None):
		self.document=None
		self.selectedChan = "No channels loaded"
		self.data = None
		self._channels=[]
		self.offsets = {}
		self._datacache={}
		self.plotColors=[]
		self.graph.plots={}
	
	def spawnViewer(self, data=None, mode=None, zoom=True):
		if data and not mode:
			if isSampledType(data):
				mode='dv'
			elif data.stype()=='image':
				mode='image'
			else:
				mode=='locus'
		if mode=='dv':
			v=Dataviewer(self, returnData=self.dataImport)
			v.Show(True)
			v.dataImport(data, zoom=zoom)
		elif mode=='image':
			from mien.image.viewer import ImageViewer
			v=ImageViewer(self)
			if data:
				v.select(data)
		else:
			import mien.datafiles.fview
			v= mien.datafiles.fview.LocusViewer(self)
			v.Show(True)
			v.dataImport(data, zoom=zoom)
		return v
	
	def onNewData(self, zoom=False, remode=True):
		if not self.data or not self.data.__tag__=='Data':
			return
		self.datapath=self.data.upath()
		self._datacache={}
		if self.data.stype()=='image':
			self.spawnViewer(self.data, 'image')
			return
		if self.has_nested_data() or self.data.stype()!='timeseries':
			dep=int(self.preferences["Display Nested Data to Depth"])
			self._channels=getDataList(self.data, ['histogram', 'ensemble', 'events', 'labeledevents', 'timeseries'], dep, self.preferences["Hide Data In"], self.preferences['Show Only Same Length Data'])
		else:
			self._channels=[(str(x), 'timeseries', (self.data.dpath(),i)) for i, x in enumerate(self.data.getLabels())]
		if not self._channels:
			self.graph.killAll()
			self.report('no data that can be displayed')
			return
		if self.data.stype()=='group':
			dts = self.data.getSubData(self._channels[0][2][0])	
			self._channels[0][2] = ("/", self._channels[0][2][1]) 
			self.data.datinit(dts.data, dts.header())
			if dts.elements:
				dts.datinit(None, {"SampleType":'group'})
			else:
				dts.sever()
		nus=self.preferences["Number of Undo Steps"]
		self.data.setUndoLength(nus, True)
		if nus:
			self.data.logflags['undoCheckpoints']=True
			self.data.log_change('checkpoint')
		self.graph.fs = self.data.fs()
		if self.data.attrib('StartTime')==None:
			self.data.setAttrib('StartTime', 0.0, False)
		if zoom:
			t = domain(self.data)
			self.graph.limits[0] = t[0]
			self.graph.limits[1] = t[-1]
		offsets = self.offsets
		self.offsets = {}
		self.chooseChan.Clear()
		toomany=self.preferences.get("Use image mode for more than X channels", 60)
		if len(self._channels)>toomany:
			self.report("There are too many channels in this dataset. Forcing image view. Other view modes will fail")
			self.inMode="Image"
			self.display()
			return
		elif len(self._channels)!=len(self.plotColors):
			self.graph.plots={}
			self.plotColors=self.graph.nextcolor(len(self._channels))
		for c in self._channels:
			n=c[0]
			self.chooseChan.Append(n)
			if offsets.has_key(n):
				self.offsets[n] = offsets[n]
		if remode and self.modes.has_key(self.inMode):
		 	self.modes[self.inMode]()
		self.display()
	
	
	def update_self(self, **kwargs):
		event=kwargs.get('event', 'modify').lower()
		remode=kwargs.get('calc_offsets', True)
		for ob in self.getObjectsFromKWArgs(kwargs):
			#print event, remode, ob
			try:
				ndi=self.document.getInstance(self.datapath)
				if kwargs.get('event')=='delete':
					if od==ndi:
						raise StandardError('data has been removed from the document')
			except:
				self.data=None
				self.onNewData()
				return
			if not self.data==ndi:
				self.data=ndi
				self.onNewData()
				return
			if ob==self.data or ob==self.data.getTop() or ob==self.document:
				self.onNewData(remode=remode)
				return
			elif ob in self.data.getElements('Data'):
				if self.has_nested_data():
					self.onNewData(remode=remode)
					return
	
	
	def onNewDoc(self):
		self.data=None
		df=self.document.getElements('Data', depth=1)
		if not df:
			self.graph.killAll()
			self.report("There are no numerical data elements to display")
			return
		df, rem=df[0],df[1:]
		for d in rem:
			if self.preferences["On Multiple Open"]=="Merge":
				combineData(df, d, False)
			elif self.preferences["On Multiple Open"]=="Nest":
				if isSampledType(d)=='e':
					compatLength(df, d)
				d.move(df)
		fn=self.document.fileinformation['filename']
		if fn:
			self.SetTitle(fn)
		self.data = df
		s=self.data.stype()
		if s=='function' or (s in ['events', 'labledevents'] and not self.data.fs()):
			resample(self.data, None)
		elif s=='locus':
			self.spawnViewer(self.data, 'locus')
			self.data=None
			return
		checkd=	self.preferences['Checkpoint Directory']
		if not os.path.exists(checkd):
			os.mkdir(checkd)
		else:
			for f in os.listdir(checkd):
				os.unlink(os.path.join(checkd, f))
		self.onNewData(zoom=True)
	
	def changedat(self, event):
		df=self.document.getElements('Data', depth=1)
		if len(df)<2:
			self.report("There are no data elements to switch to")
			return
		dats=dict([(d.name(),d) for d in df])
		d=self.askUsr("Which element?", dats.keys())
		if d:
			self.data = dats[d]
			self.onNewData(zoom=True)
	
	def combinedat(self, event):
		df=self.document.getElements('Data', depth=1)
		if len(df)<2:
			self.report("There are no additional data elements to combine")
			return
		dats=dict([(d.name(),d) for d in df if d!=self.data])
		d=self.askParam([{'Name':"Which element?",
			'Type':'List', 'Value':dats.keys()},
			{'Name':'Mode','Type':'List','Value':['Nest','Merge']}])
		if not d:
			return
		nd=	dats[d[0]]
		if d[1]=="Merge":
			combineData(self.data, nd, False)
		else:
			if isSampledType(nd)=='e':
				compatLength(self.data, nd)
			nd.move(self.data)
		self.onNewData()
	
	def bindToData(self, data):
		self.document=data.xpath(True)[0]
		self.graph.killAll()
		self.data = data
		self.onNewData(zoom=True)
	
	def launchEditor(self, event=None):
		from mien.interface.main import MienGui
		d=MienGui(self)
		d.newDoc(self.document)
	
	def makeYSep(self, **kw):
		cranges = {}
		tr = 0
		for c in self._channels:
			off = self.offsets.get(c[0], (0.0,0.0,1.0))
			mi, ma=yrange(self.data, c[2])
			ma = ma*off[2]
			ra = ma-(mi*off[2])
			cranges[c[0]] = (ma, ra, off[2], off[1])
			tr += ra
		ran=array([[x[0]-x[1], x[0]] for x in cranges.values()])
		if self.preferences["Display Range"]!="local":
			self._datacache["range"]=(ran[:,0].min(), ran[:,1].max())
		pad = tr*.02
		if pad==0.0:
			pad=1.0
		ra = cranges[self._channels[0][0]]
		self.offsets[self._channels[0][0]] = (0.0, ra[3],ra[2])
		start = ra[0]-ra[1]-pad
		for c in self._channels[1:]:
			ra =  cranges[c[0]]
			off = start - ra[0]
			self.offsets[c[0]] = (off, ra[3],ra[2])
			start = start - ra[1] - pad
	
	def makeLSep(self, **kw):
		"""Generate offsets such that the currently displaped data will use the full vertical range of the graph."""
		st, sp= self. getCurrentView()
		ymin=self.graph.limits[2]
		ymax=self.graph.limits[3]
		r=ymax-ymin
		# print r
		cr=r/len(self._channels)
		#cr=10
		#co=0
		co=ymax
		for c in self._channels:
			off = self.offsets.get(c[0], (0.0,0.0,1.0))
			mi, ma=yrange(self.data, c[2], (st, sp))
			sca=cr/(ma-mi)
			co=co-ma*sca
			self.offsets[c[0]] = (co, off[1], sca)
			co=co+mi*sca
		self._datacache["range"]=(ymin, ymax)
	
	def setcheck(self, event=None, fn=None):
		checkd=	self.preferences['Checkpoint Directory']
		if not os.path.exists(checkd):
			os.mkdir(checkd)
		if fn:
			fn = os.path.join(checkd, fn)
		else:
			d=self.askParam([{'Name':'Checkpoint Name', 'Value':'CheckPoint%i' % (len(os.listdir(checkd)),)}])
			if not d:
				return
			fn = os.path.join(checkd, d[0])
		self.save(ask=False, fname=fn, subelement=self.data, format='mdat')
	
	def getcheck(self, event=None, fn=None):
		checkd=	self.preferences['Checkpoint Directory']
		if not os.path.exists(checkd):
			os.mkdir(checkd)
		files=os.listdir(checkd)
		if not files:
			self.report('No Checkpoints')
			return
		if not fn:
			d=self.askParam([{'Name':'Checkpoint Name', 'Type':'List', 'Value':files}])
			if not d:
				return
			fn = d[0]
		if not fn in files:
			self.report('Unknown Checkpoint')
			return
		fn=os.path.join(checkd, fn)
		doc=self.load(fname=fn, format='mdat', returndoc=True)
		dat=doc.getElements('Data')[0]
		self.data.mirror(dat, True)
		self.update_all(object=self.data)
	
	def makeQSep(self, **kw):
		if not self._datacache.get("range"):
			dat=self.data.getData()
			if 'events' in self.data.stype():
				self._datacache['range']=(0, 1)
			else:
				if self.preferences["Display Range"]!="local":
					st, sp= self.getCurrentView()
					self._datacache['range']=(dat[st:sp,:].min(), dat[st:sp,:].max())
				else:
					self._datacache['range']=(dat.min(), dat.max())
		mi, ma=self._datacache['range']
		off=float(ma)-mi
		for i, c in enumerate(self._channels):
			o=self.offsets.get(c[0], (0.0,0.0,1.0))
			self.offsets[c[0]]=(-1*i*off, o[1], o[2])
	
	def makeYover(self, **kw):
		for c in self._channels:
			off = self.offsets.get(c[0], (0.0,0.0,1.0))
			if 'events' in c[1] or c[1]=='histogram':
				me=0.0
			else:
				me = channel(self.data, c[2]).mean()*off[2]
			self.offsets[c[0]] = (-me, off[1] ,off[2])
	
	def xrange2index(self, sax, spx):
		if sax>spx:
			sax,spx=spx,sax
		if sax<=self.data.start():
			sa=0
		else:
			sa=(sax-self.data.start())*self.data.fs()
		sp=(spx-self.data.start())*self.data.fs()
		if sp>self.data.shape()[0]:
			sp=self.data.shape()[0]
		if sa>=sp:
			print "warning: view indexes out of range"
			return (0, self.data.shape()[0])
		return (round(sa),round(sp))
	
	def getCurrentView(self, index=True):
		if not index:
			return (self.graph.limits[0], self.graph.limits[1])
		else:
			return self.xrange2index(self.graph.limits[0], spx=self.graph.limits[1])
	
	def getMarkIndexes(self):
		mi=[x['loc'] for x in self.graph.xmarkers]
		if not mi:
			return array([])
		mi.sort()
		mi=(array(mi)-self.data.start())*self.data.fs()
		return round(mi)
	
	def equalize(self, mode):
		if mode=='n':
			for k in self.offsets.keys():
				v=self.offsets[k]
				self.offsets[k]=(v[0], v[1], 1.0)
		else:
			if mode=='l':
				ran=self.getCurrentView()
			else:
				ran=None
			cranges = {}
			for c in self._channels:
				off = self.offsets.get(c[0], (0.0,0.0,1.0))
				
				dmin, dmax = yrange(self.data, c[2], ran)
				ra = dmax - dmin
				sc=1.0
				if ra != 0:
					sc = 1.0/ra
				self.offsets[c[0]]=(off[0], off[1], sc)
		self.modes[self.inMode](eq=True)
		self.display()
				
	
	def zeroOffset(self, **kw):
		self.offsets={}
		self._datacache['range']=None
		self._datacache['limits']=None
		self.report("Removed all offsets")
	
	def asImage(self, **kw):
		pass
	
	def doSelectChannel(self, event):
		self.selectedChan = event.GetString()
		offsets = self.offsets.get(self.selectedChan, (0.0,0.0,1.0))
		for i, c in enumerate([self.setYOff, self.setXOff, self.setYscale]):
			c.SetValue(str(offsets[i]))
	
	def doSelectMode(self, event):
		import time; st=time.time()
		self.inMode= event.GetString()
		if self.modes.has_key(self.inMode):
			self.modes[self.inMode]()
		#print time.time()-st
		self.display()
	
	def	doApplyOff(self, event):
		self.report("Setting Offsets")
		offsets = []
		for c in [self.setYOff, self.setXOff, self.setYscale]:
			offsets.append(c.GetValue())
		try:
			offsets = tuple(map(float, offsets))
			self.offsets[self.selectedChan] = offsets
			self.display()
		except:
			self.report("All offsets must have float values")
	
	def selectChannels(self, event=None):
		chans= [x[0] for x in self._channels]
		l = self.askParam([{"Name":"Which Channels?",
							"Type":"Select",
							"Value":chans}])
		if not l or len(l[0])==0:
			return None
		else:
			return [chans.index(x) for x in l[0]]
	
	def markDiff(self, event=None):
		for var in [("X", self.graph.xmarkers), ("Y", self.graph.ymarkers)]:
			if var[1]:
				locs = [m['loc'] for m in var[1]]
				locs.sort()
				fl = locs[0]
				ll = fl
				self.report("%s Differences ----------" % var[0])
				self.report("Min X = %.8g" % fl)
				for l in locs[1:]:
					df = l - fl
					dl = l - ll
					ll = l
					self.report("%s=%.8g: %.8g from min, %.8g from previous" % (var[0], l, df, dl))


	
	def markLoc(self, event=None):
		rep = "\n"
		for m in self.graph.xmarkers:
			t = m['loc']
			i = xindex(self.data, t)
			rep+= "X Mark at %.12g (sample %i)\n" % (t, i)
		for m in self.graph.ymarkers:
			t = m['loc']
			rep+= "Y Mark at %.12g\n" % (t,)
		self.report(rep)
	
	def delChan(self, event=None):
		chans=self.selectChannels()
		if not chans:
			return
		chans=[self._channels[i][2] for i in chans]
		delChans(self.data, chans)
		self.onNewData()
	
	def undo(self, event=None):
		self.data.undo()
		self.onNewData()
	
	def redo(self, event=None):
		self.data.redo()
		self.onNewData()
	
	def crop(self, event=None):
		mode = self.askParam([{"Name":"Crop Mode",
								"Type":"List",
								"Value":["Delete before mark",
										 "Delete after mark",
										 "Crop to view",
										 "By x value",
										 "By sample index"]},
								{'Name':'Set Start Time To 0?',
								"Type":"List",
								"Value":["Yes", "No"]}])
		if not mode:
			return
		mode, reset=mode
		xmin = None
		xmax = None
		if mode == "Crop to view":
			xmin, xmax =  [xindex(self.data, x) for x in self.graph.limits[:2]]
		elif mode == "Delete before mark":
			try:
				xmin = xindex(self.data, self.graph.xmarkers[-1]["loc"])
				xmax=-1
			except:
				self.report("No Markers")
		elif mode == "Delete after mark":
			try:
				xmax = xindex(self.data, self.graph.xmarkers[-1]["loc"])
				xmin = 0
			except:
				self.report("No Markers")
		elif mode == "By x value":
			d=domain(self.data)
			l2 = self.askParam([{'Name':"Start",
								"Value":d[0]},
							   {'Name':"Stop",
								"Value":d[-1]}])
			if l2:
				xmin, xmax =  [xindex(self.data, x) for x in l2]
		elif mode == "By sample index":
			l2 = self.askParam([{'Name':"Start",
								 "Value":0},
								{'Name':"Stop",
								 "Value":self.data.shape()[0]}])
			if l2:
				xmin, xmax = l2
		if xmin==None or xmax==None:
			self.report("Limits not specified")
		else:
			dats=set([x[2][0] for x in self._channels])
			for d in dats:
				dat=self.data.getSubData(d)
				crop(dat, (xmin, xmax))
				if reset=="Yes":
					dat.setAttrib('StartTime', 0.0)
			self.onNewData()
			self.report("Crop complete")
	
	def blank(self, event=None):
		d=self.askParam([{"Name":"Length(s)",
						"Value":100.0},
						{"Name":"Fs (Hz)",
						"Value":10000.0},
						{"Name":"Channels",
						"Value":1}])
		if not d:
			return
		shape=(d[0]*d[1],d[2])
		if self.data:
			dat=zeros(shape, Float32)
			h={'SamplesPerSecond':d[1], 'Labels':["c%i" % i for i in range(shape[1])], 'SampleType':'timeseries'}
			self.data.datinit(dat, h)
		else:
			if not self.document:
				self.newDoc()
			data=blankTimeSeries(shape, {'Name':'new','SamplesPerSecond':d[1]})
			self.document.newElement(data)
			self.data=data
		self.onNewData()
		self.report("Generated Blank Data")
		
	
	def dataImport(self, df, add=False, zoom=False):
		if add and self.data:
			combineData(self.data, df, True)
		else:
			self.newDoc(None)
			self.data=df.clone()
			self.document.newElement(self.data)
			if not zoom:
				zoom=True
		if zoom=='never':
			zoom=False
		self.onNewData(zoom)
		self.report("Done Loading Data")
	
	def displayOther(self, notop=True):
		if self.preferences["Display Range"]!="manual":
			maxY = -100000000
			minY = 1111111111
			trackRange=True
		else:
			trackRange=False
		for i, chan in enumerate(self._channels):
			name, style, ref=chan
			if notop and ref[0]==self.data.dpath():
				continue
			data=channel(self.data, ref)
			opts={'name':name}
			opts['color']=self.plotColors[i][0]
			opts['dashStyle']=self.plotColors[i][1]
			offsets = self.offsets.get(name, (0.0, 0.0, 1.0))
			if 'events' in style:
				opts['style']='raster'
				opts['offset']=offsets[0]
				opts['width']=4
				opts['height']=offsets[2]
				if  trackRange:
					maxY = max(offsets[2], maxY)
					minY = min(offsets[0], minY)
				data=channel(self.data, chan[2])
				if data.shape[1]>2:
					opts['colormode']='periodic'
			elif style=='histogram':
				di=self.data.getSubData(ref[0])
				bin=di.attrib('BinWidth') or 20
				if type(bin)==float:
					bin=round(bin*di.fs())
				opts['offset']=offsets[0]
				opts['binwidth']=bin
				opts['scale']=offsets[2]
				opts['style']='hist'
				if  trackRange:
					maxY = max(offsets[2], maxY)
					minY = min(offsets[0], minY)
			else:
				if style=='ensemble':
					q=self.preferences['Ensemble display mode']
					if q=='Stats':
						me=reshape(mean(data, 1), (-1, 1))
						sd=reshape(std(data, 1), (-1, 1))
						data=concatenate([me-sd, me, me+sd], 1)
					elif q=='Mean':
						data=reshape(mean(data, 1), (-1, 1))
					elif q=='Overlay':
						pass
					elif q=='Sequential':
						r=(data.max(), data.min())
						r=transpose(resize(r, (data.shape[1],2)))
						data=vstack([data, r])
						data=reshape(transpose(data), (-1, 1))
					elif q == 'MeanAndCov':
						cv = cov(data)
						data = reshape(mean(data, 1), (-1, 1))
						strt = domain(self.data.getSubData(ref[0]))[0]+ offsets[1]
						cvst =  strt + data.shape[0]/self.data.fs()
						yp=(self.graph.limits[2],self.graph.limits[3]-self.graph.limits[2])
						self.graph.addPlot(cv, style="image", start=cvst, colorrange='local', offset=yp[0], height=yp[1])
					else:
						print "ensemble display disabled"
						continue
				opts['style'] = self.preferences['defaultPlotStyle']
				if 	offsets[2]!=1.0:
					data = data * offsets[2]
				if offsets[0]:
					data = data + offsets[0]
				if  trackRange:
					if self.preferences["Display Range"]=="global":
						maxY = max(data.max(), maxY)
						minY = min(data.min(), minY)
					elif self.preferences["Display Range"]=="local":
						st, sp= self.getCurrentView()
						maxY = max(data[st:sp,:].max(), maxY)
						minY = min(data[st:sp,:].min(), minY)
			opts['start'] = domain(self.data.getSubData(ref[0]))[0]+ offsets[1]
			pn=self.graph.addPlot(data, **opts)
		if trackRange:
			if 	self._datacache.get("limits"):
				mi ,ma=self._datacache["limits"]
				minY=min(minY, mi)
				maxY=max(maxY, ma)
			self._datacache["limits"]=(float(minY), float(maxY))
	
	
	def getImageData(self):
		scales=[]
		if not self.has_nested_data():
			dat=self.data.getData()
			scales=zeros((1, dat.shape[1]), dat.dtype)
			labs=self.data.getLabels()
			for i in range(dat.shape[1]):
				try:
					l=labs[i]
				except IndexError:
					l=None
				scales[0,i]=self.offsets.get(l, (0.0, 0.0, 1.0))[2]
			if any(scales!=1):
				dat=dat*scales
		else:
			dat=None
			ind=0
			for chan in self._channels:
				name, style, ref=chan
				if 'events' in style:
					evts=self.data.getSubData(ref[0])
					data=events2ts(evts, self.data.shape()[0], self.data.start())
					data=data.astype(Float32)
				else:
					data=channel(self.data, ref)
				if not ind:
					dat=data
				else:
					dat=concatenate([dat, data], 1)
				offsets = self.offsets.get(name, (0.0, 0.0, 1.0))
				if offsets[1]:
					oi=round(offsets[1]*self.data.fs())
					for i in range(ind, ind+data.shape[1]):
						dat[:,i]=shift(dat[:,i], oi)
				scales.extend([offsets[2]]*data.shape[1])
				ind+=data.shape[1]
			scales=array(scales)
			if any(scales!=1):
				dat=dat*scales
		return dat
	
	def displayImage(self):
		dat = self.getImageData()
		cr=self.preferences["Image Contrast"]
		yp=(self.graph.limits[2],self.graph.limits[3]-self.graph.limits[2])
		if self.data.attrib('imageYrange'):
			yp = self.data.attrib('imageYrange')
			self.graph.limit(array([0, self.data.data.shape[0]/self.data.fs(), yp[0], yp[0]+yp[1]]))
		if cr=="local":
			self.graph.addPlot(dat, style="image", start=self.data.start(), colorrange=cr, offset=yp[0], height=yp[1])
		else:
			if cr=="global":
				minval=dat.min()
				maxval=dat.max()
				m=maxval-minval
			else:
				minval, maxval = cr
				dat = where(dat<minval, minval, dat)
				m=maxval-minval
				dat = where(dat>maxval, maxval, dat)
			dat=dat-minval
			if m!=0:
				m=m/255.0
				dat=dat/m
			dat=dat.astype('b')
			self.graph.addPlot(dat, style="image", start=self.data.start(), rawbytes=True, offset=yp[0], height=yp[1])
	
	def displayBlock(self):
		chans=[x for x in self._channels if x[2][0] in ['/', self.data.dpath()]]
		if not chans:
			return
		names = [c[0] for c in chans]
		name= names[0]
		offsets=array([self.offsets.get(c[0], (0.0, 0.0, 1.0)) for c in chans])
		dat = self.data.getData(copy=False)
		if any(offsets[:,1]):
			dat=dat.copy()
			for ind in range(offsets.shape[0]):
				oi=round(offsets[ind,1]*self.data.fs())
				dat[:,ind]=shift(dat[:,ind], oi)
		offsets=offsets.take([0,2], 1)
		if self.preferences["Simple Subsample"]=='Yes':
			plfast=True
		else:
			plfast=False
		self.graph.addPlot(dat, style="polyline", start=self.data.start(), color=[c[0] for c in self.plotColors[:dat.shape[1]]], dashStyle=[c[1] for c in self.plotColors[:dat.shape[1]]], offsets=offsets, fastdraw=plfast, name=name, namelist=names)
		if not self._datacache.get("range"):
			if self.preferences["Display Range"]=="local":
				st, sp= self. getCurrentView()
				self._datacache['range']=(dat[:sp,:].min(), dat[st:sp,:].max())
			else:
				self._datacache['range']=(dat.min(), dat.max())
		mi, ma=self._datacache['range']
		self._datacache["limits"]=(mi+offsets[:,0].min(), ma+offsets[:,0].max())
	
	def display(self):
		#import time;st=time.time()
		self.graph.plots={}
		if self.inMode=="Image":
			self.displayImage()
		else:
			if self.data.stype()=='timeseries' and self.preferences['defaultPlotStyle']!="points":
				self.displayBlock()
				if self.has_nested_data():
					self.displayOther()
			else:
				self.displayOther(notop=False)
			if self.inMode!="Local Sep" and self.preferences["Display Range"]!="manual":
				if not 	self._datacache.get("limits"):
					self._datacache["limits"]=[-1, 2]
				minY, maxY = self._datacache["limits"]
				pad = (maxY - minY)*.05
				if pad==0:
					pad=.01
				self.graph.limits[2] = 	float(minY-pad)
				self.graph.limits[3] = 	float(maxY+pad)
		self.graph.DrawAll()
Beispiel #5
0
class WFGui(BaseGui):
	def __init__(self, parent=None, **kwargs):
		nchans=kwargs.get('nchans', 2) 
		returnData=kwargs.get('returnData')
 		BaseGui.__init__(self, parent, title="Waveform Generator", menus = ["File", "Control"], pycommand=True,height=4)

		commands=[["File","New" , lambda x: self.new()],
				  ["File","Change Domain" ,self.resize],
 				  ["File","Play" , self.play],
 				  ["File","Save" ,lambda x: self.save(0)],
 				  ["File","Save As" , lambda x:self.save(1)],
				  ["File","----"],
				  ["File","Load Parameters" , self.load_params],
				  ["File","----"],
				  ["File", "Quit", lambda x:self.Destroy()],
				  ["Control", "Smoothing Points", self.set_smooth_points],
				  ["Control", "Fill dcl with silence", self.set_silent_fill],
				  ["Control","Refresh Display",lambda x: self.make_change()],
				  ["Control","Plot trajectory",self.trajectoryplot]]
		
		if returnData:
			self.returnDataMono=lambda x:returnData(self.dataExport(1))
			self.returnDataStereo=lambda x:returnData(self.dataExport(2))
			commands.insert(2, ["File", "Export Data (Mono)", self.returnDataMono])
			commands.insert(2, ["File", "Export Data (Stereo)", self.returnDataStereo])
			
		self.fillMenus(commands)
		id = wx.NewId()
		self.menus["Control"].AppendCheckItem(id, "Smooth Transitions")
		wx.EVT_MENU(self, id, self.change_smoothing)

		self.mainSizer = wx.BoxSizer(wx.HORIZONTAL)
		self.main.SetSizer(self.mainSizer)
		self.main.SetAutoLayout(True)
	
		self.graph=GraphFSR(self.main,-1)		
		self.mainSizer.Add(self.graph,1, wx.GROW|wx.ALIGN_CENTRE|wx.ALL, 5)
		
	   	self.display=self.display_cart
		
		vsizer2 = wx.BoxSizer(wx.VERTICAL)
		self.channels=[]
		self.controls=[]

		for s in range(nchans):
			control=ChannelControls(self.main,self, "Channel %i" % s)
			vsizer2.Add(control, 1, wx.GROW|wx.ALIGN_CENTRE|wx.ALL, 5)
			control.report=self.report
			control.make_change=self.make_change
			self.controls.append(control)
			self.channels.append(None)
		self.mainSizer.Add(vsizer2,1, wx.GROW|wx.ALIGN_CENTRE|wx.ALL, 5)
		
		self.filename=None
		self.savetype = None
		self.smoothpoints=50
		self.silent_fill=(0,0)
	   		
		self.mainSizer.Fit(self.main)
		self.SetSize(wx.Size(800,600))
		self.new(1.0, .00005)
		
	def set_silent_fill(self, event=None):
		d=self.askParam([{"Name":"Seconds of silence",
						  "Value":2.0},
						 {"Name":"Offset",
						  "Value":0.0}])
		if not d:
			return
		self.silent_fill=tuple(d)

	def dataExport(self, Channels=2):
		self.evaluate()
		self.fillResults()
		a=self.results.astype(Float32)
		if Channels==1:
			a=reshape(a[:,0], (-1,1))
		h = {"Labels":map(str, range(a.shape[1])),
			 "SamplesPerSecond":str(1.0/self.sampling)}
		return DataSet(a, h)
		
		
	def set_smooth_points(self, event=None):
		d=self.askParam([{"Name":"Number of points",
							   "Value":self.smoothpoints}])
		if not d:
			return
		self.smoothpoints=d[0]
		self.report("set number of smoothing points to %i" % self.smoothpoints)
		if self.smoothing:
			for c in self.channels:
				c.smoothing=self.smoothpoints
			self.make_change()	

	def trajectoryplot(self, event=None):
		bar = {'size':(400,400), 'style':wx.DEFAULT_FRAME_STYLE|wx.NO_FULL_REPAINT_ON_RESIZE}
		tp = wx.Frame(self, -1, "Trajectory Plot", **bar)
		tp.g=Graph(tp, -1)
		tp.g.fixAR = 1.0
		tp.Show(True)
		self.evaluate()
		l=self.graph.limits
		if l[0]>0:
			st = int(l[0]/self.sampling)
		else:
			st=0
			
		if l[1]<self.duration:
			sp =int(l[1]/self.sampling)
		else:
			sp = -1
		a=self.results[st:sp,:2]
		tp.g.addPlot(a, name="Trajectory")
		tp.g.fullScale()
		tp.g.DrawAll()
		
			
	def change_smoothing(self, event):
		if event.IsChecked():
			for c in self.channels:
				c.smoothing=self.smoothpoints
		else:
			for c in self.channels:
				c.smoothing=0
		self.make_change()	

	def make_change(self):
		self.display()
		
	def new(self, duration=None, sampling=None):
		if not duration:
			d=self.askParam([{"Name":"Duration(sec)",
							  "Value":0.2},
							 {"Name":"Sampling Rate(Hz)",
							  "Value":10000.0}])
			if not d:
				return
			self.duration=d[0]
			self.sampling=1.0/d[1]
		else:
			self.duration=duration
			self.sampling=sampling
		for s in range(len(self.channels)):
			self.channels[s]=Funcgen((0, self.duration, self.sampling))
			self.controls[s].set(self.channels[s])
		self.report("New Waveform: %.5f seconds at %.3f Hz" % (self.duration, 1/self.sampling))
		xp = self.duration*.05
		self.graph.fs = 1.0/self.sampling
		self.graph.limit(array([-xp, self.duration+xp, -2, 2]))
		self.display()
		self.filename=None

	def resize(self, event=None):
		d=self.askParam([{"Name":"Duration(sec)",
						  "Value":	self.duration},
						 {"Name":"Sampling Rate(Hz)",
						  "Value":1.0/self.sampling}])
		if not d:
			return
		self.duration=d[0]
		self.sampling=1.0/d[1]
		for s in range(len(self.channels)):
			self.channels[s].set_domain((0, self.duration, self.sampling))
		self.report("New duration: %.5f s, New sampling: %.3f Hz" % (self.duration, 1/self.sampling))
		xp = self.duration*.05
		self.graph.limit(array([-xp, self.duration+xp, -2, 2]))
		self.display()
		
	def evaluate(self):
		self.results=map(lambda x: x.generate(), self.channels)
		self.results=array(self.results)
		self.results=transpose(self.results)


	def fillResults(self):	
		if self.silent_fill[0]:
			fill=zeros((int(self.silent_fill[0]/self.sampling), self.results.shape[1]), self.results[0].dtype.char)
			fill = fill + self.silent_fill[1]
			self.results = concatenate([fill, self.results, fill])
		

	def play(self, event=None):
		self.evaluate()
		playArray(self.results, int(1.0/self.sampling))	

   	def save(self, ask):
		if ask or not self.filename:
			if self.filename:
				dir = os.path.split(self.filename)[0]
			else:
				dir = ""
			dlg=wx.FileDialog(self, message="Select file name", defaultDir=dir, wildcard="Parameters | *.param| Wave | *.wav | Stimulus | *.dcl | Stimulus (Channel 0 only) | *.scl | Matlab | *.mat | Python |*.pydat ", style=wx.SAVE)
			dlg.CenterOnParent()
			if dlg.ShowModal() == wx.ID_OK:
				self.filename=dlg.GetPath()
				self.savetype = dlg.GetFilterIndex()
			else:
				self.report("Canceled File Save.")
				return
		self.evaluate()
		if self.savetype == 0:
			if not self.filename.endswith(".param"):
				self.filename+=".param"
			self.save_params(self.filename)
		elif self.savetype == 1:
			if not self.filename.endswith(".wav"):
				self.filename+=".wav"
			array2wav(self.results, int(1.0/self.sampling), self.filename)
		elif self.savetype == 2:
			if not self.filename.endswith(".dcl"):
				self.filename+=".dcl"
			self.fillResults()
			writeFile(self.filename, self.results, {}, "dcl")
		elif self.savetype == 3:
			if not self.filename.endswith(".scl"):
				self.filename+=".scl"
			self.fillResults()
			writeFile(self.filename, reshape(self.results[:,0], (-1, 1)), {}, "scl")	
		elif self.savetype == 4:
			if not self.filename.endswith(".mat"):
				self.filename+=".mat"
			head = {"SamplesPerSecond":1.0/self.sampling}
			self.fillResults()
			writeFile(self.filename, self.results, head, "mat")	
		elif self.savetype == 5:
			if not self.filename.endswith(".pydat"):
				self.filename+=".pydat"
			head = {"SamplesPerSecond":1.0/self.sampling}
			self.fillResults()
			writeFile(self.filename, self.results, head, "pydat")	
		
	def save_params(self, file):
		par={}
		par["Duration"]=self.duration
		par["Sample Period"]=self.sampling
		par["Channels"]=[]
		for i in range(len(self.channels)):
			c={}
			c["Envelopes"]=self.channels[i].envelopes
			c["Waves"]=self.channels[i].waves
			par["Channels"].append(c)
		
		open(file, 'w').write(repr(par))

				
	def load_params(self, event=None):
		if self.filename:
			dir = os.path.split(self.filename)[0]
		else:
			dir = ""
		dlg=wx.FileDialog(self, message="Select file", defaultDir=dir, wildcard="*.param", style=wx.OPEN)
		dlg.CenterOnParent()
		if dlg.ShowModal() == wx.ID_OK:
			fname=dlg.GetPath()
		else:
			self.report("Canceled File Load.")
		   	return
		pars=eval(open(fname).read())
		self.new(pars['Duration'], pars['Sample Period'])
		for i in range(len(pars["Channels"])):
			if i>len(self.channels):
				self.report("File specifies more than the supported number of channels")
				break
			c=pars["Channels"][i]
			self.channels[i].envelopes=c["Envelopes"]
			self.channels[i].waves=c["Waves"]
			self.controls[i].set(self.channels[i])
		self.make_change()
		self.filename=fname.split('.')[0]

	def display_cart(self):
		self.evaluate()
   		self.graph.plots = {}
		for i in range(self.results.shape[1]):
			dat = self.results[:,i]
			self.graph.addPlot(dat, "Channel %i" % i, style = "envelope")
		self.graph.DrawAll()