Пример #1
0
class EMEulerExplorer(EM3DSymModel,Animator):

	def mousePressEvent(self,event):
		if self.events_mode == "inspect":
			self.current_hit = self.get_hit(event)
			if self.current_hit == None:
				EM3DSymModel.mousePressEvent(self,event)
		else:
			EM3DSymModel.mousePressEvent(self,event)

	def mouseReleaseEvent(self,event):
		if self.events_mode == "inspect":
			if self.current_hit != None:
				self.updateGL() # there needs to be a clear or something  in order for the picking to work. This is  bit of hack but our rendering function doesn't take long anyhow
				hit = self.get_hit(event)
				if hit == self.current_hit:
					self.emit(QtCore.SIGNAL("point_selected"),self.current_hit,event)
			else:
				#EM3DSymModel.mouseReleaseEvent(self,event)
				EM3DModel.mouseReleaseEvent(self, event) #behavior in EM3DSymModel is not what we want (needed in sibling classes?)

			self.current_hit = None
		else:
				#EM3DSymModel.mouseReleaseEvent(self,event)
				EM3DModel.mouseReleaseEvent(self, event) #behavior in EM3DSymModel is not what we want (needed in sibling classes?)


	def mouseMoveEvent(self,event):
		if self.events_mode == "inspect" and self.current_hit:
			pass
		else:
			EM3DSymModel.mouseMoveEvent(self,event)

	def get_hit(self,event):
		v = self.vdtools.wview.tolist()
		self.get_gl_widget().makeCurrent() # prevents a stack underflow
#		x = event.x()
#		y = v[-1]-event.y()
#		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT )
#		vals = self.render(color_picking=True)
#		glFlush()
#		vv = glReadPixels(x,y,1,1,GL_RGB,GL_FLOAT)
#		reslt = Vec3f(float(vv[0][0][0]),float(vv[0][0][1]),float(vv[0][0][2]))
#		for i,val in enumerate(vals):
##			print val,reslt,(reslt-val).length(),vv[0][0]
#			if (reslt-val).length() < 0.01:
#				print i
##				print (reslt-val).length()
#				return i
#		print vv
#
		# the problem with this approach is that depth testing is not part of picking
		sb = [0 for i in xrange(0,512)]
		glSelectBuffer(512)
		glRenderMode(GL_SELECT)
		glInitNames()
		glMatrixMode(GL_PROJECTION)
		glPushMatrix()
		glLoadIdentity()
		gluPickMatrix(event.x(),v[-1]-event.y(),5,5,v)
		self.get_gl_widget().load_perspective()
		glMatrixMode(GL_MODELVIEW)
		glInitNames()
		self.render()
		glMatrixMode(GL_PROJECTION)
		glPopMatrix()
		glMatrixMode(GL_MODELVIEW)
		glFlush()

		intersection = None
		hits = list(glRenderMode(GL_RENDER))
		for hit in hits:
			a,b,c=hit
			if len(c) > 0:
				intersection = c[0]-1
				break

		return intersection


	def keyPressEvent(self,event):

		if event.key() == Qt.Key_F1:
			self.display_web_help("http://blake.bcm.edu/emanwiki/EMAN2/Programs/e2eulerxplor")
		elif event.key() == Qt.Key_F :
			if self.flatten>0 : self.flatten=0.0
			else: self.flatten=1.0
			self.generate_current_display_list(True)
			self.updateGL()
		else:
			EM3DSymModel.keyPressEvent(self,event)

	def __init__(self, gl_widget=None, auto=True,sparse_mode=False, file_name = "", read_from=None):
		self.current_hit = None
		self.events_mode_list = ["navigate", "inspect"]
		self.events_mode = self.events_mode_list[1]

		self.init_lock = True # a lock indicated that we are still in the __init__ function
		self.au_data = None # This will be a dictionary, keys will be refinement directories, values will be something like available iterations for visual study
		if len(read_from)==0:
			read_from=None
		self.readfrom=read_from
		if self.readfrom:
			
			file_name=""
			auto=False
			datalst=[]
			for rr in self.readfrom:
				datalst.append([rr,None, None, None,rr])
			self.au_data={"data":datalst}

		if auto: # this a flag that tells the eulerxplorer to search for refinement data and automatically add elements to the inspector, if so
			self.gen_refinement_data()
		
		EM3DSymModel.__init__(self, gl_widget, eulerfilename=file_name)
		Animator.__init__(self)
		self.height_scale = 8.0 # This is a value used in EM3DSymModel which scales the height of the displayed cylinders - I made it 8 because it seemed fine. The user can change it anyhow
		self.projection_file = None  # This is a string - the name of the projection images file
		self.average_file = None # This is a string - the name of the class averages file
		self.proj_class_viewer = None # This will be an EMImageMXWidget that shows the class and/or projection
		self.particle_viewer = None  # This will be an EMImageMXWidget that shows the particles in a class
		self.clsdb = None # I think this will become redundant - it used to be the old database that stores which particles are in a class, but now that's stored in the header
		self.particle_file = None # This will be a string - the name of the file that has the particle files in it. This might be made redundant with the new approach
		self.alignment_file = None # This will be a string - the name of the file containing the alignment parameters - this is essential if you we want to show the aligned particles
		self.refine_dir = None # This will be a string - the name of the current refinement directory that is being studied
		self.dx = None # This is an EMData object storing the x shifts of the alignments for all particles. Generated by e2classaverage
		self.dy = None # This is an EMData object storing the y shifts of the alignments for all particles. Generated by e2classaverage
		self.da = None# This is an EMData object storing the angle of the alignments for all particles. Generated by e2classaverage
		self.dflip = None # This is an EMData object storing whether or not tthe alignment involved a flip, for all particles. Generated by e2classaverage
		self.classes = None # This is an EMData object storing which class(es) a particle belongs to. Generated by e2classaverage
		self.inclusions = None # This is and EMDAta storing a boolean that indicates the particle was actually included in the final average. Generated by e2classaverage

		self.average = None # This the class average itself, an EMData object
		self.projection = None # This is the projection itelse, an EMData object
		self.class_idx = None # This is the idx of the current class being studied in the interface

		self.previous_len = -1 # To keep track of the number of class averages that were previously viewable. This helps to make sure we can switch to the same class average in the context of a different refinement iteration
		self.mirror_eulers = False
		if sparse_mode:
			self.mirror_eulers = True # If True the drawn Eulers are are also rendered on the opposite side of the sphere - see EM3DSymModel.make_sym_dl_lis

		# Grab the symmetry from the workflow database if possible
		sym = "c1"
		if js_check_dict("refine_01/0_refine_parms.json"):
			try: sym = str(js_open_dict("refine_01/0_refine_parms.json")["sym"])
			except: pass

		# Have to tell the EM3DSymModel that there is a new sym
		self.set_symmetry(sym)

		# this object will have
		if self.au_data != None:
			combo_entries = self.au_data.keys()
			combo_entries.sort()
			combo_entries.reverse()

			if len(combo_entries) > 0:
				au = combo_entries[0]
				cls = self.au_data[au][0][0]
				self.au_selected(au,cls)
				self.mirror_eulers = True

		self.init_lock = False
		self.force_update=True # Force a display udpdate in EMImage3DSymModule

		QtCore.QObject.connect(self, QtCore.SIGNAL("point_selected"), self.au_point_selected)

	def __del__(self):
		EM3DSymModel.__del__(self) # this is here for documentation purposes - beware that the del function is important

	def initializeGL(self):
		glEnable(GL_NORMALIZE)

	def generate_current_display_list(self,force=False):
		'''
		Redefinition of EMImage3DSymModule.generate_current_display_list

		'''
		if self.init_lock: return 0
		if self.au_data == None or len(self.au_data) == 0:
			EM3DSymModel.generate_current_display_list(self,force)

		self.init_basic_shapes()
		if self.nomirror == True : val = 0
		else: val = 1
		self.trace_great_arcs(self.sym_object.get_asym_unit_points(val))
		self.trace_great_triangles(val)

		self.eulers = self.specified_eulers
		if self.eulers == None:	return 0

