Coverage for /Users/Newville/Codes/xraylarch/larch/plot/plotly_xafsplots.py: 0%

641 statements  

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

1#!/usr/bin/env python 

2""" 

3Plotting macros for XAFS data sets and fits 

4 

5 Function Description of what is plotted 

6 ---------------- ----------------------------------------------------- 

7 plot_mu() mu(E) for XAFS data group in various forms 

8 plot_bkg() mu(E) and background mu0(E) for XAFS data group 

9 plot_chik() chi(k) for XAFS data group 

10 plot_chie() chi(E) for XAFS data group 

11 plot_chir() chi(R) for XAFS data group 

12 plot_chifit() chi(k) and chi(R) for fit to feffit dataset 

13 plot_path_k() chi(k) for a single path of a feffit dataset 

14 plot_path_r() chi(R) for a single path of a feffit dataset 

15 plot_paths_k() chi(k) for model and all paths of a feffit dataset 

16 plot_paths_r() chi(R) for model and all paths of a feffit dataset 

17 plot_diffkk() plots from DIFFKK 

18 ---------------- ----------------------------------------------------- 

19""" 

20 

21import os 

22import numpy as np 

23import time 

24import logging 

25from copy import deepcopy 

26from matplotlib.ticker import FuncFormatter 

27 

28from larch import Group 

29from larch.math import (index_of, index_nearest, interp) 

30from larch.xafs import cauchy_wavelet, etok, ktoe 

31 

32def nullfunc(*args, **kws): 

33 pass 

34 

35get_display = _plot = _oplot = _newplot = _fitplot = _plot_text = nullfunc 

36_plot_marker = _plot_arrow = _plot_axvline = _plot_axhline = nullfunc 

37 

38 

39HAS_PLOTLY = True 

40try: 

41 import plotly 

42except ImportError: 

43 HAS_PLOTLY = False 

44 

45if HAS_PLOTLY: 

46 import plotly.graph_objs as pgo 

47 from plotly.subplots import make_subplots 

48 

49def get_display(win=1, *args, **kws): 

50 pass 

51 

52LineColors = ('#1f77b4', '#d62728', '#2ca02c', '#ff7f0e', '#9467bd', 

53 '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf') 

54 

55LineStyles = ('solid', 'dashed', 'dotted') 

56NCOLORS = len(LineColors) 

57NSTYLES = len(LineStyles) 

58 

59FIGSTYLE = dict(width=650, height=500, 

60 showlegend=True, hovermode='closest', 

61 legend=dict(borderwidth=0.5, bgcolor='#F2F2F2'), 

62 # orientation='v') #, x=0.1, y=1.15)# , yanchor='top'), 

63 plot_bgcolor='#FDFDFF', 

64 xaxis=dict(showgrid=True, gridcolor='#D8D8D8', 

65 color='#004', zerolinecolor='#DDD'), 

66 yaxis=dict(showgrid=True, gridcolor='#D8D8D8', 

67 color='#004', zerolinecolor='#DDD') 

68 ) 

69 

70def set_label_weight(label, w): 

71 return label.replace('__W__', '{0:g}'.format(w)) 

72 

73# common XAFS plot labels 

74def chirlab(kweight, show_mag=True, show_real=False, show_imag=False): 

75 """generate chi(R) label for a kweight 

76 

77 Arguments 

78 ---------- 

79 kweight k-weight to use (required) 

80 show_mag bool whether to plot |chi(R)| [True] 

81 show_real bool whether to plot Re[chi(R)] [False] 

82 show_imag bool whether to plot Im[chi(R)] [False] 

83 """ 

84 ylab = [] 

85 if show_mag: ylab.append(plotlabels.chirmag) 

86 if show_real: ylab.append(plotlabels.chirre) 

87 if show_imag: ylab.append(plotlabels.chirim) 

88 if len(ylab) > 1: ylab = [plotlabels.chir] 

89 return set_label_weight(ylab[0], kweight+1) 

90#enddef 

91 

92plotlabels = Group(k = r'$k \rm\,(\AA^{-1})$', 

93 r = r'$R \rm\,(\AA)$', 

94 energy = r'$E\rm\,(eV)$', 

95 ewithk = r'$E\rm\,(eV)$' + '\n' + r'$[k \rm\,(\AA^{-1})]$', 

96 mu = r'$\mu(E)$', 

97 norm = r'normalized $\mu(E)$', 

98 flat = r'flattened $\mu(E)$', 

99 deconv = r'deconvolved $\mu(E)$', 

100 dmude = r'$d\mu_{\rm norm}(E)/dE$', 

101 d2mude = r'$d^2\mu_{\rm norm}(E)/dE^2$', 

102 chie = r'$\chi(E)$', 

103 chie0 = r'$\chi(E)$', 

104 chie1 = r'$E\chi(E) \rm\, (eV)$', 

105 chiew = r'$E^{__W__}\chi(E) \rm\,(eV^{__W__})$', 

106 chikw = r'$k^{{__W__}}\chi(k) \rm\,(\AA^{{-__W__}})$', 

107 chi0 = r'$\chi(k)$', 

108 chi1 = r'$k\chi(k) \rm\,(\AA^{-1})$', 

109 chi2 = r'$k^2\chi(k) \rm\,(\AA^{-2})$', 

110 chi3 = r'$k^3\chi(k) \rm\,(\AA^{-3})$', 

111 chir = r'$\chi(R) \rm\,(\AA^{{-__W__}})$', 

112 chirmag = r'$|\chi(R)| \rm\,(\AA^{{-__W__}})$', 

113 chirre = r'${{\rm Re}}[\chi(R)] \rm\,(\AA^{{-__W__}})$', 

114 chirim = r'${{\rm Im}}[\chi(R)] \rm\,(\AA^{{-__W__}})$', 

115 chirpha = r'${{\rm Phase}}[\chi(R)] \rm\,(\AA^{{-__W__}})$', 

116 e0color = '#B2B282', 

117 chirlab = chirlab) 

118 

119# plotly's mathjax needs an extra package to support \AA: 

120for attr in dir(plotlabels): 

121 val = getattr(plotlabels, attr) 

122 if isinstance(val, str) and r'\AA' in val: 

123 setattr(plotlabels, attr, r'$\require{mediawiki-texvc} ' + val[1:]) 

124 

125 

126def safetitle(t): 

127 if "'" in t: 

128 t = t.replace("'", "\\'") 

129 return t 

130 

131def _get_title(dgroup, title=None): 

132 """get best title for group""" 

133 if title is not None: 

134 return safetitle(title) 

135 data_group = getattr(dgroup, 'data', None) 

136 

137 for attr in ('title', 'plot_title', 'filename', 'name', '__name__'): 

138 t = getattr(dgroup, attr, None) 

139 if t is not None: 

140 if attr == 'filename': 

141 folder, file = os.path.split(t) 

142 if folder == '': 

143 t = file 

144 else: 

145 top, folder = os.path.split(folder) 

146 t = '/'.join((folder, file)) 

147 return safetitle(t) 

148 if data_group is not None: 

149 t = getattr(data_group, attr, None) 

150 if t is not None: 

151 return t 

152 return safetitle(repr(dgroup)) 

153 

154 

155def _get_kweight(dgroup, kweight=None): 

156 if kweight is not None: 

157 return kweight 

158 callargs = getattr(dgroup, 'callargs', None) 

159 ftargs = getattr(callargs, 'xftf', {'kweight':0}) 

160 return ftargs['kweight'] 

161 

162 

163 

164def _get_erange(dgroup, emin=None, emax=None): 

165 """get absolute emin/emax for data range, allowing using 

166 values relative to e0. 

167 """ 

168 dat_emin, dat_emax = min(dgroup.energy)-100, max(dgroup.energy)+100 

169 e0 = getattr(dgroup, 'e0', 0.0) 

170 if emin is not None: 

171 if not (emin > dat_emin and emin < dat_emax): 

172 if emin+e0 > dat_emin and emin+e0 < dat_emax: 

173 emin += e0 

174 else: 

175 emin = dat_emin 

176 if emax is not None: 

