Coverage for /Users/Newville/Codes/xraylarch/larch/wxxrd/XRD1Dviewer.py: 10%

2424 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-11-09 10:08 -0600

1#!/usr/bin/env pythonw 

2''' 

3GUI for displaying 1D XRD images 

4 

5''' 

6import os 

7from os.path import expanduser 

8 

9import numpy as np 

10import sys 

11import time 

12import re 

13import math 

14 

15from threading import Thread 

16from functools import partial 

17 

18from io import StringIO 

19 

20import wx 

21import wx.lib.mixins.listctrl as listmix 

22 

23from wxmplot import PlotPanel 

24from wxmplot.basepanel import BasePanel 

25from wxutils import (SimpleText, EditableListBox, FloatCtrl, Font, 

26 pack, Popup, Button, MenuItem, Choice, Check, 

27 GridPanel, FileSave, HLine) 

28 

29import larch 

30from larch.larchlib import read_workdir, save_workdir 

31from larch.utils import nativepath, get_cwd 

32from larch.wxlib import PeriodicTablePanel, Choice, LarchWxApp 

33 

34from larch.xrd.cifdb import (cifDB, SearchCIFdb, QSTEP, QMIN, QMAX, CATEGORIES, 

35 match_database, SPACEGROUPS, create_xrdcif) 

36 

37from larch.xrd import (d_from_q,twth_from_q,q_from_twth, 

38 d_from_twth,twth_from_d,q_from_d, lambda_from_E, 

39 E_from_lambda,calc_broadening, 

40 instrumental_fit_uvw,peaklocater,peakfitter, xrd1d, 

41 peakfinder_methods, save1D) 

42 

43################################### 

44 

45VERSION = '2 (14-March-2018)' 

46 

47SLIDER_SCALE = 1000. ## sliders step in unit 1. this scales to 0.001 

48CIFSCALE = 1000 

49 

50MT01 = np.array([0,1]) 

51MT00 = np.zeros(2) 

52 

53ENERGY = 18.0 

54 

55SRCH_MTHDS = peakfinder_methods() 

56 

57CEN = wx.ALIGN_CENTER 

58LEFT = wx.ALIGN_LEFT 

59RIGHT = wx.ALIGN_RIGHT 

60ALL_CEN = wx.ALL|CEN 

61ALL_LEFT = wx.ALL|LEFT 

62ALL_RIGHT = wx.ALL|RIGHT 

63 

64BKGD_DEFAULT = {'exponent': 2,'compress': 5, 'width': 4} 

65################################### 

66 

67def YesNo(parent, question, caption = 'Yes or no?'): 

68 dlg = wx.MessageDialog(parent, question, caption, wx.YES_NO | wx.ICON_QUESTION) 

69 result = dlg.ShowModal() == wx.ID_YES 

70 dlg.Destroy() 

71 return result 

72 

73def calcFrameSize(x,y): 

74 """ 

75 Calculates an appropriate frame size based on user's display 

76 """ 

77 screenSize = wx.DisplaySize() 

78 if x > screenSize[0] * 0.9: 

79 x = int(screenSize[0] * 0.9) 

80 y = int(x*0.6) 

81 

82 return x, y 

83 

84def loadXYfile(event=None, parent=None, xrdviewer=None): 

85 

86 wildcards = 'XRD data file (*.xy)|*.xy|All files (*.*)|*.*' 

87 dlg = wx.FileDialog(parent, message='Choose 1D XRD data file', 

88 defaultDir=get_cwd(), 

89 wildcard=wildcards, 

90 style=wx.FD_OPEN|wx.FD_MULTIPLE) 

91 #style=wx.FD_OPEN) 

92 

93 path, read = None, False 

94 if dlg.ShowModal() == wx.ID_OK: 

95 read = True 

96 paths = [p.replace('\\', '/') for p in dlg.GetPaths()] 

97 dlg.Destroy() 

98 if read: 

99 for path in paths: 

100 data1dxrd = xrd1d(file=path) 

101 if xrdviewer is None: 

102 return data1dxrd 

103 else: 

104 xrdviewer.add1Ddata(data1dxrd) 

105 

106def plot_sticks(x, y): 

107 ## adds peaks to zero array to plot vertical lines of given heights 

108 xy = np.zeros((2,len(x)*3+2)) 

109 

110 xstep = (x[1] - x[0]) / 2 

111 xy[0,0] = x[ 0] - xstep 

112 xy[0,-1] = x[-1] + xstep 

113 

114 for i, xyi in enumerate(zip(x, y)): 

115 ii = i*3 

116 xy[0,ii+1:ii+4] = xyi[0] ## x 

117 xy[1,ii+2] = xyi[1] ## y 

118 return xy 

119 

120 

121class XRD1DViewerFrame(wx.Frame): 

122 def __init__(self, parent=None, _larch=None, **kws): 

123 self._larch = _larch 

124 

125 label = '1D XRD Data Analysis Software' 

126 wx.Frame.__init__(self, parent, -1, title=label, size=(1000, 650), **kws) 

127 

128 read_workdir('gsemap.dat') 

129 

130 self.default_cifdb = '%s/.larch/cif_amcsd.db' % expanduser('~') 

131 if not os.path.exists(self.default_cifdb): 

132 self.default_cifdb = 'amcsd_cif0.db' 

133 

134 self.statusbar = self.CreateStatusBar(3,wx.CAPTION) 

135 

136 panel = wx.Panel(self) 

137 self.nb = wx.Notebook(panel) 

138 

139 self.openDB() 

140 

141 ## create the page windows as children of the notebook 

142 self.xrd1Dviewer = Viewer1DXRD(self.nb,owner=self) 

143 self.xrd1Dfitting = Fitting1DXRD(self.nb,owner=self) 

144 

145 self.srch_cls = SearchCIFdb() 

146 self.amcsd_mtchlst = [] 

147 

148 ## add the pages to the notebook with the label to show on the tab 

149 self.nb.AddPage(self.xrd1Dviewer, 'Viewer') 

150 self.nb.AddPage(self.xrd1Dfitting, 'Fitting') 

151 

152 ## put the notebook in a sizer for the panel to manage the layout 

153 sizer = wx.BoxSizer() 

154 sizer.Add(self.nb, -1, wx.EXPAND) 

155 panel.SetSizer(sizer) 

156 self.XRD1DMenuBar() 

157 

158 def openDB(self,dbname=None): 

159 try: 

160 self.cifdb.close() 

161 except: 

162 pass 

163 

164 if dbname is None: 

165 dbname = self.default_cifdb 

166 

167 try: 

168 self.cifdb = cifDB(dbname=dbname) 

169 except: 

170 print('Failed to import file as database: %s' % dbname) 

171 self.cifdb = cifDB(dbname=self.default_cifdb) 

172 # print('Now using database: %s' % os.path.split(dbname)[-1]) 

173 

174 def onExit(self, event=None): 

175 

176 dlg = wx.MessageDialog(None, 'Really Quit?', 'Question', 

177 wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) 

178 

179 ret = dlg.ShowModal() 

180 if ret != wx.ID_YES: 

181 return 

182 

183 try: 

184 if hasattr(self.exit_callback, '__call__'): 

185 self.exit_callback() 

186 except: 

187 pass 

188 

189 for frame in self.xrd1Dfitting.cifframe: 

190 try: 

191 frame.closeFrame() 

192 except: 

193 pass 

194 

195 

196 try: 

197 self.cifdb.close() 

198 except: 

199 pass 

200 

201 try: 

202 self.Destroy() 

203 except: 

204 pass 

205 

206 

207 def XRD1DMenuBar(self): 

208 

209 menubar = wx.MenuBar() 

210 

211 ########################### 

212 ## diFFit1D 

213 diFFitMenu = wx.Menu() 

214 

215 MenuItem(self, diFFitMenu, '&Open 1D dataset', '', self.xrd1Dviewer.load_file) 

216 MenuItem(self, diFFitMenu, 'Open &CIFFile', '', self.xrd1Dviewer.select_CIF) 

217 MenuItem(self, diFFitMenu, 'Change larch &working folder', '', self.onFolderSelect) 

218 diFFitMenu.AppendSeparator() 

219 MenuItem(self, diFFitMenu, 'Save 1D dataset to file', '', self.save1Dxrd) 

220 MenuItem(self, diFFitMenu, 'Sa&ve displayed image to file', '', self.xrd1Dviewer.onSAVEfig) 

221 diFFitMenu.AppendSeparator() 

222 MenuItem(self, diFFitMenu, '&Quit', 'Quit program', self.onExit) 

223 

224 menubar.Append(diFFitMenu, '&File') 

225 

226 ########################### 

227 ## Analyze 

228 DatabaseMenu = wx.Menu() 

229 

230 MenuItem(self, DatabaseMenu, '&Database information', '', self.xrd1Dfitting.database_info) 

231 MenuItem(self, DatabaseMenu, '&Change database', '', self.xrd1Dfitting.open_database) 

232 

233 menubar.Append(DatabaseMenu, '&Database') 

234 

235 ########################### 

236 ## Analyze 

237 AnalyzeMenu = wx.Menu() 

238 

239 MenuItem(self, AnalyzeMenu, '&Select data for fitting', '', self.fit1Dxrd) 

240 AnalyzeMenu.AppendSeparator() 

241 MenuItem(self, AnalyzeMenu, '&Fit instrumental broadening coefficients', '', self.xrd1Dfitting.fit_instrumental) 

242 

243 menubar.Append(AnalyzeMenu, '&Analyze') 

244 

245 ########################### 

246 ## Help 

247 HelpMenu = wx.Menu() 

248 

249 MenuItem(self, HelpMenu, '&About', 'About diFFit1D viewer', self.onAbout) 

250 

251 menubar.Append(HelpMenu, '&Help') 

252 

253 ########################### 

254 ## Create Menu Bar 

255 self.SetMenuBar(menubar) 

256 self.Bind(wx.EVT_CLOSE, self.onExit) 

257 

258 def write_message(self, s, panel=0): 

259 '''write a message to the Status Bar''' 

260 self.statusbar.SetStatusText(s, panel) 

261 

262############################################## 

263#### HELP FUNCTIONS 

264 def onAbout(self, event=None): 

265 info = wx.AboutDialogInfo() 

266 info.SetName('diFFit1D XRD Data Viewer') 

267 desc = 'Using X-ray Larch version: %s' % larch.version.__version__ 

268 info.SetDescription(desc) 

269 info.SetVersion(VERSION) 

270 info.AddDeveloper('Margaret Koker: koker at cars.uchicago.edu') 

271 dlg = wx.AboutBox(info) 

272 

273############################################## 

274#### 

275 

276 def onFolderSelect(self, evt=None): 

277 style = wx.DD_DIR_MUST_EXIST|wx.DD_DEFAULT_STYLE 

278 dlg = wx.DirDialog(self, 'Select Working Directory:', get_cwd(), 

279 style=style) 

280 

281 if dlg.ShowModal() == wx.ID_OK: 

282 basedir = os.path.abspath(str(dlg.GetPath())) 

283 try: 

284 if len(basedir) > 0: 

285 os.chdir(nativepath(basedir)) 

286 save_workdir(nativepath(basedir)) 

287 except OSError: 

288 print( 'Changed folder failed') 

289 pass 

290 save_workdir('gsemap.dat') 

291 dlg.Destroy() 

292 

293 

294 def fit1Dxrd(self,event=None): 

295 ''' 

296 GUI interface for loading data to fitting panel (from data in viewer or file) 

297 mkak 2017.03.23 

298 ''' 

299 xrdv = self.xrd1Dviewer 

300 xrdf = self.xrd1Dfitting 

301 

302 indicies = [i for i,name in enumerate(xrdv.data_name) if 'cif' not in name] 

303 okay = False 

304 

305 xi = xrdv.ch_xaxis.GetSelection() 

306 xrdf.rngpl.ch_xaxis.SetSelection(xi) 

307 

308 if len(indicies) > 0: 

309 self.list = [xrdv.data_name[i] for i in indicies] 

310 self.all_data = xrdv.xy_data 

311 dlg = SelectFittingData(self) 

312 if dlg.ShowModal() == wx.ID_OK: 

313 okay = True 

314 index = dlg.slct_1Ddata.GetSelection() 

315 dlg.Destroy() 

316 else: 

317 index = -1 

318 loadXYfile(parent=self,xrdviewer=xrdv) 

319 if len(xrdv.xy_data) > 0: okay = True 

320 

321 if okay: 

322 seldat = xrdv.xy_data[index] 

323 self.nb.SetSelection(1) ## switches to fitting panel 

324 

325 adddata = True 

326 if xrdf.xrd1dgrp is not None: 

327 question = 'Replace current data file %s with selected file %s?' % \ 

328 (xrdf.xrd1dgrp.label,name) 

329 adddata = YesNo(self,question,caption='Overwrite warning') 

330 

331 if adddata: 

332 

333 if xrdf.xrd1dgrp is not None: 

334 xrdf.reset_fitting() 

335 xrdf.clearMATCHES() 

336 

337 xrdf.xrd1dgrp = seldat 

338 xrdf.plot1D.set_title(xrdf.xrd1dgrp.label) 

339 xrdf.plt_data = xrdf.xrd1dgrp.all_data() 

340 

341 xrdf.xmin = np.min(xrdf.plt_data[xi]) 

342 xrdf.xmax = np.max(xrdf.plt_data[xi]) 

343 

344 xrdf.optionsON() 

345 xrdv.optionsON() 

346 xrdf.check1Daxis() 

347 

348 xrdf.ttl_energy.SetLabel('Energy: %0.3f keV (%0.4f A)' % (seldat.energy, 

349 seldat.wavelength)) 

350 def save1Dxrd(self,event=None): 

351 ''' 

352 

353 mkak 2017.06.21 

354 ''' 

355 xrdv = self.xrd1Dviewer 

356 xrdf = self.xrd1Dfitting 

357 

358 indicies = [i for i,name in enumerate(xrdv.data_name) if 'cif' not in name] 

359 okay = False 

360 

361 if len(indicies) > 0: 

362 list_xrd1d = [xrdv.data_name[i] for i in indicies] 

363 self.all_data = xrdv.xy_data 

364 dlg = SelectSavingData(self,list_xrd1d) 

365 if dlg.ShowModal() == wx.ID_OK: 

366 okay = True 

367 index = dlg.slct_1Ddata.GetSelection() 

368 filename = dlg.File.GetValue() 

369 calfile = dlg.Poni.GetValue() if len(dlg.Poni.GetValue()) > 0 else None 

370 unts = dlg.ch_units.GetSelection() 

371 dlg.Destroy() 

372 

373 if okay: 

374 savdat = xrdv.xy_data[index] 

375 if unts == 1: ## 2theta 

376 save1D(filename, savdat.twth, savdat.I, xaxis_unit='2th', calfile=calfile) 

377 else: ## q 

378 save1D(filename, savdat.q, savdat.I, xaxis_unit='q', calfile=calfile) 

379 

380 

381class SelectSavingData(wx.Dialog): 

382 def __init__(self,parent,list_xrd1d): 

383 

384 """Constructor""" 

385 dialog = wx.Dialog.__init__(self, parent, title='Select data for saving', 

386 style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER|wx.OK, 

387 size=(350, 520)) 

388 

389 panel = wx.Panel(self) 

390 

391 mainsizer = wx.BoxSizer(wx.VERTICAL) 

392 

393 ## SELECT DATA 

394 ttl_slct = SimpleText(panel, label='Select dataset to save:') 

395 self.slct_1Ddata = wx.ListBox(panel, style=wx.LB_HSCROLL|wx.LB_NEEDED_SB, 

396 choices=list_xrd1d, size=(300, -1)) 

397 

398 datasizer = wx.BoxSizer(wx.VERTICAL) 

399 datasizer.Add(ttl_slct, flag=wx.TOP, border=8) 

400 datasizer.Add(self.slct_1Ddata, flag=wx.EXPAND|wx.TOP, border=8) 

401 

402 ## SELECT UNITS 

403 self.ch_units = wx.Choice(panel, choices=[u'q (\u212B\u207B\u00B9)',u'2\u03B8 (\u00B0)']) 

404 ttl_units = SimpleText(panel, label='Units:') 

405 

406 hsizer = wx.BoxSizer(wx.HORIZONTAL) 

407 hsizer.Add(ttl_units, flag=wx.RIGHT, border=5) 

408 hsizer.Add(self.ch_units, flag=wx.RIGHT, border=5) 

409 

410 unitsizer = wx.BoxSizer(wx.VERTICAL) 

411 unitsizer.Add(hsizer, flag=wx.TOP, border=5) 

412 

413 

414 ## SAVE TO FILE 

415 fileTtl = SimpleText(panel, label='Save data to:' ) 

416 self.File = wx.TextCtrl(panel, size=(300, 25) ) 

417 fileBtn = Button(panel, label='Browse...' ) 

418 

419 self.Bind(wx.EVT_BUTTON, self.saveXY, fileBtn ) 

420 

421 filesizer = wx.BoxSizer(wx.VERTICAL) 

422 filesizer.Add(fileTtl, flag=wx.TOP, border=5) 

423 filesizer.Add(self.File, flag=wx.EXPAND|wx.TOP, border=5) 

424 filesizer.Add(fileBtn, flag=wx.TOP, border=5) 

425 

426 ## SELECT CALIBRATION 

427 poniTtl = SimpleText(panel, label='Calibration file: (recommended)' ) 

428 self.Poni = wx.TextCtrl(panel, size=(300, 25) ) 

429 poniBtn = Button(panel, label='Browse...' ) 

430 

431 self.Bind(wx.EVT_BUTTON, self.onBROWSEponi, poniBtn ) 

432 

433 ponisizer = wx.BoxSizer(wx.VERTICAL) 

434 ponisizer.Add(poniTtl, flag=wx.TOP, border=5) 

435 ponisizer.Add(self.Poni, flag=wx.EXPAND|wx.TOP, border=5) 

436 ponisizer.Add(poniBtn, flag=wx.TOP, border=5) 

437 

438 ##### 

439 ## OKAY! 

440 oksizer = wx.BoxSizer(wx.HORIZONTAL) 

441 

442 okBtn = wx.Button(panel, wx.ID_OK ) 

443 canBtn = wx.Button(panel, wx.ID_CANCEL ) 

444 

445 oksizer.Add(canBtn, flag=wx.RIGHT, border=8) 

446 oksizer.Add(okBtn, flag=wx.RIGHT, border=8) 

447 

448 

449 mainsizer.AddSpacer(8) 

450 mainsizer.Add(datasizer, flag=wx.LEFT, border=8) 

451 mainsizer.AddSpacer(15) 

452 mainsizer.Add(unitsizer, flag=wx.LEFT, border=8) 

453 mainsizer.AddSpacer(15) 

454 mainsizer.Add(filesizer, flag=wx.LEFT, border=8) 

455 mainsizer.AddSpacer(15) 

456 mainsizer.Add(ponisizer, flag=wx.LEFT, border=8) 

457 mainsizer.AddSpacer(15) 

458 mainsizer.Add(oksizer, flag=wx.ALL|wx.ALIGN_RIGHT, border=8) 

459 

460 panel.SetSizer(mainsizer) 

461 

462 ix,iy = panel.GetBestSize() 

463 self.SetSize((ix+20, iy+50)) 

464 

465 def saveXY(self,event=None): 

466 wildcards = '1DXRD datafile (*.xy)|*.xy|All files (*.*)|*.*' 

467 if os.path.exists(self.File.GetValue()): 

468 dfltDIR = self.File.GetValue() 

469 else: 

470 dfltDIR = get_cwd() 

471 

472 dlg = wx.FileDialog(self, 'Save file as...', 

473 defaultDir=dfltDIR, 

474 wildcard=wildcards, 

475 style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) 

476 

477 path, save = None, False 

478 if dlg.ShowModal() == wx.ID_OK: 

479 save = True 

480 path = dlg.GetPath().replace('\\', '/') 

481 dlg.Destroy() 

482 

483 if save: 

484 self.File.Clear() 

485 self.File.SetValue(str(path)) 

486 

487 def onBROWSEponi(self,event=None): 

488 wildcards = 'XRD calibration file (*.poni)|*.poni|All files (*.*)|*.*' 

489 if os.path.exists(self.Poni.GetValue()): 

490 dfltDIR = self.Poni.GetValue() 

491 else: 

492 dfltDIR = get_cwd() 

493 

494 dlg = wx.FileDialog(self, message='Select XRD calibration file', 

495 defaultDir=dfltDIR, 

496 wildcard=wildcards, style=wx.FD_OPEN) 

497 path, read = None, False 

498 if dlg.ShowModal() == wx.ID_OK: 

499 read = True 

500 path = dlg.GetPath().replace('\\', '/') 

501 dlg.Destroy() 

502 

503 if read: 

504 self.Poni.Clear() 

505 self.Poni.SetValue(str(path)) 

506 

507class SelectFittingData(wx.Dialog): 

508 def __init__(self,parent): 

509 

510 """Constructor""" 

511 dialog = wx.Dialog.__init__(self, parent, title='Select data for fitting', 

512 style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER|wx.OK) 

513 #size = (210,410)) 

514 self.parent = parent 

515 self.createPanel() 

516 

517 ix,iy = self.panel.GetBestSize() 

518 self.SetSize((ix+20, iy+50)) 

519 

520 def createPanel(self): 

521 

522 self.panel = wx.Panel(self) 

523 mainsizer = wx.BoxSizer(wx.VERTICAL) 

524 

525 ## Add things 

526 self.slct_1Ddata = wx.ListBox(self.panel, 26, wx.DefaultPosition, (-1, 130), 

527 self.parent.list, wx.LB_SINGLE) 

528 btn_new = wx.Button(self.panel,label='Load data from file') 

529 btn_new.Bind(wx.EVT_BUTTON, self.load_file) 

530 

531 ##### 

532 ## OKAY! 

533 oksizer = wx.BoxSizer(wx.HORIZONTAL) 

534 self.okBtn = wx.Button(self.panel, wx.ID_OK ) 

535 canBtn = wx.Button(self.panel, wx.ID_CANCEL) 

536 

537 oksizer.Add(canBtn, flag=wx.RIGHT, border=8) 

538 oksizer.Add(self.okBtn, flag=wx.RIGHT, border=8) 

539 

540 hsizer = wx.BoxSizer(wx.HORIZONTAL) 

541 hsizer.Add(self.slct_1Ddata, flag=wx.ALL|wx.EXPAND, border=8) 

542 

543 mainsizer.Add(hsizer, flag=wx.BOTTOM|wx.EXPAND, border=8) 

544 mainsizer.AddSpacer(15) 

545 mainsizer.Add(btn_new, flag=wx.ALL, border=5) 

546 mainsizer.AddSpacer(15) 

547 mainsizer.Add(oksizer, flag=wx.ALL|wx.ALIGN_RIGHT, border=10) 

548 