#		if not self.colors_specified: self.point_colors = []
#		else: self.point_colors = self.specified_colors
#		self.points = []
#		for i in self.eulers:
#			p = i.transpose()*Vec3f(0,0,self.radius)
#			self.points.append(p)
#			if not self.colors_specified: self.point_colors.append((0.34615, 0.3143, 0.0903,1))

		self.make_sym_dl_list(self.eulers)
		return 1
	def get_data_dims(self):
		return (2*self.radius,2*self.radius,2*self.radius)

	def width(self): return 2*self.radius
	def height(self): return 2*self.radius
	def depth(self): return 2*self.radius

	def gen_refinement_data(self):
		dirs,files = get_files_and_directories()

		dirs.sort()
		for i in range(len(dirs)-1,-1,-1):
			if dirs[i][:7] != "refine_" and dirs[i][:6]!="multi_" and dirs[i][:11]!="multinoali_":
				dirs.pop(i)
			else:
				try: int(dirs[i][7:])
				except: dirs.pop(i)

		self.dirs = dirs
		print(dirs)

		self.au_data = {}
		for dir in self.dirs:
			d = self.check_refine_db_dir(dir)
			if len(d) != 0 and len(d[dir]) != 0: self.au_data.update(d)

	def check_refine_db_dir(self,dir,s1="classes",s2=None,s3="cls_result",s4="threed",s5="projections"):
		# s2 used to be class_indices
		names = [s1,s2,s3,s4,s5]
		data = {}
		data[dir] = []
		register_js_name = "{}/0_refine_parms.json".format(dir)

		files=os.listdir(dir)
		
		try:
			nums=[int(i[7:9]) for i in files if "threed" in i and "even" not in i and "odd" not in i]
			maxnum=max(nums)
		except :
			print("Nothing in ",dir)
			return {}

		for i in xrange(1,maxnum+1):
			exte="_{:02d}_even.hdf".format(i)
			exto="_{:02d}_odd.hdf".format(i)
			data[dir].append([sadd(dir,s1,exte),sadd(dir,s2,exte),sadd(dir,s3,exte),sadd(dir,s4,exte),sadd(dir,s5,exte)])
			data[dir].append([sadd(dir,s1,exto),sadd(dir,s2,exto),sadd(dir,s3,exto),sadd(dir,s4,exto),sadd(dir,s5,exto)])

		return data

	def set_projection_file(self,projection_file): self.projection_file = projection_file
	def get_inspector(self):
		if not self.inspector :
			if (self.au_data == None or len(self.au_data) == 0) and self.mirror_eulers == False: #self.mirror_eulers thing is a little bit of a hack, it's tied to the sparse_mode flag in the init function, which is used by euler_display in EMAN2.py
				self.inspector=EMAsymmetricUnitInspector(self,True,True)
			else:
				self.inspector=EMAsymmetricUnitInspector(self)
			QtCore.QObject.connect(self.inspector,QtCore.SIGNAL("au_selected"),self.au_selected)
		return self.inspector


	def au_selected(self,refine_dir,cls):
		self.refine_dir = refine_dir
		get_application().setOverrideCursor(Qt.BusyCursor)
		data = []
		for d in self.au_data[refine_dir]:
			if d[0] == cls:
				data = d;
				break

		if len(data) == 0:
			error("error, no data for %s %s, returning" %(refine_dir,cls))
