Coverage for /Users/Newville/Codes/xraylarch/larch/wxxrd/XRD2Dviewer.py: 11%

899 statements  

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

1#!/usr/bin/env pythonw 

2''' 

3GUI for displaying 2D XRD images 

4 

5''' 

6import os 

7import numpy as np 

8 

9import matplotlib.cm as colormap 

10from functools import partial 

11 

12import h5py 

13 

14import wx 

15try: 

16 from wx._core import PyDeadObjectError 

17except: 

18 PyDeadObjectError = Exception 

19 

20from wxmplot import PlotPanel 

21from wxmplot.imagepanel import ImagePanel 

22from wxutils import MenuItem 

23from wxmplot.imageconf import ImageConfig,ColorMap_List 

24 

25# import matplotlib.pyplot as plt 

26 

27import larch 

28from larch import Group 

29from larch.larchlib import read_workdir, save_workdir 

30from larch.utils.strutils import bytes2str 

31from larch.utils import get_cwd 

32from larch.wxlib import LarchWxApp 

33from larch.io import tifffile, nativepath 

34from larch.xrd import (integrate_xrd,E_from_lambda,xrd1d,read_lambda, 

35 calc_cake,twth_from_q,twth_from_d, 

36 return_ai,twth_from_xy,q_from_xy,eta_from_xy) 

37from .XRDCalibrationFrame import CalibrationPopup 

38from .XRDMaskFrame import MaskToolsPopup 

39from .XRD1Dviewer import Calc1DPopup 

40 

41################################### 

42 

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

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

45PIXELS = 1024 #2048 

46 

47QSTPS = 5000 

48 

49XLABEL = ['q','2th','d'] 

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

51 

52################################### 

53 

54class diFFit2DPanel(wx.Panel): 

55 ''' 

56 Panel for housing 2D XRD Image 

57 ''' 

58 label='2D XRD' 

59 def __init__(self,parent,type='2D image',owner=None,_larch=None,size=(500, 500)): 

60 

61 wx.Panel.__init__(self, parent) 

62 self.owner = owner 

63 self.type = type 

64 self.ai = None 

65 self.on_calibration() 

66 

67 vbox = wx.BoxSizer(wx.VERTICAL) 

68 self.plot2D = ImagePanel(self,size=size,messenger=self.owner.write_message) 

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

70 self.SetSizer(vbox) 

71 

72 self.plot2D.cursor_callback = self.on_cursor 

73 

74 

75 def on_calibration(self): 

76 

77 if self.owner.calfile is not None and os.path.exists(self.owner.calfile): 

78 self.ai = return_ai(self.owner.calfile) 

79 

80 self.ai.detector.shape = np.shape(self.owner.plt_img) 

81 

82 fit2d_param = self.ai.getFit2D() 

83 self.center = (fit2d_param['centerX'],fit2d_param['centerY']) 

84 

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

86 

87 if self.ai is not None: 

88 if self.type == 'cake': 

89 self.owner.twth = self.plot2D.xdata[int(x)] 

90 

91 self.owner.xrd2Dcake.plot_line(x=x) 

92 self.owner.xrd2Dviewer.plot_ring() 

93 else: 

94 self.owner.twth = twth_from_xy(x,y,ai=self.ai) 

95 

96 self.owner.xrd2Dviewer.plot_ring(x=x,y=y) 

97 self.owner.xrd2Dcake.plot_line() 

98 else: 

99 return 

100 

101 self.owner.xrd1Dviewer.plot_line() 

102 

103 def plot_line(self,x=None): 

104 

105 if x is None: x = np.abs(self.plot2D.xdata-self.owner.twth).argmin() 

106 

107 try: 

108 self.xrd_line.remove() 

109 except: 

110 pass 

111 

112 self.xrd_line = self.plot2D.axes.axvline(x=x, color='r', linewidth=1) 

113 self.plot2D.canvas.draw() 

114 

115 def plot_ring(self,x=None,y=None): 

116 import matplotlib.pyplot as plt 

117 if x is not None and y is not None: 

118 radius = np.sqrt((x-self.center[0])**2+(y-self.center[1])**2) 

119 else: 

120 radius = self.ai._dist * np.tan(np.radians(self.owner.twth)) 

121 radius = radius / self.ai.detector.pixel1 

122 xrd_ring = plt.Circle(self.center, radius, color='red', fill=False) 

123 

124 try: 

125 self.xrd_ring.remove() 

126 except: 

127 pass 

128 

129 self.xrd_ring = self.plot2D.axes.add_artist(xrd_ring) 

130 self.plot2D.canvas.draw() 

131 

132class diFFit1DPanel(wx.Panel): 

133 ''' 

134 Panel for housing 1D XRD 

135 ''' 

136 def __init__(self,parent,owner=None,_larch=None,size=(500, 100)): 

137 

138 wx.Panel.__init__(self, parent) 

139 self.owner = owner 

140 

141 vbox = wx.BoxSizer(wx.VERTICAL) 

142 self.plot1D = PlotPanel(self,size=size,messenger=self.owner.write_message) 

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

144 self.SetSizer(vbox) 

145 

146 self.plot1D.cursor_callback = self.on_cursor 

147 

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

149 

150 xi = self.owner.xaxis_type.GetSelection() 

151 if xi == 1: 

152 self.owner.twth = x 

153 else: 

154 ix = np.abs(self.owner.data1dxrd[1]-self.owner.twth).argmin() 

155 self.owner.twth = self.owner.data1dxrd[1][ix] 

156 

157 self.owner.xrd1Dviewer.plot_line(x=x) 

158 self.owner.xrd2Dviewer.plot_ring() 

159 self.owner.xrd2Dcake.plot_line() 

160 

161 def plot_line(self,x=None): 

162 

163 if x is None: 

164 xi = self.owner.xaxis_type.GetSelection() 

165 if xi != 1: 

166 ix = np.abs(self.owner.data1dxrd[1]-self.owner.twth).argmin() 

167 x = self.owner.data1dxrd[xi][ix] 

168 else: 

169 x = self.owner.twth 

170 

171 try: 

172 self.xrd_line.remove() 

173 except: 

174 pass 

175 

176 self.xrd_line = self.plot1D.axes.axvline(x=x, color='r', linewidth=1) 

177 self.plot1D.draw() 

178 

179 

180 

181class XRD2DViewerFrame(wx.Frame): 

182 ''' 

183 Frame for housing all 2D XRD viewer widgets 

184 ''' 

185 def __init__(self, _larch=None, xrd1Dviewer=None, ponifile=None, flip='vertical', 

186 *args, **kw): 

187 

188 screenSize = wx.DisplaySize() 

189 x,y = 1000,720 #1000,760 

190 if x > screenSize[0] * 0.9: 

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

192 y = int(x*0.6) 

193 

194 label = 'diFFit : 2D XRD Data Analysis Software' 

195 wx.Frame.__init__(self, None,title=label, size=(x,y)) 

196 

197 self.SetMinSize((700,500)) 

198 

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

200 

201 self.open_image = [] 

202 self.open_scale = [] 

203 

204 ## Default image information 

205 self.raw_img = np.zeros((PIXELS,PIXELS)) 

206 self.flp_img = np.zeros((PIXELS,PIXELS)) 

207 self.plt_img = np.zeros((PIXELS,PIXELS)) 

208 self.cake = None 

209 self.twth = None 

210 

211 self.calfile = ponifile 

212 

213 self.msk_img = np.ones((PIXELS,PIXELS)) 

214 self.bkgd_img = np.zeros((PIXELS,PIXELS)) 

215 

216 self.bkgd_scale = 0 

217 self.bkgdMAX = 2 

