Beispiel #1
0
	def init(self):
		self.data=None

		self.mmode=0
		
		self.cam = Camera2(self)
		self.cube = False
		
		self.vdtools = EMViewportDepthTools(self)
		
		self.contrast = 1.0
		self.brightness = 0.0
		self.texsample = 1.0
		self.glcontrast = 1.0
		self.glbrightness = 0.0
		self.cube = False
		
		self.tex_name = 0
		
		self.rank = 1
		
		self.tex_dl = 0
		self.inspector=None
		
		self.force_texture_update = False

		self.glflags = EMOpenGLFlagsAndTools()		# OpenGL flags - this is a singleton convenience class for testing texture support
Beispiel #2
0
	def __init__(self,application=None,winid=None,parent=None):
		fmt=QtOpenGL.QGLFormat()
		fmt.setDoubleBuffer(True);
		EMGLWidget.__init__(self, parent=parent, winid=winid)
		self.setFormat(fmt)
		self.setWindowIcon(QtGui.QIcon(get_image_directory() +"plot.png"))
		self.axes={}
		self.pparm={}			# nbins,color,histtype,orient,align,alpha,width,norm,cumul,logy,stacked
		self.inspector=None
		self.needupd=1
		self.plotimg=None
		self.shapes={}
		self.bins = {}
		self.edges = None
		self.xlimits=None
		self.ylimits=None
		self.rmousedrag=None
		self.axisparms=(None,None,"linear","linear")
		self.selected=[]
		self.comments={}			# IF reading from a file which contains per-point comments, this dictionary contains a list of comments for each point
		self.data={}				# List of Lists to plot
		self.visibility = {}		# Same entries as in self.data, but entries are true or False to indicate visibility
		self.glflags = EMOpenGLFlagsAndTools() 	# supplies power of two texturing flags
		self.tex_name = 0
		self.main_display_list = 0
		self.resize(640,480)

		self.nbins = 10 # start with 10. user can modify via inspector.
		self.stacked = False #self.inspector.stacked.isChecked()
		self.normed=False #self.inspector.normed.isChecked()
		self.histtype="bar" #histtypes[self.inspector.histtype.currentIndex()]
		self.orientation="vertical" #orientations[self.inspector.orient.currentIndex()]
		self.alignment="edge" #alignments[self.inspector.align.currentIndex()]
		self.cumulative = False #self.inspector.cumulative.isChecked()
		self.logy = False #self.inspector.logtogy.isChecked()
Beispiel #3
0
	def __init__(self,target) :
		QtGui.QWidget.__init__(self,None)
		self.target=weakref.ref(target)
		self.setWindowIcon(QtGui.QIcon(get_image_directory() +"desktop.png"))
		
		self.vbl = QtGui.QVBoxLayout(self)
		self.vbl.setMargin(0)
		self.vbl.setSpacing(6)
		self.vbl.setObjectName("vbl")
		
		self.hbl = QtGui.QHBoxLayout()
		self.hbl.setMargin(2)
		self.hbl.setSpacing(6)
		self.hbl.setObjectName("hbl")
		
		#self.listwidget = QtGui.QListWidget(self)
		#self.vbl.addWidget(self.listwidget)
		
		self.tabwidget = QtGui.QTabWidget()
		
		self.hbl_check = QtGui.QHBoxLayout()
		self.hbl_check.setMargin(0)
		self.hbl_check.setSpacing(6)
		self.hbl_check.setObjectName("hbl_check")
		
		#self.advancedcheck = QtGui.QCheckBox("Advanced",self)
		#self.hbl_check.addWidget(self.advancedcheck)
		
		self.hbl_buttons = QtGui.QHBoxLayout()
		self.hbl_buttons.setMargin(0)
		self.hbl_buttons.setSpacing(6)
		self.hbl_buttons.setObjectName("hbl_buttons")
		
		self.hbl_buttons2 = QtGui.QHBoxLayout()
		self.hbl_buttons2.setMargin(0)
		self.hbl_buttons2.setSpacing(6)
		self.hbl_buttons2.setObjectName("hbl_buttons2")
		
		self.addIso = QtGui.QPushButton("Isosurface")
		self.hbl_buttons.addWidget(self.addIso)
		
		self.addVol = QtGui.QPushButton("Volume")
		self.hbl_buttons.addWidget(self.addVol)
		
		glflags = EMOpenGLFlagsAndTools()
		if glflags.npt_textures_unsupported(): self.addVol.setEnabled(False)
		
		self.addSli = QtGui.QPushButton("Slices")
		self.hbl_buttons2.addWidget(self.addSli)
		
		self.add_sym = QtGui.QPushButton("Sym")
		self.hbl_buttons2.addWidget(self.add_sym)

		self.vbl.addLayout(self.hbl_buttons)
		self.vbl.addLayout(self.hbl_buttons2)
		
		self.hbl_buttons3 = QtGui.QHBoxLayout()
		self.delete = QtGui.QPushButton("Delete")
		self.hbl_buttons3.addWidget(self.delete)
		self.vbl.addLayout(self.hbl_buttons3)
		
		self.vbl.addLayout(self.hbl_check)
		self.vbl.addWidget(self.tabwidget)
		
		self.advanced_tab = None
		
		self.currentselection = -1
		self.settingsrow = -2
		self.targetidxmap = {}

		self.insert_advance_tab()
		
		QtCore.QObject.connect(self.addIso, QtCore.SIGNAL("clicked()"), self.add_isosurface)
		QtCore.QObject.connect(self.addVol, QtCore.SIGNAL("clicked()"), self.add_volume)
		QtCore.QObject.connect(self.addSli, QtCore.SIGNAL("clicked()"), self.add_slices)
		QtCore.QObject.connect(self.add_sym, QtCore.SIGNAL("clicked()"), self.add_symmetry)
		QtCore.QObject.connect(self.delete, QtCore.SIGNAL("clicked()"), self.delete_selection)
Beispiel #4
0
class EM3DSliceModel(EM3DModel):
	
	def __init__(self, gl_widget, image=None):
		self.data = None
		EM3DModel.__init__(self, gl_widget)
		self.init()
		self.initialized = True
		
		self.inspector=None
	
		self.axes = []
		self.axes.append( Vec3f(1,0,0) )
		self.axes.append( Vec3f(0,1,0) )
		self.axes.append( Vec3f(0,0,1) )
		self.axes_idx = 2
		
		self.track = False
		self.bright = 0
		self.contrast = 1.0
		self.busy = True
		if image :
			self.set_data(image)
			
	def set_contrast(self,val):
		self.contrast = val
		self.generate_current_display_list()
		self.updateGL()
	def set_brightness(self,val):
		self.bright = val
		self.generate_current_display_list()
		self.updateGL()
		
#	def __del__(self):
#		print "slice died"
	
	def get_type(self):
		return "Slice Viewer"

	def init(self):
		self.data=None

		self.mmode=0
		self.cam = Camera2(self)
		
		self.vdtools = EMViewportDepthTools(self)
		
		self.cube = False
		self.inspector=None
		
		self.tex_name = 0
		self.tex_dl = 0

		self.glcontrast = 1.0
		self.glbrightness = 0.0
		
		self.rank = 1
		
		self.glflags = EMOpenGLFlagsAndTools()		# OpenGL flags - this is a singleton convenience class for testing texture support
		
	def eye_coords_dif(self,x1,y1,x2,y2,mdepth=True):
		return self.vdtools.eye_coords_dif(x1,y1,x2,y2,mdepth)
	
	def update_data(self,data):
		if data==None:
			print "Error, the data is empty"
			return
		
		if (isinstance(data,EMData) and data.get_zsize()<=1) :
			print "Error, the data is not 3D"
			return
		
#		self.data = data.copy()
#		
#		min = self.data.get_attr("minimum")
#		max = self.data.get_attr("maximum")
#		
#		self.data.add(-min)
#		self.data.mult(1/(max-min))

		self.generate_current_display_list()
		self.updateGL()
		
	def set_default_contrast_settings(self):
		min = self.data.get_attr("minimum")
		max = self.data.get_attr("maximum")
