Changes in / [32c5983:2387abc] in sasview


Ignore:
Files:
6 added
1 deleted
21 edited

Legend:

Unmodified
Added
Removed
  • docs/sphinx-docs/build_sphinx.py

    reff1a8fc r8096b446  
    3535#/sasview-local-trunk/docs/sphinx-docs/build_sphinx.py 
    3636SASMODELS_SOURCE_PROLOG = os.path.join(CURRENT_SCRIPT_DIR, "..", "..", "..", "sasmodels", "doc") 
     37SASMODELS_SOURCE_MAGNETISM = os.path.join(CURRENT_SCRIPT_DIR, "..", "..", "..", "sasmodels", "doc", "ref", "magnetism") 
     38SASMODELS_SOURCE_MAGIMG = os.path.join(CURRENT_SCRIPT_DIR, "..", "..", "..", "sasmodels", "doc", "ref", "magnetism", "mag_img") 
    3739SASMODELS_SOURCE_REF_MODELS = os.path.join(CURRENT_SCRIPT_DIR, "..", "..", "..", "sasmodels", "doc", "ref", "models") 
    3840SASMODELS_SOURCE_MODELS = os.path.join(CURRENT_SCRIPT_DIR, "..", "..", "..", "sasmodels", "doc", "model") 
     
    4345SASMODELS_DEST_MODELS = os.path.join(CURRENT_SCRIPT_DIR, "source", "user", "models") 
    4446SASMODELS_DEST_IMG = os.path.join(CURRENT_SCRIPT_DIR,  "source", "user", "model-imgs", "new-models") 
     47SASMODELS_DEST_MAGIMG = os.path.join(CURRENT_SCRIPT_DIR,  "source", "user", "mag_img") 
    4548SASMODELS_DEST_BUILDIMG = os.path.join(CURRENT_SCRIPT_DIR,  "source", "user", "models", "img") 
    4649 
     
    136139 
    137140            copy_tree(docs, dest_dir) 
    138              
     141 
    139142    # Now pickup testdata_help.rst 
    140143#    print os.path.abspath(SASVIEW_TEST) 
     
    143146    if os.path.exists(SASVIEW_TEST): 
    144147       print "Found docs folder at ", SASVIEW_TEST 
    145        shutil.copytree(SASVIEW_TEST, SPHINX_SOURCE_TEST)        
    146  
    147     print "=== And the Sasmodels Docs ==="  
     148       shutil.copytree(SASVIEW_TEST, SPHINX_SOURCE_TEST) 
     149 
     150    print "=== And the Sasmodels Docs ===" 
    148151    # Make sure we have the relevant images for the new sasmodels documentation 
    149152    # First(!) we'll make a local reference copy for SasView (/new-models will be cleaned each build) 
     
    174177            shutil.copy(fromhere,tohere) 
    175178        else: print "no source directorty",SASMODELS_SOURCE_AUTOIMG ,"was found" 
    176      
     179 
    177180    # And the rst prolog with the unit substitutions 
    178181    if os.path.exists(SASMODELS_SOURCE_PROLOG): 
     
    186189                    tohere=os.path.join(SASMODELS_DEST_PROLOG,files) 
    187190                    shutil.copy(fromhere,tohere) 
     191 
     192    if os.path.exists(SASMODELS_SOURCE_MAGNETISM): 
     193        print "Found docs folder SASMODELS_SOURCE_MAGNETISM at ", SASMODELS_SOURCE_MAGNETISM 
     194        if os.path.exists(SASMODELS_DEST_REF_MODELS): 
     195            print "Found docs folder SASMODELS_DEST_REF_MODELS   at ", SASMODELS_DEST_REF_MODELS 
     196            print "Copying sasmodels model toctree files..." 
     197            for files in os.listdir(SASMODELS_SOURCE_MAGNETISM): 
     198                if files.endswith(".rst"): 
     199                    fromhere=os.path.join(SASMODELS_SOURCE_MAGNETISM,files) 
     200                    tohere=os.path.join(SASMODELS_DEST_REF_MODELS,files) 
     201                    shutil.copy(fromhere,tohere) 
     202 
     203    if os.path.exists(SASMODELS_SOURCE_MAGIMG): 
     204        print "Found img  folder SASMODELS_SOURCE_MAGIMG    at ", SASMODELS_SOURCE_MAGIMG 
     205        if not os.path.exists(SASMODELS_DEST_MAGIMG): 
     206            print "Missing docs folder SASMODELS_DEST_MAGIMG at ", SASMODELS_DEST_MAGIMG 
     207            os.makedirs(SASMODELS_DEST_MAGIMG) 
     208            print "created SASMODELS_DEST_MAGIMG at ", SASMODELS_DEST_MAGIMG 
     209        print "Copying sasmodels model auto-generated image files..." 
     210        for files in os.listdir(SASMODELS_SOURCE_MAGIMG): 
     211            fromhere=os.path.join(SASMODELS_SOURCE_MAGIMG,files) 
     212            tohere=os.path.join(SASMODELS_DEST_MAGIMG,files) 
     213            shutil.copy(fromhere,tohere) 
     214        else: print "no source directorty",SASMODELS_SOURCE_MAGIMG ,"was found" 
    188215 
    189216    if os.path.exists(SASMODELS_SOURCE_REF_MODELS): 
  • sasview/installer_generator.py

    r6a698c0 r09afe90  
    199199    msg += """Source: "dist\plugin_models\*";\tDestDir: "{userdesktop}\..\.sasview\plugin_models";\t""" 
    200200    msg += """Flags: recursesubdirs createallsubdirs\n"""  
    201     msg += """Source: "dist\compiled_models\*";\tDestDir: "{userdesktop}\..\.sasmodels\compiled_models";\t""" 
    202     msg += """Flags: recursesubdirs createallsubdirs\n""" 
    203201    msg += """Source: "dist\config\custom_config.py";\tDestDir: "{userdesktop}\..\.sasview\config";\t"""  
    204202    msg += """Flags: recursesubdirs createallsubdirs\n""" 
  • sasview/sasview.py

    rc23f303 rcde6e52  
    9999APP_NAME = 'SasView' 
    100100 
     101from matplotlib import backend_bases 
     102backend_bases.FigureCanvasBase.filetypes.pop('pgf', None) 
     103 
    101104class SasView(): 
    102105    """ 
  • sasview/setup_exe.py

    r98d89df r09afe90  
    209209data_files += guiframe.data_files() 
    210210 
    211 # precompile sas models into the sasview build path; doesn't matter too much 
    212 # where it is so long as it is a place that will get cleaned up afterwards. 
    213 import sasmodels.core 
    214 dll_path = os.path.join(build_path, 'compiled_models') 
    215 compiled_dlls = sasmodels.core.precompile_dlls(dll_path, dtype='double') 
    216  
    217 # include the compiled models as data; coordinate the target path for the 
    218 # data with installer_generator.py 
    219 data_files.append(('compiled_models', compiled_dlls)) 
    220  
    221211import sasmodels 
    222212data_files += sasmodels.data_files() 
  • src/sas/sascalc/dataloader/data_info.py

    rd72567e r45d7662  
    445445        return len(self.name) == 0 and len(self.date) == 0 and len(self.description) == 0 \ 
    446446            and len(self.term) == 0 and len(self.notes) == 0 
    447              
     447 
    448448    def single_line_desc(self): 
    449449        """ 
     
    451451        """ 
    452452        return "%s %s %s" % (self.name, self.date, self.description) 
    453       
     453 
    454454    def __str__(self): 
    455455        _str = "Process:\n" 
     
    10371037        _str += "   Z-axis:       %s\t[%s]\n" % (self._zaxis, self._zunit) 
    10381038        _str += "   Length:       %g \n" % (len(self.data)) 
     1039        _str += "   Shape:        (%d, %d)\n" % (len(self.y_bins), len(self.x_bins)) 
    10391040        return _str 
    10401041 
     
    12201221        result.mask = numpy.append(self.mask, other.mask) 
    12211222        if result.err_data is not None: 
    1222             result.err_data = numpy.append(self.err_data, other.err_data)  
     1223            result.err_data = numpy.append(self.err_data, other.err_data) 
    12231224        if self.dqx_data is not None: 
    12241225            result.dqx_data = numpy.append(self.dqx_data, other.dqx_data) 
     
    12521253        final_dataset.yaxis(data._yaxis, data._yunit) 
    12531254        final_dataset.zaxis(data._zaxis, data._zunit) 
     1255        final_dataset.x_bins = data.x_bins 
     1256        final_dataset.y_bins = data.y_bins 
    12541257    else: 
    12551258        return_string = "Should Never Happen: _combine_data_info_with_plottable input is not a plottable1d or " + \ 
  • src/sas/sascalc/dataloader/readers/cansas_constants.py

    rd398285 r250fec92  
    2727        return_me.current_level = self.CANSAS_FORMAT.get("SASentry") 
    2828        # Defaults for variable and datatype 
    29         return_me.ns_variable = "{0}.meta_data[\"{2}\"] = \"{1}\"" 
    3029        return_me.ns_datatype = "content" 
    3130        return_me.ns_optional = True 
     
    3837                        return_me.current_level = \ 
    3938                                return_me.current_level.get("<any>", "") 
    40                     cl_variable = return_me.current_level.get("variable", "") 
    4139                    cl_datatype = return_me.current_level.get("storeas", "") 
    4240                    cl_units_optional = \ 
    43                              return_me.current_level.get("units_required", "") 
     41                             return_me.current_level.get("units_optional", "") 
    4442                    # Where are how to store the variable for the given 
    4543                    # namespace CANSAS_CONSTANTS tree is hierarchical, so 
    4644                    # is no value, inherit 
    47                     return_me.ns_variable = cl_variable if cl_variable != "" \ 
    48                         else return_me.ns_variable 
    4945                    return_me.ns_datatype = cl_datatype if cl_datatype != "" \ 
    5046                        else return_me.ns_datatype 
     
    5349                                        else return_me.ns_optional 
    5450            except AttributeError: 
    55                 return_me.ns_variable = "{0}.meta_data[\"{2}\"] = \"{1}\"" 
    5651                return_me.ns_datatype = "content" 
    5752                return_me.ns_optional = True 
     
    7570    # The constants below hold information on where to store the CanSAS data 
    7671    # when loaded in using sasview 
    77     META_DATA = "{0}.meta_data[\"{2}\"] = \"{1}\"" 
    78     ANY = {"variable" : "{0}.meta_data[\"{2}\"] = \'{1}\'", 
    79            "storeas" : "content", 
    80           } 
    81     TITLE = {"variable" : "{0}.title = \"{1}\""} 
    82     SASNOTE = {"variable" : "{0}.notes.append(\'{1}\')"} 
    83     SASPROCESS_TERM = {"variable" : None, 
    84                        "attributes" : {"unit" : {"variable" : None}, 
    85                                        "name" : {"variable" : None} 
    86                                       } 
    87                       } 
    88     SASPROCESS_SASPROCESSNOTE = {"variable" : None, 
    89                                  "children" : {"<any>" : ANY} 
    90                                 } 
    91     SASPROCESS = {"variable" : None, 
    92                   "children" : {"name" : {"variable" : "{0}.name = \'{1}\'"}, 
    93                                 "date" : {"variable" : "{0}.date = \'{1}\'"}, 
    94                                 "description" : 
    95                                 {"variable" : "{0}.description = \'{1}\'"}, 
     72    ANY = {"storeas" : "content"} 
     73    TITLE = {} 
     74    SASNOTE = {} 
     75    SASPROCESS_TERM = {"attributes" : {"unit" : {}, "name" : {}}} 
     76    SASPROCESS_SASPROCESSNOTE = {"children" : {"<any>" : ANY}} 
     77    SASPROCESS = {"children" : {"name" : {}, 
     78                                "date" : {}, 
     79                                "description" : {}, 
    9680                                "term" : SASPROCESS_TERM, 
    9781                                "SASprocessnote" : SASPROCESS_SASPROCESSNOTE, 
     
    9983                               }, 
    10084                 } 
    101     RUN = {"variable" : "{0}.run.append(\"{1}\")", 
    102            "attributes" : {"name" : 
    103                            {"variable" : "{0}.run_name[\"{3}\"] = \"{1}\""}} 
    104           } 
    105     SASDATA_IDATA_Q = {"variable" : "{0}.x = numpy.append({0}.x, {1})", 
    106                        "unit" : "x_unit", 
    107                        "attributes" : {"unit" : 
    108                                        {"variable" : "{0}.xaxis(\"Q\", \'{1}\')", 
    109                                         "storeas" : "content" 
    110                                        } 
    111                                       }, 
    112                       } 
    113     SASDATA_IDATA_I = {"variable" : "{0}.y = numpy.append({0}.y, {1})", 
    114                        "unit" : "y_unit", 
    115                        "attributes" : {"unit" : 
    116                                        {"variable" : "{0}.yaxis(\"Intensity\", \'{1}\')", 
    117                                         "storeas" : "content" 
    118                                        } 
    119                                       }, 
    120                       } 
    121     SASDATA_IDATA_IDEV = {"variable" : "{0}.dy = numpy.append({0}.dy, {1})", 
     85    RUN = {"attributes" : {"name" :{}}} 
     86    SASDATA_IDATA_Q = {"units_optional" : False, 
     87                       "storeas" : "float", 
     88                        "unit" : "x_unit", 
     89                       "attributes" : {"unit" : {"storeas" : "content"}}, 
     90                      } 
     91    SASDATA_IDATA_I = {"units_optional" : False, 
     92                       "storeas" : "float", 
     93                        "unit" : "y_unit", 
     94                       "attributes" : {"unit" : {"storeas" : "content"}}, 
     95                      } 
     96    SASDATA_IDATA_IDEV = {"units_optional" : False, 
     97                          "storeas" : "float", 
    12298                          "unit" : "y_unit", 
    123                           "attributes" : {"unit" : 
    124                                           {"variable" : META_DATA, 
    125                                            "storeas" : "content" 
    126                                           } 
    127                                          }, 
    128                          } 
    129     SASDATA_IDATA_QDEV = {"variable" : "{0}.dx = numpy.append({0}.dx, {1})", 
     99                          "attributes" : {"unit" : {"storeas" : "content"}}, 
     100                         } 
     101    SASDATA_IDATA_QDEV = {"units_optional" : False, 
     102                          "storeas" : "float", 
    130103                          "unit" : "x_unit", 
    131                           "attributes" : {"unit" : 
    132                                           {"variable" : META_DATA, 
    133                                            "storeas" : "content" 
    134                                           } 
    135                                          }, 
    136                          } 
    137     SASDATA_IDATA_DQL = {"variable" : "{0}.dxl = numpy.append({0}.dxl, {1})", 
     104                          "attributes" : {"unit" : {"storeas" : "content"}}, 
     105                         } 
     106    SASDATA_IDATA_DQL = {"units_optional" : False, 
     107                         "storeas" : "float", 
    138108                         "unit" : "x_unit", 
    139                          "attributes" : {"unit" : 
    140                                          {"variable" : META_DATA, 
    141                                           "storeas" : "content" 
    142                                          } 
    143                                         }, 
    144                         } 
    145     SASDATA_IDATA_DQW = {"variable" : "{0}.dxw = numpy.append({0}.dxw, {1})", 
     109                         "attributes" : {"unit" : {"storeas" : "content"}}, 
     110                        } 
     111    SASDATA_IDATA_DQW = {"units_optional" : False, 
     112                         "storeas" : "float", 
    146113                         "unit" : "x_unit", 
    147                          "attributes" : {"unit" : 
    148                                          {"variable" : META_DATA, 
    149                                           "storeas" : "content" 
    150                                          } 
    151                                         }, 
    152                         } 
    153     SASDATA_IDATA_QMEAN = {"storeas" : "content", 
    154                            "unit" : "x_unit", 
    155                            "variable" : META_DATA, 
    156                            "attributes" : {"unit" : {"variable" : META_DATA}}, 
     114                         "attributes" : {"unit" : {"storeas" : "content"}}, 
     115                        } 
     116    SASDATA_IDATA_QMEAN = {"unit" : "x_unit", 
     117                           "attributes" : {"unit" : {}}, 
    157118                          } 
    158     SASDATA_IDATA_SHADOWFACTOR = {"variable" : META_DATA, 
    159                                   "storeas" : "content", 
    160                                  } 
    161     SASDATA_IDATA = {"storeas" : "float", 
    162                      "units_optional" : False, 
    163                      "variable" : None, 
    164                      "attributes" : {"name" : {"variable" : META_DATA, 
    165                                                "storeas" : "content", 
    166                                               }, 
    167                                      "timestamp" : {"variable" : META_DATA, 
    168                                                     "storeas" : "timestamp", 
    169                                                    } 
    170                                     }, 
     119    SASDATA_IDATA_SHADOWFACTOR = {} 
     120    SASDATA_IDATA = {"attributes" : {"name" : {},"timestamp" : {"storeas" : "timestamp"}}, 
    171121                     "children" : {"Q" : SASDATA_IDATA_Q, 
    172122                                   "I" : SASDATA_IDATA_I, 
     
    180130                                  } 
    181131                    } 
    182     SASDATA = {"attributes" : {"name" : {"variable" : META_DATA,}}, 
     132    SASDATA = {"attributes" : {"name" : {}}, 
    183133               "variable" : None, 
    184134               "children" : {"Idata" : SASDATA_IDATA, 
     
    186136                            } 
    187137              } 
    188     SASTRANSSPEC_TDATA_LAMDBA = {"variable" : "{0}.wavelength.append({1})", 
     138    SASTRANSSPEC_TDATA_LAMDBA = {"storeas" : "float", 
    189139                                 "unit" : "wavelength_unit", 
    190                                  "attributes" : 
    191                                  {"unit" : 
    192                                   {"variable" : "{0}.wavelength_unit = \"{1}\"", 
    193                                    "storeas" : "content" 
    194                                   } 
    195                                  } 
     140                                 "attributes" : {"unit" : {"storeas" : "content"}} 
    196141                                } 
    197     SASTRANSSPEC_TDATA_T = {"variable" : "{0}.transmission.append({1})", 
     142    SASTRANSSPEC_TDATA_T = {"storeas" : "float", 
    198143                            "unit" : "transmission_unit", 
    199                             "attributes" : 
    200                             {"unit" : 
    201                              {"variable" : "{0}.transmission_unit = \"{1}\"", 
    202                               "storeas" : "content" 
    203                              } 
    204                             } 
    205                            } 
    206     SASTRANSSPEC_TDATA_TDEV = {"variable" : 
    207                                "{0}.transmission_deviation.append({1})", 
     144                            "attributes" : {"unit" : {"storeas" : "content"}} 
     145                           } 
     146    SASTRANSSPEC_TDATA_TDEV = {"storeas" : "float", 
    208147                               "unit" : "transmission_deviation_unit", 
    209                                "attributes" : 
    210                                {"unit" : 
    211                                 {"variable" : 
    212                                  "{0}.transmission_deviation_unit = \"{1}\"", 
    213                                  "storeas" : "content" 
    214                                 } 
    215                                } 
    216                               } 
    217     SASTRANSSPEC_TDATA = {"storeas" : "float", 
    218                           "variable" : None, 
    219                           "children" : {"Lambda" : SASTRANSSPEC_TDATA_LAMDBA, 
     148                               "attributes" : {"unit" :{"storeas" : "content"}} 
     149                              } 
     150    SASTRANSSPEC_TDATA = {"children" : {"Lambda" : SASTRANSSPEC_TDATA_LAMDBA, 
    220151                                        "T" : SASTRANSSPEC_TDATA_T, 
    221152                                        "Tdev" : SASTRANSSPEC_TDATA_TDEV, 
     
    223154                                       } 
    224155                         } 
    225     SASTRANSSPEC = {"variable" : None, 
    226                     "children" : {"Tdata" : SASTRANSSPEC_TDATA, 
     156    SASTRANSSPEC = {"children" : {"Tdata" : SASTRANSSPEC_TDATA, 
    227157                                  "<any>" : ANY, 
    228158                                 }, 
    229                     "attributes" : 
    230                     {"name" : 
    231                      {"variable" : "{0}.name = \"{1}\""}, 
    232                      "timestamp" : 
    233                      {"variable" : "{0}.timestamp = \"{1}\""}, 
    234                     } 
     159                    "attributes" : {"name" :{}, "timestamp" : {},} 
    235160                   } 
    236     SASSAMPLE_THICK = {"variable" : "{0}.sample.thickness = {1}", 
    237                        "unit" : "sample.thickness_unit", 
    238                        "storeas" : "float", 
    239                        "attributes" : 
    240                        {"unit" : 
    241                         {"variable" : "{0}.sample.thickness_unit = \"{1}\"", 
    242                          "storeas" : "content" 
    243                         } 
    244                        }, 
    245                       } 
    246     SASSAMPLE_TRANS = {"variable" : "{0}.sample.transmission = {1}", 
    247                        "storeas" : "float", 
    248                       } 
    249     SASSAMPLE_TEMP = {"variable" : "{0}.sample.temperature = {1}", 
    250                       "unit" : "sample.temperature_unit", 
     161    SASSAMPLE_THICK = {"unit" : "thickness_unit", 
     162                       "storeas" : "float", 
     163                       "attributes" : {"unit" :{}}, 
     164                      } 
     165    SASSAMPLE_TRANS = {"storeas" : "float",} 
     166    SASSAMPLE_TEMP = {"unit" : "temperature_unit", 
    251167                      "storeas" : "float", 
    252                       "attributes" : 
    253                       {"unit" : 
    254                        {"variable" : "{0}.sample.temperature_unit = \"{1}\"", 
    255                         "storeas" : "content" 
    256                        } 
    257                       }, 
     168                      "attributes" :{"unit" :{}}, 
    258169                     } 
    259     SASSAMPLE_POS_ATTR = {"unit" : {"variable" : 
    260                                     "{0}.sample.position_unit = \"{1}\"", 
    261                                     "storeas" : "content" 
    262                                    } 
    263                          } 
    264     SASSAMPLE_POS_X = {"variable" : "{0}.sample.position.x = {1}", 
    265                        "unit" : "sample.position_unit", 
     170    SASSAMPLE_POS_ATTR = {"unit" : {}} 
     171    SASSAMPLE_POS_X = {"unit" : "position_unit", 
    266172                       "storeas" : "float", 
    267173                       "attributes" : SASSAMPLE_POS_ATTR 
    268174                      } 
    269     SASSAMPLE_POS_Y = {"variable" : "{0}.sample.position.y = {1}", 
    270                        "unit" : "sample.position_unit", 
     175    SASSAMPLE_POS_Y = {"unit" : "position_unit", 
    271176                       "storeas" : "float", 
    272177                       "attributes" : SASSAMPLE_POS_ATTR 
    273178                      } 
    274     SASSAMPLE_POS_Z = {"variable" : "{0}.sample.position.z = {1}", 
    275                        "unit" : "sample.position_unit", 
     179    SASSAMPLE_POS_Z = {"unit" : "position_unit", 
    276180                       "storeas" : "float", 
    277181                       "attributes" : SASSAMPLE_POS_ATTR 
    278182                      } 
    279     SASSAMPLE_POS = {"children" : {"variable" : None, 
    280                                    "x" : SASSAMPLE_POS_X, 
     183    SASSAMPLE_POS = {"children" : {"x" : SASSAMPLE_POS_X, 
    281184                                   "y" : SASSAMPLE_POS_Y, 
    282185                                   "z" : SASSAMPLE_POS_Z, 
    283186                                  }, 
    284187                    } 
    285     SASSAMPLE_ORIENT_ATTR = {"unit" : 
    286                              {"variable" : 
    287                               "{0}.sample.orientation_unit = \"{1}\"", 
    288                               "storeas" : "content" 
    289                              } 
    290                             } 
    291     SASSAMPLE_ORIENT_ROLL = {"variable" : "{0}.sample.orientation.x = {1}", 
    292                              "unit" : "sample.orientation_unit", 
     188    SASSAMPLE_ORIENT_ATTR = {"unit" :{}} 
     189    SASSAMPLE_ORIENT_ROLL = {"unit" : "orientation_unit", 
    293190                             "storeas" : "float", 
    294191                             "attributes" : SASSAMPLE_ORIENT_ATTR 
    295192                            } 
    296     SASSAMPLE_ORIENT_PITCH = {"variable" : "{0}.sample.orientation.y = {1}", 
    297                               "unit" : "sample.orientation_unit", 
     193    SASSAMPLE_ORIENT_PITCH = {"unit" : "orientation_unit", 
    298194                              "storeas" : "float", 
    299195                              "attributes" : SASSAMPLE_ORIENT_ATTR 
    300196                             } 
    301     SASSAMPLE_ORIENT_YAW = {"variable" : "{0}.sample.orientation.z = {1}", 
    302                             "unit" : "sample.orientation_unit", 
     197    SASSAMPLE_ORIENT_YAW = {"unit" : "orientation_unit", 
    303198                            "storeas" : "float", 
    304199                            "attributes" : SASSAMPLE_ORIENT_ATTR 
    305200                           } 
    306     SASSAMPLE_ORIENT = {"variable" : None, 
    307                         "children" : {"roll" : SASSAMPLE_ORIENT_ROLL, 
     201    SASSAMPLE_ORIENT = {"children" : {"roll" : SASSAMPLE_ORIENT_ROLL, 
    308202                                      "pitch" : SASSAMPLE_ORIENT_PITCH, 
    309203                                      "yaw" : SASSAMPLE_ORIENT_YAW, 
     
    311205                       } 
    312206    SASSAMPLE = {"attributes" : 
    313                  {"name" : {"variable" : "{0}.sample.name = \"{1}\""},}, 
    314                  "variable" : None, 
    315                  "children" : {"ID" : {"variable" : "{0}.sample.ID = \"{1}\""}, 
     207                 {"name" : {},}, 
     208                 "children" : {"ID" : {}, 
    316209                               "thickness" : SASSAMPLE_THICK, 
    317210                               "transmission" : SASSAMPLE_TRANS, 
     
    319212                               "position" : SASSAMPLE_POS, 
    320213                               "orientation" : SASSAMPLE_ORIENT, 
    321                                "details" : 
    322                                {"variable" : 
    323                                 "{0}.sample.details.append(\"{1}\")"}, 
     214                               "details" : {}, 
    324215                               "<any>" : ANY 
    325216                              }, 
    326217                } 
    327     SASINSTR_SRC_BEAMSIZE_ATTR = {"unit" : 
    328                                   "{0}.source.beam_size_unit = \"{1}\"", 
    329                                   "storeas" : "content" 
    330                                  } 
    331     SASINSTR_SRC_BEAMSIZE_X = {"variable" : "{0}.source.beam_size.x = {1}", 
    332                                "unit" : "source.beam_size_unit", 
     218    SASINSTR_SRC_BEAMSIZE_ATTR = {"unit" : ""} 
     219    SASINSTR_SRC_BEAMSIZE_X = {"unit" : "beam_size_unit", 
    333220                               "storeas" : "float", 
    334221                               "attributes" : SASINSTR_SRC_BEAMSIZE_ATTR 
    335222                              } 
    336     SASINSTR_SRC_BEAMSIZE_Y = {"variable" : "{0}.source.beam_size.y = {1}", 
    337                                "unit" : "source.beam_size_unit", 
     223    SASINSTR_SRC_BEAMSIZE_Y = {"unit" : "beam_size_unit", 
    338224                               "storeas" : "float", 
    339225                               "attributes" : SASINSTR_SRC_BEAMSIZE_ATTR 
    340226                              } 
    341     SASINSTR_SRC_BEAMSIZE_Z = {"variable" : "{0}.source.beam_size.z = {1}", 
    342                                "unit" : "source.beam_size_unit", 
     227    SASINSTR_SRC_BEAMSIZE_Z = {"unit" : "beam_size_unit", 
    343228                               "storeas" : "float", 
    344229                               "attributes" : SASINSTR_SRC_BEAMSIZE_ATTR 
    345230                              } 
    346     SASINSTR_SRC_BEAMSIZE = {"attributes" : 
    347                              {"name" : {"variable" : 
    348                                         "{0}.source.beam_size_name = \"{1}\""}}, 
    349                              "variable" : None, 
     231    SASINSTR_SRC_BEAMSIZE = {"attributes" : {"name" : {}}, 
    350232                             "children" : {"x" : SASINSTR_SRC_BEAMSIZE_X, 
    351233                                           "y" : SASINSTR_SRC_BEAMSIZE_Y, 
     
    353235                                          } 
    354236                            } 
    355     SASINSTR_SRC_WL = {"variable" : "{0}.source.wavelength = {1}", 
    356                        "unit" : "source.wavelength_unit", 
    357                        "storeas" : "float", 
    358                        "attributes" : 
    359                        {"unit" : 
    360                         {"variable" : "{0}.source.wavelength_unit = \"{1}\"", 
    361                          "storeas" : "content" 
    362                         }, 
     237    SASINSTR_SRC_WL = {"unit" : "wavelength_unit", 
     238                       "storeas" : "float", 
     239                       "attributes" : {"unit" :{}, 
    363240                       } 
    364241                      } 
    365     SASINSTR_SRC_WL_MIN = {"variable" : "{0}.source.wavelength_min = {1}", 
    366                            "unit" : "source.wavelength_min_unit", 
     242    SASINSTR_SRC_WL_MIN = {"unit" : "wavelength_min_unit", 
    367243                           "storeas" : "float", 
    368                            "attributes" : 
    369                            {"unit" : 
    370                             {"variable" : 
    371                              "{0}.source.wavelength_min_unit = \"{1}\"", 
    372                              "storeas" : "content" 
    373                             }, 
    374                            } 
     244                           "attributes" : {"unit" :{"storeas" : "content"},} 
    375245                          } 
    376     SASINSTR_SRC_WL_MAX = {"variable" : "{0}.source.wavelength_max = {1}", 
    377                            "unit" : "source.wavelength_max_unit", 
     246    SASINSTR_SRC_WL_MAX = {"unit" : "wavelength_max_unit", 
    378247                           "storeas" : "float", 
    379                            "attributes" : 
    380                            {"unit" : 
    381                             {"variable" : 
    382                              "{0}.source.wavelength_max_unit = \"{1}\"", 
    383                              "storeas" : "content" 
    384                             }, 
    385                            } 
     248                           "attributes" : {"unit" :{"storeas" : "content"},} 
    386249                          } 
    387     SASINSTR_SRC_WL_SPR = {"variable" : "{0}.source.wavelength_spread = {1}", 
    388                            "unit" : "source.wavelength_spread_unit", 
     250    SASINSTR_SRC_WL_SPR = {"unit" : "wavelength_spread_unit", 
    389251                           "storeas" : "float", 
    390                            "attributes" : 
    391                            {"unit" : 
    392                             {"variable" : 
    393                              "{0}.source.wavelength_spread_unit = \"{1}\"", 
    394                              "storeas" : "content" 
    395                             }, 
    396                            } 
     252                           "attributes" : {"unit" : {"storeas" : "content"},} 
    397253                          } 
    398     SASINSTR_SRC = {"attributes" : {"name" : {"variable" : 
    399                                               "{0}.source.name = \"{1}\""}}, 
    400                     "variable" : None, 
    401                     "children" : {"radiation" : 
    402                                   {"variable" : 
    403                                    "{0}.source.radiation = \"{1}\""}, 
     254    SASINSTR_SRC = {"attributes" : {"name" : {}}, 
     255                    "children" : {"radiation" : {}, 
    404256                                  "beam_size" : SASINSTR_SRC_BEAMSIZE, 
    405                                   "beam_shape" : 
    406                                   {"variable" : 
    407                                    "{0}.source.beam_shape = \"{1}\""}, 
     257                                  "beam_shape" : {}, 
    408258                                  "wavelength" : SASINSTR_SRC_WL, 
    409259                                  "wavelength_min" : SASINSTR_SRC_WL_MIN, 
     
    412262                                 }, 
    413263                   } 
    414     SASINSTR_COLL_APER_ATTR = {"unit" : {"variable" : "{0}.size_unit = \"{1}\"", 
    415                                          "storeas" : "content" 
    416                                         }, 
    417                               } 
    418     SASINSTR_COLL_APER_X = {"variable" : "{0}.size.x = {1}", 
    419                             "unit" : "size_unit", 
     264    SASINSTR_COLL_APER_ATTR = {"unit" : {}} 
     265    SASINSTR_COLL_APER_X = {"unit" : "size_unit", 
    420266                            "storeas" : "float", 
    421267                            "attributes" : SASINSTR_COLL_APER_ATTR 
    422268                           } 
    423     SASINSTR_COLL_APER_Y = {"variable" : "{0}.size.y = {1}", 
    424                             "unit" : "size_unit", 
     269    SASINSTR_COLL_APER_Y = {"unit" : "size_unit", 
    425270                            "storeas" : "float", 
    426271                            "attributes" : SASINSTR_COLL_APER_ATTR 
    427272                           } 
    428     SASINSTR_COLL_APER_Z = {"variable" : "{0}.size.z = {1}", 
    429                             "unit" : "size_unit", 
     273    SASINSTR_COLL_APER_Z = {"unit" : "size_unit", 
    430274                            "storeas" : "float", 
    431275                            "attributes" : SASINSTR_COLL_APER_ATTR 
    432276                           } 
    433     SASINSTR_COLL_APER_SIZE = {"attributes" : 
    434                                {"unit" : {"variable" : 
    435                                           "{0}.size_unit = \"{1}\""}}, 
     277    SASINSTR_COLL_APER_SIZE = {"attributes" : {"unit" : {}}, 
    436278                               "children" : {"storeas" : "float", 
    437279                                             "x" : SASINSTR_COLL_APER_X, 
     
    441283                              } 
    442284    SASINSTR_COLL_APER_DIST = {"storeas" : "float", 
    443                                "attributes" : 
    444                                {"storeas" : "content", 
    445                                 "unit" : {"variable" : 
    446                                           "{0}.distance_unit = \"{1}\""} 
    447                                }, 
    448                                "variable" : "{0}.distance = {1}", 
     285                               "attributes" : {"unit" : {}}, 
    449286                               "unit" : "distance_unit", 
    450287                              } 
    451     SASINSTR_COLL_APER = {"variable" : None, 
    452                           "attributes" : {"name" : {"variable" : 
    453                                                     "{0}.name = \"{1}\""}, 
    454                                           "type" : {"variable" : 
    455                                                     "{0}.type = \"{1}\""}, 
    456                                          }, 
     288    SASINSTR_COLL_APER = {"attributes" : {"name" : {}, "type" : {}, }, 
    457289                          "children" : {"size" : SASINSTR_COLL_APER_SIZE, 
    458290                                        "distance" : SASINSTR_COLL_APER_DIST 
    459291                                       } 
    460292                         } 
    461     SASINSTR_COLL = {"attributes" : 
    462                      {"name" : {"variable" : "{0}.name = \"{1}\""}}, 
    463                      "variable" : None, 
     293    SASINSTR_COLL = {"attributes" : {"name" : {}}, 
    464294                     "children" : 
    465                      {"length" : 
    466                       {"variable" : "{0}.length = {1}", 
    467                        "unit" : "length_unit", 
    468                        "storeas" : "float", 
    469                        "attributes" : 
    470                        {"storeas" : "content", 
    471                         "unit" : {"variable" : "{0}.length_unit = \"{1}\""} 
    472                        }, 
    473                       }, 
    474                       "aperture" : SASINSTR_COLL_APER, 
    475                      }, 
     295                         {"length" : 
     296                          {"unit" : "length_unit", 
     297                           "storeas" : "float", 
     298                           "attributes" : {"storeas" : "content", "unit" : {}}, 
     299                          }, 
     300                          "aperture" : SASINSTR_COLL_APER, 
     301                         }, 
    476302                    } 
    477     SASINSTR_DET_SDD = {"variable" : "{0}.distance = {1}", 
     303    SASINSTR_DET_SDD = {"storeas" : "float", 
    478304                        "unit" : "distance_unit", 
    479                         "attributes" : 
    480                         {"unit" : 
    481                          {"variable" : "{0}.distance_unit = \"{1}\"", 
    482                           "storeas" : "content" 
    483                          } 
    484                         }, 
     305                        "attributes" : {"unit" :{}}, 
    485306                       } 
    486     SASINSTR_DET_OFF_ATTR = {"unit" : {"variable" : "{0}.offset_unit = \"{1}\"", 
    487                                        "storeas" : "content" 
    488                                       }, 
    489                             } 
    490     SASINSTR_DET_OFF_X = {"variable" : "{0}.offset.x = {1}", 
     307    SASINSTR_DET_OFF_ATTR = {"unit" : {"storeas" : "content" }} 
     308    SASINSTR_DET_OFF_X = {"storeas" : "float", 
    491309                          "unit" : "offset_unit", 
    492310                          "attributes" : SASINSTR_DET_OFF_ATTR 
    493311                         } 
    494     SASINSTR_DET_OFF_Y = {"variable" : "{0}.offset.y = {1}", 
     312    SASINSTR_DET_OFF_Y = {"storeas" : "float", 
    495313                          "unit" : "offset_unit", 
    496314                          "attributes" : SASINSTR_DET_OFF_ATTR 
    497315                         } 
    498     SASINSTR_DET_OFF_Z = {"variable" : "{0}.offset.z = {1}", 
     316    SASINSTR_DET_OFF_Z = {"storeas" : "float", 
    499317                          "unit" : "offset_unit", 
    500318                          "attributes" : SASINSTR_DET_OFF_ATTR 
    501319                         } 
    502     SASINSTR_DET_OFF = {"variable" : None, 
    503                         "children" : {"x" : SASINSTR_DET_OFF_X, 
     320    SASINSTR_DET_OFF = {"children" : {"x" : SASINSTR_DET_OFF_X, 
    504321                                      "y" : SASINSTR_DET_OFF_Y, 
    505322                                      "z" : SASINSTR_DET_OFF_Z, 
    506323                                     } 
    507324                       } 
    508     SASINSTR_DET_OR_ATTR = {"unit" : "{0}.orientation_unit = \"{1}\"", 
    509                             "storeas" : "content" 
    510                            } 
    511     SASINSTR_DET_OR_ROLL = {"variable" : "{0}.orientation.x = {1}", 
     325    SASINSTR_DET_OR_ATTR = {} 
     326    SASINSTR_DET_OR_ROLL = {"storeas" : "float", 
    512327                            "unit" : "orientation_unit", 
    513328                            "attributes" : SASINSTR_DET_OR_ATTR 
    514329                           } 
    515     SASINSTR_DET_OR_PITCH = {"variable" : "{0}.orientation.y = {1}", 
     330    SASINSTR_DET_OR_PITCH = {"storeas" : "float", 
    516331                             "unit" : "orientation_unit", 
    517332                             "attributes" : SASINSTR_DET_OR_ATTR 
    518333                            } 
    519     SASINSTR_DET_OR_YAW = {"variable" : "{0}.orientation.z = {1}", 
     334    SASINSTR_DET_OR_YAW = {"storeas" : "float", 
    520335                           "unit" : "orientation_unit", 
    521336                           "attributes" : SASINSTR_DET_OR_ATTR 
    522337                          } 
    523     SASINSTR_DET_OR = {"variable" : None, 
    524                        "children" : {"roll" : SASINSTR_DET_OR_ROLL, 
     338    SASINSTR_DET_OR = {"children" : {"roll" : SASINSTR_DET_OR_ROLL, 
    525339                                     "pitch" : SASINSTR_DET_OR_PITCH, 
    526340                                     "yaw" : SASINSTR_DET_OR_YAW, 
    527341                                    } 
    528342                      } 
    529     SASINSTR_DET_BC_X = {"variable" : "{0}.beam_center.x = {1}", 
     343    SASINSTR_DET_BC_X = {"storeas" : "float", 
    530344                         "unit" : "beam_center_unit", 
    531                          "attributes" : 
    532                          {"unit" : "{0}.beam_center_unit = \"{1}\"", 
    533                           "storeas" : "content" 
    534                          } 
    535                         } 
    536     SASINSTR_DET_BC_Y = {"variable" : "{0}.beam_center.y = {1}", 
     345                         "attributes" : {"storeas" : "content"} 
     346                        } 
     347    SASINSTR_DET_BC_Y = {"storeas" : "float", 
    537348                         "unit" : "beam_center_unit", 
    538                          "attributes" : 
    539                          {"unit" : "{0}.beam_center_unit = \"{1}\"", 
    540                           "storeas" : "content" 
    541                          } 
    542                         } 
    543     SASINSTR_DET_BC_Z = {"variable" : "{0}.beam_center.z = {1}", 
     349                         "attributes" : {"storeas" : "content"} 
     350                        } 
     351    SASINSTR_DET_BC_Z = {"storeas" : "float", 
    544352                         "unit" : "beam_center_unit", 
    545                          "attributes" : 
    546                          {"unit" : "{0}.beam_center_unit = \"{1}\"", 
    547                           "storeas" : "content" 
    548                          } 
    549                         } 
    550     SASINSTR_DET_BC = {"variable" : None, 
    551                        "children" : {"x" : SASINSTR_DET_BC_X, 
     353                         "attributes" : {"storeas" : "content"} 
     354                        } 
     355    SASINSTR_DET_BC = {"children" : {"x" : SASINSTR_DET_BC_X, 
    552356                                     "y" : SASINSTR_DET_BC_Y, 
    553                                      "z" : SASINSTR_DET_BC_Z, 
    554                                     } 
    555                       } 
    556     SASINSTR_DET_PIXEL_X = {"variable" : "{0}.pixel_size.x = {1}", 
     357                                     "z" : SASINSTR_DET_BC_Z,} 
     358                      } 
     359    SASINSTR_DET_PIXEL_X = {"storeas" : "float", 
    557360                            "unit" : "pixel_size_unit", 
    558                             "attributes" : 
    559                             {"unit" : "{0}.pixel_size_unit = \"{1}\"", 
    560                              "storeas" : "content" 
    561                             } 
    562                            } 
    563     SASINSTR_DET_PIXEL_Y = {"variable" : "{0}.pixel_size.y = {1}", 
     361                            "attributes" : {"storeas" : "content" } 
     362                           } 
     363    SASINSTR_DET_PIXEL_Y = {"storeas" : "float", 
    564364                            "unit" : "pixel_size_unit", 
    565                             "attributes" : 
    566                             {"unit" : "{0}.pixel_size_unit = \"{1}\"", 
    567                              "storeas" : "content" 
    568                             } 
    569                            } 
    570     SASINSTR_DET_PIXEL_Z = {"variable" : "{0}.pixel_size.z = {1}", 
     365                            "attributes" : {"storeas" : "content"} 
     366                           } 
     367    SASINSTR_DET_PIXEL_Z = {"storeas" : "float", 
    571368                            "unit" : "pixel_size_unit", 
    572                             "attributes" : 
    573                             {"unit" : "{0}.pixel_size_unit = \"{1}\"", 
    574                              "storeas" : "content" 
    575                             } 
    576                            } 
    577     SASINSTR_DET_PIXEL = {"variable" : None, 
    578                           "children" : {"x" : SASINSTR_DET_PIXEL_X, 
     369                            "attributes" : {"storeas" : "content"} 
     370                           } 
     371    SASINSTR_DET_PIXEL = {"children" : {"x" : SASINSTR_DET_PIXEL_X, 
    579372                                        "y" : SASINSTR_DET_PIXEL_Y, 
    580373                                        "z" : SASINSTR_DET_PIXEL_Z, 
    581374                                       } 
    582375                         } 
    583     SASINSTR_DET_SLIT = {"variable" : "{0}.slit_length = {1}", 
     376    SASINSTR_DET_SLIT = {"storeas" : "float", 
    584377                         "unit" : "slit_length_unit", 
    585                          "attributes" : 
    586                          {"unit" : 
    587                           {"variable" : "{0}.slit_length_unit = \"{1}\"", 
    588                            "storeas" : "content" 
    589                           } 
    590                          } 
    591                         } 
    592     SASINSTR_DET = {"storeas" : "float", 
    593                     "variable" : None, 
    594                     "attributes" : {"name" : 
    595                                     {"storeas" : "content", 
    596                                      "variable" : "{0}.name = \"{1}\"", 
    597                                     } 
    598                                    }, 
    599                     "children" : {"name" : {"storeas" : "content", 
    600                                             "variable" : "{0}.name = \"{1}\"", 
    601                                            }, 
     378                         "attributes" : {"unit" : {}} 
     379                        } 
     380    SASINSTR_DET = {"attributes" : {"name" : {"storeas" : "content"}}, 
     381                    "children" : {"name" : {"storeas" : "content"}, 
    602382                                  "SDD" : SASINSTR_DET_SDD, 
    603383                                  "offset" : SASINSTR_DET_OFF, 
     
    608388                                 } 
    609389                   } 
    610     SASINSTR = {"variable" : None, 
    611                 "children" : 
    612                 {"variable" : None, 
    613                  "name" : {"variable" : "{0}.instrument = \"{1}\""}, 
     390    SASINSTR = {"children" : 
     391                {"name" : {}, 
    614392                 "SASsource" : SASINSTR_SRC, 
    615393                 "SAScollimation" : SASINSTR_COLL, 
     
    619397    CANSAS_FORMAT = {"SASentry" : 
    620398                     {"units_optional" : True, 
    621                       "variable" : None, 
    622399                      "storeas" : "content", 
    623                       "attributes" : {"name" : 
    624                                       {"variable" : 
    625                                        "{0}.run_name[\"{3}\"] = \"{1}\""}}, 
     400                      "attributes" : {"name" : {}}, 
    626401                      "children" : {"Title" : TITLE, 
    627402                                    "Run" : RUN, 
     
    644419 
    645420    current_level = '' 
    646     ns_variable = '' 
    647421    ns_datatype = '' 
    648422    ns_optional = True 
     
    650424    def __init__(self): 
    651425        self.current_level = {} 
    652         self.ns_variable = '' 
    653426        self.ns_datatype = "content" 
    654427        self.ns_optional = True 
  • src/sas/sascalc/dataloader/readers/cansas_reader.py

    r83b6408 r5f26aa4  
    1414 
    1515import logging 
    16 import numpy 
     16import numpy as np 
    1717import os 
    1818import sys 
     
    2020import inspect 
    2121# For saving individual sections of data 
    22 from sas.sascalc.dataloader.data_info import Data1D 
    23 from sas.sascalc.dataloader.data_info import Collimation 
    24 from sas.sascalc.dataloader.data_info import TransmissionSpectrum 
    25 from sas.sascalc.dataloader.data_info import Detector 
    26 from sas.sascalc.dataloader.data_info import Process 
    27 from sas.sascalc.dataloader.data_info import Aperture 
     22from sas.sascalc.dataloader.data_info import Data1D, DataInfo, plottable_1D 
     23from sas.sascalc.dataloader.data_info import Collimation, TransmissionSpectrum, Detector, Process, Aperture 
     24from sas.sascalc.dataloader.data_info import combine_data_info_with_plottable as combine_data 
    2825import sas.sascalc.dataloader.readers.xml_reader as xml_reader 
    2926from sas.sascalc.dataloader.readers.xml_reader import XMLreader 
    30 from sas.sascalc.dataloader.readers.cansas_constants import CansasConstants 
     27from sas.sascalc.dataloader.readers.cansas_constants import CansasConstants, CurrentLevel 
    3128 
    3229# The following 2 imports *ARE* used. Do not remove either. 
     
    3431from xml.dom.minidom import parseString 
    3532 
    36 ## TODO: Refactor to load multiple <SASData> as separate Data1D objects 
    37 ## TODO: Refactor to allow invalid XML, but give a useful warning when loaded 
    38  
    39 _ZERO = 1e-16 
    4033PREPROCESS = "xmlpreprocess" 
    4134ENCODING = "encoding" 
    4235RUN_NAME_DEFAULT = "None" 
     36INVALID_SCHEMA_PATH_1_1 = "{0}/sas/sascalc/dataloader/readers/schema/cansas1d_invalid_v1_1.xsd" 
     37INVALID_SCHEMA_PATH_1_0 = "{0}/sas/sascalc/dataloader/readers/schema/cansas1d_invalid_v1_0.xsd" 
     38INVALID_XML = "\n\nThe loaded xml file, {0} does not fully meet the CanSAS v1.x specification. SasView loaded " + \ 
     39              "as much of the data as possible.\n\n" 
    4340HAS_CONVERTER = True 
    4441try: 
     
    5249ALLOW_ALL = True 
    5350 
    54 # DO NOT REMOVE Called by outside packages: 
    55 #    sas.sasgui.perspectives.invariant.invariant_state 
    56 #    sas.sasgui.perspectives.fitting.pagestate 
    57 def get_content(location, node): 
    58     """ 
    59     Get the first instance of the content of a xpath location. 
    60  
    61     :param location: xpath location 
    62     :param node: node to start at 
    63  
    64     :return: Element, or None 
    65     """ 
    66     nodes = node.xpath(location, 
    67                        namespaces={'ns': CANSAS_NS.get("1.0").get("ns")}) 
    68     if len(nodes) > 0: 
    69         return nodes[0] 
    70     else: 
    71         return None 
    72  
    73 # DO NOT REMOVE Called by outside packages: 
    74 #    sas.sasgui.perspectives.fitting.pagestate 
    75 def write_node(doc, parent, name, value, attr=None): 
    76     """ 
    77     :param doc: document DOM 
    78     :param parent: parent node 
    79     :param name: tag of the element 
    80     :param value: value of the child text node 
    81     :param attr: attribute dictionary 
    82  
    83     :return: True if something was appended, otherwise False 
    84     """ 
    85     if attr is None: 
    86         attr = {} 
    87     if value is not None: 
    88         node = doc.createElement(name) 
    89         node.appendChild(doc.createTextNode(str(value))) 
    90         for item in attr: 
    91             node.setAttribute(item, attr[item]) 
    92         parent.appendChild(node) 
    93         return True 
    94     return False 
    95  
    9651class Reader(XMLreader): 
    9752    """ 
     
    10156        The CanSAS reader requires PyXML 0.8.4 or later. 
    10257    """ 
    103     ##CanSAS version - defaults to version 1.0 
     58    ## CanSAS version - defaults to version 1.0 
    10459    cansas_version = "1.0" 
    10560    base_ns = "{cansas1d/1.0}" 
     61    cansas_defaults = None 
     62    type_name = "canSAS" 
     63    invalid = True 
     64    ## Log messages and errors 
    10665    logging = None 
    107     errors = None 
    108     type_name = "canSAS" 
     66    errors = set() 
     67    ## Namespace hierarchy for current xml_file object 
     68    names = None 
     69    ns_list = None 
     70    ## Temporary storage location for loading multiple data sets in a single file 
     71    current_datainfo = None 
     72    current_dataset = None 
     73    current_data1d = None 
     74    data = None 
     75    ## List of data1D objects to be sent back to SasView 
     76    output = None 
    10977    ## Wildcards 
    11078    type = ["XML files (*.xml)|*.xml", "SasView Save Files (*.svs)|*.svs"] 
     
    11482    allow_all = True 
    11583 
    116     def __init__(self): 
    117         ## List of errors 
    118         self.errors = set() 
     84    def reset_state(self): 
     85        """ 
     86        Resets the class state to a base case when loading a new data file so previous 
     87        data files do not appear a second time 
     88        """ 
     89        self.current_datainfo = None 
     90        self.current_dataset = None 
     91        self.current_data1d = None 
     92        self.data = [] 
     93        self.process = Process() 
     94        self.transspectrum = TransmissionSpectrum() 
     95        self.aperture = Aperture() 
     96        self.collimation = Collimation() 
     97        self.detector = Detector() 
     98        self.names = [] 
     99        self.cansas_defaults = {} 
     100        self.output = [] 
     101        self.ns_list = None 
    119102        self.logging = [] 
    120103        self.encoding = None 
     104 
     105    def read(self, xml_file, schema_path="", invalid=True): 
     106        """ 
     107        Validate and read in an xml_file file in the canSAS format. 
     108 
     109        :param xml_file: A canSAS file path in proper XML format 
     110        :param schema_path: A file path to an XML schema to validate the xml_file against 
     111        """ 
     112        # For every file loaded, reset everything to a base state 
     113        self.reset_state() 
     114        self.invalid = invalid 
     115        # Check that the file exists 
     116        if os.path.isfile(xml_file): 
     117            basename, extension = os.path.splitext(os.path.basename(xml_file)) 
     118            # If the file type is not allowed, return nothing 
     119            if extension in self.ext or self.allow_all: 
     120                # Get the file location of 
     121                self.load_file_and_schema(xml_file, schema_path) 
     122                self.add_data_set() 
     123                # Try to load the file, but raise an error if unable to. 
     124                # Check the file matches the XML schema 
     125                try: 
     126                    self.is_cansas(extension) 
     127                    self.invalid = False 
     128                    # Get each SASentry from XML file and add it to a list. 
     129                    entry_list = self.xmlroot.xpath( 
     130                            '/ns:SASroot/ns:SASentry', 
     131                            namespaces={'ns': self.cansas_defaults.get("ns")}) 
     132                    self.names.append("SASentry") 
     133 
     134                    # Get all preprocessing events and encoding 
     135                    self.set_processing_instructions() 
     136 
     137                    # Parse each <SASentry> item 
     138                    for entry in entry_list: 
     139                        # Create a new DataInfo object for every <SASentry> 
     140 
     141 
     142                        # Set the file name and then parse the entry. 
     143                        self.current_datainfo.filename = basename + extension 
     144                        self.current_datainfo.meta_data["loader"] = "CanSAS XML 1D" 
     145                        self.current_datainfo.meta_data[PREPROCESS] = \ 
     146                            self.processing_instructions 
     147 
     148                        # Parse the XML SASentry 
     149                        self._parse_entry(entry) 
     150                        # Combine datasets with datainfo 
     151                        self.add_data_set() 
     152                except RuntimeError: 
     153                    # If the file does not match the schema, raise this error 
     154                    invalid_xml = self.find_invalid_xml() 
     155                    invalid_xml = INVALID_XML.format(basename + extension) + invalid_xml 
     156                    self.errors.add(invalid_xml) 
     157                    # Try again with an invalid CanSAS schema, that requires only a data set in each 
     158                    base_name = xml_reader.__file__ 
     159                    base_name = base_name.replace("\\", "/") 
     160                    base = base_name.split("/sas/")[0] 
     161                    if self.cansas_version == "1.1": 
     162                        invalid_schema = INVALID_SCHEMA_PATH_1_1.format(base, self.cansas_defaults.get("schema")) 
     163                    else: 
     164                        invalid_schema = INVALID_SCHEMA_PATH_1_0.format(base, self.cansas_defaults.get("schema")) 
     165                    self.set_schema(invalid_schema) 
     166                    try: 
     167                        if self.invalid: 
     168                            if self.is_cansas(): 
     169                                self.output = self.read(xml_file, invalid_schema, False) 
     170                            else: 
     171                                raise RuntimeError 
     172                        else: 
     173                            raise RuntimeError 
     174                    except RuntimeError: 
     175                        x = np.zeros(1) 
     176                        y = np.zeros(1) 
     177                        self.current_data1d = Data1D(x,y) 
     178                        self.current_data1d.errors = self.errors 
     179                        return [self.current_data1d] 
     180        else: 
     181            self.output.append("Not a valid file path.") 
     182        # Return a list of parsed entries that dataloader can manage 
     183        return self.output 
     184 
     185    def _parse_entry(self, dom): 
     186        """ 
     187        Parse a SASEntry - new recursive method for parsing the dom of 
     188            the CanSAS data format. This will allow multiple data files 
     189            and extra nodes to be read in simultaneously. 
     190 
     191        :param dom: dom object with a namespace base of names 
     192        """ 
     193 
     194        frm = inspect.stack()[1] 
     195        if not self._is_call_local(frm): 
     196            self.reset_state() 
     197            self.add_data_set() 
     198            self.names.append("SASentry") 
     199            self.parent_class = "SASentry" 
     200        self._check_for_empty_data() 
     201        self.base_ns = "{0}{1}{2}".format("{", \ 
     202                            CANSAS_NS.get(self.cansas_version).get("ns"), "}") 
     203        tagname = '' 
     204        tagname_original = '' 
     205 
     206        # Go through each child in the parent element 
     207        for node in dom: 
     208            attr = node.attrib 
     209            name = attr.get("name", "") 
     210            type = attr.get("type", "") 
     211            # Get the element name and set the current names level 
     212            tagname = node.tag.replace(self.base_ns, "") 
     213            tagname_original = tagname 
     214            # Skip this iteration when loading in save state information 
     215            if tagname == "fitting_plug_in" or tagname == "pr_inversion" or tagname == "invariant": 
     216                continue 
     217 
     218            # Get where to store content 
     219            self.names.append(tagname_original) 
     220            self.ns_list = CONSTANTS.iterate_namespace(self.names) 
     221            # If the element is a child element, recurse 
     222            if len(node.getchildren()) > 0: 
     223                self.parent_class = tagname_original 
     224                if tagname == 'SASdata': 
     225                    self._initialize_new_data_set() 
     226                ## Recursion step to access data within the group 
     227                self._parse_entry(node) 
     228                if tagname == "SASsample": 
     229                    self.current_datainfo.sample.name = name 
     230                elif tagname == "beam_size": 
     231                    self.current_datainfo.source.beam_size_name = name 
     232                elif tagname == "SAScollimation": 
     233                    self.collimation.name = name 
     234                elif tagname == "aperture": 
     235                    self.aperture.name = name 
     236                    self.aperture.type = type 
     237                self.add_intermediate() 
     238            else: 
     239                data_point, unit = self._get_node_value(node, tagname) 
     240 
     241                ## If this is a dataset, store the data appropriately 
     242                if tagname == 'Run': 
     243                    self.current_datainfo.run_name[data_point] = name 
     244                    self.current_datainfo.run.append(data_point) 
     245                elif tagname == 'Title': 
     246                    self.current_datainfo.title = data_point 
     247                elif tagname == 'SASnote': 
     248                    self.current_datainfo.notes.append(data_point) 
     249 
     250                ## I and Q Data 
     251                elif tagname == 'I': 
     252                    self.current_dataset.yaxis("Intensity", unit) 
     253                    self.current_dataset.y = np.append(self.current_dataset.y, data_point) 
     254                elif tagname == 'Idev': 
     255                    self.current_dataset.dy = np.append(self.current_dataset.dy, data_point) 
     256                elif tagname == 'Q': 
     257                    self.current_dataset.xaxis("Q", unit) 
     258                    self.current_dataset.x = np.append(self.current_dataset.x, data_point) 
     259                elif tagname == 'Qdev': 
     260                    self.current_dataset.dx = np.append(self.current_dataset.dx, data_point) 
     261                elif tagname == 'dQw': 
     262                    self.current_dataset.dxw = np.append(self.current_dataset.dxw, data_point) 
     263                elif tagname == 'dQl': 
     264                    self.current_dataset.dxl = np.append(self.current_dataset.dxl, data_point) 
     265                elif tagname == 'Qmean': 
     266                    pass 
     267                elif tagname == 'Shadowfactor': 
     268                    pass 
     269 
     270                ## Sample Information 
     271                elif tagname == 'ID' and self.parent_class == 'SASsample': 
     272                    self.current_datainfo.sample.ID = data_point 
     273                elif tagname == 'Title' and self.parent_class == 'SASsample': 
     274                    self.current_datainfo.sample.name = data_point 
     275                elif tagname == 'thickness' and self.parent_class == 'SASsample': 
     276                    self.current_datainfo.sample.thickness = data_point 
     277                    self.current_datainfo.sample.thickness_unit = unit 
     278                elif tagname == 'transmission' and self.parent_class == 'SASsample': 
     279                    self.current_datainfo.sample.transmission = data_point 
     280                elif tagname == 'temperature' and self.parent_class == 'SASsample': 
     281                    self.current_datainfo.sample.temperature = data_point 
     282                    self.current_datainfo.sample.temperature_unit = unit 
     283                elif tagname == 'details' and self.parent_class == 'SASsample': 
     284                    self.current_datainfo.sample.details.append(data_point) 
     285                elif tagname == 'x' and self.parent_class == 'position': 
     286                    self.current_datainfo.sample.position.x = data_point 
     287                    self.current_datainfo.sample.position_unit = unit 
     288                elif tagname == 'y' and self.parent_class == 'position': 
     289                    self.current_datainfo.sample.position.y = data_point 
     290                    self.current_datainfo.sample.position_unit = unit 
     291                elif tagname == 'z' and self.parent_class == 'position': 
     292                    self.current_datainfo.sample.position.z = data_point 
     293                    self.current_datainfo.sample.position_unit = unit 
     294                elif tagname == 'roll' and self.parent_class == 'orientation' and 'SASsample' in self.names: 
     295                    self.current_datainfo.sample.orientation.x = data_point 
     296                    self.current_datainfo.sample.orientation_unit = unit 
     297                elif tagname == 'pitch' and self.parent_class == 'orientation' and 'SASsample' in self.names: 
     298                    self.current_datainfo.sample.orientation.y = data_point 
     299                    self.current_datainfo.sample.orientation_unit = unit 
     300                elif tagname == 'yaw' and self.parent_class == 'orientation' and 'SASsample' in self.names: 
     301                    self.current_datainfo.sample.orientation.z = data_point 
     302                    self.current_datainfo.sample.orientation_unit = unit 
     303 
     304                ## Instrumental Information 
     305                elif tagname == 'name' and self.parent_class == 'SASinstrument': 
     306                    self.current_datainfo.instrument = data_point 
     307                ## Detector Information 
     308                elif tagname == 'name' and self.parent_class == 'SASdetector': 
     309                    self.detector.name = data_point 
     310                elif tagname == 'SDD' and self.parent_class == 'SASdetector': 
     311                    self.detector.distance = data_point 
     312                    self.detector.distance_unit = unit 
     313                elif tagname == 'slit_length' and self.parent_class == 'SASdetector': 
     314                    self.detector.slit_length = data_point 
     315                    self.detector.slit_length_unit = unit 
     316                elif tagname == 'x' and self.parent_class == 'offset': 
     317                    self.detector.offset.x = data_point 
     318                    self.detector.offset_unit = unit 
     319                elif tagname == 'y' and self.parent_class == 'offset': 
     320                    self.detector.offset.y = data_point 
     321                    self.detector.offset_unit = unit 
     322                elif tagname == 'z' and self.parent_class == 'offset': 
     323                    self.detector.offset.z = data_point 
     324                    self.detector.offset_unit = unit 
     325                elif tagname == 'x' and self.parent_class == 'beam_center': 
     326                    self.detector.beam_center.x = data_point 
     327                    self.detector.beam_center_unit = unit 
     328                elif tagname == 'y' and self.parent_class == 'beam_center': 
     329                    self.detector.beam_center.y = data_point 
     330                    self.detector.beam_center_unit = unit 
     331                elif tagname == 'z' and self.parent_class == 'beam_center': 
     332                    self.detector.beam_center.z = data_point 
     333                    self.detector.beam_center_unit = unit 
     334                elif tagname == 'x' and self.parent_class == 'pixel_size': 
     335                    self.detector.pixel_size.x = data_point 
     336                    self.detector.pixel_size_unit = unit 
     337                elif tagname == 'y' and self.parent_class == 'pixel_size': 
     338                    self.detector.pixel_size.y = data_point 
     339                    self.detector.pixel_size_unit = unit 
     340                elif tagname == 'z' and self.parent_class == 'pixel_size': 
     341                    self.detector.pixel_size.z = data_point 
     342                    self.detector.pixel_size_unit = unit 
     343                elif tagname == 'roll' and self.parent_class == 'orientation' and 'SASdetector' in self.names: 
     344                    self.detector.orientation.x = data_point 
     345                    self.detector.orientation_unit = unit 
     346                elif tagname == 'pitch' and self.parent_class == 'orientation' and 'SASdetector' in self.names: 
     347                    self.detector.orientation.y = data_point 
     348                    self.detector.orientation_unit = unit 
     349                elif tagname == 'yaw' and self.parent_class == 'orientation' and 'SASdetector' in self.names: 
     350                    self.detector.orientation.z = data_point 
     351                    self.detector.orientation_unit = unit 
     352                ## Collimation and Aperture 
     353                elif tagname == 'length' and self.parent_class == 'SAScollimation': 
     354                    self.collimation.length = data_point 
     355                    self.collimation.length_unit = unit 
     356                elif tagname == 'name' and self.parent_class == 'SAScollimation': 
     357                    self.collimation.name = data_point 
     358                elif tagname == 'distance' and self.parent_class == 'aperture': 
     359                    self.aperture.distance = data_point 
     360                    self.aperture.distance_unit = unit 
     361                elif tagname == 'x' and self.parent_class == 'size': 
     362                    self.aperture.size.x = data_point 
     363                    self.collimation.size_unit = unit 
     364                elif tagname == 'y' and self.parent_class == 'size': 
     365                    self.aperture.size.y = data_point 
     366                    self.collimation.size_unit = unit 
     367                elif tagname == 'z' and self.parent_class == 'size': 
     368                    self.aperture.size.z = data_point 
     369                    self.collimation.size_unit = unit 
     370 
     371                ## Process Information 
     372                elif tagname == 'name' and self.parent_class == 'SASprocess': 
     373                    self.process.name = data_point 
     374                elif tagname == 'description' and self.parent_class == 'SASprocess': 
     375                    self.process.description = data_point 
     376                elif tagname == 'date' and self.parent_class == 'SASprocess': 
     377                    try: 
     378                        self.process.date = datetime.datetime.fromtimestamp(data_point) 
     379                    except: 
     380                        self.process.date = data_point 
     381                elif tagname == 'SASprocessnote': 
     382                    self.process.notes.append(data_point) 
     383                elif tagname == 'term' and self.parent_class == 'SASprocess': 
     384                    unit = attr.get("unit", "") 
     385                    dic = {} 
     386                    dic["name"] = name 
     387                    dic["value"] = data_point 
     388                    dic["unit"] = unit 
     389                    self.process.term.append(dic) 
     390 
     391                ## Transmission Spectrum 
     392                elif tagname == 'T' and self.parent_class == 'Tdata': 
     393                    self.transspectrum.transmission = np.append(self.transspectrum.transmission, data_point) 
     394                    self.transspectrum.transmission_unit = unit 
     395                elif tagname == 'Tdev' and self.parent_class == 'Tdata': 
     396                    self.transspectrum.transmission_deviation = np.append(self.transspectrum.transmission_deviation, data_point) 
     397                    self.transspectrum.transmission_deviation_unit = unit 
     398                elif tagname == 'Lambda' and self.parent_class == 'Tdata': 
     399                    self.transspectrum.wavelength = np.append(self.transspectrum.wavelength, data_point) 
     400                    self.transspectrum.wavelength_unit = unit 
     401 
     402                ## Source Information 
     403                elif tagname == 'wavelength' and (self.parent_class == 'SASsource' or self.parent_class == 'SASData'): 
     404                    self.current_datainfo.source.wavelength = data_point 
     405                    self.current_datainfo.source.wavelength_unit = unit 
     406                elif tagname == 'wavelength_min' and self.parent_class == 'SASsource': 
     407                    self.current_datainfo.source.wavelength_min = data_point 
     408                    self.current_datainfo.source.wavelength_min_unit = unit 
     409                elif tagname == 'wavelength_max' and self.parent_class == 'SASsource': 
     410                    self.current_datainfo.source.wavelength_max = data_point 
     411                    self.current_datainfo.source.wavelength_max_unit = unit 
     412                elif tagname == 'wavelength_spread' and self.parent_class == 'SASsource': 
     413                    self.current_datainfo.source.wavelength_spread = data_point 
     414                    self.current_datainfo.source.wavelength_spread_unit = unit 
     415                elif tagname == 'x' and self.parent_class == 'beam_size': 
     416                    self.current_datainfo.source.beam_size.x = data_point 
     417                    self.current_datainfo.source.beam_size_unit = unit 
     418                elif tagname == 'y' and self.parent_class == 'beam_size': 
     419                    self.current_datainfo.source.beam_size.y = data_point 
     420                    self.current_datainfo.source.beam_size_unit = unit 
     421                elif tagname == 'z' and self.parent_class == 'pixel_size': 
     422                    self.current_datainfo.source.data_point.z = data_point 
     423                    self.current_datainfo.source.beam_size_unit = unit 
     424                elif tagname == 'radiation' and self.parent_class == 'SASsource': 
     425                    self.current_datainfo.source.radiation = data_point 
     426                elif tagname == 'beam_shape' and self.parent_class == 'SASsource': 
     427                    self.current_datainfo.source.beam_shape = data_point 
     428 
     429                ## Everything else goes in meta_data 
     430                else: 
     431                    new_key = self._create_unique_key(self.current_datainfo.meta_data, tagname) 
     432                    self.current_datainfo.meta_data[new_key] = data_point 
     433 
     434            self.names.remove(tagname_original) 
     435            length = 0 
     436            if len(self.names) > 1: 
     437                length = len(self.names) - 1 
     438            self.parent_class = self.names[length] 
     439        if not self._is_call_local(frm): 
     440            self.add_data_set() 
     441            empty = None 
     442            if self.output[0].dx is not None: 
     443                self.output[0].dxl = np.empty(0) 
     444                self.output[0].dxw = np.empty(0) 
     445            else: 
     446                self.output[0].dx = np.empty(0) 
     447            return self.output[0], empty 
     448 
     449 
     450    def _is_call_local(self, frm=""): 
     451        """ 
     452 
     453        :return: 
     454        """ 
     455        if frm == "": 
     456            frm = inspect.stack()[1] 
     457        mod_name = frm[1].replace("\\", "/").replace(".pyc", "") 
     458        mod_name = mod_name.replace(".py", "") 
     459        mod = mod_name.split("sas/") 
     460        mod_name = mod[1] 
     461        if mod_name != "sascalc/dataloader/readers/cansas_reader": 
     462            return False 
     463        return True 
    121464 
    122465    def is_cansas(self, ext="xml"): 
     
    134477        if ext == "svs": 
    135478            return True 
    136         return False 
     479        raise RuntimeError 
    137480 
    138481    def load_file_and_schema(self, xml_file, schema_path=""): 
    139482        """ 
    140         Loads the file and associates a schema, if a known schema exists 
     483        Loads the file and associates a schema, if a schema is passed in or if one already exists 
    141484 
    142485        :param xml_file: The xml file path sent to Reader.read 
     486        :param schema_path: The path to a schema associated with the xml_file, or find one based on the file 
    143487        """ 
    144488        base_name = xml_reader.__file__ 
     
    151495 
    152496        # Generic values for the cansas file based on the version 
    153         cansas_defaults = CANSAS_NS.get(self.cansas_version, "1.0") 
     497        self.cansas_defaults = CANSAS_NS.get(self.cansas_version, "1.0") 
    154498        if schema_path == "": 
    155             schema_path = "{0}/sas/sascalc/dataloader/readers/schema/{1}".format\ 
    156                 (base, cansas_defaults.get("schema")).replace("\\", "/") 
     499            schema_path = "{0}/sas/sascalc/dataloader/readers/schema/{1}".format \ 
     500                (base, self.cansas_defaults.get("schema")).replace("\\", "/") 
    157501 
    158502        # Link a schema to the XML file. 
    159503        self.set_schema(schema_path) 
    160         return cansas_defaults 
    161  
    162     ## TODO: Test loading invalid CanSAS XML files and see if this works 
    163     ## TODO: Once works, try adding a warning that the data is invalid 
    164     def read(self, xml_file, schema_path=""): 
    165         """ 
    166         Validate and read in an xml_file file in the canSAS format. 
    167  
    168         :param xml_file: A canSAS file path in proper XML format 
    169         """ 
    170         # output - Final list of Data1D objects 
    171         output = [] 
    172         # ns - Namespace hierarchy for current xml_file object 
    173         ns_list = [] 
    174  
    175         # Check that the file exists 
    176         if os.path.isfile(xml_file): 
    177             basename = os.path.basename(xml_file) 
    178             _, extension = os.path.splitext(basename) 
    179             # If the file type is not allowed, return nothing 
    180             if extension in self.ext or self.allow_all: 
    181                 # Get the file location of 
    182                 cansas_defaults = self.load_file_and_schema(xml_file, schema_path) 
    183  
    184                 # Try to load the file, but raise an error if unable to. 
    185                 # Check the file matches the XML schema 
    186                 try: 
    187                     if self.is_cansas(extension): 
    188                         # Get each SASentry from XML file and add it to a list. 
    189                         entry_list = self.xmlroot.xpath( 
    190                                 '/ns:SASroot/ns:SASentry', 
    191                                 namespaces={'ns': cansas_defaults.get("ns")}) 
    192                         ns_list.append("SASentry") 
    193  
    194                         # If multiple files, modify the name for each is unique 
    195                         increment = 0 
    196                         # Parse each SASentry item 
    197                         for entry in entry_list: 
    198                             # Define a new Data1D object with zeroes for 
    199                             # x_vals and y_vals 
    200                             data1d = Data1D(numpy.empty(0), numpy.empty(0), 
    201                                             numpy.empty(0), numpy.empty(0)) 
    202                             data1d.dxl = numpy.empty(0) 
    203                             data1d.dxw = numpy.empty(0) 
    204  
    205                             # If more than one SASentry, increment each in order 
    206                             name = basename 
    207                             if len(entry_list) - 1 > 0: 
    208                                 name += "_{0}".format(increment) 
    209                                 increment += 1 
    210  
    211                             # Set the Data1D name and then parse the entry. 
    212                             # The entry is appended to a list of entry values 
    213                             data1d.filename = name 
    214                             data1d.meta_data["loader"] = "CanSAS 1D" 
    215  
    216                             # Get all preprocessing events and encoding 
    217                             self.set_processing_instructions() 
    218                             data1d.meta_data[PREPROCESS] = \ 
    219                                     self.processing_instructions 
    220  
    221                             # Parse the XML file 
    222                             return_value, extras = \ 
    223                                 self._parse_entry(entry, ns_list, data1d) 
    224                             del extras[:] 
    225  
    226                             return_value = self._final_cleanup(return_value) 
    227                             output.append(return_value) 
    228                     else: 
    229                         raise RuntimeError, "Invalid XML at: {0}".format(\ 
    230                                                     self.find_invalid_xml()) 
    231                 except: 
    232                     # If the file does not match the schema, raise this error 
    233                     schema_path = "{0}/sas/sascalc/dataloader/readers/schema/cansas1d_invalid.xsd" 
    234                     invalid_xml = self.find_invalid_xml() 
    235                     invalid_xml = "\n\nThe loaded xml file does not fully meet the CanSAS v1.x specification. SasView " + \ 
    236                                   "loaded as much of the data as possible.\n\n" + invalid_xml 
    237                     self.errors.add(invalid_xml) 
    238                     self.set_schema(schema_path) 
    239                     if self.is_cansas(): 
    240                         output = self.read(xml_file, schema_path) 
    241                     else: 
    242                         raise RuntimeError, "%s cannot be read" % xml_file 
    243                 return output 
    244         # Return a list of parsed entries that dataloader can manage 
    245         return None 
    246  
    247     def _final_cleanup(self, data1d): 
     504 
     505    def add_data_set(self): 
     506        """ 
     507        Adds the current_dataset to the list of outputs after preforming final processing on the data and then calls a 
     508        private method to generate a new data set. 
     509 
     510        :param key: NeXus group name for current tree level 
     511        """ 
     512 
     513        if self.current_datainfo and self.current_dataset: 
     514            self._final_cleanup() 
     515        self.data = [] 
     516        self.current_datainfo = DataInfo() 
     517 
     518    def _initialize_new_data_set(self, parent_list=None): 
     519        """ 
     520        A private class method to generate a new 1D data object. 
     521        Outside methods should call add_data_set() to be sure any existing data is stored properly. 
     522 
     523        :param parent_list: List of names of parent elements 
     524        """ 
     525 
     526        if parent_list is None: 
     527            parent_list = [] 
     528        x = np.array(0) 
     529        y = np.array(0) 
     530        self.current_dataset = plottable_1D(x, y) 
     531 
     532    def add_intermediate(self): 
     533        """ 
     534        This method stores any intermediate objects within the final data set after fully reading the set. 
     535 
     536        :param parent: The NXclass name for the h5py Group object that just finished being processed 
     537        """ 
     538 
     539        if self.parent_class == 'SASprocess': 
     540            self.current_datainfo.process.append(self.process) 
     541            self.process = Process() 
     542        elif self.parent_class == 'SASdetector': 
     543            self.current_datainfo.detector.append(self.detector) 
     544            self.detector = Detector() 
     545        elif self.parent_class == 'SAStransmission_spectrum': 
     546            self.current_datainfo.trans_spectrum.append(self.transspectrum) 
     547            self.transspectrum = TransmissionSpectrum() 
     548        elif self.parent_class == 'SAScollimation': 
     549            self.current_datainfo.collimation.append(self.collimation) 
     550            self.collimation = Collimation() 
     551        elif self.parent_class == 'aperture': 
     552            self.collimation.aperture.append(self.aperture) 
     553            self.aperture = Aperture() 
     554        elif self.parent_class == 'SASdata': 
     555            self._check_for_empty_resolution() 
     556            self.data.append(self.current_dataset) 
     557 
     558    def _final_cleanup(self): 
    248559        """ 
    249560        Final cleanup of the Data1D object to be sure it has all the 
    250561        appropriate information needed for perspectives 
    251  
    252         :param data1d: Data1D object that has been populated 
    253         """ 
    254         # Final cleanup 
    255         # Remove empty nodes, verify array sizes are correct 
     562        """ 
     563 
     564        ## Append errors to dataset and reset class errors 
     565        self.current_datainfo.errors = set() 
    256566        for error in self.errors: 
    257             data1d.errors.append(error) 
     567            self.current_datainfo.errors.add(error) 
    258568        self.errors.clear() 
    259         numpy.trim_zeros(data1d.x) 
    260         numpy.trim_zeros(data1d.y) 
    261         numpy.trim_zeros(data1d.dy) 
    262         size_dx = data1d.dx.size 
    263         size_dxl = data1d.dxl.size 
    264         size_dxw = data1d.dxw.size 
    265         if data1d._xunit != data1d.x_unit: 
    266             data1d.x_unit = data1d._xunit 
    267         if data1d._yunit != data1d.y_unit: 
    268             data1d.y_unit = data1d._yunit 
    269         if size_dxl == 0 and size_dxw == 0: 
    270             data1d.dxl = None 
    271             data1d.dxw = None 
    272             numpy.trim_zeros(data1d.dx) 
    273         elif size_dx == 0: 
    274             data1d.dx = None 
    275             size_dx = size_dxl 
    276             numpy.trim_zeros(data1d.dxl) 
    277             numpy.trim_zeros(data1d.dxw) 
    278         return data1d 
     569 
     570        ## Combine all plottables with datainfo and append each to output 
     571        ## Type cast data arrays to float64 and find min/max as appropriate 
     572        for dataset in self.data: 
     573            if dataset.x is not None: 
     574                dataset.x = np.delete(dataset.x, [0]) 
     575                dataset.x = dataset.x.astype(np.float64) 
     576                dataset.xmin = np.min(dataset.x) 
     577                dataset.xmax = np.max(dataset.x) 
     578            if dataset.y is not None: 
     579                dataset.y = np.delete(dataset.y, [0]) 
     580                dataset.y = dataset.y.astype(np.float64) 
     581                dataset.ymin = np.min(dataset.y) 
     582                dataset.ymax = np.max(dataset.y) 
     583            if dataset.dx is not None: 
     584                dataset.dx = np.delete(dataset.dx, [0]) 
     585                dataset.dx = dataset.dx.astype(np.float64) 
     586            if dataset.dxl is not None: 
     587                dataset.dxl = np.delete(dataset.dxl, [0]) 
     588                dataset.dxl = dataset.dxl.astype(np.float64) 
     589            if dataset.dxw is not None: 
     590                dataset.dxw = np.delete(dataset.dxw, [0]) 
     591                dataset.dxw = dataset.dxw.astype(np.float64) 
     592            if dataset.dy is not None: 
     593                dataset.dy = np.delete(dataset.dy, [0]) 
     594                dataset.dy = dataset.dy.astype(np.float64) 
     595            np.trim_zeros(dataset.x) 
     596            np.trim_zeros(dataset.y) 
     597            np.trim_zeros(dataset.dy) 
     598            final_dataset = combine_data(dataset, self.current_datainfo) 
     599            self.output.append(final_dataset) 
    279600 
    280601    def _create_unique_key(self, dictionary, name, numb=0): 
    281602        """ 
    282603        Create a unique key value for any dictionary to prevent overwriting 
    283         Recurses until a unique key value is found. 
     604        Recurse until a unique key value is found. 
    284605 
    285606        :param dictionary: A dictionary with any number of entries 
     
    294615        return name 
    295616 
    296     def _unit_conversion(self, node, new_current_level, data1d, \ 
    297                                                 tagname, node_value): 
     617    def _get_node_value(self, node, tagname): 
     618        """ 
     619        Get the value of a node and any applicable units 
     620 
     621        :param node: The XML node to get the value of 
     622        :param tagname: The tagname of the node 
     623        """ 
     624        #Get the text from the node and convert all whitespace to spaces 
     625        units = '' 
     626        node_value = node.text 
     627        if node_value is not None: 
     628            node_value = ' '.join(node_value.split()) 
     629        else: 
     630            node_value = "" 
     631 
     632        # If the value is a float, compile with units. 
     633        if self.ns_list.ns_datatype == "float": 
     634            # If an empty value is given, set as zero. 
     635            if node_value is None or node_value.isspace() \ 
     636                                    or node_value.lower() == "nan": 
     637                node_value = "0.0" 
     638            #Convert the value to the base units 
     639            node_value, units = self._unit_conversion(node, tagname, node_value) 
     640 
     641        # If the value is a timestamp, convert to a datetime object 
     642        elif self.ns_list.ns_datatype == "timestamp": 
     643            if node_value is None or node_value.isspace(): 
     644                pass 
     645            else: 
     646                try: 
     647                    node_value = \ 
     648                        datetime.datetime.fromtimestamp(node_value) 
     649                except ValueError: 
     650                    node_value = None 
     651        return node_value, units 
     652 
     653    def _unit_conversion(self, node, tagname, node_value): 
    298654        """ 
    299655        A unit converter method used to convert the data included in the file 
    300656        to the default units listed in data_info 
    301657 
    302         :param new_current_level: cansas_constants level as returned by 
    303             iterate_namespace 
    304         :param attr: The attributes of the node 
    305         :param data1d: Where the values will be saved 
     658        :param node: XML node 
     659        :param tagname: name of the node 
    306660        :param node_value: The value of the current dom node 
    307661        """ 
     
    310664        err_msg = None 
    311665        default_unit = None 
    312         if 'unit' in attr and new_current_level.get('unit') is not None: 
     666        if not isinstance(node_value, float): 
     667            node_value = float(node_value) 
     668        if 'unit' in attr and attr.get('unit') is not None: 
    313669            try: 
    314670                local_unit = attr['unit'] 
    315                 if isinstance(node_value, float) is False: 
    316                     exec("node_value = float({0})".format(node_value)) 
    317                 unitname = new_current_level.get("unit") 
    318                 exec "default_unit = data1d.{0}".format(unitname) 
    319                 if local_unit is not None and default_unit is not None and \ 
    320                         local_unit.lower() != default_unit.lower() \ 
     671                unitname = self.ns_list.current_level.get("unit", "") 
     672                if "SASdetector" in self.names: 
     673                    save_in = "detector" 
     674                elif "aperture" in self.names: 
     675                    save_in = "aperture" 
     676                elif "SAScollimation" in self.names: 
     677                    save_in = "collimation" 
     678                elif "SAStransmission_spectrum" in self.names: 
     679                    save_in = "transspectrum" 
     680                elif "SASdata" in self.names: 
     681                    x = np.zeros(1) 
     682                    y = np.zeros(1) 
     683                    self.current_data1d = Data1D(x, y) 
     684                    save_in = "current_data1d" 
     685                elif "SASsource" in self.names: 
     686                    save_in = "current_datainfo.source" 
     687                elif "SASsample" in self.names: 
     688                    save_in = "current_datainfo.sample" 
     689                elif "SASprocess" in self.names: 
     690                    save_in = "process" 
     691                else: 
     692                    save_in = "current_datainfo" 
     693                exec "default_unit = self.{0}.{1}".format(save_in, unitname) 
     694                if local_unit and default_unit and local_unit.lower() != default_unit.lower() \ 
    321695                        and local_unit.lower() != "none": 
    322696                    if HAS_CONVERTER == True: 
     
    345719        if err_msg: 
    346720            self.errors.add(err_msg) 
    347         node_value = "float({0})".format(node_value) 
    348721        return node_value, value_unit 
    349722 
    350     def _check_for_empty_data(self, data1d): 
     723    def _check_for_empty_data(self): 
    351724        """ 
    352725        Creates an empty data set if no data is passed to the reader 
     
    354727        :param data1d: presumably a Data1D object 
    355728        """ 
    356         if data1d == None: 
    357             self.errors = set() 
    358             x_vals = numpy.empty(0) 
    359             y_vals = numpy.empty(0) 
    360             dx_vals = numpy.empty(0) 
    361             dy_vals = numpy.empty(0) 
    362             dxl = numpy.empty(0) 
    363             dxw = numpy.empty(0) 
    364             data1d = Data1D(x_vals, y_vals, dx_vals, dy_vals) 
    365             data1d.dxl = dxl 
    366             data1d.dxw = dxw 
    367         return data1d 
    368  
    369     def _handle_special_cases(self, tagname, data1d, children): 
    370         """ 
    371         Handle cases where the data type in Data1D is a dictionary or list 
    372  
    373         :param tagname: XML tagname in use 
    374         :param data1d: The original Data1D object 
    375         :param children: Child nodes of node 
    376         :param node: existing node with tag name 'tagname' 
    377         """ 
    378         if tagname == "SASdetector": 
    379             data1d = Detector() 
    380         elif tagname == "SAScollimation": 
    381             data1d = Collimation() 
    382         elif tagname == "SAStransmission_spectrum": 
    383             data1d = TransmissionSpectrum() 
    384         elif tagname == "SASprocess": 
    385             data1d = Process() 
    386             for child in children: 
    387                 if child.tag.replace(self.base_ns, "") == "term": 
    388                     term_attr = {} 
    389                     for attr in child.keys(): 
    390                         term_attr[attr] = \ 
    391                             ' '.join(child.get(attr).split()) 
    392                     if child.text is not None: 
    393                         term_attr['value'] = \ 
    394                             ' '.join(child.text.split()) 
    395                     data1d.term.append(term_attr) 
    396         elif tagname == "aperture": 
    397             data1d = Aperture() 
    398         if tagname == "Idata" and children is not None: 
    399             data1d = self._check_for_empty_resolution(data1d, children) 
    400         return data1d 
    401  
    402     def _check_for_empty_resolution(self, data1d, children): 
     729        if self.current_dataset == None: 
     730            x_vals = np.empty(0) 
     731            y_vals = np.empty(0) 
     732            dx_vals = np.empty(0) 
     733            dy_vals = np.empty(0) 
     734            dxl = np.empty(0) 
     735            dxw = np.empty(0) 
     736            self.current_dataset = plottable_1D(x_vals, y_vals, dx_vals, dy_vals) 
     737            self.current_dataset.dxl = dxl 
     738            self.current_dataset.dxw = dxw 
     739 
     740    def _check_for_empty_resolution(self): 
    403741        """ 
    404742        A method to check all resolution data sets are the same size as I and Q 
     
    408746        dq_exists = False 
    409747        di_exists = False 
    410         for child in children: 
    411             tag = child.tag.replace(self.base_ns, "") 
    412             if tag == "dQl": 
    413                 dql_exists = True 
    414             if tag == "dQw": 
    415                 dqw_exists = True 
    416             if tag == "Qdev": 
    417                 dq_exists = True 
    418             if tag == "Idev": 
    419                 di_exists = True 
    420         if dqw_exists and dql_exists == False: 
    421             data1d.dxl = numpy.append(data1d.dxl, 0.0) 
    422         elif dql_exists and dqw_exists == False: 
    423             data1d.dxw = numpy.append(data1d.dxw, 0.0) 
    424         elif dql_exists == False and dqw_exists == False \ 
    425                                             and dq_exists == False: 
    426             data1d.dx = numpy.append(data1d.dx, 0.0) 
    427         if di_exists == False: 
    428             data1d.dy = numpy.append(data1d.dy, 0.0) 
    429         return data1d 
    430  
    431     def _restore_original_case(self, 
    432                                tagname_original, 
    433                                tagname, 
    434                                save_data1d, 
    435                                data1d): 
    436         """ 
    437         Save the special case data to the appropriate location and restore 
    438         the original Data1D object 
    439  
    440         :param tagname_original: Unmodified tagname for the node 
    441         :param tagname: modified tagname for the node 
    442         :param save_data1d: The original Data1D object 
    443         :param data1d: If a special case was handled, an object of that type 
    444         """ 
    445         if tagname_original == "SASdetector": 
    446             save_data1d.detector.append(data1d) 
    447         elif tagname_original == "SAScollimation": 
    448             save_data1d.collimation.append(data1d) 
    449         elif tagname == "SAStransmission_spectrum": 
    450             save_data1d.trans_spectrum.append(data1d) 
    451         elif tagname_original == "SASprocess": 
    452             save_data1d.process.append(data1d) 
    453         elif tagname_original == "aperture": 
    454             save_data1d.aperture.append(data1d) 
    455         else: 
    456             save_data1d = data1d 
    457         return save_data1d 
    458  
    459     def _handle_attributes(self, node, data1d, cs_values, tagname): 
    460         """ 
    461         Process all of the attributes for a node 
    462         """ 
    463         attr = node.attrib 
    464         if attr is not None: 
    465             for key in node.keys(): 
    466                 try: 
    467                     node_value, unit = self._get_node_value(node, cs_values, \ 
    468                                                    data1d, tagname) 
    469                     cansas_attrib = \ 
    470                         cs_values.current_level.get("attributes").get(key) 
    471                     attrib_variable = cansas_attrib.get("variable") 
    472                     if key == 'unit' and unit != '': 
    473                         attrib_value = unit 
    474                     else: 
    475                         attrib_value = node.attrib[key] 
    476                     store_attr = attrib_variable.format("data1d", 
    477                                                         attrib_value, 
    478                                                         key, 
    479                                                         node_value) 
    480                     exec store_attr 
    481                 except AttributeError: 
    482                     pass 
    483         return data1d 
    484  
    485     def _get_node_value(self, node, cs_values, data1d, tagname): 
    486         """ 
    487         Get the value of a node and any applicable units 
    488  
    489         :param node: The XML node to get the value of 
    490         :param cs_values: A CansasConstants.CurrentLevel object 
    491         :param attr: The node attributes 
    492         :param dataid: The working object to be modified 
    493         :param tagname: The tagname of the node 
    494         """ 
    495         #Get the text from the node and convert all whitespace to spaces 
    496         units = '' 
    497         node_value = node.text 
    498         if node_value == "": 
    499             node_value = None 
    500         if node_value is not None: 
    501             node_value = ' '.join(node_value.split()) 
    502  
    503         # If the value is a float, compile with units. 
    504         if cs_values.ns_datatype == "float": 
    505             # If an empty value is given, set as zero. 
    506             if node_value is None or node_value.isspace() \ 
    507                                     or node_value.lower() == "nan": 
    508                 node_value = "0.0" 
    509             #Convert the value to the base units 
    510             node_value, units = self._unit_conversion(node, \ 
    511                         cs_values.current_level, data1d, tagname, node_value) 
    512  
    513         # If the value is a timestamp, convert to a datetime object 
    514         elif cs_values.ns_datatype == "timestamp": 
    515             if node_value is None or node_value.isspace(): 
    516                 pass 
    517             else: 
    518                 try: 
    519                     node_value = \ 
    520                         datetime.datetime.fromtimestamp(node_value) 
    521                 except ValueError: 
    522                     node_value = None 
    523         return node_value, units 
    524  
    525     def _parse_entry(self, dom, names=None, data1d=None, extras=None): 
    526         """ 
    527         Parse a SASEntry - new recursive method for parsing the dom of 
    528             the CanSAS data format. This will allow multiple data files 
    529             and extra nodes to be read in simultaneously. 
    530  
    531         :param dom: dom object with a namespace base of names 
    532         :param names: A list of element names that lead up to the dom object 
    533         :param data1d: The data1d object that will be modified 
    534         :param extras: Any values that should go into meta_data when data1d 
    535             is not a Data1D object 
    536         """ 
    537  
    538         if extras is None: 
    539             extras = [] 
    540         if names is None or names == []: 
    541             names = ["SASentry"] 
    542  
    543         data1d = self._check_for_empty_data(data1d) 
    544  
    545         self.base_ns = "{0}{1}{2}".format("{", \ 
    546                             CANSAS_NS.get(self.cansas_version).get("ns"), "}") 
    547         tagname = '' 
    548         tagname_original = '' 
    549  
    550         # Go through each child in the parent element 
    551         for node in dom: 
    552             try: 
    553                 # Get the element name and set the current names level 
    554                 tagname = node.tag.replace(self.base_ns, "") 
    555                 tagname_original = tagname 
    556                 if tagname == "fitting_plug_in" or tagname == "pr_inversion" or\ 
    557                     tagname == "invariant": 
    558                     continue 
    559                 names.append(tagname) 
    560                 children = node.getchildren() 
    561                 if len(children) == 0: 
    562                     children = None 
    563                 save_data1d = data1d 
    564  
    565                 # Look for special cases 
    566                 data1d = self._handle_special_cases(tagname, data1d, children) 
    567  
    568                 # Get where to store content 
    569                 cs_values = CONSTANTS.iterate_namespace(names) 
    570                 # If the element is a child element, recurse 
    571                 if children is not None: 
    572                     # Returned value is new Data1D object with all previous and 
    573                     # new values in it. 
    574                     data1d, extras = self._parse_entry(node, 
    575                                                        names, data1d, extras) 
    576  
    577                 #Get the information from the node 
    578                 node_value, _ = self._get_node_value(node, cs_values, \ 
    579                                                             data1d, tagname) 
    580  
    581                 # If appending to a dictionary (meta_data | run_name) 
    582                 # make sure the key is unique 
    583                 if cs_values.ns_variable == "{0}.meta_data[\"{2}\"] = \"{1}\"": 
    584                     # If we are within a Process, Detector, Collimation or 
    585                     # Aperture instance, pull out old data1d 
    586                     tagname = self._create_unique_key(data1d.meta_data, \ 
    587                                                       tagname, 0) 
    588                     if isinstance(data1d, Data1D) == False: 
    589                         store_me = cs_values.ns_variable.format("data1d", \ 
    590                                                             node_value, tagname) 
    591                         extras.append(store_me) 
    592                         cs_values.ns_variable = None 
    593                 if cs_values.ns_variable == "{0}.run_name[\"{2}\"] = \"{1}\"": 
    594                     tagname = self._create_unique_key(data1d.run_name, \ 
    595                                                       tagname, 0) 
    596  
    597                 # Check for Data1D object and any extra commands to save 
    598                 if isinstance(data1d, Data1D): 
    599                     for item in extras: 
    600                         exec item 
    601                 # Don't bother saving empty information unless it is a float 
    602                 if cs_values.ns_variable is not None and \ 
    603                             node_value is not None and \ 
    604                             node_value.isspace() == False: 
    605                     # Format a string and then execute it. 
    606                     store_me = cs_values.ns_variable.format("data1d", \ 
    607                                                             node_value, tagname) 
    608                     exec store_me 
    609                 # Get attributes and process them 
    610                 data1d = self._handle_attributes(node, data1d, cs_values, \ 
    611                                                  tagname) 
    612  
    613             except TypeError: 
    614                 pass 
    615             except Exception as excep: 
    616                 exc_type, exc_obj, exc_tb = sys.exc_info() 
    617                 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] 
    618                 print(excep, exc_type, fname, exc_tb.tb_lineno, \ 
    619                       tagname, exc_obj) 
    620             finally: 
    621                 # Save special cases in original data1d object 
    622                 # then restore the data1d 
    623                 save_data1d = self._restore_original_case(tagname_original, \ 
    624                                                 tagname, save_data1d, data1d) 
    625                 if tagname_original == "fitting_plug_in" or \ 
    626                     tagname_original == "invariant" or \ 
    627                     tagname_original == "pr_inversion": 
    628                     pass 
    629                 else: 
    630                     data1d = save_data1d 
    631                     # Remove tagname from names to restore original base 
    632                     names.remove(tagname_original) 
    633         return data1d, extras 
    634  
    635     def _get_pi_string(self): 
    636         """ 
    637         Creates the processing instructions header for writing to file 
    638         """ 
    639         pis = self.return_processing_instructions() 
    640         if len(pis) > 0: 
    641             pi_tree = self.create_tree(pis[0]) 
    642             i = 1 
    643             for i in range(1, len(pis) - 1): 
    644                 pi_tree = self.append(pis[i], pi_tree) 
    645             pi_string = self.to_string(pi_tree) 
    646         else: 
    647             pi_string = "" 
    648         return pi_string 
    649  
    650     def _create_main_node(self): 
    651         """ 
    652         Creates the primary xml header used when writing to file 
    653         """ 
    654         xsi = "http://www.w3.org/2001/XMLSchema-instance" 
    655         version = self.cansas_version 
    656         n_s = CANSAS_NS.get(version).get("ns") 
    657         if version == "1.1": 
    658             url = "http://www.cansas.org/formats/1.1/" 
    659         else: 
    660             url = "http://svn.smallangles.net/svn/canSAS/1dwg/trunk/" 
    661         schema_location = "{0} {1}cansas1d.xsd".format(n_s, url) 
    662         attrib = {"{" + xsi + "}schemaLocation" : schema_location, 
    663                   "version" : version} 
    664         nsmap = {'xsi' : xsi, None: n_s} 
    665  
    666         main_node = self.create_element("{" + n_s + "}SASroot", 
    667                                         attrib=attrib, nsmap=nsmap) 
    668         return main_node 
    669  
    670     def _write_run_names(self, datainfo, entry_node): 
    671         """ 
    672         Writes the run names to the XML file 
    673  
    674         :param datainfo: The Data1D object the information is coming from 
    675         :param entry_node: lxml node ElementTree object to be appended to 
    676         """ 
    677         if datainfo.run == None or datainfo.run == []: 
    678             datainfo.run.append(RUN_NAME_DEFAULT) 
    679             datainfo.run_name[RUN_NAME_DEFAULT] = RUN_NAME_DEFAULT 
    680         for item in datainfo.run: 
    681             runname = {} 
    682             if item in datainfo.run_name and \ 
    683             len(str(datainfo.run_name[item])) > 1: 
    684                 runname = {'name': datainfo.run_name[item]} 
    685             self.write_node(entry_node, "Run", item, runname) 
    686  
    687     def _write_data(self, datainfo, entry_node): 
    688         """ 
    689         Writes the I and Q data to the XML file 
    690  
    691         :param datainfo: The Data1D object the information is coming from 
    692         :param entry_node: lxml node ElementTree object to be appended to 
    693         """ 
    694         node = self.create_element("SASdata") 
    695         self.append(node, entry_node) 
    696  
    697         for i in range(len(datainfo.x)): 
    698             point = self.create_element("Idata") 
    699             node.append(point) 
    700             self.write_node(point, "Q", datainfo.x[i], 
    701                             {'unit': datainfo.x_unit}) 
    702             if len(datainfo.y) >= i: 
    703                 self.write_node(point, "I", datainfo.y[i], 
    704                                 {'unit': datainfo.y_unit}) 
    705             if datainfo.dy != None and len(datainfo.dy) > i: 
    706                 self.write_node(point, "Idev", datainfo.dy[i], 
    707                                 {'unit': datainfo.y_unit}) 
    708             if datainfo.dx != None and len(datainfo.dx) > i: 
    709                 self.write_node(point, "Qdev", datainfo.dx[i], 
    710                                 {'unit': datainfo.x_unit}) 
    711             if datainfo.dxw != None and len(datainfo.dxw) > i: 
    712                 self.write_node(point, "dQw", datainfo.dxw[i], 
    713                                 {'unit': datainfo.x_unit}) 
    714             if datainfo.dxl != None and len(datainfo.dxl) > i: 
    715                 self.write_node(point, "dQl", datainfo.dxl[i], 
    716                                 {'unit': datainfo.x_unit}) 
    717  
    718     def _write_trans_spectrum(self, datainfo, entry_node): 
    719         """ 
    720         Writes the transmission spectrum data to the XML file 
    721  
    722         :param datainfo: The Data1D object the information is coming from 
    723         :param entry_node: lxml node ElementTree object to be appended to 
    724         """ 
    725         for i in range(len(datainfo.trans_spectrum)): 
    726             spectrum = datainfo.trans_spectrum[i] 
    727             node = self.create_element("SAStransmission_spectrum", 
    728                                        {"name" : spectrum.name}) 
    729             self.append(node, entry_node) 
    730             if isinstance(spectrum.timestamp, datetime.datetime): 
    731                 node.setAttribute("timestamp", spectrum.timestamp) 
    732             for i in range(len(spectrum.wavelength)): 
    733                 point = self.create_element("Tdata") 
    734                 node.append(point) 
    735                 self.write_node(point, "Lambda", spectrum.wavelength[i], 
    736                                 {'unit': spectrum.wavelength_unit}) 
    737                 self.write_node(point, "T", spectrum.transmission[i], 
    738                                 {'unit': spectrum.transmission_unit}) 
    739                 if spectrum.transmission_deviation != None \ 
    740                 and len(spectrum.transmission_deviation) >= i: 
    741                     self.write_node(point, "Tdev", 
    742                                     spectrum.transmission_deviation[i], 
    743                                     {'unit': 
    744                                      spectrum.transmission_deviation_unit}) 
    745  
    746     def _write_sample_info(self, datainfo, entry_node): 
    747         """ 
    748         Writes the sample information to the XML file 
    749  
    750         :param datainfo: The Data1D object the information is coming from 
    751         :param entry_node: lxml node ElementTree object to be appended to 
    752         """ 
    753         sample = self.create_element("SASsample") 
    754         if datainfo.sample.name is not None: 
    755             self.write_attribute(sample, "name", 
    756                                  str(datainfo.sample.name)) 
    757         self.append(sample, entry_node) 
    758         self.write_node(sample, "ID", str(datainfo.sample.ID)) 
    759         self.write_node(sample, "thickness", datainfo.sample.thickness, 
    760                         {"unit": datainfo.sample.thickness_unit}) 
    761         self.write_node(sample, "transmission", datainfo.sample.transmission) 
    762         self.write_node(sample, "temperature", datainfo.sample.temperature, 
    763                         {"unit": datainfo.sample.temperature_unit}) 
    764  
    765         pos = self.create_element("position") 
    766         written = self.write_node(pos, 
    767                                   "x", 
    768                                   datainfo.sample.position.x, 
    769                                   {"unit": datainfo.sample.position_unit}) 
    770         written = written | self.write_node( \ 
    771             pos, "y", datainfo.sample.position.y, 
    772             {"unit": datainfo.sample.position_unit}) 
    773         written = written | self.write_node( \ 
    774             pos, "z", datainfo.sample.position.z, 
    775             {"unit": datainfo.sample.position_unit}) 
    776         if written == True: 
    777             self.append(pos, sample) 
    778  
    779         ori = self.create_element("orientation") 
    780         written = self.write_node(ori, "roll", 
    781                                   datainfo.sample.orientation.x, 
    782                                   {"unit": datainfo.sample.orientation_unit}) 
    783         written = written | self.write_node( \ 
    784             ori, "pitch", datainfo.sample.orientation.y, 
    785             {"unit": datainfo.sample.orientation_unit}) 
    786         written = written | self.write_node( \ 
    787             ori, "yaw", datainfo.sample.orientation.z, 
    788             {"unit": datainfo.sample.orientation_unit}) 
    789         if written == True: 
    790             self.append(ori, sample) 
    791  
    792         for item in datainfo.sample.details: 
    793             self.write_node(sample, "details", item) 
    794  
    795     def _write_instrument(self, datainfo, entry_node): 
    796         """ 
    797         Writes the instrumental information to the XML file 
    798  
    799         :param datainfo: The Data1D object the information is coming from 
    800         :param entry_node: lxml node ElementTree object to be appended to 
    801         """ 
    802         instr = self.create_element("SASinstrument") 
    803         self.append(instr, entry_node) 
    804         self.write_node(instr, "name", datainfo.instrument) 
    805         return instr 
    806  
    807     def _write_source(self, datainfo, instr): 
    808         """ 
    809         Writes the source information to the XML file 
    810  
    811         :param datainfo: The Data1D object the information is coming from 
    812         :param instr: instrument node  to be appended to 
    813         """ 
    814         source = self.create_element("SASsource") 
    815         if datainfo.source.name is not None: 
    816             self.write_attribute(source, "name", 
    817                                  str(datainfo.source.name)) 
    818         self.append(source, instr) 
    819         if datainfo.source.radiation == None or datainfo.source.radiation == '': 
    820             datainfo.source.radiation = "neutron" 
    821         self.write_node(source, "radiation", datainfo.source.radiation) 
    822  
    823         size = self.create_element("beam_size") 
    824         if datainfo.source.beam_size_name is not None: 
    825             self.write_attribute(size, "name", 
    826                                  str(datainfo.source.beam_size_name)) 
    827         written = self.write_node( \ 
    828             size, "x", datainfo.source.beam_size.x, 
    829             {"unit": datainfo.source.beam_size_unit}) 
    830         written = written | self.write_node( \ 
    831             size, "y", datainfo.source.beam_size.y, 
    832             {"unit": datainfo.source.beam_size_unit}) 
    833         written = written | self.write_node( \ 
    834             size, "z", datainfo.source.beam_size.z, 
    835             {"unit": datainfo.source.beam_size_unit}) 
    836         if written == True: 
    837             self.append(size, source) 
    838  
    839         self.write_node(source, "beam_shape", datainfo.source.beam_shape) 
    840         self.write_node(source, "wavelength", 
    841                         datainfo.source.wavelength, 
    842                         {"unit": datainfo.source.wavelength_unit}) 
    843         self.write_node(source, "wavelength_min", 
    844                         datainfo.source.wavelength_min, 
    845                         {"unit": datainfo.source.wavelength_min_unit}) 
    846         self.write_node(source, "wavelength_max", 
    847                         datainfo.source.wavelength_max, 
    848                         {"unit": datainfo.source.wavelength_max_unit}) 
    849         self.write_node(source, "wavelength_spread", 
    850                         datainfo.source.wavelength_spread, 
    851                         {"unit": datainfo.source.wavelength_spread_unit}) 
    852  
    853     def _write_collimation(self, datainfo, instr): 
    854         """ 
    855         Writes the collimation information to the XML file 
    856  
    857         :param datainfo: The Data1D object the information is coming from 
    858         :param instr: lxml node ElementTree object to be appended to 
    859         """ 
    860         if datainfo.collimation == [] or datainfo.collimation == None: 
    861             coll = Collimation() 
    862             datainfo.collimation.append(coll) 
    863         for item in datainfo.collimation: 
    864             coll = self.create_element("SAScollimation") 
    865             if item.name is not None: 
    866                 self.write_attribute(coll, "name", str(item.name)) 
    867             self.append(coll, instr) 
    868  
    869             self.write_node(coll, "length", item.length, 
    870                             {"unit": item.length_unit}) 
    871  
    872             for aperture in item.aperture: 
    873                 apert = self.create_element("aperture") 
    874                 if aperture.name is not None: 
    875                     self.write_attribute(apert, "name", str(aperture.name)) 
    876                 if aperture.type is not None: 
    877                     self.write_attribute(apert, "type", str(aperture.type)) 
    878                 self.append(apert, coll) 
    879  
    880                 size = self.create_element("size") 
    881                 if aperture.size_name is not None: 
    882                     self.write_attribute(size, "name", 
    883                                          str(aperture.size_name)) 
    884                 written = self.write_node(size, "x", aperture.size.x, 
    885                                           {"unit": aperture.size_unit}) 
    886                 written = written | self.write_node( \ 
    887                     size, "y", aperture.size.y, 
    888                     {"unit": aperture.size_unit}) 
    889                 written = written | self.write_node( \ 
    890                     size, "z", aperture.size.z, 
    891                     {"unit": aperture.size_unit}) 
    892                 if written == True: 
    893                     self.append(size, apert) 
    894  
    895                 self.write_node(apert, "distance", aperture.distance, 
    896                                 {"unit": aperture.distance_unit}) 
    897  
    898     def _write_detectors(self, datainfo, instr): 
    899         """ 
    900         Writes the detector information to the XML file 
    901  
    902         :param datainfo: The Data1D object the information is coming from 
    903         :param inst: lxml instrument node to be appended to 
    904         """ 
    905         if datainfo.detector == None or datainfo.detector == []: 
    906             det = Detector() 
    907             det.name = "" 
    908             datainfo.detector.append(det) 
    909  
    910         for item in datainfo.detector: 
    911             det = self.create_element("SASdetector") 
    912             written = self.write_node(det, "name", item.name) 
    913             written = written | self.write_node(det, "SDD", item.distance, 
    914                                                 {"unit": item.distance_unit}) 
    915             if written == True: 
    916                 self.append(det, instr) 
    917  
    918             off = self.create_element("offset") 
    919             written = self.write_node(off, "x", item.offset.x, 
    920                                       {"unit": item.offset_unit}) 
    921             written = written | self.write_node(off, "y", item.offset.y, 
    922                                                 {"unit": item.offset_unit}) 
    923             written = written | self.write_node(off, "z", item.offset.z, 
    924                                                 {"unit": item.offset_unit}) 
    925             if written == True: 
    926                 self.append(off, det) 
    927  
    928             ori = self.create_element("orientation") 
    929             written = self.write_node(ori, "roll", item.orientation.x, 
    930                                       {"unit": item.orientation_unit}) 
    931             written = written | self.write_node(ori, "pitch", 
    932                                                 item.orientation.y, 
    933                                                 {"unit": item.orientation_unit}) 
    934             written = written | self.write_node(ori, "yaw", 
    935                                                 item.orientation.z, 
    936                                                 {"unit": item.orientation_unit}) 
    937             if written == True: 
    938                 self.append(ori, det) 
    939  
    940             center = self.create_element("beam_center") 
    941             written = self.write_node(center, "x", item.beam_center.x, 
    942                                       {"unit": item.beam_center_unit}) 
    943             written = written | self.write_node(center, "y", 
    944                                                 item.beam_center.y, 
    945                                                 {"unit": item.beam_center_unit}) 
    946             written = written | self.write_node(center, "z", 
    947                                                 item.beam_center.z, 
    948                                                 {"unit": item.beam_center_unit}) 
    949             if written == True: 
    950                 self.append(center, det) 
    951  
    952             pix = self.create_element("pixel_size") 
    953             written = self.write_node(pix, "x", item.pixel_size.x, 
    954                                       {"unit": item.pixel_size_unit}) 
    955             written = written | self.write_node(pix, "y", item.pixel_size.y, 
    956                                                 {"unit": item.pixel_size_unit}) 
    957             written = written | self.write_node(pix, "z", item.pixel_size.z, 
    958                                                 {"unit": item.pixel_size_unit}) 
    959             written = written | self.write_node(det, "slit_length", 
    960                                                 item.slit_length, 
    961                                                 {"unit": item.slit_length_unit}) 
    962             if written == True: 
    963                 self.append(pix, det) 
    964  
    965     def _write_process_notes(self, datainfo, entry_node): 
    966         """ 
    967         Writes the process notes to the XML file 
    968  
    969         :param datainfo: The Data1D object the information is coming from 
    970         :param entry_node: lxml node ElementTree object to be appended to 
    971  
    972         """ 
    973         for item in datainfo.process: 
    974             node = self.create_element("SASprocess") 
    975             self.append(node, entry_node) 
    976             self.write_node(node, "name", item.name) 
    977             self.write_node(node, "date", item.date) 
    978             self.write_node(node, "description", item.description) 
    979             for term in item.term: 
    980                 value = term['value'] 
    981                 del term['value'] 
    982                 self.write_node(node, "term", value, term) 
    983             for note in item.notes: 
    984                 self.write_node(node, "SASprocessnote", note) 
    985             if len(item.notes) == 0: 
    986                 self.write_node(node, "SASprocessnote", "") 
    987  
    988     def _write_notes(self, datainfo, entry_node): 
    989         """ 
    990         Writes the notes to the XML file and creates an empty note if none 
    991         exist 
    992  
    993         :param datainfo: The Data1D object the information is coming from 
    994         :param entry_node: lxml node ElementTree object to be appended to 
    995  
    996         """ 
    997         if len(datainfo.notes) == 0: 
    998             node = self.create_element("SASnote") 
    999             self.append(node, entry_node) 
    1000         else: 
    1001             for item in datainfo.notes: 
    1002                 node = self.create_element("SASnote") 
    1003                 self.write_text(node, item) 
    1004                 self.append(node, entry_node) 
    1005  
    1006     def _check_origin(self, entry_node, doc, frm): 
    1007         """ 
    1008         Return the document, and the SASentry node associated with 
    1009         the data we just wrote. 
    1010         If the calling function was not the cansas reader, return a minidom 
    1011         object rather than an lxml object. 
    1012  
    1013         :param entry_node: lxml node ElementTree object to be appended to 
    1014         :param doc: entire xml tree 
    1015         """ 
    1016         if not frm: 
    1017             frm = inspect.stack()[1] 
    1018         mod_name = frm[1].replace("\\", "/").replace(".pyc", "") 
    1019         mod_name = mod_name.replace(".py", "") 
    1020         mod = mod_name.split("sas/") 
    1021         mod_name = mod[1] 
    1022         if mod_name != "sascalc/dataloader/readers/cansas_reader": 
    1023             string = self.to_string(doc, pretty_print=False) 
    1024             doc = parseString(string) 
    1025             node_name = entry_node.tag 
    1026             node_list = doc.getElementsByTagName(node_name) 
    1027             entry_node = node_list.item(0) 
    1028         return doc, entry_node 
     748        if self.current_dataset.dxl is not None: 
     749            dql_exists = True 
     750        if self.current_dataset.dxw is not None: 
     751            dqw_exists = True 
     752        if self.current_dataset.dx is not None: 
     753            dq_exists = True 
     754        if self.current_dataset.dy is not None: 
     755            di_exists = True 
     756        if dqw_exists and not dql_exists: 
     757            array_size = self.current_dataset.dxw.size - 1 
     758            self.current_dataset.dxl = np.append(self.current_dataset.dxl, np.zeros([array_size])) 
     759        elif dql_exists and not dqw_exists: 
     760            array_size = self.current_dataset.dxl.size - 1 
     761            self.current_dataset.dxw = np.append(self.current_dataset.dxw, np.zeros([array_size])) 
     762        elif not dql_exists and not dqw_exists and not dq_exists: 
     763            array_size = self.current_dataset.x.size - 1 
     764            self.current_dataset.dx = np.append(self.current_dataset.dx, np.zeros([array_size])) 
     765        if not di_exists: 
     766            array_size = self.current_dataset.y.size - 1 
     767            self.current_dataset.dy = np.append(self.current_dataset.dy, np.zeros([array_size])) 
     768 
     769 
     770    ####### All methods below are for writing CanSAS XML files ####### 
     771 
     772 
     773    def write(self, filename, datainfo): 
     774        """ 
     775        Write the content of a Data1D as a CanSAS XML file 
     776 
     777        :param filename: name of the file to write 
     778        :param datainfo: Data1D object 
     779        """ 
     780        # Create XML document 
     781        doc, _ = self._to_xml_doc(datainfo) 
     782        # Write the file 
     783        file_ref = open(filename, 'w') 
     784        if self.encoding == None: 
     785            self.encoding = "UTF-8" 
     786        doc.write(file_ref, encoding=self.encoding, 
     787                  pretty_print=True, xml_declaration=True) 
     788        file_ref.close() 
    1029789 
    1030790    def _to_xml_doc(self, datainfo): 
     
    1095855        return False 
    1096856 
    1097     def write(self, filename, datainfo): 
    1098         """ 
    1099         Write the content of a Data1D as a CanSAS XML file 
    1100  
    1101         :param filename: name of the file to write 
    1102         :param datainfo: Data1D object 
    1103         """ 
    1104         # Create XML document 
    1105         doc, _ = self._to_xml_doc(datainfo) 
    1106         # Write the file 
    1107         file_ref = open(filename, 'w') 
    1108         if self.encoding == None: 
    1109             self.encoding = "UTF-8" 
    1110         doc.write(file_ref, encoding=self.encoding, 
    1111                   pretty_print=True, xml_declaration=True) 
    1112         file_ref.close() 
     857    def _get_pi_string(self): 
     858        """ 
     859        Creates the processing instructions header for writing to file 
     860        """ 
     861        pis = self.return_processing_instructions() 
     862        if len(pis) > 0: 
     863            pi_tree = self.create_tree(pis[0]) 
     864            i = 1 
     865            for i in range(1, len(pis) - 1): 
     866                pi_tree = self.append(pis[i], pi_tree) 
     867            pi_string = self.to_string(pi_tree) 
     868        else: 
     869            pi_string = "" 
     870        return pi_string 
     871 
     872    def _create_main_node(self): 
     873        """ 
     874        Creates the primary xml header used when writing to file 
     875        """ 
     876        xsi = "http://www.w3.org/2001/XMLSchema-instance" 
     877        version = self.cansas_version 
     878        n_s = CANSAS_NS.get(version).get("ns") 
     879        if version == "1.1": 
     880            url = "http://www.cansas.org/formats/1.1/" 
     881        else: 
     882            url = "http://svn.smallangles.net/svn/canSAS/1dwg/trunk/" 
     883        schema_location = "{0} {1}cansas1d.xsd".format(n_s, url) 
     884        attrib = {"{" + xsi + "}schemaLocation" : schema_location, 
     885                  "version" : version} 
     886        nsmap = {'xsi' : xsi, None: n_s} 
     887 
     888        main_node = self.create_element("{" + n_s + "}SASroot", 
     889                                        attrib=attrib, nsmap=nsmap) 
     890        return main_node 
     891 
     892    def _write_run_names(self, datainfo, entry_node): 
     893        """ 
     894        Writes the run names to the XML file 
     895 
     896        :param datainfo: The Data1D object the information is coming from 
     897        :param entry_node: lxml node ElementTree object to be appended to 
     898        """ 
     899        if datainfo.run == None or datainfo.run == []: 
     900            datainfo.run.append(RUN_NAME_DEFAULT) 
     901            datainfo.run_name[RUN_NAME_DEFAULT] = RUN_NAME_DEFAULT 
     902        for item in datainfo.run: 
     903            runname = {} 
     904            if item in datainfo.run_name and \ 
     905            len(str(datainfo.run_name[item])) > 1: 
     906                runname = {'name': datainfo.run_name[item]} 
     907            self.write_node(entry_node, "Run", item, runname) 
     908 
     909    def _write_data(self, datainfo, entry_node): 
     910        """ 
     911        Writes the I and Q data to the XML file 
     912 
     913        :param datainfo: The Data1D object the information is coming from 
     914        :param entry_node: lxml node ElementTree object to be appended to 
     915        """ 
     916        node = self.create_element("SASdata") 
     917        self.append(node, entry_node) 
     918 
     919        for i in range(len(datainfo.x)): 
     920            point = self.create_element("Idata") 
     921            node.append(point) 
     922            self.write_node(point, "Q", datainfo.x[i], 
     923                            {'unit': datainfo.x_unit}) 
     924            if len(datainfo.y) >= i: 
     925                self.write_node(point, "I", datainfo.y[i], 
     926                                {'unit': datainfo.y_unit}) 
     927            if datainfo.dy is not None and len(datainfo.dy) > i: 
     928                self.write_node(point, "Idev", datainfo.dy[i], 
     929                                {'unit': datainfo.y_unit}) 
     930            if datainfo.dx is not None and len(datainfo.dx) > i: 
     931                self.write_node(point, "Qdev", datainfo.dx[i], 
     932                                {'unit': datainfo.x_unit}) 
     933            if datainfo.dxw is not None and len(datainfo.dxw) > i: 
     934                self.write_node(point, "dQw", datainfo.dxw[i], 
     935                                {'unit': datainfo.x_unit}) 
     936            if datainfo.dxl is not None and len(datainfo.dxl) > i: 
     937                self.write_node(point, "dQl", datainfo.dxl[i], 
     938                                {'unit': datainfo.x_unit}) 
     939 
     940    def _write_trans_spectrum(self, datainfo, entry_node): 
     941        """ 
     942        Writes the transmission spectrum data to the XML file 
     943 
     944        :param datainfo: The Data1D object the information is coming from 
     945        :param entry_node: lxml node ElementTree object to be appended to 
     946        """ 
     947        for i in range(len(datainfo.trans_spectrum)): 
     948            spectrum = datainfo.trans_spectrum[i] 
     949            node = self.create_element("SAStransmission_spectrum", 
     950                                       {"name" : spectrum.name}) 
     951            self.append(node, entry_node) 
     952            if isinstance(spectrum.timestamp, datetime.datetime): 
     953                node.setAttribute("timestamp", spectrum.timestamp) 
     954            for i in range(len(spectrum.wavelength)): 
     955                point = self.create_element("Tdata") 
     956                node.append(point) 
     957                self.write_node(point, "Lambda", spectrum.wavelength[i], 
     958                                {'unit': spectrum.wavelength_unit}) 
     959                self.write_node(point, "T", spectrum.transmission[i], 
     960                                {'unit': spectrum.transmission_unit}) 
     961                if spectrum.transmission_deviation != None \ 
     962                and len(spectrum.transmission_deviation) >= i: 
     963                    self.write_node(point, "Tdev", 
     964                                    spectrum.transmission_deviation[i], 
     965                                    {'unit': 
     966                                     spectrum.transmission_deviation_unit}) 
     967 
     968    def _write_sample_info(self, datainfo, entry_node): 
     969        """ 
     970        Writes the sample information to the XML file 
     971 
     972        :param datainfo: The Data1D object the information is coming from 
     973        :param entry_node: lxml node ElementTree object to be appended to 
     974        """ 
     975        sample = self.create_element("SASsample") 
     976        if datainfo.sample.name is not None: 
     977            self.write_attribute(sample, "name", 
     978                                 str(datainfo.sample.name)) 
     979        self.append(sample, entry_node) 
     980        self.write_node(sample, "ID", str(datainfo.sample.ID)) 
     981        self.write_node(sample, "thickness", datainfo.sample.thickness, 
     982                        {"unit": datainfo.sample.thickness_unit}) 
     983        self.write_node(sample, "transmission", datainfo.sample.transmission) 
     984        self.write_node(sample, "temperature", datainfo.sample.temperature, 
     985                        {"unit": datainfo.sample.temperature_unit}) 
     986 
     987        pos = self.create_element("position") 
     988        written = self.write_node(pos, 
     989                                  "x", 
     990                                  datainfo.sample.position.x, 
     991                                  {"unit": datainfo.sample.position_unit}) 
     992        written = written | self.write_node( \ 
     993            pos, "y", datainfo.sample.position.y, 
     994            {"unit": datainfo.sample.position_unit}) 
     995        written = written | self.write_node( \ 
     996            pos, "z", datainfo.sample.position.z, 
     997            {"unit": datainfo.sample.position_unit}) 
     998        if written == True: 
     999            self.append(pos, sample) 
     1000 
     1001        ori = self.create_element("orientation") 
     1002        written = self.write_node(ori, "roll", 
     1003                                  datainfo.sample.orientation.x, 
     1004                                  {"unit": datainfo.sample.orientation_unit}) 
     1005        written = written | self.write_node( \ 
     1006            ori, "pitch", datainfo.sample.orientation.y, 
     1007            {"unit": datainfo.sample.orientation_unit}) 
     1008        written = written | self.write_node( \ 
     1009            ori, "yaw", datainfo.sample.orientation.z, 
     1010            {"unit": datainfo.sample.orientation_unit}) 
     1011        if written == True: 
     1012            self.append(ori, sample) 
     1013 
     1014        for item in datainfo.sample.details: 
     1015            self.write_node(sample, "details", item) 
     1016 
     1017    def _write_instrument(self, datainfo, entry_node): 
     1018        """ 
     1019        Writes the instrumental information to the XML file 
     1020 
     1021        :param datainfo: The Data1D object the information is coming from 
     1022        :param entry_node: lxml node ElementTree object to be appended to 
     1023        """ 
     1024        instr = self.create_element("SASinstrument") 
     1025        self.append(instr, entry_node) 
     1026        self.write_node(instr, "name", datainfo.instrument) 
     1027        return instr 
     1028 
     1029    def _write_source(self, datainfo, instr): 
     1030        """ 
     1031        Writes the source information to the XML file 
     1032 
     1033        :param datainfo: The Data1D object the information is coming from 
     1034        :param instr: instrument node  to be appended to 
     1035        """ 
     1036        source = self.create_element("SASsource") 
     1037        if datainfo.source.name is not None: 
     1038            self.write_attribute(source, "name", 
     1039                                 str(datainfo.source.name)) 
     1040        self.append(source, instr) 
     1041        if datainfo.source.radiation == None or datainfo.source.radiation == '': 
     1042            datainfo.source.radiation = "neutron" 
     1043        self.write_node(source, "radiation", datainfo.source.radiation) 
     1044 
     1045        size = self.create_element("beam_size") 
     1046        if datainfo.source.beam_size_name is not None: 
     1047            self.write_attribute(size, "name", 
     1048                                 str(datainfo.source.beam_size_name)) 
     1049        written = self.write_node( \ 
     1050            size, "x", datainfo.source.beam_size.x, 
     1051            {"unit": datainfo.source.beam_size_unit}) 
     1052        written = written | self.write_node( \ 
     1053            size, "y", datainfo.source.beam_size.y, 
     1054            {"unit": datainfo.source.beam_size_unit}) 
     1055        written = written | self.write_node( \ 
     1056            size, "z", datainfo.source.beam_size.z, 
     1057            {"unit": datainfo.source.beam_size_unit}) 
     1058        if written == True: 
     1059            self.append(size, source) 
     1060 
     1061        self.write_node(source, "beam_shape", datainfo.source.beam_shape) 
     1062        self.write_node(source, "wavelength", 
     1063                        datainfo.source.wavelength, 
     1064                        {"unit": datainfo.source.wavelength_unit}) 
     1065        self.write_node(source, "wavelength_min", 
     1066                        datainfo.source.wavelength_min, 
     1067                        {"unit": datainfo.source.wavelength_min_unit}) 
     1068        self.write_node(source, "wavelength_max", 
     1069                        datainfo.source.wavelength_max, 
     1070                        {"unit": datainfo.source.wavelength_max_unit}) 
     1071        self.write_node(source, "wavelength_spread", 
     1072                        datainfo.source.wavelength_spread, 
     1073                        {"unit": datainfo.source.wavelength_spread_unit}) 
     1074 
     1075    def _write_collimation(self, datainfo, instr): 
     1076        """ 
     1077        Writes the collimation information to the XML file 
     1078 
     1079        :param datainfo: The Data1D object the information is coming from 
     1080        :param instr: lxml node ElementTree object to be appended to 
     1081        """ 
     1082        if datainfo.collimation == [] or datainfo.collimation == None: 
     1083            coll = Collimation() 
     1084            datainfo.collimation.append(coll) 
     1085        for item in datainfo.collimation: 
     1086            coll = self.create_element("SAScollimation") 
     1087            if item.name is not None: 
     1088                self.write_attribute(coll, "name", str(item.name)) 
     1089            self.append(coll, instr) 
     1090 
     1091            self.write_node(coll, "length", item.length, 
     1092                            {"unit": item.length_unit}) 
     1093 
     1094            for aperture in item.aperture: 
     1095                apert = self.create_element("aperture") 
     1096                if aperture.name is not None: 
     1097                    self.write_attribute(apert, "name", str(aperture.name)) 
     1098                if aperture.type is not None: 
     1099                    self.write_attribute(apert, "type", str(aperture.type)) 
     1100                self.append(apert, coll) 
     1101 
     1102                size = self.create_element("size") 
     1103                if aperture.size_name is not None: 
     1104                    self.write_attribute(size, "name", 
     1105                                         str(aperture.size_name)) 
     1106                written = self.write_node(size, "x", aperture.size.x, 
     1107                                          {"unit": aperture.size_unit}) 
     1108                written = written | self.write_node( \ 
     1109                    size, "y", aperture.size.y, 
     1110                    {"unit": aperture.size_unit}) 
     1111                written = written | self.write_node( \ 
     1112                    size, "z", aperture.size.z, 
     1113                    {"unit": aperture.size_unit}) 
     1114                if written == True: 
     1115                    self.append(size, apert) 
     1116 
     1117                self.write_node(apert, "distance", aperture.distance, 
     1118                                {"unit": aperture.distance_unit}) 
     1119 
     1120    def _write_detectors(self, datainfo, instr): 
     1121        """ 
     1122        Writes the detector information to the XML file 
     1123 
     1124        :param datainfo: The Data1D object the information is coming from 
     1125        :param inst: lxml instrument node to be appended to 
     1126        """ 
     1127        if datainfo.detector == None or datainfo.detector == []: 
     1128            det = Detector() 
     1129            det.name = "" 
     1130            datainfo.detector.append(det) 
     1131 
     1132        for item in datainfo.detector: 
     1133            det = self.create_element("SASdetector") 
     1134            written = self.write_node(det, "name", item.name) 
     1135            written = written | self.write_node(det, "SDD", item.distance, 
     1136                                                {"unit": item.distance_unit}) 
     1137            if written == True: 
     1138                self.append(det, instr) 
     1139 
     1140            off = self.create_element("offset") 
     1141            written = self.write_node(off, "x", item.offset.x, 
     1142                                      {"unit": item.offset_unit}) 
     1143            written = written | self.write_node(off, "y", item.offset.y, 
     1144                                                {"unit": item.offset_unit}) 
     1145            written = written | self.write_node(off, "z", item.offset.z, 
     1146                                                {"unit": item.offset_unit}) 
     1147            if written == True: 
     1148                self.append(off, det) 
     1149 
     1150            ori = self.create_element("orientation") 
     1151            written = self.write_node(ori, "roll", item.orientation.x, 
     1152                                      {"unit": item.orientation_unit}) 
     1153            written = written | self.write_node(ori, "pitch", 
     1154                                                item.orientation.y, 
     1155                                                {"unit": item.orientation_unit}) 
     1156            written = written | self.write_node(ori, "yaw", 
     1157                                                item.orientation.z, 
     1158                                                {"unit": item.orientation_unit}) 
     1159            if written == True: 
     1160                self.append(ori, det) 
     1161 
     1162            center = self.create_element("beam_center") 
     1163            written = self.write_node(center, "x", item.beam_center.x, 
     1164                                      {"unit": item.beam_center_unit}) 
     1165            written = written | self.write_node(center, "y", 
     1166                                                item.beam_center.y, 
     1167                                                {"unit": item.beam_center_unit}) 
     1168            written = written | self.write_node(center, "z", 
     1169                                                item.beam_center.z, 
     1170                                                {"unit": item.beam_center_unit}) 
     1171            if written == True: 
     1172                self.append(center, det) 
     1173 
     1174            pix = self.create_element("pixel_size") 
     1175            written = self.write_node(pix, "x", item.pixel_size.x, 
     1176                                      {"unit": item.pixel_size_unit}) 
     1177            written = written | self.write_node(pix, "y", item.pixel_size.y, 
     1178                                                {"unit": item.pixel_size_unit}) 
     1179            written = written | self.write_node(pix, "z", item.pixel_size.z, 
     1180                                                {"unit": item.pixel_size_unit}) 
     1181            written = written | self.write_node(det, "slit_length", 
     1182                                                item.slit_length, 
     1183                                                {"unit": item.slit_length_unit}) 
     1184            if written == True: 
     1185                self.append(pix, det) 
     1186 
     1187    def _write_process_notes(self, datainfo, entry_node): 
     1188        """ 
     1189        Writes the process notes to the XML file 
     1190 
     1191        :param datainfo: The Data1D object the information is coming from 
     1192        :param entry_node: lxml node ElementTree object to be appended to 
     1193 
     1194        """ 
     1195        for item in datainfo.process: 
     1196            node = self.create_element("SASprocess") 
     1197            self.append(node, entry_node) 
     1198            self.write_node(node, "name", item.name) 
     1199            self.write_node(node, "date", item.date) 
     1200            self.write_node(node, "description", item.description) 
     1201            for term in item.term: 
     1202                if isinstance(term, list): 
     1203                    value = term['value'] 
     1204                    del term['value'] 
     1205                elif isinstance(term, dict): 
     1206                    value = term.get("value") 
     1207                    del term['value'] 
     1208                else: 
     1209                    value = term 
     1210                self.write_node(node, "term", value, term) 
     1211            for note in item.notes: 
     1212                self.write_node(node, "SASprocessnote", note) 
     1213            if len(item.notes) == 0: 
     1214                self.write_node(node, "SASprocessnote", "") 
     1215 
     1216    def _write_notes(self, datainfo, entry_node): 
     1217        """ 
     1218        Writes the notes to the XML file and creates an empty note if none 
     1219        exist 
     1220 
     1221        :param datainfo: The Data1D object the information is coming from 
     1222        :param entry_node: lxml node ElementTree object to be appended to 
     1223 
     1224        """ 
     1225        if len(datainfo.notes) == 0: 
     1226            node = self.create_element("SASnote") 
     1227            self.append(node, entry_node) 
     1228        else: 
     1229            for item in datainfo.notes: 
     1230                node = self.create_element("SASnote") 
     1231                self.write_text(node, item) 
     1232                self.append(node, entry_node) 
     1233 
     1234    def _check_origin(self, entry_node, doc, frm): 
     1235        """ 
     1236        Return the document, and the SASentry node associated with 
     1237        the data we just wrote. 
     1238        If the calling function was not the cansas reader, return a minidom 
     1239        object rather than an lxml object. 
     1240 
     1241        :param entry_node: lxml node ElementTree object to be appended to 
     1242        :param doc: entire xml tree 
     1243        """ 
     1244        if not frm: 
     1245            frm = inspect.stack()[1] 
     1246        mod_name = frm[1].replace("\\", "/").replace(".pyc", "") 
     1247        mod_name = mod_name.replace(".py", "") 
     1248        mod = mod_name.split("sas/") 
     1249        mod_name = mod[1] 
     1250        if mod_name != "sascalc/dataloader/readers/cansas_reader": 
     1251            string = self.to_string(doc, pretty_print=False) 
     1252            doc = parseString(string) 
     1253            node_name = entry_node.tag 
     1254            node_list = doc.getElementsByTagName(node_name) 
     1255            entry_node = node_list.item(0) 
     1256        return doc, entry_node 
    11131257 
    11141258    # DO NOT REMOVE - used in saving and loading panel states. 
     
    11951339        if entry is not None and entry.text is not None: 
    11961340            exec "storage.%s = entry.text.strip()" % variable 
     1341 
     1342 
     1343# DO NOT REMOVE Called by outside packages: 
     1344#    sas.sasgui.perspectives.invariant.invariant_state 
     1345#    sas.sasgui.perspectives.fitting.pagestate 
     1346def get_content(location, node): 
     1347    """ 
     1348    Get the first instance of the content of a xpath location. 
     1349 
     1350    :param location: xpath location 
     1351    :param node: node to start at 
     1352 
     1353    :return: Element, or None 
     1354    """ 
     1355    nodes = node.xpath(location, 
     1356                       namespaces={'ns': CANSAS_NS.get("1.0").get("ns")}) 
     1357    if len(nodes) > 0: 
     1358        return nodes[0] 
     1359    else: 
     1360        return None 
     1361 
     1362# DO NOT REMOVE Called by outside packages: 
     1363#    sas.sasgui.perspectives.fitting.pagestate 
     1364def write_node(doc, parent, name, value, attr=None): 
     1365    """ 
     1366    :param doc: document DOM 
     1367    :param parent: parent node 
     1368    :param name: tag of the element 
     1369    :param value: value of the child text node 
     1370    :param attr: attribute dictionary 
     1371 
     1372    :return: True if something was appended, otherwise False 
     1373    """ 
     1374    if attr is None: 
     1375        attr = {} 
     1376    if value is not None: 
     1377        node = doc.createElement(name) 
     1378        node.appendChild(doc.createTextNode(str(value))) 
     1379        for item in attr: 
     1380            node.setAttribute(item, attr[item]) 
     1381        parent.appendChild(node) 
     1382        return True 
     1383    return False 
  • src/sas/sascalc/dataloader/readers/cansas_reader_HDF5.py

    rd72567e r479799c  
    6262        :return: List of Data1D/2D objects and/or a list of errors. 
    6363        """ 
    64  
    6564        ## Reinitialize the class when loading a new data file to reset all class variables 
    6665        self.reset_class_variables() 
     
    136135                ## If this is a dataset, store the data appropriately 
    137136                data_set = data[key][:] 
     137                unit = self._get_unit(value) 
     138 
     139                ## I and Q Data 
     140                if key == u'I': 
     141                    if type(self.current_dataset) is plottable_2D: 
     142                        self.current_dataset.data = data_set 
     143                        self.current_dataset.zaxis("Intensity", unit) 
     144                    else: 
     145                        self.current_dataset.y = data_set.flatten() 
     146                        self.current_dataset.yaxis("Intensity", unit) 
     147                    continue 
     148                elif key == u'Idev': 
     149                    if type(self.current_dataset) is plottable_2D: 
     150                        self.current_dataset.err_data = data_set.flatten() 
     151                    else: 
     152                        self.current_dataset.dy = data_set.flatten() 
     153                    continue 
     154                elif key == u'Q': 
     155                    self.current_dataset.xaxis("Q", unit) 
     156                    if type(self.current_dataset) is plottable_2D: 
     157                        self.current_dataset.q = data_set.flatten() 
     158                    else: 
     159                        self.current_dataset.x = data_set.flatten() 
     160                    continue 
     161                elif key == u'Qy': 
     162                    self.current_dataset.yaxis("Q_y", unit) 
     163                    self.current_dataset.qy_data = data_set.flatten() 
     164                    continue 
     165                elif key == u'Qydev': 
     166                    self.current_dataset.dqy_data = data_set.flatten() 
     167                    continue 
     168                elif key == u'Qx': 
     169                    self.current_dataset.xaxis("Q_x", unit) 
     170                    self.current_dataset.qx_data = data_set.flatten() 
     171                    continue 
     172                elif key == u'Qxdev': 
     173                    self.current_dataset.dqx_data = data_set.flatten() 
     174                    continue 
     175                elif key == u'Mask': 
     176                    self.current_dataset.mask = data_set.flatten() 
     177                    continue 
    138178 
    139179                for data_point in data_set: 
    140180                    ## Top Level Meta Data 
    141                     unit = self._get_unit(value) 
    142181                    if key == u'definition': 
    143182                        self.current_datainfo.meta_data['reader'] = data_point 
     
    148187                    elif key == u'SASnote': 
    149188                        self.current_datainfo.notes.append(data_point) 
    150  
    151                     ## I and Q Data 
    152                     elif key == u'I': 
    153                         if type(self.current_dataset) is plottable_2D: 
    154                             self.current_dataset.data = np.append(self.current_dataset.data, data_point) 
    155                             self.current_dataset.zaxis("Intensity", unit) 
    156                         else: 
    157                             self.current_dataset.y = np.append(self.current_dataset.y, data_point) 
    158                             self.current_dataset.yaxis("Intensity", unit) 
    159                     elif key == u'Idev': 
    160                         if type(self.current_dataset) is plottable_2D: 
    161                             self.current_dataset.err_data = np.append(self.current_dataset.err_data, data_point) 
    162                         else: 
    163                             self.current_dataset.dy = np.append(self.current_dataset.dy, data_point) 
    164                     elif key == u'Q': 
    165                         self.current_dataset.xaxis("Q", unit) 
    166                         if type(self.current_dataset) is plottable_2D: 
    167                             self.current_dataset.q = np.append(self.current_dataset.q, data_point) 
    168                         else: 
    169                             self.current_dataset.x = np.append(self.current_dataset.x, data_point) 
    170                     elif key == u'Qy': 
    171                         self.current_dataset.yaxis("Q_y", unit) 
    172                         self.current_dataset.qy_data = np.append(self.current_dataset.qy_data, data_point) 
    173                     elif key == u'Qydev': 
    174                         self.current_dataset.dqy_data = np.append(self.current_dataset.dqy_data, data_point) 
    175                     elif key == u'Qx': 
    176                         self.current_dataset.xaxis("Q_x", unit) 
    177                         self.current_dataset.qx_data = np.append(self.current_dataset.qx_data, data_point) 
    178                     elif key == u'Qxdev': 
    179                         self.current_dataset.dqx_data = np.append(self.current_dataset.dqx_data, data_point) 
    180                     elif key == u'Mask': 
    181                         self.current_dataset.mask = np.append(self.current_dataset.mask, data_point) 
    182189 
    183190                    ## Sample Information 
     
    296303        ## Type cast data arrays to float64 and find min/max as appropriate 
    297304        for dataset in self.data2d: 
    298             dataset.data = np.delete(dataset.data, [0]) 
    299305            dataset.data = dataset.data.astype(np.float64) 
    300             dataset.err_data = np.delete(dataset.err_data, [0]) 
    301306            dataset.err_data = dataset.err_data.astype(np.float64) 
    302             dataset.mask = np.delete(dataset.mask, [0]) 
    303307            if dataset.qx_data is not None: 
    304                 dataset.qx_data = np.delete(dataset.qx_data, [0]) 
    305308                dataset.xmin = np.min(dataset.qx_data) 
    306309                dataset.xmax = np.max(dataset.qx_data) 
    307310                dataset.qx_data = dataset.qx_data.astype(np.float64) 
    308311            if dataset.dqx_data is not None: 
    309                 dataset.dqx_data = np.delete(dataset.dqx_data, [0]) 
    310312                dataset.dqx_data = dataset.dqx_data.astype(np.float64) 
    311313            if dataset.qy_data is not None: 
    312                 dataset.qy_data = np.delete(dataset.qy_data, [0]) 
    313314                dataset.ymin = np.min(dataset.qy_data) 
    314315                dataset.ymax = np.max(dataset.qy_data) 
    315316                dataset.qy_data = dataset.qy_data.astype(np.float64) 
    316317            if dataset.dqy_data is not None: 
    317                 dataset.dqy_data = np.delete(dataset.dqy_data, [0]) 
    318318                dataset.dqy_data = dataset.dqy_data.astype(np.float64) 
    319319            if dataset.q_data is not None: 
    320                 dataset.q_data = np.delete(dataset.q_data, [0]) 
    321320                dataset.q_data = dataset.q_data.astype(np.float64) 
    322321            zeros = np.ones(dataset.data.size, dtype=bool) 
     
    333332            except: 
    334333                dataset.q_data = None 
     334 
     335            if dataset.data.ndim == 2: 
     336                (n_rows, n_cols) = dataset.data.shape 
     337                dataset.y_bins = dataset.qy_data[0::n_cols] 
     338                dataset.x_bins = dataset.qx_data[:n_cols] 
     339                dataset.data = dataset.data.flatten() 
     340 
    335341            final_dataset = combine_data_info_with_plottable(dataset, self.current_datainfo) 
    336342            self.output.append(final_dataset) 
     
    338344        for dataset in self.data1d: 
    339345            if dataset.x is not None: 
    340                 dataset.x = np.delete(dataset.x, [0]) 
    341346                dataset.x = dataset.x.astype(np.float64) 
    342347                dataset.xmin = np.min(dataset.x) 
    343348                dataset.xmax = np.max(dataset.x) 
    344349            if dataset.y is not None: 
    345                 dataset.y = np.delete(dataset.y, [0]) 
    346350                dataset.y = dataset.y.astype(np.float64) 
    347351                dataset.ymin = np.min(dataset.y) 
    348352                dataset.ymax = np.max(dataset.y) 
    349353            if dataset.dx is not None: 
    350                 dataset.dx = np.delete(dataset.dx, [0]) 
    351354                dataset.dx = dataset.dx.astype(np.float64) 
    352355            if dataset.dxl is not None: 
    353                 dataset.dxl = np.delete(dataset.dxl, [0]) 
    354356                dataset.dxl = dataset.dxl.astype(np.float64) 
    355357            if dataset.dxw is not None: 
    356                 dataset.dxw = np.delete(dataset.dxw, [0]) 
    357358                dataset.dxw = dataset.dxw.astype(np.float64) 
    358359            if dataset.dy is not None: 
    359                 dataset.dy = np.delete(dataset.dy, [0]) 
    360360                dataset.dy = dataset.dy.astype(np.float64) 
    361361            final_dataset = combine_data_info_with_plottable(dataset, self.current_datainfo) 
  • src/sas/sasgui/guiframe/data_panel.py

    rb5c44f0 re767897  
    22#This software was developed by the University of Tennessee as part of the 
    33#Distributed Data Analysis of Neutron Scattering Experiments (DANSE) 
    4 #project funded by the US National Science Foundation.  
     4#project funded by the US National Science Foundation. 
    55# 
    66#See the license text in license.txt 
     
    4141        as QucikPlotDialog 
    4242import sas.sasgui.guiframe.config as config 
    43   
     43 
    4444extension_list = [] 
    4545if config.APPLICATION_STATE_EXTENSION is not None: 
    4646    extension_list.append(config.APPLICATION_STATE_EXTENSION) 
    47 EXTENSIONS = config.PLUGIN_STATE_EXTENSIONS + extension_list    
     47EXTENSIONS = config.PLUGIN_STATE_EXTENSIONS + extension_list 
    4848PLUGINS_WLIST = config.PLUGINS_WLIST 
    4949APPLICATION_WLIST = config.APPLICATION_WLIST 
    5050 
    51 #Control panel width  
     51#Control panel width 
    5252if sys.platform.count("win32") > 0: 
    5353    PANEL_WIDTH = 235 
     
    6767STYLE_FLAG = wx.RAISED_BORDER|CT.TR_HAS_BUTTONS| CT.TR_HIDE_ROOT|\ 
    6868                    wx.WANTS_CHARS|CT.TR_HAS_VARIABLE_ROW_HEIGHT 
    69                      
    70                      
     69 
     70 
    7171class DataTreeCtrl(CT.CustomTreeCtrl): 
    7272    """ 
     
    9797                    CT.CustomTreeCtrl.__init__(self, parent, *args, **kwds) 
    9898        self.root = self.AddRoot("Available Data") 
    99                     
     99 
    100100    def OnCompareItems(self, item1, item2): 
    101         """  
    102         Overrides OnCompareItems in wx.TreeCtrl.  
    103         Used by the SortChildren method.  
     101        """ 
     102        Overrides OnCompareItems in wx.TreeCtrl. 
     103        Used by the SortChildren method. 
    104104        """ 
    105105        # Get the item data 
     
    113113        else: 
    114114            return 0 
    115          
     115 
    116116class DataPanel(ScrolledPanel, PanelBase): 
    117117    """ 
    118     This panel displays data available in the application and widgets to  
     118    This panel displays data available in the application and widgets to 
    119119    interact with data. 
    120120    """ 
     
    123123    ## Title to appear on top of the window 
    124124    window_caption = "Data Explorer" 
    125     #type of window  
     125    #type of window 
    126126    window_type = "Data Panel" 
    127127    ## Flag to tell the GUI manager that this panel is not 
    128128    #  tied to any perspective 
    129129    #ALWAYS_ON = True 
    130     def __init__(self, parent,  
     130    def __init__(self, parent, 
    131131                 list=None, 
    132132                 size=(PANEL_WIDTH, PANEL_HEIGHT), 
     
    138138        PanelBase.__init__(self, parent) 
    139139        self.SetupScrolling() 
    140         #Set window's font size  
     140        #Set window's font size 
    141141        self.SetWindowVariant(variant=FONT_VARIANT) 
    142         self.loader = Loader()   
     142        self.loader = Loader() 
    143143        #Default location 
    144         self._default_save_location = None   
     144        self._default_save_location = None 
    145145        self.all_data1d = True 
    146146        self.parent = parent.parent 
     
    188188        if self.parent is not None: 
    189189            self.parent.Bind(EVT_DELETE_PLOTPANEL, self._on_delete_plot_panel) 
    190       
     190 
    191191    def do_layout(self): 
    192192        """ 
     
    198198        self.layout_batch() 
    199199        self.layout_button() 
    200          
     200 
    201201    def disable_app_combo(self, enable): 
    202202        """ 
     
    204204        """ 
    205205        self.perspective_cbox.Enable(enable) 
    206          
     206 
    207207    def define_panel_structure(self): 
    208208        """ 
     
    213213        self.sizer1 = wx.BoxSizer(wx.VERTICAL) 
    214214        self.sizer1.SetMinSize(wx.Size(w/13, h*2/5)) 
    215        
     215 
    216216        self.sizer2 = wx.BoxSizer(wx.VERTICAL) 
    217217        self.sizer3 = wx.FlexGridSizer(9, 2, 4, 1) 
    218218        self.sizer4 = wx.BoxSizer(wx.VERTICAL) 
    219219        self.sizer5 = wx.BoxSizer(wx.VERTICAL) 
    220         
     220 
    221221        self.vbox.Add(self.sizer5, 0, wx.EXPAND|wx.ALL, 1) 
    222222        self.vbox.Add(self.sizer1, 1, wx.EXPAND|wx.ALL, 0) 
     
    224224        self.vbox.Add(self.sizer3, 0, wx.EXPAND|wx.ALL, 10) 
    225225        #self.vbox.Add(self.sizer4, 0, wx.EXPAND|wx.ALL,5) 
    226          
     226 
    227227        self.SetSizer(self.vbox) 
    228          
     228 
    229229    def layout_selection(self): 
    230230        """ 
     
    244244        self.selection_cbox.SetValue('Select all Data') 
    245245        wx.EVT_COMBOBOX(self.selection_cbox, -1, self._on_selection_type) 
    246         self.sizer5.AddMany([(select_txt, 0, wx.ALL, 5),  
     246        self.sizer5.AddMany([(select_txt, 0, wx.ALL, 5), 
    247247                            (self.selection_cbox, 0, wx.ALL,5)]) 
    248248        self.enable_selection() 
    249          
    250      
     249 
     250 
    251251    def _on_selection_type(self, event): 
    252252        """ 
     
    254254            :param event: UI event 
    255255        """ 
     256        def check_item_and_children(control, check_value=True): 
     257            self.tree_ctrl.CheckItem(data_ctrl, check_value) 
     258            if data_ctrl.HasChildren(): 
     259                if check_value == True and not control.IsExpanded(): 
     260                    # Only select children if control is expanded 
     261                    # Always deselect children, regardless (see ticket #259) 
     262                    return 
     263                for child_ctrl in data_ctrl.GetChildren(): 
     264                    self.tree_ctrl.CheckItem(child_ctrl, check_value) 
     265 
    256266        option = self.selection_cbox.GetValue() 
    257          
     267 
    258268        pos = self.selection_cbox.GetSelection() 
    259269        if pos == wx.NOT_FOUND: 
    260             return  
     270            return 
    261271        option = self.selection_cbox.GetString(pos) 
    262272        for item in self.list_cb_data.values(): 
    263273            data_ctrl, _, _, _, _, _, _, _ = item 
    264             _, data_class, _ = self.tree_ctrl.GetItemPyData(data_ctrl)  
     274            _, data_class, _ = self.tree_ctrl.GetItemPyData(data_ctrl) 
    265275            if option == 'Select all Data': 
    266                 self.tree_ctrl.CheckItem(data_ctrl, True)  
     276                check_item_and_children(data_ctrl, check_value=True) 
    267277            elif option == 'Unselect all Data': 
    268                 self.tree_ctrl.CheckItem(data_ctrl, False) 
     278                check_item_and_children(data_ctrl, check_value=False) 
    269279            elif option == 'Select all Data 1D': 
    270280                if data_class == 'Data1D': 
    271                     self.tree_ctrl.CheckItem(data_ctrl, True)  
     281                    check_item_and_children(data_ctrl, check_value=True) 
    272282            elif option == 'Unselect all Data 1D': 
    273283                if data_class == 'Data1D': 
    274                     self.tree_ctrl.CheckItem(data_ctrl, False)  
    275             elif option == 'Select all Data 1D': 
    276                 if data_class == 'Data1D': 
    277                     self.tree_ctrl.CheckItem(data_ctrl, True)  
     284                    check_item_and_children(data_ctrl, check_value=False) 
    278285            elif option == 'Select all Data 2D': 
    279286                if data_class == 'Data2D': 
    280                     self.tree_ctrl.CheckItem(data_ctrl, True)  
     287                    check_item_and_children(data_ctrl, check_value=True) 
    281288            elif option == 'Unselect all Data 2D': 
    282289                if data_class == 'Data2D': 
    283                     self.tree_ctrl.CheckItem(data_ctrl, False)  
     290                    check_item_and_children(data_ctrl, check_value=False) 
    284291        self.enable_append() 
    285292        self.enable_freeze() 
     
    287294        self.enable_import() 
    288295        self.enable_remove() 
    289                 
     296 
    290297    def layout_button(self): 
    291298        """ 
     
    293300        """ 
    294301        #Load Data Button 
    295         self.bt_add = wx.Button(self, wx.NewId(), "Load Data",  
     302        self.bt_add = wx.Button(self, wx.NewId(), "Load Data", 
    296303                                size=(BUTTON_WIDTH, -1)) 
    297304        self.bt_add.SetToolTipString("Load data files") 
    298305        wx.EVT_BUTTON(self, self.bt_add.GetId(), self._load_data) 
    299          
     306 
    300307        #Delete Data Button 
    301308        self.bt_remove = wx.Button(self, wx.NewId(), "Delete Data", 
     
    303310        self.bt_remove.SetToolTipString("Delete data from the application") 
    304311        wx.EVT_BUTTON(self, self.bt_remove.GetId(), self.on_remove) 
    305          
     312 
    306313        #Send data to perspective button 
    307314        self.bt_import = wx.Button(self, wx.NewId(), "Send To", 
     
    309316        self.bt_import.SetToolTipString("Send Data set to active perspective") 
    310317        wx.EVT_BUTTON(self, self.bt_import.GetId(), self.on_import) 
    311          
     318 
    312319        #Choose perspective to be send data to combo box 
    313320        self.perspective_cbox = wx.ComboBox(self, -1, 
     
    315322        if not IS_MAC: 
    316323            self.perspective_cbox.SetMinSize((BUTTON_WIDTH*1.6, -1)) 
    317         wx.EVT_COMBOBOX(self.perspective_cbox, -1,  
     324        wx.EVT_COMBOBOX(self.perspective_cbox, -1, 
    318325                        self._on_perspective_selection) 
    319      
     326 
    320327        #Append data to current Graph Button 
    321328        self.bt_append_plot = wx.Button(self, wx.NewId(), "Append Plot To", 
     
    324331                                "Plot the selected data in the active panel") 
    325332        wx.EVT_BUTTON(self, self.bt_append_plot.GetId(), self.on_append_plot) 
    326          
     333 
    327334        #Create a new graph and send data to that new graph button 
    328         self.bt_plot = wx.Button(self, wx.NewId(), "New Plot",  
     335        self.bt_plot = wx.Button(self, wx.NewId(), "New Plot", 
    329336                                 size=(BUTTON_WIDTH, -1)) 
    330337        self.bt_plot.SetToolTipString("To trigger plotting") 
    331338        wx.EVT_BUTTON(self, self.bt_plot.GetId(), self.on_plot) 
    332          
     339 
    333340        #Freeze current theory button - becomes a data set and stays on graph 
    334         self.bt_freeze = wx.Button(self, wx.NewId(), "Freeze Theory",  
     341        self.bt_freeze = wx.Button(self, wx.NewId(), "Freeze Theory", 
    335342                                   size=(BUTTON_WIDTH, -1)) 
    336343        freeze_tip = "To trigger freeze a theory: making a copy\n" 
     
    339346        self.bt_freeze.SetToolTipString(freeze_tip) 
    340347        wx.EVT_BUTTON(self, self.bt_freeze.GetId(), self.on_freeze) 
    341         
     348 
    342349        #select plot to send to combo box (blank if no data) 
    343350        if sys.platform == 'darwin': 
    344             self.cb_plotpanel = wx.ComboBox(self, -1,  
     351            self.cb_plotpanel = wx.ComboBox(self, -1, 
    345352                                            style=wx.CB_READONLY) 
    346353        else: 
    347             self.cb_plotpanel = wx.ComboBox(self, -1,  
     354            self.cb_plotpanel = wx.ComboBox(self, -1, 
    348355                                            style=wx.CB_READONLY|wx.CB_SORT) 
    349356        wx.EVT_COMBOBOX(self.cb_plotpanel, -1, self._on_plot_selection) 
    350357        self.cb_plotpanel.Disable() 
    351          
     358 
    352359        #Help button 
    353360        self.bt_help = wx.Button(self, wx.NewId(), "HELP", 
     
    365372                             ((10, 10)), 
    366373                             (self.bt_append_plot), 
    367                              (self.cb_plotpanel,  
     374                             (self.cb_plotpanel, 
    368375                              wx.EXPAND|wx.ADJUST_MINSIZE, 5), 
    369376                             ((5, 5)), 
    370377                             ((5, 5)), 
    371378                             (self.bt_import, 0, wx.EXPAND|wx.RIGHT, 5), 
    372                              (self.perspective_cbox,  
     379                             (self.perspective_cbox, 
    373380                              wx.EXPAND|wx.ADJUST_MINSIZE, 5), 
    374381                             ((10, 10)), 
     
    385392        self.enable_freeze() 
    386393        self.enable_remove_plot() 
    387          
     394 
    388395    def layout_batch(self): 
    389396        """ 
     
    397404        self.Bind(wx.EVT_RADIOBUTTON, self.on_batch_mode, 
    398405                   id=self.rb_batch_mode.GetId()) 
    399          
     406 
    400407        self.rb_single_mode.SetValue(not self.parent.batch_on) 
    401408        self.rb_batch_mode.SetValue(self.parent.batch_on) 
    402409        self.sizer4.AddMany([(self.rb_single_mode, 0, wx.ALL, 4), 
    403410                             (self.rb_batch_mode, 0, wx.ALL, 4)]) 
    404          
     411 
    405412    def on_single_mode(self, event): 
    406413        """ 
     
    410417        if self.parent is not None: 
    411418            wx.PostEvent(self.parent, NewBatchEvent(enable=False)) 
    412         
     419 
    413420    def on_batch_mode(self, event): 
    414421        """ 
     
    417424        """ 
    418425        if self.parent is not None: 
    419             wx.PostEvent(self.parent,  
     426            wx.PostEvent(self.parent, 
    420427                         NewBatchEvent(enable=True)) 
    421      
    422     def _get_data_selection(self, event):   
     428 
     429    def _get_data_selection(self, event): 
    423430        """ 
    424431            Get data selection from the right click 
     
    435442            data = theory_list.values()[0][0] 
    436443        return data 
    437      
     444 
    438445    def on_edit_data(self, event): 
    439446        """ 
     
    443450        from sas.sasgui.guiframe.local_perspectives.plotting.masking \ 
    444451            import MaskPanel as MaskDialog 
    445          
    446         panel = MaskDialog(parent=self.parent, base=self,  
     452 
     453        panel = MaskDialog(parent=self.parent, base=self, 
    447454                           data=data, id=wx.NewId()) 
    448455        panel.ShowModal() 
    449      
     456 
    450457    def on_plot_3d(self, event): 
    451458        """ 
     
    455462        from sas.sasgui.guiframe.local_perspectives.plotting.masking \ 
    456463        import FloatPanel as Float3dDialog 
    457          
    458         panel = Float3dDialog(base=self, data=data,  
     464 
     465        panel = Float3dDialog(base=self, data=data, 
    459466                              dimension=3, id=wx.NewId()) 
    460         panel.ShowModal()    
    461      
     467        panel.ShowModal() 
     468 
    462469    def on_quick_plot(self, event): 
    463470        """ 
     
    468475            dimension = 2 
    469476        else: 
    470             dimension = 1  
    471         #panel = QucikPlotDialog(base=self, data=data,  
     477            dimension = 1 
     478        #panel = QucikPlotDialog(base=self, data=data, 
    472479        #                        dimension=dimension, id=wx.NewId()) 
    473480        frame = QucikPlotDialog(self, -1, "Plot " + data.name, 'log_{10}') 
     
    477484        frame.Show(True) 
    478485        frame.SetFocus() 
    479         #panel.ShowModal()     
    480      
     486        #panel.ShowModal() 
     487 
    481488    def on_data_info(self, event): 
    482489        """ 
     
    488495        else: 
    489496            self.parent.show_data1d(data, data.name) 
    490          
     497 
    491498    def on_save_as(self, event): 
    492499        """ 
     
    506513            else: 
    507514                print "unable to save this type of data" 
    508          
     515 
    509516    def layout_data_list(self): 
    510517        """ 
     
    523530        self.data_menu.Append(id, name, msg) 
    524531        wx.EVT_MENU(self, id, self.on_data_info) 
    525          
     532 
    526533        id = wx.NewId() 
    527534        name = "Save As" 
     
    529536        self.data_menu.Append(id, name, msg) 
    530537        wx.EVT_MENU(self, id, self.on_save_as) 
    531      
     538 
    532539        quickplot_id = wx.NewId() 
    533540        name = "Quick Plot" 
     
    535542        self.data_menu.Append(quickplot_id, name, msg) 
    536543        wx.EVT_MENU(self, quickplot_id, self.on_quick_plot) 
    537          
     544 
    538545        self.plot3d_id = wx.NewId() 
    539546        name = "Quick 3DPlot (Slow)" 
     
    541548        self.data_menu.Append(self.plot3d_id, name, msg) 
    542549        wx.EVT_MENU(self, self.plot3d_id, self.on_plot_3d) 
    543              
     550 
    544551        self.editmask_id = wx.NewId() 
    545552        name = "Edit Mask" 
     
    547554        self.data_menu.Append(self.editmask_id, name, msg) 
    548555        wx.EVT_MENU(self, self.editmask_id, self.on_edit_data) 
    549          
     556 
    550557        tree_ctrl_theory_label = wx.StaticText(self, -1, "Theory") 
    551558        tree_ctrl_theory_label.SetForegroundColour('blue') 
    552         self.tree_ctrl_theory = DataTreeCtrl(parent=self,  
     559        self.tree_ctrl_theory = DataTreeCtrl(parent=self, 
    553560                                                    style=wx.SUNKEN_BORDER) 
    554         self.tree_ctrl_theory.Bind(CT.EVT_TREE_ITEM_CHECKING,  
     561        self.tree_ctrl_theory.Bind(CT.EVT_TREE_ITEM_CHECKING, 
    555562                                                    self.on_check_item) 
    556         self.tree_ctrl_theory.Bind(CT.EVT_TREE_ITEM_MENU,  
     563        self.tree_ctrl_theory.Bind(CT.EVT_TREE_ITEM_MENU, 
    557564                                   self.on_right_click_theory) 
    558565        self.sizer1.Add(tree_ctrl_label, 0, wx.LEFT, 10) 
     
    560567        self.sizer1.Add(tree_ctrl_theory_label, 0,  wx.LEFT, 10) 
    561568        self.sizer1.Add(self.tree_ctrl_theory, 1, wx.EXPAND|wx.ALL, 10) 
    562             
     569 
    563570    def on_right_click_theory(self, event): 
    564571        """ 
     
    575582            self.data_menu.Enable(self.editmask_id, False) 
    576583            self.data_menu.Enable(self.plot3d_id, menu_enable) 
    577             self.PopupMenu(self.data_menu)  
    578                     
     584            self.PopupMenu(self.data_menu) 
     585 
    579586    def on_right_click_data(self, event): 
    580587        """ 
     
    596603            self.data_menu.Enable(self.editmask_id, maskmenu_enable) 
    597604            self.data_menu.Enable(self.plot3d_id, menu_enable) 
    598             self.PopupMenu(self.data_menu)  
    599          
    600     def onContextMenu(self, event):  
     605            self.PopupMenu(self.data_menu) 
     606 
     607    def onContextMenu(self, event): 
    601608        """ 
    602609        Retrieve the state selected state 
     
    606613        pos = event.GetPosition() 
    607614        pos = self.ScreenToClient(pos) 
    608         self.PopupMenu(self.popUpMenu, pos)  
    609        
    610    
     615        self.PopupMenu(self.popUpMenu, pos) 
     616 
     617 
    611618    def on_check_item(self, event): 
    612619        """ 
     
    614621        """ 
    615622        item = event.GetItem() 
    616         item.Check(not item.IsChecked())  
     623        item.Check(not item.IsChecked()) 
    617624        self.enable_append() 
    618625        self.enable_freeze() 
     
    621628        self.enable_remove() 
    622629        event.Skip() 
    623          
     630 
    624631    def fill_cbox_analysis(self, plugin): 
    625632        """ 
     
    635642                if plug.get_perspective(): 
    636643                    self.perspective_cbox.Append(plug.sub_menu, plug) 
    637              
     644 
    638645            curr_pers = self.parent.get_current_perspective() 
    639646            if curr_pers: 
    640647                self.perspective_cbox.SetStringSelection(curr_pers.sub_menu) 
    641648                self.enable_import() 
    642                          
     649 
    643650    def load_data_list(self, list): 
    644651        """ 
     
    654661                    data_run = str(data.run) 
    655662                    data_class = data.__class__.__name__ 
    656                     path = dstate.get_path()  
     663                    path = dstate.get_path() 
    657664                    process_list = data.process 
    658665                    data_id = data.id 
     
    661668                        #new state 
    662669                        data_c = self.tree_ctrl.InsertItem(self.tree_ctrl.root, 
    663                                         0, data_name, ct_type=1,  
     670                                        0, data_name, ct_type=1, 
    664671                                        data=(data_id, data_class, state_id)) 
    665672                        data_c.Check(True) 
    666673                        d_i_c = self.tree_ctrl.AppendItem(data_c, 'Info') 
    667                         d_t_c = self.tree_ctrl.AppendItem(d_i_c,  
     674                        d_t_c = self.tree_ctrl.AppendItem(d_i_c, 
    668675                                                      'Title: %s' % data_title) 
    669                         r_n_c = self.tree_ctrl.AppendItem(d_i_c,  
     676                        r_n_c = self.tree_ctrl.AppendItem(d_i_c, 
    670677                                                      'Run: %s' % data_run) 
    671                         i_c_c = self.tree_ctrl.AppendItem(d_i_c,  
     678                        i_c_c = self.tree_ctrl.AppendItem(d_i_c, 
    672679                                                      'Type: %s' % data_class) 
    673680                        p_c_c = self.tree_ctrl.AppendItem(d_i_c, 
    674681                                                      "Path: '%s'" % s_path) 
    675682                        d_p_c = self.tree_ctrl.AppendItem(d_i_c, 'Process') 
    676                          
     683 
    677684                        for process in process_list: 
    678685                            process_str = str(process).replace('\n',' ') 
     
    680687                                process_str = process_str[:20]+' [...]' 
    681688                            self.tree_ctrl.AppendItem(d_p_c, process_str) 
    682                         theory_child = self.tree_ctrl.AppendItem(data_c,  
     689                        theory_child = self.tree_ctrl.AppendItem(data_c, 
    683690                                                                 "THEORIES") 
    684                         self.list_cb_data[state_id] = [data_c,  
     691                        self.list_cb_data[state_id] = [data_c, 
    685692                                                       d_i_c, 
    686693                                                       d_t_c, 
     
    695702                        data_c, d_i_c, d_t_c, r_n_c,  i_c_c, p_c_c, d_p_c, _ \ 
    696703                                = data_ctrl_list 
    697                         self.tree_ctrl.SetItemText(data_c, data_name)  
     704                        self.tree_ctrl.SetItemText(data_c, data_name) 
    698705                        temp = (data_id, data_class, state_id) 
    699                         self.tree_ctrl.SetItemPyData(data_c, temp)  
    700                         self.tree_ctrl.SetItemText(i_c_c,  
     706                        self.tree_ctrl.SetItemPyData(data_c, temp) 
     707                        self.tree_ctrl.SetItemText(i_c_c, 
    701708                                                   'Type: %s' % data_class) 
    702                         self.tree_ctrl.SetItemText(p_c_c,  
    703                                                    'Path: %s' % s_path)  
    704                         self.tree_ctrl.DeleteChildren(d_p_c)  
     709                        self.tree_ctrl.SetItemText(p_c_c, 
     710                                                   'Path: %s' % s_path) 
     711                        self.tree_ctrl.DeleteChildren(d_p_c) 
    705712                        for process in process_list: 
    706713                            if not process.is_empty(): 
     
    710717            # Sort by data name 
    711718            if self.tree_ctrl.root: 
    712                 self.tree_ctrl.SortChildren(self.tree_ctrl.root)     
     719                self.tree_ctrl.SortChildren(self.tree_ctrl.root) 
    713720        self.enable_remove() 
    714721        self.enable_import() 
     
    716723        self.enable_freeze() 
    717724        self.enable_selection() 
    718          
     725 
    719726    def _uncheck_all(self): 
    720727        """ 
     
    723730        for item in self.list_cb_data.values(): 
    724731            data_ctrl, _, _, _, _, _, _, _ = item 
    725             self.tree_ctrl.CheckItem(data_ctrl, False)  
     732            self.tree_ctrl.CheckItem(data_ctrl, False) 
    726733        self.enable_append() 
    727734        self.enable_freeze() 
     
    729736        self.enable_import() 
    730737        self.enable_remove() 
    731     
     738 
    732739    def append_theory(self, state_id, theory_list): 
    733740        """ 
     
    736743        """ 
    737744        if not theory_list: 
    738             return  
     745            return 
    739746        if state_id not in self.list_cb_data.keys(): 
    740747            root = self.tree_ctrl_theory.root 
     
    746753            tree = self.tree_ctrl 
    747754        if root is not None: 
    748             wx.CallAfter(self.append_theory_helper, tree=tree, root=root,  
    749                                        state_id=state_id,  
     755            wx.CallAfter(self.append_theory_helper, tree=tree, root=root, 
     756                                       state_id=state_id, 
    750757                                       theory_list=theory_list) 
    751        
    752        
     758 
     759 
    753760    def append_theory_helper(self, tree, root, state_id, theory_list): 
    754761        """ 
     
    778785                                                    name, ct_type=1, data=temp) 
    779786                    t_i_c = tree.AppendItem(t_child, 'Info') 
    780                     i_c_c = tree.AppendItem(t_i_c,  
     787                    i_c_c = tree.AppendItem(t_i_c, 
    781788                                                  'Type: %s' % theory_class) 
    782789                    t_p_c = tree.AppendItem(t_i_c, 'Process') 
    783                      
     790 
    784791                    for process in theory_data.process: 
    785792                        tree.AppendItem(t_p_c, process.__str__()) 
    786                     theory_list_ctrl[theory_id] = [t_child,  
    787                                                    i_c_c,  
     793                    theory_list_ctrl[theory_id] = [t_child, 
     794                                                   i_c_c, 
    788795                                                   t_p_c] 
    789796                else: 
    790797                    #replace theory 
    791798                    t_child, i_c_c, t_p_c = theory_list_ctrl[theory_id] 
    792                     tree.SetItemText(t_child, name)  
    793                     tree.SetItemPyData(t_child, temp)  
    794                     tree.SetItemText(i_c_c, 'Type: %s' % theory_class)  
    795                     tree.DeleteChildren(t_p_c)  
     799                    tree.SetItemText(t_child, name) 
     800                    tree.SetItemPyData(t_child, temp) 
     801                    tree.SetItemText(i_c_c, 'Type: %s' % theory_class) 
     802                    tree.DeleteChildren(t_p_c) 
    796803                    for process in theory_data.process: 
    797804                        tree.AppendItem(t_p_c, process.__str__()) 
    798                
     805 
    799806        else: 
    800807            #data didn't have a theory associated it before 
     
    807814                    theory_id = theory_data.id 
    808815                    #if theory_state is not None: 
    809                     #    name = theory_state.model.name  
     816                    #    name = theory_state.model.name 
    810817                    temp = (theory_id, theory_class, state_id) 
    811818                    t_child = tree.AppendItem(root, 
    812                             name, ct_type=1,  
     819                            name, ct_type=1, 
    813820                            data=(theory_data.id, theory_class, state_id)) 
    814821                    t_i_c = tree.AppendItem(t_child, 'Info') 
    815                     i_c_c = tree.AppendItem(t_i_c,  
     822                    i_c_c = tree.AppendItem(t_i_c, 
    816823                                                  'Type: %s' % theory_class) 
    817824                    t_p_c = tree.AppendItem(t_i_c, 'Process') 
    818                      
     825 
    819826                    for process in theory_data.process: 
    820827                        tree.AppendItem(t_p_c, process.__str__()) 
    821              
     828 
    822829                    theory_list_ctrl[theory_id] = [t_child, i_c_c, t_p_c] 
    823830                #self.list_cb_theory[data_id] = theory_list_ctrl 
    824831                self.list_cb_theory[state_id] = theory_list_ctrl 
    825          
    826              
    827     
     832 
     833 
     834 
    828835    def set_data_helper(self): 
    829836        """ 
     
    840847                if state_id not in state_to_plot: 
    841848                    state_to_plot.append(state_id) 
    842             
     849 
    843850        for theory_dict in self.list_cb_theory.values(): 
    844851            for _, value in theory_dict.iteritems(): 
     
    850857                        state_to_plot.append(state_id) 
    851858        return data_to_plot, theory_to_plot, state_to_plot 
    852      
     859 
    853860    def remove_by_id(self, id): 
    854861        """ 
     
    857864        for item in self.list_cb_data.values(): 
    858865            data_c, _, _, _, _, _,  _, _ = item 
    859             data_id, _, state_id = self.tree_ctrl.GetItemPyData(data_c)  
     866            data_id, _, state_id = self.tree_ctrl.GetItemPyData(data_c) 
    860867            if id == data_id: 
    861868                self.tree_ctrl.Delete(data_c) 
    862869                del self.list_cb_data[state_id] 
    863870                del self.list_cb_theory[data_id] 
    864                
     871 
    865872    def load_error(self, error=None): 
    866873        """ 
    867874        Pop up an error message. 
    868          
     875 
    869876        :param error: details error message to be displayed 
    870877        """ 
    871878        if error is not None or str(error).strip() != "": 
    872             dial = wx.MessageDialog(self.parent, str(error),  
     879            dial = wx.MessageDialog(self.parent, str(error), 
    873880                                    'Error Loading File', 
    874881                                    wx.OK | wx.ICON_EXCLAMATION) 
    875             dial.ShowModal()   
    876          
     882            dial.ShowModal() 
     883 
    877884    def _load_data(self, event): 
    878885        """ 
     
    881888        if self.parent is not None: 
    882889            wx.PostEvent(self.parent, NewLoadDataEvent()) 
    883              
     890 
    884891 
    885892    def on_remove(self, event): 
    886893        """ 
    887894        Get a list of item checked and remove them from the treectrl 
    888         Ask the parent to remove reference to this item  
     895        Ask the parent to remove reference to this item 
    889896        """ 
    890897        msg = "This operation will delete the data sets checked " 
     
    893900        if msg_box.ShowModal() != wx.ID_OK: 
    894901            return 
    895          
     902 
    896903        data_to_remove, theory_to_remove, _ = self.set_data_helper() 
    897904        data_key = [] 
     
    906913                    theory_list_ctrl = self.list_cb_theory[d_key] 
    907914                    theory_to_remove += theory_list_ctrl.keys() 
    908         # Remove theory from treectrl        
     915        # Remove theory from treectrl 
    909916        for _, theory_dict in self.list_cb_theory.iteritems(): 
    910917            for  key, value in theory_dict.iteritems(): 
     
    916923                        pass 
    917924                    theory_key.append(key) 
    918                      
     925 
    919926        #Remove data and related theory references 
    920927        for key in data_key: 
     
    934941                                pass 
    935942                    del theory_dict[key] 
    936                      
    937              
     943 
     944 
    938945        self.parent.remove_data(data_id=data_to_remove, 
    939946                                  theory_id=theory_to_remove) 
     
    941948        self.enable_freeze() 
    942949        self.enable_remove_plot() 
    943          
     950 
    944951    def on_import(self, event=None): 
    945952        """ 
     
    951958        temp = data_id + state_id 
    952959        self.parent.set_data(data_id=temp, theory_id=theory_id) 
    953          
     960 
    954961    def on_append_plot(self, event=None): 
    955962        """ 
     
    958965        self._on_plot_selection() 
    959966        data_id, theory_id, state_id = self.set_data_helper() 
    960         self.parent.plot_data(data_id=data_id,   
     967        self.parent.plot_data(data_id=data_id, 
    961968                              state_id=state_id, 
    962969                              theory_id=theory_id, 
    963970                              append=True) 
    964     
     971 
    965972    def on_plot(self, event=None): 
    966973        """ 
     
    968975        """ 
    969976        data_id, theory_id, state_id = self.set_data_helper() 
    970         self.parent.plot_data(data_id=data_id,   
     977        self.parent.plot_data(data_id=data_id, 
    971978                              state_id=state_id, 
    972979                              theory_id=theory_id, 
    973980                              append=False) 
    974981        self.enable_remove_plot() 
    975           
     982 
    976983    def on_close_page(self, event=None): 
    977984        """ 
     
    982989        # send parent to update menu with no show nor hide action 
    983990        self.parent.show_data_panel(action=False) 
    984      
     991 
    985992    def on_freeze(self, event): 
    986993        """ 
     
    9951002            msg = "Freeze Theory: Requires at least one theory checked." 
    9961003        wx.PostEvent(self.parent, StatusEvent(status=msg)) 
    997              
     1004 
    9981005    def set_active_perspective(self, name): 
    9991006        """ 
     
    10021009        self.perspective_cbox.SetStringSelection(name) 
    10031010        self.enable_import() 
    1004          
     1011 
    10051012    def _on_delete_plot_panel(self, event): 
    10061013        """ 
    1007         get an event with attribute name and caption to delete existing name  
     1014        get an event with attribute name and caption to delete existing name 
    10081015        from the combobox of the current panel 
    10091016        """ 
     
    10111018        caption = event.caption 
    10121019        if self.cb_plotpanel is not None: 
    1013             pos = self.cb_plotpanel.FindString(str(caption))  
     1020            pos = self.cb_plotpanel.FindString(str(caption)) 
    10141021            if pos != wx.NOT_FOUND: 
    10151022                self.cb_plotpanel.Delete(pos) 
    10161023        self.enable_append() 
    1017          
     1024 
    10181025    def set_panel_on_focus(self, name=None): 
    10191026        """ 
     
    10311038        self.enable_append() 
    10321039        self.enable_remove_plot() 
    1033      
     1040 
    10341041    def set_plot_unfocus(self): 
    10351042        """ 
     
    10371044        """ 
    10381045        return 
    1039      
     1046 
    10401047    def _on_perspective_selection(self, event=None): 
    10411048        """ 
     
    10471054            perspective.on_perspective(event=None) 
    10481055            self.parent.check_multimode(perspective=perspective) 
    1049                  
     1056 
    10501057    def _on_plot_selection(self, event=None): 
    10511058        """ 
     
    10611068        if combo.GetValue() != 'None': 
    10621069            panel = combo.GetClientData(selection) 
    1063             self.parent.on_set_plot_focus(panel)    
    1064              
     1070            self.parent.on_set_plot_focus(panel) 
     1071 
    10651072    def on_close_plot(self, event): 
    10661073        """ 
    10671074        clseo the panel on focus 
    1068         """  
     1075        """ 
    10691076        self.enable_append() 
    10701077        selection = self.cb_plotpanel.GetSelection() 
     
    10721079            panel = self.cb_plotpanel.GetClientData(selection) 
    10731080            if self.parent is not None and panel is not None: 
    1074                 wx.PostEvent(self.parent,  
     1081                wx.PostEvent(self.parent, 
    10751082                             NewPlotEvent(group_id=panel.group_id, 
    10761083                                          action="delete")) 
    10771084        self.enable_remove_plot() 
    1078      
     1085 
    10791086    def set_frame(self, frame): 
    10801087        """ 
    10811088        """ 
    10821089        self.frame = frame 
    1083      
     1090 
    10841091    def get_frame(self): 
    10851092        """ 
    10861093        """ 
    1087         return self.frame  
    1088      
     1094        return self.frame 
     1095 
    10891096    def on_help(self, event): 
    10901097        """ 
     
    11151122        """ 
    11161123        self.parent.show_data_panel(event) 
    1117                          
     1124 
    11181125    def set_schedule_full_draw(self, panel=None, func='del'): 
    11191126        """ 
     
    11211128        """ 
    11221129        self.parent.set_schedule_full_draw(panel, func) 
    1123          
     1130 
    11241131    def enable_remove_plot(self): 
    11251132        """ 
     
    11311138        #else: 
    11321139        #    self.bt_close_plot.Enable() 
    1133              
     1140 
    11341141    def enable_remove(self): 
    11351142        """ 
     
    11421149        else: 
    11431150            self.bt_remove.Enable() 
    1144              
     1151 
    11451152    def enable_import(self): 
    11461153        """ 
     
    11601167        else: 
    11611168            self.perspective_cbox.Enable() 
    1162              
     1169 
    11631170    def enable_plot(self): 
    11641171        """ 
    11651172        enable or disable plot button 
    11661173        """ 
    1167         n_t = 0  
     1174        n_t = 0 
    11681175        n_t_t = 0 
    11691176        if self.tree_ctrl != None: 
     
    11761183            self.bt_plot.Enable() 
    11771184        self.enable_append() 
    1178         
     1185 
    11791186    def enable_append(self): 
    11801187        """ 
    11811188        enable or disable append button 
    11821189        """ 
    1183         n_t = 0  
     1190        n_t = 0 
    11841191        n_t_t = 0 
    11851192        if self.tree_ctrl != None: 
     
    11871194        if self.tree_ctrl_theory != None: 
    11881195            n_t_t = self.tree_ctrl_theory.GetCount() 
    1189         if n_t + n_t_t <= 0:  
     1196        if n_t + n_t_t <= 0: 
    11901197            self.bt_append_plot.Disable() 
    11911198            self.cb_plotpanel.Disable() 
     
    11961203            self.bt_append_plot.Enable() 
    11971204            self.cb_plotpanel.Enable() 
    1198              
     1205 
    11991206    def check_theory_to_freeze(self): 
    12001207        """ 
     
    12141221        else: 
    12151222            self.bt_freeze.Disable() 
    1216          
     1223 
    12171224    def enable_selection(self): 
    12181225        """ 
     
    12291236        else: 
    12301237            self.selection_cbox.Disable() 
    1231              
     1238 
    12321239    def show_data_button(self): 
    12331240        """ 
    1234         show load data and remove data button if  
     1241        show load data and remove data button if 
    12351242        dataloader on else hide them 
    12361243        """ 
     
    12381245            gui_style = self.parent.get_style() 
    12391246            style = gui_style & GUIFRAME.DATALOADER_ON 
    1240             if style == GUIFRAME.DATALOADER_ON:  
     1247            if style == GUIFRAME.DATALOADER_ON: 
    12411248                #self.bt_remove.Show(True) 
    1242                 self.bt_add.Show(True)  
     1249                self.bt_add.Show(True) 
    12431250            else: 
    12441251                #self.bt_remove.Hide() 
    12451252                self.bt_add.Hide() 
    1246         except:  
     1253        except: 
    12471254            #self.bt_remove.Hide() 
    1248             self.bt_add.Hide()  
    1249      
     1255            self.bt_add.Hide() 
     1256 
    12501257 
    12511258 
     
    12641271        self.list_of_ctrl = [] 
    12651272        if not data_list: 
    1266             return  
     1273            return 
    12671274        self._sizer_main = wx.BoxSizer(wx.VERTICAL) 
    12681275        self._sizer_txt = wx.BoxSizer(wx.VERTICAL) 
     
    12731280        self._panel.SetupScrolling() 
    12741281        self.__do_layout(data_list, text=text) 
    1275          
     1282 
    12761283    def __do_layout(self, data_list, text=''): 
    12771284        """ 
     
    12791286        """ 
    12801287        if not data_list or len(data_list) <= 1: 
    1281             return  
     1288            return 
    12821289        #add text 
    1283          
     1290 
    12841291        text = "Deleting these file reset some panels.\n" 
    12851292        text += "Do you want to proceed?\n" 
     
    13151322                                wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10) 
    13161323        static_line = wx.StaticLine(self, -1) 
    1317          
     1324 
    13181325        self._sizer_txt.Add(self._panel, 1, wx.EXPAND|wx.LEFT|wx.RIGHT, 5) 
    13191326        self._sizer_main.Add(self._sizer_txt, 1, wx.EXPAND|wx.ALL, 10) 
    1320         #self._sizer_main.Add(self._data_text_ctrl, 0,  
     1327        #self._sizer_main.Add(self._data_text_ctrl, 0, 
    13211328        #                     wx.EXPAND|wx.LEFT|wx.RIGHT, 10) 
    13221329        self._sizer_main.Add(static_line, 0, wx.EXPAND, 0) 
     
    13241331        self.SetSizer(self._sizer_main) 
    13251332        self.Layout() 
    1326          
     1333 
    13271334    def get_data(self): 
    13281335        """ 
     
    13351342                temp.append(data) 
    13361343        return temp 
    1337                 
     1344 
    13381345class DataFrame(wx.Frame): 
    13391346    """ 
     
    13471354    #  tied to any perspective 
    13481355    ALWAYS_ON = True 
    1349      
     1356 
    13501357    def __init__(self, parent=None, owner=None, manager=None, size=(300, 800), 
    13511358                         list_of_perspective=[], list=[], *args, **kwds): 
     
    13571364        self.owner = owner 
    13581365        self._manager = manager 
    1359         self.panel = DataPanel(parent=self,  
     1366        self.panel = DataPanel(parent=self, 
    13601367                               manager=manager, 
    13611368                               list_of_perspective=list_of_perspective) 
    1362       
     1369 
    13631370    def load_data_list(self, list=[]): 
    13641371        """ 
     
    13661373        """ 
    13671374        self.panel.load_data_list(list=list) 
    1368          
    1369     
    1370      
     1375 
     1376 
     1377 
    13711378from sas.sasgui.guiframe.dataFitting import Theory1D 
    13721379from sas.sasgui.guiframe.data_state import DataState 
     
    13831390        self.msg += "name  value\n" 
    13841391        return self.msg 
    1385      
     1392 
    13861393def set_data_state(data=None, path=None, theory=None, state=None): 
    13871394    """ 
     
    13911398    dstate.set_path(path=path) 
    13921399    dstate.set_theory(theory, state) 
    1393    
     1400 
    13941401    return dstate 
    1395      
     1402 
    13961403if __name__ == "__main__": 
    1397      
     1404 
    13981405    app = wx.App() 
    13991406    try: 
     
    14771484        #raise 
    14781485        print "error", sys.exc_value 
    1479          
    1480     app.MainLoop()   
    1481      
    1482      
     1486 
     1487    app.MainLoop() 
  • src/sas/sasgui/guiframe/local_perspectives/data_loader/data_loader.py

    rfaa3ae7 ra674d0b  
    162162            logging.error("Loader returned an invalid object:\n %s" % str(item)) 
    163163            data_error = True 
    164          
     164 
    165165        data = self.parent.create_gui_data(item, p_file) 
    166166        output[data.id] = data 
     
    170170        """ 
    171171        """ 
    172         message = "" 
    173         log_msg = '' 
     172        file_errors = {} 
    174173        output = {} 
    175         any_error = False 
    176         data_error = False 
    177         error_message = "" 
     174        exception_occurred = False 
     175 
    178176        for p_file in path: 
    179             info = "info" 
    180177            basename = os.path.basename(p_file) 
    181178            _, extension = os.path.splitext(basename) 
    182179            if extension.lower() in EXTENSIONS: 
    183                 any_error = True 
    184180                log_msg = "Data Loader cannot " 
    185                 log_msg += "load: %s\n" % str(p_file) 
    186                 log_msg += """Please try to open that file from "open project" """ 
    187                 log_msg += """or "open analysis" menu\n""" 
    188                 error_message = log_msg + "\n" 
     181                log_msg += "load: {}\n".format(str(p_file)) 
     182                log_msg += "Please try to open that file from \"open project\"" 
     183                log_msg += "or \"open analysis\" menu." 
    189184                logging.info(log_msg) 
     185                file_errors[basename] = [log_msg] 
    190186                continue 
    191187 
    192188            try: 
    193                 message = "Loading Data... " + str(p_file) + "\n" 
    194                 self.load_update(output=output, message=message, info=info) 
     189                message = "Loading {}...\n".format(p_file) 
     190                self.load_update(output=output, message=message, info="info") 
    195191                temp = self.loader.load(p_file, format) 
    196                 if temp.__class__.__name__ == "list": 
    197                     for item in temp: 
    198                         output, error_message, data_error = \ 
    199                             self._process_data_and_errors(item, 
    200                                                           p_file, 
    201                                                           output, 
    202                                                           error_message) 
    203                 else: 
     192                if not isinstance(temp, list): 
     193                    temp = [temp] 
     194                for item in temp: 
     195                    error_message = "" 
    204196                    output, error_message, data_error = \ 
    205                             self._process_data_and_errors(temp, 
    206                                                           p_file, 
    207                                                           output, 
    208                                                           error_message) 
     197                        self._process_data_and_errors(item, 
     198                                                      p_file, 
     199                                                      output, 
     200                                                      error_message) 
     201                    if data_error: 
     202                        if basename in file_errors.keys(): 
     203                            file_errors[basename] += [error_message] 
     204                        else: 
     205                            file_errors[basename] = [error_message] 
     206                        self.load_update(output=output, 
     207                            message=error_message, info="warning") 
     208 
     209                self.load_update(output=output, 
     210                message="Loaded {}\n".format(p_file), 
     211                info="info") 
     212 
    209213            except: 
    210214                logging.error(sys.exc_value) 
    211                 any_error = True 
    212             if any_error or error_message != "": 
    213                 if error_message == "": 
    214                     error = "Error: " + str(sys.exc_info()[1]) + "\n" 
    215                     error += "while loading Data: \n%s\n" % str(basename) 
    216                     error_message += "The data file you selected could not be loaded.\n" 
    217                     error_message += "Make sure the content of your file" 
    218                     error_message += " is properly formatted.\n\n" 
    219                     error_message += "When contacting the SasView team, mention the" 
    220                     error_message += " following:\n%s" % str(error) 
    221                 elif data_error: 
    222                     base_message = "Errors occurred while loading " 
    223                     base_message += "{0}\n".format(basename) 
    224                     base_message += "The data file loaded but with errors.\n" 
    225                     error_message = base_message + error_message 
    226                 else: 
    227                     error_message += "%s\n" % str(p_file) 
    228                 info = "error" 
    229          
    230         if any_error or error_message: 
    231             self.load_update(output=output, message=error_message, info=info) 
    232         else: 
    233             message = "Loading Data Complete! " 
    234         message += log_msg 
    235         self.load_complete(output=output, error_message=error_message, 
    236                            message=message, path=path, info='info') 
     215 
     216                error_message = "The Data file you selected could not be loaded.\n" 
     217                error_message += "Make sure the content of your file" 
     218                error_message += " is properly formatted.\n" 
     219                error_message += "When contacting the SasView team, mention the" 
     220                error_message += " following:\n" 
     221                error_message += "Error: " + str(sys.exc_info()[1]) 
     222                file_errors[basename] = [error_message] 
     223                self.load_update(output=output, message=error_message, info="warning") 
     224 
     225        if len(file_errors) > 0: 
     226            error_message = "" 
     227            for filename, error_array in file_errors.iteritems(): 
     228                error_message += "The following errors occured whilst " 
     229                error_message += "loading {}:\n".format(filename) 
     230                for message in error_array: 
     231                    error_message += message + "\n" 
     232                error_message += "\n" 
     233            self.load_update(output=output, message=error_message, info="error") 
     234 
     235        self.load_complete(output=output, message="Loading data complete!", 
     236            info="info") 
    237237 
    238238    def load_update(self, output=None, message="", info="warning"): 
     
    254254        #    self.load_error(error_message) 
    255255        self.parent.add_data(data_list=output) 
    256  
    257  
    258  
  • src/sas/sasgui/guiframe/local_perspectives/plotting/Plotter1D.py

    refb482a r895c9cb  
    552552            self.subplot.set_xlim((xlo, xhi)) 
    553553            self.subplot.set_ylim((ylo, yhi)) 
     554        self.graph.selected_plottable = None 
    554555 
    555556 
     
    629630 
    630631            if self.parent.ClassName.count('wxDialog') == 0: 
    631                 wx_id = ids.next() 
    632                 plot_menu.Append(wx_id, '&Linear Fit', name) 
    633                 wx.EVT_MENU(self, wx_id, self.onFitting) 
    634                 plot_menu.AppendSeparator() 
     632                if plot.id != 'fit': 
     633                    wx_id = ids.next() 
     634                    plot_menu.Append(wx_id, '&Linear Fit', name) 
     635                    wx.EVT_MENU(self, wx_id, self.onFitting) 
     636                    plot_menu.AppendSeparator() 
    635637 
    636638                wx_id = ids.next() 
     
    694696        self._slicerpop.AppendSeparator() 
    695697        wx_id = ids.next() 
     698        self._slicerpop.Append(wx_id, '&Set Graph Range') 
     699        wx.EVT_MENU(self, wx_id, self.onSetRange) 
     700        wx_id = ids.next() 
    696701        self._slicerpop.Append(wx_id, '&Reset Graph Range') 
    697702        wx.EVT_MENU(self, wx_id, self.onResetGraph) 
     
    710715        self.PopupMenu(self._slicerpop, pos) 
    711716 
     717    def onSetRange(self, event): 
     718        # Display dialog 
     719        # self.subplot.set_xlim((low, high)) 
     720        # self.subplot.set_ylim((low, high)) 
     721        from sas.sasgui.plottools.RangeDialog import RangeDialog 
     722        d = RangeDialog(self, -1) 
     723        xlim = self.subplot.get_xlim() 
     724        ylim = self.subplot.get_ylim() 
     725        d.SetXRange(xlim) 
     726        d.SetYRange(ylim) 
     727        if d.ShowModal() == wx.ID_OK: 
     728            x_range = d.GetXRange() 
     729            y_range = d.GetYRange() 
     730            if x_range is not None and y_range is not None: 
     731                self.subplot.set_xlim(x_range) 
     732                self.subplot.set_ylim(y_range) 
     733                self.subplot.figure.canvas.draw_idle() 
     734        d.Destroy() 
     735 
    712736    def onFreeze(self, event): 
    713737        """ 
     
    796820                                                             int(curr_symbol))), curr_label) 
    797821        self.appD.Bind(wx.EVT_CLOSE, self.on_AppDialog_close) 
     822        self.graph.selected_plottable = None 
    798823 
    799824    def on_AppDialog_close(self, event): 
  • src/sas/sasgui/guiframe/media/data_explorer_help.rst

    rd85c194 rb64b87c  
    2020 
    2121*NOTE! When* Data Explorer *is hidden, all data loaded will be sent directly  
    22 to the current active analysis perspective, if possible. When* Data Explorer *is 
     22to the current active analysis, if possible. When* Data Explorer *is 
    2323shown, data go first to the* Data Explorer. 
    2424 
     
    116116 
    117117Click on the *Send To* button to send the currently selected data to one of the 
    118 perspectives (for *Fitting*, *P(r) Inversion*, or *Invariant* calculation). 
     118available types of analysis (*Fitting*, *P(r) Inversion*, or *Invariant* calculation). 
    119119  
    120 The *Single*/*Batch* mode radio buttons only apply to the *Fitting* perspective. 
     120The *Single*/*Batch* mode radio buttons only apply to *Fitting*. 
    121121 
    122122*Batch mode* provides serial (batch) fitting with one model function, that is,  
  • src/sas/sasgui/guiframe/media/graph_help.rst

    rf93b473f re68c9bf  
    2020^^^^^^^^^^^^^^^^^^^^^^^ 
    2121 
    22 To invoke the *Graph Menu* simply right-click on a data/theory plot, or click  
    23 the *Graph Menu* (bullet list) icon in the toolbar at the bottom of the plot.  
     22To invoke the *Graph Menu* simply right-click on a data/theory plot, or click 
     23the *Graph Menu* (bullet list) icon in the toolbar at the bottom of the plot. 
    2424Then select a menu item. 
    2525 
     
    2727^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
    2828 
    29 To expand a plot window, click the *Maximise* (square) icon in the top-right  
     29To expand a plot window, click the *Maximise* (square) icon in the top-right 
    3030corner. 
    3131 
    32 To shrink a plot window, click the *Restore down* (square-on-square) icon in  
     32To shrink a plot window, click the *Restore down* (square-on-square) icon in 
    3333the top-right corner. 
    3434 
    35 To hide a plot, click the *Minimise* (-) icon in the top-right corner of the  
     35To hide a plot, click the *Minimise* (-) icon in the top-right corner of the 
    3636plot window. 
    3737 
    38 To show a hidden plot, select the *Restore up* (square-on-square) icon on the  
     38To show a hidden plot, select the *Restore up* (square-on-square) icon on the 
    3939minimised window. 
    4040 
    41 To delete a plot, click the *Close* (x) icon in the top-right corner of the  
     41To delete a plot, click the *Close* (x) icon in the top-right corner of the 
    4242plot window. 
    4343 
    44 *NOTE! If a residuals graph (when fitting data) is hidden, it will not show up  
     44*NOTE! If a residuals graph (when fitting data) is hidden, it will not show up 
    4545after computation.* 
    4646 
     
    4848^^^^^^^^^^^^^^^ 
    4949 
    50 Select the *Pan* (crossed arrows) icon in the toolbar at the bottom of the plot  
    51 to activate this option. Move the mouse pointer to the plot. It will change to  
    52 a hand. Then left-click and drag the plot around. The axis values will adjust  
     50Select the *Pan* (crossed arrows) icon in the toolbar at the bottom of the plot 
     51to activate this option. Move the mouse pointer to the plot. It will change to 
     52a hand. Then left-click and drag the plot around. The axis values will adjust 
    5353accordingly. 
    54   
     54 
    5555To disable dragging mode, unselect the *crossed arrows* icon on the toolbar. 
    5656 
     
    5858^^^^^^^^^^^^^^^^^^^^^^^^ 
    5959 
    60 Select the *Zoom* (magnifying glass) button in the toolbar at the bottom of  
    61 the plot to activate this option. Move the mouse pointer to the plot. It will  
    62 change to a cross-hair. Then left-click and drag the pointer around to generate  
     60Select the *Zoom* (magnifying glass) button in the toolbar at the bottom of 
     61the plot to activate this option. Move the mouse pointer to the plot. It will 
     62change to a cross-hair. Then left-click and drag the pointer around to generate 
    6363a region of interest. Release the mouse button to generate the new view. 
    6464 
    6565To disable zoom mode, unselect the *Zoom* button on the toolbar. 
    6666 
    67 After zooming in on a a region, the *left arrow* or *right arrow* buttons on  
     67After zooming in on a a region, the *left arrow* or *right arrow* buttons on 
    6868the toolbar will switch between recent views. 
    6969 
    70 *NOTE! If a wheel mouse is available scrolling the wheel will zoom in/out  
    71 on the current plot (changing both axes). Alternatively, point at the numbers  
     70*NOTE! If a wheel mouse is available scrolling the wheel will zoom in/out 
     71on the current plot (changing both axes). Alternatively, point at the numbers 
    7272on one axis and scroll the wheel to zoom in/out on just that axis.* 
    7373 
    74 To return to the original view of the data, click the the *Reset* (home) icon  
     74To return to the original view of the data, click the the *Reset* (home) icon 
    7575in the toolbar at the bottom of the plot (see Resetting_the_graph_ for further details). 
    7676 
     
    7878^^^^^^^^^^^^^^^^^^^ 
    7979 
    80 To save the current plot as an image file, right click on the plot to bring up  
     80To save the current plot as an image file, right click on the plot to bring up 
    8181the *Graph Menu* (see Invoking_the_graph_menu_) and select *Save Image*. 
    82 Alternatively, click on the *Save* (floppy disk) icon in the toolbar at the  
     82Alternatively, click on the *Save* (floppy disk) icon in the toolbar at the 
    8383bottom of the plot. 
    84   
    85 A dialog window will open. Select a folder, enter a filename, choose an output  
     84 
     85A dialog window will open. Select a folder, enter a filename, choose an output 
    8686image type, and click *Save*. 
    8787 
     
    9494*  PNG (portable network graphics) 
    9595*  PS (postscript) 
    96 *  RAW/RGBA (bitmap) 
     96*  RAW/RGBA (bitmap, stored as 935x635 pixels of depth 8) 
    9797*  SVG/SVGA (scalable vector graphics) 
    9898*  TIF/TIFF (tagged iamge file) 
     
    101101^^^^^^^^^^^^^^^ 
    102102 
    103 To send the current plot to a printer, click on the *Print* (printer) icon in  
     103To send the current plot to a printer, click on the *Print* (printer) icon in 
    104104the toolbar at the bottom of the plot. 
    105105 
     
    109109^^^^^^^^^^^^^^^^^^^ 
    110110 
    111 To reset the axis range of a graph to its initial values select *Reset Graph  
     111To reset the axis range of a graph to its initial values select *Reset Graph 
    112112Range* on the *Graph Menu* (see Invoking_the_graph_menu_). Alternatively, use 
    113113the *Reset* (home) icon in the toolbar at the bottom of the plot. 
     
    133133 
    134134From the *Graph Menu* (see Invoking_the_graph_menu_) select *Change Scale*. A 
    135 dialog window will appear in which it is possible to choose different  
     135dialog window will appear in which it is possible to choose different 
    136136transformations of the x (usually Q) or y (usually I(Q)) axes, including: 
    137137 
     
    139139*  y, 1/y, ln(y), y^2, y.(x^4), 1/sqrt(y), 
    140140*  log10(y), ln(y.x), ln(y.x^2), ln(y.x^4), log10(y.x^4) 
    141   
     141 
    142142A *View* option includes short-cuts to common SAS transformations, such as: 
    143143 
     
    148148*  Kratky 
    149149 
    150 For properly corrected and scaled data, these SAS transformations can be used  
    151 to estimate, for example, Rg, rod diameter, or SANS incoherent background  
     150For properly corrected and scaled data, these SAS transformations can be used 
     151to estimate, for example, Rg, rod diameter, or SANS incoherent background 
    152152levels, via a linear fit (see Making_a_linear_fit_). 
    153153 
     
    158158 
    159159From the *Graph Menu* (see Invoking_the_graph_menu_) select *Toggle Linear/Log 
    160 Scale* to switch between a linear to log intensity scale. The type of scale  
     160Scale* to switch between a linear to log intensity scale. The type of scale 
    161161selected is written alongside the colour scale. 
    162162 
     
    167167 
    168168From the *Graph Menu* (see Invoking_the_graph_menu_) select *2D Color Map* to 
    169 choose a different color scale for the image and/or change the maximum or  
     169choose a different color scale for the image and/or change the maximum or 
    170170minimum limits of the scale. 
    171171 
     
    173173^^^^^^^^^^^^^^^^^^^^^^^^ 
    174174 
    175 Clicking anywhere in the plot window will cause the current coordinates to be  
     175Clicking anywhere in the plot window will cause the current coordinates to be 
    176176displayed in the status bar at the very bottom-left of the SasView window. 
    177   
     177 
    178178.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 
    179179 
     
    193193 
    194194In the *Dataset Menu* (see Invoking_the_dataset_menu_), highlight a data set 
    195 and select *DataInfo* to bring up a data information dialog panel for that  
     195and select *DataInfo* to bring up a data information dialog panel for that 
    196196data set. 
    197197 
     
    200200 
    201201In the *Dataset Menu* (see Invoking_the_dataset_menu_), select *Save Points as 
    202 a File* (if 1D data) or *Save as a file(DAT)* (if 2D data). A save dialog will  
     202a File* (if 1D data) or *Save as a file(DAT)* (if 2D data). A save dialog will 
    203203appear. 
    204204 
    205 1D data can be saved in either ASCII text (.TXT) or CanSAS/SASXML (.XML)  
     2051D data can be saved in either ASCII text (.TXT) or CanSAS/SASXML (.XML) 
    206206formats (see :ref:`Formats`). 
    207207 
     
    216216 
    217217In the *Dataset Menu* (see Invoking_the_dataset_menu_), select *Linear Fit*. A 
    218 fitting dialog will appear. Set some initial parameters and data limits and  
    219 click *Fit*. The fitted parameter values are displayed and the resulting line  
    220 calculated from them is added to the plot.  
     218fitting dialog will appear. Set some initial parameters and data limits and 
     219click *Fit*. The fitted parameter values are displayed and the resulting line 
     220calculated from them is added to the plot. 
    221221 
    222222This option is most useful for performing simple Guinier, XS Guinier, and 
    223 Porod type analyses, for example, to estimate Rg, a rod diameter, or incoherent  
     223Porod type analyses, for example, to estimate Rg, a rod diameter, or incoherent 
    224224background level, respectively. 
    225225 
     
    240240 
    241241In the *Dataset Menu* (see Invoking_the_dataset_menu_), select *Show Error Bar* 
    242 or *Hide Error Bar* to switch between showing/hiding the errors associated  
    243 with the chosen dataset.  
     242or *Hide Error Bar* to switch between showing/hiding the errors associated 
     243with the chosen dataset. 
    244244 
    245245Modify plot properties 
     
    247247 
    248248In the *Dataset Menu* (see Invoking_the_dataset_menu_), select *Modify Plot 
    249 Property* to change the size, color, or shape of the displayed marker for the  
     249Property* to change the size, color, or shape of the displayed marker for the 
    250250chosen dataset, or to change the dataset label that appears on the plot. 
    251251 
     
    260260This feature is only available with 2D data. 
    261261 
    262 2D data averaging allows you to perform different types of averages on your  
    263 data. The region to be averaged is displayed in the plot window and its limits  
     2622D data averaging allows you to perform different types of averages on your 
     263data. The region to be averaged is displayed in the plot window and its limits 
    264264can be modified by dragging the boundaries around. 
    265265 
     
    277277*  Box averaging on Qy 
    278278 
    279 A 'slicer' will appear (except for *Perform Circular Average*) in the plot that  
    280 you can drag by clicking on a slicer's handle. When the handle is highlighted  
     279A 'slicer' will appear (except for *Perform Circular Average*) in the plot that 
     280you can drag by clicking on a slicer's handle. When the handle is highlighted 
    281281in red, it means that the slicer can move/change size. 
    282282 
    283 *NOTE! The slicer size will reset if you try to select a region greater than  
     283*NOTE! The slicer size will reset if you try to select a region greater than 
    284284the size of the data.* 
    285285 
    286 Alternatively, once a 'slicer' is active you can also select the region to  
    287 average by bringing back the *Dataset Menu* and selecting *Edit Slicer  
    288 Parameters*. A dialog window will appear in which you can enter values to  
     286Alternatively, once a 'slicer' is active you can also select the region to 
     287average by bringing back the *Dataset Menu* and selecting *Edit Slicer 
     288Parameters*. A dialog window will appear in which you can enter values to 
    289289define a region or select the number of points to plot (*nbins*). 
    290290 
    291 A separate plot window will also have appeared, displaying the requested  
     291A separate plot window will also have appeared, displaying the requested 
    292292average. 
    293293 
    294 *NOTE! The displayed average only updates when input focus is moved back to  
     294*NOTE! The displayed average only updates when input focus is moved back to 
    295295that window; ie, when the mouse pointer is moved onto that plot.* 
    296296 
    297 Selecting *Box Sum* automatically brings up the 'Slicer Parameters' dialog in  
     297Selecting *Box Sum* automatically brings up the 'Slicer Parameters' dialog in 
    298298order to display the average numerically, rather than graphically. 
    299299 
     
    303303^^^^^^^^^^^^^^^^^^^^^^^^^ 
    304304 
    305 This operation will perform an average in constant Q-rings around the (x,y)  
     305This operation will perform an average in constant Q-rings around the (x,y) 
    306306pixel location of the beam center. 
    307307 
     
    309309^^^^^^^^^^^^^^^^^^^^^^^ 
    310310 
    311 This operation is the same as 'Unmasked Circular Average' except that any  
     311This operation is the same as 'Unmasked Circular Average' except that any 
    312312masked region is excluded. 
    313313 
     
    317317This operation averages in constant Q-arcs. 
    318318 
    319 The width of the sector is specified in degrees (+/- |delta|\|phi|\) each side  
     319The width of the sector is specified in degrees (+/- |delta|\|phi|\) each side 
    320320of the central angle (|phi|\). 
    321321 
     
    323323^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
    324324 
    325 This operation performs an average between two Q-values centered on (0,0),  
     325This operation performs an average between two Q-values centered on (0,0), 
    326326and averaged over a specified number of pixels. 
    327327 
    328 The data is returned as a function of angle (|phi|\) in degrees with zero  
     328The data is returned as a function of angle (|phi|\) in degrees with zero 
    329329degrees at the 3 O'clock position. 
    330330 
     
    334334This operation performs a sum of counts in a 2D region of interest. 
    335335 
    336 When editing the slicer parameters, the user can enter the length and the width  
     336When editing the slicer parameters, the user can enter the length and the width 
    337337the rectangular slicer and the coordinates of the center of the rectangle. 
    338338 
     
    342342This operation computes an average I(Qx) for the region of interest. 
    343343 
    344 When editing the slicer parameters, the user can control the length and the  
    345 width the rectangular slicer. The averaged output is calculated from constant  
    346 bins with rectangular shape. The resultant Q values are nominal values, that  
     344When editing the slicer parameters, the user can control the length and the 
     345width the rectangular slicer. The averaged output is calculated from constant 
     346bins with rectangular shape. The resultant Q values are nominal values, that 
    347347is, the central value of each bin on the x-axis. 
    348348 
     
    352352This operation computes an average I(Qy) for the region of interest. 
    353353 
    354 When editing the slicer parameters, the user can control the length and the  
    355 width the rectangular slicer. The averaged output is calculated from constant  
    356 bins with rectangular shape. The resultant Q values are nominal values, that  
     354When editing the slicer parameters, the user can control the length and the 
     355width the rectangular slicer. The averaged output is calculated from constant 
     356bins with rectangular shape. The resultant Q values are nominal values, that 
    357357is, the central value of each bin on the x-axis. 
    358358 
  • src/sas/sasgui/perspectives/fitting/basepage.py

    r5213d22 re4c897b  
    29422942        """ 
    29432943 
    2944         _TreeLocation = "user/sasgui/perspectives/fitting/mag_help.html" 
     2944        _TreeLocation = "user/magnetism.html" 
    29452945        _doc_viewer = DocumentationWindow(self, wx.ID_ANY, _TreeLocation, "", 
    29462946                                          "Polarized Beam/Magnetc Help") 
  • src/sas/sasgui/perspectives/fitting/media/fitting_help.rst

    r20846be rb64b87c  
    1515 
    1616 
    17 Fitting Perspective 
    18 =================== 
     17Fitting 
     18======= 
    1919 
    2020.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 
     
    2424 
    2525To fit some data you must first load some data, activate one or more data sets, 
    26 send those data sets to the fitting perspective, and select a model to fit to 
    27 each data set. 
     26send those data sets to fitting, and select a model to fit to each data set. 
    2827 
    2928Instructions on how to load and activate data are in the section :ref:`Loading_data`. 
     
    331330This mode fits one data set. 
    332331 
    333 When data is sent to the fitting perspective it is plotted in a graph window as 
    334 markers. 
     332When data is sent to the fitting it is plotted in a graph window as markers. 
    335333 
    336334If a graph does not appear, or a graph window appears but is empty, then the data 
  • src/sas/sasgui/perspectives/fitting/media/pd_help.rst

    r7805458 rb64b87c  
    105105 
    106106The median value for the distribution will be the value given for the respective 
    107 size parameter in the *Fitting Perspective*, for example, radius = 60. 
     107size parameter in the *FitPage*, for example, radius = 60. 
    108108 
    109109The polydispersity is given by |sigma| 
     
    172172 
    173173SasView only uses these array values during the computation, therefore any mean 
    174 value of the parameter represented by *x* present in the *Fitting Perspective* 
     174value of the parameter represented by *x* present in the *FitPage* 
    175175will be ignored. 
    176176 
  • src/sas/sasgui/perspectives/invariant/media/invariant_help.rst

    r70305bd2 rb64b87c  
    44.. by S King, ISIS, during SasView CodeCamp-III in Feb 2015. 
    55 
    6 Invariant Calculation Perspective 
    7 ================================= 
     6Invariant Calculation 
     7===================== 
    88 
    99Description 
     
    4545.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 
    4646 
    47 Using the perspective 
    48 --------------------- 
     47Using invariant analysis 
     48------------------------ 
    4949 
    50501) Select *Invariant* from the *Analysis* menu on the SasView toolbar. 
     
    5353 
    54543) Select a dataset and use the *Send To* button on the *Data Explorer* to load  
    55    the dataset into the *Invariant* perspective. 
     55   the dataset into the *Invariant* panel. 
    5656 
    57 4) Use the *Customised Input* boxes on the *Invariant* perspective to subtract  
     574) Use the *Customised Input* boxes on the *Invariant* panel to subtract  
    5858   any background, specify the contrast (i.e. difference in SLDs - this must be  
    5959   specified for the eventual value of Q*\  to be on an absolute scale), or to  
     
    7373 
    74748) If the value of Q*\  calculated with the extrapolated regions is invalid, a  
    75    red warning will appear at the top of the *Invariant* perspective panel. 
     75   red warning will appear at the top of the *Invariant* panel. 
    7676 
    7777   The details of the calculation are available by clicking the *Details*  
  • src/sas/sasgui/perspectives/pr/media/pr_help.rst

    r7805458 rb64b87c  
    44.. by S King, ISIS, during SasView CodeCamp-III in Feb 2015. 
    55 
    6 P(r) Inversion Perspective 
    7 ========================== 
     6P(r) Calculation 
     7================ 
    88 
    99Description 
     
    3232.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 
    3333 
    34 Using the perspective 
    35 --------------------- 
     34Using P(r) inversion 
     35-------------------- 
    3636 
    3737The user must enter 
  • src/sas/sasgui/plottools/PlotPanel.py

    r1ed6be7 r1a8e2e8e  
    1515import os 
    1616import transform 
    17 from plottables import Data1D 
    1817#TODO: make the plottables interactive 
    1918from binder import BindArtist 
     
    151150        #List of texts currently on the plot 
    152151        self.textList = [] 
     152        self.selectedText = None 
    153153        #User scale 
    154154        if xtransform != None: 
     
    190190 
    191191        # new data for the fit 
     192        from sas.sasgui.guiframe.dataFitting import Data1D 
    192193        self.fit_result = Data1D(x=[], y=[], dy=None) 
    193194        self.fit_result.symbol = 13 
     
    352353            self.leftdown = True 
    353354            ax = event.inaxes 
     355            for text in self.textList: 
     356                if text.contains(event)[0]: # If user has clicked on text 
     357                    self.selectedText = text 
     358                    return 
     359 
    354360            if ax != None: 
    355361                self.xInit, self.yInit = event.xdata, event.ydata 
     
    373379            self.mousemotion = False 
    374380            self.leftup = True 
     381            self.selectedText = None 
    375382 
    376383        #release the legend 
     
    448455            self._on_legend_motion(event) 
    449456            return 
     457 
     458        if self.leftdown and self.selectedText is not None: 
     459            # User has clicked on text and is dragging 
     460            ax = event.inaxes 
     461            if ax != None: 
     462                # Only move text if mouse is within axes 
     463                self.selectedText.set_position((event.xdata, event.ydata)) 
     464                self._dragHelper(0, 0) 
     465            else: 
     466                # User has dragged outside of axes 
     467                self.selectedText = None 
     468            return 
     469 
    450470        if self.enable_toolbar: 
    451471            #Disable dragging without the toolbar to allow zooming with toolbar 
     
    646666                dlg.setFitRange(self.xminView, self.xmaxView, 
    647667                                self.xmin, self.xmax) 
     668            else: 
     669                xlim = self.subplot.get_xlim() 
     670                ylim = self.subplot.get_ylim() 
     671                dlg.setFitRange(xlim[0], xlim[1], ylim[0], ylim[1]) 
    648672            # It would be nice for this to NOT be modal (i.e. Show). 
    649673            # Not sure about other ramifications - for example 
     
    17251749        if remove_fit: 
    17261750            self.graph.delete(self.fit_result) 
     1751            if hasattr(self, 'plots'): 
     1752                if 'fit' in self.plots.keys(): 
     1753                    del self.plots['fit'] 
    17271754        self.ly = None 
    17281755        self.q_ctrl = None 
     
    17381765        _yscale = 'linear' 
    17391766        for item in list: 
     1767            if item.id == 'fit': 
     1768                continue 
    17401769            item.setLabel(self.xLabel, self.yLabel) 
    17411770            # control axis labels from the panel itself 
     
    18691898 
    18701899        """ 
     1900        xlim = self.subplot.get_xlim() 
     1901        ylim = self.subplot.get_ylim() 
     1902 
    18711903        # Saving value to redisplay in Fit Dialog when it is opened again 
    18721904        self.Avalue, self.Bvalue, self.ErrAvalue, \ 
     
    18921924        self.graph.render(self) 
    18931925        self._offset_graph() 
     1926        if hasattr(self, 'plots'): 
     1927            # Used by Plotter1D 
     1928            fit_id = 'fit' 
     1929            self.fit_result.id = fit_id 
     1930            self.fit_result.title = 'Fit' 
     1931            self.fit_result.name = 'Fit' 
     1932            self.plots[fit_id] = self.fit_result 
     1933        self.subplot.set_xlim(xlim) 
     1934        self.subplot.set_ylim(ylim) 
    18941935        self.subplot.figure.canvas.draw_idle() 
    18951936 
  • test/sasdataloader/test/utest_abs_reader.py

    rb699768 r5f26aa4  
    176176         
    177177        self.assertEqual(self.data.run[0], "1234") 
    178         self.assertEqual(self.data.meta_data['loader'], "CanSAS 1D") 
    179         self.assertEqual(len(self.data.errors), 0) 
     178        self.assertEqual(self.data.meta_data['loader'], "CanSAS XML 1D") 
    180179         
    181180        # Data 
     
    198197        self.assertEqual(self.data.sample.name, "my sample") 
    199198        self.assertEqual(self.data.sample.thickness_unit, 'mm') 
    200         self.assertEqual(self.data.sample.thickness, 1.03) 
    201          
    202         self.assertEqual(self.data.sample.transmission, 0.327) 
     199        self.assertAlmostEqual(self.data.sample.thickness, 1.03) 
     200         
     201        self.assertAlmostEqual(self.data.sample.transmission, 0.327) 
    203202         
    204203        self.assertEqual(self.data.sample.temperature_unit, 'C') 
     
    233232         
    234233        self.assertEqual(self.data.source.wavelength_max_unit, "nm") 
    235         self.assertEqual(self.data.source.wavelength_max, 1.0) 
     234        self.assertAlmostEqual(self.data.source.wavelength_max, 1.0) 
    236235        self.assertEqual(self.data.source.wavelength_min_unit, "nm") 
    237         self.assertEqual(self.data.source.wavelength_min, 0.22) 
     236        self.assertAlmostEqual(self.data.source.wavelength_min, 0.22) 
    238237        self.assertEqual(self.data.source.wavelength_spread_unit, "percent") 
    239238        self.assertEqual(self.data.source.wavelength_spread, 14.3) 
     
    248247            self.assertEqual(item.size_unit,'mm') 
    249248            self.assertEqual(item.distance_unit,'mm') 
    250              
     249 
    251250            if item.size.x==50 \ 
    252251                and item.distance==11000.0 \ 
     
    294293            self.assertTrue(item.date in ['04-Sep-2007 18:35:02', 
    295294                                          '03-SEP-2006 11:42:47']) 
     295            print item.term 
    296296            for t in item.term: 
    297297                if t['name']=="ABS:DSTAND" \ 
     
    345345        self.assertEqual(self.data.filename, filename) 
    346346        # The followed should not have been loaded 
    347         self.assertEqual(self.data.sample.thickness, 0.00103) 
     347        self.assertAlmostEqual(self.data.sample.thickness, 0.00103) 
    348348        # This one should 
    349         self.assertEqual(self.data.sample.transmission, 0.327) 
    350          
    351         self.assertEqual(self.data.meta_data['loader'], "CanSAS 1D") 
     349        self.assertAlmostEqual(self.data.sample.transmission, 0.327) 
     350         
     351        self.assertEqual(self.data.meta_data['loader'], "CanSAS XML 1D") 
    352352        print self.data.errors 
    353353        self.assertEqual(len(self.data.errors), 1) 
     
    385385 
    386386if __name__ == '__main__': 
    387     unittest.main(testRunner=unittest.TextTestRunner(verbosity=2)) 
     387    unittest.main() 
  • test/sasdataloader/test/utest_cansas.py

    r83b6408 r1686a333  
    9999        self.assertTrue(data.detector[1].name == "main-detector-bank") 
    100100        self.assertTrue(data.detector[0].distance == 575.0) 
    101         self.assertTrue(data.detector[1].distance == 4145.02) 
     101        self.assertAlmostEqual(data.detector[1].distance, 4145.02) 
    102102        self.assertTrue(data.process[0].name == "Mantid generated CanSAS1D XML") 
    103103        self.assertTrue(data.meta_data["xmlpreprocess"] != None) 
     
    176176        data = list[0] 
    177177        self.assertTrue(data.x.size == 2) 
    178         self.assertTrue(len(data.meta_data) == 3) 
     178        self.assertTrue(len(data.meta_data) == 2) 
    179179        self.assertTrue(len(data.errors) == 1) 
    180180        self.assertTrue(data.detector[0].distance_unit == "mm") 
Note: See TracChangeset for help on using the changeset viewer.