source: sasview/src/sas/qtgui/Utilities/GuiUtils.py @ 4992ff2

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

Initial, in-progress version. Not really working atm. SASVIEW-787

  • Property mode set to 100644
File size: 26.9 KB
Line 
1"""
2Global defaults and various utility functions usable by the general GUI
3"""
4
5import os
6import re
7import sys
8import imp
9import warnings
10import webbrowser
11import urllib.parse
12
13warnings.simplefilter("ignore")
14import logging
15
16from PyQt5 import QtCore
17from PyQt5 import QtGui
18from PyQt5 import QtWidgets
19
20from periodictable import formula as Formula
21from sas.qtgui.Plotting import DataTransform
22from sas.qtgui.Plotting.ConvertUnits import convertUnit
23from sas.qtgui.Plotting.PlotterData import Data1D
24from sas.qtgui.Plotting.PlotterData import Data2D
25from sas.sascalc.dataloader.loader import Loader
26from sas.qtgui.Utilities import CustomDir
27
28## TODO: CHANGE FOR SHIPPED PATH IN RELEASE
29if os.path.splitext(sys.argv[0])[1].lower() != ".py":
30        HELP_DIRECTORY_LOCATION = "doc"
31else:
32        HELP_DIRECTORY_LOCATION = "docs/sphinx-docs/build/html"
33IMAGES_DIRECTORY_LOCATION = HELP_DIRECTORY_LOCATION + "/_images"
34
35def get_app_dir():
36    """
37        The application directory is the one where the default custom_config.py
38        file resides.
39
40        :returns: app_path - the path to the applicatin directory
41    """
42    # First, try the directory of the executable we are running
43    app_path = sys.path[0]
44    if os.path.isfile(app_path):
45        app_path = os.path.dirname(app_path)
46    if os.path.isfile(os.path.join(app_path, "custom_config.py")):
47        app_path = os.path.abspath(app_path)
48        #logging.info("Using application path: %s", app_path)
49        return app_path
50
51    # Next, try the current working directory
52    if os.path.isfile(os.path.join(os.getcwd(), "custom_config.py")):
53        #logging.info("Using application path: %s", os.getcwd())
54        return os.path.abspath(os.getcwd())
55
56    # Finally, try the directory of the sasview module
57    # TODO: gui_manager will have to know about sasview until we
58    # clean all these module variables and put them into a config class
59    # that can be passed by sasview.py.
60    #logging.info(sys.executable)
61    #logging.info(str(sys.argv))
62    from sas import sasview as sasview
63    app_path = os.path.dirname(sasview.__file__)
64    #logging.info("Using application path: %s", app_path)
65    return app_path
66
67def get_user_directory():
68    """
69        Returns the user's home directory
70    """
71    userdir = os.path.join(os.path.expanduser("~"), ".sasview")
72    if not os.path.isdir(userdir):
73        os.makedirs(userdir)
74    return userdir
75
76def _find_local_config(confg_file, path):
77    """
78        Find configuration file for the current application
79    """
80    config_module = None
81    fObj = None
82    try:
83        fObj, path_config, descr = imp.find_module(confg_file, [path])
84        config_module = imp.load_module(confg_file, fObj, path_config, descr)
85    except ImportError:
86        pass
87        #logging.error("Error loading %s/%s: %s" % (path, confg_file, sys.exc_value))
88    except ValueError:
89        print("Value error")
90        pass
91    finally:
92        if fObj is not None:
93            fObj.close()
94    #logging.info("GuiManager loaded %s/%s" % (path, confg_file))
95    return config_module
96
97
98# Get APP folder
99PATH_APP = get_app_dir()
100DATAPATH = PATH_APP
101
102# Read in the local config, which can either be with the main
103# application or in the installation directory
104config = _find_local_config('local_config', PATH_APP)
105
106if config is None:
107    config = _find_local_config('local_config', os.getcwd())
108else:
109    pass
110
111c_conf_dir = CustomDir.setup_conf_dir(PATH_APP)
112
113custom_config = _find_local_config('custom_config', c_conf_dir)
114if custom_config is None:
115    custom_config = _find_local_config('custom_config', os.getcwd())
116    if custom_config is None:
117        msgConfig = "Custom_config file was not imported"
118
119#read some constants from config
120APPLICATION_STATE_EXTENSION = config.APPLICATION_STATE_EXTENSION
121APPLICATION_NAME = config.__appname__
122SPLASH_SCREEN_PATH = config.SPLASH_SCREEN_PATH
123WELCOME_PANEL_ON = config.WELCOME_PANEL_ON
124SPLASH_SCREEN_WIDTH = config.SPLASH_SCREEN_WIDTH
125SPLASH_SCREEN_HEIGHT = config.SPLASH_SCREEN_HEIGHT
126SS_MAX_DISPLAY_TIME = config.SS_MAX_DISPLAY_TIME
127if not WELCOME_PANEL_ON:
128    WELCOME_PANEL_SHOW = False
129else:
130    WELCOME_PANEL_SHOW = True
131try:
132    DATALOADER_SHOW = custom_config.DATALOADER_SHOW
133    TOOLBAR_SHOW = custom_config.TOOLBAR_SHOW
134    FIXED_PANEL = custom_config.FIXED_PANEL
135    if WELCOME_PANEL_ON:
136        WELCOME_PANEL_SHOW = custom_config.WELCOME_PANEL_SHOW
137    PLOPANEL_WIDTH = custom_config.PLOPANEL_WIDTH
138    DATAPANEL_WIDTH = custom_config.DATAPANEL_WIDTH
139    GUIFRAME_WIDTH = custom_config.GUIFRAME_WIDTH
140    GUIFRAME_HEIGHT = custom_config.GUIFRAME_HEIGHT
141    CONTROL_WIDTH = custom_config.CONTROL_WIDTH
142    CONTROL_HEIGHT = custom_config.CONTROL_HEIGHT
143    DEFAULT_PERSPECTIVE = custom_config.DEFAULT_PERSPECTIVE
144    CLEANUP_PLOT = custom_config.CLEANUP_PLOT
145    # custom open_path
146    open_folder = custom_config.DEFAULT_OPEN_FOLDER
147    if open_folder is not None and os.path.isdir(open_folder):
148        DEFAULT_OPEN_FOLDER = os.path.abspath(open_folder)
149    else:
150        DEFAULT_OPEN_FOLDER = PATH_APP
151except AttributeError:
152    DATALOADER_SHOW = True
153    TOOLBAR_SHOW = True
154    FIXED_PANEL = True
155    WELCOME_PANEL_SHOW = False
156    PLOPANEL_WIDTH = config.PLOPANEL_WIDTH
157    DATAPANEL_WIDTH = config.DATAPANEL_WIDTH
158    GUIFRAME_WIDTH = config.GUIFRAME_WIDTH
159    GUIFRAME_HEIGHT = config.GUIFRAME_HEIGHT
160    CONTROL_WIDTH = -1
161    CONTROL_HEIGHT = -1
162    DEFAULT_PERSPECTIVE = None
163    CLEANUP_PLOT = False
164    DEFAULT_OPEN_FOLDER = PATH_APP
165
166#DEFAULT_STYLE = config.DEFAULT_STYLE
167
168PLUGIN_STATE_EXTENSIONS = config.PLUGIN_STATE_EXTENSIONS
169OPEN_SAVE_MENU = config.OPEN_SAVE_PROJECT_MENU
170VIEW_MENU = config.VIEW_MENU
171EDIT_MENU = config.EDIT_MENU
172extension_list = []
173if APPLICATION_STATE_EXTENSION is not None:
174    extension_list.append(APPLICATION_STATE_EXTENSION)
175EXTENSIONS = PLUGIN_STATE_EXTENSIONS + extension_list
176try:
177    PLUGINS_WLIST = '|'.join(config.PLUGINS_WLIST)
178except AttributeError:
179    PLUGINS_WLIST = ''
180APPLICATION_WLIST = config.APPLICATION_WLIST
181IS_WIN = True
182IS_LINUX = False
183CLOSE_SHOW = True
184TIME_FACTOR = 2
185NOT_SO_GRAPH_LIST = ["BoxSum"]
186
187
188class Communicate(QtCore.QObject):
189    """
190    Utility class for tracking of the Qt signals
191    """
192    # File got successfully read
193    fileReadSignal = QtCore.pyqtSignal(list)
194
195    # Open File returns "list" of paths
196    fileDataReceivedSignal = QtCore.pyqtSignal(dict)
197
198    # Update Main window status bar with "str"
199    # Old "StatusEvent"
200    statusBarUpdateSignal = QtCore.pyqtSignal(str)
201
202    # Send data to the current perspective
203    updatePerspectiveWithDataSignal = QtCore.pyqtSignal(list)
204
205    # New data in current perspective
206    updateModelFromPerspectiveSignal = QtCore.pyqtSignal(QtGui.QStandardItem)
207
208    # New theory data in current perspective
209    updateTheoryFromPerspectiveSignal = QtCore.pyqtSignal(QtGui.QStandardItem)
210
211    # New plot requested from the GUI manager
212    # Old "NewPlotEvent"
213    plotRequestedSignal = QtCore.pyqtSignal(list)
214
215    # Plot update requested from a perspective
216    plotUpdateSignal = QtCore.pyqtSignal(list)
217
218    # Progress bar update value
219    progressBarUpdateSignal = QtCore.pyqtSignal(int)
220
221    # Workspace charts added/removed
222    activeGraphsSignal = QtCore.pyqtSignal(list)
223
224    # Current workspace chart's name changed
225    activeGraphName = QtCore.pyqtSignal(tuple)
226
227    # Current perspective changed
228    perspectiveChangedSignal = QtCore.pyqtSignal(str)
229
230    # File/dataset got deleted
231    dataDeletedSignal = QtCore.pyqtSignal(list)
232
233    # Send data to Data Operation Utility panel
234    sendDataToPanelSignal = QtCore.pyqtSignal(dict)
235
236    # Send result of Data Operation Utility panel to Data Explorer
237    updateModelFromDataOperationPanelSignal = QtCore.pyqtSignal(QtGui.QStandardItem, dict)
238
239def updateModelItemWithPlot(item, update_data, name=""):
240    """
241    Adds a checkboxed row named "name" to QStandardItem
242    Adds 'update_data' to that row.
243    """
244    assert isinstance(item, QtGui.QStandardItem)
245    py_update_data = update_data
246
247    # Check if data with the same ID is already present
248    for index in range(item.rowCount()):
249        plot_item = item.child(index)
250        if plot_item.isCheckable():
251            plot_data = plot_item.child(0).data() #.toPyObject()
252            if plot_data.id is not None and plot_data.id == py_update_data.id:
253                # replace data section in item
254                plot_item.child(0).setData(update_data)
255                plot_item.setText(name)
256                # Plot title
257                plot_item.child(1).child(0).setText("Title: %s"%name)
258                # Force redisplay
259                return
260
261    # Create the new item
262    checkbox_item = createModelItemWithPlot(update_data, name)
263
264    # Append the new row to the main item
265    item.appendRow(checkbox_item)
266
267def createModelItemWithPlot(update_data, name=""):
268    """
269    Creates a checkboxed QStandardItem named "name"
270    Adds 'update_data' to that row.
271    """
272    #assert isinstance(update_data, QtCore.QVariant)
273    #py_update_data = update_data.toPyObject()
274    py_update_data = update_data
275
276    checkbox_item = QtGui.QStandardItem()
277    checkbox_item.setCheckable(True)
278    checkbox_item.setCheckState(QtCore.Qt.Checked)
279    checkbox_item.setText(name)
280
281    # Add "Info" item
282    if isinstance(py_update_data, (Data1D, Data2D)):
283        # If Data1/2D added - extract Info from it
284        info_item = infoFromData(py_update_data)
285    else:
286        # otherwise just add a naked item
287        info_item = QtGui.QStandardItem("Info")
288
289    # Add the actual Data1D/Data2D object
290    object_item = QtGui.QStandardItem()
291    object_item.setData(update_data)
292
293    # Set the data object as the first child
294    checkbox_item.setChild(0, object_item)
295
296    # Set info_item as the second child
297    checkbox_item.setChild(1, info_item)
298
299    # And return the newly created item
300    return checkbox_item
301
302def updateModelItem(item, update_data, name=""):
303    """
304    Adds a simple named child to QStandardItem
305    """
306    assert isinstance(item, QtGui.QStandardItem)
307    assert isinstance(update_data, list)
308
309    # Add the actual Data1D/Data2D object
310    object_item = QtGui.QStandardItem()
311    object_item.setText(name)
312    object_item.setData(update_data)
313
314    # Append the new row to the main item
315    item.appendRow(object_item)
316
317def itemFromFilename(filename, model_item):
318    """
319    Returns the model item text=filename in the model
320    """
321    assert isinstance(model_item, QtGui.QStandardItemModel)
322    assert isinstance(filename, str)
323
324    # Iterate over model looking for named items
325    item = list([i for i in [model_item.item(index) for index in range(model_item.rowCount())] if str(i.text()) == filename])
326    return item[0] if len(item)>0 else None
327
328def plotsFromFilename(filename, model_item):
329    """
330    Returns the list of plots for the item with text=filename in the model
331    """
332    assert isinstance(model_item, QtGui.QStandardItemModel)
333    assert isinstance(filename, str)
334
335    plot_data = []
336    # Iterate over model looking for named items
337    for index in range(model_item.rowCount()):
338        item = model_item.item(index)
339        if str(item.text()) == filename:
340            # TODO: assure item type is correct (either data1/2D or Plotter)
341            plot_data.append(item.child(0).data()) #.toPyObject())
342            # Going 1 level deeper only
343            for index_2 in range(item.rowCount()):
344                item_2 = item.child(index_2)
345                if item_2 and item_2.isCheckable():
346                    # TODO: assure item type is correct (either data1/2D or Plotter)
347                    plot_data.append(item_2.child(0).data()) #.toPyObject())
348
349    return plot_data
350
351def plotsFromCheckedItems(model_item):
352    """
353    Returns the list of plots for items in the model which are checked
354    """
355    assert isinstance(model_item, QtGui.QStandardItemModel)
356
357    plot_data = []
358    # Iterate over model looking for items with checkboxes
359    for index in range(model_item.rowCount()):
360        item = model_item.item(index)
361        if item.isCheckable() and item.checkState() == QtCore.Qt.Checked:
362            # TODO: assure item type is correct (either data1/2D or Plotter)
363            plot_data.append((item, item.child(0).data())) #.toPyObject()))
364        # Going 1 level deeper only
365        for index_2 in range(item.rowCount()):
366            item_2 = item.child(index_2)
367            if item_2 and item_2.isCheckable() and item_2.checkState() == QtCore.Qt.Checked:
368                # TODO: assure item type is correct (either data1/2D or Plotter)
369                plot_data.append((item_2, item_2.child(0).data())) #.toPyObject()))
370
371    return plot_data
372
373def infoFromData(data):
374    """
375    Given Data1D/Data2D object, extract relevant Info elements
376    and add them to a model item
377    """
378    assert isinstance(data, (Data1D, Data2D))
379
380    info_item = QtGui.QStandardItem("Info")
381
382    title_item = QtGui.QStandardItem("Title: " + data.title)
383    info_item.appendRow(title_item)
384    run_item = QtGui.QStandardItem("Run: " + str(data.run))
385    info_item.appendRow(run_item)
386    type_item = QtGui.QStandardItem("Type: " + str(data.__class__.__name__))
387    info_item.appendRow(type_item)
388
389    if data.path:
390        path_item = QtGui.QStandardItem("Path: " + data.path)
391        info_item.appendRow(path_item)
392
393    if data.instrument:
394        instr_item = QtGui.QStandardItem("Instrument: " + data.instrument)
395        info_item.appendRow(instr_item)
396
397    process_item = QtGui.QStandardItem("Process")
398    if isinstance(data.process, list) and data.process:
399        for process in data.process:
400            process_date = process.date
401            process_date_item = QtGui.QStandardItem("Date: " + process_date)
402            process_item.appendRow(process_date_item)
403
404            process_descr = process.description
405            process_descr_item = QtGui.QStandardItem("Description: " + process_descr)
406            process_item.appendRow(process_descr_item)
407
408            process_name = process.name
409            process_name_item = QtGui.QStandardItem("Name: " + process_name)
410            process_item.appendRow(process_name_item)
411
412    info_item.appendRow(process_item)
413
414    return info_item
415
416def openLink(url):
417    """
418    Open a URL in an external browser.
419    Check the URL first, though.
420    """
421    parsed_url = urllib.parse.urlparse(url)
422    if parsed_url.scheme:
423        webbrowser.open(url)
424    else:
425        msg = "Attempt at opening an invalid URL"
426        raise AttributeError(msg)
427
428def retrieveData1d(data):
429    """
430    Retrieve 1D data from file and construct its text
431    representation
432    """
433    if not isinstance(data, Data1D):
434        msg = "Incorrect type passed to retrieveData1d"
435        raise AttributeError(msg)
436    try:
437        xmin = min(data.x)
438        ymin = min(data.y)
439    except:
440        msg = "Unable to find min/max of \n data named %s" % \
441                    data.filename
442        #logging.error(msg)
443        raise ValueError(msg)
444
445    text = data.__str__()
446    text += 'Data Min Max:\n'
447    text += 'X_min = %s:  X_max = %s\n' % (xmin, max(data.x))
448    text += 'Y_min = %s:  Y_max = %s\n' % (ymin, max(data.y))
449    if data.dy is not None:
450        text += 'dY_min = %s:  dY_max = %s\n' % (min(data.dy), max(data.dy))
451    text += '\nData Points:\n'
452    x_st = "X"
453    for index in range(len(data.x)):
454        if data.dy is not None and len(data.dy) > index:
455            dy_val = data.dy[index]
456        else:
457            dy_val = 0.0
458        if data.dx is not None and len(data.dx) > index:
459            dx_val = data.dx[index]
460        else:
461            dx_val = 0.0
462        if data.dxl is not None and len(data.dxl) > index:
463            if index == 0:
464                x_st = "Xl"
465            dx_val = data.dxl[index]
466        elif data.dxw is not None and len(data.dxw) > index:
467            if index == 0:
468                x_st = "Xw"
469            dx_val = data.dxw[index]
470
471        if index == 0:
472            text += "<index> \t<X> \t<Y> \t<dY> \t<d%s>\n" % x_st
473        text += "%s \t%s \t%s \t%s \t%s\n" % (index,
474                                                data.x[index],
475                                                data.y[index],
476                                                dy_val,
477                                                dx_val)
478    return text
479
480def retrieveData2d(data):
481    """
482    Retrieve 2D data from file and construct its text
483    representation
484    """
485    if not isinstance(data, Data2D):
486        msg = "Incorrect type passed to retrieveData2d"
487        raise AttributeError(msg)
488
489    text = data.__str__()
490    text += 'Data Min Max:\n'
491    text += 'I_min = %s\n' % min(data.data)
492    text += 'I_max = %s\n\n' % max(data.data)
493    text += 'Data (First 2501) Points:\n'
494    text += 'Data columns include err(I).\n'
495    text += 'ASCII data starts here.\n'
496    text += "<index> \t<Qx> \t<Qy> \t<I> \t<dI> \t<dQparal> \t<dQperp>\n"
497    di_val = 0.0
498    dx_val = 0.0
499    dy_val = 0.0
500    len_data = len(data.qx_data)
501    for index in range(0, len_data):
502        x_val = data.qx_data[index]
503        y_val = data.qy_data[index]
504        i_val = data.data[index]
505        if data.err_data is not None:
506            di_val = data.err_data[index]
507        if data.dqx_data is not None:
508            dx_val = data.dqx_data[index]
509        if data.dqy_data is not None:
510            dy_val = data.dqy_data[index]
511
512        text += "%s \t%s \t%s \t%s \t%s \t%s \t%s\n" % (index,
513                                                        x_val,
514                                                        y_val,
515                                                        i_val,
516                                                        di_val,
517                                                        dx_val,
518                                                        dy_val)
519        # Takes too long time for typical data2d: Break here
520        if index >= 2500:
521            text += ".............\n"
522            break
523
524    return text
525
526def onTXTSave(data, path):
527    """
528    Save file as formatted txt
529    """
530    with open(path,'w') as out:
531        has_errors = True
532        if data.dy is None or data.dy == []:
533            has_errors = False
534        # Sanity check
535        if has_errors:
536            try:
537                if len(data.y) != len(data.dy):
538                    has_errors = False
539            except:
540                has_errors = False
541        if has_errors:
542            if data.dx is not None and data.dx != []:
543                out.write("<X>   <Y>   <dY>   <dX>\n")
544            else:
545                out.write("<X>   <Y>   <dY>\n")
546        else:
547            out.write("<X>   <Y>\n")
548
549        for i in range(len(data.x)):
550            if has_errors:
551                if data.dx is not None and data.dx != []:
552                    if  data.dx[i] is not None:
553                        out.write("%g  %g  %g  %g\n" % (data.x[i],
554                                                        data.y[i],
555                                                        data.dy[i],
556                                                        data.dx[i]))
557                    else:
558                        out.write("%g  %g  %g\n" % (data.x[i],
559                                                    data.y[i],
560                                                    data.dy[i]))
561                else:
562                    out.write("%g  %g  %g\n" % (data.x[i],
563                                                data.y[i],
564                                                data.dy[i]))
565            else:
566                out.write("%g  %g\n" % (data.x[i],
567                                        data.y[i]))
568
569def saveData1D(data):
570    """
571    Save 1D data points
572    """
573    default_name = os.path.basename(data.filename)
574    default_name, extension = os.path.splitext(default_name)
575    if not extension:
576        extension = ".txt"
577    default_name += "_out" + extension
578
579    wildcard = "Text files (*.txt);;"\
580                "CanSAS 1D files(*.xml)"
581    kwargs = {
582        'caption'   : 'Save As',
583        'directory' : default_name,
584        'filter'    : wildcard,
585        'parent'    : None,
586    }
587    # Query user for filename.
588    filename = QtWidgets.QFileDialog.getSaveFileName(**kwargs)
589
590    # User cancelled.
591    if not filename:
592        return
593
594    filename = str(filename)
595
596    #Instantiate a loader
597    loader = Loader()
598    if os.path.splitext(filename)[1].lower() == ".txt":
599        onTXTSave(data, filename)
600    if os.path.splitext(filename)[1].lower() == ".xml":
601        loader.save(filename, data, ".xml")
602
603def saveData2D(data):
604    """
605    Save data2d dialog
606    """
607    default_name = os.path.basename(data.filename)
608    default_name, _ = os.path.splitext(default_name)
609    ext_format = ".dat"
610    default_name += "_out" + ext_format
611
612    wildcard = "IGOR/DAT 2D file in Q_map (*.dat)"
613    kwargs = {
614        'caption'   : 'Save As',
615        'directory' : default_name,
616        'filter'    : wildcard,
617        'parent'    : None,
618    }
619    # Query user for filename.
620    filename = QtWidgets.QFileDialog.getSaveFileName(**kwargs)
621
622    # User cancelled.
623    if not filename:
624        return
625    filename = str(filename)
626    #Instantiate a loader
627    loader = Loader()
628
629    if os.path.splitext(filename)[1].lower() == ext_format:
630        loader.save(filename, data, ext_format)
631
632class FormulaValidator(QtGui.QValidator):
633    def __init__(self, parent=None):
634        super(FormulaValidator, self).__init__(parent)
635 
636    def validate(self, input, pos):
637        try:
638            Formula(str(input))
639            self._setStyleSheet("")
640            return QtGui.QValidator.Acceptable, pos
641
642        except Exception as e:
643            self._setStyleSheet("background-color:pink;")
644            return QtGui.QValidator.Intermediate, pos
645
646    def _setStyleSheet(self, value):
647        try:
648            if self.parent():
649                self.parent().setStyleSheet(value)
650        except:
651            pass
652
653def xyTransform(data, xLabel="", yLabel=""):
654    """
655    Transforms x and y in View and set the scale
656    """
657    # Changing the scale might be incompatible with
658    # currently displayed data (for instance, going
659    # from ln to log when all plotted values have
660    # negative natural logs).
661    # Go linear and only change the scale at the end.
662    xscale = 'linear'
663    yscale = 'linear'
664    # Local data is either 1D or 2D
665    if data.id == 'fit':
666        return
667
668    # control axis labels from the panel itself
669    yname, yunits = data.get_yaxis()
670    xname, xunits = data.get_xaxis()
671
672    # Goes through all possible scales
673    # self.x_label is already wrapped with Latex "$", so using the argument
674
675    # X
676    if xLabel == "x":
677        data.transformX(DataTransform.toX, DataTransform.errToX)
678        xLabel = "%s(%s)" % (xname, xunits)
679    if xLabel == "x^(2)":
680        data.transformX(DataTransform.toX2, DataTransform.errToX2)
681        xunits = convertUnit(2, xunits)
682        xLabel = "%s^{2}(%s)" % (xname, xunits)
683    if xLabel == "x^(4)":
684        data.transformX(DataTransform.toX4, DataTransform.errToX4)
685        xunits = convertUnit(4, xunits)
686        xLabel = "%s^{4}(%s)" % (xname, xunits)
687    if xLabel == "ln(x)":
688        data.transformX(DataTransform.toLogX, DataTransform.errToLogX)
689        xLabel = "\ln{(%s)}(%s)" % (xname, xunits)
690    if xLabel == "log10(x)":
691        data.transformX(DataTransform.toX_pos, DataTransform.errToX_pos)
692        xscale = 'log'
693        xLabel = "%s(%s)" % (xname, xunits)
694    if xLabel == "log10(x^(4))":
695        data.transformX(DataTransform.toX4, DataTransform.errToX4)
696        xunits = convertUnit(4, xunits)
697        xLabel = "%s^{4}(%s)" % (xname, xunits)
698        xscale = 'log'
699
700    # Y
701    if yLabel == "ln(y)":
702        data.transformY(DataTransform.toLogX, DataTransform.errToLogX)
703        yLabel = "\ln{(%s)}(%s)" % (yname, yunits)
704    if yLabel == "y":
705        data.transformY(DataTransform.toX, DataTransform.errToX)
706        yLabel = "%s(%s)" % (yname, yunits)
707    if yLabel == "log10(y)":
708        data.transformY(DataTransform.toX_pos, DataTransform.errToX_pos)
709        yscale = 'log'
710        yLabel = "%s(%s)" % (yname, yunits)
711    if yLabel == "y^(2)":
712        data.transformY(DataTransform.toX2, DataTransform.errToX2)
713        yunits = convertUnit(2, yunits)
714        yLabel = "%s^{2}(%s)" % (yname, yunits)
715    if yLabel == "1/y":
716        data.transformY(DataTransform.toOneOverX, DataTransform.errOneOverX)
717        yunits = convertUnit(-1, yunits)
718        yLabel = "1/%s(%s)" % (yname, yunits)
719    if yLabel == "y*x^(2)":
720        data.transformY(DataTransform.toYX2, DataTransform.errToYX2)
721        xunits = convertUnit(2, xunits)
722        yLabel = "%s \ \ %s^{2}(%s%s)" % (yname, xname, yunits, xunits)
723    if yLabel == "y*x^(4)":
724        data.transformY(DataTransform.toYX4, DataTransform.errToYX4)
725        xunits = convertUnit(4, xunits)
726        yLabel = "%s \ \ %s^{4}(%s%s)" % (yname, xname, yunits, xunits)
727    if yLabel == "1/sqrt(y)":
728        data.transformY(DataTransform.toOneOverSqrtX, DataTransform.errOneOverSqrtX)
729        yunits = convertUnit(-0.5, yunits)
730        yLabel = "1/\sqrt{%s}(%s)" % (yname, yunits)
731    if yLabel == "ln(y*x)":
732        data.transformY(DataTransform.toLogXY, DataTransform.errToLogXY)
733        yLabel = "\ln{(%s \ \ %s)}(%s%s)" % (yname, xname, yunits, xunits)
734    if yLabel == "ln(y*x^(2))":
735        data.transformY(DataTransform.toLogYX2, DataTransform.errToLogYX2)
736        xunits = convertUnit(2, xunits)
737        yLabel = "\ln (%s \ \ %s^{2})(%s%s)" % (yname, xname, yunits, xunits)
738    if yLabel == "ln(y*x^(4))":
739        data.transformY(DataTransform.toLogYX4, DataTransform.errToLogYX4)
740        xunits = convertUnit(4, xunits)
741        yLabel = "\ln (%s \ \ %s^{4})(%s%s)" % (yname, xname, yunits, xunits)
742    if yLabel == "log10(y*x^(4))":
743        data.transformY(DataTransform.toYX4, DataTransform.errToYX4)
744        xunits = convertUnit(4, xunits)
745        yscale = 'log'
746        yLabel = "%s \ \ %s^{4}(%s%s)" % (yname, xname, yunits, xunits)
747
748    # Perform the transformation of data in data1d->View
749    data.transformView()
750
751    return (xLabel, yLabel, xscale, yscale)
752
753def dataFromItem(item):
754    """
755    Retrieve Data1D/2D component from QStandardItem.
756    The assumption - data stored in SasView standard, in child 0
757    """
758    return item.child(0).data() #.toPyObject()
759
760def formatNumber(value, high=False):
761    """
762    Return a float in a standardized, human-readable formatted string.
763    This is used to output readable (e.g. x.xxxe-y) values to the panel.
764    """
765    try:
766        value = float(value)
767    except:
768        output = "NaN"
769        return output.lstrip().rstrip()
770
771    if high:
772        output = "%-7.5g" % value
773
774    else:
775        output = "%-5.3g" % value
776    return output.lstrip().rstrip()
777
778def convertUnitToHTML(unit):
779    """
780    Convert ASCII unit display into well rendering HTML
781    """
782    if unit == "1/A":
783        return "&#x212B;<sup>-1</sup>"
784    elif unit == "1/cm":
785        return "cm<sup>-1</sup>"
786    elif unit == "Ang":
787        return "&#x212B;"
788    elif unit == "1e-6/Ang^2":
789        return "10<sup>-6</sup>/&#x212B;<sup>2</sup>"
790    elif unit == "inf":
791        return "&#x221e;"
792    elif unit == "-inf":
793        return "-&#x221e;"
794    else:
795        return unit
796
797def parseName(name, expression):
798    """
799    remove "_" in front of a name
800    """
801    if re.match(expression, name) is not None:
802        word = re.split(expression, name, 1)
803        for item in word:           
804            if item.lstrip().rstrip() != '':
805                return item
806    else:
807        return name
Note: See TracBrowser for help on using the repository browser.