#		
#		self.data.add(-min)
#		self.data.mult(1/(max-min))
		self.bright = -min
		if max != min:	self.contrast = 1.0/(max-min)
		else: self.contrast = 1
		
	def set_data(self,data,fact=1.0):
		"""Pass in a 3D EMData object"""
		
		self.busy = True
		if data==None:
			print "Error, the data is empty"
			return
		
		if (isinstance(data,EMData) and data.get_zsize()<=1) :
			print "Error, the data is not 3D"
			self.busy = False
			return
		
		self.data = data
		
		self.set_default_contrast_settings()
		
		if not self.inspector or self.inspector ==None:
			self.inspector=EM3DSliceInspector(self)
		
		self.inspector.set_contrast_bright(self.contrast,self.bright)
		hist = self.data.calc_hist(256,0,1.0,self.bright,self.contrast)
		self.inspector.set_hist(hist,0,1.0) 
		
		self.slice = data.get_zsize()/2
		self.zslice = data.get_zsize()/2-1
		if self.zslice < 0: self.zslice = 0
		self.yslice = data.get_ysize()/2-1
		if self.yslice < 0: self.yslice = 0
		self.xslice = data.get_xsize()/2-1
		if self.xslice < 0: self.xslice = 0
		self.trackslice = self.xslice
		self.axis = 'z'
		self.inspector.set_sliceRange(0,data.get_zsize()-1)
		self.inspector.set_slice(self.zslice)
		self.generate_current_display_list()
		
		from emglobjects import EM3DGLWidget
		if isinstance(self.get_gl_widget(),EM3DGLWidget):
			self.get_gl_widget().set_camera_defaults(self.data)
			
		if ( self.tex_dl != 0 ): 
			glDeleteLists( self.tex_dl, 1)
			self.tex_dl = 0
		self.busy = False
	def get_eman_transform(self,p):
		
		if ( p[2] == 0 ):
			alt = 90
		else :
			alt = acos(p[2])*180.0/pi
		
		phi = atan2(p[0],p[1])
		phi *= 180.0/pi
		
		return [Transform({"type":"eman","alt":alt,"phi":phi}),alt,phi]
			
	def get_dimension_size(self):
		if ( self.axes_idx == 0 ):
			return self.data.get_xsize()
		elif ( self.axes_idx == 1 ):
			return self.data.get_ysize()
		elif ( self.axes_idx == 2 ):
			return self.data.get_zsize()
		else:
			#print "unsupported axis"
			# this is a hack and needs to be fixed eventually
			return self.data.get_xsize()
			#return 0
	def get_correct_dims_2d_emdata(self):
		if ( self.axes_idx == 0 ):
			return EMData(self.data.get_ysize(),self.data.get_zsize())
		elif ( self.axes_idx == 1 ):
			return EMData(self.data.get_xsize(),self.data.get_zsize())
		elif ( self.axes_idx == 2 ):
			return EMData(self.data.get_xsize(),self.data.get_ysize())
		else:
			#print "unsupported axis"
			# this is a hack and needs to be fixed eventually
			return EMData(self.data.get_xsize(),self.data.get_zsize())

	def generate_current_display_list(self):
		if self.busy: return
		if ( self.tex_dl != 0 ): glDeleteLists( self.tex_dl, 1)
		
		self.tex_dl = glGenLists(1)

		if (self.tex_dl == 0): return #OpenGL is initialized yet

		self.gen_2D_texture()
	
		
	def gen_2D_texture(self):
		glNewList(self.tex_dl,GL_COMPILE)
		
		n = self.get_dimension_size()
		v = self.axes[self.axes_idx]
		
		[t,alt,phi] = self.get_eman_transform(v)
			
		nn = float(self.slice)/float(n)
		trans = (nn-0.5)*v
		t.set_trans(n*trans)
	
		if False and EMUtil.cuda_available(): # disable for the time being - big textures won't work on CPU
			tmp = self.data.cut_slice_cuda(t)
		else:
			tmp = self.get_correct_dims_2d_emdata()
			tmp.cut_slice(self.data,t,True)
			
		tmp.add(self.bright)
		tmp.mult(self.contrast)
		
		hist = tmp.calc_hist(256,0,1.0,self.bright,self.contrast)
		self.inspector.set_hist(hist,0,1.0) 
		
		if ( self.tex_name != 0 ): glDeleteTextures(self.tex_name)
		self.tex_name = 0
		
		self.tex_name = self.glflags.gen_textureName(tmp)
		
		glEnable(GL_TEXTURE_2D)
		glBindTexture(GL_TEXTURE_2D, self.tex_name)
			
		#glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
#		if ( not data_dims_power_of(self.data,2) and self.glflags.npt_textures_unsupported()):
#			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
#		else:
#			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)
		
			
		glPushMatrix()
		glTranslate(trans[0]+0.5,trans[1]+0.5,trans[2]+0.5)
		glRotatef(-phi,0,0,1)
		glRotatef(-alt,1,0,0)
		glBegin(GL_QUADS)
		glTexCoord2f(0,0)
		glVertex2f(-0.5,-0.5)
		
		glTexCoord2f(1,0)
		glVertex2f( 0.5,-0.5)
		
		glTexCoord2f(1,1)
		glVertex2f( 0.5, 0.5)
		
		glTexCoord2f(0,1)
		glVertex2f(-0.5, 0.5)
		glEnd()
		glPopMatrix()
		
		glDisable(GL_TEXTURE_2D)
		glEndList()
		
	def render(self):
		if self.busy: return
		lighting = glIsEnabled(GL_LIGHTING)
		cull = glIsEnabled(GL_CULL_FACE)
		polygonmode = glGetIntegerv(GL_POLYGON_MODE)
		glDisable(GL_LIGHTING)
		glDisable(GL_CULL_FACE)
		
		glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
		
		glPushMatrix()
		self.cam.position(True)
		# the ones are dummy variables atm... they don't do anything
		self.vdtools.update(1,1)
		glPopMatrix()
		
		self.cam.position()
		self.vdtools.store_model()
		
		if ( self.track ):
			self.loadTrackAxis()
			self.generate_current_display_list()
		
		if ( self.tex_dl == 0 ):
			self.generate_current_display_list()
		
		glStencilFunc(GL_EQUAL,self.rank,0)
		glStencilOp(GL_KEEP,GL_KEEP,GL_REPLACE)
		glPushMatrix()
		glTranslate(-self.data.get_xsize()/2.0,-self.data.get_ysize()/2.0,-self.data.get_zsize()/2.0)
		glScalef(self.data.get_xsize(),self.data.get_ysize(),self.data.get_zsize())
		glCallList(self.tex_dl)
		glPopMatrix()
		
		#breaks in desktop!
		#glStencilFunc(GL_EQUAL,self.rank,self.rank)
		#glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP)
		#glPushMatrix()
		##glLoadIdentity()
		#[width,height] = self.parent.get_near_plane_dims()
		#z = self.parent.get_start_z()
		#glTranslate(-width/2.0,-height/2.0,-z-0.01)
		#glScalef(width,height,1.0)
		self.draw_bc_screen()
		#glPopMatrix()
		
		glStencilFunc(GL_ALWAYS,1,1)
		glColor3f(1,1,1)
		if self.cube:
			glPushMatrix()
			self.draw_volume_bounds()
			glPopMatrix()
			
		if ( lighting ): glEnable(GL_LIGHTING)
		if ( cull ): glEnable(GL_CULL_FACE)
		
		if ( polygonmode[0] == GL_LINE ): glPolygonMode(GL_FRONT, GL_LINE)
		if ( polygonmode[1] == GL_LINE ): glPolygonMode(GL_BACK, GL_LINE)
	
	def set_slice(self,val):
		self.slice = val
		if self.axis == 'z':
			self.zslice = val
		elif self.axis == 'y':
			self.yslice = val
		elif self.axis == 'x':
			self.xslice = val
		else:
			self.trackslice = val
		
		self.generate_current_display_list()
		self.updateGL()
		
	def setAxis(self,val):
		self.axis = str(val).strip()
		
		if (self.inspector != None):
			if self.axis == 'z':
				self.inspector.set_sliceRange(0,self.data.get_zsize()-1)
				self.inspector.set_slice(self.zslice)
				self.axes_idx = 2
				self.track = False
			elif self.axis == 'y':
				self.inspector.set_sliceRange(0,self.data.get_ysize()-1)
				self.inspector.set_slice(self.yslice)
				self.axes_idx = 1
				self.track = False
			elif self.axis == 'x':
				self.inspector.set_sliceRange(0,self.data.get_xsize()-1)
				self.inspector.set_slice(self.xslice)
				self.axes_idx = 0
				self.track = False
			elif self.axis == 'track':
				self.track = True
				self.inspector.set_sliceRange(0,self.data.get_xsize()-1)
				self.inspector.set_slice(self.trackslice)
				self.axes_idx = 3
				
				self.loadTrackAxis()
			else:
				print "Error, unknown axis", self.axis, val
		
		self.generate_current_display_list()
		self.updateGL()

	def update_inspector(self,t3d):
		if not self.inspector or self.inspector ==None:
			self.inspector=EM3DSliceInspector(self)
		self.inspector.update_rotations(t3d)
	
	def get_inspector(self):
		if not self.inspector : self.inspector=EM3DSliceInspector(self)
		return self.inspector

	def loadTrackAxis(self):
		t3d = self.vdtools.getEmanMatrix()
		#at3d = self.cam.t3d_stack[len(self.cam.t3d_stack)-1]
		
		point = Vec3f(0,0,1)
		
		point *= 1.0/self.vdtools.getCurrentScale()
		
		point = point*t3d
		
		#if ( point[2] != 0 ): point[2] = -point[2]
		
		if len(self.axes) == 3 :
			self.axes.append(point)
		else:
			self.axes[3] = point

	def resize(self):
		self.vdtools.set_update_P_inv()
Beispiel #5
0
	def __init__(self,target) :
		QtGui.QWidget.__init__(self,None)
		self.target=weakref.ref(target)
		self.setWindowIcon(QtGui.QIcon(get_image_directory() +"desktop.png"))
		
		self.vbl = QtGui.QVBoxLayout(self)
		self.vbl.setMargin(0)
		self.vbl.setSpacing(6)
		self.vbl.setObjectName("vbl")
		
		self.hbl = QtGui.QHBoxLayout()
		self.hbl.setMargin(2)
		self.hbl.setSpacing(6)
		self.hbl.setObjectName("hbl")
		
		#self.listwidget = QtGui.QListWidget(self)
		#self.vbl.addWidget(self.listwidget)
		
		self.tabwidget = QtGui.QTabWidget()
		
		self.hbl_check = QtGui.QHBoxLayout()
		self.hbl_check.setMargin(0)
		self.hbl_check.setSpacing(6)
		self.hbl_check.setObjectName("hbl_check")
		
		#self.advancedcheck = QtGui.QCheckBox("Advanced",self)
		#self.hbl_check.addWidget(self.advancedcheck)
		
		self.hbl_buttons = QtGui.QHBoxLayout()
		self.hbl_buttons.setMargin(0)
		self.hbl_buttons.setSpacing(6)
		self.hbl_buttons.setObjectName("hbl_buttons")
		
		self.hbl_buttons2 = QtGui.QHBoxLayout()
		self.hbl_buttons2.setMargin(0)
		self.hbl_buttons2.setSpacing(6)
		self.hbl_buttons2.setObjectName("hbl_buttons2")
		
		self.addIso = QtGui.QPushButton("Isosurface")
		self.hbl_buttons.addWidget(self.addIso)
		
		self.addVol = QtGui.QPushButton("Volume")
		self.hbl_buttons.addWidget(self.addVol)
		
		glflags = EMOpenGLFlagsAndTools()
		if glflags.npt_textures_unsupported(): self.addVol.setEnabled(False)
		
		self.addSli = QtGui.QPushButton("Slices")
		self.hbl_buttons2.addWidget(self.addSli)
		
		self.add_sym = QtGui.QPushButton("Sym")
		self.hbl_buttons2.addWidget(self.add_sym)

		self.vbl.addLayout(self.hbl_buttons)
		self.vbl.addLayout(self.hbl_buttons2)
		
		self.hbl_buttons3 = QtGui.QHBoxLayout()
		self.delete = QtGui.QPushButton("Delete")
		self.hbl_buttons3.addWidget(self.delete)
		self.vbl.addLayout(self.hbl_buttons3)
		
		self.vbl.addLayout(self.hbl_check)
		self.vbl.addWidget(self.tabwidget)
		
		self.advanced_tab = None
		
		self.currentselection = -1
		self.settingsrow = -2
		self.targetidxmap = {}

		self.insert_advance_tab()
		
		QtCore.QObject.connect(self.addIso, QtCore.SIGNAL("clicked()"), self.add_isosurface)
		QtCore.QObject.connect(self.addVol, QtCore.SIGNAL("clicked()"), self.add_volume)
		QtCore.QObject.connect(self.addSli, QtCore.SIGNAL("clicked()"), self.add_slices)
		QtCore.QObject.connect(self.add_sym, QtCore.SIGNAL("clicked()"), self.add_symmetry)
		QtCore.QObject.connect(self.delete, QtCore.SIGNAL("clicked()"), self.delete_selection)