177 if not (emax > dat_emin and emax < dat_emax): 

178 if emax+e0 > dat_emin and emax+e0 < dat_emax: 

179 emax += e0 

180 else: 

181 emax = dat_emax 

182 return emin, emax 

183#enddef 

184 

185def redraw(win=1, xmin=None, xmax=None, ymin=None, ymax=None, 

186 dymin=None, dymax=None, 

187 show_legend=True, stacked=False, _larch=None): 

188 disp = get_display(win=win, stacked=stacked, _larch=_larch) 

189 if disp is None: 

190 return 

191 panel = disp.panel 

192 panel.conf.show_legend = show_legend 

193 if (xmin is not None or xmax is not None or 

194 ymin is not None or ymax is not None): 

195 panel.set_xylims((xmin, xmax, ymin, ymax)) 

196 if stacked: 

197 disp.panel_bot.set_xylims((xmin, xmax, dymin, dymax)) 

198 

199 panel.unzoom_all() 

200 panel.reset_formats() 

201 if stacked: 

202 disp.panel_bot.unzoom_all() 

203 disp.panel_bot.reset_formats() 

204 if show_legend: # note: draw_legend *will* redraw the canvas 

205 panel.conf.draw_legend() 

206 else: 

207 panel.canvas.draw() 

208 if stacked: 

209 disp.panel_bot.canvas.draw() 

210 

211 #endif 

212#enddef 

213 

214 

215class PlotlyFigure: 

216 """wrapping of Plotly Figure 

217 """ 

218 

219 def __init__(self, two_yaxis=False, style=None): 

220 self.two_yaxis = two_yaxis 

221 self.style = deepcopy(FIGSTYLE) 

222 if style is not None: 

223 self.style.update(style) 

224 if self.two_yaxis: 

225 self.fig = make_subplots(specs=[[{"secondary_y": True}]]) 

226 else: 

227 self.fig = pgo.FigureWidget() 

228 

229 self.traces = [] 

230 

231 def clear(self): 

232 self.traces = [] 

233 

234 def add_plot(self, x, y, label=None, color=None, linewidth=3, 

235 style='solid', marker=None, side='left'): 

236 itrace = len(self.traces) 

237 

238 if label is None: 

239 label = "trace %d" % (1+itrace) 

240 if color is None: 

241 color = LineColors[itrace % NCOLORS] 

242 if style is None: 

243 style = LineStyles[ int(itrace*1.0 / NCOLORS) % NSTYLES] 

244 

245 trace_opts = {} 

246 if self.two_yaxis: 

247 trace_opts['secondary_y'] = (side.lower().startswith('l')) 

248 

249 lineopts = dict(color=color, width=linewidth) 

250 trace = pgo.Scatter(x=x, y=y, name=label, line=lineopts) 

251 

252 self.traces.append(trace) 

253 

254 self.fig.add_trace(trace, **trace_opts) 

255 

256 

257 def add_vline(self, *args, **kws): 

258 self.fig.add_vline(*args, **kws) 

259 

260 def set_xrange(self, xmin, xmax): 

261 self.fig.update_xaxes(range=[xmin, xmax]) 

262 

263 def set_yrange(self, ymin, ymax): 

264 self.fig.update_yaxes(range=[ymin, ymax]) 

265 

266 def set_style(self, **kws): 

267 self.style.update(**kws) 

268 self.fig.update_layout(**self.style) 

269 

270 def show(self): 

271 self.fig.show() 

272 

273def plot(xdata, ydata, dy=None, new=False, label=None, xlabel=None, 

274 ylabel=None, y2label=None, title=None, side='left', ylog_scale=None, 

275 xlog_scale=None, grid=None, xmin=None, xmax=None, ymin=None, 

276 ymax=None, color=None, style='solid', alpha=None, fill=False, 

277 drawstyle=None, linewidth=2, marker=None, markersize=None, 

278 show_legend=None, bgcolor=None, framecolor=None, gridcolor=None, 

279 textcolor=None, labelfontsize=None, titlefontsize=None, 

280 legendfontsize=None, fullbox=None, axes_style=None, zorder=None, 

281 delay_draw=False, **kws): 

282 

283 """emulate wxmplot plot() function, probably incompletely""" 

284 

285 fig = PlotlyFigure(two_yaxis=(side=='right')) 

286 if new: 

287 fig.clear() 

288 

289 fig.add_plot(xdata, ydata, label=label, color=color, linewidth=linewidth, 

290 style=style, marker=marker, side=side) 

291 

292 fig.set_style(title=title, xaxis_title=xlabel, yaxis_title=ylabel) 

293 if xmin is not None or xmax is not None: 

294 fig.set_xrange(xmin, xmax) 

295 if ymin is not None or ymax is not None: 

296 fig.set_yrange(ymin, ymax) 

297 

298 fig.show() 

299 return fig 

300 

301 

302def multi_plot(plotsets): 

303 """plot multiple traces with an array of dictionaries emulating 

304 multiplot calls to plot: 

305 

306 instead of 

307 

308 >>> plot(x1, y1, label='thing1', color='blue') 

309 >>> plot(x2, y2, label='thing2', color='red') 

310 

311 you can do 

312 

313 >>> multi_plot([dict(xdata=x1, ydata=y1, label='thing1', color='blue'), 

314 dict(xdata=x2, ydata=y2, label='thing2', color='red')]) 

315 

316 """ 

317 two_axis = False 

318 for pset in plotsets[:]: 

319 side = pset.get('side', None) 

320 if side == 'right': 

321 two_axis = True 

322 

323 

324 fig = PlotlyFigure(two_yaxis=two_axis) 

325 fig.clear() 

326 

327 sopts = dict(title=None, xlabel=None, ylabel=None, 

328 xmin=None, xmax=None, ymin=None, ymax=None) 

329 

330 for pset in plotsets[:]: 

331 xdata = pset['xdata'] 

332 ydata = pset['ydata'] 

333 popts = dict(label=None, color=None, side='left', style=None, 

334 linewidth=3, marker=None) 

335 for w in ('label', 'color', 'style', 'linewidth', 'marker', 'side'): 

336 if w in pset: 

337 popts[w] = pset[w] 

338 for w in ('xmin', 'xmax', 'ymin', 'ymax', 'title', 'xlabel', 'ylabel'): 

339 if w in pset: 

340 sopts[w] = pset[w] 

341 

342 fig.add_plot(xdata, ydata, **popts) 

343 

344 xmin = sopts.pop('xmin') 

345 xmax = sopts.pop('xmax') 

346 ymin = sopts.pop('ymin') 

347 ymax = sopts.pop('ymax') 

348 

349 sopts['xaxis_title'] = sopts.pop('xlabel') 

350 sopts['yaxis_title'] = sopts.pop('ylabel') 

351 fig.set_style(**sopts) 

352 

353 if xmin is not None or xmax is not None: 

354 fig.set_xrange(xmin, xmax) 

355 if ymin is not None or ymax is not None: 

356 fig.set_yrange(ymin, ymax) 

357 fig.show() 

358 return fig 

359 

360 

361 

362def plot_mu(dgroup, show_norm=False, show_flat=False, show_deriv=False, 

363 show_pre=False, show_post=False, show_e0=False, with_deriv=False, 

364 emin=None, emax=None, label='mu', new=True, delay_draw=False, 

365 offset=0, title=None, win=1, _larch=None): 

366 """ 

367 plot_mu(dgroup, norm=False, deriv=False, show_pre=False, show_post=False, 

368 show_e0=False, show_deriv=False, emin=None, emax=None, label=None, 

369 new=True, win=1) 

370 

371 Plot mu(E) for an XAFS data group in various forms 

372 

373 Arplguments 

374 ---------- 

375 dgroup group of XAFS data after pre_edge() results (see Note 1) 

376 show_norm bool whether to show normalized data [False] 

377 show_flat bool whether to show flattened, normalized data [False] 

378 show_deriv bool whether to show derivative of normalized data [False] 

379 show_pre bool whether to show pre-edge curve [False] 

380 show_post bool whether to show post-edge curve [False] 

381 show_e0 bool whether to show E0 [False] 

382 with_deriv bool whether to show deriv (dmu/de) together with mu [False] 

383 emin min energy to show, absolute or relative to E0 [None, start of data] 

384 emax max energy to show, absolute or relative to E0 [None, end of data] 

385 label string for label [None: 'mu', `dmu/dE', or 'mu norm'] 

386 title string for plot title [None, may use filename if available] 

387 new bool whether to start a new plot [True] 

388 delay_draw bool whether to delay draw until more traces are added [False] 

389 offset vertical offset to use for y-array [0] 

390 win integer plot window to use [1] 

391 

392 Notes 

393 ----- 

394 1. The input data group must have the following attributes: 

395 energy, mu, norm, e0, pre_edge, edge_step 

396 """ 

