Changeset dceff6e in sasview for src/sas/sasgui
- Timestamp:
- Aug 31, 2016 11:21:55 AM (8 years ago)
- Branches:
- master, ESS_GUI, ESS_GUI_Docs, ESS_GUI_batch_fitting, ESS_GUI_bumps_abstraction, ESS_GUI_iss1116, ESS_GUI_iss879, ESS_GUI_iss959, ESS_GUI_opencl, ESS_GUI_ordering, ESS_GUI_sync_sascalc, costrafo411, magnetic_scatt, release-4.2.2, ticket-1009, ticket-1094-headless, ticket-1242-2d-resolution, ticket-1243, ticket-1249, ticket885, unittest-saveload
- Children:
- ce94504
- Parents:
- ec30905 (diff), 4036cb0 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent. - Location:
- src/sas/sasgui
- Files:
-
- 1 added
- 31 edited
Legend:
- Unmodified
- Added
- Removed
-
src/sas/sasgui/guiframe/data_panel.py
rd85c194 re767897 2 2 #This software was developed by the University of Tennessee as part of the 3 3 #Distributed Data Analysis of Neutron Scattering Experiments (DANSE) 4 #project funded by the US National Science Foundation. 4 #project funded by the US National Science Foundation. 5 5 # 6 6 #See the license text in license.txt … … 13 13 import wx 14 14 from wx.build import build_options 15 15 16 # Check version 16 17 toks = str(wx.__version__).split('.') … … 40 41 as QucikPlotDialog 41 42 import sas.sasgui.guiframe.config as config 42 43 43 44 extension_list = [] 44 45 if config.APPLICATION_STATE_EXTENSION is not None: 45 46 extension_list.append(config.APPLICATION_STATE_EXTENSION) 46 EXTENSIONS = config.PLUGIN_STATE_EXTENSIONS + extension_list 47 EXTENSIONS = config.PLUGIN_STATE_EXTENSIONS + extension_list 47 48 PLUGINS_WLIST = config.PLUGINS_WLIST 48 49 APPLICATION_WLIST = config.APPLICATION_WLIST 49 50 50 #Control panel width 51 #Control panel width 51 52 if sys.platform.count("win32") > 0: 52 53 PANEL_WIDTH = 235 … … 66 67 STYLE_FLAG = wx.RAISED_BORDER|CT.TR_HAS_BUTTONS| CT.TR_HIDE_ROOT|\ 67 68 wx.WANTS_CHARS|CT.TR_HAS_VARIABLE_ROW_HEIGHT 68 69 69 70 70 71 class DataTreeCtrl(CT.CustomTreeCtrl): 71 72 """ … … 96 97 CT.CustomTreeCtrl.__init__(self, parent, *args, **kwds) 97 98 self.root = self.AddRoot("Available Data") 98 99 99 100 def OnCompareItems(self, item1, item2): 100 """ 101 Overrides OnCompareItems in wx.TreeCtrl. 102 Used by the SortChildren method. 101 """ 102 Overrides OnCompareItems in wx.TreeCtrl. 103 Used by the SortChildren method. 103 104 """ 104 105 # Get the item data … … 112 113 else: 113 114 return 0 114 115 115 116 class DataPanel(ScrolledPanel, PanelBase): 116 117 """ 117 This panel displays data available in the application and widgets to 118 This panel displays data available in the application and widgets to 118 119 interact with data. 119 120 """ … … 122 123 ## Title to appear on top of the window 123 124 window_caption = "Data Explorer" 124 #type of window 125 #type of window 125 126 window_type = "Data Panel" 126 127 ## Flag to tell the GUI manager that this panel is not 127 128 # tied to any perspective 128 129 #ALWAYS_ON = True 129 def __init__(self, parent, 130 def __init__(self, parent, 130 131 list=None, 131 132 size=(PANEL_WIDTH, PANEL_HEIGHT), … … 137 138 PanelBase.__init__(self, parent) 138 139 self.SetupScrolling() 139 #Set window's font size 140 #Set window's font size 140 141 self.SetWindowVariant(variant=FONT_VARIANT) 141 self.loader = Loader() 142 self.loader = Loader() 142 143 #Default location 143 self._default_save_location = None 144 self._default_save_location = None 144 145 self.all_data1d = True 145 146 self.parent = parent.parent … … 187 188 if self.parent is not None: 188 189 self.parent.Bind(EVT_DELETE_PLOTPANEL, self._on_delete_plot_panel) 189 190 190 191 def do_layout(self): 191 192 """ … … 197 198 self.layout_batch() 198 199 self.layout_button() 199 200 200 201 def disable_app_combo(self, enable): 201 202 """ … … 203 204 """ 204 205 self.perspective_cbox.Enable(enable) 205 206 206 207 def define_panel_structure(self): 207 208 """ … … 212 213 self.sizer1 = wx.BoxSizer(wx.VERTICAL) 213 214 self.sizer1.SetMinSize(wx.Size(w/13, h*2/5)) 214 215 215 216 self.sizer2 = wx.BoxSizer(wx.VERTICAL) 216 217 self.sizer3 = wx.FlexGridSizer(9, 2, 4, 1) 217 218 self.sizer4 = wx.BoxSizer(wx.VERTICAL) 218 219 self.sizer5 = wx.BoxSizer(wx.VERTICAL) 219 220 220 221 self.vbox.Add(self.sizer5, 0, wx.EXPAND|wx.ALL, 1) 221 222 self.vbox.Add(self.sizer1, 1, wx.EXPAND|wx.ALL, 0) … … 223 224 self.vbox.Add(self.sizer3, 0, wx.EXPAND|wx.ALL, 10) 224 225 #self.vbox.Add(self.sizer4, 0, wx.EXPAND|wx.ALL,5) 225 226 226 227 self.SetSizer(self.vbox) 227 228 228 229 def layout_selection(self): 229 230 """ … … 243 244 self.selection_cbox.SetValue('Select all Data') 244 245 wx.EVT_COMBOBOX(self.selection_cbox, -1, self._on_selection_type) 245 self.sizer5.AddMany([(select_txt, 0, wx.ALL, 5), 246 self.sizer5.AddMany([(select_txt, 0, wx.ALL, 5), 246 247 (self.selection_cbox, 0, wx.ALL,5)]) 247 248 self.enable_selection() 248 249 249 250 250 251 def _on_selection_type(self, event): 251 252 """ … … 253 254 :param event: UI event 254 255 """ 256 def check_item_and_children(control, check_value=True): 257 self.tree_ctrl.CheckItem(data_ctrl, check_value) 258 if data_ctrl.HasChildren(): 259 if check_value == True and not control.IsExpanded(): 260 # Only select children if control is expanded 261 # Always deselect children, regardless (see ticket #259) 262 return 263 for child_ctrl in data_ctrl.GetChildren(): 264 self.tree_ctrl.CheckItem(child_ctrl, check_value) 265 255 266 option = self.selection_cbox.GetValue() 256 267 257 268 pos = self.selection_cbox.GetSelection() 258 269 if pos == wx.NOT_FOUND: 259 return 270 return 260 271 option = self.selection_cbox.GetString(pos) 261 272 for item in self.list_cb_data.values(): 262 273 data_ctrl, _, _, _, _, _, _, _ = item 263 _, data_class, _ = self.tree_ctrl.GetItemPyData(data_ctrl) 274 _, data_class, _ = self.tree_ctrl.GetItemPyData(data_ctrl) 264 275 if option == 'Select all Data': 265 self.tree_ctrl.CheckItem(data_ctrl, True)276 check_item_and_children(data_ctrl, check_value=True) 266 277 elif option == 'Unselect all Data': 267 self.tree_ctrl.CheckItem(data_ctrl,False)278 check_item_and_children(data_ctrl, check_value=False) 268 279 elif option == 'Select all Data 1D': 269 280 if data_class == 'Data1D': 270 self.tree_ctrl.CheckItem(data_ctrl, True)281 check_item_and_children(data_ctrl, check_value=True) 271 282 elif option == 'Unselect all Data 1D': 272 283 if data_class == 'Data1D': 273 self.tree_ctrl.CheckItem(data_ctrl, False) 274 elif option == 'Select all Data 1D': 275 if data_class == 'Data1D': 276 self.tree_ctrl.CheckItem(data_ctrl, True) 284 check_item_and_children(data_ctrl, check_value=False) 277 285 elif option == 'Select all Data 2D': 278 286 if data_class == 'Data2D': 279 self.tree_ctrl.CheckItem(data_ctrl, True)287 check_item_and_children(data_ctrl, check_value=True) 280 288 elif option == 'Unselect all Data 2D': 281 289 if data_class == 'Data2D': 282 self.tree_ctrl.CheckItem(data_ctrl, False)290 check_item_and_children(data_ctrl, check_value=False) 283 291 self.enable_append() 284 292 self.enable_freeze() … … 286 294 self.enable_import() 287 295 self.enable_remove() 288 296 289 297 def layout_button(self): 290 298 """ 291 299 Layout widgets related to buttons 292 300 """ 293 self.bt_add = wx.Button(self, wx.NewId(), "Load Data", 301 #Load Data Button 302 self.bt_add = wx.Button(self, wx.NewId(), "Load Data", 294 303 size=(BUTTON_WIDTH, -1)) 295 304 self.bt_add.SetToolTipString("Load data files") 296 305 wx.EVT_BUTTON(self, self.bt_add.GetId(), self._load_data) 306 307 #Delete Data Button 297 308 self.bt_remove = wx.Button(self, wx.NewId(), "Delete Data", 298 309 size=(BUTTON_WIDTH, -1)) 299 310 self.bt_remove.SetToolTipString("Delete data from the application") 300 311 wx.EVT_BUTTON(self, self.bt_remove.GetId(), self.on_remove) 312 313 #Send data to perspective button 301 314 self.bt_import = wx.Button(self, wx.NewId(), "Send To", 302 315 size=(BUTTON_WIDTH, -1)) 303 316 self.bt_import.SetToolTipString("Send Data set to active perspective") 304 317 wx.EVT_BUTTON(self, self.bt_import.GetId(), self.on_import) 318 319 #Choose perspective to be send data to combo box 305 320 self.perspective_cbox = wx.ComboBox(self, -1, 306 321 style=wx.CB_READONLY) 307 322 if not IS_MAC: 308 323 self.perspective_cbox.SetMinSize((BUTTON_WIDTH*1.6, -1)) 309 wx.EVT_COMBOBOX(self.perspective_cbox, -1, 324 wx.EVT_COMBOBOX(self.perspective_cbox, -1, 310 325 self._on_perspective_selection) 311 326 327 #Append data to current Graph Button 312 328 self.bt_append_plot = wx.Button(self, wx.NewId(), "Append Plot To", 313 329 size=(BUTTON_WIDTH, -1)) … … 315 331 "Plot the selected data in the active panel") 316 332 wx.EVT_BUTTON(self, self.bt_append_plot.GetId(), self.on_append_plot) 317 318 self.bt_plot = wx.Button(self, wx.NewId(), "New Plot", 333 334 #Create a new graph and send data to that new graph button 335 self.bt_plot = wx.Button(self, wx.NewId(), "New Plot", 319 336 size=(BUTTON_WIDTH, -1)) 320 337 self.bt_plot.SetToolTipString("To trigger plotting") 321 338 wx.EVT_BUTTON(self, self.bt_plot.GetId(), self.on_plot) 322 323 self.bt_freeze = wx.Button(self, wx.NewId(), "Freeze Theory", 339 340 #Freeze current theory button - becomes a data set and stays on graph 341 self.bt_freeze = wx.Button(self, wx.NewId(), "Freeze Theory", 324 342 size=(BUTTON_WIDTH, -1)) 325 343 freeze_tip = "To trigger freeze a theory: making a copy\n" … … 328 346 self.bt_freeze.SetToolTipString(freeze_tip) 329 347 wx.EVT_BUTTON(self, self.bt_freeze.GetId(), self.on_freeze) 330 348 349 #select plot to send to combo box (blank if no data) 331 350 if sys.platform == 'darwin': 332 self.cb_plotpanel = wx.ComboBox(self, -1, 351 self.cb_plotpanel = wx.ComboBox(self, -1, 333 352 style=wx.CB_READONLY) 334 353 else: 335 self.cb_plotpanel = wx.ComboBox(self, -1, 354 self.cb_plotpanel = wx.ComboBox(self, -1, 336 355 style=wx.CB_READONLY|wx.CB_SORT) 337 356 wx.EVT_COMBOBOX(self.cb_plotpanel, -1, self._on_plot_selection) 338 357 self.cb_plotpanel.Disable() 358 359 #Help button 360 self.bt_help = wx.Button(self, wx.NewId(), "HELP", 361 size=(BUTTON_WIDTH, -1)) 362 self.bt_help.SetToolTipString("Help for the Data Explorer.") 363 wx.EVT_BUTTON(self,self.bt_help.GetId(), self.on_help) 339 364 340 365 self.sizer3.AddMany([(self.bt_add), … … 347 372 ((10, 10)), 348 373 (self.bt_append_plot), 349 (self.cb_plotpanel, 374 (self.cb_plotpanel, 350 375 wx.EXPAND|wx.ADJUST_MINSIZE, 5), 351 376 ((5, 5)), 352 377 ((5, 5)), 353 378 (self.bt_import, 0, wx.EXPAND|wx.RIGHT, 5), 354 (self.perspective_cbox, 379 (self.perspective_cbox, 355 380 wx.EXPAND|wx.ADJUST_MINSIZE, 5), 356 381 ((10, 10)), 357 382 (self.sizer4), 358 ((10, 40)),359 ( (10, 40))])383 ((10, 10)), 384 (self.bt_help, 0, wx.RIGHT, 5)]) 360 385 361 386 self.sizer3.AddGrowableCol(1, 1) … … 367 392 self.enable_freeze() 368 393 self.enable_remove_plot() 369 394 370 395 def layout_batch(self): 371 396 """ … … 379 404 self.Bind(wx.EVT_RADIOBUTTON, self.on_batch_mode, 380 405 id=self.rb_batch_mode.GetId()) 381 406 382 407 self.rb_single_mode.SetValue(not self.parent.batch_on) 383 408 self.rb_batch_mode.SetValue(self.parent.batch_on) 384 409 self.sizer4.AddMany([(self.rb_single_mode, 0, wx.ALL, 4), 385 410 (self.rb_batch_mode, 0, wx.ALL, 4)]) 386 411 387 412 def on_single_mode(self, event): 388 413 """ … … 392 417 if self.parent is not None: 393 418 wx.PostEvent(self.parent, NewBatchEvent(enable=False)) 394 419 395 420 def on_batch_mode(self, event): 396 421 """ … … 399 424 """ 400 425 if self.parent is not None: 401 wx.PostEvent(self.parent, 426 wx.PostEvent(self.parent, 402 427 NewBatchEvent(enable=True)) 403 404 def _get_data_selection(self, event): 428 429 def _get_data_selection(self, event): 405 430 """ 406 431 Get data selection from the right click … … 417 442 data = theory_list.values()[0][0] 418 443 return data 419 444 420 445 def on_edit_data(self, event): 421 446 """ … … 425 450 from sas.sasgui.guiframe.local_perspectives.plotting.masking \ 426 451 import MaskPanel as MaskDialog 427 428 panel = MaskDialog(parent=self.parent, base=self, 452 453 panel = MaskDialog(parent=self.parent, base=self, 429 454 data=data, id=wx.NewId()) 430 455 panel.ShowModal() 431 456 432 457 def on_plot_3d(self, event): 433 458 """ … … 437 462 from sas.sasgui.guiframe.local_perspectives.plotting.masking \ 438 463 import FloatPanel as Float3dDialog 439 440 panel = Float3dDialog(base=self, data=data, 464 465 panel = Float3dDialog(base=self, data=data, 441 466 dimension=3, id=wx.NewId()) 442 panel.ShowModal() 443 467 panel.ShowModal() 468 444 469 def on_quick_plot(self, event): 445 470 """ … … 450 475 dimension = 2 451 476 else: 452 dimension = 1 453 #panel = QucikPlotDialog(base=self, data=data, 477 dimension = 1 478 #panel = QucikPlotDialog(base=self, data=data, 454 479 # dimension=dimension, id=wx.NewId()) 455 480 frame = QucikPlotDialog(self, -1, "Plot " + data.name, 'log_{10}') … … 459 484 frame.Show(True) 460 485 frame.SetFocus() 461 #panel.ShowModal() 462 486 #panel.ShowModal() 487 463 488 def on_data_info(self, event): 464 489 """ … … 470 495 else: 471 496 self.parent.show_data1d(data, data.name) 472 497 473 498 def on_save_as(self, event): 474 499 """ … … 488 513 else: 489 514 print "unable to save this type of data" 490 515 491 516 def layout_data_list(self): 492 517 """ … … 505 530 self.data_menu.Append(id, name, msg) 506 531 wx.EVT_MENU(self, id, self.on_data_info) 507 532 508 533 id = wx.NewId() 509 534 name = "Save As" … … 511 536 self.data_menu.Append(id, name, msg) 512 537 wx.EVT_MENU(self, id, self.on_save_as) 513 538 514 539 quickplot_id = wx.NewId() 515 540 name = "Quick Plot" … … 517 542 self.data_menu.Append(quickplot_id, name, msg) 518 543 wx.EVT_MENU(self, quickplot_id, self.on_quick_plot) 519 544 520 545 self.plot3d_id = wx.NewId() 521 546 name = "Quick 3DPlot (Slow)" … … 523 548 self.data_menu.Append(self.plot3d_id, name, msg) 524 549 wx.EVT_MENU(self, self.plot3d_id, self.on_plot_3d) 525 550 526 551 self.editmask_id = wx.NewId() 527 552 name = "Edit Mask" … … 529 554 self.data_menu.Append(self.editmask_id, name, msg) 530 555 wx.EVT_MENU(self, self.editmask_id, self.on_edit_data) 531 556 532 557 tree_ctrl_theory_label = wx.StaticText(self, -1, "Theory") 533 558 tree_ctrl_theory_label.SetForegroundColour('blue') 534 self.tree_ctrl_theory = DataTreeCtrl(parent=self, 559 self.tree_ctrl_theory = DataTreeCtrl(parent=self, 535 560 style=wx.SUNKEN_BORDER) 536 self.tree_ctrl_theory.Bind(CT.EVT_TREE_ITEM_CHECKING, 561 self.tree_ctrl_theory.Bind(CT.EVT_TREE_ITEM_CHECKING, 537 562 self.on_check_item) 538 self.tree_ctrl_theory.Bind(CT.EVT_TREE_ITEM_MENU, 563 self.tree_ctrl_theory.Bind(CT.EVT_TREE_ITEM_MENU, 539 564 self.on_right_click_theory) 540 565 self.sizer1.Add(tree_ctrl_label, 0, wx.LEFT, 10) … … 542 567 self.sizer1.Add(tree_ctrl_theory_label, 0, wx.LEFT, 10) 543 568 self.sizer1.Add(self.tree_ctrl_theory, 1, wx.EXPAND|wx.ALL, 10) 544 569 545 570 def on_right_click_theory(self, event): 546 571 """ … … 557 582 self.data_menu.Enable(self.editmask_id, False) 558 583 self.data_menu.Enable(self.plot3d_id, menu_enable) 559 self.PopupMenu(self.data_menu) 560 584 self.PopupMenu(self.data_menu) 585 561 586 def on_right_click_data(self, event): 562 587 """ … … 578 603 self.data_menu.Enable(self.editmask_id, maskmenu_enable) 579 604 self.data_menu.Enable(self.plot3d_id, menu_enable) 580 self.PopupMenu(self.data_menu) 581 582 def onContextMenu(self, event): 605 self.PopupMenu(self.data_menu) 606 607 def onContextMenu(self, event): 583 608 """ 584 609 Retrieve the state selected state … … 588 613 pos = event.GetPosition() 589 614 pos = self.ScreenToClient(pos) 590 self.PopupMenu(self.popUpMenu, pos) 591 592 615 self.PopupMenu(self.popUpMenu, pos) 616 617 593 618 def on_check_item(self, event): 594 619 """ … … 596 621 """ 597 622 item = event.GetItem() 598 item.Check(not item.IsChecked()) 623 item.Check(not item.IsChecked()) 599 624 self.enable_append() 600 625 self.enable_freeze() … … 603 628 self.enable_remove() 604 629 event.Skip() 605 630 606 631 def fill_cbox_analysis(self, plugin): 607 632 """ … … 617 642 if plug.get_perspective(): 618 643 self.perspective_cbox.Append(plug.sub_menu, plug) 619 644 620 645 curr_pers = self.parent.get_current_perspective() 621 646 if curr_pers: 622 647 self.perspective_cbox.SetStringSelection(curr_pers.sub_menu) 623 648 self.enable_import() 624 649 625 650 def load_data_list(self, list): 626 651 """ … … 636 661 data_run = str(data.run) 637 662 data_class = data.__class__.__name__ 638 path = dstate.get_path() 663 path = dstate.get_path() 639 664 process_list = data.process 640 665 data_id = data.id … … 643 668 #new state 644 669 data_c = self.tree_ctrl.InsertItem(self.tree_ctrl.root, 645 0, data_name, ct_type=1, 670 0, data_name, ct_type=1, 646 671 data=(data_id, data_class, state_id)) 647 672 data_c.Check(True) 648 673 d_i_c = self.tree_ctrl.AppendItem(data_c, 'Info') 649 d_t_c = self.tree_ctrl.AppendItem(d_i_c, 674 d_t_c = self.tree_ctrl.AppendItem(d_i_c, 650 675 'Title: %s' % data_title) 651 r_n_c = self.tree_ctrl.AppendItem(d_i_c, 676 r_n_c = self.tree_ctrl.AppendItem(d_i_c, 652 677 'Run: %s' % data_run) 653 i_c_c = self.tree_ctrl.AppendItem(d_i_c, 678 i_c_c = self.tree_ctrl.AppendItem(d_i_c, 654 679 'Type: %s' % data_class) 655 680 p_c_c = self.tree_ctrl.AppendItem(d_i_c, 656 681 "Path: '%s'" % s_path) 657 682 d_p_c = self.tree_ctrl.AppendItem(d_i_c, 'Process') 658 683 659 684 for process in process_list: 660 685 process_str = str(process).replace('\n',' ') … … 662 687 process_str = process_str[:20]+' [...]' 663 688 self.tree_ctrl.AppendItem(d_p_c, process_str) 664 theory_child = self.tree_ctrl.AppendItem(data_c, 689 theory_child = self.tree_ctrl.AppendItem(data_c, 665 690 "THEORIES") 666 self.list_cb_data[state_id] = [data_c, 691 self.list_cb_data[state_id] = [data_c, 667 692 d_i_c, 668 693 d_t_c, … … 677 702 data_c, d_i_c, d_t_c, r_n_c, i_c_c, p_c_c, d_p_c, _ \ 678 703 = data_ctrl_list 679 self.tree_ctrl.SetItemText(data_c, data_name) 704 self.tree_ctrl.SetItemText(data_c, data_name) 680 705 temp = (data_id, data_class, state_id) 681 self.tree_ctrl.SetItemPyData(data_c, temp) 682 self.tree_ctrl.SetItemText(i_c_c, 706 self.tree_ctrl.SetItemPyData(data_c, temp) 707 self.tree_ctrl.SetItemText(i_c_c, 683 708 'Type: %s' % data_class) 684 self.tree_ctrl.SetItemText(p_c_c, 685 'Path: %s' % s_path) 686 self.tree_ctrl.DeleteChildren(d_p_c) 709 self.tree_ctrl.SetItemText(p_c_c, 710 'Path: %s' % s_path) 711 self.tree_ctrl.DeleteChildren(d_p_c) 687 712 for process in process_list: 688 713 if not process.is_empty(): … … 692 717 # Sort by data name 693 718 if self.tree_ctrl.root: 694 self.tree_ctrl.SortChildren(self.tree_ctrl.root) 719 self.tree_ctrl.SortChildren(self.tree_ctrl.root) 695 720 self.enable_remove() 696 721 self.enable_import() … … 698 723 self.enable_freeze() 699 724 self.enable_selection() 700 725 701 726 def _uncheck_all(self): 702 727 """ … … 705 730 for item in self.list_cb_data.values(): 706 731 data_ctrl, _, _, _, _, _, _, _ = item 707 self.tree_ctrl.CheckItem(data_ctrl, False) 732 self.tree_ctrl.CheckItem(data_ctrl, False) 708 733 self.enable_append() 709 734 self.enable_freeze() … … 711 736 self.enable_import() 712 737 self.enable_remove() 713 738 714 739 def append_theory(self, state_id, theory_list): 715 740 """ … … 718 743 """ 719 744 if not theory_list: 720 return 745 return 721 746 if state_id not in self.list_cb_data.keys(): 722 747 root = self.tree_ctrl_theory.root … … 728 753 tree = self.tree_ctrl 729 754 if root is not None: 730 wx.CallAfter(self.append_theory_helper, tree=tree, root=root, 731 state_id=state_id, 755 wx.CallAfter(self.append_theory_helper, tree=tree, root=root, 756 state_id=state_id, 732 757 theory_list=theory_list) 733 734 758 759 735 760 def append_theory_helper(self, tree, root, state_id, theory_list): 736 761 """ … … 760 785 name, ct_type=1, data=temp) 761 786 t_i_c = tree.AppendItem(t_child, 'Info') 762 i_c_c = tree.AppendItem(t_i_c, 787 i_c_c = tree.AppendItem(t_i_c, 763 788 'Type: %s' % theory_class) 764 789 t_p_c = tree.AppendItem(t_i_c, 'Process') 765 790 766 791 for process in theory_data.process: 767 792 tree.AppendItem(t_p_c, process.__str__()) 768 theory_list_ctrl[theory_id] = [t_child, 769 i_c_c, 793 theory_list_ctrl[theory_id] = [t_child, 794 i_c_c, 770 795 t_p_c] 771 796 else: 772 797 #replace theory 773 798 t_child, i_c_c, t_p_c = theory_list_ctrl[theory_id] 774 tree.SetItemText(t_child, name) 775 tree.SetItemPyData(t_child, temp) 776 tree.SetItemText(i_c_c, 'Type: %s' % theory_class) 777 tree.DeleteChildren(t_p_c) 799 tree.SetItemText(t_child, name) 800 tree.SetItemPyData(t_child, temp) 801 tree.SetItemText(i_c_c, 'Type: %s' % theory_class) 802 tree.DeleteChildren(t_p_c) 778 803 for process in theory_data.process: 779 804 tree.AppendItem(t_p_c, process.__str__()) 780 805 781 806 else: 782 807 #data didn't have a theory associated it before … … 789 814 theory_id = theory_data.id 790 815 #if theory_state is not None: 791 # name = theory_state.model.name 816 # name = theory_state.model.name 792 817 temp = (theory_id, theory_class, state_id) 793 818 t_child = tree.AppendItem(root, 794 name, ct_type=1, 819 name, ct_type=1, 795 820 data=(theory_data.id, theory_class, state_id)) 796 821 t_i_c = tree.AppendItem(t_child, 'Info') 797 i_c_c = tree.AppendItem(t_i_c, 822 i_c_c = tree.AppendItem(t_i_c, 798 823 'Type: %s' % theory_class) 799 824 t_p_c = tree.AppendItem(t_i_c, 'Process') 800 825 801 826 for process in theory_data.process: 802 827 tree.AppendItem(t_p_c, process.__str__()) 803 828 804 829 theory_list_ctrl[theory_id] = [t_child, i_c_c, t_p_c] 805 830 #self.list_cb_theory[data_id] = theory_list_ctrl 806 831 self.list_cb_theory[state_id] = theory_list_ctrl 807 808 809 832 833 834 810 835 def set_data_helper(self): 811 836 """ … … 822 847 if state_id not in state_to_plot: 823 848 state_to_plot.append(state_id) 824 849 825 850 for theory_dict in self.list_cb_theory.values(): 826 851 for _, value in theory_dict.iteritems(): … … 832 857 state_to_plot.append(state_id) 833 858 return data_to_plot, theory_to_plot, state_to_plot 834 859 835 860 def remove_by_id(self, id): 836 861 """ … … 839 864 for item in self.list_cb_data.values(): 840 865 data_c, _, _, _, _, _, _, _ = item 841 data_id, _, state_id = self.tree_ctrl.GetItemPyData(data_c) 866 data_id, _, state_id = self.tree_ctrl.GetItemPyData(data_c) 842 867 if id == data_id: 843 868 self.tree_ctrl.Delete(data_c) 844 869 del self.list_cb_data[state_id] 845 870 del self.list_cb_theory[data_id] 846 871 847 872 def load_error(self, error=None): 848 873 """ 849 874 Pop up an error message. 850 875 851 876 :param error: details error message to be displayed 852 877 """ 853 878 if error is not None or str(error).strip() != "": 854 dial = wx.MessageDialog(self.parent, str(error), 879 dial = wx.MessageDialog(self.parent, str(error), 855 880 'Error Loading File', 856 881 wx.OK | wx.ICON_EXCLAMATION) 857 dial.ShowModal() 858 882 dial.ShowModal() 883 859 884 def _load_data(self, event): 860 885 """ … … 863 888 if self.parent is not None: 864 889 wx.PostEvent(self.parent, NewLoadDataEvent()) 865 890 866 891 867 892 def on_remove(self, event): 868 893 """ 869 894 Get a list of item checked and remove them from the treectrl 870 Ask the parent to remove reference to this item 895 Ask the parent to remove reference to this item 871 896 """ 872 897 msg = "This operation will delete the data sets checked " … … 875 900 if msg_box.ShowModal() != wx.ID_OK: 876 901 return 877 902 878 903 data_to_remove, theory_to_remove, _ = self.set_data_helper() 879 904 data_key = [] … … 888 913 theory_list_ctrl = self.list_cb_theory[d_key] 889 914 theory_to_remove += theory_list_ctrl.keys() 890 # Remove theory from treectrl 915 # Remove theory from treectrl 891 916 for _, theory_dict in self.list_cb_theory.iteritems(): 892 917 for key, value in theory_dict.iteritems(): … … 898 923 pass 899 924 theory_key.append(key) 900 925 901 926 #Remove data and related theory references 902 927 for key in data_key: … … 916 941 pass 917 942 del theory_dict[key] 918 919 943 944 920 945 self.parent.remove_data(data_id=data_to_remove, 921 946 theory_id=theory_to_remove) … … 923 948 self.enable_freeze() 924 949 self.enable_remove_plot() 925 950 926 951 def on_import(self, event=None): 927 952 """ … … 933 958 temp = data_id + state_id 934 959 self.parent.set_data(data_id=temp, theory_id=theory_id) 935 960 936 961 def on_append_plot(self, event=None): 937 962 """ … … 940 965 self._on_plot_selection() 941 966 data_id, theory_id, state_id = self.set_data_helper() 942 self.parent.plot_data(data_id=data_id, 967 self.parent.plot_data(data_id=data_id, 943 968 state_id=state_id, 944 969 theory_id=theory_id, 945 970 append=True) 946 971 947 972 def on_plot(self, event=None): 948 973 """ … … 950 975 """ 951 976 data_id, theory_id, state_id = self.set_data_helper() 952 self.parent.plot_data(data_id=data_id, 977 self.parent.plot_data(data_id=data_id, 953 978 state_id=state_id, 954 979 theory_id=theory_id, 955 980 append=False) 956 981 self.enable_remove_plot() 957 982 958 983 def on_close_page(self, event=None): 959 984 """ … … 964 989 # send parent to update menu with no show nor hide action 965 990 self.parent.show_data_panel(action=False) 966 991 967 992 def on_freeze(self, event): 968 993 """ … … 977 1002 msg = "Freeze Theory: Requires at least one theory checked." 978 1003 wx.PostEvent(self.parent, StatusEvent(status=msg)) 979 1004 980 1005 def set_active_perspective(self, name): 981 1006 """ … … 984 1009 self.perspective_cbox.SetStringSelection(name) 985 1010 self.enable_import() 986 1011 987 1012 def _on_delete_plot_panel(self, event): 988 1013 """ 989 get an event with attribute name and caption to delete existing name 1014 get an event with attribute name and caption to delete existing name 990 1015 from the combobox of the current panel 991 1016 """ … … 993 1018 caption = event.caption 994 1019 if self.cb_plotpanel is not None: 995 pos = self.cb_plotpanel.FindString(str(caption)) 1020 pos = self.cb_plotpanel.FindString(str(caption)) 996 1021 if pos != wx.NOT_FOUND: 997 1022 self.cb_plotpanel.Delete(pos) 998 1023 self.enable_append() 999 1024 1000 1025 def set_panel_on_focus(self, name=None): 1001 1026 """ … … 1013 1038 self.enable_append() 1014 1039 self.enable_remove_plot() 1015 1040 1016 1041 def set_plot_unfocus(self): 1017 1042 """ … … 1019 1044 """ 1020 1045 return 1021 1046 1022 1047 def _on_perspective_selection(self, event=None): 1023 1048 """ … … 1029 1054 perspective.on_perspective(event=None) 1030 1055 self.parent.check_multimode(perspective=perspective) 1031 1056 1032 1057 def _on_plot_selection(self, event=None): 1033 1058 """ … … 1043 1068 if combo.GetValue() != 'None': 1044 1069 panel = combo.GetClientData(selection) 1045 self.parent.on_set_plot_focus(panel) 1046 1070 self.parent.on_set_plot_focus(panel) 1071 1047 1072 def on_close_plot(self, event): 1048 1073 """ 1049 1074 clseo the panel on focus 1050 """ 1075 """ 1051 1076 self.enable_append() 1052 1077 selection = self.cb_plotpanel.GetSelection() … … 1054 1079 panel = self.cb_plotpanel.GetClientData(selection) 1055 1080 if self.parent is not None and panel is not None: 1056 wx.PostEvent(self.parent, 1081 wx.PostEvent(self.parent, 1057 1082 NewPlotEvent(group_id=panel.group_id, 1058 1083 action="delete")) 1059 1084 self.enable_remove_plot() 1060 1085 1061 1086 def set_frame(self, frame): 1062 1087 """ 1063 1088 """ 1064 1089 self.frame = frame 1065 1090 1066 1091 def get_frame(self): 1067 1092 """ 1068 1093 """ 1069 return self.frame 1070 1094 return self.frame 1095 1096 def on_help(self, event): 1097 """ 1098 Bring up the data manager Documentation whenever 1099 the HELP button is clicked. 1100 1101 Calls DocumentationWindow with the path of the location within the 1102 documentation tree (after /doc/ ....". Note that when using old 1103 versions of Wx (before 2.9) and thus not the release version of 1104 installers, the help comes up at the top level of the file as 1105 webbrowser does not pass anything past the # to the browser when it is 1106 running "file:///...." 1107 1108 :param evt: Triggers on clicking the help button 1109 """ 1110 1111 #import documentation window here to avoid circular imports 1112 #if put at top of file with rest of imports. 1113 from documentation_window import DocumentationWindow 1114 1115 _TreeLocation = "user/sasgui/guiframe/data_explorer_help.html" 1116 _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, "", 1117 "Data Explorer Help") 1118 1071 1119 def on_close(self, event): 1072 1120 """ … … 1074 1122 """ 1075 1123 self.parent.show_data_panel(event) 1076 1124 1077 1125 def set_schedule_full_draw(self, panel=None, func='del'): 1078 1126 """ … … 1080 1128 """ 1081 1129 self.parent.set_schedule_full_draw(panel, func) 1082 1130 1083 1131 def enable_remove_plot(self): 1084 1132 """ … … 1090 1138 #else: 1091 1139 # self.bt_close_plot.Enable() 1092 1140 1093 1141 def enable_remove(self): 1094 1142 """ … … 1101 1149 else: 1102 1150 self.bt_remove.Enable() 1103 1151 1104 1152 def enable_import(self): 1105 1153 """ … … 1119 1167 else: 1120 1168 self.perspective_cbox.Enable() 1121 1169 1122 1170 def enable_plot(self): 1123 1171 """ 1124 1172 enable or disable plot button 1125 1173 """ 1126 n_t = 0 1174 n_t = 0 1127 1175 n_t_t = 0 1128 1176 if self.tree_ctrl != None: … … 1135 1183 self.bt_plot.Enable() 1136 1184 self.enable_append() 1137 1185 1138 1186 def enable_append(self): 1139 1187 """ 1140 1188 enable or disable append button 1141 1189 """ 1142 n_t = 0 1190 n_t = 0 1143 1191 n_t_t = 0 1144 1192 if self.tree_ctrl != None: … … 1146 1194 if self.tree_ctrl_theory != None: 1147 1195 n_t_t = self.tree_ctrl_theory.GetCount() 1148 if n_t + n_t_t <= 0: 1196 if n_t + n_t_t <= 0: 1149 1197 self.bt_append_plot.Disable() 1150 1198 self.cb_plotpanel.Disable() … … 1155 1203 self.bt_append_plot.Enable() 1156 1204 self.cb_plotpanel.Enable() 1157 1205 1158 1206 def check_theory_to_freeze(self): 1159 1207 """ … … 1173 1221 else: 1174 1222 self.bt_freeze.Disable() 1175 1223 1176 1224 def enable_selection(self): 1177 1225 """ … … 1188 1236 else: 1189 1237 self.selection_cbox.Disable() 1190 1238 1191 1239 def show_data_button(self): 1192 1240 """ 1193 show load data and remove data button if 1241 show load data and remove data button if 1194 1242 dataloader on else hide them 1195 1243 """ … … 1197 1245 gui_style = self.parent.get_style() 1198 1246 style = gui_style & GUIFRAME.DATALOADER_ON 1199 if style == GUIFRAME.DATALOADER_ON: 1247 if style == GUIFRAME.DATALOADER_ON: 1200 1248 #self.bt_remove.Show(True) 1201 self.bt_add.Show(True) 1249 self.bt_add.Show(True) 1202 1250 else: 1203 1251 #self.bt_remove.Hide() 1204 1252 self.bt_add.Hide() 1205 except: 1253 except: 1206 1254 #self.bt_remove.Hide() 1207 self.bt_add.Hide() 1208 1255 self.bt_add.Hide() 1256 1209 1257 1210 1258 … … 1223 1271 self.list_of_ctrl = [] 1224 1272 if not data_list: 1225 return 1273 return 1226 1274 self._sizer_main = wx.BoxSizer(wx.VERTICAL) 1227 1275 self._sizer_txt = wx.BoxSizer(wx.VERTICAL) … … 1232 1280 self._panel.SetupScrolling() 1233 1281 self.__do_layout(data_list, text=text) 1234 1282 1235 1283 def __do_layout(self, data_list, text=''): 1236 1284 """ … … 1238 1286 """ 1239 1287 if not data_list or len(data_list) <= 1: 1240 return 1288 return 1241 1289 #add text 1242 1290 1243 1291 text = "Deleting these file reset some panels.\n" 1244 1292 text += "Do you want to proceed?\n" … … 1274 1322 wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10) 1275 1323 static_line = wx.StaticLine(self, -1) 1276 1324 1277 1325 self._sizer_txt.Add(self._panel, 1, wx.EXPAND|wx.LEFT|wx.RIGHT, 5) 1278 1326 self._sizer_main.Add(self._sizer_txt, 1, wx.EXPAND|wx.ALL, 10) 1279 #self._sizer_main.Add(self._data_text_ctrl, 0, 1327 #self._sizer_main.Add(self._data_text_ctrl, 0, 1280 1328 # wx.EXPAND|wx.LEFT|wx.RIGHT, 10) 1281 1329 self._sizer_main.Add(static_line, 0, wx.EXPAND, 0) … … 1283 1331 self.SetSizer(self._sizer_main) 1284 1332 self.Layout() 1285 1333 1286 1334 def get_data(self): 1287 1335 """ … … 1294 1342 temp.append(data) 1295 1343 return temp 1296 1344 1297 1345 class DataFrame(wx.Frame): 1298 1346 """ … … 1306 1354 # tied to any perspective 1307 1355 ALWAYS_ON = True 1308 1356 1309 1357 def __init__(self, parent=None, owner=None, manager=None, size=(300, 800), 1310 1358 list_of_perspective=[], list=[], *args, **kwds): … … 1316 1364 self.owner = owner 1317 1365 self._manager = manager 1318 self.panel = DataPanel(parent=self, 1366 self.panel = DataPanel(parent=self, 1319 1367 manager=manager, 1320 1368 list_of_perspective=list_of_perspective) 1321 1369 1322 1370 def load_data_list(self, list=[]): 1323 1371 """ … … 1325 1373 """ 1326 1374 self.panel.load_data_list(list=list) 1327 1328 1329 1375 1376 1377 1330 1378 from sas.sasgui.guiframe.dataFitting import Theory1D 1331 1379 from sas.sasgui.guiframe.data_state import DataState … … 1342 1390 self.msg += "name value\n" 1343 1391 return self.msg 1344 1392 1345 1393 def set_data_state(data=None, path=None, theory=None, state=None): 1346 1394 """ … … 1350 1398 dstate.set_path(path=path) 1351 1399 dstate.set_theory(theory, state) 1352 1400 1353 1401 return dstate 1354 1402 1355 1403 if __name__ == "__main__": 1356 1404 1357 1405 app = wx.App() 1358 1406 try: … … 1436 1484 #raise 1437 1485 print "error", sys.exc_value 1438 1439 app.MainLoop() 1440 1441 1486 1487 app.MainLoop() -
src/sas/sasgui/guiframe/local_perspectives/data_loader/data_loader.py
rfaa3ae7 ra674d0b 162 162 logging.error("Loader returned an invalid object:\n %s" % str(item)) 163 163 data_error = True 164 164 165 165 data = self.parent.create_gui_data(item, p_file) 166 166 output[data.id] = data … … 170 170 """ 171 171 """ 172 message = "" 173 log_msg = '' 172 file_errors = {} 174 173 output = {} 175 any_error = False 176 data_error = False 177 error_message = "" 174 exception_occurred = False 175 178 176 for p_file in path: 179 info = "info"180 177 basename = os.path.basename(p_file) 181 178 _, extension = os.path.splitext(basename) 182 179 if extension.lower() in EXTENSIONS: 183 any_error = True184 180 log_msg = "Data Loader cannot " 185 log_msg += "load: %s\n" % str(p_file) 186 log_msg += """Please try to open that file from "open project" """ 187 log_msg += """or "open analysis" menu\n""" 188 error_message = log_msg + "\n" 181 log_msg += "load: {}\n".format(str(p_file)) 182 log_msg += "Please try to open that file from \"open project\"" 183 log_msg += "or \"open analysis\" menu." 189 184 logging.info(log_msg) 185 file_errors[basename] = [log_msg] 190 186 continue 191 187 192 188 try: 193 message = "Loading Data... " + str(p_file) + "\n"194 self.load_update(output=output, message=message, info= info)189 message = "Loading {}...\n".format(p_file) 190 self.load_update(output=output, message=message, info="info") 195 191 temp = self.loader.load(p_file, format) 196 if temp.__class__.__name__ == "list": 197 for item in temp: 198 output, error_message, data_error = \ 199 self._process_data_and_errors(item, 200 p_file, 201 output, 202 error_message) 203 else: 192 if not isinstance(temp, list): 193 temp = [temp] 194 for item in temp: 195 error_message = "" 204 196 output, error_message, data_error = \ 205 self._process_data_and_errors(temp, 206 p_file, 207 output, 208 error_message) 197 self._process_data_and_errors(item, 198 p_file, 199 output, 200 error_message) 201 if data_error: 202 if basename in file_errors.keys(): 203 file_errors[basename] += [error_message] 204 else: 205 file_errors[basename] = [error_message] 206 self.load_update(output=output, 207 message=error_message, info="warning") 208 209 self.load_update(output=output, 210 message="Loaded {}\n".format(p_file), 211 info="info") 212 209 213 except: 210 214 logging.error(sys.exc_value) 211 any_error = True 212 if any_error or error_message != "": 213 if error_message == "": 214 error = "Error: " + str(sys.exc_info()[1]) + "\n" 215 error += "while loading Data: \n%s\n" % str(basename) 216 error_message += "The data file you selected could not be loaded.\n" 217 error_message += "Make sure the content of your file" 218 error_message += " is properly formatted.\n\n" 219 error_message += "When contacting the SasView team, mention the" 220 error_message += " following:\n%s" % str(error) 221 elif data_error: 222 base_message = "Errors occurred while loading " 223 base_message += "{0}\n".format(basename) 224 base_message += "The data file loaded but with errors.\n" 225 error_message = base_message + error_message 226 else: 227 error_message += "%s\n" % str(p_file) 228 info = "error" 229 230 if any_error or error_message: 231 self.load_update(output=output, message=error_message, info=info) 232 else: 233 message = "Loading Data Complete! " 234 message += log_msg 235 self.load_complete(output=output, error_message=error_message, 236 message=message, path=path, info='info') 215 216 error_message = "The Data file you selected could not be loaded.\n" 217 error_message += "Make sure the content of your file" 218 error_message += " is properly formatted.\n" 219 error_message += "When contacting the SasView team, mention the" 220 error_message += " following:\n" 221 error_message += "Error: " + str(sys.exc_info()[1]) 222 file_errors[basename] = [error_message] 223 self.load_update(output=output, message=error_message, info="warning") 224 225 if len(file_errors) > 0: 226 error_message = "" 227 for filename, error_array in file_errors.iteritems(): 228 error_message += "The following errors occured whilst " 229 error_message += "loading {}:\n".format(filename) 230 for message in error_array: 231 error_message += message + "\n" 232 error_message += "\n" 233 self.load_update(output=output, message=error_message, info="error") 234 235 self.load_complete(output=output, message="Loading data complete!", 236 info="info") 237 237 238 238 def load_update(self, output=None, message="", info="warning"): … … 254 254 # self.load_error(error_message) 255 255 self.parent.add_data(data_list=output) 256 257 258 -
src/sas/sasgui/guiframe/local_perspectives/plotting/Plotter1D.py
rd85c194 r895c9cb 527 527 self.subplot.set_xlim((xlo, xhi)) 528 528 self.subplot.set_ylim((ylo, yhi)) 529 self.graph.selected_plottable = None 529 530 530 531 … … 555 556 self._slicerpop.set_graph(self.graph) 556 557 ids = iter(self._menu_ids) 557 if not self.graph.selected_plottable in self.plots: 558 559 560 561 562 563 564 565 566 567 568 569 570 571 558 559 # Various plot options 560 wx_id = ids.next() 561 self._slicerpop.Append(wx_id, '&Save Image', 'Save image as PNG') 562 wx.EVT_MENU(self, wx_id, self.onSaveImage) 563 wx_id = ids.next() 564 self._slicerpop.Append(wx_id, '&Print Image', 'Print image ') 565 wx.EVT_MENU(self, wx_id, self.onPrint) 566 567 wx_id = ids.next() 568 self._slicerpop.Append(wx_id, '&Copy to Clipboard', 569 'Copy to the clipboard') 570 wx.EVT_MENU(self, wx_id, self.OnCopyFigureMenu) 571 572 self._slicerpop.AppendSeparator() 572 573 573 574 for plot in self.plots.values(): … … 592 593 item_list = self.parent.get_current_context_menu(self) 593 594 if (not item_list == None) and (not len(item_list) == 0): 594 # Note: reusing menu ids in submenu. This code works because 595 # IdItems is set up as a lazy iterator returning each id in 596 # sequence, creating new ids as needed so it never runs out. 597 # zip() is set up to stop when any iterator is empty, so it 598 # only asks for the number of ids in item_list. 599 for item, wx_id in zip(item_list, self._menu_ids): 595 for item, wx_id in zip(item_list, [ids.next() for i in range(len(item_list))]): 600 596 601 597 try: … … 609 605 610 606 if self.parent.ClassName.count('wxDialog') == 0: 611 wx_id = ids.next() 612 plot_menu.Append(wx_id, '&Linear Fit', name) 613 wx.EVT_MENU(self, wx_id, self.onFitting) 614 plot_menu.AppendSeparator() 607 if plot.id != 'fit': 608 wx_id = ids.next() 609 plot_menu.Append(wx_id, '&Linear Fit', name) 610 wx.EVT_MENU(self, wx_id, self.onFitting) 611 plot_menu.AppendSeparator() 615 612 616 613 wx_id = ids.next() … … 646 643 # Option to hide 647 644 # TODO: implement functionality to hide a plottable (legend click) 648 if not self.graph.selected_plottable in self.plots: 645 646 self._slicerpop.AppendSeparator() 647 loc_menu = wx.Menu() 648 for label in self._loc_labels: 649 wx_id = ids.next() 650 loc_menu.Append(wx_id, str(label), str(label)) 651 wx.EVT_MENU(self, wx_id, self.onChangeLegendLoc) 652 653 wx_id = ids.next() 654 self._slicerpop.Append(wx_id, '&Modify Graph Appearance', 655 'Modify graph appearance') 656 wx.EVT_MENU(self, wx_id, self.modifyGraphAppearance) 657 self._slicerpop.AppendSeparator() 658 659 660 if self.position != None: 661 wx_id = ids.next() 662 self._slicerpop.Append(wx_id, '&Add Text') 663 wx.EVT_MENU(self, wx_id, self._on_addtext) 664 wx_id = ids.next() 665 self._slicerpop.Append(wx_id, '&Remove Text') 666 wx.EVT_MENU(self, wx_id, self._on_removetext) 649 667 self._slicerpop.AppendSeparator() 650 loc_menu = wx.Menu() 651 for label in self._loc_labels: 652 wx_id = ids.next() 653 loc_menu.Append(wx_id, str(label), str(label)) 654 wx.EVT_MENU(self, wx_id, self.onChangeLegendLoc) 655 656 wx_id = ids.next() 657 self._slicerpop.Append(wx_id, '&Modify Graph Appearance', 658 'Modify graph appearance') 659 wx.EVT_MENU(self, wx_id, self.modifyGraphAppearance) 660 self._slicerpop.AppendSeparator() 661 662 663 if self.position != None: 664 wx_id = ids.next() 665 self._slicerpop.Append(wx_id, '&Add Text') 666 wx.EVT_MENU(self, wx_id, self._on_addtext) 667 wx_id = ids.next() 668 self._slicerpop.Append(wx_id, '&Remove Text') 669 wx.EVT_MENU(self, wx_id, self._on_removetext) 670 self._slicerpop.AppendSeparator() 671 wx_id = ids.next() 672 self._slicerpop.Append(wx_id, '&Change Scale') 673 wx.EVT_MENU(self, wx_id, self._onProperties) 668 wx_id = ids.next() 669 self._slicerpop.Append(wx_id, '&Change Scale') 670 wx.EVT_MENU(self, wx_id, self._onProperties) 671 self._slicerpop.AppendSeparator() 672 wx_id = ids.next() 673 self._slicerpop.Append(wx_id, '&Set Graph Range') 674 wx.EVT_MENU(self, wx_id, self.onSetRange) 675 wx_id = ids.next() 676 self._slicerpop.Append(wx_id, '&Reset Graph Range') 677 wx.EVT_MENU(self, wx_id, self.onResetGraph) 678 679 if self.parent.ClassName.count('wxDialog') == 0: 674 680 self._slicerpop.AppendSeparator() 675 681 wx_id = ids.next() 676 self._slicerpop.Append(wx_id, '&Reset Graph Range') 677 wx.EVT_MENU(self, wx_id, self.onResetGraph) 678 679 if self.parent.ClassName.count('wxDialog') == 0: 680 self._slicerpop.AppendSeparator() 681 wx_id = ids.next() 682 self._slicerpop.Append(wx_id, '&Window Title') 683 wx.EVT_MENU(self, wx_id, self.onChangeCaption) 682 self._slicerpop.Append(wx_id, '&Window Title') 683 wx.EVT_MENU(self, wx_id, self.onChangeCaption) 684 684 try: 685 685 pos_evt = event.GetPosition() … … 689 689 pos = (pos_x, pos_y + 5) 690 690 self.PopupMenu(self._slicerpop, pos) 691 692 def onSetRange(self, event): 693 # Display dialog 694 # self.subplot.set_xlim((low, high)) 695 # self.subplot.set_ylim((low, high)) 696 from sas.sasgui.plottools.RangeDialog import RangeDialog 697 d = RangeDialog(self, -1) 698 xlim = self.subplot.get_xlim() 699 ylim = self.subplot.get_ylim() 700 d.SetXRange(xlim) 701 d.SetYRange(ylim) 702 if d.ShowModal() == wx.ID_OK: 703 x_range = d.GetXRange() 704 y_range = d.GetYRange() 705 if x_range is not None and y_range is not None: 706 self.subplot.set_xlim(x_range) 707 self.subplot.set_ylim(y_range) 708 self.subplot.figure.canvas.draw_idle() 709 d.Destroy() 691 710 692 711 def onFreeze(self, event): … … 776 795 int(curr_symbol))), curr_label) 777 796 self.appD.Bind(wx.EVT_CLOSE, self.on_AppDialog_close) 797 self.graph.selected_plottable = None 778 798 779 799 def on_AppDialog_close(self, event): -
src/sas/sasgui/guiframe/local_perspectives/plotting/Plotter2D.py
rd85c194 r1a696bf 293 293 294 294 wx_id = ids.next() 295 slicerpop.Append(wx_id, '&Save Image' )295 slicerpop.Append(wx_id, '&Save Image', 'Save image as png') 296 296 wx.EVT_MENU(self, wx_id, self.onSaveImage) 297 297 … … 320 320 if (not item_list == None) and (not len(item_list) == 0) and\ 321 321 self.data2D.name.split(" ")[0] != 'Residuals': 322 # The line above; Not for trunk 323 # Note: reusing menu ids for the sub-menus. See Plotter1D. 324 for item, wx_id in zip(item_list, self._menu_ids): 322 for item, wx_id in zip(item_list, [ids.next() for i in range(len(item_list))]): 325 323 try: 326 324 slicerpop.Append(wx_id, item[0], item[1]) -
src/sas/sasgui/guiframe/local_perspectives/plotting/SimplePlot.py
rd85c194 r25b9707a 188 188 """ 189 189 def __init__(self, parent, id, title, scale='log_{10}', 190 size=wx.Size(550, 470) ):190 size=wx.Size(550, 470), show_menu_icons=True): 191 191 """ 192 192 comment … … 202 202 self._default_save_location = None 203 203 self.scale = scale 204 self._show_menu_icons = show_menu_icons 204 205 self.plotpanel = SimplePlotPanel(self, -1) 205 206 self._build_menubar() … … 213 214 quit_bmp = wx.ArtProvider.GetBitmap(wx.ART_QUIT, wx.ART_TOOLBAR, tsize) 214 215 print_bmp = wx.ArtProvider.GetBitmap(wx.ART_PRINT, wx.ART_TOOLBAR, tsize) 215 preview_bmp = wx.ArtProvider.GetBitmap(wx.ART_REPORT_VIEW, wx.ART_TOOLBAR, tsize)216 216 copy_bmp = wx.ArtProvider.GetBitmap(wx.ART_COPY, wx.ART_TOOLBAR, tsize) 217 217 menu_bar = wx.MenuBar() … … 219 219 menu = wx.Menu() 220 220 id = wx.NewId() 221 item = wx.MenuItem(menu, id, "&Save Image") 222 item.SetBitmap(save_bmp) 223 menu.AppendItem(item) 221 save_item = wx.MenuItem(menu, id, "&Save Image") 222 menu.AppendItem(save_item) 224 223 wx.EVT_MENU(self, id, self.on_save_file) 225 224 226 225 id = wx.NewId() 227 item = wx.MenuItem(menu, id, "&Print Image") 228 item.SetBitmap(print_bmp) 229 menu.AppendItem(item) 226 print_item = wx.MenuItem(menu, id, "&Print Image") 227 menu.AppendItem(print_item) 230 228 wx.EVT_MENU(self, id, self.on_print_image) 231 229 232 230 menu.AppendSeparator() 233 231 id = wx.NewId() 234 item = wx.MenuItem(menu, id, "&Quit") 235 item.SetBitmap(quit_bmp) 236 menu.AppendItem(item) 232 quit_item = wx.MenuItem(menu, id, "&Quit") 233 menu.AppendItem(quit_item) 237 234 238 235 menu_bar.Append(menu, "&File") … … 241 238 menu_edit = wx.Menu() 242 239 id = wx.NewId() 243 item = wx.MenuItem(menu_edit, id, "&Copy") 244 item.SetBitmap(copy_bmp) 245 menu_edit.AppendItem(item) 240 copy_item = wx.MenuItem(menu_edit, id, "&Copy") 241 menu_edit.AppendItem(copy_item) 246 242 wx.EVT_MENU(self, id, self.on_copy_image) 243 244 if self._show_menu_icons: 245 save_item.SetBitmap(save_bmp) 246 print_item.SetBitmap(print_bmp) 247 quit_item.SetBitmap(quit_bmp) 248 copy_item.SetBitmap(copy_bmp) 247 249 248 250 menu_bar.Append(menu_edit, "&Edit") … … 324 326 except: 325 327 self.Destroy() 326 -
src/sas/sasgui/guiframe/local_perspectives/plotting/detector_dialog.py
rd85c194 r8416a02 7 7 from sas.sasgui.guiframe.events import StatusEvent 8 8 from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as Canvas 9 from matplotlib importmpl9 import matplotlib as mpl 10 10 from matplotlib import pylab 11 11 # FONT size -
src/sas/sasgui/guiframe/media/data_explorer_help.rst
rd85c194 rb64b87c 20 20 21 21 *NOTE! When* Data Explorer *is hidden, all data loaded will be sent directly 22 to the current active analysis perspective, if possible. When* Data Explorer *is22 to the current active analysis, if possible. When* Data Explorer *is 23 23 shown, data go first to the* Data Explorer. 24 24 … … 116 116 117 117 Click on the *Send To* button to send the currently selected data to one of the 118 perspectives (for*Fitting*, *P(r) Inversion*, or *Invariant* calculation).118 available types of analysis (*Fitting*, *P(r) Inversion*, or *Invariant* calculation). 119 119 120 The *Single*/*Batch* mode radio buttons only apply to the *Fitting* perspective.120 The *Single*/*Batch* mode radio buttons only apply to *Fitting*. 121 121 122 122 *Batch mode* provides serial (batch) fitting with one model function, that is, -
src/sas/sasgui/guiframe/media/graph_help.rst
rf93b473f re68c9bf 20 20 ^^^^^^^^^^^^^^^^^^^^^^^ 21 21 22 To invoke the *Graph Menu* simply right-click on a data/theory plot, or click 23 the *Graph Menu* (bullet list) icon in the toolbar at the bottom of the plot. 22 To invoke the *Graph Menu* simply right-click on a data/theory plot, or click 23 the *Graph Menu* (bullet list) icon in the toolbar at the bottom of the plot. 24 24 Then select a menu item. 25 25 … … 27 27 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 28 28 29 To expand a plot window, click the *Maximise* (square) icon in the top-right 29 To expand a plot window, click the *Maximise* (square) icon in the top-right 30 30 corner. 31 31 32 To shrink a plot window, click the *Restore down* (square-on-square) icon in 32 To shrink a plot window, click the *Restore down* (square-on-square) icon in 33 33 the top-right corner. 34 34 35 To hide a plot, click the *Minimise* (-) icon in the top-right corner of the 35 To hide a plot, click the *Minimise* (-) icon in the top-right corner of the 36 36 plot window. 37 37 38 To show a hidden plot, select the *Restore up* (square-on-square) icon on the 38 To show a hidden plot, select the *Restore up* (square-on-square) icon on the 39 39 minimised window. 40 40 41 To delete a plot, click the *Close* (x) icon in the top-right corner of the 41 To delete a plot, click the *Close* (x) icon in the top-right corner of the 42 42 plot window. 43 43 44 *NOTE! If a residuals graph (when fitting data) is hidden, it will not show up 44 *NOTE! If a residuals graph (when fitting data) is hidden, it will not show up 45 45 after computation.* 46 46 … … 48 48 ^^^^^^^^^^^^^^^ 49 49 50 Select the *Pan* (crossed arrows) icon in the toolbar at the bottom of the plot 51 to activate this option. Move the mouse pointer to the plot. It will change to 52 a hand. Then left-click and drag the plot around. The axis values will adjust 50 Select the *Pan* (crossed arrows) icon in the toolbar at the bottom of the plot 51 to activate this option. Move the mouse pointer to the plot. It will change to 52 a hand. Then left-click and drag the plot around. The axis values will adjust 53 53 accordingly. 54 54 55 55 To disable dragging mode, unselect the *crossed arrows* icon on the toolbar. 56 56 … … 58 58 ^^^^^^^^^^^^^^^^^^^^^^^^ 59 59 60 Select the *Zoom* (magnifying glass) button in the toolbar at the bottom of 61 the plot to activate this option. Move the mouse pointer to the plot. It will 62 change to a cross-hair. Then left-click and drag the pointer around to generate 60 Select the *Zoom* (magnifying glass) button in the toolbar at the bottom of 61 the plot to activate this option. Move the mouse pointer to the plot. It will 62 change to a cross-hair. Then left-click and drag the pointer around to generate 63 63 a region of interest. Release the mouse button to generate the new view. 64 64 65 65 To disable zoom mode, unselect the *Zoom* button on the toolbar. 66 66 67 After zooming in on a a region, the *left arrow* or *right arrow* buttons on 67 After zooming in on a a region, the *left arrow* or *right arrow* buttons on 68 68 the toolbar will switch between recent views. 69 69 70 *NOTE! If a wheel mouse is available scrolling the wheel will zoom in/out 71 on the current plot (changing both axes). Alternatively, point at the numbers 70 *NOTE! If a wheel mouse is available scrolling the wheel will zoom in/out 71 on the current plot (changing both axes). Alternatively, point at the numbers 72 72 on one axis and scroll the wheel to zoom in/out on just that axis.* 73 73 74 To return to the original view of the data, click the the *Reset* (home) icon 74 To return to the original view of the data, click the the *Reset* (home) icon 75 75 in the toolbar at the bottom of the plot (see Resetting_the_graph_ for further details). 76 76 … … 78 78 ^^^^^^^^^^^^^^^^^^^ 79 79 80 To save the current plot as an image file, right click on the plot to bring up 80 To save the current plot as an image file, right click on the plot to bring up 81 81 the *Graph Menu* (see Invoking_the_graph_menu_) and select *Save Image*. 82 Alternatively, click on the *Save* (floppy disk) icon in the toolbar at the 82 Alternatively, click on the *Save* (floppy disk) icon in the toolbar at the 83 83 bottom of the plot. 84 85 A dialog window will open. Select a folder, enter a filename, choose an output 84 85 A dialog window will open. Select a folder, enter a filename, choose an output 86 86 image type, and click *Save*. 87 87 … … 94 94 * PNG (portable network graphics) 95 95 * PS (postscript) 96 * RAW/RGBA (bitmap )96 * RAW/RGBA (bitmap, stored as 935x635 pixels of depth 8) 97 97 * SVG/SVGA (scalable vector graphics) 98 98 * TIF/TIFF (tagged iamge file) … … 101 101 ^^^^^^^^^^^^^^^ 102 102 103 To send the current plot to a printer, click on the *Print* (printer) icon in 103 To send the current plot to a printer, click on the *Print* (printer) icon in 104 104 the toolbar at the bottom of the plot. 105 105 … … 109 109 ^^^^^^^^^^^^^^^^^^^ 110 110 111 To reset the axis range of a graph to its initial values select *Reset Graph 111 To reset the axis range of a graph to its initial values select *Reset Graph 112 112 Range* on the *Graph Menu* (see Invoking_the_graph_menu_). Alternatively, use 113 113 the *Reset* (home) icon in the toolbar at the bottom of the plot. … … 133 133 134 134 From the *Graph Menu* (see Invoking_the_graph_menu_) select *Change Scale*. A 135 dialog window will appear in which it is possible to choose different 135 dialog window will appear in which it is possible to choose different 136 136 transformations of the x (usually Q) or y (usually I(Q)) axes, including: 137 137 … … 139 139 * y, 1/y, ln(y), y^2, y.(x^4), 1/sqrt(y), 140 140 * log10(y), ln(y.x), ln(y.x^2), ln(y.x^4), log10(y.x^4) 141 141 142 142 A *View* option includes short-cuts to common SAS transformations, such as: 143 143 … … 148 148 * Kratky 149 149 150 For properly corrected and scaled data, these SAS transformations can be used 151 to estimate, for example, Rg, rod diameter, or SANS incoherent background 150 For properly corrected and scaled data, these SAS transformations can be used 151 to estimate, for example, Rg, rod diameter, or SANS incoherent background 152 152 levels, via a linear fit (see Making_a_linear_fit_). 153 153 … … 158 158 159 159 From the *Graph Menu* (see Invoking_the_graph_menu_) select *Toggle Linear/Log 160 Scale* to switch between a linear to log intensity scale. The type of scale 160 Scale* to switch between a linear to log intensity scale. The type of scale 161 161 selected is written alongside the colour scale. 162 162 … … 167 167 168 168 From the *Graph Menu* (see Invoking_the_graph_menu_) select *2D Color Map* to 169 choose a different color scale for the image and/or change the maximum or 169 choose a different color scale for the image and/or change the maximum or 170 170 minimum limits of the scale. 171 171 … … 173 173 ^^^^^^^^^^^^^^^^^^^^^^^^ 174 174 175 Clicking anywhere in the plot window will cause the current coordinates to be 175 Clicking anywhere in the plot window will cause the current coordinates to be 176 176 displayed in the status bar at the very bottom-left of the SasView window. 177 177 178 178 .. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 179 179 … … 193 193 194 194 In the *Dataset Menu* (see Invoking_the_dataset_menu_), highlight a data set 195 and select *DataInfo* to bring up a data information dialog panel for that 195 and select *DataInfo* to bring up a data information dialog panel for that 196 196 data set. 197 197 … … 200 200 201 201 In the *Dataset Menu* (see Invoking_the_dataset_menu_), select *Save Points as 202 a File* (if 1D data) or *Save as a file(DAT)* (if 2D data). A save dialog will 202 a File* (if 1D data) or *Save as a file(DAT)* (if 2D data). A save dialog will 203 203 appear. 204 204 205 1D data can be saved in either ASCII text (.TXT) or CanSAS/SASXML (.XML) 205 1D data can be saved in either ASCII text (.TXT) or CanSAS/SASXML (.XML) 206 206 formats (see :ref:`Formats`). 207 207 … … 216 216 217 217 In the *Dataset Menu* (see Invoking_the_dataset_menu_), select *Linear Fit*. A 218 fitting dialog will appear. Set some initial parameters and data limits and 219 click *Fit*. The fitted parameter values are displayed and the resulting line 220 calculated from them is added to the plot. 218 fitting dialog will appear. Set some initial parameters and data limits and 219 click *Fit*. The fitted parameter values are displayed and the resulting line 220 calculated from them is added to the plot. 221 221 222 222 This option is most useful for performing simple Guinier, XS Guinier, and 223 Porod type analyses, for example, to estimate Rg, a rod diameter, or incoherent 223 Porod type analyses, for example, to estimate Rg, a rod diameter, or incoherent 224 224 background level, respectively. 225 225 … … 240 240 241 241 In the *Dataset Menu* (see Invoking_the_dataset_menu_), select *Show Error Bar* 242 or *Hide Error Bar* to switch between showing/hiding the errors associated 243 with the chosen dataset. 242 or *Hide Error Bar* to switch between showing/hiding the errors associated 243 with the chosen dataset. 244 244 245 245 Modify plot properties … … 247 247 248 248 In the *Dataset Menu* (see Invoking_the_dataset_menu_), select *Modify Plot 249 Property* to change the size, color, or shape of the displayed marker for the 249 Property* to change the size, color, or shape of the displayed marker for the 250 250 chosen dataset, or to change the dataset label that appears on the plot. 251 251 … … 260 260 This feature is only available with 2D data. 261 261 262 2D data averaging allows you to perform different types of averages on your 263 data. The region to be averaged is displayed in the plot window and its limits 262 2D data averaging allows you to perform different types of averages on your 263 data. The region to be averaged is displayed in the plot window and its limits 264 264 can be modified by dragging the boundaries around. 265 265 … … 277 277 * Box averaging on Qy 278 278 279 A 'slicer' will appear (except for *Perform Circular Average*) in the plot that 280 you can drag by clicking on a slicer's handle. When the handle is highlighted 279 A 'slicer' will appear (except for *Perform Circular Average*) in the plot that 280 you can drag by clicking on a slicer's handle. When the handle is highlighted 281 281 in red, it means that the slicer can move/change size. 282 282 283 *NOTE! The slicer size will reset if you try to select a region greater than 283 *NOTE! The slicer size will reset if you try to select a region greater than 284 284 the size of the data.* 285 285 286 Alternatively, once a 'slicer' is active you can also select the region to 287 average by bringing back the *Dataset Menu* and selecting *Edit Slicer 288 Parameters*. A dialog window will appear in which you can enter values to 286 Alternatively, once a 'slicer' is active you can also select the region to 287 average by bringing back the *Dataset Menu* and selecting *Edit Slicer 288 Parameters*. A dialog window will appear in which you can enter values to 289 289 define a region or select the number of points to plot (*nbins*). 290 290 291 A separate plot window will also have appeared, displaying the requested 291 A separate plot window will also have appeared, displaying the requested 292 292 average. 293 293 294 *NOTE! The displayed average only updates when input focus is moved back to 294 *NOTE! The displayed average only updates when input focus is moved back to 295 295 that window; ie, when the mouse pointer is moved onto that plot.* 296 296 297 Selecting *Box Sum* automatically brings up the 'Slicer Parameters' dialog in 297 Selecting *Box Sum* automatically brings up the 'Slicer Parameters' dialog in 298 298 order to display the average numerically, rather than graphically. 299 299 … … 303 303 ^^^^^^^^^^^^^^^^^^^^^^^^^ 304 304 305 This operation will perform an average in constant Q-rings around the (x,y) 305 This operation will perform an average in constant Q-rings around the (x,y) 306 306 pixel location of the beam center. 307 307 … … 309 309 ^^^^^^^^^^^^^^^^^^^^^^^ 310 310 311 This operation is the same as 'Unmasked Circular Average' except that any 311 This operation is the same as 'Unmasked Circular Average' except that any 312 312 masked region is excluded. 313 313 … … 317 317 This operation averages in constant Q-arcs. 318 318 319 The width of the sector is specified in degrees (+/- |delta|\|phi|\) each side 319 The width of the sector is specified in degrees (+/- |delta|\|phi|\) each side 320 320 of the central angle (|phi|\). 321 321 … … 323 323 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 324 324 325 This operation performs an average between two Q-values centered on (0,0), 325 This operation performs an average between two Q-values centered on (0,0), 326 326 and averaged over a specified number of pixels. 327 327 328 The data is returned as a function of angle (|phi|\) in degrees with zero 328 The data is returned as a function of angle (|phi|\) in degrees with zero 329 329 degrees at the 3 O'clock position. 330 330 … … 334 334 This operation performs a sum of counts in a 2D region of interest. 335 335 336 When editing the slicer parameters, the user can enter the length and the width 336 When editing the slicer parameters, the user can enter the length and the width 337 337 the rectangular slicer and the coordinates of the center of the rectangle. 338 338 … … 342 342 This operation computes an average I(Qx) for the region of interest. 343 343 344 When editing the slicer parameters, the user can control the length and the 345 width the rectangular slicer. The averaged output is calculated from constant 346 bins with rectangular shape. The resultant Q values are nominal values, that 344 When editing the slicer parameters, the user can control the length and the 345 width the rectangular slicer. The averaged output is calculated from constant 346 bins with rectangular shape. The resultant Q values are nominal values, that 347 347 is, the central value of each bin on the x-axis. 348 348 … … 352 352 This operation computes an average I(Qy) for the region of interest. 353 353 354 When editing the slicer parameters, the user can control the length and the 355 width the rectangular slicer. The averaged output is calculated from constant 356 bins with rectangular shape. The resultant Q values are nominal values, that 354 When editing the slicer parameters, the user can control the length and the 355 width the rectangular slicer. The averaged output is calculated from constant 356 bins with rectangular shape. The resultant Q values are nominal values, that 357 357 is, the central value of each bin on the x-axis. 358 358 -
src/sas/sasgui/guiframe/report_dialog.py
rd85c194 r6dd6e32 15 15 FONT_VARIANT = 0 16 16 ISPDF = True 17 elif sys.platform == "darwin": 17 # For OSX and everything else 18 else: 18 19 _STATICBOX_WIDTH = 480 19 20 PANEL_WIDTH = 530 -
src/sas/sasgui/perspectives/calculator/data_operator.py
re871a2d r0e760e9 15 15 from sas.sasgui.guiframe.documentation_window import DocumentationWindow 16 16 17 #Control panel width 17 #Control panel width 18 18 if sys.platform.count("win32") > 0: 19 19 PANEL_TOP = 0 … … 156 156 157 157 wx.EVT_TEXT_ENTER(self.data_namectr, -1, self.on_name) 158 wx.EVT_TEXT _ENTER(self.numberctr, -1, self.on_number)158 wx.EVT_TEXT(self.numberctr, -1, self.on_number) 159 159 wx.EVT_COMBOBOX(self.data1_cbox, -1, self.on_select_data1) 160 160 wx.EVT_COMBOBOX(self.operator_cbox, -1, self.on_select_operator) … … 235 235 self.name_sizer.Layout() 236 236 237 def on_number(self, event=None ):237 def on_number(self, event=None, control=None): 238 238 """ 239 239 On selecting Number for Data2 240 240 """ 241 241 self.send_warnings('') 242 item = event.GetEventObject() 242 item = control 243 if item is None and event is not None: 244 item = event.GetEventObject() 245 elif item is None: 246 raise ValueError("Event or control must be supplied") 243 247 text = item.GetValue().strip() 244 248 if self.numberctr.IsShown(): … … 251 255 except: 252 256 self._set_textctrl_color(self.numberctr, 'pink') 253 msg = "DataOperation: Number requires a float number." 254 self.send_warnings(msg, 'error') 255 return 257 if event is None: 258 msg = "DataOperation: Number requires a float number." 259 self.send_warnings(msg, 'error') 260 return False 256 261 else: 257 262 self._set_textctrl_color(self.numberctr, self.color) … … 263 268 self.draw_output(self.output) 264 269 self.Refresh() 270 return True 265 271 266 272 def on_select_data1(self, event=None): … … 607 613 wx.MessageBox(msg, 'Error') 608 614 return 615 if self.numberctr.IsEnabled() and self.numberctr.IsShown(): 616 valid_num = self.on_number(control=self.numberctr) 617 if not valid_num: 618 return 609 619 # send data to data manager 610 620 self.output.name = name … … 731 741 #add plot 732 742 self.graph.add(plot) 733 #draw 743 #draw 734 744 self.graph.render(self) 735 745 … … 985 995 window = DataOperatorWindow(parent=None, data=[], title="Data Editor") 986 996 app.MainLoop() 987 -
src/sas/sasgui/perspectives/calculator/image_viewer.py
rd0248bd r25b9707a 73 73 parent.put_icon(plot_frame) 74 74 except: 75 print "parent", parent76 75 err_msg += "Failed to load '%s'.\n" % basename 77 76 if err_msg: … … 109 108 """ 110 109 # Initialize the Frame object 111 PlotFrame.__init__(self, parent, id, title, scale, size) 110 PlotFrame.__init__(self, parent, id, title, scale, size, 111 show_menu_icons=False) 112 112 self.parent = parent 113 113 self.data = image … … 437 437 ImageView(None).load() 438 438 app.MainLoop() 439 -
src/sas/sasgui/perspectives/calculator/model_editor.py
rbb841ef r9501661 578 578 else: 579 579 out_f.write(line + "\n") 580 elif line.count("P1 = make_class"):580 elif line.count("P1 = find_model"): 581 581 out_f.write(line % (name1) + "\n") 582 elif line.count("P2 = make_class"):582 elif line.count("P2 = find_model"): 583 583 out_f.write(line % (name2) + "\n") 584 584 … … 719 719 Do the layout for parameter related widgets 720 720 """ 721 param_txt = wx.StaticText(self, -1, 'Fit Parameters (if any): ') 722 723 param_tip = "#Set the parameters and initial values.\n" 721 param_txt = wx.StaticText(self, -1, 'Fit Parameters NOT requiring' + \ 722 ' polydispersity (if any): ') 723 724 param_tip = "#Set the parameters NOT requiring polydispersity " + \ 725 "and their initial values.\n" 724 726 param_tip += "#Example:\n" 725 727 param_tip += "A = 1\nB = 1" … … 736 738 737 739 # Parameters with polydispersity 738 pd_param_txt = wx.StaticText(self, -1, 'Fit Parameters requiring polydispersity (if any): ') 739 740 pd_param_tip = "#Set the parameters and initial values.\n" 740 pd_param_txt = wx.StaticText(self, -1, 'Fit Parameters requiring ' + \ 741 'polydispersity (if any): ') 742 743 pd_param_tip = "#Set the parameters requiring polydispersity and " + \ 744 "their initial values.\n" 741 745 pd_param_tip += "#Example:\n" 742 746 pd_param_tip += "C = 2\nD = 2" … … 803 807 self.bt_close.SetToolTipString("Close this panel.") 804 808 805 self.button_sizer.AddMany([(self.bt_apply, 0, 806 wx.LEFT, EDITOR_WIDTH * 0.8), 807 (self.bt_help, 0, 808 wx.LEFT,15), 809 (self.bt_close, 0, 810 wx.LEFT | wx.BOTTOM, 15)]) 809 self.button_sizer.AddMany([(self.bt_apply, 0,0), 810 (self.bt_help, 0, wx.LEFT | wx.BOTTOM,15), 811 (self.bt_close, 0, wx.LEFT | wx.RIGHT, 15)]) 811 812 812 813 def _do_layout(self): … … 835 836 wx.ALL | wx.EXPAND, 5), 836 837 (self.msg_sizer, 0, wx.EXPAND | wx.ALL, 5), 837 (self.button_sizer, 0, wx. EXPAND | wx.ALL, 5)])838 (self.button_sizer, 0, wx.ALIGN_RIGHT)]) 838 839 self.SetSizer(self.main_sizer) 839 840 self.SetAutoLayout(True) … … 1237 1238 ##import scipy? 1238 1239 #class Model(Model1DPlugin): 1239 # name = ""1240 # name = basename without extension of __file__ 1240 1241 # def __init__(self): 1241 1242 # Model1DPlugin.__init__(self, name=self.name) 1242 1243 # #set name same as file name 1243 # self.name = self.get_fname()1244 1244 # #self.params here 1245 1245 # self.description = "%s" … … 1303 1303 """ 1304 1304 TEST_TEMPLATE = """ 1305 def get_fname(self):1306 path = sys._getframe().f_code.co_filename1307 basename = os.path.basename(path)1308 name, _ = os.path.splitext(basename)1309 return name1310 1305 ###################################################################### 1311 1306 ## THIS IS FOR TEST. DO NOT MODIFY THE FOLLOWING LINES!!!!!!!!!!!!!!!! … … 1330 1325 import sys 1331 1326 import copy 1327 import collections 1332 1328 1333 1329 import numpy 1334 1330 1335 1331 from sas.sascalc.fit.pluginmodel import Model1DPlugin 1336 from sasmodels.sasview_model import make_class 1337 from sasmodels.core import load_model_info 1338 # User can change the name of the model (only with single functional model) 1339 #P1_model: 1340 #from %s import Model as P1 1341 1342 #P2_model: 1343 #from %s import Model as P2 1332 from sasmodels.sasview_model import find_model 1344 1333 1345 1334 class Model(Model1DPlugin): 1346 name = "" 1347 def __init__(self): 1335 name = os.path.splitext(os.path.basename(__file__))[0] 1336 is_multiplicity_model = False 1337 def __init__(self, multiplicity=1): 1348 1338 Model1DPlugin.__init__(self, name='') 1349 P1 = make_class('%s')1350 P2 = make_class('%s')1339 P1 = find_model('%s') 1340 P2 = find_model('%s') 1351 1341 p_model1 = P1() 1352 1342 p_model2 = P2() 1353 1343 ## Setting model name model description 1354 1344 self.description = '%s' 1355 self.name = self.get_fname()1356 1345 if self.name.rstrip().lstrip() == '': 1357 1346 self.name = self._get_name(p_model1.name, p_model2.name) … … 1362 1351 1363 1352 ## Define parameters 1364 self.params = {}1353 self.params = collections.OrderedDict() 1365 1354 1366 1355 ## Parameter details [units, min, max] … … 1391 1380 #list of parameter that can be fitted 1392 1381 self._set_fixed_params() 1382 1393 1383 ## parameters with orientation 1384 self.orientation_params = [] 1394 1385 for item in self.p_model1.orientation_params: 1395 1386 new_item = "p1_" + item … … 1402 1393 self.orientation_params.append(new_item) 1403 1394 ## magnetic params 1395 self.magnetic_params = [] 1404 1396 for item in self.p_model1.magnetic_params: 1405 1397 new_item = "p1_" + item … … 1459 1451 1460 1452 def _set_dispersion(self): 1453 self.dispersion = collections.OrderedDict() 1461 1454 ##set dispersion only from p_model 1462 1455 for name , value in self.p_model1.dispersion.iteritems(): … … 1574 1567 1575 1568 def _set_fixed_params(self): 1569 self.fixed = [] 1576 1570 for item in self.p_model1.fixed: 1577 1571 new_item = "p1" + item … … 1624 1618 self.description += description 1625 1619 1626 def get_fname(self):1627 path = sys._getframe().f_code.co_filename1628 basename = os.path.basename(path)1629 name, _ = os.path.splitext(basename)1630 return name1631 1632 1620 if __name__ == "__main__": 1633 1621 m1= Model() -
src/sas/sasgui/perspectives/calculator/pyconsole.py
r26d6e045 r7673ecd 27 27 """ 28 28 # try running the model 29 from sasmodels. core import load_model, call_kernel30 model = load_model(path)31 29 from sasmodels.sasview_model import load_custom_model 30 Model = load_custom_model(path) 31 model = Model() 32 32 q = np.array([0.01, 0.1]) 33 kernel = model.make_kernel([q]) 34 Iq = call_kernel(kernel, {}) 35 33 Iq = model.evalDistribution(q) 36 34 qx, qy = np.array([0.01, 0.01]), np.array([0.1, 0.1]) 37 kernel = model.make_kernel([qx, qy]) 38 Iqxy = call_kernel(kernel, {}) 35 Iqxy = model.evalDistribution([qx, qy]) 39 36 40 37 result = """ … … 56 53 except Exception: 57 54 import traceback 58 result, errmsg = None, traceback.format_exc( limit=2)55 result, errmsg = None, traceback.format_exc() 59 56 60 57 parts = ["Running model '%s'..." % os.path.basename(fname)] -
src/sas/sasgui/perspectives/fitting/basepage.py
rcb4ef58 ree4b3cb 12 12 import json 13 13 import logging 14 import traceback 15 14 16 from collections import defaultdict 15 17 from wx.lib.scrolledpanel import ScrolledPanel 18 19 import sasmodels.sasview_model 16 20 from sas.sasgui.guiframe.panel_base import PanelBase 17 21 from sas.sasgui.guiframe.utils import format_number, check_float, IdList … … 198 202 self.state_change = False 199 203 ## save customized array 200 self.values = []201 self.weights = []204 self.values = {} # type: Dict[str, List[float, ...]] 205 self.weights = {} # type: Dict[str, List[float, ...]] 202 206 ## retrieve saved state 203 207 self.number_saved_state = 0 … … 852 856 angles.append(angle) 853 857 weights.append(weight) 854 except :858 except Exception: 855 859 # Skip non-data lines 856 logging.error( sys.exc_info()[1])860 logging.error(traceback.format_exc()) 857 861 return numpy.array(angles), numpy.array(weights) 858 862 except: … … 1393 1397 self.model._persistency_dict[key] = \ 1394 1398 [state.values, state.weights] 1395 except :1396 logging.error( sys.exc_info()[1])1399 except Exception: 1400 logging.error(traceback.format_exc()) 1397 1401 selection = self._find_polyfunc_selection(disp_model) 1398 1402 for list in self.fittable_param: … … 1410 1414 list[5].Disable() 1411 1415 list[6].Disable() 1412 except :1413 logging.error( sys.exc_info()[1])1416 except Exception: 1417 logging.error(traceback.format_exc()) 1414 1418 # For array, disable all fixed params 1415 1419 if selection == 1: … … 1419 1423 try: 1420 1424 item[2].Disable() 1421 except :1422 logging.error( sys.exc_info()[1])1425 except Exception: 1426 logging.error(traceback.format_exc()) 1423 1427 1424 1428 # Make sure the check box updated when all checked … … 1500 1504 is_2Ddata = True 1501 1505 if self.model != None: 1502 try: 1503 is_modified = self._check_value_enter(self.fittable_param, 1504 is_modified) 1505 is_modified = self._check_value_enter(self.fixed_param, 1506 is_modified) 1507 is_modified = self._check_value_enter(self.parameters, 1508 is_modified) 1509 except: 1510 logging.error(sys.exc_info()[1]) 1506 is_modified = (self._check_value_enter(self.fittable_param) 1507 or self._check_value_enter(self.fixed_param) 1508 or self._check_value_enter(self.parameters)) 1511 1509 1512 1510 # Here we should check whether the boundaries have been modified. … … 1557 1555 flag = True 1558 1556 self.fitrange = True 1559 is_modified = False1560 1557 1561 1558 #wx.PostEvent(self._manager.parent, StatusEvent(status=" \ … … 1570 1567 [self.data]) 1571 1568 ##Check the values 1572 self._check_value_enter(self.fittable_param , is_modified)1573 self._check_value_enter(self.fixed_param , is_modified)1574 self._check_value_enter(self.parameters , is_modified)1569 self._check_value_enter(self.fittable_param) 1570 self._check_value_enter(self.fixed_param) 1571 self._check_value_enter(self.parameters) 1575 1572 1576 1573 # If qmin and qmax have been modified, update qmin and qmax and … … 1651 1648 try: 1652 1649 self.save_current_state() 1653 except :1654 logging.error( sys.exc_info()[1])1650 except Exception: 1651 logging.error(traceback.format_exc()) 1655 1652 1656 1653 return flag 1657 1658 def _is_modified(self, is_modified):1659 """1660 return to self._is_modified1661 """1662 return is_modified1663 1654 1664 1655 def _reset_parameters_state(self, listtorestore, statelist): … … 1895 1886 if mod_cat == custom_model: 1896 1887 for model in self.model_list_box[mod_cat]: 1897 if 'sasmodels.sasview_model.' in str(model): 1898 str_m = model.id 1899 else: 1900 str_m = str(model).split(".")[0] 1901 #self.model_box.Append(str_m) 1888 str_m = model.id if hasattr(model, 'id') else model.name 1902 1889 m_list.append(self.model_dict[str_m]) 1903 1890 else: … … 1910 1897 # wx.PostEvent(self.parent.parent, 1911 1898 # StatusEvent(status=msg, info="error")) 1912 except :1913 msg = "%s\n" % (sys.exc_info()[1])1899 except Exception: 1900 msg = traceback.format_exc() 1914 1901 wx.PostEvent(self._manager.parent, 1915 1902 StatusEvent(status=msg, info="error")) … … 1964 1951 wx.PostEvent(self.parent, StatusEvent(status=msg)) 1965 1952 # Flag to register when a parameter has changed. 1966 #is_modified = False1967 1953 if tcrtl.GetValue().lstrip().rstrip() != "": 1968 1954 try: … … 1994 1980 if temp_npts != self.num_points: 1995 1981 self.num_points = temp_npts 1996 #is_modified = True1997 1982 else: 1998 1983 msg = "Cannot plot: No points in Q range!!! " … … 2146 2131 self.temp_multi_functional = True 2147 2132 elif form_factor != None: 2148 self.model = form_factor(self.multi_factor) 2133 if self.multi_factor is not None: 2134 self.model = form_factor(self.multi_factor) 2135 else: 2136 # old style plugin models do not accept a multiplicity argument 2137 self.model = form_factor() 2149 2138 else: 2150 2139 self.model = None … … 2165 2154 self.on_set_focus(None) 2166 2155 self.Layout() 2156 2167 2157 2168 2158 def _validate_qrange(self, qmin_ctrl, qmax_ctrl): … … 2272 2262 return flag 2273 2263 2274 def _check_value_enter(self, list , modified):2264 def _check_value_enter(self, list): 2275 2265 """ 2276 2266 :param list: model parameter and panel info … … 2282 2272 parameter's maximum value , 2283 2273 parameter's units] 2284 """ 2285 is_modified = modified2286 if len(list) == 0:2287 return is_modified2274 2275 Returns True if the model parameters have changed. 2276 """ 2277 is_modified = False 2288 2278 for item in list: 2289 2279 #skip angle parameters for 1D 2290 if not self.enable2D: 2291 if item in self.orientation_params: 2292 continue 2293 #try: 2280 if not self.enable2D and item in self.orientation_params: 2281 continue 2282 2294 2283 name = str(item[1]) 2295 2296 if string.find(name, ".npts") == -1 and \ 2297 string.find(name, ".nsigmas") == -1: 2298 ## check model parameters range 2299 param_min = None 2300 param_max = None 2301 2302 ## check minimun value 2303 if item[5] != None and item[5] != "": 2304 if item[5].GetValue().lstrip().rstrip() != "": 2305 try: 2306 param_min = float(item[5].GetValue()) 2307 if not self._validate_qrange(item[5], item[2]): 2308 if numpy.isfinite(param_min): 2309 item[2].SetValue(format_number(param_min)) 2310 2311 item[5].SetBackgroundColour(wx.WHITE) 2312 item[2].SetBackgroundColour(wx.WHITE) 2313 2314 except: 2315 msg = "Wrong fit parameter range entered" 2316 wx.PostEvent(self._manager.parent, 2317 StatusEvent(status=msg)) 2318 raise ValueError, msg 2319 is_modified = True 2320 ## check maximum value 2321 if item[6] != None and item[6] != "": 2322 if item[6].GetValue().lstrip().rstrip() != "": 2323 try: 2324 param_max = float(item[6].GetValue()) 2325 if not self._validate_qrange(item[2], item[6]): 2326 if numpy.isfinite(param_max): 2327 item[2].SetValue(format_number(param_max)) 2328 2329 item[6].SetBackgroundColour(wx.WHITE) 2330 item[2].SetBackgroundColour(wx.WHITE) 2331 except: 2332 msg = "Wrong Fit parameter range entered " 2333 wx.PostEvent(self._manager.parent, 2334 StatusEvent(status=msg)) 2335 raise ValueError, msg 2336 is_modified = True 2337 2338 if param_min != None and param_max != None: 2339 if not self._validate_qrange(item[5], item[6]): 2340 msg = "Wrong Fit range entered for parameter " 2341 msg += "name %s of model %s " % (name, self.model.name) 2342 wx.PostEvent(self._manager.parent, 2343 StatusEvent(status=msg)) 2344 2345 if name in self.model.details.keys(): 2346 self.model.details[name][1:3] = param_min, param_max 2347 is_modified = True 2348 else: 2349 self.model.details[name] = ["", param_min, param_max] 2350 is_modified = True 2351 try: 2352 # Check if the textctr is enabled 2353 if item[2].IsEnabled(): 2354 value = float(item[2].GetValue()) 2355 item[2].SetBackgroundColour("white") 2356 # If the value of the parameter has changed, 2357 # +update the model and set the is_modified flag 2358 if value != self.model.getParam(name) and \ 2359 numpy.isfinite(value): 2360 self.model.setParam(name, value) 2361 except: 2362 item[2].SetBackgroundColour("pink") 2363 msg = "Wrong Fit parameter value entered " 2364 wx.PostEvent(self._manager.parent, StatusEvent(status=msg)) 2284 if name.endswith(".npts") or name.endswith(".nsigmas"): 2285 continue 2286 2287 # Check that min, max and value are floats 2288 value_ctrl, min_ctrl, max_ctrl = item[2], item[5], item[6] 2289 min_str = min_ctrl.GetValue().strip() 2290 max_str = max_ctrl.GetValue().strip() 2291 value_str = value_ctrl.GetValue().strip() 2292 validity = check_float(value_ctrl) 2293 if min_str != "": 2294 validity = validity and check_float(min_ctrl) 2295 if max_str != "": 2296 validity = validity and check_float(max_ctrl) 2297 if not validity: 2298 continue 2299 2300 # Check that min is less than max 2301 low = -numpy.inf if min_str == "" else float(min_str) 2302 high = numpy.inf if max_str == "" else float(max_str) 2303 if high < low: 2304 min_ctrl.SetBackgroundColour("pink") 2305 min_ctrl.Refresh() 2306 max_ctrl.SetBackgroundColour("pink") 2307 max_ctrl.Refresh() 2308 #msg = "Invalid fit range for %s: min must be smaller than max"%name 2309 #wx.PostEvent(self._manager.parent, StatusEvent(status=msg)) 2310 continue 2311 2312 # Force value between min and max 2313 value = float(value_str) 2314 if value < low: 2315 value = low 2316 value_ctrl.SetValue(format_number(value)) 2317 elif value > high: 2318 value = high 2319 value_ctrl.SetValue(format_number(value)) 2320 2321 # Update value in model if it has changed 2322 if value != self.model.getParam(name): 2323 self.model.setParam(name, value) 2324 is_modified = True 2325 2326 if name not in self.model.details.keys(): 2327 self.model.details[name] = ["", None, None] 2328 old_low, old_high = self.model.details[name][1:3] 2329 if old_low != low or old_high != high: 2330 # The configuration has changed but it won't change the 2331 # computed curve so no need to set is_modified to True 2332 #is_modified = True 2333 self.model.details[name][1:3] = low, high 2365 2334 2366 2335 return is_modified … … 2474 2443 try: 2475 2444 self.model.set_dispersion(p, disp_model) 2476 except :2477 logging.error( sys.exc_info()[1])2445 except Exception: 2446 logging.error(traceback.format_exc()) 2478 2447 2479 2448 ## save state into … … 2588 2557 self._draw_model() 2589 2558 self.Refresh() 2590 except: 2559 except Exception: 2560 logging.error(traceback.format_exc()) 2591 2561 # Error msg 2592 2562 msg = "Error occurred:" … … 2680 2650 # Try to delete values and weight of the names array dic if exists 2681 2651 try: 2682 del self.values[name] 2683 del self.weights[name] 2684 # delete all other dic 2685 del self.state.values[name] 2686 del self.state.weights[name] 2687 del self.model._persistency_dict[name.split('.')[0]] 2688 del self.state.model._persistency_dict[name.split('.')[0]] 2689 except: 2690 logging.error(sys.exc_info()[1]) 2652 if name in self.values: 2653 del self.values[name] 2654 del self.weights[name] 2655 # delete all other dic 2656 del self.state.values[name] 2657 del self.state.weights[name] 2658 del self.model._persistency_dict[name.split('.')[0]] 2659 del self.state.model._persistency_dict[name.split('.')[0]] 2660 except Exception: 2661 logging.error(traceback.format_exc()) 2691 2662 2692 2663 def _lay_out(self): … … 2832 2803 graphs.append(item2.figure) 2833 2804 canvases.append(item2.canvas) 2834 except :2805 except Exception: 2835 2806 # Not for control panels 2836 logging.error( sys.exc_info()[1])2807 logging.error(traceback.format_exc()) 2837 2808 # Make sure the resduals plot goes to the last 2838 2809 if res_item != None: … … 2936 2907 """ 2937 2908 2938 _TreeLocation = "user/ sasgui/perspectives/fitting/mag_help.html"2909 _TreeLocation = "user/magnetism.html" 2939 2910 _doc_viewer = DocumentationWindow(self, wx.ID_ANY, _TreeLocation, "", 2940 2911 "Polarized Beam/Magnetc Help") … … 3167 3138 if item[7].__class__.__name__ == 'ComboBox': 3168 3139 disfunc = str(item[7].GetValue()) 3169 except :3170 logging.error( sys.exc_info()[1])3140 except Exception: 3141 logging.error(traceback.format_exc()) 3171 3142 3172 3143 # 2D … … 3174 3145 try: 3175 3146 check = item[0].GetValue() 3176 except :3147 except Exception: 3177 3148 check = None 3178 3149 name = item[1] … … 3202 3173 for weight in self.weights[name]: 3203 3174 disfunc += ' ' + str(weight) 3204 except :3205 logging.error( sys.exc_info()[1])3175 except Exception: 3176 logging.error(traceback.format_exc()) 3206 3177 content += name + ',' + str(check) + ',' + value + disfunc + ':' 3207 3178 … … 3403 3374 weights=pd_weights) 3404 3375 is_array = True 3405 except :3406 logging.error( sys.exc_info()[1])3376 except Exception: 3377 logging.error(traceback.format_exc()) 3407 3378 if not is_array: 3408 3379 self._disp_obj_dict[name] = disp_model … … 3418 3389 self.state.weights] 3419 3390 3420 except :3421 logging.error( sys.exc_info()[1])3391 except Exception: 3392 logging.error(traceback.format_exc()) 3422 3393 print "Error in BasePage._paste_poly_help: %s" % \ 3423 3394 sys.exc_info()[1] -
src/sas/sasgui/perspectives/fitting/batchfitpage.py
rfc18690 ree4b3cb 256 256 # if self.model != None: 257 257 # ##Check the values 258 # self._check_value_enter( self.fittable_param , is_modified)259 # self._check_value_enter( self.fixed_param , is_modified)260 # self._check_value_enter( self.parameters , is_modified)258 # self._check_value_enter( self.fittable_param) 259 # self._check_value_enter( self.fixed_param) 260 # self._check_value_enter( self.parameters) 261 261 # 262 262 # # If qmin and qmax have been modified, update qmin and qmax and -
src/sas/sasgui/perspectives/fitting/fitpage.py
r934ce649 ree4b3cb 1365 1365 try: 1366 1366 tcrtl.SetBackgroundColour(wx.WHITE) 1367 self._check_value_enter(self.fittable_param , is_modified)1368 self._check_value_enter(self.parameters , is_modified)1367 self._check_value_enter(self.fittable_param) 1368 self._check_value_enter(self.parameters) 1369 1369 except: 1370 1370 tcrtl.SetBackgroundColour("pink") -
src/sas/sasgui/perspectives/fitting/fitting.py
r934ce649 r7673ecd 273 273 wx.PostEvent(self.parent, evt) 274 274 break 275 except: 275 except Exception: 276 import traceback; traceback.print_exc() 276 277 msg = 'Delete Error: \nCould not delete the file; Check if in use.' 277 278 wx.MessageBox(msg, 'Error') … … 579 580 _, theory_state = item 580 581 self.fit_panel.set_model_state(theory_state) 581 except :582 except Exception: 582 583 msg = "Fitting: cannot deal with the theory received" 583 584 evt = StatusEvent(status=msg, info="error") -
src/sas/sasgui/perspectives/fitting/media/fitting_help.rst
r20846be rb64b87c 15 15 16 16 17 Fitting Perspective18 ======= ============17 Fitting 18 ======= 19 19 20 20 .. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ … … 24 24 25 25 To fit some data you must first load some data, activate one or more data sets, 26 send those data sets to the fitting perspective, and select a model to fit to 27 each data set. 26 send those data sets to fitting, and select a model to fit to each data set. 28 27 29 28 Instructions on how to load and activate data are in the section :ref:`Loading_data`. … … 331 330 This mode fits one data set. 332 331 333 When data is sent to the fitting perspective it is plotted in a graph window as 334 markers. 332 When data is sent to the fitting it is plotted in a graph window as markers. 335 333 336 334 If a graph does not appear, or a graph window appears but is empty, then the data -
src/sas/sasgui/perspectives/fitting/media/pd_help.rst
r7805458 rb64b87c 105 105 106 106 The median value for the distribution will be the value given for the respective 107 size parameter in the *Fit ting Perspective*, for example, radius = 60.107 size parameter in the *FitPage*, for example, radius = 60. 108 108 109 109 The polydispersity is given by |sigma| … … 172 172 173 173 SasView only uses these array values during the computation, therefore any mean 174 value of the parameter represented by *x* present in the *Fit ting Perspective*174 value of the parameter represented by *x* present in the *FitPage* 175 175 will be ignored. 176 176 -
src/sas/sasgui/perspectives/fitting/models.py
r6afc14b rdceff6e 2 2 Utilities to manage models 3 3 """ 4 import imp4 import traceback 5 5 import os 6 6 import sys … … 8 8 # Time is needed by the log method 9 9 import time 10 import datetime 10 11 import logging 11 12 import py_compile … … 20 21 21 22 PLUGIN_DIR = 'plugin_models' 23 PLUGIN_LOG = os.path.join(os.path.expanduser("~"), '.sasview', PLUGIN_DIR, 24 "plugins.log") 22 25 23 26 def get_model_python_path(): … … 28 31 29 32 30 def log(message):33 def plugin_log(message): 31 34 """ 32 35 Log a message in a file located in the user's home directory 33 36 """ 34 dir = os.path.join(os.path.expanduser("~"), '.sasview', PLUGIN_DIR) 35 out = open(os.path.join(dir, "plugins.log"), 'a') 36 out.write("%10g: %s\n" % (time.clock(), message)) 37 out = open(PLUGIN_LOG, 'a') 38 now = time.time() 39 stamp = datetime.datetime.fromtimestamp(now).strftime('%Y-%m-%d %H:%M:%S') 40 out.write("%s: %s\n" % (stamp, message)) 37 41 out.close() 38 42 … … 51 55 if not issubclass(model, Model1DPlugin): 52 56 msg = "Plugin %s must be of type Model1DPlugin \n" % str(name) 53 log(msg)57 plugin_log(msg) 54 58 return None 55 59 if model.__name__ != "Model": 56 60 msg = "Plugin %s class name must be Model \n" % str(name) 57 log(msg)61 plugin_log(msg) 58 62 return None 59 63 try: … … 63 67 str(sys.exc_type), 64 68 sys.exc_info()[1]) 65 log(msg)69 plugin_log(msg) 66 70 return None 67 71 … … 72 76 msg = "Plugin %s: error writing function \n\t :%s %s\n " % \ 73 77 (str(name), str(sys.exc_type), sys.exc_info()[1]) 74 log(msg)78 plugin_log(msg) 75 79 return None 76 80 else: 77 81 msg = "Plugin %s needs a method called function \n" % str(name) 78 log(msg)82 plugin_log(msg) 79 83 return None 80 84 return model … … 132 136 """ 133 137 def __nonzero__(self): 134 type, value, t raceback= sys.exc_info()138 type, value, tb = sys.exc_info() 135 139 if type is not None and issubclass(type, py_compile.PyCompileError): 136 140 print "Problem with", repr(value) 137 raise type, value, t raceback141 raise type, value, tb 138 142 return 1 139 143 … … 155 159 156 160 def _findModels(dir): 161 """ 162 Find custom models 163 """ 157 164 # List of plugin objects 158 plugins = {}159 165 dir = find_plugins_dir() 160 166 # Go through files in plug-in directory 161 #always recompile the folder plugin162 167 if not os.path.isdir(dir): 163 msg = "SasView couldn't locate Model plugin folder." 164 msg += """ "%s" does not exist""" % dir 168 msg = "SasView couldn't locate Model plugin folder %r." % dir 165 169 logging.warning(msg) 166 return plugins 167 else: 168 log("looking for models in: %s" % str(dir)) 169 compile_file(dir) 170 logging.info("plugin model dir: %s" % str(dir)) 171 try: 172 list = os.listdir(dir) 173 for item in list: 174 toks = os.path.splitext(os.path.basename(item)) 175 if toks[1] == '.py' and not toks[0] == '__init__': 176 name = toks[0] 177 path = [os.path.abspath(dir)] 178 file = None 179 try: 180 (file, path, info) = imp.find_module(name, path) 181 module = imp.load_module(name, file, item, info) 182 if hasattr(module, "Model"): 183 try: 184 if _check_plugin(module.Model, name) != None: 185 plugins[name] = module.Model 186 except: 187 msg = "Error accessing Model" 188 msg += "in %s\n %s %s\n" % (name, 189 str(sys.exc_type), 190 sys.exc_info()[1]) 191 log(msg) 192 else: 193 filename = os.path.join(dir, item) 194 plugins[name] = load_custom_model(filename) 195 196 except: 197 msg = "Error accessing Model" 198 msg += " in %s\n %s %s \n" % (name, 199 str(sys.exc_type), 200 sys.exc_info()[1]) 201 log(msg) 202 finally: 203 204 if not file == None: 205 file.close() 206 except: 207 # Don't deal with bad plug-in imports. Just skip. 208 msg = "Could not import model plugin: %s" % sys.exc_info()[1] 209 log(msg) 210 170 return {} 171 172 plugin_log("looking for models in: %s" % str(dir)) 173 #compile_file(dir) #always recompile the folder plugin 174 logging.info("plugin model dir: %s" % str(dir)) 175 176 plugins = {} 177 for filename in os.listdir(dir): 178 name, ext = os.path.splitext(filename) 179 if ext == '.py' and not name == '__init__': 180 path = os.path.abspath(os.path.join(dir, filename)) 181 try: 182 model = load_custom_model(path) 183 plugins[model.name] = model 184 except Exception: 185 msg = traceback.format_exc() 186 msg += "\nwhile accessing model in %r" % path 187 plugin_log(msg) 188 logging.warning("Failed to load plugin %r. See %s for details" 189 % (path, PLUGIN_LOG)) 190 211 191 return plugins 212 192 -
src/sas/sasgui/perspectives/fitting/pagestate.py
rc10d9d6c r7673ecd 19 19 import logging 20 20 import numpy 21 import string21 import traceback 22 22 23 23 import xml.dom.minidom … … 473 473 try: 474 474 value = content[1] 475 except :476 logging.error( sys.exc_value)475 except Exception: 476 logging.error(traceback.format_exc()) 477 477 if name.count("State created"): 478 478 repo_time = "" + value … … 515 515 title = content[2] + " [" + repo_time + "]" 516 516 title_name = HEADER % title 517 except :518 logging.error( sys.exc_value)517 except Exception: 518 logging.error(traceback.format_exc()) 519 519 if name == "model name ": 520 520 try: … … 530 530 q_name = ("Q Range: " + q_range) 531 531 q_range = CENTRE % q_name 532 except :533 logging.error( sys.exc_value)532 except Exception: 533 logging.error(traceback.format_exc()) 534 534 paramval = "" 535 535 for lines in param_string.split(":"): … … 864 864 attribute = getattr(self, item[1]) 865 865 attribute[name] = com_name 866 except :867 logging.error( sys.exc_value)866 except Exception: 867 logging.error(traceback.format_exc()) 868 868 869 869 # get self.values and self.weights dic. if exists … … 880 880 val = float(line) 881 881 value_list.append(val) 882 except :882 except Exception: 883 883 # pass if line is empty (it happens) 884 logging.error( sys.exc_value)884 logging.error(traceback.format_exc()) 885 885 dic[name] = numpy.array(value_list) 886 886 setattr(self, item[1], dic) … … 1293 1293 if len(note_value) > 0: 1294 1294 data_info.notes.append(note_value) 1295 except :1295 except Exception: 1296 1296 err_mess = "cansas_reader.read: error processing entry notes\n %s" % sys.exc_value 1297 1297 self.errors.append(err_mess) … … 1315 1315 if len(detail_value) > 0: 1316 1316 data_info.sample.details.append(detail_value) 1317 except :1317 except Exception: 1318 1318 err_mess = "cansas_reader.read: error processing sample details\n %s" % sys.exc_value 1319 1319 self.errors.append(err_mess) -
src/sas/sasgui/perspectives/invariant/invariant_panel.py
rc12f9b4 rcb93b40 250 250 251 251 num = self.state.saved_state['state_num'] 252 if num> 0:252 if int(num) > 0: 253 253 self._set_undo_flag(True) 254 if num< len(state.state_list) - 1:254 if int(num) < len(state.state_list) - 1: 255 255 self._set_redo_flag(True) 256 256 … … 1860 1860 (self.button_calculate, 0, 1861 1861 wx.RIGHT | wx.TOP | wx.BOTTOM, 10), 1862 (self.button_help, 0, 1862 (self.button_help, 0, 1863 1863 wx.RIGHT | wx.TOP | wx.BOTTOM, 10),]) 1864 1864 def _do_layout(self): … … 1882 1882 self.SetSizer(self.main_sizer) 1883 1883 self.SetAutoLayout(True) 1884 1884 1885 1885 def on_help(self, event): 1886 1886 """ 1887 Bring up the Invariant Documentation whenever the HELP button is 1887 Bring up the Invariant Documentation whenever the HELP button is 1888 1888 clicked. 1889 1889 -
src/sas/sasgui/perspectives/invariant/invariant_state.py
rc10d9d6c rcb93b40 426 426 if input_field is not None: 427 427 temp_state[item] = val 428 self.state_list[ ind] = temp_state428 self.state_list[str(ind)] = temp_state 429 429 430 430 # Parse current state (ie, saved_state) … … 790 790 doc = state.toXML(datainfo.name, doc=doc, entry_node=sasentry) 791 791 return doc 792 -
src/sas/sasgui/perspectives/invariant/media/invariant_help.rst
r70305bd2 rb64b87c 4 4 .. by S King, ISIS, during SasView CodeCamp-III in Feb 2015. 5 5 6 Invariant Calculation Perspective7 ===================== ============6 Invariant Calculation 7 ===================== 8 8 9 9 Description … … 45 45 .. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 46 46 47 Using the perspective48 --------------------- 47 Using invariant analysis 48 ------------------------ 49 49 50 50 1) Select *Invariant* from the *Analysis* menu on the SasView toolbar. … … 53 53 54 54 3) Select a dataset and use the *Send To* button on the *Data Explorer* to load 55 the dataset into the *Invariant* p erspective.55 the dataset into the *Invariant* panel. 56 56 57 4) Use the *Customised Input* boxes on the *Invariant* p erspectiveto subtract57 4) Use the *Customised Input* boxes on the *Invariant* panel to subtract 58 58 any background, specify the contrast (i.e. difference in SLDs - this must be 59 59 specified for the eventual value of Q*\ to be on an absolute scale), or to … … 73 73 74 74 8) If the value of Q*\ calculated with the extrapolated regions is invalid, a 75 red warning will appear at the top of the *Invariant* p erspective panel.75 red warning will appear at the top of the *Invariant* panel. 76 76 77 77 The details of the calculation are available by clicking the *Details* -
src/sas/sasgui/perspectives/pr/media/pr_help.rst
r7805458 rb64b87c 4 4 .. by S King, ISIS, during SasView CodeCamp-III in Feb 2015. 5 5 6 P(r) Inversion Perspective7 ================ ==========6 P(r) Calculation 7 ================ 8 8 9 9 Description … … 32 32 .. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 33 33 34 Using the perspective35 -------------------- -34 Using P(r) inversion 35 -------------------- 36 36 37 37 The user must enter -
src/sas/sasgui/plottools/LineModel.py
rd7bb526 rdd5bf63 1 1 #!/usr/bin/env python 2 2 """ 3 Provide Line function (y= A + Bx) 3 Provide Line function (y= Ax + B). Until July 10, 2016 this function provided 4 (y= A + Bx). This however was contrary to all the other code using it which 5 assumed (y= mx+b) or in this nomenclature (y=Ax + B). This lead to some 6 contortions in the code and worse incorrect calculations until now for at least 7 some of the functions. This seemed the easiest to fix particularly since this 8 function should disappear in a future iteration (see notes in fitDialog) 9 10 -PDB July 10, 2016 4 11 """ 5 12 … … 10 17 Class that evaluates a linear model. 11 18 12 f(x) = A + Bx19 f(x) = Ax + B 13 20 14 21 List of default parameters: 15 A = 0.016 B = 0.022 A = 1.0 23 B = 1.0 17 24 """ 18 25 … … 53 60 54 61 """ 55 return self.params['A'] + (x * self.params['B'])62 return (self.params['A'] * x) + self.params['B'] 56 63 57 64 def run(self, x=0.0): 58 65 """ 59 66 Evaluate the model 67 68 :note: This is the function called by fitDialog to calculate the 69 the y(xmin) and y(xmax), but the only difference between this and 70 runXY is when the if statement is true. I however cannot see what that 71 function is for. It needs to be documented here or removed. 72 -PDB 7/10/16 60 73 61 74 :param x: simple value … … 74 87 def runXY(self, x=0.0): 75 88 """ 76 Evaluate the model 89 Evaluate the model. 90 91 :note: This is to be what is called by fitDialog for the actual fit 92 but the only difference between this and run is when the if 93 statement is true. I however cannot see what that function 94 is for. It needs to be documented here or removed. -PDB 7/10/16 77 95 78 96 :param x: simple value -
src/sas/sasgui/plottools/PlotPanel.py
r16b769b r1a8e2e8e 15 15 import os 16 16 import transform 17 from plottables import Data1D18 17 #TODO: make the plottables interactive 19 18 from binder import BindArtist … … 151 150 #List of texts currently on the plot 152 151 self.textList = [] 152 self.selectedText = None 153 153 #User scale 154 154 if xtransform != None: … … 190 190 191 191 # new data for the fit 192 from sas.sasgui.guiframe.dataFitting import Data1D 192 193 self.fit_result = Data1D(x=[], y=[], dy=None) 193 194 self.fit_result.symbol = 13 … … 352 353 self.leftdown = True 353 354 ax = event.inaxes 355 for text in self.textList: 356 if text.contains(event)[0]: # If user has clicked on text 357 self.selectedText = text 358 return 359 354 360 if ax != None: 355 361 self.xInit, self.yInit = event.xdata, event.ydata … … 373 379 self.mousemotion = False 374 380 self.leftup = True 381 self.selectedText = None 375 382 376 383 #release the legend … … 448 455 self._on_legend_motion(event) 449 456 return 457 458 if self.leftdown and self.selectedText is not None: 459 # User has clicked on text and is dragging 460 ax = event.inaxes 461 if ax != None: 462 # Only move text if mouse is within axes 463 self.selectedText.set_position((event.xdata, event.ydata)) 464 self._dragHelper(0, 0) 465 else: 466 # User has dragged outside of axes 467 self.selectedText = None 468 return 469 450 470 if self.enable_toolbar: 451 471 #Disable dragging without the toolbar to allow zooming with toolbar … … 646 666 dlg.setFitRange(self.xminView, self.xmaxView, 647 667 self.xmin, self.xmax) 668 else: 669 xlim = self.subplot.get_xlim() 670 ylim = self.subplot.get_ylim() 671 dlg.setFitRange(xlim[0], xlim[1], ylim[0], ylim[1]) 672 # It would be nice for this to NOT be modal (i.e. Show). 673 # Not sure about other ramifications - for example 674 # if a second linear fit is started before the first is closed. 675 # consider for future - being able to work on the plot while 676 # seing the fit values would be very nice -- PDB 7/10/16 648 677 dlg.ShowModal() 649 678 … … 708 737 if dial.ShowModal() == wx.ID_OK: 709 738 self.xLabel, self.yLabel, self.viewModel = dial.getValues() 710 if self.viewModel == "Linear y vs x":711 self.xLabel = "x"712 self.yLabel = "y"713 self.viewModel = "--"714 dial.setValues(self.xLabel, self.yLabel, self.viewModel)715 if self.viewModel == "Guinier lny vs x^(2)":716 self.xLabel = "x^(2)"717 self.yLabel = "ln(y)"718 self.viewModel = "--"719 dial.setValues(self.xLabel, self.yLabel, self.viewModel)720 if self.viewModel == "XS Guinier ln(y*x) vs x^(2)":721 self.xLabel = "x^(2)"722 self.yLabel = "ln(y*x)"723 self.viewModel = "--"724 dial.setValues(self.xLabel, self.yLabel, self.viewModel)725 if self.viewModel == "Porod y*x^(4) vs x^(4)":726 self.xLabel = "x^(4)"727 self.yLabel = "y*x^(4)"728 self.viewModel = "--"729 dial.setValues(self.xLabel, self.yLabel, self.viewModel)730 739 self._onEVT_FUNC_PROPERTY() 731 740 dial.Destroy() … … 1206 1215 1207 1216 # Properties defined by plot 1208 1217 1209 1218 # Ricardo: 1210 # A empty label "$$" will prevent the panel from displaying! 1211 1219 # A empty label "$$" will prevent the panel from displaying! 1212 1220 if prop["xlabel"]: 1213 1221 self.subplot.set_xlabel(r"$%s$"%prop["xlabel"]) … … 1215 1223 self.subplot.set_ylabel(r"$%s$"%prop["ylabel"]) 1216 1224 self.subplot.set_title(prop["title"]) 1217 1225 1218 1226 1219 1227 def clear(self): … … 1559 1567 bins=[self.y_bins, self.x_bins], 1560 1568 weights=self.data) 1561 # Now, normalize the image by weights only for weights>1: 1569 # Now, normalize the image by weights only for weights>1: 1562 1570 # If weight == 1, there is only one data point in the bin so 1563 1571 # that no normalization is required. … … 1741 1749 if remove_fit: 1742 1750 self.graph.delete(self.fit_result) 1751 if hasattr(self, 'plots'): 1752 if 'fit' in self.plots.keys(): 1753 del self.plots['fit'] 1743 1754 self.ly = None 1744 1755 self.q_ctrl = None … … 1754 1765 _yscale = 'linear' 1755 1766 for item in list: 1767 if item.id == 'fit': 1768 continue 1756 1769 item.setLabel(self.xLabel, self.yLabel) 1757 1758 1770 # control axis labels from the panel itself 1759 1771 yname, yunits = item.get_yaxis() … … 1785 1797 if self.xLabel == "ln(x)": 1786 1798 item.transformX(transform.toLogX, transform.errToLogX) 1787 self.graph._xaxis_transformed("\ln \\ %s" % xname, "%s" % xunits)1799 self.graph._xaxis_transformed("\ln{(%s)}" % xname, "%s" % xunits) 1788 1800 if self.xLabel == "log10(x)": 1789 1801 item.transformX(transform.toX_pos, transform.errToX_pos) … … 1797 1809 if self.yLabel == "ln(y)": 1798 1810 item.transformY(transform.toLogX, transform.errToLogX) 1799 self.graph._yaxis_transformed("\ln \\ %s" % yname, "%s" % yunits)1811 self.graph._yaxis_transformed("\ln{(%s)}" % yname, "%s" % yunits) 1800 1812 if self.yLabel == "y": 1801 1813 item.transformY(transform.toX, transform.errToX) … … 1813 1825 yunits = convert_unit(-1, yunits) 1814 1826 self.graph._yaxis_transformed("1/%s" % yname, "%s" % yunits) 1827 if self.yLabel == "y*x^(2)": 1828 item.transformY(transform.toYX2, transform.errToYX2) 1829 xunits = convert_unit(2, self.xaxis_unit) 1830 self.graph._yaxis_transformed("%s \ \ %s^{2}" % (yname, xname), 1831 "%s%s" % (yunits, xunits)) 1815 1832 if self.yLabel == "y*x^(4)": 1816 1833 item.transformY(transform.toYX4, transform.errToYX4) … … 1826 1843 if self.yLabel == "ln(y*x)": 1827 1844 item.transformY(transform.toLogXY, transform.errToLogXY) 1828 self.graph._yaxis_transformed("\ln (%s \ \ %s)" % (yname, xname),1845 self.graph._yaxis_transformed("\ln{(%s \ \ %s)}" % (yname, xname), 1829 1846 "%s%s" % (yunits, self.xaxis_unit)) 1830 1847 if self.yLabel == "ln(y*x^(2))": … … 1844 1861 self.graph._yaxis_transformed("%s \ \ %s^{4}" % (yname, xname), 1845 1862 "%s%s" % (yunits, xunits)) 1846 if self.viewModel == "Guinier lny vs x^(2)":1847 item.transformX(transform.toX2, transform.errToX2)1848 xunits = convert_unit(2, xunits)1849 self.graph._xaxis_transformed("%s^{2}" % xname, "%s" % xunits)1850 item.transformY(transform.toLogX, transform.errToLogX)1851 self.graph._yaxis_transformed("\ln\ \ %s" % yname, "%s" % yunits)1852 if self.viewModel == "Porod y*x^(4) vs x^(4)":1853 item.transformX(transform.toX4, transform.errToX4)1854 xunits = convert_unit(4, self.xaxis_unit)1855 self.graph._xaxis_transformed("%s^{4}" % xname, "%s" % xunits)1856 item.transformY(transform.toYX4, transform.errToYX4)1857 self.graph._yaxis_transformed("%s \ \ %s^{4}" % (yname, xname),1858 "%s%s" % (yunits, xunits))1859 1863 item.transformView() 1860 1864 … … 1894 1898 1895 1899 """ 1900 xlim = self.subplot.get_xlim() 1901 ylim = self.subplot.get_ylim() 1902 1896 1903 # Saving value to redisplay in Fit Dialog when it is opened again 1897 1904 self.Avalue, self.Bvalue, self.ErrAvalue, \ … … 1917 1924 self.graph.render(self) 1918 1925 self._offset_graph() 1926 if hasattr(self, 'plots'): 1927 # Used by Plotter1D 1928 fit_id = 'fit' 1929 self.fit_result.id = fit_id 1930 self.fit_result.title = 'Fit' 1931 self.fit_result.name = 'Fit' 1932 self.plots[fit_id] = self.fit_result 1933 self.subplot.set_xlim(xlim) 1934 self.subplot.set_ylim(ylim) 1919 1935 self.subplot.figure.canvas.draw_idle() 1920 1936 -
src/sas/sasgui/plottools/PropertyDialog.py
rd7bb526 r5129686 23 23 iy += 1 24 24 ix = 1 25 self.xvalue = wx.ComboBox(self, -1 )25 self.xvalue = wx.ComboBox(self, -1, style=wx.CB_READONLY) 26 26 x_size += self.xvalue.GetSize()[0] 27 sizer.Add(self.xvalue, (iy, ix), (1, 1), wx. EXPAND | wx.ADJUST_MINSIZE, 0)27 sizer.Add(self.xvalue, (iy, ix), (1, 1), wx.ADJUST_MINSIZE, 0) 28 28 29 29 ix += 2 30 self.yvalue = wx.ComboBox(self, -1 )30 self.yvalue = wx.ComboBox(self, -1, style=wx.CB_READONLY) 31 31 x_size += self.yvalue.GetSize()[0] 32 sizer.Add(self.yvalue, (iy, ix), (1, 1), wx. EXPAND | wx.ADJUST_MINSIZE, 0)32 sizer.Add(self.yvalue, (iy, ix), (1, 1), wx.ADJUST_MINSIZE, 0) 33 33 34 34 ix += 2 35 self.view = wx.ComboBox(self, -1) 35 self.view = wx.ComboBox(self, -1, style=wx.CB_READONLY) 36 self.view.Bind(wx.EVT_COMBOBOX, self.viewChanged) 36 37 x_size += self.view.GetSize()[0] 37 38 self.view.SetMinSize((160, 30)) … … 64 65 self.yvalue.Insert("ln(y)", 2) 65 66 self.yvalue.Insert("y^(2)", 3) 66 self.yvalue.Insert("y*x^(4)", 4) 67 self.yvalue.Insert("1/sqrt(y)", 5) 68 self.yvalue.Insert("log10(y)", 6) 69 self.yvalue.Insert("ln(y*x)", 7) 70 self.yvalue.Insert("ln(y*x^(2))", 8) 71 self.yvalue.Insert("ln(y*x^(4))", 9) 72 self.yvalue.Insert("log10(y*x^(4))", 10) 67 self.yvalue.Insert("y*x^(2)", 4) 68 self.yvalue.Insert("y*x^(4)", 5) 69 self.yvalue.Insert("1/sqrt(y)", 6) 70 self.yvalue.Insert("log10(y)", 7) 71 self.yvalue.Insert("ln(y*x)", 8) 72 self.yvalue.Insert("ln(y*x^(2))", 9) 73 self.yvalue.Insert("ln(y*x^(4))", 10) 74 self.yvalue.Insert("log10(y*x^(4))", 11) 73 75 # type of view or model used 74 76 self.view.SetValue("--") … … 83 85 self.Centre() 84 86 87 def viewChanged(self, event): 88 event.Skip() 89 view = self.view.GetValue() 90 if view == "Linear y vs x": 91 self.xvalue.SetValue("x") 92 self.yvalue.SetValue("y") 93 elif view == "Guinier lny vs x^(2)": 94 self.xvalue.SetValue("x^(2)") 95 self.yvalue.SetValue("ln(y)") 96 elif view == "XS Guinier ln(y*x) vs x^(2)": 97 self.xvalue.SetValue("x^(2)") 98 self.yvalue.SetValue("ln(y*x)") 99 elif view == "Porod y*x^(4) vs x^(4)": 100 self.xvalue.SetValue("x^(4)") 101 self.yvalue.SetValue("y*x^(4)") 102 elif view == "Kratky y*x^(2) vs x": 103 self.xvalue.SetValue("x") 104 self.yvalue.SetValue("y*x^(2)") 105 85 106 def setValues(self, x, y, view): 86 107 """ -
src/sas/sasgui/plottools/fitDialog.py
rd7bb526 rdd5bf63 20 20 def format_number(value, high=False): 21 21 """ 22 Return a float in a standardized, human-readable formatted string 22 Return a float in a standardized, human-readable formatted string. 23 This is used to output readable (e.g. x.xxxe-y) values to the panel. 23 24 """ 24 25 try: … … 40 41 """ 41 42 Dialog window pops- up when select Linear fit on Context menu 42 Displays fitting parameters 43 Displays fitting parameters. This class handles the linearized 44 fitting and derives and displays specialized output parameters based 45 on the scale choice of the plot calling it. 46 47 :note1: The fitting is currently a bit convoluted as besides using 48 plottools.transform.py to handle all the conversions, it uses 49 LineModel to define a linear model and calculate a number of 50 things like residuals etc as well as the function itself given an x 51 value. It also uses fittings.py to set up the defined LineModel for 52 fitting and then send it to the SciPy NLLSQ method. As these are by 53 definition "linear nodels" it would make more sense to just call 54 a linear solver such as scipy.stats.linregress or bumps.wsolve directly. 55 This would considerably simplify the code and remove the need I think 56 for LineModel.py and possibly fittins.py altogether. -PDB 7/10/16 57 58 :note2: The linearized fits do not take resolution into account. This 59 means that for poor resolution such as slit smearing the answers will 60 be completely wrong --- Rg would be OK but I0 would be orders of 61 magnitude off. Eventually we should fix this to account properly for 62 resolution. -PDB 7/10/16 43 63 """ 44 64 wx.Dialog.__init__(self, parent, title=title, … … 50 70 # Registered owner for close event 51 71 self._registered_close = None 52 53 72 # dialog panel self call function to plot the fitting function 73 # calls the calling PlotPanel method onFitDisplay 54 74 self.push_data = push_data 55 # dialog self plottable 75 # dialog self plottable - basically the plot we are working with 76 # passed in by the caller 56 77 self.plottable = plottable 78 # is this a Guinier fit 57 79 self.rg_on = False 58 # Receive transformations of x and y 80 # Receive transformations of x and y - basically transform is passed 81 # as caller method that returns its current value for these 59 82 self.xLabel, self.yLabel, self.Avalue, self.Bvalue, \ 60 83 self.ErrAvalue, self.ErrBvalue, self.Chivalue = self.transform() 61 84 62 # Dialog interface 85 # Now set up the dialog interface 86 self.layout() 87 # Receives the type of model for the fitting 88 from LineModel import LineModel 89 self.model = LineModel() 90 # Display the fittings values 91 self.default_A = self.model.getParam('A') 92 self.default_B = self.model.getParam('B') 93 self.cstA = fittings.Parameter(self.model, 'A', self.default_A) 94 self.cstB = fittings.Parameter(self.model, 'B', self.default_B) 95 96 # Set default value of parameter in the dialog panel 97 if self.Avalue == None: 98 self.tcA.SetValue(format_number(self.default_A)) 99 else: 100 self.tcA.SetLabel(format_number(self.Avalue)) 101 if self.Bvalue == None: 102 self.tcB.SetValue(format_number(self.default_B)) 103 else: 104 self.tcB.SetLabel(format_number(self.Bvalue)) 105 if self.ErrAvalue == None: 106 self.tcErrA.SetLabel(format_number(0.0)) 107 else: 108 self.tcErrA.SetLabel(format_number(self.ErrAvalue)) 109 if self.ErrBvalue == None: 110 self.tcErrB.SetLabel(format_number(0.0)) 111 else: 112 self.tcErrB.SetLabel(format_number(self.ErrBvalue)) 113 if self.Chivalue == None: 114 self.tcChi.SetLabel(format_number(0.0)) 115 else: 116 self.tcChi.SetLabel(format_number(self.Chivalue)) 117 if self.plottable.x != []: 118 # store the values of View in self.x,self.y,self.dx,self.dy 119 self.x, self.y, self.dx, \ 120 self.dy = self.plottable.returnValuesOfView() 121 try: 122 self.mini = self.floatForwardTransform(min(self.x)) 123 except: 124 self.mini = "Invalid" 125 try: 126 self.maxi = self.floatForwardTransform(max(self.x)) 127 except: 128 self.maxi = "Invalid" 129 130 self.initXmin.SetValue(format_number(min(self.plottable.x))) 131 self.initXmax.SetValue(format_number(max(self.plottable.x))) 132 self.mini = min(self.x) 133 self.maxi = max(self.x) 134 self.xminFit.SetValue(format_number(self.mini)) 135 self.xmaxFit.SetValue(format_number(self.maxi)) 136 137 def layout(self): 138 """ 139 Sets up the panel layout for the linear fit including all the 140 labels, text entry boxes, and buttons. 141 142 """ 143 144 # set up sizers first. 145 # vbox is the panel sizer and is a vertical sizer 146 # The first element of the panel is sizer which is a gridbagsizer 147 # and contains most of the text fields 148 # this is followed by a line separator added to vbox 149 # and finally the sizer_button (a horizontal sizer) adds the buttons 63 150 vbox = wx.BoxSizer(wx.VERTICAL) 64 151 sizer = wx.GridBagSizer(5, 5) 152 sizer_button = wx.BoxSizer(wx.HORIZONTAL) 153 154 #size of string boxes in pixels 65 155 _BOX_WIDTH = 100 66 67 self.tcA = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20)) 156 _BOX_HEIGHT = 20 157 #now set up all the text fields 158 self.tcA = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, _BOX_HEIGHT)) 68 159 self.tcA.SetToolTipString("Fit value for the slope parameter.") 69 self.tcErrA = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20))160 self.tcErrA = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, _BOX_HEIGHT)) 70 161 self.tcErrA.SetToolTipString("Error on the slope parameter.") 71 self.tcB = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20))162 self.tcB = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, _BOX_HEIGHT)) 72 163 self.tcA.SetToolTipString("Fit value for the constant parameter.") 73 self.tcErrB = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20))164 self.tcErrB = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, _BOX_HEIGHT)) 74 165 self.tcErrB.SetToolTipString("Error on the constant parameter.") 75 self.tcChi = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20))166 self.tcChi = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, _BOX_HEIGHT)) 76 167 self.tcChi.SetToolTipString("Chi^2 over degrees of freedom.") 77 self.xminFit = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20))168 self.xminFit = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, _BOX_HEIGHT)) 78 169 msg = "Enter the minimum value on " 79 170 msg += "the x-axis to be included in the fit." 80 171 self.xminFit.SetToolTipString(msg) 81 self.xmaxFit = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20))172 self.xmaxFit = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, _BOX_HEIGHT)) 82 173 msg = "Enter the maximum value on " 83 174 msg += " the x-axis to be included in the fit." 84 175 self.xmaxFit.SetToolTipString(msg) 85 self.initXmin = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20))176 self.initXmin = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, _BOX_HEIGHT)) 86 177 msg = "Minimum value on the x-axis for the plotted data." 87 178 self.initXmin.SetToolTipString(msg) 88 self.initXmax = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 20))179 self.initXmax = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, _BOX_HEIGHT)) 89 180 msg = "Maximum value on the x-axis for the plotted data." 90 181 self.initXmax.SetToolTipString(msg) … … 98 189 self.initXmax.SetBackgroundColour(_BACKGROUND_COLOR) 99 190 100 # Buttons on the bottom 191 #set some flags for specific types of fits like Guinier (Rg) and 192 #Porod (bg) -- this will determine WHAT boxes show up in the 193 #sizer layout and depends on the active axis transform 101 194 self.bg_on = False 102 self.static_line_1 = wx.StaticLine(self, -1)103 self.btFit = wx.Button(self, -1, 'Fit')104 self.btFit.Bind(wx.EVT_BUTTON, self._onFit)105 self.btFit.SetToolTipString("Perform fit.")106 self.btClose = wx.Button(self, wx.ID_CANCEL, 'Close')107 self.btClose.Bind(wx.EVT_BUTTON, self._on_close)108 195 if RG_ON: 109 196 if (self.yLabel == "ln(y)" or self.yLabel == "ln(y*x)") and \ … … 112 199 if (self.xLabel == "x^(4)") and (self.yLabel == "y*x^(4)"): 113 200 self.bg_on = True 114 # Intro 115 explanation = "Perform fit for y(x) = ax + b" 201 202 # Finally set up static text strings 203 warning = "WARNING! Resolution is NOT accounted for. \n" 204 warning += "Thus slit smeared data will give very wrong answers!" 205 self.textwarn = wx.StaticText(self, -1, warning) 206 self.textwarn.SetForegroundColour(wx.RED) 207 explanation = "Perform fit for y(x) = ax + b \n" 116 208 if self.bg_on: 117 209 param_a = 'Background (= Parameter a)' 118 210 else: 119 211 param_a = 'Parameter a' 120 vbox.Add(sizer) 212 213 214 #Now set this all up in the GridBagSizer sizer 121 215 ix = 0 122 iy = 1 216 iy = 0 217 sizer.Add(self.textwarn, (iy, ix), 218 (2, 3), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15) 219 iy += 2 123 220 sizer.Add(wx.StaticText(self, -1, explanation), (iy, ix), 124 221 (1, 1), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15) 125 iy += 2222 iy += 1 126 223 sizer.Add(wx.StaticText(self, -1, param_a), (iy, ix), 127 224 (1, 1), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15) … … 281 378 wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0) 282 379 380 #Now add some space before the separation line 283 381 iy += 1 284 ix = 1 285 286 vbox.Add(self.static_line_1, 0, wx.EXPAND, 0) 287 sizer_button = wx.BoxSizer(wx.HORIZONTAL) 382 ix = 0 383 sizer.Add((20,20), (iy, ix), (1, 1), 384 wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 0) 385 386 # Buttons on the bottom 387 self.btFit = wx.Button(self, -1, 'Fit') 388 self.btFit.Bind(wx.EVT_BUTTON, self._onFit) 389 self.btFit.SetToolTipString("Perform fit.") 390 self.btClose = wx.Button(self, wx.ID_CANCEL, 'Close') 391 self.btClose.Bind(wx.EVT_BUTTON, self._on_close) 288 392 sizer_button.Add((20, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0) 289 sizer_button.Add(self.btFit, 0, wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10) 393 sizer_button.Add(self.btFit, 0, 394 wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10) 290 395 sizer_button.Add(self.btClose, 0, 291 396 wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10) 397 398 vbox.Add(sizer) 399 self.static_line_1 = wx.StaticLine(self, -1) 400 vbox.Add(self.static_line_1, 0, wx.EXPAND, 0) 292 401 vbox.Add(sizer_button, 0, wx.EXPAND | wx.BOTTOM | wx.TOP, 10) 293 402 294 sizer.Add(self.btFit, (iy, ix), (1, 1), wx.LEFT | wx.ADJUST_MINSIZE, 0)295 403 # panel.SetSizer(sizer) 296 404 self.SetSizer(vbox) 297 405 self.Centre() 298 # Receives the type of model for the fitting299 from LineModel import LineModel300 self.model = LineModel()301 # Display the fittings values302 self.default_A = self.model.getParam('A')303 self.default_B = self.model.getParam('B')304 self.cstA = fittings.Parameter(self.model, 'A', self.default_A)305 self.cstB = fittings.Parameter(self.model, 'B', self.default_B)306 307 # Set default value of parameter in fit dialog308 if self.Avalue == None:309 self.tcA.SetValue(format_number(self.default_A))310 else:311 self.tcA.SetLabel(format_number(self.Avalue))312 if self.Bvalue == None:313 self.tcB.SetValue(format_number(self.default_B))314 else:315 self.tcB.SetLabel(format_number(self.Bvalue))316 if self.ErrAvalue == None:317 self.tcErrA.SetLabel(format_number(0.0))318 else:319 self.tcErrA.SetLabel(format_number(self.ErrAvalue))320 if self.ErrBvalue == None:321 self.tcErrB.SetLabel(format_number(0.0))322 else:323 self.tcErrB.SetLabel(format_number(self.ErrBvalue))324 if self.Chivalue == None:325 self.tcChi.SetLabel(format_number(0.0))326 else:327 self.tcChi.SetLabel(format_number(self.Chivalue))328 if self.plottable.x != []:329 # store the values of View in self.x,self.y,self.dx,self.dy330 self.x, self.y, self.dx, \331 self.dy = self.plottable.returnValuesOfView()332 try:333 self.mini = self.floatForwardTransform(min(self.x))334 except:335 self.mini = "Invalid"336 try:337 self.maxi = self.floatForwardTransform(max(self.x))338 except:339 self.maxi = "Invalid"340 341 self.initXmin.SetValue(format_number(min(self.plottable.x)))342 self.initXmax.SetValue(format_number(max(self.plottable.x)))343 self.mini = min(self.x)344 self.maxi = max(self.x)345 self.xminFit.SetValue(format_number(self.mini))346 self.xmaxFit.SetValue(format_number(self.maxi))347 406 348 407 def register_close(self, owner): … … 371 430 the button Fit.Computes chisqr , 372 431 A and B parameters of the best linear fit y=Ax +B 373 Push a plottable to 432 Push a plottable to the caller 374 433 """ 375 434 tempx = [] … … 389 448 xmin = xminView 390 449 xmax = xmaxView 450 # Set the qmin and qmax in the panel that matches the 451 # transformed min and max 452 self.initXmin.SetValue(format_number(self.floatInvTransform(xmin))) 453 self.initXmax.SetValue(format_number(self.floatInvTransform(xmax))) 391 454 # Store the transformed values of view x, y,dy 392 455 # in variables before the fit … … 485 548 tempy.append(y_model) 486 549 # Set the fit parameter display when FitDialog is opened again 487 self.Avalue = cst B488 self.Bvalue = cst A550 self.Avalue = cstA 551 self.Bvalue = cstB 489 552 self.ErrAvalue = errA 490 553 self.ErrBvalue = errB … … 494 557 495 558 # Display the fitting value on the Fit Dialog 496 self._onsetValues(cst B, cstA, errA, errB, chisqr)559 self._onsetValues(cstA, cstB, errA, errB, chisqr) 497 560 498 561 def _onsetValues(self, cstA, cstB, errA, errB, Chi): … … 501 564 """ 502 565 rg = None 566 _diam = None 503 567 self.tcA.SetValue(format_number(cstA)) 504 568 self.tcB.SetValue(format_number(cstB)) … … 516 580 if self.Rgerr_tctr.IsShown(): 517 581 if rg != None and rg != 0: 518 value = format_number(3 * float( cstA) / (2 * rg))582 value = format_number(3 * float(errA) / (2 * rg)) 519 583 else: 520 584 value = '' 521 585 self.Rgerr_tctr.SetValue(value) 522 586 if self.I0err_tctr.IsShown(): 523 val = numpy.abs(numpy.exp(cstB) - numpy.exp(cstB + errB))587 val = numpy.abs(numpy.exp(cstB) * errB) 524 588 self.I0err_tctr.SetValue(format_number(val)) 525 589 if self.Diameter_tctr.IsShown(): 526 rg = 4 * numpy.sqrt(-float(cstA)) 527 value = format_number(rg) 590 rg = numpy.sqrt(-2 * float(cstA)) 591 _diam = 4 * numpy.sqrt(-float(cstA)) 592 value = format_number(_diam) 528 593 self.Diameter_tctr.SetValue(value) 529 594 if self.Diametererr_tctr.IsShown(): 530 595 if rg != None and rg != 0: 531 value = format_number(8 * float( cstA) / rg)596 value = format_number(8 * float(errA) / _diam) 532 597 else: 533 598 value = '' 534 599 self.Diametererr_tctr.SetValue(value) 535 600 if self.RgQmin_tctr.IsShown(): 536 value = format_number(rg * self. mini)601 value = format_number(rg * self.floatInvTransform(self.mini)) 537 602 self.RgQmin_tctr.SetValue(value) 538 603 if self.RgQmax_tctr.IsShown(): 539 value = format_number(rg * self. maxi)604 value = format_number(rg * self.floatInvTransform(self.maxi)) 540 605 self.RgQmax_tctr.SetValue(value) 541 606 … … 610 675 def floatInvTransform(self, x): 611 676 """ 612 transform a float.It is use to determine the x.View min and x.View 613 max for values not in x 677 transform a float.It is used to determine the x.View min and x.View 678 max for values not in x. Also used to properly calculate RgQmin, 679 RgQmax and to update qmin and qmax in the linear range boxes on the 680 panel. 614 681 615 682 """ … … 617 684 # functionality work without rewritting the whole code 618 685 # with good design (which really should be done...). 619 if self.xLabel == "x^(2)": 686 if self.xLabel == "x": 687 return x 688 elif self.xLabel == "x^(2)": 620 689 return math.sqrt(x) 690 elif self.xLabel == "x^(4)": 691 return math.sqrt(math.sqrt(x)) 621 692 elif self.xLabel == "log10(x)": 622 693 return math.pow(10, x) 623 694 elif self.xLabel == "ln(x)": 624 695 return math.exp(x) 696 elif self.xLabel == "log10(x^(4))": 697 return math.sqrt(math.sqrt(math.pow(10, x))) 625 698 return x 626 699 -
src/sas/sasgui/plottools/fittings.py
rd7bb526 rdd5bf63 1 1 """ 2 This module is used to fit a set of x,y data to a model passed to it. It is 3 used to calculate the slope and intercepts for the linearized fits. Two things 4 should be noted: 5 6 First, this fitting module uses the NLLSQ module of SciPy rather than a linear 7 fit. This along with a few other modules could probably be removed if we 8 move to a linear regression approach. 9 10 Second, this infrastructure does not allow for resolution smearing of the 11 the models. Hence the results are not that accurate even for pinhole 12 collimation of SANS but may be good for SAXS. It is completely wrong for 13 slit smeared data. 14 2 15 """ 3 16 from scipy import optimize … … 6 19 class Parameter(object): 7 20 """ 8 Class to handle model parameters 21 Class to handle model parameters - sets the parameters and their 22 initial value from the model based to it. 9 23 """ 10 24 def __init__(self, model, name, value=None): -
src/sas/sasgui/plottools/transform.py
rd7bb526 r8abd96d 291 291 292 292 293 def errToYX2( x, y, dx=None, dy=None):293 def errToYX2(y, x, dy=None, dx=None): 294 294 """ 295 295 """ … … 325 325 326 326 327 def errToLogYX2( x, y, dx=None, dy=None):327 def errToLogYX2(y, x, dy=None, dx=None): 328 328 """ 329 329 calculate error of Log(yx**2) … … 375 375 376 376 377 def errToLogYX4( x, y=None, dx=None, dy=None):377 def errToLogYX4(y, x, dy=None, dx=None): 378 378 """ 379 379 error for ln(y*x^(4)) … … 396 396 397 397 398 def errToYX4( x, y=None, dx=None, dy=None):398 def errToYX4(y, x, dy=None, dx=None): 399 399 """ 400 400 error for (y*x^(4))
Note: See TracChangeset
for help on using the changeset viewer.