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

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 83d6249 was 83d6249, checked in by Piotr Rozyczko <rozyczko@…>, 7 years ago

Perspectives are now switchable and can be added "dynamically"

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