#			print "error, no data for",au,cls,"returning"
			self.events_handlers["inspect"].reset()
			get_application().setOverrideCursor(Qt.ArrowCursor)
			return
		
		if not self.readfrom:
			try :
				self.particle_file=js_open_dict(refine_dir+"/0_refine_parms.json")["input"]
			except:
				error("No data in "+refine_dir )
				self.events_handlers["inspect"].reset()
				get_application().setOverrideCursor(Qt.ArrowCursor)
				return

		self.average_file = cls
		self.projection_file = data[4]
		self.alignment_file = data[2]
		self.clsdb = data[1]

		self.dx = None
		self.dy = None
		self.da = None
		self.dflip = None
		self.classes = None

		eulers = get_eulers_from(self.average_file)
		#s = Symmetries.get("d7")
		#eulers = s.gen_orientations("rand",{"n":EMUtil.get_image_count(self.average_file)})

		self.specify_eulers(eulers)
		#from emimagemx import EMDataListCache
		#a = EMData.read_images(self.average_file)
		#a = [test_image() for i in range(EMUtil.get_image_count(self.average_file))]
		#print len(a),len(eulers)
		#b = [a[i].set_attr("xform.projection",eulers[i]) for i in range(len(eulers))]
		#b = [a[i].set_attr("ptcl_repr",1) for i in range(len(eulers))]

		self.set_emdata_list_as_data(EMLightWeightParticleCache.from_file(self.average_file),"ptcl_repr")
		#self.set_emdata_list_as_data(EMDataListCache(self.average_file),"ptcl_repr")
#		self.set_emdata_list_as_data(a,"ptcl_repr")
		self.force_update = True
		self.au_point_selected(self.class_idx,None)
		# if we have the same number of Eulers we can update everything
#		if self.previous_len == len(eulers) : self.events_handlers["inspect"].repeat_event()
#		else:self.events_handlers["inspect"].reset()
		self.previous_len = len(eulers)
		if not self.init_lock:self.updateGL()
		get_application().setOverrideCursor(Qt.ArrowCursor)

	def __get_file_headers(self,filename):
		headers = []
		n = EMUtil.get_image_count(filename)
		for i in range(n):
			e = EMData()
			e.read_image(filename,i,True)
			headers.append(e)
		return headers

	def au_point_selected(self,i,event=None):
		if self.readfrom:
			return
		if i == None:
			if event != None and event.modifiers()&Qt.ShiftModifier:
				if self.special_euler != None:
					self.special_euler = None
					if not self.init_lock:self.regen_dl()
			return
#		self.arc_anim_points = None
		self.projection = None
		if self.euler_data:
#			db = db_open_dict(self.average_file)
#			a = db.get(i)
#			print a["nx"]
#			print self.average_file,i
#			self.average = EMData(self.average_file,i)
#			self.average["nx"]
			self.average = self.euler_data[i]#
			self.projection = EMData(self.projection_file,self.average.get_attr("projection_image_idx"))
			self.average.process_inplace("normalize.toimage",{"to":self.projection})
			try:
				self.class_idx = self.average.get_attr("projection_image_idx")
				print("%d (%d)"%(self.class_idx,self.average["ptcl_repr"]))
			except:
				self.class_idx = -1
		else: return

		#if self.projection  == None and self.average == None: return
		first = False
		if self.proj_class_viewer == None:
			first = True
			self.proj_class_viewer = EMImageMXWidget(data=None,application=get_application())
#			self.proj_class_viewer = EMImage2DWidget(image=None,application=get_application())
			QtCore.QObject.connect(self.proj_class_viewer,QtCore.SIGNAL("module_closed"),self.on_mx_view_closed)
#			self.proj_class_viewer.set_mouse_mode("App" )
			QtCore.QObject.connect(self.proj_class_viewer,QtCore.SIGNAL("mx_image_selected"), self.mx_image_selected)
			get_application().show_specific(self.proj_class_viewer)

			self.proj_class_single = EMImage2DWidget(image=None,application=get_application())
			QtCore.QObject.connect(self.proj_class_single,QtCore.SIGNAL("module_closed"),self.on_mx_view_closed)
#			QtCore.QObject.connect(self.proj_class_single,QtCore.SIGNAL("mx_image_selected"), self.mx_image_selected)
			get_application().show_specific(self.proj_class_single)

		disp = []
		if self.projection != None: disp.append(self.projection)
		if self.average != None and self.projection!=None:
			# ok, this really should be put into its own processor
			#dataf = self.projection.do_fft()
			#apix=self.projection["apix_x"]
			#curve = dataf.calc_radial_dist(dataf["ny"], 0, 0.5,True)
			#curve=[i/(dataf["nx"]*dataf["ny"])**2 for i in curve]
			#xcurve=[i/(apix*2.0*dataf["ny"]) for i in range(len(curve))]
			#xyd=XYData()
			#xyd.set_xy_list(xcurve,curve)
			#filt=self.average.process("filter.setstrucfac",{"apix":apix,"strucfac":xyd})
			#filt.process_inplace("normalize.toimage",{"to":self.average})
			self.projection["apix_x"]=self.average["apix_x"]
			self.projection["apix_y"]=self.average["apix_y"]
			self.projection["apix_z"]=self.average["apix_z"]
			filt=self.projection.process("threshold.notzero")
			filt.mult(self.average)
			filt.process_inplace("filter.matchto",{"to":self.projection})

			disp.append(filt)

		if self.average!=None:
			disp.append(self.average)

		self.proj_class_viewer.set_data(disp)
		self.proj_class_single.set_data(disp)

		self.proj_class_viewer.updateGL()
		self.proj_class_single.updateGL()
		if self.particle_viewer != None:
			self.mx_image_selected(None,None)
		if first: self.proj_class_viewer.optimally_resize()

		if i != self.special_euler:
			self.special_euler = i
			self.force_update = True

		if not self.init_lock: self.updateGL()


	def on_mx_view_closed(self):
		self.proj_class_viewer = None
		self.proj_class_single = None

	def on_particle_mx_view_closed(self):
		self.particle_viewer = None

	def animation_done_event(self,animation):
		pass

	def alignment_time_animation(self,transforms):
		if len(transforms) < 2: return
		animation = OrientationListAnimation(self,transforms,self.radius)
		self.register_animatable(animation)

	def particle_selected(self,event,lc):
		if lc != None:
			d = lc[3]
			ptcl_idx = d["Img #"]
			data = self.au_data[self.refine_dir]
			prj = []
			cls_result = []
			for l in data:
				for s in l:
					stag = base_name(s)

					if len(stag) > 11 and stag[:11] == "projections":
						prj.append(s)
					elif len(stag) > 10 and stag[:10] == "cls_result":
						cls_result.append(s)

			transforms = []
			if len(prj) != len(cls_result): RunTimeError("The number of cls_result files does not match the number of projection files?")

			e = EMData()
			for i,cr in enumerate(cls_result):
				r = Region(0,ptcl_idx,1,1)
				e.read_image(cr,0,False,r)
				p = int(e.get(0))
				e.read_image(prj[i],p,True)
				transforms.append(e["xform.projection"])

			self.alignment_time_animation(transforms)

	def mx_image_selected(self,event,lc):