549 self.panel.SetSizer(mainsizer) 

550 self.slct_1Ddata.SetSelection(0) 

551 

552 def load_file(self, event=None): 

553 print("Load File ", event) 

554 loadXYfile(parent=self, xrdviewer=self.parent.xrd1Dviewer) 

555 

556 if self.parent.xrd1Dviewer.data_name[-1] not in self.parent.list: 

557 self.parent.list.append(self.parent.xrd1Dviewer.data_name[-1]) 

558 self.slct_1Ddata.Set(self.parent.list) 

559 self.slct_1Ddata.SetSelection(self.slct_1Ddata.FindString(self.parent.list[-1])) 

560 

561class Fitting1DXRD(BasePanel): 

562 ''' 

563 Panel for housing 1D XRD fitting 

564 ''' 

565 label='Fitting' 

566 def __init__(self,parent,owner=None,_larch=None): 

567 

568 wx.Panel.__init__(self, parent) 

569 

570 self.parent = parent 

571 self.owner = owner 

572 

573 ## Default information 

574 self.xrd1dgrp = None 

575 self.plt_data = None 

576 self.plt_cif = None 

577 

578 self.plt_peaks = None 

579 self.peaklist = [] 

580 

581 self.xmin = None 

582 self.xmax = None 

583 self.x, self.y = 0,0 

584 

585 self.xlabel = 'q (1/$\AA$)' #'q (A^-1)' 

586 self.ylabel = 'Intensity (a.u.)' 

587 self.xunit = '1/A' 

588 self.dlimit = 7.5 # A -> 2th = 5 deg.; q = 0.8 1/A 

589 

590 ## Database searching parameters 

591 self.elem_include = [] 

592 self.elem_exclude = [] 

593 self.amcsd = [] 

594 self.auth_include = [] 

595 self.mnrl_include = [] 

596 

597 ## List of opened CIF frame windows (will close upon exit) 

598 self.cifframe = [] 

599 

600 self.SetFittingDefaults() 

601 self.Panel1DFitting() 

602 

603 def SetFittingDefaults(self): 

604 

605 # Peak fitting defaults 

606 self.widths = 20 

607 self.gapthrsh = 5 

608 self.halfwidth = 40 

609 self.intthrsh = 100 

610 self.thrsh = 0 

611 self.min_dist = 10 

612 

613 # Background fitting defaults 

614 self.bkgd_kwargs = BKGD_DEFAULT.copy() 

615 

616 

617############################################## 

618#### PANEL DEFINITIONS 

619 def Panel1DFitting(self): 

620 ''' 

621 Frame for housing all 1D XRD viewer widgets 

622 ''' 

623 leftside = self.LeftSidePanel(self) 

624 rightside = self.RightSidePanel(self) 

625 

626 panel1D = wx.BoxSizer(wx.HORIZONTAL) 

627 panel1D.Add(leftside,flag=wx.ALL,border=10) 

628 panel1D.Add(rightside,proportion=1,flag=wx.EXPAND|wx.ALL,border=10) 

629 

630 self.SetSizer(panel1D) 

631 

632 def createFittingPanels(self,parent): 

633 

634 pattern_title = SimpleText(parent, 'DATABASE FILTERING', size=(200, -1)) 

635 

636 self.dnb = wx.Notebook(parent) 

637 self.dnbpanels = [] 

638 

639 self.srchpl = SearchPanel(self.dnb, owner=self) 

640 self.instpl = InstrPanel(self.dnb, owner=self) 

641 self.rtgpl = ResultsPanel(self.dnb, owner=self) 

642 for p in (self.instpl, self.srchpl, self.rtgpl): 

643 self.dnb.AddPage(p,p.label.title(),True) 

644 self.dnbpanels.append(p) 

645 p.SetSize((300,600)) 

646 

647 self.dnb.SetSelection(1) 

648 sizer = wx.BoxSizer(wx.VERTICAL) 

649 sizer.Add(pattern_title, 0, ALL_CEN) 

650 sizer.Add(self.dnb,1, wx.ALL|wx.EXPAND) 

651 parent.SetSize((300,600)) 

652 pack(parent,sizer) 

653 

654 

655 def FilterTools(self,panel): 

656 ''' 

657 Frame for visual toolbox 

658 ''' 

659 

660 vbox = wx.BoxSizer(wx.VERTICAL) 

661 

662 fitting_panel = wx.Panel(panel) 

663 self.createFittingPanels(fitting_panel) 

664 vbox.Add(fitting_panel, flag=wx.ALL, border=10) 

665 

666 return vbox 

667 

668 

669 def createPatternPanels(self,parent): 

670 

671 pattern_title = SimpleText(parent, 'PATTERN PROCESSING', size=(200, -1)) 

672 self.pnb = wx.Notebook(parent) 

673 self.pnbpanels = [] 

674 

675 self.rngpl = RangeToolsPanel(self.pnb, owner=self) 

676 self.bkgdpl = BackgroundToolsPanel(self.pnb, owner=self) 

677 self.pkpl = PeakToolsPanel(self.pnb, owner=self) 

678 for p in (self.rngpl, self.bkgdpl, self.pkpl): 

679 self.pnb.AddPage(p,p.label.title(),True) 

680 self.pnbpanels.append(p) 

681 p.SetSize((300,600)) 

682 

683 self.pnb.SetSelection(0) 

684 sizer = wx.BoxSizer(wx.VERTICAL) 

685 sizer.Add(pattern_title, 0, ALL_CEN) 

686 sizer.Add(self.pnb,1, wx.ALL|wx.EXPAND) 

687 parent.SetSize((300,600)) 

688 pack(parent,sizer) 

689 

690 

691 def PatternTools(self,panel): 

692 ''' 

693 Frame for visual toolbox 

694 ''' 

695 

696 vbox = wx.BoxSizer(wx.VERTICAL) 

697 

698 pattern_panel = wx.Panel(panel) 

699 self.createPatternPanels(pattern_panel) 

700 vbox.Add(pattern_panel, flag=wx.ALL, border=10) 

701 

702 return vbox 

703 

704 def MatchPanel(self,panel): 

705 ''' 

706 Matches 

707 ''' 

708 vbox = wx.BoxSizer(wx.VERTICAL) 

709 

710 self.txt_amcsd_cnt = wx.StaticText(self, label='') 

711 vbox.Add(self.txt_amcsd_cnt, flag=wx.LEFT, border=16) 

712 

713 return vbox 

714 

715 def LeftSidePanel(self,panel): 

716 

717 vbox = wx.BoxSizer(wx.VERTICAL) 

718 

719 pattools = self.PatternTools(self) 

720 vbox.Add(pattools,flag=wx.TOP|wx.LEFT,border=10) 

721 

722 filtools = self.FilterTools(self) 

723 vbox.Add(filtools,flag=wx.LEFT,border=10) 

724 

725 matchbx = self.MatchPanel(self) 

726 vbox.Add(matchbx,flag=wx.LEFT,border=12) 

727 

728 return vbox 

729 

730 def SettingsPanel(self,panel): 

731 

732 vbox = wx.BoxSizer(wx.VERTICAL) 

733 

734 self.ttl_energy = wx.StaticText(self, label=('Energy: %0.3f keV (%0.4f A)' % (0,0))) 

735 

736 vbox.Add(self.ttl_energy, flag=wx.EXPAND|wx.ALL, border=8) 

737 

738 return vbox 

739 

740 def RightSidePanel(self,panel): 

741 vbox = wx.BoxSizer(wx.VERTICAL) 

742 hbox = wx.BoxSizer(wx.HORIZONTAL) 

743 

744 self.plot1DXRD(panel) 

745 

746 settings = self.SettingsPanel(self) 

747 btnbox = self.QuickButtons(panel) 

748 

749 vbox.Add(self.plot1D,proportion=1,flag=wx.ALL|wx.EXPAND,border = 10) 

750 hbox.Add(settings,flag=wx.RIGHT,border=10) 

751 hbox.Add(btnbox,flag=wx.LEFT,border = 1) 

752 vbox.Add(hbox,flag=wx.ALL|wx.ALIGN_RIGHT,border = 10) 

753 return vbox 

754 

755 def QuickButtons(self,panel): 

756 buttonbox = wx.BoxSizer(wx.HORIZONTAL) 

757 btn_img = wx.Button(panel,label='SAVE FIGURE') 

758 btn_calib = wx.Button(panel,label='PLOT SETTINGS') 

759 btn_integ = wx.Button(panel,label='RESET PLOT') 

760 

761 btn_img.Bind(wx.EVT_BUTTON, self.onSAVEfig) 

762 btn_calib.Bind(wx.EVT_BUTTON, self.onPLOTset) 

763 btn_integ.Bind(wx.EVT_BUTTON, self.onRESETplot) 

764 

765 buttonbox.Add(btn_img, flag=wx.ALL, border=8) 

766 buttonbox.Add(btn_calib, flag=wx.ALL, border=8) 

767 buttonbox.Add(btn_integ, flag=wx.ALL, border=8) 

768 return buttonbox 

769 

770 

771############################################## 

772#### DATA CALCULATIONS FUNCTIONS 

773 

774 def plot_all(self,show=True,showbkg=None): 

775 

776 if showbkg is None: showbkg = show 

777 

778 self.plot_background(show=showbkg) 

779 self.plot_peaks(show=show) 

780 self.plot_data() 

781 

782 def plot_data(self,event=None): 

783 

784 xi = self.rngpl.ch_xaxis.GetSelection() 

785 self.plot1D.update_line(0, self.plt_data[xi], self.plt_data[3], draw=True) 

786 

787 self.rescale1Daxis(xaxis=True,yaxis=True) 

788 

789 def plot_background(self,show=True): 

790 

791 if show: 

792 if self.xrd1dgrp is not None and not self.bkgdpl.ck_bkgd.GetValue(): 

793 xi = self.rngpl.ch_xaxis.GetSelection() 

794 self.plot1D.update_line(1,self.plt_data[xi],self.plt_data[4],draw=True,update_limits=False) 

795 else: 

796 self.plot1D.update_line(1,MT00,MT00,draw=True,update_limits=False) 

797 

798 def plot_peaks(self,show=True): 

799 

800 if show: 

801 if len(self.xrd1dgrp.pki) > 0: 

802 self.define_peaks() 

803 

804 xi = self.rngpl.ch_xaxis.GetSelection() 

805 self.plot1D.update_line(2,self.plt_peaks[xi],self.plt_peaks[3],draw=True,update_limits=False) 

806 else: 

807 self.plot1D.update_line(2,MT00,MT00,draw=True,update_limits=False) 

808 self.plt_peaks = None 

809 

810 def displayCIFpeaks(self, event=None, show=True, **kws): 

811 

812 geometry_str = ['Space group : %s (%s)', 

813 u'a,b,c : %0.3f \u212B, %0.3f \u212B, %0.3f \u212B', 

814 u'\u03B1,\u03B2,\u03B3 : %0.1f\xb0, %0.1f\xb0, %0.1f\xb0'] 

815 

816 if show and event is not None and self.xrd1dgrp is not None: 

817 cifname = event.GetString() 

818 amcsd_id = int(cifname.split()[0]) 

819 ciffile = '/%s' % cifname 

820 

821 energy = self.xrd1dgrp.energy 

822 wavelength = self.xrd1dgrp.wavelength 

823 maxI = np.max(self.plt_data[3])*0.95 

824 qmax = np.max(self.plt_data[0])*1.05 

825 

826 xi = self.rngpl.ch_xaxis.GetSelection() 

827 

828 cif = create_xrdcif(cifdb=self.owner.cifdb, amcsd_id=amcsd_id) 

829 cif.structure_factors(wavelength=wavelength, q_max=qmax) 

830 qall,Iall = cif.qhkl,cif.Ihkl 

831 Iall = Iall/max(Iall)*maxI 

832 

833 try: 

834 cifdata = [] 

835 for i,I in enumerate(Iall): 

836 cifdata.append([qall[i], twth_from_q(qall[i],wavelength), d_from_q(qall[i]), I]) 

837 cifdata = np.array(zip(*cifdata)) 

838 u,v,w = self.xrd1dgrp.uvw 

839 D = self.xrd1dgrp.D 

840 self.plt_cif = self.plt_data 

841 self.plt_cif[3] = calc_broadening(cifdata,self.plt_cif[1],wavelength,u=u,v=v,w=w,D=D) 

842 except: 

843 qall,Iall = plot_sticks(qall,Iall) 

844 self.plt_cif = np.array([qall, twth_from_q(qall,wavelength), d_from_q(qall), Iall]) 

845 self.plot1D.update_line(3,self.plt_cif[xi],self.plt_cif[3],draw=True,update_limits=False) 

846 

847 elementstr = self.owner.cifdb.composition_by_amcsd(amcsd_id,string=True) 

848 

849 self.srchpl.txt_geometry[0].SetLabel(elementstr) 

850 self.srchpl.txt_geometry[1].SetLabel(geometry_str[0] % (str(cif.symmetry.no), 

851 cif.symmetry.name)) 

852 self.srchpl.txt_geometry[2].SetLabel(geometry_str[1] % (cif.unitcell[0], 

853 cif.unitcell[1], 

854 cif.unitcell[2])) 

855 self.srchpl.txt_geometry[3].SetLabel(geometry_str[2] % (cif.unitcell[3], 

856 cif.unitcell[4], 

857 cif.unitcell[5])) 

858 else: 

859 self.plot1D.update_line(3,MT00,MT00,draw=True,update_limits=False) 

860 self.plt_cif = None 

861 for txt in self.srchpl.txt_geometry: 

862 txt.SetLabel('') 

863 

864############################################## 

865#### RANGE FUNCTIONS 

866 

867 def reset_fitting(self,name=None,min=0,max=1): 

868 

869 self.xrd1dgrp.label = name 

870 

871 self.rngpl.val_xmin.SetValue('%0.3f' % min) 

872 self.rngpl.val_xmax.SetValue('%0.3f' % max) 

873 self.rngpl.ch_xaxis.SetSelection(0) 

874 

875 self.pkpl.btn_fdpks.Enable() 

876 self.pkpl.btn_opks.Enable() 

877 

878 self.bkgdpl.btn_obkgd.Enable() 

879 self.bkgdpl.btn_fbkgd.Enable() 

880 self.bkgdpl.btn_rbkgd.Disable() 

881 self.bkgdpl.ck_bkgd.SetValue(False) 

882 self.bkgdpl.ck_bkgd.Disable() 

883 

884 self.srchpl.btn_mtch.Disable() 

885 

886 self.xmin = min 

887 self.xmax = max 

888 self.trim_data() 

889 self.delete_all_peaks() 

890 self.remove_background() 

891 

892 self.SetFittingDefaults() 

893 self.plot_all(show=False) 

894 

895 def onSetRange(self,event=None): 

896 

897 self.check_range() 

898 self.trim_data() 

899 

900 self.plot_data() 

901 

902 def check_range(self,event=None): 

903 

904 xmin,xmax = self.rngpl.val_xmin,self.rngpl.val_xmax 

905 minval,maxval = float(xmin.GetValue()),float(xmax.GetValue()) 

906 

907 xi = self.rngpl.ch_xaxis.GetSelection() 

908 x = self.xrd1dgrp.slct_xaxis(xi=xi) 

909 

910 if abs(self.xmax-maxval) > 0.005 or abs(self.xmin-minval) > 0.005: 

911 if xmax < minval: minval,maxval = float(xmax.GetValue()),float(xmin.GetValue()) 

912 self.xmin = max(minval,np.min(x)) 

913 self.xmax = min(maxval,np.max(x)) 

914 

915 if xi == 2: self.xmax = min(self.xmax,self.dlimit) 

916 

917 self.delete_all_peaks() 

918 self.remove_background() 

919 

920 xmin.SetValue('%0.3f' % self.xmin) 

921 xmax.SetValue('%0.3f' % self.xmax) 

922 

923 def onReset(self,event=None): 

924 

925 self.plt_peaks,self.xrd1dgrp.pki = None,[] 

926 self.peaklist = [] 

927 

928 self.reset_range() 

929 self.plot_all(show=False) 

930 

931 def reset_range(self,event=None): 

932 

933 xi = self.rngpl.ch_xaxis.GetSelection() 

934 x = self.xrd1dgrp.slct_xaxis(xi=xi) 

935 

936 self.xmin,self.xmax = np.min(x),np.max(x) 

937 if xi == 2: self.xmax = min(self.xmax,self.dlimit) 

938 

939 self.rngpl.val_xmin.SetValue('%0.3f' % self.xmin) 

940 self.rngpl.val_xmax.SetValue('%0.3f' % self.xmax) 

941 

942 self.trim_data() 

943 self.remove_background() 

944 

945 def trim_data(self): 

946 

947 xi = self.rngpl.ch_xaxis.GetSelection() 

948 self.xrd1dgrp.set_trim(self.xmin,self.xmax,xi=xi) 

949 self.plt_data = self.xrd1dgrp.all_data() 

950 

951############################################## 

952#### BACKGROUND FUNCTIONS 

953 

954 def onFitBkgd(self,event=None): 

955 

956 self.xrd1dgrp.fit_background(**self.bkgd_kwargs) 

957 self.plt_data = self.xrd1dgrp.plot(bkgd=False) 

958 

959 self.plot_background() 

960 

961 self.bkgdpl.btn_rbkgd.Enable() 

962 self.bkgdpl.ck_bkgd.Enable() 

963 

964 def onSbtrctBkgd(self,event=None): 

965 

966 check_bkgd = self.bkgdpl.ck_bkgd.GetValue() 

967 self.plt_data = self.xrd1dgrp.plot(bkgd=check_bkgd) 

968 

969 self.plot_all(showbkg=(check_bkgd==False)) 

970 

971 def onRmvBkgd(self,event=None): 

972 

973 self.remove_background() 

974 self.plot_background(show=False) 

975 

976 def remove_background(self,event=None): 

977 

978 self.xrd1dgrp.reset_bkgd() 

979 self.plt_data = self.xrd1dgrp.plot(bkgd=False) 

980 

981 self.bkgdpl.ck_bkgd.SetValue(False) 

982 self.bkgdpl.ck_bkgd.Disable() 

983 self.bkgdpl.btn_rbkgd.Disable() 

984 

985 self.plot_all(showbkg=False) 

986 

987 def background_options(self,event=None): 

988 

989 myDlg = BackgroundOptions(self) 

990 

991 fit = False 

992 if myDlg.ShowModal() == wx.ID_OK: 

993 self.bkgd_kwargs.update({'exponent' : int(myDlg.val_exp.GetValue()), 

994 'compress' : int(myDlg.val_comp.GetValue()), 

995 'width' : int(myDlg.val_wid.GetValue())}) 

996 fit = True 

997 myDlg.Destroy() 

998 

999 if fit: 

1000 self.onFitBkgd() 

1001 

1002 

1003############################################## 

1004#### PEAK FUNCTIONS 

1005 

1006 def onPeaks(self,event=None,filter=False): 

1007 

1008 self.find_peaks(filter=filter) 

1009 

1010 if len(self.xrd1dgrp.pki) > 0: 

1011 self.srchpl.btn_mtch.Enable() 

1012 

1013 def onAddPks(self,event=None): 

1014 

1015 xi = self.rngpl.ch_xaxis.GetSelection() 

1016 idx = (np.abs(self.plt_data[xi]-self.x)).argmin() 

1017 self.xrd1dgrp.pki.append(idx) 

1018 

1019 self.peak_display() 

1020 self.plot_peaks() 

1021 

1022 

1023 def onRmvPksAll(self,event=None,filter=False): 

1024 

1025 self.remove_all_peaks() 

1026 self.srchpl.btn_mtch.Disable() 

1027 self.plot_peaks(show=False) 

1028 

1029 def find_peaks(self,event=None,newpeaks=True,filter=False): 

1030 

1031 if len(self.xrd1dgrp.pki) > 0: 

1032 question = 'Are you sure you want to remove current peaks and search again?' 

1033 newpeaks = YesNo(self,question,caption='Replace peaks warning') 

1034 

1035 if newpeaks: 

1036 ## clears previous searches 

1037 self.remove_all_peaks() 

1038 

1039 self.intthrsh = float(self.pkpl.val_intthr.GetValue()) 

1040 if self.intthrsh > 1: self.intthrsh = int(self.intthrsh) 

1041 

1042 self.xrd1dgrp.find_peaks(bkgd = self.bkgdpl.ck_bkgd.GetValue(), 

1043 threshold = self.intthrsh, 

1044 thres = self.thrsh, 

1045 min_dist = self.min_dist, 

1046 widths = self.widths, 

1047 gapthrsh = self.gapthrsh, 

1048 method = self.pkpl.ch_pkfit.GetStringSelection() ) 

1049 self.peak_display() 

1050 self.plot_peaks() 

1051 

1052 self.pkpl.btn_rmvpks.Enable() 

1053 

1054 def peak_display(self): 

1055 

1056 self.define_peaks() 

1057 

1058 self.peaklist = [] 

1059 self.peaklistbox.Clear() 

1060 

1061 xi = self.rngpl.ch_xaxis.GetSelection() 

1062 for i,ii in enumerate(self.xrd1dgrp.pki): 

1063 

1064 ## this will only work for python 2.7 and later 

1065 ## mkak 2017.11.08 

1066 x = self.plt_peaks[3,i] 

1067 if x > 10: 

1068 pstr = 'Peak ({:6d}'.format(int(x)) 

1069 elif x > 1: 

1070 pstr = 'Peak ({:6.2f}'.format(x) 

1071 else: 

1072 pstr = 'Peak ({:6.3f}'.format(x) 

1073 peakname = pstr + ' cts @ %2.3f %s )' % (self.plt_peaks[xi,i],self.xunit) 

1074 

1075 self.peaklist += [peakname] 

1076 self.peaklistbox.Append(peakname) 

1077 self.pkpl.ttl_cntpks.SetLabel('Total: %i peaks' % (len(self.xrd1dgrp.pki))) 

1078 

1079 def onClrInstr(self,event=None): 

1080 

1081 self.xrd1dgrp.uvw = None 

1082 self.instpl.val_u.SetValue('1.0') 

1083 self.instpl.val_v.SetValue('1.0') 

1084 self.instpl.val_w.SetValue('1.0') 

1085 

1086 def onClrSize(self,event=None): 

1087 

1088 self.xrd1dgrp.D = None 

1089 self.instpl.val_D.SetValue('') 

1090 

1091 def onGetSize(self,event=None): 

1092 

1093 try: 

1094 self.xrd1dgrp.D = float(self.instpl.val_D.GetValue()) 

1095 except: 

1096 self.onClrSize() 

1097 

1098 def onSetInstr(self,event=None): 

1099 u,v,w = self.xrd1dgrp.uvw 

1100 self.instpl.val_u.SetValue('%0.6f' % u) 

1101 self.instpl.val_v.SetValue('%0.6f' % v) 