397 if not HAS_PLOTLY: 

398 logging.getLogger().error('Need plotply installed') 

399 return 

400 

401 if hasattr(dgroup, 'mu'): 

402 mu = dgroup.mu 

403 elif hasattr(dgroup, 'mutrans'): 

404 mu = dgroup.mutrans 

405 elif hasattr(dgroup, 'mufluor'): 

406 mu = dgroup.mufluor 

407 else: 

408 raise ValueError("XAFS data group has no array for mu") 

409 #endif 

410 ylabel = plotlabels.mu 

411 if label is None: 

412 label = getattr(dgroup, 'filename', 'mu') 

413 #endif 

414 if show_deriv: 

415 mu = dgroup.dmude 

416 ylabel = f"{ylabel} (deriv)" 

417 dlabel = plotlabels.dmude 

418 elif show_norm: 

419 mu = dgroup.norm 

420 ylabel = f"{ylabel} (norm)" 

421 dlabel = plotlabels.norm 

422 #endif 

423 elif show_flat: 

424 mu = dgroup.flat 

425 ylabel = f"{ylabel} (flat)" 

426 dlabel = plotlabels.flat 

427 #endif 

428 emin, emax = _get_erange(dgroup, emin, emax) 

429 title = _get_title(dgroup, title=title) 

430 

431 

432 fig = PlotlyFigure(two_yaxis=with_deriv) 

433 fig.add_plot(dgroup.energy, mu+offset, label=label) 

434 

435 if with_deriv: 

436 fig.add_plot(dgroup.energy, dgroup.dmude+offset, label=f"{ylabel} (deriv)", side='right') 

437 

438 else: 

439 if not show_norm and show_pre: 

440 fig.add_plot(dgroup.energy, dgroup.pre_edge+offset, label='pre_edge') 

441 if not show_norm and show_post: 

442 fig.add_plot(dgroup.energy, dgroup.post_edge+offset, label='post_edge') 

443 

444 if show_e0: 

445 fig.add_vline(x=dgroup.e0, line_width=2, line_dash="dash", line_color="#AAC") 

446 

447 fig.set_xrange(emin, emax) 

448 fig.set_style(title=title, xaxis_title=plotlabels.energy, yaxis_title=ylabel) 

449 fig.show() 

450 return fig 

451 

452 

453def plot_bkg(dgroup, norm=True, emin=None, emax=None, show_e0=False, 

454 label=None, title=None, new=True, delay_draw=False, offset=0, 

455 win=1, _larch=None): 

456 """ 

457 plot_bkg(dgroup, norm=True, emin=None, emax=None, show_e0=False, label=None, new=True, win=1): 

458 

459 Plot mu(E) and background mu0(E) for XAFS data group 

460 

461 Arguments 

462 ---------- 

463 dgroup group of XAFS data after autobk() results (see Note 1) 

464 norm bool whether to show normalized data [True] 

465 emin min energy to show, absolute or relative to E0 [None, start of data] 

466 emax max energy to show, absolute or relative to E0 [None, end of data] 

467 show_e0 bool whether to show E0 [False] 

468 label string for label [``None``: 'mu'] 

469 title string for plot titlte [None, may use filename if available] 

470 new bool whether to start a new plot [True] 

471 delay_draw bool whether to delay draw until more traces are added [False] 

472 offset vertical offset to use for y-array [0] 

473 win integer plot window to use [1] 

474 

475 Notes 

476 ----- 

477 1. The input data group must have the following attributes: 

478 energy, mu, bkg, norm, e0, pre_edge, edge_step, filename 

479 """ 

480 if hasattr(dgroup, 'mu'): 

481 mu = dgroup.mu 

482 elif hasattr(dgroup, 'mutrans'): 

483 mu = dgroup.mutrans 

484 else: 

485 raise ValueError("XAFS data group has no array for mu") 

486 #endif 

487 

488 bkg = dgroup.bkg 

489 ylabel = plotlabels.mu 

490 if label is None: 

491 label = 'mu' 

492 #endif 

493 emin, emax = _get_erange(dgroup, emin, emax) 

494 if norm: 

495 mu = dgroup.norm 

496 bkg = (dgroup.bkg - dgroup.pre_edge) / dgroup.edge_step 

497 ylabel = f"{ylabel} (norm)" 

498 label = f"{ylabel} (norm)" 

499 #endif 

500 title = _get_title(dgroup, title=title) 

501 

502 fig = PlotlyFigure(two_yaxis=False) 

503 fig.add_plot(dgroup.energy, mu+offset, label=label) 

504 fig.add_plot(dgroup.energy, bkg+offset, label='bkg') 

505 

506 if show_e0: 

507 fig.add_vline(x=dgroup.e0, line_width=2, line_dash="dash", line_color="#AAC") 

508 fig.set_xrange(emin, emax) 

509 fig.set_style(title=title, xaxis_title=plotlabels.energy, yaxis_title=ylabel) 

510 fig.show() 

511 return fig 

512 

513 

514def plot_chie(dgroup, emin=-5, emax=None, label=None, title=None, 

515 eweight=0, new=True, delay_draw=False, 

516 offset=0, win=1, show_k=False, _larch=None): 

517 """ 

518 plot_chie(dgroup, emin=None, emax=None, label=None, new=True, win=1): 

519 

520 Plot chi(E) for XAFS data group 

521 

522 Arguments 

523 ---------- 

524 dgroup group of XAFS data after autobk() results (see Note 1) 

525 emin min energy to show, absolute or relative to E0 [-25] 

526 emax max energy to show, absolute or relative to E0 [None, end of data] 

527 label string for label [``None``: 'mu'] 

528 title string for plot title [None, may use filename if available] 

529 new bool whether to start a new plot [True] 

530 eweight energy weightingn for energisdef es>e0 [0] 

531 delay_draw bool whether to delay draw until more traces are added [False] 

532 offset vertical offset to use for y-array [0] 

533 win integer plot window to use [1] 

534 

535 Notes 

536 ----- 

537 1. The input data group must have the following attributes: 

538 energy, mu, bkg, norm, e0, pre_edge, edge_step, filename 

539 """ 

540 if hasattr(dgroup, 'mu'): 

541 mu = dgroup.mu 

542 elif hasattr(dgroup, 'mutrans'): 

543 mu = dgroup.mutrans 

544 else: 

545 raise ValueError("XAFS data group has no array for mu") 

546 #endif 

547 e0 = dgroup.e0 

548 chie = (mu - dgroup.bkg) 

549 ylabel = plotlabels.chie 

550 if abs(eweight) > 1.e-2: 

551 chie *= (dgroup.energy-e0)**(eweight) 

552 ylabel = set_label_weight(plotlabels.chiew, eweight) 

553 xlabel = plotlabels.energy 

554 

555 emin, emax = _get_erange(dgroup, emin, emax) 

556 if emin is not None: 

557 emin = emin - e0 

558 if emax is not None: 

559 emax = emax - e0 

560 

561 

562 title = _get_title(dgroup, title=title) 

563 

564 def ek_formatter(x, pos): 

565 ex = float(x) 

566 if ex < 0: 

567 s = '' 

568 else: 

569 s = f"\n[{etok(ex):.2f}]" 

570 return r"%1.4g%s" % (x, s) 

571 

572 fig = PlotlyFigure(two_yaxis=False) 

573 fig.add_plot(dgroup.energy-e0, chie+offset, label=label) 