Beispiel #6
0
class EMVolumeModel(EM3DModel):
	def __init__(self, gl_widget, image=None):
		self.data = None
		EM3DModel.__init__(self, gl_widget)
		
		self.init()
		self.initialized = True
		
		self.initializedGL= False
		
		self.inspector=None
		
		self.tex_names_list = []		# A storage object, used to remember and later delete texture names
		
		self.axes_idx = -1
		self.axes = []
		self.axes.append(Vec3f(1,0,0))
		self.axes.append(Vec3f(0,1,0))
		self.axes.append(Vec3f(0,0,1))
		#self.axes.append( Vec3f(-1,0,0) )
		#self.axes.append( Vec3f(0,-1,0) )
		#self.add_render_axis(1,1,1)
		#self.add_render_axis(-1,1,1)
		#self.add_render_axis(-1,-1,1)
		#self.add_render_axis(1,-1,1)
		
		#self.add_render_axis(1,1,0)
		#self.add_render_axis(-1,1,0)
		#self.add_render_axis(-1,-1,0)
		#self.add_render_axis(1,-1,0)
		
		#self.add_render_axis(0,1,1)
		#self.add_render_axis(0,-1,1)
		
		#self.add_render_axis(1,0,1)
		#self.add_render_axis(-1,0,1)
			
		if image :
			self.set_data(image)
#	def __del__(self):
#		print "vol died"

	def add_render_axis(self,a,b,c):
		v = Vec3f(a,b,c);
		v.normalize()
		self.axes.append( v )
	
	def eye_coords_dif(self,x1,y1,x2,y2,mdepth=True):
		return self.vdtools.eye_coords_dif(x1,y1,x2,y2,mdepth)
	
	def get_type(self):
		return "Volume"

	def init(self):
		self.data=None

		self.mmode=0
		
		self.cam = Camera2(self)
		self.cube = False
		
		self.vdtools = EMViewportDepthTools(self)
		
		self.contrast = 1.0
		self.brightness = 0.0
		self.texsample = 1.0
		self.glcontrast = 1.0
		self.glbrightness = 0.0
		self.cube = False
		
		self.tex_name = 0
		
		self.rank = 1
		
		self.tex_dl = 0
		self.inspector=None
		
		self.force_texture_update = False

		self.glflags = EMOpenGLFlagsAndTools()		# OpenGL flags - this is a singleton convenience class for testing texture support
	
	def update_data(self,data):
		self.set_data(data)
		self.updateGL()
		
	def set_data(self,data):
		"""Pass in a 3D EMData object"""
		
		
		self.data=data
		if data==None:
			print "Error, the data is empty"
			return
		
	 	if (isinstance(data,EMData) and data.get_zsize()<=1) :
			print "Error, the data is not 3D"
			return
		
		if not self.inspector or self.inspector ==None:
			self.inspector=EMVolumeInspector(self)
		
		self.update_data_and_texture()
		
		from emglobjects import EM3DGLWidget
		if isinstance(self.get_gl_widget(),EM3DGLWidget):
			self.get_gl_widget().set_camera_defaults(self.data)
		
	def test_accum(self):
		# this code will do volume rendering using the accumulation buffer
		# I opted not to go this way because you can't retain depth in the accumulation buffer
		# Note that it only works in the z-direction
		glClear(GL_ACCUM_BUFFER_BIT)
		
		self.accum = True
		self.zsample = self.texsample*(self.data.get_zsize())
		
		if self.tex_name == 0:
			print "Error, can not render 3D texture - texture name is 0"
			return
		
		
		for z in range(0,int(self.texsample*(self.data.get_zsize()))):
			glEnable(GL_TEXTURE_3D)
			glBindTexture(GL_TEXTURE_3D, self.tex_name)
			glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
			glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP)
			glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP)
			glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP)
			glTexParameter(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
			glTexParameter(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
			glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)

			glBegin(GL_QUADS)
			
			zz = float(z)/float(self.data.get_zsize()-1)/self.texsample
			glTexCoord3f(0,0,zz)
			glVertex3f(0,0,zz)
			
			glTexCoord3f(1,0,zz)
			glVertex3f(1,0,zz)
			
			glTexCoord3f(1,1,zz)
			glVertex3f(1,1,zz)
			
			glTexCoord3f(0,1,zz)
			glVertex3f(0,1,zz)
		
			glEnd()
			glDisable(GL_TEXTURE_3D)
		
			if ( self.accum ):
				glAccum(GL_ADD, 1.0/self.zsample*self.brightness)
				glAccum(GL_ACCUM, 1.0/self.zsample*self.contrast)
		
		
		glAccum(GL_RETURN, 1.0)
		
	def render(self):
		lighting = glIsEnabled(GL_LIGHTING)
		cull = glIsEnabled(GL_CULL_FACE)
		depth = glIsEnabled(GL_DEPTH_TEST)
		
		polygonmode = glGetIntegerv(GL_POLYGON_MODE)

		glDisable(GL_LIGHTING)
		glDisable(GL_CULL_FACE)
		glDisable(GL_DEPTH_TEST)
		
		glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
		
		glPushMatrix()
		self.cam.position(True)
		# the ones are dummy variables atm... they don't do anything
		self.vdtools.update(1,1)
		glPopMatrix()
		
		self.cam.position()
		self.vdtools.store_model()

		# here is where the correct display list (x,y or z direction) is determined
		self.texture_update_if_necessary()

		glStencilFunc(GL_EQUAL,self.rank,0)
		glStencilOp(GL_KEEP,GL_KEEP,GL_REPLACE)
		glPushMatrix()
		glTranslate(-self.data.get_xsize()/2.0,-self.data.get_ysize()/2.0,-self.data.get_zsize()/2.0)
		glScalef(self.data.get_xsize(),self.data.get_ysize(),self.data.get_zsize())
		glEnable(GL_BLEND)
		#glBlendEquation(GL_MAX)
		if self.glflags.blend_equation_supported():
			glBlendEquation(GL_FUNC_ADD)
		glDepthMask(GL_FALSE)
		glBlendFunc(GL_ONE, GL_ONE)
		glCallList(self.tex_dl)
		glDepthMask(GL_TRUE)
		glDisable(GL_BLEND)
		glPopMatrix()

		# this is the accumulation buffer version of the volume model - it was for testing purposes
		# and is left here commented out incase anyone wants to investigate it in the future
		#glPushMatrix()
		#glTranslate(-self.data.get_xsize()/2.0,-self.data.get_ysize()/2.0,-self.data.get_zsize()/2.0)
		#glScalef(self.data.get_xsize(),self.data.get_ysize(),self.data.get_zsize())
		#self.test_accum()
		#glPopMatrix()
		
		#breaks in desktop!
		#glStencilFunc(GL_EQUAL,self.rank,self.rank)
		#glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP)
		#glPushMatrix()
		#glLoadIdentity()
		#[width,height] = self.parent.get_near_plane_dims()
		#z = self.parent.get_start_z()
		#glTranslate(-width/2.0,-height/2.0,-z-0.01)
		#glScalef(width,height,1.0)
		self.draw_bc_screen()
		#glPopMatrix()
		
		glStencilFunc(GL_ALWAYS,1,1)
		if self.cube:
			glPushMatrix()
			self.draw_volume_bounds()
			glPopMatrix()
			
		if ( lighting ): glEnable(GL_LIGHTING)
		if ( cull ): glEnable(GL_CULL_FACE)
		if ( depth ): glEnable(GL_DEPTH_TEST)
		
		if ( polygonmode[0] == GL_LINE ): glPolygonMode(GL_FRONT, GL_LINE)
		if ( polygonmode[1] == GL_LINE ): glPolygonMode(GL_BACK, GL_LINE)
	
	def texture_update_if_necessary(self):
		
		t3d = self.vdtools.getEmanMatrix()
		
		
		point = Vec3f(0,0,1)
		
		point = point*t3d
		
		point[0] = abs(point[0])
		point[1] = abs(point[1])
		point[2] = abs(point[2])
		#point[1] = -point[1]
		#if ( point[2] < 0 ):
			#point[2] = -point[2]
			#point[1] = -point[1]
			#point[0] = -point[0]
	
		currentaxis = self.axes_idx
		
		closest = 2*pi
		lp = point.length()
		point.normalize()
		idx = 0
		for i in self.axes:
			try:
				angle = abs(acos(point.dot(i)))
			except:
				t3d.printme()
				print 'warning, there is a bug in the volume render which may cause incorrect rendering'
				return
			if (angle < closest):
				closest = angle
				self.axes_idx = idx
			
			idx += 1

		if (currentaxis != self.axes_idx or self.force_texture_update):
			#print self.axes[self.axes_idx]
			self.gen_texture()
			
	def gen_texture(self):
		if self.glflags.threed_texturing_supported():
			self.get_3D_texture()
		else:
			self.gen_2D_texture()
			
	def get_3D_texture(self):
		if ( self.tex_dl != 0 ): glDeleteLists( self.tex_dl, 1)
		
		self.tex_dl = glGenLists(1)
		
		if self.tex_dl == 0:
			print "Error, failed to generate display list"
			return
		
		n = self.get_dimension_size()
		v = self.axes[self.axes_idx]
		[t,alt,phi] = self.get_eman_transform(v)
		v1 = t*Vec3f(-0.5,-0.5,0)
		v2 = t*Vec3f(-0.5, 0.5,0)
		v3 = t*Vec3f( 0.5, 0.5,0)
		v4 = t*Vec3f( 0.5,-0.5,0)
		vecs = [v1,v2,v3,v4]
		total = self.texsample*n
		self.data.add(self.brightness)
		if self.contrast != 0:
			self.data.mult(self.contrast*1.0/total)
		if ( self.force_texture_update ):
			if self.tex_name != 0:
				glDeleteTextures(self.tex_name)
			
			self.tex_name = self.glflags.gen_textureName(self.data)
			
			self.force_texture_update = False
			
		
		if self.tex_name == 0:
			print "Error, can not render 3D texture - texture name is 0"
			return
		
		
		glNewList(self.tex_dl,GL_COMPILE)
		glEnable(GL_TEXTURE_3D)
		glBindTexture(GL_TEXTURE_3D, self.tex_name)
		glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)
		glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP)
		glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP)
		glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP)
		glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
		if ( not data_dims_power_of(self.data,2) and self.glflags.npt_textures_unsupported()):
			glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)
		else:
			glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)

		glPushMatrix()
		glTranslate(0.5,0.5,0.5)
		glBegin(GL_QUADS)
		
		
		for i in range(0,int(self.texsample*n)):
			nn = float(i)/float(n)/self.texsample

			trans = (nn-0.5)*v
			
			for r in vecs:
			
				w = [r[0] + trans[0], r[1] + trans[1], r[2] + trans[2]]
				t = [w[0]+0.5,w[1]+0.5,w[2]+0.5]
				glTexCoord3fv(t)
				glVertex3fv(w)
			
		glEnd()
		glPopMatrix()
		glDisable(GL_TEXTURE_3D)
		glEndList()
		
		if self.contrast != 0:	self.data.mult(total*1.0/self.contrast)
		self.data.add(-self.brightness)
		
		
	def get_eman_transform(self,p):
		
		if ( p[2] == 0 ):
			alt = 90
		else :
			alt = acos(p[2])*180.0/pi
		
		phi = atan2(p[0],p[1])
		phi *= 180.0/pi
		
		t = Transform({"type":"eman","alt":alt,"phi":phi})
		
		return [t,alt,phi]
			
	def get_dimension_size(self):
		if ( self.axes_idx == 0 ):
			return self.data.get_xsize()
		elif ( self.axes_idx == 1 ):
			return self.data.get_ysize()
		elif ( self.axes_idx == 2 ):
			return self.data.get_zsize()
		else:
			#print "unsupported axis"
			# this is a hack and needs to be fixed eventually
			return self.data.get_xsize()
			#return 0
	def get_correct_dims_2d_emdata(self):
		if ( self.axes_idx == 0 ):
			return EMData(self.data.get_ysize(),self.data.get_zsize())
		elif ( self.axes_idx == 1 ):
			return EMData(self.data.get_xsize(),self.data.get_zsize())
		elif ( self.axes_idx == 2 ):
			return EMData(self.data.get_xsize(),self.data.get_ysize())
		else:
			#print "unsupported axis"
			# this is a hack and needs to be fixed eventually
			return EMData(self.data.get_xsize(),self.data.get_zsize())

	
	def gen_2D_texture(self):
			
		if ( self.tex_dl != 0 ): 
			glDeleteLists( self.tex_dl, 1)
		
		for i in self.tex_names_list:
			glDeleteTextures(i)
			
		self.tex_dl = glGenLists(1)
		if (self.tex_dl == 0 ):
			print "error, could not generate list"
			return

		glNewList(self.tex_dl,GL_COMPILE)
		glEnable(GL_TEXTURE_2D)

		n = self.get_dimension_size()
		v = self.axes[self.axes_idx]
		[t,alt,phi] = self.get_eman_transform(v)
		total = self.texsample*n
		for i in range(0,int(self.texsample*n)):
			nn = float(i)/float(n)/self.texsample
			
			trans = (nn-0.5)*v
			t.set_trans(2.0*int(n/2)*trans)
			
			if False and EMUtil.cuda_available(): # disable for the time being - big textures won't work on CPU
				tmp = self.data.cut_slice_cuda(t)
			else:
				tmp = self.get_correct_dims_2d_emdata() 
				tmp.cut_slice(self.data,t,True)
			tmp.add(self.brightness)
			tmp.mult(self.contrast*1.0/total)
			#tmp.write_image("tmp.img",-1)
			
			# get the texture name, store it, and bind it in OpenGL
			tex_name = self.glflags.gen_textureName(tmp)
			self.tex_names_list.append(tex_name)
			glBindTexture(GL_TEXTURE_2D, tex_name)
			
			self.loat_default_2D_texture_parms()
			
			glPushMatrix()
			
			glTranslate(trans[0]+0.5,trans[1]+0.5,trans[2]+0.5)
			glRotatef(-phi,0,0,1)
			glRotatef(-alt,1,0,0)
			glBegin(GL_QUADS)
			glTexCoord2f(0,0)
			glVertex2f(-0.5,-0.5)
			
			glTexCoord2f(1,0)
			glVertex2f( 0.5,-0.5)
			
			glTexCoord2f(1,1)
			glVertex2f( 0.5, 0.5)
			
			glTexCoord2f(0,1)
			glVertex2f(-0.5, 0.5)
			glEnd()
			glPopMatrix()
		
		glDisable(GL_TEXTURE_2D)
		glEndList()
		
		# this may have been toggled (i.e. if the image contrast or brightness changed)
		if self.force_texture_update == True:
			self.force_texture_update = False
	
	def loat_default_2D_texture_parms(self):
		glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)
		if ( not data_dims_power_of(self.data,2) and self.glflags.npt_textures_unsupported()):
			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)
		else:
			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) 
		
	def update_data_and_texture(self):
	
		if ( not isinstance(self.data,EMData) ): return
		
		hist = self.data.calc_hist(256,0,1.0)
		self.inspector.set_hist(hist,0,1.0)

		self.force_texture_update = True

	def set_contrast(self,val):
		self.contrast = val
		self.update_data_and_texture()
		self.updateGL()
		
	def set_brightness(self,val):
		self.brightness = val
		self.update_data_and_texture()
		self.updateGL()
		
	def set_texture_sample(self,val):
		if ( val < 0 ) :
			print "Error, cannot handle texture sample less than 0"
			return
		
		self.texsample = val
		self.force_texture_update = True
		self.updateGL()

	def update_inspector(self,t3d):
		if not self.inspector or self.inspector ==None:
			self.inspector=EMVolumeInspector(self)
		self.inspector.update_rotations(t3d)
	
	def get_inspector(self):
		if not self.inspector : self.inspector=EMVolumeInspector(self)
		return self.inspector
		
	def resize(self):
		self.vdtools.set_update_P_inv()
