- Timestamp:
- Aug 19, 2016 11:02:55 AM (8 years ago)
- Branches:
- master, ESS_GUI, ESS_GUI_Docs, ESS_GUI_batch_fitting, ESS_GUI_bumps_abstraction, ESS_GUI_iss1116, ESS_GUI_iss879, ESS_GUI_iss959, ESS_GUI_opencl, ESS_GUI_ordering, ESS_GUI_sync_sascalc, costrafo411, magnetic_scatt, release-4.1.1, release-4.1.2, release-4.2.2, ticket-1009, ticket-1094-headless, ticket-1242-2d-resolution, ticket-1243, ticket-1249, ticket885, unittest-saveload
- Children:
- 6f343e3
- Parents:
- 32c5983 (diff), 45d7662 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent. - Location:
- src/sas
- Files:
-
- 17 added
- 1 deleted
- 15 edited
Legend:
- Unmodified
- Added
- Removed
-
TabularUnified src/sas/sascalc/dataloader/data_info.py ¶
rd72567e r45d7662 445 445 return len(self.name) == 0 and len(self.date) == 0 and len(self.description) == 0 \ 446 446 and len(self.term) == 0 and len(self.notes) == 0 447 447 448 448 def single_line_desc(self): 449 449 """ … … 451 451 """ 452 452 return "%s %s %s" % (self.name, self.date, self.description) 453 453 454 454 def __str__(self): 455 455 _str = "Process:\n" … … 1037 1037 _str += " Z-axis: %s\t[%s]\n" % (self._zaxis, self._zunit) 1038 1038 _str += " Length: %g \n" % (len(self.data)) 1039 _str += " Shape: (%d, %d)\n" % (len(self.y_bins), len(self.x_bins)) 1039 1040 return _str 1040 1041 … … 1220 1221 result.mask = numpy.append(self.mask, other.mask) 1221 1222 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) 1223 1224 if self.dqx_data is not None: 1224 1225 result.dqx_data = numpy.append(self.dqx_data, other.dqx_data) … … 1252 1253 final_dataset.yaxis(data._yaxis, data._yunit) 1253 1254 final_dataset.zaxis(data._zaxis, data._zunit) 1255 final_dataset.x_bins = data.x_bins 1256 final_dataset.y_bins = data.y_bins 1254 1257 else: 1255 1258 return_string = "Should Never Happen: _combine_data_info_with_plottable input is not a plottable1d or " + \ -
TabularUnified src/sas/sascalc/dataloader/readers/cansas_constants.py ¶
rd398285 r250fec92 27 27 return_me.current_level = self.CANSAS_FORMAT.get("SASentry") 28 28 # Defaults for variable and datatype 29 return_me.ns_variable = "{0}.meta_data[\"{2}\"] = \"{1}\""30 29 return_me.ns_datatype = "content" 31 30 return_me.ns_optional = True … … 38 37 return_me.current_level = \ 39 38 return_me.current_level.get("<any>", "") 40 cl_variable = return_me.current_level.get("variable", "")41 39 cl_datatype = return_me.current_level.get("storeas", "") 42 40 cl_units_optional = \ 43 return_me.current_level.get("units_ required", "")41 return_me.current_level.get("units_optional", "") 44 42 # Where are how to store the variable for the given 45 43 # namespace CANSAS_CONSTANTS tree is hierarchical, so 46 44 # is no value, inherit 47 return_me.ns_variable = cl_variable if cl_variable != "" \48 else return_me.ns_variable49 45 return_me.ns_datatype = cl_datatype if cl_datatype != "" \ 50 46 else return_me.ns_datatype … … 53 49 else return_me.ns_optional 54 50 except AttributeError: 55 return_me.ns_variable = "{0}.meta_data[\"{2}\"] = \"{1}\""56 51 return_me.ns_datatype = "content" 57 52 return_me.ns_optional = True … … 75 70 # The constants below hold information on where to store the CanSAS data 76 71 # 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" : {}, 96 80 "term" : SASPROCESS_TERM, 97 81 "SASprocessnote" : SASPROCESS_SASPROCESSNOTE, … … 99 83 }, 100 84 } 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", 122 98 "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", 130 103 "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", 138 108 "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", 146 113 "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" : {}}, 157 118 } 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"}}, 171 121 "children" : {"Q" : SASDATA_IDATA_Q, 172 122 "I" : SASDATA_IDATA_I, … … 180 130 } 181 131 } 182 SASDATA = {"attributes" : {"name" : { "variable" : META_DATA,}},132 SASDATA = {"attributes" : {"name" : {}}, 183 133 "variable" : None, 184 134 "children" : {"Idata" : SASDATA_IDATA, … … 186 136 } 187 137 } 188 SASTRANSSPEC_TDATA_LAMDBA = {" variable" : "{0}.wavelength.append({1})",138 SASTRANSSPEC_TDATA_LAMDBA = {"storeas" : "float", 189 139 "unit" : "wavelength_unit", 190 "attributes" : 191 {"unit" : 192 {"variable" : "{0}.wavelength_unit = \"{1}\"", 193 "storeas" : "content" 194 } 195 } 140 "attributes" : {"unit" : {"storeas" : "content"}} 196 141 } 197 SASTRANSSPEC_TDATA_T = {" variable" : "{0}.transmission.append({1})",142 SASTRANSSPEC_TDATA_T = {"storeas" : "float", 198 143 "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", 208 147 "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, 220 151 "T" : SASTRANSSPEC_TDATA_T, 221 152 "Tdev" : SASTRANSSPEC_TDATA_TDEV, … … 223 154 } 224 155 } 225 SASTRANSSPEC = {"variable" : None, 226 "children" : {"Tdata" : SASTRANSSPEC_TDATA, 156 SASTRANSSPEC = {"children" : {"Tdata" : SASTRANSSPEC_TDATA, 227 157 "<any>" : ANY, 228 158 }, 229 "attributes" : 230 {"name" : 231 {"variable" : "{0}.name = \"{1}\""}, 232 "timestamp" : 233 {"variable" : "{0}.timestamp = \"{1}\""}, 234 } 159 "attributes" : {"name" :{}, "timestamp" : {},} 235 160 } 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", 251 167 "storeas" : "float", 252 "attributes" : 253 {"unit" : 254 {"variable" : "{0}.sample.temperature_unit = \"{1}\"", 255 "storeas" : "content" 256 } 257 }, 168 "attributes" :{"unit" :{}}, 258 169 } 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", 266 172 "storeas" : "float", 267 173 "attributes" : SASSAMPLE_POS_ATTR 268 174 } 269 SASSAMPLE_POS_Y = {"variable" : "{0}.sample.position.y = {1}", 270 "unit" : "sample.position_unit", 175 SASSAMPLE_POS_Y = {"unit" : "position_unit", 271 176 "storeas" : "float", 272 177 "attributes" : SASSAMPLE_POS_ATTR 273 178 } 274 SASSAMPLE_POS_Z = {"variable" : "{0}.sample.position.z = {1}", 275 "unit" : "sample.position_unit", 179 SASSAMPLE_POS_Z = {"unit" : "position_unit", 276 180 "storeas" : "float", 277 181 "attributes" : SASSAMPLE_POS_ATTR 278 182 } 279 SASSAMPLE_POS = {"children" : {"variable" : None, 280 "x" : SASSAMPLE_POS_X, 183 SASSAMPLE_POS = {"children" : {"x" : SASSAMPLE_POS_X, 281 184 "y" : SASSAMPLE_POS_Y, 282 185 "z" : SASSAMPLE_POS_Z, 283 186 }, 284 187 } 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", 293 190 "storeas" : "float", 294 191 "attributes" : SASSAMPLE_ORIENT_ATTR 295 192 } 296 SASSAMPLE_ORIENT_PITCH = {"variable" : "{0}.sample.orientation.y = {1}", 297 "unit" : "sample.orientation_unit", 193 SASSAMPLE_ORIENT_PITCH = {"unit" : "orientation_unit", 298 194 "storeas" : "float", 299 195 "attributes" : SASSAMPLE_ORIENT_ATTR 300 196 } 301 SASSAMPLE_ORIENT_YAW = {"variable" : "{0}.sample.orientation.z = {1}", 302 "unit" : "sample.orientation_unit", 197 SASSAMPLE_ORIENT_YAW = {"unit" : "orientation_unit", 303 198 "storeas" : "float", 304 199 "attributes" : SASSAMPLE_ORIENT_ATTR 305 200 } 306 SASSAMPLE_ORIENT = {"variable" : None, 307 "children" : {"roll" : SASSAMPLE_ORIENT_ROLL, 201 SASSAMPLE_ORIENT = {"children" : {"roll" : SASSAMPLE_ORIENT_ROLL, 308 202 "pitch" : SASSAMPLE_ORIENT_PITCH, 309 203 "yaw" : SASSAMPLE_ORIENT_YAW, … … 311 205 } 312 206 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" : {}, 316 209 "thickness" : SASSAMPLE_THICK, 317 210 "transmission" : SASSAMPLE_TRANS, … … 319 212 "position" : SASSAMPLE_POS, 320 213 "orientation" : SASSAMPLE_ORIENT, 321 "details" : 322 {"variable" : 323 "{0}.sample.details.append(\"{1}\")"}, 214 "details" : {}, 324 215 "<any>" : ANY 325 216 }, 326 217 } 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", 333 220 "storeas" : "float", 334 221 "attributes" : SASINSTR_SRC_BEAMSIZE_ATTR 335 222 } 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", 338 224 "storeas" : "float", 339 225 "attributes" : SASINSTR_SRC_BEAMSIZE_ATTR 340 226 } 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", 343 228 "storeas" : "float", 344 229 "attributes" : SASINSTR_SRC_BEAMSIZE_ATTR 345 230 } 346 SASINSTR_SRC_BEAMSIZE = {"attributes" : 347 {"name" : {"variable" : 348 "{0}.source.beam_size_name = \"{1}\""}}, 349 "variable" : None, 231 SASINSTR_SRC_BEAMSIZE = {"attributes" : {"name" : {}}, 350 232 "children" : {"x" : SASINSTR_SRC_BEAMSIZE_X, 351 233 "y" : SASINSTR_SRC_BEAMSIZE_Y, … … 353 235 } 354 236 } 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" :{}, 363 240 } 364 241 } 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", 367 243 "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"},} 375 245 } 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", 378 247 "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"},} 386 249 } 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", 389 251 "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"},} 397 253 } 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" : {}, 404 256 "beam_size" : SASINSTR_SRC_BEAMSIZE, 405 "beam_shape" : 406 {"variable" : 407 "{0}.source.beam_shape = \"{1}\""}, 257 "beam_shape" : {}, 408 258 "wavelength" : SASINSTR_SRC_WL, 409 259 "wavelength_min" : SASINSTR_SRC_WL_MIN, … … 412 262 }, 413 263 } 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", 420 266 "storeas" : "float", 421 267 "attributes" : SASINSTR_COLL_APER_ATTR 422 268 } 423 SASINSTR_COLL_APER_Y = {"variable" : "{0}.size.y = {1}", 424 "unit" : "size_unit", 269 SASINSTR_COLL_APER_Y = {"unit" : "size_unit", 425 270 "storeas" : "float", 426 271 "attributes" : SASINSTR_COLL_APER_ATTR 427 272 } 428 SASINSTR_COLL_APER_Z = {"variable" : "{0}.size.z = {1}", 429 "unit" : "size_unit", 273 SASINSTR_COLL_APER_Z = {"unit" : "size_unit", 430 274 "storeas" : "float", 431 275 "attributes" : SASINSTR_COLL_APER_ATTR 432 276 } 433 SASINSTR_COLL_APER_SIZE = {"attributes" : 434 {"unit" : {"variable" : 435 "{0}.size_unit = \"{1}\""}}, 277 SASINSTR_COLL_APER_SIZE = {"attributes" : {"unit" : {}}, 436 278 "children" : {"storeas" : "float", 437 279 "x" : SASINSTR_COLL_APER_X, … … 441 283 } 442 284 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" : {}}, 449 286 "unit" : "distance_unit", 450 287 } 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" : {}, }, 457 289 "children" : {"size" : SASINSTR_COLL_APER_SIZE, 458 290 "distance" : SASINSTR_COLL_APER_DIST 459 291 } 460 292 } 461 SASINSTR_COLL = {"attributes" : 462 {"name" : {"variable" : "{0}.name = \"{1}\""}}, 463 "variable" : None, 293 SASINSTR_COLL = {"attributes" : {"name" : {}}, 464 294 "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 }, 476 302 } 477 SASINSTR_DET_SDD = {" variable" : "{0}.distance = {1}",303 SASINSTR_DET_SDD = {"storeas" : "float", 478 304 "unit" : "distance_unit", 479 "attributes" : 480 {"unit" : 481 {"variable" : "{0}.distance_unit = \"{1}\"", 482 "storeas" : "content" 483 } 484 }, 305 "attributes" : {"unit" :{}}, 485 306 } 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", 491 309 "unit" : "offset_unit", 492 310 "attributes" : SASINSTR_DET_OFF_ATTR 493 311 } 494 SASINSTR_DET_OFF_Y = {" variable" : "{0}.offset.y = {1}",312 SASINSTR_DET_OFF_Y = {"storeas" : "float", 495 313 "unit" : "offset_unit", 496 314 "attributes" : SASINSTR_DET_OFF_ATTR 497 315 } 498 SASINSTR_DET_OFF_Z = {" variable" : "{0}.offset.z = {1}",316 SASINSTR_DET_OFF_Z = {"storeas" : "float", 499 317 "unit" : "offset_unit", 500 318 "attributes" : SASINSTR_DET_OFF_ATTR 501 319 } 502 SASINSTR_DET_OFF = {"variable" : None, 503 "children" : {"x" : SASINSTR_DET_OFF_X, 320 SASINSTR_DET_OFF = {"children" : {"x" : SASINSTR_DET_OFF_X, 504 321 "y" : SASINSTR_DET_OFF_Y, 505 322 "z" : SASINSTR_DET_OFF_Z, 506 323 } 507 324 } 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", 512 327 "unit" : "orientation_unit", 513 328 "attributes" : SASINSTR_DET_OR_ATTR 514 329 } 515 SASINSTR_DET_OR_PITCH = {" variable" : "{0}.orientation.y = {1}",330 SASINSTR_DET_OR_PITCH = {"storeas" : "float", 516 331 "unit" : "orientation_unit", 517 332 "attributes" : SASINSTR_DET_OR_ATTR 518 333 } 519 SASINSTR_DET_OR_YAW = {" variable" : "{0}.orientation.z = {1}",334 SASINSTR_DET_OR_YAW = {"storeas" : "float", 520 335 "unit" : "orientation_unit", 521 336 "attributes" : SASINSTR_DET_OR_ATTR 522 337 } 523 SASINSTR_DET_OR = {"variable" : None, 524 "children" : {"roll" : SASINSTR_DET_OR_ROLL, 338 SASINSTR_DET_OR = {"children" : {"roll" : SASINSTR_DET_OR_ROLL, 525 339 "pitch" : SASINSTR_DET_OR_PITCH, 526 340 "yaw" : SASINSTR_DET_OR_YAW, 527 341 } 528 342 } 529 SASINSTR_DET_BC_X = {" variable" : "{0}.beam_center.x = {1}",343 SASINSTR_DET_BC_X = {"storeas" : "float", 530 344 "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", 537 348 "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", 544 352 "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, 552 356 "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", 557 360 "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", 564 364 "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", 571 368 "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, 579 372 "y" : SASINSTR_DET_PIXEL_Y, 580 373 "z" : SASINSTR_DET_PIXEL_Z, 581 374 } 582 375 } 583 SASINSTR_DET_SLIT = {" variable" : "{0}.slit_length = {1}",376 SASINSTR_DET_SLIT = {"storeas" : "float", 584 377 "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"}, 602 382 "SDD" : SASINSTR_DET_SDD, 603 383 "offset" : SASINSTR_DET_OFF, … … 608 388 } 609 389 } 610 SASINSTR = {"variable" : None, 611 "children" : 612 {"variable" : None, 613 "name" : {"variable" : "{0}.instrument = \"{1}\""}, 390 SASINSTR = {"children" : 391 {"name" : {}, 614 392 "SASsource" : SASINSTR_SRC, 615 393 "SAScollimation" : SASINSTR_COLL, … … 619 397 CANSAS_FORMAT = {"SASentry" : 620 398 {"units_optional" : True, 621 "variable" : None,622 399 "storeas" : "content", 623 "attributes" : {"name" : 624 {"variable" : 625 "{0}.run_name[\"{3}\"] = \"{1}\""}}, 400 "attributes" : {"name" : {}}, 626 401 "children" : {"Title" : TITLE, 627 402 "Run" : RUN, … … 644 419 645 420 current_level = '' 646 ns_variable = ''647 421 ns_datatype = '' 648 422 ns_optional = True … … 650 424 def __init__(self): 651 425 self.current_level = {} 652 self.ns_variable = ''653 426 self.ns_datatype = "content" 654 427 self.ns_optional = True -
TabularUnified src/sas/sascalc/dataloader/readers/cansas_reader.py ¶
r83b6408 r5f26aa4 14 14 15 15 import logging 16 import numpy 16 import numpy as np 17 17 import os 18 18 import sys … … 20 20 import inspect 21 21 # 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 22 from sas.sascalc.dataloader.data_info import Data1D, DataInfo, plottable_1D 23 from sas.sascalc.dataloader.data_info import Collimation, TransmissionSpectrum, Detector, Process, Aperture 24 from sas.sascalc.dataloader.data_info import combine_data_info_with_plottable as combine_data 28 25 import sas.sascalc.dataloader.readers.xml_reader as xml_reader 29 26 from sas.sascalc.dataloader.readers.xml_reader import XMLreader 30 from sas.sascalc.dataloader.readers.cansas_constants import CansasConstants 27 from sas.sascalc.dataloader.readers.cansas_constants import CansasConstants, CurrentLevel 31 28 32 29 # The following 2 imports *ARE* used. Do not remove either. … … 34 31 from xml.dom.minidom import parseString 35 32 36 ## TODO: Refactor to load multiple <SASData> as separate Data1D objects37 ## TODO: Refactor to allow invalid XML, but give a useful warning when loaded38 39 _ZERO = 1e-1640 33 PREPROCESS = "xmlpreprocess" 41 34 ENCODING = "encoding" 42 35 RUN_NAME_DEFAULT = "None" 36 INVALID_SCHEMA_PATH_1_1 = "{0}/sas/sascalc/dataloader/readers/schema/cansas1d_invalid_v1_1.xsd" 37 INVALID_SCHEMA_PATH_1_0 = "{0}/sas/sascalc/dataloader/readers/schema/cansas1d_invalid_v1_0.xsd" 38 INVALID_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" 43 40 HAS_CONVERTER = True 44 41 try: … … 52 49 ALLOW_ALL = True 53 50 54 # DO NOT REMOVE Called by outside packages:55 # sas.sasgui.perspectives.invariant.invariant_state56 # sas.sasgui.perspectives.fitting.pagestate57 def get_content(location, node):58 """59 Get the first instance of the content of a xpath location.60 61 :param location: xpath location62 :param node: node to start at63 64 :return: Element, or None65 """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 None72 73 # DO NOT REMOVE Called by outside packages:74 # sas.sasgui.perspectives.fitting.pagestate75 def write_node(doc, parent, name, value, attr=None):76 """77 :param doc: document DOM78 :param parent: parent node79 :param name: tag of the element80 :param value: value of the child text node81 :param attr: attribute dictionary82 83 :return: True if something was appended, otherwise False84 """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 True94 return False95 96 51 class Reader(XMLreader): 97 52 """ … … 101 56 The CanSAS reader requires PyXML 0.8.4 or later. 102 57 """ 103 ## CanSAS version - defaults to version 1.058 ## CanSAS version - defaults to version 1.0 104 59 cansas_version = "1.0" 105 60 base_ns = "{cansas1d/1.0}" 61 cansas_defaults = None 62 type_name = "canSAS" 63 invalid = True 64 ## Log messages and errors 106 65 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 109 77 ## Wildcards 110 78 type = ["XML files (*.xml)|*.xml", "SasView Save Files (*.svs)|*.svs"] … … 114 82 allow_all = True 115 83 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 119 102 self.logging = [] 120 103 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 121 464 122 465 def is_cansas(self, ext="xml"): … … 134 477 if ext == "svs": 135 478 return True 136 r eturn False479 raise RuntimeError 137 480 138 481 def load_file_and_schema(self, xml_file, schema_path=""): 139 482 """ 140 Loads the file and associates a schema, if a known schemaexists483 Loads the file and associates a schema, if a schema is passed in or if one already exists 141 484 142 485 :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 143 487 """ 144 488 base_name = xml_reader.__file__ … … 151 495 152 496 # 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") 154 498 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("\\", "/") 157 501 158 502 # Link a schema to the XML file. 159 503 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): 248 559 """ 249 560 Final cleanup of the Data1D object to be sure it has all the 250 561 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() 256 566 for error in self.errors: 257 data1d.errors.append(error)567 self.current_datainfo.errors.add(error) 258 568 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) 279 600 280 601 def _create_unique_key(self, dictionary, name, numb=0): 281 602 """ 282 603 Create a unique key value for any dictionary to prevent overwriting 283 Recurse suntil a unique key value is found.604 Recurse until a unique key value is found. 284 605 285 606 :param dictionary: A dictionary with any number of entries … … 294 615 return name 295 616 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): 298 654 """ 299 655 A unit converter method used to convert the data included in the file 300 656 to the default units listed in data_info 301 657 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 306 660 :param node_value: The value of the current dom node 307 661 """ … … 310 664 err_msg = None 311 665 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: 313 669 try: 314 670 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() \ 321 695 and local_unit.lower() != "none": 322 696 if HAS_CONVERTER == True: … … 345 719 if err_msg: 346 720 self.errors.add(err_msg) 347 node_value = "float({0})".format(node_value)348 721 return node_value, value_unit 349 722 350 def _check_for_empty_data(self , data1d):723 def _check_for_empty_data(self): 351 724 """ 352 725 Creates an empty data set if no data is passed to the reader … … 354 727 :param data1d: presumably a Data1D object 355 728 """ 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): 403 741 """ 404 742 A method to check all resolution data sets are the same size as I and Q … … 408 746 dq_exists = False 409 747 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() 1029 789 1030 790 def _to_xml_doc(self, datainfo): … … 1095 855 return False 1096 856 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 1113 1257 1114 1258 # DO NOT REMOVE - used in saving and loading panel states. … … 1195 1339 if entry is not None and entry.text is not None: 1196 1340 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 1346 def 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 1364 def 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 -
TabularUnified src/sas/sascalc/dataloader/readers/cansas_reader_HDF5.py ¶
rd72567e r479799c 62 62 :return: List of Data1D/2D objects and/or a list of errors. 63 63 """ 64 65 64 ## Reinitialize the class when loading a new data file to reset all class variables 66 65 self.reset_class_variables() … … 136 135 ## If this is a dataset, store the data appropriately 137 136 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 138 178 139 179 for data_point in data_set: 140 180 ## Top Level Meta Data 141 unit = self._get_unit(value)142 181 if key == u'definition': 143 182 self.current_datainfo.meta_data['reader'] = data_point … … 148 187 elif key == u'SASnote': 149 188 self.current_datainfo.notes.append(data_point) 150 151 ## I and Q Data152 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)182 189 183 190 ## Sample Information … … 296 303 ## Type cast data arrays to float64 and find min/max as appropriate 297 304 for dataset in self.data2d: 298 dataset.data = np.delete(dataset.data, [0])299 305 dataset.data = dataset.data.astype(np.float64) 300 dataset.err_data = np.delete(dataset.err_data, [0])301 306 dataset.err_data = dataset.err_data.astype(np.float64) 302 dataset.mask = np.delete(dataset.mask, [0])303 307 if dataset.qx_data is not None: 304 dataset.qx_data = np.delete(dataset.qx_data, [0])305 308 dataset.xmin = np.min(dataset.qx_data) 306 309 dataset.xmax = np.max(dataset.qx_data) 307 310 dataset.qx_data = dataset.qx_data.astype(np.float64) 308 311 if dataset.dqx_data is not None: 309 dataset.dqx_data = np.delete(dataset.dqx_data, [0])310 312 dataset.dqx_data = dataset.dqx_data.astype(np.float64) 311 313 if dataset.qy_data is not None: 312 dataset.qy_data = np.delete(dataset.qy_data, [0])313 314 dataset.ymin = np.min(dataset.qy_data) 314 315 dataset.ymax = np.max(dataset.qy_data) 315 316 dataset.qy_data = dataset.qy_data.astype(np.float64) 316 317 if dataset.dqy_data is not None: 317 dataset.dqy_data = np.delete(dataset.dqy_data, [0])318 318 dataset.dqy_data = dataset.dqy_data.astype(np.float64) 319 319 if dataset.q_data is not None: 320 dataset.q_data = np.delete(dataset.q_data, [0])321 320 dataset.q_data = dataset.q_data.astype(np.float64) 322 321 zeros = np.ones(dataset.data.size, dtype=bool) … … 333 332 except: 334 333 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 335 341 final_dataset = combine_data_info_with_plottable(dataset, self.current_datainfo) 336 342 self.output.append(final_dataset) … … 338 344 for dataset in self.data1d: 339 345 if dataset.x is not None: 340 dataset.x = np.delete(dataset.x, [0])341 346 dataset.x = dataset.x.astype(np.float64) 342 347 dataset.xmin = np.min(dataset.x) 343 348 dataset.xmax = np.max(dataset.x) 344 349 if dataset.y is not None: 345 dataset.y = np.delete(dataset.y, [0])346 350 dataset.y = dataset.y.astype(np.float64) 347 351 dataset.ymin = np.min(dataset.y) 348 352 dataset.ymax = np.max(dataset.y) 349 353 if dataset.dx is not None: 350 dataset.dx = np.delete(dataset.dx, [0])351 354 dataset.dx = dataset.dx.astype(np.float64) 352 355 if dataset.dxl is not None: 353 dataset.dxl = np.delete(dataset.dxl, [0])354 356 dataset.dxl = dataset.dxl.astype(np.float64) 355 357 if dataset.dxw is not None: 356 dataset.dxw = np.delete(dataset.dxw, [0])357 358 dataset.dxw = dataset.dxw.astype(np.float64) 358 359 if dataset.dy is not None: 359 dataset.dy = np.delete(dataset.dy, [0])360 360 dataset.dy = dataset.dy.astype(np.float64) 361 361 final_dataset = combine_data_info_with_plottable(dataset, self.current_datainfo) -
TabularUnified src/sas/sasgui/guiframe/data_panel.py ¶
rb5c44f0 re767897 2 2 #This software was developed by the University of Tennessee as part of the 3 3 #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. 5 5 # 6 6 #See the license text in license.txt … … 41 41 as QucikPlotDialog 42 42 import sas.sasgui.guiframe.config as config 43 43 44 44 extension_list = [] 45 45 if config.APPLICATION_STATE_EXTENSION is not None: 46 46 extension_list.append(config.APPLICATION_STATE_EXTENSION) 47 EXTENSIONS = config.PLUGIN_STATE_EXTENSIONS + extension_list 47 EXTENSIONS = config.PLUGIN_STATE_EXTENSIONS + extension_list 48 48 PLUGINS_WLIST = config.PLUGINS_WLIST 49 49 APPLICATION_WLIST = config.APPLICATION_WLIST 50 50 51 #Control panel width 51 #Control panel width 52 52 if sys.platform.count("win32") > 0: 53 53 PANEL_WIDTH = 235 … … 67 67 STYLE_FLAG = wx.RAISED_BORDER|CT.TR_HAS_BUTTONS| CT.TR_HIDE_ROOT|\ 68 68 wx.WANTS_CHARS|CT.TR_HAS_VARIABLE_ROW_HEIGHT 69 70 69 70 71 71 class DataTreeCtrl(CT.CustomTreeCtrl): 72 72 """ … … 97 97 CT.CustomTreeCtrl.__init__(self, parent, *args, **kwds) 98 98 self.root = self.AddRoot("Available Data") 99 99 100 100 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. 104 104 """ 105 105 # Get the item data … … 113 113 else: 114 114 return 0 115 115 116 116 class DataPanel(ScrolledPanel, PanelBase): 117 117 """ 118 This panel displays data available in the application and widgets to 118 This panel displays data available in the application and widgets to 119 119 interact with data. 120 120 """ … … 123 123 ## Title to appear on top of the window 124 124 window_caption = "Data Explorer" 125 #type of window 125 #type of window 126 126 window_type = "Data Panel" 127 127 ## Flag to tell the GUI manager that this panel is not 128 128 # tied to any perspective 129 129 #ALWAYS_ON = True 130 def __init__(self, parent, 130 def __init__(self, parent, 131 131 list=None, 132 132 size=(PANEL_WIDTH, PANEL_HEIGHT), … … 138 138 PanelBase.__init__(self, parent) 139 139 self.SetupScrolling() 140 #Set window's font size 140 #Set window's font size 141 141 self.SetWindowVariant(variant=FONT_VARIANT) 142 self.loader = Loader() 142 self.loader = Loader() 143 143 #Default location 144 self._default_save_location = None 144 self._default_save_location = None 145 145 self.all_data1d = True 146 146 self.parent = parent.parent … … 188 188 if self.parent is not None: 189 189 self.parent.Bind(EVT_DELETE_PLOTPANEL, self._on_delete_plot_panel) 190 190 191 191 def do_layout(self): 192 192 """ … … 198 198 self.layout_batch() 199 199 self.layout_button() 200 200 201 201 def disable_app_combo(self, enable): 202 202 """ … … 204 204 """ 205 205 self.perspective_cbox.Enable(enable) 206 206 207 207 def define_panel_structure(self): 208 208 """ … … 213 213 self.sizer1 = wx.BoxSizer(wx.VERTICAL) 214 214 self.sizer1.SetMinSize(wx.Size(w/13, h*2/5)) 215 215 216 216 self.sizer2 = wx.BoxSizer(wx.VERTICAL) 217 217 self.sizer3 = wx.FlexGridSizer(9, 2, 4, 1) 218 218 self.sizer4 = wx.BoxSizer(wx.VERTICAL) 219 219 self.sizer5 = wx.BoxSizer(wx.VERTICAL) 220 220 221 221 self.vbox.Add(self.sizer5, 0, wx.EXPAND|wx.ALL, 1) 222 222 self.vbox.Add(self.sizer1, 1, wx.EXPAND|wx.ALL, 0) … … 224 224 self.vbox.Add(self.sizer3, 0, wx.EXPAND|wx.ALL, 10) 225 225 #self.vbox.Add(self.sizer4, 0, wx.EXPAND|wx.ALL,5) 226 226 227 227 self.SetSizer(self.vbox) 228 228 229 229 def layout_selection(self): 230 230 """ … … 244 244 self.selection_cbox.SetValue('Select all Data') 245 245 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), 247 247 (self.selection_cbox, 0, wx.ALL,5)]) 248 248 self.enable_selection() 249 250 249 250 251 251 def _on_selection_type(self, event): 252 252 """ … … 254 254 :param event: UI event 255 255 """ 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 256 266 option = self.selection_cbox.GetValue() 257 267 258 268 pos = self.selection_cbox.GetSelection() 259 269 if pos == wx.NOT_FOUND: 260 return 270 return 261 271 option = self.selection_cbox.GetString(pos) 262 272 for item in self.list_cb_data.values(): 263 273 data_ctrl, _, _, _, _, _, _, _ = item 264 _, data_class, _ = self.tree_ctrl.GetItemPyData(data_ctrl) 274 _, data_class, _ = self.tree_ctrl.GetItemPyData(data_ctrl) 265 275 if option == 'Select all Data': 266 self.tree_ctrl.CheckItem(data_ctrl, True)276 check_item_and_children(data_ctrl, check_value=True) 267 277 elif option == 'Unselect all Data': 268 self.tree_ctrl.CheckItem(data_ctrl,False)278 check_item_and_children(data_ctrl, check_value=False) 269 279 elif option == 'Select all Data 1D': 270 280 if data_class == 'Data1D': 271 self.tree_ctrl.CheckItem(data_ctrl, True)281 check_item_and_children(data_ctrl, check_value=True) 272 282 elif option == 'Unselect all Data 1D': 273 283 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) 278 285 elif option == 'Select all Data 2D': 279 286 if data_class == 'Data2D': 280 self.tree_ctrl.CheckItem(data_ctrl, True)287 check_item_and_children(data_ctrl, check_value=True) 281 288 elif option == 'Unselect all Data 2D': 282 289 if data_class == 'Data2D': 283 self.tree_ctrl.CheckItem(data_ctrl, False)290 check_item_and_children(data_ctrl, check_value=False) 284 291 self.enable_append() 285 292 self.enable_freeze() … … 287 294 self.enable_import() 288 295 self.enable_remove() 289 296 290 297 def layout_button(self): 291 298 """ … … 293 300 """ 294 301 #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", 296 303 size=(BUTTON_WIDTH, -1)) 297 304 self.bt_add.SetToolTipString("Load data files") 298 305 wx.EVT_BUTTON(self, self.bt_add.GetId(), self._load_data) 299 306 300 307 #Delete Data Button 301 308 self.bt_remove = wx.Button(self, wx.NewId(), "Delete Data", … … 303 310 self.bt_remove.SetToolTipString("Delete data from the application") 304 311 wx.EVT_BUTTON(self, self.bt_remove.GetId(), self.on_remove) 305 312 306 313 #Send data to perspective button 307 314 self.bt_import = wx.Button(self, wx.NewId(), "Send To", … … 309 316 self.bt_import.SetToolTipString("Send Data set to active perspective") 310 317 wx.EVT_BUTTON(self, self.bt_import.GetId(), self.on_import) 311 318 312 319 #Choose perspective to be send data to combo box 313 320 self.perspective_cbox = wx.ComboBox(self, -1, … … 315 322 if not IS_MAC: 316 323 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, 318 325 self._on_perspective_selection) 319 326 320 327 #Append data to current Graph Button 321 328 self.bt_append_plot = wx.Button(self, wx.NewId(), "Append Plot To", … … 324 331 "Plot the selected data in the active panel") 325 332 wx.EVT_BUTTON(self, self.bt_append_plot.GetId(), self.on_append_plot) 326 333 327 334 #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", 329 336 size=(BUTTON_WIDTH, -1)) 330 337 self.bt_plot.SetToolTipString("To trigger plotting") 331 338 wx.EVT_BUTTON(self, self.bt_plot.GetId(), self.on_plot) 332 339 333 340 #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", 335 342 size=(BUTTON_WIDTH, -1)) 336 343 freeze_tip = "To trigger freeze a theory: making a copy\n" … … 339 346 self.bt_freeze.SetToolTipString(freeze_tip) 340 347 wx.EVT_BUTTON(self, self.bt_freeze.GetId(), self.on_freeze) 341 348 342 349 #select plot to send to combo box (blank if no data) 343 350 if sys.platform == 'darwin': 344 self.cb_plotpanel = wx.ComboBox(self, -1, 351 self.cb_plotpanel = wx.ComboBox(self, -1, 345 352 style=wx.CB_READONLY) 346 353 else: 347 self.cb_plotpanel = wx.ComboBox(self, -1, 354 self.cb_plotpanel = wx.ComboBox(self, -1, 348 355 style=wx.CB_READONLY|wx.CB_SORT) 349 356 wx.EVT_COMBOBOX(self.cb_plotpanel, -1, self._on_plot_selection) 350 357 self.cb_plotpanel.Disable() 351 358 352 359 #Help button 353 360 self.bt_help = wx.Button(self, wx.NewId(), "HELP", … … 365 372 ((10, 10)), 366 373 (self.bt_append_plot), 367 (self.cb_plotpanel, 374 (self.cb_plotpanel, 368 375 wx.EXPAND|wx.ADJUST_MINSIZE, 5), 369 376 ((5, 5)), 370 377 ((5, 5)), 371 378 (self.bt_import, 0, wx.EXPAND|wx.RIGHT, 5), 372 (self.perspective_cbox, 379 (self.perspective_cbox, 373 380 wx.EXPAND|wx.ADJUST_MINSIZE, 5), 374 381 ((10, 10)), … … 385 392 self.enable_freeze() 386 393 self.enable_remove_plot() 387 394 388 395 def layout_batch(self): 389 396 """ … … 397 404 self.Bind(wx.EVT_RADIOBUTTON, self.on_batch_mode, 398 405 id=self.rb_batch_mode.GetId()) 399 406 400 407 self.rb_single_mode.SetValue(not self.parent.batch_on) 401 408 self.rb_batch_mode.SetValue(self.parent.batch_on) 402 409 self.sizer4.AddMany([(self.rb_single_mode, 0, wx.ALL, 4), 403 410 (self.rb_batch_mode, 0, wx.ALL, 4)]) 404 411 405 412 def on_single_mode(self, event): 406 413 """ … … 410 417 if self.parent is not None: 411 418 wx.PostEvent(self.parent, NewBatchEvent(enable=False)) 412 419 413 420 def on_batch_mode(self, event): 414 421 """ … … 417 424 """ 418 425 if self.parent is not None: 419 wx.PostEvent(self.parent, 426 wx.PostEvent(self.parent, 420 427 NewBatchEvent(enable=True)) 421 422 def _get_data_selection(self, event): 428 429 def _get_data_selection(self, event): 423 430 """ 424 431 Get data selection from the right click … … 435 442 data = theory_list.values()[0][0] 436 443 return data 437 444 438 445 def on_edit_data(self, event): 439 446 """ … … 443 450 from sas.sasgui.guiframe.local_perspectives.plotting.masking \ 444 451 import MaskPanel as MaskDialog 445 446 panel = MaskDialog(parent=self.parent, base=self, 452 453 panel = MaskDialog(parent=self.parent, base=self, 447 454 data=data, id=wx.NewId()) 448 455 panel.ShowModal() 449 456 450 457 def on_plot_3d(self, event): 451 458 """ … … 455 462 from sas.sasgui.guiframe.local_perspectives.plotting.masking \ 456 463 import FloatPanel as Float3dDialog 457 458 panel = Float3dDialog(base=self, data=data, 464 465 panel = Float3dDialog(base=self, data=data, 459 466 dimension=3, id=wx.NewId()) 460 panel.ShowModal() 461 467 panel.ShowModal() 468 462 469 def on_quick_plot(self, event): 463 470 """ … … 468 475 dimension = 2 469 476 else: 470 dimension = 1 471 #panel = QucikPlotDialog(base=self, data=data, 477 dimension = 1 478 #panel = QucikPlotDialog(base=self, data=data, 472 479 # dimension=dimension, id=wx.NewId()) 473 480 frame = QucikPlotDialog(self, -1, "Plot " + data.name, 'log_{10}') … … 477 484 frame.Show(True) 478 485 frame.SetFocus() 479 #panel.ShowModal() 480 486 #panel.ShowModal() 487 481 488 def on_data_info(self, event): 482 489 """ … … 488 495 else: 489 496 self.parent.show_data1d(data, data.name) 490 497 491 498 def on_save_as(self, event): 492 499 """ … … 506 513 else: 507 514 print "unable to save this type of data" 508 515 509 516 def layout_data_list(self): 510 517 """ … … 523 530 self.data_menu.Append(id, name, msg) 524 531 wx.EVT_MENU(self, id, self.on_data_info) 525 532 526 533 id = wx.NewId() 527 534 name = "Save As" … … 529 536 self.data_menu.Append(id, name, msg) 530 537 wx.EVT_MENU(self, id, self.on_save_as) 531 538 532 539 quickplot_id = wx.NewId() 533 540 name = "Quick Plot" … … 535 542 self.data_menu.Append(quickplot_id, name, msg) 536 543 wx.EVT_MENU(self, quickplot_id, self.on_quick_plot) 537 544 538 545 self.plot3d_id = wx.NewId() 539 546 name = "Quick 3DPlot (Slow)" … … 541 548 self.data_menu.Append(self.plot3d_id, name, msg) 542 549 wx.EVT_MENU(self, self.plot3d_id, self.on_plot_3d) 543 550 544 551 self.editmask_id = wx.NewId() 545 552 name = "Edit Mask" … … 547 554 self.data_menu.Append(self.editmask_id, name, msg) 548 555 wx.EVT_MENU(self, self.editmask_id, self.on_edit_data) 549 556 550 557 tree_ctrl_theory_label = wx.StaticText(self, -1, "Theory") 551 558 tree_ctrl_theory_label.SetForegroundColour('blue') 552 self.tree_ctrl_theory = DataTreeCtrl(parent=self, 559 self.tree_ctrl_theory = DataTreeCtrl(parent=self, 553 560 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, 555 562 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, 557 564 self.on_right_click_theory) 558 565 self.sizer1.Add(tree_ctrl_label, 0, wx.LEFT, 10) … … 560 567 self.sizer1.Add(tree_ctrl_theory_label, 0, wx.LEFT, 10) 561 568 self.sizer1.Add(self.tree_ctrl_theory, 1, wx.EXPAND|wx.ALL, 10) 562 569 563 570 def on_right_click_theory(self, event): 564 571 """ … … 575 582 self.data_menu.Enable(self.editmask_id, False) 576 583 self.data_menu.Enable(self.plot3d_id, menu_enable) 577 self.PopupMenu(self.data_menu) 578 584 self.PopupMenu(self.data_menu) 585 579 586 def on_right_click_data(self, event): 580 587 """ … … 596 603 self.data_menu.Enable(self.editmask_id, maskmenu_enable) 597 604 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): 601 608 """ 602 609 Retrieve the state selected state … … 606 613 pos = event.GetPosition() 607 614 pos = self.ScreenToClient(pos) 608 self.PopupMenu(self.popUpMenu, pos) 609 610 615 self.PopupMenu(self.popUpMenu, pos) 616 617 611 618 def on_check_item(self, event): 612 619 """ … … 614 621 """ 615 622 item = event.GetItem() 616 item.Check(not item.IsChecked()) 623 item.Check(not item.IsChecked()) 617 624 self.enable_append() 618 625 self.enable_freeze() … … 621 628 self.enable_remove() 622 629 event.Skip() 623 630 624 631 def fill_cbox_analysis(self, plugin): 625 632 """ … … 635 642 if plug.get_perspective(): 636 643 self.perspective_cbox.Append(plug.sub_menu, plug) 637 644 638 645 curr_pers = self.parent.get_current_perspective() 639 646 if curr_pers: 640 647 self.perspective_cbox.SetStringSelection(curr_pers.sub_menu) 641 648 self.enable_import() 642 649 643 650 def load_data_list(self, list): 644 651 """ … … 654 661 data_run = str(data.run) 655 662 data_class = data.__class__.__name__ 656 path = dstate.get_path() 663 path = dstate.get_path() 657 664 process_list = data.process 658 665 data_id = data.id … … 661 668 #new state 662 669 data_c = self.tree_ctrl.InsertItem(self.tree_ctrl.root, 663 0, data_name, ct_type=1, 670 0, data_name, ct_type=1, 664 671 data=(data_id, data_class, state_id)) 665 672 data_c.Check(True) 666 673 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, 668 675 '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, 670 677 '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, 672 679 'Type: %s' % data_class) 673 680 p_c_c = self.tree_ctrl.AppendItem(d_i_c, 674 681 "Path: '%s'" % s_path) 675 682 d_p_c = self.tree_ctrl.AppendItem(d_i_c, 'Process') 676 683 677 684 for process in process_list: 678 685 process_str = str(process).replace('\n',' ') … … 680 687 process_str = process_str[:20]+' [...]' 681 688 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, 683 690 "THEORIES") 684 self.list_cb_data[state_id] = [data_c, 691 self.list_cb_data[state_id] = [data_c, 685 692 d_i_c, 686 693 d_t_c, … … 695 702 data_c, d_i_c, d_t_c, r_n_c, i_c_c, p_c_c, d_p_c, _ \ 696 703 = data_ctrl_list 697 self.tree_ctrl.SetItemText(data_c, data_name) 704 self.tree_ctrl.SetItemText(data_c, data_name) 698 705 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, 701 708 '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) 705 712 for process in process_list: 706 713 if not process.is_empty(): … … 710 717 # Sort by data name 711 718 if self.tree_ctrl.root: 712 self.tree_ctrl.SortChildren(self.tree_ctrl.root) 719 self.tree_ctrl.SortChildren(self.tree_ctrl.root) 713 720 self.enable_remove() 714 721 self.enable_import() … … 716 723 self.enable_freeze() 717 724 self.enable_selection() 718 725 719 726 def _uncheck_all(self): 720 727 """ … … 723 730 for item in self.list_cb_data.values(): 724 731 data_ctrl, _, _, _, _, _, _, _ = item 725 self.tree_ctrl.CheckItem(data_ctrl, False) 732 self.tree_ctrl.CheckItem(data_ctrl, False) 726 733 self.enable_append() 727 734 self.enable_freeze() … … 729 736 self.enable_import() 730 737 self.enable_remove() 731 738 732 739 def append_theory(self, state_id, theory_list): 733 740 """ … … 736 743 """ 737 744 if not theory_list: 738 return 745 return 739 746 if state_id not in self.list_cb_data.keys(): 740 747 root = self.tree_ctrl_theory.root … … 746 753 tree = self.tree_ctrl 747 754 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, 750 757 theory_list=theory_list) 751 752 758 759 753 760 def append_theory_helper(self, tree, root, state_id, theory_list): 754 761 """ … … 778 785 name, ct_type=1, data=temp) 779 786 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, 781 788 'Type: %s' % theory_class) 782 789 t_p_c = tree.AppendItem(t_i_c, 'Process') 783 790 784 791 for process in theory_data.process: 785 792 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, 788 795 t_p_c] 789 796 else: 790 797 #replace theory 791 798 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) 796 803 for process in theory_data.process: 797 804 tree.AppendItem(t_p_c, process.__str__()) 798 805 799 806 else: 800 807 #data didn't have a theory associated it before … … 807 814 theory_id = theory_data.id 808 815 #if theory_state is not None: 809 # name = theory_state.model.name 816 # name = theory_state.model.name 810 817 temp = (theory_id, theory_class, state_id) 811 818 t_child = tree.AppendItem(root, 812 name, ct_type=1, 819 name, ct_type=1, 813 820 data=(theory_data.id, theory_class, state_id)) 814 821 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, 816 823 'Type: %s' % theory_class) 817 824 t_p_c = tree.AppendItem(t_i_c, 'Process') 818 825 819 826 for process in theory_data.process: 820 827 tree.AppendItem(t_p_c, process.__str__()) 821 828 822 829 theory_list_ctrl[theory_id] = [t_child, i_c_c, t_p_c] 823 830 #self.list_cb_theory[data_id] = theory_list_ctrl 824 831 self.list_cb_theory[state_id] = theory_list_ctrl 825 826 827 832 833 834 828 835 def set_data_helper(self): 829 836 """ … … 840 847 if state_id not in state_to_plot: 841 848 state_to_plot.append(state_id) 842 849 843 850 for theory_dict in self.list_cb_theory.values(): 844 851 for _, value in theory_dict.iteritems(): … … 850 857 state_to_plot.append(state_id) 851 858 return data_to_plot, theory_to_plot, state_to_plot 852 859 853 860 def remove_by_id(self, id): 854 861 """ … … 857 864 for item in self.list_cb_data.values(): 858 865 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) 860 867 if id == data_id: 861 868 self.tree_ctrl.Delete(data_c) 862 869 del self.list_cb_data[state_id] 863 870 del self.list_cb_theory[data_id] 864 871 865 872 def load_error(self, error=None): 866 873 """ 867 874 Pop up an error message. 868 875 869 876 :param error: details error message to be displayed 870 877 """ 871 878 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), 873 880 'Error Loading File', 874 881 wx.OK | wx.ICON_EXCLAMATION) 875 dial.ShowModal() 876 882 dial.ShowModal() 883 877 884 def _load_data(self, event): 878 885 """ … … 881 888 if self.parent is not None: 882 889 wx.PostEvent(self.parent, NewLoadDataEvent()) 883 890 884 891 885 892 def on_remove(self, event): 886 893 """ 887 894 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 889 896 """ 890 897 msg = "This operation will delete the data sets checked " … … 893 900 if msg_box.ShowModal() != wx.ID_OK: 894 901 return 895 902 896 903 data_to_remove, theory_to_remove, _ = self.set_data_helper() 897 904 data_key = [] … … 906 913 theory_list_ctrl = self.list_cb_theory[d_key] 907 914 theory_to_remove += theory_list_ctrl.keys() 908 # Remove theory from treectrl 915 # Remove theory from treectrl 909 916 for _, theory_dict in self.list_cb_theory.iteritems(): 910 917 for key, value in theory_dict.iteritems(): … … 916 923 pass 917 924 theory_key.append(key) 918 925 919 926 #Remove data and related theory references 920 927 for key in data_key: … … 934 941 pass 935 942 del theory_dict[key] 936 937 943 944 938 945 self.parent.remove_data(data_id=data_to_remove, 939 946 theory_id=theory_to_remove) … … 941 948 self.enable_freeze() 942 949 self.enable_remove_plot() 943 950 944 951 def on_import(self, event=None): 945 952 """ … … 951 958 temp = data_id + state_id 952 959 self.parent.set_data(data_id=temp, theory_id=theory_id) 953 960 954 961 def on_append_plot(self, event=None): 955 962 """ … … 958 965 self._on_plot_selection() 959 966 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, 961 968 state_id=state_id, 962 969 theory_id=theory_id, 963 970 append=True) 964 971 965 972 def on_plot(self, event=None): 966 973 """ … … 968 975 """ 969 976 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, 971 978 state_id=state_id, 972 979 theory_id=theory_id, 973 980 append=False) 974 981 self.enable_remove_plot() 975 982 976 983 def on_close_page(self, event=None): 977 984 """ … … 982 989 # send parent to update menu with no show nor hide action 983 990 self.parent.show_data_panel(action=False) 984 991 985 992 def on_freeze(self, event): 986 993 """ … … 995 1002 msg = "Freeze Theory: Requires at least one theory checked." 996 1003 wx.PostEvent(self.parent, StatusEvent(status=msg)) 997 1004 998 1005 def set_active_perspective(self, name): 999 1006 """ … … 1002 1009 self.perspective_cbox.SetStringSelection(name) 1003 1010 self.enable_import() 1004 1011 1005 1012 def _on_delete_plot_panel(self, event): 1006 1013 """ 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 1008 1015 from the combobox of the current panel 1009 1016 """ … … 1011 1018 caption = event.caption 1012 1019 if self.cb_plotpanel is not None: 1013 pos = self.cb_plotpanel.FindString(str(caption)) 1020 pos = self.cb_plotpanel.FindString(str(caption)) 1014 1021 if pos != wx.NOT_FOUND: 1015 1022 self.cb_plotpanel.Delete(pos) 1016 1023 self.enable_append() 1017 1024 1018 1025 def set_panel_on_focus(self, name=None): 1019 1026 """ … … 1031 1038 self.enable_append() 1032 1039 self.enable_remove_plot() 1033 1040 1034 1041 def set_plot_unfocus(self): 1035 1042 """ … … 1037 1044 """ 1038 1045 return 1039 1046 1040 1047 def _on_perspective_selection(self, event=None): 1041 1048 """ … … 1047 1054 perspective.on_perspective(event=None) 1048 1055 self.parent.check_multimode(perspective=perspective) 1049 1056 1050 1057 def _on_plot_selection(self, event=None): 1051 1058 """ … … 1061 1068 if combo.GetValue() != 'None': 1062 1069 panel = combo.GetClientData(selection) 1063 self.parent.on_set_plot_focus(panel) 1064 1070 self.parent.on_set_plot_focus(panel) 1071 1065 1072 def on_close_plot(self, event): 1066 1073 """ 1067 1074 clseo the panel on focus 1068 """ 1075 """ 1069 1076 self.enable_append() 1070 1077 selection = self.cb_plotpanel.GetSelection() … … 1072 1079 panel = self.cb_plotpanel.GetClientData(selection) 1073 1080 if self.parent is not None and panel is not None: 1074 wx.PostEvent(self.parent, 1081 wx.PostEvent(self.parent, 1075 1082 NewPlotEvent(group_id=panel.group_id, 1076 1083 action="delete")) 1077 1084 self.enable_remove_plot() 1078 1085 1079 1086 def set_frame(self, frame): 1080 1087 """ 1081 1088 """ 1082 1089 self.frame = frame 1083 1090 1084 1091 def get_frame(self): 1085 1092 """ 1086 1093 """ 1087 return self.frame 1088 1094 return self.frame 1095 1089 1096 def on_help(self, event): 1090 1097 """ … … 1115 1122 """ 1116 1123 self.parent.show_data_panel(event) 1117 1124 1118 1125 def set_schedule_full_draw(self, panel=None, func='del'): 1119 1126 """ … … 1121 1128 """ 1122 1129 self.parent.set_schedule_full_draw(panel, func) 1123 1130 1124 1131 def enable_remove_plot(self): 1125 1132 """ … … 1131 1138 #else: 1132 1139 # self.bt_close_plot.Enable() 1133 1140 1134 1141 def enable_remove(self): 1135 1142 """ … … 1142 1149 else: 1143 1150 self.bt_remove.Enable() 1144 1151 1145 1152 def enable_import(self): 1146 1153 """ … … 1160 1167 else: 1161 1168 self.perspective_cbox.Enable() 1162 1169 1163 1170 def enable_plot(self): 1164 1171 """ 1165 1172 enable or disable plot button 1166 1173 """ 1167 n_t = 0 1174 n_t = 0 1168 1175 n_t_t = 0 1169 1176 if self.tree_ctrl != None: … … 1176 1183 self.bt_plot.Enable() 1177 1184 self.enable_append() 1178 1185 1179 1186 def enable_append(self): 1180 1187 """ 1181 1188 enable or disable append button 1182 1189 """ 1183 n_t = 0 1190 n_t = 0 1184 1191 n_t_t = 0 1185 1192 if self.tree_ctrl != None: … … 1187 1194 if self.tree_ctrl_theory != None: 1188 1195 n_t_t = self.tree_ctrl_theory.GetCount() 1189 if n_t + n_t_t <= 0: 1196 if n_t + n_t_t <= 0: 1190 1197 self.bt_append_plot.Disable() 1191 1198 self.cb_plotpanel.Disable() … … 1196 1203 self.bt_append_plot.Enable() 1197 1204 self.cb_plotpanel.Enable() 1198 1205 1199 1206 def check_theory_to_freeze(self): 1200 1207 """ … … 1214 1221 else: 1215 1222 self.bt_freeze.Disable() 1216 1223 1217 1224 def enable_selection(self): 1218 1225 """ … … 1229 1236 else: 1230 1237 self.selection_cbox.Disable() 1231 1238 1232 1239 def show_data_button(self): 1233 1240 """ 1234 show load data and remove data button if 1241 show load data and remove data button if 1235 1242 dataloader on else hide them 1236 1243 """ … … 1238 1245 gui_style = self.parent.get_style() 1239 1246 style = gui_style & GUIFRAME.DATALOADER_ON 1240 if style == GUIFRAME.DATALOADER_ON: 1247 if style == GUIFRAME.DATALOADER_ON: 1241 1248 #self.bt_remove.Show(True) 1242 self.bt_add.Show(True) 1249 self.bt_add.Show(True) 1243 1250 else: 1244 1251 #self.bt_remove.Hide() 1245 1252 self.bt_add.Hide() 1246 except: 1253 except: 1247 1254 #self.bt_remove.Hide() 1248 self.bt_add.Hide() 1249 1255 self.bt_add.Hide() 1256 1250 1257 1251 1258 … … 1264 1271 self.list_of_ctrl = [] 1265 1272 if not data_list: 1266 return 1273 return 1267 1274 self._sizer_main = wx.BoxSizer(wx.VERTICAL) 1268 1275 self._sizer_txt = wx.BoxSizer(wx.VERTICAL) … … 1273 1280 self._panel.SetupScrolling() 1274 1281 self.__do_layout(data_list, text=text) 1275 1282 1276 1283 def __do_layout(self, data_list, text=''): 1277 1284 """ … … 1279 1286 """ 1280 1287 if not data_list or len(data_list) <= 1: 1281 return 1288 return 1282 1289 #add text 1283 1290 1284 1291 text = "Deleting these file reset some panels.\n" 1285 1292 text += "Do you want to proceed?\n" … … 1315 1322 wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10) 1316 1323 static_line = wx.StaticLine(self, -1) 1317 1324 1318 1325 self._sizer_txt.Add(self._panel, 1, wx.EXPAND|wx.LEFT|wx.RIGHT, 5) 1319 1326 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, 1321 1328 # wx.EXPAND|wx.LEFT|wx.RIGHT, 10) 1322 1329 self._sizer_main.Add(static_line, 0, wx.EXPAND, 0) … … 1324 1331 self.SetSizer(self._sizer_main) 1325 1332 self.Layout() 1326 1333 1327 1334 def get_data(self): 1328 1335 """ … … 1335 1342 temp.append(data) 1336 1343 return temp 1337 1344 1338 1345 class DataFrame(wx.Frame): 1339 1346 """ … … 1347 1354 # tied to any perspective 1348 1355 ALWAYS_ON = True 1349 1356 1350 1357 def __init__(self, parent=None, owner=None, manager=None, size=(300, 800), 1351 1358 list_of_perspective=[], list=[], *args, **kwds): … … 1357 1364 self.owner = owner 1358 1365 self._manager = manager 1359 self.panel = DataPanel(parent=self, 1366 self.panel = DataPanel(parent=self, 1360 1367 manager=manager, 1361 1368 list_of_perspective=list_of_perspective) 1362 1369 1363 1370 def load_data_list(self, list=[]): 1364 1371 """ … … 1366 1373 """ 1367 1374 self.panel.load_data_list(list=list) 1368 1369 1370 1375 1376 1377 1371 1378 from sas.sasgui.guiframe.dataFitting import Theory1D 1372 1379 from sas.sasgui.guiframe.data_state import DataState … … 1383 1390 self.msg += "name value\n" 1384 1391 return self.msg 1385 1392 1386 1393 def set_data_state(data=None, path=None, theory=None, state=None): 1387 1394 """ … … 1391 1398 dstate.set_path(path=path) 1392 1399 dstate.set_theory(theory, state) 1393 1400 1394 1401 return dstate 1395 1402 1396 1403 if __name__ == "__main__": 1397 1404 1398 1405 app = wx.App() 1399 1406 try: … … 1477 1484 #raise 1478 1485 print "error", sys.exc_value 1479 1480 app.MainLoop() 1481 1482 1486 1487 app.MainLoop() -
TabularUnified src/sas/sasgui/guiframe/local_perspectives/data_loader/data_loader.py ¶
rfaa3ae7 ra674d0b 162 162 logging.error("Loader returned an invalid object:\n %s" % str(item)) 163 163 data_error = True 164 164 165 165 data = self.parent.create_gui_data(item, p_file) 166 166 output[data.id] = data … … 170 170 """ 171 171 """ 172 message = "" 173 log_msg = '' 172 file_errors = {} 174 173 output = {} 175 any_error = False 176 data_error = False 177 error_message = "" 174 exception_occurred = False 175 178 176 for p_file in path: 179 info = "info"180 177 basename = os.path.basename(p_file) 181 178 _, extension = os.path.splitext(basename) 182 179 if extension.lower() in EXTENSIONS: 183 any_error = True184 180 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." 189 184 logging.info(log_msg) 185 file_errors[basename] = [log_msg] 190 186 continue 191 187 192 188 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") 195 191 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 = "" 204 196 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 209 213 except: 210 214 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") 237 237 238 238 def load_update(self, output=None, message="", info="warning"): … … 254 254 # self.load_error(error_message) 255 255 self.parent.add_data(data_list=output) 256 257 258 -
TabularUnified src/sas/sasgui/guiframe/local_perspectives/plotting/Plotter1D.py ¶
ra47d0c8 r2387abc 552 552 self.subplot.set_xlim((xlo, xhi)) 553 553 self.subplot.set_ylim((ylo, yhi)) 554 self.graph.selected_plottable = None 554 555 555 556 … … 629 630 630 631 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() 635 637 636 638 wx_id = ids.next() … … 694 696 self._slicerpop.AppendSeparator() 695 697 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() 696 701 self._slicerpop.Append(wx_id, '&Reset Graph Range') 697 702 wx.EVT_MENU(self, wx_id, self.onResetGraph) … … 710 715 self.PopupMenu(self._slicerpop, pos) 711 716 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 712 736 def onFreeze(self, event): 713 737 """ … … 796 820 int(curr_symbol))), curr_label) 797 821 self.appD.Bind(wx.EVT_CLOSE, self.on_AppDialog_close) 822 self.graph.selected_plottable = None 798 823 799 824 def on_AppDialog_close(self, event): -
TabularUnified src/sas/sasgui/guiframe/media/data_explorer_help.rst ¶
rd85c194 rb64b87c 20 20 21 21 *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 *is22 to the current active analysis, if possible. When* Data Explorer *is 23 23 shown, data go first to the* Data Explorer. 24 24 … … 116 116 117 117 Click 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).118 available types of analysis (*Fitting*, *P(r) Inversion*, or *Invariant* calculation). 119 119 120 The *Single*/*Batch* mode radio buttons only apply to the *Fitting* perspective.120 The *Single*/*Batch* mode radio buttons only apply to *Fitting*. 121 121 122 122 *Batch mode* provides serial (batch) fitting with one model function, that is, -
TabularUnified src/sas/sasgui/guiframe/media/graph_help.rst ¶
rf93b473f re68c9bf 20 20 ^^^^^^^^^^^^^^^^^^^^^^^ 21 21 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. 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. 24 24 Then select a menu item. 25 25 … … 27 27 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 28 28 29 To expand a plot window, click the *Maximise* (square) icon in the top-right 29 To expand a plot window, click the *Maximise* (square) icon in the top-right 30 30 corner. 31 31 32 To shrink a plot window, click the *Restore down* (square-on-square) icon in 32 To shrink a plot window, click the *Restore down* (square-on-square) icon in 33 33 the top-right corner. 34 34 35 To hide a plot, click the *Minimise* (-) icon in the top-right corner of the 35 To hide a plot, click the *Minimise* (-) icon in the top-right corner of the 36 36 plot window. 37 37 38 To show a hidden plot, select the *Restore up* (square-on-square) icon on the 38 To show a hidden plot, select the *Restore up* (square-on-square) icon on the 39 39 minimised window. 40 40 41 To delete a plot, click the *Close* (x) icon in the top-right corner of the 41 To delete a plot, click the *Close* (x) icon in the top-right corner of the 42 42 plot window. 43 43 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 45 45 after computation.* 46 46 … … 48 48 ^^^^^^^^^^^^^^^ 49 49 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 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 53 53 accordingly. 54 54 55 55 To disable dragging mode, unselect the *crossed arrows* icon on the toolbar. 56 56 … … 58 58 ^^^^^^^^^^^^^^^^^^^^^^^^ 59 59 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 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 63 63 a region of interest. Release the mouse button to generate the new view. 64 64 65 65 To disable zoom mode, unselect the *Zoom* button on the toolbar. 66 66 67 After zooming in on a a region, the *left arrow* or *right arrow* buttons on 67 After zooming in on a a region, the *left arrow* or *right arrow* buttons on 68 68 the toolbar will switch between recent views. 69 69 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 71 on the current plot (changing both axes). Alternatively, point at the numbers 72 72 on one axis and scroll the wheel to zoom in/out on just that axis.* 73 73 74 To return to the original view of the data, click the the *Reset* (home) icon 74 To return to the original view of the data, click the the *Reset* (home) icon 75 75 in the toolbar at the bottom of the plot (see Resetting_the_graph_ for further details). 76 76 … … 78 78 ^^^^^^^^^^^^^^^^^^^ 79 79 80 To save the current plot as an image file, right click on the plot to bring up 80 To save the current plot as an image file, right click on the plot to bring up 81 81 the *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 82 Alternatively, click on the *Save* (floppy disk) icon in the toolbar at the 83 83 bottom of the plot. 84 85 A dialog window will open. Select a folder, enter a filename, choose an output 84 85 A dialog window will open. Select a folder, enter a filename, choose an output 86 86 image type, and click *Save*. 87 87 … … 94 94 * PNG (portable network graphics) 95 95 * PS (postscript) 96 * RAW/RGBA (bitmap )96 * RAW/RGBA (bitmap, stored as 935x635 pixels of depth 8) 97 97 * SVG/SVGA (scalable vector graphics) 98 98 * TIF/TIFF (tagged iamge file) … … 101 101 ^^^^^^^^^^^^^^^ 102 102 103 To send the current plot to a printer, click on the *Print* (printer) icon in 103 To send the current plot to a printer, click on the *Print* (printer) icon in 104 104 the toolbar at the bottom of the plot. 105 105 … … 109 109 ^^^^^^^^^^^^^^^^^^^ 110 110 111 To reset the axis range of a graph to its initial values select *Reset Graph 111 To reset the axis range of a graph to its initial values select *Reset Graph 112 112 Range* on the *Graph Menu* (see Invoking_the_graph_menu_). Alternatively, use 113 113 the *Reset* (home) icon in the toolbar at the bottom of the plot. … … 133 133 134 134 From 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 135 dialog window will appear in which it is possible to choose different 136 136 transformations of the x (usually Q) or y (usually I(Q)) axes, including: 137 137 … … 139 139 * y, 1/y, ln(y), y^2, y.(x^4), 1/sqrt(y), 140 140 * log10(y), ln(y.x), ln(y.x^2), ln(y.x^4), log10(y.x^4) 141 141 142 142 A *View* option includes short-cuts to common SAS transformations, such as: 143 143 … … 148 148 * Kratky 149 149 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 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 152 152 levels, via a linear fit (see Making_a_linear_fit_). 153 153 … … 158 158 159 159 From 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 160 Scale* to switch between a linear to log intensity scale. The type of scale 161 161 selected is written alongside the colour scale. 162 162 … … 167 167 168 168 From 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 169 choose a different color scale for the image and/or change the maximum or 170 170 minimum limits of the scale. 171 171 … … 173 173 ^^^^^^^^^^^^^^^^^^^^^^^^ 174 174 175 Clicking anywhere in the plot window will cause the current coordinates to be 175 Clicking anywhere in the plot window will cause the current coordinates to be 176 176 displayed in the status bar at the very bottom-left of the SasView window. 177 177 178 178 .. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 179 179 … … 193 193 194 194 In 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 195 and select *DataInfo* to bring up a data information dialog panel for that 196 196 data set. 197 197 … … 200 200 201 201 In 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 202 a File* (if 1D data) or *Save as a file(DAT)* (if 2D data). A save dialog will 203 203 appear. 204 204 205 1D data can be saved in either ASCII text (.TXT) or CanSAS/SASXML (.XML) 205 1D data can be saved in either ASCII text (.TXT) or CanSAS/SASXML (.XML) 206 206 formats (see :ref:`Formats`). 207 207 … … 216 216 217 217 In 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. 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. 221 221 222 222 This 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 223 Porod type analyses, for example, to estimate Rg, a rod diameter, or incoherent 224 224 background level, respectively. 225 225 … … 240 240 241 241 In 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. 242 or *Hide Error Bar* to switch between showing/hiding the errors associated 243 with the chosen dataset. 244 244 245 245 Modify plot properties … … 247 247 248 248 In 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 249 Property* to change the size, color, or shape of the displayed marker for the 250 250 chosen dataset, or to change the dataset label that appears on the plot. 251 251 … … 260 260 This feature is only available with 2D data. 261 261 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 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 264 264 can be modified by dragging the boundaries around. 265 265 … … 277 277 * Box averaging on Qy 278 278 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 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 281 281 in red, it means that the slicer can move/change size. 282 282 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 284 284 the size of the data.* 285 285 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 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 289 289 define a region or select the number of points to plot (*nbins*). 290 290 291 A separate plot window will also have appeared, displaying the requested 291 A separate plot window will also have appeared, displaying the requested 292 292 average. 293 293 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 295 295 that window; ie, when the mouse pointer is moved onto that plot.* 296 296 297 Selecting *Box Sum* automatically brings up the 'Slicer Parameters' dialog in 297 Selecting *Box Sum* automatically brings up the 'Slicer Parameters' dialog in 298 298 order to display the average numerically, rather than graphically. 299 299 … … 303 303 ^^^^^^^^^^^^^^^^^^^^^^^^^ 304 304 305 This operation will perform an average in constant Q-rings around the (x,y) 305 This operation will perform an average in constant Q-rings around the (x,y) 306 306 pixel location of the beam center. 307 307 … … 309 309 ^^^^^^^^^^^^^^^^^^^^^^^ 310 310 311 This operation is the same as 'Unmasked Circular Average' except that any 311 This operation is the same as 'Unmasked Circular Average' except that any 312 312 masked region is excluded. 313 313 … … 317 317 This operation averages in constant Q-arcs. 318 318 319 The width of the sector is specified in degrees (+/- |delta|\|phi|\) each side 319 The width of the sector is specified in degrees (+/- |delta|\|phi|\) each side 320 320 of the central angle (|phi|\). 321 321 … … 323 323 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 324 324 325 This operation performs an average between two Q-values centered on (0,0), 325 This operation performs an average between two Q-values centered on (0,0), 326 326 and averaged over a specified number of pixels. 327 327 328 The data is returned as a function of angle (|phi|\) in degrees with zero 328 The data is returned as a function of angle (|phi|\) in degrees with zero 329 329 degrees at the 3 O'clock position. 330 330 … … 334 334 This operation performs a sum of counts in a 2D region of interest. 335 335 336 When editing the slicer parameters, the user can enter the length and the width 336 When editing the slicer parameters, the user can enter the length and the width 337 337 the rectangular slicer and the coordinates of the center of the rectangle. 338 338 … … 342 342 This operation computes an average I(Qx) for the region of interest. 343 343 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 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 347 347 is, the central value of each bin on the x-axis. 348 348 … … 352 352 This operation computes an average I(Qy) for the region of interest. 353 353 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 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 357 357 is, the central value of each bin on the x-axis. 358 358 -
TabularUnified src/sas/sasgui/perspectives/fitting/basepage.py ¶
r5213d22 re4c897b 2942 2942 """ 2943 2943 2944 _TreeLocation = "user/ sasgui/perspectives/fitting/mag_help.html"2944 _TreeLocation = "user/magnetism.html" 2945 2945 _doc_viewer = DocumentationWindow(self, wx.ID_ANY, _TreeLocation, "", 2946 2946 "Polarized Beam/Magnetc Help") -
TabularUnified src/sas/sasgui/perspectives/fitting/media/fitting_help.rst ¶
r20846be rb64b87c 15 15 16 16 17 Fitting Perspective18 ======= ============17 Fitting 18 ======= 19 19 20 20 .. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ … … 24 24 25 25 To 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. 26 send those data sets to fitting, and select a model to fit to each data set. 28 27 29 28 Instructions on how to load and activate data are in the section :ref:`Loading_data`. … … 331 330 This mode fits one data set. 332 331 333 When data is sent to the fitting perspective it is plotted in a graph window as 334 markers. 332 When data is sent to the fitting it is plotted in a graph window as markers. 335 333 336 334 If a graph does not appear, or a graph window appears but is empty, then the data -
TabularUnified src/sas/sasgui/perspectives/fitting/media/pd_help.rst ¶
r7805458 rb64b87c 105 105 106 106 The median value for the distribution will be the value given for the respective 107 size parameter in the *Fit ting Perspective*, for example, radius = 60.107 size parameter in the *FitPage*, for example, radius = 60. 108 108 109 109 The polydispersity is given by |sigma| … … 172 172 173 173 SasView only uses these array values during the computation, therefore any mean 174 value of the parameter represented by *x* present in the *Fit ting Perspective*174 value of the parameter represented by *x* present in the *FitPage* 175 175 will be ignored. 176 176 -
TabularUnified src/sas/sasgui/perspectives/invariant/media/invariant_help.rst ¶
r70305bd2 rb64b87c 4 4 .. by S King, ISIS, during SasView CodeCamp-III in Feb 2015. 5 5 6 Invariant Calculation Perspective7 ===================== ============6 Invariant Calculation 7 ===================== 8 8 9 9 Description … … 45 45 .. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 46 46 47 Using the perspective48 --------------------- 47 Using invariant analysis 48 ------------------------ 49 49 50 50 1) Select *Invariant* from the *Analysis* menu on the SasView toolbar. … … 53 53 54 54 3) Select a dataset and use the *Send To* button on the *Data Explorer* to load 55 the dataset into the *Invariant* p erspective.55 the dataset into the *Invariant* panel. 56 56 57 4) Use the *Customised Input* boxes on the *Invariant* p erspectiveto subtract57 4) Use the *Customised Input* boxes on the *Invariant* panel to subtract 58 58 any background, specify the contrast (i.e. difference in SLDs - this must be 59 59 specified for the eventual value of Q*\ to be on an absolute scale), or to … … 73 73 74 74 8) If the value of Q*\ calculated with the extrapolated regions is invalid, a 75 red warning will appear at the top of the *Invariant* p erspective panel.75 red warning will appear at the top of the *Invariant* panel. 76 76 77 77 The details of the calculation are available by clicking the *Details* -
TabularUnified src/sas/sasgui/perspectives/pr/media/pr_help.rst ¶
r7805458 rb64b87c 4 4 .. by S King, ISIS, during SasView CodeCamp-III in Feb 2015. 5 5 6 P(r) Inversion Perspective7 ================ ==========6 P(r) Calculation 7 ================ 8 8 9 9 Description … … 32 32 .. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 33 33 34 Using the perspective35 -------------------- -34 Using P(r) inversion 35 -------------------- 36 36 37 37 The user must enter -
TabularUnified src/sas/sasgui/plottools/PlotPanel.py ¶
r1ed6be7 r1a8e2e8e 15 15 import os 16 16 import transform 17 from plottables import Data1D18 17 #TODO: make the plottables interactive 19 18 from binder import BindArtist … … 151 150 #List of texts currently on the plot 152 151 self.textList = [] 152 self.selectedText = None 153 153 #User scale 154 154 if xtransform != None: … … 190 190 191 191 # new data for the fit 192 from sas.sasgui.guiframe.dataFitting import Data1D 192 193 self.fit_result = Data1D(x=[], y=[], dy=None) 193 194 self.fit_result.symbol = 13 … … 352 353 self.leftdown = True 353 354 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 354 360 if ax != None: 355 361 self.xInit, self.yInit = event.xdata, event.ydata … … 373 379 self.mousemotion = False 374 380 self.leftup = True 381 self.selectedText = None 375 382 376 383 #release the legend … … 448 455 self._on_legend_motion(event) 449 456 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 450 470 if self.enable_toolbar: 451 471 #Disable dragging without the toolbar to allow zooming with toolbar … … 646 666 dlg.setFitRange(self.xminView, self.xmaxView, 647 667 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]) 648 672 # It would be nice for this to NOT be modal (i.e. Show). 649 673 # Not sure about other ramifications - for example … … 1725 1749 if remove_fit: 1726 1750 self.graph.delete(self.fit_result) 1751 if hasattr(self, 'plots'): 1752 if 'fit' in self.plots.keys(): 1753 del self.plots['fit'] 1727 1754 self.ly = None 1728 1755 self.q_ctrl = None … … 1738 1765 _yscale = 'linear' 1739 1766 for item in list: 1767 if item.id == 'fit': 1768 continue 1740 1769 item.setLabel(self.xLabel, self.yLabel) 1741 1770 # control axis labels from the panel itself … … 1869 1898 1870 1899 """ 1900 xlim = self.subplot.get_xlim() 1901 ylim = self.subplot.get_ylim() 1902 1871 1903 # Saving value to redisplay in Fit Dialog when it is opened again 1872 1904 self.Avalue, self.Bvalue, self.ErrAvalue, \ … … 1892 1924 self.graph.render(self) 1893 1925 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) 1894 1935 self.subplot.figure.canvas.draw_idle() 1895 1936
Note: See TracChangeset
for help on using the changeset viewer.