source: branch/2frame/GSASIIIO.py @ 2909

Last change on this file since 2909 was 2909, checked in by toby, 5 years ago

improve window title; still working on help

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 90.3 KB
Line 
1# -*- coding: utf-8 -*-
2########### SVN repository information ###################
3# $Date: 2017-07-05 18:30:37 +0000 (Wed, 05 Jul 2017) $
4# $Author: toby $
5# $Revision: 2909 $
6# $URL: branch/2frame/GSASIIIO.py $
7# $Id: GSASIIIO.py 2909 2017-07-05 18:30:37Z toby $
8########### SVN repository information ###################
9'''
10*GSASIIIO: Misc I/O routines*
11=============================
12
13Module with miscellaneous routines for input and output. Many
14are GUI routines to interact with user.
15
16Includes support for image reading.
17
18Also includes base classes for data import routines.
19
20This module needs some work to separate wx from non-wx routines
21'''
22"""GSASIIIO: functions for IO of data
23   Copyright: 2008, Robert B. Von Dreele (Argonne National Laboratory)
24"""
25import wx
26import math
27import numpy as np
28import copy
29import cPickle
30import sys
31import re
32import random as ran
33import GSASIIpath
34GSASIIpath.SetVersionNumber("$Revision: 2909 $")
35import GSASIIdataGUI as G2gd
36import GSASIIobj as G2obj
37import GSASIIlattice as G2lat
38import GSASIImath as G2mth
39import GSASIIpwdGUI as G2pdG
40import GSASIIimgGUI as G2imG
41import GSASIIimage as G2img
42import GSASIIElem as G2el
43import GSASIIstrIO as G2stIO
44import GSASIImapvars as G2mv
45import GSASIIctrlGUI as G2G
46import os
47import os.path as ospath
48
49DEBUG = False       #=True for various prints
50TRANSP = False      #=true to transpose images for testing
51if GSASIIpath.GetConfigValue('Transpose'): TRANSP = True
52npsind = lambda x: np.sin(x*np.pi/180.)
53
54def sfloat(S):
55    'Convert a string to float. An empty field or a unconvertable value is treated as zero'
56    if S.strip():
57        try:
58            return float(S)
59        except ValueError:
60            pass
61    return 0.0
62
63def sint(S):
64    'Convert a string to int. An empty field is treated as zero'
65    if S.strip():
66        return int(S)
67    else:
68        return 0
69
70def trim(val):
71    '''Simplify a string containing leading and trailing spaces
72    as well as newlines, tabs, repeated spaces etc. into a shorter and
73    more simple string, by replacing all ranges of whitespace
74    characters with a single space.
75
76    :param str val: the string to be simplified
77
78    :returns: the (usually) shortened version of the string
79    '''
80    return re.sub('\s+', ' ', val).strip()
81
82def makeInstDict(names,data,codes):
83    inst = dict(zip(names,zip(data,data,codes)))
84    for item in inst:
85        inst[item] = list(inst[item])
86    return inst
87
88def FileDlgFixExt(dlg,file):
89    'this is needed to fix a problem in linux wx.FileDialog'
90    ext = dlg.GetWildcard().split('|')[2*dlg.GetFilterIndex()+1].strip('*')
91    if ext not in file:
92        file += ext
93    return file
94       
95def GetPowderPeaks(fileName):
96    'Read powder peaks from a file'
97    sind = lambda x: math.sin(x*math.pi/180.)
98    asind = lambda x: 180.*math.asin(x)/math.pi
99    wave = 1.54052
100    File = open(fileName,'Ur')
101    Comments = []
102    peaks = []
103    S = File.readline()
104    while S:
105        if S[:1] == '#':
106            Comments.append(S[:-1])
107        else:
108            item = S.split()
109            if len(item) == 1:
110                peaks.append([float(item[0]),1.0])
111            elif len(item) > 1:
112                peaks.append([float(item[0]),float(item[0])])
113        S = File.readline()
114    File.close()
115    if Comments:
116       print 'Comments on file:'
117       for Comment in Comments: 
118            print Comment
119            if 'wavelength' in Comment:
120                wave = float(Comment.split('=')[1])
121    Peaks = []
122    if peaks[0][0] > peaks[-1][0]:          # d-spacings - assume CuKa
123        for peak in peaks:
124            dsp = peak[0]
125            sth = wave/(2.0*dsp)
126            if sth < 1.0:
127                tth = 2.0*asind(sth)
128            else:
129                break
130            Peaks.append([tth,peak[1],True,False,0,0,0,dsp,0.0])
131    else:                                   #2-thetas - assume Cuka (for now)
132        for peak in peaks:
133            tth = peak[0]
134            dsp = wave/(2.0*sind(tth/2.0))
135            Peaks.append([tth,peak[1],True,False,0,0,0,dsp,0.0])
136    limits = [1000.,0.]
137    for peak in Peaks:
138        limits[0] = min(limits[0],peak[0])
139        limits[1] = max(limits[1],peak[0])
140    limits[0] = max(1.,(int(limits[0]-1.)/5)*5.)
141    limits[1] = min(170.,(int(limits[1]+1.)/5)*5.)
142    return Comments,Peaks,limits,wave
143
144def GetCheckImageFile(G2frame,treeId):
145    '''Try to locate an image file if the project and image have been moved
146    together. If the image file cannot be found, request the location from
147    the user.
148
149    :param wx.Frame G2frame: main GSAS-II Frame and data object
150    :param wx.Id treeId: Id for the main tree item for the image
151    :returns: Npix,imagefile,imagetag with (Npix) number of pixels,
152       imagefile, if it exists, or the name of a file that does exist or False if the user presses Cancel
153       and (imagetag) an optional image number
154
155    '''
156    Npix,Imagefile,imagetag = G2frame.GPXtree.GetImageLoc(treeId)
157    if isinstance(Imagefile,list):
158        imagefile,imagetag = Imagefile
159    else:
160        imagefile = Imagefile
161    if not os.path.exists(imagefile):
162        print 'Image file '+imagefile+' not found'
163        fil = imagefile.replace('\\','/') # windows?!
164        # see if we can find a file with same name or in a similarly named sub-dir
165        pth,fil = os.path.split(fil)
166        prevpth = None
167        while pth and pth != prevpth:
168            prevpth = pth
169            if os.path.exists(os.path.join(G2frame.dirname,fil)):
170                print 'found image file '+os.path.join(G2frame.dirname,fil)
171                imagefile = os.path.join(G2frame.dirname,fil)
172                G2frame.GPXtree.UpdateImageLoc(treeId,imagefile)
173                return Npix,imagefile,imagetag
174            pth,enddir = os.path.split(pth)
175            fil = os.path.join(enddir,fil)
176        # not found as a subdirectory, drop common parts of path for last saved & image file names
177        #    if image was .../A/B/C/imgs/ima.ge
178        #      & GPX was  .../A/B/C/refs/fil.gpx but is now .../NEW/TEST/TEST1
179        #    will look for .../NEW/TEST/TEST1/imgs/ima.ge, .../NEW/TEST/imgs/ima.ge, .../NEW/imgs/ima.ge and so on
180        Controls = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,G2frame.root, 'Controls'))
181        gpxPath = Controls.get('LastSavedAs','').replace('\\','/').split('/') # blank in older .GPX files
182        imgPath = imagefile.replace('\\','/').split('/')
183        for p1,p2 in zip(gpxPath,imgPath):
184            if p1 == p2:
185                gpxPath.pop(0),imgPath.pop(0)
186            else:
187                break
188        fil = os.path.join(*imgPath) # file with non-common prefix elements
189        prevpth = None
190        pth = os.path.abspath(G2frame.dirname)
191        while pth and pth != prevpth:
192            prevpth = pth
193            if os.path.exists(os.path.join(pth,fil)):
194                print 'found image file '+os.path.join(pth,fil)
195                imagefile = os.path.join(pth,fil)
196                G2frame.GPXtree.UpdateImageLoc(treeId,imagefile)
197                return Npix,imagefile,imagetag
198            pth,enddir = os.path.split(pth)
199        #GSASIIpath.IPyBreak()
200
201    if not os.path.exists(imagefile):
202        prevnam = os.path.split(imagefile)[1]
203        prevext = os.path.splitext(imagefile)[1]
204        wildcard = 'Image format (*'+prevext+')|*'+prevext
205        dlg = wx.FileDialog(G2frame, 'Previous image file ('+prevnam+') not found; open here', '.', prevnam,
206                            wildcard,wx.OPEN)
207        try:
208            dlg.SetFilename(''+ospath.split(imagefile)[1])
209            if dlg.ShowModal() == wx.ID_OK:
210                imagefile = dlg.GetPath()
211                G2frame.GPXtree.UpdateImageLoc(treeId,imagefile)
212            else:
213                imagefile = False
214        finally:
215            dlg.Destroy()
216    return Npix,imagefile,imagetag
217
218def EditImageParms(parent,Data,Comments,Image,filename):
219    dlg = wx.Dialog(parent, wx.ID_ANY, 'Edit image parameters',
220                    style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
221    def onClose(event):
222        dlg.EndModal(wx.ID_OK)
223    mainsizer = wx.BoxSizer(wx.VERTICAL)
224    h,w = Image.shape[:2]
225    mainsizer.Add(wx.StaticText(dlg,wx.ID_ANY,'File '+str(filename)+'\nImage size: '+str(h)+' x '+str(w)),
226        0,wx.ALIGN_LEFT|wx.ALL, 2)
227   
228    vsizer = wx.BoxSizer(wx.HORIZONTAL)
229    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Wavelength (\xC5) '),
230        0,wx.ALIGN_LEFT|wx.ALL, 2)
231    wdgt = G2G.ValidatedTxtCtrl(dlg,Data,'wavelength')
232    vsizer.Add(wdgt)
233    mainsizer.Add(vsizer,0,wx.ALIGN_LEFT|wx.ALL, 2)
234
235    vsizer = wx.BoxSizer(wx.HORIZONTAL)
236    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Pixel size (\xb5m). Width '),
237        0,wx.ALIGN_LEFT|wx.ALL, 2)
238    wdgt = G2G.ValidatedTxtCtrl(dlg,Data['pixelSize'],0,
239                                 size=(50,-1))
240    vsizer.Add(wdgt)
241    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'  Height '),wx.ALIGN_LEFT|wx.ALL, 2)
242    wdgt = G2G.ValidatedTxtCtrl(dlg,Data['pixelSize'],1,size=(50,-1))
243    vsizer.Add(wdgt)
244    mainsizer.Add(vsizer,0,wx.ALIGN_LEFT|wx.ALL, 2)
245
246    vsizer = wx.BoxSizer(wx.HORIZONTAL)
247    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Sample to detector (mm) '),
248        0,wx.ALIGN_LEFT|wx.ALL, 2)
249    wdgt = G2G.ValidatedTxtCtrl(dlg,Data,'distance')
250    vsizer.Add(wdgt)
251    mainsizer.Add(vsizer,0,wx.ALIGN_LEFT|wx.ALL, 2)
252
253    vsizer = wx.BoxSizer(wx.HORIZONTAL)
254    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Beam center (pixels). X = '),
255        0,wx.ALIGN_LEFT|wx.ALL, 2)
256    wdgt = G2G.ValidatedTxtCtrl(dlg,Data['center'],0,size=(75,-1))
257    vsizer.Add(wdgt)
258    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'  Y = '),wx.ALIGN_LEFT|wx.ALL, 2)
259    wdgt = G2G.ValidatedTxtCtrl(dlg,Data['center'],1,size=(75,-1))
260    vsizer.Add(wdgt)
261    mainsizer.Add(vsizer,0,wx.ALIGN_LEFT|wx.ALL, 2)
262
263    vsizer = wx.BoxSizer(wx.HORIZONTAL)
264    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Comments '),
265        0,wx.ALIGN_LEFT|wx.ALL, 2)
266    wdgt = G2G.ValidatedTxtCtrl(dlg,Comments,0,size=(250,-1))
267    vsizer.Add(wdgt)
268    mainsizer.Add(vsizer,0,wx.ALIGN_LEFT|wx.ALL, 2)
269
270    btnsizer = wx.StdDialogButtonSizer()
271    OKbtn = wx.Button(dlg, wx.ID_OK, 'Continue')
272    OKbtn.SetDefault()
273    OKbtn.Bind(wx.EVT_BUTTON,onClose)
274    btnsizer.AddButton(OKbtn) # not sure why this is needed
275    btnsizer.Realize()
276    mainsizer.Add(btnsizer, 1, wx.ALIGN_CENTER|wx.ALL|wx.EXPAND, 5)
277    dlg.SetSizer(mainsizer)
278    dlg.CenterOnParent()
279    dlg.ShowModal()
280   
281def LoadImage2Tree(imagefile,G2frame,Comments,Data,Npix,Image):
282    '''Load an image into the tree. Saves the location of the image, as well as the
283    ImageTag (where there is more than one image in the file), if defined.
284    '''
285    ImgNames = G2gd.GetGPXtreeDataNames(G2frame,['IMG ',])
286    TreeLbl = 'IMG '+os.path.basename(imagefile)
287    ImageTag = Data.get('ImageTag')
288    if ImageTag:
289        TreeLbl += ' #'+'%04d'%(ImageTag)
290        imageInfo = (imagefile,ImageTag)
291    else:
292        imageInfo = imagefile
293    TreeName = G2obj.MakeUniqueLabel(TreeLbl,ImgNames)
294    Id = G2frame.GPXtree.AppendItem(parent=G2frame.root,text=TreeName)
295    G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Comments'),Comments)
296    Imax = np.amax(Image)
297    if G2frame.imageDefault:
298        Data = copy.copy(G2frame.imageDefault)
299        Data['showLines'] = True
300        Data['ring'] = []
301        Data['rings'] = []
302        Data['cutoff'] = 10
303        Data['pixLimit'] = 20
304        Data['edgemin'] = 100000000
305        Data['calibdmin'] = 0.5
306        Data['calibskip'] = 0
307        Data['ellipses'] = []
308        Data['calibrant'] = ''
309        Data['GonioAngles'] = [0.,0.,0.]
310        Data['DetDepthRef'] = False
311    else:
312        Data['type'] = 'PWDR'
313        Data['color'] = GSASIIpath.GetConfigValue('Contour_color','Paired')
314        Data['tilt'] = 0.0
315        Data['rotation'] = 0.0
316        Data['showLines'] = False
317        Data['ring'] = []
318        Data['rings'] = []
319        Data['cutoff'] = 10
320        Data['pixLimit'] = 20
321        Data['calibdmin'] = 0.5
322        Data['calibskip'] = 0
323        Data['edgemin'] = 100000000
324        Data['ellipses'] = []
325        Data['GonioAngles'] = [0.,0.,0.]
326        Data['DetDepth'] = 0.
327        Data['DetDepthRef'] = False
328        Data['calibrant'] = ''
329        Data['IOtth'] = [2.0,5.0]
330        Data['LRazimuth'] = [0.,180.]
331        Data['azmthOff'] = 0.0
332        Data['outChannels'] = 2500
333        Data['outAzimuths'] = 1
334        Data['centerAzm'] = False
335        Data['fullIntegrate'] = False
336        Data['setRings'] = False
337        Data['background image'] = ['',-1.0]                           
338        Data['dark image'] = ['',-1.0]
339        Data['Flat Bkg'] = 0.0
340    Data['setDefault'] = False
341    Data['range'] = [(0,Imax),[0,Imax]]
342    G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Image Controls'),Data)
343    Masks = {'Points':[],'Rings':[],'Arcs':[],'Polygons':[],'Frames':[],'Thresholds':[(0,Imax),[0,Imax]]}
344    G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Masks'),Masks)
345    G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Stress/Strain'),
346        {'Type':'True','d-zero':[],'Sample phi':0.0,'Sample z':0.0,'Sample load':0.0})
347    G2frame.GPXtree.SetItemPyData(Id,[Npix,imageInfo])
348    G2frame.PickId = Id
349    G2frame.PickIdText = G2frame.GetTreeItemsList(G2frame.PickId)
350    G2frame.Image = Id
351
352def GetImageData(G2frame,imagefile,imageOnly=False,ImageTag=None,FormatName=''):
353    '''Read a single image with an image importer.
354
355    :param wx.Frame G2frame: main GSAS-II Frame and data object.
356    :param str imagefile: name of image file
357    :param bool imageOnly: If True return only the image,
358      otherwise  (default) return more (see below)
359    :param int/str ImageTag: specifies a particular image to be read from a file.
360      First image is read if None (default).
361    :param str formatName: the image reader formatName
362
363    :returns: an image as a numpy array or a list of four items:
364      Comments, Data, Npix and the Image, as selected by imageOnly
365
366    '''
367    # determine which formats are compatible with this file
368    primaryReaders = []
369    secondaryReaders = []
370    for rd in G2frame.ImportImageReaderlist:
371        flag = rd.ExtensionValidator(imagefile)
372        if flag is None: 
373            secondaryReaders.append(rd)
374        elif flag:
375            if not FormatName:
376                primaryReaders.append(rd)
377            elif FormatName == rd.formatName:
378                primaryReaders.append(rd)
379    if len(secondaryReaders) + len(primaryReaders) == 0:
380        print('Error: No matching format for file '+imagefile)
381        raise Exception('No image read')
382    fp = None
383    errorReport = ''
384    if not imagefile:
385        return
386    fp = open(imagefile,'Ur')
387    for rd in primaryReaders+secondaryReaders:
388        rd.ReInitialize() # purge anything from a previous read
389        fp.seek(0)  # rewind
390        rd.errors = "" # clear out any old errors
391        if not rd.ContentsValidator(fp): # rejected on cursory check
392            errorReport += "\n  "+rd.formatName + ' validator error'
393            if rd.errors: 
394                errorReport += ': '+rd.errors
395                continue
396        if imageOnly:
397            ParentFrame = None # prevent GUI access on reread
398        else:
399            ParentFrame = G2frame
400        if GSASIIpath.GetConfigValue('debug'):
401            flag = rd.Reader(imagefile,fp,ParentFrame,blocknum=ImageTag)
402        else:
403            flag = False
404            try:
405                flag = rd.Reader(imagefile,fp,ParentFrame,blocknum=ImageTag)
406            except rd.ImportException as detail:
407                rd.errors += "\n  Read exception: "+str(detail)
408            except Exception as detail:
409                import traceback
410                rd.errors += "\n  Unhandled read exception: "+str(detail)
411                rd.errors += "\n  Traceback info:\n"+str(traceback.format_exc())
412        if flag: # this read succeeded
413            if rd.Image is None:
414                raise Exception('No image read. Strange!')
415            if GSASIIpath.GetConfigValue('Transpose'):
416                print 'Transposing Image!'
417                rd.Image = rd.Image.T
418            #rd.readfilename = imagefile
419            if imageOnly:
420                return rd.Image
421            else:
422                return rd.Comments,rd.Data,rd.Npix,rd.Image
423    else:
424        print('Error reading file '+imagefile)
425        print('Error messages(s)\n'+errorReport)
426        raise Exception('No image read')   
427
428def ReadImages(G2frame,imagefile):
429    '''Read one or more images from a file and put them into the Tree
430    using image importers. Called only in :meth:`AutoIntFrame.OnTimerLoop`.
431
432    :param wx.Frame G2frame: main GSAS-II Frame and data object.
433    :param str imagefile: name of image file
434
435    :returns: a list of the id's of the IMG tree items created
436    '''
437    # determine which formats are compatible with this file
438    primaryReaders = []
439    secondaryReaders = []
440    for rd in G2frame.ImportImageReaderlist:
441        flag = rd.ExtensionValidator(imagefile)
442        if flag is None:
443            secondaryReaders.append(rd)
444        elif flag:
445            primaryReaders.append(rd)
446    if len(secondaryReaders) + len(primaryReaders) == 0:
447        print('Error: No matching format for file '+imagefile)
448        raise Exception('No image read')
449    errorReport = ''
450    fp = open(imagefile,'Ur')
451    rdbuffer = {} # create temporary storage for file reader
452    for rd in primaryReaders+secondaryReaders:
453        rd.ReInitialize() # purge anything from a previous read
454        fp.seek(0)  # rewind
455        rd.errors = "" # clear out any old errors
456        if not rd.ContentsValidator(fp): # rejected on cursory check
457            errorReport += "\n  "+rd.formatName + ' validator error'
458            if rd.errors: 
459                errorReport += ': '+rd.errors
460                continue
461        ParentFrame = G2frame
462        block = 0
463        repeat = True
464        CreatedIMGitems = []
465        while repeat: # loop if the reader asks for another pass on the file
466            block += 1
467            repeat = False
468            if GSASIIpath.GetConfigValue('debug'):
469                flag = rd.Reader(imagefile,fp,ParentFrame,blocknum=block,Buffer=rdbuffer)
470            else:
471                flag = False
472                try:
473                    flag = rd.Reader(imagefile,fp,ParentFrame,blocknum=block,Buffer=rdbuffer)
474                except rd.ImportException as detail:
475                    rd.errors += "\n  Read exception: "+str(detail)
476                except Exception as detail:
477                    import traceback
478                    rd.errors += "\n  Unhandled read exception: "+str(detail)
479                    rd.errors += "\n  Traceback info:\n"+str(traceback.format_exc())
480            if flag: # this read succeeded
481                if rd.Image is None:
482                    raise Exception('No image read. Strange!')
483                if GSASIIpath.GetConfigValue('Transpose'):
484                    print 'Transposing Image!'
485                    rd.Image = rd.Image.T
486                rd.Data['ImageTag'] = rd.repeatcount
487                LoadImage2Tree(imagefile,G2frame,rd.Comments,rd.Data,rd.Npix,rd.Image)
488                repeat = rd.repeat
489            CreatedIMGitems.append(G2frame.Image)
490        if CreatedIMGitems: return CreatedIMGitems
491    else:
492        print('Error reading file '+imagefile)
493        print('Error messages(s)\n'+errorReport)
494        return []
495        #raise Exception('No image read')   
496
497def SaveMultipleImg(G2frame):
498    if not G2frame.GPXtree.GetCount():
499        print 'no images!'
500        return
501    choices = G2gd.GetGPXtreeDataNames(G2frame,['IMG ',])
502    if len(choices) == 1:
503        names = choices
504    else:
505        dlg = G2G.G2MultiChoiceDialog(G2frame,'Stress/Strain fitting','Select images to fit:',choices)
506        dlg.SetSelections([])
507        names = []
508        if dlg.ShowModal() == wx.ID_OK:
509            names = [choices[sel] for sel in dlg.GetSelections()]
510        dlg.Destroy()
511    if not names: return
512    for name in names:
513        Id = G2gd.GetGPXtreeItemId(G2frame, G2frame.root, name)
514        Npix,imagefile,imagetag = G2frame.GPXtree.GetImageLoc(Id)
515        imroot = os.path.splitext(imagefile)[0]
516        if imagetag:
517            imroot += '_' + str(imagetag)
518        Data = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,Id, 'Image Controls'))
519        print('Writing '+imroot+'.imctrl')
520        File = open(imroot+'.imctrl','w')
521        keys = ['type','wavelength','calibrant','distance','center',
522                    'tilt','rotation','azmthOff','fullIntegrate','LRazimuth',
523                    'IOtth','outChannels','outAzimuths','invert_x','invert_y','DetDepth',
524                    'calibskip','pixLimit','cutoff','calibdmin','chisq','Flat Bkg',
525                    'binType','SampleShape','PolaVal','SampleAbs','dark image','background image']
526        for key in keys:
527            if key not in Data: continue    #uncalibrated!
528            File.write(key+':'+str(Data[key])+'\n')
529        File.close()
530        mask = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,Id, 'Masks'))
531        G2imG.CleanupMasks(mask)
532        print('Writing '+imroot+'.immask')
533        File = open(imroot+'.immask','w')
534        for key in ['Points','Rings','Arcs','Polygons','Frames','Thresholds']:
535            File.write(key+':'+str(mask[key])+'\n')
536        File.close()
537       
538def PutG2Image(filename,Comments,Data,Npix,image):
539    'Write an image as a python pickle - might be better as an .edf file?'
540    File = open(filename,'wb')
541    cPickle.dump([Comments,Data,Npix,image],File,1)
542    File.close()
543    return
544   
545def ProjFileOpen(G2frame,showProvenance=True):
546    'Read a GSAS-II project file and load into the G2 data tree'
547    if not os.path.exists(G2frame.GSASprojectfile):
548        print ('\n*** Error attempt to open project file that does not exist:\n   '+
549               str(G2frame.GSASprojectfile))
550        return
551    LastSavedUsing = None
552    file = open(G2frame.GSASprojectfile,'rb')
553    if showProvenance: print 'loading from file: ',G2frame.GSASprojectfile
554    #G2frame.SetTitle("GSAS-II data tree: "+
555    #                 os.path.split(G2frame.GSASprojectfile)[1])
556    G2frame.SetTitle("GSAS-II data tree: "+
557                     os.path.split(G2frame.GSASprojectfile)[1],1)
558    wx.BeginBusyCursor()
559    try:
560        while True:
561            try:
562                data = cPickle.load(file)
563            except EOFError:
564                break
565            datum = data[0]
566           
567            Id = G2frame.GPXtree.AppendItem(parent=G2frame.root,text=datum[0])
568            if datum[0].startswith('PWDR'):               
569                if 'ranId' not in datum[1][0]: # patch: add random Id if not present
570                    datum[1][0]['ranId'] = ran.randint(0,sys.maxint)
571                G2frame.GPXtree.SetItemPyData(Id,datum[1][:3])  #temp. trim off junk (patch?)
572            elif datum[0].startswith('HKLF'): 
573                if 'ranId' not in datum[1][0]: # patch: add random Id if not present
574                    datum[1][0]['ranId'] = ran.randint(0,sys.maxint)
575                G2frame.GPXtree.SetItemPyData(Id,datum[1])
576            else:
577                G2frame.GPXtree.SetItemPyData(Id,datum[1])             
578                if datum[0] == 'Controls' and 'LastSavedUsing' in datum[1]:
579                    LastSavedUsing = datum[1]['LastSavedUsing']
580                if datum[0] == 'Controls' and 'PythonVersions' in datum[1] and GSASIIpath.GetConfigValue('debug') and showProvenance:
581                    print('Packages used to create .GPX file:')
582                    if 'dict' in str(type(datum[1]['PythonVersions'])):  #patch
583                        for p in sorted(datum[1]['PythonVersions'],key=lambda s: s.lower()):
584                            print({:<14s}: {:s}".format(p[0],p[1]))
585                    else:
586                        for p in datum[1]['PythonVersions']:
587                            print({:<12s} {:s}".format(p[0]+':',p[1]))
588            oldPDF = False
589            for datus in data[1:]:
590#patch - 1/23/17 PDF cleanup
591                if datus[0][:4] in ['I(Q)','S(Q)','F(Q)','G(R)']:
592                    oldPDF = True
593                    data[1][1][datus[0][:4]] = copy.deepcopy(datus[1][:2])
594                    continue
595#end PDF cleanup
596                sub = G2frame.GPXtree.AppendItem(Id,datus[0])
597#patch
598                if datus[0] == 'Instrument Parameters' and len(datus[1]) == 1:
599                    if datum[0].startswith('PWDR'):
600                        datus[1] = [dict(zip(datus[1][3],zip(datus[1][0],datus[1][1],datus[1][2]))),{}]
601                    else:
602                        datus[1] = [dict(zip(datus[1][2],zip(datus[1][0],datus[1][1]))),{}]
603                    for item in datus[1][0]:               #zip makes tuples - now make lists!
604                        datus[1][0][item] = list(datus[1][0][item])
605#end patch
606                G2frame.GPXtree.SetItemPyData(sub,datus[1])
607            if 'PDF ' in datum[0][:4] and oldPDF:
608                sub = G2frame.GPXtree.AppendItem(Id,'PDF Peaks')
609                G2frame.GPXtree.SetItemPyData(sub,{'Limits':[1.,5.],'Background':[2,[0.,-0.2*np.pi],False],'Peaks':[]})
610            if datum[0].startswith('IMG'):                   #retrieve image default flag & data if set
611                Data = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,Id,'Image Controls'))
612                if Data['setDefault']:
613                    G2frame.imageDefault = Data               
614        file.close()
615        if LastSavedUsing:
616            print('GPX load successful. Last saved with GSAS-II revision '+LastSavedUsing)
617        else:
618            print('project load successful')
619        G2frame.NewPlot = True
620    except:
621        msg = wx.MessageDialog(G2frame,message="Error reading file "+
622            str(G2frame.GSASprojectfile)+". This is not a GSAS-II .gpx file",
623            caption="Load Error",style=wx.ICON_ERROR | wx.OK | wx.STAY_ON_TOP)
624        msg.ShowModal()
625    finally:
626        wx.EndBusyCursor()
627        G2frame.Status.SetStatusText('Mouse RB click item to refresh/raise; RB drag/drop to reorder')
628   
629def ProjFileSave(G2frame):
630    'Save a GSAS-II project file'
631    if not G2frame.GPXtree.IsEmpty():
632        file = open(G2frame.GSASprojectfile,'wb')
633        print 'save to file: ',G2frame.GSASprojectfile
634        # stick the file name into the tree and version info into tree so they are saved.
635        # (Controls should always be created at this point)
636        try:
637            Controls = G2frame.GPXtree.GetItemPyData(
638                G2gd.GetGPXtreeItemId(G2frame,G2frame.root, 'Controls'))
639            Controls['LastSavedAs'] = os.path.abspath(G2frame.GSASprojectfile)
640            Controls['LastSavedUsing'] = str(GSASIIpath.GetVersionNumber())
641            Controls['PythonVersions'] = G2frame.PackageVersions
642        except:
643            pass
644        wx.BeginBusyCursor()
645        try:
646            item, cookie = G2frame.GPXtree.GetFirstChild(G2frame.root)
647            while item:
648                data = []
649                name = G2frame.GPXtree.GetItemText(item)
650                data.append([name,G2frame.GPXtree.GetItemPyData(item)])
651                item2, cookie2 = G2frame.GPXtree.GetFirstChild(item)
652                while item2:
653                    name = G2frame.GPXtree.GetItemText(item2)
654                    data.append([name,G2frame.GPXtree.GetItemPyData(item2)])
655                    item2, cookie2 = G2frame.GPXtree.GetNextChild(item, cookie2)                           
656                item, cookie = G2frame.GPXtree.GetNextChild(G2frame.root, cookie)                           
657                cPickle.dump(data,file,1)
658            file.close()
659            pth = os.path.split(os.path.abspath(G2frame.GSASprojectfile))[0]
660            if GSASIIpath.GetConfigValue('Save_paths'): G2G.SaveGPXdirectory(pth)
661            G2frame.LastGPXdir = pth
662        finally:
663            wx.EndBusyCursor()
664        print('project save successful')
665
666def SaveIntegration(G2frame,PickId,data,Overwrite=False):
667    'Save image integration results as powder pattern(s)'
668    azms = G2frame.Integrate[1]
669    X = G2frame.Integrate[2][:-1]
670    N = len(X)
671    Id = G2frame.GPXtree.GetItemParent(PickId)
672    name = G2frame.GPXtree.GetItemText(Id)
673    name = name.replace('IMG ',data['type']+' ')
674    Comments = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,Id, 'Comments'))
675    if 'PWDR' in name:
676        names = ['Type','Lam','Zero','Polariz.','U','V','W','X','Y','SH/L','Azimuth'] 
677        codes = [0 for i in range(11)]
678    elif 'SASD' in name:
679        names = ['Type','Lam','Zero','Azimuth'] 
680        codes = [0 for i in range(4)]
681        X = 4.*np.pi*npsind(X/2.)/data['wavelength']    #convert to q
682    Xminmax = [X[0],X[-1]]
683    Azms = []
684    dazm = 0.
685    if data['fullIntegrate'] and data['outAzimuths'] == 1:
686        Azms = [45.0,]                              #a poor man's average?
687    else:
688        for i,azm in enumerate(azms[:-1]):
689            if azm > 360. and azms[i+1] > 360.:
690                Azms.append(G2img.meanAzm(azm%360.,azms[i+1]%360.))
691            else:   
692                Azms.append(G2img.meanAzm(azm,azms[i+1]))
693        dazm = np.min(np.abs(np.diff(azms)))/2.
694    G2frame.IntgOutList = []
695    for i,azm in enumerate(azms[:-1]):
696        Aname = name+" Azm= %.2f"%((azm+dazm)%360.)
697        item, cookie = G2frame.GPXtree.GetFirstChild(G2frame.root)
698        # if Overwrite delete any duplicate
699        if Overwrite and G2gd.GetGPXtreeItemId(G2frame,G2frame.root,Aname):
700            print('Replacing '+Aname)
701            item = G2gd.GetGPXtreeItemId(G2frame,G2frame.root,Aname)
702            G2frame.GPXtree.Delete(item)
703        else:
704            nOcc = 0
705            while item:
706                Name = G2frame.GPXtree.GetItemText(item)
707                if Aname in Name:
708                    nOcc += 1
709                item, cookie = G2frame.GPXtree.GetNextChild(G2frame.root, cookie)
710            if nOcc:
711                Aname += '(%d)'%(nOcc)
712        Sample = G2obj.SetDefaultSample()       #set as Debye-Scherrer
713        Sample['Gonio. radius'] = data['distance']
714        Sample['Omega'] = data['GonioAngles'][0]
715        Sample['Chi'] = data['GonioAngles'][1]
716        Sample['Phi'] = data['GonioAngles'][2]
717        Sample['Azimuth'] = (azm+dazm)%360.    #put here as bin center
718        polariz = 0.99    #set default polarization for synchrotron radiation!
719        for item in Comments:
720            if 'polariz' in item:
721                try:
722                    polariz = float(item.split('=')[1])
723                except:
724                    polariz = 0.99
725        if 'PWDR' in Aname:
726            parms = ['PXC',data['wavelength'],0.0,polariz,1.0,-0.10,0.4,0.30,1.0,0.0001,Azms[i]]
727        elif 'SASD' in Aname:
728            Sample['Trans'] = data['SampleAbs'][0]
729            parms = ['LXC',data['wavelength'],0.0,Azms[i]]
730        Y = G2frame.Integrate[0][i]
731        Ymin = np.min(Y)
732        Ymax = np.max(Y)
733        W = np.where(Y>0.,1./Y,1.e-6)                    #probably not true
734        Id = G2frame.GPXtree.AppendItem(parent=G2frame.root,text=Aname)
735        G2frame.IntgOutList.append(Id)
736        G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Comments'),Comments)                   
737        G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Limits'),[tuple(Xminmax),Xminmax])
738        if 'PWDR' in Aname:
739            G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Background'),[['chebyschev',1,3,1.0,0.0,0.0],
740                {'nDebye':0,'debyeTerms':[],'nPeaks':0,'peaksList':[]}])
741        inst = [dict(zip(names,zip(parms,parms,codes))),{}]
742        for item in inst[0]:
743            inst[0][item] = list(inst[0][item])
744        G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Instrument Parameters'),inst)
745        if 'PWDR' in Aname:
746            G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Sample Parameters'),Sample)
747            G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Peak List'),{'sigDict':{},'peaks':[]})
748            G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Index Peak List'),[[],[]])
749            G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Unit Cells List'),[])
750            G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Reflection Lists'),{})
751        elif 'SASD' in Aname:             
752            G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Substances'),G2pdG.SetDefaultSubstances())
753            G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Sample Parameters'),Sample)
754            G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Models'),G2pdG.SetDefaultSASDModel())
755        valuesdict = {
756            'wtFactor':1.0,
757            'Dummy':False,
758            'ranId':ran.randint(0,sys.maxint),
759            'Offset':[0.0,0.0],'delOffset':0.02*Ymax,'refOffset':-0.1*Ymax,'refDelt':0.1*Ymax,
760            'qPlot':False,'dPlot':False,'sqrtPlot':False,'Yminmax':[Ymin,Ymax]
761            }
762        G2frame.GPXtree.SetItemPyData(
763            Id,[valuesdict,
764                [np.array(X),np.array(Y),np.array(W),np.zeros(N),np.zeros(N),np.zeros(N)]])
765    return Id       #last powder pattern generated
766   
767def XYsave(G2frame,XY,labelX='X',labelY='Y',names=None):
768    'Save XY table data'
769    pth = G2G.GetExportPath(G2frame)
770    dlg = wx.FileDialog(
771        G2frame, 'Enter csv filename for XY table', pth, '',
772        'XY table file (*.csv)|*.csv',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
773    try:
774        if dlg.ShowModal() == wx.ID_OK:
775            filename = dlg.GetPath()
776            filename = os.path.splitext(filename)[0]+'.csv'
777            File = open(filename,'w')
778        else:
779            filename = None
780    finally:
781        dlg.Destroy()
782    if not filename:
783        return
784    for i in range(len(XY)):
785        if names != None:
786            header = '%s,%s(%s)\n'%(labelX,labelY,names[i])
787        else:
788            header = '%s,%s(%d)\n'%(labelX,labelY,i)
789        File.write(header)
790        for x,y in XY[i].T:
791            File.write('%.3f,%.3f\n'%(x,y))   
792    File.close()
793    print ' XY data saved to: ',filename
794           
795def PDFSave(G2frame,exports,PDFsaves):
796    'Save a PDF I(Q), S(Q), F(Q) and G(r)  in column formats'
797    import scipy.interpolate as scintp
798    for export in exports:
799        PickId = G2gd.GetGPXtreeItemId(G2frame, G2frame.root, export)
800        PDFControls = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame, PickId,'PDF Controls'))
801        if PDFsaves[0]:     #I(Q)
802            iqfilename = ospath.join(G2frame.dirname,export.replace(' ','_')[5:]+'.iq')
803            iqdata = PDFControls['I(Q)'][0]
804            iqfxn = scintp.interp1d(iqdata[0],iqdata[1],kind='linear')
805            iqfile = open(iqfilename,'w')
806            iqfile.write('#T I(Q) %s\n'%(export))
807            iqfile.write('#L Q     I(Q)\n')
808            qnew = np.arange(iqdata[0][0],iqdata[0][-1],0.005)
809            iqnew = zip(qnew,iqfxn(qnew))
810            for q,iq in iqnew:
811                iqfile.write("%15.6g %15.6g\n" % (q,iq))
812            iqfile.close()
813            print ' I(Q) saved to: ',iqfilename
814           
815        if PDFsaves[1]:     #S(Q)
816            sqfilename = ospath.join(G2frame.dirname,export.replace(' ','_')[5:]+'.sq')
817            sqdata = PDFControls['S(Q)'][1]
818            sqfxn = scintp.interp1d(sqdata[0],sqdata[1],kind='linear')
819            sqfile = open(sqfilename,'w')
820            sqfile.write('#T S(Q) %s\n'%(export))
821            sqfile.write('#L Q     S(Q)\n')
822            qnew = np.arange(sqdata[0][0],sqdata[0][-1],0.005)
823            sqnew = zip(qnew,sqfxn(qnew))
824            for q,sq in sqnew:
825                sqfile.write("%15.6g %15.6g\n" % (q,sq))
826            sqfile.close()
827            print ' S(Q) saved to: ',sqfilename
828           
829        if PDFsaves[2]:     #F(Q)
830            fqfilename = ospath.join(G2frame.dirname,export.replace(' ','_')[5:]+'.fq')
831            fqdata = PDFControls['F(Q)'][1]
832            fqfxn = scintp.interp1d(fqdata[0],fqdata[1],kind='linear')
833            fqfile = open(sqfilename,'w')
834            fqfile.write('#T F(Q) %s\n'%(export))
835            fqfile.write('#L Q     F(Q)\n')
836            qnew = np.arange(sqdata[0][0],sqdata[0][-1],0.005)
837            fqnew = zip(qnew,fqfxn(qnew))
838            for q,fq in fqnew:
839                fqfile.write("%15.6g %15.6g\n" % (q,fq))
840            fqfile.close()
841            print ' F(Q) saved to: ',fqfilename
842           
843        if PDFsaves[3]:     #G(R)
844            grfilename = ospath.join(G2frame.dirname,export.replace(' ','_')[5:]+'.gr')
845            grdata = PDFControls['G(R)'][1]
846            grfxn = scintp.interp1d(grdata[0],grdata[1],kind='linear')
847            grfile = open(grfilename,'w')
848            grfile.write('#T G(R) %s\n'%(export))
849            grfile.write('#L R     G(R)\n')
850            rnew = np.arange(grdata[0][0],grdata[0][-1],0.010)
851            grnew = zip(rnew,grfxn(rnew))
852            for r,gr in grnew:
853                grfile.write("%15.6g %15.6g\n" % (r,gr))
854            grfile.close()
855            print ' G(R) saved to: ',grfilename
856       
857        if PDFsaves[4]: #pdfGUI file for G(R)
858            pId = G2gd.GetGPXtreeItemId(G2frame, G2frame.root, 'PWDR'+export[4:])
859            Inst = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame, pId,'Instrument Parameters'))[0]
860            Limits = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame, pId,'Limits'))
861            grfilename = ospath.join(G2frame.dirname,export.replace(' ','_')[5:]+'.gr')
862            grdata = PDFControls['G(R)'][1]
863            qdata = PDFControls['I(Q)'][1][0]
864            grfxn = scintp.interp1d(grdata[0],grdata[1],kind='linear')
865            grfile = open(grfilename,'w')
866            rnew = np.arange(grdata[0][0],grdata[0][-1],0.010)
867            grnew = zip(rnew,grfxn(rnew))
868
869            grfile.write('[DEFAULT]\n')
870            grfile.write('\n')
871            grfile.write('version = GSAS-II-v'+str(GSASIIpath.GetVersionNumber())+'\n')
872            grfile.write('\n')
873            grfile.write('# input and output specifications\n')
874            grfile.write('dataformat = Qnm\n')
875            grfile.write('inputfile = %s\n'%(PDFControls['Sample']['Name']))
876            grfile.write('backgroundfile = %s\n'%(PDFControls['Sample Bkg.']['Name']))
877            grfile.write('outputtype = gr\n')
878            grfile.write('\n')
879            grfile.write('# PDF calculation setup\n')
880            if 'x' in Inst['Type']:
881                grfile.write('mode = %s\n'%('xray'))
882            elif 'N' in Inst['Type']:
883                grfile.write('mode = %s\n'%('neutron'))
884            wave = G2mth.getMeanWave(Inst)
885            grfile.write('wavelength = %.5f\n'%(wave))
886            formula = ''
887            for el in PDFControls['ElList']:
888                formula += el
889                num = PDFControls['ElList'][el]['FormulaNo']
890                if num == round(num):
891                    formula += '%d'%(int(num))
892                else:
893                    formula += '%.2f'%(num)
894            grfile.write('composition = %s\n'%(formula))
895            grfile.write('bgscale = %.3f\n'%(-PDFControls['Sample Bkg.']['Mult']))
896            highQ = 2.*np.pi/G2lat.Pos2dsp(Inst,Limits[1][1])
897            grfile.write('qmaxinst = %.2f\n'%(highQ))
898            grfile.write('qmin = %.5f\n'%(qdata[0]))
899            grfile.write('qmax = %.4f\n'%(qdata[-1]))
900            grfile.write('rmin = %.2f\n'%(PDFControls['Rmin']))
901            grfile.write('rmax = %.2f\n'%(PDFControls['Rmax']))
902            grfile.write('rstep = 0.01\n')
903           
904           
905            grfile.write('\n')
906            grfile.write('# End of config '+63*'-')
907            grfile.write('\n')
908            grfile.write('#### start data\n')
909            grfile.write('#S 1\n')
910            grfile.write('#L r($\AA$)  G($\AA^{-2}$)\n')           
911            for r,gr in grnew:
912                grfile.write("%15.2F %15.6F\n" % (r,gr))
913            grfile.close()
914            print ' G(R) saved to: ',grfilename
915   
916def PeakListSave(G2frame,file,peaks):
917    'Save powder peaks to a data file'
918    print 'save peak list to file: ',G2frame.peaklistfile
919    if not peaks:
920        dlg = wx.MessageDialog(G2frame, 'No peaks!', 'Nothing to save!', wx.OK)
921        try:
922            dlg.ShowModal()
923        finally:
924            dlg.Destroy()
925        return
926    for peak in peaks:
927        file.write("%10.4f %12.2f %10.3f %10.3f \n" % \
928            (peak[0],peak[2],peak[4],peak[6]))
929    print 'peak list saved'
930             
931def IndexPeakListSave(G2frame,peaks):
932    'Save powder peaks from the indexing list'
933    file = open(G2frame.peaklistfile,'wa')
934    print 'save index peak list to file: ',G2frame.peaklistfile
935    wx.BeginBusyCursor()
936    try:
937        if not peaks:
938            dlg = wx.MessageDialog(G2frame, 'No peaks!', 'Nothing to save!', wx.OK)
939            try:
940                dlg.ShowModal()
941            finally:
942                dlg.Destroy()
943            return
944        for peak in peaks:
945            file.write("%12.6f\n" % (peak[7]))
946        file.close()
947    finally:
948        wx.EndBusyCursor()
949    print 'index peak list saved'
950   
951class MultipleChoicesDialog(wx.Dialog):
952    '''A dialog that offers a series of choices, each with a
953    title and a wx.Choice widget. Intended to be used Modally.
954    typical input:
955
956        *  choicelist=[ ('a','b','c'), ('test1','test2'),('no choice',)]
957        *  headinglist = [ 'select a, b or c', 'select 1 of 2', 'No option here']
958       
959    selections are placed in self.chosen when OK is pressed
960
961    Also see GSASIIctrlGUI
962    '''
963    def __init__(self,choicelist,headinglist,
964                 head='Select options',
965                 title='Please select from options below',
966                 parent=None):
967        self.chosen = []
968        wx.Dialog.__init__(
969            self,parent,wx.ID_ANY,head, 
970            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
971        panel = wx.Panel(self)
972        mainSizer = wx.BoxSizer(wx.VERTICAL)
973        mainSizer.Add((10,10),1)
974        topLabl = wx.StaticText(panel,wx.ID_ANY,title)
975        mainSizer.Add(topLabl,0,wx.ALIGN_CENTER_VERTICAL|wx.CENTER,10)
976        self.ChItems = []
977        for choice,lbl in zip(choicelist,headinglist):
978            mainSizer.Add((10,10),1)
979            self.chosen.append(0)
980            topLabl = wx.StaticText(panel,wx.ID_ANY,' '+lbl)
981            mainSizer.Add(topLabl,0,wx.ALIGN_LEFT,10)
982            self.ChItems.append(wx.Choice(self, wx.ID_ANY, (100, 50), choices = choice))
983            mainSizer.Add(self.ChItems[-1],0,wx.ALIGN_CENTER,10)
984
985        OkBtn = wx.Button(panel,-1,"Ok")
986        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
987        cancelBtn = wx.Button(panel,-1,"Cancel")
988        cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
989        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
990        btnSizer.Add((20,20),1)
991        btnSizer.Add(OkBtn)
992        btnSizer.Add((20,20),1)
993        btnSizer.Add(cancelBtn)
994        btnSizer.Add((20,20),1)
995        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
996        panel.SetSizer(mainSizer)
997        panel.Fit()
998        self.Fit()
999       
1000    def OnOk(self,event):
1001        parent = self.GetParent()
1002        if parent is not None: parent.Raise()
1003        # save the results from the choice widgets
1004        self.chosen = []
1005        for w in self.ChItems:
1006            self.chosen.append(w.GetSelection())
1007        self.EndModal(wx.ID_OK)             
1008           
1009    def OnCancel(self,event):
1010        parent = self.GetParent()
1011        if parent is not None: parent.Raise()
1012        self.chosen = []
1013        self.EndModal(wx.ID_CANCEL)             
1014           
1015def ExtractFileFromZip(filename, selection=None, confirmread=True,
1016                       confirmoverwrite=True, parent=None,
1017                       multipleselect=False):
1018    '''If the filename is a zip file, extract a file from that
1019    archive.
1020
1021    :param list Selection: used to predefine the name of the file
1022      to be extracted. Filename case and zip directory name are
1023      ignored in selection; the first matching file is used.
1024
1025    :param bool confirmread: if True asks the user to confirm before expanding
1026      the only file in a zip
1027
1028    :param bool confirmoverwrite: if True asks the user to confirm
1029      before overwriting if the extracted file already exists
1030
1031    :param bool multipleselect: if True allows more than one zip
1032      file to be extracted, a list of file(s) is returned.
1033      If only one file is present, do not ask which one, otherwise
1034      offer a list of choices (unless selection is used).
1035   
1036    :returns: the name of the file that has been created or a
1037      list of files (see multipleselect)
1038
1039    If the file is not a zipfile, return the name of the input file.
1040    If the zipfile is empty or no file has been selected, return None
1041    '''
1042    import zipfile # do this now, since we can save startup time by doing this only on need
1043    import shutil
1044    zloc = os.path.split(filename)[0]
1045    if not zipfile.is_zipfile(filename):
1046        #print("not zip")
1047        return filename
1048
1049    z = zipfile.ZipFile(filename,'r')
1050    zinfo = z.infolist()
1051
1052    if len(zinfo) == 0:
1053        #print('Zip has no files!')
1054        zlist = [-1]
1055    if selection:
1056        choices = [os.path.split(i.filename)[1].lower() for i in zinfo]
1057        if selection.lower() in choices:
1058            zlist = [choices.index(selection.lower())]
1059        else:
1060            print('debug: file '+str(selection)+' was not found in '+str(filename))
1061            zlist = [-1]
1062    elif len(zinfo) == 1 and confirmread:
1063        result = wx.ID_NO
1064        dlg = wx.MessageDialog(
1065            parent,
1066            'Is file '+str(zinfo[0].filename)+
1067            ' what you want to extract from '+
1068            str(os.path.split(filename)[1])+'?',
1069            'Confirm file', 
1070            wx.YES_NO | wx.ICON_QUESTION)
1071        try:
1072            result = dlg.ShowModal()
1073        finally:
1074            dlg.Destroy()
1075        if result == wx.ID_NO:
1076            zlist = [-1]
1077        else:
1078            zlist = [0]
1079    elif len(zinfo) == 1:
1080        zlist = [0]
1081    elif multipleselect:
1082        # select one or more from a from list
1083        choices = [i.filename for i in zinfo]
1084        dlg = G2G.G2MultiChoiceDialog(parent,'Select file(s) to extract from zip file '+str(filename),
1085            'Choose file(s)',choices)
1086        if dlg.ShowModal() == wx.ID_OK:
1087            zlist = dlg.GetSelections()
1088        else:
1089            zlist = []
1090        dlg.Destroy()
1091    else:
1092        # select one from a from list
1093        choices = [i.filename for i in zinfo]
1094        dlg = wx.SingleChoiceDialog(parent,
1095            'Select file to extract from zip file'+str(filename),'Choose file',
1096            choices,)
1097        if dlg.ShowModal() == wx.ID_OK:
1098            zlist = [dlg.GetSelection()]
1099        else:
1100            zlist = [-1]
1101        dlg.Destroy()
1102       
1103    outlist = []
1104    for zindex in zlist:
1105        if zindex >= 0:
1106            efil = os.path.join(zloc, os.path.split(zinfo[zindex].filename)[1])
1107            if os.path.exists(efil) and confirmoverwrite:
1108                result = wx.ID_NO
1109                dlg = wx.MessageDialog(parent,
1110                    'File '+str(efil)+' already exists. OK to overwrite it?',
1111                    'Confirm overwrite',wx.YES_NO | wx.ICON_QUESTION)
1112                try:
1113                    result = dlg.ShowModal()
1114                finally:
1115                    dlg.Destroy()
1116                if result == wx.ID_NO:
1117                    zindex = -1
1118        if zindex >= 0:
1119            # extract the file to the current directory, regardless of it's original path
1120            #z.extract(zinfo[zindex],zloc)
1121            eloc,efil = os.path.split(zinfo[zindex].filename)
1122            outfile = os.path.join(zloc, efil)
1123            fpin = z.open(zinfo[zindex])
1124            fpout = file(outfile, "wb")
1125            shutil.copyfileobj(fpin, fpout)
1126            fpin.close()
1127            fpout.close()
1128            outlist.append(outfile)
1129    z.close()
1130    if multipleselect and len(outlist) >= 1:
1131        return outlist
1132    elif len(outlist) == 1:
1133        return outlist[0]
1134    else:
1135        return None
1136
1137######################################################################
1138# base classes for reading various types of data files
1139#   not used directly, only by subclassing
1140######################################################################
1141def BlockSelector(ChoiceList, ParentFrame=None,title='Select a block',
1142    size=None, header='Block Selector',useCancel=True):
1143    ''' Provide a wx dialog to select a block if the file contains more
1144    than one set of data and one must be selected
1145    '''
1146    if useCancel:
1147        dlg = wx.SingleChoiceDialog(
1148            ParentFrame,title, header,ChoiceList)
1149    else:
1150        dlg = wx.SingleChoiceDialog(
1151            ParentFrame,title, header,ChoiceList,
1152            style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER|wx.OK|wx.CENTRE)
1153    if size: dlg.SetSize(size)
1154    dlg.CenterOnParent()
1155    if dlg.ShowModal() == wx.ID_OK:
1156        sel = dlg.GetSelection()
1157        return sel
1158    else:
1159        return None
1160    dlg.Destroy()
1161
1162def MultipleBlockSelector(ChoiceList, ParentFrame=None,
1163    title='Select a block',size=None, header='Block Selector'):
1164    '''Provide a wx dialog to select a block of data if the
1165    file contains more than one set of data and one must be
1166    selected.
1167
1168    :returns: a list of the selected blocks
1169    '''
1170    dlg = wx.MultiChoiceDialog(ParentFrame,title, header,ChoiceList+['Select all'],
1171        wx.CHOICEDLG_STYLE)
1172    dlg.CenterOnScreen()
1173    if size: dlg.SetSize(size)
1174    if dlg.ShowModal() == wx.ID_OK:
1175        sel = dlg.GetSelections()
1176    else:
1177        return []
1178    dlg.Destroy()
1179    selected = []
1180    if len(ChoiceList) in sel:
1181        return range(len(ChoiceList))
1182    else:
1183        return sel
1184    return selected
1185
1186def MultipleChoicesSelector(choicelist, headinglist, ParentFrame=None, **kwargs):
1187    '''A modal dialog that offers a series of choices, each with a title and a wx.Choice
1188    widget. Typical input:
1189   
1190       * choicelist=[ ('a','b','c'), ('test1','test2'),('no choice',)]
1191       
1192       * headinglist = [ 'select a, b or c', 'select 1 of 2', 'No option here']
1193       
1194    optional keyword parameters are: head (window title) and title
1195    returns a list of selected indicies for each choice (or None)
1196    '''
1197    result = None
1198    dlg = MultipleChoicesDialog(choicelist,headinglist,
1199        parent=ParentFrame, **kwargs)         
1200    dlg.CenterOnParent()
1201    if dlg.ShowModal() == wx.ID_OK:
1202        result = dlg.chosen
1203    dlg.Destroy()
1204    return result
1205
1206def PhaseSelector(ChoiceList, ParentFrame=None,
1207    title='Select a phase', size=None,header='Phase Selector'):
1208    ''' Provide a wx dialog to select a phase if the file contains more
1209    than one phase
1210    '''
1211    return BlockSelector(ChoiceList,ParentFrame,title,
1212        size,header)
1213
1214######################################################################
1215def striphist(var,insChar=''):
1216    'strip a histogram number from a var name'
1217    sv = var.split(':')
1218    if len(sv) <= 1: return var
1219    if sv[1]:
1220        sv[1] = insChar
1221    return ':'.join(sv)
1222class ExportBaseclass(object):
1223    '''Defines a base class for the exporting of GSAS-II results.
1224
1225    This class is subclassed in the various exports/G2export_*.py files. Those files
1226    are imported in :meth:`GSASIIdataGUI.GSASII._init_Exports` which defines the
1227    appropriate menu items for each one and the .Exporter method is called
1228    directly from the menu item.
1229
1230    Routines may also define a .Writer method, which is used to write a single
1231    file without invoking any GUI objects.
1232    '''
1233    def __init__(self,G2frame,formatName,extension,longFormatName=None,):
1234        self.G2frame = G2frame
1235        self.formatName = formatName # short string naming file type
1236        self.extension = extension
1237        if longFormatName: # longer string naming file type
1238            self.longFormatName = longFormatName
1239        else:
1240            self.longFormatName = formatName
1241        self.OverallParms = {}
1242        self.Phases = {}
1243        self.Histograms = {}
1244        self.powderDict = {}
1245        self.xtalDict = {}
1246        self.parmDict = {}
1247        self.sigDict = {}
1248        # updated in InitExport:
1249        self.currentExportType = None # type of export that has been requested
1250        # updated in ExportSelect (when used):
1251        self.phasenam = None # a list of selected phases
1252        self.histnam = None # a list of selected histograms
1253        self.filename = None # name of file to be written (single export) or template (multiple files)
1254        self.dirname = '' # name of directory where file(s) will be written
1255        self.fullpath = '' # name of file being written -- full path
1256       
1257        # items that should be defined in a subclass of this class
1258        self.exporttype = []  # defines the type(s) of exports that the class can handle.
1259        # The following types are defined: 'project', "phase", "powder", "single"
1260        self.multiple = False # set as True if the class can export multiple phases or histograms
1261        # self.multiple is ignored for "project" exports
1262
1263    def InitExport(self,event):
1264        '''Determines the type of menu that called the Exporter and
1265        misc initialization.
1266        '''
1267        self.filename = None # name of file to be written (single export)
1268        self.dirname = '' # name of file to be written (multiple export)
1269        if event:
1270            self.currentExportType = self.G2frame.ExportLookup.get(event.Id)
1271
1272    def MakePWDRfilename(self,hist):
1273        '''Make a filename root (no extension) from a PWDR histogram name
1274
1275        :param str hist: the histogram name in data tree (starts with "PWDR ")
1276        '''
1277        file0 = ''
1278        file1 = hist[5:]
1279        # replace repeated blanks
1280        while file1 != file0:
1281            file0 = file1
1282            file1 = file0.replace('  ',' ').strip()
1283        file0 = file1.replace('Azm= ','A')
1284        # if angle has unneeded decimal places on aziumuth, remove them
1285        if file0[-3:] == '.00': file0 = file0[:-3]
1286        file0 = file0.replace('.','_')
1287        file0 = file0.replace(' ','_')
1288        return file0
1289
1290    def ExportSelect(self,AskFile='ask'):
1291        '''Selects histograms or phases when needed. Sets a default file name when
1292        requested into self.filename; always sets a default directory in self.dirname.
1293
1294        :param bool AskFile: Determines how this routine processes getting a
1295          location to store the current export(s).
1296         
1297          * if AskFile is 'ask' (default option), get the name of the file to be written;
1298            self.filename and self.dirname are always set. In the case where
1299            multiple files must be generated, the export routine should do this
1300            based on self.filename as a template.
1301          * if AskFile is 'dir', get the name of the directory to be used;
1302            self.filename is not used, but self.dirname is always set. The export routine
1303            will always generate the file name.
1304          * if AskFile is 'single', get only the name of the directory to be used when
1305            multiple items will be written (as multiple files) are used
1306            *or* a complete file name is requested when a single file
1307            name is selected. self.dirname is always set and self.filename used
1308            only when a single file is selected.
1309          * if AskFile is 'default', creates a name of the file to be used from
1310            the name of the project (.gpx) file. If the project has not been saved,
1311            then the name of file is requested.
1312            self.filename and self.dirname are always set. In the case where
1313            multiple file names must be generated, the export routine should do this
1314            based on self.filename.
1315          * if AskFile is 'default-dir', sets self.dirname from the project (.gpx)
1316            file. If the project has not been saved, then a directory is requested.
1317            self.filename is not used.
1318
1319        :returns: True in case of an error
1320        '''
1321       
1322        numselected = 1
1323        if self.currentExportType == 'phase':
1324            if len(self.Phases) == 0:
1325                self.G2frame.ErrorDialog(
1326                    'Empty project',
1327                    'Project does not contain any phases.')
1328                return True
1329            elif len(self.Phases) == 1:
1330                self.phasenam = self.Phases.keys()
1331            elif self.multiple: 
1332                choices = sorted(self.Phases.keys())
1333                phasenum = G2G.ItemSelector(choices,self.G2frame,multiple=True)
1334                if phasenum is None: return True
1335                self.phasenam = [choices[i] for i in phasenum]
1336                if not self.phasenam: return True
1337                numselected = len(self.phasenam)
1338            else:
1339                choices = sorted(self.Phases.keys())
1340                phasenum = G2G.ItemSelector(choices,self.G2frame)
1341                if phasenum is None: return True
1342                self.phasenam = [choices[phasenum]]
1343                numselected = len(self.phasenam)
1344        elif self.currentExportType == 'single':
1345            if len(self.xtalDict) == 0:
1346                self.G2frame.ErrorDialog(
1347                    'Empty project',
1348                    'Project does not contain any single crystal data.')
1349                return True
1350            elif len(self.xtalDict) == 1:
1351                self.histnam = self.xtalDict.values()
1352            elif self.multiple:
1353                choices = sorted(self.xtalDict.values())
1354                hnum = G2G.ItemSelector(choices,self.G2frame,multiple=True)
1355                if not hnum: return True
1356                self.histnam = [choices[i] for i in hnum]
1357                numselected = len(self.histnam)
1358            else:
1359                choices = sorted(self.xtalDict.values())
1360                hnum = G2G.ItemSelector(choices,self.G2frame)
1361                if hnum is None: return True
1362                self.histnam = [choices[hnum]]
1363                numselected = len(self.histnam)
1364        elif self.currentExportType == 'powder':
1365            if len(self.powderDict) == 0:
1366                self.G2frame.ErrorDialog(
1367                    'Empty project',
1368                    'Project does not contain any powder data.')
1369                return True
1370            elif len(self.powderDict) == 1:
1371                self.histnam = self.powderDict.values()
1372            elif self.multiple:
1373                choices = sorted(self.powderDict.values())
1374                hnum = G2G.ItemSelector(choices,self.G2frame,multiple=True)
1375                if not hnum: return True
1376                self.histnam = [choices[i] for i in hnum]
1377                numselected = len(self.histnam)
1378            else:
1379                choices = sorted(self.powderDict.values())
1380                hnum = G2G.ItemSelector(choices,self.G2frame)
1381                if hnum is None: return True
1382                self.histnam = [choices[hnum]]
1383                numselected = len(self.histnam)
1384        elif self.currentExportType == 'image':
1385            if len(self.Histograms) == 0:
1386                self.G2frame.ErrorDialog(
1387                    'Empty project',
1388                    'Project does not contain any images.')
1389                return True
1390            elif len(self.Histograms) == 1:
1391                self.histnam = self.Histograms.keys()
1392            else:
1393                choices = sorted(self.Histograms.keys())
1394                hnum = G2G.ItemSelector(choices,self.G2frame,multiple=self.multiple)
1395                if self.multiple:
1396                    if not hnum: return True
1397                    self.histnam = [choices[i] for i in hnum]
1398                else:
1399                    if hnum is None: return True
1400                    self.histnam = [choices[hnum]]
1401                numselected = len(self.histnam)
1402        if self.currentExportType == 'map':
1403            # search for phases with maps
1404            mapPhases = []
1405            choices = []
1406            for phasenam in sorted(self.Phases):
1407                phasedict = self.Phases[phasenam] # pointer to current phase info           
1408                if len(phasedict['General']['Map'].get('rho',[])):
1409                    mapPhases.append(phasenam)
1410                    if phasedict['General']['Map'].get('Flip'):
1411                        choices.append('Charge flip map: '+str(phasenam))
1412                    elif phasedict['General']['Map'].get('MapType'):
1413                        choices.append(
1414                            str(phasedict['General']['Map'].get('MapType'))
1415                            + ' map: ' + str(phasenam))
1416                    else:
1417                        choices.append('unknown map: '+str(phasenam))
1418            # select a map if needed
1419            if len(mapPhases) == 0:
1420                self.G2frame.ErrorDialog(
1421                    'Empty project',
1422                    'Project does not contain any maps.')
1423                return True
1424            elif len(mapPhases) == 1:
1425                self.phasenam = mapPhases
1426            else: 
1427                phasenum = G2G.ItemSelector(choices,self.G2frame,multiple=self.multiple)
1428                if self.multiple:
1429                    if not phasenum: return True
1430                    self.phasenam = [mapPhases[i] for i in phasenum]
1431                else:
1432                    if phasenum is None: return True
1433                    self.phasenam = [mapPhases[phasenum]]
1434            numselected = len(self.phasenam)
1435
1436        # items selected, now set self.dirname and usually self.filename
1437        if AskFile == 'ask' or (AskFile == 'single' and numselected == 1) or (
1438            AskFile == 'default' and not self.G2frame.GSASprojectfile
1439            ):
1440            filename = self.askSaveFile()
1441            if not filename: return True
1442            self.dirname,self.filename = os.path.split(filename)
1443        elif AskFile == 'dir' or AskFile == 'single' or (
1444            AskFile == 'default-dir' and not self.G2frame.GSASprojectfile
1445            ):
1446            self.dirname = self.askSaveDirectory()
1447            if not self.dirname: return True
1448        elif AskFile == 'default-dir' or AskFile == 'default':
1449            self.dirname,self.filename = os.path.split(
1450                os.path.splitext(self.G2frame.GSASprojectfile)[0] + self.extension
1451                )
1452        else:
1453            raise Exception('This should not happen!')
1454
1455    def loadParmDict(self):
1456        '''Load the GSAS-II refinable parameters from the tree into a dict (self.parmDict). Update
1457        refined values to those from the last cycle and set the uncertainties for the
1458        refined parameters in another dict (self.sigDict).
1459
1460        Expands the parm & sig dicts to include values derived from constraints.
1461        '''
1462        self.parmDict = {}
1463        self.sigDict = {}
1464        rigidbodyDict = {}
1465        covDict = {}
1466        consDict = {}
1467        Histograms,Phases = self.G2frame.GetUsedHistogramsAndPhasesfromTree()
1468        if self.G2frame.GPXtree.IsEmpty(): return # nothing to do
1469        item, cookie = self.G2frame.GPXtree.GetFirstChild(self.G2frame.root)
1470        while item:
1471            name = self.G2frame.GPXtree.GetItemText(item)
1472            if name == 'Rigid bodies':
1473                 rigidbodyDict = self.G2frame.GPXtree.GetItemPyData(item)
1474            elif name == 'Covariance':
1475                 covDict = self.G2frame.GPXtree.GetItemPyData(item)
1476            elif name == 'Constraints':
1477                 consDict = self.G2frame.GPXtree.GetItemPyData(item)
1478            item, cookie = self.G2frame.GPXtree.GetNextChild(self.G2frame.root, cookie)
1479        rbVary,rbDict =  G2stIO.GetRigidBodyModels(rigidbodyDict,Print=False)
1480        self.parmDict.update(rbDict)
1481        rbIds = rigidbodyDict.get('RBIds',{'Vector':[],'Residue':[]})
1482        Natoms,atomIndx,phaseVary,phaseDict,pawleyLookup,FFtables,BLtables,MFtables,maxSSwave =  G2stIO.GetPhaseData(
1483            Phases,RestraintDict=None,rbIds=rbIds,Print=False)
1484        self.parmDict.update(phaseDict)
1485        hapVary,hapDict,controlDict =  G2stIO.GetHistogramPhaseData(
1486            Phases,Histograms,Print=False,resetRefList=False)
1487        self.parmDict.update(hapDict)
1488        histVary,histDict,controlDict =  G2stIO.GetHistogramData(Histograms,Print=False)
1489        self.parmDict.update(histDict)
1490        self.parmDict.update(zip(
1491            covDict.get('varyList',[]),
1492            covDict.get('variables',[])))
1493        self.sigDict = dict(zip(
1494            covDict.get('varyList',[]),
1495            covDict.get('sig',[])))
1496        # expand to include constraints: first compile a list of constraints
1497        constList = []
1498        for item in consDict:
1499            if item.startswith('_'): continue
1500            constList += consDict[item]
1501        # now process the constraints
1502        G2mv.InitVars()
1503        constDict,fixedList,ignored = G2stIO.ProcessConstraints(constList)
1504        varyList = covDict.get('varyListStart')
1505        if varyList is None and len(constDict) == 0:
1506            # no constraints can use varyList
1507            varyList = covDict.get('varyList')
1508        elif varyList is None:
1509            # old GPX file from before pre-constraint varyList is saved
1510            print ' *** Old refinement: Please use Calculate/Refine to redo  ***'
1511            raise Exception(' *** Export aborted ***')
1512        else:
1513            varyList = list(varyList)
1514        try:
1515            groups,parmlist = G2mv.GroupConstraints(constDict)
1516            G2mv.GenerateConstraints(groups,parmlist,varyList,constDict,fixedList,self.parmDict)
1517        except:
1518            # this really should not happen
1519            print ' *** ERROR - constraints are internally inconsistent ***'
1520            errmsg, warnmsg = G2mv.CheckConstraints(varyList,constDict,fixedList)
1521            print 'Errors',errmsg
1522            if warnmsg: print 'Warnings',warnmsg
1523            raise Exception(' *** CIF creation aborted ***')
1524        # add the constrained values to the parameter dictionary
1525        G2mv.Dict2Map(self.parmDict,varyList)
1526        # and add their uncertainties into the esd dictionary (sigDict)
1527        if covDict.get('covMatrix') is not None:
1528            self.sigDict.update(G2mv.ComputeDepESD(covDict['covMatrix'],covDict['varyList'],self.parmDict))
1529
1530    def loadTree(self):
1531        '''Load the contents of the data tree into a set of dicts
1532        (self.OverallParms, self.Phases and self.Histogram as well as self.powderDict
1533        & self.xtalDict)
1534       
1535        * The childrenless data tree items are overall parameters/controls for the
1536          entire project and are placed in self.OverallParms
1537        * Phase items are placed in self.Phases
1538        * Data items are placed in self.Histogram. The key for these data items
1539          begin with a keyword, such as PWDR, IMG, HKLF,... that identifies the data type.
1540        '''
1541        self.OverallParms = {}
1542        self.powderDict = {}
1543        self.xtalDict = {}
1544        self.Phases = {}
1545        self.Histograms = {}
1546        self.SeqRefdata = None
1547        self.SeqRefhist = None
1548        if self.G2frame.GPXtree.IsEmpty(): return # nothing to do
1549        histType = None       
1550        if self.currentExportType == 'phase':
1551            # if exporting phases load them here
1552            sub = G2gd.GetGPXtreeItemId(self.G2frame,self.G2frame.root,'Phases')
1553            if not sub:
1554                print 'no phases found'
1555                return True
1556            item, cookie = self.G2frame.GPXtree.GetFirstChild(sub)
1557            while item:
1558                phaseName = self.G2frame.GPXtree.GetItemText(item)
1559                self.Phases[phaseName] =  self.G2frame.GPXtree.GetItemPyData(item)
1560                item, cookie = self.G2frame.GPXtree.GetNextChild(sub, cookie)
1561            return
1562        elif self.currentExportType == 'single':
1563            histType = 'HKLF'
1564        elif self.currentExportType == 'powder':
1565            histType = 'PWDR'
1566        elif self.currentExportType == 'image':
1567            histType = 'IMG'
1568
1569        if histType: # Loading just one kind of tree entry
1570            item, cookie = self.G2frame.GPXtree.GetFirstChild(self.G2frame.root)
1571            while item:
1572                name = self.G2frame.GPXtree.GetItemText(item)
1573                if name.startswith(histType):
1574                    if self.Histograms.get(name): # there is already an item with this name
1575                        print('Histogram name '+str(name)+' is repeated. Renaming')
1576                        if name[-1] == '9':
1577                            name = name[:-1] + '10'
1578                        elif name[-1] in '012345678':
1579                            name = name[:-1] + str(int(name[-1])+1)
1580                        else:                           
1581                            name += '-1'
1582                    self.Histograms[name] = {}
1583                    # the main info goes into Data, but the 0th
1584                    # element contains refinement results, carry
1585                    # that over too now.
1586                    self.Histograms[name]['Data'] = self.G2frame.GPXtree.GetItemPyData(item)[1]
1587                    self.Histograms[name][0] = self.G2frame.GPXtree.GetItemPyData(item)[0]
1588                    item2, cookie2 = self.G2frame.GPXtree.GetFirstChild(item)
1589                    while item2: 
1590                        child = self.G2frame.GPXtree.GetItemText(item2)
1591                        self.Histograms[name][child] = self.G2frame.GPXtree.GetItemPyData(item2)
1592                        item2, cookie2 = self.G2frame.GPXtree.GetNextChild(item, cookie2)
1593                item, cookie = self.G2frame.GPXtree.GetNextChild(self.G2frame.root, cookie)
1594            # index powder and single crystal histograms by number
1595            for hist in self.Histograms:
1596                if hist.startswith("PWDR"): 
1597                    d = self.powderDict
1598                elif hist.startswith("HKLF"): 
1599                    d = self.xtalDict
1600                else:
1601                    return                   
1602                i = self.Histograms[hist].get('hId')
1603                if i is None and not d.keys():
1604                    i = 0
1605                elif i is None or i in d.keys():
1606                    i = max(d.keys())+1
1607                d[i] = hist
1608            return
1609        # else standard load: using all interlinked phases and histograms
1610        self.Histograms,self.Phases = self.G2frame.GetUsedHistogramsAndPhasesfromTree()
1611        item, cookie = self.G2frame.GPXtree.GetFirstChild(self.G2frame.root)
1612        while item:
1613            name = self.G2frame.GPXtree.GetItemText(item)
1614            item2, cookie2 = self.G2frame.GPXtree.GetFirstChild(item)
1615            if not item2: 
1616                self.OverallParms[name] = self.G2frame.GPXtree.GetItemPyData(item)
1617            item, cookie = self.G2frame.GPXtree.GetNextChild(self.G2frame.root, cookie)
1618        # index powder and single crystal histograms
1619        for hist in self.Histograms:
1620            i = self.Histograms[hist]['hId']
1621            if hist.startswith("PWDR"): 
1622                self.powderDict[i] = hist
1623            elif hist.startswith("HKLF"): 
1624                self.xtalDict[i] = hist
1625
1626    def dumpTree(self,mode='type'):
1627        '''Print out information on the data tree dicts loaded in loadTree.
1628        Used for testing only.
1629        '''
1630        if self.SeqRefdata and self.SeqRefhist:
1631            print('Note that dumpTree does not show sequential results')
1632        print '\nOverall'
1633        if mode == 'type':
1634            def Show(arg): return type(arg)
1635        else:
1636            def Show(arg): return arg
1637        for key in self.OverallParms:
1638            print '  ',key,Show(self.OverallParms[key])
1639        print 'Phases'
1640        for key1 in self.Phases:
1641            print '    ',key1,Show(self.Phases[key1])
1642        print 'Histogram'
1643        for key1 in self.Histograms:
1644            print '    ',key1,Show(self.Histograms[key1])
1645            for key2 in self.Histograms[key1]:
1646                print '      ',key2,Show(self.Histograms[key1][key2])
1647
1648    def defaultSaveFile(self):
1649        return os.path.abspath(
1650            os.path.splitext(self.G2frame.GSASprojectfile
1651                             )[0]+self.extension)
1652       
1653    def askSaveFile(self):
1654        '''Ask the user to supply a file name
1655
1656        :returns: a file name (str) or None if Cancel is pressed
1657        '''
1658       
1659        pth = G2G.GetExportPath(self.G2frame)
1660        defnam = os.path.splitext(
1661            os.path.split(self.G2frame.GSASprojectfile)[1]
1662            )[0]+self.extension
1663        dlg = wx.FileDialog(
1664            self.G2frame, 'Input name for file to write', pth, defnam,
1665            self.longFormatName+' (*'+self.extension+')|*'+self.extension,
1666            wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
1667        dlg.CenterOnParent()
1668        try:
1669            if dlg.ShowModal() == wx.ID_OK:
1670                filename = dlg.GetPath()
1671                self.G2frame.LastExportDir = os.path.split(filename)[0]
1672                filename = os.path.splitext(filename)[0]+self.extension # make sure extension is correct
1673            else:
1674                filename = None
1675        finally:
1676            dlg.Destroy()
1677        return filename
1678
1679    def askSaveDirectory(self):
1680        '''Ask the user to supply a directory name. Path name is used as the
1681        starting point for the next export path search.
1682
1683        :returns: a directory name (str) or None if Cancel is pressed
1684        '''
1685        pth = G2G.GetExportPath(self.G2frame)
1686        dlg = wx.DirDialog(
1687            self.G2frame, 'Input directory where file(s) will be written', pth,
1688            wx.DD_DEFAULT_STYLE)
1689        dlg.CenterOnParent()
1690        try:
1691            if dlg.ShowModal() == wx.ID_OK:
1692                filename = dlg.GetPath()
1693                self.G2frame.LastExportDir = filename
1694            else:
1695                filename = None
1696        finally:
1697            dlg.Destroy()
1698        return filename
1699
1700    # Tools for file writing.
1701    def OpenFile(self,fil=None,mode='w'):
1702        '''Open the output file
1703
1704        :param str fil: The name of the file to open. If None (default)
1705          the name defaults to self.dirname + self.filename.
1706          If an extension is supplied, it is not overridded,
1707          but if not, the default extension is used.
1708        :returns: the file object opened by the routine which is also
1709          saved as self.fp
1710        '''
1711        if mode == 'd': # debug mode
1712            self.fullpath = '(stdout)'
1713            self.fp = sys.stdout
1714            return
1715        if not fil:
1716            if not os.path.splitext(self.filename)[1]:
1717                self.filename += self.extension
1718            fil = os.path.join(self.dirname,self.filename)
1719        self.fullpath = os.path.abspath(fil)
1720        self.fp = open(self.fullpath,mode)
1721        return self.fp
1722
1723    def Write(self,line):
1724        '''write a line of output, attaching a line-end character
1725
1726        :param str line: the text to be written.
1727        '''
1728        self.fp.write(line+'\n')
1729       
1730    def CloseFile(self,fp=None):
1731        '''Close a file opened in OpenFile
1732
1733        :param file fp: the file object to be closed. If None (default)
1734          file object self.fp is closed.
1735        '''
1736        if self.fp == sys.stdout: return # debug mode
1737        if fp is None:
1738            fp = self.fp
1739            self.fp = None
1740        if fp is not None: fp.close()
1741       
1742    def SetSeqRef(self,data,hist):
1743        '''Set the exporter to retrieve results from a sequential refinement
1744        rather than the main tree
1745        '''
1746        self.SeqRefdata = data
1747        self.SeqRefhist = hist
1748        data_name = data[hist]
1749        for i,val in zip(data_name['varyList'],data_name['sig']):
1750            self.sigDict[i] = val
1751            self.sigDict[striphist(i)] = val
1752        for i in data_name['parmDict']:
1753            self.parmDict[striphist(i)] = data_name['parmDict'][i]
1754            self.parmDict[i] = data_name['parmDict'][i]
1755            # zero out the dA[xyz] terms, they would only bring confusion
1756            key = i.split(':')
1757            if len(key) < 3: continue
1758            if key[2].startswith('dA'):
1759                self.parmDict[i] = 0.0
1760        for i,(val,sig) in data_name.get('depParmDict',{}).iteritems():
1761            self.parmDict[i] = val
1762            self.sigDict[i] = sig
1763        #GSASIIpath.IPyBreak()
1764               
1765    # Tools to pull information out of the data arrays
1766    def GetCell(self,phasenam):
1767        """Gets the unit cell parameters and their s.u.'s for a selected phase
1768
1769        :param str phasenam: the name for the selected phase
1770        :returns: `cellList,cellSig` where each is a 7 element list corresponding
1771          to a, b, c, alpha, beta, gamma, volume where `cellList` has the
1772          cell values and `cellSig` has their uncertainties.
1773        """
1774        if self.SeqRefdata and self.SeqRefhist:
1775            return self.GetSeqCell(phasenam,self.SeqRefdata[self.SeqRefhist])
1776        phasedict = self.Phases[phasenam] # pointer to current phase info
1777        try:
1778            pfx = str(phasedict['pId'])+'::'
1779            A,sigA = G2stIO.cellFill(pfx,phasedict['General']['SGData'],self.parmDict,self.sigDict)
1780            cellSig = G2stIO.getCellEsd(pfx,phasedict['General']['SGData'],A,
1781                self.OverallParms['Covariance'])  # returns 7 vals, includes sigVol
1782            cellList = G2lat.A2cell(A) + (G2lat.calc_V(A),)
1783            return cellList,cellSig
1784        except KeyError:
1785            cell = phasedict['General']['Cell'][1:]
1786            return cell,7*[0]
1787           
1788    def GetSeqCell(self,phasenam,data_name):
1789        """Gets the unit cell parameters and their s.u.'s for a selected phase
1790        and histogram in a sequential fit
1791
1792        :param str phasenam: the name for the selected phase
1793        :param dict data_name: the sequential refinement parameters for the selected histogram
1794        :returns: `cellList,cellSig` where each is a 7 element list corresponding
1795          to a, b, c, alpha, beta, gamma, volume where `cellList` has the
1796          cell values and `cellSig` has their uncertainties.
1797        """
1798        phasedict = self.Phases[phasenam]
1799        SGdata = phasedict['General']['SGData']
1800        pId = phasedict['pId']
1801        RecpCellTerms = G2lat.cell2A(phasedict['General']['Cell'][1:7])
1802        ESDlookup = {}
1803        Dlookup = {}
1804        varied = [striphist(i) for i in data_name['varyList']]
1805        for item,val in data_name['newCellDict'].iteritems():
1806            if item in varied:
1807                ESDlookup[val[0]] = item
1808                Dlookup[item] = val[0]
1809        A = RecpCellTerms[:]
1810        for i in range(6):
1811            var = str(pId)+'::A'+str(i)
1812            if var in ESDlookup:
1813                A[i] = data_name['newCellDict'][ESDlookup[var]][1] # override with refined value
1814        cellDict = dict(zip([str(pId)+'::A'+str(i) for i in range(6)],A))
1815        zeroDict = {i:0.0 for i in cellDict}
1816        A,zeros = G2stIO.cellFill(str(pId)+'::',SGdata,cellDict,zeroDict)
1817        covData = {
1818            'varyList': [Dlookup.get(striphist(v),v) for v in data_name['varyList']],
1819            'covMatrix': data_name['covMatrix']
1820            }
1821        return list(G2lat.A2cell(A)) + [G2lat.calc_V(A)], G2stIO.getCellEsd(str(pId)+'::',SGdata,A,covData)
1822               
1823    def GetAtoms(self,phasenam):
1824        """Gets the atoms associated with a phase. Can be used with standard
1825        or macromolecular phases
1826
1827        :param str phasenam: the name for the selected phase
1828        :returns: a list of items for eac atom where each item is a list containing:
1829          label, typ, mult, xyz, and td, where
1830
1831          * label and typ are the atom label and the scattering factor type (str)
1832          * mult is the site multiplicity (int)
1833          * xyz is contains a list with four pairs of numbers:
1834            x, y, z and fractional occupancy and
1835            their standard uncertainty (or a negative value)
1836          * td is contains a list with either one or six pairs of numbers:
1837            if one number it is U\ :sub:`iso` and with six numbers it is
1838            U\ :sub:`11`, U\ :sub:`22`, U\ :sub:`33`, U\ :sub:`12`, U\ :sub:`13` & U\ :sub:`23`
1839            paired with their standard uncertainty (or a negative value)
1840        """
1841        phasedict = self.Phases[phasenam] # pointer to current phase info           
1842        cx,ct,cs,cia = phasedict['General']['AtomPtrs']
1843        cfrac = cx+3
1844        fpfx = str(phasedict['pId'])+'::Afrac:'       
1845        atomslist = []
1846        for i,at in enumerate(phasedict['Atoms']):
1847            if phasedict['General']['Type'] == 'macromolecular':
1848                label = '%s_%s_%s_%s'%(at[ct-1],at[ct-3],at[ct-4],at[ct-2])
1849            else:
1850                label = at[ct-1]
1851            fval = self.parmDict.get(fpfx+str(i),at[cfrac])
1852            fsig = self.sigDict.get(fpfx+str(i),-0.009)
1853            mult = at[cs+1]
1854            typ = at[ct]
1855            xyz = []
1856            for j,v in enumerate(('x','y','z')):
1857                val = at[cx+j]
1858                pfx = str(phasedict['pId']) + '::A' + v + ':' + str(i)
1859                val = self.parmDict.get(pfx, val)
1860                dpfx = str(phasedict['pId'])+'::dA'+v+':'+str(i)
1861                sig = self.sigDict.get(dpfx,-0.000009)
1862                xyz.append((val,sig))
1863            xyz.append((fval,fsig))
1864            td = []
1865            if at[cia] == 'I':
1866                pfx = str(phasedict['pId'])+'::AUiso:'+str(i)
1867                val = self.parmDict.get(pfx,at[cia+1])
1868                sig = self.sigDict.get(pfx,-0.0009)
1869                td.append((val,sig))
1870            else:
1871                for i,var in enumerate(('AU11','AU22','AU33','AU12','AU13','AU23')):
1872                    pfx = str(phasedict['pId'])+'::'+var+':'+str(i)
1873                    val = self.parmDict.get(pfx,at[cia+2+i])
1874                    sig = self.sigDict.get(pfx,-0.0009)
1875                    td.append((val,sig))
1876            atomslist.append((label,typ,mult,xyz,td))
1877        return atomslist
1878######################################################################
1879def ExportPowderList(G2frame):
1880    '''Returns a list of extensions supported by :func:`GSASIIIO:ExportPowder`
1881    This is used in :meth:`GSASIIimgGUI.AutoIntFrame` only.
1882   
1883    :param wx.Frame G2frame: the GSAS-II main data tree window
1884    '''
1885    extList = []
1886    for obj in G2frame.exporterlist:
1887        if 'powder' in obj.exporttype:
1888            try:
1889                obj.Writer
1890                extList.append(obj.extension)
1891            except AttributeError:
1892                pass
1893    return extList
1894
1895def ExportPowder(G2frame,TreeName,fileroot,extension):
1896    '''Writes a single powder histogram using the Export routines.
1897    This is used in :meth:`GSASIIimgGUI.AutoIntFrame` only.
1898
1899    :param wx.Frame G2frame: the GSAS-II main data tree window
1900    :param str TreeName: the name of the histogram (PWDR ...) in the data tree
1901    :param str fileroot: name for file to be written, extension ignored
1902    :param str extension: extension for file to be written (start with '.'). Must
1903      match a powder export routine that has a Writer object.
1904    '''
1905    filename = os.path.abspath(os.path.splitext(fileroot)[0]+extension)
1906    for obj in G2frame.exporterlist:
1907        if obj.extension == extension and 'powder' in obj.exporttype:
1908            obj.currentExportType = 'powder'
1909            obj.InitExport(None)
1910            obj.loadTree() # load all histograms in tree into dicts
1911            if TreeName not in obj.Histograms:
1912                raise Exception('Histogram not found: '+str(TreeName))
1913            try:
1914                obj.Writer
1915            except AttributeError:
1916                continue
1917            try:
1918                obj.Writer(TreeName,filename)
1919                return
1920            except Exception,err:
1921                print('Export Routine for '+extension+' failed.')
1922                print err
1923    else:
1924        print('No Export routine supports extension '+extension)
1925
1926def ExportSequential(G2frame,data,obj,exporttype):
1927    '''
1928    Used to export from every phase/dataset in a sequential refinement using
1929    a .Writer method for either projects or phases. Prompts to select histograms
1930    and for phase exports, which phase(s).
1931
1932    :param wx.Frame G2frame: the GSAS-II main data tree window
1933    :param dict data: the sequential refinement data object
1934    :param str exporttype: indicates the type of export ('project' or 'phase')
1935    '''
1936    if len(data['histNames']) == 0:
1937        G2G.G2MessageBox(G2frame,'There are no sequential histograms','Warning')
1938    obj.InitExport(None)
1939    obj.loadTree()
1940    obj.loadParmDict()
1941    if len(data['histNames']) == 1:
1942        histlist = data['histNames']
1943    else:
1944        dlg = G2G.G2MultiChoiceDialog(G2frame,'Select histograms to export from list',
1945                                 'Select histograms',data['histNames'])
1946        if dlg.ShowModal() == wx.ID_OK:
1947            histlist = [data['histNames'][l] for l in dlg.GetSelections()]
1948            dlg.Destroy()
1949        else:
1950            dlg.Destroy()
1951            return
1952    if exporttype == 'Phase':
1953        phaselist = obj.Phases.keys()
1954        if len(obj.Phases) == 0:
1955            G2G.G2MessageBox(G2frame,'There are no phases in sequential ref.','Warning')
1956            return
1957        elif len(obj.Phases) > 1:
1958            dlg = G2G.G2MultiChoiceDialog(G2frame,'Select phases to export from list',
1959                                    'Select phases', phaselist)
1960            if dlg.ShowModal() == wx.ID_OK:
1961                phaselist = [phaselist[l] for l in dlg.GetSelections()]
1962                dlg.Destroy()
1963            else:
1964                dlg.Destroy()
1965                return
1966        filename = obj.askSaveFile()
1967        if not filename: return True
1968        obj.dirname,obj.filename = os.path.split(filename)
1969        print('Writing output to file '+str(obj.filename)+"...")
1970        mode = 'w'
1971        for p in phaselist:
1972            for h in histlist:
1973                obj.SetSeqRef(data,h)
1974                #GSASIIpath.IPyBreak()
1975                obj.Writer(h,phasenam=p,mode=mode)
1976                mode = 'a'
1977        print('...done')
1978    elif exporttype == 'Project':  # note that the CIF exporter is not yet ready for this
1979        filename = obj.askSaveFile()
1980        if not filename: return True
1981        obj.dirname,obj.filename = os.path.split(filename)
1982        print('Writing output to file '+str(obj.filename)+"...")
1983        mode = 'w'
1984        for h in histlist:
1985            obj.SetSeqRef(data,h)
1986            obj.Writer(h,mode=mode)
1987            print('\t'+str(h)+' written')
1988            mode = 'a'
1989        print('...done')
1990    elif exporttype == 'Powder':
1991        filename = obj.askSaveFile()
1992        if not filename: return True
1993        obj.dirname,obj.filename = os.path.split(filename)
1994        print('Writing output to file '+str(obj.filename)+"...")
1995        mode = 'w'
1996        for h in histlist:
1997            obj.SetSeqRef(data,h)
1998            obj.Writer(h,mode=mode)
1999            print('\t'+str(h)+' written')
2000            mode = 'a'
2001        print('...done')
2002
2003def ReadDIFFaX(DIFFaXfile):
2004    print 'read ',DIFFaXfile
2005    Layer = {'Laue':'-1','Cell':[False,1.,1.,1.,90.,90.,90,1.],'Width':[[10.,10.],[False,False]],
2006        'Layers':[],'Stacking':[],'Transitions':[],'Toler':0.01,'AtInfo':{}}
2007    df = open(DIFFaXfile,'r')
2008    lines = df.readlines()
2009    df.close()
2010    struct = False
2011    Struct = []
2012    stack = False
2013    Stack = []
2014    trans = False
2015    Trans = []
2016    for diff in lines:
2017        diff = diff[:-1].lower()
2018        if '!'  in diff:
2019            continue
2020        while '}' in diff: #strip comments
2021            iB = diff.index('{')
2022            iF = diff.index('}')+1
2023            if iB:
2024                diff = diff[:iB]
2025            else:
2026                diff = diff[iF:]
2027        if not diff:
2028            continue
2029        if diff.strip() == 'instrumental':
2030            continue
2031        if diff.strip() == 'structural':
2032            struct = True
2033            continue
2034        elif diff.strip() == 'stacking':
2035            struct = False
2036            stack = True
2037            continue
2038        elif diff.strip() == 'transitions':
2039            stack = False
2040            trans = True
2041            continue
2042        diff = diff.strip()
2043        if struct:
2044            if diff:
2045                Struct.append(diff)
2046        elif stack:
2047            if diff:
2048                Stack.append(diff)
2049        elif trans:
2050            if diff:
2051                Trans.append(diff)
2052   
2053#STRUCTURE records
2054    laueRec = Struct[1].split()
2055    Layer['Laue'] = laueRec[0]
2056    if Layer['Laue'] == 'unknown' and len(laueRec) > 1:
2057        Layer['Toler'] = float(laueRec[1])    #tolerance for 'unknown'?
2058    if Layer['Laue'] == '2/m(1)': Layer['Laue'] = '2/m(c)'
2059    if Layer['Laue'] == '2/m(2)': Layer['Laue'] = '2/m(ab)'
2060    cell = Struct[0].split()
2061    Layer['Cell'] = [False,float(cell[0]),float(cell[1]),float(cell[2]),90.,90.,float(cell[3]),1.0]
2062    nLayers = int(Struct[2])
2063    N = 3
2064    if 'layer' not in Struct[3]:
2065        N = 4
2066        if Struct[3] != 'infinite':
2067            width = Struct[3].split()
2068            Layer['Width'][0] = [float(width[0]),float(width[1])]
2069    for nL in range(nLayers):
2070        if '=' in Struct[N]:
2071            name = Struct[N].split('=')
2072            sameas = int(name[1])-1
2073            Layer['Layers'].append({'Name':name[0],'SameAs':Layer['Layers'][sameas]['Name'],'Symm':'None','Atoms':[]})
2074            N += 1
2075            continue
2076        Symm = 'None'
2077        if 'centro' in Struct[N+1]: Symm = '-1'
2078        Layer['Layers'].append({'Name':Struct[N],'SameAs':'','Symm':Symm,'Atoms':[]})
2079        N += 2
2080        while 'layer' not in Struct[N]:
2081            atom = Struct[N][4:].split()
2082            atomType = G2el.FixValence(Struct[N][:4].replace(' ','').strip().capitalize())
2083            if atomType not in Layer['AtInfo']:
2084                Layer['AtInfo'][atomType] = G2el.GetAtomInfo(atomType)
2085            atomName = '%s(%s)'%(atomType,atom[0])
2086            newVals = []
2087            for val in atom[1:6]:
2088                if '/' in val:
2089                    newVals.append(eval(val+'.'))
2090                else:
2091                    newVals.append(float(val))               
2092            atomRec = [atomName,atomType,newVals[0],newVals[1],newVals[2],newVals[4],newVals[3]/78.9568]
2093            Layer['Layers'][-1]['Atoms'].append(atomRec)
2094            N += 1
2095            if N > len(Struct)-1:
2096                break
2097#TRANSITIONS records
2098    transArray = []
2099    N = 0
2100    for i in range(nLayers):
2101        transArray.append([])
2102        for j in range(nLayers):
2103            vals = Trans[N].split()
2104            newVals = []
2105            for val in vals[:4]:
2106                if '/' in val:
2107                    newVals.append(eval(val+'.'))
2108                else:
2109                    newVals.append(float(val))
2110            transArray[-1].append(newVals+['',False])
2111            N += 1
2112    Layer['Transitions'] = transArray
2113#STACKING records
2114    Layer['Stacking'] = [Stack[0],'']
2115    if Stack[0] == 'recursive':
2116        Layer['Stacking'][1] = Stack[1]
2117    elif Stack[0] == 'explicit':
2118        if Stack[1] == 'random':
2119            Layer['Stacking'][1] = Stack[1]
2120        else:
2121            Layer['Stacking'][1] = 'list'
2122            Layer['Stacking'].append('')
2123            for stack in Stack[2:]:
2124                Layer['Stacking'][2] += ' '+stack
2125    return Layer
2126
2127if __name__ == '__main__':
2128    import GSASIIdataGUI
2129    application = GSASIIdataGUI.GSASIImain(0)
2130    G2frame = application.main
2131    #app = wx.PySimpleApp()
2132    #G2frame = wx.Frame(None) # create a frame
2133    #frm.Show(True)
2134    #filename = '/tmp/notzip.zip'
2135    #filename = '/tmp/all.zip'
2136    #filename = '/tmp/11bmb_7652.zip'
2137   
2138    #selection=None, confirmoverwrite=True, parent=None
2139    #print ExtractFileFromZip(filename, selection='11bmb_7652.fxye',parent=frm)
2140    #print ExtractFileFromZip(filename,multipleselect=True)
2141    #                         #confirmread=False, confirmoverwrite=False)
2142
2143    # choicelist=[ ('a','b','c'),
2144    #              ('test1','test2'),('no choice',)]
2145    # titles = [ 'a, b or c', 'tests', 'No option here']
2146    # dlg = MultipleChoicesDialog(
2147    #     choicelist,titles,
2148    #     parent=frm)
2149    # if dlg.ShowModal() == wx.ID_OK:
2150    #     print 'Got OK'
2151    imagefile = '/tmp/NDC5_00237_3.ge3'
2152    Comments, Data, Npix, Image = GetImageData(G2frame,imagefile,imageOnly=False,ImageTag=None)
2153
2154    print("\n\nResults loaded to Comments, Data, Npix and Image\n\n")
2155
2156    GSASIIpath.IPyBreak_base()
Note: See TracBrowser for help on using the repository browser.