Beispiel #7
0
class EM3DSliceModel(EM3DModel):
    def __init__(self, gl_widget, image=None):
        self.data = None
        EM3DModel.__init__(self, gl_widget)
        self.init()
        self.initialized = True

        self.inspector = None

        self.axes = []
        self.axes.append(Vec3f(1, 0, 0))
        self.axes.append(Vec3f(0, 1, 0))
        self.axes.append(Vec3f(0, 0, 1))
        self.axes_idx = 2

        self.track = False
        self.bright = 0
        self.contrast = 1.0
        self.busy = True
        if image:
            self.set_data(image)

    def set_contrast(self, val):
        self.contrast = val
        self.generate_current_display_list()
        self.updateGL()

    def set_brightness(self, val):
        self.bright = val
        self.generate_current_display_list()
        self.updateGL()

#	def __del__(self):
#		print "slice died"

    def get_type(self):
        return "Slice Viewer"

    def init(self):
        self.data = None

        self.mmode = 0
        self.cam = Camera2(self)

        self.vdtools = EMViewportDepthTools(self)

        self.cube = False
        self.inspector = None

        self.tex_name = 0
        self.tex_dl = 0

        self.glcontrast = 1.0
        self.glbrightness = 0.0

        self.rank = 1

        self.glflags = EMOpenGLFlagsAndTools(
        )  # OpenGL flags - this is a singleton convenience class for testing texture support

    def eye_coords_dif(self, x1, y1, x2, y2, mdepth=True):
        return self.vdtools.eye_coords_dif(x1, y1, x2, y2, mdepth)

    def update_data(self, data):
        if data == None:
            print("Error, the data is empty")
            return

        if (isinstance(data, EMData) and data.get_zsize() <= 1):
            print("Error, the data is not 3D")
            return