574 

575 fig.set_xrange(emin, emax) 

576 fig.set_style(title=title, xaxis_title=xlabel, yaxis_title=ylabel) 

577 fig.show() 

578 return fig 

579 

580 

581def plot_chik(dgroup, kweight=None, kmax=None, show_window=True, 

582 scale_window=True, label=None, title=None, new=True, 

583 delay_draw=False, offset=0, win=1, _larch=None): 

584 """ 

585 plot_chik(dgroup, kweight=None, kmax=None, show_window=True, label=None, 

586 new=True, win=1) 

587 

588 Plot k-weighted chi(k) for XAFS data group 

589 

590 Arguments 

591 ---------- 

592 dgroup group of XAFS data after autobk() results (see Note 1) 

593 kweight k-weighting for plot [read from last xftf(), or 0] 

594 kmax max k to show [None, end of data] 

595 show_window bool whether to also plot k-window [True] 

596 scale_window bool whether to scale k-window to max |chi(k)| [True] 

597 label string for label [``None`` to use 'chi'] 

598 title string for plot title [None, may use filename if available] 

599 new bool whether to start a new plot [True] 

600 delay_draw bool whether to delay draw until more traces are added [False] 

601 offset vertical offset to use for y-array [0] 

602 win integer plot window to use [1] 

603 

604 Notes 

605 ----- 

606 1. The input data group must have the following attributes: 

607 k, chi, kwin, filename 

608 """ 

609 kweight = _get_kweight(dgroup, kweight) 

610 

611 chi = dgroup.chi * dgroup.k ** kweight 

612 opts = dict(win=win, show_legend=True, delay_draw=True, linewidth=3, 

613 _larch=_larch) 

614 if label is None: 

615 label = 'chi' 

616 #endif 

617 if new: 

618 title = _get_title(dgroup, title=title) 

619 

620 fig = PlotlyFigure(two_yaxis=False) 

621 fig.add_plot(dgroup.k, chi+offset, label=label) 

622 

623 if show_window and hasattr(dgroup, 'kwin'): 

624 kwin = dgroup.kwin 

625 if scale_window: 

626 kwin = kwin*max(abs(chi)) 

627 fig.add_plot(dgroup.k, kwin+offset, label='window') 

628 

629 if kmax is not None: 

630 fig.set_xrange(0, kmax) 

631 ylabel = set_label_weight(plotlabels.chikw, kweight) 

632 fig.set_style(title=title, xaxis_title=plotlabels.k, 

633 yaxis_title=ylabel) 

634 

635 fig.show() 

636 return fig 

637 

638#enddef 

639 

640def plot_chir(dgroup, show_mag=True, show_real=False, show_imag=False, 

641 show_window=False, rmax=None, label=None, title=None, 

642 new=True, delay_draw=False, offset=0, win=1, _larch=None): 

643 """ 

644 plot_chir(dgroup, show_mag=True, show_real=False, show_imag=False, 

645 rmax=None, label=None, new=True, win=1) 

646 

647 Plot chi(R) for XAFS data group 

648 

649 Arguments 

650 ---------- 

651 dgroup group of XAFS data after xftf() results (see Note 1) 

652 show_mag bool whether to plot |chi(R)| [True] 

653 show_real bool whether to plot Re[chi(R)] [False] 

654 show_imag bool whether to plot Im[chi(R)] [False] 

655 show_window bool whether to R-windw for back FT (will be scaled) [False] 

656 label string for label [``None`` to use 'chir'] 

657 title string for plot title [None, may use filename if available] 

658 rmax max R to show [None, end of data] 

659 new bool whether to start a new plot [True] 

660 delay_draw bool whether to delay draw until more traces are added [False] 

661 offset vertical offset to use for y-array [0] 

662 win integer plot window to use [1] 

663 

664 Notes 

665 ----- 

666 1. The input data group must have the following attributes: 

667 r, chir_mag, chir_im, chir_re, kweight, filename 

668 """ 

669 kweight = _get_kweight(dgroup, None) 

670 

671 if new: 

672 title = _get_title(dgroup, title=title) 

673 

674 opts = dict(win=win, show_legend=True, linewidth=3, title=title, 

675 zorder=20, xmax=rmax, xlabel=plotlabels.r, new=new, 

676 delay_draw=True, _larch=_larch) 

677 

678 ylabel = plotlabels.chirlab(kweight, show_mag=show_mag, 

679 show_real=show_real, show_imag=show_imag) 

680 opts['ylabel'] = ylabel 

681 if not hasattr(dgroup, 'r'): 

682 print("group does not have chi(R) data") 

683 return 

684 #endif 

685 if label is None: 

686 label = 'chir' 

687 #endif 

688 fig = PlotlyFigure(two_yaxis=False) 

689 if show_mag: 

690 fig.add_plot(dgroup.r, dgroup.chir_mag+offset, label=f'{label} (mag)') 

691 #endif 

692 if show_real: 

693 fig.add_plot(dgroup.r, dgroup.chir_re+offset, label=f'{label} (real)') 

694 opts['new'] = False 

695 #endif 

696 if show_imag: 

697 fig.add_plot(dgroup.r, dgroup.chir_im+offset, label=f'{label} (imag)') 

698 #endif 

699 if show_window and hasattr(dgroup, 'rwin'): 

700 rwin = dgroup.rwin * max(dgroup.chir_mag) 

701 fig.add_plot(dgroup.r, rwin+offset, label='window') 

702 #endif 

703 if rmax is not None: 

704 fig.set_xrange(0, rmax) 

705 

706 fig.set_style(title=title, xaxis_title=plotlabels.r, yaxis_title=ylabel) 

707 fig.show() 

708 return fig 

709 

710#enddef 

711 

712def plot_chiq(dgroup, kweight=None, kmax=None, show_chik=False, label=None, 

713 title=None, new=True, delay_draw=False, offset=0, win=1, 

714 show_window=False, scale_window=True, _larch=None): 

715 """ 

716 plot_chiq(dgroup, kweight=None, kmax=None, show_chik=False, label=None, 

717 new=True, win=1) 

718 

719 Plot Fourier filtered chi(k), optionally with k-weighted chi(k) for XAFS data group 

720 

721 Arguments 

722 ---------- 

723 dgroup group of XAFS data after autobk() results (see Note 1) 

724 kweight k-weighting for plot [read from last xftf(), or 0] 

725 kmax max k to show [None, end of data] 

726 show_chik bool whether to also plot k-weighted chi(k) [False] 

727 show_window bool whether to also plot FT k-window [False] 

728 scale_window bool whether to scale FT k-window to max |chi(q)| [True] 

729 label string for label [``None`` to use 'chi'] 

730 title string for plot title [None, may use filename if available] 

731 new bool whether to start a new plot [True] 

732 delay_draw bool whether to delay draw until more traces are added [False] 

733 offset vertical offset to use for y-array [0] 

734 win integer plot window to use [1] 

735 

736 Notes 

737 ----- 

738 1. The input data group must have the following attributes: 

739 k, chi, kwin, filename 

740 """ 

741 kweight = _get_kweight(dgroup, kweight) 

742 nk = len(dgroup.k) 

743 chiq = dgroup.chiq_re[:nk] 

744 opts = dict(win=win, show_legend=True, delay_draw=True, linewidth=3, _larch=_larch) 

745 if label is None: 

746 label = 'chi(q) (filtered)' 

747 #endif 

748 if new: 

749 title = _get_title(dgroup, title=title) 

750 

751 _plot(dgroup.k, chiq+offset, xlabel=plotlabels.k, 

752 ylabel=set_label_weight(plotlabels.chikw, kweight), 

753 title=title, label=label, zorder=20, new=new, xmax=kmax, **opts) 

754 

755 if show_chik: 

756 chik = dgroup.chi * dgroup.k ** kweight 

757 _plot(dgroup.k, chik+offset, zorder=16, label='chi(k)', **opts) 

758 #endif 

759 if show_window and hasattr(dgroup, 'kwin'): 

760 kwin = dgroup.kwin 

761 if scale_window: 

762 kwin = kwin*max(abs(chiq)) 