218 

219 self.use_mask = False 

220 self.use_bkgd = False 

221 

222 self.xrddisplay1D = xrd1Dviewer 

223 

224 self.xrd1Dviewer = None 

225 self.xrd2Dcake = None 

226 

227 self.color = 'bone' 

228 self.flip = flip 

229 

230 read_workdir('gsemap.dat') 

231 

232 self.XRD2DMenuBar() 

233 self.Panel2DViewer() 

234 

235 self.Centre() 

236 self.Show() 

237 

238 if ponifile is None: 

239 self.btn_integ.Disable() 

240 else: 

241 self.btn_integ.Enable() 

242 

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

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

245 self.SetStatusText(s, panel) 

246 

247 def optionsON(self): 

248 

249 if len(self.open_image) > 0: 

250 

251 self.ch_clr.Enable() 

252 self.sldr_cntrst.Enable() 

253 self.entr_min.Enable() 

254 self.entr_max.Enable() 

255 self.btn_ct1.Enable() 

256 self.ch_flp.Enable() 

257 self.ch_scl.Enable() 

258 self.btn_mask.Enable() 

259 self.btn_bkgd.Enable() 

260 

261 img_no = self.ch_img.GetSelection() 

262 if self.open_image[img_no].iframes > 1: 

263 self.hrz_frm_sldr.Enable() 

264 self.hrz_frm_sldr.SetRange(0, int(self.open_image[img_no].iframes-1)) 

265 self.hrz_frm_sldr.SetValue(int(self.open_image[img_no].i)) 

266 for btn in self.hrz_frm_btn: btn.Enable() 

267 else: 

268 self.hrz_frm_sldr.Disable() 

269 self.hrz_frm_sldr.SetRange(0,0) 

270 self.hrz_frm_sldr.SetValue(0) 

271 for btn in self.hrz_frm_btn: btn.Disable() 

272 

273 if self.open_image[img_no].jframes > 1: 

274 self.vrt_frm_sldr.Enable() 

275 self.vrt_frm_sldr.SetRange(0,int(self.open_image[img_no].jframes-1)) 

276 self.vrt_frm_sldr.SetValue(int(self.open_image[img_no].j)) 

277 for btn in self.vrt_frm_btn: btn.Enable() 

278 else: 

279 self.vrt_frm_sldr.Disable() 

280 self.vrt_frm_sldr.SetRange(0,0) 

281 self.vrt_frm_sldr.SetValue(0) 

282 for btn in self.vrt_frm_btn: btn.Disable() 

283 

284############################################## 

285#### OPENING AND DISPLAYING IMAGES 

286 

287 def loadIMAGE(self,event=None): 

288 wildcards = '2DXRD image files (*.*)|*.*|All files (*.*)|*.*' 

289 dlg = wx.FileDialog(self, message='Choose 2D XRD image', 

290 defaultDir=get_cwd(), 

291 wildcard=wildcards, style=wx.FD_OPEN) 

292 

293 path, read = '', False 

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

295 read = True 

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

297 dlg.Destroy() 

298 

299 if read: 

300 print('\nReading XRD image file: %s' % path) 

301 

302 image,xrmfile = None,None 

303 try: 

304 xrmfile = h5py.File(path, 'r') 

305 except IOError: 

306 try: 

307 from larch.io import read_xrd_netcdf 

308 image = read_xrd_netcdf(path) 

309 except TypeError: 

310 try: 

311 image = tifffile.imread(path) 

312 except ValueError: 

313 print('Could not read file.') 

314 return 

315 

316 iname = os.path.split(path)[-1] 

317 self.plot2Dxrd(iname, image, path=path, h5file=xrmfile) 

318 

319 def close2Dxrd(self,event=None): 

320 

321 img_no = self.ch_img.GetSelection() 

322 try: 

323 print('Closing XRD image file: %s' % self.open_image[img_no].path) 

324 try: 

325 self.open_image[img_no].h5file.close() 

326 except: 

327 pass 

328 del self.open_image[img_no] 

329 except: 

330 pass 

331 

332 self.ch_img.Set([image.label for image in self.open_image]) 

333 if len(self.open_image) > 0: 

334 self.ch_img.SetSelection(0) 

335 self.selectIMAGE() 

336 else: 

337 self.clearIMAGE() 

338 

339 

340 def plot2Dxrd(self,iname,image,path='',h5file=None): 

341 

342 self.write_message('Displaying image: %s' % iname, panel=0) 

343 

344 try: 

345 new_img = XRDImg(label=iname, path=path, image=image, h5file=h5file) 

346 except: 

347 fail_msg = 'Image failed to load.' 

348 self.write_message(fail_msg, panel=0) 

349 print (fail_msg) 

350 return 

351 

352 self.open_image.append(new_img) 

353 

354 if self.open_image[-1].calfile is not None: 

355 if os.path.exists(self.open_image[-1].calfile): 

356 self.calfile = self.open_image[-1].calfile 

357 self.xrd2Dviewer.on_calibration() 

358 

359 

360 self.ch_img.Set([image.label for image in self.open_image]) 

361 self.ch_img.SetStringSelection(iname) 

362 

363 self.raw_img = self.open_image[-1].get_image() 

364 self.twth = None 

365 self.displayIMAGE(auto_contrast=True,unzoom=True) 

366 

367 if self.open_image[-1].iframes > 1: 

368 self.hrz_frm_sldr.SetRange(0,(self.open_image[-1].iframes-1)) 

369 self.hrz_frm_sldr.SetValue(int(self.open_image[-1].i)) 

370 else: 

371 self.hrz_frm_sldr.Disable() 

372 for btn in self.hrz_frm_btn: btn.Disable() 

373 

374 if self.open_image[-1].jframes > 1: 

375 self.vrt_frm_sldr.SetRange(0,(self.open_image[-1].jframes-1)) 

376 self.vrt_frm_sldr.SetValue(int(self.open_image[-1].j)) 

377 else: 

378 self.vrt_frm_sldr.Disable() 

379 for btn in self.vrt_frm_btn: btn.Disable() 

380 

381 

382 def changeFRAME(self,flag='hslider',event=None): 

383 

384 img_no = self.ch_img.GetSelection() 

385 if self.open_image[img_no].iframes > 1 or self.open_image[img_no].jframes > 1: 

386 i,j = self.open_image[img_no].i,self.open_image[img_no].j 

387 if flag=='next': i = i + 1 

388 elif flag=='previous': i = i - 1 

389 elif flag=='hslider': i = self.hrz_frm_sldr.GetValue() 

390 elif flag=='up': j = j + 1 

391 elif flag=='down': j = j - 1 

392 elif flag=='vslider': j = self.vrt_frm_sldr.GetValue() 

393 

394 if i < 0: i = self.open_image[img_no].iframes + i 

395 if j < 0: j = self.open_image[img_no].jframes + j 

396 if i > self.open_image[img_no].iframes: i = i - self.open_image[img_no].iframes 

397 if j > self.open_image[img_no].jframes: j = j - self.open_image[img_no].jframes 

398 

399 self.raw_img = self.open_image[img_no].get_image(i=i,j=j) 

400 

401 self.hrz_frm_sldr.SetValue(i) 

402 self.vrt_frm_sldr.SetValue(j) 

403 self.displayIMAGE(auto_contrast=False,unzoom=False)#unzoom=True) 

404 

405 def clearIMAGE(self): 

406 

407 try: 

408 self.xrd2Dviewer.plot2D.clear() 

409 self.xrd2Dviewer.plot2D.redraw() 

410 except: 

411 pass 

412 

413 def displayIMAGE(self,auto_contrast=True,unzoom=False): 