1102 self.instpl.val_w.SetValue('%0.6f' % w) 

1103 

1104 def onGetInstr(self,event=None): 

1105 

1106 try: 

1107 self.xrd1dgrp.uvw = (float(self.instpl.val_u.GetValue()), 

1108 float(self.instpl.val_v.GetValue()), 

1109 float(self.instpl.val_w.GetValue())) 

1110 self.onSetInstr() 

1111 except: 

1112 self.onClrInstr() 

1113 

1114 

1115 def fit_instrumental(self,event=None): 

1116 

1117 try: 

1118 self.xrd1dgrp.uvw = instrumental_fit_uvw(self.xrd1dgrp.pki, 

1119 self.plt_data[1],self.plt_data[3], 

1120 halfwidth=self.halfwidth, 

1121 verbose=False) 

1122 self.onSetInstr() 

1123 self.dnb.SetSelection(0) 

1124 except: 

1125 pass 

1126 

1127# def fit_peaks(self,event=None): 

1128# 

1129# pktwth,pkFWHM,pkI = peakfitter(self.xrd1dgrp.pki,self.plt_data[1],self.plt_data[3], 

1130# halfwidth=self.halfwidth, 

1131# fittype='double', 

1132# verbose=True) 

1133# print('\nFit results:') 

1134# for i,(twthi,fwhmi,inteni) in enumerate(zip(pktwth,pkFWHM,pkI)): 

1135# print('Peak %i @ %0.2f deg. (fwhm %0.3f deg, %i counts)' % (i,twthi,fwhmi,inteni)) 

1136# print 

1137# 

1138# ## Updates variable and plot with fit results 

1139# wavelength = self.xrd1dgrp.wavelength 

1140# self.plt_peaks = np.zeros((4,len(pktwth))) 

1141# self.plt_peaks[0] = q_from_twth(pktwth,wavelength) 

1142# self.plt_peaks[1] = pktwth 

1143# self.plt_peaks[2] = d_from_twth(pktwth,wavelength) 

1144# self.plt_peaks[3] = pkI 

1145# 

1146# self.plot_peaks() 

1147 

1148 def remove_all_peaks(self,event=None): 

1149 

1150 self.delete_all_peaks() 

1151 self.pkpl.btn_rmvpks.Disable() 

1152 

1153 def delete_all_peaks(self,event=None): 

1154 

1155 self.plt_peaks,self.xrd1dgrp.pki = None,[] 

1156 

1157 self.peaklist = [] 

1158 self.peaklistbox.Clear() 

1159 self.pkpl.ttl_cntpks.SetLabel('Total: 0 peaks') 

1160 

1161 def peak_options(self,event=None): 

1162 

1163 method = SRCH_MTHDS[self.pkpl.ch_pkfit.GetSelection()] 

1164 myDlg = PeakOptions(self,method=method) 

1165 if myDlg.ShowModal() == wx.ID_OK: 

1166 self.halfwidth = int(myDlg.val0.GetValue()) 

1167 if method == 'scipy.signal.find_peaks_cwt': 

1168 self.widths = int(myDlg.val1.GetValue()) 

1169 self.gapthrsh = int(myDlg.val2.GetValue()) 

1170 elif method == 'peakutils.indexes': 

1171 self.thrsh = int(myDlg.val1.GetValue()) 

1172 self.min_dist = int(myDlg.val2.GetValue()) 

1173 

1174 myDlg.Destroy() 

1175 

1176 

1177 def select_peak(self, evt=None, peakname=None, **kws): 

1178 

1179 if peakname is None and evt is not None: 

1180 peakname = evt.GetString() 

1181 

1182 def define_peaks(self): 

1183 

1184 peaks=np.zeros((5,len(self.xrd1dgrp.pki))) 

1185 for axis,data in enumerate(self.plt_data): 

1186 peaks[axis] = peaklocater(self.xrd1dgrp.pki,data) 

1187 self.plt_peaks = peaks 

1188 

1189 def rm_sel_peaks(self, peakname, event=None): 

1190 

1191 if peakname in self.peaklist: 

1192 

1193 pki = self.peaklist.index(peakname) 

1194 

1195 self.peaklist.pop(pki) 

1196 self.xrd1dgrp.pki.pop(pki) 

1197 

1198 self.plot_peaks() 

1199 

1200 self.pkpl.ttl_cntpks.SetLabel('Total: %i peaks' % (len(self.xrd1dgrp.pki))) 

1201 

1202############################################## 

1203#### PLOTPANEL FUNCTIONS 

1204 def plot1DXRD(self,panel): 

1205 

1206 self.plot1D = PlotPanel(panel,size=(1000, 600),messenger=self.owner.write_message) 

1207 self.plot1D.cursor_mode = 'zoom' 

1208 self.plot1D.cursor_callback = self.on_cursor 

1209 

1210 ## initialize plots 

1211 keys = ['label', 'color', 'linewidth', 'marker', 'markersize', 'show_legend', 

1212 'xlabel', 'ylabel'] 

1213 argplt = [['Data', 'blue', None, '', 0, True, self.xlabel, self.ylabel], 

1214 ['Background', 'red', None, '', 0, True, self.xlabel, self.ylabel], 

1215 ['Peaks', 'red', 0, 'o',8, True, self.xlabel, self.ylabel], 

1216 ['CIF data', 'green', None, '', 0, True, self.xlabel, self.ylabel]] 

1217 

1218 for i,argi in enumerate(argplt): 

1219 args = dict(zip(keys, argi)) 

1220 if i == 0: 

1221 self.plot1D.plot(MT01,MT01,**args) 

1222 else: 

1223 self.plot1D.oplot(MT00,MT00,**args) 

1224 

1225 def on_cursor(self,x=None, y=None, **kw): 

1226 self.x,self.y = x,y 

1227 

1228 def onSAVEfig(self,event=None): 

1229 self.plot1D.save_figure() 

1230 

1231 def onPLOTset(self,event=None): 

1232 self.plot1D.configure() 

1233 

1234 def onRESETplot(self,event=None): 

1235 self.plot1D.reset_config() 

1236 

1237 def onChangeXscale(self,event=None): 

1238 

1239 self.check1Daxis() 

1240 

1241 xi = self.rngpl.ch_xaxis.GetSelection() 

1242 

1243 if np.max(self.xrd1dgrp.bkgd) > 0 and not self.bkgdpl.ck_bkgd.GetValue(): 

1244 self.plot1D.update_line(1, self.plt_data[xi], self.plt_data[4], draw=True, 

1245 update_limits=False) 

1246 if self.plt_peaks is not None: 

1247 self.plot1D.update_line(2,self.plt_peaks[xi],self.plt_peaks[3],draw=True,update_limits=False) 

1248 if self.plt_cif is not None: 

1249 self.plot1D.update_line(3,self.plt_cif[xi],self.plt_cif[3],draw=True,update_limits=False) 

1250 

1251 def optionsON(self,event=None): 

1252 

1253 ## RangeToolsPanel 

1254 self.rngpl.ch_xaxis.Enable() 

1255 self.rngpl.val_xmin.Enable() 

1256 self.rngpl.val_xmax.Enable() 

1257 self.rngpl.btn_rngreset.Enable() 

1258 ## BackgroundToolsPanel 

1259 self.bkgdpl.btn_fbkgd.Enable() 

1260 self.bkgdpl.btn_obkgd.Enable() 

1261 self.bkgdpl.btn_rbkgd.Disable() 

1262 self.bkgdpl.ck_bkgd.Disable() 

1263 ## PeakToolsPanel 

1264 self.pkpl.btn_fdpks.Enable() 

1265 self.pkpl.btn_opks.Enable() 

1266 self.pkpl.val_intthr.Enable() 

1267 self.pkpl.btn_rmvpks.Disable() #Enable() 

1268 self.pkpl.btn_addpks.Enable() 

1269 ## InstrumentToolsPanel 

1270 self.instpl.val_u.Enable() 

1271 self.instpl.val_v.Enable() 

1272 self.instpl.val_w.Enable() 

1273 self.instpl.val_D.Enable() 

1274 self.instpl.btn_clrinst.Enable() 

1275 self.instpl.btn_clrsize.Enable() 

1276 

1277 

1278 def check1Daxis(self,event=None,yaxis=False): 

1279 

1280 xi = self.rngpl.ch_xaxis.GetSelection() 

1281 minx,maxx = np.min(self.plt_data[xi]),np.max(self.plt_data[xi]) 

1282 if xi == 2: maxx = min(maxx,self.dlimit) 

1283 

1284 self.rngpl.val_xmin.SetValue('%0.3f' % minx) 

1285 self.rngpl.val_xmax.SetValue('%0.3f' % maxx) 

1286 

1287 ## d 

1288 if xi == 2: 

1289 self.xlabel = 'd ($\AA$)' 

1290 self.xunit = 'A' #'$\AA$' 

1291 ## 2theta 

1292 elif xi == 1: 

1293 self.xlabel = r'$2\Theta$'+r' $(^\circ)$' 

1294 self.xunit = 'deg.' #'$(^\circ)$' 

1295 ## q 

1296 else: 

1297 self.xlabel = 'q (1/$\AA$)' 

1298 self.xunit = '1/A' #'1/$\AA$' 

1299 self.rngpl.unit_xmin.SetLabel(self.xunit) 

1300 self.rngpl.unit_xmax.SetLabel(self.xunit) 

1301 

1302 self.plot_data() 

1303 

1304 def rescale1Daxis(self,xaxis=True,yaxis=False): 

1305 

1306 xi = self.rngpl.ch_xaxis.GetSelection() 

1307 x,y = self.plt_data[xi],self.plt_data[3] 

1308 

1309 if xaxis: self.set_xview(np.min(x), np.max(x)) 

1310 if yaxis: self.set_yview(np.min(y), np.max(y)) 

1311 

1312 def set_xview(self, x1, x2): 

1313 

1314 xi = self.rngpl.ch_xaxis.GetSelection() 

1315 xmin,xmax = np.min(self.plt_data[xi]),np.max(self.plt_data[xi]) 

1316 

1317 x1,x2 = max(xmin,x1),min(xmax,x2) 

1318 if xi == 2: x2 = min(x2,self.dlimit) 

1319 

1320 self.plot1D.axes.set_xlim((x1, x2)) 

1321 self.plot1D.canvas.draw() 

1322 

1323 def set_yview(self, y1, y2): 

1324 

1325 ymin,ymax = np.min(self.plt_data[3]),np.max(self.plt_data[3]) 

1326 y1,y2 = max(ymin,y1),min(ymax,y2) 

1327 

1328 self.plot1D.axes.set_ylim((y1, y2)) 

1329 self.plot1D.canvas.draw() 

1330 

1331############################################## 

1332#### DATABASE FUNCTIONS 

1333 

1334 def database_info(self,event=None): 

1335 

1336 myDlg = DatabaseInfoGUI(self) 

1337 

1338 change = False 

1339 if myDlg.ShowModal() == wx.ID_OK: change = True 

1340 myDlg.Destroy() 

1341 

1342 def open_database(self,event=None): 

1343 wildcards = 'AMCSD database file (*.db)|*.db|All files (*.*)|*.*' 

1344 dlg = wx.FileDialog(self, message='Choose AMCSD database file', 

1345 defaultDir=get_cwd(), 

1346 wildcard=wildcards, style=wx.FD_OPEN) 

1347 

1348 path, read = None, False 

1349 if dlg.ShowModal() == wx.ID_OK: 

1350 read = True 

1351 path = dlg.GetPath().replace('\\', '/') 

1352 dlg.Destroy() 

1353 

1354 if read: 

1355 try: 

1356 self.owner.openDB(dbname=path) 

1357 except: 

1358 pass 

1359 return path 

1360 

1361 

1362 def filter_database(self,event=None): 

1363 print(" filter database B") 

1364 cifdb = self.owner.cifdb 

1365 

1366 myDlg = XRDSearchGUI(cifdb, self.owner.srch_cls) 

1367 

1368 filter = False 

1369 

1370 if myDlg.ShowModal() == wx.ID_OK: 

1371 

1372 self.elem_include = myDlg.srch.elem_incl 

1373 self.elem_exclude = myDlg.srch.elem_excl 

1374 self.owner.srch_cls = myDlg.srch 

1375 

1376 list_amcsd = [] 

1377 if len(myDlg.AMCSD.GetValue()) > 0: 

1378 myDlg.entrAMCSD() 

1379 

1380 for id in myDlg.srch.amcsd: 

1381 try: 

1382 list_amcsd += [int(id)] 

1383 except: 

1384 pass 

1385 if len(list_amcsd) < 1: list_amcsd = None 

1386 

1387 

1388 if myDlg.Mineral.IsTextEmpty(): 

1389 self.mnrl_include = None 

1390 else: 

1391 self.mnrl_include = myDlg.Mineral.GetStringSelection() 

1392 if myDlg.Author.GetValue() == '': 

1393 self.auth_include = None 

1394 else: 

1395 self.auth_include = myDlg.Author.GetValue().split(',') 

1396 

1397 filter = True 

1398 myDlg.Destroy() 

1399 

1400 if filter == True: 

1401 

1402 if len(self.elem_include) > 0 or len(self.elem_exclude) > 0: 

1403 list_amcsd = cifdb.amcsd_by_chemistry(include=self.elem_include, 

1404 exclude=self.elem_exclude, 

1405 list=list_amcsd) 

1406 if self.mnrl_include is not None: 

1407 list_amcsd = cifdb.amcsd_by_mineral(self.mnrl_include, 

1408 list=list_amcsd) 

1409 if self.auth_include is not None: 

1410 list_amcsd = cifdb.amcsd_by_author(include=self.auth_include, 

1411 list=list_amcsd) 

1412 try: 

1413 self.displayMATCHES(list_amcsd) 

1414 except: 

1415 pass 

1416 

1417 

1418 def onMatch(self,event=None): 

1419 

1420 q_pks = peaklocater(self.xrd1dgrp.pki,self.plt_data[0]) 

1421 # print('Still need to determine how best to rank these matches') 

1422 list_amcsd = match_database(self.owner.cifdb, q_pks, 

1423 qmin=np.min(self.plt_data[0]), 

1424 qmax=np.max(self.plt_data[0])) 

1425 self.displayMATCHES(list_amcsd) 

1426 

1427 def displayMATCHES(self,list_amcsd): 

1428 ''' 

1429 Populates Results Panel with list 

1430 ''' 

1431 self.srchpl.amcsdlistbox.Clear() 

1432 self.displayCIFpeaks(show=False) 

1433 

1434 if list_amcsd is not None and len(list_amcsd) > 0: 

1435 for amcsd in list_amcsd: 

1436 try: 

1437 elem,name,spgp,autr = self.owner.cifdb.all_by_amcsd(amcsd) 

1438 entry = '%i : %s' % (amcsd,name) 

1439 self.srchpl.amcsdlistbox.Append(entry) 

1440 except: 

1441 print('\t ** amcsd #%i not found in database.' % amcsd) 

1442 list_amcsd.remove(amcsd) 

1443 if len(list_amcsd) == 1: 

1444 self.txt_amcsd_cnt.SetLabel('1 MATCH') 

1445 elif len(list_amcsd) > 1: 

1446 self.txt_amcsd_cnt.SetLabel('%i MATCHES' % len(list_amcsd)) 

1447 else: 

1448 self.txt_amcsd_cnt.SetLabel('') 

1449 

1450 self.srchpl.btn_clr.Enable() 

1451 self.srchpl.btn_shw.Enable() 

1452 self.srchpl.amcsdlistbox.EnsureVisible(0) 

1453 

1454 def clearMATCHES(self,event=None): 

1455 ''' 

1456 Populates Results Panel with list 

1457 ''' 

1458 self.txt_amcsd_cnt.SetLabel('') 

1459 

1460 self.srchpl.amcsdlistbox.Clear() 

1461 self.owner.srch_cls = SearchCIFdb() 

1462 

1463 self.srchpl.btn_clr.Disable() 

1464 self.srchpl.btn_shw.Disable() 

1465 

1466 try: 

1467 self.displayCIFpeaks(show=False) 

1468 except: 

1469 pass 

1470 

1471class BackgroundOptions(wx.Dialog): 

1472 def __init__(self,parent): 

1473 

1474 """Constructor""" 

1475 dialog = wx.Dialog.__init__(self, parent, title='Background fitting options', 

1476 style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER, 

1477 size = (210,410)) 

1478 self.parent = parent 

1479 

1480 self.createPanel() 

1481 

1482 self.PanelValues() 

1483 

1484 ix,iy = self.panel.GetBestSize() 

1485 self.SetSize((ix+20, iy+40)) 

1486 

1487 def PanelValues(self, event=None): 

1488 

1489 ## Set defaults 

1490 self.val_exp.SetValue( str( self.parent.bkgd_kwargs['exponent'] ) ) 

1491 self.val_comp.SetValue( str( self.parent.bkgd_kwargs['compress'] ) ) 

1492 self.val_wid.SetValue( str( self.parent.bkgd_kwargs['width'] ) ) 

1493 

1494 

1495 def PanelDefaults(self, event=None): 

1496 

1497 ## Set defaults 

1498 self.val_exp.SetValue( str( BKGD_DEFAULT['exponent'] ) ) 

1499 self.val_comp.SetValue( str( BKGD_DEFAULT['compress'] ) ) 

1500 self.val_wid.SetValue( str( BKGD_DEFAULT['width'] ) ) 

1501 

1502 def createPanel(self): 

1503 

1504 self.panel = wx.Panel(self) 

1505 sizer = wx.GridBagSizer(3, 3) 

1506 

1507 mainsizer = wx.BoxSizer(wx.VERTICAL) 

1508 

1509 ## Exponent 

1510 self.val_exp = wx.TextCtrl(self.panel,wx.TE_PROCESS_ENTER) 

1511 

1512 ## Compress 

1513 self.val_comp = wx.TextCtrl(self.panel,wx.TE_PROCESS_ENTER) 

1514 

1515 ## Width 

1516 self.val_wid = wx.TextCtrl(self.panel,wx.TE_PROCESS_ENTER) 

1517 

1518 ## Reset button 

1519 btn_reset = Button(self.panel,label='reset',size=(90, -1),action=self.PanelDefaults) 

1520 

1521 ##### 

1522 ## OKAY! 

1523 oksizer = wx.BoxSizer(wx.HORIZONTAL) 

1524 

1525 hlpBtn = wx.Button(self.panel, wx.ID_HELP ) 

1526 self.okBtn = wx.Button(self.panel, wx.ID_OK ) 

1527 canBtn = wx.Button(self.panel, wx.ID_CANCEL ) 

1528 

1529 hlpBtn.Bind(wx.EVT_BUTTON, lambda evt: wx.TipWindow( 

1530 self, 'These values are specific to the background fitting defined in:' 

1531 ' Nucl. Instrum. Methods (1987) B22, 78-81.\n\n' 

1532 ' EXPONENT : Specifies the power of polynomial which is used.\n\n' 

1533 ' COMPRESS : Compression factor to apply before fitting the background.\n\n' 

1534 ' WIDTH : Specifies the width of the polynomials which are concave downward.')) 

1535 

1536 

1537 def txt(s): 

1538 return SimpleText(self.panel, s) 

1539 sizer.Add(txt('EXPONENT'), ( 0, 0), (1, 4), ALL_CEN, 2) 

1540 sizer.Add(self.val_exp, ( 0, 4), (1, 2), ALL_LEFT, 2) 

1541 sizer.Add(txt('COMPRESS'), ( 1, 0), (1, 4), ALL_CEN, 2) 

1542 sizer.Add(self.val_comp, ( 1, 4), (1, 2), ALL_LEFT, 2) 

1543 sizer.Add(txt('WIDTH'), ( 2, 0), (1, 4), ALL_CEN, 2) 

1544 sizer.Add(self.val_wid, ( 2, 4), (1, 2), ALL_LEFT, 2) 

1545 sizer.Add(btn_reset, ( 3, 4), (1, 2), ALL_LEFT, 2) 

1546 

1547 sizer.Add(hlpBtn, ( 5, 0), (1, 2), ALL_LEFT, 2) 

1548 sizer.Add(self.okBtn, ( 5, 4), (1, 2), ALL_LEFT, 2) 

1549 sizer.Add(canBtn, ( 5, 2), (1, 2), ALL_LEFT, 2) 

1550 

1551 pack(self.panel, sizer) 

1552 

1553 

1554class PeakOptions(wx.Dialog): 

1555 def __init__(self,parent,method='peakutils.indexes'): 

1556 

1557 """Constructor""" 

1558 dialog = wx.Dialog.__init__(self, parent, title='Peak searching options', 

1559 style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER, 

1560 size = (210,410)) 

1561 self.parent = parent 

1562 

1563 if method == 'scipy.signal.find_peaks_cwt': 

1564 self.createPanel_scipy() 

1565 

1566 ## Set defaults 

1567 self.val1.SetValue(str(self.parent.widths)) 

1568 self.val2.SetValue(str(self.parent.gapthrsh)) 

1569 elif method == 'peakutils.indexes': 

1570 self.createPanel_index() 

1571 

1572 ## Set defaults 

1573 self.val1.SetValue(str(self.parent.thrsh)) 

1574 self.val2.SetValue(str(self.parent.min_dist)) 

1575 else: 

1576 return 

1577 

1578 ix,iy = self.panel.GetBestSize() 

1579 self.SetSize((ix+20, iy+50)) 

1580 

1581 def createPanel_index(self): 

1582 

1583 self.panel = wx.Panel(self) 

1584 

1585 mainsizer = wx.BoxSizer(wx.VERTICAL) 

1586 

1587 ## Threshold 

1588 thrshsizer = wx.BoxSizer(wx.VERTICAL) 

1589 

1590 ttl_thrsh = wx.StaticText(self.panel, label='Threshold') 

1591 self.val1 = wx.TextCtrl(self.panel,wx.TE_PROCESS_ENTER) 

1592 

1593 thrshsizer.Add(ttl_thrsh, flag=wx.RIGHT, border=5) 

1594 thrshsizer.Add(self.val1, flag=wx.RIGHT, border=5) 

1595 

1596 ## Minimum distance 

1597 distsizer = wx.BoxSizer(wx.VERTICAL) 

1598 

1599 ttl_gpthr = wx.StaticText(self.panel, label='Minimum distance') 

1600 

1601 self.val2 = wx.TextCtrl(self.panel,wx.TE_PROCESS_ENTER) 

1602 distsizer.Add(ttl_gpthr, flag=wx.RIGHT, border=5) 

1603 distsizer.Add(self.val2, flag=wx.RIGHT, border=5) 

1604 

1605 

1606 ##### 

1607 ## OKAY! 

1608 oksizer = wx.BoxSizer(wx.HORIZONTAL) 

1609 

1610 hlpBtn = wx.Button(self.panel, wx.ID_HELP ) 

1611 okBtn = wx.Button(self.panel, wx.ID_OK ) 

