Changes in / [04e1c80:186d678] in sasview
- Location:
- src/sas
- Files:
-
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
src/sas/qtgui/MainWindow/DataExplorer.py
r722b7d6 r722b7d6 225 225 Called when the "Open Project" menu item chosen. 226 226 """ 227 # check if any items loaded and warn about data deletion 228 if self.model.rowCount() > 0: 229 msg = "This operation will set remove all data, plots and analyses from" 230 msg += " SasView before loading the project. Do you wish to continue?" 231 msgbox = QtWidgets.QMessageBox(self) 232 msgbox.setIcon(QtWidgets.QMessageBox.Warning) 233 msgbox.setText(msg) 234 msgbox.setWindowTitle("Project Load") 235 # custom buttons 236 button_yes = QtWidgets.QPushButton("Yes") 237 msgbox.addButton(button_yes, QtWidgets.QMessageBox.YesRole) 238 button_no = QtWidgets.QPushButton("No") 239 msgbox.addButton(button_no, QtWidgets.QMessageBox.RejectRole) 240 retval = msgbox.exec_() 241 if retval == QtWidgets.QMessageBox.RejectRole: 242 # cancel fit 243 return 244 227 245 kwargs = { 228 246 'parent' : self, 229 247 'caption' : 'Open Project', 230 'filter' : 'Project (*.json);;All files (*.*)',248 'filter' : 'Project Files (*.json);;Old Project Files (*.svs);;All files (*.*)', 231 249 'options' : QtWidgets.QFileDialog.DontUseNativeDialog 232 250 } 233 251 filename = QtWidgets.QFileDialog.getOpenFileName(**kwargs)[0] 234 252 if filename: 235 load_thread = threads.deferToThread(self.readProject, filename) 236 load_thread.addCallback(self.readProjectComplete) 237 load_thread.addErrback(self.readProjectFailed) 238 239 def loadFailed(self, reason): 240 """ 241 """ 242 print("file load FAILED: ", reason) 243 pass 244 245 def readProjectFailed(self, reason): 246 """ 247 """ 248 print("readProjectFailed FAILED: ", reason) 249 pass 250 251 def readProject(self, filename): 252 self.communicator.statusBarUpdateSignal.emit("Loading Project... %s" % os.path.basename(filename)) 253 try: 254 manager = DataManager() 255 with open(filename, 'r') as infile: 256 manager.load_from_readable(infile) 257 258 self.communicator.statusBarUpdateSignal.emit("Loaded Project: %s" % os.path.basename(filename)) 259 return manager 260 261 except: 262 self.communicator.statusBarUpdateSignal.emit("Failed: %s" % os.path.basename(filename)) 263 raise 264 265 def readProjectComplete(self, manager): 266 self.model.clear() 267 268 self.manager.assign(manager) 269 self.model.beginResetModel() 270 for id, item in self.manager.get_all_data().items(): 271 self.updateModel(item.data, item.path) 272 273 self.model.endResetModel() 253 self.deleteAllItems() 254 self.readProject(filename) 255 256 def loadAnalysis(self): 257 """ 258 Called when the "Open Analysis" menu item chosen. 259 """ 260 kwargs = { 261 'parent' : self, 262 'caption' : 'Open Analysis', 263 'filter' : 'Project (*.fitv);;All files (*.*)', 264 'options' : QtWidgets.QFileDialog.DontUseNativeDialog 265 } 266 filename = QtWidgets.QFileDialog.getOpenFileName(**kwargs)[0] 267 if filename: 268 self.readAnalysis(filename) 274 269 275 270 def saveProject(self): … … 285 280 name_tuple = QtWidgets.QFileDialog.getSaveFileName(**kwargs) 286 281 filename = name_tuple[0] 287 if filename: 288 _, extension = os.path.splitext(filename) 289 if not extension: 290 filename = '.'.join((filename, 'json')) 291 self.communicator.statusBarUpdateSignal.emit("Saving Project... %s\n" % os.path.basename(filename)) 292 with open(filename, 'w') as outfile: 293 self.manager.save_to_writable(outfile) 282 if not filename: 283 return 284 _, extension = os.path.splitext(filename) 285 if not extension: 286 filename = '.'.join((filename, 'json')) 287 self.communicator.statusBarUpdateSignal.emit("Saving Project... %s\n" % os.path.basename(filename)) 288 289 return filename 290 291 def saveAsAnalysisFile(self, tab_id=1): 292 """ 293 Show the save as... dialog and return the chosen filepath 294 """ 295 default_name = "FitPage"+str(tab_id)+".fitv" 296 297 wildcard = "fitv files (*.fitv)" 298 kwargs = { 299 'caption' : 'Save As', 300 'directory' : default_name, 301 'filter' : wildcard, 302 'parent' : None, 303 } 304 # Query user for filename. 305 filename_tuple = QtWidgets.QFileDialog.getSaveFileName(**kwargs) 306 filename = filename_tuple[0] 307 return filename 308 309 def saveAnalysis(self, data, tab_id=1): 310 """ 311 Called when the "Save Analysis" menu item chosen. 312 """ 313 filename = self.saveAsAnalysisFile(tab_id) 314 if not filename: 315 return 316 _, extension = os.path.splitext(filename) 317 if not extension: 318 filename = '.'.join((filename, 'fitv')) 319 self.communicator.statusBarUpdateSignal.emit("Saving analysis... %s\n" % os.path.basename(filename)) 320 321 with open(filename, 'w') as outfile: 322 GuiUtils.saveData(outfile, data) 323 324 self.communicator.statusBarUpdateSignal.emit('Analysis saved.') 325 326 def allDataForModel(self, model): 327 # data model 328 all_data = {} 329 for i in range(model.rowCount()): 330 properties = {} 331 item = model.item(i) 332 data = GuiUtils.dataFromItem(item) 333 if data is None: continue 334 # Now, all plots under this item 335 filename = data.filename 336 is_checked = item.checkState() 337 properties['checked'] = is_checked 338 other_datas = [] 339 # no need to save other_datas - things will be refit on read 340 #other_datas = GuiUtils.plotsFromFilename(filename, model) 341 # skip the main plot 342 #other_datas = list(other_datas.values())[1:] 343 all_data[data.id] = [data, properties, other_datas] 344 return all_data 345 346 def getDataForID(self, id): 347 # return the dataset with the given ID 348 all_data = [] 349 for model in (self.model, self.theory_model): 350 for i in range(model.rowCount()): 351 properties = {} 352 item = model.item(i) 353 data = GuiUtils.dataFromItem(item) 354 if data is None: continue 355 if data.id != id: continue 356 # We found the dataset - save it. 357 filename = data.filename 358 is_checked = item.checkState() 359 properties['checked'] = is_checked 360 other_datas = GuiUtils.plotsFromFilename(filename, model) 361 # skip the main plot 362 other_datas = list(other_datas.values())[1:] 363 all_data = [data, properties, other_datas] 364 break 365 return all_data 366 367 def getAllData(self): 368 """ 369 converts all datasets into serializable dictionary 370 """ 371 data = self.allDataForModel(self.model) 372 theory = self.allDataForModel(self.theory_model) 373 374 all_data = {} 375 for key, value in data.items(): 376 all_data[key] = value 377 for key, value in theory.items(): 378 if key in all_data: 379 raise ValueError("Inconsistent data in Project file.") 380 all_data[key] = value 381 return all_data 382 383 def saveDataToFile(self, outfile): 384 """ 385 Save every dataset to a json file 386 """ 387 all_data = self.getAllData() 388 # save datas 389 GuiUtils.saveData(outfile, all_data) 390 391 def readProject(self, filename): 392 """ 393 Read out datasets and fitpages from file 394 """ 395 # Find out the filetype based on extension 396 ext = os.path.splitext(filename)[1] 397 all_data = {} 398 if 'svs' in ext.lower(): 399 # backward compatibility mode. 400 datasets = GuiUtils.readProjectFromSVS(filename) 401 #[[item_1, state_1], [item_2, state_2],...] 402 403 # Convert fitpage properties and update the dict 404 all_data = GuiUtils.convertFromSVS(datasets) 405 else: 406 with open(filename, 'r') as infile: 407 all_data = GuiUtils.readDataFromFile(infile) 408 409 for key, value in all_data.items(): 410 data_dict = {key:value['fit_data']} 411 items = self.updateModelFromData(data_dict) 412 # send newly created item to its perspective 413 if 'fit_params' in value: 414 self.sendItemToPerspective(items[0]) 415 # Make the perspective read the rest of the read data 416 self._perspective().updateFromParameters(value['fit_params']) 417 418 pass # debugger 419 420 def readAnalysis(self, filename): 421 """ 422 Read out a single dataset and fitpage from file 423 """ 424 with open(filename, 'r') as infile: 425 all_data = GuiUtils.readDataFromFile(infile) 426 # simulate full project structure 427 all_data_dict = {1:all_data['fit_data']} 428 items = self.updateModelFromData(all_data_dict) 429 # TODO: allow other perspectives 430 # send newly created item to its perspective 431 if len(items) > 0: 432 self.sendItemToPerspective(items[0]) 433 # Make the perspective read the rest of the read data 434 self._perspective().updateFromParameters(all_data['fit_params']) 435 436 pass 437 438 def updateModelFromData(self, data): 439 """ 440 Given data from analysis/project file, 441 create indices and populate data/theory models 442 """ 443 # model items for top level datasets 444 items = [] 445 #self.model.beginResetModel() 446 for key, value in data.items(): 447 # key - cardinal number of dataset 448 # value - main dataset, [dependant filesets] 449 # add the main index 450 if not value: continue 451 new_data = value[0] 452 from sas.sascalc.dataloader.data_info import Data1D as old_data1d 453 from sas.sascalc.dataloader.data_info import Data2D as old_data2d 454 if isinstance(new_data, (old_data1d, old_data2d)): 455 new_data = self.manager.create_gui_data(value[0], new_data.filename) 456 assert isinstance(new_data, (Data1D, Data2D)) 457 properties = value[1] 458 is_checked = properties['checked'] 459 new_item = GuiUtils.createModelItemWithPlot(new_data, new_data.filename) 460 new_item.setCheckState(is_checked) 461 items.append(new_item) 462 model = self.theory_model 463 if new_data.is_data: 464 model = self.model 465 model.appendRow(new_item) 466 self.manager.add_data(data_list={new_data.id:new_data}) 467 468 # Add the underlying data 469 if not value[2]: 470 continue 471 for plot in value[2]: 472 assert isinstance(plot, (Data1D, Data2D)) 473 GuiUtils.updateModelItemWithPlot(new_item, plot, plot.name) 474 return items 294 475 295 476 def deleteFile(self, event): … … 410 591 retval = msgbox.exec_() 411 592 593 def sendItemToPerspective(self, item): 594 """ 595 Send the passed item data to the current perspective and set the relevant notifiers 596 """ 597 # Set the signal handlers 598 self.communicator.updateModelFromPerspectiveSignal.connect(self.updateModelFromPerspective) 599 selected_items = [item] 600 # Notify the GuiManager about the send request 601 try: 602 self._perspective().setData(data_item=selected_items, is_batch=False) 603 except Exception as ex: 604 msg = "%s perspective returned the following message: \n%s\n" %(self._perspective().name, str(ex)) 605 logging.error(msg) 606 msg = str(ex) 607 msgbox = QtWidgets.QMessageBox() 608 msgbox.setIcon(QtWidgets.QMessageBox.Critical) 609 msgbox.setText(msg) 610 msgbox.setStandardButtons(QtWidgets.QMessageBox.Ok) 611 retval = msgbox.exec_() 412 612 413 613 def freezeCheckedData(self): … … 1036 1236 self.actionQuick3DPlot.triggered.connect(self.quickData3DPlot) 1037 1237 self.actionEditMask.triggered.connect(self.showEditDataMask) 1038 self.actionDelete.triggered.connect(self.delete Item)1238 self.actionDelete.triggered.connect(self.deleteSelectedItem) 1039 1239 self.actionFreezeResults.triggered.connect(self.freezeSelectedItems) 1040 1240 … … 1248 1448 self.freezeItem(item_to_copy) 1249 1449 1250 def deleteItem(self): 1450 def deleteAllItems(self): 1451 """ 1452 Deletes all datasets from both model and theory_model 1453 """ 1454 deleted_items = [self.model.item(row) for row in range(self.model.rowCount()) 1455 if self.model.item(row).isCheckable()] 1456 deleted_names = [item.text() for item in deleted_items] 1457 # Let others know we deleted data 1458 self.communicator.dataDeletedSignal.emit(deleted_items) 1459 # update stored_data 1460 self.manager.update_stored_data(deleted_names) 1461 1462 # Clear the model 1463 self.model.clear() 1464 1465 def deleteSelectedItem(self): 1251 1466 """ 1252 1467 Delete the current item … … 1265 1480 return 1266 1481 1482 indices = self.current_view.selectedIndexes() 1483 self.deleteIndices(indices) 1484 1485 def deleteIndices(self, indices): 1486 """ 1487 Delete model idices from the current view 1488 """ 1489 proxy = self.current_view.model() 1490 model = proxy.sourceModel() 1491 1492 deleted_items = [] 1493 deleted_names = [] 1494 1267 1495 # Every time a row is removed, the indices change, so we'll just remove 1268 1496 # rows and keep calling selectedIndexes until it returns an empty list. 1269 indices = self.current_view.selectedIndexes()1270 1271 proxy = self.current_view.model()1272 model = proxy.sourceModel()1273 1274 deleted_items = []1275 deleted_names = []1276 1277 1497 while len(indices) > 0: 1278 1498 index = indices[0] 1279 row_index = proxy.mapToSource(index) 1280 item_to_delete = model.itemFromIndex(row_index) 1499 #row_index = proxy.mapToSource(index) 1500 #item_to_delete = model.itemFromIndex(row_index) 1501 item_to_delete = model.itemFromIndex(index) 1281 1502 if item_to_delete and item_to_delete.isCheckable(): 1282 row = row_index.row() 1503 #row = row_index.row() 1504 row = index.row() 1283 1505 1284 1506 # store the deleted item details so we can pass them on later … … 1407 1629 checkbox_item.setCheckable(True) 1408 1630 checkbox_item.setCheckState(QtCore.Qt.Checked) 1409 checkbox_item.setText(os.path.basename(p_file)) 1631 if p_file is not None: 1632 checkbox_item.setText(os.path.basename(p_file)) 1410 1633 1411 1634 # Add the actual Data1D/Data2D object -
src/sas/qtgui/MainWindow/DataManager.py
re2e5f3d r345b3b3 29 29 from sas.qtgui.Plotting.PlotterData import Data1D 30 30 from sas.qtgui.Plotting.PlotterData import Data2D 31 from sas.qtgui.Plotting.Plottables import Plottable32 31 from sas.qtgui.Plotting.Plottables import PlottableTheory1D 33 32 from sas.qtgui.Plotting.Plottables import PlottableFit1D -
src/sas/qtgui/MainWindow/GuiManager.py
r0c83303 r0c83303 254 254 if self._current_perspective: 255 255 self._current_perspective.setClosable() 256 #self._workspace.workspace.removeSubWindow(self._current_perspective)257 256 self._current_perspective.close() 258 257 self._workspace.workspace.removeSubWindow(self._current_perspective) … … 468 467 self._workspace.actionOpen_Project.triggered.connect(self.actionOpen_Project) 469 468 self._workspace.actionOpen_Analysis.triggered.connect(self.actionOpen_Analysis) 470 self._workspace.actionSave.triggered.connect(self.actionSave )469 self._workspace.actionSave.triggered.connect(self.actionSave_Project) 471 470 self._workspace.actionSave_Analysis.triggered.connect(self.actionSave_Analysis) 472 471 self._workspace.actionQuit.triggered.connect(self.actionQuit) … … 558 557 """ 559 558 """ 560 print("actionOpen_Analysis TRIGGERED")561 pass 562 563 def actionSave (self):559 self.filesWidget.loadAnalysis() 560 pass 561 562 def actionSave_Project(self): 564 563 """ 565 564 Menu Save Project 566 565 """ 567 self.filesWidget.saveProject() 566 filename = self.filesWidget.saveProject() 567 568 # datasets 569 all_data = self.filesWidget.getAllData() 570 571 # fit tabs 572 params = self.perspective().serializeAllFitpage() 573 574 # project dictionary structure: 575 # analysis[data.id] = [{"fit_data":[data, checkbox, child data], 576 # "fit_params":[fitpage_state]} 577 # "fit_params" not present if dataset not sent to fitting 578 analysis = {} 579 580 for id, data in all_data.items(): 581 data_content = {"fit_data":data} 582 if id in params.keys(): 583 # this dataset is represented also by the fit tab. Add to it. 584 data_content["fit_params"] = params[id] 585 analysis[id] = data_content 586 587 with open(filename, 'w') as outfile: 588 GuiUtils.saveData(outfile, analysis) 568 589 569 590 def actionSave_Analysis(self): … … 571 592 Menu File/Save Analysis 572 593 """ 573 self.communicate.saveAnalysisSignal.emit() 594 per = self.perspective() 595 if not isinstance(per, FittingWindow): 596 return 597 # get fit page serialization 598 params = per.serializeCurrentFitpage() 599 data_id = per.currentTabDataId() 600 tab_id = per.currentTab.tab_id 601 data = self.filesWidget.getDataForID(data_id) 602 analysis = {} 603 analysis['fit_data'] = data 604 analysis['fit_params'] = params 605 606 self.filesWidget.saveAnalysis(analysis, tab_id) 607 608 pass 574 609 575 610 def actionQuit(self): … … 1047 1082 """ 1048 1083 self._workspace.actionReport.setEnabled(False) 1084 self._workspace.actionOpen_Analysis.setEnabled(False) 1085 self._workspace.actionSave_Analysis.setEnabled(False) 1086 if hasattr(perspective, 'isSerializable') and perspective.isSerializable(): 1087 self._workspace.actionOpen_Analysis.setEnabled(True) 1088 self._workspace.actionSave_Analysis.setEnabled(True) 1089 1049 1090 if isinstance(perspective, Perspectives.PERSPECTIVES["Fitting"]): 1050 1091 self.checkAnalysisOption(self._workspace.actionFitting) -
src/sas/qtgui/MainWindow/UnitTesting/DataExplorerTest.py
ra24eacf rb1b71ad 854 854 855 855 # Attempt at deleting 856 self.form.delete Item()856 self.form.deleteSelectedItem() 857 857 858 858 # Test the warning dialog called once … … 868 868 self.form.current_view.selectionModel().select(select_index, QtCore.QItemSelectionModel.Rows) 869 869 # delete it. now for good 870 self.form.delete Item()870 self.form.deleteSelectedItem() 871 871 872 872 # Test the warning dialog called once -
src/sas/qtgui/Perspectives/Fitting/FittingPerspective.py
rd2007a8 ra3c59503 112 112 def onLatexCopy(self): 113 113 self.currentTab.onCopyToClipboard("Latex") 114 115 def serializeAllFitpage(self): 116 # serialize all active fitpages and return 117 # a dictionary: {data_id: fitpage_state} 118 params = {} 119 for i, tab in enumerate(self.tabs): 120 tab_data = self.getSerializedFitpage(tab) 121 if tab.tab_id is None: continue 122 id = tab_data['data_id'][0] 123 params[id] = tab_data 124 return params 125 126 def serializeCurrentFitpage(self): 127 # serialize current(active) fitpage 128 return self.getSerializedFitpage(self.currentTab) 129 130 def getSerializedFitpage(self, tab): 131 """ 132 get serialize requested fit tab 133 """ 134 fitpage_state = tab.getFitPage() 135 fitpage_state += tab.getFitModel() 136 # put the text into dictionary 137 line_dict = {} 138 for line in fitpage_state: 139 #content = line.split(',') 140 if len(line) > 1: 141 line_dict[line[0]] = line[1:] 142 return line_dict 143 144 def currentTabDataId(self): 145 """ 146 Returns the data ID of the current tab 147 """ 148 tab_id = None 149 if self.currentTab.data: 150 tab_id = self.currentTab.data.id 151 return tab_id 152 153 def updateFromParameters(self, parameters): 154 """ 155 Pass the update parameters to the current fit page 156 """ 157 self.currentTab.createPageForParameters(parameters) 114 158 115 159 def closeEvent(self, event): … … 258 302 return True 259 303 304 def isSerializable(self): 305 """ 306 Tell the caller that this perspective writes its state 307 """ 308 return True 309 260 310 def setData(self, data_item=None, is_batch=False): 261 311 """ … … 337 387 pass 338 388 389 def getCurrentStateAsXml(self): 390 """ 391 Returns an XML version of the current state 392 """ 393 state = {} 394 for tab in self.tabs: 395 pass 396 return state 397 339 398 @property 340 399 def currentTab(self): -
src/sas/qtgui/Perspectives/Fitting/FittingWidget.py
r0c83303 r0c83303 52 52 TAB_POLY = 3 53 53 CATEGORY_DEFAULT = "Choose category..." 54 MODEL_DEFAULT = "Choose model..." 54 55 CATEGORY_STRUCTURE = "Structure Factor" 55 56 CATEGORY_CUSTOM = "Plugin Models" … … 574 575 # Signals from other widgets 575 576 self.communicate.customModelDirectoryChanged.connect(self.onCustomModelChange) 576 self.communicate.saveAnalysisSignal.connect(self.savePageState)577 #self.communicate.loadAnalysisSignal.connect(self.loadPageState)578 577 self.smearing_widget.smearingChangedSignal.connect(self.onSmearingOptionsUpdate) 579 578 … … 1029 1028 model = self.cbModel.currentText() 1030 1029 1030 if model == MODEL_DEFAULT: 1031 # if the previous category was not the default, keep it. 1032 # Otherwise, just return 1033 if self._previous_model_index != 0: 1034 # We need to block signals, or else state changes on perceived unchanged conditions 1035 self.cbModel.blockSignals(True) 1036 self.cbModel.setCurrentIndex(self._previous_model_index) 1037 self.cbModel.blockSignals(False) 1038 return 1039 1031 1040 # Assure the control is active 1032 1041 if not self.cbModel.isEnabled(): … … 1035 1044 if not model: 1036 1045 return 1046 1047 self.chkMagnetism.setEnabled(self.canHaveMagnetism()) 1048 self.chkMagnetism.setEnabled(self.canHaveMagnetism()) 1049 self.tabFitting.setTabEnabled(TAB_MAGNETISM, self.chkMagnetism.isChecked() and self.canHaveMagnetism()) 1050 self._previous_model_index = self.cbModel.currentIndex() 1037 1051 1038 1052 # Reset parameters to fit … … 1213 1227 self._model_model.clear() 1214 1228 return 1215 1229 # Wipe out the parameter model 1230 self._model_model.clear() 1216 1231 # Safely clear and enable the model combo 1217 1232 self.cbModel.blockSignals(True) … … 1225 1240 model_list = self.master_category_dict[category] 1226 1241 # Populate the models combobox 1242 self.cbModel.blockSignals(True) 1243 self.cbModel.addItem(MODEL_DEFAULT) 1227 1244 self.cbModel.addItems(sorted([model for (model, _) in model_list])) 1245 self.cbModel.blockSignals(False) 1228 1246 1229 1247 def onPolyModelChange(self, top, bottom): … … 3410 3428 return report_logic.reportList() 3411 3429 3412 def savePageState(self):3413 """3414 Create and serialize local PageState3415 """3416 filepath = self.saveAsAnalysisFile()3417 if filepath is None or filepath == "":3418 return3419 3420 fitpage_state = self.getFitPage()3421 fitpage_state += self.getFitModel()3422 3423 with open(filepath, 'w') as statefile:3424 for line in fitpage_state:3425 statefile.write(str(line))3426 3427 self.communicate.statusBarUpdateSignal.emit('Analysis saved.')3428 3429 def saveAsAnalysisFile(self):3430 """3431 Show the save as... dialog and return the chosen filepath3432 """3433 default_name = "FitPage"+str(self.tab_id)+".fitv"3434 3435 wildcard = "fitv files (*.fitv)"3436 kwargs = {3437 'caption' : 'Save As',3438 'directory' : default_name,3439 'filter' : wildcard,3440 'parent' : None,3441 }3442 # Query user for filename.3443 filename_tuple = QtWidgets.QFileDialog.getSaveFileName(**kwargs)3444 filename = filename_tuple[0]3445 return filename3446 3447 3430 def loadPageStateCallback(self,state=None, datainfo=None, format=None): 3448 3431 """ … … 3563 3546 """ 3564 3547 param_list = [] 3548 if self.kernel_module is None: 3549 return param_list 3550 3565 3551 param_list.append(['model_name', str(self.cbModel.currentText())]) 3566 3552 … … 3667 3653 cb_text = cb.text() 3668 3654 3669 context = {}3670 3655 lines = cb_text.split(':') 3671 3656 if lines[0] != 'sasview_parameter_values': … … 3679 3664 line_dict[content[0]] = content[1:] 3680 3665 3666 self.updatePageWithParameters(line_dict) 3667 3668 def createPageForParameters(self, line_dict): 3669 """ 3670 Sets up page with requested model/str factor 3671 and fills it up with sent parameters 3672 """ 3673 if 'fitpage_category' in line_dict: 3674 self.cbCategory.setCurrentIndex(self.cbCategory.findText(line_dict['fitpage_category'][0])) 3675 if 'fitpage_model' in line_dict: 3676 self.cbModel.setCurrentIndex(self.cbModel.findText(line_dict['fitpage_model'][0])) 3677 if 'fitpage_structure' in line_dict: 3678 self.cbStructureFactor.setCurrentIndex(self.cbStructureFactor.findText(line_dict['fitpage_structure'][0])) 3679 3680 # Now that the page is ready for parameters, fill it up 3681 self.updatePageWithParameters(line_dict) 3682 3683 def updatePageWithParameters(self, line_dict): 3684 """ 3685 Update FitPage with parameters in line_dict 3686 """ 3687 if 'model_name' not in line_dict.keys(): 3688 return 3681 3689 model = line_dict['model_name'][0] 3682 3683 if 'model_name' not in line_dict.keys(): 3684 return False 3690 context = {} 3685 3691 3686 3692 if 'multiplicity' in line_dict.keys(): -
src/sas/qtgui/Perspectives/Fitting/UnitTesting/ComplexConstraintTest.py
r725d9c06 r2eeda93 34 34 category_index = self.tab1.cbCategory.findText("Shape Independent") 35 35 self.tab1.cbCategory.setCurrentIndex(category_index) 36 model_index = self.tab1.cbModel.findText("be_polyelectrolyte") 37 self.tab1.cbModel.setCurrentIndex(model_index) 38 36 39 category_index = self.tab2.cbCategory.findText("Cylinder") 37 40 self.tab2.cbCategory.setCurrentIndex(category_index) 41 model_index = self.tab2.cbModel.findText("barbell") 42 self.tab2.cbModel.setCurrentIndex(model_index) 38 43 39 44 tabs = [self.tab1, self.tab2] -
src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingWidgetTest.py
rec4a143 rec4a143 175 175 category_index = self.widget.cbCategory.findText("Shape Independent") 176 176 self.widget.cbCategory.setCurrentIndex(category_index) 177 model_index = self.widget.cbModel.findText("be_polyelectrolyte") 178 self.widget.cbModel.setCurrentIndex(model_index) 177 179 178 180 # test the model combo content 179 self.assertEqual(self.widget.cbModel.count(), 28)181 self.assertEqual(self.widget.cbModel.count(), 30) 180 182 181 183 # Try to change back to default … … 201 203 category_index = self.widget.cbCategory.findText("Shape Independent") 202 204 self.widget.cbCategory.setCurrentIndex(category_index) 205 model_index = self.widget.cbModel.findText("be_polyelectrolyte") 206 self.widget.cbModel.setCurrentIndex(model_index) 203 207 204 208 # check the enablement of controls … … 215 219 # 216 220 # Now change the model 221 <<<<<<< HEAD 222 self.widget.cbModel.setCurrentIndex(4) 223 ======= 217 224 self.widget.cbModel.setCurrentIndex(2) 225 >>>>>>> ESS_GUI 218 226 self.assertEqual(self.widget.cbModel.currentText(),'dab') 219 227 … … 226 234 self.widget.data_is_loaded = True 227 235 # Reset the sasmodel index 228 self.widget.cbModel.setCurrentIndex( 1)236 self.widget.cbModel.setCurrentIndex(2) 229 237 self.assertEqual(self.widget.cbModel.currentText(),'broad_peak') 230 238 … … 377 385 category_index = self.widget.cbCategory.findText("Shape Independent") 378 386 self.widget.cbCategory.setCurrentIndex(category_index) 387 model_index = self.widget.cbModel.findText("be_polyelectrolyte") 388 self.widget.cbModel.setCurrentIndex(model_index) 389 379 390 # Check the poly model 380 391 self.assertEqual(self.widget._poly_model.rowCount(), 0) … … 383 394 # Change the category index so we have a model available 384 395 self.widget.cbCategory.setCurrentIndex(2) 396 self.widget.cbModel.setCurrentIndex(1) 385 397 386 398 # Check the poly model … … 556 568 category_index = self.widget.cbCategory.findText("Sphere") 557 569 self.widget.cbCategory.setCurrentIndex(category_index) 570 model_index = self.widget.cbModel.findText("adsorbed_layer") 571 self.widget.cbModel.setCurrentIndex(model_index) 558 572 559 573 # Check the magnetic model … … 634 648 category_index = self.widget.cbCategory.findText("Sphere") 635 649 self.widget.cbCategory.setCurrentIndex(category_index) 650 model_index = self.widget.cbModel.findText("adsorbed_layer") 651 self.widget.cbModel.setCurrentIndex(model_index) 636 652 637 653 # Check the enablement/text … … 973 989 category_index = self.widget.cbCategory.findText("Sphere") 974 990 self.widget.cbCategory.setCurrentIndex(category_index) 991 model_index = self.widget.cbModel.findText("adsorbed_layer") 992 self.widget.cbModel.setCurrentIndex(model_index) 975 993 self.widget.main_params_to_fit = ['scale'] 976 994 … … 986 1004 self.assertListEqual(fp.main_params_to_fit, ['scale']) 987 1005 988 def testPushFitPage(self):1006 def notestPushFitPage(self): 989 1007 """ 990 1008 Push current state of fitpage onto stack … … 997 1015 self.widget.data = item 998 1016 category_index = self.widget.cbCategory.findText("Sphere") 1017 model_index = self.widget.cbModel.findText("adsorbed_layer") 1018 self.widget.cbModel.setCurrentIndex(model_index) 999 1019 1000 1020 # Asses the initial state of stack -
src/sas/qtgui/Utilities/GuiUtils.py
raed159f rb1b71ad 11 11 import webbrowser 12 12 import urllib.parse 13 import json 14 from io import BytesIO 13 15 14 16 import numpy as np … … 26 28 from sas.qtgui.Plotting.PlotterData import Data1D 27 29 from sas.qtgui.Plotting.PlotterData import Data2D 30 from sas.qtgui.Plotting.Plottables import Plottable 31 from sas.sascalc.dataloader.data_info import Sample, Source, Vector 32 from sas.qtgui.Plotting.Plottables import View 33 from sas.qtgui.Plotting.Plottables import PlottableTheory1D 34 from sas.qtgui.Plotting.Plottables import PlottableFit1D 35 from sas.qtgui.Plotting.Plottables import Text 36 from sas.qtgui.Plotting.Plottables import Chisq 37 from sas.qtgui.MainWindow.DataState import DataState 38 28 39 from sas.sascalc.dataloader.loader import Loader 29 40 from sas.qtgui.Utilities import CustomDir … … 257 268 sendDataToGridSignal = QtCore.pyqtSignal(list) 258 269 259 # Action Save Analysis triggered260 saveAnalysisSignal = QtCore.pyqtSignal()261 262 270 # Mask Editor requested 263 271 maskEditorSignal = QtCore.pyqtSignal(Data2D) … … 287 295 resultPlotUpdateSignal = QtCore.pyqtSignal(list) 288 296 289 def updateModelItemWithPlot(item, update_data, name="" ):297 def updateModelItemWithPlot(item, update_data, name="", checkbox_state=None): 290 298 """ 291 299 Adds a checkboxed row named "name" to QStandardItem … … 312 320 # Force redisplay 313 321 return 314 315 322 # Create the new item 316 323 checkbox_item = createModelItemWithPlot(update_data, name) 317 324 325 if checkbox_state is not None: 326 checkbox_item.setCheckState(checkbox_state) 318 327 # Append the new row to the main item 319 328 item.appendRow(checkbox_item) … … 566 575 if isinstance(data.process, list) and data.process: 567 576 for process in data.process: 577 if process is None: 578 continue 568 579 process_date = process.date 569 580 process_date_item = QtGui.QStandardItem("Date: " + process_date) … … 1140 1151 return result 1141 1152 1153 def saveData(fp, data): 1154 """ 1155 save content of data to fp (a .write()-supporting file-like object) 1156 """ 1157 1158 def add_type(dict, type): 1159 dict['__type__'] = type.__name__ 1160 return dict 1161 1162 def jdefault(o): 1163 """ 1164 objects that can't otherwise be serialized need to be converted 1165 """ 1166 # tuples and sets (TODO: default JSONEncoder converts tuples to lists, create custom Encoder that preserves tuples) 1167 if isinstance(o, (tuple, set)): 1168 content = { 'data': list(o) } 1169 return add_type(content, type(o)) 1170 1171 # "simple" types 1172 if isinstance(o, (Sample, Source, Vector)): 1173 return add_type(o.__dict__, type(o)) 1174 if isinstance(o, (Plottable, View)): 1175 return add_type(o.__dict__, type(o)) 1176 1177 # DataState 1178 if isinstance(o, (Data1D, Data2D)): 1179 # don't store parent 1180 content = o.__dict__.copy() 1181 #content.pop('parent') 1182 return add_type(content, type(o)) 1183 1184 # ndarray 1185 if isinstance(o, np.ndarray): 1186 buffer = BytesIO() 1187 np.save(buffer, o) 1188 buffer.seek(0) 1189 content = { 'data': buffer.read().decode('latin-1') } 1190 return add_type(content, type(o)) 1191 1192 # not supported 1193 logging.info("data cannot be serialized to json: %s" % type(o)) 1194 return None 1195 1196 json.dump(data, fp, indent=2, sort_keys=True, default=jdefault) 1197 1198 def readDataFromFile(fp): 1199 ''' 1200 ''' 1201 supported = [ 1202 tuple, set, 1203 Sample, Source, Vector, 1204 Plottable, Data1D, Data2D, PlottableTheory1D, PlottableFit1D, Text, Chisq, View, 1205 DataState, np.ndarray] 1206 1207 lookup = dict((cls.__name__, cls) for cls in supported) 1208 1209 class TooComplexException(Exception): 1210 pass 1211 1212 def simple_type(cls, data, level): 1213 class Empty(object): 1214 def __init__(self): 1215 for key, value in data.items(): 1216 setattr(self, key, generate(value, level)) 1217 1218 # create target object 1219 o = Empty() 1220 o.__class__ = cls 1221 1222 return o 1223 1224 def construct(type, data, level): 1225 try: 1226 cls = lookup[type] 1227 except KeyError: 1228 logging.info('unknown type: %s' % type) 1229 return None 1230 1231 # tuples and sets 1232 if cls in (tuple, set): 1233 # convert list to tuple/set 1234 return cls(generate(data['data'], level)) 1235 1236 # "simple" types 1237 if cls in (Sample, Source, Vector): 1238 return simple_type(cls, data, level) 1239 if issubclass(cls, Plottable) or (cls == View): 1240 return simple_type(cls, data, level) 1241 1242 # DataState 1243 if cls == DataState: 1244 o = simple_type(cls, data, level) 1245 o.parent = None # TODO: set to ??? 1246 return o 1247 1248 # ndarray 1249 if cls == np.ndarray: 1250 buffer = BytesIO() 1251 buffer.write(data['data'].encode('latin-1')) 1252 buffer.seek(0) 1253 return np.load(buffer) 1254 1255 logging.info('not implemented: %s, %s' % (type, cls)) 1256 return None 1257 1258 def generate(data, level): 1259 if level > 16: # recursion limit (arbitrary number) 1260 raise TooComplexException() 1261 else: 1262 level += 1 1263 1264 if isinstance(data, dict): 1265 try: 1266 type = data['__type__'] 1267 except KeyError: 1268 # if dictionary doesn't have __type__ then it is assumed to be just an ordinary dictionary 1269 o = {} 1270 for key, value in data.items(): 1271 o[key] = generate(value, level) 1272 return o 1273 1274 return construct(type, data, level) 1275 1276 if isinstance(data, list): 1277 return [generate(item, level) for item in data] 1278 1279 return data 1280 1281 new_stored_data = {} 1282 for id, data in json.load(fp).items(): 1283 try: 1284 new_stored_data[id] = generate(data, 0) 1285 except TooComplexException: 1286 logging.info('unable to load %s' % id) 1287 1288 return new_stored_data 1289 1290 def readProjectFromSVS(filepath): 1291 """ 1292 Read old SVS file and convert to the project dictionary 1293 """ 1294 from sas.sascalc.dataloader.readers.cansas_reader import Reader as CansasReader 1295 from sas.sascalc.fit.pagestate import Reader 1296 1297 loader = Loader() 1298 loader.associate_file_reader('.svs', Reader) 1299 temp = loader.load(filepath) 1300 state_reader = Reader() 1301 data_svs, state_svs = state_reader.read(filepath) 1302 1303 output = [] 1304 if isinstance(temp, list) and isinstance(state_svs, list): 1305 for item, state in zip(temp, state_svs): 1306 output.append([item, state]) 1307 else: 1308 output[temp, state_svs] 1309 return output 1310 1311 def convertFromSVS(datasets): 1312 """ 1313 Read in properties from SVS and convert into a simple dict 1314 """ 1315 content = {} 1316 for dataset in datasets: 1317 # we already have data - interested only in properties 1318 #[[item_1, state_1], [item_2, state_2],...] 1319 data = dataset[0] 1320 params = dataset[1] 1321 content[params.data_id] = {} 1322 content[params.data_id]['fit_data'] = [data, {'checked': 2}, []] 1323 param_dict = {} 1324 param_dict['fitpage_category'] = [params.categorycombobox] 1325 param_dict['fitpage_model'] = [params.formfactorcombobox] 1326 param_dict['fitpage_structure'] = [params.structurecombobox] 1327 param_dict['2D_params'] = [str(params.is_2D)] 1328 param_dict['chainfit_params'] = ["False"] 1329 param_dict['data_id'] = [params.data_id] 1330 param_dict['data_name'] = [params.data_name] 1331 param_dict['is_data'] = [str(params.is_data)] 1332 param_dict['magnetic_params'] = [str(params.magnetic_on)] 1333 param_dict['model_name'] = [params.formfactorcombobox] 1334 param_dict['polydisperse_params'] = [str(params.enable_disp)] 1335 param_dict['q_range_max'] = [str(params.qmax)] 1336 param_dict['q_range_min'] = [str(params.qmin)] 1337 # Smearing is a bit trickier. 4.x has multiple keywords, 1338 # one for each combobox option 1339 if params.enable_smearer: 1340 if params.slit_smearer: 1341 w = 1 1342 elif params.pinhole_smearer: 1343 w = 2 1344 else: 1345 w = 0 1346 param_dict['smearing'] = [str(w)] 1347 # weighting is a bit trickier. 4.x has multiple keywords, 1348 # one for each radio box. 1349 if params.dI_noweight: 1350 w = 2 1351 elif params.dI_didata: 1352 w = 3 1353 elif params.dI_sqrdata: 1354 w = 4 1355 elif params.dI_idata: 1356 w = 5 1357 else: 1358 w = 2 1359 param_dict['weighting'] = [str(w)] 1360 1361 # 4.x multi_factor is really the multiplicity 1362 if params.multi_factor is not None: 1363 param_dict['multiplicity'] = [str(int(params.multi_factor))] 1364 1365 # playing with titles 1366 data.filename = params.file 1367 data.title = params.data_name 1368 data.name = params.data_name 1369 1370 # main parameters 1371 for p in params.parameters: 1372 p_name = p[1] 1373 param_dict[p_name] = [str(p[0]), str(p[2]), None, str(p[5][1]), str(p[6][1])] 1374 # orientation parameters 1375 if params.is_2D: 1376 for p in params.orientation_params: 1377 p_name = p[1] 1378 param_dict[p_name] = [str(p[0]), str(p[2]), None, str(p[5][1]), str(p[6][1])] 1379 1380 # disperse parameters 1381 if params.enable_disp: 1382 for p in params.fittable_param: 1383 p_name = p[1] 1384 param_dict[p_name] = [str(p[0]), str(p[2]), None, str(35), str(3)] 1385 1386 # magnetic parameters 1387 1388 content[params.data_id]['fit_params'] = param_dict 1389 return content 1142 1390 1143 1391 def enum(*sequential, **named): -
src/sas/sascalc/dataloader/readers/cansas_reader.py
rb8080e1 rb1b71ad 184 184 if CANSAS_NS.get(self.cansas_version).get("ns") == value.rsplit(" ")[0]: 185 185 return True 186 if ext == " svs":186 if ext == ".svs": 187 187 return True # Why is this required? 188 188 # If we get to this point then file isn't valid CanSAS -
src/sas/sascalc/fit/pagestate.py
rb8080e1 rb1b71ad 1249 1249 1250 1250 else: 1251 self.call_back(format=ext)1251 #self.call_back(format=ext) 1252 1252 raise RuntimeError("%s is not a file" % path) 1253 1253 1254 1254 # Return output consistent with the loader's api 1255 1255 if len(output) == 0: 1256 self.call_back(state=None, datainfo=None, format=ext)1256 #self.call_back(state=None, datainfo=None, format=ext) 1257 1257 return None 1258 1258 else: 1259 states=[] 1259 1260 for data in output: 1260 1261 # Call back to post the new state … … 1281 1282 if isinstance(data.run_name, dict): 1282 1283 # Note: key order in dict is not guaranteed, so sort 1283 name = data.run_name.keys()[0]1284 name = list(data.run_name.keys())[0] 1284 1285 else: 1285 1286 name = data.run_name … … 1289 1290 state.version = fitstate.version 1290 1291 # store state in fitting 1291 self.call_back(state=state, datainfo=data, format=ext)1292 #self.call_back(state=state, datainfo=data, format=ext) 1292 1293 self.state = state 1294 states.append(state) 1293 1295 simfitstate = self._parse_simfit_state(entry) 1294 1296 if simfitstate is not None: 1295 self.call_back(state=simfitstate)1296 1297 return output1297 #self.call_back(state=simfitstate) 1298 states.append(simfitstate) 1299 return (output, states) 1298 1300 except: 1299 self.call_back(format=ext)1301 #self.call_back(format=ext) 1300 1302 raise 1301 1303
Note: See TracChangeset
for help on using the changeset viewer.