414 

415 self.flipIMAGE() 

416 self.checkIMAGE() 

417 self.calcIMAGE() 

418 

419 if unzoom: 

420 self.xrd2Dviewer.plot2D.display(self.plt_img,unzoom=unzoom) 

421 else: 

422 self.xrd2Dviewer.plot2D.conf.data = self.plt_img 

423 self.xrd2Dviewer.plot2D.redraw() 

424 self.display1DXRD() 

425 

426 if auto_contrast: self.setContrast(auto_contrast=True) 

427 

428 self.txt_ct2.SetLabel('[ image range: %i to %i ]' % 

429 (np.min(self.plt_img),np.max(self.plt_img))) 

430 

431 self.optionsON() 

432 self.xrd2Dviewer.plot2D.redraw() 

433 

434 def redrawIMAGE(self,unzoom=False): 

435 

436 self.flipIMAGE() 

437 self.checkIMAGE() 

438 self.calcIMAGE() 

439 self.colorIMAGE() 

440 

441 self.xrd2Dviewer.plot2D.redraw() 

442 self.display1DXRD() 

443 

444 def selectIMAGE(self,event=None): 

445 

446 img_no = self.ch_img.GetSelection() 

447 self.raw_img = self.open_image[img_no].get_image() 

448 

449 self.write_message('Displaying image: %s' % self.open_image[img_no].label, panel=0) 

450 try: 

451 self.displayIMAGE(auto_contrast=False,unzoom=True) 

452 self.setContrast() 

453 except: 

454 self.write_message('Image failed to load.', panel=0) 

455 

456 def onChangeXscale(self,event=None): 

457 

458 xi = self.xaxis_type.GetSelection() 

459 

460 self.xrd1Dviewer.plot1D.update_line(0, self.data1dxrd[xi],self.data1dxrd[3]) 

461 if self.twth is not None: self.xrd1Dviewer.plot_line() 

462 self.xrd1Dviewer.plot1D.set_viewlimits() 

463 self.xrd1Dviewer.plot1D.set_xlabel(XUNIT[xi]) 

464 if xi == 2: self.xrd1Dviewer.plot1D.axes.set_xlim(np.min(self.data1dxrd[xi]), 6) 

465 self.xrd1Dviewer.plot1D.draw() 

466 

467 

468############################################## 

469#### IMAGE DISPLAY FUNCTIONS 

470 

471 def calcIMAGE(self): 

472 if self.use_mask is True: 

473 if self.use_bkgd is True: 

474 self.plt_img = self.flp_img * self.msk_img - self.bkgd_img * self.bkgd_scale 

475 else: 

476 self.plt_img = self.flp_img * self.msk_img 

477 else: 

478 if self.use_bkgd is True: 

479 self.plt_img = self.flp_img - self.bkgd_img * self.bkgd_scale 

480 else: 

481 self.plt_img = self.flp_img 

482 

483 def flipIMAGE(self): 

484 if self.flip == 'vertical': # Vertical 

485 self.flp_img = self.raw_img[::-1,:] 

486 elif self.flip == 'horizontal': # Horizontal 

487 self.flp_img = self.raw_img[:,::-1] 

488 elif self.flip == 'both': # both 

489 self.flp_img = self.raw_img[::-1,::-1] 

490 else: # None 

491 self.flp_img = self.raw_img 

492 

493 def checkIMAGE(self): 

494 ## Reshapes/replaces mask and/or background if shape doesn't match that of image 

495 if self.msk_img.shape != self.raw_img.shape: 

496 self.msk_img = np.ones(self.raw_img.shape) 

497 if self.bkgd_img.shape != self.raw_img.shape: 

498 self.bkgd_img = np.zeros(self.raw_img.shape) 

499 

500 ## Calculates the number of pixels in image, masked pixels, and background pixels 

501 img_pxls = self.raw_img.shape[0]*self.raw_img.shape[1] 

502 msk_pxls = img_pxls - int(sum(sum(self.msk_img))) 

503 bkgd_pxls = int(sum(sum(self.bkgd_img))) 

504 

505 ## Enables mask checkbox. 

506 if msk_pxls == 0 or msk_pxls == img_pxls: 

507 self.ch_msk.Disable() 

508 self.msk_img = np.ones(self.raw_img.shape) 

509 else: 

510 self.ch_msk.Enable() 

511 

512 ## Enables background slider and sets range. 

513 if bkgd_pxls == 0: 

514 self.sldr_bkgd.Disable() 

515 self.use_bkgd = False 

516 else: 

517 self.sldr_bkgd.Enable() 

518 self.use_bkgd = True 

519 

520 self.sldr_bkgd.SetRange(0, int(self.bkgdMAX*SLIDER_SCALE)) 

521 self.sldr_bkgd.SetValue(int(self.bkgd_scale*SLIDER_SCALE)) 

522 

523 def colorIMAGE(self,unzoom=False): 

524 self.xrd2Dviewer.plot2D.conf.cmap[0] = getattr(colormap, self.color) 

525 self.xrd2Dviewer.plot2D.display(self.plt_img) #,unzoom=unzoom) 

526 

527 if self.cake is not None: 

528 self.xrd2Dcake.plot2D.conf.cmap[0] = getattr(colormap, self.color) 

529 self.xrd2Dcake.plot2D.display(self.cake[0]) #,unzoom=unzoom) 

530 

531 def setCOLOR(self,event=None): 

532 if self.color != self.ch_clr.GetString(self.ch_clr.GetSelection()): 

533 self.color = self.ch_clr.GetString(self.ch_clr.GetSelection()) 

534 self.colorIMAGE() 

535 

536 def setFLIP(self,event=None): 

537 

538 if self.flip != self.ch_flp.GetString(self.ch_flp.GetSelection()): 

539 self.flip = self.ch_flp.GetString(self.ch_flp.GetSelection()) 

540 self.redrawIMAGE(unzoom=False) 

541 

542 def setZSCALE(self,event=None): 

543 if self.ch_scl.GetSelection() == 1: ## log 

544 self.xrd2Dviewer.plot2D.conf.log_scale = True 

545 if self.xrd2Dcake is not None: 

546 self.xrd2Dcake.plot2D.conf.log_scale = True 

547 if self.xrd1Dviewer is not None: 

548 self.xrd1Dviewer.plot1D.axes.set_yscale('log') 

549 self.xrd1Dviewer.plot1D.set_viewlimits() 

550 self.xrd1Dviewer.plot1D.draw() 

551 else: ## linear 

552 self.xrd2Dviewer.plot2D.conf.log_scale = False 

553 if self.xrd2Dcake is not None: 

554 self.xrd2Dcake.plot2D.conf.log_scale = False 

555 if self.xrd1Dviewer is not None: 

556 self.xrd1Dviewer.plot1D.axes.set_yscale('linear') 

557 self.xrd1Dviewer.plot1D.set_viewlimits() 

558 self.xrd1Dviewer.plot1D.draw() 

559 

560 self.xrd2Dviewer.plot2D.redraw() 

561 if self.cake is not None: 

562 self.xrd2Dcake.plot2D.redraw() 

563 

564 

565############################################## 

566#### BACKGROUND FUNCTIONS 

567 def onBkgdScale(self,event=None): 

568 self.bkgd_scale = self.sldr_bkgd.GetValue()/SLIDER_SCALE 

569 self.redrawIMAGE(unzoom=False) 

570 

571############################################## 

572#### IMAGE CONTRAST FUNCTIONS 

573 

574 def onContrastRange(self,event=None): 

575 

576 img_no = self.ch_img.GetSelection() 

577 img = self.open_image[img_no] 