1612 canBtn = wx.Button(self.panel, wx.ID_CANCEL ) 

1613 

1614 hlpBtn.Bind(wx.EVT_BUTTON, lambda evt: wx.TipWindow( 

1615 self, 'These values are specific to the built-in peakutils.index' 

1616 ' function: ' 

1617 ' thres : Threshold for detecting a peak/valley. The ' 

1618 ' absolute value of the intensity must be above this value. ' 

1619 ' min_dist : Minimum distance between each detected peak. The ' 

1620 ' peak with the highest amplitude is preferred to satisfy this ' 

1621 ' constraint. ' 

1622 ' ')) 

1623 

1624 oksizer.Add(hlpBtn, flag=wx.RIGHT, border=8) 

1625 oksizer.Add(canBtn, flag=wx.RIGHT, border=8) 

1626 oksizer.Add(okBtn, flag=wx.RIGHT, border=8) 

1627 

1628 mainsizer.Add(thrshsizer, flag=wx.ALL, border=8) 

1629 mainsizer.AddSpacer(10) 

1630 mainsizer.Add(distsizer, flag=wx.ALL, border=5) 

1631 mainsizer.AddSpacer(10) 

1632 mainsizer.Add(oksizer, flag=wx.ALL|wx.ALIGN_RIGHT, border=10) 

1633 

1634 

1635 self.panel.SetSizer(mainsizer) 

1636 

1637 def createPanel_scipy(self): 

1638 

1639 self.panel = wx.Panel(self) 

1640 

1641 mainsizer = wx.BoxSizer(wx.VERTICAL) 

1642 

1643 ## Regions 

1644 rgnsizer = wx.BoxSizer(wx.VERTICAL) 

1645 

1646 ttl_rgn = wx.StaticText(self.panel, label='Regions') 

1647 self.val1 = wx.TextCtrl(self.panel,wx.TE_PROCESS_ENTER) 

1648 rgnsizer.Add(ttl_rgn, flag=wx.RIGHT, border=5) 

1649 rgnsizer.Add(self.val1, flag=wx.RIGHT, border=5) 

1650 

1651 ## Gap threshold 

1652 gpthrsizer = wx.BoxSizer(wx.VERTICAL) 

1653 

1654 ttl_gpthr = wx.StaticText(self.panel, label='Gap threshold') 

1655 self.val2 = wx.TextCtrl(self.panel,wx.TE_PROCESS_ENTER) 

1656 gpthrsizer.Add(ttl_gpthr, flag=wx.RIGHT, border=5) 

1657 gpthrsizer.Add(self.val2, flag=wx.RIGHT, border=5) 

1658 

1659 

1660 ##### 

1661 ## OKAY! 

1662 oksizer = wx.BoxSizer(wx.HORIZONTAL) 

1663 

1664 hlpBtn = wx.Button(self.panel, wx.ID_HELP ) 

1665 self.okBtn = wx.Button(self.panel, wx.ID_OK , label='Find peaks') 

1666 canBtn = wx.Button(self.panel, wx.ID_CANCEL ) 

1667 

1668 hlpBtn.Bind(wx.EVT_BUTTON, lambda evt: wx.TipWindow( 

1669 self, 'These values are specific to the built-in scipy function:' 

1670 ' scipy.signal.find_peaks_cwt(vector, widths, wavelet=None,' 

1671 ' max_distances=None, gap_thresh=None, min_length=None,' 

1672 ' min_snr=1, noise_perc=10), where he number of regions defines the' 

1673 ' width squence [widths = arange(int(len(x_axis)/regions))]')) 

1674 

1675 oksizer.Add(hlpBtn, flag=wx.RIGHT, border=8) 

1676 oksizer.Add(canBtn, flag=wx.RIGHT, border=8) 

1677 oksizer.Add(self.okBtn, flag=wx.RIGHT, border=8) 

1678 

1679 mainsizer.Add(rgnsizer, flag=wx.ALL, border=8) 

1680 mainsizer.AddSpacer(10) 

1681 mainsizer.Add(gpthrsizer, flag=wx.ALL, border=5) 

1682 mainsizer.AddSpacer(10) 

1683 mainsizer.Add(oksizer, flag=wx.ALL|wx.ALIGN_RIGHT, border=10) 

1684 

1685 

1686 self.panel.SetSizer(mainsizer) 

1687 

1688class Viewer1DXRD(wx.Panel): 

1689 ''' 

1690 Panel for housing 1D XRD viewer 

1691 ''' 

1692 label='Viewer' 

1693 def __init__(self, parent, owner=None, _larch=None): 

1694 

1695 wx.Panel.__init__(self, parent) 

1696 self.parent = parent 

1697 self.owner = owner 

1698 

1699 ## Default information 

1700 self.plotlist = [] 

1701 self.xlabel = 'q (1/$\AA$)' #'q (A^-1)' 

1702 self.ylabel = 'Intensity (a.u.)' 

1703 self.dlimit = 7.5 # A -> 2th = 5 deg.; q = 0.8 1/A 

1704 

1705 self.data_name = [] 

1706 self.xy_data = [] 

1707 self.xy_plot = [] 

1708 self.xy_scale = [] 

1709 self.idata = [] 

1710 

1711 self.cif_name = [] 

1712 self.cif_plot = [] 

1713 self.cif_all = [] 

1714 self.cif_scale = [] 

1715 self.icif = [] 

1716 

1717 # leftbox = wx.BoxSizer(wx.VERTICAL) 

1718 

1719 # add_btns = wx.BoxSizer(wx.HORIZONTAL) 

1720 # add_btns.Add(Button(self, label=' Add Data Set ', 

1721 # action=self.load_file), 

1722 # wx.ALL, border=3) 

1723 # add_btns.Add(Button(self, label=' Add CIF Structure ', 

1724 # action=self.select_CIF), 

1725 # wx.ALL, border=3) 

1726 

1727 dattools = self.DataBox(self) 

1728 # ciftools = self.CIFBox(self) 

1729 

1730 # leftbox.Add(plttools, flag=wx.ALL, border=2) 

1731 # leftbox.Add(add_btns, flag=wx.ALL,border=10) 

1732 # leftbox.Add(dattools, flag=wx.ALL,border=2) 

1733 # leftbox.Add(ciftools, flag=wx.ALL,border=10) 

1734 

1735 # tlbx = wx.StaticBox(self,label='PLOT TOOLBOX') 

1736 xybox = wx.BoxSizer(wx.HORIZONTAL) 

1737 

1738 xunits = [u'q (\u212B\u207B\u00B9)',u'2\u03B8 (\u00B0)',u'd (\u212B)'] 

1739 yscales = ['linear','log'] 

1740 

1741 self.ch_xaxis = Choice(self, choices=xunits, action=self.check1Daxis) 

1742 self.ch_yaxis = Choice(self, choices=yscales, action=self.onLogLinear) 

1743 self.ch_xaxis.SetSelection(0) 

1744 self.ch_yaxis.SetSelection(0) 

1745 

1746 xybox.Add(wx.StaticText(self, label='X scale:'), wx.ALL, border=4) 

1747 xybox.Add(self.ch_xaxis, wx.ALL, border=4) 

1748 xybox.Add(wx.StaticText(self, label='Y scale:'), wx.ALL, border=4) 

1749 xybox.Add(self.ch_yaxis, wx.ALL, border=4) 

1750 

1751 

1752 # rightbox = wx.BoxSizer(wx.VERTICAL) 

1753 self.plot1D = PlotPanel(self,size=(700, 450), 

1754 messenger=self.owner.write_message) 

1755 self.plot1D.cursor_mode = 'zoom' 

1756 # rightbox.Add(self.plot1D, proportion=1, flag=wx.ALL|wx.EXPAND, border=10) 

1757 

1758 panel = wx.GridBagSizer(3) 

1759 panel.Add(dattools, (0, 0), (1, 1), wx.ALL, border=5) 

1760 panel.Add(self.plot1D, (0, 1), (1, 1), wx.ALL|wx.EXPAND, border=5) 

1761 panel.Add(xybox, (1, 1), (1, 1), wx.ALL, border=5) 

1762 

1763 self.SetSizer(panel) 

1764 

1765 

1766 def onSAVEfig(self,event=None): 

1767 self.plot1D.save_figure() 

1768 

1769 def onPLOTset(self,event=None): 

1770 self.plot1D.configure() 

1771 

1772 def onRESETplot(self,event=None): 

1773 self.plot1D.reset_config() 

1774 

1775 def onLogLinear(self, event=None): 

1776 self.plot1D.axes.set_yscale(self.ch_yaxis.GetString(self.ch_yaxis.GetSelection())) 

1777 self.rescale1Daxis(xaxis=False, yaxis=True) 

1778 

1779 def OToolbox(self, panel): 

1780 ''' 

1781 Frame for visual toolbox 

1782 ''' 

1783 

1784 tlbx = wx.StaticBox(self,label='PLOT TOOLBOX') 

1785 vbox = wx.StaticBoxSizer(tlbx, wx.VERTICAL) 

1786 

1787 ########################### 

1788 ## X-Scale 

1789 hbox_xaxis = wx.BoxSizer(wx.HORIZONTAL) 

1790 ttl_xaxis = wx.StaticText(self, label='X-SCALE') 

1791 xunits = [u'q (\u212B\u207B\u00B9)',u'2\u03B8 (\u00B0)',u'd (\u212B)'] 

1792 self.ch_xaxis = wx.Choice(self,choices=xunits) 

1793 

1794 self.ch_xaxis.Bind(wx.EVT_CHOICE, self.check1Daxis) 

1795 

1796 hbox_xaxis.Add(ttl_xaxis, flag=wx.RIGHT, border=8) 

1797 hbox_xaxis.Add(self.ch_xaxis, flag=wx.EXPAND, border=8) 

1798 vbox.Add(hbox_xaxis, flag=wx.ALL, border=10) 

1799 

1800 ########################### 

1801 ## Y-Scale 

1802 hbox_yaxis = wx.BoxSizer(wx.HORIZONTAL) 

1803 ttl_yaxis = wx.StaticText(self, label='Y-SCALE') 

1804 yscales = ['linear','log'] 

1805 self.ch_yaxis = wx.Choice(self,choices=yscales) 

1806 

1807 self.ch_yaxis.Bind(wx.EVT_CHOICE, self.onLogLinear) 

1808 

1809 hbox_yaxis.Add(ttl_yaxis, flag=wx.RIGHT, border=8) 

1810 hbox_yaxis.Add(self.ch_yaxis, flag=wx.EXPAND, border=8) 

1811 vbox.Add(hbox_yaxis, flag=wx.ALL, border=10) 

1812 

1813 self.ch_xaxis.Disable() 

1814 self.ch_yaxis.Disable() 

1815 return vbox 

1816 

1817 def XYChoices(self, panel): 

1818 '''Frame for x/y scale''' 

1819 pass 

1820 # tlbx = wx.StaticBox(self,label='PLOT TOOLBOX') 

1821 box = wx.BoxSizer(wx.HORIZONTAL) 

1822 

1823 xunits = [u'q (\u212B\u207B\u00B9)',u'2\u03B8 (\u00B0)',u'd (\u212B)'] 

1824 yscales = ['linear','log'] 

1825 

1826 self.ch_xaxis = Choice(self, choices=xunits, action=self.check1Daxis) 

1827 self.ch_yaxis = Choice(self, choices=yscales, action=self.onLogLinear) 

1828 

1829 box.Add(wx.StaticText(self, label='X scale:'), wx.ALL, border=4) 

1830 box.Add(self.ch_xaxis, wx.ALL, border=4) 

1831 box.Add(wx.StaticText(self, label='Y scale:'), wx.ALL, border=4) 

1832 box.Add(self.ch_yaxis, wx.ALL, border=4) 

1833 # self.ch_xaxis.Disable() 

1834 # self.ch_yaxis.Disable() 

1835 return box 

1836 

1837 def DataBox(self,panel): 

1838 ''' 

1839 Frame for data toolbox 

1840 ''' 

1841 

1842 tlbx = wx.StaticBox(self,label='DATA TOOLBOX') 

1843 vbox = wx.StaticBoxSizer(tlbx,wx.VERTICAL) 

1844 

1845 

1846 ########################### 

1847 ## DATA CHOICE 

1848 

1849 self.ch_data = wx.Choice(self,choices=self.data_name) 

1850 self.ch_data.Bind(wx.EVT_CHOICE, self.onSELECT) 

1851 vbox.Add(self.ch_data, flag=wx.BOTTOM|wx.TOP|wx.EXPAND, border=8) 

1852 

1853 ########################### 

1854 # Energy display 

1855 self.ttl_energy = wx.StaticText(self, label=('Energy:')) 

1856 vbox.Add(self.ttl_energy, flag=wx.RIGHT, border=8) 

1857 

1858 ########################### 

1859 ## Scale 

1860 hbox_scl = wx.BoxSizer(wx.HORIZONTAL) 

1861 ttl_scl = wx.StaticText(self, label='SCALE Y TO:') 

1862 self.val_scale = wx.TextCtrl(self,style=wx.TE_PROCESS_ENTER) 

1863 self.btn_reset = wx.Button(self,label='reset') 

1864 

1865 self.val_scale.Bind(wx.EVT_TEXT_ENTER, self.normalize1Ddata) 

1866 self.btn_reset.Bind(wx.EVT_BUTTON, self.reset1Dscale) 

1867 

1868 hbox_scl.Add(ttl_scl, flag=wx.RIGHT, border=8) 

1869 hbox_scl.Add(self.val_scale, flag=wx.RIGHT, border=8) 

1870 hbox_scl.Add(self.btn_reset, flag=wx.RIGHT, border=8) 

1871 

1872 vbox.Add(hbox_scl, flag=wx.BOTTOM|wx.TOP, border=8) 

1873 

1874 ## Disable until data 

1875 self.btn_reset.Disable() 

1876 self.val_scale.Disable() 

1877 

1878 return vbox 

1879 

1880 def CIFBox(self,panel): 

1881 ''' 

1882 Frame for data toolbox 

1883 ''' 

1884 

1885 tlbx = wx.StaticBox(self,label='CIF TOOLBOX') 

1886 vbox = wx.StaticBoxSizer(tlbx,wx.VERTICAL) 

1887 

1888 ########################### 

1889 ## DATA CHOICE 

1890 

1891 self.ch_cif = wx.Choice(self,choices=self.cif_name) 

1892 self.ch_cif.Bind(wx.EVT_CHOICE, self.selectCIF) 

1893 vbox.Add(self.ch_cif, flag=wx.BOTTOM|wx.TOP|wx.EXPAND, border=8) 

1894 

1895 ########################### 

1896 ## Energy 

1897 hbox_E = wx.BoxSizer(wx.HORIZONTAL) 

1898 self.slctEorL = wx.Choice(self,choices=['Energy (keV)','Wavelength (A)']) 

1899 self.val_cifE = wx.TextCtrl(self,style=wx.TE_PROCESS_ENTER) 

1900 

1901 self.slctEorL.Bind(wx.EVT_CHOICE, self.onEorLSel) 

1902 self.val_cifE.Bind(wx.EVT_TEXT_ENTER, self.onResetE) 

1903 

1904 hbox_E.Add(self.slctEorL, flag=wx.RIGHT, border=8) 

1905 hbox_E.Add(self.val_cifE, flag=wx.RIGHT, border=8) 

1906 vbox.Add(hbox_E, flag=wx.BOTTOM|wx.TOP, border=8) 

1907 

1908 ########################### 

1909 ## Scale 

1910 hbox_scl = wx.BoxSizer(wx.HORIZONTAL) 

1911 ttl_scl = wx.StaticText(self, label='SCALE Y TO:') 

1912 self.val_cifscale = wx.TextCtrl(self,style=wx.TE_PROCESS_ENTER) 

1913 self.btn_cifreset = wx.Button(self,label='reset') 

1914 

1915 self.val_cifscale.Bind(wx.EVT_TEXT_ENTER, partial(self.normalize1Ddata,cif=True)) 

1916 self.btn_cifreset.Bind(wx.EVT_BUTTON, self.resetCIFscale) 

1917 

1918 hbox_scl.Add(ttl_scl, flag=wx.RIGHT, border=8) 

1919 hbox_scl.Add(self.val_cifscale, flag=wx.RIGHT, border=8) 

1920 hbox_scl.Add(self.btn_cifreset, flag=wx.RIGHT, border=8) 

1921 

1922 vbox.Add(hbox_scl, flag=wx.BOTTOM|wx.TOP, border=8) 

1923 

1924 ## Disable until data 

1925 self.val_cifscale.Disable() 

1926 self.btn_cifreset.Disable() 

1927 self.slctEorL.Disable() 

1928 self.val_cifE.Disable() 

1929 

1930 return vbox 

1931 

1932 

1933 

1934 

1935 

1936 

1937############################################## 

1938#### XRD PLOTTING FUNCTIONS 

1939 

1940 def addCIFdata(self,cif,newcif,datalabel): 

1941 

1942 cif_no = len(self.cif_name) 

1943 

1944 ## Add 'raw' data to array 

1945 self.cif_plot.append(newcif) 

1946 self.cif_all.append(cif) 

1947 

1948 cifscale = np.max(self.cif_plot[-1][3]) 

1949 self.cif_scale.append(int(cifscale)) 

1950 

1951 self.cif_name.append(datalabel) 

1952 

1953 ## Plot data (x,y) 

1954 self.icif.append(len(self.plotlist)) 

1955 xi = self.ch_xaxis.GetSelection() 

1956 

1957 cifarg = {'xlabel':self.xlabel,'ylabel':self.ylabel,'label':datalabel,'marker':'','markersize':0,'show_legend':True} 

1958 self.plotlist.append(self.plot1D.oplot(self.cif_plot[-1][xi],self.cif_plot[-1][3],**cifarg)) 

1959 

1960 ## Use correct x-axis units 

1961 self.check1Daxis() 

1962 

1963 self.ch_cif.Set(self.cif_name) 

1964 self.ch_cif.SetStringSelection(datalabel) 

1965 

1966 ## Update toolbox panel, scale all cif to 1000 

1967 self.val_cifscale.SetValue('%i' % self.cif_scale[cif_no]) 

1968 self.optionsON(data=False,cif=True) 

1969 

1970 def readCIF(self, path, cifscale=CIFSCALE, verbose=False): 

1971 wavelength = lambda_from_E(self.getE()) 

1972 qmin, qmax = 0.2, 8.0 

1973 for i,data in enumerate(self.xy_plot): 

1974 qmax = 1.05*np.max(data[0]) 

1975 qmin = 0.95*np.min(data[0]) 

1976 if qmax > (4*math.pi/wavelength): qmax = (4*math.pi/wavelength)*0.95 

1977 

1978 cif = create_xrdcif(filename=path) 

1979 cif.structure_factors(wavelength=wavelength, q_min=qmin, q_max=qmax) 

1980 qall, Iall = plot_sticks(cif.qhkl, cif.Ihkl) 

1981 if len(Iall) > 0: 

1982 twth = twth_from_q(qall, wavelength) 

1983 d = d_from_q(qall) 

1984 I = Iall/np.max(Iall)*cifscale 

1985 else: 

1986 print('No real structure factors found in range.') 

1987 return 

1988 

1989 return [qall, twth, d, I] 

1990 

1991 def onResetE(self,event=None): 

1992 

1993 wavelength = lambda_from_E(self.getE()) 

1994 

1995 qmin, qmax = 0.2, 8.0 

1996 for i,data in enumerate(self.xy_plot): 

1997 qmax = 1.05*np.max(data[0]) 

1998 qmin = 0.95*np.min(data[0]) 

1999 if qmax > (4*math.pi/wavelength): qmax = (4*math.pi/wavelength)*0.95 

2000 

2001 

2002 xi = self.ch_xaxis.GetSelection() 

2003 for i,cif_no in enumerate(self.icif): 

2004 self.cif_plot[i] = calculateCIF(self.cif_all[i], wavelength=wavelength, 

2005 qmin=qmin, qmax=qmax, 

2006 cifscale=self.cif_scale[i]) 

2007 self.plot1D.update_line(cif_no,np.array(self.cif_plot[i][xi]), 

2008 np.array(self.cif_plot[i][3])) 

2009 self.plot1D.canvas.draw() 

2010 

2011 def onEorLSel(self,event=None): 

2012 

2013 try: 

2014 current = float(self.val_cifE.GetValue()) 

2015 except: 

2016 return 

2017 

2018 if self.slctEorL.GetSelection() == 1 and current > 5: 

2019 new = '%0.4f' % lambda_from_E(current) 

2020 elif self.slctEorL.GetSelection() == 0 and current < 5: 

2021 new = '%0.4f' % E_from_lambda(current) 

2022 else: 

2023 return 

2024 

2025 self.val_cifE.SetValue(new) 

2026 

2027 def optionsON(self,data=True,cif=False): 

2028 

2029 self.ch_xaxis.Enable() 

2030 self.ch_yaxis.Enable() 

2031 

2032 if data: 

2033 self.val_scale.Enable() 

2034 self.btn_reset.Enable() 

2035 if cif: 

2036 self.val_cifscale.Enable() 

2037 self.btn_cifreset.Enable() 

2038 self.slctEorL.Enable() 

2039 self.val_cifE.Enable() 

2040 

2041 def add1Ddata(self,data1dxrd): 

2042 

2043 try: 

2044 len(data1dxrd.I) 

2045 except: 

2046 return 

2047 

2048 self.xy_data.append(data1dxrd) 

2049 

2050 if self.xy_data[-1].label is None: 

2051 self.xy_data[-1].label = 'dataset %i' % len(self.xy_data) 

2052 datalabel = self.xy_data[-1].label 

2053 

2054 self.data_name.append(datalabel) 

2055 self.idata.append(len(self.plotlist)) 

2056 self.xy_scale.append(np.max(self.xy_data[-1].I)) 

2057 

2058 self.xy_plot.append(self.xy_data[-1].all_data()) 

2059 

2060 ## Plot data (x,y) 

2061 xi = self.ch_xaxis.GetSelection() 

2062 datarg = {'xlabel':self.xlabel,'ylabel':self.ylabel,'label':datalabel,'marker':'', 

2063 'show_legend':True} 

2064 x,y = self.xy_plot[-1][xi],self.xy_plot[-1][3] 

2065 self.plotlist.append(self.plot1D.oplot(x,y,**datarg)) 

2066 

2067 ## Use correct x-axis units 

2068 self.check1Daxis(yaxis=True) 

2069 

2070 self.ch_data.Set(self.data_name) 

2071 self.ch_data.SetStringSelection(datalabel) 

2072 

2073 ## Update toolbox panel 

2074 self.val_scale.SetValue('%i' % self.xy_scale[-1]) 

2075 self.optionsON(data=True,cif=False) 

2076 self.ttl_energy.SetLabel('Energy: %0.3f keV (%0.4f A)' % (self.xy_data[-1].energy, 

2077 self.xy_data[-1].wavelength)) 

