Changeset 3195
- Timestamp:
- Dec 18, 2017 3:18:15 PM (5 years ago)
- Location:
- trunk
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/GSASIIIO.py
r3190 r3195 500 500 rd.Image = rd.Image.T 501 501 rd.Data['ImageTag'] = rd.repeatcount 502 if GSASIIpath.GetConfigValue('Image_1IDmetadata'):503 rd.readfilename = imagefile504 Get1IDMetadata(rd)502 rd.readfilename = imagefile 503 # Load generic metadata, as configured 504 GetColumnMetadata(rd) 505 505 LoadImage2Tree(imagefile,G2frame,rd.Comments,rd.Data,rd.Npix,rd.Image) 506 506 repeat = rd.repeat … … 2158 2158 return Layer 2159 2159 2160 def Read1IDpar(imagefile): 2161 '''Reads image metadata from a 1-ID style .par file from the same directory 2162 as the image. The .par file has any number of columns separated by spaces. 2163 As an index to the .par file a second label file must be specified with the 2164 same file name as the .par file but the extension must be .XXX_lbls (where 2160 def readColMetadata(imagefile): 2161 '''Reads image metadata from a column-oriented metadata table 2162 (1-ID style .par file). Called by :func:`GetColumnMetadata` 2163 2164 The .par file has any number of columns separated by spaces. 2165 The directory for the file must be specified in 2166 Config variable ``Column_Metadata_directory``. 2167 As an index to the .par file a second "label file" must be specified with the 2168 same file root name as the .par file but the extension must be .XXX_lbls (where 2165 2169 .XXX is the extension of the image) or if that is not present extension 2166 .lbls. Called by :func:`Get1IDMetadata`2167 2168 :param str imagefile: the full name of the image file (with directory and extension)2170 .lbls. 2171 2172 :param str imagefile: the full name of the image file (with extension, directory optional) 2169 2173 2170 2174 :returns: a dict with parameter values. Named parameters will have the type based on … … 2223 2227 2224 2228 ``filename:lambda x,y: "{}_{:0>6}".format(x,y)|33,34`` 2225 Here the function to be used is defined with a lambda statement: 2229 Here the function to be used is defined with a lambda statement:: 2226 2230 2227 2231 lambda x,y: "{}_{:0>6}".format(x,y) … … 2231 2235 the file name, followed by a underscore (_), followed by the second parameter (y, col. 34), 2232 2236 which will be left-padded with zeros to six characters (format directive ``:0>6``). 2233 2237 2238 When there will be more than one image generated per line in the .par file, an alternate way to 2239 generate list of file names takes into account the number of images generated:: 2240 2241 lambda x,y,z: ["{}_{:0>6}".format(x,int(y)+i) for i in range(int(z))] 2242 2243 Here a third parameter is used to specify the number of images generated, where 2244 the image number is incremented for each image. 2245 2234 2246 ``distance: float | 75`` 2235 2247 Here the contents of column 75 will be converted to a floating point number … … 2258 2270 **Pre-defined parameter names** 2259 2271 2260 ============= ========= ======== ==================================================== 2272 ============= ========= ======== ===================================================== 2261 2273 keyword required type Description 2262 ============= ========= ======== ==================================================== 2263 filename yes str generates the file name prefix for the matching image 2264 file (MyImage001 for file /tmp/MyImage001.tif). 2274 ============= ========= ======== ===================================================== 2275 filename yes str or generates the file name prefix for the matching image 2276 list file (MyImage001 for file /tmp/MyImage001.tif) or 2277 a list of file names. 2265 2278 polarization no float generates the polarization expected based on the 2266 2279 monochromator angle, defaults to 0.99. … … 2272 2285 2 floats [200.0, 200.0]. 2273 2286 wavelength yes float generates the wavelength in Angstroms 2274 ============= ========= ======== ==================================================== 2275 2287 ============= ========= ======== ===================================================== 2276 2288 2277 2289 ''' 2278 2290 dir,fil = os.path.split(os.path.abspath(imagefile)) 2279 2291 imageName,ext = os.path.splitext(fil) 2280 parfiles = glob.glob(os.path.join(dir,'*.par')) 2292 if not GSASIIpath.GetConfigValue('Column_Metadata_directory'): return 2293 parfiles = glob.glob(os.path.join(GSASIIpath.GetConfigValue('Column_Metadata_directory'),'*.par')) 2281 2294 if len(parfiles) == 0: 2282 print('Sorry, No 1-ID .par file found in '+dir) 2295 print('Sorry, No Column metadata (.par) file found in '+ 2296 GSASIIpath.GetConfigValue('Column_Metadata_directory')) 2283 2297 return {} 2284 2298 for parFil in parfiles: # loop over all .par files (hope just 1) in image dir until image is found … … 2290 2304 else: 2291 2305 print('Warning: No labels definitions found for '+parFil) 2292 return {}2293 fp = open(lblFil,'Ur') # read column labels2294 lbldict = {}2295 fmt = ""2296 keyExp = {}2297 keyCols = {}2298 labels = {}2299 for line in fp: # read label definitions2300 items = line.strip().split(':')2301 if len(items) < 2: continue # no colon, line is a comment2302 # is this line a definition for a named parameter?2303 key = items[0]2304 try:2305 int(key)2306 except ValueError: # named parameters are not valid numbers2307 items = line.split(':',1)[1].split('|')2308 try:2309 keyExp[key] = eval(items[0]) # compile the expression2310 if not callable(keyExp[key]):2311 raise Exception("Expression not a function")2312 except Exception as msg:2313 print('Warning: Expression "{}" is not valid for key {}'.format(items[0],key))2314 print(msg)2315 keyCols[key] = [int(i) for i in items[1].strip().split(',')]2316 if key.lower().startswith('freeprm') and len(items) > 2:2317 labels[key] = items[2]2318 continue2319 if len(items) == 2: # simple column definition2320 lbldict[int(items[0])] = items[1]2321 fp.close()2322 if 'filename' not in keyExp:2323 print("Warning: No valid filename expression in {} file, skipping .par".format(lblFil))2324 2306 continue 2325 # read the .par, looking for the matching image rootname 2307 labels,lbldict,keyCols,keyExp,errors = readColMetadataLabels(lblFil) 2308 if errors: 2309 print('Errors in labels file '+lblFil) 2310 for i in errors: print(' '+i) 2311 continue 2312 else: 2313 print('Read '+lblFil) 2314 # scan through each line in this .par file, looking for the matching image rootname 2326 2315 fp = open(parFil,'Ur') 2327 for i ,line in enumerate(fp):2316 for iline,line in enumerate(fp): 2328 2317 items = line.strip().split(' ') 2329 name = keyExp['filename'](*[items[j] for j in keyCols['filename']]) 2330 if name == imageName: # got our match, parse the line and finish 2331 metadata = {lbldict[j]:items[j] for j in lbldict} 2332 metadata.update( 2333 {key:keyExp[key](*[items[j] for j in keyCols[key]]) for key in keyExp}) 2334 metadata['par file'] = parFil 2335 metadata['lbls file'] = lblFil 2336 for lbl in labels: 2337 metadata['label_'+lbl[4:].lower()] = labels[lbl] 2338 print("Metadata read from {} line {}".format(parFil,i+1)) 2339 return metadata 2318 nameList = keyExp['filename'](*[items[j] for j in keyCols['filename']]) 2319 if type(nameList) is str: 2320 if nameList != imageName: continue 2321 name = nameList 2322 else: 2323 for name in nameList: 2324 if name == imageName: break # got a match 2325 else: 2326 continue 2327 # parse the line and finish 2328 metadata = evalColMetadataDicts(items,labels,lbldict,keyCols,keyExp) 2329 metadata['par file'] = parFil 2330 metadata['lbls file'] = lblFil 2331 print("Metadata read from {} line {}".format(parFil,iline+1)) 2332 fp.close() 2333 return metadata 2340 2334 else: 2341 2335 print("Image {} not found in {}".format(imageName,parFil)) … … 2344 2338 fp.close() 2345 2339 else: 2346 print("Warning: No 1-IDmetadata for image {}".format(imageName))2340 print("Warning: No .par metadata for image {}".format(imageName)) 2347 2341 return {} 2348 2342 2349 def Get1IDMetadata(reader): 2350 '''Add 1-ID metadata to an image using a 1-ID .par file using :func:`Read1IDpar` 2343 def readColMetadataLabels(lblFil): 2344 '''Read the .*lbls file and setup for metadata assignments 2345 ''' 2346 lbldict = {} 2347 keyExp = {} 2348 keyCols = {} 2349 labels = {} 2350 errors = [] 2351 fp = open(lblFil,'Ur') # read column labels 2352 for iline,line in enumerate(fp): # read label definitions 2353 line = line.strip() 2354 if not line or line[0] == '#': continue # comments 2355 items = line.split(':') 2356 if len(items) < 2: continue # lines with no colon are also comments 2357 # does this line a definition for a named parameter? 2358 key = items[0] 2359 try: 2360 int(key) 2361 except ValueError: # try as named parameter since not a valid number 2362 items = line.split(':',1)[1].split('|') 2363 try: 2364 f = eval(items[0]) # compile the expression 2365 if not callable(f): 2366 errors += ['Expression "{}" for key {} is not a function (line {})'. 2367 format(items[0],key,iline)] 2368 continue 2369 keyExp[key] = f 2370 except Exception as msg: 2371 errors += ['Expression "{}" for key {} is not valid (line {})'. 2372 format(items[0],key,iline)] 2373 errors += [str(msg)] 2374 continue 2375 keyCols[key] = [int(i) for i in items[1].strip().split(',')] 2376 if key.lower().startswith('freeprm') and len(items) > 2: 2377 labels[key] = items[2] 2378 continue 2379 if len(items) == 2: # simple column definition 2380 lbldict[int(items[0])] = items[1] 2381 fp.close() 2382 if 'filename' not in keyExp: 2383 errors += ["File {} is invalid. No valid filename expression.".format(lblFil)] 2384 return labels,lbldict,keyCols,keyExp,errors 2385 2386 def evalColMetadataDicts(items,labels,lbldict,keyCols,keyExp,ShowError=False): 2387 '''Evaluate the metadata for a line in the .par file 2388 ''' 2389 metadata = {lbldict[j]:items[j] for j in lbldict} 2390 named = {} 2391 for key in keyExp: 2392 try: 2393 res = keyExp[key](*[items[j] for j in keyCols[key]]) 2394 except: 2395 if ShowError: 2396 res = "*** error ***" 2397 else: 2398 continue 2399 named[key] = res 2400 metadata.update(named) 2401 for lbl in labels: # add labels for FreePrm's 2402 metadata['label_'+lbl[4:].lower()] = labels[lbl] 2403 return metadata 2404 2405 def GetColumnMetadata(reader): 2406 '''Add metadata to an image from a column-type metadata file 2407 using :func:`readColMetadata` 2351 2408 2352 2409 :param reader: a reader object from reading an image 2353 2410 2354 2411 ''' 2355 parParms = Read1IDpar(reader.readfilename) 2412 if not GSASIIpath.GetConfigValue('Column_Metadata_directory'): return 2413 parParms = readColMetadata(reader.readfilename) 2356 2414 if not parParms: return # check for read failure 2357 2415 specialKeys = ('filename',"polarization", "center", "distance", "pixelSize", "wavelength",) … … 2378 2436 print('Error: distance not defined in {}'.format(parParms['lbls file'])) 2379 2437 2438 def testColumnMetadata(G2frame): 2439 '''Test the column-oriented metadata parsing, as implemented at 1-ID, by showing results 2440 when using a .par and .lbls pair. 2441 2442 * Select a .par file, if more than one in selected dir. 2443 * Select the .*lbls file, if more than one matching .par file. 2444 * Parse the .lbls file, showing errors if encountered; loop until errors are fixed. 2445 * Search for an image or a line in the .par file and show the results when interpreted 2446 2447 See :func:`readColMetadata` for more details. 2448 ''' 2449 if not GSASIIpath.GetConfigValue('Column_Metadata_directory'): 2450 G2G.G2MessageBox(G2frame,'The configuration option for I-ID Metadata is not set.\n'+ 2451 'Please use the File/Preferences menu to set Column_Metadata_directory', 2452 'Warning') 2453 return 2454 parFiles = glob.glob(os.path.join(GSASIIpath.GetConfigValue('Column_Metadata_directory'),'*.par')) 2455 if not parFiles: 2456 G2G.G2MessageBox(G2frame,'No .par files found in directory {}. ' 2457 .format(GSASIIpath.GetConfigValue('Column_Metadata_directory'))+ 2458 '\nThis is set by config variable Column_Metadata_directory '+ 2459 '(Set in File/Preferences menu).', 2460 'Warning') 2461 return 2462 parList = [] 2463 for parFile in parFiles: 2464 lblList = [] 2465 parRoot = os.path.splitext(parFile)[0] 2466 for f in glob.glob(parRoot+'.*lbls'): 2467 if os.path.exists(f): lblList.append(f) 2468 if not len(lblList): 2469 continue 2470 parList.append(parFile) 2471 if len(parList) == 0: 2472 G2G.G2MessageBox(G2frame,'No .lbls or .EXT_lbls file found for .par file(s) in directory {}. ' 2473 .format(GSASIIpath.GetConfigValue('Column_Metadata_directory'))+ 2474 '\nThis is set by config variable Column_Metadata_directory '+ 2475 '(Set in File/Preferences menu).', 2476 'Warning') 2477 return 2478 elif len(parList) == 1: 2479 parFile = parList[0] 2480 else: 2481 dlg = G2G.G2SingleChoiceDialog(G2frame, 2482 'More than 1 .par file found. (Better if only 1!). Choose the one to test in '+ 2483 GSASIIpath.GetConfigValue('Column_Metadata_directory'), 2484 'Choose .par file', [os.path.split(i)[1] for i in parList]) 2485 if dlg.ShowModal() == wx.ID_OK: 2486 parFile = parList[dlg.GetSelection()] 2487 dlg.Destroy() 2488 else: 2489 dlg.Destroy() 2490 return 2491 # got .par file; now work on .*lbls file 2492 lblList = [] 2493 parRoot = os.path.splitext(parFile)[0] 2494 for f in glob.glob(parRoot+'.*lbls'): 2495 if os.path.exists(f): lblList.append(f) 2496 if not len(lblList): 2497 raise Exception('How did this happen! No .*lbls files for '+parFile) 2498 elif len(lblList) == 1: 2499 lblFile = lblList[0] 2500 else: 2501 dlg = G2G.G2SingleChoiceDialog(G2frame, 2502 'Select label file for .par file '+parFile, 2503 'Choose label file', [os.path.split(i)[1] for i in lblList]) 2504 if dlg.ShowModal() == wx.ID_OK: 2505 lblFile = lblList[dlg.GetSelection()] 2506 dlg.Destroy() 2507 else: 2508 dlg.Destroy() 2509 return 2510 # parse the labels file 2511 errors = True 2512 while errors: 2513 labels,lbldict,keyCols,keyExp,errors = readColMetadataLabels(lblFile) 2514 if errors: 2515 t = "Error reading file "+lblFile 2516 for l in errors: 2517 t += '\n' 2518 t += l 2519 t += "\n\nPlease edit the file and press OK (or Cancel to quit)" 2520 dlg = wx.MessageDialog(G2frame,message=t, 2521 caption="Read Error",style=wx.ICON_ERROR| wx.OK|wx.STAY_ON_TOP|wx.CANCEL) 2522 if dlg.ShowModal() != wx.ID_OK: return 2523 # request a line number, read that line 2524 dlg = G2G.SingleStringDialog(G2frame,'Read what', 2525 'Enter a line number or an image file name (-1=last line)', 2526 '-1',size=(400,-1)) 2527 if dlg.Show(): 2528 fileorline = dlg.GetValue() 2529 dlg.Destroy() 2530 else: 2531 dlg.Destroy() 2532 return 2533 # and report the generated key pairs in metadata dict 2534 linenum = None 2535 try: 2536 linenum = int(fileorline) 2537 except: 2538 imageName = os.path.splitext(os.path.split(fileorline)[1])[0] 2539 2540 fp = open(parFile,'Ur') 2541 for iline,line in enumerate(fp): 2542 if linenum is not None: 2543 if iline == linenum: 2544 items = line.strip().split(' ') 2545 n = "Line {}".format(iline) 2546 break 2547 else: 2548 continue 2549 else: 2550 items = line.strip().split(' ') 2551 nameList = keyExp['filename'](*[items[j] for j in keyCols['filename']]) 2552 if type(nameList) is str: 2553 if nameList != imageName: continue 2554 name = nameList 2555 break 2556 else: 2557 for name in nameList: 2558 print (name,name == imageName) 2559 if name == imageName: 2560 n = "Image {} found in line {}".format(imageName,iline) 2561 break # got a match 2562 else: 2563 continue 2564 break 2565 else: 2566 if linenum is not None: 2567 n = "Line {}".format(iline) 2568 else: 2569 n = "Image {} not found. Reporting line {}".format(imageName,iline) 2570 items = line.strip().split(' ') 2571 fp.close() 2572 metadata = evalColMetadataDicts(items,labels,lbldict,keyCols,keyExp,True) 2573 title = "Results: ("+n+")" 2574 t = [] 2575 n = ["Named parameters:"] 2576 l = ['',"Labeled columns:"] 2577 for key in sorted(metadata): 2578 if key == "filename" or key.startswith('label_prm'): continue 2579 if key in keyCols: 2580 n += [" {} = {}".format(key,metadata[key])] 2581 elif key in lbldict.values(): 2582 l += [" {} = {}".format(key,metadata[key])] 2583 else: 2584 t += ["** Unexpected: {}".format(key,metadata[key])] 2585 if type(metadata['filename']) is str: 2586 l += ["","Filename: "+ metadata['filename']] 2587 else: 2588 l += ["","Filename(s): "] 2589 for i,j in enumerate(metadata['filename']): 2590 if i: l[-1] += ', ' 2591 l[-1] += j 2592 t += n + l + ['','Unused columns:'] 2593 usedCols = lbldict.keys() 2594 for i in keyCols.values(): usedCols += i 2595 for i in range(len(items)): 2596 if i in usedCols: continue 2597 t += [" {}: {}".format(i,items[i])] 2598 dlg = G2G.G2SingleChoiceDialog(None,title,'Column metadata parse results',t, 2599 monoFont=True,filterBox=False,size=(400,600), 2600 style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER|wx.CENTRE|wx.OK) 2601 dlg.ShowModal() 2602 2380 2603 if __name__ == '__main__': 2381 2604 import GSASIIdataGUI -
trunk/GSASIIctrlGUI.py
r3187 r3195 1811 1811 Sizer = wx.BoxSizer(wx.VERTICAL) 1812 1812 topSizer = wx.BoxSizer(wx.HORIZONTAL) 1813 h = max(35,17*int(len(title)/26.+1)) # adjust height of title box with guessed # of lines 1813 1814 topSizer.Add( 1814 wx.StaticText(self,wx.ID_ANY,title,size=(-1, 35)),1815 wx.StaticText(self,wx.ID_ANY,title,size=(-1,h)), 1815 1816 1,wx.ALL|wx.EXPAND|WACV,1) 1816 1817 if filterBox: … … 1822 1823 self.filterBox.Bind(wx.EVT_CHAR,self.onChar) 1823 1824 self.filterBox.Bind(wx.EVT_TEXT_ENTER,self.Filter) 1824 topSizer.Add(self.filterBox,0,wx.ALL,0)1825 topSizer.Add(self.filterBox,0,wx.ALL,0) 1825 1826 Sizer.Add(topSizer,0,wx.ALL|wx.EXPAND,8) 1826 1827 self.clb = wx.ListBox(self, wx.ID_ANY, (30,30), wx.DefaultSize, ChoiceList) … … 2031 2032 '''Dialog to obtain a single float value from user 2032 2033 2034 :param wx.Frame parent: name of parent frame 2035 :param str title: title string for dialog 2036 :param str prompt: string to tell user what they are inputing 2037 :param str value: default input value, if any 2038 :param list limits: upper and lower value used to set bounds for entry, use [None,None] 2039 for no bounds checking, [None,val] for only upper bounds, etc. Default is [0,1]. 2040 Values outside of limits will be ignored. 2041 :param str format: string to format numbers. Defaults to '%.5g'. Use '%d' to have 2042 integer input (but dlg.GetValue will still return a float). 2043 2033 2044 Typical usage:: 2034 2045 … … 2040 2051 2041 2052 ''' 2053 # TODO: better to generalize this for int & float, use validated text control, OK as default. 2054 # then make SingleFloatDialog & SingleIntDialog as wrappers. Would be good to remove the %-style 2055 # format, too. 2042 2056 def __init__(self,parent,title,prompt,value,limits=[0.,1.],format='%.5g'): 2043 2057 wx.Dialog.__init__(self,parent,-1,title, … … 2056 2070 try: 2057 2071 val = float(valItem.GetValue()) 2058 if val < self.limits[0] or val > self.limits[1]: 2072 if self.limits[0] is not None and val < self.limits[0]: 2073 raise ValueError 2074 if self.limits[1] is not None and val > self.limits[1]: 2059 2075 raise ValueError 2060 2076 except ValueError: … … 2097 2113 parent.Raise() 2098 2114 self.EndModal(wx.ID_CANCEL) 2115 2116 class SingleIntDialog(SingleFloatDialog): 2117 '''Dialog to obtain a single int value from user 2118 2119 :param wx.Frame parent: name of parent frame 2120 :param str title: title string for dialog 2121 :param str prompt: string to tell user what they are inputing 2122 :param str value: default input value, if any 2123 :param list limits: upper and lower value used to set bounds for entries. Default 2124 is [None,None] -- for no bounds checking; use [None,val] for only upper bounds, etc. 2125 Default is [0,1]. Values outside of limits will be ignored. 2126 2127 Typical usage:: 2128 2129 limits = (0,None) # allows zero or positive values only 2130 dlg = G2G.SingleIntDialog(G2frame,'New value','Enter new value for...',default,limits) 2131 if dlg.ShowModal() == wx.ID_OK: 2132 parm = dlg.GetValue() 2133 dlg.Destroy() 2134 2135 ''' 2136 def __init__(self,parent,title,prompt,value,limits=[None,None]): 2137 SingleFloatDialog.__init__(self,parent,title,prompt,value,limits=limits,format='%d') 2138 def GetValue(self): 2139 return int(self.value) 2099 2140 2100 2141 ################################################################################ -
trunk/GSASIIdataGUI.py
r3192 r3195 783 783 if rd.sumfile: 784 784 rd.readfilename = rd.sumfile 785 if GSASIIpath.GetConfigValue('Image_1IDmetadata'):786 G2IO.Get1IDMetadata(rd)785 # Load generic metadata, as configured 786 G2IO.GetColumnMetadata(rd) 787 787 G2IO.LoadImage2Tree(rd.readfilename,self,rd.Comments,rd.Data,rd.Npix,rd.Image) 788 788 rd_list.append(True) # save a stub the result before it is written over … … 2530 2530 self._Add_ImportMenu_reflectometry(Import) 2531 2531 self._Add_ImportMenu_PDF(Import) 2532 2533 item = Import.Append(wx.ID_ANY,'Column metadata test','Test Column (.par) metadata import') 2534 self.Bind(wx.EVT_MENU, self.OnColMetaTest, id=item.GetId()) 2532 2535 2533 2536 #====================================================================== … … 2932 2935 'implement unfortunate synonym. with luck no longer used' 2933 2936 self.SetTitle(text,location=0) 2934 2937 2938 def OnColMetaTest(self,event): 2939 'Test the .par/.*lbls pair for contents' 2940 G2IO.testColumnMetadata(self) 2935 2941 2936 2942 def OnReadPowderPeaks(self,event): -
trunk/config_example.py
r3189 r3195 171 171 '''If True, shows various timing results.''' 172 172 173 Image_1IDmetadata = False174 '''When Trueand when images are read, GSAS-II will read metadata from a 1-ID175 style .par and a .EXT_lbls or .lbls file. See :func:`GSASIIIO.Read1IDpar` for176 information on how this is done. 173 Column_Metadata_directory = None 174 '''When specified and when images are read, GSAS-II will read metadata from a 1-ID 175 style .par and a .EXT_lbls (EXT = image extension) or .lbls file. See :func:`GSASIIIO.readColMetadata` for 176 information on how this is done. 177 177 ''' -
trunk/imports/G2img_1TIF.py
r3194 r3195 213 213 else: 214 214 if IFD[258][2][0] == 16: 215 if sizexy == [3888,3072] :215 if sizexy == [3888,3072] or sizexy == [3072,3888]: 216 216 tifType = 'Dexela' 217 217 pixy = [74.8,74.8]
Note: See TracChangeset
for help on using the changeset viewer.