578 

579 img.minval = int(self.entr_min.GetValue()) 

580 img.maxval = int(self.entr_max.GetValue()) 

581 

582 self.setContrast() 

583 

584 

585 def onSlider(self,event=None): 

586 

587 img_no = self.ch_img.GetSelection() 

588 img = self.open_image[img_no] 

589 

590 curval = int(self.sldr_cntrst.GetValue()) 

591 

592 self.xrd2Dviewer.plot2D.conf.auto_intensity = False 

593 self.xrd2Dviewer.plot2D.conf.int_lo[0] = img.minval 

594 self.xrd2Dviewer.plot2D.conf.int_hi[0] = curval 

595 self.xrd2Dviewer.plot2D.redraw() 

596 

597 if self.cake is not None: 

598 self.xrd2Dcake.plot2D.conf.auto_intensity = False 

599 self.xrd2Dcake.plot2D.conf.int_lo[0] = img.minval 

600 self.xrd2Dcake.plot2D.conf.int_hi[0] = curval 

601 self.xrd2Dcake.plot2D.redraw() 

602 

603 def setContrast(self,event=None,auto_contrast=False): 

604 img_no = self.ch_img.GetSelection() 

605 img = self.open_image[img_no] 

606 

607 if auto_contrast: img.set_contrast(np.min(self.plt_img),np.max(self.plt_img)) 

608 

609 self.xrd2Dviewer.plot2D.conf.auto_intensity = False 

610 self.xrd2Dviewer.plot2D.conf.int_lo[0] = img.minval 

611 if auto_contrast: 

612 self.xrd2Dviewer.plot2D.conf.int_hi[0] = img.maxval*0.4 

613 else: 

614 self.xrd2Dviewer.plot2D.conf.int_hi[0] = img.maxval 

615 self.xrd2Dviewer.plot2D.redraw() 

616 

617 self.sldr_cntrst.SetRange(int(img.minval), int(img.maxval)) 

618 if auto_contrast: 

619 self.sldr_cntrst.SetValue(int(img.maxval*0.4)) 

620 else: 

621 self.sldr_cntrst.SetValue(int(img.maxval)) 

622 self.entr_min.SetValue('%i' % img.minval) 

623 self.entr_max.SetValue('%i' % img.maxval) 

624 

625 if self.cake is not None: 

626 self.xrd2Dcake.plot2D.conf.auto_intensity = False 

627 self.xrd2Dcake.plot2D.conf.int_lo[0] = img.minval 

628 if auto_contrast: 

629 self.xrd2Dcake.plot2D.conf.int_hi[0] = img.maxval*0.4 

630 else: 

631 self.xrd2Dcake.plot2D.conf.int_hi[0] = img.maxval 

632 self.xrd2Dcake.plot2D.redraw() 

633 

634 

635############################################## 

636#### XRD MANIPULATION FUNTIONS 

637 

638 def saveIMAGE(self,event=None,raw=False): 

639 wildcards = 'XRD image (*.tiff)|*.tiff|All files (*.*)|*.*' 

640 dlg = wx.FileDialog(self, 'Save image as...', 

641 defaultDir=get_cwd(), 

642 wildcard=wildcards, 

643 style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) 

644 

645 path, save = None, False 

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

647 save = True 

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

649 dlg.Destroy() 

650 

651 if save: 

652 if raw: 

653 tifffile.imsave(path,self.raw_img) 

654 else: 

655 tifffile.imsave(path,self.plt_img) 

656 

657 def on1DXRD(self,event=None): 

658 

659 read, save, plot = False, False, False 

660 if self.calfile is not None and self.plt_img is not None: 

661 myDlg = Calc1DPopup(self,self.plt_img) 

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

663 read = True 

664 save = myDlg.ch_save.GetValue() 

665 plot = myDlg.ch_plot.GetValue() 

666 unts = myDlg.save_choice.GetSelection() 

667 wdgs = myDlg.wedges.GetValue() 

668 if int(myDlg.xstep.GetValue()) < 1: 

669 attrs = {'steps':5001} 

670 else: 

671 attrs = {'steps':int(myDlg.xstep.GetValue())} 

672 unit = '2th' if unts == 1 else 'q' 

673 attrs.update({'unit':unit,'verbose':True}) 

674 myDlg.Destroy() 

675 else: 

676 print('Data and calibration files must be available for this function.') 

677 return 

678 

679 if read: 

680 if save: 

681 wildcards = '1D XRD file (*.xy)|*.xy|All files (*.*)|*.*' 

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

683 defaultDir=get_cwd(), 

684 wildcard=wildcards, 

685 style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) 

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

687 filename = dlg.GetPath().replace('\\', '/') 

688 if not filename.endswith('.xy'): 

689 filename = '%s.xy' % filename 

690 attrs.update({'file':filename}) 

691 

692 dlg.Destroy() 

693 data1D = integrate_xrd(self.plt_img,self.calfile,**attrs) 

694 if wdgs > 1: 

695 xrdq_wdg,xrd1d_wdg,lmts_wdg = [],[],[] 

696 wdg_sz = 360./int(wdgs) 

697 for iwdg in range(wdgs): 

698 wdg_lmts = np.array([iwdg*wdg_sz, (iwdg+1)*wdg_sz]) - 180 

699 attrs.update({'wedge_limits':wdg_lmts}) 

700 

701 if save: 

702 wedgename = '%s_%i_to_%ideg.xy' % (filename.split('.xy')[0], 

703 (wdg_lmts[0]+180), 

704 (wdg_lmts[1]+180)) 

705 attrs.update({'file':wedgename}) 

706 q,counts = integrate_xrd(self.plt_img,self.calfile,**attrs) 

707 xrdq_wdg += [q] 

708 xrd1d_wdg += [counts] 

709 lmts_wdg += [wdg_lmts] 

710 

711 

712 if plot: 

713 if self.xrddisplay1D is None: 

714 self.xrddisplay1D = diFFit1DFrame() 

715 

716 kwargs = {} 

717 wvlngth = read_lambda(self.calfile) 

718 kwargs.update({'wavelength':wvlngth,'energy':E_from_lambda(wvlngth)}) 

719 kwargs.update({'label':self.open_image[self.ch_img.GetSelection()].label}) 

720 data1dxrd = xrd1d(**kwargs) 

721 data1dxrd.xrd_from_2d(data1D,attrs['unit']) 

722 

723 try: 

724 self.xrddisplay1D.xrd1Dviewer.add1Ddata(data1dxrd) 

725 except PyDeadObjectError: 

726 self.xrddisplay1D = diFFit1DFrame() 

727 self.xrddisplay1D.xrd1Dviewer.add1Ddata(data1dxrd) 

728 

729 if wdgs > 1: 

730 for lmts,q,cnts in zip(lmts_wdg,xrdq_wdg,xrd1d_wdg): 

731 label = '%s (%i to %i deg)' % (self.open_image[self.ch_img.GetSelection()].label, 

732 (lmts[0]+180), (lmts[1]+180)) 

733 kwargs.update({'label':label}) 

734 data1dxrd = xrd1d(**kwargs) 

735 data1dxrd.xrd_from_2d([q,cnts],'q') 

736 self.xrddisplay1D.xrd1Dviewer.add1Ddata(data1dxrd) 

737 self.xrddisplay1D.Show() 

738 

739 

740 

741 

742############################################## 

743#### CALIBRATION FUNCTIONS 

744 def display1DXRD(self,event=None): 

745 

746 if len(self.open_image) > 0 and self.calfile is not None: 

747 

748 if self.xrd2Dcake is None or self.xrd1Dviewer is None: 

749 rightside = self.RightSidePanel(self.panel) 

