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 fileUpdate(self): "Called when the user selects a file from the list or need to completely refresh display" QtGui.qApp.setOverrideCursor(Qt.BusyCursor) if self.vclasses==None : self.vclasses=EMImageMXWidget() self.vclasses.set_mouse_mode("App") QtCore.QObject.connect(self.vclasses,QtCore.SIGNAL("mx_image_selected"),self.classSelect) QtCore.QObject.connect(self.vclasses,QtCore.SIGNAL("mx_image_double"),self.classDouble) self.vclasses.set_title("Classes") # self.classes=EMData.read_images(self.curFile()) self.vclasses.set_data(self.curFile(),self.curFile()) # self.vclasses.set_single_active_set("selected") # This makes the 'set' representing the selected class-averages current self.vclasses.set_mouse_mode("App") self.vclasses.enable_set("evalptcl",[]) # This makes sure the particle file is in the list of choices and is selected try: ptclfile=EMData(self.curFile(),0,True)["class_ptcl_src"] i=self.wptclfile.findText(ptclfile) if i==-1 : self.wptclfile.insertItem(0,ptclfile) self.wptclfile.setCurrentIndex(0) else: self.wptclfile.setCurrentIndex(i) except: QtGui.QMessageBox.warning(self,"Error !","This image does not appear to be a class average. (No class_ptcl_src, etc.)") ptclfile="None" # Make sure our display widgets exist if self.vgoodptcl==None : self.vgoodptcl=EMImageMXWidget() self.vgoodptcl.set_title("Included Particles") if self.vbadptcl==None : self.vbadptcl=EMImageMXWidget() self.vbadptcl.set_title("Excluded Particles") self.vclasses.show() self.vgoodptcl.show() self.vbadptcl.show() QtGui.qApp.setOverrideCursor(Qt.ArrowCursor)
def fileUpdate(self): "Called when the user selects a file from the list or need to completely refresh display" QtGui.qApp.setOverrideCursor(Qt.BusyCursor) if self.vclasses == None: self.vclasses = EMImageMXWidget() self.vclasses.set_mouse_mode("App") QtCore.QObject.connect(self.vclasses, QtCore.SIGNAL("mx_image_selected"), self.classSelect) QtCore.QObject.connect(self.vclasses, QtCore.SIGNAL("mx_image_double"), self.classDouble) self.vclasses.set_title("Classes") # self.classes=EMData.read_images(self.curFile()) self.vclasses.set_data(self.curFile(), self.curFile()) # self.vclasses.set_single_active_set("selected") # This makes the 'set' representing the selected class-averages current self.vclasses.set_mouse_mode("App") self.vclasses.enable_set("evalptcl", []) # This makes sure the particle file is in the list of choices and is selected try: ptclfile = EMData(self.curFile(), 0, True)["class_ptcl_src"] i = self.wptclfile.findText(ptclfile) if i == -1: self.wptclfile.insertItem(0, ptclfile) self.wptclfile.setCurrentIndex(0) else: self.wptclfile.setCurrentIndex(i) except: QtGui.QMessageBox.warning( self, "Error !", "This image does not appear to be a class average. (No class_ptcl_src, etc.)" ) ptclfile = "None" # Make sure our display widgets exist if self.vgoodptcl == None: self.vgoodptcl = EMImageMXWidget() self.vgoodptcl.set_title("Included Particles") if self.vbadptcl == None: self.vbadptcl = EMImageMXWidget() self.vbadptcl.set_title("Excluded Particles") self.vclasses.show() self.vgoodptcl.show() self.vbadptcl.show() QtGui.qApp.setOverrideCursor(Qt.ArrowCursor)
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()
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
def __init__(self,images,voltage=None,apix=None,cs=None,ac=10.0,box=512): """The 'new' e2boxer interface. """ try: from emimage2d import EMImage2DWidget except: print "Cannot import EMAN image GUI objects (EMImage2DWidget)" sys.exit(1) try: from emimagemx import EMImageMXWidget except: print "Cannot import EMAN image GUI objects (EMImageMXWidget)" sys.exit(1) try: from emplot2d import EMPlot2DWidget except: print "Cannot import EMAN plot GUI objects (is matplotlib installed?)" sys.exit(1) QtGui.QWidget.__init__(self,None) self.setWindowIcon(QtGui.QIcon(get_image_directory() + "ctf.png")) self.data=None self.curfilename = None self.defaultvoltage=voltage self.defaultapix=apix self.defaultcs=cs self.defaultac=ac self.wimage=EMImage2DWidget() self.wimage.setWindowTitle("Micrograph") self.wparticles=EMImageMXWidget() self.wparticles.setWindowTitle("Particles") #self.wfft=EMImage2DWidget() #self.wfft.setWindowTitle("e2evalimage - 2D FFT") #self.wplot=EMPlot2DWidget() #self.wplot.setWindowTitle("e2evalimage - Plot") self.wimage.connect(QtCore.SIGNAL("mousedown"),self.imgmousedown) self.wimage.connect(QtCore.SIGNAL("mousedrag"),self.imgmousedrag) self.wimage.connect(QtCore.SIGNAL("mouseup") ,self.imgmouseup) self.wparticles.connect(QtCore.SIGNAL("mousedown"),self.ptclmousedown) self.wparticles.connect(QtCore.SIGNAL("mousedrag"),self.ptclmousedrag) self.wparticles.connect(QtCore.SIGNAL("mouseup") ,self.ptclmouseup) self.wimage.mmode="app" self.wparticles.mmode="app" # This object is itself a widget we need to set up self.gbl = QtGui.QGridLayout(self) self.gbl.setMargin(8) self.gbl.setSpacing(6) # plot list and plot mode combobox self.setlist=e2ctf.MyListWidget(self) self.setlist.setSizePolicy(QtGui.QSizePolicy.Preferred,QtGui.QSizePolicy.Expanding) for i in images: self.setlist.addItem(i) self.gbl.addWidget(self.setlist,0,0,10,2) self.lboxmode=QtGui.QLabel("Mode:",self) self.gbl.addWidget(self.lboxmode,10,0) self.sboxmode=QtGui.QComboBox(self) self.sboxmode.addItem("Manual") self.sboxmode.addItem("Reference") self.sboxmode.setCurrentIndex(1) self.gbl.addWidget(self.sboxmode,10,1) self.lanmode=QtGui.QLabel("Annotate:",self) self.gbl.addWidget(self.lanmode,12,0) self.sanmode=QtGui.QComboBox(self) self.sanmode.addItem("Box") self.sanmode.addItem("Box+dot") self.sanmode.addItem("Circle") self.sanmode.addItem("None") self.gbl.addWidget(self.sanmode,12,1) self.sdefocus=ValSlider(self,(0,5),"Defocus:",0.0,90) self.gbl.addWidget(self.sdefocus,0,2,1,3) self.squality=ValSlider(self,(0,9),"Quality (0-9):",0,90) self.squality.setIntonly(True) self.gbl.addWidget(self.squality,6,2,1,3) self.brefit=QtGui.QPushButton("Autobox") self.gbl.addWidget(self.brefit,7,2) self.bclrauto=QtGui.QPushButton("Clear Auto") self.gbl.addWidget(self.bclrauto,7,3) self.bclrall=QtGui.QPushButton("Clear All") self.gbl.addWidget(self.bclrall,7,4) self.sapix=ValBox(self,(0,500),"A/pix:",1.0,90) if self.defaultapix!=None : self.sapix.setValue(self.defaultapix) self.gbl.addWidget(self.sapix,10,2) self.svoltage=ValBox(self,(0,500),"Voltage (kV):",200,90) if self.defaultvoltage!=None : self.svoltage.setValue(self.defaultvoltage) self.gbl.addWidget(self.svoltage,11,2) self.scs=ValBox(self,(0,5),"Cs (mm):",4.1,90) if self.defaultcs!=None : self.scs.setValue(self.defaultcs) self.gbl.addWidget(self.scs,12,2) self.sboxsize=ValBox(self,(0,500),"Box Size:",256,90) self.sboxsize.intonly=True self.gbl.addWidget(self.sboxsize,13,2) self.sptclsize=ValBox(self,(0,500),"Ptcl Size:",256,90) self.sptclsize.intonly=True self.gbl.addWidget(self.sptclsize,14,2) QtCore.QObject.connect(self.sdefocus, QtCore.SIGNAL("valueChanged"), self.newCTF) QtCore.QObject.connect(self.sapix, QtCore.SIGNAL("valueChanged"), self.newCTF) QtCore.QObject.connect(self.svoltage, QtCore.SIGNAL("valueChanged"), self.newCTF) QtCore.QObject.connect(self.scs, QtCore.SIGNAL("valueChanged"), self.newCTF) QtCore.QObject.connect(self.sboxsize, QtCore.SIGNAL("valueChanged"), self.newBox) # QtCore.QObject.connect(self.soversamp, QtCore.SIGNAL("valueChanged"), self.newBox) QtCore.QObject.connect(self.squality,QtCore.SIGNAL("valueChanged"),self.newQualityFactor) QtCore.QObject.connect(self.setlist,QtCore.SIGNAL("currentRowChanged(int)"),self.newSet) QtCore.QObject.connect(self.setlist,QtCore.SIGNAL("keypress"),self.listkey) QtCore.QObject.connect(self.sboxmode,QtCore.SIGNAL("currentIndexChanged(int)"),self.newBoxMode) self.resize(720,380) # figured these values out by printing the width and height in resize event ### This section is responsible for background updates self.busy=False self.needupdate=True self.needredisp=False self.procthread=None self.errors=None # used to communicate errors back from the reprocessing thread self.timer=QTimer() QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.timeOut) self.timer.start(100) self.setWindowTitle("e2boxer21 - Control Panel") self.wimage.show() self.wfft.show() self.wplot.show() E2loadappwin("e2boxer21","main",self) E2loadappwin("e2boxer21","image",self.wimage.qt_parent) E2loadappwin("e2boxer21","particles",self.wparticles.qt_parent)
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 __new__(cls,data=None,old=None,app=None,force_2d=False,force_plot=False,filename="",replace=True): """This will create a new EMImage* object depending on the type of 'data'. If old= is provided, and of the appropriate type, it will be used rather than creating a new instance. """ if isinstance(data,EMData) and data.get_size()==0: raise RuntimeError("Can not display an EMData object that has no pixels") from EMAN2 import remove_directories_from_name if force_plot and force_2d: # ok this sucks but it suffices for the time being print "Error, the force_plot and force_2d options are mutually exclusive" return None if force_plot or (isinstance(data,EMData) and data.get_zsize()==1 and data.get_ysize()==1): from emplot2d import EMPlot2DWidget if old: if isinstance(old,EMPlot2DWidget) : old.set_data(data,remove_directories_from_name(filename),replace) return old widget = EMPlot2DWidget(application=app) widget.set_data(data,remove_directories_from_name(filename),replace) return widget elif force_2d or (isinstance(data,EMData) and data.get_zsize()==1): from emimage2d import EMImage2DWidget if old: if isinstance(old,EMImage2DWidget) : old.set_data(data,filename) return old widget = EMImage2DWidget(application=app) widget.set_data(data,filename) return widget elif isinstance(data,EMData): if isinstance(old,EMScene3D): widget = old else: widget = EMScene3D() data = EMDataItem3D(data, transform=Transform()) #data.setSelectedItem(True) isosurface = EMIsosurface(data, transform=Transform()) widget.insertNewNode(os.path.basename(filename), data, parentnode=widget) widget.insertNewNode("Iso", isosurface, parentnode=data) return widget elif isinstance(data,list) and isinstance(data[0],EMData): from emimagemx import EMImageMXWidget if old: if isinstance(old,EMImageMXWidget) : old.set_data(data,filename) return old widget = EMImageMXWidget(application=app) widget.set_data(data,filename) return widget elif isinstance(data,list): from emplot3d import EMPlot3DWidgetNew if (isinstance(data[0],list) or isinstance(data[0],tuple)) and len(data) > 2: if old: if isinstance(old,EMPlot3DWidgetNew) : old.set_data(data,remove_directories_from_name(filename),replace) return old widget = EMPlot3DWidgetNew() widget.set_data(data,remove_directories_from_name(filename),replace) return widget else: from emplot2d import EMPlot2DWidget if old: if isinstance(old,EMPlot2DWidget) : old.set_data(data,remove_directories_from_name(filename),replace) return old widget = EMPlot2DWidget(application=app) widget.set_data(data,remove_directories_from_name(filename),replace) return widget else: raise Exception,"data must be a single EMData object or a list of EMData objects"
def __init__(self,imagenames,voltage=None,apix=None,cs=None,ac=10.0,box=256,ptcl=200): """The 'new' e2boxer interface. """ QtGui.QWidget.__init__(self,None) # self.setWindowIcon(QtGui.QIcon(get_image_directory() + "ctf.png")) self.data=None self.curfilename = None # current selected file for boxing self.filenames=imagenames # list of available filenames self.micrograph=None self.boxes=None self.defaultvoltage=voltage self.defaultapix=apix self.defaultcs=cs self.defaultac=ac self.db = None # open JSON file for current image self.wimage=EMImage2DWidget() self.wimage.setWindowTitle("Micrograph") self.wparticles=EMImageMXWidget() self.wparticles.setWindowTitle("Particles") self.wrefs=EMImageMXWidget() self.wrefs.setWindowTitle("Box Refs") self.wbadrefs=EMImageMXWidget() self.wbadrefs.setWindowTitle("Bad Box Refs") #self.wfft=EMImage2DWidget() #self.wfft.setWindowTitle("e2evalimage - 2D FFT") #self.wplot=EMPlot2DWidget() #self.wplot.setWindowTitle("e2evalimage - Plot") self.wimage.connect(self.wimage,QtCore.SIGNAL("mousedown"),self.imgmousedown) self.wimage.connect(self.wimage,QtCore.SIGNAL("mousedrag"),self.imgmousedrag) self.wimage.connect(self.wimage,QtCore.SIGNAL("mouseup") ,self.imgmouseup) self.wparticles.connect(self.wparticles,QtCore.SIGNAL("mousedown"),self.ptclmousedown) self.wparticles.connect(self.wparticles,QtCore.SIGNAL("mousedrag"),self.ptclmousedrag) self.wparticles.connect(self.wparticles,QtCore.SIGNAL("mouseup") ,self.ptclmouseup) self.wrefs.connect(self.wparticles,QtCore.SIGNAL("mousedown"),self.refmousedown) self.wrefs.connect(self.wparticles,QtCore.SIGNAL("mousedrag"),self.refmousedrag) self.wrefs.connect(self.wparticles,QtCore.SIGNAL("mouseup") ,self.refmouseup) self.wimage.mmode="app" self.wparticles.mmode="app" # This object is itself a widget we need to set up self.gbl = QtGui.QGridLayout(self) self.gbl.setMargin(8) self.gbl.setSpacing(6) # Micrograph list self.setlist=QtGui.QListWidget(self) self.setlist.setSizePolicy(QtGui.QSizePolicy.Preferred,QtGui.QSizePolicy.Expanding) for i in imagenames: self.setlist.addItem(i) self.gbl.addWidget(self.setlist,0,0,12,2) self.setlist.connect(self.setlist,QtCore.SIGNAL("currentRowChanged(int)"),self.newSet) self.setlist.connect(self.setlist,QtCore.SIGNAL("keypress"),self.listKey) # Mouse Modes self.mmode="manual" self.boxmm=QtGui.QGroupBox("Mouse Mode",self) self.boxmm.setFlat(False) self.gbl.addWidget(self.boxmm,0,2,3,2) self.hbl0=QtGui.QHBoxLayout(self.boxmm) self.bmmanual=QtGui.QPushButton("Manual") self.bmmanual.setToolTip("Manual selection of particles. No impact on autoselection.") self.bmmanual.setAutoExclusive(True) self.bmmanual.setCheckable(True) self.bmmanual.setChecked(True) self.hbl0.addWidget(self.bmmanual) self.bmdel=QtGui.QPushButton("Delete") self.bmdel.setToolTip("Delete particles from any mode. Can also shift-click in other mouse modes.") self.bmdel.setAutoExclusive(True) self.bmdel.setCheckable(True) self.hbl0.addWidget(self.bmdel) self.bmgref=QtGui.QPushButton("Good Refs") self.bmgref.setToolTip("Identify some good particles. Available to all autoboxers.") self.bmgref.setAutoExclusive(True) self.bmgref.setCheckable(True) self.hbl0.addWidget(self.bmgref) self.bmbref=QtGui.QPushButton("Bad Refs") self.bmbref.setToolTip("Identify regions which should not be selected as particles.") self.bmbref.setAutoExclusive(True) self.bmbref.setCheckable(True) self.hbl0.addWidget(self.bmbref) QtCore.QObject.connect(self.bmmanual,QtCore.SIGNAL("clicked(bool)"),self.setMouseManual) QtCore.QObject.connect(self.bmdel,QtCore.SIGNAL("clicked(bool)"),self.setMouseDel) QtCore.QObject.connect(self.bmgref,QtCore.SIGNAL("clicked(bool)"),self.setMouseGoodRef) QtCore.QObject.connect(self.bmbref,QtCore.SIGNAL("clicked(bool)"),self.setMouseBadRef) # Global parameters self.boxparm=QtGui.QGroupBox("Parameters",self) self.boxparm.setFlat(False) self.gbl.addWidget(self.boxparm,3,2,3,3) self.gbl1=QtGui.QGridLayout(self.boxparm) self.gbl1.setMargin(8) self.gbl1.setSpacing(6) self.vbbsize = ValBox(label="Box Size:",value=box) self.gbl1.addWidget(self.vbbsize,0,0) self.vbbpsize = ValBox(label="Ptcl Size:",value=ptcl) self.gbl1.addWidget(self.vbbpsize,0,1) self.vbbapix = ValBox(label="A/pix:",value=apix) self.gbl1.addWidget(self.vbbapix,0,2) self.vbvoltage = ValBox(label="Voltage:",value=voltage) self.gbl1.addWidget(self.vbvoltage,1,0) self.vbbac = ValBox(label="% AC:",value=ac) self.gbl1.addWidget(self.vbbac,1,1) self.vbcs = ValBox(label="Cs:",value=cs) self.gbl1.addWidget(self.vbcs,1,2) # Autoboxing Tabs self.autolbl = QtGui.QLabel("Autoboxing Methods:") self.gbl.addWidget(self.autolbl,7,2) self.autotab = QtGui.QTabWidget() self.gbl.addWidget(self.autotab,8,2,6,3) self.bautobox = QtGui.QPushButton("Autobox") self.gbl.addWidget(self.bautobox,7,4) QtCore.QObject.connect(self.bautobox,QtCore.SIGNAL("clicked(bool)"),self.doAutoBox) # Individual tabs from Dictionary self.abwid=[] for name,bname,cls in GUIBoxer.aboxmodes: w=QtGui.QWidget() gl=QtGui.QGridLayout(w) self.abwid.append((w,gl)) cls.setup_gui(gl) self.autotab.addTab(w,name) self.setWindowTitle("e2boxer21 - Control Panel") self.wimage.show() # self.wfft.show() # self.wplot.show() E2loadappwin("e2boxer21","main",self) E2loadappwin("e2boxer21","image",self.wimage.qt_parent) E2loadappwin("e2boxer21","particles",self.wparticles.qt_parent) E2loadappwin("e2boxer21","refs",self.wrefs.qt_parent) E2loadappwin("e2boxer21","badrefs",self.wbadrefs.qt_parent) self.newSet(0)
class GUIBoxer(QtGui.QWidget): # Dictionary of autopickers # to add a new one, provide name:(Qt_setup_function,picker_execution_function) # Qt_setup_function(self,empty_grid_layout) # picker_execution_function(self,... aboxmodes = [ ("by Ref","auto_ref",boxerByRef), ("Gauss","auto_gauss",boxerGauss) ] boxcolors = { "selected":(0.9,0.9,0.9), "manual":(0,0,0), "refgood":(0,0.8,0), "refbad":(0.8,0,0), "unknown":[.4,.4,.1], "auto_ref":(.1,.1,.4), "auto_gauss":(.4,.1,.4) } def __init__(self,imagenames,voltage=None,apix=None,cs=None,ac=10.0,box=256,ptcl=200): """The 'new' e2boxer interface. """ QtGui.QWidget.__init__(self,None) # self.setWindowIcon(QtGui.QIcon(get_image_directory() + "ctf.png")) self.data=None self.curfilename = None # current selected file for boxing self.filenames=imagenames # list of available filenames self.micrograph=None self.boxes=None self.defaultvoltage=voltage self.defaultapix=apix self.defaultcs=cs self.defaultac=ac self.db = None # open JSON file for current image self.wimage=EMImage2DWidget() self.wimage.setWindowTitle("Micrograph") self.wparticles=EMImageMXWidget() self.wparticles.setWindowTitle("Particles") self.wrefs=EMImageMXWidget() self.wrefs.setWindowTitle("Box Refs") self.wbadrefs=EMImageMXWidget() self.wbadrefs.setWindowTitle("Bad Box Refs") #self.wfft=EMImage2DWidget() #self.wfft.setWindowTitle("e2evalimage - 2D FFT") #self.wplot=EMPlot2DWidget() #self.wplot.setWindowTitle("e2evalimage - Plot") self.wimage.connect(self.wimage,QtCore.SIGNAL("mousedown"),self.imgmousedown) self.wimage.connect(self.wimage,QtCore.SIGNAL("mousedrag"),self.imgmousedrag) self.wimage.connect(self.wimage,QtCore.SIGNAL("mouseup") ,self.imgmouseup) self.wparticles.connect(self.wparticles,QtCore.SIGNAL("mousedown"),self.ptclmousedown) self.wparticles.connect(self.wparticles,QtCore.SIGNAL("mousedrag"),self.ptclmousedrag) self.wparticles.connect(self.wparticles,QtCore.SIGNAL("mouseup") ,self.ptclmouseup) self.wrefs.connect(self.wparticles,QtCore.SIGNAL("mousedown"),self.refmousedown) self.wrefs.connect(self.wparticles,QtCore.SIGNAL("mousedrag"),self.refmousedrag) self.wrefs.connect(self.wparticles,QtCore.SIGNAL("mouseup") ,self.refmouseup) self.wimage.mmode="app" self.wparticles.mmode="app" # This object is itself a widget we need to set up self.gbl = QtGui.QGridLayout(self) self.gbl.setMargin(8) self.gbl.setSpacing(6) # Micrograph list self.setlist=QtGui.QListWidget(self) self.setlist.setSizePolicy(QtGui.QSizePolicy.Preferred,QtGui.QSizePolicy.Expanding) for i in imagenames: self.setlist.addItem(i) self.gbl.addWidget(self.setlist,0,0,12,2) self.setlist.connect(self.setlist,QtCore.SIGNAL("currentRowChanged(int)"),self.newSet) self.setlist.connect(self.setlist,QtCore.SIGNAL("keypress"),self.listKey) # Mouse Modes self.mmode="manual" self.boxmm=QtGui.QGroupBox("Mouse Mode",self) self.boxmm.setFlat(False) self.gbl.addWidget(self.boxmm,0,2,3,2) self.hbl0=QtGui.QHBoxLayout(self.boxmm) self.bmmanual=QtGui.QPushButton("Manual") self.bmmanual.setToolTip("Manual selection of particles. No impact on autoselection.") self.bmmanual.setAutoExclusive(True) self.bmmanual.setCheckable(True) self.bmmanual.setChecked(True) self.hbl0.addWidget(self.bmmanual) self.bmdel=QtGui.QPushButton("Delete") self.bmdel.setToolTip("Delete particles from any mode. Can also shift-click in other mouse modes.") self.bmdel.setAutoExclusive(True) self.bmdel.setCheckable(True) self.hbl0.addWidget(self.bmdel) self.bmgref=QtGui.QPushButton("Good Refs") self.bmgref.setToolTip("Identify some good particles. Available to all autoboxers.") self.bmgref.setAutoExclusive(True) self.bmgref.setCheckable(True) self.hbl0.addWidget(self.bmgref) self.bmbref=QtGui.QPushButton("Bad Refs") self.bmbref.setToolTip("Identify regions which should not be selected as particles.") self.bmbref.setAutoExclusive(True) self.bmbref.setCheckable(True) self.hbl0.addWidget(self.bmbref) QtCore.QObject.connect(self.bmmanual,QtCore.SIGNAL("clicked(bool)"),self.setMouseManual) QtCore.QObject.connect(self.bmdel,QtCore.SIGNAL("clicked(bool)"),self.setMouseDel) QtCore.QObject.connect(self.bmgref,QtCore.SIGNAL("clicked(bool)"),self.setMouseGoodRef) QtCore.QObject.connect(self.bmbref,QtCore.SIGNAL("clicked(bool)"),self.setMouseBadRef) # Global parameters self.boxparm=QtGui.QGroupBox("Parameters",self) self.boxparm.setFlat(False) self.gbl.addWidget(self.boxparm,3,2,3,3) self.gbl1=QtGui.QGridLayout(self.boxparm) self.gbl1.setMargin(8) self.gbl1.setSpacing(6) self.vbbsize = ValBox(label="Box Size:",value=box) self.gbl1.addWidget(self.vbbsize,0,0) self.vbbpsize = ValBox(label="Ptcl Size:",value=ptcl) self.gbl1.addWidget(self.vbbpsize,0,1) self.vbbapix = ValBox(label="A/pix:",value=apix) self.gbl1.addWidget(self.vbbapix,0,2) self.vbvoltage = ValBox(label="Voltage:",value=voltage) self.gbl1.addWidget(self.vbvoltage,1,0) self.vbbac = ValBox(label="% AC:",value=ac) self.gbl1.addWidget(self.vbbac,1,1) self.vbcs = ValBox(label="Cs:",value=cs) self.gbl1.addWidget(self.vbcs,1,2) # Autoboxing Tabs self.autolbl = QtGui.QLabel("Autoboxing Methods:") self.gbl.addWidget(self.autolbl,7,2) self.autotab = QtGui.QTabWidget() self.gbl.addWidget(self.autotab,8,2,6,3) self.bautobox = QtGui.QPushButton("Autobox") self.gbl.addWidget(self.bautobox,7,4) QtCore.QObject.connect(self.bautobox,QtCore.SIGNAL("clicked(bool)"),self.doAutoBox) # Individual tabs from Dictionary self.abwid=[] for name,bname,cls in GUIBoxer.aboxmodes: w=QtGui.QWidget() gl=QtGui.QGridLayout(w) self.abwid.append((w,gl)) cls.setup_gui(gl) self.autotab.addTab(w,name) self.setWindowTitle("e2boxer21 - Control Panel") self.wimage.show() # self.wfft.show() # self.wplot.show() E2loadappwin("e2boxer21","main",self) E2loadappwin("e2boxer21","image",self.wimage.qt_parent) E2loadappwin("e2boxer21","particles",self.wparticles.qt_parent) E2loadappwin("e2boxer21","refs",self.wrefs.qt_parent) E2loadappwin("e2boxer21","badrefs",self.wbadrefs.qt_parent) self.newSet(0) #QWidget *firstPageWidget = new QWidget; #QWidget *secondPageWidget = new QWidget; #QWidget *thirdPageWidget = new QWidget; #QStackedWidget *stackedWidget = new QStackedWidget; #stackedWidget->addWidget(firstPageWidget); #stackedWidget->addWidget(secondPageWidget); #stackedWidget->addWidget(thirdPageWidget); #QVBoxLayout *layout = new QVBoxLayout; #layout->addWidget(stackedWidget); #setLayout(layout); #QComboBox *pageComboBox = new QComboBox; #pageComboBox->addItem(tr("Page 1")); #pageComboBox->addItem(tr("Page 2")); #pageComboBox->addItem(tr("Page 3")); #connect(pageComboBox, SIGNAL(activated(int)),stackedWidget, SLOT(setCurrentIndex(int))); #self.lboxmode=QtGui.QLabel("Mode:",self) #self.gbl.addWidget(self.lboxmode,10,0) #self.sboxmode=QtGui.QComboBox(self) #self.sboxmode.addItem("Manual") #self.sboxmode.addItem("Reference") #self.sboxmode.setCurrentIndex(1) #self.gbl.addWidget(self.sboxmode,10,1) #self.lanmode=QtGui.QLabel("Annotate:",self) #self.gbl.addWidget(self.lanmode,12,0) #self.sanmode=QtGui.QComboBox(self) #self.sanmode.addItem("Box") #self.sanmode.addItem("Box+dot") #self.sanmode.addItem("Circle") #self.sanmode.addItem("None") #self.gbl.addWidget(self.sanmode,12,1) #self.sdefocus=ValSlider(self,(0,5),"Defocus:",0.0,90) #self.gbl.addWidget(self.sdefocus,0,2,1,3) #self.squality=ValSlider(self,(0,9),"Quality (0-9):",0,90) #self.squality.setIntonly(True) #self.gbl.addWidget(self.squality,6,2,1,3) #self.brefit=QtGui.QPushButton("Autobox") #self.gbl.addWidget(self.brefit,7,2) #self.bclrauto=QtGui.QPushButton("Clear Auto") #self.gbl.addWidget(self.bclrauto,7,3) #self.bclrall=QtGui.QPushButton("Clear All") #self.gbl.addWidget(self.bclrall,7,4) #self.sapix=ValBox(self,(0,500),"A/pix:",1.0,90) #if self.defaultapix!=None : self.sapix.setValue(self.defaultapix) #self.gbl.addWidget(self.sapix,10,2) #self.svoltage=ValBox(self,(0,500),"Voltage (kV):",200,90) #if self.defaultvoltage!=None : self.svoltage.setValue(self.defaultvoltage) #self.gbl.addWidget(self.svoltage,11,2) #self.scs=ValBox(self,(0,5),"Cs (mm):",4.1,90) #if self.defaultcs!=None : self.scs.setValue(self.defaultcs) #self.gbl.addWidget(self.scs,12,2) #self.sboxsize=ValBox(self,(0,500),"Box Size:",256,90) #self.sboxsize.intonly=True #self.gbl.addWidget(self.sboxsize,13,2) #self.sptclsize=ValBox(self,(0,500),"Ptcl Size:",256,90) #self.sptclsize.intonly=True #self.gbl.addWidget(self.sptclsize,14,2) #QtCore.QObject.connect(self.sdefocus, QtCore.SIGNAL("valueChanged"), self.newCTF) #QtCore.QObject.connect(self.sapix, QtCore.SIGNAL("valueChanged"), self.newCTF) #QtCore.QObject.connect(self.svoltage, QtCore.SIGNAL("valueChanged"), self.newCTF) #QtCore.QObject.connect(self.scs, QtCore.SIGNAL("valueChanged"), self.newCTF) #QtCore.QObject.connect(self.sboxsize, QtCore.SIGNAL("valueChanged"), self.newBox) ## QtCore.QObject.connect(self.soversamp, QtCore.SIGNAL("valueChanged"), self.newBox) #QtCore.QObject.connect(self.squality,QtCore.SIGNAL("valueChanged"),self.newQualityFactor) #QtCore.QObject.connect(self.setlist,QtCore.SIGNAL("currentRowChanged(int)"),self.newSet) #QtCore.QObject.connect(self.setlist,QtCore.SIGNAL("keypress"),self.listkey) #QtCore.QObject.connect(self.sboxmode,QtCore.SIGNAL("currentIndexChanged(int)"),self.newBoxMode) #self.resize(720,380) # figured these values out by printing the width and height in resize event #### This section is responsible for background updates #self.busy=False #self.needupdate=True #self.needredisp=False #self.procthread=None #self.errors=None # used to communicate errors back from the reprocessing thread #self.timer=QTimer() #QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.timeOut) #self.timer.start(100) # self.recalc() def setMouseManual(self,x): self.mmode="manual" def setMouseDel(self,x): self.mmode="del" def setMouseGoodRef(self,x): self.mmode="refgood" def setMouseBadRef(self,x): self.mmode="refbad" def imgmousedown(self,event) : m=self.wimage.scr_to_img((event.x(),event.y())) boxsize2=self.vbbsize.getValue()//2 ptclsize=self.vbbpsize.getValue() self.curbox=0 # check to see if click was inside an existing box, in which case we move it for i in self.boxes: if abs(m.x-i[0])<boxsize2 and abs(m.y-i[1])<boxsize2 : self.curbox=i break else : # Create a new box if self.mmode=="del" : return # This is for creating a new box, so clearly not desirable in delete mode self.curbox=len(self.boxes) self.boxes.append((m[0],m[1],self.mmode)) self.__addBox(self.curbox,self.boxes[-1]) #self.guiim.add_shape("cen",["rect",.9,.9,.4,x0,y0,x0+2,y0+2,1.0]) def imgmousedrag(self,event) : if self.calcmode==0: m=self.wimage.scr_to_img((event.x(),event.y())) parms=self.parms[self.curset] parms[2]=(m[0]-parms[0]/2,m[1]-parms[0]/2) self.needredisp=True self.recalc() # box deletion when shift held down #if event.modifiers()&Qt.ShiftModifier: #for i,j in enumerate(self.boxes): def imgmouseup(self,event) : m=self.wimage.scr_to_img((event.x(),event.y())) if self.calcmode==1: parms=self.parms[self.curset] nx=self.data["nx"]/parms[0]-1 grid=int((m[0]-parms[0]/2)/parms[0])+int((m[1]-parms[0]/2)/parms[0])*nx if grid in parms[3] : parms[3].remove(grid) else: parms[3].add(grid) self.needredisp=True self.recalc() def ptclmousedown(self,event) : return def ptclmousedrag(self,event) : return def ptclmouseup(self,event) : return def refmousedown(self,event) : return def refmousedrag(self,event) : return def refmouseup(self,event) : return def newSet(self,val): "called when a new data set is selected from the list" first=True newfilename=str(self.setlist.item(val).text()) if newfilename==self.curfilename : return # Write the current image parameters to the database if self.curfilename!=None and self.boxes!=None : self.save_boxes() first=False self.micrograph=load_micrograph(newfilename) self.wimage.set_data(self.micrograph) if first : E2loadappwin("e2boxer21","image",self.wimage.qt_parent) self.curfilename=newfilename self.restore_boxes() def save_boxes(self): js=js_open_dict(info_name(self.curfilename)) js["boxes"]=self.boxes def restore_boxes(self): # first we restore the list of box locations js=js_open_dict(info_name(self.curfilename)) try: self.boxes=js["boxes"] except: self.boxes=[] boxsize=self.vbbsize.getValue() ptclsize=self.vbbpsize.getValue() micro=self.wimage.get_data() self.wimage.del_shapes() if len(self.boxes)==0 : self.wparticles.set_data([]) return # Then we extract the actual boxed out particles goodrefs=[] badrefs=[] self.particles=[] for i,box in enumerate(self.boxes): self.__addBox(i,box) # extract the data boxim=self.micrograph.get_clip(Region(box[0]-boxsize//2,box[1]-boxsize//2,boxsize,boxsize)) boxim["ptcl_source_coord"]=(box[0],box[1]) if box[2]=="refgood": goodrefs.append(boxim) elif box[2]=="refbad": badrefs.append(boxim) else: self.particles.append(boxim) # finally redisplay as appropriate self.wimage.update() self.wparticles.set_data(self.particles) if len(self.particles)>0 : self.wparticles.show() if len(goodrefs)+len(badrefs)!=0: self.goodrefs=goodrefs self.badrefs=badrefs self.wrefs.set_data(self.goodrefs) self.wbadrefs.set_data(self.badrefs) if len(self.goodrefs)>0 : self.wrefs.show() if len(self.badrefs)>0 : self.wbadrefs.show() def __addBox(self,i,box): """takes the number of the box in self.boxes and the (x,y,mode) tuple and displays it""" # Display the actual box boxsize=self.vbbsize.getValue() ptclsize=self.vbbpsize.getValue() try: color=self.boxcolors[box[2]] except: color=self.boxcolors["unknown"] self.wimage.add_shape("box{}".format(i),EMShape(("rect",color[0],color[1],color[2],box[0]-boxsize//2,box[1]-boxsize//2,box[0]+boxsize//2,box[1]+boxsize//2,2))) self.wimage.add_shape("cir{}".format(i),EMShape(("circle",color[0],color[1],color[2],box[0],box[1],ptclsize/2,1.5))) def listKey(self,event): pass #if event.key()>=Qt.Key_0 and event.key()<=Qt.Key_9 : #q=int(event.key())-Qt.Key_0 #self.squality.setValue(q) #elif event.key() == Qt.Key_Left: #self.sdefocus.setValue(self.sdefocus.getValue()-0.03) #elif event.key() == Qt.Key_Right: #self.sdefocus.setValue(self.sdefocus.getValue()+0.03) #elif event.key()==Qt.Key_I : #self.doImport() #elif event.key()==Qt.Key_U : #self.unImport() def doAutoBox(self,b): """Autobox button pressed, find the right algorithm and call it""" name,bname,fn1=self.aboxmodes[self.autotab.currentIndex()] print name," called" def closeEvent(self,event): # QtGui.QWidget.closeEvent(self,event) E2saveappwin("e2boxer21","main",self) E2saveappwin("e2boxer21","image",self.wimage.qt_parent) E2saveappwin("e2boxer21","particles",self.wparticles.qt_parent) E2saveappwin("e2boxer21","refs",self.wrefs.qt_parent) E2saveappwin("e2boxer21","badrefs",self.wbadrefs.qt_parent) #self.writeCurParm() event.accept() QtGui.qApp.exit(0)
def __init__(self, images, voltage=None, apix=None, cs=None, ac=10.0, box=512): """The 'new' e2boxer interface. """ try: from emimage2d import EMImage2DWidget except: print "Cannot import EMAN image GUI objects (EMImage2DWidget)" sys.exit(1) try: from emimagemx import EMImageMXWidget except: print "Cannot import EMAN image GUI objects (EMImageMXWidget)" sys.exit(1) try: from emplot2d import EMPlot2DWidget except: print "Cannot import EMAN plot GUI objects (is matplotlib installed?)" sys.exit(1) QtGui.QWidget.__init__(self, None) self.setWindowIcon(QtGui.QIcon(get_image_directory() + "ctf.png")) self.data = None self.curfilename = None self.defaultvoltage = voltage self.defaultapix = apix self.defaultcs = cs self.defaultac = ac self.wimage = EMImage2DWidget() self.wimage.setWindowTitle("Micrograph") self.wparticles = EMImageMXWidget() self.wparticles.setWindowTitle("Particles") #self.wfft=EMImage2DWidget() #self.wfft.setWindowTitle("e2evalimage - 2D FFT") #self.wplot=EMPlot2DWidget() #self.wplot.setWindowTitle("e2evalimage - Plot") self.wimage.connect(QtCore.SIGNAL("mousedown"), self.imgmousedown) self.wimage.connect(QtCore.SIGNAL("mousedrag"), self.imgmousedrag) self.wimage.connect(QtCore.SIGNAL("mouseup"), self.imgmouseup) self.wparticles.connect(QtCore.SIGNAL("mousedown"), self.ptclmousedown) self.wparticles.connect(QtCore.SIGNAL("mousedrag"), self.ptclmousedrag) self.wparticles.connect(QtCore.SIGNAL("mouseup"), self.ptclmouseup) self.wimage.mmode = "app" self.wparticles.mmode = "app" # This object is itself a widget we need to set up self.gbl = QtGui.QGridLayout(self) self.gbl.setMargin(8) self.gbl.setSpacing(6) # plot list and plot mode combobox self.setlist = e2ctf.MyListWidget(self) self.setlist.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Expanding) for i in images: self.setlist.addItem(i) self.gbl.addWidget(self.setlist, 0, 0, 10, 2) self.lboxmode = QtGui.QLabel("Mode:", self) self.gbl.addWidget(self.lboxmode, 10, 0) self.sboxmode = QtGui.QComboBox(self) self.sboxmode.addItem("Manual") self.sboxmode.addItem("Reference") self.sboxmode.setCurrentIndex(1) self.gbl.addWidget(self.sboxmode, 10, 1) self.lanmode = QtGui.QLabel("Annotate:", self) self.gbl.addWidget(self.lanmode, 12, 0) self.sanmode = QtGui.QComboBox(self) self.sanmode.addItem("Box") self.sanmode.addItem("Box+dot") self.sanmode.addItem("Circle") self.sanmode.addItem("None") self.gbl.addWidget(self.sanmode, 12, 1) self.sdefocus = ValSlider(self, (0, 5), "Defocus:", 0.0, 90) self.gbl.addWidget(self.sdefocus, 0, 2, 1, 3) self.squality = ValSlider(self, (0, 9), "Quality (0-9):", 0, 90) self.squality.setIntonly(True) self.gbl.addWidget(self.squality, 6, 2, 1, 3) self.brefit = QtGui.QPushButton("Autobox") self.gbl.addWidget(self.brefit, 7, 2) self.bclrauto = QtGui.QPushButton("Clear Auto") self.gbl.addWidget(self.bclrauto, 7, 3) self.bclrall = QtGui.QPushButton("Clear All") self.gbl.addWidget(self.bclrall, 7, 4) self.sapix = ValBox(self, (0, 500), "A/pix:", 1.0, 90) if self.defaultapix != None: self.sapix.setValue(self.defaultapix) self.gbl.addWidget(self.sapix, 10, 2) self.svoltage = ValBox(self, (0, 500), "Voltage (kV):", 200, 90) if self.defaultvoltage != None: self.svoltage.setValue(self.defaultvoltage) self.gbl.addWidget(self.svoltage, 11, 2) self.scs = ValBox(self, (0, 5), "Cs (mm):", 4.1, 90) if self.defaultcs != None: self.scs.setValue(self.defaultcs) self.gbl.addWidget(self.scs, 12, 2) self.sboxsize = ValBox(self, (0, 500), "Box Size:", 256, 90) self.sboxsize.intonly = True self.gbl.addWidget(self.sboxsize, 13, 2) self.sptclsize = ValBox(self, (0, 500), "Ptcl Size:", 256, 90) self.sptclsize.intonly = True self.gbl.addWidget(self.sptclsize, 14, 2) QtCore.QObject.connect(self.sdefocus, QtCore.SIGNAL("valueChanged"), self.newCTF) QtCore.QObject.connect(self.sapix, QtCore.SIGNAL("valueChanged"), self.newCTF) QtCore.QObject.connect(self.svoltage, QtCore.SIGNAL("valueChanged"), self.newCTF) QtCore.QObject.connect(self.scs, QtCore.SIGNAL("valueChanged"), self.newCTF) QtCore.QObject.connect(self.sboxsize, QtCore.SIGNAL("valueChanged"), self.newBox) # QtCore.QObject.connect(self.soversamp, QtCore.SIGNAL("valueChanged"), self.newBox) QtCore.QObject.connect(self.squality, QtCore.SIGNAL("valueChanged"), self.newQualityFactor) QtCore.QObject.connect(self.setlist, QtCore.SIGNAL("currentRowChanged(int)"), self.newSet) QtCore.QObject.connect(self.setlist, QtCore.SIGNAL("keypress"), self.listkey) QtCore.QObject.connect(self.sboxmode, QtCore.SIGNAL("currentIndexChanged(int)"), self.newBoxMode) self.resize( 720, 380 ) # figured these values out by printing the width and height in resize event ### This section is responsible for background updates self.busy = False self.needupdate = True self.needredisp = False self.procthread = None self.errors = None # used to communicate errors back from the reprocessing thread self.timer = QTimer() QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.timeOut) self.timer.start(100) self.setWindowTitle("e2boxer21 - Control Panel") self.wimage.show() self.wfft.show() self.wplot.show() E2loadappwin("e2boxer21", "main", self) E2loadappwin("e2boxer21", "image", self.wimage.qt_parent) E2loadappwin("e2boxer21", "particles", self.wparticles.qt_parent)
class GUIBoxer(QtGui.QWidget): def __init__(self, images, voltage=None, apix=None, cs=None, ac=10.0, box=512): """The 'new' e2boxer interface. """ try: from emimage2d import EMImage2DWidget except: print "Cannot import EMAN image GUI objects (EMImage2DWidget)" sys.exit(1) try: from emimagemx import EMImageMXWidget except: print "Cannot import EMAN image GUI objects (EMImageMXWidget)" sys.exit(1) try: from emplot2d import EMPlot2DWidget except: print "Cannot import EMAN plot GUI objects (is matplotlib installed?)" sys.exit(1) QtGui.QWidget.__init__(self, None) self.setWindowIcon(QtGui.QIcon(get_image_directory() + "ctf.png")) self.data = None self.curfilename = None self.defaultvoltage = voltage self.defaultapix = apix self.defaultcs = cs self.defaultac = ac self.wimage = EMImage2DWidget() self.wimage.setWindowTitle("Micrograph") self.wparticles = EMImageMXWidget() self.wparticles.setWindowTitle("Particles") #self.wfft=EMImage2DWidget() #self.wfft.setWindowTitle("e2evalimage - 2D FFT") #self.wplot=EMPlot2DWidget() #self.wplot.setWindowTitle("e2evalimage - Plot") self.wimage.connect(QtCore.SIGNAL("mousedown"), self.imgmousedown) self.wimage.connect(QtCore.SIGNAL("mousedrag"), self.imgmousedrag) self.wimage.connect(QtCore.SIGNAL("mouseup"), self.imgmouseup) self.wparticles.connect(QtCore.SIGNAL("mousedown"), self.ptclmousedown) self.wparticles.connect(QtCore.SIGNAL("mousedrag"), self.ptclmousedrag) self.wparticles.connect(QtCore.SIGNAL("mouseup"), self.ptclmouseup) self.wimage.mmode = "app" self.wparticles.mmode = "app" # This object is itself a widget we need to set up self.gbl = QtGui.QGridLayout(self) self.gbl.setMargin(8) self.gbl.setSpacing(6) # plot list and plot mode combobox self.setlist = e2ctf.MyListWidget(self) self.setlist.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Expanding) for i in images: self.setlist.addItem(i) self.gbl.addWidget(self.setlist, 0, 0, 10, 2) self.lboxmode = QtGui.QLabel("Mode:", self) self.gbl.addWidget(self.lboxmode, 10, 0) self.sboxmode = QtGui.QComboBox(self) self.sboxmode.addItem("Manual") self.sboxmode.addItem("Reference") self.sboxmode.setCurrentIndex(1) self.gbl.addWidget(self.sboxmode, 10, 1) self.lanmode = QtGui.QLabel("Annotate:", self) self.gbl.addWidget(self.lanmode, 12, 0) self.sanmode = QtGui.QComboBox(self) self.sanmode.addItem("Box") self.sanmode.addItem("Box+dot") self.sanmode.addItem("Circle") self.sanmode.addItem("None") self.gbl.addWidget(self.sanmode, 12, 1) self.sdefocus = ValSlider(self, (0, 5), "Defocus:", 0.0, 90) self.gbl.addWidget(self.sdefocus, 0, 2, 1, 3) self.squality = ValSlider(self, (0, 9), "Quality (0-9):", 0, 90) self.squality.setIntonly(True) self.gbl.addWidget(self.squality, 6, 2, 1, 3) self.brefit = QtGui.QPushButton("Autobox") self.gbl.addWidget(self.brefit, 7, 2) self.bclrauto = QtGui.QPushButton("Clear Auto") self.gbl.addWidget(self.bclrauto, 7, 3) self.bclrall = QtGui.QPushButton("Clear All") self.gbl.addWidget(self.bclrall, 7, 4) self.sapix = ValBox(self, (0, 500), "A/pix:", 1.0, 90) if self.defaultapix != None: self.sapix.setValue(self.defaultapix) self.gbl.addWidget(self.sapix, 10, 2) self.svoltage = ValBox(self, (0, 500), "Voltage (kV):", 200, 90) if self.defaultvoltage != None: self.svoltage.setValue(self.defaultvoltage) self.gbl.addWidget(self.svoltage, 11, 2) self.scs = ValBox(self, (0, 5), "Cs (mm):", 4.1, 90) if self.defaultcs != None: self.scs.setValue(self.defaultcs) self.gbl.addWidget(self.scs, 12, 2) self.sboxsize = ValBox(self, (0, 500), "Box Size:", 256, 90) self.sboxsize.intonly = True self.gbl.addWidget(self.sboxsize, 13, 2) self.sptclsize = ValBox(self, (0, 500), "Ptcl Size:", 256, 90) self.sptclsize.intonly = True self.gbl.addWidget(self.sptclsize, 14, 2) QtCore.QObject.connect(self.sdefocus, QtCore.SIGNAL("valueChanged"), self.newCTF) QtCore.QObject.connect(self.sapix, QtCore.SIGNAL("valueChanged"), self.newCTF) QtCore.QObject.connect(self.svoltage, QtCore.SIGNAL("valueChanged"), self.newCTF) QtCore.QObject.connect(self.scs, QtCore.SIGNAL("valueChanged"), self.newCTF) QtCore.QObject.connect(self.sboxsize, QtCore.SIGNAL("valueChanged"), self.newBox) # QtCore.QObject.connect(self.soversamp, QtCore.SIGNAL("valueChanged"), self.newBox) QtCore.QObject.connect(self.squality, QtCore.SIGNAL("valueChanged"), self.newQualityFactor) QtCore.QObject.connect(self.setlist, QtCore.SIGNAL("currentRowChanged(int)"), self.newSet) QtCore.QObject.connect(self.setlist, QtCore.SIGNAL("keypress"), self.listkey) QtCore.QObject.connect(self.sboxmode, QtCore.SIGNAL("currentIndexChanged(int)"), self.newBoxMode) self.resize( 720, 380 ) # figured these values out by printing the width and height in resize event ### This section is responsible for background updates self.busy = False self.needupdate = True self.needredisp = False self.procthread = None self.errors = None # used to communicate errors back from the reprocessing thread self.timer = QTimer() QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.timeOut) self.timer.start(100) self.setWindowTitle("e2boxer21 - Control Panel") self.wimage.show() self.wfft.show() self.wplot.show() E2loadappwin("e2boxer21", "main", self) E2loadappwin("e2boxer21", "image", self.wimage.qt_parent) E2loadappwin("e2boxer21", "particles", self.wparticles.qt_parent) # self.recalc() def listkey(self, event): if event.key() >= Qt.Key_0 and event.key() <= Qt.Key_9: q = int(event.key()) - Qt.Key_0 self.squality.setValue(q) #elif event.key() == Qt.Key_Left: #self.sdefocus.setValue(self.sdefocus.getValue()-0.03) #elif event.key() == Qt.Key_Right: #self.sdefocus.setValue(self.sdefocus.getValue()+0.03) #elif event.key()==Qt.Key_I : #self.doImport() #elif event.key()==Qt.Key_U : #self.unImport() def closeEvent(self, event): # QtGui.QWidget.closeEvent(self,event) E2saveappwin("e2evalimage", "main", self) E2saveappwin("e2evalimage", "image", self.wimage.qt_parent) E2saveappwin("e2evalimage", "particles", self.wparticles.qt_parent) #self.writeCurParm() event.accept() QtGui.qApp.exit(0) #app=QtGui.qApp #if self.wimage != None: #app.close_specific(self.wimage) #self.wimage = None #if self.wfft != None: #app.close_specific(self.wfft) #if self.wplot != None: #app.close_specific(self.wplot) #app.close_specific(self) # self.emit(QtCore.SIGNAL("module_closed")) # this signal is important when e2ctf is being used by a program running its own event loop def update_plot(self): # if self.wplot == None: return # it's closed/not visible if self.incalc: return # no plot updates during a recomputation parms = self.parms[self.curset] apix = self.sapix.getValue() ds = 1.0 / (apix * parms[0] * parms[5]) ctf = parms[1] bg1d = array(ctf.background) r = len(ctf.background) s = arange(0, ds * r, ds) # This updates the FFT CTF-zero circles if self.f2danmode == 0: fit = ctf.compute_1d(len(s) * 2, ds, Ctf.CtfType.CTF_AMP) shp = {} nz = 0 for i in range(1, len(fit)): if fit[i - 1] * fit[i] <= 0.0: nz += 1 shp["z%d" % i] = EMShape( ("circle", 0.0, 0.0, 1.0 / nz, r, r, i, 1.0)) self.wfft.del_shapes() self.wfft.add_shapes(shp) self.wfft.updateGL() # Single measurement circle mode elif self.f2danmode == 1: self.wfft.del_shapes() if self.ringrad == 0: self.ringrad = 1.0 self.wfft.add_shape( "ring", EMShape(("circle", 0.2, 1.0, 0.2, r, r, self.ringrad, 1.0))) self.wfft.add_shape( "ringlbl", EMShape(("scrlabel", 0.2, 1.0, 0.2, 10, 10, "r=%d pix -> 1/%1.2f 1/A (%1.4f)" % (self.ringrad, 1.0 / (self.ringrad * ds), self.ringrad * ds), 24.0, 2.0))) self.wfft.updateGL() # 2-D Crystal mode elif self.f2danmode == 2: shp = {} for a in range(-5, 6): for b in range(-5, 6): shp["m%d%d" % (a, b)] = EMShape( ("circle", 1.0, 0.0, 0.0, a * self.xpos1[0] + b * self.xpos2[0] + self.fft["nx"] / 2 - 1, a * self.xpos1[1] + b * self.xpos2[1] + self.fft["ny"] / 2, 3, 1.0)) self.wfft.del_shapes() self.wfft.add_shapes(shp) self.wfft.add_shape( "xtllbl", EMShape(("scrlabel", 1.0, 0.3, 0.3, 10, 10, "Unit Cell: %1.2f,%1.2f" % (1.0 / (hypot(*self.xpos1) * ds), 1.0 / (hypot(*self.xpos2) * ds)), 60.0, 2.0))) # except: pass self.wfft.updateGL() else: self.wfft.del_shapes() self.wfft.updateGL() # Now update the plots for the correct plot mode if self.plotmode == 0: try: bgsub = self.fft1d - bg1d except: print "Error computing bgsub on this image" return self.wplot.set_data((s, bgsub), "fg-bg", quiet=True, color=0) fit = array(ctf.compute_1d(len(s) * 2, ds, Ctf.CtfType.CTF_AMP)) # The fit curve fit = fit * fit # squared # auto-amplitude for b-factor adjustment rto, nrto = 0, 0 for i in range(int(.04 / ds) + 1, min(int(0.15 / ds), len(s) - 1)): if bgsub[i] > 0: rto += fit[i] nrto += fabs(bgsub[i]) if nrto == 0: rto = 1.0 else: rto /= nrto fit = [fit[i] / rto for i in range(len(s))] # print ctf_cmp((self.sdefocus.value,self.sbfactor.value,rto),(ctf,bgsub,int(.04/ds)+1,min(int(0.15/ds),len(s)-1),ds,self.sdefocus.value)) self.wplot.set_data((s, fit), "fit", color=1) self.wplot.setAxisParms("s (1/" + "$\AA$" + ")", "Intensity (a.u)") elif self.plotmode == 1: self.wplot.set_data((s[1:], self.fft1d[1:]), "fg", quiet=True, color=1) self.wplot.set_data((s[1:], bg1d[1:]), "bg", color=0) self.wplot.setAxisParms("s (1/" + "$\AA$" + ")", "Intensity (a.u)") elif self.plotmode == 2: if self.fft1dang == None: self.recalc_real() bgsub = self.fft1d - bg1d bgsuba = [array(self.fft1dang[i]) - bg1d for i in xrange(4)] # Write the current image parameters to the database # for i in xrange(4): bgsuba[i][0]=0 self.wplot.set_data((s, bgsub), "fg", quiet=True, color=0) self.wplot.set_data((s[3:], bgsuba[0][3:]), "fg 0-45", quiet=True, color=2) self.wplot.set_data((s[3:], bgsuba[1][3:]), "fg 45-90", quiet=True, color=3) self.wplot.set_data((s[3:], bgsuba[2][3:]), "fg 90-135", quiet=True, color=4) self.wplot.set_data((s[3:], bgsuba[3][3:]), "fg 135-180", quiet=True, color=6) fit = array(ctf.compute_1d(len(s) * 2, ds, Ctf.CtfType.CTF_AMP)) # The fit curve fit = fit * fit # squared # auto-amplitude for b-factor adjustment rto, nrto = 0, 0 for i in range(int(.04 / ds) + 1, min(int(0.15 / ds), len(s) - 1)): if bgsub[i] > 0: rto += fit[i] nrto += fabs(bgsub[i]) if nrto == 0: rto = 1.0 else: rto /= nrto fit /= rto self.wplot.set_data((s, fit), "fit", color=1) self.wplot.setAxisParms("s (1/" + "$\AA$" + ")", "Intensity (a.u)") elif self.plotmode == 3: if self.fft1dang == None: self.recalc_real() #bgsub=self.fft1d-bg1d #bgsuba=[array(self.fft1dang[i])-bg1d for i in xrange(4)] fg = self.fft1d fga = [array(self.fft1dang[i]) for i in xrange(4)] for i in xrange(4): fga[i][0] = 0 self.wplot.set_data((s, fg), "fg", quiet=True, color=0) self.wplot.set_data((s, fga[0]), "fg 0-45", quiet=True, color=2) self.wplot.set_data((s, fga[1]), "fg 45-90", quiet=True, color=3) self.wplot.set_data((s, fga[2]), "fg 90-135", quiet=True, color=4) self.wplot.set_data((s, fga[3]), "fg 135-180", quiet=True, color=6) #fit=array(ctf.compute_1d(len(s)*2,ds,Ctf.CtfType.CTF_AMP)) # The fit curve #fit=fit*fit # squared ## auto-amplitude for b-factor adjustment #rto,nrto=0,0 #for i in range(int(.04/ds)+1,min(int(0.15/ds),len(s)-1)): #if bgsub[i]>0 : #rto+=fit[i] #nrto+=fabs(bgsub[i]) #if nrto==0 : rto=1.0 #else : rto/=nrto #fit/=rto #self.wplot.set_data((s,fit),"fit",color=1) #self.wplot.setAxisParms("s (1/"+ "$\AA$" + ")","Intensity (a.u)") if self.plotmode == 4: if min(bg1d) <= 0.0: bg1d += min(bg1d) + max(bg1d) / 10000.0 ssnr = (self.fft1d - bg1d) / bg1d self.wplot.set_data((s, ssnr), "SSNR", quiet=True, color=0) #fit=array(ctf.compute_1d(len(s)*2,ds,Ctf.CtfType.CTF_AMP)) # The fit curve #fit=fit*fit # squared ## auto-amplitude for b-factor adjustment #rto,nrto=0,0 #for i in range(int(.04/ds)+1,min(int(0.15/ds),len(s)-1)): #if bgsub[i]>0 : #rto+=fit[i] #nrto+=fabs(bgsub[i]) #if nrto==0 : rto=1.0 #else : rto/=nrto #fit=[fit[i]/rto for i in range(len(s))] ## print ctf_cmp((self.sdefocus.value,self.sbfactor.value,rto),(ctf,bgsub,int(.04/ds)+1,min(int(0.15/ds),len(s)-1),ds,self.sdefocus.value)) #self.wplot.set_data((s,fit),"fit",color=1) self.wplot.setAxisParms("s (1/" + "$\AA$" + ")", "Est. SSNR") def timeOut(self): if self.busy: return # Redisplay before spawning thread for more interactive display if self.needredisp: try: self.redisplay() except: pass # Spawn a thread to reprocess the data if self.needupdate and self.procthread == None: self.procthread = threading.Thread(target=self.recalc_real) self.procthread.start() if self.errors: QtGui.QMessageBox.warning( None, "Error", "The following processors encountered errors during processing of 1 or more images:" + "\n".join(self.errors)) self.errors = None def doRefit(self): parms = self.parms[self.curset] apix = self.sapix.getValue() ds = 1.0 / (apix * parms[0] * parms[5]) try: parms[1] = e2ctf.ctf_fit(self.fft1d, parms[1].background, parms[1].background, self.fft, self.fftbg, parms[1].voltage, parms[1].cs, parms[1].ampcont, apix, bgadj=False, autohp=True, verbose=1) except: print "CTF Autofit Failed" traceback.print_exc() parms[1].defocus = 1.0 self.sdefocus.setValue(parms[1].defocus, True) self.sbfactor.setValue(parms[1].bfactor, True) self.sampcont.setValue(parms[1].ampcont, True) self.update_plot() def unImport(self, val=None): print "unimport ", base_name(self.setlist.item(self.curset).text()) item = base_name(self.setlist.item(self.curset).text()) try: os.unlink("micrographs/%s.hdf" % item) except: print "Couldn't delete micrographs/%s.hdf" % item def doImport(self, val=None): """Imports the currently selected image into a project""" print "import ", base_name(self.setlist.item(self.curset).text()) # This is just the (presumably) unique portion of the filename item = base_name(self.setlist.item(self.curset).text()) # create directory if necessary if not os.access("micrographs", os.R_OK): try: os.mkdir("micrographs") except: QtGui.QMessageBox.warning( self, "Error !", "Cannot create micrographs directory") return #db=db_open_dict("bdb:micrographs#%s"%item) self.data["ctf"] = self.parms[self.curset][1] if self.cinvert.getValue() != 0: self.data.mult(-1) if self.cxray.getValue(): self.data.process_inplace("threshold.clampminmax.nsigma", { "nsigma": 4, "tomean": 1 }) self.data.write_image("micrographs/%s.hdf" % item) self.writeCurParm() # js_open_dict(info_name(item))["ctf"]=[self.parms[val][1],None,None,None,None] # db_parms=db_open_dict("bdb:e2ctf.parms") # db_parms[item]=[self.parms[val][1].to_string(),self.fft1d,self.parms[val][1].background,self.parms[val][4]] def writeCurParm(self): "Called to store the current parameters for this image to the frameparms database" parms = self.parms[self.curset] js = js_open_dict(info_name(self.curfilename)) js.setval("ctf_frame", parms, True) js.setval("quality", parms[4]) # db_fparms=db_open_dict("bdb:e2ctf.frameparms") # curtag=item_name(str(self.setlist.item(self.curset).text())) # db_fparms[curtag]=self.parms[self.curset] def newSet(self, val): "called when a new data set is selected from the list" # Write the current image parameters to the database if val != self.curset: self.writeCurParm() # now set the new item self.curset = val # This deals with Z stacks and multi image files fsp = str(self.setlist.item(val).text()) if "," in fsp: fsp, n = fsp.split(",") self.data = EMData(fsp, int(n)) # read the image from disk elif ";" in fsp: fsp, n = fsp.split(";") hdr = EMData(fsp, 0, True) self.data = EMData(fsp, 0, False, Region(0, 0, int(n), hdr["nx"], hdr["ny"], 1)) # read the image from disk else: self.data = EMData(fsp, 0) # read the image from disk self.wimage.setWindowTitle("e2evalimage - " + fsp.split("/")[-1]) self.wfft.setWindowTitle("e2evalimage - 2D FFT - " + fsp.split("/")[-1]) self.wplot.setWindowTitle("e2evalimage - Plot - " + fsp.split("/")[-1]) if self.defaultapix != None: self.data["apix_x"] = self.defaultapix self.wimage.set_data(self.data) self.curfilename = str(self.setlist.item(val).text()) ctf = self.parms[val][1] # if voltage is 0, we need to initialize if ctf.voltage == 0: try: ctf.voltage = self.data["microscope_voltage"] except: pass if ctf.voltage == 0: ctf.voltage = self.defaultvoltage try: ctf.cs = self.data["microscope_cs"] except: pass if ctf.cs == 0: ctf.cs = self.defaultcs ctf.apix = self.data["apix_x"] ctf.defocus = 0.0 #triggers fitting ctf.bfactor = 200.0 ctf.ampcont = self.defaultac self.sdefocus.setValue(ctf.defocus, True) self.sbfactor.setValue(ctf.bfactor, True) self.sapix.setValue(ctf.apix, True) self.sampcont.setValue(ctf.ampcont, True) self.svoltage.setValue(ctf.voltage, True) self.scs.setValue(ctf.cs, True) self.sboxsize.setValue(self.parms[val][0], True) self.squality.setValue(self.parms[val][4], True) #if self.guiim != None: ## print self.data #self.guiim.set_data(self.data[val][4]) #if self.guiiminit: #self.guiim.optimally_resize() #self.guiiminit = False #self.guiim.updateGL() self.recalc() def recalc(self): self.needupdate = True def recalc_real(self): "Called to recompute the power spectra, also updates plot" self.needupdate = False if self.data == None: self.procthread = None return self.incalc = True # to avoid incorrect plot updates # To simplify expressions parms = self.parms[self.curset] apix = self.sapix.getValue() if len(parms) == 5: parms.append( 1 ) # for old projects where there was no oversampling specification else: parms[5] = max(1, int(parms[5])) ds = 1.0 / (apix * parms[0] * parms[5]) # Mode where user drags the box around the parent image if self.calcmode == 0: # extract the data and do an fft clip = self.data.get_clip( Region(parms[2][0], parms[2][1], parms[0], parms[0])) clip.process_inplace("normalize.edgemean") if parms[5] > 1: clip = clip.get_clip( Region(0, 0, parms[0] * parms[5], parms[0] * parms[5]) ) # since we aren't using phases, doesn't matter if we center it or not self.fft = clip.do_fft() # self.fft.mult(1.0/parms[0]**2) self.fft.mult(1.0 / parms[0]) # mode where user selects/deselcts tiled image set elif self.calcmode == 1: # update the box display on the image nx = self.data["nx"] / parms[0] - 1 self.fft = None nbx = 0 for x in range(nx): for y in range(self.data["ny"] / parms[0] - 1): # User deselected this one if int(x + y * nx) in parms[3]: continue # read the data and make the FFT clip = self.data.get_clip( Region(x * parms[0] + parms[0] / 2, y * parms[0] + parms[0] / 2, parms[0], parms[0])) clip.process_inplace("normalize.edgemean") if parms[5] > 1: clip = clip.get_clip( Region(0, 0, parms[0] * parms[5], parms[0] * parms[5]) ) # since we aren't using phases, doesn't matter if we center it or not fft = clip.do_fft() # fft.mult(parms[0]) fft.ri2inten() if self.fft == None: self.fft = fft else: self.fft += fft nbx += 1 self.fft.mult(1.0 / (nbx * parms[0]**2)) self.fft.process_inplace("math.sqrt") self.fft[ "is_intensity"] = 0 # These 2 steps are done so the 2-D display of the FFT looks better. Things would still work properly in 1-D without it # self.fft.mult(1.0/(nbx*parms[0]**2)) self.fftbg = self.fft.process("math.nonconvex") self.fft1d = self.fft.calc_radial_dist( self.fft.get_ysize() / 2, 0.0, 1.0, 1) # note that this handles the ri2inten averages properly if self.plotmode == 2 or self.plotmode == 3: self.fft1dang = array( self.fft.calc_radial_dist(self.fft.get_ysize() / 2, 0.0, 1.0, 4, self.sang45.getValue() * .017453292, 1) ) # This form generates 4 sequential power spectra representing angular ranges self.fft1dang = self.fft1dang.reshape( (4, self.fft.get_ysize() / 2)) else: self.fft1dang = None # Compute 1-D curve and background bg_1d = e2ctf.low_bg_curve(self.fft1d, ds) parms[1].background = bg_1d parms[1].dsbg = ds self.fft1d = array(self.fft1d) self.needredisp = True self.incalc = False time.sleep(.2) # help make sure update has a chance self.procthread = None # dbquality = self.db[os.path.basename(self.curfilename)] # print dbquality # item=item_name(self.curfilename) # db=db_open_dict("bdb:e2ctf.parms") # if db[item]==None or db[item[3]]==None : db[item]=[parms[1].to_string(),self.fft1d,parms[1].background,5] # # print item,db[item][3] # try: self.squality.setValue(int(db[item[3]])) # except: self.squality.setValue(5) def redisplay(self): if self.incalc: return self.needredisp = False self.busy = True parms = self.parms[self.curset] apix = self.sapix.getValue() ds = 1.0 / (apix * parms[0] * parms[5]) # Fitting not done yet. Need to make 2D background somehow if parms[1].defocus == 0: self.doRefit() self.wimage.show() self.wfft.show() self.wplot.show() self.update_plot() # To simplify expressions if self.calcmode == 0: # update the box display on the image self.wimage.del_shapes() self.wimage.add_shape( "box", EMShape(("rect", .3, .9, .3, parms[2][0], parms[2][1], parms[2][0] + parms[0], parms[2][1] + parms[0], 1))) self.wimage.updateGL() elif self.calcmode == 1: # update the box display on the image nx = self.data["nx"] / parms[0] - 1 shp = {} for x in range(nx): for y in range(self.data["ny"] / parms[0] - 1): # User deselected this one if int(x + y * nx) in parms[3]: continue # Make a shape for this box shp["box%02d%02d" % (x, y)] = EMShape( ("rect", .3, .9, .3, (x + .5) * parms[0], (y + .5) * parms[0], (x + 1.5) * parms[0], (y + 1.5) * parms[0], 1)) self.wimage.del_shapes() self.wimage.add_shapes(shp) self.wimage.updateGL() if self.f2dmode > 0: if self.f2dmode == 1: self.wfft.set_data(self.fft - self.fftbg) else: self.wfft.set_data(self.fftbg) else: self.wfft.set_data(self.fft) self.busy = False def newCalcMode(self, mode): self.calcmode = mode self.recalc() def new2DMode(self, mode): self.f2dmode = mode self.recalc() def new2DAnMode(self, mode): self.f2danmode = mode self.needredisp = True def newPlotMode(self, mode): self.plotmode = mode self.wplot.set_data( None, replace=True, quiet=True ) # clear the data so plots are properly redisplayed, but don't update the display self.needredisp = True def newBox(self): parms = self.parms[self.curset] parms[0] = self.sboxsize.value # parms[5]=self.soversamp.value parms[5] = 1 parms[3] = set() self.recalc() def newQualityFactor(self): parms = self.parms[self.curset] parms[4] = self.squality.value def newCTF(self): parms = self.parms[self.curset] parms[1].defocus = self.sdefocus.value parms[1].bfactor = self.sbfactor.value parms[1].dfdiff = self.sdfdiff.value parms[1].dfang = self.sdfang.value parms[1].apix = self.sapix.value parms[1].ampcont = self.sampcont.value parms[1].voltage = self.svoltage.value parms[1].cs = self.scs.value self.needredisp = True def imgmousedown(self, event): if self.calcmode == 0: m = self.wimage.scr_to_img((event.x(), event.y())) parms = self.parms[self.curset] parms[2] = (m[0] - parms[0] / 2, m[1] - parms[0] / 2) self.recalc() self.needredisp = True #self.guiim.add_shape("cen",["rect",.9,.9,.4,x0,y0,x0+2,y0+2,1.0]) def imgmousedrag(self, event): if self.calcmode == 0: m = self.wimage.scr_to_img((event.x(), event.y())) parms = self.parms[self.curset] parms[2] = (m[0] - parms[0] / 2, m[1] - parms[0] / 2) self.needredisp = True self.recalc() # box deletion when shift held down #if event.modifiers()&Qt.ShiftModifier: #for i,j in enumerate(self.boxes): def imgmouseup(self, event): m = self.wimage.scr_to_img((event.x(), event.y())) if self.calcmode == 1: parms = self.parms[self.curset] nx = self.data["nx"] / parms[0] - 1 grid = int((m[0] - parms[0] / 2) / parms[0]) + int( (m[1] - parms[0] / 2) / parms[0]) * nx if grid in parms[3]: parms[3].remove(grid) else: parms[3].add(grid) self.needredisp = True self.recalc() def fftmousedown(self, event, m): #m=self.wfft.scr_to_img((event.x(),event.y())) if self.f2danmode == 1: self.ringrad = hypot(m[0] - self.fft["nx"] / 2, m[1] - self.fft["ny"] / 2) self.needredisp = True elif self.f2danmode == 2: if (event.modifiers() & Qt.ControlModifier): self.xpos2 = ((m[0] - self.fft["nx"] / 2) / 3.0, (m[1] - self.fft["ny"] / 2) / 3.0) else: self.xpos1 = ((m[0] - self.fft["nx"] / 2) / 3.0, (m[1] - self.fft["ny"] / 2) / 3.0) self.needredisp = True #self.guiim.add_shape("cen",["rect",.9,.9,.4,x0,y0,x0+2,y0+2,1.0]) def fftmousedrag(self, event, m): #m=self.wfft.scr_to_img((event.x(),event.y())) if self.f2danmode == 1: self.ringrad = hypot(m[0] - self.fft["nx"] / 2, m[1] - self.fft["ny"] / 2) self.needredisp = True elif self.f2danmode == 2: if (event.modifiers() & Qt.ControlModifier): self.xpos2 = ((m[0] - self.fft["nx"] / 2) / 3.0, (m[1] - self.fft["ny"] / 2) / 3.0) else: self.xpos1 = ((m[0] - self.fft["nx"] / 2) / 3.0, (m[1] - self.fft["ny"] / 2) / 3.0) self.needredisp = True # box deletion when shift held down #if event.modifiers()&Qt.ShiftModifier: #for i,j in enumerate(self.boxes): def fftmouseup(self, event, m): "up" #m=self.wfft.scr_to_img((event.x(),event.y())) def plotmousedown(self, event): "mousedown in plot"
def __init__(self, imagenames, voltage=None, apix=None, cs=None, ac=10.0, box=256, ptcl=200): """The 'new' e2boxer interface. """ QtGui.QWidget.__init__(self, None) # self.setWindowIcon(QtGui.QIcon(get_image_directory() + "ctf.png")) self.data = None self.curfilename = None # current selected file for boxing self.filenames = imagenames # list of available filenames self.micrograph = None self.boxes = None self.defaultvoltage = voltage self.defaultapix = apix self.defaultcs = cs self.defaultac = ac self.db = None # open JSON file for current image self.wimage = EMImage2DWidget() self.wimage.setWindowTitle("Micrograph") self.wparticles = EMImageMXWidget() self.wparticles.setWindowTitle("Particles") self.wrefs = EMImageMXWidget() self.wrefs.setWindowTitle("Box Refs") self.wbadrefs = EMImageMXWidget() self.wbadrefs.setWindowTitle("Bad Box Refs") #self.wfft=EMImage2DWidget() #self.wfft.setWindowTitle("e2evalimage - 2D FFT") #self.wplot=EMPlot2DWidget() #self.wplot.setWindowTitle("e2evalimage - Plot") self.wimage.connect(self.wimage, QtCore.SIGNAL("mousedown"), self.imgmousedown) self.wimage.connect(self.wimage, QtCore.SIGNAL("mousedrag"), self.imgmousedrag) self.wimage.connect(self.wimage, QtCore.SIGNAL("mouseup"), self.imgmouseup) self.wparticles.connect(self.wparticles, QtCore.SIGNAL("mousedown"), self.ptclmousedown) self.wparticles.connect(self.wparticles, QtCore.SIGNAL("mousedrag"), self.ptclmousedrag) self.wparticles.connect(self.wparticles, QtCore.SIGNAL("mouseup"), self.ptclmouseup) self.wrefs.connect(self.wparticles, QtCore.SIGNAL("mousedown"), self.refmousedown) self.wrefs.connect(self.wparticles, QtCore.SIGNAL("mousedrag"), self.refmousedrag) self.wrefs.connect(self.wparticles, QtCore.SIGNAL("mouseup"), self.refmouseup) self.wimage.mmode = "app" self.wparticles.mmode = "app" # This object is itself a widget we need to set up self.gbl = QtGui.QGridLayout(self) self.gbl.setMargin(8) self.gbl.setSpacing(6) # Micrograph list self.setlist = QtGui.QListWidget(self) self.setlist.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Expanding) for i in imagenames: self.setlist.addItem(i) self.gbl.addWidget(self.setlist, 0, 0, 12, 2) self.setlist.connect(self.setlist, QtCore.SIGNAL("currentRowChanged(int)"), self.newSet) self.setlist.connect(self.setlist, QtCore.SIGNAL("keypress"), self.listKey) # Mouse Modes self.mmode = "manual" self.boxmm = QtGui.QGroupBox("Mouse Mode", self) self.boxmm.setFlat(False) self.gbl.addWidget(self.boxmm, 0, 2, 3, 2) self.hbl0 = QtGui.QHBoxLayout(self.boxmm) self.bmmanual = QtGui.QPushButton("Manual") self.bmmanual.setToolTip( "Manual selection of particles. No impact on autoselection.") self.bmmanual.setAutoExclusive(True) self.bmmanual.setCheckable(True) self.bmmanual.setChecked(True) self.hbl0.addWidget(self.bmmanual) self.bmdel = QtGui.QPushButton("Delete") self.bmdel.setToolTip( "Delete particles from any mode. Can also shift-click in other mouse modes." ) self.bmdel.setAutoExclusive(True) self.bmdel.setCheckable(True) self.hbl0.addWidget(self.bmdel) self.bmgref = QtGui.QPushButton("Good Refs") self.bmgref.setToolTip( "Identify some good particles. Available to all autoboxers.") self.bmgref.setAutoExclusive(True) self.bmgref.setCheckable(True) self.hbl0.addWidget(self.bmgref) self.bmbref = QtGui.QPushButton("Bad Refs") self.bmbref.setToolTip( "Identify regions which should not be selected as particles.") self.bmbref.setAutoExclusive(True) self.bmbref.setCheckable(True) self.hbl0.addWidget(self.bmbref) QtCore.QObject.connect(self.bmmanual, QtCore.SIGNAL("clicked(bool)"), self.setMouseManual) QtCore.QObject.connect(self.bmdel, QtCore.SIGNAL("clicked(bool)"), self.setMouseDel) QtCore.QObject.connect(self.bmgref, QtCore.SIGNAL("clicked(bool)"), self.setMouseGoodRef) QtCore.QObject.connect(self.bmbref, QtCore.SIGNAL("clicked(bool)"), self.setMouseBadRef) # Global parameters self.boxparm = QtGui.QGroupBox("Parameters", self) self.boxparm.setFlat(False) self.gbl.addWidget(self.boxparm, 3, 2, 3, 3) self.gbl1 = QtGui.QGridLayout(self.boxparm) self.gbl1.setMargin(8) self.gbl1.setSpacing(6) self.vbbsize = ValBox(label="Box Size:", value=box) self.gbl1.addWidget(self.vbbsize, 0, 0) self.vbbpsize = ValBox(label="Ptcl Size:", value=ptcl) self.gbl1.addWidget(self.vbbpsize, 0, 1) self.vbbapix = ValBox(label="A/pix:", value=apix) self.gbl1.addWidget(self.vbbapix, 0, 2) self.vbvoltage = ValBox(label="Voltage:", value=voltage) self.gbl1.addWidget(self.vbvoltage, 1, 0) self.vbbac = ValBox(label="% AC:", value=ac) self.gbl1.addWidget(self.vbbac, 1, 1) self.vbcs = ValBox(label="Cs:", value=cs) self.gbl1.addWidget(self.vbcs, 1, 2) # Autoboxing Tabs self.autolbl = QtGui.QLabel("Autoboxing Methods:") self.gbl.addWidget(self.autolbl, 7, 2) self.autotab = QtGui.QTabWidget() self.gbl.addWidget(self.autotab, 8, 2, 6, 3) self.bautobox = QtGui.QPushButton("Autobox") self.gbl.addWidget(self.bautobox, 7, 4) QtCore.QObject.connect(self.bautobox, QtCore.SIGNAL("clicked(bool)"), self.doAutoBox) # Individual tabs from Dictionary self.abwid = [] for name, bname, cls in GUIBoxer.aboxmodes: w = QtGui.QWidget() gl = QtGui.QGridLayout(w) self.abwid.append((w, gl)) cls.setup_gui(gl) self.autotab.addTab(w, name) self.setWindowTitle("e2boxer21 - Control Panel") self.wimage.show() # self.wfft.show() # self.wplot.show() E2loadappwin("e2boxer21", "main", self) E2loadappwin("e2boxer21", "image", self.wimage.qt_parent) E2loadappwin("e2boxer21", "particles", self.wparticles.qt_parent) E2loadappwin("e2boxer21", "refs", self.wrefs.qt_parent) E2loadappwin("e2boxer21", "badrefs", self.wbadrefs.qt_parent) self.newSet(0)
class GUIBoxer(QtGui.QWidget): # Dictionary of autopickers # to add a new one, provide name:(Qt_setup_function,picker_execution_function) # Qt_setup_function(self,empty_grid_layout) # picker_execution_function(self,... aboxmodes = [("by Ref", "auto_ref", boxerByRef), ("Gauss", "auto_gauss", boxerGauss)] boxcolors = { "selected": (0.9, 0.9, 0.9), "manual": (0, 0, 0), "refgood": (0, 0.8, 0), "refbad": (0.8, 0, 0), "unknown": [.4, .4, .1], "auto_ref": (.1, .1, .4), "auto_gauss": (.4, .1, .4) } def __init__(self, imagenames, voltage=None, apix=None, cs=None, ac=10.0, box=256, ptcl=200): """The 'new' e2boxer interface. """ QtGui.QWidget.__init__(self, None) # self.setWindowIcon(QtGui.QIcon(get_image_directory() + "ctf.png")) self.data = None self.curfilename = None # current selected file for boxing self.filenames = imagenames # list of available filenames self.micrograph = None self.boxes = None self.defaultvoltage = voltage self.defaultapix = apix self.defaultcs = cs self.defaultac = ac self.db = None # open JSON file for current image self.wimage = EMImage2DWidget() self.wimage.setWindowTitle("Micrograph") self.wparticles = EMImageMXWidget() self.wparticles.setWindowTitle("Particles") self.wrefs = EMImageMXWidget() self.wrefs.setWindowTitle("Box Refs") self.wbadrefs = EMImageMXWidget() self.wbadrefs.setWindowTitle("Bad Box Refs") #self.wfft=EMImage2DWidget() #self.wfft.setWindowTitle("e2evalimage - 2D FFT") #self.wplot=EMPlot2DWidget() #self.wplot.setWindowTitle("e2evalimage - Plot") self.wimage.connect(self.wimage, QtCore.SIGNAL("mousedown"), self.imgmousedown) self.wimage.connect(self.wimage, QtCore.SIGNAL("mousedrag"), self.imgmousedrag) self.wimage.connect(self.wimage, QtCore.SIGNAL("mouseup"), self.imgmouseup) self.wparticles.connect(self.wparticles, QtCore.SIGNAL("mousedown"), self.ptclmousedown) self.wparticles.connect(self.wparticles, QtCore.SIGNAL("mousedrag"), self.ptclmousedrag) self.wparticles.connect(self.wparticles, QtCore.SIGNAL("mouseup"), self.ptclmouseup) self.wrefs.connect(self.wparticles, QtCore.SIGNAL("mousedown"), self.refmousedown) self.wrefs.connect(self.wparticles, QtCore.SIGNAL("mousedrag"), self.refmousedrag) self.wrefs.connect(self.wparticles, QtCore.SIGNAL("mouseup"), self.refmouseup) self.wimage.mmode = "app" self.wparticles.mmode = "app" # This object is itself a widget we need to set up self.gbl = QtGui.QGridLayout(self) self.gbl.setMargin(8) self.gbl.setSpacing(6) # Micrograph list self.setlist = QtGui.QListWidget(self) self.setlist.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Expanding) for i in imagenames: self.setlist.addItem(i) self.gbl.addWidget(self.setlist, 0, 0, 12, 2) self.setlist.connect(self.setlist, QtCore.SIGNAL("currentRowChanged(int)"), self.newSet) self.setlist.connect(self.setlist, QtCore.SIGNAL("keypress"), self.listKey) # Mouse Modes self.mmode = "manual" self.boxmm = QtGui.QGroupBox("Mouse Mode", self) self.boxmm.setFlat(False) self.gbl.addWidget(self.boxmm, 0, 2, 3, 2) self.hbl0 = QtGui.QHBoxLayout(self.boxmm) self.bmmanual = QtGui.QPushButton("Manual") self.bmmanual.setToolTip( "Manual selection of particles. No impact on autoselection.") self.bmmanual.setAutoExclusive(True) self.bmmanual.setCheckable(True) self.bmmanual.setChecked(True) self.hbl0.addWidget(self.bmmanual) self.bmdel = QtGui.QPushButton("Delete") self.bmdel.setToolTip( "Delete particles from any mode. Can also shift-click in other mouse modes." ) self.bmdel.setAutoExclusive(True) self.bmdel.setCheckable(True) self.hbl0.addWidget(self.bmdel) self.bmgref = QtGui.QPushButton("Good Refs") self.bmgref.setToolTip( "Identify some good particles. Available to all autoboxers.") self.bmgref.setAutoExclusive(True) self.bmgref.setCheckable(True) self.hbl0.addWidget(self.bmgref) self.bmbref = QtGui.QPushButton("Bad Refs") self.bmbref.setToolTip( "Identify regions which should not be selected as particles.") self.bmbref.setAutoExclusive(True) self.bmbref.setCheckable(True) self.hbl0.addWidget(self.bmbref) QtCore.QObject.connect(self.bmmanual, QtCore.SIGNAL("clicked(bool)"), self.setMouseManual) QtCore.QObject.connect(self.bmdel, QtCore.SIGNAL("clicked(bool)"), self.setMouseDel) QtCore.QObject.connect(self.bmgref, QtCore.SIGNAL("clicked(bool)"), self.setMouseGoodRef) QtCore.QObject.connect(self.bmbref, QtCore.SIGNAL("clicked(bool)"), self.setMouseBadRef) # Global parameters self.boxparm = QtGui.QGroupBox("Parameters", self) self.boxparm.setFlat(False) self.gbl.addWidget(self.boxparm, 3, 2, 3, 3) self.gbl1 = QtGui.QGridLayout(self.boxparm) self.gbl1.setMargin(8) self.gbl1.setSpacing(6) self.vbbsize = ValBox(label="Box Size:", value=box) self.gbl1.addWidget(self.vbbsize, 0, 0) self.vbbpsize = ValBox(label="Ptcl Size:", value=ptcl) self.gbl1.addWidget(self.vbbpsize, 0, 1) self.vbbapix = ValBox(label="A/pix:", value=apix) self.gbl1.addWidget(self.vbbapix, 0, 2) self.vbvoltage = ValBox(label="Voltage:", value=voltage) self.gbl1.addWidget(self.vbvoltage, 1, 0) self.vbbac = ValBox(label="% AC:", value=ac) self.gbl1.addWidget(self.vbbac, 1, 1) self.vbcs = ValBox(label="Cs:", value=cs) self.gbl1.addWidget(self.vbcs, 1, 2) # Autoboxing Tabs self.autolbl = QtGui.QLabel("Autoboxing Methods:") self.gbl.addWidget(self.autolbl, 7, 2) self.autotab = QtGui.QTabWidget() self.gbl.addWidget(self.autotab, 8, 2, 6, 3) self.bautobox = QtGui.QPushButton("Autobox") self.gbl.addWidget(self.bautobox, 7, 4) QtCore.QObject.connect(self.bautobox, QtCore.SIGNAL("clicked(bool)"), self.doAutoBox) # Individual tabs from Dictionary self.abwid = [] for name, bname, cls in GUIBoxer.aboxmodes: w = QtGui.QWidget() gl = QtGui.QGridLayout(w) self.abwid.append((w, gl)) cls.setup_gui(gl) self.autotab.addTab(w, name) self.setWindowTitle("e2boxer21 - Control Panel") self.wimage.show() # self.wfft.show() # self.wplot.show() E2loadappwin("e2boxer21", "main", self) E2loadappwin("e2boxer21", "image", self.wimage.qt_parent) E2loadappwin("e2boxer21", "particles", self.wparticles.qt_parent) E2loadappwin("e2boxer21", "refs", self.wrefs.qt_parent) E2loadappwin("e2boxer21", "badrefs", self.wbadrefs.qt_parent) self.newSet(0) #QWidget *firstPageWidget = new QWidget; #QWidget *secondPageWidget = new QWidget; #QWidget *thirdPageWidget = new QWidget; #QStackedWidget *stackedWidget = new QStackedWidget; #stackedWidget->addWidget(firstPageWidget); #stackedWidget->addWidget(secondPageWidget); #stackedWidget->addWidget(thirdPageWidget); #QVBoxLayout *layout = new QVBoxLayout; #layout->addWidget(stackedWidget); #setLayout(layout); #QComboBox *pageComboBox = new QComboBox; #pageComboBox->addItem(tr("Page 1")); #pageComboBox->addItem(tr("Page 2")); #pageComboBox->addItem(tr("Page 3")); #connect(pageComboBox, SIGNAL(activated(int)),stackedWidget, SLOT(setCurrentIndex(int))); #self.lboxmode=QtGui.QLabel("Mode:",self) #self.gbl.addWidget(self.lboxmode,10,0) #self.sboxmode=QtGui.QComboBox(self) #self.sboxmode.addItem("Manual") #self.sboxmode.addItem("Reference") #self.sboxmode.setCurrentIndex(1) #self.gbl.addWidget(self.sboxmode,10,1) #self.lanmode=QtGui.QLabel("Annotate:",self) #self.gbl.addWidget(self.lanmode,12,0) #self.sanmode=QtGui.QComboBox(self) #self.sanmode.addItem("Box") #self.sanmode.addItem("Box+dot") #self.sanmode.addItem("Circle") #self.sanmode.addItem("None") #self.gbl.addWidget(self.sanmode,12,1) #self.sdefocus=ValSlider(self,(0,5),"Defocus:",0.0,90) #self.gbl.addWidget(self.sdefocus,0,2,1,3) #self.squality=ValSlider(self,(0,9),"Quality (0-9):",0,90) #self.squality.setIntonly(True) #self.gbl.addWidget(self.squality,6,2,1,3) #self.brefit=QtGui.QPushButton("Autobox") #self.gbl.addWidget(self.brefit,7,2) #self.bclrauto=QtGui.QPushButton("Clear Auto") #self.gbl.addWidget(self.bclrauto,7,3) #self.bclrall=QtGui.QPushButton("Clear All") #self.gbl.addWidget(self.bclrall,7,4) #self.sapix=ValBox(self,(0,500),"A/pix:",1.0,90) #if self.defaultapix!=None : self.sapix.setValue(self.defaultapix) #self.gbl.addWidget(self.sapix,10,2) #self.svoltage=ValBox(self,(0,500),"Voltage (kV):",200,90) #if self.defaultvoltage!=None : self.svoltage.setValue(self.defaultvoltage) #self.gbl.addWidget(self.svoltage,11,2) #self.scs=ValBox(self,(0,5),"Cs (mm):",4.1,90) #if self.defaultcs!=None : self.scs.setValue(self.defaultcs) #self.gbl.addWidget(self.scs,12,2) #self.sboxsize=ValBox(self,(0,500),"Box Size:",256,90) #self.sboxsize.intonly=True #self.gbl.addWidget(self.sboxsize,13,2) #self.sptclsize=ValBox(self,(0,500),"Ptcl Size:",256,90) #self.sptclsize.intonly=True #self.gbl.addWidget(self.sptclsize,14,2) #QtCore.QObject.connect(self.sdefocus, QtCore.SIGNAL("valueChanged"), self.newCTF) #QtCore.QObject.connect(self.sapix, QtCore.SIGNAL("valueChanged"), self.newCTF) #QtCore.QObject.connect(self.svoltage, QtCore.SIGNAL("valueChanged"), self.newCTF) #QtCore.QObject.connect(self.scs, QtCore.SIGNAL("valueChanged"), self.newCTF) #QtCore.QObject.connect(self.sboxsize, QtCore.SIGNAL("valueChanged"), self.newBox) ## QtCore.QObject.connect(self.soversamp, QtCore.SIGNAL("valueChanged"), self.newBox) #QtCore.QObject.connect(self.squality,QtCore.SIGNAL("valueChanged"),self.newQualityFactor) #QtCore.QObject.connect(self.setlist,QtCore.SIGNAL("currentRowChanged(int)"),self.newSet) #QtCore.QObject.connect(self.setlist,QtCore.SIGNAL("keypress"),self.listkey) #QtCore.QObject.connect(self.sboxmode,QtCore.SIGNAL("currentIndexChanged(int)"),self.newBoxMode) #self.resize(720,380) # figured these values out by printing the width and height in resize event #### This section is responsible for background updates #self.busy=False #self.needupdate=True #self.needredisp=False #self.procthread=None #self.errors=None # used to communicate errors back from the reprocessing thread #self.timer=QTimer() #QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.timeOut) #self.timer.start(100) # self.recalc() def setMouseManual(self, x): self.mmode = "manual" def setMouseDel(self, x): self.mmode = "del" def setMouseGoodRef(self, x): self.mmode = "refgood" def setMouseBadRef(self, x): self.mmode = "refbad" def imgmousedown(self, event): m = self.wimage.scr_to_img((event.x(), event.y())) boxsize2 = self.vbbsize.getValue() // 2 ptclsize = self.vbbpsize.getValue() self.curbox = 0 # check to see if click was inside an existing box, in which case we move it for i in self.boxes: if abs(m.x - i[0]) < boxsize2 and abs(m.y - i[1]) < boxsize2: self.curbox = i break else: # Create a new box if self.mmode == "del": return # This is for creating a new box, so clearly not desirable in delete mode self.curbox = len(self.boxes) self.boxes.append((m[0], m[1], self.mmode)) self.__addBox(self.curbox, self.boxes[-1]) #self.guiim.add_shape("cen",["rect",.9,.9,.4,x0,y0,x0+2,y0+2,1.0]) def imgmousedrag(self, event): if self.calcmode == 0: m = self.wimage.scr_to_img((event.x(), event.y())) parms = self.parms[self.curset] parms[2] = (m[0] - parms[0] / 2, m[1] - parms[0] / 2) self.needredisp = True self.recalc() # box deletion when shift held down #if event.modifiers()&Qt.ShiftModifier: #for i,j in enumerate(self.boxes): def imgmouseup(self, event): m = self.wimage.scr_to_img((event.x(), event.y())) if self.calcmode == 1: parms = self.parms[self.curset] nx = self.data["nx"] / parms[0] - 1 grid = int((m[0] - parms[0] / 2) / parms[0]) + int( (m[1] - parms[0] / 2) / parms[0]) * nx if grid in parms[3]: parms[3].remove(grid) else: parms[3].add(grid) self.needredisp = True self.recalc() def ptclmousedown(self, event): return def ptclmousedrag(self, event): return def ptclmouseup(self, event): return def refmousedown(self, event): return def refmousedrag(self, event): return def refmouseup(self, event): return def newSet(self, val): "called when a new data set is selected from the list" first = True newfilename = str(self.setlist.item(val).text()) if newfilename == self.curfilename: return # Write the current image parameters to the database if self.curfilename != None and self.boxes != None: self.save_boxes() first = False self.micrograph = load_micrograph(newfilename) self.wimage.set_data(self.micrograph) if first: E2loadappwin("e2boxer21", "image", self.wimage.qt_parent) self.curfilename = newfilename self.restore_boxes() def save_boxes(self): js = js_open_dict(info_name(self.curfilename)) js["boxes"] = self.boxes def restore_boxes(self): # first we restore the list of box locations js = js_open_dict(info_name(self.curfilename)) try: self.boxes = js["boxes"] except: self.boxes = [] boxsize = self.vbbsize.getValue() ptclsize = self.vbbpsize.getValue() micro = self.wimage.get_data() self.wimage.del_shapes() if len(self.boxes) == 0: self.wparticles.set_data([]) return # Then we extract the actual boxed out particles goodrefs = [] badrefs = [] self.particles = [] for i, box in enumerate(self.boxes): self.__addBox(i, box) # extract the data boxim = self.micrograph.get_clip( Region(box[0] - boxsize // 2, box[1] - boxsize // 2, boxsize, boxsize)) boxim["ptcl_source_coord"] = (box[0], box[1]) if box[2] == "refgood": goodrefs.append(boxim) elif box[2] == "refbad": badrefs.append(boxim) else: self.particles.append(boxim) # finally redisplay as appropriate self.wimage.update() self.wparticles.set_data(self.particles) if len(self.particles) > 0: self.wparticles.show() if len(goodrefs) + len(badrefs) != 0: self.goodrefs = goodrefs self.badrefs = badrefs self.wrefs.set_data(self.goodrefs) self.wbadrefs.set_data(self.badrefs) if len(self.goodrefs) > 0: self.wrefs.show() if len(self.badrefs) > 0: self.wbadrefs.show() def __addBox(self, i, box): """takes the number of the box in self.boxes and the (x,y,mode) tuple and displays it""" # Display the actual box boxsize = self.vbbsize.getValue() ptclsize = self.vbbpsize.getValue() try: color = self.boxcolors[box[2]] except: color = self.boxcolors["unknown"] self.wimage.add_shape( "box{}".format(i), EMShape(("rect", color[0], color[1], color[2], box[0] - boxsize // 2, box[1] - boxsize // 2, box[0] + boxsize // 2, box[1] + boxsize // 2, 2))) self.wimage.add_shape( "cir{}".format(i), EMShape(("circle", color[0], color[1], color[2], box[0], box[1], ptclsize / 2, 1.5))) def listKey(self, event): pass #if event.key()>=Qt.Key_0 and event.key()<=Qt.Key_9 : #q=int(event.key())-Qt.Key_0 #self.squality.setValue(q) #elif event.key() == Qt.Key_Left: #self.sdefocus.setValue(self.sdefocus.getValue()-0.03) #elif event.key() == Qt.Key_Right: #self.sdefocus.setValue(self.sdefocus.getValue()+0.03) #elif event.key()==Qt.Key_I : #self.doImport() #elif event.key()==Qt.Key_U : #self.unImport() def doAutoBox(self, b): """Autobox button pressed, find the right algorithm and call it""" name, bname, fn1 = self.aboxmodes[self.autotab.currentIndex()] print name, " called" def closeEvent(self, event): # QtGui.QWidget.closeEvent(self,event) E2saveappwin("e2boxer21", "main", self) E2saveappwin("e2boxer21", "image", self.wimage.qt_parent) E2saveappwin("e2boxer21", "particles", self.wparticles.qt_parent) E2saveappwin("e2boxer21", "refs", self.wrefs.qt_parent) E2saveappwin("e2boxer21", "badrefs", self.wbadrefs.qt_parent) #self.writeCurParm() event.accept() QtGui.qApp.exit(0)
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 __new__(cls,filename,application,force_plot=False,force_2d=False,old=None): file_type = Util.get_filename_ext(filename) em_file_type = EMUtil.get_image_ext_type(file_type) if not file_exists(filename): return None if force_plot and force_2d: # ok this sucks but it suffices for the time being print "Error, the force_plot and force_2d options are mutually exclusive" return None if force_plot: from emplot2d import EMPlot2DWidget if isinstance(old,EMPlot2DWidget): widget = old else: widget = EMPlot2DWidget(application=application) widget.set_data_from_file(filename) return widget if em_file_type != IMAGE_UNKNOWN or filename[:4] == "bdb:": n = EMUtil.get_image_count(filename) nx,ny,nz = gimme_image_dimensions3D(filename) if n > 1 and nz == 1: if force_2d: a = EMData() data=a.read_images(filename) else: data = None # This is like a flag - the ImageMXWidget only needs the file name elif nz == 1: data = [EMData(filename,0)] else: data = EMData() data.read_image(filename,0,not force_2d) # This should be 3-D. We read the header-only here data = [data] if data != None and len(data) == 1: data = data[0] if force_2d or isinstance(data,EMData) and data.get_zsize()==1: if isinstance(data,list) or data.get_ysize() != 1: from emimage2d import EMImage2DWidget if isinstance(old,EMImage2DWidget): widget = old else: widget= EMImage2DWidget(application=application) else: from emplot2d import EMPlot2DWidget if isinstance(old,EMPlot2DWidget): widget = old else: widget = EMPlot2DWidget(application=application) widget.set_data_from_file(filename) return widget elif isinstance(data,EMData): if isinstance(old,EMScene3D): widget = old else: widget = EMScene3D() # print n,data for ii in xrange(n): data=EMData(filename,ii) datai = EMDataItem3D(data, transform=Transform()) widget.insertNewNode(os.path.basename(filename), datai, parentnode=widget) isosurface = EMIsosurface(datai, transform=Transform()) widget.insertNewNode("Iso", isosurface, parentnode=datai) return widget elif data == None or isinstance(data,list): from emimagemx import EMImageMXWidget if isinstance(old,EMImageMXWidget): widget = old else: widget = EMImageMXWidget(application=application) data = filename else: print filename raise # weirdness, this should never happen widget.set_data(data,filename) return widget else: from emplot2d import EMPlot2DWidget if isinstance(old,EMPlot2DWidget): widget = old else: widget = EMPlot2DWidget(application=application) widget.set_data_from_file(filename) return widget
def __new__(cls, filename, application, force_plot=False, force_2d=False, old=None): file_type = Util.get_filename_ext(filename) em_file_type = EMUtil.get_image_ext_type(file_type) if not file_exists(filename): return None if force_plot and force_2d: # ok this sucks but it suffices for the time being print( "Error, the force_plot and force_2d options are mutually exclusive" ) return None if force_plot: from emplot2d import EMPlot2DWidget if isinstance(old, EMPlot2DWidget): widget = old else: widget = EMPlot2DWidget(application=application) widget.set_data_from_file(filename) return widget if em_file_type != IMAGE_UNKNOWN or filename[:4] == "bdb:": n = EMUtil.get_image_count(filename) nx, ny, nz = gimme_image_dimensions3D(filename) if n > 1 and nz == 1: if force_2d: a = EMData() data = a.read_images(filename) else: data = None # This is like a flag - the ImageMXWidget only needs the file name elif nz == 1: data = [EMData(filename, 0)] else: data = EMData() data.read_image( filename, 0, not force_2d ) # This should be 3-D. We read the header-only here data = [data] if data != None and len(data) == 1: data = data[0] if force_2d or isinstance(data, EMData) and data.get_zsize() == 1: if isinstance(data, list) or data.get_ysize() != 1: from emimage2d import EMImage2DWidget if isinstance(old, EMImage2DWidget): widget = old else: widget = EMImage2DWidget(application=application) else: from emplot2d import EMPlot2DWidget if isinstance(old, EMPlot2DWidget): widget = old else: widget = EMPlot2DWidget(application=application) widget.set_data_from_file(filename) return widget elif isinstance(data, EMData): if isinstance(old, EMScene3D): widget = old else: widget = EMScene3D() # print n,data for ii in xrange(n): data = EMData(filename, ii) datai = EMDataItem3D(data, transform=Transform()) widget.insertNewNode(os.path.basename(filename), datai, parentnode=widget) isosurface = EMIsosurface(datai, transform=Transform()) widget.insertNewNode("Iso", isosurface, parentnode=datai) return widget elif data == None or isinstance(data, list): from emimagemx import EMImageMXWidget if isinstance(old, EMImageMXWidget): widget = old else: widget = EMImageMXWidget(application=application) data = filename else: print(filename) raise # weirdness, this should never happen widget.set_data(data, filename) return widget else: from emplot2d import EMPlot2DWidget if isinstance(old, EMPlot2DWidget): widget = old else: widget = EMPlot2DWidget(application=application) widget.set_data_from_file(filename) return widget
class EMClassPtclTool(QtGui.QWidget): """This class is a tab widget for inspecting particles within class-averages""" def __init__(self, extrafiles=None): QtGui.QWidget.__init__(self) self.vbl = QtGui.QVBoxLayout(self) self.extrafiles = extrafiles # A listwidget for selecting which class-average file we're looking at self.wclassfilel = QtGui.QLabel("Class-average File:") self.vbl.addWidget(self.wclassfilel) self.wfilesel = QtGui.QListWidget() self.vbl.addWidget(self.wfilesel) self.vbl.addSpacing(5) # A widget containing the current particle filename, editable by the user # If edited it will also impact set generation ! self.wptclfilel = QtGui.QLabel("Particle Data File:") self.vbl.addWidget(self.wptclfilel) self.wptclfile = QtGui.QComboBox(self) self.vbl.addWidget(self.wptclfile) self.vbl.addSpacing(5) # Selection tools self.wselectg = QtGui.QGroupBox("Class Selection", self) self.wselectg.setFlat(False) self.vbl.addWidget(self.wselectg) self.vbl.addSpacing(5) self.gbl0 = QtGui.QGridLayout(self.wselectg) self.wselallb = QtGui.QPushButton("All") self.gbl0.addWidget(self.wselallb, 0, 0) self.wselnoneb = QtGui.QPushButton("Clear") self.gbl0.addWidget(self.wselnoneb, 0, 1) self.wselrangeb = QtGui.QPushButton("Range") self.gbl0.addWidget(self.wselrangeb, 1, 0) self.wselinvertb = QtGui.QPushButton("Invert") self.gbl0.addWidget(self.wselinvertb, 0, 2) self.wsel3db = QtGui.QPushButton("From 3D") self.gbl0.addWidget(self.wsel3db, 1, 2) self.wprocessg = QtGui.QGroupBox("Process results", self) self.wprocessg.setFlat(False) self.vbl.addWidget(self.wprocessg) self.vbl2 = QtGui.QVBoxLayout(self.wprocessg) self.wselused = CheckBox(None, "Included Ptcls", 1, 100) self.vbl2.addWidget(self.wselused) self.wselunused = CheckBox(None, "Excluded Ptcls", 1, 100) self.vbl2.addWidget(self.wselunused) # Mark particles in selected classes as bad self.wmarkbut = QtGui.QPushButton("Mark as Bad") self.vbl2.addWidget(self.wmarkbut) # Mark particles in selected classes as good self.wmarkgoodbut = QtGui.QPushButton("Mark as Good") self.vbl2.addWidget(self.wmarkgoodbut) # Make a new set from selected classes self.wmakebut = QtGui.QPushButton("Make New Set") self.vbl2.addWidget(self.wmakebut) # self.wmakebut.setEnabled(False) # Save list self.wsavebut = QtGui.QPushButton("Save Particle List") self.vbl2.addWidget(self.wsavebut) # Save micrograph dereferenced lists self.wsaveorigbut = QtGui.QPushButton("Save CCD-based List") self.vbl2.addWidget(self.wsaveorigbut) QtCore.QObject.connect(self.wfilesel, QtCore.SIGNAL("itemSelectionChanged()"), self.fileUpdate) QtCore.QObject.connect(self.wptclfile, QtCore.SIGNAL("currentIndexChanged(int)"), self.ptclChange) QtCore.QObject.connect(self.wselallb, QtCore.SIGNAL("clicked(bool)"), self.selAllClasses) QtCore.QObject.connect(self.wselnoneb, QtCore.SIGNAL("clicked(bool)"), self.selNoClasses) QtCore.QObject.connect(self.wselrangeb, QtCore.SIGNAL("clicked(bool)"), self.selRangeClasses) QtCore.QObject.connect(self.wselinvertb, QtCore.SIGNAL("clicked(bool)"), self.selInvertClasses) QtCore.QObject.connect(self.wsel3db, QtCore.SIGNAL("clicked(bool)"), self.sel3DClasses) QtCore.QObject.connect(self.wmakebut, QtCore.SIGNAL("clicked(bool)"), self.makeNewSet) QtCore.QObject.connect(self.wmarkbut, QtCore.SIGNAL("clicked(bool)"), self.markBadPtcl) QtCore.QObject.connect(self.wmarkgoodbut, QtCore.SIGNAL("clicked(bool)"), self.markGoodPtcl) QtCore.QObject.connect(self.wsavebut, QtCore.SIGNAL("clicked(bool)"), self.savePtclNum) QtCore.QObject.connect(self.wsaveorigbut, QtCore.SIGNAL("clicked(bool)"), self.saveOrigPtclNum) # View windows, one for class-averages, one for good particles and one for bad particles self.vclasses = None self.vgoodptcl = None self.vbadptcl = None self.updateFiles() def makeNewSet(self, x): "Makes a new particle set based on the selected class-averages" setname = QtGui.QInputDialog.getText( None, "Set Name", "Please specify the name for the set. If you specify an existing set, new particles will be added to the end" ) if setname[1] == False: return else: setname = setname[0] if setname[-4:] != ".lst": setname = setname + ".lst" if not "/" in setname: setname = "sets/" + setname lst = LSXFile(self.curPtclFile()) # lst file for dereferenceing lstout = LSXFile(setname) include = [] # iterate over each particle from each marked class-average for n in self.curPtclIter(self.wselused.getValue(), self.wselunused.getValue()): try: orign, origfile, comment = lst.read( n ) # the original file/number dereferenced from the LST file except: QtGui.QMessageBox.warning( self, "Error !", "The data_source '%s' does not follow EMAN2.1 project conventions. Cannot find raw particles for set." % srcfile) return include.append((origfile, orign, comment)) # build a list so we can sort by frame # write the new set for i in sorted(include): lstout.write(-1, i[1], i[0], i[2]) def markBadPtcl(self, x): "Mark particles from the selected class-averages as bad in the set interface" r = QtGui.QMessageBox.question( None, "Are you sure ?", "WARNING: There is no undo for this operation. It will mark all particles associated with the selected class-averages as bad. Are you sure you want to proceed ?", QtGui.QMessageBox.Yes | QtGui.QMessageBox.Cancel) if r == QtGui.QMessageBox.Cancel: return lst = LSXFile(self.curPtclFile()) # lst file for dereferenceing ptcls = { } # dictionary keyed by original frame filename with list of selected particle #s # iterate over each particle from each marked class-average for n in self.curPtclIter(self.wselused.getValue(), self.wselunused.getValue()): try: orign, origfile, comment = lst.read(n) except: QtGui.QMessageBox.warning( self, "Error !", "The data_source '%s' does not follow EMAN2.1 project conventions. Cannot find raw particles for set." % srcfile) return try: ptcls[origfile].append( orign) # try to add to a list for an existing filename except: ptcls[origfile] = [ orign ] # creates the list for this filename if it's new #now mark the particles as bad newbad = 0 totbad = 0 for origfile in ptcls: js = js_open_dict( info_name(origfile)) # get the info dict for this file try: sets = js["sets"] except: sets = {"bad_particles": []} try: badset = set(sets["bad_particles"]) except: badset = set() try: newset = list(set(ptcls[origfile]) | badset) sets[ "bad_particles"] = newset # update the set of bad particles for this image file js["sets"] = sets totbad += len(badset) newbad += len(newset) - len(badset) except: print "Error setting bad particles in ", origfile js_close_dict(info_name(origfile)) print newbad, " new particles marked as bad. Total of ", totbad, " in affected micrographs" def markGoodPtcl(self, x): "Mark particles from the selected class-averages as good in the set interface" r = QtGui.QMessageBox.question( None, "Are you sure ?", "WARNING: There is no undo for this operation. It will un-mark all particles associated with the selected class-averages as bad. Are you sure you want to proceed ?", QtGui.QMessageBox.Yes | QtGui.QMessageBox.Cancel) if r == QtGui.QMessageBox.Cancel: return lst = LSXFile(self.curPtclFile()) # lst file for dereferenceing ptcls = { } # dictionary keyed by original frame filename with list of selected particle #s # iterate over each particle from each marked class-average for n in self.curPtclIter(self.wselused.getValue(), self.wselunused.getValue()): try: orign, origfile, comment = lst.read(n) except: QtGui.QMessageBox.warning( self, "Error !", "The data_source '%s' does not follow EMAN2.1 project conventions. Cannot find raw particles for set." % srcfile) return try: ptcls[origfile].append( orign) # try to add to a list for an existing filename except: ptcls[origfile] = [ orign ] # creates the list for this filename if it's new #now mark the particles as good badafter = 0 badbefore = 0 for origfile in ptcls: js = js_open_dict( info_name(origfile)) # get the info dict for this file try: badset = set(js["sets"]["bad_particles"]) js["sets"]["bad_particles"] = list( badset - set(ptcls[origfile]) ) # update the set of bad particles for this image file except: pass # since marking as good is the same as removing from the bad list, if there is no bad list, there is nothing to do try: sets = js["sets"] except: continue # if no current bad particles, nothing to mark good try: badset = sets["bad_particles"] except: continue try: newset = list(badset - set(ptcls[origfile])) sets[ "bad_particles"] = newset # update the set of bad particles for this image file js["sets"] = sets badbefore += len(badset) badafter += len(newset) except: continue print badbefore, " bad particles before processing, now ", badafter def savePtclNum(self, x): "Saves a list of particles from marked classes into a text file" filename = QtGui.QInputDialog.getText( None, "Filename", "Please enter a filename for the particle list. The file will contain the particle number (within the particle file) for each particle associated with a selected class-average." ) if filename[1] == False or filename[0] == "": return out = file(filename[0], "w") for i in self.curPtclIter(self.wselused.getValue(), self.wselunused.getValue()): out.write("%d\n" % i) out.close() def saveOrigPtclNum(self, x): "Saves a file containing micrograph-dereferenced particles" filename = QtGui.QInputDialog.getText( None, "Filename", "Please enter a filename for the particle list. The file will contain particle number and image file, one per line. Image files will be referenced back to the original per-CCD frame stacks." ) if filename[1] == False or filename[0] == "": return lst = LSXFile(self.curPtclFile()) # lst file for dereferenceing include = [] # iterate over each particle from each marked class-average for n in self.curPtclIter(self.wselused.getValue(), self.wselunused.getValue()): try: orign, origfile, comment = lst.read( n ) # the original file/number dereferenced from the LST file except: QtGui.QMessageBox.warning( self, "Error !", "The data_source '%s' does not follow EMAN2.1 project conventions. Cannot find raw particles for set." % srcfile) return include.append((origfile, orign, comment)) # build a list so we can sort by frame # write the output file out = file(filename, "w") for i in sorted(include): out.write("{}\t{}\n".format(i[1], i[0])) out = None def selAllClasses(self, x): "Mark all classes as selected" self.vclasses.all_set() def selNoClasses(self, x): "Clear selection" self.vclasses.clear_set() def selRangeClasses(self, x): "Select a range of images (ask the user for the range)" rng = QtGui.QInputDialog.getText( None, "Select Range", "Enter the range of particle values as first-last (inclusive). Merges with existing selection." ) if rng[1] == False: return try: x0, x1 = rng[0].split("-") x0 = int(x0) x1 = int(x1) + 1 except: QtGui.QMessageBox.warning(self, "Error !", "Invalid range specified. Use: min-max") return self.vclasses.subset_set(range(x0, x1)) def selInvertClasses(self, x): "Inverts the current selection set" self.vclasses.invert_set() def sel3DClasses(self, x): "Select a range of images based on those used in a 3-D reconstruction associated with this classes file. Removes current selection first." f = self.curFile() if not '#classes_' in f: QtGui.QMessageBox.warning( self, "Error !", "A classes_xx file from a refine_xx directory is not currently selected" ) return # construct the path to the threed_xx file num = f.split("_")[-1] pre = f.split("#")[0] d3path = "%s#threed_%s" % (pre, num) try: a = EMData(d3path, 0, True) goodptcl = a["threed_ptcl_idxs"] except: QtGui.QMessageBox.warning(self, "Error !", "Cannot read classes from " + d3path) return self.vclasses.clear_set() self.vclasses.subset_set(goodptcl) def ptclChange(self, value): "Called when a change of particle data file occurs to zero out the display" try: self.vgoodptcl.set_data(None) self.vbadptcl.set_data(None) except: pass def updateFiles(self): "Updates the list of classes files" subdir = sorted([ i for i in os.listdir(e2getcwd()) if "r2d_" in i or "relion2d_" in i or "refine_" in i or "multi_" in i or "multinoali_" in i ]) for d in subdir: try: dbs = os.listdir(d) except: continue dbs.sort() for db in dbs: if "classes_" in db or "allrefs_" in db: self.wfilesel.addItem("%s/%s" % (d, db)) for f in self.extrafiles: self.wfilesel.addItem(f) dbs = os.listdir("sets") dbs.sort() for db in dbs: self.wptclfile.addItem("sets/" + db) def curPtclIter(self, included=True, excluded=True): "This is a generator function which yields n (in self.curPtclFile()) for all particles associated with selected classes" for ci in self.curSet(): try: c = EMData(self.curFile(), ci, True) # read header for current class average if included: incl = c["class_ptcl_idxs"] if isinstance(incl, int): incl = [ incl ] # This should not happen, but seems to sometimes for some reason for i in incl: yield (i) if excluded and c.has_attr("exc_class_ptcl_idxs"): excl = c["exc_class_ptcl_idxs"] if isinstance(excl, int): excl = [ excl ] # This should not happen, but seems to sometimes for some reason for i in excl: yield (i) except: print "Problem with class %d (%s). Skipping" % (ci, self.curFile()) traceback.print_exc() continue def curFile(self): "return the currently selected file as a readable path" return str(self.wfilesel.item(self.wfilesel.currentRow()).text() ) # text of the currently selected item def curSet(self): "return a set (integers) of the currently selected class-averages" return self.vclasses.get_set("evalptcl") def curPtclFile(self): "return the particle file associated with the currently selected classes file" return str(self.wptclfile.currentText() ) # text of the currently selected item def fileUpdate(self): "Called when the user selects a file from the list or need to completely refresh display" QtGui.qApp.setOverrideCursor(Qt.BusyCursor) if self.vclasses == None: self.vclasses = EMImageMXWidget() self.vclasses.set_mouse_mode("App") QtCore.QObject.connect(self.vclasses, QtCore.SIGNAL("mx_image_selected"), self.classSelect) QtCore.QObject.connect(self.vclasses, QtCore.SIGNAL("mx_image_double"), self.classDouble) self.vclasses.set_title("Classes") # self.classes=EMData.read_images(self.curFile()) self.vclasses.set_data(self.curFile(), self.curFile()) # self.vclasses.set_single_active_set("selected") # This makes the 'set' representing the selected class-averages current self.vclasses.set_mouse_mode("App") self.vclasses.enable_set("evalptcl", []) # This makes sure the particle file is in the list of choices and is selected try: ptclfile = EMData(self.curFile(), 0, True)["class_ptcl_src"] i = self.wptclfile.findText(ptclfile) if i == -1: self.wptclfile.insertItem(0, ptclfile) self.wptclfile.setCurrentIndex(0) else: self.wptclfile.setCurrentIndex(i) except: QtGui.QMessageBox.warning( self, "Error !", "This image does not appear to be a class average. (No class_ptcl_src, etc.)" ) ptclfile = "None" # Make sure our display widgets exist if self.vgoodptcl == None: self.vgoodptcl = EMImageMXWidget() self.vgoodptcl.set_title("Included Particles") if self.vbadptcl == None: self.vbadptcl = EMImageMXWidget() self.vbadptcl.set_title("Excluded Particles") self.vclasses.show() self.vgoodptcl.show() self.vbadptcl.show() QtGui.qApp.setOverrideCursor(Qt.ArrowCursor) def classSelect(self, event, lc): "Single clicked class particle. lc=(img#,x,y,image_dict)" QtGui.qApp.setOverrideCursor(Qt.BusyCursor) ptclfile = self.curPtclFile() try: ptclgood = lc[3]["class_ptcl_idxs"] self.vgoodptcl.set_data(EMData.read_images(ptclfile, ptclgood)) except: QtGui.QMessageBox.warning( self, "Error !", "This image does not appear to be a class average. (No class_ptcl_src, etc.)" ) QtGui.qApp.setOverrideCursor(Qt.ArrowCursor) return try: ptclbad = lc[3]["exc_class_ptcl_idxs"] self.vbadptcl.set_data(EMData.read_images(ptclfile, ptclbad)) except: ptclbad = [] self.vbadptcl.set_data(None) self.vgoodptcl.show() self.vbadptcl.show() QtGui.qApp.setOverrideCursor(Qt.ArrowCursor) def classDouble(self, event, lc): self.vclasses.image_set_associate(lc[0], update_gl=True) def closeEvent(self, event): try: self.vclasses.commit_sets() self.vclasses.close() except: pass try: self.vgoodptcl.close() except: pass try: self.vbadptcl.close() except: pass QtGui.QWidget.closeEvent(self, event)
def __new__(cls, data=None, old=None, app=None, force_2d=False, force_plot=False, filename="", replace=True): """This will create a new EMImage* object depending on the type of 'data'. If old= is provided, and of the appropriate type, it will be used rather than creating a new instance. """ if isinstance(data, EMData) and data.get_size() == 0: raise RuntimeError( "Can not display an EMData object that has no pixels") from EMAN2 import remove_directories_from_name if force_plot and force_2d: # ok this sucks but it suffices for the time being print( "Error, the force_plot and force_2d options are mutually exclusive" ) return None if force_plot or (isinstance(data, EMData) and data.get_zsize() == 1 and data.get_ysize() == 1): from emplot2d import EMPlot2DWidget if old: if isinstance(old, EMPlot2DWidget): old.set_data(data, remove_directories_from_name(filename), replace) return old widget = EMPlot2DWidget(application=app) widget.set_data(data, remove_directories_from_name(filename), replace) return widget elif force_2d or (isinstance(data, EMData) and data.get_zsize() == 1): from emimage2d import EMImage2DWidget if old: if isinstance(old, EMImage2DWidget): old.set_data(data, filename) return old widget = EMImage2DWidget(application=app) widget.set_data(data, filename) return widget elif isinstance(data, EMData): if isinstance(old, EMScene3D): widget = old else: widget = EMScene3D() data = EMDataItem3D(data, transform=Transform()) #data.setSelectedItem(True) isosurface = EMIsosurface(data, transform=Transform()) widget.insertNewNode(os.path.basename(filename), data, parentnode=widget) widget.insertNewNode("Iso", isosurface, parentnode=data) return widget elif isinstance(data, list) and isinstance(data[0], EMData): from emimagemx import EMImageMXWidget if old: if isinstance(old, EMImageMXWidget): old.set_data(data, filename) return old widget = EMImageMXWidget(application=app) widget.set_data(data, filename) return widget elif isinstance(data, list): from emplot3d import EMPlot3DWidgetNew if (isinstance(data[0], list) or isinstance(data[0], tuple)) and len(data) > 2: if old: if isinstance(old, EMPlot3DWidgetNew): old.set_data(data, remove_directories_from_name(filename), replace) return old widget = EMPlot3DWidgetNew() widget.set_data(data, remove_directories_from_name(filename), replace) return widget else: from emplot2d import EMPlot2DWidget if old: if isinstance(old, EMPlot2DWidget): old.set_data(data, remove_directories_from_name(filename), replace) return old widget = EMPlot2DWidget(application=app) widget.set_data(data, remove_directories_from_name(filename), replace) return widget else: raise Exception( "data must be a single EMData object or a list of EMData objects" )
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
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
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 setData(self, data): if data == None: self.data = None return elif isinstance(data, str): self.datafile = data self.nimg = EMUtil.get_image_count(data) self.origdata = EMData(data, 0) if self.origdata["nz"] == 1: if self.nimg > 20: self.origdata = EMData.read_images( data, range(0, self.nimg, self.nimg / 20) ) # read regularly separated images from the file totalling ~20 elif self.nimg > 1: self.origdata = EMData.read_images(data, range(self.nimg)) else: self.origdata = [self.origdata] else: self.origdata = [self.origdata] else: self.datafile = None if isinstance(data, EMData): self.origdata = [data] else: self.origdata = data self.nx = self.origdata[0]["nx"] self.ny = self.origdata[0]["ny"] self.nz = self.origdata[0]["nz"] if self.apix <= 0.0: self.apix = self.origdata[0]["apix_x"] EMProcessorWidget.parmdefault["apix"] = (0, (0.2, 10.0), self.apix, None) origfft = self.origdata[0].do_fft() self.pspecorig = origfft.calc_radial_dist(self.ny / 2, 0.0, 1.0, 1) ds = 1.0 / (self.apix * self.ny) self.pspecs = [ds * i for i in range(len(self.pspecorig))] if self.viewer != None: for v in self.viewer: v.close() if self.nz == 1 or self.force2d: if len(self.origdata) > 1: self.viewer = [EMImageMXWidget()] self.mfile_save_stack.setEnabled(True) self.mfile_save_map.setEnabled(False) else: self.viewer = [EMImage2DWidget()] self.mfile_save_stack.setEnabled(False) self.mfile_save_map.setEnabled(True) else: self.mfile_save_stack.setEnabled(False) self.mfile_save_map.setEnabled(True) self.viewer = [EMScene3D()] self.sgdata = EMDataItem3D(test_image_3d(3), transform=Transform()) self.viewer[0].insertNewNode('Data', self.sgdata, parentnode=self.viewer[0]) isosurface = EMIsosurface(self.sgdata, transform=Transform()) self.viewer[0].insertNewNode("Iso", isosurface, parentnode=self.sgdata) volslice = EMSliceItem3D(self.sgdata, transform=Transform()) self.viewer[0].insertNewNode("Slice", volslice, parentnode=self.sgdata) E2loadappwin("e2filtertool", "image", self.viewer[0].qt_parent) self.procChange(-1)
class EMClassPtclTool(QtGui.QWidget): """This class is a tab widget for inspecting particles within class-averages""" def __init__(self,extrafiles=None): QtGui.QWidget.__init__(self) self.vbl = QtGui.QVBoxLayout(self) self.extrafiles=extrafiles # A listwidget for selecting which class-average file we're looking at self.wclassfilel=QtGui.QLabel("Class-average File:") self.vbl.addWidget(self.wclassfilel) self.wfilesel=QtGui.QListWidget() self.vbl.addWidget(self.wfilesel) self.vbl.addSpacing(5) # A widget containing the current particle filename, editable by the user # If edited it will also impact set generation ! self.wptclfilel=QtGui.QLabel("Particle Data File:") self.vbl.addWidget(self.wptclfilel) self.wptclfile=QtGui.QComboBox(self) self.vbl.addWidget(self.wptclfile) self.vbl.addSpacing(5) # Selection tools self.wselectg=QtGui.QGroupBox("Class Selection",self) self.wselectg.setFlat(False) self.vbl.addWidget(self.wselectg) self.vbl.addSpacing(5) self.gbl0=QtGui.QGridLayout(self.wselectg) self.wselallb=QtGui.QPushButton("All") self.gbl0.addWidget(self.wselallb,0,0) self.wselnoneb=QtGui.QPushButton("Clear") self.gbl0.addWidget(self.wselnoneb,0,1) self.wselrangeb=QtGui.QPushButton("Range") self.gbl0.addWidget(self.wselrangeb,1,0) self.wselinvertb=QtGui.QPushButton("Invert") self.gbl0.addWidget(self.wselinvertb,0,2) self.wsel3db=QtGui.QPushButton("From 3D") self.gbl0.addWidget(self.wsel3db,1,2) self.wprocessg=QtGui.QGroupBox("Process results",self) self.wprocessg.setFlat(False) self.vbl.addWidget(self.wprocessg) self.vbl2=QtGui.QVBoxLayout(self.wprocessg) self.wselused=CheckBox(None,"Included Ptcls",1,100) self.vbl2.addWidget(self.wselused) self.wselunused=CheckBox(None,"Excluded Ptcls",1,100) self.vbl2.addWidget(self.wselunused) # Mark particles in selected classes as bad self.wmarkbut=QtGui.QPushButton("Mark as Bad") self.vbl2.addWidget(self.wmarkbut) # Mark particles in selected classes as good self.wmarkgoodbut=QtGui.QPushButton("Mark as Good") self.vbl2.addWidget(self.wmarkgoodbut) # Make a new set from selected classes self.wmakebut=QtGui.QPushButton("Make New Set") self.vbl2.addWidget(self.wmakebut) # self.wmakebut.setEnabled(False) # Save list self.wsavebut=QtGui.QPushButton("Save Particle List") self.vbl2.addWidget(self.wsavebut) # Save micrograph dereferenced lists self.wsaveorigbut=QtGui.QPushButton("Save CCD-based List") self.vbl2.addWidget(self.wsaveorigbut) QtCore.QObject.connect(self.wfilesel,QtCore.SIGNAL("itemSelectionChanged()"),self.fileUpdate) QtCore.QObject.connect(self.wptclfile,QtCore.SIGNAL("currentIndexChanged(int)"),self.ptclChange) QtCore.QObject.connect(self.wselallb,QtCore.SIGNAL("clicked(bool)"),self.selAllClasses) QtCore.QObject.connect(self.wselnoneb,QtCore.SIGNAL("clicked(bool)"),self.selNoClasses) QtCore.QObject.connect(self.wselrangeb,QtCore.SIGNAL("clicked(bool)"),self.selRangeClasses) QtCore.QObject.connect(self.wselinvertb,QtCore.SIGNAL("clicked(bool)"),self.selInvertClasses) QtCore.QObject.connect(self.wsel3db,QtCore.SIGNAL("clicked(bool)"),self.sel3DClasses) QtCore.QObject.connect(self.wmakebut,QtCore.SIGNAL("clicked(bool)"),self.makeNewSet) QtCore.QObject.connect(self.wmarkbut,QtCore.SIGNAL("clicked(bool)"),self.markBadPtcl) QtCore.QObject.connect(self.wmarkgoodbut,QtCore.SIGNAL("clicked(bool)"),self.markGoodPtcl) QtCore.QObject.connect(self.wsavebut,QtCore.SIGNAL("clicked(bool)"),self.savePtclNum) QtCore.QObject.connect(self.wsaveorigbut,QtCore.SIGNAL("clicked(bool)"),self.saveOrigPtclNum) # View windows, one for class-averages, one for good particles and one for bad particles self.vclasses=None self.vgoodptcl=None self.vbadptcl=None self.updateFiles() def makeNewSet(self,x): "Makes a new particle set based on the selected class-averages" setname=QtGui.QInputDialog.getText(None,"Set Name","Please specify the name for the set. If you specify an existing set, new particles will be added to the end") if setname[1]==False : return else: setname=setname[0] if setname[-4:]!=".lst" : setname=setname+".lst" if not "/" in setname : setname="sets/"+setname lst=LSXFile(self.curPtclFile()) # lst file for dereferenceing lstout=LSXFile(setname) include=[] # iterate over each particle from each marked class-average for n in self.curPtclIter(self.wselused.getValue(),self.wselunused.getValue()): try : orign,origfile,comment=lst.read(n) # the original file/number dereferenced from the LST file except: QtGui.QMessageBox.warning(self,"Error !","The data_source '%s' does not follow EMAN2.1 project conventions. Cannot find raw particles for set."%srcfile) return include.append((origfile,orign,comment)) # build a list so we can sort by frame # write the new set for i in sorted(include) : lstout.write(-1,i[1],i[0],i[2]) def markBadPtcl(self,x): "Mark particles from the selected class-averages as bad in the set interface" r=QtGui.QMessageBox.question(None,"Are you sure ?","WARNING: There is no undo for this operation. It will mark all particles associated with the selected class-averages as bad. Are you sure you want to proceed ?",QtGui.QMessageBox.Yes|QtGui.QMessageBox.Cancel) if r==QtGui.QMessageBox.Cancel : return lst=LSXFile(self.curPtclFile()) # lst file for dereferenceing ptcls={} # dictionary keyed by original frame filename with list of selected particle #s # iterate over each particle from each marked class-average for n in self.curPtclIter(self.wselused.getValue(),self.wselunused.getValue()): try : orign,origfile,comment=lst.read(n) except: QtGui.QMessageBox.warning(self,"Error !","The data_source '%s' does not follow EMAN2.1 project conventions. Cannot find raw particles for set."%srcfile) return try: ptcls[origfile].append(orign) # try to add to a list for an existing filename except: ptcls[origfile]=[orign] # creates the list for this filename if it's new #now mark the particles as bad newbad=0 totbad=0 for origfile in ptcls: js=js_open_dict(info_name(origfile)) # get the info dict for this file try: sets=js["sets"] except: sets={"bad_particles":[]} try: badset=set(sets["bad_particles"]) except: badset=set() try: newset=list(set(ptcls[origfile])|badset) sets["bad_particles"]=newset # update the set of bad particles for this image file js["sets"]=sets totbad+=len(badset) newbad+=len(newset)-len(badset) except: print "Error setting bad particles in ",origfile print newbad, " new particles marked as bad. Total of ",totbad," in affected micrographs" def markGoodPtcl(self,x): "Mark particles from the selected class-averages as good in the set interface" r=QtGui.QMessageBox.question(None,"Are you sure ?","WARNING: There is no undo for this operation. It will un-mark all particles associated with the selected class-averages as bad. Are you sure you want to proceed ?",QtGui.QMessageBox.Yes|QtGui.QMessageBox.Cancel) if r==QtGui.QMessageBox.Cancel : return lst=LSXFile(self.curPtclFile()) # lst file for dereferenceing ptcls={} # dictionary keyed by original frame filename with list of selected particle #s # iterate over each particle from each marked class-average for n in self.curPtclIter(self.wselused.getValue(),self.wselunused.getValue()): try : orign,origfile,comment=lst.read(n) except: QtGui.QMessageBox.warning(self,"Error !","The data_source '%s' does not follow EMAN2.1 project conventions. Cannot find raw particles for set."%srcfile) return try: ptcls[origfile].append(orign) # try to add to a list for an existing filename except: ptcls[origfile]=[orign] # creates the list for this filename if it's new #now mark the particles as good badafter=0 badbefore=0 for origfile in ptcls: js=js_open_dict(info_name(origfile)) # get the info dict for this file try: badset=set(js["sets"]["bad_particles"]) js["sets"]["bad_particles"]=list(badset-set(ptcls[origfile])) # update the set of bad particles for this image file except: pass # since marking as good is the same as removing from the bad list, if there is no bad list, there is nothing to do try: sets=js["sets"] except: continue # if no current bad particles, nothing to mark good try: badset=sets["bad_particles"] except: continue try: newset=list(badset-set(ptcls[origfile])) sets["bad_particles"]=newset # update the set of bad particles for this image file js["sets"]=sets badbefore+=len(badset) badafter+=len(newset) except: continue print badbefore," bad particles before processing, now ",badafter def savePtclNum(self,x): "Saves a list of particles from marked classes into a text file" filename=QtGui.QInputDialog.getText(None,"Filename","Please enter a filename for the particle list. The file will contain the particle number (within the particle file) for each particle associated with a selected class-average.") if filename[1]==False or filename[0]=="" : return out=file(filename[0],"w") for i in self.curPtclIter(self.wselused.getValue(),self.wselunused.getValue()): out.write("%d\n"%i) out.close() def saveOrigPtclNum(self,x): "Saves a file containing micrograph-dereferenced particles" filename=QtGui.QInputDialog.getText(None,"Filename","Please enter a filename for the particle list. The file will contain particle number and image file, one per line. Image files will be referenced back to the original per-CCD frame stacks.") if filename[1]==False or filename[0]=="" : return lst=LSXFile(self.curPtclFile()) # lst file for dereferenceing include=[] # iterate over each particle from each marked class-average for n in self.curPtclIter(self.wselused.getValue(),self.wselunused.getValue()): try : orign,origfile,comment=lst.read(n) # the original file/number dereferenced from the LST file except: QtGui.QMessageBox.warning(self,"Error !","The data_source '%s' does not follow EMAN2.1 project conventions. Cannot find raw particles for set."%srcfile) return include.append((origfile,orign,comment)) # build a list so we can sort by frame # write the output file out=file(filename,"w") for i in sorted(include) : out.write("{}\t{}\n".format(i[1],i[0])) out=None def selAllClasses(self,x): "Mark all classes as selected" self.vclasses.all_set() def selNoClasses(self,x): "Clear selection" self.vclasses.clear_set() def selRangeClasses(self,x): "Select a range of images (ask the user for the range)" rng=QtGui.QInputDialog.getText(None,"Select Range","Enter the range of particle values as first-last (inclusive). Merges with existing selection.") if rng[1]==False : return try: x0,x1=rng[0].split("-") x0=int(x0) x1=int(x1)+1 except: QtGui.QMessageBox.warning(self,"Error !","Invalid range specified. Use: min-max") return self.vclasses.subset_set(range(x0,x1)) def selInvertClasses(self,x): "Inverts the current selection set" self.vclasses.invert_set() def sel3DClasses(self,x): "Select a range of images based on those used in a 3-D reconstruction associated with this classes file. Removes current selection first." f=self.curFile() if not '#classes_' in f : QtGui.QMessageBox.warning(self,"Error !","A classes_xx file from a refine_xx directory is not currently selected") return # construct the path to the threed_xx file num=f.split("_")[-1] pre=f.split("#")[0] d3path="%s#threed_%s"%(pre,num) try: a=EMData(d3path,0,True) goodptcl=a["threed_ptcl_idxs"] except: QtGui.QMessageBox.warning(self,"Error !","Cannot read classes from "+d3path) return self.vclasses.clear_set() self.vclasses.subset_set(goodptcl) def ptclChange(self,value): "Called when a change of particle data file occurs to zero out the display" try: self.vgoodptcl.set_data(None) self.vbadptcl.set_data(None) except: pass def updateFiles(self): "Updates the list of classes files" subdir=sorted([i for i in os.listdir(e2getcwd()) if "r2d_" in i or "relion2d_" in i or "refine_" in i or "multi_" in i]) for d in subdir: try: dbs=os.listdir(d) except: continue dbs.sort() for db in dbs: if "classes_" in db or "allrefs_" in db : self.wfilesel.addItem("%s/%s"%(d,db)) for f in self.extrafiles: self.wfilesel.addItem(f) dbs=os.listdir("sets") dbs.sort() for db in dbs: self.wptclfile.addItem("sets/"+db) def curPtclIter(self,included=True,excluded=True): "This is a generator function which yields n (in self.curPtclFile()) for all particles associated with selected classes" for ci in self.curSet(): try : c=EMData(self.curFile(),ci,True) # read header for current class average if included : incl=c["class_ptcl_idxs"] if isinstance(incl,int) : incl=[incl] # This should not happen, but seems to sometimes for some reason for i in incl: yield(i) if excluded and c.has_attr("exc_class_ptcl_idxs"): excl=c["exc_class_ptcl_idxs"] if isinstance(excl,int) : excl=[excl] # This should not happen, but seems to sometimes for some reason for i in excl: yield(i) except: print "Problem with class %d (%s). Skipping"%(ci,self.curFile()) traceback.print_exc() continue def curFile(self): "return the currently selected file as a readable path" return str(self.wfilesel.item(self.wfilesel.currentRow()).text()) # text of the currently selected item def curSet(self): "return a set (integers) of the currently selected class-averages" return self.vclasses.get_set("evalptcl") def curPtclFile(self): "return the particle file associated with the currently selected classes file" return str(self.wptclfile.currentText()) # text of the currently selected item def fileUpdate(self): "Called when the user selects a file from the list or need to completely refresh display" QtGui.qApp.setOverrideCursor(Qt.BusyCursor) if self.vclasses==None : self.vclasses=EMImageMXWidget() self.vclasses.set_mouse_mode("App") QtCore.QObject.connect(self.vclasses,QtCore.SIGNAL("mx_image_selected"),self.classSelect) QtCore.QObject.connect(self.vclasses,QtCore.SIGNAL("mx_image_double"),self.classDouble) self.vclasses.set_title("Classes") # self.classes=EMData.read_images(self.curFile()) self.vclasses.set_data(self.curFile(),self.curFile()) # self.vclasses.set_single_active_set("selected") # This makes the 'set' representing the selected class-averages current self.vclasses.set_mouse_mode("App") self.vclasses.enable_set("evalptcl",[]) # This makes sure the particle file is in the list of choices and is selected try: ptclfile=EMData(self.curFile(),0,True)["class_ptcl_src"] i=self.wptclfile.findText(ptclfile) if i==-1 : self.wptclfile.insertItem(0,ptclfile) self.wptclfile.setCurrentIndex(0) else: self.wptclfile.setCurrentIndex(i) except: QtGui.QMessageBox.warning(self,"Error !","This image does not appear to be a class average. (No class_ptcl_src, etc.)") ptclfile="None" # Make sure our display widgets exist if self.vgoodptcl==None : self.vgoodptcl=EMImageMXWidget() self.vgoodptcl.set_title("Included Particles") if self.vbadptcl==None : self.vbadptcl=EMImageMXWidget() self.vbadptcl.set_title("Excluded Particles") self.vclasses.show() self.vgoodptcl.show() self.vbadptcl.show() QtGui.qApp.setOverrideCursor(Qt.ArrowCursor) def classSelect(self,event,lc): "Single clicked class particle. lc=(img#,x,y,image_dict)" QtGui.qApp.setOverrideCursor(Qt.BusyCursor) ptclfile=self.curPtclFile() try: ptclgood=lc[3]["class_ptcl_idxs"] self.vgoodptcl.set_data(EMData.read_images(ptclfile,ptclgood)) except: QtGui.QMessageBox.warning(self,"Error !","This image does not appear to be a class average. (No class_ptcl_src, etc.)") QtGui.qApp.setOverrideCursor(Qt.ArrowCursor) return try: ptclbad=lc[3]["exc_class_ptcl_idxs"] self.vbadptcl.set_data(EMData.read_images(ptclfile,ptclbad)) except: ptclbad=[] self.vbadptcl.set_data(None) self.vgoodptcl.show() self.vbadptcl.show() QtGui.qApp.setOverrideCursor(Qt.ArrowCursor) def classDouble(self,event,lc): self.vclasses.image_set_associate(lc[0],update_gl=True) def closeEvent(self,event): try : self.vclasses.commit_sets() self.vclasses.close() except: pass try : self.vgoodptcl.close() except: pass try : self.vbadptcl.close() except: pass QtGui.QWidget.closeEvent(self, event)
class GUIBoxer(QtGui.QWidget): def __init__(self,images,voltage=None,apix=None,cs=None,ac=10.0,box=512): """The 'new' e2boxer interface. """ try: from emimage2d import EMImage2DWidget except: print "Cannot import EMAN image GUI objects (EMImage2DWidget)" sys.exit(1) try: from emimagemx import EMImageMXWidget except: print "Cannot import EMAN image GUI objects (EMImageMXWidget)" sys.exit(1) try: from emplot2d import EMPlot2DWidget except: print "Cannot import EMAN plot GUI objects (is matplotlib installed?)" sys.exit(1) QtGui.QWidget.__init__(self,None) self.setWindowIcon(QtGui.QIcon(get_image_directory() + "ctf.png")) self.data=None self.curfilename = None self.defaultvoltage=voltage self.defaultapix=apix self.defaultcs=cs self.defaultac=ac self.wimage=EMImage2DWidget() self.wimage.setWindowTitle("Micrograph") self.wparticles=EMImageMXWidget() self.wparticles.setWindowTitle("Particles") #self.wfft=EMImage2DWidget() #self.wfft.setWindowTitle("e2evalimage - 2D FFT") #self.wplot=EMPlot2DWidget() #self.wplot.setWindowTitle("e2evalimage - Plot") self.wimage.connect(QtCore.SIGNAL("mousedown"),self.imgmousedown) self.wimage.connect(QtCore.SIGNAL("mousedrag"),self.imgmousedrag) self.wimage.connect(QtCore.SIGNAL("mouseup") ,self.imgmouseup) self.wparticles.connect(QtCore.SIGNAL("mousedown"),self.ptclmousedown) self.wparticles.connect(QtCore.SIGNAL("mousedrag"),self.ptclmousedrag) self.wparticles.connect(QtCore.SIGNAL("mouseup") ,self.ptclmouseup) self.wimage.mmode="app" self.wparticles.mmode="app" # This object is itself a widget we need to set up self.gbl = QtGui.QGridLayout(self) self.gbl.setMargin(8) self.gbl.setSpacing(6) # plot list and plot mode combobox self.setlist=e2ctf.MyListWidget(self) self.setlist.setSizePolicy(QtGui.QSizePolicy.Preferred,QtGui.QSizePolicy.Expanding) for i in images: self.setlist.addItem(i) self.gbl.addWidget(self.setlist,0,0,10,2) self.lboxmode=QtGui.QLabel("Mode:",self) self.gbl.addWidget(self.lboxmode,10,0) self.sboxmode=QtGui.QComboBox(self) self.sboxmode.addItem("Manual") self.sboxmode.addItem("Reference") self.sboxmode.setCurrentIndex(1) self.gbl.addWidget(self.sboxmode,10,1) self.lanmode=QtGui.QLabel("Annotate:",self) self.gbl.addWidget(self.lanmode,12,0) self.sanmode=QtGui.QComboBox(self) self.sanmode.addItem("Box") self.sanmode.addItem("Box+dot") self.sanmode.addItem("Circle") self.sanmode.addItem("None") self.gbl.addWidget(self.sanmode,12,1) self.sdefocus=ValSlider(self,(0,5),"Defocus:",0.0,90) self.gbl.addWidget(self.sdefocus,0,2,1,3) self.squality=ValSlider(self,(0,9),"Quality (0-9):",0,90) self.squality.setIntonly(True) self.gbl.addWidget(self.squality,6,2,1,3) self.brefit=QtGui.QPushButton("Autobox") self.gbl.addWidget(self.brefit,7,2) self.bclrauto=QtGui.QPushButton("Clear Auto") self.gbl.addWidget(self.bclrauto,7,3) self.bclrall=QtGui.QPushButton("Clear All") self.gbl.addWidget(self.bclrall,7,4) self.sapix=ValBox(self,(0,500),"A/pix:",1.0,90) if self.defaultapix!=None : self.sapix.setValue(self.defaultapix) self.gbl.addWidget(self.sapix,10,2) self.svoltage=ValBox(self,(0,500),"Voltage (kV):",200,90) if self.defaultvoltage!=None : self.svoltage.setValue(self.defaultvoltage) self.gbl.addWidget(self.svoltage,11,2) self.scs=ValBox(self,(0,5),"Cs (mm):",4.1,90) if self.defaultcs!=None : self.scs.setValue(self.defaultcs) self.gbl.addWidget(self.scs,12,2) self.sboxsize=ValBox(self,(0,500),"Box Size:",256,90) self.sboxsize.intonly=True self.gbl.addWidget(self.sboxsize,13,2) self.sptclsize=ValBox(self,(0,500),"Ptcl Size:",256,90) self.sptclsize.intonly=True self.gbl.addWidget(self.sptclsize,14,2) QtCore.QObject.connect(self.sdefocus, QtCore.SIGNAL("valueChanged"), self.newCTF) QtCore.QObject.connect(self.sapix, QtCore.SIGNAL("valueChanged"), self.newCTF) QtCore.QObject.connect(self.svoltage, QtCore.SIGNAL("valueChanged"), self.newCTF) QtCore.QObject.connect(self.scs, QtCore.SIGNAL("valueChanged"), self.newCTF) QtCore.QObject.connect(self.sboxsize, QtCore.SIGNAL("valueChanged"), self.newBox) # QtCore.QObject.connect(self.soversamp, QtCore.SIGNAL("valueChanged"), self.newBox) QtCore.QObject.connect(self.squality,QtCore.SIGNAL("valueChanged"),self.newQualityFactor) QtCore.QObject.connect(self.setlist,QtCore.SIGNAL("currentRowChanged(int)"),self.newSet) QtCore.QObject.connect(self.setlist,QtCore.SIGNAL("keypress"),self.listkey) QtCore.QObject.connect(self.sboxmode,QtCore.SIGNAL("currentIndexChanged(int)"),self.newBoxMode) self.resize(720,380) # figured these values out by printing the width and height in resize event ### This section is responsible for background updates self.busy=False self.needupdate=True self.needredisp=False self.procthread=None self.errors=None # used to communicate errors back from the reprocessing thread self.timer=QTimer() QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.timeOut) self.timer.start(100) self.setWindowTitle("e2boxer21 - Control Panel") self.wimage.show() self.wfft.show() self.wplot.show() E2loadappwin("e2boxer21","main",self) E2loadappwin("e2boxer21","image",self.wimage.qt_parent) E2loadappwin("e2boxer21","particles",self.wparticles.qt_parent) # self.recalc() def listkey(self,event): if event.key()>=Qt.Key_0 and event.key()<=Qt.Key_9 : q=int(event.key())-Qt.Key_0 self.squality.setValue(q) #elif event.key() == Qt.Key_Left: #self.sdefocus.setValue(self.sdefocus.getValue()-0.03) #elif event.key() == Qt.Key_Right: #self.sdefocus.setValue(self.sdefocus.getValue()+0.03) #elif event.key()==Qt.Key_I : #self.doImport() #elif event.key()==Qt.Key_U : #self.unImport() def closeEvent(self,event): # QtGui.QWidget.closeEvent(self,event) E2saveappwin("e2evalimage","main",self) E2saveappwin("e2evalimage","image",self.wimage.qt_parent) E2saveappwin("e2evalimage","particles",self.wparticles.qt_parent) #self.writeCurParm() event.accept() QtGui.qApp.exit(0) #app=QtGui.qApp #if self.wimage != None: #app.close_specific(self.wimage) #self.wimage = None #if self.wfft != None: #app.close_specific(self.wfft) #if self.wplot != None: #app.close_specific(self.wplot) #app.close_specific(self) # self.emit(QtCore.SIGNAL("module_closed")) # this signal is important when e2ctf is being used by a program running its own event loop def update_plot(self): # if self.wplot == None: return # it's closed/not visible if self.incalc : return # no plot updates during a recomputation parms=self.parms[self.curset] apix=self.sapix.getValue() ds=1.0/(apix*parms[0]*parms[5]) ctf=parms[1] bg1d=array(ctf.background) r=len(ctf.background) s=arange(0,ds*r,ds) # This updates the FFT CTF-zero circles if self.f2danmode==0 : fit=ctf.compute_1d(len(s)*2,ds,Ctf.CtfType.CTF_AMP) shp={} nz=0 for i in range(1,len(fit)): if fit[i-1]*fit[i]<=0.0: nz+=1 shp["z%d"%i]=EMShape(("circle",0.0,0.0,1.0/nz,r,r,i,1.0)) self.wfft.del_shapes() self.wfft.add_shapes(shp) self.wfft.updateGL() # Single measurement circle mode elif self.f2danmode==1 : self.wfft.del_shapes() if self.ringrad==0: self.ringrad=1.0 self.wfft.add_shape("ring",EMShape(("circle",0.2,1.0,0.2,r,r,self.ringrad,1.0))) self.wfft.add_shape("ringlbl",EMShape(("scrlabel",0.2,1.0,0.2,10,10,"r=%d pix -> 1/%1.2f 1/A (%1.4f)"%(self.ringrad,1.0/(self.ringrad*ds),self.ringrad*ds),24.0,2.0))) self.wfft.updateGL() # 2-D Crystal mode elif self.f2danmode==2 : shp={} for a in range(-5,6): for b in range(-5,6): shp["m%d%d"%(a,b)]=EMShape(("circle",1.0,0.0,0.0,a*self.xpos1[0]+b*self.xpos2[0]+self.fft["nx"]/2-1,a*self.xpos1[1]+b*self.xpos2[1]+self.fft["ny"]/2,3,1.0)) self.wfft.del_shapes() self.wfft.add_shapes(shp) self.wfft.add_shape("xtllbl",EMShape(("scrlabel",1.0,0.3,0.3,10,10,"Unit Cell: %1.2f,%1.2f"%(1.0/(hypot(*self.xpos1)*ds),1.0/(hypot(*self.xpos2)*ds)),60.0,2.0))) # except: pass self.wfft.updateGL() else: self.wfft.del_shapes() self.wfft.updateGL() # Now update the plots for the correct plot mode if self.plotmode==0: try: bgsub=self.fft1d-bg1d except: print "Error computing bgsub on this image" return self.wplot.set_data((s,bgsub),"fg-bg",quiet=True,color=0) fit=array(ctf.compute_1d(len(s)*2,ds,Ctf.CtfType.CTF_AMP)) # The fit curve fit=fit*fit # squared # auto-amplitude for b-factor adjustment rto,nrto=0,0 for i in range(int(.04/ds)+1,min(int(0.15/ds),len(s)-1)): if bgsub[i]>0 : rto+=fit[i] nrto+=fabs(bgsub[i]) if nrto==0 : rto=1.0 else : rto/=nrto fit=[fit[i]/rto for i in range(len(s))] # print ctf_cmp((self.sdefocus.value,self.sbfactor.value,rto),(ctf,bgsub,int(.04/ds)+1,min(int(0.15/ds),len(s)-1),ds,self.sdefocus.value)) self.wplot.set_data((s,fit),"fit",color=1) self.wplot.setAxisParms("s (1/"+ "$\AA$" +")","Intensity (a.u)") elif self.plotmode==1: self.wplot.set_data((s[1:],self.fft1d[1:]),"fg",quiet=True,color=1) self.wplot.set_data((s[1:],bg1d[1:]),"bg",color=0) self.wplot.setAxisParms("s (1/"+ "$\AA$" +")","Intensity (a.u)") elif self.plotmode==2: if self.fft1dang==None: self.recalc_real() bgsub=self.fft1d-bg1d bgsuba=[array(self.fft1dang[i])-bg1d for i in xrange(4)] # Write the current image parameters to the database # for i in xrange(4): bgsuba[i][0]=0 self.wplot.set_data((s,bgsub),"fg",quiet=True,color=0) self.wplot.set_data((s[3:],bgsuba[0][3:]),"fg 0-45",quiet=True,color=2) self.wplot.set_data((s[3:],bgsuba[1][3:]),"fg 45-90",quiet=True,color=3) self.wplot.set_data((s[3:],bgsuba[2][3:]),"fg 90-135",quiet=True,color=4) self.wplot.set_data((s[3:],bgsuba[3][3:]),"fg 135-180",quiet=True,color=6) fit=array(ctf.compute_1d(len(s)*2,ds,Ctf.CtfType.CTF_AMP)) # The fit curve fit=fit*fit # squared # auto-amplitude for b-factor adjustment rto,nrto=0,0 for i in range(int(.04/ds)+1,min(int(0.15/ds),len(s)-1)): if bgsub[i]>0 : rto+=fit[i] nrto+=fabs(bgsub[i]) if nrto==0 : rto=1.0 else : rto/=nrto fit/=rto self.wplot.set_data((s,fit),"fit",color=1) self.wplot.setAxisParms("s (1/"+ "$\AA$" + ")","Intensity (a.u)") elif self.plotmode==3: if self.fft1dang==None: self.recalc_real() #bgsub=self.fft1d-bg1d #bgsuba=[array(self.fft1dang[i])-bg1d for i in xrange(4)] fg=self.fft1d fga=[array(self.fft1dang[i]) for i in xrange(4)] for i in xrange(4): fga[i][0]=0 self.wplot.set_data((s,fg),"fg",quiet=True,color=0) self.wplot.set_data((s,fga[0]),"fg 0-45",quiet=True,color=2) self.wplot.set_data((s,fga[1]),"fg 45-90",quiet=True,color=3) self.wplot.set_data((s,fga[2]),"fg 90-135",quiet=True,color=4) self.wplot.set_data((s,fga[3]),"fg 135-180",quiet=True,color=6) #fit=array(ctf.compute_1d(len(s)*2,ds,Ctf.CtfType.CTF_AMP)) # The fit curve #fit=fit*fit # squared ## auto-amplitude for b-factor adjustment #rto,nrto=0,0 #for i in range(int(.04/ds)+1,min(int(0.15/ds),len(s)-1)): #if bgsub[i]>0 : #rto+=fit[i] #nrto+=fabs(bgsub[i]) #if nrto==0 : rto=1.0 #else : rto/=nrto #fit/=rto #self.wplot.set_data((s,fit),"fit",color=1) #self.wplot.setAxisParms("s (1/"+ "$\AA$" + ")","Intensity (a.u)") if self.plotmode==4: if min(bg1d)<=0.0 : bg1d+=min(bg1d)+max(bg1d)/10000.0 ssnr=(self.fft1d-bg1d)/bg1d self.wplot.set_data((s,ssnr),"SSNR",quiet=True,color=0) #fit=array(ctf.compute_1d(len(s)*2,ds,Ctf.CtfType.CTF_AMP)) # The fit curve #fit=fit*fit # squared ## auto-amplitude for b-factor adjustment #rto,nrto=0,0 #for i in range(int(.04/ds)+1,min(int(0.15/ds),len(s)-1)): #if bgsub[i]>0 : #rto+=fit[i] #nrto+=fabs(bgsub[i]) #if nrto==0 : rto=1.0 #else : rto/=nrto #fit=[fit[i]/rto for i in range(len(s))] ## print ctf_cmp((self.sdefocus.value,self.sbfactor.value,rto),(ctf,bgsub,int(.04/ds)+1,min(int(0.15/ds),len(s)-1),ds,self.sdefocus.value)) #self.wplot.set_data((s,fit),"fit",color=1) self.wplot.setAxisParms("s (1/"+ "$\AA$" + ")","Est. SSNR") def timeOut(self): if self.busy : return # Redisplay before spawning thread for more interactive display if self.needredisp : try: self.redisplay() except: pass # Spawn a thread to reprocess the data if self.needupdate and self.procthread==None: self.procthread=threading.Thread(target=self.recalc_real) self.procthread.start() if self.errors: QtGui.QMessageBox.warning(None,"Error","The following processors encountered errors during processing of 1 or more images:"+"\n".join(self.errors)) self.errors=None def doRefit(self): parms=self.parms[self.curset] apix=self.sapix.getValue() ds=1.0/(apix*parms[0]*parms[5]) try: parms[1]=e2ctf.ctf_fit(self.fft1d,parms[1].background,parms[1].background,self.fft,self.fftbg,parms[1].voltage,parms[1].cs,parms[1].ampcont,apix,bgadj=False,autohp=True,verbose=1) except: print "CTF Autofit Failed" traceback.print_exc() parms[1].defocus=1.0 self.sdefocus.setValue(parms[1].defocus,True) self.sbfactor.setValue(parms[1].bfactor,True) self.sampcont.setValue(parms[1].ampcont,True) self.update_plot() def unImport(self,val=None): print "unimport ",base_name(self.setlist.item(self.curset).text()) item=base_name(self.setlist.item(self.curset).text()) try: os.unlink("micrographs/%s.hdf"%item) except: print "Couldn't delete micrographs/%s.hdf"%item def doImport(self,val=None): """Imports the currently selected image into a project""" print "import ",base_name(self.setlist.item(self.curset).text()) # This is just the (presumably) unique portion of the filename item=base_name(self.setlist.item(self.curset).text()) # create directory if necessary if not os.access("micrographs",os.R_OK) : try : os.mkdir("micrographs") except: QtGui.QMessageBox.warning(self,"Error !","Cannot create micrographs directory") return #db=db_open_dict("bdb:micrographs#%s"%item) self.data["ctf"]=self.parms[self.curset][1] if self.cinvert.getValue()!=0 : self.data.mult(-1) if self.cxray.getValue() : self.data.process_inplace("threshold.clampminmax.nsigma",{"nsigma":4,"tomean":1}) self.data.write_image("micrographs/%s.hdf"%item) self.writeCurParm() # js_open_dict(info_name(item))["ctf"]=[self.parms[val][1],None,None,None,None] # db_parms=db_open_dict("bdb:e2ctf.parms") # db_parms[item]=[self.parms[val][1].to_string(),self.fft1d,self.parms[val][1].background,self.parms[val][4]] def writeCurParm(self): "Called to store the current parameters for this image to the frameparms database" parms=self.parms[self.curset] js=js_open_dict(info_name(self.curfilename)) js.setval("ctf_frame",parms,True) js.setval("quality",parms[4]) # db_fparms=db_open_dict("bdb:e2ctf.frameparms") # curtag=item_name(str(self.setlist.item(self.curset).text())) # db_fparms[curtag]=self.parms[self.curset] def newSet(self,val): "called when a new data set is selected from the list" # Write the current image parameters to the database if val!=self.curset : self.writeCurParm() # now set the new item self.curset=val # This deals with Z stacks and multi image files fsp=str(self.setlist.item(val).text()) if "," in fsp : fsp,n=fsp.split(",") self.data=EMData(fsp,int(n)) # read the image from disk elif ";" in fsp : fsp,n=fsp.split(";") hdr=EMData(fsp,0,True) self.data=EMData(fsp,0,False,Region(0,0,int(n),hdr["nx"],hdr["ny"],1)) # read the image from disk else : self.data=EMData(fsp,0) # read the image from disk self.wimage.setWindowTitle("e2evalimage - " + fsp.split("/")[-1]) self.wfft.setWindowTitle("e2evalimage - 2D FFT - "+fsp.split("/")[-1]) self.wplot.setWindowTitle("e2evalimage - Plot - "+fsp.split("/")[-1]) if self.defaultapix!=None : self.data["apix_x"]=self.defaultapix self.wimage.set_data(self.data) self.curfilename = str(self.setlist.item(val).text()) ctf=self.parms[val][1] # if voltage is 0, we need to initialize if ctf.voltage==0: try: ctf.voltage=self.data["microscope_voltage"] except: pass if ctf.voltage==0 : ctf.voltage=self.defaultvoltage try: ctf.cs=self.data["microscope_cs"] except: pass if ctf.cs==0 : ctf.cs=self.defaultcs ctf.apix=self.data["apix_x"] ctf.defocus=0.0 #triggers fitting ctf.bfactor=200.0 ctf.ampcont=self.defaultac self.sdefocus.setValue(ctf.defocus,True) self.sbfactor.setValue(ctf.bfactor,True) self.sapix.setValue(ctf.apix,True) self.sampcont.setValue(ctf.ampcont,True) self.svoltage.setValue(ctf.voltage,True) self.scs.setValue(ctf.cs,True) self.sboxsize.setValue(self.parms[val][0],True) self.squality.setValue(self.parms[val][4],True) #if self.guiim != None: ## print self.data #self.guiim.set_data(self.data[val][4]) #if self.guiiminit: #self.guiim.optimally_resize() #self.guiiminit = False #self.guiim.updateGL() self.recalc() def recalc(self): self.needupdate=True def recalc_real(self): "Called to recompute the power spectra, also updates plot" self.needupdate=False if self.data==None : self.procthread=None return self.incalc=True # to avoid incorrect plot updates # To simplify expressions parms=self.parms[self.curset] apix=self.sapix.getValue() if len(parms)==5 : parms.append(1) # for old projects where there was no oversampling specification else: parms[5]=max(1,int(parms[5])) ds=1.0/(apix*parms[0]*parms[5]) # Mode where user drags the box around the parent image if self.calcmode==0: # extract the data and do an fft clip=self.data.get_clip(Region(parms[2][0],parms[2][1],parms[0],parms[0])) clip.process_inplace("normalize.edgemean") if parms[5]>1 : clip=clip.get_clip(Region(0,0,parms[0]*parms[5],parms[0]*parms[5])) # since we aren't using phases, doesn't matter if we center it or not self.fft=clip.do_fft() # self.fft.mult(1.0/parms[0]**2) self.fft.mult(1.0/parms[0]) # mode where user selects/deselcts tiled image set elif self.calcmode==1: # update the box display on the image nx=self.data["nx"]/parms[0]-1 self.fft=None nbx=0 for x in range(nx): for y in range(self.data["ny"]/parms[0]-1): # User deselected this one if int(x+y*nx) in parms[3] : continue # read the data and make the FFT clip=self.data.get_clip(Region(x*parms[0]+parms[0]/2,y*parms[0]+parms[0]/2,parms[0],parms[0])) clip.process_inplace("normalize.edgemean") if parms[5]>1 : clip=clip.get_clip(Region(0,0,parms[0]*parms[5],parms[0]*parms[5])) # since we aren't using phases, doesn't matter if we center it or not fft=clip.do_fft() # fft.mult(parms[0]) fft.ri2inten() if self.fft==None: self.fft=fft else: self.fft+=fft nbx+=1 self.fft.mult(1.0/(nbx*parms[0]**2)) self.fft.process_inplace("math.sqrt") self.fft["is_intensity"]=0 # These 2 steps are done so the 2-D display of the FFT looks better. Things would still work properly in 1-D without it # self.fft.mult(1.0/(nbx*parms[0]**2)) self.fftbg=self.fft.process("math.nonconvex") self.fft1d=self.fft.calc_radial_dist(self.fft.get_ysize()/2,0.0,1.0,1) # note that this handles the ri2inten averages properly if self.plotmode==2 or self.plotmode==3: self.fft1dang=array(self.fft.calc_radial_dist(self.fft.get_ysize()/2,0.0,1.0,4,self.sang45.getValue()*.017453292,1)) # This form generates 4 sequential power spectra representing angular ranges self.fft1dang=self.fft1dang.reshape((4,self.fft.get_ysize()/2)) else: self.fft1dang=None # Compute 1-D curve and background bg_1d=e2ctf.low_bg_curve(self.fft1d,ds) parms[1].background=bg_1d parms[1].dsbg=ds self.fft1d=array(self.fft1d) self.needredisp=True self.incalc=False time.sleep(.2) # help make sure update has a chance self.procthread=None # dbquality = self.db[os.path.basename(self.curfilename)] # print dbquality # item=item_name(self.curfilename) # db=db_open_dict("bdb:e2ctf.parms") # if db[item]==None or db[item[3]]==None : db[item]=[parms[1].to_string(),self.fft1d,parms[1].background,5] # # print item,db[item][3] # try: self.squality.setValue(int(db[item[3]])) # except: self.squality.setValue(5) def redisplay(self): if self.incalc: return self.needredisp=False self.busy=True parms=self.parms[self.curset] apix=self.sapix.getValue() ds=1.0/(apix*parms[0]*parms[5]) # Fitting not done yet. Need to make 2D background somehow if parms[1].defocus==0: self.doRefit() self.wimage.show() self.wfft.show() self.wplot.show() self.update_plot() # To simplify expressions if self.calcmode==0: # update the box display on the image self.wimage.del_shapes() self.wimage.add_shape("box",EMShape(("rect",.3,.9,.3,parms[2][0],parms[2][1],parms[2][0]+parms[0],parms[2][1]+parms[0],1))) self.wimage.updateGL() elif self.calcmode==1: # update the box display on the image nx=self.data["nx"]/parms[0]-1 shp={} for x in range(nx): for y in range(self.data["ny"]/parms[0]-1): # User deselected this one if int(x+y*nx) in parms[3] : continue # Make a shape for this box shp["box%02d%02d"%(x,y)]=EMShape(("rect",.3,.9,.3,(x+.5)*parms[0],(y+.5)*parms[0],(x+1.5)*parms[0],(y+1.5)*parms[0],1)) self.wimage.del_shapes() self.wimage.add_shapes(shp) self.wimage.updateGL() if self.f2dmode>0 : if self.f2dmode==1 : self.wfft.set_data(self.fft-self.fftbg) else : self.wfft.set_data(self.fftbg) else : self.wfft.set_data(self.fft) self.busy=False def newCalcMode(self,mode): self.calcmode=mode self.recalc() def new2DMode(self,mode): self.f2dmode=mode self.recalc() def new2DAnMode(self,mode): self.f2danmode=mode self.needredisp=True def newPlotMode(self,mode): self.plotmode=mode self.wplot.set_data(None,replace=True,quiet=True) # clear the data so plots are properly redisplayed, but don't update the display self.needredisp=True def newBox(self): parms=self.parms[self.curset] parms[0]=self.sboxsize.value # parms[5]=self.soversamp.value parms[5]=1 parms[3]=set() self.recalc() def newQualityFactor(self): parms=self.parms[self.curset] parms[4]=self.squality.value def newCTF(self) : parms=self.parms[self.curset] parms[1].defocus=self.sdefocus.value parms[1].bfactor=self.sbfactor.value parms[1].dfdiff=self.sdfdiff.value parms[1].dfang=self.sdfang.value parms[1].apix=self.sapix.value parms[1].ampcont=self.sampcont.value parms[1].voltage=self.svoltage.value parms[1].cs=self.scs.value self.needredisp=True def imgmousedown(self,event) : if self.calcmode==0: m=self.wimage.scr_to_img((event.x(),event.y())) parms=self.parms[self.curset] parms[2]=(m[0]-parms[0]/2,m[1]-parms[0]/2) self.recalc() self.needredisp=True #self.guiim.add_shape("cen",["rect",.9,.9,.4,x0,y0,x0+2,y0+2,1.0]) def imgmousedrag(self,event) : if self.calcmode==0: m=self.wimage.scr_to_img((event.x(),event.y())) parms=self.parms[self.curset] parms[2]=(m[0]-parms[0]/2,m[1]-parms[0]/2) self.needredisp=True self.recalc() # box deletion when shift held down #if event.modifiers()&Qt.ShiftModifier: #for i,j in enumerate(self.boxes): def imgmouseup(self,event) : m=self.wimage.scr_to_img((event.x(),event.y())) if self.calcmode==1: parms=self.parms[self.curset] nx=self.data["nx"]/parms[0]-1 grid=int((m[0]-parms[0]/2)/parms[0])+int((m[1]-parms[0]/2)/parms[0])*nx if grid in parms[3] : parms[3].remove(grid) else: parms[3].add(grid) self.needredisp=True self.recalc() def fftmousedown(self,event,m) : #m=self.wfft.scr_to_img((event.x(),event.y())) if self.f2danmode==1: self.ringrad=hypot(m[0]-self.fft["nx"]/2,m[1]-self.fft["ny"]/2) self.needredisp=True elif self.f2danmode==2: if (event.modifiers()&Qt.ControlModifier): self.xpos2=((m[0]-self.fft["nx"]/2)/3.0,(m[1]-self.fft["ny"]/2)/3.0) else: self.xpos1=((m[0]-self.fft["nx"]/2)/3.0,(m[1]-self.fft["ny"]/2)/3.0) self.needredisp=True #self.guiim.add_shape("cen",["rect",.9,.9,.4,x0,y0,x0+2,y0+2,1.0]) def fftmousedrag(self,event,m) : #m=self.wfft.scr_to_img((event.x(),event.y())) if self.f2danmode==1: self.ringrad=hypot(m[0]-self.fft["nx"]/2,m[1]-self.fft["ny"]/2) self.needredisp=True elif self.f2danmode==2: if (event.modifiers()&Qt.ControlModifier): self.xpos2=((m[0]-self.fft["nx"]/2)/3.0,(m[1]-self.fft["ny"]/2)/3.0) else: self.xpos1=((m[0]-self.fft["nx"]/2)/3.0,(m[1]-self.fft["ny"]/2)/3.0) self.needredisp=True # box deletion when shift held down #if event.modifiers()&Qt.ShiftModifier: #for i,j in enumerate(self.boxes): def fftmouseup(self,event,m) : "up" #m=self.wfft.scr_to_img((event.x(),event.y())) def plotmousedown(self,event) : "mousedown in plot"