763 _plot(dgroup.k, kwin+offset, zorder=12, label='window', **opts) 

764 #endif 

765 

766 redraw(win=win, xmax=kmax, _larch=_larch) 

767#enddef 

768 

769 

770def plot_wavelet(dgroup, show_mag=True, show_real=False, show_imag=False, 

771 rmax=None, kmax=None, kweight=None, title=None, win=1, _larch=None): 

772 """ 

773 plot_wavelet(dgroup, show_mag=True, show_real=False, show_imag=False, 

774 rmax=None, kmax=None, kweight=None, title=None, win=1) 

775 

776 Plot wavelet for XAFS data group 

777 

778 Arguments 

779 ---------- 

780 dgroup group of XAFS data after xftf() results (see Note 1) 

781 show_mag bool whether to plot wavelet magnitude [True] 

782 show_real bool whether to plot real part of wavelet [False] 

783 show_imag bool whether to plot imaginary part of wavelet [False] 

784 title string for plot title [None, may use filename if available] 

785 rmax max R to show [None, end of data] 

786 kmax max k to show [None, end of data] 

787 kweight k-weight to use to construct wavelet [None, take from group] 

788 win integer image window to use [1] 

789 

790 Notes 

791 ----- 

792 The wavelet will be performed 

793 """ 

794 kweight = _get_kweight(dgroup, kweight) 

795 cauchy_wavelet(dgroup, kweight=kweight, rmax_out=rmax) 

796 title = _get_title(dgroup, title=title) 

797 

798 opts = dict(win=win, title=title, x=dgroup.k, y=dgroup.wcauchy_r, xmax=kmax, 

799 ymax=rmax, xlabel=plotlabels.k, ylabel=plotlabels.r, 

800 show_axis=True, _larch=_larch) 

801 if show_mag: 

802 _imshow(dgroup.wcauchy_mag, **opts) 

803 elif show_real: 

804 _imshow(dgroup.wcauchy_real, **opts) 

805 elif show_imag: 

806 _imshow(dgroup.wcauchy_imag, **opts) 

807 #endif 

808#enddef 

809 

810def plot_chifit(dataset, kmin=0, kmax=None, kweight=None, rmax=None, 

811 show_mag=True, show_real=False, show_imag=False, 

812 title=None, new=True, delay_draw=False, offset=0, win=1, 

813 _larch=None): 

814 """ 

815 plot_chifit(dataset, kmin=0, kmax=None, rmax=None, 

816 show_mag=True, show_real=False, show_imag=False, 

817 new=True, win=1) 

818 

819 Plot k-weighted chi(k) and chi(R) for fit to feffit dataset 

820 

821 Arguments 

822 ---------- 

823 dataset feffit dataset, after running feffit() 

824 kmin min k to show [0] 

825 kmax max k to show [None, end of data] 

826 kweight kweight to show [None, taken from dataset] 

827 rmax max R to show [None, end of data] 

828 show_mag bool whether to plot |chidr(R)| [True] 

829 show_real bool whether to plot Re[chi(R)] [False] 

830 show_imag bool whether to plot Im[chi(R)] [False] 

831 title string for plot title [None, may use filename if available] 

832 new bool whether to start a new plot [True] 

833 delay_draw bool whether to delay draw until more traces are added [False] 

834 offset vertical offset to use for y-array [0] 

835 win integer plot window to use [1] 

836 

837 """ 

838 if kweight is None: 

839 kweight = dataset.transform.kweight 

840 #endif 

841 if isinstance(kweight, (list, tuple, np.ndarray)): kweight=kweight[0] 

842 

843 data_chik = dataset.data.chi * dataset.data.k**kweight 

844 model_chik = dataset.model.chi * dataset.model.k**kweight 

845 

846 title = _get_title(dataset, title=title) 

847 

848# opts=dict(labelfontsize=10, legendfontsize=10, linewidth=3, 

849# show_legend=True, delay_draw=True, win=win, title=title, 

850# _larch=_larch) 

851 fig = PlotlyFigure(two_yaxis=False) 

852 

853 # k-weighted chi(k) in first plot window 

854 _plot(dataset.data.k, data_chik+offset, xmin=kmin, xmax=kmax, 

855 xlabel=plotlabels.k, 

856 ylabel=set_label_weight(plotlabels.chikw, kweight), 

857 label='data', new=new, **opts) 

858 _plot(dataset.model.k, model_chik+offset, label='fit', **opts) 

859 redraw(win=win, xmin=kmin, xmax=kmax, _larch=_larch) 

860 

861 # show chi(R) in next plot window 

862 opts['win'] = win = win+1 

863 ylabel = plotlabels.chirlab(kweight, show_mag=show_mag, 

864 show_real=show_real, show_imag=show_imag) 

865 

866 opts.update(dict(xlabel=plotlabels.r, ylabel=ylabel, 

867 xmax=rmax, new=True, show_legend=True)) 

868 

869 if show_mag: 

870 _plot(dataset.data.r, dataset.data.chir_mag+offset, 

871 label='|data|', **opts) 

872 opts['new'] = False 

873 _plot(dataset.model.r, dataset.model.chir_mag+offset, 

874 label='|fit|', **opts) 

875 #endif 

876 if show_real: 

877 _plot(dataset.data.r, dataset.data.chir_re+offset, label='Re[data]', **opts) 

878 opts['new'] = False 

879 _plot(dataset.model.r, dataset.model.chir_re+offset, label='Re[fit]', **opts) 

880 #endif 

881 if show_imag: 

882 _plot(dataset.data.r, dataset.data.chir_im+offset, label='Im[data]', **opts) 

883 opts['new'] = False 

884 _plot(dataset.model.r, dataset.model.chir_im+offset, label='Im[fit]', **opts) 

885 #endif 

886 if show_mag or show_real or show_imag: 

887 redraw(win=opts['win'], xmax=opts['xmax'], _larch=_larch) 

888 #endif 

889#enddef 

890 

891def plot_path_k(dataset, ipath=0, kmin=0, kmax=None, offset=0, label=None, 

892 new=False, delay_draw=False, win=1, _larch=None, **kws): 

893 """ 

894 plot_path_k(dataset, ipath, kmin=0, kmax=None, offset=0, 

895 label=None, new=False, win=1, **kws) 

896 

897 Plot k-weighted chi(k) for a single Path of a feffit dataset 

898 

899 Arguments 

900 ---------- 

901 dataset feffit dataset, after running feffit() 

902 ipath index of path, starting count at 0 [0] 

903 kmin min k to show [0] 

904 kmax max k to show [None, end of data] 

905 offset vertical offset to use for plot [0] 

906 label path label ['path %d' % ipath] 

907 new bool whether to start a new plot [True] 

908 delay_draw bool whether to delay draw until more traces are added [False] 

909 win integer plot window to use [1] 

910 kws additional keyword arguments are passed to plot() 

911 """ 

912 kweight = dataset.transform.kweight 

913 path = dataset.pathlist[ipath] 

914 if label is None: label = 'path %i' % (1+ipath) 

915 

916 chi_kw = offset + path.chi * path.k**kweight 

917 

918 _plot(path.k, chi_kw, label=label, xmin=kmin, xmax=kmax, 

919 xlabel=plotlabels.k, 

920 ylabel=set_label_weight(plotlabels.chikw, kweight), 

921 win=win, new=new, delay_draw=delay_draw, _larch=_larch, **kws) 

922 if delay_draw: 

923 redraw(win=win, xmin=kmin, xmax=kmax, _larch=_larch) 

924#enddef 

925 

926def plot_path_r(dataset, ipath, rmax=None, offset=0, label=None, 

927 show_mag=True, show_real=False, show_imag=True, 

928 new=False, delay_draw=False, win=1, _larch=None, 

929 **kws): 