2078 

2079 def normalize1Ddata(self,event=None,cif=False): 

2080 

2081 if cif: 

2082 cif_no = self.ch_cif.GetSelection() 

2083 y = self.cif_plot[cif_no][3] 

2084 

2085 self.cif_scale[cif_no] = float(self.val_cifscale.GetValue()) 

2086 if self.cif_scale[cif_no] <= 0: 

2087 self.cif_scale[cif_no] = CIFSCALE 

2088 self.val_cifscale.SetValue('%i' % self.cif_scale[cif_no]) 

2089 self.cif_plot[cif_no][3] = y/np.max(y) * self.cif_scale[cif_no] 

2090 else: 

2091 plt_no = self.ch_data.GetSelection() 

2092 y = self.xy_data[plt_no].I 

2093 

2094 self.xy_scale[plt_no] = float(self.val_scale.GetValue()) 

2095 if self.xy_scale[plt_no] <= 0: 

2096 self.xy_scale[plt_no] = np.max(y) 

2097 self.val_scale.SetValue('%i' % self.xy_scale[plt_no]) 

2098 self.xy_plot[plt_no][3] = y/np.max(y) * self.xy_scale[plt_no] 

2099 

2100 self.plot1D.unzoom_all() 

2101 self.rescale1Daxis(xaxis=False,yaxis=True) 

2102 

2103 def onSELECT(self,event=None): 

2104 

2105 data_str = self.ch_data.GetString(self.ch_data.GetSelection()) 

2106 

2107 plt_no = self.ch_data.GetSelection() 

2108 self.val_scale.SetValue('%i' % self.xy_scale[plt_no]) 

2109 

2110 self.ttl_energy.SetLabel('Energy: %0.3f keV (%0.4f A)' % (self.xy_data[plt_no].energy, 

2111 self.xy_data[plt_no].wavelength)) 

2112 

2113 def selectCIF(self,event=None): 

2114 

2115 cif_str = self.ch_cif.GetString(self.ch_cif.GetSelection()) 

2116 

2117 cif_no = self.ch_cif.GetSelection() 

2118 self.val_cifscale.SetValue('%i' % self.cif_scale[cif_no]) 

2119 

2120 def check1Daxis(self,event=None,yaxis=False): 

2121 

2122 self.plot1D.unzoom_all() 

2123 

2124 ## d 

2125 if self.ch_xaxis.GetSelection() == 2: 

2126 self.xlabel = 'd ($\AA$)' 

2127 ## 2theta 

2128 elif self.ch_xaxis.GetSelection() == 1: 

2129 self.xlabel = r'$2\Theta$'+r' $(^\circ)$' 

2130 ## q 

2131 else: 

2132 self.xlabel = 'q (1/$\AA$)' 

2133 

2134 self.rescale1Daxis(xaxis=True,yaxis=yaxis) 

2135 

2136 def rescale1Daxis(self,xaxis=True,yaxis=False): 

2137 

2138 xi = self.ch_xaxis.GetSelection() 

2139 

2140 xmin,xmax,ymin,ymax = 0,10,0,10 

2141 

2142 for i,plt_no in enumerate(self.icif): 

2143 

2144 x = np.array(self.cif_plot[i][xi]) 

2145 y = np.array(self.cif_plot[i][3]) 

2146 

2147 if xmax < np.max(x): xmax = np.max(x) 

2148 if xmin > np.min(x): xmin = np.min(x) 

2149 if ymax < np.max(y): ymax = np.max(y) 

2150 if ymin > np.min(y): ymin = np.min(y) 

2151 

2152 self.plot1D.update_line(plt_no,x,y) 

2153 

2154 for i,plt_no in enumerate(self.idata): 

2155 x = np.array(self.xy_plot[i][xi]) 

2156 y = np.array(self.xy_plot[i][3]) 

2157 

2158 if xmax < np.max(x): xmax = np.max(x) 

2159 if xmin > np.min(x): xmin = np.min(x) 

2160 if ymax < np.max(y): ymax = np.max(y) 

2161 if ymin > np.min(y): ymin = np.min(y) 

2162 

2163 self.plot1D.update_line(plt_no,x,y) 

2164 

2165 if xi == 2: xmax = min(xmax,self.dlimit) 

2166 if xaxis: self.set_xview(xmin, xmax) 

2167 if yaxis: self.set_yview(ymin, ymax) 

2168 

2169 def reset1Dscale(self,event=None): 

2170 

2171 plt_no = self.ch_data.GetSelection() 

2172 xi = self.ch_xaxis.GetSelection() 

2173 

2174 self.xy_plot[plt_no][3] = self.xy_data[plt_no].I 

2175 self.plot1D.update_line(int(self.idata[plt_no]), 

2176 np.array(self.xy_plot[plt_no][xi]), 

2177 np.array(self.xy_plot[plt_no][3])) 

2178 self.xy_scale[plt_no] = np.max(self.xy_data[plt_no].I) 

2179 self.val_scale.SetValue('%i' % self.xy_scale[plt_no]) 

2180 

2181 self.plot1D.canvas.draw() 

2182 self.plot1D.unzoom_all() 

2183 self.rescale1Daxis(xaxis=False,yaxis=True) 

2184 

2185 

2186 def resetCIFscale(self,event=None): 

2187 

2188 cif_no = self.ch_cif.GetSelection() 

2189 xi = self.ch_xaxis.GetSelection() 

2190 

2191 self.cif_scale[cif_no] = CIFSCALE 

2192 self.val_cifscale.SetValue('%i' % self.cif_scale[cif_no]) 

2193 self.normalize1Ddata(cif=True) 

2194 

2195 self.plot1D.update_line(int(self.icif[cif_no]), 

2196 np.array(self.cif_plot[cif_no][xi]), 

2197 np.array(self.cif_plot[cif_no][3])) 

2198 self.plot1D.canvas.draw() 

2199 self.plot1D.unzoom_all() 

2200 

2201 self.rescale1Daxis(xaxis=False,yaxis=True) 

2202 

2203 def set_xview(self, x1, x2): 

2204 

2205 if len(self.xy_plot) > 0: 

2206 xydata = self.xy_plot 

2207 elif len(self.cif_plot) > 0: 

2208 xydata = self.cif_plot 

2209 else: 

2210 return 

2211 xi = self.ch_xaxis.GetSelection() 

2212 xmin,xmax = self.abs_limits(xydata,axis=xi) 

2213 

2214 x1 = max(xmin,x1) 

2215 x2 = min(xmax,x2) 

2216 

2217 self.plot1D.axes.set_xlim((x1, x2)) 

2218 self.plot1D.set_xlabel(self.xlabel) 

2219 self.plot1D.canvas.draw() 

2220 

2221 def set_yview(self, y1, y2): 

2222 

2223 if len(self.xy_plot) > 0: 

2224 xydata = self.xy_plot 

2225 elif len(self.cif_plot) > 0: 

2226 xydata = self.cif_plot 

2227 else: 

2228 return 

2229 ymin,ymax = self.abs_limits(xydata,axis=3) 

2230 

2231 y1 = max(ymin,y1) 

2232 y2 = min(ymax,y2) 

2233 

2234 self.plot1D.axes.set_ylim((y1, y2)) 

2235 self.plot1D.set_ylabel(self.ylabel) 

2236 self.plot1D.canvas.draw() 

2237 

2238 def abs_limits(self,xydata,axis=0): 

2239 

2240 mini, maxi = 0,1 

2241 for axisi in xydata: 

2242 mini = np.min(axisi[axis]) if np.min(axisi[axis]) < mini else mini 

2243 maxi = np.max(axisi[axis]) if np.max(axisi[axis]) > maxi else maxi 

2244 

2245 return mini,maxi 

2246 

2247############################################## 

2248#### XRD FILE OPENING/SAVING 

2249 def load_file(self,event=None): 

2250 

2251 loadXYfile(parent=self,xrdviewer=self) 

2252 

2253 def saveXYFILE(self,event=None): 

2254 wildcards = 'XRD data file (*.xy)|*.xy|All files (*.*)|*.*' 

2255 dlg = wx.FileDialog(self, 'Save data as...', 

2256 defaultDir=get_cwd(), 

2257 wildcard=wildcards, 

2258 style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) 

2259 

2260 path, save = None, False 

2261 if dlg.ShowModal() == wx.ID_OK: 

2262 save = True 

2263 path = dlg.GetPath().replace('\\', '/') 

2264 dlg.Destroy() 

2265 

2266 if save: 

2267 ## mkak 2016.11.16 

2268 print('Not yet capable of saving data. Function yet to be written.') 

2269 

2270 def select_CIF(self, event=None, cifscale=CIFSCALE): 

2271 

2272 if len(self.xy_data) > 0: 

2273 plt_no = self.ch_data.GetSelection() 

2274 energy = self.xy_data[plt_no].energy 

2275 else: 

2276 energy = ENERGY 

2277 

2278 qmin,qmax = None,None 

2279 for i,xydata in enumerate(self.xy_plot): 

2280 if i == 0: 

2281 qmin,qmax = np.min(xydata[0]),np.max(xydata[0]) 

2282 else: 

2283 if qmin > np.min(xydata[0]): qmin = np.min(xydata[0]) 

2284 if qmax < np.max(xydata[0]): qmax = np.max(xydata[0]) 

2285 if qmin is None: qmin = QMIN 

2286 if qmax is None: qmax = QMAX 

2287 

2288 dlg = SelectCIFData(self, self.owner.cifdb, 

2289 qmin=qmin, qmax=qmax, energy=energy) 

2290 

2291 okay = False 

2292 if dlg.ShowModal() == wx.ID_OK: 

2293 if True: #try: 

2294 energy = E_from_lambda(dlg.returnLambda()) 

2295 qaxis = dlg.returnQ() 

2296 qmin, qmax = min(qaxis), max(qaxis) 

2297 

2298 if dlg.type == 'file': 

2299 path = dlg.path 

2300 cif = create_xrdcif(filename=path) 

2301 name = os.path.split(path)[-1] 

2302 elif dlg.type == 'database': 

2303 amcsd_id = dlg.amcsd_id 

2304 cif = create_xrdcif(cifdb=self.owner.cifdb, amcsd_id=amcsd_id) 

2305 name = 'AMCSD %i' % amcsd_id 

2306 if cif.label is not None: 

2307 name = '%s : %s' % (name,cif.label) 

2308 

2309 okay = True 

2310 else: # except: 

2311 print('ERROR: something failed while loading CIF') 

2312 pass 

2313 

2314 

2315 dlg.Destroy() 

2316 

2317 if okay: 

2318 self.slctEorL.SetSelection(0) 

2319 self.val_cifE.SetValue(str(energy)) 

2320 wavelength = lambda_from_E(energy) 

2321 newcif = calculateCIF(cif, wavelength=wavelength, qmin=qmin, qmax=qmax, 

2322 cifscale=cifscale) 

2323 self.addCIFdata(cif, newcif, name) 

2324 

2325 def getE(self): 

2326 

2327 try: 

2328 energy = float(self.val_cifE.GetValue()) 

2329 except: 

2330 energy = None 

2331 

2332 if energy is None: 

2333 try: 

2334 plt_no = self.ch_data.GetSelection() 

2335 energy = self.xy_data[plt_no].energy 

2336 except: 

2337 energy = ENERGY 

2338 self.val_cifE.SetValue('%0.3f' % energy) 

2339 self.slctEorL.SetSelection(0) 

2340 else: 

2341 if self.slctEorL.GetSelection() == 0: 

2342 energy = float(self.val_cifE.GetValue()) 

2343 else: 

2344 energy = E_from_lambda(float(self.val_cifE.GetValue())) 

2345 return energy 

2346 

2347 

2348 

2349 

2350def calculateCIF(cif, wavelength=0.65, qmin=0.5, qmax=5.5, cifscale=CIFSCALE): 

2351 cif.structure_factors(wavelength=wavelength, q_min=qmin, q_max=qmax) 

2352 qall, Iall = cif.qhkl, cif.Ihkl 

2353 Iall = Iall/np.max(Iall)*cifscale 

2354 qall, Iall = plot_sticks(qall, Iall) 

2355 

2356 return np.array([qall, twth_from_q(qall,wavelength), d_from_q(qall), Iall]) 

2357 

2358 

2359 

2360class SelectCIFData(wx.Dialog): 

2361 def __init__(self, parent, cifdb, qmin=QMIN, qmax=QMAX, 

2362 energy=ENERGY): 

2363 

2364 self.cifdb = cifdb 

2365 self.type = None 

2366 self.path = None 

2367 self.amcsd_id = None 

2368 

2369 self.xaxis = 0 

2370 

2371 """Constructor""" 

2372 dialog = wx.Dialog.__init__(self, parent, 

2373 title='Select CIF to plot', size=(450, 600)) 

2374 

2375 panel = wx.Panel(self) 

2376 

2377 self.parent = parent 

2378 

2379 

2380 ##### 

2381 ## ENERGY 

2382 self.ch_EorL = wx.Choice(panel, choices=['Energy (keV)','Wavelength (A)']) 

2383 self.val_cifE = wx.TextCtrl(panel, style=wx.TE_PROCESS_ENTER) 

2384 

2385 self.ch_EorL.Bind(wx.EVT_CHOICE, self.onEorLSel) 

2386 

2387 enrgsizer = wx.BoxSizer(wx.HORIZONTAL) 

2388 enrgsizer.Add(self.ch_EorL, flag=wx.RIGHT, border=5) 

2389 enrgsizer.AddSpacer(15) 

2390 enrgsizer.Add(self.val_cifE, flag=wx.RIGHT, border=5) 

2391 

2392 ##### 

2393 ## X-AXIS 

2394 self.ch_xaxis = wx.Choice(panel, choices=[u'q (\u212B\u207B\u00B9)',u'2\u03B8 (\u00B0)',u'd (\u212B)']) 

2395 self.val_xmin = wx.TextCtrl(panel, style=wx.TE_PROCESS_ENTER) 

2396 ttl_xaxis = SimpleText(panel, label=' to ') 

2397 self.val_xmax = wx.TextCtrl(panel, style=wx.TE_PROCESS_ENTER) 

2398 

2399 self.ch_xaxis.Bind(wx.EVT_CHOICE, self.onXscaleSel) 

2400 

2401 xaxssizer = wx.BoxSizer(wx.HORIZONTAL) 

2402 xaxssizer.Add(self.ch_xaxis, flag=wx.RIGHT, border=5) 

2403 xaxssizer.AddSpacer(15) 

2404 xaxssizer.Add(self.val_xmin, flag=wx.RIGHT, border=5) 

2405 xaxssizer.AddSpacer(15) 

2406 xaxssizer.Add(ttl_xaxis, flag=wx.RIGHT, border=5) 

2407 xaxssizer.AddSpacer(15) 

2408 xaxssizer.Add(self.val_xmax, flag=wx.RIGHT, border=5) 

2409 

2410 

2411 btn_fltr = wx.Button(panel, label='Search CIF database') 

2412 ttl_or = SimpleText(panel, label='- OR -') 

2413 btn_ld = wx.Button(panel, label='Load CIF from file') 

2414 

2415 opts = wx.LB_HSCROLL|wx.LB_NEEDED_SB|wx.LB_SORT 

2416 self.cif_list = wx.ListBox(panel, style=opts, choices=[''], size=(250, -1)) 

2417 self.cif_list.Bind(wx.EVT_LISTBOX, self.showCIF ) 

2418 

2419 btn_fltr.Bind(wx.EVT_BUTTON, self.filter_database) 

2420 btn_ld.Bind(wx.EVT_BUTTON, self.load_file) 

2421 

2422 ##### 

2423 ## OKAY! 

2424 okBtn = wx.Button(panel, wx.ID_OK ) 

2425 canBtn = wx.Button(panel, wx.ID_CANCEL ) 

2426 

2427 oksizer = wx.BoxSizer(wx.HORIZONTAL) 

2428 oksizer.Add(canBtn, flag=wx.RIGHT, border=8) 

2429 oksizer.Add(okBtn, flag=wx.RIGHT, border=8) 

2430 

2431 

2432 ##### 

2433 ## BUTTON 

2434 btnsizer = wx.BoxSizer(wx.HORIZONTAL) 

2435 btnsizer.Add(btn_fltr, flag=wx.RIGHT, border=5) 

2436 btnsizer.AddSpacer(15) 

2437 btnsizer.Add(ttl_or, flag=wx.RIGHT, border=5) 

2438 btnsizer.AddSpacer(15) 

2439 btnsizer.Add(btn_ld, flag=wx.RIGHT, border=5) 

2440 

2441 

2442 ##### 

2443 ## TOTAL 

2444 mainsizer = wx.BoxSizer(wx.VERTICAL) 

2445 mainsizer.AddSpacer(5) 

2446 mainsizer.Add(enrgsizer, flag=wx.BOTTOM|wx.TOP|wx.LEFT, border=5) 

2447 mainsizer.AddSpacer(5) 

2448 mainsizer.Add(xaxssizer, flag=wx.BOTTOM|wx.TOP|wx.LEFT, border=5) 

2449 mainsizer.AddSpacer(15) 

2450 mainsizer.Add(btnsizer, flag=wx.BOTTOM|wx.TOP|wx.LEFT, border=5) 

2451 mainsizer.AddSpacer(10) 

2452 mainsizer.Add(self.cif_list, flag=wx.BOTTOM|wx.LEFT, border=8) 

2453 mainsizer.AddSpacer(15) 

2454 mainsizer.Add(oksizer, flag=wx.BOTTOM|wx.ALIGN_RIGHT, border=10) 

2455 

2456 panel.SetSizer(mainsizer) 

2457 

2458 ix,iy = panel.GetBestSize() 

2459 self.SetSize((ix+20, iy+50)) 

2460 

2461 self.val_cifE.SetValue('%0.4f' % energy) 

2462 self.ch_xaxis.SetSelection(self.xaxis) 

2463 self.val_xmin.SetValue('%0.4f' % qmin) 

2464 self.val_xmax.SetValue('%0.4f' % qmax) 

2465 

2466 def returnLambda(self,event=None): 

2467 

2468 if self.ch_EorL.GetSelection() == 1: 

2469 return float(self.val_cifE.GetValue()) 

2470 elif self.ch_EorL.GetSelection() == 0: 

2471 return lambda_from_E(float(self.val_cifE.GetValue())) 

2472 

2473 def returnQ(self,event=None): 

2474 

2475 val_min = float(self.val_xmin.GetValue()) 

2476 val_max = float(self.val_xmax.GetValue()) 

2477 wavelength = self.returnLambda() 

2478 

2479 if self.ch_xaxis.GetSelection() == 2: 

2480 return q_from_d(val_min),q_from_d(val_max) 

2481 elif self.ch_xaxis.GetSelection() == 1: 

2482 return q_from_twth(val_min,wavelength),q_from_twth(val_max,wavelength) 

2483 else: 

2484 return val_min,val_max 

2485 

2486 def onXscaleSel(self,event=None): 

2487 

2488 try: 

2489 val_min = float(self.val_xmin.GetValue()) 

2490 val_max = float(self.val_xmax.GetValue()) 

2491 except: 

2492 self.ch_xaxis.SetSelection(0) 

2493 self.val_xmin.SetValue('%0.4f' % 0.2) 

2494 self.val_xmax.SetValue('%0.4f' % 6.0) 

2495 print('error in x-axis min/max input') 

2496 return 

2497 

2498 wavelength = self.returnLambda() 

2499 if self.ch_xaxis.GetSelection() != self.xaxis: 

2500 

2501 if self.ch_xaxis.GetSelection() == 2: ### select d 

2502 if self.xaxis == 1: ## was 2th 

2503 val_min = d_from_twth(val_min,wavelength) 

2504 val_max = d_from_twth(val_max,wavelength) 

2505 else: ## was q 

2506 val_min = d_from_q(val_min) 

2507 val_max = d_from_q(val_max) 

2508 elif self.ch_xaxis.GetSelection() == 1: ### select 2th 

2509 if self.xaxis == 2: ## was d 

2510 val_min = twth_from_d(val_min,wavelength) 

2511 val_max = twth_from_d(val_max,wavelength) 

2512 else: ## was q 

2513 val_min = twth_from_q(val_min,wavelength) 

2514 val_max = twth_from_q(val_max,wavelength) 

2515 else: ### select q 

2516 if self.xaxis == 2: ## was d 

2517 val_min = q_from_d(val_min) 

2518 val_max = q_from_d(val_max) 

2519 else: ## was 2th 

2520 val_min = q_from_twth(val_min,wavelength) 

2521 val_max = q_from_twth(val_max,wavelength) 

2522 self.xaxis = self.ch_xaxis.GetSelection() 

2523 

2524 self.val_xmin.SetValue('%0.4f' % min(val_min,val_max)) 

2525 self.val_xmax.SetValue('%0.4f' % max(val_min,val_max)) 

2526 

2527 

2528 def onEorLSel(self,event=None): 

2529 

2530 try: 

2531 current = float(self.val_cifE.GetValue()) 

2532 except: 

2533 return 

2534 

2535 if self.ch_EorL.GetSelection() == 1 and current > 5: 

2536 new = '%0.4f' % lambda_from_E(current) 

2537 elif self.ch_EorL.GetSelection() == 0 and current < 5: 

2538 new = '%0.4f' % E_from_lambda(current) 

2539 else: 

2540 return 

2541 

2542 self.val_cifE.SetValue(new) 

2543 

2544 

2545 def load_file(self,event=None): 

2546 wildcards = 'CIF file (*.cif)|*.cif|All files (*.*)|*.*' 

2547 dlg = wx.FileDialog(self, message='Choose CIF', 

2548 defaultDir=get_cwd(), 

2549 wildcard=wildcards, style=wx.FD_OPEN) 

2550 

2551 read = False 

2552 if dlg.ShowModal() == wx.ID_OK: 

2553 read = True 

2554 self.path = dlg.GetPath().replace('\\', '/') 

2555 dlg.Destroy() 

2556 

2557 if read: 

2558 self.type = 'file' 

2559 self.cif_list.Clear() 

2560 self.cif_list.Append(os.path.split(self.path)[-1]) 

2561 self.amcsd_id = None 

2562 

2563 self.cif_list.SetSelection(0) 

2564 

2565 def filter_database(self,event=None): 

2566 # print(" filter database A") 

2567 myDlg = XRDSearchGUI(self.cifdb, self.parent.owner.srch_cls) 

2568 

2569 filter = False 

2570 list_amcsd = None 

2571 

2572 if myDlg.ShowModal() == wx.ID_OK: 

2573 

2574 elem_include = myDlg.srch.elem_incl 

2575 elem_exclude = myDlg.srch.elem_excl 

2576 self.parent.owner.srch_cls = myDlg.srch 

2577 

2578 if len(myDlg.AMCSD.GetValue()) > 0: 