#		self.data = data.copy()
#
#		min = self.data.get_attr("minimum")
#		max = self.data.get_attr("maximum")
#
#		self.data.add(-min)
#		self.data.mult(1/(max-min))

        self.generate_current_display_list()
        self.updateGL()

    def set_default_contrast_settings(self):
        min = self.data.get_attr("minimum")
        max = self.data.get_attr("maximum")
        #
        #		self.data.add(-min)
        #		self.data.mult(1/(max-min))
        self.bright = -min
        if max != min: self.contrast = 1.0 / (max - min)
        else: self.contrast = 1

    def set_data(self, data, fact=1.0):
        """Pass in a 3D EMData object"""

        self.busy = True
        if data == None:
            print("Error, the data is empty")
            return

        if (isinstance(data, EMData) and data.get_zsize() <= 1):
            print("Error, the data is not 3D")
            self.busy = False
            return

        self.data = data

        self.set_default_contrast_settings()

        if not self.inspector or self.inspector == None:
            self.inspector = EM3DSliceInspector(self)

        self.inspector.set_contrast_bright(self.contrast, self.bright)
        hist = self.data.calc_hist(256, 0, 1.0, self.bright, self.contrast)
        self.inspector.set_hist(hist, 0, 1.0)

        self.slice = data.get_zsize() / 2
        self.zslice = data.get_zsize() / 2 - 1
        if self.zslice < 0: self.zslice = 0
        self.yslice = data.get_ysize() / 2 - 1
        if self.yslice < 0: self.yslice = 0
        self.xslice = data.get_xsize() / 2 - 1
        if self.xslice < 0: self.xslice = 0
        self.trackslice = self.xslice
        self.axis = 'z'
        self.inspector.set_sliceRange(0, data.get_zsize() - 1)
        self.inspector.set_slice(self.zslice)
        self.generate_current_display_list()

        from emglobjects import EM3DGLWidget
        if isinstance(self.get_gl_widget(), EM3DGLWidget):
            self.get_gl_widget().set_camera_defaults(self.data)

        if (self.tex_dl != 0):
            glDeleteLists(self.tex_dl, 1)
            self.tex_dl = 0
        self.busy = False

    def get_eman_transform(self, p):

        if (p[2] == 0):
            alt = 90
        else:
            alt = acos(p[2]) * 180.0 / pi

        phi = atan2(p[0], p[1])
        phi *= 180.0 / pi

        return [Transform({"type": "eman", "alt": alt, "phi": phi}), alt, phi]

    def get_dimension_size(self):
        if (self.axes_idx == 0):
            return self.data.get_xsize()
        elif (self.axes_idx == 1):
            return self.data.get_ysize()
        elif (self.axes_idx == 2):
            return self.data.get_zsize()
        else:
            #print "unsupported axis"
            # this is a hack and needs to be fixed eventually
            return self.data.get_xsize()
            #return 0
    def get_correct_dims_2d_emdata(self):
        if (self.axes_idx == 0):
            return EMData(self.data.get_ysize(), self.data.get_zsize())
        elif (self.axes_idx == 1):
            return EMData(self.data.get_xsize(), self.data.get_zsize())
        elif (self.axes_idx == 2):
            return EMData(self.data.get_xsize(), self.data.get_ysize())
        else:
            #print "unsupported axis"
            # this is a hack and needs to be fixed eventually
            return EMData(self.data.get_xsize(), self.data.get_zsize())

    def generate_current_display_list(self):
        if self.busy: return
        if (self.tex_dl != 0): glDeleteLists(self.tex_dl, 1)

        self.tex_dl = glGenLists(1)

        if (self.tex_dl == 0): return  #OpenGL is initialized yet

        self.gen_2D_texture()

    def gen_2D_texture(self):
        glNewList(self.tex_dl, GL_COMPILE)

        n = self.get_dimension_size()
        v = self.axes[self.axes_idx]

        [t, alt, phi] = self.get_eman_transform(v)

        nn = float(self.slice) / float(n)
        trans = (nn - 0.5) * v
        t.set_trans(n * trans)

        if False and EMUtil.cuda_available(
        ):  # disable for the time being - big textures won't work on CPU
            tmp = self.data.cut_slice_cuda(t)
        else:
            tmp = self.get_correct_dims_2d_emdata()
            tmp.cut_slice(self.data, t, True)

        tmp.add(self.bright)
        tmp.mult(self.contrast)

        hist = tmp.calc_hist(256, 0, 1.0, self.bright, self.contrast)
        self.inspector.set_hist(hist, 0, 1.0)

        if (self.tex_name != 0): glDeleteTextures(self.tex_name)
        self.tex_name = 0

        self.tex_name = self.glflags.gen_textureName(tmp)

        glEnable(GL_TEXTURE_2D)
        glBindTexture(GL_TEXTURE_2D, self.tex_name)

        #glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
        #		if ( not data_dims_power_of(self.data,2) and self.glflags.npt_textures_unsupported()):
        #			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
        #		else:
        #			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)

        glPushMatrix()
        glTranslate(trans[0] + 0.5, trans[1] + 0.5, trans[2] + 0.5)
        glRotatef(-phi, 0, 0, 1)
        glRotatef(-alt, 1, 0, 0)
        glBegin(GL_QUADS)
        glTexCoord2f(0, 0)
        glVertex2f(-0.5, -0.5)

        glTexCoord2f(1, 0)
        glVertex2f(0.5, -0.5)

        glTexCoord2f(1, 1)
        glVertex2f(0.5, 0.5)

        glTexCoord2f(0, 1)
        glVertex2f(-0.5, 0.5)
        glEnd()
        glPopMatrix()

        glDisable(GL_TEXTURE_2D)
        glEndList()

    def render(self):
        if self.busy: return
        lighting = glIsEnabled(GL_LIGHTING)
        cull = glIsEnabled(GL_CULL_FACE)
        polygonmode = glGetIntegerv(GL_POLYGON_MODE)
        glDisable(GL_LIGHTING)
        glDisable(GL_CULL_FACE)

        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)

        glPushMatrix()
        self.cam.position(True)
        # the ones are dummy variables atm... they don't do anything
        self.vdtools.update(1, 1)
        glPopMatrix()

        self.cam.position()
        self.vdtools.store_model()

        if (self.track):
            self.loadTrackAxis()
            self.generate_current_display_list()

        if (self.tex_dl == 0):
            self.generate_current_display_list()

        glStencilFunc(GL_EQUAL, self.rank, 0)
        glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE)
        glPushMatrix()
        glTranslate(-self.data.get_xsize() / 2.0, -self.data.get_ysize() / 2.0,
                    -self.data.get_zsize() / 2.0)
        glScalef(self.data.get_xsize(), self.data.get_ysize(),
                 self.data.get_zsize())
        glCallList(self.tex_dl)
        glPopMatrix()

        #breaks in desktop!
        #glStencilFunc(GL_EQUAL,self.rank,self.rank)
        #glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP)
        #glPushMatrix()
        ##glLoadIdentity()
        #[width,height] = self.parent.get_near_plane_dims()
        #z = self.parent.get_start_z()
        #glTranslate(-width/2.0,-height/2.0,-z-0.01)
        #glScalef(width,height,1.0)
        self.draw_bc_screen()
        #glPopMatrix()

        glStencilFunc(GL_ALWAYS, 1, 1)
        glColor3f(1, 1, 1)
        if self.cube:
            glPushMatrix()
            self.draw_volume_bounds()
            glPopMatrix()

        if (lighting): glEnable(GL_LIGHTING)
        if (cull): glEnable(GL_CULL_FACE)

        if (polygonmode[0] == GL_LINE): glPolygonMode(GL_FRONT, GL_LINE)
        if (polygonmode[1] == GL_LINE): glPolygonMode(GL_BACK, GL_LINE)

    def set_slice(self, val):
        self.slice = val
        if self.axis == 'z':
            self.zslice = val
        elif self.axis == 'y':
            self.yslice = val
        elif self.axis == 'x':
            self.xslice = val
        else:
            self.trackslice = val

        self.generate_current_display_list()
        self.updateGL()

    def setAxis(self, val):
        self.axis = str(val).strip()

        if (self.inspector != None):
            if self.axis == 'z':
                self.inspector.set_sliceRange(0, self.data.get_zsize() - 1)
                self.inspector.set_slice(self.zslice)
                self.axes_idx = 2
                self.track = False
            elif self.axis == 'y':
                self.inspector.set_sliceRange(0, self.data.get_ysize() - 1)
                self.inspector.set_slice(self.yslice)
                self.axes_idx = 1
                self.track = False
            elif self.axis == 'x':
                self.inspector.set_sliceRange(0, self.data.get_xsize() - 1)
                self.inspector.set_slice(self.xslice)
                self.axes_idx = 0
                self.track = False
            elif self.axis == 'track':
                self.track = True
                self.inspector.set_sliceRange(0, self.data.get_xsize() - 1)
                self.inspector.set_slice(self.trackslice)
                self.axes_idx = 3

                self.loadTrackAxis()
            else:
                print("Error, unknown axis", self.axis, val)

        self.generate_current_display_list()
        self.updateGL()

    def update_inspector(self, t3d):
        if not self.inspector or self.inspector == None:
            self.inspector = EM3DSliceInspector(self)
        self.inspector.update_rotations(t3d)

    def get_inspector(self):
        if not self.inspector: self.inspector = EM3DSliceInspector(self)
        return self.inspector

    def loadTrackAxis(self):
        t3d = self.vdtools.getEmanMatrix()
        #at3d = self.cam.t3d_stack[len(self.cam.t3d_stack)-1]

        point = Vec3f(0, 0, 1)

        point *= 1.0 / self.vdtools.getCurrentScale()

        point = point * t3d

        #if ( point[2] != 0 ): point[2] = -point[2]

        if len(self.axes) == 3:
            self.axes.append(point)
        else:
            self.axes[3] = point

    def resize(self):
        self.vdtools.set_update_P_inv()