#		self.arc_anim_points = None
		get_application().setOverrideCursor(Qt.BusyCursor)
		if lc != None: self.sel = lc[0]

		if self.average != None:
			included = []
			if self.average.has_attr("class_ptcl_idxs"):
				included = self.average["class_ptcl_idxs"]
			excluded = []
			if self.average.has_attr("exc_class_ptcl_idxs"):
				excluded = self.average["exc_class_ptcl_idxs"]

			all = included + excluded
			#all.sort()

			bdata = []
			data = []
			idx_included = []
			running_idx = 0
			from emimagemx import ApplyAttribute
			for val in included:
				bdata.append([self.particle_file,val,[ApplyAttribute("Img #",val)]])
				idx_included.append(running_idx)
				running_idx += 1

			idx_excluded = []
			for val in excluded:
				bdata.append([self.particle_file,val,[ApplyAttribute("Img #",val)]])
				idx_excluded.append(running_idx)
				running_idx += 1

			data = EMLightWeightParticleCache(bdata)

			first = False
			if self.particle_viewer == None:
				first = True
				self.particle_viewer = EMImageMXWidget(data=None,application=get_application())
				self.particle_viewer.set_mouse_mode("App" )
				QtCore.QObject.connect(self.particle_viewer,QtCore.SIGNAL("module_closed"),self.on_particle_mx_view_closed)
				QtCore.QObject.connect(self.particle_viewer,QtCore.SIGNAL("mx_image_selected"), self.particle_selected)
				get_application().show_specific(self.particle_viewer)


			self.check_images_in_memory()

			if self.sel== 0 or self.alignment_file == None:
				self.particle_viewer.set_data(data)
			else:

				for i,[name,idx,f] in enumerate(bdata):
					index = -1
					if self.classes.get_xsize() == 1:
						index = 0 # just assume it's the first one - this is potentially fatal assumption, but in obscure situations only
					else:
						for j in range(self.classes.get_xsize()):
							if int(self.classes.get(j,idx)) == self.class_idx:
								index = j
								break
					if index == -1:
						print("couldn't find")
						get_application().setOverrideCursor(Qt.ArrowCursor)
						return

					x = self.dx.get(index,idx)
					y = self.dy.get(index,idx)
					a = self.da.get(index,idx)
					m = self.dflip.get(index,idx)

					t = Transform({"type":"2d","alpha":a,"mirror":int(m)})
					t.set_trans(x,y)
					from emimagemx import ApplyTransform
					f.append(ApplyTransform(t))
					#data[i].transform(t)
				self.particle_viewer.set_data(data)


			if first:
				self.particle_viewer.updateGL()
				self.particle_viewer.optimally_resize()

			self.particle_viewer.clear_sets(False)
			self.particle_viewer.enable_set("Excluded",idx_excluded,True,False)
			self.particle_viewer.enable_set("Included",idx_included,False,False)
			self.particle_viewer.updateGL()

			get_application().setOverrideCursor(Qt.ArrowCursor)

			self.updateGL()

	def check_images_in_memory(self):
		if self.alignment_file != None:
			if self.dx == None:
				self.dx = EMData(self.alignment_file,2)
			if self.dy == None:
				self.dy = EMData(self.alignment_file,3)
			if self.da == None:
				self.da = EMData(self.alignment_file,4)
			if self.dflip == None:
				self.dflip  = EMData(self.alignment_file,5)
			if self.classes == None:
				self.classes  = EMData(self.alignment_file,0)
			if self.inclusions == None:
				self.inclusions  = EMData(self.alignment_file,1)


	def set_events_mode(self,mode):
		if not mode in self.events_mode_list:
			print("error, unknown events mode", mode)
			return

		else:
			self.events_mode = mode

	def closeEvent(self,event):
		if self.inspector !=None: self.inspector.close()
		if self.proj_class_viewer !=None: self.proj_class_viewer.close()
		if self.proj_class_single !=None: self.proj_class_single.close()
		if self.particle_viewer != None: self.particle_viewer.close()
		get_application().close_specific(self)
		self.emit(QtCore.SIGNAL("module_closed")) # this signal is
Пример #2
0
class EMEulerExplorer(EM3DSymModel,Animator):

	def mousePressEvent(self,event):
		if self.events_mode == "inspect":
			self.current_hit = self.get_hit(event)
			if self.current_hit == None:
				EM3DSymModel.mousePressEvent(self,event)
		else:
			EM3DSymModel.mousePressEvent(self,event)

	def mouseReleaseEvent(self,event):
		if self.events_mode == "inspect":
			if self.current_hit != None:
				self.updateGL() # there needs to be a clear or something  in order for the picking to work. This is  bit of hack but our rendering function doesn't take long anyhow
				hit = self.get_hit(event)
				if hit == self.current_hit:
					self.emit(QtCore.SIGNAL("point_selected"),self.current_hit,event)
			else:
				#EM3DSymModel.mouseReleaseEvent(self,event)
				EM3DModel.mouseReleaseEvent(self, event) #behavior in EM3DSymModel is not what we want (needed in sibling classes?)

			self.current_hit = None
		else:
				#EM3DSymModel.mouseReleaseEvent(self,event)
				EM3DModel.mouseReleaseEvent(self, event) #behavior in EM3DSymModel is not what we want (needed in sibling classes?)


	def mouseMoveEvent(self,event):
		if self.events_mode == "inspect" and self.current_hit:
			pass
		else:
			EM3DSymModel.mouseMoveEvent(self,event)

	def get_hit(self,event):
		v = self.vdtools.wview.tolist()
		self.get_gl_widget().makeCurrent() # prevents a stack underflow
