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

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

Incorporate Jackson O'Donnell's gpx_manipulations code

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