Beispiel #8
0
class EMHistogramWidget(EMGLWidget):
	"""A QT widget for drawing 2-D plots using matplotlib
	"""

	def __init__(self,application=None,winid=None,parent=None):
		fmt=QtOpenGL.QGLFormat()
		fmt.setDoubleBuffer(True);
		EMGLWidget.__init__(self, parent=parent, winid=winid)
		self.setFormat(fmt)
		self.setWindowIcon(QtGui.QIcon(get_image_directory() +"plot.png"))
		self.axes={}
		self.pparm={}			# nbins,color,histtype,orient,align,alpha,width,norm,cumul,logy,stacked
		self.inspector=None
		self.needupd=1
		self.plotimg=None
		self.shapes={}
		self.bins = {}
		self.edges = None
		self.xlimits=None
		self.ylimits=None
		self.rmousedrag=None
		self.axisparms=(None,None,"linear","linear")
		self.selected=[]
		self.comments={}			# IF reading from a file which contains per-point comments, this dictionary contains a list of comments for each point
		self.data={}				# List of Lists to plot
		self.visibility = {}		# Same entries as in self.data, but entries are true or False to indicate visibility
		self.glflags = EMOpenGLFlagsAndTools() 	# supplies power of two texturing flags
		self.tex_name = 0
		self.main_display_list = 0
		self.resize(640,480)

		self.nbins = 10 # start with 10. user can modify via inspector.
		self.stacked = False #self.inspector.stacked.isChecked()
		self.normed=False #self.inspector.normed.isChecked()
		self.histtype="bar" #histtypes[self.inspector.histtype.currentIndex()]
		self.orientation="vertical" #orientations[self.inspector.orient.currentIndex()]
		self.alignment="edge" #alignments[self.inspector.align.currentIndex()]
		self.cumulative = False #self.inspector.cumulative.isChecked()
		self.logy = False #self.inspector.logtogy.isChecked()

	def initializeGL(self):
		GL.glClearColor(0,0,0,0)
		GL.glEnable(GL_DEPTH_TEST)

	def paintGL(self):
		try: GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
		except: pass # this is a hack.

		GL.glMatrixMode(GL.GL_MODELVIEW)
		GL.glLoadIdentity()
		self.render()

	def resizeGL(self, width, height):
		side = min(width, height)
		GL.glViewport(0,0,self.width(),self.height())
		GL.glMatrixMode(GL.GL_PROJECTION)
		GL.glLoadIdentity()
		GL.glOrtho(0.0,self.width(),0.0,self.height(),-10,10)
		GL.glMatrixMode(GL.GL_MODELVIEW)
		GL.glLoadIdentity()

		self.resize_event(width,height)

	def closeEvent(self,event):
		self.clear_gl_memory()
		EMGLWidget.closeEvent(self, event)
		if self.inspector : self.inspector.closeEvent(self, event)

	def keyPressEvent(self,event):
		if event.key() == Qt.Key_C:
			self.show_inspector(1)
		elif event.key() == Qt.Key_F1:
			try: from PyQt4 import QtWebKit
			except: return
			try:
				try: test = self.browser
				except:
					self.browser = QtWebKit.QWebView()
					self.browser.load(QtCore.QUrl("http://blake.bcm.edu/emanwiki/e2display"))
					self.browser.resize(800,800)
				if not self.browser.isVisible(): self.browser.show()
			except: pass

	def setWindowTitle(self,filename):
		EMGLWidget.setWindowTitle(self, remove_directories_from_name(filename,1))

	def clear_gl_memory(self):
		if self.tex_name != 0:
			GL.glDeleteTextures(self.tex_name)
			self.tex_name = 0
		if self.main_display_list != 0:
			glDeleteLists(self.main_display_list,1)
			self.main_display_list = 0

	def set_data(self,input_data,key="data",replace=False,quiet=False,color=-1,alpha=0.8,rwidth=0.8):#,htype="bar",orient="vertical",align="mid",alpha=0.8,width=0.8,norm=False,cumul=False,logy=False,stacked=False):
		"""Set a keyed data set. The key should generally be a string describing the data.
		'data' is a tuple/list of tuples/list representing all values for a particular
		axis. eg - the points: 1,5; 2,7; 3,9 would be represented as ((1,2,3),(5,7,9)).
		Multiple axes may be set, and which axis represents which axis in the plot can be
		selected by the user. 'data' can also be an EMData object, in which case the entire
		data array is plotted as if it were 1-D.

		linetype and symtype are integers. -1 will disable either. Default is autoselect."""
		self.del_shapes()
		self.needupd=1
		if replace:
			self.data = {}
			self.axes = {}
			self.bins = {}
			self.visibility = {}
		if input_data is None :
			self.data.pop(key)
			self.visibility.pop(key)
			self.axes.pop(key)
			self.bins.pop(key)
			try: self.comments.pop(key)
			except: pass
			if self.inspector: self.inspector.datachange()
			if not quiet: self.updateGL()
			return
		if self.data.has_key(key) : oldkey=True
		else: oldkey=False
		if isinstance(input_data,EMData):
			data = input_data.get_data_as_vector()
		else: data = input_data
		if not isinstance(data[0],list) and not isinstance(data[0],tuple) and not isinstance(data[0],ndarray):
			x_axis = arange(len(data))
			data = [ x_axis,array(data) ]		# replace data with our refactored version
			self.data[key]= data
			self.visibility.setdefault(key,True)
		else:
			self.data[key]=[array(i) for i in data]
			self.visibility.setdefault(key,True)
		try:
			if len(data)>1 :
				if len(data)>2:
					try:
						if data[0][2]-data[0][1]==1 : self.axes[key]=(1,)#,2,-2,-2)	# if it looks like the first axis is a boring count
						else : self.axes[key]=(0,)#,1,-2,-2)
					except: self.axes[key]=(0,)#,1,-2,-2)
				else : self.axes[key]=(0,)#,1,-2,-2)
			else : self.axes[key]=(-1,)#,0,-2,-2)
		except:
			print "Data error:", data
			return

		self.bins[key],self.edges = np.histogram(self.data[key][self.axes[key][0]],self.nbins,range=self.xlimits,density=self.normed)

		if oldkey:
			pp=self.pparm[key]
			if color < 0 or color > len(colortypes): color= pp[0]
			if alpha > 1.0 or alpha < 0.0: alpha = pp[1]
			if rwidth > 1.0 or rwidth < 0.0: rwidth = pp[2]
		else:
			if color < 0: color=len(self.data)%len(colortypes)
			if color > len(colortypes): color = 0
			if alpha > 1.0: alpha = 1.0
			if alpha < 0.0: alpha = 0.8
			if rwidth < 0.0: rwidth = 0.8
			if rwidth > 1.0: rwidth = 1.0
		self.pparm[key]=(color,alpha,rwidth)

		self.autoscale()
		if self.inspector: self.inspector.datachange()
		if not quiet: self.updateGL()

	def get_inspector(self):
		if not self.inspector :
			self.inspector=EMHistogramInspector(self)
			self.inspector.datachange()
		return self.inspector

	def set_data_from_file(self,filename,replace=False,quiet=False):
		"""Reads a keyed data set from a file. Automatically interpret the file contents."""
		self.del_shapes()
		if replace:
			self.data = {}
			self.axes = {}
			self.visibility = {}
		file_type = Util.get_filename_ext(filename)
		em_file_type = EMUtil.get_image_ext_type(file_type)
		if em_file_type != IMAGE_UNKNOWN or filename[:4]=="bdb:" :
			im=EMData.read_images(filename)
			if len(im) == 1:
				im = im[0]
				l = [i for i in range(im.get_size())]
				k = im.get_data_as_vector()
				if self.data.has_key(filename) : filename="{}.{}".format(filename,len(self.data))
				self.set_data([l,k],filename,quiet=quiet)
			elif im[0].get_attr_default("isvector",0):
				all=[]
				for j in range(im[0].get_xsize()):
					r=[]
					for i in range(len(im)):
						r.append(im[i][j,0])
					all.append(r)
				self.set_data(all,vecset,quiet=quiet)
			else:
				for idx,image in enumerate(im):
					l = [i for i in range(image.get_size())]
					k = image.get_data_as_vector()
					self.set_data([l,k],filename+":"+str(idx),quiet=quiet)
		elif file_type == 'fp':
			fin=file(filename)
			fph=struct.unpack("120sII",fin.read(128))
			ny=fph[1]
			nx=fph[2]
			data=[]
			for i in range(nx):
				data.append(struct.unpack("%df"%ny,fin.read(4*ny)))
			self.set_data(data,filename,quiet=quiet)
		else:
			try:
				fin=file(filename)
				fin.seek(0)
				rdata=fin.readlines()
				if '#' in rdata[0]:
					try: comments=[i.split("#",1)[1].strip() for i in rdata if i[0]!="#"]
					except: comments=None
				else: comments=None
				rdata=[i.split("#")[0] for i in rdata if i[0]!='#']
				if ',' in rdata[0]: rdata=[[float(j) for j in i.split(',')] for i in rdata]
				else : rdata=[[float(j) for j in i.split()] for i in rdata]
				nx=len(rdata[0])
				ny=len(rdata)
				data=[[rdata[j][i] for j in range(ny)] for i in range(nx)]
				self.set_data(data,remove_directories_from_name(filename,1),quiet=quiet)#,comments=comments)
			except:
				traceback.print_exc()
				print "couldn't read",filename
				return False
		return True

	@staticmethod
	def get_data_from_file(filename):
		file_type = Util.get_filename_ext(filename)
		em_file_type = EMUtil.get_image_ext_type(file_type)
		data = None
		if em_file_type != IMAGE_UNKNOWN or filename[:4]=="bdb:" :
			im=EMData.read_images(filename)
			if len(im) == 1:
				im = im[0]
				l = [i for i in range(im.get_size())]
				k = im.get_data_as_vector()
				data = [l,k]
			elif im[0].get_attr_default("isvector",0):
				all=[]
				for j in range(im[0].get_xsize()):
					r=[]
					for i in range(len(im)):
						r.append(im[i][j,0])
					all.append(r)
				data = all
			else:
				for idx,image in enumerate(im):
					l = [i for i in range(image.get_size())]
					k = image.get_data_as_vector()
					data = [l,k]
		elif file_type == 'fp':
			fin=file(filename)
			fph=struct.unpack("120sII",fin.read(128))
			ny=fph[1]
			nx=fph[2]
			data=[]
			for i in range(nx):
				data.append(struct.unpack("%df"%ny,fin.read(4*ny)))
		else:
			try:
				fin=file(filename)
				fin.seek(0)
				rdata=fin.readlines()
				rdata=[i for i in rdata if i[0]!='#']
				if ',' in rdata[0]: rdata=[[float(j) for j in i.split(',')] for i in rdata]
				else : rdata=[[float(j) for j in i.split()] for i in rdata]
				nx=len(rdata[0])
				ny=len(rdata)
				data=[[array([rdata[j][i]]) for j in range(ny)] for i in range(nx)]
			except:
				print "couldn't read",filename
		return data

	@staticmethod
	def is_file_readable(filename):
		'''
		Called by file browsing interfaces to determine if the file is plottable
		Tries to parse two lines, convert the values into floats, make sure
		the number of columns matches etc. If something goes wrong then return False.
		This function should be tightly coupled to set_data_from_file function, should
		any adaptations occur in future
		'''
		try:
			fin=file(filename)
			fin.seek(0)
			rdata = []
			while (len(rdata) < 2):
				line = fin.readline()
				if line == '': # this is equivalent to EOF
					break
				elif line[0] == '#': continue
				else: rdata.append(line)
			#print rdata
			if len(rdata) < 2: return False
			if ',' in rdata[0]: rdata=[[float(j) for j in i.split(',')] for i in rdata]
			else : rdata=[[float(j) for j in i.split()] for i in rdata]
			if len(rdata[0]) == 0 or len(rdata[1]) == 0: return False
			if  len(rdata[0]) != len(rdata[1]) : return False
			return True
		except:
			return False

	def render(self):
		try:
			if self.data==None or len(self.data)==0: return
			if self.xlimits==None or self.ylimits==None: return
		except:
			return
		render = False
		if self.needupd or not self.plotimg:
			self.needupd=0
			if self.main_display_list != 0:
				glDeleteLists(self.main_display_list,1)
				self.main_display_list = 0
		if self.main_display_list == 0:
			self.main_display_list = glGenLists(1)
			glNewList(self.main_display_list,GL_COMPILE)
			render = True
		lighting = glIsEnabled(GL_LIGHTING)
		glDisable(GL_LIGHTING)
		EMShape.font_renderer=self.font_renderer		# Important !  Each window has to have its own font_renderer. Only one context active at a time, so this is ok.
		GL.glPushMatrix()
		# overcome depth issues
		glTranslate(0,0,5)
		for k,s in self.shapes.items():
			s.draw(self.scr2plot)
		GL.glPopMatrix()
		if render:
			fig=Figure((self.width()/72.0,self.height()/72.0),dpi=72.0)
			ax=fig.add_axes((.1,.1,.88,.88),autoscale_on=False,xlim=self.xlimits,ylim=self.ylimits,xscale=self.axisparms[2],yscale=self.axisparms[3])
			#if self.axisparms[0] and len(self.axisparms[0])>0 : ax.set_xlabel(self.axisparms[0],size="xx-large")
			#if self.axisparms[1] and len(self.axisparms[1])>0 : ax.set_ylabel(self.axisparms[1],size="xx-large")
			ax.tick_params(axis='x', labelsize="x-large")
			ax.tick_params(axis='y', labelsize="x-large")
			canvas=FigureCanvasAgg(fig)

			if self.inspector == None:
				self.inspector = self.get_inspector()

			#tostack = []
			usedkeys = []
			#colors = []

			if self.alignment == "center":
				histalign = "mid"
			elif self.alignment == "edge":
				histalign = "left"

			for k in self.axes.keys():
				if not self.visibility[k]: continue

				dcurr = self.data[k][self.axes[k][0]]
				color = colortypes[self.pparm[k][0]]
				alpha = self.pparm[k][1]
				rwidth = self.pparm[k][2]

				self.bins[k],self.edges = np.histogram(dcurr,self.nbins,range=self.xlimits,density=self.normed)
				width = (self.edges[1]-self.edges[0])*rwidth

				if self.cumulative:
					self.bins[k] = np.cumsum(self.bins[k])
				if self.normed:
					self.bins[k] /= np.sum(self.bins[k])
					self.bins[k] /= len(self.axes.keys())

				if self.histtype == "bar":
					if self.stacked and len(usedkeys) > 0:
						bottom = self.getTotals(keys=usedkeys)
						ax.bar(self.edges[:-1],self.bins[k], width, color=color,bottom=bottom, align=self.alignment, log=self.logy, orientation=self.orientation, alpha=alpha)
					else:
						ax.bar(self.edges[:-1],self.bins[k], width, color=color, align=self.alignment, log=self.logy, orientation=self.orientation, alpha=alpha)
						usedkeys.append(k)

				elif self.histtype == "step" or self.histtype == "stepfilled":
					if self.stacked == False:
						ax.hist(self.bins[k],bins=self.edges,color=None,range=self.xlimits,histtype=self.histtype, align=histalign, orientation=self.orientation,alpha=self.inspector.alpha.getValue(),normed=self.normed,cumulative=self.cumulative,log=self.logy,stacked=self.stacked)
					else:
						tostack.append(self.bins[k])
						colors.append(color)

			if self.histtype == "step" or self.histtype == "stepfilled":
				if self.stacked == True:
					ax.hist(tostack,bins=self.edges,color=colors,range=self.xlimits,histtype=self.histtype,orientation=self.orientation,align=histalign,alpha=self.inspector.alpha.getValue(),normed=self.normed,cumulative=self.cumulative,log=self.logy,stacked=self.stacked)

			self.autoscale(True)
			ax.set_ylim(self.ylimits)

			canvas.draw()
			self.plotimg = canvas.tostring_rgb()  # save this and convert to bitmap as needed

			# this try except block is because the developers of matplotlib have been changing their API
			try: # this would work for matplotlib 0.98
				self.scrlim=(ax.get_window_extent().xmin,ax.get_window_extent().ymin,ax.get_window_extent().xmax-ax.get_window_extent().xmin,ax.get_window_extent().ymax-ax.get_window_extent().ymin)
			except:
				try: # this should work for matplotlib 0.91
					self.scrlim=(ax.get_window_extent().xmin(),ax.get_window_extent().ymin(),ax.get_window_extent().xmax()-ax.get_window_extent().xmin(),ax.get_window_extent().ymax()-ax.get_window_extent().ymin())
				except:
					print 'there is a problem with your matplotlib'
					return
			self.plotlim=(ax.get_xlim()[0],ax.get_ylim()[0],ax.get_xlim()[1]-ax.get_xlim()[0],ax.get_ylim()[1]-ax.get_ylim()[0])

			if not self.glflags.npt_textures_unsupported():
				self.__texture_plot(self.plotimg)
			else:
				GL.glRasterPos(0,self.height()-1)
				GL.glPixelZoom(1.0,-1.0)
		#		print "paint ",self.width(),self.height(), self.width()*self.height(),len(a)
				GL.glPixelStorei(GL.GL_UNPACK_ALIGNMENT,1)
				GL.glDrawPixels(self.width(),self.height(),GL.GL_RGB,GL.GL_UNSIGNED_BYTE,self.plotimg)
		else:
			try:
				glCallList(self.main_display_list)
			except: pass

		if render :
			glEndList()
			try: glCallList(self.main_display_list)
			except: pass

		if lighting : glEnable(GL_LIGHTING)


	def __texture_plot(self,image_data):
		texture_2d_was_enabled = GL.glIsEnabled(GL.GL_TEXTURE_2D)
		if not texture_2d_was_enabled:GL.glEnable(GL.GL_TEXTURE_2D)

		if self.tex_name != 0: GL.glDeleteTextures(self.tex_name)
		self.tex_name = GL.glGenTextures(1)
		GL.glPixelStorei(GL.GL_UNPACK_ALIGNMENT,1)
		GL.glBindTexture(GL.GL_TEXTURE_2D,self.tex_name)
		GL.glTexImage2D(GL.GL_TEXTURE_2D,0,GL.GL_RGB,self.width(),self.height(),0,GL.GL_RGB,GL.GL_UNSIGNED_BYTE, image_data)

		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)

		# POSITIONING POLICY - the texture occupies the entire screen area
		glBegin(GL_QUADS)

		glTexCoord2f(0,0)
		glVertex2f(0,self.height())

		glTexCoord2f(1,0)
		glVertex2f(self.width(),self.height())

		glTexCoord2f(1,1)
		glVertex2f(self.width(),0)

		glTexCoord2f(0,1)
		glVertex2f(0,0)

		glEnd()

		if not texture_2d_was_enabled: GL.glDisable(GL.GL_TEXTURE_2D)

	def scr2plot(self,x,y) :
		""" converts screen coordinates to plot coordinates """
		try:
			if self.axisparms[2]=="linear" : x2=(x-self.scrlim[0])/self.scrlim[2]*self.plotlim[2]+self.plotlim[0]
			else : x2=10.0**((x-self.scrlim[0])/self.scrlim[2]*(log10(self.plotlim[2]+self.plotlim[0])-log10(self.plotlim[0]))+log10(self.plotlim[0]))
			if self.axisparms[3]=="linear" : y2=(self.height()-y-self.scrlim[1])/self.scrlim[3]*self.plotlim[3]+self.plotlim[1]
			else : y2=10.0**((self.height()-y-self.scrlim[1])/self.scrlim[3]*(log10(self.plotlim[3]+self.plotlim[1])-log10(self.plotlim[1]))+log10(self.plotlim[1]))
			return (x2,y2)
		except: return (0,0)

	def plot2scr(self,x,y) :
		""" converts plot coordinates to screen coordinates """
		try:
			if self.axisparms[2]=="linear" : x2=(x-self.plotlim[0])/self.plotlim[2]*self.scrlim[2]+self.scrlim[0]
			else : x2=(-(self.scrlim[2]*log(x)) + (self.scrlim[0] + self.scrlim[2])*log(10)*log10(self.plotlim[0])-self.scrlim[0]*log(10)*log10(self.plotlim[0] +self.plotlim[2])) /(log(10)*(log10(self.plotlim[0]) - log10(self.plotlim[0] + self.plotlim[2])))
			if self.axisparms[3]=="linear" :y2=self.height()-((y-self.plotlim[1])/self.plotlim[3]*self.scrlim[3]+self.scrlim[1])
			else : y2=(self.scrlim[3]*log(y) + self.height()*log(10.0)*log10(self.plotlim[1])-self.scrlim[1]*log(10.0)*log10(self.plotlim[1])-self.scrlim[3]*log(10.0)*log10(self.plotlim[1]) - self.height()*log(10.0)*log10(self.plotlim[1]+self.plotlim[3]) + self.scrlim[1]*log(10)*log10(self.plotlim[1]+self.plotlim[3])) / (log(10)*(log10(self.plotlim[1]) - log10(self.plotlim[1]+self.plotlim[3])))
			return (x2,y2)
		except:
			return (0,0)

	def resize_event(self,width,height):
		self.full_refresh()

	def full_refresh(self):
		'''
		This function is called from resizeGL and from the inspector when somebody toggles the display of a line
		'''
		self.needupd=1
		self.del_shapes(("xcross","ycross","lcross","Circle"))

	def setAxisParms(self,xlabel,ylabel,xlog="linear",ylog="linear"):
		#self.axisparms=(xlabel,ylabel,xlog,ylog)
		self.needupd=1
		self.updateGL()

	def setAxes(self,key,xa,quiet=False):
		if self.axes[key]==(xa,) : return
		self.axes[key]=(xa,)
		self.autoscale(True)
		self.needupd=1
		if not quiet : self.updateGL()

	def setPlotParms(self,key,color=-1,alpha=0.8,rwidth=0.8,quiet=False):
		if self.pparm[key]==(color,alpha,rwidth): return
		self.pparm[key]=(color,alpha,rwidth)
		self.needupd=1
		if not quiet: self.updateGL()

	def add_shape(self,k,s):
		"""Add a 'shape' object to be overlaid on the image. Each shape is
		keyed into a dictionary, so different types of shapes for different
		purposes may be simultaneously displayed. The 'scr' shapes are in
		screen coordinates rather than data coordinates

		0            1  2  3  4  5     6     7     8
		"rect"       R  G  B  x0 y0    x1    y1    linew
		"line"       R  G  B  x0 y0    x1    y1    linew
		"label"      R  G  B  x0 y0    text  size	linew
		"circle"     R  G  B  x0 y0    r     linew
		"scrrect"    R  G  B  x0 y0    x1    y1    linew
		"scrline"    R  G  B  x0 y0    x1    y1    linew
		"scrlabel"   R  G  B  x0 y0    text  size	linew
		"scrcircle"  R  G  B  x0 y0    r     linew
		"""
		self.shapes[k]=s
		self.shapechange=1

	def add_shapes(self,d):
		self.shapes.update(d)
		self.shapechange=1

	def del_shapes(self,k=None):
		if k:
			try:
				for i in k:
					if i in self.shapes : del self.shapes[i]
			except:
				try: del self.shapes[k]
				except: return
		else:
			self.shapes={}
		self.shapechange=1

	def update_selected(self,evc,lc): # could use this to highlight selected bin in histogram
		"""Update the list of 'selected' points, and display coord info.
evc is the cursor selection point in screen coords
lc is the cursor selection point in plot coords"""
		return

	def mousePressEvent(self, event):
		lc=self.scr2plot(event.x(),event.y())
		if event.button()==Qt.MidButton or (event.button()==Qt.LeftButton and event.modifiers()&Qt.AltModifier):
			self.show_inspector(1)
		elif event.button()==Qt.RightButton or (event.button()==Qt.LeftButton and event.modifiers()&Qt.AltModifier):
			self.del_shapes()
			self.updateGL()
			self.rmousedrag=(event.x(),event.y())
		elif event.button()==Qt.LeftButton:
			self.del_shapes()
			self.add_shape("ycross",EMShape(("scrline",0,0,0,event.x(),self.scrlim[1],event.x(),self.scrlim[3]+self.scrlim[1],1)))
			histlabel = ""
			idx = self.getBinIndex(lc[0])
			if idx != None:
				count = self.getBinCount(idx)
				histlabel = "{}; ({:1.5g}, {:1.5g})".format(count,self.edges[idx],self.edges[idx+1])
			else:
				histlabel = ""
			self.add_shape("lcrosshist0",EMShape(("scrlabel",0,0,0,self.scrlim[2]-175,self.scrlim[3]-10,histlabel,120.0,-1)))
			self.add_shape("lcrosshist",EMShape(("scrlabel",0,0,0,self.scrlim[2]-175,self.scrlim[3]-10,histlabel,120.0,-1)))
			self.update_selected((event.x(),event.y()),lc)
			self.updateGL()

	def mouseMoveEvent(self, event):
		lc=self.scr2plot(event.x(),event.y())
		if  self.rmousedrag:
			self.add_shape("xzoom1",EMShape(("scrline",0,0,0,self.rmousedrag[0],self.scrlim[1],self.rmousedrag[0],self.scrlim[3]+self.scrlim[1],1)))
			self.add_shape("xzoom2",EMShape(("scrline",0,0,0,event.x(),self.scrlim[1],event.x(),self.scrlim[3]+self.scrlim[1],1)))
			zm = self.scr2plot(self.rmousedrag[0],self.rmousedrag[1])
			zoomlabel = "{:1.5g}; ({:1.5g},{:1.5g})".format(np.abs(lc[0]-zm[0]),zm[0],lc[0])
			self.add_shape("lzoom",EMShape(("scrlabel",0,0,0,self.scrlim[2]-175,self.scrlim[3]-10,zoomlabel,120.0,-1)))
			self.updateGL()
		elif event.buttons()&Qt.LeftButton:
			self.del_shapes()
			self.add_shape("ycross",EMShape(("scrline",0,0,0,event.x(),self.scrlim[1],event.x(),self.scrlim[3]+self.scrlim[1],1)))
			histlabel = ""
			idx = self.getBinIndex(lc[0])
			if idx != None:
				count = self.getBinCount(idx)
				histlabel = "{}; ({:1.5g}, {:1.5g})".format(count,self.edges[idx],self.edges[idx+1])
			else:
				histlabel = ""
			self.add_shape("lcrosshist",EMShape(("scrlabel",0,0,0,self.scrlim[2]-175,self.scrlim[3]-10,histlabel,120.0,-1)))
			self.update_selected((event.x(),event.y()),lc)
			self.updateGL()

	def getBinIndex(self,x):
		if x < self.edges[0] or x > self.edges[-1]: return None
		else:
			idx = 0
			for x0,x1 in zip(self.edges[:-1],self.edges[1:]):
				if x > x0 and x < x1: break
				else: idx+=1
			return idx

	def getTotals(self,bins=[],keys=[]):
		if len(bins) == 0:
			return [self.getBinCount(n,keys) for n in range(self.nbins)]
		else:
			return [self.getBinCount(n,keys) for n in bins]

	def getBinCount(self,n,keys=[]):
		if len(keys) == 0:
			return sum([self.bins[k][n] for k in self.bins.keys()])
		else:
			return sum([self.bins[k][n] for k in keys])

	def setPlotRepr(self,repr):
		if self.histtype != repr["histtype"]:
			self. histtype = repr["histtype"]
			self.needupd = 1
		if self.orientation != repr["orientation"]:
			self. orientation = repr["orientation"]
			self.needupd = 1
		if self.alignment != repr["alignment"]:
			self. alignment = repr["alignment"]
			self.needupd = 1
		if self.normed != repr["normed"]:
			self. normed = repr["normed"]
			self.needupd = 1
		if self.logy != repr["logy"]:
			self. logy = repr["logy"]
			self.needupd = 1
		if self.cumulative != repr["cumulative"]:
			self. cumulative = repr["cumulative"]
			self.needupd = 1
		if self.stacked != repr["stacked"]:
			self. stacked = repr["stacked"]
			self.needupd = 1

	def setNBins(self,nbins):
		if nbins != self.nbins:
			self.nbins = nbins
			self.needupd = 1

	def mouseReleaseEvent(self, event):
		lc =self.scr2plot(event.x(),event.y())
		if self.rmousedrag:
			lc2=self.scr2plot(*self.rmousedrag)
			if fabs(event.x()-self.rmousedrag[0])+fabs(event.y()-self.rmousedrag[1])<3 : self.rescale(0,0,0,0)
			else :
				self.autoscale(True)
				self.rescale(min(lc[0],lc2[0]),max(lc[0],lc2[0]),self.ylimits[0],self.ylimits[1])
			self.rmousedrag=None

	def rescale(self,x0,x1,y0,y1,quiet=False):
		"adjusts the value range for the x/y axes"
		self.xlimits=(x0,x1)
		self.ylimits=(y0,y1)
		if x0>=x1 or y0>=y1 : self.autoscale()
		self.needupd=1
		self.del_shapes()  # also triggers an update
		self.updateGL()
		if self.inspector: self.inspector.update()

	def recolor(self,c0,c1,quiet=False):
		"adjusts the value range for the marker color display"
		self.needupd=1
		self.del_shapes()  # also triggers an update
		self.updateGL()
		if self.inspector: self.inspector.update()

	def autoscale(self,force=False,xmin=1.0e38,xmax=-1.0e38,ymin = 0,ymax = -1e38):
		"This autoscales, but only axes which currently have invalid settings"

		if force or self.xlimits==None or self.xlimits[1]<=self.xlimits[0] :
			for k in self.axes.keys():
				if not self.visibility[k]: continue
				xmin=min(xmin,min(self.data[k][self.axes[k][0]]))
				xmax=max(xmax,max(self.data[k][self.axes[k][0]]))
			if self.axisparms[2]!="linear" : self.xlimits=(xmin/1.1,xmax*1.1)
			else:
				margin=(xmax-xmin)*0.025
				self.xlimits=(xmin-margin,xmax+margin)

		if force or self.ylimits==None or self.ylimits[1]<=self.ylimits[0] :
			if self.stacked:
				counts = self.getTotals()
				ymax = max(ymax,max(counts))
				ymin = min(ymin,min(counts))
			else:
				for k in self.bins.keys():
					#print(self.bins[k])
					ymax = max(ymax,max(self.bins[k]))
					ymin = min(ymin,min(self.bins[k]))
			if self.axisparms[3]!="linear" :
				self.ylimits=(ymin/1.1,ymax*1.1)
			else:
				margin = ymax*0.025
				self.ylimits = (ymin-margin, ymax+margin)

		if self.inspector: self.inspector.update()

	def wheelEvent(self, event):
		pass
		#if event.delta() > 0:
			#self.set_scale(self.scale + MAG_INC)
		#elif event.delta() < 0:
			#if ( self.scale - MAG_INC > 0 ):
				#self.set_scale(self.scale - MAG_INC)
		## The self.scale variable is updated now, so just update with that
		#if self.inspector: self.inspector.set_scale(self.scale)

	def leaveEvent(self,event):
		pass