#		x = event.x()
#		y = v[-1]-event.y()
#		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT )
#		vals = self.render(color_picking=True)
#		glFlush()
#		vv = glReadPixels(x,y,1,1,GL_RGB,GL_FLOAT)
#		reslt = Vec3f(float(vv[0][0][0]),float(vv[0][0][1]),float(vv[0][0][2]))
#		for i,val in enumerate(vals):
##			print val,reslt,(reslt-val).length(),vv[0][0]
#			if (reslt-val).length() < 0.01:
#				print i
##				print (reslt-val).length()
#				return i
#		print vv
#
		# the problem with this approach is that depth testing is not part of picking
		sb = [0 for i in xrange(0,512)]
		glSelectBuffer(512)
		glRenderMode(GL_SELECT)
		glInitNames()
		glMatrixMode(GL_PROJECTION)
		glPushMatrix()
		glLoadIdentity()
		gluPickMatrix(event.x(),v[-1]-event.y(),5,5,v)
		self.get_gl_widget().load_perspective()
		glMatrixMode(GL_MODELVIEW)
		glInitNames()
		self.render()
		glMatrixMode(GL_PROJECTION)
		glPopMatrix()
		glMatrixMode(GL_MODELVIEW)
		glFlush()

		intersection = None
		hits = list(glRenderMode(GL_RENDER))
		for hit in hits:
			a,b,c=hit
			if len(c) > 0:
				intersection = c[0]-1
				break

		return intersection


	def keyPressEvent(self,event):

		if event.key() == Qt.Key_F1:
			self.display_web_help("http://blake.bcm.edu/emanwiki/EMAN2/Programs/e2eulerxplor")
		elif event.key() == Qt.Key_F :
			if self.flatten>0 : self.flatten=0.0
			else: self.flatten=1.0
			self.generate_current_display_list(True)
			self.updateGL()
		else:
			EM3DSymModel.keyPressEvent(self,event)

	def __init__(self, gl_widget=None, auto=True,sparse_mode=False, file_name = ""):
		self.current_hit = None
		self.events_mode_list = ["navigate", "inspect"]
		self.events_mode = self.events_mode_list[1]


		self.init_lock = True # a lock indicated that we are still in the __init__ function
		self.au_data = None # This will be a dictionary, keys will be refinement directories, values will be something like available iterations for visual study
		if auto: # this a flag that tells the eulerxplorer to search for refinement data and automatically add elements to the inspector, if so
			self.gen_refinement_data()

		EM3DSymModel.__init__(self, gl_widget, eulerfilename=file_name)
		Animator.__init__(self)
		self.height_scale = 8.0 # This is a value used in EM3DSymModel which scales the height of the displayed cylinders - I made it 8 because it seemed fine. The user can change it anyhow
		self.projection_file = None  # This is a string - the name of the projection images file
		self.average_file = None # This is a string - the name of the class averages file
		self.proj_class_viewer = None # This will be an EMImageMXWidget that shows the class and/or projection
		self.particle_viewer = None  # This will be an EMImageMXWidget that shows the particles in a class
		self.clsdb = None # I think this will become redundant - it used to be the old database that stores which particles are in a class, but now that's stored in the header
		self.particle_file = None # This will be a string - the name of the file that has the particle files in it. This might be made redundant with the new approach
		self.alignment_file = None # This will be a string - the name of the file containing the alignment parameters - this is essential if you we want to show the aligned particles
		self.refine_dir = None # This will be a string - the name of the current refinement directory that is being studied
		self.dx = None # This is an EMData object storing the x shifts of the alignments for all particles. Generated by e2classaverage
		self.dy = None # This is an EMData object storing the y shifts of the alignments for all particles. Generated by e2classaverage
		self.da = None# This is an EMData object storing the angle of the alignments for all particles. Generated by e2classaverage
		self.dflip = None # This is an EMData object storing whether or not tthe alignment involved a flip, for all particles. Generated by e2classaverage
		self.classes = None # This is an EMData object storing which class(es) a particle belongs to. Generated by e2classaverage
		self.inclusions = None # This is and EMDAta storing a boolean that indicates the particle was actually included in the final average. Generated by e2classaverage

		self.average = None # This the class average itself, an EMData object
		self.projection = None # This is the projection itelse, an EMData object
		self.class_idx = None # This is the idx of the current class being studied in the interface

		self.previous_len = -1 # To keep track of the number of class averages that were previously viewable. This helps to make sure we can switch to the same class average in the context of a different refinement iteration
		self.mirror_eulers = False
		if sparse_mode:
			self.mirror_eulers = True # If True the drawn Eulers are are also rendered on the opposite side of the sphere - see EM3DSymModel.make_sym_dl_lis

		# Grab the symmetry from the workflow database if possible
		sym = "c1"
		if js_check_dict("refine_01/0_refine_parms.json"):
			try: sym = str(js_open_dict("refine_01/0_refine_parms.json")["sym"])
			except: pass

		# Have to tell the EM3DSymModel that there is a new sym
		self.set_symmetry(sym)

		# this object will have
		if self.au_data != None:
			combo_entries = self.au_data.keys()
			combo_entries.sort()
			combo_entries.reverse()

			if len(combo_entries) > 0:
				au = combo_entries[0]
				cls = self.au_data[au][0][0]
				self.au_selected(au,cls)
				self.mirror_eulers = True

		self.init_lock = False
		self.force_update=True # Force a display udpdate in EMImage3DSymModule

		QtCore.QObject.connect(self, QtCore.SIGNAL("point_selected"), self.au_point_selected)

	def __del__(self):
		EM3DSymModel.__del__(self) # this is here for documentation purposes - beware that the del function is important

	def initializeGL(self):
		glEnable(GL_NORMALIZE)

	def generate_current_display_list(self,force=False):
		'''
		Redefinition of EMImage3DSymModule.generate_current_display_list

		'''
		if self.init_lock: return 0
		if self.au_data == None or len(self.au_data) == 0:
			EM3DSymModel.generate_current_display_list(self,force)

		self.init_basic_shapes()
		if self.nomirror == True : val = 0
		else: val = 1
		self.trace_great_arcs(self.sym_object.get_asym_unit_points(val))
		self.trace_great_triangles(val)

		self.eulers = self.specified_eulers
		if self.eulers == None:	return 0

