1 """
2 Layer interactor.
3 """
4
5 import numpy
6 from reflectometry.model1d.model.layer import FlatLayer, SlopeLayer, \
7 SplineLayer, TetheredPolymerLayer, JoinLayer, NoLayer
8 from baseInteractor import BaseInteractor
9 from reflutils import flatlayer_pickradius, slopelayer_pickradius, \
10 splinelayer_pickradius, interface_pickradius
11
12
13
14
15
17 """
18 Abstract base class for the layer interactors.
19
20 Layers should define:
21 set_layer
22 move
23 save
24 restore
25 update
26 """
27 - def __init__(self,
28 base,
29 axes,
30 layer,
31 par,
32 color='black'
33 ):
40
43
57
58
60
61 ValidParNames = ["mu", "rho", "theta", "phi"]
62 name = label.split("[")[0].strip()
63
64 if name in ValidParNames:
65 return label
66 else:
67 return ""
68
69
71
72 try: idx = self.layerMarker.index(event.artist)
73 except: idx = None
74 return idx
75
76
78 """ Update the rho layer """
79 n = self._curr_n
80 self.infopanel.updateNLayer( n )
81
82 idx = self._lookupIndex( event )
83 self.infopanel.updateRhoValue( event.ydata, idx=idx )
84
85
87 """ Update the mu layer """
88 n = self._curr_n
89 self.infopanel.updateNLayer( n )
90
91 idx = self._lookupIndex( event )
92 self.infopanel.updateMuValue( event.ydata, idx=idx )
93
94
96 """ Update the phi layer """
97 n = self._curr_n
98 self.infopanel.updateNLayer( n )
99
100 idx = self._lookupIndex( event )
101 self.infopanel.updatePhiValue( event.ydata, idx=idx )
102
103
105
106 """ Update the theta layer """
107 n = self._curr_n
108 self.infopanel.updateNLayer( n )
109
110 idx = self._lookupIndex( event )
111 self.infopanel.updateThetaValue( event.ydata, idx=idx )
112
113
115
116 name = label.split("[")
117
118 if len(name) <= 1:
119 return True
120 else:
121 return False
122
123
125 idx = self._lookupIndex( event )
126 if idx==0: return self._save_depth_n +1
127 elif idx == self.getMarkerSize()-1: return self._save_depth_n
128 else: return self._save_n
129
130
132 if self.IsFlatLayer( event.artist.get_label() ):
133 return self._save_n
134 else:
135 return self._GetBestCurrLayerNum(event)
136
137
152
153
155 """ Show the rho layer """
156 n = self._curr_n
157 self.infopanel.updateNLayer( n )
158
159 idx = self._lookupIndex( event )
160 self.infopanel.showRhoValue( idx=idx )
161
162
164 """ show the mu layer """
165 n = self._curr_n
166 self.infopanel.updateNLayer( n )
167
168 idx = self._lookupIndex( event )
169 self.infopanel.showMuValue( idx=idx )
170
171
173 """ show the phi layer """
174 n = self._curr_n
175 self.infopanel.updateNLayer( n )
176
177 idx = self._lookupIndex( event )
178 self.infopanel.showPhiValue( idx=idx )
179
180
182 """ show the theta layer """
183 n = self._curr_n
184 self.infopanel.updateNLayer( n )
185
186 idx = self._lookupIndex( event )
187 self.infopanel.showThetaValue( idx=idx )
188
189
191 """ Update the layer value """
192 _pn = self.Artist2Name( event.artist.get_label() )
193
194 self._curr_n = self.getBestCurrLayerNum(event)
195
196 if len(_pn) > 0:
197
198 if _pn[:3] == "rho": self.showRhoValue( event)
199 elif _pn[:2] == "mu": self.showMuValue( event)
200 elif _pn[:3] == "phi": self.showPhiValue( event)
201 elif _pn[:5] == "theta": self.showThetaValue(event)
202 else:
203 raise ValueError("Invalid parmeter name")
204
205
206
208 filled_markers =[ 'o',
209 's',
210 'p',
211 'd',
212 'h',
213 '+',
214 'x',
215 'D',
216 'H',
217 'v',
218 '^',
219 '<',
220 '>',
221 '1',
222 '2',
223 '3',
224 '4',
225 ]
226 return filled_markers[ i%len(filled_markers) ]
227
228
229
230
231
233 """
234 Interactor for FlatLayer to handle flat slabs.
235 """
237 """
238 Setup the widgets required to edit layer n.
239 """
240 self.layernum = n
241 v = self.layer._val
242 ax = self.axes
243
244 self.layerMarker = ax.plot( [], [],
245 '--',
246 label = self.par,
247 linewidth = 2,
248 color = self.color,
249 pickradius = flatlayer_pickradius,
250 zorder = 5
251 )[0]
252 self.markers = [ self.layerMarker ]
253
254 self.connect_markers(self.markers)
255
256 self.update(show)
257
258
271
272
273 - def move(self, x, y, evt):
274 """
275 Update the model with the new widget position.
276 """
277 self.layer._val = y
278
279
280 - def save(self, evt):
281 """
282 Save the current state of the model represented by the widget.
283 """
284 self._saved_v = self.layer._val
285
286
288 """
289 Restore the widget and model to the saved state.
290 """
291 self.layer._val = self._saved_v
292
293
294
295
296
298 """
299 Interactor for SlopeLayer to handle the line control points.
300
301 For slope layer, we use 'p' marker
302 """
304 return len(self.layerMarker)
305
306
308 """
309 Setup the widgets required to edit layer n.
310 """
311 self.layernum = n
312
313 left, right = self.layer._val
314 ax = self.axes
315
316 self.layerMarker = [ ax.plot( [], [],
317 linestyle = '',
318 markersize = 10,
319 label = "%s[%d]"%(self.par,i),
320 linewidth = 2,
321 color = self.color,
322 pickradius = slopelayer_pickradius,
323 zorder = 3,
324 alpha = 0.6,
325 marker = 'p',
326 visible = False
327 )[0] for i in xrange( 2 ) ]
328
329 slopeLine = ax.plot( [], [],
330 '--',
331 label = 'slope::line::'+self.par,
332 linewidth = 2,
333 color = self.color,
334 pickradius = 0,
335 zorder = 5,
336 visible = False
337 )[0]
338
339
340 self.markers = [self.layerMarker[0], self.layerMarker[1]]
341
342 self.connect_markers(self.markers)
343 self.markers.append( slopeLine )
344
345 self.update()
346
347
348
350 """
351 Draw the widgets in their new positions.
352 """
353 model = self.base.model
354 n = self.layernum
355
356
357 left_x = [ model.offset[n]]
358 right_x = [ model.offset[n+self.layer.span] ]
359
360 left_y = [self.layer._val[0] ]
361 right_y = [self.layer._val[1] ]
362
363 leftMarker = self.markers[0]
364 rightMarker = self.markers[1]
365 lineMarker = self.markers[2]
366
367 leftMarker.set( visible=(n>0))
368 lineMarker.set( visible=(n>0))
369 rightMarker.set(visible=(n>0))
370
371 m_x = [ model.offset[n], model.offset[n+self.layer.span] ]
372 m_y = [self.layer._val[0], self.layer._val[1] ]
373
374 leftMarker.set_data( left_x, left_y )
375 rightMarker.set_data(right_x, right_y)
376 lineMarker.set_data( m_x, m_y )
377
378
379
380 - def move(self, x, y, evt):
381 """
382 Update the model with the new widget position.
383 """
384 idx = self._lookupIndex( evt )
385
386 if idx != None :
387 self.layer._val[ idx ] = y
388
389
390
391
392
393 - def save(self, evt):
394 """
395 Save the current state of the model represented by the widget.
396 """
397 self._saved_v = self.layer._val
398
399
400
402 """
403 Restore the widget and model to the saved state.
404 """
405 self.layer._val = self._saved_v
406
407
408
409
410
412 """
413 Interactor for TetheredPolymer to handle bspline control points.
414
415 For TetheredPolymer layer, we use "circle" marker
416 """
418
419 ValidParNames = ["mu", "rho", "theta", "phi"]
420 name = label.split("_")[0].strip()
421
422 if name in ValidParNames:
423 return label
424 else:
425 return ""
426
427
442
443
445 """ Update the rho layer """
446 n = self._curr_n
447 self.infopanel.updateNLayer( n )
448
449 idx = self._lookupIndex( event )
450
451 if idx == 2:
452 self.infopanel.updateRhoValue( event.xdata,
453 idx=idx,
454 name=name )
455 return
456 self.infopanel.updateRhoValue( event.ydata, idx=idx, name=name )
457
458
460 """ Update the mu layer """
461 n = self._curr_n
462 self.infopanel.updateNLayer( n )
463
464 idx = self._lookupIndex( event )
465 self.infopanel.updateMuValue( event.ydata, idx=idx, name=name )
466
467
469 """ Update the phi layer """
470 n = self._curr_n
471 self.infopanel.updateNLayer( n )
472
473 idx = self._lookupIndex( event )
474 self.infopanel.updatePhiValue( event.ydata, idx=idx, name=name )
475
476
478
479 """ Update the theta layer """
480 n = self._curr_n
481 self.infopanel.updateNLayer( n )
482
483 idx = self._lookupIndex( event )
484 self.infopanel.updateThetaValue( event.ydata, idx=idx, name=name )
485
486
488 return len(self.layerMarker)
489
490
492 """
493 Setup the widgets required to edit layer n.
494 """
495 self.layernum = n
496
497 ax = self.axes
498
499 polymerLine = ax.plot( [], [],
500 '--',
501 label = "%s_polymerSLD"%self.par,
502 linewidth = 2,
503 color = self.color,
504 pickradius = flatlayer_pickradius,
505 zorder = 5,
506 visible = False
507 )[0]
508
509 solventLine = ax.plot( [], [],
510 '--',
511 label = "%s_solventSLD"%self.par,
512 linewidth = 2,
513 color = self.color,
514 pickradius = flatlayer_pickradius,
515 zorder = 5,
516 visible = False
517 )[0]
518
519 L0Line = ax.axvline(x=0,
520 linewidth=2,
521 linestyle='--',
522 label="%s_L0"%self.par,
523 color=self.color,
524 alpha=0.5,
525 pickradius=interface_pickradius
526 )
527
528 self.layerMarker = [ polymerLine, solventLine, L0Line]
529
530 self.markers = []
531 for i in xrange( self.getMarkerSize() ):
532 self.markers.append(self.layerMarker[i])
533
534 self.connect_markers(self.markers)
535 self.update()
536
537
539 """
540 Draw the widgets in their new positions.
541 """
542 model = self.base.model
543 n = self.layernum
544
545 left_x = model.offset[n]
546 right_x = model.offset[n+self.layer.span]
547 span = right_x - left_x
548
549 L0 = self.layer._val[2]
550 nv = 2
551
552 if span*0.1 > L0: Lshift = L0
553 else: Lshift = span*0.1
554
555 control = [
556 [left_x, left_x+Lshift],
557 [right_x-span*0.1, right_x]
558 ]
559 for i in xrange(nv):
560 self.markers[i].set(visible=(n>0))
561
562
563 for i in xrange(nv):
564 m_x = [ control[i][0], control[i][1] ]
565 m_y = [ self.layer._val[i], self.layer._val[i] ]
566 self.markers[i].set_data(m_x, m_y)
567
568 self.markers[2].set_xdata( [L0, L0])
569
570
571 - def move(self, x, y, evt):
572 """
573 Update the model with the new widget position.
574 """
575 idx = self._lookupIndex( evt )
576
577 if idx != None :
578 self.layer._val[idx] = y
579
580
581 - def save(self, evt):
582 """
583 Save the current state of the model represented by the widget.
584 """
585 self._saved_v = self.layer._val
586
587
589 """
590 Restore the widget and model to the saved state.
591 """
592 self.layer._val = self._saved_v
593
594
595
596
598 """
599 Interactor for SplineLayer to handle bspline control points.
600
601 For spline layer, we use "circle" marker
602 """
604 return len(self.layerMarker)
605
606
608 """
609 Setup the widgets required to edit layer n.
610 """
611 self.layernum = n
612
613 ax = self.axes
614
615 splineLines = [ ax.plot( [], [],
616 '--',
617 label = 'slope::line::'+self.par,
618 linewidth = 2,
619 color = self.color,
620 pickradius = 0,
621 zorder = 5,
622 visible = False
623 )[0] for i in xrange(len(self.layer._val)-1) ]
624
625 self.layerMarker = [ax.plot( [], [],
626 linestyle='',
627 markersize = 10,
628 label = "%s[%d]"%(self.par,i),
629 linewidth = 2,
630 color = self.color,
631 pickradius = splinelayer_pickradius,
632 zorder = 3,
633 alpha = 0.6,
634 marker = 'o',
635 visible = False
636 )[0] for i in xrange( len(self.layer._val) ) ]
637
638
639
640 self.markers = []
641 for i in xrange( len(self.layerMarker) ):
642 self.markers.append(self.layerMarker[i])
643
644 self.connect_markers(self.markers)
645
646 for i in xrange( len(splineLines) ):
647 self.markers.append( splineLines[i] )
648
649 self.update()
650
651
653 """
654 Draw the widgets in their new positions.
655 """
656 model = self.base.model
657 n = self.layernum
658
659 left_x = model.offset[n]
660 right_x = model.offset[n+self.layer.span]
661 span = right_x - left_x
662
663 nv = len( self.layer._val )
664 control_z = numpy.arange(0.0, nv)/(nv-1.0)*span + left_x
665
666 for i in xrange(nv*2-1):
667 self.markers[i].set(visible=(n>0))
668
669
670 for i in xrange(nv):
671 self.markers[i].set_data(control_z[i], self.layer._val[i])
672
673
674 for i in xrange(nv-1):
675 m_x = [ control_z[i], control_z[i+1] ]
676 m_y = [ self.layer._val[i], self.layer._val[i+1] ]
677 self.markers[i+nv].set_data(m_x, m_y)
678
679
680 - def move(self, x, y, evt):
681 """
682 Update the model with the new widget position.
683 """
684 idx = self._lookupIndex( evt )
685 if idx != None :
686 self.layer._val[idx] = y
687
688
689 - def save(self, evt):
690 """
691 Save the current state of the model represented by the widget.
692 """
693 self._saved_v = self.layer._val
694
695
697 """
698 Restore the widget and model to the saved state.
699 """
700 self.layer._val = self._saved_v
701
702
703
704
705
707 """
708 Null Interactor for undefined layers.
709 """
712
715
716 - def move(self, x, y):
718
721
724
725
726
727
728
729
730
732 """
733 Given a layer, find the associated interactor.
734 """
743 - def __call__(self,
744 base,
745 axes,
746 layer,
747 par,
748 **kw
749 ):
754
755 Interactor = _LayerInteractorFactory()
756