930 """ 

931 plot_path_r(dataset, ipath,rmax=None, offset=0, label=None, 

932 show_mag=True, show_real=False, show_imag=True, 

933 new=False, win=1, **kws) 

934 

935 Plot chi(R) for a single Path of a feffit dataset 

936 

937 Arguments 

938 ---------- 

939 dataset feffit dataset, after running feffit() 

940 ipath index of path, starting count at 0 [0] 

941 rmax max R to show [None, end of data] 

942 offset vertical offset to use for plot [0] 

943 label path label ['path %d' % ipath] 

944 show_mag bool whether to plot |chi(R)| [True] 

945 show_real bool whether to plot Re[chi(R)] [False] 

946 show_imag bool whether to plot Im[chi(R)] [False] 

947 new bool whether to start a new plot [True] 

948 delay_draw bool whether to delay draw until more traces are added [False] 

949 win integer plot window to use [1] 

950 kws additional keyword arguments are passed to plot() 

951 """ 

952 path = dataset.pathlist[ipath] 

953 if label is None: 

954 label = 'path %i' % (1+ipath) 

955 #endif 

956 kweight =dataset.transform.kweight 

957 ylabel = plotlabels.chirlab(kweight, show_mag=show_mag, 

958 show_real=show_real, show_imag=show_imag) 

959 

960 opts = dict(xlabel=plotlabels.r, ylabel=ylabel, xmax=rmax, new=new, 

961 delay_draw=True, _larch=_larch) 

962 

963 opts.update(kws) 

964 if show_mag: 

965 _plot(path.r, offset+path.chir_mag, label=label, **opts) 

966 opts['new'] = False 

967 #endif 

968 if show_real: 

969 _plot(path.r, offset+path.chir_re, label=label, **opts) 

970 opts['new'] = False 

971 #endif 

972 if show_imag: 

973 _plot(path.r, offset+path.chir_im, label=label, **opts) 

974 opts['new'] = False 

975 #endif 

976 redraw(win=win, xmax=rmax, _larch=_larch) 

977#enddef 

978 

979def plot_paths_k(dataset, offset=-1, kmin=0, kmax=None, title=None, 

980 new=True, delay_draw=False, win=1, _larch=None, **kws): 

981 

982 """ 

983 plot_paths_k(dataset, offset=-1, kmin=0, kmax=None, new=True, win=1, **kws): 

984 

985 Plot k-weighted chi(k) for model and all paths of a feffit dataset 

986 

987 Arguments 

988 ---------- 

989 dataset feffit dataset, after running feffit() 

990 kmin min k to show [0] 

991 kmax max k to show [None, end of data] 

992 offset vertical offset to use for paths for plot [-1] 

993 new bool whether to start a new plot [True] 

994 title string for plot title [None, may use filename if available] 

995 win integer plot window to use [1] 

996 delay_draw bool whether to delay draw until more traces are added [False] 

997 kws additional keyword arguments are passed to plot() 

998 """ 

999 # make k-weighted chi(k) 

1000 kweight = dataset.transform.kweight 

1001 model = dataset.model 

1002 

1003 model_chi_kw = model.chi * model.k**kweight 

1004 

1005 title = _get_title(dataset, title=title) 

1006 

1007 _plot(model.k, model_chi_kw, title=title, label='sum', new=new, 

1008 xlabel=plotlabels.r, ylabel=plotlabels.chikw.format(kweight), 

1009 xmin=kmin, xmax=kmax, win=win, delay_draw=True,_larch=_larch, 

1010 **kws) 

1011 

1012 for ipath in range(len(dataset.pathlist)): 

1013 plot_path_k(dataset, ipath, offset=(ipath+1)*offset, 

1014 kmin=kmin, kmax=kmax, new=False, delay_draw=True, 

1015 win=win, _larch=_larch) 

1016 #endfor 

1017 redraw(win=win, xmin=kmin, xmax=kmax, _larch=_larch) 

1018#enddef 

1019 

1020def plot_paths_r(dataset, offset=-0.25, rmax=None, show_mag=True, 

1021 show_real=False, show_imag=False, title=None, new=True, 

1022 win=1, delay_draw=False, _larch=None, **kws): 

1023 """ 

1024 plot_paths_r(dataset, offset=-0.5, rmax=None, show_mag=True, show_real=False, 

1025 show_imag=False, new=True, win=1, **kws): 

1026 

1027 Plot chi(R) for model and all paths of a feffit dataset 

1028 

1029 Arguments 

1030 ---------- 

1031 dataset feffit dataset, after running feffit() 

1032 offset vertical offset to use for paths for plot [-0.5] 

1033 rmax max R to show [None, end of data] 

1034 show_mag bool whether to plot |chi(R)| [True] 

1035 show_real bool whether to plot Re[chi(R)] [False] 

1036 show_imag bool whether to plot Im[chi(R)] [False] 

1037 title string for plot title [None, may use filename if available] 

1038 new bool whether to start a new plot [True] 

1039 delay_draw bool whether to delay draw until more traces are added [False] 

1040 win integer plot window to use [1] 

1041 kws additional keyword arguments are passed to plot() 

1042 """ 

1043 kweight = dataset.transform.kweight 

1044 model = dataset.model 

1045 

1046 ylabel = plotlabels.chirlab(kweight, show_mag=show_mag, 

1047 show_real=show_real, show_imag=show_imag) 

1048 title = _get_title(dataset, title=title) 

1049 opts = dict(xlabel=plotlabels.r, ylabel=ylabel, xmax=rmax, new=new, 

1050 delay_draw=True, title=title, _larch=_larch) 

1051 opts.update(kws) 

1052 if show_mag: 

1053 _plot(model.r, model.chir_mag, label='|sum|', **opts) 

1054 opts['new'] = False 

1055 #endif 

1056 if show_real: 

1057 _plot(model.r, model.chir_re, label='Re[sum]', **opts) 

1058 opts['new'] = False 

1059 #endif 

1060 if show_imag: 

1061 _plot(model.r, model.chir_im, label='Im[sum]', **opts) 

1062 opts['new'] = False 

1063 #endif 

1064 

1065 for ipath in range(len(dataset.pathlist)): 

1066 plot_path_r(dataset, ipath, offset=(ipath+1)*offset, 

1067 show_mag=show_mag, show_real=show_real, 

1068 show_imag=show_imag, **opts) 

1069 #endfor 

1070 redraw(win=win, xmax=rmax,_larch=_larch) 

1071#enddef 

1072 

1073 

1074def extend_plotrange(x, y, xmin=None, xmax=None, extend=0.10): 

1075 """return plot limits to extend a plot range for x, y pairs""" 

1076 xeps = min(diff(x)) / 5. 

1077 if xmin is None: 

1078 xmin = min(x) 

1079 if xmax is None: 

1080 xmax = max(x) 

1081 

1082 xmin = max(min(x), xmin-5) 

1083 xmax = min(max(x), xmax+5) 

1084 

1085 i0 = index_of(x, xmin + xeps) 

1086 i1 = index_of(x, xmax + xeps) + 1 

1087 

1088 xspan = x[i0:i1] 

1089 xrange = max(xspan) - min(xspan) 

1090 yspan = y[i0:i1] 

1091 yrange = max(yspan) - min(yspan) 

1092 

1093 return (min(xspan) - extend * xrange, 

1094 max(xspan) + extend * xrange, 

1095 min(yspan) - extend * yrange, 

1096 max(yspan) + extend * yrange) 

1097 

1098def plot_prepeaks_baseline(dgroup, subtract_baseline=False, show_fitrange=True, 

1099 show_peakrange=True, win=1, _larch=None, **kws): 

1100 """Plot pre-edge peak baseline fit, as from `pre_edge_baseline` or XAS Viewer 

1101 

1102 dgroup must have a 'prepeaks' attribute 

1103 """ 

1104 if not hasattr(dgroup, 'prepeaks'): 

1105 raise ValueError('Group needs prepeaks') 

1106 #endif 

1107 ppeak = dgroup.prepeaks 

1108 

1109 px0, px1, py0, py1 = extend_plotrange(dgroup.xdat, dgroup.ydat, 

1110 xmin=ppeak.emin, xmax=ppeak.emax) 

1111 

1112 title = "pre_edge baseline\n %s" % dgroup.filename 

1113 