#		if not self.colors_specified: self.point_colors = []
#		else: self.point_colors = self.specified_colors
#		self.points = []
#		for i in self.eulers:
#			p = i.transpose()*Vec3f(0,0,self.radius)
#			self.points.append(p)
#			if not self.colors_specified: self.point_colors.append((0.34615, 0.3143, 0.0903,1))

		self.make_sym_dl_list(self.eulers)
		return 1
	def get_data_dims(self):
		return (2*self.radius,2*self.radius,2*self.radius)

	def width(self): return 2*self.radius
	def height(self): return 2*self.radius
	def depth(self): return 2*self.radius

	def gen_refinement_data(self):
		dirs,files = get_files_and_directories()

		dirs.sort()
		for i in range(len(dirs)-1,-1,-1):
			if len(dirs[i]) != 9:
				dirs.pop(i)
			elif dirs[i][:7] != "refine_":
				dirs.pop(i)
			else:
				try: int(dirs[i][7:])
				except: dirs.pop(i)

		self.dirs = dirs
		print dirs

		self.au_data = {}
		for dir in self.dirs:
			d = self.check_refine_db_dir(dir)
			if len(d) != 0 and len(d[dir]) != 0: self.au_data.update(d)

	def check_refine_db_dir(self,dir,s1="classes",s2=None,s3="cls_result",s4="threed",s5="projections"):
		# s2 used to be class_indices
		names = [s1,s2,s3,s4,s5]
		data = {}
		data[dir] = []
		register_js_name = "{}/0_refine_parms.json".format(dir)

		files=os.listdir(dir)
		try:
			nums=[int(i[7:9]) for i in files if "threed" in i and "even" not in i and "odd" not in i]
			maxnum=max(nums)
		except :
			print "Nothing in ",dir
			return {}

		for i in xrange(1,maxnum+1):
			exte="_{:02d}_even.hdf".format(i)
			exto="_{:02d}_odd.hdf".format(i)
			data[dir].append([sadd(dir,s1,exte),sadd(dir,s2,exte),sadd(dir,s3,exte),sadd(dir,s4,exte),sadd(dir,s5,exte)])
			data[dir].append([sadd(dir,s1,exto),sadd(dir,s2,exto),sadd(dir,s3,exto),sadd(dir,s4,exto),sadd(dir,s5,exto)])

		return data

	def set_projection_file(self,projection_file): self.projection_file = projection_file
	def get_inspector(self):
		if not self.inspector :
			if (self.au_data == None or len(self.au_data) == 0) and self.mirror_eulers == False: #self.mirror_eulers thing is a little bit of a hack, it's tied to the sparse_mode flag in the init function, which is used by euler_display in EMAN2.py
				self.inspector=EMAsymmetricUnitInspector(self,True,True)
			else:
				self.inspector=EMAsymmetricUnitInspector(self)
			QtCore.QObject.connect(self.inspector,QtCore.SIGNAL("au_selected"),self.au_selected)
		return self.inspector


	def au_selected(self,refine_dir,cls):
		self.refine_dir = refine_dir
		get_application().setOverrideCursor(Qt.BusyCursor)
		data = []
		for d in self.au_data[refine_dir]:
			if d[0] == cls:
				data = d;
				break

		if len(data) == 0:
			error("error, no data for %s %s, returning" %(refine_dir,cls))
#			print "error, no data for",au,cls,"returning"
			self.events_handlers["inspect"].reset()
			get_application().setOverrideCursor(Qt.ArrowCursor)
			return

		try :
			self.particle_file=js_open_dict(refine_dir+"/0_refine_parms.json")["input"]
		except:
			error("No data in "+refine_dir )
			self.events_handlers["inspect"].reset()
			get_application().setOverrideCursor(Qt.ArrowCursor)
			return

		self.average_file = cls
		self.projection_file = data[4]
		self.alignment_file = data[2]
		self.clsdb = data[1]

		self.dx = None
		self.dy = None
		self.da = None
		self.dflip = None
		self.classes = None

		eulers = get_eulers_from(self.average_file)
		#s = Symmetries.get("d7")
		#eulers = s.gen_orientations("rand",{"n":EMUtil.get_image_count(self.average_file)})

		self.specify_eulers(eulers)
		#from emimagemx import EMDataListCache
		#a = EMData.read_images(self.average_file)
		#a = [test_image() for i in range(EMUtil.get_image_count(self.average_file))]
		#print len(a),len(eulers)
		#b = [a[i].set_attr("xform.projection",eulers[i]) for i in range(len(eulers))]
		#b = [a[i].set_attr("ptcl_repr",1) for i in range(len(eulers))]

		self.set_emdata_list_as_data(EMLightWeightParticleCache.from_file(self.average_file),"ptcl_repr")
		#self.set_emdata_list_as_data(EMDataListCache(self.average_file),"ptcl_repr")
#		self.set_emdata_list_as_data(a,"ptcl_repr")
		self.force_update = True
		self.au_point_selected(self.class_idx,None)
		# if we have the same number of Eulers we can update everything
#		if self.previous_len == len(eulers) : self.events_handlers["inspect"].repeat_event()
#		else:self.events_handlers["inspect"].reset()
		self.previous_len = len(eulers)
		if not self.init_lock:self.updateGL()
		get_application().setOverrideCursor(Qt.ArrowCursor)

	def __get_file_headers(self,filename):
		headers = []
		n = EMUtil.get_image_count(filename)
		for i in range(n):
			e = EMData()
			e.read_image(filename,i,True)
			headers.append(e)
		return headers

	def au_point_selected(self,i,event=None):
		if i == None:
			if event != None and event.modifiers()&Qt.ShiftModifier:
				if self.special_euler != None:
					self.special_euler = None
					if not self.init_lock:self.regen_dl()
			return