750 self.panel2D.Add(rightside,proportion=1,flag=wx.EXPAND|wx.ALL,border=10) 

751 self.panel2D.Layout() 

752 self.Fit() 

753 self.SetSize((1400,720)) 

754 

755 tools1dxrd = self.ToolBox_1DXRD(self.panel) 

756 self.leftside.Add(tools1dxrd,flag=wx.ALL|wx.EXPAND,border=10) 

757 self.leftside.Layout() 

758 

759 self.panel2D.Layout() 

760 self.Fit() 

761 self.SetSize((1400,720)) 

762 

763 self.btn_integ.Enable() 

764 

765 ## Cake calculations 

766 xi = 1 

767 self.xaxis_type.SetSelection(xi) 

768 

769 self.cake = calc_cake(self.plt_img, self.calfile, unit=XLABEL[xi], xsteps=QSTPS, ysteps=QSTPS) 

770 self.xrd2Dcake.plot2D.display(self.cake[0],x=self.cake[1],y=self.cake[2], 

771 xlabel=XLABEL[xi],ylabel='eta') 

772 self.xrd2Dcake.plot2D.conf.auto_intensity = False 

773 self.xrd2Dcake.plot2D.conf.int_lo[0] = self.xrd2Dviewer.plot2D.conf.int_lo[0] 

774 self.xrd2Dcake.plot2D.conf.int_hi[0] = self.xrd2Dviewer.plot2D.conf.int_hi[0] 

775 self.xrd2Dcake.plot2D.redraw() 

776 

777 ## 1DXRD calculations 

778 

779 q,I = integrate_xrd(self.plt_img, self.calfile, unit=XLABEL[xi], steps=QSTPS) 

780 self.data1dxrd = xrd1d(x=q,xtype=XLABEL[xi],I=I).all_data() 

781 

782 self.xrd1Dviewer.plot1D.plot(self.data1dxrd[xi],self.data1dxrd[3],color='blue', 

783 xlabel=XUNIT[xi]) 

784 self.xrd1Dviewer.plot1D.axes.yaxis.set_visible(False) 

785 self.xrd1Dviewer.plot1D.axes.spines['left'].set_visible(False) 

786 self.xrd1Dviewer.plot1D.axes.spines['right'].set_visible(False) 

787 self.xrd1Dviewer.plot1D.axes.spines['top'].set_visible(False) 

788 self.xrd1Dviewer.plot1D.draw() 

789 

790 

791 def Calibrate(self,event=None): 

792 

793 CalibrationPopup(self) 

794 

795 def openPONI(self,event=None): 

796 

797 wildcards = 'pyFAI calibration file (*.poni)|*.poni|All files (*.*)|*.*' 

798 dlg = wx.FileDialog(self, message='Choose pyFAI calibration file', 

799 defaultDir=get_cwd(), 

800 wildcard=wildcards, style=wx.FD_OPEN) 

801 

802 path, read = None, False 

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

804 read = True 

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

806 dlg.Destroy() 

807 

808 if read: 

809 print('Loading calibration file:\n\t%s' % path) 

810 self.calfile = path 

811 self.xrd2Dviewer.on_calibration() 

812 self.display1DXRD() 

813 

814 

815############################################## 

816#### BACKGROUND FUNCTIONS 

817 def clearBkgd(self,event=None): 

818 

819 self.bkgd = np.zeros(self.raw_img.shape) 

820 self.checkIMAGE() 

821 

822 def openBkgd(self,event=None): 

823 

824 wildcards = 'XRD background image (*.edf,*.tif,*.tiff)|*.tif;*.tiff;*.edf|All files (*.*)|*.*' 

825 dlg = wx.FileDialog(self, message='Choose XRD background image', 

826 defaultDir=get_cwd(), 

827 wildcard=wildcards, style=wx.FD_OPEN) 

828 

829 path, read = None, False 

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

831 read = True 

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

833 dlg.Destroy() 

834 

835 if read: 

836 try: 

837 self.bkgd_img = np.array(tifffile.imread(path)) 

838 self.checkIMAGE() 

839 print('Reading background:\n\t%s' % path) 

840 except: 

841 print('\nCannot read as an image file: %s\n' % path) 

842 return 

843 

844 

845############################################## 

846#### MASK FUNCTIONS 

847 def openMask(self,event=None): 

848 

849 wildcards = 'pyFAI mask file (*.edf)|*.edf|All files (*.*)|*.*' 

850 dlg = wx.FileDialog(self, message='Choose pyFAI mask file', 

851 defaultDir=get_cwd(), 

852 wildcard=wildcards, style=wx.FD_OPEN) 

853 

854 path, read = None, False 

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

856 read = True 

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

858 dlg.Destroy() 

859 

860 if read: 

861 try: 

862 try: 

863 raw_mask = np.array(tifffile.imread(path)) 

864 except: 

865 import fabio 

866 raw_mask = fabio.open(path).data 

867 self.msk_img = np.ones(raw_mask.shape)-raw_mask 

868 self.checkIMAGE() 

869 print('Reading mask:\n\t%s' % path) 

870 except: 

871 print('\nCannot read as mask file: %s\n' % path) 

872 return 

873 

874 self.ch_msk.SetValue(True) 

875 self.applyMask(event=True) 

876 

877# def createMask(self,event=None): 

878# 

879# MaskToolsPopup(self) 

880# print('Popup to create mask!') 

881 

882 def clearMask(self,event=None): 

883 

884 self.msk_img = np.zeros(self.raw_img.shape) 

885 self.checkIMAGE() 

886 

887 def applyMask(self,event=None): 

888 

889 self.use_mask = self.ch_msk.GetValue() 

890 self.redrawIMAGE(unzoom=False) 

891 

892############################################## 

893#### HELP FUNCTIONS 

894 def onAbout(self, event=None): 

895 info = wx.AboutDialogInfo() 

896 info.SetName('diFFit2D XRD Data Viewer') 

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

898 info.SetDescription(desc) 

899 info.SetVersion(VERSION) 

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

901 dlg = wx.AboutBox(info) 

902 

903############################################## 

904#### MENU FUNCTIONS 

905 def onFolderSelect(self, evt=None): 

906 style = wx.DD_DIR_MUST_EXIST|wx.DD_DEFAULT_STYLE 

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

908 style=style) 

909 

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

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

912 try: 

913 if len(basedir) > 0: 

914 os.chdir(nativepath(basedir)) 

915 save_workdir(nativepath(basedir)) 

916 except OSError: 

917 print( 'Changed folder failed') 

918 pass 

919 save_workdir('gsemap.dat') 

920 dlg.Destroy() 

921 

922 def onClose(self, event=None): 

923 for image in self.open_image: 

924 try: 

925 image.h5file.close() 

926 except: 

927 pass 

928 

929 try: 

930 self.Destroy() 

931 except: 

932 pass 

933 

934 

935 def onExit(self, event=None): 

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

937 wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) 

938 

939 ret = dlg.ShowModal() 

940 if ret != wx.ID_YES: 

941 return 

942 self.onClose() 

943 

944 

945############################################## 

946#### PANEL DEFINITIONS 

947 def XRD2DMenuBar(self): 

948 

949 menubar = wx.MenuBar() 

950 

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

952 ## diFFit2D 

953 diFFitMenu = wx.Menu() 

954 

955 MenuItem(self, diFFitMenu, '&Open diffration image', '', self.loadIMAGE) 

956 MenuItem(self, diFFitMenu, 'Sa&ve displayed image to file', '', partial(self.saveIMAGE,raw=False)) 