2579 myDlg.entrAMCSD() 

2580 list_amcsd = [] 

2581 

2582 for id in myDlg.srch.amcsd: 

2583 try: 

2584 list_amcsd += [int(id)] 

2585 except: 

2586 pass 

2587 

2588 

2589 mnrl_include = myDlg.Mineral.GetStringSelection() 

2590 # print( myDlg.Mineral.GetStringSelection()) 

2591 # print("Mineral name > ", mnrl_include, " < ") 

2592 # print("elem include > ", elem_include, " < ") 

2593 # print("elem exclude > ", elem_exclude, " < ") 

2594 

2595 if myDlg.Author.GetValue() == '': 

2596 auth_include = None 

2597 else: 

2598 auth_include = myDlg.Author.GetValue().split(',') 

2599 

2600 filter = True 

2601 myDlg.Destroy() 

2602 

2603 if filter: 

2604 if len(elem_include) > 0 or len(elem_exclude) > 0: 

2605 list_amcsd = self.cifdb.amcsd_by_chemistry(include=elem_include, 

2606 exclude=elem_exclude, 

2607 list=list_amcsd) 

2608 if mnrl_include is not None: 

2609 # print( " mineral name ", mnrl_include, ' >l ', list_amcsd) 

2610 list_amcsd = self.cifdb.amcsd_by_mineral(mnrl_include, 

2611 list=list_amcsd)[:1000] 

2612 

2613 # print(" --> ", len(list_amcsd)) 

2614 

2615 if auth_include is not None: 

2616 list_amcsd = self.cifdb.amcsd_by_author(include=auth_include, 

2617 list=list_amcsd) 

2618 self.returnMATCHES(list_amcsd) 

2619 

2620 def returnMATCHES(self, list_amcsd): 

2621 ''' 

2622 Populates Results Panel with list 

2623 ''' 

2624 self.cif_list.Clear() 

2625 

2626 if list_amcsd is not None and len(list_amcsd) > 0: 

2627 for amcsd in list_amcsd[:200]: 

2628 try: 

2629 elem,name,spgp,autr = self.cifdb.all_by_amcsd(amcsd) 

2630 entry = 'AMCSD %i : %s' % (amcsd,name) 

2631 self.cif_list.Append(entry) 

2632 except: 

2633 print('\t ** amcsd #%i not found in database.' % amcsd) 

2634 list_amcsd.remove(amcsd) 

2635 

2636 

2637 ## automatically selects first in list. 

2638 self.cif_list.EnsureVisible(0) 

2639 try: 

2640 self.cif_list.SetSelection(0) 

2641 except: 

2642 pass 

2643 

2644 amcsd_id = self.cif_list.GetString(self.cif_list.GetSelection()) 

2645 self.amcsd_id = int(amcsd_id.split()[1]) 

2646 self.type = 'database' 

2647 

2648 

2649 def showCIF(self, event=None, **kws): 

2650 

2651 if event is not None: 

2652 self.amcsd_id = int(event.GetString().split()[1]) 

2653 self.type = 'database' 

2654 self.path = None 

2655 

2656class RangeToolsPanel(wx.Panel): 

2657 ''' 

2658 Panel for housing range tools in fitting panel 

2659 ''' 

2660 label='Range' 

2661 def __init__(self,parent,owner=None,_larch=None): 

2662 

2663 wx.Panel.__init__(self, parent) 

2664 

2665 self.parent = parent 

2666 self.owner = owner 

2667 

2668 ## Default information 

2669 

2670 

2671 rangepanel = self.RangeTools() 

2672 

2673 panel1D = wx.BoxSizer(wx.HORIZONTAL) 

2674 panel1D.Add(rangepanel,flag=wx.ALL,border=10) 

2675 self.SetSizer(panel1D) 

2676 

2677 def RangeTools(self): 

2678 

2679 ########################### 

2680 ## Range tools 

2681 vbox_rng = wx.BoxSizer(wx.VERTICAL) 

2682 hbox_xaxis = wx.BoxSizer(wx.HORIZONTAL) 

2683 hbox_xmin = wx.BoxSizer(wx.HORIZONTAL) 

2684 hbox_xmax = wx.BoxSizer(wx.HORIZONTAL) 

2685 hbox_xset = wx.BoxSizer(wx.HORIZONTAL) 

2686 

2687 ########################### 

2688 ## X-Scale 

2689 

2690 ttl_xaxis = wx.StaticText(self, label='X-SCALE') 

2691 xunits = [u'q (\u212B\u207B\u00B9)',u'2\u03B8 (\u00B0)',u'd (\u212B)'] 

2692 self.ch_xaxis = wx.Choice(self,choices=xunits) 

2693 self.ch_xaxis.Bind(wx.EVT_CHOICE, self.owner.onChangeXscale) 

2694 hbox_xaxis.Add(ttl_xaxis, flag=wx.RIGHT, border=8) 

2695 hbox_xaxis.Add(self.ch_xaxis, flag=wx.EXPAND, border=8) 

2696 

2697 ########################### 

2698 ## X-Range 

2699 ttl_xmin = wx.StaticText(self, label='minimum') 

2700 self.val_xmin = wx.TextCtrl(self,style=wx.TE_PROCESS_ENTER) 

2701 self.unit_xmin = wx.StaticText(self, label=self.owner.xunit) 

2702 self.val_xmin.Bind(wx.EVT_TEXT_ENTER, self.owner.onSetRange) 

2703 hbox_xmin.Add(ttl_xmin, flag=wx.RIGHT, border=8) 

2704 hbox_xmin.Add(self.val_xmin, flag=wx.RIGHT, border=8) 

2705 hbox_xmin.Add(self.unit_xmin, flag=wx.RIGHT, border=8) 

2706 

2707 ttl_xmax= wx.StaticText(self, label='maximum') 

2708 self.val_xmax = wx.TextCtrl(self,style=wx.TE_PROCESS_ENTER) 

2709 self.unit_xmax = wx.StaticText(self, label=self.owner.xunit) 

2710 self.val_xmax.Bind(wx.EVT_TEXT_ENTER, self.owner.onSetRange) 

2711 hbox_xmax.Add(ttl_xmax, flag=wx.RIGHT, border=8) 

2712 hbox_xmax.Add(self.val_xmax, flag=wx.RIGHT, border=8) 

2713 hbox_xmax.Add(self.unit_xmax, flag=wx.RIGHT, border=8) 

2714 

2715 self.btn_rngreset = wx.Button(self,label='reset') 

2716 self.btn_rngreset.Bind(wx.EVT_BUTTON, self.owner.onReset) 

2717 

2718 hbox_xset.Add(self.btn_rngreset, flag=wx.RIGHT, border=8) 

2719 

2720 vbox_rng.Add(hbox_xaxis, flag=wx.ALL, border=10) 

2721 vbox_rng.Add(hbox_xmin, flag=wx.BOTTOM, border=8) 

2722 vbox_rng.Add(hbox_xmax, flag=wx.BOTTOM, border=8) 

2723 vbox_rng.Add(hbox_xset, flag=wx.BOTTOM|wx.ALIGN_RIGHT, border=8) 

2724 

2725 ## until data is loaded: 

2726 self.ch_xaxis.Disable() 

2727 self.val_xmin.Disable() 

2728 self.val_xmax.Disable() 

2729 self.btn_rngreset.Disable() 

2730 

2731 return vbox_rng 

2732 

2733 

2734class BackgroundToolsPanel(wx.Panel): 

2735 ''' 

2736 Panel for housing background tools in fitting panel 

2737 ''' 

2738 label='Background' 

2739 def __init__(self,parent,owner=None,_larch=None): 

2740 

2741 wx.Panel.__init__(self, parent) 

2742 

2743 self.parent = parent 

2744 self.owner = owner 

2745 

2746 ## Default information 

2747 

2748 

2749 

2750 bkgdpanel = self.BackgroundTools() 

2751 

2752 panel1D = wx.BoxSizer(wx.HORIZONTAL) 

2753 panel1D.Add(bkgdpanel,flag=wx.ALL,border=10) 

2754 self.SetSizer(panel1D) 

2755 

2756 def BackgroundTools(self): 

2757 

2758 ########################### 

2759 ## Background tools 

2760 vbox_bkgd = wx.BoxSizer(wx.VERTICAL) 

2761 hbox_bkgd = wx.BoxSizer(wx.HORIZONTAL) 

2762 

2763 self.btn_fbkgd = wx.Button(self,label='Fit') 

2764 self.btn_fbkgd.Bind(wx.EVT_BUTTON, self.owner.onFitBkgd) 

2765 hbox_bkgd.Add(self.btn_fbkgd, flag=wx.RIGHT, border=8) 

2766 

2767 self.btn_obkgd = wx.Button(self,label='Options') 

2768 self.btn_obkgd.Bind(wx.EVT_BUTTON, self.owner.background_options) 

2769 hbox_bkgd.Add(self.btn_obkgd, flag=wx.RIGHT, border=8) 

2770 

2771 self.btn_rbkgd = wx.Button(self,label='Remove') 

2772 self.btn_rbkgd.Bind(wx.EVT_BUTTON, self.owner.onRmvBkgd) 

2773 

2774 vbox_bkgd.Add(hbox_bkgd, flag=wx.BOTTOM, border=8) 

2775 vbox_bkgd.Add(self.btn_rbkgd, flag=wx.BOTTOM, border=8) 

2776 

2777 self.ck_bkgd = wx.CheckBox(self,label='Subtract') 

2778 self.ck_bkgd.Bind(wx.EVT_CHECKBOX, self.owner.onSbtrctBkgd) 

2779 vbox_bkgd.Add(self.ck_bkgd, flag=wx.BOTTOM, border=8) 

2780 

2781 ## until data is loaded: 

2782 self.btn_fbkgd.Disable() 

2783 self.btn_obkgd.Disable() 

2784 self.btn_rbkgd.Disable() 

2785 self.ck_bkgd.Disable() 

2786 

2787 return vbox_bkgd 

2788 

2789 

2790class PeakToolsPanel(wx.Panel): 

2791 ''' 

2792 Panel for housing background tools in fitting panel 

2793 ''' 

2794 label='Peaks' 

2795 def __init__(self,parent,owner=None,_larch=None): 

2796 

2797 wx.Panel.__init__(self, parent) 

2798 

2799 self.parent = parent 

2800 self.owner = owner 

2801 

2802 ## Default information 

2803 

2804 

2805 pkspanel = self.PeakTools() 

2806 

2807 panel1D = wx.BoxSizer(wx.HORIZONTAL) 

2808 panel1D.Add(pkspanel,flag=wx.ALL,border=10) 

2809 self.SetSizer(panel1D) 

2810 

2811 def PeakTools(self): 

2812 

2813 ########################### 

2814 ## Peak tools 

2815 vbox_pks = wx.BoxSizer(wx.VERTICAL) 

2816 hbox0_pks = wx.BoxSizer(wx.HORIZONTAL) 

2817 hbox1_pks = wx.BoxSizer(wx.HORIZONTAL) 

2818 hbox2_pks = wx.BoxSizer(wx.HORIZONTAL) 

2819 hbox3_pks = wx.BoxSizer(wx.HORIZONTAL) 

2820 hbox4_pks = wx.BoxSizer(wx.HORIZONTAL) 

2821 

2822 ## Fit type 

2823 ttl_fit = wx.StaticText(self, label='Fit type') 

2824 self.ch_pkfit = wx.Choice(self,choices=SRCH_MTHDS) 

2825 

2826 hbox0_pks.Add(ttl_fit, flag=wx.RIGHT, border=5) 

2827 hbox0_pks.Add(self.ch_pkfit, flag=wx.RIGHT, border=5) 

2828 

2829 self.btn_fdpks = wx.Button(self,label='Find peaks') 

2830 self.btn_fdpks.Bind(wx.EVT_BUTTON, partial(self.owner.onPeaks, filter=True)) 

2831 hbox2_pks.Add(self.btn_fdpks, flag=wx.RIGHT, border=8) 

2832 

2833 self.btn_opks = wx.Button(self,label='Search options') 

2834 self.btn_opks.Bind(wx.EVT_BUTTON, self.owner.peak_options) 

2835 hbox2_pks.Add(self.btn_opks, flag=wx.RIGHT, border=8) 

2836 

2837 intthrsizer = wx.BoxSizer(wx.VERTICAL) 

2838 

2839 ttl_intthr = wx.StaticText(self, label='Intensity threshold') 

2840 self.val_intthr = wx.TextCtrl(self, style=wx.TE_PROCESS_ENTER) 

2841 self.val_intthr.Bind(wx.EVT_TEXT_ENTER, partial(self.owner.find_peaks, filter=True)) 

2842 hbox1_pks.Add(ttl_intthr, flag=wx.RIGHT, border=8) 

2843 hbox1_pks.Add(self.val_intthr, flag=wx.RIGHT, border=8) 

2844 

2845 self.owner.peaklistbox = EditableListBox(self, self.owner.select_peak, 

2846 remove_action=self.owner.rm_sel_peaks, 

2847 size=(250, -1)) 

2848 

2849 vbox = wx.BoxSizer(wx.VERTICAL) 

2850 self.ttl_cntpks = wx.StaticText(self, label=('Total: 0 peaks')) 

2851 hbox3_pks.Add(self.ttl_cntpks, flag=wx.EXPAND|wx.ALL, border=8) 

2852 

2853 self.btn_addpks = wx.Button(self,label='Add last click') 

2854 self.btn_addpks.Bind(wx.EVT_BUTTON, self.owner.onAddPks) 

2855 hbox4_pks.Add(self.btn_addpks, flag=wx.RIGHT, border=8) 

2856 

2857 self.btn_rmvpks = wx.Button(self,label='Remove all') 

2858 self.btn_rmvpks.Bind(wx.EVT_BUTTON, self.owner.onRmvPksAll) 

2859 hbox4_pks.Add(self.btn_rmvpks, flag=wx.RIGHT, border=8) 

2860 

2861 vbox_pks.Add(hbox0_pks, flag=wx.BOTTOM, border=8) 

2862 vbox_pks.Add(hbox1_pks, flag=wx.BOTTOM, border=8) 

2863 vbox_pks.Add(hbox2_pks, flag=wx.BOTTOM, border=8) 

2864 vbox_pks.Add(self.owner.peaklistbox, flag=wx.BOTTOM, border=8) 

2865 vbox_pks.Add(hbox3_pks, flag=wx.BOTTOM, border=8) 

2866 vbox_pks.Add(hbox4_pks, flag=wx.BOTTOM, border=8) 

2867 

2868 self.val_intthr.SetValue(str(self.owner.intthrsh)) 

2869 self.ch_pkfit.SetSelection(0) 

2870 

2871 ## until data is loaded: 

2872 self.btn_fdpks.Disable() 

2873# self.btn_opks.Disable() 

2874 self.val_intthr.Disable() 

2875 self.btn_rmvpks.Disable() 

2876 self.btn_addpks.Disable() 

2877 

2878 return vbox_pks 

2879 

2880class SearchPanel(wx.Panel): 

2881 ''' 

2882 Panel for housing range tools in fitting panel 

2883 ''' 

2884 label='Search' 

2885 def __init__(self,parent,owner=None,_larch=None): 

2886 

2887 wx.Panel.__init__(self, parent) 

2888 

2889 self.parent = parent 

2890 self.owner = owner 

2891 

2892 matchpanel = self.SearchMatchTools() 

2893# refpanel = self.RefinementTools() 

2894 respanel = self.ResultsTools() 

2895 

2896 panel1D = wx.BoxSizer(wx.VERTICAL) 

2897 panel1D.Add(matchpanel,flag=wx.ALL,border=10) 

2898 panel1D.Add(respanel,flag=wx.ALL,border=10) 

2899 self.SetSizer(panel1D) 

2900 

2901 def SearchMatchTools(self): 

2902 hbox = wx.BoxSizer(wx.HORIZONTAL) 

2903 

2904 self.btn_mtch = wx.Button(self,label='Search by peaks') 

2905 btn_srch = wx.Button(self,label='Filter database') 

2906 

2907 self.btn_mtch.Bind(wx.EVT_BUTTON, self.owner.onMatch) 

2908 btn_srch.Bind(wx.EVT_BUTTON, self.owner.filter_database) 

2909 

2910 hbox.Add(self.btn_mtch, flag=wx.BOTTOM|wx.RIGHT, border=8) 

2911 hbox.Add(btn_srch, flag=wx.BOTTOM, border=8) 

2912 

2913 ## until peaks are available to search 

2914 self.btn_mtch.Disable() 

2915 

2916 return hbox 

2917 

2918 def ResultsTools(self): 

2919 

2920 vbox = wx.BoxSizer(wx.VERTICAL) 

2921 hbox = wx.BoxSizer(wx.HORIZONTAL) 

2922 

2923 self.amcsdlistbox = EditableListBox(self, self.owner.displayCIFpeaks, size=(200,120)) 

2924 

2925 self.txt_geometry = [ wx.StaticText(self, label=''), 

2926 wx.StaticText(self, label=''), 

2927 wx.StaticText(self, label=''), 

2928 wx.StaticText(self, label='')] 

2929 

2930 self.btn_shw = wx.Button(self,label='View CIF text') 

2931 self.btn_shw.Bind(wx.EVT_BUTTON, self.displayCIF) 

2932 

2933 self.btn_clr = wx.Button(self,label='Clear list') 

2934 self.btn_clr.Bind(wx.EVT_BUTTON, self.owner.clearMATCHES) 

2935 

2936 hbox.Add(self.btn_shw, flag=wx.BOTTOM|wx.RIGHT, border=8) 

2937 hbox.Add(self.btn_clr, flag=wx.BOTTOM, border=8) 

2938 

2939 vbox.Add(self.amcsdlistbox, flag=wx.BOTTOM, border=6) 

2940 vbox.Add(self.txt_geometry[0], flag=wx.TOP, border=2) 

2941 vbox.Add(self.txt_geometry[1], flag=wx.TOP|wx.BOTTOM, border=2) 

2942 vbox.Add(self.txt_geometry[2], flag=wx.TOP|wx.BOTTOM, border=2) 

2943 vbox.Add(self.txt_geometry[3], flag=wx.BOTTOM, border=1) 

2944 vbox.Add(hbox, flag=wx.RIGHT|wx.TOP, border=8) 

2945 

2946 

2947 self.btn_clr.Disable() 

2948 self.btn_shw.Disable() 

2949 

2950 return vbox 

2951 

2952 def displayCIF(self,event=None): 

2953 

2954 title = self.amcsdlistbox.GetStringSelection() 

2955 amcsd = self.amcsdlistbox.GetStringSelection().split()[0] 

2956 

2957 self.owner.cifframe += [CIFFrame(amcsd=int(amcsd), title=title, 

2958 cifdb=self.owner.owner.cifdb)] 

2959 

2960 

2961class CIFPanel(wx.Panel): 

2962 

2963 def __init__(self, parent,cifdb=None,amcsd=100): 

2964 wx.Panel.__init__(self, parent) 

2965 

2966 cif_text_box = wx.TextCtrl(self, style=wx.TE_MULTILINE|wx.HSCROLL) 

2967 

2968 sizer = wx.BoxSizer(wx.VERTICAL) 

2969 sizer.Add(cif_text_box, 1, wx.ALL|wx.EXPAND) 

2970 

2971 self.SetSizer(sizer) 

2972 

2973 if cifdb is None: 

2974 cifdb = cifDB(dbname='%s/.larch/cif_amcsd.db' % expanduser('~')) 

2975 

2976 cif_text_box.SetValue(cifdb.cif_by_amcsd(amcsd)) 

2977 

2978 

2979class CIFFrame(wx.Frame): 

2980 

2981 def __init__(self, amcsd=None, title='', cifdb=None): 

2982 title = 'CIF Display - %s' % title 

2983 wx.Frame.__init__(self, None, size=(650,900), title=title) 

2984 

2985 panel = CIFPanel(self, cifdb=cifdb, amcsd=amcsd) 

2986 

2987 self.Show() 

2988 

2989 def closeFrame(self, event=None): 

2990 

2991 try: 

2992 self.Destroy() 

2993 except: 

2994 pass 

2995 

2996 

2997 

2998class InstrPanel(wx.Panel): 

2999 ''' 

3000 Panel for housing background tools in fitting panel 

3001 ''' 

3002 label='Width' 

3003 def __init__(self,parent,owner=None,_larch=None): 

3004 

3005 wx.Panel.__init__(self, parent) 

3006 

3007 self.parent = parent 

3008 self.owner = owner 

3009 

3010 instrpanel = self.InstrumentTools() 

3011 

3012 panel1D = wx.BoxSizer(wx.HORIZONTAL) 

3013 panel1D.Add(instrpanel,flag=wx.ALL,border=10) 

3014 self.SetSizer(panel1D) 

3015 

3016 def InstrumentTools(self): 

3017 

3018 vbox = wx.BoxSizer(wx.VERTICAL) 

3019 

3020 hbox_inst = wx.BoxSizer(wx.HORIZONTAL) 

3021 hbox_u = wx.BoxSizer(wx.HORIZONTAL) 

3022 hbox_v = wx.BoxSizer(wx.HORIZONTAL) 

3023 hbox_w = wx.BoxSizer(wx.HORIZONTAL) 

3024 hbox_size = wx.BoxSizer(wx.HORIZONTAL) 

3025 hbox_D = wx.BoxSizer(wx.HORIZONTAL) 

3026 hbox_hw = wx.BoxSizer(wx.HORIZONTAL) 

3027 

3028 ttl_inst = wx.StaticText(self, label='Instrumental') 

3029 ttl_u = wx.StaticText(self, label='u') 

3030 ttl_v = wx.StaticText(self, label='v') 

3031 ttl_w = wx.StaticText(self, label='w') 

3032 ttl_size = wx.StaticText(self, label='Size broadening') 

3033 ttl_D = wx.StaticText(self, label='D (A)') 

3034 ttl_hw = wx.StaticText(self, label='Half width') 

3035 

3036 self.val_u = wx.TextCtrl(self,style=wx.TE_PROCESS_ENTER) 

3037 self.val_v = wx.TextCtrl(self,style=wx.TE_PROCESS_ENTER) 

3038 self.val_w = wx.TextCtrl(self,style=wx.TE_PROCESS_ENTER) 

3039 self.val_D = wx.TextCtrl(self,style=wx.TE_PROCESS_ENTER) 

3040 self.val_hw = wx.TextCtrl(self,style=wx.TE_PROCESS_ENTER) 

3041 

3042 self.btn_clrinst = wx.Button(self,label='Clear') 

3043 self.btn_clrsize = wx.Button(self,label='Clear') 

3044 

3045 self.val_u.Bind(wx.EVT_TEXT_ENTER, self.owner.onGetInstr) 

3046 self.val_v.Bind(wx.EVT_TEXT_ENTER, self.owner.onGetInstr) 

