source: sasview/src/sas/qtgui/Perspectives/Invariant/InvariantPerspective.py @ adf81b8

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalc
Last change on this file since adf81b8 was 31c5b58, checked in by Piotr Rozyczko <rozyczko@…>, 7 years ago

Refactored to allow running with run.py.
Minor fixes to plotting.

  • Property mode set to 100644
File size: 23.5 KB
Line 
1# global
2import sys
3import os
4from PyQt4 import QtCore
5from PyQt4 import QtGui
6from PyQt4 import QtWebKit
7
8from twisted.internet import threads
9from twisted.internet import reactor
10
11# sas-global
12from sas.sascalc.invariant import invariant
13from sas.sasgui.guiframe.dataFitting import Data1D
14#import GuiUtils
15import sas.qtgui.GuiUtils as GuiUtils
16
17# local
18from UI.TabbedInvariantUI import Ui_tabbedInvariantUI
19from InvariantDetails import DetailsDialog
20from InvariantUtils import WIDGETS
21
22# The minimum q-value to be used when extrapolating
23Q_MINIMUM = 1e-5
24# The maximum q-value to be used when extrapolating
25Q_MAXIMUM = 10
26# the ratio of maximum q value/(qmax of data) to plot the theory data
27Q_MAXIMUM_PLOT = 3
28
29
30class MyModel(object):
31    def __init__(self):
32        self._model = QtGui.QStandardItemModel(self)
33
34    def addItem(self, item):
35        item = QtGui.QStandardItem(str(item))
36        self._model.appendRow(item)
37
38class InvariantWindow(QtGui.QDialog, Ui_tabbedInvariantUI):
39    # The controller which is responsible for managing signal slots connections
40    # for the gui and providing an interface to the data model.
41    def __init__(self, manager=None, parent=None):
42        super(InvariantWindow, self).__init__(parent)
43        self.setupUi(self)
44
45        self.setWindowTitle("Invariant Perspective")
46
47        # initial input params
48        self._background = 0.0
49        self._scale = 1.0
50        self._contrast = 1.0
51        self._porod = 1.0
52        self._npoints_low = 10
53        self._npoints_high = 10
54        self._power_low = 4
55
56        self._manager = manager
57        self._reactor = self._manager.reactor()
58        self._model_item = QtGui.QStandardItem()
59
60        self._helpView = QtWebKit.QWebView()
61        self.detailsDialog = DetailsDialog(self)
62
63        self._low_extrapolate = False
64        self._low_guinier  = True
65        self._low_fit  = True
66        self._high_extrapolate = False
67        self._high_power_value  = False
68
69        # no reason to have this widget resizable
70        self.setFixedSize(self.minimumSizeHint())
71
72        self.communicate = GuiUtils.Communicate()
73
74        self._data = None
75        self._path = ""
76
77        # Mask file selector
78        ###################################################
79        #self._path = "cyl_400_20.txt"
80        #from sas.sascalc.dataloader.loader import  Loader
81        #loader = Loader()
82        #try:
83        #    self._data = loader.load(self._path)
84        #except:
85        #    raise
86        ###################################################
87
88        self.lineEdit_8.setText(str(Q_MINIMUM))
89        self.lineEdit_9.setText(str(Q_MAXIMUM))
90
91        # Let's choose the Standard Item Model.
92        self.model = QtGui.QStandardItemModel(self)
93
94        # Connect buttons to slots.
95        # Needs to be done early so default values propagate properly.
96        self.setupSlots()
97
98        # Set up the model.
99        self.setupModel()
100
101        # Set up the mapper
102        self.setupMapper()
103
104    def closeEvent(self, event):
105        """
106        Overwrite the default close method of QWidget
107        """
108        # No close on perspectives - one must always be active.
109        event.ignore()
110
111    def communicator(self):
112        """ Getter for the communicator """
113        return self.communicate
114
115    def updateFromModel(self):
116        """
117        update the globals based on the data in the model
118        """
119        self._background = float(self.model.item(WIDGETS.W_BACKGROUND).text())
120        self._contrast   = float(self.model.item(WIDGETS.W_CONTRAST).text())
121        self._scale      = float(self.model.item(WIDGETS.W_SCALE).text())
122
123        # High extrapolate
124        self._low_extrapolate = ( str(self.model.item(WIDGETS.W_ENABLE_LOWQ).text()) == 'true')
125        self._low_points = float(self.model.item(WIDGETS.W_NPTS_LOWQ).text())
126        self._low_guinier  = ( str(self.model.item(WIDGETS.W_LOWQ_GUINIER).text()) == 'true')
127        self._low_fit  = ( str(self.model.item(WIDGETS.W_LOWQ_FIT).text()) == 'true')
128        self._low_power_value  = float(self.model.item(WIDGETS.W_LOWQ_POWER_VALUE).text())
129
130        # High extrapolating
131        self._high_extrapolate = ( str(self.model.item(WIDGETS.W_ENABLE_HIGHQ).text()) == 'true')
132        self._high_points  = float(self.model.item(WIDGETS.W_NPTS_HIGHQ).text())
133        self._high_fit  = ( str(self.model.item(WIDGETS.W_HIGHQ_FIT).text()) == 'true')
134        self._high_power_value  = float(self.model.item(WIDGETS.W_HIGHQ_POWER_VALUE).text())
135
136    def calculateInvariant(self):
137        """
138        Use twisted to thread the calculations away.
139        """
140        # Find out if extrapolation needs to be used.
141        extrapolation = None
142        if self._low_extrapolate  and not self._high_extrapolate:
143            extrapolation = "low"
144        elif not self._low_extrapolate  and self._high_extrapolate:
145            extrapolation = "high"
146        elif self._low_extrapolate and self._high_extrapolate:
147            extrapolation = "both"
148        try:
149            # modify the Calculate button to indicate background process
150            self.pushButton.setText("Calculating...")
151            self.pushButton.setEnabled(False)
152            self.style = self.pushButton.styleSheet()
153            self.pushButton.setStyleSheet("background-color: rgb(255, 255, 0); color: rgb(0, 0, 0)")
154            # Send the calculations to separate thread.
155            d = threads.deferToThread(self.calculateThread, extrapolation)
156            # Add deferred callback for call return
157            d.addCallback(self.plotResult)
158        except Exception as ex:
159            # Set the button back to available
160            self.pushButton.setEnabled(True)
161            self.pushButton.setText("Calculate")
162            self.pushButton.setStyleSheet(self.style)
163
164
165    def plotResult(self, model):
166        """
167        """
168        self.model = model
169        self.mapper.toFirst()
170
171        # Set the button back to available
172        self.pushButton.setEnabled(True)
173        self.pushButton.setText("Calculate")
174        self.pushButton.setStyleSheet(self.style)
175
176        # Send the modified model item to DE for keeping in the model
177        self.communicate.updateModelFromPerspectiveSignal.emit(self._model_item)
178
179
180    def calculateThread(self, extrapolation):
181        """
182        Perform Invariant calculations.
183
184        TODO: Create a dictionary of results to be sent to DE on completion.
185        """
186        self.updateFromModel()
187
188        qstar_low = 0.0
189        qstar_low_err = 0.0
190        qstar_high = 0.0
191        qstar_high_err = 0.0
192        qstar_total = 0.0
193        qstar_total_low_err = 0.0
194
195        # Prepare the invariant object
196        inv = invariant.InvariantCalculator(data=self._data,
197                                            background = self._background,
198                                            scale = self._scale)
199
200        if self._low_extrapolate:
201            function_low = "power_law"
202            if self._low_guinier:
203                function_low = "guinier"
204            if self._low_fit:
205                self._low_power_value = None
206            inv.set_extrapolation(range="low",
207                                  npts=self._low_points,
208                                  function=function_low,
209                                  power=self._low_power_value)
210
211        if self._high_extrapolate:
212            function_low = "power_law"
213            inv.set_extrapolation(range="high",
214                                  npts=self._high_points,
215                                  function=function_low,
216                                  power=self._low_power_value)
217
218        #Compute invariant
219        # TODO: proper exception handling and logic -
220        # display info, update lineedits, don't run extrapolations etc.
221        calculation_failed = False
222        try:
223            qstar_total, qstar_total_error         = inv.get_qstar_with_error()
224        except Exception as ex:
225            calculation_failed = True
226            # Display relevant information
227            item = QtGui.QStandardItem("ERROR")
228            self.model.setItem(WIDGETS.W_INVARIANT, item)
229            item = QtGui.QStandardItem("ERROR")
230            self.model.setItem(WIDGETS.W_INVARIANT_ERR, item)
231        try:
232            volume_fraction, volume_fraction_error = \
233                inv.get_volume_fraction_with_error(self._contrast)
234        except Exception as ex:
235            calculation_failed = True
236            # Display relevant information
237            item = QtGui.QStandardItem("ERROR")
238            self.model.setItem(WIDGETS.W_VOLUME_FRACTION, item)
239            item = QtGui.QStandardItem("ERROR")
240            self.model.setItem(WIDGETS.W_VOLUME_FRACTION_ERR, item)
241        try:
242            surface, surface_error = \
243                inv.get_surface_with_error(self._contrast, self._porod)
244        except Exception as ex:
245            calculation_failed = True
246            # Display relevant information
247            item = QtGui.QStandardItem("ERROR")
248            self.model.setItem(WIDGETS.W_SPECIFIC_SURFACE, item)
249            item = QtGui.QStandardItem("ERROR")
250            self.model.setItem(WIDGETS.W_SPECIFIC_SURFACE_ERR, item)
251
252        if(calculation_failed):
253            # TODO: NOTIFY THE GUI MANAGER!!
254            self.mapper.toFirst()
255            return self.model
256
257        if self._low_extrapolate:
258            # for presentation in InvariantDetails
259            qstar_low, qstar_low_err = inv.get_qstar_low()
260            extrapolated_data = inv.get_extra_data_low(self._low_points)
261            power_low = inv.get_extrapolation_power(range='low')
262
263            #inv.data = extrapolated_data
264            #qstar_total, qstar_total_error = inv.get_qstar_with_error()
265
266            # Plot the chart
267            title = "Low-Q extrapolation"
268
269            # Convert the data into plottable
270            extrapolated_data = self._manager.createGuiData(extrapolated_data)
271
272            # Add the plot to the model item
273            # variant_item = QtCore.QVariant(self._plotter)
274            variant_item = QtCore.QVariant(extrapolated_data)
275
276            # This needs to run in the main thread
277            reactor.callFromThread(GuiUtils.updateModelItem, self._model_item, variant_item, title)
278
279        if self._high_extrapolate:
280            # for presentation in InvariantDetails
281            qmax_plot = Q_MAXIMUM_PLOT * max(self._data.x)
282            if qmax_plot > Q_MAXIMUM:
283                qmax_plot = Q_MAXIMUM
284            qstar_high, qstar_high_err = inv.get_qstar_high()
285            power_high = inv.get_extrapolation_power(range='high')
286            high_out_data = inv.get_extra_data_high(q_end=qmax_plot, npts=500)
287
288            # Convert the data into plottable
289            high_out_data = self._manager.createGuiData(high_out_data)
290
291            # find how to add this plot to the existing plot for low_extrapolate
292            # Plot the chart
293            title = "High-Q extrapolation"
294
295            # Add the plot to the model item
296            # variant_item = QtCore.QVariant(self._plotter)
297            variant_item = QtCore.QVariant(high_out_data)
298            # This needs to run in the main thread
299            reactor.callFromThread(GuiUtils.updateModelItem, self._model_item, variant_item, title)
300
301        item = QtGui.QStandardItem(str(float('%.5g'% volume_fraction)))
302        self.model.setItem(WIDGETS.W_VOLUME_FRACTION, item)
303        item = QtGui.QStandardItem(str(float('%.5g'% volume_fraction_error)))
304        self.model.setItem(WIDGETS.W_VOLUME_FRACTION_ERR, item)
305        item = QtGui.QStandardItem(str(float('%.5g'% surface)))
306        self.model.setItem(WIDGETS.W_SPECIFIC_SURFACE, item)
307        item = QtGui.QStandardItem(str(float('%.5g'% surface_error)))
308        self.model.setItem(WIDGETS.W_SPECIFIC_SURFACE_ERR, item)
309        item = QtGui.QStandardItem(str(float('%.5g'% qstar_total)))
310        self.model.setItem(WIDGETS.W_INVARIANT, item)
311        item = QtGui.QStandardItem(str(float('%.5g'% qstar_total_error)))
312        self.model.setItem(WIDGETS.W_INVARIANT_ERR, item)
313
314        #item = QtGui.QStandardItem(str(float('%.5g'% qstar_total)))
315        #self.model.setItem(WIDGETS.D_TOTAL_QSTAR, item)
316        #item = QtGui.QStandardItem(str(float('%.5g'% qstar_total_err)))
317        #self.model.setItem(WIDGETS.D_TOTAL_QSTAR_ERR, item)
318        item = QtGui.QStandardItem(str(float('%.5g'% qstar_low)))
319        self.model.setItem(WIDGETS.D_LOW_QSTAR, item)
320        item = QtGui.QStandardItem(str(float('%.5g'% qstar_low_err)))
321        self.model.setItem(WIDGETS.D_LOW_QSTAR_ERR, item)
322        item = QtGui.QStandardItem(str(float('%.5g'% qstar_high)))
323        self.model.setItem(WIDGETS.D_HIGH_QSTAR, item)
324        item = QtGui.QStandardItem(str(float('%.5g'% qstar_high_err)))
325        self.model.setItem(WIDGETS.D_HIGH_QSTAR_ERR, item)
326
327        self.mapper.toFirst()
328
329        return self.model
330               
331    def title(self):
332        """
333        Perspective name
334        """
335        return "Invariant panel"
336
337    def status(self):
338        """
339        """
340        self.detailsDialog.setModel(self.model)
341        self.detailsDialog.showDialog()
342
343    def help(self):
344        """
345        """
346        _TreeLocation = self._manager.HELP_DIRECTORY_LOCATION + \
347            "/user/sasgui/perspectives/invariant/invariant_help.html"
348        self._helpView.load(QtCore.QUrl(_TreeLocation))
349        self._helpView.show()
350
351    def setupSlots(self):
352        self.pushButton.clicked.connect(self.calculateInvariant)
353        self.pushButton_2.clicked.connect(self.status)
354        self.pushButton_3.clicked.connect(self.help)
355
356        self.radioButton.toggled.connect(self.lowGuinierAndPowerToggle)
357        self.radioButton_8.toggled.connect(self.hiFitAndFixToggle)
358
359        self.radioButton_3.toggled.connect(self.lowFitAndFixToggle)
360
361        # Bug workaround for QDataWidgetMapper() not reacting to checkbox clicks.
362        # https://bugreports.qt.io/browse/QTBUG-1818
363        self.checkBox.clicked.connect(self.setFocus)
364        self.checkBox_2.clicked.connect(self.setFocus)
365
366        self.model.itemChanged.connect(self.modelChanged)
367
368    def modelChanged(self, item):
369        """
370        """
371        if item.row() == WIDGETS.W_ENABLE_LOWQ:
372            toggle = (str(item.text()) == 'true')
373            self._low_extrapolate = toggle
374            self.lowQToggle(toggle)
375        elif item.row() == WIDGETS.W_ENABLE_HIGHQ:
376            toggle = (str(item.text()) == 'true')
377            self._high_extrapolate = toggle
378            self.highQToggle(toggle)
379       
380    def lowGuinierAndPowerToggle(self, toggle):
381        """
382        """
383        self._low_guinier = toggle
384        toggle = not toggle
385        self.lineEdit_11.setEnabled(toggle)
386        self.radioButton_3.setEnabled(toggle)
387        self.radioButton_4.setEnabled(toggle)
388        self.lineEdit_11.setEnabled(toggle and (not self._low_fit))
389
390    def lowFitAndFixToggle(self, toggle):
391        """
392        """
393        self._low_fit = toggle
394        toggle = not toggle
395        self.lineEdit_11.setEnabled(toggle)
396
397    def hiFitAndFixToggle(self, toggle):
398        """
399        """
400        self.lineEdit_13.setEnabled(toggle)
401
402    def highQToggle(self, clicked):
403        """
404        Disable/enable High Q extrapolation
405        """
406        self.radioButton_7.setEnabled(clicked)
407        self.radioButton_8.setEnabled(clicked)
408        self.lineEdit_12.setEnabled(clicked)
409        self.lineEdit_13.setEnabled(clicked)
410
411    def lowQToggle(self, clicked):
412        """
413        Disable/enable Low Q extrapolation
414        """
415        self.radioButton.setEnabled(clicked)
416        self.radioButton_2.setEnabled(clicked)
417        self.lineEdit_11.setEnabled(clicked and not self._low_fit)
418
419        # Enable subelements
420        self.radioButton_3.setEnabled(clicked and not self._low_guinier)
421        self.radioButton_4.setEnabled(clicked and not self._low_guinier)
422        self.lineEdit_10.setEnabled(clicked and not self._low_guinier)
423
424    def setupModel(self):
425
426        # filename
427        item = QtGui.QStandardItem(self._path)
428        self.model.setItem(WIDGETS.W_FILENAME, item)
429
430        # add Q parameters to the model
431        #qmin = min(self._data.x)
432        qmin = 0.0
433        item = QtGui.QStandardItem(str(qmin))
434        self.model.setItem(WIDGETS.W_QMIN, item)
435        qmax = 0.0
436        item = QtGui.QStandardItem(str(qmax))
437        self.model.setItem(WIDGETS.W_QMAX, item)
438
439        # add custom input params
440        item = QtGui.QStandardItem(str(self._background))
441        self.model.setItem(WIDGETS.W_BACKGROUND, item)
442        item = QtGui.QStandardItem(str(self._contrast))
443        self.model.setItem(WIDGETS.W_CONTRAST, item)
444        item = QtGui.QStandardItem(str(self._scale))
445        self.model.setItem(WIDGETS.W_SCALE, item)
446       
447        # Dialog elements
448        itemf = QtGui.QStandardItem("false")
449        self.model.setItem(WIDGETS.W_ENABLE_HIGHQ, itemf)
450        itemf = QtGui.QStandardItem("false")
451        self.model.setItem(WIDGETS.W_ENABLE_LOWQ, itemf)
452
453        item = QtGui.QStandardItem(str(self._npoints_low))
454        self.model.setItem(WIDGETS.W_NPTS_LOWQ, item)
455        item = QtGui.QStandardItem(str(self._npoints_high))
456        self.model.setItem(WIDGETS.W_NPTS_HIGHQ, item)
457
458        itemt = QtGui.QStandardItem("true")
459        self.model.setItem(WIDGETS.W_LOWQ_GUINIER, itemt)
460
461        itemt = QtGui.QStandardItem("true")
462        self.model.setItem(WIDGETS.W_LOWQ_FIT, itemt)
463        item = QtGui.QStandardItem(str(self._power_low))
464        self.model.setItem(WIDGETS.W_LOWQ_POWER_VALUE, item)
465
466        itemt = QtGui.QStandardItem("true")
467        self.model.setItem(WIDGETS.W_HIGHQ_FIT, itemt)
468        item = QtGui.QStandardItem(str(self._power_low))
469        self.model.setItem(WIDGETS.W_HIGHQ_POWER_VALUE, item)
470
471
472    def setupMapper(self):
473        # Set up the mapper.
474        self.mapper = QtGui.QDataWidgetMapper(self)
475        self.mapper.setOrientation(QtCore.Qt.Vertical)
476        self.mapper.setModel(self.model)
477
478        # Set up the view on the model for testing
479        # self.tableView.setModel(self.model)
480
481        # Filename
482        self.mapper.addMapping(self.lineEdit, WIDGETS.W_FILENAME)
483        # Qmin/Qmax
484        self.mapper.addMapping(self.lineEdit_2, WIDGETS.W_QMIN)
485        self.mapper.addMapping(self.lineEdit_3, WIDGETS.W_QMAX)
486
487        # Background
488        self.mapper.addMapping(self.lineEdit_4, WIDGETS.W_BACKGROUND)
489        # Scale
490        self.mapper.addMapping(self.lineEdit_5, WIDGETS.W_SCALE)
491        # Contrast
492        self.mapper.addMapping(self.lineEdit_6, WIDGETS.W_CONTRAST)
493
494        # Lowq/Highq items
495        self.mapper.addMapping(self.checkBox, WIDGETS.W_ENABLE_LOWQ)
496        self.mapper.addMapping(self.checkBox_2, WIDGETS.W_ENABLE_HIGHQ)
497
498        self.mapper.addMapping(self.lineEdit_10, WIDGETS.W_NPTS_LOWQ)
499        self.mapper.addMapping(self.radioButton, WIDGETS.W_LOWQ_GUINIER)
500
501        self.mapper.addMapping(self.radioButton_3, WIDGETS.W_LOWQ_FIT)
502        self.mapper.addMapping(self.lineEdit_11, WIDGETS.W_LOWQ_POWER_VALUE)
503
504        self.mapper.addMapping(self.radioButton_7, WIDGETS.W_HIGHQ_FIT)
505        self.mapper.addMapping(self.lineEdit_13, WIDGETS.W_HIGHQ_POWER_VALUE)
506   
507        # Output
508        self.mapper.addMapping(self.lineEdit_14, WIDGETS.W_VOLUME_FRACTION)
509        self.mapper.addMapping(self.lineEdit_15, WIDGETS.W_VOLUME_FRACTION_ERR)
510        self.mapper.addMapping(self.lineEdit_16, WIDGETS.W_SPECIFIC_SURFACE)
511        self.mapper.addMapping(self.lineEdit_17, WIDGETS.W_SPECIFIC_SURFACE_ERR)
512        self.mapper.addMapping(self.lineEdit_19, WIDGETS.W_INVARIANT)
513        self.mapper.addMapping(self.lineEdit_18, WIDGETS.W_INVARIANT_ERR)
514
515        self.mapper.toFirst()
516
517    def setData(self, data_item):
518        """
519        Obtain a QStandardItem object and dissect it to get Data1D/2D
520        Pass it over to the calculator
521        """
522        if not isinstance(data_item, list):
523            msg = "Incorrect type passed to the Invariant Perspective"
524            raise AttributeError, msg
525
526        if not isinstance(data_item[0], QtGui.QStandardItem):
527            msg = "Incorrect type passed to the Invariant Perspective"
528            raise AttributeError, msg
529
530        self._model_item = data_item[0]
531
532        # Extract data on 1st child - this is the Data1D/2D component
533        data = self._model_item.child(0).data().toPyObject()
534        self.model.item(WIDGETS.W_FILENAME).setData(QtCore.QVariant(self._model_item.text()))
535
536        ##### DEBUG ####
537        # set data in the debug tree view window
538        self.treeView.setModel(self.model)
539
540        self.calculate(data_list=[data])
541       
542    def calculate(self, data_list=None):
543        """
544        receive a list of data and compute invariant
545
546        TODO: pass warnings/messages to log
547        """
548        msg = ""
549        data = None
550        if data_list is None:
551            data_list = []
552        if len(data_list) >= 1:
553            if len(data_list) == 1:
554                data = data_list[0]
555            else:
556                data_1d_list = []
557                data_2d_list = []
558                error_msg = ""
559                # separate data into data1d and data2d list
560                for data in data_list:
561                    if data is not None:
562                        if issubclass(data.__class__, Data1D):
563                            data_1d_list.append(data)
564                        else:
565                            error_msg += " %s  type %s \n" % (str(data.name),
566                                                              str(data.__class__.__name__))
567                            data_2d_list.append(data)
568                if len(data_2d_list) > 0:
569                    msg = "Invariant does not support the following data types:\n"
570                    msg += error_msg
571                if len(data_1d_list) == 0:
572                    # remake this as a qt event
573                    #wx.PostEvent(self.parent, StatusEvent(status=msg, info='error'))
574                    return
575
576                # TODO: add msgbox for data choice
577                #msg += "Invariant panel does not allow multiple data!\n"
578                #msg += "Please select one.\n"
579                #if len(data_list) > 1:
580                    #from invariant_widgets import DataDialog
581                    #dlg = DataDialog(data_list=data_1d_list, text=msg)
582                    #if dlg.ShowModal() == wx.ID_OK:
583                    #    data = dlg.get_data()
584                    #else:
585                    #    data = None
586                    #dlg.Destroy()
587
588            if data is None:
589                msg += "invariant receives no data. \n"
590                #wx.PostEvent(self.parent, StatusEvent(status=msg, info='error'))
591                return
592            if not issubclass(data.__class__, Data1D):
593                msg += "invariant cannot be computed for data of "
594                msg += "type %s\n" % (data.__class__.__name__)
595                #wx.PostEvent(self.parent, StatusEvent(status=msg, info='error'))
596                return
597            else:
598                #wx.PostEvent(self.parent, NewPlotEvent(plot=data, title=data.title))
599                try:
600                    self._data = data
601                    self._path = "unique path"
602                    self.calculateInvariant()
603                except:
604                    msg = "Invariant Set_data: " + str(sys.exc_value)
605                    #wx.PostEvent(self.parent, StatusEvent(status=msg, info="error"))
606        else:
607            msg = "invariant cannot be computed for data of "
608            msg += "type %s" % (data.__class__.__name__)
609            #wx.PostEvent(self.parent, StatusEvent(status=msg, info='error'))
610
611    def allowBatch(self):
612        """
613        Tell the caller that we don't accept multiple data instances
614        """
615        return False
616
617if __name__ == "__main__":
618    app = QtGui.QApplication([])
619    import qt4reactor
620    qt4reactor.install()
621    # DO NOT move the following import to the top!
622    # (unless you know what you're doing)
623    from twisted.internet import reactor
624    dlg = InvariantWindow(reactor)
625    dlg.show()
626    reactor.run()
Note: See TracBrowser for help on using the repository browser.