957 MenuItem(self, diFFitMenu, 'Save r&aw image to file', '', partial(self.saveIMAGE,raw=True)) 

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

959 

960# MenuItem(self, diFFitMenu, '&Save settings', '', None) 

961# MenuItem(self, diFFitMenu, '&Load settings', '', None) 

962# MenuItem(self, diFFitMenu, 'A&dd analysis to map file', '', None) 

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

964 

965 menubar.Append(diFFitMenu, '&diFFit2D') 

966 

967 ########################### 

968 ## Process 

969 ProcessMenu = wx.Menu() 

970 

971 MenuItem(self, ProcessMenu, 'Load &mask file', '', self.openMask) 

972 MenuItem(self, ProcessMenu, 'Remove current mas&k', '', self.clearMask) 

973# MenuItem(self, ProcessMenu, 'C&reate mas&k', '', self.createMask) 

974 ProcessMenu.AppendSeparator() 

975 MenuItem(self, ProcessMenu, 'Load &background image', '', self.openBkgd) 

976 MenuItem(self, ProcessMenu, 'Remove current back&ground image', '', self.clearBkgd) 

977 ProcessMenu.AppendSeparator() 

978 MenuItem(self, ProcessMenu, 'Close current image', '', self.close2Dxrd) 

979 

980 menubar.Append(ProcessMenu, '&Process') 

981 

982 ########################### 

983 ## Analyze 

984 AnalyzeMenu = wx.Menu() 

985 

986# MenuItem(self, AnalyzeMenu, '&Calibrate', '', self.Calibrate) 

987 MenuItem(self, AnalyzeMenu, 'Load cali&bration file', '', self.openPONI) 

988# MenuItem(self, AnalyzeMenu, 'Show current calibratio&n', '', None) 

989 AnalyzeMenu.AppendSeparator() 

990 MenuItem(self, AnalyzeMenu, '&Integrate (open 1D viewer)', '', self.on1DXRD) 

991 

992 menubar.Append(AnalyzeMenu, 'Anal&yze') 

993 

994 ########################### 

995 ## Help 

996 HelpMenu = wx.Menu() 

997 

998 MenuItem(self, HelpMenu, '&About', 'About diFFit2D viewer', self.onAbout) 

999 

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

1001 

1002 ########################### 

1003 ## Create Menu Bar 

1004 self.SetMenuBar(menubar) 

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

1006 

1007 def LeftSidePanel(self,panel): 

1008 

1009 vbox = wx.BoxSizer(wx.VERTICAL) 

1010 

1011 imgbox = self.ImageBox(self.panel) 

1012 vistools = self.Toolbox(self.panel) 

1013 

1014 vbox.Add(imgbox,flag=wx.ALL|wx.EXPAND,border=10) 

1015 vbox.Add(vistools,flag=wx.ALL|wx.EXPAND,border=10) 

1016 

1017 return vbox 

1018 

1019 def Panel2DViewer(self): 

1020 ''' 

1021 Frame for housing all 2D XRD viewer widgets 

1022 ''' 

1023 self.panel = wx.Panel(self) 

1024 

1025 self.leftside = self.LeftSidePanel(self.panel) 

1026 center = self.CenterPanel(self.panel) 

1027 #rightside = self.RightSidePanel(self.panel) 

1028 

1029 self.panel2D = wx.BoxSizer(wx.HORIZONTAL) 

1030 self.panel2D.Add(self.leftside,flag=wx.ALL,border=10) 

1031 self.panel2D.Add(center,proportion=1,flag=wx.EXPAND|wx.ALL,border=10) 

1032 #self.panel2D.Add(rightside,proportion=1,flag=wx.EXPAND|wx.ALL,border=10) 

1033 

1034 self.panel.SetSizer(self.panel2D) 

1035 

1036 

1037 def ToolBox_1DXRD(self,panel): 

1038 

1039 tlbx = wx.StaticBox(self.panel,label='1DXRD TOOLBOX') 

1040 hbox = wx.StaticBoxSizer(tlbx,wx.HORIZONTAL) 

1041 

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

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

1044 

1045 self.xaxis_type = wx.Choice(self,choices=xunits) 

1046 self.xaxis_type.Bind(wx.EVT_CHOICE, self.onChangeXscale) 

1047 

1048 hbox.Add(ttl_xaxis, flag=wx.RIGHT, border=8) 

1049 hbox.Add(self.xaxis_type, flag=wx.EXPAND, border=8) 

1050 

1051 return hbox 

1052 

1053 def ImageBox(self,panel): 

1054 ''' 

1055 Frame for data toolbox 

1056 ''' 

1057 

1058 tlbx = wx.StaticBox(self.panel,label='DISPLAYED IMAGE') 

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

1060 

1061 

1062 ########################### 

1063 ## DATA CHOICE 

1064 

1065 

1066 self.ch_img = wx.Choice(self.panel,choices=[]) 

1067 self.ch_img.Bind(wx.EVT_CHOICE, self.selectIMAGE) 

1068 vbox.Add(self.ch_img, flag=wx.EXPAND|wx.ALL, border=8) 

1069 

1070 self.hrz_frm_sldr = wx.Slider(self.panel, minValue=0, maxValue=100, size=(120,-1), 

1071 style = wx.SL_HORIZONTAL|wx.SL_LABELS) 

1072 self.vrt_frm_sldr = wx.Slider(self.panel, minValue=0, maxValue=100, size=(-1,120), 

1073 style = wx.SL_VERTICAL|wx.SL_LABELS|wx.SL_INVERSE) 

1074 

1075 self.vrt_frm_btn = [ wx.Button(self.panel,label=u'\u2191', size=(40, -1)), 

1076 wx.Button(self.panel,label=u'\u2193', size=(40, -1))] 

1077 self.hrz_frm_btn = [ wx.Button(self.panel,label=u'\u2190', size=(40, -1)), 

1078 wx.Button(self.panel,label=u'\u2192', size=(40, -1))] 

1079 

1080 self.hrz_frm_btn[0].Bind(wx.EVT_BUTTON, partial(self.changeFRAME,'previous') ) 

1081 self.hrz_frm_btn[1].Bind(wx.EVT_BUTTON, partial(self.changeFRAME,'next') ) 

1082 self.hrz_frm_sldr.Bind(wx.EVT_SLIDER, partial(self.changeFRAME,'hslider') ) 

1083 

1084 self.vrt_frm_btn[0].Bind(wx.EVT_BUTTON, partial(self.changeFRAME,'up') ) 

1085 self.vrt_frm_btn[1].Bind(wx.EVT_BUTTON, partial(self.changeFRAME,'down') ) 

1086 self.vrt_frm_sldr.Bind(wx.EVT_SLIDER, partial(self.changeFRAME,'vslider') ) 

1087 

1088 aszr = wx.BoxSizer(wx.HORIZONTAL) 

1089 bszr = wx.BoxSizer(wx.VERTICAL) 

1090 cszr = wx.BoxSizer(wx.VERTICAL) 

1091 dszr = wx.BoxSizer(wx.HORIZONTAL) 

1092 

1093 aszr.Add(self.hrz_frm_btn[0], flag=wx.RIGHT|wx.CENTER, border=18) 

1094 aszr.Add(self.hrz_frm_btn[1], flag=wx.LEFT|wx.CENTER, border=18) 

1095 

1096 bszr.Add(self.vrt_frm_btn[0], flag=wx.BOTTOM|wx.CENTER, border=8) 

1097 bszr.Add(aszr, flag=wx.CENTER, border=8) 

1098 bszr.Add(self.vrt_frm_btn[1], flag=wx.TOP|wx.CENTER, border=8) 

1099 