#		self.arc_anim_points = None
		self.projection = None
		if self.euler_data:
#			db = db_open_dict(self.average_file)
#			a = db.get(i)
#			print a["nx"]
#			print self.average_file,i
#			self.average = EMData(self.average_file,i)
#			self.average["nx"]
			self.average = self.euler_data[i]#
			self.projection = EMData(self.projection_file,self.average.get_attr("projection_image_idx"))
			self.average.process_inplace("normalize.toimage",{"to":self.projection})
			try:
				self.class_idx = self.average.get_attr("projection_image_idx")
				print "%d (%d)"%(self.class_idx,self.average["ptcl_repr"])
			except:
				self.class_idx = -1
		else: return

		#if self.projection  == None and self.average == None: return
		first = False
		if self.proj_class_viewer == None:
			first = True
			self.proj_class_viewer = EMImageMXWidget(data=None,application=get_application())
#			self.proj_class_viewer = EMImage2DWidget(image=None,application=get_application())
			QtCore.QObject.connect(self.proj_class_viewer,QtCore.SIGNAL("module_closed"),self.on_mx_view_closed)
#			self.proj_class_viewer.set_mouse_mode("App" )
			QtCore.QObject.connect(self.proj_class_viewer,QtCore.SIGNAL("mx_image_selected"), self.mx_image_selected)
			get_application().show_specific(self.proj_class_viewer)

			self.proj_class_single = EMImage2DWidget(image=None,application=get_application())
			QtCore.QObject.connect(self.proj_class_single,QtCore.SIGNAL("module_closed"),self.on_mx_view_closed)
#			QtCore.QObject.connect(self.proj_class_single,QtCore.SIGNAL("mx_image_selected"), self.mx_image_selected)
			get_application().show_specific(self.proj_class_single)

		disp = []
		if self.projection != None: disp.append(self.projection)
		if self.average != None and self.projection!=None:
			# ok, this really should be put into its own processor
			#dataf = self.projection.do_fft()
			#apix=self.projection["apix_x"]
			#curve = dataf.calc_radial_dist(dataf["ny"], 0, 0.5,True)
			#curve=[i/(dataf["nx"]*dataf["ny"])**2 for i in curve]
			#xcurve=[i/(apix*2.0*dataf["ny"]) for i in range(len(curve))]
			#xyd=XYData()
			#xyd.set_xy_list(xcurve,curve)
			#filt=self.average.process("filter.setstrucfac",{"apix":apix,"strucfac":xyd})
			#filt.process_inplace("normalize.toimage",{"to":self.average})
			self.projection["apix_x"]=self.average["apix_x"]
			self.projection["apix_y"]=self.average["apix_y"]
			self.projection["apix_z"]=self.average["apix_z"]
			filt=self.projection.process("threshold.notzero")
			filt.mult(self.average)
			filt.process_inplace("filter.matchto",{"to":self.projection})

			disp.append(filt)

		if self.average!=None:
			disp.append(self.average)

		self.proj_class_viewer.set_data(disp)
		self.proj_class_single.set_data(disp)

		self.proj_class_viewer.updateGL()
		self.proj_class_single.updateGL()
		if self.particle_viewer != None:
			self.mx_image_selected(None,None)
		if first: self.proj_class_viewer.optimally_resize()

		if i != self.special_euler:
			self.special_euler = i
			self.force_update = True

		if not self.init_lock: self.updateGL()


	def on_mx_view_closed(self):
		self.proj_class_viewer = None
		self.proj_class_single = None

	def on_particle_mx_view_closed(self):
		self.particle_viewer = None

	def animation_done_event(self,animation):
		pass

	def alignment_time_animation(self,transforms):
		if len(transforms) < 2: return
		animation = OrientationListAnimation(self,transforms,self.radius)
		self.register_animatable(animation)

	def particle_selected(self,event,lc):
		if lc != None:
			d = lc[3]
			ptcl_idx = d["Img #"]
			data = self.au_data[self.refine_dir]
			prj = []
			cls_result = []
			for l in data:
				for s in l:
					stag = base_name(s)

					if len(stag) > 11 and stag[:11] == "projections":
						prj.append(s)
					elif len(stag) > 10 and stag[:10] == "cls_result":
						cls_result.append(s)

			transforms = []
			if len(prj) != len(cls_result): RunTimeError("The number of cls_result files does not match the number of projection files?")

			e = EMData()
			for i,cr in enumerate(cls_result):
				r = Region(0,ptcl_idx,1,1)
				e.read_image(cr,0,False,r)
				p = int(e.get(0))
				e.read_image(prj[i],p,True)
				transforms.append(e["xform.projection"])

			self.alignment_time_animation(transforms)

	def mx_image_selected(self,event,lc):