3047 self.val_w.Bind(wx.EVT_TEXT_ENTER, self.owner.onGetInstr) 

3048 self.val_D.Bind(wx.EVT_TEXT_ENTER, self.owner.onGetSize) 

3049 

3050 self.btn_clrinst.Bind(wx.EVT_BUTTON, self.owner.onClrInstr) 

3051 self.btn_clrsize.Bind(wx.EVT_BUTTON, self.owner.onClrSize) 

3052 

3053 hbox_inst.Add(ttl_inst, flag=wx.RIGHT, border=8) 

3054 hbox_inst.AddSpacer(33) 

3055 hbox_inst.Add(self.btn_clrinst, flag=wx.RIGHT, border=8) 

3056 

3057 

3058 hbox_u.Add(ttl_u, flag=wx.RIGHT, border=8) 

3059 hbox_u.Add(self.val_u, flag=wx.RIGHT, border=8) 

3060 

3061 hbox_v.Add(ttl_v, flag=wx.RIGHT, border=8) 

3062 hbox_v.Add(self.val_v, flag=wx.RIGHT, border=8) 

3063 

3064 hbox_w.Add(ttl_w, flag=wx.RIGHT, border=8) 

3065 hbox_w.Add(self.val_w, flag=wx.RIGHT, border=8) 

3066 

3067 hbox_size.Add(ttl_size, flag=wx.RIGHT, border=8) 

3068 hbox_size.AddSpacer(25) 

3069 hbox_size.Add(self.btn_clrsize, flag=wx.RIGHT, border=8) 

3070 

3071 

3072 hbox_D.Add(ttl_D, flag=wx.RIGHT, border=8) 

3073 hbox_D.Add(self.val_D, flag=wx.RIGHT, border=8) 

3074 

3075 hbox_hw.Add(ttl_hw, flag=wx.RIGHT, border=5) 

3076 hbox_hw.Add(self.val_hw, flag=wx.RIGHT, border=5) 

3077 

3078 vbox.Add(hbox_inst, flag=wx.BOTTOM, border=8) 

3079 vbox.Add(hbox_u, flag=wx.BOTTOM, border=8) 

3080 vbox.Add(hbox_v, flag=wx.BOTTOM, border=8) 

3081 vbox.Add(hbox_w, flag=wx.BOTTOM, border=8) 

3082 vbox.AddSpacer(15) 

3083 vbox.Add(hbox_hw, flag=wx.BOTTOM, border=8) 

3084 vbox.AddSpacer(15) 

3085 vbox.Add(hbox_size, flag=wx.BOTTOM, border=8) 

3086 vbox.Add(hbox_D, flag=wx.BOTTOM, border=8) 

3087 

3088 self.val_u.SetValue('1.0') 

3089 self.val_v.SetValue('1.0') 

3090 self.val_w.SetValue('1.0') 

3091 self.val_D.SetValue('') 

3092 self.val_hw.SetValue(str(self.owner.halfwidth)) 

3093 

3094 self.val_u.Disable() 

3095 self.val_v.Disable() 

3096 self.val_w.Disable() 

3097 self.val_D.Disable() 

3098 

3099 self.btn_clrinst.Disable() 

3100 self.btn_clrsize.Disable() 

3101 

3102 

3103 return vbox 

3104 

3105class ResultsPanel(wx.Panel): 

3106 ''' 

3107 Panel for .... 

3108 ''' 

3109 label='Results' 

3110 def __init__(self,parent,owner=None,_larch=None): 

3111 

3112 wx.Panel.__init__(self, parent) 

3113 

3114 self.parent = parent 

3115 self.owner = owner 

3116 

3117 ## Default information 

3118# respanel = self.ResultsTools() 

3119 

3120 panel1D = wx.BoxSizer(wx.HORIZONTAL) 

3121# panel1D.Add(respanel,flag=wx.ALL,border=10) 

3122 self.SetSizer(panel1D) 

3123 

3124# def ResultsTools(self): 

3125# 

3126# vbox = wx.BoxSizer(wx.VERTICAL) 

3127# 

3128# return vbox 

3129 

3130##### Pop-up from 2D XRD Viewer to calculate 1D pattern 

3131class Calc1DPopup(wx.Dialog): 

3132 

3133 def __init__(self,parent,xrd2Ddata): 

3134 """Constructor""" 

3135 dialog = wx.Dialog.__init__(self, parent, title='Calculate 1DXRD options', 

3136 style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER, 

3137 size = (210,460)) 

3138 self.parent = parent 

3139 self.data2D = xrd2Ddata 

3140 

3141 self.createPanel() 

3142 

3143 ## Set defaults 

3144 self.setDefaults() 

3145 

3146 ix,iy = self.panel.GetBestSize() 

3147 self.SetSize((ix+50, iy+50)) 

3148 

3149 

3150 def createPanel(self): 

3151 

3152 self.panel = wx.Panel(self) 

3153 

3154 mainsizer = wx.BoxSizer(wx.VERTICAL) 

3155 

3156 ## Azimutal wedges 

3157 wedgesizer = wx.BoxSizer(wx.VERTICAL) 

3158 ttl_wedges = wx.StaticText(self.panel, label='AZIMUTHAL WEDGES') 

3159 wsizer = wx.BoxSizer(wx.HORIZONTAL) 

3160 self.wedges = wx.SpinCtrl(self.panel, style=wx.SP_VERTICAL|wx.SP_ARROW_KEYS|wx.SP_WRAP) 

3161 wsizer.Add(self.wedges,flag=wx.RIGHT,border=8) 

3162 

3163 wedgesizer.Add(ttl_wedges,flag=wx.BOTTOM,border=8) 

3164 wedgesizer.Add(wsizer,flag=wx.BOTTOM,border=8) 

3165 

3166 ## X-Range 

3167 xsizer = wx.BoxSizer(wx.VERTICAL) 

3168 ttl_xrange = wx.StaticText(self.panel, label='X-RANGE') 

3169 xstepsizer = wx.BoxSizer(wx.HORIZONTAL) 

3170 ttl_xstep = wx.StaticText(self.panel, label='steps') 

3171 self.xstep = wx.TextCtrl(self.panel,wx.TE_PROCESS_ENTER) 

3172 xstepsizer.Add(ttl_xstep, flag=wx.RIGHT, border=5) 

3173 xstepsizer.Add(self.xstep, flag=wx.RIGHT, border=5) 

3174 xsizer.Add(ttl_xrange, flag=wx.BOTTOM, border=5) 

3175 xsizer.Add(xstepsizer, flag=wx.TOP|wx.BOTTOM, border=5) 

3176 

3177 ## Plot/save 

3178 

3179 self.ch_save = wx.CheckBox(self.panel, label = 'Save 1D?') 

3180 self.ch_plot = wx.CheckBox(self.panel, label = 'Plot 1D?') 

3181 

3182 self.save_choice = wx.Choice(self.panel, choices=[u'q (\u212B\u207B\u00B9)',u'2\u03B8 (\u00B0)']) 

3183 

3184 self.ch_save.Bind(wx.EVT_CHECKBOX, self.onCHECK) 

3185 self.ch_plot.Bind(wx.EVT_CHECKBOX, self.onCHECK) 

3186 

3187 savesizer = wx.BoxSizer(wx.HORIZONTAL) 

3188 savesizer.Add(self.ch_save, flag=wx.RIGHT, border=5) 

3189 savesizer.Add(self.save_choice, flag=wx.RIGHT, border=5) 

3190 

3191 minisizer = wx.BoxSizer(wx.VERTICAL) 

3192 minisizer.Add(savesizer, flag=wx.RIGHT, border=5) 

3193 minisizer.Add(self.ch_plot, flag=wx.RIGHT, border=5) 

3194 

3195 ##### 

3196 ## OKAY! 

3197 oksizer = wx.BoxSizer(wx.HORIZONTAL) 

3198 self.okBtn = wx.Button(self.panel, wx.ID_OK ) 

3199 canBtn = wx.Button(self.panel, wx.ID_CANCEL ) 

3200 

3201 oksizer.Add(canBtn, flag=wx.RIGHT, border=8) 

3202 oksizer.Add(self.okBtn, flag=wx.RIGHT, border=8) 

3203 

3204 mainsizer.Add(wedgesizer, flag=wx.ALL, border=8) 

3205 mainsizer.AddSpacer(15) 

3206 mainsizer.Add(xsizer, flag=wx.ALL, border=5) 

3207 mainsizer.AddSpacer(15) 

3208 mainsizer.Add(minisizer, flag=wx.ALL, border=8) 

3209 mainsizer.AddSpacer(15) 

3210 mainsizer.Add(oksizer, flag=wx.ALL|wx.ALIGN_RIGHT, border=10) 

3211 

3212 self.panel.SetSizer(mainsizer) 

3213 

3214 

3215 def onCHECK(self,event=None): 

3216 if self.ch_save.GetValue() or self.ch_plot.GetValue(): 

3217 self.okBtn.Enable() 

3218 else: 

3219 self.okBtn.Disable() 

3220 

3221 def setDefaults(self): 

3222 

3223 self.xstep.SetValue(str(5001)) 

3224 self.wedges.SetValue(1) 

3225 self.wedges.SetRange(1,36) 

3226 self.save_choice.SetSelection(1) 

3227 

3228 self.okBtn.Disable() 

3229 

3230 def onSPIN(self,event=None): 

3231 self.wedges.SetValue(str(event.GetPosition())) 

3232 

3233class DatabaseInfoGUI(wx.Dialog): 

3234 ''' 

3235 Displays number of entries in current database; allows for loading new database files 

3236 mkak 2017.03.23 

3237 ''' 

3238 

3239 #---------------------------------------------------------------------- 

3240 def __init__(self, parent): 

3241 

3242 wx.Dialog.__init__(self, parent, title='Database Information') 

3243 ## remember: size=(width,height) 

3244 self.parent = parent 

3245 self.panel = wx.Panel(self) 

3246 

3247 sizer = wx.BoxSizer(wx.VERTICAL) 

3248 

3249 ## Database info 

3250 self.txt_dbname = wx.StaticText(self.panel, label='Current file : ') 

3251 self.txt_nocif = wx.StaticText(self.panel, label='Number of cif entries : ') 

3252 

3253 ## Database buttons 

3254 db_sizer = wx.BoxSizer(wx.HORIZONTAL) 

3255 

3256 dbBtn = wx.Button(self.panel, label='Load new database' ) 

3257 rstBtn = wx.Button(self.panel, label='Reset to default database') 

3258 

3259 dbBtn.Bind(wx.EVT_BUTTON, self.onNewFile ) 

3260 rstBtn.Bind(wx.EVT_BUTTON, self.onResetFile ) 

3261 

3262 db_sizer.Add(dbBtn, flag=wx.RIGHT, border=10) 

3263 db_sizer.Add(rstBtn, flag=wx.RIGHT, border=10) 

3264 

3265 ## Okay, etc. buttons 

3266 ok_sizer = wx.BoxSizer(wx.HORIZONTAL) 

3267 

3268 hlpBtn = wx.Button(self.panel, wx.ID_HELP ) 

3269 okBtn = wx.Button(self.panel, wx.ID_OK, label='Close') 

3270 #canBtn = wx.Button(self.panel, wx.ID_CANCEL ) 

3271 

3272 ok_sizer.Add(hlpBtn, flag=wx.ALL, border=8) 

3273 #ok_sizer.Add(canBtn, flag=wx.ALL, border=8) 

3274 ok_sizer.Add(okBtn, flag=wx.ALL, border=8) 

3275 

3276 sizer.Add(self.txt_dbname, flag=wx.ALL, border=10) 

3277 sizer.Add(self.txt_nocif, flag=wx.ALL, border=10) 

3278 sizer.Add(db_sizer, flag=wx.ALL, border=10) 

3279 sizer.AddSpacer(5) 

3280 sizer.Add(ok_sizer, flag=wx.ALIGN_RIGHT|wx.ALL, border=10) 

3281 self.panel.SetSizer(sizer) 

3282 

3283 self.onUpdateText() 

3284 

3285 def onNewFile(self,event=None): 

3286 

3287 path = self.parent.open_database() 

3288 self.onUpdateText() 

3289 

3290 def onResetFile(self,event=None): 

3291 

3292 self.parent.owner.openDB() 

3293 self.onUpdateText() 

3294 

3295 def onUpdateText(self,event=None): 

3296 

3297 try: 

3298 filename = self.parent.owner.cifdb.dbname 

3299 except: 

3300 return 

3301 nocif = self.parent.owner.cifdb.cifcount() 

3302 

3303 self.txt_dbname.SetLabel('Current file : %s' % filename) 

3304 try: 

3305 self.txt_nocif.SetLabel('Number of cif entries : %s' % '{:,}'.format(nocif)) 

3306 except: 

3307 self.txt_nocif.SetLabel('Number of cif entries : %i' % nocif) 

3308 

3309 ix,iy = self.panel.GetBestSize() 

3310 self.SetSize((ix+40, iy+40)) 

3311 self.Show() 

3312 

3313######################################################################### 

3314class XRDSearchGUI(wx.Dialog): 

3315 

3316 def __init__(self, database, srch_cls): 

3317 

3318 wx.Dialog.__init__(self, None, title='Crystal Structure Database Search') 

3319 ## remember: size=(width,height) 

3320 self.cifdb = database 

3321 

3322 self.panel = wx.Panel(self) 

3323 

3324 sizer = wx.BoxSizer(wx.VERTICAL) 

3325 grd_sizer = wx.GridBagSizer( 5, 6) 

3326 ok_sizer = wx.BoxSizer(wx.HORIZONTAL) 

3327 

3328 ## Mineral search 

3329 lbl_Mineral = wx.StaticText(self.panel, label='Mineral name:' ) 

3330 self.minerals = self.cifdb.get_mineral_names() 

3331 self.Mineral = wx.ComboBox(self.panel, choices=self.minerals, size=(270, -1)) 

3332 

3333 ## AMCSD search 

3334 lbl_AMCSD = wx.StaticText(self.panel, label='AMCSD search:' ) 

3335 self.AMCSD = wx.TextCtrl(self.panel, size=(270, -1), style=wx.TE_PROCESS_ENTER) 

3336 

3337 ## Author search 

3338 lbl_Author = wx.StaticText(self.panel, label='Author(s):' ) 

3339 self.Author = wx.TextCtrl(self.panel, size=(175, -1), style=wx.TE_PROCESS_ENTER) 

3340 self.atrslct = wx.Button(self.panel, label='Select...') 

3341 

3342 ## Chemistry search 

3343 lbl_Chemistry = wx.StaticText(self.panel, label='Chemistry:' ) 

3344 self.Chemistry = wx.TextCtrl(self.panel, size=(175, -1), style=wx.TE_PROCESS_ENTER) 

3345 self.chmslct = wx.Button(self.panel, label='Specify...') 

3346 

3347 ## Cell parameter symmetry search 

3348 lbl_Symmetry = wx.StaticText(self.panel, label='Symmetry/unit cell:' ) 

3349 self.Symmetry = wx.TextCtrl(self.panel, size=(175, -1), style=wx.TE_PROCESS_ENTER) 

3350 self.symslct = wx.Button(self.panel, label='Specify...') 

3351 

3352 ## Category search 

3353 opts = wx.LB_EXTENDED|wx.LB_HSCROLL|wx.LB_NEEDED_SB|wx.LB_SORT 

3354 lbl_Category = wx.StaticText(self.panel, label='Category:', style=wx.TE_PROCESS_ENTER) 

3355 self.Category = wx.ListBox(self.panel, style=opts, choices=CATEGORIES, size=(270, -1)) 

3356 

3357 ## General search 

3358 lbl_Keyword = wx.StaticText(self.panel, label='Keyword search:' ) 

3359 self.Keyword = wx.TextCtrl(self.panel, size=(270, -1), style=wx.TE_PROCESS_ENTER) 

3360 

3361 ## Define buttons 

3362 self.rstBtn = wx.Button(self.panel, label='Reset' ) 

3363 hlpBtn = wx.Button(self.panel, wx.ID_HELP ) 

3364 okBtn = wx.Button(self.panel, wx.ID_OK ) 

3365 canBtn = wx.Button(self.panel, wx.ID_CANCEL ) 

3366 

3367 ## Bind buttons for functionality 

3368 self.rstBtn.Bind(wx.EVT_BUTTON, self.onReset ) 

3369 

3370 self.chmslct.Bind(wx.EVT_BUTTON, self.onChemistry ) 

3371 self.atrslct.Bind(wx.EVT_BUTTON, self.onAuthor ) 

3372 self.symslct.Bind(wx.EVT_BUTTON, self.onSymmetry ) 

3373 

3374 self.Chemistry.Bind(wx.EVT_TEXT_ENTER, self.entrChemistry ) 

3375 self.AMCSD.Bind(wx.EVT_TEXT_ENTER, self.entrAMCSD ) 

3376 self.Mineral.Bind(wx.EVT_TEXT_ENTER, self.entrMineral ) 

3377 self.Author.Bind(wx.EVT_TEXT_ENTER, self.entrAuthor ) 

3378 self.Symmetry.Bind(wx.EVT_TEXT_ENTER, self.entrSymmetry ) 

3379 self.Category.Bind(wx.EVT_TEXT_ENTER, self.entrCategory ) 

3380 self.Keyword.Bind(wx.EVT_TEXT_ENTER, self.entrKeyword ) 

3381 

3382 grd_sizer.Add(lbl_Mineral, pos = ( 1,1) ) 

3383 grd_sizer.Add(self.Mineral, pos = ( 1,2), span = (1,3) ) 

3384 

3385 grd_sizer.Add(lbl_AMCSD, pos = ( 2,1) ) 

3386 grd_sizer.Add(self.AMCSD, pos = ( 2,2), span = (1,3) ) 

3387 

3388 grd_sizer.Add(lbl_Author, pos = ( 3,1) ) 

3389 grd_sizer.Add(self.Author, pos = ( 3,2), span = (1,2) ) 

3390 grd_sizer.Add(self.atrslct, pos = ( 3,4) ) 

3391 

3392 grd_sizer.Add(lbl_Chemistry, pos = ( 4,1) ) 

3393 grd_sizer.Add(self.Chemistry, pos = ( 4,2), span = (1,2) ) 

3394 grd_sizer.Add(self.chmslct, pos = ( 4,4) ) 

3395 

3396 grd_sizer.Add(lbl_Symmetry, pos = ( 5,1) ) 

3397 grd_sizer.Add(self.Symmetry, pos = ( 5,2), span = (1,2) ) 

3398 grd_sizer.Add(self.symslct, pos = ( 5,4) ) 

3399 

3400 grd_sizer.Add(lbl_Category, pos = ( 6,1) ) 

3401 grd_sizer.Add(self.Category, pos = ( 6,2), span = (1,3) ) 

3402 

3403 grd_sizer.Add(lbl_Keyword, pos = ( 7,1) ) 

3404 grd_sizer.Add(self.Keyword, pos = ( 7,2), span = (1,3) ) 

3405 

3406 ok_sizer.Add(hlpBtn, flag=wx.ALL, border=8) 

3407 ok_sizer.Add(canBtn, flag=wx.ALL, border=8) 

3408 ok_sizer.Add(self.rstBtn, flag=wx.ALL, border=8) 

3409 ok_sizer.Add(okBtn, flag=wx.ALL, border=8) 

3410 

3411 sizer.Add(grd_sizer) 

3412 sizer.AddSpacer(15) 

3413 sizer.Add(ok_sizer) 

3414 self.panel.SetSizer(sizer) 

3415 

3416 ## No categories are specified yet in database 

3417 ## mkak 2017.05.19 

3418 lbl_Category.Disable() 

3419 self.Category.Disable() 

3420 

3421 ix,iy = self.panel.GetBestSize() 

3422 self.SetSize((ix+40, iy+40)) 

3423 

3424 self.Show() 

3425 

3426 self.srch = SearchCIFdb() if srch_cls is None else srch_cls 

3427 self.setValues() 

3428 

3429 

3430######################################################################### 

3431 

3432 def setValues(self): 

3433 

3434 key = 'authors' 

3435 self.Author.SetValue(self.srch.show_parameter(key=key)) 

3436 

3437 self.Symmetry.SetValue(self.srch.show_geometry()) 

3438 

3439 key = 'categories' 

3440 # print("categoiries ", self.Category, dir(self.Category)) 

3441 # print(" -- = ", self.srch.show_parameter(key=key)) 

3442 # self.Category.Set(self.srch.show_parameter(key=key)) 

3443 

3444 key = 'keywords' 

3445 self.Keyword.SetValue(self.srch.show_parameter(key=key)) 

3446 

3447 key = 'amcsd' 

3448 self.AMCSD.SetValue(self.srch.show_parameter(key=key)) 

3449 

3450 if len(np.shape(self.srch.mnrlname)) > 0: 

3451 self.srch.mnrlname = self.srch.mnrlname[0] 

3452 self.Mineral.SetStringSelection(self.srch.mnrlname) 

3453 

3454 self.Chemistry.SetValue(self.srch.show_chemistry()) 

3455 

3456 

3457 def entrAuthor(self,event=None): 

3458 key = 'authors' 

3459 self.srch.read_parameter(self.Author.GetValue(),key=key) 

3460 self.Author.SetValue(self.srch.show_parameter(key=key)) 

3461 

3462 def entrSymmetry(self,event=None): 

3463 self.srch.read_geometry(str(self.Symmetry.GetValue())) 

3464 self.Symmetry.SetValue(self.srch.show_geometry()) 

3465 

3466 def entrCategory(self,event=None): 

3467 key = 'categories' 

3468 self.srch.read_parameter(self.Category.GetValue(),key=key) 

3469 self.Category.SetValue(self.srch.show_parameter(key=key)) 

3470 

3471 def entrKeyword(self,event=None): 

3472 key = 'keywords' 

3473 self.srch.read_parameter(self.Keyword.GetValue(),key=key) 

3474 self.Keyword.SetValue(self.srch.show_parameter(key=key)) 

3475 

3476 def entrAMCSD(self,event=None): 

3477 key = 'amcsd' 

3478 self.srch.read_parameter(self.AMCSD.GetValue(),key=key) 

3479 self.AMCSD.SetValue(self.srch.show_parameter(key=key)) 

3480 

3481 def entrMineral(self,event=None): 

3482 key = 'mnrlname' 

3483 self.srch.mnrlname = event.GetString() 

3484 if self.srch.mnrlname not in self.minerals: 

3485 self.minerals.insert(1,self.srch.mnrlname) 

3486 self.Mineral.Set(self.minerals) 

3487 self.Mineral.SetStringSelection(self.srch.mnrlname) 

3488 self.srch.read_parameter(self.srch.mnrlname,key=key) 

3489 

3490 def entrChemistry(self,event=None): 

3491 self.srch.read_chemistry(self.Chemistry.GetValue()) 

3492 self.Chemistry.SetValue(self.srch.show_chemistry()) 

