1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 """Module containing the classes for GUI components involving spectral data."""
25
26
27 import wx
28 import wx.lib.buttons
29
30
31 from graphics import fetch_icon
32 from gui.components.base_list import Base_list
33 from gui.string_conv import float_to_gui, gui_to_str, str_to_gui
34 from gui.uf_objects import Uf_storage; uf_store = Uf_storage()
35 from lib.compat import u
36 from pipe_control.spectrum import replicated_flags, replicated_ids
37 from status import Status; status = Status()
38 from specific_analyses.relax_disp.data import is_cpmg_exp_type, is_r1rho_exp_type
39 from user_functions.data import Uf_info; uf_info = Uf_info()
40
41
42
43 MENU_SPECTRUM_BASEPLANE_RMSD = wx.NewId()
44 MENU_SPECTRUM_DELETE = wx.NewId()
45 MENU_SPECTRUM_INTEGRATION_POINTS = wx.NewId()
46 MENU_SPECTRUM_REPLICATED = wx.NewId()
47 MENU_RELAX_DISP_EXP_TYPE = wx.NewId()
48 MENU_RELAX_FIT_RELAX_TIME = wx.NewId()
49 MENU_RELAX_DISP_RELAX_TIME = wx.NewId()
50 MENU_SPECTROMETER_FRQ = wx.NewId()
51 MENU_RELAX_DISP_SPIN_LOCK_FIELD = wx.NewId()
52 MENU_RELAX_DISP_SPIN_LOCK_OFFSET = wx.NewId()
53 MENU_RELAX_DISP_CPMG_SETUP = wx.NewId()
54
55
57 """The GUI element for listing loaded spectral data."""
58
59 - def __init__(self, gui=None, parent=None, box=None, id=None, fn_add=None, proportion=0, button_placement='default', noe_flag=False, relax_fit_flag=False, relax_disp_flag=False):
60 """Build the spectral list GUI element.
61
62 @keyword gui: The main GUI object.
63 @type gui: wx.Frame instance
64 @keyword parent: The parent GUI element that this is to be attached to (the panel object).
65 @type parent: wx object
66 @keyword data: The data storage container.
67 @type data: class instance
68 @keyword box: The vertical box sizer to pack this GUI component into.
69 @type box: wx.BoxSizer instance
70 @keyword id: A unique identification string. This is used to register the update method with the GUI user function observer object.
71 @type id: str
72 @keyword fn_add: The function to execute when clicking on the 'Add' button.
73 @type fn_add: func
74 @keyword proportion: The window proportion parameter.
75 @type proportion: bool
76 @keyword button_placement: Override the button visibility and placement. The value of 'default' will leave the buttons at the default setting. The value of 'top' will place the buttons at the top, 'bottom' will place them at the bottom, and None will turn off the buttons.
77 @type button_placement: str or None
78 @keyword noe_flag: A flag which when True will enable the steady-state NOE portions of the wizard.
79 @type noe_flag: bool
80 @keyword relax_fit_flag: A flag which when True will enable the relaxation curve-fitting portions of the wizard.
81 @type relax_fit_flag: bool
82 @keyword relax_disp_flag: A flag which when True will enable the relaxation dispersion portions of the wizard.
83 @type relax_disp_flag: bool
84 """
85
86
87 self.fn_add = fn_add
88 self.noe_flag = noe_flag
89 self.relax_fit_flag = relax_fit_flag
90 self.relax_disp_flag = relax_disp_flag
91
92
93 super(Spectra_list, self).__init__(gui=gui, parent=parent, box=box, id=id, proportion=proportion, button_placement=button_placement)
94
95
97 """Launch the relax_disp.cpmg_setup user function.
98
99 @keyword event: The wx event.
100 @type event: wx event
101 @keyword item: This is for debugging purposes only, to allow the GUI tests to select items without worrying about OS dependent wxPython bugs.
102 @type item: None or int
103 """
104
105
106 if item == None:
107 item = self.element.GetFirstSelected()
108
109
110 id = gui_to_str(self.element.GetItemText(item))
111
112
113 frq = None
114 frq_flag = False
115 if hasattr(cdp, 'cpmg_frqs') and id in cdp.cpmg_frqs:
116 frq = cdp.cpmg_frqs[id]
117 frq_flag = True
118
119
120 even = True
121 even_flag = False
122 if hasattr(cdp, 'ncyc_even') and id in cdp.ncyc_even:
123 even = cdp.ncyc_even[id]
124 even_flag = True
125
126
127 if frq_flag:
128 uf_store['relax_disp.cpmg_setup'](spectrum_id=id, cpmg_frq=frq, ncyc_even=even)
129 else:
130 uf_store['relax_disp.cpmg_setup'](spectrum_id=id, ncyc_even=even)
131
132
134 """Launch the relax_disp.exp_type user function.
135
136 @keyword event: The wx event.
137 @type event: wx event
138 @keyword item: This is for debugging purposes only, to allow the GUI tests to select items without worrying about OS dependent wxPython bugs.
139 @type item: None or int
140 """
141
142
143 if item == None:
144 item = self.element.GetFirstSelected()
145
146
147 id = gui_to_str(self.element.GetItemText(item))
148
149
150 exp_type = None
151 if hasattr(cdp, 'exp_type') and id in cdp.exp_type:
152 exp_type = cdp.exp_type[id]
153
154
155 if exp_type == None:
156 uf_store['relax_disp.exp_type'](spectrum_id=id)
157 else:
158 uf_store['relax_disp.exp_type'](spectrum_id=id, exp_type=exp_type)
159
160
162 """Launch the relax_disp.relax_time user function.
163
164 @keyword event: The wx event.
165 @type event: wx event
166 @keyword item: This is for debugging purposes only, to allow the GUI tests to select items without worrying about OS dependent wxPython bugs.
167 @type item: None or int
168 """
169
170
171 if item == None:
172 item = self.element.GetFirstSelected()
173
174
175 id = gui_to_str(self.element.GetItemText(item))
176
177
178 time = None
179 if hasattr(cdp, 'relax_times') and id in cdp.relax_times:
180 time = cdp.relax_times[id]
181
182
183 if time == None:
184 uf_store['relax_disp.relax_time'](spectrum_id=id)
185 else:
186 uf_store['relax_disp.relax_time'](time=time, spectrum_id=id)
187
188
190 """Launch the relax_disp.spin_lock_field user function.
191
192 @keyword event: The wx event.
193 @type event: wx event
194 @keyword item: This is for debugging purposes only, to allow the GUI tests to select items without worrying about OS dependent wxPython bugs.
195 @type item: None or int
196 """
197
198
199 if item == None:
200 item = self.element.GetFirstSelected()
201
202
203 id = gui_to_str(self.element.GetItemText(item))
204
205
206 nu1 = None
207 nu1_flag = False
208 if hasattr(cdp, 'spin_lock_nu1') and id in cdp.spin_lock_nu1:
209 nu1 = cdp.spin_lock_nu1[id]
210 nu1_flag = True
211
212
213 if nu1_flag:
214 uf_store['relax_disp.spin_lock_field'](field=nu1, spectrum_id=id)
215 else:
216 uf_store['relax_disp.spin_lock_field'](spectrum_id=id)
217
218
220 """Launch the relax_disp.spin_lock_offset user function.
221
222 @keyword event: The wx event.
223 @type event: wx event
224 @keyword item: This is for debugging purposes only, to allow the GUI tests to select items without worrying about OS dependent wxPython bugs.
225 @type item: None or int
226 """
227
228
229 if item == None:
230 item = self.element.GetFirstSelected()
231
232
233 id = gui_to_str(self.element.GetItemText(item))
234
235
236 offset = None
237 offset_flag = False
238 if hasattr(cdp, 'spin_lock_offset') and id in cdp.spin_lock_offset:
239 offset = cdp.spin_lock_offset[id]
240 offset_flag = True
241
242
243 if offset_flag:
244 uf_store['relax_disp.spin_lock_offset'](offset=offset, spectrum_id=id)
245 else:
246 uf_store['relax_disp.spin_lock_offset'](spectrum_id=id)
247
248
250 """Launch the relax_fit.relax_time user function.
251
252 @keyword event: The wx event.
253 @type event: wx event
254 @keyword item: This is for debugging purposes only, to allow the GUI tests to select items without worrying about OS dependent wxPython bugs.
255 @type item: None or int
256 """
257
258
259 if item == None:
260 item = self.element.GetFirstSelected()
261
262
263 id = gui_to_str(self.element.GetItemText(item))
264
265
266 time = None
267 if hasattr(cdp, 'relax_times') and id in cdp.relax_times:
268 time = cdp.relax_times[id]
269
270
271 if time == None:
272 uf_store['relax_fit.relax_time'](spectrum_id=id)
273 else:
274 uf_store['relax_fit.relax_time'](time=time, spectrum_id=id)
275
276
278 """Launch the spectrometer.frequency user function.
279
280 @keyword event: The wx event.
281 @type event: wx event
282 @keyword item: This is for debugging purposes only, to allow the GUI tests to select items without worrying about OS dependent wxPython bugs.
283 @type item: None or int
284 """
285
286
287 if item == None:
288 item = self.element.GetFirstSelected()
289
290
291 id = gui_to_str(self.element.GetItemText(item))
292
293
294 frq = None
295 if hasattr(cdp, 'spectrometer_frq') and id in cdp.spectrometer_frq:
296 frq = cdp.spectrometer_frq[id]
297
298
299 if frq == None:
300 uf_store['spectrometer.frequency'](id=id)
301 else:
302 uf_store['spectrometer.frequency'](frq=frq, id=id)
303
304
306 """Launch the spectrum.baseplane_rmsd user function.
307
308 @param event: The wx event.
309 @type event: wx event
310 """
311
312
313 item = self.element.GetFirstSelected()
314
315
316 id = gui_to_str(self.element.GetItemText(item))
317
318
319 uf_store['spectrum.baseplane_rmsd'](spectrum_id=id)
320
321
323 """Launch the spectrum.delete user function.
324
325 @param event: The wx event.
326 @type event: wx event
327 """
328
329
330 item = self.element.GetFirstSelected()
331
332
333 if item == -1:
334 id = None
335
336
337 else:
338
339 id = gui_to_str(self.element.GetItemText(item))
340
341
342 uf_store['spectrum.delete'](spectrum_id=id)
343
344
346 """Launch the spectrum.error_analysis user function.
347
348 @param event: The wx event.
349 @type event: wx event
350 """
351
352
353 item = self.element.GetFirstSelected()
354
355
356 ids = []
357 while True:
358
359 if item == -1:
360 break
361
362
363 ids.append(gui_to_str(self.element.GetItemText(item)))
364
365
366 item = self.element.GetNextSelected(item)
367
368
369 if not len(ids):
370 ids = None
371
372
373 uf_store['spectrum.error_analysis'](subset=ids, wx_wizard_modal=True)
374
375
376 self.gui.show_controller(None)
377 self.gui.controller.log_panel.on_goto_end(None)
378
379
381 """Launch the spectrum.integration_points user function.
382
383 @param event: The wx event.
384 @type event: wx event
385 """
386
387
388 item = self.element.GetFirstSelected()
389
390
391 id = gui_to_str(self.element.GetItemText(item))
392
393
394 uf_store['spectrum.integration_points'](spectrum_id=id)
395
396
398 """Launch the spectrum.replicated user function.
399
400 @param event: The wx event.
401 @type event: wx event
402 """
403
404
405 item = self.element.GetFirstSelected()
406
407
408 id = gui_to_str(self.element.GetItemText(item))
409
410
411 replicates = replicated_ids(id)
412
413
414 if replicates == []:
415 uf_store['spectrum.replicated'](spectrum_ids=id)
416 else:
417 uf_store['spectrum.replicated'](spectrum_ids=replicates)
418
419
421 """Add the dispersion point info to the element.
422
423 This is either the CPMG pulse frequency or the spin-lock field strength. Both share the same column.
424
425 @param index: The column index for the data.
426 @type index: int
427 @return: True if the data exists, False otherwise.
428 @rtype: bool
429 """
430
431
432 self.element.InsertColumn(index, u("\u03BDCPMG (Hz) or Spin-lock \u03BD1 (Hz)"))
433
434
435 if not hasattr(cdp, 'spectrum_ids'):
436 return True
437
438
439 for i in range(len(cdp.spectrum_ids)):
440
441 if hasattr(cdp, 'cpmg_frqs') and cdp.spectrum_ids[i] in cdp.cpmg_frqs:
442 self.element.SetStringItem(i, index, float_to_gui(cdp.cpmg_frqs[cdp.spectrum_ids[i]]))
443
444
445 if hasattr(cdp, 'spin_lock_nu1') and cdp.spectrum_ids[i] in cdp.spin_lock_nu1:
446 self.element.SetStringItem(i, index, float_to_gui(cdp.spin_lock_nu1[cdp.spectrum_ids[i]]))
447
448
449 return True
450
451
453 """Add the experiment type info to the element.
454
455 @param index: The column index for the data.
456 @type index: int
457 @return: True if the data exists, False otherwise.
458 @rtype: bool
459 """
460
461
462 self.element.InsertColumn(index, u("Experiment type"))
463
464
465 if not hasattr(cdp, 'spectrum_ids') or not hasattr(cdp, 'exp_type'):
466 return True
467
468
469 for i in range(len(cdp.spectrum_ids)):
470
471 if cdp.spectrum_ids[i] not in cdp.exp_type:
472 continue
473
474
475 self.element.SetStringItem(i, index, float_to_gui(cdp.exp_type[cdp.spectrum_ids[i]]))
476
477
478 return True
479
480
482 """Add the spectrometer frequency info to the element.
483
484 @param index: The column index for the data.
485 @type index: int
486 @return: True if the frequency data exists, False otherwise.
487 @rtype: bool
488 """
489
490
491 self.element.InsertColumn(index, u("\u03C9H (MHz)"))
492
493
494 if not hasattr(cdp, 'spectrum_ids'):
495 return True
496 if not hasattr(cdp, 'spectrometer_frq') or not len(cdp.spectrometer_frq):
497 return True
498
499
500 for i in range(len(cdp.spectrum_ids)):
501
502 if cdp.spectrum_ids[i] not in cdp.spectrometer_frq:
503 continue
504
505
506 self.element.SetStringItem(i, index, float_to_gui(cdp.spectrometer_frq[cdp.spectrum_ids[i]]/1e6))
507
508
509 return True
510
511
513 """Add the offset info to the element.
514
515 @param index: The column index for the data.
516 @type index: int
517 @return: True if the data exists, False otherwise.
518 @rtype: bool
519 """
520
521
522 self.element.InsertColumn(index, u("Offset \u03C9_rf (ppm)"))
523
524
525 if not hasattr(cdp, 'spectrum_ids'):
526 return True
527
528
529 for i in range(len(cdp.spectrum_ids)):
530 if hasattr(cdp, 'spin_lock_offset') and cdp.spectrum_ids[i] in cdp.spin_lock_offset:
531 self.element.SetStringItem(i, index, float_to_gui(cdp.spin_lock_offset[cdp.spectrum_ids[i]]))
532
533
534 return True
535
536
538 """Create the popup menu.
539
540 @keyword id: The spectrum ID string for the row that was clicked on.
541 @type id: str
542 @return: The popup menu.
543 @rtype: list of dict of wxID, str, str, method
544 """
545
546
547 popup_menus = [
548 {
549 'id': MENU_SPECTRUM_BASEPLANE_RMSD,
550 'text': "Set the &baseplane RMSD",
551 'icon': fetch_icon(uf_info.get_uf('spectrum.baseplane_rmsd').gui_icon),
552 'method': self.action_spectrum_baseplane_rmsd
553 }, {
554 'id': MENU_SPECTRUM_DELETE,
555 'text': "&Delete the peak intensities",
556 'icon': fetch_icon(uf_info.get_uf('spectrum.delete').gui_icon),
557 'method': self.action_spectrum_delete
558 }, {
559 'id': MENU_SPECTRUM_INTEGRATION_POINTS,
560 'text': "Set the number of integration &points",
561 'icon': fetch_icon(uf_info.get_uf('spectrum.integration_points').gui_icon),
562 'method': self.action_spectrum_integration_points
563 }, {
564 'id': MENU_SPECTRUM_REPLICATED,
565 'text': "Specify which spectra are &replicated",
566 'icon': fetch_icon(uf_info.get_uf('spectrum.replicated').gui_icon),
567 'method': self.action_spectrum_replicated
568 }
569 ]
570 if self.relax_disp_flag:
571 popup_menus.append({
572 'id': MENU_RELAX_DISP_EXP_TYPE,
573 'text': "Set the &experiment type",
574 'icon': None,
575 'method': self.action_relax_disp_exp_type
576 })
577 if self.relax_fit_flag:
578 popup_menus.append({
579 'id': MENU_RELAX_FIT_RELAX_TIME,
580 'text': "Set the relaxation &time",
581 'icon': fetch_icon(uf_info.get_uf('relax_fit.relax_time').gui_icon),
582 'method': self.action_relax_fit_relax_time
583 })
584 if self.relax_disp_flag:
585 popup_menus.append({
586 'id': MENU_RELAX_DISP_RELAX_TIME,
587 'text': "Set the relaxation &time",
588 'icon': fetch_icon(uf_info.get_uf('relax_disp.relax_time').gui_icon),
589 'method': self.action_relax_disp_relax_time
590 })
591 popup_menus.append({
592 'id': MENU_SPECTROMETER_FRQ,
593 'text': "Set the spectrometer &frequency",
594 'icon': fetch_icon("relax.spectrometer"),
595 'method': self.action_spectrometer_frq
596 })
597 if self.relax_disp_flag and is_r1rho_exp_type(id):
598 popup_menus.append({
599 'id': MENU_RELAX_DISP_SPIN_LOCK_FIELD,
600 'text': u("Set the spin-&lock field strength \u03BD1"),
601 'icon': fetch_icon("relax.relax_disp"),
602 'method': self.action_relax_disp_spin_lock_field
603 })
604 popup_menus.append({
605 'id': MENU_RELAX_DISP_SPIN_LOCK_OFFSET,
606 'text': u("Set the spin-&lock offset \u03C9_rf"),
607 'icon': fetch_icon("relax.relax_disp"),
608 'method': self.action_relax_disp_spin_lock_offset
609 })
610 if self.relax_disp_flag and is_cpmg_exp_type(id):
611 popup_menus.append({
612 'id': MENU_RELAX_DISP_CPMG_SETUP,
613 'text': u("Set the &CPMG pulse sequence information"),
614 'icon': fetch_icon("relax.relax_disp"),
615 'method': self.action_relax_disp_cpmg_setup
616 })
617
618
619 return popup_menus
620
621
623 """Add the NOE spectral type info to the element.
624
625 @param index: The column index for the data.
626 @type index: int
627 @return: True if a spectrum type exists, False otherwise.
628 @rtype: bool
629 """
630
631
632 if not hasattr(cdp, 'spectrum_type') or not len(cdp.spectrum_type):
633 return False
634
635
636 self.element.InsertColumn(index, str_to_gui("NOE spectrum type"))
637
638
639 table = {
640 'sat': 'Saturated',
641 'ref': 'Reference'
642 }
643
644
645 if not hasattr(cdp, 'spectrum_ids'):
646 return True
647
648
649 for i in range(len(cdp.spectrum_ids)):
650
651 if cdp.spectrum_ids[i] not in cdp.spectrum_type:
652 continue
653
654
655 self.element.SetStringItem(i, index, str_to_gui(table[cdp.spectrum_type[cdp.spectrum_ids[i]]]))
656
657
658 return True
659
660
662 """Add the relaxation delay time info to the element.
663
664 @param index: The column index for the data.
665 @type index: int
666 @return: True if relaxation times exist, False otherwise.
667 @rtype: bool
668 """
669
670
671 if not hasattr(cdp, 'relax_times') or not len(cdp.relax_times):
672 return False
673
674
675 self.element.InsertColumn(index, str_to_gui("Delay times (s)"))
676
677
678 if not hasattr(cdp, 'spectrum_ids'):
679 return True
680
681
682 for i in range(len(cdp.spectrum_ids)):
683
684 if cdp.spectrum_ids[i] not in cdp.relax_times:
685 continue
686
687
688 self.element.SetStringItem(i, index, float_to_gui(cdp.relax_times[cdp.spectrum_ids[i]]))
689
690
691 return True
692
693
695 """Add the replicated spectra info to the element.
696
697 @param index: The column index for the data.
698 @type index: int
699 @return: True if relaxation times exist, False otherwise.
700 @rtype: bool
701 """
702
703
704 if not hasattr(cdp, 'replicates') or not len(cdp.replicates):
705 return False
706
707
708 repl = replicated_flags()
709
710
711 self.element.InsertColumn(index, str_to_gui("Replicate IDs"))
712
713
714 if not hasattr(cdp, 'spectrum_ids'):
715 return True
716
717
718 for i in range(len(cdp.spectrum_ids)):
719
720 if not repl[cdp.spectrum_ids[i]]:
721 continue
722
723
724 id_list = replicated_ids(cdp.spectrum_ids[i])
725
726
727 text = ''
728 for j in range(len(id_list)):
729
730 text = "%s%s" % (text, id_list[j])
731
732
733 if j < len(id_list)-1:
734 text = "%s, " % text
735
736
737 self.element.SetStringItem(i, index, str_to_gui(text))
738
739
740 return True
741
742
744 """Override the base variables."""
745
746
747 self.title = "Spectra list"
748 self.observer_base_name = "spectra list"
749
750
751 self.columns = []
752
753
754 self.button_placement = 'top'
755 self.button_size = (170, 40)
756 self.button_info = [
757 {
758 'object': 'button_add',
759 'label': ' Add',
760 'icon': fetch_icon('oxygen.actions.list-add-relax-blue', "22x22"),
761 'method': self.fn_add,
762 'tooltip': "Read a spectral data file."
763 }, {
764 'object': 'button_delete',
765 'label': ' Delete',
766 'icon': fetch_icon('oxygen.actions.list-remove', "22x22"),
767 'method': self.action_spectrum_delete,
768 'tooltip': "Delete loaded relaxation data from the relax data store."
769 }, {
770 'object': 'button_error_analysis',
771 'label': ' Error analysis',
772 'icon': fetch_icon('oxygen.categories.applications-education', "22x22"),
773 'method': self.action_spectrum_error_analysis,
774 'tooltip': "Perform a peak intensity error analysis on the currently loaded data or data subsets. Select a subset of the spectra below to perform the error analysis only on this subset."
775 }
776 ]
777
778
780 """Method called from self.build_element_safe() to update the list data."""
781
782
783 index = 1
784
785
786 self.element.DeleteAllItems()
787 self.element.DeleteAllColumns()
788
789
790 self.element.InsertColumn(0, str_to_gui("Spectrum ID"))
791
792
793 n = 0
794 if hasattr(cdp, 'spectrum_ids'):
795
796 n = len(cdp.spectrum_ids)
797
798
799 for i in range(n):
800 self.element.InsertStringItem(i, str_to_gui(cdp.spectrum_ids[i]))
801
802
803 if self.noe_spectrum_type(index):
804 index += 1
805
806
807 if self.relax_disp_flag and self.add_exp_type(index):
808 index += 1
809
810
811 if self.relax_disp_flag and self.add_frqs(index):
812 index += 1
813
814
815 if self.relax_disp_flag and self.add_disp_point(index):
816 index += 1
817
818
819 if self.relax_disp_flag and self.add_offset(index):
820 index += 1
821
822
823 if (self.relax_fit_flag or self.relax_disp_flag) and self.relax_times(index):
824 index += 1
825
826
827 if self.replicates(index):
828 index += 1
829