1114 popts = dict(xmin=px0, xmax=px1, ymin=py0, ymax=py1, title=title, 

1115 xlabel='Energy (eV)', ylabel='mu (normalized)', delay_draw=True, 

1116 show_legend=True, style='solid', linewidth=3, 

1117 label='data', new=True, 

1118 marker='None', markersize=4, win=win, _larch=_larch) 

1119 popts.update(kws) 

1120 

1121 ydat = dgroup.ydat 

1122 xdat = dgroup.xdat 

1123 if subtract_baseline: 

1124 xdat = ppeak.energy 

1125 ydat = ppeak.baseline 

1126 popts['label'] = 'baseline subtracted peaks' 

1127 _plot(xdat, ydat, **popts) 

1128 else: 

1129 _plot(xdat, ydat, **popts) 

1130 popts['new'] = False 

1131 popts['label'] = 'baseline' 

1132 _oplot(ppeak.energy, ppeak.baseline, **popts) 

1133 

1134 popts = dict(win=win, _larch=_larch, delay_draw=True, 

1135 label='_nolegend_') 

1136 

1137 if show_fitrange: 

1138 for x in (ppeak.emin, ppeak.emax): 

1139 _plot_axvline(x, color='#DDDDCC', **popts) 

1140 _plot_axvline(ppeak.centroid, color='#EECCCC', **popts) 

1141 

1142 if show_peakrange: 

1143 for x in (ppeak.elo, ppeak.ehi): 

1144 y = ydat[index_of(xdat, x)] 

1145 _plot_marker(x, y, color='#222255', marker='o', size=8, **popts) 

1146 

1147 redraw(win=win, xmin=px0, xmax=px1, ymin=py0, ymax=py1, 

1148 show_legend=True, _larch=_larch) 

1149#enddef 

1150 

1151def plot_prepeaks_fit(dgroup, nfit=0, show_init=False, subtract_baseline=False, 

1152 show_residual=False, win=1, _larch=None): 

1153 """plot pre-edge peak fit, as from XAS Viewer 

1154 

1155 dgroup must have a 'peakfit_history' attribute 

1156 """ 

1157 if not hasattr(dgroup, 'prepeaks'): 

1158 raise ValueError('Group needs prepeaks') 

1159 #endif 

1160 if show_init: 

1161 result = pkfit = dgroup.prepeaks 

1162 else: 

1163 hist = getattr(dgroup.prepeaks, 'fit_history', None) 

1164 if nfit > len(hist): 

1165 nfit = 0 

1166 pkfit = hist[nfit] 

1167 result = pkfit.result 

1168 #endif 

1169 

1170 if pkfit is None: 

1171 raise ValueError('Group needs prepeaks.fit_history or init_fit') 

1172 #endif 

1173 

1174 opts = pkfit.user_options 

1175 xeps = min(diff(dgroup.xdat)) / 5. 

1176 xdat = 1.0*pkfit.energy 

1177 ydat = 1.0*pkfit.norm 

1178 

1179 xdat_full = 1.0*dgroup.xdat 

1180 ydat_full = 1.0*dgroup.ydat 

1181 

1182 if show_init: 

1183 yfit = pkfit.init_fit 

1184 ycomps = None # pkfit.init_ycomps 

1185 ylabel = 'model' 

1186 else: 

1187 yfit = 1.0*result.best_fit 

1188 ycomps = pkfit.ycomps 

1189 ylabel = 'best fit' 

1190 

1191 baseline = 0.*ydat 

1192 if ycomps is not None: 

1193 for label, ycomp in ycomps.items(): 

1194 if label in opts['bkg_components']: 

1195 baseline += ycomp 

1196 

1197 plotopts = dict(title='%s:\npre-edge peak' % dgroup.filename, 

1198 xlabel='Energy (eV)', ylabel=opts['array_desc'], 

1199 delay_draw=True, show_legend=True, style='solid', 

1200 linewidth=3, marker='None', markersize=4) 

1201 

1202 if subtract_baseline: 

1203 ydat -= baseline 

1204 yfit -= baseline 

1205 ydat_full = 1.0*ydat 

1206 xdat_full = 1.0*xdat 

1207 plotopts['ylabel'] = '%s-baseline' % plotopts['ylabel'] 

1208 

1209 dx0, dx1, dy0, dy1 = extend_plotrange(xdat_full, ydat_full, 

1210 xmin=opts['emin'], xmax=opts['emax']) 

1211 fx0, fx1, fy0, fy1 = extend_plotrange(xdat, yfit, 

1212 xmin=opts['emin'], xmax=opts['emax']) 

1213 

1214 ncolor = 0 

1215 popts = {'win': win, '_larch': _larch} 

1216 plotopts.update(popts) 

1217 dymin = dymax = None 

1218 if show_residual: 

1219 popts['stacked'] = True 

1220 _fitplot(xdat, ydat, yfit, label='data', label2=ylabel, **plotopts) 

1221 dy = yfit - ydat 

1222 dymax, dymin = dy.max(), dy.min() 

1223 dymax += 0.05 * (dymax - dymin) 

1224 dymin -= 0.05 * (dymax - dymin) 

1225 else: 

1226 _plot(xdat_full, ydat_full, new=True, label='data', 

1227 color=LineColors[0], **plotopts) 

1228 _oplot(xdat, yfit, label=ylabel, color=LineColors[1], **plotopts) 

1229 ncolor = 1 

1230 

1231 if ycomps is not None: 

1232 ncomps = len(ycomps) 

1233 if not subtract_baseline: 

1234 ncolor += 1 

1235 _oplot(xdat, baseline, label='baseline', delay_draw=True, 

1236 style='short dashed', marker='None', markersize=5, 

1237 color=LineColors[ncolor], **popts) 

1238 

1239 for icomp, label in enumerate(ycomps): 

1240 ycomp = ycomps[label] 

1241 if label in opts['bkg_components']: 

1242 continue 

1243 ncolor = (ncolor+1) % 10 

1244 _oplot(xdat, ycomp, label=label, delay_draw=(icomp != ncomps-1), 

1245 style='short dashed', marker='None', markersize=5, 

1246 color=LineColors[ncolor], **popts) 

1247 

1248 if opts.get('show_fitrange', False): 

1249 for attr in ('emin', 'emax'): 

1250 _plot_axvline(opts[attr], ymin=0, ymax=1, 

1251 delay_draw=False, color='#DDDDCC', 

1252 label='_nolegend_', **popts) 

1253 

1254 if opts.get('show_centroid', False): 

1255 pcen = getattr(dgroup.prepeaks, 'centroid', None) 

1256 if hasattr(result, 'params'): 

1257 pcen = result.params.get('fit_centroid', None) 

1258 if pcen is not None: 

1259 pcen = pcen.value 

1260 if pcen is not None: 

1261 _plot_axvline(pcen, delay_draw=False, ymin=0, ymax=1, 

1262 color='#EECCCC', label='_nolegend_', **popts) 

1263 

1264 redraw(xmin=dx0, xmax=dx1, ymin=min(dy0, fy0), 

1265 ymax=max(dy1, fy1), dymin=dymin, dymax=dymax, show_legend=True, **popts) 

1266 

1267def _pca_ncomps(result, min_weight=0, ncomps=None): 

1268 if ncomps is None: 

1269 if min_weight > 1.e-12: 

1270 ncomps = where(result.variances < min_weight)[0][0] 

1271 else: 

1272 ncomps = argmin(result.ind) 

1273 return ncomps 

1274 

1275 

1276def plot_pca_components(result, min_weight=0, ncomps=None, min_variance=1.e-5, win=1, _larch=None, **kws): 

1277 """Plot components from PCA result 

1278 

1279 result must be output of `pca_train` 

1280 """ 

1281 title = "PCA components" 

1282 popts = dict(xmin=result.xmin, xmax=result.xmax, title=title, 

1283 xlabel=plotlabels.energy, ylabel=plotlabels.norm, 

1284 delay_draw=True, show_legend=True, style='solid', 

1285 linewidth=3, new=True, marker='None', markersize=4, 

1286 win=win, _larch=_larch) 

1287 

1288 popts.update(kws) 

1289 ncomps = int(result.nsig) 

1290 