1100 cszr.Add(bszr, flag=wx.CENTER, border=6) 

1101 cszr.Add(self.hrz_frm_sldr, flag=wx.CENTER, border=6) 

1102 

1103 dszr.AddSpacer(50) 

1104 dszr.Add(cszr, flag=wx.CENTER, border=6) 

1105 dszr.Add(self.vrt_frm_sldr, flag=wx.CENTER, border=6) 

1106 

1107 

1108 

1109 vbox.Add(dszr, flag=wx.EXPAND|wx.CENTER|wx.ALL, border=8) 

1110 

1111 return vbox 

1112 

1113 

1114 def Toolbox(self,panel): 

1115 ''' 

1116 Frame for visual toolbox 

1117 ''' 

1118 

1119 tlbx = wx.StaticBox(self.panel,label='2DXRD TOOLBOX')#, size=(200, 200)) 

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

1121 

1122 ########################### 

1123 ## Color 

1124 hbox_clr = wx.BoxSizer(wx.HORIZONTAL) 

1125 self.txt_clr = wx.StaticText(self.panel, label='COLOR') 

1126 

1127 colors = [] 

1128 for key in colormap.datad: 

1129 if not key.endswith('_r'): 

1130 colors.append(key) 

1131 self.ch_clr = wx.Choice(self.panel,choices=colors) 

1132 #self.ch_clr = wx.Choice(self.panel,choices=ColorMap_List) 

1133 

1134 self.ch_clr.Bind(wx.EVT_CHOICE,self.setCOLOR) 

1135 

1136 hbox_clr.Add(self.txt_clr, flag=wx.RIGHT, border=6) 

1137 hbox_clr.Add(self.ch_clr, flag=wx.RIGHT, border=6) 

1138 vbox.Add(hbox_clr, flag=wx.ALL, border=4) 

1139 

1140 ########################### 

1141 ## Contrast 

1142 vbox_ct = wx.BoxSizer(wx.VERTICAL) 

1143 

1144 hbox_ct1 = wx.BoxSizer(wx.HORIZONTAL) 

1145 self.txt_ct1 = wx.StaticText(self.panel, label='CONTRAST') 

1146 self.txt_ct2 = wx.StaticText(self.panel, label='', size=(175,-1)) 

1147 

1148 hbox_ct1.Add(self.txt_ct1, flag=wx.RIGHT, border=6) 

1149 hbox_ct1.Add(self.txt_ct2, flag=wx.RIGHT, border=6) 

1150 vbox_ct.Add(hbox_ct1, flag=wx.TOP|wx.BOTTOM, border=4) 

1151 

1152 hbox_ct2 = wx.BoxSizer(wx.HORIZONTAL) 

1153 

1154 self.sldr_cntrst = wx.Slider(self.panel, style=wx.SL_LABELS, 

1155 size=(275,-1), minValue=0, maxValue=5000000) 

1156 

1157 self.entr_min = wx.TextCtrl(self.panel, style=wx.TE_PROCESS_ENTER, size=(50,-1)) 

1158 self.entr_max = wx.TextCtrl(self.panel, style=wx.TE_PROCESS_ENTER, size=(80,-1)) 

1159 

1160 self.sldr_cntrst.Bind(wx.EVT_SLIDER,self.onSlider) 

1161 self.entr_min.Bind(wx.EVT_TEXT_ENTER,self.onContrastRange) 

1162 self.entr_max.Bind(wx.EVT_TEXT_ENTER,self.onContrastRange) 

1163 

1164 self.btn_ct1 = wx.Button(self.panel,label='reset',size=(50,-1)) 

1165 

1166 self.btn_ct1.Bind(wx.EVT_BUTTON,partial(self.setContrast,auto_contrast=True) ) 

1167 

1168 ttl_to = wx.StaticText(self.panel, label='to') 

1169 hbox_ct2.Add(self.entr_min, flag=wx.RIGHT, border=6) 

1170 hbox_ct2.Add(ttl_to, flag=wx.RIGHT, border=6) 

1171 hbox_ct2.Add(self.entr_max, flag=wx.RIGHT, border=6) 

1172 hbox_ct2.Add(self.btn_ct1, flag=wx.RIGHT, border=6) 

1173 

1174 vbox_ct.Add(self.sldr_cntrst, flag=wx.EXPAND|wx.RIGHT, border=6) 

1175 vbox_ct.Add(hbox_ct2, flag=wx.CENTER|wx.TOP, border=6) 

1176 vbox.Add(vbox_ct, flag=wx.ALL, border=4) 

1177 

1178 ########################### 

1179 ## Flip 

1180 hbox_flp = wx.BoxSizer(wx.HORIZONTAL) 

1181 self.txt_flp = wx.StaticText(self.panel, label='IMAGE FLIP') 

1182 flips = ['none','vertical','horizontal','both'] 

1183 self.ch_flp = wx.Choice(self.panel,choices=flips) 

1184 

1185 self.ch_flp.Bind(wx.EVT_CHOICE,self.setFLIP) 

1186 

1187 hbox_flp.Add(self.txt_flp, flag=wx.RIGHT|wx.TOP|wx.BOTTOM, border=6) 

1188 hbox_flp.Add(self.ch_flp, flag=wx.RIGHT|wx.TOP|wx.BOTTOM, border=6) 

1189 vbox.Add(hbox_flp, flag=wx.ALL, border=4) 

1190 

1191 ########################### 

1192 ## Scale 

1193 hbox_scl = wx.BoxSizer(wx.HORIZONTAL) 

1194 self.txt_scl = wx.StaticText(self.panel, label='SCALE') 

1195 scales = ['linear','log'] 

1196 self.ch_scl = wx.Choice(self.panel,choices=scales) 

1197 

1198 self.ch_scl.Bind(wx.EVT_CHOICE,self.setZSCALE) 

1199 

1200 hbox_scl.Add(self.txt_scl, flag=wx.RIGHT|wx.TOP|wx.BOTTOM, border=6) 

1201 hbox_scl.Add(self.ch_scl, flag=wx.RIGHT|wx.TOP|wx.BOTTOM, border=6) 

1202 vbox.Add(hbox_scl, flag=wx.ALL, border=4) 

1203 

1204 

1205 ########################### 

1206 ## Mask 

1207 hbox_msk = wx.BoxSizer(wx.HORIZONTAL) 

1208 self.btn_mask = wx.Button(panel,label='MASK') 

1209 self.ch_msk = wx.CheckBox(self.panel,label='Apply?') 

1210 

1211 self.ch_msk.Bind(wx.EVT_CHECKBOX,self.applyMask) 

1212 self.btn_mask.Bind(wx.EVT_BUTTON,self.openMask) 

1213 

1214 hbox_msk.Add(self.btn_mask, flag=wx.RIGHT|wx.TOP|wx.BOTTOM, border=6) 

1215 hbox_msk.Add(self.ch_msk, flag=wx.RIGHT|wx.TOP|wx.BOTTOM, border=6) 

1216 vbox.Add(hbox_msk, flag=wx.ALL, border=4) 

1217 

1218 ########################### 

1219 ## Background 

1220 hbox_bkgd1 = wx.BoxSizer(wx.HORIZONTAL) 

1221 self.btn_bkgd = wx.Button(panel,label='BACKGROUND') 

1222 self.sldr_bkgd = wx.Slider(self.panel,style=wx.SL_VALUE_LABEL, minValue=0, maxValue=1000) 

1223 

1224 self.sldr_bkgd.Bind(wx.EVT_SLIDER,self.onBkgdScale) 

1225 self.btn_bkgd.Bind(wx.EVT_BUTTON,self.openBkgd) 

1226 