3493 

3494######################################################################### 

3495# def SetValues(self,event=None): 

3496# 

3497# 

3498# ## Mineral search 

3499# if len(self.parent.mnrl_include) == 1: 

3500# if self.parent.mnrl_include[0] not in self.minerals: 

3501# self.minerals.insert(1,self.parent.mnrl_include[0]) 

3502# self.Mineral.Set(self.minerals) 

3503# self.Mineral.SetSelection(1) 

3504# else: 

3505# 

3506# 

3507# self.Mineral = wx.ComboBox(self.panel, choices=self.minerals, size=(270, -1), style=wx.TE_PROCESS_ENTER) 

3508# 

3509# ## AMCSD search 

3510# self.AMCSD = wx.TextCtrl(self.panel, size=(270, -1), style=wx.TE_PROCESS_ENTER) 

3511# 

3512# ## Author search 

3513# self.Author = wx.TextCtrl(self.panel, size=(175, -1), style=wx.TE_PROCESS_ENTER) 

3514# 

3515# ## Chemistry search 

3516# 

3517# self.Chemistry.SetValue(self.srch.show_chemistry()) 

3518# 

3519# 

3520# ## Cell parameter symmetry search 

3521# self.Symmetry = wx.TextCtrl(self.panel, size=(175, -1), style=wx.TE_PROCESS_ENTER) 

3522# 

3523# ## General search 

3524# lbl_Keyword = wx.StaticText(self.panel, label='Keyword search:' ) 

3525# self.Keyword = wx.TextCtrl(self.panel, size=(270, -1), style=wx.TE_PROCESS_ENTER) 

3526# 

3527# 

3528# ## Database searching parameters 

3529# self.parent.elem_include = [] 

3530# self.parent.elem_exclude = [] 

3531# self.parent.amcsd = [] 

3532# self.parent.auth_include = [] 

3533# self.parent.mnrl_include = [] 

3534 

3535######################################################################### 

3536 def onChemistry(self,event=None): 

3537 dlg = PeriodicTableSearch(self,include=self.srch.elem_incl, 

3538 exclude=self.srch.elem_excl) 

3539 update = False 

3540 if dlg.ShowModal() == wx.ID_OK: 

3541 incl = dlg.element_include 

3542 excl = dlg.element_exclude 

3543 update = True 

3544 dlg.Destroy() 

3545 

3546 if update: 

3547 self.srch.elem_incl = incl 

3548 self.srch.elem_excl = excl 

3549 self.Chemistry.SetValue(self.srch.show_chemistry()) 

3550 

3551 

3552 def onAuthor(self,event=None): 

3553 authorlist = self.cifdb.return_author_names() 

3554 dlg = AuthorListTable(self,authorlist,include=self.srch.authors) 

3555 

3556 update = False 

3557 if dlg.ShowModal() == wx.ID_OK: 

3558 incl = [] 

3559 ii = dlg.authlist.GetSelections() 

3560 for i in ii: 

3561 incl +=[authorlist[i]] 

3562 update = True 

3563 dlg.Destroy() 

3564 

3565 if update: 

3566 self.srch.authors = incl 

3567 self.Author.SetValue(self.srch.show_parameter(key='authors')) 

3568 

3569 def onSymmetry(self,event=None): 

3570 dlg = XRDSymmetrySearch(self,search=self.srch) 

3571 update = False 

3572 if dlg.ShowModal() == wx.ID_OK: 

3573 vals = [dlg.min_a.GetValue(), dlg.max_a.GetValue(), 

3574 dlg.min_b.GetValue(), dlg.max_b.GetValue(), 

3575 dlg.min_c.GetValue(), dlg.max_c.GetValue(), 

3576 dlg.min_alpha.GetValue(), dlg.max_alpha.GetValue(), 

3577 dlg.min_beta.GetValue(), dlg.max_beta.GetValue(), 

3578 dlg.min_gamma.GetValue(), dlg.max_gamma.GetValue(), 

3579 dlg.SG.GetSelection()] 

3580 update = True 

3581 dlg.Destroy() 

3582 

3583 if update: 

3584 for i,val in enumerate(vals): 

3585 if val == '' or val == 0: 

3586 vals[i] = None 

3587 elif val != 12: 

3588 vals[i] = '%0.3f' % float(val) 

3589 

3590 self.srch.a.min, self.srch.a.max, self.srch.a.unit = vals[0],vals[1],'A' 

3591 self.srch.b.min, self.srch.b.max, self.srch.b.unit = vals[2],vals[3],'A' 

3592 self.srch.c.min, self.srch.c.max, self.srch.c.unit = vals[4],vals[5],'A' 

3593 

3594 self.srch.alpha.min, self.srch.alpha.max, self.srch.alpha.unit = vals[6],vals[7],'deg' 

3595 self.srch.beta.min, self.srch.beta.max, self.srch.beta.unit = vals[8],vals[9],'deg' 

3596 self.srch.gamma.min, self.srch.gamma.max, self.srch.gamma.unit = vals[10],vals[11],'deg' 

3597 

3598 self.srch.sg = vals[12] 

3599 

3600 self.Symmetry.SetValue(self.srch.show_geometry()) 

3601 

3602 def onReset(self,event=None): 

3603 self.minerals = self.cifdb.get_mineral_names() 

3604 self.Mineral.Set(self.minerals) 

3605 self.Mineral.Select(0) 

3606 self.Author.Clear() 

3607 self.AMCSD.Clear() 

3608 self.Chemistry.Clear() 

3609 self.Symmetry.Clear() 

3610 self.Category.DeselectAll() 

3611 self.Keyword.Clear() 

3612 self.srch.__init__() 

3613 

3614 

3615######################################################################### 

3616class PeriodicTableSearch(wx.Dialog): 

3617 

3618 def __init__(self, parent,include=[],exclude=[]): 

3619 

3620 wx.Dialog.__init__(self, parent, wx.ID_ANY, title='Periodic Table of Elements') 

3621 

3622 panel = wx.Panel(self) 

3623 self.ptable = PeriodicTablePanel(panel,title='Select Element(s)', 

3624 onselect=self.onSelectElement, 

3625 highlight=True) 

3626 

3627 okBtn = wx.Button(panel, wx.ID_OK, label='Search selected' ) 

3628 exBtn = wx.Button(panel, label='Exclude all others' ) 

3629 rstBtn = wx.Button(panel, label='Clear' ) 

3630 canBtn = wx.Button(panel, wx.ID_CANCEL ) 

3631 

3632 ## Bind buttons for functionality 

3633 exBtn.Bind(wx.EVT_BUTTON, self.onExclude ) 

3634 rstBtn.Bind(wx.EVT_BUTTON, self.onClear ) 

3635 

3636 main_sizer = wx.BoxSizer(wx.VERTICAL) 

3637 

3638 main_sizer.Add(self.ptable, flag=wx.ALL, border=20) 

3639 

3640 btn_sizer = wx.BoxSizer(wx.HORIZONTAL) 

3641 btn_sizer.Add(okBtn, flag=wx.RIGHT, border=5) 

3642 btn_sizer.Add(exBtn, flag=wx.RIGHT, border=5) 

3643 btn_sizer.Add(rstBtn, flag=wx.RIGHT, border=5) 

3644 btn_sizer.Add(canBtn, flag=wx.RIGHT, border=5) 

3645 

3646 main_sizer.Add(btn_sizer, flag=wx.ALL, border=20) 

3647 

3648 pack(panel, main_sizer) 

3649 

3650 ix,iy = panel.GetBestSize() 

3651 self.SetSize((ix+20, iy+50)) 

3652 

3653 self.element_include = include 

3654 self.element_exclude = exclude 

3655 self.setDefault() 

3656 

3657 

3658 self.cnt_elem = len(self.ptable.syms) 

3659 

3660 def setDefault(self): 

3661 

3662 for name in self.ptable.ctrls: 

3663 if name in self.element_include: 

3664 textwid = self.ptable.ctrls[name] 

3665 textwid.SetForegroundColour(self.ptable.SEL_FG) 

3666 textwid.SetBackgroundColour(self.ptable.SEL_BG) 

3667 elif name in self.element_exclude: 

3668 textwid = self.ptable.ctrls[name] 

3669 textwid.SetForegroundColour(self.ptable.NEG_FG) 

3670 textwid.SetBackgroundColour(self.ptable.NEG_BG) 

3671 else: 

3672 textwid = self.ptable.ctrls[name] 

3673 textwid.SetForegroundColour(self.ptable.REG_FG) 

3674 textwid.SetBackgroundColour(self.ptable.REG_BG) 

3675 

3676 #self.ptable.onexclude(selected=self.element_include) 

3677 

3678 def onSelectElement(self,elem=None, event=None): 

3679 

3680 if elem not in self.element_include and elem not in self.element_exclude: 

3681 self.element_include += [elem] 

3682 elif elem in self.element_include: 

3683 self.element_exclude += [elem] 

3684 i = self.element_include.index(elem) 

3685 self.element_include.pop(i) 

3686 elif elem in self.element_exclude: 

3687 i = self.element_exclude.index(elem) 

3688 self.element_exclude.pop(i) 

3689 

3690 def onClear(self,event=None): 

3691 

3692 self.element_include = [] 

3693 self.element_exclude = [] 

3694 self.ptable.onclear() 

3695 

3696 def onExclude(self,event=None): 

3697 

3698 for elem in self.ptable.syms: 

3699 if elem not in self.element_include and elem not in self.element_exclude: 

3700 self.element_exclude += [elem] 

3701 self.ptable.onexclude(selected=self.element_include) 

3702 

3703######################################################################### 

3704class AuthorListTable(wx.Dialog): 

3705 """""" 

3706 

3707 def __init__(self,parent,authorlist,include=[]): 

3708 

3709 ## Constructor 

3710 dialog = wx.Dialog.__init__(self, parent, title='Cell Parameters and Symmetry') 

3711 ## remember: size=(width,height) 

3712 self.panel = wx.Panel(self) 

3713 self.list = authorlist 

3714 self.include = include 

3715 

3716 sizer = wx.BoxSizer(wx.VERTICAL) 

3717 ok_sizer = wx.BoxSizer(wx.HORIZONTAL) 

3718 

3719 self.authlist = wx.ListBox(self.panel, size=(170, 130), style= wx.LB_MULTIPLE) 

3720 self.authlist.Set(self.list) 

3721 

3722 ## Define buttons 

3723 self.rstBtn = wx.Button(self.panel, label='Reset' ) 

3724 hlpBtn = wx.Button(self.panel, wx.ID_HELP ) 

3725 okBtn = wx.Button(self.panel, wx.ID_OK ) 

3726 canBtn = wx.Button(self.panel, wx.ID_CANCEL ) 

3727 

3728 ## Bind buttons for functionality 

3729 ok_sizer.Add(hlpBtn, flag=wx.ALL, border=8) 

3730 ok_sizer.Add(canBtn, flag=wx.ALL, border=8) 

3731 ok_sizer.Add(self.rstBtn, flag=wx.ALL, border=8) 

3732 ok_sizer.Add(okBtn, flag=wx.ALL, border=8) 

3733 

3734 

3735 sizer.Add(self.authlist) 

3736 sizer.AddSpacer(15) 

3737 sizer.Add(ok_sizer) 

3738 self.panel.SetSizer(sizer) 

3739 

3740 ix,iy = self.panel.GetBestSize() 

3741 self.SetSize((ix+40, iy+40)) 

3742 

3743 self.Show() 

3744 self.onSet() 

3745 

3746 def onReset(self,event=None): 

3747 

3748 for i,n in enumerate(self.list): 

3749 self.authlist.Deselect(i) 

3750 

3751 

3752 def onSet(self,event=None): 

3753 

3754 for i,n in enumerate(self.list): 

3755 if n in self.include: 

3756 self.authlist.Select(i) 

3757 else: 

3758 self.authlist.Deselect(i) 

3759 

3760 

3761 

3762######################################################################### 

3763class XRDSymmetrySearch(wx.Dialog): 

3764 ''' 

3765 GUI interface for specifying lattice parameters 

3766 ''' 

3767 

3768 def __init__(self,parent,search=None): 

3769 

3770 ## Constructor 

3771 dialog = wx.Dialog.__init__(self, parent, title='Cell Parameters and Symmetry') 

3772 ## remember: size=(width,height) 

3773 self.panel = wx.Panel(self) 

3774 

3775 sizer = wx.BoxSizer(wx.VERTICAL) 

3776 grd_sizer = wx.GridBagSizer( 5, 6) 

3777 ok_sizer = wx.BoxSizer(wx.HORIZONTAL) 

3778 

3779 ## Lattice parameters 

3780 lbl_a = wx.StaticText(self.panel, label='a (A)' ) 

3781 self.min_a = wx.TextCtrl(self.panel, size=(100, -1), style = wx.TE_PROCESS_ENTER ) 

3782 self.max_a = wx.TextCtrl(self.panel, size=(100, -1), style = wx.TE_PROCESS_ENTER ) 

3783 

3784 lbl_b = wx.StaticText(self.panel, label='b (A)' ) 

3785 self.min_b = wx.TextCtrl(self.panel, size=(100, -1), style = wx.TE_PROCESS_ENTER ) 

3786 self.max_b = wx.TextCtrl(self.panel, size=(100, -1), style = wx.TE_PROCESS_ENTER ) 

3787 

3788 lbl_c = wx.StaticText(self.panel, label='c (A)' ) 

3789 self.min_c = wx.TextCtrl(self.panel, size=(100, -1), style = wx.TE_PROCESS_ENTER ) 

3790 self.max_c = wx.TextCtrl(self.panel, size=(100, -1), style = wx.TE_PROCESS_ENTER ) 

3791 

3792 lbl_alpha = wx.StaticText(self.panel, label='alpha (deg)' ) 

3793 self.min_alpha = wx.TextCtrl(self.panel, size=(100, -1), style = wx.TE_PROCESS_ENTER ) 

3794 self.max_alpha = wx.TextCtrl(self.panel, size=(100, -1), style = wx.TE_PROCESS_ENTER ) 

3795 

3796 lbl_beta = wx.StaticText(self.panel, label='beta (deg)' ) 

3797 self.min_beta = wx.TextCtrl(self.panel, size=(100, -1), style = wx.TE_PROCESS_ENTER ) 

3798 self.max_beta = wx.TextCtrl(self.panel, size=(100, -1), style = wx.TE_PROCESS_ENTER ) 

3799 

3800 lbl_gamma = wx.StaticText(self.panel, label='gamma (deg)' ) 

3801 self.min_gamma = wx.TextCtrl(self.panel, size=(100, -1), style = wx.TE_PROCESS_ENTER ) 

3802 self.max_gamma = wx.TextCtrl(self.panel, size=(100, -1), style = wx.TE_PROCESS_ENTER ) 

3803 

3804 SG_list = [''] 

3805 for sgno in np.arange(230): 

3806 SG_list.append('%3d' % (sgno+1)) 

3807 

3808 hm_notations = [''] 

3809 ## Displays all space groups 

3810 for spgrp_no in sorted(SPACEGROUPS.keys()): 

3811 for spgrp_name in sorted(SPACEGROUPS[spgrp_no]): 

3812 hm_notations += ['%s : %s' % (spgrp_no,spgrp_name)] 

3813 

3814 lbl_SG = wx.StaticText(self.panel, label='Space group:') 

3815 self.SG = wx.Choice(self.panel, choices=SG_list) 

3816 self.HMsg = wx.Choice(self.panel, choices=hm_notations) 

3817 

3818 self.HMsg.Bind(wx.EVT_CHOICE, self.onSpaceGroup) 

3819 

3820 ## Define buttons 

3821 self.rstBtn = wx.Button(self.panel, label='Reset' ) 

3822 hlpBtn = wx.Button(self.panel, wx.ID_HELP ) 

3823 okBtn = wx.Button(self.panel, wx.ID_OK ) 

3824 canBtn = wx.Button(self.panel, wx.ID_CANCEL ) 

3825 

3826 ## Bind buttons for functionality 

3827 self.rstBtn.Bind(wx.EVT_BUTTON, self.onReset ) 

3828 

3829 grd_sizer.Add(lbl_a, pos = ( 1,1) ) 

3830 grd_sizer.Add(self.min_a, pos = ( 1,2) ) 

3831 grd_sizer.Add(self.max_a, pos = ( 1,3) ) 

3832 

3833 grd_sizer.Add(lbl_b, pos = ( 2,1) ) 

3834 grd_sizer.Add(self.min_b, pos = ( 2,2) ) 

3835 grd_sizer.Add(self.max_b, pos = ( 2,3) ) 

3836 

3837 grd_sizer.Add(lbl_c, pos = ( 3,1) ) 

3838 grd_sizer.Add(self.min_c, pos = ( 3,2) ) 

3839 grd_sizer.Add(self.max_c, pos = ( 3,3) ) 

3840 

3841 grd_sizer.Add(lbl_alpha, pos = ( 4,1) ) 

3842 grd_sizer.Add(self.min_alpha, pos = ( 4,2) ) 

3843 grd_sizer.Add(self.max_alpha, pos = ( 4,3) ) 

3844 

3845 grd_sizer.Add(lbl_beta, pos = ( 5,1) ) 

3846 grd_sizer.Add(self.min_beta, pos = ( 5,2) ) 

3847 grd_sizer.Add(self.max_beta, pos = ( 5,3) ) 

3848 

3849 grd_sizer.Add(lbl_gamma, pos = ( 6,1) ) 

3850 grd_sizer.Add(self.min_gamma, pos = ( 6,2) ) 

3851 grd_sizer.Add(self.max_gamma, pos = ( 6,3) ) 

3852 

3853 grd_sizer.Add(lbl_SG, pos = ( 7,1) ) 

3854 grd_sizer.Add(self.SG, pos = ( 7,2) ) 

3855 grd_sizer.Add(self.HMsg, pos = ( 7,3) ) 

3856 

3857 self.min_a.Bind(wx.EVT_TEXT_ENTER, self.formatFloat) 

3858 self.max_a.Bind(wx.EVT_TEXT_ENTER, self.formatFloat) 

3859 self.min_b.Bind(wx.EVT_TEXT_ENTER, self.formatFloat) 

3860 self.max_b.Bind(wx.EVT_TEXT_ENTER, self.formatFloat) 

3861 self.min_c.Bind(wx.EVT_TEXT_ENTER, self.formatFloat) 

3862 self.max_c.Bind(wx.EVT_TEXT_ENTER, self.formatFloat) 

3863 self.min_alpha.Bind(wx.EVT_TEXT_ENTER, self.formatFloat) 

3864 self.max_alpha.Bind(wx.EVT_TEXT_ENTER, self.formatFloat) 

3865 self.min_beta.Bind(wx.EVT_TEXT_ENTER, self.formatFloat) 

3866 self.max_beta.Bind(wx.EVT_TEXT_ENTER, self.formatFloat) 

3867 self.min_gamma.Bind(wx.EVT_TEXT_ENTER, self.formatFloat) 

3868 self.max_gamma.Bind(wx.EVT_TEXT_ENTER, self.formatFloat) 

3869 

3870 ok_sizer.Add(hlpBtn, flag=wx.ALL, border=8) 

3871 ok_sizer.Add(canBtn, flag=wx.ALL, border=8) 

3872 ok_sizer.Add(self.rstBtn, flag=wx.ALL, border=8) 

3873 ok_sizer.Add(okBtn, flag=wx.ALL, border=8) 

3874 

3875 

3876 sizer.Add(grd_sizer) 

3877 sizer.AddSpacer(15) 

3878 sizer.Add(ok_sizer) 

3879 self.panel.SetSizer(sizer) 

3880 

3881 ix,iy = self.panel.GetBestSize() 

3882 self.SetSize((ix+40, iy+40)) 

3883 

3884 self.Show() 

3885 

3886 if search is not None: 

3887 self.srch = search 

3888 self.SetSearch() 

3889 

3890######################################################################### 

3891 def onReset(self,event=None): 

3892 self.min_a.Clear() 

3893 self.max_a.Clear() 

3894 self.min_b.Clear() 

3895 self.max_b.Clear() 

3896 self.min_c.Clear() 

3897 self.max_c.Clear() 

3898 self.min_alpha.Clear() 

3899 self.max_alpha.Clear() 

3900 self.min_beta.Clear() 

3901 self.max_beta.Clear() 

3902 self.min_gamma.Clear() 

3903 self.max_gamma.Clear() 

3904 self.SG.SetSelection(0) 

3905 self.HMsg.SetSelection(0) 

3906 

3907 def SetSearch(self): 

3908 

3909 if self.srch.a.min is not None: 

3910 self.min_a.SetValue(self.srch.a.min) 

3911 if self.srch.a.max is not None: 

3912 self.max_a.SetValue(self.srch.a.max) 

3913 if self.srch.b.min is not None: 

3914 self.min_b.SetValue(self.srch.b.min) 

3915 if self.srch.b.max is not None: 

3916 self.max_b.SetValue(self.srch.b.max) 

3917 if self.srch.c.min is not None: 

3918 self.min_c.SetValue(self.srch.c.min) 

3919 if self.srch.c.max is not None: 

3920 self.max_c.SetValue(self.srch.c.max) 

3921 if self.srch.alpha.min is not None: 

3922 self.min_alpha.SetValue(self.srch.alpha.min) 

3923 if self.srch.alpha.max is not None: 

3924 self.max_alpha.SetValue(self.srch.alpha.max) 

3925 if self.srch.beta.min is not None: 

3926 self.min_beta.SetValue(self.srch.beta.min) 

3927 if self.srch.beta.max is not None: 

3928 self.max_beta.SetValue(self.srch.beta.max) 

3929 if self.srch.gamma.min is not None: 

3930 self.min_gamma.SetValue(self.srch.gamma.min) 

3931 if self.srch.gamma.max is not None: 

3932 self.max_gamma.SetValue(self.srch.gamma.max) 

3933 if self.srch.sg is not None: 

3934 self.SG.SetSelection(int(self.srch.sg)) 

3935 

3936 def onSpaceGroup(self,event=None): 

3937 

3938 i = self.HMsg.GetSelection() 

3939 if i > 0: 

3940 slct = int(self.HMsg.GetString(self.HMsg.GetSelection()).split()[0]) 

3941 self.SG.SetSelection(slct) 

3942 else: 

3943 self.SG.SetSelection(0) 

3944 

3945 def formatFloat(self,event): 

3946 event.GetEventObject().SetValue('%0.3f' % float(event.GetString())) 

3947 

3948class XRD1DViewer(LarchWxApp): 

3949 def __init__(self, **kws): 

3950 LarchWxApp.__init__(self) 

3951 

3952 def createApp(self): 

3953 frame = XRD1DViewerFrame() 

3954 frame.Show() 

3955 self.SetTopWindow(frame) 

3956 return True 

3957 

3958if __name__ == '__main__': 

3959 XRD1DViewer().MainLoop()