1291 _plot(result.x, result.mean, label='Mean', **popts) 

1292 for i, comp in enumerate(result.components): 

1293 if result.variances[i] > min_variance: 

1294 label = 'Comp# %d (%.4f)' % (i+1, result.variances[i]) 

1295 _oplot(result.x, comp, label=label, **popts) 

1296 

1297 redraw(win=win, show_legend=True, _larch=_larch) 

1298 

1299def plot_pca_weights(result, min_weight=0, ncomps=None, win=1, _larch=None, **kws): 

1300 """Plot component weights from PCA result (aka SCREE plot) 

1301 

1302 result must be output of `pca_train` 

1303 """ 

1304 max_comps = len(result.components) 

1305 

1306 title = "PCA Variances (SCREE) and Indicator Values" 

1307 

1308 popts = dict(title=title, xlabel='Component #', zorder=10, 

1309 xmax=max_comps+1.5, xmin=0.25, ymax=1, ylabel='variance', 

1310 style='solid', ylog_scale=True, show_legend=True, 

1311 linewidth=1, new=True, marker='o', win=win, _larch=_larch) 

1312 

1313 popts.update(kws) 

1314 

1315 ncomps = max(1, int(result.nsig)) 

1316 x = 1 + arange(ncomps) 

1317 y = result.variances[:ncomps] 

1318 _plot(x, y, label='significant', **popts) 

1319 

1320 xe = 1 + arange(ncomps-1, max_comps) 

1321 ye = result.variances[ncomps-1:ncomps+max_comps] 

1322 

1323 popts.update(dict(new=False, zorder=5, style='short dashed', 

1324 color='#B34050', ymin=2e-3*result.variances[ncomps-1])) 

1325 _plot(xe, ye, label='not significant', **popts) 

1326 

1327 xi = 1 + arange(len(result.ind)-1) 

1328 

1329 _plot(xi, result.ind[1:], zorder=15, y2label='Indicator Value', 

1330 label='IND', style='solid', win=win, show_legend=True, 

1331 linewidth=1, marker='o', side='right', _larch=_larch) 

1332 

1333 

1334 

1335def plot_pca_fit(dgroup, win=1, with_components=False, _larch=None, **kws): 

1336 """Plot data and fit result from pca_fit, which rom PCA result 

1337 

1338 result must be output of `pca_fit` 

1339 """ 

1340 

1341 title = "PCA fit: %s" % (dgroup.filename) 

1342 result = dgroup.pca_result 

1343 model = result.pca_model 

1344 

1345 popts = dict(xmin=model.xmin, xmax=model.xmax, title=title, 

1346 xlabel=plotlabels.energy, ylabel=plotlabels.norm, 

1347 delay_draw=True, show_legend=True, style='solid', 

1348 linewidth=3, new=True, marker='None', markersize=4, 

1349 stacked=True, win=win, _larch=_larch) 

1350 popts.update(kws) 

1351 _fitplot(result.x, result.ydat, result.yfit, 

1352 label='data', label2='PCA fit', **popts) 

1353 

1354 disp = get_display(win=win, stacked=True, _larch=_larch) 

1355 if with_components and disp is not None: 

1356 disp.panel.oplot(result.x, model.mean, label='mean') 

1357 for n in range(len(result.weights)): 

1358 cval = model.components[n]*result.weights[n] 

1359 disp.panel.oplot(result.x, cval, label='Comp #%d' % (n+1)) 

1360 redraw(win=win, show_legend=True, stacked=True, _larch=_larch) 

1361 

1362def plot_diffkk(dgroup, emin=None, emax=None, new=True, label=None, 

1363 title=None, delay_draw=False, offset=0, win=1, _larch=None): 

1364 """ 

1365 plot_diffkk(dgroup, norm=True, emin=None, emax=None, show_e0=False, label=None, new=True, win=1): 

1366 

1367 Plot mu(E) and background mu0(E) for XAFS data group 

1368 

1369 Arguments 

1370 ---------- 

1371 dgroup group of XAFS data after autobk() results (see Note 1) 

1372 norm bool whether to show normalized data [True] 

1373 emin min energy to show, absolute or relative to E0 [None, start of data] 

1374 emax max energy to show, absolute or relative to E0 [None, end of data] 

1375 show_e0 bool whether to show E0 [False] 

1376 label string for label [``None``: 'mu'] 

1377 title string for plot title [None, may use filename if available] 

1378 new bool whether to start a new plot [True] 

1379 delay_draw bool whether to delay draw until more traces are added [False] 

1380 offset vertical offset to use for y-array [0] 

1381 win integer plot window to use [1] 

1382 

1383 Notes 

1384 ----- 

1385 1. The input data group must have the following attributes: 

1386 energy, mu, bkg, norm, e0, pre_edge, edge_step, filename 

1387 """ 

1388 if hasattr(dgroup, 'f2'): 

1389 f2 = dgroup.f2 

1390 else: 

1391 raise ValueError("Data group has no array for f2") 

1392 #endif 

1393 ylabel = r'$f \rm\,\, (e^{-})$ ' 

1394 emin, emax = _get_erange(dgroup, emin, emax) 

1395 title = _get_title(dgroup, title=title) 

1396 

1397 labels = {'f2': r"$f_2(E)$", 'fpp': r"$f''(E)$", 'fp': r"$f'(E)$", 'f1': r"$f_1(E)$"} 

1398 

1399 opts = dict(win=win, show_legend=True, linewidth=3, 

1400 delay_draw=True, _larch=_larch) 

1401 

1402 _plot(dgroup.energy, f2, xlabel=plotlabels.energy, ylabel=ylabel, 

1403 title=title, label=labels['f2'], zorder=20, new=new, xmin=emin, xmax=emax, 

1404 **opts) 

1405 zorder = 15 

1406 for attr in ('fpp', 'f1', 'fp'): 

1407 yval = getattr(dgroup, attr) 

1408 if yval is not None: 

1409 _plot(dgroup.energy, yval, zorder=zorder, label=labels[attr], **opts) 

1410 zorder = zorder - 3 

1411 

1412 redraw(win=win, xmin=emin, xmax=emax, _larch=_larch) 

1413#enddef 

1414 

1415def plot_feffdat(feffpath, with_phase=True, title=None, 

1416 new=True, delay_draw=False, win=1, _larch=None): 

1417 """ 

1418 plot_feffdat(feffpath, with_phase=True, title=None, new=True, win=1): 

1419 

1420 Plot Feff's magnitude and phase as a function of k for a FeffPath 

1421 

1422 Arguments 

1423 ---------- 

1424 feffpath feff path as read by feffpath() 

1425 with_pase whether to plot phase(k) as well as magnitude [True] 

1426 title string for plot title [None, may use filename if available] 

1427 new bool whether to start a new plot [True] 

1428 delay_draw bool whether to delay draw until more traces are added [False] 

1429 win integer plot window to use [1] 

1430 

1431 Notes 

1432 ----- 

1433 1. The input data group must have the following attributes: 

1434 energy, mu, bkg, norm, e0, pre_edge, edge_step, filename 

1435 """ 

1436 if hasattr(feffpath, '_feffdat'): 

1437 fdat = feffpath._feffdat 

1438 else: 

1439 raise ValueError("must pass in a Feff path as from feffpath()") 

1440 #endif 

1441 

1442 _plot(fdat.k, fdat.mag_feff, xlabel=plotlabels.k, 

1443 ylabel='|F(k)|', title=title, label='magnitude', zorder=20, 

1444 new=new, win=win, show_legend=True, 

1445 delay_draw=delay_draw, linewidth=3, _larch=_larch) 

1446 

1447 if with_phase: 

1448 _plot(fdat.k, fdat.pha_feff, xlabel=plotlabels.k, 

1449 y2label='Phase(k)', title=title, label='phase', side='right', 

1450 zorder=10, new=False, win=win, show_legend=True, 

1451 delay_draw=delay_draw, linewidth=3, _larch=_larch) 

1452 #endif 

1453 

1454 if delay_draw: 

1455 redraw(win=win, xmin=emin, xmax=emax, _larch=_larch) 

1456#enddef