#		self.arc_anim_points = None
		get_application().setOverrideCursor(Qt.BusyCursor)
		if lc != None: self.sel = lc[0]

		if self.average != None:
			included = []
			if self.average.has_attr("class_ptcl_idxs"):
				included = self.average["class_ptcl_idxs"]
			excluded = []
			if self.average.has_attr("exc_class_ptcl_idxs"):
				excluded = self.average["exc_class_ptcl_idxs"]

			all = included + excluded
			#all.sort()

			bdata = []
			data = []
			idx_included = []
			running_idx = 0
			from emimagemx import ApplyAttribute
			for val in included:
				bdata.append([self.particle_file,val,[ApplyAttribute("Img #",val)]])
				idx_included.append(running_idx)
				running_idx += 1

			idx_excluded = []
			for val in excluded:
				bdata.append([self.particle_file,val,[ApplyAttribute("Img #",val)]])
				idx_excluded.append(running_idx)
				running_idx += 1

			data = EMLightWeightParticleCache(bdata)

			first = False
			if self.particle_viewer == None:
				first = True
				self.particle_viewer = EMImageMXWidget(data=None,application=get_application())
				self.particle_viewer.set_mouse_mode("App" )
				QtCore.QObject.connect(self.particle_viewer,QtCore.SIGNAL("module_closed"),self.on_particle_mx_view_closed)
				QtCore.QObject.connect(self.particle_viewer,QtCore.SIGNAL("mx_image_selected"), self.particle_selected)
				get_application().show_specific(self.particle_viewer)


			self.check_images_in_memory()

			if self.sel== 0 or self.alignment_file == None:
				self.particle_viewer.set_data(data)
			else:

				for i,[name,idx,f] in enumerate(bdata):
					index = -1
					if self.classes.get_xsize() == 1:
						index = 0 # just assume it's the first one - this is potentially fatal assumption, but in obscure situations only
					else:
						for j in range(self.classes.get_xsize()):
							if int(self.classes.get(j,idx)) == self.class_idx:
								index = j
								break
					if index == -1:
						print "couldn't find"
						get_application().setOverrideCursor(Qt.ArrowCursor)
						return

					x = self.dx.get(index,idx)
					y = self.dy.get(index,idx)
					a = self.da.get(index,idx)
					m = self.dflip.get(index,idx)

					t = Transform({"type":"2d","alpha":a,"mirror":int(m)})
					t.set_trans(x,y)
					from emimagemx import ApplyTransform
					f.append(ApplyTransform(t))
					#data[i].transform(t)
				self.particle_viewer.set_data(data)


			if first:
				self.particle_viewer.updateGL()
				self.particle_viewer.optimally_resize()

			self.particle_viewer.clear_sets(False)
			self.particle_viewer.enable_set("Excluded",idx_excluded,True,False)
			self.particle_viewer.enable_set("Included",idx_included,False,False)
			self.particle_viewer.updateGL()

			get_application().setOverrideCursor(Qt.ArrowCursor)

			self.updateGL()

	def check_images_in_memory(self):
		if self.alignment_file != None:
			if self.dx == None:
				self.dx = EMData(self.alignment_file,2)
			if self.dy == None:
				self.dy = EMData(self.alignment_file,3)
			if self.da == None:
				self.da = EMData(self.alignment_file,4)
			if self.dflip == None:
				self.dflip  = EMData(self.alignment_file,5)
			if self.classes == None:
				self.classes  = EMData(self.alignment_file,0)
			if self.inclusions == None:
				self.inclusions  = EMData(self.alignment_file,1)


	def set_events_mode(self,mode):
		if not mode in self.events_mode_list:
			print "error, unknown events mode", mode
			return

		else:
			self.events_mode = mode

	def closeEvent(self,event):
		if self.inspector !=None: self.inspector.close()
		if self.proj_class_viewer !=None: self.proj_class_viewer.close()
		if self.proj_class_single !=None: self.proj_class_single.close()
		if self.particle_viewer != None: self.particle_viewer.close()
		get_application().close_specific(self)
		self.emit(QtCore.SIGNAL("module_closed")) # this signal is
Пример #3
0
class ParticlesWindow:
	def __init__(self, rctwidget):
		self.rctwidget = rctwidget
		self.window=EMImageMXWidget(application=self.rctwidget.parent_window)
		self.window.set_display_values(["tilt","PImg#"])
		self.window.set_mouse_mode("App")
		self.window.setWindowTitle("Particles")
		self.window.optimally_resize()

		self.connect_signals()
		self.listsofparts = []
		self.numlists = 0
		self.closed = False
	
	def addlist(self, name):
		data = []
		data.append(name)
		data.append(0)
		data.append([])
		self.listsofparts.append(data)
		self.numlists = len(self.listsofparts)
		
	def update_particles(self, particles, idx):
		#print self.listsofparts[idx][0]
		# reset the relevent list of particles
		self.listsofparts[idx][1] = len(particles)
		self.listsofparts[idx][2] = particles

		# get the number of lists and the minimum number of particles in a given list..
		listlength = 1e308	
		for lst in self.listsofparts:
			listlength = min(listlength, lst[1])
		
		i = 0
		self.totparts = []
		for part in xrange(listlength):	
			for lst in xrange(self.numlists):
				self.listsofparts[lst][2][part].set_attr("tilt", self.listsofparts[lst][0])
				self.listsofparts[lst][2][part].set_attr("PImg#", part)
				self.totparts.append(self.listsofparts[lst][2][part])
				i += 1	
				
		if self.totparts != []:
			self.window.set_data(self.totparts)
			self.window.updateGL()
			
	def connect_signals(self):
		QtCore.QObject.connect(self.window,QtCore.SIGNAL("mx_image_selected"),self.box_selected)
		QtCore.QObject.connect(self.window,QtCore.SIGNAL("mx_mousedrag"),self.box_moved)
		QtCore.QObject.connect(self.window,QtCore.SIGNAL("mx_mouseup"),self.box_released)
		QtCore.QObject.connect(self.window,QtCore.SIGNAL("mx_boxdeleted"),self.box_image_deleted)
		QtCore.QObject.connect(self.window,QtCore.SIGNAL("module_closed"),self.module_closed)
			
	def box_selected(self,event,lc):
		if lc == None or lc[0] == None: return
		self.moving_box_data = [event.x(),event.y(),lc[0]]
	
	def box_moved(self,event,scale):
		winidx = self.moving_box_data[2] % self.numlists
		ppidx = int(self.moving_box_data[2]/self.numlists)
		if self.moving_box_data:
			dx = 0.2*(event.x() - self.moving_box_data[0])
			dy = 0.2*(self.moving_box_data[1] - event.y())
			self.rctwidget.windowlist[winidx].boxes.move_box(ppidx,dx,dy)
			self.rctwidget.windowlist[winidx].update_mainwin()
			self.rctwidget.windowlist[winidx].update_particles()
		
	def box_released(self, event,lc):
		pass
		
	def box_image_deleted(self,event,lc):
		if lc == None or lc[0] == None: return
		
		#delete all particle pairs
		ppidx = int(lc[0]/self.numlists)
		for i,window in enumerate(self.rctwidget.windowlist):
			window.boxes.remove_box(ppidx,self.rctwidget.boxsize)
			window.update_mainwin()
			window.update_particles()
		
	def module_closed(self):
		E2saveappwin("e2rctboxer","particles",self.window.qt_parent)
		pass