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
« 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
5'''
6import os
7from os.path import expanduser
9import numpy as np
10import sys
11import time
12import re
13import math
15from threading import Thread
16from functools import partial
18from io import StringIO
20import wx
21import wx.lib.mixins.listctrl as listmix
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)
29import larch
30from larch.larchlib import read_workdir, save_workdir
31from larch.utils import nativepath, get_cwd
32from larch.wxlib import PeriodicTablePanel, Choice, LarchWxApp
34from larch.xrd.cifdb import (cifDB, SearchCIFdb, QSTEP, QMIN, QMAX, CATEGORIES,
35 match_database, SPACEGROUPS, create_xrdcif)
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)
43###################################
45VERSION = '2 (14-March-2018)'
47SLIDER_SCALE = 1000. ## sliders step in unit 1. this scales to 0.001
48CIFSCALE = 1000
50MT01 = np.array([0,1])
51MT00 = np.zeros(2)
53ENERGY = 18.0
55SRCH_MTHDS = peakfinder_methods()
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
64BKGD_DEFAULT = {'exponent': 2,'compress': 5, 'width': 4}
65###################################
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
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)
82 return x, y
84def loadXYfile(event=None, parent=None, xrdviewer=None):
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)
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)
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))
110 xstep = (x[1] - x[0]) / 2
111 xy[0,0] = x[ 0] - xstep
112 xy[0,-1] = x[-1] + xstep
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
121class XRD1DViewerFrame(wx.Frame):
122 def __init__(self, parent=None, _larch=None, **kws):
123 self._larch = _larch
125 label = '1D XRD Data Analysis Software'
126 wx.Frame.__init__(self, parent, -1, title=label, size=(1000, 650), **kws)
128 read_workdir('gsemap.dat')
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'
134 self.statusbar = self.CreateStatusBar(3,wx.CAPTION)
136 panel = wx.Panel(self)
137 self.nb = wx.Notebook(panel)
139 self.openDB()
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)
145 self.srch_cls = SearchCIFdb()
146 self.amcsd_mtchlst = []
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')
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()
158 def openDB(self,dbname=None):
159 try:
160 self.cifdb.close()
161 except:
162 pass
164 if dbname is None:
165 dbname = self.default_cifdb
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])
174 def onExit(self, event=None):
176 dlg = wx.MessageDialog(None, 'Really Quit?', 'Question',
177 wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
179 ret = dlg.ShowModal()
180 if ret != wx.ID_YES:
181 return
183 try:
184 if hasattr(self.exit_callback, '__call__'):
185 self.exit_callback()
186 except:
187 pass
189 for frame in self.xrd1Dfitting.cifframe:
190 try:
191 frame.closeFrame()
192 except:
193 pass
196 try:
197 self.cifdb.close()
198 except:
199 pass
201 try:
202 self.Destroy()
203 except:
204 pass
207 def XRD1DMenuBar(self):
209 menubar = wx.MenuBar()
211 ###########################
212 ## diFFit1D
213 diFFitMenu = wx.Menu()
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)
224 menubar.Append(diFFitMenu, '&File')
226 ###########################
227 ## Analyze
228 DatabaseMenu = wx.Menu()
230 MenuItem(self, DatabaseMenu, '&Database information', '', self.xrd1Dfitting.database_info)
231 MenuItem(self, DatabaseMenu, '&Change database', '', self.xrd1Dfitting.open_database)
233 menubar.Append(DatabaseMenu, '&Database')
235 ###########################
236 ## Analyze
237 AnalyzeMenu = wx.Menu()
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)
243 menubar.Append(AnalyzeMenu, '&Analyze')
245 ###########################
246 ## Help
247 HelpMenu = wx.Menu()
249 MenuItem(self, HelpMenu, '&About', 'About diFFit1D viewer', self.onAbout)
251 menubar.Append(HelpMenu, '&Help')
253 ###########################
254 ## Create Menu Bar
255 self.SetMenuBar(menubar)
256 self.Bind(wx.EVT_CLOSE, self.onExit)
258 def write_message(self, s, panel=0):
259 '''write a message to the Status Bar'''
260 self.statusbar.SetStatusText(s, panel)
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)
273##############################################
274####
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)
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()
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
302 indicies = [i for i,name in enumerate(xrdv.data_name) if 'cif' not in name]
303 okay = False
305 xi = xrdv.ch_xaxis.GetSelection()
306 xrdf.rngpl.ch_xaxis.SetSelection(xi)
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
321 if okay:
322 seldat = xrdv.xy_data[index]
323 self.nb.SetSelection(1) ## switches to fitting panel
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')
331 if adddata:
333 if xrdf.xrd1dgrp is not None:
334 xrdf.reset_fitting()
335 xrdf.clearMATCHES()
337 xrdf.xrd1dgrp = seldat
338 xrdf.plot1D.set_title(xrdf.xrd1dgrp.label)
339 xrdf.plt_data = xrdf.xrd1dgrp.all_data()
341 xrdf.xmin = np.min(xrdf.plt_data[xi])
342 xrdf.xmax = np.max(xrdf.plt_data[xi])
344 xrdf.optionsON()
345 xrdv.optionsON()
346 xrdf.check1Daxis()
348 xrdf.ttl_energy.SetLabel('Energy: %0.3f keV (%0.4f A)' % (seldat.energy,
349 seldat.wavelength))
350 def save1Dxrd(self,event=None):
351 '''
353 mkak 2017.06.21
354 '''
355 xrdv = self.xrd1Dviewer
356 xrdf = self.xrd1Dfitting
358 indicies = [i for i,name in enumerate(xrdv.data_name) if 'cif' not in name]
359 okay = False
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()
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)
381class SelectSavingData(wx.Dialog):
382 def __init__(self,parent,list_xrd1d):
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))
389 panel = wx.Panel(self)
391 mainsizer = wx.BoxSizer(wx.VERTICAL)
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))
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)
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:')
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)
410 unitsizer = wx.BoxSizer(wx.VERTICAL)
411 unitsizer.Add(hsizer, flag=wx.TOP, border=5)
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...' )
419 self.Bind(wx.EVT_BUTTON, self.saveXY, fileBtn )
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)
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...' )
431 self.Bind(wx.EVT_BUTTON, self.onBROWSEponi, poniBtn )
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)
438 #####
439 ## OKAY!
440 oksizer = wx.BoxSizer(wx.HORIZONTAL)
442 okBtn = wx.Button(panel, wx.ID_OK )
443 canBtn = wx.Button(panel, wx.ID_CANCEL )
445 oksizer.Add(canBtn, flag=wx.RIGHT, border=8)
446 oksizer.Add(okBtn, flag=wx.RIGHT, border=8)
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)
460 panel.SetSizer(mainsizer)
462 ix,iy = panel.GetBestSize()
463 self.SetSize((ix+20, iy+50))
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()
472 dlg = wx.FileDialog(self, 'Save file as...',
473 defaultDir=dfltDIR,
474 wildcard=wildcards,
475 style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
477 path, save = None, False
478 if dlg.ShowModal() == wx.ID_OK:
479 save = True
480 path = dlg.GetPath().replace('\\', '/')
481 dlg.Destroy()
483 if save:
484 self.File.Clear()
485 self.File.SetValue(str(path))
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()
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()
503 if read:
504 self.Poni.Clear()
505 self.Poni.SetValue(str(path))
507class SelectFittingData(wx.Dialog):
508 def __init__(self,parent):
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()
517 ix,iy = self.panel.GetBestSize()
518 self.SetSize((ix+20, iy+50))
520 def createPanel(self):
522 self.panel = wx.Panel(self)
523 mainsizer = wx.BoxSizer(wx.VERTICAL)
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)
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)
537 oksizer.Add(canBtn, flag=wx.RIGHT, border=8)
538 oksizer.Add(self.okBtn, flag=wx.RIGHT, border=8)
540 hsizer = wx.BoxSizer(wx.HORIZONTAL)
541 hsizer.Add(self.slct_1Ddata, flag=wx.ALL|wx.EXPAND, border=8)
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)
549 self.panel.SetSizer(mainsizer)
550 self.slct_1Ddata.SetSelection(0)
552 def load_file(self, event=None):
553 print("Load File ", event)
554 loadXYfile(parent=self, xrdviewer=self.parent.xrd1Dviewer)
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]))
561class Fitting1DXRD(BasePanel):
562 '''
563 Panel for housing 1D XRD fitting
564 '''
565 label='Fitting'
566 def __init__(self,parent,owner=None,_larch=None):
568 wx.Panel.__init__(self, parent)
570 self.parent = parent
571 self.owner = owner
573 ## Default information
574 self.xrd1dgrp = None
575 self.plt_data = None
576 self.plt_cif = None
578 self.plt_peaks = None
579 self.peaklist = []
581 self.xmin = None
582 self.xmax = None
583 self.x, self.y = 0,0
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
590 ## Database searching parameters
591 self.elem_include = []
592 self.elem_exclude = []
593 self.amcsd = []
594 self.auth_include = []
595 self.mnrl_include = []
597 ## List of opened CIF frame windows (will close upon exit)
598 self.cifframe = []
600 self.SetFittingDefaults()
601 self.Panel1DFitting()
603 def SetFittingDefaults(self):
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
613 # Background fitting defaults
614 self.bkgd_kwargs = BKGD_DEFAULT.copy()
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)
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)
630 self.SetSizer(panel1D)
632 def createFittingPanels(self,parent):
634 pattern_title = SimpleText(parent, 'DATABASE FILTERING', size=(200, -1))
636 self.dnb = wx.Notebook(parent)
637 self.dnbpanels = []
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))
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)
655 def FilterTools(self,panel):
656 '''
657 Frame for visual toolbox
658 '''
660 vbox = wx.BoxSizer(wx.VERTICAL)
662 fitting_panel = wx.Panel(panel)
663 self.createFittingPanels(fitting_panel)
664 vbox.Add(fitting_panel, flag=wx.ALL, border=10)
666 return vbox
669 def createPatternPanels(self,parent):
671 pattern_title = SimpleText(parent, 'PATTERN PROCESSING', size=(200, -1))
672 self.pnb = wx.Notebook(parent)
673 self.pnbpanels = []
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))
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)
691 def PatternTools(self,panel):
692 '''
693 Frame for visual toolbox
694 '''
696 vbox = wx.BoxSizer(wx.VERTICAL)
698 pattern_panel = wx.Panel(panel)
699 self.createPatternPanels(pattern_panel)
700 vbox.Add(pattern_panel, flag=wx.ALL, border=10)
702 return vbox
704 def MatchPanel(self,panel):
705 '''
706 Matches
707 '''
708 vbox = wx.BoxSizer(wx.VERTICAL)
710 self.txt_amcsd_cnt = wx.StaticText(self, label='')
711 vbox.Add(self.txt_amcsd_cnt, flag=wx.LEFT, border=16)
713 return vbox
715 def LeftSidePanel(self,panel):
717 vbox = wx.BoxSizer(wx.VERTICAL)
719 pattools = self.PatternTools(self)
720 vbox.Add(pattools,flag=wx.TOP|wx.LEFT,border=10)
722 filtools = self.FilterTools(self)
723 vbox.Add(filtools,flag=wx.LEFT,border=10)
725 matchbx = self.MatchPanel(self)
726 vbox.Add(matchbx,flag=wx.LEFT,border=12)
728 return vbox
730 def SettingsPanel(self,panel):
732 vbox = wx.BoxSizer(wx.VERTICAL)
734 self.ttl_energy = wx.StaticText(self, label=('Energy: %0.3f keV (%0.4f A)' % (0,0)))
736 vbox.Add(self.ttl_energy, flag=wx.EXPAND|wx.ALL, border=8)
738 return vbox
740 def RightSidePanel(self,panel):
741 vbox = wx.BoxSizer(wx.VERTICAL)
742 hbox = wx.BoxSizer(wx.HORIZONTAL)
744 self.plot1DXRD(panel)
746 settings = self.SettingsPanel(self)
747 btnbox = self.QuickButtons(panel)
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
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')
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)
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
771##############################################
772#### DATA CALCULATIONS FUNCTIONS
774 def plot_all(self,show=True,showbkg=None):
776 if showbkg is None: showbkg = show
778 self.plot_background(show=showbkg)
779 self.plot_peaks(show=show)
780 self.plot_data()
782 def plot_data(self,event=None):
784 xi = self.rngpl.ch_xaxis.GetSelection()
785 self.plot1D.update_line(0, self.plt_data[xi], self.plt_data[3], draw=True)
787 self.rescale1Daxis(xaxis=True,yaxis=True)
789 def plot_background(self,show=True):
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)
798 def plot_peaks(self,show=True):
800 if show:
801 if len(self.xrd1dgrp.pki) > 0:
802 self.define_peaks()
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
810 def displayCIFpeaks(self, event=None, show=True, **kws):
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']
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
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
826 xi = self.rngpl.ch_xaxis.GetSelection()
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
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)
847 elementstr = self.owner.cifdb.composition_by_amcsd(amcsd_id,string=True)
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('')
864##############################################
865#### RANGE FUNCTIONS
867 def reset_fitting(self,name=None,min=0,max=1):
869 self.xrd1dgrp.label = name
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)
875 self.pkpl.btn_fdpks.Enable()
876 self.pkpl.btn_opks.Enable()
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()
884 self.srchpl.btn_mtch.Disable()
886 self.xmin = min
887 self.xmax = max
888 self.trim_data()
889 self.delete_all_peaks()
890 self.remove_background()
892 self.SetFittingDefaults()
893 self.plot_all(show=False)
895 def onSetRange(self,event=None):
897 self.check_range()
898 self.trim_data()
900 self.plot_data()
902 def check_range(self,event=None):
904 xmin,xmax = self.rngpl.val_xmin,self.rngpl.val_xmax
905 minval,maxval = float(xmin.GetValue()),float(xmax.GetValue())
907 xi = self.rngpl.ch_xaxis.GetSelection()
908 x = self.xrd1dgrp.slct_xaxis(xi=xi)
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))
915 if xi == 2: self.xmax = min(self.xmax,self.dlimit)
917 self.delete_all_peaks()
918 self.remove_background()
920 xmin.SetValue('%0.3f' % self.xmin)
921 xmax.SetValue('%0.3f' % self.xmax)
923 def onReset(self,event=None):
925 self.plt_peaks,self.xrd1dgrp.pki = None,[]
926 self.peaklist = []
928 self.reset_range()
929 self.plot_all(show=False)
931 def reset_range(self,event=None):
933 xi = self.rngpl.ch_xaxis.GetSelection()
934 x = self.xrd1dgrp.slct_xaxis(xi=xi)
936 self.xmin,self.xmax = np.min(x),np.max(x)
937 if xi == 2: self.xmax = min(self.xmax,self.dlimit)
939 self.rngpl.val_xmin.SetValue('%0.3f' % self.xmin)
940 self.rngpl.val_xmax.SetValue('%0.3f' % self.xmax)
942 self.trim_data()
943 self.remove_background()
945 def trim_data(self):
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()
951##############################################
952#### BACKGROUND FUNCTIONS
954 def onFitBkgd(self,event=None):
956 self.xrd1dgrp.fit_background(**self.bkgd_kwargs)
957 self.plt_data = self.xrd1dgrp.plot(bkgd=False)
959 self.plot_background()
961 self.bkgdpl.btn_rbkgd.Enable()
962 self.bkgdpl.ck_bkgd.Enable()
964 def onSbtrctBkgd(self,event=None):
966 check_bkgd = self.bkgdpl.ck_bkgd.GetValue()
967 self.plt_data = self.xrd1dgrp.plot(bkgd=check_bkgd)
969 self.plot_all(showbkg=(check_bkgd==False))
971 def onRmvBkgd(self,event=None):
973 self.remove_background()
974 self.plot_background(show=False)
976 def remove_background(self,event=None):
978 self.xrd1dgrp.reset_bkgd()
979 self.plt_data = self.xrd1dgrp.plot(bkgd=False)
981 self.bkgdpl.ck_bkgd.SetValue(False)
982 self.bkgdpl.ck_bkgd.Disable()
983 self.bkgdpl.btn_rbkgd.Disable()
985 self.plot_all(showbkg=False)
987 def background_options(self,event=None):
989 myDlg = BackgroundOptions(self)
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()
999 if fit:
1000 self.onFitBkgd()
1003##############################################
1004#### PEAK FUNCTIONS
1006 def onPeaks(self,event=None,filter=False):
1008 self.find_peaks(filter=filter)
1010 if len(self.xrd1dgrp.pki) > 0:
1011 self.srchpl.btn_mtch.Enable()
1013 def onAddPks(self,event=None):
1015 xi = self.rngpl.ch_xaxis.GetSelection()
1016 idx = (np.abs(self.plt_data[xi]-self.x)).argmin()
1017 self.xrd1dgrp.pki.append(idx)
1019 self.peak_display()
1020 self.plot_peaks()
1023 def onRmvPksAll(self,event=None,filter=False):
1025 self.remove_all_peaks()
1026 self.srchpl.btn_mtch.Disable()
1027 self.plot_peaks(show=False)
1029 def find_peaks(self,event=None,newpeaks=True,filter=False):
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')
1035 if newpeaks:
1036 ## clears previous searches
1037 self.remove_all_peaks()
1039 self.intthrsh = float(self.pkpl.val_intthr.GetValue())
1040 if self.intthrsh > 1: self.intthrsh = int(self.intthrsh)
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()
1052 self.pkpl.btn_rmvpks.Enable()
1054 def peak_display(self):
1056 self.define_peaks()
1058 self.peaklist = []
1059 self.peaklistbox.Clear()
1061 xi = self.rngpl.ch_xaxis.GetSelection()
1062 for i,ii in enumerate(self.xrd1dgrp.pki):
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)
1075 self.peaklist += [peakname]
1076 self.peaklistbox.Append(peakname)
1077 self.pkpl.ttl_cntpks.SetLabel('Total: %i peaks' % (len(self.xrd1dgrp.pki)))
1079 def onClrInstr(self,event=None):
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')
1086 def onClrSize(self,event=None):
1088 self.xrd1dgrp.D = None
1089 self.instpl.val_D.SetValue('')
1091 def onGetSize(self,event=None):
1093 try:
1094 self.xrd1dgrp.D = float(self.instpl.val_D.GetValue())
1095 except:
1096 self.onClrSize()
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)
1104 def onGetInstr(self,event=None):
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()
1115 def fit_instrumental(self,event=None):
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
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()
1148 def remove_all_peaks(self,event=None):
1150 self.delete_all_peaks()
1151 self.pkpl.btn_rmvpks.Disable()
1153 def delete_all_peaks(self,event=None):
1155 self.plt_peaks,self.xrd1dgrp.pki = None,[]
1157 self.peaklist = []
1158 self.peaklistbox.Clear()
1159 self.pkpl.ttl_cntpks.SetLabel('Total: 0 peaks')
1161 def peak_options(self,event=None):
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())
1174 myDlg.Destroy()
1177 def select_peak(self, evt=None, peakname=None, **kws):
1179 if peakname is None and evt is not None:
1180 peakname = evt.GetString()
1182 def define_peaks(self):
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
1189 def rm_sel_peaks(self, peakname, event=None):
1191 if peakname in self.peaklist:
1193 pki = self.peaklist.index(peakname)
1195 self.peaklist.pop(pki)
1196 self.xrd1dgrp.pki.pop(pki)
1198 self.plot_peaks()
1200 self.pkpl.ttl_cntpks.SetLabel('Total: %i peaks' % (len(self.xrd1dgrp.pki)))
1202##############################################
1203#### PLOTPANEL FUNCTIONS
1204 def plot1DXRD(self,panel):
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
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]]
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)
1225 def on_cursor(self,x=None, y=None, **kw):
1226 self.x,self.y = x,y
1228 def onSAVEfig(self,event=None):
1229 self.plot1D.save_figure()
1231 def onPLOTset(self,event=None):
1232 self.plot1D.configure()
1234 def onRESETplot(self,event=None):
1235 self.plot1D.reset_config()
1237 def onChangeXscale(self,event=None):
1239 self.check1Daxis()
1241 xi = self.rngpl.ch_xaxis.GetSelection()
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)
1251 def optionsON(self,event=None):
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()
1278 def check1Daxis(self,event=None,yaxis=False):
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)
1284 self.rngpl.val_xmin.SetValue('%0.3f' % minx)
1285 self.rngpl.val_xmax.SetValue('%0.3f' % maxx)
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)
1302 self.plot_data()
1304 def rescale1Daxis(self,xaxis=True,yaxis=False):
1306 xi = self.rngpl.ch_xaxis.GetSelection()
1307 x,y = self.plt_data[xi],self.plt_data[3]
1309 if xaxis: self.set_xview(np.min(x), np.max(x))
1310 if yaxis: self.set_yview(np.min(y), np.max(y))
1312 def set_xview(self, x1, x2):
1314 xi = self.rngpl.ch_xaxis.GetSelection()
1315 xmin,xmax = np.min(self.plt_data[xi]),np.max(self.plt_data[xi])
1317 x1,x2 = max(xmin,x1),min(xmax,x2)
1318 if xi == 2: x2 = min(x2,self.dlimit)
1320 self.plot1D.axes.set_xlim((x1, x2))
1321 self.plot1D.canvas.draw()
1323 def set_yview(self, y1, y2):
1325 ymin,ymax = np.min(self.plt_data[3]),np.max(self.plt_data[3])
1326 y1,y2 = max(ymin,y1),min(ymax,y2)
1328 self.plot1D.axes.set_ylim((y1, y2))
1329 self.plot1D.canvas.draw()
1331##############################################
1332#### DATABASE FUNCTIONS
1334 def database_info(self,event=None):
1336 myDlg = DatabaseInfoGUI(self)
1338 change = False
1339 if myDlg.ShowModal() == wx.ID_OK: change = True
1340 myDlg.Destroy()
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)
1348 path, read = None, False
1349 if dlg.ShowModal() == wx.ID_OK:
1350 read = True
1351 path = dlg.GetPath().replace('\\', '/')
1352 dlg.Destroy()
1354 if read:
1355 try:
1356 self.owner.openDB(dbname=path)
1357 except:
1358 pass
1359 return path
1362 def filter_database(self,event=None):
1363 print(" filter database B")
1364 cifdb = self.owner.cifdb
1366 myDlg = XRDSearchGUI(cifdb, self.owner.srch_cls)
1368 filter = False
1370 if myDlg.ShowModal() == wx.ID_OK:
1372 self.elem_include = myDlg.srch.elem_incl
1373 self.elem_exclude = myDlg.srch.elem_excl
1374 self.owner.srch_cls = myDlg.srch
1376 list_amcsd = []
1377 if len(myDlg.AMCSD.GetValue()) > 0:
1378 myDlg.entrAMCSD()
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
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(',')
1397 filter = True
1398 myDlg.Destroy()
1400 if filter == True:
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
1418 def onMatch(self,event=None):
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)
1427 def displayMATCHES(self,list_amcsd):
1428 '''
1429 Populates Results Panel with list
1430 '''
1431 self.srchpl.amcsdlistbox.Clear()
1432 self.displayCIFpeaks(show=False)
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('')
1450 self.srchpl.btn_clr.Enable()
1451 self.srchpl.btn_shw.Enable()
1452 self.srchpl.amcsdlistbox.EnsureVisible(0)
1454 def clearMATCHES(self,event=None):
1455 '''
1456 Populates Results Panel with list
1457 '''
1458 self.txt_amcsd_cnt.SetLabel('')
1460 self.srchpl.amcsdlistbox.Clear()
1461 self.owner.srch_cls = SearchCIFdb()
1463 self.srchpl.btn_clr.Disable()
1464 self.srchpl.btn_shw.Disable()
1466 try:
1467 self.displayCIFpeaks(show=False)
1468 except:
1469 pass
1471class BackgroundOptions(wx.Dialog):
1472 def __init__(self,parent):
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
1480 self.createPanel()
1482 self.PanelValues()
1484 ix,iy = self.panel.GetBestSize()
1485 self.SetSize((ix+20, iy+40))
1487 def PanelValues(self, event=None):
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'] ) )
1495 def PanelDefaults(self, event=None):
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'] ) )
1502 def createPanel(self):
1504 self.panel = wx.Panel(self)
1505 sizer = wx.GridBagSizer(3, 3)
1507 mainsizer = wx.BoxSizer(wx.VERTICAL)
1509 ## Exponent
1510 self.val_exp = wx.TextCtrl(self.panel,wx.TE_PROCESS_ENTER)
1512 ## Compress
1513 self.val_comp = wx.TextCtrl(self.panel,wx.TE_PROCESS_ENTER)
1515 ## Width
1516 self.val_wid = wx.TextCtrl(self.panel,wx.TE_PROCESS_ENTER)
1518 ## Reset button
1519 btn_reset = Button(self.panel,label='reset',size=(90, -1),action=self.PanelDefaults)
1521 #####
1522 ## OKAY!
1523 oksizer = wx.BoxSizer(wx.HORIZONTAL)
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 )
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.'))
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)
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)
1551 pack(self.panel, sizer)
1554class PeakOptions(wx.Dialog):
1555 def __init__(self,parent,method='peakutils.indexes'):
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
1563 if method == 'scipy.signal.find_peaks_cwt':
1564 self.createPanel_scipy()
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()
1572 ## Set defaults
1573 self.val1.SetValue(str(self.parent.thrsh))
1574 self.val2.SetValue(str(self.parent.min_dist))
1575 else:
1576 return
1578 ix,iy = self.panel.GetBestSize()
1579 self.SetSize((ix+20, iy+50))
1581 def createPanel_index(self):
1583 self.panel = wx.Panel(self)
1585 mainsizer = wx.BoxSizer(wx.VERTICAL)
1587 ## Threshold
1588 thrshsizer = wx.BoxSizer(wx.VERTICAL)
1590 ttl_thrsh = wx.StaticText(self.panel, label='Threshold')
1591 self.val1 = wx.TextCtrl(self.panel,wx.TE_PROCESS_ENTER)
1593 thrshsizer.Add(ttl_thrsh, flag=wx.RIGHT, border=5)
1594 thrshsizer.Add(self.val1, flag=wx.RIGHT, border=5)
1596 ## Minimum distance
1597 distsizer = wx.BoxSizer(wx.VERTICAL)
1599 ttl_gpthr = wx.StaticText(self.panel, label='Minimum distance')
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)
1606 #####
1607 ## OKAY!
1608 oksizer = wx.BoxSizer(wx.HORIZONTAL)
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 )
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 ' '))
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)
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)
1635 self.panel.SetSizer(mainsizer)
1637 def createPanel_scipy(self):
1639 self.panel = wx.Panel(self)
1641 mainsizer = wx.BoxSizer(wx.VERTICAL)
1643 ## Regions
1644 rgnsizer = wx.BoxSizer(wx.VERTICAL)
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)
1651 ## Gap threshold
1652 gpthrsizer = wx.BoxSizer(wx.VERTICAL)
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)
1660 #####
1661 ## OKAY!
1662 oksizer = wx.BoxSizer(wx.HORIZONTAL)
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 )
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))]'))
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)
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)
1686 self.panel.SetSizer(mainsizer)
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):
1695 wx.Panel.__init__(self, parent)
1696 self.parent = parent
1697 self.owner = owner
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
1705 self.data_name = []
1706 self.xy_data = []
1707 self.xy_plot = []
1708 self.xy_scale = []
1709 self.idata = []
1711 self.cif_name = []
1712 self.cif_plot = []
1713 self.cif_all = []
1714 self.cif_scale = []
1715 self.icif = []
1717 # leftbox = wx.BoxSizer(wx.VERTICAL)
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)
1727 dattools = self.DataBox(self)
1728 # ciftools = self.CIFBox(self)
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)
1735 # tlbx = wx.StaticBox(self,label='PLOT TOOLBOX')
1736 xybox = wx.BoxSizer(wx.HORIZONTAL)
1738 xunits = [u'q (\u212B\u207B\u00B9)',u'2\u03B8 (\u00B0)',u'd (\u212B)']
1739 yscales = ['linear','log']
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)
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)
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)
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)
1763 self.SetSizer(panel)
1766 def onSAVEfig(self,event=None):
1767 self.plot1D.save_figure()
1769 def onPLOTset(self,event=None):
1770 self.plot1D.configure()
1772 def onRESETplot(self,event=None):
1773 self.plot1D.reset_config()
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)
1779 def OToolbox(self, panel):
1780 '''
1781 Frame for visual toolbox
1782 '''
1784 tlbx = wx.StaticBox(self,label='PLOT TOOLBOX')
1785 vbox = wx.StaticBoxSizer(tlbx, wx.VERTICAL)
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)
1794 self.ch_xaxis.Bind(wx.EVT_CHOICE, self.check1Daxis)
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)
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)
1807 self.ch_yaxis.Bind(wx.EVT_CHOICE, self.onLogLinear)
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)
1813 self.ch_xaxis.Disable()
1814 self.ch_yaxis.Disable()
1815 return vbox
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)
1823 xunits = [u'q (\u212B\u207B\u00B9)',u'2\u03B8 (\u00B0)',u'd (\u212B)']
1824 yscales = ['linear','log']
1826 self.ch_xaxis = Choice(self, choices=xunits, action=self.check1Daxis)
1827 self.ch_yaxis = Choice(self, choices=yscales, action=self.onLogLinear)
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
1837 def DataBox(self,panel):
1838 '''
1839 Frame for data toolbox
1840 '''
1842 tlbx = wx.StaticBox(self,label='DATA TOOLBOX')
1843 vbox = wx.StaticBoxSizer(tlbx,wx.VERTICAL)
1846 ###########################
1847 ## DATA CHOICE
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)
1853 ###########################
1854 # Energy display
1855 self.ttl_energy = wx.StaticText(self, label=('Energy:'))
1856 vbox.Add(self.ttl_energy, flag=wx.RIGHT, border=8)
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')
1865 self.val_scale.Bind(wx.EVT_TEXT_ENTER, self.normalize1Ddata)
1866 self.btn_reset.Bind(wx.EVT_BUTTON, self.reset1Dscale)
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)
1872 vbox.Add(hbox_scl, flag=wx.BOTTOM|wx.TOP, border=8)
1874 ## Disable until data
1875 self.btn_reset.Disable()
1876 self.val_scale.Disable()
1878 return vbox
1880 def CIFBox(self,panel):
1881 '''
1882 Frame for data toolbox
1883 '''
1885 tlbx = wx.StaticBox(self,label='CIF TOOLBOX')
1886 vbox = wx.StaticBoxSizer(tlbx,wx.VERTICAL)
1888 ###########################
1889 ## DATA CHOICE
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)
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)
1901 self.slctEorL.Bind(wx.EVT_CHOICE, self.onEorLSel)
1902 self.val_cifE.Bind(wx.EVT_TEXT_ENTER, self.onResetE)
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)
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')
1915 self.val_cifscale.Bind(wx.EVT_TEXT_ENTER, partial(self.normalize1Ddata,cif=True))
1916 self.btn_cifreset.Bind(wx.EVT_BUTTON, self.resetCIFscale)
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)
1922 vbox.Add(hbox_scl, flag=wx.BOTTOM|wx.TOP, border=8)
1924 ## Disable until data
1925 self.val_cifscale.Disable()
1926 self.btn_cifreset.Disable()
1927 self.slctEorL.Disable()
1928 self.val_cifE.Disable()
1930 return vbox
1937##############################################
1938#### XRD PLOTTING FUNCTIONS
1940 def addCIFdata(self,cif,newcif,datalabel):
1942 cif_no = len(self.cif_name)
1944 ## Add 'raw' data to array
1945 self.cif_plot.append(newcif)
1946 self.cif_all.append(cif)
1948 cifscale = np.max(self.cif_plot[-1][3])
1949 self.cif_scale.append(int(cifscale))
1951 self.cif_name.append(datalabel)
1953 ## Plot data (x,y)
1954 self.icif.append(len(self.plotlist))
1955 xi = self.ch_xaxis.GetSelection()
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))
1960 ## Use correct x-axis units
1961 self.check1Daxis()
1963 self.ch_cif.Set(self.cif_name)
1964 self.ch_cif.SetStringSelection(datalabel)
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)
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
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
1989 return [qall, twth, d, I]
1991 def onResetE(self,event=None):
1993 wavelength = lambda_from_E(self.getE())
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
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()
2011 def onEorLSel(self,event=None):
2013 try:
2014 current = float(self.val_cifE.GetValue())
2015 except:
2016 return
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
2025 self.val_cifE.SetValue(new)
2027 def optionsON(self,data=True,cif=False):
2029 self.ch_xaxis.Enable()
2030 self.ch_yaxis.Enable()
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()
2041 def add1Ddata(self,data1dxrd):
2043 try:
2044 len(data1dxrd.I)
2045 except:
2046 return
2048 self.xy_data.append(data1dxrd)
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
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))
2058 self.xy_plot.append(self.xy_data[-1].all_data())
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))
2067 ## Use correct x-axis units
2068 self.check1Daxis(yaxis=True)
2070 self.ch_data.Set(self.data_name)
2071 self.ch_data.SetStringSelection(datalabel)
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))
2079 def normalize1Ddata(self,event=None,cif=False):
2081 if cif:
2082 cif_no = self.ch_cif.GetSelection()
2083 y = self.cif_plot[cif_no][3]
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
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]
2100 self.plot1D.unzoom_all()
2101 self.rescale1Daxis(xaxis=False,yaxis=True)
2103 def onSELECT(self,event=None):
2105 data_str = self.ch_data.GetString(self.ch_data.GetSelection())
2107 plt_no = self.ch_data.GetSelection()
2108 self.val_scale.SetValue('%i' % self.xy_scale[plt_no])
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))
2113 def selectCIF(self,event=None):
2115 cif_str = self.ch_cif.GetString(self.ch_cif.GetSelection())
2117 cif_no = self.ch_cif.GetSelection()
2118 self.val_cifscale.SetValue('%i' % self.cif_scale[cif_no])
2120 def check1Daxis(self,event=None,yaxis=False):
2122 self.plot1D.unzoom_all()
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$)'
2134 self.rescale1Daxis(xaxis=True,yaxis=yaxis)
2136 def rescale1Daxis(self,xaxis=True,yaxis=False):
2138 xi = self.ch_xaxis.GetSelection()
2140 xmin,xmax,ymin,ymax = 0,10,0,10
2142 for i,plt_no in enumerate(self.icif):
2144 x = np.array(self.cif_plot[i][xi])
2145 y = np.array(self.cif_plot[i][3])
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)
2152 self.plot1D.update_line(plt_no,x,y)
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])
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)
2163 self.plot1D.update_line(plt_no,x,y)
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)
2169 def reset1Dscale(self,event=None):
2171 plt_no = self.ch_data.GetSelection()
2172 xi = self.ch_xaxis.GetSelection()
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])
2181 self.plot1D.canvas.draw()
2182 self.plot1D.unzoom_all()
2183 self.rescale1Daxis(xaxis=False,yaxis=True)
2186 def resetCIFscale(self,event=None):
2188 cif_no = self.ch_cif.GetSelection()
2189 xi = self.ch_xaxis.GetSelection()
2191 self.cif_scale[cif_no] = CIFSCALE
2192 self.val_cifscale.SetValue('%i' % self.cif_scale[cif_no])
2193 self.normalize1Ddata(cif=True)
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()
2201 self.rescale1Daxis(xaxis=False,yaxis=True)
2203 def set_xview(self, x1, x2):
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)
2214 x1 = max(xmin,x1)
2215 x2 = min(xmax,x2)
2217 self.plot1D.axes.set_xlim((x1, x2))
2218 self.plot1D.set_xlabel(self.xlabel)
2219 self.plot1D.canvas.draw()
2221 def set_yview(self, y1, y2):
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)
2231 y1 = max(ymin,y1)
2232 y2 = min(ymax,y2)
2234 self.plot1D.axes.set_ylim((y1, y2))
2235 self.plot1D.set_ylabel(self.ylabel)
2236 self.plot1D.canvas.draw()
2238 def abs_limits(self,xydata,axis=0):
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
2245 return mini,maxi
2247##############################################
2248#### XRD FILE OPENING/SAVING
2249 def load_file(self,event=None):
2251 loadXYfile(parent=self,xrdviewer=self)
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)
2260 path, save = None, False
2261 if dlg.ShowModal() == wx.ID_OK:
2262 save = True
2263 path = dlg.GetPath().replace('\\', '/')
2264 dlg.Destroy()
2266 if save:
2267 ## mkak 2016.11.16
2268 print('Not yet capable of saving data. Function yet to be written.')
2270 def select_CIF(self, event=None, cifscale=CIFSCALE):
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
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
2288 dlg = SelectCIFData(self, self.owner.cifdb,
2289 qmin=qmin, qmax=qmax, energy=energy)
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)
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)
2309 okay = True
2310 else: # except:
2311 print('ERROR: something failed while loading CIF')
2312 pass
2315 dlg.Destroy()
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)
2325 def getE(self):
2327 try:
2328 energy = float(self.val_cifE.GetValue())
2329 except:
2330 energy = None
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
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)
2356 return np.array([qall, twth_from_q(qall,wavelength), d_from_q(qall), Iall])
2360class SelectCIFData(wx.Dialog):
2361 def __init__(self, parent, cifdb, qmin=QMIN, qmax=QMAX,
2362 energy=ENERGY):
2364 self.cifdb = cifdb
2365 self.type = None
2366 self.path = None
2367 self.amcsd_id = None
2369 self.xaxis = 0
2371 """Constructor"""
2372 dialog = wx.Dialog.__init__(self, parent,
2373 title='Select CIF to plot', size=(450, 600))
2375 panel = wx.Panel(self)
2377 self.parent = parent
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)
2385 self.ch_EorL.Bind(wx.EVT_CHOICE, self.onEorLSel)
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)
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)
2399 self.ch_xaxis.Bind(wx.EVT_CHOICE, self.onXscaleSel)
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)
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')
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 )
2419 btn_fltr.Bind(wx.EVT_BUTTON, self.filter_database)
2420 btn_ld.Bind(wx.EVT_BUTTON, self.load_file)
2422 #####
2423 ## OKAY!
2424 okBtn = wx.Button(panel, wx.ID_OK )
2425 canBtn = wx.Button(panel, wx.ID_CANCEL )
2427 oksizer = wx.BoxSizer(wx.HORIZONTAL)
2428 oksizer.Add(canBtn, flag=wx.RIGHT, border=8)
2429 oksizer.Add(okBtn, flag=wx.RIGHT, border=8)
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)
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)
2456 panel.SetSizer(mainsizer)
2458 ix,iy = panel.GetBestSize()
2459 self.SetSize((ix+20, iy+50))
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)
2466 def returnLambda(self,event=None):
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()))
2473 def returnQ(self,event=None):
2475 val_min = float(self.val_xmin.GetValue())
2476 val_max = float(self.val_xmax.GetValue())
2477 wavelength = self.returnLambda()
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
2486 def onXscaleSel(self,event=None):
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
2498 wavelength = self.returnLambda()
2499 if self.ch_xaxis.GetSelection() != self.xaxis:
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()
2524 self.val_xmin.SetValue('%0.4f' % min(val_min,val_max))
2525 self.val_xmax.SetValue('%0.4f' % max(val_min,val_max))
2528 def onEorLSel(self,event=None):
2530 try:
2531 current = float(self.val_cifE.GetValue())
2532 except:
2533 return
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
2542 self.val_cifE.SetValue(new)
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)
2551 read = False
2552 if dlg.ShowModal() == wx.ID_OK:
2553 read = True
2554 self.path = dlg.GetPath().replace('\\', '/')
2555 dlg.Destroy()
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
2563 self.cif_list.SetSelection(0)
2565 def filter_database(self,event=None):
2566 # print(" filter database A")
2567 myDlg = XRDSearchGUI(self.cifdb, self.parent.owner.srch_cls)
2569 filter = False
2570 list_amcsd = None
2572 if myDlg.ShowModal() == wx.ID_OK:
2574 elem_include = myDlg.srch.elem_incl
2575 elem_exclude = myDlg.srch.elem_excl
2576 self.parent.owner.srch_cls = myDlg.srch
2578 if len(myDlg.AMCSD.GetValue()) > 0:
2579 myDlg.entrAMCSD()
2580 list_amcsd = []
2582 for id in myDlg.srch.amcsd:
2583 try:
2584 list_amcsd += [int(id)]
2585 except:
2586 pass
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, " < ")
2595 if myDlg.Author.GetValue() == '':
2596 auth_include = None
2597 else:
2598 auth_include = myDlg.Author.GetValue().split(',')
2600 filter = True
2601 myDlg.Destroy()
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]
2613 # print(" --> ", len(list_amcsd))
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)
2620 def returnMATCHES(self, list_amcsd):
2621 '''
2622 Populates Results Panel with list
2623 '''
2624 self.cif_list.Clear()
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)
2637 ## automatically selects first in list.
2638 self.cif_list.EnsureVisible(0)
2639 try:
2640 self.cif_list.SetSelection(0)
2641 except:
2642 pass
2644 amcsd_id = self.cif_list.GetString(self.cif_list.GetSelection())
2645 self.amcsd_id = int(amcsd_id.split()[1])
2646 self.type = 'database'
2649 def showCIF(self, event=None, **kws):
2651 if event is not None:
2652 self.amcsd_id = int(event.GetString().split()[1])
2653 self.type = 'database'
2654 self.path = None
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):
2663 wx.Panel.__init__(self, parent)
2665 self.parent = parent
2666 self.owner = owner
2668 ## Default information
2671 rangepanel = self.RangeTools()
2673 panel1D = wx.BoxSizer(wx.HORIZONTAL)
2674 panel1D.Add(rangepanel,flag=wx.ALL,border=10)
2675 self.SetSizer(panel1D)
2677 def RangeTools(self):
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)
2687 ###########################
2688 ## X-Scale
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)
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)
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)
2715 self.btn_rngreset = wx.Button(self,label='reset')
2716 self.btn_rngreset.Bind(wx.EVT_BUTTON, self.owner.onReset)
2718 hbox_xset.Add(self.btn_rngreset, flag=wx.RIGHT, border=8)
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)
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()
2731 return vbox_rng
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):
2741 wx.Panel.__init__(self, parent)
2743 self.parent = parent
2744 self.owner = owner
2746 ## Default information
2750 bkgdpanel = self.BackgroundTools()
2752 panel1D = wx.BoxSizer(wx.HORIZONTAL)
2753 panel1D.Add(bkgdpanel,flag=wx.ALL,border=10)
2754 self.SetSizer(panel1D)
2756 def BackgroundTools(self):
2758 ###########################
2759 ## Background tools
2760 vbox_bkgd = wx.BoxSizer(wx.VERTICAL)
2761 hbox_bkgd = wx.BoxSizer(wx.HORIZONTAL)
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)
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)
2771 self.btn_rbkgd = wx.Button(self,label='Remove')
2772 self.btn_rbkgd.Bind(wx.EVT_BUTTON, self.owner.onRmvBkgd)
2774 vbox_bkgd.Add(hbox_bkgd, flag=wx.BOTTOM, border=8)
2775 vbox_bkgd.Add(self.btn_rbkgd, flag=wx.BOTTOM, border=8)
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)
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()
2787 return vbox_bkgd
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):
2797 wx.Panel.__init__(self, parent)
2799 self.parent = parent
2800 self.owner = owner
2802 ## Default information
2805 pkspanel = self.PeakTools()
2807 panel1D = wx.BoxSizer(wx.HORIZONTAL)
2808 panel1D.Add(pkspanel,flag=wx.ALL,border=10)
2809 self.SetSizer(panel1D)
2811 def PeakTools(self):
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)
2822 ## Fit type
2823 ttl_fit = wx.StaticText(self, label='Fit type')
2824 self.ch_pkfit = wx.Choice(self,choices=SRCH_MTHDS)
2826 hbox0_pks.Add(ttl_fit, flag=wx.RIGHT, border=5)
2827 hbox0_pks.Add(self.ch_pkfit, flag=wx.RIGHT, border=5)
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)
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)
2837 intthrsizer = wx.BoxSizer(wx.VERTICAL)
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)
2845 self.owner.peaklistbox = EditableListBox(self, self.owner.select_peak,
2846 remove_action=self.owner.rm_sel_peaks,
2847 size=(250, -1))
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)
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)
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)
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)
2868 self.val_intthr.SetValue(str(self.owner.intthrsh))
2869 self.ch_pkfit.SetSelection(0)
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()
2878 return vbox_pks
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):
2887 wx.Panel.__init__(self, parent)
2889 self.parent = parent
2890 self.owner = owner
2892 matchpanel = self.SearchMatchTools()
2893# refpanel = self.RefinementTools()
2894 respanel = self.ResultsTools()
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)
2901 def SearchMatchTools(self):
2902 hbox = wx.BoxSizer(wx.HORIZONTAL)
2904 self.btn_mtch = wx.Button(self,label='Search by peaks')
2905 btn_srch = wx.Button(self,label='Filter database')
2907 self.btn_mtch.Bind(wx.EVT_BUTTON, self.owner.onMatch)
2908 btn_srch.Bind(wx.EVT_BUTTON, self.owner.filter_database)
2910 hbox.Add(self.btn_mtch, flag=wx.BOTTOM|wx.RIGHT, border=8)
2911 hbox.Add(btn_srch, flag=wx.BOTTOM, border=8)
2913 ## until peaks are available to search
2914 self.btn_mtch.Disable()
2916 return hbox
2918 def ResultsTools(self):
2920 vbox = wx.BoxSizer(wx.VERTICAL)
2921 hbox = wx.BoxSizer(wx.HORIZONTAL)
2923 self.amcsdlistbox = EditableListBox(self, self.owner.displayCIFpeaks, size=(200,120))
2925 self.txt_geometry = [ wx.StaticText(self, label=''),
2926 wx.StaticText(self, label=''),
2927 wx.StaticText(self, label=''),
2928 wx.StaticText(self, label='')]
2930 self.btn_shw = wx.Button(self,label='View CIF text')
2931 self.btn_shw.Bind(wx.EVT_BUTTON, self.displayCIF)
2933 self.btn_clr = wx.Button(self,label='Clear list')
2934 self.btn_clr.Bind(wx.EVT_BUTTON, self.owner.clearMATCHES)
2936 hbox.Add(self.btn_shw, flag=wx.BOTTOM|wx.RIGHT, border=8)
2937 hbox.Add(self.btn_clr, flag=wx.BOTTOM, border=8)
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)
2947 self.btn_clr.Disable()
2948 self.btn_shw.Disable()
2950 return vbox
2952 def displayCIF(self,event=None):
2954 title = self.amcsdlistbox.GetStringSelection()
2955 amcsd = self.amcsdlistbox.GetStringSelection().split()[0]
2957 self.owner.cifframe += [CIFFrame(amcsd=int(amcsd), title=title,
2958 cifdb=self.owner.owner.cifdb)]
2961class CIFPanel(wx.Panel):
2963 def __init__(self, parent,cifdb=None,amcsd=100):
2964 wx.Panel.__init__(self, parent)
2966 cif_text_box = wx.TextCtrl(self, style=wx.TE_MULTILINE|wx.HSCROLL)
2968 sizer = wx.BoxSizer(wx.VERTICAL)
2969 sizer.Add(cif_text_box, 1, wx.ALL|wx.EXPAND)
2971 self.SetSizer(sizer)
2973 if cifdb is None:
2974 cifdb = cifDB(dbname='%s/.larch/cif_amcsd.db' % expanduser('~'))
2976 cif_text_box.SetValue(cifdb.cif_by_amcsd(amcsd))
2979class CIFFrame(wx.Frame):
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)
2985 panel = CIFPanel(self, cifdb=cifdb, amcsd=amcsd)
2987 self.Show()
2989 def closeFrame(self, event=None):
2991 try:
2992 self.Destroy()
2993 except:
2994 pass
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):
3005 wx.Panel.__init__(self, parent)
3007 self.parent = parent
3008 self.owner = owner
3010 instrpanel = self.InstrumentTools()
3012 panel1D = wx.BoxSizer(wx.HORIZONTAL)
3013 panel1D.Add(instrpanel,flag=wx.ALL,border=10)
3014 self.SetSizer(panel1D)
3016 def InstrumentTools(self):
3018 vbox = wx.BoxSizer(wx.VERTICAL)
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)
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')
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)
3042 self.btn_clrinst = wx.Button(self,label='Clear')
3043 self.btn_clrsize = wx.Button(self,label='Clear')
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)
3050 self.btn_clrinst.Bind(wx.EVT_BUTTON, self.owner.onClrInstr)
3051 self.btn_clrsize.Bind(wx.EVT_BUTTON, self.owner.onClrSize)
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)
3058 hbox_u.Add(ttl_u, flag=wx.RIGHT, border=8)
3059 hbox_u.Add(self.val_u, flag=wx.RIGHT, border=8)
3061 hbox_v.Add(ttl_v, flag=wx.RIGHT, border=8)
3062 hbox_v.Add(self.val_v, flag=wx.RIGHT, border=8)
3064 hbox_w.Add(ttl_w, flag=wx.RIGHT, border=8)
3065 hbox_w.Add(self.val_w, flag=wx.RIGHT, border=8)
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)
3072 hbox_D.Add(ttl_D, flag=wx.RIGHT, border=8)
3073 hbox_D.Add(self.val_D, flag=wx.RIGHT, border=8)
3075 hbox_hw.Add(ttl_hw, flag=wx.RIGHT, border=5)
3076 hbox_hw.Add(self.val_hw, flag=wx.RIGHT, border=5)
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)
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))
3094 self.val_u.Disable()
3095 self.val_v.Disable()
3096 self.val_w.Disable()
3097 self.val_D.Disable()
3099 self.btn_clrinst.Disable()
3100 self.btn_clrsize.Disable()
3103 return vbox
3105class ResultsPanel(wx.Panel):
3106 '''
3107 Panel for ....
3108 '''
3109 label='Results'
3110 def __init__(self,parent,owner=None,_larch=None):
3112 wx.Panel.__init__(self, parent)
3114 self.parent = parent
3115 self.owner = owner
3117 ## Default information
3118# respanel = self.ResultsTools()
3120 panel1D = wx.BoxSizer(wx.HORIZONTAL)
3121# panel1D.Add(respanel,flag=wx.ALL,border=10)
3122 self.SetSizer(panel1D)
3124# def ResultsTools(self):
3125#
3126# vbox = wx.BoxSizer(wx.VERTICAL)
3127#
3128# return vbox
3130##### Pop-up from 2D XRD Viewer to calculate 1D pattern
3131class Calc1DPopup(wx.Dialog):
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
3141 self.createPanel()
3143 ## Set defaults
3144 self.setDefaults()
3146 ix,iy = self.panel.GetBestSize()
3147 self.SetSize((ix+50, iy+50))
3150 def createPanel(self):
3152 self.panel = wx.Panel(self)
3154 mainsizer = wx.BoxSizer(wx.VERTICAL)
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)
3163 wedgesizer.Add(ttl_wedges,flag=wx.BOTTOM,border=8)
3164 wedgesizer.Add(wsizer,flag=wx.BOTTOM,border=8)
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)
3177 ## Plot/save
3179 self.ch_save = wx.CheckBox(self.panel, label = 'Save 1D?')
3180 self.ch_plot = wx.CheckBox(self.panel, label = 'Plot 1D?')
3182 self.save_choice = wx.Choice(self.panel, choices=[u'q (\u212B\u207B\u00B9)',u'2\u03B8 (\u00B0)'])
3184 self.ch_save.Bind(wx.EVT_CHECKBOX, self.onCHECK)
3185 self.ch_plot.Bind(wx.EVT_CHECKBOX, self.onCHECK)
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)
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)
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 )
3201 oksizer.Add(canBtn, flag=wx.RIGHT, border=8)
3202 oksizer.Add(self.okBtn, flag=wx.RIGHT, border=8)
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)
3212 self.panel.SetSizer(mainsizer)
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()
3221 def setDefaults(self):
3223 self.xstep.SetValue(str(5001))
3224 self.wedges.SetValue(1)
3225 self.wedges.SetRange(1,36)
3226 self.save_choice.SetSelection(1)
3228 self.okBtn.Disable()
3230 def onSPIN(self,event=None):
3231 self.wedges.SetValue(str(event.GetPosition()))
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 '''
3239 #----------------------------------------------------------------------
3240 def __init__(self, parent):
3242 wx.Dialog.__init__(self, parent, title='Database Information')
3243 ## remember: size=(width,height)
3244 self.parent = parent
3245 self.panel = wx.Panel(self)
3247 sizer = wx.BoxSizer(wx.VERTICAL)
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 : ')
3253 ## Database buttons
3254 db_sizer = wx.BoxSizer(wx.HORIZONTAL)
3256 dbBtn = wx.Button(self.panel, label='Load new database' )
3257 rstBtn = wx.Button(self.panel, label='Reset to default database')
3259 dbBtn.Bind(wx.EVT_BUTTON, self.onNewFile )
3260 rstBtn.Bind(wx.EVT_BUTTON, self.onResetFile )
3262 db_sizer.Add(dbBtn, flag=wx.RIGHT, border=10)
3263 db_sizer.Add(rstBtn, flag=wx.RIGHT, border=10)
3265 ## Okay, etc. buttons
3266 ok_sizer = wx.BoxSizer(wx.HORIZONTAL)
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 )
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)
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)
3283 self.onUpdateText()
3285 def onNewFile(self,event=None):
3287 path = self.parent.open_database()
3288 self.onUpdateText()
3290 def onResetFile(self,event=None):
3292 self.parent.owner.openDB()
3293 self.onUpdateText()
3295 def onUpdateText(self,event=None):
3297 try:
3298 filename = self.parent.owner.cifdb.dbname
3299 except:
3300 return
3301 nocif = self.parent.owner.cifdb.cifcount()
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)
3309 ix,iy = self.panel.GetBestSize()
3310 self.SetSize((ix+40, iy+40))
3311 self.Show()
3313#########################################################################
3314class XRDSearchGUI(wx.Dialog):
3316 def __init__(self, database, srch_cls):
3318 wx.Dialog.__init__(self, None, title='Crystal Structure Database Search')
3319 ## remember: size=(width,height)
3320 self.cifdb = database
3322 self.panel = wx.Panel(self)
3324 sizer = wx.BoxSizer(wx.VERTICAL)
3325 grd_sizer = wx.GridBagSizer( 5, 6)
3326 ok_sizer = wx.BoxSizer(wx.HORIZONTAL)
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))
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)
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...')
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...')
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...')
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))
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)
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 )
3367 ## Bind buttons for functionality
3368 self.rstBtn.Bind(wx.EVT_BUTTON, self.onReset )
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 )
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 )
3382 grd_sizer.Add(lbl_Mineral, pos = ( 1,1) )
3383 grd_sizer.Add(self.Mineral, pos = ( 1,2), span = (1,3) )
3385 grd_sizer.Add(lbl_AMCSD, pos = ( 2,1) )
3386 grd_sizer.Add(self.AMCSD, pos = ( 2,2), span = (1,3) )
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) )
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) )
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) )
3400 grd_sizer.Add(lbl_Category, pos = ( 6,1) )
3401 grd_sizer.Add(self.Category, pos = ( 6,2), span = (1,3) )
3403 grd_sizer.Add(lbl_Keyword, pos = ( 7,1) )
3404 grd_sizer.Add(self.Keyword, pos = ( 7,2), span = (1,3) )
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)
3411 sizer.Add(grd_sizer)
3412 sizer.AddSpacer(15)
3413 sizer.Add(ok_sizer)
3414 self.panel.SetSizer(sizer)
3416 ## No categories are specified yet in database
3417 ## mkak 2017.05.19
3418 lbl_Category.Disable()
3419 self.Category.Disable()
3421 ix,iy = self.panel.GetBestSize()
3422 self.SetSize((ix+40, iy+40))
3424 self.Show()
3426 self.srch = SearchCIFdb() if srch_cls is None else srch_cls
3427 self.setValues()
3430#########################################################################
3432 def setValues(self):
3434 key = 'authors'
3435 self.Author.SetValue(self.srch.show_parameter(key=key))
3437 self.Symmetry.SetValue(self.srch.show_geometry())
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))
3444 key = 'keywords'
3445 self.Keyword.SetValue(self.srch.show_parameter(key=key))
3447 key = 'amcsd'
3448 self.AMCSD.SetValue(self.srch.show_parameter(key=key))
3450 if len(np.shape(self.srch.mnrlname)) > 0:
3451 self.srch.mnrlname = self.srch.mnrlname[0]
3452 self.Mineral.SetStringSelection(self.srch.mnrlname)
3454 self.Chemistry.SetValue(self.srch.show_chemistry())
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))
3462 def entrSymmetry(self,event=None):
3463 self.srch.read_geometry(str(self.Symmetry.GetValue()))
3464 self.Symmetry.SetValue(self.srch.show_geometry())
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))
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))
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))
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)
3490 def entrChemistry(self,event=None):
3491 self.srch.read_chemistry(self.Chemistry.GetValue())
3492 self.Chemistry.SetValue(self.srch.show_chemistry())
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 = []
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()
3546 if update:
3547 self.srch.elem_incl = incl
3548 self.srch.elem_excl = excl
3549 self.Chemistry.SetValue(self.srch.show_chemistry())
3552 def onAuthor(self,event=None):
3553 authorlist = self.cifdb.return_author_names()
3554 dlg = AuthorListTable(self,authorlist,include=self.srch.authors)
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()
3565 if update:
3566 self.srch.authors = incl
3567 self.Author.SetValue(self.srch.show_parameter(key='authors'))
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()
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)
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'
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'
3598 self.srch.sg = vals[12]
3600 self.Symmetry.SetValue(self.srch.show_geometry())
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__()
3615#########################################################################
3616class PeriodicTableSearch(wx.Dialog):
3618 def __init__(self, parent,include=[],exclude=[]):
3620 wx.Dialog.__init__(self, parent, wx.ID_ANY, title='Periodic Table of Elements')
3622 panel = wx.Panel(self)
3623 self.ptable = PeriodicTablePanel(panel,title='Select Element(s)',
3624 onselect=self.onSelectElement,
3625 highlight=True)
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 )
3632 ## Bind buttons for functionality
3633 exBtn.Bind(wx.EVT_BUTTON, self.onExclude )
3634 rstBtn.Bind(wx.EVT_BUTTON, self.onClear )
3636 main_sizer = wx.BoxSizer(wx.VERTICAL)
3638 main_sizer.Add(self.ptable, flag=wx.ALL, border=20)
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)
3646 main_sizer.Add(btn_sizer, flag=wx.ALL, border=20)
3648 pack(panel, main_sizer)
3650 ix,iy = panel.GetBestSize()
3651 self.SetSize((ix+20, iy+50))
3653 self.element_include = include
3654 self.element_exclude = exclude
3655 self.setDefault()
3658 self.cnt_elem = len(self.ptable.syms)
3660 def setDefault(self):
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)
3676 #self.ptable.onexclude(selected=self.element_include)
3678 def onSelectElement(self,elem=None, event=None):
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)
3690 def onClear(self,event=None):
3692 self.element_include = []
3693 self.element_exclude = []
3694 self.ptable.onclear()
3696 def onExclude(self,event=None):
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)
3703#########################################################################
3704class AuthorListTable(wx.Dialog):
3705 """"""
3707 def __init__(self,parent,authorlist,include=[]):
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
3716 sizer = wx.BoxSizer(wx.VERTICAL)
3717 ok_sizer = wx.BoxSizer(wx.HORIZONTAL)
3719 self.authlist = wx.ListBox(self.panel, size=(170, 130), style= wx.LB_MULTIPLE)
3720 self.authlist.Set(self.list)
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 )
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)
3735 sizer.Add(self.authlist)
3736 sizer.AddSpacer(15)
3737 sizer.Add(ok_sizer)
3738 self.panel.SetSizer(sizer)
3740 ix,iy = self.panel.GetBestSize()
3741 self.SetSize((ix+40, iy+40))
3743 self.Show()
3744 self.onSet()
3746 def onReset(self,event=None):
3748 for i,n in enumerate(self.list):
3749 self.authlist.Deselect(i)
3752 def onSet(self,event=None):
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)
3762#########################################################################
3763class XRDSymmetrySearch(wx.Dialog):
3764 '''
3765 GUI interface for specifying lattice parameters
3766 '''
3768 def __init__(self,parent,search=None):
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)
3775 sizer = wx.BoxSizer(wx.VERTICAL)
3776 grd_sizer = wx.GridBagSizer( 5, 6)
3777 ok_sizer = wx.BoxSizer(wx.HORIZONTAL)
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 )
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 )
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 )
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 )
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 )
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 )
3804 SG_list = ['']
3805 for sgno in np.arange(230):
3806 SG_list.append('%3d' % (sgno+1))
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)]
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)
3818 self.HMsg.Bind(wx.EVT_CHOICE, self.onSpaceGroup)
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 )
3826 ## Bind buttons for functionality
3827 self.rstBtn.Bind(wx.EVT_BUTTON, self.onReset )
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) )
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) )
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) )
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) )
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) )
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) )
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) )
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)
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)
3876 sizer.Add(grd_sizer)
3877 sizer.AddSpacer(15)
3878 sizer.Add(ok_sizer)
3879 self.panel.SetSizer(sizer)
3881 ix,iy = self.panel.GetBestSize()
3882 self.SetSize((ix+40, iy+40))
3884 self.Show()
3886 if search is not None:
3887 self.srch = search
3888 self.SetSearch()
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)
3907 def SetSearch(self):
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))
3936 def onSpaceGroup(self,event=None):
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)
3945 def formatFloat(self,event):
3946 event.GetEventObject().SetValue('%0.3f' % float(event.GetString()))
3948class XRD1DViewer(LarchWxApp):
3949 def __init__(self, **kws):
3950 LarchWxApp.__init__(self)
3952 def createApp(self):
3953 frame = XRD1DViewerFrame()
3954 frame.Show()
3955 self.SetTopWindow(frame)
3956 return True
3958if __name__ == '__main__':
3959 XRD1DViewer().MainLoop()