This repository has been archived by the owner on Sep 16, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
/
GSASIIdataGUI.py
8637 lines (8161 loc) · 426 KB
/
GSASIIdataGUI.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# -*- coding: utf-8 -*-
#GSASIIdataGUI - Main GUI routines
#========== SVN repository information ###################
# $Date: 2024-03-17 12:50:24 -0500 (Sun, 17 Mar 2024) $
# $Author: toby $
# $Revision: 5767 $
# $URL: https://subversion.xray.aps.anl.gov/pyGSAS/trunk/GSASIIdataGUI.py $
# $Id: GSASIIdataGUI.py 5767 2024-03-17 17:50:24Z toby $
#=========- SVN repository information ###################
'''
Routines for main GUI wx.Frame follow.
'''
from __future__ import division, print_function
import platform
import pickle
import time
import math
import random as ran
import copy
import sys
import os
import inspect
if '2' in platform.python_version_tuple()[0]:
import cPickle
else:
try:
import _pickle as cPickle
except:
print('Warning: failed to import the optimized Py3 pickle (_pickle)')
import pickle as cPickle
import re
import numpy as np
import numpy.ma as ma
import matplotlib as mpl
try:
import OpenGL as ogl
try:
import OpenGL.GL # this fails in <=2020 versions of Python on OS X 11.x
except ImportError:
print('Drat, patching for Big Sur')
from ctypes import util
orig_util_find_library = util.find_library
def new_util_find_library( name ):
res = orig_util_find_library( name )
if res: return res
return '/System/Library/Frameworks/'+name+'.framework/'+name
util.find_library = new_util_find_library
except ImportError:
pass
import scipy as sp
import struct as st
try:
import wx
import wx.grid as wg
#import wx.wizard as wz
#import wx.aui
import wx.lib.scrolledpanel as wxscroll
except ImportError:
pass
import GSASIIpath
GSASIIpath.SetVersionNumber("$Revision: 5767 $")
import GSASIImath as G2mth
import GSASIIIO as G2IO
import GSASIIfiles as G2fil
import GSASIIstrIO as G2stIO
import GSASIIlattice as G2lat
import GSASIIplot as G2plt
import GSASIIpwdGUI as G2pdG
import GSASIIimgGUI as G2imG
import GSASIIphsGUI as G2phG
import GSASIIspc as G2spc
import GSASIImapvars as G2mv
import GSASIIconstrGUI as G2cnstG
import GSASIIrestrGUI as G2restG
import GSASIIobj as G2obj
import GSASIIlog as log
import GSASIIctrlGUI as G2G
import GSASIIElem as G2elem
import GSASIIpwd as G2pwd
import GSASIIstrMain as G2stMn
#import GSASIIstrMath as G2stMth
import defaultIparms as dI
import GSASIIfpaGUI as G2fpa
import GSASIIseqGUI as G2seq
import GSASIIddataGUI as G2ddG
#import GSASIIspc as G2spc
try:
wx.NewIdRef
wx.NewId = wx.NewIdRef
except AttributeError:
pass
# trig functions in degrees
sind = lambda x: np.sin(x*np.pi/180.)
tand = lambda x: np.tan(x*np.pi/180.)
cosd = lambda x: np.cos(x*np.pi/180.)
# Define short names for convenience
WACV = wx.ALIGN_CENTER_VERTICAL
VERY_LIGHT_GREY = wx.Colour(240,240,240)
DULL_YELLOW = (230,230,190)
# define Ids for wx menu items
commonTrans = {'abc':np.eye(3),'a-cb':np.array([[1.,0.,0.],[0.,0.,-1.],[0.,1.,0.]]),
'ba-c':np.array([[0.,1.,0.],[1.,0.,0.],[0.,0.,-1.]]),'-cba':np.array([[0.,0.,-1.],[0.,1.,0.],[1.,0.,0.]]),
'bca':np.array([[0.,1.,0.],[0.,0.,1.],[1.,0.,0.]]),'cab':np.array([[0.,0.,1.],[1.,0.,0.],[0.,1.,0.]]),
'R->H':np.array([[1.,-1.,0.],[0.,1.,-1.],[1.,1.,1.]]),'H->R':np.array([[2./3,1./3,1./3],[-1./3,1./3,1./3],[-1./3,-2./3,1./3]]),
'P->A':np.array([[-1.,0.,0.],[0.,-1.,1.],[0.,1.,1.]]),'R->O':np.array([[-1.,0.,0.],[0.,-1.,0.],[0.,0.,1.]]),
'P->B':np.array([[-1.,0.,1.],[0.,-1.,0.],[1.,0.,1.]]),'B->P':np.array([[-.5,0.,.5],[0.,-1.,0.],[.5,0.,.5]]),
'P->C':np.array([[1.,1.,0.],[1.,-1.,0.],[0.,0.,-1.]]),'C->P':np.array([[.5,.5,0.],[.5,-.5,0.],[0.,0.,-1.]]),
'P->F':np.array([[-1.,1.,1.],[1.,-1.,1.],[1.,1.,-1.]]),'F->P':np.array([[0.,.5,.5],[.5,0.,.5],[.5,.5,0.]]),
'P->I':np.array([[0.,1.,1.],[1.,0.,1.],[1.,1.,0.]]),'I->P':np.array([[-.5,.5,.5],[.5,-.5,.5],[.5,.5,-.5]]),
'A->P':np.array([[-1.,0.,0.],[0.,-.5,.5],[0.,.5,.5]]),'O->R':np.array([[-1.,0.,0.],[0.,-1.,0.],[0.,0.,1.]]),
'abc*':np.eye(3), }
commonNames = ['abc','bca','cab','a-cb','ba-c','-cba','P->A','A->P','P->B','B->P','P->C','C->P',
'P->I','I->P','P->F','F->P','H->R','R->H','R->O','O->R','abc*','setting 1->2'] #don't put any new ones after the setting one!
def SetDefaultDData(dType,histoName,NShkl=0,NDij=0):
''' Sets default values for various histogram parameters
param: str dType: 3 letter histogram type, e.g. 'PNT'
param: str histoName: histogram name as it aoears in tree
param: NShkl int: number of generalized mustrain coefficients - depends on symmetry
param: NDij int: number of hydrostatic strain coefficients - depends on symmetry
returns dict: default data for histogram - found in data tab for phase/histogram
'''
if dType in ['SXC','SNC','SEC']:
return {'Histogram':histoName,'Show':False,'Scale':[1.0,True],'Type':dType,
'Babinet':{'BabA':[0.0,False],'BabU':[0.0,False]},
'Extinction':['Lorentzian','None', {'Tbar':0.1,'Cos2TM':0.955,
'Eg':[1.e-10,False],'Es':[1.e-10,False],'Ep':[1.e-10,False]}],
'Flack':[0.0,False]}
elif dType == 'SNT':
return {'Histogram':histoName,'Show':False,'Scale':[1.0,True],'Type':dType,
'Babinet':{'BabA':[0.0,False],'BabU':[0.0,False]},
'Extinction':['Lorentzian','None', {
'Eg':[1.e-10,False],'Es':[1.e-10,False],'Ep':[1.e-10,False]}]}
elif 'P' in dType:
return {'Histogram':histoName,'Show':False,'Scale':[1.0,False],'Type':dType,
'Pref.Ori.':['MD',1.0,False,[0,0,1],0,{},[],0.1],
'Size':['isotropic',[1.,1.,1.],[False,False,False],[0,0,1],
[1.,1.,1.,0.,0.,0.],6*[False,]],
'Mustrain':['isotropic',[1000.0,1000.0,1.0],[False,False,False],[0,0,1],
NShkl*[0.01,],NShkl*[False,]],
'HStrain':[NDij*[0.0,],NDij*[False,]],
'Extinction':[0.0,False],'Babinet':{'BabA':[0.0,False],'BabU':[0.0,False]}}
def GetDisplay(pos):
'''Gets display number (0=main display) for window position (pos). If pos outside all displays
returns None
'''
displays = np.array([list(wx.Display(i).GetGeometry()) for i in range(wx.Display.GetCount())])
for ip,display in enumerate(displays):
display[2:3] += display[0:1]
if (display[0] < pos[0] < display[2]) and (display[1] < pos[1] < display[3]):
return ip
return None
#### class definitions used for main GUI ######################################
class MergeDialog(wx.Dialog):
''' HKL transformation & merge dialog
:param wx.Frame parent: reference to parent frame (or None)
:param data: HKLF data
'''
def __init__(self,parent,data):
wx.Dialog.__init__(self,parent,wx.ID_ANY,'Setup HKLF merge',
pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
self.panel = wx.Panel(self) #just a dummy - gets destroyed in Draw!
self.data = data
self.Super = data[1]['Super']
if self.Super:
self.Trans = np.eye(4)
else:
self.Trans = np.eye(3)
self.Cent = 'noncentrosymmetric'
self.Laue = '1'
self.Class = 'triclinic'
self.Common = 'abc'
self.Draw()
def Draw(self):
def OnCent(event):
Obj = event.GetEventObject()
self.Cent = Obj.GetValue()
self.Laue = ''
wx.CallAfter(self.Draw)
def OnLaue(event):
Obj = event.GetEventObject()
self.Laue = Obj.GetValue()
wx.CallAfter(self.Draw)
def OnClass(event):
Obj = event.GetEventObject()
self.Class = Obj.GetValue()
self.Laue = ''
wx.CallAfter(self.Draw)
def OnCommon(event):
Obj = event.GetEventObject()
self.Common = Obj.GetValue()
self.Trans = commonTrans[self.Common]
wx.CallAfter(self.Draw)
self.panel.Destroy()
self.panel = wx.Panel(self)
mainSizer = wx.BoxSizer(wx.VERTICAL)
MatSizer = wx.BoxSizer(wx.HORIZONTAL)
transSizer = wx.BoxSizer(wx.VERTICAL)
transSizer.Add(wx.StaticText(self.panel,label=" HKL Transformation matrix: M*H = H'"))
if self.Super:
Trmat = wx.FlexGridSizer(4,4,0,0)
else:
commonSizer = wx.BoxSizer(wx.HORIZONTAL)
commonSizer.Add(wx.StaticText(self.panel,label=' Common transformations: '),0,WACV)
common = wx.ComboBox(self.panel,value=self.Common,choices=commonNames[:-2], #not the last two!
style=wx.CB_READONLY|wx.CB_DROPDOWN)
common.Bind(wx.EVT_COMBOBOX,OnCommon)
commonSizer.Add(common,0,WACV)
transSizer.Add(commonSizer)
Trmat = wx.FlexGridSizer(3,3,0,0)
for iy,line in enumerate(self.Trans):
for ix,val in enumerate(line):
item = G2G.ValidatedTxtCtrl(self.panel,self.Trans[iy],ix,nDig=(10,3),size=(65,25))
Trmat.Add(item)
transSizer.Add(Trmat)
MatSizer.Add((10,0),0)
MatSizer.Add(transSizer)
mainSizer.Add(MatSizer)
laueClass = ['triclinic','monoclinic','orthorhombic','trigonal(H)','trigonal(R)','tetragonal','hexagonal','cubic']
centroLaue = {'triclinic':['-1',],'monoclinic':['2/m','1 1 2/m','2/m 1 1',],
'orthorhombic':['m m m',],'trigonal(H)':['-3','-3 m 1','-3 1 m',],'trigonal(R)':['-3','-3 m'],\
'tetragonal':['4/m','4/m m m',],'hexagonal':['6/m','6/m m m',],'cubic':['m 3','m 3 m']}
noncentroLaue = {'triclinic':['1',],'monoclinic':['2','2 1 1','1 1 2','m','m 1 1','1 1 m',],
'orthorhombic':['2 2 2','m m 2','m 2 m','2 m m',],
'trigonal(H)':['3','3 1 2','3 2 1','3 m 1','3 1 m',],'trigonal(R)':['3','3 m'],
'tetragonal':['4','-4','4 2 2','4 m m','-4 2 m','-4 m 2',], \
'hexagonal':['6','-6','6 2 2','6 m m','-6 m 2','-6 2 m',],'cubic':['2 3','4 3 2','-4 3 m']}
centChoice = ['noncentrosymmetric','centrosymmetric']
mainSizer.Add(wx.StaticText(self.panel,label=' Select Laue class for new lattice:'),0)
Class = wx.ComboBox(self.panel,value=self.Class,choices=laueClass,
style=wx.CB_READONLY|wx.CB_DROPDOWN)
Class.Bind(wx.EVT_COMBOBOX,OnClass)
mainSizer.Add(Class,0)
mainSizer.Add(wx.StaticText(self.panel,label=' Target Laue symmetry:'),0)
Cent = wx.ComboBox(self.panel,value=self.Cent,choices=centChoice,
style=wx.CB_READONLY|wx.CB_DROPDOWN)
Cent.Bind(wx.EVT_COMBOBOX,OnCent)
mergeSizer = wx.BoxSizer(wx.HORIZONTAL)
mergeSizer.Add(Cent,0,WACV)
mergeSizer.Add((10,0),0)
Choice = centroLaue[self.Class]
if 'non' in self.Cent:
Choice = noncentroLaue[self.Class]
Laue = wx.ComboBox(self.panel,value=self.Laue,choices=Choice,
style=wx.CB_READONLY|wx.CB_DROPDOWN)
Laue.Bind(wx.EVT_COMBOBOX,OnLaue)
mergeSizer.Add(Laue,0,WACV)
mainSizer.Add(mergeSizer)
OkBtn = wx.Button(self.panel,-1,"Ok")
OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
cancelBtn = wx.Button(self.panel,-1,"Cancel")
cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
btnSizer = wx.BoxSizer(wx.HORIZONTAL)
btnSizer.Add((20,20),1)
if self.Laue:
btnSizer.Add(OkBtn)
btnSizer.Add((20,20),1)
btnSizer.Add(cancelBtn)
btnSizer.Add((20,20),1)
mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
self.panel.SetSizer(mainSizer)
self.panel.Fit()
self.Fit()
def GetSelection(self):
return self.Trans,self.Cent,self.Laue
def OnOk(self,event):
parent = self.GetParent()
if parent is not None: parent.Raise()
self.EndModal(wx.ID_OK)
def OnCancel(self,event):
parent = self.GetParent()
if parent is not None: parent.Raise()
self.EndModal(wx.ID_CANCEL)
def GUIpatches():
'Misc fixes that only needs to be done when running a GUI'
try: # patch for LANG environment var problem on occasional OSX machines
import locale
locale.getdefaultlocale()
except ValueError:
print('Fixing location (see https://github.com/matplotlib/matplotlib/issues/5420.)')
os.environ['LC_ALL'] = 'en_US.UTF-8'
locale.getdefaultlocale()
# PATCH: for Mavericks (OS X 10.9.x), wx produces an annoying warning about LucidaGrandeUI.
# In case stderr has been suppressed there, redirect python error output to stdout. Nobody
# else should care much about this.
sys.stderr = sys.stdout
def convVersion(version):
'''Convert a version string ("x", "x.y", "x.y.z") into a series of ints.
:returns: [i0, i1, i2] where None is used if a value is not specified
and 0 is used if a field cannot be parsed.
'''
vIntList = [None,None,None]
for i,v in enumerate(version.split('.')):
if i >= 3: break
if len(v) == 0: break
v = list(filter(None,re.split('(\\d+)',v)))[0] # conv '1b2' to '1'
try:
vIntList[i] = int(v)
except:
vIntList[i] = 0
return vIntList
def compareVersions(version1,version2):
'''Compare two version strings ("x", "x.y", "x.y.z")
Note that '3.' matches '3.1', and '3.0' matches '3.0.1'
but '3.0.0' does not match '3.0.1'
:returns: 0 if the versions match, -1 if version1 < version2,
or 1 if version1 > version2
'''
for v1,v2 in zip(convVersion(version1),convVersion(version2)):
if v1 is None or v2 is None:
return 0
if v1 < v2: return -1
if v1 > v2: return 1
return 0
# tabulate package versions that users should be warned about
versionDict = {}
'''Variable versionDict is used to designate versions of packages that
should generate warnings or error messages.
* ``versionDict['tooOld']`` is a dict with module versions that are too old and are
known to cause serious errors
* ``versionDict['tooOldWarn']`` is a dict with module versions that are
significantly out of date and should be updated, but will probably function OK.
* ``versionDict['badVersionWarn']`` is a dict of with lists of package
versions that are known to have bugs. One should select an older or
newer version of the package.
* ``versionDict['tooNewUntested']`` is a dict with module versions that have
not been tested but there is no reason to expect problems
* ``versionDict['tooNewWarn']`` is a dict with module versions that have not
been tested but there are concerns that problems may occur.
**Packages/versions to be avoided**
* Python:
* We are no longer supporting Python <=2.7 and <=3.6. Jan. 2023: We will soon start
removing code that is specific to Python 2.7.
* A problem has been noted with wx4.0.7.post2 with Python 3.10 that we can't
yet duplicate (2/4/22).
* We anticipate that Python 3.10+ will flag code that previously worked fine,
because it reports errors where we pass a floating point number to a
wxpython routine that expects a int value. We are fixing these as we learn about them.
* wxPython:
* <=2.x.x: while most of GSAS-II has been written to be
compatible with older versions of wxpython, we are now testing with
version 4.0+ only.
* wxpython 3.0 is pretty similar to 4.0, but we did see
some issues with Python 3.x.
* wxpython 4.1 has some serious internal bugs with Python 3.10+ so we recommend
4.2+ for compatibility with newer Python versions.
* 4.2.0 has a problem on MacOS where buttons w/default size are not displayed properly.
(see https://github.com/wxWidgets/Phoenix/issues/2319). Worked around (mostly?) in our code.
* Matplotlib:
* 1.x: there have been significant API changes since these versions and
significant graphics errors will occur.
* 3.1.x and 3.2.x: these versions have a known bug for plotting
3-D surfaces, such as microstrain vs crystal axes. The plots may appear
distorted as the lengths of x, y & z will not be constrained as equal.
Preferably use 3.0.x as 3.3.x is not fully tested.
* between 3.3.x vs 3.6.x there seems to be a change in how 3d graphics
are handled; we seem to have this fixed, but not sure how <3.3 will work.
Since 3.1 & 3.2 have problems; warn w/mpl <3.3.0
* numpy:
* 1.16.0: produces .gpx files that are not compatible with older
version numpy versions. This is a pretty outmoded version; upgrade.
'''
# add comments above when changing anything below
versionDict['tooOld'] = {'matplotlib': '2.', 'Python':'2.7'}
'modules that will certainly fail'
versionDict['tooOldWarn'] = {'wx': '3.99','Python':'3.6','matplotlib': '3.2.99'}
'modules that may fail and should be updated'
versionDict['badVersionWarn'] = {'numpy':['1.16.0'],
'matplotlib': ['3.1','3.2'],
'wx':['4.1']}
'versions of modules that are known to have bugs'
versionDict['tooNewWarn'] = {}
'module versions newer than what we have tested & where problems are suspected'
versionDict['tooNewUntested'] = {'Python':'3.12','wx': '4.2.2'}
'module versions newer than what we have tested but no problems are suspected'
def ShowVersions():
'''Show the versions all of required Python packages, etc.
'''
import numpy as np
import scipy as sp
import wx
import matplotlib as mpl
import OpenGL as ogl
import GSASIIpath
pkgList = [('Python',None), ('wx',wx), ('matplotlib', mpl), ('numpy',np),
('scipy',sp), ('OpenGL',ogl)]
if GSASIIpath.GetConfigValue('debug'):
try:
import IPython
pkgList.append(('IPython',IPython))
except:
pass
print ("Python/module versions loaded:")
version = '?'
versionDict['errors'] = ''
warn = False
for s,m in pkgList:
msg = ''
if s == 'Python':
pkgver = platform.python_version()
prefix = ''
msg = "from {}. ".format(sys.executable)
else:
pkgver = m.__version__
prefix = 'Package '
if s in versionDict['tooOld']:
match = compareVersions(pkgver,versionDict['tooOld'][s])
if match <= 0:
if msg: msg += ' -- '
msg += "Too old, problems are likely"
warn = True
if versionDict['errors']: versionDict['errors'] += '\n'
versionDict['errors'] += prefix + '{} version {} is too old for GSAS-II. An update is required. '.format(s,pkgver)
if s in versionDict['tooOldWarn']:
match = compareVersions(pkgver,versionDict['tooOldWarn'][s])
if match <= 0:
msg += "Version can cause problems"
warn = True
if s in versionDict['badVersionWarn']:
for v in versionDict['badVersionWarn'][s]:
if compareVersions(pkgver,v) == 0:
msg += "Version is known to be buggy"
warn = True
break
if s in versionDict['tooNewUntested'] and not warn:
match = compareVersions(pkgver,versionDict['tooNewUntested'][s])
if match >= 0:
msg += "\n "
msg += "New untested version; please keep us posted"
warn = True
if s in versionDict['tooNewWarn'] and not warn:
match = compareVersions(pkgver,versionDict['tooNewWarn'][s])
if match >= 0:
msg += "Tests incomplete w/suspected bugs; Please report problems"
print(" {:12s}{} {}".format(s+':',pkgver,msg))
Image = None
try:
from PIL import Image
except ImportError:
try:
import Image
except ImportError:
pass
if Image is None:
print ("Image module not present; Note that PIL (Python Imaging Library) or pillow is needed for some image operations")
else:
# version # can be in various places, try standard dunderscore first
for ver in '__version__','VERSION','PILLOW_VERSION':
if hasattr(Image,ver):
try:
version = eval('Image.'+ver)
break
except:
pass
print (" Image: %s (PIL or Pillow)"%version)
print (" Platform: %s %s %s"%(sys.platform,platform.architecture()[0],platform.machine()))
try:
import mkl
print (" Max threads:%s"%mkl.get_max_threads())
except:
pass
print(GSASIIpath.getG2VersionInfo())
if not GSASIIpath.TestSPG(GSASIIpath.binaryPath):
versionDict['errors'] += 'Error accessing GSAS-II binary files. Only limited functionality available.'
else:
prog = 'convcell'
if sys.platform.startswith('win'): prog += '.exe'
if not os.path.exists(os.path.join(GSASIIpath.binaryPath,prog)):
versionDict['errors'] += 'Installed binary files need an update. If you built them, rerun scons'
if warn:
print(70*'=')
print('''You are running GSAS-II in a Python environment with either untested
or known to be problematic packages, as noted above. If you are seeing
problems in running GSAS-II you are suggested to install an additional
copy of GSAS-II from one of the gsas2full installers (see
https://bit.ly/G2install). This will provide a working Python
environment as well as the latest GSAS-II version.
For information on GSAS-II package requirements see
https://gsas-ii.readthedocs.io/en/latest/packages.html''')
print(70*'=','\n')
def TestOldVersions():
'''Test the versions of required Python packages, etc.
Returns a non-empty text string if there are problems.
'''
import numpy as np
import scipy as sp
import wx
import matplotlib as mpl
import OpenGL as ogl
warnmsg = ''
errmsg = ''
for s,m in [('Python',None), ('wx',wx), ('matplotlib', mpl), ('numpy',np),
('scipy',sp), ('OpenGL',ogl)]:
if s == 'Python':
pkgver = platform.python_version()
prefix = ''
else:
pkgver = m.__version__
prefix = 'Package '+s
if s in versionDict['tooOld']:
match = compareVersions(pkgver,versionDict['tooOld'][s])
if match <= 0:
if errmsg: errmsg += '\n'
errmsg += prefix + '{} version {} is too old to run GSAS-II.'.format(s,pkgver)
if s in versionDict['tooOldWarn']:
match = compareVersions(pkgver,versionDict['tooOldWarn'][s])
if match <= 0:
if warnmsg: warnmsg += '\n'
warnmsg += prefix + '{} version {} is likely too old for GSAS-II.'.format(s,pkgver)
if s in versionDict['badVersionWarn']:
for v in versionDict['badVersionWarn'][s]:
if compareVersions(pkgver,v) == 0:
if errmsg: errmsg += '\n'
errmsg += prefix + '{} version {} causes problems with GSAS-II.'.format(s,pkgver)
break
return errmsg,warnmsg
#### GUI creation #############################################################
def GSASIImain(application):
'''Start up the GSAS-II GUI'''
ShowVersions()
GUIpatches()
if platform.python_version()[:3] == '2.7':
msg = '''The end-of-life for python 2.7 was January 1, 2020.
We strongly recommend reinstalling GSAS-II from a new installation kit as we may not be able to offer support for operation of GSAS-II in python 2.7. See instructions for details.
'''
download = ''
cmds = []
instructions = 'https://subversion.xray.aps.anl.gov/trac/pyGSAS'
if sys.platform == "win32":
download = 'https://subversion.xray.aps.anl.gov/admin_pyGSAS/downloads/gsas2full-Latest-Windows-x86_64.exe'
instructions = 'https://subversion.xray.aps.anl.gov/trac/pyGSAS/wiki/SingleStepWindowsIllustrated'
elif sys.platform == "darwin":
cmds = ['echo starting download, please wait...',
'''echo 'curl "https://subversion.xray.aps.anl.gov/admin_pyGSAS/downloads/gsas2full-Latest-MacOSX-x86_64.sh" > /tmp/g2.sh; bash /tmp/g2.sh' ''',
'curl "https://subversion.xray.aps.anl.gov/admin_pyGSAS/downloads/gsas2full-Latest-MacOSX-x86_64.sh" > /tmp/g2.sh; bash /tmp/g2.sh'
]
instructions = 'https://subversion.xray.aps.anl.gov/trac/pyGSAS/wiki/MacSingleStepInstallerFigs'
elif sys.platform.startswith("linux"):
download = 'https://subversion.xray.aps.anl.gov/admin_pyGSAS/downloads/gsas2full-Latest-Linux-x86_64.sh'
instructions = 'https://subversion.xray.aps.anl.gov/trac/pyGSAS/wiki/LinuxSingleStepInstaller'
else:
print(u'Unknown platform: '+sys.platform)
if platform.architecture()[0] != '64bit' and sys.platform == "win32":
msg += '''\nYou are currently using 32-bit Python. Please check if you are running 32-bit windows or 64-bit windows (use Start/Settings/System/About & look for "System type".
We recommend using the 64-bit installer if you have 64-bit windows.'''
download = ''
elif platform.architecture()[0] != '64bit' and sys.platform.startswith("linux"):
msg += '''\nYou are using 32-bit Python. We now only package for 64-bit linux.
If you are running 32-bit linux you will need to install Python yourself.
See instructions at https://subversion.xray.aps.anl.gov/trac/pyGSAS/wiki/InstallLinux'''
instructions = 'https://subversion.xray.aps.anl.gov/trac/pyGSAS/wiki/InstallLinux'
dlg = wx.Dialog(None,wx.ID_ANY,'End-Of-Life warning for Python 2.7',
style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
mainSizer = wx.BoxSizer(wx.VERTICAL)
txt = wx.StaticText(dlg,wx.ID_ANY,G2G.StripIndents(msg))
mainSizer.Add(txt)
txt.Wrap(400)
dlg.SetSizer(mainSizer)
btnsizer = wx.BoxSizer(wx.HORIZONTAL)
btnsizer.Add((1,1),1,wx.EXPAND,1)
OKbtn = wx.Button(dlg, wx.ID_OK,'Continue')
OKbtn.SetDefault()
OKbtn.Bind(wx.EVT_BUTTON,lambda event: dlg.EndModal(wx.ID_OK))
btnsizer.Add(OKbtn)
btn = wx.Button(dlg, wx.ID_ANY,'Show Instructions')
def openInstructions(event):
G2G.ShowWebPage(instructions,None)
btn.Bind(wx.EVT_BUTTON, openInstructions)
btnsizer.Add(btn)
if download:
btn = wx.Button(dlg, wx.ID_ANY,'Start Download')
btn.Bind(wx.EVT_BUTTON,lambda event: dlg.EndModal(wx.ID_YES))
btnsizer.Add(btn)
elif cmds:
btn = wx.Button(dlg, wx.ID_ANY,'Start Install')
btn.Bind(wx.EVT_BUTTON,lambda event: dlg.EndModal(wx.ID_CANCEL))
btnsizer.Add(btn)
#btn = wx.Button(dlg, wx.ID_CANCEL)
#btnsizer.AddButton(btn)
btnsizer.Add((1,1),1,wx.EXPAND,1)
#btnsizer.Realize()
mainSizer.Add((-1,5),1,wx.EXPAND,1)
mainSizer.Add(btnsizer,0,wx.ALIGN_CENTER,0)
mainSizer.Add((-1,10))
res = 0
try:
res = dlg.ShowModal()
finally:
dlg.Destroy()
if res == wx.ID_YES:
G2G.ShowWebPage(download,None)
G2G.ShowWebPage(instructions,None)
wx.Sleep(1)
dlg = wx.MessageDialog(None,G2G.StripIndents(
'''Download has been started in your browser; installation instructions will also be shown in a web page\n\nPress OK to exit GSAS-II, Cancel to continue.'''),
'start install',wx.OK|wx.CANCEL)
if dlg.ShowModal() == wx.ID_OK:
sys.exit()
elif res == wx.ID_CANCEL:
dlg = wx.MessageDialog(None,G2G.StripIndents(
'''Press OK to continue. Instructions will be shown in a web page.
Download and installation will start in the terminal window after you press OK. Respond to questions there.'''),
'start install',wx.OK|wx.CANCEL)
if dlg.ShowModal() == wx.ID_OK:
G2G.ShowWebPage(instructions,None)
GSASIIpath.runScript(cmds, wait=True)
sys.exit()
if versionDict['errors']:
msg = (
'\n\nGSAS-II will attempt to start, but this problem needs '+
'to be fixed for proper operation. Usually, the simplest solution '+
'will be to reinstall GSAS-II.'+
'\nSee https://bit.ly/G2install')
dlg = wx.MessageDialog(None, versionDict['errors']+msg,
'GSAS-II Installation Problem', wx.OK)
try:
dlg.ShowModal()
finally:
dlg.Destroy()
msg = ''
#sys.exit()
elif platform.python_version_tuple()[0] == '2' and int(platform.python_version_tuple()[1]) < 7:
msg = 'GSAS-II works best with Python version 3.7 or later.\nThis version is way too old: '+sys.version.split()[0]
elif platform.python_version_tuple()[0] == '3' and int(platform.python_version_tuple()[1]) < 6:
msg = 'GSAS-II works best with Python version 3.7 or later.\nThis version is too old: '+sys.version.split()[0]
else:
msg = ''
if msg:
dlg = wx.MessageDialog(None, msg, 'Python version error', wx.OK)
try:
dlg.ShowModal()
finally:
dlg.Destroy()
sys.exit()
application.main = GSASII(None) # application.main is the main wx.Frame (G2frame in most places)
application.SetTopWindow(application.main)
# save the current package versions
application.main.PackageVersions = G2fil.get_python_versions([wx, mpl, np, sp, ogl])
if GSASIIpath.GetConfigValue('wxInspector'):
import wx.lib.inspection as wxeye
wxeye.InspectionTool().Show()
try:
application.SetAppDisplayName('GSAS-II')
except:
pass
#application.GetTopWindow().SendSizeEvent()
application.GetTopWindow().Show(True)
application.main.UpdateTask = GSASIIpath.GetRepoUpdatesInBackground()
#### Create main frame (window) for GUI; main menu items here #######################################
class GSASII(wx.Frame):
'''Define the main GSAS-II frame and its associated menu items.
:param parent: reference to parent application
'''
def MenuBinding(self,event):
'''Called when a menu is clicked upon; looks up the binding in table
'''
log.InvokeMenuCommand(event.GetId(),self,event)
def _Add_FileMenuItems(self, parent):
'''Add items to File menu
'''
item = parent.Append(wx.ID_ANY,'&Open project...\tCtrl+O','Open a GSAS-II project (.gpx) file')
self.Bind(wx.EVT_MENU, self.OnFileOpen, id=item.GetId())
# if sys.platform == "darwin":
item = parent.Append(wx.ID_ANY,'&Open in new window...','Open a GSAS-II project (.gpx) file in a separate process')
self.Bind(wx.EVT_MENU, self.OnNewGSASII, id=item.GetId())
item = parent.Append(wx.ID_ANY,'Reopen recent...\tCtrl+E','Reopen a previously used GSAS-II project (.gpx) file')
self.Bind(wx.EVT_MENU, self.OnFileReopen, id=item.GetId())
item = parent.Append(wx.ID_ANY,'&Open w/project browser\tCtrl+B','Use project browser to a GSAS-II project (.gpx) file')
self.Bind(wx.EVT_MENU, self.OnFileBrowse, id=item.GetId())
item = parent.Append(wx.ID_ANY,'&Save project\tCtrl+S','Save project under current name')
self.Bind(wx.EVT_MENU, self.OnFileSave, id=item.GetId())
item = parent.Append(wx.ID_ANY,'Save project as...','Save current project to new file')
self.Bind(wx.EVT_MENU, self.OnFileSaveas, id=item.GetId())
item = parent.Append(wx.ID_ANY,'&New project','Create empty new project, saving current is optional')
self.Bind(wx.EVT_MENU, self.OnFileClose, id=item.GetId())
item = parent.Append(wx.ID_PREFERENCES,"&Preferences",'')
self.Bind(wx.EVT_MENU, self.OnPreferences, item)
if GSASIIpath.HowIsG2Installed() == 'svn':
item = parent.Append(wx.ID_ANY,'Edit proxy...','Edit proxy internet information (used for updates)')
self.Bind(wx.EVT_MENU, self.EditProxyInfo, id=item.GetId())
if GSASIIpath.GetConfigValue('debug'):
try:
import IPython
item = parent.Append(wx.ID_ANY,"IPython Console",'')
self.Bind(wx.EVT_MENU,
lambda event:GSASIIpath.IPyBreak(),
item)
except ImportError:
pass
def OnwxInspect(event):
import wx.lib.inspection as wxeye
wxeye.InspectionTool().Show()
item = parent.Append(wx.ID_ANY,"wx inspection tool",'')
self.Bind(wx.EVT_MENU, OnwxInspect, item)
item = parent.Append(wx.ID_ANY,'Reopen current\tCtrl+0','Reread the current GSAS-II project (.gpx) file')
self.Bind(wx.EVT_MENU, self.OnFileReread, id=item.GetId())
item = parent.Append(wx.ID_ANY,"Install GSASIIscriptable shortcut",'')
self.Bind(wx.EVT_MENU,
lambda event: GSASIIpath.makeScriptShortcut(),
item)
item = parent.Append(wx.ID_EXIT,'Exit\tALT+F4','Exit from GSAS-II')
self.Bind(wx.EVT_MENU, self.ExitMain, id=item.GetId())
def _Add_DataMenuItems(self,parent):
'''Add items to Data menu
'''
item = parent.Append(wx.ID_ANY,'Read Powder Pattern Peaks...','')
self.Bind(wx.EVT_MENU, self.OnReadPowderPeaks, id=item.GetId())
item = parent.Append(wx.ID_ANY,'Sum or Average powder data','')
self.Bind(wx.EVT_MENU, self.OnPwdrSum, id=item.GetId())
item = parent.Append(wx.ID_ANY,'Sum image data','')
self.Bind(wx.EVT_MENU, self.OnImageSum, id=item.GetId())
item = parent.Append(wx.ID_ANY,'Add new phase','')
self.Bind(wx.EVT_MENU, self.OnAddPhase, id=item.GetId())
item = parent.Append(wx.ID_ANY,'Delete phase entries','')
self.Bind(wx.EVT_MENU, self.OnDeletePhase, id=item.GetId())
item = parent.Append(wx.ID_ANY,'Rename data entry',
'Rename the selected data tree item (PWDR, HKLF or IMG)')
self.Bind(wx.EVT_MENU, self.OnRenameData, id=item.GetId())
item = parent.Append(wx.ID_ANY,'Delete data entries',
'Delete selected data items from data tree')
self.Bind(wx.EVT_MENU, self.OnDataDelete, id=item.GetId())
item = parent.Append(wx.ID_ANY,'Delete plots','Delete selected plots')
self.Bind(wx.EVT_MENU, self.OnPlotDelete, id=item.GetId())
item = parent.Append(wx.ID_ANY,'Delete sequential result entries','')
self.Bind(wx.EVT_MENU, self.OnDeleteSequential, id=item.GetId())
expandmenu = wx.Menu()
item = parent.AppendSubMenu(expandmenu,'Expand tree items',
'Expand items of type in GSAS-II data tree')
for s in 'all','IMG','PWDR','PDF','HKLF','SASD','REFD':
if s == 'all':
help = 'Expand all items in GSAS-II data tree'
else:
help = 'Expand '+s+' type items in GSAS-II data tree'
item = expandmenu.Append(wx.ID_ANY,s,help)
self.Bind(wx.EVT_MENU,self.ExpandAll,id=item.GetId())
movemenu = wx.Menu()
item = parent.AppendSubMenu(movemenu,'Move tree items',
'Move items of type items to end of GSAS-II data tree')
for s in 'IMG','PWDR','PDF','HKLF','SASD','REFD','Phase':
help = 'Move '+s+' type items to end of GSAS-II data tree'
item = movemenu.Append(wx.ID_ANY,s,help)
self.Bind(wx.EVT_MENU,self.MoveTreeItems,id=item.GetId())
def _Add_CalculateMenuItems(self,parent):
'''Add items to the Calculate menu
'''
item = parent.Append(wx.ID_ANY,'Setup PDFs','Create PDF tree entries for selected powder patterns')
self.MakePDF.append(item)
self.Bind(wx.EVT_MENU, self.OnMakePDFs, id=item.GetId())
item = parent.Append(wx.ID_ANY,'&View LS parms\tCTRL+L','View least squares parameters')
self.Bind(wx.EVT_MENU, self.OnShowLSParms, id=item.GetId())
item = parent.Append(wx.ID_ANY,'&Refine\tCTRL+R','Perform a refinement')
if len(self.Refine): # extend state for new menus to match main
state = self.Refine[0].IsEnabled()
else:
state = False
item.Enable(state)
self.Refine.append(item)
self.Bind(wx.EVT_MENU, self.OnRefine, id=item.GetId())
item = parent.Append(wx.ID_ANY,'Compute partials','Record the contribution from each phase')
self.Refine.append(item)
item.Enable(state) # disabled during sequential fits
self.Bind(wx.EVT_MENU, self.OnRefinePartials, id=item.GetId())
item = parent.Append(wx.ID_ANY,'&Parameter Impact\tCTRL+I','Perform a derivative calculation')
self.Bind(wx.EVT_MENU, self.OnDerivCalc, id=item.GetId())
item = parent.Append(wx.ID_ANY,'Save partials as csv','Save the computed partials as a csv file')
self.Refine.append(item)
item.Enable(state) # disabled during sequential fits
self.Bind(wx.EVT_MENU, self.OnSavePartials, id=item.GetId())
item = parent.Append(wx.ID_ANY,'Setup Cluster Analysis','Setup Cluster Analysis')
self.Bind(wx.EVT_MENU, self.OnClusterAnalysis, id=item.GetId())
item = parent.Append(wx.ID_ANY,'&Run Fprime','X-ray resonant scattering')
self.Bind(wx.EVT_MENU, self.OnRunFprime, id=item.GetId())
item = parent.Append(wx.ID_ANY,'&Run Absorb','x-ray absorption')
self.Bind(wx.EVT_MENU, self.OnRunAbsorb, id=item.GetId())
item = parent.Append(wx.ID_ANY,'&Run PlotXNFF','Plot X-ray, neutron & magnetic form factors')
self.Bind(wx.EVT_MENU, self.OnRunPlotXNFF, id=item.GetId())
# if GSASIIpath.GetConfigValue('debug'): # allow exceptions for debugging
# item = parent.Append(help='', id=wx.ID_ANY, kind=wx.ITEM_NORMAL,
# text='tree test')
# self.Bind(wx.EVT_MENU, self.TreeTest, id=item.GetId())
def _init_Imports(self):
'''import all the G2phase*.py & G2sfact*.py & G2pwd*.py files that
are found in the path
'''
self.ImportPhaseReaderlist = G2fil.LoadImportRoutines('phase','Phase')
self.ImportSfactReaderlist = G2fil.LoadImportRoutines('sfact','Struct_Factor')
self.ImportPowderReaderlist = G2fil.LoadImportRoutines('pwd','Powder_Data')
self.ImportSmallAngleReaderlist = G2fil.LoadImportRoutines('sad','SmallAngle_Data')
self.ImportReflectometryReaderlist = G2fil.LoadImportRoutines('rfd','Reflectometry_Data')
self.ImportPDFReaderlist = G2fil.LoadImportRoutines('pdf','PDF_Data')
self.ImportImageReaderlist = G2fil.LoadImportRoutines('img','Images')
self.ImportMenuId = {}
def testSeqRefineMode(self):
'''Returns the list of histograms included in a sequential refinement or
an empty list if a standard (non-sequential) refinement.
Also sets Menu item status depending on mode
'''
cId = GetGPXtreeItemId(self,self.root, 'Controls')
if cId:
controls = self.GPXtree.GetItemPyData(cId)
seqSetting = controls.get('Seq Data',[])
else:
seqSetting = None
for item in self.Refine:
if 'Le Bail' in item.GetItemLabel() or 'partials' in item.GetItemLabel() :
item.Enable(not seqSetting)
elif seqSetting:
item.SetItemLabel('Se&quential refine\tCtrl+R') #might fail on old wx
else:
item.SetItemLabel('&Refine\tCtrl+R') #might fail on old wx
if seqSetting:
seqMode = True
else:
seqMode = False
for menu,Id in self.ExportSeq:
menu.Enable(Id,seqMode)
for menu,Id in self.ExportNonSeq:
menu.Enable(Id,not seqMode)
return seqSetting
def PreviewFile(self,filename):
'utility to confirm we have the right file'
fp = open(filename,'r')
rdmsg = u'File '+ filename +u' begins:\n\n'
try:
rdmsg += fp.read(80)
rdmsg += '\n\nDo you want to read this file?'
except UnicodeDecodeError:
rdmsg = None
fp.close()
if rdmsg is None or not all([ord(c) < 128 and ord(c) != 0 for c in rdmsg]): # show only if ASCII
rdmsg = u'File '+ filename +u' is a binary file. Do you want to read this file?'
# it would be better to use something that
# would resize better, but this will do for now
dlg = wx.MessageDialog(self, rdmsg,'Is this the file you want?',wx.YES_NO|wx.ICON_QUESTION)
dlg.SetSize((700,300)) # does not resize on Mac
result = wx.ID_NO
try:
result = dlg.ShowModal()
finally:
dlg.Destroy()
if result == wx.ID_NO: return True
return False
def OnImportGeneric(self,reader,readerlist,label,multiple=False,
usedRanIdList=[],Preview=True,load2Tree=False):
'''Used for all imports, including Phases, datasets, images...
Called from :meth:`GSASII.OnImportPhase`, :meth:`GSASII.OnImportImage`,
:meth:`GSASII.OnImportSfact`, :meth:`GSASII.OnImportPowder`,
:meth:`GSASII.OnImportSmallAngle` and :meth:'GSASII.OnImportReflectometry`
Uses reader_objects subclassed from :class:`GSASIIobj.ImportPhase`,
:class:`GSASIIobj.ImportStructFactor`,
:class:`GSASIIobj.ImportPowderData`,
:class:`GSASIIobj.ImportSmallAngleData`
:class:`GSASIIobj.ImportReflectometryData` or
:class:`GSASIIobj.ImportImage`.
If a specific reader is specified, only that method will be called,
but if no reader is specified, every one that is potentially
compatible (by file extension) will be tried on the file(s)
selected in the Open File dialog.
:param reader_object reader: This will be a reference to
a particular object to be used to read a file or None,
if every appropriate reader should be used.
:param list readerlist: a list of reader objects appropriate for
the current read attempt. At present, this will be either
self.ImportPhaseReaderlist, self.ImportSfactReaderlist
self.ImportPowderReaderlist or self.ImportImageReaderlist
(defined in _init_Imports from the files found in the path),
but in theory this list could be tailored.
Used only when reader is None.
:param str label: string to place on the open file dialog:
Open `label` input file
:param bool multiple: True if multiple files can be selected
in the file dialog. False is default. At present True is used
only for reading of powder data.
:param list usedRanIdList: an optional list of random Ids that
have been used and should not be reused
:param bool Preview: indicates if a preview of the file should
be shown. Default is True, but set to False for image files
which are all binary.
:param bool load2Tree: indicates if the file should be loaded
into the data tree immediately (used for images only). True
only when called from :meth:`OnImportImage`; causes return
value to change to a list of True values rather than
reader objects.
:returns: a list of reader objects (rd_list) that were able
to read the specified file(s). This list may be empty.
'''
self.lastimport = ''
self.zipfile = None
singlereader = True
if reader is None:
singlereader = False
multiple = False
#print "use all formats"
choices = "any file (*.*)|*.*"
choices += "|zip archive (.zip)|*.zip"
extdict = {}
# compile a list of allowed extensions
for rd in readerlist:
fmt = rd.formatName
for extn in rd.extensionlist:
if not extdict.get(extn): extdict[extn] = []
extdict[extn] += [fmt,]
for extn in sorted(extdict.keys(),key=lambda k: k.lower()):
fmt = ''
for f in extdict[extn]:
if fmt != "": fmt += ', '
fmt += f
choices += "|" + fmt + " file (*" + extn + ")|*" + extn
else:
readerlist = [reader,]
# compile a list of allowed extensions
choices = reader.formatName + " file ("
w = ""
for extn in reader.extensionlist:
if w != "": w += ";"
w += "*" + extn
choices += w + ")|" + w
choices += "|zip archive (.zip)|*.zip"
if not reader.strictExtension:
choices += "|any file (*.*)|*.*"
# get the file(s)