Package reflectometry :: Package model1d :: Package profileview :: Module reflInteractor

Source Code for Module reflectometry.model1d.profileview.reflInteractor

  1  """ 
  2  Reflectometry profile interactor. 
  3  """ 
  4   
  5  from matplotlib import transforms 
  6   
  7  from reflutils import twinx, interface_color, disable_color, active_color, \ 
  8                        rho_color, mu_color, phi_color, theta_color, title_color 
  9   
 10  from binder              import BindArtist 
 11  from layerInteractor     import Interactor 
 12  from interfaceInteractor import InterfaceInteractor 
 13  from roughnessInteractor import RoughnessInteractor 
 14  from listener   import Listener 
 15  from fit        import Fit 
 16   
 17  # ================== Main profile interactor ===================== 
18 -class ReflectometryInteractor:
19 """ 20 Reflectometry profile editor 21 """
22 - def __init__(self, 23 ax, 24 model, 25 listener, 26 parent 27 ):
28 self.listener= listener 29 self.ax = ax 30 self.parent = parent 31 self.customTitle = parent.get_title() 32 if self.customTitle == None: 33 self.customTitle = r"customerTitle" 34 35 # Theta needs a separate axis, we put these two axes into a figure 36 if model.magnetic: 37 self.ax2 = twinx( self.ax ) 38 else: 39 self.ax2 = None 40 41 # Draw title 42 self.title_text = None 43 self.set_title( self.customTitle ) 44 45 self.ax.set_xlabel( r'$\rm{z}\ (\AA)$' ) 46 if model.magnetic: 47 self.ax.set_ylabel( r'$\rm{Density}\ \times 10^{-6}\ \ \rho,\ \mu,\ \rho_M$') 48 else: 49 self.ax.set_ylabel(r'$\rm{Density}\ \times 10^{-6}\ \ \rho,\ \mu$') 50 51 if model.magnetic: 52 self.ax2.set_ylabel(r'$\rm{Magnetic\ Angle\ (\ ^\circ)}$') 53 54 # TODO: the connect mechanism needs to be owned by the canvas rather 55 # than the axes --- cannot have multiple profiles on the same canvas 56 # until connect is in the right place. 57 58 59 self.connect = BindArtist( ax.figure ) 60 61 # Clear connections to all artists. 62 self.connect.clearall() 63 64 65 self.connect('motion', ax, self.onMotion ) 66 self.connect('click', ax.figure, self.onContext) 67 68 # ax.figure.canvas.mpl_connect('motion_notify_event',self.onMotion) 69 70 # Add model 71 self.model = model 72 73 # Add interactor for Interface 74 self.interface = InterfaceInteractor(self,ax) 75 76 # Add interactor for Roughness 77 self.roughness = RoughnessInteractor(self,ax) 78 79 self.profiles = [] 80 self.layernum = None 81 self.axes_frozen = False 82 83 self._showRho = True 84 self._showMu = True 85 self._showPhi = True 86 self._showTheta = True 87 self._showDepth = True 88 89 # Add some plots 90 [self.hrho] = ax.plot([],[],'-',color=rho_color,label=r'$\rho$') 91 [self.hmu ] = ax.plot([],[],'-',color=mu_color, label=r'$\mu$' ) 92 93 # More plots in magnetic case 94 if self.model.magnetic: 95 [self.hP ] = self.ax.plot( [], [], '-', color=phi_color, 96 label = r'$\rho_M$') 97 [self.htheta] = self.ax2.plot( [], [], '-', color=theta_color, 98 label = r'$\theta_M$') 99 100 # Show Legend ? 101 if self.parent.modelPanel.IsShowLegend(): 102 self.ShowLegend(show=True) 103 104 # update the figure 105 self.update()
106 107 108
109 - def ShowRho(self, show=True, update=False):
110 self._showRho = show 111 if update: 112 self.update()
113
114 - def ShowMu(self, show=True, update=False):
115 self._showMu = show 116 if update: 117 self.update()
118
119 - def ShowPhi(self, show=True, update=False):
120 self._showPhi = show 121 if update: 122 self.update()
123
124 - def ShowTheta(self, show=True, update=False):
125 self._showTheta = show 126 if update: 127 self.update()
128
129 - def ShowDepth(self, show=True, update=False):
130 self._showDepth = show 131 if update: 132 self.update()
133 134
135 - def ShowLegend(self, show=True, update=False):
136 if show: 137 if self.model.magnetic: 138 self.hlegend = self.ax.legend( 139 (self.hrho, self.hmu, self.hP, self.htheta), 140 #('SLD','Absorption','Mag. SLD','Mag. angle'), 141 (r'$\rho$', r'$\mu$', r'$\rho_M$', r'$\theta_M$'), 142 loc = (0.85,0.5) 143 #loc='upper right' 144 ) 145 else: 146 self.hlegend = self.ax.legend( (self.hrho, self.hmu), 147 (r'$\rho$', r'$\mu$'), 148 loc = (0.85,0.5) 149 #loc='upper right' 150 ) 151 152 self.hlegend.get_frame().set( alpha=0.2, facecolor='yellow' ) 153 else: 154 del self.hlegend 155 self.ax.legend_=None 156 157 if update: 158 self.update()
159 160
161 - def onMotion(self, event):
162 """Respond to motion events by changing the active layer.""" 163 # Find the layer containing the event.xdata 164 Layer_num = self.model.find(event.xdata) 165 166 self.parent.modelPanel.update(Layer_num) 167 168 self.set_layer( Layer_num ) 169 170 return False
171 172
173 - def onContext(self, ev):
174 """Context menu (eventually ...).""" 175 return False
176 177
178 - def get_title(self):
179 return self.customTitle
180 181
182 - def set_title(self, title=None):
183 self.customTitle = title 184 if title != None: 185 if self.title_text != None: 186 self.title_text.remove() 187 self.title_text=self.ax.text(-0.1, 1.05, 188 str(title), 189 transform=self.ax.transAxes, 190 ha='left', 191 va='bottom', 192 fontsize=12, 193 color=title_color 194 ) 195 196 self.parent.set_title( title )
197 198 199
200 - def set_layer(self, n):
201 """Make layer n the active layer.""" 202 # Check if the markers are already set 203 if n == self.layernum: 204 return 205 self.layernum = n 206 207 #self.interface.refresh() #FZW 208 209 # Clear the old markers 210 for interactor in self.profiles: 211 interactor.clear_markers() 212 213 # Reset the profile interactors to those appropriate for the layer type 214 if self.model.magnetic: 215 axes = [self.ax]*3 + [self.ax2] # ax ax ax ax2 216 else: #nonmagnetic case 217 axes = [self.ax]*2 218 219 profile_colors = [rho_color, mu_color, phi_color, theta_color] 220 profile_pars = ["rho", "mu", "phi", "theta" ] 221 self.profiles = [ Interactor(self,ax,L,p, color=c) 222 for ax,c,p, L in zip(axes, 223 profile_colors, 224 profile_pars, 225 self.model[n]) 226 ] 227 # Rho 228 if self._showRho: 229 self.profiles[0].set_layer(n) 230 else: 231 self.profiles[0].set_layer(n, False) 232 233 # Mu 234 if self._showMu: 235 self.profiles[1].set_layer(n) # mu 236 else: 237 self.profiles[1].set_layer(n, False) # 238 239 if self.model.magnetic: 240 # Phi 241 if self._showPhi: 242 self.profiles[2].set_layer(n) 243 else: 244 self.profiles[2].set_layer(n, False) 245 246 # Theta 247 if self._showTheta: 248 self.profiles[3].set_layer(n) 249 else: 250 self.profiles[3].set_layer(n, False) 251 252 253 # Move the roughness markers for the interface 254 self.roughness.set_layer(n) 255 #self.ylim = 0, 100 256 257 258 self.draw()
259 260
261 - def update(self):
262 """ 263 Respond to changes in the model by recalculating the profiles and 264 resetting the widgets. 265 """ 266 # We are done the manipulation; let the model send its update signal 267 # to whomever is listening. 268 self.listener.signal('update',self) 269 270 # Update locations 271 self.model.calc_offsets() 272 #for interactor in self.profiles: 273 # interactor.update() 274 275 if len(self.profiles)>0: 276 # Rhi 277 if self._showRho: 278 self.profiles[0].update() 279 else: 280 self.profiles[0].update(False) 281 282 # Mu 283 if self._showMu: 284 self.profiles[1].update() 285 else: 286 self.profiles[1].update(False) 287 288 289 if self.model.magnetic: 290 # Phi 291 if self._showPhi: 292 self.profiles[2].update() 293 else: 294 self.profiles[2].update(False) 295 296 # Theta 297 if self._showTheta: 298 self.profiles[3].update() 299 else: 300 self.profiles[3].update(False) 301 302 if self._showDepth: 303 self.interface.update() 304 else: 305 self.interface.update(False) 306 307 self.roughness.update() 308 309 # Update profile 310 z,p = self.model.calc(n=200) 311 # update rho 312 self.hrho.set_data(z,p[0]) 313 if self._showRho: 314 self.hrho.set_visible(True) 315 else: 316 self.hrho.set_visible(False) 317 318 # update mu 319 self.hmu.set_data(z,p[1]) 320 if self._showMu: 321 self.hmu.set_visible(True) 322 else: 323 self.hmu.set_visible(False) 324 325 if self.model.magnetic: 326 # update phi 327 self.hP.set_data(z,p[2]) 328 if self._showPhi: 329 self.hP.set_visible(True) 330 else: 331 self.hP.set_visible(False) 332 333 # update theta 334 self.htheta.set_data(z,p[3]) 335 if self._showTheta: 336 self.htheta.set_visible(True) 337 else: 338 self.htheta.set_visible(False) 339 340 341 # Compute automatic y limits 342 # Note: theta limits are on ax2 343 344 # The ylim of marker for spline layer, etc 345 m = self.model.calcMarker() 346 347 if self.model.magnetic: 348 lo = min( p[0].min(), p[1].min(), p[2].min(), m[0] ) 349 hi = max( p[0].max(), p[1].max(), p[2].max(), m[1] ) 350 fluff = 0.1*(hi-lo) 351 self.ylim = lo-fluff, hi+fluff 352 else: 353 lo = min( p[0].min(), p[1].min(), m[0] ) 354 hi = max( p[0].max(), p[1].max(), m[1] ) 355 fluff = 0.05*(hi-lo) 356 self.ylim = lo-fluff, hi+fluff 357 358 self.ax.set_ylim(lo-fluff, hi+fluff) 359 360 # Compute reflectivity 361 self.draw()
362 363
364 - def freeze_axes(self):
365 self.axes_frozen = True
366 367
368 - def thaw_axes(self):
369 self.axes_frozen = False
370 371
372 - def draw(self):
373 """Set the limits and tell the canvas to render itself.""" 374 # TODO: Stop doing surprising things with limits 375 # TODO: Detect if user is zoomed, and freeze limits if that is the case 376 377 if not self.axes_frozen: 378 self.ax.set_xlim(self.model.offset[0 ], 379 self.model.offset[-1] 380 ) 381 self.ax.set_ylim(*self.ylim) 382 if self.model.magnetic: 383 self.ax2.set_ylim(0,360) 384 385 self.ax.figure.canvas.draw_idle()
386 387 388 389 390 # ================ Example program ===========================
391 -def demo():
392 from reflectometry.model1d import Profile 393 import pylab 394 # Names for the layers, including incident medium and substrate 395 names = [ r"Si", r"Fe_2O_3", r"Fe", r"Thiol", r"D_2O" ] 396 397 # Depths for the layers, excluding incident medium and substrate 398 d = [100, 120, 180] 399 400 # Profile definitions 401 rho = [2.07, 3, 8, -1, 5.76] 402 mu = [0, 0, 2, 0, 1] 403 P = [0, 0, 5, 0, 0] 404 theta = [0, 0, 270, 0, 0] 405 rough = [30,10,20,30] 406 407 model = Profile(depth=d, 408 rho=rho, 409 mu=mu, 410 phi=P, 411 theta=theta, 412 rough=rough, 413 names=names 414 ) 415 416 # Turn the model into a user interface 417 listener = Listener() 418 profile = ReflectometryInteractor(pylab.subplot(111), model, listener) 419 fit = Fit([profile]) 420 listener.connect("update",profile,fit.update) 421 pylab.show() 422 print "d2 = ",model.depth[2]
423 424 if __name__ == "__main__": demo() 425