1227 hbox_bkgd1.Add(self.btn_bkgd, flag=wx.RIGHT|wx.TOP, border=6) 

1228 hbox_bkgd1.Add(self.sldr_bkgd, flag=wx.EXPAND|wx.TOP, border=6) 

1229 vbox.Add(hbox_bkgd1, flag=wx.TOP|wx.BOTTOM, border=4) 

1230 

1231 self.sldr_bkgd.SetValue(int(self.bkgd_scale*SLIDER_SCALE)) 

1232 

1233 ########################### 

1234 ## Set defaults 

1235 self.ch_clr.SetStringSelection(self.color) 

1236 self.ch_flp.SetStringSelection(self.flip) 

1237 self.ch_scl.SetSelection(0) 

1238 self.ch_msk.Disable() 

1239 self.ch_clr.Disable() 

1240 self.sldr_cntrst.Disable() 

1241 self.entr_min.Disable() 

1242 self.entr_max.Disable() 

1243 self.btn_ct1.Disable() 

1244 self.ch_flp.Disable() 

1245 self.ch_scl.Disable() 

1246 self.btn_mask.Disable() 

1247 self.btn_bkgd.Disable() 

1248 self.sldr_bkgd.Disable() 

1249 

1250 self.hrz_frm_sldr.Disable() 

1251 for btn in self.hrz_frm_btn: btn.Disable() 

1252 

1253 self.vrt_frm_sldr.Disable() 

1254 for btn in self.vrt_frm_btn: btn.Disable() 

1255 

1256 return vbox 

1257 

1258 

1259 def RightSidePanel(self,panel): 

1260 vbox = wx.BoxSizer(wx.VERTICAL) 

1261 

1262 self.xrd2Dcake = diFFit2DPanel(panel,owner=self,size=(400,400),type='cake') 

1263 self.xrd1Dviewer = diFFit1DPanel(panel,owner=self,size=(400,100)) 

1264 

1265 vbox.Add(self.xrd2Dcake, proportion=1, flag=wx.TOP|wx.EXPAND, border = 10) 

1266 vbox.Add(self.xrd1Dviewer, proportion=1, flag=wx.BOTTOM|wx.EXPAND, border = 10) 

1267 

1268 return vbox 

1269 

1270 def CenterPanel(self,panel): 

1271 

1272 self.xrd2Dviewer = diFFit2DPanel(panel,owner=self) 

1273 btnbox = self.QuickButtons(panel) 

1274 

1275 vbox = wx.BoxSizer(wx.VERTICAL) 

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

1277 vbox.Add(btnbox,flag=wx.ALL, border = 10) 

1278 return vbox 

1279 

1280 def QuickButtons(self,panel): 

1281 buttonbox = wx.BoxSizer(wx.HORIZONTAL) 

1282 self.btn_img = wx.Button(panel,label='LOAD IMAGE') 

1283 self.btn_calib = wx.Button(panel,label='CALIBRATION') 

1284 self.btn_integ = wx.Button(panel,label='INTEGRATE (1D)') 

1285 

1286 self.btn_img.Bind(wx.EVT_BUTTON,self.loadIMAGE) 

1287 self.btn_calib.Bind(wx.EVT_BUTTON,self.openPONI) 

1288 self.btn_integ.Bind(wx.EVT_BUTTON,self.on1DXRD) 

1289 

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

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

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

1293 

1294 return buttonbox 

1295 

1296 

1297class XRDImg(Group): 

1298 ''' 

1299 XRD image class 

1300 

1301 Attributes: 

1302 ------------ 

1303 * self.label = 'Data: CeO2_Allende' # name of data set 

1304 * self.path = '/Volumes/Data/CeO2_Allende.tif' # file containing x-y data 

1305 * self.type = 'tiff' # file type 

1306 

1307 # Data parameters 

1308 * self.image = None or array # should be a 3-D array [no * x * y] 

1309 * self.iframes = 1 # number of frames in self.image (row) 

1310 * self.i = 0 # integer indicating current frame (row) 

1311 * self.jframes = 1 # number of frames in self.image (col) 

1312 * self.j = 0 # integer indicating current frame (col) 

1313 * self.minval = 0 # integer of minimum display contrast 

1314 * self.maxval = 100 # integer of maximum display contrast 

1315 

1316 mkak 2017.08.15 

1317 ''' 

1318 

1319 def __init__(self, label=None, path='', type='tiff', image=None, h5file=None): 

1320 

1321 self.label = label 

1322 self.path = path 

1323 self.type = type 

1324 

1325 self.calfile = None 

1326 

1327 self.h5file = h5file 

1328 self.image = np.zeros((1,1,PIXELS,PIXELS)) if image is None else image 

1329 

1330 self.check_image() 

1331 self.calc_range() 

1332 

1333 

1334 def check_image(self): 

1335 

1336 if self.h5file is None: 

1337 shp = np.shape(self.image) 

1338 if len(shp) == 2: 

1339 self.image = np.reshape(self.image,(1,1,shp[0],shp[1])) 

1340 if len(shp) == 3: 

1341 self.image = np.reshape(self.image,(1,shp[0],shp[1],shp[2])) 

1342 

1343 self.jframes,self.iframes,self.xpix,self.ypix = np.shape(self.image) 

1344 else: 

1345 try: 

1346 self.h5xrd = self.h5file['xrmmap/xrd2D/counts'] 

1347 except: 

1348 self.image = None 

1349 print('No 2DXRD data in %s' % os.path.split(self.h5file.filename)[-1]) 

1350 return 

1351 self.calfile = bytes2str(self.h5file['xrmmap/xrd1D'].attrs.get('calfile','')) 

1352 if not os.path.exists(self.calfile): 

1353 self.calfile = None 

1354 

1355 ## making an assumption that h5 map file always has multiple rows and cols 

1356 self.jframes,self.iframes,self.xpix,self.ypix = self.h5xrd.shape 

1357 

1358 self.i = 0 if self.iframes < 4 else int(self.iframes)/2 

1359 self.j = 0 if self.jframes < 4 else int(self.jframes)/2 

1360 

1361 def calc_range(self): 

1362 

1363 if self.h5file is None: 

1364 self.minval = self.image[self.j,self.i].min() 

1365 self.maxval = self.image[self.j,self.i].max() 

1366 else: 

1367 self.minval = self.h5xrd[self.j,self.i].min() 

1368 self.maxval = self.h5xrd[self.j,self.i].max() 

1369 

1370 def get_image(self,i=None,j=None): 

1371 

1372 if i is not None and i != self.i: 

1373 if i < 0: i == self.iframes-1 

1374 if i >= self.iframes: i = 0 

1375 self.i = i 

1376 

1377 if j is not None and j != self.j: 

1378 if j < 0: j == self.jframes-1 

1379 if j >= self.jframes: j = 0 

1380 self.j = j 

1381 

1382 if self.h5file is None: 

1383 return self.image[self.j,self.i] 

1384 else: 

1385 return self.h5xrd[self.j,self.i] 

1386 

1387 def set_contrast(self,minval,maxval): 

1388 

1389 if maxval == minval: maxval = minval+100 

1390 

1391 self.minval = int(minval) 

1392 self.maxval = int(maxval) 

1393 

1394 

1395class XRD2DViewer(LarchWxApp): 

1396 def __init__(self, **kws): 

1397 LarchWxApp.__init__(self, **kws) 

1398 

1399 def createApp(self): 

1400 frame = XRD2DViewerFrame() 

1401 frame.Show() 

1402 self.SetTopWindow(frame) 

1403 return True 

1404 

1405 

1406if __name__ == '__main__': 

1407 XRD2DViewer().MainLoop()